イージングによるグリッサンド
イージング([英]easing)とはアニメーションに加速・減速の効果を付けることで、直線的ではない滑らかで自然な動きを実現するために使われる。加速・減速にはいくつか典型的なパターンがある*1。
今回はイージングを音高に適用して、グリッサンド音を作った。
プログラムについて。音に関係ある部分のみ。音はいつものようにChucKで鳴らした。イージング処理自体はProcessingの外部ライブラリを使ってProcessing側で実行して、OSCで逐次ChucK側に必要な値(=音高)を渡すようにした。
音高は最後にChucKのStd.mtofで周波数に変換するまでMIDIノート番号で表現しているが、Std.mtofの引数はfloat型で整数に制限されないので*2、特に工夫しなくてもイージングが適用できる。
ChucKのプログラム。イージングの初期設定をProcessing側に送った後は、順次Processing側から送られてくる音高の音を鳴らす。
起動時に6個のコマンドライン引数を与える。
- イージングのパターン(string)
- Quad, Cubic, Quart, Quint, Sine, Circ, Expo, Back, Bounce, Elastic
- イージングの入り方・終り方(string)
- easeIn, easeOut, easeInOut
- 時刻(float)
- 開始時のMIDIノート番号(float)
- 変化量(float)
- 処理時間(float)
上記3〜6は、Processing側でイージング処理を行うメソッドの引数にそのまま渡すもので、ChucKの時間制御とは直接関係ない。
BeeThree b => dac; .2 => b.gain; if (me.args() != 6) { <<<"specify ", "curve:inout:time:beginning:change:duration">>>; me.exit(); } me.arg(2) => Std.atof => float stime; me.arg(3) => Std.atof => float beginning; me.arg(4) => Std.atof => float change; me.arg(5) => Std.atof => float duration; OscSend send; send.setHost("127.0.0.1", 12000); send.startMsg("/args, s, s, f, f, f, f"); send.addString(me.arg(0)); send.addString(me.arg(1)); send.addFloat(stime); send.addFloat(beginning); send.addFloat(change); send.addFloat(duration); beginning => Std.mtof => b.freq; 1 => b.noteOn; OscRecv recv; 12001 => recv.port; recv.listen(); recv.event("/note, f") @=> OscEvent oe; float note; while(oe => now) { while (oe.nextMsg() != 0) { oe.getFloat() => note => Std.mtof => b.freq; } if (note == -1) { break; } } 1 => b.noteOff; second => now;
Processingのプログラム。ChucK側からイージングの初期設定を受け取って、イージング処理を実行し、順次ChucK側に音高を送る。
import oscP5.*; import netP5.*; import penner.easing.*; import java.lang.reflect.Method; OscP5 osc; NetAddress addr; Class easingClass; Method easingMethod; int fps = 60; float time = 0; float beginning = 0; float change = 0; float duration = 0; void setup() { frameRate(fps); osc = new OscP5(this, 12000); addr = new NetAddress("127.0.0.1", 12001); easingClass = null; noLoop(); } void draw() { if (easingClass == null) return; Object ret = null; try { ret = easingMethod.invoke(null, new Object[] { new Float(time), new Float(beginning), new Float(change), new Float(duration) }); } catch (Exception e) { e.printStackTrace(); exit(); } OscMessage msg = new OscMessage("/note"); if (time <= duration) { msg.add( ((Float)ret).floatValue() ); time++; } else { msg.add(-1.0); noLoop(); } osc.send(msg, addr); } void oscEvent(OscMessage msg) { if (msg.checkAddrPattern("/args")) { try { easingClass = Class.forName("penner.easing." + msg.get(0).stringValue()); Class[] args = { Float.TYPE, Float.TYPE, Float.TYPE, Float.TYPE }; easingMethod = easingClass.getMethod(msg.get(1).stringValue(), args); } catch (Exception e) { e.printStackTrace(); exit(); } time = msg.get(2).floatValue(); beginning = msg.get(3).floatValue(); change = msg.get(4).floatValue(); duration = msg.get(5).floatValue(); loop(); } }
例外処理は手抜き。
*1:というか、Robert Pennerという人が作った一連のパターンが有名らしい
*2:Std.mtofがMIDI Tuning Standardを実装しているから