ならば

音とかで遊んでいたログ

ローレンツアトラクタを聴く

SuperColliderに取り組み始めた。

できそうな範囲で遊んでみようということで、ローレンツアトラクタを使って音を鳴らす。
ついでにOSCでProcessingと連携して絵も描く。


SuperColliderのプログラム。
x座標が左右の定位に、y座標が音高に、z座標が音量に対応。

(
    SynthDef(\pfm, {|pan, freq, mul|
        var sig;
        sig = Pan2.ar(SinOsc.ar(freq, 0, mul), pan) * 
                EnvGen.kr(Env.perc(0.05, 0.1, 0.4, -8), doneAction: 2);
        Out.ar(0, sig);
    }).send(s);

    r = Routine({
        var sigma = 10, rho = 28, beta = 8/3, dt = 0.01;
        var pos = [20, 1, 0], px, py, pz, nx, ny, nz;
        var osc = NetAddr("127.0.0.1", 12000);
        loop {
            px = pos[0] + (sigma * (pos[1] - pos[0]) * dt);
            py = pos[1] + ((pos[0] * (rho - pos[2]) - pos[1]) * dt);
            pz = pos[2] + ((pos[0] * pos[1] - (beta * pos[2])) * dt);
            pos = [px, py, pz];
            nx = clip2(px / 25, 1);
            ny = 10.0 * py + 330;
            nz = clip2(10.0 / pz, 1);
            Synth(\pfm, [pan: nx, freq: ny, mul: nz]);
            osc.sendMsg("/pos", nx, ny, nz);
            0.05.wait;
        };
    });
)
r.play;
r.stop;


Processingのプログラム。
OSCを使った連携テストのためだけ。

import oscP5.*;
import netP5.*;

final int MAX = 500;
final int FPS = 20;
final int WSZ = 600;
final int PORT = 12000;
final color BGC = 0x333333;

OscP5 osc;
float pos[][];
int tail;
int init;

void setup() {
  tail = 1;
  init = MAX;
  pos = new float[MAX][3];
  background(BGC);
  smooth();
  frameRate(FPS);
  frame.setAlwaysOnTop(true);
  size(WSZ, WSZ);
  osc = new OscP5(this, PORT);
}

void draw() {
  translate(WSZ / 2, 50);  
  background(BGC);
  int idx, idxn, c;
  for (int i = init; i < MAX - 3; i++) {
    idx = (tail + i) % MAX;
    idxn = (idx + 1) % MAX;
    stroke(constrain(i, 50, 255), constrain(i, 50, 255), 0);
    strokeWeight(pow(pos[idx][2] * 3, 2));
    line(pos[idx][0] * WSZ / 2, WSZ - pos[idx][1], 
          pos[idxn][0] * WSZ / 2, WSZ - pos[idxn][1]);
  }
}

void oscEvent(OscMessage msg) {
  if (msg.checkAddrPattern("/pos")) {
    pos[tail][0] = msg.get(0).floatValue();
    pos[tail][1] = msg.get(1).floatValue();
    pos[tail][2] = msg.get(2).floatValue();
    if (init > 0) init--;
    tail = (tail + 1) % MAX;
  }
}


いくつもあるsyntax sugar(なのか?)が全然甘くない。むしろ辛い。saltだよ!