Saturday, January 22, 2011

Well, it's all come down to this: a clone of the FCB1010 based on the Arduino MEGA2560 microcontroller.

I got the MEGA2560 in the mail the other day and it is a real pain to use at first. NewSoftSerial.h is a necessary include. On a side note: I would like to thank Arduino for NOT pointing that out anywhere in the documentation and let me assume my brand new microcontroller was bricked for about 3 hours. Jeeze!

Hardware

Before hooking everything up, I had to first do some soldering. Well, not some. A ton. Everything hooked to the resistor packs in the image of my hardware setup below had to be hooked into a daughter board.


And here is the finished daughter board.
Top

Bottom


And here is the Arduino with everything hooked up to it and everything being insulated/held-on by good old-fashioned electrical tape.

I opted for pin/ribbon cable connections between the boards to avoid any spaghetti wiring. It keeps everything organized and neat. And I think it looks cool.

Software

OK so I'm not an experienced electronics engineer or claim to know very much about the topic. As such, I wasn't sure which switch went to which digital pin after I soldered them all in. So I wrote some code to easily tell me. I knew the input pins were 22-33 so I wrote this code, uploaded, opened the serial monitor and started pressing buttons on the footswitch boards.

#include <NewSoftSerial.h>

void setup()
{
  Serial.begin(9600);
}

void loop()
{
  if(digitalRead(22) == LOW){
    Serial.println("22 pressed.");
  }
  if(digitalRead(23) == LOW){
    Serial.println("23 pressed.");
  }
  if(digitalRead(24) == LOW){
    Serial.println("24 pressed.");
  }
  if(digitalRead(25) == LOW){
    Serial.println("25 pressed.");
  }
  if(digitalRead(26) == LOW){
    Serial.println("26 pressed.");
  }
  if(digitalRead(27) == LOW){
    Serial.println("27 pressed.");
  }
  if(digitalRead(28) == LOW){
    Serial.println("28 pressed.");
  }
  if(digitalRead(29) == LOW){
    Serial.println("29 pressed.");
  }
  if(digitalRead(30) == LOW){
    Serial.println("30 pressed.");
  }
  if(digitalRead(31) == LOW){
    Serial.println("31 pressed.");
  }
  if(digitalRead(32) == LOW){
    Serial.println("32 pressed.");
  }
  if(digitalRead(33) == LOW){
    Serial.println("33 pressed.");
  }
}



That step was quick. Figuring out the LED pins was a trail and error test that took a while longer.

The next step was to marry the test effect change code with the wah/volume code. This was no easy task and took hours of troubleshooting with a sniper rifle to get it right. Here is the final functional code to produce a clone of the FCB1010.


#include <NewSoftSerial.h>

int bank = 0x00;//Default bank of 0
int number_in_bank = 0x0A;//10 effects per bank
const int volume_pin = 0;// Pot connected to analog pin 0
const int wah_pin = 1;// Pot connected to analog pin 1
const int pot_threshold = 7;// Threshold amount to guard against false values
const int midi_channel = 0;

void setup() {
  for(int i = 34; i <= 43; i++)//Set up the LED pins and make them float high right off the bat
  {
    pinMode(i, OUTPUT);
    digitalWrite(i, HIGH);
  }

  Serial.begin(31250);//  Set MIDI baud rate:

  changeProgram(0x00,43);//Homed to program 1
}

