PiSTARTERをMIDI音源にするテスト Part.1
1.はじめに
PiSTARTERでMIDIメッセージを受信できるようになったので、PiSTARTERのSOUND命令で音を鳴らしてみました!( ゚∀゚)
今のところ、下記のような制限がありますが、一応鳴るようになりました(*´▽`*)
2.準備
前回とほぼ同じです。
- USB-MIDI入力デバイスをRaspberryPiに繋ぎます。
- PCとRaspberryPiをMIDIケーブルでつなぎます。
- RaspberryPiのUARTのTX(8番ピン:GPIO14)とRX(10番ピン:GPIO15)をジャンパー線でつなぎます。
3.PiSTARTER(smilebasic)のプログラム
PiSTARTERで下記のプログラムを実行して、PCのMIDI再生ソフトを使ってPCからRaspberryPiにMIDI信号を送ると、PiSTARTER側で音が鳴ります。対応しているMIDIメッセージは以下の通りです。
' 'PiSTARTERをMIDI音源にするテスト by みなつ ' option strict '画面初期化 acls var gw=1280,gh=1024 'GRP Width,Height var sw=1280/4,sh=720/4 'SCREEN Width,Height xscreen sw,sh '以前に起動したプロセスがあればkillする var dq$=chr$(&h22) ?system$("sudo /bin/sh -c "+dq$+"/bin/ps auxww|/bin/grep '/bin/cp /dev/snd/midiC1D0'|/bin/grep -v grep|/usr/bin/awk '{print \$2}'|/usr/bin/xargs -r /bin/kill"+dq$) 'MIDIメッセージをシリアルに出力するプロセスをバックグラウンドで起動 ?system$("sudo /bin/sh -c '/usr/bin/nohup /bin/cp /dev/snd/midiC1D0 /dev/serial0 > /dev/null 2>&1 &'") 'シリアルポートをスタート uartstart 4000000 '変数定義 var i dim rx[1024] 'UART受信バッファ var s 'UARTからの受信サイズ var KR$=chr$(&h1c),KL$=chr$(&h1d),KU$=chr$(&h1e),KD$=chr$(&h1f) 'ピアノロール表示パラメータ var gw2=gw/4,gh8=gh/8 dim mute[16] dim chCol[16] dim chR[16],chG[16],chB[16] for i=0 to 15 var br=255-64-((i>>3) and 1)*64 var r=((i>>2) and 1)*255 var g=((i>>1) and 1)*255 var b=((i>>0) and 1)*255 chR[i]=r+br chG[i]=g+br chB[i]=b+br chCol[i]=rgb(r+br,g+br,b+br) next var ox=0,last_cnt gpage 0,1 sppage 1 'MIDIのパート情報 dim chVol[16]:fill chVol,127 dim sndCh[16] dim sndVel[16] dim sndNote[16] while true '0〜9、a〜fで、指定チャネルの表示/非表示切り替え var k$=inkey$() if k$!="" then var m=instr("0123456789abcdef",k$) if m!=-1 then mute[m]=!mute[m] endif endif 'UARTからMIDIメッセージを受信 uartrecv rx out s for i=0 to s-1 if !(rx[i] and &h80) then continue 'データバイトをスキップ var cmd=rx[i] and &hf0 var ch=rx[i] and &hf var note=rx[i+1] var vel=rx[i+2] var gx=(ch div 8)*gw2+ox var gy=(ch mod 8)*gh8 if cmd==&h90 || cmd==&h80 then '&h8n [note] [velocity] (nはチャンネル番号):ノートOFF '&h9n [note] [velocity] (nはチャンネル番号):ノートON vel=vel*chVol[ch]/127*!!(cmd==&h90) if ch!=9 then noteOn ch,note,vel 'ドラムパートはひとまず無視 elseif cmd==&hb0 then if note==&h78 || note==&h7b then '&hBn &h78 (nはチャンネル番号):オールサウンドオフ '&hBn &h7B (nはチャンネル番号):オールノートオフ allOff elseif note==&h7 then '&hb0 &h07 vol:チャンネルボリューム chVol[ch]=vel endif endif next '描画位置を1ドット右に変更し、画面を1ドット左にスクロール var cnt=maincnt if last_cnt!=cnt then last_cnt=cnt view_scroll (ox+2) mod gw2 gline ox,0,ox,gh-1,0 gline gw2+ox,0,gw2+ox,gh-1,0 for i=0 to 15 note=sndNote[i] if !note then continue ch=sndCh[i] vel=sndVel[i] var v=vel/127 gpset ox,gh8-1-note,rgb(chR[ch]*v,chG[ch]*v,chB[ch]*v)*!!v next var nx=(ox+1) mod gw2 ' gcopy ox,0,ox,gh-1,nx,0,1 ' gcopy gw2+ox,0,gw2+ox,gh-1,gw2+nx,0,1 ox=nx endif soundStep wend '画面(スプライト)を指定位置にスクロール def view_scroll x var sclX=sw/gw2 var ch for ch=0 to 0 var sp=ch*2 if mute[ch] then if spused(sp) then sphide sp if spused(sp+1) then sphide sp+1 continue endif var gx=(ch div 8)*gw2 var gy=(ch mod 8)*gh8 spset sp,gx+x,gy,gw2-x,gh8,1+#spadd spofs sp,0,0 spcolor sp,rgb(200,255,255,255) spscale sp,sclX,sh/gh8 if x>0 then spset sp+1,gx,gy,x,gh8,1+#spadd spofs sp+1,(gw2-x)*sclX,0 spcolor sp+1,rgb(200,255,255,255) spscale sp+1,sclX,sh/gh8 else if spused(sp+1) then sphide sp+1 endif next end def noteOn ch,note,vel var i for i=0 to 15 if sndNote[i]==note && sndCh[i]==ch then break next ' if i==16 then ' for i=0 to 15 ' if sndNote[i]==0 then break ' next ' endif if i==16 then var minVel=sndVel[0],minI=0 for i=1 to 15 if sndVel[i]>24) and 255 sound ch*8+2,(R%>>16) and 255 sound ch*8+1,(R%>> 8) and 255 sound ch*8+0,R% and 255 end def vol ch,v sound ch*8+4,v end