refactored code slightly

This commit is contained in:
Lauchmelder 2022-04-09 01:07:53 +02:00
parent ae75b01938
commit f58cfd8bdc
7 changed files with 298 additions and 51 deletions

View file

@ -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 = &current_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 = &current_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
View 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
View 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
View 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
View 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
View 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
View 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