Go Down

Topic: USB Midi Foot Controller Help (Read 2765 times) previous topic - next topic

NervusTwitch

Also I cant find out how to add the expression pedal in the code, no idea how to start.
I really just want it to function as a wah control but Im lost here.
I have looked at examples for other projects but not even sure if it will work or were I would put the code.


Grumpy_Mike

#16
Aug 03, 2020, 02:44 pm Last Edit: Aug 03, 2020, 03:11 pm by Grumpy_Mike
Quote
I seem to be missing something here.
Did you make the same changes in the variables.h file as well as this code?
You need to post both files due to the absoloutly moronic way this code is written.

EDIT - OK now I am a bit cross. In reply #4 you said:-
Quote
Also my variables file
But this was not your variables.h file was it? It was your main file again. I though you were telling me the truth so I assumed that the author had done something absoloutly mad. It now appears that he was not being crazy here.

What you seem to have done is to change the number of LEDs and push buttons you have without updating the size of the arrays in the variables.h file. This means that you are addressing arrays outside the declared bounds and reading and writing at memory locations that have been allocated to something else. This will cause all sorts of strange behavior that is not symptomatic of what is going wrong.

So change the variables.h file to make these arrays bigger.
Note for single variables you don't need to do things like this:-
Code: [Select]
int button_states[5] = {false, false, false, false, false};
you can use:-
Code: [Select]
int button_states[] = {false, false, false, false, false, false, false};
and the array will be made big enough to hold all the variables.
In the case of two dimensional arrays you only have to specify the first dimension.

So make these changes and post back both files and say what happens.

Quote
Also I cant find out how to add the expression pedal in the code
So I told you how to do this in reply#9. If you do not understand something about that explanation then please ask specifically about what you don't understand.

NervusTwitch

Ok I made those changes long ago in the variables.h file.
Later when Im home I'll post the files.

So in your reply about the pedal, I will look at it again.

Thanks

cameron206

OK  so that never really crossed my mind, something to think about but for me one thing at a time. I'm just starting to get some kind of grasp on this.

If I were you, I would think about this before you go much further... because it fundamentally changes how you handle the LEDs.

And truly.. outside of the LEDs, your code is trivial. Look at the 'Trasposer' example in the control surface library if you are sending notes.

IN re: the LEDS.. if you want it to reflect the STATE of a condition in your DAW.. you gotta get into callbacks. Maybe emulate a known controller. And this will be very DAW specific.

NervusTwitch

variables.h file.
I can post the main file but since my post count is low the forum makes me wait a few minutes to post again.
As for what I dont understand about adding the expression pedal, I dont understand any of that. I dont know how to even start to add it in,where or anything. I have looked at a few others projects and tried to figure out what to do but none of it worked,thru out a ton of errors.

Just so I dont seem to dense here...lol I need to clarify. In another post I talked about health issues,well that severe nerve damage that affects everything. That includes brain function and memory. Makes it hard for me at times to absorb and learn new things.

I just dont want to come off as being difficult or not willing.

Code: [Select]
/ Arduino Pins
const byte button_pins[7] = {1, 2, 3, 4, 5, 6, 7};   // Pins where buttons are connected
const byte switch_pins[2] = {8, 9};            // Pins where the switch is connected
const byte led_pins[7] = {10, 16, 14, 15, 18, 19, 20}; // Pins where LEDs are connected

// Layer: this is the currently select layer (changed by the switch)g
byte current_layer; // 0 = switch up, 1 = switch off, 2 = switch down

// CC values are the numbers in the decimal column of this table
// https://www.midi.org/specifications-old/item/table-3-control-change-messages-data-bytes-2

const int button_layers[2][7] = {
    /*
    Layer 0 (Switch Up)
    ,----------------------,
    |  49 |  50 | 51  |    |
    |----------------------|
    |  80 |  81 |  82 | 85 |
    `----------------------`
    */
    {
        49, 50, 51,
        80, 81, 82, 85},

    /*
    Layer 1 (Switch Off)
    ,---------------------,
    |  16 |  17 | 18 |    |
    |---------------------|
    |  19 |  20 | 21 | 48 |
    `---------------------`
    */
    {
        16, 17, 18,
        19, 20, 21, 48}
};

// Button modes: 0 = push button, 1 = toggle button
byte button_modes[2][7] = {
    // Layer 0 (Switch Up)
    {0, 0, 0, 0, 0, 0, 0},

    // Layer 1 (Switch Off)
    {0, 0, 0, 0, 0, 0, 0}
};

int buttonState = 0;
int lastButtonState = 0;

