簡易的なディレイ・コーラスエフェクト

再生する音のパターンはそれぞれ全く同じですが、 同じ音を重ねて再生することで音に広がりを与えることができます。

私の piano.js を使用!

エフェクトなし

ディレイエフェクト

  • 120ms後に
  • ピッチを1/10半音上げ
  • ボリュームを30%から
  • 40%ずつ減少した音を再生
  • それを2回繰り返す

コーラスエフェクト

  • 即座に
  • ピッチを1/5半音上げ
  • ボリュームを30%から
  • 50%減少した音を再生

ソースコード

シーケンサーメソッド (piano.js から一部抜粋)


        const seqIdAllowFlg = new Set();
        /**
        * タイミング(リズム)に合わせてコールバック関数を実行する。
        * 
        * @param {Function} callback 1つ前の実行からsequence[i-1]の間待機して実行される関数。この関数には引数としてvalues[i]が渡される。
        * @param {Array} sequence 次のcallbackの実行までの待機時間の配列。valuesと要素数が等しい、もしくは要素数-1である必要がある。
        * @param {Array} values callbackに渡される値の配列。sequenceと要素数が等しい、もしくは要素数+1である必要がある。
        * @param {number} [bpm=240] sequence[]に設定されている値の1を全音符、1/4を1拍とした時のBPM。
        * @param {any} [seqId=undefined] 同一のIdは重ねて呼び出しができない。未設定の場合は重複した呼び出しが可能。
        */
        function sequencer(callback, sequence, values, bpm = 240, seqId = undefined) {
            // sequenceとvaluesは完全に1対1で対応している必要がある
            // sequenceの最後の値は意味をなさないため省略できる
            if (sequence.length !== values.length && sequence.length + 1 !== values.length) {
                throw new Error("The length of sequence and values are did not match");
            }

            // 同一Idの重複呼び出しをロック
            if (seqId != undefined) {
                if (seqIdAllowFlg.has(seqId)) {
                    return;
                }
                seqIdAllowFlg.add(seqId);
            }

            // 全てのvalues[i]をsequence[0:i]の遅延で呼び出す
            let totalTime = 0;
            for (let i = 0; i < values.length; i++) {
                // 秒をミリ秒に変換し、BPMを乗する
                // 240BPM全音符 = 60BPM4分音符 = 1000ms
                const waitTime = sequence[i] ? sequence[i] * 1000 / (bpm / 240) : 0;

                const value = values[i];

                // sequence[i]以前の全てを足した分だけ待機する
                setTimeout(() => {
                    // 関数呼び出し
                    callback(value);
                }, totalTime);

                totalTime += waitTime;
            }

            // ロックを解放
            if (seqId != undefined) {
                setTimeout(() => {
                    seqIdAllowFlg.delete(seqId);
                }, totalTime);
            }
        }
      

ディレイエフェクト用シーケンサ


        /**
         * @param {Function} callback 引数の配列の第二引数はvolume
         * @param {Array} sequence 通常通り
         * @param {Array} values 通常通り
         * @param {number} bpm 通常通り
         * @param {any} seqId 自動的にプレフィックスが付加される
         * @param {number} delayMs 遅延する秒数(ミリ)
         * @param {number} pitchShift 一つ前から音程をずらす値(midi)
         * @param {number} volume 1番目の音量
         * @param {number} decay 一つ前から変化する音量の倍率(1 := 1倍)
         * @param {number} overwrap 重ねる回数
         */
        function playNoteAllDelaySequencer(
            callback,
            sequence,
            values,
            bpm = 240,
            seqId = undefined,
            delayMs = 0,
            pitchShift = 0,
            volume = 0.25,
            decay = 1,
            overwrap = 1
        ) {
            let totalTime = 0;
            for (let i = 0; i < overwrap + 1; i++) {
                const waitTime = delayMs;

                const shiftedValues = values.map((value) => {
                    return [
                        value.map((midi) => {
                            return midi + pitchShift * i;
                        }),
                        volume * Math.pow(decay, i)
                    ]
                });

                const prefixSeqId = seqId != undefined ? `delay${i}-${seqId}` : undefined;

                setTimeout(() => {
                    sequencer(callback, sequence, shiftedValues, bpm, prefixSeqId);
                }, totalTime);

                totalTime += waitTime;
            }
        }
      

音楽パターン


        const SONG1_SEQUENCE = [
            2 / 24,
            1 / 24,
            1 / 8,

            2 / 24 + 0.02,
            1 / 24 + 0.01,
            1 / 24 + 0.01,
            1.5 / 24 + 0.02,

            1 / 20,
            1 / 20,
            1 / 20,
            1.5 / 20,

            1 / 16,
            1 / 16,
            1 / 16,

            1 / 24,
            2 / 24,
            2 / 24,

            3 / 28,
            4 / 28,

            0.5
        ];
        const SONG1_VALUES = [
            [41, 60, 65, 69],
            [57],
            [72],

            [46, 53.1, 56.1, 61, 65 - 0.05, 68, 72, 75, 77],
            [75],
            [73],
            [72],

            [53, 70],
            [60],
            [63, 68],
            [70],

            [48, 58, 63],
            [55],
            [65],

            [49, 56, 60, 63],
            [65],
            [63],

            [39, 46.1, 55, 58],
            [63],

            [41 - 0.15, 48 - 0.15, 53.05, 57, 60, 65]
        ];