Showing posts with label diy. Show all posts
Showing posts with label diy. Show all posts

Monday, January 24, 2011


Extending the functionality of my hack job is necessary. I mean, when was the last time you saw someone spend hours building something and just wanted to hit them when they stopped at just good enough? I have some parts on order from the good folks at Sparkfun Electronics for phantom power and panel mount USB hookup (w00t!) and also a little surprise that I will be adding in as soon as I figure out how to mount it.

I had a thought the other day. If I can control volume and wah with the expression pedals, what else can I control? According to the manual (page 17) I can control quite a few things with them (not all are useful though). Then it was just a matter for code and how to shift between modes of operation.

Here is my logic: if you step on two of the effects pedals at once, the program sends the expression pedals into a different mode depending on which two were pressed.

First off, there has to be a global array variable that can be changed depending on what mode is desired. I put “int expression_choice[] = {1,2};” at the top of the code. I arbitrarily assigned wah the value of one and volume the value of two. Array index 0 is on the left and index 1 is on the right for left and right pedals respectively.




Secondly, there has to be something in the loop() function to catch when the two buttons are pressed simultaneously. For this it is necessary to put it BEFORE the effects change buttons in the if statement within the loop(). Here's what I did in order to get Volume/Wah, Double Wah, Reverb/Volume and Delay/Volume.

