Project showcase
Ondes Martenot Style MIDI Controller

Ondes Martenot Style MIDI Controller © GPL3+

Ondes Martenot Style MIDI controller, Arduino MEGA based. To use with Ondes VST by Soniccouture.

  • 2,989 views
  • 1 comment
  • 9 respects

Components and supplies

Necessary tools and machines

09507 01
Soldering iron (generic)
26w6260 40
Multitool, Screwdriver
Hy gluegun
Hot glue gun (generic)

Apps and online services

About this project

REQUIRES A BASIC/GOOD KNOWLEGDE OF MIDI PROTOCOL.

*****************************************************************

I built a MIDI controller prototype based on the Ondes Martenot, french instrument from around 1920. The instrument is rare as hell and costs a huge amount of money, so not an option. Same for the Ondomo and other similar devices. Instead, I decided to build a controller intended to be used with Soniccouture's Ondes Kontakt instrument. This is simply the best Ondes Martenot VST available out there.

MIDI is sent via USB, using Hairless MIDI/serial bridge and loopMIDI (a virtual MIDI input), or via standard MIDI plug. (just comment serial.begin and uncomment midi.begin in the setup part of the sketch).

So, I tried to replicate as much as possible the drawer of a real Ondes Martenot, with all the buttons and faders.

Basically, a few potentiometers and a button sending MIDI CCs. I used CCs that are by default unasigned, and then routed them to the different parameters shown in the Ondes VST. For more realism, use slide pots instead of regular pots. I'll probably go that way if I PCB this project, eventually.

The core of this project: a 10-turn 10k pot sending the pitchbend message. That's how you get the slide effect with the ring. That's what makes the Ondes Martenot a so unique instrument.

The volume pushbutton is actually an FSR, sending CC11 message. A NOTE ON(middle C + octaveshift) is triggered when pressed and NOTE OFF when released.

I added the 6 «trill buttons» you can find on a real Ondes Martenot. Each of them adds a certain amount of pitchbend to momentarily modulate the sound (quarter-tone up/down, semi-tone, tone, minor third and fifth up).

I also added octave shift buttons and MIDI channel buttons, and LEDs. I still got problems with these LEDs and idk why. When turned on, sometimes, the program sends notes on/off very fast or the sound gets weird when pitch shifted (high notes sounds a bit like a saw wave...). Coding mistake, I guess. I'm quite new to this... Anyways for now I disabled the LEDs so everything works fine, except a flickering pot. Probably due to a loose connection somewhere... I might just replace it.

A nice improvement would be to add a real keyboard to the controller. With a switch to switch between the ribbon control and the keyboard. On a real Ondes Martenot, the keyboard is «floating», allowing the player to do vibrato while holding a note. Quite a challenge to replicate on a DIY MIDI controller, but doable.

It could be convenient to add a switch to send MIDI wether via USB or 5-pin MIDI plug. So no need to open the sketch, modify, then reupload to the board... A switch to turn on/off the pitchbend ribbon could also be useful.

For more independance, a simple volume (CC7) slide pot could be added. Especially convenient if using CC11 with the FSR, wich I think is the best. If you use CC7 with the FSR, then no need for that.

For a quieter and smoother action with the ribbon, use only 2 pulleys instead of 4, and better quality ones...

Code

MIDI_Controller_v1-2_CMB.inoC/C++
the 3 files must be in the same folder.
#include <MIDI.h>
#include "Controller.h"

MIDI_CREATE_DEFAULT_INSTANCE();


//**************************************************************************************************


//serial debug, to change manually:
int DEBUG = false;

//debounce time for buttons (channel and octave shift):
int debouncetime = 100;

//DEFINES:
#define PITCHBEND_POT A1

//midi channel buttons
#define MIDICH_BUTTON_UP 29
#define MIDICH_BUTTON_DOWN 30

//FSR:
#define FSR_PIN A0
#define FSR_LED_PIN 44

//trill buttons:
#define QUARTERTONEUP_BUTTON 8
#define QUARTERTONEDOWN_BUTTON 7
#define SEMITONEUP_BUTTON 9
#define TONEUP_BUTTON 10
#define THIRDUP_BUTTON 11
#define FIFTHUP_BUTTON 12

