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(2019年5月時点非公開)

上記から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;
  }
}

上リンクからRWMIDIをダンロードする。
zipファイルを解凍してrwmidiフォルダを/書類/Processing/libraries/の中に移動する。

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;
NetAddress myRemoteLocation;

int ch = 0;  //Midi Chの設定 ここ変えるとKontakt Playeyの別のラックの音出せる
int note_on = 0;  //NoteOnナンバー(変数)
int note_off = 60; //NoteOffナンバー(変数)
int pitch = 8192; //ピッチベンド
int vel = 100;  //Velocity(音の強さ)の設定0〜127
int program = 10; //プログラムチェンジ(音色)の設定
int dev = 0;  //音源の設定 UVI Workstsionの起動したときは1
int devLength = 0; //デバイスの数
int rcv_port = 8000; //受信ポート
int lock = 0; //マウスの連打を防止するため
    
int interval_cnt = 0;
float firstValue = 0;
String[] patt_address = new String[16];
int noteNo = 0;

void setup () {
  size (500, 300); //ウィンドウサイズ
  frameRate (30);
  oscP5 = new OscP5 (this, rcv_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() );
  }
  
  //TouchOSCのLiveControl iPad.touchoscのDrumsのパッドに合わせたOSCパターンの初期化
  for (int i = 0; i < 16; i++) {
    patt_address[i] = "/7/push" + String.valueOf(i+1);
  }
  
  myRemoteLocation = new NetAddress("192.168.0.2",8000); //ipad側のUIリセットに利用
  
  //TouchOSCのVelを初期値に設定
  OscMessage myMessage1 = new OscMessage("/7/fader0");
  oscP5.send(myMessage1.add(vel/127.0), myRemoteLocation);
  //TouchOSCのインターフェースをリセット
  OscMessage myMessage3 = new OscMessage("/7/fader3");
  oscP5.send(myMessage3.add(0.5), myRemoteLocation); 
}
 
void draw () {
  background (164, 0, 0);
  text ("Push Keys or Send OSC!", 15, 20);
  
  text ("Device Name: " + output.getName (), 15, 60);
  text ("Program Change: " + program, 15, 80);
  if(note_on==0) {
    text ("Pushed Key: --", 15, 100); 
    text ("Note No: --", 15, 120); 
  } else {
    text ("Pushed Key: " + key, 15, 100);
    text ("Note No: " + note_on, 15, 120);
  }
  
  text ("OSC RCV_PORT: " + rcv_port + ")", 15, 160);
  if(noteNo==0) {
    text ("OSC Message: --", 15, 180); 
    text ("Note No: --", 15, 200); 
  } else {
    text ("OSC Message: " + patt_address[noteNo-60], 15, 180);
    text ("Note No: " + noteNo, 15, 200);
  }
}
 
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の送信
  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) {
  
  for (int k = 0; k < 16; k++) {
    if (theOscMessage.checkAddrPattern(patt_address[k])) {
      if (theOscMessage.checkTypetag("f")) {
        firstValue = theOscMessage.get(0).floatValue();
      }
      noteNo = k + 60;
      
      if (firstValue == 1) {
        output.sendNoteOn( ch, noteNo, vel );
        println("noteon: ", ch, noteNo, vel);
        interval_cnt = interval_cnt ++;
      }  else {
        delay(10);//パッドを軽く押したら、ボスって音がする noteonからnoteoffの間が短すぎる delayで解決
        output.sendNoteOff( ch, noteNo, vel );
        println("noteoff: ", ch, noteNo, vel);
        
        output.sendPitchBend( ch, 8192 );  //ピッチベンドのリセット
        //TouchOSCのインターフェースをリセット
        OscMessage myMessage3 = new OscMessage("/7/fader3");
        oscP5.send(myMessage3.add(0.5), myRemoteLocation); 
      }
    }
  }

  //vel
  if (theOscMessage.checkAddrPattern("/7/fader0")) {
    if (theOscMessage.checkTypetag("f")) {
      vel = (int)(127*theOscMessage.get(0).floatValue());
    }
    println("vel: " + vel);
  }

  //pitchbend 0〜16383
  if (theOscMessage.checkAddrPattern("/7/fader3")) {
    if (theOscMessage.checkTypetag("f")) {
      pitch = (int)(16383*theOscMessage.get(0).floatValue());
    }
    println("pitch: " + pitch);
    output.sendPitchBend( ch, pitch );
  }
 
  //program(音色)Touch OSC Send+
  if (theOscMessage.checkAddrPattern("/7/nav6")) {
    if (theOscMessage.checkTypetag("f")) {
      if((int)(theOscMessage.get(0).floatValue())==0) {
        if (program<100) {
          program=program+1;
        }
        println("program: " + program);
        output.sendProgramChange (program);
      }
    }
  }
  
  //program(音色)Touch OSC Send-
  if (theOscMessage.checkAddrPattern("/7/nav5")) {
    if (theOscMessage.checkTypetag("f")) {
      if((int)(theOscMessage.get(0).floatValue())==0) {
        if (program>0) {
          program=program-1;
        }
        println("program: " + program);
        output.sendProgramChange (program);
      }
    }
  }
  
}

 

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

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

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

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

 