void loop() {
  //////////////////////
  //Expression Options//
  //////////////////////
  if (digitalRead(23) == LOW && digitalRead(25) == LOW)//1 AND 2
  {
    expression_choice[0] = 1;  //Wah
    expression_choice[1] = 2;  //Volume
  }
  else if (digitalRead(25) == LOW && digitalRead(29) == LOW)//2 AND 3
  {
    expression_choice[0] = 1;  //Wah
    expression_choice[1] = 1;  //Double Wah!
  }
  else if (digitalRead(29) == LOW && digitalRead(27) == LOW)//3 AND 4
  {
    expression_choice[0] = 3;  //Reverb
    expression_choice[1] = 2;  //Volume

  }
  else if (digitalRead(27) == LOW && digitalRead(33) == LOW)//4 AND 5
  {
    expression_choice[0] = 4;  //Delay
    expression_choice[1] = 2;  //Volume

  }
  ///////////
  //EFFECTS//
  ///////////

  //
  //Lower Button Bank
  //

  //Button 1
  else if(digitalRead(23) == LOW)....

Beyond that, I did a bit of a shakeup at the bottom of the code. Since the left and right pedals are no longer strictly wah and volume, I renamed the changeVolume and wahCharacter functions to reflect that. Also in those functions, I added some extra if logic so that based on what value expression_choice is it will reflect that by sending the proper Control Change codes for whatever mode I want. Here's the bottom of the code.

void rightPedal(byte channel, byte volume)
{
  Serial.print(0xB0 | (channel & 0x0F), BYTE); //Control Change
  if(expression_choice[1] == 2){
    Serial.print(0x07, BYTE);//Volume CC number
  }
  else if(expression_choice[0] == 1)
  {
    Serial.print(0x1B, BYTE);//Wah character CC number
  }
  Serial.print(volume & 0x7F, BYTE);//Value (0-127)
}


void leftPedal(byte channel, byte wah)
{
  Serial.print(0xB0 | (channel & 0x0F), BYTE);//Control Change

  if(expression_choice[0] == 1)
  {
    Serial.print(0x1B, BYTE);//Wah character CC number
  }
  else if(expression_choice[0] == 3)
  {
    Serial.print(0x12, BYTE);//Reverb character CC number
  }
  else if(expression_choice[0] == 4)
  {
    Serial.print(0x32, BYTE);//Delay timing CC number
  }

  Serial.print(wah & 0x7F, BYTE);//Value (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 >= 10)
  {
    if (pin == volume_pin)
    {
     rightPedal(midi_channel, nMappedValue);
    }
    else
    {
      leftPedal(midi_channel, nMappedValue);
    }
  }
  else//Turn it off
  {
    if (pin == volume_pin)
    {
     rightPedal(midi_channel, 0);
    }
    else
    {
      leftPedal(midi_channel, 0);
    }
  }
}

So if all goes according to plan, you should have something that works like this:

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->

Thursday, January 20, 2011

Since my Arduino Mega just shipped today, I only have volume and wah to test really.

The FCB1010 chassis comes with 2 expression pedals that can be used to vary a plethora of things. For me, I just want things to be the way they used to be: wah on the left, volume on the right.

What makes volume and wah unique from the effects discussed previously are three things: 1. They are variable and work via potentiometers instead of pushbuttons, 2. They are analog inputs and not digital and 3. In the software, they are controlled by a Control Change instead of a Program Change(effects).

The hardware setup is as in the image below if you wish to test.

The code for both is the same. I'll admit I grabbed the code from this site. No shame in not re-inventing the wheel.

The control code for volume is 0x07 and the wah control is 0x11. It took some trial and error to find the wah control code since there is a typo in the documentation. “Wah off/position” should be “Wah on/position”.

Here's the code to enable wah. Just change 0x11 to 0x07 for volume.
// Constant
const int POT_PIN = 0;              // Pot connected to analog pin 0
const int POT_THRESHOLD = 7;        // Threshold amount to guard against false values
const int MIDI_CHANNEL = 0;         // MIDI Channel 1

void setup()
{
    Serial.begin(31250);     // Starts communication with the serial port
}

void loop()
{
    static int s_nLastPotValue = 0;
    static int s_nLastMappedValue = 0;

    int nCurrentPotValue = analogRead(POT_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){
    
      MidiVolume(MIDI_CHANNEL, nMappedValue);
    }
}

void MidiVolume(byte channel, byte volume)
{
    Serial.print(0xB0 | (channel & 0x0F), BYTE);    // Control change command
    Serial.print(0x11, BYTE);                       // Volume command
    Serial.print(volume & 0x7F, BYTE);              // Volume 0-127
}


Still to Come


Beyond the breadboard: PCB and wiring
10 effect bank: 2 footswitch boards
Awesome eye candy: LCD screen
<- Part 2       Part 4 ->

Wednesday, January 19, 2011

So I threw out all of the code from the last post. Can't take the bull by the horns like that.

Testing


First off, I set the V-Amp to communicate through the MIDI in on channel 1. Consult the manual on how to do this. Editing the settings on that piece of gear is like working a Chinese puzzle box.

Upon examining the existing hardware, it was determined that the code has to use reverse HIGH/LOW logic. So when a switch goes low, instead of being normally high, it will change effects/effect banks and make the negative end of an LED go low when necessary. Get all that?

Test Program 1 – Bank Up/Bank Down


Like the title suggests, this code just changes the number (bank number) on the V-Amp's 7 segment displays using 2 momentary buttons. There are 5 effects per bank.
See image for hardware required.


int program = 0x00;
int bank = 0x01;
int number_in_bank = 0x05;

void setup() {
  for(int i = 2; i <= 3; i++)
  {
    pinMode(i, INPUT);
  }
 
  //  Set MIDI baud rate:
  Serial.begin(31250);
  changeProgram(program);
}

void loop() {
 
  if(digitalRead(2) == LOW){
    program += number_in_bank;
    changeProgram(program);
    delay(500);
  }
  if(digitalRead(3) == LOW){
    program -= number_in_bank;
    changeProgram(program);
    delay(500);
  }
}

void changeProgram(int program) {
  Serial.print(0xC0, BYTE);
  Serial.print(program, BYTE);
}


Verdict: WORKS!

Test Program 2 – One whole switchboard


This code will utilize one whole switchboard from the FCB1010. The button hooked into pin 2 of the Arduino will move the effects up one bank (add 5).
See image for hardware required.



int program = 0x00;
int bank = 0x00;
int number_in_bank = 0x05;

void setup() {
  for(int i = 2; i <= 7; i++)
  {
    pinMode(i, INPUT);
  }
 
  //  Set MIDI baud rate:
  Serial.begin(31250);
  changeProgram(program);
}

void loop() {
 
  if(digitalRead(2) == LOW)
  {
    program += number_in_bank;
    bank += number_in_bank;
    changeProgram(program);
    delay(500);
  }
  else if(digitalRead(7) == LOW)
  {
    program = bank + 0x00;
    changeProgram(program);
    delay(500);
  }
  else if(digitalRead(6) == LOW)
  {
    program = bank + 0x01;
    changeProgram(program);
    delay(500);
  }
  else if(digitalRead(5) == LOW)
  {
    program = bank + 0x02;
    changeProgram(program);
    delay(500);
  }
  else if(digitalRead(4) == LOW)
  {
    program = bank + 0x03;
    changeProgram(program);
    delay(500);
  }
  else if(digitalRead(3) == LOW)
  {
    program = bank + 0x04;
    changeProgram(program);
    delay(500);
  }
}

void changeProgram(int program) {
  Serial.print(0xC0, BYTE);
  Serial.print(program, BYTE);
}


Verdict: I tried factoring out the repetitive code into an elegant loop. It just plain didn't work. As written: WORKS!

Test 3 – LEDs


Factored-out some code. Also, the FCB1010 has LEDs that light up that correspond with whatever effect is active. This has to be accounted for in the code.

See image for hardware required.

int program = 0x00;
int bank = 0x00;
int number_in_bank = 0x05;

void setup() {
  for(int i = 2; i <= 7; i++)
  {
    pinMode(i, INPUT);
  }
 for(int i = 8; i <= 12; i++)
 {
   pinMode(i, OUTPUT);
   digitalWrite(i, HIGH);
 }
  //  Set MIDI baud rate:
  Serial.begin(31250);
  changeProgram(program,0x00,0);
}

void loop() {
 
  if(digitalRead(2) == LOW)
  {
    program += number_in_bank;
    bank += number_in_bank;
    changeProgram(program,0x00,0);
    delay(500);
  }
  else if(digitalRead(7) == LOW)
  {
    changeProgram(program,0x00,12);
  }
  else if(digitalRead(6) == LOW)
  {
    changeProgram(program, 0x01,11);
  }
  else if(digitalRead(5) == LOW)
  {
    changeProgram(program,0x02,10);
  }
  else if(digitalRead(4) == LOW)
  {
    changeProgram(program, 0x03, 9);
  }
  else if(digitalRead(3) == LOW)
  {
    changeProgram(program,0x04,8);
  }
}

void changeProgram(int program, int effect_number, int LED) {
  program = bank + effect_number;
  Serial.print(0xC0, BYTE);
  Serial.print(program, BYTE);
  digitalWrite(LED,LOW);
 
  for(int i = 8; i <= 12; i++){
    if(i != LED)
    {
      digitalWrite(i, HIGH);
    }
  }
  delay(500);
}


Verdict: WORKS!!!!!!1!!one!!!

Future Installments


I ran out of I/O and I lack the know-how to build a multiplexing circuit. As such, I will have to wait until the Arduino MEGA256 arrives to add more stuff. (Sad face)

Still to go: add another 5 effects changing switches and a down bank switch (Another footswitch board), expression pedals and (optional) an LED/LCD screen telling me what effect is active.
<- Part 1       Part 4 ->

Sunday, January 16, 2011

So I'm a guitarist that has been playing for right around 12 years. As such, I've amassed some equipment that is quite pricey.

Last week a power surge took out my Behringer FCB1010 midi foot controller that I use to control my Behringer V-Amp Pro multieffects processor. Double damn it!

I was sad and pissed off. I think I went through the seven stages of grief when I saw a bunch of surface mount resistors and transistors let the magic smoke out on the foot controller's main circuit board. Then a thought occurred to me. The controller board is nothing more than a crude microcontroller like a BASIC Stamp or an Arduino. All of the actual physical controls were in tact (pushbuttons and rheostats). I could build a better foot controller with an Arduino.

Planning

I have all of the original manuals for both the V-Amp and the FCB1010 that show the MIDI implementation and control codes. So those values just need plugged into the code.

I want this new controller to have the following features:
  1. Run on phantom power through the MIDI out port
  2. USB port mounted where the mains power used to come into the chassis for programming without tearing the thing apart.
  3. Fully-functional volume and wah expression pedals
  4. All selector switches function as labeled.

Reverse Engineering

All drawings are the circuit boards unmodified. Some changes may be necessary.
The footswitch PCB Both identical to this:
The MIDI out PCB (MIDI in won't be used so omitted):

The Code

I'm really crappy at coding for a microcontroller that I haven't even received in the mail yet. As such, the code so far is just my thought process as to how it will work. This is just for the changing of banks and changing of programs via MIDI. Any help would be appreciated.
const byte BANKSELECT = 0x00;        //0-31
const byte CONTROL_CHANGE = 0xB0;    //For Volume and Wah
const byte PROGRAMCHANGE = 0xC0;    //0-127
const int MIDI_CHANNEL = 0;;  
const int SERIAL_PORT_RATE = 31250;
const int UPPERLIMIT = 127;
const int LOWERLIMIT = 0;
const int UPPER_BANK = 25;
const int LOWER_BANK = 1;
const int LED[] = {1,2,3,4,5,6,7,8,9,10};
const int SWITCH[] = {11,12,13,14,15,16,17,18,19,20,21,22};
int ACTIVE = 0;

void setup(){
  int BANK_PROGS[][5] = {};
  //Populate bank_progs array
  int i,j;
   int COUNTER = 0;
  for(i=1; i<26; i++)
  {
    for(j=0; j<5; i++)
      BANK_PROGS[i][j] == COUNTER;
      COUNTER++;
    {
    
    }
  }

  int x;
  for(x=0; x<10; x++){
    pinMode(LED[x], OUTPUT);
  }
  for(x=0; x<13; x++){
    pinMode(SWITCH[x], INPUT);
  }
  byte BANK = 0x01;            //Default Bank is homed
  Serial.begin(SERIAL_PORT_RATE);
}

void loop(){
  //Search for a high switch
  int x;
  for(x=0; x<10; x++){
    int SWITCHSTATE = digitalRead(SWITCH[x]);
    if(SWITCHSTATE == HIGH){
      if(x=5)
      {
        BANK_CHANGE(1);
      }else if(x=11)
      {
        BANK_CHANGE(0);
      }
      else
      {
        int program = 0;
        EFFECT_CHANGE(x);
      }
      ACTIVE = x;
    }
  }
  //TURN THE ACTIVE LED ON
  digitalWrite(LED[ACTIVE], HIGH);

}

void BANK_CHANGE(int BANKDIFF){
  int BANK=0;
  if(BANKDIFF==1){
  //Bank Up  
    if(BANK!=UPPER_BANK){
      BANK = BANK+2;
    }else{
      BANK = 0x00;
    }
  
  }else{
    //Bank Down
    if(BANK != 0){
      BANK = BANK-2;
    }else{
      BANK = UPPER_BANK;      
    }
  }
  Serial.print(CONTROL_CHANGE, BYTE);
  Serial.print(BANKSELECT, BYTE);
  Serial.print(BANK, BYTE);
}

void EFFECT_CHANGE(byte program){
    Serial.print(PROGRAMCHANGE, BYTE);
    Serial.print(program, BYTE);
}

Stay tuned for more as this project develops.
Part 2 ->
Subscribe to RSS Feed Follow me on Twitter!