// Using an 88-components piano base to do polyphonic pitch tracking

//load in the sound in and a pretrained basis
(
	b = Buffer.read(s,File.realpath(FluidNMFMatch.class.filenameSymbol).dirname.withTrailingSlash ++ "../AudioFiles/Tremblay-SA-UprightPianoPedalWide.wav");
	c = Buffer.read(s,File.realpath(FluidNMFMatch.class.filenameSymbol).dirname.withTrailingSlash ++ "../AudioFiles/filters/piano-dicts.wav");
)
b.play
c.query

//use the pretrained bases to compute activations of each notes to drive the amplitude of a resynth
(
{
	var source, resynth;
	source = PlayBuf.ar(2, b,loop:1).sum;
	resynth = SinOsc.ar((21..108).midicps, 0, FluidNMFMatch.kr(source,c,88,10,4096).madd(0.002)).sum;
	[source, resynth]
}.play
)


//now sample and hold the same stream to get notes identified, played and sent back via osc
(
{
	var source, resynth, chain, trig, acts;
	source = PlayBuf.ar(2,b,loop:1).sum;

	// built in attack detection, delayed until the stable part of the sound
	chain = FFT(LocalBuf(256), source);
	trig = TDelay.kr(Onsets.kr(chain, 0.5),0.1);

	// samples and holds activation values that are scaled and capped, in effect thresholding them
	acts = Latch.kr(FluidNMFMatch.kr(source,c,88,10,4096).linlin(15,20,0,0.1),trig);

	// resynths as in the previous example, with the values sent back to the language
	resynth = SinOsc.ar((21..108).midicps, 0, acts).sum;
	SendReply.kr(trig, '/activations', acts);
	[source, resynth]
	// [source, T2A.ar(trig)]
	// resynth
}.play
)

// define a receiver for the activations
(
	OSCdef(\listener, {|msg|
		var data = msg[3..];
		// removes the silent and spits out the indicies as midinote number
		data.collect({arg item, i; if (item > 0.01, {i + 21})}).reject({arg item; item.isNil}).postln;
	}, '/activations');
)