Sequencing the playing of a portion of an audio file

PlayBuf has a startPos parameter. This works in conjunction with the trigger input: when a trigger occurs (that is, when trigger was <= 0 and now is > 0), playback resets to the sample frame given by startPos.

I see that your code examples use Routine to trigger the segments. This simplifies the situation a lot!

I would recommend a new Synth per segment (your first approach) – because: Every segment needs an envelope, to avoid clicks at the beginning and end. IMO the simplest way to do that is to have the SynthDef just play once, with one time through the envelope, and release itself at the end.

The triggering approach may need to crossfade envelopes. This would require two players, two envelopes, and a mechanism to toggle between them. I recently posted an example but you’ll see below that the “one-segment” SynthDef is much simpler.

This is not the job of the buffer player. It is a good job for the envelope (which, noted above, every audio source needs).

Give the SynthDef a “play time” parameter, and use this in the envelope.

One thing here – var windowSize is not a parameter – arg windowSize would be a parameter. vars are invisible outside of the function, so you should not use var for something you want to control from a Synth arg list. (Edit: var windowSize = \windowSize.kr would also be a parameter – the “var” is local to the function, but the “.kr” exposes \windowSize as a parameter.)

With a couple of refinements:

(1..2).do { |numChannels|
    SynthDef(("bufseg" ++ i).asSymbol, {
        |out, bufnum, startPos, windowSize = -1, amp = 0.1, pan = 0|
        // basically: if window < 0, use the full buffer duration
        var time = Select.kr(windowSize < 0, [windowSize, BufDur.kr(bufnum)]);
        var env = EnvGen.kr(Env([0, 1, 1, 0], [0.01, time - 0.02, 0.01]), doneAction: 2);
        var sig = PlayBuf.ar(numChannels, bufnum,
            rate: BufRateScale.kr(bufnum),
            startPos: startPos
        ) * env;
        // note: numChannels is not a synthdef arg!
        // so concerns about "`if` in a synthdef" do not apply to this block
        var panned = if(numChannels == 1) {
            Pan2.ar(sig, pan, amp)
        } {
            Balance2.ar(sig[0], sig[1], pan, amp)
        };
        Out.ar(out, panned);
    })
}

hjh

2 Likes