SoundPoolを使って音を鳴らしてみる

# はじめに
<img width="150" alt="override_method" src="https://qiita-image-store.s3.amazonaws.com/0/90254/9b7dd3d0-920a-9a54-43b0-ac437d0ffd82.png">
こんな感じのものを作っていきます。

ボタンを押すと音がなる簡単なアプリを作った状態から、それを参考にしながら作る形式で紹介していきます。

このページの読者はプログラミングの初級者を想定しているので、表現が回りくどい部分があります。あらかじめご了承ください。

ページに間違い等がございましたら、コメントでご指摘くださると嬉しいです。

# オリジナルの状態
<img width="200" alt="override_method" src="https://qiita-image-store.s3.amazonaws.com/0/90254/8d828aac-fd09-22aa-f8fb-78cbd80f3e30.png">

上の画像のようにボタンを押すとチャイムの音がなるアプリの改造として作っていきます。

もともとの MainActivity と、Clap のコードは以下のようなものをイメージしています。

[MainActivity.java]

```
public class MainActivity extends AppCompatActivity {

    //"変数"を宣言している。値を入れる箱を作っているイメージ。何も指定しなければ、値は入っていない(=空箱)
    Button button;
    Clap clapInstance;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //箱の中身を詰めている。
        button = (Button) findViewById(R.id.button);
        clapInstance = new Clap(getApplicationContext());

        //ボタンが押された時の処理を書いている。
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                clapInstance.play();
            }
        });
    }
}
```

[Clap.java]

```
public class Clap {
    private SoundPool soundPool;
    private int soundId;

    public Clap(Context context) {
        soundPool = new SoundPool(1, AudioManager.STREAM_MUSIC, 0);
        soundId = soundPool.load(context, R.raw.sound_chime, 1);
    }

    public void play() {
        soundPool.play(soundId, 1.0f, 1.0f, 0, 0, 1.0f);
    }
}
```

