MIDIプログラミング

MIDIとは?

Musical Instrument Digital Interfaceの略で、電子楽器デジタルインタフェースの世界共通規格。楽器同士を接続して演奏情報を伝達するためのハードウェアおよびソフトウェアやファイル形式まで多岐に渡る。特にMIDIインターフェスを装備した電子楽器をMIDIコントローラ。その音源をMIDI音源と呼ぶ。シンセサイザーやコンピュータを使った音楽制作にはなくてはならないものである。

しかしながら、MIDIは1982年に実装されたもので、現在では通信速度や柔軟性に難があり、MIDIの代替規格としてネットワーク経由で演奏情報を伝達可能なOSC (Open Sound Control)も使われ始めている。とはいえ、新旧の電子楽器の混在する現在ではまだまだMIDI規格は利用され続けるだろう。

参考文献:MIDIバイブル〈1〉MIDI1.0規格 基礎編

様々な形のMIDIコントローラ

 

MIDI音源(ハードウェア)

Back To Top

MIDIプログラミング

MIDIプログラミングは、コンピュータ上のMIDI規格を用いてプログラミングを行う。独自の演奏インターフェースを持ったソフトウェア、ハードウェアであるMIDIコントローラの設計、プログラミングを用いた音楽制作などを行うことができる。

今回はProcessingを利用したMIDIプログラミングの方法を紹介するが、Cycling’74 MaxやPureDataはもともとコンピュータによる音楽制作のために開発されたもので、音楽制作のためのツールや音響処理のためのアルゴリズムが実装されている。Maxについては別日に演習を行う。

下の映像の作品でも、音に関する処理には全てMIDIプログラミングによって実装されている。

Back To Top

MIDIライブラリ(設定済)

ProcessingでMIDIを扱うためにはMIDIライブラリをインストールする必要がある。MIDIライブラリには、MIDIBus、proMIDI、SoundCypherなどいくつか種類が存在する。それぞれ、Processingのバージョン対応やソフトシンセ対応などに制限があるため、目的に適したものを使う必要がある。

今回はRWMIDIを利用する。というのもProcessing3+MIDIBusでは最新のJavaソフトシンセであるGervillの音が鳴らないなどの問題(2017.8.26現在)があったり、RWMIDIであればPitchBendへ対応可能だからだ。

RWMIDIはProcessing2対応のみで開発者のサイト(ruinwesen.com)はすでに閉鎖されている?ようだが、Processing3に対応させて公開している人がいるのでそちらを利用する。さらに、それをPitchBendが利用できるように改造する方法も紹介する。PitchBendは音高を滑らかに変化させるもので、音の表現が格段に高まる。

RWMIDI(Processing3対応版)https://github.com/torrejuseppe/rwmidi-revival

上記からzipファイルをダウンロード後、解凍したフォルダ名をrwmidiに変更。Processingのlibrariesフォルダに入れる。

さらに、PitchBend機能を追加するために以下の作業を行う。

rwmidi/src/rwmidi/MidiEvent.javaの20行目あたりに以下を追加。

public static final int PITCH_BEND = 0xE0;

rwmidi/src/rwmidi/MidiOutput.javaの95行目あたりに以下を追加。

/**
 * Send a Pitch Bend change message on this output.
 * @param channel Channel on which to send the message
 * @param value Pitch Bend value
 * @return 1 on success, 0 on error
 */
public int sendPitchBend(int channel, int value) {
  if (value > MAXPITCHBEND) value = MAXPITCHBEND;
  if (value < MINPITCHBEND) value = MINPITCHBEND;
  byte lsb = (byte) (value % 128);
  byte msb = (byte) (value/128);
  
  ShortMessage msg = new ShortMessage();
  try {
    msg.setMessage(MidiEvent.PITCH_BEND, channel, lsb, msb);
    receiver.send(msg, -1);
    return 1;
  } catch (InvalidMidiDataException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    return 0;
  }
}

Back To Top

プログラムの動作環境

本講義ノートで紹介するプログラム(スケッチ)の動作確認は以下の環境で行っている。

OS: macOS Sierra(10.12.6)
Processing:バージョン3.3.5
MIDIライブラリ:RWMIDI(前述の改造版)※マニュアルインストール
OSCライブラリ:oscP5

OSCライブラリの追加は、スケッチメニュー>ライブラリをインポート>ライブラリを追加から行うことができる。

Back To Top

実験1 マウスで音を鳴らす

①スケッチの準備

Processingを起動して、空のスケッチウィンドウに以下のコードをコピー&ペーストする。

import rwmidi.*; //RWMIDIライブラリの読み込み
MidiOutput output;
 
int ch = 0; //Midi Chの設定
int note = 60; //Noteナンバー(音階)の設定
int vel = 100;  //Velocity(音の強さ)の設定0〜127
int program = 1; //プログラムチェンジ(音色)の設定
int dev = 0; //音源の設定
int devLength = 0; //デバイスの数
 
void setup () {
  size (500, 300); //ウィンドウサイズ
  frameRate (30);
  devLength = RWMidi.getOutputDevices ().length; //デバイスの数
  output = RWMidi.getOutputDevices () [dev].createOutput(); //デバイスの設定
  output.sendProgramChange (program); //プログラムチェンジの設定
  //デバイスリストの表示
  for (int i = 0; i < devLength; i++) {
    println ("Output Device " + i + " : " +  RWMidi.getOutputDevices () [i].getName() );
  }
}
 
void draw () {
  background (0, 104, 55);
  text ("Device Name: " + output.getName (), 15, 20);
  text ("Program Change: " + program, 15, 40);
  text ("Click and release! ", 15, 80);
}
 
void mousePressed () {  //マウスを押した時
  output.sendNoteOn ( ch, note, vel );  //NoteOnの送信
  println ( "Ch: " + ch + "  Note: " + note + "  Vel: " + vel);  //Debug  
}
 
void mouseReleased () {  //マウスを離した時
  output.sendNoteOff(ch, note, vel);  //NoteOffの送信
}

 

②スケッチの実行

Runボタンを押して実行すると緑のウィンドウが表示されるので、ウィンドウ上でクリックすると音が鳴る。

 

③音源の確認

起動時に出力先リストがコンソール(下図)に表示される。本スケッチでは8行目のdevice=0として、Gervill OpenJDKを選択している。deviceの引数を変更することで出力先を変更することもできる。

 

④音階と音色の変更

音階はスケッチ5行目のnote(Noteナンバー)の数値を変更する。

int note = 60; //Noteナンバー(音階)の設定

音色はスケッチ7行目のprogram(プログラムチェンジ)の数値を変更する。

int program = 1; //プログラムチェンジ(音色)の設定

Back To Top

MIDIメッセージ解説

MIDIにおける演奏情報の送受信にはMIDIメッセージが使われる。MIDIメッセージには数種類存在する。ここではノートオン/オフ、プログラムチェンジについて解説する。

 

①ノートオン/オフ

ノートオンメッセージ:鍵盤を押した時に送信されるデータセット。
ノートオフメッセージ:鍵盤を離した時に送信されるデータセット。

ノートオン/オフメッセージはさらに以下のデータで構成されている。

チャンネル:複数の音源の切替(1-16)
ノートナンバー:音階を数字で表現したもの(0-127)
ベロシティ:鍵盤を押す早さ、音の強さ(0-127)

今回はチャンネルとベロシティは変更せず、ノートナンバーのみ変更する。ノートナンバーはピアノの鍵盤で見ると下図のように対応する。中央のC(ド)=60。

 

②プログラムチェンジ

プログラムチェンジを利用して音色を変更できる。音色の種類についてはGeneral MIDI(GM)を参照。以下にその一部を掲載する。数多くの音色があるのがわかる。

