KMDのプログラミングメモノート

主にUnity(C#)を中心としたプログラムの備忘録

Unity 音楽再生アプリもどきの作成





はじめに

以前の記事で下の動画の音楽再生アプリのようなものを紹介しましたが、今回はその制作方法について紹介します。






1. 準備

Projectウィンドウで右クリック、「Create」⇒「Scene」と選択して新しいシーンを作成する。
次に、Hierarchyの+ボタンを押して「UI」⇒「Canvas」の順に選択してキャンバスを作成したら下の画像のように

  • Render Mode…Screen Space - Camera
  • Render Camera…作成したシーン上にあるMainCamera

と設定を行う。


そしたら、再生ボタンなどに使用する画像を準備してアセットに追加する。



Canvasに適宜用意した画像を利用してUIを追加していき以下のように画面を作成する。

番号 ゲームオブジェクト名 UIの種類 機能など
NameText Text 再生している曲名の表示
BackButton Button 押すと10秒戻る
用意した画像「DoubleTriangle」を反転(Scale X=-1)にして使用
PauseButton Button 再生/停止を制御
用意した画像「Triangle」を使用
ForwardButton Button 押すと10秒進む
用意した画像「DoubleTriangle」を使用
TimeText Text 再生時刻と音楽の長さを表示
TimeSlider Slider 再生時刻をスライダーで表示
ここから再生時刻を制御はできない。
SpeedText Text 再生速度が何倍かを表示
SpeedSlider Slider 再生速度を変更できる
VolumeText Text 「音量」という文字の表示
スクリプトなどからの制御は行わない
VolumeSlider Slider 音量を調節できる





2. メインとなるスクリプトとゲームオブジェクトの作成

Hierarchyから「Create」⇒「Empy」でゲームオブジェクトを作成して名前を「MusicController」に変更。以降作成するスクリプトはすべてこのオブジェクトに追加する
さらにAudio Sourceを追加してAudioClipに再生したい音楽ファイルを追加する。
続けて制御用のスクリプト「MusicController.cs」を作成して次のプログラムを記述して、下の画像のように画面を設定する。

音楽ファイルは魔王魂のものを使用しています。


プログラム

  • シングルトンにすることで以降に作成するスクリプトからaudioSourceに簡単にアクセスできるようにしている。
  • ゲームが開始したらNameTextにaudioSourceに設定したclip名を表示する。
using UnityEngine;
using UnityEngine.UI;

public class MusicController : MonoBehaviour
{
    [SerializeField] Text nameText;
    public AudioSource audioSource;

    public static MusicController I { get; private set; }

    private void Awake()
    {
        I = this;
    }

    private void Start()
    {
        nameText.text = audioSource.clip.name;
    }
}





3. 再生/停止ボタンの制御(②PauseButton)

「PauseController.cs」を用意してプログラムを記述して「MusicController」オブジェクトにアタッチし設定をします。



プログラム

  • 関数Start内のbutton.onClick.AddListenerでPauseButtonを押したときの処理( 再生/停止の変更)を割り当てている。
  • 再生はaudioSource.Pause()で、停止はaudioSource.Play()で制御できる。
  • Update関数内でaudioSource.isPlayingから音楽が再生中か判断して、画像を変更する。
using UnityEngine;
using UnityEngine.UI;

public class PauseController : MonoBehaviour
{
    [SerializeField] Button button;
    [SerializeField] Image buttonImage;
    [SerializeField] Sprite triangleSprite;
    [SerializeField] Sprite boxSprite;

    private void Start()
    {
        //イベントを追加
        button.onClick.AddListener(PauseUnPause);
    }

    private void Update()
    {
        //再生中なら「||」、停止中なら「▶」にアイコンを設定
        if (MusicController.I.audioSource.isPlaying)
            buttonImage.sprite = boxSprite;
        else
            buttonImage.sprite = triangleSprite;

    }

    //再生・停止の変更
    void PauseUnPause()
    {
        if (MusicController.I.audioSource.isPlaying)//停止
        {
            MusicController.I.audioSource.Pause();
        }
        else
        {
            //MusicController.I.audioSourceを何度も書くのは面倒なので簡潔に宣言
            AudioSource aS = MusicController.I.audioSource;

            //詳しいことはわからないがこれがないとダメ
            aS.timeSamples = (int)(aS.clip.frequency * aS.time);


            aS.Play();
        }
    }
}





4. 10秒戻り/進み機能(②BackButton、④ForwardButton)

「StepController.cs」を用意してプログラムを記述して「MusicController」オブジェクトにアタッチし設定をします。



プログラム

  • Awake関数内でそれぞれのボタンを押したときの処理( 再生/停止の変更)を割り当てている。
  • audioSource.timeが現在の再生時刻なのでこれを±10することで再生時刻を変更している。
  • ±10秒したときにaudioSource.timeが0より小さくなったり、音楽ファイルの長さよりも大きくなったりしないように制御をしている。
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Events;

public class StepController : MonoBehaviour
{
    [SerializeField] Button backButton;
    [SerializeField] Button forwardButton;

    private void Awake()
    {
        //「▶▶」ボタンの設定
        UnityAction action1 = () =>
        {
            float time = MusicController.I.audioSource.time + 10;
            if (time > MusicController.I.audioSource.clip.length)
            {
                MusicController.I.audioSource.Stop();
            }
            else
            {
                MusicController.I.audioSource.time = time;
            }
        };
        forwardButton.onClick.AddListener(action1);

        //「◂◂」ボタンの設定
        UnityAction action2 = () =>
        {
            float time = MusicController.I.audioSource.time - 10;
            if (time < 0) 
            {
                MusicController.I.audioSource.time = 0;
            }
            else
            {
                MusicController.I.audioSource.time = time;
            }
        };
        backButton.onClick.AddListener(action2);
    }
}





5. 再生時刻の表示(⑤TimeText、⑥TimeSlider)

「TimeLineController.cs」を用意してプログラムを記述して「MusicController」オブジェクトにアタッチし設定をします。



プログラム

  • Start関数内で音楽ファイルの長さを取得。
  • 基本的にaudioSourceの関数で取得できる長さは秒単位なので関数Strで分+秒表記に変更する。
using UnityEngine;
using UnityEngine.UI;

public class TimeLineController : MonoBehaviour
{
    [SerializeField] Text text;
    [SerializeField] Slider slider;
    float length;

    string Str(float length)
    {
        int min = (int)length / 60;
        int sec = (int)length % 60;
        return $"{min}:{sec.ToString("D2")}";
    }

    private void Start()
    {
        //曲の全体の長さを取得
        length = MusicController.I.audioSource.clip.length;
    }

    void Update()
    {
        //現在の再生個所を表示
        float nowTime = MusicController.I.audioSource.time;

        //テキスト表示
        text.text = $"{Str(nowTime)}/{Str(length)}";

        //スライダーの設定
        slider.value = nowTime / length;
    }
}





6. 再生速度の制御(⑦SpeedText、⑧SpeedSlider)

「SpeedController.cs」を用意してプログラムを記述して「MusicController」オブジェクトにアタッチし設定をします。



プログラム

  • SpeedSliderの値が再生速度の倍率を示すようにするので最小値と最大値をデフォルトの0~1ではなく0.3~3に変更。
  • Sliderの値が変更されたときに行う関数onValueChangedはインスペクター上でも設定できるが、今回はスクリプトからUnityActionをAddListnerすることで設定している。
  • 再生速度の初期の倍率は1にしたいのでその設定もしている。
  • audioSource.pitchを変更することで再生速度の調節を行っている。
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Events;

public class SpeedController : MonoBehaviour
{
    [SerializeField] Text text;
    [SerializeField] Slider slider;

    void Awake()
    {
        //スライダーの最大値・最小値を設定
        slider.maxValue = 3.0f;
        slider.minValue = 0.3f;

        //スライダーの値を変更すると、再生速度を変更してテキストに表示するよう設定
        UnityAction<float> action = (float value) =>
        {
            MusicController.I.audioSource.pitch = value;
            text.text = $"{value.ToString("F1")}倍";
        };
        slider.onValueChanged.AddListener(action);

        //スライダーの値を1.0にする
        slider.value = 1.0f;
    }
}





7. 音量の制御(⑩VolumeSlider)

「VolumeController.cs」を用意してプログラムを記述して「MusicController」オブジェクトにアタッチし設定をします。



プログラム

  • 処理そのものは「SpeedController.cs」に記述したものと似ている。
  • audioSource.volumeを変更することで音量の調節を行っている。
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Events;

public class VolumeController : MonoBehaviour
{
    [SerializeField] Slider slider;

    void Awake()
    {
        //スライダーの最大値・最小値を設定
        slider.maxValue = 1.0f;
        slider.minValue = 0.0f;

        //スライダーの値を変更すると、再生速度を変更してテキストに表示するよう設定
        UnityAction<float> action = (float value) =>
        {
            MusicController.I.audioSource.volume = value;
        };
        slider.onValueChanged.AddListener(action);


        //スライダーの値を1.0にする
        slider.value = 0.5f;
    }
}





その他

以上の工程で完成しますが

  • ⑥TimeSliderを変更することで再生位置の変更などをできるようにする
  • 再生する音楽を変更できるようにする

など改善の余地はあります。

前者についてはこちらの記事で解説を行っています。
kiironomidori.hatenablog.com