void loop() {
  ///////////
  //EFFECTS//
  ///////////

  //
  //Lower Button Bank
  //

  //Button 1
  if(digitalRead(23) == LOW)
  {
    changeProgram(0x00,43);
  }
  //Button 2
  if(digitalRead(25) == LOW)
  {
    changeProgram(0x01,41);
  }
  //Button 3
  if(digitalRead(29) == LOW)
  {
    changeProgram(0x02,39);
  }
  //Button 4
  if(digitalRead(27) == LOW)
  {
    changeProgram(0x03,37);
  }
  //Button 5
  else if(digitalRead(33) == LOW)
  {
    changeProgram(0x04,35);
  }
  //Bank Down
  else if(digitalRead(31) == LOW)
  {
    if(bank != 0x01)
    {
      bank -= number_in_bank;
      changeProgram(0x00,43);
      delay(250);
    }
  }

  //
  //Upper Bank
  //

  //Button 6
  else if(digitalRead(22) == LOW)
  {
    changeProgram(0x05,42);
  }
  //Button 7
  else if(digitalRead(24) == LOW)
  {
    changeProgram(0x06,40);
  }
  //Button 8
  else if(digitalRead(26) == LOW)
  {
    changeProgram(0x07,38);
  }
  //Button 9
  else if(digitalRead(28) == LOW)
  {
    changeProgram(0x08,36);
  }
  //Button 10 (0)
  else if(digitalRead(30) == LOW)
  {
    changeProgram(0x09,34);
  }
  //Bank Up
  else if(digitalRead(32) == LOW)
  {
    if(bank != 0x19)
    {
      bank += number_in_bank;
      changeProgram(0x00,43);
      delay(250);
    }
  }
  //////////
  //VOLUME//
  //////////
  expression(volume_pin);
  ///////
  //WAH//
  ///////
  expression(wah_pin);
}

void changeProgram(int effect_number, int LED) {
  int program = bank + effect_number;//Program 1 would be bank(0)+effect_button(0) so 0x00 with 10 effects in the bank
  Serial.print(0xC0, BYTE);//Program Change
  Serial.print(program, BYTE);
  digitalWrite(LED,LOW);  //Light the associated LED

  for(int i =34; i <= 43; i++)//Turn off all the rest of the LEDs
  {
    if(i != LED)
    {
      digitalWrite(i, HIGH);
    }
  }
  delay(250);//Some debounce
}

void changeVolume(byte channel, byte volume)
{
  Serial.print(0xB0 | (channel & 0x0F), BYTE); //Control Change
  Serial.print(0x07, BYTE);//Volume CC number        
  Serial.print(volume & 0x7F, BYTE);//Volume level (0-127)
}


void wahCharacter(byte channel, byte wah)
{
  Serial.print(0xB0 | (channel & 0x0F), BYTE);//Control Change
  Serial.print(0x1B, BYTE);//Wah character CC number
  Serial.print(wah & 0x7F, BYTE);//Wah tone character (0-127)
}

void expression(int pin)
{
  static int s_nLastPotValue = 0;
  static int s_nLastMappedValue = 0;
  int nCurrentPotValue = analogRead(pin);
  if(abs(nCurrentPotValue - s_nLastPotValue) < pot_threshold)
    return;
  s_nLastPotValue = nCurrentPotValue;
  int nMappedValue = map(nCurrentPotValue, 0, 1023, 0, 127); // Map the value to 0-127
  if(nMappedValue == s_nLastMappedValue)
    return;
  s_nLastMappedValue = nMappedValue;
  if(nMappedValue >= 15){
    if (pin == volume_pin)
    { 
     changeVolume(midi_channel, nMappedValue);
    }
    else
    {
      wahCharacter(midi_channel, nMappedValue);
    }
  }
}


Extra

While messing with the code, I discovered that you can run 2 wah pedals off of the same controller. The effects processor takes the setpoints from both of the expression pedals and bounces in between them. It sounds like this [link]

Just change void expression to this:


void expression(int pin)
{
  static int s_nLastPotValue = 0;
  static int s_nLastMappedValue = 0;
  int nCurrentPotValue = analogRead(pin);
  if(abs(nCurrentPotValue - s_nLastPotValue) < pot_threshold)
    return;
  s_nLastPotValue = nCurrentPotValue;
  int nMappedValue = map(nCurrentPotValue, 0, 1023, 0, 127); // Map the value to 0-127
  if(nMappedValue == s_nLastMappedValue)
    return;
  s_nLastMappedValue = nMappedValue;
  if(nMappedValue >= 15){
    wahCharacter(midi_channel, nMappedValue);
  }
}


Still to Come

I have an LCD display on the way. This should be fun.

Possibly messing with shift keys.

<-Part 3   Part 5->
Reactions:
Categories: , , , ,

2 comments:

  1. Keeps getting better and better

    ReplyDelete
  2. very good read! i also playing around with the code but the threshold method will not work. i have a permanent midi stream. im just about to have 2 pedals.

    ReplyDelete

Subscribe to RSS Feed Follow me on Twitter!