// Button states: true = button ON, false = button OFF
int button_states[7] = {false, false, false, false, false, false, false};

long time = 0;         // the last time the output pin was toggled
long debounce = 200;   // the debounce time, increase if the output flickers

// LED states
bool led_states[7] = {false, false, false, false, false, false, false};

byte ppqn = 0; // "Pulse Per Quarter Note"

NervusTwitch

If I were you, I would think about this before you go much further... because it fundamentally changes how you handle the LEDs.

And truly.. outside of the LEDs, your code is trivial. Look at the 'Trasposer' example in the control surface library if you are sending notes.

IN re: the LEDS.. if you want it to reflect the STATE of a condition in your DAW.. you gotta get into callbacks. Maybe emulate a known controller. And this will be very DAW specific.
I have been going thru all the control surface examples and trying to get some grasp on them. It just looks much easier than the one Im working with.
I think one of my issues is that other than connecting and audio interface to connect my mics to and being able to record into the DAW,I have never messed with anything midi and really just learning it as I go here. Ive always been a bit old school when it came to my gear. My only midi experience has been creating bass and drum tracks to add virtual instruments to to have backing tracks to play my guitar with.

Honestly this pedal is just to control pc amp sims and effects since the wife has started working at home I cant really use my main gear while she works.

At this point with the pedal controls Id just like the 7 switches and expression pedal to work and the leds. I dont need any banks or anything really.

NervusTwitch

Did you make the same changes in the variables.h file as well as this code?
You need to post both files due to the absoloutly moronic way this code is written.

EDIT - OK now I am a bit cross. In reply #4 you said:-But this was not your variables.h file was it? It was your main file again. I though you were telling me the truth so I assumed that the author had done something absoloutly mad. It now appears that he was not being crazy here.

What you seem to have done is to change the number of LEDs and push buttons you have without updating the size of the arrays in the variables.h file. This means that you are addressing arrays outside the declared bounds and reading and writing at memory locations that have been allocated to something else. This will cause all sorts of strange behavior that is not symptomatic of what is going wrong.

So change the variables.h file to make these arrays bigger.
Note for single variables you don't need to do things like this:-
Code: [Select]
int button_states[5] = {false, false, false, false, false};
you can use:-
Code: [Select]
int button_states[] = {false, false, false, false, false, false, false};
and the array will be made big enough to hold all the variables.
In the case of two dimensional arrays you only have to specify the first dimension.

So make these changes and post back both files and say what happens.
So I told you how to do this in reply#9. If you do not understand something about that explanation then please ask specifically about what you don't understand.

main code
Code: [Select]
/*
Arduino USB MIDI FootSwitch
by Hecsall (https://github.com/Hecsall)
*/

// https://www.arduino.cc/en/Reference/MIDIUSB
#include "MIDIUSB.h"
#include "variables.h"

// Utility functions

// Event type is hard-coded (0x09 = note on, 0x08 = note off).
// First parameter is the MIDI channel, combined with the note-on/note-off.
// Channel can be anything between 0-15. Typically reported to the user as 1-16.
// Second parameter (pitch) is the note number (48 = middle C).
// Third parameter is the velocity (0 -> 127, 0 = no_sound, 64 = normal, 127 = fastest).

void noteOn(byte channel, byte pitch, byte velocity)
{
    midiEventPacket_t noteOn = {0x09, 0x90 | channel, pitch, velocity};
    MidiUSB.sendMIDI(noteOn);
}

void noteOff(byte channel, byte pitch, byte velocity)
{
    midiEventPacket_t noteOff = {0x08, 0x80 | channel, pitch, velocity};
    MidiUSB.sendMIDI(noteOff);
}

// Event type hard-coded (0x0B = control change, aka "MIDI CC").
// First parameter is the channel (0-15), combined with the event type.
// Second parameter is the "control change" number (0-119, see top link to midi.org).
// Third parameter is the control value (0-127).

void controlChange(byte channel, byte control, byte value)
{
    midiEventPacket_t event = {0x0B, 0xB0 | channel, control, value};
    MidiUSB.sendMIDI(event);
}



// Button in "Push" mode
void handlePushButton(byte i)
{
    if (digitalRead(button_pins[i]) == LOW && button_states[i] == false)
    {
        controlChange(0, button_layers[current_layer][i], 127);
        MidiUSB.flush();
        button_states[i] = true;
        digitalWrite(led_pins[i], HIGH); // Turn the LED on
        led_states[i] = true;
        delay(15);
    }
    else if (digitalRead(button_pins[i]) == HIGH && button_states[i] == true)
    {
        controlChange(0, button_layers[current_layer][i], 0);
        MidiUSB.flush();
        button_states[i] = false;
        digitalWrite(led_pins[i], LOW); // Turn the LED off
        led_states[i] = false;
        delay(15);
    }
}

// Button in "Toggle" mode
void handleToggleButton(byte i)
{
    buttonState = digitalRead(button_pins[i]);
    if (buttonState != lastButtonState){
        if (buttonState == LOW && button_states[i] == false)
        {
            controlChange(0, button_layers[current_layer][i], 127);
            MidiUSB.flush();
            button_states[i] = true;
            digitalWrite(led_pins[i], HIGH); // Turn the LED on
            led_states[i] = true;
        }
        else if (buttonState == LOW && button_states[i] == true)
        {
            controlChange(0, button_layers[current_layer][i], 0);
            MidiUSB.flush();
            button_states[i] = false;
            digitalWrite(led_pins[i], LOW); // Turn the LED off
            led_states[i] = false;
        }
        delay(100);
    }
    lastButtonState = buttonState;
}

// Button "Change" mode
void handleChangeMode(byte i)
{
    buttonState = digitalRead(button_pins[i]);
    if (buttonState != lastButtonState){
        // Note: only layer 1 (switch OFF) can be customized
        if (buttonState == LOW && button_modes[1][i] == 0 && millis() - time > debounce)
        {
            button_modes[1][i] = 1;
            digitalWrite(led_pins[i], HIGH); // Turn the LED on
            led_states[i] = true;
            time = millis();
        }
        else if (buttonState == LOW && button_modes[1][i] == 1 && millis() - time > debounce)
        {
            button_modes[1][i] = 0;
            digitalWrite(led_pins[i], LOW); // Turn the LED off
            led_states[i] = false;
            time = millis();
        }
        delay(50);
    }
    lastButtonState = buttonState;
}

// Turn off all LEDs
void poweroffLeds()
{
    for (uint8_t i = 0; i < 7; i++)
    {
        digitalWrite(led_pins[i], LOW);
        led_states[i] = false;
    }
}

// Turn on all the current mode LEDs
void showModeLeds()
{
    for (uint8_t i = 0; i < 7; i++)
    {
        if (button_modes[1][i] == 1)
        {
            digitalWrite(led_pins[i], HIGH);
            led_states[i] = true;
        }
    }
}

cameron206

At this point with the pedal controls Id just like the 7 switches and expression pedal to work and the leds. I dont need any banks or anything really.
Well, here is some code for the switches and an EXP pedal.
NO LEDs-- you can add that when you decide precisely what you want them to do :)

It compiles for Leonardo, and I think it is self explanatory.



Code: [Select]
// midi.controller  for 7 switch DAW control
// by Cameron @the.nw.enterprise, http://thenorthwestenterprise.com/
// Library Source https://github.com/tttapa/Control-Surface
// Dependency library maybe should also be installed: https://github.com/PaulStoffregen/Encoder
// Written for PRO MICRO

#include <Control_Surface.h> // Include the library

// Instantiate a MIDI interface
//USBDebugMIDI_Interface usbmidi(115200); // uncomment this for serial monitor in ide
//HardwareSerialMIDI_Interface serialmidi = {Serial, MIDI_BAUD}; //uncomment this for 5-pin operation- this sends on TX
USBMIDI_Interface midi; // uncomment for native MIDI over USB
//HairlessMIDI_Interface hair (); // uncomment this for Hairless

/*Instantiate CCbuttons
Will fire 127 on press and 0 on release. Use a momentary switch, like the others.
Assign CC number from here:
https://tttapa.github.io/Control-Surface-doc/Doxygen/d4/dbe/namespaceMIDI__CC.html
https://www.midi.org/specifications-old/item/table-3-control-change-messages-data-bytes-2
*/

CCButton button2 = {2, {MIDI_CC::Sound_Controller_1, CHANNEL_1},};  //switch  CC#70
CCButton button3 = {3, {MIDI_CC::Sound_Controller_2, CHANNEL_1},};  //switch  CC#71
CCButton button4 = {4, {MIDI_CC::Sound_Controller_3, CHANNEL_1},};  //switch  CC#72
CCButton button5 = {5, {MIDI_CC::Sound_Controller_4, CHANNEL_1},};  //switch  CC#73
CCButton button6 = {6, {MIDI_CC::Sound_Controller_5, CHANNEL_1},};  //switch  CC#74
CCButton button7 = {7, {MIDI_CC::Sound_Controller_6, CHANNEL_1},};  //switch  CC#75
CCButton button8 = {8, {MIDI_CC::Sound_Controller_7, CHANNEL_1},};  //switch  CC#76