1  Acoustic Piano アコースティックピアノ
2  Bright Piano ブライトピアノ
3  Electric Grand Piano エレクトリックグランドピアノ
4  Honky-tonk Piano  ホンキートンクピアノ
5  Electric Piano エレクトリックピアノ
6  Electric Piano 2 エレクトリックピアノ2
7  Harpsichord ハープシコード
8  Clavi  クラビネット
9  Celesta  チェレスタ
10  Glockenspiel グロッケンシュピール
11  Musical box オルゴール
12  Vibraphone ヴィブラフォン
13  Marimba マリンバ
14  Xylophone シロフォン
15  Tubular Bell チューブラーベル
16  Dulcimer ダルシマー
17  Drawbar Organ ドローバーオルガン
18  Percussive Organ パーカッシブオルガン
19  Rock Organ ロックオルガン
20  Church organ チャーチオルガン
21  Reed organ リードオルガン
22  Accordion アコーディオン
23  Harmonica ハーモニカ
24  Tango Accordion タンゴアコーディオン
25  Acoustic Guitar (nylon)  アコースティックギター(ナイロン弦)
26  Acoustic Guitar (steel)  アコースティックギター(スチール弦)
27  Electric Guitar (jazz)  ジャズギター
28  Electric Guitar (clean) クリーンギター

Back To Top

実験2 キーボードで演奏

①スケッチの準備

Processingを起動して、空のスケッチウィンドウに以下のコードをコピー&ペーストする。

import oscP5.*; //oscP5ライブラリの読み込み
import netP5.*;
import rwmidi.*;  //RWMIDIライブラリの読み込み
OscP5 oscP5;
MidiOutput output;
 
int ch = 0;  //Midi Chの設定 ここ変えるとKontakt Playeyの別のラックの音出せる
int note_on = 60;  //NoteOnナンバー(変数)
int note_off = 60; //NoteOffナンバー(変数)
int pitch = 8192; //ピッチベンド
int vel = 100;  //Velocity(音の強さ)の設定0〜127
int program = 1; //プログラムチェンジ(音色)の設定
int dev = 0;  //音源の設定 Kontaktをport a(=0)にした時はJavaは2
int devLength = 0; //デバイスの数
int port = 12000; //ポートナンバー
int lock = 0; //マウスの連打を防止するため
 
void setup () {
  size (500, 300); //ウィンドウサイズ
  frameRate (30);
  oscP5 = new OscP5 (this, port);  //受信アドレスとポート,thisはDHCPで自動に振られたアドレスになる
  devLength = RWMidi.getOutputDevices ().length; //デバイスの数
  output = RWMidi.getOutputDevices () [dev].createOutput(); //デバイスの設定
  output.sendProgramChange (program); //プログラムチェンジの設定
  //デバイスリストの表示
  for (int i = 0; i < devLength; i++) {
    println ("Output Device " + i + " : " +  RWMidi.getOutputDevices () [i].getName() );
  }
}
 
void draw () {
  background (164, 0, 0);
  text ("Device Name: " + output.getName (), 15, 20);
  text ("Program Change: " + program, 15, 40);
  text ("Push Keys or Send OSC! (port: " + port + ")", 15, 80);
}
 
void keyPressed () { //キーを押した時
output.sendPitchBend( ch, 8192 );

if(lock==0){
  switch(key) {
    case'z': note_on = 41; break;
    case'x': note_on = 43; break;
    case'c': note_on = 45; break;
    case'v': note_on = 47; break;
    case'b': note_on = 48; break;
    case'n': note_on = 50; break;
    case'm': note_on = 52; break;
    case',': note_on = 53; break;
    case'.': note_on = 55; break;
    case'/': note_on = 57; break;
    case'_': note_on = 59; break;
    case'a': note_on = 60; break;
    case's': note_on = 62; break;
    case'd': note_on = 64; break;
    case'f': note_on = 65; break;
    case'g': note_on = 67; break;
    case'h': note_on = 69; break;
    case'j': note_on = 71; break;
    case'k': note_on = 72; break;
    case'l': note_on = 74; break;
    case';': note_on = 76; break;
    case':': note_on = 77; break;
    case']': note_on = 79; break;
    default: note_on = 0; break;
  }
  output.sendNoteOn ( ch, note_on, vel ); //NoteOnの送信
  println ( "Ch: " + ch + " Note: " + note_on + " Vel: " + vel);  //デバッッグ

  lock=1;
}

}
 
