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 <stdatomic.h>
|
||||
|
||||
static const char* devices[] = {"/dev/midi", "/dev/midi2", NULL};
|
||||
#include "midi_interface.h"
|
||||
|
||||
typedef struct Note
|
||||
{
|
||||
|
@ -20,7 +20,7 @@ typedef struct Note
|
|||
typedef struct Offset
|
||||
{
|
||||
signed char pitch;
|
||||
signed char velocity
|
||||
signed char velocity;
|
||||
} Offset;
|
||||
|
||||
static const Offset pattern[] = {
|
||||
|
@ -58,80 +58,78 @@ void *arpeggio_loop(void* data);
|
|||
|
||||
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;
|
||||
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_create(&arpeggio_thread, NULL, arpeggio_loop, (void*)fd);
|
||||
pthread_create(&arpeggio_thread, NULL, arpeggio_loop, (void*)&interface);
|
||||
|
||||
Message* message;
|
||||
create_message(&message);
|
||||
|
||||
for(;;)
|
||||
{
|
||||
read(fd, (void*)data, sizeof(data));
|
||||
|
||||
if(data[0] != 0xfd)
|
||||
result = read_midi_device(interface, message);
|
||||
if(result < 0)
|
||||
{
|
||||
if(data[2] > 0)
|
||||
fprintf(stderr, "Failed to read message: %s\n", midi_strerror(result));
|
||||
if(result == MIDI_UNKNOWN_STATUS_BYTE)
|
||||
{
|
||||
key_down = 1;
|
||||
note = ¤t_note;
|
||||
fprintf(stderr, "%x\n", message->type);
|
||||
exit(result);
|
||||
}
|
||||
}
|
||||
|
||||
current_note.channel = 0x90;
|
||||
current_note.pitch = data[1];
|
||||
current_note.velocity = data[2];
|
||||
}
|
||||
else if(data[1] == current_note.pitch)
|
||||
{
|
||||
key_down = 0;
|
||||
note = NULL;
|
||||
step = 0;
|
||||
}
|
||||
// if(message->type != SYSTEM_EXCLUSIVE)
|
||||
// printf("ch: %x, s: %x -- %02x %02x\n", message->channel, message->type, message->data[0], message->data[1]);
|
||||
|
||||
if(message->type == NOTE_ON)
|
||||
{
|
||||
key_down = 1;
|
||||
note = ¤t_note;
|
||||
|
||||
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);
|
||||
close(fd);
|
||||
free_message(message);
|
||||
close(interface.fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
if(note != NULL)
|
||||
{
|
||||
Note out = *note;
|
||||
out.pitch += pattern[step].pitch;
|
||||
out.velocity += pattern[step].velocity;
|
||||
write(fd, &out, sizeof(Note));
|
||||
message->data[0] = out.pitch + pattern[step].pitch;
|
||||
message->data[1] = out.velocity + pattern[step].velocity;
|
||||
int result = write_midi_device(*interface, message);
|
||||
if(result < 0)
|
||||
fprintf(stderr, "Failed to send message: %s\n", midi_strerror(result));
|
||||
|
||||
step++;
|
||||
if(step >= (sizeof(pattern) / sizeof(Offset)))
|
||||
|
@ -140,4 +138,6 @@ void *arpeggio_loop(void* data)
|
|||
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