//octave buttons:
#define OCTAVEDOWN_BUTTON 3
#define OCTAVEUP_BUTTON 2
#define OCTAVE_LED_UP 46          
#define OCTAVE_LED_DOWN 45        

//VARIABLES:
//trill buttons:
int QUARTERTONEUPCOUNTER = 0;
int QUARTERTONEDOWNCOUNTER = 0;
int SEMITONEUPCOUNTER = 0;
int TONEUPCOUNTER = 0;
int THIRDUPCOUNTER = 0;
int FIFTHUPCOUNTER = 0;

int QUARTERTONEVALUE = 170;           //a semi-tone = 16384/48 = 341.
int SEMITONEVALUE = 341;
int TONEVALUE = 682;
int THIRDVALUE = 1023;
int FIFTHVALUE = 2387;

int trillvalue;

//midi channel buttons:
int MIDICH = 1;
int midich_plus;
int midich_moins;

//pitchbend:
int PB_INPUT_CURRENT = 0;
int PB_INPUT_ADJUST;      
int PB_INPUT_LAST = 0;
int PB_MAP;
int PB_INVERT;
int PB_ADJUST;
int PB_TOTAL;
int PB;
int PB_INPUT_CURRENT_LED_MAP;

//FSR LED:
int FSR_INPUT;
int FSR_INPUT_LED_MAP;

//ajustements:
float PBmultiplier = 1.25;         
int middleCadjust = 15;            

//octaves buttons:
int OCTAVECOUNTER = 0;
int OCTAVECOUNTERX;
int OCTAVE_COUNTER_LAST = 0;
int OCTAVE_COUNTER_CURRENT = 0;

//FSR notetrigger:
int currentNoteTriggerState = 0;
int lastNoteTriggerState = 0;


//NOTES AND VOLTS:
//************************************************************
//***SET THE NUMBER OF CONTROLS USED**************************
//************************************************************
//combien de TrillButtons:
//byte NUMBER_TRILLBUTTONS = 6;
//---How many buttons are connected directly to pins?---------
byte NUMBER_BUTTONS = 1;
//---How many potentiometers are connected directly to pins?--
byte NUMBER_POTS = 13;
//---How many buttons are connected to a multiplexer?---------
byte NUMBER_MUX_BUTTONS = 0;
//---How many potentiometers are connected to a multiplexer?--
byte NUMBER_MUX_POTS = 0;

//************************************************************

//***ANY MULTIPLEXERS? (74HC4067)************************************
//MUX address pins must be connected to Arduino UNO pins 2,3,4,5
//A0 = PIN2, A1 = PIN3, A2 = PIN4, A3 = PIN5
//*******************************************************************
//Mux NAME (OUTPUT PIN, , How Many Mux Pins?(8 or 16) , Is It Analog?);

//Mux M1(10, 16, false); //Digital multiplexer on Arduino pin 10
//Mux M2(A5, 8, true); //Analog multiplexer on Arduino analog pin A5
//*******************************************************************

//***DEFINE DIRECTLY CONNECTED POTENTIOMETERS************************
//Pot (Pin Number, Command, CC Control, Channel Number)
//**Command parameter is for future use**

Pot PO1(A3, 0, 85, MIDICH);        //BRIGHT
Pot PO2(A5, 0, 20, MIDICH);        //D3
Pot PO3(A6, 0, 22, MIDICH);        //D2
Pot PO4(A7, 0, 23, MIDICH);        //D1
Pot PO5(A8, 0, 24, MIDICH);        //LINE
Pot PO6(A9, 0, 25, MIDICH);        //8
Pot PO7(A10, 0, 26, MIDICH);       //N
Pot PO8(A11, 0, 27, MIDICH);       //C
Pot PO9(A12, 0, 28, MIDICH);      //O
Pot PO10(A13, 0, 29, MIDICH);      //G
Pot PO11(A14, 0, 30, MIDICH);      //g
Pot PO12(A15, 0, 31, MIDICH);      //S
Pot PO13(A0, 0, 11, MIDICH);         //FSR
//Pot PO14(A5, 0, 31, 1);

//*******************************************************************
//Add pots used to array below like this->  Pot *POTS[] {&PO1, &PO2, &PO3, &PO4, &PO5, &PO6};
Pot *POTS[] {&PO1, &PO2, &PO3, &PO4, &PO5, &PO6, &PO7, &PO8, &PO9, &PO10, &PO11, &PO12, &PO13};
//*******************************************************************

//***DEFINE DIRECTLY CONNECTED BUTTONS*******************************
//Button (Pin Number, Command, Note Number, Channel, Debounce Time)
//** Command parameter 0=NOTE  1=CC  2=Toggle CC **

Button BU1(6, 2, 86, MIDICH, 5 );          //TUTTI toggle
//Button BU2(x, x, x, x, x);          
//Button BU3(4, 1, 64, 1, 5 );
//Button BU4(5, 2, 63, 1, 5 );
//Button BU5(6, 0, 64, 1, 5 );
//Button BU6(7, 0, 65, 1, 5 );
//Button BU7(8, 1, 64, 1, 5 );
//Button BU8(9, 2, 64, 1, 5 );
//*******************************************************************
//Add buttons used to array below like this->  Button *BUTTONS[] {&BU1, &BU2, &BU3, &BU4, &BU5, &BU6, &BU7, &BU8};
Button *BUTTONS[] {&BU1};
//*******************************************************************

//***DEFINE BUTTONS CONNECTED TO MULTIPLEXER*************************
//Button::Button(Mux mux, byte muxpin, byte command, byte value, byte channel, byte debounce)
//** Command parameter 0=NOTE  1=CC  2=Toggle CC **

//Button MBU1(M1, 0, 0, 70, 1, 5);
//Button MBU2(M1, 1, 1, 71, 1, 5);
//Button MBU3(M1, 2, 2, 72, 1, 5);
//Button MBU4(M1, 3, 0, 73, 1, 5);
//Button MBU5(M1, 4, 0, 74, 1, 5);
//Button MBU6(M1, 5, 0, 75, 1, 5);
//Button MBU7(M1, 6, 0, 76, 1, 5);
//Button MBU8(M1, 7, 0, 77, 1, 5);
//Button MBU9(M1, 8, 0, 78, 1, 5);
//Button MBU10(M1, 9, 0, 79, 1, 5);
//Button MBU11(M1, 10, 0, 80, 1, 5);
//Button MBU12(M1, 11, 0, 81, 1, 5);
//Button MBU13(M1, 12, 0, 82, 1, 5);
//Button MBU14(M1, 13, 0, 83, 1, 5);
//Button MBU15(M1, 14, 0, 84, 1, 5);
//Button MBU16(M1, 15, 0, 85, 1, 5);
//*******************************************************************
////Add multiplexed buttons used to array below like this->  Button *MUXBUTTONS[] {&MBU1, &MBU2, &MBU3, &MBU4, &MBU5, &MBU6.....};
Button *MUXBUTTONS[] {};

//*******************************************************************

//***DEFINE POTENTIOMETERS CONNECTED TO MULTIPLEXER*******************
//Pot::Pot(Mux mux, byte muxpin, byte command, byte control, byte channel)
//**Command parameter is for future use**
//assigns au cc 20  27 inclusivement (midi cc qui sont de base unasigned...)
//Pot MPO1(M2, 0, 0, 20, 1);
//Pot MPO2(M2, 1, 0, 21, 1);
//Pot MPO3(M2, 2, 0, 22, 1);
//Pot MPO4(M2, 3, 0, 23, 1);
//Pot MPO5(M2, 4, 0, 24, 1);
//Pot MPO6(M2, 5, 0, 25, 1);
//Pot MPO7(M2, 6, 0, 26, 1);
//Pot MPO8(M2, 7, 0, 27, 1);
//Pot MPO9(M2, 8, 0, 50, 1);
//Pot MPO10(M2, 9, 0, 55, 2);
//Pot MPO11(M2, 10, 0, 50, 1);
//Pot MPO12(M2, 11, 0, 55, 2);
//Pot MPO13(M2, 12, 0, 50, 1);
//Pot MPO14(M2, 13, 0, 55, 2);
//Pot MPO15(M2, 14, 0, 50, 1);
//Pot MPO16(M2, 15, 0, 55, 2);
//*******************************************************************
//Add multiplexed pots used to array below like this->  Pot *MUXPOTS[] {&MPO1, &MPO2, &MPO3, &MPO4, &MPO5, &MPO6.....};
Pot *MUXPOTS[] {};

