LinkedVoicerSequencer : VoicerSequencer
In VoicerSequencer, the frequency, duration, length and other patterns run independently, making it impossible to choose between patterns of different lengths. LinkedVoicerSequencer plays a pattern that returns NoteSequences. Each [NoteSequence] acts as a mini-VoicerSequencer, with the advantage that several of them can be used in a pattern stream and each one will be kept intact.
*new(voicer, pattern)
voicer: The voicer that will play the sequence.
pattern: The pattern of NoteSequences. The pattern must return NoteSequences; if it does not, you will get an error.
play(quant = 1, offset = 0)
Play the sequence beginning at the desired quantize and offset values.
reset(quant = 1, offset = 0)
Reset the sequence to its beginning.
stop(quant = 1, offset = 0)
Stop playing.
Example:
This is a big example borrowed from an electro/jazz track of mine built in SuperCollider. I'm giving you this element of the piece in its entirety because it really demonstrates the power of this kind of sequencing. It uses a finite state machine to generate an improv solo--not as good as a real performer, but surprisingly coherent.
m = MixerChannel.new("lead", s, 1, 2, level:0.4); // allow time for server to boot if needed
// execute all of the following
(
var sens;
sens = { arg scaler, value, sense; // for building the instrument
(scaler == 0).if({
1
}, {
(scaler == 1).if({
(value-1) * sense + 1
}, {
scaler * ((value - 1) * sense + 1)
})
});
};
t = TempoClock(128/60);
// the instrument
Instr([\analog, \sawpulse], { arg freq, gate, freqlag, env, fenv, ffreq, rq, width, vsens, fenvsens, detune, pb, plfofreq, mw, plfoClass;
var sig, plfo, amp, fcurve;
amp = Latch.kr(sens.value(1, gate, vsens), gate);
plfo = plfoClass.kr(plfofreq, mul:mw, add:1);
freq = Lag.kr(freq, freqlag) * pb * plfo; // pb = pitch bend factor
fcurve = sens.value(ffreq, EnvGen.kr(fenv, gate), fenvsens);
sig = Mix.ar([Pulse.ar(freq, width), Saw.ar(freq*detune)]);
sig = RLPF.ar(sig, fcurve, rq) * EnvGen.kr(env, gate, doneAction:2) * amp;
}, #[\freq, \amp, [0.000001, 20, \exponential], nil, nil, \freq, [1, 0.001], [0.0001, 0.9999], nil, nil, [0.95, 1.05263, \exponential, 0, 1], [0.5, 2, \exponential, 0, 1], [0, 10], [0, 0.1], nil]);
~lead = MonoPortaVoicer(1, Instr.at([\analog, \sawpulse]), [\env, Env.adsr(0.04, 0.2, 0.6, 0.1), \fenv, Env.adsr(0, 0.3, 0.1, 20), \width, `0.9, \vsens, `0.8, \fenvsens, `0.7, \detune, `1.007, \pb, 1, \plfofreq, `6, \mw, KrNumberEditor(0, #[0, 0.1]).lag_(0.25), \rq, `0.3, \plfoClass, SinOsc], target: m).clock_(t).latency_(1).portaTime_(0.05);
p = ~lead.addProcess([
["Stop", { arg p, g; g.stopAll },
LinkedVoicerSequencer(~lead, Pfsm([
#[0, 3, 1], // starting places
NoteSequence(Pseq([78, 81, 78, 76, 78, 76, 72, 71, 69, 66].midicps, 1),
Pseq(#[0.25, 1.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25], 1),
Pseq(#[0.3, 1.2, 0.3, 0.2, 0.3, 0.2, 0.3, 0.2, 0.3, 0.2],1 ),
true, nil, [\gate, Pseq(#[1, 0.5, 0.75, 0.5, 0.75, 0.5, 0.75, 0.5, 0.75, 0.5], 1),
\mw, Pseq([0, 0.03, Pseq(#[0], inf)], 1)]
), #[1, 2, 3, 4, 7],
NoteSequence(Pseq([64, 66, 69, 71, 72, 73].midicps, 1),
Pseq(#[0.25], 6),
Pseq(#[0.3, 0.2, 0.2, 0.2, 0.3, 0.2], 1),
true, nil, [\gate, Pseq(#[1, 0.5, 0.5, 0.5, 0.5, 0.5], 1),
\mw, 0]
), #[1, 2, 3, 4, 5].weight(#[4, 2, 2, 2, 1]),
NoteSequence(Pseq([69, 71, 69, 66, 64, 69, 71, 69].midicps, 1),
Pseq(#[0.125, 0.625, 0.25, 0.25, 0.25, 0.25, 0.25, 0.75], 1),
Pseq(#[0.2, 0.64, 0.2, 0.2, 0.2, 0.3, 0.3, 0.75], 1),
true, nil, [\gate, Pseq(#[0.5, 0.75, 0.5, 0.5, 0.5, 1, 0.5, 0.5], 1),
\mw, 0]
), #[0, 1, 3, 5].weight(#[1, 4, 4, 1]),
NoteSequence(Pseq([72, 73, 76, 72, 71, 69, 66, 71, 69].midicps, 1),
Pseq(#[0.25, 0.25, 0.25, 0.083, 0.083, 0.084, 0.25, 0.25, 0.25], 1),
Pseq(#[0.3, 0.2, 0.2, 0.1, 0.07, 0.07, 0.2, 0.3, 0.2], 1),
true, nil, [\gate, Pseq(#[1, 0.5, 0.5, 1, 0.3, 0.3, 0.75, 0.75, 0.5], 1),
\mw, 0]
), #[1, 3, 4].weight(#[4, 2, 3]),
NoteSequence(Pseq([64, 66, 69, 71, 72, 73, 71, 69, 66, 71, 69, 66, 64, 69].midicps, 1),
Pseq(#[0.25, 0.25, 0.25, 0.25, 0.125, 0.375, 0.166, 0.166, 0.168,
0.5, 0.166, 0.166, 0.168, 0.5], 1),
Pseq(#[0.3, 0.2, 0.2, 0.2, 0.14, 0.4, 0.2, 0.2, 0.2, 0.6, 0.2, 0.2, 0.2, 0.5],1),
true,
[\gate, Pseq(#[0.5, 0.5, 0.6, 0.8, 1, 0.5, 0.5, 0.5, 0.5, 1,
0.5, 0.5, 0.5, 0.45], 1),
\mw, 0]
), #[0, 1, 3, 5].weight(#[1, 4, 2, 1]),
NoteSequence(Pseq([72, 73, 76, 78, 81, 78, 83, 81, 84, 85].midicps, 1),
Pseq(#[0.25, 0.25, 0.25, 0.25, 0.5, 0.5, 0.5, 0.5, 0.125, 1.125], 1),
Pseq(#[0.3, 0.2, 0.2, 0.2, 0.95, 0.25, 0.95, 0.25, 0.2, 1.13], 1),
true, nil, [\gate, Pseq(#[0.7, 0.5, 0.5, 0.5, 0.7, 0.5, 0.8, 0.5, 1, 0.5], 1),
\mw, Pseq([Pseq(#[0], 9), 0.03], 1)]
), #[6, 8, 9, 10, 11, 13].weight(#[3, 1, 1, 4, 2, 2]),
NoteSequence(Pseq([83, 81, 78, 83, 81, 78, 76, 72, 73, 78, 72, 72, 71].midicps, 1),
Pseq(#[0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25,
0.25, 2], 1),
Pseq(#[0.3, 0.3, 0.2, 0.3, 0.3, 0.3, 0.2, 0.3, 0.2, 0.3, 0.2, 0.3, 2], 1),
true, nil, [\gate, Pseq(#[0.5, 0.5, 0.5, 0.8, 0.5, 0.5, 0.5, 0.8, 0.5, 0.8, 0.5,
1, 0.4], 1),
\mw, Pseq([Pseq([0], 12), 0.03], 1)]
), #[0, 7, 3].weight(#[1, 5, 4]),
NoteSequence(Pseq([69, 71, 72, 71, 69, 66, 64, 69, 71].midicps, 1),
Pseq(#[0.25, 0.25, 0.25, 0.25, 0.166, 0.167, 0.167, 0.25, 0.25], 1),
Pseq(#[0.2, 0.2, 0.3, 0.2, 0.2, 0.2, 0.14, 0.3, 0.2], 1),
true, nil, [\gate, Pseq(#[0.5, 0.5, 0.8, 0.5, 0.5, 0.5, 0.5, 0.8, 0.5], 1)]
), #[3, 4, 5].weight(#[3, 2, 1]),
NoteSequence(Pseq([84, 85, 84, 84, 88, 84, 83, 81, 83, 81, 78, 76, 81, 83].midicps, 1),
Pseq(#[0.125, 0.535, 0.67, 1.92, 0.25, 0.166, 0.167, 0.167,
0.25, 0.25, 0.25, 0.25, 0.25, 0.25], 1),
Pseq(#[0.2, 3.12, 0.2, 0.2, 0.2, 0.2, 0.2, 0.15, 0.3, 0.2, 0.2, 0.2,
0.3, 0.2], 1),
true, nil, [\gate, Pseq(#[1, 0.8, 0.8, 0.8, 1, 1, 0.8, 0.8, 1, 0.8, 0.8, 0.8,
1, 0.8], 1),
\mw, Pseq([0, 0.005, 0.005, 0.06, Pseq(#[0], 10)], 1)]
), #[10, 11, 12].weight(#[3, 4, 3]),
// same as #4, 8va
NoteSequence(Pseq(([64, 66, 69, 71, 72, 73, 71, 69, 66, 71, 69, 66, 64, 69]+12).midicps, 1),
Pseq(#[0.25, 0.25, 0.25, 0.25, 0.125, 0.375, 0.166, 0.166, 0.168,
0.5, 0.166, 0.166, 0.168, 0.5], 1),
Pseq(#[0.3, 0.2, 0.2, 0.2, 0.14, 0.4, 0.2, 0.2, 0.2, 0.6, 0.2, 0.2, 0.2, 0.5],1),
true, nil, [\gate, Pseq(#[0.5, 0.5, 0.6, 0.8, 1, 0.5, 0.5, 0.5, 0.5, 1,
0.5, 0.5, 0.5, 0.45], 1),
\mw, 0]
), #[11, 12].weight(#[5, 2]),
NoteSequence(Pseq([81, 84, 83, 81, 78, 76, 81, 83].midicps, 1),
Pseq(#[0.25], 8),
Pseq(#[0.2, 0.3, 0.3, 0.2, 0.3, 0.2, 0.3, 0.2], 1),
true, nil, [\gate, Pseq(#[0.5, 1, 0.5, 0.5, 0.6, 0.5, 0.8, 0.5], 1),
\mw, 0]
), #[0, 9, 11, 12].weight(#[1, 2, 2, 5]),
// same as #1, 8va
NoteSequence(Pseq(([64, 66, 69, 71, 72, 73]+12).midicps, 1),
Pseq(#[0.25], 6),
Pseq(#[0.3, 0.2, 0.2, 0.2, 0.3, 0.2], 1),
true, nil, [\gate, Pseq(#[1, 0.5, 0.5, 0.5, 0.5, 0.5], 1),
\mw, 0]
), #[6, 8, 9, 10, 13].weight(#[2, 1, 4, 4, 3]),
NoteSequence(Pseq([78, 81, 83, 78, 83, 84, 78, 84, 85].midicps, 1),
Pseq(#[0.25, 0.25, 0.5, 0.25, 0.25, 0.5, 0.25, 0.25, 1.75], 1),
Pseq(#[0.2, 0.3, 0.2, 0.2, 0.3, 0.2, 0.2, 0.3, 1.75], 1),
true, nil, [\gate, Pseq(#[0.4, 0.8, 0.5, 0.4, 0.8, 0.5, 0.4, 1, 0.8], 1),
\mw, Pseq([Pseq([0], 8), 0.03], 1)]
), #[8, 13].weight(#[1, 2]),
NoteSequence(Pseq([88, 84, 83, 81, 83, 81, 78, 76, 81, 83].midicps, 1),
Pseq(#[0.25, 0.166, 0.167, 0.167,
0.25, 0.25, 0.25, 0.25, 0.25, 0.25], 1),
Pseq(#[0.2, 0.2, 0.2, 0.15, 0.3, 0.2, 0.2, 0.2,
0.3, 0.2], 1),
true, nil, [\gate, Pseq(#[1, 1, 0.8, 0.8, 1, 0.8, 0.8, 0.8,
1, 0.8], 1),
\mw, 0]
), #[10].weight(#[5, 2])
], inf))
],
["Improv 1", { arg p, g; g.stopOthers(p); p.reset.play }]
]);
// control the filter cutoff with the modwheel (or gui slider)
~leadsock = VoicerMIDISocket(0, ~lead);
~leadsock.addControl(\mw, \ffreq, 2000, [800, 20000, \exponential], \omni);
~lead.gui;
)
// Now, to play the sequence, choose it from the menu.
// When you choose a menu item, it will wait for the next barline to take action.
~lead.free; m.free; // when done