Midi bass pedals

Hey there Makers!

I have built a bass midi pedal using old organ pedals (1 octave, 13 momentary switches) with the mega 2560 and a sparkfun midi shield. It is great, but I want to make use of the buttons and rotary pots that are on the midi shield. The buttons are just momentary switches that appear on the digital inputs of the arduino mega D2, D3, D4 and the pots are the analog in A0, A1. There is a line of code in my sketch that sets which octave range my pedals are in and the velocity.

int keyOffset = 0;
int keyVelocity = 100;

I can write a value for key offset +12 to set an octave up +24 two octaves up, or, -12 for an octave down etc.
I can set the key velocity value from 0 to 127 to change volume…but these values are then programmed onto the mega.

Can I write these parameters as variables that can be adjusted realtime using the momentary switches on the digital inputs for octave changes, and the analog input for a volume change?

Cheers, JB

1 Like

Hey, @James42662. Thanks for bringing your question to the forum - it sounds like a pretty juicy project!

Speaking conceptually for a moment about the lines

int keyOffset = 0;
int keyVelocity = 100;

The variables are declared and set tosome value to start off with - an initialisation value. At any point in your sketch you are free to modify the value stored in those variables.
Whatever button debouncing functionality that is included in your sketch could be applied to incrementing/decrementing octave by button pushes, to look something like this (pseudocode):

if (octaveUpButtonPushed) {
    keyOffset += 12;
    while(octaveUpButtonPushed){} // do nothing if button held down. Stop octave shooting up several steps
}

and likewise for octave down.

setting the keyVelocity from a pot is as easy as dropping this (untested) one-liner at the top of your main loop:
keyVelocity = int(map(analogRead(pot),0,1023,0,127)));
This reads the analog value from the pot (0 - 1023), then maps it to a value between 0-127, and finally casts the result as an integer so it’s compatible with keyVelocity.

Best of luck! Let us know how you travel. Once you’re finished, we’d love to see something like this over in our projects area.

1 Like

Hey Michael,

Thanks for your reply. It is a ‘juicy project’ and I will definately post it in your projects area, it is a big learning curve for me in terms of midi and programming! I got the analog pot to work as volume, just had to initialise potentiometer and define pin number, then your one-liner at top of loop works great, so thanks for that! It doesn’t control volume while note on is pressed, only adjusts volume in note off state…am trying to figure out that?
I have not been successful in getting the buttons to change octaves…still working on that. If I post my sketch you may be able to see where I’m going wrong?

I appreciate you taking the time to help out,

Cheers, James.

Sounds like the synthesis code is blocking rather than interrupt-driven e.g. the octave control code I gave you is blocking because of the while loop: while a button is being held the rest of the code does not execute.
To help with looking at your code, consider only posting what is absolutely necessary, or boiling it down into a representative sample to help keep things clear.

Hey Michael,

Yeah, something stops the rest of the loop running when I try to add the octave change code.

This is what I’m running;

struct key
{
int pin;
int midiKey;
int debounce;
int keySent;
};

struct key keys[] =
{
{ 22, 25, 0, 0 }, // Db red
{ 24, 26, 0, 0 }, // D red
{ 26, 27, 0, 0 }, // Eb orange
{ 28, 28, 0, 0 }, // E orange
{ 30, 29, 0, 0 }, // F yellow
{ 32, 30, 0, 0 }, // Gb green
{ 34, 31, 0, 0 }, // G green
{ 36, 32, 0, 0 }, // Ab blue
{ 38, 33, 0, 0 }, // A blue
{ 40, 34, 0, 0 }, // Bb violet
{ 42, 35, 0, 0 }, // B violet
{ 44, 36, 0, 0 }, // C brown
{ 48, 24, 0, 0 }, // C brown
{ 0, 0, 0, 0 } // end of list marker
};

int keyOffset = 12;
int sensorPin = A0;
int sensorValue = 0;
int keyVelocity = 100;

void setup() {
// put your setup code here, to run once:
for(int i = 0; keys[i].pin != 0; ++i)
{
pinMode(keys[i].pin, INPUT_PULLUP);
}
//start serial with midi baudrate 31250
Serial.begin(31250);
}

void Midi_Send(byte cmd, byte data1, byte data2)
{
Serial.write(cmd);
Serial.write(data1);
Serial.write(data2);
}

void noteOn(int midiKey)
{
Midi_Send(0x90, midiKey, keyVelocity);
}

void noteOff(int midiKey)
{
Midi_Send(0x80, midiKey, keyVelocity);
}

void loop() {
// put your main code here, to run repeatedly:;
keyVelocity = (int(map(analogRead(sensorPin),0,1023,0,127)));
sensorValue = analogRead(sensorPin);
byte byte1;
byte byte2;
byte byte3;
int value;

//*************** MIDI THRU ******************//
if(Serial.available() > 0)
{
byte1 = Serial.read();
byte2 = Serial.read();
byte3 = Serial.read();

Midi_Send(byte1, byte2, byte3);

}

// Look for bass pedal key events
for(int i = 0; keys[i].pin != 0; ++i)
{
value = digitalRead(keys[i].pin);
if(keys[i].debounce == 0) // Key has been off
{
if(value == LOW) // Key is now on
{
noteOn(keys[i].midiKey + keyOffset); // Send the MIDI note on message
keys[i].keySent = keys[i].midiKey + keyOffset;
keys[i].debounce = DEBOUNCE; // Set the note off debounce counter
}
}
else // Key has been on
{
if(value == HIGH) // Key has gone off
{
if(–keys[i].debounce == 0) // If Key has remained off for DEBOUNCE scans,
noteOff(keys[i].keySent); // In case the offset has changed, send MIDI off for the right note
}
else // Key has not gone off
keys[i].debounce = DEBOUNCE; // Reset debounce counter in case we got
// a small number of key off scans
}
}
}

Hi James,

It’s a little tricky without reading the formatted code. You can retain your formatting and styling by using the < /> button.

But taking a look at it, I can see a few ways to clean it up and make it a little simpler. Bear in mind that if you’re looking to save some software overheads you can implement a hardware MIDI thru solution. But anyway, the general idea is that note values increment or decrement by 12 for each octave, which I can see you’ve implemented. The issue will be somewhere in adding the keyOffset to the values in your struct.

The best way to get through these problems is to track it down yourself as it will highlight how you can improve the flow of your code.

The first step is to use some sort of feedback. The best option for troubleshooting is the Serial connection. Use it to print out every value and piece of data that is used for each event. You can see if the keyOffset value (12) is, in fact, being adding to your MIDI note values, or not, and track down the problem from there.

Also, regarding the hardware MIDI thru, there’s a great thread on the Teensy forums about a MIDI project, and halfway down is a well drawn schematic for hardware MIDI thru which just takes an output from the optoisolater and runs it through a schmitt trigger to ensure a clean edge is transmitted.

Hi Sam and Michael

Thanks for your advice so far on my midi bass pedals project. I have spent quite a lot of time adding code for the octave up and down function. Through trial and error I managed to get a round about way to do part of it! I spent some time just uploading some basic example codes to get the hang of assigning buttons to turn on and off Leds etc. In the process I tried to keyOffset (octave change) at the digitalWrite Led command…and it worked! But, when I try to do this a second time for octave down it stops any sound from happening. I have found that whichever code follows the first is the one that will work, i.e. octave down command followed by octave up command, then the octaveUp will work and not the down. If I swap this order then the octaveDown will work and not the up? I think I probably need to approach it all by adding keyOffset to the struct keys, like you mentioned Sam, but have trouble verifying code to upload!

here is code with format;

    void loop() {
      // put your main code here, to run repeatedly:
      // read the state of the pushbutton value:
      valDown = digitalRead(octaveDownButton);
      if ( valDown == HIGH && old_valDown == LOW) {
          Downstate = 1 - Downstate;
          delay (250);
        }

      valUp = digitalRead(octaveUpButton);
      if ( valUp == HIGH && old_valUp == LOW) {
        Upstate = 1 - Upstate;
        delay (250);
        }

        old_valDown = valDown;

        if ( Downstate == 1)
          digitalWrite(octaveDownLed, HIGH);
        else
          digitalWrite(octaveDownLed, LOW);
        // check if the pushbutton is pressed.
        // if it is, the buttonState is HIGH:
        if (Downstate == LOW) {
          // turn LED on:
        
          digitalWrite(octaveDownLed, LOW);
          keyOffset = 0;
        } else {
          // turn LED off:
          digitalWrite(octaveDownLed, HIGH);
          keyOffset = 12;

      old_valUp = valUp;

      if ( Upstate == 1)
        digitalWrite(octaveUpLed, HIGH);
      else
        digitalWrite(octaveUpLed, LOW);
      // check if the pushbutton is pressed.
      // if it is, the buttonState is HIGH:
      if (Upstate == LOW) {
        // turn LED on:
        digitalWrite(octaveUpLed, LOW);
        keyOffset = 24;
      } else {
        // turn LED off:
        digitalWrite(octaveUpLed, HIGH);
        keyOffset = 12;
        }

When you say you’re having trouble verifying the code to upload? I’m assuming you’re hitting compilation errors? What are they?