//*******************************************************************

void setup() {

  //pinModes pour octave buttons:
  pinMode(OCTAVEDOWN_BUTTON, INPUT);
  pinMode(OCTAVEUP_BUTTON, INPUT);

  //pinModes pour trillbuttons:
  pinMode(QUARTERTONEUP_BUTTON, INPUT);
  pinMode(QUARTERTONEDOWN_BUTTON, INPUT);
  pinMode(SEMITONEUP_BUTTON, INPUT);
  pinMode(TONEUP_BUTTON, INPUT);
  pinMode(THIRDUP_BUTTON, INPUT);
  pinMode(FIFTHUP_BUTTON, INPUT);

  //MIDICH buttons:
  pinMode(MIDICH_BUTTON_DOWN, INPUT);
  pinMode(MIDICH_BUTTON_UP, INPUT);

  //leds:
  pinMode(OCTAVE_LED_DOWN, OUTPUT);
  pinMode(OCTAVE_LED_UP, OUTPUT);

  pinMode(FSR_LED_PIN, OUTPUT);


    //MIDI.begin();
    Serial.begin(115200);       //115200 = default rate of Hairless MIDI/serial bridge software.

}

//*************************************************************************************************************

void loop() {

  //added:
  MIDIChannel();
  PBVOID();
  NoteTrigger();
  LEDs();

  //original:
  if (NUMBER_BUTTONS != 0) updateButtons();
  if (NUMBER_POTS != 0) updatePots();
  if (NUMBER_MUX_BUTTONS != 0) updateMuxButtons();              
  if (NUMBER_MUX_POTS != 0) updateMuxPots();

  //added, serial debug:
  if (DEBUG == true) {
    Serial.print(PB_INPUT_CURRENT);
    Serial.print(", "); Serial.print(PB_INPUT_ADJUST);
    Serial.print(", "); Serial.print(PB_TOTAL);
    Serial.print(", "); Serial.print(MIDICH);
    Serial.print(", "); Serial.print(currentNoteTriggerState);
    Serial.print(", "); Serial.print(OCTAVECOUNTER);
    //Serial.print(", "); Serial.print();
    //Serial.print(", "); Serial.print();
    //Serial.print(", "); Serial.print();
    //Serial.print(", "); Serial.print();
    //Serial.print(", "); Serial.print();
    //Serial.print(", "); Serial.print();
    Serial.println();
  }
}

//*************************************************************************************************************************************

void MIDIChannel() {

  MIDICH = constrain(MIDICH, 1, 16);

  midich_plus = digitalRead(MIDICH_BUTTON_UP);
  midich_moins = digitalRead(MIDICH_BUTTON_DOWN);

  //+:
  if (midich_plus == HIGH) {
    MIDICH++;
    delay(debouncetime);
  }
  //-:
  if (midich_moins == HIGH) {
    MIDICH--;
    delay(debouncetime);
  }

}

//***********************************************************************

void NoteTrigger() {

  OCTAVECOUNTER = constrain(OCTAVECOUNTER, -3, 3);      //+- 3 octaves max shift
  
  //octave buttons:
  if (digitalRead(OCTAVEUP_BUTTON) == HIGH) {
    OCTAVECOUNTER++;
    delay(debouncetime);
    }
  if (digitalRead(OCTAVEDOWN_BUTTON) == HIGH) {
    OCTAVECOUNTER--;
    delay(debouncetime);
    }

    OCTAVECOUNTERX = OCTAVECOUNTER * 12;


    currentNoteTriggerState = analogRead(FSR_PIN);

        if (currentNoteTriggerState > 0 && lastNoteTriggerState == 0) {
          MIDI.sendNoteOn(60 + OCTAVECOUNTERX, 127, MIDICH);         
          }
        if (currentNoteTriggerState == 0 && lastNoteTriggerState > 0) {
          MIDI.sendNoteOff(60 + OCTAVECOUNTERX, 127, MIDICH);
          }

    lastNoteTriggerState = currentNoteTriggerState;

}

//************************************************************************
      
void PBVOID() {
       
   //quarter tone up:
   if (digitalRead(QUARTERTONEUP_BUTTON) == HIGH) {
      QUARTERTONEUPCOUNTER = QUARTERTONEVALUE;
   }
   if (digitalRead(QUARTERTONEUP_BUTTON) == LOW) {
      QUARTERTONEUPCOUNTER = 0;
   }
   //quarter tone down:
   if (digitalRead(QUARTERTONEDOWN_BUTTON) == HIGH) {
      QUARTERTONEDOWNCOUNTER = -QUARTERTONEVALUE;
   }
   if (digitalRead(QUARTERTONEDOWN_BUTTON) == LOW) {
      QUARTERTONEDOWNCOUNTER = 0;
   }
   //semi-tone up:
   if (digitalRead(SEMITONEUP_BUTTON) == HIGH) {
     SEMITONEUPCOUNTER = SEMITONEVALUE;
   }
   if (digitalRead(SEMITONEUP_BUTTON) == LOW) {
     SEMITONEUPCOUNTER = 0;
   }
   //tone up:
   if (digitalRead(TONEUP_BUTTON) == HIGH) {
     TONEUPCOUNTER = TONEVALUE;
   }
   if (digitalRead(TONEUP_BUTTON) == LOW) {
     TONEUPCOUNTER = 0;
   }
   //third up:
   if (digitalRead(THIRDUP_BUTTON) == HIGH) {
     THIRDUPCOUNTER = THIRDVALUE;
   }
   if (digitalRead(THIRDUP_BUTTON) == LOW) {
     THIRDUPCOUNTER = 0;
   }
   //fifth up:
   if (digitalRead(FIFTHUP_BUTTON) == HIGH) {
     FIFTHUPCOUNTER = FIFTHVALUE;
   }
   if (digitalRead(FIFTHUP_BUTTON) == LOW) {
     FIFTHUPCOUNTER = 0;
   }

   trillvalue = QUARTERTONEUPCOUNTER + QUARTERTONEDOWNCOUNTER + SEMITONEUPCOUNTER + TONEUPCOUNTER + THIRDUPCOUNTER + FIFTHUPCOUNTER;

    //pitch bend pot:
    PB_INPUT_CURRENT = analogRead(PITCHBEND_POT);
    PB_INPUT_CURRENT_LED_MAP = map(PB_INPUT_CURRENT, -8192, 8191, 0, 255);
    PB_INPUT_ADJUST = PB_INPUT_CURRENT + middleCadjust;
    PB_INPUT_ADJUST = constrain(PB_INPUT_ADJUST, 0, 1023);
    PB_MAP = map(PB_INPUT_ADJUST, 1023, 0, -8192, 8191);       //signed integer value.
    PB_ADJUST = PB_MAP * PBmultiplier;
    PB_TOTAL = PB_ADJUST + trillvalue;
    PB_TOTAL = constrain(PB_TOTAL, -8192, 8191);

  //send pitchbend continuoulsy:
  MIDI.sendPitchBend(PB_TOTAL, MIDICH); 
  delay(2); //for stability     
       
}

//*******************************************************************

void LEDs() {
  
  OCTAVE_COUNTER_CURRENT = OCTAVECOUNTER;

  if(OCTAVE_COUNTER_CURRENT != OCTAVE_COUNTER_LAST) {
      if (OCTAVECOUNTER == -3) {
        analogWrite(OCTAVE_LED_DOWN, 255);
        digitalWrite(OCTAVE_LED_UP, LOW);
        }
      if (OCTAVECOUNTER == -2) {
        analogWrite(OCTAVE_LED_DOWN, 170);
        digitalWrite(OCTAVE_LED_UP, LOW);
        }
      if (OCTAVECOUNTER == -1) {
        analogWrite(OCTAVE_LED_DOWN, 85);
        digitalWrite(OCTAVE_LED_UP, LOW);
        }
      if (OCTAVECOUNTER == 0) {
        digitalWrite(OCTAVE_LED_DOWN, LOW);
        digitalWrite(OCTAVE_LED_UP, LOW);
        }
      if (OCTAVECOUNTER == 1) {
        digitalWrite(OCTAVE_LED_DOWN, LOW);
        analogWrite(OCTAVE_LED_UP, 85);
        }
      if (OCTAVECOUNTER == 2) {
        digitalWrite(OCTAVE_LED_DOWN, LOW);
        analogWrite(OCTAVE_LED_UP, 170);
        }
      if (OCTAVECOUNTER == 3) {
        digitalWrite(OCTAVE_LED_DOWN, LOW);
        analogWrite(OCTAVE_LED_UP, 255);
        }
    }
        
  OCTAVE_COUNTER_LAST = OCTAVE_COUNTER_CURRENT;

  FSR_INPUT = analogRead(FSR_PIN);
  FSR_INPUT_LED_MAP = map(FSR_INPUT, 0, 1024, 0, 255);
  
    //FSR LED:
    if(analogRead(FSR_PIN) > 0) {
      analogWrite(FSR_LED_PIN, FSR_INPUT_LED_MAP);
      }
    if(analogRead(FSR_PIN) == 0) {
      digitalWrite(FSR_LED_PIN, LOW);
      }
          
}

