openframeworks、サウンド機能・音響合成、ofxmaxim, ofxosc, ofxpd, ofxsupercollider
DESCRIPTION
TRANSCRIPT
Media Art II 2011 第7回:openFrameworksサウンド、音響合成ofxMaxim, ofxOsc, ofxSuperCollider, ofxPd
2011年11月15日多摩美術大学 情報デザイン学科 情報芸術コース田所 淳
今日の内容‣ openFrameworks音に関する機能いろいろ
‣ openFrameworksの標準機能‣ サウンドファイルの再生 (ofSoundPlayer)‣ サウンド入出力 (audioIn(), audioOut())
‣ 音響合成のためのAddonを利用 (ofxMaxim)
‣ 外部プログラムとの連携‣ OSCとは?‣ Pdとの連携 (ofxPd)‣ SuperColliderとの連携 (ofxSuperCollider)
サウンドファイルの再生ofSoundPlayer
サウンドファイルの再生 - ofSoundPlayer‣ ofSoundPlayer‣ サウンドファイルをよみこんで、再生する‣ おそらく、一番楽なサウンドを鳴らすための方法
‣ 画像ファイルの読込と同様、ファイルはプロジェクトのdataフォルダに格納する
‣ 《projectのフォルダ》/bin/data/
サウンドファイルの再生 - ofSoundPlayer‣ ofSoundPlayer‣ サウンドファイルをよみこんで、再生する‣ おそらく、一番楽なサウンドを鳴らすための方法
‣ 様々な機能を内蔵‣ ボリュームの設定‣ 左右の定位(pan)‣ 周波数解析(FFT) ...etc.
‣ 音声ファイルはプロジェクトのdataフォルダに格納する‣ 《projectのフォルダ》/bin/data/
サウンドファイルの再生 - ofSoundPlayer‣ サウンドファイルを読み込んで再生するサンプル
‣ 再生されたサンプルをリアルタイムにFFT解析し、視覚化‣ 画面の中心から両端に向かって、周波数帯域ごとのパワーの値で円を描いてみる
サウンドファイルの再生 - ofSoundPlayer‣ testApp.h#pragma once#include "ofMain.h"
class testApp : public ofBaseApp{ public: void setup(); void update(); void draw(); ofSoundPlayer mySound;
float * fft;
int nBandsToGet;};
サウンドファイルの再生 - ofSoundPlayer‣ testApp.h#pragma once#include "ofMain.h"
class testApp : public ofBaseApp{ public: void setup(); void update(); void draw(); ofSoundPlayer mySound;
float * fft;
int nBandsToGet;};
※サウンドプレーヤー
※FFT解析結果を格納する配列(ポインタ)
※FFT解析の分解精度(2の累乗)
サウンドファイルの再生 - ofSoundPlayer‣ testApp.cpp - 1 of 2‣#include "testApp.h"void testApp::setup(){! ofSetFrameRate(60); ofSetVerticalSync(true); ofSetCircleResolution(32); ofEnableBlendMode(OF_BLENDMODE_ADD); ofBackground(0, 0, 0); nBandsToGet = 1024; mySound.loadSound("sounds/drumLoop.aif"); mySound.setLoop(true); mySound.play();}
void testApp::update(){ ofSoundUpdate(); fft = ofSoundGetSpectrum(nBandsToGet);}
サウンドファイルの再生 - ofSoundPlayer‣ testApp.cpp - 1 of 2‣#include "testApp.h"void testApp::setup(){! ofSetFrameRate(60); ofSetVerticalSync(true); ofSetCircleResolution(32); ofEnableBlendMode(OF_BLENDMODE_ADD); ofBackground(0, 0, 0); nBandsToGet = 1024; mySound.loadSound("sounds/drumLoop.aif"); mySound.setLoop(true); mySound.play();}
void testApp::update(){ ofSoundUpdate(); fft = ofSoundGetSpectrum(nBandsToGet);}
※画面初期設定
サウンドファイルの再生 - ofSoundPlayer‣ testApp.cpp - 1 of 2‣#include "testApp.h"void testApp::setup(){! ofSetFrameRate(60); ofSetVerticalSync(true); ofSetCircleResolution(32); ofEnableBlendMode(OF_BLENDMODE_ADD); ofBackground(0, 0, 0); nBandsToGet = 1024; mySound.loadSound("sounds/drumLoop.aif"); mySound.setLoop(true); mySound.play();}
void testApp::update(){ ofSoundUpdate(); fft = ofSoundGetSpectrum(nBandsToGet);}
※FFTの周波数成分の解像度を設定 (2の累乗)
サウンドファイルの再生 - ofSoundPlayer‣ testApp.cpp - 1 of 2‣#include "testApp.h"void testApp::setup(){! ofSetFrameRate(60); ofSetVerticalSync(true); ofSetCircleResolution(32); ofEnableBlendMode(OF_BLENDMODE_ADD); ofBackground(0, 0, 0); nBandsToGet = 1024; mySound.loadSound("sounds/drumLoop.aif"); mySound.setLoop(true); mySound.play();}
void testApp::update(){ ofSoundUpdate(); fft = ofSoundGetSpectrum(nBandsToGet);}
※サウンドファイルを読み込んでループ再生
サウンドファイルの再生 - ofSoundPlayer‣ testApp.cpp - 1 of 2‣#include "testApp.h"void testApp::setup(){! ofSetFrameRate(60); ofSetVerticalSync(true); ofSetCircleResolution(32); ofEnableBlendMode(OF_BLENDMODE_ADD); ofBackground(0, 0, 0); nBandsToGet = 1024; mySound.loadSound("sounds/drumLoop.aif"); mySound.setLoop(true); mySound.play();}
void testApp::update(){ ofSoundUpdate(); fft = ofSoundGetSpectrum(nBandsToGet);}
※サウンドプレーヤーを更新して、FFT解析
サウンドファイルの再生 - ofSoundPlayer‣ testApp.cpp - 2 of 2void testApp::draw(){ float width = float(ofGetWidth()) / float(nBandsToGet) / 2.0f;
for (int i = 0;i < nBandsToGet; i++){ int b = float(255) / float(nBandsToGet) * i; int g = 31; int r = 255 - b; ofSetColor(r, g, b);
ofCircle(ofGetWidth()/2 + width * i, ofGetHeight()/2, fft[i] * 800);
ofCircle(ofGetWidth()/2 - width * i, ofGetHeight()/2, fft[i] * 800); }}
サウンドファイルの再生 - ofSoundPlayer‣ testApp.cpp - 2 of 2void testApp::draw(){ float width = float(ofGetWidth()) / float(nBandsToGet) / 2.0f;
for (int i = 0;i < nBandsToGet; i++){ int b = float(255) / float(nBandsToGet) * i; int g = 31; int r = 255 - b; ofSetColor(r, g, b);
ofCircle(ofGetWidth()/2 + width * i, ofGetHeight()/2, fft[i] * 800);
ofCircle(ofGetWidth()/2 - width * i, ofGetHeight()/2, fft[i] * 800); }}
※円の配置間隔を計算
サウンドファイルの再生 - ofSoundPlayer‣ testApp.cpp - 2 of 2void testApp::draw(){ float width = float(ofGetWidth()) / float(nBandsToGet) / 2.0f;
for (int i = 0;i < nBandsToGet; i++){ int b = float(255) / float(nBandsToGet) * i; int g = 31; int r = 255 - b; ofSetColor(r, g, b);
ofCircle(ofGetWidth()/2 + width * i, ofGetHeight()/2, fft[i] * 800);
ofCircle(ofGetWidth()/2 - width * i, ofGetHeight()/2, fft[i] * 800); }}
※色のグラデーションを生成
サウンドファイルの再生 - ofSoundPlayer‣ testApp.cpp - 2 of 2void testApp::draw(){ float width = float(ofGetWidth()) / float(nBandsToGet) / 2.0f;
for (int i = 0;i < nBandsToGet; i++){ int b = float(255) / float(nBandsToGet) * i; int g = 31; int r = 255 - b; ofSetColor(r, g, b);
ofCircle(ofGetWidth()/2 + width * i, ofGetHeight()/2, fft[i] * 800);
ofCircle(ofGetWidth()/2 - width * i, ofGetHeight()/2, fft[i] * 800); }}
※円の描画
サウンドファイルの再生 - ofSoundPlayer‣ 実行結果:サウンドのループ再生と、FFT解析
サウンド入出力audioIn(), audioOut()
サウンド入出力‣ openFrameworksには、サウンド入出力のためのイベントが用意されている
‣ サウンド入力‣ void audioIn(float * input, int bufferSize, int nChannels);
‣ サウンド出力‣ void audioOut(float * input, int bufferSize, int nChannels);
‣ input - 入出力される信号のデータ‣ bufferSize - バッファサイズ‣ nChannels - チャンネル数
サウンド入出力‣ Exampleにあるサンプルプログラムを参考にしてみる
‣ サウンド入力‣ apps/examples/audioInputExample
‣ サウンド出力‣ apps/examples/audioOutputExample
サウンド入力 - audioInputExample‣ testApp.h#ifndef _TEST_APP#define _TEST_APP#include "ofMain.h"
class testApp : public ofBaseApp{public: void setup(); void update(); void draw(); 《中略》 void audioIn(float * input, int bufferSize, int nChannels); ! vector <float> left; vector <float> right; vector <float> volHistory;
《後略》
サウンド入力 - audioInputExample‣ testApp.h#ifndef _TEST_APP#define _TEST_APP#include "ofMain.h"
class testApp : public ofBaseApp{public: void setup(); void update(); void draw(); 《中略》 void audioIn(float * input, int bufferSize, int nChannels); ! vector <float> left; vector <float> right; vector <float> volHistory;
《後略》
※サウンド入力のためのイベント
サウンド入力 - audioInputExample‣ testApp.cpp audioIn()関数void testApp::audioIn(float * input, int bufferSize, int nChannels){!! float curVol = 0.0;! int numCounted = 0;!
! for (int i = 0; i < bufferSize; i++){! ! left[i]!! = input[i*2]*0.5;! ! right[i]! = input[i*2+1]*0.5;! ! curVol += left[i] * left[i];! ! curVol += right[i] * right[i];! ! numCounted+=2;! }
! curVol /= (float)numCounted;! curVol = sqrt( curVol );!! smoothedVol *= 0.93;! smoothedVol += 0.07 * curVol;! bufferCounter++;!}
サウンド入力 - audioInputExample‣ testApp.cpp audioIn()関数void testApp::audioIn(float * input, int bufferSize, int nChannels){!! float curVol = 0.0;! int numCounted = 0;!
! for (int i = 0; i < bufferSize; i++){! ! left[i]!! = input[i*2]*0.5;! ! right[i]! = input[i*2+1]*0.5;! ! curVol += left[i] * left[i];! ! curVol += right[i] * right[i];! ! numCounted+=2;! }
! curVol /= (float)numCounted;! curVol = sqrt( curVol );!! smoothedVol *= 0.93;! smoothedVol += 0.07 * curVol;! bufferCounter++;!}
左右の入力の波形を取得取得した波形から音量を算出音量の表示の変化をスムーズに加工
サウンド入力 - audioInputExample‣ 実行結果:波形と音量の平均が表示される
サウンド出力 - audioOutputExample‣ testApp.h#ifndef _TEST_APP#define _TEST_APP#include "ofMain.h"
class testApp : public ofBaseApp{public: void setup(); void update(); void draw();
《中略》 void audioOut(float * input, int bufferSize, int nChannels); ofSoundStream soundStream; float ! pan; int! ! sampleRate; bool ! bNoise; float ! volume; vector <float> lAudio; vector <float> rAudio;};
#endif
サウンド出力 - audioOutputExample‣ testApp.h#ifndef _TEST_APP#define _TEST_APP#include "ofMain.h"
class testApp : public ofBaseApp{public: void setup(); void update(); void draw();
《中略》 void audioOut(float * input, int bufferSize, int nChannels); ofSoundStream soundStream; float ! pan; int! ! sampleRate; bool ! bNoise; float ! volume; vector <float> lAudio; vector <float> rAudio;};
#endif
※サウンド出力のためのイベント
サウンド出力 - audioOutputExample‣ testApp.cpp audioOutイベントvoid testApp::audioOut(float * output, int bufferSize, int nChannels){ float leftScale = 1 - pan; float rightScale = pan;
while (phase > TWO_PI){ phase -= TWO_PI; } if ( bNoise == true){ for (int i = 0; i < bufferSize; i++){ lAudio[i] = output[i*nChannels ] = ofRandom(0, 1) * volume * leftScale; rAudio[i] = output[i*nChannels + 1] = ofRandom(0, 1) * volume * rightScale; } } else { phaseAdder = 0.95f * phaseAdder + 0.05f * phaseAdderTarget; for (int i = 0; i < bufferSize; i++){ phase += phaseAdder; float sample = sin(phase); lAudio[i] = output[i*nChannels ] = sample * volume * leftScale; rAudio[i] = output[i*nChannels + 1] = sample * volume * rightScale; } }}
サウンド出力 - audioOutputExample‣ testApp.cpp audioOutイベントvoid testApp::audioOut(float * output, int bufferSize, int nChannels){ float leftScale = 1 - pan; float rightScale = pan;
while (phase > TWO_PI){ phase -= TWO_PI; } if ( bNoise == true){ for (int i = 0; i < bufferSize; i++){ lAudio[i] = output[i*nChannels ] = ofRandom(0, 1) * volume * leftScale; rAudio[i] = output[i*nChannels + 1] = ofRandom(0, 1) * volume * rightScale; } } else { phaseAdder = 0.95f * phaseAdder + 0.05f * phaseAdderTarget; for (int i = 0; i < bufferSize; i++){ phase += phaseAdder; float sample = sin(phase); lAudio[i] = output[i*nChannels ] = sample * volume * leftScale; rAudio[i] = output[i*nChannels + 1] = sample * volume * rightScale; } }}
※左右の定位(パン)の設定
サウンド出力 - audioOutputExample‣ testApp.cpp audioOutイベントvoid testApp::audioOut(float * output, int bufferSize, int nChannels){ float leftScale = 1 - pan; float rightScale = pan;
while (phase > TWO_PI){ phase -= TWO_PI; } if ( bNoise == true){ for (int i = 0; i < bufferSize; i++){ lAudio[i] = output[i*nChannels ] = ofRandom(0, 1) * volume * leftScale; rAudio[i] = output[i*nChannels + 1] = ofRandom(0, 1) * volume * rightScale; } } else { phaseAdder = 0.95f * phaseAdder + 0.05f * phaseAdderTarget; for (int i = 0; i < bufferSize; i++){ phase += phaseAdder; float sample = sin(phase); lAudio[i] = output[i*nChannels ] = sample * volume * leftScale; rAudio[i] = output[i*nChannels + 1] = sample * volume * rightScale; } }}
※sin波生成用のカウンタ(位相)をリセット
サウンド出力 - audioOutputExample‣ testApp.cpp audioOutイベントvoid testApp::audioOut(float * output, int bufferSize, int nChannels){ float leftScale = 1 - pan; float rightScale = pan;
while (phase > TWO_PI){ phase -= TWO_PI; } if ( bNoise == true){ for (int i = 0; i < bufferSize; i++){ lAudio[i] = output[i*nChannels ] = ofRandom(0, 1) * volume * leftScale; rAudio[i] = output[i*nChannels + 1] = ofRandom(0, 1) * volume * rightScale; } } else { phaseAdder = 0.95f * phaseAdder + 0.05f * phaseAdderTarget; for (int i = 0; i < bufferSize; i++){ phase += phaseAdder; float sample = sin(phase); lAudio[i] = output[i*nChannels ] = sample * volume * leftScale; rAudio[i] = output[i*nChannels + 1] = sample * volume * rightScale; } }}
※ホワイトノイズの生成
サウンド出力 - audioOutputExample‣ testApp.cpp audioOutイベントvoid testApp::audioOut(float * output, int bufferSize, int nChannels){ float leftScale = 1 - pan; float rightScale = pan;
while (phase > TWO_PI){ phase -= TWO_PI; } if ( bNoise == true){ for (int i = 0; i < bufferSize; i++){ lAudio[i] = output[i*nChannels ] = ofRandom(0, 1) * volume * leftScale; rAudio[i] = output[i*nChannels + 1] = ofRandom(0, 1) * volume * rightScale; } } else { phaseAdder = 0.95f * phaseAdder + 0.05f * phaseAdderTarget; for (int i = 0; i < bufferSize; i++){ phase += phaseAdder; float sample = sin(phase); lAudio[i] = output[i*nChannels ] = sample * volume * leftScale; rAudio[i] = output[i*nChannels + 1] = sample * volume * rightScale; } }}
※sin波の生成
サウンド出力 - audioOutputExample‣ 実行結果:サウンド(sin波とホワイトノイズ)を出力
サウンド入出力のプログラミング‣ testApp(ofBaseApp)に内蔵されているサウンド機能、audioIn() と audioOut() だけで高度な音響生成を行えるか?
‣ 技術的には不可能ではない‣ しかしながら、全てのデジタル信号処理(DSP)のプログラムを自前で用意しなければならない
‣ 専門的な知識が必要
‣ もう少し、お手軽な方法はないだろうか…?
音響合成のためのAddonを利用ofxMaxim
音響合成のためのAddon - ofxMaxim‣ ofxMaxim - C++で書かれた音響合成のためのライブラリ「Maxmilian」をopenFrameworksのAddonにしたもの
‣ Maxmilianページ(http://maximilian.strangeloop.co.uk/)
音響合成のためのAddon - ofxMaxim‣ 自分で一から音響生成のコードを書くより、ずっと簡単
‣ 様々な波形のオシレータ‣ サンプリング、オーディオファイルの再生‣ エンベロープ (時間による音量変化)‣ フィルタ‣ FFT (高速フーリエ変換) による周波数解析 ... etc.
ofxMaxim - ofxMaxiOscで波形を生成‣ ofxMaximに内蔵されているオシレータ‣ ofxMaxiOsc クラスを使用
オシレーター名称 説明
sinwave サイン波
saw のこぎり波
pulse 矩形波、パルス
triangle 三角波
noise ホワイトノイズ
ofxMaxim - ofxMaxiOscで波形を生成‣ いろいろな波形の音響を生成するプログラムを作ってみる‣ ofxMaximを使用するために、addonsフォルダに追加する
ofxMaxim - ofxMaxiOscで波形を生成‣ testApp.h#pragma once#include "ofMain.h"#include "ofxMaxim.h"
class testApp : public ofBaseApp{public: void setup(); void update(); void draw(); void keyPressed(int key); void audioOut(float * input, int bufferSize, int nChannels); void audioIn(float * input, int bufferSize, int nChannels);
int initialBufferSize; int sampleRate; int mode; double wave,sample,outputs[2];
ofxMaxiMix mymix; ofxMaxiOsc osc; vector <float> lAudio; vector <float> rAudio;};
ofxMaxim - ofxMaxiOscで波形を生成‣ testApp.cpp - audioOut() 音を生成している部分void testApp::audioOut(float * output, int bufferSize, int nChannels){ for (int i = 0; i < bufferSize; i++){ float freq = mouseY; float pan = (float)mouseX / (float)ofGetWidth(); switch (mode) { case 0: wave = osc.sinewave(freq); break; case 1: wave = osc.saw(freq); break; case 2: wave = osc.pulse(freq, 0.99); break; case 3: wave = osc.phasor(freq); break; case 4: wave = osc.triangle(freq); break; case 5: wave = osc.noise(); break; default: wave = osc.sinewave(freq); break; }
モードに応じて、波形を変更
ofxMaxim - ofxMaxiOscで波形を生成‣ testApp.cpp - audioOut() 音を生成している部分 mymix.stereo(wave, outputs, pan); lAudio[i] = output[i*nChannels ] = outputs[0]; rAudio[i] = output[i*nChannels + 1] = outputs[1]; }!}
生成された波形をミックス
サウンド再生波形表示用に値を確保している
ofxMaxim - ofxMaxiOscで波形を生成‣ 実行結果 (キーボードで波形を変更)
ofxMaximでFM合成‣ オシレータofxMaximOscをくみあわせた、音響合成も可能‣ 例えば、シンプルなFM合成を実装してみる
OSC(mod)
OSC(car)
freq amp
freq amp
+
ofxMaximでFM合成‣ testApp.h#pragma once#include "ofMain.h"#include "ofxMaxim.h"
class testApp : public ofBaseApp{public: ~testApp(); void setup(); void update(); void draw(); void audioOut(float * input, int bufferSize, int nChannels); void audioIn(float * input, int bufferSize, int nChannels);! int initialBufferSize; int sampleRate; double outputs[2]; double wave;
ofxMaxiMix mymix; ofxMaxiOsc car; ofxMaxiOsc mod; vector <float> lAudio; vector <float> rAudio;};
ofxMaximでFM合成‣ testApp.h#pragma once#include "ofMain.h"#include "ofxMaxim.h"
class testApp : public ofBaseApp{public: ~testApp(); void setup(); void update(); void draw(); void audioOut(float * input, int bufferSize, int nChannels); void audioIn(float * input, int bufferSize, int nChannels);! int initialBufferSize; int sampleRate; double outputs[2]; double wave;
ofxMaxiMix mymix; ofxMaxiOsc car; ofxMaxiOsc mod; vector <float> lAudio; vector <float> rAudio;};
バッファーサイズ、サンプリングレイト出力
ofxMaximでFM合成‣ testApp.h#pragma once#include "ofMain.h"#include "ofxMaxim.h"
class testApp : public ofBaseApp{public: ~testApp(); void setup(); void update(); void draw(); void audioOut(float * input, int bufferSize, int nChannels); void audioIn(float * input, int bufferSize, int nChannels);! int initialBufferSize; int sampleRate; double outputs[2]; double wave;
ofxMaxiMix mymix; ofxMaxiOsc car; ofxMaxiOsc mod; vector <float> lAudio; vector <float> rAudio;};
ミキシングキャリアオシレーター周波数モジュレーターオシレーター周波数
ofxMaximでFM合成‣ testApp.cpp - audioOut() FM合成をしている部分void testApp::audioOut(float * output, int bufferSize, int nChannels){ for (int i = 0; i < bufferSize; i++){ float index, modFreq; ofMap(modFreq, 0, mouseX, 20, 8000); ofMap(index, 0, mouseY, 1, 2000); wave = car.sinewave(mouseY*mod.sinewave(mouseX/10)+440); mymix.stereo(wave, outputs, 0.5); lAudio[i] = output[i*nChannels ] = outputs[0]; rAudio[i] = output[i*nChannels + 1] = outputs[1];! }}
ofxMaximでFM合成‣ testApp.cpp - audioOut() FM合成をしている部分void testApp::audioOut(float * output, int bufferSize, int nChannels){ for (int i = 0; i < bufferSize; i++){ float index, modFreq; ofMap(modFreq, 0, mouseX, 20, 8000); ofMap(index, 0, mouseY, 1, 2000); wave = car.sinewave(mouseY*mod.sinewave(mouseX/10)+440); mymix.stereo(wave, outputs, 0.5); lAudio[i] = output[i*nChannels ] = outputs[0]; rAudio[i] = output[i*nChannels + 1] = outputs[1];! }}
モジュレーターの周波数とモジュレーターの音量(Index)を設定
ofxMaximでFM合成‣ testApp.cpp - audioOut() FM合成をしている部分void testApp::audioOut(float * output, int bufferSize, int nChannels){ for (int i = 0; i < bufferSize; i++){ float index, modFreq; ofMap(modFreq, 0, mouseX, 20, 8000); ofMap(index, 0, mouseY, 1, 2000); wave = car.sinewave(mouseY*mod.sinewave(mouseX/10)+440); mymix.stereo(wave, outputs, 0.5); lAudio[i] = output[i*nChannels ] = outputs[0]; rAudio[i] = output[i*nChannels + 1] = outputs[1];! }}
FM合成
ofxMaximでFM合成‣ testApp.cpp - audioOut() FM合成をしている部分void testApp::audioOut(float * output, int bufferSize, int nChannels){ for (int i = 0; i < bufferSize; i++){ float index, modFreq; ofMap(modFreq, 0, mouseX, 20, 8000); ofMap(index, 0, mouseY, 1, 2000); wave = car.sinewave(mouseY*mod.sinewave(mouseX/10)+440); mymix.stereo(wave, outputs, 0.5); lAudio[i] = output[i*nChannels ] = outputs[0]; rAudio[i] = output[i*nChannels + 1] = outputs[1];! }}
左右2chでミックス
ofxMaximでFM合成‣ testApp.cpp - audioOut() FM合成をしている部分void testApp::audioOut(float * output, int bufferSize, int nChannels){ for (int i = 0; i < bufferSize; i++){ float index, modFreq; ofMap(modFreq, 0, mouseX, 20, 8000); ofMap(index, 0, mouseY, 1, 2000); wave = car.sinewave(mouseY*mod.sinewave(mouseX/10)+440); mymix.stereo(wave, outputs, 0.5); lAudio[i] = output[i*nChannels ] = outputs[0]; rAudio[i] = output[i*nChannels + 1] = outputs[1];! }} オーディオ出力
波形表示用にデータをコピー
ofxMaximでFM合成‣ 実行結果:FM合成
音響合成言語・アプリケーションとの連携Open Sound Control (OSC) について
‣ Open Sound Control のプロジェクトのWebページより
‣ Open Sound Control (OSC) is a protocol for communication among computers, sound synthesizers, and other multimedia devices that is optimized for modern networking technology. Bringing the benefits of modern networking technology to the world of electronic musical instruments, OSC's advantages include interoperability, accuracy, flexibility, and enhanced organization and documentation.
Open Sound Control とは
‣ Open Sound Control のプロジェクトのWebページより
‣ Open Sound Control (OSC) は、コンピュータやシンセサイザーや、その他のマルチメディアデバイス同士でコミュニケーションするための通信プロトコルです。現代のネットワーク技術の成果を電子楽器の世界に適用することで、OSCは、相互運用性、正確さ、柔軟さ、また、拡張性に優れた性能を持ちます。
Open Sound Control とは
‣ Open Sound Control のポイント
‣ ポストMIDIを目指す‣ インターネットのプロトコルの仕組みを、音楽やマルチメディアの世界へ適用 (UDP/IPを利用)
‣ 多くの機器、言語、アプリケーションに実装済み‣ オープンでシンプルな命名規則 ← URLの仕組みに似ている
Open Sound Control とは
‣ Open Sound Control が実装された主な環境
‣ サウンド系‣ Max/MSP‣ Pd‣ SuperCollider‣ Chuck‣ Csound‣ Reactor など
‣ ビジュアル系‣ Flash ( flosc )‣ Processing‣ OpenFrameworks‣ QuartzComposer‣ vvvv
Open Sound Control とは
‣ Open Sound Control が実装された主な環境
‣ デバイス‣ Lemur‣ monome
Open Sound Control とは
‣ Open Sound Control が実装された主な環境
‣ もちろんiPhoneも
Open Sound Control とは
‣ では、実際にOSCのプロトコルは、どんななっているのか?
/trigger/inst/a 440 0.1 “hello”
OSCのプロトコル
OSC Message OSC Arguments
• 情報内容をラベリング• URLに同様の名前付けの規則
• 情報の本体• いろいろな型を同時に含めることができる
‣ OSC Messageのアドレスパターン → URLのような階層構造
OSC Message
OSC の通信のしくみ
‣ 送信側:IPアドレスとportを指定
OSC の通信のしくみ
IP: 192.168.1.3port: 57120
‣ 受信側:ポートをオープン
OSC の通信のしくみ
IP: 192.168.1.3port: 57120
‣ 接続
OSC の通信のしくみ
IP: 192.168.1.3port: 57120
‣ 送信側:情報を送信‣ 受信側:受信
OSC の通信のしくみ
/trigger/inst/a 440 0.1 “hello”
IP: 192.168.1.3port: 57120
‣ 受信側:OSCのメッセージを解釈、アプリケーションに適用
OSC の通信のしくみ
/trigger/inst/a 440 0.1 “hello”
IP: 192.168.1.3port: 57120
‣ openFrameworksでOSCを使用するには?‣ ofxOsc というアドオンを利用する‣ OSCメッセージの送受信ができる
openFrameworksでOSCを使用するには?
‣ いくつかの、音響合成言語、アプリケーションは、独自にOSCを活用したAddonが存在する
‣ Pd (pure data):ofxPd‣ Pdを利用して音響合成が可能、Pdのパッチは、oFのプロジェクトに内包できる
‣ SuperCollider:ofxSuperCollider‣ OSCを介してSuperColliderのサーバーと通信して音響合成
‣ ofxSuperColliderServer‣ SuperColliderのパッチをoFのプロジェクトに内包できるバージョン (比嘉了さん作!!)
openFrameworksでOSCを使用するには?
Pdとの連携 - ofxPd
‣ 簡単なFM合成で実験‣ Pdのパッチ
Pdとの連携 - ofxPd
‣ 作成したPdのパッチは、dataフォルダに入れる
‣ 連携の詳細は、サンプルファイル「06_ofxPd」をみながら解説します
Pdとの連携 - ofxPd
SuperColliderとの連携 - ofxSuperCollider
‣ ofxPdと同様、SuperColliderとの連携も可能
‣ 起動手順が重要、以下の手順で
‣ まず、SuperColliderのパッチを開く‣ SCのLocalhost ServerをBoot‣ SynthDefファイルを選択して評価、楽器を生成‣ openFrameworksのアプリを実行
SuperColliderと連携 - ofxSuperCollider
ofxMaximでFM合成‣ SuperColliderの楽器定義、reverb, baseSound, newRingSynthDef("reverb", {
arg wet=1.0; var in, fx; in = In.ar(0, 2); fx = in; fx = GVerb.ar(fx, 80); ReplaceOut.ar(0, fx);}).store;
SynthDef("baseSound", { arg note=40, amp=0.1, fadein=12.0; var env, out; env = EnvGen.kr(Env.new([0, amp], [fadein])); out = RLPF.ar(LFPulse.ar([note, note+7].midicps, 0.15), SinOsc.kr(0.1, 0, 10, 72).midicps, 0.1, 0.1); Out.ar(0, out*env);}).store;
SynthDef("newRing", { arg note=40, amp=0.5, pan = 0.0, decay=4.0; var env1, out1, env2, out2, mix; out1 = RLPF.ar(LFPulse.ar([note, note+7].midicps, 0.15), SinOsc.kr(0.1, 0, 10, 72).midicps, 0.1, 0.1); out2 = SinOsc.ar([(note+48).midicps, (note+55).midicps]); env1 = EnvGen.kr(Env.perc(decay/4.0, decay/4.0*3.0, amp, -4), doneAction: 2); env2 = EnvGen.kr(Env.adsr(0.001, 0.4, 0.0, decay, amp*0.1, -4)); mix = (out1 * env1) + (out2 * env2); mix = CombN.ar(mix, 0.31, 0.31, 2, 0.5, mix); Out.ar(0, mix);}).store;
‣ openFrameworks側の実装はサンプルファイルを見ながら解説します
‣ 「07_ofxSuperCollider」
SuperColliderと連携 - ofxSuperCollider
‣ 実行結果:画面をクリック!
SuperColliderと連携 - ofxSuperCollider
‣ ofxSuperColliderを活用したデモを作成してみました‣ 参考にしてみてください
‣http://goo.gl/9rH4K‣ 1_NodeGarden‣ 2_FallCircle‣ 3_RectSequencer
ofxSuperColliderデモ
‣ 1_NodeGarden
ofxSuperColliderデモ