# 音源の準備
Androidアプリの音源ファイルを用意してください。
今回は、[こちら](http://maoudamashii.jokersounds.com/core.cgi?page=1&field=%E5%8A%B9%E6%9E%9C%E9%9F%B3%E7%B4%A0%E6%9D%90%3C%3E%E6%A5%BD%E5%99%A8)のサイトから、ogg音源をダウンロードさせてもらっています。

# ピアノアプリ作成
## 音源ファイルをrawファイルに入れる
res/rawファイルの場所に、ダウンロードしてきたファイルを入れます。

<img width="300" alt="override_method" src="https://qiita-image-store.s3.amazonaws.com/0/90254/673b4664-1939-de7e-3c4c-160255e8dfc4.png">

↓入れた後のrawの様子。
<img width="300" alt="override_method" src="https://qiita-image-store.s3.amazonaws.com/0/90254/a7b1ed54-4b37-0392-2ce8-2e357637fe00.png">

## レイアウトファイルの作成
### ファイルの新規作成
layoutのフォルダから右クリックで新しいレイアウトファイルを作成します。今回のサンプルでは activity_piano という名前にしています。

↓新規ファイルの作成は右クリックから。
<img width="300" alt="override_method" src="https://qiita-image-store.s3.amazonaws.com/0/90254/4282963b-9a6f-058a-6623-95416baf1176.png">

### LinearLayoutからRelativeLayoutに変える
レイアウトについて...

>AndroidStudioでプロジェクトを新規作成した場合のRelativeLayoutですが、ファイルの新規作成はデフォルトだとLinearLayoutを追加することになります。

慣れた方がやりやすい!? ということで、RelativeLayoutに変更しちゃいましょう。

↓LinearLayoutの部分を選択します。
<img width="400" alt="override_method" src="https://qiita-image-store.s3.amazonaws.com/0/90254/78664937-9ce7-8d92-f366-46500bce0eb8.png">

↓RelativeLayoutのReを入力するとAndroidStudioが補完してくれるので、エンターを押しちゃいましょう(楽！)。
<img width="400" alt="override_method" src="https://qiita-image-store.s3.amazonaws.com/0/90254/6975ec6c-13c0-9062-f7f0-8cd25b925611.png">

↓RelativeLayoutに変えることができました。
<img width="400" alt="override_method" src="https://qiita-image-store.s3.amazonaws.com/0/90254/fd34515d-4d3a-046f-a74d-f9ea77a22589.png">


### Buttonを配置する
"ドレミファソラシド"の８音を鳴らす予定なので、ボタンを８つ配置します。配置は自由にやっていただいて大丈夫です。

↓RelativeLayoutにButtonを８つ配置していきます。
<img width="500" alt="override_method" src="https://qiita-image-store.s3.amazonaws.com/0/90254/dd2287bc-e947-f440-8e04-a226e5f49c45.png">

↓Buttonを８つ配置してみました。
<img width="500" alt="override_method" src="https://qiita-image-store.s3.amazonaws.com/0/90254/3249e17e-cc27-b7a4-f47c-89ada6e1a33a.png">

### Buttonに文字とidを設定する
ButtonのTextを"ド", "レ", ...と言った文字を設定して、さらにidも割り振っていきましょう。

<img width="300" alt="override_method" src="https://qiita-image-store.s3.amazonaws.com/0/90254/350aff23-7c8c-e494-067f-a25678c81efd.png">

↓配置したButtonにidとtextを設定した。
<img width="300" alt="override_method" src="https://qiita-image-store.s3.amazonaws.com/0/90254/5b2c8678-539a-2ac9-6337-5e06274b8b2b.png">

### デザイン調整
デフォルトのままでも動きますが、見た目が残念なので、少しでもよくするために

- Buttonの色
- Buttonの大きさ
- ButtonのTextの色
- 背景の色

を変更していきます。

Buttonの色を変更していきます。
色のバリエーションは[COLORS > 今回使った色の組み合わせ](https://coolors.co/00468c-1e91d6-8fc93a-e4cc37-e18335)のページから選んでいます。

Buttonの色は background に色を設定することで変えることができます。

↓変更前のボタンの色。
<img width="300" alt="override_method" src="https://qiita-image-store.s3.amazonaws.com/0/90254/eb846a6d-c012-f5a1-654b-6099ee6a8ceb.png">


(＊textとidを割り振る前の画像を表示しています)


↓変更後のボタンの色。
<img width="300" alt="override_method" src="https://qiita-image-store.s3.amazonaws.com/0/90254/b7775786-d766-c4c5-fbf8-95b701c69853.png">

↓他の部分も調整したのが以下のものです。
<img width="300" alt="override_method" src="https://qiita-image-store.s3.amazonaws.com/0/90254/25737839-e4ae-4434-6afd-b8e60d05d14b.png">

設定した値をまとめると以下のようになります。

| 設定する場所 | 設定する値     |
| :------------- | :------------- |
| background       | それぞれの値      |
| textColor      | #d0f0f0      |
| textSize       | 32sp      |
| width/height       | 72dp      |

## Pianoクラスの作成
サンプルの Clap と作りは全く同じです。

ただ、Clapの場合には鳴らす音は１種類だけでしたが、Pianoでは８種類の音を鳴らすことになる点だけ注意が必要です。

```
public class Piano {
    private SoundPool soundPool;

    private int soundIdDo;
    private int soundIdRe;
    private int soundIdMi;
    private int soundIdFa;
    private int soundIdSo;
    private int soundIdRa;
    private int soundIdSi;
    private int soundIdDo2;

    public Piano(Context context) {
        soundPool = new SoundPool(1, AudioManager.STREAM_MUSIC, 0);

        //rawファイルから音楽データをとってくる
        soundIdDo = soundPool.load(context, R.raw.sound_do, 1);
        soundIdRe = soundPool.load(context, R.raw.sound_re, 1);
        soundIdMi = soundPool.load(context, R.raw.sound_mi, 1);
        soundIdFa = soundPool.load(context, R.raw.sound_fa, 1);
        soundIdSo = soundPool.load(context, R.raw.sound_so, 1);
        soundIdRa = soundPool.load(context, R.raw.sound_ra, 1);
        soundIdSi = soundPool.load(context, R.raw.sound_si, 1);
        soundIdDo2 = soundPool.load(context, R.raw.sound_do2, 1);
    }

    //音を鳴らすための"メソッド"を書いていく
    public void playDo() {
        soundPool.play(soundIdDo, 1.0f, 1.0f, 0, 0, 1.0f);
    }

    public void playRe() {
        soundPool.play(soundIdRe, 1.0f, 1.0f, 0, 0, 1.0f);
    }

    public void playMi() {
        soundPool.play(soundIdMi, 1.0f, 1.0f, 0, 0, 1.0f);
    }

    public void playFa() {
        soundPool.play(soundIdFa, 1.0f, 1.0f, 0, 0, 1.0f);
    }

    public void playSo() {
        soundPool.play(soundIdSo, 1.0f, 1.0f, 0, 0, 1.0f);
    }

    public void playRa() {
        soundPool.play(soundIdRa, 1.0f, 1.0f, 0, 0, 1.0f);
    }

    public void playSi() {
        soundPool.play(soundIdSi, 1.0f, 1.0f, 0, 0, 1.0f);
    }

    public void playDo2() {
        soundPool.play(soundIdDo2, 1.0f, 1.0f, 0, 0, 1.0f);
    }
}
```

## MainActivityを変更する
準備したレイアウトファイルと、Pianoクラスを実装していきます。

### レイアウトファイルを適用する
<img width="300" alt="override_method" src="https://qiita-image-store.s3.amazonaws.com/0/90254/3cdc59a5-9c28-39e7-5db6-1c087267a375.png">

<img width="300" alt="override_method" src="https://qiita-image-store.s3.amazonaws.com/0/90254/37140101-4d71-577d-6fbf-35d5e575f604.png">

<img width="300" alt="override_method" src="https://qiita-image-store.s3.amazonaws.com/0/90254/643c1fe3-58c4-3370-d629-9064dab0d3f0.png">


### Pianoクラスを実装する
ドの音だけ実装したのがしたのコードになります。
他の音も同様に実装できます。
```
public class MainActivity extends AppCompatActivity {

    //"変数"を宣言している。値を入れる箱を作っているイメージ。何も指定しなければ、値は入っていない(=空箱)
    Button button;
    Clap clapInstance;

    Button buttonDo;
    Piano pianoInstance;

    Button[] buttons = new Button[8];

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_piano);
//
//        //箱の中身を詰めている。
//        button = (Button) findViewById(R.id.button);
//        clapInstance = new Clap(getApplicationContext());
//
//        //ボタンが押された時の処理を書いている。
//        button.setOnClickListener(new View.OnClickListener() {
//            @Override
//            public void onClick(View v) {
//                clapInstance.play();
//            }
//        });

        buttonDo = (Button) findViewById(R.id.button_do);

        pianoInstance = new Piano(getApplicationContext());

        buttonDo.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                pianoInstance.playDo();
            }
        });
    }
}
```

## 完成
実装まで終わればとりあえず、アプリは動くようになります。

## コードを短く

```
public class MainActivity extends AppCompatActivity {

    //"変数"を宣言している。値を入れる箱を作っているイメージ。何も指定しなければ、値は入っていない(=空箱)
    Button button;
    Clap clapInstance;

    Button buttonDo;
    Piano pianoInstance;

    Button[] buttons = new Button[8];

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_piano);

        buttonDo = (Button) findViewById(R.id.button_do);

        pianoInstance = new Piano(getApplicationContext());

        buttonDo.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                pianoInstance.playDo();
            }
        });

        getViews();
        setOnClicks();
    }

    private void getViews() {
        buttons[0] = (Button) findViewById(R.id.button_do);
        buttons[1] = (Button) findViewById(R.id.button_re);
        buttons[2] = (Button) findViewById(R.id.button_mi);
        buttons[3] = (Button) findViewById(R.id.button_fa);
        buttons[4] = (Button) findViewById(R.id.button_so);
        buttons[5] = (Button) findViewById(R.id.button_ra);
        buttons[6] = (Button) findViewById(R.id.button_si);
        buttons[7] = (Button) findViewById(R.id.button_do2);
    }

    private void setOnClicks() {
        for (int i = 0; i < 8; i++) {
            final int index = i;
            buttons[index].setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    pianoInstance.play(index);
                }
            });
        }
    }
}
```

```
public class Piano {
    private SoundPool soundPool;

    private int soundIdDo;
    private int soundIdRe;
    private int soundIdMi;
    private int soundIdFa;
    private int soundIdSo;
    private int soundIdRa;
    private int soundIdSi;
    private int soundIdDo2;

    public Piano(Context context) {
        soundPool = new SoundPool(1, AudioManager.STREAM_MUSIC, 0);

        //rawファイルから音楽データをとってくる
        soundIdDo = soundPool.load(context, R.raw.sound_do, 1);
        soundIdRe = soundPool.load(context, R.raw.sound_re, 1);
        soundIdMi = soundPool.load(context, R.raw.sound_mi, 1);
        soundIdFa = soundPool.load(context, R.raw.sound_fa, 1);
        soundIdSo = soundPool.load(context, R.raw.sound_so, 1);
        soundIdRa = soundPool.load(context, R.raw.sound_ra, 1);
        soundIdSi = soundPool.load(context, R.raw.sound_si, 1);
        soundIdDo2 = soundPool.load(context, R.raw.sound_do2, 1);
    }

    //音を鳴らすための"メソッド"
    public void play(int key) {
        switch (key) {
            case 0:
                soundPool.play(soundIdDo, 1.0f, 1.0f, 0, 0, 1.0f);
                break;
            case 1:
                soundPool.play(soundIdRe, 1.0f, 1.0f, 0, 0, 1.0f);
                break;
            case 2:
                soundPool.play(soundIdRe, 1.0f, 1.0f, 0, 0, 1.0f);
                break;
            case 3:
                soundPool.play(soundIdMi, 1.0f, 1.0f, 0, 0, 1.0f);
                break;
            case 4:
                soundPool.play(soundIdSo, 1.0f, 1.0f, 0, 0, 1.0f);
                break;
            case 5:
                soundPool.play(soundIdRa, 1.0f, 1.0f, 0, 0, 1.0f);
                break;
            case 6:
                soundPool.play(soundIdSi, 1.0f, 1.0f, 0, 0, 1.0f);
                break;
            case 7:
                soundPool.play(soundIdDo2, 1.0f, 1.0f, 0, 0, 1.0f);
                break;

        }
    }
}
```

## レイアウト別案

<img width="300" alt="override_method" src="https://qiita-image-store.s3.amazonaws.com/0/90254/7ec818bf-3e41-86d9-eacb-261a12e51885.png">

```
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#d0f0f0"
    android:orientation="horizontal">

    <Button
        android:id="@+id/button_do"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_margin="1dp"
        android:layout_weight="1"
        android:background="#00468C"
        android:text="ド"
        android:textColor="#f0f0f0"
        android:textSize="32sp" />

    
    <Button
        android:id="@+id/button_re"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_margin="1dp"
        android:layout_weight="1"
        android:background="#1E91D6"
        android:text="レ"
        android:textColor="#f0f0f0"
        android:textSize="32sp" />

    <Button
        android:id="@+id/button_mi"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_margin="1dp"
        android:layout_weight="1"
        android:background="#1E91D6"
        android:text="ミ"
        android:textColor="#f0f0f0"
        android:textSize="32sp" />


    <Button
        android:id="@+id/button_fa"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_margin="1dp"
        android:layout_weight="1"
        android:background="#8FC93A"
        android:text="ファ"
        android:textColor="#f0f0f0"
        android:textSize="32sp" />

    <Button
        android:id="@+id/button_so"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_margin="1dp"
        android:layout_weight="1"
        android:background="#8FC93A"
        android:text="ソ"
        android:textColor="#f0f0f0"
        android:textSize="32sp" />

    <Button
        android:id="@+id/button_ra"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_margin="1dp"
        android:layout_weight="1"
        android:background="#E18335"
        android:text="ラ"
        android:textColor="#f0f0f0"
        android:textSize="32sp" />

    <Button
        android:id="@+id/button_si"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_margin="1dp"
        android:layout_weight="1"
        android:background="#E18335"
        android:text="シ"
        android:textColor="#f0f0f0"
        android:textSize="32sp" />

    <Button
        android:id="@+id/button_do2"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_margin="1dp"
        android:layout_weight="1"
        android:background="#E4CC37"
        android:text="ド"
        android:textColor="#f0f0f0"
        android:textSize="32sp" />


</LinearLayout>
```