«more fun with patternproxies, feat. a hack to access internals of the EventStreamPlayer» by alln4tural

on 25 Oct'12 15:39 in patternspatternproxieshacks

possibly too-detailed demo of using functions to generate patterns, and then a function to modify the internals of the resulting EventStreamPlayers while they are running.

  • This latter function uses a sort of hack (thanks to Jonatan, see discussion on sc-users here) to get at the arrays inside the patternpairs of the patternproxy inside the 'receiver' inside the stream of the player.
    z = i.stream.slotAt('receiver');

  • The point here is that using this technique, one need not maintain administrative data about the patterns themselves -- one only has to remember the players as they are being created.

and the meta-point here, beyond me having fun figuring out markdown, is that i would like to make an argument for a less hacky way of legally getting at an EventStreamPlayer's progenitor Pattern.

code
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
102
103
104
105
106
107
108
// switching to mono cz SinedPink.aiff is boring

// two BufRd-based synths, one percussive, one smoother:
(
SynthDef(\bufRdperc1, {| out = 0, bufnum = 0, rate=1, inter=2, posfrac = 0.5, dur = 1, amp = 0.9|
	var widthfrac = (dur/BufDur.ir(bufnum)) * rate;
	var sig = Splay.ar([			
		BufRd.ar(1, bufnum, Phasor.ar(
				0, 
				(BufRateScale.kr(bufnum) * rate), 
				(posfrac * BufSamples.kr(bufnum)), 
				(posfrac * BufSamples.kr(bufnum)) + (widthfrac * BufSamples.kr(bufnum))), 
			1, inter)
	]);
	Out.ar(out, sig  
				* EnvGen.kr(Env.perc,1,1,0,dur,2)
				* amp
	)
}).add;

SynthDef(\bufRdsmooth1, {| out = 0, bufnum = 0, rate=1, inter=2, posfrac = 0.5, dur = 1, amp = 1|
	var widthfrac = ((dur/2)/BufDur.ir(bufnum)) * rate;
	var forward = BufRd.ar(1, bufnum, Phasor.ar(
				0, 
				(BufRateScale.kr(bufnum) * rate.abs), 
				(posfrac * BufSamples.kr(bufnum)) - (widthfrac * BufSamples.kr(bufnum)), 
				(posfrac * BufSamples.kr(bufnum)) + (widthfrac * BufSamples.kr(bufnum))), 
			1, inter);
	var backward = BufRd.ar(1, bufnum, Phasor.ar(
				0, 
				(BufRateScale.kr(bufnum) * rate.abs * (-1)), 
				(posfrac * BufSamples.kr(bufnum)) + (widthfrac * BufSamples.kr(bufnum)), 
				(posfrac * BufSamples.kr(bufnum)) - (widthfrac * BufSamples.kr(bufnum))), 
			1, inter);
	var sound = BiPanB2.ar(forward,backward,FSinOsc.kr(dur));
	sound = sound * EnvGen.kr(Env.sine,1,1,0,dur,2);
	sound = sound * amp;
	Out.ar(out, sound);
}).add;

)

//
// two functions that generate Pbinds
(
~make1perc = { |durs, lib|
	var n   = durs.size;
	Pbind(
	  \bufnum,	PatternProxy(Pseq({lib.choose}!n,inf)),
	  \rate,	PatternProxy(Pseq([1],inf)),
	  \posfrac,	PatternProxy(Pseq({512.rand/512}!n,inf)),
	  \dur, 	PatternProxy(Pseq(durs,inf)),
	  \amp,	PatternProxy(Pseq({(1..3).choose}!n,inf)), 
	  \instrument,PatternProxy(Pfunc({ |ev| ("bufRdperc" ++ ev[\bufnum].numChannels) }))
        );
};

~make1smooth = { |durs, lib|
	var n   = durs.size;
	Pbind(
	  \bufnum,	PatternProxy(Pseq({lib.choose}!n,inf)),
	  \rate,	PatternProxy(Pseq([1],inf)),
	  \posfrac,	PatternProxy(Pseq({512.rand/512}!n,inf)),
	  \dur, 	PatternProxy(Pseq(durs,inf)),
	  \amp,	PatternProxy(Pseq({(1..3).choose}!n,inf)), 
	  \instrument,PatternProxy(Pfunc({ |ev| ("bufRdsmooth" ++ ev[\bufnum].numChannels) }))
        );
};

//
//
// the function with the hack to get at, and modify while running, the internals of the patterns

~frac = { |n = 1|
	~players.do{ |i|
		var z = i.stream.slotAt('receiver'); // the hack. it wd be nice to have legal method for this
		z.patternpairs.at(z.patternpairs.indexOf('posfrac') + 1).source = Pseq({512.rand/512}!n,inf)
	}		
};

)

//
//
//
// fun things to execute at runtime
//

/*
~buffers is an array of mono Buffers. if you don't have any, you can do
~buffers = [Buffer.read(s, Platform.resourceDir ++ "/sounds/a11wlk01.wav")];
*/


[1/8, 1/4, 1/2].do{|i| ~players = ~players.add((~make1perc.([i], [~buffers.choose])).play)}


1.do{~players = ~players.add((~make1smooth.([1], [~buffers.choose])).play)}


~frac.();
~frac.(x = 1);
~frac.(x = x*2);
~frac.(x = x+2);
~frac.(x.postln);


~players.pop.stop;
raw 3202 chars (focus & ctrl+a+c to copy)
reception
comments
vividsnow user 27 Oct'12 16:59

interesting technique and fun sound ) but code seems to work with stereo buffers only, so a11wlk01 is not an option - there is stereo SinedPink.aiff in Platform.resourceDir++'/sounds' p.s. need to reset "~players = [];" on re-run

alln4tural user 28 Oct'12 09:08

ah, thanks -- at home i have mono versions of the synthdefs, sorry. i didnt want to add those, too, it's already too complicated.

i do ~players.pop.stop to kill them one by one.