2023年6月25日日曜日

YMF709-Dの使い方

YMF709-Dの使い方

注意:このサイトの内容を鵜呑みにし、事故や損失を招いた場合でも当方は一切の責任は負いかねます。自己責任でお願いします。





YMF709-D
YMF709
正式な型番はYMF709-DZ
HD-81からの取り外し品です。
1997年製造?

YMF709-Dは4オペレータのFM音源IC (OPOS または OPO-S)です。(LSIですが便宜上ICと呼びます。)

主にYAMAHAのハーモニーディレクターで用いられていた音源ICです。
搭載機器は確認できているもので、YAMAHA HD-81とYAMAHA HD-100のみです。

入手性は非常に悪く、現状は上記2機種を入手して分解する方法しかありません。


この音源ICの知名度はかなり低く、仕様も公開されていないため、今回はHD-81を解析した結果をもとに使い方をまとめました。

幸い、HD-100のサービスマニュアルが入手できるため、ピン配置と周辺回路の情報は得ることができました。



HD-100のサービスマニュアルでは、YMF709-Dを「OPOS」、「OPO-S」と呼んでいます。

YAMAHAのFM音源の系統は、大きなくくりで見ると「OPN」、「OPM」、「OPL」、「OPS」の4つあります。
このうちOPMは、「OPP」や「OPZ」などOPMに機能を増やした後継があり、OPOSもOPMの後継または先代の1つであると予想できます。

特にOPPはOPMに主にチャンネルボリューム機能を追加したもので、機能的にOPMからあまり進化していなくても別シリーズ名を付けている場合があります。
OPOSもまだ使用機器が確認されていない「OPO (Operator Type-O)」が存在するとして、そのサブセットまたは一部の機能変更したものだとすると、OPOSはOPM並みに仕様が近い可能性があります。




解析の結果、YM2151(OPM)の類似品の可能性が高いとわかりました。
レジスタ配置のほとんどはOPMと同一ですが、音程にかかわるレジスタの違いや一部機能の省略と仕様の違いがあります。
ちなみに、OPPはOPMにチャンネルボリュームレジスタを追加したものですが、OPOSはチャンネルボリュームレジスタの追加は見られないため、OPOSはOPMの音階をさらに細分化して出力できるようにしたものだと思います。

音色パラメータは一部を除いて互換性があり、OPM→OPOSの移植も容易にできます。
実際、YAMAHA HD-81のYMF709-DをYM2151に付けかえてみたところ、音程は狂っていますが発音することを確認しました。

TX-81ZのYM2414(OPZ)をYMF709-Dに付けかえてみた場合、正常な発音はしなかったため、レジスタ配置はOPMよりであると思います。(マスターボリューム変更時に大音量のノイズ音が出ます。OPMと同様の挙動)

YM2164(OPP)搭載機器はまだ入手していないため、確認していません。


YMF709-D単体では、音を出すことはできず、YM3012などの専用のDACが必要です。


・YMF709-D (OPOS)の特徴

軽く調べた結果、OPMと比較した時、以下の特徴がわかりました。未知の仕様が存在するかもしれないので参考程度にみてください。

・4オペレータ8アルゴリズム、同時発音数 : 8
・24ピンDIP
・ハードウェアエンベロープ
・ハードウェアLFO
・ノイズジェネレータ

OPMとの違い

・発音周波数の細分化(17bit値で周波数を決定)
・LFOはオペレータ出力のAM(振幅変調)のみ(LFOによるPM(位相変調)は無し)?
・DT2無し?
・AMS(LFO振幅変調感度)がオペレータ毎に設定可能?



ハーモニーディレクタは絶対周波数に焦点をあてた製品なので、LFOによる周波数変調は不要なため、PMを省いたのでしょうか?


OPMの取柄であるDT2(非整数倍のオペレータ周波数倍率)が無いため、OPM系統というのには無理がありそうです。
OPMのDT2レジスタビットの場所には、代わりにAMSが割り当てられています。AMSをオペレータ毎に設定できるため、OPMでDT2を使わない場合より多少音色に変化を与えられますがDT2ほど効果的ではなさそうです。
実際、HD-81ではどの音色パラメータもこのレジスタビット値を0としています。
そのため、HD-81の音色パラメータをOPMにセットした場合と同じ音色が出ます。



勝手な憶測をすると、幻の「OPO」はAMSをオペレータ毎に設定してより複雑な音色をつくるコンセプトの音源だと考えられます。
そのOPOにハーモニーディレクタ用に発音周波数の細分化を付け足したのがこのOPOSなのではないでしょうか?
OPM、OPP、OPOSのICのダイの画像を見比べることができれば、系統の関係が見えてきそうな気がします。



・ピン配置

YM2151(OPM)と同様です。YM2151を付け替えてソフトウェアでの対応が可能です。

※HD-100のサービスマニュアル内のOPOSピン配置表の番号は誤植なので注意


ピン番号名称I/O機能
1VSS(GND)-グランド端子です。
2~IRQO割り込み要求端子です。

内部タイマーカウンタにより、割り込み要求がされるようです。

オープンドレイン出力なので、プルアップ抵抗が必要になります。
3~ICIリセット端子です。
この端子がLの期間、内部レジスタを初期化します。
4A0Iアドレス / データセレクト端子です。

この端子がLの場合、D0~D7はアドレス入力端子となります。

Hの場合、D0~D7はデータ入力端子となります。
5~WRIライト端子です。

この端子がLでかつ、「~CS」がLの期間、
D0~D7端子の状態が内部レジスタへラッチされます。
6~RDIリード端子です。

この端子がLでかつ、「A0」がHでかつ、「~CS」がLの期間、
内部ステータスレジスタの状態がD0~D7端子へラッチされます。
7~CSIチップセレクト端子です。

この端子がLの期間、「~WR」または「~RD」端子がLの時、
書き込み・読み込みができます。
8CT1O汎用出力端子です。

$1Bのbit6に割り当てられています。
9CT2O汎用出力端子です。

$1Bのbit7に割り当てられています。
10D0I/Oデータピンです。
11VSS(GND)-グランド端子です。
12D1I/Oデータピンです。
13D2I/Oデータピンです。
14D3I/Oデータピンです。
15D4I/Oデータピンです。
16D5I/Oデータピンです。
17D6I/Oデータピンです。
18D7I/Oデータピンです。
19SH2Oチャンネル2のアナログ出力ホールド端子です。

チャンネル1のデータラッチ信号としても使います。(要検証)

YM3012などのDACへ接続します。
20SH1Oチャンネル1のアナログ出力ホールド端子です。

チャンネル2のデータラッチ信号としても使います。(要検証)

YM3012などのDACへ接続します。
21SOOシリアルデータ出力端子です。

YM3012などのDACへ接続します。
22VDD(+5V)-電源端子です。
+5Vの電源を用意してください。
23Φ1Oクロック出力端子です。

YM3012などのDACへ接続します。
24ΦMIクロック入力端子です。

HD-81の場合、3.5MHz
HD-100の場合、3.83616MHz
のクロックを入力しています。

仕様上はYM2151のように標準で3.58MHz、最大で4.0MHzまで入力できると予想できます。



・YMF709-Dのレジスタ(書き込み専用)

YMF709-Dは$00~$FFの256バイトのレジスタを持っています。

このレジスタも軽く調べてみただけなので、ミスがあると思います。違う部分を指摘していただけるととても助かります。
YM2151(OPM)と違うと思われるレジスタやビットには赤色で色かけしています。
また、(未検証)とある部分や黄色で色かけしている部分はYM2151に基づいた予想の機能で、基本的に実際に動作を確認していない部分なので注意してください。

アドレス
レジスタ名 機能
$00 - 未使用
$01 TEST テスト用のレジスタです。

仕様は恐らくYM2151と同様と予想。

bit7
bit6
bit5
bit4
bit3
bit2
bit1
bit0
TEST_6TEST_5TEST_4TEST_3TEST_2TEST_1LFO_RESETTEST_0


TEST_0 ~ TEST_6 には常に0を書き込んだ状態にしてください。


LFO_RESET:
このビットをHにすると、LFOが停止します。

LFO = H : LFOの停止
LFO = L : LFOを動作(位相がリセットされます。)

$02~07 - 未使用
$08 KON KEY ON
キーオン・キーオフレジスタです。


bit7
bit6
bit5
bit4
bit3
bit2
bit1
bit0
-SN_3SN_2SN_1SN_0CH_2CH_1CH_0


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
ノイズジェネレータの設定レジスタです。


bit7
bit6
bit5
bit4
bit3
bit2
bit1
bit0
NE--NFRQ_4NFRQ_3NFRQ_2NFRQ_1NFRQ_0


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をセットします。


bit7
bit6
bit5
bit4
bit3
bit2
bit1
bit0
NA_9NA_8NA_7NA_6NA_5NA_4NA_3NA_2


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をセットします。


bit7
bit6
bit5
bit4
bit3
bit2
bit1
bit0
------NA_1NA_0


$12 CLKB 内部タイマーBの設定値8bitです。


bit7
bit6
bit5
bit4
bit3
bit2
bit1
bit0
CLKB_7CLKB_6CLKB_5CLKB_4CLKB_3CLKB_2CLKB_1CLKB_0


CLKB: (未検証)
タイマーBの設定値です。

  Tb  = 1024 * (256 - CLKB) / ΦM    [s]

Tb : タイマーAオーバーフロー周期[s]
CLKB = 0~255(0x00~0xFF) :ノイズ周波数決定ビット
ΦM : 入力クロック周波数[Hz]

$13 - 未使用
$14 TIM_CONF 内部タイマーの動作設定ビット群です。


bit7
bit6
bit5
bit4
bit3
bit2
bit1
bit0
CSM-F_RESET_BF_RESET_AIRQ_EN_BIRQ_EN_ALOAD_BLOAD_A


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周波数設定レジスタです。


bit7
bit6
bit5
bit4
bit3
bit2
bit1
bit0
LFRQ_7LFRQ_6LFRQ_5LFRQ_4LFRQ_3LFRQ_2LFRQ_1LFRQ_0


LFRQ: (未検証)
LFRQ = 0~255 (0x00~0xFF) : LFO発振周波数決定レジスタ
(入力クロック周波数 ΦM = 3.579545Mhzの場合、0.0008Hz~52.9127hz)

LFRQにセットする値が大きいほど発振周波数が高くなります。

$19 PMD_AMD AMPLITUDE MODULATION DEPTH
振幅変調深度設定レジスタです。


bit7
bit6
bit5
bit4
bit3
bit2
bit1
bit0
LFO_MD_F?LFO_MD_6LFO_MD_5LFO_MD_4LFO_MD_3LFO_MD_2LFO_MD_1LFO_MD_0


LFO_MD_F?:
YM2151の場合、変調データのセット選択ビットです。LFO_MD_0~LFO_MD_6のデータのセット先を決定します。
YMF709-Dの場合、LFOによる位相変調があるかわかりませんが、このビットをLにした状態でないとAMDを設定できません。

LFO_MD_F = L : AMD(振幅変調深度レジスタへ書き込み)


LFO_MD:
変調深度をセットします。
AMDの場合、補数なしでセットします。

LFO_MD = 0~127 (0x00 ~ 0x7F): AMD深度のセット(LFO_MD_F = L)

$1A - 未使用
$1B CT_W CONTROL OUTPUT / WAVE FORM
汎用端子出力ビット・LFO変調波形設定レジスタです。


bit7
bit6
bit5
bit4
bit3
bit2
bit1
bit0
CT2CT1----LFO_W_1LFO_W_0


CT:
汎用出力ポートに出力する値をセットします。

CT1 = H or L : CT1端子(8pin)にHまたはLを出力します。
CT2 = H or L : CT2端子(9pin)にHまたはLを出力します。


LFO_W:
LFO変調波形決定ビットです。

LFO_W_1LFO_W_0波形
LL鋸歯状波
LH矩形波
HL三角波
HHノイズ

$1C~$1F - 未使用
$20~27 LR_FB_CON チャンネル出力・フィードバック・アルゴリズム設定レジスタです。

$20~$27にCH1~CH8が割り当てられています。


bit7
bit6
bit5
bit4
bit3
bit2
bit1
bit0
RL_RRL_LFL_2FL_1FL_0CONECT_2CONECT_1CONECT_0


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
コネクションを設定します。

CONECT_2CONECT_1CONECT_0アルゴリズム
LLL
0. シリアル4連モード

[M1]→[C1]→[M2]→[C2]→OUT

※[M1]は自己フィードバックあり
LLH
1. ダブル変調シリアル3連モード

[M1]→⊕→[M2]→[C2]→OUT
[C1]↗

※[M1]は自己フィードバックあり
LHL
2. ダブル変調モード①

[C1]→[M2]→⊕→[C2]→OUT
[M1]↗

※[M1]は自己フィードバックあり
LHH
3. ダブル変調モード②

[M1]→[C1]→⊕→[C2]→OUT
[M2]↗

※[M1]は自己フィードバックあり
HLL
4. シリアル2連・2パラレルモード

[M1]→[C1]→⊕→OUT
[M2]→[C2]↗

※[M1]は自己フィードバックあり
HLH
5. 共通変調3パラレルモード

↗[C1]↘
[M1]→[M2]→⊕→OUT
↘[C2]↗

※[M1]は自己フィードバックあり
HHL
6. シリアル2連+2サインモード

[M2]↘
[M1]→[C1]→⊕→OUT
[C2]↗

※[M1]は自己フィードバックあり
HHH
7. パラレルサイン合成モード

[M1]↘
[C1]↘
[M2]→⊕→OUT
[C2]↗

※[M1]は自己フィードバックあり

$28~$2F TP_H TONE PERIOD H
音程設定レジスタ上位ビットです。
$30~$37の「TONE PERIOD L」とセットで使用します。
$38~$3Fの「MICRO TUNE」とセットで使用します。

$28~$2FにCH1~CH8が割り当てられています。


bit7
bit6
bit5
bit4
bit3
bit2
bit1
bit0
TP_H_15TP_H_14TP_H_13TP_H_12TP_H_11TP_H_10TP_H_9TP_H_8


TP:
TONE 
PERIOD
音程設定ビットです。
$30~$37にある「TONE PERIOD L」、$38~$3Fの「MICRO TUNE」とセットで使用します。

TP = (TP_H << 8) | TP_L

TP = 0~65535 (0x0000 ~ 0xFFFF) : 音程設定ビット

この値が大きいほど、高い音程の音が出力されます。




レジスタ設定値と出力周波数foutは以下の関係があります。
   (TP << 1) | M = fout * (2^27) / ΦM

レジスタ設定値から出力周波数を求めたい場合は以下のとおりです。
   fout = ((TP << 1) | M) * ΦM / (2^26)   [Hz]

TONE PERIOD : 音程設定ビット(16bit)

M :MICRO TUNE設定ビット(1bit)
ΦM : 入力クロック周波数[Hz]



--MIDIノートナンバーからレジスタ値を求める場合--
   (TP << 1) | M = (440 / (2 ^ (69/12))) * (2 ^ (note_n/12)) * (2^27) / ΦM
      = 8.175799 * (2 ^ (note_n/12)) * (2^27) / ΦM


note_n : MIDIノートナンバ(0~127、note_n=69のときfout=440)
ΦM : 入力クロック周波数[Hz]


   [入力クロックΦM = 3.579545MHzの場合]

  (TP << 1) | M = 8.175799 * (2 ^ (note/12)) * (2^27) / (3.579545 * 10^6)
      = 306.5577235 * (2 ^ (note/12))


$30~$37 TP_L TONE PERIOD L
音程設定レジスタ下位ビットです。
$28~$2Fの「TONE PERIOD H」とセットで使用します。
$38~$3Fの「MICRO TUNE」とセットで使用します。

$30~$38にCH1~CH8が割り当てられています。


bit7
bit6
bit5
bit4
bit3
bit2
bit1
bit0
TP_H_7TP_H_6TP_H_5TP_H_4TP_H_3TP_H_2TP_H_1TP_H_0


詳しくは$28~$2Fの「TONE PERIOD H」をみてください。

$38~$3F LFRQ2_M LOW FREQUENCY 2? / MICRO TUNE
LFO周波数設定レジスタ2?・音程微調整ビットです。

このレジスタの仕様はまだ不明です。
特にbit0以外のレジスタの挙動はまだ把握していないので、参考にしないでください。

音程微調整ビットは$38~$3FにCH1~CH8が割り当てられています。



bit7
bit6
bit5
bit4
bit3
bit2
bit1
bit0
LFRQ2_5?LFRQ2_4?LFRQ2_3?LFRQ2_2?LFRQ2_1?LFRQ2_0??M


LFRQ2: (何ビット値かは不明。bit7~bit1のいずれかの範囲)
このレジスタの挙動はまだ謎です。
このレジスタの値を変化させると、LFOの周波数が変化します。
ただし、$38~$3Fのこのレジスタの合計値がLFOの周波数を決定しているようです。
チャンネルごとにLFOの周波数を決められないようなので注意してください。

