DIYstompboxes.com

DIY Stompboxes => Digital & DSP => Topic started by: easilyamused on April 18, 2017, 10:15:01 PM

Title: Mapping the Problematique - a one-trick MIDI pedal
Post by: easilyamused on April 18, 2017, 10:15:01 PM
I've been thinking about this one for ages and finally got around to trying a prototype... The idea is to use a small micro-controller (ATTiny85, Uno etc) to send the appropriate MIDI sequence to my Whammy 5 pedal for playing Muse's "Map of the Problematique" -
see, told you it was one-trick ;)

The code seems to work just fine, but I discovered that the Program Change ID for Octave up and Octave down seem to be incorrect in the Digitech manual. Manual states PC=2 is oct down, and PC=8 for oct up. In my tests and using and confirmed on an external midi watcher app (Midi Wrench) it needs PC=1 and PC=7 respectively. Has anyone else found this?

Here's my code which can be easily tested if you have an Uno, Midi Shield and a Whammy 5. There's a bit of redundant stuff in there, and no promises on compactness or best practice (I'm a Mechanical Engineer)


/*
  ------------
  aM U S Ed
  ------------
 
  "Map of the Problematique" Sequencer for Digitech Whammy5
  using ARDUINO UNO to send required MIDI Program Changes and Control Changes
 
  EasilyAmused, April 2017

  Hardware:
  Arduino Uno
  Sparkfun Midi Shield
  Digitech Whammy 5
  Midi cable
 
  TO DO:
  Use a toggle switch to choose between external and internal midi clock sync
  - use a digital pin to detect setting, put checks in the code to activate
  This ^^ is somewhat moot given this is only  for one song, and the song
  played at 125 bpm... Would be purest to forego this external sync entirely!?

*/

#include <elapsedMillis.h>
elapsedMillis timeElapsed;

const int CHANNEL = 1;  // MIDI Channel to output to. Set Whammy to listen on this, or OMNI...
const int CONTNUM = 11; // Expression pedal code on Whammy5 is 11
const int running = 1;
const int stopped = 0;
const int REDLED = 7;   // Using MIDI Shield for testing
const int SOURCE = 4;
const int STOMP = 2;    // use interrupt on this pin (start/stop switch)

boolean EXT_CLOCK = false;  // External midi clock ("true" if using an external clock)

unsigned int interval = 120; // 120ms interval should give 1/4 notes at 125 bpm. Do the math...
                             //60L * 1000 * 1000 / BPM / 4 (in microsec)
byte data;                   // for holding incoming MIDI data byte (TBD)
byte midi_start = 0xfa;
byte midi_stop = 0xfc;
byte midi_clock = 0xf8;
byte midi_continue = 0xfb;
int midi_state = running;   // running/stopped
int tock = 0;               // start of a 16th note
int tick_counter = 0;       // Midi clock is defined by 6 pulses (ticks) per 16th note
int prog[16]={8,8,2,2,2,2,8,8,2,2,2,2,8,8,2,2}; // PC 2 = octave down, PC 8 = octave up
int pitch[16]={127,0,127,0,127,0,127,0,127,0,127,0,127,0,127,127}; // expression pedal position
int i = 0; //index for arrays

void setup()
{
pinMode(STOMP, INPUT_PULLUP);
attachInterrupt(2, stomp_handler, CHANGE);
pinMode(SOURCE, INPUT);
pinMode(REDLED, OUTPUT);
digitalWrite(REDLED,HIGH); // sparkfun midi shield HIGH ==> LED is OFF
Serial.begin(31250);
}

void loop() {     
/*
    if (Serial.available() > 0) { // FOR EXTERNAL MIDI CLOCK - TBD
      data = Serial.read();       // FOR EXTERNAL MIDI CLOCK - TBD
      }
*/

  while(true) {          // FOR INTERNAL MIDI CLOCK ONLY TEST
    data = midi_clock;   // FOR INTERNAL MIDI CLOCK ONLY TEST

    if (data == midi_clock) {
     
      if (++tick_counter > 5) {
        tock = 1;
        tick_counter = 0;
      }
    }

    if (data == midi_start) {   
      midi_state = running;
      i = 0;                  // reset to beginning of 16 step sequence (bar)
      tick_counter = 5;
    }
   
    if (data == midi_continue) {   
      midi_state = running;
      tick_counter = 5;
    }   
     
    if (data == midi_stop) {
      midi_state = stopped;
    }

    if ( (tock == 1) && (midi_state == running) ) {
      while(timeElapsed < interval) {
       // twiddle thumbs until timing is right
       }
       if (!EXT_CLOCK) {
        syncClock();
       }
       
      progChange(CHANNEL, prog[i]-1);   
      controlChange(CHANNEL, CONTNUM, pitch[i]);
     
      if (++i > 15) {
        i=0;
        digitalWrite(REDLED,LOW);
        delay(20);
        digitalWrite(REDLED,HIGH);
        }   // loop over the array (sequence length = 16 x 16th notes)
       
      tock = 0;
      timeElapsed = 0;
      }
 
    if(digitalRead(SOURCE)) {
        EXT_CLOCK=true;
        digitalWrite(0,HIGH);
      }
      else {
        EXT_CLOCK=false;
        digitalWrite(0,LOW);
      }
   
    } // end of if loop for midi reading
 
} // end of main loop()


void progChange(int newChannel, int prognum) {
  Serial.write( 0xC0 | (newChannel-1) );
  Serial.write(prognum);
}

void controlChange(int newChannel, int controlNumber, int controlValue) {
  Serial.write( 0xB0 | (newChannel-1) ); 
  Serial.write(controlNumber); 
  Serial.write(controlValue);


void syncClock() {
  Serial.write(midi_clock);
}

void stomp_handler() // toggles the midi_state given a stomp switch
{
  static unsigned long last_interrupt_time = 0;
  unsigned long interrupt_time = millis();
  // If interrupts come faster than 200ms, assume it's a bounce and ignore
  if (interrupt_time - last_interrupt_time > 200)
  {
    if (midi_state == running) {
      midi_state = stopped;
    }
    else {
      midi_state = running;
      i = 0;
      tick_counter = 5;
    }
  }
  last_interrupt_time = interrupt_time;
}



Title: Re: Mapping the Problematique - a one-trick MIDI pedal
Post by: Ice-9 on April 19, 2017, 04:55:04 AM
Sounds like they have numbered the programs from 1-128 but as midi starts at 0 it should be 0-127, so I would guess all program change numbers are 1 out. Could this be the answer ?
Title: Re: Mapping the Problematique - a one-trick MIDI pedal
Post by: easilyamused on April 19, 2017, 05:33:49 AM
Quote from: Ice-9 on April 19, 2017, 04:55:04 AM
Sounds like they have numbered the programs from 1-128 but as midi starts at 0 it should be 0-127, so I would guess all program change numbers are 1 out. Could this be the answer ?
Yes that sounds plausible. It works, so maybe I'll go with that! Thanks!


Sent from my iPhone using Tapatalk
Title: Re: Mapping the Problematique - a one-trick MIDI pedal
Post by: ElectricDruid on April 19, 2017, 06:24:04 PM
That'd be exactly the same as the MIDI channels, which are "labelled" 1-16, but in practice are actually 0-15.

MIDI Channel 1 being 0000 is such second nature to me now that I don't even notice how odd that is.

Tom
Title: Re: Mapping the Problematique - a one-trick MIDI pedal
Post by: easilyamused on April 19, 2017, 06:50:56 PM
Quote from: ElectricDruid on April 19, 2017, 06:24:04 PM
That'd be exactly the same as the MIDI channels, which are "labelled" 1-16, but in practice are actually 0-15.

MIDI Channel 1 being 0000 is such second nature to me now that I don't even notice how odd that is.

Tom
Thanks Tom! I knew someone around here would have the definitive answer.


Sent from my iPhone using Tapatalk