プチコン3号の音周りの仕様について調べたメモです。
実機の動作を見ながら大体こんな感じかなーで書きなぐったものなので、正しさはその程度です。 動作の確認は、今のところ v3.5.2 で行っています。
間違い・質問などございましたら、twitter もしくは下の方のコメント欄にお願いします。
twitter: @myu314_petitcom
- 推敲、書き忘れ追加などなど
- 一定の再生スピードを超える発生する不具合について調査
内部シーケンサの TPQN は 48。
音長の計算で小数点以下は切り捨て。 付点の計算は、切り捨てた値に対して行われる。
R9 = [R192]21 'FLOOR(192/9)
R9. = [R192]31 'FLOOR(FLOOR(192/9) * 1.5)
R9..= [R192]36 'FLOOR(FLOOR(192/9) * 1.75)
T120 V127 @0 O4 L4 Q8
Vo = POW(V/128, 2)
Pan Law は square root、P=64 の時 -3dB。
Vo(L) = SQR(1-P/128)
Vo(R) = SQR(P/128)
Pitch(cent) += 100 * (@D / 64)
マニュアルには @D127 は1音(200cent)高くなると書かれているが、 実際は 198.4375cent で、1.5cent ほど低い。
音色変更コマンドは 次のキーオンのタイミングで音色を変更する。
C& @5C C = C&C @5C
[C& @5]2 C = C @5C& C
-
音符/休符の無いループはエラーになる
[ V100 ] 'Illegal MML
-
ループで戻った場合に復元される情報
V100 [C V50 C]2 C = V100 C V50 C V100 C V50 C C @0 [C @5 C]2 C = @C C @5 CCC
QコマンドとVコマンドは、おそらくノート情報に埋め込まれるため、ループしても1度目と同じように演奏される。 それ以外の命令はループで戻っても情報は復元されない。
音の長さを全体の Q/8
だけ鳴らし、残りを休む。スタッカートなどの表現に使う。Q=0 の時は 192分音符の長さで演奏される。
Qコマンドは2つの音を1つの音として扱う&コマンドを除いて、タイやポルタメントには影響しない。
Q4C2 = Q4C4&C4 = Q8C4R4
Q4C4& C4 = Q8C2 Q4
Q4C_G = Q8C_G Q4
&コマンドは 実際には2種類ある。
-
2つの音を1つの音として扱う
C2&C4
のように同じ音程の音を スペースや他のコマンドを挟まずに &でつなぐと、 2つの音を1つの音として扱う。この場合C2.
と見なす。 -
MML上の次の音を、キーオン無しで演奏するノートと見なす
上記を踏まえると次のような動作となる。
C4&C4_G 'C2_G と同じ。2拍でCからGまで滑らかに鳴らす
C4& C4_G '1拍Cを伸ばし、1拍でCからGまで滑らかに鳴らす。上との違いは&の後のスペースだけ
[C&]3G 'CCC&G と同じ。C& の MML上の次の音はループ後のG
C&@5DE 'C&D@5E と同じ。C& の後のDは キーオン無しのノートなので、音色変更はEから反映される
[C&@5]2D 'C@5C&D と同じ。ループ2回目のCは通常のノートなので、音色変更が反映される
特に C& C4_G
のように スペースの有無で挙動が変わる点に注意。
-
MMLの見かけ上の前の音に&がついている
-
演奏中直前のノートに&がついている
C&[C&] 'Cの音が鳴りっぱなしになる C&[C] 'C&C [C] と同じ。ループ2回目のCは条件2を満たしていない [C&]2C 'CC&C と同じ。ループ2回目のC&は条件1を満たしてない
おそらくシーケンスデータのノートデータには次のフラグが用意されてるのではないかな…。
- 自分自身に&が付いている
- MMLの見かけ上の前の音に&が付いている
音程1[音長1]_音程2[音長2]
音程1から音程2まで、音長1の長さで滑らかに鳴らしたあと、音程2を音長2の長さ維持する。 音長2は指定されていない場合0(=長さ無し)として扱う。
-
ポルタメントコマンドの間にループは挟めない
[C_]G 'Illegal MML
-
ポルタメントの後の音程に音長をつけた場合、 滑らかに繋いだあと後の音程を音長分伸ばす
L4 C_G = 1拍でCからGまで滑らかに鳴らす L4 C_G = 1拍でCからGまで滑らかに鳴らしたあと、Gのまま1拍伸ばす
-
ポルタメントの前後の音程の間に入れた V,P,@,@MP,@MA,@ML,@D などのコマンドは、ポルタメント開始地点から反映される
L4 C_ @1G = @1 C_G L4 C&C_@D-128G = @D-128C2_G = >B-2_<F L4 C& C_@D-128G = C& @D-128C_G = C&>B-_<F
-
Depth
-
Range
モジュレーションのかかり具合
Range * Depth / 128
-
Speed
LFOの周波数
LFO freq(Hz) = Speed / 2.5
-
Delay
変調し始めるまでの時間
Delay time(sec) = 2.5 * Delay / 128
W ... Range * Depth / 128
F ... Speed / 2.5
t ... 時間
PI2 ... PI() * 2
TRI ... SINの三角波版みたいな関数
-
@MP: Pitch modulation
W=1 の時、±100centの幅でビブラートがかかる。
Pitch(cent) += 100 * W * SIN(F * t * PI2)
-
@MA: Amp modulation
振れ幅が [W*0.5 .. W*2.0] になるような波形。 2を超えた場合、クリッピング。
Vo *= MIN(2, POW(2, W * SIN(F * t * PI2)))
-
@ML: Panpot modulation
W=1, P=64 の時、丁度P0-P127を滑らかに変化する……(64-0 != 127-64 なのでちょっとだけずれるけど)
Pan += 64 * W * TRI(F * t * PI2)
- テンポに依存しない
- キーオンごとにリセットされる (…のでオートパンとしては使い辛い)
- リリース音にもモジュレーションはかかる
P = 160 / 32728
-
音量
Vo = POW(4*t, 4) / (1 + POW(4*t, 4))
-
時間
0<= i <= 108
A=2570*P B=-1/32 T[i] = A / (i + 1) + B
108 < i <= 127
T[i] = T[108] * (127 - i) / (127 - 108)
-
音量
A = 1/128 Vo *= (POW(A,t) - A) / (1 - A)
-
時間
0<= i <= 50 の時
A=64050*P T[i] = A / (2 * i + 1)
50 < i < 126 の時
T[i] = T[50] * (126 - i) / (126 - 50)
126<= i
T[126] = 4 * P T[127] = P
V コマンドと同じ。
Vo *= POW(DL / 128, 2)
Decay の音量が Vo に到達した時点で減衰は打ち切られる。
Decay Time は減衰しきる(音量が0になる)までにかかる時間を表す。 減衰中に音量が Decay Level に到達したらそこからキーオフまで現在の音量を維持する。 この時の t を p とする。 つまり実際の減衰時間は Decay Level に依存する。
Releaseの音量計算に使う t は Decay のものを引き継ぐので、0 ではなく p から始まる。 Release Time は t が p から 1 まで変化する時間を表す。 Decay Level によって減衰するカーブは変化するが、0になるまでの時間は変化しない。
-
TPQN=48
-
160サンプル毎にシーケンスデータは処理される。
次のMMLのように同一のタイミングでキーオン/オフが発生した場合、音は鳴らない。
'T256 で 192分音符は 159.80...サンプルとなり 160サンプルより僅かに短い @E127,127,127,127 T256 C192
またこの仕様上、波形は必ず160サンプル単位で出力される。
-
sampling rate = 32728 Hz
-
samples per audio frame = 160
音情報が更新される間隔
- WAVSET は 基準音程 33 の時、GMセットと同じ高さになる
-
配列サイズが 2^n (n=4..14) ではない時、リサンプリングされる
-
配列サイズが 8193〜16383 の時、ループ範囲が正しく設定されない(BUG?)
-
配列のサイズによって音程が変わる
nが1大きくなると1オクターブ下がり、小さくなると上がる。 n=8(256)の時 WAVSET と同じになる。