Algorave Helsinki meetup, 2025-05-06
livecoding on Macintosh IIci
following my work on building a performance system on SuperCollider 2 and my Mac OS 9 EP, i presented my latest project in retrocomputer music making: creating a music livecoding system for Macintosh IIci.
i wrote about this in a separate post.
Robot Uprising and ideas for sound robotics
Karim (Make Gyver) briefly presented Robot Uprising, a series of deep, story driven hackathons, and we discussed some preliminary ideas on how to incorporate sound and music related challenges.
Karim's notes:
Algorave meetup
Robot Uprising inspo
Tech for robots
- normal microfone
- mic array for directional sound stuff
- contact mics (on an arm so you can point them somewhere)
- echolocation -> sonar
- light sensors for light2sound stuff
- Use OSC (builds on UDP) --> provide code to go from OSC to our UDP packages → try writing s/t to steer the Robots with OSC
Ideas
- having speaker all over the space with different frequencies, play around with it
- maybe use it for navigation → fixed robot, you have to make them move by playing certain frequencies from certain boxes
- find spots that have cool interference from the different frequency speakers
- speakers make "noise" find spots that even out to clear signal like sine (-microfone sends sound to computer, move till its mostly clear)
- detect certain colours or shapes that are mapped to sound, navigate the robot to make music or recreate a given melody -> reinforcement learning
- or shoot light to sensor that triggers sound
- entry level puzzle Sample triggering to make music -> Webcam if you go somewhere it plays a sample. Try to make music by moving to the right spot
- Stuff in a dark room with only sound. Robots are only allowed to blink every so often
- sound scaping
Learning
- Interesting stuff to learnil from puzzles:
- fourier transform
- onset/transient detection
exponential rhythms
the topic of programming exponential rhythms came up.
in TidalCycles
i showed my old implementation of exponential rhythms in TidalCycles, but it was a bit broken. here is an improved version:
-- a version of `plyWith` taking an additional function `s` as argument. this
-- function maps the index of each repetition sub-event to the relative duration
-- of that event, allowing non-uniform rhythms to be created.
_plyShapeWith :: (Floating a, RealFrac a)
=> Int -> (a -> a) -> (Pattern b -> Pattern b) -> Pattern b
-> Pattern b
_plyShapeWith n s f p = repeated
where
-- make an `n`-length list of relative event durations by applying the
-- function `s` to 0, 1, ..., n-1.
-- time is Rational, so lets spare the user the hassle of converting.
times = map ((`approxRational` 1e-6) . s . fromIntegral) [0..n-1]
-- given a single event `v`, build a list of sub-events by applying the
-- function `f` repeatedly. this list is infinite, but it will be truncated
-- to the length of `times` once we zip them together.
reps v = iterate f $ pure v
-- turn a single event `v` into a list of (duration, sub-event) pairs.
timesAndReps v = zip times $ reps v
-- for every event in the pattern `p`, generate the list of durations and
-- sub-events, and pass it to `timeCat` to concatenate the sub-events using
-- their corresponding durations.
-- finally, `squeezeJoin` the resulting pattern, so that each result of
-- `timeCat` gets fit into the duration of the original event from `p`.
repeated = squeezeJoin $ (timeCat . timesAndReps) <$> p
-- same as the above, but accepts a pattern for the first argument (number of
-- repetitions).
plyShapeWith :: (Floating a, RealFrac a
=> Pattern Int -> (a -> a) -> (Pattern b -> Pattern b) -> Pattern b
-> Pattern b
plyShapeWith np s f p = (\n -> _plyShapeWith n s f p) =<< np
-- special case for easy exponential rhythms. the second argument `bp` (base
-- pattern) now determines the base of the exponential function to generate the
-- duration for each repetition sub-event. pass >1 for rhythms that slow down,
-- <1 for rhythms that speed up.
plyExpWith :: (RealFrac a, Floating a)
=> Pattern Int -> Pattern a -> (Pattern b -> Pattern b) -> Pattern b
-> Pattern b
plyExpWith np bp f p = innerJoin $ (\b -> plyShapeWith np (b**) f p) <$> bp
-- example:
-- steady kick as backdrop
d1 $ s "techno:1*4"
-- hihats alternately slowing down and speeding up
d2 $ plyExpWith 16 "<1.1 0.9>" id
$ s "808:1"
# legato 1
-- claps with occasional bounce
d3 $ sometimesBy 0.33 (plyExpWith 8 0.8 (|* lpf 0.75))
$ s ((1/2) ~> "[cp]*2")
# lpf 12000
# legato 1
in SuperCollider
Joonas (Forces) showed how to use Pseg
for exponential rhythm, together with VSTPlugin
(1 bar loop of exponentially growing drum triggering):
VSTPlugin.search;
(
SynthDef(\vsti, { arg out = 0;
// VST instruments usually don't have inputs
Out.ar(out, VSTPlugin.ar(nil, 2));
}).add;
)
//vst here
~vsti = VSTPluginController(Synth(\vsti)).open("FM8", editor:true);
~vsti.editor;
(
~p = Pbindef(\pro,
\type, \vst_midi,
\vst, ~vsti, // the VSTPluginController instance
\degree, 50,
\dur, Pseg(Pseq([1/4,1/32],inf),Pseq([1,0],inf),\exp,inf),
\legato, 1.0,
\amp, 1
);
~pPlay=~p.play;
)
~pPlay.stop;
i came up with a more "manual" approach, using plain math to calculate an array of durations for Pseq
:
(
// define some example synths
SynthDef(\kick, { |out=0, amp=0.2|
var sig;
sig = SinOsc.ar(EnvGen.ar(Env([800,40], [0.01], [\exp])));
sig = sig * EnvGen.ar(Env.perc(0.001, 0.3)) * amp;
Out.ar(out, sig ! 2);
}).add;
SynthDef(\hat, { |out=0, amp=0.2|
var sig;
sig = WhiteNoise.ar;
sig = RHPF.ar(sig, 8000);
sig = sig * EnvGen.ar(Env.perc(0.001, 0.1)) * amp;
Out.ar(out, sig ! 2);
}).add;
// set a nice tempo
TempoClock.default.tempo = 130 / (4*60);
)
(
// steady kick
Pdef(\beat, Pbind(
\instrument, \kick,
\dur, 1/4
)).play(quant: 1);
)
(
// exponential hats
var num, base, durs;
num = 16; // number of steps
base = 1.1; // base of exponential
durs = num.collect { |i| base.pow(i) }; // relative durations
durs = durs / durs.sum; // divide by total duration to fit in 1 bar
// durs = durs / 2; // fit in half bar
Pdef(\hats, Pbind(
\instrument, \hat,
\dur, Pseq(durs, inf)
)).play(quant: 1);
)
taui's Max 4 Live patches
Aleksi (taui) showed some of his Max 4 Live patches with unconventional and creative interfaces: