Make GrainBuf play the original audio pack

I was experimenting with the GrainBuf, and thought it should play back the whole audio file, if I specify the duration and the rate to correspond to the audio file and set the start position to 0. I did this:

(
f = {
	var b = ~p2;
	GrainBuf.ar(
		numChannels: 1,
		trigger: \t_trig.kr(1),
		dur: BufDur.ir(b),
		sndbuf: b,
		rate: BufRateScale.kr(b),
		pos: 0,
		envbufnum: Buffer.sendCollection(
			s,
			Env(times: [4, 4]).discretize, 
			// wait: 1,
			action: {"FINITO!".postln}
		)
	)
}.play
)

but it sounds as parts of the audio are chopped off. I tried this with different audio files and the result is the same. Can any one explain where the chopping comes from? Is it happening because of the default hanning envelope?
Also does the pos argument cause a wrapping around the sound file? In the example above pos: 0 and pos: 1 sound and look exactly the same (plotted).

You should define your custom env outside GrainBuf so you only need to do it once. Also, your env has a triangle shape, which is not ideal for what you are looking for. Try this:

(
// var env = Env(times: [4, 4]);
var env = Env([0, 1, 1,0], [0.02, 1, 0.02]).plot;
e = Buffer.sendCollection(s, env.discretize, 1);
);

b = Buffer.read(s, Platform.resourceDir +/+ "sounds/a11wlk01-44_1.aiff");

(
f = {
	// var b = ~p2;
	GrainBuf.ar(
		numChannels: 1,
		trigger: \t_trig.kr(1),
		dur: BufDur.ir(b),
		sndbuf: b,
		rate: BufRateScale.kr(b),
		pos: 0,
		envbufnum: e
		)
}.play
)

Grate! Thank you!
It’s strange though that with the rate argument BufRateScale.kr(b) causes a pitch shift, but specifying 1 as rate doesn’t!

I just checked and I am equally surprised. This bug was reported all the way back in 2017. Does any other readers of this thread know if this issue was ever looked at?

1 Like

And may I ask (just for sake of my learning) how did you came to the idea to look for and find that specific bug report? Did you look all the issue reports on github?!

It seem like a clear bug to me and I searched for

Supercollider + GrainBuf + bug

and the page came up as one of the first hits.

I normally only look for bug reports if I find something really odd about a specific class or method and also, corresponding with people on the forum has taught me about at least one bug that directly influence what I am working on at the moment.

1 Like

SC’s original release included PlayBuf for normal playback, and TGrains for granulation.

In this original release, PlayBuf required (and still requires) BufRateScale to play a buffer back at its native pitch – but TGrains always used rate = 1.0 for native pitch, without BufRateScale. One could argue that this was a bad decision, but the fact is that from the beginning, there was an informal convention that, in granular UGens, rate = 1.0 means normal pitch.

Since I wasn’t completely sure if my memory was correct, I tried it:

p = Platform.userAppSupportDir +/+ "sounds/vocal-samples/VOCALS and SPOKEN WORD/male misc/absolutely_gorgeous.aif";

(
f = SoundFile.openRead(p);
f.sampleRate.postln;  // 22050, definitely not matching system SR
f.close;
)

s.boot;

b = Buffer.read(s, p);

// PlayBuf rate 1
// too high
a = { PlayBuf.ar(1, b, rate: 1, doneAction: 2).dup }.play;

// PlayBuf rate BufRateScale
// correct
a = { PlayBuf.ar(1, b, rate: BufRateScale.kr(b), doneAction: 2).dup }.play;

// TGrains rate 1
// ***correct pitch***
(
a = {
	var trigRate = 50, overlap = 4;
	var grainDur = overlap / trigRate;
	var half = grainDur * 0.5;
	var bufdur = BufDur.kr(b);
	var phase = Line.kr(half, bufdur - half, bufdur - grainDur, doneAction: 2);
	TGrains.ar(2, Impulse.ar(trigRate), b,
		rate: 1,
		centerPos: phase,
		dur: grainDur,
		amp: 0.5
	)
}.play;
)

GrainBuf was added later (2007), and follows, rather than violates, this convention. That is, the issue report makes it sound like GrainBuf is renegade, but in fact, it’s following precedent.

So if this were to be “fixed,” then all granular UGens would have to be changed. This would cause every granulator SynthDef, everywhere in the SC-verse, to change behavior. I… don’t think we’re going to do that.

I think the best solution is to update the documentation to make it absolutely clear, in all of the buffer-granulator help files, that rate here does not follow the same rule as in PlayBuf. TGrains already says “1.0 is normal, 2.0 is one octave up” and none of the examples uses BufRateScale. GrainBuf alas doesn’t specify.

hjh

Good to know a little about the history of SC and see decisions like this in a historic perspective. Also, thanks for updating the Github page so other people won’t find the same issue and think it is a bug.