void keyReleased () { //キーを離した時
  switch(key) {
    case'z': note_off = 41; break;
    case'x': note_off = 43; break;
    case'c': note_off = 45; break;
    case'v': note_off = 47; break;
    case'b': note_off = 48; break;
    case'n': note_off = 50; break;
    case'm': note_off = 52; break;
    case',': note_off = 53; break;
    case'.': note_off = 55; break;
    case'/': note_off = 57; break;
    case'_': note_off = 59; break;
    case'a': note_off = 60; break;
    case's': note_off = 62; break;
    case'd': note_off = 64; break;
    case'f': note_off = 65; break;
    case'g': note_off = 67; break;
    case'h': note_off = 69; break;
    case'j': note_off = 71; break;
    case'k': note_off = 72; break;
    case'l': note_off = 74; break;
    case';': note_off = 76; break;
    case':': note_off = 77; break;
    case']': note_off = 79; break;
    default: note_off = 0; break;
  }
    output.sendNoteOff(ch, note_off, vel); //NoteOffの送信
    
    lock=0;
}

void mouseMoved ()
{
    output.sendPitchBend(0, (int) map(mouseX, 0, 800, 0, 16382)); //ピッチベンドの送信
}

//OSC受信処理
void oscEvent (OscMessage theOscMessage) {
 
  //OSCで/noteonを受信した時
  if(theOscMessage.checkAddrPattern("/noteon")) {
    if (theOscMessage.checkTypetag("i")) { //受信データのint判定
      println("/noteon: " + theOscMessage.get(0).intValue());
      note_on = theOscMessage.get(0).intValue();
      output.sendNoteOn( ch, note_on, vel );
    }
    output.sendPitchBend( ch, 8192 );  //ピッチベンドのリセット
  }
 
   //OSCで/noteoffを受信した時
    if(theOscMessage.checkAddrPattern("/noteoff")) { //NoteOff
     if (theOscMessage.checkTypetag("i")) { //受信データのint判定
      println("/noteoff: " + theOscMessage.get(0).intValue());
      note_off = theOscMessage.get(0).intValue();
      output.sendNoteOff(ch, note_off, vel);
    }
  }
 
   //OSCで/pitchを受信した時 ピッチベンドは0〜16383
    if(theOscMessage.checkAddrPattern("/pitch")) {
     if (theOscMessage.checkTypetag("i")) { //受信データのint判定
      println("/pitch: " + theOscMessage.get(0).intValue());
      pitch = theOscMessage.get(0).intValue();
      output.sendPitchBend( ch, pitch );
    }
  }
 
}

 

②スケッチの実行(キーボードとマウスで演奏)

Runボタンを押して実行すると赤いウィンドウが表示される。

キーボードの下図のキーを押すことで演奏することができる。

キーを押したまま、マウスを左右に振ることで音高を変化させることもできる。

 

③音色の変更

スケッチの12行目のprogramの引数を変更して音色を変えてみよう。

int program = 1; //プログラムチェンジ(音色)の設定

Back To Top

実験3 Kontakt Player音源の利用

フリーのソフトウェア音源Kontakt Playerとサウンドライブラリーを利用する。Kontakt PlayerはNative Instrumentsが無料で公開しているもので、サウンドライブラリーを読み込んで再生するプレイヤーである。Kontakt Playerだけでは音は鳴らないので、同じく無料のサウンドライブラリーをダウンロードして利用する。
映像メディア室のiMacにはすでにインストール済。

 

