LoginSignup
3
0

More than 5 years have passed since last update.

MATLABでMIDI音源を鳴らす

Last updated at Posted at 2017-08-24

はじめに

WindowsのMIDI APIを使うと、c/c++言語プログラムでMIDI音源を制御することができます。また、MATLABのMEX機能を用いることで、C/C++言語で記述されたプログラムを、MATLAB環境に取り込むことができます。ここでは、Visual Studio環境でMIDI出力をテストし、MATLAB環境へ移植する手順を概説します。

Visual Studio環境でテスト

使用コマンド、用語など

以下のプログラムをVisual Studio環境でコンパイルし、動作を確認します。以下は、プログラム内のコマンド、用語のポイント。

  • mmsystem.h: MIDIコマンドに関する情報の格納されたヘッダファイル。
  • argv[] : コマンドライン入力字に文字列が格納される配列。
  • HMIDIOUT: MIDIハンドルの定義。
  • midiOutOpen: MIDIデバイスのオープン。第一引数はMIDIハンドルのポインタ、第二引数はデバイスID。MIDI_MAPPERは、"デフォルトのデバイス"の意味。
  • midiOutClose: MIDIデバイスのクローズ。引数はMIDIハンドル。
  • midiOutShortMsg: MIDIメッセージの送信。第一引数はMIDIハンドル、第二引数はMIDIメッセージ
  • MIDIメッセージ: 4バイト信号を16進数で表現。最下位(一番右)1バイトがステータスバイト
  • ステータスバイト: メッセージの種別を示す。ここでは以下の三種類を使用
    • 0x90: ノートオン(発音の開始)。上位バイトで音程、さらに上位バイトで音量情報を与える。
    • 0x80: ノートオフ(発音の終了)。上位バイトで、該当する音程情報を与える。
    • 0xC0: プログラムチェンジ。上位バイトで、音色番号を与える。

Cプログラム

#include <stdio.h>
#include "stdafx.h"
#include <Windows.h>
#include <mmsystem.h>
#pragma comment(lib, "winmm.lib")

int main(int argc, char *argv[])
{
    HMIDIOUT hmo;   // MIDI out handle

    int pitch;  // 音程(0~127: C-1~G9)
    int duration;   // 音の長さ(msec)
    int velocity;   // ベロシティ(音量)
    int timbre; // 音色

    pitch    = atoi(argv[1]); //コマンドライン入力の文字列をinteger型へ変換
    duration = atoi(argv[2]);
    velocity = atoi(argv[3]);
    timbre   = atoi(argv[4]);

    midiOutOpen(&hmo, MIDI_MAPPER, 0, 0, 0); // MIDIデバイスオープン
    midiOutShortMsg(hmo, 0xC0 | (timbre << 8)); // 0xC*: プログラムチェンジ

    midiOutShortMsg(hmo, 0x90 | (velocity << 16) | (pitch << 8)); // 0x90: ノートオン
    Sleep(duration);
    midiOutShortMsg(hmo, 0x80 | (pitch << 8));     // 0x80: ノートオフ

    midiOutClose(hmo);                             // MIDIデバイスクローズ
}

テスト

Visual Studio内でコマンドライン引数を与えて評価する場合は、
「Solution Explorerペインでプロジェクト名を右クリック」
  ⇒ Propertiesを選択
  ⇒ Debugging
  ⇒ Command Argumentsに、引数を記入(複数ある場合は、スペースで区切る)
ここでは、以下の引数をテストしています。

  • 第一引数:60(音程:C4、ド)
  • 第二引数:1000(長さ:1000[msec]発音)
  • 第三引数:100(音量:maxは127)
  • 第四引数:1(音色:GM音源では1番はグランドピアノ)

image.png

Visual Studio環境でテスト後、DOS窓等で実行する場合は、実行ファイル名の後、スペース区切りで引数を羅列して入力します。

image.png

MATLAB環境へ移植

コマンド・用語等

以下のプログラム例の様に、mexFunction(ゲートウェイルーチン)を介すことで、C/C++言語で記述されたプログラムを、MATLABで実行できる形式にコンパイルすることができます。以下は、プログラム内のコマンド、用語のポイント

  • miditest(): 実際の処理部(オリジナルのプログラムに該当)。コマンドライン引数の受け渡しに関連する部分は削除し、MATLAB環境で受け取る形式に修正。それ以外は変更なし。
  • mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]): MATLABと上記"実際の処理部"との間を取り持つゲートウェイルーチン。お約束なので、このまま使用。
  • mxGetScalar(prhs[n]): n番目の右辺入力引数を取得。

MATLAB環境でコンパイルするために修正したプログラム

#include "mex.h"
#include <stdio.h>
#include <Windows.h>
#include <mmsystem.h>

#pragma comment(lib, "winmm.lib")

int miditest(int pitch, int duration, int velocity, int timbre)
{
    HMIDIOUT hmo;     // MIDI out handle

    midiOutOpen(&hmo, MIDI_MAPPER, 0, 0, 0);    // open MIDI out device
    midiOutShortMsg(hmo, 0xC0 | (timbre << 8)); // 0xC*: program change

    midiOutShortMsg(hmo, 0x90 | (velocity << 16 | pitch << 8)); // 0x90: note on
    Sleep(duration);                                                         
    midiOutShortMsg(hmo, 0x80 | (pitch << 8));   // 0x80: note off
    midiOutClose(hmo);                           // close MIDI out device

    return 0;
}

void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
    int pitch, duration, velocity, timbre;

    pitch       = mxGetScalar(prhs[0]); //右辺入力取得(0番目)
    duration    = mxGetScalar(prhs[1]); //右辺入力取得(1番目)
    velocity    = mxGetScalar(prhs[2]); //右辺入力取得(2番目)
    timbre      = mxGetScalar(prhs[3]); //右辺入力取得(3番目) 

    miditest(pitch, duration, velocity, timbre);
}

テスト

MATLABのコマンドウィンドウで、以下の様にmexコマンドを実行し、上記プログラムをコンパイルします。

 >>mex filename.cpp

ビルドに成功すると、"MEXは正常に完了しました"というメッセージが表示され、Cコードと同じディレクトリに、"mexw64"という拡張子を持つファイル(一般に、"MEXファイル"と呼ばれる)が現れます。後は、MATLABのコマンドウィンドウで、以下の様にMEXファイルに必要な引数を与えることで、MATLAB環境からMIDI音源を鳴らすことができます。

image.png

まとめ

Windows環境において、非常に短い記述でMIDI音源を鳴らすことができました。またMATLABへの移植も大きな修正は不要です。ここでの例は非常にシンプルですが、同様の手順で、複数音源の同時再生や、MIDIファイルを読み込んで再生することも可能でしょう。

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0