/*******************************************************************************
*  MIDI Velocity Switch: Transpose notes that exceed a velocity threshold.     *
*                                                                              *
*  Copyright 2012, Costis Merziotis                                            *
*  Parts of the code have been copied/adapted from Philip S. Considine's       *
*  excellent MIDI effects and as such retain their original copyright.         *
*                                                                              *
*  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 Velocity Switch

slider1:0<0,15,1{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16}>Channel
slider2:100<0,127,1>Velocity Threshold
slider3:60<0,127,1>Note In
slider4:60<0,127,1>Note Out

////////////////////////////////////////////////////////////////////////////////
@init
statNoteOn = $x90;
statNoteOff = $x80;

////////////////////////////////////////////////////////////////////////////////
@slider

slider2 = min(max(slider2 | 0, 0), 127);
slider3 = min(max(slider3 | 0, 0), 127);	// Remove fractions and clamp to legal range
slider4 = min(max(slider4 | 0, 0), 127);

selectedChannel = slider1;
velocityThreshold = slider2;
noteIn = slider3;
noteOut = slider4;

////////////////////////////////////////////////////////////////////////////////
@block
while
(
	midirecv(offset, msg1, msg23) ?
	(	
		// Extract message type and channel
		status = msg1 & $xF0;
		channel = msg1 & $x0F;
		// Is it on the selected channel
		channel == selectedChannel ? 
		(
			// Is it a Note On event?
			status == statNoteOn ?
			(
				// Extract note number and velocity
				note = msg23 & $x7F;
				velocity = msg23 >> 8;				
				// Is it the selected note and above the velocity threshold?
				note == noteIn ?
				(	
					velocity >= velocityThreshold ?
					(
						// Change note status
						noteStatus = 1;
						// Switch to noteOut
						note = noteOut;

						// Modify MIDI message data
						msg1 = status + selectedChannel;
						msg23 = (msg23 & $xFF00) | note;
					);
					velocity == 0 ? // In case NoteOn messages with zero velocity are sent instead of NoteOff
					(
						noteStatus == 1 ? //Is the key depressed?
						(
							// Change note status
							noteStatus = 0;
							// Switch to noteOut
							note = noteOut;
						);
						// Modify MIDI message data
						msg1 = status + selectedChannel;
						msg23 = (msg23 & $xFF00) | note;						
					);
				);
			);
			status == statNoteOff ? // In case of regular NoteOff messages
			(
				// Extract note number 
				note = msg23 & $x7F;
				// Is it the selected note?
				note == noteIn ?
				(	
					noteStatus == 1 ? //Is the key depressed?
					(
						// Change note status
						noteStatus = 0;
						// Switch to noteOut
						note = noteOut;
					);
					// Modify MIDI message data
					msg1 = status + selectedChannel;
					msg23 = (msg23 & $xFF00) | note;						
				);
			);
		);
		
		// Pass message on
		midisend(offset, msg1, msg23);
		
		1; // Force loop to continue until all messages have been processed
	);
);
