Unity

[Unity] 0から始めるMusic.cs

♬ Music.cs

https://github.com/geekdrums/MusicEngine

Music.csは @geekdrums さんが製作されたライブラリです。
(こういう発表インタラクティブミュージックに関する記事を投稿 されている方です)
Music.csは最終更新が2015年ですが、Unity2018でも動作します。

🤔Music.csで何ができるか?

以下のPDFに解説が記載されています。
https://github.com/geekdrums/MusicEngine/blob/master/AboutMusicEngine.pdf

また以下のようなサンプルゲームも公開されています。
https://unityroom.com/games/musicpong
https://unityroom.com/games/spacetogo

Music.cs は主に以下の機能を提供しています。

  • 今再生している音楽の情報を取得することができる
  • 今再生している音楽のリズムのタイミングが現フレームで合致したかを取得できる

🗂 Unityの中に取り込む

https://github.com/geekdrums/MusicEngine

zip.png

ZIPファイルをDLして解凍し、そのままUnityに入れ込んでください。
(中にある Music.cs だけでも稼働します)

⚙ Music.cs の下準備

Music.csのアタッチ

任意のGameObjectにMusic.csをアタッチします。
(RequireComponet に指定があるため AudioSource も一緒にアタッチされます)

music1.png

次に一緒に追加された AudioSource に再生したいBGMを指定します。

music2.png

BGMの情報を指定する

Music.cs 自体には音楽のテンポを解析する機能はないため、こちらで一部の情報を指定する必要があります。

項目 内容
UnitPerBeat 何unitで1拍か
UnitPerBar 何unitで1小節が
Tempo BPM/曲の速さ

4/4拍子の場合、UnitPerBeatは4 / UnitPerBarは4*4=16を指定します。
TempoはBPM (Beats Per Minute)を指定します。
1分間に何拍存在するか、という速さの指標で、多ければ早くなります。
これを的確に指定しないとリズムがずれます。

曲を自作する場合はBPMは自分で指定するので問題ないですが
BPMが記載されていないフリーの素材を使用する場合
このようなサイト を使用して、測定することになります (BPMは下1桁が 0 or 5 で構成されることが多いので測定で出た値を四捨五入しつつ、前後にずらして調整していくのが良いでしょう)

music3.png

これで下準備は完了です。

( Sections.Size を指定することで曲を複数に分割し、取り扱うことができますが、今回は割愛しています🙏)

🐄 リズムに合わせてオブジェクトを動かす

リズムに合わせてオブジェクトを拡大/縮小させてみます。
Music.IsJustChangedBeat を使用し、拍が切り替わるタイミングを取得します。
Music の一部のメソッドやメンバーは static 宣言されているため
どこのクラスからも参照することができます。

以下を動かしたいオブジェクトにアタッチします。
transform.scale を変更しているので3DモデルでもSpriteRendererでもuGUIでも何でもとりあえず動きます。

DOTweenをインポートしている前提です。

ChangeScale.cs
using UnityEngine;
using DG.Tweening;

public class ChangeScale : MonoBehaviour
{
    public float Rate = 1.1f;
    public float Time = 0.2f;

    private Vector3 baseScale;

    void Start()
    {
        this.baseScale = this.gameObject.transform.localScale;
    }

    void Update()
    {
        if (Music.IsPlaying && Music.IsJustChangedBeat())
        {
            this.gameObject.transform.DOScale(this.baseScale * this.Rate, 0.0f);
            this.gameObject.transform.DOScale(this.baseScale, this.Time);
        }
    }
}

これでUI要素や背景オブジェクトを動かすだけでも楽しい!
適当に Rate や Time をいじって遊んでください。 Music と一緒にアタッチされたBGM用の AudioSource のピッチ変更にも追従するので、ピッチを動かして遊んでみるものいいでしょう。

music4.gif

🎨 小節ごとに背景色を変える

Music.IsJustChangedBar を使用し、小節が切り替わるタイミングを取得します。
1小節ごとに背景色を変えてみましょう。

ChangeColor.cs
using UnityEngine;
using DG.Tweening;
using UnityEngine.UI;

// SpriteRendererでも可
[RequireComponent(typeof(Image))]
public class ChangeColor : MonoBehaviour
{
    public float Time = 0.2f;

    void Update()
    {
        if (Music.IsPlaying && Music.IsJustChangedBar())
        {
            Color color = new Color(
                Random.Range(0.5f, 0.8f),
                Random.Range(0.5f, 0.8f),
                Random.Range(0.5f, 0.8f),
                1f
            );
            this.GetComponent<Image>().DOColor(color, Time);
        }
    }
}

music5.gif

💬 リズムに合わせて音を鳴らす

普段、SEを鳴らす際にはBGMとの関係性を意識せずに鳴らしていますが
クオンタイズを使用することで、BGMとSEがズレのない状態で (後方にやや貯めてから) 再生することができます。

Music.QuantizePlay に鳴らしたい効果音をアタッチした AudioSource を渡します。 Music 側でタイミングを調整した上で再生してくれます。

以下はボタンを押した時に音を鳴らすという例です。

SEPlayQuantizeButton.cs
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.EventSystems;

[RequireComponent(typeof(AudioSource))]
public class SEPlayQuantizeButton : MonoBehaviour, IPointerDownHandler
{
    public void OnPointerDown(PointerEventData eventData)
    {
        Music.QuantizePlay(this.GetComponent<AudioSource>());
    }
}

最後に

応用的な機能の使い方は省きました「リズムに合わせてオブジェクトを動かす」「リズムに合わせて音を鳴らす」ということについて説明しました。ぜひぜひ試してみてくださいー!