/*******************************************************************************
*  Copyright 2007 - 2021, 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
desc: MIDI Duplicate Note Filter [IXix]
//tags: MIDI filter processing
//author: IXix

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

in_pin:none
out_pin:none

////////////////////////////////////////////////////////////////////////////////
@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] > 0 ? 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
  );
);

