Commit 06ea48ce authored by Christian Fibich's avatar Christian Fibich
Browse files

Add midi_ftdi

parent c6c8e327
CFLAGS=-DFLUID -DMIDI_CHANNEL=0 -std=c99
LDFLAGS=-lm -lfluidsynth
SRC=midi_ftdi.c
midi_ftdi : $(SRC)
$(CC) $(CFLAGS) $(LDFLAGS) $^ -o $@
# MIDI FTDI #
Demo program that configures an FTDI with the MIDI baudrate
and parses midi commands.
## Prerequisites ##
* libfluidsynth-dev libfluidsynth1 fluidsynth
* Check where soundfonts are installed and tweak SOUNDFONT
* qjackctl patching may be necessary
## Getting Started ##
$ make
$ ./midi_ftdi /path/to/serial-if
/*
* Copyright (c) Christian Fibich, 2017
*
* Reads MIDI commands from the serial port given in first commandline
* argument and plays them back with fluidsynth.
*
* Prerequisites: libfluidsynth-dev libfluidsynth1 fluidsynth
* Check where soundfonts are installed and tweak SOUNDFONT
* qjackctl patching may be necessary
*/
#include <stdio.h>
#include <termios.h>
#include <unistd.h>
#include <assert.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <linux/serial.h>
#include <errno.h>
#include <signal.h>
#include <ctype.h>
#include <math.h>
#ifdef FLUID
#include <fluidsynth.h>
#define SOUNDFONT "/usr/share/sounds/sf2/FluidR3_GM.sf2"
#ifndef MIDI_CHANNEL
/* MIDI Instrument */
#define MIDI_CHANNEL 0
#endif
static fluid_settings_t* settings;
static fluid_synth_t* synth;
static fluid_audio_driver_t* adriver;
#endif
struct termios g_initialAtt;
unsigned char g_termflg = 0;
#define SPEED 31250
void handle(int a) {
(void) a;
g_termflg = 1;
}
#define NUM_OSC 8
enum midi_state {
EXPECT_COMMAND,
EXPECT_NOTE,
EXPECT_VELOCITY
};
enum midi_command {
NOTE_ON = 0x90,
NOTE_OFF = 0x80,
SYSTEM = 0xF0
};
int do_osc(int freq, int on) {
static int osc[NUM_OSC] = {0};
int i;
for (i = 0; i < NUM_OSC; i++) {
if (on && osc[i] == 0) {
osc[i] = freq;
break;
} else if (!on && osc[i] == freq) {
osc[i] = 0;
break;
}
}
return i;
}
void midi(unsigned char c) {
static enum midi_state ms = EXPECT_COMMAND;
static enum midi_command mc;
static int freq;
static int mn;
switch (ms) {
case EXPECT_COMMAND: {
mc = c & 0xF0;
switch (mc) {
case NOTE_ON:
case NOTE_OFF: ms = EXPECT_NOTE; break;
case SYSTEM:
/* handle system command here */
/* 0xFE is keep-alive */
break;
}
break;
}
case EXPECT_NOTE: {
if (c == 0xFE) ms = EXPECT_COMMAND; /* keep-alive signals that sequence is complete */
else {
mn = c;
freq = (int)(pow(2,((double)c - 21.0)/12.0)*27.5);
ms = EXPECT_VELOCITY;
}
break;
}
case EXPECT_VELOCITY: {
int midi_osc;
if (mc == NOTE_ON && c > 0) {
if ((midi_osc = do_osc(freq,1)) < NUM_OSC) {
printf("Note on: %d hz\n", freq);
#ifdef FLUID
if(synth) fluid_synth_noteon(synth,MIDI_CHANNEL,mn,100);
#endif
} else printf("No osc avail\n");
} else {
if ((midi_osc = do_osc(freq,0)) < NUM_OSC) {
printf("Note off: %d hz\n", freq);
#ifdef FLUID
if(synth) fluid_synth_noteoff(synth,MIDI_CHANNEL,mn);
#endif
} else printf("No osc avail\n");
}
ms = EXPECT_NOTE;
break;
}
}
}
int main(int argc, char *argv[])
{
assert(argc > 1);
int port = 0;
#ifdef FLUID
settings = new_fluid_settings();
synth = new_fluid_synth(settings);
adriver = new_fluid_audio_driver(settings, synth);
int sfont_id = fluid_synth_sfload(synth, SOUNDFONT, 1);
#endif
signal(SIGINT,handle);
assert((port = open(argv[1], O_RDWR | O_NOCTTY)) >= 0);
tcgetattr(port,&g_initialAtt);// save this to restore later
struct termios newAtt=g_initialAtt;
newAtt.c_cflag = B38400 | CS8 | CLOCAL | CREAD;
newAtt.c_lflag = 0;
newAtt.c_cc[VMIN] = 0;
newAtt.c_cc[VTIME] = 10;
//cfmakeraw(&newAtt);
tcsetattr(port,TCSANOW,&newAtt);
struct serial_struct serial_info;
if(ioctl(port, TIOCGSERIAL, &serial_info) < 0) {
printf("Error: could not get comm ioctl\n");
exit(0);
}
serial_info.custom_divisor = (serial_info.baud_base+SPEED/2)/SPEED;
serial_info.flags |= ASYNC_SPD_CUST;
if(ioctl(port, TIOCSSERIAL, &serial_info) < 0) {
printf("Error: could not set custom comm baud divisor\n");
exit(0);
}
char out[] = "is this the correct baud rate??\n";
write(port,out,sizeof(out));
char c;
int idx = 0;
while(1) {
int rv = read(port,&c,1);
if (rv == 0) {
#ifdef DEBUG
fprintf(stderr,"Read timeout.\n");
#endif
} else if (rv < 0) {
perror("read");
break;
} else {
#ifdef DEBUG
printf("%8d | %02x | %c\n", idx++, c&0xff, (isprint(c) && !isspace(c)) ? c : '.');
#else
midi(c);
#endif
}
if (g_termflg) break;
}
tcsetattr(port,TCSANOW,&g_initialAtt);
close(port);
return -1;
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment