You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
105 lines
5.4 KiB
Plaintext
105 lines
5.4 KiB
Plaintext
(
|
|
// SYNTHDEF
|
|
SynthDef(\flicker, { |automate = 1, bufs = #[0, 1, 2, 3, 4, 5, 6, 7, 8],
|
|
fadeInTrigBusNum = 0, fadeOutTrigBusNum = 2, wakeTrigBusNum = 1|
|
|
//~~~~~ Vars ~~~~~
|
|
// fadeInTimes, fadeOutTimes, wakeTimes according to example in score with 1 minute delay
|
|
// start times / fade ins
|
|
var fadeInTimes = [1, 50] * 60;
|
|
// end times / fade outs (must be same length as fadeInTimes with fadeInTimes[i] < fadeOutTimes[i])
|
|
var fadeOutTimes = [47, 106] * 60;
|
|
// These are the times to wake up with a flourish of activity and the reading of an entry in the journal
|
|
var wakeTimes = [4, 9, 17, 24, 34, 44, 53, 57, 73, 97, 101, 106] * 60;
|
|
// These are the frequency ratios of the ensemble parts
|
|
var freqRatios = [2, 3/2, 5/4, 7/4, 11/8, 13/8, 17/16, 19/16, 23/16];
|
|
// Triggers
|
|
var fadeInTrigs, wakeUpTrigs, fadeOutTrigs;
|
|
// Rich-get-richer vars
|
|
var pulse, state, runningPulseCount, norms, wealthGainLag, probs, selects;
|
|
// Control signal vars
|
|
var energy, switches, switchesSmoothed;
|
|
// Sonification vars
|
|
var lamentations, hums, ensemble, drone, fadeIn, fadeInOutEnv, wakeEnv, fadeOut;
|
|
// Timed trigger
|
|
var timedTrigger = {|times| Changed.kr(EnvGen.kr(Env.step({|i| i % 2} ! (times.size + 1),
|
|
times.differentiate ++ [0.01]), Impulse.kr(0)))};
|
|
// Monitor time
|
|
var sTrig, sCount, secs, mins;
|
|
|
|
//~~~~~ Triggers ~~~~~
|
|
// Triggers for fadeInTimes
|
|
fadeInTrigs = Select.kr(automate, [InTrig.kr(fadeInTrigBusNum), timedTrigger.value(fadeInTimes)]);
|
|
// Triggers for fadeOutTimes
|
|
fadeOutTrigs = Select.kr(automate, [InTrig.kr(fadeOutTrigBusNum), timedTrigger.value(fadeOutTimes)]);
|
|
// Triggers for wakeTimes
|
|
wakeUpTrigs = Select.kr(automate, [InTrig.kr(wakeTrigBusNum), timedTrigger.value(wakeTimes)]);
|
|
|
|
//~~~~~ Rich-get-richer Algorithm ~~~~~
|
|
// Update resolution
|
|
pulse = Impulse.kr(30);
|
|
// State of consciousness: asleep or awake; a wake up lasts 60 seconds plus a bit of a tail
|
|
state = EnvGen.kr(Env.sine(60), wakeUpTrigs);
|
|
// Binary representation of which element was selected
|
|
selects = LocalIn.kr(9);
|
|
// Running sum of the times each of the 9 elements has been selected over 120 pulses
|
|
runningPulseCount = RunningSum.kr(pulse * selects * (state > 0), (ControlRate.ir / 30) * 120);
|
|
// Normalize the counts over 121 pulses (adding a 1 in the wake states so probs is always > 1)
|
|
norms = ((0.925 * (state > 0) + 0.075 + runningPulseCount) / 129);
|
|
// Goes from 0 to 1 over several pulses after an element is chosen ending with 1 to 4 lights on favoring 2 or 3
|
|
wealthGainLag = pow((PulseCount.kr(pulse, selects) /
|
|
TWChoose.kr(wakeUpTrigs, [1, 2, 3, 4], [1, 2, 2, 1], 1)).clip, 4);
|
|
// Probabilities such that the rich get richer except directly after an element is selected
|
|
probs = {|i| pow(norms[i] * wealthGainLag[i], state * 4)} ! 9;
|
|
// Select an element
|
|
selects = TWindex.kr(pulse, probs, 1);
|
|
// Feedback binary representation
|
|
LocalOut.kr({|i| (i <= selects) * (selects <= i) } ! 9);
|
|
|
|
//~~~~~ Control signals ~~~~~
|
|
// The norms are basically the amount of energy to each element
|
|
energy = norms;
|
|
// In a toy model manner, this mimics voltage to the system
|
|
switches = {|i| TRand.kr(0, 1, pulse) < energy[i]} ! 9;
|
|
// Smooths the signal such that the lag time is greater as the element gets richer
|
|
switchesSmoothed = {|i| Lag2.kr(switches[i], 0.25 + (0.75 * energy[i]))} ! 9;
|
|
|
|
//~~~~~ Sonification ~~~~~
|
|
// Playback of the Lassus Lamentations with a LPF as to not overwhelm to overall sound
|
|
// Each of the Lamentations as a 2 in 3 chance of sounding
|
|
lamentations = {|i| LPF.ar(PlayBuf.ar(2, bufs[i], 1, wakeUpTrigs,
|
|
TIRand.kr(0, BufFrames.ir(bufs[i]), wakeUpTrigs), 1), 2880) *
|
|
switchesSmoothed[i] * TWChoose.kr(wakeUpTrigs, [0, 1], [1, 2], 1)} ! 9;
|
|
// Toy model of an electric hum
|
|
hums = {|i| var buf = Array.fill(256, {1.0.rand2}).as(LocalBuf.clear);
|
|
LPF.ar(Osc.ar(buf, 60, 0), 960) * switchesSmoothed[i]} ! 9;
|
|
// Sustained tones based on energy to that element
|
|
ensemble = {|i| SinOsc.ar(240 * freqRatios[i], 0) * energy[i]} ! 9;
|
|
// Drone in sleep state that gets attenuated in wake state
|
|
drone = {|i| var harm = pow(2, 2 - (i / 3).trunc), amp = (1 - (0.75 * energy.sum)) * (1 / pow(harm, 2));
|
|
SinOsc.ar(60 * harm + TRand.kr(-3, 3, switches[i]), 0, amp)} ! 9;
|
|
|
|
//~~~~~ Mix ~~~~~
|
|
// Fade ins (10 secs) / outs (30 secs)
|
|
fadeInOutEnv = EnvGen.kr(Env.asr(10, 1, 30, \sine),
|
|
Latch.kr(Select.kr(fadeOutTrigs, [1, 0]), fadeInTrigs + fadeOutTrigs));
|
|
// Fade wake sounds in and out based on total energy in the system
|
|
wakeEnv = pow(0.8 * energy.sum + 0.2, 4);
|
|
// Final mix currently set to output stereo where the multiplier is the final output level
|
|
// Send to separate channel for more control of the indivuals sounds (e.g. with a mixer)
|
|
// The lamentations of a 50 / 50 chance of sounding at all
|
|
Out.ar([0,1], Mix.new(lamentations) * fadeInOutEnv * wakeEnv * 0.75 * TIRand.kr(0, 1, wakeUpTrigs));
|
|
Out.ar([0,1], Mix.new(hums) * fadeInOutEnv * wakeEnv * 0.075);
|
|
Out.ar([0,1], Mix.new(ensemble) * fadeInOutEnv * wakeEnv * 0.125);
|
|
Out.ar([0,1], Mix.new(drone) * fadeInOutEnv * 0.25);
|
|
|
|
//~~~~~ Visualization Control ~~~~~
|
|
// Send signals to visualizer (these could be sent and scaled appropriated to control real lights)
|
|
{|i| SendTrig.kr(pulse, i, switchesSmoothed[i] * fadeInOutEnv)} ! 9;
|
|
{|i| SendTrig.kr(pulse, i + 9, energy[i] * fadeInOutEnv * wakeEnv)} ! 9;
|
|
|
|
//~~~~~ Monitor Time ~~~~~
|
|
sTrig = PulseDivider.kr(pulse, 30); sCount = PulseCount.kr(sTrig);
|
|
secs = sCount % 60; mins = (sCount / 60).trunc;
|
|
Poll.kr(sTrig, mins + (secs / 100), "time (min.secs)");
|
|
}).send(s);
|
|
) |