Wham Jammer adaptation problems

Hi,

I am adapting the Wham Jammer project from Notes and Volts for my own needs. I have a Whammy 5 and a Bass Whammy set to receive midi on channels 11 and 14 respectively.

The code I have attached below works as intended for the Bass Whammy on channel 14, however, the midi program change and control change messages are not being sent out for the Whammy 5 on channel 11.
If I remove all of the Bass Whammy functions (BW) from the code, it works as intended for the Whammy 5 and will send out messages on channel 11.

I am not getting any errors when compiling.

#include <MIDI.h>

#define LED 13

MIDI_CREATE_DEFAULT_INSTANCE();

// Globals
byte chordMode = 0;

// MIDI note arrays
byte twoOctave[] = { 0, 5, 11, 16, 21, 27, 32, 37, 42, 48, 53, 58, 64, 69, 74, 79, 85,
                     90, 95, 101, 106, 111, 117, 122, 127 };

byte twoOctaveDn[] = { 127, 122, 117, 111, 106, 101, 95, 90, 85, 79, 74, 69, 64, 58, 53, 48, 42,
                       37, 32, 27, 21, 16, 11, 5, 0 };


void setup() {
  pinMode(LED, OUTPUT);
  MIDI.begin(MIDI_CHANNEL_OMNI);

  // MIDI channel 11 callbacks - Guitar Whammy
  MIDI.setHandleNoteOn(HandleNoteOnGW);
  MIDI.setHandleNoteOff(HandleNoteOffGW);
  MIDI.setHandlePitchBend(HandlePitchBendGW);
  MIDI.setHandleControlChange(HandleCCGW);

  // MIDI channel 14 callbacks - Bass Whammy
  MIDI.setHandleNoteOn(HandleNoteOnBW);
  MIDI.setHandleNoteOff(HandleNoteOffBW);
  MIDI.setHandlePitchBend(HandlePitchBendBW);
  MIDI.setHandleControlChange(HandleCCBW);
}

void loop() {
  MIDI.read();
}

// Functions for Guitar Whammy on MIDI channel 11

void HandleNoteOnGW(byte channel, byte pitch, byte velocity) {
  if (channel == 11) {
    if (velocity == 0) {
      digitalWrite(LED, LOW);
      MIDI.sendControlChange(11, 0, 11);
    } else {
      digitalWrite(LED, HIGH);
      MIDI.sendControlChange(11, noteConvertGW(pitch), 11);
    }
  }
}

void HandleNoteOffGW(byte channel, byte pitch, byte velocity) {
  if (channel == 11) {
    digitalWrite(LED, LOW);
    MIDI.sendControlChange(11, 0, 11);
  }
}

void HandlePitchBendGW(byte channel, int bend) {
  if (channel == 11) {
    if (bend < 0) {
      bend = map(bend, -8192, 0, 127, 0);
      MIDI.sendProgramChange((8 + chordMode), 11);
    } else {
      bend = map(bend, 0, 8192, 0, 127);
      MIDI.sendProgramChange((0 + chordMode), 11);
    }
    MIDI.sendControlChange(11, bend, 11);
  }
}

byte noteConvertGW(byte note) {
  if (note >= 0 && note <= 23) {
    MIDI.sendProgramChange((8 + chordMode), 11);
    return twoOctaveDn[note];
  } else if (note >= 24 && note <= 48) {
    MIDI.sendProgramChange((0 + chordMode), 11);
    return twoOctave[note - 24];
  } else {
    return 0;
  }
}

void HandleCCGW(byte channel, byte number, byte value) {
  if (channel == 11) {
    if (number == 64) {
      if ((value >= 64) && (value <= 127)) chordMode = 42;
      else chordMode = 0;
    }
  }
}

// Functions for Bass Whammy on MIDI channel 14

void HandleNoteOnBW(byte channel, byte pitch, byte velocity) {
  if (channel == 14) {
    if (velocity == 0) {
      digitalWrite(LED, LOW);
      MIDI.sendControlChange(11, 0, 14);
    } else {
      digitalWrite(LED, HIGH);
      MIDI.sendControlChange(11, noteConvertBW(pitch), 14);
    }
  }
}

void HandleNoteOffBW(byte channel, byte pitch, byte velocity) {
  if (channel == 14) {
    digitalWrite(LED, LOW);
    MIDI.sendControlChange(11, 0, 14);
  }
}

void HandlePitchBendBW(byte channel, int bend) {
  if (channel == 14) {
    if (bend < 0) {
      bend = map(bend, -8192, 0, 127, 0);
      MIDI.sendProgramChange((8 + chordMode), 14);
    } else {
      bend = map(bend, 0, 8192, 0, 127);
      MIDI.sendProgramChange((0 + chordMode), 14);
    }
    MIDI.sendControlChange(11, bend, 14);
  }
}

byte noteConvertBW(byte note) {
  if (note >= 0 && note <= 23) {
    MIDI.sendProgramChange((8 + chordMode), 14);
    return twoOctaveDn[note];
  } else if (note >= 24 && note <= 48) {
    MIDI.sendProgramChange((0 + chordMode), 14);
    return twoOctave[note - 24];
  } else {
    return 0;
  }
}

void HandleCCBW(byte channel, byte number, byte value) {
  if (channel == 14) {
    if (number == 64) {
      if ((value >= 64) && (value <= 127)) chordMode = 42;
      else chordMode = 0;
    }
  }
}

The compiler doesn't read your comments. It doesn't know which function should be called when it needs to handle a note on message. Your code is setting one function and then changing it's mind and setting a different function, overriding the first.

Thanks! Any idea how I can discriminate between the two?

What happens (?physically?, ?electrically?) to make the change between 11 and 14?

I wouldn't say it changes between the two. Both would often occur at the same time. The arduino receives both messages at the same time and I would like it do one thing with channel 11 messages and a different thing with channel 14 messages.

I have no clue about the MIDI library, but my guess is... you would create two instances, one for MIDI_11 and one for MIDI_14, rather than this default instance

[edit] This (create multiple instances) probably will not work because in reading some of the library, the CREATE_DEFAULT uses a hardware serial port... the Uno and Nano only have one hardware serial. Mega2560 has more than one.[/edit]

Create and bind the MIDI interface to the default hardware Serial port

If that didn't burn the house down, you would then let each instance take care of their own business.

Again... this is a guess at MIDI.h... can it have two instances, and can they operate simultaneously.

[edit to my edit]
You probably CAN use two instances... this from the same library

Overriding the Default Serial Settings

When going Hairless (or just want to change the baudrate), override the DefaultSerialSettings. Due to the use of C++ macros, the easy to use MIDI_CREATE_DEFAULT_INSTANCE(); is replaced with more verbose declarations (exposing the great modularity of the library, allowing it to have multiple transport mechanisms that have extended the MIDI protocols over the years (USB, BLE, RTP,...))

[/edit to my edit]

You can have only one handler function for each command. The channel is a parameter to the handler function. So the function can use that to decide what action to take:

void HandleNoteOn(byte channel, byte pitch, byte velocity) {
  if (channel == 11) {
    if (velocity == 0) {
      digitalWrite(LED, LOW);
      MIDI.sendControlChange(11, 0, 11);
    } else {
      digitalWrite(LED, HIGH);
      MIDI.sendControlChange(11, noteConvertGW(pitch), 11);
    }
  }
  else if (channel == 14) {
    if (velocity == 0) {
      digitalWrite(LED, LOW);
      MIDI.sendControlChange(11, 0, 14);
    } else {
      digitalWrite(LED, HIGH);
      MIDI.sendControlChange(11, noteConvertBW(pitch), 14);
    }
  }
}

I combined your 2 handler functions into one.

I am not a midi expert. I have no idea what a "wham jammer" is. (Maybe it blocks any songs featuring George Michael?) I cannot test this code for you. But it seems like the obvious solution to me.

Thank you @PaulRB! Your solution set me on the right path. I've got it working now.
Thank you too @xfpd.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.