(
//~~FUNCTION THAT GENERATES THE GUI
~generateGUI = {
	var win, clockStringFunc, masterView, faderViews, tabs;
	var tabButtonReset, masterButton, guitarOButton, guitarIButton, percButton, ensembleButton, accompButton, startPos = 0;
	var groupNames = ["guitar - ostinato", "guitar - interrupt", "percussion", "interrupt highlights", "fields / beats / flicker"], groupAbbr = ["go", "gi", "p", "e", "a"];
	var accompNames = ["brown noise", "white noise", "sine beating", "flicker"];
	var goVol, giVol, pVol, eVol, aVol, goPan, giPan, pPan, ePan, aPan, goMute, giMute, pMute, eMute, aMute, volGroups, panGroups, muteGroups;
	var masterMuteGroups, masterVolGroups;

	goVol = giVol = pVol = eVol = aVol = [0.8, 0.8, 0.8, 0.8, 0.8, 0.8];
	goMute = giMute = pMute = eMute = aMute = [1, 1, 1, 1, 1, 1];
	goPan = giPan = pPan = ePan = aPan = [0, 0, 0, 0, 0, 0];
	volGroups = [goVol, giVol, pVol, eVol, aVol];
	muteGroups = [goMute, giMute, pMute, eMute, aMute];
	panGroups = [goPan, goPan, pPan, ePan, aPan];
	masterMuteGroups = [1, 1, 1, 1, 1];
	masterVolGroups = [0.8, 0.8, 0.8, 0.8, 0.8];

	clockStringFunc = {
		arg secInt;
		var min, sec;
		sec = secInt;
		min = (sec / 60).trunc.asString;
		if(min.size == 1, {min = "0" ++ min}, {});
		sec =  (sec % 60).trunc.asString;
		if(sec.size == 1, {sec = "0" ++ sec}, {});
		min ++ ":" ++ sec
	};

	~appStatusFunc = Task({
		loop {
			{~appStatus.string = ~appStatusString ++ "*"}.defer;
			0.5.wait; {~appStatus.string = ~appStatusString ++ "* *"}.defer;
			0.5.wait; {~appStatus.string = ~appStatusString ++ "* * *"}.defer;
			0.5.wait; {~appStatus.string = ~appStatusString ++ "* * * *"}.defer;
			0.5.wait; {~appStatus.string = ~appStatusString ++ "* * * * *"}.defer;
			0.5.wait;
		}
	});

	win = Window("ostinato and interrupt", Rect(500, 500, 1100, 500), false).front;
	masterView = {
		var view, masterIndicators, master, generator, transport, ranSeed, startPosText, pauseButton, clock;

		OSCFunc({ arg msg, time;
			{clock.string = clockStringFunc.value(msg[3])}.defer;
		},'/tr', s.addr);
		OSCFunc.new({arg msg; {
			{|i| masterIndicators[i].value = msg[3 + i].ampdb.linlin(-40, 0, 0, 1)} ! 2}.defer},
		'/allMasterLevels', s.addr);

		view = View(win);
		masterIndicators = [LevelIndicator(), LevelIndicator()];
		master = HLayout(
			VLayout(
				HLayout(
					Slider(view).value_(0.8).action_({|v| ~play.set(\allMasterVol, v.value * 1.25)}),
					masterIndicators[0],
					masterIndicators[1]),
				Button(view).states_([["mute", Color.black], ["mute", Color.black, Color.grey]]).action_(
					{|v| ~play.set(\allMasterMute, (1 - v.value).abs)}),
				StaticText(view).string_("          master          ").align_(\center),
				StaticText(view).string_("(all)").align_(\center)),
			nil);
		generator = HLayout(
			Button(view).states_([["generate"]]).action_({
				~appStatusString = "generating data";
				~appStatusFunc.start;
				~generateData.value(seed: ranSeed.string.asInteger);
			}),
			ranSeed = TextField(view).string_("20170121"),
			Button(view).states_([["reset seed"]]).action_({ ranSeed.string = "20170121"}),
			Button(view).states_([["random seed"]]).action_({ ranSeed.string = 50000000.rand.asString}),
			[~appStatus = StaticText(view).string_("status: ready"), stretch: 1],
			nil);
		transport = HLayout(
			Button(view).states_([["play", Color.black], ["stop", Color.black, Color.grey]]).action_(
				{| pState |
					pauseButton.value = 0;
					if(pState.value == 0, {~play.set(\playRate, 0, \startTrig, 0); clock.string = startPosText.string},
						{~play.set(\startPos, startPos, \playRate, 1, \startTrig, 1)})}),
			pauseButton = Button(view).states_([["pause", Color.black], ["pause", Color.black, Color.grey]]).action_(
				{| pState |
					if(pState.value == 1, {~play.set(\playRate, 0)},{~play.set(\playRate, 1)})}),
			StaticText(view).string_("start time"),
			[Slider(view, Rect(0, 0, 30, 20)).action_(
				{|pos|
					var min, sec;
					startPosText.string = clockStringFunc.value(pos.value * ~totalDur);
					startPos = pos.value;
			}), stretch: 1],
			startPosText = StaticText(win).string_("00:00").font_(Font("Monaco", 15)),
			nil);
		view.layout_(HLayout(master,
			[VLayout(generator,
				clock = StaticText(win).string_("00:00").font_(Font("Monaco", 300));,
				transport
	), alignment: \top])) };
	faderViews = { |group|
		var view, masterIndicators, trackIndicators, master, tracks;
		view = View(win);
		masterIndicators = {LevelIndicator()} ! 10;
		trackIndicators = {LevelIndicator()} ! 26;

		OSCFunc.new({arg msg; {
			{|i| masterIndicators[i].value = msg[3 + i].ampdb.linlin(-40, 0, 0, 1)} ! 10}.defer},
		'/groupMasterLevels', s.addr);
		OSCFunc.new({arg msg; {
			{|i| trackIndicators[i].value = msg[3 + i].ampdb.linlin(-40, 0, 0, 1)} ! 26}.defer},
		'/groupTrackLevels', s.addr);

		master = HLayout(
			VLayout(
				[HLayout(
					Slider(view).value_(0.8).action_(
						{|v| masterVolGroups[group] = v.value * 1.25; ~play.set(\masterVolGroups, masterVolGroups)}),
					masterIndicators[group * 2],
					masterIndicators[group * 2 + 1]), stretch: 2],
				Button(view).states_([["mute", Color.black], ["mute", Color.black, Color.grey]]).action_(
					{|v| masterMuteGroups[group] = (1 - v.value).abs; ~play.set(\masterMuteGroups, masterMuteGroups)}),
				StaticText(view).string_("             master             ").align_(\center),
				StaticText(view).string_("("++groupNames[group]++")").align_(\center)
			),
			nil);
		tracks = { |part|
			HLayout(
				VLayout(
					HLayout(
						Slider(view).value_(0.8).action_(
							{|v| volGroups[group][part] = v.value * 1.25; ~play.set(groupAbbr[group] ++ "Vol", volGroups[group])}),
						trackIndicators[group * 6 + part - if(group > 0, {2}, {0})]),
					Button(view).states_([["mute", Color.black], ["mute", Color.black, Color.grey]]).action_(
						{|v| muteGroups[group][part] = (1 - v.value).abs; ~play.set(groupAbbr[group] ++ "Mute", muteGroups[group])}),
					StaticText(view).string_("pan").align_(\center),
					Knob(view).value_(0.5).action_(
						{|v| panGroups[group][part] = v.value * 2 - 1; ~play.set(groupAbbr[group] ++ "Pan", panGroups[group])}),
					StaticText(view).string_(
						if(group == 4, {accompNames[part]}, {(6 - part).asString})).align_(\center)
				),
				nil)
		} ! if((group == 0) || (group == 4), {4}, {6});
		view.layout_(HLayout(master, nil, *tracks))} ! 5;
	tabButtonReset = {masterButton.value = 1;
		guitarOButton.value = 1; guitarIButton.value = 1; percButton.value = 1; ensembleButton.value = 1; accompButton.value = 1;};
	win.layout = VLayout(
		HLayout(
			masterButton = Button().states_([["master controls", Color.white, Color.grey], ["master controls", Color.black]]).action_(
				{tabButtonReset.value; masterButton.value = 0; tabs.index = 0 }).value_(0),
			guitarOButton = Button().states_([["guitar (ostinato)", Color.white, Color.grey], ["guitar (ostinato)", Color.black]]).action_(
				{tabButtonReset.value; guitarOButton.value = 0; tabs.index = 1 }).value_(1),
			guitarIButton = Button().states_([["guitar (interrupt)", Color.white, Color.grey], ["guitar (interrupt)", Color.black]]).action_(
				{tabButtonReset.value; guitarIButton.value = 0; tabs.index = 2 }).value_(1),
			percButton = Button().states_([["percussion", Color.white, Color.grey], ["percussion", Color.black]]).action_(
				{tabButtonReset.value; percButton.value = 0; tabs.index = 3 }).value_(1),
			ensembleButton = Button().states_([["interrupt highlights", Color.white, Color.grey], ["interrupt highlights", Color.black]]).action_(
				{tabButtonReset.value; ensembleButton.value = 0; tabs.index = 4 }).value_(1),
			accompButton = Button().states_([["fields / beats / flicker", Color.white, Color.grey],
				["fields / beats / flicker", Color.black]]).action_(
				{tabButtonReset.value; accompButton.value = 0; tabs.index = 5 }).value_(1)),
		tabs = StackLayout(masterView.value, faderViews[0], faderViews[1], faderViews[2], faderViews[3], faderViews[4]));
};
)