« 5月18日:サンプリング&プレイバック | メイン | 6月15日:パフォーマンスについて考える »

6月1日: OSCによるネットワーク上でのコミュニケーション

Open Sound Control, ネットワークの利用

複数のコンピュータ間をつなぐネットワークは、メディアアートの表現にとって様々な可能性を秘めた、欠かすことのできない重要な要素である。コンピュータネットワークの技術は、日々進歩しており、それを用いた表現もまた刻々と進化している。コンピュータ音楽の分野でも、通信技術の進歩に伴って、ネットワーク上での音楽表現やコミュニケーションを実現するために様々な研究が行われており、その成果を利用することが可能となってきている。

今週の授業では、コンピュータネットワークを利用して、複数のコンピューター同士で音響合成のためのパラメータを双方向にやり取りする手法の例として、Open Sound Control(OSC)というプロトコル(データをやり取りするための規則)を取り上げる。OSCの基本的な考え方を解説した上で、Max/MSP、Flash、SuperColliderでのインプリメンテーションについて解説する。

OSCとは何か?

Open Sound Control(以降OSCと表記)は、カルフォルニア州立大学バークレー校のCNMAT(Center for New Music and Audio Technorogies)を中心に研究開発が進められている、コンピュータ音楽のための通信プロトコル(規則)である。OSCは現在のコンピュータネットワーク技術に対応して、複数のコンピュータやシンセサイザー、また様々なマルチメディアのデバイス間でコミュニケーションすることを目指している。

OSCホームページ
http://cnmat.cnmat.berkeley.edu/OSC/

これまでの通信技術(= MIDI)の限界

これまでコンピュータと電子楽器間を相互接続するプロトコルとして、MIDI(Musical Instrument Digital Interface)が標準的に用いられてきた。しかしながらコンピュータや電子デバイス、ネットワーク技術の進歩につれて、MIDIは時代遅れのものになりつつある。

MIDIの限界

  • バンド幅の限界
    • 複雑な音楽情報を制御するには、通信帯域が狭すぎる(31,250 bit/sec程度)
    • データの遅延も無視できない程生じてしまう
  • 相互接続の限界
    • 短方向の通信しかできないので通信の方向ごとにケーブルが必要(IN, OUT, THRU)
    • チャンネル数にも制限がある
  • 音楽記述の限界
    • 平均率の楽譜表現に偏ったプロトコル
    • 音色を記述することができない
    • 連続する値の変化を記述できない

OSCの特徴

OSCではこれまでのMIDIの欠点を踏まえた上でプロトコルの設計がなされている。

  • 開放的・動的なネーミング手法、URL(= Uniform Resorce Locator)とよく似た考え方
  • 数値、記号双方を通信できる
  • 高度なパターンマッチング
  • 高解像度の時間制御
  • 帯域幅の制限はしていない
  • 多くのソフトウェア、プログラミング言語に実装済み

OSCの実装されたプログラミング言語・アプリケーション一覧

サンプルファイルのダウンロード

本日のサンプルは以下からダウンロードしてください。

Download file

OSCを介して、Max/MSP同士でコミュニケーションする

OSCデータの送受信の基本形

0601_fig01.gif

0601_fig02.gif

  • メッセージの送信:OpenSoundControlオブジェクトの第1インレットに送信したいデータを入力
    • 受け取ったメッセージを"outudt write ネットワークアドレス(or URI) port番号"を用いてネットに送信
  • メッセージの受信:"outudt write ネットワークアドレス(or URI) port番号"を用いてネットから受信
    • 受け取った内容を、OpenSoundControlオブジェクトを用いて変換、osc-routeを用いてメッセージから値を取り出す
  • それぞれのメッセージは、「OSCメッセージ 値」という組合せで送られる
  • OSCメッセージの名前はURIのように、スラッシュ"/"で区切られた階層的な構造になっていることに注意。
  • この例では、OSCメッセージが階層的に構築されている
    • /message
    • /control
      • /number
      • /level
      • /bang

応用:Sine Wave Quartetto

0601_fig03.gif

0601_fig04.gif

  • 4つのオシレータをネットでコラボレーションしながら操作する
  • パラメータをさまざまな音響合成に応用することで、いろいろバリエーションを増やすことが可能

floscで、FlashからMax/MSPをコントロールする

Flashと他のOSCを使用可能なアプリケーション・言語とを、OSC経由でコミュニケーションするには、floscというJAVAで書かれたサーバーを経由して使います。floscは、flash5以降に標準装備されているXMLSocketを利用してFlashとOSCアプリとのゲートウェイ(異なるコンピューターのネットワークを接続する装置)のような役割を果たします。

floscを介したOSCの送信テスト画面

0601_fig05.gif

ActionScriptでのOSC入出力のための関数定義

/**
* flosc - Flash OpenSound Control
* Ben Chun, 2002
*
* Credits:
* design and structure based on MoockComm by Colin Moock.
* server based on CommServer by Derek Clayton.
* (see TcpServer.java and TcpClient.java for more information.)
*
*/

stop ();

// *** general init
var incomingUpdated = false;	// flag to scroll the "incoming" window
incoming = "";					// clear the text field to start out

// attach the scroll manager movie
// (see its child movie's enterframe event for scroll code)
attachMovie("processScroll", "processScroll", 0);

// turn off ugly yellow highlight on buttons
_focusrect = 0;

// 新たなソケットを生成し、サーバ接続を要求
function connect () {
	mySocket = new XMLSocket();
	mySocket.onConnect = handleConnect;
	mySocket.onClose = handleClose;
	mySocket.onXML = handleIncoming;

	if (!mySocket.connect(IPaddress, port)) gotoAndStop("connectionFailed");
}

//サーバから切り離す
function disconnect () {
	mySocket.close();
	mySocket.connected = false;
	incoming = "";
	gotoAndStop(2);
}


// XMLエンコードされたOSCパケットを扱うための関数
function handleIncoming (xmlIn) {
	
	// USEFUL DEBUG - display the raw xml data in the output window
	// incoming += xmlIn.toString() +"¥n";

	// parse out the packet information
	e = xmlIn.firstChild;
	if (e != null && e.nodeName == "OSCPACKET") {
		packet = new OSCPacket(e.attributes.address, e.attributes.port,
								e.attributes.time, xmlIn);
		displayPacketHeaders(packet);
		parseMessages(xmlIn);
	}

	// tell the text field manager it's time to scroll
	incomingUpdated = true;
	lastScrollPos = incoming.scroll;
}


//接続が成功したときに返答するための関数
function handleConnect (succeeded) {
	if(succeeded) {
		incoming += "Connected to " + IPaddress + 
					" on port " + port + "¥n";
		mySocket.connected = true;
	} else {
		mySocket.connected = false;
	}
	gotoAndPlay("connecting");
}


//サーバ接続がとぎれた際に呼ばれる関数
function handleClose () {
	incoming += ("The server at " + IPaddress + " has terminated the connection.¥n");
	incomingUpdated = true;
	mySocket.connected = false;
	numClients = 0;
}


//OSCパケット生成
function OSCPacket(address, port, time, xmlData) {
	this.address = address;
	this.port = port;
	this.time = time;
	this.xmlData = xmlData;
}


//OSCパケットの情報をテキストフィールドに表持するための関数
function displayPacketHeaders(packet) {
	incoming += "** OSC Packet from " + packet.address +
				", port " + packet.port +
				" for time " + packet.time + "¥n";
}


//XMLエンコードされたOSCパケットからメッセージを取り出すための関数
function parseMessages(node) {

	if (node.nodeName == "MESSAGE") {
		incoming += "Message name: " + node.attributes.NAME + "¥n";
		// loop over the arguments of the message
		for (var child = node.firstChild; child != null; child=child.nextSibling) {
			if (child.nodeName == "ARGUMENT") {
				incoming += "¥tArg type " + child.attributes.TYPE;
				incoming += ", value " + child.attributes.VALUE + "¥n";
			}
		}
	}
	else { // look recursively for a message node
		for (var child = node.firstChild; child != null; child=child.nextSibling) {
			parseMessages(child);
		}
	}
}


