Skip to content

Instantly share code, notes, and snippets.

@scztt
Last active January 15, 2022 10:56
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/c95e090f8ed4ce8dffaee85d592fc2fe to your computer and use it in GitHub Desktop.
Save scztt/c95e090f8ed4ce8dffaee85d592fc2fe to your computer and use it in GitHub Desktop.

Event.addEventType(\pattern, { var pat, event, outerEvent, recursionLevel, instrument, embeddingLevel, freq, rest; var args, defaults, timingOffset;

~pattern = ~pattern ?? { ~instrument };

if (~pattern.isKindOf(Function)) {
	defaults = ~pattern.def.prototypeFrame;
	args = ~pattern.def.argNames.collect {
		|name, i|
		currentEnvironment[name].value ?? { defaults[i] }
	};
	pat = ~pattern.value(*args);
} {
	if (~pattern.isKindOf(Symbol)) {
		~pattern = Pdef(~pattern);
	};

	pat = ~pattern.value;
};

if (pat.isKindOf(Event)) {
	Error("Event patterns must be wrapped in a Ref or a function when passed in as an \instrument argument").throw;
};

if(pat.notNil) {
	if (pat.isKindOf(PatternProxy)) {
		pat = pat.pattern; // optimization. outer pattern takes care for replacement
	};

	// preserve information from outer pattern, but not delta.
	if(~transparency ? true) {
		outerEvent 						= currentEnvironment.copy;
		outerEvent[\instrument] 		= nil;
		outerEvent[\pattern] 			= nil;
		outerEvent[\type] 				= nil;
		outerEvent[\parentType] 		= nil;
		outerEvent[\timingOffset] 		= nil;
		outerEvent[\addToCleanup] 		= nil;
		outerEvent[\removeFromCleanup]	= nil;
	} {
		outerEvent = Event.default;
	};

	outerEvent.put(\delta, nil); // block delta modification by Ppar
	outerEvent.put(\instrument, ~synthDef);

	timingOffset = ~timingOffset.value ? 0;

	// not sure why we DON'T need to account for positive timingOffset here,
	// but if we do it breaks....
	if (~gatePattern ? true) {
		pat = pat.finDur(~sustain.value - timingOffset.min(0));
	};

	if (timingOffset < 0) {
		pat = pat.asStream;
		pat.fastForward(timingOffset.neg, 0, outerEvent);
		pat = pat.asEventStreamPlayer(outerEvent);
		pat.play(thisThread.clock, quant:0.0);
	} {
		pat.play(thisThread.clock, outerEvent, 0.0)
	}
}

}, Event.parentEvents.default.copy.putAll((legato:1)));

// Reset `pattern` every `durs` beats.
// If pattern is finished, yield `emptyValue` until we are reset.
// (
// Pdef(\ptclip, Pbind(
// \scale, Scale.bartok,
// \dur, 1/8, \legato, 3,
// \octave, 4,
// \degree, PTclip(
// Prand([0, 1, 3, 6, 8], inf),
// Pseq([1, 1.5, 0.75], inf).trace,
// )
// )).play
// )
PTclip : FilterPattern {
var <>durs, <>emptyValue;
*new { arg pattern, durs, emptyValue;
^super.new(pattern)
.durs_(durs)
.emptyValue_(emptyValue)
.init
}
init {
if (pattern.isSequenceableCollection) { pattern = Pseq(pattern); };
if (durs.isNumber) { durs = [durs] };
if (durs.isSequenceableCollection) { durs = Pseq(durs); };
}
storeArgs { ^[pattern, durs, emptyValue] }
embedInStream { |inval|
var valueStream, emptyStream, durStream, isRest;
var dur, value;
var cleanup = EventStreamCleanup.new;
thisThread.endBeat = thisThread.endBeat ? thisThread.beats;
// endBeat > beats only if Pfindur ended something early
thisThread.endBeat = thisThread.endBeat min: thisThread.beats;
durStream = durs.asStream;
while {
dur = durStream.next(inval);
dur.notNil;
} {
thisThread.endBeat = thisThread.endBeat + dur;
// Log(PTclip).info("thisThread.endBeat = %, dur = % ", thisThread.endBeat, dur);
valueStream = pattern.asStream;
while {
(thisThread.beats < thisThread.endBeat).if({
value = valueStream.next(inval) ?? { emptyValue.value(inval) };
if (value.isKindOf(Event)) {
if ((thisThread.beats + value.delta) >= thisThread.endBeat) {
if (value.isRest) {
value = value.copy.deltaOrDur_(Rest(thisThread.endBeat - thisThread.beats));
} {
value = value.copy.deltaOrDur_(thisThread.endBeat - thisThread.beats);
}
};
cleanup.update(value);
};
true;
}, {
false
})
} {
inval = value.yield(inval);
}
};
^cleanup.exit(inval);
}
}
+Object {
finDur {
|durs, emptyValue|
^PTclip(this.asPattern, durs, emptyValue)
}
}
+Pattern {
finDur {
|durs, emptyValue|
^PTclip(this, durs, emptyValue)
}
}
+Event {
deltaOrDur_{
|delta|
if (this[\delta].notNil) {
this[\delta] = delta;
} {
this[\dur] = delta / (this[\stretch] ? 1)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment