I have a Keith MacMillen Softstep... but its really complicated to program, and the buttons are rubber. I never knew if the thing was ever pressed or not. I wanted the "click" of a regular guitar pedal. And I don't need something that complicated. There are some other pedals you can purchase... but their footprint wasn't correct for my pedal board. And I didn't want to spend another $300-$400.
So for around $70 I built my own.
Physical Construction:
I used luan ply and just made it in the wood shop.
SKETCHUP MODEL
Switches:
You need momentary SPST switches. I got the "silent" ones so it doesn't sound like a firecracker going off in the middle of the worship service. Something like this:
Microcontroller:
I used an arduino teensy that I bought from sparkfun. It offers a couple of important things:
• It has USB connectivity
•It's powered via USB
•It supports a native MIDI control without need for some intermediary software.
•It has a ton of digital pins
LCD Display
I bought it HERE from sparkfun. I wanted a serial rather than parallel connection so I didn't have to chew up lots of extra pins. (pins= possible switches or leds, or connectors)
Connections.
I suppose if I were really thorough I'd have some sort of fancy connection diagram. Basically,
I hooked pin 1 up to the serial LCD pin. And then the switches have all the connections from there. You could in theory have 24 or so physical buttons/switches. Or if you were really good with programming could figure out a way to use multiple banks. But that's too complicated for me.
Code:
This was the hard part. I first got it working with the MIDI buttons sketch. Then got the serial LCD sketch to work. As I'm not a programmer, I had to learn to combine the two together.
Here's the Arduino Code
/* Buttons to USB MIDI Example
You must select MIDI from the "Tools > USB Type" menu
To view the raw MIDI data on Linux: aseqdump -p "Teensy MIDI"
This example code is in the public domain.
You'll have to change the pin assignments below if you use different pins than I did.
*/
#include
#include
#define txPin 1
// the MIDI channel number to send messages
const int channel = 1;
SoftwareSerial LCD = SoftwareSerial(0, txPin);
// since the LCD does not send data back to the Arduino, we should only define the txPin
const int LCDdelay=10; // conservative, 2 actually works
// Create Bounce objects for each button. The Bounce object
// automatically deals with contact chatter or "bounce", and
// it makes detecting changes very simple.
Bounce button14 = Bounce(14, 100);
Bounce button15 = Bounce(15, 100); // 5 = 5 ms debounce time
Bounce button2 = Bounce(2, 10); // which is appropriate for good
Bounce button3 = Bounce(3, 10); // quality mechanical pushbuttons
Bounce button4 = Bounce(4, 10);
Bounce button5 = Bounce(5, 10); // if a button is too "sensitive"
Bounce button6 = Bounce(6, 200); // to rapid touch, you can
Bounce button7 = Bounce(7, 10); // increase this time.
Bounce button8 = Bounce(8, 10);
Bounce button9 = Bounce(9, 10);
Bounce button10 = Bounce(10, 10);
Bounce button11 = Bounce(11, 10);
Bounce button12= Bounce(12, 10);
// wbp: goto with row & column
void lcdPosition(int row, int col) {
LCD.write(0xFE); //command flag
LCD.write((col + row*64 + 128)); //position
delay(LCDdelay);
}
void clearLCD(){
LCD.write(0xFE); //command flag
LCD.write(0x01); //clear command.
delay(LCDdelay);
}
void backlightOn() { //turns on the backlight
LCD.write(0x7C); //command flag for backlight stuff
LCD.write(157); //light level.
delay(LCDdelay);
}
void backlightOff(){ //turns off the backlight
LCD.write(0x7C); //command flag for backlight stuff
LCD.write(128); //light level for off.
delay(LCDdelay);
}
void serCommand(){ //a general function to call the command flag for issuing all other commands
LCD.write(0xFE);
}
void setup() {
// Configure the pins for input mode with pullup resistors.
// The pushbuttons connect from each pin to ground. When
// the button is pressed, the pin reads LOW because the button
// shorts it to ground. When released, the pin reads HIGH
// because the pullup resistor connects to +5 volts inside
// the chip. LOW for "on", and HIGH for "off" may seem
// backwards, but using the on-chip pullup resistors is very
// convenient. The scheme is called "active low", and it's
// very commonly used in electronics... so much that the chip
// has built-in pullup resistors!
pinMode(txPin, OUTPUT);
pinMode(2, INPUT_PULLUP);
pinMode(3, INPUT_PULLUP);
pinMode(4, INPUT_PULLUP);
pinMode(5, INPUT_PULLUP);
pinMode(6, INPUT_PULLUP); // Teensy++ 2.0 LED, may need 1k resistor pullup
pinMode(7, INPUT_PULLUP);
pinMode(8, INPUT_PULLUP);
pinMode(9, INPUT_PULLUP);
pinMode(10, INPUT_PULLUP);
pinMode(11, INPUT_PULLUP);
pinMode(12, INPUT_PULLUP);
pinMode(13, INPUT_PULLUP);
pinMode(14, INPUT_PULLUP); //channel 1
pinMode(15, INPUT_PULLUP); // channel 2 Teensy 2.0 LED, may need 1k resistor pullup
LCD.begin(9600);
clearLCD();
lcdPosition(0,0);
LCD.print(" Scott's MIDI Dominator");
}
void loop() {
// Update all the buttons. There should not be any long
// delays in loop(), so this runs repetitively at a rate
// faster than the buttons could be pressed and released.
button14.update();
button15.update();
button2.update();
button3.update();
button4.update();
button5.update();
button6.update();
button7.update();
button8.update();
button9.update();
button10.update();
button11.update();
button12.update();
// Check each button for "falling" edge.
// Send a MIDI Note On message when each button presses
// Update the Joystick buttons only upon changes.
// falling = high (not pressed - voltage from pullup resistor)
// to low (pressed - button connects pin to ground)
if (button14.fallingEdge()) {
usbMIDI.sendNoteOn(60, 99, channel); // 60 = C4
if (digitalRead(14) == LOW) {
LCD.print ("SONG 1");
LCD.print (0xFE, BYTE);
LCD.print (0x01, BYTE);
LCD.print (" SONG 1 ");}
}
if (button15.fallingEdge()) {
usbMIDI.sendNoteOn(61, 99, channel); // 61 = C#4
if (digitalRead(15) == LOW) {
LCD.print ("SONG 2");
LCD.print (0xFE, BYTE);
LCD.print (0x01, BYTE);
LCD.print (" SONG 2 ");}
}
if (button2.fallingEdge()) {
usbMIDI.sendNoteOn(62, 99, channel); // 62 = D4
if (digitalRead(2) == LOW) {
LCD.print ("SONG 3");
LCD.print (0xFE, BYTE);
LCD.print (0x01, BYTE);
LCD.print (" SONG 3 ");}
}
if (button3.fallingEdge()) {
usbMIDI.sendNoteOn(63, 99, channel); // 63 = D#4
if (digitalRead(3) == LOW) {
LCD.print ("SONG 4");
LCD.print (0xFE, BYTE);
LCD.print (0x01, BYTE);
LCD.print (" SONG 4 ");}
}
if (button4.fallingEdge()) {
usbMIDI.sendNoteOn(64, 99, channel); // 64 = E4
if (digitalRead(4) == LOW) {
LCD.print ("SONG 5");
LCD.print (0xFE, BYTE);
LCD.print (0x01, BYTE);
LCD.print (" SONG 5 "); }
}
if (button5.fallingEdge()) {
usbMIDI.sendNoteOn(65, 99, channel); // 65 = F4
if (digitalRead(5) == LOW) {
LCD.print ("SONG 6");
LCD.print (0xFE, BYTE);
LCD.print (0x01, BYTE);
LCD.print (" SONG 6 ");}
}
if (button6.fallingEdge()) {
usbMIDI.sendNoteOn(66, 99, channel); // 66 = F#4
if (digitalRead(6) == LOW) {
LCD.print ("PLAY");
LCD.print (0xFE, BYTE);
LCD.print (0x01, BYTE);
LCD.print (">>>>>PLAY<<<<<");}
}
if (button7.fallingEdge()) {
usbMIDI.sendNoteOn(67, 99, channel); // 67 = G4
if (digitalRead(7) == LOW) {
LCD.print ("STOP");
LCD.print (0xFE, BYTE);
LCD.print (0x01, BYTE);
LCD.print (" STOP XXXXXXXXXXXXXXXX"); }
}
if (button8.fallingEdge()) {
usbMIDI.sendNoteOn(68, 99, channel); // 68 = G#4
if (digitalRead(8) == LOW) {
LCD.print ("NEXT");
LCD.print (0xFE, BYTE);
LCD.print (0x01, BYTE);
LCD.print (" NEXT >>>>>>>>>>>>>>>>");}
}
if (button9.fallingEdge()) {
usbMIDI.sendNoteOn(69, 99, channel); // 69 = A5
if (digitalRead(9) == LOW) {
LCD.print ("PREVIOUS");
LCD.print (0xFE, BYTE);
LCD.print (0x01, BYTE);
LCD.print (" PREVIOUS <<<<<<<<<<<<<<<<"); }
}
if (button10.fallingEdge()) {
usbMIDI.sendNoteOn(70, 99, channel); // 70 = A#5
if (digitalRead(10) == LOW) {
LCD.print ("EXTRA BUTTON 11");
LCD.print (0xFE, BYTE);
LCD.print (0x01, BYTE);
LCD.print ("EXTRA BUTTON 11"); }
}
if (button11.fallingEdge()) {
usbMIDI.sendNoteOn(71, 99, channel); // 71 = B5
if (digitalRead(11) == LOW) {
LCD.print ("EXTRA BUTTON 12");
LCD.print (0xFE, BYTE);
LCD.print (0x01, BYTE);
LCD.print ("EXTRA BUTTON 12"); }
}
if (button12.fallingEdge()) {
usbMIDI.sendNoteOn(72, 99, channel); // 72 = C6
if (digitalRead(12) == LOW) {
LCD.print ("EXTRA BUTTON 13");
LCD.print (0xFE, BYTE);
LCD.print (0x01, BYTE);
LCD.print ("EXTRA BUTTON 13");
}
delay(50);
}
// Check each button for "rising" edge
// Send a MIDI Note Off message when each button releases
// For many types of projects, you only care when the button
// is pressed and the release isn't needed.
// rising = low (pressed - button connects pin to ground)
// to high (not pressed - voltage from pullup resistor)
if (button14.risingEdge()) {
usbMIDI.sendNoteOff(60, 0, channel); // 60 = C4
}
if (button15.risingEdge()) {
usbMIDI.sendNoteOff(61, 0, channel); // 61 = C#4
}
if (button2.risingEdge()) {
usbMIDI.sendNoteOff(62, 0, channel); // 62 = D4
}
if (button3.risingEdge()) {
usbMIDI.sendNoteOff(63, 0, channel); // 63 = D#4
}
if (button4.risingEdge()) {
usbMIDI.sendNoteOff(64, 0, channel); // 64 = E4
}
if (button5.risingEdge()) {
usbMIDI.sendNoteOff(65, 0, channel); // 65 = F4
}
if (button6.risingEdge()) {
usbMIDI.sendNoteOff(66, 0, channel); // 66 = F#4
}
if (button7.risingEdge()) {
usbMIDI.sendNoteOff(67, 0, channel); // 67 = G4
}
if (button8.risingEdge()) {
usbMIDI.sendNoteOff(68, 0, channel); // 68 = G#4
}
if (button9.risingEdge()) {
usbMIDI.sendNoteOff(69, 0, channel); // 69 = A5
}
if (button10.risingEdge()) {
usbMIDI.sendNoteOff(70, 0, channel); // 70 = A#5
}
if (button11.risingEdge()) {
usbMIDI.sendNoteOff(71, 0, channel); // 71 = B5
}
if (button12.risingEdge()) {
usbMIDI.sendNoteOff(72, 0, channel); // 71 = C6
}
}