この値を大きくするとLFO周波数が高くなります。



M:
音程微調整ビットです。
このレジスタの機能はHD-81の挙動から推測したので、違う可能性があります。
YM2414(OPZ)の$30~$37のMICRO TUNEビットと同じ機能かはわかりません。

音程設定レジスタのLSBに相当します。

詳しくは$28~$2Fの「TONE PERIOD H」をみてください。

$40~5F DT1_MUL DETUNE(1) / PHASE MULTIPLY
スロット倍率微調整・スロット倍率設定レジスタです。

$40~$5FにSLOT1~SLOT32が割り当てられています。


bit7
bit6
bit5
bit4
bit3
bit2
bit1
bit0
-DT1_2DT1_1DT1_0MUL_3MUL_2MUL_1MUL_0


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が割り当てられています。


bit7
bit6
bit5
bit4
bit3
bit2
bit1
bit0
-TL_6TL_5TL_4TL_3TL_2TL_1TL_0


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が割り当てられています。


bit7
bit6
bit5
bit4
bit3
bit2
bit1
bit0
KS_1KS_0-AR_4AR_3AR_2AR_1AR_0


KS: (未検証)
ピッチによるエンベロープ時間補正ビットです。
実際の楽器の場合、ピッチが高くなるにつれ、エンベロープ時間が短くなります。
このビットは、この特性を再現するためのビットです。

KS = 0~3 (0x0 ~ 0x3) : ピッチによるエンベロープ時間補正のセット(値が大きいほどエンベロープ時間を短くします。)



AR:
出力レベルのエンベロープ制御する際のアタック時間を設定するビットです。
この値が小さいほどアタック時間が増加します。

AR = 0~31 (0x0 ~ 0x1F) : アタック時間のセット

$A0~$BF D1R FIRST DECAY RATE
エンベロープファーストディケイレート設定レジスタです。

bit7のAMS有効フラグは無いようです。

$80~$9FにSLOT1~SLOT32が割り当てられています。


bit7
bit6
bit5
bit4
bit3
bit2
bit1
bit0
---D1R_4D1R_3D1R_2D1R_1D1R_0


D1R:
出力レベルのエンベロープ制御する際のファーストディケイ時間(ファーストディケイレベルまで移行する時間)を設定するビットです。
この値が小さいほどファーストディケイ時間が増加します。

D1R = 0~31 (0x00 ~ 0x1F) : ファーストディケイ時間のセット

$C0~$DF AMS_D2R AMPLITUDE MODULATION SENSITIVITY / SECOND DECAY RATE
LFO振幅変調感度・エンベロープセカンドディケイレート設定レジスタです。

$C0~$DFにSLOT1~SLOT32が割り当てられています。


bit7
bit6
bit5
bit4
bit3
bit2
bit1
bit0
AMS_1AMS_0-D2R_4D2R_3D2R_2D2R_1D2R_0


AMS:
LFO振幅変調感度設定ビットです。DT2レジスタではないので注意してください。


スロットごとにAMSを設定出来るため、YMF709にはAMS有効フラグがありません。
このレジスタビット値をセットすると振幅変調がかかります。
AMS=0で振幅変調無効、この値が大きいほど振幅変調が強くかかります。

AMS = 0~3 : LFO振幅変調感度設定



D2R:
出力レベルのエンベロープ制御する際のセカンドトディケイ時間(0レベルまで移行する時間)を設定するビットです。
この値が小さいほどセカンドディケイ時間が増加します。

D2R = 0~31 (0x00 ~ 0x1F) : セカンドトディケイ時間のセット

$EF~$FF D1L_RR FIRST DECAY LEVEL / RELEASE RATE
エンベロープファーストディケイレベル・エンベロープセカンドディケイレート設定レジスタです。

$C0~$DFにSLOT1~SLOT32が割り当てられています。


bit7
bit6
bit5
bit4
bit3
bit2
bit1
bit0
D1L_3D1L_2D1L_1D1L_0RR_3RR_2RR_1RR_0


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) : リリース時間のセット



レジスタマップ

YMF709-Dの内部レジスタのレジスタマップ(ビットマップ)です。
軽く調べただけなので、間違えているものがあると思います。あまり参考にしない方がよいかもしれません。

"レジスタビット名"_"ビット名またはチャンネルNO.またはスロットNO."_"第何ビット"
の形で表しています。

bit7bit6bit5bit4bit3bit2bit1bit0
$00
$01TEST_6TEST_5TEST_4TEST_3TEST_2TEST_1LFO_RESETTEST_0
$02
$03
$04
$05
$06
$07
$08SN_3SN_2SN_1SN_0CH_2CH_1CH_0
$09
$0A
$0B
$0C
$0D
$0E
$0FNE
NFRQ_4NFRQ_3NFRQ_2NFRQ_1NFRQ_0
$10NA_9NA_8NA_7NA_6NA_5NA_4NA_3NA_2
$11NA_1NA_0
$12CLKB_7CLKB_6CLKB_5CLKB_4CLKB_3CLKB_2CLKB_1CLKB_0
$13
$14CSMF_RESET_BF_RESET_AIRQ_EN_BIRQ_EN_ALOAD_BLOAD_A
$15
$16
$17
$18LFRQ_7LFRQ_6LFRQ_5LFRQ_4LFRQ_3LFRQ_2LFRQ_1LFRQ_0
$19LFO_MD_F?LFO_MD_6LFO_MD_5LFO_MD_4LFO_MD_3LFO_MD_2LFO_MD_1LFO_MD_0
$1A
$1BCT2CT1LFO_W_1LFO_W_0
$1C
$1D
$1E
$1F
$20RL_CH1_RRL_CH1_LFL_CH1_2FL_CH1_1FL_CH1_0CONECT_CH1_2CONECT_CH1_1CONECT_CH1_0
$21RL_CH2_RRL_CH2_LFL_CH2_2FL_CH2_1FL_CH2_0CONECT_CH2_2CONECT_CH2_1CONECT_CH2_0
$22RL_CH3_RRL_CH3_LFL_CH3_2FL_CH3_1FL_CH3_0CONECT_CH3_2CONECT_CH3_1CONECT_CH3_0
$23RL_CH4_RRL_CH4_LFL_CH4_2FL_CH4_1FL_CH4_0CONECT_CH4_2CONECT_CH4_1CONECT_CH4_0
$24RL_CH5_RRL_CH5_LFL_CH5_2FL_CH5_1FL_CH5_0CONECT_CH5_2CONECT_CH5_1CONECT_CH5_0
$25RL_CH6_RRL_CH6_LFL_CH6_2FL_CH6_1FL_CH6_0CONECT_CH6_2CONECT_CH6_1CONECT_CH6_0
$26RL_CH7_RRL_CH7_LFL_CH7_2FL_CH7_1FL_CH7_0CONECT_CH7_2CONECT_CH7_1CONECT_CH7_0
$27RL_CH8_RRL_CH8_LFL_CH8_2FL_CH8_1FL_CH8_0CONECT_CH8_2CONECT_CH8_1CONECT_CH8_0
$28TP_CH1_15TP_CH1_14TP_CH1_13TP_CH1_12TP_CH1_11TP_CH1_10TP_CH1_9TP_CH1_8
$29TP_CH2_15TP_CH2_14TP_CH2_13TP_CH2_12TP_CH2_11TP_CH2_10TP_CH2_9TP_CH2_8
$2ATP_CH3_15TP_CH3_14TP_CH3_13TP_CH3_12TP_CH3_11TP_CH3_10TP_CH3_9TP_CH3_8
$2BTP_CH4_15TP_CH4_14TP_CH4_13TP_CH4_12TP_CH4_11TP_CH4_10TP_CH4_9TP_CH4_8
$2CTP_CH5_15TP_CH5_14TP_CH5_13TP_CH5_12TP_CH5_11TP_CH5_10TP_CH5_9TP_CH5_8
$2DTP_CH6_15TP_CH6_14TP_CH6_13TP_CH6_12TP_CH6_11TP_CH6_10TP_CH6_9TP_CH6_8
$2ETP_CH7_15TP_CH7_14TP_CH7_13TP_CH7_12TP_CH7_11TP_CH7_10TP_CH7_9TP_CH7_8
$2FTP_CH8_15TP_CH8_14TP_CH8_13TP_CH8_12TP_CH8_11TP_CH8_10TP_CH8_9TP_CH8_8
$30TP_CH1_7TP_CH1_6TP_CH1_5TP_CH1_4TP_CH1_3TP_CH1_2TP_CH1_1TP_CH1_0
$31TP_CH2_7TP_CH2_6TP_CH2_5TP_CH2_4TP_CH2_3TP_CH2_2TP_CH2_1TP_CH2_0
$32TP_CH3_7TP_CH3_6TP_CH3_5TP_CH3_4TP_CH3_3TP_CH3_2TP_CH3_1TP_CH3_0
$33TP_CH4_7TP_CH4_6TP_CH4_5TP_CH4_4TP_CH4_3TP_CH4_2TP_CH4_1TP_CH4_0
$34TP_CH5_7TP_CH5_6TP_CH5_5TP_CH5_4TP_CH5_3TP_CH5_2TP_CH5_1TP_CH5_0
$35TP_CH6_7TP_CH6_6TP_CH6_5TP_CH6_4TP_CH6_3TP_CH6_2TP_CH6_1TP_CH6_0
$36TP_CH7_7TP_CH7_6TP_CH7_5TP_CH7_4TP_CH7_3TP_CH7_2TP_CH7_1TP_CH7_0
$37TP_CH8_7TP_CH8_6TP_CH8_5TP_CH8_4TP_CH8_3TP_CH8_2TP_CH8_1TP_CH8_0
$38LFRQ2_R1_5LFRQ2_R1_4LFRQ2_R1_3LFRQ2_R1_2LFRQ2_R1_1LFRQ2_R1_0
M_CH2_0
$39LFRQ2_R2_5LFRQ2_R2_4LFRQ2_R2_3LFRQ2_R2_2LFRQ2_R2_1LFRQ2_R2_0
M_CH2_0
$3ALFRQ2_R3_5LFRQ2_R3_4LFRQ2_R3_3LFRQ2_R3_2LFRQ2_R3_1LFRQ2_R3_0
M_CH3_0
$3BLFRQ2_R4_5LFRQ2_R4_4LFRQ2_R4_3LFRQ2_R4_2LFRQ2_R4_1LFRQ2_R4_0
M_CH4_0
$3CLFRQ2_R5_5LFRQ2_R5_4LFRQ2_R5_3LFRQ2_R5_2LFRQ2_R5_1LFRQ2_R5_0
M_CH5_0
$3DLFRQ2_R6_5LFRQ2_R6_4LFRQ2_R6_3LFRQ2_R6_2LFRQ2_R6_1LFRQ2_R6_0
M_CH6_0
$3ELFRQ2_R7_5LFRQ2_R7_4LFRQ2_R7_3LFRQ2_R7_2LFRQ2_R7_1LFRQ2_R7_0
M_CH7_0
$3FLFRQ2_R8_5LFRQ2_R8_4LFRQ2_R8_3LFRQ2_R8_2LFRQ2_R8_1LFRQ2_R8_0
M_CH8_0
$40DT1_SLOT1_2DT1_SLOT1_1DT1_SLOT1_0MUL_SLOT1_3MUL_SLOT1_2MUL_SLOT1_1MUL_SLOT1_0
$41DT1_SLOT2_2DT1_SLOT2_1DT1_SLOT2_0MUL_SLOT2_3MUL_SLOT2_2MUL_SLOT2_1MUL_SLOT2_0
$42DT1_SLOT3_2DT1_SLOT3_1DT1_SLOT3_0MUL_SLOT3_3MUL_SLOT3_2MUL_SLOT3_1MUL_SLOT3_0
$43DT1_SLOT4_2DT1_SLOT4_1DT1_SLOT4_0MUL_SLOT4_3MUL_SLOT4_2MUL_SLOT4_1MUL_SLOT4_0
$44DT1_SLOT5_2DT1_SLOT5_1DT1_SLOT5_0MUL_SLOT5_3MUL_SLOT5_2MUL_SLOT5_1MUL_SLOT5_0
$45DT1_SLOT6_2DT1_SLOT6_1DT1_SLOT6_0MUL_SLOT6_3MUL_SLOT6_2MUL_SLOT6_1MUL_SLOT6_0
$46DT1_SLOT7_2DT1_SLOT7_1DT1_SLOT7_0MUL_SLOT7_3MUL_SLOT7_2MUL_SLOT7_1MUL_SLOT7_0
$47DT1_SLOT8_2DT1_SLOT8_1DT1_SLOT8_0MUL_SLOT8_3MUL_SLOT8_2MUL_SLOT8_1MUL_SLOT8_0
$48DT1_SLOT9_2DT1_SLOT9_1DT1_SLOT9_0MUL_SLOT9_3MUL_SLOT9_2MUL_SLOT9_1MUL_SLOT9_0
$49DT1_SLOT10_2DT1_SLOT10_1DT1_SLOT10_0MUL_SLOT10_3MUL_SLOT10_2MUL_SLOT10_1MUL_SLOT10_0
$4ADT1_SLOT11_2DT1_SLOT11_1DT1_SLOT11_0MUL_SLOT11_3MUL_SLOT11_2MUL_SLOT11_1MUL_SLOT11_0
$4BDT1_SLOT12_2DT1_SLOT12_1DT1_SLOT12_0MUL_SLOT12_3MUL_SLOT12_2MUL_SLOT12_1MUL_SLOT12_0
$4CDT1_SLOT13_2DT1_SLOT13_1DT1_SLOT13_0MUL_SLOT13_3MUL_SLOT13_2MUL_SLOT13_1MUL_SLOT13_0
$4DDT1_SLOT14_2DT1_SLOT14_1DT1_SLOT14_0MUL_SLOT14_3MUL_SLOT14_2MUL_SLOT14_1MUL_SLOT14_0
$4EDT1_SLOT15_2DT1_SLOT15_1DT1_SLOT15_0MUL_SLOT15_3MUL_SLOT15_2MUL_SLOT15_1MUL_SLOT15_0
$4FDT1_SLOT16_2DT1_SLOT16_1DT1_SLOT16_0MUL_SLOT16_3MUL_SLOT16_2MUL_SLOT16_1MUL_SLOT16_0
$50DT1_SLOT17_2DT1_SLOT17_1DT1_SLOT17_0MUL_SLOT17_3MUL_SLOT17_2MUL_SLOT17_1MUL_SLOT17_0
$51DT1_SLOT18_2DT1_SLOT18_1DT1_SLOT18_0MUL_SLOT18_3MUL_SLOT18_2MUL_SLOT18_1MUL_SLOT18_0
$52DT1_SLOT19_2DT1_SLOT19_1DT1_SLOT19_0MUL_SLOT19_3MUL_SLOT19_2MUL_SLOT19_1MUL_SLOT19_0
$53DT1_SLOT20_2DT1_SLOT20_1DT1_SLOT20_0MUL_SLOT20_3MUL_SLOT20_2MUL_SLOT20_1MUL_SLOT20_0
$54DT1_SLOT21_2DT1_SLOT21_1DT1_SLOT21_0MUL_SLOT21_3MUL_SLOT21_2MUL_SLOT21_1MUL_SLOT21_0
$55DT1_SLOT22_2DT1_SLOT22_1DT1_SLOT22_0MUL_SLOT22_3MUL_SLOT22_2MUL_SLOT22_1MUL_SLOT22_0
$56DT1_SLOT23_2DT1_SLOT23_1DT1_SLOT23_0MUL_SLOT23_3MUL_SLOT23_2MUL_SLOT23_1MUL_SLOT23_0
$57DT1_SLOT24_2DT1_SLOT24_1DT1_SLOT24_0MUL_SLOT24_3MUL_SLOT24_2MUL_SLOT24_1MUL_SLOT24_0
$58DT1_SLOT25_2DT1_SLOT25_1DT1_SLOT25_0MUL_SLOT25_3MUL_SLOT25_2MUL_SLOT25_1MUL_SLOT25_0
$59DT1_SLOT26_2DT1_SLOT26_1DT1_SLOT26_0MUL_SLOT26_3MUL_SLOT26_2MUL_SLOT26_1MUL_SLOT26_0
$5ADT1_SLOT27_2DT1_SLOT27_1DT1_SLOT27_0MUL_SLOT27_3MUL_SLOT27_2MUL_SLOT27_1MUL_SLOT27_0
$5BDT1_SLOT28_2DT1_SLOT28_1DT1_SLOT28_0MUL_SLOT28_3MUL_SLOT28_2MUL_SLOT28_1MUL_SLOT28_0
$5CDT1_SLOT29_2DT1_SLOT29_1DT1_SLOT29_0MUL_SLOT29_3MUL_SLOT29_2MUL_SLOT29_1MUL_SLOT29_0
$5DDT1_SLOT30_2DT1_SLOT30_1DT1_SLOT30_0MUL_SLOT30_3MUL_SLOT30_2MUL_SLOT30_1MUL_SLOT30_0
$5EDT1_SLOT31_2DT1_SLOT31_1DT1_SLOT31_0MUL_SLOT31_3MUL_SLOT31_2MUL_SLOT31_1MUL_SLOT31_0
$5FDT1_SLOT32_2DT1_SLOT32_1DT1_SLOT32_0MUL_SLOT32_3MUL_SLOT32_2MUL_SLOT32_1MUL_SLOT32_0
$60TL_SLOT1_6TL_SLOT1_5TL_SLOT1_4TL_SLOT1_3TL_SLOT1_2TL_SLOT1_1TL_SLOT1_0
$61TL_SLOT2_6TL_SLOT2_5TL_SLOT2_4TL_SLOT2_3TL_SLOT2_2TL_SLOT2_1TL_SLOT2_0
$62TL_SLOT3_6TL_SLOT3_5TL_SLOT3_4TL_SLOT3_3TL_SLOT3_2TL_SLOT3_1TL_SLOT3_0
$63TL_SLOT4_6TL_SLOT4_5TL_SLOT4_4TL_SLOT4_3TL_SLOT4_2TL_SLOT4_1TL_SLOT4_0
$64TL_SLOT5_6TL_SLOT5_5TL_SLOT5_4TL_SLOT5_3TL_SLOT5_2TL_SLOT5_1TL_SLOT5_0
$65TL_SLOT6_6TL_SLOT6_5TL_SLOT6_4TL_SLOT6_3TL_SLOT6_2TL_SLOT6_1TL_SLOT6_0
$66TL_SLOT7_6TL_SLOT7_5TL_SLOT7_4TL_SLOT7_3TL_SLOT7_2TL_SLOT7_1TL_SLOT7_0
$67TL_SLOT8_6TL_SLOT8_5TL_SLOT8_4TL_SLOT8_3TL_SLOT8_2TL_SLOT8_1TL_SLOT8_0
$68TL_SLOT9_6TL_SLOT9_5TL_SLOT9_4TL_SLOT9_3TL_SLOT9_2TL_SLOT9_1TL_SLOT9_0
$69TL_SLOT10_6TL_SLOT10_5TL_SLOT10_4TL_SLOT10_3TL_SLOT10_2TL_SLOT10_1TL_SLOT10_0
$6ATL_SLOT11_6TL_SLOT11_5TL_SLOT11_4TL_SLOT11_3TL_SLOT11_2TL_SLOT11_1TL_SLOT11_0
$6BTL_SLOT12_6TL_SLOT12_5TL_SLOT12_4TL_SLOT12_3TL_SLOT12_2TL_SLOT12_1TL_SLOT12_0
$6CTL_SLOT13_6TL_SLOT13_5TL_SLOT13_4TL_SLOT13_3TL_SLOT13_2TL_SLOT13_1TL_SLOT13_0
$6DTL_SLOT14_6TL_SLOT14_5TL_SLOT14_4TL_SLOT14_3TL_SLOT14_2TL_SLOT14_1TL_SLOT14_0
$6ETL_SLOT15_6TL_SLOT15_5TL_SLOT15_4TL_SLOT15_3TL_SLOT15_2TL_SLOT15_1TL_SLOT15_0
$6FTL_SLOT16_6TL_SLOT16_5TL_SLOT16_4TL_SLOT16_3TL_SLOT16_2TL_SLOT16_1TL_SLOT16_0
$70TL_SLOT17_6TL_SLOT17_5TL_SLOT17_4TL_SLOT17_3TL_SLOT17_2TL_SLOT17_1TL_SLOT17_0
$71TL_SLOT18_6TL_SLOT18_5TL_SLOT18_4TL_SLOT18_3TL_SLOT18_2TL_SLOT18_1TL_SLOT18_0
$72TL_SLOT19_6TL_SLOT19_5TL_SLOT19_4TL_SLOT19_3TL_SLOT19_2TL_SLOT19_1TL_SLOT19_0
$73TL_SLOT20_6TL_SLOT20_5TL_SLOT20_4TL_SLOT20_3TL_SLOT20_2TL_SLOT20_1TL_SLOT20_0
$74TL_SLOT21_6TL_SLOT21_5TL_SLOT21_4TL_SLOT21_3TL_SLOT21_2TL_SLOT21_1TL_SLOT21_0
$75TL_SLOT22_6TL_SLOT22_5TL_SLOT22_4TL_SLOT22_3TL_SLOT22_2TL_SLOT22_1TL_SLOT22_0
$76TL_SLOT23_6TL_SLOT23_5TL_SLOT23_4TL_SLOT23_3TL_SLOT23_2TL_SLOT23_1TL_SLOT23_0
$77TL_SLOT24_6TL_SLOT24_5TL_SLOT24_4TL_SLOT24_3TL_SLOT24_2TL_SLOT24_1TL_SLOT24_0
$78TL_SLOT25_6TL_SLOT25_5TL_SLOT25_4TL_SLOT25_3TL_SLOT25_2TL_SLOT25_1TL_SLOT25_0
$79TL_SLOT26_6TL_SLOT26_5TL_SLOT26_4TL_SLOT26_3TL_SLOT26_2TL_SLOT26_1TL_SLOT26_0
$7ATL_SLOT27_6TL_SLOT27_5TL_SLOT27_4TL_SLOT27_3TL_SLOT27_2TL_SLOT27_1TL_SLOT27_0
$7BTL_SLOT28_6TL_SLOT28_5TL_SLOT28_4TL_SLOT28_3TL_SLOT28_2TL_SLOT28_1TL_SLOT28_0
$7CTL_SLOT29_6TL_SLOT29_5TL_SLOT29_4TL_SLOT29_3TL_SLOT29_2TL_SLOT29_1TL_SLOT29_0
$7DTL_SLOT30_6TL_SLOT30_5TL_SLOT30_4TL_SLOT30_3TL_SLOT30_2TL_SLOT30_1TL_SLOT30_0
$7ETL_SLOT31_6TL_SLOT31_5TL_SLOT31_4TL_SLOT31_3TL_SLOT31_2TL_SLOT31_1TL_SLOT31_0
$7FTL_SLOT32_6TL_SLOT32_5TL_SLOT32_4TL_SLOT32_3TL_SLOT32_2TL_SLOT32_1TL_SLOT32_0
$80KS_SLOT1_1KS_SLOT1_0AR_SLOT1_4AR_SLOT1_3AR_SLOT1_2AR_SLOT1_1AR_SLOT1_0
$81KS_SLOT2_1KS_SLOT2_0AR_SLOT2_4AR_SLOT2_3AR_SLOT2_2AR_SLOT2_1AR_SLOT2_0
$82KS_SLOT3_1KS_SLOT3_0AR_SLOT3_4AR_SLOT3_3AR_SLOT3_2AR_SLOT3_1AR_SLOT3_0
$83KS_SLOT4_1KS_SLOT4_0AR_SLOT4_4AR_SLOT4_3AR_SLOT4_2AR_SLOT4_1AR_SLOT4_0
$84KS_SLOT5_1KS_SLOT5_0AR_SLOT5_4AR_SLOT5_3AR_SLOT5_2AR_SLOT5_1AR_SLOT5_0
$85KS_SLOT6_1KS_SLOT6_0AR_SLOT6_4AR_SLOT6_3AR_SLOT6_2AR_SLOT6_1AR_SLOT6_0
$86KS_SLOT7_1KS_SLOT7_0AR_SLOT7_4AR_SLOT7_3AR_SLOT7_2AR_SLOT7_1AR_SLOT7_0
$87KS_SLOT8_1KS_SLOT8_0AR_SLOT8_4AR_SLOT8_3AR_SLOT8_2AR_SLOT8_1AR_SLOT8_0
$88KS_SLOT9_1KS_SLOT9_0AR_SLOT9_4AR_SLOT9_3AR_SLOT9_2AR_SLOT9_1AR_SLOT9_0
$89KS_SLOT10_1KS_SLOT10_0AR_SLOT10_4AR_SLOT10_3AR_SLOT10_2AR_SLOT10_1AR_SLOT10_0
$8AKS_SLOT11_1KS_SLOT11_0AR_SLOT11_4AR_SLOT11_3AR_SLOT11_2AR_SLOT11_1AR_SLOT11_0
$8BKS_SLOT12_1KS_SLOT12_0AR_SLOT12_4AR_SLOT12_3AR_SLOT12_2AR_SLOT12_1AR_SLOT12_0
$8CKS_SLOT13_1KS_SLOT13_0AR_SLOT13_4AR_SLOT13_3AR_SLOT13_2AR_SLOT13_1AR_SLOT13_0
$8DKS_SLOT14_1KS_SLOT14_0AR_SLOT14_4AR_SLOT14_3AR_SLOT14_2AR_SLOT14_1AR_SLOT14_0
$8EKS_SLOT15_1KS_SLOT15_0AR_SLOT15_4AR_SLOT15_3AR_SLOT15_2AR_SLOT15_1AR_SLOT15_0
$8FKS_SLOT16_1KS_SLOT16_0AR_SLOT16_4AR_SLOT16_3AR_SLOT16_2AR_SLOT16_1AR_SLOT16_0
$90KS_SLOT17_1KS_SLOT17_0AR_SLOT17_4AR_SLOT17_3AR_SLOT17_2AR_SLOT17_1AR_SLOT17_0
$91KS_SLOT18_1KS_SLOT18_0AR_SLOT18_4AR_SLOT18_3AR_SLOT18_2AR_SLOT18_1AR_SLOT18_0
$92KS_SLOT19_1KS_SLOT19_0AR_SLOT19_4AR_SLOT19_3AR_SLOT19_2AR_SLOT19_1AR_SLOT19_0
$93KS_SLOT20_1KS_SLOT20_0AR_SLOT20_4AR_SLOT20_3AR_SLOT20_2AR_SLOT20_1AR_SLOT20_0
$94KS_SLOT21_1KS_SLOT21_0AR_SLOT21_4AR_SLOT21_3AR_SLOT21_2AR_SLOT21_1AR_SLOT21_0
$95KS_SLOT22_1KS_SLOT22_0AR_SLOT22_4AR_SLOT22_3AR_SLOT22_2AR_SLOT22_1AR_SLOT22_0
$96KS_SLOT23_1KS_SLOT23_0AR_SLOT23_4AR_SLOT23_3AR_SLOT23_2AR_SLOT23_1AR_SLOT23_0
$97KS_SLOT24_1KS_SLOT24_0AR_SLOT24_4AR_SLOT24_3AR_SLOT24_2AR_SLOT24_1AR_SLOT24_0
$98KS_SLOT25_1KS_SLOT25_0AR_SLOT25_4AR_SLOT25_3AR_SLOT25_2AR_SLOT25_1AR_SLOT25_0
$99KS_SLOT26_1KS_SLOT26_0AR_SLOT26_4AR_SLOT26_3AR_SLOT26_2AR_SLOT26_1AR_SLOT26_0
$9AKS_SLOT27_1KS_SLOT27_0AR_SLOT27_4AR_SLOT27_3AR_SLOT27_2AR_SLOT27_1AR_SLOT27_0
$9BKS_SLOT28_1KS_SLOT28_0AR_SLOT28_4AR_SLOT28_3AR_SLOT28_2AR_SLOT28_1AR_SLOT28_0
$9CKS_SLOT29_1KS_SLOT29_0AR_SLOT29_4AR_SLOT29_3AR_SLOT29_2AR_SLOT29_1AR_SLOT29_0
$9DKS_SLOT30_1KS_SLOT30_0AR_SLOT30_4AR_SLOT30_3AR_SLOT30_2AR_SLOT30_1AR_SLOT30_0
$9EKS_SLOT31_1KS_SLOT31_0AR_SLOT31_4AR_SLOT31_3AR_SLOT31_2AR_SLOT31_1AR_SLOT31_0
$9FKS_SLOT32_1KS_SLOT32_0AR_SLOT32_4AR_SLOT32_3AR_SLOT32_2AR_SLOT32_1AR_SLOT32_0
$A0   D1R_SLOT1_4D1R_SLOT1_3D1R_SLOT1_2D1R_SLOT1_1D1R_SLOT1_0
$A1   D1R_SLOT2_4D1R_SLOT2_3D1R_SLOT2_2D1R_SLOT2_1D1R_SLOT2_0
$A2   D1R_SLOT3_4D1R_SLOT3_3D1R_SLOT3_2D1R_SLOT3_1D1R_SLOT3_0
$A3   D1R_SLOT4_4D1R_SLOT4_3D1R_SLOT4_2D1R_SLOT4_1D1R_SLOT4_0
$A4   D1R_SLOT5_4D1R_SLOT5_3D1R_SLOT5_2D1R_SLOT5_1D1R_SLOT5_0
$A5   D1R_SLOT6_4D1R_SLOT6_3D1R_SLOT6_2D1R_SLOT6_1D1R_SLOT6_0
$A6   D1R_SLOT7_4D1R_SLOT7_3D1R_SLOT7_2D1R_SLOT7_1D1R_SLOT7_0
$A7   D1R_SLOT8_4D1R_SLOT8_3D1R_SLOT8_2D1R_SLOT8_1D1R_SLOT8_0
$A8   D1R_SLOT9_4D1R_SLOT9_3D1R_SLOT9_2D1R_SLOT9_1D1R_SLOT9_0
$A9   D1R_SLOT10_4D1R_SLOT10_3D1R_SLOT10_2D1R_SLOT10_1D1R_SLOT10_0
$AA   D1R_SLOT11_4D1R_SLOT11_3D1R_SLOT11_2D1R_SLOT11_1D1R_SLOT11_0
$AB   D1R_SLOT12_4D1R_SLOT12_3D1R_SLOT12_2D1R_SLOT12_1D1R_SLOT12_0
$AC   D1R_SLOT13_4D1R_SLOT13_3D1R_SLOT13_2D1R_SLOT13_1D1R_SLOT13_0
$AD   D1R_SLOT14_4D1R_SLOT14_3D1R_SLOT14_2D1R_SLOT14_1D1R_SLOT14_0
$AE   D1R_SLOT15_4D1R_SLOT15_3D1R_SLOT15_2D1R_SLOT15_1D1R_SLOT15_0
$AF   D1R_SLOT16_4D1R_SLOT16_3D1R_SLOT16_2D1R_SLOT16_1D1R_SLOT16_0
$B0   D1R_SLOT17_4D1R_SLOT17_3D1R_SLOT17_2D1R_SLOT17_1D1R_SLOT17_0
$B1   D1R_SLOT18_4D1R_SLOT18_3D1R_SLOT18_2D1R_SLOT18_1D1R_SLOT18_0
$B2   D1R_SLOT19_4D1R_SLOT19_3D1R_SLOT19_2D1R_SLOT19_1D1R_SLOT19_0
$B3   D1R_SLOT20_4D1R_SLOT20_3D1R_SLOT20_2D1R_SLOT20_1D1R_SLOT20_0
$B4   D1R_SLOT21_4D1R_SLOT21_3D1R_SLOT21_2D1R_SLOT21_1D1R_SLOT21_0
$B5   D1R_SLOT22_4D1R_SLOT22_3D1R_SLOT22_2D1R_SLOT22_1D1R_SLOT22_0
$B6   D1R_SLOT23_4D1R_SLOT23_3D1R_SLOT23_2D1R_SLOT23_1D1R_SLOT23_0
$B7   D1R_SLOT24_4D1R_SLOT24_3D1R_SLOT24_2D1R_SLOT24_1D1R_SLOT24_0
$B8   D1R_SLOT25_4D1R_SLOT25_3D1R_SLOT25_2D1R_SLOT25_1D1R_SLOT25_0
$B9   D1R_SLOT26_4D1R_SLOT26_3D1R_SLOT26_2D1R_SLOT26_1D1R_SLOT26_0
$BA   D1R_SLOT27_4D1R_SLOT27_3D1R_SLOT27_2D1R_SLOT27_1D1R_SLOT27_0
$BB   D1R_SLOT28_4D1R_SLOT28_3D1R_SLOT28_2D1R_SLOT28_1D1R_SLOT28_0
$BC   D1R_SLOT29_4D1R_SLOT29_3D1R_SLOT29_2D1R_SLOT29_1D1R_SLOT29_0
$BD   D1R_SLOT30_4D1R_SLOT30_3D1R_SLOT30_2D1R_SLOT30_1D1R_SLOT30_0
$BE   D1R_SLOT31_4D1R_SLOT31_3D1R_SLOT31_2D1R_SLOT31_1D1R_SLOT31_0
$BF   D1R_SLOT32_4D1R_SLOT32_3D1R_SLOT32_2D1R_SLOT32_1D1R_SLOT32_0
$C0AMS_SLOT1_1AMS_SLOT1_0D2R_SLOT1_4D2R_SLOT1_3D2R_SLOT1_2D2R_SLOT1_1D2R_SLOT1_0
$C1AMS_SLOT2_1AMS_SLOT2_0D2R_SLOT2_4D2R_SLOT2_3D2R_SLOT2_2D2R_SLOT2_1D2R_SLOT2_0
$C2AMS_SLOT3_1AMS_SLOT3_0D2R_SLOT3_4D2R_SLOT3_3D2R_SLOT3_2D2R_SLOT3_1D2R_SLOT3_0
$C3AMS_SLOT4_1AMS_SLOT4_0D2R_SLOT4_4D2R_SLOT4_3D2R_SLOT4_2D2R_SLOT4_1D2R_SLOT4_0
$C4AMS_SLOT5_1AMS_SLOT5_0D2R_SLOT5_4D2R_SLOT5_3D2R_SLOT5_2D2R_SLOT5_1D2R_SLOT5_0
$C5AMS_SLOT6_1AMS_SLOT6_0D2R_SLOT6_4D2R_SLOT6_3D2R_SLOT6_2D2R_SLOT6_1D2R_SLOT6_0
$C6AMS_SLOT7_1AMS_SLOT7_0D2R_SLOT7_4D2R_SLOT7_3D2R_SLOT7_2D2R_SLOT7_1D2R_SLOT7_0
$C7AMS_SLOT8_1AMS_SLOT8_0D2R_SLOT8_4D2R_SLOT8_3D2R_SLOT8_2D2R_SLOT8_1D2R_SLOT8_0
$C8AMS_SLOT9_1AMS_SLOT9_0D2R_SLOT9_4D2R_SLOT9_3D2R_SLOT9_2D2R_SLOT9_1D2R_SLOT9_0
$C9AMS_SLOT10_1AMS_SLOT10_0D2R_SLOT10_4D2R_SLOT10_3D2R_SLOT10_2D2R_SLOT10_1D2R_SLOT10_0
$CAAMS_SLOT11_1AMS_SLOT11_0D2R_SLOT11_4D2R_SLOT11_3D2R_SLOT11_2D2R_SLOT11_1D2R_SLOT11_0
$CBAMS_SLOT12_1AMS_SLOT12_0D2R_SLOT12_4D2R_SLOT12_3D2R_SLOT12_2D2R_SLOT12_1D2R_SLOT12_0
$CCAMS_SLOT13_1AMS_SLOT13_0D2R_SLOT13_4D2R_SLOT13_3D2R_SLOT13_2D2R_SLOT13_1D2R_SLOT13_0
$CDAMS_SLOT14_1AMS_SLOT14_0D2R_SLOT14_4D2R_SLOT14_3D2R_SLOT14_2D2R_SLOT14_1D2R_SLOT14_0
$CEAMS_SLOT15_1AMS_SLOT15_0D2R_SLOT15_4D2R_SLOT15_3D2R_SLOT15_2D2R_SLOT15_1D2R_SLOT15_0
$CFAMS_SLOT16_1AMS_SLOT16_0D2R_SLOT16_4D2R_SLOT16_3D2R_SLOT16_2D2R_SLOT16_1D2R_SLOT16_0
$D0AMS_SLOT17_1AMS_SLOT17_0D2R_SLOT17_4D2R_SLOT17_3D2R_SLOT17_2D2R_SLOT17_1D2R_SLOT17_0
$D1AMS_SLOT18_1AMS_SLOT18_0D2R_SLOT18_4D2R_SLOT18_3D2R_SLOT18_2D2R_SLOT18_1D2R_SLOT18_0
$D2AMS_SLOT19_1AMS_SLOT19_0D2R_SLOT19_4D2R_SLOT19_3D2R_SLOT19_2D2R_SLOT19_1D2R_SLOT19_0
$D3AMS_SLOT20_1AMS_SLOT20_0D2R_SLOT20_4D2R_SLOT20_3D2R_SLOT20_2D2R_SLOT20_1D2R_SLOT20_0
$D4AMS_SLOT21_1AMS_SLOT21_0D2R_SLOT21_4D2R_SLOT21_3D2R_SLOT21_2D2R_SLOT21_1D2R_SLOT21_0
$D5AMS_SLOT22_1AMS_SLOT22_0D2R_SLOT22_4D2R_SLOT22_3D2R_SLOT22_2D2R_SLOT22_1D2R_SLOT22_0
$D6AMS_SLOT23_1AMS_SLOT23_0D2R_SLOT23_4D2R_SLOT23_3D2R_SLOT23_2D2R_SLOT23_1D2R_SLOT23_0
$D7AMS_SLOT24_1AMS_SLOT24_0D2R_SLOT24_4D2R_SLOT24_3D2R_SLOT24_2D2R_SLOT24_1D2R_SLOT24_0
$D8AMS_SLOT25_1AMS_SLOT25_0D2R_SLOT25_4D2R_SLOT25_3D2R_SLOT25_2D2R_SLOT25_1D2R_SLOT25_0
$D9AMS_SLOT26_1AMS_SLOT26_0D2R_SLOT26_4D2R_SLOT26_3D2R_SLOT26_2D2R_SLOT26_1D2R_SLOT26_0
$DAAMS_SLOT27_1AMS_SLOT27_0D2R_SLOT27_4D2R_SLOT27_3D2R_SLOT27_2D2R_SLOT27_1D2R_SLOT27_0
$DBAMS_SLOT28_1AMS_SLOT28_0D2R_SLOT28_4D2R_SLOT28_3D2R_SLOT28_2D2R_SLOT28_1D2R_SLOT28_0
$DCAMS_SLOT29_1AMS_SLOT29_0D2R_SLOT29_4D2R_SLOT29_3D2R_SLOT29_2D2R_SLOT29_1D2R_SLOT29_0
$DDAMS_SLOT30_1AMS_SLOT30_0D2R_SLOT30_4D2R_SLOT30_3D2R_SLOT30_2D2R_SLOT30_1D2R_SLOT30_0
$DEAMS_SLOT31_1AMS_SLOT31_0D2R_SLOT31_4D2R_SLOT31_3D2R_SLOT31_2D2R_SLOT31_1D2R_SLOT31_0
$DFAMS_SLOT32_1AMS_SLOT32_0D2R_SLOT32_4D2R_SLOT32_3D2R_SLOT32_2D2R_SLOT32_1D2R_SLOT32_0
$E0D1L_SLOT1_3D1L_SLOT1_2D1L_SLOT1_1D1L_SLOT1_0RR_SLOT1_3RR_SLOT1_2RR_SLOT1_1RR_SLOT1_0
$E1D1L_SLOT2_3D1L_SLOT2_2D1L_SLOT2_1D1L_SLOT2_0RR_SLOT2_3RR_SLOT2_2RR_SLOT2_1RR_SLOT2_0
$E2D1L_SLOT3_3D1L_SLOT3_2D1L_SLOT3_1D1L_SLOT3_0RR_SLOT3_3RR_SLOT3_2RR_SLOT3_1RR_SLOT3_0
$E3D1L_SLOT4_3D1L_SLOT4_2D1L_SLOT4_1D1L_SLOT4_0RR_SLOT4_3RR_SLOT4_2RR_SLOT4_1RR_SLOT4_0
$E4D1L_SLOT5_3D1L_SLOT5_2D1L_SLOT5_1D1L_SLOT5_0RR_SLOT5_3RR_SLOT5_2RR_SLOT5_1RR_SLOT5_0
$E5D1L_SLOT6_3D1L_SLOT6_2D1L_SLOT6_1D1L_SLOT6_0RR_SLOT6_3RR_SLOT6_2RR_SLOT6_1RR_SLOT6_0
$E6D1L_SLOT7_3D1L_SLOT7_2D1L_SLOT7_1D1L_SLOT7_0RR_SLOT7_3RR_SLOT7_2RR_SLOT7_1RR_SLOT7_0
$E7D1L_SLOT8_3D1L_SLOT8_2D1L_SLOT8_1D1L_SLOT8_0RR_SLOT8_3RR_SLOT8_2RR_SLOT8_1RR_SLOT8_0
$E8D1L_SLOT9_3D1L_SLOT9_2D1L_SLOT9_1D1L_SLOT9_0RR_SLOT9_3RR_SLOT9_2RR_SLOT9_1RR_SLOT9_0
$E9D1L_SLOT10_3D1L_SLOT10_2D1L_SLOT10_1D1L_SLOT10_0RR_SLOT10_3RR_SLOT10_2RR_SLOT10_1RR_SLOT10_0
$EAD1L_SLOT11_3D1L_SLOT11_2D1L_SLOT11_1D1L_SLOT11_0RR_SLOT11_3RR_SLOT11_2RR_SLOT11_1RR_SLOT11_0
$EBD1L_SLOT12_3D1L_SLOT12_2D1L_SLOT12_1D1L_SLOT12_0RR_SLOT12_3RR_SLOT12_2RR_SLOT12_1RR_SLOT12_0
$ECD1L_SLOT13_3D1L_SLOT13_2D1L_SLOT13_1D1L_SLOT13_0RR_SLOT13_3RR_SLOT13_2RR_SLOT13_1RR_SLOT13_0
$EDD1L_SLOT14_3D1L_SLOT14_2D1L_SLOT14_1D1L_SLOT14_0RR_SLOT14_3RR_SLOT14_2RR_SLOT14_1RR_SLOT14_0
$EED1L_SLOT15_3D1L_SLOT15_2D1L_SLOT15_1D1L_SLOT15_0RR_SLOT15_3RR_SLOT15_2RR_SLOT15_1RR_SLOT15_0
$EFD1L_SLOT16_3D1L_SLOT16_2D1L_SLOT16_1D1L_SLOT16_0RR_SLOT16_3RR_SLOT16_2RR_SLOT16_1RR_SLOT16_0
$F0D1L_SLOT17_3D1L_SLOT17_2D1L_SLOT17_1D1L_SLOT17_0RR_SLOT17_3RR_SLOT17_2RR_SLOT17_1RR_SLOT17_0
$F1D1L_SLOT18_3D1L_SLOT18_2D1L_SLOT18_1D1L_SLOT18_0RR_SLOT18_3RR_SLOT18_2RR_SLOT18_1RR_SLOT18_0
$F2D1L_SLOT19_3D1L_SLOT19_2D1L_SLOT19_1D1L_SLOT19_0RR_SLOT19_3RR_SLOT19_2RR_SLOT19_1RR_SLOT19_0
$F3D1L_SLOT20_3D1L_SLOT20_2D1L_SLOT20_1D1L_SLOT20_0RR_SLOT20_3RR_SLOT20_2RR_SLOT20_1RR_SLOT20_0
$F4D1L_SLOT21_3D1L_SLOT21_2D1L_SLOT21_1D1L_SLOT21_0RR_SLOT21_3RR_SLOT21_2RR_SLOT21_1RR_SLOT21_0
$F5D1L_SLOT22_3D1L_SLOT22_2D1L_SLOT22_1D1L_SLOT22_0RR_SLOT22_3RR_SLOT22_2RR_SLOT22_1RR_SLOT22_0
$F6D1L_SLOT23_3D1L_SLOT23_2D1L_SLOT23_1D1L_SLOT23_0RR_SLOT23_3RR_SLOT23_2RR_SLOT23_1RR_SLOT23_0
$F7D1L_SLOT24_3D1L_SLOT24_2D1L_SLOT24_1D1L_SLOT24_0RR_SLOT24_3RR_SLOT24_2RR_SLOT24_1RR_SLOT24_0
$F8D1L_SLOT25_3D1L_SLOT25_2D1L_SLOT25_1D1L_SLOT25_0RR_SLOT25_3RR_SLOT25_2RR_SLOT25_1RR_SLOT25_0
$F9D1L_SLOT26_3D1L_SLOT26_2D1L_SLOT26_1D1L_SLOT26_0RR_SLOT26_3RR_SLOT26_2RR_SLOT26_1RR_SLOT26_0
$FAD1L_SLOT27_3D1L_SLOT27_2D1L_SLOT27_1D1L_SLOT27_0RR_SLOT27_3RR_SLOT27_2RR_SLOT27_1RR_SLOT27_0
$FBD1L_SLOT28_3D1L_SLOT28_2D1L_SLOT28_1D1L_SLOT28_0RR_SLOT28_3RR_SLOT28_2RR_SLOT28_1RR_SLOT28_0
$FCD1L_SLOT29_3D1L_SLOT29_2D1L_SLOT29_1D1L_SLOT29_0RR_SLOT29_3RR_SLOT29_2RR_SLOT29_1RR_SLOT29_0
$FDD1L_SLOT30_3D1L_SLOT30_2D1L_SLOT30_1D1L_SLOT30_0RR_SLOT30_3RR_SLOT30_2RR_SLOT30_1RR_SLOT30_0
$FED1L_SLOT31_3D1L_SLOT31_2D1L_SLOT31_1D1L_SLOT31_0RR_SLOT31_3RR_SLOT31_2RR_SLOT31_1RR_SLOT31_0
$FFD1L_SLOT32_3D1L_SLOT32_2D1L_SLOT32_1D1L_SLOT32_0RR_SLOT32_3RR_SLOT32_2RR_SLOT32_1RR_SLOT32_0


