SuperColliderの音律とスケール、パターン、テンポについてです。
周波数と音程 cpsmidi, midicps
sclangでは音程にmidiノート番号が使われます。
周波数からmidiノート番号への変換は cpsmidi midiノート番号から周波数への変換は midicps で行います。midiノート番号はfloat値でも指定できます。
440.cpsmidi.postln; // 69 69.midicps.postln; // 440
12平均律の音程間の比率 pow(2, note / 12) の値を note.midiratio として計算できます。逆に比率から note の値を求めるときは ratio.ratiomidi とします。
1.midiratio.postln; // 1.0594630943591 pow(2, 1 / 12).postln; // 1.0594630943593 pow(2, 1 / 12).ratiomidi.postln; // 1 1.midiratio.ratiomidi.postln; // 0.999999999996
midiratioは精度がやや落ちるようです。
音律とスケール
Tuning と Scale で音律とスケールを管理できます。
var size = 9;
var semitones = Array.fill(size, { |index| 12 * sin(pi / 2 * index / size) });
var tuning = Tuning(semitones);
var scale = Scale(#[0, 1, 3, 5, 7], size, tuning);
tuning.semitones.postln;
scale.semitones.postln;
プリセットされた音律とスケールは以下で確認できます。
Tuning.directory; Scale.directory;
スケールに音律を渡す場合は scale.pitchesPerOctave == tuning.size が true となる必要があります。 false の場合は渡した音律が無視されます。以下の例の size の値を変えることで確認できます。
var size = 12;
var semitones = Array.fill(size, { |index| 12 * sin(pi / 2 * index / size) });
var tuning = Tuning(semitones);
var scale = Scale.minor(tuning);
(scale.pitchesPerOctave == tuning.size).postln;
tuning.semitones.postln;
scale.semitones.postln;
パターン
Pbind でパターンを組むことができます。
Pbind( \scale, Scale.chromatic, \degree, Pseq([0, 12, 27, -2], 8), \dur, 0.2 ).play;
scale はスケール、 degree はスケール内の度数、 \dur は音の長さです。
Pseq は Pseq(演奏する配列, 繰り返し回数) となっており、呼び出されるたびに配列の値を前から順に取り出します。配列を入れ子にすることでコードを演奏できます。
Pbind( \scale, Scale.chromatic, \degree, Pseq([[0, 15, 17], 12, -19, -12], 8), \dur, 0.2 ).play;
SynthDef で作ったシンセを \instrument で指定できます。シンセのパラメータも Pbind に組み込めます。
\scale には関数を指定することもできます。 \scale に指定された関数は performDegreeToKey というメソッドから呼び出されているようです。
SynthDef(\saw,
{ | out, freq, dur, pan, amp |
var env = Env([1e-6, 1, 0.5, 1e-6], [0.0, dur, 0.4], \exp);
var osc = Saw.ar(freq, EnvGen.ar(env, doneAction: 2));
Out.ar(out, Pan2.ar(osc, pan, amp))
}
).add;
~scaleSin = { | degree, stepsPerOctave, accidental |
48 * sin(pi / 8 * degree / stepsPerOctave)
};
{ | shift(0) |
var repeat = 4;
var chord = [-12, 0, 12, 24];
Pbind(
\instrument, \saw,
\scale, Scale.chromatic(Tuning.just),
\degree, Pseq([-12, chord, 0, chord, 12, chord, 0] + shift, repeat),
\dur, Pseq([1, 1, 1, 2, 1, 1, 1] * 0.1, repeat),
\amp, 0.4,
).play;
}.value(-18);
Ppar で複数のパターンを並行して演奏できます。
SynthDef(\sawfilter,
{ | out, freq, dur, pan, amp, cutoff, res |
var env = Env([1e-6, 1, 0.5, 1e-6], [0.0, dur, 0.4], \exp);
var osc = Saw.ar(freq, EnvGen.ar(env, doneAction: 2));
var filter = MoogVCF.ar(osc, cutoff, res);
Out.ar(out, Pan2.ar(filter, pan, amp))
}
).add;
{
var theme = [0, 2, 5, 7, 9];
var seq = { theme.choose };
var seqsize = 16;
var bind = { | shift(0) |
Pbind(
\instrument, \sawfilter,
\scale, Scale.minor(Tuning.mean6),
\degree, Pseq(Array.fill(seqsize, seq) + shift - 12),
\dur, 0.25,
\cutoff, Pseq(Array.fill(seqsize, { rrand(300, 4000.rand) })),
\res, 0.86,
\amp, 0.7
)
};
Ppar(Array.fill(theme.size, { |i| bind.value(theme[i]) }), inf).play;
}.value;
テンポ
TempoClock でテンポを指定できます。 TempoClock.default.tempo の値は beats/second なので beats/minute (BPM) で指定するときは一分の秒数である60で割ってやります。
TempoClock.default.tempo = 142 / 60; // 142BPM。
SynthDef(\pulseDetune,
{ | out, freq, dur, pan, amp |
var env = Env([1, 1e-6], [dur], -4);
var envGen = EnvGen.ar(env, doneAction: 2);
var osc1 = Pulse.ar(freq, 0.15);
var osc2 = Pulse.ar(freq * 1.04, 0.4);
Out.ar(out, Pan2.ar(osc1 + osc2, pan, amp * envGen))
}
).add;
Pbind(
\instrument, \pulseDetune,
\scale, Scale.suznak,
\degree, Pn(Pfuncn({24.rand - 14}), inf),
\dur, 0.25 // 16分。
).play;