//**********************************************************************************************

void updateButtons() {

        // Cycle through Button array
        for (int i = 0; i < NUMBER_BUTTONS; i = i + 1) {
          byte message = BUTTONS[i]->getValue();

          //  Button is pressed
          if (message == 0) {
            switch (BUTTONS[i]->Bcommand) {
              case 0: //Note
                MIDI.sendNoteOn(BUTTONS[i]->Bvalue + OCTAVECOUNTER * 12, 127, BUTTONS[i]->Bchannel);
                break;
              case 1: //CC
                MIDI.sendControlChange(BUTTONS[i]->Bvalue, 127, BUTTONS[i]->Bchannel);
                break;
              case 2: //Toggle
                if (BUTTONS[i]->Btoggle == 0) {
                  MIDI.sendControlChange(BUTTONS[i]->Bvalue, 127, MIDICH);      //origine: BUTTONS[i]->Bchannel
                  BUTTONS[i]->Btoggle = 1;
                }
                else if (BUTTONS[i]->Btoggle == 1) {
                  MIDI.sendControlChange(BUTTONS[i]->Bvalue, 0, MIDICH);        //origine: BUTTONS[i]->Bchannel
                  BUTTONS[i]->Btoggle = 0;
                }
                break;
            }
          }

          //  Button is not pressed
          if (message == 1) {
            switch (BUTTONS[i]->Bcommand) {
              case 0:
                MIDI.sendNoteOff(BUTTONS[i]->Bvalue + OCTAVECOUNTER * 12, 0, BUTTONS[i]->Bchannel);
                break;
              case 1:
                MIDI.sendControlChange(BUTTONS[i]->Bvalue, 0, BUTTONS[i]->Bchannel);
                break;
            }
          }
        }
}
     
//*******************************************************************

void updateMuxButtons() {

        // Cycle through Mux Button array
        for (int i = 0; i < NUMBER_MUX_BUTTONS; i = i + 1) {

          MUXBUTTONS[i]->muxUpdate();
          byte message = MUXBUTTONS[i]->getValue();

          //  Button is pressed
          if (message == 0) {
            switch (MUXBUTTONS[i]->Bcommand) {
              case 0: //Note
                MIDI.sendNoteOn(MUXBUTTONS[i]->Bvalue, 127, MUXBUTTONS[i]->Bchannel);
                break;
              case 1: //CC
                MIDI.sendControlChange(MUXBUTTONS[i]->Bvalue, 127, MUXBUTTONS[i]->Bchannel);
                break;
              case 2: //Toggle
                if (MUXBUTTONS[i]->Btoggle == 0) {
                  MIDI.sendControlChange(MUXBUTTONS[i]->Bvalue, 127, MUXBUTTONS[i]->Bchannel);
                  MUXBUTTONS[i]->Btoggle = 1;
                }
                else if (MUXBUTTONS[i]->Btoggle == 1) {
                  MIDI.sendControlChange(MUXBUTTONS[i]->Bvalue, 0, MUXBUTTONS[i]->Bchannel);
                  MUXBUTTONS[i]->Btoggle = 0;
                }
                break;
            }
          }
          //  Button is not pressed
          if (message == 1) {
            switch (MUXBUTTONS[i]->Bcommand) {
              case 0:
                MIDI.sendNoteOff(MUXBUTTONS[i]->Bvalue, 0, MUXBUTTONS[i]->Bchannel);
                break;
              case 1:
                MIDI.sendControlChange(MUXBUTTONS[i]->Bvalue, 0, MUXBUTTONS[i]->Bchannel);
                break;
            }
          }
        }
}
      
