Browse Source

add GPIO note gate functions to control synth VCA

main
cinnaboot 3 years ago
parent
commit
87c5ce0bd0
  1. 2
      Makefile
  2. 54
      src/main.cpp
  3. 19
      src/midi.cpp
  4. 9
      src/midi.h
  5. 52
      src/spi.cpp
  6. 19
      src/spi.h

2
Makefile

@ -1,7 +1,7 @@
CXX=g++
CXXFLAGS= -std=c++11 -g -ggdb3 -Wall
LDFLAGS=-lasound
LDFLAGS=-lasound -lgpiod
OBJDIR = build
SRCDIR = src

54
src/main.cpp

@ -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);

19
src/midi.cpp

@ -63,22 +63,27 @@ midiConnect(alsa_sequencer* seq, const char* midi_device)
return false;
}
i32
alsa_note_event
midiProcess(const snd_seq_event_t* ev)
{
assert(ev != nullptr);
i32 note = -1;
alsa_note_event nev = {0};
if((ev->type == SND_SEQ_EVENT_NOTEON) ||
(ev->type == SND_SEQ_EVENT_NOTEOFF))
{
const char *type = (ev->type==SND_SEQ_EVENT_NOTEON) ? "on " : "off";
printf("[%d] Note %s: %d, 0x%2x vel(%2x)\n",
ev->time.tick, type,
printf("[%d] Note %s: %d, 0x%2x vel(%2x), channel: %d\n",
ev->time.tick,
type,
ev->data.note.note,
ev->data.note.note,
ev->data.note.velocity);
note = ev->data.note.note;
ev->data.note.velocity,
ev->data.note.channel);
nev.note = ev->data.note.note;
nev.channel = ev->data.note.channel;
nev.note_on = (ev->type == SND_SEQ_EVENT_NOTEON) ? true : false;
}
else if(ev->type == SND_SEQ_EVENT_CONTROLLER)
{
@ -92,7 +97,7 @@ midiProcess(const snd_seq_event_t* ev)
printf("[%d] Unknown: Unhandled Event Received\n", ev->time.tick);
}
return note;
return nev;
}
i32

9
src/midi.h

@ -14,11 +14,18 @@ struct alsa_sequencer
snd_seq_addr_t dest;
};
struct alsa_note_event
{
u8 note;
u8 channel;
bool note_on;
};
bool midiOpen(alsa_sequencer* seq);
bool midiConnect(alsa_sequencer* seq, const char* midi_device);
i32 midiProcess(const snd_seq_event_t* ev);
alsa_note_event midiProcess(const snd_seq_event_t* ev);
i32 midiClose(alsa_sequencer* seq);

52
src/spi.cpp

@ -1,6 +1,7 @@
#include <cassert>
#include <cstdio>
#include <cstring>
#include <fcntl.h>
#include <unistd.h>
#include <linux/types.h>
@ -9,6 +10,57 @@
#include "spi.h"
// GPIO
bool
gpioInit(gpio_info* gpio, const char* chip_name, u32 line_num)
{
strncpy(gpio->chip_name, chip_name, sizeof(gpio->chip_name));
gpio->line_num = line_num;
gpio->chip = gpiod_chip_open_by_name(gpio->chip_name);
if (!gpio->chip) {
printf("Error opening chip, %s\n", gpio->chip_name);
return false;
}
gpio->line = gpiod_chip_get_line(gpio->chip, line_num);
if (!gpio->line) {
printf("Error opening line, chip: %s, line: %d\n", gpio->chip_name, line_num);
gpiod_chip_close(gpio->chip);
return false;
}
i32 ret = gpiod_line_request_output(gpio->line, "Consumer", 0);
if (ret < 0) {
printf("Error setting line output, chip: %s, line: %d\n", gpio->chip_name, line_num);
gpiod_line_release(gpio->line);
gpiod_chip_close(gpio->chip);
return false;
}
return true;
}
bool
gpioSetValue(gpio_info* gpio, u32 value)
{
assert(gpio);
i32 ret = gpiod_line_set_value(gpio->line, value);
if (ret < 0) {
printf("Error setting line value, chip: %s, line: %d\n", gpio->chip_name, gpio->line_num);
return false;
}
return true;
}
// SPI
i32 open_device(u8 channel, u32 speed, u8 mode_flags);

19
src/spi.h

@ -3,10 +3,28 @@
#include <linux/spi/spi.h>
#include <linux/spi/spidev.h>
#include <gpiod.h>
#include "types.h"
// GPIO
struct gpio_info
{
char chip_name[16];
u32 line_num;
gpiod_chip* chip;
gpiod_line* line;
};
bool gpioInit(gpio_info* gpio, const char* chip_name, u32 line_num);
bool gpioSetValue(gpio_info* gpio, u32 value);
// SPI
struct spi_connection
{
i32 fd;
@ -17,7 +35,6 @@ struct spi_connection
u8* buffer;
};
spi_connection spiInit(u32 speed, u32 max_dac_input, u8* buf, u32 buf_len, u8 flags, u8 channel);
bool spiWrite(i32 fd, u32 speed, u8* buf, u32 buf_len);

Loading…
Cancel
Save