;------------------------------------------------------------------------------
; MidiTalk
; Ver.0.96 2022/08/31 チューニングをシステムパラメータからパートパラメータに変更
;                     パート用チューニングをSysExに追加
;                     従来のチューニングSysExは互換性のためパートチューニングの一括変更として動作させる
; Ver.0.95 2020/02/24 FMの現在の音色レジスタをダンプするSysExを追加。
;		      レジスタダンプの処理の一部を共通化、サブルーチンとして分離。
;		      ネイティブ形式の音色情報のSSG-EGがレジスタダンプとMidiTalkコントローラで一致していなかった。
; Ver.0.94 2019/11/2 リセットのモードに応じて受信するプログラムチェンジの番号を切り替えるようにした。Mono:120-127,125-127 Poly:0-7,0-3
; Ver.0.93 2019/5/1 event_noteoff内でのループ省略カウンタTMP01のチェック手順を見直し、ループの時間を短縮した。
;                    チェックアルゴリズムの変更だけなので、Blinkenlightsに影響は出ない。
; Ver.0.92 2019/4/29 SP0256の日本語発音を追加
; Ver.0.91 2018/9/23 SP0256の発音チューニングが少し上にずれているので、SSG/FMの音程テーブルも440/444Hzに変更。
; Ver.0.90 2018/9/19 ポリモードでリセットした時にパート2をエンベロープSSG用に初期化するようにした。
; Ver.0.89 2018/9/18 ボイス変更の優先度の再計算方法を変更した。
;                    演奏中にボイスを切り替えても鳴りっぱなしや優先度の重複を起こさなくなった。
;                    現在判明している問題事項はすべて解消された。 
; Ver.0.88b 2018/9/18 チャンネル変更でリセットオールコントローラ、オールノートオフ、オールサウンドオフの等価処理を行うようにした。
;                     演奏中にチャンネルを切り替えても音が鳴りっぱなしになることが無くなった。
; Ver.0.88a 2018/9/18 リセットオールコントローラをパートチャンネル変更に使うため処理部分を分離。
; Ver.0.88 2018/6/6 CTRL_EPとCTRL_NPでSSG以外のボイスもループ対象にしていたため、YMZの関係ないレジスタに不要な値を書き込んでいた。
; Ver.0.87 2018/6/3 Neko Projectがリアルタイムメッセージを送出しないので、クロック・スタート・コンティニュー・ストップの代替用コントロールチェンジを作った。
; Ver.0.86 2018/5/23 ポリモードリセットの初期値にFMとSSGのフラグをセットし忘れていた。
; Ver.0.85 2018/5/16 パートに直接エンベロープシェイプを送信するSysExを追加。
; Ver.0.84 2016/3/26 パートに直接Vol,Exp,Bend,Sensを送信するSysExを追加。ユニゾンやデチューン用のレイヤーパートを作りやすくなった。
; Ver.0.83 2016/3/21 ピッチベンドの分解能を128段階に変更。音程テーブルを4倍に拡張。リセットデータとSP0256のフレーズデータを移動。
; Ver.0.82 2015/5/11 FMとSSGのレベル補正をパートごとに適用するように変更。レベル補正のコマンド番号を変更。
;		     FLAG1-METRO_RUNのフラグビットの場所を変更。
;		     ピッチベンドをフルアップにした時にSSGのノイズが一番低くなるのを直した。
; Ver.0.81 2014/10/21 SYSEXをページ2に移動した。
;		      チャンネルプレッシャーを実装した。チャンネルのノートオン中のボイスに対して、ベロシティを相対的に加減算して音量を再送信する。
;		      ベロシティを受信しない場合はチャンネルプレッシャも動作させない。
; Ver.0.80 2014/8/14 SP0256のクロック回路を変更。クロックの切り替えをノート番号では無くピッチベンドで行うように変更。
;		      FLAGからPREV_CLOCKを廃止し、SSG_LEVELをFLAGに併合。FLAG2を廃止、FLAG3をPFLAGに名称変更。
; Ver.0.79 2014/5/17 SSGエンベロープ系CC番号割り当て変更
; Ver.0.78 2014/4/26 FLAG2をFLAG3とし、FLAG2をFLAG1の拡張とした。
;		     SSGカーブ補正ON/OFFエクスクルーシブを付けた。
; Ver.0.77 2014/3/29 SP0256のクロックを2.46MHzから4MHzに変更したのにあわせて、クロックビットを反転した。
; Ver.0.76 2014/1/4 ピッチベンド7FFFの時に、強制的に8000に書き換えて1足りない計算をさせるようにした。これでフルピッチアップが実現できた。
; Ver.0.75 2013/11/25 システムリセットにリセットモードをつけて、リセット後の状態(モノ・ポリ)を選択出来るようにした。
;		      各社リセットをかけると、モノモードでリセットをかかるようにした。
; Ver.0.74 2013/11/18 初期のボイス割り当てを変更、Vo0-2→Pt0,Vo369C→Pt1,Vo4578ABDE→Pt2,VoF→PtF
; Ver.0.73 2013/8/31 全てのSYSEXの処理完了時、EX_ADDR2のチェックを必ず行い、アドレスインクリメントが必要ないものはSYSEX_UNMATCHで終わるようにした。
;		     system_resetでFIFOSTATUSをクリアし忘れていた。
; Ver.0.72 2013/8/30 SYSEX処理ルーチン中で、有効アドレス長のチェックを行っていなかったものがあった。
;		     FMパラメータをプリセットに保存するSYSEXをつけた。
;		     FMプリセットをダンプするSYSEXをつけた。
;		     メモリダンプのSYSEXアドレス番号を7Eに変更。
; Ver.0.71 2013/8/28 loadfmprogram内のFSRインクリメントの場所がややこしいので変更。
;		     DR,SR,SSG-EGのパラメータもRAMに保存するようにした。今後EEPROMに書き込むようにしたい。
; Ver.0.70 2013/8/24 ページ0の未使用RAMを全てFIFOに割り当てた。MIDI用6バイト、SP0256用32バイトになった。
;		     変数宣言でFIFOのアドレスを変更した時、LEDの点灯条件を自動的に計算するようにした。
; Ver.0.69 2013/7/24 Volume,Expression,PitchBendを相対的に変更するCCの番号を#39,43,41に変更
; Ver.0.68 2013/4/16 Volume,Expression,PitchBendを相対的に変更するCC#87,88,89を定義
;		     ボリュームかエクスプレッションが0でFMの音量補正がONの時に音漏れするのを直した。
;		     プログラムページ0の空きが無くなったため、コントロールチェンジテーブルをページ1に移した。
; Ver.0.67 2013/4/15 FM音源の音量補正を切り替えられるようにSYSEXを実装した。
; Ver.0.66 2012/12/30 CC#35を新設。FMで発音させるSLOTを選択する。
; Ver.0.65 2012/10/8 MIDIとSPのバッファ使用LEDを入れ替え。MIDIフルのLEDは正常な状態に復帰するまでラッチするようにした。
; Ver.0.64 2012/7/9 SSG Prog126にノート番号をNPに代入するノイズを追加した。ピッチベンドでも変更できる(センシティビティは無視)。PART_NOTE_TO_NP新設。
; Ver.0.63 2012/7/5 SUPPRESS_SHAPESETフラグを追加。Ver.0.59の動作を修正(VOL,EXP,RESETALLCTRLでエンベロープの再セットを抑制する)。
; Ver.0.62 2012/6/23 PART_RXPROGRAMフラグと処理を追加。DOOM用^^
; Ver.0.61 2012/6/17 新音色追加。プログラム変更無し。
; Ver.0.60 2012/5/29 各社リセット受信ルーチンを作成。で、そのリセット自体を禁止するSYSEXを作成。
;		     TONEERRORフラグ廃止(まったく使っていない)。METRO_RUN,TUNINGフラグ移動。
; Ver.0.59 2012/5/27 PART_RXVOLUMEとPART_RXEXPRESSIONを反映するようにした。値は受信しないが音量の再送信がかかるため、SSGのエンベロープがリトリガされる。
; Ver.---- 2012/5/27 MidiTalk Controller作成終了。速過ぎるだろ…
; Ver.---- 2012/5/26 VB2005でコントロール用のソフトを作成。PART_RXVOLUMEとPART_RXEXPRESSIONがかなり以前から反映されていないことが判明。今ごろなぜ…
; Ver.0.58 2012/5/24 Ver.0.43で無効にしたノートオフの優先度変更アルゴリズムを変更し、再度有効化させた。いよいよ完成か？
; Ver.0.57 2012/5/20 holdoffのコメントを変更。プログラムの変更はなし。
; Ver.0.56 2012/5/19 帯域LEDの個数を変更。FIFOの割り当てサイズを自動的に再計算するように変更。ただし再アセンブルは必要。(安定版)
; Ver.0.55 2012/5/17 TL/SLの反転(Ver.0.49)を元に戻した。NPをCC#86に移動。CC#85にエンベロープ即時反映を追加。
; Ver.---- 2012/5/13 基板完成。
; Ver.---- 2012/5/12 パターン完成。基板の現像を終えたところで裏表が逆に気付く。
; Ver.---- 2012/5/5 アナログ回路が完成。
; Ver.0.54 2012/4/28 なぜか0xFFを送るソフト(spc2midi)が存在するため、0xFFイベントのリセットをコメントアウト。
; Ver.0.53 2012/4/22 SSGVOLUMEの対数変換テーブルを変更。FMの音量も変換したい…(安定版)
; Ver.0.52 2012/4/19 受信割り込み時、PCLATHをクリアしていなかったためMIDIQUEUEへジャンプする時に停止する時があった。
; Ver.0.51 2012/4/15 CC#121作成。CC#7,#11,#121用音量セットルーチンを分離。
;		     CC#64,#121用ホールドオフルーチンを分離。ピッチベンド,CC#121用ピッチ再送信ルーチンを分離。
;		     SP0256の音素配列が使いにくいので、テーブルで変換するようにした。
;		     FIFOのバッファフルLEDの消灯動作が正しくなかった。
;		     全てのルーチンを実装完了。
; Ver.0.50 2012/4/14 CC#64作成。
;		     ホールド中にピッチベンドをかけるとVOICE_NOTEOFFを除去していないため正しい音にならなかった。
;		     ホールド中にボリューム･エクスプレッションをかけるとVOICE_SUSTAINを除去していないため正しい音にならなかった。
;		     FMのボイスはリリース音があるため、ノートオフされていてもピッチベンド・ボリューム･エクスプレッションをかけるようにした。
;		     ピッチベンドのボイスループを降順検索に変えた。
;		     SYSEXの番号を変更。SYX#00にシステムリセットを割り当て。
;		     音源ICリセット(SYX#7F)を削除。レジスタデバッグをSYX#7Fに割り当てページ1に移動。
; Ver.0.49 2012/4/12 TLとSLで最大と最小の値を反転させた。
; Ver.0.48 2012/4/11 SLとSRのコントロールチェンジを入れ替え。SSG-EGが0〜8の範囲になっていなかった。
; Ver.0.47 2012/4/10 loadfmprogramをプログラムチェンジ120〜127に適用。
; Ver.0.46 2012/4/9 loadfmprogramを作成。
; Ver.0.45 2012/4/8 ssgchannelを作成し、同様の処理を行っているところを省く。
;		    CTRL_NP,CTRL_EP,CTRL_VOLUME,CTRL_EXPRESSION作成。
; Ver.0.44 2012/4/7 FMのパラメータが所定のアドレスに保存されていなかった。
; Ver.0.43 2012/4/6 コントロールチェンジでFMのパラメータ変更ができるようになった。MC-8の動きがおかしい。
; 		    ノートオフで優先度を更新すると前回と同じボイスに発音処理されてリリース音が伸びないので、優先度の更新をしないようにした。
;		    発音中にアルゴリズムを切り替えるとfm_setvelocityでTLが書き換えられるため、元のアルゴリズムに戻すと音がおかしくなるのは仕様とする。
;		    音を元に戻すには、モジュレータになっているOPのTLを書き換えれば直る。
; Ver.0.42 2012/4/5 Vol,Expルーチン共通化のためVer.0.36の変更を元に戻した。
; Ver.0.41 2012/4/4 ノートオフとボイスオフ処理を分離し、CC#120,123を作成。バッチリ音が消える！感激。
; Ver.0.40 2012/4/3 event_noteoffで優先度処理とボイスオフ処理を分離できるように整理した。(オールノートオフに利用)
; Ver.0.39 2012/4/1 パートミュートはパートチャンネルと同時にチェックするようにした
; Ver.0.38 2012/3/31 CC#06,41,98,99,100,101を実装。プログラムチェンジからエンベロープを分離。
; Ver.0.37 2012/3/29 プログラムチェンジにエンベロープシェイプを組み合わせた。
; Ver.0.36 2012/3/28 FM音源のPART_RXVELOCITYがOFFの時TLを送信しないようにした。
;          2012/3/27 PC-9801-26K中古を購入。直ってよかった。
; Ver.0.35 2012/3/25 いくつかのシステムエクスクルーシブをページ1に移動させた。ベロシティ・ボリューム・エクスプレッション・チューニングフラグをエクスクルーシブに追加。
; Ver.0.34 2012/3/24 ピッチベンドの処理を追加した。YM2203を壊してしまった。メトロノームが鳴らないと思ったらすごく発熱していた。
; Ver.0.33 2012/3/23 EEPROMに保存した音源パラメータをシステムリセットでロードするようにした。プログラムチェンジがパートごとに反映されていなかった。
; Ver.0.32 2012/3/20 0.27のソースからノートオン・ノートオフを引っ張ってきて鳴るように戻した。(安定版)
; Ver.0.31 2012/3/20 toneshift廃止ssg_settoneに併合。ssgvolume廃止ssg_setvelocityに併合。
;		     音程、ベロシティ処理とレジスタセットを関数に分離。PART,VOICE変数を追加。
;		     ノートオフにサスティンフラグを反映。一時変数の使い方を変更。
;		     オペレータのデータの並びを1234から4231に変更。
;		     FMのTL送信をループに変更。
; Ver.0.30 2012/3/19 いろいろ手を加えたら鳴らなくなった。
; Ver.0.29 2012/3/18 FM,SSGのノートオンでボリューム・エクスプレッション・ミュートフラグ・ピッチベンドを反映。
; Ver.0.28 2012/3/17 新しいフラグ等の定義を追加する。
; Ver.0.27 2012/3/14 SysExでデバッグ用にレジスタの値をSPで発音できるようにした。
; Ver.0.26 2012/3/13 SysExでSP-FIFOに入れる77hを定義した。
; Ver.0.25 2012/3/12 SysExでPART_CHANNELとVOICE_PARTを変更できるようにした。
; Ver.0.24 2012/3/11 SysExのデータバイトを1バイトづつ受信するようにした。
; Ver.0.23 2012/3/11 ssgwriteの上位4ビットをフラグ形式から数値0〜3指定に変更した
; Ver.0.22 2012/3/10 SSG,FM全音駆動成功、SSG用プログラムチェンジ実装
; Ver.0.21 2012/3/10 FM音源1音3チャンネル駆動成功
; Ver.0.20 2012/3/4 fmwriteでCS/WRの立ち上がり前にデータを取り込む現象が見られたため、A0の前にPORTBへ出力するように変更。FMついに完成〜。
; Ver.0.19 2012/3/4 tonecalc,toneshiftを修正、FM音源を鳴らそうとしたがTLに2E・2Fを入れると異常な音が出力されるので、いったん元に戻す。
; Ver.0.18 2012/3/1 MIDI FIFOがあふれた時の処理を割り込みルーチン内に作成。
; Ver.0.17 2012/2/26 変数の配置を修正。toneload,toneshift,ssgvolumeを作成。モノでSSGを駆動させて発音させた。ついに完成〜。
; Ver.0.16 2012/2/19 最終アンプまでの回路が完成。YM3014から出た波形が歪む。原因がわからない。
; Ver.0.15 2012/2/18 16bitの四則演算ルーチンを作成
; Ver.0.14 2012/2/15 メトロノームをエクスクルーシブで拍子と中拍を2個指定できるようにした。拍の変更は次の小節から反映するようにした。
; Ver.0.13 2012/2/14 MIDIクロックのメトロノームもできたけど結構変拍子の曲が多いので結局使い道が無いか…消すかな…
; Ver.0.12 2012/2/13 FM音源のSSGもすんなり鳴った
; Ver,0.11 2012/2/11 fmwriteのビジーチェックを発音前に変更
; Ver.0.10 2012/2/5 エクスクルーシブのアドレスを0x00〜0x12の間で正しく認識するように変更
; Ver.0.9 2012/1/29 エクスクルーシブのみでSP0256を駆動、いきなりマトモに動いてびっくりした
; Ver.0.8 2012/1/16 マルチパート用ノートオフルーチン作成、全パートでノートオフさせると大変時間がかかる
; Ver.0.7 2012/1/12 処理が間に合いそうに無いので16バイト(5.12ms分)の受信FIFOを付けた
; Ver.0.6 2012/1/9 エクスクルーシブ解析・マルチパート用ノートオンルーチン作成
; Ver.0.5 2012/1/8 MIDIイベント処理ルーチン作成
; Ver.0.4 2012/1/7 fmwriteでYM2203のSSG駆動チェック
; Ver.0.3 2012/1/4 fmwrite作成
; Ver.0.2 2012/1/3 spwrite作成
; Ver.0.1 2012/1/2 ssgwrite作成
; Ver.0.0 2012/1/1 基本回路、音程テーブル作成
;------------------------------------------------------------------------------
; IRP,RP1,RP0を切り替える所で◆ RP=をコメントに置く
; PCLATHを切り替えるところで■ PCLATHをコメントに置く
;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
; デバイス	PIC16F877A
; 動作周波数	20MHz
;------------------------------------------------------------------------------
	LIST	P=16F877A,R=DEC,N=0
	INCLUDE	"P16F877A.INC"
	ERRORLEVEL	0,-302,-307
	__CONFIG	0x3F72

;------------------------------------------------------------------------------
; 変数宣言 ページ0
;------------------------------------------------------------------------------
; 受信データの処理用
MIDI		EQU	0x20		; 受信したMIDIオクテット
EVENT		EQU	0x21		; 最後のイベントNo
PARAM1		EQU	0x22		; EVENTに続くパラメータ
PARAM2		EQU	0x23		; PARAM1に続くパラメータ
CHANNEL		EQU	0x24		; 最後のMIDIイベントから分離したチャンネル情報
EX_ADDR1	EQU	0x25		; SysEX用アドレス(PARAM1)自動インクリメントなし
EX_ADDR2	EQU	0x26		; SysEX用アドレス(PARAM2)自動インクリメント対象、SYSEX_RESET用のメーカー判別チェック状態
EX_DATA		EQU	0x27		; 前回のSysExデータ

; メトロノームの処理用
CLOCK_COUNT	EQU	0x28		; MIDIクロックカウント
CLOCK_LIMIT	EQU	0x29		; メトロノーム間隔
BEAT_COUNT	EQU	0x2A
BEAT_LIMIT	EQU	0x2B
MIDDLE_BEAT1	EQU	0x2C		; 中拍カウント
MIDDLE_BEAT2	EQU	0x2D

; ノートの処理用
NOTE		EQU	0x2E		; ノート番号
PITCHBEND	EQU	0x2F		; ピッチベンドMSB
BENDSENS	EQU	0x30		; ピッチベンドセンシティビティ
TONE_H		EQU	0x31		; 表引き用トーン番号、実トーンデータ
TONE_L		EQU	0x32
OCTAVE		EQU	0x33		; オクターブ

; ベロシティの処理用
VELOCITY	EQU	0x34		; ベロシティ
VOLUME		EQU	0x35		; ベロシティ計算用
EXPRESSION	EQU	0x36		; ベロシティ計算用

PART		EQU	0x37		; 引数
VOICE		EQU	0x38		; 引数
SSGCHIP		EQU	0x39		; ssgchannelの戻り値
SSGCHANNEL	EQU	0x3A		; ssgchannelの戻り値

EEPADDR		EQU	0x3B		; プログラムチェンジロード用

; フラグ変数
FLAG1		EQU	0x3C		; システムリセットで影響を受けるフラグ
PFLAG		EQU	0x3D		; システムリセットがかかってもリセットされないフラグ

; 音源ICのデータ転送用
WRITE_ADDR	EQU	0x3E		; FMレジスタアドレス・SSGレジスタアドレス/CS
WRITE_DATA	EQU	0x3F		; FM/SSG/SPデータ

; FIFOバッファと処理用変数
READPTR1	EQU	0x40		; FIFOリードポインタ
WRITEPTR1	EQU	0x41		; FIFOライトポインタ
USEDSIZE1	EQU	0x42		; FIFO使用サイズ

READPTR2	EQU	0x43
WRITEPTR2	EQU	0x44
USEDSIZE2	EQU	0x45

READDATA	EQU	0x46		; 読み込みデータ作業領域
WRITEDATA1	EQU	0x47		; 書き込みデータ作業領域、割り込みで上書きされるので個別に用意する
WRITEDATA2	EQU	0x48
FIFOSTATUS	EQU	0x49		; FIFOステータスフラグ

					; 空きRAMが必要な場合は、FIFO領域を削ること。
FIFOBUF1	EQU	0x4A		; MIDIバッファ(ここを変更すると、アセンブル時に自動的にバッファのサイズが計算される)
FIFOBUF2	EQU	0x50		; SP0256バッファ(ここを変更すると、アセンブル時に自動的にバッファのサイズが計算される)
FIFOEND		EQU	0x70
; 一時使用変数
TMP00		EQU	0x70
TMP01		EQU	0x71
TMP02		EQU	0x72
TMP03		EQU	0x73
TMP10		EQU	0x74
TMP11		EQU	0x75
TMP12		EQU	0x76
TMP13		EQU	0x77
TMP20		EQU	0x78
TMP21		EQU	0x79
TMP22		EQU	0x7A
TMP23		EQU	0x7B

; 割り込み発生時のレジスタ退避領域
W_		EQU	0x7C		; Wレジスタ
STATUS_		EQU	0x7D		; STATUSレジスタ
PCLATH_		EQU	0x7E		; PCLATHレジスタ
FSR_		EQU	0x7F		; FSRレジスタ

;------------------------------------------------------------------------------
; TMPの個別用途変数宣言
;------------------------------------------------------------------------------
VAR1H		EQU	TMP20		; 割られる数MSB、商MSB
VAR1L		EQU	TMP21		; 割られる数LSB、商LSB
VAR2H		EQU	TMP12		; 割る数MSB
VAR2L		EQU	TMP13		; 割る数LSB
MODULO_H	EQU	TMP22		; 剰余MSB
MODULO_L	EQU	TMP23		; 剰余LSB
RELATIVE_LIMIT	EQU	TMP22		; TMP22[0] relative_addsubで上限を0x80に変更するフラグ
;------------------------------------------------------------------------------
; 変数宣言 ページ1 ボイスアサイナ関連
;------------------------------------------------------------------------------
PART_CHANNEL	EQU	0xA0		; 受信するチャンネル		(bit3-0)
					; パートミュートフラグ		(bit4)
					; ベロシティ受信フラグ		(bit5)
					; パートサスティン中フラグ	(bit6)
					; パートプログラムチェンジ受信フラグ (bit7)

PART_MAXVOICE	EQU	0xB0		; パートの最大ボイス数(自動計算)(bit4-0)

VOICE_PART	EQU	0xC0		; ボイスが割り当てられているパート(bit3-0)
					; ボイスミュートフラグ		(bit4)
					; パートごとのFMのTLレベル補正	(bit5)
					; パートごとのSSGの対数レベル補正(bit6)
					; パートごとのチューニング      (bit7)

VOICE_PRIORITY	EQU	0xD0		; ボイスの優先順位(自動計算)	(bit3-0)

VOICE_NOTE	EQU	0xE0		; ボイスのノート番号		(bit6-0)
					; ノートオフフラグ		(bit7)

;------------------------------------------------------------------------------
; 変数宣言 ページ2 ボイス・パート情報
;------------------------------------------------------------------------------
VOICE_VELOCITY	EQU	0x110		; ベロシティ			(bit6-0)
					; サスティン中ボイスフラグ	(bit7)

PART_VOLUME	EQU	0x120		; ボリューム			(bit6-0)
					; ボリューム受信フラグ		(bit7)

PART_EXPRESSION	EQU	0x130		; エクスプレッション		(bit6-0)
					; エクスプレッション受信フラグ	(bit7)

PART_PITCHBEND	EQU	0x140		; ピッチベンド			(bit7-0)

PART_BENDSENS	EQU	0x150		; ピッチベンドセンシティビティ	(bit5-0)
					; RPN-L受信フラグ		(bit6)
					; RPN-M受信フラグ		(bit7)

PART_ENVSHAPE	EQU	0x160		; SSGエンベロープシェイプ	(bit3-0)
					; SSGエンベロープ使用フラグ	(bit4)
					; SSGプログラムチェンジ		(bit6-5)
					; SSG NoteToNPフラグ		(bit7)

;------------------------------------------------------------------------------
; 変数宣言 ページ3 音源レジスタ・複数用途のビット保持用
; オペレータのデータは 4,2,3,1 の順番で配置すること
;------------------------------------------------------------------------------
DT_MULTI	EQU	0x190		; 4OP*3Ch
TL		EQU	0x19C		; 4OP*3Ch
KS_AR		EQU	0x1A8		; 4OP*3Ch
DR		EQU	0x1B4		; 4OP*3Ch
SR		EQU	0x1C0		; 4OP*3Ch
SL_RR		EQU	0x1CC		; 4OP*3Ch
SSG_EG		EQU	0x1D8		; 4OP*3Ch
FB_ALG		EQU	0x1E4		; 3Ch
SLOT		EQU	0x1E7		; 3Ch
SSG_ENABLE	EQU	0x1EA		; 4Chip

;空		EQU	0x1EE
;空		EQU	0x1EF
;------------------------------------------------------------------------------
; 定数・フラグ宣言
;------------------------------------------------------------------------------
LED_EVENT	EQU	0		; RA0 イベント処理中LED
LED_SPLEV1	EQU	1		; RA1 SPバッファ使用量LED
LED_SPLEV2	EQU	2		; RA2 SPバッファ使用量LED
LED_SPFULL	EQU	3		; RA3 SPバッファフルLED
LED_MIDIDATA	EQU	4		; RA4 MIDIデータありLED
LED_MIDIFULL	EQU	5		; RA5 MIDIバッファフルLED

FMBUSY		EQU	7		; RB7 FM BUSYフラグ

FMCS		EQU	3		; RC3 FM /CS
FMWR		EQU	4		; RC4 FM /WR
FMRD		EQU	5		; RC5 FM /RD
FMNOCS		EQU	B'00111000'	; FM /CS開放
FMWRCS		EQU	B'00100000'	; FM /WR/CS駆動
FMRDCS		EQU	B'00010000'	; FM /RD/CS駆動

LRQ		EQU	0		; RD0 SP /LRQ (IN)
SBY		EQU	1		; RD1 SP SBY  (IN)
ALD		EQU	2		; RD2 SP /ALD
A0		EQU	3		; RD3 FM/SSG A0
SSG1		EQU	4		; RD4 SSG-1 /WR/CS
SSG2		EQU	5		; RD5 SSG-2 /WR/CS
SSG3		EQU	6		; RD6 SSG-3 /WR/CS
SSG4		EQU	7		; RD7 SSG-4 /WR/CS

SSG_RESET	EQU	0		; RE0 FM/SSG /IC
SP_RESET	EQU	1		; RE1 SP /RESET
SP_OSC		EQU	2		; RE2 SPクロックセレクト 0=4.0 1=3.2

EX_PHASE1	EQU	0		; FLAG1-0 エクスクルーシブフェーズ
EX_PHASE2	EQU	1		; FLAG1-1 エクスクルーシブフェーズ
EX_PHASE4	EQU	2		; FLAG1-2 エクスクルーシブフェーズ
SUPPRESS_SHAPESET EQU	3		; FLAG1-3 エンベロープシェイプの再セットを抑制するフラグ
METRO_RUN	EQU	4		; FLAG1-4 メトロノーム実行中フラグ
FM_LEVEL	EQU	5		; FLAG1-5 FMのTLレベル補正(0=しない,1=する)
SSG_LEVEL	EQU	6		; FLAG1-6 SSGの対数レベル補正(0=しない,1=する)
TUNING		EQU	7		; FLAG1-7 チューニングフラグのロード値(toneloadの引数)


VENDOR_RESET	EQU	0		; PFLAG-0 各社リセットを受ける場合に1
SP_PHONETIC	EQU	1		; PFLAG-1 メモリダンプをフォネティックコードで行う
RESET_MODE	EQU	2		; PFLAG-2 system_resetの0:モノ 1:ポリモードを指定する

FIFO1EMPTY	EQU	0		; FIFOSTATUS-0 FIFO1読み出し時、データが無かった
FIFO1FULL	EQU	1		; FIFOSTATUS-1 FIFO1書き込み時、バッファが一杯だった
FIFO2EMPTY	EQU	4		; FIFOSTATUS-4 FIFO2読み出し時、データが無かった
FIFO2FULL	EQU	5		; FIFOSTATUS-5 FIFO2書き込み時、バッファが一杯だった
FIFO1SIZE	EQU	FIFOBUF2-FIFOBUF1 ; FIFOバッファのサイズ
FIFO2SIZE	EQU	FIFOEND-FIFOBUF2; FIFOバッファのサイズ

EVENT_RCVD	EQU	7		; EVENT-7 EVENTを受信した 1=受信済み
PARAM_NOTRCVD	EQU	7		; PARAMx-7 PARAMxを受信していない 0=受信済み

PHASE_ID	EQU	0		; FLAG1-[210] ID受信フェーズ
PHASE_ADDR	EQU	1		; FLAG1-[210] アドレス受信フェーズ
PHASE_DATA	EQU	2		; FLAG1-[210] データ受信フェーズ
PHASE_IGNORE	EQU	3		; FLAG1-[210] 無視フェーズ
PHASE_RESET	EQU	4		; FLAG1-[210] メーカー別リセット検出モード

PART_MUTE	EQU	4		; PART_CHANNEL-4 パートミュートフラグ
PART_RXVELOCITY	EQU	5		; PART_CHANNEL-5 ベロシティ受信フラグ
PART_SUSTAIN	EQU	6		; PART_CHANNEL-6 サスティンコントロールチェンジフラグ
PART_RXPROGRAM	EQU	7		; PART_CHANNEL-7 パートプログラムチェンジ受信フラグ

VOICE_MUTE	EQU	4		; VOICE_PART-4 ボイス不使用フラグ
PART_FM_LEVEL	EQU	5		; VOICE_PART-5 パートごとのFMのTLレベル補正
PART_SSG_LEVEL	EQU	6		; VOICE_PART-6 パートごとのSSGの対数レベル補正
PART_TUNING	EQU	7		; VOICE_PART-7 パートごとのチューニング周波数切り替え(0=440,1=444)

VOICE_NOTEOFF	EQU	7		; VOICE_NOTE-7 ノートオフフラグ

VOICE_SUSTAIN	EQU	7		; VOICE_VELOCITY-7 サスティン中ボイスフラグ

PART_RXVOLUME	EQU	7		; PART_VOLUME-7 ボリューム受信フラグ

PART_RXEXPRESSION EQU	7		; PART_EXPRESSION-7 エクスプレッション受信フラグ

PART_RPNL	EQU	6		; PART_BENDSENS-6 RPN-L=0 受信フラグ
PART_RPNM	EQU	7		; PART_BENDSENS-7 RPN-M=0 受信フラグ

PART_USEENV	EQU	4		; PART_ENVSHAPE-4 SSGエンベロープ使用フラグ
PART_PROG_NOISE	EQU	5		; PART_ENVSHAPE-5 SSGプログラムチェンジ ノイズ
PART_PROG_BOTH	EQU	6		; PART_ENVSHAPE-6 SSGプログラムチェンジ トーン+ノイズ
PART_NOTE_TO_NP	EQU	7		; PART_ENVSHAPE-7 SSGノート番号をNPに代入するフラグ

;------------------------------------------------------------------------------
; SP0256基本発音テーブル
;------------------------------------------------------------------------------
PA1		EQU	0
PA2		EQU	1
PA3		EQU	2
PA4		EQU	3
PA5		EQU	4
OY		EQU	5
AY		EQU	6
EH		EQU	7
KK3		EQU	8
PP		EQU	9
JH		EQU	10
NN1		EQU	11
IH		EQU	12
TT2		EQU	13
RR1		EQU	14
AX		EQU	15
MM		EQU	16
TT1		EQU	17
DH1		EQU	18
IY		EQU	19
EY		EQU	20
DD1		EQU	21
UW1		EQU	22
AO		EQU	23
AA		EQU	24
YY2		EQU	25
AE		EQU	26
HH1		EQU	27
BB1		EQU	28
TH		EQU	29
UH		EQU	30
UW2		EQU	31
AW		EQU	32
DD2		EQU	33
GG3		EQU	34
VV		EQU	35
GG1		EQU	36
SH		EQU	37
ZH		EQU	38
RR2		EQU	39
FF		EQU	40
KK2		EQU	41
KK1		EQU	42
ZZ		EQU	43
NG		EQU	44
LL		EQU	45
WW		EQU	46
XR		EQU	47
WH		EQU	48
YY1		EQU	49
CH		EQU	50
ER1		EQU	51
ER2		EQU	52
OW		EQU	53
DH2		EQU	54
SS		EQU	55
NN2		EQU	56
HH2		EQU	57
OR		EQU	58
AR		EQU	59
YR		EQU	60
GG2		EQU	61
EL		EQU	62
BB2		EQU	63

;------------------------------------------------------------------------------
; 電源ON
;------------------------------------------------------------------------------
	ORG	0
	GOTO	POWER_ON
;------------------------------------------------------------------------------
; 割り込み分岐
; 割り込み処理は次のオクテットが来るまでの320us(1600ステップ)以内に完了すること
;------------------------------------------------------------------------------
	ORG	4			; 割り込みベクタ
	MOVWF	W_			; Wセーブ
	SWAPF	STATUS,W		; STATUSセーブ
	MOVWF	STATUS_
	MOVF	PCLATH,W		; PCLATHセーブ
	MOVWF	PCLATH_
	MOVF	FSR,W			; FSRセーブ
	MOVWF	FSR_

	BCF	STATUS,RP0		; ◆ RP=0
	BCF	STATUS,RP1
	CLRF	PCLATH
	BTFSS	FIFOSTATUS,FIFO1FULL	; 前回バッファがあふれていない場合は、そのままバッファに入れる
	 GOTO	MIDIQUEUE

	MOVLW	0x80			; 前回バッファあふれた場合は不正な演奏になるため、
	SUBWF	RCREG,W			; 0x80以上が来るまで0x00-0x7Fをバッファに入れない
	BTFSS	STATUS,C
	 GOTO	INTRETURN

	MOVF	RCREG,W			; 0xF8以上のリアルタイムメッセージも0x80以上のイベントと関係なく
	SUBLW	0xF7			; 出現するため、FULLフラグが解除されないように受信しないでおく。
	BTFSS	STATUS,C		; F8のメトロノームがずれてカウントされたり、
	 GOTO	INTRETURN		; メトロノームが停止しない場合があることに注意。

	BSF	PORTA,LED_MIDIFULL	; バッファフルLEDラッチ解除
MIDIQUEUE
	MOVF	RCREG,W			; 受信データを取り出してFIFOに書き込み
	CALL	fifo1write		; FIFOがあふれたら、次に受信するタイミングで対処する

INTRETURN
	MOVF	FSR_,W			; FSRリストア
	MOVWF	FSR
	MOVF	PCLATH_,W		; PCLATHリストア
	MOVWF	PCLATH
	SWAPF	STATUS_,W		; STATUSリストア
	MOVWF	STATUS
	SWAPF	W_,F			; Wリストア
	SWAPF	W_,W
	RETFIE

;------------------------------------------------------------------------------
; 電源投入時のSFR初期化
;------------------------------------------------------------------------------
POWER_ON				; 電源ON I/O初期化 未使用ポートは入力にする事
	MOVLW	B'00111111'		; LED消灯
	MOVWF	PORTA
	CLRF	PORTB
	MOVLW	B'00111000'		; FM/RD,/WR,/CSはH
	MOVWF	PORTC
	MOVLW	B'11110100'		; SSG/WR/CSはH、A0はL、/ALDはH
	MOVWF	PORTD
	MOVLW	B'00000000'		; SPクロック=0(4.0) FM/SSG/SPリセットアクティブ
	MOVWF	PORTE

	BSF	STATUS,RP0		; ◆ RP=1
	MOVLW	B'00000000'		; RA[5]SPバッファフルLED [4]SPバッファ使用LED [3]MIDIバッファフルLED [21]MIDIバッファ使用量LED [0]イベント処理中LED
	MOVWF	TRISA
	CLRF	TRISB			; RB[7-0]データ
	MOVLW	B'11000111'		; RC[76]USART=1 [5]FM/RD [4]FM/WR [3]FM/CS [2-0]未使用入力
	MOVWF	TRISC
	MOVLW	B'00000011'		; RD[7-4]SSG/WR/CS [3]A0 [2]SP/ALD [1]SPSBY [0]SP/LRQ
	MOVWF	TRISD
	MOVLW	B'00000000'		; RE[2]SPクロック選択 0=4.0 1=3.2 [1]SP/RESET [0]FM/SSG/IC
	MOVWF	TRISE

	MOVLW	B'00000110'		; A/Dコンバータ初期化
	MOVWF	ADCON1			; RA,REは全てデジタルI/O

	CLRF	TXSTA			; USART初期化
	MOVLW	9			; 20,000,000/(31,250*64)-1=9
	MOVWF	SPBRG

	BSF	PIE1,RCIE		; USART受信割り込み許可

	BCF	STATUS,RP0		; ◆ RP=0
	BSF	RCSTA,SPEN		; USART初期化 まだ受信は開始しない

	MOVLW	B'11000000'		; 割り込み許可(GIE,PEIE)
	MOVWF	INTCON

;------------------------------------------------------------------------------
; ループ前処理 システムリセット実行
;------------------------------------------------------------------------------
	CLRF	PFLAG
	BSF	PFLAG,RESET_MODE	; ポリモードでリセット
	CALL	system_reset
;------------------------------------------------------------------------------
; メインループ
;------------------------------------------------------------------------------
MAINLOOP
	CALL	fifo1read		; MIDI受信バッファチェック
	BTFSC	FIFOSTATUS,FIFO1EMPTY
	 GOTO	EVENT_END		; バッファが空の時

EVENTCHECK				; 受信データの種類判定
	BCF	PORTA,LED_EVENT		; イベントLED ON
	MOVWF	MIDI			; FIFOから読み出したデータを保存

	MOVF	MIDI,W
	SUBLW	0x7F			; 0x00〜0x7Fの場合パラメータ解析へ
	BTFSC	STATUS,C
	 GOTO	proc_param
	
	MOVF	MIDI,W
	SUBLW	0xF7			; 0x80〜0xF7の場合イベント解析へ
	BTFSC	STATUS,C
	 GOTO	proc_event

	MOVF	MIDI,W
	SUBLW	0xF8			; 0xF8の場合クロック
	BTFSC	STATUS,Z
	 GOTO	event_clock
	
	MOVF	MIDI,W
	SUBLW	0xFA			; 0xFAの場合スタート
	BTFSC	STATUS,Z
	 GOTO	event_start

	MOVF	MIDI,W
	SUBLW	0xFB			; 0xFBの場合コンティニュー
	BTFSC	STATUS,Z
	 GOTO	event_continue
	
	MOVF	MIDI,W
	SUBLW	0xFC			; 0xFCの場合ストップ
	BTFSC	STATUS,Z
	 GOTO	event_stop
	
	MOVF	MIDI,W
	SUBLW	0xFE			; 0xFEの場合アクティブセンシング
	BTFSC	STATUS,Z
	 GOTO	event_active

	MOVF	MIDI,W
	SUBLW	0xFF			; 0xFFの場合システムリセット
	BTFSC	STATUS,Z
	 GOTO	event_reset
EVENT_END				; その他(0xF9,0xFD)は定義されていないので無視
	BSF	PORTA,LED_EVENT		; イベントLED OFF
SPEECHCHECK
	BTFSC	PORTD,LRQ		; /LRQ=0になっている事を確認
	 GOTO	MAINLOOP		; /LRQ=1の場合はSP0256が処理中のため、発声処理をスキップする

	CALL	fifo2read		; SP0256発声バッファチェック
	BTFSC	FIFOSTATUS,FIFO2EMPTY
	 GOTO	MAINLOOP
	MOVWF	WRITE_DATA		; 発声データが入っていたらspwriteをコール
	CALL	spwrite
	GOTO	MAINLOOP
;------------------------------------------------------------------------------
; メインループ終了
;------------------------------------------------------------------------------

;------------------------------------------------------------------------------
; イベント解析 80〜F7の時にここへ来る
;------------------------------------------------------------------------------
proc_event
	MOVLW	B'11111000'		; エクスクルーシブフェーズをPHASE_IDにセット
	ANDWF	FLAG1,F

	MOVLW	0xF1			; ランニングステータスはチャンネルメッセージに適用されるため
	SUBWF	MIDI,W			; 0xF1〜0xF7は無効なイベントに書き換える
	BTFSC	STATUS,C
	 CLRF	MIDI
	MOVF	MIDI,W			; 今回のイベントを記録
	MOVWF	EVENT
	ANDLW	0x0F			; チャンネル情報だけを取り出してあらかじめ入れておく
	MOVWF	CHANNEL

	BSF	PARAM1,PARAM_NOTRCVD	; PARAM1を無効にする
	GOTO	EVENT_END		; イベント解析終了

;------------------------------------------------------------------------------
; パラメータ解析 00〜7F、各イベント処理へ分岐
;------------------------------------------------------------------------------
proc_param
	BTFSS	EVENT,EVENT_RCVD	; イベントが一度も受信されていない場合は何のパラメータか不明のため戻る
	 GOTO	EVENT_END
	BTFSS	PARAM1,PARAM_NOTRCVD	; PARAM1の受信か？
	 GOTO	PROC_PARAM2

PROC_PARAM1
	MOVF	MIDI,W			; PARAM1へ代入
	MOVWF	PARAM1

	MOVF	EVENT,W
	SUBLW	0xBF			; 前回のイベントが0x80〜0xBFか？
	BTFSC	STATUS,C
	 GOTO	EVENT_END		; 0x80〜0xBFはPARAM2が必要なのでリターン

	MOVF	EVENT,W
	SUBLW	0xCF			; 前回のイベントが0xC0〜0xCFか？
	BTFSC	STATUS,C
	 GOTO	event_program		; プログラムチェンジ

	MOVF	EVENT,W
	SUBLW	0xDF			; 前回のイベントが0xD0〜0xDFか？
	BTFSC	STATUS,C
	 GOTO	event_chpress		; チャンネルプレッシャ

	BTFSC	FLAG1,EX_PHASE2		; 0xF0でエクスクルーシブフェーズがPHASE_DATA,PHASE_IGNORE,PHASE_RESETの場合は、
	 GOTO	event_sysex		; データを1バイトづつ受信する。PHASE_RESETはEX_PHASE4フラグのみONとする
	BTFSC	FLAG1,EX_PHASE4
	 GOTO	event_sysex

	GOTO	EVENT_END		; 0xE0〜0xEF、0xF0(PHASE_ID,PHASE_ADDR)はPARAM2が必要なのでリターン
					; 0xF1以上はここへは来ない
PROC_PARAM2
	MOVF	MIDI,W			; PARAM2へ代入
	MOVWF	PARAM2

	MOVF	EVENT,W
	SUBLW	0x8F			; 前回のイベントが0x80〜0x8Fか？
	BTFSC	STATUS,C
	 GOTO	event_noteoff		; ノートオフ

	MOVF	EVENT,W
	SUBLW	0x9F			; 前回のイベントが0x90〜0x9Fか？
	BTFSC	STATUS,C
	 GOTO	event_noteon		; ノートオン

	MOVF	EVENT,W
	SUBLW	0xAF			; 前回のイベントが0xA0〜0xAFか？
	BTFSC	STATUS,C
	 GOTO	event_polypress		; ポリフォニックキープレッシャ

	MOVF	EVENT,W
	SUBLW	0xBF			; 前回のイベントが0xB0〜0xBFか？
	BTFSC	STATUS,C
	 GOTO	event_control		; コントロールチェンジ
					; 0xC0〜0xDFはここへは来ない
	MOVF	EVENT,W
	SUBLW	0xEF			; 前回のイベントが0xE0〜0xEFか？
	BTFSC	STATUS,C
	 GOTO	event_pitch		; ピッチベンド

	GOTO	event_sysex		; 0xF0でエクスクルーシブフェーズがPHASE_ID,PHASE_ADDRの場合は
					; データを2バイトづつ受信する
					; 0xF1以上はここへは来ない

;------------------------------------------------------------------------------
; 80 ノートオフ
; PART
; TMP00 voicecount
; TMP01 voices
; TMP02 priority
; TMP03 new_priority
; VOICE NoteOffVoice
;
; For PART = 0 To 15						' 全パートチェック
; 	If PART_CHANNEL(PART) <> CHANNEL Then NextPart		' チャンネル一致？
;
;	voices = PART_MAXVOICE(PART)				' ループ省略用カウンタ
;	priority = 255						' 優先度検出用
;	new_priority = 0					' 更新後の優先度
;	For voicecount = 0 To 15				' ボイスチェックループ
; 		If voices = 0 Then Break			' ループ省略チェック
;		If VOICE_PART(voicecount) <> PART Then Next	' ボイスのパート割り当てチェック
;		voices = voices - 1				' 省略カウンタデクリメント
;		If VOICE_NOTE(voicecount):VOICE_NOTEOFF = True Then ' ボイスOFFしているボイスの数を数えて優先度を作る
;			new_priority = new_priority + 1
;		End If
;		If VOICE_NOTE(voicecount) <> PARAM1 Then Next	' ノート番号一致？
;		If VOICE_PRIORITY(voicecount) < priority Then	' 0に近い優先度のボイスを探す
;			priority = VOICE_PRIORITY(voicecount)	' ボイスオフ候補の優先度を記録
;			NoteOffVoice = voicecount		' ボイスオフ候補のボイス番号を記録
;		End If
;	Next
;	If priority = 255 Then Next				' 優先度が255のままの場合は、該当ノート番号なしと判断する
;
;	voices = PART_MAXVOICE(PART)				' ループ省略用カウンタ
;	For voicecount = 0 To 15				' 優先度更新ループ
; 		If voices = 0 Then Break			' ループ省略チェック
;		If VOICE_PART(voicecount) <> PART Then Next	' ボイスのパート割り当てチェック
;		voices = voices - 1				' 省略カウンタデクリメント
;		If VOICE_NOTE(voicecount):VOICE_NOTEOFF = False Then ' ノートがONしていて、
;			If VOICE_PRIORITY(voicecount) < priority Then	' チェックしているボイスの優先度がボイスオフ候補の優先度よりも値が小さい(優先度が高い)場合、
;				VOICE_PRIORITY(voicecount) = VOICE_PRIORITY(voicecount) + 1	' 優先度を1段階下げる
;			End If
;		End If
;	Next
;	VOICE_PRIORITY(NoteOffVoice) = new_priority		' ボイスオフした番号の優先度をボイスOFF中の優先度の最低に設定する
;
;	VOICE_NOTE(NoteOffVoice):VOICE_NOTEOFF = True		' ノートオフを記録
;	If PART_CHANNEL(VOICE_PART(NoteOffVoice)):PART_SUSTAIN = True Then	' サスティン中の場合は、
;		VOICE_VELOCITY(NoteOffVoice):VOICE_SUSTAIN = True		' サスティンフラグを立ててボイスオフしない
;	Else
;		VoiceOff(NoteOffVoice)				' ボイスオフする
;	End If
; Next
;------------------------------------------------------------------------------
event_noteoff
	BCF	STATUS,IRP		; ◆ IRP=0
	CLRF	PART			; パートカウントリセット
NOTEOFF_LOOP
	MOVLW	PART_CHANNEL		; 受信チャンネルチェック
	ADDWF	PART,W
	MOVWF	FSR
	MOVF	INDF,W
	ANDLW	0x1F			; ミュートフラグとチャンネルを一度にチェック
	SUBWF	CHANNEL,W
	BTFSS	STATUS,Z
	 GOTO	NOTEOFF_LOOPEND		; チャンネル違いのためこのパートを処理しない

	MOVLW	PART_MAXVOICE		; 省略カウンタセット
	ADDWF	PART,W
	MOVWF	FSR
	MOVF	INDF,W
	MOVWF	TMP01
	MOVLW	0xFF			; 優先度リセット
	MOVWF	TMP02
	CLRF	TMP03			; 次の優先度リセット
	MOVLW	16			; 16ボイス分ループ
	MOVWF	TMP00
NOTEOFF_VOICE1
	MOVF	TMP01,W			; 現在のパートのPART_MAXVOICE分ノートのチェックしたか?
	BTFSC	STATUS,Z		; 所属パートチェックはPART_MAXVOICE分ループすればVOICELOOPを抜けても良い
	 GOTO	NOTEOFF_VOICE1BREAKCHECK

	MOVF	TMP00,W			; 現在のボイスが外側ループのパートに所属しているか?
	SUBLW	16
	ADDLW	VOICE_PART
	MOVWF	FSR
	MOVF	INDF,W
	ANDLW	0x1F
	SUBWF	PART,W
	BTFSS	STATUS,Z
	 GOTO	NOTEOFF_VOICE1END

	DECF	TMP01,F			; 省略カウンタデクリメント

	MOVF	TMP00,W
	SUBLW	16
	ADDLW	VOICE_NOTE
	MOVWF	FSR
	BTFSC	INDF,VOICE_NOTEOFF	; ノートOFFの数を数えて次の優先度を作る
	 INCF	TMP03,F
	MOVF	INDF,W			; ボイスのノートは消音すべきノートと同じか?
	SUBWF	PARAM1,W		; ノートオフフラグが立っている時はノートに一致しないため無視される
	BTFSS	STATUS,Z
	 GOTO	NOTEOFF_VOICE1END

	MOVF	TMP00,W			; ボイスの優先度を調べる
	SUBLW	16
	ADDLW	VOICE_PRIORITY
	MOVWF	FSR
	MOVF	INDF,W
	SUBWF	TMP02,W			; 一番優先度の高い(0に近い)ボイスを検索する
	BTFSS	STATUS,C
	 GOTO	NOTEOFF_VOICE1END	; 他のものより優先度が低かったら次のボイスへ
	
	MOVF	INDF,W			; 優先度が高かったら次のボイスと比較するために保存する
	MOVWF	TMP02
	MOVF	TMP00,W			; ノートオフするボイス番号も保存する
	SUBLW	16
	MOVWF	VOICE

NOTEOFF_VOICE1END
	DECFSZ	TMP00,F			; 16ボイス分ループ
	 GOTO	NOTEOFF_VOICE1
NOTEOFF_VOICE1BREAKCHECK
	COMF	TMP02,W			; 該当ノートが存在せず優先度が更新されなかった場合、
	BTFSC	STATUS,Z		; ノートオフボイスなしのため次のパートへ進む
	 GOTO	NOTEOFF_LOOPEND

	MOVLW	PART_MAXVOICE		; 省略カウンタセット
	ADDWF	PART,W
	MOVWF	FSR
	MOVF	INDF,W
	MOVWF	TMP01
	MOVLW	16			; 16ボイス分ループ
	MOVWF	TMP00
NOTEOFF_VOICE2
	MOVF	TMP01,W			; 現在のパートのPART_MAXVOICE分ノート番号のチェックしたか?
	BTFSC	STATUS,Z		; 所属パートチェックをPART_MAXVOICE分ループすればVOICELOOPを抜けても良い
	 GOTO	NOTEOFF_VOICE2BREAK

	MOVF	TMP00,W			; 現在のボイスが外側ループのパートに所属しているか?
	SUBLW	16
	ADDLW	VOICE_PART
	MOVWF	FSR
	MOVF	INDF,W
	ANDLW	0x1F
	SUBWF	PART,W
	BTFSS	STATUS,Z
	 GOTO	NOTEOFF_VOICE2END

	DECF	TMP01,F			; 省略カウンタデクリメント
	
	MOVF	TMP00,W			; ノートオンされているボイスで、
	SUBLW	16
	ADDLW	VOICE_NOTE
	MOVWF	FSR
	BTFSC	INDF,VOICE_NOTEOFF
	 GOTO	NOTEOFF_VOICE2END

	MOVF	TMP00,W			; ボイスの優先度を調べる
	SUBLW	16
	ADDLW	VOICE_PRIORITY
	MOVWF	FSR
	MOVF	TMP02,W			; オフするボイスよりも優先度の高い(0に近い)ボイスか?
	SUBWF	INDF,W
	BTFSS	STATUS,C
	 INCF	INDF,F			; 優先度が高い場合は、優先度を1ランク下げる
NOTEOFF_VOICE2END
	DECFSZ	TMP00,F			; 16ボイス分ループ
	 GOTO	NOTEOFF_VOICE2
NOTEOFF_VOICE2BREAK
	MOVLW	VOICE_PRIORITY		; ノートオフしたボイスのプライオリティを最大にする
	ADDWF	VOICE,W
	MOVWF	FSR
	MOVF	TMP03,W			; 優先度を更新
	MOVWF	INDF

NOTEOFF_VOICEOFF
	MOVLW	VOICE_NOTE		; ノート番号にノートオフビットを立てる
	ADDWF	VOICE,W
	MOVWF	FSR
	BSF	INDF,VOICE_NOTEOFF

	MOVF	VOICE,W			; このボイスの担当するパートがサスティン中の場合は、
	ADDLW	VOICE_PART
	MOVWF	FSR
	MOVF	INDF,W
	ANDLW	0x0F
	ADDLW	PART_CHANNEL
	MOVWF	FSR
	BTFSC	INDF,PART_SUSTAIN
	 GOTO	NOTEOFF_VOICEOFF_SUSTAIN ; サスティン処理を行いボイスオフしない
	CALL	voiceoff
NOTEOFF_LOOPEND
	INCF	PART,W			; 16パート分ループする
	MOVWF	PART
	SUBLW	16
	BTFSS	STATUS,Z
	 GOTO	NOTEOFF_LOOP

	BSF	PARAM1,PARAM_NOTRCVD	; PARAM1を無効にする
	GOTO	EVENT_END

NOTEOFF_VOICEOFF_SUSTAIN		; ボイスのサスティン処理
	BSF	STATUS,IRP		; ◆ IRP=1
	MOVLW	LOW VOICE_VELOCITY
	ADDWF	VOICE,W
	MOVWF	FSR
	BSF	INDF,VOICE_SUSTAIN	; ボイスサスティンフラグを立てる
	BCF	STATUS,IRP		; ◆ IRP=0
	GOTO	NOTEOFF_LOOPEND

;------------------------------------------------------------------------------
; 90 ノートオン
; VOICE			ボイス番号ループカウンタ
; PART			ボイスが所属しているパート番号
; TMP00			SSG ENABLEレジスタ作成、PART_MAXVOICE - 1 計算用
;
;for(voicenum = 0; voicenum =< 15; voicenum++)
;{
;	tgt_part = assign(voicenum)					' ボイス番号が所属しているパートを割り出す
;	tgt_chnl = channel(tgt_part)					' パートが受信するチャンネルを割り出す
;	if tgt_chnl != midich then loopexit				' チャンネルが一致しない場合はループを抜ける
;
;	priority = priority(voicenum)					' 優先度を出す
;	if(priority == 0)						' 優先度が一番高い場合は
;	{
;		note(voicenum) = note					' ノートオン
;		priority(voicenum) = maxvoice(tgt_part) - 1		' 優先度を更新
;	}
;	else	{ priority(voicenum) --; }
;}
;------------------------------------------------------------------------------
event_noteon
	MOVF	PARAM2,W		; PARAM2(ベロシティ)が0の時は、ノートオフで処理する
	BTFSC	STATUS,Z
	 GOTO	event_noteoff

	BCF	STATUS,IRP		; ◆ IRP=0
	CLRF	VOICE			; ループカウントリセット
NOTEON_LOOP
	MOVLW	VOICE_PART		; ボイスが割り当てられているパートを調べる
	ADDWF	VOICE,W
	MOVWF	FSR
	BTFSC	INDF,VOICE_MUTE		; ミュートボイスはスキップ
	 GOTO	NOTEON_LOOPEND
	MOVF	INDF,W
	ANDLW	0x1F
	MOVWF	PART
	
	MOVLW	PART_CHANNEL		; 受信チャンネルチェック
	ADDWF	PART,W
	MOVWF	FSR
	MOVF	INDF,W
	ANDLW	0x1F			; ミュートフラグとチャンネルを一度にチェック
	SUBWF	CHANNEL,W
	BTFSS	STATUS,Z
	 GOTO	NOTEON_LOOPEND		; チャンネル違いのためこのパートを処理しない

	MOVLW	VOICE_PRIORITY		; 一致するならばボイスの優先度を調べる
	ADDWF	VOICE,W
	MOVWF	FSR
	MOVF	INDF,W
	BTFSS	STATUS,Z
	 GOTO	NOTEON_PRIORITY_ONLY	; 最優先でない場合は優先度を変更

NOTEON_VOICEON				; 最優先(=0)の場合ボイスオン
	MOVLW	VOICE_NOTE		; ノート保存
	ADDWF	VOICE,W
	MOVWF	FSR
	MOVF	PARAM1,W
	MOVWF	INDF

	BSF	STATUS,IRP		; ◆ IRP=1
	MOVLW	LOW VOICE_VELOCITY	; ベロシティ保存
	ADDWF	VOICE,W
	MOVWF	FSR
	MOVF	PARAM2,W
	MOVWF	INDF
	BCF	STATUS,IRP		; ◆ IRP=0

	MOVF	VOICE,W			; ボイス番号が0〜2の時FM
	SUBLW	2
	BTFSC	STATUS,C
	 GOTO	NOTEON_VOICEON_FM

	MOVF	VOICE,W			; ボイス番号が3〜14の時SSG
	SUBLW	14
	BTFSC	STATUS,C
	 GOTO	NOTEON_VOICEON_SSG
	
NOTEON_VOICEON_SP			; ボイス番号が15の時SP
	MOVLW	PA1
	BTFSC	PARAM1,6		; ノート番号が64以上の時はPA1で音を消す
	 GOTO	NOTEON_VOICEON_SP_FIFOWRITE

	MOVF	PARAM1,W		; ノート番号をALLPHONE_TABLEに変換する。
	BSF	STATUS,RP1		; ◆ RP=2
	ADDLW	LOW ALLOPHONE_TABLE
	MOVWF	EEADR
	MOVLW	HIGH ALLOPHONE_TABLE
	MOVWF	EEADRH
	BTFSC	STATUS,C
	 INCF	EEADRH,F

	BSF	STATUS,RP0		; ◆ RP=3
	BSF	EECON1,EEPGD
	BSF	EECON1,RD
	NOP
	NOP
	BCF	STATUS,RP0		; ◆ RP=2
	MOVF	EEDATA,W
	BCF	STATUS,RP1		; ◆ RP=0
NOTEON_VOICEON_SP_FIFOWRITE
	CALL	fifo2write
	GOTO	NOTEON_VOICEON_UPDATE

NOTEON_VOICEON_FM			; FM発音
	CALL	fm_setfnum		; 音程セット
	CALL	fm_setvelocity		; ベロシティセット

	MOVLW	0x28
	MOVWF	WRITE_ADDR
	MOVLW	0x00
	ADDWF	VOICE,W			; ボイス番号を足してノートオンを実行
	MOVWF	WRITE_DATA		; 一度ノートオフしないとアタックが始まらない
	CALL	fmwrite

	BSF	STATUS,IRP		; ◆ IRP=1
	MOVLW	LOW SLOT		; 発音させるSLOTを読み出す
	ADDWF	VOICE,W
	MOVWF	FSR
	SWAPF	INDF,W			; 上下ビットを入れ替えてSLOTの位置に持ってくる
	BCF	STATUS,IRP		; ◆ IRP=0

	ADDWF	VOICE,W
	MOVWF	WRITE_DATA
	CALL	fmwrite
	GOTO	NOTEON_VOICEON_UPDATE

NOTEON_VOICEON_SSG
	CALL	ssg_settone		; 音程セット
	CALL	ssg_setvelocity		; ベロシティセット
	LCALL	ssg_setnp

	LCALL	ssgchannel		; SSGチップ・チャンネル割り出し
	SWAPF	SSGCHIP,W		; MIXアドレス7 OR SSGCHIPを行う
	ADDLW	7
	MOVWF	WRITE_ADDR

	BSF	STATUS,IRP		; ◆ IRP=1
	MOVLW	LOW PART_ENVSHAPE	; パートのプログラムチェンジをチェック
	ADDWF	PART,W
	MOVWF	FSR
	BTFSC	INDF,PART_PROG_NOISE	; プログラムチェンジ=NOISEの時
	 GOTO	NOTEON_VOICEON_SSG_PROG1
	BTFSC	INDF,PART_PROG_BOTH	; プログラムチェンジ=BOTHの時
	 GOTO	NOTEON_VOICEON_SSG_PROG2
NOTEON_VOICEON_SSG_PROG0
	MOVLW	B'00000001'		; TONE
	GOTO	NOTEON_VOICEON_SSG_PROG
NOTEON_VOICEON_SSG_PROG1
	MOVLW	B'00001000'		; NOISE
	GOTO	NOTEON_VOICEON_SSG_PROG
NOTEON_VOICEON_SSG_PROG2
	MOVLW	B'00001001'		; BOTH
NOTEON_VOICEON_SSG_PROG
	MOVWF	TMP00
NOTEON_VOICEON_SSG_PROG3
	MOVF	SSGCHANNEL,F
	BTFSC	STATUS,Z
	 GOTO	NOTEON_VOICEON_SSG_PROG4 ; SSGCHANNELがゼロになるまでTMP00を左シフトしてENABLEビットを該当のパートまで移動させる
	BCF	STATUS,C
	RLF	TMP00,F
	DECF	SSGCHANNEL,F
	GOTO	NOTEON_VOICEON_SSG_PROG3
NOTEON_VOICEON_SSG_PROG4
	MOVLW	LOW SSG_ENABLE		; 保存された他のパートのENABLEとミックスする
	ADDWF	SSGCHIP,W		; ENABLEはアクティブローのため、COMFとANDで該当パートを0にしないといけない
	MOVWF	FSR			; めんどくせぇ
	COMF	TMP00,W
	ANDWF	INDF,W
	MOVWF	INDF
	BCF	STATUS,IRP		; ◆ IRP=0
	MOVWF	WRITE_DATA
	CALL	ssgwrite

NOTEON_VOICEON_UPDATE
	MOVLW	PART_MAXVOICE		; パートの最大ボイス-1を求めて
	ADDWF	PART,W
	MOVWF	FSR
	DECF	INDF,W
	MOVWF	TMP00

	MOVLW	VOICE_PRIORITY		; その値を優先度を変更に代入
	ADDWF	VOICE,W
	MOVWF	FSR
	MOVF	TMP00,W
	MOVWF	INDF
	GOTO	NOTEON_LOOPEND
	
NOTEON_PRIORITY_ONLY
	MOVLW	VOICE_PRIORITY
	ADDWF	VOICE,W
	MOVWF	FSR
	DECF	INDF,F
NOTEON_LOOPEND
	INCF	VOICE,W			; 16ボイス分回す
	MOVWF	VOICE
	SUBLW	16
	BTFSS	STATUS,Z
	 GOTO	NOTEON_LOOP

	BSF	PARAM1,PARAM_NOTRCVD	; PARAM1を無効にする
	GOTO	EVENT_END

;------------------------------------------------------------------------------
; A0 ポリフォニックキープレッシャ 実装しない
;------------------------------------------------------------------------------
event_polypress
	BSF	PARAM1,PARAM_NOTRCVD	; PARAM1を無効にする
	GOTO	EVENT_END

;------------------------------------------------------------------------------
; B0 コントロールチェンジ
;------------------------------------------------------------------------------
event_control
	LGOTO	EVENT_CONTROL_P1	; ページ1で処理する

;------------------------------------------------------------------------------
; C0 プログラムチェンジ
; これを受信後にノートオンになったボイスから有効になる。
;------------------------------------------------------------------------------
event_program
	MOVLW	3
	MOVWF	VOICE
PROGRAM_FMLOOP				; FM音源プログラムチェンジ
	CALL	voice_channel_check_P0	; チェック中のボイスがチャンネルに一致しているか？
	BTFSS	STATUS,Z
	 GOTO	PROGRAM_FMNEXT

	MOVF	VOICE,W			; ボイスのパートを求める
	ADDLW	VOICE_PART - 1
	MOVWF	FSR
	MOVF	INDF,W
	ANDLW	0x1F
	ADDLW	PART_CHANNEL		; パートのプログラムチェンジ受信フラグをチェック
	MOVWF	FSR
	BTFSS	INDF,PART_RXPROGRAM	; プログラムチェンジ受信フラグがOFFの場合はスキップ
	 GOTO	PROGRAM_FMNEXT

	DECF	VOICE,F			; +1オフセット除去
	BTFSS	PFLAG,RESET_MODE
	 GOTO	PROGRAM_FMMONO
PROGRAM_FMPOLY
	MOVF	PARAM1,W
	SUBLW	7			; ポリモードではプログラムナンバーは0〜7に設定する
	MOVF	PARAM1,W
	GOTO	PROGRAM_FMCOM
PROGRAM_FMMONO
	MOVLW	120
	SUBWF	PARAM1,W		; モノモードではプログラムナンバーは120〜127に設定する
PROGRAM_FMCOM
	BTFSC	STATUS,C		; 120以下の時は実行しない
	 CALL	loadfmprogram
	INCF	VOICE,F			; +1オフセット
PROGRAM_FMNEXT
	DECFSZ	VOICE,F
	 GOTO	PROGRAM_FMLOOP

	MOVLW	16			; SSG音源プログラムチェンジ
	MOVWF	PART
PROGRAM_SSGLOOP
	CALL	part_channel_check_P0
	BTFSS	STATUS,Z
	 GOTO	PROGRAM_SSGNEXT		; チャンネルが一致しない場合は次のパート

	MOVF	PART,W			; パートのプログラムチェンジ受信フラグをチェック
	ADDLW	PART_CHANNEL - 1
	MOVWF	FSR
	BTFSS	INDF,PART_RXPROGRAM
	 GOTO	PROGRAM_SSGNEXT

	MOVLW	LOW PART_ENVSHAPE - 1	; 一致する場合は、該当のパートのプログラムチェンジを変更
	ADDWF	PART,W
	MOVWF	FSR
	BSF	STATUS,IRP		; ◆ IRP=1
	MOVLW	B'00011111'		; PART_PROGRAMビットをリセット(トーン)
	ANDWF	INDF,F

	MOVLW	1			; 125=ノイズ
	BTFSS	PFLAG,RESET_MODE
	 ADDLW	124
	SUBWF	PARAM1,W
	BTFSC	STATUS,Z
	 BSF	INDF,PART_PROG_NOISE

	MOVLW	2			; 126=ノイズ+NP
	BTFSS	PFLAG,RESET_MODE
	 ADDLW	124
	SUBWF	PARAM1,W
	MOVLW	B'10100000'		; PART_PROG_NOISE + PART_NOTE_TO_NP
	BTFSC	STATUS,Z
	 IORWF	INDF,F

	MOVLW	3			; 127=トーン+ノイズ
	BTFSS	PFLAG,RESET_MODE
	 ADDLW	124
	SUBWF	PARAM1,W
	BTFSC	STATUS,Z
	 BSF	INDF,PART_PROG_BOTH

	BCF	STATUS,IRP		; ◆ IRP=0
PROGRAM_SSGNEXT
	DECFSZ	PART,F
	 GOTO	PROGRAM_SSGLOOP
	BSF	PARAM1,PARAM_NOTRCVD	; PARAM1を無効にする
	GOTO	EVENT_END

;------------------------------------------------------------------------------
; D0 チャンネルプレッシャ
;------------------------------------------------------------------------------
event_chpress
	LGOTO	EVENT_CHPRESS_P1	; ページ1で処理する

;------------------------------------------------------------------------------
; E0 ピッチベンド
;
; TMP00		ボイスループカウンタ
; TMP01		ボイスの担当するパート
;------------------------------------------------------------------------------
event_pitch
	MOVLW	0x7F			; MSBが7Fか？
	SUBWF	PARAM2,W
	BTFSS	STATUS,Z
	 GOTO	PITCH_PART
	MOVLW	0x7F			; LSBも7Fか？
	SUBWF	PARAM1,W
	BTFSS	STATUS,Z
	 GOTO	PITCH_PART
	MOVLW	0x80			; 最大ピッチアップの時はMSBを0x80とする。
	MOVWF	PARAM2
PITCH_PART
	MOVLW	16
	MOVWF	PART
PITCH_PARTLOOP
	CALL	part_channel_check_P0
	BTFSS	STATUS,Z
	 GOTO	PITCH_PARTNEXT		; チャンネルが一致しない場合は次のパート

	MOVF	PART,W
	ADDLW	LOW PART_PITCHBEND - 1	; パートの受信するチャンネルをチェックして値を保存する
	MOVWF	FSR
	BSF	STATUS,IRP		; ◆ IRP=1
	MOVF	PARAM2,W		; ピッチベンドの値をそのまま入れる
	MOVWF	INDF
	BCF	STATUS,IRP		; ◆ IRP=0
PITCH_PARTNEXT
	DECFSZ	PART,F
	 GOTO	PITCH_PARTLOOP
	CALL	sendpitch
	BSF	PARAM1,PARAM_NOTRCVD	; PARAM1を無効にする
	GOTO	EVENT_END

;------------------------------------------------------------------------------
; F0 エクスクルーシブ
; 1度目のコール PARAM1にメーカーID、PARAM2に機種IDが入る(PHASE_ID)
; 2度目のコール PARAM1に上位アドレス、PARAM2に下位アドレスが入る(PHASE_ADDR)
; 3度目以降のコール PARAM1にデータが入る(PHASE_DATA) 2バイト必要な場合は、SYSEX_DATABACKUPで一度目をリターンさせる
; SYSEXの個々の処理はページ2に記述する
;------------------------------------------------------------------------------
event_sysex
	BTFSC	FLAG1,EX_PHASE4		; PHASE_RESET?
	 GOTO	SYSEX_RESET

	MOVF	FLAG1,W			; PHASE_IGNORE?
	ANDLW	B'00000011'
	XORLW	PHASE_IGNORE
	BTFSC	STATUS,Z
	 GOTO	SYSEX_RETURN

	MOVF	FLAG1,W			; PHASE_DATA?
	ANDLW	B'00000011'
	XORLW	PHASE_DATA
	BTFSC	STATUS,Z
	 GOTO	SYSEX_DATASET
	
	MOVF	FLAG1,W			; PHASE_ADDR?
	ANDLW	B'00000011'
	XORLW	PHASE_ADDR
	BTFSC	STATUS,Z
	 GOTO	SYSEX_ADDRESS

SYSEX_IDCHECK				; PHASE_ID
	MOVLW	0x7D			; メーカーIDチェック
	SUBWF	PARAM1,W
	BTFSS	STATUS,Z
	 GOTO	SYSEX_RESETCHECK	; ID違い、他メーカーチェック
	MOVLW	0x01			; 機種IDチェック
	SUBWF	PARAM2,W
	BTFSS	STATUS,Z
	 GOTO	SYSEX_UNMATCH		; ID違い、フェーズ3へ移行

	MOVF	FLAG1,W
	ANDLW	B'11111100'
	ADDLW	PHASE_ADDR		; IDチェック完了、PHASE_ADDRへ移行
	MOVWF	FLAG1
	GOTO	SYSEX_RETURN
SYSEX_RESETCHECK
	BTFSS	PFLAG,VENDOR_RESET	; 各社リセットを受けない場合は、ID違い、フェーズ3へ移行
	 GOTO	SYSEX_UNMATCH

	CLRF	EX_ADDR2		; チェックアドレスリセット

	MOVLW	0x41			; メーカーIDチェック
	SUBWF	PARAM1,W
	BTFSS	STATUS,Z
	 GOTO	SYSEX_RESETCHECK_YAMAHA	; ID違い、他メーカーチェック
	MOVLW	0x10			; 機種IDチェック
	SUBWF	PARAM2,W
	BTFSS	STATUS,Z
	 GOTO	SYSEX_UNMATCH		; ID違い、フェーズ3へ移行

	MOVLW	0			; Roland系列
	GOTO	SYSEX_RESETCHECK_OK

SYSEX_RESETCHECK_YAMAHA
	MOVLW	0x43			; メーカーIDチェック
	SUBWF	PARAM1,W
	BTFSS	STATUS,Z
	 GOTO	SYSEX_RESETCHECK_GM	; ID違い、他メーカーチェック
	MOVLW	0x10			; 機種IDチェック
	SUBWF	PARAM2,W
	BTFSS	STATUS,Z
	 GOTO	SYSEX_UNMATCH		; ID違い、フェーズ3へ移行

	MOVLW	12			; Yamaha系列
	GOTO	SYSEX_RESETCHECK_OK

SYSEX_RESETCHECK_GM
	MOVLW	0x7E			; メーカーIDチェック
	SUBWF	PARAM1,W
	BTFSS	STATUS,Z
	 GOTO	SYSEX_UNMATCH		; ID違い、フェーズ3へ移行
	MOVLW	0x7F			; 機種IDチェック
	SUBWF	PARAM2,W
	BTFSS	STATUS,Z
	 GOTO	SYSEX_UNMATCH		; ID違い、フェーズ3へ移行

	MOVLW	17			; GM
SYSEX_RESETCHECK_OK
	MOVWF	EX_ADDR2
	BSF	FLAG1,EX_PHASE4		; 機種が入った場合は、フェーズ4へ移行
	GOTO	SYSEX_RETURN

SYSEX_ADDRESS				; PHASE_ADDR
	MOVF	PARAM1,W		; レジスタアドレスをセット
	MOVWF	EX_ADDR1
	MOVF	PARAM2,W
	MOVWF	EX_ADDR2
	BSF	EX_DATA,PARAM_NOTRCVD	; 前回のバックアップデータをクリア

	MOVF	FLAG1,W
	ANDLW	B'11111100'
	ADDLW	PHASE_DATA		; アドレスセット完了、PHASE_DATAへ移行
	MOVWF	FLAG1
	GOTO	SYSEX_RETURN

SYSEX_DATASET				; PHASE_DATA
	LGOTO	SYSEX_DATASET_P2	; ページ2で処理する

SYSEX_RESET				; PHASE_RESET
	LGOTO	SYSEX_RESET_P2		; ページ2で処理する

					; リターン用の処理はページ0と2で同じ物を用意しておく
SYSEX_UNMATCH				; PHASE_IGNOREをセットして戻る
	MOVLW	PHASE_IGNORE
	IORWF	FLAG1,F
	GOTO	SYSEX_RETURN
SYSEX_INC_RETURN			; アドレスをインクリメントしてリターン
	INCF	EX_ADDR2,F
	BSF	EX_DATA,PARAM_NOTRCVD	; バックアップしたデータを無効化する
SYSEX_RETURN				; アドレスをインクリメントせずにリターン
	BSF	PARAM1,PARAM_NOTRCVD	; PARAM1を無効にする
	GOTO	EVENT_END

;------------------------------------------------------------------------------
; F8 クロック
;------------------------------------------------------------------------------
event_clock
	BTFSS	FLAG1,METRO_RUN
	 GOTO	EVENT_END
	
	MOVF	CLOCK_LIMIT,W		; CLOCK_LIMITが0の時は、メトロノームを実行しない
	BTFSC	STATUS,Z
	 GOTO	EVENT_END
	
	DECFSZ	CLOCK_COUNT,F		; CLOCK_COUNTはダウンカウンタ
	 GOTO	EVENT_END
	MOVF	CLOCK_LIMIT,W		; 指定の長さがダウンカウンタでカウントされ終わったら、新しい長さをロードする
	MOVWF	CLOCK_COUNT
BEAT_CHECK
	DECFSZ	BEAT_COUNT,F		; BEAT_COUNTはダウンカウンタ
	 GOTO	BEAT_LOW		; 指定の拍がダウンカウンタでカウントされ終わったら、新しい拍をロードする
	MOVF	BEAT_LIMIT,W
	MOVWF	BEAT_COUNT
BEAT_1ST
	MOVLW	0x00			; YM2203 SSG-Aセットアップ
	MOVWF	WRITE_ADDR
	MOVLW	0x3C
	MOVWF	WRITE_DATA
	CALL	fmwrite
BEAT_SOUND
	MOVLW	0x0D			; ENV SHAPE
	MOVWF	WRITE_ADDR
	MOVLW	0x09
	MOVWF	WRITE_DATA
	CALL	fmwrite
	GOTO	EVENT_END

BEAT_LOW
	DECF	MIDDLE_BEAT1,W
	SUBWF	BEAT_LIMIT,W
	SUBWF	BEAT_COUNT,W
	BTFSC	STATUS,Z
	 GOTO	BEAT_MIDDLE
		
	DECF	MIDDLE_BEAT2,W
	SUBWF	BEAT_LIMIT,W
	SUBWF	BEAT_COUNT,W
	BTFSC	STATUS,Z
	 GOTO	BEAT_MIDDLE

	MOVLW	0x00			; YM2203 SSG-Aセットアップ
	MOVWF	WRITE_ADDR
	MOVLW	0xEF
	MOVWF	WRITE_DATA
	CALL	fmwrite
	GOTO	BEAT_SOUND

BEAT_MIDDLE
	MOVLW	0x00			; YM2203 SSG-Aセットアップ
	MOVWF	WRITE_ADDR
	MOVLW	0x77
	MOVWF	WRITE_DATA
	CALL	fmwrite
	GOTO	BEAT_SOUND

;------------------------------------------------------------------------------
; FA スタート
;------------------------------------------------------------------------------
event_start
	MOVF	CLOCK_LIMIT,W		; CLOCK_LIMITが0の時は、メトロノームを実行しない
	BTFSC	STATUS,Z
	 GOTO	EVENT_END
	
	BSF	FLAG1,METRO_RUN
	MOVLW	1
	MOVWF	CLOCK_COUNT
	MOVWF	BEAT_COUNT

	MOVLW	0x01			; YM2203 SSG-Aセットアップ
	MOVWF	WRITE_ADDR
	MOVLW	0x00
	MOVWF	WRITE_DATA
	CALL	fmwrite
	
	MOVLW	0x07			; MIX
	MOVWF	WRITE_ADDR
	MOVLW	0x3E
	MOVWF	WRITE_DATA
	CALL	fmwrite
	
	MOVLW	0x08			; VOLUME
	MOVWF	WRITE_ADDR
	MOVLW	0x10
	MOVWF	WRITE_DATA
	CALL	fmwrite
	
	MOVLW	0x0B			; ENV
	MOVWF	WRITE_ADDR
	MOVLW	0x00
	MOVWF	WRITE_DATA
	CALL	fmwrite
	
	MOVLW	0x0C			; ENV
	MOVWF	WRITE_ADDR
	MOVLW	0x02
	MOVWF	WRITE_DATA
	CALL	fmwrite

	GOTO	EVENT_END

;------------------------------------------------------------------------------
; FB コンティニュー
;------------------------------------------------------------------------------
event_continue
	MOVF	CLOCK_LIMIT,W		; CLOCK_LIMITが0の時は、メトロノームを実行しない
	BTFSC	STATUS,Z
	 GOTO	EVENT_END
	
	BSF	FLAG1,METRO_RUN
	GOTO	EVENT_END

;------------------------------------------------------------------------------
; FC ストップ
;------------------------------------------------------------------------------
event_stop
	BCF	FLAG1,METRO_RUN
	GOTO	EVENT_END

;------------------------------------------------------------------------------
; FE アクティブセンシング 実装しない
;------------------------------------------------------------------------------
event_active
	GOTO	EVENT_END

;------------------------------------------------------------------------------
; FF システムリセット 電源投入と同じ初期化を行う
;------------------------------------------------------------------------------
event_reset
	; CALL	system_reset
	GOTO	EVENT_END

;------------------------------------------------------------------------------
; システムリセットルーチン
; 音源ICをリセットし、すべてのパラメータを初期化する
; PFLAG-RESET_MODEにリセットモードを指定する。
; 0:モノモード	1:ポリモード
;------------------------------------------------------------------------------
system_reset
	BCF	RCSTA,CREN		; 受信停止

	CALL	icreset

	MOVLW	FIFOBUF1		; FIFO初期化
	MOVWF	READPTR1		; FIFOバッファをエンプティ状態にする
	MOVWF	WRITEPTR1
	CLRF	USEDSIZE1
	MOVLW	FIFOBUF2
	MOVWF	READPTR2
	MOVWF	WRITEPTR2
	CLRF	USEDSIZE2
	CLRF	FIFOSTATUS

	BCF	STATUS,IRP		; ◆ IRP=0
	MOVLW	PART_CHANNEL		; 0xA0-0xEF初期化
	MOVWF	FSR
	BCF	STATUS,RP0		; ◆ RP=0
	BTFSC	PFLAG,RESET_MODE	; RESET_MODEによってロードするアドレスを切り替える
	 GOTO	RESET_POLY
RESET_MONO
	BSF	STATUS,RP1		; ◆ RP=2
	MOVLW	LOW INIT_REGISTER_TABLE_0 ; 初期データのアドレスをセット
	MOVWF	EEADR
	MOVLW	HIGH INIT_REGISTER_TABLE_0
	MOVWF	EEADRH
	GOTO	PARAM_INIT0
RESET_POLY
	BSF	STATUS,RP1		; ◆ RP=2
	MOVLW	LOW INIT_REGISTER_TABLE_1
	MOVWF	EEADR
	MOVLW	HIGH INIT_REGISTER_TABLE_1
	MOVWF	EEADRH
PARAM_INIT0
	MOVLW	0xF0-0xA0		; 初期化ループ1
	MOVWF	TMP00
PARAM_INIT1
	BSF	STATUS,RP0		; ◆ RP=3
	BSF	EECON1,EEPGD
	BSF	EECON1,RD
	NOP
	NOP
	BCF	STATUS,RP0		; ◆ RP=2
	MOVF	EEDATA,W
	MOVWF	INDF
	INCF	FSR,F
	INCF	EEADR,F
	BTFSC	STATUS,Z		; 下の桁が0(=桁上がり)したら上の桁も+1する
	 INCF	EEADRH,F
	DECFSZ	TMP00,F
	 GOTO	PARAM_INIT1

	BSF	STATUS,IRP		; ◆ IRP=1
	MOVLW	LOW VOICE_VELOCITY	; 0x110-0x16F初期化
	MOVWF	FSR
	MOVLW	LOW INIT_REGISTER_TABLE_COM
	MOVWF	EEADR
	MOVLW	HIGH INIT_REGISTER_TABLE_COM
	MOVWF	EEADRH

	MOVLW	0x170-0x110		; 初期化ループ2
	MOVWF	TMP00
PARAM_INIT2
	BSF	STATUS,RP0		; ◆ RP=3
	BSF	EECON1,EEPGD
	BSF	EECON1,RD
	NOP
	NOP
	BCF	STATUS,RP0		; ◆ RP=2
	MOVF	EEDATA,W
	MOVWF	INDF
	INCF	FSR,F
	INCF	EEADR,F
	BTFSC	STATUS,Z		; 下の桁が0(=桁上がり)したら上の桁も+1する
	 INCF	EEADRH,F
	DECFSZ	TMP00,F
	 GOTO	PARAM_INIT2
	BCF	STATUS,RP1		; ◆ RP=0

	BTFSS	PFLAG,RESET_MODE
	 GOTO	PARAM_INIT3
	MOVLW	0x61			; ポリモードの時はパート2をエンベロープに設定する
	MOVWF	FSR			; 0x161 = 0x19 UseEnv,Shape=9(2)
	MOVLW	0x19
	MOVWF	INDF

	CLRF	WRITE_DATA		; $0B = 00h
	MOVLW	0x0B
	MOVWF	WRITE_ADDR
	CALL	ssgwrite
	MOVLW	0x1B
	MOVWF	WRITE_ADDR
	CALL	ssgwrite
	MOVLW	0x2B
	MOVWF	WRITE_ADDR
	CALL	ssgwrite
	MOVLW	0x3B
	MOVWF	WRITE_ADDR
	CALL	ssgwrite

	MOVLW	0x30
	MOVWF	WRITE_DATA		; $0C = 30h
	MOVLW	0x0C
	MOVWF	WRITE_ADDR
	CALL	ssgwrite
	MOVLW	0x1C
	MOVWF	WRITE_ADDR
	CALL	ssgwrite
	MOVLW	0x2C
	MOVWF	WRITE_ADDR
	CALL	ssgwrite
	MOVLW	0x3C
	MOVWF	WRITE_ADDR
	CALL	ssgwrite

PARAM_INIT3
	BCF	STATUS,IRP		; ◆ IRP=0
	CLRF	EVENT			; イベント処理変数リセット
	CLRF	CLOCK_LIMIT

	MOVLW	B'00000000'		; 440Hz,METRO=OFF,レベル補正フラグはパートごとに自動ロードされるので初期化の必要は無い
	MOVWF	FLAG1

	BSF	RCSTA,CREN		; 受信開始
	RETURN

;------------------------------------------------------------------------------
; 音源ハードウエアリセットルーチン
; FM音源のパラメータレジスタも初期化する
;------------------------------------------------------------------------------
icreset
	CLRF	PORTE			; SPクロック=0(4.0) FM/SSG/SPリセットアクティブ
	MOVLW	100			; FM,SSG,SPリセット 1msウエイト
	CALL	mwait
	MOVLW	B'00000011'		; SPクロック=0(4.0) FM,SSG,SPリセット解除
	MOVWF	PORTE
	MOVLW	100			; リセット解除後しばらくの間YM2203が応答しないため1msウエイト
	CALL	mwait

	CLRF	VOICE			; FM音源レジスタ初期化
	CLRW
	CALL	loadfmprogram
	INCF	VOICE,F
	CLRW
	CALL	loadfmprogram
	INCF	VOICE,F
	CLRW
	CALL	loadfmprogram
		
	BSF	STATUS,IRP		; ◆ IRP=1
	MOVLW	LOW SSG_ENABLE		; SSG ENABLE初期化
	MOVWF	FSR
	MOVLW	0x3F
	MOVWF	INDF
	INCF	FSR,F
	MOVWF	INDF
	INCF	FSR,F
	MOVWF	INDF
	INCF	FSR,F
	MOVWF	INDF
	BCF	STATUS,IRP		; ◆ IRP=0
	RETURN

;------------------------------------------------------------------------------
; FM音源のプログラムをロードする
; 引数
;	VOICE	ボイス番号(0-2)(非破壊)
;	W	プログラム番号(0-7)(破壊)
; 使用変数
;	TMP23	ループカウンタ、その他テンポラリ
;------------------------------------------------------------------------------
loadfmprogram
	MOVWF	TMP23			; プログラム番号からEEPROMの開始アドレスを計算する
	RRF	TMP23,F
	RRF	TMP23,F
	RRF	TMP23,F
	RRF	TMP23,W
	ANDLW	0xE0
	MOVWF	EEPADDR

	BSF	STATUS,IRP		; ◆ IRP=1
	RLF	VOICE,W			; VOICE * 4
	MOVWF	TMP23
	RLF	TMP23,W
	ANDLW	0x0C
	ADDLW	LOW DT_MULTI		; ボイスによってFM音源レジスタの開始アドレスを変える
	MOVWF	FSR

	MOVLW	4			; 4OP分ループ
	MOVWF	TMP23
	MOVLW	0x3C			; VOICE1-OP4 DT/MULTI
	ADDWF	VOICE,W
	MOVWF	WRITE_ADDR
LOADFMPROGRAM_L1
	CALL	eepread			; データ読み出し
	MOVWF	WRITE_DATA		; DT/MULTI
	MOVWF	INDF
	CALL	fmwrite

	INCF	EEPADDR,F
	MOVLW	0x10
	ADDWF	WRITE_ADDR,F
	MOVLW	12
	ADDWF	FSR,F
;--
	CALL	eepread
	MOVWF	WRITE_DATA		; TL
	MOVWF	INDF
	CALL	fmwrite

	INCF	EEPADDR,F
	MOVLW	0x10
	ADDWF	WRITE_ADDR,F
	MOVLW	12
	ADDWF	FSR,F
;--
	CALL	eepread
	MOVWF	WRITE_DATA		; KS/AR
	MOVWF	INDF
	CALL	fmwrite

	INCF	EEPADDR,F
	MOVLW	0x10
	ADDWF	WRITE_ADDR,F
	MOVLW	12
	ADDWF	FSR,F
;--
	CALL	eepread
	MOVWF	WRITE_DATA		; DR
	MOVWF	INDF
	CALL	fmwrite

	INCF	EEPADDR,F
	MOVLW	0x10
	ADDWF	WRITE_ADDR,F
	MOVLW	12
	ADDWF	FSR,F
;--
	CALL	eepread
	MOVWF	WRITE_DATA		; SR
	MOVWF	INDF
	CALL	fmwrite

	INCF	EEPADDR,F
	MOVLW	0x10
	ADDWF	WRITE_ADDR,F
	MOVLW	12
	ADDWF	FSR,F
;--
	CALL	eepread			; SL/RR
	MOVWF	WRITE_DATA
	MOVWF	INDF
	CALL	fmwrite

	INCF	EEPADDR,F
	MOVLW	0x10
	ADDWF	WRITE_ADDR,F
	MOVLW	12
	ADDWF	FSR,F
;--
	CALL	eepread
	MOVWF	WRITE_DATA		; SSG-EG
	MOVWF	INDF
	CALL	fmwrite

	INCF	EEPADDR,F
	MOVLW	SSG_EG - DT_MULTI - 1	; 次のオペレータに移る
	SUBWF	FSR,F
	MOVLW	100
	SUBWF	WRITE_ADDR,F
	DECFSZ	TMP23,F
	 GOTO	LOADFMPROGRAM_L1

	MOVLW	0xB0			; FB/ALG
	ADDWF	VOICE,W
	MOVWF	WRITE_ADDR
	MOVLW	LOW FB_ALG
	ADDWF	VOICE,W
	MOVWF	FSR
	CALL	eepread
	MOVWF	WRITE_DATA
	MOVWF	INDF
	CALL	fmwrite

	INCF	EEPADDR,F
	MOVLW	LOW SLOT		; SLOT
	ADDWF	VOICE,W
	MOVWF	FSR
	CALL	eepread
	MOVWF	INDF

	BCF	STATUS,IRP		; ◆ IRP=0
	RETURN

;------------------------------------------------------------------------------
; FM音源のレジスタをプログラムチェンジプリセットにセーブする
; 引数
;	VOICE	ボイス番号(0-2)(非破壊)
;	W	プログラム番号(0-7)(破壊)
; 使用変数
;	TMP22,TMP23	ループカウンタ、その他テンポラリ
;------------------------------------------------------------------------------
savefmprogram
	MOVWF	TMP23			; プログラム番号からEEPROMの開始アドレスを計算する
	RRF	TMP23,F
	RRF	TMP23,F
	RRF	TMP23,F
	RRF	TMP23,W
	ANDLW	0xE0
	MOVWF	EEPADDR

	BSF	STATUS,IRP		; ◆ IRP=1
	RLF	VOICE,W			; VOICE * 4
	MOVWF	TMP23
	RLF	TMP23,W
	ANDLW	0x0C
	ADDLW	LOW DT_MULTI		; ボイスによってFM音源レジスタの開始アドレスを変える
	MOVWF	FSR

	MOVLW	4			; 4OP分ループ
	MOVWF	TMP23
SAVEFMPROGRAM_L1
	MOVLW	6			; DT/MULTI,TL,KS/AR,DR,SR,SL/RRの書き込み動作は同一なのでループで処理させる
	MOVWF	TMP22
SAVEFMPROGRAM_L2
	MOVF	INDF,W
	MOVWF	EEDATA
	CALL	eepwrite		; データ書き込み

	INCF	EEPADDR,F
	MOVLW	12
	ADDWF	FSR,F
	DECFSZ	TMP22,F
	 GOTO	SAVEFMPROGRAM_L2
;--
	MOVF	INDF,W			; SSG-EG
	MOVWF	EEDATA
	CALL	eepwrite

	INCF	EEPADDR,F
	MOVLW	SSG_EG - DT_MULTI - 1	; 次のオペレータに移る
	SUBWF	FSR,F
	DECFSZ	TMP23,F
	 GOTO	SAVEFMPROGRAM_L1

	MOVLW	LOW FB_ALG
	ADDWF	VOICE,W
	MOVWF	FSR
	MOVF	INDF,W			; FB/ALG
	MOVWF	EEDATA
	CALL	eepwrite
	INCF	EEPADDR,F

	MOVLW	LOW SLOT
	ADDWF	VOICE,W
	MOVWF	FSR
	MOVF	INDF,W			; SLOT
	MOVWF	EEDATA
	CALL	eepwrite

	BCF	STATUS,IRP		; ◆ IRP=0
	RETURN

;------------------------------------------------------------------------------
; ボイスオフルーチン
; VOICEにボイス番号をセットしてコールすると該当のボイスをオフする。
; ボイスがオンしていなくてもオフの規定の処理を実行する。
; フラグのセット処理は実行しない。
; TMP10を使用
;------------------------------------------------------------------------------
voiceoff				; ボイスオフ処理
	MOVF	VOICE,W			; ボイス番号が0〜2の時FM
	SUBLW	2
	BTFSC	STATUS,C
	 GOTO	VOICEOFF_FM

	MOVF	VOICE,W			; ボイス番号が3〜14の時SSG
	SUBLW	14
	BTFSC	STATUS,C
	 GOTO	VOICEOFF_SSG
	
VOICEOFF_SP				; ボイス番号が15の時SP
	MOVLW	PA1			; ボイスオフはPA1を発行することで行う
	CALL	fifo2write
	RETURN

VOICEOFF_FM
	MOVLW	0x28			; MIX
	MOVWF	WRITE_ADDR
	MOVF	VOICE,W
	MOVWF	WRITE_DATA
	CALL	fmwrite
	RETURN

VOICEOFF_SSG
	CALL	ssgchannel		; SSGチップ・チャンネル割り出し
	CLRF	WRITE_DATA		; ボリュームゼロ書き込み
	MOVF	SSGCHANNEL,W
	ADDLW	0x08
	MOVWF	WRITE_ADDR
	SWAPF	SSGCHIP,W
	ADDWF	WRITE_ADDR,F
	CALL	ssgwrite

	SWAPF	SSGCHIP,W		; SSG選択の数値を上位に設定
	ADDLW	7			; MIXアドレス
	MOVWF	WRITE_ADDR

	MOVLW	B'00001001'		; IORWFでSSGのENABLEレジスタに1を上書きする
	MOVWF	TMP10
VOICEOFF_SSG_DATA
	MOVF	SSGCHANNEL,F
	BTFSC	STATUS,Z
	 GOTO	VOICEOFF_SSG_DATA2	; SSGCHANNELがゼロになるまでTMP10を左シフトしてENABLEビットを該当のパートまで移動させる
	BCF	STATUS,C
	RLF	TMP10,F
	DECF	SSGCHANNEL,F
	GOTO	VOICEOFF_SSG_DATA
VOICEOFF_SSG_DATA2
	BSF	STATUS,IRP		; ◆ IRP=1
	MOVLW	LOW SSG_ENABLE		; 保存された他のパートのENABLEとミックスする
	ADDWF	SSGCHIP,W		; ENABLEはアクティブローのため、IORWFで該当パートを1にしないといけない
	MOVWF	FSR
	MOVF	TMP10,W
	IORWF	INDF,W
	MOVWF	INDF
	BCF	STATUS,IRP		; ◆ IRP=0
	MOVWF	WRITE_DATA
	CALL	ssgwrite
	RETURN

;■■■■■■■■■■■■■■■ FIFO関連ルーチン ■■■■■■■■■■■■■■■
;------------------------------------------------------------------------------
; FIFO読み出しルーチン
;	変数全てをポインタで渡すと処理が面倒なので、バッファごとに同じプログラムを用意する
;	バッファが空の場合は、エンプティフラグをセットしてリターンする。
;
; 引数
;	なし
;
; 戻り値
;	W			読み出したデータ
;	FIFOSTATUS-FIFO1EMPTY	FIFOバッファエンプティフラグ
;	FIFOSTATUS-FIFO2EMPTY
;
; 使用変数
;	なし
;------------------------------------------------------------------------------
fifo1read
	MOVF	USEDSIZE1,W
	BTFSS	STATUS,Z		; バッファエンプティチェック
	 GOTO	FIFO1READ1
	BSF	FIFOSTATUS,FIFO1EMPTY	; 空フラグを立ててリターン
	RETURN
FIFO1READ1
	BCF	FIFOSTATUS,FIFO1EMPTY	; 空フラグOFF
	BCF	STATUS,IRP		; ◆ IRP=0
	MOVF	READPTR1,W		; バッファを間接アクセス
	MOVWF	FSR
	MOVF	INDF,W
	MOVWF	READDATA
	DECF	USEDSIZE1,F		; FIFOのデータ数を-1(呼び出し時にチェックをしているので、マイナスになることはない)
	INCF	READPTR1,F		; 読み出しポインタをインクリメント

	BSF	PORTA,LED_MIDIDATA	; 残りデータLEDを消灯
	MOVF	USEDSIZE1,W		; MIDIフルLEDは割り込みルーチンでラッチを解除させる
	BTFSS	STATUS,Z
	 BCF	PORTA,LED_MIDIDATA	; バッファが1以上の時LED点灯
FIFO1READ2
	MOVLW	FIFOBUF1		; ポインタのロールオーバーのチェック
	ADDLW	FIFO1SIZE
	SUBWF	READPTR1,W
	BTFSS	STATUS,Z
	 GOTO	FIFO1READ3		; そのままリターン
	MOVLW	FIFOBUF1		; ロールオーバーしていたならば、先頭位置に移動
	MOVWF	READPTR1
FIFO1READ3
	MOVF	READDATA,W		; Wに読み込みデータを入れてリターン
	RETURN

fifo2read
	MOVF	USEDSIZE2,W
	BTFSS	STATUS,Z		; バッファエンプティチェック
	 GOTO	FIFO2READ1
	BSF	FIFOSTATUS,FIFO2EMPTY	; 空フラグを立ててリターン
	RETURN
FIFO2READ1
	BCF	FIFOSTATUS,FIFO2EMPTY	; 空フラグOFF
	BCF	STATUS,IRP		; ◆ IRP=0
	MOVF	READPTR2,W		; バッファを間接アクセス
	MOVWF	FSR
	MOVF	INDF,W
	MOVWF	READDATA
	DECF	USEDSIZE2,F		; FIFOのデータ数を-1(呼び出し時にチェックをしているので、マイナスになることはない)
	INCF	READPTR2,F		; 読み出しポインタをインクリメント

	MOVLW	B'00001110'		; SPバッファのLEDを全て消灯
	IORWF	PORTA,F
	MOVF	USEDSIZE2,W		; バッファ使用量LED用計算
	BTFSC	STATUS,Z		; バッファが空の時は以降のLED点灯を実行しない
	 GOTO	FIFO2READ2
	BCF	PORTA,LED_SPLEV1	; 1以上レベル1点灯
	MOVLW	(FIFOEND-FIFOBUF2)/2	; 半分以上
	SUBWF	USEDSIZE2,W
	BTFSC	STATUS,C
	 BCF	PORTA,LED_SPLEV2	; レベル2点灯
FIFO2READ2
	MOVLW	FIFOBUF2		; ポインタのロールオーバーのチェック
	ADDLW	FIFO2SIZE
	SUBWF	READPTR2,W
	BTFSS	STATUS,Z
	 GOTO	FIFO2READ3		; そのままリターン
	MOVLW	FIFOBUF2		; ロールオーバーしていたならば、先頭位置に移動
	MOVWF	READPTR2
FIFO2READ3
	MOVF	READDATA,W		; Wに読み込みデータを入れてリターン
	RETURN

;------------------------------------------------------------------------------
; FIFO書き込みルーチン
;	変数全てをポインタで渡すと処理が面倒なので、バッファごとに同じプログラムを用意する
;	バッファがいっぱいの場合は、データを書き込まずにフルフラグをセットしてリターンする。
;
; 引数
;	W		書き込むデータ(破壊)
;
; 戻り値
;	FIFOSTATUS-FIFO1FULL	FIFOバッファフルフラグ
;	FIFOSTATUS-FIFO2FULL
;
; 使用変数
;	なし
;------------------------------------------------------------------------------
fifo1write
	MOVWF	WRITEDATA1		; Wに入っている書き込みデータを退避
	MOVLW	FIFO1SIZE		; バッファフルチェック
	SUBWF	USEDSIZE1,W
	BTFSS	STATUS,Z
	 GOTO	FIFO1WRITE1
	BSF	FIFOSTATUS,FIFO1FULL	; フルフラグを立ててリターン
	BCF	PORTA,LED_MIDIFULL	; バッファフルLEDオン
	RETURN
FIFO1WRITE1
	BCF	FIFOSTATUS,FIFO1FULL	; フルフラグOFF
	BCF	STATUS,IRP		; ◆ IRP=0
	MOVF	WRITEPTR1,W		; バッファを間接アクセス
	MOVWF	FSR
	MOVF	WRITEDATA1,W
	MOVWF	INDF
	INCF	USEDSIZE1,F		; データ量を+1(呼び出し時にチェックをしているので、データ数オーバーになることはない)
	INCF	WRITEPTR1,F

	BCF	PORTA,LED_MIDIDATA	; 残データLEDオン、フルLEDは割り込みルーチンでラッチを解除させる
FIFO1WRITE2
	MOVLW	FIFOBUF1		; ポインタのロールオーバーのチェック
	ADDLW	FIFO1SIZE
	SUBWF	WRITEPTR1,W
	BTFSS	STATUS,Z
	 RETURN				; そのままリターン
	MOVLW	FIFOBUF1		; ロールオーバーしていたならば、先頭位置に移動
	MOVWF	WRITEPTR1
	RETURN

fifo2write				; FIFO2書き込み、書き込むデータをWに入れてコール
	MOVWF	WRITEDATA2		; Wに入っている書き込みデータを退避
	MOVLW	FIFO2SIZE		; バッファフルチェック
	SUBWF	USEDSIZE2,W
	BTFSS	STATUS,Z
	 GOTO	FIFO2WRITE1
	BSF	FIFOSTATUS,FIFO2FULL	; フルフラグを立ててリターン
	BCF	PORTA,LED_SPFULL	; バッファフルLEDオン
	RETURN
FIFO2WRITE1
	BCF	FIFOSTATUS,FIFO2FULL	; フルフラグOFF
	BCF	STATUS,IRP		; ◆ IRP=0
	MOVF	WRITEPTR2,W		; バッファを間接アクセス
	MOVWF	FSR
	MOVF	WRITEDATA2,W
	MOVWF	INDF
	INCF	USEDSIZE2,F		; データ量を+1(呼び出し時にチェックをしているので、データ数オーバーになることはない)
	INCF	WRITEPTR2,F

	MOVLW	B'00001110'		; SPバッファのLEDを全て消灯
	IORWF	PORTA,F
	MOVF	USEDSIZE2,W		; バッファ使用量LED用計算
	BTFSC	STATUS,Z		; バッファが空の時は12を実行しない
	 GOTO	FIFO2WRITE2
	BCF	PORTA,LED_SPLEV1	; 1以上レベル1点灯
	MOVLW	(FIFOEND-FIFOBUF2)/2
	SUBWF	USEDSIZE2,W
	BTFSC	STATUS,C
	 BCF	PORTA,LED_SPLEV2	; 半分以上レベル2点灯
FIFO2WRITE2
	MOVLW	FIFOBUF2		; ポインタのロールオーバーのチェック
	ADDLW	FIFO2SIZE
	SUBWF	WRITEPTR2,W
	BTFSS	STATUS,Z
	 RETURN				; そのままリターン
	MOVLW	FIFOBUF2		; ロールオーバーしていたならば、先頭位置に移動
	MOVWF	WRITEPTR2
	RETURN

;■■■■■■■■■■■■■■■ 音程関連ルーチン ■■■■■■■■■■■■■■■
;------------------------------------------------------------------------------
; ピッチベンド・CC#89,#121のためのピッチ送信ルーチン
; CHANNELで受信したパートの音程を再送信する。
;------------------------------------------------------------------------------
sendpitch
	MOVLW	16			; ボイスごとに今回のチャンネルと同じパートをチェックする
	MOVWF	TMP00
SENDPITCH_L1
	MOVF	TMP00,W
	ADDLW	VOICE_NOTE - 1		; ボイスがノートオンされている？
	MOVWF	FSR
	BTFSS	INDF,VOICE_NOTEOFF
	 GOTO	SENDPITCH_L2

	MOVF	TMP00,W
	SUBLW	3			; ボイス0〜2(FM)か？
	BTFSC	STATUS,C
	 GOTO	SENDPITCH_L2

	MOVF	TMP00,W
	SUBLW	16			; ボイス15(SP0256)か？
	BTFSC	STATUS,Z
	 GOTO	SENDPITCH_L2

	BSF	STATUS,IRP		; ◆ IRP=1
	MOVF	TMP00,W
	ADDLW	LOW VOICE_VELOCITY - 1	; ノートオフの時、サスティン中？
	MOVWF	FSR
	BTFSS	INDF,VOICE_SUSTAIN
	 GOTO	SENDPITCH_L1NEXT	; サスティンもされていない場合は、次のボイス
SENDPITCH_L2
	BCF	STATUS,IRP		; ◆ IRP=0
	MOVF	TMP00,W
	ADDLW	VOICE_PART - 1		; ボイスからパート番号を求める
	MOVWF	FSR
	BTFSC	INDF,VOICE_MUTE		; ミュートボイスの場合はスキップ
	 GOTO	SENDPITCH_L1NEXT

	MOVF	INDF,W
	ANDLW	0x1F
	MOVWF	TMP01

	ADDLW	PART_CHANNEL		; パートからチャンネルを求める
	MOVWF	FSR
	MOVLW	0x1F			; ミュートフラグも一度に調べる
	ANDWF	INDF,W
	SUBWF	CHANNEL,W
	BTFSS	STATUS,Z
	 GOTO	SENDPITCH_L1NEXT

	DECF	TMP00,W			; TMP00のオフセット除去
	MOVWF	VOICE
	MOVF	TMP01,W
	MOVWF	PART

	MOVLW	15
	SUBWF	VOICE,W
	BTFSC	STATUS,Z
	 GOTO	SENDPITCH_SP		; SP用ピッチベンドへ分岐
	
	MOVLW	3
	SUBWF	VOICE,W
	BTFSC	STATUS,C
	 GOTO	SENDPITCH_SSG		; SSG用ピッチベンドへ分岐

SENDPITCH_FM
	CALL	fm_setfnum
	GOTO	SENDPITCH_L1NEXT
SENDPITCH_SP
	CALL	sp_setclock
	GOTO	SENDPITCH_L1NEXT
SENDPITCH_SSG
	CALL	ssg_settone
	LCALL	ssg_setnp
	MOVLW	HIGH SENDPITCH_L1NEXT
	MOVWF	PCLATH			; ■ PCLATH
SENDPITCH_L1NEXT
	BCF	STATUS,IRP		; ◆ IRP=0
	DECFSZ	TMP00,F
	 GOTO	SENDPITCH_L1
	RETURN
;------------------------------------------------------------------------------
; FM音程セットルーチン
;	ボイス番号とパート番号をセットしてコールすると、指定されたボイスの周波数情報を再計算して音源ICにセットする。
;
; 引数
;	VOICE		ボイス番号(非破壊)
;	PART		ボイスが所属しているパート番号(非破壊)
;
; 戻り値
;	なし
;
; 使用変数
;	TMP11,12,13,20,21,22,23
;------------------------------------------------------------------------------
fm_setfnum
	MOVLW	VOICE_NOTE		; ノートロード
	ADDWF	VOICE,W
	MOVWF	FSR
	MOVF	INDF,W
	ANDLW	0x7F			; VOICE_NOTEOFF除去
	MOVWF	NOTE

	MOVLW	VOICE_PART		; パートチューニングロード
	ADDWF	PART,W
	MOVWF	FSR
	BCF	FLAG1,TUNING
	BTFSC	INDF,PART_TUNING
	 BSF	FLAG1,TUNING

	BSF	STATUS,IRP		; ◆ IRP=1
	MOVLW	LOW PART_PITCHBEND	; ピッチベンドロード
	ADDWF	PART,W
	MOVWF	FSR
	MOVF	INDF,W
	MOVWF	PITCHBEND

	MOVLW	LOW PART_BENDSENS	; ピッチベンドセンシティビティロード
	ADDWF	PART,W
	MOVWF	FSR
	MOVF	INDF,W
	ANDLW	B'00111111'
	MOVWF	BENDSENS
	BCF	STATUS,IRP		; ◆ IRP=0

	CALL	tonecalc		; F-Num計算
	MOVLW	HIGH FMTONE440
	MOVWF	TMP20
	MOVLW	LOW FMTONE440
	MOVWF	TMP21
	CALL	toneload

	RLF	OCTAVE,F		; オクターブを補正
	RLF	OCTAVE,F
	RLF	OCTAVE,W
	ANDLW	B'00111000'
	IORWF	TONE_H,W
	MOVWF	WRITE_DATA
	MOVLW	0xA4			; 上位音程書き込み
	ADDWF	VOICE,W			; ボイスを加算
	MOVWF	WRITE_ADDR
	CALL	fmwrite	

	MOVF	TONE_L,W
	MOVWF	WRITE_DATA
	MOVLW	0xA0			; 下位音程書き込み
	ADDWF	VOICE,W			; ボイスを加算
	MOVWF	WRITE_ADDR
	CALL	fmwrite
	RETURN

;------------------------------------------------------------------------------
; SSG音程セットルーチン
;	ボイス番号とパート番号をセットしてコールすると、指定されたボイスの周波数情報を再計算して音源ICにセットする。
;
; 引数
;	VOICE		ボイス番号(非破壊)
;	PART		ボイスが所属しているパート番号(非破壊)
;
; 戻り値
;	なし
;
; 使用変数
;	TMP11,12,13,20,21,22,23
;------------------------------------------------------------------------------
ssg_settone
	MOVLW	VOICE_NOTE		; ノートロード
	ADDWF	VOICE,W
	MOVWF	FSR
	MOVF	INDF,W
	ANDLW	0x7F			; VOICE_NOTEOFF除去
	MOVWF	NOTE

	MOVLW	VOICE_PART		; パートチューニングロード
	ADDWF	PART,W
	MOVWF	FSR
	BCF	FLAG1,TUNING
	BTFSC	INDF,PART_TUNING
	 BSF	FLAG1,TUNING

	BSF	STATUS,IRP		; ◆ IRP=1
	MOVLW	LOW PART_PITCHBEND	; ピッチベンドロード
	ADDWF	PART,W
	MOVWF	FSR
	MOVF	INDF,W
	MOVWF	PITCHBEND

	MOVLW	LOW PART_BENDSENS	; ピッチベンドセンシティビティロード
	ADDWF	PART,W
	MOVWF	FSR
	MOVF	INDF,W
	ANDLW	B'00111111'
	MOVWF	BENDSENS
	BCF	STATUS,IRP		; ◆ IRP=0

	CALL	tonecalc
	MOVLW	HIGH SSGTONE440
	MOVWF	TMP20
	MOVLW	LOW SSGTONE440
	MOVWF	TMP21
	CALL	toneload

	DECF	OCTAVE,F		; オクターブに応じて周波数情報を倍していく
TONESHIFTLOOP
	MOVF	OCTAVE,W
	BTFSC	STATUS,Z
	 GOTO	TONESHIFTNEXT		; オクターブのカウンタが0になるまで１オクターブ上げる
	DECF	OCTAVE,F
	BCF	STATUS,C
	RRF	TONE_H,F		; 音階データを２で割って１オクターブ上げる
	RRF	TONE_L,F
	GOTO	TONESHIFTLOOP
TONESHIFTNEXT
	MOVF	TONE_L,W
	MOVWF	WRITE_DATA

	CALL	ssgchannel		; SSGチップ・チャンネル割り出し
	BCF	STATUS,C		; SSGCHANNELの0,1,2を左シフトして、0,2,4のアドレスを作る
	RLF	SSGCHANNEL,W
	MOVWF	WRITE_ADDR
	SWAPF	SSGCHIP,W		; SSG選択の数値を上位に設定
	ADDWF	WRITE_ADDR,F
	CALL	ssgwrite	

	MOVF	TONE_H,W
	MOVWF	WRITE_DATA
	BCF	STATUS,C		; TMP03の0,1,2を左シフトして、0,2,4のアドレスを作る
	RLF	SSGCHANNEL,W
	ADDLW	1			; 1,3,5のアドレスに変更
	MOVWF	WRITE_ADDR
	SWAPF	SSGCHIP,W		; SSG選択の数値を上位に設定
	ADDWF	WRITE_ADDR,F
	CALL	ssgwrite	
	RETURN

;------------------------------------------------------------------------------
; SP0256クロックセットルーチン
;	パート番号をセットしてコールすると、指定されたパートのピッチベンドにあわせてクロックを変更する。
;
; 引数
;	PART		ボイスが所属しているパート番号(非破壊)
;
; 戻り値
;	なし
;
; 使用変数
;	なし
;------------------------------------------------------------------------------
sp_setclock
	BSF	STATUS,IRP		; ◆ IRP=1
	MOVLW	LOW PART_PITCHBEND	; ピッチベンドロード
	ADDWF	PART,W
	MOVWF	FSR
	MOVF	INDF,W
	MOVWF	PITCHBEND
	BCF	STATUS,IRP		; ◆ IRP=0

	MOVLW	0x40
	SUBWF	PITCHBEND,W
	BTFSC	STATUS,C		; ピッチベンドが0x40以上の時はクロックアップ
	 GOTO	SP_CLOCK_UP
SP_CLOCK_DOWN
	BSF	PORTE,SP_OSC
	RETURN
SP_CLOCK_UP
	BCF	PORTE,SP_OSC
	RETURN

;------------------------------------------------------------------------------
; SP0256用にプログラムEEPROMのフレーズデータを呼び出してFIFOにセットする
;
; 引数
;	W		フレーズインデックス番号
;
; 戻り値
;	なし
;
; 使用変数
;	なし
;------------------------------------------------------------------------------
phraseload
	BTFSC	PFLAG,SP_PHONETIC
	 ADDLW	16
	BCF	STATUS,RP0
	BSF	STATUS,RP1		; ◆ RP=2
	ADDLW	LOW SPHEX_INDEX		; フレーズのインデックスをロード
	MOVWF	EEADR
	MOVLW	HIGH SPHEX_INDEX
	MOVWF	EEADRH
	BTFSC	STATUS,C
	 INCF	EEADRH,F

	BSF	STATUS,RP0		; ◆ RP=3
	BSF	EECON1,EEPGD
	BSF	EECON1,RD
	NOP
	NOP
	BCF	STATUS,RP0		; ◆ RP=2
	MOVF	EEDATH,W		; インデックスから実際のアドレスへジャンプ
	MOVWF	EEADRH
	MOVF	EEDATA,W
	MOVWF	EEADR
PHRASELOAD_LOOP				; フレーズをロード
	BSF	STATUS,RP0		; ◆ RP=3
	BSF	EECON1,EEPGD
	BSF	EECON1,RD
	NOP
	NOP
	BCF	STATUS,RP0		; ◆ RP=2
	MOVF	EEDATA,W
	BCF	STATUS,RP1		; ◆ RP=0
	CALL	fifo2write		; フレーズデータをFIFOに入れる

	BSF	STATUS,RP1		; ◆ RP=2
	MOVLW	1
	ADDWF	EEADR,F			; フレーズアドレスインクリメント
	BTFSC	STATUS,C
	 INCF	EEADRH,F
	MOVF	EEDATH,W
	BTFSC	STATUS,Z		; 次のフレーズがある場合はZフラグが立つ
	 GOTO	PHRASELOAD_LOOP

	BCF	STATUS,RP1		; ◆ RP=0
	RETURN	

;------------------------------------------------------------------------------
; トーン表インデックス計算ルーチン
;	ノート番号、ピッチベンド、ピッチベンドセンシティビティから周波数の表引きに必要な番号を計算する。
;
; 引数
;	NOTE		受信したノート番号(非破壊)
;	PITCHBEND	ピッチベンド情報 0x80-0x40-0x00(非破壊)
;	BENDSENS	ピッチベンドセンシティビティ(非破壊)
;
; 戻り値
;	TONE_H,TONE_L	表引き番号
;	OCTAVE		オクターブシフト数値
;
; 使用変数
;	TMP11,12,13,20,21,22,23
;------------------------------------------------------------------------------
tonecalc
	MOVF	NOTE,W			; ノート番号を表引き番号に変換する
	MOVWF	TONE_H			; NOTEを6ビット左シフトする
	CLRF	TONE_L
	BCF	STATUS,C
	RRF	TONE_H,F
	RRF	TONE_L,F
	RRF	TONE_H,F
	RRF	TONE_L,F

	MOVLW	0x40			; アップでもダウンでも0x40からの絶対値を求める
	SUBWF	PITCHBEND,W		; PITCHBEND-0x40
	BTFSC	STATUS,C		; ベンドアップかダウンかチェック
	 GOTO	BENDCALC1
BENDDOWN1
	MOVF	PITCHBEND,W		; 0x40-PITCHBEND
	SUBLW	0x40
BENDCALC1
	MOVWF	TMP22
	MOVF	BENDSENS,W		; ピッチベンドセンシティビティを掛ける
	MOVWF	TMP23
	CALL	mul16

	MOVF	TONE_H,W
	MOVWF	TMP22
	MOVF	TONE_L,W
	MOVWF	TMP23

	MOVLW	0x40			; 絶対値で計算しているので、
	SUBWF	PITCHBEND,W		; ベンドアップかダウンかチェックして
	BTFSS	STATUS,C		; 実際の値を加減算する
	 GOTO	BENDDOWN2
	CALL	add16
	GOTO	BENDCALC2
BENDDOWN2
	MOVF	TMP20,W			; ベンドダウンの時は、項を入れ替えて計算する
	MOVWF	TMP13
	MOVF	TMP22,W
	MOVWF	TMP20
	MOVF	TMP13,W
	MOVWF	TMP22

	MOVF	TMP21,W
	MOVWF	TMP13
	MOVF	TMP23,W
	MOVWF	TMP21
	MOVF	TMP13,W
	MOVWF	TMP23

	CALL	sub16
BENDCALC2
	MOVLW	HIGH 768
	MOVWF	VAR2H
	MOVLW	LOW  768
	MOVWF	VAR2L
	CALL	div16
	MOVF	MODULO_H,W
	MOVWF	TONE_H
	MOVF	MODULO_L,W
	MOVWF	TONE_L
	DECF	VAR1L,W
	MOVWF	OCTAVE
	RETURN

;------------------------------------------------------------------------------
; トーンデータ表引きルーチン
;	音階データのベースアドレスに表引き番号を加算して周波数データをロードする。
;
; 引数
;	TONE_H,TONE_L	表引き番号(破壊)
;	TMP20,21	音階データのベースアドレスMSB,LSB(破壊)
;	FLAG1-TUNING	チューニング周波数フラグ(非破壊)
;
; 戻り値
;	TONE_H,TONE_L	音階データ
;
; 使用変数
;	TMP20,21,22,23
;------------------------------------------------------------------------------
toneload
	MOVLW	3
	BTFSC	FLAG1,TUNING		; チューニングフラグによってベースアドレスに768を加算する
	 ADDWF	TMP20,F			; 768=0x300なので上位に3を加算するだけでよい

	MOVF	TONE_H,W		; ベースアドレスに表引き番号を加算する
	MOVWF	TMP22
	MOVF	TONE_L,W
	MOVWF	TMP23
	CALL	add16
	
	MOVF	TMP20,W
	BSF	STATUS,RP1		; ◆ RP=2
	MOVWF	EEADRH
	BCF	STATUS,RP1		; ◆ RP=0
	MOVF	TMP21,W
	BSF	STATUS,RP1		; ◆ RP=2
	MOVWF	EEADR
	
	BSF	STATUS,RP0		; ◆ RP=3
	BSF	EECON1,EEPGD
	BSF	EECON1,RD
	NOP
	NOP
	BCF	STATUS,RP0		; ◆ RP=2
	MOVF	EEDATA,W
	BCF	STATUS,RP1		; ◆ RP=0
	MOVWF	TONE_L
	BSF	STATUS,RP1		; ◆ RP=2
	MOVF	EEDATH,W
	BCF	STATUS,RP1		; ◆ RP=0
	MOVWF	TONE_H
	RETURN

;■■■■■■■■■■■■■■■ 音量関連ルーチン ■■■■■■■■■■■■■■■
;------------------------------------------------------------------------------
; FMベロシティセットルーチン
;	ボイス番号とパート番号をセットしてコールすると、指定されたボイスの音量を再計算して音源ICにセットする。
;	PART_RXVELOCITYが0の時は最大音量をセットする。
;
; 引数
;	VOICE		ボイス番号(非破壊)
;	PART		ボイスが所属しているパート番号(非破壊)
;
; 戻り値
;	なし
;
; 使用変数
;	TMP13,20,21,22,23
;------------------------------------------------------------------------------
fm_setvelocity
	BSF	STATUS,IRP		; ◆ IRP=1
	MOVLW	LOW VOICE_VELOCITY	; ベロシティロード
	ADDWF	VOICE,W
	MOVWF	FSR
	MOVF	INDF,W
	ANDLW	0x7F
	MOVWF	VELOCITY

	BCF	STATUS,IRP		; ◆ IRP=0
	MOVLW	PART_CHANNEL		; ベロシティフラグチェック
	ADDWF	PART,W
	MOVWF	FSR
	MOVF	VELOCITY,W
	BTFSS	INDF,PART_RXVELOCITY
	 MOVLW	0x7F			; ベロシティを無視する場合は0x7Fをベロシティに使用する
	MOVWF	VELOCITY

	MOVLW	LOW VOICE_PART		; FMのTLレベル補正フラグロード
	ADDWF	PART,W
	MOVWF	FSR
	BCF	FLAG1,FM_LEVEL
	BTFSC	INDF,PART_FM_LEVEL
	 BSF	FLAG1,FM_LEVEL

	BSF	STATUS,IRP		; ◆ IRP=1
	MOVLW	LOW PART_VOLUME		; ボリュームロード
	ADDWF	PART,W
	MOVWF	FSR
	MOVF	INDF,W
	ANDLW	0x7F
	MOVWF	VOLUME

	MOVLW	LOW PART_EXPRESSION	; エクスプレッションロード
	ADDWF	PART,W
	MOVWF	FSR
	MOVF	INDF,W
	ANDLW	0x7F
	MOVWF	EXPRESSION

	CALL	velcalc			; ベロシティ×ボリューム×エクスプレッション
	MOVLW	0x4C			; CH1,OP4アドレスに+VOICEでチャンネル変更
	ADDWF	VOICE,W
	MOVWF	WRITE_ADDR
	
	CALL	FMVEL_OPTABLE		; オペレータを処理するループの回数をロード
	MOVWF	TMP12

	RLF	VOICE,W			; ボイス番号×4をしてTL-OP4のアドレスを出す
	MOVWF	TMP13
	RLF	TMP13,W
	ANDLW	B'00001100'
	ADDLW	LOW TL
	MOVWF	FSR
FMVEL_TLLOOP
	MOVF	VELOCITY,W		; ベロシティ×TL
	MOVWF	TMP22
	MOVF	INDF,W
	SUBLW	0x7F
	MOVWF	TMP23
	CALL	mul16

	BTFSS	FLAG1,FM_LEVEL		; FM音源のレベル補正を使用するか？
	 GOTO	FM_VEL_NOTMODIFY
	MOVF	VOLUME,F		; 補正するがVOLUMEまたはEXPRESSIONが0の時は
	BTFSC	STATUS,Z		; 音漏れを防ぐため補正対象から外す
	 GOTO	FM_VEL_NOTMODIFY
	MOVF	EXPRESSION,F
	BTFSC	STATUS,Z
	 GOTO	FM_VEL_NOTMODIFY
	MOVF	TMP20,W			; レベル補正を使用する場合は6bitを使用し、
	SUBLW	0x3F			; 0x3F-Velで減衰値とする
	GOTO	FM_VEL_WRITE
FM_VEL_NOTMODIFY
	RLF	TMP21,F			; レベル補正を使用しない場合は、
	RLF	TMP20,W			; 7bit目を持ってくる
	SUBLW	0x7F			; 0x7F-Velで減衰値とする
FM_VEL_WRITE
	MOVWF	WRITE_DATA
	CALL	fmwrite

	DECF	TMP12,F			; TMP12がゼロになるまでループ
	BTFSC	STATUS,Z
	 GOTO	FMVEL_END
	MOVLW	4			; WRITE_ADDR-4をして次のオペレータへ進む
	SUBWF	WRITE_ADDR,F
	INCF	FSR,F
	GOTO	FMVEL_TLLOOP

FMVEL_END
	BCF	STATUS,IRP		; ◆ IRP=0
	RETURN

FMVEL_OPTABLE				; アルゴリズムによって処理するTLの個数でループ回数を変化させる
	MOVLW	LOW FB_ALG		; アルゴリズムをチェック
	ADDWF	VOICE,W			; ボイスを加算
	MOVWF	FSR
	MOVLW	HIGH FMVEL_OPTABLE1
	MOVWF	PCLATH			; ■ PCLATH
	MOVF	INDF,W
	ANDLW	7
	ADDWF	PCL,F
FMVEL_OPTABLE1
	RETLW	1
	RETLW	1
	RETLW	1
	RETLW	1
	RETLW	2
	RETLW	3
	RETLW	3
	RETLW	4

;------------------------------------------------------------------------------
; SSGベロシティセットルーチン
;	ボイス番号とパート番号をセットしてコールすると、指定されたボイスの音量を再計算して音源ICにセットする。
;	PART_USEENVが1の時は、音量をセットせずにエンベロープシェープレジスタに書き込む。
;	ただし、SUPPRESS_SHAPESETが1の時は、エンベロープシェープを再セットしない。
;	PART_RXVELOCITYが0の時は最大音量をセットする。
;
; 引数
;	VOICE		ボイス番号(非破壊)
;	PART		ボイスが所属しているパート番号(非破壊)
;
; 戻り値
;	なし
;
; 使用変数
;	TMP11,12,13,20,21,22,23
;------------------------------------------------------------------------------
ssg_setvelocity
	CLRF	TMP12			; エンベロープを使うかどうかのフラグ用
	BSF	STATUS,IRP		; ◆ IRP=1
	MOVLW	LOW PART_ENVSHAPE	; エンベロープフラグチェック
	ADDWF	PART,W
	MOVWF	FSR
	BTFSS	INDF,PART_USEENV
	 GOTO	SSG_SETVELOCITY
	MOVLW	0x10			; エンベロープを使う時の固定値を書き込む
	MOVWF	TMP23
	MOVF	INDF,W
	MOVWF	TMP11			; エンベロープシェープロード
	GOTO	SSGWRITEVOLUME

SSG_SETVELOCITY
	COMF	TMP12,F			; エンベロープを使わない
	MOVLW	LOW VOICE_VELOCITY	; ベロシティロード
	ADDWF	VOICE,W
	MOVWF	FSR
	MOVF	INDF,W
	ANDLW	0x7F
	MOVWF	VELOCITY

	BCF	STATUS,IRP		; ◆ IRP=0
	MOVLW	PART_CHANNEL		; ベロシティフラグチェック
	ADDWF	PART,W
	MOVWF	FSR
	MOVF	VELOCITY,W
	BTFSS	INDF,PART_RXVELOCITY
	 MOVLW	0x7F			; ベロシティを無視する場合は0x7Fをベロシティに使用する
	MOVWF	VELOCITY

	MOVLW	LOW VOICE_PART		; SSGの対数レベル補正フラグロード
	ADDWF	PART,W
	MOVWF	FSR
	BCF	FLAG1,SSG_LEVEL
	BTFSC	INDF,PART_SSG_LEVEL
	 BSF	FLAG1,SSG_LEVEL

	BSF	STATUS,IRP		; ◆ IRP=1
	MOVLW	LOW PART_VOLUME		; ボリュームロード
	ADDWF	PART,W
	MOVWF	FSR
	MOVF	INDF,W
	ANDLW	0x7F
	MOVWF	VOLUME

	MOVLW	LOW PART_EXPRESSION	; エクスプレッションロード
	ADDWF	PART,W
	MOVWF	FSR
	MOVF	INDF,W
	ANDLW	0x7F
	MOVWF	EXPRESSION

	CALL	velcalc			; ベロシティ×ボリューム×エクスプレッション
	BTFSC	FLAG1,SSG_LEVEL		; SSG対数補正を使う場合は、SSGVOLUMEへ飛ぶ
	 GOTO	SSGVOLUME
NO_SSGVOLUME
	RRF	VELOCITY,W
	MOVWF	TMP23
	RRF	TMP23,F			; 対数補正を使わない場合は、VELOCITYの6〜3ビットをそのまま値として使用する
	RRF	TMP23,W
	ANDLW	0x0F
	MOVWF	TMP23
	GOTO	SSGWRITEVOLUME
SSGVOLUME				; SSGの音量は対数のため、ベロシティの値を直接代入すると表現がおかしくなるので補正する
	MOVLW	15			; 117 98 83 70 58 49 41 35 29 25 21 17 15 12 10
	MOVWF	TMP23

	MOVLW	117			; 15
	SUBWF	VELOCITY,W
	BTFSC	STATUS,C
	 GOTO	SSGWRITEVOLUME
	DECF	TMP23,F

	MOVLW	98			; 14
	SUBWF	VELOCITY,W
	BTFSC	STATUS,C
	 GOTO	SSGWRITEVOLUME
	DECF	TMP23,F

	MOVLW	83			; 13
	SUBWF	VELOCITY,W
	BTFSC	STATUS,C
	 GOTO	SSGWRITEVOLUME
	DECF	TMP23,F

	MOVLW	70			; 12
	SUBWF	VELOCITY,W
	BTFSC	STATUS,C
	 GOTO	SSGWRITEVOLUME
	DECF	TMP23,F

	MOVLW	58			; 11
	SUBWF	VELOCITY,W
	BTFSC	STATUS,C
	 GOTO	SSGWRITEVOLUME
	DECF	TMP23,F

	MOVLW	49			; 10
	SUBWF	VELOCITY,W
	BTFSC	STATUS,C
	 GOTO	SSGWRITEVOLUME
	DECF	TMP23,F

	MOVLW	41			; 9
	SUBWF	VELOCITY,W
	BTFSC	STATUS,C
	 GOTO	SSGWRITEVOLUME
	DECF	TMP23,F

	MOVLW	35			; 8
	SUBWF	VELOCITY,W
	BTFSC	STATUS,C
	 GOTO	SSGWRITEVOLUME
	DECF	TMP23,F

	MOVLW	29			; 7
	SUBWF	VELOCITY,W
	BTFSC	STATUS,C
	 GOTO	SSGWRITEVOLUME
	DECF	TMP23,F

	MOVLW	25			; 6
	SUBWF	VELOCITY,W
	BTFSC	STATUS,C
	 GOTO	SSGWRITEVOLUME
	DECF	TMP23,F

	MOVLW	21			; 5
	SUBWF	VELOCITY,W
	BTFSC	STATUS,C
	 GOTO	SSGWRITEVOLUME
	DECF	TMP23,F

	MOVLW	17			; 4
	SUBWF	VELOCITY,W
	BTFSC	STATUS,C
	 GOTO	SSGWRITEVOLUME
	DECF	TMP23,F

	MOVLW	15			; 3
	SUBWF	VELOCITY,W
	BTFSC	STATUS,C
	 GOTO	SSGWRITEVOLUME
	DECF	TMP23,F

	MOVLW	12			; 2
	SUBWF	VELOCITY,W
	BTFSC	STATUS,C
	 GOTO	SSGWRITEVOLUME
	DECF	TMP23,F

	MOVLW	10			; 1
	SUBWF	VELOCITY,W
	BTFSC	STATUS,C
	 GOTO	SSGWRITEVOLUME

	CLRF	TMP23			; 0
SSGWRITEVOLUME
	MOVF	TMP23,W
	MOVWF	WRITE_DATA

	CALL	ssgchannel		; SSGチップ・チャンネル割り出し
	MOVLW	8			; 音量アドレス8+レジスタ選択を行う
	ADDWF	SSGCHANNEL,W
	MOVWF	WRITE_ADDR
	SWAPF	SSGCHIP,W		; SSG選択の数値を上位に設定
	ADDWF	WRITE_ADDR,F
	CALL	ssgwrite

	MOVF	TMP12,W			; エンベロープを使わない時は、そのまま終了。
	BTFSS	STATUS,Z
	 GOTO	SETVEL_END

	BTFSC	FLAG1,SUPPRESS_SHAPESET	; エンベロープシェープの再セットが抑制されている場合は、そのまま終了。
	 GOTO	SETVEL_END

	MOVF	TMP11,W			; エンベロープシェープを書く
	ANDLW	0x0F
	MOVWF	WRITE_DATA
	MOVLW	0x0D			; エンベロープシェープレジスタに書く
	MOVWF	WRITE_ADDR
	SWAPF	SSGCHIP,W		; SSG選択の数値を上位に設定
	ADDWF	WRITE_ADDR,F
	CALL	ssgwrite
SETVEL_END
	BCF	STATUS,IRP		; ◆ IRP=0
	RETURN

;------------------------------------------------------------------------------
; ベロシティ値計算ルーチン
;
; 引数
;	VELOCITY	受信したベロシティ0x00-0x7F(破壊)
;	VOLUME		ボリューム情報 0x00-0x80(非破壊)
;	EXPRESSION	エクスプレッション情報 0x00-0x80(非破壊)
;
; 戻り値
;	VELOCITY	計算されたベロシティ0x00-0x7F
;
; 使用変数
;	TMP13,20,21,22,23
;------------------------------------------------------------------------------
velcalc
	MOVF	VELOCITY,W		; ベロシティ×ボリューム
	MOVWF	TMP22
	MOVF	VOLUME,W
	MOVWF	TMP23
	CALL	mul16
	RLF	TMP21,F			; 7*7bitの計算なので、*2して最上位を8ビットに収める
	RLF	TMP20,F

	MOVF	TMP20,W			; 結果×エクスプレッション
	MOVWF	TMP22
	MOVF	EXPRESSION,W
	MOVWF	TMP23
	CALL	mul16
	RLF	TMP21,F			; 7*7bitの計算なので、*2して最上位を8ビットに収める
	RLF	TMP20,W

	MOVWF	VELOCITY		; 結果×エクスプレッションをベロシティに入れて返す
	RETURN

;■■■■■■■■■■■■■■■ 算術演算ルーチン ■■■■■■■■■■■■■■■
;------------------------------------------------------------------------------
; 足し算 16bit + 16bit = 16bit
;
; 引数
;	TMP20	足される数 MSB(破壊)
;	TMP21	足される数 LSB(破壊)
;	TMP22	足す数 MSB(非破壊)
;	TMP23	足す数 LSB(非破壊)
;
; 戻り値
;	TMP20	和 MSB
;	TMP21	和 LSB
;
; 使用変数
;	なし
;------------------------------------------------------------------------------
add16
	MOVF	TMP23,W
	ADDWF	TMP21,F
	BTFSC	STATUS,C
	 INCF	TMP20,F
	MOVF	TMP22,W
	ADDWF	TMP20,F
	RETURN

;------------------------------------------------------------------------------
; 引き算 16bit - 16bit = 16bit
;
; 引数
;	TMP20	引かれる数 MSB(破壊)
;	TMP21	引かれる数 LSB(破壊)
;	TMP22	引く数 MSB(非破壊)
;	TMP23	引く数 LSB(非破壊)
;
; 戻り値
;	TMP20	差 MSB
;	TMP21	差 LSB
;
; 使用変数
;	なし
;------------------------------------------------------------------------------
sub16
	MOVF	TMP23,W
	SUBWF	TMP21,F
	BTFSS	STATUS,C
	 DECF	TMP20,F
	MOVF	TMP22,W
	SUBWF	TMP20,F
	RETURN

;------------------------------------------------------------------------------
; 掛け算 8bit * 8bit = 16bit
;
; 引数
;	TMP22		かけられる数(非破壊)
;	TMP23		かける数(破壊)
;
; 戻り値
;	TMP20		積 MSB
;	TMP21		積 LSB
;
; 使用変数
;	TMP13		ループカウンタ
;------------------------------------------------------------------------------
mul16
	CLRF	TMP20
	CLRF	TMP21
	MOVLW	8
	MOVWF	TMP13
	MOVF	TMP22,W
	BCF	STATUS,C
MUL16LOOP
	RRF	TMP23,F
	BTFSC	STATUS,C
	 ADDWF	TMP20,F
	RRF	TMP20,F
	RRF	TMP21,F
	DECFSZ	TMP13,F
	 GOTO	MUL16LOOP
	RETURN

;------------------------------------------------------------------------------
; 割り算 16bit / 16bit = 商16bit + 剰余16bit
;	http://elm-chan.org/docs/avrlib/div16.txt
; 引数		
; 	TMP12	VAR2H		割る数 MSB(非破壊)
;	TMP13	VAR2L		割る数 LSB(非破壊)
;	TMP20	VAR1H		割られる数 MSB(破壊)
;	TMP21	VAR1L		割られる数 LSB(破壊)
;
; 戻り値
;	TMP20	VAR1H		商 MSB
;	TMP21	VAR1L		商 LSB
;	TMP22	MODULO_H 	剰余 MSB
;	TMP23	MODULO_L 	剰余 LSB
;
; 使用変数
;	TMP11			ループカウンタ
;------------------------------------------------------------------------------
div16
	CLRF	MODULO_H		; clr	modh
	CLRF	MODULO_L		; clr	modl
	MOVLW	16			; ldi	tmp11,16
	MOVWF	TMP11
DIV16LOOP
	BCF	STATUS,C		; lsl	var1l
	RLF	VAR1L,F
	RLF	VAR1H,F			; rol	var1h
	RLF	MODULO_L,F		; rol	modl
	RLF	MODULO_H,F		; rol	modh
	MOVF	VAR2L,W			; cp	mod0,var2l
	SUBWF	MODULO_L,W
	MOVF	VAR2H,W			; cpc	mod1,var2h
	BTFSS	STATUS,C
	 INCF	VAR2H,W
	SUBWF	MODULO_H,W
	BTFSS	STATUS,C		; brcs	DIV16NEXTLOOP
	 GOTO	DIV16NEXTLOOP
	INCF	VAR1L,F			; inc	var1l
	MOVF	VAR2L,W			; sub	modl,var2l
	SUBWF	MODULO_L,F
	MOVF	VAR2H,W			; sbc	modh,var2h
	BTFSS	STATUS,C
	 INCF	VAR2H,W
	SUBWF	MODULO_H,F
DIV16NEXTLOOP
	DECFSZ	TMP11,F			; dec	tmp11
	 GOTO	DIV16LOOP		; brne	DIV16LOOP
	RETURN				; ret

;■■■■■■■■■■■■■■■ 音源コントロールルーチン ■■■■■■■■■■■■■■■
;------------------------------------------------------------------------------
; YM2203書き込みルーチン ステップ数はYM2203のBUSYフラグに依存する
; データはCS/WRの立ち上がりで取り込むはずがそれ以前で取り込む誤動作が発生したため、
; A0セットアップの前にPORTBに出力すること。
;
; 引数
;	WRITE_ADDR	レジスタアドレス(非破壊)
;	WRITE_DATA	レジスタデータ(非破壊)
;
; 戻り値
;	なし
;
; 使用変数
;	なし
;------------------------------------------------------------------------------
fmwrite
	CALL	fmbusycheck		; BUSYフラグをチェックしておく

	MOVF	WRITE_ADDR,W		; 書き込むアドレスをロード
	MOVWF	PORTB			; D0-D7セットアップ
	
	BCF	PORTD,A0		; A0セットアップ(アドレスモード)
	MOVLW	FMWRCS			; /WR/CSセットアップ
	MOVWF	PORTC
	MOVLW	FMNOCS			; /WR/CSを元に戻す(FM起動)
	MOVWF	PORTC
	
	CALL	fmbusycheck

	MOVF	WRITE_DATA,W		; 書き込むデータをロード
	MOVWF	PORTB			; D0-D7セットアップ
	
	BSF	PORTD,A0		; A0セットアップ(データモード)
	MOVLW	FMWRCS			; /WR/CSセットアップ
	MOVWF	PORTC
	MOVLW	FMNOCS			; /WR/CSを元に戻す(FM起動)
	MOVWF	PORTC
	RETURN

fmbusycheck				; BUSYフラグチェック
	BSF	STATUS,RP0		; ◆ RP=1
	COMF	TRISB,F			; PORTBを入力に変更
	BCF	STATUS,RP0		; ◆ RP=0
	BCF	PORTD,A0		; A0セットアップ
FMBUSYCHECK_LOOP
	MOVLW	FMRDCS			; /RD/CSセットアップ
	MOVWF	PORTC
	NOP				; Min250ns必要なのでウエイト
	BTFSS	PORTB,FMBUSY
	 GOTO	FMBUSYCHECK_RETURN
	MOVLW	FMNOCS			; /RD/CSを元に戻す
	MOVWF	PORTC
	GOTO	FMBUSYCHECK_LOOP
FMBUSYCHECK_RETURN
	MOVLW	FMNOCS			; /RD/CSを元に戻す
	MOVWF	PORTC			; ◆ RP=1
	BSF	STATUS,RP0		; PORTBを出力に変更
	COMF	TRISB,F
	BCF	STATUS,RP0		; ◆ RP=0
	RETURN

;------------------------------------------------------------------------------
; YMZ294書き込みルーチン
;
; 引数
;	WRITE_ADDR	bit5-4= SSG1-4の選択(破壊)
;			bit3-0= YMZ294のレジスタアドレス(破壊)
;	WRITE_DATA	レジスタデータ(非破壊)
;
; 戻り値
;	なし
;
; 使用変数
;	TMP22,23
;------------------------------------------------------------------------------
ssgwrite
	SWAPF	WRITE_ADDR,W		; 4,5ビットの値をダウンカウンタとして利用
	ANDLW	B'00000011'
	ADDLW	1
	MOVWF	TMP22
	MOVLW	0x08
	MOVWF	TMP23
SSGWRITE_BITLOOP
	RLF	TMP23,F			; 1〜4回シフトする
	DECFSZ	TMP22,F
	 GOTO	SSGWRITE_BITLOOP
	MOVLW	0x0F
	ANDWF	WRITE_ADDR,W		; 下位4ビットとマージ
	ADDWF	TMP23,W
	MOVWF	WRITE_ADDR

	BCF	PORTD,A0		; A0セットアップ(アドレスモード)

	COMF	WRITE_ADDR,W		; 書き込みアドレスをビット反転してロード
	ANDLW	B'11110000'
	IORLW	B'00000100'		; A0=0,/ALD=1に注意
	MOVWF	PORTD			; 4本の/WR/CSを一度にセットアップ

	MOVF	WRITE_ADDR,W
	ANDLW	B'00001111'		; アドレスだけを抽出
	MOVWF	PORTB			; D0-D7セットアップ

	MOVLW	B'11110100'		; /WR/CSを全て元に戻す(SSG起動)
	MOVWF	PORTD

	NOP				; READ MODIFY WRITE誤動作防止
	BSF	PORTD,A0		; A0セットアップ(データモード)

	COMF	WRITE_ADDR,W		; 書き込みアドレスをビット反転してロード
	ANDLW	B'11110000'
	IORLW	B'00001100'		; A0=1,/ALD=1に注意
	MOVWF	PORTD			; 4本の/WR/CSを一度にセットアップ

	MOVF	WRITE_DATA,W		; 書き込むデータをロード
	MOVWF	PORTB			; D0-D7セットアップ

	MOVLW	B'11111100'		; /WR/CSを全て元に戻す(SSG起動)
	MOVWF	PORTD
	RETURN

;------------------------------------------------------------------------------
; SP0256書き込みルーチン
;
; 引数
;	WRITE_DATA	SP0256のデータ選択
;
; 戻り値
;	なし
;
; 使用変数
;	なし
;------------------------------------------------------------------------------
spwrite
	MOVLW	64			; 64以上の時はPA1を代入する
	SUBWF	WRITE_DATA,W
	MOVF	WRITE_DATA,W
	BTFSC	STATUS,C
	 MOVLW	PA1
	MOVWF	PORTB
SPWRITE_LRQ_POLLING
	BTFSC	PORTD,LRQ		; /LRQ=0になっている事を確認
	 GOTO	SPWRITE_LRQ_POLLING	; /LRQ条件を満たすまでループ

	BCF	PORTD,ALD		; SP0256起動
	NOP
	BSF	PORTD,ALD		; SP0256終了
	RETURN

;■■■■■■■■■■■■■■■ 雑用ルーチン ■■■■■■■■■■■■■■■
;------------------------------------------------------------------------------
; ボイス番号からSSGのチップとチャンネルを割り出すルーチン
; VOICEでカウントされるループでSSGのチップとチャンネル番号が必要な時に使う。
; 引数
;	VOICE	ボイス番号(非破壊)
; 戻り値
;	SSGCHIP		チップ選択番号
;	SSGCHANNEL	チャンネル選択番号
; 使用変数
;	なし
;------------------------------------------------------------------------------
ssgchannel
	MOVLW	3			; SSGボイスは3から始まる
	SUBWF	VOICE,W			; どのYMZ294のどのパートを駆動するか判定する
	MOVWF	SSGCHANNEL
	CLRF	SSGCHIP
SSGCHANNEL_LOOP
	MOVLW	3
	SUBWF	SSGCHANNEL,W
	BTFSS	STATUS,C
	 RETURN				; 3以下になったらループを抜けるてリターン
	MOVWF	SSGCHANNEL
	INCF	SSGCHIP,F
	GOTO	SSGCHANNEL_LOOP

;------------------------------------------------------------------------------
; パートループ用受信チャンネルチェックルーチン
; PARTでカウントされるパートループで受信したチャンネルが一致するか確認を行う。
; パートミュートも同時にチェックされ、受信処理が必要ならばZフラグがセットされる。
; リターン後は以下の要領で分岐する。
;	BTFSS	STATUS,Z
;	 GOTO	NEXTLOOP
;------------------------------------------------------------------------------
part_channel_check_P0
	MOVF	PART,W
	ADDLW	PART_CHANNEL-1
	MOVWF	FSR
	MOVF	INDF,W
	ANDLW	0x1F
	SUBWF	CHANNEL,W
	RETURN

;------------------------------------------------------------------------------
; ボイスループ用受信チャンネルチェックルーチン
; VOICEでカウントされるボイスループで受信したチャンネルが一致するか確認を行う。
; VOICEは+1でオフセットされている。
; ボイス・パートミュートも同時にチェックされ、受信処理が必要ならばZフラグがセットされる。
; リターン後は以下の要領で分岐する。
;	BTFSS	STATUS,Z
;	 GOTO	NEXTLOOP
;------------------------------------------------------------------------------
voice_channel_check_P0
	MOVF	VOICE,W
	ADDLW	VOICE_PART-1
	MOVWF	FSR
	BCF	STATUS,Z
	BTFSC	INDF,VOICE_MUTE
	 RETURN
	MOVF	INDF,W
	ANDLW	0x0F
	ADDLW	PART_CHANNEL
	MOVWF	FSR	
	MOVF	INDF,W
	ANDLW	0x1F
	SUBWF	CHANNEL,W
	RETURN

;------------------------------------------------------------------------------
; 内蔵EEPROMアクセスルーチン
;------------------------------------------------------------------------------
eepread
	MOVF	EEPADDR,W		; アドレスはプログラム中のページ切り替えが面倒なので、別に用意しておく
	BSF	STATUS,RP1		; ◆ RP=2
	MOVWF	EEADR
	BSF	STATUS,RP0		; ◆ RP=3
	BCF	EECON1,EEPGD		; データEEPROMを選択
	BSF	EECON1,RD		; 読み出し
	BCF	STATUS,RP0		; ◆ RP=2
	MOVF	EEDATA,W		; Wに入れてリターン
	BCF	STATUS,RP1		; ◆ RP=0
	RETURN

eepwrite
	BSF	STATUS,RP1		; ◆ RP=2
	MOVWF	EEDATA			; データをWに入れてコール
	BCF	STATUS,RP1		; ◆ RP=0
	MOVF	EEPADDR,W		; 書き込みアドレスのロード
	BSF	STATUS,RP1		; ◆ RP=2
	MOVWF	EEADR
	BSF	STATUS,RP0		; ◆ RP=3
	BCF	EECON1,EEPGD		; データEEPROMを選択
	BSF	EECON1,WREN
	MOVLW	0x55			; 書き込みパターン
	MOVWF	EECON2
	MOVLW	0xAA
	MOVWF	EECON2
	BSF	EECON1,WR		; 書き込み
EEPWRITEPOLL
	BTFSC	EECON1,WR		; 書き込みが終わるまでループ
	 GOTO	EEPWRITEPOLL
	BCF	EECON1,WREN		; 書き込み保護
	BCF	STATUS,RP1		; ◆ RP=0
	BCF	STATUS,RP0
	RETURN

;------------------------------------------------------------------------------
; ウエイトルーチン
;
; 引数
;	W		ウエイト時間(破壊)
;
; 戻り値
;	なし
;
; 使用変数
;	TMP23		wait
;	TMP22,23	mwait
;	TMP21,22,23	lwait
;------------------------------------------------------------------------------
lwait					; 長時間ウエイト
	MOVWF	TMP21			; Wにループ回数をセット後CALL
lwait1					; W*12808+4 [Step]
	MOVLW	0
	CALL	mwait
	DECFSZ	TMP21,F
	 GOTO	lwait1
	RETURN

mwait					; 中時間ウェイト
	MOVWF	TMP22			; Wにループ回数をセット後CALL
mwait1					; W*50+4 [Step]
	MOVLW	14
	CALL	wait
	DECFSZ	TMP22,F
	 GOTO	mwait1
	RETURN

wait					; 短時間ウェイト
	MOVWF	TMP23			; Wにループ回数をセット後CALL
wait1					; W*3+4 [Step]
	DECFSZ	TMP23,F
	 GOTO	wait1
	RETURN

;------------------------------------------------------------------------------
; ページ1
;------------------------------------------------------------------------------
	ORG	0800H
;------------------------------------------------------------------------------
; B0 コントロールチェンジ
;	OP4 OP2 OP3 OP1
; ALG	|------3------|	0-7
; FB	 -   -   -   9	0-7
; MLT	12  13  14  15	0-15
; DT	16  17  18  19	0-7
; TL	20  21  22  23	0-127
; KS	24  25  26  27	0-3
; EG	28  29  30  31	0-15
; AR	44  45  46  47  0-31
; DR	48  49  50  51	0-31
; SL	52  53  54  55	0-15
; SR	56  57  58  59	0-31
; RR	60  61  62  63	0-15
; SLOT	|------35-----|	0-15
;
; Vol-Incr	39	00-40-7F(-64-0-+63)
; Pitch-Incr	41	00-40-7F(-64-0-+63)
; Exp-Incr	43	00-40-7F(-64-0-+63)
; Envelope	80,81	0-8
; Env0L		82	0-127
; Env1L		83	0-127(128-255)
; Env0H		84	0-127
; Env1H		85	0-127(128-255)
; Noise		86	0-31
;
; DataEntry-M	6	RPNフラグが両方0の時BENDSENSの値を変更、音程は再送信しない。
; NRPN-L	98	無条件にPART_RPNL=1
; NRPN-M	99	無条件にPART_RPNM=1
; RPN-L		100	0の時PART_RPNL=0
; RPN-M		101	0の時PART_RPNM=0
;
; Volume-M	7	PART_RXVOLUME=1の時パートに値を取り込む、無条件に音量を再送信する。
; Expression-M	11	PART_RXEXPRESSION=1の時パートに値を取り込む、無条件に音量を再送信する。
; Hold		64	0-63:VOICE_SUSTAIN=1のボイスを消音、64-127:PART_SUSTAINフラグオン
; AllSoundOff	120	ハード的に消音、ノートオフはしない
; ResetAllCntl	121	EXP=127,BEND=64,RPN=NULL,HOLD=OFF,トーン・ベロシティ再送信
; AllNoteOff	123	ノートオフ、サスティン移行処理を含める
;------------------------------------------------------------------------------
EVENT_CONTROL_P1
	MOVF	PARAM1,W		;PARAM1によってコントロールチェンジのルーチンへ分岐する
	MOVWF	TMP00
	MOVLW	LOW CTRLPROC_TABLE
	ADDWF	TMP00,F
	MOVLW	HIGH CTRLPROC_TABLE
	BTFSC	STATUS,C
	 ADDLW	1
	MOVWF	PCLATH
	MOVF	TMP00,W
	MOVWF	PCL
CTRLPROC_TABLE
	GOTO	CTRL_RETURN_P1		; 0
	GOTO	CTRL_RETURN_P1		; 1
	GOTO	CTRL_RETURN_P1		; 2
	GOTO	CTRL_ALG		; 3 CTRL_ALG		0-7 8以上は7とする
	GOTO	CTRL_RETURN_P1		; 4
	GOTO	CTRL_RETURN_P1		; 5
	GOTO	CTRL_DATAENTRY		; 6 CTRL_DATAENTRY	RPN=0用 0-63 64以上は63とする
	GOTO	CTRL_VOLUME		; 7 CTRL_VOLUME		0-127
	GOTO	CTRL_RETURN_P1		; 8
	GOTO	CTRL_FB			; 9 CTRL_FB		0-7 8以上は7とする
	GOTO	CTRL_RETURN_P1		; 10
	GOTO	CTRL_EXPRESSION		; 11 CTRL_EXPRESSION	0-127
	GOTO	CTRL_MULTI		; 12 MLT OP4		0-15 16以上は15とする
	GOTO	CTRL_MULTI		; 13 MLT OP2
	GOTO	CTRL_MULTI		; 14 MLT OP3
	GOTO	CTRL_MULTI		; 15 MLT OP1
	GOTO	CTRL_DT			; 16 DT OP4		0-7 8以上は7とする
	GOTO	CTRL_DT			; 17 DT OP2
	GOTO	CTRL_DT			; 18 DT OP3
	GOTO	CTRL_DT			; 19 DT OP1
	GOTO	CTRL_TL			; 20 TL OP4		0-127
	GOTO	CTRL_TL			; 21 TL OP2
	GOTO	CTRL_TL			; 22 TL OP3
	GOTO	CTRL_TL			; 23 TL OP1
	GOTO	CTRL_KS			; 24 KS OP4		0-3 4以上は3とする
	GOTO	CTRL_KS			; 25 KS OP2
	GOTO	CTRL_KS			; 26 KS OP3
	GOTO	CTRL_KS			; 27 KS OP1
	GOTO	CTRL_EG			; 28 EG OP4		0-8 9以上は0とする
	GOTO	CTRL_EG			; 29 EG OP2
	GOTO	CTRL_EG			; 30 EG OP3
	GOTO	CTRL_EG			; 31 EG OP1
	GOTO	CTRL_RETURN_P1		; 32
	GOTO	CTRL_RETURN_P1		; 33
	GOTO	CTRL_RETURN_P1		; 34
	GOTO	CTRL_SLOT		; 35 SLOT		0-15 16以上は15とする
	GOTO	CTRL_RETURN_P1		; 36
	GOTO	CTRL_RETURN_P1		; 37
	GOTO	CTRL_RETURN_P1		; 38
	GOTO	CTRL_VOL_INCR		; 39 CTRL_VOL_INCR	0 64 127 (-64 0 +63)
	GOTO	CTRL_RETURN_P1		; 40
	GOTO	CTRL_PITCH_INCR		; 41 CTRL_PITCH_INCR	0 64 127 (-64 0 +63)
	GOTO	CTRL_RETURN_P1		; 42
	GOTO	CTRL_EXP_INCR		; 43 CTRL_EXP_INCR	0 64 127 (-64 0 +63)
	GOTO	CTRL_AR			; 44 AR OP4		0-31 32以上は31とする
	GOTO	CTRL_AR			; 45 AR OP2
	GOTO	CTRL_AR			; 46 AR OP3
	GOTO	CTRL_AR			; 47 AR OP1
	GOTO	CTRL_DR			; 48 DR OP4		0-31 32以上は31とする
	GOTO	CTRL_DR			; 49 DR OP2
	GOTO	CTRL_DR			; 50 DR OP3
	GOTO	CTRL_DR			; 51 DR OP1
	GOTO	CTRL_SL			; 52 SL OP4		0-15 16以上は15とする
	GOTO	CTRL_SL			; 53 SL OP2
	GOTO	CTRL_SL			; 54 SL OP3
	GOTO	CTRL_SL			; 55 SL OP1
	GOTO	CTRL_SR			; 56 SR OP4		0-31 32以上は31とする
	GOTO	CTRL_SR			; 57 SR OP2
	GOTO	CTRL_SR			; 58 SR OP3
	GOTO	CTRL_SR			; 59 SR OP1
	GOTO	CTRL_RR			; 60 RR OP4		0-15 16以上は15とする
	GOTO	CTRL_RR			; 61 RR OP2
	GOTO	CTRL_RR			; 62 RR OP3
	GOTO	CTRL_RR			; 63 RR OP1
	GOTO	CTRL_HOLD		; 64 CTRL_HOLD		0-63:OFF 64-127:ON
	GOTO	CTRL_RETURN_P1		; 65
	GOTO	CTRL_RETURN_P1		; 66
	GOTO	CTRL_RETURN_P1		; 67
	GOTO	CTRL_RETURN_P1		; 68
	GOTO	CTRL_RETURN_P1		; 69
	GOTO	CTRL_RETURN_P1		; 70
	GOTO	CTRL_RETURN_P1		; 71
	GOTO	CTRL_RETURN_P1		; 72
	GOTO	CTRL_RETURN_P1		; 73
	GOTO	CTRL_RETURN_P1		; 74
	GOTO	CTRL_RETURN_P1		; 75
	GOTO	CTRL_RETURN_P1		; 76
	GOTO	CTRL_RETURN_P1		; 77
	GOTO	CTRL_RETURN_P1		; 78
	GOTO	CTRL_RETURN_P1		; 79
	GOTO	CTRL_ENVELOPE		; 80 CTRL_ENVELOPE	0-8 9以上は0とする
	GOTO	CTRL_ENVELOPE		; 81 CTRL_ENVELOPE	0-8 9以上は0とする
	GOTO	CTRL_EP			; 82 CTRL_EP		0-127
	GOTO	CTRL_EP			; 83 CTRL_EP
	GOTO	CTRL_EP			; 84 CTRL_EP
	GOTO	CTRL_EP			; 85 CTRL_EP
	GOTO	CTRL_NP			; 86 CTRL_NP		0-31 32以上は31とする
	GOTO	CTRL_RETURN_P1		; 87
	GOTO	CTRL_RETURN_P1		; 88
	GOTO	CTRL_RETURN_P1		; 89
	GOTO	CTRL_RETURN_P1		; 90
	GOTO	CTRL_RETURN_P1		; 91
	GOTO	CTRL_RETURN_P1		; 92
	GOTO	CTRL_RETURN_P1		; 93
	GOTO	CTRL_RETURN_P1		; 94
	GOTO	CTRL_RETURN_P1		; 95
	GOTO	CTRL_RETURN_P1		; 96
	GOTO	CTRL_RETURN_P1		; 97
	GOTO	CTRL_NRPNL		; 98 CTRL_NRPNL
	GOTO	CTRL_NRPNM		; 99 CTRL_NRPNM
	GOTO	CTRL_RPNL		; 100 CTRL_RPNL
	GOTO	CTRL_RPNM		; 101 CTRL_RPNM
	GOTO	CTRL_RETURN_P1		; 102
	GOTO	CTRL_RETURN_P1		; 103
	GOTO	CTRL_RETURN_P1		; 104
	GOTO	CTRL_RETURN_P1		; 105
	GOTO	CTRL_RETURN_P1		; 106
	GOTO	CTRL_RETURN_P1		; 107
	GOTO	CTRL_RETURN_P1		; 108
	GOTO	CTRL_RETURN_P1		; 109
	GOTO	CTRL_ALTN_CLOCK		; 110 ALTN_CLOCK 	0-127
	GOTO	CTRL_ALTN_START		; 111 ALTN_START	PARAM2無視
	GOTO	CTRL_ALTN_CONTINUE	; 112 ALTN_CONTINUE	PARAM2無視
	GOTO	CTRL_ALTN_STOP		; 113 ALTN_STOP		PARAM2無視
	GOTO	CTRL_RETURN_P1		; 114
	GOTO	CTRL_RETURN_P1		; 115
	GOTO	CTRL_RETURN_P1		; 116
	GOTO	CTRL_RETURN_P1		; 117
	GOTO	CTRL_RETURN_P1		; 118
	GOTO	CTRL_RETURN_P1		; 119
	GOTO	CTRL_ALLSOUNDOFF	; 120 CTRL_ALLSOUNDOFF	PARAM2無視
	GOTO	CTRL_RESETALLCTRL	; 121 CTRL_RESETALLCTRL	PARAM2無視
	GOTO	CTRL_RETURN_P1		; 122
	GOTO	CTRL_ALLNOTEOFF		; 123 CTRL_ALLNOTEOFF	PARAM2無視
	GOTO	CTRL_ALLNOTEOFF		; 124 CTRL_ALLNOTEOFF	PARAM2無視
	GOTO	CTRL_ALLNOTEOFF		; 125 CTRL_ALLNOTEOFF	PARAM2無視
	GOTO	CTRL_ALLNOTEOFF		; 126 CTRL_ALLNOTEOFF	PARAM2無視
	GOTO	CTRL_ALLNOTEOFF		; 127 CTRL_ALLNOTEOFF	PARAM2無視
;------------------------------------------------------------------------------
CTRL_RETURN_P1				; 共通リターン
	BSF	PARAM1,PARAM_NOTRCVD	; PARAM1を無効にする
	LGOTO	EVENT_END
;------------------------------------------------------------------------------
CTRL_ALG				; CC#03
	MOVLW	8			; PARAM2が8以上の時は7にセット。
	SUBWF	PARAM2,W
	MOVF	PARAM2,W
	BTFSC	STATUS,C
	 MOVLW	7
	MOVWF	PARAM2

	MOVLW	3			; ボイス0〜2の処理ループ
	MOVWF	VOICE
CTRL_ALG_L1
	CALL	voice_channel_check_P1	; チェック中のボイスのチャンネルを調べる
	BTFSS	STATUS,Z
	 GOTO	CTRL_ALG_L1_NEXT
	
	DECF	VOICE,F			; voice_channel_check_P1のVOICEは+1オフセットしているので-1する。
	MOVLW	LOW FB_ALG
	ADDWF	VOICE,W
	MOVWF	FSR
	BSF	STATUS,IRP		; ◆ IRP=1
	MOVF	INDF,W
	ANDLW	0x38			; 過去のFBを取り出す
	ADDWF	PARAM2,W		; ALGを足して
	MOVWF	INDF			; 書き戻す
	MOVWF	WRITE_DATA
	BCF	STATUS,IRP		; ◆ IRP=0
	MOVF	VOICE,W
	ADDLW	0xB0			; FB/ALGのアドレスにボイス番号を足してFMレジスタに設定する
	MOVWF	WRITE_ADDR
	LCALL	fmwrite
	INCF	VOICE,F
	MOVLW	HIGH $
	MOVWF	PCLATH			; ■ PCLATH
CTRL_ALG_L1_NEXT
	DECFSZ	VOICE,F
	 GOTO	CTRL_ALG_L1
	GOTO	CTRL_RETURN_P1		; 終了
;------------------------------------------------------------------------------
CTRL_DATAENTRY				; CC#06
	MOVLW	64			; PARAM2が64以上の時は63にセット。
	SUBWF	PARAM2,W
	MOVF	PARAM2,W
	BTFSC	STATUS,C
	 MOVLW	63
	MOVWF	PARAM2

	MOVLW	16
	MOVWF	PART			; 操作中のパート番号
CTRL_DATAENTRY_L1
	CALL	part_channel_check_P1
	BTFSS	STATUS,Z
	 GOTO	CTRL_DATAENTRY_L1_NEXT	; チャンネル不一致
	
	MOVF	PART,W			; 該当パートのPART_BENDSENSを操作
	ADDLW	LOW PART_BENDSENS - 1
	MOVWF	FSR
	BSF	STATUS,IRP		; ◆ IRP=1
	MOVLW	B'11000000'		; RPNフラグが0になっているかチェック
	ANDWF	INDF,W
	BTFSS	STATUS,Z
	 GOTO	CTRL_DATAENTRY_L1_NEXT

	MOVF	PARAM2,W
	MOVWF	INDF
CTRL_DATAENTRY_L1_NEXT
	BCF	STATUS,IRP		; ◆ IRP=0
	DECFSZ	PART,F
	 GOTO	CTRL_DATAENTRY_L1
	GOTO	CTRL_RETURN_P1		; 終了
;------------------------------------------------------------------------------
CTRL_VOLUME				; CC#07
	MOVLW	16
	MOVWF	PART
CTRL_VOLUME_L1
	CALL	part_channel_check_P1
	BTFSS	STATUS,Z
	 GOTO	CTRL_VOLUME_L1_NEXT	; チャンネルが一致しない場合は次のパート

	MOVF	PART,W
	ADDLW	LOW PART_VOLUME - 1	; パートの受信するチャンネルをチェックして値を保存する
	MOVWF	FSR
	BSF	STATUS,IRP		; ◆ IRP=1
	BTFSS	INDF,PART_RXVOLUME	; 値を取り込まないパートはスキップ
	 GOTO	CTRL_VOLUME_L1_SKIP
	MOVF	PARAM2,W		; ボリュームの値をそのまま入れる
	MOVWF	INDF
	BSF	INDF,PART_RXVOLUME	; PART_RXVOLUMEフラグが消えてしまうのでもう一度立てる
CTRL_VOLUME_L1_SKIP
	BCF	STATUS,IRP		; ◆ IRP=0
CTRL_VOLUME_L1_NEXT
	DECFSZ	PART,F
	 GOTO	CTRL_VOLUME_L1
	BSF	FLAG1,SUPPRESS_SHAPESET	; エンベロープの再セットを抑制する
	CALL	sendvolume
	BCF	FLAG1,SUPPRESS_SHAPESET
	GOTO	CTRL_RETURN_P1		; 終了
;------------------------------------------------------------------------------
CTRL_FB					; CC#09
	MOVLW	8			; PARAM2が8以上の時は7にセット。
	SUBWF	PARAM2,W
	MOVF	PARAM2,W
	BTFSC	STATUS,C
	 MOVLW	7
	MOVWF	PARAM2
	SWAPF	PARAM2,F		; 3bit左シフト
	RRF	PARAM2,W
	ANDLW	0x38
	MOVWF	PARAM2

	MOVLW	3			; ボイス0〜2の処理ループ
	MOVWF	VOICE
CTRL_FB_L1
	CALL	voice_channel_check_P1	; チェック中のボイスのチャンネルを調べる
	BTFSS	STATUS,Z
	 GOTO	CTRL_FB_L1_NEXT
	
	DECF	VOICE,F			; voice_channel_check_P1のVOICEは+1オフセットしているので-1する。
	MOVLW	LOW FB_ALG
	ADDWF	VOICE,W
	MOVWF	FSR
	BSF	STATUS,IRP		; ◆ IRP=1
	MOVF	INDF,W
	ANDLW	0x07			; 過去のALGを取り出す
	ADDWF	PARAM2,W		; FBを足して
	MOVWF	INDF			; 書き戻す
	MOVWF	WRITE_DATA
	BCF	STATUS,IRP		; ◆ IRP=0
	MOVF	VOICE,W
	ADDLW	0xB0			; FB/ALGのアドレスにボイス番号を足してFMレジスタに設定する
	MOVWF	WRITE_ADDR
	LCALL	fmwrite
	INCF	VOICE,F
	MOVLW	HIGH $
	MOVWF	PCLATH			; ■ PCLATH
CTRL_FB_L1_NEXT
	DECFSZ	VOICE,F
	 GOTO	CTRL_FB_L1
	GOTO	CTRL_RETURN_P1		; 終了
;------------------------------------------------------------------------------
CTRL_EXPRESSION				; CC#11
	MOVLW	16
	MOVWF	PART
CTRL_EXPRESSION_L1
	CALL	part_channel_check_P1
	BTFSS	STATUS,Z
	 GOTO	CTRL_EXPRESSION_L1_NEXT	; チャンネルが一致しない場合は次のパート

	MOVF	PART,W
	ADDLW	LOW PART_EXPRESSION - 1	; パートの受信するチャンネルをチェックして値を保存する
	MOVWF	FSR
	BSF	STATUS,IRP		; ◆ IRP=1
	BTFSS	INDF,PART_RXEXPRESSION	; 値を取り込まないパートはスキップ
	 GOTO	CTRL_EXPRESSION_L1_SKIP
	MOVF	PARAM2,W		; エクスプレッションの値をそのまま入れる
	MOVWF	INDF
	BSF	INDF,PART_RXEXPRESSION	; PART_RXEXPRESSIONフラグが消えてしまうのでもう一度立てる
CTRL_EXPRESSION_L1_SKIP
	BCF	STATUS,IRP		; ◆ IRP=0
CTRL_EXPRESSION_L1_NEXT
	DECFSZ	PART,F
	 GOTO	CTRL_EXPRESSION_L1
	BSF	FLAG1,SUPPRESS_SHAPESET	; エンベロープの再セットを抑制する
	CALL	sendvolume
	BCF	FLAG1,SUPPRESS_SHAPESET
	GOTO	CTRL_RETURN_P1		; 終了
;------------------------------------------------------------------------------
CTRL_MULTI				; CC#12-15
	MOVLW	16			; PARAM2が16以上の時は15にセット。
	SUBWF	PARAM2,W
	MOVF	PARAM2,W
	BTFSC	STATUS,C
	 MOVLW	15
	MOVWF	PARAM2

	MOVLW	12			; OP番号に変換するためにCC#を0〜3に補正する
	SUBWF	PARAM1,F
	MOVLW	0x30			; FMレジスタベースアドレス
	MOVWF	TMP00
	CALL	ctrl_fmaddr

	MOVLW	3			; ボイス0〜2の処理ループ
	MOVWF	VOICE
CTRL_MULTI_L1
	CALL	voice_channel_check_P1	; チェック中のボイスのチャンネルを調べる
	BTFSS	STATUS,Z
	 GOTO	CTRL_MULTI_L1_NEXT
	
	DECF	VOICE,F			; voice_channel_check_P1のVOICEは+1オフセットしているので-1する。
	CALL	ctrl_storeoffset
	ADDLW	LOW DT_MULTI
	MOVWF	FSR
	BSF	STATUS,IRP		; ◆ IRP=1
	MOVF	INDF,W
	ANDLW	0x70			; 過去のDTを取り出す
	ADDWF	PARAM2,W		; MLTを足して
	MOVWF	INDF			; 書き戻す
	MOVWF	WRITE_DATA
	BCF	STATUS,IRP		; ◆ IRP=0
	MOVF	VOICE,W
	ADDWF	TMP00,W			; DT/MLTのアドレスにボイス番号を足してFMレジスタに設定する
	MOVWF	WRITE_ADDR
	LCALL	fmwrite
	INCF	VOICE,F
	MOVLW	HIGH $
	MOVWF	PCLATH			; ■ PCLATH
CTRL_MULTI_L1_NEXT
	DECFSZ	VOICE,F
	 GOTO	CTRL_MULTI_L1
	GOTO	CTRL_RETURN_P1		; 終了
;------------------------------------------------------------------------------
CTRL_DT					; CC#16-19
	MOVLW	8			; PARAM2が8以上の時は7にセット。
	SUBWF	PARAM2,W
	MOVF	PARAM2,W
	BTFSC	STATUS,C
	 MOVLW	7
	MOVWF	PARAM2
	SWAPF	PARAM2,W		; 4bit左シフト
	ANDLW	0x70
	MOVWF	PARAM2

	MOVLW	16			; OP番号に変換するためにCC#を0〜3に補正する
	SUBWF	PARAM1,F
	MOVLW	0x30			; FMレジスタベースアドレス
	MOVWF	TMP00
	CALL	ctrl_fmaddr

	MOVLW	3			; ボイス0〜2の処理ループ
	MOVWF	VOICE
CTRL_DT_L1
	CALL	voice_channel_check_P1	; チェック中のボイスのチャンネルを調べる
	BTFSS	STATUS,Z
	 GOTO	CTRL_DT_L1_NEXT
	
	DECF	VOICE,F			; voice_channel_check_P1のVOICEは+1オフセットしているので-1する。
	CALL	ctrl_storeoffset
	ADDLW	LOW DT_MULTI
	MOVWF	FSR
	BSF	STATUS,IRP		; ◆ IRP=1
	MOVF	INDF,W
	ANDLW	0x0F			; 過去のMULTIを取り出す
	ADDWF	PARAM2,W		; DTを足して
	MOVWF	INDF			; 書き戻す
	MOVWF	WRITE_DATA
	BCF	STATUS,IRP		; ◆ IRP=0
	MOVF	VOICE,W
	ADDWF	TMP00,W			; DT/MLTのアドレスにボイス番号を足してFMレジスタに設定する
	MOVWF	WRITE_ADDR
	LCALL	fmwrite
	INCF	VOICE,F
	MOVLW	HIGH $
	MOVWF	PCLATH			; ■ PCLATH
CTRL_DT_L1_NEXT
	DECFSZ	VOICE,F
	 GOTO	CTRL_DT_L1
	GOTO	CTRL_RETURN_P1		; 終了
;------------------------------------------------------------------------------
CTRL_TL					; CC#20-23
	MOVLW	20			; OP番号に変換するためにCC#を0〜3に補正する
	SUBWF	PARAM1,F
	MOVLW	0x40			; FMレジスタベースアドレス
	MOVWF	TMP00
	CALL	ctrl_fmaddr

	MOVLW	3			; ボイス0〜2の処理ループ
	MOVWF	VOICE
CTRL_TL_L1
	CALL	voice_channel_check_P1	; チェック中のボイスのチャンネルを調べる
	BTFSS	STATUS,Z
	 GOTO	CTRL_TL_L1_NEXT
	
	DECF	VOICE,F			; voice_channel_check_P1のVOICEは+1オフセットしているので-1する。
	CALL	ctrl_storeoffset
	ADDLW	LOW TL
	MOVWF	FSR
	BSF	STATUS,IRP		; ◆ IRP=1
	MOVF	PARAM2,W
	MOVWF	INDF			; TLを保存
	MOVWF	WRITE_DATA
	BCF	STATUS,IRP		; ◆ IRP=0
	MOVF	VOICE,W
	ADDWF	TMP00,W			; TLのアドレスにボイス番号を足してFMレジスタに設定する
	MOVWF	WRITE_ADDR
	LCALL	fmwrite
	INCF	VOICE,F
	MOVLW	HIGH $
	MOVWF	PCLATH			; ■ PCLATH
CTRL_TL_L1_NEXT
	DECFSZ	VOICE,F
	 GOTO	CTRL_TL_L1
	GOTO	CTRL_RETURN_P1		; 終了
;------------------------------------------------------------------------------
CTRL_KS					; CC#24-27
	MOVLW	4			; PARAM2が4以上の時は3にセット。
	SUBWF	PARAM2,W
	MOVF	PARAM2,W
	BTFSC	STATUS,C
	 MOVLW	3
	MOVWF	PARAM2
	SWAPF	PARAM2,F		; 6bit左シフト
	RLF	PARAM2,F
	RLF	PARAM2,W
	ANDLW	0xC0
	MOVWF	PARAM2

	MOVLW	24			; OP番号に変換するためにCC#を0〜3に補正する
	SUBWF	PARAM1,F
	MOVLW	0x50			; FMレジスタベースアドレス
	MOVWF	TMP00
	CALL	ctrl_fmaddr

	MOVLW	3			; ボイス0〜2の処理ループ
	MOVWF	VOICE
CTRL_KS_L1
	CALL	voice_channel_check_P1	; チェック中のボイスのチャンネルを調べる
	BTFSS	STATUS,Z
	 GOTO	CTRL_KS_L1_NEXT
	
	DECF	VOICE,F			; voice_channel_check_P1のVOICEは+1オフセットしているので-1する。
	CALL	ctrl_storeoffset
	ADDLW	LOW KS_AR
	MOVWF	FSR
	BSF	STATUS,IRP		; ◆ IRP=1
	MOVF	INDF,W
	ANDLW	0x1F			; 過去のARを取り出す
	ADDWF	PARAM2,W		; KSを足して
	MOVWF	INDF			; 書き戻す
	MOVWF	WRITE_DATA
	BCF	STATUS,IRP		; ◆ IRP=0
	MOVF	VOICE,W
	ADDWF	TMP00,W			; KS/ARのアドレスにボイス番号を足してFMレジスタに設定する
	MOVWF	WRITE_ADDR
	LCALL	fmwrite
	INCF	VOICE,F
	MOVLW	HIGH $
	MOVWF	PCLATH			; ■ PCLATH
CTRL_KS_L1_NEXT
	DECFSZ	VOICE,F
	 GOTO	CTRL_KS_L1
	GOTO	CTRL_RETURN_P1		; 終了
;------------------------------------------------------------------------------
CTRL_EG					; CC#28-31
	MOVLW	9			; PARAM2が9以上の時は0にリセット。
	SUBWF	PARAM2,W
	BTFSC	STATUS,C
	 CLRF	PARAM2
	MOVF	PARAM2,W		; PARAM2が1以上の時は+7して8〜15に変更。
	BTFSS	STATUS,Z
	 ADDLW	7
	MOVWF	PARAM2

	MOVLW	28			; OP番号に変換するためにCC#を0〜3に補正する
	SUBWF	PARAM1,F
	MOVLW	0x90			; FMレジスタベースアドレス
	MOVWF	TMP00
	CALL	ctrl_fmaddr

	MOVLW	3			; ボイス0〜2の処理ループ
	MOVWF	VOICE
CTRL_EG_L1
	CALL	voice_channel_check_P1	; チェック中のボイスのチャンネルを調べる
	BTFSS	STATUS,Z
	 GOTO	CTRL_EG_L1_NEXT
	
	DECF	VOICE,F			; voice_channel_check_P1のVOICEは+1オフセットしているので-1する。
	CALL	ctrl_storeoffset
	ADDLW	LOW SSG_EG
	MOVWF	FSR
	BSF	STATUS,IRP		; ◆ IRP=1
	MOVF	PARAM2,W
	MOVWF	INDF			; EGを保存
	MOVWF	WRITE_DATA
	BCF	STATUS,IRP		; ◆ IRP=0
	MOVF	VOICE,W
	ADDWF	TMP00,W			; EGのアドレスにボイス番号を足してFMレジスタに設定する
	MOVWF	WRITE_ADDR
	LCALL	fmwrite
	INCF	VOICE,F
	MOVLW	HIGH $
	MOVWF	PCLATH			; ■ PCLATH
CTRL_EG_L1_NEXT
	DECFSZ	VOICE,F
	 GOTO	CTRL_EG_L1
	GOTO	CTRL_RETURN_P1		; 終了
;------------------------------------------------------------------------------
CTRL_SLOT				; CC#35
	MOVLW	16			; PARAM2が16以上の時は15にセット。
	SUBWF	PARAM2,W
	MOVF	PARAM2,W
	BTFSC	STATUS,C
	 MOVLW	15
	MOVWF	PARAM2

	MOVLW	3			; ボイス0〜2の処理ループ
	MOVWF	VOICE
CTRL_SLOT_L1
	CALL	voice_channel_check_P1	; チェック中のボイスのチャンネルを調べる
	BTFSS	STATUS,Z
	 GOTO	CTRL_SLOT_L1_NEXT
	
	DECF	VOICE,F			; voice_channel_check_P1のVOICEは+1オフセットしているので-1する。
	MOVLW	LOW SLOT
	ADDWF	VOICE,W
	MOVWF	FSR
	BSF	STATUS,IRP		; ◆ IRP=1
	MOVF	PARAM2,W		; SLOTはボイスON時に使用するため、ここで音源に書き込む必要は無い。
	MOVWF	INDF
	BCF	STATUS,IRP		; ◆ IRP=0
	INCF	VOICE,F
CTRL_SLOT_L1_NEXT
	DECFSZ	VOICE,F
	 GOTO	CTRL_SLOT_L1
	GOTO	CTRL_RETURN_P1		; 終了

;------------------------------------------------------------------------------
CTRL_VOL_INCR				; CC#39
	MOVLW	16
	MOVWF	PART
VOLINCR_L1
	CALL	part_channel_check_P1
	BTFSS	STATUS,Z
	 GOTO	VOLINCR_L1_NEXT		; チャンネルが一致しない場合は次のパート

	MOVF	PART,W
	ADDLW	LOW PART_VOLUME - 1	; パートの受信するチャンネルをチェックして値を保存する
	MOVWF	FSR
	BSF	STATUS,IRP		; ◆ IRP=1
	BTFSS	INDF,PART_RXVOLUME	; 値を取り込まないパートはスキップ
	 GOTO	VOLINCR_L1_SKIP
	MOVF	INDF,W			; 現在のボリュームに対して相対的に変化させる
	ANDLW	0x7F			; PART_RXVOLUMEフラグを除去
	MOVWF	TMP20
	MOVF	PARAM2,W
	MOVWF	TMP21
	BCF	RELATIVE_LIMIT,0	; Max 0x7F
	CALL	relative_addsub
	MOVWF	INDF			; 結果を保存
	BSF	INDF,PART_RXVOLUME	; PART_RXVOLUMEフラグが消えてしまうのでもう一度立てる
VOLINCR_L1_SKIP
	BCF	STATUS,IRP		; ◆ IRP=0
VOLINCR_L1_NEXT
	DECFSZ	PART,F
	 GOTO	VOLINCR_L1
	BSF	FLAG1,SUPPRESS_SHAPESET	; エンベロープの再セットを抑制する
	CALL	sendvolume
	BCF	FLAG1,SUPPRESS_SHAPESET
	GOTO	CTRL_RETURN_P1		; 終了
;------------------------------------------------------------------------------
CTRL_PITCH_INCR				; CC#41
	MOVLW	16
	MOVWF	PART
PITCHINCR_PARTLOOP
	CALL	part_channel_check_P1
	BTFSS	STATUS,Z
	 GOTO	PITCHINCR_PARTNEXT	; チャンネルが一致しない場合は次のパート

	MOVF	PART,W
	ADDLW	LOW PART_PITCHBEND - 1	; パートの受信するチャンネルをチェックして値を保存する
	MOVWF	FSR
	BSF	STATUS,IRP		; ◆ IRP=1
	MOVF	INDF,W			; 現在のピッチベンドに対して相対的に変化させる
	MOVWF	TMP20
	MOVF	PARAM2,W
	MOVWF	TMP21
	BSF	RELATIVE_LIMIT,0	; Max 0x80
	CALL	relative_addsub
	MOVWF	INDF			; 結果を保存
	BCF	STATUS,IRP		; ◆ IRP=0
PITCHINCR_PARTNEXT
	DECFSZ	PART,F
	 GOTO	PITCHINCR_PARTLOOP
	LCALL	sendpitch		; ■ PCLATH
	LGOTO	CTRL_RETURN_P1		; ■ PCLATH
;------------------------------------------------------------------------------
CTRL_EXP_INCR				; CC#43
	MOVLW	16
	MOVWF	PART
EXPINCR_L1
	CALL	part_channel_check_P1
	BTFSS	STATUS,Z
	 GOTO	EXPINCR_L1_NEXT		; チャンネルが一致しない場合は次のパート

	MOVF	PART,W
	ADDLW	LOW PART_EXPRESSION - 1	; パートの受信するチャンネルをチェックして値を保存する
	MOVWF	FSR
	BSF	STATUS,IRP		; ◆ IRP=1
	BTFSS	INDF,PART_RXEXPRESSION	; 値を取り込まないパートはスキップ
	 GOTO	EXPINCR_L1_SKIP
	MOVF	INDF,W			; 現在のエクスプレッションに対して相対的に変化させる
	ANDLW	0x7F			; PART_RXEXPRESSIONフラグを除去
	MOVWF	TMP20
	MOVF	PARAM2,W
	MOVWF	TMP21
	BCF	RELATIVE_LIMIT,0	; Max 0x7F
	CALL	relative_addsub
	MOVWF	INDF			; 結果を保存
	BSF	INDF,PART_RXEXPRESSION	; PART_RXEXPRESSIONフラグが消えてしまうのでもう一度立てる
EXPINCR_L1_SKIP
	BCF	STATUS,IRP		; ◆ IRP=0
EXPINCR_L1_NEXT
	DECFSZ	PART,F
	 GOTO	EXPINCR_L1
	BSF	FLAG1,SUPPRESS_SHAPESET	; エンベロープの再セットを抑制する
	CALL	sendvolume
	BCF	FLAG1,SUPPRESS_SHAPESET
	GOTO	CTRL_RETURN_P1		; 終了
;------------------------------------------------------------------------------
CTRL_AR					; CC#44-47
	MOVLW	32			; PARAM2が32以上の時は31にセット。
	SUBWF	PARAM2,W
	MOVF	PARAM2,W
	BTFSC	STATUS,C
	 MOVLW	31
	MOVWF	PARAM2

	MOVLW	44			; OP番号に変換するためにCC#を0〜3に補正する
	SUBWF	PARAM1,F
	MOVLW	0x50			; FMレジスタベースアドレス
	MOVWF	TMP00
	CALL	ctrl_fmaddr

	MOVLW	3			; ボイス0〜2の処理ループ
	MOVWF	VOICE
CTRL_AR_L1
	CALL	voice_channel_check_P1	; チェック中のボイスのチャンネルを調べる
	BTFSS	STATUS,Z
	 GOTO	CTRL_AR_L1_NEXT
	
	DECF	VOICE,F			; voice_channel_check_P1のVOICEは+1オフセットしているので-1する。
	CALL	ctrl_storeoffset
	ADDLW	LOW KS_AR
	MOVWF	FSR
	BSF	STATUS,IRP		; ◆ IRP=1
	MOVF	INDF,W
	ANDLW	0xC0			; 過去のKSを取り出す
	ADDWF	PARAM2,W		; ARを足して
	MOVWF	INDF			; 書き戻す
	MOVWF	WRITE_DATA
	BCF	STATUS,IRP		; ◆ IRP=0
	MOVF	VOICE,W
	ADDWF	TMP00,W			; KS/ARのアドレスにボイス番号を足してFMレジスタに設定する
	MOVWF	WRITE_ADDR
	LCALL	fmwrite
	INCF	VOICE,F
	MOVLW	HIGH $
	MOVWF	PCLATH			; ■ PCLATH
CTRL_AR_L1_NEXT
	DECFSZ	VOICE,F
	 GOTO	CTRL_AR_L1
	GOTO	CTRL_RETURN_P1		; 終了
;------------------------------------------------------------------------------
CTRL_DR					; CC#48-51
	MOVLW	32			; PARAM2が32以上の時は31にセット。
	SUBWF	PARAM2,W
	MOVF	PARAM2,W
	BTFSC	STATUS,C
	 MOVLW	31
	MOVWF	PARAM2

	MOVLW	48			; OP番号に変換するためにCC#を0〜3に補正する
	SUBWF	PARAM1,F
	MOVLW	0x60			; FMレジスタベースアドレス
	MOVWF	TMP00
	CALL	ctrl_fmaddr

	MOVLW	3			; ボイス0〜2の処理ループ
	MOVWF	VOICE
CTRL_DR_L1
	CALL	voice_channel_check_P1	; チェック中のボイスのチャンネルを調べる
	BTFSS	STATUS,Z
	 GOTO	CTRL_DR_L1_NEXT
	
	DECF	VOICE,F			; voice_channel_check_P1のVOICEは+1オフセットしているので-1する。
	CALL	ctrl_storeoffset
	ADDLW	LOW DR
	MOVWF	FSR
	BSF	STATUS,IRP		; ◆ IRP=1
	MOVF	PARAM2,W
	MOVWF	INDF			; DRを保存
	MOVWF	WRITE_DATA
	BCF	STATUS,IRP		; ◆ IRP=0
	MOVF	VOICE,W
	ADDWF	TMP00,W			; DRのアドレスにボイス番号を足してFMレジスタに設定する
	MOVWF	WRITE_ADDR
	LCALL	fmwrite
	INCF	VOICE,F
	MOVLW	HIGH $
	MOVWF	PCLATH			; ■ PCLATH
CTRL_DR_L1_NEXT
	DECFSZ	VOICE,F
	 GOTO	CTRL_DR_L1
	GOTO	CTRL_RETURN_P1		; 終了
;------------------------------------------------------------------------------
CTRL_SL					; CC#52-55
	MOVLW	16			; PARAM2が16以上の時は15にセット。
	SUBWF	PARAM2,W
	MOVF	PARAM2,W
	BTFSC	STATUS,C
	 MOVLW	15
	MOVWF	PARAM2
	SWAPF	PARAM2,F		; 4bit左シフト

	MOVLW	52			; OP番号に変換するためにCC#を0〜3に補正する
	SUBWF	PARAM1,F
	MOVLW	0x80			; FMレジスタベースアドレス
	MOVWF	TMP00
	CALL	ctrl_fmaddr

	MOVLW	3			; ボイス0〜2の処理ループ
	MOVWF	VOICE
CTRL_SL_L1
	CALL	voice_channel_check_P1	; チェック中のボイスのチャンネルを調べる
	BTFSS	STATUS,Z
	 GOTO	CTRL_SL_L1_NEXT
	
	DECF	VOICE,F			; voice_channel_check_P1のVOICEは+1オフセットしているので-1する。
	CALL	ctrl_storeoffset
	ADDLW	LOW SL_RR
	MOVWF	FSR
	BSF	STATUS,IRP		; ◆ IRP=1
	MOVF	INDF,W
	ANDLW	0x0F			; 過去のRRを取り出す
	ADDWF	PARAM2,W		; SLを足して
	MOVWF	INDF			; 書き戻す
	MOVWF	WRITE_DATA
	BCF	STATUS,IRP		; ◆ IRP=0
	MOVF	VOICE,W
	ADDWF	TMP00,W			; SL/RRのアドレスにボイス番号を足してFMレジスタに設定する
	MOVWF	WRITE_ADDR
	LCALL	fmwrite
	INCF	VOICE,F
	MOVLW	HIGH $
	MOVWF	PCLATH			; ■ PCLATH
CTRL_SL_L1_NEXT
	DECFSZ	VOICE,F
	 GOTO	CTRL_SL_L1
	GOTO	CTRL_RETURN_P1		; 終了
;------------------------------------------------------------------------------
CTRL_SR					; CC#56-59
	MOVLW	32			; PARAM2が32以上の時は31にセット。
	SUBWF	PARAM2,W
	MOVF	PARAM2,W
	BTFSC	STATUS,C
	 MOVLW	31
	MOVWF	PARAM2

	MOVLW	56			; OP番号に変換するためにCC#を0〜3に補正する
	SUBWF	PARAM1,F
	MOVLW	0x70			; FMレジスタベースアドレス
	MOVWF	TMP00
	CALL	ctrl_fmaddr

	MOVLW	3			; ボイス0〜2の処理ループ
	MOVWF	VOICE
CTRL_SR_L1
	CALL	voice_channel_check_P1	; チェック中のボイスのチャンネルを調べる
	BTFSS	STATUS,Z
	 GOTO	CTRL_SR_L1_NEXT
	
	DECF	VOICE,F			; voice_channel_check_P1のVOICEは+1オフセットしているので-1する。
	CALL	ctrl_storeoffset
	ADDLW	LOW SR
	MOVWF	FSR
	BSF	STATUS,IRP		; ◆ IRP=1
	MOVF	PARAM2,W
	MOVWF	INDF			; SRを保存
	MOVWF	WRITE_DATA
	BCF	STATUS,IRP		; ◆ IRP=0
	MOVF	VOICE,W
	ADDWF	TMP00,W			; SRのアドレスにボイス番号を足してFMレジスタに設定する
	MOVWF	WRITE_ADDR
	LCALL	fmwrite
	INCF	VOICE,F
	MOVLW	HIGH $
	MOVWF	PCLATH			; ■ PCLATH
CTRL_SR_L1_NEXT
	DECFSZ	VOICE,F
	 GOTO	CTRL_SR_L1
	GOTO	CTRL_RETURN_P1		; 終了
;------------------------------------------------------------------------------
CTRL_RR					; CC#60-63
	MOVLW	16			; PARAM2が16以上の時は15にセット。
	SUBWF	PARAM2,W
	MOVF	PARAM2,W
	BTFSC	STATUS,C
	 MOVLW	15
	MOVWF	PARAM2

	MOVLW	60			; OP番号に変換するためにCC#を0〜3に補正する
	SUBWF	PARAM1,F
	MOVLW	0x80			; FMレジスタベースアドレス
	MOVWF	TMP00
	CALL	ctrl_fmaddr

	MOVLW	3			; ボイス0〜2の処理ループ
	MOVWF	VOICE
CTRL_RR_L1
	CALL	voice_channel_check_P1	; チェック中のボイスのチャンネルを調べる
	BTFSS	STATUS,Z
	 GOTO	CTRL_RR_L1_NEXT
	
	DECF	VOICE,F			; voice_channel_check_P1のVOICEは+1オフセットしているので-1する。
	CALL	ctrl_storeoffset
	ADDLW	LOW SL_RR
	MOVWF	FSR
	BSF	STATUS,IRP		; ◆ IRP=1
	MOVF	INDF,W
	ANDLW	0xF0			; 過去のSLを取り出す
	ADDWF	PARAM2,W		; RRを足して
	MOVWF	INDF			; 書き戻す
	MOVWF	WRITE_DATA
	BCF	STATUS,IRP		; ◆ IRP=0
	MOVF	VOICE,W
	ADDWF	TMP00,W			; SL/RRのアドレスにボイス番号を足してFMレジスタに設定する
	MOVWF	WRITE_ADDR
	LCALL	fmwrite
	INCF	VOICE,F
	MOVLW	HIGH $
	MOVWF	PCLATH			; ■ PCLATH
CTRL_RR_L1_NEXT
	DECFSZ	VOICE,F
	 GOTO	CTRL_RR_L1
	GOTO	CTRL_RETURN_P1		; 終了
;------------------------------------------------------------------------------
CTRL_HOLD				; CC#64
	BTFSS	PARAM2,6		; HOLD ON/OFF分岐
	 GOTO	CTRL_HOLDOFF
CTRL_HOLDON				; HOLD ONはPART_SUSTAINに1をセットするだけ。
	MOVLW	16
	MOVWF	PART
CTRL_HOLDON_L1
	CALL	part_channel_check_P1
	BTFSS	STATUS,Z
	 GOTO	CTRL_HOLDON_NEXT

	MOVF	PART,W
	ADDLW	PART_CHANNEL - 1
	MOVWF	FSR
	BSF	INDF,PART_SUSTAIN
CTRL_HOLDON_NEXT
	DECFSZ	PART,F
	 GOTO	CTRL_HOLDON_L1
	GOTO	CTRL_RETURN_P1		; 終了

CTRL_HOLDOFF
	CALL	holdoff
	GOTO	CTRL_RETURN_P1		; 終了
;------------------------------------------------------------------------------
CTRL_ENVELOPE				; CC#80-81
	MOVLW	9			; PARAM2が9以上の時は0にリセット。
	SUBWF	PARAM2,W
	BTFSC	STATUS,C
	 CLRF	PARAM2
	MOVF	PARAM2,W		; PARAM2が1以上の時は+7して8〜15に変更。
	BTFSS	STATUS,Z
	 ADDLW	7
	MOVWF	PARAM2

	MOVLW	16
	MOVWF	PART			; 操作中のパート番号
CTRL_ENV_L1
	CALL	part_channel_check_P1
	BTFSS	STATUS,Z
	 GOTO	CTRL_ENV_L1_NEXT	; チャンネル不一致

	MOVF	PART,W			; 該当パートのエンベロープフラグを操作
	ADDLW	LOW PART_ENVSHAPE - 1
	MOVWF	FSR
	BSF	STATUS,IRP		; ◆ IRP=1
	MOVF	PARAM2,W
	BCF	INDF,PART_USEENV	; エンベロープ強制OFF
	BTFSC	STATUS,Z		; エンベロープなしの時スキップ
	 GOTO	CTRL_ENV_L1_NEXT

	BSF	INDF,PART_USEENV	; エンベロープON
	MOVLW	0xF0
	ANDWF	INDF,F			; エンベロープシェイプリセット
	MOVF	PARAM2,W		; エンベロープを書く
	IORWF	INDF,F
CTRL_ENV_L1_NEXT
	BCF	STATUS,IRP		; ◆ IRP=0
	DECFSZ	PART,F
	 GOTO	CTRL_ENV_L1
	BTFSC	PARAM1,0		; PARAM1[0]が1(CC#81)の時、再トリガのためにボリュームを送信
	 CALL	sendvolume
	GOTO	CTRL_RETURN_P1		; 終了
;------------------------------------------------------------------------------
CTRL_EP					; CC#80-83
	MOVF	PARAM2,W
	BTFSC	PARAM1,0		; PARAM1[0]が1(CC#が83,85)の時0x80をPARAM2に加算
	 ADDLW	0x80
	MOVWF	WRITE_DATA		; WRITE_DATAは非破壊なので、この時点で入れておく。

	MOVLW	0x0B			; EPアドレス
	BTFSS	PARAM1,1		; PARAM1[1]が0(CC#が84,85)の時、EPアドレスを0x0Cに変更する。
	 MOVLW	0x0C
	MOVWF	TMP00

	MOVLW	15
	MOVWF	VOICE
CTRL_EP_L1
	CALL	voice_channel_check_P1	; チェック中のボイスのチャンネルを調べる
	BTFSS	STATUS,Z
	 GOTO	CTRL_EP_NEXT

	DECF	VOICE,F			; voice_channel_check_P1のVOICEは+1オフセットしているので-1する。
	LCALL	ssgchannel		; ■ PCLATH
	SWAPF	SSGCHIP,W		; SSG選択の数値を上位に設定
	ADDWF	TMP00,W			; EPアドレス
	MOVWF	WRITE_ADDR
	CALL	ssgwrite		; PCLATHロード済み(W:306)
	INCF	VOICE,F
	MOVLW	HIGH $
	MOVWF	PCLATH			; ■ PCLATH
CTRL_EP_NEXT
	DECF	VOICE,F
	MOVLW	3
	SUBWF	VOICE,W
	BTFSS	STATUS,Z
	 GOTO	CTRL_EP_L1
	GOTO	CTRL_RETURN_P1		; 終了
;------------------------------------------------------------------------------
CTRL_NP					; CC#86
	MOVLW	32			; PARAM2が32以上の時は31にセット。
	SUBWF	PARAM2,W
	MOVF	PARAM2,W
	BTFSC	STATUS,C
	 MOVLW	31
	MOVWF	WRITE_DATA		; WRITE_DATAは非破壊なので、この時点で入れておく。

	MOVLW	15
	MOVWF	VOICE
CTRL_NP_L1
	CALL	voice_channel_check_P1	; チェック中のボイスのチャンネルを調べる
	BTFSS	STATUS,Z
	 GOTO	CTRL_NP_NEXT

	DECF	VOICE,F			; voice_channel_check_P1のVOICEは+1オフセットしているので-1する。
	LCALL	ssgchannel		; ■ PCLATH
	SWAPF	SSGCHIP,W		; SSG選択の数値を上位に設定
	ADDLW	6			; NPアドレス
	MOVWF	WRITE_ADDR
	CALL	ssgwrite		; PCLATHロード済み(W:306)
	INCF	VOICE,F
	MOVLW	HIGH $
	MOVWF	PCLATH			; ■ PCLATH
CTRL_NP_NEXT
	DECF	VOICE,F
	MOVLW	3
	SUBWF	VOICE,W
	BTFSS	STATUS,Z
	 GOTO	CTRL_NP_L1
	GOTO	CTRL_RETURN_P1		; 終了
;------------------------------------------------------------------------------
CTRL_NRPNL				; CC#98
	MOVLW	16
	MOVWF	PART			; 操作中のパート番号
CTRL_NRPNL_L1
	CALL	part_channel_check_P1
	BTFSS	STATUS,Z
	 GOTO	CTRL_NRPNL_L1_NEXT	; チャンネル不一致
	
	MOVF	PART,W
	ADDLW	LOW PART_BENDSENS - 1	; 該当パートのRPNフラグを操作
	MOVWF	FSR
	BSF	STATUS,IRP		; ◆ IRP=1
	BSF	INDF,PART_RPNL		; RPNLフラグ強制ON
	BCF	STATUS,IRP		; ◆ IRP=0
CTRL_NRPNL_L1_NEXT
	DECFSZ	PART,F
	 GOTO	CTRL_NRPNL_L1
	GOTO	CTRL_RETURN_P1		; 終了
;------------------------------------------------------------------------------
CTRL_NRPNM				; CC#99
	MOVLW	16
	MOVWF	PART			; 操作中のパート番号
CTRL_NRPNM_L1
	CALL	part_channel_check_P1
	BTFSS	STATUS,Z
	 GOTO	CTRL_NRPNM_L1_NEXT	; チャンネル不一致
	
	MOVF	PART,W
	ADDLW	LOW PART_BENDSENS - 1	; 該当パートのRPNフラグを操作
	MOVWF	FSR
	BSF	STATUS,IRP		; ◆ IRP=1
	BSF	INDF,PART_RPNM		; RPNMフラグ強制ON
	BCF	STATUS,IRP		; ◆ IRP=0
CTRL_NRPNM_L1_NEXT
	DECFSZ	PART,F
	 GOTO	CTRL_NRPNM_L1
	GOTO	CTRL_RETURN_P1		; 終了
;------------------------------------------------------------------------------
CTRL_RPNL				; CC#100
	MOVLW	16
	MOVWF	PART			; 操作中のパート番号
CTRL_RPNL_L1
	CALL	part_channel_check_P1
	BTFSS	STATUS,Z
	 GOTO	CTRL_RPNL_L1_NEXT	; チャンネル不一致
	
	MOVF	PART,W
	ADDLW	LOW PART_BENDSENS - 1	; 該当パートのRPNフラグを操作
	MOVWF	FSR
	BSF	STATUS,IRP		; ◆ IRP=1
	BSF	INDF,PART_RPNL		; RPNLフラグ強制ON
	MOVF	PARAM2,W		; PARAM2=0?
	BTFSC	STATUS,Z
	 BCF	INDF,PART_RPNL		; RPNLフラグOFF
	BCF	STATUS,IRP		; ◆ IRP=0
CTRL_RPNL_L1_NEXT
	DECFSZ	PART,F
	 GOTO	CTRL_RPNL_L1
	GOTO	CTRL_RETURN_P1		; 終了
;------------------------------------------------------------------------------
CTRL_RPNM				; CC#101
	MOVLW	16
	MOVWF	PART			; 操作中のパート番号
CTRL_RPNM_L1
	CALL	part_channel_check_P1
	BTFSS	STATUS,Z
	 GOTO	CTRL_RPNM_L1_NEXT	; チャンネル不一致
	
	MOVF	PART,W
	ADDLW	LOW PART_BENDSENS - 1	; 該当パートのRPNフラグを操作
	MOVWF	FSR
	BSF	STATUS,IRP		; ◆ IRP=1
	BSF	INDF,PART_RPNM		; RPNMフラグ強制ON
	MOVF	PARAM2,W		; PARAM2=0?
	BTFSC	STATUS,Z
	 BCF	INDF,PART_RPNM		; RPNMフラグOFF
	BCF	STATUS,IRP		; ◆ IRP=0
CTRL_RPNM_L1_NEXT
	DECFSZ	PART,F
	 GOTO	CTRL_RPNM_L1
	GOTO	CTRL_RETURN_P1		; 終了
;------------------------------------------------------------------------------
CTRL_ALTN_CLOCK				; CC#110 PARAM2=進めるクロック数
	BTFSS	FLAG1,METRO_RUN
	 GOTO	CTRL_RETURN_P1

	MOVF	CLOCK_LIMIT,W		; CLOCK_LIMITが0の時は、メトロノームを実行しない
	BTFSC	STATUS,Z
	 GOTO	CTRL_RETURN_P1

	MOVF	PARAM2,W		; PARAM2がCLOCK_LIMITより大きい時は誤動作するので実行しない
	SUBWF	CLOCK_LIMIT,W
	BTFSS	STATUS,C
	 GOTO	CTRL_RETURN_P1

	MOVF	PARAM2,W		; CLOCK_COUNTから指定のクロック数を引いて、
	SUBWF	CLOCK_COUNT,F		; ゼロ以下ならメトロノームを実行
	BTFSC	STATUS,Z
	 GOTO	CTRL_ALTN_CLOCK2
	BTFSS	STATUS,C
	 GOTO	CTRL_ALTN_CLOCK2
	GOTO	CTRL_RETURN_P1
CTRL_ALTN_CLOCK2
	MOVF	CLOCK_LIMIT,W		; 引きすぎの分も考慮して加算する
	ADDWF	CLOCK_COUNT,F
	BSF	PARAM1,PARAM_NOTRCVD	; PARAM1を無効にする
	LGOTO	BEAT_CHECK		; ■ PCLATH
;------------------------------------------------------------------------------
CTRL_ALTN_START				; CC#111
	BSF	PARAM1,PARAM_NOTRCVD	; PARAM1を無効にする
	LGOTO	event_start		; ■ PCLATH
;------------------------------------------------------------------------------
CTRL_ALTN_CONTINUE			; CC#112
	BSF	PARAM1,PARAM_NOTRCVD	; PARAM1を無効にする
	LGOTO	event_continue		; ■ PCLATH
;------------------------------------------------------------------------------
CTRL_ALTN_STOP				; CC#113
	BSF	PARAM1,PARAM_NOTRCVD	; PARAM1を無効にする
	LGOTO	event_stop		; ■ PCLATH
;------------------------------------------------------------------------------
CTRL_ALLSOUNDOFF			; CC#120
	MOVLW	16			; 該当チャンネルのボイスを強制的に切る。フラグの処理も行わない。
	MOVWF	VOICE			; ボイスが発音していなくてもチャンネルが一致すれば消音処理を行う。
CTRL_ALLSOUNDOFF_L1
	CALL	voice_channel_check_P1	; チェック中のボイスのチャンネルを調べる
	BTFSS	STATUS,Z
	 GOTO	CTRL_ALLSOUNDOFF_L1_NEXT
	
	DECF	VOICE,F			; voice_channel_check_P1のVOICEは+1オフセットしているので-1する。
	LCALL	voiceoff		; ■ PCLATH
	INCF	VOICE,F
	MOVLW	HIGH $
	MOVWF	PCLATH			; ■ PCLATH
CTRL_ALLSOUNDOFF_L1_NEXT
	DECFSZ	VOICE,F
	 GOTO	CTRL_ALLSOUNDOFF_L1
	GOTO	CTRL_RETURN_P1		; 終了
;------------------------------------------------------------------------------
CTRL_RESETALLCTRL			; CC#121
	MOVLW	16
	MOVWF	PART			; 操作中のパート番号
CTRL_RESETALLCTRL_L1
	CALL	part_channel_check_P1
	BTFSC	STATUS,Z		; チャンネルチェック
	 CALL	reset_controller
	DECFSZ	PART,F
	 GOTO	CTRL_RESETALLCTRL_L1
	CALL	holdoff
	BSF	FLAG1,SUPPRESS_SHAPESET	; エンベロープの再セットを抑制する
	CALL	sendvolume
	BCF	FLAG1,SUPPRESS_SHAPESET
	LCALL	sendpitch		; ■ PCLATH
	LGOTO	CTRL_RETURN_P1		; ■ PCLATH
;------------------------------------------------------------------------------
CTRL_ALLNOTEOFF				; CC#123
	MOVLW	16			; 該当チャンネルのノートを強制的にオフにする。サスティンフラグの処理を行う。
	MOVWF	VOICE			; ノートは最大16ボイス分しかないため、ボイス基準のループで処理を行う。
CTRL_ALLNOTEOFF_L1			; すべてのノートをオフにするため、優先順位を更新しない。
	CALL	voice_channel_check_P1	; ボイスのパートのチャンネルが一致しているか？
	BTFSS	STATUS,Z
	 GOTO	CTRL_ALLNOTEOFF_L1_NEXT

	DECF	VOICE,F			; voice_channel_check_P1のVOICEは+1オフセットしているので-1する。
	MOVF	VOICE,W			; ノート番号にノートオフビットを立てる
	ADDLW	VOICE_NOTE
	MOVWF	FSR
	BSF	INDF,VOICE_NOTEOFF

	MOVF	VOICE,W			; このボイスの担当するパートがサスティン中の場合は、
	ADDLW	VOICE_PART
	MOVWF	FSR
	MOVF	INDF,W
	ANDLW	0x0F
	ADDLW	PART_CHANNEL
	MOVWF	FSR
	BTFSC	INDF,PART_SUSTAIN
	 GOTO	CTRL_ALLNOTEOFF_SUSTAIN ; サスティン処理を行いボイスオフしない

	LCALL	voiceoff		; ■ PCLATH
	INCF	VOICE,F
	MOVLW	HIGH $
	MOVWF	PCLATH			; ■ PCLATH
CTRL_ALLNOTEOFF_L1_NEXT
	DECFSZ	VOICE,F
	 GOTO	CTRL_ALLNOTEOFF_L1
	GOTO	CTRL_RETURN_P1		; 終了

CTRL_ALLNOTEOFF_SUSTAIN			; ボイスのサスティン処理
	BSF	STATUS,IRP		; ◆ IRP=1
	MOVLW	LOW VOICE_VELOCITY
	ADDWF	VOICE,W
	MOVWF	FSR
	BSF	INDF,VOICE_SUSTAIN	; ボイスサスティンフラグを立てる
	BCF	STATUS,IRP		; ◆ IRP=0
	INCF	VOICE,F
	GOTO	CTRL_ALLNOTEOFF_L1_NEXT
;------------------------------------------------------------------------------
; D0 チャンネルプレッシャ
;   ボイス0〜14をスキャンし、ノートオン状態でチャンネルが一致するボイスを処理対象とする
;   同一チャンネルのベロシティに加減算を行い相対変化させる(-64-0-63)
;   処理そのものはVOL,EXP処理とほぼ同じため、コントロールチェンジの共通ルーチンを使用する
;   ベロシティを受信しない場合はチャンネルプレッシャも動作させない。
;------------------------------------------------------------------------------
EVENT_CHPRESS_P1
	MOVLW	15
	MOVWF	VOICE
EVENT_CHPRESS_L1
	MOVF	VOICE,W
	ADDLW	VOICE_NOTE-1
	MOVWF	FSR
	BCF	STATUS,IRP		; ◆ IRP=0
	BTFSC	INDF,VOICE_NOTEOFF	; ノートオフのボイスはスキップする
	 GOTO	EVENT_CHPRESS_L1_NEXT

	CALL	voice_channel_check_P1	; チャンネルが一致しない場合は次のボイス
	BTFSS	STATUS,Z
	 GOTO	EVENT_CHPRESS_L1_NEXT
	
	MOVF	VOICE,W
	ADDLW	LOW VOICE_VELOCITY - 1
	MOVWF	FSR
	BSF	STATUS,IRP		; ◆ IRP=1
	MOVF	INDF,W
	ANDLW	0x7F			; VOICE_SUSTAINフラグを除去
	MOVWF	TMP20
	MOVF	PARAM1,W
	MOVWF	TMP21
	BCF	RELATIVE_LIMIT,0	; Max 0x7F
	MOVLW	0x80			; VOICE_SUSTAINフラグを用意しておく
	ANDWF	INDF,F
	CALL	relative_addsub
	IORWF	INDF,F			; 結果をVOICE_SUSTAINフラグとマージして保存
EVENT_CHPRESS_L1_NEXT
	DECFSZ	VOICE,F
	 GOTO	EVENT_CHPRESS_L1

	BSF	FLAG1,SUPPRESS_SHAPESET	; エンベロープの再セットを抑制する
	CALL	sendvolume
	BCF	FLAG1,SUPPRESS_SHAPESET
	GOTO	CTRL_RETURN_P1		; 終了
;------------------------------------------------------------------------------
; FM音源パラメータ設定共通ルーチン
; MLT,DT,TL,KS,EG,AR,DR,SR,SL,RRの各アドレスを計算する
; PARAM1は破壊される。
; TMP00 = (3 - PARAM1[0-3]) * 4 + TMP00	FM音源のレジスタ番号
;------------------------------------------------------------------------------
ctrl_fmaddr
	MOVF	PARAM1,W
	SUBLW	3
	MOVWF	TMP23
	RLF	TMP23,F
	RLF	TMP23,W
	ANDLW	0x0C
	ADDWF	TMP00,F
	RETURN

;------------------------------------------------------------------------------
; FM音源パラメータ保存レジスタアドレス計算ルーチン
; VOICE * 4 + PARAM1
;------------------------------------------------------------------------------
ctrl_storeoffset
	RLF	VOICE,W
	MOVWF	TMP23
	RLF	TMP23,W
	ANDLW	0x0C
	ADDWF	PARAM1,W
	RETURN
;------------------------------------------------------------------------------
; パートループ用受信チャンネルチェックルーチン
; PARTでカウントされるパートループで受信したチャンネルが一致するか確認を行う。
; PARTは+1でオフセットされている。
; パートミュートも同時にチェックされ、受信処理が必要ならばZフラグがセットされる。
; リターン後は以下の要領で分岐する。
;	BTFSS	STATUS,Z
;	 GOTO	NEXTLOOP
;------------------------------------------------------------------------------
part_channel_check_P1
	MOVF	PART,W
	ADDLW	PART_CHANNEL-1
	MOVWF	FSR
	MOVF	INDF,W
	ANDLW	0x1F
	SUBWF	CHANNEL,W
	RETURN

;------------------------------------------------------------------------------
; ボイスループ用受信チャンネルチェックルーチン
; VOICEでカウントされるボイスループで受信したチャンネルが一致するか確認を行う。
; VOICEは+1でオフセットされている。
; ボイス・パートミュートも同時にチェックされ、受信処理が必要ならばZフラグがセットされる。
; リターン後は以下の要領で分岐する。
;	BTFSS	STATUS,Z
;	 GOTO	NEXTLOOP
;------------------------------------------------------------------------------
voice_channel_check_P1
	MOVF	VOICE,W
	ADDLW	VOICE_PART-1
	MOVWF	FSR
	BCF	STATUS,Z
	BTFSC	INDF,VOICE_MUTE
	 RETURN
	MOVF	INDF,W
	ANDLW	0x0F
	ADDLW	PART_CHANNEL
	MOVWF	FSR	
	MOVF	INDF,W
	ANDLW	0x1F
	SUBWF	CHANNEL,W
	RETURN

;------------------------------------------------------------------------------
; CC#07・#11・#85・#87・#88・#121・ChPressのための音量送信ルーチン
; CHANNELで受信したパートの音量を再送信する。
;------------------------------------------------------------------------------
sendvolume
	MOVLW	15			; ボイスごとに今回のチャンネルと同じパートをチェックする
	MOVWF	VOICE			; SP0256は音量調整できないためループは15回でOK
SENDVOLUME_L1
	MOVF	VOICE,W
	ADDLW	VOICE_NOTE - 1		; ボイスがノートオンされている？
	MOVWF	FSR
	BTFSS	INDF,VOICE_NOTEOFF
	 GOTO	SENDVOLUME_L2

	MOVF	VOICE,W			; ボイス0〜2(FM)か？
	SUBLW	3			; FMはハードウエアエンベロープがあるため、どの条件でもボリュームをセットして問題ない。
	BTFSC	STATUS,C		; SSGはエンベロープを使わないボイスオフ時にボリュームを操作するとホワイトノイズが出るので、
	 GOTO	SENDVOLUME_L2		; ボイス3以降で実行しないように分岐させる。

	BSF	STATUS,IRP		; ◆ IRP=1
	MOVF	VOICE,W
	ADDLW	LOW VOICE_VELOCITY - 1	; ノートオフの時、サスティン中？
	MOVWF	FSR
	BTFSS	INDF,VOICE_SUSTAIN
	 GOTO	SENDVOLUME_L1_NEXT	; サスティンもされていない場合は、次のボイス
SENDVOLUME_L2
	BCF	STATUS,IRP		; ◆ IRP=0
	MOVF	VOICE,W
	ADDLW	VOICE_PART - 1		; ボイスからパート番号を求める
	MOVWF	FSR
	BTFSC	INDF,VOICE_MUTE		; ミュートボイスの場合はスキップ
	 GOTO	SENDVOLUME_L1_NEXT

	MOVF	INDF,W
	ANDLW	0x1F
	MOVWF	PART

	ADDLW	PART_CHANNEL		; パートからチャンネルを求める
	MOVWF	FSR
	MOVLW	0x1F			; ミュートフラグも一度に調べる
	ANDWF	INDF,W
	SUBWF	CHANNEL,W
	BTFSS	STATUS,Z
	 GOTO	SENDVOLUME_L1_NEXT

	DECF	VOICE,F
	MOVLW	3
	SUBWF	VOICE,W
	BTFSC	STATUS,C
	 GOTO	SENDVOLUME_SSG
SENDVOLUME_FM
	LCALL	fm_setvelocity		; ■ PCLATH
	INCF	VOICE,F
	LGOTO	SENDVOLUME_L1_NEXT	; ■ PCLATH
SENDVOLUME_SSG
	LCALL	ssg_setvelocity		; ■ PCLATH
	INCF	VOICE,F
	MOVLW	HIGH $
	MOVWF	PCLATH			; ■ PCLATH
SENDVOLUME_L1_NEXT
	BCF	STATUS,IRP		; ◆ IRP=0
	DECFSZ	VOICE,F
	 GOTO	SENDVOLUME_L1
	RETURN
;------------------------------------------------------------------------------
; CC#64・#121のためのホールドオフルーチン
; CHANNELで受信したパートのホールドを解除し、ボイスをオフにする。
;
;    If part_sustain = 0 Then
;        For a = 1 To MAX
;            If voice.voice_sustain = 1 Then voice.voice_sustain = 0
;        Next
;    End If
;------------------------------------------------------------------------------
holdoff
	MOVLW	16
	MOVWF	PART			; 各パートのチャンネルをチェックしてPART_SUSTAINに0をセットする。
HOLDOFF_L1
	CALL	part_channel_check_P1
	BTFSS	STATUS,Z
	 GOTO	HOLDOFF_NEXT1

	MOVF	PART,W
	ADDLW	PART_CHANNEL - 1
	MOVWF	FSR
	BCF	INDF,PART_SUSTAIN	; PART_SUSTAIN = 0
HOLDOFF_NEXT1
	DECFSZ	PART,F
	 GOTO	HOLDOFF_L1

	MOVLW	16			; 各ボイスのチャンネルをチェック
	MOVWF	VOICE
HOLDOFF_L2				; ノートオフしてからボイスがオフされずに残っているものをVOICE_SUSTAINで調べてオフにする。
	CALL	voice_channel_check_P1	; 今回のチャンネルと一致しているボイスか？
	BTFSS	STATUS,Z
	 GOTO	HOLDOFF_NEXT2
	
	DECF	VOICE,F			; オフセット除去
	BSF	STATUS,IRP		; ◆ IRP=1
	MOVF	VOICE,W
	ADDLW	LOW VOICE_VELOCITY	; ボイスのサスティンフラグをチェック
	MOVWF	FSR
	BTFSS	INDF,VOICE_SUSTAIN
	 GOTO	HOLDOFF_NOTSUSTAIN	; サスティンしていないボイス
	BCF	INDF,VOICE_SUSTAIN	; サスティンしているボイスは、フラグをリセットしてからボイスオフ
	BCF	STATUS,IRP		; ◆ IRP=0
	LCALL	voiceoff		; ■ PCLATH
	MOVLW	HIGH $
	MOVWF	PCLATH			; ■ PCLATH
HOLDOFF_NOTSUSTAIN
	BCF	STATUS,IRP		; ◆ IRP=0
	INCF	VOICE,F
HOLDOFF_NEXT2
	DECFSZ	VOICE,F
	 GOTO	HOLDOFF_L2
	RETURN

;------------------------------------------------------------------------------
; CC#121とパートチャンネル変更のためのコントローラリセットルーチン
; PARTに指定されたパートのEXPRESSION,PITCHBEND,RPNをリセットする。
; PARTは1から始まる値になっている。オフセットに注意
;------------------------------------------------------------------------------
reset_controller
	BSF	STATUS,IRP		; ◆ IRP=1
	MOVF	PART,W
	ADDLW	LOW PART_EXPRESSION - 1
	MOVWF	FSR
	MOVLW	0x80			; PART_RXEXPRESSIONフラグを保持する
	ANDWF	INDF,W
	IORLW	127			; PART_EXPRESSION=127
	MOVWF	INDF

	MOVF	PART,W
	ADDLW	LOW PART_PITCHBEND - 1
	MOVWF	FSR
	MOVLW	0x40			; PART_PITCHBEND=64
	MOVWF	INDF

	MOVF	PART,W
	ADDLW	LOW PART_BENDSENS - 1
	MOVWF	FSR
	BSF	INDF,PART_RPNM		; RPNMフラグ強制ON
	BSF	INDF,PART_RPNL		; RPNLフラグ強制ON
	BCF	STATUS,IRP		; ◆ IRP=0
	RETURN

;------------------------------------------------------------------------------
; SSG NPセットルーチン
;	ボイス番号とパート番号をセットしてコールすると、指定されたボイスの周波数情報を再計算してNPにセットする。
;
; 引数
;	VOICE		ボイス番号(非破壊)
;	PART		ボイスが所属しているパート番号(非破壊)
;	PART_NOTE_TO_NP	ノート番号をNPに代入するフラグ
; 戻り値
;	なし
;
; 使用変数
;	TMP20
;------------------------------------------------------------------------------
ssg_setnp
	MOVLW	LOW PART_ENVSHAPE	; PART_NOTE_TO_NPが立っていない場合は、何もせずにリターン。
	ADDWF	PART,W
	MOVWF	FSR
	BSF	STATUS,IRP		; ◆ IRP=1
	RLF	INDF,W			; bit7(PART_NOTE_TO_NP)をCフラグに送る
	BCF	STATUS,IRP		; ◆ IRP=0
	BTFSS	STATUS,C
	 RETURN

	MOVLW	VOICE_NOTE		; ノートロード
	ADDWF	VOICE,W
	MOVWF	FSR
	MOVF	INDF,W
	ANDLW	0x7F			; VOICE_NOTEOFF除去
	MOVWF	NOTE

	MOVLW	LOW PART_PITCHBEND	; ピッチベンドロード
	ADDWF	PART,W
	MOVWF	FSR
	BSF	STATUS,IRP		; ◆ IRP=1
	MOVLW	0x80			; フルアップピッチならば0x7Fに置き換える
	SUBWF	INDF,W
	MOVLW	0x7F
	BTFSS	STATUS,Z
	 MOVF	INDF,W
	BCF	STATUS,IRP		; ◆ IRP=0
	MOVWF	PITCHBEND

	MOVLW	36			; NOTE-36
	SUBWF	NOTE,W
	BTFSS	STATUS,C		; 0以下になったら
	 CLRW				; 0を強制適用
	MOVWF	NOTE

	MOVLW	32			; 32以上になったら
	SUBWF	NOTE,W
	MOVLW	31			; 31を強制適用
	BTFSC	STATUS,C
	 MOVWF	NOTE

	RRF	PITCHBEND,W		; 00-40-7Fを00-20-3Fに変更
	ANDLW	0x3F
	MOVWF	PITCHBEND

	MOVLW	0x20			; アップでもダウンでも0x20からの絶対値を求める
	SUBWF	PITCHBEND,W		; PITCHBEND-0x20
	BTFSC	STATUS,C		; ベンドアップかダウンかチェック
	 GOTO	NPBENDCALC1
NPBENDDOWN1
	MOVF	PITCHBEND,W		; 0x20-PITCHBEND
	SUBLW	0x20
NPBENDCALC1
	MOVWF	TMP20			; 一時保存

	MOVLW	0x20
	SUBWF	PITCHBEND,W		; ベンドアップかダウンかチェックして
	BTFSS	STATUS,C		; 実際の値を加減算する
	 GOTO	NPBENDOWN2

	MOVF	TMP20,W			; 加算の時
	ADDWF	NOTE,F			; NOTE+PITCHBENDで0x20をオーバーしたら強制的に0x1Fを代入
	MOVLW	0x20
	SUBWF	NOTE,W
	BTFSS	STATUS,C
	 GOTO	NPSEND
	MOVLW	0x1F
	MOVWF	NOTE
	GOTO	NPSEND

NPBENDOWN2				; 減算の時	
	MOVF	TMP20,W
	SUBWF	NOTE,F
	BTFSS	STATUS,C		; 0を下回った時は、NOTEを0にセット
	 CLRF	NOTE
NPSEND
	MOVF	NOTE,W
	SUBLW	0x1F			; 0x1F-Wをして、低域と高域を反転させる
	MOVWF	WRITE_DATA
	LCALL	ssgchannel		; ■ PCLATH SSGチップ・チャンネル割り出し
	MOVLW	6			; NPアドレス
	MOVWF	WRITE_ADDR
	SWAPF	SSGCHIP,W		; SSG選択の数値を上位に設定
	ADDWF	WRITE_ADDR,F
	CALL	ssgwrite		; PCLATHを戻すステップがもったいないのでページ0へジャンプする(W:306)
	RETURN

;------------------------------------------------------------------------------
; CC#87・#88・#89・ChPressのための加減算ルーチン
; W=TMP20+(TMP21-0x40)
; ただし戻り値は 0 <= TMP20 <= 127 とし、キャリーアウトしないようにする。
;------------------------------------------------------------------------------
relative_addsub
	MOVLW	0x40
	SUBWF	TMP21,F			; 0-64-127を-64-0-63に変更
	MOVF	TMP21,W			; 足す数
	BTFSC	TMP21,7			; プラスかマイナスか？
	 GOTO	RELATIVE_MINUS
RELATIVE_PLUS
	ADDWF	TMP20,F			; TMP20=TMP20+TMP21
	MOVLW	0x7F
	BTFSC	RELATIVE_LIMIT,0	; ピッチベンド用に最大値のフラグを見て0x80に上限値を変更する
	 MOVLW 0x80
	BTFSS	TMP20,7			; 0x7F以下なら
	 MOVF	TMP20,W			; 結果をWに入れてリターン
	RETURN
RELATIVE_MINUS
	ADDWF	TMP20,F			; TMP20=TMP20+TMP21(TMP21は補数になっている)
	CLRW
	BTFSC	STATUS,C		; 0x00以上なら
	 MOVF	TMP20,W			; 結果をWに入れてリターン
	RETURN

;------------------------------------------------------------------------------
; リセット後のレジスタ初期設定 0xA0-0xEF,0x110-0x16F
;------------------------------------------------------------------------------
	ORG	0x0E20
INIT_REGISTER_TABLE_0			; モノボイスでリセット
	DA	0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF	; 0xA0 PART_RXPROGRAM=ON,PART_SUSTAIN=OFF,PART_RXVELOCITY=ON,PART_MUTE,RX_CHANNEL
	DA	0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01	; 0xB0 PART_MAXVOICE
	DA	0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F	; 0xC0 SSG_LEVEL=1,FM_LEVEL=1,VOICE_MUTE=0,VOICE_PART,PART_TUNING
	DA	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00	; 0xD0 VOICE_PRIORITY
	DA	0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80	; 0xE0 VOICE_NOTEOFF=ON,VOICE_NOTE

INIT_REGISTER_TABLE_1			; ポリボイスでリセット
	DA	0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF	; 0xA0 PART_RXPROGRAM=ON,PART_SUSTAIN=OFF,PART_RXVELOCITY=ON,PART_MUTE,RX_CHANNEL
	DA	0x03,0x04,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01	; 0xB0 PART_MAXVOICE
	DA	0x60,0x60,0x60,0x61,0x62,0x62,0x61,0x62,0x62,0x61,0x62,0x62,0x61,0x62,0x62,0x6F	; 0xC0 SSG_LEVEL=1,FM_LEVEL=1,VOICE_MUTE=0,VOICE_PART,PART_TUNING
	DA	0x00,0x01,0x02,0x00,0x00,0x01,0x01,0x02,0x03,0x02,0x04,0x05,0x03,0x06,0x07,0x00	; 0xD0 VOICE_PRIORITY
	DA	0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80	; 0xE0 VOICE_NOTEOFF=ON,VOICE_NOTE

INIT_REGISTER_TABLE_COM			; モノ・ポリ共通
	DA	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00	; 0x110 VOICE_SUSTAIN=OFF,VOICE_VELOCITY=0
	DA	0xE4,0xE4,0xE4,0xE4,0xE4,0xE4,0xE4,0xE4,0xE4,0xE4,0xE4,0xE4,0xE4,0xE4,0xE4,0xE4	; 0x120	PART_RXVOLUME=ON,PART_VOLUME=100
	DA	0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF	; 0x130 PART_RXEXPRESSION=ON,PART_EXPRESSION=127
	DA	0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40	; 0x140 PART_PITCHBEND=64(中央)
	DA	0xC2,0xC2,0xC2,0xC2,0xC2,0xC2,0xC2,0xC2,0xC2,0xC2,0xC2,0xC2,0xC2,0xC2,0xC2,0xC2	; 0x150 PART_RPN-x=1(未受信),PART_BENDSENS=2
	DA	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00	; 0x160 PART_NOTE_TO_NP=0,PART_PROG_BOTH=0,PART_PROG_NOISE=0,PART_USEENV=0

;------------------------------------------------------------------------------
; SP0256 音素変換テーブル
;------------------------------------------------------------------------------
ALLOPHONE_TABLE
			; ストップ
	DA	PA1	; 0
	DA	PA2	; 1
	DA	PA3	; 2
	DA	PA4	; 3
	DA	PA5	; 4
			; 子音
	DA	PP	; 5
	DA	BB1	; 6
	DA	BB2	; 7
	DA	TT1	; 8
	DA	TT2	; 9
	DA	DD1	; 10
	DA	DD2	; 11
	DA	KK1	; 12
	DA	KK2	; 13
	DA	KK3	; 14
	DA	GG1	; 15
	DA	GG2	; 16
	DA	GG3	; 17
	DA	WH	; 18
	DA	FF	; 19
	DA	VV	; 20
	DA	TH	; 21
	DA	DH1	; 22
	DA	DH2	; 23
	DA	SS	; 24
	DA	ZZ	; 25
	DA	SH	; 26
	DA	ZH	; 27
	DA	HH1	; 28
	DA	HH2	; 29
	DA	CH	; 30
	DA	JH	; 31
	DA	MM	; 32
	DA	NN1	; 33
	DA	NN2	; 34
	DA	NG	; 35
	DA	WW	; 36
	DA	RR1	; 37
	DA	RR2	; 38
	DA	LL	; 39
	DA	EL	; 40
	DA	YY1	; 41
	DA	YY2	; 42
			; 母音
	DA	YR	; 43
	DA	IY	; 44
	DA	IH	; 45
	DA	UW1	; 46
	DA	UW2	; 47
	DA	UH	; 48
	DA	EY	; 49
	DA	EH	; 50
	DA	XR	; 51
	DA	ER1	; 52
	DA	ER2	; 53
	DA	AX	; 54
	DA	OW	; 55
	DA	OY	; 56
	DA	AE	; 57
	DA	AW	; 58
	DA	AY	; 59
	DA	AR	; 60
	DA	AA	; 61
	DA	AO	; 62
	DA	OR	; 63

;------------------------------------------------------------------------------
; SP0256 16進数プログラムリードテーブル
;------------------------------------------------------------------------------
SPHEX_INDEX
	DA	SP_0		; フレーズが入っているアドレスのポインタを格納する
	DA	SP_1
	DA	SP_2
	DA	SP_3
	DA	SP_4
	DA	SP_5
	DA	SP_6
	DA	SP_7
	DA	SP_8
	DA	SP_9
	DA	SP_A
	DA	SP_B
	DA	SP_C
	DA	SP_D
	DA	SP_E
	DA	SP_F
	DA	SP_0_P		; フレーズが入っているアドレスのポインタを格納する
	DA	SP_1_P
	DA	SP_2_P
	DA	SP_3_P
	DA	SP_4_P
	DA	SP_5_P
	DA	SP_6_P
	DA	SP_7_P
	DA	SP_8_P
	DA	SP_9_P
	DA	SP_A_P
	DA	SP_B_P
	DA	SP_C_P
	DA	SP_D_P
	DA	SP_E_P
	DA	SP_F_P

SP_0				; 実際のフレーズ
	DA	ZZ
	DA	EH
	DA	RR2
	DA	OW + 0x0100
SP_1
	DA	YY1
	DA	CH
	DA	IY + 0x0100
SP_2
	DA	NN1
	DA	IY
	DA	PA3 + 0x0100
SP_3
	DA	SS
	DA	SS
	DA	AX
	DA	AX
	DA	NN1 + 0x0100
SP_4
	DA	YY1
	DA	AO
	DA	NN1 + 0x0100
SP_5
	DA	GG2
	DA	AX
	DA	OW + 0x0100
SP_6
	DA	RR2
	DA	AO
	DA	KK3
	DA	UH + 0x0100
SP_7
	DA	NN2
	DA	AA
	DA	NN2
	DA	AA + 0x0100
SP_8
	DA	HH1
	DA	AX
	DA	CH + 0x0100
SP_9
	DA	KK1
	DA	UW2 + 0x0100
SP_A
	DA	EH
	DA	EH
	DA	EY + 0x0100
SP_B
	DA	BB2
	DA	IY
	DA	PA3 + 0x0100
SP_C
	DA	SS
	DA	SS
	DA	IY + 0x0100
SP_D
	DA	DD2
	DA	IY
	DA	PA3 + 0x0100
SP_E
	DA	IY
	DA	PA4 + 0x0100
SP_F
	DA	EH
	DA	EH
	DA	FF
	DA	FF + 0x0100

SP_0_P				; フォネティックコード
	DA	ZZ
	DA	YR
	DA	OW + 0x0100
SP_1_P
	DA	WW
	DA	AX
	DA	NN1 + 0x0100
SP_2_P
	DA	TT2
	DA	UW2 + 0x0100
SP_3_P
	DA	TT2
	DA	RR1
	DA	IY + 0x0100
SP_4_P
	DA	FF
	DA	OR + 0x0100
SP_5_P
	DA	FF
	DA	AY
	DA	FF + 0x0100
SP_6_P
	DA	SS
	DA	SS
	DA	IH
	DA	IH
	DA	PA3
	DA	KK2
	DA	SS + 0x0100
SP_7_P
	DA	SS
	DA	SS
	DA	EH
	DA	EH
	DA	VV
	DA	IH
	DA	NN1 + 0x0100
SP_8_P
	DA	EY
	DA	PA3
	DA	TT2 + 0x0100
SP_9_P
	DA	NN1
	DA	AY
	DA	NN2
	DA	ER1 + 0x0100
SP_A_P
	DA	AA
	DA	LL
	DA	FF
	DA	AA
	DA	AA + 0x0100
SP_B_P
	DA	BB2
	DA	RR1
	DA	AA
	DA	AA
	DA	BB2
	DA	OW + 0x0100
SP_C_P
	DA	CH
	DA	AX
	DA	AX
	DA	RR2
	DA	IY + 0x0100
SP_D_P
	DA	DD2
	DA	EH
	DA	LL
	DA	TT1
	DA	AA
	DA	AA + 0x0100
SP_E_P
	DA	EH
	DA	KK2
	DA	OW + 0x0100
SP_F_P
	DA	FF
	DA	AO
	DA	KK2
	DA	SS
	DA	TT2
	DA	RR2
	DA	PA4
	DA	TT2 + 0x0100

;------------------------------------------------------------------------------
; ページ2
;------------------------------------------------------------------------------
	ORG	1000H
;------------------------------------------------------------------------------
; SYSEX分岐
; F0 7D 01 までチェック済みで次のEX_ADDR1を使って分岐させる。
;------------------------------------------------------------------------------
SYSEX_DATASET_P2
	MOVLW	0x00			; 0x00はシステムリセット
	SUBWF	EX_ADDR1,W
	BTFSC	STATUS,Z
	 GOTO	SYSEX_SYSTEMRESET

	MOVLW	0x01			; 0x01はパート受信チャンネル
	SUBWF	EX_ADDR1,W
	BTFSC	STATUS,Z
	 GOTO	SYSEX_CHANNEL

	MOVLW	0x02			; 0x02はボイスとパートの関連付け
	SUBWF	EX_ADDR1,W
	BTFSC	STATUS,Z
	 GOTO	SYSEX_VOICE

	MOVLW	0x03			; 0x03はチューニング切り替え
	SUBWF	EX_ADDR1,W
	BTFSC	STATUS,Z
	 GOTO	SYSEX_TUNING_ALL

	MOVLW	0x04			; 0x04はメトロノームの動作定義
	SUBWF	EX_ADDR1,W
	BTFSC	STATUS,Z
	 GOTO	SYSEX_METRONOME

	MOVLW	0x05			; 0x05は各社リセットの受信フラグ
	SUBWF	EX_ADDR1,W
	BTFSC	STATUS,Z
	 GOTO	SYSEX_VENDORRESET

	MOVLW	0x06			; 0x06はSP0256ダンプのフォネティックフラグ
	SUBWF	EX_ADDR1,W
	BTFSC	STATUS,Z
	 GOTO	SYSEX_PHONETIC

	MOVLW	0x10			; 0x10はベロシティ受信フラグ
	SUBWF	EX_ADDR1,W
	BTFSC	STATUS,Z
	 GOTO	SYSEX_VELOCITY

	MOVLW	0x11			; 0x11はボリューム受信フラグ
	SUBWF	EX_ADDR1,W
	BTFSC	STATUS,Z
	 GOTO	SYSEX_VOLUME

	MOVLW	0x12			; 0x12はエクスプレッション受信フラグ
	SUBWF	EX_ADDR1,W
	BTFSC	STATUS,Z
	 GOTO	SYSEX_EXPRESSION

	MOVLW	0x13			; 0x13はプログラムチェンジ受信フラグ
	SUBWF	EX_ADDR1,W
	BTFSC	STATUS,Z
	 GOTO	SYSEX_PROGRAM

	MOVLW	0x14			; 0x14はFM音源の音量補正
	SUBWF	EX_ADDR1,W
	BTFSC	STATUS,Z
	 GOTO	SYSEX_FM_LEVEL

	MOVLW	0x15			; 0x15はSSG音源の音量補正
	SUBWF	EX_ADDR1,W
	BTFSC	STATUS,Z
	 GOTO	SYSEX_SSG_LEVEL

	MOVLW	0x16			; 0x16はパートボリューム変更
	SUBWF	EX_ADDR1,W
	BTFSC	STATUS,Z
	 GOTO	SYSEX_SET_VOLUME

	MOVLW	0x17			; 0x17はパートエクスプレッション変更
	SUBWF	EX_ADDR1,W
	BTFSC	STATUS,Z
	 GOTO	SYSEX_SET_EXPRESSION

	MOVLW	0x18			; 0x18はパートピッチベンド変更
	SUBWF	EX_ADDR1,W
	BTFSC	STATUS,Z
	 GOTO	SYSEX_SET_PITCHBEND

	MOVLW	0x19			; 0x19はパートピッチベンドセンシティビティ変更
	SUBWF	EX_ADDR1,W
	BTFSC	STATUS,Z
	 GOTO	SYSEX_SET_BENDSENS

	MOVLW	0x1A			; 0x1Aはパートエンベロープシェイプ変更
	SUBWF	EX_ADDR1,W
	BTFSC	STATUS,Z
	 GOTO	SYSEX_SET_ENVSHAPE

	MOVLW	0x1B			; 0x1Aはパートチューニング変更
	SUBWF	EX_ADDR1,W
	BTFSC	STATUS,Z
	 GOTO	SYSEX_TUNING_PART

	MOVLW	0x20			; 0x20はFMプログラム保存
	SUBWF	EX_ADDR1,W
	BTFSC	STATUS,Z
	 GOTO	SYSEX_SAVEFMPROGRAM

	MOVF	EX_ADDR1,W
	SUBLW	0x6F			; 〜0x6Fは無視
	BTFSC	STATUS,C
	 GOTO	SYSEX_UNMATCH_P2

	MOVF	EX_ADDR1,W
	SUBLW	0x73			; 0x70〜0x73はSSGデバッグ
	BTFSC	STATUS,C
	 GOTO	SYSEX_7X_SSG

	MOVF	EX_ADDR1,W
	SUBLW	0x75			; 0x74〜0x75はFMデバッグ
	BTFSC	STATUS,C
	 GOTO	SYSEX_7X_FM

	MOVLW	0x76			; 0x76はSPデバッグ
	SUBWF	EX_ADDR1,W
	BTFSC	STATUS,Z
	 GOTO	SYSEX_76

	MOVLW	0x77			; 0x77はSPデバッグ
	SUBWF	EX_ADDR1,W
	BTFSC	STATUS,Z
	 GOTO	SYSEX_77

	MOVLW	0x7D			; 0x7DはFMレジスタダンプ
	SUBWF	EX_ADDR1,W
	BTFSC	STATUS,Z
	 GOTO	SYSEX_FMDUMP

	MOVLW	0x7E			; 0x7Eはレジスタダンプ
	SUBWF	EX_ADDR1,W
	BTFSC	STATUS,Z
	 GOTO	SYSEX_RAMDUMP

	MOVLW	0x7F			; 0x7Fはレジスタプリセットダンプ
	SUBWF	EX_ADDR1,W
	BTFSC	STATUS,Z
	 GOTO	SYSEX_PRESETDUMP

	GOTO	SYSEX_UNMATCH_P2	; 未対応アドレスはPHASE_IGNOREへ移行
;------------------------------------------------------------------------------
; SYSEX個別内容
; EX_ADDR1は固定
;
; SYSEX_DATABACKUPでリターンすると、PARAM1をEX_DATAに格納して次のデータを受信する。
;   EX_ADDR2をインクリメントしないので、2バイト用・ニブルデータ等に使用できる。
; SYSEX_INC_RETURNでリターンすると、EX_ADDR2をインクリメントする。
;   
; SYSEX_UNMATCHでリターンさせると以降のエクスクルーシブは無条件に無視される。
;   固定長エクスクルーシブの終端に使う。
;
;------------------------------------------------------------------------------
SYSEX_SYSTEMRESET			; F0 7D 01 00 [00] [PARAM1] F7
	MOVF	EX_ADDR2,W
	BTFSS	STATUS,Z
	 GOTO	SYSEX_UNMATCH_P2

	MOVF	PARAM1,W		; リセットモードが2以上の場合はリセットを行わない
	SUBLW	1
	BTFSS	STATUS,C
	 GOTO	SYSEX_UNMATCH_P2

	BCF	PFLAG,RESET_MODE	; PARAM1からリセットモードをセットしてリセットをコール
	BTFSC	PARAM1,0
	 BSF	PFLAG,RESET_MODE
	LCALL	system_reset
	GOTO	SYSEX_UNMATCH		; PCLATHを戻すステップがもったいないのでページ0へジャンプする(W:306)
;------------------------------------------------------------------------------
SYSEX_CHANNEL				; F0 7D 01 01 [0-0F] [PARAM1] .. F7
	MOVLW	16			; 16バイト目以降は無視する
	SUBWF	EX_ADDR2,W
	BTFSC	STATUS,C
	 GOTO	SYSEX_UNMATCH_P2

	MOVLW	17			; チャンネルが16以上の無効な値の時は、強制的に16を代入する
	SUBWF	PARAM1,W
	MOVF	PARAM1,W
	BTFSC	STATUS,C
	 MOVLW	16
	MOVWF	PARAM1

	MOVLW	PART_CHANNEL		; PART_CHANNELにエクスクルーシブのアドレスを足して
	ADDWF	EX_ADDR2,W		; データの保存場所を確定
	MOVWF	FSR

	MOVF	INDF,W			; 値が変わらないなら変更をスキップする
	ANDLW	0x1F
	SUBWF	PARAM1,W
	BTFSC	STATUS,Z
	 GOTO	SYSEX_INC_RETURN_P2

	BTFSC	INDF,PART_MUTE		; ミュートパートなら変更前処理を省く
	 GOTO	SYSEX_CHANNEL_CHANGE

	INCF	EX_ADDR2,W		; 該当パートのコントローラをリセット
	MOVWF	PART
	LCALL	reset_controller	; ■ PCLATH
	MOVLW	HIGH $
	MOVWF	PCLATH			; ■ PCLATH

	MOVLW	16			; 全ボイスをスキャン
	MOVWF	TMP00
SYSEX_CHANNEL_VOICEOFF
	MOVLW	VOICE_PART - 1		; ボイスのパート番号チェック
	ADDWF	TMP00,W 
	MOVWF	FSR
	MOVF	INDF,W
	ANDLW	0x1F
	SUBWF	EX_ADDR2,W
	BTFSS	STATUS,Z
	 GOTO	SYSEX_CHANNEL_VOICEOFF_NEXT ; 別のパートだった

	MOVLW	VOICE_NOTE - 1		; NoteOff?
	ADDWF	TMP00,W 
	MOVWF	FSR
	COMF	INDF,W
	MOVWF	TMP01
	MOVLW	LOW VOICE_VELOCITY - 1	; Not Sustain?
	ADDWF	TMP00,W 
	MOVWF	FSR
	BSF	STATUS,IRP		; ◆ IRP=1
	MOVF	INDF,W
	BCF	STATUS,IRP		; ◆ IRP=0
	IORWF	TMP01,W
	ANDLW	0x80
	BTFSC	STATUS,Z		; 発音中の状態でない場合はスキップ
	 GOTO	SYSEX_CHANNEL_VOICEOFF_NEXT

	DECF	TMP00,W			; ボイス停止
	MOVWF	VOICE
	CLRF	PCLATH			; ■ PCLATH
	CALL	voiceoff
	MOVLW	HIGH $
	MOVWF	PCLATH			; ■ PCLATH

	MOVLW	VOICE_NOTE - 1		; NoteOff
	ADDWF	TMP00,W 
	MOVWF	FSR
	BSF	INDF,VOICE_NOTEOFF
	MOVLW	LOW VOICE_VELOCITY - 1	; Not Sustain
	ADDWF	TMP00,W 
	MOVWF	FSR
	BSF	STATUS,IRP		; ◆ IRP=1
	BCF	INDF,VOICE_SUSTAIN	; Not Sustain
	BCF	STATUS,IRP		; ◆ IRP=0
SYSEX_CHANNEL_VOICEOFF_NEXT
	DECFSZ	TMP00,F
	 GOTO	SYSEX_CHANNEL_VOICEOFF	; 前処理ループ終わり

SYSEX_CHANNEL_CHANGE
	MOVLW	PART_CHANNEL		; PART_CHANNELにエクスクルーシブのアドレスを足して
	ADDWF	EX_ADDR2,W		; チャンネルデータを代入する
	MOVWF	FSR

	MOVLW	B'11100000'		; 既存のフラグとチャンネル番号をミックスして保存
	ANDWF	INDF,W
	IORWF	PARAM1,W
	MOVWF	INDF
	GOTO	SYSEX_INC_RETURN_P2	; 次のアドレスへ
;------------------------------------------------------------------------------
SYSEX_VOICE				; F0 7D 01 02 [0-0F] [PARAM1] .. F7
	MOVLW	16			; 16バイト目以降は無視する
	SUBWF	EX_ADDR2,W
	BTFSC	STATUS,C
	 GOTO	SYSEX_UNMATCH_P2

	MOVLW	17			; パートデータが16以上の無効な値の時は、強制的に16を代入する
	SUBWF	PARAM1,W
	MOVF	PARAM1,W
	BTFSC	STATUS,C
	 MOVLW	16
	MOVWF	PARAM1

	MOVLW	VOICE_PART		; VOICE_PARTにエクスクルーシブのアドレスを足して
	ADDWF	EX_ADDR2,W		; データの保存場所を確定
	MOVWF	FSR

	MOVF	INDF,W			; 値が変わらないなら変更をスキップする
	ANDLW	0x1F
	MOVWF	TMP00			; 変更前のパート番号をデタッチ用に一時保存
	SUBWF	PARAM1,W
	BTFSC	STATUS,Z
	 GOTO	SYSEX_INC_RETURN_P2

	BTFSC	INDF,VOICE_MUTE		; ミュートボイスなら変更前処理を省く
	 GOTO	SYSEX_VOICE_CHANGE
;--
	MOVLW	VOICE_NOTE		; ボイスが発音中なら消音し、フラグをリセットする
	ADDWF	EX_ADDR2,W		; NoteOff?
	MOVWF	FSR
	COMF	INDF,W
	MOVWF	TMP01
	BSF	INDF,VOICE_NOTEOFF	; コード量削減のため、無条件にリセットする
	MOVLW	LOW VOICE_VELOCITY	; Not Sustain?
	ADDWF	EX_ADDR2,W
	MOVWF	FSR
	BSF	STATUS,IRP		; ◆ IRP=1
	MOVF	INDF,W
	BCF	INDF,VOICE_SUSTAIN	; コード量削減のため、無条件にリセットする
	BCF	STATUS,IRP		; ◆ IRP=0
	IORWF	TMP01,W
	ANDLW	0x80
	BTFSC	STATUS,Z		; 発音中の状態でない場合はスキップ
	 GOTO	SYSEX_VOICE_DETACH

	MOVF	EX_ADDR2,W		; ボイス停止
	MOVWF	VOICE
	CLRF	PCLATH			; ■ PCLATH
	CALL	voiceoff
	MOVLW	HIGH $
	MOVWF	PCLATH			; ■ PCLATH
;--
SYSEX_VOICE_DETACH
	MOVLW	VOICE_PRIORITY
	ADDWF	EX_ADDR2,W
	MOVWF	FSR
	MOVF	INDF,W
	MOVWF	TMP01			; デタッチするボイスの優先度

	MOVLW	16
	MOVWF	TMP02
SYSEX_VOICE_DETACH_LOOP
	MOVLW	VOICE_PART - 1		; デタッチするボイスと同じパート番号のボイスを検索
	ADDWF	TMP02,W
	MOVWF	FSR
	MOVF	INDF,W
	ANDLW	0x1F
	SUBWF	TMP00,W
	BTFSS	STATUS,Z
	 GOTO	SYSEX_VOICE_DETACH_NEXT

	MOVLW	VOICE_PRIORITY - 1	; そのボイスの優先度がデタッチするボイスの優先度より高い場合、
	ADDWF	TMP02,W			; デクリメントして優先度を繰り上げる。
	MOVWF	FSR
	MOVF	INDF,W
	SUBWF	TMP01,W
	BTFSS	STATUS,C
	 DECF	INDF,F
SYSEX_VOICE_DETACH_NEXT
	DECFSZ	TMP02,F
	 GOTO	SYSEX_VOICE_DETACH_LOOP
	MOVLW	PART_MAXVOICE		; 変更前のPART_MAXVOICEをデクリメント
	ADDWF	TMP00,W
	MOVWF	FSR
	DECF	INDF,F
;--
SYSEX_VOICE_CHANGE
	MOVLW	VOICE_PART
	ADDWF	EX_ADDR2,W
	MOVWF	FSR
	MOVLW	B'11100000'		; 既存のフラグとパート番号をミックスして保存
	ANDWF	INDF,W
	IORWF	PARAM1,W
	MOVWF	INDF
;--
	BTFSC	INDF,VOICE_MUTE		; 変更後がミュートボイスなら優先度の変更を省く
	 GOTO	SYSEX_INC_RETURN_P2	;  ミュートボイスは過去の優先度が放置されるが問題ない。
;--
SYSEX_VOICE_ATTACH			; 変更後のパート内でノートオフしているボイスの最低優先度としてアタッチする
	CLRF	TMP00			; ノートオフボイスのカウンタ
	MOVLW	16
	MOVWF	TMP01
SYSEX_VOICE_ATTACH_LOOP
	MOVLW	VOICE_PART - 1		; アタッチするボイスと同じパート番号のボイスを検索
	ADDWF	TMP01,W
	MOVWF	FSR
	MOVF	INDF,W
	ANDLW	0x1F
	SUBWF	PARAM1,W
	BTFSS	STATUS,Z
	 GOTO	SYSEX_VOICE_ATTACH_NEXT
	
	MOVLW	VOICE_NOTE - 1		; そのボイスはノートオフか?
	ADDWF	TMP01,W
	MOVWF	FSR
	BTFSS	INDF,VOICE_NOTEOFF
	 GOTO	SYSEX_VOICE_ATTACH_ISON
	INCF	TMP00,F
	GOTO	SYSEX_VOICE_ATTACH_NEXT
SYSEX_VOICE_ATTACH_ISON
	MOVLW	VOICE_PRIORITY - 1	; ノートオンのボイスはVOICE_PRIORITYをインクリメントして
	ADDWF	TMP01,W			; 優先度を繰り下げる。
	MOVWF	FSR
	INCF	INDF,F
SYSEX_VOICE_ATTACH_NEXT
	DECFSZ	TMP01,F
	 GOTO	SYSEX_VOICE_ATTACH_LOOP

	MOVLW	PART_MAXVOICE		; 既存のPART_MAXVOICEをインクリメント
	ADDWF	PARAM1,W
	MOVWF	FSR
	INCF	INDF,F
	MOVLW	VOICE_PRIORITY		; 優先度を付与
	ADDWF	EX_ADDR2,W
	MOVWF	FSR
	DECF	TMP00,W			; 自分もカウントされているので-1する
	MOVWF	INDF
	GOTO	SYSEX_INC_RETURN_P2	; 次のアドレスへ

;------------------------------------------------------------------------------
SYSEX_TUNING_ALL			; F0 7D 01 03 [00] [00|01] F7
	MOVF	EX_ADDR2,W
	BTFSS	STATUS,Z
	 GOTO	SYSEX_UNMATCH_P2

	MOVF	PARAM1,W		; 設定値が2以上の場合は値をセットしない
	SUBLW	1
	BTFSS	STATUS,C
	 GOTO	SYSEX_UNMATCH_P2

	MOVLW	16
	MOVWF	TMP00			; ループカウンタ
	MOVLW	VOICE_PART
	MOVWF	FSR
SYSEX_TUNING_ALL_LOOP
	BSF	INDF,PART_TUNING	; PART_TUNING=1(444Hz)
	MOVF	PARAM1,W		; PARAM1が0の時は
	BTFSC	STATUS,Z
	 BCF	INDF,PART_TUNING	; PART_TUNING=0(440Hz)に変更
	INCF	FSR,F
	DECFSZ	TMP00,F
	 GOTO	SYSEX_TUNING_ALL_LOOP
	GOTO	SYSEX_UNMATCH_P2
;------------------------------------------------------------------------------
SYSEX_METRONOME				; F0 7D 01 04 [00-03] [PARAM1] .. F7
	MOVLW	0			; 0=CLOCK_LIMIT 全=96 2分=48 4分=24 8分=12 16分=6 32分=3
	SUBWF	EX_ADDR2,W		; 	BEAT_LIMIT=1,MIDDLE_BEAT1,MIDDLE_BEAT2はクリアされる
	BTFSC	STATUS,Z
	 GOTO	SYSEX_METRONOME_00

	MOVLW	1			; 1=BEAT_LIMIT(拍子)
	SUBWF	EX_ADDR2,W		; 	MIDDLE_BEAT1,MIDDLE_BEAT2はクリアされる
	BTFSC	STATUS,Z
	 GOTO	SYSEX_METRONOME_01

	MOVLW	2			; 2=MIDDLE_BEAT1(任意)
	SUBWF	EX_ADDR2,W		; 	MIDDLE_BEAT2はクリアされる
	BTFSC	STATUS,Z
	 GOTO	SYSEX_METRONOME_02

	MOVLW	3			; 3=MIDDLE_BEAT2(任意)
	SUBWF	EX_ADDR2,W
	BTFSC	STATUS,Z
	 GOTO	SYSEX_METRONOME_03

	GOTO	SYSEX_UNMATCH_P2	; それ以外のアドレスは無視

SYSEX_METRONOME_00
	MOVF	PARAM1,W
	MOVWF	CLOCK_LIMIT
	MOVLW	1
	MOVWF	BEAT_LIMIT
	CLRF	MIDDLE_BEAT1
	CLRF	MIDDLE_BEAT2
	GOTO	SYSEX_INC_RETURN_P2

SYSEX_METRONOME_01
	MOVF	PARAM1,W
	MOVWF	BEAT_LIMIT
	CLRF	MIDDLE_BEAT1
	CLRF	MIDDLE_BEAT2
	GOTO	SYSEX_INC_RETURN_P2

SYSEX_METRONOME_02
	MOVF	PARAM1,W
	MOVWF	MIDDLE_BEAT1
	CLRF	MIDDLE_BEAT2
	GOTO	SYSEX_INC_RETURN_P2

SYSEX_METRONOME_03
	MOVF	PARAM1,W
	MOVWF	MIDDLE_BEAT2
	GOTO	SYSEX_UNMATCH_P2
;------------------------------------------------------------------------------
SYSEX_VENDORRESET			; F0 7D 01 05 [00] [00|01] .. F7
	MOVF	EX_ADDR2,W
	BTFSS	STATUS,Z
	 GOTO	SYSEX_UNMATCH_P2

	MOVF	PARAM1,W		; 設定値が2以上の場合は値をセットしない
	SUBLW	1
	BTFSS	STATUS,C
	 GOTO	SYSEX_UNMATCH_P2

	BSF	PFLAG,VENDOR_RESET	; フラグをセットする
	MOVF	PARAM1,W		; PARAM1が0の時は
	BTFSC	STATUS,Z
	 BCF	PFLAG,VENDOR_RESET	; フラグをクリアする
	GOTO	SYSEX_UNMATCH_P2
;------------------------------------------------------------------------------
SYSEX_PHONETIC			; F0 7D 01 06 [00] [00|01] .. F7
	MOVF	EX_ADDR2,W
	BTFSS	STATUS,Z
	 GOTO	SYSEX_UNMATCH_P2

	MOVF	PARAM1,W		; 設定値が2以上の場合は値をセットしない
	SUBLW	1
	BTFSS	STATUS,C
	 GOTO	SYSEX_UNMATCH_P2

	BSF	PFLAG,SP_PHONETIC	; フラグをセットする
	MOVF	PARAM1,W		; PARAM1が0の時は
	BTFSC	STATUS,Z
	 BCF	PFLAG,SP_PHONETIC	; フラグをクリアする
	GOTO	SYSEX_UNMATCH_P2
;------------------------------------------------------------------------------
SYSEX_VELOCITY				; F0 7D 01 10 [00-0F] [00|01] .. F7
	MOVLW	16			; 16バイト目以降は無視する
	SUBWF	EX_ADDR2,W
	BTFSC	STATUS,C
	 GOTO	SYSEX_UNMATCH_P2

	MOVF	PARAM1,W		; 設定値が2以上の場合は値をセットせず次のアドレスへ進める
	SUBLW	1
	BTFSS	STATUS,C
	 GOTO	SYSEX_INC_RETURN_P2

	MOVLW	PART_CHANNEL		; PART_CHANNELにエクスクルーシブのアドレスを足して
	ADDWF	EX_ADDR2,W		; パートの位置を計算する
	MOVWF	FSR

	BSF	INDF,PART_RXVELOCITY	; PART_RXVELOCITY=1
	MOVF	PARAM1,W		; PARAM1が0の時は
	BTFSC	STATUS,Z
	 BCF	INDF,PART_RXVELOCITY	; PART_RXVELOCITY=0に変更
	GOTO	SYSEX_INC_RETURN_P2
;------------------------------------------------------------------------------
SYSEX_VOLUME				; F0 7D 01 11 [00-0F] [00|01] .. F7
	MOVLW	16			; 16バイト目以降は無視する
	SUBWF	EX_ADDR2,W
	BTFSC	STATUS,C
	 GOTO	SYSEX_UNMATCH_P2

	MOVF	PARAM1,W		; 設定値が2以上の場合は値をセットせず次のアドレスへ進める
	SUBLW	1
	BTFSS	STATUS,C
	 GOTO	SYSEX_INC_RETURN_P2

	MOVLW	LOW PART_VOLUME		; PART_VOLUMEにエクスクルーシブのアドレスを足して
	ADDWF	EX_ADDR2,W		; パートの位置を計算する
	MOVWF	FSR
	BSF	STATUS,IRP		; ◆ IRP=1

	BSF	INDF,PART_RXVOLUME	; PART_RXVOLUME=1
	MOVF	PARAM1,W		; PARAM1が0の時は
	BTFSC	STATUS,Z
	 BCF	INDF,PART_RXVOLUME	; PART_RXVOLUME=0に変更
	BCF	STATUS,IRP		; ◆ IRP=0
	GOTO	SYSEX_INC_RETURN_P2
;------------------------------------------------------------------------------
SYSEX_EXPRESSION			; F0 7D 01 12 [00-0F] [00|01] .. F7
	MOVLW	16			; 16バイト目以降は無視する
	SUBWF	EX_ADDR2,W
	BTFSC	STATUS,C
	 GOTO	SYSEX_UNMATCH_P2

	MOVF	PARAM1,W		; 設定値が2以上の場合は値をセットせず次のアドレスへ進める
	SUBLW	1
	BTFSS	STATUS,C
	 GOTO	SYSEX_INC_RETURN_P2

	MOVLW	LOW PART_EXPRESSION	; PART_EXPRESSIONにエクスクルーシブのアドレスを足して
	ADDWF	EX_ADDR2,W		; パートの位置を計算する
	MOVWF	FSR
	BSF	STATUS,IRP		; ◆ IRP=1

	BSF	INDF,PART_RXEXPRESSION	; PART_RXEXPRESSION=1
	MOVF	PARAM1,W		; PARAM1が0の時は
	BTFSC	STATUS,Z
	 BCF	INDF,PART_RXEXPRESSION	; PART_RXEXPRESSION=0に変更
	BCF	STATUS,IRP		; ◆ IRP=0
	GOTO	SYSEX_INC_RETURN_P2
;------------------------------------------------------------------------------
SYSEX_PROGRAM				; F0 7D 01 13 [00-0F] [00|01] .. F7
	MOVLW	16			; 16バイト目以降は無視する
	SUBWF	EX_ADDR2,W
	BTFSC	STATUS,C
	 GOTO	SYSEX_UNMATCH_P2

	MOVF	PARAM1,W		; 設定値が2以上の場合は値をセットせず次のアドレスへ進める
	SUBLW	1
	BTFSS	STATUS,C
	 GOTO	SYSEX_INC_RETURN_P2

	MOVLW	PART_CHANNEL		; PART_CHANNELにエクスクルーシブのアドレスを足して
	ADDWF	EX_ADDR2,W		; パートの位置を計算する
	MOVWF	FSR

	BSF	INDF,PART_RXPROGRAM	; PART_RXPROGRAM=1
	MOVF	PARAM1,W		; PARAM1が0の時は
	BTFSC	STATUS,Z
	 BCF	INDF,PART_RXPROGRAM	; PART_RXPROGRAM=0に変更
	GOTO	SYSEX_INC_RETURN_P2
;------------------------------------------------------------------------------
SYSEX_FM_LEVEL				; F0 7D 01 14 [00-0F] [00|01] .. F7
	MOVLW	16			; 16バイト目以降は無視する
	SUBWF	EX_ADDR2,W
	BTFSC	STATUS,C
	 GOTO	SYSEX_UNMATCH_P2

	MOVF	PARAM1,W		; 設定値が2以上の場合は値をセットせず次のアドレスへ進める
	SUBLW	1
	BTFSS	STATUS,C
	 GOTO	SYSEX_INC_RETURN_P2

	MOVLW	VOICE_PART		; VOICE_PARTにエクスクルーシブのアドレスを足して
	ADDWF	EX_ADDR2,W		; パートの位置を計算する
	MOVWF	FSR

	BSF	INDF,PART_FM_LEVEL	; PART_FM_LEVEL=1
	MOVF	PARAM1,W		; PARAM1が0の時は
	BTFSC	STATUS,Z
	 BCF	INDF,PART_FM_LEVEL	; PART_FM_LEVEL=0に変更
	GOTO	SYSEX_INC_RETURN_P2
;------------------------------------------------------------------------------
SYSEX_SSG_LEVEL				; F0 7D 01 15 [00-0F] [00|01] .. F7
	MOVLW	16			; 16バイト目以降は無視する
	SUBWF	EX_ADDR2,W
	BTFSC	STATUS,C
	 GOTO	SYSEX_UNMATCH_P2

	MOVF	PARAM1,W		; 設定値が2以上の場合は値をセットせず次のアドレスへ進める
	SUBLW	1
	BTFSS	STATUS,C
	 GOTO	SYSEX_INC_RETURN_P2

	MOVLW	VOICE_PART		; VOICE_PARTにエクスクルーシブのアドレスを足して
	ADDWF	EX_ADDR2,W		; パートの位置を計算する
	MOVWF	FSR

	BSF	INDF,PART_SSG_LEVEL	; PART_SSG_LEVEL=1
	MOVF	PARAM1,W		; PARAM1が0の時は
	BTFSC	STATUS,Z
	 BCF	INDF,PART_SSG_LEVEL	; PART_SSG_LEVEL=0に変更
	GOTO	SYSEX_INC_RETURN_P2
;------------------------------------------------------------------------------
SYSEX_SET_VOLUME			; F0 7D 01 16 [00-0F] [00-7F] .. F7
	MOVLW	16			; 16バイト目以降は無視する
	SUBWF	EX_ADDR2,W
	BTFSC	STATUS,C
	 GOTO	SYSEX_UNMATCH_P2

	MOVF	PARAM1,W		; データセットを共通ルーチンにするため
	MOVWF	TMP00			;  受信した値はTMP00に入れておく。
	MOVLW	LOW PART_VOLUME		; PART_VOLUMEにエクスクルーシブのアドレスを足して
SYSEX_SET_VCOMMON
	ADDWF	EX_ADDR2,W		; パートの位置を計算する
	MOVWF	FSR
	BSF	STATUS,IRP		; ◆ IRP=1
	MOVLW	0x80
	ANDWF	INDF,W
	ADDWF	TMP00,W
	MOVWF	INDF
	BCF	STATUS,IRP		; ◆ IRP=0

	MOVF	EX_ADDR2,W		; パートからチャンネルを求め、
	ADDLW	PART_CHANNEL		; 音量セットルーチンのチャンネルチェックで除外されないようにする。
	MOVWF	FSR
	MOVF	INDF,W
	ANDLW	0x1F			; パートのミュート状態も含めているので、
	MOVWF	CHANNEL			; ミュートしているチャンネルパートも反映される。
	BSF	FLAG1,SUPPRESS_SHAPESET	; エンベロープの再セットを抑制する
	LCALL	sendvolume		; ■ PCLATH
	BCF	FLAG1,SUPPRESS_SHAPESET
	LGOTO	SYSEX_INC_RETURN_P2	; ■ PCLATH
;------------------------------------------------------------------------------
SYSEX_SET_EXPRESSION			; F0 7D 01 17 [00-0F] [00-7F] .. F7
	MOVLW	16			; 16バイト目以降は無視する
	SUBWF	EX_ADDR2,W
	BTFSC	STATUS,C
	 GOTO	SYSEX_UNMATCH_P2

	MOVF	PARAM1,W		; SYSEX_SET_VOLUMEと同じ
	MOVWF	TMP00
	MOVLW	LOW PART_EXPRESSION
	GOTO	SYSEX_SET_VCOMMON
;------------------------------------------------------------------------------
SYSEX_SET_PITCHBEND			; F0 7D 01 18 [00-0F] [00-7F] .. F7
	MOVLW	16			; 16バイト目以降は無視する
	SUBWF	EX_ADDR2,W
	BTFSC	STATUS,C
	 GOTO	SYSEX_UNMATCH_P2

	MOVLW	LOW PART_PITCHBEND
	ADDWF	EX_ADDR2,W		; パートの位置を計算する
	MOVWF	FSR
	MOVF	PARAM1,W
	BSF	STATUS,IRP		; ◆ IRP=1
	MOVWF	INDF
SYSEX_SET_PCOMMON
	BCF	STATUS,IRP		; ◆ IRP=0
	MOVF	EX_ADDR2,W
	ADDLW	PART_CHANNEL
	MOVWF	FSR
	MOVF	INDF,W
	ANDLW	0x1F
	MOVWF	CHANNEL
	LCALL	sendpitch		; ■ PCLATH
	LGOTO	SYSEX_INC_RETURN_P2	; ■ PCLATH
;------------------------------------------------------------------------------
SYSEX_SET_BENDSENS			; F0 7D 01 19 [00-0F] [00-7F] .. F7
	MOVLW	16			; 16バイト目以降は無視する
	SUBWF	EX_ADDR2,W
	BTFSC	STATUS,C
	 GOTO	SYSEX_UNMATCH_P2

	MOVLW	64			; PARAM1が64以上の時は63にセット。
	SUBWF	PARAM1,W
	MOVF	PARAM1,W
	BTFSC	STATUS,C
	 MOVLW	63
	MOVWF	TMP00

	MOVLW	LOW PART_BENDSENS
	ADDWF	EX_ADDR2,W		; パートの位置を計算する
	MOVWF	FSR
	BSF	STATUS,IRP		; ◆ IRP=1
	MOVLW	0xC0
	ANDWF	INDF,W
	ADDWF	TMP00,W
	MOVWF	INDF
	GOTO	SYSEX_SET_PCOMMON
;------------------------------------------------------------------------------
SYSEX_SET_ENVSHAPE			; F0 7D 01 1A [00-0F] [00-08] .. F7
	MOVLW	16			; 16バイト目以降は無視する
	SUBWF	EX_ADDR2,W
	BTFSC	STATUS,C
	 GOTO	SYSEX_UNMATCH_P2

	MOVLW	9			; PARAM1が9以上の時は0にセット。
	SUBWF	PARAM1,W
	BTFSC	STATUS,C
	 CLRF	PARAM1
	MOVF	PARAM1,W		; PARAM1が1以上の時は+7して8〜15に変更。
	BTFSS	STATUS,Z
	 ADDLW	7
	MOVWF	TMP00

	MOVLW	LOW PART_ENVSHAPE
	ADDWF	EX_ADDR2,W		; パートの位置を計算する
	MOVWF	FSR
	BSF	STATUS,IRP		; ◆ IRP=1
	MOVLW	0xE0
	ANDWF	INDF,F
	MOVF	TMP00,W
	BTFSS	STATUS,Z
	 BSF	INDF,PART_USEENV
	ADDWF	INDF,F
	GOTO	SYSEX_SET_PCOMMON
;------------------------------------------------------------------------------
SYSEX_TUNING_PART			; F0 7D 01 1B [00-0F] [00|01] .. F7
	MOVLW	16			; 16バイト目以降は無視する
	SUBWF	EX_ADDR2,W
	BTFSC	STATUS,C
	 GOTO	SYSEX_UNMATCH_P2

	MOVF	PARAM1,W		; 設定値が2以上の場合は値をセットせず次のアドレスへ進める
	SUBLW	1
	BTFSS	STATUS,C
	 GOTO	SYSEX_INC_RETURN_P2

	MOVLW	VOICE_PART		; VOICE_PARTにエクスクルーシブのアドレスを足して
	ADDWF	EX_ADDR2,W		; パートの位置を計算する
	MOVWF	FSR

	BSF	INDF,PART_TUNING	; PART_TUNING=1
	MOVF	PARAM1,W		; PARAM1が0の時は
	BTFSC	STATUS,Z
	 BCF	INDF,PART_TUNING	; PART_TUNING=0に変更
	GOTO	SYSEX_INC_RETURN_P2
;------------------------------------------------------------------------------
SYSEX_SAVEFMPROGRAM			; F0 7D 01 20 [00] [EX_DATA] [PARAM1] F7
	MOVF	EX_ADDR2,W		; ※次にEX_DATAを使うので、2バイトではなく1バイトと扱う
	BTFSS	STATUS,Z
	 GOTO	SYSEX_UNMATCH_P2

	BTFSC	EX_DATA,PARAM_NOTRCVD	; プログラム番号が来ていない場合はバックアップを実行してからもう一度ここへ来る
	 GOTO	SYSEX_DATABACKUP_P2

	MOVF	EX_DATA,W		; savefmprogram引数用ボイス番号
	MOVWF	VOICE
	SUBLW	2			; 指定されているボイス番号が3以上の場合は実行しない
	BTFSS	STATUS,C
	 GOTO	SYSEX_UNMATCH_P2

	MOVLW	120
	SUBWF	PARAM1,W		; プログラム番号が120未満の場合は実行しない
	BTFSS	STATUS,C
	 GOTO	SYSEX_UNMATCH_P2
					; W=savefmprogram引数用プログラム番号
	LCALL	savefmprogram		; ■ PCLATH
	GOTO	SYSEX_UNMATCH		; PCLATHを戻すステップがもったいないのでページ0へジャンプする(W:306)
;------------------------------------------------------------------------------
SYSEX_7X_SSG				; F0 7D 01 70-73 [00-0D] [ [EX_DATA] [PARAM1] ] .. F7
	BTFSC	EX_DATA,PARAM_NOTRCVD	; 1バイト目が来ていない場合はバックアップを実行してからもう一度ここへ来る
	 GOTO	SYSEX_DATABACKUP_P2
	
	MOVLW	0x70			; EX_ADDR1-0x70をして/CS/WRを決める
	SUBWF	EX_ADDR1,W
	MOVWF	WRITE_ADDR
	SWAPF	WRITE_ADDR,F
	
	MOVLW	0x0E			; 0x0E以上のアドレスは無効化し、SYSEX_7X_FMのように循環はさせない
	SUBWF	EX_ADDR2,W
	BTFSC	STATUS,C
	 GOTO	SYSEX_UNMATCH_P2

	MOVF	EX_ADDR2,W		; アドレスと/CSをマージ
	ANDLW	B'00001111'
	IORWF	WRITE_ADDR,F

	SWAPF	EX_DATA,W		; データの上位をロード
	ANDLW	0xF0
	MOVWF	WRITE_DATA
	MOVF	PARAM1,W
	ANDLW	0x0F
	IORWF	WRITE_DATA,F		; データの下位をロード
	LCALL	ssgwrite		; ■ PCLATH
	GOTO	SYSEX_INC_RETURN	; PCLATHを戻すステップがもったいないのでページ0へジャンプする(W:306)
;------------------------------------------------------------------------------
SYSEX_7X_FM				; F0 7D 01 74|75 [00-7F] [ [EX_DATA] [PARAM1] ] .. F7
	BTFSC	EX_DATA,PARAM_NOTRCVD	; 1バイト目が来ていない場合はバックアップを実行してからもう一度ここへ来る
	 GOTO	SYSEX_DATABACKUP_P2

	MOVLW	0x74			; EX_ADDR1が0x74の時は0、0x75の時は0x80をEX_ADDR2に足す
	SUBWF	EX_ADDR1,W
	MOVLW	0			; 74はアドレスが00-7Fで循環する
	BTFSS	STATUS,Z
	 MOVLW	0x80			; 75はアドレスが80-FFで循環する
	ADDWF	EX_ADDR2,W
	MOVWF	WRITE_ADDR

	MOVF	WRITE_ADDR,W		; 書き込んではいけないレジスタを除外する
	SUBLW	0x0D			; 0x00〜0x0Dのアドレスは有効
	BTFSC	STATUS,C
	 GOTO	SYSEX_7X_fmwrite

	MOVF	WRITE_ADDR,W
	SUBLW	0x23			; 0x0E〜0x23のアドレスはスキップ
	BTFSC	STATUS,C
	 GOTO	SYSEX_INC_RETURN_P2

	MOVF	WRITE_ADDR,W
	SUBLW	0x28			; 0x24〜0x28のアドレスは有効
	BTFSC	STATUS,C
	 GOTO	SYSEX_7X_fmwrite

	MOVF	WRITE_ADDR,W
	SUBLW	0x2F			; 0x29〜0x2Fのアドレスはスキップ
	BTFSC	STATUS,C
	 GOTO	SYSEX_INC_RETURN_P2

	MOVLW	0xB3			; 0xB3以上のアドレスはスキップ
	SUBWF	WRITE_ADDR,W
	BTFSC	STATUS,C
	 GOTO	SYSEX_INC_RETURN_P2

	COMF	WRITE_ADDR,W		; 0x30〜0xB2のアドレスで、なおかつ
	ANDLW	B'00000011'		; bit1,0が11の時(3,7,B,F)はスキップ
	BTFSC	STATUS,Z
	 GOTO	SYSEX_INC_RETURN_P2
SYSEX_7X_fmwrite
	SWAPF	EX_DATA,W		; データの上位をロード
	ANDLW	0xF0
	MOVWF	WRITE_DATA
	MOVF	PARAM1,W
	ANDLW	0x0F
	IORWF	WRITE_DATA,F		; データの下位をロード
	LCALL	fmwrite			; ■ PCLATH
	GOTO	SYSEX_INC_RETURN	; PCLATHを戻すステップがもったいないのでページ0へジャンプする(W:306)
;------------------------------------------------------------------------------
SYSEX_76				; F0 7D 01 76 [00] [PARAM1] .. F7
	MOVF	EX_ADDR2,W		; SYSEX_RETURNを使うのでアドレスがインクリメントされることは無いが、EX_ADDR2のチェックは行う。
	BTFSS	STATUS,Z
	 GOTO	SYSEX_UNMATCH_P2

	MOVF	PARAM1,W
	MOVWF	WRITE_DATA		; 0x76は発声FIFOに入れずに発声を行う
	LCALL	spwrite			; ■ PCLATH
	GOTO	SYSEX_RETURN		; PCLATHを戻すステップがもったいないのでページ0へジャンプする(W:306)
;------------------------------------------------------------------------------
SYSEX_77				; F0 7D 01 77 [00] [PARAM1] .. F7
	MOVF	EX_ADDR2,W		; SYSEX_RETURNを使うのでアドレスがインクリメントされることは無いが、EX_ADDR2のチェックは行う。
	BTFSS	STATUS,Z
	 GOTO	SYSEX_UNMATCH_P2

	MOVF	PARAM1,W		; 0x77は発声FIFOに入れ発声を行う
	LCALL	fifo2write		; ■ PCLATH
	GOTO	SYSEX_RETURN		; PCLATHを戻すステップがもったいないのでページ0へジャンプする(W:306)
;------------------------------------------------------------------------------
SYSEX_FMDUMP				; F0 7D 01 7D [00] [PARAM1] F7
	MOVF	EX_ADDR2,W
	BTFSS	STATUS,Z
	 GOTO	SYSEX_UNMATCH_P2

	MOVLW	3
	SUBWF	PARAM1,W		; ボイス番号が3以上の場合は実行しない
	BTFSC	STATUS,C
	 GOTO	SYSEX_UNMATCH_P2

	BCF	RCSTA,CREN		; 長時間発音するのでMIDIバッファがあふれるのを防ぐために受信停止

	RLF	PARAM1,W		; ボイス番号からRAMの開始アドレスを計算する
	MOVWF	TMP00
	RLF	TMP00,W
	ANDLW	0x0C
	ADDLW	LOW DT_MULTI
	MOVWF	TMP00

	MOVLW	4			; 4オペレータ分
	MOVWF	TMP01
SYSEX_FMDUMP_L1
	MOVLW	7			; 7パラメータ分
	MOVWF	TMP02
SYSEX_FMDUMP_L2
	BSF	STATUS,IRP		; ◆ IRP=1
	MOVF	TMP00,W
	MOVWF	FSR
	MOVF	INDF,W
	MOVWF	TMP03
	LCALL	sysex_dumpload		; ■ PCLATH
	LCALL	sysex_dumpout		; ■ PCLATH

	MOVLW	12			; 7パラメータ分
	ADDWF	TMP00,F
	DECFSZ	TMP02,F
	 GOTO	SYSEX_FMDUMP_L2

	MOVLW	12*7-1			; 4オペレータ分
	SUBWF	TMP00,F
	DECFSZ	TMP01,F
	 GOTO	SYSEX_FMDUMP_L1


	MOVF	PARAM1,W
	ADDLW	LOW FB_ALG
	MOVWF	TMP00

	MOVLW	2			; 2パラメータ分
	MOVWF	TMP01
SYSEX_FMDUMP_L3
	BSF	STATUS,IRP		; ◆ IRP=1
	MOVF	TMP00,W
	MOVWF	FSR
	MOVF	INDF,W
	MOVWF	TMP03
	LCALL	sysex_dumpload		; ■ PCLATH
	LCALL	sysex_dumpout		; ■ PCLATH

	MOVLW	SLOT-FB_ALG		; 2パラメータ分
	ADDWF	TMP00,F
	DECFSZ	TMP01,F
	 GOTO	SYSEX_FMDUMP_L3
	
	BSF	RCSTA,CREN		; 受信開始
	GOTO	SYSEX_UNMATCH_P2
;------------------------------------------------------------------------------
SYSEX_RAMDUMP				; F0 7D 01 7E [00-03] [EX_DATA] [PARAM1] F7
	MOVLW	4			; EX_ADDR2が4以上の時は無視する
	SUBWF	EX_ADDR2,W		; 
	BTFSC	STATUS,C
	 GOTO	SYSEX_UNMATCH_P2

	BTFSC	EX_DATA,PARAM_NOTRCVD	; 1バイト目が来ていない場合はバックアップを実行してからもう一度ここへ来る
	 GOTO	SYSEX_DATABACKUP_P2

	MOVF	PARAM1,W		; ダンプバイト数が0の時は実行しない
	BTFSC	STATUS,Z
	 GOTO	SYSEX_UNMATCH_P2

	BCF	RCSTA,CREN		; 長時間発音するのでMIDIバッファがあふれるのを防ぐために受信停止

	RLF	EX_DATA,F		; INDFアドレスをロードする
	RRF	EX_ADDR2,W
	RRF	EX_DATA,W
	MOVWF	TMP00

	MOVF	PARAM1,W		; ループカウンタ
	MOVWF	TMP01
SYSEX_RAMDUMP_L1
	BCF	STATUS,IRP		; ◆ IRP=0
	BTFSC	EX_ADDR2,1		; IRPビットをロードする
	 BSF	STATUS,IRP
	MOVF	TMP00,W
	MOVWF	FSR
	MOVF	INDF,W
	MOVWF	TMP03
	
	LCALL	sysex_dumpload		; ■ PCLATH
	LCALL	sysex_dumpout		; ■ PCLATH

	INCF	TMP00,F
	DECFSZ	TMP01,F
	 GOTO	SYSEX_RAMDUMP_L1
	BSF	RCSTA,CREN		; 受信開始
	GOTO	SYSEX_UNMATCH_P2
;------------------------------------------------------------------------------
SYSEX_PRESETDUMP			; F0 7D 01 7F [00] [PARAM1] F7
	MOVF	EX_ADDR2,W
	BTFSS	STATUS,Z
	 GOTO	SYSEX_UNMATCH_P2

	MOVLW	120
	SUBWF	PARAM1,W		; プログラム番号が120未満の場合は実行しない
	BTFSS	STATUS,C
	 GOTO	SYSEX_UNMATCH_P2

	BCF	RCSTA,CREN		; 長時間発音するのでMIDIバッファがあふれるのを防ぐために受信停止

	MOVWF	TMP00			; プログラム番号からEEPROMの開始アドレスを計算する
	RRF	TMP00,F
	RRF	TMP00,F
	RRF	TMP00,F
	RRF	TMP00,W
	ANDLW	0xE0
	MOVWF	EEPADDR

	MOVLW	30			; パラメータ30個分
	MOVWF	TMP01
SYSEX_PRESETDUMP_L1
	LCALL	eepread
	MOVWF	TMP03
	LCALL	sysex_dumpload		; ■ PCLATH
	LCALL	sysex_dumpout		; ■ PCLATH

	INCF	EEPADDR,F
	DECFSZ	TMP01,F
	 GOTO	SYSEX_PRESETDUMP_L1
	BSF	RCSTA,CREN		; 受信開始
	GOTO	SYSEX_UNMATCH_P2
;------------------------------------------------------------------------------
sysex_dumpload
	SWAPF	TMP03,W			; 上位4ビットロード
	ANDLW	0x0F
	LCALL	phraseload		; ■ PCLATH

	MOVF	TMP03,W			; 下位4ビットロード
	ANDLW	0x0F
	CALL	phraseload		; PCLATHは変更済み(W:306)

	MOVLW	PA5			; スペース
	CALL	fifo2write		; PCLATHは変更済み(W:306)
	RETURN
;------------------------------------------------------------------------------
sysex_dumpout				; ダンプ発声の共通部分
	BTFSC	PORTD,LRQ		; /LRQ=0になっている事を確認
	 GOTO	sysex_dumpout		; /LRQ=1の場合はSP0256が処理中のため、発声処理をスキップする終わるまで待つ

	LCALL	fifo2read		; ■ PCLATH SP0256発声バッファチェック
	MOVWF	WRITE_DATA
	MOVLW	HIGH $
	MOVWF	PCLATH			; ■ PCLATH
	BTFSC	FIFOSTATUS,FIFO2EMPTY
	 RETURN
	LCALL	spwrite			; ■ PCLATH 発声データが空になるまでspwriteをコール
	LGOTO	sysex_dumpout		; ■ PCLATH
;------------------------------------------------------------------------------
					; リターン用の処理はページ0と2で同じ物を用意しておく
SYSEX_DATABACKUP_P2			; 今回のPARAM1データをEX_DATAに送り、2バイトを1セットとして処理する
	MOVF	PARAM1,W		; アドレスはインクリメントしない
	MOVWF	EX_DATA
	GOTO	SYSEX_RETURN_P2
SYSEX_UNMATCH_P2			; PHASE_IGNOREをセットして戻る
	MOVLW	PHASE_IGNORE
	IORWF	FLAG1,F
	BCF	FLAG1,EX_PHASE4		; PHASE_RESETもクリアする
	GOTO	SYSEX_RETURN_P2
SYSEX_INC_RETURN_P2			; アドレスをインクリメントしてリターン
	INCF	EX_ADDR2,F
	BSF	EX_DATA,PARAM_NOTRCVD	; バックアップしたデータを無効化する
SYSEX_RETURN_P2				; アドレスをインクリメントせずにリターン
	BSF	PARAM1,PARAM_NOTRCVD	; PARAM1を無効にする
	LGOTO	EVENT_END

;------------------------------------------------------------------------------
; SYSEX_RESET メーカー別リセット検出ロジック
;------------------------------------------------------------------------------
SYSEX_RESET_P2
	MOVF	EX_ADDR2,W		; EX_ADDR2によってチェックする値を変更する
	MOVWF	TMP00
	MOVLW	LOW RESET_SEQUENCE_TABLE
	ADDWF	TMP00,F
	MOVLW	HIGH RESET_SEQUENCE_TABLE
	BTFSC	STATUS,C
	 ADDLW	1
	MOVWF	PCLATH
	MOVF	TMP00,W
	MOVWF	PCL
RESET_SEQUENCE_TABLE
	GOTO	RESEQ_42		; 0 Roland開始ポイント
	GOTO	RESEQ_12		; 1
	GOTO	RESEQ_40_BR_00		; 2 モードメッセージなら7へ分岐する
	GOTO	RESEQ_00		; 3
	GOTO	RESEQ_7F		; 4
	GOTO	RESEQ_00		; 5
	GOTO	RESEQ_EX_41		; 6 リセット実行
	GOTO	RESEQ_00		; 7
	GOTO	RESEQ_7F		; 8
	GOTO	RESEQ_00_BR_01		; 9 シングル/ダブルモードにより11へ分岐する
	GOTO	RESEQ_EX_01		; 10 リセット実行
	GOTO	RESEQ_EX_00		; 11 リセット実行
	GOTO	RESEQ_4C		; 12 Yamaha開始ポイント
	GOTO	RESEQ_00		; 13
	GOTO	RESEQ_00		; 14
	GOTO	RESEQ_7E		; 15
	GOTO	RESEQ_EX_00		; 16 リセット実行
	GOTO	RESEQ_09		; 17 GM開始ポイント
	GOTO	RESEQ_EX_01_02_03	; 18 リセット実行

RESEQ_00				; 値をチェック
	MOVLW	0x00
	GOTO	RESEQ_CHECK
RESEQ_09
	MOVLW	0x09
	GOTO	RESEQ_CHECK
RESEQ_12
	MOVLW	0x12
	GOTO	RESEQ_CHECK
RESEQ_42
	MOVLW	0x42
	GOTO	RESEQ_CHECK
RESEQ_4C
	MOVLW	0x4C
	GOTO	RESEQ_CHECK
RESEQ_7E
	MOVLW	0x7E
	GOTO	RESEQ_CHECK
RESEQ_7F
	MOVLW	0x7F
RESEQ_CHECK
	SUBWF	PARAM1,W
	BTFSC	STATUS,Z
	 GOTO	SYSEX_INC_RETURN_P2	; 一致しているならば、チェックアドレスをインクリメントする
	GOTO	SYSEX_UNMATCH_P2	; PARAM1と一致しないならば、PHASE_IGNOREでチェックを中断

RESEQ_40_BR_00				; 値をチェック、分岐
	MOVLW	0x40
	SUBWF	PARAM1,W
	BTFSC	STATUS,Z
	 GOTO	SYSEX_INC_RETURN_P2	; PARAM1が0x40なら次へ
	MOVLW	0x00
	SUBWF	PARAM1,W
	BTFSS	STATUS,Z
	 GOTO	SYSEX_UNMATCH_P2	; PARAM1が0x00と一致しない場合はPHASE_IGNOREでチェックを中断
	MOVLW	6
	MOVWF	EX_ADDR2		; 一致している場合は、現在を6として次に7が実行されるようにする。
	GOTO	SYSEX_INC_RETURN_P2

RESEQ_00_BR_01
	MOVLW	0x00
	SUBWF	PARAM1,W
	BTFSC	STATUS,Z
	 GOTO	SYSEX_INC_RETURN_P2	; PARAM1が0x00なら次へ
	MOVLW	0x01
	SUBWF	PARAM1,W
	BTFSS	STATUS,Z
	 GOTO	SYSEX_UNMATCH_P2	; PARAM1が0x01と一致しない場合はPHASE_IGNOREでチェックを中断
	MOVLW	10
	MOVWF	EX_ADDR2		; 一致している場合は、現在を10として次に11が実行されるようにする。
	GOTO	SYSEX_INC_RETURN_P2

RESEQ_EX_01_02_03			; 値をチェック、リセット
	MOVLW	0x01
	SUBWF	PARAM1,W
	BTFSC	STATUS,Z
	 GOTO	RESEQ_DO_RESET		; PARAM1が0x01ならリセット

	MOVLW	0x02
	SUBWF	PARAM1,W
	BTFSC	STATUS,Z
	 GOTO	RESEQ_DO_RESET		; PARAM1が0x02ならリセット

	MOVLW	0x03
	SUBWF	PARAM1,W
	BTFSC	STATUS,Z
	 GOTO	RESEQ_DO_RESET		; PARAM1が0x03ならリセット
	GOTO	SYSEX_UNMATCH_P2	; PARAM1と一致しないならば、PHASE_IGNOREでチェックを中断

RESEQ_EX_41				; 値をチェック、リセット
	MOVLW	0x41
	GOTO	RESEQ_EX_CHECK
RESEQ_EX_01
	MOVLW	0x01
	GOTO	RESEQ_EX_CHECK
RESEQ_EX_00
	MOVLW	0x00
RESEQ_EX_CHECK
	SUBWF	PARAM1,W
	BTFSS	STATUS,Z
	 GOTO	SYSEX_UNMATCH_P2	; PARAM1と一致しないならば、PHASE_IGNOREでチェックを中断
RESEQ_DO_RESET				; 一致しているならばリセット実行
	BCF	PFLAG,RESET_MODE	; 各社リセットの時は、モノモードでリセットを行う。
	LCALL	system_reset
	GOTO	SYSEX_RETURN		; PCLATHを戻すステップがもったいないのでページ0へジャンプする(W:306)
					; system_resetでフラグとEVENTがリセットされるのでPHASE_IGNOREに移行する必要はない。

;------------------------------------------------------------------------------
; ページ3
;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
; 音階データ 768ワード
; DAでプログラムメモリにデータを入れても、14ビットしか入らないことに注意
;------------------------------------------------------------------------------
	ORG	1400H
SSGTONE440
	DA	0x0EEE		; C1+0
	DA	0x0EEB		; C1+1
	DA	0x0EE7		; C1+2
	DA	0x0EE4		; C1+3
	DA	0x0EE0		; C1+4
	DA	0x0EDD		; C1+5
	DA	0x0EDA		; C1+6
	DA	0x0ED6		; C1+7
	DA	0x0ED3		; C1+8
	DA	0x0ECF		; C1+9
	DA	0x0ECC		; C1+10
	DA	0x0EC8		; C1+11
	DA	0x0EC5		; C1+12
	DA	0x0EC2		; C1+13
	DA	0x0EBE		; C1+14
	DA	0x0EBB		; C1+15
	DA	0x0EB7		; C1+16
	DA	0x0EB4		; C1+17
	DA	0x0EB1		; C1+18
	DA	0x0EAD		; C1+19
	DA	0x0EAA		; C1+20
	DA	0x0EA6		; C1+21
	DA	0x0EA3		; C1+22
	DA	0x0EA0		; C1+23
	DA	0x0E9C		; C1+24
	DA	0x0E99		; C1+25
	DA	0x0E96		; C1+26
	DA	0x0E92		; C1+27
	DA	0x0E8F		; C1+28
	DA	0x0E8C		; C1+29
	DA	0x0E88		; C1+30
	DA	0x0E85		; C1+31
	DA	0x0E81		; C1+32
	DA	0x0E7E		; C1+33
	DA	0x0E7B		; C1+34
	DA	0x0E77		; C1+35
	DA	0x0E74		; C1+36
	DA	0x0E71		; C1+37
	DA	0x0E6D		; C1+38
	DA	0x0E6A		; C1+39
	DA	0x0E67		; C1+40
	DA	0x0E63		; C1+41
	DA	0x0E60		; C1+42
	DA	0x0E5D		; C1+43
	DA	0x0E59		; C1+44
	DA	0x0E56		; C1+45
	DA	0x0E53		; C1+46
	DA	0x0E50		; C1+47
	DA	0x0E4C		; C1+48
	DA	0x0E49		; C1+49
	DA	0x0E46		; C1+50
	DA	0x0E42		; C1+51
	DA	0x0E3F		; C1+52
	DA	0x0E3C		; C1+53
	DA	0x0E38		; C1+54
	DA	0x0E35		; C1+55
	DA	0x0E32		; C1+56
	DA	0x0E2F		; C1+57
	DA	0x0E2B		; C1+58
	DA	0x0E28		; C1+59
	DA	0x0E25		; C1+60
	DA	0x0E22		; C1+61
	DA	0x0E1E		; C1+62
	DA	0x0E1B		; C1+63
	DA	0x0E18		; C#1+0
	DA	0x0E14		; C#1+1
	DA	0x0E11		; C#1+2
	DA	0x0E0E		; C#1+3
	DA	0x0E0B		; C#1+4
	DA	0x0E07		; C#1+5
	DA	0x0E04		; C#1+6
	DA	0x0E01		; C#1+7
	DA	0x0DFE		; C#1+8
	DA	0x0DFB		; C#1+9
	DA	0x0DF7		; C#1+10
	DA	0x0DF4		; C#1+11
	DA	0x0DF1		; C#1+12
	DA	0x0DEE		; C#1+13
	DA	0x0DEA		; C#1+14
	DA	0x0DE7		; C#1+15
	DA	0x0DE4		; C#1+16
	DA	0x0DE1		; C#1+17
	DA	0x0DDE		; C#1+18
	DA	0x0DDA		; C#1+19
	DA	0x0DD7		; C#1+20
	DA	0x0DD4		; C#1+21
	DA	0x0DD1		; C#1+22
	DA	0x0DCE		; C#1+23
	DA	0x0DCA		; C#1+24
	DA	0x0DC7		; C#1+25
	DA	0x0DC4		; C#1+26
	DA	0x0DC1		; C#1+27
	DA	0x0DBE		; C#1+28
	DA	0x0DBB		; C#1+29
	DA	0x0DB7		; C#1+30
	DA	0x0DB4		; C#1+31
	DA	0x0DB1		; C#1+32
	DA	0x0DAE		; C#1+33
	DA	0x0DAB		; C#1+34
	DA	0x0DA8		; C#1+35
	DA	0x0DA4		; C#1+36
	DA	0x0DA1		; C#1+37
	DA	0x0D9E		; C#1+38
	DA	0x0D9B		; C#1+39
	DA	0x0D98		; C#1+40
	DA	0x0D95		; C#1+41
	DA	0x0D92		; C#1+42
	DA	0x0D8E		; C#1+43
	DA	0x0D8B		; C#1+44
	DA	0x0D88		; C#1+45
	DA	0x0D85		; C#1+46
	DA	0x0D82		; C#1+47
	DA	0x0D7F		; C#1+48
	DA	0x0D7C		; C#1+49
	DA	0x0D79		; C#1+50
	DA	0x0D75		; C#1+51
	DA	0x0D72		; C#1+52
	DA	0x0D6F		; C#1+53
	DA	0x0D6C		; C#1+54
	DA	0x0D69		; C#1+55
	DA	0x0D66		; C#1+56
	DA	0x0D63		; C#1+57
	DA	0x0D60		; C#1+58
	DA	0x0D5D		; C#1+59
	DA	0x0D5A		; C#1+60
	DA	0x0D56		; C#1+61
	DA	0x0D53		; C#1+62
	DA	0x0D50		; C#1+63
	DA	0x0D4D		; D1+0
	DA	0x0D4A		; D1+1
	DA	0x0D47		; D1+2
	DA	0x0D44		; D1+3
	DA	0x0D41		; D1+4
	DA	0x0D3E		; D1+5
	DA	0x0D3B		; D1+6
	DA	0x0D38		; D1+7
	DA	0x0D35		; D1+8
	DA	0x0D32		; D1+9
	DA	0x0D2F		; D1+10
	DA	0x0D2C		; D1+11
	DA	0x0D29		; D1+12
	DA	0x0D26		; D1+13
	DA	0x0D22		; D1+14
	DA	0x0D1F		; D1+15
	DA	0x0D1C		; D1+16
	DA	0x0D19		; D1+17
	DA	0x0D16		; D1+18
	DA	0x0D13		; D1+19
	DA	0x0D10		; D1+20
	DA	0x0D0D		; D1+21
	DA	0x0D0A		; D1+22
	DA	0x0D07		; D1+23
	DA	0x0D04		; D1+24
	DA	0x0D01		; D1+25
	DA	0x0CFE		; D1+26
	DA	0x0CFB		; D1+27
	DA	0x0CF8		; D1+28
	DA	0x0CF5		; D1+29
	DA	0x0CF2		; D1+30
	DA	0x0CEF		; D1+31
	DA	0x0CEC		; D1+32
	DA	0x0CE9		; D1+33
	DA	0x0CE6		; D1+34
	DA	0x0CE3		; D1+35
	DA	0x0CE0		; D1+36
	DA	0x0CDD		; D1+37
	DA	0x0CDA		; D1+38
	DA	0x0CD7		; D1+39
	DA	0x0CD5		; D1+40
	DA	0x0CD2		; D1+41
	DA	0x0CCF		; D1+42
	DA	0x0CCC		; D1+43
	DA	0x0CC9		; D1+44
	DA	0x0CC6		; D1+45
	DA	0x0CC3		; D1+46
	DA	0x0CC0		; D1+47
	DA	0x0CBD		; D1+48
	DA	0x0CBA		; D1+49
	DA	0x0CB7		; D1+50
	DA	0x0CB4		; D1+51
	DA	0x0CB1		; D1+52
	DA	0x0CAE		; D1+53
	DA	0x0CAB		; D1+54
	DA	0x0CA8		; D1+55
	DA	0x0CA5		; D1+56
	DA	0x0CA2		; D1+57
	DA	0x0CA0		; D1+58
	DA	0x0C9D		; D1+59
	DA	0x0C9A		; D1+60
	DA	0x0C97		; D1+61
	DA	0x0C94		; D1+62
	DA	0x0C91		; D1+63
	DA	0x0C8E		; D#1+0
	DA	0x0C8B		; D#1+1
	DA	0x0C88		; D#1+2
	DA	0x0C85		; D#1+3
	DA	0x0C83		; D#1+4
	DA	0x0C80		; D#1+5
	DA	0x0C7D		; D#1+6
	DA	0x0C7A		; D#1+7
	DA	0x0C77		; D#1+8
	DA	0x0C74		; D#1+9
	DA	0x0C71		; D#1+10
	DA	0x0C6E		; D#1+11
	DA	0x0C6B		; D#1+12
	DA	0x0C69		; D#1+13
	DA	0x0C66		; D#1+14
	DA	0x0C63		; D#1+15
	DA	0x0C60		; D#1+16
	DA	0x0C5D		; D#1+17
	DA	0x0C5A		; D#1+18
	DA	0x0C57		; D#1+19
	DA	0x0C55		; D#1+20
	DA	0x0C52		; D#1+21
	DA	0x0C4F		; D#1+22
	DA	0x0C4C		; D#1+23
	DA	0x0C49		; D#1+24
	DA	0x0C46		; D#1+25
	DA	0x0C44		; D#1+26
	DA	0x0C41		; D#1+27
	DA	0x0C3E		; D#1+28
	DA	0x0C3B		; D#1+29
	DA	0x0C38		; D#1+30
	DA	0x0C35		; D#1+31
	DA	0x0C33		; D#1+32
	DA	0x0C30		; D#1+33
	DA	0x0C2D		; D#1+34
	DA	0x0C2A		; D#1+35
	DA	0x0C27		; D#1+36
	DA	0x0C25		; D#1+37
	DA	0x0C22		; D#1+38
	DA	0x0C1F		; D#1+39
	DA	0x0C1C		; D#1+40
	DA	0x0C19		; D#1+41
	DA	0x0C17		; D#1+42
	DA	0x0C14		; D#1+43
	DA	0x0C11		; D#1+44
	DA	0x0C0E		; D#1+45
	DA	0x0C0B		; D#1+46
	DA	0x0C09		; D#1+47
	DA	0x0C06		; D#1+48
	DA	0x0C03		; D#1+49
	DA	0x0C00		; D#1+50
	DA	0x0BFE		; D#1+51
	DA	0x0BFB		; D#1+52
	DA	0x0BF8		; D#1+53
	DA	0x0BF5		; D#1+54
	DA	0x0BF2		; D#1+55
	DA	0x0BF0		; D#1+56
	DA	0x0BED		; D#1+57
	DA	0x0BEA		; D#1+58
	DA	0x0BE7		; D#1+59
	DA	0x0BE5		; D#1+60
	DA	0x0BE2		; D#1+61
	DA	0x0BDF		; D#1+62
	DA	0x0BDC		; D#1+63
	DA	0x0BDA		; E1+0
	DA	0x0BD7		; E1+1
	DA	0x0BD4		; E1+2
	DA	0x0BD2		; E1+3
	DA	0x0BCF		; E1+4
	DA	0x0BCC		; E1+5
	DA	0x0BC9		; E1+6
	DA	0x0BC7		; E1+7
	DA	0x0BC4		; E1+8
	DA	0x0BC1		; E1+9
	DA	0x0BBE		; E1+10
	DA	0x0BBC		; E1+11
	DA	0x0BB9		; E1+12
	DA	0x0BB6		; E1+13
	DA	0x0BB4		; E1+14
	DA	0x0BB1		; E1+15
	DA	0x0BAE		; E1+16
	DA	0x0BAC		; E1+17
	DA	0x0BA9		; E1+18
	DA	0x0BA6		; E1+19
	DA	0x0BA3		; E1+20
	DA	0x0BA1		; E1+21
	DA	0x0B9E		; E1+22
	DA	0x0B9B		; E1+23
	DA	0x0B99		; E1+24
	DA	0x0B96		; E1+25
	DA	0x0B93		; E1+26
	DA	0x0B91		; E1+27
	DA	0x0B8E		; E1+28
	DA	0x0B8B		; E1+29
	DA	0x0B89		; E1+30
	DA	0x0B86		; E1+31
	DA	0x0B83		; E1+32
	DA	0x0B81		; E1+33
	DA	0x0B7E		; E1+34
	DA	0x0B7B		; E1+35
	DA	0x0B79		; E1+36
	DA	0x0B76		; E1+37
	DA	0x0B73		; E1+38
	DA	0x0B71		; E1+39
	DA	0x0B6E		; E1+40
	DA	0x0B6C		; E1+41
	DA	0x0B69		; E1+42
	DA	0x0B66		; E1+43
	DA	0x0B64		; E1+44
	DA	0x0B61		; E1+45
	DA	0x0B5E		; E1+46
	DA	0x0B5C		; E1+47
	DA	0x0B59		; E1+48
	DA	0x0B56		; E1+49
	DA	0x0B54		; E1+50
	DA	0x0B51		; E1+51
	DA	0x0B4F		; E1+52
	DA	0x0B4C		; E1+53
	DA	0x0B49		; E1+54
	DA	0x0B47		; E1+55
	DA	0x0B44		; E1+56
	DA	0x0B42		; E1+57
	DA	0x0B3F		; E1+58
	DA	0x0B3C		; E1+59
	DA	0x0B3A		; E1+60
	DA	0x0B37		; E1+61
	DA	0x0B35		; E1+62
	DA	0x0B32		; E1+63
	DA	0x0B2F		; F1+0
	DA	0x0B2D		; F1+1
	DA	0x0B2A		; F1+2
	DA	0x0B28		; F1+3
	DA	0x0B25		; F1+4
	DA	0x0B23		; F1+5
	DA	0x0B20		; F1+6
	DA	0x0B1D		; F1+7
	DA	0x0B1B		; F1+8
	DA	0x0B18		; F1+9
	DA	0x0B16		; F1+10
	DA	0x0B13		; F1+11
	DA	0x0B11		; F1+12
	DA	0x0B0E		; F1+13
	DA	0x0B0C		; F1+14
	DA	0x0B09		; F1+15
	DA	0x0B06		; F1+16
	DA	0x0B04		; F1+17
	DA	0x0B01		; F1+18
	DA	0x0AFF		; F1+19
	DA	0x0AFC		; F1+20
	DA	0x0AFA		; F1+21
	DA	0x0AF7		; F1+22
	DA	0x0AF5		; F1+23
	DA	0x0AF2		; F1+24
	DA	0x0AF0		; F1+25
	DA	0x0AED		; F1+26
	DA	0x0AEB		; F1+27
	DA	0x0AE8		; F1+28
	DA	0x0AE5		; F1+29
	DA	0x0AE3		; F1+30
	DA	0x0AE0		; F1+31
	DA	0x0ADE		; F1+32
	DA	0x0ADB		; F1+33
	DA	0x0AD9		; F1+34
	DA	0x0AD6		; F1+35
	DA	0x0AD4		; F1+36
	DA	0x0AD1		; F1+37
	DA	0x0ACF		; F1+38
	DA	0x0ACC		; F1+39
	DA	0x0ACA		; F1+40
	DA	0x0AC7		; F1+41
	DA	0x0AC5		; F1+42
	DA	0x0AC2		; F1+43
	DA	0x0AC0		; F1+44
	DA	0x0ABD		; F1+45
	DA	0x0ABB		; F1+46
	DA	0x0AB9		; F1+47
	DA	0x0AB6		; F1+48
	DA	0x0AB4		; F1+49
	DA	0x0AB1		; F1+50
	DA	0x0AAF		; F1+51
	DA	0x0AAC		; F1+52
	DA	0x0AAA		; F1+53
	DA	0x0AA7		; F1+54
	DA	0x0AA5		; F1+55
	DA	0x0AA2		; F1+56
	DA	0x0AA0		; F1+57
	DA	0x0A9D		; F1+58
	DA	0x0A9B		; F1+59
	DA	0x0A99		; F1+60
	DA	0x0A96		; F1+61
	DA	0x0A94		; F1+62
	DA	0x0A91		; F1+63
	DA	0x0A8F		; F#1+0
	DA	0x0A8C		; F#1+1
	DA	0x0A8A		; F#1+2
	DA	0x0A87		; F#1+3
	DA	0x0A85		; F#1+4
	DA	0x0A83		; F#1+5
	DA	0x0A80		; F#1+6
	DA	0x0A7E		; F#1+7
	DA	0x0A7B		; F#1+8
	DA	0x0A79		; F#1+9
	DA	0x0A76		; F#1+10
	DA	0x0A74		; F#1+11
	DA	0x0A72		; F#1+12
	DA	0x0A6F		; F#1+13
	DA	0x0A6D		; F#1+14
	DA	0x0A6A		; F#1+15
	DA	0x0A68		; F#1+16
	DA	0x0A66		; F#1+17
	DA	0x0A63		; F#1+18
	DA	0x0A61		; F#1+19
	DA	0x0A5E		; F#1+20
	DA	0x0A5C		; F#1+21
	DA	0x0A5A		; F#1+22
	DA	0x0A57		; F#1+23
	DA	0x0A55		; F#1+24
	DA	0x0A52		; F#1+25
	DA	0x0A50		; F#1+26
	DA	0x0A4E		; F#1+27
	DA	0x0A4B		; F#1+28
	DA	0x0A49		; F#1+29
	DA	0x0A47		; F#1+30
	DA	0x0A44		; F#1+31
	DA	0x0A42		; F#1+32
	DA	0x0A3F		; F#1+33
	DA	0x0A3D		; F#1+34
	DA	0x0A3B		; F#1+35
	DA	0x0A38		; F#1+36
	DA	0x0A36		; F#1+37
	DA	0x0A34		; F#1+38
	DA	0x0A31		; F#1+39
	DA	0x0A2F		; F#1+40
	DA	0x0A2D		; F#1+41
	DA	0x0A2A		; F#1+42
	DA	0x0A28		; F#1+43
	DA	0x0A26		; F#1+44
	DA	0x0A23		; F#1+45
	DA	0x0A21		; F#1+46
	DA	0x0A1E		; F#1+47
	DA	0x0A1C		; F#1+48
	DA	0x0A1A		; F#1+49
	DA	0x0A17		; F#1+50
	DA	0x0A15		; F#1+51
	DA	0x0A13		; F#1+52
	DA	0x0A11		; F#1+53
	DA	0x0A0E		; F#1+54
	DA	0x0A0C		; F#1+55
	DA	0x0A0A		; F#1+56
	DA	0x0A07		; F#1+57
	DA	0x0A05		; F#1+58
	DA	0x0A03		; F#1+59
	DA	0x0A00		; F#1+60
	DA	0x09FE		; F#1+61
	DA	0x09FC		; F#1+62
	DA	0x09F9		; F#1+63
	DA	0x09F7		; G1+0
	DA	0x09F5		; G1+1
	DA	0x09F2		; G1+2
	DA	0x09F0		; G1+3
	DA	0x09EE		; G1+4
	DA	0x09EC		; G1+5
	DA	0x09E9		; G1+6
	DA	0x09E7		; G1+7
	DA	0x09E5		; G1+8
	DA	0x09E2		; G1+9
	DA	0x09E0		; G1+10
	DA	0x09DE		; G1+11
	DA	0x09DC		; G1+12
	DA	0x09D9		; G1+13
	DA	0x09D7		; G1+14
	DA	0x09D5		; G1+15
	DA	0x09D2		; G1+16
	DA	0x09D0		; G1+17
	DA	0x09CE		; G1+18
	DA	0x09CC		; G1+19
	DA	0x09C9		; G1+20
	DA	0x09C7		; G1+21
	DA	0x09C5		; G1+22
	DA	0x09C3		; G1+23
	DA	0x09C0		; G1+24
	DA	0x09BE		; G1+25
	DA	0x09BC		; G1+26
	DA	0x09BA		; G1+27
	DA	0x09B7		; G1+28
	DA	0x09B5		; G1+29
	DA	0x09B3		; G1+30
	DA	0x09B1		; G1+31
	DA	0x09AE		; G1+32
	DA	0x09AC		; G1+33
	DA	0x09AA		; G1+34
	DA	0x09A8		; G1+35
	DA	0x09A5		; G1+36
	DA	0x09A3		; G1+37
	DA	0x09A1		; G1+38
	DA	0x099F		; G1+39
	DA	0x099D		; G1+40
	DA	0x099A		; G1+41
	DA	0x0998		; G1+42
	DA	0x0996		; G1+43
	DA	0x0994		; G1+44
	DA	0x0992		; G1+45
	DA	0x098F		; G1+46
	DA	0x098D		; G1+47
	DA	0x098B		; G1+48
	DA	0x0989		; G1+49
	DA	0x0986		; G1+50
	DA	0x0984		; G1+51
	DA	0x0982		; G1+52
	DA	0x0980		; G1+53
	DA	0x097E		; G1+54
	DA	0x097C		; G1+55
	DA	0x0979		; G1+56
	DA	0x0977		; G1+57
	DA	0x0975		; G1+58
	DA	0x0973		; G1+59
	DA	0x0971		; G1+60
	DA	0x096E		; G1+61
	DA	0x096C		; G1+62
	DA	0x096A		; G1+63
	DA	0x0968		; G#1+0
	DA	0x0966		; G#1+1
	DA	0x0964		; G#1+2
	DA	0x0961		; G#1+3
	DA	0x095F		; G#1+4
	DA	0x095D		; G#1+5
	DA	0x095B		; G#1+6
	DA	0x0959		; G#1+7
	DA	0x0957		; G#1+8
	DA	0x0954		; G#1+9
	DA	0x0952		; G#1+10
	DA	0x0950		; G#1+11
	DA	0x094E		; G#1+12
	DA	0x094C		; G#1+13
	DA	0x094A		; G#1+14
	DA	0x0947		; G#1+15
	DA	0x0945		; G#1+16
	DA	0x0943		; G#1+17
	DA	0x0941		; G#1+18
	DA	0x093F		; G#1+19
	DA	0x093D		; G#1+20
	DA	0x093B		; G#1+21
	DA	0x0939		; G#1+22
	DA	0x0936		; G#1+23
	DA	0x0934		; G#1+24
	DA	0x0932		; G#1+25
	DA	0x0930		; G#1+26
	DA	0x092E		; G#1+27
	DA	0x092C		; G#1+28
	DA	0x092A		; G#1+29
	DA	0x0928		; G#1+30
	DA	0x0925		; G#1+31
	DA	0x0923		; G#1+32
	DA	0x0921		; G#1+33
	DA	0x091F		; G#1+34
	DA	0x091D		; G#1+35
	DA	0x091B		; G#1+36
	DA	0x0919		; G#1+37
	DA	0x0917		; G#1+38
	DA	0x0915		; G#1+39
	DA	0x0912		; G#1+40
	DA	0x0910		; G#1+41
	DA	0x090E		; G#1+42
	DA	0x090C		; G#1+43
	DA	0x090A		; G#1+44
	DA	0x0908		; G#1+45
	DA	0x0906		; G#1+46
	DA	0x0904		; G#1+47
	DA	0x0902		; G#1+48
	DA	0x0900		; G#1+49
	DA	0x08FE		; G#1+50
	DA	0x08FC		; G#1+51
	DA	0x08F9		; G#1+52
	DA	0x08F7		; G#1+53
	DA	0x08F5		; G#1+54
	DA	0x08F3		; G#1+55
	DA	0x08F1		; G#1+56
	DA	0x08EF		; G#1+57
	DA	0x08ED		; G#1+58
	DA	0x08EB		; G#1+59
	DA	0x08E9		; G#1+60
	DA	0x08E7		; G#1+61
	DA	0x08E5		; G#1+62
	DA	0x08E3		; G#1+63
	DA	0x08E1		; A2+0 440Hz
	DA	0x08DF		; A2+1
	DA	0x08DD		; A2+2
	DA	0x08DB		; A2+3
	DA	0x08D9		; A2+4
	DA	0x08D6		; A2+5
	DA	0x08D4		; A2+6
	DA	0x08D2		; A2+7
	DA	0x08D0		; A2+8
	DA	0x08CE		; A2+9
	DA	0x08CC		; A2+10
	DA	0x08CA		; A2+11
	DA	0x08C8		; A2+12
	DA	0x08C6		; A2+13
	DA	0x08C4		; A2+14
	DA	0x08C2		; A2+15
	DA	0x08C0		; A2+16
	DA	0x08BE		; A2+17
	DA	0x08BC		; A2+18
	DA	0x08BA		; A2+19
	DA	0x08B8		; A2+20
	DA	0x08B6		; A2+21
	DA	0x08B4		; A2+22
	DA	0x08B2		; A2+23
	DA	0x08B0		; A2+24
	DA	0x08AE		; A2+25
	DA	0x08AC		; A2+26
	DA	0x08AA		; A2+27
	DA	0x08A8		; A2+28
	DA	0x08A6		; A2+29
	DA	0x08A4		; A2+30
	DA	0x08A2		; A2+31
	DA	0x08A0		; A2+32
	DA	0x089E		; A2+33
	DA	0x089C		; A2+34
	DA	0x089A		; A2+35
	DA	0x0898		; A2+36
	DA	0x0896		; A2+37
	DA	0x0894		; A2+38
	DA	0x0892		; A2+39
	DA	0x0890		; A2+40
	DA	0x088E		; A2+41
	DA	0x088C		; A2+42
	DA	0x088A		; A2+43
	DA	0x0888		; A2+44
	DA	0x0886		; A2+45
	DA	0x0884		; A2+46
	DA	0x0882		; A2+47
	DA	0x0880		; A2+48
	DA	0x087E		; A2+49
	DA	0x087C		; A2+50
	DA	0x087A		; A2+51
	DA	0x0879		; A2+52
	DA	0x0877		; A2+53
	DA	0x0875		; A2+54
	DA	0x0873		; A2+55
	DA	0x0871		; A2+56
	DA	0x086F		; A2+57
	DA	0x086D		; A2+58
	DA	0x086B		; A2+59
	DA	0x0869		; A2+60
	DA	0x0867		; A2+61
	DA	0x0865		; A2+62
	DA	0x0863		; A2+63
	DA	0x0861		; A#2+0
	DA	0x085F		; A#2+1
	DA	0x085D		; A#2+2
	DA	0x085B		; A#2+3
	DA	0x0859		; A#2+4
	DA	0x0858		; A#2+5
	DA	0x0856		; A#2+6
	DA	0x0854		; A#2+7
	DA	0x0852		; A#2+8
	DA	0x0850		; A#2+9
	DA	0x084E		; A#2+10
	DA	0x084C		; A#2+11
	DA	0x084A		; A#2+12
	DA	0x0848		; A#2+13
	DA	0x0846		; A#2+14
	DA	0x0844		; A#2+15
	DA	0x0842		; A#2+16
	DA	0x0841		; A#2+17
	DA	0x083F		; A#2+18
	DA	0x083D		; A#2+19
	DA	0x083B		; A#2+20
	DA	0x0839		; A#2+21
	DA	0x0837		; A#2+22
	DA	0x0835		; A#2+23
	DA	0x0833		; A#2+24
	DA	0x0831		; A#2+25
	DA	0x082F		; A#2+26
	DA	0x082E		; A#2+27
	DA	0x082C		; A#2+28
	DA	0x082A		; A#2+29
	DA	0x0828		; A#2+30
	DA	0x0826		; A#2+31
	DA	0x0824		; A#2+32
	DA	0x0822		; A#2+33
	DA	0x0820		; A#2+34
	DA	0x081E		; A#2+35
	DA	0x081D		; A#2+36
	DA	0x081B		; A#2+37
	DA	0x0819		; A#2+38
	DA	0x0817		; A#2+39
	DA	0x0815		; A#2+40
	DA	0x0813		; A#2+41
	DA	0x0811		; A#2+42
	DA	0x0810		; A#2+43
	DA	0x080E		; A#2+44
	DA	0x080C		; A#2+45
	DA	0x080A		; A#2+46
	DA	0x0808		; A#2+47
	DA	0x0806		; A#2+48
	DA	0x0804		; A#2+49
	DA	0x0803		; A#2+50
	DA	0x0801		; A#2+51
	DA	0x07FF		; A#2+52
	DA	0x07FD		; A#2+53
	DA	0x07FB		; A#2+54
	DA	0x07F9		; A#2+55
	DA	0x07F7		; A#2+56
	DA	0x07F6		; A#2+57
	DA	0x07F4		; A#2+58
	DA	0x07F2		; A#2+59
	DA	0x07F0		; A#2+60
	DA	0x07EE		; A#2+61
	DA	0x07EC		; A#2+62
	DA	0x07EB		; A#2+63
	DA	0x07E9		; B2+0
	DA	0x07E7		; B2+1
	DA	0x07E5		; B2+2
	DA	0x07E3		; B2+3
	DA	0x07E1		; B2+4
	DA	0x07E0		; B2+5
	DA	0x07DE		; B2+6
	DA	0x07DC		; B2+7
	DA	0x07DA		; B2+8
	DA	0x07D8		; B2+9
	DA	0x07D7		; B2+10
	DA	0x07D5		; B2+11
	DA	0x07D3		; B2+12
	DA	0x07D1		; B2+13
	DA	0x07CF		; B2+14
	DA	0x07CE		; B2+15
	DA	0x07CC		; B2+16
	DA	0x07CA		; B2+17
	DA	0x07C8		; B2+18
	DA	0x07C6		; B2+19
	DA	0x07C5		; B2+20
	DA	0x07C3		; B2+21
	DA	0x07C1		; B2+22
	DA	0x07BF		; B2+23
	DA	0x07BD		; B2+24
	DA	0x07BC		; B2+25
	DA	0x07BA		; B2+26
	DA	0x07B8		; B2+27
	DA	0x07B6		; B2+28
	DA	0x07B4		; B2+29
	DA	0x07B3		; B2+30
	DA	0x07B1		; B2+31
	DA	0x07AF		; B2+32
	DA	0x07AD		; B2+33
	DA	0x07AC		; B2+34
	DA	0x07AA		; B2+35
	DA	0x07A8		; B2+36
	DA	0x07A6		; B2+37
	DA	0x07A5		; B2+38
	DA	0x07A3		; B2+39
	DA	0x07A1		; B2+40
	DA	0x079F		; B2+41
	DA	0x079D		; B2+42
	DA	0x079C		; B2+43
	DA	0x079A		; B2+44
	DA	0x0798		; B2+45
	DA	0x0796		; B2+46
	DA	0x0795		; B2+47
	DA	0x0793		; B2+48
	DA	0x0791		; B2+49
	DA	0x078F		; B2+50
	DA	0x078E		; B2+51
	DA	0x078C		; B2+52
	DA	0x078A		; B2+53
	DA	0x0788		; B2+54
	DA	0x0787		; B2+55
	DA	0x0785		; B2+56
	DA	0x0783		; B2+57
	DA	0x0782		; B2+58
	DA	0x0780		; B2+59
	DA	0x077E		; B2+60
	DA	0x077C		; B2+61
	DA	0x077B		; B2+62
	DA	0x0779		; B2+63

SSGTONE444
	DA	0x0ECC		; C1+0
	DA	0x0EC8		; C1+1
	DA	0x0EC5		; C1+2
	DA	0x0EC2		; C1+3
	DA	0x0EBE		; C1+4
	DA	0x0EBB		; C1+5
	DA	0x0EB7		; C1+6
	DA	0x0EB4		; C1+7
	DA	0x0EB1		; C1+8
	DA	0x0EAD		; C1+9
	DA	0x0EAA		; C1+10
	DA	0x0EA6		; C1+11
	DA	0x0EA3		; C1+12
	DA	0x0EA0		; C1+13
	DA	0x0E9C		; C1+14
	DA	0x0E99		; C1+15
	DA	0x0E96		; C1+16
	DA	0x0E92		; C1+17
	DA	0x0E8F		; C1+18
	DA	0x0E8B		; C1+19
	DA	0x0E88		; C1+20
	DA	0x0E85		; C1+21
	DA	0x0E81		; C1+22
	DA	0x0E7E		; C1+23
	DA	0x0E7B		; C1+24
	DA	0x0E77		; C1+25
	DA	0x0E74		; C1+26
	DA	0x0E71		; C1+27
	DA	0x0E6D		; C1+28
	DA	0x0E6A		; C1+29
	DA	0x0E67		; C1+30
	DA	0x0E63		; C1+31
	DA	0x0E60		; C1+32
	DA	0x0E5D		; C1+33
	DA	0x0E59		; C1+34
	DA	0x0E56		; C1+35
	DA	0x0E53		; C1+36
	DA	0x0E4F		; C1+37
	DA	0x0E4C		; C1+38
	DA	0x0E49		; C1+39
	DA	0x0E46		; C1+40
	DA	0x0E42		; C1+41
	DA	0x0E3F		; C1+42
	DA	0x0E3C		; C1+43
	DA	0x0E38		; C1+44
	DA	0x0E35		; C1+45
	DA	0x0E32		; C1+46
	DA	0x0E2F		; C1+47
	DA	0x0E2B		; C1+48
	DA	0x0E28		; C1+49
	DA	0x0E25		; C1+50
	DA	0x0E21		; C1+51
	DA	0x0E1E		; C1+52
	DA	0x0E1B		; C1+53
	DA	0x0E18		; C1+54
	DA	0x0E14		; C1+55
	DA	0x0E11		; C1+56
	DA	0x0E0E		; C1+57
	DA	0x0E0B		; C1+58
	DA	0x0E07		; C1+59
	DA	0x0E04		; C1+60
	DA	0x0E01		; C1+61
	DA	0x0DFE		; C1+62
	DA	0x0DFA		; C1+63
	DA	0x0DF7		; C#1+0
	DA	0x0DF4		; C#1+1
	DA	0x0DF1		; C#1+2
	DA	0x0DEE		; C#1+3
	DA	0x0DEA		; C#1+4
	DA	0x0DE7		; C#1+5
	DA	0x0DE4		; C#1+6
	DA	0x0DE1		; C#1+7
	DA	0x0DDE		; C#1+8
	DA	0x0DDA		; C#1+9
	DA	0x0DD7		; C#1+10
	DA	0x0DD4		; C#1+11
	DA	0x0DD1		; C#1+12
	DA	0x0DCE		; C#1+13
	DA	0x0DCA		; C#1+14
	DA	0x0DC7		; C#1+15
	DA	0x0DC4		; C#1+16
	DA	0x0DC1		; C#1+17
	DA	0x0DBE		; C#1+18
	DA	0x0DBA		; C#1+19
	DA	0x0DB7		; C#1+20
	DA	0x0DB4		; C#1+21
	DA	0x0DB1		; C#1+22
	DA	0x0DAE		; C#1+23
	DA	0x0DAB		; C#1+24
	DA	0x0DA7		; C#1+25
	DA	0x0DA4		; C#1+26
	DA	0x0DA1		; C#1+27
	DA	0x0D9E		; C#1+28
	DA	0x0D9B		; C#1+29
	DA	0x0D98		; C#1+30
	DA	0x0D95		; C#1+31
	DA	0x0D91		; C#1+32
	DA	0x0D8E		; C#1+33
	DA	0x0D8B		; C#1+34
	DA	0x0D88		; C#1+35
	DA	0x0D85		; C#1+36
	DA	0x0D82		; C#1+37
	DA	0x0D7F		; C#1+38
	DA	0x0D7C		; C#1+39
	DA	0x0D78		; C#1+40
	DA	0x0D75		; C#1+41
	DA	0x0D72		; C#1+42
	DA	0x0D6F		; C#1+43
	DA	0x0D6C		; C#1+44
	DA	0x0D69		; C#1+45
	DA	0x0D66		; C#1+46
	DA	0x0D63		; C#1+47
	DA	0x0D60		; C#1+48
	DA	0x0D5D		; C#1+49
	DA	0x0D59		; C#1+50
	DA	0x0D56		; C#1+51
	DA	0x0D53		; C#1+52
	DA	0x0D50		; C#1+53
	DA	0x0D4D		; C#1+54
	DA	0x0D4A		; C#1+55
	DA	0x0D47		; C#1+56
	DA	0x0D44		; C#1+57
	DA	0x0D41		; C#1+58
	DA	0x0D3E		; C#1+59
	DA	0x0D3B		; C#1+60
	DA	0x0D38		; C#1+61
	DA	0x0D35		; C#1+62
	DA	0x0D32		; C#1+63
	DA	0x0D2F		; D1+0
	DA	0x0D2C		; D1+1
	DA	0x0D28		; D1+2
	DA	0x0D25		; D1+3
	DA	0x0D22		; D1+4
	DA	0x0D1F		; D1+5
	DA	0x0D1C		; D1+6
	DA	0x0D19		; D1+7
	DA	0x0D16		; D1+8
	DA	0x0D13		; D1+9
	DA	0x0D10		; D1+10
	DA	0x0D0D		; D1+11
	DA	0x0D0A		; D1+12
	DA	0x0D07		; D1+13
	DA	0x0D04		; D1+14
	DA	0x0D01		; D1+15
	DA	0x0CFE		; D1+16
	DA	0x0CFB		; D1+17
	DA	0x0CF8		; D1+18
	DA	0x0CF5		; D1+19
	DA	0x0CF2		; D1+20
	DA	0x0CEF		; D1+21
	DA	0x0CEC		; D1+22
	DA	0x0CE9		; D1+23
	DA	0x0CE6		; D1+24
	DA	0x0CE3		; D1+25
	DA	0x0CE0		; D1+26
	DA	0x0CDD		; D1+27
	DA	0x0CDA		; D1+28
	DA	0x0CD7		; D1+29
	DA	0x0CD4		; D1+30
	DA	0x0CD1		; D1+31
	DA	0x0CCE		; D1+32
	DA	0x0CCC		; D1+33
	DA	0x0CC9		; D1+34
	DA	0x0CC6		; D1+35
	DA	0x0CC3		; D1+36
	DA	0x0CC0		; D1+37
	DA	0x0CBD		; D1+38
	DA	0x0CBA		; D1+39
	DA	0x0CB7		; D1+40
	DA	0x0CB4		; D1+41
	DA	0x0CB1		; D1+42
	DA	0x0CAE		; D1+43
	DA	0x0CAB		; D1+44
	DA	0x0CA8		; D1+45
	DA	0x0CA5		; D1+46
	DA	0x0CA2		; D1+47
	DA	0x0C9F		; D1+48
	DA	0x0C9D		; D1+49
	DA	0x0C9A		; D1+50
	DA	0x0C97		; D1+51
	DA	0x0C94		; D1+52
	DA	0x0C91		; D1+53
	DA	0x0C8E		; D1+54
	DA	0x0C8B		; D1+55
	DA	0x0C88		; D1+56
	DA	0x0C85		; D1+57
	DA	0x0C82		; D1+58
	DA	0x0C80		; D1+59
	DA	0x0C7D		; D1+60
	DA	0x0C7A		; D1+61
	DA	0x0C77		; D1+62
	DA	0x0C74		; D1+63
	DA	0x0C71		; D#1+0
	DA	0x0C6E		; D#1+1
	DA	0x0C6B		; D#1+2
	DA	0x0C69		; D#1+3
	DA	0x0C66		; D#1+4
	DA	0x0C63		; D#1+5
	DA	0x0C60		; D#1+6
	DA	0x0C5D		; D#1+7
	DA	0x0C5A		; D#1+8
	DA	0x0C57		; D#1+9
	DA	0x0C55		; D#1+10
	DA	0x0C52		; D#1+11
	DA	0x0C4F		; D#1+12
	DA	0x0C4C		; D#1+13
	DA	0x0C49		; D#1+14
	DA	0x0C46		; D#1+15
	DA	0x0C44		; D#1+16
	DA	0x0C41		; D#1+17
	DA	0x0C3E		; D#1+18
	DA	0x0C3B		; D#1+19
	DA	0x0C38		; D#1+20
	DA	0x0C35		; D#1+21
	DA	0x0C33		; D#1+22
	DA	0x0C30		; D#1+23
	DA	0x0C2D		; D#1+24
	DA	0x0C2A		; D#1+25
	DA	0x0C27		; D#1+26
	DA	0x0C24		; D#1+27
	DA	0x0C22		; D#1+28
	DA	0x0C1F		; D#1+29
	DA	0x0C1C		; D#1+30
	DA	0x0C19		; D#1+31
	DA	0x0C16		; D#1+32
	DA	0x0C14		; D#1+33
	DA	0x0C11		; D#1+34
	DA	0x0C0E		; D#1+35
	DA	0x0C0B		; D#1+36
	DA	0x0C09		; D#1+37
	DA	0x0C06		; D#1+38
	DA	0x0C03		; D#1+39
	DA	0x0C00		; D#1+40
	DA	0x0BFD		; D#1+41
	DA	0x0BFB		; D#1+42
	DA	0x0BF8		; D#1+43
	DA	0x0BF5		; D#1+44
	DA	0x0BF2		; D#1+45
	DA	0x0BF0		; D#1+46
	DA	0x0BED		; D#1+47
	DA	0x0BEA		; D#1+48
	DA	0x0BE7		; D#1+49
	DA	0x0BE5		; D#1+50
	DA	0x0BE2		; D#1+51
	DA	0x0BDF		; D#1+52
	DA	0x0BDC		; D#1+53
	DA	0x0BDA		; D#1+54
	DA	0x0BD7		; D#1+55
	DA	0x0BD4		; D#1+56
	DA	0x0BD1		; D#1+57
	DA	0x0BCF		; D#1+58
	DA	0x0BCC		; D#1+59
	DA	0x0BC9		; D#1+60
	DA	0x0BC7		; D#1+61
	DA	0x0BC4		; D#1+62
	DA	0x0BC1		; D#1+63
	DA	0x0BBE		; E1+0
	DA	0x0BBC		; E1+1
	DA	0x0BB9		; E1+2
	DA	0x0BB6		; E1+3
	DA	0x0BB4		; E1+4
	DA	0x0BB1		; E1+5
	DA	0x0BAE		; E1+6
	DA	0x0BAB		; E1+7
	DA	0x0BA9		; E1+8
	DA	0x0BA6		; E1+9
	DA	0x0BA3		; E1+10
	DA	0x0BA1		; E1+11
	DA	0x0B9E		; E1+12
	DA	0x0B9B		; E1+13
	DA	0x0B99		; E1+14
	DA	0x0B96		; E1+15
	DA	0x0B93		; E1+16
	DA	0x0B91		; E1+17
	DA	0x0B8E		; E1+18
	DA	0x0B8B		; E1+19
	DA	0x0B89		; E1+20
	DA	0x0B86		; E1+21
	DA	0x0B83		; E1+22
	DA	0x0B81		; E1+23
	DA	0x0B7E		; E1+24
	DA	0x0B7B		; E1+25
	DA	0x0B79		; E1+26
	DA	0x0B76		; E1+27
	DA	0x0B73		; E1+28
	DA	0x0B71		; E1+29
	DA	0x0B6E		; E1+30
	DA	0x0B6B		; E1+31
	DA	0x0B69		; E1+32
	DA	0x0B66		; E1+33
	DA	0x0B64		; E1+34
	DA	0x0B61		; E1+35
	DA	0x0B5E		; E1+36
	DA	0x0B5C		; E1+37
	DA	0x0B59		; E1+38
	DA	0x0B56		; E1+39
	DA	0x0B54		; E1+40
	DA	0x0B51		; E1+41
	DA	0x0B4F		; E1+42
	DA	0x0B4C		; E1+43
	DA	0x0B49		; E1+44
	DA	0x0B47		; E1+45
	DA	0x0B44		; E1+46
	DA	0x0B42		; E1+47
	DA	0x0B3F		; E1+48
	DA	0x0B3C		; E1+49
	DA	0x0B3A		; E1+50
	DA	0x0B37		; E1+51
	DA	0x0B35		; E1+52
	DA	0x0B32		; E1+53
	DA	0x0B2F		; E1+54
	DA	0x0B2D		; E1+55
	DA	0x0B2A		; E1+56
	DA	0x0B28		; E1+57
	DA	0x0B25		; E1+58
	DA	0x0B22		; E1+59
	DA	0x0B20		; E1+60
	DA	0x0B1D		; E1+61
	DA	0x0B1B		; E1+62
	DA	0x0B18		; E1+63
	DA	0x0B16		; F1+0
	DA	0x0B13		; F1+1
	DA	0x0B11		; F1+2
	DA	0x0B0E		; F1+3
	DA	0x0B0B		; F1+4
	DA	0x0B09		; F1+5
	DA	0x0B06		; F1+6
	DA	0x0B04		; F1+7
	DA	0x0B01		; F1+8
	DA	0x0AFF		; F1+9
	DA	0x0AFC		; F1+10
	DA	0x0AFA		; F1+11
	DA	0x0AF7		; F1+12
	DA	0x0AF5		; F1+13
	DA	0x0AF2		; F1+14
	DA	0x0AF0		; F1+15
	DA	0x0AED		; F1+16
	DA	0x0AEA		; F1+17
	DA	0x0AE8		; F1+18
	DA	0x0AE5		; F1+19
	DA	0x0AE3		; F1+20
	DA	0x0AE0		; F1+21
	DA	0x0ADE		; F1+22
	DA	0x0ADB		; F1+23
	DA	0x0AD9		; F1+24
	DA	0x0AD6		; F1+25
	DA	0x0AD4		; F1+26
	DA	0x0AD1		; F1+27
	DA	0x0ACF		; F1+28
	DA	0x0ACC		; F1+29
	DA	0x0ACA		; F1+30
	DA	0x0AC7		; F1+31
	DA	0x0AC5		; F1+32
	DA	0x0AC2		; F1+33
	DA	0x0AC0		; F1+34
	DA	0x0ABD		; F1+35
	DA	0x0ABB		; F1+36
	DA	0x0AB8		; F1+37
	DA	0x0AB6		; F1+38
	DA	0x0AB4		; F1+39
	DA	0x0AB1		; F1+40
	DA	0x0AAF		; F1+41
	DA	0x0AAC		; F1+42
	DA	0x0AAA		; F1+43
	DA	0x0AA7		; F1+44
	DA	0x0AA5		; F1+45
	DA	0x0AA2		; F1+46
	DA	0x0AA0		; F1+47
	DA	0x0A9D		; F1+48
	DA	0x0A9B		; F1+49
	DA	0x0A98		; F1+50
	DA	0x0A96		; F1+51
	DA	0x0A94		; F1+52
	DA	0x0A91		; F1+53
	DA	0x0A8F		; F1+54
	DA	0x0A8C		; F1+55
	DA	0x0A8A		; F1+56
	DA	0x0A87		; F1+57
	DA	0x0A85		; F1+58
	DA	0x0A83		; F1+59
	DA	0x0A80		; F1+60
	DA	0x0A7E		; F1+61
	DA	0x0A7B		; F1+62
	DA	0x0A79		; F1+63
	DA	0x0A76		; F#1+0
	DA	0x0A74		; F#1+1
	DA	0x0A72		; F#1+2
	DA	0x0A6F		; F#1+3
	DA	0x0A6D		; F#1+4
	DA	0x0A6A		; F#1+5
	DA	0x0A68		; F#1+6
	DA	0x0A66		; F#1+7
	DA	0x0A63		; F#1+8
	DA	0x0A61		; F#1+9
	DA	0x0A5E		; F#1+10
	DA	0x0A5C		; F#1+11
	DA	0x0A5A		; F#1+12
	DA	0x0A57		; F#1+13
	DA	0x0A55		; F#1+14
	DA	0x0A52		; F#1+15
	DA	0x0A50		; F#1+16
	DA	0x0A4E		; F#1+17
	DA	0x0A4B		; F#1+18
	DA	0x0A49		; F#1+19
	DA	0x0A46		; F#1+20
	DA	0x0A44		; F#1+21
	DA	0x0A42		; F#1+22
	DA	0x0A3F		; F#1+23
	DA	0x0A3D		; F#1+24
	DA	0x0A3B		; F#1+25
	DA	0x0A38		; F#1+26
	DA	0x0A36		; F#1+27
	DA	0x0A34		; F#1+28
	DA	0x0A31		; F#1+29
	DA	0x0A2F		; F#1+30
	DA	0x0A2C		; F#1+31
	DA	0x0A2A		; F#1+32
	DA	0x0A28		; F#1+33
	DA	0x0A25		; F#1+34
	DA	0x0A23		; F#1+35
	DA	0x0A21		; F#1+36
	DA	0x0A1E		; F#1+37
	DA	0x0A1C		; F#1+38
	DA	0x0A1A		; F#1+39
	DA	0x0A17		; F#1+40
	DA	0x0A15		; F#1+41
	DA	0x0A13		; F#1+42
	DA	0x0A10		; F#1+43
	DA	0x0A0E		; F#1+44
	DA	0x0A0C		; F#1+45
	DA	0x0A09		; F#1+46
	DA	0x0A07		; F#1+47
	DA	0x0A05		; F#1+48
	DA	0x0A03		; F#1+49
	DA	0x0A00		; F#1+50
	DA	0x09FE		; F#1+51
	DA	0x09FC		; F#1+52
	DA	0x09F9		; F#1+53
	DA	0x09F7		; F#1+54
	DA	0x09F5		; F#1+55
	DA	0x09F2		; F#1+56
	DA	0x09F0		; F#1+57
	DA	0x09EE		; F#1+58
	DA	0x09EC		; F#1+59
	DA	0x09E9		; F#1+60
	DA	0x09E7		; F#1+61
	DA	0x09E5		; F#1+62
	DA	0x09E2		; F#1+63
	DA	0x09E0		; G1+0
	DA	0x09DE		; G1+1
	DA	0x09DC		; G1+2
	DA	0x09D9		; G1+3
	DA	0x09D7		; G1+4
	DA	0x09D5		; G1+5
	DA	0x09D2		; G1+6
	DA	0x09D0		; G1+7
	DA	0x09CE		; G1+8
	DA	0x09CC		; G1+9
	DA	0x09C9		; G1+10
	DA	0x09C7		; G1+11
	DA	0x09C5		; G1+12
	DA	0x09C3		; G1+13
	DA	0x09C0		; G1+14
	DA	0x09BE		; G1+15
	DA	0x09BC		; G1+16
	DA	0x09BA		; G1+17
	DA	0x09B7		; G1+18
	DA	0x09B5		; G1+19
	DA	0x09B3		; G1+20
	DA	0x09B1		; G1+21
	DA	0x09AE		; G1+22
	DA	0x09AC		; G1+23
	DA	0x09AA		; G1+24
	DA	0x09A8		; G1+25
	DA	0x09A5		; G1+26
	DA	0x09A3		; G1+27
	DA	0x09A1		; G1+28
	DA	0x099F		; G1+29
	DA	0x099D		; G1+30
	DA	0x099A		; G1+31
	DA	0x0998		; G1+32
	DA	0x0996		; G1+33
	DA	0x0994		; G1+34
	DA	0x0991		; G1+35
	DA	0x098F		; G1+36
	DA	0x098D		; G1+37
	DA	0x098B		; G1+38
	DA	0x0989		; G1+39
	DA	0x0986		; G1+40
	DA	0x0984		; G1+41
	DA	0x0982		; G1+42
	DA	0x0980		; G1+43
	DA	0x097E		; G1+44
	DA	0x097B		; G1+45
	DA	0x0979		; G1+46
	DA	0x0977		; G1+47
	DA	0x0975		; G1+48
	DA	0x0973		; G1+49
	DA	0x0971		; G1+50
	DA	0x096E		; G1+51
	DA	0x096C		; G1+52
	DA	0x096A		; G1+53
	DA	0x0968		; G1+54
	DA	0x0966		; G1+55
	DA	0x0963		; G1+56
	DA	0x0961		; G1+57
	DA	0x095F		; G1+58
	DA	0x095D		; G1+59
	DA	0x095B		; G1+60
	DA	0x0959		; G1+61
	DA	0x0956		; G1+62
	DA	0x0954		; G1+63
	DA	0x0952		; G#1+0
	DA	0x0950		; G#1+1
	DA	0x094E		; G#1+2
	DA	0x094C		; G#1+3
	DA	0x094A		; G#1+4
	DA	0x0947		; G#1+5
	DA	0x0945		; G#1+6
	DA	0x0943		; G#1+7
	DA	0x0941		; G#1+8
	DA	0x093F		; G#1+9
	DA	0x093D		; G#1+10
	DA	0x093B		; G#1+11
	DA	0x0938		; G#1+12
	DA	0x0936		; G#1+13
	DA	0x0934		; G#1+14
	DA	0x0932		; G#1+15
	DA	0x0930		; G#1+16
	DA	0x092E		; G#1+17
	DA	0x092C		; G#1+18
	DA	0x092A		; G#1+19
	DA	0x0927		; G#1+20
	DA	0x0925		; G#1+21
	DA	0x0923		; G#1+22
	DA	0x0921		; G#1+23
	DA	0x091F		; G#1+24
	DA	0x091D		; G#1+25
	DA	0x091B		; G#1+26
	DA	0x0919		; G#1+27
	DA	0x0917		; G#1+28
	DA	0x0915		; G#1+29
	DA	0x0912		; G#1+30
	DA	0x0910		; G#1+31
	DA	0x090E		; G#1+32
	DA	0x090C		; G#1+33
	DA	0x090A		; G#1+34
	DA	0x0908		; G#1+35
	DA	0x0906		; G#1+36
	DA	0x0904		; G#1+37
	DA	0x0902		; G#1+38
	DA	0x0900		; G#1+39
	DA	0x08FE		; G#1+40
	DA	0x08FB		; G#1+41
	DA	0x08F9		; G#1+42
	DA	0x08F7		; G#1+43
	DA	0x08F5		; G#1+44
	DA	0x08F3		; G#1+45
	DA	0x08F1		; G#1+46
	DA	0x08EF		; G#1+47
	DA	0x08ED		; G#1+48
	DA	0x08EB		; G#1+49
	DA	0x08E9		; G#1+50
	DA	0x08E7		; G#1+51
	DA	0x08E5		; G#1+52
	DA	0x08E3		; G#1+53
	DA	0x08E1		; G#1+54
	DA	0x08DF		; G#1+55
	DA	0x08DD		; G#1+56
	DA	0x08DB		; G#1+57
	DA	0x08D8		; G#1+58
	DA	0x08D6		; G#1+59
	DA	0x08D4		; G#1+60
	DA	0x08D2		; G#1+61
	DA	0x08D0		; G#1+62
	DA	0x08CE		; G#1+63
	DA	0x08CC		; A2+0 444Hz
	DA	0x08CA		; A2+1
	DA	0x08C8		; A2+2
	DA	0x08C6		; A2+3
	DA	0x08C4		; A2+4
	DA	0x08C2		; A2+5
	DA	0x08C0		; A2+6
	DA	0x08BE		; A2+7
	DA	0x08BC		; A2+8
	DA	0x08BA		; A2+9
	DA	0x08B8		; A2+10
	DA	0x08B6		; A2+11
	DA	0x08B4		; A2+12
	DA	0x08B2		; A2+13
	DA	0x08B0		; A2+14
	DA	0x08AE		; A2+15
	DA	0x08AC		; A2+16
	DA	0x08AA		; A2+17
	DA	0x08A8		; A2+18
	DA	0x08A6		; A2+19
	DA	0x08A4		; A2+20
	DA	0x08A2		; A2+21
	DA	0x08A0		; A2+22
	DA	0x089E		; A2+23
	DA	0x089C		; A2+24
	DA	0x089A		; A2+25
	DA	0x0898		; A2+26
	DA	0x0896		; A2+27
	DA	0x0894		; A2+28
	DA	0x0892		; A2+29
	DA	0x0890		; A2+30
	DA	0x088E		; A2+31
	DA	0x088C		; A2+32
	DA	0x088A		; A2+33
	DA	0x0888		; A2+34
	DA	0x0886		; A2+35
	DA	0x0884		; A2+36
	DA	0x0882		; A2+37
	DA	0x0880		; A2+38
	DA	0x087E		; A2+39
	DA	0x087C		; A2+40
	DA	0x087A		; A2+41
	DA	0x0878		; A2+42
	DA	0x0877		; A2+43
	DA	0x0875		; A2+44
	DA	0x0873		; A2+45
	DA	0x0871		; A2+46
	DA	0x086F		; A2+47
	DA	0x086D		; A2+48
	DA	0x086B		; A2+49
	DA	0x0869		; A2+50
	DA	0x0867		; A2+51
	DA	0x0865		; A2+52
	DA	0x0863		; A2+53
	DA	0x0861		; A2+54
	DA	0x085F		; A2+55
	DA	0x085D		; A2+56
	DA	0x085B		; A2+57
	DA	0x0859		; A2+58
	DA	0x0857		; A2+59
	DA	0x0856		; A2+60
	DA	0x0854		; A2+61
	DA	0x0852		; A2+62
	DA	0x0850		; A2+63
	DA	0x084E		; A#2+0
	DA	0x084C		; A#2+1
	DA	0x084A		; A#2+2
	DA	0x0848		; A#2+3
	DA	0x0846		; A#2+4
	DA	0x0844		; A#2+5
	DA	0x0842		; A#2+6
	DA	0x0840		; A#2+7
	DA	0x083F		; A#2+8
	DA	0x083D		; A#2+9
	DA	0x083B		; A#2+10
	DA	0x0839		; A#2+11
	DA	0x0837		; A#2+12
	DA	0x0835		; A#2+13
	DA	0x0833		; A#2+14
	DA	0x0831		; A#2+15
	DA	0x082F		; A#2+16
	DA	0x082D		; A#2+17
	DA	0x082C		; A#2+18
	DA	0x082A		; A#2+19
	DA	0x0828		; A#2+20
	DA	0x0826		; A#2+21
	DA	0x0824		; A#2+22
	DA	0x0822		; A#2+23
	DA	0x0820		; A#2+24
	DA	0x081E		; A#2+25
	DA	0x081D		; A#2+26
	DA	0x081B		; A#2+27
	DA	0x0819		; A#2+28
	DA	0x0817		; A#2+29
	DA	0x0815		; A#2+30
	DA	0x0813		; A#2+31
	DA	0x0811		; A#2+32
	DA	0x080F		; A#2+33
	DA	0x080E		; A#2+34
	DA	0x080C		; A#2+35
	DA	0x080A		; A#2+36
	DA	0x0808		; A#2+37
	DA	0x0806		; A#2+38
	DA	0x0804		; A#2+39
	DA	0x0802		; A#2+40
	DA	0x0801		; A#2+41
	DA	0x07FF		; A#2+42
	DA	0x07FD		; A#2+43
	DA	0x07FB		; A#2+44
	DA	0x07F9		; A#2+45
	DA	0x07F7		; A#2+46
	DA	0x07F6		; A#2+47
	DA	0x07F4		; A#2+48
	DA	0x07F2		; A#2+49
	DA	0x07F0		; A#2+50
	DA	0x07EE		; A#2+51
	DA	0x07EC		; A#2+52
	DA	0x07EB		; A#2+53
	DA	0x07E9		; A#2+54
	DA	0x07E7		; A#2+55
	DA	0x07E5		; A#2+56
	DA	0x07E3		; A#2+57
	DA	0x07E1		; A#2+58
	DA	0x07E0		; A#2+59
	DA	0x07DE		; A#2+60
	DA	0x07DC		; A#2+61
	DA	0x07DA		; A#2+62
	DA	0x07D8		; A#2+63
	DA	0x07D7		; B2+0
	DA	0x07D5		; B2+1
	DA	0x07D3		; B2+2
	DA	0x07D1		; B2+3
	DA	0x07CF		; B2+4
	DA	0x07CD		; B2+5
	DA	0x07CC		; B2+6
	DA	0x07CA		; B2+7
	DA	0x07C8		; B2+8
	DA	0x07C6		; B2+9
	DA	0x07C5		; B2+10
	DA	0x07C3		; B2+11
	DA	0x07C1		; B2+12
	DA	0x07BF		; B2+13
	DA	0x07BD		; B2+14
	DA	0x07BC		; B2+15
	DA	0x07BA		; B2+16
	DA	0x07B8		; B2+17
	DA	0x07B6		; B2+18
	DA	0x07B4		; B2+19
	DA	0x07B3		; B2+20
	DA	0x07B1		; B2+21
	DA	0x07AF		; B2+22
	DA	0x07AD		; B2+23
	DA	0x07AC		; B2+24
	DA	0x07AA		; B2+25
	DA	0x07A8		; B2+26
	DA	0x07A6		; B2+27
	DA	0x07A4		; B2+28
	DA	0x07A3		; B2+29
	DA	0x07A1		; B2+30
	DA	0x079F		; B2+31
	DA	0x079D		; B2+32
	DA	0x079C		; B2+33
	DA	0x079A		; B2+34
	DA	0x0798		; B2+35
	DA	0x0796		; B2+36
	DA	0x0795		; B2+37
	DA	0x0793		; B2+38
	DA	0x0791		; B2+39
	DA	0x078F		; B2+40
	DA	0x078E		; B2+41
	DA	0x078C		; B2+42
	DA	0x078A		; B2+43
	DA	0x0788		; B2+44
	DA	0x0787		; B2+45
	DA	0x0785		; B2+46
	DA	0x0783		; B2+47
	DA	0x0781		; B2+48
	DA	0x0780		; B2+49
	DA	0x077E		; B2+50
	DA	0x077C		; B2+51
	DA	0x077B		; B2+52
	DA	0x0779		; B2+53
	DA	0x0777		; B2+54
	DA	0x0775		; B2+55
	DA	0x0774		; B2+56
	DA	0x0772		; B2+57
	DA	0x0770		; B2+58
	DA	0x076E		; B2+59
	DA	0x076D		; B2+60
	DA	0x076B		; B2+61
	DA	0x0769		; B2+62
	DA	0x0768		; B2+63

FMTONE440
	DA	0x0269		; C1+0
	DA	0x026A		; C1+1
	DA	0x026A		; C1+2
	DA	0x026B		; C1+3
	DA	0x026B		; C1+4
	DA	0x026C		; C1+5
	DA	0x026D		; C1+6
	DA	0x026D		; C1+7
	DA	0x026E		; C1+8
	DA	0x026E		; C1+9
	DA	0x026F		; C1+10
	DA	0x026F		; C1+11
	DA	0x0270		; C1+12
	DA	0x0271		; C1+13
	DA	0x0271		; C1+14
	DA	0x0272		; C1+15
	DA	0x0272		; C1+16
	DA	0x0273		; C1+17
	DA	0x0273		; C1+18
	DA	0x0274		; C1+19
	DA	0x0274		; C1+20
	DA	0x0275		; C1+21
	DA	0x0276		; C1+22
	DA	0x0276		; C1+23
	DA	0x0277		; C1+24
	DA	0x0277		; C1+25
	DA	0x0278		; C1+26
	DA	0x0278		; C1+27
	DA	0x0279		; C1+28
	DA	0x027A		; C1+29
	DA	0x027A		; C1+30
	DA	0x027B		; C1+31
	DA	0x027B		; C1+32
	DA	0x027C		; C1+33
	DA	0x027C		; C1+34
	DA	0x027D		; C1+35
	DA	0x027E		; C1+36
	DA	0x027E		; C1+37
	DA	0x027F		; C1+38
	DA	0x027F		; C1+39
	DA	0x0280		; C1+40
	DA	0x0281		; C1+41
	DA	0x0281		; C1+42
	DA	0x0282		; C1+43
	DA	0x0282		; C1+44
	DA	0x0283		; C1+45
	DA	0x0283		; C1+46
	DA	0x0284		; C1+47
	DA	0x0285		; C1+48
	DA	0x0285		; C1+49
	DA	0x0286		; C1+50
	DA	0x0286		; C1+51
	DA	0x0287		; C1+52
	DA	0x0287		; C1+53
	DA	0x0288		; C1+54
	DA	0x0289		; C1+55
	DA	0x0289		; C1+56
	DA	0x028A		; C1+57
	DA	0x028A		; C1+58
	DA	0x028B		; C1+59
	DA	0x028C		; C1+60
	DA	0x028C		; C1+61
	DA	0x028D		; C1+62
	DA	0x028D		; C1+63
	DA	0x028E		; C#1+0
	DA	0x028F		; C#1+1
	DA	0x028F		; C#1+2
	DA	0x0290		; C#1+3
	DA	0x0290		; C#1+4
	DA	0x0291		; C#1+5
	DA	0x0292		; C#1+6
	DA	0x0292		; C#1+7
	DA	0x0293		; C#1+8
	DA	0x0293		; C#1+9
	DA	0x0294		; C#1+10
	DA	0x0294		; C#1+11
	DA	0x0295		; C#1+12
	DA	0x0296		; C#1+13
	DA	0x0296		; C#1+14
	DA	0x0297		; C#1+15
	DA	0x0297		; C#1+16
	DA	0x0298		; C#1+17
	DA	0x0299		; C#1+18
	DA	0x0299		; C#1+19
	DA	0x029A		; C#1+20
	DA	0x029A		; C#1+21
	DA	0x029B		; C#1+22
	DA	0x029C		; C#1+23
	DA	0x029C		; C#1+24
	DA	0x029D		; C#1+25
	DA	0x029D		; C#1+26
	DA	0x029E		; C#1+27
	DA	0x029F		; C#1+28
	DA	0x029F		; C#1+29
	DA	0x02A0		; C#1+30
	DA	0x02A1		; C#1+31
	DA	0x02A1		; C#1+32
	DA	0x02A2		; C#1+33
	DA	0x02A2		; C#1+34
	DA	0x02A3		; C#1+35
	DA	0x02A4		; C#1+36
	DA	0x02A4		; C#1+37
	DA	0x02A5		; C#1+38
	DA	0x02A5		; C#1+39
	DA	0x02A6		; C#1+40
	DA	0x02A7		; C#1+41
	DA	0x02A7		; C#1+42
	DA	0x02A8		; C#1+43
	DA	0x02A8		; C#1+44
	DA	0x02A9		; C#1+45
	DA	0x02AA		; C#1+46
	DA	0x02AA		; C#1+47
	DA	0x02AB		; C#1+48
	DA	0x02AC		; C#1+49
	DA	0x02AC		; C#1+50
	DA	0x02AD		; C#1+51
	DA	0x02AD		; C#1+52
	DA	0x02AE		; C#1+53
	DA	0x02AF		; C#1+54
	DA	0x02AF		; C#1+55
	DA	0x02B0		; C#1+56
	DA	0x02B0		; C#1+57
	DA	0x02B1		; C#1+58
	DA	0x02B2		; C#1+59
	DA	0x02B2		; C#1+60
	DA	0x02B3		; C#1+61
	DA	0x02B4		; C#1+62
	DA	0x02B4		; C#1+63
	DA	0x02B5		; D1+0
	DA	0x02B5		; D1+1
	DA	0x02B6		; D1+2
	DA	0x02B7		; D1+3
	DA	0x02B7		; D1+4
	DA	0x02B8		; D1+5
	DA	0x02B9		; D1+6
	DA	0x02B9		; D1+7
	DA	0x02BA		; D1+8
	DA	0x02BA		; D1+9
	DA	0x02BB		; D1+10
	DA	0x02BC		; D1+11
	DA	0x02BC		; D1+12
	DA	0x02BD		; D1+13
	DA	0x02BE		; D1+14
	DA	0x02BE		; D1+15
	DA	0x02BF		; D1+16
	DA	0x02C0		; D1+17
	DA	0x02C0		; D1+18
	DA	0x02C1		; D1+19
	DA	0x02C1		; D1+20
	DA	0x02C2		; D1+21
	DA	0x02C3		; D1+22
	DA	0x02C3		; D1+23
	DA	0x02C4		; D1+24
	DA	0x02C5		; D1+25
	DA	0x02C5		; D1+26
	DA	0x02C6		; D1+27
	DA	0x02C7		; D1+28
	DA	0x02C7		; D1+29
	DA	0x02C8		; D1+30
	DA	0x02C9		; D1+31
	DA	0x02C9		; D1+32
	DA	0x02CA		; D1+33
	DA	0x02CA		; D1+34
	DA	0x02CB		; D1+35
	DA	0x02CC		; D1+36
	DA	0x02CC		; D1+37
	DA	0x02CD		; D1+38
	DA	0x02CE		; D1+39
	DA	0x02CE		; D1+40
	DA	0x02CF		; D1+41
	DA	0x02D0		; D1+42
	DA	0x02D0		; D1+43
	DA	0x02D1		; D1+44
	DA	0x02D2		; D1+45
	DA	0x02D2		; D1+46
	DA	0x02D3		; D1+47
	DA	0x02D4		; D1+48
	DA	0x02D4		; D1+49
	DA	0x02D5		; D1+50
	DA	0x02D5		; D1+51
	DA	0x02D6		; D1+52
	DA	0x02D7		; D1+53
	DA	0x02D7		; D1+54
	DA	0x02D8		; D1+55
	DA	0x02D9		; D1+56
	DA	0x02D9		; D1+57
	DA	0x02DA		; D1+58
	DA	0x02DB		; D1+59
	DA	0x02DB		; D1+60
	DA	0x02DC		; D1+61
	DA	0x02DD		; D1+62
	DA	0x02DD		; D1+63
	DA	0x02DE		; D#1+0
	DA	0x02DF		; D#1+1
	DA	0x02DF		; D#1+2
	DA	0x02E0		; D#1+3
	DA	0x02E1		; D#1+4
	DA	0x02E1		; D#1+5
	DA	0x02E2		; D#1+6
	DA	0x02E3		; D#1+7
	DA	0x02E3		; D#1+8
	DA	0x02E4		; D#1+9
	DA	0x02E5		; D#1+10
	DA	0x02E5		; D#1+11
	DA	0x02E6		; D#1+12
	DA	0x02E7		; D#1+13
	DA	0x02E7		; D#1+14
	DA	0x02E8		; D#1+15
	DA	0x02E9		; D#1+16
	DA	0x02E9		; D#1+17
	DA	0x02EA		; D#1+18
	DA	0x02EB		; D#1+19
	DA	0x02EB		; D#1+20
	DA	0x02EC		; D#1+21
	DA	0x02ED		; D#1+22
	DA	0x02ED		; D#1+23
	DA	0x02EE		; D#1+24
	DA	0x02EF		; D#1+25
	DA	0x02EF		; D#1+26
	DA	0x02F0		; D#1+27
	DA	0x02F1		; D#1+28
	DA	0x02F2		; D#1+29
	DA	0x02F2		; D#1+30
	DA	0x02F3		; D#1+31
	DA	0x02F4		; D#1+32
	DA	0x02F4		; D#1+33
	DA	0x02F5		; D#1+34
	DA	0x02F6		; D#1+35
	DA	0x02F6		; D#1+36
	DA	0x02F7		; D#1+37
	DA	0x02F8		; D#1+38
	DA	0x02F8		; D#1+39
	DA	0x02F9		; D#1+40
	DA	0x02FA		; D#1+41
	DA	0x02FA		; D#1+42
	DA	0x02FB		; D#1+43
	DA	0x02FC		; D#1+44
	DA	0x02FC		; D#1+45
	DA	0x02FD		; D#1+46
	DA	0x02FE		; D#1+47
	DA	0x02FF		; D#1+48
	DA	0x02FF		; D#1+49
	DA	0x0300		; D#1+50
	DA	0x0301		; D#1+51
	DA	0x0301		; D#1+52
	DA	0x0302		; D#1+53
	DA	0x0303		; D#1+54
	DA	0x0303		; D#1+55
	DA	0x0304		; D#1+56
	DA	0x0305		; D#1+57
	DA	0x0305		; D#1+58
	DA	0x0306		; D#1+59
	DA	0x0307		; D#1+60
	DA	0x0308		; D#1+61
	DA	0x0308		; D#1+62
	DA	0x0309		; D#1+63
	DA	0x030A		; E1+0
	DA	0x030A		; E1+1
	DA	0x030B		; E1+2
	DA	0x030C		; E1+3
	DA	0x030D		; E1+4
	DA	0x030D		; E1+5
	DA	0x030E		; E1+6
	DA	0x030F		; E1+7
	DA	0x030F		; E1+8
	DA	0x0310		; E1+9
	DA	0x0311		; E1+10
	DA	0x0311		; E1+11
	DA	0x0312		; E1+12
	DA	0x0313		; E1+13
	DA	0x0314		; E1+14
	DA	0x0314		; E1+15
	DA	0x0315		; E1+16
	DA	0x0316		; E1+17
	DA	0x0316		; E1+18
	DA	0x0317		; E1+19
	DA	0x0318		; E1+20
	DA	0x0319		; E1+21
	DA	0x0319		; E1+22
	DA	0x031A		; E1+23
	DA	0x031B		; E1+24
	DA	0x031B		; E1+25
	DA	0x031C		; E1+26
	DA	0x031D		; E1+27
	DA	0x031E		; E1+28
	DA	0x031E		; E1+29
	DA	0x031F		; E1+30
	DA	0x0320		; E1+31
	DA	0x0320		; E1+32
	DA	0x0321		; E1+33
	DA	0x0322		; E1+34
	DA	0x0323		; E1+35
	DA	0x0323		; E1+36
	DA	0x0324		; E1+37
	DA	0x0325		; E1+38
	DA	0x0326		; E1+39
	DA	0x0326		; E1+40
	DA	0x0327		; E1+41
	DA	0x0328		; E1+42
	DA	0x0328		; E1+43
	DA	0x0329		; E1+44
	DA	0x032A		; E1+45
	DA	0x032B		; E1+46
	DA	0x032B		; E1+47
	DA	0x032C		; E1+48
	DA	0x032D		; E1+49
	DA	0x032E		; E1+50
	DA	0x032E		; E1+51
	DA	0x032F		; E1+52
	DA	0x0330		; E1+53
	DA	0x0331		; E1+54
	DA	0x0331		; E1+55
	DA	0x0332		; E1+56
	DA	0x0333		; E1+57
	DA	0x0333		; E1+58
	DA	0x0334		; E1+59
	DA	0x0335		; E1+60
	DA	0x0336		; E1+61
	DA	0x0336		; E1+62
	DA	0x0337		; E1+63
	DA	0x0338		; F1+0
	DA	0x0339		; F1+1
	DA	0x0339		; F1+2
	DA	0x033A		; F1+3
	DA	0x033B		; F1+4
	DA	0x033C		; F1+5
	DA	0x033C		; F1+6
	DA	0x033D		; F1+7
	DA	0x033E		; F1+8
	DA	0x033F		; F1+9
	DA	0x033F		; F1+10
	DA	0x0340		; F1+11
	DA	0x0341		; F1+12
	DA	0x0342		; F1+13
	DA	0x0342		; F1+14
	DA	0x0343		; F1+15
	DA	0x0344		; F1+16
	DA	0x0345		; F1+17
	DA	0x0345		; F1+18
	DA	0x0346		; F1+19
	DA	0x0347		; F1+20
	DA	0x0348		; F1+21
	DA	0x0348		; F1+22
	DA	0x0349		; F1+23
	DA	0x034A		; F1+24
	DA	0x034B		; F1+25
	DA	0x034B		; F1+26
	DA	0x034C		; F1+27
	DA	0x034D		; F1+28
	DA	0x034E		; F1+29
	DA	0x034F		; F1+30
	DA	0x034F		; F1+31
	DA	0x0350		; F1+32
	DA	0x0351		; F1+33
	DA	0x0352		; F1+34
	DA	0x0352		; F1+35
	DA	0x0353		; F1+36
	DA	0x0354		; F1+37
	DA	0x0355		; F1+38
	DA	0x0355		; F1+39
	DA	0x0356		; F1+40
	DA	0x0357		; F1+41
	DA	0x0358		; F1+42
	DA	0x0359		; F1+43
	DA	0x0359		; F1+44
	DA	0x035A		; F1+45
	DA	0x035B		; F1+46
	DA	0x035C		; F1+47
	DA	0x035C		; F1+48
	DA	0x035D		; F1+49
	DA	0x035E		; F1+50
	DA	0x035F		; F1+51
	DA	0x0360		; F1+52
	DA	0x0360		; F1+53
	DA	0x0361		; F1+54
	DA	0x0362		; F1+55
	DA	0x0363		; F1+56
	DA	0x0363		; F1+57
	DA	0x0364		; F1+58
	DA	0x0365		; F1+59
	DA	0x0366		; F1+60
	DA	0x0367		; F1+61
	DA	0x0367		; F1+62
	DA	0x0368		; F1+63
	DA	0x0369		; F#1+0
	DA	0x036A		; F#1+1
	DA	0x036B		; F#1+2
	DA	0x036B		; F#1+3
	DA	0x036C		; F#1+4
	DA	0x036D		; F#1+5
	DA	0x036E		; F#1+6
	DA	0x036E		; F#1+7
	DA	0x036F		; F#1+8
	DA	0x0370		; F#1+9
	DA	0x0371		; F#1+10
	DA	0x0372		; F#1+11
	DA	0x0372		; F#1+12
	DA	0x0373		; F#1+13
	DA	0x0374		; F#1+14
	DA	0x0375		; F#1+15
	DA	0x0376		; F#1+16
	DA	0x0376		; F#1+17
	DA	0x0377		; F#1+18
	DA	0x0378		; F#1+19
	DA	0x0379		; F#1+20
	DA	0x037A		; F#1+21
	DA	0x037A		; F#1+22
	DA	0x037B		; F#1+23
	DA	0x037C		; F#1+24
	DA	0x037D		; F#1+25
	DA	0x037E		; F#1+26
	DA	0x037E		; F#1+27
	DA	0x037F		; F#1+28
	DA	0x0380		; F#1+29
	DA	0x0381		; F#1+30
	DA	0x0382		; F#1+31
	DA	0x0383		; F#1+32
	DA	0x0383		; F#1+33
	DA	0x0384		; F#1+34
	DA	0x0385		; F#1+35
	DA	0x0386		; F#1+36
	DA	0x0387		; F#1+37
	DA	0x0387		; F#1+38
	DA	0x0388		; F#1+39
	DA	0x0389		; F#1+40
	DA	0x038A		; F#1+41
	DA	0x038B		; F#1+42
	DA	0x038B		; F#1+43
	DA	0x038C		; F#1+44
	DA	0x038D		; F#1+45
	DA	0x038E		; F#1+46
	DA	0x038F		; F#1+47
	DA	0x0390		; F#1+48
	DA	0x0390		; F#1+49
	DA	0x0391		; F#1+50
	DA	0x0392		; F#1+51
	DA	0x0393		; F#1+52
	DA	0x0394		; F#1+53
	DA	0x0395		; F#1+54
	DA	0x0395		; F#1+55
	DA	0x0396		; F#1+56
	DA	0x0397		; F#1+57
	DA	0x0398		; F#1+58
	DA	0x0399		; F#1+59
	DA	0x039A		; F#1+60
	DA	0x039A		; F#1+61
	DA	0x039B		; F#1+62
	DA	0x039C		; F#1+63
	DA	0x039D		; G1+0
	DA	0x039E		; G1+1
	DA	0x039F		; G1+2
	DA	0x039F		; G1+3
	DA	0x03A0		; G1+4
	DA	0x03A1		; G1+5
	DA	0x03A2		; G1+6
	DA	0x03A3		; G1+7
	DA	0x03A4		; G1+8
	DA	0x03A4		; G1+9
	DA	0x03A5		; G1+10
	DA	0x03A6		; G1+11
	DA	0x03A7		; G1+12
	DA	0x03A8		; G1+13
	DA	0x03A9		; G1+14
	DA	0x03A9		; G1+15
	DA	0x03AA		; G1+16
	DA	0x03AB		; G1+17
	DA	0x03AC		; G1+18
	DA	0x03AD		; G1+19
	DA	0x03AE		; G1+20
	DA	0x03AF		; G1+21
	DA	0x03AF		; G1+22
	DA	0x03B0		; G1+23
	DA	0x03B1		; G1+24
	DA	0x03B2		; G1+25
	DA	0x03B3		; G1+26
	DA	0x03B4		; G1+27
	DA	0x03B5		; G1+28
	DA	0x03B5		; G1+29
	DA	0x03B6		; G1+30
	DA	0x03B7		; G1+31
	DA	0x03B8		; G1+32
	DA	0x03B9		; G1+33
	DA	0x03BA		; G1+34
	DA	0x03BB		; G1+35
	DA	0x03BB		; G1+36
	DA	0x03BC		; G1+37
	DA	0x03BD		; G1+38
	DA	0x03BE		; G1+39
	DA	0x03BF		; G1+40
	DA	0x03C0		; G1+41
	DA	0x03C1		; G1+42
	DA	0x03C1		; G1+43
	DA	0x03C2		; G1+44
	DA	0x03C3		; G1+45
	DA	0x03C4		; G1+46
	DA	0x03C5		; G1+47
	DA	0x03C6		; G1+48
	DA	0x03C7		; G1+49
	DA	0x03C8		; G1+50
	DA	0x03C8		; G1+51
	DA	0x03C9		; G1+52
	DA	0x03CA		; G1+53
	DA	0x03CB		; G1+54
	DA	0x03CC		; G1+55
	DA	0x03CD		; G1+56
	DA	0x03CE		; G1+57
	DA	0x03CF		; G1+58
	DA	0x03CF		; G1+59
	DA	0x03D0		; G1+60
	DA	0x03D1		; G1+61
	DA	0x03D2		; G1+62
	DA	0x03D3		; G1+63
	DA	0x03D4		; G#1+0
	DA	0x03D5		; G#1+1
	DA	0x03D6		; G#1+2
	DA	0x03D6		; G#1+3
	DA	0x03D7		; G#1+4
	DA	0x03D8		; G#1+5
	DA	0x03D9		; G#1+6
	DA	0x03DA		; G#1+7
	DA	0x03DB		; G#1+8
	DA	0x03DC		; G#1+9
	DA	0x03DD		; G#1+10
	DA	0x03DE		; G#1+11
	DA	0x03DE		; G#1+12
	DA	0x03DF		; G#1+13
	DA	0x03E0		; G#1+14
	DA	0x03E1		; G#1+15
	DA	0x03E2		; G#1+16
	DA	0x03E3		; G#1+17
	DA	0x03E4		; G#1+18
	DA	0x03E5		; G#1+19
	DA	0x03E6		; G#1+20
	DA	0x03E7		; G#1+21
	DA	0x03E7		; G#1+22
	DA	0x03E8		; G#1+23
	DA	0x03E9		; G#1+24
	DA	0x03EA		; G#1+25
	DA	0x03EB		; G#1+26
	DA	0x03EC		; G#1+27
	DA	0x03ED		; G#1+28
	DA	0x03EE		; G#1+29
	DA	0x03EF		; G#1+30
	DA	0x03F0		; G#1+31
	DA	0x03F1		; G#1+32
	DA	0x03F1		; G#1+33
	DA	0x03F2		; G#1+34
	DA	0x03F3		; G#1+35
	DA	0x03F4		; G#1+36
	DA	0x03F5		; G#1+37
	DA	0x03F6		; G#1+38
	DA	0x03F7		; G#1+39
	DA	0x03F8		; G#1+40
	DA	0x03F9		; G#1+41
	DA	0x03FA		; G#1+42
	DA	0x03FB		; G#1+43
	DA	0x03FC		; G#1+44
	DA	0x03FC		; G#1+45
	DA	0x03FD		; G#1+46
	DA	0x03FE		; G#1+47
	DA	0x03FF		; G#1+48
	DA	0x0400		; G#1+49
	DA	0x0401		; G#1+50
	DA	0x0402		; G#1+51
	DA	0x0403		; G#1+52
	DA	0x0404		; G#1+53
	DA	0x0405		; G#1+54
	DA	0x0406		; G#1+55
	DA	0x0407		; G#1+56
	DA	0x0408		; G#1+57
	DA	0x0408		; G#1+58
	DA	0x0409		; G#1+59
	DA	0x040A		; G#1+60
	DA	0x040B		; G#1+61
	DA	0x040C		; G#1+62
	DA	0x040D		; G#1+63
	DA	0x040E		; A2+0 (440Hz)
	DA	0x040F		; A2+1
	DA	0x0410		; A2+2
	DA	0x0411		; A2+3
	DA	0x0412		; A2+4
	DA	0x0413		; A2+5
	DA	0x0414		; A2+6
	DA	0x0415		; A2+7
	DA	0x0416		; A2+8
	DA	0x0417		; A2+9
	DA	0x0418		; A2+10
	DA	0x0418		; A2+11
	DA	0x0419		; A2+12
	DA	0x041A		; A2+13
	DA	0x041B		; A2+14
	DA	0x041C		; A2+15
	DA	0x041D		; A2+16
	DA	0x041E		; A2+17
	DA	0x041F		; A2+18
	DA	0x0420		; A2+19
	DA	0x0421		; A2+20
	DA	0x0422		; A2+21
	DA	0x0423		; A2+22
	DA	0x0424		; A2+23
	DA	0x0425		; A2+24
	DA	0x0426		; A2+25
	DA	0x0427		; A2+26
	DA	0x0428		; A2+27
	DA	0x0429		; A2+28
	DA	0x042A		; A2+29
	DA	0x042B		; A2+30
	DA	0x042C		; A2+31
	DA	0x042D		; A2+32
	DA	0x042D		; A2+33
	DA	0x042E		; A2+34
	DA	0x042F		; A2+35
	DA	0x0430		; A2+36
	DA	0x0431		; A2+37
	DA	0x0432		; A2+38
	DA	0x0433		; A2+39
	DA	0x0434		; A2+40
	DA	0x0435		; A2+41
	DA	0x0436		; A2+42
	DA	0x0437		; A2+43
	DA	0x0438		; A2+44
	DA	0x0439		; A2+45
	DA	0x043A		; A2+46
	DA	0x043B		; A2+47
	DA	0x043C		; A2+48
	DA	0x043D		; A2+49
	DA	0x043E		; A2+50
	DA	0x043F		; A2+51
	DA	0x0440		; A2+52
	DA	0x0441		; A2+53
	DA	0x0442		; A2+54
	DA	0x0443		; A2+55
	DA	0x0444		; A2+56
	DA	0x0445		; A2+57
	DA	0x0446		; A2+58
	DA	0x0447		; A2+59
	DA	0x0448		; A2+60
	DA	0x0449		; A2+61
	DA	0x044A		; A2+62
	DA	0x044B		; A2+63
	DA	0x044C		; A#2+0
	DA	0x044D		; A#2+1
	DA	0x044E		; A#2+2
	DA	0x044F		; A#2+3
	DA	0x0450		; A#2+4
	DA	0x0451		; A#2+5
	DA	0x0452		; A#2+6
	DA	0x0453		; A#2+7
	DA	0x0454		; A#2+8
	DA	0x0455		; A#2+9
	DA	0x0456		; A#2+10
	DA	0x0457		; A#2+11
	DA	0x0458		; A#2+12
	DA	0x0459		; A#2+13
	DA	0x045A		; A#2+14
	DA	0x045B		; A#2+15
	DA	0x045C		; A#2+16
	DA	0x045D		; A#2+17
	DA	0x045E		; A#2+18
	DA	0x045F		; A#2+19
	DA	0x0460		; A#2+20
	DA	0x0461		; A#2+21
	DA	0x0462		; A#2+22
	DA	0x0463		; A#2+23
	DA	0x0464		; A#2+24
	DA	0x0465		; A#2+25
	DA	0x0466		; A#2+26
	DA	0x0467		; A#2+27
	DA	0x0468		; A#2+28
	DA	0x0469		; A#2+29
	DA	0x046A		; A#2+30
	DA	0x046B		; A#2+31
	DA	0x046C		; A#2+32
	DA	0x046D		; A#2+33
	DA	0x046E		; A#2+34
	DA	0x046F		; A#2+35
	DA	0x0470		; A#2+36
	DA	0x0471		; A#2+37
	DA	0x0472		; A#2+38
	DA	0x0473		; A#2+39
	DA	0x0474		; A#2+40
	DA	0x0475		; A#2+41
	DA	0x0476		; A#2+42
	DA	0x0477		; A#2+43
	DA	0x0478		; A#2+44
	DA	0x0479		; A#2+45
	DA	0x047A		; A#2+46
	DA	0x047B		; A#2+47
	DA	0x047D		; A#2+48
	DA	0x047E		; A#2+49
	DA	0x047F		; A#2+50
	DA	0x0480		; A#2+51
	DA	0x0481		; A#2+52
	DA	0x0482		; A#2+53
	DA	0x0483		; A#2+54
	DA	0x0484		; A#2+55
	DA	0x0485		; A#2+56
	DA	0x0486		; A#2+57
	DA	0x0487		; A#2+58
	DA	0x0488		; A#2+59
	DA	0x0489		; A#2+60
	DA	0x048A		; A#2+61
	DA	0x048B		; A#2+62
	DA	0x048C		; A#2+63
	DA	0x048D		; B2+0
	DA	0x048E		; B2+1
	DA	0x048F		; B2+2
	DA	0x0490		; B2+3
	DA	0x0491		; B2+4
	DA	0x0492		; B2+5
	DA	0x0494		; B2+6
	DA	0x0495		; B2+7
	DA	0x0496		; B2+8
	DA	0x0497		; B2+9
	DA	0x0498		; B2+10
	DA	0x0499		; B2+11
	DA	0x049A		; B2+12
	DA	0x049B		; B2+13
	DA	0x049C		; B2+14
	DA	0x049D		; B2+15
	DA	0x049E		; B2+16
	DA	0x049F		; B2+17
	DA	0x04A0		; B2+18
	DA	0x04A1		; B2+19
	DA	0x04A2		; B2+20
	DA	0x04A4		; B2+21
	DA	0x04A5		; B2+22
	DA	0x04A6		; B2+23
	DA	0x04A7		; B2+24
	DA	0x04A8		; B2+25
	DA	0x04A9		; B2+26
	DA	0x04AA		; B2+27
	DA	0x04AB		; B2+28
	DA	0x04AC		; B2+29
	DA	0x04AD		; B2+30
	DA	0x04AE		; B2+31
	DA	0x04AF		; B2+32
	DA	0x04B0		; B2+33
	DA	0x04B2		; B2+34
	DA	0x04B3		; B2+35
	DA	0x04B4		; B2+36
	DA	0x04B5		; B2+37
	DA	0x04B6		; B2+38
	DA	0x04B7		; B2+39
	DA	0x04B8		; B2+40
	DA	0x04B9		; B2+41
	DA	0x04BA		; B2+42
	DA	0x04BB		; B2+43
	DA	0x04BC		; B2+44
	DA	0x04BE		; B2+45
	DA	0x04BF		; B2+46
	DA	0x04C0		; B2+47
	DA	0x04C1		; B2+48
	DA	0x04C2		; B2+49
	DA	0x04C3		; B2+50
	DA	0x04C4		; B2+51
	DA	0x04C5		; B2+52
	DA	0x04C6		; B2+53
	DA	0x04C7		; B2+54
	DA	0x04C9		; B2+55
	DA	0x04CA		; B2+56
	DA	0x04CB		; B2+57
	DA	0x04CC		; B2+58
	DA	0x04CD		; B2+59
	DA	0x04CE		; B2+60
	DA	0x04CF		; B2+61
	DA	0x04D0		; B2+62
	DA	0x04D1		; B2+63

FMTONE444
	DA	0x026F		; C1+0
	DA	0x026F		; C1+1
	DA	0x0270		; C1+2
	DA	0x0271		; C1+3
	DA	0x0271		; C1+4
	DA	0x0272		; C1+5
	DA	0x0272		; C1+6
	DA	0x0273		; C1+7
	DA	0x0273		; C1+8
	DA	0x0274		; C1+9
	DA	0x0275		; C1+10
	DA	0x0275		; C1+11
	DA	0x0276		; C1+12
	DA	0x0276		; C1+13
	DA	0x0277		; C1+14
	DA	0x0277		; C1+15
	DA	0x0278		; C1+16
	DA	0x0278		; C1+17
	DA	0x0279		; C1+18
	DA	0x027A		; C1+19
	DA	0x027A		; C1+20
	DA	0x027B		; C1+21
	DA	0x027B		; C1+22
	DA	0x027C		; C1+23
	DA	0x027D		; C1+24
	DA	0x027D		; C1+25
	DA	0x027E		; C1+26
	DA	0x027E		; C1+27
	DA	0x027F		; C1+28
	DA	0x027F		; C1+29
	DA	0x0280		; C1+30
	DA	0x0281		; C1+31
	DA	0x0281		; C1+32
	DA	0x0282		; C1+33
	DA	0x0282		; C1+34
	DA	0x0283		; C1+35
	DA	0x0283		; C1+36
	DA	0x0284		; C1+37
	DA	0x0285		; C1+38
	DA	0x0285		; C1+39
	DA	0x0286		; C1+40
	DA	0x0286		; C1+41
	DA	0x0287		; C1+42
	DA	0x0288		; C1+43
	DA	0x0288		; C1+44
	DA	0x0289		; C1+45
	DA	0x0289		; C1+46
	DA	0x028A		; C1+47
	DA	0x028A		; C1+48
	DA	0x028B		; C1+49
	DA	0x028C		; C1+50
	DA	0x028C		; C1+51
	DA	0x028D		; C1+52
	DA	0x028D		; C1+53
	DA	0x028E		; C1+54
	DA	0x028F		; C1+55
	DA	0x028F		; C1+56
	DA	0x0290		; C1+57
	DA	0x0290		; C1+58
	DA	0x0291		; C1+59
	DA	0x0292		; C1+60
	DA	0x0292		; C1+61
	DA	0x0293		; C1+62
	DA	0x0293		; C1+63
	DA	0x0294		; C#1+0
	DA	0x0294		; C#1+1
	DA	0x0295		; C#1+2
	DA	0x0296		; C#1+3
	DA	0x0296		; C#1+4
	DA	0x0297		; C#1+5
	DA	0x0297		; C#1+6
	DA	0x0298		; C#1+7
	DA	0x0299		; C#1+8
	DA	0x0299		; C#1+9
	DA	0x029A		; C#1+10
	DA	0x029A		; C#1+11
	DA	0x029B		; C#1+12
	DA	0x029C		; C#1+13
	DA	0x029C		; C#1+14
	DA	0x029D		; C#1+15
	DA	0x029D		; C#1+16
	DA	0x029E		; C#1+17
	DA	0x029F		; C#1+18
	DA	0x029F		; C#1+19
	DA	0x02A0		; C#1+20
	DA	0x02A1		; C#1+21
	DA	0x02A1		; C#1+22
	DA	0x02A2		; C#1+23
	DA	0x02A2		; C#1+24
	DA	0x02A3		; C#1+25
	DA	0x02A4		; C#1+26
	DA	0x02A4		; C#1+27
	DA	0x02A5		; C#1+28
	DA	0x02A5		; C#1+29
	DA	0x02A6		; C#1+30
	DA	0x02A7		; C#1+31
	DA	0x02A7		; C#1+32
	DA	0x02A8		; C#1+33
	DA	0x02A8		; C#1+34
	DA	0x02A9		; C#1+35
	DA	0x02AA		; C#1+36
	DA	0x02AA		; C#1+37
	DA	0x02AB		; C#1+38
	DA	0x02AC		; C#1+39
	DA	0x02AC		; C#1+40
	DA	0x02AD		; C#1+41
	DA	0x02AD		; C#1+42
	DA	0x02AE		; C#1+43
	DA	0x02AF		; C#1+44
	DA	0x02AF		; C#1+45
	DA	0x02B0		; C#1+46
	DA	0x02B0		; C#1+47
	DA	0x02B1		; C#1+48
	DA	0x02B2		; C#1+49
	DA	0x02B2		; C#1+50
	DA	0x02B3		; C#1+51
	DA	0x02B4		; C#1+52
	DA	0x02B4		; C#1+53
	DA	0x02B5		; C#1+54
	DA	0x02B5		; C#1+55
	DA	0x02B6		; C#1+56
	DA	0x02B7		; C#1+57
	DA	0x02B7		; C#1+58
	DA	0x02B8		; C#1+59
	DA	0x02B9		; C#1+60
	DA	0x02B9		; C#1+61
	DA	0x02BA		; C#1+62
	DA	0x02BB		; C#1+63
	DA	0x02BB		; D1+0
	DA	0x02BC		; D1+1
	DA	0x02BC		; D1+2
	DA	0x02BD		; D1+3
	DA	0x02BE		; D1+4
	DA	0x02BE		; D1+5
	DA	0x02BF		; D1+6
	DA	0x02C0		; D1+7
	DA	0x02C0		; D1+8
	DA	0x02C1		; D1+9
	DA	0x02C1		; D1+10
	DA	0x02C2		; D1+11
	DA	0x02C3		; D1+12
	DA	0x02C3		; D1+13
	DA	0x02C4		; D1+14
	DA	0x02C5		; D1+15
	DA	0x02C5		; D1+16
	DA	0x02C6		; D1+17
	DA	0x02C7		; D1+18
	DA	0x02C7		; D1+19
	DA	0x02C8		; D1+20
	DA	0x02C9		; D1+21
	DA	0x02C9		; D1+22
	DA	0x02CA		; D1+23
	DA	0x02CA		; D1+24
	DA	0x02CB		; D1+25
	DA	0x02CC		; D1+26
	DA	0x02CC		; D1+27
	DA	0x02CD		; D1+28
	DA	0x02CE		; D1+29
	DA	0x02CE		; D1+30
	DA	0x02CF		; D1+31
	DA	0x02D0		; D1+32
	DA	0x02D0		; D1+33
	DA	0x02D1		; D1+34
	DA	0x02D2		; D1+35
	DA	0x02D2		; D1+36
	DA	0x02D3		; D1+37
	DA	0x02D4		; D1+38
	DA	0x02D4		; D1+39
	DA	0x02D5		; D1+40
	DA	0x02D5		; D1+41
	DA	0x02D6		; D1+42
	DA	0x02D7		; D1+43
	DA	0x02D7		; D1+44
	DA	0x02D8		; D1+45
	DA	0x02D9		; D1+46
	DA	0x02D9		; D1+47
	DA	0x02DA		; D1+48
	DA	0x02DB		; D1+49
	DA	0x02DB		; D1+50
	DA	0x02DC		; D1+51
	DA	0x02DD		; D1+52
	DA	0x02DD		; D1+53
	DA	0x02DE		; D1+54
	DA	0x02DF		; D1+55
	DA	0x02DF		; D1+56
	DA	0x02E0		; D1+57
	DA	0x02E1		; D1+58
	DA	0x02E1		; D1+59
	DA	0x02E2		; D1+60
	DA	0x02E3		; D1+61
	DA	0x02E3		; D1+62
	DA	0x02E4		; D1+63
	DA	0x02E5		; D#1+0
	DA	0x02E5		; D#1+1
	DA	0x02E6		; D#1+2
	DA	0x02E7		; D#1+3
	DA	0x02E7		; D#1+4
	DA	0x02E8		; D#1+5
	DA	0x02E9		; D#1+6
	DA	0x02E9		; D#1+7
	DA	0x02EA		; D#1+8
	DA	0x02EB		; D#1+9
	DA	0x02EB		; D#1+10
	DA	0x02EC		; D#1+11
	DA	0x02ED		; D#1+12
	DA	0x02ED		; D#1+13
	DA	0x02EE		; D#1+14
	DA	0x02EF		; D#1+15
	DA	0x02EF		; D#1+16
	DA	0x02F0		; D#1+17
	DA	0x02F1		; D#1+18
	DA	0x02F2		; D#1+19
	DA	0x02F2		; D#1+20
	DA	0x02F3		; D#1+21
	DA	0x02F4		; D#1+22
	DA	0x02F4		; D#1+23
	DA	0x02F5		; D#1+24
	DA	0x02F6		; D#1+25
	DA	0x02F6		; D#1+26
	DA	0x02F7		; D#1+27
	DA	0x02F8		; D#1+28
	DA	0x02F8		; D#1+29
	DA	0x02F9		; D#1+30
	DA	0x02FA		; D#1+31
	DA	0x02FA		; D#1+32
	DA	0x02FB		; D#1+33
	DA	0x02FC		; D#1+34
	DA	0x02FC		; D#1+35
	DA	0x02FD		; D#1+36
	DA	0x02FE		; D#1+37
	DA	0x02FF		; D#1+38
	DA	0x02FF		; D#1+39
	DA	0x0300		; D#1+40
	DA	0x0301		; D#1+41
	DA	0x0301		; D#1+42
	DA	0x0302		; D#1+43
	DA	0x0303		; D#1+44
	DA	0x0303		; D#1+45
	DA	0x0304		; D#1+46
	DA	0x0305		; D#1+47
	DA	0x0306		; D#1+48
	DA	0x0306		; D#1+49
	DA	0x0307		; D#1+50
	DA	0x0308		; D#1+51
	DA	0x0308		; D#1+52
	DA	0x0309		; D#1+53
	DA	0x030A		; D#1+54
	DA	0x030A		; D#1+55
	DA	0x030B		; D#1+56
	DA	0x030C		; D#1+57
	DA	0x030D		; D#1+58
	DA	0x030D		; D#1+59
	DA	0x030E		; D#1+60
	DA	0x030F		; D#1+61
	DA	0x030F		; D#1+62
	DA	0x0310		; D#1+63
	DA	0x0311		; E1+0
	DA	0x0311		; E1+1
	DA	0x0312		; E1+2
	DA	0x0313		; E1+3
	DA	0x0314		; E1+4
	DA	0x0314		; E1+5
	DA	0x0315		; E1+6
	DA	0x0316		; E1+7
	DA	0x0316		; E1+8
	DA	0x0317		; E1+9
	DA	0x0318		; E1+10
	DA	0x0319		; E1+11
	DA	0x0319		; E1+12
	DA	0x031A		; E1+13
	DA	0x031B		; E1+14
	DA	0x031B		; E1+15
	DA	0x031C		; E1+16
	DA	0x031D		; E1+17
	DA	0x031E		; E1+18
	DA	0x031E		; E1+19
	DA	0x031F		; E1+20
	DA	0x0320		; E1+21
	DA	0x0320		; E1+22
	DA	0x0321		; E1+23
	DA	0x0322		; E1+24
	DA	0x0323		; E1+25
	DA	0x0323		; E1+26
	DA	0x0324		; E1+27
	DA	0x0325		; E1+28
	DA	0x0326		; E1+29
	DA	0x0326		; E1+30
	DA	0x0327		; E1+31
	DA	0x0328		; E1+32
	DA	0x0328		; E1+33
	DA	0x0329		; E1+34
	DA	0x032A		; E1+35
	DA	0x032B		; E1+36
	DA	0x032B		; E1+37
	DA	0x032C		; E1+38
	DA	0x032D		; E1+39
	DA	0x032E		; E1+40
	DA	0x032E		; E1+41
	DA	0x032F		; E1+42
	DA	0x0330		; E1+43
	DA	0x0331		; E1+44
	DA	0x0331		; E1+45
	DA	0x0332		; E1+46
	DA	0x0333		; E1+47
	DA	0x0334		; E1+48
	DA	0x0334		; E1+49
	DA	0x0335		; E1+50
	DA	0x0336		; E1+51
	DA	0x0336		; E1+52
	DA	0x0337		; E1+53
	DA	0x0338		; E1+54
	DA	0x0339		; E1+55
	DA	0x0339		; E1+56
	DA	0x033A		; E1+57
	DA	0x033B		; E1+58
	DA	0x033C		; E1+59
	DA	0x033C		; E1+60
	DA	0x033D		; E1+61
	DA	0x033E		; E1+62
	DA	0x033F		; E1+63
	DA	0x033F		; F1+0
	DA	0x0340		; F1+1
	DA	0x0341		; F1+2
	DA	0x0342		; F1+3
	DA	0x0342		; F1+4
	DA	0x0343		; F1+5
	DA	0x0344		; F1+6
	DA	0x0345		; F1+7
	DA	0x0345		; F1+8
	DA	0x0346		; F1+9
	DA	0x0347		; F1+10
	DA	0x0348		; F1+11
	DA	0x0348		; F1+12
	DA	0x0349		; F1+13
	DA	0x034A		; F1+14
	DA	0x034B		; F1+15
	DA	0x034C		; F1+16
	DA	0x034C		; F1+17
	DA	0x034D		; F1+18
	DA	0x034E		; F1+19
	DA	0x034F		; F1+20
	DA	0x034F		; F1+21
	DA	0x0350		; F1+22
	DA	0x0351		; F1+23
	DA	0x0352		; F1+24
	DA	0x0352		; F1+25
	DA	0x0353		; F1+26
	DA	0x0354		; F1+27
	DA	0x0355		; F1+28
	DA	0x0355		; F1+29
	DA	0x0356		; F1+30
	DA	0x0357		; F1+31
	DA	0x0358		; F1+32
	DA	0x0359		; F1+33
	DA	0x0359		; F1+34
	DA	0x035A		; F1+35
	DA	0x035B		; F1+36
	DA	0x035C		; F1+37
	DA	0x035C		; F1+38
	DA	0x035D		; F1+39
	DA	0x035E		; F1+40
	DA	0x035F		; F1+41
	DA	0x0360		; F1+42
	DA	0x0360		; F1+43
	DA	0x0361		; F1+44
	DA	0x0362		; F1+45
	DA	0x0363		; F1+46
	DA	0x0363		; F1+47
	DA	0x0364		; F1+48
	DA	0x0365		; F1+49
	DA	0x0366		; F1+50
	DA	0x0367		; F1+51
	DA	0x0367		; F1+52
	DA	0x0368		; F1+53
	DA	0x0369		; F1+54
	DA	0x036A		; F1+55
	DA	0x036B		; F1+56
	DA	0x036B		; F1+57
	DA	0x036C		; F1+58
	DA	0x036D		; F1+59
	DA	0x036E		; F1+60
	DA	0x036E		; F1+61
	DA	0x036F		; F1+62
	DA	0x0370		; F1+63
	DA	0x0371		; F#1+0
	DA	0x0372		; F#1+1
	DA	0x0372		; F#1+2
	DA	0x0373		; F#1+3
	DA	0x0374		; F#1+4
	DA	0x0375		; F#1+5
	DA	0x0376		; F#1+6
	DA	0x0376		; F#1+7
	DA	0x0377		; F#1+8
	DA	0x0378		; F#1+9
	DA	0x0379		; F#1+10
	DA	0x037A		; F#1+11
	DA	0x037A		; F#1+12
	DA	0x037B		; F#1+13
	DA	0x037C		; F#1+14
	DA	0x037D		; F#1+15
	DA	0x037E		; F#1+16
	DA	0x037E		; F#1+17
	DA	0x037F		; F#1+18
	DA	0x0380		; F#1+19
	DA	0x0381		; F#1+20
	DA	0x0382		; F#1+21
	DA	0x0383		; F#1+22
	DA	0x0383		; F#1+23
	DA	0x0384		; F#1+24
	DA	0x0385		; F#1+25
	DA	0x0386		; F#1+26
	DA	0x0387		; F#1+27
	DA	0x0387		; F#1+28
	DA	0x0388		; F#1+29
	DA	0x0389		; F#1+30
	DA	0x038A		; F#1+31
	DA	0x038B		; F#1+32
	DA	0x038B		; F#1+33
	DA	0x038C		; F#1+34
	DA	0x038D		; F#1+35
	DA	0x038E		; F#1+36
	DA	0x038F		; F#1+37
	DA	0x0390		; F#1+38
	DA	0x0390		; F#1+39
	DA	0x0391		; F#1+40
	DA	0x0392		; F#1+41
	DA	0x0393		; F#1+42
	DA	0x0394		; F#1+43
	DA	0x0395		; F#1+44
	DA	0x0395		; F#1+45
	DA	0x0396		; F#1+46
	DA	0x0397		; F#1+47
	DA	0x0398		; F#1+48
	DA	0x0399		; F#1+49
	DA	0x039A		; F#1+50
	DA	0x039A		; F#1+51
	DA	0x039B		; F#1+52
	DA	0x039C		; F#1+53
	DA	0x039D		; F#1+54
	DA	0x039E		; F#1+55
	DA	0x039F		; F#1+56
	DA	0x039F		; F#1+57
	DA	0x03A0		; F#1+58
	DA	0x03A1		; F#1+59
	DA	0x03A2		; F#1+60
	DA	0x03A3		; F#1+61
	DA	0x03A4		; F#1+62
	DA	0x03A4		; F#1+63
	DA	0x03A5		; G1+0
	DA	0x03A6		; G1+1
	DA	0x03A7		; G1+2
	DA	0x03A8		; G1+3
	DA	0x03A9		; G1+4
	DA	0x03A9		; G1+5
	DA	0x03AA		; G1+6
	DA	0x03AB		; G1+7
	DA	0x03AC		; G1+8
	DA	0x03AD		; G1+9
	DA	0x03AE		; G1+10
	DA	0x03AF		; G1+11
	DA	0x03AF		; G1+12
	DA	0x03B0		; G1+13
	DA	0x03B1		; G1+14
	DA	0x03B2		; G1+15
	DA	0x03B3		; G1+16
	DA	0x03B4		; G1+17
	DA	0x03B5		; G1+18
	DA	0x03B5		; G1+19
	DA	0x03B6		; G1+20
	DA	0x03B7		; G1+21
	DA	0x03B8		; G1+22
	DA	0x03B9		; G1+23
	DA	0x03BA		; G1+24
	DA	0x03BB		; G1+25
	DA	0x03BB		; G1+26
	DA	0x03BC		; G1+27
	DA	0x03BD		; G1+28
	DA	0x03BE		; G1+29
	DA	0x03BF		; G1+30
	DA	0x03C0		; G1+31
	DA	0x03C1		; G1+32
	DA	0x03C1		; G1+33
	DA	0x03C2		; G1+34
	DA	0x03C3		; G1+35
	DA	0x03C4		; G1+36
	DA	0x03C5		; G1+37
	DA	0x03C6		; G1+38
	DA	0x03C7		; G1+39
	DA	0x03C8		; G1+40
	DA	0x03C8		; G1+41
	DA	0x03C9		; G1+42
	DA	0x03CA		; G1+43
	DA	0x03CB		; G1+44
	DA	0x03CC		; G1+45
	DA	0x03CD		; G1+46
	DA	0x03CE		; G1+47
	DA	0x03CF		; G1+48
	DA	0x03CF		; G1+49
	DA	0x03D0		; G1+50
	DA	0x03D1		; G1+51
	DA	0x03D2		; G1+52
	DA	0x03D3		; G1+53
	DA	0x03D4		; G1+54
	DA	0x03D5		; G1+55
	DA	0x03D6		; G1+56
	DA	0x03D7		; G1+57
	DA	0x03D7		; G1+58
	DA	0x03D8		; G1+59
	DA	0x03D9		; G1+60
	DA	0x03DA		; G1+61
	DA	0x03DB		; G1+62
	DA	0x03DC		; G1+63
	DA	0x03DD		; G#1+0
	DA	0x03DE		; G#1+1
	DA	0x03DF		; G#1+2
	DA	0x03DF		; G#1+3
	DA	0x03E0		; G#1+4
	DA	0x03E1		; G#1+5
	DA	0x03E2		; G#1+6
	DA	0x03E3		; G#1+7
	DA	0x03E4		; G#1+8
	DA	0x03E5		; G#1+9
	DA	0x03E6		; G#1+10
	DA	0x03E7		; G#1+11
	DA	0x03E8		; G#1+12
	DA	0x03E8		; G#1+13
	DA	0x03E9		; G#1+14
	DA	0x03EA		; G#1+15
	DA	0x03EB		; G#1+16
	DA	0x03EC		; G#1+17
	DA	0x03ED		; G#1+18
	DA	0x03EE		; G#1+19
	DA	0x03EF		; G#1+20
	DA	0x03F0		; G#1+21
	DA	0x03F1		; G#1+22
	DA	0x03F1		; G#1+23
	DA	0x03F2		; G#1+24
	DA	0x03F3		; G#1+25
	DA	0x03F4		; G#1+26
	DA	0x03F5		; G#1+27
	DA	0x03F6		; G#1+28
	DA	0x03F7		; G#1+29
	DA	0x03F8		; G#1+30
	DA	0x03F9		; G#1+31
	DA	0x03FA		; G#1+32
	DA	0x03FB		; G#1+33
	DA	0x03FC		; G#1+34
	DA	0x03FC		; G#1+35
	DA	0x03FD		; G#1+36
	DA	0x03FE		; G#1+37
	DA	0x03FF		; G#1+38
	DA	0x0400		; G#1+39
	DA	0x0401		; G#1+40
	DA	0x0402		; G#1+41
	DA	0x0403		; G#1+42
	DA	0x0404		; G#1+43
	DA	0x0405		; G#1+44
	DA	0x0406		; G#1+45
	DA	0x0407		; G#1+46
	DA	0x0408		; G#1+47
	DA	0x0409		; G#1+48
	DA	0x0409		; G#1+49
	DA	0x040A		; G#1+50
	DA	0x040B		; G#1+51
	DA	0x040C		; G#1+52
	DA	0x040D		; G#1+53
	DA	0x040E		; G#1+54
	DA	0x040F		; G#1+55
	DA	0x0410		; G#1+56
	DA	0x0411		; G#1+57
	DA	0x0412		; G#1+58
	DA	0x0413		; G#1+59
	DA	0x0414		; G#1+60
	DA	0x0415		; G#1+61
	DA	0x0416		; G#1+62
	DA	0x0417		; G#1+63
	DA	0x0418		; A2+0
	DA	0x0418		; A2+1
	DA	0x0419		; A2+2
	DA	0x041A		; A2+3
	DA	0x041B		; A2+4
	DA	0x041C		; A2+5
	DA	0x041D		; A2+6
	DA	0x041E		; A2+7
	DA	0x041F		; A2+8
	DA	0x0420		; A2+9
	DA	0x0421		; A2+10
	DA	0x0422		; A2+11
	DA	0x0423		; A2+12
	DA	0x0424		; A2+13
	DA	0x0425		; A2+14
	DA	0x0426		; A2+15
	DA	0x0427		; A2+16
	DA	0x0428		; A2+17
	DA	0x0429		; A2+18
	DA	0x042A		; A2+19
	DA	0x042B		; A2+20
	DA	0x042C		; A2+21
	DA	0x042D		; A2+22
	DA	0x042D		; A2+23
	DA	0x042E		; A2+24
	DA	0x042F		; A2+25
	DA	0x0430		; A2+26
	DA	0x0431		; A2+27
	DA	0x0432		; A2+28
	DA	0x0433		; A2+29
	DA	0x0434		; A2+30
	DA	0x0435		; A2+31
	DA	0x0436		; A2+32
	DA	0x0437		; A2+33
	DA	0x0438		; A2+34
	DA	0x0439		; A2+35
	DA	0x043A		; A2+36
	DA	0x043B		; A2+37
	DA	0x043C		; A2+38
	DA	0x043D		; A2+39
	DA	0x043E		; A2+40
	DA	0x043F		; A2+41
	DA	0x0440		; A2+42
	DA	0x0441		; A2+43
	DA	0x0442		; A2+44
	DA	0x0443		; A2+45
	DA	0x0444		; A2+46
	DA	0x0445		; A2+47
	DA	0x0446		; A2+48
	DA	0x0447		; A2+49
	DA	0x0448		; A2+50
	DA	0x0449		; A2+51
	DA	0x044A		; A2+52
	DA	0x044B		; A2+53
	DA	0x044C		; A2+54
	DA	0x044D		; A2+55
	DA	0x044E		; A2+56
	DA	0x044F		; A2+57
	DA	0x0450		; A2+58
	DA	0x0451		; A2+59
	DA	0x0452		; A2+60
	DA	0x0453		; A2+61
	DA	0x0454		; A2+62
	DA	0x0455		; A2+63
	DA	0x0456		; A#2+0
	DA	0x0457		; A#2+1
	DA	0x0458		; A#2+2
	DA	0x0459		; A#2+3
	DA	0x045A		; A#2+4
	DA	0x045B		; A#2+5
	DA	0x045C		; A#2+6
	DA	0x045D		; A#2+7
	DA	0x045E		; A#2+8
	DA	0x045F		; A#2+9
	DA	0x0460		; A#2+10
	DA	0x0461		; A#2+11
	DA	0x0462		; A#2+12
	DA	0x0463		; A#2+13
	DA	0x0464		; A#2+14
	DA	0x0465		; A#2+15
	DA	0x0466		; A#2+16
	DA	0x0467		; A#2+17
	DA	0x0468		; A#2+18
	DA	0x0469		; A#2+19
	DA	0x046A		; A#2+20
	DA	0x046B		; A#2+21
	DA	0x046C		; A#2+22
	DA	0x046D		; A#2+23
	DA	0x046E		; A#2+24
	DA	0x046F		; A#2+25
	DA	0x0470		; A#2+26
	DA	0x0471		; A#2+27
	DA	0x0472		; A#2+28
	DA	0x0473		; A#2+29
	DA	0x0474		; A#2+30
	DA	0x0475		; A#2+31
	DA	0x0476		; A#2+32
	DA	0x0477		; A#2+33
	DA	0x0478		; A#2+34
	DA	0x0479		; A#2+35
	DA	0x047A		; A#2+36
	DA	0x047C		; A#2+37
	DA	0x047D		; A#2+38
	DA	0x047E		; A#2+39
	DA	0x047F		; A#2+40
	DA	0x0480		; A#2+41
	DA	0x0481		; A#2+42
	DA	0x0482		; A#2+43
	DA	0x0483		; A#2+44
	DA	0x0484		; A#2+45
	DA	0x0485		; A#2+46
	DA	0x0486		; A#2+47
	DA	0x0487		; A#2+48
	DA	0x0488		; A#2+49
	DA	0x0489		; A#2+50
	DA	0x048A		; A#2+51
	DA	0x048B		; A#2+52
	DA	0x048C		; A#2+53
	DA	0x048D		; A#2+54
	DA	0x048E		; A#2+55
	DA	0x048F		; A#2+56
	DA	0x0490		; A#2+57
	DA	0x0491		; A#2+58
	DA	0x0493		; A#2+59
	DA	0x0494		; A#2+60
	DA	0x0495		; A#2+61
	DA	0x0496		; A#2+62
	DA	0x0497		; A#2+63
	DA	0x0498		; B2+0
	DA	0x0499		; B2+1
	DA	0x049A		; B2+2
	DA	0x049B		; B2+3
	DA	0x049C		; B2+4
	DA	0x049D		; B2+5
	DA	0x049E		; B2+6
	DA	0x049F		; B2+7
	DA	0x04A0		; B2+8
	DA	0x04A1		; B2+9
	DA	0x04A2		; B2+10
	DA	0x04A4		; B2+11
	DA	0x04A5		; B2+12
	DA	0x04A6		; B2+13
	DA	0x04A7		; B2+14
	DA	0x04A8		; B2+15
	DA	0x04A9		; B2+16
	DA	0x04AA		; B2+17
	DA	0x04AB		; B2+18
	DA	0x04AC		; B2+19
	DA	0x04AD		; B2+20
	DA	0x04AE		; B2+21
	DA	0x04AF		; B2+22
	DA	0x04B0		; B2+23
	DA	0x04B2		; B2+24
	DA	0x04B3		; B2+25
	DA	0x04B4		; B2+26
	DA	0x04B5		; B2+27
	DA	0x04B6		; B2+28
	DA	0x04B7		; B2+29
	DA	0x04B8		; B2+30
	DA	0x04B9		; B2+31
	DA	0x04BA		; B2+32
	DA	0x04BB		; B2+33
	DA	0x04BC		; B2+34
	DA	0x04BE		; B2+35
	DA	0x04BF		; B2+36
	DA	0x04C0		; B2+37
	DA	0x04C1		; B2+38
	DA	0x04C2		; B2+39
	DA	0x04C3		; B2+40
	DA	0x04C4		; B2+41
	DA	0x04C5		; B2+42
	DA	0x04C6		; B2+43
	DA	0x04C7		; B2+44
	DA	0x04C9		; B2+45
	DA	0x04CA		; B2+46
	DA	0x04CB		; B2+47
	DA	0x04CC		; B2+48
	DA	0x04CD		; B2+49
	DA	0x04CE		; B2+50
	DA	0x04CF		; B2+51
	DA	0x04D0		; B2+52
	DA	0x04D1		; B2+53
	DA	0x04D3		; B2+54
	DA	0x04D4		; B2+55
	DA	0x04D5		; B2+56
	DA	0x04D6		; B2+57
	DA	0x04D7		; B2+58
	DA	0x04D8		; B2+59
	DA	0x04D9		; B2+60
	DA	0x04DA		; B2+61
	DA	0x04DB		; B2+62
	DA	0x04DD		; B2+63

;------------------------------------------------------------------------------
; データEEPROM
;------------------------------------------------------------------------------
	ORG	2100H
	;	DTML,TL  ,KSAR,DR  ,SR  ,SLRR,EG
; Preset0 #120 01001F1F000F00017F1F1F000F00017F1F1F000F00017F1F1F000F00000F00000000 Sine
	DE	0x01,0x00,0x1F,0x1F,0x00,0x0F,0x00	; OP4
	DE	0x01,0x7F,0x1F,0x1F,0x00,0x0F,0x00	; OP2
	DE	0x01,0x7F,0x1F,0x1F,0x00,0x0F,0x00	; OP3
	DE	0x01,0x7F,0x1F,0x1F,0x00,0x0F,0x00	; OP1
	DE	0x00,0x0F,255,255			; FB,ALG,SLOT,PAD*2
; Preset1 #121 01001F1F000700017F1F1F000F00017F1F1F000F0001201F0A004700320900000000 Bass
	DE	0x01,0x00,0x1F,0x1F,0x00,0x07,0x00	; OP4
	DE	0x01,0x7F,0x1F,0x1F,0x00,0x0F,0x00	; OP2
	DE	0x01,0x7F,0x1F,0x1F,0x00,0x0F,0x00	; OP3
	DE	0x01,0x20,0x1F,0x0A,0x00,0x47,0x00	; OP1
	DE	0x32,0x09,255,255			; FB,ALG,SLOT,PAD*2
; Preset2 #122 71001F1F080800310A1F1F0A0800011E1F1F0000000E321F1F000000040F00000000 EP
	DE	0x71,0x00,0x1F,0x1F,0x08,0x08,0x00	; OP4
	DE	0x31,0x0A,0x1F,0x1F,0x0A,0x08,0x00	; OP2
	DE	0x01,0x1E,0x1F,0x1F,0x00,0x00,0x00	; OP3
	DE	0x0E,0x32,0x1F,0x1F,0x00,0x00,0x00	; OP1
	DE	0x04,0x0F,255,255			; FB,ALG,SLOT,PAD*2
; Preset3 #123 1100490A0006001114590B0049000428550B002600311E590A0015003A0F00000000 ビオラ
	DE	0x11,0x00,0x49,0x0A,0x00,0x06,0x00	; OP4
	DE	0x11,0x14,0x59,0x0B,0x00,0x49,0x00	; OP2
	DE	0x04,0x28,0x55,0x0B,0x00,0x26,0x00	; OP3
	DE	0x31,0x1E,0x59,0x0A,0x00,0x15,0x00	; OP1
	DE	0x3A,0x0F,255,255			; FB,ALG,SLOT,PAD*2
; Preset4 #124 01001F1F06060002195F0C0A760001231F1F00060008321F1F000600030F00000000 琴
	DE	0x01,0x00,0x1F,0x1F,0x06,0x06,0x00	; OP4
	DE	0x02,0x19,0x5F,0x0C,0x0A,0x76,0x00	; OP2
	DE	0x01,0x23,0x1F,0x1F,0x00,0x06,0x00	; OP3
	DE	0x08,0x32,0x1F,0x1F,0x00,0x06,0x00	; OP1
	DE	0x03,0x0F,255,255			; FB,ALG,SLOT,PAD*2
; Preset5 #125 0100101F000900011E1F1F100100013C101F000700020C1F1F10A6003B0F00000000 フルート
	DE	0x01,0x00,0x10,0x1F,0x00,0x09,0x00	; OP4
	DE	0x01,0x1E,0x1F,0x1F,0x10,0x01,0x00	; OP2
	DE	0x01,0x3C,0x10,0x1F,0x00,0x07,0x00	; OP3
	DE	0x02,0x0C,0x1F,0x1F,0x10,0xA6,0x00	; OP1
	DE	0x3B,0x0F,255,255			; FB,ALG,SLOT,PAD*2
; Preset6 #126 02001F0F00F5000F321F1300AF0007321F0F00A5000F1E1F1300AF003B0F00000000 FLEXATONE
	DE	0x02,0x00,0x1F,0x0F,0x00,0xF5,0x00	; OP4
	DE	0x0F,0x32,0x1F,0x13,0x00,0xAF,0x00	; OP2
	DE	0x07,0x32,0x1F,0x0F,0x00,0xA5,0x00	; OP3
	DE	0x0F,0x1E,0x1F,0x13,0x00,0xAF,0x00	; OP1
	DE	0x3B,0x0F,255,255			; FB,ALG,SLOT,PAD*2
; Preset7 #127 01001F1F000F00017F1F1F000F00017F1F1F000F00011F1F1F000F003A0900000000 SAW
	DE	0x01,0x00,0x1F,0x1F,0x00,0x0F,0x00	; OP4
	DE	0x01,0x7F,0x1F,0x1F,0x00,0x0F,0x00	; OP2
	DE	0x01,0x7F,0x1F,0x1F,0x00,0x0F,0x00	; OP3
	DE	0x01,0x1F,0x1F,0x1F,0x00,0x0F,0x00	; OP1
	DE	0x3A,0x09,255,255			; FB,ALG,SLOT,PAD*2

	END