(
//busses
~masterBus = Bus.audio(s, 1);
~guitarBus = Bus.audio(s, 1);
~accompHighBus = Bus.audio(s, 1);
~accompLowLowerBusA = Bus.audio(s, 1);
~accompLowUpperBusA = Bus.audio(s, 1);
~accompLowLowerBusB = Bus.audio(s, 1);
~accompLowUpperBusB = Bus.audio(s, 1);
~interludeTremoloBus = Bus.audio(s, 1);

SynthDef(\masterPlayerControl ++ ~hash, {
	arg sel = 0,
	masterVol = 1, masterMute = 1,
	guitarVol = 1, guitarPan = 0, guitarMute = 1,
	accompHighVol = 1, accompHighPan = 0, accompHighMute = 1,
	accompLowLowerVol = 1, accompLowLowerPan = 0, accompLowLowerMute = 1,
	accompLowUpperVol = 1, accompLowUpperPan = 0, accompLowUpperMute = 1,
	interludeVol = 1, interludePan = 0, interludeMute = 1;
	var guitarSig, accompHighSig, accompLowLowerSig, accompLowUpperSig, interludeSig,
	guitarSigPanned, accompHighSigPanned, accompLowLowerSigPanned, accompLowUpperSigPanned, interludeSigPanned,
	masterSig, imp;

	guitarSig = In.ar(~guitarBus) * guitarVol;
	accompHighSig = In.ar(~accompHighBus) * accompHighVol;
	accompLowLowerSig = Mix.ar(
		[
			In.ar(~accompLowLowerBusA) * EnvGen.kr(Env.asr(0.001, 1, 0.1), (sel + 1) % 2),
			In.ar(~accompLowLowerBusB) * EnvGen.kr(Env.asr(0.001, 1, 0.1), sel)
		]
	) * accompLowLowerVol;
	accompLowUpperSig = Mix.ar(
		[
			In.ar(~accompLowUpperBusA) * EnvGen.kr(Env.asr(0.001, 1, 0.1), (sel + 1) % 2),
			In.ar(~accompLowUpperBusB) * EnvGen.kr(Env.asr(0.001, 1, 0.1), sel)
		]
	) * accompLowUpperVol;
	interludeSig = In.ar(~interludeTremoloBus) * interludeVol;

	guitarSigPanned = Pan2.ar(guitarSig * guitarMute, guitarPan);
	accompHighSigPanned = Pan2.ar(accompHighSig * accompHighMute, accompHighPan);
	accompLowLowerSigPanned = Pan2.ar(accompLowLowerSig * accompLowLowerMute, accompLowLowerPan);
	accompLowUpperSigPanned = Pan2.ar(accompLowUpperSig * accompLowUpperMute, accompLowUpperPan);
	interludeSigPanned = Pan2.ar(interludeSig * interludeMute, interludePan);
	masterSig = Mix.ar(
		[
			guitarSigPanned,
			accompHighSigPanned,
			accompLowLowerSigPanned,
			accompLowUpperSigPanned,
			interludeSigPanned
		]) * masterVol * masterMute;

	Out.ar(0, masterSig);

	imp = Impulse.kr(10);
	SendReply.kr(imp,
		'/masterLevels' ++ ~hash,
		values: [Amplitude.kr(masterSig)]);
	SendReply.kr(imp,
		'/trackLevels' ++ ~hash,
		values:
		[
			Amplitude.kr(guitarSig), Amplitude.kr(accompHighSig),
			Amplitude.kr(accompLowLowerSig), Amplitude.kr(accompLowUpperSig),
			Amplitude.kr(interludeSig)
		]
	);
}).add;


SynthDef(\transport ++ ~hash, {arg measure = 0, beat = 0, gate = 1, dur = 1;
	SendReply.kr(Impulse.kr(0) * (measure > 0) * (beat > 0),'/measureClock' ++ ~hash, values: [measure, beat]);
	SendReply.kr(Impulse.kr(0) * (measure < 1) * (beat < 1),'/nextSubsection' ++ ~hash);
	EnvGen.kr(Env.sine(dur), gate, doneAction: 2);
}).add;


//~~~~karplus
SynthDef(\karplus ++ ~hash, {arg freq, gate = 1, amp = 0.5, bus;
	Out.ar(bus,
		Pluck.ar(WhiteNoise.ar(0.1), Impulse.kr(0), 220.reciprocal, freq.reciprocal, 10, coef:0) *
		Linen.kr(gate, doneAction: 2) * amp)
}).add;


//~~~~accompaniment
SynthDef(\accompBass ++ ~hash, {arg freq1 = 100, freq2 = 100, gate = 1, amp = 0.5, busLower, busUpper, cutoff = 0;
	var env, lower, upper;
	env = EnvGen.kr(Env.perc(0.1, 10, level: amp), Impulse.kr(0) + Changed.kr(freq2));
	lower = SinOsc.ar(freq1, 0, 0.5) * env;
	upper = SinOsc.ar(freq2, 0, 0.5) * env;
	Out.ar(busLower, lower);
	Out.ar(busUpper, upper)
}).add;


//this is not releasing properly
SynthDef(\accompTreble ++ ~hash, {arg freq, gate = 1, sustain, amp, bus;
	var treble;
	treble = SinOsc.ar(freq, 0, EnvGen.kr(Env.sine(sustain, amp * 0.1), gate, doneAction: 2));
	Out.ar(bus, treble)
}).add;

SynthDef(\interludeTremelo ++ ~hash, { arg gate = 0, amp = 1;
	var tremeloTrig, freq, sig, feedback, fade;
	//fast tremelo - note that this can be slower so long as the delaytime of the feedback remains short
	tremeloTrig = Impulse.kr(50);
	//tremelo between two notes
	freq = Select.kr(Stepper.kr(tremeloTrig, 0, 0, 1), [62.midicps, 62.midicps * 5/6]);
	//occasionally tremelo on same note
	freq = Select.kr(TWChoose.kr(Dust.kr(10), [0, 1, 2], [5, 1, 1], 1), [freq, 62.midicps, 62.midicps * 5/6]) / 2;
	//generate signal
	sig = VarSaw.ar(freq,  0, 0.3, 0.1) * EnvGen.kr(Env.perc(0.01, 0.1), tremeloTrig);
	//feedback
	feedback = CombC.ar(sig, 0.2, 50.reciprocal, 5);
	fade = feedback * EnvGen.ar(Env.asr(20, 1, 20), gate) * amp;
	Out.ar(~interludeTremoloBus, fade);
}).add;

//~~~~gen music
~genPatterns = {arg guitarSeqIn, accompLowSeqIn, accompHighSeqIn, sectionSeqIn, beatFrac = 1/8;
	var calcSustains, genSectionSec, sectionLimits, measureCount;

	//~~~~helper sus function
	calcSustains = {arg stringSeq, durSeq;
		var res = [];
		stringSeq.size.do({arg index;
			var curString, dur, count;
			if(stringSeq[index].isRest.not, {
				curString = stringSeq[index];
				dur = durSeq[index];
				count = 1;
				while({(stringSeq[(index + count).clip(0, stringSeq.size - 1)] != curString) &&
					(dur < 16) && (count < 100)}, {
					dur = dur + durSeq[(index + count).clip(0, durSeq.size - 1)];
					count = count + 1;
				});
				res = res.add(dur.clip(0, 16));
			}, {
				res.add(Rest());
			});
		});
		res
	};

	genSectionSec = {arg seq, startTime, endTime, type;
		var durSum, resSeqs, inSecs, mult;
		durSum = 0;
		resSeqs = [];
		seq.do({arg item;
			if((durSum >= startTime) && (durSum < endTime), {
				var dur = durSum - startTime;
				if((resSeqs.size == 0) && (dur > 0), {
					switch(type,
						0, {resSeqs = resSeqs.add([Rest(-1), Rest(-1), dur])},
						1, {resSeqs = resSeqs.add([Rest(-1), Rest(-1), dur])},
						2, {resSeqs = resSeqs.add([Rest(-1), dur, dur])})
				});
				resSeqs = resSeqs.add(item);
			});
			durSum = durSum + if(type == 2, {item[1]}, {item[2]});
		});
		resSeqs
	};

	measureCount = 0;
	sectionLimits = [];
	sectionSeqIn.slice(nil, 0).add(100000).doAdjacentPairs({arg a, b; sectionLimits = sectionLimits.add([a, b])});
	~sectionStartMeasure = [];
	sectionLimits.collect({arg timePair, secIndex;
		var startTime, endTime, beatLength, beatSeq, measureSeq,
		guitarSecSeq, accompLowSecSeq, accompHighSecSeq,
		stringSeq, fretSeq, durSeq, susSeq, trigSeq, openStrings, pattern;

		startTime = timePair[0];
		endTime = timePair[1];

		if((secIndex % 4) == 0, {measureCount = 0});
		beatLength = (endTime - startTime) / 8;
		beatSeq = ((beatLength / 2) - 1).asInteger.collect({[1, 2]});
		beatSeq = if((beatLength % 2) == 0, {beatSeq.add([1, 2])}, {beatSeq.add([1, 2, 3])});
		measureSeq = measureCount + beatSeq.collect({arg measure, mIndex; measure.collect({mIndex + 1})}).flat;
		~sectionStartMeasure = ~sectionStartMeasure.add(measureCount + 1);
		measureCount = measureSeq.last;
		beatSeq = beatSeq.flat;
		measureSeq = measureSeq.add(0);
		beatSeq = beatSeq.add(0);

		guitarSecSeq = genSectionSec.value(guitarSeqIn, startTime, endTime, 0);
		accompLowSecSeq = genSectionSec.value(accompLowSeqIn, startTime, endTime, 1);
		accompHighSecSeq = genSectionSec.value(accompHighSeqIn, startTime, endTime, 2);

		if(accompHighSecSeq == [], {accompHighSecSeq = [[Rest(-1), 1, 0], [Rest(-1), 1, 0]]});

		openStrings = [1/1, 3/2, 2/1, 5/2, 35/12, 7/2];
		stringSeq = guitarSecSeq.slice(nil, 0);
		fretSeq = guitarSecSeq.slice(nil, 1);
		durSeq = guitarSecSeq.slice(nil, 2);
		susSeq = calcSustains.value(stringSeq, durSeq);

		pattern = EventPatternProxy.new;
		pattern.source = Ppar([
			Pbind(
				\instrument, \karplus ++ ~hash,
				\amp, 0.3,
				\dur, Pseq(durSeq * beatFrac),
				\sustain, Pseq(susSeq * beatFrac),
				\freq, Pseq(stringSeq.collect({arg string, index;
					if(string.isRest, {Rest()}, {
						((62.midicps * openStrings[string]).cpsmidi + fretSeq[index]).midicps})})),
				\bus, ~guitarBus.index),
			if(accompLowSecSeq.size > 1, {
				Pmono(
					\accompBass ++ ~hash,
					\amp, 0.5,
					\freq1, Pseq(accompLowSecSeq.slice(nil, 0)),
					\freq2, Pseq(accompLowSecSeq.slice(nil, 1)),
					\dur, Pseq(accompLowSecSeq.slice(nil, 2)) * beatFrac,
					\busLower, if(secIndex % 2 == 0, {~accompLowLowerBusA.index}, {~accompLowLowerBusB.index}),
					\busUpper, if(secIndex % 2 == 0, {~accompLowUpperBusA.index}, {~accompLowUpperBusB.index}))
			}, {
				Pmono(
					\accompBass ++ ~hash,
					\amp, 0.5,
					\freq1, Pseq([accompLowSecSeq[0][0]]),
					\freq2, Pseq([accompLowSecSeq[0][1]]),
					\dur, Pseq([accompLowSecSeq[0][2]]) * beatFrac,
					\busLower, if(secIndex % 2 == 0, {~accompLowLowerBusA.index}, {~accompLowLowerBusB.index}),
					\busUpper, if(secIndex % 2 == 0, {~accompLowUpperBusA.index}, {~accompLowUpperBusB.index}))
			}),
			Pbind(
				\instrument, \accompTreble ++ ~hash,
				\freq, Pseq(accompHighSecSeq.slice(nil, 0)),
				\dur, Pseq(accompHighSecSeq.slice(nil, 1) * beatFrac),
				\sustain, Pseq(accompHighSecSeq.slice(nil, 2) * beatFrac),
				\amp, 0.5,
				\bus, ~accompHighBus.index),
			Pbind(
				\instrument, \transport ++ ~hash,
				\measure, Pseq(measureSeq),
				\beat, Pseq(beatSeq),
				\dur, beatFrac * 8
			)
		]);
		pattern
	});
};

)

/*
//machine options
(
var durUnit = 0.15;

SynthDef(\machine, {arg freq, gate = 1, sustain, amp;
	var sound;
	sound = TWChoose.ar(Impulse.kr(0), [
		PinkNoise.ar(EnvGen.kr(Env.perc(0.01, sustain, amp * 10), gate, doneAction: 2)),
		BrownNoise.ar(EnvGen.kr(Env.perc(0.01, sustain, amp * 2), gate, doneAction: 2))
	], [0, 20], 1);
	Out.ar([0, 1], sound)
}).add;

~machine1 = Pbind(
	\instrument, \machine,
	\amp, Pseq(3000.collect({arg i; (i / 2000).clip(0, 0.03)})),
	\dur, Pseq(1000.collect({[durUnit, durUnit + (durUnit / 100).rand2].wchoose([10, 1].normalizeSum)}).flat),
	\sustain, Pseq(1000.collect({durUnit * (1.75 + 0.5.rand)})),//2.25].wchoose([1, 20].normalizeSum)})),
	\freq, Pseq(1000.collect({[[300, 250], [300, 250].choose].wchoose([10, 1].normalizeSum)}).flat / 2)
).play;

SynthDef(\machine, {arg freq, gate = 1, sustain, amp = 0.03;
	var trig, sound;
	trig = Impulse.kr(10);
	sound = BrownNoise.ar(EnvGen.kr(Env.perc(0.01, 0.3 + TRand.kr(0, 0.1, trig), amp), TDelay.kr(trig, TRand.kr(0, 0.002, Dust.kr(0.75)))));
	Out.ar([0, 1], sound)
}).play;
)
*/