・YMF709-Dのレジスタ(読み取り専用)

YMF709-Dは内部に1バイトの読み取り専用レジスタを持っています。
セットしたアドレスによらず、YMF709-Dのステータス情報を返します。
(テストモードの機能で内部レジスタのデータを読み取ることもできるようです。)

bit7
bit6
bit5
bit4
bit3
bit2
bit1
bit0
B-----IST_BIST_B


B:
WRITE BUSY FLAG
ライトビジーフラグです。
このフラグがHの時にYMF709-Dのレジスタへ値を書き込むことは禁止されています。

B -> H : データ書き込み中のため、YMF709-Dへのライトアクセスは禁止
B -> L : YMF709-Dへのライトアクセス可能


IST: (未検証)
タイマーオーバーフローステータスフラグです。
このフラグがHの時、YMF709-Dの内部タイマーのオーバーフローフラグが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)
CH1SLOT1SLOT9SLOT17SLOT25
CH2SLOT2SLOT10SLOT18SLOT26
CH3SLOT3SLOT11SLOT19SLOT27
CH4SLOT4SLOT12SLOT20SLOT28
CH5SLOT5SLOT13SLOT21SLOT29
CH6SLOT6SLOT14SLOT22SLOT30
CH7SLOT7SLOT15SLOT23SLOT31
CH8SLOT8SLOT16SLOT24SLOT32


・タイミング図

YMF709-Dのデータシートは入手できないため、制御タイミングの仕様がわかりません。
ただ、YM2151と同じ方法でレジスタの読み書き出来ました。
YM2151のレジスタ読み書き手順については以下を参照してください。




・使い方(制御)



YMF709-Dの発音手順のほとんどはYM2151と同様なので、異なる部分だけ手順を示します。


「②音程設定レジスタに音程をセットする。」


