やっとのことで・・・
MIDI Trigger Converterのプログラムを発掘したのでご紹介します。
商用利用される場合はご連絡下さい。それ以外ではご自由にどうぞ。
(申し訳ございませんがサポートは期待されないでください、汗)
(ブログにコピーするときに、
文字化けしているかもしれないのでそのままでは動作しません。
修正をお願いいたします。
<、>、はそれぞれ小文字に変換してください。)
; =========================== ここから ===============================
LIST P=16F84
#include <p16F84.inc>
LIST r=dec ;10進数を定数とする
__CONFIG _CP_OFF & _HS_OSC & _PWRTE_ON & _WDT_OFF
;_CP_OFF コードプロテクトしない
;_HS_OSC 4MHz~20MHz(水晶振動子orセラミック振動子 4MHzで計算
;_PWRTE_ON パワーアップタイマ有効
;_WDT_OFF ウォッチドックタイマ無効
;---------------------------------------------------------------
;アドレスに名前を付ける
;
; GPR 0x0C~0x4F を使用可能(SFR 0x00~0x0Bまではシステム用)
;---------------------------------------------------------------
temp2 equ 0x0E
temp equ 0x10
xmit equ 0x11
i equ 0x12
j equ 0x13
k equ 0x14
rmit equ 0x18
statusData equ 0x19
noteData equ 0x1A
veloData equ 0x1B
triger0 equ 0x20
triger1 equ 0x21
triger2 equ 0x22
triger3 equ 0x23
triger4 equ 0x24
triger5 equ 0x25
triger6 equ 0x26
triger7 equ 0x27
INDEX equ 0x28
statusLED equ 0x2F
statusLED2 equ 0x2E
;***************************************************************
;リセットベクタ
;***************************************************************
org 0
goto start
;***************************************************************
;割り込みベクタ
;***************************************************************
org 4
;***************************************************************
;スタート
;***************************************************************
start
;---------------------------------------------------------------
;ポートの設定
;---------------------------------------------------------------
clrf PORTA
clrf PORTB
bsf STATUS,RP0 ;ページを1に切り替え
movlw B'00000001'
movwf TRISA ;portA(bit0~4)を0Bitのみ入力に設定 H=入力 (bit4のみ=オープンドレイン)
movlw B'00000000'
movwf TRISB ;portB(bit0~7)を全て出力に設定
;portAのbit0をMIDIの入力に
;portAのbit2をMIDIの出力に
;portAのbit3をstatusLEDに
;portBはトリガ主力用に
;---------------------------------------------------------------
;変数初期化
;---------------------------------------------------------------
bcf STATUS,RP0 ;ページを0に切り替え
bsf PORTA,2 ;ストップビットを初期状態?
bcf PORTA,3 ;statusLED消灯
movlw 0x00
movwf triger0 ;Snare_Drum
movwf triger1 ;Stick
movwf triger2 ;Kick_Drum
movwf triger3 ;Cymbal1
movwf triger4 ;Low_Tom
movwf triger5 ;High_Tom
movwf triger6 ;Closed_HiHat
movwf triger7 ;Open_HiHat
movlw 0xFF
movwf statusLED
bsf PORTA,3 ;statusLED点灯
;***************************************************************
;メイン
;***************************************************************
main
;startbitの検出
btfss PORTA,0 ;1μs 1(2) fのbビット目が1だったら次命令スキップ
goto status_get ;3μs
;----------MIDIスルーのテスト--↓---------
; btfsc PORTA,0 ;1μs 1(2) fのbビット目がLoだったら次命令スキップ
; goto led_
; call getmidi
; goto throughout
;-------------------------↑---------
;トリガー出力
movlw 0 ;1μs
movwf temp ;2
bcf STATUS,C ;3 キャリークリア
rrf triger0,f ;4 PORTAの内容を右に1ビットシフトして最下位(bit0)のあふれをSTATUSのCに入れる
rrf temp,f ;5
rrf triger1,f ;6
rrf temp,f ;7
rrf triger2,f ;8
rrf temp,f ;9
rrf triger3,f ;10
rrf temp,f ;11
rrf triger4,f ;12
rrf temp,f ;13
rrf triger5,f ;14
rrf temp,f ;15
rrf triger6,f ;16
rrf temp,f ;17
rrf triger7,f ;18
rrf temp,w ;19
;トリガーを出力 20μS+2μS = 32μS以下だけどギリギリかな?
movwf TRISB ;20
;startbitの検出
btfss PORTA,0 ;1μs 1(2) fのbビット目が1だったら次命令スキップ
goto status_get ;3μs
movlw 20 ;Y = 3*X + 1
movwf temp ;3*5+3 = 18μs
main1
;startbitの検出
btfss PORTA,0 ;1μs 1(2) fのbビット目が1だったら次命令スキップ
goto status_get ;3μs
decfsz temp,f
goto main1
;最終的なトリガーは
; (22+22*20)μS~(22+22*20)×7μS = 462μS~3234μS = 0.0005~0.003s
;
;LEDを点滅がしている時は待機中
led_
decfsz statusLED,w
goto led_on
led_off
bcf PORTA,3 ;statusLED消灯
decfsz statusLED2,w
goto led_on1
led_off1
movlw 0xFF
movwf statusLED
goto led_on2
led_on
decf statusLED,f
bsf PORTA,3 ;statusLED点灯
movlw 0xFF
movwf statusLED2
led_on1
decf statusLED2,f
led_on2
goto main ;2
status_get
;ステータスをゲット
call getmidi ;4μs getmidi関数を呼び込み(midi信号を受け取る)
; rmitにデータが入る
btfss statusData,7 ;5μs 1(2) fのbビット目が1だったら次命令スキップ
goto data_byte ;7μs
status_byte
;Microsoft GS Wavetable SW Synth ドラムセット 0x99 or 0x89
movlw 0x01 ;5
movwf statusLED ;6
movlw 0xFF ;7
movwf statusLED2 ;8
bcf PORTA,3 ;9 statusLED消灯
movfw statusData ;10μs
sublw 0x99 ;11μs ノートオン
btfsc STATUS,Z ;12μs 1(2)
goto note_on ;14μs 2
movfw statusData ;14μs
sublw 0x89 ;15μs ノートオフ
btfsc STATUS,Z ;16μs 1(2)
goto note_off ;18μs 2
;ドラムセットのノートオン、オフ以外はスルー出力
; それでも32μs以上は無理
;
throughout
bsf PORTA,2 ;RA2をmidi出力
movfw statusData
movwf xmit
call sendmidi ;sendmidi関数を呼び込み(midi信号を送る)
movfw noteData
movwf xmit
call sendmidi ;sendmidi関数を呼び込み(midi信号を送る)
movfw veloData
movwf xmit
call sendmidi ;sendmidi関数を呼び込み(midi信号を送る)
goto main ; 2
data_byte
;いきなりデーターバイト = ステータスがなければ無視 取りこぼしetc?
goto main
;---------------------------------------------------------------
;SUBルーチン
;---------------------------------------------------------------
note_off ;18μs
;とりあえずノートオフは無視
goto main
note_on
;14μs
org 0x0200 ;TABLE_LOOKUPルーチンのアドレス0x200H
TABLE_LOOKUP
movlw 31
subwf noteData,w ;
andlw B'00011111'
movwf INDEX ;Wレジスタよりインデックス値
movlw LOW(TABLE) ;テーブル開始の下位アドレス
addwf INDEX,F ;下位アドレスとインデックスを加算
movlw HIGH(TABLE) ;テーブル開始の上位アドレス
movwf PCLATH ;上位アドレスをPCLATHに代入
btfsc STATUS,C ;キャリフラグが1なら
incf PCLATH,F ;上位アドレス(PCLATH)へ桁上がりあり
movfw INDEX ;インデックスをWレジスタへ
movwf PCL ; ↑ ジャンプテーブルへ飛ぶ テーブルのgotoで
;---------------------------------------------------------------
TABLE
;ノートナンバーは31から考慮 0~31 b'00011111'
goto Sticks ;31 1
; goto Square_Click ;32
; goto Metronome_Click ;33
; goto Metronome_Bell ;34
goto Sticks ;32 2
goto Sticks ;33 3
goto Sticks ;34 4
goto Kick_Drum2 ;35 5
goto Kick_Drum1 ;36 6
goto Side_Stick ;37 7
goto Snare_Drum1 ;38 8
goto Hand_Clap ;39 9
goto Snare_Drum2 ;40 10
goto Low_Tom2 ;41 11
goto Closed_HiHat ;42 12
goto Low_Tom1 ;43 13
goto Pedal_HiHat ;44 14
goto Mid_Tom2 ;45 15
goto Open_HiHat ;46 16
goto Mid_Tom1 ;47 17
goto High_Tom2 ;48 18
goto Crash_Cymbal1 ;49 19
goto High_Tom1 ;50 20
; goto Ride_Cymbal1 ;51
; goto Chinese_Cymbal ;52
; goto Ride_Bell ;53
goto Crash_Cymbal1 ;51 21
goto Crash_Cymbal1 ;52 22
goto Crash_Cymbal1 ;53 23
; goto Tambourine ;54
goto Snare_Drum1 ;54 24
; goto Splash_Cymbal ;55
goto Crash_Cymbal1 ;55 25
; goto Cowbell ;56
goto High_Tom1 ;50 26
; goto Crash_Cymbal2 ;57
goto Crash_Cymbal1 ;55 27
; goto Vibra_Slap ;58
; goto Ride_Cymbal2 ;59
goto Crash_Cymbal1 ;55 28
goto Crash_Cymbal1 ;55 29
; goto High_Bongo ;60
; goto Low_Bongo ;61
goto High_Tom1 ;50 30
goto Low_Tom1 ;43 31
; goto Mute_HighConga ;62
; goto Open_HighConga ;63
goto High_Tom1 ;50 32
goto Low_Tom1 ;43 33
; goto Low_Conga ;64 34
; goto High_Timbale ;65 35
; goto Low_Timbale ;66 36
; goto High_Agogo ;67 37
org 0x0280
Sticks ;NO.31
movlw 0x7f
movwf triger1
goto main
movlw 0xff ;1μs max 3+4+7*5=42μs +ここ以前の17μs = 59μsで取りこぼすかもね?
movwf triger1 ;2μs
bsf veloData,0 ;3μs
Sticks1
rlf veloData,f ;1μs
btfsc STATUS,C ;2μs 1(2) STATUSのCが0ならば、gotoをスキップ、1ならばgoto
goto main ;4μs
rrf triger1,f ;4μs
goto Sticks1 ;5μs
Side_Stick ;NO.37
goto Sticks ;5μs
Snare_Drum1 ;NO.38
movlw 0x7f
movwf triger0
goto main
movlw 0xff ;1μs max 3+4+7*5=42μs +ここ以前の17μs = 59μsで取りこぼすかもね?
movwf triger0 ;2μs
bsf veloData,0 ;3μs
Snare_Drum11
rlf veloData,f ;1μs
btfsc STATUS,C ;2μs 1(2) STATUSのCが0ならば、gotoをスキップ、1ならばgoto
goto main ;4μs
rrf triger0,f ;4μs
goto Snare_Drum11;5μs
Snare_Drum2 ;NO.40
goto Snare_Drum1 ;2μs
Kick_Drum2 ;NO.35
movlw 0x7f
movwf triger2
goto main
movlw 0xff ;1μs max 3+4+7*5=42μs +ここ以前の17μs = 59μsで取りこぼすかもね?
movwf triger2 ;2μs
bsf veloData,0 ;3μs
Kick_Drum21
rlf veloData,f ;1μs
btfsc STATUS,C ;2μs 1(2) STATUSのCが0ならば、gotoをスキップ、1ならばgoto
goto main ;4μs
rrf triger2,f ;4μs
goto Kick_Drum21 ;5μs
Kick_Drum1 ;NO.36
goto Kick_Drum2 ;2μs
Low_Tom2 ;NO.41
movlw 0x7f
movwf triger4
goto main
movlw 0xff ;1μs max 3+4+7*5=42μs +ここ以前の17μs = 59μsで取りこぼすかもね?
movwf triger4 ;2μs
bsf veloData,0 ;3μs
Low_Tom21
rlf veloData,f ;1μs
btfsc STATUS,C ;2μs 1(2) STATUSのCが0ならば、gotoをスキップ、1ならばgoto
goto main ;4μs
rrf triger4,f ;4μs
goto Low_Tom21 ;5μs
Low_Tom1 ;NO.43
goto Low_Tom2
Mid_Tom2 ;NO.45
goto Low_Tom2
Mid_Tom1 ;NO.47
movlw 0x7f
movwf triger5
goto main
movlw 0xff ;1μs max 3+4+7*5=42μs +ここ以前の17μs = 59μsで取りこぼすかもね?
movwf triger5 ;2μs
bsf veloData,0 ;3μs
Mid_Tom11
rlf veloData,f ;1μs
btfsc STATUS,C ;2μs 1(2) STATUSのCが0ならば、gotoをスキップ、1ならばgoto
goto main ;4μs
rrf triger5,f ;4μs
goto Mid_Tom11 ;5μs
High_Tom2 ;NO.48
goto Mid_Tom1 ;2μs
High_Tom1 ;NO.50
goto Mid_Tom1 ;2μs
Closed_HiHat;NO.42
movlw 0x7f
movwf triger6
goto main
movlw 0xff ;1μs max 3+4+7*5=42μs +ここ以前の17μs = 59μsで取りこぼすかもね?
movwf triger6 ;2μs
bsf veloData,0 ;3μs
Closed_HiHat1
rlf veloData,f ;1μs
btfsc STATUS,C ;2μs 1(2) STATUSのCが0ならば、gotoをスキップ、1ならばgoto
goto main ;4μs
rrf triger6,f ;4μs
goto Closed_HiHat1;5μs
Pedal_HiHat ;NO.44
goto Closed_HiHat;2μs
Open_HiHat ;NO.46
movlw 0x7f
movwf triger7
goto main
movlw 0xff ;1μs max 3+4+7*5=42μs +ここ以前の17μs = 59μsで取りこぼすかもね?
movwf triger7 ;2μs
bsf veloData,0 ;3μs
Open_HiHat1
rlf veloData,f ;1μs
btfsc STATUS,C ;2μs 1(2) STATUSのCが0ならば、gotoをスキップ、1ならばgoto
goto main ;4μs
rrf triger7,f ;4μs
goto Open_HiHat1 ;5μs
Crash_Cymbal1;NO.49
movlw 0x7f
movwf triger3
goto main
movlw 0xff ;1μs max 3+4+7*5=42μs +ここ以前の17μs = 59μsで取りこぼすかもね?
movwf triger3 ;2μs
bsf veloData,0 ;3μs
Crash_Cymbal11
rlf veloData,f ;1μs
btfsc STATUS,C ;2μs 1(2) STATUSのCが0ならば、gotoをスキップ、1ならばgoto
goto main ;4μs
rrf triger3,f ;4μs
goto Crash_Cymbal11;5μs
Ride_Cymbal1;NO.51
goto Crash_Cymbal1;2μs
Hand_Clap ;NO.39
goto Crash_Cymbal1;2μs
Tambourine ;NO.54
goto Crash_Cymbal1;2μs
;---------------------------------------------------------------
;ウエイト 1=1/40000=0.25μs 1命令4クロック=1μS 20μs程度
;---------------------------------------------------------------
wait_loop
movlw 5 ;Y = 3*X + 3 (return含む)
movwf temp2 ;3*5+3 = 18μs
wait_loop1
decfsz temp2,f
goto wait_loop1
return
;---------------------------------------------------------------
; MIDI ショートメッセージ入力ルーチン
;---------------------------------------------------------------
; スタートビットは論理0、ストップビットは論理1
; 5mAのカレントループとし論理0が電流が流れている状態
;
; 初めがHI? startbit(LO) → 0bit→1、2、3、4、5、6、7bit stopbit(HI)
;
; start 0 1 2 3 4 5 6 7 stop ←0bitが先に来る
; ――――――__ ― ― ― ― ― ― ― ― ――――――
;
;4MHzバージョン
;1/40000=0.25μs 1命令4クロック=1μS 1命令サイクル1μs
;MIDI 1bit=32μS
;
; bcf STATUS,RP0 ;STATUSの 5をクリア(0) → バンク0
;
; call getmidi ;2μs getmidi関数を呼び込み(midi信号を受け取る)
; statusData
; noteData
; veloData にデータが入る
getmidi
;____________startbit_______________
btfsc PORTA,0 ;2μs 1(2) fのbビット目がゼロだったら次命令スキップ
goto getmidi
startb_0
movlw 9 ;Y = 3 * X + 1
;X=9 28μs消費
movwf temp
loop_01
decfsz temp,f
goto loop_01 ;end delay
movlw 8 ; midi信号は8ビット
;31μs 1
movwf j ;32μs 1
;____________ここまでは_______________
getloop_0
;8Bit巡回シフト命令で1バイトを入力
rrf PORTA,w ;PORTAの内容を右に1ビットシフトして最下位(bit0)のあふれをSTATUSのCに入れる 答えはWに
;1μs 1
rrf statusData,f ;STATUSのCとrmitの内容を合せて右に1ビットシフト
;2μs 1
movlw 8 ;Y = 3 * X + 1 X=8 27μs消費
movwf temp
loop_02
decfsz temp,f ; 1*(X-1)+2
goto loop_02 ; 2*(X-1)
nop ;28μs
nop ;29μs
decfsz j,f ;30μs 1(2)
goto getloop_0 ;32μs 2
nop ;32μs 1
stopb_0
;____________stopbit_______________
;ストップビットが来たらリターン
loop_03
btfss PORTA,0 ;fのbビット目が1だったら次命令スキップ
goto loop_03
; return ;2μs
getmidi_1
;____________startbit_______________
btfsc PORTA,0 ;2μs 1(2) fのbビット目がゼロだったら次命令スキップ
goto getmidi_1
startb_1
movlw 10 ;Y = 3 * X + 1
;X=10 31μs消費
movwf temp
loop_11
decfsz temp,f
goto loop_11 ;end delay
movlw 8 ; midi信号は8ビット
;31μs 1
movwf j ;32μs 1
;____________ここまでは_______________
getloop_1
;8Bit巡回シフト命令で1バイトを入力
rrf PORTA,w ;PORTAの内容を右に1ビットシフトして最下位(bit0)のあふれをSTATUSのCに入れる 答えはWに
;1μs 1
rrf noteData,f ;STATUSのCとrmitの内容を合せて右に1ビットシフト
;2μs 1
movlw 8 ;Y = 3 * X + 1 X=8 27μs消費
movwf temp
loop_12
decfsz temp,f ; 1*(X-1)+2
goto loop_12 ; 2*(X-1)
nop ;28μs
nop ;29μs
decfsz j,f ;30μs 1(2)
goto getloop_1 ;32μs 2
nop ;32μs 1
stopb_1
btfss noteData,7 ;fのbビット目が1だったら次命令スキップ
goto loop_13
movfw noteData ;ステータスバイトだった(取りこぼしてずれた???)
movwf statusData
goto loop_03
;____________stopbit_______________
;ストップビットが来たらリターン
loop_13
btfss PORTA,0 ;fのbビット目が1だったら次命令スキップ
goto loop_13
; return ;2μs
getmidi_2
;____________startbit_______________
btfsc PORTA,0 ;2μs 1(2) fのbビット目がゼロだったら次命令スキップ
goto getmidi_2
startb_2
movlw 10 ;Y = 3 * X + 1
;X=10 31μs消費
movwf temp
loop_21
decfsz temp,f
goto loop_21 ;end delay
movlw 8 ; midi信号は8ビット
;31μs 1
movwf j ;32μs 1
;____________ここまでは_______________
getloop_2
;8Bit巡回シフト命令で1バイトを入力
rrf PORTA,w ;PORTAの内容を右に1ビットシフトして最下位(bit0)のあふれをSTATUSのCに入れる 答えはWに
;1μs 1
rrf veloData,f ;STATUSのCとrmitの内容を合せて右に1ビットシフト
;2μs 1
movlw 8 ;Y = 3 * X + 1 X=9 25μs消費
movwf temp
loop_22
decfsz temp,f ; 1*(X-1)+2
goto loop_22 ; 2*(X-1)
nop ;28μs
nop ;29μs
decfsz j,f ;30μs 1(2)
goto getloop_2 ;32μs 2
nop ;32μs 1
stopb_2
btfss veloData,7 ;fのbビット目が1だったら次命令スキップ
goto loop_23
movfw veloData ;ステータスバイトだった(取りこぼしてずれた???)
movwf statusData
goto loop_03
;____________stopbit_______________
;ストップビットが来たらリターン
loop_23
btfss PORTA,0 ;fのbビット目が1だったら次命令スキップ
goto loop_23
return ;2μs
;---------------------------------------------------------------
; MIDI バイト出力ルーチン
;---------------------------------------------------------------
;自作電子楽器ノブログ http://toucylab.exblog.jp/4256675/ さんの流用です
;
; bcf STATUS,RP0 ; STATUSの 5をクリア(0) → バンク0
; bsf PORTA,2 ;RA2をmidi出力
;
; movlw 90h ; ノートオン、チャンネル1
; movwf xmit ;xmitに10010000(Ox90)を格納
; call sendmidi ;sendmidi関数を呼び込み(midi信号を送る)
;のように使用します
;
;4MHzバージョン
;ウエイト 1=1/40000=0.25μs 1命令4クロック=1μS
;MIDIは1ビット32μS = 1/31250bit (31.25Kbit/sec)
; なので32μSでループを終らせる
;
; 1バイト出力するのに 32μS * 10bit ≒ 320μS
; したがって1MIDIショートメッセージ(3バイト)でおよそ1ms必要
;
sendmidi
starta_
bcf PORTA,2 ; スタートビット
movlw 7 ;Y = 3 * X + 1 X=7 22μs消費
movwf temp
loop1_
decfsz temp,f
goto loop1_ ;end delay
nop ;23μs
movlw 8 ; midi信号は8ビット
;24μs
movwf j ;25μs
sendloop_
rrf xmit,f ; xmitの内容を右に1ビットシフトしてSTATUSのCに入れる
;26μs
btfsc STATUS,C ; STATUSのCが0ならば、gotoをスキップ、1ならばgoto
;27μs
goto send1_ ;29μs
send0_
nop ;29μs
nop ;30μs
nop ;31μs
bcf PORTA,2 ;0ビットを送る 32μs
goto endloop_ ;2μs
send1_
nop ;30μs
nop ;31μs
bsf PORTA,2 ;1ビットを送る 32μs
nop ;1μs
nop ;2μs
endloop_
nop ;3μs
movlw 6 ;Y = 3 * X + 1 X=6 19μs消費
movwf temp
loop2_
decfsz temp,f ; 1*(X-1)+2
goto loop2_ ; 2*(X-1)
decfsz j,f ;23μs
goto sendloop_ ;25μs
stopb_
nop ;28μs
nop ;29μs
nop ;30μs
nop ;31μs
bsf PORTA,2 ; ストップビット 32μs
movlw 9 ; Y = 3 * X + 1 + 2(return)
;X=9 30μs消費
movwf temp
loop3_
decfsz temp,f
goto loop3_ ; end delay
return ;2μs以上( call + α )を他で消費するのでちょうど?
;---------------------------------------------------------------
END
; プログラムの終了をアセンブラに指示する
; =========================== ここまで ===============================