環境
Unity2021.3.4f1
概要
プロシージャルに音階の波形を生成して、かえるのうたを流してみました。
そのままだとノイズがひどいので、AudioMixerを作成してLowpassフィルタを追加して値調整するとノイズが軽減されます。
using UnityEngine; [RequireComponent(typeof(AudioSource))] public class ProcedualAudio : MonoBehaviour { private float _outputSampleRate; private float _bpm = 120; //BPM60=1分間に四分音符を60回鳴らす速度 private class NoteParam { public enum Note { C4, //ド D4, //レ E4, //ミ F4, //ファ G4, //ソ A4, //ラ B4, //シ } private static float[] _tones = new float[] { 261.626f, 293.665f, 329.628f, 349.228f, 391.995f, 440.000f, 493.883f, }; public Note note; public float tone; public float beat; public NoteParam(Note note_, float beat_) { note = note_; tone = _tones[(int)note]; beat = beat_; } public float GetTime(float bpm) { return (beat * 4.0f) / (bpm / 60.0f); } } private NoteParam[] _notes = new NoteParam[] { new NoteParam(NoteParam.Note.C4, 1.0f / 4.0f), new NoteParam(NoteParam.Note.D4, 1.0f / 4.0f), new NoteParam(NoteParam.Note.E4, 1.0f / 4.0f), new NoteParam(NoteParam.Note.F4, 1.0f / 4.0f), new NoteParam(NoteParam.Note.E4, 1.0f / 4.0f), new NoteParam(NoteParam.Note.D4, 1.0f / 4.0f), new NoteParam(NoteParam.Note.C4, 1.0f / 2.0f), new NoteParam(NoteParam.Note.E4, 1.0f / 4.0f), new NoteParam(NoteParam.Note.F4, 1.0f / 4.0f), new NoteParam(NoteParam.Note.G4, 1.0f / 4.0f), new NoteParam(NoteParam.Note.A4, 1.0f / 4.0f), new NoteParam(NoteParam.Note.G4, 1.0f / 4.0f), new NoteParam(NoteParam.Note.F4, 1.0f / 4.0f), new NoteParam(NoteParam.Note.E4, 1.0f / 2.0f), new NoteParam(NoteParam.Note.C4, 1.0f / 2.0f), new NoteParam(NoteParam.Note.C4, 1.0f / 2.0f), new NoteParam(NoteParam.Note.C4, 1.0f / 2.0f), new NoteParam(NoteParam.Note.C4, 1.0f / 2.0f), new NoteParam(NoteParam.Note.C4, 1.0f / 8.0f), new NoteParam(NoteParam.Note.C4, 1.0f / 8.0f), new NoteParam(NoteParam.Note.D4, 1.0f / 8.0f), new NoteParam(NoteParam.Note.D4, 1.0f / 8.0f), new NoteParam(NoteParam.Note.E4, 1.0f / 8.0f), new NoteParam(NoteParam.Note.E4, 1.0f / 8.0f), new NoteParam(NoteParam.Note.F4, 1.0f / 8.0f), new NoteParam(NoteParam.Note.F4, 1.0f / 8.0f), new NoteParam(NoteParam.Note.E4, 1.0f / 4.0f), new NoteParam(NoteParam.Note.D4, 1.0f / 4.0f), new NoteParam(NoteParam.Note.C4, 1.0f / 2.0f), }; private int _noteIndex = 0; private double _prevDspTime; private void Start() { _outputSampleRate = AudioSettings.outputSampleRate; _noteIndex = 0; _prevDspTime = AudioSettings.dspTime; } private void OnAudioFilterRead(float[] data, int channels) { var note = _notes[_noteIndex]; var sec = note.GetTime(_bpm); var dspTime = AudioSettings.dspTime; var elapsedDspTime = dspTime - _prevDspTime; if(elapsedDspTime > sec) { _prevDspTime = dspTime; _noteIndex ++; _noteIndex %= _notes.Length; note = _notes[_noteIndex]; sec = note.GetTime(_bpm); } //Debug.Log($"noteIndex:{_noteIndex} dspTime:{dspTime} sec:{sec} elapsedDspTime:{elapsedDspTime}"); var begin = (float)(AudioSettings.dspTime % (1.0 / (double)note.tone)); int currentSampleIndex = 0; var volume = Mathf.Lerp(1.0f, 0.5f, (float)elapsedDspTime / sec); for (int i = 0; i< data.Length; i++) { float time = begin + (float)currentSampleIndex / _outputSampleRate; data[i] = volume * Mathf.Sin(2.0f * Mathf.PI * time * note.tone); currentSampleIndex++; if (channels == 2) { data[i + 1] = data[i]; i++; } } } }
感想
これをもっとちゃんとやったものがmidi再生ってことになるのでしょうか。