// Setup for an Analog pot for an EXP pedal on cc #11
CCPotentiometer potentiometer = {
  A0, {MIDI_CC::Expression_Controller, CHANNEL_1}
};


void setup() {
Control_Surface.begin(); // Initialize Control Surface
}

void loop() {
Control_Surface.loop(); // Update the Control Surface
}



*sorry Mike.  :)

NervusTwitch

Thanks.
That will give me something to look thru.
The leds arent a big deal for if I click with mouse or keyboard like you mention in previous reply.
This pedal setup is mostly just to be used with my amp sims in pc and while using the same sims inside my DAW(Reaper).

So really all Im gonna need them for is visual ref when playing and using my foot.
I have been spending some time looking over Control Surface and watching this guy on youtube that has lots of tutorials on code,those has given me some insight to how code functions a bit better.

I was not joking when I said I knew nothing about code, I just kinda jumped into. Then again I have a habit doing that with everything...lol.

Grumpy_Mike

Quote
As for what I dont understand about adding the expression pedal, I dont understand any of that.
Ok.
The expression peddle is controlled by MIDI Control Changes message number 0x0b, well at least this controls the most significant 7 bits of it. The least significant 7 bits of it is controlled by MIDI Control Changes message number 0x2b ( these are hexadecimal numbers which makes it easy to spot patterns you could use decimal numbers here but then they disintegrate in your mind to just random numbers )
A lot of by MIDI Control Changes message have their most significant values at 0x0(something) and their least significant value at 0x2(something).

In practice in the Arduino you only get a 10 bit reading from the A/D converter so often you only use the most significant MIDI message.

You peddle is basically a potentiometer connected to an analogue input pin so you get a reading of between 0 and 1023. If you divide that by 8 then you get a number between 0 and 127.

So to send the peddle to the appropriate MIDI controller number ( which is 0x0b ) you need to read the value and send it to the controller.
Code: [Select]
rawValue = analogRead(pin);
controlChange(0x01, 0x0b, rawValue >> 3); // assuming you are sending to channel 1

With the >> meaning shift to the right 3 places, which is a quick way of dividing by eight.
 
Now the problem with this is that it will send lots and lots of control values all being the same and flood the channel. So it is best to arrange things so that you only send data when the peddle changes. Therefore you have to keep a track of the last reading you took when you sent control data. This means a better code is:-

Code: [Select]
rawValue = analogRead(pin);
if(abs(rawValue - lastRaw) >= 8) {
         controlChange(0x01, 0x0b, rawValue >> 3); // assuming you are sending to channel 1
         lastRaw = rawValue;
}

The abs takes the absolute value of the subtraction so it works if the new value is higher or lower than the last value. Note all these new variables will need to be declaired at the start of the code before ant function definition.

So where to put this code? You want to do this as often as possible so you put it at the very beginning of the void function.

@cameron206   "*sorry Mike"
No I think you are right to do this, lets get away from that awful code.

NervusTwitch

Thanks Grumpy.
So of that info I knew about the pot values and such, that midi stuff had me really confused.

The void function was really messing me up last night until I saw that guy on youtube that teaches code for the arduino. He cleared up the void functions for me, I think. I'll know I try it.

As for the code Ive been using,its really not exactly what I wanted my setup to do but it was the closest I could find to base mine off of. I figured it wouldnt be too hard to edit it.

The buttons and adding more to the original code and same for the leds wasnt too difficult to figure out on my own. My biggest issue has been trying to learn the code for pot.

Ive been tinkering with the original code learning how some of the basics work since cameron showed me the Control Surface. That just looks less complicated and not near as messy.
This just takes me awhile to do stuff like this with that nerve damage. If I sit at a desk too long my skin feels like my entire body is bad sun burnt so I have to step away often.

I'll put this info to use later, I have to step away for a day until the health stuff calms down.

Thank you both,I'm sure I'll have some more questions soon.

NervusTwitch

Well, here is some code for the switches and an EXP pedal.
NO LEDs-- you can add that when you decide precisely what you want them to do :)

It compiles for Leonardo, and I think it is self explanatory.



Code: [Select]
// midi.controller  for 7 switch DAW control
// by Cameron @the.nw.enterprise, http://thenorthwestenterprise.com/
// Library Source https://github.com/tttapa/Control-Surface
// Dependency library maybe should also be installed: https://github.com/PaulStoffregen/Encoder
// Written for PRO MICRO

#include <Control_Surface.h> // Include the library

