«Sound file chunks: Workaround for single-precision buffer indexing» by jamshark70

on 06 Nov'13 21:19 in bufferutilitylongbufrdchunksincremental

One of the common questions on the list is about handling very large sound files with BufRd. BufRd indexes into the buffer using a single-precision float, which supports buffers only up to 2**24 frames (a bit more than six minutes at 44.1 kHz).

This approach loads sequential chunks of a sound file into buffers that are within reach of BufRd. Then, the SynthDef can advance from one buffer to the next during playback.

Each buffer holds one extra sample, to try to give BufRd's linear interpolation enough information to work with. There may or may not be an off-by-one bug here. If you find a problem, let me know.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
(
~loadChunks = { |server, path, startFrame = 0, numFrames = -1, action, chunkSize = 1048576|
	var sf, numCh, bufs, incr = 0;
	sf = SoundFile.openRead(path);
	if(sf.isOpen) {
		numCh = sf.numChannels;
		if(numFrames < 0) {
			numFrames = sf.numFrames - startFrame;
		} {
			numFrames = min(numFrames, sf.numFrames - startFrame);
		};
		sf.close;
		bufs = Buffer.allocConsecutive((numFrames / (chunkSize - 1)).roundUp, server, chunkSize, numCh);
		{
			server.sync;
			bufs.do { |buf, i|
				buf.read(path, startFrame + incr, chunkSize, 0);
				server.sync;
				incr = incr + chunkSize - 1;  // overlap 1 sample for interpolation
			};
			action.value(bufs);
		}.fork(AppClock);
		bufs
	} {
		"% could not be opened.".format(path).warn;
	};
};
)

b = ~loadChunks.value(s, "your-file.aiff", action: { "done".postln });

(
SynthDef(\playchunks, { |out = 0, bufnum, numbufs = 1, rate = 1, amp = 0.1|
	var phaseTrigFb = LocalIn.ar(1),
	frames = BufFrames.kr(bufnum),
	phase = Phasor.ar(phaseTrigFb, rate, 1, frames + 1000, 1),
	phaseTrig = phase >= (frames - 1),
	bufOffset = PulseCount.ar(phaseTrig),
	sig = BufRd.ar(2, bufnum + bufOffset, phase, loop: 0);
	FreeSelf.kr(bufOffset >= numbufs);
	LocalOut.ar(phaseTrig);
	Out.ar(out, sig * amp);
}).add;
)

a = Synth(\playchunks, [bufnum: b.first, numbufs: b.size, amp: 1]);

a.free;

b.do(_.free);
raw 1390 chars (focus & ctrl+a+c to copy)
reception
comments