PICのソースです。 MIDI Trigger Converter MIDI入力 [楽器]
PIC16F84のソース(βバージョン?)を下に示しておきましょう
とりあえず動きますが、わからないデータが来た場合無視するようにしてあります。
出力と違って、入力は大変ですよね。
回路は単純ですので、
portAのbit0をMIDIの入力に
portAのbit2をMIDIの出力に
portAのbit3をstatusLEDに
portB0~7bitはトリガ主力用に
回路図は、
前回の写真とは若干異なりますが、上の様な感じでOKと思います。
バッファのLS245(HCT245)は必要ないかもしれませんが、手持ちにあったので組み込んでみました。
(一応、商用以外でしたら自由にご使用いただいてかまいません。リンクはして頂くとうれしいですね。)
長いので、追記に記入しました。
出力するトリガーは可変に出来るのですが、4MHzでは速度的に厳しいのでベェロシティによらず一定にしてあります。
何かのお役に立ちましたらどうぞ。
とりあえず動きますが、わからないデータが来た場合無視するようにしてあります。
出力と違って、入力は大変ですよね。
回路は単純ですので、
portAのbit0をMIDIの入力に
portAのbit2をMIDIの出力に
portAのbit3をstatusLEDに
portB0~7bitはトリガ主力用に
回路図は、
前回の写真とは若干異なりますが、上の様な感じでOKと思います。
バッファのLS245(HCT245)は必要ないかもしれませんが、手持ちにあったので組み込んでみました。
(一応、商用以外でしたら自由にご使用いただいてかまいません。リンクはして頂くとうれしいですね。)
長いので、追記に記入しました。
出力するトリガーは可変に出来るのですが、4MHzでは速度的に厳しいのでベェロシティによらず一定にしてあります。
何かのお役に立ちましたらどうぞ。
; =========================== ここから =============================== LIST P=16F84 #includeLIST 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信号を受け取る) ; 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 ; プログラムの終了をアセンブラに指示する ; =========================== ここまで ===============================
コメント 0