«freeze playback» by LFSaw

on 03 Jul'23 10:31 in playbackjitfreezeefx

Explore options to freeze playback of a sound file (a) by playhead movement (b) by FFT freeze

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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
q = q ? ();

// load buffers
// e.g. mono sound (see below)
q.audioBuffer = Buffer.read(s, Platform.resourceDir +/+ "sounds/a11wlk01.wav");

(
Ndef(\freezePlayer).addSpec(
	\lpFreq, \freq,
	\hpFreq, \freq,
	\shift, [0.125, 4, \exp],
	\freezeRate, [10, 100, \exp], // how fast to go back and forth
	\rateDir, [-1, 1, \lin], // direction of movement in the buffer, if 1 or -1, use normal playback
	\rate, [0.125, 16, \exp], // how fast the buffer should play back/forth in normal mode
	\modSource, [0, 2, \lin, 0], // [SinOsc, LFPulse, LFTri]
);

// make sure to check number of channels of the buffer(s) to be used
Ndef(\freezePlayer, {|bufnum = 0|
	var numChannels = 1;
	var chain, efx;
	var rateDir = \rateDir.kr(0);
	// var wet = \wet.kr(0) > 0;
	var wet = rateDir.abs < 1;
	var rateScale = BufRateScale.kr(bufnum);

	// possible modulation sources are e.g. LFPulse, LFTri, SinOsc..
	// for the system to work properly, the integrated signal should be 0, (i.e. going equal parts backwards and forwards).
	var modSource = LinSelectX.kr(\modSource.kr(0), [
		SinOsc.kr(\freezeRate.kr(20), phase: 0).range(-1, 1),
		LFPulse.kr(\freezeRate.kr(20), iphase: 0).range(-1, 1),
		LFTri.kr(\freezeRate.kr(20), iphase: 0).range(-1, 1)
	]);


	var rateFX = (
		((1-wet) * rateDir.sign) // normal playback
		+ (wet * (modSource + rateDir)) // "freeze"
	) * \rate.kr(1) * rateScale;

	var snd = PlayBuf.ar(
		numChannels: numChannels,
		bufnum: bufnum,
		rate: rateFX,
		trigger: \trig.tr(1),
		loop: 1
	);

	snd = LPF.ar(HPF.ar(snd, \hpFreq.kr(10)), \lpFreq.kr(10000));
});
);

Ndef(\freezePlayer).set(\bufnum, q.audioBuffer.bufnum);
Ndef(\freezePlayer).edit;


// q.audioBuffer.play

//////////////// frequency-domain

(
Ndef(\freezePlayerFFT).addSpec(
	\lpFreq, \freq,
	\hpFreq, \freq,
	\wet, [0, 1, \lin, 1],
	\frShift, [0.25, 4, \exp],
	\frDiff, [0, 1, \lin, 1]
);
Ndef(\freezePlayerFFT, {|bufnum = 0|
	var numChannels = 1;
	var chain, efx;
	var wet = \wet.kr(0) > 0;
	var buffer = q.audioBuffer;
	var snd = PlayBuf.ar(
		numChannels: numChannels,
		bufnum: bufnum,
		rate: \rate.kr(1) * BufRateScale.kr(bufnum) * (1-wet),
		trigger: \trig.tr(1),
		loop: 1
	);

	// FFT processing
    chain = FFT(LocalBuf(4096), snd); // encode to frequency domain
	chain = PV_Diffuser(chain, \frDiff.kr(0) * wet);
	chain = PV_Freeze(chain, wet);
	chain = PV_BinShift(chain, \frShift.kr(1));

	efx = IFFT(chain); // decode to time domain

	snd = Select.ar(wet, [snd, efx]);
	// snd = efx;

	snd = LPF.ar(HPF.ar(snd, \hpFreq.kr(10)), \lpFreq.kr(10000));
});
)

Ndef(\freezePlayerFFT).set(\bufnum, q.audioBuffer.bufnum);


Ndef(\freezePlayerFFT).play
Ndef(\freezePlayerFFT).edit
raw 2753 chars (focus & ctrl+a+c to copy)
reception
comments