③音色の変更

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

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

Back To Top

ソフトシンセの利用(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

ソフトシンセの利用(UVIWorkstation)

※1107教室Mac OSX10.8環境

 

①UVIWorkstationの起動

※フリー音源UVIWorkstationはココからダウンロードできる。

ApplicationフォルダからUVIWorkstationを起動する。

 

②Audio Deviceの確認(UVIWorkstation)

Fileメニュー>Audio and MIDI Settingsをクリックする。

Audio DeviceのOutputを確認する。
Built-in OutputはMac標準の出力装置。

 

③音源ライブラリの読み込み

フォルダアイコン>Soundbanks>Falcon Preset Tour>任意の音源(uvip)をダブルクリックする。

 

④演奏実験

下図アイコンをクリックして、Keyboradインターフェースを表示する。

鍵盤で音が鳴るか実験。

 

⑤AUDIO-MIDI設定(Mac)

Applicationフォルダ>ユーティリティ>AUDIO-MIDI設定.appを起動する。

ウィンドウメニュー>MIDIウィンドウ(MIDIスタジオ)を表示する。

IACドライバをダブルクリックして、装置のオンラインにチェックを入れる。

 

⑥MIDI Devicesの確認(UVIWorkstation)

Fileメニュー>Audio and MIDI Settingsをクリックする。

MIDI Devicesを確認する。Port AにIACドライバIACバス1が表示されていれば問題ない。

 

⑦Proessingスケッチで演奏

実験2のスケッチをRunして、コンソールウィンドウに表示されるOutput Deviceを確認する。

下図例では、Unknown name Apple Inc.がOutput Device 1であることがわかる。

実験2のスケッチのコード13行目dev=1に変更する。

Back To Top

実験3 iPadで演奏(デモのみ)

実験2のスケッチはOSC受信にも対応させているので、iPhoneやiPad等のOSCアプリから遠隔で演奏することができる。今回はTouch OSC(600円)を利用したデモを行う。

iPadから下図のような流れでOSC送信している。OSC受信には、IPアドレスとポート番号の指定が必要。

 

ソフトシンセがOSCを直接受信できる場合は下図のような制御方法も可能。

Back To Top

Open Sound Controlとは?

Open Sound Control (OSC)は、ネットワークを介してコンピュータやサウンドシンセサイザー機器同士でデータ通信を行なうための規格。通信方式はUDPやTCP。Ethernet や無線LAN でデータを送ることができる。

OSCはMIDI次世代規格として位置づけられているが、Processing、openFrameworks、TouchDesignerで扱うことが可能で、VJソフトや照明機器等、異なるプラットフォーム間の通信としても使われている。仕様が決められていたMIDIメッセージに対して、OSCでは制約がなくURL形式で自由に名前付けした階層化されたデータを扱うことができる。このため、複雑なデータを効率良く送信することが可能である。

Back To Top

実験4 OSCリモート演奏

OSC通信を利用して、異なるPC間のリモート演奏を実験する。

OSC通信には、下図のように送信先のIPアドレスとポート番号が必須となる。(IPアドレスとポート番号の解説は別途

 

①スケッチの準備

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

import oscP5.*; //oscP5ライブラリの読み込み
import netP5.*;
import rwmidi.*;  //RWMIDIライブラリの読み込み
import processing.net.*;
OscP5 oscP5;
MidiOutput output;
NetAddress myRemoteLocation;

int ch = 0;  //Midi Chの設定 ここ変えるとKontakt Playeyの別のラックの音出せる
int note_on = 0;  //NoteOnナンバー(変数)
int note_off = 60; //NoteOffナンバー(変数)
int pitch = 8192; //ピッチベンド
int vel = 100;  //Velocity(音の強さ)の設定0〜127
int program = 20; //プログラムチェンジ(音色)の設定
int dev = 0;  //音源の設定 UVI Workstsionの起動したときは1
int devLength = 0; //デバイスの数

int lock = 0; //マウスの連打を防止するため
int interval_cnt = 0;
float firstValue = 0;
String[] patt_address = new String[80]; //osc受信照合メッセージ格納
int noteNo = 0;

int rcv_port = 8000; //受信ポート

void setup () {
  size (500, 300); //ウィンドウサイズ
  frameRate (30);
  oscP5 = new OscP5 (this, rcv_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() );
  }
  
  //このスケッチ同士で演奏し合うOSCパターンの初期化
  for (int i = 41; i < 80; i++) {
    patt_address[i] = "/naka" + String.valueOf(i);
  }
  
  myRemoteLocation = new NetAddress("192.168.0.8", 8000); //送信先IPアドレスとポート
}
 
void draw () {
  background (0, 0, 0);
  text ("***** OSC Communication!! *****", 15, 20);
  
  text ("Device Name: " + output.getName (), 15, 40);
  text ("Program Change: " + program, 15, 60);
  if(note_on==0) {
    text ("Pushed Key: --", 15, 100); 
    text ("Send Note No: --", 15, 120); 
  } else {
    text ("Pushed Key: " + key, 15, 100);
    text ("Send Note No: " + note_on, 15, 120);
  }
  
  if(noteNo==0) {
    text ("OSC Message: --", 15, 160);
    text ("Receive Note No: --", 15, 180); 
  } else {
    text ("OSC Message: " + patt_address[noteNo], 15, 160);
    text ("Receive Note No: " + noteNo, 15, 180);
  }
  //text ("This PC IP: " + Server.ip(), 15, 260);
  text ("This PC IP: ***.***.***.***", 15, 260);
  text ("PORT: " + rcv_port, 170, 260);
  
  text ("Remote IP: " + myRemoteLocation.address(), 15, 280);
  text ("PORT: " + myRemoteLocation.port(), 170, 280);
}
 
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;
  }

  OscMessage myMessage = new OscMessage("/naka"+ String.valueOf(note_on)).add(1.0);
  oscP5.send(myMessage, myRemoteLocation);
  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;
  }
  
  OscMessage myMessage2 = new OscMessage("/naka"+ String.valueOf(note_off)).add(0.0);
  oscP5.send(myMessage2, myRemoteLocation);
    
  lock=0;
}

