summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile4
-rw-r--r--documents/sfspec24.pdfbin0 -> 530464 bytes
-rw-r--r--main.c65
-rw-r--r--midi.c109
-rw-r--r--midi.h16
5 files changed, 175 insertions, 19 deletions
diff --git a/Makefile b/Makefile
index 41533ef..98a41d3 100644
--- a/Makefile
+++ b/Makefile
@@ -1,9 +1,9 @@
CC := cc
CFLAGS := -Wall -Wextra -Wshadow -Wunused -Wswitch-enum -Wpedantic -Wundef
LDFLAGS := -lm -ldl -lpthread -lasound
-CFILES := main.c minisdl_audio.c
+FILES := main.c midi.c minisdl_audio.c
PROG := ttdaw
$(PROG): main.c
- $(CC) $(CFLAGS) -o $(PROG) $(CFILES) $(LDFLAGS)
+ $(CC) $(CFLAGS) -o $(PROG) $(FILES) $(LDFLAGS)
diff --git a/documents/sfspec24.pdf b/documents/sfspec24.pdf
new file mode 100644
index 0000000..252aff9
--- /dev/null
+++ b/documents/sfspec24.pdf
Binary files differ
diff --git a/main.c b/main.c
index c196cdd..3a45592 100644
--- a/main.c
+++ b/main.c
@@ -2,32 +2,48 @@
#include <stdlib.h>
#include <stdarg.h>
#include <getopt.h>
+#include <pthread.h>
#include "version.h"
+#include "midi.h"
void help(const char *argv0) {
printf("Usage: %s [options]\n"
"\nAvailable options:\n"
- " -h,--help this help\n"
- " -v,--version show version\n"
- " -l,--list list available devices\n"
- " -p,--port=client:port device port\n",
+ " -l,--list list available devices\n"
+ " -p,--port=client:port device port\n"
+ " -s,--soundfont=file.sf2 soundfont file\n"
+ " -h,--help this help\n"
+ " -v,--version show version\n",
argv0);
}
int main(int argc, char *argv[]) {
- const char short_options[] = "hvlp";
+ const char short_options[] = "lp:s:hv:";
const struct option long_options[] = {
- { "help", 0, NULL, 'h' },
- { "version", 0, NULL, 'v' },
{ "list", 0, NULL, 'l' },
{ "port", 1, NULL, 'p' },
+ { "soundfont", 1, NULL, 's' },
+ { "help", 0, NULL, 'h' },
+ { "version", 0, NULL, 'v' },
{ 0 },
};
- int c;
- while ((c = getopt_long(argc, argv, short_options, long_options, NULL)) != -1) {
- switch (c) {
+ char *port_name = NULL;
+ char *soundfont_file = NULL;
+
+ int opt;
+ while ((opt = getopt_long(argc, argv, short_options, long_options, NULL)) != -1) {
+ switch (opt) {
+ case 'l':
+ fprintf(stderr, "List feature is NOT implemented yet.\n");
+ return 0;
+ case 'p':
+ port_name = optarg;
+ break;
+ case 's':
+ soundfont_file = optarg;
+ break;
case 'h':
help(argv[0]);
return 0;
@@ -38,18 +54,33 @@ int main(int argc, char *argv[]) {
fprintf(stdout, "%s\n", TTDAW_WARRANTY);
fprintf(stdout, "\n%s\n", TTDAW_AUTHOR);
return 0;
- case 'l':
- fprintf(stderr, "List feature is NOT implemented yet.\n");
- return 0;
- case 'p':
- fprintf(stderr, "Port feature is NOT implemented yet.\n");
- return 0;
default:
- fprintf(stdout, "No option provided\n");
+ fprintf(stdout, "Missing options. Check help.\n");
return 0;
}
}
+ if (port_name == NULL || soundfont_file == NULL) {
+ fprintf(stdout, "Missing options. Check help.\n\n");
+ fprintf(stdout, "Port and soundfile are required fields.\n\n");
+ return 1;
+ }
+
+ fprintf(stdout, "> Device port: %s\n", port_name);
+ fprintf(stdout, "> Soundfont: %s\n", soundfont_file);
+
+ // Create and start MIDI thread.
+ pthread_t midi_thread;
+ MidiArgs midi_args = { port_name };
+
+ if (pthread_create(&midi_thread, NULL, midi, (void*)&midi_args) != 0) {
+ fprintf(stderr, "Error creating midi thread\n");
+ return 1;
+ }
+
+ pthread_join(midi_thread, NULL);
+
+ fprintf(stdout, "Exiting...\n");
return 0;
}
diff --git a/midi.c b/midi.c
new file mode 100644
index 0000000..3d21f79
--- /dev/null
+++ b/midi.c
@@ -0,0 +1,109 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <alloca.h>
+#include <unistd.h>
+#include <alsa/asoundlib.h>
+
+#include "midi.h"
+
+static snd_seq_t *seq_handle;
+static snd_seq_addr_t *ports;
+
+void *midi(void *arg) {
+ MidiArgs* args = (MidiArgs*)arg;
+
+ while (1) {
+ if (snd_seq_open(&seq_handle, "default", SND_SEQ_OPEN_DUPLEX, 0) < 0) {
+ fprintf(stderr, "Error opening ALSA sequencer.\n");
+ exit(1);
+ }
+
+ if (snd_seq_set_client_name(seq_handle, CLIENT_NAME) < 0) {
+ fprintf(stderr, "Could not set up client name.\n");
+ exit(1);
+ }
+
+ if (snd_seq_create_simple_port(seq_handle, CLIENT_NAME,
+ SND_SEQ_PORT_CAP_WRITE |
+ SND_SEQ_PORT_CAP_SUBS_WRITE,
+ SND_SEQ_PORT_TYPE_MIDI_GENERIC |
+ SND_SEQ_PORT_TYPE_APPLICATION) < 0) {
+ fprintf(stderr, "Error creating sequencer port.\n");
+ exit(1);
+ }
+
+ // Connecting ports.
+ ports = realloc(ports, MAX_MIDI_PORTS * sizeof(snd_seq_addr_t));
+ if (snd_seq_parse_address(seq_handle, &ports[0], args->port_name) < 0) {
+ fprintf(stderr, "Invalid port %s.\n", args->port_name);
+ exit(1);
+ }
+
+ // Listing assigned ports.
+ fprintf(stdout, "Ports:\n");
+ for (int j = 0; j < MAX_MIDI_PORTS; j++) {
+ fprintf(stdout, " client: %d, port: %d\n", ports[j].client, ports[j].port);
+ }
+
+ // Connecting ports.
+ for (int i = 0; i < MAX_MIDI_PORTS; ++i) {
+ int err = snd_seq_connect_from(seq_handle, 0, ports[i].client, ports[i].port);
+ if (err < 0) {
+ fprintf(stderr, "Cannot connect from port %d:%d - %s", ports[i].client, ports[i].port, snd_strerror(err));
+ exit(1);
+ }
+ }
+
+ if (snd_seq_nonblock(seq_handle, 1) < 0) {
+ fprintf(stderr, "Set nonblock mode failed.");
+ exit(1);
+ }
+
+
+ // Reading MIDI device.
+ struct pollfd *pfds;
+ size_t npfds;
+
+ npfds = snd_seq_poll_descriptors_count(seq_handle, POLLIN);
+ pfds = alloca(sizeof(*pfds) * npfds);
+
+ for (;;) {
+ snd_seq_poll_descriptors(seq_handle, pfds, npfds, POLLIN);
+ if (poll(pfds, npfds, -1) < 0) {
+ break;
+ }
+
+ for (;;) {
+ snd_seq_event_t *ev;
+
+ if (snd_seq_event_input(seq_handle, &ev) < 0) {
+ break;
+ }
+
+ if (ev) {
+ switch (ev->type) {
+ case SND_SEQ_EVENT_NOTEON:
+ printf("%3d:%-3dNote on %2d, note %d, velocity: %3d\n",
+ ev->source.client, ev->source.port,
+ ev->data.note.channel,
+ ev->data.note.note,
+ ev->data.note.velocity);
+ break;
+
+ case SND_SEQ_EVENT_NOTEOFF:
+ printf("%3d:%-3dNote off\t%2d, note %d\n",
+ ev->source.client, ev->source.port,
+ ev->data.note.channel,
+ ev->data.note.note);
+ break;
+
+
+ }
+ }
+ }
+
+ fflush(stdout);
+ }
+ }
+}
+
diff --git a/midi.h b/midi.h
new file mode 100644
index 0000000..81b105b
--- /dev/null
+++ b/midi.h
@@ -0,0 +1,16 @@
+#include <alsa/asoundlib.h>
+
+#ifndef MIDI_H_
+#define MIDI_H_
+
+#define CLIENT_NAME "ttdaw"
+#define MAX_MIDI_PORTS 1
+
+typedef struct {
+ char *port_name;
+} MidiArgs;
+
+void *midi(void *arg);
+
+#endif // MIDI_H_
+