// Instantiate a MIDI interface
//USBDebugMIDI_Interface usbmidi(115200); // uncomment this for serial monitor in ide
//HardwareSerialMIDI_Interface serialmidi = {Serial, MIDI_BAUD}; //uncomment this for 5-pin operation- this sends on TX
USBMIDI_Interface midi; // uncomment for native MIDI over USB
//HairlessMIDI_Interface hair (); // uncomment this for Hairless

/*Instantiate CCbuttons
Will fire 127 on press and 0 on release. Use a momentary switch, like the others.
Assign CC number from here:
https://tttapa.github.io/Control-Surface-doc/Doxygen/d4/dbe/namespaceMIDI__CC.html
https://www.midi.org/specifications-old/item/table-3-control-change-messages-data-bytes-2
*/

CCButton button2 = {2, {MIDI_CC::Sound_Controller_1, CHANNEL_1},};  //switch  CC#70
CCButton button3 = {3, {MIDI_CC::Sound_Controller_2, CHANNEL_1},};  //switch  CC#71
CCButton button4 = {4, {MIDI_CC::Sound_Controller_3, CHANNEL_1},};  //switch  CC#72
CCButton button5 = {5, {MIDI_CC::Sound_Controller_4, CHANNEL_1},};  //switch  CC#73
CCButton button6 = {6, {MIDI_CC::Sound_Controller_5, CHANNEL_1},};  //switch  CC#74
CCButton button7 = {7, {MIDI_CC::Sound_Controller_6, CHANNEL_1},};  //switch  CC#75
CCButton button8 = {8, {MIDI_CC::Sound_Controller_7, CHANNEL_1},};  //switch  CC#76


// Setup for an Analog pot for an EXP pedal on cc #11
CCPotentiometer potentiometer = {
  A0, {MIDI_CC::Expression_Controller, CHANNEL_1}
};


void setup() {
Control_Surface.begin(); // Initialize Control Surface
}

void loop() {
Control_Surface.loop(); // Update the Control Surface
}



*sorry Mike.  :)
Ok couple questions here after looking at that code. So far the buttons are making sense.
But in this example:
 
Code: [Select]
CCButton button7 = {6, {MIDI_CC::Sound_Controller_6, CHANNEL_1},};  //switch  CC#75

Is the number "6" the pin slot used on the board? or is that suppose to be added after "channel_1} HERE,}"

Also in the section for expression pedal, "A0", does it always need to be that pin or any in the section labeled with A?

In the other code I was using the pins are labeled as 0,1,2 etc... but the ones labeled with "A" in the number, it was using 18,29,20 and so on.
So in control surface does it need to be told the A,A1 or can it be either?

I didnt explain that the best but this pic will show what Im asking:



https://learn.sparkfun.com/tutorials/pro-micro--fio-v3-hookup-guide/hardware-overview-pro-micro

cameron206

Ok couple questions here after looking at that code. So far the buttons are making sense.
But in this example:
 
Code: [Select]
CCButton button7 = {6, {MIDI_CC::Sound_Controller_6, CHANNEL_1},};  //switch  CC#75

Is the number "6" the pin slot used on the board? or is that suppose to be added after "channel_1} HERE,}"

Also in the section for expression pedal, "A0", does it always need to be that pin or any in the section labeled with A?


Yes, the 6 is pin 6.. same with the others.
And the A0 can be any analog pin. On your diagram pins 18-21 are Analog pins 0-3.. as silkscreened on the board.

IN re: the LEDs.. look at the examples in the "MIDI-Callback" section if you wanna do this ~correctly~.
If you really want to get that going, you gotta set up your DAW to pulse out some MIDI messages to let your controller know the position or state of the function you are controlling. Generic remotes often don't do this, so depending on your DAW.. you might have to emulate some supported controller. This just entails programming your control with the same messages, and setting up your DAW to commune with it.

It sounds more complicated than it is... but is really the only way to have your LEDs consistently reflect the position of your parameter, unless you ALWAYS start with the parameters off, and all your project files have them off, etc.

NervusTwitch

Ok that makes sense. SO when making the code I just enter whats printed on the board for the A pins?

When I made things using MMjoy in place of making my own code for other projects, it used a totally different numbering than what was on the board so Im just making sure.

Havent really tried anything with code, just reading it over to make sense, so far much easier for me than the old mess.

Thank you.

Grumpy_Mike

#29
Aug 04, 2020, 09:03 am Last Edit: Aug 04, 2020, 09:04 am by Grumpy_Mike
Quote
The void function was really messing me up last night
Void is simply telling the compiler that this function returns no values. When beginners talk about the void function they normally mean the loop function. But any function can be a void function. If your YouTube person  didn't make that clear that marks him out as a beginner himself, so he might have made other mistakes.

Go Up