(
//~~FUNCTION THAT GENERATES THE PIECE (calls SynthDef(\ostinato_and_interrupt))
~generateData = {
	arg isLaunch = false, seed = 20170121; // set if ran on application launch and random seed
	var sample_index = 0; // init sample index
	var perc_allocs, guit_open_allocs, guit_harm_allocs, guit_mute_allocs, guit_bass_allocs; // allocation messages

	// this function reads all the subfolders creating allocation messages and an array that tells synth the range of each type of sample
	var allocMSGs = {
		arg inFolder;
		var bufAllocs = [];
		var bufDelims = [];
		PathName(inFolder).folders.sort({arg a, b; a.folderName[0..1].asInteger < b.folderName[0..1].asInteger }).collect({
			|folder|
			bufDelims = bufDelims.add(sample_index);
			folder.files.collect({|file|
				bufAllocs  = bufAllocs.add([0, [\b_allocRead, sample_index, file.fullPath]]); // allocation message
				sample_index = sample_index+1;
			});
		});
		bufDelims = bufDelims.add(sample_index); // start and end buffer index for each subfolder
		[bufAllocs, bufDelims]
	};

	// run the above function on each folder
	perc_allocs = allocMSGs.value(~dir +/+ "../samples/percussion/");
	guit_open_allocs = allocMSGs.value(~dir +/+ "../samples/strings_open/");
	guit_harm_allocs = allocMSGs.value(~dir +/+ "../samples/strings_harmonics/");
	guit_mute_allocs = allocMSGs.value(~dir +/+ "../samples/strings_muted/");
	guit_bass_allocs = allocMSGs.value(~dir +/+ "../samples/ostinato_bass/");

	// excecute everything in non real time, generate soundfile starting with 4 seconds of silence
	Score.recordNRT(
		perc_allocs[0] ++ guit_open_allocs[0] ++ guit_harm_allocs[0] ++ guit_mute_allocs[0] ++ guit_bass_allocs[0] ++
		[
			[0, [\b_alloc, sample_index + 1, 10000, 5]],
			[0, [\d_recv, ~ostinato_and_interrupt.asBytes(s);]],
			[4, [\s_new, \ostinato_and_interrupt, 10000, 0, 0, \scoreBuf, sample_index + 1, \seed, seed] ++
				[\percBufDelims, $[,] ++ perc_allocs[1] ++ [$]] ++
				[\guitOpenBufDelims, $[,] ++ guit_open_allocs[1] ++ [$]] ++
				[\guitHarmBufDelims, $[,] ++ guit_harm_allocs[1] ++ [$]] ++
				[\guitMuteBufDelims, $[,] ++ guit_mute_allocs[1] ++ [$]] ++
				[\guitBassBufDelims, $[,] ++ guit_bass_allocs[1] ++ [$]]
			],
			[60 * 20, [\b_write, sample_index + 1, ~dir +/+ "gen_data_resources/ostinato_and_interrupt_data.wav", "WAV", "float"]],
			[60 * 20, [\c_set, 0, 0]]],
		~dir +/+ "gen_data_resources/ostinato_and_interrupt_osc",
		~dir +/+ "../audio/ostinato_and_interrupt.wav",
		headerFormat: "WAV", options: ServerOptions.new.numOutputBusChannels = 26, action: {

			// trim the multichannel audio file down to the correct size
			var datasf, insf, outsf, data, durSum, n, pad, newSize;

			~appStatusString = "writing files";
			datasf = SoundFile.openRead(~dir +/+ "gen_data_resources/ostinato_and_interrupt_data.wav");
			datasf.readData(data = FloatArray.newClear(10000));
			datasf.close;
			data = data.clump(5).drop(1);
			durSum = 0;
			n = 0;
			while( {data[n][4] != 0}, {
				durSum = durSum + data[n][4];
				n=n+1;
			});
			insf = SoundFile.openRead(~dir +/+ "../audio/ostinato_and_interrupt.wav");
			outsf = SoundFile.new.headerFormat_(insf.headerFormat).numChannels_(
				insf.numChannels).sampleRate_(insf.sampleRate).sampleFormat_(insf.sampleFormat);
			outsf.openWrite(~dir +/+ "../audio/ostinato_and_interrupt_cut.wav");
			pad = insf.sampleRate * 4 * insf.numChannels;
			insf.readData(data = FloatArray.newClear(pad));
			(((durSum + (22 * 5))/5.0).ceil).do({
				insf.readData(data = FloatArray.newClear(insf.sampleRate * insf.numChannels));
				outsf.writeData(data)});
			insf.close;
			outsf.close;
			File.delete(~dir +/+ "../audio/ostinato_and_interrupt.wav");
			File.copy(~dir +/+ "../audio/ostinato_and_interrupt_cut.wav", ~dir +/+ "../audio/ostinato_and_interrupt.wav");
			File.delete(~dir +/+ "../audio/ostinato_and_interrupt_cut.wav");

			// call transcriber function
			~appStatusString = "generating lilypond";
			~generateLilypond.value;

			// load the buffer for playback
			~appStatusString = "loading buffer";
			Buffer.read(s, ~dir +/+ "../audio/ostinato_and_interrupt.wav", action: {
				|buf| ~totalDur = buf.duration;
				if(isLaunch == true, {~play = Synth.new(\play, [\buf, buf])}, {~play.set(\buf, buf)});
				~appStatusFunc.stop;
				{~appStatus.string = "ready"}.defer
			});
	});
};
)

// uncomment below to run generator without gui
/*(
"ostinato_and_interrupt_generator_synthdef.scd".loadRelative(true, {
	~dir = thisProcess.nowExecutingPath.dirname;
    ~appStatus = StaticText();
	~generateData.value;
});
)*/