Skip to content

Instantly share code, notes, and snippets.

@scztt
Last active February 8, 2022 22:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save scztt/dcd493c32ac772716cb905cf4eb635b4 to your computer and use it in GitHub Desktop.
Save scztt/dcd493c32ac772716cb905cf4eb635b4 to your computer and use it in GitHub Desktop.
PparStream : Stream {
var <>initStreamAction, <>endStreamAction;
var priorityQ, <now;
var <injectFunc;
*initClass {
Class.initClassTree(Event);
Event.addEventType(\fork, {
var event, outerEvent, recursionLevel, instrument, embeddingLevel, freq, rest;
var args, defaults, timingOffset, sustain;
var size, pattern;
pattern = ~pattern ?? { ~instrument };
if(pattern.notNil) {
// preserve information from outer pattern, but not delta.
if (pattern.isKindOf(Function)) {
defaults = pattern.def.prototypeFrame;
args = pattern.def.argNames.collect {
|name, i|
currentEnvironment[name].value ?? { defaults[i] }
};
pattern = pattern.value(*args);
};
if(~transparency ? true) {
outerEvent = currentEnvironment.copy;
outerEvent.putPairs(
[
\instrument, \pattern, \type,
\parentType, \addToCleanup, \removeFromCleanup, \sustain, \legato
].collect([_, nil]).flatten
)
} {
outerEvent = Event.default.copy;
};
outerEvent.put(\delta, nil); // block delta modification by Ppar
outerEvent.put(\instrument, ~synthDef);
if (~flop ?? { false }) {
outerEvent = outerEvent.asPairs.flop.collect(_.asEvent);
outerEvent.do(_.parent_(currentEnvironment.parent));
} {
outerEvent = [outerEvent]
};
outerEvent.do {
|outerEvent, i|
var innerPattern, timingOffset, gatePattern, localPattern;
outerEvent.use {
innerPattern = pattern;
if (innerPattern.isKindOf(Symbol)) {
innerPattern = Pdef(pattern);
};
if (outerEvent.size > 1) {
innerPattern = innerPattern.copy;
};
innerPattern = innerPattern.value;
if (innerPattern.isKindOf(Event)) {
Error("Event patterns must be wrapped in a Ref or a function when passed in as an \instrument argument").throw;
};
if (innerPattern.isKindOf(PatternProxy)) {
innerPattern = innerPattern.pattern; // optimization. outer pattern takes care for replacement
};
if (innerPattern.notNil) {
timingOffset = (~timingOffset.value ? 0);
gatePattern = (~gatePattern.value ? true);
// not sure why we DON'T need to account for positive timingOffset here,
// but if we do it breaks....
if (gatePattern) {
innerPattern = innerPattern.finDur(~sustain.value - timingOffset.min(0));
};
innerPattern = Pevent(innerPattern, outerEvent);
if (timingOffset < 0) {
innerPattern.fastForward(timingOffset.neg, 0, outerEvent);
};
currentEnvironment['injectStream'].value(timingOffset, innerPattern, outerEvent)
}
}
}
}
}, Event.parentEvents.default.copy.putAll((legato:1)));
}
*new {
^super.new.init
}
init {
priorityQ = PriorityQueue();
now = 0;
injectFunc = { |delta, stream, inval| this.injectStream(delta, stream, inval) };
}
reset {
this.init();
}
injectStream {
|delta, stream, inval|
stream = stream.asStream;
initStreamAction !? {
stream = initStreamAction.value(stream, inval).asStream
};
priorityQ.put(now + delta, stream);
^stream;
}
embedInStream {
|inval|
var stream, nextTime, outval;
now = 0;
while { priorityQ.notEmpty } {
nextTime = priorityQ.topPriority;
if (nextTime > now) {
inval = Event.silent(nextTime - now, inval).yield;
now = nextTime;
} {
stream = priorityQ.pop;
outval = stream.next(inval).asEvent;
if (outval.notNil) {
// requeue stream
priorityQ.put(now + outval.delta, stream);
outval[\delta] = 0;
outval['injectStream'] = injectFunc;
inval = outval.yield;
} {
endStreamAction.value(stream, inval);
}
};
};
^inval
}
}
Ppar2 : ListPattern {
var <>initStreamAction, <>endStreamAction;
embedInStream {
|inval|
var parStream = PparStream()
.initStreamAction_(initStreamAction)
.endStreamAction_(endStreamAction);
repeats.value(inval).do({
list.do(parStream.injectStream(0, _, inval));
parStream.embedInStream(inval);
parStream.reset();
})
}
}
Pb : Ppar2 {
*new {
|...keysValues|
^super.new([
Pbind(
*keysValues
)
])
}
}
+Ppar {
*new {
|list, repeats=1|
^Ppar2.new(list, repeats);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment