An alternative solution, something that I've been experimenting with a little - here's a pattern that allows you to merge events that occur at the same time. In your case, your "merge" is just to throw away the snare and only play the kick, but you can imagine there may be other kinds of transformations that would be interesting too.~toMerge = List();~mergeFunc = {|events|events.detect({ |e| e[\instrument] == \kick })// you could modify the event in other ways, or merge in a more complex way here};Pdef(\merge, Pfunc({|event|if (event[\delta] < 0.000001) {~toMerge.add(event);event = Event.silent(event[\delta], event); // return a silent event and wait for more} {if (~toMerge.size > 0) {event = ~mergeFunc.(~toMerge).put(\delta, event[\delta]);~toMerge.clear();}};event;}));Chaining this with your existing event stream should do it:Pdef(\merged, Pdef(\merge) <> Ptpar([0, a, 0.5, b])).play;~mergeFunc = { |events| var e = events.detect({ |e| e[\instrument] == \kick }); e[\amp] = e[\amp] * 1.5 }; // make the kick a bit louder when it overlapsThis would be easy enough to package up into a Ptmerge class that took e.g. a merge function and the merge delta (0.000001), which would make the things quite easy and flexible to use. I'm not sure how you would output more than one even when you merge - it might not be possible with the above structure, but who knows.- SOn Fri, Dec 7, 2018 at 12:26 PM <caseywescott@xxxxxxxxx> wrote:Wow.This works perfectly. Thank you so much for the clear explanation Daniel. Your code really made several concepts I was vague about much clearer. Thank you. I will be checking out Xenakis' sieves soon too.Cheers,CaseyOn Fri, Dec 7, 2018 at 6:11 AM <daniel-mayer@xxxxxxxx> wrote:
Am 07.12.2018 um 11:34 schrieb caseywescott@xxxxxxxxx:
> Hi,
>
> I'm using patterns to sequence kick and snares. I'm attempting to 'mute' the snare-pattern such that when the kick-pattern is triggering a note, the snare pattern is 'muted' so that the two synths will never play at the same time. Is there a functionality in patterns that I can use to do this or do I need to create a 'kick synth' that gates a snare-synth or that mutes a bus sending triggers to a snare synth?
Hi,
I'm not aware of something out of the box and I wouldn't go for a server-side solution here.
The question touches two topics:
1) timing: logical vs. physical time:
http://doc.sccode.org/Guides/ServerTiming.html
2) data sharing with patterns:
http://doc.sccode.org/Tutorials/A-Practical-Guide/PG_06g_Data_Sharing.html
With Ptpar you have two independant streams and the decisions in the second stream should be based on data in the first stream. So you'd have to introduce a slight time-shift in the second stream (by an offset in Ptpar) to guarantee order of execution. That would practically suffice (if the shift is very small), but you can optionally equalize the shift by using \lag or \timingOffset in the first stream. The latter doesn't change the logical time (and hence doesn't affect the order of execution), but adds latency so that the result is again in perfect sync.
// most snare events muted here
(
var a, b, kickTime,
lagTime = 0.00001, // time-shift mainly to be used in Ptpar
threshold = 0.001; // threshold for regarding beats as "happening at the same logical time"
//kick pattern
a = Pbind(
\dur, Prand([
Pseq([0.25, 0.25, 0.25, 0.25,0.25, 0.25, 0.25, 0.25]/2, 1),
Pseq([0.5, 0.5, 0.5, 0.5], 1),
Prand([1, 1, 0.75, 0.25, 1], 1),
Pseq([0.25, 0.5, 0.25, 0.25,0.25, 1, 0.25, 0.25]/2, 1)
], inf),
\lag, lagTime,
// assign logical kickTime to variable that can be taken over by second stream
// if you don't use local code block variables as here, then you can take envir variables as well
\kickTime, Pfunc { kickTime = thisThread.clock.beats },
\amp, Pxrand([1, 0.5, 0.7], inf),
\instrument, \kick);
//snare pattern
b = Pbind(
\dur, Pxrand([
Pseq([1,1], 1),
Pseq([1,0.25,1,1.75], 1),
Pseq([1,0.25,1,1.75]/2, 1),
Pseq([0.5, 0.5], 1),
Pseq([0.25, 0.25, 0.25, 0.25,0.25, 0.25, 0.25, 0.25]/2, 1),
Pseq([0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.5, 0.25, 0.25,0.25]/16, 1);
Pseq([0.5, 0.25, 0.75, 0.25,0.25, 1, 0.75, 0.25]/2, 1),
], inf),
\snareTime, Pfunc { thisThread.clock.beats },
// Pfunc with argument can take over previous value of Event
\mute, Pfunc { |e| ((kickTime - e[\snareTime]).abs < threshold).if { 1 }{ 0 } },
\amp, Pxrand([1, 1, 0.5, 0.85,0.75, 1, 0.65, 1], inf) * (1 - Pkey(\mute)),
\instrument, \snare
);
// things can be observed better if we play on a quant grid
Ptpar([0, a, 0.5 + lagTime, b]).trace.play(quant: 1)
)
// compare, we get more snare events with an odd offset
...
Ptpar([0, a, 0.03 + lagTime, b]).trace.play(quant: 1)
There is a totally different approach also, but it would require a bit rewriting: Xenakis' sieves are a powerful generative tool. The miSCellaneous_lib quark includes two implemenations of sieves: a "classical" one with integers as generators and a second one that can be fed with Patterns. The "logical difference" operator is exactly what you are doing here in another form. The corresponding classes are PSVdif_i and PSVdif_oi.
Sorry, I have no time to work out your example with these classes right now, but there are rhythmical examples at the end of the help file "Sieves and Psieve patterns"
Regards
Daniel
----------------------------------------------------
http://daniel-mayer.at/software_en.htm
----------------------------------------------------
_______________________________________________
sc-users mailing list
info (subscription, etc.): http://www.birmingham.ac.uk/facilities/ea-studios/research/supercollider/mailinglist.aspx
archive: https://listarc.bham.ac.uk/marchives/sc-users/
search: https://listarc.bham.ac.uk/lists/sc-users/search/