|
|
|
|
@ -1,5 +1,4 @@
|
|
|
|
|
|
|
|
|
|
// TODO: gate on/off controls, can just use hardware GPIO in digital mode
|
|
|
|
|
// TODO: update README with wiring instructions for SPI to DAC
|
|
|
|
|
// TODO: DAC voltage stepping
|
|
|
|
|
// if we use DAC input 4080 = 5V, then we can do steps of 1/12V on exactly
|
|
|
|
|
@ -13,10 +12,13 @@
|
|
|
|
|
#include <unistd.h> |
|
|
|
|
#include <linux/spi/spi.h> |
|
|
|
|
|
|
|
|
|
#include "spi.h" |
|
|
|
|
#include "spi.h" // FIXME: should rename to gpio.h |
|
|
|
|
#include "midi.h" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define GPIO_CHIP_NAME "gpiochip1" |
|
|
|
|
#define GPIO_LINE_NUM 82 // GPIO Pin #38 on 'le-potato'
|
|
|
|
|
|
|
|
|
|
#define SPI_SPEED 1000000 |
|
|
|
|
#define SPI_BUFFER_LENGTH 2 |
|
|
|
|
#define SPI_CHANNEL 0 |
|
|
|
|
@ -57,18 +59,49 @@ convertNoteToDACInput(u8 midi_note)
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void |
|
|
|
|
loopMIDI(alsa_sequencer* seq, spi_connection* spi) |
|
|
|
|
loopMIDI(alsa_sequencer* seq, spi_connection* spi, gpio_info* gpio) |
|
|
|
|
{ |
|
|
|
|
// TODO: there's probably a more elegant way to handle this, but this was
|
|
|
|
|
// the first idea that came up, and seems to work
|
|
|
|
|
// NOTE: MIDI Note '0' is a vaild note, but 255 is not. So, we'll use 255
|
|
|
|
|
// as a placeholder to represent an unused PLAYING_NOTE
|
|
|
|
|
static const u32 MAX_NOTES = 6; |
|
|
|
|
static u8 PLAYING_NOTES[MAX_NOTES] = {255,255,255,255,255,255}; |
|
|
|
|
|
|
|
|
|
while(1) |
|
|
|
|
{ |
|
|
|
|
printf("\n--------------------\n"); |
|
|
|
|
snd_seq_event_t *ev = nullptr; |
|
|
|
|
snd_seq_event_input(seq->seq_handle, &ev); |
|
|
|
|
i32 note = midiProcess(ev); |
|
|
|
|
|
|
|
|
|
if (note >= 0) { |
|
|
|
|
i32 dac_in = convertNoteToDACInput(note); |
|
|
|
|
// FIXME: we should only be processing notes from the first channel
|
|
|
|
|
alsa_note_event nev = midiProcess(ev); |
|
|
|
|
bool note_tracked = false; |
|
|
|
|
|
|
|
|
|
for (u32 i = 0; i < MAX_NOTES; i++) { |
|
|
|
|
if (PLAYING_NOTES[i] == nev.note) { |
|
|
|
|
note_tracked = true; |
|
|
|
|
|
|
|
|
|
if (nev.note_on) { // do nothing
|
|
|
|
|
break; |
|
|
|
|
} else { // remove note from tracked list
|
|
|
|
|
assert(gpioSetValue(gpio, 0)); // send set gate off
|
|
|
|
|
PLAYING_NOTES[i] = 255; |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// send note voltage to DAC, and add note to tracked list
|
|
|
|
|
if (!note_tracked && nev.note_on ) { |
|
|
|
|
for (u32 i = 0; i < MAX_NOTES; i++) { |
|
|
|
|
if (PLAYING_NOTES[i] == 255) { |
|
|
|
|
PLAYING_NOTES[i] = nev.note; |
|
|
|
|
assert(gpioSetValue(gpio, 1)); // send set gate on
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
i32 dac_in = convertNoteToDACInput(nev.note); |
|
|
|
|
// TODO: could check return value here for SPI error
|
|
|
|
|
spiSendVoltage(spi, dac_in); |
|
|
|
|
} |
|
|
|
|
@ -101,6 +134,11 @@ main(i32 argc, char* argv[])
|
|
|
|
|
u8 spi_buf[SPI_BUFFER_LENGTH] = {0}; |
|
|
|
|
spi_connection spi = spiInit(SPI_SPEED, MAX_DAC_INPUT, spi_buf, SPI_BUFFER_LENGTH, SPI_FLAGS, SPI_CHANNEL); |
|
|
|
|
|
|
|
|
|
gpio_info gpio = {0}; |
|
|
|
|
|
|
|
|
|
if (!gpioInit(&gpio, GPIO_CHIP_NAME, GPIO_LINE_NUM)) |
|
|
|
|
return 1; |
|
|
|
|
|
|
|
|
|
if (spi.fd < 0) { |
|
|
|
|
printf("error opening SPI device\n"); |
|
|
|
|
return 1; |
|
|
|
|
@ -112,7 +150,7 @@ main(i32 argc, char* argv[])
|
|
|
|
|
while ((opt = getopt(argc, argv, "tlk:h")) != -1) { |
|
|
|
|
switch (opt) { |
|
|
|
|
case 'l': |
|
|
|
|
loopMIDI(&seq, &spi); |
|
|
|
|
loopMIDI(&seq, &spi, &gpio); |
|
|
|
|
break; |
|
|
|
|
case 'k': |
|
|
|
|
if (!midiConnect(&seq, optarg)) { |
|
|
|
|
@ -120,7 +158,7 @@ main(i32 argc, char* argv[])
|
|
|
|
|
exit(1); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
loopMIDI(&seq, &spi); |
|
|
|
|
loopMIDI(&seq, &spi, &gpio); |
|
|
|
|
break; |
|
|
|
|
case 't': |
|
|
|
|
loopTestVoltages(&spi); |
|
|
|
|
|