Skip to content

Instantly share code, notes, and snippets.

@greed9
Created October 26, 2023 00:36
Show Gist options
  • Save greed9/982dd291a13458fd37d35724a332ea00 to your computer and use it in GitHub Desktop.
Save greed9/982dd291a13458fd37d35724a332ea00 to your computer and use it in GitHub Desktop.
// Turntable/sequencer to MIDI
// Tracks numbered zero-relative from the hub outwards
#define TRACK_3_PIN 51
#define TRACK_2_PIN 52
#define TRACK_1_PIN 49
#define TRACK_0_PIN 50
#define FLASH_PIN 4 // Flash LED strips when mark detected
#define INTERRUPT_PIN 48
#define pitchD3 50 // any old pitch for now, irrelevant for drum
#define pitchG2 43
#define pitchE2 40
#define pitchC1 24
#define CHANNEL 1 // channels will be 1-4
volatile uint32_t edge_detected = 0;
// info on Pins, Tracks and Notes
typedef struct track_type {
uint16_t pin ;
uint16_t status ;
uint16_t note ;
} TRACK ;
// maps optical tracks to hw pins
// Status of each track, mark not mark
static TRACK sensors[4] = {
{ TRACK_0_PIN, 0, pitchD3 },
{ TRACK_1_PIN, 0, pitchG2 },
{ TRACK_2_PIN, 0, pitchE2 },
{ TRACK_3_PIN, 0, pitchC1 }
} ;
// Logical structure of a MIDI message
typedef struct
{
uint8_t header;
uint8_t byte1;
uint8_t byte2;
uint8_t byte3;
} midiEventPacket_t;
// saw white to black
void optical_isr() {
edge_detected = 1;
}
// Send MIDI notes
void noteOn(byte channel, byte pitch, byte velocity) {
midiEventPacket_t noteOn = {0x09, 0x90 | channel, pitch, velocity};
sendMIDISerial(noteOn);
}
void noteOff(byte channel, byte pitch, byte velocity) {
midiEventPacket_t noteOff = {0x08, 0x80 | channel, pitch, velocity};
sendMIDISerial(noteOff);
}
void debugPrintMIDI( midiEventPacket_t event)
{
Serial.print (event.header);
Serial.print ( "," ) ;
Serial.print ( event.byte1 ) ;
Serial.print( ",") ;
Serial.print ( event.byte2 ) ;
Serial.print( ",") ;
Serial.print ( event.byte3 ) ;
Serial.println(";") ;
}
// low-level serial send
void sendMIDISerial(midiEventPacket_t event)
{
uint8_t data[4];
data[0] = event.header;
data[1] = event.byte1;
data[2] = event.byte2;
data[3] = event.byte3;
debugPrintMIDI( event ) ;
//Serial.write(data, 4);
}
// send note on and immediate note off for selected sensor(s)
void playNotes( TRACK sensor_array[4])
{
// send MIDI to serial for the tripped optical sensor
for( int i = 0 ; i < 4 ; i++)
{
if( sensor_array[i].status) {
noteOn(CHANNEL + i, sensor_array[i].note, 127) ;
// do I need/dare a delay here?
noteOff(CHANNEL + i, sensor_array[i].note, 127) ;
}
}
}
// One-time init
void setup() {
// MIDI runs at 31.25kbps
Serial.begin(31250);
// map track numbers to pin numbers
for( int i = 0 ; i < 4 ; i++ ) {
pinMode( sensors[i].pin, INPUT_PULLUP) ;
}
// Timing track
pinMode(INTERRUPT_PIN, INPUT_PULLUP);
// Control LED strip
pinMode( FLASH_PIN, OUTPUT) ;
//attachInterrupt(digitalPinToInterrupt(4), left, CHANGE);
attachInterrupt(digitalPinToInterrupt(INTERRUPT_PIN), optical_isr, FALLING);
}
// Event loop
void loop() {
uint16_t mark_detected = 0 ;
uint16_t current_pin_status = 0 ;
if (edge_detected) {
edge_detected = 0;
for( int i = 0 ; i < 4 ; i++ ) {
current_pin_status = !digitalRead( sensors[i].pin) ;
sensors[i].status = current_pin_status ;
mark_detected |= current_pin_status ;
}
// flash if any marks detected
if (mark_detected) {
digitalWrite( FLASH_PIN, 1 ) ;
playNotes(sensors) ;
}
else
{
digitalWrite( FLASH_PIN, 0) ;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment