Arduino MIDI Remapper - Part 5

Fig.1 - Reassigned percussion and chorus pushbuttons on the XB5

In Part 4 I showed how NRPN messages from the XB5 organ can be decoded to control parameters in the B4000+ sound module using CC messages. In this post we look at controlling the effects using the XB5s pushbuttons, e.g. vibrato, chorus, percussion (2nd & 3rd harmonic) etc.
For some of the controls is was fairly straightforward to simply determine which XB5 button was pressed then change the appropriate B4000+ parameter accordingly, e.g. bass pedal sustain. However, the percussion and vibrato/chorus controls were more tricky as the ergonomics are different in both cases.

Vibrato/chorus

The XB5 has a control for selecting either vibrato or chorus and another for selecting depth of effect (using two buttons). The B4000+ just uses one control to select type (vibrato or chorus) and depth. This is shown in the table below.


To make things simpler I decided to leave out the vibrato functions (V1, V2 & V3) as I never use those sounds. Therefore I only needed the two buttons for depth (both buttons are activated for depth 3). This left a spare button which I repurposed as a MIDI all-notes-off function (see below).

Percussion

The XB5 allows you to switch on/off 2nd harmonic and 3rd harmonic percussion independently. The B4000+ has a control for turning percussion on/off and another control which sets the harmonic (a range of harmonics are available, not just 2nd or 3rd). I decided to repurpose the “2nd” button to switch percussion on/off and the “3rd” button to switch between 2nd or 3rd harmonic (see Fig.1).

Case Statements

Rather than using multiple “if” statements for decoding the different push-buttons, I used  “switch” and “case” statements, which is more elegant from a programming perspective.
Switch statements have the syntax:

switch (expression) {
    case constant 1: statement sequence 1;
        break;
    case constant 2: statement sequence 2;
        break;
.
.
.
    case constant N: statement sequence N;
        break;
}

The switch works by checking the expression against the constants. If a match is found, that sequence of statements is executed. If the statement sequence associated with the matching case does not contain a break, execution will continue on into the next case (Schildt, 2003).

I implemented the pushbutton remapping in the Arduino code and used MIDI-OX for testing and debugging, before confirming correct operation with the XB5 and B4000+. A snippet of the resulting code is shown below.

 
void handleMidiEventControlChange(byte inChannel, byte inControlNumber, byte inControlValue) 
{
  if (inControlNumber!=5)     //Use this to filter out a given CC message
  {
    if (inControlNumber==92)
    {
      inControlNumber=4;      //Change CC number for Leslie speed control
    }   
    if (inControlNumber==99)
    {
      NRPNcode = inControlValue;
      NRPNflag = 1;      //Set flag to indicate that an NRPN message has been recieved
    } 
    if (inControlNumber==6)
    {
      // Process NRPN message
      data = inControlValue;
      if (NRPNflag==1)
      {
        //Check NRPN code
        switch (NRPNcode)
        {
          case 9:      //Is it Leslie on/off?
            inControlNumber=83;
            inControlValue=data;
            break;
          case 23:     //Is it vibrato upper?     
            inControlNumber=50;
            inControlValue=data;
            break;
          case 24:     //Is it vibrato lower?
            inControlNumber=49;
            inControlValue=data;
            break;
          case 11:     // Vibrato/chorus button?
            // XB5 uses a seperate NRPN message to switch between vibrato & chorus
            // whereas B4000+ uses a single CC message for V1,V2,V3,C1,C2,C3.
            // Simpler to remove option to switch from chorus to vibrato and repurpose
            // XB5 vibrato/chorus button for something else. 
            inControlNumber=123;  // All notes off
            inControlValue=0;
            break;
          case 69:     //Is it vibrato/chorus mode 1,2,3?
            // Use this to just to switch between C1, C2 & C3. 
            if (data==32)   // V1/C1
            {
              inControlNumber=51;
              inControlValue=0;   // C1
            }
            if (data==64)   // V2/C2
            {
              inControlNumber=51;
              inControlValue=2;   // C2
            }
            if (data==96)   // V3/C3
            {
              inControlNumber=51;
              inControlValue=4;   // C3
            }
            break;
          case 8:     //Is it pedal sustain?     
            if (data==0)   // Sustain off
            {
              inControlNumber=103;
              inControlValue=0;   // Release=0
            }
            if (data==127)   // Sustain on
            {
              inControlNumber=103;
              inControlValue=95;   // 75% release
            }
            break;
          case 18:     // Percussion ON/OFF - Repurposing of 2nd harmonic button     
            inControlNumber=40;
            inControlValue=data;    // Switch percussion ON/OFF
            break;
          case 19:     // 2nd/3rd harmonic? - Repurposing of 3rd harmonic button
            inControlNumber=37;
            if (data==0)   // 2nd percussion?
            {
              inControlValue=57;   // Harmonic=2nd
            }
            if (data==127)   // 3rd percussion?
            {
              inControlValue=68;   // Harmonic=3rd
            }
            break;
          case 21:     // Soft percussion?
            inControlNumber=38;
            if (data==0)
            {
              inControlValue=27;   // 79% percussion level
            }
            if (data==127)   // Soft percussion?
            {
              inControlValue=63;   // 50% percussion level
            }
            break;
          case 22:     // Fast percussion decay?
            inControlNumber=39;
            if (data==0)   // Slow decay?
            {
              inControlValue=42;   // 33% decay
            }
            if (data==127)   // Fast decay?
            {
              inControlValue=0;
            }
            break;
        }
      }
      NRPNflag = 0;   //Reset NRPN flag
    }
    if ((inControlNumber==80)||(inControlNumber==81)||(inControlNumber==82))    //Check if it is drawbar setting
    {
      index = (inControlNumber-80)*81 + inControlValue;
      inControlNumber = byte1[index];
      inControlValue = byte2[index];
    }
    MIDI.sendControlChange(inControlNumber, inControlValue, inChannel);
  }
}

While testing software there have been occasions when a rogue note-on message has been generated, thus causing a note to be stuck on. I suspected this was just due to glitches/latency from using a ‘software’ serial port. This is addressed in the next installment of this blog, but for convenience I added a MIDI all-notes-off function using a (now) spare XB5 push-button (see above).


Continued in Part 6.

Reference

Schildt, Herbert (2003), “C/C++ Programmer’s Reference”, published by McGraw-Hill/Osborne.

 

Disclaimer: This is my personal blog. Views expressed in my posts are my own and not of my employer. The information provided comes with no warranty. I cannot be held responsible for the content of external websites. Any practical work you undertake is done at your own risk. Please make health and safety your number one priority.

Comments