YM2151ではキーコードレジスタどキーフラクション(音程の微調整)レジスタに分けて音程を指定しています。
この方式では、オクターブとノートナンバー(C,C#,…,A#,B)から直接レジスタ値を求めることができるため、マイコン側の除算や乗算などの演算コストを減らすことができます。

ただし、周波数からレジスタ値を求める場合、オクターブとノートナンバーとキーフラクション値の3つを求めなければならず、むしろ演算コストが大きくなります。


ハーモニーディレクタは楽器のチューニングなどでも使えるように、音階ごとに周波数を細かく設定出来る特徴があります。
周波数から先ほどの3つの値を求めるのは合理的では無いため、YMF709-Dの場合は周波数からレジスタ値を簡単に求められるような仕様となっています。
具体的みてみると、YMF709-Dは17bit値の音程レジスタがあり、周波数と定数を乗算するだけで求めることができます。

YMF709-Dの音程レジスタは17bit値なのですが、
このLSBを「MICRO TUNE」と呼ぶことにしました。
これは、YM2414(OPZ)の$30~$37にあるMICRO TUNEビットと似ている気がするためです。

残りの16bit分は「TONE PERIOD」と呼んでいますが、SSG音源(PSG)のTPを由来としています。
ただし、SSGの場合はレジスタ値が小さいほど高い音程となりますが、
YMF709-Dの場合はレジスタ値が大きいほど高い音程となることに注意してください。


・TP_H($2X : bit0~7)    (X = 8~F : チャンネル1~8)
    チャンネル1~8の音程設定レジスタbit15~8

・TP_L($3X : bit0~7)    (X = 0~7 : チャンネル1~8)
    チャンネル1~8の音程設定レジスタbit7~0

・M($3X : bit0)    (X = 8~F : チャンネル1~8)
    チャンネル1~8のマイクロチューンレジスタ


--MIDIノートナンバーからレジスタ値を求める場合--
   (TP << 1) | M = (440 / (2 ^ (69/12))) * (2 ^ (note_n/12)) * (2^27) / ΦM
      = 8.175799 * (2 ^ (note_n/12)) * (2^27) / ΦM

note_n : MIDIノートナンバ(0~127、note_n=69のときfout=440)
ΦM : 入力クロック周波数[Hz]


   [入力クロックΦM = 3.579545MHzの場合]

  (TP << 1) | M = 8.175799 * (2 ^ (note/12)) * (2^27) / (3.579545 * 10^6)
      = 306.5577235 * (2 ^ (note/12))

上記式からわかるようにMIDIノートナンバーから求める場合、定数の乗算だけでは求められません。
306.5577235 * (2 ^ (note/12))のテーブルを用意すると楽にYMF709-Dへ音程をセットできます。


----YMF709-Dのパラメータについて----

YMF709-Dの音色パラメータのほとんどはYM2151にもあります。
そのため、YM2151のシミュレータであるVOPMexでYMF709-Dの音色のほとんどを再現
することができます。


YMF709-DはDT2とPMSが無いと思われるため、
VOPMexでYMF709-Dの音色を再現する場合、次のパラメータを0に固定にします。

・DT2
・PMS

ほかにもAMSの仕様に違いがあります。
YM2151はAMSをチャンネルごとに設定するのに対し、YMF709-DのAMSはオペレータごとに設定しなければいけません。

検証していませんが、YMF709-Dの4つあるオペレータのAMSを共通化すると良いかもしれません。
ただし、YM2151はオペレータごとにAMSの有無を設定できる「AMS_EN」があるので、AMS_ENがOFFの場合はYMF709-DのAMSを0にしなければいけません。

YMF709-Dの$38~$3Fのbit7~bit1の仕様はまだ分かっていないため、常にLとすることをおすすめします。


・使い方(回路)


YMF709-Dのデータシートは入手できないため、電気的仕様はわかりません。

電源電圧や部品定数は、YMF709-Dが使用されているYAMAHA HD-81とYAMAHA HD-100の回路を参考にすると良さそうです。
YAMAHA HD-81の音源周りの回路図



YAMAHA HD-100の音源周りの回路図

細かいとことに違いがありますが、基本的にYM2151と同様の回路のようです。
YM2151のDAC周りの回路と同様なもので発音させることができます。
YM2151の回路については以下を参照してください。



・クロック

HD-81とHD-100ではYMF709-Dに入力するクロック周波数に違いがあります。
HD-81は3.5MHz、HD-100は3.83616MHzのクロックを使用しているようです。

YM2151の場合、最大で4MHzのクロック入力が可能であり、
YMF709-Dも最大クロック周波数が4MHzの可能性が高いです。



・DAC回り

DACはYM2151でおなじみのYM3012を使用しています。
データフォーマットが特殊なので、市販のDACを使用したい場合は別途変換回路が必要です。

HD-81の場合、「SH2」端子間に抵抗とコンデンサによる遅延回路を入れているようです。
HD-100の場合は入れていないので、クロックの周波数が関係しているかもしれません。


・使用例  - MIDIの受信 -


YMF709-Dを1個使用してMIDIを受信する場合の回路とプログラム(Arduino ATmega328p用)を紹介します。


この回路ではYM2151としていますが、YMF709-Dにそのまま置き換えて使うことができます。



音色パラメータはエクスクルーシブメッセージで送信できます。
パラメータ構造はYAMAHA VCEDフォーマットに近いですが、いくつか異なる部分があるので、
詳細はプログラム内のコメントを参照してください。


プログラムチェンジ(登録先)→「Program Change parameter Change」→「VCED parameter Change」または「VCED Bulk Dump」→プログラムチェンジ(登録先)
の順で送信することで、プログラムナンバーとOPMパラメータが結び付けられ、該当チャンネルの音色が反映されます。
別のチャンネルにも同じ音を割り当てたい時は、プログラムチェンジを該当チャンネルで行うことで音色が反映されます。

ただし、パーカッションチャンネル(ch10)のみVCEDナンバーの上位7bitが#define DRUM_VCED、
下位7bitがノートオン時のノートナンバーで指定された音色がキーオン時に登録され、発音します。
(プログラム例ではDRUM_VCED=0x08としています。)




↑OPM系で使用できる音色パラメータ付きMIDIのサンプルです。
音色パラメータの送信&反映手順の参考として用意しておきます。
YMF709-Dの場合、一部パラメータが異なります。

※2024_10_28:軽微な不具合を修正しました。対応するMIDIファイルも要修正(VCEDバルク入力のデータがずれていた問題を修正)

↓以前のバージョンはこちら

・プログラム

// YMF709-DでMIDI演奏プログラム_Ver.1.1
// ©oy
// https://oykenkyu.blogspot.com/2023/06/ymf709-d.html

// HardwareSerial.h内の「SERIAL_RX_BUFFER_SIZE」を64から256へ変更してください。「SERIAL_TX_BUFFER_SIZE」は変更しなくてよいです。

#include "avr/io.h"
#include "avr/interrupt.h"
#include <avr/pgmspace.h>

 #define SERIALSPEED 31250 // UARTのボーレート(MIDIのボーレートは31250bps)
//#define SERIALSPEED 38400 // UARTのボーレート(デバッグ用)
#define XTAL 16000000     // 水晶振動子の周波数
// #define XTAL 24576000 //水晶振動子の周波数(ドラムパートでもたつく場合に有効です。ATmega328pによっては動作しない場合があります。)

#define YMF709_N 1 // YMF709の個数(ATmega328の場合SRAMの関係上最大1つ  SRAMがより多いマイコンを推奨  ただし、setupとymf709_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          // YMF709最大チャンネル数(YMF709は1つで8チャンネル分発音できます。)
#define MIDI_MAX_TR CH // MIDIトラック数

#define FM_DRUM_CH 7 // 音源内のドラムチャンネル

// YMF709オペレータ名と順番(レジスタ配置順と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


// YMF709オペレータ名(アドレス計算用)
#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


// YMF709レジスタ
#define TEST 0x01      // テストレジスタ
#define LFO_RESET 0x02 // テストレジスタ_LFOリセット

#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 CT1 0x80   // 汎用端子出力ビット・LFO変調波形設定レジスタ_汎用出力ポートCT1への出力値
#define CT2 0x40   // 汎用端子出力ビット・LFO変調波形設定レジスタ_汎用出力ポートCT2への出力値
#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   // 音程設定レジスタ(YM2151用)
//#define OCT 0x70  // 音程設定レジスタ_オクターブ設定(YM2151用)
//#define NOTE 0x0F // 音程設定レジスタ_ノート設定(YM2151用)
//#define KF 0x30    // キーフラクションレジスタ
//#define KF_KF 0xFC // キーフラクションレジスタ設定
#define TP_H 0x28 // 音程設定レジスタ上位
#define TP_L 0x30 // 音程設定レジスタ下位

//#define PMS_AMS 0x38 // LFO振幅変調感度設定レジスタ(YM2151用)
//#define PMS 0x70     // LFO位相変調設定(YM2151用)
//#define AMS 0x03     // LFO振幅変調設定(YM2151用)
#define MT_MT 0x38 // 音程微調整設定レジスタ
#define MT 0x01 // 音程微調整設定レジスタ

#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 D1R_D1R 0xA0 // エンベロープファーストディケイレート設定レジスタ
//#define AMS_EN 0x80     // AMS有効フラグ・エンベロープファーストディケイレート設定レジスタ_AMS有効フラグ設定
#define D1R 0x1F        // エンベロープファーストディケイレート設定レジスタ_エンベロープファーストディケイレート設定

//#define DT2_D2R 0xC0 // スロット倍率粗調整・エンベロープセカンドディケイレート設定レジスタ(YM2151用)
//#define DT2 0xC0     // スロット倍率粗調整・エンベロープセカンドディケイレート設定レジスタ_スロット倍率粗調整設定(YM2151用)
//#define D2R 0x1F     // スロット倍率粗調整・エンベロープセカンドディケイレート設定レジスタ_エンベロープセカンドディケイレート設定(YM2151用)
#define AMS_D2R 0xC0 // LFO振幅変調設定・エンベロープセカンドディケイレート設定レジスタ
#define AMS 0xC0     // LFO振幅変調設定・エンベロープセカンドディケイレート設定レジスタ_LFO振幅変調設定
#define D2R 0x1F     // LFO振幅変調設定・エンベロープセカンドディケイレート設定レジスタ_エンベロープセカンドディケイレート設定

#define D1L_RR 0xE0 // エンベロープファーストディケイレベル・エンベロープセカンドディケイレート設定レジスタ
#define D1L 0xF0    // エンベロープファーストディケイレベル・エンベロープセカンドディケイレート設定レジスタ_エンベロープファーストディケイレベル設定
#define RR 0x0F     // エンベロープファーストディケイレベル・エンベロープセカンドディケイレート設定レジスタ_エンベロープセカンドディケイレート設定

// YMF709レジスタ保存
union Ymf709_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 tp_h[8];
    unsigned char tp_l[8];
    unsigned char mt_mt[8];
    unsigned char dt1_mul[32];
    unsigned char tl[32];
    unsigned char ks_ar[32];
    unsigned char d1r_d1r[32];
    unsigned char ams_d2r[32];
    unsigned char d1l_rr[32];
  } reg;
  unsigned char data[256];
};

// YMF709_保存用
Ymf709_data_st ymf709_data[YMF709_N];

unsigned char ymf709_slot_en[CH];                                                       // スロットONOFF保存用(ノートオンで使用)
unsigned char ymf709_main_vol[CH];                                                      // 音量保存用(オペレータごとの最終出力演算に使用)
unsigned char ymf709_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


//@3.579MHz
PROGMEM const uint16_t ymf709_note_conv[12] = {
  //A A# B C C# D D# E F F# G G#
  33001, 34964, 37043, 39245, 41579, 44051, 46671, 49446, 52386, 55501, 58802, 62298
};

// YMF709のレベル変換 127*(1-log127(vol))
const unsigned char PROGMEM ymf709_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};
// YMF709パラメータ
// パラメータ構造
// 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 ymf709_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チャンネルからYMF709のチャンネルへ変換
char ymf709_tr[16] = {0, 1, 2, 3, 4, 5, 6, 8, 9, 7, 10, 11, 12, 13, 14, 15}; // YMF709が1個
// char ymf709_tr[16] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 15, 10, 11, 12, 13, 14, 9};//YMF709が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}; // メインベロシティ(YMF709では未使用)(ノートベロシティと乗算して使用)
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;                                                            // サスティン有効フラグ

/////////////////////////////関数

// YMF709へ書き込み
inline void ymf709_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_YMF709:D2~D7
  PORTD = 0x00; // pin2~pin7_YMF709:D2~D7

  DDRB = 0x3F;  // pin8~pin9_YMF709:D0~D1   pin10~pin13_YMF709:~RD, ~WE, A0, ~RST
  PORTB = 0x3C; // pin8~pin9_YMF709:D0~D1   pin10~pin13_YMF709:~RD, ~WE, A0, ~RST

  DDRC = 0x0F;  // pin14~pin17_YMF709:~CS0 ~ ~CS3
  PORTC = 0x0F; // pin14~pin17_YMF709:~CS0 ~ ~CS3

  // リセット
  PORTB &= ~0x20; // pin13_YMF709: ~RST = L
  delay(200);
  PORTB |= 0x20; // pin13_YMF709: ~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++)
  {
    ymf709_regset_write(i, TEST, 0xFF, 0x00);
  }

  // YMF709キーオフ
  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++)
  {
    ymf709_vced_set(i, 0);//VCED反映
  }

 
 
  // 初期チャンネル音量
  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()); // イベント処理
    }
  }
}

// YMF709へ書き込み
void ymf709_write(unsigned char cs, unsigned char adr, unsigned char data)
{
  unsigned char temp_data = 0x80; // ステータスレジスタの内容を一時保存
  DDRD &= 0x03;                   // pin2~pin7_YMF709:D2~D7を高Z
  DDRB &= 0xFC;                   // pin8~pin9_YMF709:D0~D1を高Z
  DDRB |= 0x3C;                   // YMF709:~RST,A0,~WE,~RDを出力に設定

  PORTB |= 0x10; // pin13_YMF709: A0 = H
  PORTB |= 0x04; // pin12_YMF709: ~RD = H
  PORTB |= 0x08; // pin11_YMF709: ~WR = H

  PORTD &= 0x80; // pin11_YMF709: D7プルアップ無効
  // チップセレクト
  PORTC = (PORTC & 0xF0) | (0x0F & (~(1 << cs))); // pin14~pin17_YMF709:~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_YMF709:~CS0 ~ ~CS3 = L
      return;
    }
    PORTB &= ~0x04; // pin12_YMF709: ~RD = L
    delayMicroseconds(8);
    temp_data = PIND;
    // delayMicroseconds(10);
    PORTB |= 0x04; // pin12_YMF709: ~RD = H
    delayMicroseconds(8);
    if ((temp_data >> 7) == 0x00)
    {
      break;
    }
  }

  // アドレスのセット
  PORTB &= ~0x10; // pin13_YMF709: A0 = L
  // delayMicroseconds(5);
  DDRD |= 0xFC; // pin2~pin7_YMF709:D2~D7を出力ポートにする
  DDRB |= 0x03; // pin8~pin9_YMF709:D0~D1を出力ポートにする
  // delayMicroseconds(5);
  PORTB = (PORTB & 0xFC) | (0x03 & adr); // pin9,8_YMF709:D1,D0
  PORTD = (PORTD & 0x03) | (0xFC & adr); // pin7~2_YMF709:D7~D2

  delayMicroseconds(8);
  PORTB &= ~0x08; // pin11_YMF709: ~WR = L
  delayMicroseconds(8);
  PORTB |= 0x08; // pin11_YMF709: ~WR = H
  delayMicroseconds(8);

  // データのセット
  PORTB |= 0x10; // pin13_YMF709: A0 = H
  // delayMicroseconds(5);

  PORTB = (PORTB & 0xFC) | (0x03 & data); // pin9,8_YMF709:D1,D0
  PORTD = (PORTD & 0x03) | (0xFC & data); // pin7~2_YMF709:D7~D2

  delayMicroseconds(8);
  PORTB &= ~0x08; // pin11_YMF709: ~WR = L
  delayMicroseconds(8);
  PORTB |= 0x08; // pin11_YMF709: ~WR = H
  delayMicroseconds(8);

  PORTC = (PORTC & 0xF0) | (0x0F); // pin14~pin17_YMF709:~CS0 ~ ~CS3 = L
  delayMicroseconds(8);
}

// YMF709のレジスタビットへ値をセット
void ymf709_regset(unsigned char cs, unsigned char adr, unsigned char reg, unsigned char data)
{
  if (cs >= YMF709_N)
  {
    return;
  }

  // regはマスクビット群
  //(reg & (-reg))は、複数のHビットのうち右端のHビットのみ残す
  //(reg & (-reg)) * dataは、実質ビットシフト

  // レジスタの保存
  // ymf709_data[cs].data[adr] = (ymf709_data[cs].data[adr] & (~reg)) | (reg & ((reg & (-reg)) * data));

  ymf709_data[cs].data[adr] = (ymf709_data[cs].data[adr] & (~reg)) | (reg & ((reg & (reg ^ (reg << 1))) * data));
}

// YMF709のレジスタビットへ値をセット(ymf709への書き込みも行う)
void ymf709_regset_write(unsigned char cs, unsigned char adr, unsigned char reg, unsigned char data)
{
  if (cs >= YMF709_N)
  {
    return;
  }

  // regはマスクビット群
  //(reg & (-reg))は、複数のHビットのうち右端のHビットのみ残す
  //(reg & (-reg)) * dataは、実質ビットシフト

  // レジスタの保存
  // ymf709_data[cs].data[adr] = (ymf709_data[cs].data[adr] & (~reg)) | (reg & ((reg & (-reg)) * data));
  ymf709_data[cs].data[adr] = (ymf709_data[cs].data[adr] & (~reg)) | (reg & ((reg & (reg ^ (reg << 1))) * data));
  // ymf709へ書き込み
  ymf709_write(cs, adr, ymf709_data[cs].data[adr]);
}

// YMF709のレジスタ仮想読み込み(マイコン内のRAMから読み込み)
unsigned char ymf709_regread(unsigned char cs, unsigned char adr, unsigned char reg)
{
  return (reg & ymf709_data[cs].data[adr]) / (reg & (reg ^ (reg << 1)));
}