//***********************************************************************

void updatePots() {
        for (int i = 0; i < NUMBER_POTS; i = i + 1) {
          byte potmessage = POTS[i]->getValue();
          if (potmessage != 255) MIDI.sendControlChange(POTS[i]->Pcontrol, potmessage, MIDICH);        //origine: POTS[i]->Pchannel
        }
}
      
//***********************************************************************

void updateMuxPots() {
        for (int i = 0; i < NUMBER_MUX_POTS; i = i + 1) {
          MUXPOTS[i]->muxUpdate();
          byte potmessage = MUXPOTS[i]->getValue();
          if (potmessage != 255) MIDI.sendControlChange(MUXPOTS[i]->Pcontrol, potmessage, MUXPOTS[i]->Pchannel);
        }
}

// ********************   END   ***************************** //
Controller.hC/C++
#ifndef Controller_h
#define Controller_h

#include <Arduino.h>

//***********************************************************************
class Mux
{
  public:
    Mux(byte outpin_, byte numPins_, bool analog_);
    byte outpin;
    byte numPins;
    bool analog;
};
//************************************************************************
//Button (Pin Number, Command, Note Number, Channel, Debounce Time)
class Button
{
  public:
    Button(byte pin, byte command, byte value, byte channel, byte debounce);
    Button(Mux mux, byte muxpin, byte command, byte value, byte channel, byte debounce);
    byte getValue();
    void muxUpdate();
    void newValue(byte command, byte value, byte channel);
    byte Bcommand;
    byte Bvalue;
    byte Bchannel;
    byte Btoggle;

  private:
    byte _previous;
    byte _current;
    unsigned long _time;
    int _debounce;
    byte _pin;
    byte _muxpin;
    byte _numMuxPins;
    byte _value;
    byte _command;
    bool _busy;
    byte _status;
    byte _last;
    byte _enablepin;
};
//*************************************************************************
class Pot
{
  public:
    Pot(byte pin, byte command, byte control, byte channel);
    Pot(Mux mux, byte muxpin ,byte command, byte control, byte channel);
    void muxUpdate();
    void newValue(byte command, byte value, byte channel);
    byte getValue();
    byte Pcommand;
    byte Pcontrol;
    byte Pchannel;

  private:
    byte _pin;
    byte _muxpin;
    byte _numMuxPins;
    byte _control;
    int _value;
    int _oldValue;
    bool _changed;
    byte _enablepin;
};
//*************************************************************************
#endif
Controller.cppC/C++
#include "Controller.h"

//****************************************************************************************
Mux::Mux(byte outpin_, byte numPins_, bool analog_)
{
  outpin = outpin_;
  //enablepin = enablepin_;
  numPins = numPins_;
  analog = analog_;
  if (analog == false) pinMode(outpin, INPUT_PULLUP);
  //pinMode(enablepin, OUTPUT);
  pinMode(24, OUTPUT);
  pinMode(25, OUTPUT);
  pinMode(26, OUTPUT);
  if (numPins > 8) pinMode(27, OUTPUT);
}
//****************************************************************************************
//Button (Pin Number, Command, Note Number, Channel, Debounce Time)
Button::Button(byte pin, byte command, byte value, byte channel, byte debounce)
{
  _pin = pin;
  pinMode(_pin, INPUT_PULLUP);
  _value = value;
  _command = command;
  _debounce = debounce;
  _time = 0;
  _busy = false;
  _status = 0b00000010;
  _last = 1;
  Bcommand = command;
  Bvalue = value;
  Bchannel = channel;
  Btoggle = 0;
}

Button::Button(Mux mux, byte muxpin, byte command, byte value, byte channel, byte debounce)
{
  _pin = mux.outpin;
  _numMuxPins = mux.numPins;
  _muxpin = muxpin;
  _value = value;
  _command = command;
  _debounce = debounce;
  _time = 0;
  _busy = false;
  _status = 0b00000010;
  _last = 1;
  Bcommand = command;
  Bvalue = value;
  Bchannel = channel;
  Btoggle = 0;
}

