Recursive_phrasing

Hello everybody,
I’m studying the recursive_phrasing documentation in the jitlib tutorial and I need help.
In the Pdef(\sweep) above, the arguments freq and sustain have to be evaluated, cause they are functions.
The other arguments n and ratio are not functions so they don’t need to be evaluated (no need to do ratio.value).
My question is what is the difference between freq and ratio, why the first one is a function and the last a value ?
Same question with sustain why is this a function ?

In the examples:

(
s.boot;

SynthDef(\pgrain,
    { arg out = 0, freq=800, sustain=0.001, amp=0.5, pan = 0;
        var window;
        window = Env.sine(sustain, amp * AmpCompA.kr(freq));
        Out.ar(out,
            Pan2.ar(
                SinOsc.ar(freq),
                pan
            ) * EnvGen.ar(window, doneAction: Done.freeSelf)
        )
    }
).add;

Pdef(\sweep, { arg sustain=1, n=8, freq=440, ratio=0.1;
    Pbind(
        \instrument, \pgrain,
        \dur, sustain.value / n,
        \freq, Pseq((1..n)) * ratio + 1 * freq.value // freq is a function, has to be evaluated
    )
});

Pbind(
    \type, \phrase, // phrase event from global library
    \instrument, \sweep,
    \n, 15,
    \degree, Pseq([0, 4, 6, 3], inf),
    \sustain, Pseq([1.3, 0.2, 0.4],inf)
).play;

)

Other question:

Pdef(\sweep, { arg sustain=1, n=8, freq=440, ratio=0.1;
    Pbind(
        \instrument, \pgrain,
        \dur, sustain.value / n,
        \postSustain, sustain.value.postln,
        \postN, n.postln,
        \postFreq, freq.value.postln,
        \freq, Pseq((1..n)) * ratio + 1 * freq.value // freq is a function, has to be evaluated
    )
});

Pbind(
    \type, \phrase,
    \instrument, \sweep,
    //\n, 15, // if I comment this, I can see n = 8 (the default value declared in Pdef(\sweep) for n is 8)
    //\degree, Pseq([0, 4, 6, 3], inf), // if I comment this, I can see freq = 261.62 in the post window (the default value declared in Pdef(\sweep) for freq is 440, I don't understand why I see 261.62)
    //\sustain, Pseq([1.3, 0.2, 0.4],inf) // if I comment this, I can see sustain = 0.8 in the post window (the default value declared in Pdef(\sweep) for sustain is 1, I don't understand why I see 0.8)
).play;

If someone can help with that, I’ll be gratefull
Thanks a lot

The default values for things like freq and sustain are defined in the default Event. There’s a longer description of where this default event comes from here: How do Events get their defaults?

The short-short answer - freq, for example, is defined as:

freq: #{
    (~midinote.value + ~ctranspose).midicps * ~harmonic;
}

It’s defined this way because (by default) it gets calculated based on other keys in the Event. Usually, you would specify \degree or \midinote since they are more musically meaningful - but you can also override this and specify a \freq explicitly as well. In your use-case, it should always be safe to call .value() on the arguments coming from the outer synth, so it’s probably better to get in the habit of doing this rather than trying to learn which are functions and which are not.

Thank you for your answer,
this makes sense.
In the example above when the arg sutain = 1 in Pdef(\sweep), if I don’t provide sustain value in the outer Pattern, it post sustain = 0.8 in the post window because of:

durEvent: (
				tempo: nil,
				dur: 1.0,
				stretch: 1.0,
				legato: 0.8,
				sustain: #{ ~dur * ~legato * ~stretch },
				lag: 0.0,
				strum: 0.0,
				strumEndsTogether: false
			),

the default values of legato (which is 0.8), dur & stretch (which are 1).
sustain: #{ 1 * 0.8 * 1 }
sustain = 0.8
Is this right ?

so what’s confused me now is:
what is the point to define a default value for sustain in the Pdef(\sweep) definition ?
When does this default value will be in use ? In which cases ?

(same question for freq and it’s default value)

Thanks a lot

Hello everybody,
sorry to bother you again, but I’m having difficulties to wrap my head around recursive_phrasing tutorial.
I think, I don’t really understand what \recursionLevel does in the Pattern context.
The key \transparency set to 0 block the proliferation of outer pattern values into the phrase but I don’t understand what’s happening at a value of 1, 2 or 10.

here is an example from that tutorial:

Pdef(\sweep, { arg sustain=1, n=8, degree=0, ratio=1;
    Pbind(
        \instrument, \pgrain,
        \dur, sustain.value.debug("sustain") / n,
        \degree, Pseq((1..n)) * ratio + 1 + degree.value.debug("degree")
    )
});

