(\a: 1, \b: 2) ++ (\a: 10) // ( 'a': 10, 'b': 2 )
(\a: 10) ++ (\a:1, \b: 2) // ( 'a': 1, 'b': 2 )
So the ++
on Events
work by replacing the values on the left, with the values on the right, but if there are keys on the left that are not in the right, it leaves them.
So in the previous case…
spec ++ default_voice == default_voice
… because spec doesn’t contain unique new keys. Here are some more examples.
(\a: 1, \b: 2) ++ (\a: 10) // ( 'a': 10, 'b': 2 )
(\a: 10, \c: 4) ++ (\a: 1, \b: 2) // ( 'a': 1, 'b': 2, 'c': 4 )
() ++ (\a: 1) // ('a' : 1)
(\a: 1) ++ (\b: 2) // ('a' : 1, 'b': 2)
What isn’t clear at all from the documentation, is that this works perfectly well with ugens! You can even mix channels this way.
(\freq : SinOsc.kr() ) ++ (\freq: WhiteNoise.kr(1!10)) == (\freq: WhiteNoise.kr(1!10))
To take this to the extreme…
This might be getting off topic now, but it does show how far you can take this concept, and that you don’t have to execute the events in parallel.
Below, I have a default event, then a series of stages, each with a duration.
Each stage lasts for its duration, and will linearly fade into the next stage in \lerpIn
time.
If you run this code you should expect amp
to move between 10 and 40 for 30 seconds, then interpolate in 3 seconds to moving between 220 and 440.
(
{
var default = (
\duration: 20, \lerpIn: 3,
\freq: LFNoise2.kr(2).range(220, 440),
\amp: -15.dbamp
);
var stage1 = (\duration: 30, \freq: LFNoise2.kr(20).range(10, 40));
var stage2 = (\duration: 90, \amp: LFNoise2.kr(2).range(0, 1), \lerpIn: 20);
var stage3 = (\duration: 60, \amp: 0 );
var stages_array_event = [stage1, stage2, stage3].collect{|s| default ++ s};
var stages_event_array = default.collect{|v, k| stages_array_event.collect{|e| e[k] } };
var rolling_durations = stages_event_array[\duration].integrate;
var timer = Phasor.kr(0, ControlRate.ir.reciprocal, 0, inf);
var breaks = IEnvGen.kr(Env(rolling_durations.size.collect{|i| i}, rolling_durations), timer);
var stage_number = breaks.round(1);
var lerp_time = Select.kr(stage_number, stages_event_array[\lerpIn]);
var smooth_stage_number = VarLag.kr(stage_number, lerp_time);
var final_event = stages_event_array.collect{ |v, k|
LinSelectX.kr(smooth_stage_number, v)
};
var amp = final_event[\freq].poll;
/// or more helpfully...
// ugenFunction.valueWithEnvir(final_event)
}.play
)
I’ve built (and am currently building) whole multimedia works where each event is an osc map, which then fade between each other.
Below is a src (microphone amplitude) used to control the amp of a synth. It will last for 40 seconds before fading into the next osc map (whatever that my be). This is done by having the final function (ugenFunction
in the above) take a bunch of inputs, and map them to buses.
(
\duration: 40,
'/flucoma/waterGrain/amp' : src['/micIn/amp'],
...
)
One day, I’ll do a longer post about this and share a piece on this forum… right now, answering questions on here is a great way to procrastinate from the PhD…