Routineで作曲とレンダリング

サイコロを使わない作曲法を考えてますが、考えはじめると難しい
というか適当を以って旨とする本文の趣旨とはだいぶかけ離れてきますな。

(
~va = [0,0,0,0,1];		// 音列
~sc = [0,2,3,5,7,9,10];	// 音階

SynthDef("hoge", {
arg nn;
var
e = EnvGen.ar(Env.perc(0, 1), doneAction:2);
o = SinOsc.ar(nn.midicps, 0, e); 
Out.ar(0, Pan2.ar(o, 0, 0.5));
}).store;

r = Routine {
i = 0;
v = ~va.size;
loop {
	v.do({ |i|
		j = i+v-1%v;
		c = ~va[i] + ~va[j] % 7;
		~va.put(i, c);		// 音列のi番目をcに書き換え
		Synth(\hoge, [\nn, ~sc[c]+72]);
		c.post;
		(c+1/8).wait;
	});
} 
}.play;
)

r.stop;

さてこれはどうやって音を選んでいるのか?
次もやってることはほぼ同じです。ちなみにシンセはFM合成で。

(
Tempo.tempo = 4;
~va = [0,0,0,0,0,0,1];
~sc = [0,3.5,5,7,10.7,12,15.7,17,19,22.7];

SynthDef("hoge", {
arg freq, pan;
var
e = EnvGen.ar(Env.perc(0, 2), doneAction:2);
m = SinOsc.ar(freq*7/3, 0, e);
o = SinOsc.ar(freq, m, e/3);
Out.ar(0, Pan2.ar(o, pan));
}).store;

r = Routine {
v = ~va.size;
loop {
	v.do({ |i|
		j = i+v-1%v;
		c = ~va[i] + ~va[j] % 10;
		~va.put(i, c);
		~va.asString.postln;
		Synth(\hoge, [
			\freq, (~sc[c]+60).midicps,
			\pan, 2/(v-1)*i-1
		]);
		1.wait;
	});
}
}.play;
)

r.stop;

これは何かというと遅れフィボナッチという擬似乱数生成法の真似事です。
配列のいくつか前の数どうしを足してmodするという、偶然性のかけらもない計算ですが、結果はデタラメなようなそうでもないような、なかなか興味深いものです。
ずっと見てると戻ってきます。音列の初期値をいじって遊べます。
えー、Rountineで作曲と言いつつ、あまり込み入ったことはできませんでしたが、こんな感じでいろいろ遊べるっぽい。

Rountineをレンダリング

せっかくなのでこれもレンダリングの方法を考えてみます。
他の方法があるのかも知れぬが、要するにRountineでスコアを書けばいいのだろう。
前のやつを元にして書き換えます。

(
~va = [0,0,0,0,0,0,1];
~sc = [0,3.5,5,7,10.7,12,15.7,17,19,22.7];
~ar = Array.new;	// 空のスコア(配列)
~dur = 60;		// 全体の長さ(秒)
~spd = 0.2;		// 速さ

r = Routine {
v = ~va.size;
t = 0;			// 時間
while({ t < ~dur }, {		// 時間が全体の長さ未満ならば
	v.do({ |i|
		j = i+v-1%v;
		c = ~va[i] + ~va[j] % 10;
		~va.put(i, c);
		~va.asString.postln;
		~ar = ~ar.add(		// スコアに追加
			[t, [\s_new, \hoge, -1, 0, 0,  
			\freq, (~sc[c]+60).midicps,
			\pan, 2/(v-1)*i-1]]
		);
		t = t + ~spd;		// 時間を更新
	});
});
~ar.add([t, [\c_set, 0, 0]]);		// 演奏終わり
"done".postln;
}.play;
)

loopをやめて、予め全体の長さを決めてwhileすることにした。
スコアに追加するメッセージを直して、他は大して変更ありません。
Post Windowにずらずら出てきてdoneと出たら完了。

Score.play(~ar);

ちゃんと出来てるみたいですね!

o = ServerOptions.new.numOutputBusChannels = 2;
Score.recordNRT(~ar, "hoge.osc", "hoge.wav",
headerFormat: "WAV", sampleFormat: "int16",
options: o);

はいできた。
最後がぶち切れてしまいましたが、c_setの手前でtを増やしてマージンを作ってあげればオッケーでしょう。