Go Down

Topic: Arduino DUE sends Midi-Clock by Interrupt. Tempo set with Encoder (Read 142 times) previous topic - next topic

roundseven

Hello,

this is a small sketch for people who want to send midi-clock with the DUE. I use a rotary encoder with button function for tempo setting and start-stop. I tested it with the Synthstrom Deluge and its working fine.

Code: [Select]

/*
 * Midi Clock per interrupt on Serial1
 * Tempo set with a rotary encoder
 * Start/Stop with the encoder button.
 * See also pin reference Arduino DUE: https://www.arduino.cc/reference/en/language/functions/communication/serial/
 */

#include <DueTimer.h>
#define ENCODER_OPTIMIZE_INTERRUPTS
#include <Encoder.h>

const int midiClock = 0xf8;    // midic clock pulse byte
const int startByte = 0xfa;    // midi clock start byte
const int stopByte = 0xFC;     // midi clock stop byte

// rotary encoder pins
const int SW = 22;             
const int CLK = 24;
const int DT = 26;

// initializing the encoder object
Encoder Encoder(DT,CLK);

int encoderValue = 120;
int encoderValueOLD = 120;

// start bpm (beats per minute)
int bpm = 120;       
long interval = 60000000 / (24 * bpm);

bool startclock = true;

void setup() {
  // midi baut rate
  Serial1.begin(31250);

  pinMode(SW, INPUT);
  // read encoder button by interrupt. RISING: interrupt when button up
  attachInterrupt(digitalPinToInterrupt(SW), midiclock_STARTSTOP, RISING);

  // initialize Encoder with 120bpm * 4. The function "encoder_READ()" divides the value by 4 for exacter performance
  Encoder.write(480);

  // initializing midi clock interrupt timer
  Timer1.attachInterrupt(send_MIDICLOCK);

  // initializing encoder interrupt timer dependent on the bpm value (better results than with a fix value)
  Timer2.attachInterrupt(read_ENCODER);
  Timer2.start(interval);
}

void update_TEMPO() {
  interval = 60000000 / (24 * bpm);
 
  Timer1.start(interval);   // midi clock
  Timer2.start(interval);   // encoder
}

void send_MIDICLOCK() {
  if (startclock) {
    Serial1.write(midiClock);
  }
}

void midiclock_STARTSTOP() {
  startclock = !startclock;

  if (startclock) {
    Timer1.start(interval);
    Serial1.write(startByte);
  }
  else {
    Timer1.stop();
    Serial1.write(stopByte);
  }
}

void read_ENCODER() {
  // works better when dividing the encoder value by 4. Maybe it depends on the used encoder type
  // and you have to use a differnet dividor
  encoderValue = Encoder.read() / 4;
 
  if (encoderValue != encoderValueOLD) {
    encoderValueOLD = encoderValue;
   
    if (encoderValue > 240) {
      // upper tempo limit
      encoderValue = 240;
      // bpm * 4 cause of encoderValue = Encoder.read() / 4;
      Encoder.write(960);
    }
    else if (encoderValue < 40) {
      // lower tempo limit
      encoderValue = 40;
      Encoder.write(160);
    }

    bpm = encoderValue;
   
    update_TEMPO();
  }
}

void loop() {
  // main loop
}

roundseven

A version with the <RotaryEncoder.h> library. Better debouncing.

Code: [Select]

/*
* Midi Clock per interrupt on Serial1
* Tempo set with a rotary encoder
* Start/Stop with the encoder button.
* See also pin reference Arduino DUE: https://www.arduino.cc/reference/en/language/functions/communication/serial/
*/

#include <DueTimer.h>
#include <RotaryEncoder.h>

const int midiClock = 0xf8;    // midic clock pulse byte
const int startByte = 0xfa;    // midi clock start byte
const int stopByte = 0xFC;     // midi clock stop byte

// rotary encoder pins
const int SW = 46;            
const int CLK = 48;
const int DT = 50;

// initializing the encoder object
RotaryEncoder Encoder(DT,CLK);

int encoderValue = 120;
int encoderValueOLD = 120;

// start bpm (beats per minute)
int bpm = 120;        
long interval = 60000000 / (24 * bpm);

bool startclock = true;

void setup() {
 // midi baut rate
 Serial1.begin(31250);

 pinMode(SW, INPUT);
 // read encoder button by interrupt. RISING: interrupt when button up
 attachInterrupt(digitalPinToInterrupt(SW), midiclock_STARTSTOP, RISING);

 // initialize Encoder with 120bpm
 Encoder.setPosition(bpm);

 // initializing midi clock interrupt timer
 Timer0.attachInterrupt(send_MIDICLOCK);

 // initializing encoder interrupt timer dependent on the bpm value (better results than with a fix value)
 Timer1.attachInterrupt(read_ENCODER);
 Timer1.start(interval);
}

void update_TEMPO() {
 interval = 60000000 / (24 * bpm);

 Timer0.start(interval);   // midi clock
 Timer1.start(interval);   // encoder
}

void send_MIDICLOCK() {
 if (startclock) {
   Serial1.write(midiClock);
 }
}

void midiclock_STARTSTOP() {
 startclock = !startclock;

 if (startclock) {
   Timer0.start(interval);
   Serial1.write(startByte);
 }
 else {
   Timer0.stop();
   Serial1.write(stopByte);
 }
}

void read_ENCODER() {
 
 Encoder.tick();
 encoderValue = Encoder.getPosition();
 
 if (encoderValue != encoderValueOLD) {
   encoderValueOLD = encoderValue;

   if (encoderValue > 240) {
     // upper tempo limit
     encoderValue = 240;
   }
   else if (encoderValue < 40) {
     // lower tempo limit
     encoderValue = 40;
   }

   bpm = encoderValue;
   Encoder.setPosition(bpm);
   
   SerialUSB.println(bpm);
   update_TEMPO();
 }
}

void loop() {

}

Go Up