// title: composition barebone // author: vividsnow // description: // attempt to create abstraction for composition based on spawning parts using tags and distance between numerical params (check "find" function) // code: ( 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)); }) )