YM2151の使い方
注意:このサイトの内容を鵜呑みにし、事故や損失を招いた場合でも当方は一切の責任は負いかねます。自己責任でお願いします。
YM2151は4オペレータのFM音源IC (OPM)です。(LSIですが便宜上ICと呼びます。)
X68KやMSX拡張シンセサイザユニット「YAMAHA SFG-01」などに用いられていました。
アーケードゲームなどにもよく用いられていたようで、中古品も割と豊富に出回っているため、入手は比較的容易です。
ただし、某オークションサイト等では偽物も多く出回っているため、注意が必要です。
確実に本物のYM2151を入手したい場合、アーケード基板を購入して部品取りをして利用すると良いでしょう。
本物を手軽に入手したい場合、東京ラジオデパートの1Fでガチャガチャ方式で販売している"FM音源伝説"がおすすめです。(動作保証していなく、故障している可能性もあります。注意してください。)
YM2151単体では、音を出すことはできず、YM3012などの専用のDACが必要です。
・YM2151の特徴
・4オペレータ8アルゴリズム、同時発音数 : 8
・24ピンDIP
・ハードウェアエンベロープ
・ハードウェアLFO
・ノイズジェネレータ
・ピン配置
ピン番号 | 名称 | I/O | 機能 |
---|---|---|---|
1 | VSS(GND) | - | グランド端子です。 |
2 | ~IRQ | O | 割り込み要求端子です。 内部タイマーカウンタにより、割り込み要求がされるようです。 オープンドレイン出力なので、プルアップ抵抗が必要になります。 |
3 | ~IC | I | リセット端子です。 この端子がLの期間、内部レジスタを初期化します。 |
4 | A0 | I | アドレス / データセレクト端子です。 この端子がLの場合、D0~D7はアドレス入力端子となります。 Hの場合、D0~D7はデータ入力端子となります。 |
5 | ~WR | I | ライト端子です。 この端子がLでかつ、「~CS」がLの期間、 D0~D7端子の状態が内部レジスタへラッチされます。 |
6 | ~RD | I | リード端子です。 この端子がLでかつ、「A0」がHでかつ、「~CS」がLの期間、 内部ステータスレジスタの状態がD0~D7端子へラッチされます。 |
7 | ~CS | I | チップセレクト端子です。 この端子がLの期間、「~WR」または「~RD」端子がLの時、 書き込み・読み込みができます。 |
8 | CT1 | O | 汎用出力端子です。 $1Bのbit7に割り当てられています。 |
9 | CT2 | O | 汎用出力端子です。 $1Bのbit6に割り当てられています。 |
10 | D0 | I/O | データピンです。 |
11 | VSS(GND) | - | グランド端子です。 |
12 | D1 | I/O | データピンです。 |
13 | D2 | I/O | データピンです。 |
14 | D3 | I/O | データピンです。 |
15 | D4 | I/O | データピンです。 |
16 | D5 | I/O | データピンです。 |
17 | D6 | I/O | データピンです。 |
18 | D7 | I/O | データピンです。 |
19 | SH2 | O | チャンネル2のアナログ出力ホールド端子です。 チャンネル1のデータラッチ信号としても使います。(要検証) YM3012などのDACへ接続します。 |
20 | SH1 | O | チャンネル1のアナログ出力ホールド端子です。 チャンネル2のデータラッチ信号としても使います。(要検証) YM3012などのDACへ接続します。 |
21 | SO | O | シリアルデータ出力端子です。 YM3012などのDACへ接続します。 |
22 | VDD(+5V) | - | 電源端子です。 +5Vの電源を用意してください。 |
23 | Φ1 | O | クロック出力端子です。 YM3012などのDACへ接続します。 |
24 | ΦM | I | クロック入力端子です。 標準で3.58MHzを入力します。 最大で4.0MHzまで入力できます。 |
・YM2151のレジスタ(書き込み専用)
YM2151は$00~$FFの256バイトのレジスタを持っています。
アドレス |
レジスタ名 | 機能 | ||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
$00 | - | 未使用 | ||||||||||||||||||||||||||||||||||||||||||||||||||||
$01 | TEST | テスト用のレジスタです。
TEST_0 ~ TEST_6 には常に0を書き込んだ状態にしてください。 LFO_RESET: このビットをHにすると、LFOが停止します。 LFO = H : LFOの停止 LFO = L : LFOを動作(位相がリセットされます。) |
||||||||||||||||||||||||||||||||||||||||||||||||||||
$02~07 | - | 未使用 | ||||||||||||||||||||||||||||||||||||||||||||||||||||
$08 | KON | KEY ON キーオン・キーオフレジスタです。
SN: スロット番号です。 オペレータのオンオフを指定します。 SN = H : キーオン SN = L : キーオフ SN_0 : M1(OP1) SN_1 : C1(OP2) SN_2 : M2(OP3) SN_3 : C2(OP4) CH: チャンネル番号を指定します。 CH = 0~7(0x0~0x7) : キーオン・キーオフしたいチャンネル CH1~CH8 |
||||||||||||||||||||||||||||||||||||||||||||||||||||
$09~$0E | - | 未使用 | ||||||||||||||||||||||||||||||||||||||||||||||||||||
$0F | NOISE | Noise Generator ノイズジェネレータの設定レジスタです。
NE: ノイズ有効無効ビットです。 有効にすると、スロット32(CH8のC2)がノイズジェネレータと入れ替わります。 NE = L : 無効 NE = H :有効 NFRQ: ノイズ周波数決定ビットです。 fn = ΦM / (32 * NFRQ) [Hz] fn : ノイズ周波数[Hz] ΦM : 入力クロック周波数[Hz] NFRQ = 0~31(0x00~0x1F) :ノイズ周波数決定ビット |
||||||||||||||||||||||||||||||||||||||||||||||||||||
$10 | CLKA1 | 内部タイマーAの設定値10bit中の上位8bitです。 CLKA2($11)に下位2bitをセットします。
NA: タイマーAの設定値です。 Ta = 64 * (1024 - NA) / ΦM [s] Ta : タイマーAオーバーフロー周期[s] NA = 0~1023(0x000~0x3FF) :タイマー周期決定ビット ΦM : 入力クロック周波数[Hz] |
||||||||||||||||||||||||||||||||||||||||||||||||||||
$11 | CLKA2 | 内部タイマーAの設定値10bit中の下位2bitです。 CLKA1($10)に上位8bitをセットします。
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
$12 | CLKB | 内部タイマーBの設定値8bitです。
CLKB: タイマーBの設定値です。 Tb = 1024 * (256 - CLKB) / ΦM [s] Tb : タイマーAオーバーフロー周期[s] CLKB = 0~255(0x00~0xFF) :タイマー周期決定ビット ΦM : 入力クロック周波数[Hz] |
||||||||||||||||||||||||||||||||||||||||||||||||||||
$13 | - | 未使用 | ||||||||||||||||||||||||||||||||||||||||||||||||||||
$14 | TIM_CONF | 内部タイマーの動作設定ビット群です。
CSM: このビットをHにすると、タイマーAのオーバーフロービットがHの時に、 すべてのスロットをキーオンします。 F_RESET: このビットにHを書き込むと、タイマーのオーバーフロービットをクリアします。 Lを書き込んだ場合、変化しません。 F_RESET_A <- H : タイマーAのオーバーフロービットをクリア F_RESET_B <- H : タイマーBのオーバーフロービットをクリア IRQ_EN: このビットをHにすると、タイマーがオーバーフローした時に、割り込み要求出力をします。 IRQ_EN_A = H : タイマーAによる割り込み要求出力を有効 IRQ_EN_B = H : タイマーBによる割り込み要求出力を有効 LOAD: このビットをHにすると、タイマーが動作します。Lにすると、停止します。 LOAD_A = H : タイマーAを動作させる。 LOAD_B = H : タイマーBを動作させる。 |
||||||||||||||||||||||||||||||||||||||||||||||||||||
$15~$17 | - | 未使用 | ||||||||||||||||||||||||||||||||||||||||||||||||||||
$18 | LFRQ | LOW FREQUENCY LFO周波数設定レジスタです。
LFRQ: LFRQ = 0~255 (0x00~0xFF) : LFO発振周波数決定レジスタ (入力クロック周波数 ΦM = 3.579545Mhzの場合、0.0008Hz~52.9127hz) LFRQにセットする値が大きいほど発振周波数が高くなります。 |
||||||||||||||||||||||||||||||||||||||||||||||||||||
$19 | PMD_AMD | PHASE MODULATION DEPTH / AMPLITUDE MODULATION DEPTH 位相変調・振幅変調深度設定レジスタです。
LFO_MD_F: 変調データのセット選択ビットです。LFO_MD_0~LFO_MD_6のデータのセット先を決定します。 LFO_MD_F = H : PMD(位相変調深度レジスタへ書き込み) LFO_MD_F = L : AMD(振幅変調深度レジスタへ書き込み) LFO_MD: 変調深度をセットします。 PMDの場合、2の補数でセットします。 AMDの場合、補数なしでセットします。 LFO_MD = -64 ~ 63 (0x40 ~ 0x3F): PMD深度のセット(LFO_MD_F = H) LFO_MD = 0~127 (0x00 ~ 0x7F): AMD深度のセット(LFO_MD_F = L) |
||||||||||||||||||||||||||||||||||||||||||||||||||||
$1A | - | 未使用 | ||||||||||||||||||||||||||||||||||||||||||||||||||||
$1B | CT_W | CONTROL OUTPUT / WAVE FORM 汎用端子出力ビット・LFO変調波形設定レジスタです。
CT: 汎用出力ポートに出力する値をセットします。 CT1 = H or L : CT1端子(8pin)にHまたはLを出力します。 CT2 = H or L : CT2端子(9pin)にHまたはLを出力します。 LFO_W: LFO変調波形決定ビットです。
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
$1C~$1F | - | 未使用 | ||||||||||||||||||||||||||||||||||||||||||||||||||||
$20~27 | LR_FB_CON | チャンネル出力・フィードバック・アルゴリズム設定レジスタです。 $20~$27にCH1~CH8が割り当てられています。
RL: LEFT CHANNEL ENABLE / RIGHT CHANNEL ENABLE LまたはRチャンネルの出力を決定します。 RL_R = H : Rチャンネルの出力を有効にします。 RL_L = H : Lチャンネルの出力を有効にします。 FL: SELF FEEDBACK LEVEL M1(OP1)のフィードバックレベルを指定します。 Fb_level = π * (2 ^ (-5 + FL)) ※FL ≠ 0 Fb_leve : フィードバックレベル FL = 0~7 (0x0 ~ 0x7) : フィードバックレベル設定ビット(FL = 0のときのみ Fb_level = 0) CONECT: CONNECTION コネクションを設定します。
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
$28~$2F | KC | KEY CODE 音程設定レジスタです。 $28~$2FにCH1~CH8が割り当てられています。
OCT: オクターブ設定ビットです。 OCT = 0~7 (0x0 ~ 0x7) : 音程のセット NOTE: ノート設定ビットです。 入力クロックΦM = 3.579545MHzの場合
-- 出力周波数foutとOCT, NOTEの関係 -- ΦM = 3.579545MHz , OCT = 4 , NOTE =10 の時、440Hz(A)を出力 n = NOTE - ( (NOTE - ((NOTE-1)/3) ) / 3) ※nを求める場合のみ剰余は切り捨てで演算 fout = 440 * ( 2 ^ (-4 + OCT + (n - 8)/12 ) ) *(ΦM / 3579545) = ( 2 ^ (OCT + (n/12)) ) * ΦM * (11 / 1431818) * (2 ^ (-8/12)) = ( 2 ^ (OCT + (n/12)) ) * ΦM * (1 / 206624) = ( 2 ^ (OCT + (n/12)) ) * ΦM * (4.83970μ) [Hz] OCT : オクターブ設定ビット NOTE : ノート設定ビット n : ノート設定ビットから求めた音階(NOTE=0~14 → n=0~11) ΦM : 入力クロック周波数[Hz] |
||||||||||||||||||||||||||||||||||||||||||||||||||||
$30~$37 | KF | KEY FRACTION キーフラクション(音程の微調整)レジスタです。 $30~$37にCH1~CH8が割り当てられています。
KF: キーフラクションビットです。 KF = 0~63 (0x00 ~ 0x3F) : キーフラクションのセット KFが1つ大きくなるごとに音程が1.6(100/64)セント上がります。 |
||||||||||||||||||||||||||||||||||||||||||||||||||||
$38~$3F | PMS_AMS | PHASE MODULATION SENSITIVITY / AMPLITUDE MODULATION SENSITIVITY LFO位相変調・振幅変調感度設定レジスタです。 このレジスタではチャンネルごとにLFOの感度を設定できます。 $38~$3FにCH1~CH8が割り当てられています。
PMS: LFO位相変調感度設定ビットです。 PMS = 0~7 (0x0 ~ 0x7) : PMS感度のセット
AMS: LFO振幅変調感度設定ビットです。 $A0~$BFの「AMS_EN」ビットがHのとき、LFOによる振幅変調がかかります。 最大振幅変調度 AMS = 0 : 0dB AMS = 1 : 23.90625dB AMS = 2 : 47.8215dB AMS = 3 : 95.625dB |
||||||||||||||||||||||||||||||||||||||||||||||||||||
$40~5F | DT1_MUL | DETUNE(1) / PHASE MULTIPLY スロット倍率微調整・スロット倍率設定レジスタです。 $40~$5FにSLOT1~SLOT32が割り当てられています。
DT1: スロット周波数の倍率微調整ビットです。 数セント程度のデチューンができます。 DT1 = 0~7 (0x0 ~ 0x7) : デチューンのセット MUL: スロット周波数の倍率設定ビットです。 MUL = 0~15 (0x0 ~ 0xF) :スロット倍率のセット Ns = MUL (MUL ≠ 0) Ns = 1/2 (MUL = 0) Ns : 基本周波数からの倍率[倍] |
||||||||||||||||||||||||||||||||||||||||||||||||||||
$60~$7F | TL | TOTAL LEVEL スロット出力レベル設定レジスタです。 $60~$7FにSLOT1~SLOT32が割り当てられています。
TL: スロット出力レベル設定レジスタです。 TL = 0で最大信号レベル、127で最小信号レベルとなります。 TL = 0~127 (0x00 ~ 0x7F) : スロット出力レベルのセット 減衰量Atlは、 Atl = 0.75 * TL [dB] となります。 |
||||||||||||||||||||||||||||||||||||||||||||||||||||
$80~$9F | KS_AR | KEY SCALING / ATTACK RATE ピッチによるエンベロープ補正・エンベロープアタックレート設定レジスタです。 $80~$9FにSLOT1~SLOT32が割り当てられています。
KS: ピッチによるエンベロープ時間補正ビットです。 実際の楽器の場合、ピッチが高くなるにつれ、エンベロープ時間が短くなります。 このビットは、この特性を再現するためのビットです。 KS = 0~3 (0x0 ~ 0x3) : ピッチによるエンベロープ時間補正のセット(値が大きいほどエンベロープ時間を短くします。) AR: 出力レベルのエンベロープ制御する際のアタック時間を設定するビットです。 この値が小さいほどアタック時間が増加します。 AR = 0~31 (0x0 ~ 0x1F) : アタック時間のセット |
||||||||||||||||||||||||||||||||||||||||||||||||||||
$A0~$BF | AMS_EN_D1R | AMPLITUDE MODULATION SENSITIVITY ENABLE / FIRST DECAY RATE AMS有効フラグ・エンベロープファーストディケイレート設定レジスタです。 $80~$9FにSLOT1~SLOT32が割り当てられています。
AMS_EN: スロットLFO振幅変調有効無効設定ビットです。 有効にすると、LFOより振幅変調を行います。振幅変調深度は、$37~$3Fにある「PMS_AMS」レジスタのbit0, bit1で決めます。 AMS_EN = H : AMS有効 AMS_EN = L : AMS無効 D1R: 出力レベルのエンベロープ制御する際のファーストディケイ時間(ファーストディケイレベルまで移行する時間)を設定するビットです。 この値が小さいほどファーストディケイ時間が増加します。 D1R = 0~31 (0x00 ~ 0x1F) : ファーストディケイ時間のセット |
||||||||||||||||||||||||||||||||||||||||||||||||||||
$C0~$DF | DT2_D2R | DETUNE(2) / SECOND DECAY RATE スロット倍率粗調整・エンベロープセカンドディケイレート設定レジスタです。 $C0~$DFにSLOT1~SLOT32が割り当てられています。
DT2: スロット周波数の倍率粗調整ビットです。 数セント程度のデチューンができます。 DT2 = 0~3 (0x0 ~ 0x3) : デチューンのセット
D2R: 出力レベルのエンベロープ制御する際のセカンドトディケイ時間(0レベルまで移行する時間)を設定するビットです。 この値が小さいほどセカンドディケイ時間が増加します。 D2R = 0~31 (0x00 ~ 0x1F) : セカンドトディケイ時間のセット |
||||||||||||||||||||||||||||||||||||||||||||||||||||
$EF~$FF | D1L_RR | FIRST DECAY LEVEL / RELEASE RATE エンベロープファーストディケイレベル・エンベロープセカンドディケイレート設定レジスタです。 $C0~$DFにSLOT1~SLOT32が割り当てられています。
D1L: 出力レベルのエンベロープ制御する際のファーストディケイレベル(ファーストディケイ時間経過後の出力レベル)を設定するビットです。 この値が小さいほどファーストディケイレベルが大きくなります。 D1L = 0~15 (0x0 ~ 0xF) : ファーストディケイレベルのセット ファーストディケイレベルfdl[dB]は、 fdl = -3 * D1L [dB] : ※D1L ≠ 0xF fdl = -3 * D1L -48 [dB] : ※D1L = 0xF となります。 RR: 出力レベルのエンベロープ制御する際のリリース時間(キーオフ後に出力レベルが0移行するまでのに時間)を設定するビットです。 この値が小さいほどリリース時間が増加します。 RR = 0~15 (0x0 ~ 0xF) : リリース時間のセット |
レジスタマップ
YM2151の内部レジスタのレジスタマップ(ビットマップ)です。
"レジスタビット名"_"ビット名またはチャンネルNO.またはスロットNO."_"第何ビット"
の形で表しています。
bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 | |
---|---|---|---|---|---|---|---|---|
$00 | ||||||||
$01 | TEST_6 | TEST_5 | TEST_4 | TEST_3 | TEST_2 | TEST_1 | LFO_RESET | TEST_0 |
$02 | ||||||||
$03 | ||||||||
$04 | ||||||||
$05 | ||||||||
$06 | ||||||||
$07 | ||||||||
$08 | SN_3 | SN_2 | SN_1 | SN_0 | CH_2 | CH_1 | CH_0 | |
$09 | ||||||||
$0A | ||||||||
$0B | ||||||||
$0C | ||||||||
$0D | ||||||||
$0E | ||||||||
$0F | NE | NFRQ_4 | NFRQ_3 | NFRQ_2 | NFRQ_1 | NFRQ_0 | ||
$10 | NA_9 | NA_8 | NA_7 | NA_6 | NA_5 | NA_4 | NA_3 | NA_2 |
$11 | NA_1 | NA_0 | ||||||
$12 | CLKB_7 | CLKB_6 | CLKB_5 | CLKB_4 | CLKB_3 | CLKB_2 | CLKB_1 | CLKB_0 |
$13 | ||||||||
$14 | CSM | F_RESET_B | F_RESET_A | IRQ_EN_B | IRQ_EN_A | LOAD_B | LOAD_A | |
$15 | ||||||||
$16 | ||||||||
$17 | ||||||||
$18 | LFRQ_7 | LFRQ_6 | LFRQ_5 | LFRQ_4 | LFRQ_3 | LFRQ_2 | LFRQ_1 | LFRQ_0 |
$19 | LFO_MD_F | LFO_MD_6 | LFO_MD_5 | LFO_MD_4 | LFO_MD_3 | LFO_MD_2 | LFO_MD_1 | LFO_MD_0 |
$1A | ||||||||
$1B | CT2 | CT1 | LFO_W_1 | LFO_W_0 | ||||
$1C | ||||||||
$1D | ||||||||
$1E | ||||||||
$1F | ||||||||
$20 | RL_CH1_R | RL_CH1_L | FL_CH1_2 | FL_CH1_1 | FL_CH1_0 | CONECT_CH1_2 | CONECT_CH1_1 | CONECT_CH1_0 |
$21 | RL_CH2_R | RL_CH2_L | FL_CH2_2 | FL_CH2_1 | FL_CH2_0 | CONECT_CH2_2 | CONECT_CH2_1 | CONECT_CH2_0 |
$22 | RL_CH3_R | RL_CH3_L | FL_CH3_2 | FL_CH3_1 | FL_CH3_0 | CONECT_CH3_2 | CONECT_CH3_1 | CONECT_CH3_0 |
$23 | RL_CH4_R | RL_CH4_L | FL_CH4_2 | FL_CH4_1 | FL_CH4_0 | CONECT_CH4_2 | CONECT_CH4_1 | CONECT_CH4_0 |
$24 | RL_CH5_R | RL_CH5_L | FL_CH5_2 | FL_CH5_1 | FL_CH5_0 | CONECT_CH5_2 | CONECT_CH5_1 | CONECT_CH5_0 |
$25 | RL_CH6_R | RL_CH6_L | FL_CH6_2 | FL_CH6_1 | FL_CH6_0 | CONECT_CH6_2 | CONECT_CH6_1 | CONECT_CH6_0 |
$26 | RL_CH7_R | RL_CH7_L | FL_CH7_2 | FL_CH7_1 | FL_CH7_0 | CONECT_CH7_2 | CONECT_CH7_1 | CONECT_CH7_0 |
$27 | RL_CH8_R | RL_CH8_L | FL_CH8_2 | FL_CH8_1 | FL_CH8_0 | CONECT_CH8_2 | CONECT_CH8_1 | CONECT_CH8_0 |
$28 | OCT_CH1_2 | OCT_CH1_1 | OCT_CH1_0 | NOTE_CH1_3 | NOTE_CH1_2 | NOTE_CH1_1 | NOTE_CH1_0 | |
$29 | OCT_CH2_2 | OCT_CH2_1 | OCT_CH2_0 | NOTE_CH2_3 | NOTE_CH2_2 | NOTE_CH2_1 | NOTE_CH2_0 | |
$2A | OCT_CH3_2 | OCT_CH3_1 | OCT_CH3_0 | NOTE_CH3_3 | NOTE_CH3_2 | NOTE_CH3_1 | NOTE_CH3_0 | |
$2B | OCT_CH4_2 | OCT_CH4_1 | OCT_CH4_0 | NOTE_CH4_3 | NOTE_CH4_2 | NOTE_CH4_1 | NOTE_CH4_0 | |
$2C | OCT_CH5_2 | OCT_CH5_1 | OCT_CH5_0 | NOTE_CH5_3 | NOTE_CH5_2 | NOTE_CH5_1 | NOTE_CH5_0 | |
$2D | OCT_CH6_2 | OCT_CH6_1 | OCT_CH6_0 | NOTE_CH6_3 | NOTE_CH6_2 | NOTE_CH6_1 | NOTE_CH6_0 | |
$2E | OCT_CH7_2 | OCT_CH7_1 | OCT_CH7_0 | NOTE_CH7_3 | NOTE_CH7_2 | NOTE_CH7_1 | NOTE_CH7_0 | |
$2F | OCT_CH8_2 | OCT_CH8_1 | OCT_CH8_0 | NOTE_CH8_3 | NOTE_CH8_2 | NOTE_CH8_1 | NOTE_CH8_0 | |
$30 | KF_CH1_5 | KF_CH1_4 | KF_CH1_3 | KF_CH1_2 | KF_CH1_1 | KF_CH1_0 | ||
$31 | KF_CH2_5 | KF_CH2_4 | KF_CH2_3 | KF_CH2_2 | KF_CH2_1 | KF_CH2_0 | ||
$32 | KF_CH3_5 | KF_CH3_4 | KF_CH3_3 | KF_CH3_2 | KF_CH3_1 | KF_CH3_0 | ||
$33 | KF_CH4_5 | KF_CH4_4 | KF_CH4_3 | KF_CH4_2 | KF_CH4_1 | KF_CH4_0 | ||
$34 | KF_CH5_5 | KF_CH5_4 | KF_CH5_3 | KF_CH5_2 | KF_CH5_1 | KF_CH5_0 | ||
$35 | KF_CH6_5 | KF_CH6_4 | KF_CH6_3 | KF_CH6_2 | KF_CH6_1 | KF_CH6_0 | ||
$36 | KF_CH7_5 | KF_CH7_4 | KF_CH7_3 | KF_CH7_2 | KF_CH7_1 | KF_CH7_0 | ||
$37 | KF_CH8_5 | KF_CH8_4 | KF_CH8_3 | KF_CH8_2 | KF_CH8_1 | KF_CH8_0 | ||
$38 | PMS_CH1_2 | PMS_CH1_1 | PMS_CH1_0 | AMS_CH1_1 | AMS_CH1_0 | |||
$39 | PMS_CH2_2 | PMS_CH2_1 | PMS_CH2_0 | AMS_CH2_1 | AMS_CH2_0 | |||
$3A | PMS_CH3_2 | PMS_CH3_1 | PMS_CH3_0 | AMS_CH3_1 | AMS_CH3_0 | |||
$3B | PMS_CH4_2 | PMS_CH4_1 | PMS_CH4_0 | AMS_CH4_1 | AMS_CH4_0 | |||
$3C | PMS_CH5_2 | PMS_CH5_1 | PMS_CH5_0 | AMS_CH5_1 | AMS_CH5_0 | |||
$3D | PMS_CH6_2 | PMS_CH6_1 | PMS_CH6_0 | AMS_CH6_1 | AMS_CH6_0 | |||
$3E | PMS_CH7_2 | PMS_CH7_1 | PMS_CH7_0 | AMS_CH7_1 | AMS_CH7_0 | |||
$3F | PMS_CH8_2 | PMS_CH8_1 | PMS_CH8_0 | AMS_CH8_1 | AMS_CH8_0 | |||
$40 | DT1_SLOT1_2 | DT1_SLOT1_1 | DT1_SLOT1_0 | MUL_SLOT1_3 | MUL_SLOT1_2 | MUL_SLOT1_1 | MUL_SLOT1_0 | |
$41 | DT1_SLOT2_2 | DT1_SLOT2_1 | DT1_SLOT2_0 | MUL_SLOT2_3 | MUL_SLOT2_2 | MUL_SLOT2_1 | MUL_SLOT2_0 | |
$42 | DT1_SLOT3_2 | DT1_SLOT3_1 | DT1_SLOT3_0 | MUL_SLOT3_3 | MUL_SLOT3_2 | MUL_SLOT3_1 | MUL_SLOT3_0 | |
$43 | DT1_SLOT4_2 | DT1_SLOT4_1 | DT1_SLOT4_0 | MUL_SLOT4_3 | MUL_SLOT4_2 | MUL_SLOT4_1 | MUL_SLOT4_0 | |
$44 | DT1_SLOT5_2 | DT1_SLOT5_1 | DT1_SLOT5_0 | MUL_SLOT5_3 | MUL_SLOT5_2 | MUL_SLOT5_1 | MUL_SLOT5_0 | |
$45 | DT1_SLOT6_2 | DT1_SLOT6_1 | DT1_SLOT6_0 | MUL_SLOT6_3 | MUL_SLOT6_2 | MUL_SLOT6_1 | MUL_SLOT6_0 | |
$46 | DT1_SLOT7_2 | DT1_SLOT7_1 | DT1_SLOT7_0 | MUL_SLOT7_3 | MUL_SLOT7_2 | MUL_SLOT7_1 | MUL_SLOT7_0 | |
$47 | DT1_SLOT8_2 | DT1_SLOT8_1 | DT1_SLOT8_0 | MUL_SLOT8_3 | MUL_SLOT8_2 | MUL_SLOT8_1 | MUL_SLOT8_0 | |
$48 | DT1_SLOT9_2 | DT1_SLOT9_1 | DT1_SLOT9_0 | MUL_SLOT9_3 | MUL_SLOT9_2 | MUL_SLOT9_1 | MUL_SLOT9_0 | |
$49 | DT1_SLOT10_2 | DT1_SLOT10_1 | DT1_SLOT10_0 | MUL_SLOT10_3 | MUL_SLOT10_2 | MUL_SLOT10_1 | MUL_SLOT10_0 | |
$4A | DT1_SLOT11_2 | DT1_SLOT11_1 | DT1_SLOT11_0 | MUL_SLOT11_3 | MUL_SLOT11_2 | MUL_SLOT11_1 | MUL_SLOT11_0 | |
$4B | DT1_SLOT12_2 | DT1_SLOT12_1 | DT1_SLOT12_0 | MUL_SLOT12_3 | MUL_SLOT12_2 | MUL_SLOT12_1 | MUL_SLOT12_0 | |
$4C | DT1_SLOT13_2 | DT1_SLOT13_1 | DT1_SLOT13_0 | MUL_SLOT13_3 | MUL_SLOT13_2 | MUL_SLOT13_1 | MUL_SLOT13_0 | |
$4D | DT1_SLOT14_2 | DT1_SLOT14_1 | DT1_SLOT14_0 | MUL_SLOT14_3 | MUL_SLOT14_2 | MUL_SLOT14_1 | MUL_SLOT14_0 | |
$4E | DT1_SLOT15_2 | DT1_SLOT15_1 | DT1_SLOT15_0 | MUL_SLOT15_3 | MUL_SLOT15_2 | MUL_SLOT15_1 | MUL_SLOT15_0 | |
$4F | DT1_SLOT16_2 | DT1_SLOT16_1 | DT1_SLOT16_0 | MUL_SLOT16_3 | MUL_SLOT16_2 | MUL_SLOT16_1 | MUL_SLOT16_0 | |
$50 | DT1_SLOT17_2 | DT1_SLOT17_1 | DT1_SLOT17_0 | MUL_SLOT17_3 | MUL_SLOT17_2 | MUL_SLOT17_1 | MUL_SLOT17_0 | |
$51 | DT1_SLOT18_2 | DT1_SLOT18_1 | DT1_SLOT18_0 | MUL_SLOT18_3 | MUL_SLOT18_2 | MUL_SLOT18_1 | MUL_SLOT18_0 | |
$52 | DT1_SLOT19_2 | DT1_SLOT19_1 | DT1_SLOT19_0 | MUL_SLOT19_3 | MUL_SLOT19_2 | MUL_SLOT19_1 | MUL_SLOT19_0 | |
$53 | DT1_SLOT20_2 | DT1_SLOT20_1 | DT1_SLOT20_0 | MUL_SLOT20_3 | MUL_SLOT20_2 | MUL_SLOT20_1 | MUL_SLOT20_0 | |
$54 | DT1_SLOT21_2 | DT1_SLOT21_1 | DT1_SLOT21_0 | MUL_SLOT21_3 | MUL_SLOT21_2 | MUL_SLOT21_1 | MUL_SLOT21_0 | |
$55 | DT1_SLOT22_2 | DT1_SLOT22_1 | DT1_SLOT22_0 | MUL_SLOT22_3 | MUL_SLOT22_2 | MUL_SLOT22_1 | MUL_SLOT22_0 | |
$56 | DT1_SLOT23_2 | DT1_SLOT23_1 | DT1_SLOT23_0 | MUL_SLOT23_3 | MUL_SLOT23_2 | MUL_SLOT23_1 | MUL_SLOT23_0 | |
$57 | DT1_SLOT24_2 | DT1_SLOT24_1 | DT1_SLOT24_0 | MUL_SLOT24_3 | MUL_SLOT24_2 | MUL_SLOT24_1 | MUL_SLOT24_0 | |
$58 | DT1_SLOT25_2 | DT1_SLOT25_1 | DT1_SLOT25_0 | MUL_SLOT25_3 | MUL_SLOT25_2 | MUL_SLOT25_1 | MUL_SLOT25_0 | |
$59 | DT1_SLOT26_2 | DT1_SLOT26_1 | DT1_SLOT26_0 | MUL_SLOT26_3 | MUL_SLOT26_2 | MUL_SLOT26_1 | MUL_SLOT26_0 | |
$5A | DT1_SLOT27_2 | DT1_SLOT27_1 | DT1_SLOT27_0 | MUL_SLOT27_3 | MUL_SLOT27_2 | MUL_SLOT27_1 | MUL_SLOT27_0 | |
$5B | DT1_SLOT28_2 | DT1_SLOT28_1 | DT1_SLOT28_0 | MUL_SLOT28_3 | MUL_SLOT28_2 | MUL_SLOT28_1 | MUL_SLOT28_0 | |
$5C | DT1_SLOT29_2 | DT1_SLOT29_1 | DT1_SLOT29_0 | MUL_SLOT29_3 | MUL_SLOT29_2 | MUL_SLOT29_1 | MUL_SLOT29_0 | |
$5D | DT1_SLOT30_2 | DT1_SLOT30_1 | DT1_SLOT30_0 | MUL_SLOT30_3 | MUL_SLOT30_2 | MUL_SLOT30_1 | MUL_SLOT30_0 | |
$5E | DT1_SLOT31_2 | DT1_SLOT31_1 | DT1_SLOT31_0 | MUL_SLOT31_3 | MUL_SLOT31_2 | MUL_SLOT31_1 | MUL_SLOT31_0 | |
$5F | DT1_SLOT32_2 | DT1_SLOT32_1 | DT1_SLOT32_0 | MUL_SLOT32_3 | MUL_SLOT32_2 | MUL_SLOT32_1 | MUL_SLOT32_0 | |
$60 | TL_SLOT1_6 | TL_SLOT1_5 | TL_SLOT1_4 | TL_SLOT1_3 | TL_SLOT1_2 | TL_SLOT1_1 | TL_SLOT1_0 | |
$61 | TL_SLOT2_6 | TL_SLOT2_5 | TL_SLOT2_4 | TL_SLOT2_3 | TL_SLOT2_2 | TL_SLOT2_1 | TL_SLOT2_0 | |
$62 | TL_SLOT3_6 | TL_SLOT3_5 | TL_SLOT3_4 | TL_SLOT3_3 | TL_SLOT3_2 | TL_SLOT3_1 | TL_SLOT3_0 | |
$63 | TL_SLOT4_6 | TL_SLOT4_5 | TL_SLOT4_4 | TL_SLOT4_3 | TL_SLOT4_2 | TL_SLOT4_1 | TL_SLOT4_0 | |
$64 | TL_SLOT5_6 | TL_SLOT5_5 | TL_SLOT5_4 | TL_SLOT5_3 | TL_SLOT5_2 | TL_SLOT5_1 | TL_SLOT5_0 | |
$65 | TL_SLOT6_6 | TL_SLOT6_5 | TL_SLOT6_4 | TL_SLOT6_3 | TL_SLOT6_2 | TL_SLOT6_1 | TL_SLOT6_0 | |
$66 | TL_SLOT7_6 | TL_SLOT7_5 | TL_SLOT7_4 | TL_SLOT7_3 | TL_SLOT7_2 | TL_SLOT7_1 | TL_SLOT7_0 | |
$67 | TL_SLOT8_6 | TL_SLOT8_5 | TL_SLOT8_4 | TL_SLOT8_3 | TL_SLOT8_2 | TL_SLOT8_1 | TL_SLOT8_0 | |
$68 | TL_SLOT9_6 | TL_SLOT9_5 | TL_SLOT9_4 | TL_SLOT9_3 | TL_SLOT9_2 | TL_SLOT9_1 | TL_SLOT9_0 | |
$69 | TL_SLOT10_6 | TL_SLOT10_5 | TL_SLOT10_4 | TL_SLOT10_3 | TL_SLOT10_2 | TL_SLOT10_1 | TL_SLOT10_0 | |
$6A | TL_SLOT11_6 | TL_SLOT11_5 | TL_SLOT11_4 | TL_SLOT11_3 | TL_SLOT11_2 | TL_SLOT11_1 | TL_SLOT11_0 | |
$6B | TL_SLOT12_6 | TL_SLOT12_5 | TL_SLOT12_4 | TL_SLOT12_3 | TL_SLOT12_2 | TL_SLOT12_1 | TL_SLOT12_0 | |
$6C | TL_SLOT13_6 | TL_SLOT13_5 | TL_SLOT13_4 | TL_SLOT13_3 | TL_SLOT13_2 | TL_SLOT13_1 | TL_SLOT13_0 | |
$6D | TL_SLOT14_6 | TL_SLOT14_5 | TL_SLOT14_4 | TL_SLOT14_3 | TL_SLOT14_2 | TL_SLOT14_1 | TL_SLOT14_0 | |
$6E | TL_SLOT15_6 | TL_SLOT15_5 | TL_SLOT15_4 | TL_SLOT15_3 | TL_SLOT15_2 | TL_SLOT15_1 | TL_SLOT15_0 | |
$6F | TL_SLOT16_6 | TL_SLOT16_5 | TL_SLOT16_4 | TL_SLOT16_3 | TL_SLOT16_2 | TL_SLOT16_1 | TL_SLOT16_0 | |
$70 | TL_SLOT17_6 | TL_SLOT17_5 | TL_SLOT17_4 | TL_SLOT17_3 | TL_SLOT17_2 | TL_SLOT17_1 | TL_SLOT17_0 | |
$71 | TL_SLOT18_6 | TL_SLOT18_5 | TL_SLOT18_4 | TL_SLOT18_3 | TL_SLOT18_2 | TL_SLOT18_1 | TL_SLOT18_0 | |
$72 | TL_SLOT19_6 | TL_SLOT19_5 | TL_SLOT19_4 | TL_SLOT19_3 | TL_SLOT19_2 | TL_SLOT19_1 | TL_SLOT19_0 | |
$73 | TL_SLOT20_6 | TL_SLOT20_5 | TL_SLOT20_4 | TL_SLOT20_3 | TL_SLOT20_2 | TL_SLOT20_1 | TL_SLOT20_0 | |
$74 | TL_SLOT21_6 | TL_SLOT21_5 | TL_SLOT21_4 | TL_SLOT21_3 | TL_SLOT21_2 | TL_SLOT21_1 | TL_SLOT21_0 | |
$75 | TL_SLOT22_6 | TL_SLOT22_5 | TL_SLOT22_4 | TL_SLOT22_3 | TL_SLOT22_2 | TL_SLOT22_1 | TL_SLOT22_0 | |
$76 | TL_SLOT23_6 | TL_SLOT23_5 | TL_SLOT23_4 | TL_SLOT23_3 | TL_SLOT23_2 | TL_SLOT23_1 | TL_SLOT23_0 | |
$77 | TL_SLOT24_6 | TL_SLOT24_5 | TL_SLOT24_4 | TL_SLOT24_3 | TL_SLOT24_2 | TL_SLOT24_1 | TL_SLOT24_0 | |
$78 | TL_SLOT25_6 | TL_SLOT25_5 | TL_SLOT25_4 | TL_SLOT25_3 | TL_SLOT25_2 | TL_SLOT25_1 | TL_SLOT25_0 | |
$79 | TL_SLOT26_6 | TL_SLOT26_5 | TL_SLOT26_4 | TL_SLOT26_3 | TL_SLOT26_2 | TL_SLOT26_1 | TL_SLOT26_0 | |
$7A | TL_SLOT27_6 | TL_SLOT27_5 | TL_SLOT27_4 | TL_SLOT27_3 | TL_SLOT27_2 | TL_SLOT27_1 | TL_SLOT27_0 | |
$7B | TL_SLOT28_6 | TL_SLOT28_5 | TL_SLOT28_4 | TL_SLOT28_3 | TL_SLOT28_2 | TL_SLOT28_1 | TL_SLOT28_0 | |
$7C | TL_SLOT29_6 | TL_SLOT29_5 | TL_SLOT29_4 | TL_SLOT29_3 | TL_SLOT29_2 | TL_SLOT29_1 | TL_SLOT29_0 | |
$7D | TL_SLOT30_6 | TL_SLOT30_5 | TL_SLOT30_4 | TL_SLOT30_3 | TL_SLOT30_2 | TL_SLOT30_1 | TL_SLOT30_0 | |
$7E | TL_SLOT31_6 | TL_SLOT31_5 | TL_SLOT31_4 | TL_SLOT31_3 | TL_SLOT31_2 | TL_SLOT31_1 | TL_SLOT31_0 | |
$7F | TL_SLOT32_6 | TL_SLOT32_5 | TL_SLOT32_4 | TL_SLOT32_3 | TL_SLOT32_2 | TL_SLOT32_1 | TL_SLOT32_0 | |
$80 | KS_SLOT1_1 | KS_SLOT1_0 | AR_SLOT1_4 | AR_SLOT1_3 | AR_SLOT1_2 | AR_SLOT1_1 | AR_SLOT1_0 | |
$81 | KS_SLOT2_1 | KS_SLOT2_0 | AR_SLOT2_4 | AR_SLOT2_3 | AR_SLOT2_2 | AR_SLOT2_1 | AR_SLOT2_0 | |
$82 | KS_SLOT3_1 | KS_SLOT3_0 | AR_SLOT3_4 | AR_SLOT3_3 | AR_SLOT3_2 | AR_SLOT3_1 | AR_SLOT3_0 | |
$83 | KS_SLOT4_1 | KS_SLOT4_0 | AR_SLOT4_4 | AR_SLOT4_3 | AR_SLOT4_2 | AR_SLOT4_1 | AR_SLOT4_0 | |
$84 | KS_SLOT5_1 | KS_SLOT5_0 | AR_SLOT5_4 | AR_SLOT5_3 | AR_SLOT5_2 | AR_SLOT5_1 | AR_SLOT5_0 | |
$85 | KS_SLOT6_1 | KS_SLOT6_0 | AR_SLOT6_4 | AR_SLOT6_3 | AR_SLOT6_2 | AR_SLOT6_1 | AR_SLOT6_0 | |
$86 | KS_SLOT7_1 | KS_SLOT7_0 | AR_SLOT7_4 | AR_SLOT7_3 | AR_SLOT7_2 | AR_SLOT7_1 | AR_SLOT7_0 | |
$87 | KS_SLOT8_1 | KS_SLOT8_0 | AR_SLOT8_4 | AR_SLOT8_3 | AR_SLOT8_2 | AR_SLOT8_1 | AR_SLOT8_0 | |
$88 | KS_SLOT9_1 | KS_SLOT9_0 | AR_SLOT9_4 | AR_SLOT9_3 | AR_SLOT9_2 | AR_SLOT9_1 | AR_SLOT9_0 | |
$89 | KS_SLOT10_1 | KS_SLOT10_0 | AR_SLOT10_4 | AR_SLOT10_3 | AR_SLOT10_2 | AR_SLOT10_1 | AR_SLOT10_0 | |
$8A | KS_SLOT11_1 | KS_SLOT11_0 | AR_SLOT11_4 | AR_SLOT11_3 | AR_SLOT11_2 | AR_SLOT11_1 | AR_SLOT11_0 | |
$8B | KS_SLOT12_1 | KS_SLOT12_0 | AR_SLOT12_4 | AR_SLOT12_3 | AR_SLOT12_2 | AR_SLOT12_1 | AR_SLOT12_0 | |
$8C | KS_SLOT13_1 | KS_SLOT13_0 | AR_SLOT13_4 | AR_SLOT13_3 | AR_SLOT13_2 | AR_SLOT13_1 | AR_SLOT13_0 | |
$8D | KS_SLOT14_1 | KS_SLOT14_0 | AR_SLOT14_4 | AR_SLOT14_3 | AR_SLOT14_2 | AR_SLOT14_1 | AR_SLOT14_0 | |
$8E | KS_SLOT15_1 | KS_SLOT15_0 | AR_SLOT15_4 | AR_SLOT15_3 | AR_SLOT15_2 | AR_SLOT15_1 | AR_SLOT15_0 | |
$8F | KS_SLOT16_1 | KS_SLOT16_0 | AR_SLOT16_4 | AR_SLOT16_3 | AR_SLOT16_2 | AR_SLOT16_1 | AR_SLOT16_0 | |
$90 | KS_SLOT17_1 | KS_SLOT17_0 | AR_SLOT17_4 | AR_SLOT17_3 | AR_SLOT17_2 | AR_SLOT17_1 | AR_SLOT17_0 | |
$91 | KS_SLOT18_1 | KS_SLOT18_0 | AR_SLOT18_4 | AR_SLOT18_3 | AR_SLOT18_2 | AR_SLOT18_1 | AR_SLOT18_0 | |
$92 | KS_SLOT19_1 | KS_SLOT19_0 | AR_SLOT19_4 | AR_SLOT19_3 | AR_SLOT19_2 | AR_SLOT19_1 | AR_SLOT19_0 | |
$93 | KS_SLOT20_1 | KS_SLOT20_0 | AR_SLOT20_4 | AR_SLOT20_3 | AR_SLOT20_2 | AR_SLOT20_1 | AR_SLOT20_0 | |
$94 | KS_SLOT21_1 | KS_SLOT21_0 | AR_SLOT21_4 | AR_SLOT21_3 | AR_SLOT21_2 | AR_SLOT21_1 | AR_SLOT21_0 | |
$95 | KS_SLOT22_1 | KS_SLOT22_0 | AR_SLOT22_4 | AR_SLOT22_3 | AR_SLOT22_2 | AR_SLOT22_1 | AR_SLOT22_0 | |
$96 | KS_SLOT23_1 | KS_SLOT23_0 | AR_SLOT23_4 | AR_SLOT23_3 | AR_SLOT23_2 | AR_SLOT23_1 | AR_SLOT23_0 | |
$97 | KS_SLOT24_1 | KS_SLOT24_0 | AR_SLOT24_4 | AR_SLOT24_3 | AR_SLOT24_2 | AR_SLOT24_1 | AR_SLOT24_0 | |
$98 | KS_SLOT25_1 | KS_SLOT25_0 | AR_SLOT25_4 | AR_SLOT25_3 | AR_SLOT25_2 | AR_SLOT25_1 | AR_SLOT25_0 | |
$99 | KS_SLOT26_1 | KS_SLOT26_0 | AR_SLOT26_4 | AR_SLOT26_3 | AR_SLOT26_2 | AR_SLOT26_1 | AR_SLOT26_0 | |
$9A | KS_SLOT27_1 | KS_SLOT27_0 | AR_SLOT27_4 | AR_SLOT27_3 | AR_SLOT27_2 | AR_SLOT27_1 | AR_SLOT27_0 | |
$9B | KS_SLOT28_1 | KS_SLOT28_0 | AR_SLOT28_4 | AR_SLOT28_3 | AR_SLOT28_2 | AR_SLOT28_1 | AR_SLOT28_0 | |
$9C | KS_SLOT29_1 | KS_SLOT29_0 | AR_SLOT29_4 | AR_SLOT29_3 | AR_SLOT29_2 | AR_SLOT29_1 | AR_SLOT29_0 | |
$9D | KS_SLOT30_1 | KS_SLOT30_0 | AR_SLOT30_4 | AR_SLOT30_3 | AR_SLOT30_2 | AR_SLOT30_1 | AR_SLOT30_0 | |
$9E | KS_SLOT31_1 | KS_SLOT31_0 | AR_SLOT31_4 | AR_SLOT31_3 | AR_SLOT31_2 | AR_SLOT31_1 | AR_SLOT31_0 | |
$9F | KS_SLOT32_1 | KS_SLOT32_0 | AR_SLOT32_4 | AR_SLOT32_3 | AR_SLOT32_2 | AR_SLOT32_1 | AR_SLOT32_0 | |
$A0 | AMS_SLOT1_EN | D1R_SLOT1_4 | D1R_SLOT1_3 | D1R_SLOT1_2 | D1R_SLOT1_1 | D1R_SLOT1_0 | ||
$A1 | AMS_SLOT2_EN | D1R_SLOT2_4 | D1R_SLOT2_3 | D1R_SLOT2_2 | D1R_SLOT2_1 | D1R_SLOT2_0 | ||
$A2 | AMS_SLOT3_EN | D1R_SLOT3_4 | D1R_SLOT3_3 | D1R_SLOT3_2 | D1R_SLOT3_1 | D1R_SLOT3_0 | ||
$A3 | AMS_SLOT4_EN | D1R_SLOT4_4 | D1R_SLOT4_3 | D1R_SLOT4_2 | D1R_SLOT4_1 | D1R_SLOT4_0 | ||
$A4 | AMS_SLOT5_EN | D1R_SLOT5_4 | D1R_SLOT5_3 | D1R_SLOT5_2 | D1R_SLOT5_1 | D1R_SLOT5_0 | ||
$A5 | AMS_SLOT6_EN | D1R_SLOT6_4 | D1R_SLOT6_3 | D1R_SLOT6_2 | D1R_SLOT6_1 | D1R_SLOT6_0 | ||
$A6 | AMS_SLOT7_EN | D1R_SLOT7_4 | D1R_SLOT7_3 | D1R_SLOT7_2 | D1R_SLOT7_1 | D1R_SLOT7_0 | ||
$A7 | AMS_SLOT8_EN | D1R_SLOT8_4 | D1R_SLOT8_3 | D1R_SLOT8_2 | D1R_SLOT8_1 | D1R_SLOT8_0 | ||
$A8 | AMS_SLOT9_EN | D1R_SLOT9_4 | D1R_SLOT9_3 | D1R_SLOT9_2 | D1R_SLOT9_1 | D1R_SLOT9_0 | ||
$A9 | AMS_SLOT10_EN | D1R_SLOT10_4 | D1R_SLOT10_3 | D1R_SLOT10_2 | D1R_SLOT10_1 | D1R_SLOT10_0 | ||
$AA | AMS_SLOT11_EN | D1R_SLOT11_4 | D1R_SLOT11_3 | D1R_SLOT11_2 | D1R_SLOT11_1 | D1R_SLOT11_0 | ||
$AB | AMS_SLOT12_EN | D1R_SLOT12_4 | D1R_SLOT12_3 | D1R_SLOT12_2 | D1R_SLOT12_1 | D1R_SLOT12_0 | ||
$AC | AMS_SLOT13_EN | D1R_SLOT13_4 | D1R_SLOT13_3 | D1R_SLOT13_2 | D1R_SLOT13_1 | D1R_SLOT13_0 | ||
$AD | AMS_SLOT14_EN | D1R_SLOT14_4 | D1R_SLOT14_3 | D1R_SLOT14_2 | D1R_SLOT14_1 | D1R_SLOT14_0 | ||
$AE | AMS_SLOT15_EN | D1R_SLOT15_4 | D1R_SLOT15_3 | D1R_SLOT15_2 | D1R_SLOT15_1 | D1R_SLOT15_0 | ||
$AF | AMS_SLOT16_EN | D1R_SLOT16_4 | D1R_SLOT16_3 | D1R_SLOT16_2 | D1R_SLOT16_1 | D1R_SLOT16_0 | ||
$B0 | AMS_SLOT17_EN | D1R_SLOT17_4 | D1R_SLOT17_3 | D1R_SLOT17_2 | D1R_SLOT17_1 | D1R_SLOT17_0 | ||
$B1 | AMS_SLOT18_EN | D1R_SLOT18_4 | D1R_SLOT18_3 | D1R_SLOT18_2 | D1R_SLOT18_1 | D1R_SLOT18_0 | ||
$B2 | AMS_SLOT19_EN | D1R_SLOT19_4 | D1R_SLOT19_3 | D1R_SLOT19_2 | D1R_SLOT19_1 | D1R_SLOT19_0 | ||
$B3 | AMS_SLOT20_EN | D1R_SLOT20_4 | D1R_SLOT20_3 | D1R_SLOT20_2 | D1R_SLOT20_1 | D1R_SLOT20_0 | ||
$B4 | AMS_SLOT21_EN | D1R_SLOT21_4 | D1R_SLOT21_3 | D1R_SLOT21_2 | D1R_SLOT21_1 | D1R_SLOT21_0 | ||
$B5 | AMS_SLOT22_EN | D1R_SLOT22_4 | D1R_SLOT22_3 | D1R_SLOT22_2 | D1R_SLOT22_1 | D1R_SLOT22_0 | ||
$B6 | AMS_SLOT23_EN | D1R_SLOT23_4 | D1R_SLOT23_3 | D1R_SLOT23_2 | D1R_SLOT23_1 | D1R_SLOT23_0 | ||
$B7 | AMS_SLOT24_EN | D1R_SLOT24_4 | D1R_SLOT24_3 | D1R_SLOT24_2 | D1R_SLOT24_1 | D1R_SLOT24_0 | ||
$B8 | AMS_SLOT25_EN | D1R_SLOT25_4 | D1R_SLOT25_3 | D1R_SLOT25_2 | D1R_SLOT25_1 | D1R_SLOT25_0 | ||
$B9 | AMS_SLOT26_EN | D1R_SLOT26_4 | D1R_SLOT26_3 | D1R_SLOT26_2 | D1R_SLOT26_1 | D1R_SLOT26_0 | ||
$BA | AMS_SLOT27_EN | D1R_SLOT27_4 | D1R_SLOT27_3 | D1R_SLOT27_2 | D1R_SLOT27_1 | D1R_SLOT27_0 | ||
$BB | AMS_SLOT28_EN | D1R_SLOT28_4 | D1R_SLOT28_3 | D1R_SLOT28_2 | D1R_SLOT28_1 | D1R_SLOT28_0 | ||
$BC | AMS_SLOT29_EN | D1R_SLOT29_4 | D1R_SLOT29_3 | D1R_SLOT29_2 | D1R_SLOT29_1 | D1R_SLOT29_0 | ||
$BD | AMS_SLOT30_EN | D1R_SLOT30_4 | D1R_SLOT30_3 | D1R_SLOT30_2 | D1R_SLOT30_1 | D1R_SLOT30_0 | ||
$BE | AMS_SLOT31_EN | D1R_SLOT31_4 | D1R_SLOT31_3 | D1R_SLOT31_2 | D1R_SLOT31_1 | D1R_SLOT31_0 | ||
$BF | AMS_SLOT32_EN | D1R_SLOT32_4 | D1R_SLOT32_3 | D1R_SLOT32_2 | D1R_SLOT32_1 | D1R_SLOT32_0 | ||
$C0 | DT2_SLOT1_1 | DT2_SLOT1_0 | D2R_SLOT1_4 | D2R_SLOT1_3 | D2R_SLOT1_2 | D2R_SLOT1_1 | D2R_SLOT1_0 | |
$C1 | DT2_SLOT2_1 | DT2_SLOT2_0 | D2R_SLOT2_4 | D2R_SLOT2_3 | D2R_SLOT2_2 | D2R_SLOT2_1 | D2R_SLOT2_0 | |
$C2 | DT2_SLOT3_1 | DT2_SLOT3_0 | D2R_SLOT3_4 | D2R_SLOT3_3 | D2R_SLOT3_2 | D2R_SLOT3_1 | D2R_SLOT3_0 | |
$C3 | DT2_SLOT4_1 | DT2_SLOT4_0 | D2R_SLOT4_4 | D2R_SLOT4_3 | D2R_SLOT4_2 | D2R_SLOT4_1 | D2R_SLOT4_0 | |
$C4 | DT2_SLOT5_1 | DT2_SLOT5_0 | D2R_SLOT5_4 | D2R_SLOT5_3 | D2R_SLOT5_2 | D2R_SLOT5_1 | D2R_SLOT5_0 | |
$C5 | DT2_SLOT6_1 | DT2_SLOT6_0 | D2R_SLOT6_4 | D2R_SLOT6_3 | D2R_SLOT6_2 | D2R_SLOT6_1 | D2R_SLOT6_0 | |
$C6 | DT2_SLOT7_1 | DT2_SLOT7_0 | D2R_SLOT7_4 | D2R_SLOT7_3 | D2R_SLOT7_2 | D2R_SLOT7_1 | D2R_SLOT7_0 | |
$C7 | DT2_SLOT8_1 | DT2_SLOT8_0 | D2R_SLOT8_4 | D2R_SLOT8_3 | D2R_SLOT8_2 | D2R_SLOT8_1 | D2R_SLOT8_0 | |
$C8 | DT2_SLOT9_1 | DT2_SLOT9_0 | D2R_SLOT9_4 | D2R_SLOT9_3 | D2R_SLOT9_2 | D2R_SLOT9_1 | D2R_SLOT9_0 | |
$C9 | DT2_SLOT10_1 | DT2_SLOT10_0 | D2R_SLOT10_4 | D2R_SLOT10_3 | D2R_SLOT10_2 | D2R_SLOT10_1 | D2R_SLOT10_0 | |
$CA | DT2_SLOT11_1 | DT2_SLOT11_0 | D2R_SLOT11_4 | D2R_SLOT11_3 | D2R_SLOT11_2 | D2R_SLOT11_1 | D2R_SLOT11_0 | |
$CB | DT2_SLOT12_1 | DT2_SLOT12_0 | D2R_SLOT12_4 | D2R_SLOT12_3 | D2R_SLOT12_2 | D2R_SLOT12_1 | D2R_SLOT12_0 | |
$CC | DT2_SLOT13_1 | DT2_SLOT13_0 | D2R_SLOT13_4 | D2R_SLOT13_3 | D2R_SLOT13_2 | D2R_SLOT13_1 | D2R_SLOT13_0 | |
$CD | DT2_SLOT14_1 | DT2_SLOT14_0 | D2R_SLOT14_4 | D2R_SLOT14_3 | D2R_SLOT14_2 | D2R_SLOT14_1 | D2R_SLOT14_0 | |
$CE | DT2_SLOT15_1 | DT2_SLOT15_0 | D2R_SLOT15_4 | D2R_SLOT15_3 | D2R_SLOT15_2 | D2R_SLOT15_1 | D2R_SLOT15_0 | |
$CF | DT2_SLOT16_1 | DT2_SLOT16_0 | D2R_SLOT16_4 | D2R_SLOT16_3 | D2R_SLOT16_2 | D2R_SLOT16_1 | D2R_SLOT16_0 | |
$D0 | DT2_SLOT17_1 | DT2_SLOT17_0 | D2R_SLOT17_4 | D2R_SLOT17_3 | D2R_SLOT17_2 | D2R_SLOT17_1 | D2R_SLOT17_0 | |
$D1 | DT2_SLOT18_1 | DT2_SLOT18_0 | D2R_SLOT18_4 | D2R_SLOT18_3 | D2R_SLOT18_2 | D2R_SLOT18_1 | D2R_SLOT18_0 | |
$D2 | DT2_SLOT19_1 | DT2_SLOT19_0 | D2R_SLOT19_4 | D2R_SLOT19_3 | D2R_SLOT19_2 | D2R_SLOT19_1 | D2R_SLOT19_0 | |
$D3 | DT2_SLOT20_1 | DT2_SLOT20_0 | D2R_SLOT20_4 | D2R_SLOT20_3 | D2R_SLOT20_2 | D2R_SLOT20_1 | D2R_SLOT20_0 | |
$D4 | DT2_SLOT21_1 | DT2_SLOT21_0 | D2R_SLOT21_4 | D2R_SLOT21_3 | D2R_SLOT21_2 | D2R_SLOT21_1 | D2R_SLOT21_0 | |
$D5 | DT2_SLOT22_1 | DT2_SLOT22_0 | D2R_SLOT22_4 | D2R_SLOT22_3 | D2R_SLOT22_2 | D2R_SLOT22_1 | D2R_SLOT22_0 | |
$D6 | DT2_SLOT23_1 | DT2_SLOT23_0 | D2R_SLOT23_4 | D2R_SLOT23_3 | D2R_SLOT23_2 | D2R_SLOT23_1 | D2R_SLOT23_0 | |
$D7 | DT2_SLOT24_1 | DT2_SLOT24_0 | D2R_SLOT24_4 | D2R_SLOT24_3 | D2R_SLOT24_2 | D2R_SLOT24_1 | D2R_SLOT24_0 | |
$D8 | DT2_SLOT25_1 | DT2_SLOT25_0 | D2R_SLOT25_4 | D2R_SLOT25_3 | D2R_SLOT25_2 | D2R_SLOT25_1 | D2R_SLOT25_0 | |
$D9 | DT2_SLOT26_1 | DT2_SLOT26_0 | D2R_SLOT26_4 | D2R_SLOT26_3 | D2R_SLOT26_2 | D2R_SLOT26_1 | D2R_SLOT26_0 | |
$DA | DT2_SLOT27_1 | DT2_SLOT27_0 | D2R_SLOT27_4 | D2R_SLOT27_3 | D2R_SLOT27_2 | D2R_SLOT27_1 | D2R_SLOT27_0 | |
$DB | DT2_SLOT28_1 | DT2_SLOT28_0 | D2R_SLOT28_4 | D2R_SLOT28_3 | D2R_SLOT28_2 | D2R_SLOT28_1 | D2R_SLOT28_0 | |
$DC | DT2_SLOT29_1 | DT2_SLOT29_0 | D2R_SLOT29_4 | D2R_SLOT29_3 | D2R_SLOT29_2 | D2R_SLOT29_1 | D2R_SLOT29_0 | |
$DD | DT2_SLOT30_1 | DT2_SLOT30_0 | D2R_SLOT30_4 | D2R_SLOT30_3 | D2R_SLOT30_2 | D2R_SLOT30_1 | D2R_SLOT30_0 | |
$DE | DT2_SLOT31_1 | DT2_SLOT31_0 | D2R_SLOT31_4 | D2R_SLOT31_3 | D2R_SLOT31_2 | D2R_SLOT31_1 | D2R_SLOT31_0 | |
$DF | DT2_SLOT32_1 | DT2_SLOT32_0 | D2R_SLOT32_4 | D2R_SLOT32_3 | D2R_SLOT32_2 | D2R_SLOT32_1 | D2R_SLOT32_0 | |
$E0 | D1L_SLOT1_3 | D1L_SLOT1_2 | D1L_SLOT1_1 | D1L_SLOT1_0 | RR_SLOT1_3 | RR_SLOT1_2 | RR_SLOT1_1 | RR_SLOT1_0 |
$E1 | D1L_SLOT2_3 | D1L_SLOT2_2 | D1L_SLOT2_1 | D1L_SLOT2_0 | RR_SLOT2_3 | RR_SLOT2_2 | RR_SLOT2_1 | RR_SLOT2_0 |
$E2 | D1L_SLOT3_3 | D1L_SLOT3_2 | D1L_SLOT3_1 | D1L_SLOT3_0 | RR_SLOT3_3 | RR_SLOT3_2 | RR_SLOT3_1 | RR_SLOT3_0 |
$E3 | D1L_SLOT4_3 | D1L_SLOT4_2 | D1L_SLOT4_1 | D1L_SLOT4_0 | RR_SLOT4_3 | RR_SLOT4_2 | RR_SLOT4_1 | RR_SLOT4_0 |
$E4 | D1L_SLOT5_3 | D1L_SLOT5_2 | D1L_SLOT5_1 | D1L_SLOT5_0 | RR_SLOT5_3 | RR_SLOT5_2 | RR_SLOT5_1 | RR_SLOT5_0 |
$E5 | D1L_SLOT6_3 | D1L_SLOT6_2 | D1L_SLOT6_1 | D1L_SLOT6_0 | RR_SLOT6_3 | RR_SLOT6_2 | RR_SLOT6_1 | RR_SLOT6_0 |
$E6 | D1L_SLOT7_3 | D1L_SLOT7_2 | D1L_SLOT7_1 | D1L_SLOT7_0 | RR_SLOT7_3 | RR_SLOT7_2 | RR_SLOT7_1 | RR_SLOT7_0 |
$E7 | D1L_SLOT8_3 | D1L_SLOT8_2 | D1L_SLOT8_1 | D1L_SLOT8_0 | RR_SLOT8_3 | RR_SLOT8_2 | RR_SLOT8_1 | RR_SLOT8_0 |
$E8 | D1L_SLOT9_3 | D1L_SLOT9_2 | D1L_SLOT9_1 | D1L_SLOT9_0 | RR_SLOT9_3 | RR_SLOT9_2 | RR_SLOT9_1 | RR_SLOT9_0 |
$E9 | D1L_SLOT10_3 | D1L_SLOT10_2 | D1L_SLOT10_1 | D1L_SLOT10_0 | RR_SLOT10_3 | RR_SLOT10_2 | RR_SLOT10_1 | RR_SLOT10_0 |
$EA | D1L_SLOT11_3 | D1L_SLOT11_2 | D1L_SLOT11_1 | D1L_SLOT11_0 | RR_SLOT11_3 | RR_SLOT11_2 | RR_SLOT11_1 | RR_SLOT11_0 |
$EB | D1L_SLOT12_3 | D1L_SLOT12_2 | D1L_SLOT12_1 | D1L_SLOT12_0 | RR_SLOT12_3 | RR_SLOT12_2 | RR_SLOT12_1 | RR_SLOT12_0 |
$EC | D1L_SLOT13_3 | D1L_SLOT13_2 | D1L_SLOT13_1 | D1L_SLOT13_0 | RR_SLOT13_3 | RR_SLOT13_2 | RR_SLOT13_1 | RR_SLOT13_0 |
$ED | D1L_SLOT14_3 | D1L_SLOT14_2 | D1L_SLOT14_1 | D1L_SLOT14_0 | RR_SLOT14_3 | RR_SLOT14_2 | RR_SLOT14_1 | RR_SLOT14_0 |
$EE | D1L_SLOT15_3 | D1L_SLOT15_2 | D1L_SLOT15_1 | D1L_SLOT15_0 | RR_SLOT15_3 | RR_SLOT15_2 | RR_SLOT15_1 | RR_SLOT15_0 |
$EF | D1L_SLOT16_3 | D1L_SLOT16_2 | D1L_SLOT16_1 | D1L_SLOT16_0 | RR_SLOT16_3 | RR_SLOT16_2 | RR_SLOT16_1 | RR_SLOT16_0 |
$F0 | D1L_SLOT17_3 | D1L_SLOT17_2 | D1L_SLOT17_1 | D1L_SLOT17_0 | RR_SLOT17_3 | RR_SLOT17_2 | RR_SLOT17_1 | RR_SLOT17_0 |
$F1 | D1L_SLOT18_3 | D1L_SLOT18_2 | D1L_SLOT18_1 | D1L_SLOT18_0 | RR_SLOT18_3 | RR_SLOT18_2 | RR_SLOT18_1 | RR_SLOT18_0 |
$F2 | D1L_SLOT19_3 | D1L_SLOT19_2 | D1L_SLOT19_1 | D1L_SLOT19_0 | RR_SLOT19_3 | RR_SLOT19_2 | RR_SLOT19_1 | RR_SLOT19_0 |
$F3 | D1L_SLOT20_3 | D1L_SLOT20_2 | D1L_SLOT20_1 | D1L_SLOT20_0 | RR_SLOT20_3 | RR_SLOT20_2 | RR_SLOT20_1 | RR_SLOT20_0 |
$F4 | D1L_SLOT21_3 | D1L_SLOT21_2 | D1L_SLOT21_1 | D1L_SLOT21_0 | RR_SLOT21_3 | RR_SLOT21_2 | RR_SLOT21_1 | RR_SLOT21_0 |
$F5 | D1L_SLOT22_3 | D1L_SLOT22_2 | D1L_SLOT22_1 | D1L_SLOT22_0 | RR_SLOT22_3 | RR_SLOT22_2 | RR_SLOT22_1 | RR_SLOT22_0 |
$F6 | D1L_SLOT23_3 | D1L_SLOT23_2 | D1L_SLOT23_1 | D1L_SLOT23_0 | RR_SLOT23_3 | RR_SLOT23_2 | RR_SLOT23_1 | RR_SLOT23_0 |
$F7 | D1L_SLOT24_3 | D1L_SLOT24_2 | D1L_SLOT24_1 | D1L_SLOT24_0 | RR_SLOT24_3 | RR_SLOT24_2 | RR_SLOT24_1 | RR_SLOT24_0 |
$F8 | D1L_SLOT25_3 | D1L_SLOT25_2 | D1L_SLOT25_1 | D1L_SLOT25_0 | RR_SLOT25_3 | RR_SLOT25_2 | RR_SLOT25_1 | RR_SLOT25_0 |
$F9 | D1L_SLOT26_3 | D1L_SLOT26_2 | D1L_SLOT26_1 | D1L_SLOT26_0 | RR_SLOT26_3 | RR_SLOT26_2 | RR_SLOT26_1 | RR_SLOT26_0 |
$FA | D1L_SLOT27_3 | D1L_SLOT27_2 | D1L_SLOT27_1 | D1L_SLOT27_0 | RR_SLOT27_3 | RR_SLOT27_2 | RR_SLOT27_1 | RR_SLOT27_0 |
$FB | D1L_SLOT28_3 | D1L_SLOT28_2 | D1L_SLOT28_1 | D1L_SLOT28_0 | RR_SLOT28_3 | RR_SLOT28_2 | RR_SLOT28_1 | RR_SLOT28_0 |
$FC | D1L_SLOT29_3 | D1L_SLOT29_2 | D1L_SLOT29_1 | D1L_SLOT29_0 | RR_SLOT29_3 | RR_SLOT29_2 | RR_SLOT29_1 | RR_SLOT29_0 |
$FD | D1L_SLOT30_3 | D1L_SLOT30_2 | D1L_SLOT30_1 | D1L_SLOT30_0 | RR_SLOT30_3 | RR_SLOT30_2 | RR_SLOT30_1 | RR_SLOT30_0 |
$FE | D1L_SLOT31_3 | D1L_SLOT31_2 | D1L_SLOT31_1 | D1L_SLOT31_0 | RR_SLOT31_3 | RR_SLOT31_2 | RR_SLOT31_1 | RR_SLOT31_0 |
$FF | D1L_SLOT32_3 | D1L_SLOT32_2 | D1L_SLOT32_1 | D1L_SLOT32_0 | RR_SLOT32_3 | RR_SLOT32_2 | RR_SLOT32_1 | RR_SLOT32_0 |
・YM2151のレジスタ(読み取り専用)
YM2151は内部に1バイトの読み取り専用レジスタを持っています。
セットしたアドレスによらず、YM2151のステータス情報を返します。
(テストモードの機能で内部レジスタのデータを読み取ることもできるようです。)
B: WRITE BUSY FLAG ライトビジーフラグです。 このフラグがHの時にYM2151のレジスタへ値を書き込むことは禁止されています。 B -> H : データ書き込み中のため、YM2151へのライトアクセスは禁止 B -> L : YM2151へのライトアクセス可能 IST: タイマーオーバーフローステータスフラグです。 このフラグがHの時、YM2151の内部タイマーのオーバーフローフラグがHになったことを示します。 IST_A -> H : タイマーAがオーバーフローしています。 IST_A -> L : タイマーAがオーバーフローしていません。 IST_B -> H : タイマーBがオーバーフローしています。 IST_B -> L : タイマーBがオーバーフローしていません。 |
---|
スロット、チャンネル、モジュレータ・キャリアの関係
チャンネルとモジュレータ・キャリアからスロット番号を参照するための表です。
CH No. | M1(OP1) | M2(OP3) | C1(OP2) | C2(OP4) |
---|---|---|---|---|
CH1 | SLOT1 | SLOT9 | SLOT17 | SLOT25 |
CH2 | SLOT2 | SLOT10 | SLOT18 | SLOT26 |
CH3 | SLOT3 | SLOT11 | SLOT19 | SLOT27 |
CH4 | SLOT4 | SLOT12 | SLOT20 | SLOT28 |
CH5 | SLOT5 | SLOT13 | SLOT21 | SLOT29 |
CH6 | SLOT6 | SLOT14 | SLOT22 | SLOT30 |
CH7 | SLOT7 | SLOT15 | SLOT23 | SLOT31 |
CH8 | SLOT8 | SLOT16 | SLOT24 | SLOT32 |
・タイミング図
YM2151への書き込みタイミング
アドレス・データの書き込みタイミングです。アドレスを書き込む場合は4番ピンの「A0」をLにします。データを書き込む場合は「A0」をHにします。
YM2151のステータスレジスタの読み取りタイミング
読み取りの場合、YM2151は常にステータスレジスタの内容を返すため、アドレスの書き込みは不要です。
YM2151のレジスタへ値をセットする
YM2151は、アドレスバスとデータバスを共用しています。YM2151へアドレス値を書き込んでからデータ値を書き込むことで、任意の場所の内部レジスタへデータをセットできます。
レジスタへデータを際には、原則事前にYM2151の「WRITE BUSY FLAG」(ステータスレジスタの第7ビット)がLとなっていることをチェックする必要があります。
1度YM2151のレジスタへデータを書き込むと、68入力クロック分の待機時間が必要です。ピン数の節約などの理由でステータスレジスタを読まない場合、十分なウェイト時間が必要です。
YM2151は、アドレスバスとデータバスを共用しています。
YM2151へアドレス値を書き込んでからデータ値を書き込むことで、任意の場所の内部レジスタへデータをセットできます。
-- YM2151のレジスタへのデータセット手順 (ステータスレジスタをチェックする場合) --
①A0ピンをHにする②~RDピンをLにする③~CSピンをLにする④D7ピンがHの場合(BUSY中)、~CS, ~RDピンをHにして一定時間待機後②へ⑤~RDピンをHにする⑥A0ピンをLにする⑦書き込み先アドレスをD0~D7へセットする⑧~WEピンをLにする⑨~WEピンをHにする⑩A0ピンをHにする⑪書き込むデータをD0~D7へセットする⑫~WEピンをLにする⑬~WEピンをHにする⑭~CSピンをHにする
①A0ピンをHにする
②~RDピンをLにする
③~CSピンをLにする
④D7ピンがHの場合(BUSY中)、~CS, ~RDピンをHにして一定時間待機後②へ
⑤~RDピンをHにする
⑥A0ピンをLにする
⑦書き込み先アドレスをD0~D7へセットする
⑧~WEピンをLにする
⑨~WEピンをHにする
⑩A0ピンをHにする
⑪書き込むデータをD0~D7へセットする
⑫~WEピンをLにする
⑬~WEピンをHにする
⑭~CSピンをHにする
-- YM2151のレジスタへのデータセット手順 (ステータスレジスタをチェックしない場合) --
①YM2151の入力クロック68サイクル分以上待機する(余裕をもって多く待機することをおすすめします。)②~CSピンをLにする③A0ピンをLにする④書き込み先アドレスをD0~D7へセットする⑤~WEピンをLにする⑥~WEピンをHにする⑦A0ピンをHにする⑧書き込むデータをD0~D7へセットする⑨~WEピンをLにする⑩~WEピンをHにする⑪~CSピンをHにする
①YM2151の入力クロック68サイクル分以上待機する(余裕をもって多く待機することをおすすめします。)
②~CSピンをLにする
③A0ピンをLにする
④書き込み先アドレスをD0~D7へセットする
⑤~WEピンをLにする
⑥~WEピンをHにする
⑦A0ピンをHにする
⑧書き込むデータをD0~D7へセットする
⑨~WEピンをLにする
⑩~WEピンをHにする
⑪~CSピンをHにする
・使い方(制御)
YM2151は、256バイト分のレジスタアドレス空間を持ち、そのほとんどが発音に必要なレジスタとなっています。
音色の設定がほとんどできないPSG音源や、音色をレジスタでほとんど制御しないPCMサンプリング音源と比較するとレジスタ数が多いため、FM音源の難しさを感じます。
YM2151はレジスタ数こそは多いものの、特殊な用途のレジスタは少なめです。
-- レジスタの種類 --
大雑把に分けると、
・タイマー系レジスタ
・トーン出力・音程設定レジスタ
・LFO関連レジスタ
・コネクション(アルゴリズム)・倍率レジスタ
・エンベロープレジスタ
があります。
このうち、FM音源特有のレジスタは、
・LFO関連レジスタ
・コネクション(アルゴリズム)・倍率レジスタ
の2種類くらいなので、実はそんなに難しくないかもしれません。
-FM音源について- FM音源IC内のレジスタがどのような機能を持つのかを理解するには、FM音源がどのような仕組みで音色を作り出すかを知る必要があります。 ネット上には、とても分かりやすくFM音源について解説しているページが多数あるので、詳しく知りたい方は各自で調べてみてください。 FM音源について少しかみ砕いて説明すると、 FM音源の場合、「オペレータ」という1つのブロックの発振器を複数連結して1つの音色を作り上げます。 「オペレータ」どうしのつなぎ方で音色の特徴が変化します。直列(オペレータでオペレータに変調をかける)にしたり、並列(オペレータの出力値の加算)にしたりと色々な組み合わせができます。 この組み合わせを「コネクション」や「アルゴリズム」と呼びます。1つの音色にたくさんオペレータを連結すれば、より音作りの幅が広がります。 「オペレータ」を直列に接続することで、オペレータでオペレータに変調をかけることができます。わかりにくいので変調をかける方のオペレータを「モジュレータ」、変調をかけられる方のオペレータを「キャリア」と呼びます。 オペレータ(モジュレータ、キャリア)ごとに発振周波数比を変えることで、単一オペレータだけでは実現できない波形を作り出せます。 接続した複数のオペレータの発振周波数比が同じであれば、基本周波数が変わっても、出力波形は周期(周波数)が変わるだけで形は変わりません。 音色の音程を変える際、いちいちオペレータごとに周波数比が変わらないように計算してFM音源ICのオペレータ発振レジスタに値を書き込むのは、非常に億劫です。 そのため、通常のFM音源ICには、基音周波数と周波数比を指定する(倍率レジスタ)だけで自動的に各オペレータの発振周波数を設定してくれる機能があります。 この機能があれば、音程を変えたい時に基本周波数設定レジスタへピッチデータを一度書き込むだけで済みます。 ここで、オペレータについてもう少し詳しく見てみます。 原則オペレータ単体では、基本的な波形(YM2151の場合は正弦波のみ)しか出力できません。 しかし、出力の振幅の時間変化(エンベロープ)は個別に制御できます。 音の振幅の時間変化のイメージとして、 ピアノみたいな音であれば、最大音量から徐々に減衰していき、 ストリング系の音であれば、だんだん音量が上がってある一定の音量となる感じです。 音の振幅のエンベロープの場合は、アルゴリズムの最終段にあるオペレータ(キャリア)に対してエンベロープを設定してあげればよいわけです。 オペレータを直列に接続した場合、モジュレータのエンベロープ制御は、変調度合いの時間制御となります。 例えば、アルゴリズムを「モジュレータ」→「キャリア」として、モジュレータの出力レベルをキーオンから時間がたつにつれ減衰するようなエンベロープに設定するとします。 すると、キャリアの出力はキーオンから時間がたつにつれて非正弦波から正弦波へ近づきます。 FM音源は、少ないパラメータでこのような著しい波形の時間変化を可能とします。 ここまでで、FM音源がどのように波形を生成するかをイメージできれば良いでしょう。 YM2151をはじめとするFM音源ICのオペレータは、さらにLFOや自己フィードバックが可能です。 LFOLFO(ロー・フリークエンシー・オシレータ : 低周波発振器)は、その名の通り低い周波数で発振する発振器です。 発振器といえば先ほど説明したオペレータを思い浮かべると思いますが、 LFOの場合は「すべてのオペレータ(スロット)へ位相変調・振幅変調ができる」という特徴があります。(少なくともYM2151の場合です。LFOが複数あるFM音源ICの場合は違います) LFOの出力を直接音声として出力できません。 LFOの役割はモジュレータと大差がないようにも思えますが、LFOの場合は非常に低い周波数(数mHz ~ 数十Hz程度)の発振しかできません。 逆にモジュレータは、基本周波数の1/2の周波数程度までしか低い周波数で発振できません。 LFOは音色となる波形の生成というよりは、ビブラートやピッチベンドなどの演奏上のエフェクトを付けるための機能といえるでしょう。 モジュレータの自己フィードバックモジュレータの中には自己フィードバックをかけて自分自身を変調できるものもあります。 (YM2151の場合は、4つあるオペレータのうち1つ) これにより、原則オペレータ単体(1つのモジュレータ)では基本的な波形しか生成できなかったのが、 1つのモジュレータで、複雑な波形を生成できるようになりました。 フィードバックレベルを調整することで、基本波を歪ませたり発散させてノイズを出したりできます。 以上がFM音源の概要です。 音作りは、最低限「アルゴリズム」、「オペレータの発振倍率」、「エンベロープ」の設定さえできれば可能です。 加えて、「LFO」、「自己フィードバックレベル」を設定すると楽器としての音作りの幅が広がります。 ちなみにですが、オペレータ番号はチャンネルごとに割り当てられたオペレータの順番を表します。 チャンネル関係になくICの中にあるすべてのオペレータの通し番号は「スロット番号」と呼びます。 一概にこの通りではないですが、 スロット数 = オペレータ数 * チャンネル数 の関係が成り立ちます。 |
---|
・タイマー系レジスタ
・CLKA1($10 : bit0~7) タイマーAのオーバーフロー周期上位8bit
・CLKA2($11 : bit0~1) タイマーAのオーバーフロー周期下位2bit
・CLKB($12 : bit0~7) タイマーBのオーバーフロー周期
・TIM_CONF($14)
CSM($14 : bit7) タイマーAによるオートキーオンの有無
F_RESET_B($14 : bit5) タイマーBのオーバーフローフラグクリア
F_RESET_A($14 : bit4) タイマーAのオーバーフローフラグクリア
IRQ_EN_B($14 : bit3) タイマーBのオーバーフローフラグ立ち有効無効
IRQ_EN_A($14 : bit2) タイマーAのオーバーフローフラグ立ち有効無効
LOAD_B($14 : bit1) タイマーBの動作の有無
LOAD_A($14 : bit0) タイマーAの動作の有無
YM2151は、2つのタイマーを内蔵しています。
それぞれのタイマーを設定することで、一定時間ごとに割り込み要求信号を~IRQピン(2番ピン)から出力します。
YM2151をマイコンを用いて発音する場合、必ずしも使う必要がない機能です。
・トーン出力・音程設定系レジスタ
・KON($08)
SN_0 ~ SN_1($08 : bit3~6) スロット1~4のキーオン・キーオフ(チャンネルはCH($08 : bit0~2)で指定)
・LR_FB_CON($2X) (X = 0~7 : チャンネル1~8)
RL_R($2X : bit7) チャンネル1~8のR出力の有無
RL_L($2X : bit6) チャンネル1~8のL出力の有無
・KC($2X) (X = 8~F : チャンネル1~8)
OCT($2X : bit4~6) チャンネル1~8の音程(オクターブ)設定
NOTE($2X : bit0~3) チャンネル1~8の音程(ノート)設定
・KF($3X) (X = 0~7 : チャンネル1~8)
KF($3X : bit2~7) チャンネル1~8の音程(キーフラクション)設定
キーオン・キーオフは、スロットごとにセットできます。
YM2151の場合、チャンネル音量レジスタがありません。4つのオペレータのうち、キャリア出力部分のみ(アルゴリズムによって操作するTLレジスタの数が異なります)のスロット出力トータルレベルレジスタ(TL : $60~$7F)を操作してください。
YM2151は、ステレオ出力に対応していますがパンポットの設定はできません。パン制御を行いたい場合、2チャンネル分を左右に割り当て使用する必要があります。
・LFO関連のレジスタ
・TEST($01)
LFO_RESET($01 : bit1) LFOリセット
・LFRQ($18 : bit0~7) LFO周波数設定
・PMD_AMD($19)
LFO_MD_F($19 : bit7) 位相変調 or 振幅変調パラメータセット先指定ビット
LFO_MD($19 : bit0~6) 位相変調 or 振幅変調パラメータ (LFO_MD_F($19 : bit7)でセット先指定)
・CT_W($1B)
LFO_W($1B : bit0~1) LFO波形設定ビット
・PMS_AMS($3X) (X = 8~F : チャンネル1~8)
PMS($3X : bit4~6) LFO位相変調感度設定
AMS($3X : bit0~1) LFO振幅変調感度設定
・AMS_EN_D1R($A0+X) (X = 0~1F : スロット1~32)
AMS_EN($A0+X : bit7) LFO振幅変調の有無
・コネクション(アルゴリズム)・倍率関係のレジスタ
・NOISE($0F)
NE($0F : bit7) スロット32をノイズジェネレータとするか?
NFRQ($0F : bit0~4) ノイズ周波数設定
・LR_FB_CON($2X) (X = 0~7 : チャンネル1~8)
FL($2X : bit3~5) M1(OP1)のフィードバックレベル設定
CONECT($2X : bit0~2) アルゴリズム(コネクション)の設定
・DT1_MUL($40+X) (X = 0~1F : スロット1~32)
DT1($40+X : bit4~6) スロット周波数倍率微調整
MUL($40+X : bit0~3) スロット周波数倍率設定
・TL($60+X) (X = 0~1F : スロット1~32)
TL($60+X : bit0~6) スロット出力レベル設定
・DT2_D2R($C0+X) (X = 0~1F : スロット1~32)
DT2($C0+X : bit6~7) スロット周波数倍率粗調整
キャリアのスロット出力トータルレベルレジスタ(TL : $60~$7F)は、チャンネル音量となります。モジュレータのスロット出力トータルレベルレジスタは、変調度となります。
・エンベロープレジスタ
・KS_AR($80+X) (X = 0~1F : スロット1~32)
KS($80+X : bit6~7) ピッチによるエンベロープ補正設定ビット
AR($80+X : bit0~3) アタックレート設定ビット
・AMS_EN_D1R($A0+X) (X = 0~1F : スロット1~32)
D1R($A0+X : bit0~4) ファーストディケイレート設定ビット
・DT2_D2R($C0+X) (X = 0~1F : スロット1~32)
D2R($C0+X : bit0~4) セカンドディケイレート設定ビット
・D1L_RR($E0+X) (X = 0~1F : スロット1~32)
D1L($E0+X : bit4~7) ファーストディケイレベル設定ビット
RR($E0+X : bit0~3) リリースレート設定ビット
・使い方(制御)
--YM2151のリセット直後からの基本的な発音手順--
①音色を決定するパラメータ群をYM2151へセットする。
②音程設定レジスタに音程をセットする。
③キーオン・キーオフレジスタへキーオンしたいオペレータを選択してセットする。
ここでは、3段階のステップに分けていますが、①の音色パラメータ群のセットでは数十バイト分のパラメータがあります。音色を変更しない場合、YM2151の起動後に一度だけ書き込めばよいです。
①音色を決定するパラメータ群をYM2151へセットする。
FM音源は波形生成の原理上、多数のパラメータが必要です。
このパラメータの変化でどのような音が出るか予測することが難しく、FM音源ICへ手を出しにくくする要因となっています。
パラメータについては後述します。
②音程設定レジスタに音程をセットする。
音程設定レジスタは2種類あります。
・KC($2X) (X = 8~F : チャンネル1~8)
OCT($2X : bit4~6) チャンネル1~8の音程(オクターブ)設定
NOTE($2X : bit0~3) チャンネル1~8の音程(ノート)設定
・KF($3X) (X = 0~7 : チャンネル1~8)
KF($3X : bit2~7) チャンネル1~8の音程(キーフラクション)設定
KCは12階音とオクターブを決定し、KFは音程の微調整ができます。
音程 | NOTE |
---|---|
C# | 0 (0x0) |
D | 1 (0x1) |
D# | 2 (0x2) |
E | 4 (0x4) |
F | 5 (0x5) |
F# | 6 (0x6) |
G | 8 (0x8) |
G# | 9 (0x9) |
A | 10 (0x10) |
A# | 12 (0x12) |
B | 13 (0x13) |
C | 14 (0x14) |
KCの音階設定ビットの数値と音階の関係は、連続的ではありませんので注意してください。計算によって求めても良いですが、オクターブとノートのテーブルを用意すると楽に音程をYM2151へセットできます。
音程の微調整は、約1.6(100/64)セントずつ設定できます。
クロック入力周波数が3.58MHzでない時の音程の調整や、ピッチベンドなどに利用します。
③キーオン・キーオフレジスタへキーオンしたいオペレータを選択してセットする。
キーオン・キーオフレジスタにキーオンしたいオペレータのON/OFFフラグを操作することで、キーオン・キーオフすることができます。
・KON($08)
SN_0 ~ SN_1($08 : bit3~6) スロット1~4のキーオン・キーオフ(チャンネルはCH($08 : bit0~2)で指定)
キーオンすると、エンベロープ関連レジスタにセットされたパラメータに基づいて、各オペレータの出力振幅が時間的に変化を開始します。
キーオフするまでは、エンベロープ制御が持続するので、もう一度エンベロープ波形の先頭から振幅制御をしたい場合は、KONレジスタのオペレータON/OFFフラグをLにする必要があります。
----YM2151のパラメータについて----
FM音源は波形生成の原理上、多数のパラメータが必要です。
このパラメータの変化でどのような音が出るか予測することが難しく、FM音源ICへ手を出しにくくする要因となっています。
地道にパラメータを変更していき音色を探るのも面白いのですが、多くの時間が必要です。
幸いにもYM2151の場合、VOPMexというYM2151を忠実に再現したシミュレータが開発されており、プリセットパラメータも用意されています。
PPSE部 Softwareのページ VOPMex
VOPMexは、もともとはSam氏が開発したVSTプラグインのVOPMをosoumen氏が改良・修正したVSTプラグインのようです。
VOPMexには、阿保 剛 氏が作成したYM2151のプリセットパラメータが内蔵されているので、このVSTプラグインの導入後すぐにPC上で発音できます。
VAL-SOUND
VOPMexは、VSTプラグインなので単体では起動できません。
VST対応のDAWを導入しても良いですが、今回は音色のシミュレートとパラメータの取得さえできればよいので、「VSTHost」を使います。
VSTHost
VSTHostを起動してVOPMexを読み込むことで利用できます。
実物のYM2151で演奏するにはパラメータが必要なので、VOPMex内の「Export」を押して書き出します。
VOPMの書き出しパラメータは次のような構造をしています。
1行目
LFRQ, AMD, PMD, WF(LFO波形), NFRQ
2行目
PAN(bit7,bit6)(※), FL(フィードバックレベル), CON(アルゴリズム), AMS, PMS, SLOT(bit6~bit3)(KON($08)のSNビットに相当), NE(bit7)
3行目
M1-AR, M1-D1R, M1-D2R, M1-RR, M1-D1L, M1-TL, M1-KS, M1-MUL, M1-DT1, M1-DT2, M1-AMS-EN
4行目
C1-AR, C1-D1R, C1-D2R, C1-RR, C1-D1L, C1-TL, C1-KS, C1-MUL, C1-DT1, C1-DT2, C1-AMS-EN
5行目
M2-AR, M2-D1R, M2-D2R, M2-RR, M2-D1L, M2-TL, M2-KS, M2-MUL, M2-DT1, M2-DT2, M2-AMS-EN
6行目
C2-AR, C2-D1R, C2-D2R, C2-RR, C2-D1L, C2-TL, C2-KS, C2-MUL, C2-DT1, C2-DT2, C2-AMS-EN
※VOPMのパラメータ「PAN」はデフォルトでモノラル出力(64 = 0x40)となっているので、YM2151実機でステレオ出力にする場合は192 = 0xC0にする必要があります。
このパラメータをそのままYM2151へ与えると、シミュレートした時と同じような音色を出すことができます。
ただし、YM2151のレジスタにパラメータを与える場合、1バイト分のレジスタに複数のパラメータが入る場合がほとんどのため、事前にデータの整理をするかプログラム上でビット演算などする必要があります。
・使い方(回路)
YM2151の消費電力は最大630mWほどあり、通電中に手で触るとそれなりに熱さを感じます。
複数のYM2151を使った音源装置を製作する場合、電源容量に注意してください。
(YM2151を4つ使用した場合、USBからの給電は難しくなります。)
YM2151のクロック源として基本的に3.58MHz(3.579545MHz)のクリスタルオシレータを使用します。
4MHzのクリスタルオシレータを用いると、音程がずれるためKFレジスタなどで補正が必要になります。
・DAC周り
YM2151は単体での音声出力はできず、基本的には専用の外付けDACが必要です。
YM2151で使用可能な外付けDAC
・YM3012 (ステレオDAC)
・YM3014 (モノラルDAC)
これらのDACもYM2151と同様に入手方法が限られるため、偽物に注意してください。
・YM2151とYM3012の接続例
YM3012を使う場合、YM2151から出力されるΦ1, SO, SH1, SH2の4種類の信号をYM3012のCLOCKΦ1, SD, SAM2, SAM1へ入力します。
Φ1はシリアルデータのクロック信号出力、SOはシリアルデータ出力、SH1はCH1ホールド兼CH2シリアルデータラッチ、SH2はCH2ホールド兼CH1シリアルデータラッチとなります。
基本的には
SO -> SD
Φ1 -> CLOCKΦ1
SH1 -> SAM1
SH2 -> SAM2
という感じで接続します。
出力するチャンネルのLとRを入れ替えたい場合、
SH1 -> SAM2
SH2 -> SAM1
とします。
YM2151のDACとしてYM3012を使う場合は、これらの信号を深く理解しなくても良いです。
上記の回路は、MSX拡張シンセサイザユニット「YAMAHA SFG-01」のDAC~LPF周りの回路を元に作成しました。
YM3012は、外付けオペアンプがいくつか必要になります。
上記回路例では、基準電圧生成用に1回路、DACバッファ用に1回路、サンプルホールド用に2回路、LPF用に2回路分のオペアンプを使っています。
基準電圧生成用やDACバッファ用およびサンプルホールド用のオペアンプは、スルーレートが4V/μs以上のものを使用します。
※参考 NJM4558族の標準スルーレート
NJM4558 SR:1V/μs ×
NJM4559 SR:2V/μs ×
NJM4556A SR:3V/μs △
NJM4560 SR:4V/μs ○
YAMAHA SFG-01の場合NJM4556S、YAMAHA TX81Zの場合NJM072Dを使用しているようです。
YM3012のデータシートにはサンプルホールド用コンデンサは560pF ~ 3300pF、
YM3012の前の抵抗は100Ω ~ 1KΩあたりを使うと良いとあります。
これらの最適な値はVDDで決まるとありますが、具体的な決め方は書かれていません。
オペアンプのスルーレートやサンプリング周波数でも変わってくると思うので、
ここでは詳しい値の決め方は省きます。
NJM4560を使用した時、1500pと270Ωを推奨とあるので、この条件で設計するのが無難でしょう。
(YAMAHA SFG-01の場合0.01μFと大きい値となっているが、NJM4560ではなくNJM4556を使用しているのが関係している?)
・LPFのカットオフ周波数
YM2151のサンプリングレートfs[Hz]は、
fs = Φ1 / (チャンネル数 * 1フレームのシリアルデータ数)
= (ΦM / 2) / (2 *16)
= ΦM / 64 [Hz]
YM2151に入力するクロックΦMの周波数が3.58MHzの場合、サンプリング周波数は、
fs = ΦM / 64
= 3.58M / 64
=55.9KHz
となります。
よって、クロックΦMの周波数が3.58MHzの時には、約28KHz(55.9/2 KHz)以上の周波数成分をカットする必要があります。
理想LPFであれば28KHz以上でカットできますが、基本的にアナログLPFのカット特性は理想LPFのカット特性からかけ離れているので、余裕をもってカットオフ周波数(フィルタ通過後に源信号が-3dBになる周波数)を15~20KHz付近にもつアナログLPF用意してあげます。
YAMAHA SFG-01は19KHz付近、TX81Z(YM2414を使用しているがサンプリング周波数は55.9KHz)は16KHz付近にカットオフ周波数をもつフィルタを用意しています。
・YM2151と市販のDACとの接続例
YM3012などの専用DACがどうしても入手できなかったり、複数のYM2151の出力を1つのDACにまとめたい場合、市販のDACを用いる手段もあります。
そこで今回はYM2151の出力フォーマットと市販のDACとの接続例を紹介します。
YM2151をはじめとするYAMAHAのFM音源ICは、DACを内蔵しているものと外部に専用のDACを接続しなければいけない物の2種類あります。
厄介なことに外付けDACを必要とするFM音源は独自フォーマットで音声データ出力しているため、市販のDACは使用できません。
市販のDACを接続して音を出すようにするには、音声データを変換する必要があります。
・YM2151の音声データ出力フォーマット
YM2151は1フレーム(片チャンネル分1サンプル 、以降フレームはこの事を指す)分の16bitデータを任意の回数シフト(出力値の倍率だと1,1/2 , 1/4,1/8 …)し10bitのデータとして送り出します。
この10bitのデータのMSB(Bit9)は常に符号ビットとなります。
シフト数は0~6bitの7種類なので、3bitでシフト情報を送り出します。
例えば-512 ~ 511の数値の場合、10bit以内の2進データなのでシフトせずに出力するのでデータは無劣化となります。
逆に-32768 ~ -16385 または 16384 ~ 32767の数値の場合、16bitの数値データとなるので6bit分シフトして10bitに丸め出力します。
ほとんどの市販のDACは1フレーム16bitのデータを受信してアナログ値を出力するので、YM2151が出力した値10bit+シフト3bitのデータを16bitへ変換する必要があります。
シフト回路が必要になるので、回路規模が少し増えます。
CPLDやFPGAを使うのが良いでしょう。
・データのシフト
YM2151は16bitのデータを10bitに丸めるため、任意の数だけシフトします。数値的にはx2^(-N)となります。
YM2151が送信する実際のシフトデータ3bitはどのようになっているかというと、1~7の値を取ります。0は送信しません。
アナログ値Vout[V]と入力データは次のような関係があります。
Vout = ((1/2) * Vmax) + ((1/4) * Vmax * (-1 + D9 + D8*2^(-1) + D7*2^(-2) + … + D0*2^(-9) + 2^(-10)) * 2^(-N)) [V]
N = ~S2*4 + ~S1*2 + ~S0 : 「~」はビット反転記号
= 7 - (S2*4 + S1*2 + S0)
D0 ~ D9 : 入力データ10bit(D9は符号ビットでD9=1で正、D9=0で負、)
S0 ~ S2 : シフト数データ3bit (S=1~7)
・変換回路
ロジックICを使用したYM2151 -> MSBファースト2'コンプリメント16bitDAC用変換回路を作ってみました。
μPD6376は過去に秋月電子で販売されていたステレオDACです。
スーパーファミコンにも使用されているので、部品取りなどして入手すると良さそうです。
あまり深く考えずに作ったので正常に動作するかはわかりません。(LRCKがBCKの立ち下がりに同期していない等の問題があります。)
変換イメージの参考程度にとらえてください。
変換する上でポイントとなるのが、符号ビット、LRCKの生成、シフト回路の3つです。
・符号ビットの扱い
YM2151が出力するデータの符号はD9(MSB)=1で正値、D9(MSB)=0で負値となっています。
市販のDACは2の補数値を入力しなければいけないため、D15(MSB)=0で正値、D15(MSB)=1で負値となるように変換します。
幸いにもビット反転をすれば良さそうなのがすぐ分かります。
・LRCKの生成
YM2151が出力した10bit+3bitのデータを1フレーム分のサンプルとしてラッチするために、SH1とSH2の2つの信号がYM2151から出力されています。
DAC側はSH1の立ち下がりでCH2のフレームデータを内部へラッチします。同様にSH2の立ち下がりでCH1のフレームデータを内部へラッチします。
専用DACのYM3012はさらにSH1がHの間CH1のサンプルホールドコンデンサへアナログ値を出力し、SH2がHの間CH2のサンプルホールドコンデンサへアナログ値を出力します。
市販のDACの場合、サンプルホールド回路が必要なものと不要なものがあり、今回はサンプルホールド回路が不要のものを想定したため、SH1, SH2の立ち下がりタイミングのみ考えます。
市販のDAC(MSBファースト2'コンプリメントDAC)は、BCK, DATA, LRCKの3線で受信してアナログ値へ変換することが多いです。(さらにフレームごとにラッチするためのクロックWCLKや、サンプリング周波数の192倍、256倍、384倍、…を必要とするDACもあります。)
BCKはDAC内のシフトレジスタのシフトクロック、DATAはシリアルデータ、LRCKは出力チャンネル指定兼フレームラッチ信号です。
LRCKがHへ立ち上がるとCH1へのアナログ出力、Lへ立ち上がるとCH2へのアナログ出力というような感じで制御するための信号です。
変換回路例では、YM2151から出力されたSH1とSH2をLRCKへ変換するためにRS-FFとD-FFを使っています。
・シフト回路
10bitのデータを任意のビット数シフトするシフト回路を用意します。
パラレルでシフト回路を作成するとそれなりに回路規模が大きくなってしまうので、今回はDACへデータ送信する時にシリアルでシフト演算をしています。
YM2151が出力するシリアルデータは、ダミー3bit+数値10bit+シフト数3bit = 16bitで1フレーム分となっています。
Φ1をDACのシリアルデータのクロック源として使う場合、シリアルシフトする際にパラレル入力とパラレル出力ができるシフトレジスタを用意しなければいけません。
よって、Φ1の2倍のクロック周波数のΦMを使うことにします。
ΦMが32クロック分でDACへ1フレームを送信します。
上記回路例では、シフトレジスタへのパラレルデータのラッチに1クロック(ダミー1クロック)、16bitのシフトに16クロック、ダミーを15クロックの構成となっています。
出力後のフィルタの設計はYM3012を使ったときのものと同様で良いでしょう。
・YM2151とCPLD+汎用DACとの接続例
最後にCPLDを使ってYM2151 -> MSBファースト2'コンプリメント16bitDAC用変換回路を紹介します。
今回はXILINXのXC9500シリーズを使った例を挙げておきます。
開発ソフトの「XILINX ISE」は現時点(2022/06/23)でまだダウンロード可能です。また、パラレルポートがあるPCであれば、JTAGライタを自作してCPLDへ書き込みできます。
・VHDL
--YM2151 -> MSBファースト2'コンプリメント16bitDAC用変換
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity main is
Port (
BCK : out STD_LOGIC;--DACへ
OUT_DATA : out STD_LOGIC;--DACへ
LRCK : out STD_LOGIC;--DACへ
P1 : in STD_LOGIC;--YM2151から入力
IN_DATA : in STD_LOGIC;--YM2151から入力
SH1 : in STD_LOGIC;--YM2151から入力
SH2 : in STD_LOGIC--YM2151から入力
);
end main;
architecture Behavioral of main is
signal IN_SHIFT_REG : STD_LOGIC_VECTOR(12 downto 0);--入力シフトレジスタ13bit
--bit12~10はシフト数、bit9~0はデータ
signal OUT_SHIFT_REG : STD_LOGIC_VECTOR(14 downto 0);--出力シフトレジスタ13bit
signal IN_WCLK : STD_LOGIC;--入力ワードクロック
signal OUT_DATA_TEMP : STD_LOGIC_VECTOR(15 downto 0);--16bitへ変換後一時保存
signal LRCK_TEMP : STD_LOGIC;--LRCK状態一時保存
signal LRCK_SHIFT_OUT : STD_LOGIC;--出力シフトレジスタへデータをラッチする用(LRCKと同値)
begin
--入力シフトレジスタ
process (P1) begin
if (P1'event and P1= '1') then
IN_SHIFT_REG(12) <= IN_DATA;
IN_SHIFT_REG(11 downto 0) <= IN_SHIFT_REG(12 downto 1);
end if;
end process;
--ワードクロック生成
IN_WCLK <= SH1 nor SH2;
--13bitから16bitへ変換
process (IN_WCLK) begin
if (IN_WCLK'event and IN_WCLK= '1') then
case IN_SHIFT_REG(12 downto 10) is
when "001" => OUT_DATA_TEMP <= ((not IN_SHIFT_REG(9)) & (not IN_SHIFT_REG(9)) & (not IN_SHIFT_REG(9)) & (not IN_SHIFT_REG(9)) & (not IN_SHIFT_REG(9)) & (not IN_SHIFT_REG(9)) & (not IN_SHIFT_REG(9)) & IN_SHIFT_REG(8 downto 0));
when "010" => OUT_DATA_TEMP <= ((not IN_SHIFT_REG(9)) & (not IN_SHIFT_REG(9)) & (not IN_SHIFT_REG(9)) & (not IN_SHIFT_REG(9)) & (not IN_SHIFT_REG(9)) & (not IN_SHIFT_REG(9)) & IN_SHIFT_REG(8 downto 0) & '0');
when "011" => OUT_DATA_TEMP <= ((not IN_SHIFT_REG(9)) & (not IN_SHIFT_REG(9)) & (not IN_SHIFT_REG(9)) & (not IN_SHIFT_REG(9)) & (not IN_SHIFT_REG(9)) & IN_SHIFT_REG(8 downto 0) & "00");
when "100" => OUT_DATA_TEMP <= ((not IN_SHIFT_REG(9)) & (not IN_SHIFT_REG(9)) & (not IN_SHIFT_REG(9)) & (not IN_SHIFT_REG(9)) & IN_SHIFT_REG(8 downto 0) & "000");
when "101" => OUT_DATA_TEMP <= ((not IN_SHIFT_REG(9)) & (not IN_SHIFT_REG(9)) & (not IN_SHIFT_REG(9)) & IN_SHIFT_REG(8 downto 0) & "0000");
when "110" => OUT_DATA_TEMP <= ((not IN_SHIFT_REG(9)) & (not IN_SHIFT_REG(9)) & IN_SHIFT_REG(8 downto 0) & "00000");
when "111" => OUT_DATA_TEMP <= ((not IN_SHIFT_REG(9)) & IN_SHIFT_REG(8 downto 0) & "000000");
when others => OUT_DATA_TEMP <= "----------------";
end case;
end if;
end process;
--LRCK生成(非同期)
process (SH1,SH2) begin
if (SH1= '1') then
LRCK_TEMP <= '1';
elsif (SH2= '1') then
LRCK_TEMP <= '0';
else
LRCK_TEMP <= LRCK_TEMP;
end if;
end process;
--出力シフトレジスタ(MSBから出力)
process (P1, LRCK_TEMP) begin
if (P1'event and P1= '1') then
--LRCKの出力
LRCK <= LRCK_TEMP;--LRCKは出力シフト用のクロック(BCK= P1の反転)の立下りに同・・ LRCK_SHIFT_OUT <= LRCK_TEMP;
LRCK_SHIFT_OUT <= LRCK_TEMP;
--出力シフトレジスタへデータをセット
if (LRCK_SHIFT_OUT = LRCK_TEMP) then
OUT_DATA <= OUT_SHIFT_REG(14);
OUT_SHIFT_REG(14 downto 1) <= OUT_SHIFT_REG(13 downto 0);
--OUT_SHIFT_REG(0) <= '-';
else
OUT_DATA <= OUT_DATA_TEMP(15);
OUT_SHIFT_REG <= OUT_DATA_TEMP(14 downto 0);
end if;
end if;
end process;
--BCKの出力(入力クロックと逆位相)
BCK <= not P1;
end Behavioral;
回路規模はそこそこありますが、FPGAであれば気にすることなく書き込める規模です。
CPLDの場合、マクロセル数等が少ないものは入りきらない場合があります。
上記VHDL例では、XC9500シリーズのCPLDでマクロセルが48以上のもので動作します。
(XC9536では無理なので、XC9572やXC95144などのCPLDを用意してください。)
変換回路自体の仕組みは、「YM2151とYM3012・YM3014の以外のDACとの接続例」で紹介したものとは違いますが、変換の流れは同じなのでVHDLの中身については説明しません。(大きく違うのはシフト演算の方法ぐらいです)
・XC95144xl TQ100を使用した場合の回路
「YM2151とYM3012・YM3014の以外のDACとの接続例」で紹介した回路のロジックIC部分をまるまるCPLDに置き換えているのでだいぶすっきりしました。
DAC出力後のフィルタの設計はYM3012を使ったときのものと同様で良いでしょう。
・使用例 - MIDIの受信 -
YM2151を1個使用してMIDIを受信する場合の回路とプログラム(Arduino ATmega328p用)を紹介します。
音色パラメータはエクスクルーシブメッセージで送信できます。
パラメータ構造はYAMAHA VCEDフォーマットに近いですが、いくつか異なる部分があるので、
詳細はプログラム内のコメントを参照してください。
プログラムチェンジ(登録先)→「Program Change parameter Change」→「VCED parameter Change」または「VCED Bulk Dump」→プログラムチェンジ(登録先)
の順で送信することで、プログラムナンバーとOPMパラメータが結び付けられ、該当チャンネルの音色が反映されます。
別のチャンネルにも同じ音を割り当てたい時は、プログラムチェンジを該当チャンネルで行うことで音色が反映されます。
ただし、パーカッションチャンネル(ch10)のみVCEDナンバーの上位7bitが#define DRUM_VCED、
下位7bitがノートオン時のノートナンバーで指定された音色がキーオン時に登録され、発音します。
(プログラム例ではDRUM_VCED=0x08としています。)
※2024_10_28:軽微な不具合を修正しました。対応するMIDIファイルも要修正(VCEDバルク入力のデータがずれていた問題を修正)
さらにYM2164 (OPP),YM2414 (OPZ)でも演奏できるようにしました。
プログラム中の変数"unsigned char test[CH>>3]"で使用する音源ICを選択してください。(LFO未使用の場合、OPMでもTEST_OPP_OPZにすることが可能)
↓以前のバージョンはこちら
// YM2151・YM2164でMIDI演奏プログラム_Ver.1.1
// ©oy
// https://oykenkyu.blogspot.com/2022/05/ym2151.html
//YM2151 (OPM), YM2164 (OPP), YM2414 (OPZ)の3種類が使用可能
//ただし、YM2414 (OPZ)はOPMにあるレジスタ以外は操作対象外。さらにエンベロープの互換性が無いので、音色によっては崩れる。
//YM2414 (OPZ)を接続する場合は19番ピンSH2を2.2KΩの抵抗でプルアップしてください。
//下部の変数"unsigned char test[CH>>3]"で使用する音源ICを選択(LFO未使用の場合、OPMでもTEST_OPP_OPZにすることが可能)
// HardwareSerial.h内の「SERIAL_RX_BUFFER_SIZE」を64から256へ変更してください。「SERIAL_TX_BUFFER_SIZE」は変更しなくてよいです。
#include "avr/io.h"
#include "avr/interrupt.h"
#define SERIALSPEED 31250 // UARTのボーレート(MIDIのボーレートは31250bps)
//#define SERIALSPEED 38400 // UARTのボーレート(デバッグ用)
#define XTAL 16000000 // 水晶振動子の周波数
// #define XTAL 24576000 //水晶振動子の周波数(ドラムパートでもたつく場合に有効です。ATmega328pによっては動作しない場合があります。)
#define YM2151_N 1 // YM2151の個数(ATmega328の場合SRAMの関係上最大1つ SRAMがより多いマイコンを推奨 ただし、setupとym2151_writeの改変が必要)
#define VCED_N 12 // midi VCED保存可能最大パラメータ数
#define PC_N 12 // midi プログラムチェンジ-VCED紐付け保存可能最大数
#define DRUM_VCED 0x08 //(ch10(midiチャンネル0xX9)のノートナンバーNNはVCEDナンバー (hdata=0x08, ldata=0xNN)に割り当て
#define CH 16 // YM2151最大チャンネル数(YM2151は1つで8チャンネル分発音できます。)
#define MIDI_MAX_TR CH // MIDIトラック数
#define FM_DRUM_CH 7 // 音源内のドラムチャンネル
// YM2151オペレータ名と順番(レジスタ配置順とOP順が違うので注意)
#define OP1 0
#define OP2 2
#define OP3 1
#define OP4 3
#define M1 0
#define C1 2
#define M2 1
#define C2 3
// YM2151オペレータ名(アドレス計算用)
#define OP1_A 0
#define OP2_A 16
#define OP3_A 8
#define OP4_A 24
#define M1_A 0
#define C1_A 16
#define M2_A 8
#define C2_A 24
// YM2151レジスタ
#define TEST_OPM 0x01 // YM2151テストレジスタ
#define TEST_OPP_OPZ 0x09 // YM2164テストレジスタ
#define LFO_RESET 0x02 // テストレジスタ_LFOリセット
#define VOL_2164 0x00 // YM2164ボリュームレジスタ
#define VOL_2164_REG 0x7F // YM2164ボリュームレジスタビット
#define KON 0x08 // キーオン・キーオフレジスタ
#define SN 0x78 // キーオン・キーオフレジスタ_スロット指定
#define CH_REG 0x07 // キーオン・キーオフレジスタ_スロット指定
#define NOISE 0x0F // ノイズレジスタ
#define NE 0x80 // ノイズレジスタ_ノイズ有効
#define NFRQ 0x1F // ノイズレジスタ_ノイズ周波数
#define CLKA1 0x10 // タイマーA周期設定レジスタ上位8bit
#define CLKA2 0x11 // タイマーA周期設定レジスタ下位2bit
#define CLKA2_CLKA2 0x03 // タイマーA周期設定レジスタ下位2bit設定
#define CLKB 0x12 // タイマーB周期設定レジスタ
#define TIM_CONF 0x14 // タイマー動作設定レジスタ
#define CSM 0x80 // タイマー動作設定レジスタ_タイマーAによるオートキーオン有効
#define F_RESET_B 0x20 // タイマー動作設定レジスタ_タイマーBオーバーフローフラグクリア
#define F_RESET_A 0x10 // タイマー動作設定レジスタ_タイマーAオーバーフローフラグクリア
#define IRQ_EN_B 0x08 // タイマー動作設定レジスタ_タイマーBによる割り込み要求出力を有効
#define IRQ_EN_A 0x04 // タイマー動作設定レジスタ_タイマーAによる割り込み要求出力を有効
#define LOAD_B 0x02 // タイマー動作設定レジスタ_タイマーBのカウント動作を有効
#define LOAD_A 0x01 // タイマー動作設定レジスタ_タイマーAのカウント動作を有効
#define LFRQ 0x18 // LFO周波数設定レジスタ
#define PMD_AMD 0x19 // 位相変調・振幅変調深度設定レジスタ
#define LFO_MD_F 0x80 // 位相変調・振幅変調深度設定レジスタ_位相変調深度レジスタへ書き込み
#define LFO_MD 0x7F // 位相変調・振幅変調深度設定レジスタ_変調深度
#define CT_W 0x1B // 汎用端子出力ビット・LFO変調波形設定レジスタ
#define CT2 0x80 // 汎用端子出力ビット・LFO変調波形設定レジスタ_汎用出力ポートCT2への出力値
#define CT1 0x40 // 汎用端子出力ビット・LFO変調波形設定レジスタ_汎用出力ポートCT1への出力値
#define LFO_W 0x03 // 汎用端子出力ビット・LFO変調波形設定レジスタ_LFO変調波形
#define LR_FB_CON 0x20 // チャンネル出力・フィードバック・アルゴリズム設定レジスタ
#define RL 0xC0 // チャンネル出力・フィードバック・アルゴリズム設定レジスタ_RLチャンネルの出力を有効
#define RL_R 0x80 // チャンネル出力・フィードバック・アルゴリズム設定レジスタ_Rチャンネルの出力を有効
#define RL_L 0x40 // チャンネル出力・フィードバック・アルゴリズム設定レジスタ_Lチャンネルの出力を有効
#define FL 0x38 // チャンネル出力・フィードバック・アルゴリズム設定レジスタ_フィードバックレベル
#define CONECT 0x07 // チャンネル出力・フィードバック・アルゴリズム設定レジスタ_コネクション
#define KC 0x28 // 音程設定レジスタ
#define OCT 0x70 // 音程設定レジスタ_オクターブ設定
#define NOTE 0x0F // 音程設定レジスタ_ノート設定
#define KF 0x30 // キーフラクションレジスタ
#define KF_KF 0xFC // キーフラクションレジスタ設定
#define PMS_AMS 0x38 // LFO位相変調・振幅変調感度設定レジスタ
#define PMS 0x70 // LFO位相変調設定
#define AMS 0x03 // LFO振幅変調設定
#define DT1_MUL 0x40 // スロット倍率微調整・スロット倍率設定レジスタ
#define DT1 0x70 // スロット倍率微調整・スロット倍率設定レジスタ_スロット倍率微調整設定
#define MUL 0x0F // スロット倍率微調整・スロット倍率設定レジスタ_スロット倍率設定
#define TL 0x60 // スロット出力レベル設定レジスタ
#define TL_TL 0x7F // スロット出力レベル設定
#define KS_AR 0x80 // ピッチによるエンベロープ補正・エンベロープアタックレート設定レジスタ
#define KS 0xC0 // ピッチによるエンベロープ補正・エンベロープアタックレート設定レジスタ_ピッチによるエンベロープ補正設定
#define AR 0x1F // ピッチによるエンベロープ補正・エンベロープアタックレート設定レジスタ_エンベロープアタックレート設定
#define AMS_EN_D1R 0xA0 // AMS有効フラグ・エンベロープファーストディケイレート設定レジスタ
#define AMS_EN 0x80 // AMS有効フラグ・エンベロープファーストディケイレート設定レジスタ_AMS有効フラグ設定
#define D1R 0x1F // AMS有効フラグ・エンベロープファーストディケイレート設定レジスタ_エンベロープファーストディケイレート設定
#define DT2_D2R 0xC0 // スロット倍率粗調整・エンベロープセカンドディケイレート設定レジスタ
#define DT2 0xC0 // スロット倍率粗調整・エンベロープセカンドディケイレート設定レジスタ_スロット倍率粗調整設定
#define D2R 0x1F // スロット倍率粗調整・エンベロープセカンドディケイレート設定レジスタ_エンベロープセカンドディケイレート設定
#define D1L_RR 0xE0 // エンベロープファーストディケイレベル・エンベロープセカンドディケイレート設定レジスタ
#define D1L 0xF0 // エンベロープファーストディケイレベル・エンベロープセカンドディケイレート設定レジスタ_エンベロープファーストディケイレベル設定
#define RR 0x0F // エンベロープファーストディケイレベル・エンベロープセカンドディケイレート設定レジスタ_エンベロープセカンドディケイレート設定
//テストレジスタアドレス保存 YM2151とYM2164の混在用
//使用する音源ICをここで選択(LFO未使用の場合、OPMでもTEST_OPP_OPZにすることが可能)
unsigned char test[CH>>3] = {TEST_OPM, TEST_OPM};//OPMの場合TEST_OPM、OPPとOPZの場合TEST_OPP_OPZに設定
// YM2151レジスタ保存
union Ym2151_data_st
{
struct
{
unsigned char reserve_00;
unsigned char test;
unsigned char reserve_02;
unsigned char reserve_03;
unsigned char reserve_04;
unsigned char reserve_05;
unsigned char reserve_06;
unsigned char reserve_07;
unsigned char kon;
unsigned char reserve_09;
unsigned char reserve_0A;
unsigned char reserve_0B;
unsigned char reserve_0C;
unsigned char reserve_0D;
unsigned char reserve_0E;
unsigned char noise;
unsigned char clka1;
unsigned char clka2;
unsigned char clkb;
unsigned char reserve_13;
unsigned char tim_conf;
unsigned char reserve_15;
unsigned char reserve_16;
unsigned char reserve_17;
unsigned char lfrq;
unsigned char pmd_amd;
unsigned char reserve_1A;
unsigned char ct_w;
unsigned char reserve_1C;
unsigned char reserve_1D;
unsigned char reserve_1E;
unsigned char reserve_1F;
unsigned char lr_fb_conf[8];
unsigned char kc[8];
unsigned char kf[8];
unsigned char pms_ams[8];
unsigned char dt1_mul[32];
unsigned char tl[32];
unsigned char ks_ar[32];
unsigned char ams_en_d1r[32];
unsigned char dt2_d2r[32];
unsigned char d1l_rr[32];
} reg;
unsigned char data[256];
};
// YM2151_保存用
Ym2151_data_st ym2151_data[YM2151_N];
unsigned char ym2151_slot_en[CH]; // スロットONOFF保存用(ノートオンで使用)
unsigned char ym2151_main_vol[CH]; // 音量保存用(オペレータごとの最終出力演算に使用)
unsigned char ym2151_lfo_rst_en[CH] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // LFOをリセットするか? 0:no, 1~255:yes
// VCED保存用
unsigned char vced_ram[VCED_N][64];
// VCEDナンバー保存(Program Change parameter Changeで受信した値と内部値の変換)
unsigned int vced_tr[VCED_N]; // 0bXXNNNNNN NNNNNNNN,[N:データ、X:未使用]
unsigned char vced_tr_c = 0; // 登録用カウンタ、最大VCED_N-1
// プログラムチェンジとVCEDナンバー保存の紐付け
unsigned int vced_nc[PC_N];
unsigned char pc_nc[PC_N];
unsigned char vced_pc_c = 0; // 登録用カウンタ、最大PC_N-1
// YM2151のノートデータへ変換
const unsigned char PROGMEM ym2151_note_conv[96] = {
0x00, 0x01, 0x02, 0x04, 0x05, 0x06, 0x08, 0x09, 0x0A, 0x0C, 0x0D, 0x0E,
0x10, 0x11, 0x12, 0x14, 0x15, 0x16, 0x18, 0x19, 0x1A, 0x1C, 0x1D, 0x1E,
0x20, 0x21, 0x22, 0x24, 0x25, 0x26, 0x28, 0x29, 0x2A, 0x2C, 0x2D, 0x2E,
0x30, 0x31, 0x32, 0x34, 0x35, 0x36, 0x38, 0x39, 0x3A, 0x3C, 0x3D, 0x3E,
0x40, 0x41, 0x42, 0x44, 0x45, 0x46, 0x48, 0x49, 0x4A, 0x4C, 0x4D, 0x4E,
0x50, 0x51, 0x52, 0x54, 0x55, 0x56, 0x58, 0x59, 0x5A, 0x5C, 0x5D, 0x5E,
0x60, 0x61, 0x62, 0x64, 0x65, 0x66, 0x68, 0x69, 0x6A, 0x6C, 0x6D, 0x6E,
0x70, 0x71, 0x72, 0x74, 0x75, 0x76, 0x78, 0x79, 0x7A, 0x7C, 0x7D, 0x7E};
// YM2151のレベル変換 127*(1-log127(vol))
const unsigned char PROGMEM ym2151_tl_vol_conv[128] = {
127, 127, 109, 98, 91, 85, 80, 76, 72, 69, 67, 64, 62, 60, 58, 56,
54, 53, 51, 50, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37,
36, 35, 35, 34, 33, 32, 32, 31, 30, 30, 29, 28, 28, 27, 27, 26,
26, 25, 24, 24, 23, 23, 22, 22, 21, 21, 21, 20, 20, 19, 19, 18,
18, 18, 17, 17, 16, 16, 16, 15, 15, 15, 14, 14, 13, 13, 13, 12,
12, 12, 11, 11, 11, 11, 10, 10, 10, 9, 9, 9, 8, 8, 8, 8,
7, 7, 7, 7, 6, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4,
3, 3, 3, 3, 2, 2, 2, 2, 1, 1, 1, 1, 1, 0, 0, 0};
// YM2151パラメータ
// パラメータ構造
// LFRQ,AMD,PMD,WF,NFRQ
//,PAN(bit7,bit6),FL,CON,AMS,PMS,SLOT(bit6~bit3),NE(bit7)
//,M1-AR,M1-D1R,M1-D2R,M1-RR,M1-D1L,M1-TL,M1-KS,M1-MUL,M1-DT1,M1-DT2,M1-AMS-EN
//,C1-AR,C1-D1R,C1-D2R,C1-RR,C1-D1L,C1-TL,C1-KS,C1-MUL,C1-DT1,C1-DT2,C1-AMS-EN
//,M2-AR,M2-D1R,M2-D2R,M2-RR,M2-D1L,M2-TL,M2-KS,M2-MUL,M2-DT1,M2-DT2,M2-AMS-EN
//,C2-AR,C2-D1R,C2-D2R,C2-RR,C2-D1L,C2-TL,C2-KS,C2-MUL,C2-DT1,C2-DT2,C2-AMS-EN
// TRPS(音程:標準は24),reserve,reserve,reserve,reserve,reserve,reserve,reserve
const unsigned char PROGMEM ym2151_parameter[][64] = {
//0 YAMAHA HD-81 P.ORGAN
{
0, 0, 0, 2, 0,
0b11000000, 0, 4, 0, 0, 120, 0,
20, 2, 0, 4, 0, 34, 1, 8, 0, 0, 0,
14, 2, 0, 7, 0, 31, 0, 4, 0, 0, 0,
18, 2, 0, 4, 0, 27, 1, 0, 0, 0, 0,
13, 2, 0, 7, 0, 8, 0, 0, 0, 0, 0,
48, 0, 0, 0, 0, 0, 0, 0
},
//1 YAMAHA HD-81 PIANO
{
0, 0, 0, 0, 0,
0b11000000, 0, 4, 0, 0, 120, 0,
31, 6, 6, 7, 4, 39, 1, 3, 0, 0, 0,
30, 3, 3, 5, 4, 16, 3, 1, 0, 0, 0,
31, 5, 5, 6, 4, 44, 1, 1, 0, 0, 0,
30, 3, 3, 5, 4, 13, 3, 1, 0, 0, 0,
36, 0, 0, 0, 0, 0, 0, 0
},
//2 YAMAHA HD-81 W.WIND(H)
{
0, 0, 0, 0, 0,
0b11000000, 7, 4, 0, 0, 64, 0,
31, 31, 0, 3, 4, 127, 0, 4, 0, 0, 0,
31, 16, 0, 8, 1, 127, 1, 2, 0, 0, 0,
15, 31, 0, 3, 4, 127, 0, 4, 0, 0, 0,
15, 16, 0, 8, 1, 6, 1, 2, 0, 0, 0,
24, 0, 0, 0, 0, 0, 0, 0
},
//3 YAMAHA HD-81 W.WIND
{
0, 0, 0, 0, 0,
0b11000000, 6, 4, 0, 0, 120, 0,
29, 31, 0, 3, 4, 32, 0, 4, 0, 0, 0,
14, 16, 0, 8, 1, 29, 1, 1, 0, 0, 0,
30, 31, 0, 3, 4, 33, 0, 4, 0, 0, 0,
14, 16, 0, 8, 1, 11, 1, 1, 0, 0, 0,
36, 0, 0, 0, 0, 0, 0, 0
},
//4 YAMAHA HD-81 BRASS
{
0, 0, 0, 0, 0,
0b11000000, 7, 5, 0, 0, 120, 0,
13, 5, 0, 4, 0, 33, 2, 1, 0, 0, 0,
16, 4, 0, 8, 0, 16, 0, 1, 0, 0, 0,
16, 3, 0, 8, 0, 18, 0, 1, 0, 0, 0,
16, 6, 0, 8, 4, 18, 1, 1, 0, 0, 0,
36, 0, 0, 0, 0, 0, 0, 0
},
//5 YAMAHA HD-81 BRASS(L)
{
0, 0, 0, 0, 0,
0b11000000, 7, 5, 0, 0, 120, 0,
10, 5, 0, 4, 2, 29, 2, 0, 0, 0, 0,
17, 4, 0, 8, 0, 16, 0, 0, 0, 0, 0,
17, 3, 0, 8, 0, 18, 0, 0, 0, 0, 0,
17, 6, 0, 8, 4, 18, 1, 0, 0, 0, 0,
48, 0, 0, 0, 0, 0, 0, 0
},
//6 YAMAHA HD-81 STRING
{
0, 0, 0, 0, 0,
0b11000000, 7, 2, 0, 0, 120, 0,
18, 4, 0, 4, 0, 29, 1, 0, 0, 0, 0,
17, 6, 0, 4, 0, 48, 1, 2, 0, 0, 0,
16, 8, 0, 4, 0, 63, 1, 2, 0, 0, 0,
11, 6, 0, 8, 0, 6, 1, 0, 0, 0, 0,
48, 0, 0, 0, 0, 0, 0, 0
},
//7 YAMAHA HD-81 STRING(L)
{
0, 0, 0, 0, 0,
0b11000000, 7, 2, 0, 0, 120, 0,
18, 4, 0, 4, 0, 30, 1, 0, 0, 0, 0,
17, 6, 0, 4, 0, 48, 1, 2, 0, 0, 0,
16, 8, 0, 4, 0, 63, 1, 2, 0, 0, 0,
11, 6, 0, 8, 0, 6, 1, 0, 0, 0, 0,
48, 0, 0, 0, 0, 0, 0, 0
}
};
// デフォルトトーン[ch0,ch1,ch2,…,]
// 増やすと半音高くなります。(出力音程 = def_tone + (midiの音程))
char def_tone[CH] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
// デフォルトキー
char def_key = 0;
// MIDIチャンネルからYM2151のチャンネルへ変換
char ym2151_tr[16] = {0, 1, 2, 3, 4, 5, 6, 8, 9, 7, 10, 11, 12, 13, 14, 15}; // YM2151が1個
// char ym2151_tr[16] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 15, 10, 11, 12, 13, 14, 9};//YM2151が2個
//--------------------------------------------------------------
// ドラム発音用
unsigned char drum_note_num = 0; // ドラムチャンネルセット保存用
// MIDI受信用
char midi_main_vel[16] = {127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127}; // メインベロシティ(YM2151では未使用)(ノートベロシティと乗算して使用)
char midi_pan[16] = {64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64}; // パン
char midi_vel[16] = {127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127}; // ベロシティ
unsigned char midi_buf[256]; // 受信バッファ
int ex_mess_en = 0; // midi_read()で使用
unsigned int dat_ph = 0; // midi_read()で使用
unsigned char read_buf_h; // midi_read()で使用
unsigned int stop_byte = 0; // midi_read()で使用
unsigned char read_buf = 0; // midi_read()で使用
unsigned char running_ch = 0x90; // ランニングステータスチャンネル
unsigned char midiprog[16] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; // MIDIプログラムチェンジ保存
unsigned char sas_en = 0; // サスティン有効フラグ
/////////////////////////////関数
// YM2151へ書き込み
inline void ym2151_write(unsigned char cs, unsigned char adr, unsigned char data);
// 音程のセット
void ptc_set(unsigned char ch, unsigned int notenum);
// メインの音量とパンのセット
void main_vel_pan_set(unsigned char vel, unsigned char pan);
// チャンネルの音量とパンのセット
void vel_pan_set(unsigned char ch, unsigned char vel, unsigned char pan);
// チャンネルノートオン
void note_on(unsigned char ch);
// チャンネルノートオフ
void note_off(unsigned char ch);
// 音色セット
void inst_set(unsigned char ch, unsigned char inst);
// MIDI受信関係
// 1バイトずつmidi_readを実行し、1グループのmidiメッセージを受信し終えるとmidi_comを実行
void midi_read(char read_buf);
// MIDIデータ入力処理
inline void midi_com(unsigned char *in_midi_mess);
// セットアップ
void setup()
{
Serial.begin(SERIALSPEED * (16000000.0 / XTAL)); // シリアル通信開始(MIDI受信)
//Serial.print("OK\r\n");
delay(100);
// ポート設定
// out_put
DDRD = 0xFC; // pin2~pin7_YM2151:D2~D7
PORTD = 0x00; // pin2~pin7_YM2151:D2~D7
DDRB = 0x3F; // pin8~pin9_YM2151:D0~D1 pin10~pin13_YM2151:~RD, ~WE, A0, ~RST
PORTB = 0x3C; // pin8~pin9_YM2151:D0~D1 pin10~pin13_YM2151:~RD, ~WE, A0, ~RST
DDRC = 0x0F; // pin14~pin17_YM2151:~CS0 ~ ~CS3
PORTC = 0x0F; // pin14~pin17_YM2151:~CS0 ~ ~CS3
// リセット
PORTB &= ~0x20; // pin13_YM2151: ~RST = L
delay(200);
PORTB |= 0x20; // pin13_YM2151: ~RST = H
delay(200);
// VCED保存用初期化
for (int i = 0; i < VCED_N; i++)
{
vced_tr[i] = 0; // 0bXXNNNNNN NNNNNNNN,[N:データ、X:未使用]
}
// プログラムチェンジとVCEDナンバー保存の紐付け初期化
for (int i = 0; i < PC_N; i++)
{
vced_nc[i] = 0; // 0bXXNNNNNN NNNNNNNN,[N:データ、X:未使用]
pc_nc[i] = i;
}
// テストレジスタ初期化
for (int i = 0; i < (CH >> 3); i++)
{
ym2151_regset_write(i, test[i], 0xFF, 0x00);
if(test[i] == TEST_OPP_OPZ)
{
//YM2164 (OPP),YM2414 (OPZ)だった場合、チャンネルボリュームを設定(TLで音量制御するため、この以降チャンネルボリュームは不変)
for (int j = 0; j < 8; j++)
{
ym2151_regset_write(i, VOL_2164, VOL_2164_REG + j, 0x00);
}
//YM2414 (OPZ)向け
ym2151_regset_write(i, 0x0A, 0xFF, 0x04);//opz_test2(?,?,?,?,音割れ,ステレオ可,?,サンプルホールド端子出力しない)
ym2151_regset_write(i, 0x1C, 0xFF, 0x00);//opz_test(?,?,?,?,?,?,?,?)
ym2151_regset_write(i, 0x1E, 0xFF, 0x00);//opz_test(?,?,?,?,?,?,?,?)
ym2151_regset_write(i, 0x15, 0xFF, 0x01);//opz_test(?,?,?,?,?,?,不明,ステレオ可)
}
}
// YM2151キーオフ
for (int i = 0; i < CH; i++)
{
note_off(i);
}
// パラメータ初期化
for (int i = 0; i < VCED_N; i++)
{
//intparam_set_vced(ch, inst);
intparam_set_vced(i, 1);//内部音色パラメータをVCED保存領域にセット
}
for (int i = 0; i < CH; i++)
{
ym2151_vced_set(i, 0);//VCED反映
}
/*// パラメータ初期化
for (int i = 0; i < (YM2151_N<<3); i++)
{
ym2151_param_set_all_test(i >> 3,i & 0x07,0);
}*/
// 初期チャンネル音量
for (int i = 0; i < CH; i++)
{
vel_pan_set(i, 0, 64);
}
}
void loop()
{
while (1)
{
if (Serial.available() > 0)
{
midi_read(Serial.read()); // イベント処理
}
}
}
// YM2151へ書き込み
void ym2151_write(unsigned char cs, unsigned char adr, unsigned char data)
{
unsigned char temp_data = 0x80; // ステータスレジスタの内容を一時保存
DDRD &= 0x03; // pin2~pin7_YM2151:D2~D7を高Z
DDRB &= 0xFC; // pin8~pin9_YM2151:D0~D1を高Z
DDRB |= 0x3C; // YM2151:~RST,A0,~WE,~RDを出力に設定
PORTB |= 0x10; // pin13_YM2151: A0 = H
PORTB |= 0x04; // pin12_YM2151: ~RD = H
PORTB |= 0x08; // pin11_YM2151: ~WR = H
PORTD &= 0x80; // pin11_YM2151: D7プルアップ無効
// チップセレクト
PORTC = (PORTC & 0xF0) | (0x0F & (~(1 << cs))); // pin14~pin17_YM2151:~CS0 ~ ~CS3
delayMicroseconds(8);
// ビジーフラグがLになるまで待機
/*for (int time_out = 0; time_out <= 10; time_out++)
{
if (time_out == 10)
{
PORTC = (PORTC & 0xF0) | (0x0F); // pin14~pin17_YM2151:~CS0 ~ ~CS3 = L
return;
}
PORTB &= ~0x04; // pin12_YM2151: ~RD = L
delayMicroseconds(8);
temp_data = PIND;
// delayMicroseconds(10);
PORTB |= 0x04; // pin12_YM2151: ~RD = H
delayMicroseconds(8);
if ((temp_data >> 7) == 0x00)
{
break;
}
}*/
delayMicroseconds(80);
// アドレスのセット
PORTB &= ~0x10; // pin13_YM2151: A0 = L
// delayMicroseconds(5);
DDRD |= 0xFC; // pin2~pin7_YM2151:D2~D7を出力ポートにする
DDRB |= 0x03; // pin8~pin9_YM2151:D0~D1を出力ポートにする
// delayMicroseconds(5);
PORTB = (PORTB & 0xFC) | (0x03 & adr); // pin9,8_YM2151:D1,D0
PORTD = (PORTD & 0x03) | (0xFC & adr); // pin7~2_YM2151:D7~D2
delayMicroseconds(8);
PORTB &= ~0x08; // pin11_YM2151: ~WR = L
delayMicroseconds(8);
PORTB |= 0x08; // pin11_YM2151: ~WR = H
delayMicroseconds(8);
// データのセット
PORTB |= 0x10; // pin13_YM2151: A0 = H
// delayMicroseconds(5);
PORTB = (PORTB & 0xFC) | (0x03 & data); // pin9,8_YM2151:D1,D0
PORTD = (PORTD & 0x03) | (0xFC & data); // pin7~2_YM2151:D7~D2
delayMicroseconds(8);
PORTB &= ~0x08; // pin11_YM2151: ~WR = L
delayMicroseconds(8);
PORTB |= 0x08; // pin11_YM2151: ~WR = H
delayMicroseconds(8);
PORTC = (PORTC & 0xF0) | (0x0F); // pin14~pin17_YM2151:~CS0 ~ ~CS3 = L
delayMicroseconds(8);
}
// YM2151のレジスタビットへ値をセット
void ym2151_regset(unsigned char cs, unsigned char adr, unsigned char reg, unsigned char data)
{
if (cs >= YM2151_N)
{
return;
}
// regはマスクビット群
//(reg & (-reg))は、複数のHビットのうち右端のHビットのみ残す
//(reg & (-reg)) * dataは、実質ビットシフト
// レジスタの保存
// ym2151_data[cs].data[adr] = (ym2151_data[cs].data[adr] & (~reg)) | (reg & ((reg & (-reg)) * data));
ym2151_data[cs].data[adr] = (ym2151_data[cs].data[adr] & (~reg)) | (reg & ((reg & (reg ^ (reg << 1))) * data));
}
// YM2151のレジスタビットへ値をセット(ym2151への書き込みも行う)
void ym2151_regset_write(unsigned char cs, unsigned char adr, unsigned char reg, unsigned char data)
{
if (cs >= YM2151_N)
{
return;
}
// regはマスクビット群
//(reg & (-reg))は、複数のHビットのうち右端のHビットのみ残す
//(reg & (-reg)) * dataは、実質ビットシフト
// レジスタの保存
// ym2151_data[cs].data[adr] = (ym2151_data[cs].data[adr] & (~reg)) | (reg & ((reg & (-reg)) * data));
ym2151_data[cs].data[adr] = (ym2151_data[cs].data[adr] & (~reg)) | (reg & ((reg & (reg ^ (reg << 1))) * data));
// ym2151へ書き込み
ym2151_write(cs, adr, ym2151_data[cs].data[adr]);
}
// YM2151のレジスタ仮想読み込み(マイコン内のRAMから読み込み)
unsigned char ym2151_regread(unsigned char cs, unsigned char adr, unsigned char reg)
{
return (reg & ym2151_data[cs].data[adr]) / (reg & (reg ^ (reg << 1)));
}
// ym2151パラメータセット(LFO、ノイズ含むすべて)
void ym2151_param_set_all(unsigned char cs, unsigned char ch, int inst)
{
// 入力データ構造
// LFRQ,AMD,PMD,WF,NFRQ
//,PAN(bit7,bit6),FL,CON,AMS,PMS,SLOT(bit6~bit3),NE(bit7)
//,M1-AR,M1-D1R,M1-D2R,M1-RR,M1-D1L,M1-TL,M1-KS,M1-MUL,M1-DT1,M1-DT2,M1-AMS-EN(bit7)
//,C1-AR,C1-D1R,C1-D2R,C1-RR,C1-D1L,C1-TL,C1-KS,C1-MUL,C1-DT1,C1-DT2,C1-AMS-EN
//,M2-AR,M2-D1R,M2-D2R,M2-RR,M2-D1L,M2-TL,M2-KS,M2-MUL,M2-DT1,M2-DT2,M2-AMS-EN
//,C2-AR,C2-D1R,C2-D2R,C2-RR,C2-D1L,C2-TL,C2-KS,C2-MUL,C2-DT1,C2-DT2,C2-AMS-EN
// reserve,reserve,reserve,reserve,reserve,reserve,reserve,reserve
ym2151_regset_write(cs, LFRQ, 0xFF, pgm_read_byte_near((int)(ym2151_parameter[inst] + 0))); // LFRQ
ym2151_regset_write(cs, PMD_AMD, LFO_MD_F | LFO_MD, 0x7F & pgm_read_byte_near((int)(ym2151_parameter[inst] + 1))); // AMD
ym2151_regset_write(cs, PMD_AMD, LFO_MD_F | LFO_MD, LFO_MD_F | pgm_read_byte_near((int)(ym2151_parameter[inst] + 2))); // PMD
ym2151_regset_write(cs, CT_W, LFO_W, pgm_read_byte_near((int)(ym2151_parameter[inst] + 3))); // WF
ym2151_regset_write(cs, NOISE, NFRQ, pgm_read_byte_near((int)(ym2151_parameter[inst] + 4))); // NFRQ
ym2151_regset_write(cs, LR_FB_CON + ch, 0xFF, (pgm_read_byte_near((int)(ym2151_parameter[inst] + 5)) & RL) | ((pgm_read_byte_near((int)(ym2151_parameter[inst] + 6)) << 3) & FL) | (pgm_read_byte_near((int)(ym2151_parameter[inst] + 7)) & CONECT)); // PAN(bit7,bit6), FL, CON
// ym2151_regset_write(cs, LR_FB_CON + ch, FL, pgm_read_byte_near((int)(ym2151_parameter[inst] + 6)));//FL
// ym2151_regset_write(cs, LR_FB_CON + ch, CONECT, pgm_read_byte_near((int)(ym2151_parameter[inst] + 7)));//CON
ym2151_regset_write(cs, PMS_AMS + ch, 0xFF, (pgm_read_byte_near((int)(ym2151_parameter[inst] + 8)) & AMS) | ((pgm_read_byte_near((int)(ym2151_parameter[inst] + 9)) << 4) & PMS)); // AMS,PMS
// ym2151_regset_write(cs, PMS_AMS + ch, PMS, pgm_read_byte_near((int)(ym2151_parameter[inst] + 9)));//PMS
ym2151_slot_en[(cs << 3) | ch] = pgm_read_byte_near((int)(ym2151_parameter[inst] + 10)); // SLOT(bit6~bit3)
ym2151_regset_write(cs, NOISE, NE, pgm_read_byte_near((int)(ym2151_parameter[inst] + 11)) >> 7); // NE(bit7)
// M1
ym2151_regset_write(cs, KS_AR + ch, 0xFF, (pgm_read_byte_near((int)(ym2151_parameter[inst] + 12)) & AR) | (pgm_read_byte_near((int)(ym2151_parameter[inst] + 18)) << 6)); // M1-AR,KS
ym2151_regset_write(cs, AMS_EN_D1R + ch, 0xFF, (pgm_read_byte_near((int)(ym2151_parameter[inst] + 13)) & D1R) | (pgm_read_byte_near((int)(ym2151_parameter[inst] + 22)) & AMS_EN)); // M1-D1R,AMS-EN(bit7)
ym2151_regset_write(cs, DT2_D2R + ch, 0xFF, (pgm_read_byte_near((int)(ym2151_parameter[inst] + 14)) & D2R) | (pgm_read_byte_near((int)(ym2151_parameter[inst] + 21)) << 6)); // M1-D2R,DT2
ym2151_regset_write(cs, D1L_RR + ch, 0xFF, (pgm_read_byte_near((int)(ym2151_parameter[inst] + 15)) & RR) | (pgm_read_byte_near((int)(ym2151_parameter[inst] + 16)) << 4)); // M1-RR,D1L
// ym2151_regset_write(cs, D1L_RR + ch, D1L, pgm_read_byte_near((int)(ym2151_parameter[inst] + 16)));//M1-D1L
ym2151_regset_write(cs, TL + ch, TL_TL, pgm_read_byte_near((int)(ym2151_parameter[inst] + 17))); // M1-TL
// ym2151_regset_write(cs, KS_AR + ch, KS, pgm_read_byte_near((int)(ym2151_parameter[inst] + 18)));//M1-KS
ym2151_regset_write(cs, DT1_MUL + ch, 0xFF, (pgm_read_byte_near((int)(ym2151_parameter[inst] + 19)) & MUL) | (pgm_read_byte_near((int)(ym2151_parameter[inst] + 20)) << 4)); // M1-MUL,DT1
// ym2151_regset_write(cs, DT1_MUL + ch, DT1, pgm_read_byte_near((int)(ym2151_parameter[inst] + 20)));//M1-DT1
// ym2151_regset_write(cs, DT2_D2R + ch, DT2, pgm_read_byte_near((int)(ym2151_parameter[inst] + 21)));//M1-DT2
// ym2151_regset_write(cs, AMS_EN_D1R + ch, AMS_EN, pgm_read_byte_near((int)(ym2151_parameter[inst] + 22)));//M1-AMS-EN(bit7)
// C1
ym2151_regset_write(cs, KS_AR + ch + 16, 0xFF, (pgm_read_byte_near((int)(ym2151_parameter[inst] + 23)) & AR) | (pgm_read_byte_near((int)(ym2151_parameter[inst] + 29)) << 6)); // C1-AR,KS
ym2151_regset_write(cs, AMS_EN_D1R + ch + 16, 0xFF, (pgm_read_byte_near((int)(ym2151_parameter[inst] + 24)) & D1R) | (pgm_read_byte_near((int)(ym2151_parameter[inst] + 33)) & AMS_EN)); // C1-D1R,AMS-EN(bit7)
ym2151_regset_write(cs, DT2_D2R + ch + 16, 0xFF, (pgm_read_byte_near((int)(ym2151_parameter[inst] + 25)) & D2R) | (pgm_read_byte_near((int)(ym2151_parameter[inst] + 32)) << 6)); // C1-D2R,DT2
ym2151_regset_write(cs, D1L_RR + ch + 16, 0xFF, (pgm_read_byte_near((int)(ym2151_parameter[inst] + 26)) & RR) | (pgm_read_byte_near((int)(ym2151_parameter[inst] + 27)) << 4)); // C1-RR,D1L
// ym2151_regset_write(cs, D1L_RR + ch + 16, D1L, pgm_read_byte_near((int)(ym2151_parameter[inst] + 27)));//C1-D1L
ym2151_regset_write(cs, TL + ch + 16, TL_TL, pgm_read_byte_near((int)(ym2151_parameter[inst] + 28))); // C1-TL
// ym2151_regset_write(cs, KS_AR + ch + 16, KS, pgm_read_byte_near((int)(ym2151_parameter[inst] + 29)));//C1-KS
ym2151_regset_write(cs, DT1_MUL + ch + 16, 0xFF, (pgm_read_byte_near((int)(ym2151_parameter[inst] + 30)) & MUL) | (pgm_read_byte_near((int)(ym2151_parameter[inst] + 31)) << 4)); // C1-MUL,DT1
// ym2151_regset_write(cs, DT1_MUL + ch + 16, DT1, pgm_read_byte_near((int)(ym2151_parameter[inst] + 31)));//C1-DT1
// ym2151_regset_write(cs, DT2_D2R + ch + 16, DT2, pgm_read_byte_near((int)(ym2151_parameter[inst] + 32)));//C1-DT2
// ym2151_regset_write(cs, AMS_EN_D1R + ch + 16, AMS_EN, pgm_read_byte_near((int)(ym2151_parameter[inst] + 33)));//C1-AMS-EN(bit7)
// M2
ym2151_regset_write(cs, KS_AR + ch + 8, 0xFF, (pgm_read_byte_near((int)(ym2151_parameter[inst] + 34)) & AR) | (pgm_read_byte_near((int)(ym2151_parameter[inst] + 40)) << 6)); // M2-AR,KS
ym2151_regset_write(cs, AMS_EN_D1R + ch + 8, 0xFF, (pgm_read_byte_near((int)(ym2151_parameter[inst] + 35)) & D1R) | (pgm_read_byte_near((int)(ym2151_parameter[inst] + 44)) & AMS_EN)); // M2-D1R,AMS-EN(bit7)
ym2151_regset_write(cs, DT2_D2R + ch + 8, 0xFF, (pgm_read_byte_near((int)(ym2151_parameter[inst] + 36)) & D2R) | (pgm_read_byte_near((int)(ym2151_parameter[inst] + 43)) << 6)); // M2-D2R,DT2
ym2151_regset_write(cs, D1L_RR + ch + 8, 0xFF, (pgm_read_byte_near((int)(ym2151_parameter[inst] + 37)) & RR) | (pgm_read_byte_near((int)(ym2151_parameter[inst] + 38)) << 4)); // M2-RR,D1L
// ym2151_regset_write(cs, D1L_RR + ch + 8, D1L, pgm_read_byte_near((int)(ym2151_parameter[inst] + 38)));//M2-D1L
ym2151_regset_write(cs, TL + ch + 8, TL_TL, pgm_read_byte_near((int)(ym2151_parameter[inst] + 39))); // M2-TL
// ym2151_regset_write(cs, KS_AR + ch + 8, KS, pgm_read_byte_near((int)(ym2151_parameter[inst] + 40)));//M2-KS
ym2151_regset_write(cs, DT1_MUL + ch + 8, 0xFF, (pgm_read_byte_near((int)(ym2151_parameter[inst] + 41)) & MUL) | (pgm_read_byte_near((int)(ym2151_parameter[inst] + 42)) << 4)); // M2-MUL,DT1
// ym2151_regset_write(cs, DT1_MUL + ch + 8, DT1, pgm_read_byte_near((int)(ym2151_parameter[inst] + 42)));//M2-DT1
// ym2151_regset_write(cs, DT2_D2R + ch + 8, DT2, pgm_read_byte_near((int)(ym2151_parameter[inst] + 43)));//M2-DT2
// ym2151_regset_write(cs, AMS_EN_D1R + ch + 8, AMS_EN, pgm_read_byte_near((int)(ym2151_parameter[inst] + 44)));//M2-AMS-EN(bit7)
// C2
ym2151_regset_write(cs, KS_AR + ch + 24, 0xFF, (pgm_read_byte_near((int)(ym2151_parameter[inst] + 45)) & AR) | (pgm_read_byte_near((int)(ym2151_parameter[inst] + 51)) << 6)); // C2-AR,KS
ym2151_regset_write(cs, AMS_EN_D1R + ch + 24, 0xFF, (pgm_read_byte_near((int)(ym2151_parameter[inst] + 46)) & D1R) | (pgm_read_byte_near((int)(ym2151_parameter[inst] + 55)) & AMS_EN)); // C2-D1R,AMS-EN(bit7)
ym2151_regset_write(cs, DT2_D2R + ch + 24, 0xFF, (pgm_read_byte_near((int)(ym2151_parameter[inst] + 47)) & D2R) | (pgm_read_byte_near((int)(ym2151_parameter[inst] + 54)) << 6)); // C2-D2R,DT2
ym2151_regset_write(cs, D1L_RR + ch + 24, 0xFF, (pgm_read_byte_near((int)(ym2151_parameter[inst] + 48)) & RR) | (pgm_read_byte_near((int)(ym2151_parameter[inst] + 49)) << 4)); // C2-RR,D1L
// ym2151_regset_write(cs, D1L_RR + ch + 24, D1L, pgm_read_byte_near((int)(ym2151_parameter[inst] + 49)));//C2-D1L
ym2151_regset_write(cs, TL + ch + 24, TL_TL, pgm_read_byte_near((int)(ym2151_parameter[inst] + 50))); // C2-TL
// ym2151_regset_write(cs, KS_AR + ch + 24, KS, pgm_read_byte_near((int)(ym2151_parameter[inst] + 51)));//C2-KS
ym2151_regset_write(cs, DT1_MUL + ch + 24, 0xFF, (pgm_read_byte_near((int)(ym2151_parameter[inst] + 52)) & MUL) | (pgm_read_byte_near((int)(ym2151_parameter[inst] + 53)) << 4)); // C2-MUL,DT1
// ym2151_regset_write(cs, DT1_MUL + ch + 24, DT1, pgm_read_byte_near((int)(ym2151_parameter[inst] + 53)));//C2-DT1
// ym2151_regset_write(cs, DT2_D2R + ch + 24, DT2, pgm_read_byte_near((int)(ym2151_parameter[inst] + 54)));//C2-DT2
// ym2151_regset_write(cs, AMS_EN_D1R + ch + 24, AMS_EN, pgm_read_byte_near((int)(ym2151_parameter[inst] + 55)));//C2-AMS-EN(bit7)
}
// ym2151パラメータセット(LFO、ノイズ含むすべて)
void ym2151_param_set_all_test(unsigned char cs, unsigned char ch, int inst)
{
// 入力データ構造
// LFRQ,AMD,PMD,WF,NFRQ
//,PAN(bit7,bit6),FL,CON,AMS,PMS,SLOT(bit6~bit3),NE(bit7)
//,M1-AR,M1-D1R,M1-D2R,M1-RR,M1-D1L,M1-TL,M1-KS,M1-MUL,M1-DT1,M1-DT2,M1-AMS-EN(bit7)
//,C1-AR,C1-D1R,C1-D2R,C1-RR,C1-D1L,C1-TL,C1-KS,C1-MUL,C1-DT1,C1-DT2,C1-AMS-EN
//,M2-AR,M2-D1R,M2-D2R,M2-RR,M2-D1L,M2-TL,M2-KS,M2-MUL,M2-DT1,M2-DT2,M2-AMS-EN
//,C2-AR,C2-D1R,C2-D2R,C2-RR,C2-D1L,C2-TL,C2-KS,C2-MUL,C2-DT1,C2-DT2,C2-AMS-EN
// reserve,reserve,reserve,reserve,reserve,reserve,reserve,reserve
/*
ym2151_regset_write(cs, LFRQ, 0xFF, pgm_read_byte_near((int)(ym2151_parameter[inst] + 0))); // LFRQ
ym2151_regset_write(cs, PMD_AMD, LFO_MD_F | LFO_MD, 0x7F & pgm_read_byte_near((int)(ym2151_parameter[inst] + 1))); // AMD
ym2151_regset_write(cs, PMD_AMD, LFO_MD_F | LFO_MD, LFO_MD_F | pgm_read_byte_near((int)(ym2151_parameter[inst] + 2))); // PMD
ym2151_regset_write(cs, CT_W, LFO_W, pgm_read_byte_near((int)(ym2151_parameter[inst] + 3))); // WF
ym2151_regset_write(cs, NOISE, NFRQ, pgm_read_byte_near((int)(ym2151_parameter[inst] + 4))); // NFRQ
*/
ym2151_regset_write(cs, LR_FB_CON + ch, 0xFF, (pgm_read_byte_near((int)(ym2151_parameter[inst] + 5)) & RL) | ((pgm_read_byte_near((int)(ym2151_parameter[inst] + 6)) << 3) & FL) | (pgm_read_byte_near((int)(ym2151_parameter[inst] + 7)) & CONECT)); // PAN(bit7,bit6), FL, CON
// ym2151_regset_write(cs, LR_FB_CON + ch, FL, pgm_read_byte_near((int)(ym2151_parameter[inst] + 6)));//FL
// ym2151_regset_write(cs, LR_FB_CON + ch, CONECT, pgm_read_byte_near((int)(ym2151_parameter[inst] + 7)));//CON
ym2151_regset_write(cs, PMS_AMS + ch, 0xFF, (pgm_read_byte_near((int)(ym2151_parameter[inst] + 8)) & AMS) | ((pgm_read_byte_near((int)(ym2151_parameter[inst] + 9)) << 4) & PMS)); // AMS,PMS
// ym2151_regset_write(cs, PMS_AMS + ch, PMS, pgm_read_byte_near((int)(ym2151_parameter[inst] + 9)));//PMS
ym2151_slot_en[(cs << 3) | ch] = pgm_read_byte_near((int)(ym2151_parameter[inst] + 10)); // SLOT(bit6~bit3)
ym2151_regset_write(cs, NOISE, NE, pgm_read_byte_near((int)(ym2151_parameter[inst] + 11)) >> 7); // NE(bit7)
// M1
ym2151_regset_write(cs, KS_AR + ch, 0xFF, (pgm_read_byte_near((int)(ym2151_parameter[inst] + 12)) & AR) | (pgm_read_byte_near((int)(ym2151_parameter[inst] + 18)) << 6)); // M1-AR,KS
ym2151_regset_write(cs, AMS_EN_D1R + ch, 0xFF, (pgm_read_byte_near((int)(ym2151_parameter[inst] + 13)) & D1R) | (pgm_read_byte_near((int)(ym2151_parameter[inst] + 22)) & AMS_EN)); // M1-D1R,AMS-EN(bit7)
ym2151_regset_write(cs, DT2_D2R + ch, 0xFF, (pgm_read_byte_near((int)(ym2151_parameter[inst] + 14)) & D2R) | (pgm_read_byte_near((int)(ym2151_parameter[inst] + 21)) << 6)); // M1-D2R,DT2
ym2151_regset_write(cs, D1L_RR + ch, 0xFF, (pgm_read_byte_near((int)(ym2151_parameter[inst] + 15)) & RR) | (pgm_read_byte_near((int)(ym2151_parameter[inst] + 16)) << 4)); // M1-RR,D1L
// ym2151_regset_write(cs, D1L_RR + ch, D1L, pgm_read_byte_near((int)(ym2151_parameter[inst] + 16)));//M1-D1L
ym2151_regset_write(cs, TL + ch, TL_TL, pgm_read_byte_near((int)(ym2151_parameter[inst] + 17))); // M1-TL
// ym2151_regset_write(cs, KS_AR + ch, KS, pgm_read_byte_near((int)(ym2151_parameter[inst] + 18)));//M1-KS
ym2151_regset_write(cs, DT1_MUL + ch, 0xFF, (pgm_read_byte_near((int)(ym2151_parameter[inst] + 19)) & MUL) | (pgm_read_byte_near((int)(ym2151_parameter[inst] + 20)) << 4)); // M1-MUL,DT1
// ym2151_regset_write(cs, DT1_MUL + ch, DT1, pgm_read_byte_near((int)(ym2151_parameter[inst] + 20)));//M1-DT1
// ym2151_regset_write(cs, DT2_D2R + ch, DT2, pgm_read_byte_near((int)(ym2151_parameter[inst] + 21)));//M1-DT2
// ym2151_regset_write(cs, AMS_EN_D1R + ch, AMS_EN, pgm_read_byte_near((int)(ym2151_parameter[inst] + 22)));//M1-AMS-EN(bit7)
// C1
ym2151_regset_write(cs, KS_AR + ch + 16, 0xFF, (pgm_read_byte_near((int)(ym2151_parameter[inst] + 23)) & AR) | (pgm_read_byte_near((int)(ym2151_parameter[inst] + 29)) << 6)); // C1-AR,KS
ym2151_regset_write(cs, AMS_EN_D1R + ch + 16, 0xFF, (pgm_read_byte_near((int)(ym2151_parameter[inst] + 24)) & D1R) | (pgm_read_byte_near((int)(ym2151_parameter[inst] + 33)) & AMS_EN)); // C1-D1R,AMS-EN(bit7)
ym2151_regset_write(cs, DT2_D2R + ch + 16, 0xFF, (pgm_read_byte_near((int)(ym2151_parameter[inst] + 25)) & D2R) | (pgm_read_byte_near((int)(ym2151_parameter[inst] + 32)) << 6)); // C1-D2R,DT2
ym2151_regset_write(cs, D1L_RR + ch + 16, 0xFF, (pgm_read_byte_near((int)(ym2151_parameter[inst] + 26)) & RR) | (pgm_read_byte_near((int)(ym2151_parameter[inst] + 27)) << 4)); // C1-RR,D1L
// ym2151_regset_write(cs, D1L_RR + ch + 16, D1L, pgm_read_byte_near((int)(ym2151_parameter[inst] + 27)));//C1-D1L
ym2151_regset_write(cs, TL + ch + 16, TL_TL, pgm_read_byte_near((int)(ym2151_parameter[inst] + 28))); // C1-TL
// ym2151_regset_write(cs, KS_AR + ch + 16, KS, pgm_read_byte_near((int)(ym2151_parameter[inst] + 29)));//C1-KS
ym2151_regset_write(cs, DT1_MUL + ch + 16, 0xFF, (pgm_read_byte_near((int)(ym2151_parameter[inst] + 30)) & MUL) | (pgm_read_byte_near((int)(ym2151_parameter[inst] + 31)) << 4)); // C1-MUL,DT1
// ym2151_regset_write(cs, DT1_MUL + ch + 16, DT1, pgm_read_byte_near((int)(ym2151_parameter[inst] + 31)));//C1-DT1
// ym2151_regset_write(cs, DT2_D2R + ch + 16, DT2, pgm_read_byte_near((int)(ym2151_parameter[inst] + 32)));//C1-DT2
// ym2151_regset_write(cs, AMS_EN_D1R + ch + 16, AMS_EN, pgm_read_byte_near((int)(ym2151_parameter[inst] + 33)));//C1-AMS-EN(bit7)
// M2
ym2151_regset_write(cs, KS_AR + ch + 8, 0xFF, (pgm_read_byte_near((int)(ym2151_parameter[inst] + 34)) & AR) | (pgm_read_byte_near((int)(ym2151_parameter[inst] + 40)) << 6)); // M2-AR,KS
ym2151_regset_write(cs, AMS_EN_D1R + ch + 8, 0xFF, (pgm_read_byte_near((int)(ym2151_parameter[inst] + 35)) & D1R) | (pgm_read_byte_near((int)(ym2151_parameter[inst] + 44)) & AMS_EN)); // M2-D1R,AMS-EN(bit7)
ym2151_regset_write(cs, DT2_D2R + ch + 8, 0xFF, (pgm_read_byte_near((int)(ym2151_parameter[inst] + 36)) & D2R) | (pgm_read_byte_near((int)(ym2151_parameter[inst] + 43)) << 6)); // M2-D2R,DT2
ym2151_regset_write(cs, D1L_RR + ch + 8, 0xFF, (pgm_read_byte_near((int)(ym2151_parameter[inst] + 37)) & RR) | (pgm_read_byte_near((int)(ym2151_parameter[inst] + 38)) << 4)); // M2-RR,D1L
// ym2151_regset_write(cs, D1L_RR + ch + 8, D1L, pgm_read_byte_near((int)(ym2151_parameter[inst] + 38)));//M2-D1L
ym2151_regset_write(cs, TL + ch + 8, TL_TL, pgm_read_byte_near((int)(ym2151_parameter[inst] + 39))); // M2-TL
// ym2151_regset_write(cs, KS_AR + ch + 8, KS, pgm_read_byte_near((int)(ym2151_parameter[inst] + 40)));//M2-KS
ym2151_regset_write(cs, DT1_MUL + ch + 8, 0xFF, (pgm_read_byte_near((int)(ym2151_parameter[inst] + 41)) & MUL) | (pgm_read_byte_near((int)(ym2151_parameter[inst] + 42)) << 4)); // M2-MUL,DT1
// ym2151_regset_write(cs, DT1_MUL + ch + 8, DT1, pgm_read_byte_near((int)(ym2151_parameter[inst] + 42)));//M2-DT1
// ym2151_regset_write(cs, DT2_D2R + ch + 8, DT2, pgm_read_byte_near((int)(ym2151_parameter[inst] + 43)));//M2-DT2
// ym2151_regset_write(cs, AMS_EN_D1R + ch + 8, AMS_EN, pgm_read_byte_near((int)(ym2151_parameter[inst] + 44)));//M2-AMS-EN(bit7)
// C2
ym2151_regset_write(cs, KS_AR + ch + 24, 0xFF, (pgm_read_byte_near((int)(ym2151_parameter[inst] + 45)) & AR) | (pgm_read_byte_near((int)(ym2151_parameter[inst] + 51)) << 6)); // C2-AR,KS
ym2151_regset_write(cs, AMS_EN_D1R + ch + 24, 0xFF, (pgm_read_byte_near((int)(ym2151_parameter[inst] + 46)) & D1R) | (pgm_read_byte_near((int)(ym2151_parameter[inst] + 55)) & AMS_EN)); // C2-D1R,AMS-EN(bit7)
ym2151_regset_write(cs, DT2_D2R + ch + 24, 0xFF, (pgm_read_byte_near((int)(ym2151_parameter[inst] + 47)) & D2R) | (pgm_read_byte_near((int)(ym2151_parameter[inst] + 54)) << 6)); // C2-D2R,DT2
ym2151_regset_write(cs, D1L_RR + ch + 24, 0xFF, (pgm_read_byte_near((int)(ym2151_parameter[inst] + 48)) & RR) | (pgm_read_byte_near((int)(ym2151_parameter[inst] + 49)) << 4)); // C2-RR,D1L
// ym2151_regset_write(cs, D1L_RR + ch + 24, D1L, pgm_read_byte_near((int)(ym2151_parameter[inst] + 49)));//C2-D1L
ym2151_regset_write(cs, TL + ch + 24, TL_TL, pgm_read_byte_near((int)(ym2151_parameter[inst] + 50))); // C2-TL
// ym2151_regset_write(cs, KS_AR + ch + 24, KS, pgm_read_byte_near((int)(ym2151_parameter[inst] + 51)));//C2-KS
ym2151_regset_write(cs, DT1_MUL + ch + 24, 0xFF, (pgm_read_byte_near((int)(ym2151_parameter[inst] + 52)) & MUL) | (pgm_read_byte_near((int)(ym2151_parameter[inst] + 53)) << 4)); // C2-MUL,DT1
// ym2151_regset_write(cs, DT1_MUL + ch + 24, DT1, pgm_read_byte_near((int)(ym2151_parameter[inst] + 53)));//C2-DT1
// ym2151_regset_write(cs, DT2_D2R + ch + 24, DT2, pgm_read_byte_near((int)(ym2151_parameter[inst] + 54)));//C2-DT2
// ym2151_regset_write(cs, AMS_EN_D1R + ch + 24, AMS_EN, pgm_read_byte_near((int)(ym2151_parameter[inst] + 55)));//C2-AMS-EN(bit7)
}
// 音程のセット
void ptc_set(unsigned char ch, unsigned int notenum)
{
unsigned char cs_temp = ch >> 3;
unsigned char ch_temp = ch & 0x07;
if (ch != FM_DRUM_CH)
{ // ドラムチャンネル以外
ym2151_data[cs_temp].reg.kc[ch_temp] = pgm_read_byte_near((int)(ym2151_note_conv + notenum + def_tone[ch] - 25));
ym2151_write(cs_temp, KC + ch_temp, pgm_read_byte_near((int)(ym2151_note_conv + notenum + def_tone[ch] - 25)));
}
else
{
// ドラムチャンネル
// VCEDパラメータのセット(処理が重いため、テンポが速い曲は注意)
ym2151_vced_set(FM_DRUM_CH, (unsigned int)(((unsigned int)DRUM_VCED << 7) | (unsigned int)notenum));
ym2151_write(cs_temp, KC + ch_temp, pgm_read_byte_near((int)(ym2151_note_conv + 64 + def_tone[ch] - 25)));
}
}
// メインの音量とパンのセット
void main_vel_pan_set(unsigned char vel, unsigned char pan)
{
// 何もしません。
}
// チャンネルの音量とパンのセット
void vel_pan_set(unsigned char ch, unsigned char vel, unsigned char pan)
{
// YM2151はチャンネル音量設定ができないためTL値の変更で代用(低音量で音色が変わるので注意)
// アルゴリズムによって音量制御レジスタ(TL)の個数が変わる
unsigned char conect_temp = 0; // アルゴリズムの種類一時保存
unsigned char cs_temp = ch >> 3;
unsigned char ch_temp = ch & 0x07;
ym2151_main_vol[ch] = vel;
conect_temp = ym2151_data[cs_temp].reg.lr_fb_conf[ch_temp] & 0x07;
if (ch == 7)
{
//(ym2151_data[cs_temp].reg.tl[ch_temp + (C2 * 8)] + pgm_read_byte_near(ym2151_tl_vol_conv + vel)
}
if ((conect_temp & 0x04) == 0)
{
if (((unsigned int)ym2151_data[cs_temp].reg.tl[ch_temp + (C2 * 8)] + pgm_read_byte_near(ym2151_tl_vol_conv + vel)) > 127)
{
ym2151_write(cs_temp, TL + ch_temp + (C2 * 8), TL_TL & (127));
}
else
{
//-/ym2151_write(cs_temp, TL + ch_temp + (C2*8), TL_TL & (ym2151_data[cs_temp].reg.tl[ch_temp + (C2 * 8)] + ((127 - vel)>>1)));
ym2151_write(cs_temp, TL + ch_temp + (C2 * 8), TL_TL & (ym2151_data[cs_temp].reg.tl[ch_temp + (C2 * 8)] + pgm_read_byte_near(ym2151_tl_vol_conv + vel)));
}
ym2151_write(cs_temp, TL + ch_temp + (M1 * 8), ym2151_data[cs_temp].reg.tl[ch_temp + (M1 * 8)]);
ym2151_write(cs_temp, TL + ch_temp + (M2 * 8), ym2151_data[cs_temp].reg.tl[ch_temp + (M2 * 8)]);
ym2151_write(cs_temp, TL + ch_temp + (C1 * 8), ym2151_data[cs_temp].reg.tl[ch_temp + (C1 * 8)]);
}
else if (conect_temp == 4)
{
if (((unsigned int)ym2151_data[cs_temp].reg.tl[ch_temp + (C1 * 8)] + pgm_read_byte_near(ym2151_tl_vol_conv + vel)) > 127)
{
ym2151_write(cs_temp, TL + ch_temp + (C1 * 8), TL_TL & (127));
}
else
{
ym2151_write(cs_temp, TL + ch_temp + (C1 * 8), TL_TL & (ym2151_data[cs_temp].reg.tl[ch_temp + (C1 * 8)] + pgm_read_byte_near(ym2151_tl_vol_conv + vel)));
}
if (((unsigned int)ym2151_data[cs_temp].reg.tl[ch_temp + (C2 * 8)] + pgm_read_byte_near(ym2151_tl_vol_conv + vel)) > 127)
{
ym2151_write(cs_temp, TL + ch_temp + (C2 * 8), TL_TL & (127));
}
else
{
ym2151_write(cs_temp, TL + ch_temp + (C2 * 8), TL_TL & (ym2151_data[cs_temp].reg.tl[ch_temp + (C2 * 8)] + pgm_read_byte_near(ym2151_tl_vol_conv + vel)));
}
ym2151_write(cs_temp, TL + ch_temp + (M1 * 8), ym2151_data[cs_temp].reg.tl[ch_temp + (M1 * 8)]);
ym2151_write(cs_temp, TL + ch_temp + (M2 * 8), ym2151_data[cs_temp].reg.tl[ch_temp + (M2 * 8)]);
}
else if (conect_temp == 7)
{
if (((unsigned int)ym2151_data[cs_temp].reg.tl[ch_temp + (M1 * 8)] + pgm_read_byte_near(ym2151_tl_vol_conv + vel)) > 127)
{
ym2151_write(cs_temp, TL + ch_temp + (M1 * 8), TL_TL & (127));
}
else
{
ym2151_write(cs_temp, TL + ch_temp + (M1 * 8), TL_TL & (ym2151_data[cs_temp].reg.tl[ch_temp + (M1 * 8)] + pgm_read_byte_near(ym2151_tl_vol_conv + vel)));
}
if (((unsigned int)ym2151_data[cs_temp].reg.tl[ch_temp + (M2 * 8)] + pgm_read_byte_near(ym2151_tl_vol_conv + vel)) > 127)
{
ym2151_write(cs_temp, TL + ch_temp + (M2 * 8), TL_TL & (127));
}
else
{
ym2151_write(cs_temp, TL + ch_temp + (M2 * 8), TL_TL & (ym2151_data[cs_temp].reg.tl[ch_temp + (M2 * 8)] + pgm_read_byte_near(ym2151_tl_vol_conv + vel)));
}
if (((unsigned int)ym2151_data[cs_temp].reg.tl[ch_temp + (C1 * 8)] + pgm_read_byte_near(ym2151_tl_vol_conv + vel)) > 127)
{
ym2151_write(cs_temp, TL + ch_temp + (C1 * 8), TL_TL & (127));
}
else
{
ym2151_write(cs_temp, TL + ch_temp + (C1 * 8), TL_TL & (ym2151_data[cs_temp].reg.tl[ch_temp + (C1 * 8)] + pgm_read_byte_near(ym2151_tl_vol_conv + vel)));
}
if (((unsigned int)ym2151_data[cs_temp].reg.tl[ch_temp + (C2 * 8)] + pgm_read_byte_near(ym2151_tl_vol_conv + vel)) > 127)
{
ym2151_write(cs_temp, TL + ch_temp + (C2 * 8), TL_TL & (127));
}
else
{
ym2151_write(cs_temp, TL + ch_temp + (C2 * 8), TL_TL & (ym2151_data[cs_temp].reg.tl[ch_temp + (C2 * 8)] + pgm_read_byte_near(ym2151_tl_vol_conv + vel)));
}
}
else
{
if (((unsigned int)ym2151_data[cs_temp].reg.tl[ch_temp + (M2 * 8)] + pgm_read_byte_near(ym2151_tl_vol_conv + vel)) > 127)
{
ym2151_write(cs_temp, TL + ch_temp + (M2 * 8), TL_TL & (127));
}
else
{
ym2151_write(cs_temp, TL + ch_temp + (M2 * 8), TL_TL & (ym2151_data[cs_temp].reg.tl[ch_temp + (M2 * 8)] + pgm_read_byte_near(ym2151_tl_vol_conv + vel)));
}
if (((unsigned int)ym2151_data[cs_temp].reg.tl[ch_temp + (C1 * 8)] + pgm_read_byte_near(ym2151_tl_vol_conv + vel)) > 127)
{
ym2151_write(cs_temp, TL + ch_temp + (C1 * 8), TL_TL & (127));
}
else
{
ym2151_write(cs_temp, TL + ch_temp + (C1 * 8), TL_TL & (ym2151_data[cs_temp].reg.tl[ch_temp + (C1 * 8)] + pgm_read_byte_near(ym2151_tl_vol_conv + vel)));
}
if (((unsigned int)ym2151_data[cs_temp].reg.tl[ch_temp + (C2 * 8)] + pgm_read_byte_near(ym2151_tl_vol_conv + vel)) > 127)
{
ym2151_write(cs_temp, TL + ch_temp + (C2 * 8), TL_TL & (127));
}
else
{
ym2151_write(cs_temp, TL + ch_temp + (C2 * 8), TL_TL & (ym2151_data[cs_temp].reg.tl[ch_temp + (C2 * 8)] + pgm_read_byte_near(ym2151_tl_vol_conv + vel)));
}
ym2151_write(cs_temp, TL + ch_temp + (M1 * 8), ym2151_data[cs_temp].reg.tl[ch_temp + (M1 * 8)]);
}
// パン
if(test[cs_temp] == TEST_OPP_OPZ)
{
// パンが5以下か122以上のとき左右の出力のオンオフを行う
if (pan <= 5)
{
ym2151_regset_write(cs_temp, 0x15, 0xFF, 0x01);//YM2414 OPZ用
ym2151_regset_write(cs_temp, 0x30+ch_temp, 0x01, 0x00);//YM2414 OPZ用
ym2151_regset_write(cs_temp, 0x15, 0xFF, 0x00);//YM2414 OPZ用
ym2151_regset_write(cs_temp, LR_FB_CON + ch_temp, RL, 0x01);
}
else if (pan >= 122)
{
ym2151_regset_write(cs_temp, 0x15, 0xFF, 0x01);//YM2414 OPZ用
ym2151_regset_write(cs_temp, 0x30+ch_temp, 0x01, 0x00);//YM2414 OPZ用
ym2151_regset_write(cs_temp, 0x15, 0xFF, 0x00);//YM2414 OPZ用
ym2151_regset_write(cs_temp, LR_FB_CON + ch_temp, RL, 0x02);
}
else
{
ym2151_regset_write(cs_temp, 0x15, 0xFF, 0x01);//YM2414 OPZ用
ym2151_regset_write(cs_temp, 0x30+ch_temp, 0x01, 0x01);//YM2414 OPZ用
ym2151_regset_write(cs_temp, 0x15, 0xFF, 0x00);//YM2414 OPZ用
ym2151_regset_write(cs_temp, LR_FB_CON + ch_temp, RL, 0x03);
}
}
else
{
// パンが5以下か122以上のとき左右の出力のオンオフを行う
if (pan <= 5)
{
ym2151_regset_write(cs_temp, LR_FB_CON + ch_temp, RL, 0x01);
}
else if (pan >= 122)
{
ym2151_regset_write(cs_temp, LR_FB_CON + ch_temp, RL, 0x02);
}
else
{
ym2151_regset_write(cs_temp, LR_FB_CON + ch_temp, RL, 0x03);
}
}
}
// チャンネルノートオン
void note_on(unsigned char ch)
{
unsigned char cs_temp = ch >> 3;
// LFOのリセット
if (ym2151_lfo_rst_en[ch] != 0)
{
// LFOをリセットするチャンネルの場合リセット
ym2151_write(cs_temp, test[cs_temp], LFO_RESET);
ym2151_write(cs_temp, test[cs_temp], 0);
}
if (ch != FM_DRUM_CH)
{
// ドラムチャンネル以外
ym2151_data[cs_temp].reg.kon = (ym2151_slot_en[ch] & SN) | (ch & CH_REG);
ym2151_write(cs_temp, KON, ym2151_data[cs_temp].reg.kon);
}
else
{
// ドラムチャンネル
ym2151_data[cs_temp].reg.kon = (ym2151_slot_en[ch] & SN) | (ch & CH_REG);
ym2151_write(cs_temp, KON, ym2151_data[cs_temp].reg.kon);
}
}
// チャンネルノートオフ
void note_off(unsigned char ch)
{
unsigned char cs_temp = ch >> 3;
if (ch != FM_DRUM_CH)
{ // ドラムチャンネル以外
ym2151_data[cs_temp].reg.kon = ch & CH_REG;
ym2151_write(cs_temp, KON, ym2151_data[cs_temp].reg.kon);
}
else
{
// ドラムチャンネル
ym2151_data[cs_temp].reg.kon = ch & CH_REG;
ym2151_write(cs_temp, KON, ym2151_data[cs_temp].reg.kon);
}
}
// 音色セット
void inst_set(unsigned char ch, unsigned char inst)
{
ym2151_param_set_all(ch >> 3, ch & 0x07, inst);
}
// MIDI受信用関数/////////////////////////////
// 1バイトずつmidi_readを実行し、1グループのmidiメッセージを受信し終えるとmidi_comを実行
void midi_read(char read_buf)
{
if (ex_mess_en == 1)
{
if ((unsigned char)read_buf == 0xF7)
{ // エクスクルーシブ・メッセージ終了
ex_mess_en = 0;
stop_byte = dat_ph;
}
}
else if (((read_buf >> 7) & 0x01) == 1)
{
// データ始まり検出したら
dat_ph = 0;
ex_mess_en = 0;
read_buf_h = 0xF0 & read_buf;
if (((0x80 <= (unsigned char)read_buf_h) && (0xB0 >= (unsigned char)read_buf_h)) || ((unsigned char)read_buf_h == 0xE0))
{
// 3バイト読み取り
running_ch = read_buf; // ランニングステータスチャンネルセット
stop_byte = 2;
}
else if (((unsigned char)read_buf_h == 0xC0) || ((unsigned char)read_buf_h == 0xD0))
{
// 2バイト読み取り
running_ch = read_buf;
stop_byte = 1;
}
else
{
switch ((unsigned char)read_buf)
{
case 0xF0: // エクスクルーシブ・メッセージ
ex_mess_en = 1;
stop_byte = 254;
// Serial.print("ex_mess_en\r\n");//デバッグ用*/
break;
case 0xF1: // MIDIタイムコード
case 0xF3: // ソング・セレクト
stop_byte = 1;
break;
case 0xF2: // ソング・ポジション・ポインター
stop_byte = 2;
break;
case 0xF6: // チューン・リクエスト
case 0xF7: // エンド・オブ・エクスクルーシブ
case 0xF8: // タイミング・クロック(MIDIクロック)
case 0xFA: // スタート
case 0xFB: // コンティニュー
case 0xFC: // ストップ
case 0xFF: // システム・リセット
stop_byte = 0;
break;
case 0xFE: // アクティブ・センシングc
stop_byte = 0;
break;
}
}
}
else if (dat_ph == 0)
{
// ランニングステータス//////
stop_byte = 2;
midi_buf[0] = running_ch;
dat_ph++;
//////////////////////////
}
midi_buf[dat_ph] = read_buf; // 受信データ格納
if (dat_ph >= stop_byte)
{
// 指定バイト数受信完了
stop_byte = 3;
ex_mess_en = 0;
if ((midi_buf[0] == 0xFE) && (dat_ph == 0))
{
dat_ph = 0; // アクティブセンシングは処理しない
}
else
{
midi_com(midi_buf);
}
dat_ph = 0;
midi_buf[0] = 0;
return;
}
if ((((midi_buf[0] >> 7) & 0x01) == 1) || (ex_mess_en == 1))
{
// 1バイト目がメッセージ以外読み取りしない
dat_ph++;
}
}
// MIDIデータ入力処理
inline void midi_com(unsigned char *in_midi_mess)
{
unsigned char in_midi_data_buf_h0 = in_midi_mess[0] >> 4; // 上位4ビットのみを右へ4ビットシフト
unsigned char in_midi_data_buf_l0 = in_midi_mess[0] & 0x0f; // 下位4ビットのみ チャンネル
unsigned char in_midi_data_buf_1 = in_midi_mess[1];
unsigned char in_midi_data_buf_2 = in_midi_mess[2];
unsigned char cs_temp;
unsigned char ch_temp;
// 80
if (in_midi_data_buf_h0 == 0x08)
{
// ノートオフ
if (in_midi_data_buf_l0 < MIDI_MAX_TR)
{
note_off(ym2151_tr[in_midi_data_buf_l0]);
}
}
// 90
else if (in_midi_data_buf_h0 == 0x09)
{
if (in_midi_mess[2] == 0)
{
// ノートオフ
if (in_midi_data_buf_l0 < MIDI_MAX_TR)
{
note_off(ym2151_tr[in_midi_data_buf_l0]);
}
}
else
{
midi_vel[ym2151_tr[in_midi_data_buf_l0]] = in_midi_data_buf_2; // ベロシティ保存
// ノートオン
if (in_midi_data_buf_l0 < MIDI_MAX_TR)
{
ptc_set(ym2151_tr[in_midi_data_buf_l0], in_midi_mess[1] + def_key); // チャンネル, 音程
vel_pan_set(ym2151_tr[in_midi_data_buf_l0], ((int)((int)midi_vel[ym2151_tr[in_midi_data_buf_l0]] * (int)midi_main_vel[ym2151_tr[in_midi_data_buf_l0]]) >> 7), midi_pan[ym2151_tr[in_midi_data_buf_l0]]); // チャンネル, 音量, パン
note_on(ym2151_tr[in_midi_data_buf_l0]); // ノートオン
}
}
}
else if (in_midi_data_buf_h0 == 0x0A)
{
// ポリフォニックキープレッシャー
// 何もしない
}
else if (in_midi_data_buf_h0 == 0x0B)
{
// コントロールチェンジ
switch (in_midi_mess[1])
{
case 0x07: // チャンネルボリューム
midi_main_vel[ym2151_tr[in_midi_data_buf_l0]] = in_midi_mess[2];
break;
case 0x0A: // パン
midi_pan[ym2151_tr[in_midi_data_buf_l0]] = in_midi_mess[2];
break;
case 0x78:
case 0x79:
for (int i = 0; i < MIDI_MAX_TR; i++)
{
note_off(i);
}
break;
case 0x40: // サスティン
if (in_midi_mess[2] == 0x7F)
{
sas_en = 1;
}
else
{
sas_en = 0;
}
break;
default:
break;
}
}
else if (in_midi_data_buf_h0 == 0x0C)
{
// プログラムチェンジ
midiprog[in_midi_data_buf_l0] = in_midi_mess[1];
ym2151_vced_set(ym2151_tr[in_midi_data_buf_l0], fond_vced(midiprog[in_midi_data_buf_l0])); // 指定チャンネルにvcedパラメータを反映
}
else if (in_midi_data_buf_h0 == 0x0E)
{
// ピッチベンド
// 何もしない
}
else if (in_midi_data_buf_h0 == 0x0F)
{
// システムメッセージ
if (in_midi_mess[0] == 0xFE)
{
// アクティブセンシング
}
if (in_midi_mess[0] == 0xF0)
{
// エクスクルーシブ・メッセージ
if ((in_midi_mess[1] == 0x43)) // YAMAHA
{
// FM音源パラメータ変更(DX-27やTX81Zとの互換性はありません。)
// DX-27 EXM
// sub-st/ch param group sw data
// F0, 43, (0001nnnn), (00001000), (0mmmmmmm), (0ddddddd), F7
//[0],[1],[2], [3], [4], [5], [6]
// TX81Z EXM
// sub-st/ch param group param no. data
// F0, 43, (0001nnnn), (00010010), (0mmmmmmm), (0ddddddd), F7
//[0],[1],[2], [3], [4], [5], [6]
cs_temp = (ym2151_tr[in_midi_mess[2] & 0x0F]) >> 3;
ch_temp = ym2151_tr[in_midi_mess[2] & 0x0F] & 0x07;
unsigned char op_temp = OP4; // オペレータ番号による先頭位置計算用
// VCEDフォーマット(DX-27やTX81Zのサービスマニュアルを参照、ただしパラメータの互換性が無いものもあり)
// TX81Zのオペレータ番号とYM2151のオペレータ番号は違うので注意!(YM2414のOP4~OP1 → YM2151のOP1~OP4)
// Serial.print("YAMAHA\r\n");
// Program Change parameter Change(VCEDで受信したパラメータ群と発音チャンネルを結びつけます)
// basicRcvch,param group, ,PGMchangeNo, data(high), data(low),
// F0, 43, (0001nnnn), (00010000), 7F, (0kkkkkkk), (0hhhhhhh), (0lllllll), F7
//[0],[1],[2] , [3] ,[4], [5], [6], [7], [8]
if (((in_midi_mess[2] & 0x10) == 0x10) && (in_midi_mess[3] == 0x10) && (in_midi_mess[4] == 0x7F))
{
// Serial.print("PCPC\r\n");
int f_c = 0; // 検索用カウンタ
// プログラムチェンジ、VCED、内部パラメータナンバー(TX81Z互換)、SRAM保存用の4つを結びつける
// プログラムチェンジを受信した時、プログラムチェンジ値より内部パラメータナンバーをさがし、内部パラメータナンバーからSRAM保存用に変換して現在登録されているVCEDを該当chに反映させる。
// VCEDを受信した時、chより内部パラメータナンバーをさがし、内部パラメータナンバーをSRAM保存用に変換してVCEDを更新する
// PCPCで受信したチャンネルは未使用
for (f_c = 0; f_c < PC_N; f_c++)
{
// もし、受信したPCPCに登録済みプログラムチェンジナンバーがある場合、
// 紐付け更新
if (pc_nc[f_c] == in_midi_mess[5])
{
vced_nc[f_c] = ((unsigned int)in_midi_mess[6] << 7) | ((unsigned int)in_midi_mess[7]);
vced_num_set(vced_nc[f_c]);
continue;
}
}
if (f_c >= PC_N)
{
// 受信したPCPCに登録済みプログラムチェンジナンバーが無い場合、
// 新しくプログラムチェンジナンバーとVCEDナンバーを紐付け
if (vced_pc_c >= PC_N)
{
vced_pc_c = 0;
}
vced_nc[vced_pc_c] = ((unsigned int)in_midi_mess[6] << 7) | ((unsigned int)in_midi_mess[7]);
vced_num_set(vced_nc[vced_pc_c]);
pc_nc[vced_pc_c] = in_midi_mess[5];
vced_pc_c++;
}
// 紐付け完了後、すべてのチャンネルの現在のプログラムチェンジナンバーより、該当チャンネルのVCEDを更新
//
for (f_c = 0; f_c < 16; f_c++)
{
if (midiprog[f_c] == in_midi_mess[5])
{
ym2151_vced_set(ym2151_tr[f_c], fond_vced(midiprog[f_c])); // 指定チャンネルにvcedパラメータを反映
}
}
}
//VCED parameter Change
// sub-st/ch param group param no. data
// F0, 43, (0001nnnn), (00010010), (0mmmmmmm), (0ddddddd), F7
//[0],[1], [2], [3], [4], [5], [6]
// VCED1つ変更
else if (((in_midi_mess[2] & 0x10) == 0x10) && ((in_midi_mess[3] == 0x08) || (in_midi_mess[3] == 0x12)))
{
// 受信したチャンネルのプログラムチェンジより、VCEDナンバーを見つけてパラメータを変更する
unsigned char vced_itn = vced_itn_get(fond_vced(midiprog[in_midi_mess[2] & 0x0F]));
vced_ram[vced_itn][in_midi_mess[4]] = in_midi_mess[5];
ym2151_vced_t_set(ym2151_tr[in_midi_mess[2] & 0x0F], fond_vced(midiprog[in_midi_mess[2] & 0x0F]), in_midi_mess[4]);
}
// VCED一括変更(Arduinoの場合、UART受信バッファのサイズを変更しないと動作しない可能性があります。UART送信等出来なくなります。)
//不具合修正前
// sub-st/ch prm group ,size, data [0] , ... ,data [92] ,sum(未チェック)
// F0, 43, (0000nnnn), (00000000), 5D, (0ddddddd), ... ,(0ddddddd),(0sssssss), F7
//[0],[1], [2], [3], [4], [5], , ... , [98] ,[99] , [100]
// パラメータ数は93(0x5D)バイト、メッセージバイト数(F0~F7)までは101バイト
// ただし以下のコードでは、68バイト目以降は未使用なのでパラメータ数は63(0x3F)バイトでも良い
//不具合修正後
// sub-st/ch, , prm group ,size, data [0] , ... ,data [92] ,sum(未チェック)
// F0, 43, (0000nnnn), (00000011), (00000000), 5D, (0ddddddd), ... ,(0ddddddd),(0sssssss), F7
//[0],[1], [2] , [3] , [5] ,[5], [6] , ... , [98] ,[99] , [100]
// パラメータ数は93(0x5D)バイト、メッセージバイト数(F0~F7)までは101バイト
//
else if (((in_midi_mess[2] & 0x10) == 0x00) && ((in_midi_mess[3] == 0x03) && (in_midi_mess[4] == 0x00) && (in_midi_mess[5] >= 0x3F) && (in_midi_mess[5] <= 0x5D)))
{
// 受信したチャンネルのプログラムチェンジより、VCEDナンバーを見つけてパラメータを変更する
unsigned char vced_itn = vced_itn_get(fond_vced(midiprog[in_midi_mess[2] & 0x0F]));
for (int f_c = 0; f_c < 63; f_c++)
{
//vced_ram[vced_itn][f_c] = in_midi_mess[f_c + 5];//不具合修正
vced_ram[vced_itn][f_c] = in_midi_mess[f_c + 6];
}
ym2151_vced_set(ym2151_tr[in_midi_mess[2] & 0x0F], fond_vced(midiprog[in_midi_mess[2] & 0x0F])); // 指定チャンネルにvcedパラメータを反映
}
}
else if (in_midi_mess[1] == 0x7E && in_midi_mess[2] == 0x7F)
{
// ユニバーサル
if (in_midi_mess[3] == 0x09)
{
// GM
if (in_midi_mess[4] == 0x01)
{
// GMシステム・オン
for (int i = 0; i < MIDI_MAX_TR; i++)
{
note_off(i);
}
}
if (in_midi_mess[4] == 0x02)
{
// GMシステム・オフ
for (int i = 0; i < MIDI_MAX_TR; i++)
{
note_off(i);
}
}
}
}
}
}
}
// 14bit値VCEDナンバーとvcedパラメータ保存番号と紐付け
void vced_num_set(unsigned int vced_n)
{
for (int f_c = 0; f_c < VCED_N; f_c++)
{
// もし、紐付け済み14bit値VCEDナンバーがある場合、
// 何もしない
if (vced_tr[f_c] == vced_n)
{
return;
}
}
// 無い場合、新しく紐付け(登録数上限に達したら削除し登録)
if (vced_tr_c >= VCED_N)
{
vced_tr_c = 0;
}
vced_tr[vced_tr_c] = vced_n;
vced_tr_c++;
}
// 14bit値VCEDナンバーからvcedパラメータ保存番号を見つけて返す
unsigned char vced_itn_get(unsigned int vced_n)
{
unsigned char f_c = 0;
unsigned char ret_vced_itn = 0;
for (f_c = 0; f_c < VCED_N; f_c++)
{
// もし、紐付け済み14bit値VCEDナンバーがある場合、
// vcedパラメータ保存番号を返す
if (vced_tr[f_c] == vced_n)
{
ret_vced_itn = f_c;
continue;
}
}
return ret_vced_itn;
}
// 指定チャンネルにvcedパラメータを反映
void ym2151_vced_set(unsigned char ch, unsigned int vced_n)
{
unsigned char cs_temp = ch >> 3;
unsigned char ch_temp = ch & 0x07;
ym2151_regset_write(cs_temp, D1L_RR + ch_temp + OP4_A, RR, 0x0F);//リリース時間を最小にする
ym2151_regset_write(cs_temp, D1L_RR + ch_temp + OP3_A, RR, 0x0F);
ym2151_regset_write(cs_temp, D1L_RR + ch_temp + OP2_A, RR, 0x0F);
ym2151_regset_write(cs_temp, D1L_RR + ch_temp + OP1_A, RR, 0x0F);
// vced_nは14bit値
unsigned char vced_itr = vced_itn_get(vced_n); // 14bit値VCEDナンバーからvcedパラメータ保存番号を見つける
vel_pan_set(ch, 0, 64);
note_off(ch);
ym2151_slot_en[ch] = 0x78; // SLOT(bit6~bit3)
// OP1
// 0:AR(0-31)
ym2151_regset_write(cs_temp, KS_AR + ch_temp + OP1_A, AR, vced_ram[vced_itr][0]);
// 1:D1R(0-31)
ym2151_regset_write(cs_temp, AMS_EN_D1R + ch_temp + OP1_A, D1R, vced_ram[vced_itr][1]);
// 2:D2R(0-31)
ym2151_regset_write(cs_temp, DT2_D2R + ch_temp + OP1_A, D2R, vced_ram[vced_itr][2]);
// 3:RR(0-15:DX27)(1-15:TX81Z)
ym2151_regset_write(cs_temp, D1L_RR + ch_temp + OP1_A, RR, vced_ram[vced_itr][3]);
// 4:D1L(0-15)
ym2151_regset_write(cs_temp, D1L_RR + ch_temp + OP1_A, D1L, vced_ram[vced_itr][4]);
// 5:LS(0-99)
// VCEDフォーマット非従順、値を無視
// 6:RS(0-3)
ym2151_regset_write(cs_temp, KS_AR + ch_temp + OP1_A, KS, 0x03 & vced_ram[vced_itr][9]);
// 7:EBS(0-7)
// VCEDフォーマット非従順、値を無視
// 8:AME(0-1)
ym2151_regset_write(cs_temp, AMS_EN_D1R + ch_temp + OP1_A, AMS_EN, vced_ram[vced_itr][8]);
// 9:KVS(0-7)
// VCEDフォーマット非従順、値を無視
// 10:OUT(0-99)
// VCEDフォーマット非従順、本来は0~99を0~127にスケーリングしなければいけない。
ym2151_regset_write(cs_temp, TL + ch_temp + OP1_A, TL_TL, vced_ram[vced_itr][10]);
// 11:F(0-63)
// MUL(4bit)とDT2(2bit) (予想)
ym2151_regset_write(cs_temp, DT1_MUL + ch_temp + OP1_A, MUL, vced_ram[vced_itr][11] >> 2);
ym2151_regset_write(cs_temp, DT2_D2R + ch_temp + OP1_A, DT2, vced_ram[vced_itr][11]);
// 12:DET(0-6)
// VCEDフォーマット非従順、本来はcenter=3だが、DT1=0~7として入力
ym2151_regset_write(cs_temp, DT1_MUL + ch_temp + OP1_A, DT1, vced_ram[vced_itr][12]);
// OP2
// 13:AR(0-31)
ym2151_regset_write(cs_temp, KS_AR + ch_temp + OP2_A, AR, vced_ram[vced_itr][13]);
// 14:D1R(0-31)
ym2151_regset_write(cs_temp, AMS_EN_D1R + ch_temp + OP2_A, D1R, vced_ram[vced_itr][14]);
// 15:D2R(0-31)
ym2151_regset_write(cs_temp, DT2_D2R + ch_temp + OP2_A, D2R, vced_ram[vced_itr][15]);
// 16:RR(0-15:DX27)(1-15:TX81Z)
ym2151_regset_write(cs_temp, D1L_RR + ch_temp + OP2_A, RR, vced_ram[vced_itr][16]);
// 17:D1L(0-15)
ym2151_regset_write(cs_temp, D1L_RR + ch_temp + OP2_A, D1L, vced_ram[vced_itr][17]);
// 18:LS(0-99)
// VCEDフォーマット非従順、値を無視
// 19:RS(0-3)
ym2151_regset_write(cs_temp, KS_AR + ch_temp + OP2_A, KS, 0x03 & vced_ram[vced_itr][19]);
// 20:EBS(0-7)
// VCEDフォーマット非従順、値を無視
// 21:AME(0-1)
ym2151_regset_write(cs_temp, AMS_EN_D1R + ch_temp + OP2_A, AMS_EN, vced_ram[vced_itr][21]);
// 22:KVS(0-7)
// VCEDフォーマット非従順、値を無視
// 23:OUT(0-99)
// VCEDフォーマット非従順、本来は0~99を0~127にスケーリングしなければいけない。
ym2151_regset_write(cs_temp, TL + ch_temp + OP2_A, TL_TL, vced_ram[vced_itr][23]);
// 24:F(0-63)
// MUL(4bit)とDT2(2bit) (予想)
ym2151_regset_write(cs_temp, DT1_MUL + ch_temp + OP2_A, MUL, vced_ram[vced_itr][24] >> 2);
ym2151_regset_write(cs_temp, DT2_D2R + ch_temp + OP2_A, DT2, vced_ram[vced_itr][24]);
// 25:DET(0-6)
// VCEDフォーマット非従順、本来はcenter=3だが、DT1=0~7として入力
ym2151_regset_write(cs_temp, DT1_MUL + ch_temp + OP2_A, DT1, vced_ram[vced_itr][25]);
// OP3
// 26:AR(0-31)
ym2151_regset_write(cs_temp, KS_AR + ch_temp + OP3_A, AR, vced_ram[vced_itr][26]);
// 27:D1R(0-31)
ym2151_regset_write(cs_temp, AMS_EN_D1R + ch_temp + OP3_A, D1R, vced_ram[vced_itr][27]);
// 28:D2R(0-31)
ym2151_regset_write(cs_temp, DT2_D2R + ch_temp + OP3_A, D2R, vced_ram[vced_itr][28]);
// 29:RR(0-15:DX27)(1-15:TX81Z)
ym2151_regset_write(cs_temp, D1L_RR + ch_temp + OP3_A, RR, vced_ram[vced_itr][29]);
// 30:D1L(0-15)
ym2151_regset_write(cs_temp, D1L_RR + ch_temp + OP3_A, D1L, vced_ram[vced_itr][30]);
// 31:LS(0-99)
// VCEDフォーマット非従順、値を無視
// 32:RS(0-3)
ym2151_regset_write(cs_temp, KS_AR + ch_temp + OP3_A, KS, 0x03 & vced_ram[vced_itr][32]);
// 33:EBS(0-7)
// VCEDフォーマット非従順、値を無視
// 34:AME(0-1)
ym2151_regset_write(cs_temp, AMS_EN_D1R + ch_temp + OP3_A, AMS_EN, vced_ram[vced_itr][34]);
// 35:KVS(0-7)
// VCEDフォーマット非従順、値を無視
// 36:OUT(0-99)
// VCEDフォーマット非従順、本来は0~99を0~127にスケーリングしなければいけない。
ym2151_regset_write(cs_temp, TL + ch_temp + OP3_A, TL_TL, vced_ram[vced_itr][36]);
// 37:F(0-63)
// MUL(4bit)とDT2(2bit) (予想)
ym2151_regset_write(cs_temp, DT1_MUL + ch_temp + OP3_A, MUL, vced_ram[vced_itr][37] >> 2);
ym2151_regset_write(cs_temp, DT2_D2R + ch_temp + OP3_A, DT2, vced_ram[vced_itr][37]);
// 38:DET(0-6)
// VCEDフォーマット非従順、本来はcenter=3だが、DT1=0~7として入力
ym2151_regset_write(cs_temp, DT1_MUL + ch_temp + OP3_A, DT1, vced_ram[vced_itr][38]);
// OP4
// 39:AR(0-31)
ym2151_regset_write(cs_temp, KS_AR + ch_temp + OP4_A, AR, vced_ram[vced_itr][39]);
// 40:D1R(0-31)
ym2151_regset_write(cs_temp, AMS_EN_D1R + ch_temp + OP4_A, D1R, vced_ram[vced_itr][40]);
// 41:D2R(0-31)
ym2151_regset_write(cs_temp, DT2_D2R + ch_temp + OP4_A, D2R, vced_ram[vced_itr][41]);
// 42:RR(0-15:DX27)(1-15:TX81Z)
ym2151_regset_write(cs_temp, D1L_RR + ch_temp + OP4_A, RR, vced_ram[vced_itr][42]);
// 43:D1L(0-15)
ym2151_regset_write(cs_temp, D1L_RR + ch_temp + OP4_A, D1L, vced_ram[vced_itr][43]);
// 44:LS(0-99)
// VCEDフォーマット非従順、値を無視
// 45:RS(0-3)
ym2151_regset_write(cs_temp, KS_AR + ch_temp + OP4_A, KS, 0x03 & vced_ram[vced_itr][45]);
// 46:EBS(0-7)
// VCEDフォーマット非従順、値を無視
// 47:AME(0-1)
ym2151_regset_write(cs_temp, AMS_EN_D1R + ch_temp + OP4_A, AMS_EN, vced_ram[vced_itr][47]);
// 48:KVS(0-7)
// VCEDフォーマット非従順、値を無視
// 49:OUT(0-99)
// VCEDフォーマット非従順、本来は0~99を0~127にスケーリングしなければいけない。
ym2151_regset_write(cs_temp, TL + ch_temp + OP4_A, TL_TL, vced_ram[vced_itr][49]);
// 50:F(0-63)
// MUL(4bit)とDT2(2bit) (予想)
ym2151_regset_write(cs_temp, DT1_MUL + ch_temp + OP4_A, MUL, vced_ram[vced_itr][50] >> 2);
ym2151_regset_write(cs_temp, DT2_D2R + ch_temp + OP4_A, DT2, vced_ram[vced_itr][50]);
// 51:DET(0-6)
// VCEDフォーマット非従順、本来はcenter=3だが、DT1=0~7として入力
ym2151_regset_write(cs_temp, DT1_MUL + ch_temp + OP4_A, DT1, vced_ram[vced_itr][51]);
// 52:ALG(0-7)
ym2151_regset_write(cs_temp, LR_FB_CON + ch_temp, CONECT, vced_ram[vced_itr][52]);
// 53:FBL(0~7)
ym2151_regset_write(cs_temp, LR_FB_CON + ch_temp, FL, vced_ram[vced_itr][53]);
// 54:LFS(0~99)
// VCEDフォーマット非従順、本来は0~99を0~255にスケーリングしなければいけない。
// LFO関係はチャンネルに限らず共通なので、0の時無視する
if (vced_ram[vced_itr][54] != 0)
{
ym2151_regset_write(cs_temp, LFRQ, 0xFF, vced_ram[vced_itr][54]);
// LFOをリセットするチャンネルに登録
ym2151_lfo_rst_en[ch] = 1;
}
else
{
// LFOをリセットするチャンネル解除
ym2151_lfo_rst_en[ch] = 0;
}
// 55:LFD(0~99)
// VCEDフォーマット非従順、値を無視
// 56:PMD(0~99)
// VCEDフォーマット非従順、本来は0~99を0~127にスケーリングしなければいけない。
// LFO関係はチャンネルに限らず共通なので、0の時無視する
if (vced_ram[vced_itr][56] != 0)
{
ym2151_regset_write(cs_temp, PMD_AMD, LFO_MD_F | LFO_MD, LFO_MD_F | vced_ram[vced_itr][56]);
}
// 57:AMD(0~99)
// VCEDフォーマット非従順、本来は0~99を0~127にスケーリングしなければいけない。
// LFO関係はチャンネルに限らず共通なので、0の時無視する
if (vced_ram[vced_itr][57] != 0)
{
ym2151_regset_write(cs_temp, PMD_AMD, LFO_MD_F | LFO_MD, 0x7F & vced_ram[vced_itr][57]);
}
// 58:SYNQ(0~1)
// VCEDフォーマット非従順、値を無視
// 59:LW(0~3)
// LFO関係はチャンネルに限らず共通なので、LFRQ=0の時無視する
if (vced_ram[vced_itr][54] != 0)
{
ym2151_regset_write(cs_temp, CT_W, LFO_W, vced_ram[vced_itr][59]);
}
// 60:PMS(0~7)
ym2151_regset_write(cs_temp, PMS_AMS + ch_temp, PMS, vced_ram[vced_itr][60]);
// 61:AMS(0~7)
// VCEDフォーマット非従順、本来は0~7を0~3にスケーリングしなければいけない。
ym2151_regset_write(cs_temp, PMS_AMS + ch_temp, AMS, vced_ram[vced_itr][61]);
// 62:TRPS,MID.C(0~48)//62:TRPS,MID.C(0~48) center = 24
def_tone[ch] = vced_ram[vced_itr][62] - 24;
// 以降無視
}
// 指定チャンネルにvcedパラメータを1つ反映
void ym2151_vced_t_set(unsigned char ch, unsigned int vced_n, unsigned int vced_pn)
{
unsigned char op_temp = OP1;
unsigned char cs_temp = ch >> 3;
unsigned char ch_temp = ch & 0x07;
unsigned int vced_pn_temp = vced_pn;
// vced_nは14bit値
unsigned char vced_itr = vced_itn_get(vced_n); // 14bit値VCEDナンバーからvcedパラメータ保存番号を見つける
// オペレータに対するパラメータ変更
if ((vced_pn_temp >= 0) && (vced_pn_temp <= 51))
{
// オペレータ番号による先頭位置計算
if ((vced_pn_temp >= 13) && (vced_pn_temp <= 25))
{
// OP2
op_temp = OP2;
vced_pn_temp -= 13;
}
else if ((vced_pn_temp >= 26) && (vced_pn_temp <= 38))
{
// OP3
op_temp = OP3;
vced_pn_temp -= 26;
}
else if ((vced_pn_temp >= 39) && (vced_pn_temp <= 51))
{
// OP4
op_temp = OP4;
vced_pn_temp -= 39;
}
switch (vced_pn_temp)
{
case 0: // 0:AR(0-31)
ym2151_regset_write(cs_temp, KS_AR + ch_temp + (op_temp * 8), AR, vced_ram[vced_itr][vced_pn]);
break;
case 1: // 1:D1R(0-31)
ym2151_regset_write(cs_temp, AMS_EN_D1R + ch_temp + (op_temp * 8), D1R, vced_ram[vced_itr][vced_pn]);
break;
case 2: // 2:D2R(0-31)
ym2151_regset_write(cs_temp, DT2_D2R + ch_temp + (op_temp * 8), D2R, vced_ram[vced_itr][vced_pn]);
break;
case 3: // 3:RR(0-15:DX27)(1-15:TX81Z)
ym2151_regset_write(cs_temp, D1L_RR + ch_temp + (op_temp * 8), RR, vced_ram[vced_itr][vced_pn]);
break;
case 4: // 4:D1L(0-15)
ym2151_regset_write(cs_temp, D1L_RR + ch_temp + (op_temp * 8), D1L, vced_ram[vced_itr][vced_pn]);
break;
case 5: // 5:LS(0-99)
// VCEDフォーマット非従順、値を無視
break;
case 6: // 6:RS(0-3)
// VCEDフォーマット非従順、値を無視
ym2151_regset_write(cs_temp, KS_AR + ch_temp + (op_temp * 8), KS, 0x03 & vced_ram[vced_itr][vced_pn]);
break;
case 7: // 7:EBS(0-7)
// VCEDフォーマット非従順、値を無視
break;
case 8: // 8:AME(0-1)
ym2151_regset_write(cs_temp, AMS_EN_D1R + ch_temp + (op_temp * 8), AMS_EN, vced_ram[vced_itr][vced_pn]);
break;
case 9: // 9:KVS(0-7)
// VCEDフォーマット非従順、値を無視
break;
case 10: // 10:OUT(0-99)
// VCEDフォーマット非従順、本来は0~99を0~127にスケーリングしなければいけない。
ym2151_regset_write(cs_temp, TL + ch_temp + (op_temp * 8), TL_TL, vced_ram[vced_itr][vced_pn]);
break;
case 11: // 11:F(0-63)
// MUL(4bit)とDT2(2bit) (予想)
ym2151_regset_write(cs_temp, DT1_MUL + ch_temp + (op_temp * 8), MUL, vced_ram[vced_itr][vced_pn] >> 2);
ym2151_regset_write(cs_temp, DT2_D2R + ch_temp + (op_temp * 8), DT2, vced_ram[vced_itr][vced_pn]);
break;
case 12: // 12:DET(0-6)
// VCEDフォーマット非従順、本来はcenter=3だが、DT1=0~7として入力
ym2151_regset_write(cs_temp, DT1_MUL + ch_temp + (op_temp * 8), DT1, vced_ram[vced_itr][vced_pn]);
break;
default:
break;
}
}
else // チャンネルごとに対するパラメータ変更(例外あり)
{
switch (vced_pn)
{
case 52: // 52:ALG(0-7)
ym2151_regset_write(cs_temp, LR_FB_CON + ch_temp, CONECT, vced_ram[vced_itr][vced_pn]);
break;
case 53: // 53:FBL(0~7)
ym2151_regset_write(cs_temp, LR_FB_CON + ch_temp, FL, vced_ram[vced_itr][vced_pn]);
break;
case 54: // 54:LFS(0~99)
// VCEDフォーマット非従順、本来は0~99を0~127にスケーリングしなければいけない。
// LFO関係はチャンネルに限らず共通なので注意
if (vced_ram[vced_itr][54] != 0)
{
ym2151_regset_write(cs_temp, LFRQ, 0xFF, vced_ram[vced_itr][vced_pn]);
// LFOをリセットするチャンネルに登録
ym2151_lfo_rst_en[ch] = 1;
}
else
{
// LFOをリセットするチャンネル解除
ym2151_lfo_rst_en[ch] = 0;
}
break;
case 55: // 55:LFD(0~99)
// VCEDフォーマット非従順、値を無視
break;
case 56: // 56:PMD(0~99)
// VCEDフォーマット非従順、本来は0~99を0~127にスケーリングしなければいけない。
// LFO関係はチャンネルに限らず共通なので注意
if (vced_ram[vced_itr][56] != 0)
{
ym2151_regset_write(cs_temp, PMD_AMD, LFO_MD_F | LFO_MD, LFO_MD_F | vced_ram[vced_itr][vced_pn]);
}
break;
case 57: // 57:AMD(0~99)
// VCEDフォーマット非従順、本来は0~99を0~127にスケーリングしなければいけない。
// LFO関係はチャンネルに限らず共通なので注意
if (vced_ram[vced_itr][57] != 0)
{
ym2151_regset_write(cs_temp, PMD_AMD, LFO_MD_F | LFO_MD, 0x7F & vced_ram[vced_itr][vced_pn]);
}
break;
case 58: // 58:SYNQ(0~1)
// VCEDフォーマット非従順、値を無視
break;
case 59: // 59:LW(0~3)
ym2151_regset_write(cs_temp, CT_W, LFO_W, vced_ram[vced_itr][vced_pn]);
break;
case 60: // 60:PMS(0~7)
ym2151_regset_write(cs_temp, PMS_AMS + ch_temp, PMS, vced_ram[vced_itr][vced_pn]);
break;
case 61: // 61:AMS(0~7)
ym2151_regset_write(cs_temp, PMS_AMS + ch_temp, AMS, vced_ram[vced_itr][vced_pn]);
break;
case 62: // 62:TRPS,MID.C(0~48) center = 24
def_tone[ch] = vced_ram[vced_itr][vced_pn] - 24;
break;
default:
break;
}
}
}
// プログラムチェンジナンバーよりVCEDナンバー(14bit値)をさがし、返す
unsigned int fond_vced(unsigned char pc_num)
{
unsigned int ret_vced_n = 0; // 見つからない場合は0を返す
for (int f_c = 0; f_c < PC_N; f_c++)
{
if (pc_nc[f_c] == pc_num)
{
ret_vced_n = vced_nc[f_c];
continue;
}
}
return ret_vced_n;
}
//起動時に内部パラメータをVCED保存領域にセットする
void intparam_set_vced(unsigned char vced_itr, unsigned char inst)
{
// 入力データ構造
// LFRQ,AMD,PMD,WF,NFRQ
//,PAN(bit7,bit6),FL,CON,AMS,PMS,SLOT(bit6~bit3),NE(bit7)
//,M1-AR,M1-D1R,M1-D2R,M1-RR,M1-D1L,M1-TL,M1-KS,M1-MUL,M1-DT1,M1-DT2,M1-AMS-EN(bit7)
//,C1-AR,C1-D1R,C1-D2R,C1-RR,C1-D1L,C1-TL,C1-KS,C1-MUL,C1-DT1,C1-DT2,C1-AMS-EN
//,M2-AR,M2-D1R,M2-D2R,M2-RR,M2-D1L,M2-TL,M2-KS,M2-MUL,M2-DT1,M2-DT2,M2-AMS-EN
//,C2-AR,C2-D1R,C2-D2R,C2-RR,C2-D1L,C2-TL,C2-KS,C2-MUL,C2-DT1,C2-DT2,C2-AMS-EN
// TRPS(音程:標準は24),reserve,reserve,reserve,reserve,reserve,reserve,reserve
//LFRQ
vced_ram[vced_itr][54] = pgm_read_byte_near((int)(ym2151_parameter[inst] + 0));
// AMD
vced_ram[vced_itr][57] = pgm_read_byte_near((int)(ym2151_parameter[inst] + 1));
// PMD
vced_ram[vced_itr][56] = pgm_read_byte_near((int)(ym2151_parameter[inst] + 2));
// WF
vced_ram[vced_itr][59] = pgm_read_byte_near((int)(ym2151_parameter[inst] + 3));
// NFRQ
//無視
//PAN(bit7,bit6)
//無視
//FL
vced_ram[vced_itr][53] = pgm_read_byte_near((int)(ym2151_parameter[inst] + 6));
//CONECT
vced_ram[vced_itr][52] = pgm_read_byte_near((int)(ym2151_parameter[inst] + 7));
//PMS
vced_ram[vced_itr][60] = pgm_read_byte_near((int)(ym2151_parameter[inst] + 8));
//AMS
vced_ram[vced_itr][61] = pgm_read_byte_near((int)(ym2151_parameter[inst] + 9));
//SLOT
//無視
//NE
//無視
//ym2151_regset_write(cs, PMD_AMD, LFO_MD_F | LFO_MD, 0x7F & pgm_read_byte_near((int)(ym2151_parameter[inst] + 1))); // AMD
//ym2151_regset_write(cs, PMD_AMD, LFO_MD_F | LFO_MD, LFO_MD_F | pgm_read_byte_near((int)(ym2151_parameter[inst] + 2))); // PMD
//ym2151_regset_write(cs, CT_W, LFO_W, pgm_read_byte_near((int)(ym2151_parameter[inst] + 3))); // WF
//ym2151_regset_write(cs, NOISE, NFRQ, pgm_read_byte_near((int)(ym2151_parameter[inst] + 4))); // NFRQ
//ym2151_regset_write(cs, LR_FB_CON + ch, 0xFF, (pgm_read_byte_near((int)(ym2151_parameter[inst] + 5)) & RL) | ((pgm_read_byte_near((int)(ym2151_parameter[inst] + 6)) << 3) & FL) | (pgm_read_byte_near((int)(ym2151_parameter[inst] + 7)) & CONECT)); // PAN(bit7,bit6), FL, CON
//// ym2151_regset_write(cs, LR_FB_CON + ch, FL, pgm_read_byte_near((int)(ym2151_parameter[inst] + 6)));//FL
//// ym2151_regset_write(cs, LR_FB_CON + ch, CONECT, pgm_read_byte_near((int)(ym2151_parameter[inst] + 7)));//CON
//ym2151_regset_write(cs, PMS_AMS + ch, 0xFF, (pgm_read_byte_near((int)(ym2151_parameter[inst] + 8)) & AMS) | ((pgm_read_byte_near((int)(ym2151_parameter[inst] + 9)) << 4) & PMS)); // AMS,PMS
//// ym2151_regset_write(cs, PMS_AMS + ch, PMS, pgm_read_byte_near((int)(ym2151_parameter[inst] + 9)));//PMS
//ym2151_slot_en[(cs << 3) | ch] = pgm_read_byte_near((int)(ym2151_parameter[inst] + 10)); // SLOT(bit6~bit3)
//ym2151_regset_write(cs, NOISE, NE, pgm_read_byte_near((int)(ym2151_parameter[inst] + 11)) >> 7); // NE(bit7)
// OP1-M1-AR
vced_ram[vced_itr][0] = pgm_read_byte_near((int)(ym2151_parameter[inst] + 12));
// OP1-M1-D1R
vced_ram[vced_itr][1] = pgm_read_byte_near((int)(ym2151_parameter[inst] + 13));
// OP1-M1-D2R
vced_ram[vced_itr][2] = pgm_read_byte_near((int)(ym2151_parameter[inst] + 14));
// OP1-M1-RR
vced_ram[vced_itr][3] = pgm_read_byte_near((int)(ym2151_parameter[inst] + 15));
// OP1-M1-D1L
vced_ram[vced_itr][4] = pgm_read_byte_near((int)(ym2151_parameter[inst] + 16));
// OP1-M1-TL
vced_ram[vced_itr][10] = pgm_read_byte_near((int)(ym2151_parameter[inst] + 17));
// OP1-M1-KS
vced_ram[vced_itr][6] = pgm_read_byte_near((int)(ym2151_parameter[inst] + 18));
// OP1-M1-MUL-DT2
vced_ram[vced_itr][11] = (pgm_read_byte_near((int)(ym2151_parameter[inst] + 19)) << 2) | pgm_read_byte_near((int)(ym2151_parameter[inst] + 21));
// OP1-M1-DT1
vced_ram[vced_itr][12] = pgm_read_byte_near((int)(ym2151_parameter[inst] + 20));
// OP1-M1-AMS_EN
vced_ram[vced_itr][8] = pgm_read_byte_near((int)(ym2151_parameter[inst] + 22)) >> 7;
// M1
//ym2151_regset_write(cs, KS_AR + ch, 0xFF, (pgm_read_byte_near((int)(ym2151_parameter[inst] + 12)) & AR) | (pgm_read_byte_near((int)(ym2151_parameter[inst] + 18)) << 6)); // M1-AR,KS
//ym2151_regset_write(cs, AMS_EN_D1R + ch, 0xFF, (pgm_read_byte_near((int)(ym2151_parameter[inst] + 13)) & D1R) | (pgm_read_byte_near((int)(ym2151_parameter[inst] + 22)) & AMS_EN)); // M1-D1R,AMS-EN(bit7)
//ym2151_regset_write(cs, DT2_D2R + ch, 0xFF, (pgm_read_byte_near((int)(ym2151_parameter[inst] + 14)) & D2R) | (pgm_read_byte_near((int)(ym2151_parameter[inst] + 21)) << 6)); // M1-D2R,DT2
//ym2151_regset_write(cs, D1L_RR + ch, 0xFF, (pgm_read_byte_near((int)(ym2151_parameter[inst] + 15)) & RR) | (pgm_read_byte_near((int)(ym2151_parameter[inst] + 16)) << 4)); // M1-RR,D1L
//// ym2151_regset_write(cs, D1L_RR + ch, D1L, pgm_read_byte_near((int)(ym2151_parameter[inst] + 16)));//M1-D1L
//ym2151_regset_write(cs, TL + ch, TL_TL, pgm_read_byte_near((int)(ym2151_parameter[inst] + 17))); // M1-TL
//// ym2151_regset_write(cs, KS_AR + ch, KS, pgm_read_byte_near((int)(ym2151_parameter[inst] + 18)));//M1-KS
//ym2151_regset_write(cs, DT1_MUL + ch, 0xFF, (pgm_read_byte_near((int)(ym2151_parameter[inst] + 19)) & MUL) | (pgm_read_byte_near((int)(ym2151_parameter[inst] + 20)) << 4)); // M1-MUL,DT1
//// ym2151_regset_write(cs, DT1_MUL + ch, DT1, pgm_read_byte_near((int)(ym2151_parameter[inst] + 20)));//M1-DT1
//// ym2151_regset_write(cs, DT2_D2R + ch, DT2, pgm_read_byte_near((int)(ym2151_parameter[inst] + 21)));//M1-DT2
//// ym2151_regset_write(cs, AMS_EN_D1R + ch, AMS_EN, pgm_read_byte_near((int)(ym2151_parameter[inst] + 22)));//M1-AMS-EN(bit7)
// OP2-C1-AR
vced_ram[vced_itr][13] = pgm_read_byte_near((int)(ym2151_parameter[inst] + 23));
// OP2-C1-D1R
vced_ram[vced_itr][14] = pgm_read_byte_near((int)(ym2151_parameter[inst] + 24));
// OP2-C1-D2R
vced_ram[vced_itr][15] = pgm_read_byte_near((int)(ym2151_parameter[inst] + 25));
// OP2-C1-RR
vced_ram[vced_itr][16] = pgm_read_byte_near((int)(ym2151_parameter[inst] + 26));
// OP2-C1-D1L
vced_ram[vced_itr][17] = pgm_read_byte_near((int)(ym2151_parameter[inst] + 27));
// OP2-C1-TL
vced_ram[vced_itr][23] = pgm_read_byte_near((int)(ym2151_parameter[inst] + 28));
// OP2-C1-KS
vced_ram[vced_itr][19] = pgm_read_byte_near((int)(ym2151_parameter[inst] + 29));
// OP2-C1-MUL-DT2
vced_ram[vced_itr][24] = (pgm_read_byte_near((int)(ym2151_parameter[inst] + 30)) << 2) | pgm_read_byte_near((int)(ym2151_parameter[inst] + 32));
// OP2-C1-DT1
vced_ram[vced_itr][25] = pgm_read_byte_near((int)(ym2151_parameter[inst] + 31));
// OP2-C1-AMS_EN
vced_ram[vced_itr][21] = pgm_read_byte_near((int)(ym2151_parameter[inst] + 33)) >> 7;
// C1
//ym2151_regset_write(cs, KS_AR + ch + 16, 0xFF, (pgm_read_byte_near((int)(ym2151_parameter[inst] + 23)) & AR) | (pgm_read_byte_near((int)(ym2151_parameter[inst] + 29)) << 6)); // C1-AR,KS
//ym2151_regset_write(cs, AMS_EN_D1R + ch + 16, 0xFF, (pgm_read_byte_near((int)(ym2151_parameter[inst] + 24)) & D1R) | (pgm_read_byte_near((int)(ym2151_parameter[inst] + 33)) & AMS_EN)); // C1-D1R,AMS-EN(bit7)
//ym2151_regset_write(cs, DT2_D2R + ch + 16, 0xFF, (pgm_read_byte_near((int)(ym2151_parameter[inst] + 25)) & D2R) | (pgm_read_byte_near((int)(ym2151_parameter[inst] + 32)) << 6)); // C1-D2R,DT2
//ym2151_regset_write(cs, D1L_RR + ch + 16, 0xFF, (pgm_read_byte_near((int)(ym2151_parameter[inst] + 26)) & RR) | (pgm_read_byte_near((int)(ym2151_parameter[inst] + 27)) << 4)); // C1-RR,D1L
//// ym2151_regset_write(cs, D1L_RR + ch + 16, D1L, pgm_read_byte_near((int)(ym2151_parameter[inst] + 27)));//C1-D1L
//ym2151_regset_write(cs, TL + ch + 16, TL_TL, pgm_read_byte_near((int)(ym2151_parameter[inst] + 28))); // C1-TL
//// ym2151_regset_write(cs, KS_AR + ch + 16, KS, pgm_read_byte_near((int)(ym2151_parameter[inst] + 29)));//C1-KS
//ym2151_regset_write(cs, DT1_MUL + ch + 16, 0xFF, (pgm_read_byte_near((int)(ym2151_parameter[inst] + 30)) & MUL) | (pgm_read_byte_near((int)(ym2151_parameter[inst] + 31)) << 4)); // C1-MUL,DT1
//// ym2151_regset_write(cs, DT1_MUL + ch + 16, DT1, pgm_read_byte_near((int)(ym2151_parameter[inst] + 31)));//C1-DT1
//// ym2151_regset_write(cs, DT2_D2R + ch + 16, DT2, pgm_read_byte_near((int)(ym2151_parameter[inst] + 32)));//C1-DT2
//// ym2151_regset_write(cs, AMS_EN_D1R + ch + 16, AMS_EN, pgm_read_byte_near((int)(ym2151_parameter[inst] + 33)));//C1-AMS-EN(bit7)
// OP3-M2-AR
vced_ram[vced_itr][26] = pgm_read_byte_near((int)(ym2151_parameter[inst] + 34));
// OP3-M2-D1R
vced_ram[vced_itr][27] = pgm_read_byte_near((int)(ym2151_parameter[inst] + 35));
// OP3-M2-D2R
vced_ram[vced_itr][28] = pgm_read_byte_near((int)(ym2151_parameter[inst] + 36));
// OP3-M2-RR
vced_ram[vced_itr][29] = pgm_read_byte_near((int)(ym2151_parameter[inst] + 37));
// OP3-M2-D1L
vced_ram[vced_itr][30] = pgm_read_byte_near((int)(ym2151_parameter[inst] + 38));
// OP3-M2-TL
vced_ram[vced_itr][36] = pgm_read_byte_near((int)(ym2151_parameter[inst] + 39));
// OP3-M2-KS
vced_ram[vced_itr][32] = pgm_read_byte_near((int)(ym2151_parameter[inst] + 40));
// OP3-M2-MUL-DT2
vced_ram[vced_itr][37] = (pgm_read_byte_near((int)(ym2151_parameter[inst] + 41)) << 2) | pgm_read_byte_near((int)(ym2151_parameter[inst] + 43));
// OP3-M2-DT1
vced_ram[vced_itr][38] = pgm_read_byte_near((int)(ym2151_parameter[inst] + 42));
// OP3-M2-AMS_EN
vced_ram[vced_itr][34] = pgm_read_byte_near((int)(ym2151_parameter[inst] + 44)) >> 7;
// M2
//ym2151_regset_write(cs, KS_AR + ch + 8, 0xFF, (pgm_read_byte_near((int)(ym2151_parameter[inst] + 34)) & AR) | (pgm_read_byte_near((int)(ym2151_parameter[inst] + 40)) << 6)); // M2-AR,KS
//ym2151_regset_write(cs, AMS_EN_D1R + ch + 8, 0xFF, (pgm_read_byte_near((int)(ym2151_parameter[inst] + 35)) & D1R) | (pgm_read_byte_near((int)(ym2151_parameter[inst] + 44)) & AMS_EN)); // M2-D1R,AMS-EN(bit7)
//ym2151_regset_write(cs, DT2_D2R + ch + 8, 0xFF, (pgm_read_byte_near((int)(ym2151_parameter[inst] + 36)) & D2R) | (pgm_read_byte_near((int)(ym2151_parameter[inst] + 43)) << 6)); // M2-D2R,DT2
//ym2151_regset_write(cs, D1L_RR + ch + 8, 0xFF, (pgm_read_byte_near((int)(ym2151_parameter[inst] + 37)) & RR) | (pgm_read_byte_near((int)(ym2151_parameter[inst] + 38)) << 4)); // M2-RR,D1L
//// ym2151_regset_write(cs, D1L_RR + ch + 8, D1L, pgm_read_byte_near((int)(ym2151_parameter[inst] + 38)));//M2-D1L
//ym2151_regset_write(cs, TL + ch + 8, TL_TL, pgm_read_byte_near((int)(ym2151_parameter[inst] + 39))); // M2-TL
//// ym2151_regset_write(cs, KS_AR + ch + 8, KS, pgm_read_byte_near((int)(ym2151_parameter[inst] + 40)));//M2-KS
//ym2151_regset_write(cs, DT1_MUL + ch + 8, 0xFF, (pgm_read_byte_near((int)(ym2151_parameter[inst] + 41)) & MUL) | (pgm_read_byte_near((int)(ym2151_parameter[inst] + 42)) << 4)); // M2-MUL,DT1
//// ym2151_regset_write(cs, DT1_MUL + ch + 8, DT1, pgm_read_byte_near((int)(ym2151_parameter[inst] + 42)));//M2-DT1
//// ym2151_regset_write(cs, DT2_D2R + ch + 8, DT2, pgm_read_byte_near((int)(ym2151_parameter[inst] + 43)));//M2-DT2
//// ym2151_regset_write(cs, AMS_EN_D1R + ch + 8, AMS_EN, pgm_read_byte_near((int)(ym2151_parameter[inst] + 44)));//M2-AMS-EN(bit7)
// OP4-C2-AR
vced_ram[vced_itr][39] = pgm_read_byte_near((int)(ym2151_parameter[inst] + 45));
// OP4-C2-D1R
vced_ram[vced_itr][40] = pgm_read_byte_near((int)(ym2151_parameter[inst] + 46));
// OP4-C2-D2R
vced_ram[vced_itr][41] = pgm_read_byte_near((int)(ym2151_parameter[inst] + 47));
// OP4-C2-RR
vced_ram[vced_itr][42] = pgm_read_byte_near((int)(ym2151_parameter[inst] + 48));
// OP4-C2-D1L
vced_ram[vced_itr][43] = pgm_read_byte_near((int)(ym2151_parameter[inst] + 49));
// OP4-C2-TL
vced_ram[vced_itr][49] = pgm_read_byte_near((int)(ym2151_parameter[inst] + 50));
// OP4-C2-KS
vced_ram[vced_itr][45] = pgm_read_byte_near((int)(ym2151_parameter[inst] + 51));
// OP4-C2-MUL-DT2
vced_ram[vced_itr][50] = (pgm_read_byte_near((int)(ym2151_parameter[inst] + 52)) << 2) | pgm_read_byte_near((int)(ym2151_parameter[inst] + 54));
// OP4-C2-DT1
vced_ram[vced_itr][51] = pgm_read_byte_near((int)(ym2151_parameter[inst] + 53));
// OP4-C2-AMS_EN
vced_ram[vced_itr][47] = pgm_read_byte_near((int)(ym2151_parameter[inst] + 55)) >> 7;
// C2
//ym2151_regset_write(cs, KS_AR + ch + 24, 0xFF, (pgm_read_byte_near((int)(ym2151_parameter[inst] + 45)) & AR) | (pgm_read_byte_near((int)(ym2151_parameter[inst] + 51)) << 6)); // C2-AR,KS
//ym2151_regset_write(cs, AMS_EN_D1R + ch + 24, 0xFF, (pgm_read_byte_near((int)(ym2151_parameter[inst] + 46)) & D1R) | (pgm_read_byte_near((int)(ym2151_parameter[inst] + 55)) & AMS_EN)); // C2-D1R,AMS-EN(bit7)
//ym2151_regset_write(cs, DT2_D2R + ch + 24, 0xFF, (pgm_read_byte_near((int)(ym2151_parameter[inst] + 47)) & D2R) | (pgm_read_byte_near((int)(ym2151_parameter[inst] + 54)) << 6)); // C2-D2R,DT2
//ym2151_regset_write(cs, D1L_RR + ch + 24, 0xFF, (pgm_read_byte_near((int)(ym2151_parameter[inst] + 48)) & RR) | (pgm_read_byte_near((int)(ym2151_parameter[inst] + 49)) << 4)); // C2-RR,D1L
//// ym2151_regset_write(cs, D1L_RR + ch + 24, D1L, pgm_read_byte_near((int)(ym2151_parameter[inst] + 49)));//C2-D1L
//ym2151_regset_write(cs, TL + ch + 24, TL_TL, pgm_read_byte_near((int)(ym2151_parameter[inst] + 50))); // C2-TL
//// ym2151_regset_write(cs, KS_AR + ch + 24, KS, pgm_read_byte_near((int)(ym2151_parameter[inst] + 51)));//C2-KS
//ym2151_regset_write(cs, DT1_MUL + ch + 24, 0xFF, (pgm_read_byte_near((int)(ym2151_parameter[inst] + 52)) & MUL) | (pgm_read_byte_near((int)(ym2151_parameter[inst] + 53)) << 4)); // C2-MUL,DT1
//// ym2151_regset_write(cs, DT1_MUL + ch + 24, DT1, pgm_read_byte_near((int)(ym2151_parameter[inst] + 53)));//C2-DT1
//// ym2151_regset_write(cs, DT2_D2R + ch + 24, DT2, pgm_read_byte_near((int)(ym2151_parameter[inst] + 54)));//C2-DT2
//// ym2151_regset_write(cs, AMS_EN_D1R + ch + 24, AMS_EN, pgm_read_byte_near((int)(ym2151_parameter[inst] + 55)));//C2-AMS-EN(bit7)
vced_ram[vced_itr][62] = pgm_read_byte_near((int)(ym2151_parameter[inst] + 56));//音程
}
上記動画で使用した音色パラメータを置いておきます。
・参考
YM2151の偽物・互換品リスト
EMMA Italian Dumping team YM2151
YM2151テストレジスタの詳細
MSX Assembly Page
Yamaha YM2151 OPM test register info by Jarek Burczynski
YM2151の出力の詳細
如是我聞~これからFPGAの話をしよう~ FM音源のDACインターフェース解析の更新 [IPコア]
・関連記事
/*検索エンジン用単語リスト*/
使い方
sound generator
how to use
usage
情報の一覧性が高くて助かります。まとめありがとうございます。、
返信削除