YM2612 Technical Notes

■===================================
■Yamaha ym2612 documentation
■by sasayaki
■===================================
■音の原理
水面に物を落とすと、落下点を中心に波が発生しドーナッツ状に広がっていきます。
地上でもこの水が空気に置き換わっただけで同じ現象が発生します。
この波が耳の鼓膜にまで伝わり、鼓膜を揺らすと電気信号に変り脳に送られ音として認識します。
■音色の原理
自然界には色々な音(音色)が存在しますが、それは波の高さと波の幅の違いであり、鼓膜の揺れに違いが出ることで
音(音色)の違いを認識します。
そして、人間は波の高さが大きい程音量が大きいと感じ、波のは幅が狭い程高音と認識します。
音楽では音の高さとしてドレミファソラシで1セットとする音階というルールがあり、そのセットの順番を
オクターブというルールとしています。これは誰が決めたわけではありませんが、古代の人が心地よい音を奏で
ているうちに自然にそうなったものを、後世の人が気が付いたルールです。
波の幅を時間で表現したものを周波数と呼び、1秒の時を1Hzとし、1/440秒(440Hz)の時に4オクターブ目のラの音という
ルールになっています。
これも後で気が付いたルールですが、周波数を2倍は1オクターブ上の音になるという原理があります。
4オクターブ目のラ(A4)の周波数は440Hzで1オクターブ上は2倍の880Hz(4402)、その1オクターブ上は更に 2倍の1760Hz(4404)になります。2のN乗の関係になります。
次に1オクターブ内の音階のルールですが、これは楽器や音楽によって異なり、同じドレミでも
楽器により周波数が異なります。しかしオーケストラやバンドなど複数の楽器が集まり
一緒に曲を奏でる場合、音の調律を合わせるのが難しいので、4オクターブ目のラ(A4)だけは
440Hzで統一する国際的に取り決め広く採用されています。
それ以外の音階のルールは楽器や音楽の特性があるのでバラバラで複数のルールが存在しますが、
YM2612では西洋音楽で広く使われる平均律というルールを採用しています。
平均律とは、1オクターブを「C、C#、D、D#、E、F、F#、G、G#、A、A#、B」の12音の半音で
表現し、周波数を12分割で均等ぶ分割するというものです。ピアノの鍵盤を見ると白鍵と黒鍵の
大きさが違い順番も交互ではないので、均等に見えませんが、実は均等なのです。
但し、単純に1/12の等分ではなく、1オクターブ上の周波数は2のN乗の関係なので半音上(Cの上のC#とか)は
「2の(1/12)乗」の1.05946倍した周波数になります。Cを1.05946倍するとC#、さらに1.05946倍するとD、
さらに1.05946倍するとD#という関係であり、440に1.05946を12回掛けると880になり1オクターブ上になります。
■YM2612の特徴
YM2612の仕事はプログラマが指定した種類の波を作り出すことです。
さらに言えば、波の幅は時間毎にスライスしてみると音量の増減の変化なので、YM2612の仕事は一定時間毎に音量を
変化させることが仕事となります。
■FM音源
単純な波(正弦波)では単調な音になるので、YM2612は複雑な波を作り出し色々な音色を表現できます。
YM2612では2つの周波数を少しタイミングをずらし発生させ組み合わせる
FM音源(Frequency Modulation:位相変調方式)技術により複雑な音を出します。
440Hzの1回の波は1/440秒と極短時間であるため、実際にはプログラマの指定している時間だけ波を連続して
発生させます。この連続し波を繰り返す際に波の動きを細かく変化させる事で色々な音色を作り出します。
■YM2612の仕組み
YM2612で波を作り出す処理を「スロット」と呼びます。(オペレータと呼ぶこともありますが、OP(operator)と混同するのでスロットと呼びます)
1つのスロットでは単純な正弦波しか出せませんが、4つのスロットを組み合わせることで複雑な音を作り出します。
組み合わせは8パターンありアルゴリズムと呼びます。
スロットは1つの正弦波を作りますが、1つ前のスロットが作った波を取り込むことで、2つの周波数から
FM音源の計算をします。4つのスロットを直列に並べ計算結果を引き継げば、かなり複雑な音色が作れます。
スロットの中身は「PG(Phase Generator)、OP(operator)、EG(Envelop Generator)」という部品で構成されます。

PGはプログラマの指定した波の幅をカウンタを使い求めるのが仕事です。
スロットを実行する毎にPGはカウントアップし最大になるとゼロに戻るを繰り返します。
1秒間にカウンタが440回転するようにカウントアップすると440Hzの音がでます。

OPはPGから受け取ったカウンタ値から正弦波を作り出し、1つ前のスロットが作った波と
合成しFM音源の計算をするのが仕事になります。

EGは音量の起伏を計算で作り出します。例えばピアノの鍵盤を叩くと最大音の音が出て少しずつ音は小さくなり余韻ののち
無音になりますが、この音量の起伏の変化(エンベロープ)を計算するのが仕事になります。
EGもPGと同様にカウンタをもっており時間により計算値が変化していきます
EGの結果はOPに渡され、OPはFM音源の計算結果とEGの結果を合成したものを、スロットの処理結果として出力します。
■FM音源の計算
ここから実装の詳しい話に入ります。YM2612のマニュアルを分析することで、実装方法を推測していきます。

FM音源の計算式は「F(t)=A(t)sin(ωct+I(t)sinωmt)」となります。
1つ目のスロットの処理が「I(t)sinωmt」で、2つ目のスロットが「F(t)=A(t)sin(ωct)」となり、
1つ目のスロットが作った波「I(t)sinωmt」を合成し「F(t)」を計算するという式になります。
FM音源の計算では合成する2つの波を「キャリア(c)」と「モジュレータ(m)」呼び、OPが計算した正弦波をキャリア、
1つ前のスロットが作った波をモジュレータと呼びます。
まずモジュレータ「I(t)sinωmt」の説明をします。
「ωm」はPGの結果であり、OPで時間毎「t」に正弦波(sin波)を計算するので「sinωmt」と表現します。
これにEGの結果「I(t)」を合成したという意味になります。
キャリア「A(t)sin(ωct)」も考え方は同じで、違いはEGの結果を「A(t)」とする所です。
キャリアのEGはモジュレータの周波数の計算に使うので、キャリアのEGを周波数に影響を与えることから
変調度(modulation Index)と呼びます。
モジュレータのEGは本来の音量の増減に影響を与えるので振幅(Amplitude)と呼びます。
FM音源の合成は「ωct+I(t)sinωmt」の所であり、2つの波を加算したものから、新たな波「F(t)」を算出します。

■PG(Phase Generator)
PGはプログラマが指定した周波数にしたがいカウンタをカウントアップしますが、PGだけでカウントアップ値を
計算するのは大変なので、プログラマがカウントを計算してあげる必要があります。
YM2612のマニュアルにはプログラマが担当する計算は「F-Number = ((144 * fnote * (2^20) / M) / (2^(B-1)) 」とあります。
Mはマスタークロックで8000000(8Mhz)、Bはオクターブ、fnoteは周波数を示し、計算結果のF-NumberとB(block:オクターブ)をPGに指定します。
440Hz(4オクターブ目のラ)の音を出すには「(144 * 440 * (2^20) / 8000000) / (2^(4-1))=1038.1」なので
YM2612に1038と4を指定しなさいという意味になります。
「144」は1回のスロットの処理で必要なYM2612内のクロック数を示します。
YM2612は同時に6音を発生できます。そして1つの音(チャンネル)では4つのスロットが実行されますが、YM2612には
1つのスロットしか存在せず、オペーレータの1回の計算にはYM2612内のの時間で1クロックで処理を行います。
その1つスロットを順番に6音×4スロットの24回だけ実行することで、1回分の計算を行います。
そしてGenesisのYM2612は入力されたマスタクロック(8Mhz)を1/6に分周した速度で処理しているので、マスタクロックで
換算すると24回×6の144クロックで1回の計算しているとなります。
「(2^20)」はカウンタのサイズが20bit(0~1048576)の整数であることを示します。
「(2^(B-1)」(Bはblockの頭文字)ですが、1オクターブ上の周波数は2乗した値なので 2^B(2のB乗)となります。YM2612では2オクターブ目を
基準として1オクターブは1/2して求める仕様であるため、「(2^(B-1)」という計算になります。
PGは1038と4を受け取ると「F-Number * (2 ^ (block – 1))」から8304を求め、8304毎カウントアップします。

なお、ここまでの説明はYM2612のマニュアルでの話であり、実機のMegaDriveの実装と違いを考慮する必要があります。
1.マニュアルのクロックは8.0HzでMegaDriveは7.670454Hzで動作するので、7.670454/8.0で0.95倍する必要があります。
2.スロットを「8000000(8Mhz) / 144(クロック)」で1秒間に55555回実行し、本エミュレータは1秒間に44100回の周期で実行するので、
  55555/44100で1.26倍する必要があります。
1と2を合わせ「(7.670454 / 8.0) * ((8000000 / 144) / 44100)」クロックの重さを1.2倍にする必要があります。

■OP(operator)
OPはPGから受け取ったカウンタ値と1つ前のスロットが作った波の値を合成(加算)しSIN波を作り、その後EGから
受け取った値で音量を調整します。
PGのカウンタは20bitの精度がありますが人間の耳はそこまでの精密さは聞き取れないので、回路を簡素化するためにも
上位の10bitのみOPに渡します。OPはこの値からSIN波を求めますがSINの計算は大変なので、
計算済のSINテーブル(1周期は10bitで0x400個の値)を持っています。
数学の世界ではSIN値は-1~+1の範囲の値ですが、YM2612に浮動小数値の計算はない(当時のチップは貧弱)ので
10bit(1024)を掛け整数部分だけ使い-1024~+1023で整数の計算を行います。

■キーコード
この後に説明するDetuneやAttackなど周波数や音量に微妙な揺れを与える機能で使用します。この値は周波数により
内部で自動で計算されます。
微妙な揺れを与える場合、100Hzに1を加えると1%の変動ですが1000Hzでは0.1%の変動であり、高音になる程効果が薄れます。
その為、高音では大きな揺れにする必要があります。1オクターブ内で4分割で8オクターブあるので、キーコードは
32段階の値を持ちます。

■マルチプル
プログラマが指定した周波数に一定の倍率を掛けます。1/2~15の16段階です。周波数に単純に指定値を掛けるだけですが、
最小値は1/2でありそれ以降は1~15の整数という点が実装で面倒です。

■Detune
PGでの特徴的な機能にDetuneという周波数を微妙にずらし不協和音を作り出す機能があります。
マニュアルのには0.053Hz、0.106Hz、0.159Hzと、0.053Hzの倍数でずらすことができます。
8304毎カウントアップすると440Hzになるので「440/8304」から1カウントで0.053Hzの精度があることがわかります。
1カウントは0.053Hzとなるので、F-NumberとBlockで求めたカウントにそれぞれ+1、+2、+3とずらす値を加算するだけの処理になります
キーコードを考慮した値を値を加算します。

■LFO
LFOは周波数とエンベロープのカウントアップ値に細かな振動(SIN波)を与える仕組みです。(周波数のカウントアップ値をあげれば高音になる)
周波数を変えるのはPMS、エンベロープを変えるのはAMSと呼びます。
まずLFO Freqレジスタで振動(SIN波)の周波数を設定します。設定により3.98~72.7Hzの8段階の速度で振動を発生します。
その振動を周波数にどれだけ影響させるか(変調の深さ)はPMSレジスタで設定します。設定により3.4~80セントの8段階で周波数に加算します
セントとは半音(CとC#の間とか)を100等分した値を示す単位です。1オクターブは12音階なので1オクターブは1200セントとなります。
平均律の考え方から1セント上の周波数は2の(1/1200)乗上となります。1セント上は1.0005778倍した値になります。
(1.00057781.00057781.0005778・・・と1200買い繰り返すと2乗した値になります)
LFO Freqレジスタが1の時は±3.4セント幅でSIN波で振動をさせるのでカウントアップ値を1.0019645倍します。
振動の周波数はメインのカウンタと同じ仕組みで1カウントで0.053Hzを表現するので、3.98Hzならば75毎に20bitのカウンタを
カウントアップし、その周期に合わせて周波数と音量を変化させます。

■EG(Envelop Generator)
EGは音量の変化を計算します。単純にPGとOPの計算では起伏のない単調な音しか出せません。
例えばピアノの鍵盤を叩くと最大音量の音が出て少しずつ音は小さくなり余韻ののち無音になりますが、この音量の
変化を制御するのがEGです。
音圧に関してマニュアルの出力制御回路の説明に「ダイナミックレンジは96dB、設定可能な分解能は0.75dBです」と
あるので、エンベロープはデシベルで計算することがわかります。
音圧は指数関数的に増加します。人間が聞き取れる最小の音圧を基準値0(0dB)として、ささやき声(20dB)で
基準値の10倍、昼間の住宅地(40dB)で基準値の100倍、うるさい会話(60dB)で基準値の1000倍となるので
96dbだと63095倍という理論です。人間が音量が半分に下がったと認識するには、PCから出る音を1/10にする必要があります。
YM2612は逆で、PG+OPの最大のSIN値を最大音量とし、そこから96dB下がる(減衰)すると無音になるという考え方です。

EGの計算した音量値をOPの周波数値に反映するには周波数値を一旦デシベル値に変換し音量値の反映後に元の音圧値(線形)に
戻す必要があります。
一般的な音響理論の音圧のデシベルへの変換は「デシベル値=20*log10(音圧値)」、戻しは「音圧値=Pow(10, デシベル値)」となります。
「設定可能な分解能は0.75dB」というのはTotalLevelレジスタの設定値が「48,24,12,6,3,1.5,0.75」の組み合わせで全部足すと96dBに
なるところからきます。

エンベロープはAttack、Decay、Sustain、Release、Sustain Level、Total Levelで計算します。
ピアノの鍵盤を叩くと瞬間的に最大音量まで上がり、最大まで行くと少し下がって安定し、そこから時間の経過で
少しずつ音量が下がり、鍵盤を離すと少し加速して音量が下がり無音に戻ります。
鍵盤を叩き瞬間的に最大音量まで上がる速度をAttackで指定し、その時の最大音量をTotal Levelで指定します。
最大まで行くと少し下がって安定するまでの速度をDecayで指定し、その時の安定する音量をSustain Levelで指定します。
時間の経過で少しずつ音量が下がる速度をSustainで指定します。
鍵盤を離してから無音になるまでの速度をReleaseで指定します。

■KeyOn、KeyOff
スロット毎に音のオン、オフを指定でき、音を出し始める時の指定をKeyOn、音を止める時をKeyOnと呼びます。

■キースケール
Attackなどでのエンベロープの計算でキーコードを反映することでより自然な音を作り出します。
キースケールは0~3の4段階の指定ができます。
0の時はキーコードを1/8した整数値をAttackに加算します。(0~3)、結果が0の時はキースケールを機能させません。
1の時はキーコードを1/4した整数値をAttackに加算します。(0~7)
2の時はキーコードを1/2した整数値をAttackに加算します。(0~15)
3の時はキーコードを1/1した整数値をAttackに加算します。(0~31)

■Attack、Total Level
エンベロープもカウンタをもち、KeyOnのタイミングでカウンタを0に初期化し、スロットを実行する毎にAttackで指定した値を加算し、
カウンタがオーバーフローしたら次のDecayに移行します。
カウンタは音量の割合を示し、カウンタ0は音量0%、カウンタの最大値は音量100%となります。
この割合にTotal Levelで指定した最大音量を掛けることで発生する音量を決定します。
カウンタのサイズはマニュアルで書いてはありませんが、20bitで求めるLFOのAMSを反映する事を考えると同じで20bitであることが合理的です。
Attackは32段階で指定が大きいほど早く最大音量になります(カウンタの加算値が大きい)。0を指定すると音は出ません(カウンタの加算がゼロ)。
Attackはキースケールを組み合わせて音量を決定します。
「(Attack * 2) + キースケール」となります。Attack(32段階)を2倍した値にキースケール(32段階)を加算した値なので
合計で96段階となります。63段階目が最大値で63より大きい場合は全て63段階目と同じ値になります。
Attackの指定でカウンタを上げる値は上の段階に上がる度に指数関数的に増えます。Attack値が大きいほど早く最大値に上がります。
ここの計算値はマニュアルには記載がなく不明です。わからないので先人の知恵を参考に
本エミュレータでは「1.476751 * Math.Exp(0.17438 * x)」という適当な計算をしています。
0~3段階目は0、64~95段階目は63段階目の値をコピーします。

■Decay、Sustain Level
AttackからDecayに移行する際にカウンタを0に初期化し、スロットを実行する毎にDecayで指定した値を加算し、
カウンタがオーバーフローしたら次のSustainに移行します。
カウンタ0は最大音量(0dB)で、カウンタの最大値は無音(-96dB)と考えます。
Decayは指定での加算する値は直線的に増える仕様なので、カウンタが20%時点は-19.2dBとなるので、
最大音量から-19.2dB下げるにはカウンタを20%まで進めればいいとなります。
つまりSustain Levelは音量を指定するのではなく、最大音量からの減衰量を指定します。
本エミュレータでは「1.476751 * Math.Exp(0.17438 * x)/14」という適当な計算をしています。

■Sustain
DecayからSustainに移行する際にカウンタを0に初期化し、スロットを実行する毎にSustainで指定した値を加算し、
カウンタがオーバーフローしたら次のReleaseに移行します。
カウンタ0はSustain Levelとなり、カウンタの最大値は無音(-96dB)と考えます。
Sustainのままであればカウンタの最大値になる前(カウンタの最大値 – Sustain Level)に無音(-96dB)になります。
無音(-96dB)になったらエンベロープ処理を終了します。
Sustainも指定での加算する値は直線的に増える仕様です。

■Release
Attack、Decay、Sustainのどの状態でもKeyOffでReleaseに移行します。
Sustainに移行する際にカウンタを0に初期化し、スロットを実行する毎にSustainで指定した値を加算し、
無音(-96dB)になったらエンベロープ処理を終了します。
カウンタ0は移行時点のカウンタ値となり、カウンタの最大値は無音(-96dB)と考えます。

アルゴリズム
フィードバック
SSG
AMON
出力
タイマ