summaryrefslogtreecommitdiff
path: root/source/saw/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'source/saw/main.c')
-rw-r--r--source/saw/main.c248
1 files changed, 180 insertions, 68 deletions
diff --git a/source/saw/main.c b/source/saw/main.c
index 4f4d2ae..721eb76 100644
--- a/source/saw/main.c
+++ b/source/saw/main.c
@@ -58,11 +58,9 @@
enum {
// TODO
- //
- // Use 28224000 for time rate, divisible by common sample rates
- // like 192000, 44100 etc.
- //
- // Dynamic buffer size.
+ // - Use 28224000 for time rate, divisible by common sample rates
+ // like 192000, 44100 etc.
+ // - Dynamic buffer size.
CHANNEL_COUNT = 2,
SAMPLE_RATE = 44100,
@@ -193,6 +191,7 @@ typedef struct {
saw_envelope_t envelope;
} saw_oscillator_t;
+typedef DA(u8) saw_da_u8_t;
typedef DA(f32) saw_da_f32_t;
typedef struct {
@@ -239,49 +238,71 @@ typedef struct {
//
// Global state
//
+// NOTE
+// At some point we want to move all global data into a struct
+// saw_context_t.
+//
// ================================================================
+// Graphics
+//
+
static struct NVGcontext *saw_nvg;
-static ma_device saw_audio_device;
+static i32 saw_font_text = -1;
+static i32 saw_font_icons = -1;
+
+// Audio
+//
+
+static ma_device saw_audio_device;
// Input events
//
-static i64 saw_mouse_x = 0;
-static i64 saw_mouse_y = 0;
-static i64 saw_mouse_dx = 0;
-static i64 saw_mouse_dy = 0;
-static b8 saw_lbutton_click = 0;
-static b8 saw_lbutton_down = 0;
-static b8 saw_rbutton_click = 0;
-static b8 saw_rbutton_down = 0;
-static b8 saw_mbutton_click = 0;
-static b8 saw_mbutton_down = 0;
-static b8 saw_mouse_on = 0;
-static b8 saw_shift_on = 0;
-static b8 saw_ctrl_on = 0;
-static b8 saw_key_pressed[512] = { 0 };
-static char saw_drop_file[4096] = { 0 };
-
-static b8 saw_playback_on = 0;
-static i64 saw_playback_frame = 0;
-static i64 saw_playback_lookahead = 0;
-static i64 saw_playback_offset_read = 0;
-static i64 saw_playback_offset_write = 0;
-static f32 saw_playback_buffer[BUFFER_SIZE] = { 0.f };
-static f32 saw_playback_temp[BUFFER_SIZE];
+static i64 saw_mouse_x = 0;
+static i64 saw_mouse_y = 0;
+static i64 saw_mouse_dx = 0;
+static i64 saw_mouse_dy = 0;
+static b8 saw_lbutton_click = 0;
+static b8 saw_lbutton_down = 0;
+static b8 saw_rbutton_click = 0;
+static b8 saw_rbutton_down = 0;
+static b8 saw_mbutton_click = 0;
+static b8 saw_mbutton_down = 0;
+static b8 saw_mouse_on = 0;
+static b8 saw_shift_on = 0;
+static b8 saw_ctrl_on = 0;
+
+// Playback
+//
+
+static b8 saw_playback_on = 0;
+static i64 saw_playback_frame = 0;
+static i64 saw_playback_lookahead = 0;
+static i64 saw_playback_offset_read = 0;
+static i64 saw_playback_offset_write = 0;
static mtx_t saw_playback_mutex;
-static i64 saw_current_track = 0;
-static i64 saw_current_roll = 0;
-static i64 saw_edit_mode = EDIT_MODE_HAND;
+// Buffers
+//
+
+static f32 saw_playback_buffer[BUFFER_SIZE];
+static f32 saw_playback_temp[BUFFER_SIZE];
+static b8 saw_key_pressed[512];
+static c8 saw_drop_file_name[4096];
+static saw_da_u8_t saw_drop_file_data;
+
+// Project state
+//
-static char saw_project_file_buf[4096];
-static str_t saw_project_file;
-static i32 saw_font_text = -1;
-static i32 saw_font_icons = -1;
+static i64 saw_current_track = 0;
+static i64 saw_current_roll = 0;
+static i64 saw_edit_mode = EDIT_MODE_HAND;
static mt64_state_t saw_rng_mt64;
+static c8 saw_project_file_buf[4096];
+static str_t saw_project_file;
+
static saw_voice_t saw_voices[VOICE_COUNT] = { 0 };
static saw_roll_t saw_rolls[ROLL_COUNT];
static saw_track_t saw_tracks[TRACK_COUNT];
@@ -326,6 +347,10 @@ static f64 saw_ui_input_buffer = 0.;
//
// Sound
//
+// NOTE
+// When music and signal processing procedures become stable enough
+// we will separate them into a library and add tests.
+//
// ================================================================
#ifdef __GNUC__
@@ -869,6 +894,9 @@ static void saw_sampler_cleanup(saw_sampler_t *sampler) {
//
// UI
//
+// TODO
+// - UI library and tests.
+//
// ================================================================
static void saw_ui_begin(void) {
@@ -1782,7 +1810,7 @@ static void saw_ui_sampler(saw_sampler_t *sampler, i64 x0, i64 y0,
i64 w = (width * 5) / 6;
i64 sample_height = text_height * 4;
- if (saw_drop_file[0] != '\0') {
+ if (saw_drop_file_data.size != 0) {
// Load the audio sample from a file
//
@@ -1790,8 +1818,9 @@ static void saw_ui_sampler(saw_sampler_t *sampler, i64 x0, i64 y0,
u32 sample_rate;
drwav_uint64 count;
- f32 *samples = drwav_open_file_and_read_pcm_frames_f32(
- saw_drop_file, &channels, &sample_rate, &count, NULL);
+ f32 *samples = drwav_open_memory_and_read_pcm_frames_f32(
+ saw_drop_file_data.values, saw_drop_file_data.size, &channels,
+ &sample_rate, &count, NULL);
if (samples == NULL) {
printf("drwav_open_file_and_read_pcm_frames_f32 failed.\n");
@@ -1856,12 +1885,7 @@ static void saw_ui_sampler(saw_sampler_t *sampler, i64 x0, i64 y0,
nvgTextAlign(saw_nvg, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE);
nvgText(saw_nvg, x0 + width / 2,
frame_height - y0 - height + sample_height / 2,
-#ifdef __EMSCRIPTEN__
- "Not implemented for the web yet",
-#else
- "Drop a WAV file here",
-#endif
- NULL);
+ "Drop a WAV file here", NULL);
}
saw_ui_value_float(x, y0 + height - sample_height - text_height, w,
@@ -2509,6 +2533,15 @@ static void saw_init_audio(void) {
}
static void saw_init(void) {
+ // Init globals
+ //
+
+ memset(saw_key_pressed, 0, sizeof saw_key_pressed);
+ memset(saw_drop_file_name, 0, sizeof saw_drop_file_name);
+ memset(&saw_drop_file_data, 0, sizeof saw_drop_file_data);
+ memset(saw_playback_buffer, 0, sizeof saw_playback_buffer);
+ memset(saw_playback_temp, 0, sizeof saw_playback_temp);
+
// Init RNG
//
@@ -2868,8 +2901,8 @@ static void saw_init(void) {
static void saw_frame(void) {
// TODO
- // Check how much time passed to see if we need to adjust the
- // buffer size.
+ // - Check how much time passed to see if we need to adjust the
+ // buffer size.
(void) saw_ui_value_int;
@@ -3002,7 +3035,11 @@ static void saw_frame(void) {
saw_ctrl_on = 0;
memset(saw_key_pressed, 0, sizeof saw_key_pressed);
- memset(saw_drop_file, 0, sizeof saw_drop_file);
+
+ if (saw_drop_file_data.size != 0) {
+ memset(saw_drop_file_name, 0, sizeof saw_drop_file_name);
+ DA_DESTROY(saw_drop_file_data);
+ }
}
}
@@ -3167,6 +3204,23 @@ static void saw_cleanup(void) {
saw_sampler_cleanup(&saw_tracks[i].sampler);
}
+#ifdef __EMSCRIPTEN__
+static void saw_fetch_drop(
+ sapp_html5_fetch_response const *response) {
+ assert(response != NULL);
+
+ if (response == NULL || !response->succeeded) {
+ printf("Unable to fetch the dropped file\n");
+ fflush(stdout);
+ return;
+ }
+
+ assert(saw_drop_file_data.size >= response->data.size);
+
+ DA_RESIZE(saw_drop_file_data, response->data.size);
+}
+#endif
+
static void saw_event(sapp_event const *event) {
#ifdef __EMSCRIPTEN__
// In browser, resume the audio only after a user action.
@@ -3289,20 +3343,80 @@ static void saw_event(sapp_event const *event) {
break;
case SAPP_EVENTTYPE_FILES_DROPPED: {
+ // Get the dropped file name
+ //
+
+ i32 drop_count = sapp_get_num_dropped_files();
+ if (drop_count <= 0)
+ break;
+
+ c8 const *file_name = sapp_get_dropped_file_path(0);
+
+ i64 len = strlen(file_name);
+
+ assert(len > 0);
+ if (len <= 0)
+ break;
+
+ if (len >= sizeof saw_drop_file_name)
+ len = sizeof saw_drop_file_name - 1;
+
+ memcpy(saw_drop_file_name, file_name, len);
+ saw_drop_file_name[len] = '\0';
+
+ // Read the file data into the buffer
+ //
+
#ifdef __EMSCRIPTEN__
- (void) saw_drop_file;
+ i64 size = sapp_html5_get_dropped_file_size(0);
#else
- i32 n = sapp_get_num_dropped_files();
+ i64 size = file_info(str(len, file_name)).size;
+#endif
- if (n > 0) {
- char const *file_name = sapp_get_dropped_file_path(0);
- i64 len = strlen(file_name);
+ assert(size > 0);
+ if (size <= 0)
+ break;
- if (len > 0 && len < sizeof saw_drop_file) {
- memcpy(saw_drop_file, file_name, len);
- saw_drop_file[len] = '\0';
- }
+ if (saw_drop_file_data.size > 0)
+ DA_DESTROY(saw_drop_file_data);
+
+ DA_INIT(saw_drop_file_data, size, NULL);
+
+ assert(saw_drop_file_data.size == size);
+ if (saw_drop_file_data.size != size) {
+ printf("Bad alloc.\n");
+ fflush(stdout);
+ break;
}
+
+#ifdef __EMSCRIPTEN__
+ sapp_html5_fetch_dropped_file(&(sapp_html5_fetch_request) {
+ .dropped_file_index = 0,
+ .callback = saw_fetch_drop,
+ .buffer = { .ptr = saw_drop_file_data.values,
+ .size = size },
+ });
+#else
+ FILE *f = fopen(file_name, "rb");
+
+ assert(f != NULL);
+ if (f == NULL) {
+ printf("Unable to open file `%s`\n", file_name);
+ fflush(stdout);
+ break;
+ }
+
+ size = fread(saw_drop_file_data.values, 1, size, f);
+ fclose(f);
+
+ assert(size > 0);
+ if (size <= 0) {
+ printf("Unable to read file `%s`\n", file_name);
+ fflush(stdout);
+ break;
+ }
+
+ DA_RESIZE(saw_drop_file_data, size);
#endif
} break;
@@ -3368,17 +3482,15 @@ sapp_desc sokol_main(i32 argc, char **argv) {
exit(0);
return (sapp_desc) {
- .window_title = "Saw",
- .width = 1280,
- .height = 720,
-#ifndef __EMSCRIPTEN__
+ .window_title = "Saw",
+ .width = 1280,
+ .height = 720,
.enable_dragndrop = 1,
- .max_dropped_file_path_length = sizeof saw_drop_file,
-#endif
- .init_cb = saw_init,
- .frame_cb = saw_frame,
- .cleanup_cb = saw_cleanup,
- .event_cb = saw_event,
- .logger.func = log_,
+ .max_dropped_file_path_length = sizeof saw_drop_file_name,
+ .init_cb = saw_init,
+ .frame_cb = saw_frame,
+ .cleanup_cb = saw_cleanup,
+ .event_cb = saw_event,
+ .logger.func = log_,
};
}