«composition barebone» by vividsnow

on 16 Jun'12 10:44 in composition

attempt to create abstraction for composition based on spawning parts using tags and distance between numerical params (check "find" function)

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
(
Server.internal.waitForBoot({
	var clock = TempoClock(4);
	var bus = 8;
	var channels = 2; // per bus
	Pproto(
		{
			var out = ~out = (type: \audioBus, channels: channels * bus).yield.out;
			{ // or multichannel diskout
				Out.ar(0, Mix(In.ar(~out, channels * bus).clump(channels))) 
			}.play(Server.internal);
			{ Stethoscope(Server.internal, channels * bus, out, zoom:1/4).toggleSize }.defer;
		},
		Pspawn(
			Pbind(*[ // or maybe ppar for independent partition 
				method: \par,
				tag: Pwrand([\break,\steady,\transit], [1,3,1].normalizeSum, inf), // part tag - Pfsm?..
				repeatability: Pwrand([true,false], [0.1,0.9], inf),
				delta: Pfunc({ |ev| // set part duration and pattern
					ev.dur = (8,12..16).choose;
					ev.param = ev.dict.param.next(());
					ev.pattern = ev.retrieve;
					ev.dur;
				})
			]),
			( // proto event used as object
				retrieve: { |ev|
					var pat = ev.dict.selector(ev);
					ev.repeatability.and(ev.archive.size > 0).if({ // add some already played part
						var part = ev.archive.choose;
						ev.dur = ev.dur + part[1].dur;
						pat = Pseq([ part[0], pat ]);
					});
					ev.archive.add([pat, (dur: ev.dur)]); // backup part
					pat;
				},
				dict: ( 
					param: Pbind(*[ // common part params
						intensity: Pbrown(),
						variability: Pbrown(),
					]).asStream,
					selector: { |self, ev| // selects first combinator with nearest common param
						self.find(\combinators, ( tags: ev.tag.asArray, param: ev.param )).first.fn(ev);
					},
					combinators: [ // tagged part variants
						( tags:[\steady], param: (intensity: 0.5), fn: { |self, ev| 
							Pfindur( ev.dur * 1.rrand(4), Pbindf(
								ev.bag.rnd(ev, Pseq([1,2],inf)),
								\octave, self.state.octave.next
							))
						}, state: ( octave: Prand((2..6), inf).asStream ) ),
						( tags:[\break], param: (intensity: 0.5), fn: { |self, ev| 
							Pfindur( ev.dur * 1.rrand(4), Pbindf(
								ev.bag.rnd(ev, Pbrown(1/16,2,1.rrand(4)/16)),
								\note, Pbrown(0,22,1.rrand(4)),
								\octave, 2.rrand(5)
							))
						}),
						( tags:[\transit], param: (intensity:0.5), fn: { |self, ev|
							Pfindur( ev.dur, ev.bag.rnd(ev, ev.dur * 2.rrand(3)) )
						})
					],
					find: { | self, type, params | // function for to search pattern by tags and sort by distance to param
						self.at(type).select({ |i,n| // select by tag
							(i.includesKey(\tags).if({i.tags},{[]})).includesAll(params.tags); 
						}).collect({ |i,n|
							[ i, params.param.keys.sect(
								i.includesKey(\param).if({i.param.keys},{[]})
							).collect({ |k| i.param[k] sqrdif: params.param[k] }).sum ];
						}).sort({ |a, b| a[1] < b[1] }).collect({ |i| i[0] }); // sort by params
					}
				),
				bag: ( // simple key-value store
					rnd: { |self, ev, dur| Pbind(*[
						delta: dur,
						dur: Pkey(\delta) * Pfunc({ thisThread.clock.beatDur }) / 1.rrand(4),
						amp: Pseg(Pbrown(0.1, 0.5), Pseq(ev.dur.partition(ev.dur,1/16)), \sine, inf),
						note: Pbrown(0,11,1.rrand(4)),
						out: Pkey(\out) + (bus.rand * 2),
						pan: Pstutter(1.exprand(16), Pbrown(-0.9,0.9,0.1.rrand(0.8)))
					]) }
				),
				archive: [] // already played patterns
			)
		)
	).play(clock, (server:Server.internal));
})
)
raw 3320 chars (focus & ctrl+a+c to copy)
reception
comments
alln4tural user 16 Jun'12 12:02

i am going to need an extrabig bottle of grok before i understand this one ..

vividsnow user 17 Jun'12 10:03

basis of this are Pproto, Pspawn, Event types with cleanup and Using Environments as object prototypes - good stuff to know.. maybe )