diff options
| author | Mitja Felicijan <mitja.felicijan@gmail.com> | 2024-10-12 06:14:14 +0200 |
|---|---|---|
| committer | Mitja Felicijan <mitja.felicijan@gmail.com> | 2024-10-12 06:14:14 +0200 |
| commit | 39bd41ad4d4832d4022a99e3cfcc49409f8b2da6 (patch) | |
| tree | 051b355fa3ea5cfcceb2b63efba0bbdf13970ee9 | |
| parent | 920bdc358831087c46db736120a718ed9a75fbd4 (diff) | |
| download | ttdaw-39bd41ad4d4832d4022a99e3cfcc49409f8b2da6.tar.gz | |
Added basic interface and keyboard capture of terminal
| -rw-r--r-- | documents/SoundFont Technical Specification, v2.04.pdf (renamed from documents/sfspec24.pdf) | bin | 530464 -> 530464 bytes | |||
| -rw-r--r-- | documents/Standard MIDI Files Specification, v1.0.pdf | bin | 0 -> 84070 bytes | |||
| -rw-r--r-- | examples/sandbox.lua | 12 | ||||
| -rw-r--r-- | interface.c | 100 | ||||
| -rw-r--r-- | main.c | 45 | ||||
| -rw-r--r-- | midi.c | 30 | ||||
| -rw-r--r-- | synth.c | 3 |
7 files changed, 149 insertions, 41 deletions
diff --git a/documents/sfspec24.pdf b/documents/SoundFont Technical Specification, v2.04.pdf Binary files differindex 252aff9..252aff9 100644 --- a/documents/sfspec24.pdf +++ b/documents/SoundFont Technical Specification, v2.04.pdf diff --git a/documents/Standard MIDI Files Specification, v1.0.pdf b/documents/Standard MIDI Files Specification, v1.0.pdf Binary files differnew file mode 100644 index 0000000..e422bf8 --- /dev/null +++ b/documents/Standard MIDI Files Specification, v1.0.pdf diff --git a/examples/sandbox.lua b/examples/sandbox.lua index 43c3ec7..d42eb6e 100644 --- a/examples/sandbox.lua +++ b/examples/sandbox.lua @@ -5,16 +5,16 @@ -- note_on(note, sf_preset, effect) -- note_off(note) -- delay(millisecons) --- play_pattern(pattern_name, repeat) +-- play_block(pattern_name, repeat) -- Effects: -- delay -- reverb --- This is a pattern definition. +-- This is a block/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) +block("A1", function(self) for i = 1, 10 do note_on(40 + i, 1, nil) delay(10) @@ -23,8 +23,8 @@ end) -- This is the actual song timeline. timeline(function(self) - play_pattern("A1", 1) - play_pattern("F2", 3) - play_pattern("D4", 2) + play_block("A1", 1) + play_block("F2", 3) + play_block("D4", 2) end) diff --git a/interface.c b/interface.c index 26aca55..1347ce2 100644 --- a/interface.c +++ b/interface.c @@ -1,16 +1,108 @@ +#include <stdlib.h> #include <stdio.h> +#include <locale.h> #include <unistd.h> #include "interface.h" #include "mutex.h" +#define TB_IMPL +#include "termbox2.h" + +static int block_width = 14; +static int block_height = 4; + +void draw_block(int x, int y, const char *label, int empty) { + + tb_set_cell(x, y, 0x250C, TB_WHITE, TB_DEFAULT); + tb_set_cell(x+block_width-1, y, 0x2510, TB_WHITE, TB_DEFAULT); + tb_set_cell(x, y+block_height-1, 0x2514, TB_WHITE, TB_DEFAULT); + tb_set_cell(x+block_width-1, y+block_height-1, 0x2518, TB_WHITE, TB_DEFAULT); + + tb_printf(x+(block_width/2) - (strlen(label)/2), y+(block_height/2)-1 ,TB_YELLOW, 0, label); + tb_printf(x+(block_width/2) - (strlen("empty")/2), y+(block_height/2) ,TB_DIM, 0, "empty"); + + tb_present(); +} + +void draw_blocks() { + int offset_x = 0; + int offset_y = 6; + char col_names[6] = {'A', 'B', 'C', 'D', 'E', 'F'}; + + for (int r = 0; r < 4; r++) { + for (int c = 0; c < 6; c++) { + char label[3]; + label[0] = col_names[c]; + label[1] = '1' + r; + label[2] = '\0'; + draw_block(offset_x+(block_width*c), offset_y+(block_height*r), label, 0); + } + } +} + +void draw_help_tooltip(const char* tooltip_text) { + tb_printf(tb_width() - strlen(tooltip_text) - 1, tb_height()-1, TB_DIM, 0, tooltip_text); + tb_present(); +} + void *interface(void *arg) { InterfaceArgs* args = (InterfaceArgs*)arg; - (void)args; + + int ret; + setlocale(LC_ALL, ""); + + ret = tb_init(); + if (ret) { + fprintf(stderr, "tb_init() failed with error code %d\n", ret); + exit(1); + } + + tb_set_input_mode(TB_INPUT_ESC | TB_INPUT_MOUSE); + struct tb_event ev; + + tb_clear(); + tb_present(); + + // Show currently selected soundfont. + tb_printf(0, 0, TB_GREEN, 0, "Soundfont: %s", args->soundfont_file); + tb_printf(0, 1, TB_GREEN, 0, "Preset: %s", args->soundfont_preset); + tb_present(); + + // Draw interface. + draw_help_tooltip("Ctrl+q - Quit"); + draw_blocks(); + /* draw_block(10, 10, "A1"); */ while(1) { - // Do the thread stuff here. - sleep(1); - fprintf(stdout, "hi from interface thread\n"); + ret = tb_poll_event(&ev); + + if (ret != TB_OK) { + if (ret == TB_ERR_POLL && tb_last_errno() == EINTR) { + /* Poll was interrupted, maybe by a SIGWINCH; try again */ + continue; + } + /* Some other error occurred; bail */ + break; + } + + switch (ev.type) { + case TB_EVENT_KEY: + if (ev.key == TB_KEY_CTRL_Q) { + tb_shutdown(); + exit(0); + } + + if (ev.key == TB_KEY_ARROW_UP) { + + } + + if (ev.key == TB_KEY_ARROW_DOWN) { + + } + + break; + } } } + @@ -13,6 +13,7 @@ void help(const char *argv0) { printf("Usage: %s [options]\n" "\nAvailable options:\n" + " -n,--new creates a new song file\n" " -l,--list list available devices\n" " -c,--client=client:port device client and port\n" " -s,--soundfont=file.sf2 soundfont file\n" @@ -23,8 +24,9 @@ void help(const char *argv0) { } int main(int argc, char *argv[]) { - const char short_options[] = "lc:s:p:hv"; + const char short_options[] = "n:lc:s:p:hv"; const struct option long_options[] = { + { "new", 1, NULL, 'n' }, { "list", 0, NULL, 'l' }, { "client", 1, NULL, 'c' }, { "soundfont", 1, NULL, 's' }, @@ -34,6 +36,7 @@ int main(int argc, char *argv[]) { { 0 }, }; + char *new_song_name = NULL; char *port_name = NULL; char *soundfont_file = NULL; int soundfont_preset = 0; @@ -41,6 +44,8 @@ int main(int argc, char *argv[]) { int opt; while ((opt = getopt_long(argc, argv, short_options, long_options, NULL)) != -1) { switch (opt) { + case 'n': + new_song_name = optarg; case 'l': fprintf(stderr, "List feature is NOT implemented yet.\n"); return 0; @@ -69,19 +74,37 @@ int main(int argc, char *argv[]) { } } + if (new_song_name != NULL) { + fprintf(stdout, "Creating new song file with name %s\n", new_song_name); + return 0; + } + if (port_name == NULL || soundfont_file == NULL || soundfont_preset < 0) { fprintf(stdout, "Missing options. Check help.\n"); fprintf(stdout, "Port, soundfile and preset are required fields.\n"); return 1; } - fprintf(stdout, "> Device port: %s\n", port_name); - fprintf(stdout, "> Soundfont: %s\n", soundfont_file); - fprintf(stdout, "> SF preset: %d\n", soundfont_preset); + /* fprintf(stdout, "> Device port: %s\n", port_name); */ + /* fprintf(stdout, "> Soundfont: %s\n", soundfont_file); */ + /* fprintf(stdout, "> SF preset: %d\n", soundfont_preset); */ + /* fprintf(stdout, "> Song name: %s\n", new_song_name); */ // Create mutex. initialize_mutex(); + // 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; + } + // Create synth thread. pthread_t synth_thread; SynthArgs synth_args = { @@ -103,22 +126,10 @@ 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(interface_thread, NULL); pthread_join(midi_thread, NULL); pthread_join(synth_thread, NULL); - pthread_join(interface_thread, NULL); // Destroy mutex. destroy_mutex(); @@ -6,6 +6,7 @@ #include "midi.h" #include "mutex.h" +#include "termbox2.h" static snd_seq_t *seq_handle; static snd_seq_addr_t *ports; @@ -40,10 +41,10 @@ void *midi(void *arg) { } // 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); - } + /* 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) { @@ -87,21 +88,24 @@ void *midi(void *arg) { 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); + tb_printf(0, 3, TB_CYAN, 0, "Note: %3d", ev->data.note.note); + tb_printf(0, 4, TB_CYAN, 0, "Velocity: %3d", ev->data.note.velocity); + tb_present(); + /* 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); + /* printf("%3d:%-3dNote off\t%2d, note %d\n", */ + /* ev->source.client, ev->source.port, */ + /* ev->data.note.channel, */ + /* ev->data.note.note); */ break; @@ -4,6 +4,7 @@ #include "synth.h" #include "mutex.h" #include "minisdl_audio.h" +#include "termbox2.h" #define TSF_IMPLEMENTATION #include "tsf.h" @@ -73,7 +74,7 @@ void *synth(void *arg) { SDL_UnlockMutex(g_Mutex); - printf("Consumed: note=%d, state=%d velocity:%d\n", shared_data.note, shared_data.state, shared_data.velocity); + /* printf("Consumed: note=%d, state=%d velocity:%d\n", shared_data.note, shared_data.state, shared_data.velocity); */ // Reset state to indicate data has been consumed. shared_data.action = 0; |