Pbind(
    \type, \phrase,
    \instrument, \sweep,
    \synthDef, Prand([\pgrain, \default, \noiseGrain],inf), // I don't hear any change
    \n, Prand([2, 4, 3, 8], inf),
    \degree, Pseq([-5, 0, -2], inf),
    \recursionLevel, Prand([0, 1],inf)
).play

What is the key \synthDef is supposed to do here ?
If I comment that line, nothing change.
What is the aim of that example ?

If someone can help me, it’ll be great cause I’m feeling very stupid at the moment.
Thank you in advance

The default value in Pdef(\sweep) is only used if there is no default value in the Event for the given key. \sustain have a default value in the event so there is no point to define a default value for sustain, you are right. Same for freq

Probably an error in the example code, the synthDef argument is missing. try with:

Pdef(\sweep, { arg sustain=1, n=8, degree=0, ratio=1, synthDef;
    Pbind(
        \instrument, synthDef,
        \dur, sustain.value.debug("sustain") / n,
        \degree, Pseq((1..n)) * ratio + 1 + degree.value.debug("degree")
    )
});

Thank you for these clarifications.

hey everyone,
yes, recursive_phrasing has been the most confusing help document for me so far.
this is another question:
consider the two following situations; they only differ in one argument (dur):

//// 1
(
Pdef(\sweep, { | dur = 1, n = 4, freq |
	Pbind(
		\instrument, \pgrain,
		\dur, dur / n,
		\freq, Pseries(1, 1, inf) * freq % 5000
	)
});
Pbind(
	\type, \phrase,
	\instrument, \sweep,
	\degree, Pseq([0, 1, 2, 3], inf),
	\recursionLevel, 1
).play
)

//// 2
(
Pdef(\sweep, { | unit = 1, n = 4, freq |
	Pbind(
		\instrument, \pgrain,
		\dur, unit / n,
		\freq, Pseries(1, 1, inf) * freq % 5000
	)
});
Pbind(
	\type, \phrase,
	\instrument, \sweep,
	\degree, Pseq([0, 1, 2, 3], inf),
	\recursionLevel, 1
).play
)

This difference is causing the recursionLevel parameter to not respond in the second situation.
I might guess that this has something to do with recursionLevel being defined in the source code as a function of the dur key, or something to that effect … ??
Has anyone any idea what goes on behind the scene in general regarding the recursive phrasing paradigm?

Note that the second example behaves the same as the first if you add this to \sweep:

        \unit, (unit / n)

I don’t use recursive phrasing much, but I believe a 1 will use the arguments of the events produced by your first \sweep to spawn another \sweep - it think it should be the same as e.g. having Pdef(\sweep_1) with \instrument, \sweep_2, and Pdef(\sweep_1) with \pgrain like your example.

With this in mind, the reason you get a different result:

1: The events from \sweep have \dur, 1 / 4. Because of the recursion, this recursively spawns another sweep - the dur argument to this is 1 / 4, so these will be \dur, 1 / 4 / 4, or \dur, 1 / 16.

2: In the second case, you’re using unit but you’re not specifying that in any of the Pbinds, so you’re getting the default value every time, which always leaves you with \dur, 1 / 4.

I also find the \recursionLevel parameter a little hard to think about, and musically not that interesting (especially for values > 1) - you might consider just ditching the recursion and breaking this into three patterns, even if that means a little code duplication. Musically, you’ll probably end up wanting to alter each of the patterns separately anyway.

1 Like

thank you for the response… really appreciate it.

1 Like

Some general remarks on this: I, too, find the nesting into many levels with Patterns something very difficult to apply musically, regardless of the implementation. E.g., also with “normal” Patterns, usually, two levels, is the max for me. However, the nesting idea is appealing, given the hierarchical structuring of many traditional musical forms.
To mention another possibility: Pspawner allows arbitrary nesting as well, combined with its other powerful features, this is a very interesting option.
And another way of nesting: you can combine Patterns with synths that are sequencing themselves. miSCellaneous_lib’s Buffer Granulation tutorial contains examples for this (3. Hybrid Implementations)

1 Like

If anyone is interested in an alternative way of doing replacement-based pattern processing, I have a rather experimental pattern class based on chaining replacements of events, similar to recursive phrasing. I find it a little more modular and expressive for the cases i use it for. And - it produces a single stream of events that can be modified later on, where recursive phrasing simply plays the replacement patterns independently, which means you effectively “lose” the events.

The class and some examples: PparStream.sc · GitHub