I've just tried to use the supercollider generated code snippet:
-- | parameters for the SynthDefs: dirt_grain_envelope2
let (contour, contour_p) = pF "contour" (Nothing)
(curve, curve_p) = pF "curve" (Nothing)
(plat, plat_p) = pF "plat" (Nothing)
But that failed. Any idea what is wrong?
• Couldn't match expected type ‘Pattern Double’
with actual type ‘Maybe a0’
• In the second argument of ‘pF’, namely ‘(Nothing)’
In the expression: pF "plat" (Nothing)
In a pattern binding: (plat, plat_p) = pF "plat" (Nothing)
And what did you expect? (Genuine question, I can't infer from your code).
What is a "supercollider generated code snippet"?
The type is
pF :: String -> Pattern Double -> ControlPattern
so the second argument must be a pattern (Nothing
is not a pattern) and the result will be a pattern (but your code was expecting a pair)
Honestly, I never understood how the pF
function worked. But it seems that its signature has changed at some stage?
Looking inot https://github.com/tidalcycles/Tidal/blob/master/src/Sound/Tidal/Params.hs I see that now one writes simply bandq = pF "bandq"
etc.
Then perhaps we can improve documentation.
Something like: pF s p
takes s :: String
and p :: Pattern Float
and computes a control pattern that has the same structure as p
, where each value v :: Float
in p
results in a ControlMap
with single key s
and value v
.
pF "foo" "[0.1,2.3]"
(0>1)|foo: 0.1f
(0>1)|foo: 2.3f
Yes things are simpler (and more flexible) now, that should indeed just be
let contour = pF "contour"
curve = pF "curve"
plat = pF "plat"
1 Like
On tuesday, I plan to introduce a bit of granular synthesis / microsound to the students, so I've added a grain envelope to superdirt. We'll hav eto think about parameter names in tidal …
SynthDef("dirt_grain_envelope" ++ numChannels, { |out, sustain = 1, tilt = 0.5, plat = 0, curve = -3 |
var signal = In.ar(out, numChannels);
var p = plat.clip(0, 1);
var c = tilt.clip(0, 1);
var riseAndFall = 1 - p;
var attack = c * riseAndFall;
var release = (1 - c) * riseAndFall;
var hold = p;
var env = EnvGen.ar(Env.linen(attack, hold, release, 1, curve), timeScale: sustain);
signal = signal * env;
ReplaceOut.ar(out, signal);
}, [\ir, \ir, \ir, \ir, \ir]).add;
(
~dirt.addModule('grenvelo',
{ |dirtEvent|
dirtEvent.sendSynth('dirt_grain_envelope' ++ ~numChannels,
[
sustain: ~sustain,
tilt: ~tilt,
plat: ~plat,
curve:~curve,
out: ~out
])
}, { ~tilt.notNil });
);
let tilt = pF "tilt"
plat = pF "plat"
curve = pF "curve"
d1 $ (slow 3) $ sound "hh*20 can*10 uxay:2*18 speakspell*8 "
# end 0.8
# begin 0.2
# tilt (slow 7 tri)
# plat (slow 12 tri)
# n 0
# legato (slow 5 tri * 13)
# curve (-6)
d1 $ sound "hh*20 bd*56 can*100" # tilt (sin 0.2 + 1 * 0.5) # plat 0 # n "0 4*7 6 0*9 7 -4*10" # legato (sin 0.421 + 1 * 0.5) # curve (-9) # begin 0.2
6 Likes
I think we should think about a better naming scheme for parameters. The effects are treading on each others' feet a little.
I just had a play with this code. Really cool!
I've been looking for a granular synthdef to use with Tidal. A granular engine mixed with Tidal's control sounds like it would be really powerful.
This synthdef seems just as you describe, a single granular envelope that can transverse through the buffer. Do you think it might be possible to modify code like this so that it could create multiple grain streams at once?
Did you have a problem that looked like this?
ERROR: Variable 'numChannels' not defined.
in interpreted text
line 31 char 45:
SynthDef("dirt_grain_envelope" ++ numChannels ,{ |out, sustain = 1, tilt = 0.5, plat = 0, curve = -3 |
var signal = In.ar(out, numChannels);
-----------------------------------
Yes, I had to modify the SC code by adding one line above. Here's the code I ended up with:
(
var numChannels = ~dirt.numChannels;
SynthDef("dirt_grain_envelope" ++ numChannels, { |out, sustain = 1, tilt = 0.5, plat = 0, curve = -3 |
var signal = In.ar(out, numChannels);
var p = plat.clip(0, 1);
var c = tilt.clip(0, 1);
var riseAndFall = 1 - p;
var attack = c * riseAndFall;
var release = (1 - c) * riseAndFall;
var hold = p;
var env = EnvGen.ar(Env.linen(attack, hold, release, 1, curve), timeScale: sustain);
signal = signal * env;
ReplaceOut.ar(out, signal);
}, [\ir, \ir, \ir, \ir, \ir]).add;
)
(
~dirt.addModule('grenvelo',
{ |dirtEvent|
dirtEvent.sendSynth('dirt_grain_envelope' ++ ~numChannels,
[
sustain: ~sustain,
tilt: ~tilt,
plat: ~plat,
curve:~curve,
out: ~out
])
}, { ~tilt.notNil });
);
3 Likes
That is strange, I can't really get a feeling of what's going on when I have this effect running.
UPDATE: ok, now I get it, that is really cool!
1 Like
I think you can do two things to start with if you want to have parallel streams:
- using
jux
- setting
legato
quite high so you have event bleeding
This is e.g. something I am trying right now (the sample won't work though, sorry for that)
d1
$ juxBy 0.5 (slow 4)
$ jux (slow 2)
$ every 4 (
(struct "t(5,16)")
. (# s "juno_wobble")
. (|- note 9)
. (# squiz (slow 2 $ range 0.5 3 saw))
)
$ sound "[piano_f*2, piano_f:3*3, piano_f:5*8]"
# tilt (slow 2 $ perlin)
# plat (slow 3 $ segment 64 $ rand)
# curve (irand 9)
# legato (slow 4 $ range 2 20 tri)
PS: @yaxu I would love to know if there is a way to embed an audio file in a post.
1 Like