// ymf709パラメータセット(LFO、ノイズ含むすべて)
void ymf709_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

  ymf709_regset_write(cs, LFRQ, 0xFF, pgm_read_byte_near((int)(ymf709_parameter[inst] + 0)));                            // LFRQ
  ymf709_regset_write(cs, PMD_AMD, LFO_MD_F | LFO_MD, 0x7F & pgm_read_byte_near((int)(ymf709_parameter[inst] + 1)));     // AMD
  ymf709_regset_write(cs, PMD_AMD, LFO_MD_F | LFO_MD, LFO_MD_F | pgm_read_byte_near((int)(ymf709_parameter[inst] + 2))); // PMD
  ymf709_regset_write(cs, CT_W, LFO_W, pgm_read_byte_near((int)(ymf709_parameter[inst] + 3)));                           // WF
  ymf709_regset_write(cs, NOISE, NFRQ, pgm_read_byte_near((int)(ymf709_parameter[inst] + 4)));                           // NFRQ

  ymf709_regset_write(cs, LR_FB_CON + ch, 0xFF, (pgm_read_byte_near((int)(ymf709_parameter[inst] + 5)) & RL) | ((pgm_read_byte_near((int)(ymf709_parameter[inst] + 6)) << 3) & FL) | (pgm_read_byte_near((int)(ymf709_parameter[inst] + 7)) & CONECT)); // PAN(bit7,bit6), FL, CON
  // ymf709_regset_write(cs, LR_FB_CON + ch, FL, pgm_read_byte_near((int)(ymf709_parameter[inst] + 6)));//FL
  // ymf709_regset_write(cs, LR_FB_CON + ch, CONECT, pgm_read_byte_near((int)(ymf709_parameter[inst] + 7)));//CON
  //ymf709_regset_write(cs, PMS_AMS + ch, 0xFF, (pgm_read_byte_near((int)(ymf709_parameter[inst] + 8)) & AMS) | ((pgm_read_byte_near((int)(ymf709_parameter[inst] + 9)) << 4) & PMS)); // AMS,PMS
  // ymf709_regset_write(cs, PMS_AMS + ch, PMS, pgm_read_byte_near((int)(ymf709_parameter[inst] + 9)));//PMS
  ymf709_slot_en[(cs << 3) | ch] = pgm_read_byte_near((int)(ymf709_parameter[inst] + 10));         // SLOT(bit6~bit3)
  ymf709_regset_write(cs, NOISE, NE, pgm_read_byte_near((int)(ymf709_parameter[inst] + 11)) >> 7); // NE(bit7)

  // M1
  ymf709_regset_write(cs, KS_AR + ch, 0xFF, (pgm_read_byte_near((int)(ymf709_parameter[inst] + 12)) & AR) | (pgm_read_byte_near((int)(ymf709_parameter[inst] + 18)) << 6));           // M1-AR,KS
  ymf709_regset_write(cs, D1R_D1R + ch, D1R, (pgm_read_byte_near((int)(ymf709_parameter[inst] + 13)) & D1R)); // M1-D1R,AMS-EN(bit7)
  ymf709_regset_write(cs, AMS_D2R + ch, D2R, (pgm_read_byte_near((int)(ymf709_parameter[inst] + 14)) & D2R));        // M1-D2R,DT2
  ymf709_regset_write(cs, D1L_RR + ch, 0xFF, (pgm_read_byte_near((int)(ymf709_parameter[inst] + 15)) & RR) | (pgm_read_byte_near((int)(ymf709_parameter[inst] + 16)) << 4));          // M1-RR,D1L
  // ymf709_regset_write(cs, D1L_RR + ch, D1L, pgm_read_byte_near((int)(ymf709_parameter[inst] + 16)));//M1-D1L
  ymf709_regset_write(cs, TL + ch, TL_TL, pgm_read_byte_near((int)(ymf709_parameter[inst] + 17))); // M1-TL
  // ymf709_regset_write(cs, KS_AR + ch, KS, pgm_read_byte_near((int)(ymf709_parameter[inst] + 18)));//M1-KS
  ymf709_regset_write(cs, DT1_MUL + ch, 0xFF, (pgm_read_byte_near((int)(ymf709_parameter[inst] + 19)) & MUL) | (pgm_read_byte_near((int)(ymf709_parameter[inst] + 20)) << 4)); // M1-MUL,DT1
  // ymf709_regset_write(cs, DT1_MUL + ch, DT1, pgm_read_byte_near((int)(ymf709_parameter[inst] + 20)));//M1-DT1
  // ymf709_regset_write(cs, AMS_D2R + ch, AMS, pgm_read_byte_near((int)(ymf709_parameter[inst] + 21)));//M1-AMS
  // ymf709_regset_write(cs, D1R_D1R + ch, AMS_EN, pgm_read_byte_near((int)(ymf709_parameter[inst] + 22)));//M1-AMS-EN(bit7)
  if(pgm_read_byte_near((int)(ymf709_parameter[inst] + 22)) == 0x80)
  {
    ymf709_regset_write(cs, AMS_D2R + ch, AMS, pgm_read_byte_near((int)(ymf709_parameter[inst] + 8))); // AMS
  }else{
    ymf709_regset_write(cs, AMS_D2R + ch, AMS, 0); // AMS
  }
 
  // C1
  ymf709_regset_write(cs, KS_AR + ch + 16, 0xFF, (pgm_read_byte_near((int)(ymf709_parameter[inst] + 23)) & AR) | (pgm_read_byte_near((int)(ymf709_parameter[inst] + 29)) << 6));           // C1-AR,KS
  ymf709_regset_write(cs, D1R_D1R + ch + 16, D1R, (pgm_read_byte_near((int)(ymf709_parameter[inst] + 24)) & D1R)); // C1-D1R
  ymf709_regset_write(cs, AMS_D2R + ch + 16, D2R, (pgm_read_byte_near((int)(ymf709_parameter[inst] + 25)) & D2R)); // C1-D2R
  ymf709_regset_write(cs, D1L_RR + ch + 16, 0xFF, (pgm_read_byte_near((int)(ymf709_parameter[inst] + 26)) & RR) | (pgm_read_byte_near((int)(ymf709_parameter[inst] + 27)) << 4));          // C1-RR,D1L
  // ymf709_regset_write(cs, D1L_RR + ch + 16, D1L, pgm_read_byte_near((int)(ymf709_parameter[inst] + 27)));//C1-D1L
  ymf709_regset_write(cs, TL + ch + 16, TL_TL, pgm_read_byte_near((int)(ymf709_parameter[inst] + 28))); // C1-TL
  // ymf709_regset_write(cs, KS_AR + ch + 16, KS, pgm_read_byte_near((int)(ymf709_parameter[inst] + 29)));//C1-KS
  ymf709_regset_write(cs, DT1_MUL + ch + 16, 0xFF, (pgm_read_byte_near((int)(ymf709_parameter[inst] + 30)) & MUL) | (pgm_read_byte_near((int)(ymf709_parameter[inst] + 31)) << 4)); // C1-MUL,DT1
  // ymf709_regset_write(cs, DT1_MUL + ch + 16, DT1, pgm_read_byte_near((int)(ymf709_parameter[inst] + 31)));//C1-DT1
  // ymf709_regset_write(cs, AMS_D2R + ch + 16, AMS, pgm_read_byte_near((int)(ymf709_parameter[inst] + 32)));//C1-AMS
  // ymf709_regset_write(cs, D1R_D1R + ch + 16, AMS_EN, pgm_read_byte_near((int)(ymf709_parameter[inst] + 33)));//C1-AMS-EN(bit7)
  if(pgm_read_byte_near((int)(ymf709_parameter[inst] + 33)) == 0x80)
  {
    ymf709_regset_write(cs, AMS_D2R + ch + 16, AMS, pgm_read_byte_near((int)(ymf709_parameter[inst] + 8))); // AMS
  }else{
    ymf709_regset_write(cs, AMS_D2R + ch + 16, AMS, 0); // AMS
  }

  // M2
  ymf709_regset_write(cs, KS_AR + ch + 8, 0xFF, (pgm_read_byte_near((int)(ymf709_parameter[inst] + 34)) & AR) | (pgm_read_byte_near((int)(ymf709_parameter[inst] + 40)) << 6));           // M2-AR,KS
  ymf709_regset_write(cs, D1R_D1R + ch + 8, D1R, (pgm_read_byte_near((int)(ymf709_parameter[inst] + 35)) & D1R)); // M2-D1R
  ymf709_regset_write(cs, AMS_D2R + ch + 8, D2R, (pgm_read_byte_near((int)(ymf709_parameter[inst] + 36)) & D2R));        // M2-D2R,
  ymf709_regset_write(cs, D1L_RR + ch + 8, 0xFF, (pgm_read_byte_near((int)(ymf709_parameter[inst] + 37)) & RR) | (pgm_read_byte_near((int)(ymf709_parameter[inst] + 38)) << 4));          // M2-RR,D1L
  // ymf709_regset_write(cs, D1L_RR + ch + 8, D1L, pgm_read_byte_near((int)(ymf709_parameter[inst] + 38)));//M2-D1L
  ymf709_regset_write(cs, TL + ch + 8, TL_TL, pgm_read_byte_near((int)(ymf709_parameter[inst] + 39))); // M2-TL
  // ymf709_regset_write(cs, KS_AR + ch + 8, KS, pgm_read_byte_near((int)(ymf709_parameter[inst] + 40)));//M2-KS
  ymf709_regset_write(cs, DT1_MUL + ch + 8, 0xFF, (pgm_read_byte_near((int)(ymf709_parameter[inst] + 41)) & MUL) | (pgm_read_byte_near((int)(ymf709_parameter[inst] + 42)) << 4)); // M2-MUL,DT1
  // ymf709_regset_write(cs, DT1_MUL + ch + 8, DT1, pgm_read_byte_near((int)(ymf709_parameter[inst] + 42)));//M2-DT1
  // ymf709_regset_write(cs, AMS_D2R + ch + 8, AMS, pgm_read_byte_near((int)(ymf709_parameter[inst] + 43)));//M2-AMS
  // ymf709_regset_write(cs, D1R_D1R + ch + 8, AMS_EN, pgm_read_byte_near((int)(ymf709_parameter[inst] + 44)));//M2-AMS-EN(bit7)
  if(pgm_read_byte_near((int)(ymf709_parameter[inst] + 44)) == 0x80)
  {
    ymf709_regset_write(cs, AMS_D2R + ch + 8, AMS, pgm_read_byte_near((int)(ymf709_parameter[inst] + 8))); // AMS
  }else{
    ymf709_regset_write(cs, AMS_D2R + ch + 8, AMS, 0); // AMS
  }

  // C2
  ymf709_regset_write(cs, KS_AR + ch + 24, 0xFF, (pgm_read_byte_near((int)(ymf709_parameter[inst] + 45)) & AR) | (pgm_read_byte_near((int)(ymf709_parameter[inst] + 51)) << 6));           // C2-AR,KS
  ymf709_regset_write(cs, D1R_D1R + ch + 24, D1R, (pgm_read_byte_near((int)(ymf709_parameter[inst] + 46)) & D1R)); // C2-D1R
  ymf709_regset_write(cs, AMS_D2R + ch + 24, D2R, (pgm_read_byte_near((int)(ymf709_parameter[inst] + 47)) & D2R));        // C2-D2R
  ymf709_regset_write(cs, D1L_RR + ch + 24, 0xFF, (pgm_read_byte_near((int)(ymf709_parameter[inst] + 48)) & RR) | (pgm_read_byte_near((int)(ymf709_parameter[inst] + 49)) << 4));          // C2-RR,D1L
  // ymf709_regset_write(cs, D1L_RR + ch + 24, D1L, pgm_read_byte_near((int)(ymf709_parameter[inst] + 49)));//C2-D1L
  ymf709_regset_write(cs, TL + ch + 24, TL_TL, pgm_read_byte_near((int)(ymf709_parameter[inst] + 50))); // C2-TL
  // ymf709_regset_write(cs, KS_AR + ch + 24, KS, pgm_read_byte_near((int)(ymf709_parameter[inst] + 51)));//C2-KS
  ymf709_regset_write(cs, DT1_MUL + ch + 24, 0xFF, (pgm_read_byte_near((int)(ymf709_parameter[inst] + 52)) & MUL) | (pgm_read_byte_near((int)(ymf709_parameter[inst] + 53)) << 4)); // C2-MUL,DT1
  // ymf709_regset_write(cs, DT1_MUL + ch + 24, DT1, pgm_read_byte_near((int)(ymf709_parameter[inst] + 53)));//C2-DT1
  // ymf709_regset_write(cs, AMS_D2R + ch + 24, AMS, pgm_read_byte_near((int)(ymf709_parameter[inst] + 54)));//C2-AMS
  // ymf709_regset_write(cs, D1R_D1R + ch + 24, AMS_EN, pgm_read_byte_near((int)(ymf709_parameter[inst] + 55)));//C2-AMS-EN(bit7)
  if(pgm_read_byte_near((int)(ymf709_parameter[inst] + 55)) == 0x80)
  {
    ymf709_regset_write(cs, AMS_D2R + ch + 24, AMS, pgm_read_byte_near((int)(ymf709_parameter[inst] + 8))); // AMS
  }else{
    ymf709_regset_write(cs, AMS_D2R + ch + 24, AMS, 0); // AMS
  }

}

// 音程のセット
void ptc_set(unsigned char ch, unsigned int notenum)
{
  unsigned char cs_temp = ch >> 3;
  unsigned char ch_temp = ch & 0x07;
  unsigned int note_temp;
  unsigned int note_oct;
  unsigned int note12;//note_temp%12
  unsigned int note;

  if (ch != FM_DRUM_CH)
  {
    // ドラムチャンネル以外
    note_temp = notenum + def_tone[ch] + 3;
    note_oct = note_temp / 12;
    note12 = note_temp - (note_oct*12);//note_temp%12
    note = pgm_read_word_near(ymf709_note_conv + note12) >> (10 - note_oct);
   
    ymf709_data[cs_temp].reg.tp_h[ch_temp] = note >> 8;
    ymf709_data[cs_temp].reg.tp_l[ch_temp] = 0xFF & note;
    ymf709_write(cs_temp, TP_H + ch_temp, note >> 8);
    ymf709_write(cs_temp, TP_L + ch_temp, 0xFF & note);
   
  }
  else
  {
    // ドラムチャンネル
    // VCEDパラメータのセット(処理が重いため、テンポが速い曲は注意)
    ymf709_vced_set(FM_DRUM_CH, (unsigned int)(((unsigned int)DRUM_VCED << 7) | (unsigned int)notenum));
   
    note_temp = 64 + def_tone[ch] + 3;
    note_oct = note_temp / 12;
    note12 = note_temp - (note_oct*12);//note_temp%12
    note = pgm_read_word_near(ymf709_note_conv + note12) >> (10 - note_oct);
   
    ymf709_write(cs_temp, TP_H + ch_temp, note >> 8);
    ymf709_write(cs_temp, TP_L + ch_temp, 0xFF & note);
   
  }
}

// メインの音量とパンのセット
void main_vel_pan_set(unsigned char vel, unsigned char pan)
{
  // 何もしません。
}

// チャンネルの音量とパンのセット
void vel_pan_set(unsigned char ch, unsigned char vel, unsigned char pan)
{
  // YMF709はチャンネル音量設定ができないためTL値の変更で代用(低音量で音色が変わるので注意)
  // アルゴリズムによって音量制御レジスタ(TL)の個数が変わる
  unsigned char conect_temp = 0; // アルゴリズムの種類一時保存
  unsigned char cs_temp = ch >> 3;
  unsigned char ch_temp = ch & 0x07;

  ymf709_main_vol[ch] = vel;

  conect_temp = ymf709_data[cs_temp].reg.lr_fb_conf[ch_temp] & 0x07;

  if (ch == 7)
  {
    //(ymf709_data[cs_temp].reg.tl[ch_temp + (C2 * 8)] + pgm_read_byte_near(ymf709_tl_vol_conv + vel)
  }
  if ((conect_temp & 0x04) == 0)
  {
    if (((unsigned int)ymf709_data[cs_temp].reg.tl[ch_temp + (C2 * 8)] + pgm_read_byte_near(ymf709_tl_vol_conv + vel)) > 127)
    {
      ymf709_write(cs_temp, TL + ch_temp + (C2 * 8), TL_TL & (127));
    }
    else
    {
      //-/ymf709_write(cs_temp, TL + ch_temp + (C2*8), TL_TL & (ymf709_data[cs_temp].reg.tl[ch_temp + (C2 * 8)] + ((127 - vel)>>1)));
      ymf709_write(cs_temp, TL + ch_temp + (C2 * 8), TL_TL & (ymf709_data[cs_temp].reg.tl[ch_temp + (C2 * 8)] + pgm_read_byte_near(ymf709_tl_vol_conv + vel)));
    }

    ymf709_write(cs_temp, TL + ch_temp + (M1 * 8), ymf709_data[cs_temp].reg.tl[ch_temp + (M1 * 8)]);
    ymf709_write(cs_temp, TL + ch_temp + (M2 * 8), ymf709_data[cs_temp].reg.tl[ch_temp + (M2 * 8)]);
    ymf709_write(cs_temp, TL + ch_temp + (C1 * 8), ymf709_data[cs_temp].reg.tl[ch_temp + (C1 * 8)]);
  }
  else if (conect_temp == 4)
  {
    if (((unsigned int)ymf709_data[cs_temp].reg.tl[ch_temp + (C1 * 8)] + pgm_read_byte_near(ymf709_tl_vol_conv + vel)) > 127)
    {
      ymf709_write(cs_temp, TL + ch_temp + (C1 * 8), TL_TL & (127));
    }
    else
    {
      ymf709_write(cs_temp, TL + ch_temp + (C1 * 8), TL_TL & (ymf709_data[cs_temp].reg.tl[ch_temp + (C1 * 8)] + pgm_read_byte_near(ymf709_tl_vol_conv + vel)));
    }
    if (((unsigned int)ymf709_data[cs_temp].reg.tl[ch_temp + (C2 * 8)] + pgm_read_byte_near(ymf709_tl_vol_conv + vel)) > 127)
    {
      ymf709_write(cs_temp, TL + ch_temp + (C2 * 8), TL_TL & (127));
    }
    else
    {
      ymf709_write(cs_temp, TL + ch_temp + (C2 * 8), TL_TL & (ymf709_data[cs_temp].reg.tl[ch_temp + (C2 * 8)] + pgm_read_byte_near(ymf709_tl_vol_conv + vel)));
    }

    ymf709_write(cs_temp, TL + ch_temp + (M1 * 8), ymf709_data[cs_temp].reg.tl[ch_temp + (M1 * 8)]);
    ymf709_write(cs_temp, TL + ch_temp + (M2 * 8), ymf709_data[cs_temp].reg.tl[ch_temp + (M2 * 8)]);
  }
  else if (conect_temp == 7)
  {
    if (((unsigned int)ymf709_data[cs_temp].reg.tl[ch_temp + (M1 * 8)] + pgm_read_byte_near(ymf709_tl_vol_conv + vel)) > 127)
    {
      ymf709_write(cs_temp, TL + ch_temp + (M1 * 8), TL_TL & (127));
    }
    else
    {
      ymf709_write(cs_temp, TL + ch_temp + (M1 * 8), TL_TL & (ymf709_data[cs_temp].reg.tl[ch_temp + (M1 * 8)] + pgm_read_byte_near(ymf709_tl_vol_conv + vel)));
    }
    if (((unsigned int)ymf709_data[cs_temp].reg.tl[ch_temp + (M2 * 8)] + pgm_read_byte_near(ymf709_tl_vol_conv + vel)) > 127)
    {
      ymf709_write(cs_temp, TL + ch_temp + (M2 * 8), TL_TL & (127));
    }
    else
    {
      ymf709_write(cs_temp, TL + ch_temp + (M2 * 8), TL_TL & (ymf709_data[cs_temp].reg.tl[ch_temp + (M2 * 8)] + pgm_read_byte_near(ymf709_tl_vol_conv + vel)));
    }

    if (((unsigned int)ymf709_data[cs_temp].reg.tl[ch_temp + (C1 * 8)] + pgm_read_byte_near(ymf709_tl_vol_conv + vel)) > 127)
    {
      ymf709_write(cs_temp, TL + ch_temp + (C1 * 8), TL_TL & (127));
    }
    else
    {
      ymf709_write(cs_temp, TL + ch_temp + (C1 * 8), TL_TL & (ymf709_data[cs_temp].reg.tl[ch_temp + (C1 * 8)] + pgm_read_byte_near(ymf709_tl_vol_conv + vel)));
    }
    if (((unsigned int)ymf709_data[cs_temp].reg.tl[ch_temp + (C2 * 8)] + pgm_read_byte_near(ymf709_tl_vol_conv + vel)) > 127)
    {
      ymf709_write(cs_temp, TL + ch_temp + (C2 * 8), TL_TL & (127));
    }
    else
    {
      ymf709_write(cs_temp, TL + ch_temp + (C2 * 8), TL_TL & (ymf709_data[cs_temp].reg.tl[ch_temp + (C2 * 8)] + pgm_read_byte_near(ymf709_tl_vol_conv + vel)));
    }
  }
  else
  {
    if (((unsigned int)ymf709_data[cs_temp].reg.tl[ch_temp + (M2 * 8)] + pgm_read_byte_near(ymf709_tl_vol_conv + vel)) > 127)
    {
      ymf709_write(cs_temp, TL + ch_temp + (M2 * 8), TL_TL & (127));
    }
    else
    {
      ymf709_write(cs_temp, TL + ch_temp + (M2 * 8), TL_TL & (ymf709_data[cs_temp].reg.tl[ch_temp + (M2 * 8)] + pgm_read_byte_near(ymf709_tl_vol_conv + vel)));
    }

    if (((unsigned int)ymf709_data[cs_temp].reg.tl[ch_temp + (C1 * 8)] + pgm_read_byte_near(ymf709_tl_vol_conv + vel)) > 127)
    {
      ymf709_write(cs_temp, TL + ch_temp + (C1 * 8), TL_TL & (127));
    }
    else
    {
      ymf709_write(cs_temp, TL + ch_temp + (C1 * 8), TL_TL & (ymf709_data[cs_temp].reg.tl[ch_temp + (C1 * 8)] + pgm_read_byte_near(ymf709_tl_vol_conv + vel)));
    }
    if (((unsigned int)ymf709_data[cs_temp].reg.tl[ch_temp + (C2 * 8)] + pgm_read_byte_near(ymf709_tl_vol_conv + vel)) > 127)
    {
      ymf709_write(cs_temp, TL + ch_temp + (C2 * 8), TL_TL & (127));
    }
    else
    {
      ymf709_write(cs_temp, TL + ch_temp + (C2 * 8), TL_TL & (ymf709_data[cs_temp].reg.tl[ch_temp + (C2 * 8)] + pgm_read_byte_near(ymf709_tl_vol_conv + vel)));
    }

    ymf709_write(cs_temp, TL + ch_temp + (M1 * 8), ymf709_data[cs_temp].reg.tl[ch_temp + (M1 * 8)]);
  }

  // パン
  // パンが5以下か122以上のとき左右の出力のオンオフを行う
  if (pan <= 5)
  {
    ymf709_regset_write(cs_temp, LR_FB_CON + ch_temp, RL, 0x01);
  }
  else if (pan >= 122)
  {
    ymf709_regset_write(cs_temp, LR_FB_CON + ch_temp, RL, 0x02);
  }
  else
  {
    ymf709_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 (ymf709_lfo_rst_en[ch] != 0)
  {
    // LFOをリセットするチャンネルの場合リセット
    ymf709_write(cs_temp, TEST, LFO_RESET);
    ymf709_write(cs_temp, TEST, 0);
  }

  if (ch != FM_DRUM_CH)
  {
    // ドラムチャンネル以外
    ymf709_data[cs_temp].reg.kon = (ymf709_slot_en[ch] & SN) | (ch & CH_REG);
    ymf709_write(cs_temp, KON, ymf709_data[cs_temp].reg.kon);
  }
  else
  {
    // ドラムチャンネル
    ymf709_data[cs_temp].reg.kon = (ymf709_slot_en[ch] & SN) | (ch & CH_REG);
    ymf709_write(cs_temp, KON, ymf709_data[cs_temp].reg.kon);
  }
}

// チャンネルノートオフ
void note_off(unsigned char ch)
{
  unsigned char cs_temp = ch >> 3;
 
   if (ch == FM_DRUM_CH)
  { // ドラムチャンネル以外
    ymf709_data[cs_temp].reg.kon = ch & CH_REG;
    ymf709_write(cs_temp, KON, ymf709_data[cs_temp].reg.kon);
  }
  else
  {
    // ドラムチャンネル
    ymf709_data[cs_temp].reg.kon = ch & CH_REG;
    ymf709_write(cs_temp, KON, ymf709_data[cs_temp].reg.kon);
  }
}

// 音色セット
void inst_set(unsigned char ch, unsigned char inst)
{
  ymf709_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(ymf709_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(ymf709_tr[in_midi_data_buf_l0]);
      }
    }
    else
    {
      midi_vel[ymf709_tr[in_midi_data_buf_l0]] = in_midi_data_buf_2; // ベロシティ保存
      // ノートオン
      if (in_midi_data_buf_l0 < MIDI_MAX_TR)
      {
        ptc_set(ymf709_tr[in_midi_data_buf_l0], in_midi_mess[1] + def_key);                                                                                                                                      // チャンネル, 音程
        vel_pan_set(ymf709_tr[in_midi_data_buf_l0], ((int)((int)midi_vel[ymf709_tr[in_midi_data_buf_l0]] * (int)midi_main_vel[ymf709_tr[in_midi_data_buf_l0]]) >> 7), midi_pan[ymf709_tr[in_midi_data_buf_l0]]); // チャンネル, 音量, パン
        note_on(ymf709_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[ymf709_tr[in_midi_data_buf_l0]] = in_midi_mess[2];
      break;
    case 0x0A: // パン
      midi_pan[ymf709_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];
    ymf709_vced_set(ymf709_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 = (ymf709_tr[in_midi_mess[2] & 0x0F]) >> 3;
        ch_temp = ymf709_tr[in_midi_mess[2] & 0x0F] & 0x07;
        unsigned char op_temp = OP4; // オペレータ番号による先頭位置計算用

        // VCEDフォーマット(DX-27やTX81Zのサービスマニュアルを参照、ただしパラメータの互換性が無いものもあり)
        // TX81Zのオペレータ番号とYMF709のオペレータ番号は違うので注意!(YM2414のOP4~OP1 → YMF709の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])
            {
              ymf709_vced_set(ymf709_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];
          ymf709_vced_t_set(ymf709_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 + 6];
          }

          ymf709_vced_set(ymf709_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 ymf709_vced_set(unsigned char ch, unsigned int vced_n)
{
  unsigned char cs_temp = ch >> 3;
  unsigned char ch_temp = ch & 0x07;
  ymf709_regset_write(cs_temp, D1L_RR + ch_temp + OP4_A, RR, 0x0F);//リリース時間を最小にする
  ymf709_regset_write(cs_temp, D1L_RR + ch_temp + OP3_A, RR, 0x0F);
  ymf709_regset_write(cs_temp, D1L_RR + ch_temp + OP2_A, RR, 0x0F);
  ymf709_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);

  ymf709_slot_en[ch] = 0x78;         // SLOT(bit6~bit3)
 

  // OP1
  // 0:AR(0-31)
  ymf709_regset_write(cs_temp, KS_AR + ch_temp + OP1_A, AR, vced_ram[vced_itr][0]);
  // 1:D1R(0-31)
  ymf709_regset_write(cs_temp, D1R_D1R + ch_temp + OP1_A, D1R, vced_ram[vced_itr][1]);
  // 2:D2R(0-31)
  ymf709_regset_write(cs_temp, AMS_D2R + ch_temp + OP1_A, D2R, vced_ram[vced_itr][2]);
  // 3:RR(0-15:DX27)(1-15:TX81Z)
  ymf709_regset_write(cs_temp, D1L_RR + ch_temp + OP1_A, RR, vced_ram[vced_itr][3]);
  // 4:D1L(0-15)
  ymf709_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)
  ymf709_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)
  //ymf709_regset_write(cs_temp, D1R_D1R + ch_temp + OP1_A, AMS_EN, vced_ram[vced_itr][8]);
  if(vced_ram[vced_itr][8] == 1)
  {
    ymf709_regset_write(cs_temp, AMS_D2R + ch + OP1_A, AMS, vced_ram[vced_itr][61]);
  }else{
    ymf709_regset_write(cs_temp, AMS_D2R + ch + OP1_A, AMS, 0); // AMS
  }
  // 9:KVS(0-7)
  // VCEDフォーマット非従順、値を無視
  // 10:OUT(0-99)
  // VCEDフォーマット非従順、本来は0~99を0~127にスケーリングしなければいけない。
  ymf709_regset_write(cs_temp, TL + ch_temp + OP1_A, TL_TL, vced_ram[vced_itr][10]);
  // 11:F(0-63)
  // MUL(4bit)とDT2(2bit) (予想)
  ymf709_regset_write(cs_temp, DT1_MUL + ch_temp + OP1_A, MUL, vced_ram[vced_itr][11] >> 2);
  //YMF709はDT2が無いため無視
  //ymf709_regset_write(cs_temp, AMS_D2R + ch_temp + OP1_A, DT2, vced_ram[vced_itr][11]);
  // 12:DET(0-6)
  // VCEDフォーマット非従順、本来はcenter=3だが、DT1=0~7として入力
  ymf709_regset_write(cs_temp, DT1_MUL + ch_temp + OP1_A, DT1, vced_ram[vced_itr][12]);

  // OP2
  // 13:AR(0-31)
  ymf709_regset_write(cs_temp, KS_AR + ch_temp + OP2_A, AR, vced_ram[vced_itr][13]);
  // 14:D1R(0-31)
  ymf709_regset_write(cs_temp, D1R_D1R + ch_temp + OP2_A, D1R, vced_ram[vced_itr][14]);
  // 15:D2R(0-31)
  ymf709_regset_write(cs_temp, AMS_D2R + ch_temp + OP2_A, D2R, vced_ram[vced_itr][15]);
  // 16:RR(0-15:DX27)(1-15:TX81Z)
  ymf709_regset_write(cs_temp, D1L_RR + ch_temp + OP2_A, RR, vced_ram[vced_itr][16]);
  // 17:D1L(0-15)
  ymf709_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)
  ymf709_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)
  //ymf709_regset_write(cs_temp, D1R_D1R + ch_temp + OP2_A, AMS_EN, vced_ram[vced_itr][21]);
  if(vced_ram[vced_itr][21] == 1)
  {
    ymf709_regset_write(cs_temp, AMS_D2R + ch + OP2_A, AMS, vced_ram[vced_itr][61]);
  }else{
    ymf709_regset_write(cs_temp, AMS_D2R + ch + OP2_A, AMS, 0); // AMS
  }
  // 22:KVS(0-7)
  // VCEDフォーマット非従順、値を無視
  // 23:OUT(0-99)
  // VCEDフォーマット非従順、本来は0~99を0~127にスケーリングしなければいけない。
  ymf709_regset_write(cs_temp, TL + ch_temp + OP2_A, TL_TL, vced_ram[vced_itr][23]);
  // 24:F(0-63)
  // MUL(4bit)とDT2(2bit) (予想)
  ymf709_regset_write(cs_temp, DT1_MUL + ch_temp + OP2_A, MUL, vced_ram[vced_itr][24] >> 2);
  //YMF709はDT2が無いため無視
  //ymf709_regset_write(cs_temp, AMS_D2R + ch_temp + OP2_A, DT2, vced_ram[vced_itr][24]);
  // 25:DET(0-6)
  // VCEDフォーマット非従順、本来はcenter=3だが、DT1=0~7として入力
  ymf709_regset_write(cs_temp, DT1_MUL + ch_temp + OP2_A, DT1, vced_ram[vced_itr][25]);

  // OP3
  // 26:AR(0-31)
  ymf709_regset_write(cs_temp, KS_AR + ch_temp + OP3_A, AR, vced_ram[vced_itr][26]);
  // 27:D1R(0-31)
  ymf709_regset_write(cs_temp, D1R_D1R + ch_temp + OP3_A, D1R, vced_ram[vced_itr][27]);
  // 28:D2R(0-31)
  ymf709_regset_write(cs_temp, AMS_D2R + ch_temp + OP3_A, D2R, vced_ram[vced_itr][28]);
  // 29:RR(0-15:DX27)(1-15:TX81Z)
  ymf709_regset_write(cs_temp, D1L_RR + ch_temp + OP3_A, RR, vced_ram[vced_itr][29]);
  // 30:D1L(0-15)
  ymf709_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)
  ymf709_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)
  //ymf709_regset_write(cs_temp, D1R_D1R + ch_temp + OP3_A, AMS_EN, vced_ram[vced_itr][34]);
  if(vced_ram[vced_itr][34] == 1)
  {
    ymf709_regset_write(cs_temp, AMS_D2R + ch + OP3_A, AMS, vced_ram[vced_itr][61]);
  }else{
    ymf709_regset_write(cs_temp, AMS_D2R + ch + OP3_A, AMS, 0); // AMS
  }
  // 35:KVS(0-7)
  // VCEDフォーマット非従順、値を無視
  // 36:OUT(0-99)
  // VCEDフォーマット非従順、本来は0~99を0~127にスケーリングしなければいけない。
  ymf709_regset_write(cs_temp, TL + ch_temp + OP3_A, TL_TL, vced_ram[vced_itr][36]);
  // 37:F(0-63)
  // MUL(4bit)とDT2(2bit) (予想)
  ymf709_regset_write(cs_temp, DT1_MUL + ch_temp + OP3_A, MUL, vced_ram[vced_itr][37] >> 2);
  //YMF709はDT2が無いため無視
  //ymf709_regset_write(cs_temp, AMS_D2R + ch_temp + OP3_A, DT2, vced_ram[vced_itr][37]);
  // 38:DET(0-6)
  // VCEDフォーマット非従順、本来はcenter=3だが、DT1=0~7として入力
  ymf709_regset_write(cs_temp, DT1_MUL + ch_temp + OP3_A, DT1, vced_ram[vced_itr][38]);

  // OP4
  // 39:AR(0-31)
  ymf709_regset_write(cs_temp, KS_AR + ch_temp + OP4_A, AR, vced_ram[vced_itr][39]);
  // 40:D1R(0-31)
  ymf709_regset_write(cs_temp, D1R_D1R + ch_temp + OP4_A, D1R, vced_ram[vced_itr][40]);
  // 41:D2R(0-31)
  ymf709_regset_write(cs_temp, AMS_D2R + ch_temp + OP4_A, D2R, vced_ram[vced_itr][41]);
  // 42:RR(0-15:DX27)(1-15:TX81Z)
  ymf709_regset_write(cs_temp, D1L_RR + ch_temp + OP4_A, RR, vced_ram[vced_itr][42]);
  // 43:D1L(0-15)
  ymf709_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)
  ymf709_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)
  //ymf709_regset_write(cs_temp, D1R_D1R + ch_temp + OP4_A, AMS_EN, vced_ram[vced_itr][47]);
  if(vced_ram[vced_itr][47] == 1)
  {
    ymf709_regset_write(cs_temp, AMS_D2R + ch + OP4_A, AMS, vced_ram[vced_itr][61]);
  }else{
    ymf709_regset_write(cs_temp, AMS_D2R + ch + OP4_A, AMS, 0); // AMS
  }
  // 48:KVS(0-7)
  // VCEDフォーマット非従順、値を無視
  // 49:OUT(0-99)
  // VCEDフォーマット非従順、本来は0~99を0~127にスケーリングしなければいけない。
  ymf709_regset_write(cs_temp, TL + ch_temp + OP4_A, TL_TL, vced_ram[vced_itr][49]);
  // 50:F(0-63)
  // MUL(4bit)とDT2(2bit) (予想)
  ymf709_regset_write(cs_temp, DT1_MUL + ch_temp + OP4_A, MUL, vced_ram[vced_itr][50] >> 2);
  //YMF709はDT2が無いため無視
  //ymf709_regset_write(cs_temp, AMS_D2R + ch_temp + OP4_A, DT2, vced_ram[vced_itr][50]);
  // 51:DET(0-6)
  // VCEDフォーマット非従順、本来はcenter=3だが、DT1=0~7として入力
  ymf709_regset_write(cs_temp, DT1_MUL + ch_temp + OP4_A, DT1, vced_ram[vced_itr][51]);

  // 52:ALG(0-7)
  ymf709_regset_write(cs_temp, LR_FB_CON + ch_temp, CONECT, vced_ram[vced_itr][52]);
  // 53:FBL(0~7)
  ymf709_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)
  {
    ymf709_regset_write(cs_temp, LFRQ, 0xFF, vced_ram[vced_itr][54]);

    // LFOをリセットするチャンネルに登録
    ymf709_lfo_rst_en[ch] = 1;
  }
  else
  {
    // LFOをリセットするチャンネル解除
    ymf709_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)
  {
    ymf709_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)
  {
    ymf709_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)
  {
    ymf709_regset_write(cs_temp, CT_W, LFO_W, vced_ram[vced_itr][59]);
  }
  // 60:PMS(0~7)
  //ymf709_regset_write(cs_temp, PMS_AMS + ch_temp, PMS, vced_ram[vced_itr][60]);
  // 61:AMS(0~7)
  // VCEDフォーマット非従順、本来は0~7を0~3にスケーリングしなければいけない。
  //ymf709_regset_write(cs_temp, PMS_AMS + ch_temp, AMS, vced_ram[vced_itr][61]);
  if(vced_ram[vced_itr][8] == 1)
  {
    ymf709_regset_write(cs_temp, AMS_D2R + ch + OP1_A, AMS, vced_ram[vced_itr][61]);
  }else{
    ymf709_regset_write(cs_temp, AMS_D2R + ch + OP1_A, AMS, 0); // AMS
  }
  if(vced_ram[vced_itr][21] == 1)
  {
    ymf709_regset_write(cs_temp, AMS_D2R + ch + OP2_A, AMS, vced_ram[vced_itr][61]);
  }else{
    ymf709_regset_write(cs_temp, AMS_D2R + ch + OP2_A, AMS, 0); // AMS
  }
  if(vced_ram[vced_itr][34] == 1)
  {
    ymf709_regset_write(cs_temp, AMS_D2R + ch + OP3_A, AMS, vced_ram[vced_itr][61]);
  }else{
    ymf709_regset_write(cs_temp, AMS_D2R + ch + OP3_A, AMS, 0); // AMS
  }
  if(vced_ram[vced_itr][47] == 1)
  {
    ymf709_regset_write(cs_temp, AMS_D2R + ch + OP4_A, AMS, vced_ram[vced_itr][61]);
  }else{
    ymf709_regset_write(cs_temp, AMS_D2R + ch + OP4_A, AMS, 0); // AMS
  }
  // 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 ymf709_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 char vced_pn_op = vced_pn;
  // vced_nは14bit値
  unsigned char vced_itr = vced_itn_get(vced_n); // 14bit値VCEDナンバーからvcedパラメータ保存番号を見つける

  // オペレータに対するパラメータ変更
  if ((vced_pn >= 0) && (vced_pn <= 51))
  {
    // オペレータ番号による先頭位置計算
    if ((vced_pn >= 13) && (vced_pn <= 25))
    {
      // OP2
      op_temp = OP2;
      vced_pn_op -= 13;
    }
    else if ((vced_pn >= 26) && (vced_pn <= 38))
    {
      // OP3
      op_temp = OP3;
      vced_pn_op -= 26;
    }
    else if ((vced_pn >= 39) && (vced_pn <= 51))
    {
      // OP4
      op_temp = OP4;
      vced_pn_op -= 39;
    }
    switch (vced_pn_op)
    {
    case 0: // 0:AR(0-31)
      ymf709_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)
      ymf709_regset_write(cs_temp, D1R_D1R + ch_temp + (op_temp * 8), D1R, vced_ram[vced_itr][vced_pn]);
      break;
    case 2: // 2:D2R(0-31)
      ymf709_regset_write(cs_temp, AMS_D2R + ch_temp + (op_temp * 8), D2R, vced_ram[vced_itr][vced_pn]);
      break;
    case 3: // 3:RR(0-15:DX27)(1-15:TX81Z)
      ymf709_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)
      ymf709_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フォーマット非従順、値を無視
      ymf709_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)
      //ymf709_regset_write(cs_temp, D1R_D1R + ch_temp + (op_temp * 8), AMS_EN, vced_ram[vced_itr][vced_pn]);
      if(vced_ram[vced_itr][vced_pn] == 1)
      {
        ymf709_regset_write(cs_temp, AMS_D2R + ch + (op_temp * 8), AMS, vced_ram[vced_itr][61]);
      }else{
        ymf709_regset_write(cs_temp, AMS_D2R + ch + (op_temp * 8), AMS, 0);
      }
      break;
    case 9: // 9:KVS(0-7)
      // VCEDフォーマット非従順、値を無視
      break;
    case 10: // 10:OUT(0-99)
      // VCEDフォーマット非従順、本来は0~99を0~127にスケーリングしなければいけない。
      ymf709_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) (予想)
      ymf709_regset_write(cs_temp, DT1_MUL + ch_temp + (op_temp * 8), MUL, vced_ram[vced_itr][vced_pn] >> 2);
      //YMF709はDT2が無いため無視
      //ymf709_regset_write(cs_temp, AMS_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として入力
      ymf709_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)
      ymf709_regset_write(cs_temp, LR_FB_CON + ch_temp, CONECT, vced_ram[vced_itr][vced_pn]);
      break;
    case 53: // 53:FBL(0~7)
      ymf709_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)
      {
        ymf709_regset_write(cs_temp, LFRQ, 0xFF, vced_ram[vced_itr][vced_pn]);
        // LFOをリセットするチャンネルに登録
        ymf709_lfo_rst_en[ch] = 1;
      }
      else
      {
        // LFOをリセットするチャンネル解除
        ymf709_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)
      {
        ymf709_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)
      {
        ymf709_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)
      ymf709_regset_write(cs_temp, CT_W, LFO_W, vced_ram[vced_itr][vced_pn]);
      break;
    case 60: // 60:PMS(0~7)
      //ymf709_regset_write(cs_temp, PMS_AMS + ch_temp, PMS, vced_ram[vced_itr][vced_pn]);
      break;
    case 61: // 61:AMS(0~7)
      //ymf709_regset_write(cs_temp, PMS_AMS + ch_temp, AMS, vced_ram[vced_itr][vced_pn]);
      if(vced_ram[vced_itr][8] == 1)
      {
        ymf709_regset_write(cs_temp, AMS_D2R + ch + OP1_A, AMS, vced_ram[vced_itr][vced_pn]);
      }else{
        ymf709_regset_write(cs_temp, AMS_D2R + ch + OP1_A, AMS, 0);
      }
      if(vced_ram[vced_itr][21] == 1)
      {
        ymf709_regset_write(cs_temp, AMS_D2R + ch + OP2_A, AMS, vced_ram[vced_itr][vced_pn]);
      }else{
        ymf709_regset_write(cs_temp, AMS_D2R + ch + OP2_A, AMS, 0);
      }
      if(vced_ram[vced_itr][34] == 1)
      {
        ymf709_regset_write(cs_temp, AMS_D2R + ch + OP3_A, AMS, vced_ram[vced_itr][vced_pn]);
      }else{
        ymf709_regset_write(cs_temp, AMS_D2R + ch + OP3_A, AMS, 0);
      }
      if(vced_ram[vced_itr][47] == 1)
      {
        ymf709_regset_write(cs_temp, AMS_D2R + ch + OP4_A, AMS, vced_ram[vced_itr][vced_pn]);
      }else{
        ymf709_regset_write(cs_temp, AMS_D2R + ch + OP4_A, AMS, 0);
      }
      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)(ymf709_parameter[inst] + 0));
  // AMD
  vced_ram[vced_itr][57] = pgm_read_byte_near((int)(ymf709_parameter[inst] + 1));
  // PMD
  vced_ram[vced_itr][56] = pgm_read_byte_near((int)(ymf709_parameter[inst] + 2));
  // WF
  vced_ram[vced_itr][59] = pgm_read_byte_near((int)(ymf709_parameter[inst] + 3));
  // NFRQ
  //無視

  //PAN(bit7,bit6)
  //無視
  //FL
  vced_ram[vced_itr][53] = pgm_read_byte_near((int)(ymf709_parameter[inst] + 6));
  //CONECT
  vced_ram[vced_itr][52] = pgm_read_byte_near((int)(ymf709_parameter[inst] + 7));
  //PMS
  vced_ram[vced_itr][60] = pgm_read_byte_near((int)(ymf709_parameter[inst] + 8));
  //AMS
  vced_ram[vced_itr][61] = pgm_read_byte_near((int)(ymf709_parameter[inst] + 9));
  //SLOT
  //無視
  //NE
  //無視


  // OP1-M1-AR
  vced_ram[vced_itr][0] = pgm_read_byte_near((int)(ymf709_parameter[inst] + 12));
  // OP1-M1-D1R
  vced_ram[vced_itr][1] = pgm_read_byte_near((int)(ymf709_parameter[inst] + 13));
  // OP1-M1-D2R
  vced_ram[vced_itr][2] = pgm_read_byte_near((int)(ymf709_parameter[inst] + 14));
  // OP1-M1-RR
  vced_ram[vced_itr][3] = pgm_read_byte_near((int)(ymf709_parameter[inst] + 15));
  // OP1-M1-D1L
  vced_ram[vced_itr][4] = pgm_read_byte_near((int)(ymf709_parameter[inst] + 16));
  // OP1-M1-TL
  vced_ram[vced_itr][10] = pgm_read_byte_near((int)(ymf709_parameter[inst] + 17));
  // OP1-M1-KS
  vced_ram[vced_itr][6] = pgm_read_byte_near((int)(ymf709_parameter[inst] + 18));
  // OP1-M1-MUL-DT2
  vced_ram[vced_itr][11] = (pgm_read_byte_near((int)(ymf709_parameter[inst] + 19)) << 2) | pgm_read_byte_near((int)(ymf709_parameter[inst] + 21));
  // OP1-M1-DT1
  vced_ram[vced_itr][12] = pgm_read_byte_near((int)(ymf709_parameter[inst] + 20));
  // OP1-M1-AMS_EN
  vced_ram[vced_itr][8] = pgm_read_byte_near((int)(ymf709_parameter[inst] + 22)) >> 7;
 
 
  // OP2-C1-AR
  vced_ram[vced_itr][13] = pgm_read_byte_near((int)(ymf709_parameter[inst] + 23));
  // OP2-C1-D1R
  vced_ram[vced_itr][14] = pgm_read_byte_near((int)(ymf709_parameter[inst] + 24));
  // OP2-C1-D2R
  vced_ram[vced_itr][15] = pgm_read_byte_near((int)(ymf709_parameter[inst] + 25));
  // OP2-C1-RR
  vced_ram[vced_itr][16] = pgm_read_byte_near((int)(ymf709_parameter[inst] + 26));
  // OP2-C1-D1L
  vced_ram[vced_itr][17] = pgm_read_byte_near((int)(ymf709_parameter[inst] + 27));
  // OP2-C1-TL
  vced_ram[vced_itr][23] = pgm_read_byte_near((int)(ymf709_parameter[inst] + 28));
  // OP2-C1-KS
  vced_ram[vced_itr][19] = pgm_read_byte_near((int)(ymf709_parameter[inst] + 29));
  // OP2-C1-MUL-DT2
  vced_ram[vced_itr][24] = (pgm_read_byte_near((int)(ymf709_parameter[inst] + 30)) << 2) | pgm_read_byte_near((int)(ymf709_parameter[inst] + 32));
  // OP2-C1-DT1
  vced_ram[vced_itr][25] = pgm_read_byte_near((int)(ymf709_parameter[inst] + 31));
  // OP2-C1-AMS_EN
  vced_ram[vced_itr][21] = pgm_read_byte_near((int)(ymf709_parameter[inst] + 33)) >> 7;
 
 
  // OP3-M2-AR
  vced_ram[vced_itr][26] = pgm_read_byte_near((int)(ymf709_parameter[inst] + 34));
  // OP3-M2-D1R
  vced_ram[vced_itr][27] = pgm_read_byte_near((int)(ymf709_parameter[inst] + 35));
  // OP3-M2-D2R
  vced_ram[vced_itr][28] = pgm_read_byte_near((int)(ymf709_parameter[inst] + 36));
  // OP3-M2-RR
  vced_ram[vced_itr][29] = pgm_read_byte_near((int)(ymf709_parameter[inst] + 37));
  // OP3-M2-D1L
  vced_ram[vced_itr][30] = pgm_read_byte_near((int)(ymf709_parameter[inst] + 38));
  // OP3-M2-TL
  vced_ram[vced_itr][36] = pgm_read_byte_near((int)(ymf709_parameter[inst] + 39));
  // OP3-M2-KS
  vced_ram[vced_itr][32] = pgm_read_byte_near((int)(ymf709_parameter[inst] + 40));
  // OP3-M2-MUL-DT2
  vced_ram[vced_itr][37] = (pgm_read_byte_near((int)(ymf709_parameter[inst] + 41)) << 2) | pgm_read_byte_near((int)(ymf709_parameter[inst] + 43));
  // OP3-M2-DT1
  vced_ram[vced_itr][38] = pgm_read_byte_near((int)(ymf709_parameter[inst] + 42));
  // OP3-M2-AMS_EN
  vced_ram[vced_itr][34] = pgm_read_byte_near((int)(ymf709_parameter[inst] + 44)) >> 7;
 
 
  // OP4-C2-AR
  vced_ram[vced_itr][39] = pgm_read_byte_near((int)(ymf709_parameter[inst] + 45));
  // OP4-C2-D1R
  vced_ram[vced_itr][40] = pgm_read_byte_near((int)(ymf709_parameter[inst] + 46));
  // OP4-C2-D2R
  vced_ram[vced_itr][41] = pgm_read_byte_near((int)(ymf709_parameter[inst] + 47));
  // OP4-C2-RR
  vced_ram[vced_itr][42] = pgm_read_byte_near((int)(ymf709_parameter[inst] + 48));
  // OP4-C2-D1L
  vced_ram[vced_itr][43] = pgm_read_byte_near((int)(ymf709_parameter[inst] + 49));
  // OP4-C2-TL
  vced_ram[vced_itr][49] = pgm_read_byte_near((int)(ymf709_parameter[inst] + 50));
  // OP4-C2-KS
  vced_ram[vced_itr][45] = pgm_read_byte_near((int)(ymf709_parameter[inst] + 51));
  // OP4-C2-MUL-DT2
  vced_ram[vced_itr][50] = (pgm_read_byte_near((int)(ymf709_parameter[inst] + 52)) << 2) | pgm_read_byte_near((int)(ymf709_parameter[inst] + 54));
  // OP4-C2-DT1
  vced_ram[vced_itr][51] = pgm_read_byte_near((int)(ymf709_parameter[inst] + 53));
  // OP4-C2-AMS_EN
  vced_ram[vced_itr][47] = pgm_read_byte_near((int)(ymf709_parameter[inst] + 55)) >> 7;
 
 
  vced_ram[vced_itr][62] = pgm_read_byte_near((int)(ymf709_parameter[inst] + 56));//音程
}







YM2151用に作ったものを一部変更しただけのプログラムです。
DT2とLFOの位相変調周りのレジスタアクセスを無効にしています。



上記動画で使用した音色パラメータを置いておきます。


0 件のコメント:

コメントを投稿