見出し画像

Unityやってみる24:【AudioSource】サイレンっぽい音を、うーうー鳴らしてみる

 こんにちは。Unity素人おじさんです。ただしプログラミング歴は結構長いです。

 「スクリプトだけで何かする」チャレンジをひとまず中断し、オーディオ関係の機能をいじってみることにしました。

 で、ChatGPTにスクリプトを書いてもらったり、音源を自作したりして、「サイレンをうーうー鳴らすデモ。スペースキーで音のオンオフ、キーボードの左右で音程の変更」、を実現できました。

 スクリプトはすべてChatGPTに任せたため、ほぼほぼ何も理解できてないのですが、コンポーネント指向プログラミングでは、理解するよりも出来ることを増やしていくことが重要です。ありがたく利用させていただきましょう。ありがとうChatGPTくん(笑。

 では簡単に手順を説明していきます。


 方針としては、「音の鳴らし方が確認できればいい。余計なオブジェクトはいらない。極力シンプルに簡単に」、とします。

 まずいつものように、プロジェクトを新規作成します。テンプレートは「3D コア」を使います。作成後Unityエディターで開くと、こうなりますね。カメラとライト以外は、何もない状態です。

 今回は、音だけ鳴らせればいいので、上記にいきなりオーディオソース・オブジェクトを配置しちゃいます。その手順は次の通りです。

①別途用意した音源(wavファイル)を、上部メニューの「Assets」→「Import New Asset」で、インポートする。

 私が実験用に用意した音源はこれ。実験したい人はダウンロードしてお使いください。

 

※効果音用の音源は、mp3でなくwavで用意した方がいいです。理由は後述。

②インポートした音源アセットのアイコンを、ヒエラルキーパネルにドラッグ&ドロップしてシーンにセットする

 配置された音源アセットには、AudioSouceコンポーネントが自動でアタッチされます。それにより、スクリプトから、AudioSouceとして利用可能となりますね。

 なお今回、サイレンのような連続音を鳴らそうとしているので、AudioSourceの設定の「Loop」にチェックしておきましょう。忘れやすいので注意です。

追記:Loopのチェックを忘れた時のために、スクリプトでチェックを自動でで付けてもいいですね。

③セットしたAudioSourceに、「Add Component」→「New Script」で新規スクリプトをアタッチする。名前は「AudioController」としておく

④アタッチしたスクリプトをエディターで開いて、サウンド制御用のスクリプトをコピペして保存する

 コピペするスクリプトはこれです。コメントも含め、すべてChatGPTが書いてくれたものです。理解は後にして、ひとまず何も考えずにコピペしましょう。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class AudioController : MonoBehaviour
{
    public AudioSource audioSource;      // オーディオソース
    public float pitchChangeSpeed = 1.0f; // 音程の変化スピード

    private bool isPlaying = false;       // オーディオ再生中かどうか
    private float targetPitch = 1.0f;     // 目標の音程

    void Update()
    {
        // 左キーで音程を下げる
        if (Input.GetKey(KeyCode.LeftArrow))
        {
            targetPitch -= pitchChangeSpeed * Time.deltaTime;
        }

        // 右キーで音程を上げる
        if (Input.GetKey(KeyCode.RightArrow))
        {
            targetPitch += pitchChangeSpeed * Time.deltaTime;
        }

        // スペースキーでオーディオの再生をオン/オフする
        if (Input.GetKeyDown(KeyCode.Space))
        {
            if (isPlaying)
            {
                audioSource.Stop();
                isPlaying = false;
            }
            else
            {
                audioSource.Play();
                isPlaying = true;
            }
        }

        // 音程を0.1~2.0の範囲にクランプする
        targetPitch = Mathf.Clamp(targetPitch, 0.1f, 2.0f);

        // オーディオの音程を目標の音程に近づける
        audioSource.pitch = Mathf.Lerp(audioSource.pitch, targetPitch, Time.deltaTime);
    }
}

⑤インスペクターパネルから、AudioSourceの設定が可能になるので、シーンにセットしたAudioSource自体を、ドラッグ&ドロップする

⑥実行して確認する

 以上で実行の準備は完了です。実行してみました。ゲームビューには何も表示されていませんが、キーボードの左右で音の高さ変更、スペースキーでオンオフが、実現されています。またインスペクターパネルの、AudioSourceコンポーネントの、pitchという設定が、キーボードの左右で変化します。音の高さは、Pitchを変更することで、変えられるんですね。

 あまり高い音にすると、耳が痛くなります💦

追記:うまく左右のキーを操作すると、ぐずる赤ちゃんの声みたいになります。めっちゃうるさいです(笑。

 音の高さを上げる場合は、同時に音量を下げるようにした方が、いいかも知れません。また無理やり高周波や大音量を出し続けると、PCにダメージを与える可能性が高いので、注意が必要です。今回のスクリプトでは、Mathf.Clampという関数で、音程(Pitch)を0.1f~2.0fの範囲に制限してくれているようです。

 以上が、音を出して音程を調整する方法でした。ここからは、サイレン用の音源(wav)をどうやって作ったかを、比較的詳しくご説明しておきます。


今回、とあるYoutubeの動画の、津波警報の音を使わせていただきました。作りたいのは時間の経過によらず、音程・音量が一定の「単調音」であるため、電子的な音とか、機械的な回転音であれば、なんでもいいはずです。ただ、うまく切り取らないと、おかしな音になってしまうかも知れません。

私が録音とか加工に使っている、「Audacity」というフリーソフトの画面で、簡単にご説明します。

 下の図は、警告音全体を録音してみた波形です。横軸が時間です。縦軸は音の強弱です。

 最初は低い音から始まって、音量や音程が、上がったり下がったりしながらだんだん一定の音程になり、しばらくそのままなり続けます。1.5秒当たりから右は、ほぼほぼ一定の波形になり、それが3.0秒くらいまで続いていますね。今回のデモのような、音量も音程も一定な、「単調音」が必要な場合、安定している右の方を狙って切り取って、wavに保存するといいですね。


 一つ注意点です。音の大きさというのは、音の強さで表現できますから、上の波形の上下への振れ幅の大きさで、確認することが出来ます。
 しかし音の高さというのは、音が上下する速さ、つまり「周波数」によって決まりますから、上の波形ではそれがつぶれてしまっていて、確認できませんね。ご参考までに0.5秒辺りの波形と、2.5秒辺りの波形を、拡大してみましょう。

 まず0.5秒の付近の拡大波形です。波形があるパターンを形成しているのが見えますね。そのパターンの10個分を、選択した状態です。赤で囲った部分に、その選択した始点と、終点の時刻が表示されています。0.490秒から0.511秒、つまりこの波形の周期は、(0.511-0.490)/10で、0.0021秒となります。周波数f=1/t=1/0.0021=476なので、周波数は476Hzということになります。

 次に、2.5秒辺りの拡大波形を見てみましょう。だいぶ波形の幅が短くなっていますね。音程が上がっているということです。波形の周期はt=(2.553-2.540)/10=0.0013秒、周波数を計算すると、f=1/0.0013=769Hz、となります。

 最初は大体476Hzだったのが、最後は769Hzで安定。769/476=1.616倍。

 ここで次の表を見てください。ChatGPTが、私の要望に従って作ってくれたものです。ドレミの「ド」の周波数を1とした場合に、次のドまでのそれぞれの音の、周波数がその何倍になるかを示したものです。1.616倍というのは、だいたいラの位置に近いですね。つまり私がサンプルに利用させていただいたサイレン音は、ドレミで表すと、「ド~~~ォオオラァアアア!」って表現できるようです(笑。


 ちょっと脱線しましたけど、録音した音源の、安定した部分を切り出すための、考え方でした。

さらにいくつか、注意点です。

①切り出す波形は、左右がつながってないといけない。

 次の図は、悪いサンプルです。選択範囲(水色部分)の左と右で、波形の高さが一致していないです。これだと連続再生した時に、ブツブツとノイズが乗ってしまいます。

 次の図が、正しいサンプルです。波形が中央の線と重なる部分から始まり、重なる部分で終わっています。このように切り取れていると、ループ時のブツブツというノイズを、減らすことができます。

②切り取る波形の長さは、ある程度長くしておく

 上の2枚の画像では、波形を1つ~2つ分で切り取っていますけど、あまりに短い時間でLOOP処理させた場合、AudioSourceコンポーネントの、STOPイベントの検出処理と、音源の再生処理だけで、PCがすごい負担を強いられることになりそうです。

 そうすると何が起こるかというと、普段は起こらない処理を超高速に強いられることになったPCが、発熱したり、激しく劣化したりすることになります。一定の単調な音の再生だけでいいので、そんなに高速にループさせる必要は、全くありませんね。なのである程度以上の長さに、しておきましょう。

 何秒くらいが適切かは、実行しようとしているハードなどで違うと思いますが、「0.5秒以上は欲しい。1.0秒以上あれば安心」、くらいの目安を持っておけば、いい気がします。Unity素人おじさんである、私が言ってることなので、あまり信用しないようお願いします(笑。

③切り取った波形を保存する際の形式は、mp3はダメ。wavにしておく

 なぜmp3だとダメかというと、そもそもmp3は、楽曲を効率よく保存するためのものなので、次のように勝手に空白の時間を入れられちゃうんですよね。私は今日知りました(笑。


 以上、今日はUnityで、サイレンをうーうー鳴らしてみました(笑。

 AudioSourceコンポーネントには、他にもいろんな設定がありますね。

 1日2日で理解できるものではなさそうですが、今後も勉強して、何かわかったらご報告してきます。

この記事が気に入ったらサポートをしてみませんか?