SinOsc
Env([0, 1, 0.8, 0.4, 0.2, 0], [0.01, 0.3, 0.56666, 0.2, 0.3], [\sin, \sin, \sin, \sin, -2]).plot;
a.play;
(
var bufTime, rBufTime, pianoBufTime, rPianoBufTime, warpBufTime, rWarpBufTime, notes, pevents, psink, maxDel, bandPassFunc;
var testBuffer, saxBuf, pianoBuf, drumsBuf, voiceSaxWarpBuf, grainBuf, fftBufA, fftBufB, fftBufC, fftPeakBuf, fftBufRd, trigFftBuf, delTimeBuf, fbBuf;
var testbus, routebus0, routebus1, routebus2, routebus3, voiceSaxbus, drumsbus, pianobus, voicebus, saxbus, p1Route, extraBus0, extraBus1, extraBus2;
var initMod, killMod, reverbRoute, voiceIn, saxInRec, pianoRec, exciterFilt, granular, loopProc, drumLoopProc2, evanLoopProc, loopProc2, loopStretch, warpMoment, endWarpMoment, pianoTrigWarp, fftStretch, playback;
var fftHop, fftWinsize, fftBufRdSize, fftBufTime, rFFTBufTime;
var procBoolean, midiFunction, midiMixerFunction, init1, init2, init3, ampControlVoice, ampControlPiano, ampControlDrums, peakControlLP, peakControlHP;
var pianoTrigWarpFunc, drumLoopProc2Func, warpMomentManyFunc, fftStretchFunc, cymbalTrigDelay, test;
var saxInbus, pianoInbus, drumsInbus, voiceInbus, pedalInbus;
var pianoTrigEnv1, pianoTrigEnv2, pianoTrigEnv3;

pianoBufTime = 7 * 60;
rPianoBufTime = pianoBufTime.reciprocal;

warpBufTime = 4 * 60;
rWarpBufTime = warpBufTime.reciprocal;

fftBufTime = 60;
rFFTBufTime = fftBufTime.reciprocal;

saxInbus = 0;
pianoInbus = [0, 1];
drumsInbus = [2,3,4];
voiceInbus = 0;
maxDel = 0.5;

bandPassFunc = { arg freq; 2 * freq/s.sampleRate };
notes = CtkProtoNotes(

	SynthDef(\testFFT, {arg hop = 0.25, wintype = 1, fftBuf1, fftRecBuf;
		var src, chain;∏
		src = SoundIn.ar(pianoInbus);
		chain = FFT(fftBuf1, src, hop, wintype);
		chain = PV_RecordBuf(chain, fftRecBuf, 0, 1, 0, hop, wintype);
	}),
	SynthDef(\saxIn, {arg amp, outbus1;
		var src, env, out;
		//src = SinOsc.ar(LFNoise1.ar(6).range(300, 440), 0);
		src = SoundIn.ar(saxInbus);
		src = Limiter.ar(LeakDC.ar(src), -3.dbamp);
		out = Out.ar(outbus1, src);
	}),
	SynthDef(\voiceIn, {arg amp, outbus1;
		var src, out;
		src = SoundIn.ar(voiceInbus);
		src = Limiter.ar(LeakDC.ar(src), -3.dbamp);
		out = Out.ar(outbus1, src);
	}),
	SynthDef(\pianoIn, {arg amp, outbus0 = extraBus0, outbus1 = extraBus1, pianoInbus, buffer;
		var src, out;
		src = SoundIn.ar([pianoInbus]);
		// src = PlayBuf.ar(1, buffer, loop: 1);
		src = Limiter.ar(LeakDC.ar(src), -3.dbamp);
		out = Out.ar(outbus0, src);
		// out = Out.ar(outbus1, src);
	}),
	SynthDef(\pianoIn2, {arg outbus0 = extraBus0;
		var src, out;
		src = SoundIn.ar(pianoInbus);
		out = Out.ar(outbus0, src);
	}),
	SynthDef(\voiceProcess, {arg outbus0, amp;
		var src, out;
		src = SoundIn.ar(voiceInbus);
		out = Out.ar(outbus0, Pan2.ar(src *amp.dbamp, 0));
	}),
	SynthDef(\drumsIn, {arg outbus = extraBus0, buffer, amp = 0;
		var src, env, out;
		// src = PlayBuf.ar(1, buffer, loop: 1);
		src = SoundIn.ar(drumsInbus);
		src = Limiter.ar(LeakDC.ar(src), -3.dbamp);
	out = Out.ar(outbus, src * amp.dbamp)

	}),
	SynthDef(\saxRec, {arg inbus, gate = 1, buffer;
		var recBuf, env, src, chain;
		src = In.ar(inbus);
		recBuf = RecordBuf.ar(src, buffer, loop: 0);
	}),
	SynthDef(\pianoRec, {arg inbus, gate = 1, buffer, fftRecBuf, fftBuf1, hop = 0.25,
		wintype = 1;
		var recBuf, env, src, chain;
		src = In.ar(inbus);
		recBuf = RecordBuf.ar(src, buffer, loop: 0);
		chain = FFT(fftBuf1, src, hop, wintype);
		chain = PV_RecordBuf(chain, fftRecBuf, 0, 1, 0, hop, wintype);
	}),
	SynthDef(\drumsRec, {arg inbus, gate = 1, buffer, fftRecBuf, fftBuf1, hop = 0.25,
		wintype = 1;
		var recBuf, env, src, chain;
		src = In.ar(inbus);
		recBuf = RecordBuf.ar(src, buffer, loop: 0);
	}),
	SynthDef(\voiceRec, {arg inbus, gate = 1, buffer, fftRecBuf, fftBuf1, hop = 0.25,
		wintype = 1;
		var recBuf, env, src, chain;
		src = In.ar(inbus);
		recBuf = RecordBuf.ar(src, buffer, loop: 0);
		// chain = FFT(fftBuf1, src, hop, wintype);
		// chain = PV_RecordBuf(chain, fftRecBuf, 0, 1, 0, hop, wintype);
	}),
	SynthDef(\periodic, {arg outbus, duration, grainFreq, grainPeriod, grainAmp,
		sndBuffer;
		var grains, env, freq, trigger, pan, rate, pos, out, ctrl;
		// env = EnvGen.kr(Env([0, 1, 1, 0], [0.3, 0.4, 0.3], \sin), timeScale: duration);
		// create overlaps
		trigger = Impulse.ar(grainFreq);
		rate = LFNoise2.kr(0.1).range(0.707, 1.3);
		pos = LFNoise1.kr(2).range(0, 1);
		// pan = WhiteNoise.ar * EnvGen.kr(Env([0, 1, 0], [0.5, 0.5], [5, -5]), timeScale: duration);
		grains = GrainBuf.ar(2, trigger, grainPeriod, sndBuffer, rate, pos, 4);
		Out.ar(outbus, grains);
	}),
	SynthDef(\playback2, {arg outbus, buffer, startPos, loop, amp, dur, pan = 0, rate = 1;
		var src, env, out;
		env = EnvGen.kr(Env([0, 1, 0], [0.3, 0.4], \sin, 1), timeScale: dur, levelScale: amp, doneAction: 2);
		src = PlayBuf.ar(1,buffer, rate * BufRateScale.kr(buffer), 1,
			startPos * BufSampleRate.kr(buffer),loop);
		out = Out.ar(outbus, Pan2.ar(src * env, pan))
	}),
	SynthDef(\playback, {arg outbus, buffer, startPos, loop = 0, amp, dur, pan = 0, rate = 1;
		var src, env, out;
		env = EnvGen.kr(Env([0, 1, 1, 0], [0.2, 0.4, 0.2], \sin),
			timeScale: dur,
			levelScale: amp,
			doneAction: 2);
		src = PlayBuf.ar(1, buffer, rate * BufRateScale.kr(buffer), 1,
			startPos * BufSampleRate.kr(buffer), loop);
		out = Out.ar(outbus, Pan2.ar(src * env, pan))
	}),
	SynthDef(\trigWarpNote, {arg outbus, buffer, startPoint, endPoint, dur, freqScale,
		winSize, overlaps, amp, pan = 0;
		var env, envGen, out, point;
		point = EnvGen.kr(Env([startPoint, endPoint], [dur], \lin));
		env = Control.names([\env]).kr(Env.newClear(8));
		envGen = EnvGen.kr(env, timeScale: dur,
			levelScale: amp, doneAction: 2);
		out = WarpZ.ar(1, buffer, point, freqScale, winSize, -1, overlaps, 0.8, 1, 0.1, 0.1);
		Out.ar(outbus, Pan2.ar(out * envGen, pan));
	}),
	SynthDef(\warpNote, {arg outbus, buffer, pan = 0, startPoint, endPoint, dur, freqScale, winSize,
		overlaps, ampEnv;
		var env, out, point, offset;
		offset = 0;
		point = EnvGen.kr(Env([startPoint + offset, endPoint], [dur]));
		//env = EnvGen.kr(Env([0, 0.7, 0.7, 0], [2, 10, 5], \sin));
		out = Warp1.ar(1, buffer, point, freqScale, winSize, -1, overlaps, 0.8);
		Out.ar(outbus, Pan2.ar(out, pan));
	}),
	SynthDef(\fftStretch, {arg outbus, playBuf, fftBuf2, rdBuf, startPoint, start = 0,
		end = 1, modMin, modMax, amp = 1;
		var chain, out, pointer, warp, mix, trig, rate, play;
		pointer = Line.ar(start, end, 60);
		// warp = WarpZ.ar(1, playBuf, pointer, 1, 0.1, -1, 36, 0.2, 4, 0.01, 0.01 );
		// chain = FFT(fftBuf1, play, hop, wintype);
		// chain = PV_RecordBuf(chain, rdBuf, 0, 1, 0, hop, wintype);
		chain = PV_BufRd(fftBuf2, rdBuf, pointer);
		mix = -1;
		out = Out.ar(outbus, IFFT(chain, 1).dup);
		//				out = Out.ar(outbus, warp.dup);
		// out = Balance2.ar(IFFT(chain, 1), warp, mix);
		Out.ar(outbus, out.dup); // send out stereo
	}),
	SynthDef(\pitchShift, {arg inbus, outbus;
		var pitch, out, src, pitchRate;
		src = In.ar(inbus);
		pitchRate = Line.kr(1, 0.92, 8);
		pitch = PitchShift.ar(src, 0.2, pitchRate);
		out = Out.ar(outbus, Pan2.ar(pitch, 0));
	}),
	SynthDef(\trigFun, {arg inbus, trigLevel, trigID = 10;
		var input, amp, ampDelay, diff;
		input = In.ar(inbus, 1);
		// smooth decays a little
		amp = Amplitude.ar(input, 0.01, 0.1).ampdb;
		ampDelay = DelayN.ar(amp, 0.01, 0.01);
		// take the amp now, and the amp 0.01 seconds ago, and find the difference
		// envelope out what will be the first bit of running this
		diff = (amp - ampDelay) * XLine.kr(0.0001, 1, 2);
		// delay diff a little, so catch a better 'amp' reading to send back
		diff = DelayN.ar(diff, 0.05);
		// send the current amp back to look for values above a floor
		SendTrig.ar(diff > trigLevel, trigID, amp);
	}),
	SynthDef(\fftPeakRead, {arg inbus, fftBuf, playBuf, notedur, lpBus,
		hpBus, hop = 0.5, wintype = 0;
		var play, chain, lpOut, hpOut, freq, lpFreq, hpFreq, mag;
		play = SoundIn.ar(inbus);
		// play = In.ar(inbus);
		// play = PlayBuf.ar(1, playBuf, loop: 1);
		chain = FFT(fftBuf, play, hop, wintype);
		# freq , mag = FFTPeak.kr(chain);
		// freq.poll;
		// (freq < 360).if({mag.poll}, {2.postln});
		lpOut = Out.kr(lpBus, freq);
		hpOut = Out.kr(hpBus, freq);
	}),
	SynthDef(\bindel, {arg inbus, fftBuf, delbuf, fbbuf, playBuf, maxDel, notedur, hp, lp;
		var env, play, play1, chain, out, freq, mag;
	    env = EnvGen.kr(Env([0, 1, 1, 0], [0.02, 0.96, 0.02]), timeScale: notedur, doneAction: 2);
		play = SoundIn.ar(inbus);
		// play = In.ar(inbus);
		// play = PlayBuf.ar(1, playBuf, loop: 1);
		chain = FFT(fftBuf, play, 0.5);
		// # freq, mag = FFTPeak.kr(chain);
		chain = PV_MagAbove(chain, 0.1);
		chain = PV_BrickWall(chain, (bandPassFunc.value(hp - 30))/*.poll(2, label: "hi")*/);
		chain = PV_BrickWall(chain, (bandPassFunc.value(lp + 30)-1)/*.poll(2, label: "low")*/);
		//chain, maxDel, delbuf, fbbuf, overlaps
		chain = PV_BinDelay(chain, maxDel, delbuf, fbbuf, 0.5);
		chain = IFFT(chain);
		out = Out.ar(0, Pan2.ar(chain * env, 0));
	}),
	SynthDef(\bufwrite, {arg maxDel, bin, delbuf, fbbuf, notedur;
		var feedback, freq, maxDelay, env;
		env = EnvGen.kr(Env([0, 1, 0], [0.1, 0.8, 0.1], \sin), timeScale: notedur, doneAction: 2);
	// freq = In.kr(inbus);
	// feedback = LinLin.kr(freq, 200, 1000, 0.3, 0.9);
		// freq.poll(2, label: "freq");
		// feedback.poll(2, label: "feedback");
	// maxDelay = LinLin.kr(freq, 200, 1000, maxDel, 0.2).clip(0.2, maxDel);
	// maxDelay.poll(2, label: "maxDelay");
	// first - write out delay values
		BufWr.kr(
			0.2,
			delbuf,
			bin);
	// for feedback values - do a similar thing, but modulate the bounds of the range
		BufWr.kr(
			LFNoise1.kr(0.2).range(0.1, 0.2),
			fbbuf,
			bin);
	}),
	SynthDef(\fftTrigFun, {arg inbus, trigLevel, fftBuf, trigID = 8;
		var input, spec, specDelay, diff, chain;
		input = SoundIn.ar(inbus);
		// input = In.ar(inbus);
		// smooth decays a little
	    chain = FFT(fftBuf, input, 0.25, 1);
	    spec = SpecFlatness.kr(chain).poll;
		specDelay = DelayN.ar(K2A.ar(spec), 0.01, 0.01);
		// take the amp now, and the amp 0.01 seconds ago, and find the difference
		// envelope out what will be the first bit of running this
		diff = (spec - specDelay) * XLine.kr(0.0001, 1, 2);
		// delay diff a little, so catch a better 'amp' reading to send back
		diff = DelayN.ar(diff, 0.05);
		// send the current amp back to look for values above a floor
		SendTrig.ar(diff < trigLevel, trigID, spec);
	}),
	SynthDef(\fftStretchTrig, {arg inbus, trigLevel, trigID = 9;
		var input, amp, ampDelay, diff;
		input = SoundIn.ar(inbus, 1);
		// smooth decays a little
		amp = Amplitude.ar(input, 0.01, 0.1).ampdb;
		amp.poll;
		ampDelay = DelayN.ar(amp, 0.01, 0.01);
		// take the amp now, and the amp 0.01 seconds ago, and find the difference
		// envelope out what will be the first bit of running this
		diff = (amp - ampDelay) * XLine.kr(0.0001, 1, 2);
		// delay diff a little, so catch a better 'amp' reading to send back
		diff = DelayN.ar(diff, 0.05);
		// send the current amp back to look for values above a floor
		SendTrig.ar(diff > trigLevel, trigID, amp);
	});
);

s.boot;

Routine.run({
	var cond;
	cond = Condition.new;
	s.waitForBoot({

		fftHop = 0.25;
		fftWinsize = 2048;
		fftBufRdSize = 60.calcPVRecSize(fftWinsize, fftHop, s.sampleRate);
		//
		// grainBuf1 = CtkBuffer.buffer(s.sampleRate, 1, s),
		// grainBuf2 = CtkBuffer.buffer(s.sampleRate, 1, s);

		// saxBuf = CtkBuffer.buffer((bufTime) * s.sampleRate, 1, s).load;
		testBuffer = CtkBuffer.new("/Users/Ivan/Documents/New Ensemble/Processing Assets/Output 1-22.wav").load;
		// testBuffer.load;
		grainBuf = CtkBuffer.buffer(120 * s.sampleRate, 1, s).load;
		fftBufA = CtkBuffer.buffer(4096).load;
		fftBufB = CtkBuffer.buffer(4096).load;
		fftBufC = CtkBuffer.buffer(2048).load;
		fftPeakBuf = CtkBuffer.buffer(2048).load;
		fftBufRd = CtkBuffer.buffer(fftBufRdSize).load;
		pianoBuf = CtkBuffer.buffer((pianoBufTime) * s.sampleRate, 1, s).load;
		drumsBuf = CtkBuffer.buffer((4 *60) * s.sampleRate, 1, s).load;
		voiceSaxWarpBuf = CtkBuffer.buffer((warpBufTime * s.sampleRate), 1, s).load;
		trigFftBuf = CtkBuffer.buffer(512).load;
		delTimeBuf = CtkBuffer.buffer(256).load;
		fbBuf = CtkBuffer.buffer(256).load;

		testbus = CtkAudio.new(server: s);
		routebus0 = CtkAudio.new(server: s);
		routebus1 = CtkAudio.new(server: s);
		routebus2 = CtkAudio.new(server: s);
		routebus3 = CtkAudio.new(server: s);
		drumsbus = CtkAudio.new(server: s);
		pianobus = CtkAudio.new(server: s);
		voicebus = CtkAudio.new(server: s);
		voiceSaxbus = CtkAudio.new(server: s);
		saxbus = CtkAudio.new(server: s);
		p1Route = CtkAudio.new(server: s);
		extraBus0 = CtkAudio.new(server: s);
		extraBus1 = CtkAudio.new(server: s);
		extraBus2 = CtkAudio.new(server: s);

		//create array of Booleans to use for toggling (array instead of three different
		procBoolean = Array.newClear(3);
		//init values - put false (== "proc is off by default")
		procBoolean.size.do({arg inc;
			procBoolean[inc] = false;
		});
		peakControlLP = CtkControl.play;
		peakControlHP = CtkControl.play;
		ampControlVoice = CtkControl.play;
		ampControlPiano = CtkControl.play;
		ampControlDrums = CtkControl.play;
		ampControlVoice.set(0);
		ampControlPiano.set(0);
		ampControlDrums.set(0);
		pianoTrigEnv1 = Env([0, 1, 0.9, 0], [0.005, 0.1, 0.895], [\sin, 3, -3]);
		pianoTrigEnv2 = Env([0.001, 1, 0.001], [0.005, 0.995], [\sin, -5]);
		pianoTrigEnv3 = Env([0, 1, 0.05, 0.05, 0], [0.005, 0.445, 0.25, 0.3], [10, -8, \lin, -2]);

		MIDIClient.init;
		MIDIIn.connect(0, 0);
		MIDIIn.connect(0, 2);
		midiMixerFunction = {arg src, chan, num, val;
			[src, num, val].postln;
			switch(num,
				10, {ampControlVoice.set(((val/127)).postln)}, {nil},
				11, {ampControlPiano.set(((val/127)).postln)}, {nil},
				12, {ampControlDrums.set(((val/127)).postln)}, {nil}
		)};

		midiFunction = { arg src, chan, num, vel;
			switch(num,
				60, {procBoolean[0].if({
					pianoTrigWarpFunc.release;
					procBoolean[0] = false;
					"button 1 - OFF".postln;
					}, {
						pianoTrigWarpFunc.play;
						procBoolean[0] = true;
						"button 1 - ON".postln;
					});
				},
				62, {
					procBoolean[1].if({
						warpMomentManyFunc.release;
						procBoolean[1] = false;
						"button 2 - OFF".postln;
						}, {
							warpMomentManyFunc.play;
							procBoolean[1] = true;
							"button 2 - ON".postln;
					});
				},
				64, {
					procBoolean[2].if({
						drumLoopProc2Func.release;
						procBoolean[2] = false;
						"button 3 - OFF".postln;
						}, {
							drumLoopProc2Func.play;
							procBoolean[2] = true;
							"button 3 - ON".postln;
					});
				},
			)
		};

		s.sync(cond);
		"buffers loaded".postln;

		/* ProcMods */

		initMod = ProcMod.new.function_({arg group, routebus;
			Routine({
				var rate;
				rate = 1;
				MIDIIn.addFuncTo(\noteOn, midiFunction);
				MIDIIn.addFuncTo(\control, midiMixerFunction);
				// init1 = notes[\saxIn].note(target: 0).amp_(ampControlDrums)
				// .outbus0_(0).outbus1_(routebus0).play;
				// init2 = notes[\voiceIn].note(target: 0).amp_(0).outbus0_(0).play;
				// init3 = notes[\pianoIn].note(target: 0).amp_(ampControlPiano).outbus0_(0).play;
				"started".postln;});
		});

		killMod = ProcMod.new.function_({

			// init1.release;
				// init2.free;
				// init3.release;
			MIDIIn.removeFuncFrom(\noteOn, midiFunction);
			MIDIIn.removeFuncFrom(\control, midiMixerFunction);
			MIDIClient.reset;
			MIDIIn.disconnect;

				[testBuffer, grainBuf, fftBufA, fftBufB, fftBufC, fftBufRd,
				pianoBuf, drumsBuf, voiceSaxWarpBuf, trigFftBuf, delTimeBuf, fbBuf, fftPeakBuf,
				routebus0, routebus1,routebus2, drumsbus, pianobus, voicebus, voiceSaxbus, saxbus,
				p1Route, extraBus0, extraBus1, extraBus2, peakControlLP, peakControlHP,
				ampControlDrums, ampControlPiano, ampControlVoice].do({arg me;
					me.free;
				});
			"Kill runs".postln;
		});

		granular = {arg id, amp, env;
			var proc;
			proc = ProcModR.new(env, amp, 2, 0, id: id);
			proc.function_({arg group, routebus, server;
				var task;
				task = Routine({
					var start, end;
					start = 0;
					notes[\periodic].note(target: group, addAction: \head).outbus_(routebus)
					.grainFreq_(50).grainPeriod_(0.2)
					.grainAmp_(-12.dbamp).sndBuffer_(testBuffer).play;
				});
			task;
			});
		};

		playback = {arg id, amp, env, writebus;
			var proc;
			proc = ProcModR.new(env, amp, 2, 0, id: id);
			proc.function_({arg group, routebus, server;
				var task;
				task = Routine({
					notes[\playback2].note(target: group).outbus_(writebus).buffer_(testBuffer)
					.startPos_(0).loop_(1).amp_(0.dbamp).play;
				})
			})
		};

		fftStretch = {arg id, amp, env, duration, trigLevel, noiseFloor, writebus;
			var proc;
			proc = ProcModR.new(env, amp, 2, 0, id:id);
			proc.function_({arg group, routebus, server, pm;
				var task;
				task = Routine({
					var lastTrig;
					notes[\testFFT].note(target: group, addAction: \head)
					.fftBuf1_(fftBufA)
					.fftRecBuf_(fftBufRd).play;
					lastTrig = 0;
					notes[\fftStretchTrig].note(target: group, addAction: \tail)
					.inbus_(0).trigLevel_(trigLevel).play;
					0.5.wait;
					proc.responder_(OSCresponderNode(nil, \tr2,{arg time, resp, msg;
						var start, end;
						msg.postln;
						(msg[2] == 9).if({
							(msg[3] > noiseFloor).if({
								((Main.elapsedTime - lastTrig) > 0.2).if({
									start = pm.now;
									start.postln;
									end = (start + duration) * rFFTBufTime;
									start = start * rFFTBufTime;
									lastTrig = Main.elapsedTime;
									notes[\fftStretch].note(target: group, addAction: \tail)
									.playBuf_(testBuffer)
									.outbus_(writebus)
									.fftBuf2_(fftBufB)
									.rdBuf_(fftBufRd)
									.start_(start)
									.end_(end).play;
									notes[\pitchShift].note(target: group, addAction: \tail)
									.inbus_(writebus).outbus_(routebus).play;
									task;
									});
								});
							});
					}));
				});
				task;
			});
			proc;
		};

		evanLoopProc = {arg id, amp, env, rate = 1, delayLow = 0,
			delayHigh = 0, durLow = 1, durHigh = 2, numProcs = 1, waitBetweenMods, length = 30, offset = 0;
				var proc;
				proc = ProcModR.new(env, amp, 2, 0, id: id);
				proc.function_({arg group, routebus, server, pm;
				Task({
					notes[\drumsIn].note(addAction: \head, target: group)
					.outbus_(drumsbus).play;
					notes[\drumsRec].note(addAction: \tail, target: group)
					.inbus_(drumsbus)
					.buffer_(drumsBuf).play;
					3.wait;
					inf.do({arg i;
						numProcs.do({
							var dur, start, now, pos, delay;
							delay = rrand(delayLow, delayHigh);
							dur = rrand(durLow, durHigh);
							"dur:".postln;
							dur.postln;
							start = 0;
							now = pm.now;
							"now".postln;
							now.postln;
							(now <= length).if({
								pos = rrand(start, now)}, {pos = rrand(pm.now - length, pm.now)});
							"pos:".postln;
							pos.postln;
							notes[\playback].note(addAction: \tail, target: group)
							.outbus_(routebus)
							.buffer_(drumsBuf)
							.startPos_(pos)
							.loop_(0)
							.dur_(dur)
							.amp_(amp)
							.rate_((rate == 1).if({rate}, {CtkControl.lfo(LFNoise2, 0.5, rate, 1)})).play;
							delay.wait;
						});
						waitBetweenMods.wait;
					});
				});
			});
proc;
};

		drumLoopProc2 = {arg id, amp, env, rate = 1, offset = 0, writebus = 0;
			var proc;
			proc = ProcModR.new(env, amp, 2, writebus, id: id);
			proc.function_({arg group, routebus, server, pm;
				Routine({
					notes[\drumsIn].note(addAction: \head, target: group)
					.outbus_(drumsbus).play;
					notes[\pianoIn].note(addAction: \head, target: group).outbus0_(drumsbus).play;
					notes[\drumsRec].note(addAction: \tail, target: group)
					.inbus_(drumsbus)
					.buffer_(drumsBuf)
					.fftRecBuf_(fftBufRd)
					.hop_(fftHop)
					.wintype_(1)
					.fftBuf1_(fftBufA).play;
					0.1.wait;
					inf.do({arg i;
						var start, now, pos, dur;
						dur = rrand(5, 7);
						start = 0;
						now = pm.now;
						"now is: ".post;
						now.postln;
						(now <= 30).if({
							pos = rrand(start, now)}, {pos = rrand(start, 30)});
						"pos is: ".post;
						pos.postln;
						notes[\playback2].note(duration: dur, addAction: \tail, target: group)
						.buffer_(drumsBuf)
						.outbus_(routebus)
						.startPos_(pos)
						.loop_(1)
						.amp_(amp)
						.pan_(rrand(-0.6, 0.6))
						.rate_((rate == 1).if({rate}, {CtkControl.lfo(LFNoise2, 0.5, rate, 1)})).play;
						rrand(0.5, 2).wait;
					})
				});
				Routine({
					notes[\drumsIn].note(addAction: \head, target: group)
					.outbus_(drumsbus).play;
					notes[\drumsRec].note(addAction: \tail, target: group)
					.inbus_(drumsbus)
					.buffer_(drumsBuf)
					.fftRecBuf_(fftBufRd)
					.hop_(fftHop)
					.wintype_(1)
					.fftBuf1_(fftBufA).play;
					0.1.wait;
					inf.do({arg i;
						var start, now, pos, dur;
						dur = rrand(5, 7);
						start = 0;
						now = pm.now;
						"now is: ".post;
						now.postln;
						(now <= 30).if({
						pos = rrand(start, now)}, {pos = rrand(start, 30)});
						"pos is: ".post;
						pos.postln;
						notes[\playback2].note(duration: dur, addAction: \tail, target: group)
						.buffer_(drumsBuf)
						.outbus_(routebus)
						.startPos_(pos)
						.loop_(1)
						.amp_(amp)
						.pan_(rrand(-0.6, 0.6))
						.rate_((rate == 1).if({rate}, {CtkControl.lfo(LFNoise2, 0.5, rate, 1)})).play;
						rrand(0.5, 2).wait;
					})
				})
			});
			proc;
		};

		cymbalTrigDelay = {arg id, amp, env, trigLevel, specCeiling = 0.1, dur, panMin = -0.6, panMax = 0.6; //pevent id
			var proc;
			proc = ProcModR.new(env, amp, 2, 0, id: id);
			proc.function_({ arg group, routebus, server, pm;
				var task;
				task = Routine({
					var lastTrig, init;
					notes[\drumsIn].note(addAction:\head, target: group)
					.outbus0_(drumsbus).buffer_(testBuffer).play;
					// notes[\drumsRec].note(addAction:\tail, target: group)
					// .inbus_(drumsbus)
					// .buffer_(drumsBuf)
					// .fftRecBuf_(fftBufRd)
					// .hop_(fftHop)
					// .wintype_(1)
					// .fftBuf1_(fftBufA).play;
					init = Main.elapsedTime;
					lastTrig = 0.0; // will hold the last time triggered
					notes[\fftTrigFun].note(addAction:\tail, target: group)
					.fftBuf_(fftBufC).inbus_(drumsInbus).
					trigLevel_(trigLevel).play;
			        notes[\fftPeakRead].note(addAction: \head, target: group).inbus_(drumsInbus)
					                .fftBuf_(fftPeakBuf).lpBus_(peakControlLP)
					                .hpBus_(peakControlHP).play;
					0.5.wait;
					proc.responder_(OSCresponderNode(nil, '/tr', {arg time, resp, msg;
						var timeTrack;
						msg.postln;
						(msg[2] == 8).if({
							// look above a certain noise floor
							(msg[3] < specCeiling).if({
								// only trigger if last trigger was at least 1 seconds ago
								((Main.elapsedTime - lastTrig) > 1).if({
									lastTrig = Main.elapsedTime;
						            notes[\bindel].note(addAction: \tail, target: group)
						            .inbus_(drumsInbus)
									.fftBuf_(trigFftBuf)
									.delbuf_(delTimeBuf)
						            .fbbuf_(fbBuf)
									.maxDel_(maxDel)
						            .hp_(peakControlHP)
									.lp_(peakControlLP)
									.notedur_(dur).play;
									msg.postln;
						            256.do({arg thisBin;
					               	notes[\bufwrite].note(addAction: \head, target: group)
								    .maxDel_(maxDel)
						            .bin_(thisBin).delbuf_(delTimeBuf).fbbuf_(fbBuf).play;
									});
								})
							});
						});
					}));
				});
				task;
			});
			proc;
		};

		pianoTrigWarp = {arg id, amp, env, trigLevel, noiseFloor, warpRangeMin, warpRangeMax, durMin, durMax, envIn, freq = 0, panMin = -0.6, panMax = 0.6; //pevent id
			var proc;
			proc = ProcModR.new(env, amp, 2, 0, id: id);
			proc.function_({ arg group, routebus, server, pm;
				var task;
				task = Routine({
					var lastTrig, init;
					notes[\pianoIn].note(addAction:\head, target: group).outbus0_(pianobus).buffer_(testBuffer).play;
					notes[\pianoRec].note(addAction:\tail, target: group)
					.inbus_(pianobus)
					.buffer_(pianoBuf)
					.fftRecBuf_(fftBufRd)
					.hop_(fftHop)
					.wintype_(1)
					.fftBuf1_(fftBufA).play;
					init = Main.elapsedTime;
					lastTrig = 0.0; // will hold the last time triggered
					notes[\trigFun].note(addAction:\tail, target: group).inbus_(pianobus).
					trigLevel_(trigLevel).play;
					0.5.wait;
					proc.responder_(OSCresponderNode(nil, '/tr', {arg time, resp, msg;
						var start, end, dur, timeTrack;
						msg.postln;
						(msg[2] == 10).if({
							// look above a certain noise floor
							(msg[3] > noiseFloor).if({
								// only trigger if last trigger was at least 1 seconds ago
								((Main.elapsedTime - lastTrig) > 1).if({
									timeTrack = time - init;
									timeTrack.postln;
									start = pm.now - 0.05;
									start.postln;
									end = (start + rrand(warpRangeMin, warpRangeMax)) * rPianoBufTime;
									start = start * rPianoBufTime;
									durMin.isKindOf(Env).if({
										dur = Tendency(durMin, durMax);
										dur = dur.at(timeTrack).postln},
										{dur = exprand(durMin, durMax)});
									lastTrig = Main.elapsedTime;
									notes[\trigWarpNote].note(addAction: \tail, target: group)
									.outbus_(routebus)
									.buffer_(pianoBuf)
									.startPoint_(start)
									.endPoint_(end)
									.freqScale_((freq == 0).if({1},
										{CtkControl.lfo(
											LFNoise1, 3, CtkControl.env(
												Env([1, 0.986], [dur - 8], \lin)),
												CtkControl.env(Env([1, 1.015], [dur -8], \lin)))}))
									.winSize_(0.1)
									.amp_(amp)
									.overlaps_(46)
									.pan_(rrand(panMin, panMax))
									.env_(envIn)
									.dur_(dur.isKindOf(Env).if({CtkControl.env(dur)}, {dur})).play;
									msg.postln;
								})
							});
						});
					}));
				});
				task;
			});
			proc;
		};
		warpMoment = {arg id, amp, env, startPoint, scale, window, overlaps, dur, endAdd = 4, offset = 0;
			var proc;
			proc = ProcModR.new(env, amp, 2, 0, id: id);
			proc.function_({ arg group, routebus, server;
				Task({
					var start, end;
					"Warping".postln;
					start = startPoint;
					end = (start + endAdd) * rWarpBufTime;
					start = start;
					notes[\saxIn].note(addAction: \head, target: group).outbus1_(voiceSaxbus).play;
					notes[\voiceIn].note(addAction: \head, target: group).outbus1_(voiceSaxbus).play;
					notes[\voiceRec].note(addAction: \tail, target: group).inbus_(voiceSaxbus)
					.buffer_(voiceSaxWarpBuf).play;
					notes[\warpNote].note(starttime: 0.25, addAction: \tail, target: group)
					.outbus_(routebus).buffer_(voiceSaxWarpBuf)
					.startPoint_(start)
					.endPoint_(end)
					.freqScale_(scale)
					.winSize_(window)
					.overlaps_(overlaps)
					.dur_(dur).play;
				});
			});
		};

		psink = ProcSink(\KromerImprov);
		//
		// pianoTrigWarpFunc = pianoTrigWarp.value(\pianoTrigWarp, -8.dbamp, Env([0, 1, 0], [0.1, 8], \sin, 1),
		// 	trigLevel: 3,
		// 	noiseFloor: -52,
		// 	warpRangeMin: 0.2,
		// 	warpRangeMax: 0.7,
		// 	durMin: 9,
		// 	durMax: 38
		// );
		// drumLoopProc2Func = drumLoopProc2.value(\drumLoopProc2, 6.dbamp, Env([0, 1, 0], [24, 24], \sin, 1));
		warpMomentManyFunc = warpMoment.value(\voiceSaxWarp, -2.dbamp, Env([0, 1, 0.3, 0.1, 0],
			[0.2, 0.5, 0.2, 0.1] * 6,[\sin, -3, \sin, -2]),
			startPoint: 0,
			scale: 1,
			window: 0.2,
			overlaps: 34,
			dur: 7,
			endAdd: rrand(1.5, 3)
		);
		psink.add(cymbalTrigDelay.value(\cymbalTrig, 0.dbamp, Env([0, 1, 0], [1, 1], \sin, 1),
			trigLevel: -0.06,
			noiseFloor: 0,
			specCeiling: 0.65,
			dur: 3
		));
		test = playback.value(\tester, 0.dbamp, Env([0, 1, 0], [1, 1], \sin), testbus);
		//
		// fftStretchFunc = fftStretch.value(\stretch, -3.dbamp, Env([0, 1, 0], [1, 10], \sin, 1),
		// 30, extraBus1);
		//
		// psink.add(fftStretchFunc);
		// psink.add(drumLoopProc2Func);
		psink.add(warpMomentManyFunc);
		psink.add(test);
		// psink.add(pianoTrigWarpFunc);

		pevents = ProcEvents.new([

	/* 0 */ [
				nil, nil
			],

	/* 1 */
			[
				warpMoment.value(\voiceSaxWarp, -8.dbamp, Env([0, 1, 0.3, 0.1, 0],
					[5, 10, 7, 7], [\sin, -3, \sin, -2]),
					startPoint: 0,
					scale: 1,
					window: 0.2,
					overlaps: 34,
					dur: 29,
					endAdd: 5), nil
			],
	/* 2 */
			[
				nil, \voiceSaxWarp
			],
			[
				evanLoopProc.value(\evanLoop1, 6.dbamp, Env([0, 1, 1.3, 0], [24, 4.5, 1],
				[3, 7, -4], 1),
					durLow: 4,
					durHigh: 7,
					delayLow: 1.0,
					delayHigh: 2.0,
					numProcs: 9,
					waitBetweenMods: 0,
					length: 25
				), nil
			],
			[
				nil, \evanLoop1
			],

			/*[
				evanLoopProc.value(\evanLoop2, -3.dbamp, Env([0, 1, 1.3, 0], [24, 4, 1], [2, 7, -4], 1),
					durLow: 4,
					durHigh: 7,
					delayLow: 1.0,
					delayHigh: 2.0,
					numProcs: 8,
					waitBetweenMods: 0,
					length: 25
				), \evanLoop1
			],
			[
				nil, \evanLoop2
			],*/
	/* 3 */
			/*[ drumLoopProc2.value(\drumLoopProc2, -6.dbamp, Env([0, 1, 1, 0], [24, 20, 40],
				[3, -5, -5], 1)), nil
			],
	/* 4 */
			[

					[drumLoopProc2.value(\drumLoopProc4, 1.dbamp, Env([0, 0.9, 1, 0], [30, 4, 1],
						[3, 5, -5], 1)), drumLoopProc2.value(\drumLoopProc3, -2.dbamp, Env([0, 0.9, 1, 0], [30, 4, 1],
					[3, 5, -5], 1))], \drumLoopProc2
			],
	/* 5 */
			[
				nil, [\drumLoopProc4, \drumLoopProc3]
			],*/
	/* 5*/
			[
				pianoTrigWarp.value(\pianoTrigWarp, -14.dbamp, Env([0, 1, 0], [0.1, 4],
					\sin, 1),
					trigLevel: 4,
					noiseFloor: -48,
					warpRangeMin: 0.2,
					warpRangeMax: 0.7,
					durMin: 5,
					durMax: 11,
					envIn: pianoTrigEnv1
				), nil
			],
	/* 6 */
			[
				pianoTrigWarp.value(\pianoTrigWarp2, -14.dbamp, Env([0, 1, 0], [0.1, 3],
					\sin, 1),
					trigLevel: 4,
					noiseFloor: -48,
					warpRangeMin: 0.1,
					warpRangeMax: 0.7,
					durMin: 10,
					durMax: 18,
					envIn: pianoTrigEnv2
				), \pianoTrigWarp,
			],
	/* 7 */
			[
				pianoTrigWarp.value(\pianoTrigWarp3, -14.dbamp, Env([0, 1, 0], [0.1, 3],
					\sin, 1),
					trigLevel: 4,
					noiseFloor: -48,
					warpRangeMin: 0.1,
					warpRangeMax: 0.7,
					durMin: 29,
					durMax: 29,
					envIn: pianoTrigEnv3,
					freq: 1
				), \pianoTrigWarp2
			]
		], 0.dbamp, initMod, killMod, id: \test);

		pevents.perfGUI;
		// pevents.pracGUI;
		pevents.pedalTrig(s.options.numOutputBusChannels + 7);

	});

});
)
s.makeGui;

Env([0, 1, 0.25, 0.2, 0], [0.005, 0.255, 0.3, 0.4], [10, -7, 2, -2]).plot;

Env([0, 1, 0.35, 0.3, 0.05, 0], [0.005, 0.355, 0.2, 0.15, 0.25], [10, -7, \lin, -2, -1]).plot;