refactored code slightly
This commit is contained in:
parent
ae75b01938
commit
f58cfd8bdc
102
src/main.c
102
src/main.c
|
@ -8,7 +8,7 @@
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <stdatomic.h>
|
#include <stdatomic.h>
|
||||||
|
|
||||||
static const char* devices[] = {"/dev/midi", "/dev/midi2", NULL};
|
#include "midi_interface.h"
|
||||||
|
|
||||||
typedef struct Note
|
typedef struct Note
|
||||||
{
|
{
|
||||||
|
@ -20,7 +20,7 @@ typedef struct Note
|
||||||
typedef struct Offset
|
typedef struct Offset
|
||||||
{
|
{
|
||||||
signed char pitch;
|
signed char pitch;
|
||||||
signed char velocity
|
signed char velocity;
|
||||||
} Offset;
|
} Offset;
|
||||||
|
|
||||||
static const Offset pattern[] = {
|
static const Offset pattern[] = {
|
||||||
|
@ -58,80 +58,78 @@ void *arpeggio_loop(void* data);
|
||||||
|
|
||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
unsigned char data[3] = {0, 0, 0};
|
MidiInterface interface;
|
||||||
|
int result = open_midi_device(&interface, NULL);
|
||||||
|
if(result < 0)
|
||||||
|
exit(result);
|
||||||
|
|
||||||
int key_down = 0;
|
int key_down = 0;
|
||||||
Note current_note;
|
Note current_note;
|
||||||
|
|
||||||
const char* device;
|
|
||||||
int fd;
|
|
||||||
int i = 0;
|
|
||||||
while((device = devices[i++]) != NULL)
|
|
||||||
{
|
|
||||||
printf("Trying %s...", device);
|
|
||||||
|
|
||||||
fd = open(device, O_RDWR, 0);
|
|
||||||
if(fd < 0)
|
|
||||||
{
|
|
||||||
printf("Failed: %s\n", strerror(errno));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
printf("Success!\n");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(fd < 0)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "No MIDI devices detected.\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("Using MIDI device %s\n", device);
|
|
||||||
pthread_t arpeggio_thread;
|
pthread_t arpeggio_thread;
|
||||||
pthread_create(&arpeggio_thread, NULL, arpeggio_loop, (void*)fd);
|
pthread_create(&arpeggio_thread, NULL, arpeggio_loop, (void*)&interface);
|
||||||
|
|
||||||
|
Message* message;
|
||||||
|
create_message(&message);
|
||||||
|
|
||||||
for(;;)
|
for(;;)
|
||||||
{
|
{
|
||||||
read(fd, (void*)data, sizeof(data));
|
result = read_midi_device(interface, message);
|
||||||
|
if(result < 0)
|
||||||
if(data[0] != 0xfd)
|
|
||||||
{
|
{
|
||||||
if(data[2] > 0)
|
fprintf(stderr, "Failed to read message: %s\n", midi_strerror(result));
|
||||||
|
if(result == MIDI_UNKNOWN_STATUS_BYTE)
|
||||||
{
|
{
|
||||||
key_down = 1;
|
fprintf(stderr, "%x\n", message->type);
|
||||||
note = ¤t_note;
|
exit(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
current_note.channel = 0x90;
|
// if(message->type != SYSTEM_EXCLUSIVE)
|
||||||
current_note.pitch = data[1];
|
// printf("ch: %x, s: %x -- %02x %02x\n", message->channel, message->type, message->data[0], message->data[1]);
|
||||||
current_note.velocity = data[2];
|
|
||||||
}
|
if(message->type == NOTE_ON)
|
||||||
else if(data[1] == current_note.pitch)
|
{
|
||||||
{
|
key_down = 1;
|
||||||
key_down = 0;
|
note = ¤t_note;
|
||||||
note = NULL;
|
|
||||||
step = 0;
|
current_note.channel = 0x90;
|
||||||
}
|
current_note.pitch = message->data[0];
|
||||||
|
current_note.velocity = message->data[1];
|
||||||
|
}
|
||||||
|
else if(message->type == NOTE_OFF && message->data[0] == note->pitch)
|
||||||
|
{
|
||||||
|
key_down = 0;
|
||||||
|
note = NULL;
|
||||||
|
step = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_join(arpeggio_thread, NULL);
|
pthread_join(arpeggio_thread, NULL);
|
||||||
close(fd);
|
free_message(message);
|
||||||
|
close(interface.fd);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *arpeggio_loop(void* data)
|
void *arpeggio_loop(void* data)
|
||||||
{
|
{
|
||||||
int fd = (int)data;
|
MidiInterface* interface = (MidiInterface*)data;
|
||||||
|
Message* message;
|
||||||
|
create_message(&message);
|
||||||
|
message->channel = 0;
|
||||||
|
message->length = 2;
|
||||||
|
message->type = NOTE_ON;
|
||||||
|
|
||||||
while(stop == 0)
|
while(stop == 0)
|
||||||
{
|
{
|
||||||
if(note != NULL)
|
if(note != NULL)
|
||||||
{
|
{
|
||||||
Note out = *note;
|
Note out = *note;
|
||||||
out.pitch += pattern[step].pitch;
|
message->data[0] = out.pitch + pattern[step].pitch;
|
||||||
out.velocity += pattern[step].velocity;
|
message->data[1] = out.velocity + pattern[step].velocity;
|
||||||
write(fd, &out, sizeof(Note));
|
int result = write_midi_device(*interface, message);
|
||||||
|
if(result < 0)
|
||||||
|
fprintf(stderr, "Failed to send message: %s\n", midi_strerror(result));
|
||||||
|
|
||||||
step++;
|
step++;
|
||||||
if(step >= (sizeof(pattern) / sizeof(Offset)))
|
if(step >= (sizeof(pattern) / sizeof(Offset)))
|
||||||
|
@ -140,4 +138,6 @@ void *arpeggio_loop(void* data)
|
||||||
usleep(166666);
|
usleep(166666);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
free_message(message);
|
||||||
}
|
}
|
81
src/message.c
Normal file
81
src/message.c
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
#include "message.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "midi_error.h"
|
||||||
|
|
||||||
|
void create_message(Message** message)
|
||||||
|
{
|
||||||
|
*message = (Message*)malloc(sizeof(Message));
|
||||||
|
(*message)->data = (uint8_t*)malloc(8);
|
||||||
|
}
|
||||||
|
|
||||||
|
void free_message(Message* message)
|
||||||
|
{
|
||||||
|
free(message->data);
|
||||||
|
free(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
int data_length(MessageType type)
|
||||||
|
{
|
||||||
|
switch(type)
|
||||||
|
{
|
||||||
|
case NOTE_ON: return 2;
|
||||||
|
case NOTE_OFF: return 2;
|
||||||
|
|
||||||
|
case SYSTEM_EXCLUSIVE: return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return MIDI_UNKNOWN_STATUS_BYTE;
|
||||||
|
}
|
||||||
|
|
||||||
|
int decode_status_byte(Message* message, uint8_t status)
|
||||||
|
{
|
||||||
|
message->channel = (status & 0xF);
|
||||||
|
message->type = (status & 0xF0);
|
||||||
|
switch(status & 0xF0)
|
||||||
|
{
|
||||||
|
case 0x90:
|
||||||
|
message->type = NOTE_ON;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x80:
|
||||||
|
message->type = NOTE_OFF;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xF0:
|
||||||
|
message->type = SYSTEM_EXCLUSIVE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return MIDI_UNKNOWN_STATUS_BYTE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int encode_status_byte(const Message* message, uint8_t* status)
|
||||||
|
{
|
||||||
|
*status = 0;
|
||||||
|
*status |= (message->channel & 0xF);
|
||||||
|
|
||||||
|
switch(message->type)
|
||||||
|
{
|
||||||
|
case NOTE_ON:
|
||||||
|
*status |= 0x90;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NOTE_OFF:
|
||||||
|
*status |= 0x80;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SYSTEM_EXCLUSIVE:
|
||||||
|
*status |= 0xF0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return MIDI_UNKNOWN_STATUS_BYTE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
28
src/message.h
Normal file
28
src/message.h
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
#ifndef _MESSAGE_H_
|
||||||
|
#define _MESSAGE_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
typedef enum MessageType
|
||||||
|
{
|
||||||
|
NOTE_OFF, NOTE_ON,
|
||||||
|
SYSTEM_EXCLUSIVE
|
||||||
|
} MessageType;
|
||||||
|
|
||||||
|
typedef struct Message
|
||||||
|
{
|
||||||
|
uint8_t channel;
|
||||||
|
MessageType type;
|
||||||
|
|
||||||
|
int length;
|
||||||
|
uint8_t* data;
|
||||||
|
} Message;
|
||||||
|
|
||||||
|
void create_message(Message** message);
|
||||||
|
void free_message(Message* message);
|
||||||
|
|
||||||
|
int data_length(MessageType type);
|
||||||
|
int decode_status_byte(Message* message, uint8_t status);
|
||||||
|
int encode_status_byte(const Message* message, uint8_t* status);
|
||||||
|
|
||||||
|
#endif
|
15
src/midi_error.c
Normal file
15
src/midi_error.c
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
#include "midi_error.h"
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
static const char* error_messages[] = {
|
||||||
|
NULL, NULL,
|
||||||
|
"Failed to read from MIDI device.",
|
||||||
|
"Failed to write to MIDI device.",
|
||||||
|
"Unknown MIDI status byte"
|
||||||
|
};
|
||||||
|
|
||||||
|
const char* midi_strerror(MidiError error)
|
||||||
|
{
|
||||||
|
return error_messages[-error];
|
||||||
|
}
|
13
src/midi_error.h
Normal file
13
src/midi_error.h
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
#ifndef _MIDI_ERROR_H_
|
||||||
|
#define _MIDI_ERROR_H_
|
||||||
|
|
||||||
|
typedef enum MidiError
|
||||||
|
{
|
||||||
|
MIDI_READ_ERROR = -2,
|
||||||
|
MIDI_WRITE_ERROR = -3,
|
||||||
|
MIDI_UNKNOWN_STATUS_BYTE = -4
|
||||||
|
} MidiError;
|
||||||
|
|
||||||
|
const char* midi_strerror(MidiError error);
|
||||||
|
|
||||||
|
#endif
|
90
src/midi_interface.c
Normal file
90
src/midi_interface.c
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
#include "midi_interface.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <memory.h>
|
||||||
|
|
||||||
|
static const char* devices[] = {"/dev/midi", "/dev/midi2", NULL};
|
||||||
|
|
||||||
|
int try_open_device(const char* device);
|
||||||
|
|
||||||
|
int open_midi_device(MidiInterface* interface, const char* device)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
if(device != NULL)
|
||||||
|
{
|
||||||
|
fd = try_open_device(device);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
while((device = devices[i++]) != NULL)
|
||||||
|
{
|
||||||
|
fd = try_open_device(device);
|
||||||
|
if(fd >= 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(device == NULL)
|
||||||
|
fprintf(stderr, "Failed to locate MIDI device.\n");
|
||||||
|
else if(fd < 0)
|
||||||
|
fprintf(stderr, "Failed to open MIDI device %s\n", device);
|
||||||
|
else
|
||||||
|
printf("Using device %s\n", device);
|
||||||
|
|
||||||
|
interface->fd = fd;
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
int read_midi_device(MidiInterface interface, Message* buffer)
|
||||||
|
{
|
||||||
|
uint8_t status;
|
||||||
|
int result = read(interface.fd, &status, 1);
|
||||||
|
if(result < 0)
|
||||||
|
return MIDI_READ_ERROR;
|
||||||
|
|
||||||
|
result = decode_status_byte(buffer, status);
|
||||||
|
if(result < 0)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
buffer->length = data_length(buffer->type);
|
||||||
|
if(buffer->length < 0)
|
||||||
|
return buffer->length;
|
||||||
|
|
||||||
|
result = read(interface.fd, buffer->data, buffer->length);
|
||||||
|
if(result < 0)
|
||||||
|
return MIDI_READ_ERROR;
|
||||||
|
|
||||||
|
if(buffer->type == NOTE_ON && buffer->data[1] == 0)
|
||||||
|
{
|
||||||
|
buffer->type = NOTE_OFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int write_midi_device(MidiInterface interface, const Message* buffer)
|
||||||
|
{
|
||||||
|
uint8_t status;
|
||||||
|
int result = encode_status_byte(buffer, &status);
|
||||||
|
if(result < 0)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
uint8_t* buffer_out = (uint8_t*)malloc(1 + buffer->length);
|
||||||
|
buffer_out[0] = status;
|
||||||
|
memcpy(buffer_out + 1, buffer->data, buffer->length);
|
||||||
|
|
||||||
|
result = write(interface.fd, buffer_out, 1 + buffer->length);
|
||||||
|
if(result < 0)
|
||||||
|
return MIDI_WRITE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
int try_open_device(const char* device)
|
||||||
|
{
|
||||||
|
int fd = open(device, O_RDWR, 0);
|
||||||
|
|
||||||
|
return fd;
|
||||||
|
}
|
20
src/midi_interface.h
Normal file
20
src/midi_interface.h
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
#ifndef _MIDI_INTERFACE_H_
|
||||||
|
#define _MIDI_INTERFACE_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "message.h"
|
||||||
|
#include "midi_error.h"
|
||||||
|
|
||||||
|
typedef struct MidiInterface
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
} MidiInterface;
|
||||||
|
|
||||||
|
int open_midi_device(MidiInterface* interface, const char* device);
|
||||||
|
|
||||||
|
int read_midi_device(MidiInterface interface, Message* buffer);
|
||||||
|
int write_midi_device(MidiInterface interface, const Message* buffer);
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in a new issue