summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMitja Felicijan <mitja.felicijan@gmail.com>2024-10-11 07:51:18 +0200
committerMitja Felicijan <mitja.felicijan@gmail.com>2024-10-11 07:51:18 +0200
commit920bdc358831087c46db736120a718ed9a75fbd4 (patch)
treee884606865dccd8e756c4271b24f7ecc33f19826
parentac6283f92b0579c0e820e13a83715389455d3171 (diff)
downloadttdaw-920bdc358831087c46db736120a718ed9a75fbd4.tar.gz
Added boilerplate interface code
-rw-r--r--Makefile2
-rw-r--r--examples/sandbox.lua30
-rw-r--r--interface.c14
-rw-r--r--interface.h7
-rw-r--r--main.c29
-rw-r--r--midi.c166
-rw-r--r--mutex.h6
-rw-r--r--synth.h4
-rw-r--r--version.h16
9 files changed, 169 insertions, 105 deletions
diff --git a/Makefile b/Makefile
index fca5cb9..c8d97de 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
CC := cc
CFLAGS := -Wall -Wextra -Wshadow -Wunused -Wswitch-enum -Wpedantic -ggdb
LDFLAGS := -lm -ldl -lpthread -lasound
-FILES := main.c midi.c synth.c mutex.c minisdl_audio.c
+FILES := main.c midi.c synth.c interface.c mutex.c minisdl_audio.c
PROG := ttdaw
$(PROG): main.c
diff --git a/examples/sandbox.lua b/examples/sandbox.lua
new file mode 100644
index 0000000..43c3ec7
--- /dev/null
+++ b/examples/sandbox.lua
@@ -0,0 +1,30 @@
+-- Song file structure
+-- This is just an outline of it and this will change.
+
+-- API specification:
+-- note_on(note, sf_preset, effect)
+-- note_off(note)
+-- delay(millisecons)
+-- play_pattern(pattern_name, repeat)
+
+-- Effects:
+-- delay
+-- reverb
+
+-- This is a pattern definition.
+-- Columns go from A..F and rows go from 1..4.
+-- This blocks will be visualized in the DAW.
+pattern("A1", function(self)
+ for i = 1, 10 do
+ note_on(40 + i, 1, nil)
+ delay(10)
+ end
+end)
+
+-- This is the actual song timeline.
+timeline(function(self)
+ play_pattern("A1", 1)
+ play_pattern("F2", 3)
+ play_pattern("D4", 2)
+end)
+
diff --git a/interface.c b/interface.c
index 6399cb8..26aca55 100644
--- a/interface.c
+++ b/interface.c
@@ -1,2 +1,16 @@
+#include <stdio.h>
+#include <unistd.h>
+
#include "interface.h"
+#include "mutex.h"
+
+void *interface(void *arg) {
+ InterfaceArgs* args = (InterfaceArgs*)arg;
+ (void)args;
+ while(1) {
+ // Do the thread stuff here.
+ sleep(1);
+ fprintf(stdout, "hi from interface thread\n");
+ }
+}
diff --git a/interface.h b/interface.h
index e320785..da8227e 100644
--- a/interface.h
+++ b/interface.h
@@ -1,5 +1,12 @@
#ifndef INTERFACE_H
#define INTERFACE_H
+typedef struct {
+ char *soundfont_file;
+ int soundfont_preset;
+} InterfaceArgs;
+
+void *interface(void *arg);
+
#endif // INTERFACE_H
diff --git a/main.c b/main.c
index 2bc6927..d1c8567 100644
--- a/main.c
+++ b/main.c
@@ -7,6 +7,7 @@
#include "version.h"
#include "midi.h"
#include "synth.h"
+#include "interface.h"
#include "mutex.h"
void help(const char *argv0) {
@@ -27,7 +28,7 @@ int main(int argc, char *argv[]) {
{ "list", 0, NULL, 'l' },
{ "client", 1, NULL, 'c' },
{ "soundfont", 1, NULL, 's' },
- { "preset", 1, NULL, 'p' },
+ { "preset", 0, NULL, 'p' },
{ "help", 0, NULL, 'h' },
{ "version", 0, NULL, 'v' },
{ 0 },
@@ -35,7 +36,7 @@ int main(int argc, char *argv[]) {
char *port_name = NULL;
char *soundfont_file = NULL;
- int soundfont_preset = -1;
+ int soundfont_preset = 0;
int opt;
while ((opt = getopt_long(argc, argv, short_options, long_options, NULL)) != -1) {
@@ -56,11 +57,11 @@ int main(int argc, char *argv[]) {
help(argv[0]);
return 0;
case 'v':
- fprintf(stdout, "ttdaw version %s\n", TTDAW_VERSION);
- fprintf(stdout, "Website: %s.\n", TTDAW_WEBSITE);
- fprintf(stdout, "%s\n", TTDAW_LICENSE);
- fprintf(stdout, "%s\n", TTDAW_WARRANTY);
- fprintf(stdout, "\n%s\n", TTDAW_AUTHOR);
+ fprintf(stdout, "ttdaw version %s\n", VERSION);
+ fprintf(stdout, "Website: %s.\n", WEBSITE);
+ fprintf(stdout, "%s\n", LICENSE);
+ fprintf(stdout, "%s\n", WARRANTY);
+ fprintf(stdout, "\n%s\n", AUTHOR);
return 0;
default:
fprintf(stdout, "Missing options. Check help.\n");
@@ -102,8 +103,22 @@ int main(int argc, char *argv[]) {
return 1;
}
+ // Create UI thread.
+ pthread_t interface_thread;
+ InterfaceArgs interface_args = {
+ .soundfont_file = soundfont_file,
+ .soundfont_preset = soundfont_preset,
+ };
+
+ if (pthread_create(&interface_thread, NULL, interface, (void*)&interface_args) != 0) {
+ fprintf(stderr, "Error creating interface thread\n");
+ return 1;
+ }
+
+ // Start threads.
pthread_join(midi_thread, NULL);
pthread_join(synth_thread, NULL);
+ pthread_join(interface_thread, NULL);
// Destroy mutex.
destroy_mutex();
diff --git a/midi.c b/midi.c
index 92df3d3..e924b70 100644
--- a/midi.c
+++ b/midi.c
@@ -13,110 +13,108 @@ 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_open(&seq_handle, "default", SND_SEQ_OPEN_DUPLEX, 0) < 0) {
+ fprintf(stderr, "Error opening ALSA sequencer.\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);
- }
+ if (snd_seq_set_client_name(seq_handle, CLIENT_NAME) < 0) {
+ fprintf(stderr, "Could not set up client name.\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);
- }
+ 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);
+ }
- // 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.
+ 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);
+ }
- // 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);
- }
- }
+ // 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);
+ }
- if (snd_seq_nonblock(seq_handle, 1) < 0) {
- fprintf(stderr, "Set nonblock mode failed.");
+ // 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;
- // Reading MIDI device.
- struct pollfd *pfds;
- size_t npfds;
+ npfds = snd_seq_poll_descriptors_count(seq_handle, POLLIN);
+ pfds = alloca(sizeof(*pfds) * 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_poll_descriptors(seq_handle, pfds, npfds, POLLIN);
- if (poll(pfds, npfds, -1) < 0) {
+ snd_seq_event_t *ev;
+
+ if (snd_seq_event_input(seq_handle, &ev) < 0) {
break;
}
- for (;;) {
- snd_seq_event_t *ev;
+ if (ev) {
+ pthread_mutex_lock(&mutex);
+ switch (ev->type) {
+ case SND_SEQ_EVENT_NOTEON:
+ shared_data.note = ev->data.note.note;
+ shared_data.state = 1;
+ shared_data.velocity = ev->data.note.velocity;
+ 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:
+ shared_data.note = ev->data.note.note;
+ shared_data.state = 0;
+ shared_data.velocity = 0;
+ printf("%3d:%-3dNote off\t%2d, note %d\n",
+ ev->source.client, ev->source.port,
+ ev->data.note.channel,
+ ev->data.note.note);
+ break;
- if (snd_seq_event_input(seq_handle, &ev) < 0) {
- break;
- }
- if (ev) {
- pthread_mutex_lock(&mutex);
- switch (ev->type) {
- case SND_SEQ_EVENT_NOTEON:
- shared_data.note = ev->data.note.note;
- shared_data.state = 1;
- shared_data.velocity = ev->data.note.velocity;
- 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:
- shared_data.note = ev->data.note.note;
- shared_data.state = 0;
- shared_data.velocity = 0;
- printf("%3d:%-3dNote off\t%2d, note %d\n",
- ev->source.client, ev->source.port,
- ev->data.note.channel,
- ev->data.note.note);
- break;
- default:
- break;
- }
-
- shared_data.action = 1;
-
- pthread_cond_signal(&cond_synth);
- pthread_mutex_unlock(&mutex);
}
- }
- fflush(stdout);
+ shared_data.action = 1;
+
+ pthread_cond_signal(&cond_synth);
+ pthread_mutex_unlock(&mutex);
+ }
}
+
+ fflush(stdout);
}
}
diff --git a/mutex.h b/mutex.h
index 78b4cdf..2894b41 100644
--- a/mutex.h
+++ b/mutex.h
@@ -1,5 +1,5 @@
-#ifndef MUTEX_H
-#define MUTEX_H
+#ifndef MUTEX_H_
+#define MUTEX_H_
#include <pthread.h>
@@ -19,5 +19,5 @@ extern pthread_cond_t cond_synth;
void initialize_mutex();
void destroy_mutex();
-#endif // MUTEX_H
+#endif // MUTEX_H_
diff --git a/synth.h b/synth.h
index 7e08157..2fec78b 100644
--- a/synth.h
+++ b/synth.h
@@ -2,7 +2,7 @@
#define SYNTH_H_
#define AUDIO_FREQ 44100
-#define AUDIO_SAMPLES 64
+#define AUDIO_SAMPLES 128
#define AUDIO_CHANNELS 2
typedef struct {
@@ -12,5 +12,5 @@ typedef struct {
void *synth(void *arg);
-#endif // SYNTH_H_
+#endif // SYNTH_H_
diff --git a/version.h b/version.h
index e5962f6..76f1a1e 100644
--- a/version.h
+++ b/version.h
@@ -1,11 +1,11 @@
-#ifndef TTDAW_VERSION_H
-#define TTDAW_VERSION_H
+#ifndef VERSION_H_
+#define VERSION_H_
-#define TTDAW_VERSION "0.1"
-#define TTDAW_WEBSITE "https://github.com/mitjafelicijan/ttdaw"
-#define TTDAW_LICENSE "This is free software: you are free to change and redistribute it."
-#define TTDAW_WARRANTY "There is NO WARRANTY, to the extent permitted by law."
-#define TTDAW_AUTHOR "Written by Mitja Felicijan <https://mitjafelicijan.com>."
+#define VERSION "0.1"
+#define WEBSITE "https://github.com/mitjafelicijan/ttdaw"
+#define LICENSE "This is free software: you are free to change and redistribute it."
+#define WARRANTY "There is NO WARRANTY, to the extent permitted by law."
+#define AUTHOR "Written by Mitja Felicijan <https://mitjafelicijan.com>."
-#endif
+#endif // VERSION_H_