Sequencing the playing of a portion of an audio file

Hi everyone,

I have to do a simple thing, but unfortunately, I don’t know in which way would be “better”.
I would love to use a SynthDef and a Routine for sequencing.

I need to:

  1. Play an audio buffer for a specific amount of time, for example “1/8 - 1/16 - 1-32” the file could be longer or shorter.

  2. I would like to been able to playing it once or n times.

  3. I would like to play the audio file from the beginning, or to set a specific cue.

What do u suggest?

The structures it could be something like that.

b = Buffer.read(s, Platform.resourceDir +/+ "sounds/a11wlk01.wav");

SynthDef(\playThatBuf, {
	var snd, windowSize;
	
	snd =  // the Buffer player with windowSize


	Out.ar(\out.kr(0), snd);
}).add;

(


var s, bpm, beat;
s = Server.default;

bpm = 160;
beat = 60 / bpm;

	Routine({
		loop {
			var subdivisions;
			subdivisions = [2, 4, 8, 16].choose;
			subdivisions.do { |i|
				s.bind { Synth(\playThatBuf, [  windowSize: (beat / subdivisions) ]) };
				(beat / subdivisions).wait;
			};
		};
	}).play;



or is it better to have a sampler on the server and to work with .set ?

Routine({
		loop {
			s.bind { playThatBuf.set() };
		
		};
	}).play;

Thanks in advance,
best!

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