//XMLエンコードされたOSCメッセージを生成する
function sendOSC(name, arg, destAddr, destPort) {
	xmlOut = new XML();

	osc = xmlOut.createElement("OSCPACKET");
	osc.attributes.TIME = 0;
	osc.attributes.PORT = destPort;
	osc.attributes.ADDRESS = destAddr;

	message = xmlOut.createElement("MESSAGE");
	message.attributes.NAME = name;

	argument = xmlOut.createElement("ARGUMENT");
	// NOTE : the server expects all strings to be encoded
	// with the escape function.
	argument.attributes.VALUE = escape(arg);
	argument.attributes.TYPE = "s";
	
	// NOTE : to send more than one argument, just create
	// more elements and appendChild them to the message.
	// the same goes for multiple messages in a packet.
	message.appendChild(argument);
	osc.appendChild(message);
	xmlOut.appendChild(osc);

	if (mySocket && mySocket.connected) {
		mySocket.send(xmlOut);
		incoming += "Sent XML-encoded OSC destined for "
					+ destAddr
					+ ", port "
					+ destPort
					+ "¥n";
	}

	incomingUpdated = true;
}

OSCメッセージ送信ボタンに埋め込まれた、ボタンスクリプト

on (release) {
	sendOSC(_root.msgName, _root.msgArg, destAddr, destPort);
}

flosc応用: 宇宙船(?)の位置でオシレータをコントロール!

0601_fig06.gif

0601_fig07.gif

宇宙船オブジェクトに適用されているムービーオブジェクト

onClipEvent (load) {
	// パラメータの初期化
	thrust = 1;
	decay = .97;
	maxSpeed = 15;
}
onClipEvent (enterFrame) {
	// 右回転
	if (Key.isDown(Key.RIGHT)) {
		_rotation += 10;
	}
	// 左回転
	if (Key.isDown(Key.LEFT)) {
		_rotation -= 10;
	}
	// ↑が押されたら、移動軌道を再計算	
	if (Key.isDown(Key.UP)) {
		//三角関数を利用して、移動スピードと軌道を計算
		xSpeed += thrust*Math.sin(_rotation*(Math.PI/180));
		ySpeed += thrust*Math.cos(_rotation*(Math.PI/180));
		flames._visible = 1;
	} else {
		// ↑が押されていなければ、惰性で進む
		xSpeed *= decay;
		ySpeed *= decay;
		flames._visible = 0;
	}
	// 常にプラス方向に推進する
	speed = Math.sqrt((xSpeed*xSpeed)+(ySpeed*ySpeed));
	// スピードを最大値以内におさめる
	if (speed>maxSpeed) {
		xSpeed *= maxSpeed/speed;
		ySpeed *= maxSpeed/speed;
	}
	// 
	// 計算されたX,Yの移動スピードで物体を移動
	_y -= ySpeed;
	_x += xSpeed;
	// 
	// 画面からはみ出したら、反対側から出現
	if (_y<0) {
		_y = 400;
	}
	if (_y>400) {
		_y = 0;
	}
	if (_x<0) {
		_x = 400;
	}
	if (_x>400) {
		_x = 0;
	}
        // ムービーのX,Y座標をもとに、OSCメッセージを送信		      
	_root.sendOSC("/xpos", _x*2+100, _root.destAddr, _root.destPort);
	_root.sendOSC("/ypos", _y*2+100, _root.destAddr, _root.destPort);
}

SuperCollider ←→ Max/MSPのコミュニケーション

Max/MSPでSCのインタフェイスを作る

SCのポート57110にOSCメッセージを送信

0601_fig08.gif

SuperCollider3側プログラム

Max/MSPからOSCメッセージを受け取り、音を鳴らす

(
SynthDef("double-osc", { arg freq1 = 440, freq2 = 440, am = 0.5;
	var osc1, osc2;
	osc1 = SinOsc.ar(freq1,0,amp);
	osc2 = SinOsc.ar(freq2,0,amp);
	Out.ar(0, [osc1, osc2]);
}).writeDefFile;

s.sendSynthDef("double-osc");
)

さらに細かい内容は…

サンプルフォルダ内の、赤松政行氏による、「SuperCollider3におけるネットワーキング」を参照してください。(※フォルダ"dspss2004-aka"内)。

投稿者 Atsushi Tadokoro : May 31, 2004 11:16 PM

コメント