void mouseMoved ()
{

  OscMessage myMessage3 = new OscMessage("/naka"+ String.valueOf(255)).add((float)mouseX/(float)width); //naka255をピッチベンドに設定
  oscP5.send(myMessage3, myRemoteLocation);
}

//OSC受信処理
void oscEvent (OscMessage theOscMessage) {
  
  for (int k = 41; k < 80; k++) {
    if (theOscMessage.checkAddrPattern(patt_address[k])) {
      if (theOscMessage.checkTypetag("f")) {
        firstValue = theOscMessage.get(0).floatValue();
      }
      noteNo = k;
      
      if (firstValue == 1) {
        output.sendNoteOn( ch, noteNo, vel );
        println("noteon: ", ch, noteNo, vel);
        interval_cnt = interval_cnt ++;
      }  else {
        delay(10);//パッドを軽く押したら、ボスって音がする noteonからnoteoffの間が短すぎる delayで解決
        output.sendNoteOff( ch, noteNo, vel );
        println("noteoff: ", ch, noteNo, vel);
        
        output.sendPitchBend( ch, 8192 );  //ピッチベンドのリセット
      }
    }
  }

  //pitchbend 0〜16383
  if (theOscMessage.checkAddrPattern("/naka255")) { //255をピッチベントに設定
    if (theOscMessage.checkTypetag("f")) {
      pitch = (int)(16383*theOscMessage.get(0).floatValue());
    }
    //println("pitch: " + pitch);
    output.sendPitchBend( ch, pitch );
  }
  
}

 

②送信IPアドレスの設定

パートナーPCのIPアドレス(送信先)を確認する。

システム環境設定>ネットワーク>詳細>TCP/IPのIPv4アドレス(下図)で確認。

コード43行目の"192.168.0.8"を送信先のIPアドレスに変更する。

 

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

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

実験2と同じキーボードで送信先PCを利用して演奏することができる。キーを押したまま、マウスを左右に振ることで音高を変化させることもできる。送信先で音色や音源を変更するなど実験してみよう。

Pushed KeyとSend Note Noに操作情報、OSC MessageとReceive Note Noに受信情報が表示される。

Back To Top

実験5 OSCマルチリモート演奏(デモのみ)

操作側から複数アプリケーションに対して同時にOSCを送信することができる。OSC対応の音響機器、映像機器、照明機器を用いれば、大規模な演出システムを実現することもできる。

①スケッチの準備

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

import oscP5.*; //oscP5ライブラリの読み込み
import netP5.*;
import rwmidi.*;  //RWMIDIライブラリの読み込み
import processing.net.*;
OscP5 oscP5;
MidiOutput output;
NetAddress myRemoteLocation;