①Kontakt 5 Playerの起動

アプリケーションフォルダ > Native Instruments > Kontakt 5 > Kontakt 5.appを起動する。

 

②バーチャルMIDIポートの確認

Kontakt 5メニューからPreferencesをクリックする。

MIDIタブのInputsの中のKontakt 5 Virtual InputのStatusがPort Aになっていることを確認する。

 

③サウンドライブラリー(nki)の読み込み

サウンドライブラリーFactory Selectionには多くの音源が用意されているので試してみよう。
Factory SelectionのInstruments(下図左)をクリックして表示されるnkiファイルリストの一つをダブルクリックする。

ブラウザーウィンドウ(上図左)が表示されていない場合は、右上にあるWorkspace Management(下図)から表示させる。

 

④音源の変更

実験2で使ったスケッチを利用する。RunしたままならStopする。
スケッチの13行目のdevの引数を2に変更する。

int dev = 2; //音源の設定

デバイスナンバーは実験2のスケッチをRunした直後にコンソールに表示されるので確認できる。デバイスナンバーはKontakt Playerを起動した後に自動的に振り直されて変わる場合があるので注意。

 

⑤キーボードとマウスで演奏

スケッチをRunする。
下図のようにProcessingの赤いウィンドウが前面にないとキーが反応しないので注意。
キーを押しながらマウスを動かしてみよう。

 

⑥別のサウンドライブラリーを試す

Kontakt Playerで異なるライブラリを使う場合は音源ユニットの×をクリックして閉じてから利用する。

Kontakt Playerでは同時に複数の音源(nki)を利用した演奏も可能だが、今回のスケッチでは実装していない。(ノートメッセージのチャンネルを変更することで可能)

Back To Top

実験4 iPhoneで演奏(デモのみ)

実験2のスケッチはOSC受信にも対応させているので、iPhoneやiPadのOSCアプリから遠隔で演奏することができる。今回はiOSC(170円)を利用する。PCとiPhoneを同じネットワーク上に接続し、IPアドレス、ポートを一致させる。IPアドレスはLanScanなどで確認。OSCのデータ構造は以下のように設定した。

ノートオン:/noteon(0〜127)
ノートオフ:/noteoff(0〜127)
ピッチベンド:/pitch(0〜16383)

ピッチベンドも使えるので、下図のようなインターフェースを使えば、音の高さを滑らかに変化させることもできる。

Back To Top

Open Sound Controlとは?

Open Sound Control (OSC)は、ネットワークを介してコンピュータやサウンドシンセサイザー機器同士でデータ通信を行なうための規格。通信方式としてはUDPやTCPを採用しているため、Ethernet や無線LAN でデータを送ることができる。OSCはMIDIの次世代規格としての位置づけられているが、Flash、Max/MSP、Processing、openFrameworksでも扱うことが可能で、マイコンや照明機器などの異なるプラットフォーム間の通信としても使われている。MIDIメッセージでは仕様が決められていたのに対して、OSCでは制約がなく、URL形式で自由に名前付けした階層化されたデータを扱うことができる。このため、複雑なデータを効率良く送信することが可能である。

映像メディア室のiMacにも個別にIPアドレスが振られているので、1台のiPhoneから全てのiMacを制御することも可能だ。

Back To Top

KAGURA

KAGURAはSHIKUMI DESIGNが開発しているジェスチャーによる音楽演奏アプリケーション。アプリケーションは以下サイトからダウンロード可能。ウェブカメラでも動作可能だが、インテル® RealSense™3Dカメラを持っていればより表現力の高い演奏を行うことができる。KAGURAはジェスチャー解析とMIDIプログラミングを融合したものと言える。

https://www.kagura.cc/jp/

Back To Top