Ableton Live の Operator の設定値を WebAudioAPI で利用する


Ableton Live の FM音源 Operator では Coarse と Fine の値で各オシレーターの周波数の調節ができます。

調節後の周波数を求める式は以下のとおり。

outputFrequency = inputFrequency * Coarse * (1 + Fine / 1000);

上記の式をすごく雑に説明すると、計算前の周波数に対する比率を計算していて、Coarse が整数部分、Fine が小数点以下の部分となっています。

計算後の周波数 = 計算前の周波数 * Coarse.Fine

# Coarse = 11, Fine = 965 のときなら、計算前の周波数に 11.965 をかける

そこで、以下のような関数を用意すると..

function convertFineIntoRatio(fine) {
  if (fine < 0) {
    return 1 / (1 - fine / 1000);
  }
  return 1 + fine / 1000;
}

冒頭のスクリーンショットの設定は、このように書ける。

opA.frequency.value = frequency *  0.5 * convertFineIntoRatio(993);
opB.frequency.value = frequency * 12.0 * convertFineIntoRatio(  0);
opC.frequency.value = frequency *  0.5 * convertFineIntoRatio(995);
opD.frequency.value = frequency * 11.0 * convertFineIntoRatio(965);

マイナス値の設定にも対応しているので、このようにも書ける。

opA.frequency.value = frequency *  1.0 * convertFineIntoRatio( -7);
opB.frequency.value = frequency * 12.0 * convertFineIntoRatio(  0);
opC.frequency.value = frequency *  1.0 * convertFineIntoRatio( -5);
opD.frequency.value = frequency * 12.0 * convertFineIntoRatio(-35);

比率からMIDIノート番号を計算してやれば、その100倍が detune の値となるので、以下のような関数を用意すると..

function convertFineIntoDetune(fine) {
  var sign = fine < 0 ? -1 : +1;
  var ratio = 1 + Math.abs(fine) / 1000;

  return sign * Math.log(ratio) * Math.LOG2E * 12 * 100;
}

このように書ける。

opA.frequency.value = frequency * 0.5;
opB.frequency.value = frequency * 12;
opC.frequency.value = frequency * 0.5;
opD.frequency.value = frequency * 11;

opA.detune.value = convertFineIntoDetune(993);
opB.detune.value = convertFineIntoDetune(0);
opC.detune.value = convertFineIntoDetune(995);
opD.detune.value = convertFineIntoDetune(965);

もしくはマイナス値を使ってこう。

opA.frequency.value = frequency;
opB.frequency.value = frequency * 12;
opC.frequency.value = frequency;
opD.frequency.value = frequency * 12;

opA.detune.value = convertFineIntoDetune(-7);
opB.detune.value = convertFineIntoDetune(0);
opC.detune.value = convertFineIntoDetune(-5);
opD.detune.value = convertFineIntoDetune(-35);

ちなみに Level 値の dB は以下の式で変換できるので、

function convertDecibelIntoGain(db) {
  return Math.pow(10, db * 0.05);
}

こう書ける。

opALevel.gain.value = convertDecibelIntoGain(-2.8);
opBLevel.gain.value = convertDecibelIntoGain(-22);
opCLevel.gain.value = convertDecibelIntoGain(-5.7);
opDLevel.gain.value = convertDecibelIntoGain(-40);

けど、多分変調方式が異なる (よくある位相で変調するやり方に対して、Web Audio API は周波数でしか変調できない) のでゲインの値は適宜調節が必要。

僕はモジュレーターのゲイン値は勘で調節している。

opALevel.gain.value = convertDecibelIntoGain(-2.8);
opBLevel.gain.value = convertDecibelIntoGain(-22) * frequency * 20;
opCLevel.gain.value = convertDecibelIntoGain(-5.7);
opDLevel.gain.value = convertDecibelIntoGain(-40) * frequency * 20;

これをFMアルゴリズムに従って接続すれば そこそこ 同じ音がつくれる。

参考にしたトピック
https://forum.ableton.com/viewtopic.php?f=4&t=26560