diff options
author | Mitya Selivanov <automainint@guattari.tech> | 2023-09-29 12:12:08 +0200 |
---|---|---|
committer | Mitya Selivanov <automainint@guattari.tech> | 2023-09-29 12:12:08 +0200 |
commit | 262d062e1c77d201a0e76d4bc615541a3dc87aeb (patch) | |
tree | 40396764f29358992bb0c37a6e707f08dfc36c3f | |
parent | 97ee833f60fd378e519421d17458ea743904e96b (diff) | |
download | saw-262d062e1c77d201a0e76d4bc615541a3dc87aeb.zip |
UI: Instrument settings
-rw-r--r-- | TODO | 2 | ||||
-rw-r--r-- | build_and_test.sh | 4 | ||||
-rw-r--r-- | source/saw/main.c | 547 |
3 files changed, 404 insertions, 149 deletions
@@ -2,7 +2,6 @@ To-Do list - Sound: Track looping - UI: Playback controls -- UI: Instrument settings - UI: Effects stack - UI: Volume control - Sound: Simple tonal synth @@ -51,3 +50,4 @@ Done - UI: Text rendering - UI: Piano roll panning - UI: Track composing +- UI: Instrument settings diff --git a/build_and_test.sh b/build_and_test.sh index 0b40374..3ec7361 100644 --- a/build_and_test.sh +++ b/build_and_test.sh @@ -92,7 +92,7 @@ esac if [ "$COMPILE" = "gcc" ] || [ "$COMPILE" = "clang" ]; then if [ "$1" = "release" ]; then - FLAGS="-O3" + FLAGS="-O3 -DNDEBUG" elif [ "$COMPILE" = "gcc" ] && [ "$OS" != "Windows" ]; then FLAGS="-O0 -fsanitize=undefined,address,leak" elif [ "$OS" != "Windows" ]; then @@ -102,7 +102,7 @@ if [ "$COMPILE" = "gcc" ] || [ "$COMPILE" = "clang" ]; then fi else if [ "$1" = "release" ]; then - FLAGS="-O2" + FLAGS="-O2 -DNDEBUG" else FLAGS="-Od" fi diff --git a/source/saw/main.c b/source/saw/main.c index 123dcbd..b5f46be 100644 --- a/source/saw/main.c +++ b/source/saw/main.c @@ -1,4 +1,5 @@ #include "profiler.h" +#include "version.h" #include "../kit/math.h" #include "../kit/time.h" @@ -22,6 +23,7 @@ #include "../thirdparty/nanovg_gl.h" #include <stdio.h> +#include <stdlib.h> #include "font.inl.h" @@ -29,15 +31,29 @@ enum { SAW_CHANNEL_COUNT = 2, SAW_SAMPLE_RATE = 44100, - VOICE_COUNT = 16, - ROLL_SIZE = 80, - SHEET_SIZE = 200, - ROLL_COUNT = 16, - TRACK_COUNT = 8, + TRACK_COUNT = 16, + ROLL_COUNT = 32, + PITCH_COUNT = 80, + VOICE_COUNT = 16, + UNISON_COUNT = 100, + SHEET_SIZE = 200, ROLL_DEFAULT_OFFSET_Y = 710, INSTRUMENT_SINE = 0, + + TRACK_INPUT_NONE = 0, + TRACK_INPUT_INSTRUMENT, + TRACK_INPUT_WARP, + TRACK_INPUT_PHASE, + TRACK_INPUT_UNISON, + TRACK_INPUT_SPREAD, + TRACK_INPUT_STEREO_WIDTH, + TRACK_INPUT_VOLUME, + TRACK_INPUT_SUSTAIN, + TRACK_INPUT_ATTACK, + TRACK_INPUT_DECAY, + TRACK_INPUT_RELEASE, }; typedef struct { @@ -46,7 +62,8 @@ typedef struct { f64 duration; f64 frequency; f64 amplitude; - f64 stereo_factor; + f64 phase[2]; + i64 track; } saw_voice_t; typedef struct { @@ -60,7 +77,7 @@ typedef struct { i8 enabled; i64 track; i32 last_index; - i8 turned_off[ROLL_SIZE]; + i8 pitch_turned_off[PITCH_COUNT]; i64 rate; saw_roll_note_t notes[SHEET_SIZE]; i64 frame; @@ -85,9 +102,13 @@ typedef struct { i32 instrument; f64 warp; f64 phase; + i32 unison; + f64 spread; f64 stereo_width; f64 volume; saw_envelope_t envelope; + i32 value_input; + f64 value_buffer; } saw_track_t; typedef struct { @@ -144,11 +165,11 @@ static saw_compose_t saw_compose = { #endif static f64 saw_random(f64 min, f64 max) { - if (max < min) + if (max - min < .000001) return min; u64 x = mt64_generate(&saw_mt64); u64 range = (u64) ((max - min) * 10000 + 0.5); - return min + (max - min) * (range * (x % (range + 1))); + return min + (max - min) * ((1.0 / range) * (x % (range + 1))); } static f64 saw_envelope(f64 t, f64 attack, f64 decay, f64 sustain, @@ -175,6 +196,30 @@ static f64 saw_pitch_amplitude(i64 pitch) { return .2 / exp(0.02 * pitch); } +static void saw_play_voice(saw_track_t *track, saw_roll_t *roll, + i64 pitch, i64 duration) { + if (saw_voices[VOICE_COUNT - 1].enabled) + return; + + for (i32 n = VOICE_COUNT - 1; n > 0; --n) + saw_voices[n] = saw_voices[n - 1]; + + f64 s = track->stereo_width / 8; + + saw_voices[0] = (saw_voice_t) { + .enabled = 1, + .time = 0, + .duration = ((f64) duration) / roll->rate, + .frequency = saw_pitch_frequency(pitch), + .amplitude = saw_pitch_amplitude(pitch) * track->volume, + .phase = { + saw_random(-s, s), + saw_random(-s, s), + }, + .track = roll->track, + }; +} + static void saw_playback(i32 frame_count) { if (!saw_playback_on) return; @@ -188,28 +233,17 @@ static void saw_playback(i32 frame_count) { continue; for (i32 i = 0; i < SHEET_SIZE; i++) { - saw_roll_note_t *p = roll->notes + i; - if (!p->enabled) + saw_roll_note_t *note = roll->notes + i; + if (!note->enabled) continue; i64 frame = roll->frame + - (p->time * SAW_SAMPLE_RATE) / roll->rate; + (note->time * SAW_SAMPLE_RATE) / roll->rate; if (saw_playback_frame + frame_count <= frame || saw_playback_frame > frame) continue; - if (saw_voices[VOICE_COUNT - 1].enabled) - continue; - for (i32 n = VOICE_COUNT - 1; n > 0; --n) - saw_voices[n] = saw_voices[n - 1]; - - saw_voices[0] = (saw_voice_t) { - .enabled = 1, - .time = 0, - .duration = ((f64) p->duration) / roll->rate, - .frequency = saw_pitch_frequency(p->pitch), - .amplitude = saw_pitch_amplitude(p->pitch), - .stereo_factor = saw_random(-0.01, 0.01), - }; + saw_play_voice(saw_tracks + roll->track, roll, note->pitch, + note->duration); } } @@ -231,26 +265,28 @@ static void saw_audio(ma_device *device, void *void_out_, if (!saw_voices[n].enabled) continue; - f64 period = M_PI * 2.; - f64 frequency = saw_voices[n].frequency; - f64 amplitude = saw_voices[n].amplitude; - f64 stereo_factor = saw_voices[n].stereo_factor; + saw_track_t *track = saw_tracks + saw_voices[n].track; + + f64 period = M_PI * 2.; + f64 frequency = saw_voices[n].frequency; + f64 amplitude = saw_voices[n].amplitude; + f64 phase_l = track->phase + saw_voices[n].phase[0]; + f64 phase_r = track->phase + saw_voices[n].phase[1]; - // envelope - f64 attack = .007; - f64 decay = .3; - f64 sustain = .15; + f64 attack = track->envelope.attack; + f64 decay = track->envelope.decay; + f64 sustain = track->envelope.sustain; f64 duration = saw_voices[n].duration; - f64 release = .4; + f64 release = track->envelope.release; for (i64 i = 0; i < frame_count; i++) { f64 t = (f64) saw_voices[n].time / (f64) SAW_SAMPLE_RATE; f64 a = amplitude * saw_envelope(t, attack, decay, sustain, duration, release); - f64 k = period * frequency; - - out[i * 2] += (f32) (sin(k * t) * a); - out[i * 2 + 1] += (f32) (sin(k * t + stereo_factor) * a); + out[i * 2] += (f32) (sin((t * frequency + phase_l) * period) * + a); + out[i * 2 + 1] += + (f32) (sin((t * frequency + phase_r) * period) * a); saw_voices[n].time++; @@ -432,21 +468,21 @@ static void saw_ui_compose(i64 x0, i64 y0, i64 width, i64 height) { } saw_rolls[n] = (saw_roll_t) { - .enabled = 1, - .track = track, - .last_index = -1, - .turned_off = { 0 }, - .rate = 6, - .notes = { 0 }, - .frame = frame, - .size = 6 / grid_rate, - .grid_input = 0, - .grid_note = 0, - .grid_time = 0, - .offset_x_input = 0, - .offset_y_input = 0, - .offset_x = 0, - .offset_y = ROLL_DEFAULT_OFFSET_Y, + .enabled = 1, + .track = track, + .last_index = -1, + .pitch_turned_off = { 0 }, + .rate = 6, + .notes = { 0 }, + .frame = frame, + .size = 6 / grid_rate, + .grid_input = 0, + .grid_note = 0, + .grid_time = 0, + .offset_x_input = 0, + .offset_y_input = 0, + .offset_x = 0, + .offset_y = ROLL_DEFAULT_OFFSET_Y, }; saw_current_roll = n; @@ -554,7 +590,7 @@ static void saw_ui_compose(i64 x0, i64 y0, i64 width, i64 height) { saw_compose.offset_y + track * track_height; i64 w = grid_scale / grid_rate; - if (track >= 0 && track < ROLL_COUNT && x >= x0 && + if (track >= 0 && track < TRACK_COUNT && x >= x0 && x + w < x0 + width && y >= frame_height - y0 - height + track_height && y + track_height < frame_height - y0) { @@ -595,6 +631,96 @@ static void saw_ui_track(saw_track_t *track, i64 x0, i64 y0, i64 border = 2; i64 column_width = 200; + i64 next_y = header_offset; + + // Values input and highlight + // + + if (!saw_lbutton_down && track->value_input != TRACK_INPUT_NONE) { + track->value_input = TRACK_INPUT_NONE; + track->value_buffer = 0; + sapp_lock_mouse(0); + } + + for (i32 input_index = TRACK_INPUT_INSTRUMENT; + input_index <= TRACK_INPUT_RELEASE; ++input_index) { + if ((track->value_input == TRACK_INPUT_NONE || + track->value_input == input_index) && + saw_mouse_x >= x0 && saw_mouse_x < x0 + width && + saw_mouse_y >= frame_height - y0 - height + next_y && + saw_mouse_y < + frame_height - y0 - height + next_y + text_height) { + i64 x = x0 + column_width; + i64 y = frame_height - y0 - height + next_y; + i64 w = width - column_width; + i64 h = text_height; + + if (w > 0) { + nvgBeginPath(saw_nvg); + nvgRect(saw_nvg, x + border, y, w - border * 2, h); + nvgFillColor(saw_nvg, nvgRGBA(200, 240, 200, 80)); + nvgFill(saw_nvg); + } + + if (saw_lbutton_click && + track->value_input == TRACK_INPUT_NONE) { + sapp_lock_mouse(1); + track->value_input = input_index; + + switch (input_index) { + case TRACK_INPUT_INSTRUMENT: + track->value_buffer = track->instrument * 100; + break; + + case TRACK_INPUT_UNISON: + track->value_buffer = track->unison * 100; + break; + + case TRACK_INPUT_WARP: + track->value_buffer = track->warp * 10000; + break; + + case TRACK_INPUT_PHASE: + track->value_buffer = track->phase * 10000; + break; + + case TRACK_INPUT_SPREAD: + track->value_buffer = track->spread * 10000; + break; + + case TRACK_INPUT_STEREO_WIDTH: + track->value_buffer = track->stereo_width * 10000; + break; + + case TRACK_INPUT_VOLUME: + track->value_buffer = track->volume * 10000; + break; + + case TRACK_INPUT_SUSTAIN: + track->value_buffer = track->envelope.sustain * 10000; + break; + + case TRACK_INPUT_ATTACK: + track->value_buffer = track->envelope.attack * 100000; + break; + + case TRACK_INPUT_DECAY: + track->value_buffer = track->envelope.decay * 100000; + break; + + case TRACK_INPUT_RELEASE: + track->value_buffer = track->envelope.release * 100000; + break; + + default:; + } + } + } + if (input_index == TRACK_INPUT_VOLUME) + next_y += header_offset; + next_y += text_height; + } + // Draw text // @@ -606,88 +732,102 @@ static void saw_ui_track(saw_track_t *track, i64 x0, i64 y0, nvgText(saw_nvg, x0 + border * 2, frame_height - y0 - height + text_height - border * 2, title.values, title.values + title.size); + next_y = header_offset + text_height; char buf_instr[][100] = { "Sine" }; nvgText(saw_nvg, x0 + border * 2, - frame_height - y0 - height + header_offset + text_height - - border * 2, + frame_height - y0 - height + next_y - border * 2, "Instrument", 0); nvgText(saw_nvg, x0 + column_width + border * 2, - frame_height - y0 - height + header_offset + text_height - - border * 2, + frame_height - y0 - height + next_y - border * 2, buf_instr[track->instrument], 0); + next_y += text_height; char buf[100]; - sprintf(buf, "%d", (i32) (track->phase * 100 + 0.5)); + sprintf(buf, "%.3f", (f32) track->warp); nvgText(saw_nvg, x0 + border * 2, - frame_height - y0 - height + header_offset + - text_height * 2 - border * 2, - "Phase", 0); + frame_height - y0 - height + next_y - border * 2, "Warp", + 0); nvgText(saw_nvg, x0 + column_width + border * 2, - frame_height - y0 - height + header_offset + - text_height * 2 - border * 2, - buf, 0); + frame_height - y0 - height + next_y - border * 2, buf, 0); + next_y += text_height; - sprintf(buf, "%d", (i32) (track->stereo_width * 100 + 0.5)); + sprintf(buf, "%.3f", (f32) track->phase); nvgText(saw_nvg, x0 + border * 2, - frame_height - y0 - height + header_offset + - text_height * 3 - border * 2, + frame_height - y0 - height + next_y - border * 2, "Phase", + 0); + nvgText(saw_nvg, x0 + column_width + border * 2, + frame_height - y0 - height + next_y - border * 2, buf, 0); + next_y += text_height; + + sprintf(buf, "%d", (i32) track->unison); + nvgText(saw_nvg, x0 + border * 2, + frame_height - y0 - height + next_y - border * 2, "Unison", + 0); + nvgText(saw_nvg, x0 + column_width + border * 2, + frame_height - y0 - height + next_y - border * 2, buf, 0); + next_y += text_height; + + sprintf(buf, "%.3f", (f32) track->spread); + nvgText(saw_nvg, x0 + border * 2, + frame_height - y0 - height + next_y - border * 2, "Spread", + 0); + nvgText(saw_nvg, x0 + column_width + border * 2, + frame_height - y0 - height + next_y - border * 2, buf, 0); + next_y += text_height; + + sprintf(buf, "%.3f", (f32) track->stereo_width); + nvgText(saw_nvg, x0 + border * 2, + frame_height - y0 - height + next_y - border * 2, "Stereo width", 0); nvgText(saw_nvg, x0 + column_width + border * 2, - frame_height - y0 - height + header_offset + - text_height * 3 - border * 2, - buf, 0); + frame_height - y0 - height + next_y - border * 2, buf, 0); + next_y += text_height; - sprintf(buf, "%d", (i32) (track->volume * 100 + 0.5)); + sprintf(buf, "%.3f", (f32) track->volume); nvgText(saw_nvg, x0 + border * 2, - frame_height - y0 - height + header_offset + - text_height * 4 - border * 2, - "Volume", 0); + frame_height - y0 - height + next_y - border * 2, "Volume", + 0); nvgText(saw_nvg, x0 + column_width + border * 2, - frame_height - y0 - height + header_offset + - text_height * 4 - border * 2, - buf, 0); + frame_height - y0 - height + next_y - border * 2, buf, 0); + next_y += header_offset; nvgText(saw_nvg, x0 + border * 2, - frame_height - y0 - height + header_offset + - text_height * 6 - border * 2, + frame_height - y0 - height + next_y - border * 2, "Envelope", 0); + next_y += text_height; + sprintf(buf, "%.3f", (f32) track->envelope.sustain); nvgText(saw_nvg, x0 + column_width / 4 + border * 2, - frame_height - y0 - height + header_offset + - text_height * 7 - border * 2, - "Sustain", 0); + frame_height - y0 - height + next_y - border * 2, "Sustain", + 0); nvgText(saw_nvg, x0 + column_width + border * 2, - frame_height - y0 - height + header_offset + - text_height * 7 - border * 2, - buf, 0); + frame_height - y0 - height + next_y - border * 2, buf, 0); + next_y += text_height; + sprintf(buf, "%.1f ms", (f32) (track->envelope.attack * 1000)); nvgText(saw_nvg, x0 + column_width / 4 + border * 2, - frame_height - y0 - height + header_offset + - text_height * 8 - border * 2, - "Attack", 0); + frame_height - y0 - height + next_y - border * 2, "Attack", + 0); nvgText(saw_nvg, x0 + column_width + border * 2, - frame_height - y0 - height + header_offset + - text_height * 8 - border * 2, - buf, 0); + frame_height - y0 - height + next_y - border * 2, buf, 0); + next_y += text_height; + sprintf(buf, "%.1f ms", (f32) (track->envelope.decay * 1000)); nvgText(saw_nvg, x0 + column_width / 4 + border * 2, - frame_height - y0 - height + header_offset + - text_height * 9 - border * 2, - "Decay", 0); + frame_height - y0 - height + next_y - border * 2, "Decay", + 0); nvgText(saw_nvg, x0 + column_width + border * 2, - frame_height - y0 - height + header_offset + - text_height * 9 - border * 2, - buf, 0); + frame_height - y0 - height + next_y - border * 2, buf, 0); + next_y += text_height; + sprintf(buf, "%.1f ms", (f32) (track->envelope.release * 1000)); nvgText(saw_nvg, x0 + column_width / 4 + border * 2, - frame_height - y0 - height + header_offset + - text_height * 10 - border * 2, - "Release", 0); + frame_height - y0 - height + next_y - border * 2, "Release", + 0); nvgText(saw_nvg, x0 + column_width + border * 2, - frame_height - y0 - height + header_offset + - text_height * 10 - border * 2, - buf, 0); + frame_height - y0 - height + next_y - border * 2, buf, 0); + next_y += text_height; nvgFill(saw_nvg); } @@ -710,7 +850,7 @@ static void saw_ui_roll(saw_roll_t *roll, i64 x0, i64 y0, i64 width, nvgBeginPath(saw_nvg); nvgRect(saw_nvg, x0, frame_height - y0 - height, width, text_height); - nvgFillColor(saw_nvg, nvgRGBA(100, 80, 70, 160)); + nvgFillColor(saw_nvg, nvgRGBA(80, 60, 50, 160)); nvgFill(saw_nvg); nvgBeginPath(saw_nvg); @@ -727,7 +867,7 @@ static void saw_ui_roll(saw_roll_t *roll, i64 x0, i64 y0, i64 width, i8 hover_any = 0; - for (i32 pitch = 0; pitch < ROLL_SIZE; pitch++) { + for (i32 pitch = 0; pitch < PITCH_COUNT; pitch++) { i32 x = x0 + border; i32 y = frame_height - y0 - (pitch + 1) * pianokey_height + border + roll->offset_y; @@ -745,7 +885,7 @@ static void saw_ui_roll(saw_roll_t *roll, i64 x0, i64 y0, i64 width, i8 has_cursor = saw_mouse_x >= x && saw_mouse_x < x + w && saw_mouse_y >= y && saw_mouse_y < y + h; - nvgFillColor(saw_nvg, roll->turned_off[pitch] + nvgFillColor(saw_nvg, roll->pitch_turned_off[pitch] ? nvgRGBA(220, 220, 220, 160) : has_cursor ? nvgRGBA(200, 200, 255, 255) : nvgRGBA(220, 220, 220, 255)); @@ -757,25 +897,14 @@ static void saw_ui_roll(saw_roll_t *roll, i64 x0, i64 y0, i64 width, if (has_cursor) { hover_any = 1; - if (!roll->turned_off[pitch] && + if (!roll->pitch_turned_off[pitch] && (saw_lbutton_click || - (saw_lbutton_down && roll->last_index != pitch)) && - !saw_voices[VOICE_COUNT - 1].enabled) { - for (i32 n = VOICE_COUNT - 1; n > 0; --n) - saw_voices[n] = saw_voices[n - 1]; - - saw_voices[0] = (saw_voice_t) { - .enabled = 1, - .time = 0, - .duration = .6, - .frequency = saw_pitch_frequency(pitch), - .amplitude = saw_pitch_amplitude(pitch), - .stereo_factor = saw_random(-0.01, 0.01), - }; - } + (saw_lbutton_down && roll->last_index != pitch))) + saw_play_voice(saw_tracks + roll->track, roll, pitch, 2); if (saw_rbutton_click) - roll->turned_off[pitch] = !roll->turned_off[pitch]; + roll->pitch_turned_off[pitch] = + !roll->pitch_turned_off[pitch]; roll->last_index = pitch; } @@ -806,7 +935,7 @@ static void saw_ui_roll(saw_roll_t *roll, i64 x0, i64 y0, i64 width, // Draw music sheet // - for (i32 pitch = 0; pitch < ROLL_SIZE; pitch++) { + for (i32 pitch = 0; pitch < PITCH_COUNT; pitch++) { i32 y = frame_height - y0 - (pitch + 1) * pianokey_height + roll->offset_y; @@ -852,7 +981,7 @@ static void saw_ui_roll(saw_roll_t *roll, i64 x0, i64 y0, i64 width, saw_mouse_x < x + w && saw_mouse_y >= y && saw_mouse_y < y + h; - nvgFillColor(saw_nvg, roll->turned_off[pitch] + nvgFillColor(saw_nvg, roll->pitch_turned_off[pitch] ? nvgRGBA(160, 150, 120, 100) : has_cursor ? nvgRGBA(180, 180, 220, 160) @@ -862,7 +991,7 @@ static void saw_ui_roll(saw_roll_t *roll, i64 x0, i64 y0, i64 width, // Empty cell input // - if (!roll->grid_input && !roll->turned_off[pitch] && + if (!roll->grid_input && !roll->pitch_turned_off[pitch] && has_cursor && saw_lbutton_click) { for (i32 n = 0; n < SHEET_SIZE; n++) if (!roll->notes[n].enabled) { @@ -1058,21 +1187,21 @@ static void saw_init(void) { saw_compose.rolls[i] = (i == 0 ? 0 : -1); saw_rolls[i] = (saw_roll_t) { - .enabled = (i == 0), - .track = 0, - .last_index = -1, - .turned_off = { 0 }, - .rate = 6, - .notes = { 0 }, - .frame = 0, - .size = 48, - .grid_input = 0, - .grid_note = 0, - .grid_time = 0, - .offset_x_input = 0, - .offset_y_input = 0, - .offset_x = 0, - .offset_y = ROLL_DEFAULT_OFFSET_Y, + .enabled = (i == 0), + .track = 0, + .last_index = -1, + .pitch_turned_off = { 0 }, + .rate = 6, + .notes = { 0 }, + .frame = 0, + .size = 48, + .grid_input = 0, + .grid_note = 0, + .grid_time = 0, + .offset_x_input = 0, + .offset_y_input = 0, + .offset_x = 0, + .offset_y = ROLL_DEFAULT_OFFSET_Y, }; } @@ -1081,14 +1210,17 @@ static void saw_init(void) { .instrument = INSTRUMENT_SINE, .warp = .5, .phase = .0, + .unison = 1, + .spread = .1, .stereo_width = .2, - .volume = .2, + .volume = 1., .envelope = { .sustain = .15, .attack = .007, .decay = .3, .release = .4, }, + .value_input = TRACK_INPUT_NONE, }; } @@ -1097,7 +1229,7 @@ static void saw_frame(void) { i32 frame_height = sapp_height(); glViewport(0, 0, frame_width, frame_height); - glClearColor(.23f, .19f, .16f, 1.f); + glClearColor(.15f, .12f, .10f, 1.f); glClearDepth(1.); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); @@ -1169,6 +1301,107 @@ static void saw_event(sapp_event const *event) { saw_compose.offset_y += event->mouse_dy; } + if (saw_current_track != -1) { + saw_track_t *track = saw_tracks + saw_current_track; + + track->value_buffer -= (event->modifiers & + SAPP_MODIFIER_SHIFT) + ? event->mouse_dy * 300 + : (event->modifiers & + SAPP_MODIFIER_CTRL) + ? event->mouse_dy + : event->mouse_dy * 20; + + switch (track->value_input) { + case TRACK_INPUT_INSTRUMENT: + // TODO + // + break; + + case TRACK_INPUT_WARP: + track->warp = track->value_buffer * .0001; + if (track->warp < -1.) + track->warp = -1.; + if (track->warp > 1.) + track->warp = 1.; + break; + + case TRACK_INPUT_PHASE: + track->value_buffer = (f64) ((i64) track->value_buffer % + 10000); + while (track->value_buffer < 0) + track->value_buffer += 10000; + track->phase = track->value_buffer * .0001; + break; + + case TRACK_INPUT_UNISON: + track->unison = (i64) (track->value_buffer * .01 + 0.5); + if (track->unison < 1) + track->unison = 1; + if (track->unison > UNISON_COUNT) + track->unison = UNISON_COUNT; + break; + + case TRACK_INPUT_SPREAD: + track->spread = track->value_buffer * .0001; + if (track->spread < 0.) + track->spread = 0.; + if (track->spread > 1.) + track->spread = 1.; + break; + + case TRACK_INPUT_STEREO_WIDTH: + track->stereo_width = track->value_buffer * .0001; + if (track->stereo_width < 0.) + track->stereo_width = 0.; + if (track->stereo_width > 2.) + track->stereo_width = 2.; + break; + + case TRACK_INPUT_VOLUME: + track->volume = track->value_buffer * .0001; + if (track->volume < 0.) + track->volume = 0.; + if (track->volume > 2.) + track->volume = 2.; + break; + + case TRACK_INPUT_SUSTAIN: + track->envelope.sustain = track->value_buffer * .0001; + if (track->envelope.sustain < 0.) + track->envelope.sustain = 0.; + if (track->envelope.sustain > 1.) + track->envelope.sustain = 1.; + break; + + case TRACK_INPUT_ATTACK: + track->envelope.attack = track->value_buffer * .00001; + if (track->envelope.attack < 0.) + track->envelope.attack = 0.; + if (track->envelope.attack > 60.) + track->envelope.attack = 60.; + break; + + case TRACK_INPUT_DECAY: + track->envelope.decay = track->value_buffer * .00001; + if (track->envelope.decay < 0.) + track->envelope.decay = 0.; + if (track->envelope.decay > 60.) + track->envelope.decay = 60.; + break; + + case TRACK_INPUT_RELEASE: + track->envelope.release = track->value_buffer * .00001; + if (track->envelope.release < 0.) + track->envelope.release = 0.; + if (track->envelope.release > 60.) + track->envelope.release = 60.; + break; + + default:; + } + } + break; case SAPP_EVENTTYPE_MOUSE_DOWN: @@ -1218,6 +1451,7 @@ static void saw_event(sapp_event const *event) { saw_compose.offset_y = 0; break; + default:; } } @@ -1232,11 +1466,32 @@ char const *__lsan_default_suppressions() { return "leak:nvidia"; } -sapp_desc sokol_main(int argc, char **argv) { - static char title[] = "saw"; +sapp_desc sokol_main(i32 argc, char **argv) { + i8 print_version = 0; + + for (i32 i = 0; i < argc; i++) + if (strcmp(argv[i], "--version") == 0) + print_version = 1; + else if (i > 0) + printf("Unknown command line argument: \"%s\"\n", argv[i]); + + if (print_version) { + printf("saw %d.%d.%d" +#if SAW_VERSION_DEV + "_dev" +#endif +#ifndef NDEBUG + " (Debug)" +#endif + " - Music sequencer standalone application.\n", + SAW_VERSION_MAJOR, SAW_VERSION_MINOR, SAW_VERSION_BABY); + exit(0); + } + + fflush(stdout); return (sapp_desc) { - .window_title = title, + .window_title = "saw", .width = 1280, .height = 720, .init_cb = saw_init, |