はじめに
Qiitaで書く内容じゃないかもしれませんが、otophilia氏が作成したSuperColliderのコードをまだ聴けるのか試してみたく、久しぶりにSuperColliderを触ってみました。
※氏について知らない方は多分楽しめない記事です。
※SuperCollider関連の記事はリンク切れで怪しいサイトに変わっているものもあるので気をつけてください。
ネット上に残っている情報を探してみる
otophiliaのサイトを見る
下記は現存するotophilia氏のWebサイトで、SuperCollider製のいくつかのコードが残っています。
ただ、公開されているものはコード作成支援ツールのように思われます。
本人のブログを見る
氏が亡くなられた後、彼の父親が引き継いで運営しているブログがあります。
同様に彼について調べてらっしゃる方がおり、利用した検索パラメータを残してくれているため後を追ってブログを調べてみました。
ブログ記事内のコードを片っ端から鳴らしてみよう
①「October 17, 2007 一日一段落しか進まない」内のコード
そのままだとなぜか動かなかったです。
ちょっと修正して下記のようにしたら動きました。
SynthDef(\test, {
arg outBus=0, amp=0.1, dur=2, note = 60, ntx = 12;
var in, out, n, oscs;
n = 8;
in = LocalIn.ar(n);
in = DelayC.ar(in, 0.3, ExpRand(0.1, 0.3) - ControlRate.ir.reciprocal);
oscs = Array.fill(n,{ |i|
SinOsc.ar( (i*ntx + note ).midicps, in[i+1%n] * LFNoise0.kr(i*ExpRand(0.5, 4), 2) )
});
out = [oscs[0] + oscs[2], oscs[1] + oscs[3] ];
out = Splay.ar(out, Rand(0, 1).squared, EnvGen.kr( Env.perc(0,dur,-4), 1, amp, 0, 1, 2), Rand(-1, 1));
Out.ar(outBus, out);
LocalOut.ar(oscs);
}).add;
s.waitForBoot({
Task({
0.5.wait;
inf.do{|i|
var dur, note, ntx;
dur = exprand(0.1, 8);
note = rrand(0, 5) * 12 + [0, 3, 7, 10, 14].choose + 30;
ntx = [12, 19, 24].choose;
Synth(\test, [\outBus, 0, \dur, dur, \amp, 0.2, \note, note, \ntx, ntx]);
(dur/4).wait;
};
}).play;
Task({
0.5.wait;
inf.do{|i|
var dur, note, ntx;
dur = exprand(0.1, 8);
rrand(4, 12).do{|i|
var dur, note, ntx;
dur = exprand(0.01, 0.2);
note = rrand(2, 8) * 12 + [0, 3, 7, 10, 14].choose + 30;
ntx = [22, 24, 26].choose;
Synth(\test, [\outBus, 0, \dur, dur, \amp, 0.1, \note, note, \ntx, ntx]);
(dur/4).wait;
};
(dur/4).wait;
};
}).play;
});
音の重ね方にどことなくimoutoidらしさを感じます。
②「October 29, 2007 今日のグリッチノイズ」内のコード
音声ファイルが必要なようなので、適当にドラムループを持ってきて利用しました。
こちらはパス以外編集なしで動きました。
(
s = Server.default;
s.latency = 0.3;
Routine.run {var c;
c = Condition.new;
s.bootSync(c);
(
~buf = Buffer.read(s, "/Users/ユーザ名/Music/scd/amen-break.mp3");
SynthDef('test',{
arg outBus=0, bNum=0, dur=1, stP=0,
grFreq=100, gtFreq=10, panFreq=10, speed=1, gtTh=0.5,
lAmp=1, rAmp=1;
var out, pulse, gate, sch, pan;
sch = Sweep.ar(1, SampleRate.ir * speed);
pulse = Impulse.ar(grFreq);
out = PlayBuf.ar(2, bNum, 1, pulse, stP + sch, 1);
out = Limiter.ar(out*2, 1, 0.01);
gate = LFNoise0.ar(gtFreq, 0.5, 0.5) > gtTh;
pan = LFNoise0.ar(panFreq);
out = Pan2.ar(out, pan, gate);
out[0] = out[0] * lAmp;
out[1] = out[1] * rAmp;
Line.kr(0, 1, dur, doneAction:2);
OffsetOut.ar(outBus, out);
}).send(s);
); s.sync(c);
s.record;
(
~msg = List.new;
~bpm = 120;
~chWait = 1/4;
~task2 !? {~task2.stop};
~task2 = Task({inf.do{|i|
~chWait = exprand(0.004, 1.0);
~synth = Synth.basicNew('test');
~msg.add( ~synth.newMsg(nil, ['outBus', 0, 'bNum', ~buf.bufnum,
'dur', 60/~bpm * ~chWait,
'stP', rand(1.0) * ~buf.numFrames,
'grFreq', exprand(12.0, 300.0),
'gtFreq', exprand(100.0, 400.0),
'panFreq', exprand(4, 30),
'speed', [{rand(1.0)**4* 0.2}, {rand(1.0)**3* -0.2}].choose.value,
'gtTh', rrand(0.2, 0.4),
'lAmp', [1, -1].choose, 'rAmp', [1, -1].choose
]) );
~synth2 = Synth.basicNew('test');
~msg.add( ~synth2.newMsg(nil, ['outBus', 0, 'bNum', ~buf.bufnum,
'dur', 60/~bpm * ~chWait,
'stP', rand(1.0) * ~buf.numFrames,
'grFreq', exprand(2000.0, 20000.0),
'gtFreq', exprand(30.0, 100.0),
'panFreq', exprand(4, 40),
'speed', [{rand(1.0)**3* 1}, {rand(1.0)**3* -1}].choose.value,
'gtTh', rrand(0.6, 0.9),
'lAmp', [1, -1].choose, 'rAmp', [1, -1].choose
]) );
~msg !? {s.listSendBundle(s.latency, ~msg)};
~msg = List.new;
~chWait.wait;
}}, TempoClock(~bpm/60)).start;
);
};
);
ピーガガガみたいなノイズが聞けます。
こういう音をDAW内で作るの面倒なので、これは未だに有益なんじゃないでしょうか?
③「February 02, 2008 「はい」か「いいえ」で答えてください」内のコード
これは編集なしでも動きました。すごい。
(
Routine.run{var c; c=Condition.new; s.bootSync(c);
s.freeAll;
TempoClock.all.do{|x|x.clear};
SynthDef("test", {
arg outBus=0, pitch=40, freq, amp=1.0, fmFreq;
var out;
pitch = Lag2.kr(pitch, 4.0);
pitch = pitch + LFClipNoise.kr(Rand(3.0,5.0), 6, 6) + LFClipNoise.kr(Rand(3.0,5.0), 9.5, 9.5);
freq = pitch.midicps;
amp = amp*AmpComp.kr(freq, 60.midicps, 0.25);
fmFreq = freq*(LFNoise0.kr(Rand(3.0,5.0), 4, 5).floor) * LFNoise2.ar(8000, 0.02, 1);
out = SinOsc.ar(freq, SinOsc.ar(fmFreq,0,LFNoise2.kr(0.4, 0.8)) + SinOsc.ar(freq));
out = HPF.ar(Ringz.ar(WhiteNoise.ar, fmFreq, 0.04, 0.1), 2000, 0.1, out);
amp = LFNoise2.kr(2, 0.5, 0.5)*amp;
out = amp*out;
out = Pan2.ar(out, LFNoise2.kr(Rand(1.0,2.0)));
Out.ar(outBus, out);
}).send(s);
SynthDef("fx1", {
arg inBus=0, outBus=0;
var out;
out = In.ar(0, 2);
out = AllpassN.ar(out.reverse, 0.6, 0.6, 1) + out;
out = HPF.ar(AllpassN.ar(out.reverse, 1.0, LFNoise2.kr(0.6).linexp(-1,1, 0.1, 1.0), 2), 3000, 0.7, out);
out = AllpassN.ar(out, 0.4, 0.4, 1);
out = FreeVerb2.ar(out[0], out[1], 0.4, 0.9, 0.96);
out = Limiter.ar(out, 1.0, 0.1);
ReplaceOut.ar(outBus, out);
}).send(s);
s.sync(c);
~clock = TempoClock(0.5, 0, Main.elapsedTime.floor+0.4);
~msg = List.new;
~seq = [
[0, 12, 19, 26, 33]+24,
[0, 12, 19, 26, 33]+24,
[0, 9, 16, 23, 28]+8+24,
[0, 9, 16, 21, 28]+8+24,
];
~clock.schedAbs(0, {|beat|
var bar;
bar = beat.div(4);
if(beat==0){
~synGroup = Group.new;
~synths = ~seq[0].collect{Synth.basicNew("test")};
~synths.do{|x, i|
~msg.add(
x.newMsg(~synGroup, ['outBus', 0, 'pitch', ~seq.wrapAt(bar)[i], 'amp', 0.3])
)
};
~fx1 = Synth.basicNew("fx1");
~msg.add(~fx1.addAfterMsg(~synGroup, ['inBus', 0, 'outBus', 0]));
}{
~synths.do{|x, i|
~msg.add(
x.setMsg('outBus', 0, 'pitch', ~seq.wrapAt(bar)[i])
)
};
};
s.listSendBundle(0.2, ~msg);
~msg = List.new;
1.0;
});
}
);
pad音源を重ねてピッチベンドをかけているような雰囲気でとても美しいです。
昨年のコードと比較して曲らしさ(展開)が生まれている気がしました。
④「February 04, 2008 サイコ・アコースティクス・イリュージョン(相手は死ぬ)」内のコード
実験的な耳の錯覚を利用したコードです。
ブログ記事に書いているように片耳ずつ聞いてから両耳で聞くと感動します。
(
Routine.run{var c; c=Condition.new; s.bootSync(c);
SynthDef("sineTest", {
arg outBus=0, freq=1000, amp=1.0, ph0=0, ph1=0;
var out;
amp = EnvGen.kr(Env.perc(0.01, 0.6, 1, -7), 1, amp, doneAction:2);
out = [LFTri.ar(freq, ph0, amp), LFTri.ar(freq, ph1, amp)];
Out.ar(outBus, out);
}).send(s);
~array = [42, 49, 54, 56, 57, 59, 61, 64, 66, 68, 69, 71, 73];
~array2 = [11, 12, 10, 9, 11, 10, 8, 9, 10];
~array3 = [0, 1, 2, 3, 4];
~array4 = [5, 6, 5, 5, 6, 6];
~array5 = [0, 3, -2, 1, 0, 3, 7, 12];
~no = 0;
SystemClock.sched(0.0, {
var trs;
trs = ~array5.wrapAt(~no.div(64));
s.makeBundle(0.2, {
~array.do{|x, i|
var ph, tone;
ph = 4.0.rand;
tone = [~array2.wrapAt(~no), ~array3.wrapAt(~no), ~array4.wrapAt(~no)];
Synth("sineTest", [
'freq', (x+trs).midicps,
'amp', ~array.size.reciprocal,
'ph0', ph,
'ph1', switch(i)
{tone[0]}{ph+2%4}
{tone[1]}{ph+2%4}
{tone[2]}{ph+2%4} ? ph;
]);
};
});
~no = ~no+1;
0.12;
});
}
);
ブログ内にあったコードはこのぐらいですね。
公式example
公式example内にacid_otophilia.scd
という彼の作成したコードがあります。
exampleに載るだけあってかなり出来が良いです。
その他
幸運にも記事内にコードを追記してくださったおかげでジムノペディは実行できました。
※こちらの記事内で「いつ消えるかわからない」と指摘のあったリンクは消えてますね...さもありなん
また、記事内のリンクから動画をアップロードしたユーザを辿るといくつかの現存していないotophilia氏のコードの実行結果を映した動画が見つかります。
こちらの動画からコードを発掘するのも良いかもしれません
supercollider.jpに元々あったコードは今は見れないようですね。
サルベージされるのを待ちます。
今回紹介したページ群再掲