/*******************************************************************************
*  Copyright 2007 - 2011, Philip S. Considine                                  *
*  This program is free software: you can redistribute it and/or modify        *
*  it under the terms of the GNU General Public License as published by        *
*  the Free Software Foundation, either version 3 of the License, or           *
*  (at your option) any later version.                                         *
*                                                                              *
*  This program is distributed in the hope that it will be useful,             *
*  but WITHOUT ANY WARRANTY; without even the implied warranty of              *
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the                *
*  GNU General Public License (http://www.gnu.org/licenses/)for more details.  *
*******************************************************************************/

desc: MIDI Duplicate Note Filter

slider1:0<0,15,1{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16}>Input Channel

////////////////////////////////////////////////////////////////////////////////
@init

statNoteOn = $x90;
statNoteOff = $x80;

////////////////////////////////////////////////////////////////////////////////
@slider
inChannel = slider1;

////////////////////////////////////////////////////////////////////////////////
@block

trigger & (2 ^ 0) ? // Reset counters and send all notes off on this channel.
(
	i = 0;
	while
	(
		tracker[i] = 0;
		midisend(0, statNoteOff + inChannel, i | 0 * 256);
		(i += 1) < 127;
	);
	trigger -= 2 ^ 0;
);

while
(
	midirecv(offset, msg1, msg23) ?
	(	
		// Reset pass flag
		passThru = 1;
		
		// Extract message type and channel
		status = msg1 & $xF0;
		channel = msg1 & $x0F;
			
		// Is it on our channel?
		channel == inChannel ? 
		(
			// Is it a note event?
			status == statNoteOn || status == statNoteOff ?
			(
				// Get note and velocity
				note = msg23 & $x7F;
				velocity = msg23 >> 8;
				
				// Update counters and flag to pass if necessary. Zero velocity is regarded as note off
				status == statNoteOn && velocity > 0 ?
				(
					// Note on
					tracker[note] += 1;
					tracker[note] == 1 ? midisend(offset, msg1, msg23);
				)
				:
				(
					// Note off
					tracker[note] -= 1;
					tracker[note] == 0 ? midisend(offset, msg1, msg23);
				);
			)
			:
			(
				midisend(offset, msg1, msg23); // Not a note, pass thru
			);
		)
		:
		(
			midisend(offset, msg1, msg23); // Not on our channel, pass thru
		);
		
		1; // Force loop to continue until all messages have been processed
	);
);

