みなつ@プチコン

BASICでゲームが作れるWiiU/3DS用ソフト「プチコン」のブログです(*´▽`*)

PiSTARTERでUARTをループバックさせて、MIDIメッセージを入力するテスト Part.1

1.仕組み

RaspberryPiのUART出力ピン(TX)とUART入力ピン(RX)を電気的につないで、UARTに出力された文字を、そのままUARTで受信(ループバック)できるようにしておきます。その状態で、Linuxの aseqdump というMIDI-INからのメッセージをダンプするコマンドの出力をUARTに送信すると、PiSTARTERのUARTRECVコマンドで受信できちゃうのです!ヾ(*´∀`*)ノ

ただし、今回試した方法ではaseqdumpのテキスト出力を使用しているため、遅延がかなりあります(´・ω・`)

テキスト形式ではなくバイナリのままMIDIメッセージを受信すれば遅延は改善されると思いますが、それは今後の課題ということで(*ノノ)

 

 2.準備

  • USB-MIDIキーボードをPiSTARTERに繋ぎます。
  • RaspberryPiのUARTのTX(8番ピン:GPIO14)とRX(10番ピン:GPIO15)をジャンパー線でつなぎます。

    f:id:tksm372:20190103024456p:plain

  • PiSTARTERをquitでいったん抜けて、以下のコマンドを実行します。
    aseqdump -p ポート番号 > /dev/serial0 &
    (最後の&を忘れずに。ポート番号は、aseqdump -l で確認できます。)

    f:id:tksm372:20190103102103p:plain

  • 以下のコマンドを実行して、PiSTARTERを起動します。
    smilebasic

3.PiSTARTER(smilebasic)のプログラム

以下のプログラムを実行すると、USB-MIDIキーボードで押した鍵盤の音が、PiSTARTERから鳴ります。カーソルキーの上下で、音色番号(256~383)を変更可能です。

'
'UARTからMIDIメッセージを受信するテスト by みなつ
'
option strict
acls

var KR$=chr$(&h1c),KL$=chr$(&h1d),KU$=chr$(&h1e),KD$=chr$(&h1f)
var cr=&h0d,lf=&h0a
var z=asc("0")

var i
dim rx[80] 'UART受信バッファ
var s,l$ 'UARTからの受信サイズと、1行バッファ

'音色番号
var tone=256

'ノート番号と音符の対応表を作成
dim nn$[12]
copy nn$,@nn,12
@nn:data "C","C+","D","D+","E","F","F+","G","G+","A","A+","B"

dim note$[128]
for i=0 to 127
 var o=(i div 12)-1
 note$[i]=format$("O%d %s",o,nn$[i mod 12])
next

'シリアルポートをスタート
uartstart 4000000

while true
 'カーソルキーの上下で音色番号を変更
 var k$=inkey$()
 if k$!="" then
  var tt=tone
  inc tt,(k$==KU$)-(k$==KD$)
  if tt!=tone then tone=tt:?format$("tone=%d",tone)
 endif
 
 'UARTからaseqdumpコマンドの出力を受信
 uartrecv rx out s
 for i=0 to s-1
  if rx[i]==cr then continue

  if rx[i]==lf then 'LF(改行コードの2バイト目)が来たら、1行処理する
   var n=val(mid$(l$,39,3)) 'ノート番号を抽出
   var onoff=(l$[14]=="n")  'KeyOn/Offを抽出
   if onoff==1 then
    beep tone,(n-60)*100
    'bgmplay note$[n]
    ?note$[n]
   endif
   l$=""
   continue
  endif

  inc l$,chr$(rx[i])
 next
wend

4.バックグラウンドジョブを停止させる方法

PiSTARTERをquitでいったん抜けて、以下のコマンドを実行します。
kill %1

f:id:tksm372:20190103030958p:plain