int ch = 0;  //Midi Chの設定 ここ変えるとKontakt Playeyの別のラックの音出せる
int note_on = 0;  //NoteOnナンバー(変数)
int note_off = 60; //NoteOffナンバー(変数)
int pitch = 8192; //ピッチベンド
int vel = 100;  //Velocity(音の強さ)の設定0〜127
int program = 20; //プログラムチェンジ(音色)の設定
int dev = 0;  //音源の設定 UVI Workstsionの起動したときは1
int devLength = 0; //デバイスの数

int lock = 0; //マウスの連打を防止するため
int interval_cnt = 0;
float firstValue = 0;
String[] patt_address = new String[80]; //osc受信照合メッセージ格納
int noteNo = 0;

int rcv_port = 8000; //受信ポート
int ip_max = 40;
NetAddress[] multiRemoteLocation = new NetAddress[ip_max];

void setup () {
  size (500, 300); //ウィンドウサイズ
  frameRate (30);
  oscP5 = new OscP5 (this, rcv_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() );
  }
  
  //このスケッチ同士で演奏し合うOSCパターンの初期化
  for (int i = 41; i < 80; i++) {
    patt_address[i] = "/naka" + String.valueOf(i);
  }
  
  //複数IPアドレスの初期化
  for (int i = 0; i < ip_max; i++) {
    multiRemoteLocation[i] = new NetAddress("192.168.0."+i, 8000);
  }
}
 
void draw () {
  background (0, 0, 150);
  text ("***** OSC Communication!! *****", 15, 20);
  
  text ("Device Name: " + output.getName (), 15, 40);
  text ("Program Change: " + program, 15, 60);
  if(note_on==0) {
    text ("Pushed Key: --", 15, 100); 
    text ("Send Note No: --", 15, 120); 
  } else {
    text ("Pushed Key: " + key, 15, 100);
    text ("Send Note No: " + note_on, 15, 120);
  }
  
  if(noteNo==0) {
    text ("OSC Message: --", 15, 160);
    text ("Receive Note No: --", 15, 180); 
  } else {
    text ("OSC Message: " + patt_address[noteNo], 15, 160);
    text ("Receive Note No: " + noteNo, 15, 180);
  }
  
  text ("This PC IP: " + Server.ip(), 15, 260);
  text ("PORT: " + rcv_port, 170, 260);
  
  text ("Multi Remote IP: Refer to Code 48", 15, 280);
}
 
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;
  }
  OscMessage myMessage = new OscMessage("/naka"+ String.valueOf(note_on)).add(1.0);
  for (int i=0; i<ip_max; i++) {
    oscP5.send(myMessage, multiRemoteLocation[i]); 
  }
  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;
  }
  OscMessage myMessage2 = new OscMessage("/naka"+ String.valueOf(note_off)).add(0.0);
  for (int i=0; i<ip_max; i++) {
    oscP5.send(myMessage2, multiRemoteLocation[i]); 
  }
    
    lock=0;
}

void mouseMoved ()
{

  OscMessage myMessage3 = new OscMessage("/naka"+ String.valueOf(255)).add((float)mouseX/(float)width); //naka255をピッチベンドに設定
    for (int i=0; i<ip_max; i++) {
    oscP5.send(myMessage3, multiRemoteLocation[i]); 
  }
}

//OSC受信処理
void oscEvent (OscMessage theOscMessage) {
  
  for (int k = 41; k < 80; k++) {
    if (theOscMessage.checkAddrPattern(patt_address[k])) {
      if (theOscMessage.checkTypetag("f")) {
        firstValue = theOscMessage.get(0).floatValue();
      }
      noteNo = k;
      
      if (firstValue == 1) {
        output.sendNoteOn( ch, noteNo, vel );
        println("noteon: ", ch, noteNo, vel);
        interval_cnt = interval_cnt ++;
      }  else {
        delay(10);//パッドを軽く押したら、ボスって音がする noteonからnoteoffの間が短すぎる delayで解決
        output.sendNoteOff( ch, noteNo, vel );
        println("noteoff: ", ch, noteNo, vel);
        
        output.sendPitchBend( ch, 8192 );  //ピッチベンドのリセット
      }
    }
  }

  //pitchbend 0〜16383
  if (theOscMessage.checkAddrPattern("/naka255")) { //255をピッチベントに設定
    if (theOscMessage.checkTypetag("f")) {
      pitch = (int)(16383*theOscMessage.get(0).floatValue());
    }
    println("pitch: " + pitch);
    output.sendPitchBend( ch, pitch );
  }
  
}

 

②リモートIPアドレスの設定

コード47行目の「”192.168.0.”」を使用環境のIPアドレスに合わせる。
0〜ip_max(25行目)までの複数IPアドレスに対してOSCを送信する。

 

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

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

実験2と同じキーボードで複数の送信側PCを利用して演奏することができる。
キーを押したまま、マウスを左右に振ることで音高を変化させることもできる。

Back To Top

KAGURA

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

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

Back To Top