-------------------- CONTENTS -------------------- ・ MIDI マスターチューン中継器 フリーソフト ・ MIDI 受信 → MIDI 送信 データフローチャート ・ MIDI 初期化から終端までのプロセスフローチャート ・ 無限ループ対策、プログラミング あれこれ ・ 便利なツール ・ MIDI プレーヤーの紹介 ・ MIDI 楽曲 ダウンロードサイト ・ 局長の独り言 |
MIDI マスターチューン中継器 フリーソフトウェア | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
▲ 有りそうで無かった、マスターチューン機能を持った MIDI 中継器です。 ★ A4=440Hz で作成された MIDI 楽曲データを例えば基準周波数 A4=442Hz で演奏できます。 ★ MIDI カラオケ楽曲を伴奏にギター演奏する際に、ギターのチューニング変更をしなくても良くなります。 ★ ホールとかスタジオに設置された生ピアノのチューニングに合わせられます。 ★ 季節(温度・湿度)でピッチが変わる楽器に合わせられます。 ★ 移調もできます。 ★ MIDI 楽曲を聴いた後に生楽器を演奏すると気になっていたピッチの違和感が解消されます。 ★ 現在では、ほとんどのバンドとヴォーカルは A4=442Hz で演奏・歌唱されている一方で、 MIDI 楽曲の多くは相変わらず古典的な A4=440Hz で作成されています。 音楽鑑賞・楽器演奏・歌唱の音楽環境を A4=442Hz に統一するためにも、 本ソフトウェアをご活用されることをミュージシャンに限らず広く音楽愛好家にお奨めします。 ★ 440Hz・442Hz 混在時に有ったモヤモヤとした霞が晴れてスッキリします。 442Hz に慣れた耳で 440Hz を聞くと、ステージのセリが一段下がったように感じます。 ■ MMT_105.zip (299,435Byte)をダウンロード 又は Vector からダウンロード。 解凍すると以下のフォルダにファイルができます。 \MMT_105\Bitmap\ ┣ MMT.exe ← ダブルクリックで実行 ┗ Readme_MMT.txt フォントはWindows 標準フォントのみを使用しています。 ドット数字は右図のビットマップ画像を合成しています。 ■ 当ソフトに限らず FireFox 旧バージョンで稀にダウンロード失敗して解凍の際に “書庫が壊れています”と言われて解凍できない場合は、 ブラウザのキャッシュをクリアしてから、再度ダウンロードしてください。 ■ MMT.exe をダブルクリックすると起動します。 MMT.iniファイルは MMT.exeを実行後に作成されます。 もし、挙動が異常になった場合は MMT.iniファイルを削除してから、MMT.exe を起動してください。 ファクトリーセットに戻ります。 ■ Win7(64/32bit) で動作検証済です。 Win8.0(64bit)では THROUGH オフモードは正常動作しますが、オンにすると発音されません。 対策はこちらをご覧願います。 Win10(64bit)でも THROUGH オフモードは正常動作しますが、オンにすると発音されません。 対策はありませんので THROUGH オフモード でご利用願います。 ■ 本ソフトウェアは に掲載しましたウィルスチェッカで検疫済です。 ■ 著作権を留保する以外、一切の縛りはありません。ご自由にどうぞ。 本ソフトウェアに関する一切の義務も責務も担保しません。 ■ アンインストールは、\MMT_105 フォルダを削除してください。レジストリを汚しません。 ■ 更新履歴 ver1.05 2017年 1月27日(このバージョン以降の更新予定はありません) 基準音発音中は、他のボタン操作を無効化。 ver1.04 2017年 1月26日 基準音を発音可能化。 ver1.03 2017年 1月24日 ブロックする XG用SysEx“F0 43 ** ** 03 ** ** F7" を廃止。 ブロックする XG用SysEx“F0 43 ** ** 00 00 00 ** ** ** ** F7”を追加。 ver1.02 2017年 1月23日 ブロックする XG用SysEx“F0 43 ** ** 30 00 00 ** ** ** F7”を追加。 続けてファインチューニングを送出する SC-88用SysEx“F0 41 ** ** 12 00 00 7F ** ** F7”を追加。 ver1.01 2017年 1月14日 終了時のウィンドウの状態を次回起動時に復元化。 THROUGH を On から Off に切替えた際に、ファインチューンを送出化。 CPU 使用率の低減化。その他微修正。 ver1.00 2017年 1月 1日 初版リリース ■“MIDI Master Tune”の運用には仮想 MIDI ケーブルが必要になります。 loopMIDI の導入方法はこちらをご覧願います。(Win10 でも利用可能) Midi York の導入方法はこちらをご覧願います。 (Win10 では利用不可) ▲ 起動したら先ず〔In:〕の右側をマウスクリックすると開くダイアログにて、 MIDI 入力デバイスを選択します。 MIDI 入力デバイスは最大22個まで検出できます。 もし、入力デバイスが1個もない場合は下図の様に空のリストボックスが開きますので、 〔ESC〕キーを押して閉じます。 ▲〔Out:〕の右側をマウスクリックすると開くダイアログにて、 MIDI 出力デバイスを選択します。 MIDI 出力デバイスは最大22個まで検出できます。 仮想 MIDI ケーブルを使用の場合は、ループバック結線できないようになっています。 MIDI In で In From MIDI Yoke: 1 を使用しているので、 MIDI Out では Out To MIDI York: 1 は選択できないようになっています。 ループバック結線すると MIDI データが無限循環してしまいます。 リストに表示されている BASSMIDI Driver (port A 〜 B) は、 Windows の既定の MIDI デバイスとして利用可能なサウンドフォント音源です。 CollSoft VirtualMIDISynth は同じく、Windows の既定の MIDI デバイスとして利用可能なサウンドフォント音源です。 CoolSoft VirtualMIDISynth の導入方法はこちらをご覧願います。(Win10 でも利用可能) CollSoft VirtualMIDISynth は MIDI Mixer と Master Volume 付きですので簡単にマイナスワン演奏ができます。 但し、このソフト音源だけは接続と切断に2〜3秒かかります。 より高音質な YAMAHA SXG 音源の導入方法はこちらをご覧願います。 導入の手間を掛けても利用する価値のある、手持ちのソフト音源の中でベストな音質です。 ▲ 前回終了時のウィンドウの状態(表示/最小化)を起動時に復元できます。 ウィンドウ最小化の状態でタスクバーの〔MMT〕をクリックすると開くポップアップメニューで 〔ウィンドウを閉じる〕をクリックして終了させると、次回ウィンドウが最小化の状態で起動します。 自動起動させる際に、ウィンドウが表示されないので邪魔になりません。 ▲ 本ソフトウェアをWindows起動時に自動起動させる場合は、先に仮想MIDIケーブルと仮想音源が有効になっている ことが必要です。もしそれらの起動に時間がかかって先にMMTが起動してしまうような場合には、 遅延起動設定フリーソフトウェア「Startup Delayer Standard」を利用します。 ▲〔キーシフト〕では、半音ステップで -7 から +7 の範囲でキーシフトできます。 〔周波数設定〕では、0.5Hzステップで 435.0Hz から 445.5Hz の範囲で基準ピッチを設定できます。 キーシフトと周波数設定はドラムチャンネルには送出しません。 の♪をクリックすると基準音を発音します。チャンネル16を使用するので演奏停止中に操作してください。 基準音発音中は、基準音〔-〕と〔+〕ボタン以外は操作できません。 Microsoft GS Wavetable Synth 音源の場合は、基準音発音中に〔-〕〔+〕ボタンを押してもピッチが変化しません。 一旦発音オフしてから発音オンにするとピッチが反映されます。 ▲〔Through〕ボタンを押すと MIDI スルーになります。(Win7 の場合) 基準周波数を〔SEND〕することはできますが、 多くの MIDI ファイルでは曲頭でリセットを送出するので、その瞬間に 440Hz に戻ってしまいます。 プレーヤによってはプレイスタート時にリセットを送出するので、その瞬間に 440Hz に戻ってしまいます。 キーシフトは無効になります。 Windows8 では〔THROUGH〕オンにすると、Windows8 標準の winmm.dll では発音できませんので、 DLL-FILES.com サイトから上のファイルをダウンロードして、解凍するとできる winmm.dll を MMT.exe と同じフォルダーへ置くと発音できます。 winmm.dll はバージョンが上がると不思議なことに規模(機能)が縮小されています! ▲ タスクバーのアイコンが、MIDIデータ受信中はさりげなくブリンクします。 もしお気に召さないようでしたら MMT.INI ファイルの [InitialSetting] の g_IconBlink=1 の値を“0”にしてください。 ▲ 〔赤〕〔橙〕〔緑〕〔青〕ボタンを押すと、LED 文字とボタン照明の色を設定できます。 〔赤〕 〔橙〕 〔緑〕 〔青〕 ■ 以下のマスターチューニング SysEx メッセージを受信した場合は、MIDI Out への送出をブロックします。 [Ignore these MIDI SysEx messages.] <XG Master Tune1>=F0 43 ** ** 30 00 00 ** ** ** F7 <XG Master Tune2>=F0 43 ** ** 00 00 00 ** ** ** ** F7 <GS Master Tune >=F0 41 ** ** 12 40 00 00 ** ** ** ** ** F7 <GM1 Master Tune>=F0 7F ** ** 01 ** ** F7 <GM2 Master Tune>=F0 7F ** ** 03 ** ** F7 <User Define 1 >= <User Define 2 >= <User Define 3 >= <User Define 4 >= MMT.ini ファイルの <User Define 1 >= から <User Define 4 >= に、ブロックする SysEx をユーザーが定義できます。 = 以降の文字長さは最大50です。“*”は Don't care です。 ■ 以下のシステムリセット SysEx メッセージを受信した場合は、 MIDI Out へスルーした直後に、 設定された周波数に対応したチャンネルファインチューニングを送出します。(ドラムチャンネルは除外) [After receiving these MIDI SysEx messages, Send master tune.] <XG Reset >=F0 43 ** ** 00 00 7E 00 F7 <GS Reset >=F0 41 ** ** 12 40 00 7F ** ** F7 <88 Reset >=F0 41 ** ** 12 00 00 7F ** ** F7 <GM1 Reset >=F0 7E ** ** 01 F7 <GM2 Reset >=F0 7E ** ** 03 F7 <User Define 1 >= <User Define 2 >= <User Define 3 >= <User Define 4 >= MMT.ini ファイルの <User Define 1 >= から <User Define 4 >= に、 システムリセット SysEx をユーザーが定義できます。 = 以降の文字長さは最大50です。“*”は Don't care です。 ■ アドレスレジスタ MSB(101)と LSB(100) へチャンネルファインチューニング設定の準備をした後に、 データ レジスタ MSB( 6) と LSB( 38) へチャンネルファインチューニング値を書込もうとするのをブロックします。 (ドラムチャンネルは除外) ■ リセットオールコントロール(0xBn, 121, 0)を受信した場合は、MIDI Out へスルーした直後に、 チャンネルファインチューニングを送出します。(ドラムチャンネルは除外) ▲ 送出をブロックした場合は〔THROUGH〕が一瞬暗転表示になります。 ▲ リセットの後に、ファインチューニングを続けて送出した場合は〔SEND〕が一瞬ハイライト表示になります。 ※ 操作注意事項 もし、曲頭にリセットが無いMIDI楽曲を演奏する場合は、 先に、音源側でMIDI信号(ファインチューン)を受信できる状態にしておいて、 次に、本機を起動するか、MIDI Out デバイスを選択します。 順序が逆になってしまった場合は、音源が接続された後で〔SEND〕ボタンを一回押します。 曲頭にリセットが無い楽曲とは、生録音された殆どのMIDIファイルとか、 作者が習慣的にリセットを入れない場合などです。 ■ リアルタイムクロック 0xF8 は、デフォルトではブロックしています。 どうしてもスルーさせたい場合は、MMT.ini ファイルの [InitialSetting] → g_SkipF8=1 の値“1”を“0”に変更してください。 ■ 周波数に対応したファインチューニング値です。 static BYTE tune[11][2][2] = { {{ 0x2B, 0x33 },{ 0x4E, 0x34 }}, // 435.0Hz, 435.5Hz {{ 0x70, 0x35 },{ 0x13, 0x37 }}, // 436.0Hz, 436.5Hz {{ 0x35, 0x38 },{ 0x57, 0x39 }}, // 437.0Hz, 437.5Hz {{ 0x79, 0x3A },{ 0x1B, 0x3C }}, // 438.0Hz, 438.5Hz {{ 0x3D, 0x3D },{ 0x5E, 0x3E }}, // 439.0Hz, 439.5Hz {{ 0x00, 0x40 },{ 0x21, 0x41 }}, // 440.0Hz, 440.5Hz {{ 0x41, 0x42 },{ 0x62, 0x43 }}, // 441.0Hz, 441.5Hz {{ 0x03, 0x45 },{ 0x23, 0x46 }}, // 442.0Hz, 442.5Hz {{ 0x43, 0x47 },{ 0x63, 0x48 }}, // 443.0Hz, 443.5Hz {{ 0x03, 0x4A },{ 0x23, 0x4B }}, // 444.0Hz, 444.5Hz {{ 0x42, 0x4C },{ 0x61, 0x4D }} // 445.0Hz, 445.5Hz }; //-------------------------------------------------------------------------------------------------------------- // 周波数に対応したファインチューニング値の計算式です //-------------------------------------------------------------------------------------------------------------- double Cent; double Cent0_200; double Frequency; byte FineTuneLSB, FineTuneMSB; int FineTune; for( Frequency = 435.0; Frequency <= 445.5; Frequency += 0.5 ){ Cent = ( log( Frequency/440 ) / log(2)) * 1200; Cent0_200 = Cent + 100; FineTune = (int)(((double)0x3fff / (double)200) * Cent0_200 + (double)0.5 ); FineTuneMSB = FineTune >> 7; FineTuneLSB = FineTune & 0x007F; TRACE( "Frequency=[%5.1f], Cent=[%9.5lf], Cent0_200=[%9.5lf], FineTune=0x%04X, FineTuneLSB=0x%02X, FineTuneMSB=0x%02X\n", Frequency, Cent, Cent0_200, FineTune, FineTuneLSB, FineTuneMSB ); } ■ 周波数 - セント 対応表です。 Frequency=[435.0], Cent=[-19.78575] Frequency=[435.5], Cent=[-17.79697] Frequency=[436.0], Cent=[-15.81047] Frequency=[436.5], Cent=[-13.82624] Frequency=[437.0], Cent=[-11.84429] Frequency=[437.5], Cent=[ -9.86461] Frequency=[438.0], Cent=[ -7.88718] Frequency=[438.5], Cent=[ -5.91202] Frequency=[439.0], Cent=[ -3.93910] Frequency=[439.5], Cent=[ -1.96843] Frequency=[440.0], Cent=[ 0.00000] Frequency=[440.5], Cent=[ 1.96619] Frequency=[441.0], Cent=[ 3.93016] Frequency=[441.5], Cent=[ 5.89190] Frequency=[442.0], Cent=[ 7.85142] Frequency=[442.5], Cent=[ 9.80872] Frequency=[443.0], Cent=[ 11.76381] Frequency=[443.5], Cent=[ 13.71670] Frequency=[444.0], Cent=[ 15.66738] Frequency=[444.5], Cent=[ 17.61587] Frequency=[445.0], Cent=[ 19.56217] Frequency=[445.5], Cent=[ 21.50629] MIDI キーボードなどで基準ピッチを周波数でなくセントで設定する機種の場合は、 A4=442Hz に合わせるには、+8 セントにすれば宜しいでしょう。 ▲〔Panic〕ボタンを押すと全チャンネルオールサウンドオフを送出します。 ■ MMT.EXE を複数起動したい場合は、 \MMT_105\Bitmap\ ┗ MMT.exe \MMT_999\Bitmap\ ┗ MMT.exe のように \MMT105\ フォルダのコピーを作成して、フォルダ名を例えば \MMT_999\ のようにします。 MMT.EXE 起動時にアプリケーション名“MMT.EXE”を見て二重起動を抑止するのではなく、 フォルダ名で判定しています。 |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
MIDI受信 → MIDI送信 データフローチャート |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
▲ MIDI 受信 → MIDI 送信 データフローチャートです。 ■ デバイスとハンドラ及びそれらを操作する関数。 MIDI In Device GetMidiInDevice() HMIDIIN m_hMidiIn MIDI 受信ハンドラ MidiInOpen() midiInStart() midiInStop() midiInReset() midiInClose() midiInPrepareHeader() midiInUnprepareHeader() midiConnect() midiDisconnect() MIDIHDR* m_pHdrIn SysEx 受信用バッファ CALLBACK MidiInProc() MIM_DATA: 受信応答割込み関数 MIM_LONGDATA:受信応答割込み関数 mf_MidiOutShortMsg() 上の CALLBACK MidiInProc() から割込み外部の当関数を PostMessage() で呼び、 ここで MidiOutShortMsg() を実行する。 mf_MidiOutLongMsg() 上の CALLBACK MidiInProc() から割込み外部の当関数を PostMessage() で呼び、 ここで MidiOutLongMsg() を実行する。 (これら二つの関数内部でリエントラント可能な関数だけを使用するのであれば、割込み内部で処理可能) HMIDIOUT m_hMidiOut MIDI 送信ハンドラ midiOutOpen() midiOutPrepareHeader() midiOutShortMessage() midiOutLongMsg() midiOutUnprepareHeader() midiOutReset() midiOutClose() MIDIHDR* m_pHdrOut SysEx 送信用バッファ CALLBACK MidiOutProc() MOM_DONE:受信応答割込み関数 MIDI Out Device GetMidiOutDevice() |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
MIDI 初期化から終端までのプロセスフローチャート |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
▲ MIDI 初期化から終端までのプロセスフローチャートです。 MIDI Through は必要により実施します。 MIDI In と MIDI Out がどちらも一個の場合です。 もし、複数の MIDI In と MIDI Out を設ける場合は、複数の SysEx 用メモリが必要です。 |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
無限ループ対策、プログラミング あれこれ (忘備録) |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
【無限ループ対策:その1】 mmsystem の midiOutLongMsg() 関数実行前に、直前のロングメッセージ送出完了の MOM_DONE を確認するのですが、 MIDI Out デバイスが切断されてしまうといつまで経っても MOM_DONE がセットされません。 そこで MOM_DONE 待ちループが10秒間を超えた場合は、ロングメッセージの送出をキャンセルします。 具体的には、 // メンバー変数 clock_t start, finish; double duration; MMRESULT mmResult; HMIDIIN m_hMidiIn; MIDIHDR* m_pHdrIn HMIDIOUT m_hMidiOut; MIDIHDR* m_pHdrOut; BOOL m_MOM_DONE = TRUE; // 送信完了フラグを初期化 // m_MOM_DONE が TRUE になるのを待つ start = clock(); // MOM_DONE 待ちの開始時刻を取得 while( FALSE == m_MOM_DONE ){ // 送信完了すると割込みで m_MOM_DONE が TRUE になる finish = clock(); // 現在時刻得を取得 duration = (double)(finish - start) / CLOCKS_PER_SEC; // 経過時間を算出 if( 10.0 <= duration ){ // 10秒経過しても MOM_DONE にならない場合 MessageBox( NULL, "MIDI Out デバイスが行方不明です.Window's MIDI Mapper に変えます.", "MIDI Master Tune", MB_OK ); if( NULL != m_hMidiIn ){ // MIDI In デバイスが有効の場合 midiInPrepareHeader( m_hMidiIn, m_pHdrIn, sizeof( MIDIHDR )); // 次の SysEx 受信用バッファを準備 midiInAddBuffer( m_hMidiIn, m_pHdrIn, sizeof( MIDIHDR )); // 次の SysEx 受信用バッファを準備 } mf_MidiOutClose(); // 現在の MIDI Out デバイスクローズ mf_MidiOutOpen( 0 ); // Window's MIDI Mapper をオープン return( 1 ); // 送信キャンセルして帰る } } // m_MOM_DONE が TRUE になったのでロングメッセージを送出します m_MOM_DONE = FALSE; // 送信直前に送信完了フラグをクリア mmResult = midiOutLongMsg( m_hMidiOut, m_pHdrOut, sizeof(MIDIHDR)); MidiOutProc() 内で ロングメッセージ送出完了(MOM_DONE)を検出する具体的方法は、 void CALLBACK MidiOutProc( LPHMIDIOUT lphmo, UINT wMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2 ){ switch( wMsg ){ case MOM_DONE: CMIDI::m_MOM_DONE = TRUE; // ここでは送信完了フラグをセットするだけ g_pView->PostMessage( defID_MOM_DONE, dwParam1, dwParam2 ); // 送信完了処理は、 break; // CView:: クラスで行う } } この対策が成されていないアプリケーションは、タスクマネージャーの力を借りて閉じなければなりません。 ▲ 実際には、このメッセージボックスが表示されます。 midiConnect() でスルーモードにした場合は、MIDI 出力デバイスが切断されてしまってもフリーズしません。 【無限ループ対策:その2】 mmsystem の midiOutLongMsg() 関数は、MIDI Out デバイスが切断されてしまうといつまで経っても帰って来ません。 そこで midiOutLongMsg() が10秒間を超えても帰って来ない場合は、止むを得ずアプリケーションを強制終了します。 具体的には、 //-------------------------------------------------------------------------------------------------------------- // midiOutLongMsg() の直前でタイムオーバー検出用のタイマーをスタートします //-------------------------------------------------------------------------------------------------------------- int g_Timer9; g_Timer9 = 0; // 無限ループ検出用タイマーをスタート mmResult = midiOutLongMsg( m_hMidiOut, m_pHdrOut, sizeof(MIDIHDR)); // この関数は送信終了しないと帰ってこない g_Timer9 = -1; // 無限ループ検出用タイマーをストップ //-------------------------------------------------------------------------------------------------------------- // 10ミリ秒インターバルタイマー割込みで、10秒経過を検出します //-------------------------------------------------------------------------------------------------------------- void CALLBACK TimerCallback1( UINT, UINT, DWORD, DWORD, DWORD ){ if( 0 <= g_Timer9 ){ // タイマー稼働中の場合 g_Timer9 ++; // タイマーカウントアップ if( 1000 <= g_Timer9 ){ // 10秒以上経過した場合 MessageBox( NULL, "MIDI 出力デバイスが行方不明です。強制終了します”, "MIDI Master Tune", MB_OK ); exit( EXIT_FAILURE ); // 止むを得ず強制終了 } } midiOutLongMsg() 関数がハングアップしてしまうと、 midiInClose() も midiOutClose() も実行できなくなってしまうので、 止むを得ず Exit() で強制終了する他ありません。 この対策が成されていないアプリケーションは、タスクマネージャーの力を借りて閉じなければなりません。 ▲ 実際には、このメッセージボックスが表示されます。 midiConnect() でスルーモードにした場合は、MIDI 出力デバイスが切断されてしまってもフリーズしません。 【割込み関数内から定義関数を呼び出さない】(稀に MIDI 送信が混乱する不具合への対応策) 『EnterCriticalSection(), LeaveCriticalSection(), midiOutLongMsg(), midiOutShortMsg(), OutputDebugString() PostMessage(), PostThreadMessage(), SetEvent(), timeGetSystemTime(), timeGetTime() timeKillEvent(), imeSetEvent() を除き、コールバック関数内からシステム定義関数を呼び出さないようにします』 ということになっています。 割込み内部ではリエントラント可能でない関数を呼び出さないようにします。 これを無視した場合、ただ演奏しているだけならば正常動作しますが、演奏途中でマスターチューンを 変更するなどの操作をすると、操作のタイミングによっては予期せぬ不具合が発生します。 フォアグランドでマスターチューン等を送信途中にバックグラウンドでノートオン等を送信すると、 フォアグランドの送信データが分断されてしまうだけでなく、処理関数が予期せぬ結果を生むことがあります。 したがって CALLBACK MidiInProc() 内では、 g_pView->PostMessage( defID_MIM_DATA, dwParam1, dwParam2 ) // ショートメッセージを送信 g_pView->PostMessage( defID_MIM_LONGDATA, (DWORD)hMidiIn, (DWORD)dwParam1 ) // ロングメッセージ を送信 のメッセージをビューウィンドウへポストするだけにして、CView::クラス内に defID_MIM_DATA 及び defID_MIM_LONGDATA メッセージ受信関数を実装して、ショートメッセージとロングメッセージの送信処理をするようにします。 メッセージの宛先はウィンドウを持つクラスに限られるので CView::クラスにしました。 フォアグラウンド プログラム に於いても、ショートメッセージとロングメッセージの送信は バックグラウンド の CALLBACK MidiInProc() と同様に、 defID_MIM_DATA または defID_MIM_LONGDATA メッセージをポストして、 これらのメッセージ受信関数(バックグラウンドと共通)内にてメッセージを送信します。 この方法により、フォアグラウンドで送信途中にこれを強制中断して、バックグラウンドで送信することは無くなります。 即ち MIDI メッセージは不可分に送信されます。同時にリクエストがかかっても一方の送信が完了してから次の送信が始まります。 具体的には、 void CALLBACK MidiInProc(HMIDIIN hMidiIn, UINT wMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2){ if( g_Through ){ return(); } // midiConnect() で MIDI スルーモードにしても、この関数が呼ばれる! switch( wMsg ){ case MIM_DATA: // a complete MIDI message is received by a MIDI input device. g_pView->PostMessage( defID_MIM_DATA, dwParam1, dwParam2 ); break; case MIM_LONGDATA: // a complete MIDI system-exclusive message is received, // or when a buffer has been filled with system-exclusive data. g_pView->PostMessage( defID_MIM_LONGDATA, (DWORD)hMidiIn, (DWORD)dwParam1 ); break; } } CView::クラスへのポインタ g_pVew は、OnCreate() で次のように取得します。 CMMTView* g_pView; int CMMTView::OnCreate( LPCREATESTRUCT lpCreateStruct ){ g_pView = this; // ビューへのポインタを取得 defID_MIM_DATA と defID_MIM_LONGDATA は、次のように定義します。 #define defID_MIM_DATA WM_APP + 0 #define defID_MIM_LONGDATA WM_APP + 1 この概念図を下に載せます。 【手法1】では、フォアグラウンドの MIDI 送信処理が分断されてしまうことが発生します。 【手法2】では、フォアグラウンドの MIDI 送信処理が分断されません。 PostMessage() 関数はこのためにあるようなものです。 別の手法として『フォアグラウンド専用 MIDI 送信処理』と『バックグラウンド専用 MIDI 送信処理』を 別に設ければ良いのではないか、というのは陥り易い誤りです。 【任意形状のエリア検出方法】 ▲ マウスポインタがパネル上のどのエリアに有るかを判定する簡便な方法を紹介します。 検出したいエリア別に赤色の明度だけを変えた上のような画像を 05.bmp ファイルとして作成します HDC m_hImage05HDC; HBITMAP m_hImage05BMP; HBITMAP m_hFile05BMP; BITMAP m_BmpInfo05; // エリア検出用05.bmpファイルを読込み HDC hDC = ::GetDC( hWnd ); char* pszFileName = new char[ MAX_PATH ]; // バッファを初期化 GetCurrentDirectory( MAX_PATH, (LPTSTR)pszFileName ); // カレントディレクトリを取得 strcat((LPTSTR)pszFileName, (LPTSTR)"\\Bitmap\\"); // ファイルのフルパスを作成 strcat((LPTSTR)pszFileName, "05.bmp" ); // ファイルのフルパスを作成 m_hFile05BMP = (HBITMAP)LoadImage( NULL, pszFileName, // 05.bmp ファイルを読込み IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION | LR_VGACOLOR ); delete ((void*)pszFileName ); // 後始末 GetObject( m_hFile05BMP, sizeof(BITMAP), &m_BmpInfo05 ); // 05.bmp画像のサイズを取得 // エリア検出用画像用メモリを作成 m_hImage05HDC = CreateCompatibleDC( hDC ); // コンパチ DC を作成 m_hImage05BMP = CreateCompatibleBitmap( hDC, m_BmpInfo05.bmWidth, m_BmpInfo05.bmHeight); SelectObject( m_hImage05HDC, m_hFile05BMP ); // m_hImage05HDC に m_hFile05BMP をアサイン BitBlt( m_hImage05HDC, 0, 0, m_BmpInfo05.bmWidth, m_BmpInfo05.bmHeight, m_hImage05HDC, 0, 0, SRCCOPY ); // 以上で m_hImage05HDC にエリア検出用画像が作成された // マウス座標の背景色を見てエリアを判別 int m_MouseArea; void CMMTView::mf_GetZoneNo( CPoint mouse ){ COLORREF color; BYTE r, g, b; // マウス位置の背景色を取得 color = ::GetPixel( m_hImage05HDC, mouse.x, mouse.y ); // 背景色を取得 r = GetRValue( color ); g = GetGValue( color ); b = GetBValue( color ); // r, g, b に分解 // 取得した背景色(赤色の明度)からエリアを検出 switch( r ){ case 255: m_MouseArea = -1; break; // 無効エリア case 250: m_MouseArea = 0; break; // [GERAL MIDI] ボタン case 240: m_MouseArea = 1; break; // [SG] ボタン case 230: m_MouseArea = 2; break; // [XG] ボタン case 220: m_MouseArea = 3; break; // [MIDI In] MIDI 入力デバイス名表示エリア case 210: m_MouseArea = 4; break; // [MIDI Out] MIDI 出力デバイス名表示エリア case 200: m_MouseArea = 5; break; // [THROUGH] ボタン case 190: m_MouseArea = 6; break; // 周波数 [-] ボタン case 180: m_MouseArea = 7; break; // 周波数 [+] ボタン : : ▲ 前作 “パチンコゲーム 天穴狙い Special” で使用したエリア検出用画像です。 パチンコ球の中心は灰色のエリア上に置けます。 赤色は硬いオブジェクト(釘)で緑はプラスチック製のオブジェクトです。 青色は他の球です。自球と他球の衝突もこの方式で検出しています。 これを座標(x,y)比較方式ではやってられません。 |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
便利なツール |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
【SoftTuner】 ▲ 渡辺氏作の「 SoftTuner」 です。 10種以上のチューナーを試してみましたが、複音の中からのピッチ検出能力はこれがベストです。 チューナ−機能付きバージョンも試みましたが、複音の中から優勢な基本波を検出するまでは セオリー通りでできますが、見易さが上の「SoftTuner」の足元にも及びそうにないので、 残念ながらこれは諦めました。“餅は餅屋”にお任せしましょう。 別の言い訳 → 実際動作させてみるとセントメーターのニードルの動きが目立ち過ぎて、 本来の売りである「Master Tuning」が霞んでしまうということでもあります。 【Free Music Instrument Tuner】 ▲「Free Music Instrument Tuner」です。 ▲ 設定ダイアログです。 【BOSS Tuner for Android】 【KAWAI Touch Tuner】 ▲ Roland のアンドロイドアプリ ▲ KAWAI の iPhone アプリ 「BOSS Tuner for Android」です。 「Touch Tuner」です。 【オンライン チューナー】 ▲ こちらは https://www.alexdemartos.es/wtuner/ オンラインチューナーです。基準周波数 A4=442Hz 設定可能。 FF, Chrome, Opera, Dragon で動作します。IE, Safari では動作不可。 【MIDI Dump Player】 ▲「Midi Dump Player」 プレーヤーです。 【MIDI-OX モニター】 ▲「MIDI-OX」 モニターです。 |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
MIDI Player の紹介 |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
【TMIDI Player】 ▲ MIDI 黎明期からある、常用の「TMIDI Player」 プレーヤーです。 【MidRadio Player の設定】 ▲ YAMAHA MidRadio Player は、半音ステップで移調はできますがファインチューンはできません。 〔オプション〕→〔MIDI出力先の選択〕で開くダイアログの〔再生〕タブにて、 “◎ MIDI デバイスを使う” をチェックして、ドロップダウンリストから仮想MIDIケーブルの一つを選択します。 この仮想MIDIケーブルの受け側に本機「MIDI Master Tune」を接続して、本機経由でMIDI音源をドライブします。 この方法により、ヤマハ ミュージック データ ショップ に大量にある MIDI 楽曲データ(有料)を、 基準ピッチを変更できない(変更したくない)楽器演奏のバックとして利用できます。 ★ 今までファインチューンができないという理由でご利用を躊躇っていたプレーヤーは、 これを機会に是非 MidRadio Player をお試しください。 ・ 上で紹介した「CoolSoft Virtual MIDI Synth」を音源にすれば、 ミキサーパネルでリードメロディの音量を調整できます。 ▲ 手持ちのサウンドフォント(フルセット)です。 波形データサイズの大きいサウンドフォントが必ずしも高音質とは限りません。 主に FluidR3_GM.sf2(144MB), A320U.sf2(9MB), A340.sf2(79MB), SGM-V2.01.sf2(241MB), merlin_vienna.sf2(102MB) を常用しています。 ■ FireFox ブラウザで MidRadio Player サンプル曲を視聴するには、 〔メニュー〕→〔ツール〕→〔オプション〕→〔プログラム〕にて、 mrl ファイルを開くプログラムを “YAMAHA MidRadio Player を使用” にセットします。 【KbMedia Player】 ▲ NIFTY-Serve で MIDI 黎明期からある Kobarin さん作の「KbMedia Player」ファイルブラウザ型プレーヤです。 ダウンロードは自己解凍型 .exe ファイルです。解凍すればインストールしなくても実行できます。 別途「Visual C++ 2015 再頒布可能パッケージ」が必要ですが、この手間を掛けても利用する価値があります。 .zip ファイルを解凍することなく「KbMedia Player」で読込して演奏可能です。 【Sarasvati Player】 ▲ こちらはシステムトレイ内で動作する哀朱姫さん作の「Sarasvati Player」です。 他のプレーヤのように演奏開始の都度ウィンドウが開かないので、邪魔になりません。 ▲ アイコンは、同じくシステムトレイ内で動作する MP3 WavePlayer です。 【vanBasco's Karaoke Player】 ▲ vanBaco's Karaoke Player は、日本語のホルダーとファイル名を扱えます。 6000+ Midi KaraOke File Free Download サイトから大量にダウンロードできる .kar ファイルを演奏できます。 |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
MIDI 楽曲をダウンロードできるサイト |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
(順不動、縛りがきついサイトは除外)
※ MIDI ファイルのDLとご利用は、自己責任でどうぞ。 |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
局長の独り言 |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
プログラム開発当時68歳でした。まだまだプログラマー現役です。 “プログラマー30歳定年”説何のその! 右も左も真っ暗闇の中で、何が起こるかわからない先進導抗を手探りで掘り進む時が苦労もありますが一番楽しい時! 先に明りが見えると一気に士気が落ちてしまいます。本抗堀は誰にでもできそう。 “蟻の一歩”進んで三段跳びで戻ったり・・・。 コーディングで心掛けていることは、 ・ 記述性より可読性 ・ トリッキーなコーディングは絶対禁止 ・ 記憶よりも記録(コメント)を残す です。 近頃では過重労働が問題になっていますが、 現役時代勤めていた3号館は午前0時前に消灯することはありませんでした。出図前は徹夜でした。 音声合成・物理モデル音源他を研究開発していた12号館はそれよりも後でした。ここは“不夜城”と呼ばれていました。 |