みなさん、こんにちは。
新しい物好き一階です。
ざっと調べた限りArudinoとWebAudioApiのサンプルはあれどWindowsC++ or C#のサンプルがありませんでした。これも時代の流れかなぁと寂しく思いつつ、WindowsのC++でプログラミング開始。
1.まずはお勉強
実はMIDIデータは作ったり再生した事はあるものの、プログラム上から命令を出したことがないので、まずはMIDIのフォーマットやWin32APIの使い方を勉強。
※.net FrameworkにはMIDI制御用の機能がないのでWin32APIを利用しています。
このサイトやこのサイトを参考にしました。
2.eVY1の使い方
eVY1では事前に歌詞をエクスクルーシブメッセージでデバイスに送信しておくと、音をならす度に歌詞を1文字ずつ音に合わせて発生してくれる。
なのでプログラム的には以下のような流れになる。
MIDIデバイスOpen⇒エクスクルーシブメッセージ送信⇒音を鳴らす⇒MIDIデバイスクローズ
3.まずは音を鳴らす
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
// ライブラリの使用宣言 #pragma comment (lib, "winmm.lib") int PlayMidi() { // MIDIデバイス取得 HMIDIOUT hMidiOut; if ( midiOutOpen( (LPHMIDIOUT)&hMidiOut, 1, (DWORD_PTR)NULL, (DWORD_PTR)0, CALLBACK_NULL ) != MMSYSERR_NOERROR ) { // MIDIデバイスがない。 return 1; } // 送信準備 midiOutShortMsg(hMidiOut, 0x000000c0); Sleep(100); // ド midiOutShortMsg(hMidiOut, 0x00403c90); Sleep(1000); midiOutShortMsg(hMidiOut, 0x00003c90); // レ midiOutShortMsg(hMidiOut, 0x00403e90); Sleep(1000); midiOutShortMsg(hMidiOut, 0x00003e90); // MIDIデバイス解放 midiOutReset(hMidiOut); midiOutClose(hMidiOut); return 0; } |
※midiOutOpenの第2引数は自分の環境に合わせて変えてください。
デフォルトで”あ”が設定されているみたいなので、このプログラムを実行すると”ド”と”レ”を、あ↑あ↑と歌ってくれます。
無事音が出たので次は「さくらさくら」を歌わせてみます。
[歌っている動画]
4.歌詞の送信データの中身
歌詞はASCIIコードで送信するので、どの文字がどういうコードで構成されているかをYAMAHAのマニュアルページの一番下からMIDI仕様書をダウンロードして確認する。(今日現在だと34ページに該当情報が記載されている)
5.エクスクルーシブメッセージの送信
下記ロジックをその1の送信準備の直前に入れると、歌詞が”あ”から”き”に変更されることが確認できる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
MIDIHDR mhMidi; ZeroMemory(&mhMidi, sizeof(mhMidi)); // 歌詞データ BYTE vocalData[] = {0xF0, 0x43, 0x79, 0x09, 0x00, 0x50, 0x10, 0x6B, 0x27, 0x20, 0x69, 0x00, 0xF7 }; mhMidi.lpData = (LPSTR)vocalData; mhMidi.dwBufferLength = 13; mhMidi.dwBytesRecorded = 13; midiOutPrepareHeader(hMidiOut, &mhMidi, sizeof(mhMidi)); midiOutLongMsg(hMidiOut, &mhMidi, sizeof(mhMidi)); while ((mhMidi.dwFlags & MHDR_DONE) == 0); midiOutUnprepareHeader(hMidiOut, &mhMidi, sizeof(mhMidi)); |
6.歌詞データの作成
特にプログラム上で動的に変更しないのならばここの歌唱データ変換ツールを使うと便利。
0x付加&SysExで作成した文字をカンマ区切りで上記ロジックの”BYTE vocalData[]”に入れれば歌詞が入れ替わる。
プログラムで生成する場合は以下(大分手抜きですが)。
[変換部分]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
void WordStringToByte( char* wordData, BYTE* byteWord ) { // ヘッダ情報 byteWord[0] = 0xF0; byteWord[1] = 0x43; byteWord[2] = 0x79; byteWord[3] = 0x09; byteWord[4] = 0x00; byteWord[5] = 0x50; byteWord[6] = 0x10; // 歌詞情報 int j = 0; int length = strlen( wordData ); for( int i = 7; i < length+7; i++ ) { byteWord[i] = (int)(unsigned char)wordData[j]; j++; if( j == length ) { break; } } // 終了情報 byteWord[length+7] = 0x00; byteWord[length+8] = 0xF7; return; } |
[呼び出し元]
1 2 3 4 |
// 歌詞を"ふぁ"と"ずぃ"に設定。歌詞の連結は"," wordData = "p\ a,dz i"; BYTE byteWord[255]; WordStringToByte( wordData, byteWord ); |
[エクスクルーシブメッセージ設定部分]
1 2 3 4 5 6 7 8 |
/* mhMidi.lpData = (LPSTR)vocalData; mhMidi.dwBufferLength = 13; mhMidi.dwBytesRecorded = 13; */ mhMidi.lpData = (LPSTR)byteWord; mhMidi.dwBufferLength = strlen( wordData )+9; mhMidi.dwBytesRecorded = strlen( wordData )+9; |
次はこれをKinectかPerCあたりと組み合わせてみます。