aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--documents/SoundFont Technical Specification, v2.04.pdf (renamed from documents/sfspec24.pdf)bin530464 -> 530464 bytes
-rw-r--r--documents/Standard MIDI Files Specification, v1.0.pdfbin0 -> 84070 bytes
-rw-r--r--examples/sandbox.lua12
-rw-r--r--interface.c100
-rw-r--r--main.c45
-rw-r--r--midi.c30
-rw-r--r--synth.c3
7 files changed, 149 insertions, 41 deletions
diff --git a/documents/sfspec24.pdf b/documents/SoundFont Technical Specification, v2.04.pdf
index 252aff9..252aff9 100644
--- a/documents/sfspec24.pdf
+++ b/documents/SoundFont Technical Specification, v2.04.pdf
Binary files differ
diff --git a/documents/Standard MIDI Files Specification, v1.0.pdf b/documents/Standard MIDI Files Specification, v1.0.pdf
new file mode 100644
index 0000000..e422bf8
--- /dev/null
+++ b/documents/Standard MIDI Files Specification, v1.0.pdf
Binary files differ
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 @@
5-- note_on(note, sf_preset, effect) 5-- note_on(note, sf_preset, effect)
6-- note_off(note) 6-- note_off(note)
7-- delay(millisecons) 7-- delay(millisecons)
8-- play_pattern(pattern_name, repeat) 8-- play_block(pattern_name, repeat)
9 9
10-- Effects: 10-- Effects:
11-- delay 11-- delay
12-- reverb 12-- reverb
13 13
14-- This is a pattern definition. 14-- This is a block/pattern definition.
15-- Columns go from A..F and rows go from 1..4. 15-- Columns go from A..F and rows go from 1..4.
16-- This blocks will be visualized in the DAW. 16-- This blocks will be visualized in the DAW.
17pattern("A1", function(self) 17block("A1", function(self)
18 for i = 1, 10 do 18 for i = 1, 10 do
19 note_on(40 + i, 1, nil) 19 note_on(40 + i, 1, nil)
20 delay(10) 20 delay(10)
@@ -23,8 +23,8 @@ end)
23 23
24-- This is the actual song timeline. 24-- This is the actual song timeline.
25timeline(function(self) 25timeline(function(self)
26 play_pattern("A1", 1) 26 play_block("A1", 1)
27 play_pattern("F2", 3) 27 play_block("F2", 3)
28 play_pattern("D4", 2) 28 play_block("D4", 2)
29end) 29end)
30 30
diff --git a/interface.c b/interface.c
index 26aca55..1347ce2 100644
--- a/interface.c
+++ b/interface.c
@@ -1,16 +1,108 @@
1#include <stdlib.h>
1#include <stdio.h> 2#include <stdio.h>
3#include <locale.h>
2#include <unistd.h> 4#include <unistd.h>
3 5
4#include "interface.h" 6#include "interface.h"
5#include "mutex.h" 7#include "mutex.h"
6 8
9#define TB_IMPL
10#include "termbox2.h"
11
12static int block_width = 14;
13static int block_height = 4;
14
15void draw_block(int x, int y, const char *label, int empty) {
16
17 tb_set_cell(x, y, 0x250C, TB_WHITE, TB_DEFAULT);
18 tb_set_cell(x+block_width-1, y, 0x2510, TB_WHITE, TB_DEFAULT);
19 tb_set_cell(x, y+block_height-1, 0x2514, TB_WHITE, TB_DEFAULT);
20 tb_set_cell(x+block_width-1, y+block_height-1, 0x2518, TB_WHITE, TB_DEFAULT);
21
22 tb_printf(x+(block_width/2) - (strlen(label)/2), y+(block_height/2)-1 ,TB_YELLOW, 0, label);
23 tb_printf(x+(block_width/2) - (strlen("empty")/2), y+(block_height/2) ,TB_DIM, 0, "empty");
24
25 tb_present();
26}
27
28void draw_blocks() {
29 int offset_x = 0;
30 int offset_y = 6;
31 char col_names[6] = {'A', 'B', 'C', 'D', 'E', 'F'};
32
33 for (int r = 0; r < 4; r++) {
34 for (int c = 0; c < 6; c++) {
35 char label[3];
36 label[0] = col_names[c];
37 label[1] = '1' + r;
38 label[2] = '\0';
39 draw_block(offset_x+(block_width*c), offset_y+(block_height*r), label, 0);
40 }
41 }
42}
43
44void draw_help_tooltip(const char* tooltip_text) {
45 tb_printf(tb_width() - strlen(tooltip_text) - 1, tb_height()-1, TB_DIM, 0, tooltip_text);
46 tb_present();
47}
48
7void *interface(void *arg) { 49void *interface(void *arg) {
8 InterfaceArgs* args = (InterfaceArgs*)arg; 50 InterfaceArgs* args = (InterfaceArgs*)arg;
9 (void)args; 51
52 int ret;
53 setlocale(LC_ALL, "");
54
55 ret = tb_init();
56 if (ret) {
57 fprintf(stderr, "tb_init() failed with error code %d\n", ret);
58 exit(1);
59 }
60
61 tb_set_input_mode(TB_INPUT_ESC | TB_INPUT_MOUSE);
62 struct tb_event ev;
63
64 tb_clear();
65 tb_present();
66
67 // Show currently selected soundfont.
68 tb_printf(0, 0, TB_GREEN, 0, "Soundfont: %s", args->soundfont_file);
69 tb_printf(0, 1, TB_GREEN, 0, "Preset: %s", args->soundfont_preset);
70 tb_present();
71
72 // Draw interface.
73 draw_help_tooltip("Ctrl+q - Quit");
74 draw_blocks();
75 /* draw_block(10, 10, "A1"); */
10 76
11 while(1) { 77 while(1) {
12 // Do the thread stuff here. 78 ret = tb_poll_event(&ev);
13 sleep(1); 79
14 fprintf(stdout, "hi from interface thread\n"); 80 if (ret != TB_OK) {
81 if (ret == TB_ERR_POLL && tb_last_errno() == EINTR) {
82 /* Poll was interrupted, maybe by a SIGWINCH; try again */
83 continue;
84 }
85 /* Some other error occurred; bail */
86 break;
87 }
88
89 switch (ev.type) {
90 case TB_EVENT_KEY:
91 if (ev.key == TB_KEY_CTRL_Q) {
92 tb_shutdown();
93 exit(0);
94 }
95
96 if (ev.key == TB_KEY_ARROW_UP) {
97
98 }
99
100 if (ev.key == TB_KEY_ARROW_DOWN) {
101
102 }
103
104 break;
105 }
15 } 106 }
16} 107}
108
diff --git a/main.c b/main.c
index d1c8567..61f01f2 100644
--- a/main.c
+++ b/main.c
@@ -13,6 +13,7 @@
13void help(const char *argv0) { 13void help(const char *argv0) {
14 printf("Usage: %s [options]\n" 14 printf("Usage: %s [options]\n"
15 "\nAvailable options:\n" 15 "\nAvailable options:\n"
16 " -n,--new creates a new song file\n"
16 " -l,--list list available devices\n" 17 " -l,--list list available devices\n"
17 " -c,--client=client:port device client and port\n" 18 " -c,--client=client:port device client and port\n"
18 " -s,--soundfont=file.sf2 soundfont file\n" 19 " -s,--soundfont=file.sf2 soundfont file\n"
@@ -23,8 +24,9 @@ void help(const char *argv0) {
23} 24}
24 25
25int main(int argc, char *argv[]) { 26int main(int argc, char *argv[]) {
26 const char short_options[] = "lc:s:p:hv"; 27 const char short_options[] = "n:lc:s:p:hv";
27 const struct option long_options[] = { 28 const struct option long_options[] = {
29 { "new", 1, NULL, 'n' },
28 { "list", 0, NULL, 'l' }, 30 { "list", 0, NULL, 'l' },
29 { "client", 1, NULL, 'c' }, 31 { "client", 1, NULL, 'c' },
30 { "soundfont", 1, NULL, 's' }, 32 { "soundfont", 1, NULL, 's' },
@@ -34,6 +36,7 @@ int main(int argc, char *argv[]) {
34 { 0 }, 36 { 0 },
35 }; 37 };
36 38
39 char *new_song_name = NULL;
37 char *port_name = NULL; 40 char *port_name = NULL;
38 char *soundfont_file = NULL; 41 char *soundfont_file = NULL;
39 int soundfont_preset = 0; 42 int soundfont_preset = 0;
@@ -41,6 +44,8 @@ int main(int argc, char *argv[]) {
41 int opt; 44 int opt;
42 while ((opt = getopt_long(argc, argv, short_options, long_options, NULL)) != -1) { 45 while ((opt = getopt_long(argc, argv, short_options, long_options, NULL)) != -1) {
43 switch (opt) { 46 switch (opt) {
47 case 'n':
48 new_song_name = optarg;
44 case 'l': 49 case 'l':
45 fprintf(stderr, "List feature is NOT implemented yet.\n"); 50 fprintf(stderr, "List feature is NOT implemented yet.\n");
46 return 0; 51 return 0;
@@ -69,19 +74,37 @@ int main(int argc, char *argv[]) {
69 } 74 }
70 } 75 }
71 76
77 if (new_song_name != NULL) {
78 fprintf(stdout, "Creating new song file with name %s\n", new_song_name);
79 return 0;
80 }
81
72 if (port_name == NULL || soundfont_file == NULL || soundfont_preset < 0) { 82 if (port_name == NULL || soundfont_file == NULL || soundfont_preset < 0) {
73 fprintf(stdout, "Missing options. Check help.\n"); 83 fprintf(stdout, "Missing options. Check help.\n");
74 fprintf(stdout, "Port, soundfile and preset are required fields.\n"); 84 fprintf(stdout, "Port, soundfile and preset are required fields.\n");
75 return 1; 85 return 1;
76 } 86 }
77 87
78 fprintf(stdout, "> Device port: %s\n", port_name); 88 /* fprintf(stdout, "> Device port: %s\n", port_name); */
79 fprintf(stdout, "> Soundfont: %s\n", soundfont_file); 89 /* fprintf(stdout, "> Soundfont: %s\n", soundfont_file); */
80 fprintf(stdout, "> SF preset: %d\n", soundfont_preset); 90 /* fprintf(stdout, "> SF preset: %d\n", soundfont_preset); */
91 /* fprintf(stdout, "> Song name: %s\n", new_song_name); */
81 92
82 // Create mutex. 93 // Create mutex.
83 initialize_mutex(); 94 initialize_mutex();
84 95
96 // Create UI thread.
97 pthread_t interface_thread;
98 InterfaceArgs interface_args = {
99 .soundfont_file = soundfont_file,
100 .soundfont_preset = soundfont_preset,
101 };
102
103 if (pthread_create(&interface_thread, NULL, interface, (void*)&interface_args) != 0) {
104 fprintf(stderr, "Error creating interface thread\n");
105 return 1;
106 }
107
85 // Create synth thread. 108 // Create synth thread.
86 pthread_t synth_thread; 109 pthread_t synth_thread;
87 SynthArgs synth_args = { 110 SynthArgs synth_args = {
@@ -103,22 +126,10 @@ int main(int argc, char *argv[]) {
103 return 1; 126 return 1;
104 } 127 }
105 128
106 // Create UI thread.
107 pthread_t interface_thread;
108 InterfaceArgs interface_args = {
109 .soundfont_file = soundfont_file,
110 .soundfont_preset = soundfont_preset,
111 };
112
113 if (pthread_create(&interface_thread, NULL, interface, (void*)&interface_args) != 0) {
114 fprintf(stderr, "Error creating interface thread\n");
115 return 1;
116 }
117
118 // Start threads. 129 // Start threads.
130 pthread_join(interface_thread, NULL);
119 pthread_join(midi_thread, NULL); 131 pthread_join(midi_thread, NULL);
120 pthread_join(synth_thread, NULL); 132 pthread_join(synth_thread, NULL);
121 pthread_join(interface_thread, NULL);
122 133
123 // Destroy mutex. 134 // Destroy mutex.
124 destroy_mutex(); 135 destroy_mutex();
diff --git a/midi.c b/midi.c
index e924b70..341df15 100644
--- a/midi.c
+++ b/midi.c
@@ -6,6 +6,7 @@
6 6
7#include "midi.h" 7#include "midi.h"
8#include "mutex.h" 8#include "mutex.h"
9#include "termbox2.h"
9 10
10static snd_seq_t *seq_handle; 11static snd_seq_t *seq_handle;
11static snd_seq_addr_t *ports; 12static snd_seq_addr_t *ports;
@@ -40,10 +41,10 @@ void *midi(void *arg) {
40 } 41 }
41 42
42 // Listing assigned ports. 43 // Listing assigned ports.
43 fprintf(stdout, "Ports:\n"); 44 /* fprintf(stdout, "Ports:\n"); */
44 for (int j = 0; j < MAX_MIDI_PORTS; j++) { 45 /* for (int j = 0; j < MAX_MIDI_PORTS; j++) { */
45 fprintf(stdout, " client: %d, port: %d\n", ports[j].client, ports[j].port); 46 /* fprintf(stdout, " client: %d, port: %d\n", ports[j].client, ports[j].port); */
46 } 47 /* } */
47 48
48 // Connecting ports. 49 // Connecting ports.
49 for (int i = 0; i < MAX_MIDI_PORTS; ++i) { 50 for (int i = 0; i < MAX_MIDI_PORTS; ++i) {
@@ -87,21 +88,24 @@ void *midi(void *arg) {
87 shared_data.note = ev->data.note.note; 88 shared_data.note = ev->data.note.note;
88 shared_data.state = 1; 89 shared_data.state = 1;
89 shared_data.velocity = ev->data.note.velocity; 90 shared_data.velocity = ev->data.note.velocity;
90 printf("%3d:%-3dNote on %2d, note %d, velocity: %3d\n", 91 tb_printf(0, 3, TB_CYAN, 0, "Note: %3d", ev->data.note.note);
91 ev->source.client, ev->source.port, 92 tb_printf(0, 4, TB_CYAN, 0, "Velocity: %3d", ev->data.note.velocity);
92 ev->data.note.channel, 93 tb_present();
93 ev->data.note.note, 94 /* printf("%3d:%-3dNote on %2d, note %d, velocity: %3d\n", */
94 ev->data.note.velocity); 95 /* ev->source.client, ev->source.port, */
96 /* ev->data.note.channel, */
97 /* ev->data.note.note, */
98 /* ev->data.note.velocity); */
95 break; 99 break;
96 100
97 case SND_SEQ_EVENT_NOTEOFF: 101 case SND_SEQ_EVENT_NOTEOFF:
98 shared_data.note = ev->data.note.note; 102 shared_data.note = ev->data.note.note;
99 shared_data.state = 0; 103 shared_data.state = 0;
100 shared_data.velocity = 0; 104 shared_data.velocity = 0;
101 printf("%3d:%-3dNote off\t%2d, note %d\n", 105 /* printf("%3d:%-3dNote off\t%2d, note %d\n", */
102 ev->source.client, ev->source.port, 106 /* ev->source.client, ev->source.port, */
103 ev->data.note.channel, 107 /* ev->data.note.channel, */
104 ev->data.note.note); 108 /* ev->data.note.note); */
105 break; 109 break;
106 110
107 111
diff --git a/synth.c b/synth.c
index d65ba41..3608eb3 100644
--- a/synth.c
+++ b/synth.c
@@ -4,6 +4,7 @@
4#include "synth.h" 4#include "synth.h"
5#include "mutex.h" 5#include "mutex.h"
6#include "minisdl_audio.h" 6#include "minisdl_audio.h"
7#include "termbox2.h"
7 8
8#define TSF_IMPLEMENTATION 9#define TSF_IMPLEMENTATION
9#include "tsf.h" 10#include "tsf.h"
@@ -73,7 +74,7 @@ void *synth(void *arg) {
73 74
74 SDL_UnlockMutex(g_Mutex); 75 SDL_UnlockMutex(g_Mutex);
75 76
76 printf("Consumed: note=%d, state=%d velocity:%d\n", shared_data.note, shared_data.state, shared_data.velocity); 77 /* printf("Consumed: note=%d, state=%d velocity:%d\n", shared_data.note, shared_data.state, shared_data.velocity); */
77 78
78 // Reset state to indicate data has been consumed. 79 // Reset state to indicate data has been consumed.
79 shared_data.action = 0; 80 shared_data.action = 0;