void Button::muxUpdate()
{
  byte temp = _muxpin;
  temp = temp << 2;
  if (_numMuxPins > 8) PORTA = PORTA & B11000011;
  else PORTA = PORTA & B11100011;
  PORTA = PORTA | temp;
}

byte Button::getValue()
{
  // If BUSY bit not set - read button
  if (bitRead(_status, 0) == false) { // If busy false
    if (digitalRead(_pin) == _last) return 2; // If same as last state - exit
  }

  // If NEW Bit set - Key just pressed, record time
  if (bitRead(_status, 1) == true) { // If new is true
    bitSet(_status, 0); // Set busy TRUE
    bitClear(_status, 1); // Set New FALSE
    _time = millis();
    return 255;
  }

  // Check if debounce time has passed - If no, exit
  if (millis() - _time < _debounce) return 255;

  // Debounce time has passed. Read pin to see if still set the same
  // If it has changed back - assume false alarm
  if (digitalRead(_pin) == _last) {
    bitClear(_status, 0); // Set busy false
    bitSet(_status, 1); // Set new true
    return 255;
  }

  // If this point is reached, event is valid. return event type
  else {
    bitClear(_status, 0); // Set busy false
    bitSet(_status, 1); // Set new true
    _last = ((~_last) & 0b00000001); // invert _last
    return _last;
  }
}

void Button::newValue(byte command, byte value, byte channel)
{
  Bvalue = value;
  Bcommand = command;
  Bchannel = channel;
}

//********************************************************************
Pot::Pot(byte pin, byte command, byte control, byte channel)
{
  _pin = pin;
  _control = control;
  _value = analogRead(_pin);
  _value = _value >> 3;
  _oldValue = _value << 3;
  _value = _value << 3;
  Pcommand = command;
  Pcontrol = control;
  Pchannel = channel;
}

void Pot::muxUpdate()
{
  byte temp = _muxpin;
  temp = temp << 2;
  if (_numMuxPins > 8) PORTA = PORTA & B11000011;
  else PORTA = PORTA & B11100011;
  //PORTA = PORTA & B11000011;
  PORTA = PORTA | temp;
}

Pot::Pot(Mux mux, byte muxpin, byte command, byte control, byte channel)
{
  _pin = mux.outpin;
  _numMuxPins = mux.numPins;
  _muxpin = muxpin;
  _control = control;
  muxUpdate();
  _value = analogRead(_pin);
  _value = _value >> 3;
  _oldValue = _value << 3;
  _value = _value << 3;
  Pcommand = command;
  Pcontrol = control;
  Pchannel = channel;
}

byte Pot::getValue()
{
  _value = analogRead(_pin);
  int tmp = (_oldValue - _value);
  if (tmp >= 8 || tmp <= -8) {
    _oldValue = _value >> 3;
    _oldValue = _oldValue << 3;
    return _value >> 3;
  }
  return 255;
}

void Pot::newValue(byte command, byte value, byte channel) {
  Pcommand = command;
  Pcontrol = value;
  Pchannel = channel;
}

Comments

Similar projects you might like

Arduino MIDI Controller with Encoder + OLED Display + EEPROM

Project in progress by yilmazyurdakul

  • 24,691 views
  • 6 comments
  • 43 respects

Unopad - Arduino MIDI Controller with Ableton

Project tutorial by Stefan Vasic

  • 4,500 views
  • 5 comments
  • 9 respects

Arduino MIDI Arpeggiator

Project tutorial by Dmitry

  • 48,780 views
  • 63 comments
  • 149 respects

Arduino LED MIDI Controller with FL Studio

Project tutorial by reyadeetopee

  • 9,504 views
  • 1 comment
  • 21 respects

Arduino: Continuous MIDI Controller / Keyboard

Project tutorial by abhilash_patel

  • 6,206 views
  • 1 comment
  • 15 respects

Massive MIDI Controller for Full Bucket FB3100 Synthesizer

Project showcase by kboutorabi

  • 12,782 views
  • 4 comments
  • 41 respects
Add projectSign up / Login