/*
**THIS CODE USES JAMES HARKINS' DEWDROP-LIB.**
See the Quarks helpfile for installation instructions.

• Run the SynthDefs eclosure at the bottom of this file first.  Once a SynthDef is loaded in SC, it is stored permanently.

First, load the synthdef at the bottom.  Once a synthdef is defined, SC stores it permanently.

Next, run the patch.  Samples are chosen by the mod wheel.  Volume is controlled by midiCC 102.

--------------------------------------------------
William Brent 2008
www.williambrent.com
*/

(
var paths, buffers, ch_1, ch_1_sock, ch_1_ped, cs_bufnum;

// Sample loading happens immediately below.  You'll have to write a correct path for files that actually exist on your machine.  Add as many samples to the list as you like.
paths = [
"~/SC_sounds/Perc/2.aif".standardizePath,
"~/SC_sounds/Perc/3.aif".standardizePath,
"~/SC_sounds/Perc/4.aif".standardizePath
];

paths.do{
	|item, i|
	
	// I'm specifying a specific buffer number for each buffer.  This is normally not a great idea, but since we're not allocating and de-allocating a lot of buffers, it doesn't matter here.
	Buffer.read(s, item, bufnum: i);
};

// To turn off hardware/software auto sync.  Maybe you prefer to have it on (true)...
AbstractMIDIControl.syncByDefault = false;

// ControlSpec lets you map a 0-1 range to whatever.  In this case, 0-1 becomes 0-2 when cs_mul is applied.
cs_bufnum = ControlSpec(0, paths.size-1, 'linear');

ch_1 = Voicer(20, \pitch_shift, [\out_bus, 0]);  // First arg is number of simultaneous voices allowed.
ch_1_sock = VoicerMIDISocket(0, ch_1);  // First arg is MIDI channel number (starting at 0 for channel 1).

ch_1_sock.addControl(1, \bufnum, 0, cs_bufnum); // specify cs_bufnum as a reference for the upper/lower limit values of the mod wheel.
ch_1_sock.addControl(102, \mul, 1);

ch_1_ped = VoicerSusPedal(0, 64, ch_1);

/*
// Add a different type of synthdef on channel 2.  Copy this code to add as many channels as you need...
ch_2 = Voicer(20, \new_synthdef_here, [\out_bus, 0]);  // First arg is number of simultaneous voices allowed.
ch_2_sock = VoicerMIDISocket(1, ch_2);  // First arg is MIDI channel number (starting at 0 for channel 1).

ch_2_sock.addControl(1, \bufnum, 0, cs_bufnum); // specify cs_bufnum as a reference for the upper/lower limit values of the mod wheel.
ch_2_sock.addControl(103, \mul, 1); // use midi CC 103 for channel 2

ch_2_ped = VoicerSusPedal(1, 64, ch_1);
*/

// Free the buffers allocated in "a".  Otherwise they sit there occupying RAM and eventually your computer will have to turn to hard drive swap space (a bad thing).
CmdPeriod.doOnce {
	a.do{ |item, i| item.free; };
	ch_1.free; ch_1_sock.free; ch_1_ped.free;
//	ch_2.free; ch_2_sock.free; ch_2_ped.free;
}

)

// A synthdef.  Make more of your own and assign them to Voicers on different MIDI channels
(
SynthDef(\pitch_shift, { |out_bus = 0, bufnum = 0, freq = 261.6255653006, mul = 1, gate = 0|
	var output, cs_amp;
	
	cs_amp = ControlSpec(0.0, 5, 'linear');
	
	bufnum = Latch.kr(bufnum, gate);  // Latch onto the bufnum so mod wheel motions during a note sustain won't change things around

	output = 
	Pan2.ar(
		PitchShift.ar(
			PlayBuf.ar(
				1,
				bufnum,
				BufRateScale.kr(bufnum)
			),
			0.1,
			freq/261.6255653006,  // center the ratio around middle C (MIDI note 60)
			0,
			0.004
		), 
		0,
		cs_amp.map(mul)
	)
	*
	EnvGen.kr(
		Env.asr(0.005, 0.25, 0.2, 1, 1),
		gate,
		doneAction: 2
	);

	Out.ar(out_bus, output);

}).load(s);
)