Skip to content

Instantly share code, notes, and snippets.

@cowboy
Last active September 28, 2021 04:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cowboy/5ad43d0d369c79b6d6538f076698e17a to your computer and use it in GitHub Desktop.
Save cowboy/5ad43d0d369c79b6d6538f076698e17a to your computer and use it in GitHub Desktop.
Akai Force Rec Pedal (USB MIDI) - for Teensy LC
// ===============================================================
// Akai Force Rec Pedal (USB MIDI) - for Teensy LC
// "Cowboy" Ben Alman, 2021
// https://gist.github.com/cowboy/5ad43d0d369c79b6d6538f076698e17a
// ===============================================================
// Why does this exist?
//
// I designed this to circumvent an issue with the Akai Force where receiving
// an MMC Rec message signals that the loop should end at the end of the
// current measure BUT it also stops recording the current clip at the moment
// MMC Rec is received, NOT at the end of the measure, which makes it very hard
// to end loop recording via foot pedal in a musical way.
//
// Usage
//
// While recording:
// - Press the pedal to queue an MMC Rec message to be sent at the end of the
// current measure. This will a) tell Force that it should set the loop length
// to the end of the measure and b) turn recording mode off at the end of the
// measure.
// - If you hold the pedal past the end of the measure, it will do "a" above
// but keep recording mode on, instead of turing it off.
// - If you press the pedal again before the end of the current measure, it
// will cancel the previous queued behavior.
//
// While not recording:
// - Press the pedal to queue an MMC Rec message to be sent at the end of
// the current measure.
// - If you press the pedal again before the end of the current measure, it
// will cancel the previous queued behavior.
//
// In order for this to work, you need to ensure the Force is set to send "MIDI
// Clock" and "Receive MMC" and be sure to enable "Sync" on the "Cowboy Akai
// Force Rec Pedal" Output Port. Also, note that because MIDI clock is dumb,
// this device can't know about any other time signature than what is hard-coded
// into it, which in this case is 4. I don't think Force supports anything other
// than 4/4 time, but if you want to change this, see BEATS_PER_MEASURE.
//
// How do I build this?
//
// This requires a momentary (normally open) foot pedal, like the Yamaha FC5.
//
// In order to use a foot pedal, I found the easiest way was to wire a 1/4" mono
// jack to a Teensy LC, and use an existing foot pedal. You'll probably want to
// put it in a project box of some kind.
//
// * Teensy LC https://www.pjrc.com/store/teensylc.html
// * 1/4" Mono Jack https://www.switchcraft.com/Category_Multi.aspx?Parent=952
// * Project Box https://www.hammfg.com/electronics/small-case
//
// How do I program this?
//
// Program with the Arduino IDE and Teensyduino. Their instructions are pretty
// comprehensive, but you may also want to read some guides or tutorials.
// Have fun!
//
// * Arduino IDE https://www.arduino.cc/en/software
// * Teensyduino https://www.pjrc.com/teensy/teensyduino.html
#include <Bounce.h>
// Assume 4/4 time
int BEATS_PER_MEASURE = 4;
int PPQN = 24;
int MAX_PULSES = PPQN * BEATS_PER_MEASURE;
// Change these pins if desired
int SWITCH_PIN = 0;
int LED_PIN = LED_BUILTIN;
Bounce button0 = Bounce(SWITCH_PIN, 5);
byte counter;
byte button_pressed = 0;
byte rec_toggle_pending = 0;
byte clock_running = 0;
byte led_lit = 0;
void setup() {
Serial.begin(115200);
// Setup pins
pinMode(SWITCH_PIN, INPUT_PULLUP);
pinMode(LED_PIN, OUTPUT);
// MIDI message handlers
usbMIDI.setHandleClock(onClock);
usbMIDI.setHandleStart(onStart);
usbMIDI.setHandleContinue(onContinue);
usbMIDI.setHandleStop(onStop);
blink(5);
}
void led_on() {
led_lit = 1;
digitalWrite(LED_PIN, HIGH);
}
void led_off() {
led_lit = 0;
digitalWrite(LED_PIN, LOW);
}
void led_toggle() {
if (led_lit) {
led_off();
} else {
led_on();
}
}
void blink(int count) {
for (int i = 0; i < count; i++) {
led_on();
delay(50);
led_off();
delay(50);
}
}
void loop() {
button0.update();
// Pedal pressed
if (button0.risingEdge()) {
button_pressed = 1;
if (clock_running) {
// Toggle pending state
rec_toggle_pending = 1 - rec_toggle_pending;
// Turn the LED on or off accordingly
if (rec_toggle_pending) {
led_on();
} else {
led_off();
}
} else {
// Complain if pressed when the clock is not running
blink(2);
}
}
// Pedal released
else if (button0.fallingEdge()) {
button_pressed = 0;
}
usbMIDI.read();
}
void send_rec() {
static uint8_t mmc_rec[6] = {0xF0, 0x7F, 0x7F, 0x06, 0x06, 0xF7};
usbMIDI.sendSysEx(6, mmc_rec);
}
void onClock() {
if (++counter == MAX_PULSES) {
counter = 0;
// Send rec message if pending
if (rec_toggle_pending) {
rec_toggle_pending = 0;
send_rec();
// Since this is the beginning of the measure, send again
// if the pedal is held down
if (button_pressed) {
send_rec();
}
}
}
if (counter == 0) {
led_on();
} else if (counter % PPQN == 0 || counter == 2) {
led_toggle();
} else if (counter % PPQN == 1 || counter == 3) {
led_toggle();
} else if (counter == MAX_PULSES - 2) {
led_off();
}
}
void onStart() {
Serial.println("Start");
led_on();
counter = 0;
clock_running = 1;
rec_toggle_pending = 0;
}
void onContinue() {
Serial.println("Continue");
clock_running = 1;
}
void onStop() {
Serial.println("Stop");
led_off();
clock_running = 0;
rec_toggle_pending = 0;
}
// To give your project a unique name, this code must be
// placed into a .c file (its own tab). It can not be in
// a .cpp file or your main sketch (the .ino file).
#include "usb_names.h"
// Edit these lines to create your own name. The length must
// match the number of characters in your custom name.
#define MIDI_NAME {'C', 'o', 'w', 'b', 'o', 'y', ' ', 'A', 'k', 'a', 'i', ' ', 'F', 'o', 'r', 'c', 'e', ' ', 'R', 'e', 'c', ' ', 'P', 'e', 'd', 'a', 'l'}
#define MIDI_NAME_LEN 27
// Do not change this part. This exact format is required by USB.
struct usb_string_descriptor_struct usb_string_product_name = {
2 + MIDI_NAME_LEN * 2,
3,
MIDI_NAME
};
@cowboy
Copy link
Author

cowboy commented Sep 28, 2021

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment