From 7eb5ff91b2778e38dac27ddb402fd741f9614256 Mon Sep 17 00:00:00 2001 From: Mitya Selivanov Date: Sat, 2 Mar 2024 00:59:38 +0100 Subject: Refactor: use float for UI coordinates --- compile_flags.txt | 2 +- source/saw/main.c | 609 ++++++++++++++++++++++++++++-------------------------- 2 files changed, 314 insertions(+), 297 deletions(-) diff --git a/compile_flags.txt b/compile_flags.txt index 942c91c..3420365 100644 --- a/compile_flags.txt +++ b/compile_flags.txt @@ -1 +1 @@ --Isource +-Wall -Werror -Isource diff --git a/source/saw/main.c b/source/saw/main.c index 8b29fd4..d278187 100644 --- a/source/saw/main.c +++ b/source/saw/main.c @@ -25,6 +25,7 @@ #include "../kit/input_buffer.h" #include "../kit/threads.h" #include "../kit/status.h" +#include #if defined(__EMSCRIPTEN__) # include @@ -64,7 +65,7 @@ // Constants // -#define TIME_EPS 0.0001 +#define EPS 0.00001 #define REFERENCE_PITCH 440.0 // A_4 #define EQUAL_TEMPERAMENT_FACTOR 1.05946309436 // 2^(1/12) #define GLOBAL_VOLUME 2.0 @@ -156,8 +157,8 @@ typedef struct { i64 time; i64 duration; i64 loop_duration; - i64 ui_offset_x; - i64 ui_offset_y; + f64 ui_offset_x; + f64 ui_offset_y; // dynamic properties // @@ -215,8 +216,8 @@ typedef struct { i32 grid_roll; i32 grid_cell; b8 ui_offset_input; - i64 ui_offset_x; - i64 ui_offset_y; + f64 ui_offset_x; + f64 ui_offset_y; b8 duplicate_input; } saw_compose_t; @@ -310,8 +311,8 @@ static saw_compose_t saw_compose = { .grid_roll = 0, .grid_cell = 0, .ui_offset_input = 0, - .ui_offset_x = 0, - .ui_offset_y = 0, + .ui_offset_x = 0., + .ui_offset_y = 0., .duplicate_input = 0, }; @@ -666,7 +667,7 @@ static void saw_audio_render(void) { sustain, duration, release); - if (frequency < TIME_EPS) + if (frequency < EPS) break; f64 crossfade = (sam->crossfade * sam->base_frequency) / @@ -684,15 +685,14 @@ static void saw_audio_render(void) { // f64 q = t; - if (sample_duration > TIME_EPS) + if (sample_duration > EPS) q -= sample_duration * floor(q / sample_duration); q += sample_begin; f64 u0 = 1.; - if (sample_duration > TIME_EPS && - crossfade > TIME_EPS && t >= sample_duration && - q < crossfade) { + if (sample_duration > EPS && crossfade > EPS && + t >= sample_duration && q < crossfade) { // Play the body crossfade // @@ -714,7 +714,7 @@ static void saw_audio_render(void) { f64 u = u0; if (t >= sample_duration && q < crossfade && - crossfade > TIME_EPS) + crossfade > EPS) u *= q / crossfade; f64 r = sample_begin + q; @@ -1086,9 +1086,9 @@ static ib_token_t saw_parse_roll(ib_token_t tok, saw_roll_t *roll) { tok = next; } else if (AR_EQUAL(ib_str(name), SZ("ui_offset"))) { - i64 x, y; - ib_token_t next = saw_parse_int(tok, &x); - next = saw_parse_int(next, &y); + f64 x, y; + ib_token_t next = saw_parse_float(tok, &x); + next = saw_parse_float(next, &y); if (next.status == KIT_OK) { tok = next; @@ -1463,8 +1463,8 @@ static void saw_project_print_to_file(str_t file_name) { fprintf(f, " time %lld\n", roll->time); fprintf(f, " duration %lld\n", roll->duration); fprintf(f, " loop_duration %lld\n", roll->loop_duration); - fprintf(f, " ui_offset %lld %lld\n\n", - roll->ui_offset_x, roll->ui_offset_y); + fprintf(f, " ui_offset %f %f\n\n", roll->ui_offset_x, + roll->ui_offset_y); } fprintf(f, "}\n"); @@ -1529,7 +1529,7 @@ static void saw_project_print_to_file(str_t file_name) { // // TODO // - UI library and tests. -// - Use floating-point values for coordinates. +// - Fix Y-axis inconsistency. // // ================================================================ @@ -1541,6 +1541,9 @@ static void saw_ui_end(void) { if (saw_ui_input_active != -1 && !saw_lbutton_down) { assert(0); + // Make sure to deactivate the input when the mouse button is not + // down. + saw_ui_input_active = -1; #ifndef __EMSCRIPTEN__ @@ -1549,11 +1552,11 @@ static void saw_ui_end(void) { } } -static b8 saw_ui_button(i64 x0, i64 y0, i64 width, i64 height, +static b8 saw_ui_button(f64 x0, f64 y0, f64 width, f64 height, i64 color_index, str_t icon, str_t label, b8 is_active) { - i64 frame_height = sapp_height(); - i64 y = frame_height - y0 - height; + f64 frame_height = sapp_height(); + f64 y = frame_height - y0 - height; b8 has_cursor = saw_mouse_x >= x0 && saw_mouse_x < x0 + width && saw_mouse_y >= y && saw_mouse_y < y + height; saw_ui_color_t c = saw_ui_colors[color_index]; @@ -1569,36 +1572,36 @@ static b8 saw_ui_button(i64 x0, i64 y0, i64 width, i64 height, c.normal[2], c.normal[3])); if (icon.size > 0) { - nvgFontSize(saw_nvg, (height * 3) / 5); + nvgFontSize(saw_nvg, height * .6); nvgFontFaceId(saw_nvg, saw_font_icons); nvgTextAlign(saw_nvg, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE); - nvgText(saw_nvg, x0 + height / 2, y + height / 2, icon.values, + nvgText(saw_nvg, x0 + height * .5, y + height * .5, icon.values, icon.values + icon.size); x0 += height; - width -= height * 2; + width -= height * 2.; } if (label.size > 0) { - nvgFontSize(saw_nvg, (height * 4) / 5); + nvgFontSize(saw_nvg, height * .8); nvgFontFaceId(saw_nvg, saw_font_text); nvgTextAlign(saw_nvg, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE); - nvgText(saw_nvg, x0 + width / 2, y + height / 2, label.values, + nvgText(saw_nvg, x0 + width * .5, y + height * .5, label.values, label.values + label.size); } return saw_lbutton_click && has_cursor; } -static void saw_ui_value_float(i64 x0, i64 y0, i64 width, i64 height, +static void saw_ui_value_float(f64 x0, f64 y0, f64 width, f64 height, i64 color_index, str_t label, f64 scale, f64 min, f64 max, f64 *data) { - assert(data != NULL && scale != .0); - if (data == NULL || scale == .0) + assert(data != NULL && (scale < -EPS || scale > EPS)); + if (data == NULL || !(scale < -EPS || scale > EPS)) return; - i64 frame_height = sapp_height(); - i64 y = frame_height - y0 - height; + f64 frame_height = sapp_height(); + f64 y = frame_height - y0 - height; b8 has_cursor = saw_mouse_x >= x0 && saw_mouse_x < x0 + width && saw_mouse_y >= y && saw_mouse_y < y + height; saw_ui_color_t c = saw_ui_colors[color_index]; @@ -1618,9 +1621,9 @@ static void saw_ui_value_float(i64 x0, i64 y0, i64 width, i64 height, if (saw_ui_input_active == saw_ui_input_index) { if (saw_lbutton_down) { - saw_ui_input_buffer -= saw_shift_on ? saw_mouse_dy * 300 + saw_ui_input_buffer -= saw_shift_on ? saw_mouse_dy * 300. : saw_ctrl_on ? saw_mouse_dy - : saw_mouse_dy * 20; + : saw_mouse_dy * 20.; } else { saw_ui_input_active = -1; @@ -1644,19 +1647,19 @@ static void saw_ui_value_float(i64 x0, i64 y0, i64 width, i64 height, if (saw_ui_input_active == saw_ui_input_index || (saw_ui_input_active == -1 && has_cursor)) { nvgBeginPath(saw_nvg); - nvgRect(saw_nvg, x0 + width / 2, y, width / 2, height); + nvgRect(saw_nvg, x0 + width * .5, y, width * .5, height); nvgFillColor(saw_nvg, nvgRGBAf(.9f, .95f, .9f, .5f)); nvgFill(saw_nvg); } - nvgFontSize(saw_nvg, (height * 4) / 5); + nvgFontSize(saw_nvg, height * .8); nvgFontFaceId(saw_nvg, saw_font_text); if (label.size > 0) { nvgFillColor(saw_nvg, nvgRGBAf(c.normal[0], c.normal[1], c.normal[2], c.normal[3])); nvgTextAlign(saw_nvg, NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE); - nvgText(saw_nvg, x0, y + (height * 5) / 8, label.values, + nvgText(saw_nvg, x0, y + height * 5. * .125, label.values, label.values + label.size); x0 += width / 2; } @@ -1670,7 +1673,8 @@ static void saw_ui_value_float(i64 x0, i64 y0, i64 width, i64 height, nvgTextAlign(saw_nvg, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE); c8 buf[256]; sprintf(buf, "%.3f", (f32) *data); - nvgText(saw_nvg, x0 + width / 4, y + (height * 5) / 8, buf, NULL); + nvgText(saw_nvg, x0 + width * .25, y + height * 5. * .125, buf, + NULL); } // Increment UI element input index @@ -1679,15 +1683,15 @@ static void saw_ui_value_float(i64 x0, i64 y0, i64 width, i64 height, ++saw_ui_input_index; } -static void saw_ui_value_int(i64 x0, i64 y0, i64 width, i64 height, +static void saw_ui_value_int(f64 x0, f64 y0, f64 width, f64 height, i64 color_index, str_t label, f64 scale, i64 min, i64 max, i64 *data) { - assert(data != NULL && scale != .0); - if (data == NULL || scale == .0) + assert(data != NULL && (scale < -EPS || scale > EPS)); + if (data == NULL || !(scale < -EPS || scale > EPS)) return; - i64 frame_height = sapp_height(); - i64 y = frame_height - y0 - height; + f64 frame_height = sapp_height(); + f64 y = frame_height - y0 - height; b8 has_cursor = saw_mouse_x >= x0 && saw_mouse_x < x0 + width && saw_mouse_y >= y && saw_mouse_y < y + height; saw_ui_color_t c = saw_ui_colors[color_index]; @@ -1707,9 +1711,9 @@ static void saw_ui_value_int(i64 x0, i64 y0, i64 width, i64 height, if (saw_ui_input_active == saw_ui_input_index) { if (saw_lbutton_down) { - saw_ui_input_buffer -= saw_shift_on ? saw_mouse_dy * 300 + saw_ui_input_buffer -= saw_shift_on ? saw_mouse_dy * 300. : saw_ctrl_on ? saw_mouse_dy - : saw_mouse_dy * 20; + : saw_mouse_dy * 20.; } else { saw_ui_input_active = -1; @@ -1733,7 +1737,7 @@ static void saw_ui_value_int(i64 x0, i64 y0, i64 width, i64 height, if (saw_ui_input_active == saw_ui_input_index || (saw_ui_input_active == -1 && has_cursor)) { nvgBeginPath(saw_nvg); - nvgRect(saw_nvg, x0 + width / 2, y, width / 2, height); + nvgRect(saw_nvg, x0 + width * .5, y, width * .5, height); nvgFillColor(saw_nvg, nvgRGBAf(.9f, .95f, .9f, .5f)); nvgFill(saw_nvg); } @@ -1759,7 +1763,8 @@ static void saw_ui_value_int(i64 x0, i64 y0, i64 width, i64 height, nvgTextAlign(saw_nvg, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE); c8 buf[256]; sprintf(buf, "%lld", *data); - nvgText(saw_nvg, x0 + width / 4, y + (height * 5) / 8, buf, NULL); + nvgText(saw_nvg, x0 + width * .25, y + (height * 5.) * .125, buf, + NULL); } // Increment UI element input index @@ -1768,11 +1773,12 @@ static void saw_ui_value_int(i64 x0, i64 y0, i64 width, i64 height, ++saw_ui_input_index; } -static void saw_ui_value_list(i64 x0, i64 y0, i64 width, i64 height, +static void saw_ui_value_list(f64 x0, f64 y0, f64 width, f64 height, i64 color_index, str_t label, f64 scale, i64 size, str_t *names, i32 *data) { - assert(data != NULL && names != NULL && scale != .0); - if (data == NULL || names == NULL || scale == .0) + assert(data != NULL && names != NULL && + (scale < -EPS || scale > EPS)); + if (data == NULL || names == NULL || !(scale < -EPS || scale > EPS)) return; i64 frame_height = sapp_height(); @@ -1796,9 +1802,9 @@ static void saw_ui_value_list(i64 x0, i64 y0, i64 width, i64 height, if (saw_ui_input_active == saw_ui_input_index) { if (saw_lbutton_down) { - saw_ui_input_buffer -= saw_shift_on ? saw_mouse_dy * 300 + saw_ui_input_buffer -= saw_shift_on ? saw_mouse_dy * 300. : saw_ctrl_on ? saw_mouse_dy - : saw_mouse_dy * 20; + : saw_mouse_dy * 20.; } else { saw_ui_input_active = -1; @@ -1822,19 +1828,19 @@ static void saw_ui_value_list(i64 x0, i64 y0, i64 width, i64 height, if (saw_ui_input_active == saw_ui_input_index || (saw_ui_input_active == -1 && has_cursor)) { nvgBeginPath(saw_nvg); - nvgRect(saw_nvg, x0 + width / 2, y, width / 2, height); + nvgRect(saw_nvg, x0 + width * .5, y, width * .5, height); nvgFillColor(saw_nvg, nvgRGBAf(.9f, .95f, .9f, .5f)); nvgFill(saw_nvg); } - nvgFontSize(saw_nvg, (height * 4) / 5); + nvgFontSize(saw_nvg, height * .8); nvgFontFaceId(saw_nvg, saw_font_text); if (label.size > 0) { nvgFillColor(saw_nvg, nvgRGBAf(c.normal[0], c.normal[1], c.normal[2], c.normal[3])); nvgTextAlign(saw_nvg, NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE); - nvgText(saw_nvg, x0, y + (height * 5) / 8, label.values, + nvgText(saw_nvg, x0, y + height * 5 * .125, label.values, label.values + label.size); x0 += width / 2; } @@ -1847,8 +1853,8 @@ static void saw_ui_value_list(i64 x0, i64 y0, i64 width, i64 height, c.active[2], c.active[3])); nvgTextAlign(saw_nvg, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE); str_t s = names[*data]; - nvgText(saw_nvg, x0 + width / 4, y + (height * 5) / 8, s.values, - s.values + s.size); + nvgText(saw_nvg, x0 + width * .25, y + height * 5 * .125, + s.values, s.values + s.size); } // Increment UI element input index @@ -1859,21 +1865,21 @@ static void saw_ui_value_list(i64 x0, i64 y0, i64 width, i64 height, static void saw_ui_reset_offset(void) { if (saw_current_roll != -1) { - saw_rolls[saw_current_roll].ui_offset_x = 0; + saw_rolls[saw_current_roll].ui_offset_x = 0.; saw_rolls[saw_current_roll].ui_offset_y = ROLL_DEFAULT_UI_OFFSET_Y; } - saw_compose.ui_offset_x = 0; - saw_compose.ui_offset_y = 0; + saw_compose.ui_offset_x = 0.; + saw_compose.ui_offset_y = 0.; } -static void saw_ui_header(i64 x0, u64 y0, u64 width, i64 height) { - if (height > (2 * width) / 15) - height = (2 * width) / 15; +static void saw_ui_header(f64 x0, f64 y0, f64 width, f64 height) { + if (height > 2. * width / 15.) + height = 2. * width / 15.; - i64 x = x0; - i64 s = height; + f64 x = x0; + f64 s = height; c8 backward_fast[] = "\uf049"; c8 play[] = "\uf04b"; @@ -1924,24 +1930,26 @@ static void saw_ui_header(i64 x0, u64 y0, u64 width, i64 height) { saw_edit_mode = EDIT_MODE_CLONE; } -static void saw_ui_compose(i64 x0, i64 y0, i64 width, i64 height) { - i64 frame_height = sapp_height(); +static void saw_ui_compose(f64 x0, f64 y0, f64 width, f64 height) { + f64 frame_height = sapp_height(); + f64 track_height = 60.; + f64 grid_scale = 50.; + f64 grid_rate = 3.; + f64 border = 2.; - i64 track_height = 60; - i64 grid_scale = 50; - i64 grid_rate = 3; - i64 border = 2; + assert(track_height > EPS); + assert(grid_rate > EPS); + assert(grid_scale > EPS); // Time bar // nvgBeginPath(saw_nvg); nvgRect(saw_nvg, x0, frame_height - y0 - height + border, width, - track_height / 5 - border * 2); + track_height * .2 - border * 2.); nvgRect(saw_nvg, x0, - frame_height - y0 - height + border + - (track_height * 4) / 5, - width, track_height / 5 - border * 2); + frame_height - y0 - height + border + track_height * .8, + width, track_height * .2 - border * 2.); nvgFillColor(saw_nvg, nvgRGBA(180, 140, 120, 160)); nvgFill(saw_nvg); @@ -1956,20 +1964,23 @@ static void saw_ui_compose(i64 x0, i64 y0, i64 width, i64 height) { if (!roll->enabled) continue; - i64 top = frame_height - y0 - height + track_height; - i64 bottom = frame_height - y0; - i64 dx = x0 + saw_compose.ui_offset_x; - i64 l = dx + (roll->time * grid_scale) / SAMPLE_RATE; - i64 r = l + (roll->duration * grid_scale) / SAMPLE_RATE; - i64 u = frame_height - y0 - height + track_height + + f64 top = frame_height - y0 - height + track_height; + f64 bottom = frame_height - y0; + f64 dx = x0 + saw_compose.ui_offset_x; + f64 l = dx + (roll->time * grid_scale) / SAMPLE_RATE; + f64 r = l + (roll->duration * grid_scale) / SAMPLE_RATE; + f64 u = frame_height - y0 - height + track_height + saw_compose.ui_offset_y + roll->track * track_height; - i64 d = u + track_height; - i64 s = grid_scale / grid_rate; + f64 d = u + track_height; + + f64 s = grid_scale / grid_rate; + + assert(s > EPS); if (l < x0) - l = dx + ((x0 - dx + (s - 1)) / s) * s; + l = x0; if (r >= x0 + width) - r = dx + ((x0 + width - dx) / s) * s; + r = x0 + width; if (u < top) u = top; if (d > bottom) @@ -1978,10 +1989,10 @@ static void saw_ui_compose(i64 x0, i64 y0, i64 width, i64 height) { if (l >= r || u >= d) continue; - i64 x = l; - i64 w = r - l; - i64 y = u; - i64 h = d - u; + f64 x = l; + f64 w = r - l; + f64 y = u; + f64 h = d - u; b8 is_choosen = (saw_current_roll == i); @@ -1995,8 +2006,8 @@ static void saw_ui_compose(i64 x0, i64 y0, i64 width, i64 height) { saw_mouse_y >= y && saw_mouse_y < y + h); nvgBeginPath(saw_nvg); - nvgRect(saw_nvg, x + border, y + border, w - border * 2, - h - border * 2); + nvgRect(saw_nvg, x + border, y + border, w - border * 2., + h - border * 2.); nvgFillColor(saw_nvg, is_choosen ? nvgRGBA(240, 230, 200, 255) : is_playing ? nvgRGBA(240, 210, 180, 240) : has_cursor ? nvgRGBA(210, 210, 255, 255) @@ -2012,21 +2023,24 @@ static void saw_ui_compose(i64 x0, i64 y0, i64 width, i64 height) { } else { if (saw_edit_mode == EDIT_MODE_HAND && saw_lbutton_click) { if (saw_current_roll == i) { - i64 cell = ((saw_mouse_x - saw_compose.ui_offset_x) * - grid_rate) / - grid_scale; - i64 c0 = (roll->time * grid_rate) / SAMPLE_RATE; - i64 c1 = c0 + (roll->duration * grid_rate) / SAMPLE_RATE; + i64 cell = (i64) floor( + ((saw_mouse_x - saw_compose.ui_offset_x) * + grid_rate) / + grid_scale); + i64 c0 = (i64) floor((roll->time * grid_rate) / + SAMPLE_RATE); + i64 c1 = c0 + (i64) floor((roll->duration * grid_rate) / + SAMPLE_RATE); saw_compose.grid_input = 1; saw_compose.grid_roll = saw_current_roll; if (cell - c0 > c1 - cell) { saw_compose.grid_cell = c0; - roll->duration = ((cell - c0 + 1) * SAMPLE_RATE) / - grid_rate; + roll->duration = (i64) floor( + ((cell - c0 + 1) * SAMPLE_RATE) / grid_rate); } else { saw_compose.grid_cell = c1 - 1; - roll->duration = ((c1 - cell + 1) * SAMPLE_RATE) / - grid_rate; + roll->duration = (i64) floor( + ((c1 - cell + 1) * SAMPLE_RATE) / grid_rate); } } else { saw_current_roll = i; @@ -2055,14 +2069,14 @@ static void saw_ui_compose(i64 x0, i64 y0, i64 width, i64 height) { saw_mouse_y >= frame_height - y0 - height + track_height && saw_mouse_y < frame_height - y0) { - i64 track = (saw_mouse_y - saw_compose.ui_offset_y - - frame_height + y0 + height) / - track_height - + i64 track = (i64) floor((saw_mouse_y - saw_compose.ui_offset_y - + frame_height + y0 + height) / + track_height) - 1; - i64 cell = ((saw_mouse_x - saw_compose.ui_offset_x) * - grid_rate) / - grid_scale; - i64 frame = (cell * SAMPLE_RATE) / grid_rate; + i64 cell = (i64) floor( + ((saw_mouse_x - saw_compose.ui_offset_x) * grid_rate) / + grid_scale); + i64 frame = (i64) floor((cell * SAMPLE_RATE) / grid_rate); i64 n = -1; @@ -2072,9 +2086,9 @@ static void saw_ui_compose(i64 x0, i64 y0, i64 width, i64 height) { break; } - i64 x = x0 + saw_compose.ui_offset_x + + f64 x = x0 + saw_compose.ui_offset_x + (frame * grid_scale) / SAMPLE_RATE; - i64 y = frame_height - y0 - height + track_height + + f64 y = frame_height - y0 - height + track_height + saw_compose.ui_offset_y + track * track_height; if (track < 0 || track >= TRACK_COUNT || x < x0 || @@ -2097,7 +2111,8 @@ static void saw_ui_compose(i64 x0, i64 y0, i64 width, i64 height) { .rate = ROLL_DEFAULT_RATE, .notes = { 0 }, .time = frame, - .duration = (ROLL_DEFAULT_RATE * SAMPLE_RATE) / grid_rate, + .duration = (i64) floor((ROLL_DEFAULT_RATE * SAMPLE_RATE) / + grid_rate), .loop_duration = 0, .ui_offset_x = 0, .ui_offset_y = ROLL_DEFAULT_UI_OFFSET_Y, @@ -2121,18 +2136,18 @@ static void saw_ui_compose(i64 x0, i64 y0, i64 width, i64 height) { if (saw_current_roll == -1) break; - i64 track = (saw_mouse_y - saw_compose.ui_offset_y - - frame_height + y0 + height) / - track_height - + i64 track = (i64) floor((saw_mouse_y - saw_compose.ui_offset_y - + frame_height + y0 + height) / + track_height) - 1; - i64 cell = ((saw_mouse_x - saw_compose.ui_offset_x) * - grid_rate) / - grid_scale; + i64 cell = (i64) floor( + ((saw_mouse_x - saw_compose.ui_offset_x) * grid_rate) / + grid_scale); if (cell < 0 || track < 0 || track >= TRACK_COUNT) break; - i64 frame = (cell * SAMPLE_RATE) / grid_rate; + i64 frame = (i64) floor((cell * SAMPLE_RATE) / grid_rate); i64 n = -1; @@ -2189,22 +2204,22 @@ static void saw_ui_compose(i64 x0, i64 y0, i64 width, i64 height) { if (saw_compose.grid_input) { if (saw_edit_mode == EDIT_MODE_HAND && saw_lbutton_down) { - i64 cell = ((saw_mouse_x - saw_compose.ui_offset_x) * - grid_rate) / - grid_scale; + i64 cell = (i64) floor( + ((saw_mouse_x - saw_compose.ui_offset_x) * grid_rate) / + grid_scale); saw_roll_t *p = saw_rolls + saw_compose.grid_roll; if (cell >= 0) { if (saw_compose.grid_cell <= cell) { p->time = (saw_compose.grid_cell * SAMPLE_RATE) / grid_rate; - p->duration = ((1 + cell - saw_compose.grid_cell) * - SAMPLE_RATE) / - grid_rate; + p->duration = (i64) floor( + ((1 + cell - saw_compose.grid_cell) * SAMPLE_RATE) / + grid_rate); } else { p->time = (cell * SAMPLE_RATE) / grid_rate; - p->duration = ((1 + saw_compose.grid_cell - cell) * - SAMPLE_RATE) / - grid_rate; + p->duration = (i64) floor( + ((1 + saw_compose.grid_cell - cell) * SAMPLE_RATE) / + grid_rate); } } @@ -2214,28 +2229,31 @@ static void saw_ui_compose(i64 x0, i64 y0, i64 width, i64 height) { saw_roll_t *q = saw_rolls + i; if (!q->enabled || p->track != q->track) continue; - i64 q_cell = (q->time * grid_rate) / SAMPLE_RATE; - i64 q_size = (q->duration * grid_rate) / SAMPLE_RATE; + i64 q_cell = (i64) floor((q->time * grid_rate) / SAMPLE_RATE); + i64 q_size = (i64) floor((q->duration * grid_rate) / + SAMPLE_RATE); if (saw_compose.grid_cell < q_cell && cell >= q_cell) { cell = q_cell - 1; - p->time = (saw_compose.grid_cell * SAMPLE_RATE) / grid_rate; - p->duration = ((q_cell - saw_compose.grid_cell) * - SAMPLE_RATE) / - grid_rate; + p->time = (i64) floor( + (saw_compose.grid_cell * SAMPLE_RATE) / grid_rate); + p->duration = (i64) floor( + ((q_cell - saw_compose.grid_cell) * SAMPLE_RATE) / + grid_rate); } if (saw_compose.grid_cell > q_cell && cell < q_cell + q_size) { - cell = q_cell + q_size; - p->time = ((q_cell + q_size) * SAMPLE_RATE) / grid_rate; - p->duration = ((1 + saw_compose.grid_cell - q_cell - - q_size) * - SAMPLE_RATE) / - grid_rate; + cell = q_cell + q_size; + p->time = (i64) floor(((q_cell + q_size) * SAMPLE_RATE) / + grid_rate); + p->duration = (i64) floor( + ((1 + saw_compose.grid_cell - q_cell - q_size) * + SAMPLE_RATE) / + grid_rate); } } if (p->duration <= 0) - p->duration = SAMPLE_RATE / grid_rate; + p->duration = (i64) floor(SAMPLE_RATE / grid_rate); } else saw_compose.grid_input = 0; } @@ -2243,10 +2261,9 @@ static void saw_ui_compose(i64 x0, i64 y0, i64 width, i64 height) { // Playback indicator // - i64 x = x0 + saw_compose.ui_offset_x - border * 2 + - (saw_playback_frame * grid_scale + SAMPLE_RATE / 2) / - SAMPLE_RATE; - i64 w = border * 4; + f64 x = x0 + saw_compose.ui_offset_x - border * 2. + + (saw_playback_frame * grid_scale) / SAMPLE_RATE; + f64 w = border * 4.; if (x >= x0 - border * 2 && x < x0 + width) { nvgBeginPath(saw_nvg); @@ -2264,13 +2281,14 @@ static void saw_ui_compose(i64 x0, i64 y0, i64 width, i64 height) { frame_height + y0 + height) / track_height - 1; - i64 cell = ((saw_mouse_x - saw_compose.ui_offset_x) * grid_rate) / - grid_scale; - i64 x = x0 + saw_compose.ui_offset_x + + i64 cell = (i64) floor( + ((saw_mouse_x - saw_compose.ui_offset_x) * grid_rate) / + grid_scale); + f64 x = x0 + saw_compose.ui_offset_x + (cell * grid_scale) / grid_rate; - i64 y = frame_height - y0 - height + track_height + + f64 y = frame_height - y0 - height + track_height + saw_compose.ui_offset_y + track * track_height; - i64 w = grid_scale / grid_rate; + f64 w = grid_scale / grid_rate; if (track >= 0 && track < TRACK_COUNT && x >= x0 && x + w < x0 + width && @@ -2291,10 +2309,10 @@ static void saw_ui_compose(i64 x0, i64 y0, i64 width, i64 height) { saw_mouse_x < x0 + width && saw_mouse_y >= frame_height - y0 - height && saw_mouse_y < frame_height - y0) { - i64 dx = x0 + saw_compose.ui_offset_x; - i64 s = grid_scale / grid_rate; - i64 x = dx + ((saw_mouse_x - dx + s / 2) / s) * s; - i64 w = border * 4; + f64 dx = x0 + saw_compose.ui_offset_x; + f64 s = grid_scale / grid_rate; + f64 x = dx + ((saw_mouse_x - dx + s / 2) / s) * s; + f64 w = border * 4; nvgBeginPath(saw_nvg); nvgRect(saw_nvg, x - w / 2, frame_height - y0 - height, w, @@ -2304,13 +2322,13 @@ static void saw_ui_compose(i64 x0, i64 y0, i64 width, i64 height) { } } -static void saw_ui_choose_instrument(saw_track_t *track, i64 x0, - i64 y0, i64 width, i64 height) { - i64 text_height = 40; - i64 y = y0 + height - text_height; +static void saw_ui_choose_instrument(saw_track_t *track, f64 x0, + f64 y0, f64 width, f64 height) { + f64 text_height = 40.; + f64 y = y0 + height - text_height; - x0 += width / 8; - width = (width * 3) / 4; + x0 += width * .125; + width *= .75; if (saw_ui_button(x0, y, width, text_height, TINT_ORANGE, SZ("\uf83e"), SZ("Oscillator"), 1)) { @@ -2363,12 +2381,12 @@ static void saw_ui_choose_instrument(saw_track_t *track, i64 x0, } } -static void saw_ui_oscillator(saw_oscillator_t *osc, i64 x0, i64 y0, - i64 width, i64 height) { - i64 frame_height = sapp_height(); - i64 text_height = 33; - i64 x = x0 + width / 12; - i64 w = (width * 5) / 6; +static void saw_ui_oscillator(saw_oscillator_t *osc, f64 x0, f64 y0, + f64 width, f64 height) { + f64 frame_height = sapp_height(); + f64 text_height = 33.; + f64 x = x0 + width / 12.; + f64 w = width * 5. / 6.; str_t wave_names[] = { SZ("Sine"), SZ("Saw up"), SZ("Saw down"), @@ -2379,50 +2397,49 @@ static void saw_ui_oscillator(saw_oscillator_t *osc, i64 x0, i64 y0, TINT_WHITE, SZ("Wave"), 500., sizeof wave_names / sizeof *wave_names, wave_names, &osc->wave); - saw_ui_value_float(x, y0 + height - text_height * 2, w, text_height, - TINT_WHITE, SZ("Warp"), 10000, -1., 1., - &osc->warp); + saw_ui_value_float(x, y0 + height - text_height * 2., w, + text_height, TINT_WHITE, SZ("Warp"), 10000, -1., + 1., &osc->warp); // FIXME // Looping phase value. - saw_ui_value_float(x, y0 + height - text_height * 3, w, text_height, - TINT_WHITE, SZ("Phase"), 10000, 0., 1., - &osc->phase); - saw_ui_value_float(x, y0 + height - text_height * 4, w, text_height, - TINT_WHITE, SZ("Stereo"), 10000, 0., 2., - &osc->stereo_width); - saw_ui_value_float(x, y0 + height - text_height * 5, w, text_height, - TINT_WHITE, SZ("Volume"), 10000, 0., 2., - &osc->volume); + saw_ui_value_float(x, y0 + height - text_height * 3., w, + text_height, TINT_WHITE, SZ("Phase"), 10000, 0., + 1., &osc->phase); + saw_ui_value_float(x, y0 + height - text_height * 4., w, + text_height, TINT_WHITE, SZ("Stereo"), 10000, 0., + 2., &osc->stereo_width); + saw_ui_value_float(x, y0 + height - text_height * 5., w, + text_height, TINT_WHITE, SZ("Volume"), 10000, 0., + 2., &osc->volume); nvgFontSize(saw_nvg, text_height); nvgFontFaceId(saw_nvg, saw_font_text); nvgFillColor(saw_nvg, nvgRGBA(255, 255, 255, 255)); nvgTextAlign(saw_nvg, NVG_ALIGN_LEFT | NVG_ALIGN_BASELINE); - nvgText(saw_nvg, x, - frame_height - y0 - height + (text_height * 13) / 2, + nvgText(saw_nvg, x, frame_height - y0 - height + text_height * 6.5, "Envelope", 0); - saw_ui_value_float(x, y0 + height - text_height * 8, w, text_height, - TINT_WHITE, SZ("Sustain"), 10000, 0., 1., - &osc->envelope.sustain); - saw_ui_value_float(x, y0 + height - text_height * 9, w, text_height, - TINT_WHITE, SZ("Attack"), 100000, 0., 6., - &osc->envelope.attack); - saw_ui_value_float(x, y0 + height - text_height * 10, w, + saw_ui_value_float(x, y0 + height - text_height * 8., w, + text_height, TINT_WHITE, SZ("Sustain"), 10000, + 0., 1., &osc->envelope.sustain); + saw_ui_value_float(x, y0 + height - text_height * 9., w, + text_height, TINT_WHITE, SZ("Attack"), 100000, + 0., 6., &osc->envelope.attack); + saw_ui_value_float(x, y0 + height - text_height * 10., w, text_height, TINT_WHITE, SZ("Decay"), 100000, 0., 6., &osc->envelope.decay); - saw_ui_value_float(x, y0 + height - text_height * 11, w, + saw_ui_value_float(x, y0 + height - text_height * 11., w, text_height, TINT_WHITE, SZ("Release"), 100000, 0., 6., &osc->envelope.release); } -static void saw_ui_sampler(saw_sampler_t *sampler, i64 x0, i64 y0, - i64 width, i64 height) { - i64 frame_height = sapp_height(); - i64 text_height = 33; - i64 x = x0 + width / 12; - i64 w = (width * 5) / 6; - i64 sample_height = text_height * 4; +static void saw_ui_sampler(saw_sampler_t *sampler, f64 x0, f64 y0, + f64 width, f64 height) { + f64 frame_height = sapp_height(); + f64 text_height = 33.; + f64 x = x0 + width / 12.; + f64 w = width * 5. / 6.; + f64 sample_height = text_height * 4.; if (saw_drop_file_data.size != 0) { // Load the audio sample from memory @@ -2495,7 +2512,7 @@ static void saw_ui_sampler(saw_sampler_t *sampler, i64 x0, i64 y0, nvgBeginPath(saw_nvg); f64 dw = (f64) w / SAMPLER_OUTLINE_SIZE; - f64 h = sample_height / 2; + f64 h = sample_height * .5; f64 y = frame_height - y0 - height + h; assert(dw > .0001); @@ -2508,28 +2525,32 @@ static void saw_ui_sampler(saw_sampler_t *sampler, i64 x0, i64 y0, nvgFill(saw_nvg); } } else { - nvgFontSize(saw_nvg, text_height / 2); + nvgFontSize(saw_nvg, text_height * .5); nvgFontFaceId(saw_nvg, saw_font_text); nvgFillColor(saw_nvg, nvgRGBAf(1.f, .7f, .2f, .5f)); nvgTextAlign(saw_nvg, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE); - nvgText(saw_nvg, x0 + width / 2, - frame_height - y0 - height + sample_height / 2, + nvgText(saw_nvg, x0 + width * .5, + frame_height - y0 - height + sample_height * .5, "Drop a WAV file here", NULL); } saw_ui_value_float(x, y0 + height - sample_height - text_height, w, text_height, TINT_WHITE, SZ("Begin"), 100000, 0., 60., &sampler->begin); - saw_ui_value_float(x, y0 + height - sample_height - text_height * 2, + saw_ui_value_float(x, + y0 + height - sample_height - text_height * 2., w, text_height, TINT_WHITE, SZ("End"), 100000, 0., 60., &sampler->end); - saw_ui_value_float(x, y0 + height - sample_height - text_height * 3, + saw_ui_value_float(x, + y0 + height - sample_height - text_height * 3., w, text_height, TINT_WHITE, SZ("Crossfade"), 100000, 0., 60., &sampler->crossfade); - saw_ui_value_float(x, y0 + height - sample_height - text_height * 4, + saw_ui_value_float(x, + y0 + height - sample_height - text_height * 4., w, text_height, TINT_WHITE, SZ("Base freq."), 500, 1., 44100., &sampler->base_frequency); - saw_ui_value_float(x, y0 + height - sample_height - text_height * 5, + saw_ui_value_float(x, + y0 + height - sample_height - text_height * 5., w, text_height, TINT_WHITE, SZ("Volume."), 10000, 0., 2., &sampler->volume); @@ -2539,46 +2560,47 @@ static void saw_ui_sampler(saw_sampler_t *sampler, i64 x0, i64 y0, nvgTextAlign(saw_nvg, NVG_ALIGN_LEFT | NVG_ALIGN_BASELINE); nvgText(saw_nvg, x, frame_height - y0 - height + sample_height + - (text_height * 13) / 2, + text_height * 6.5, "Envelope", NULL); - saw_ui_value_float(x, y0 + height - sample_height - text_height * 8, + saw_ui_value_float(x, + y0 + height - sample_height - text_height * 8., w, text_height, TINT_WHITE, SZ("Sustain"), 10000, 0., 1., &sampler->envelope.sustain); - saw_ui_value_float(x, y0 + height - sample_height - text_height * 9, + saw_ui_value_float(x, + y0 + height - sample_height - text_height * 9., w, text_height, TINT_WHITE, SZ("Attack"), 100000, 0., 6., &sampler->envelope.attack); saw_ui_value_float(x, - y0 + height - sample_height - text_height * 10, + y0 + height - sample_height - text_height * 10., w, text_height, TINT_WHITE, SZ("Decay"), 100000, 0., 6., &sampler->envelope.decay); saw_ui_value_float(x, - y0 + height - sample_height - text_height * 11, + y0 + height - sample_height - text_height * 11., w, text_height, TINT_WHITE, SZ("Release"), 100000, 0., 6., &sampler->envelope.release); } -static void saw_ui_track(saw_track_t *track, i64 x0, i64 y0, - i64 width, i64 height, str_t title) { - i64 frame_height = sapp_height(); - - i64 text_height = 33; - i64 header_offset = 60; - i64 border = 2; +static void saw_ui_track(saw_track_t *track, f64 x0, f64 y0, + f64 width, f64 height, str_t title) { + f64 frame_height = sapp_height(); + f64 text_height = 33.; + f64 header_offset = 60.; + f64 border = 2.; nvgFontSize(saw_nvg, text_height - border); nvgFontFaceId(saw_nvg, saw_font_text); nvgTextAlign(saw_nvg, NVG_ALIGN_LEFT | NVG_ALIGN_BASELINE); nvgFillColor(saw_nvg, nvgRGBA(255, 255, 255, 255)); - nvgText(saw_nvg, x0 + border * 2, - frame_height - y0 - height + text_height - border * 2, + nvgText(saw_nvg, x0 + border * 2., + frame_height - y0 - height + text_height - border * 2., title.values, title.values + title.size); if (track->instrument != INSTRUMENT_NONE) { - i64 x = x0 + width - (text_height * 3) / 2; - i64 y = frame_height - y0 - height; - i64 s = text_height; + f64 x = x0 + width - text_height * 1.5; + f64 y = frame_height - y0 - height; + f64 s = text_height; b8 has_cursor = saw_mouse_x >= x && saw_mouse_y >= y && saw_mouse_x < x + s && saw_mouse_y < y + s; @@ -2621,18 +2643,19 @@ static void saw_ui_track(saw_track_t *track, i64 x0, i64 y0, } } -static void saw_ui_roll(saw_roll_t *roll, i64 x0, i64 y0, i64 width, - i64 height, str_t title) { - i64 frame_height = sapp_height(); +static void saw_ui_roll(saw_roll_t *roll, f64 x0, f64 y0, f64 width, + f64 height, str_t title) { + f64 frame_height = sapp_height(); + f64 text_height = 35.; + f64 header_height = 35.; + f64 pianokey_height = 35.; + f64 pianokey_width = 100.; + f64 border = 2.; - i64 text_height = 35; - i64 header_height = 35; - i64 pianokey_height = 35; - i64 pianokey_width = 100; - i64 border = 2; + f64 sheet_offset = 40.; + f64 sheet_scale = (40. * SAMPLE_RATE) / (10000. * roll->rate); - i64 sheet_offset = 40; - i64 sheet_scale = (40 * SAMPLE_RATE) / (10000 * roll->rate); + assert(sheet_scale > EPS); // Title text // @@ -2648,7 +2671,7 @@ static void saw_ui_roll(saw_roll_t *roll, i64 x0, i64 y0, i64 width, nvgFontFaceId(saw_nvg, saw_font_text); nvgTextAlign(saw_nvg, NVG_ALIGN_LEFT | NVG_ALIGN_BASELINE); nvgFillColor(saw_nvg, nvgRGBA(255, 255, 255, 255)); - nvgText(saw_nvg, x0 + border * 2, + nvgText(saw_nvg, x0 + border * 2., frame_height - y0 - height + text_height - border * 2, title.values, title.values + title.size); nvgFill(saw_nvg); @@ -2656,19 +2679,20 @@ static void saw_ui_roll(saw_roll_t *roll, i64 x0, i64 y0, i64 width, // Tuning control // { - i64 x = x0 + border; - i64 y = y0 + height - text_height - header_height; - i64 w = pianokey_width; - i64 h = header_height; + f64 x = x0 + border; + f64 y = y0 + height - text_height - header_height; + f64 w = pianokey_width; + f64 h = header_height; - if (saw_ui_button(x, y, w / 2, h, TINT_PINK, SZ("\uf52d"), SZ(""), + if (saw_ui_button(x, y, w * .5, h, TINT_PINK, SZ("\uf52d"), + SZ(""), roll->tuning_tag == TUNING_PYTHAGOREAN)) { saw_tuning_pythagorean(roll->tuning, roll->mark_pitch); roll->tuning_tag = TUNING_PYTHAGOREAN; } - if (saw_ui_button(x + w / 2, y, w / 2, h, TINT_PINK, SZ("\uf5ac"), - SZ(""), + if (saw_ui_button(x + w * .5, y, w * .5, h, TINT_PINK, + SZ("\uf5ac"), SZ(""), roll->tuning_tag == TUNING_EQUAL_TEMPERAMENT)) { saw_tuning_equal_temperament(roll->tuning); roll->tuning_tag = TUNING_EQUAL_TEMPERAMENT; @@ -2678,15 +2702,15 @@ static void saw_ui_roll(saw_roll_t *roll, i64 x0, i64 y0, i64 width, // Loop control // { - i64 x = x0 + pianokey_width + sheet_offset; - i64 y = frame_height - y0 - height + text_height; - i64 w = width - pianokey_width - sheet_offset; - i64 h = header_height / 5; - i64 border = 5; + f64 x = x0 + pianokey_width + sheet_offset; + f64 y = frame_height - y0 - height + text_height; + f64 w = width - pianokey_width - sheet_offset; + f64 h = header_height * .2; + f64 border = 5.; c8 repeat[] = "\uf363"; - nvgFontSize(saw_nvg, header_height - border * 2); + nvgFontSize(saw_nvg, header_height - border * 2.); nvgFontFaceId(saw_nvg, saw_font_icons); if (roll->loop_duration == 0) nvgFillColor(saw_nvg, nvgRGBA(80, 80, 80, 160)); @@ -2697,8 +2721,7 @@ static void saw_ui_roll(saw_roll_t *roll, i64 x0, i64 y0, i64 width, y + header_height / 2, repeat, repeat + (sizeof repeat - 1)); - i64 rw = (roll->loop_duration * roll->rate * sheet_scale + - SAMPLE_RATE / 2) / + i64 rw = (roll->loop_duration * roll->rate * sheet_scale) / SAMPLE_RATE; i64 rx = roll->ui_offset_x; @@ -2713,7 +2736,7 @@ static void saw_ui_roll(saw_roll_t *roll, i64 x0, i64 y0, i64 width, if (rw > 0) { nvgBeginPath(saw_nvg); nvgRect(saw_nvg, x + rx, y, rw, h); - nvgRect(saw_nvg, x + rx, y + h * 4, rw, h); + nvgRect(saw_nvg, x + rx, y + h * 4., rw, h); nvgFillColor(saw_nvg, nvgRGBA(180, 80, 40, 160)); nvgFill(saw_nvg); } @@ -2721,10 +2744,10 @@ static void saw_ui_roll(saw_roll_t *roll, i64 x0, i64 y0, i64 width, nvgBeginPath(saw_nvg); if (rx > 0) { nvgRect(saw_nvg, x, y, rx, h); - nvgRect(saw_nvg, x, y + h * 4, rx, h); + nvgRect(saw_nvg, x, y + h * 4., rx, h); } nvgRect(saw_nvg, x + rx + rw, y, w - rx - rw, h); - nvgRect(saw_nvg, x + rx + rw, y + h * 4, w - rx - rw, h); + nvgRect(saw_nvg, x + rx + rw, y + h * 4., w - rx - rw, h); nvgFillColor(saw_nvg, nvgRGBA(80, 80, 80, 160)); nvgFill(saw_nvg); @@ -2734,15 +2757,15 @@ static void saw_ui_roll(saw_roll_t *roll, i64 x0, i64 y0, i64 width, roll->loop_input = 1; if (roll->loop_input && saw_lbutton_down) { - i64 t = (saw_mouse_x - x0 - pianokey_width - sheet_offset - - roll->ui_offset_x + sheet_scale / 2) / + f64 t = (saw_mouse_x - x0 - pianokey_width - sheet_offset - + roll->ui_offset_x) / sheet_scale; if (t <= 0) roll->loop_duration = 0; else - roll->loop_duration = (t * SAMPLE_RATE + roll->rate / 2) / - roll->rate; + roll->loop_duration = (i64) floor( + (t * SAMPLE_RATE) / roll->rate + .5); } } @@ -2752,14 +2775,14 @@ static void saw_ui_roll(saw_roll_t *roll, i64 x0, i64 y0, i64 width, // Piano roll // { - i64 w = pianokey_width - border * 2; - i64 h = pianokey_height - border * 2; + f64 w = pianokey_width - border * 2.; + f64 h = pianokey_height - border * 2.; b8 hover_any = 0; for (i64 pitch = 0; pitch < PITCH_COUNT; pitch++) { - i64 x = x0 + border; - i64 y = frame_height - y0 - (pitch + 1) * pianokey_height + + f64 x = x0 + border; + f64 y = frame_height - y0 - (pitch + 1) * pianokey_height + border + roll->ui_offset_y; if (y > frame_height - y0 - pianokey_height) continue; @@ -2779,7 +2802,7 @@ static void saw_ui_roll(saw_roll_t *roll, i64 x0, i64 y0, i64 width, : nvgRGBA(220, 220, 220, 255)); nvgFill(saw_nvg); - nvgFontSize(saw_nvg, h / 2); + nvgFontSize(saw_nvg, h * .5); if (pitch == roll->mark_pitch) { nvgFontFaceId(saw_nvg, saw_font_icons); @@ -2806,10 +2829,10 @@ static void saw_ui_roll(saw_roll_t *roll, i64 x0, i64 y0, i64 width, memset(buf, 0, sizeof buf); sprintf(buf, "%.1f", (f32) roll->tuning[pitch]); - nvgFontSize(saw_nvg, (h * 2) / 3); + nvgFontSize(saw_nvg, h * 2. / 3.); nvgFillColor(saw_nvg, nvgRGBAf(.1f, .1f, .1f, 1.f)); nvgTextAlign(saw_nvg, NVG_ALIGN_RIGHT | NVG_ALIGN_MIDDLE); - nvgText(saw_nvg, x + w, y + h / 2, buf, NULL); + nvgText(saw_nvg, x + w, y + h * .5, buf, NULL); // Piano roll input // @@ -2865,7 +2888,7 @@ static void saw_ui_roll(saw_roll_t *roll, i64 x0, i64 y0, i64 width, // for (i64 pitch = 0; pitch < PITCH_COUNT; pitch++) { - i64 y = frame_height - y0 - (pitch + 1) * pianokey_height + + f64 y = frame_height - y0 - (pitch + 1) * pianokey_height + roll->ui_offset_y; if (y > frame_height - y0 - pianokey_height) @@ -2873,14 +2896,14 @@ static void saw_ui_roll(saw_roll_t *roll, i64 x0, i64 y0, i64 width, if (y < frame_height - y0 - height + text_height + header_height) break; - i64 h = pianokey_height; + f64 h = pianokey_height; for (i64 t = 0; t < (roll->duration * roll->rate) / SAMPLE_RATE; t++) { - i64 x = x0 + pianokey_width + sheet_offset + t * sheet_scale + + f64 x = x0 + pianokey_width + sheet_offset + t * sheet_scale + roll->ui_offset_x; - if (x >= x0 + width - sheet_scale - border) + if (x >= x0 + width - sheet_scale) break; i64 note = -1; @@ -2907,11 +2930,11 @@ static void saw_ui_roll(saw_roll_t *roll, i64 x0, i64 y0, i64 width, if (x < x0 + pianokey_width + sheet_offset) continue; - i64 w = sheet_scale; + f64 w = sheet_scale; nvgBeginPath(saw_nvg); - nvgRect(saw_nvg, x + border, y + border, w - border * 2, - h - border * 2); + nvgRect(saw_nvg, x + border, y + border, w - border * 2., + h - border * 2.); b8 turned_off = roll->pitch_turned_off[pitch] || (roll->loop_duration > 0 && @@ -2959,7 +2982,7 @@ static void saw_ui_roll(saw_roll_t *roll, i64 x0, i64 y0, i64 width, if (!note->enabled) continue; - i64 y = frame_height - y0 - (note->pitch + 1) * pianokey_height + + f64 y = frame_height - y0 - (note->pitch + 1) * pianokey_height + roll->ui_offset_y; if (y + pianokey_height > frame_height - y0) @@ -2967,14 +2990,10 @@ static void saw_ui_roll(saw_roll_t *roll, i64 x0, i64 y0, i64 width, if (y < frame_height - y0 - height + text_height + header_height) continue; - i64 x = x0 + pianokey_width + sheet_offset + roll->ui_offset_x + - (note->time * roll->rate * sheet_scale + - SAMPLE_RATE / 2) / - SAMPLE_RATE; - i64 w = (note->duration * roll->rate * sheet_scale + - SAMPLE_RATE / 2) / - SAMPLE_RATE; - i64 h = pianokey_height; + f64 x = x0 + pianokey_width + sheet_offset + roll->ui_offset_x + + (note->time * roll->rate * sheet_scale) / SAMPLE_RATE; + f64 w = (note->duration * roll->rate * sheet_scale) / SAMPLE_RATE; + f64 h = pianokey_height; b8 has_cursor = (roll->grid_input && roll->grid_note == n) || (saw_mouse_x >= x && saw_mouse_x < x + w && @@ -2999,11 +3018,10 @@ static void saw_ui_roll(saw_roll_t *roll, i64 x0, i64 y0, i64 width, frame >= roll->time + note->time && frame < roll->time + note->time + note->duration; - i64 underflow = (x0 + pianokey_width + sheet_offset + - sheet_scale - 1 - x) / - sheet_scale; - i64 overflow = (x + w + sheet_scale + 1 - x0 - width) / - sheet_scale; + f64 underflow = ceil((x0 + pianokey_width + sheet_offset - x) / + sheet_scale); + f64 overflow = floor((x + w + sheet_scale - x0 - width) / + sheet_scale); if (underflow > 0) { x += underflow * sheet_scale; @@ -3014,8 +3032,8 @@ static void saw_ui_roll(saw_roll_t *roll, i64 x0, i64 y0, i64 width, w -= overflow * sheet_scale; nvgBeginPath(saw_nvg); - nvgRect(saw_nvg, x + border, y + border, w - border * 2, - h - border * 2); + nvgRect(saw_nvg, x + border, y + border, w - border * 2., + h - border * 2.); nvgFillColor(saw_nvg, is_playing ? nvgRGBA(255, 230, 200, 255) : has_cursor ? nvgRGBA(190, 190, 230, 255) @@ -3036,9 +3054,10 @@ static void saw_ui_roll(saw_roll_t *roll, i64 x0, i64 y0, i64 width, if (roll->grid_input) { if (saw_edit_mode == EDIT_MODE_HAND && saw_lbutton_down) { - i64 t = (saw_mouse_x - x0 - pianokey_width - sheet_offset - - roll->ui_offset_x) / - sheet_scale; + i64 t = (i64) floor((saw_mouse_x - x0 - pianokey_width - + sheet_offset - roll->ui_offset_x) / + sheet_scale + + .5); saw_roll_note_t *p = roll->notes + roll->grid_note; @@ -3092,14 +3111,13 @@ static void saw_ui_roll(saw_roll_t *roll, i64 x0, i64 y0, i64 width, frame -= ((frame - roll->time) / roll->loop_duration) * roll->loop_duration; - i64 x = x0 + pianokey_width + sheet_offset + roll->ui_offset_x - - border * 2 + - ((frame - roll->time) * roll->rate * sheet_scale + - SAMPLE_RATE / 2) / + f64 x = x0 + pianokey_width + sheet_offset + roll->ui_offset_x - + border * 2. + + ((frame - roll->time) * roll->rate * sheet_scale) / SAMPLE_RATE; - i64 w = border * 4; + f64 w = border * 4; - if (x >= x0 + pianokey_width + sheet_offset - border * 2 && + if (x >= x0 + pianokey_width + sheet_offset - border * 2. && x < x0 + width) { nvgBeginPath(saw_nvg); nvgRect(saw_nvg, x, frame_height - y0 - height + text_height, w, @@ -3116,14 +3134,13 @@ static void saw_ui_roll(saw_roll_t *roll, i64 x0, i64 y0, i64 width, saw_mouse_x < x0 + width && saw_mouse_y >= frame_height - y0 - height && saw_mouse_y < frame_height - y0) { - i64 dx = x0 + pianokey_width + sheet_offset + roll->ui_offset_x; - i64 x = dx + - ((saw_mouse_x - dx + sheet_scale / 2) / sheet_scale) * - sheet_scale; - i64 w = border * 4; + f64 dx = x0 + pianokey_width + sheet_offset + roll->ui_offset_x; + f64 x = dx + floor((saw_mouse_x - dx) / sheet_scale + .5) * + sheet_scale; + f64 w = border * 4.; nvgBeginPath(saw_nvg); - nvgRect(saw_nvg, x - w / 2, + nvgRect(saw_nvg, x - w * .5, frame_height - y0 - height + text_height, w, height - text_height); nvgFillColor(saw_nvg, nvgRGBA(80, 80, 240, 160)); -- cgit v1.2.3