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;