ならば

音とかで遊んでいたログ

イージングによるグリッサンド

イージング([英]easing)とはアニメーションに加速・減速の効果を付けることで、直線的ではない滑らかで自然な動きを実現するために使われる。加速・減速にはいくつか典型的なパターンがある*1

今回はイージングを音高に適用して、グリッサンド音を作った。



静止画だけの一覧。
    


プログラムについて。音に関係ある部分のみ。音はいつものようにChucKで鳴らした。イージング処理自体はProcessingの外部ライブラリを使ってProcessing側で実行して、OSCで逐次ChucK側に必要な値(=音高)を渡すようにした。
音高は最後にChucKのStd.mtofで周波数に変換するまでMIDIノート番号で表現しているが、Std.mtofの引数はfloat型で整数に制限されないので*2、特に工夫しなくてもイージングが適用できる。

ChucKのプログラム。イージングの初期設定をProcessing側に送った後は、順次Processing側から送られてくる音高の音を鳴らす。
起動時に6個のコマンドライン引数を与える。

  1. イージングのパターン(string)
    • Quad, Cubic, Quart, Quint, Sine, Circ, Expo, Back, Bounce, Elastic
  2. イージングの入り方・終り方(string)
    • easeIn, easeOut, easeInOut
  3. 時刻(float)
  4. 開始時のMIDIノート番号(float)
  5. 変化量(float)
  6. 処理時間(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を実装しているから