Last active
September 28, 2021 04:57
-
-
Save cowboy/5ad43d0d369c79b6d6538f076698e17a to your computer and use it in GitHub Desktop.
Akai Force Rec Pedal (USB MIDI) - for Teensy LC
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// =============================================================== | |
// 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; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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 | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
See newer version with 8x8 LED matrix https://gist.github.com/cowboy/6c2230d54aea58577c5b7953ea86aebe