From 06c55ae15d5b0ad96dd175677403c38d23f1f66b Mon Sep 17 00:00:00 2001 From: Mitya Selivanov Date: Wed, 14 Feb 2024 20:26:49 +0100 Subject: Choose instrument UI --- source/saw/main.c | 745 +++++++++++++++++++++++++++++++----------------------- 1 file changed, 434 insertions(+), 311 deletions(-) diff --git a/source/saw/main.c b/source/saw/main.c index 12b271e..d139773 100644 --- a/source/saw/main.c +++ b/source/saw/main.c @@ -52,8 +52,11 @@ enum { // TODO + // // Use 28224000 for time rate, divisible by common sample rates // like 192000, 44100 etc. + // + // Dynamic buffer size. CHANNEL_COUNT = 2, SAMPLE_RATE = 44100, @@ -82,26 +85,30 @@ enum { ROLL_DEFAULT_RATE = 8, ROLL_DEFAULT_UI_OFFSET_Y = 710, - INSTRUMENT_SINE = 0, - INSTRUMENT_SAW_UP, - INSTRUMENT_SAW_DOWN, - INSTRUMENT_SQUARE_UP, - INSTRUMENT_SQUARE_DOWN, - INSTRUMENT_KICK, - INSTRUMENT_COUNT, - - 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, + WAVE_SINE = 0, + WAVE_SAW_UP, + WAVE_SAW_DOWN, + WAVE_SQUARE_UP, + WAVE_SQUARE_DOWN, + WAVE_KICK, + WAVE_COUNT, + + INSTRUMENT_NONE = 0, + INSTRUMENT_OSCILLATOR, + INSTRUMENT_SAMPLER, + + OSCILLATOR_INPUT_NONE = 0, + OSCILLATOR_INPUT_WAVE, + OSCILLATOR_INPUT_WARP, + OSCILLATOR_INPUT_PHASE, + OSCILLATOR_INPUT_UNISON, + OSCILLATOR_INPUT_SPREAD, + OSCILLATOR_INPUT_STEREO_WIDTH, + OSCILLATOR_INPUT_VOLUME, + OSCILLATOR_INPUT_SUSTAIN, + OSCILLATOR_INPUT_ATTACK, + OSCILLATOR_INPUT_DECAY, + OSCILLATOR_INPUT_RELEASE, EDIT_MODE_HAND = 0, EDIT_MODE_ERASE, @@ -160,11 +167,9 @@ typedef struct { } saw_envelope_t; typedef struct { - i32 instrument; + i32 wave; f64 warp; f64 phase; - i32 unison; - f64 spread; f64 stereo_width; f64 volume; saw_envelope_t envelope; @@ -173,6 +178,19 @@ typedef struct { // i32 value_input; f64 value_buffer; +} saw_oscillator_t; + +typedef struct { + // TODO + int _; +} saw_sampler_t; + +typedef struct { + i32 instrument; + union { + saw_oscillator_t oscillator; + saw_sampler_t sampler; + }; } saw_track_t; typedef struct { @@ -303,25 +321,33 @@ static void saw_play_voice(saw_track_t *track, saw_roll_t *roll, 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 / (f64) SAMPLE_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, - }; + switch (track->instrument) { + case INSTRUMENT_OSCILLATOR: { + saw_oscillator_t *osc = &track->oscillator; + + f64 s = osc->stereo_width / 8; + + saw_voices[0] = (saw_voice_t) { + .enabled = 1, + .time = 0, + .duration = (f64) duration / (f64) SAMPLE_RATE, + .frequency = saw_pitch_frequency(pitch), + .amplitude = saw_pitch_amplitude(pitch) * osc->volume, + .phase = { + saw_random(-s, s), + saw_random(-s, s), + }, + .track = roll->track, + }; + } break; + + default:; + } } static f64 saw_oscillator(i32 type, f64 frequency, f64 phase, f64 warp, f64 t) { - if (type == INSTRUMENT_KICK) { + if (type == WAVE_KICK) { frequency /= 8.; f64 q = t * frequency + phase; frequency /= 8.; @@ -333,11 +359,11 @@ static f64 saw_oscillator(i32 type, f64 frequency, f64 phase, t = t - floor(t); switch (type) { - case INSTRUMENT_SINE: return sin(t * (M_PI * 2)); - case INSTRUMENT_SAW_UP: return -1. + t * 2.; - case INSTRUMENT_SAW_DOWN: return 1. - t * 2.; - case INSTRUMENT_SQUARE_UP: return t < .5 + warp / 2. ? -1. : 1.; - case INSTRUMENT_SQUARE_DOWN: return t < .5 + warp / 2. ? 1. : -1.; + case WAVE_SINE: return sin(t * (M_PI * 2)); + case WAVE_SAW_UP: return -1. + t * 2.; + case WAVE_SAW_DOWN: return 1. - t * 2.; + case WAVE_SQUARE_UP: return t < .5 + warp / 2. ? -1. : 1.; + case WAVE_SQUARE_DOWN: return t < .5 + warp / 2. ? 1. : -1.; default:; } @@ -382,8 +408,14 @@ static void saw_audio_render(void) { if (!note->enabled || note->time != roll_frame) continue; - saw_play_voice(saw_tracks + roll->track, roll, - note->pitch, note->duration); + switch (saw_tracks[roll->track].instrument) { + case INSTRUMENT_OSCILLATOR: + saw_play_voice(saw_tracks + roll->track, roll, + note->pitch, note->duration); + break; + + default:; + } } } @@ -399,36 +431,45 @@ static void saw_audio_render(void) { saw_track_t *track = saw_tracks + saw_voices[n].track; - i32 wave_type = track->instrument; - f64 warp = track->warp; - 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]; - - f64 attack = track->envelope.attack; - f64 decay = track->envelope.decay; - f64 sustain = track->envelope.sustain; - f64 duration = saw_voices[n].duration; - f64 release = track->envelope.release; - - f64 t = (f64) saw_voices[n].time / (f64) SAMPLE_RATE; - f64 a = amplitude * saw_envelope(t, attack, decay, sustain, - duration, release); - - saw_playback_temp[i * CHANNEL_COUNT] += - (f32) (saw_oscillator(wave_type, frequency, phase_l, - warp, t) * - a); - saw_playback_temp[i * CHANNEL_COUNT + 1] += - (f32) (saw_oscillator(wave_type, frequency, phase_r, - warp, t) * - a); - - saw_voices[n].time++; - - if (t > duration + release) - saw_voices[n].enabled = 0; + switch (track->instrument) { + case INSTRUMENT_OSCILLATOR: { + saw_oscillator_t *osc = &track->oscillator; + + i32 wave_type = osc->wave; + f64 warp = osc->warp; + f64 frequency = saw_voices[n].frequency; + f64 amplitude = saw_voices[n].amplitude; + f64 phase_l = osc->phase + saw_voices[n].phase[0]; + f64 phase_r = osc->phase + saw_voices[n].phase[1]; + + f64 attack = osc->envelope.attack; + f64 decay = osc->envelope.decay; + f64 sustain = osc->envelope.sustain; + f64 duration = saw_voices[n].duration; + f64 release = osc->envelope.release; + + f64 t = (f64) saw_voices[n].time / (f64) SAMPLE_RATE; + f64 a = amplitude * saw_envelope(t, attack, decay, + sustain, duration, + release); + + saw_playback_temp[i * CHANNEL_COUNT] += + (f32) (saw_oscillator(wave_type, frequency, phase_l, + warp, t) * + a); + saw_playback_temp[i * CHANNEL_COUNT + 1] += + (f32) (saw_oscillator(wave_type, frequency, phase_r, + warp, t) * + a); + + saw_voices[n].time++; + + if (t > duration + release) + saw_voices[n].enabled = 0; + } break; + + default:; + } } } } @@ -541,9 +582,12 @@ static void saw_reset_ui_offset(void) { } static void saw_ui_header(i64 x0, u64 y0, u64 width, i64 height) { + if (height > (2 * width) / 15) + height = (2 * width) / 15; + i64 frame_height = sapp_height(); - i64 border = 14; + i64 border = height > 14 * 4 ? 14 : height / 4; nvgFontSize(saw_nvg, height - border * 2); nvgFontFaceId(saw_nvg, saw_font_icons); @@ -1033,8 +1077,53 @@ static void saw_ui_compose(i64 x0, i64 y0, i64 width, i64 height) { } } -static void saw_ui_track(saw_track_t *track, i64 x0, i64 y0, - i64 width, i64 height, str_t title) { +static void saw_ui_choose_instrument(saw_track_t *track, i64 x0, + i64 y0, i64 width, i64 height) { + i64 frame_height = sapp_height(); + + i64 text_height = 40; + i64 border = 4; + + nvgFontSize(saw_nvg, text_height - border); + nvgFontFaceId(saw_nvg, saw_font_text); + + i64 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 + text_height; + + if (has_cursor) + nvgFillColor(saw_nvg, nvgRGBA(255, 255, 255, 255)); + else + nvgFillColor(saw_nvg, nvgRGBA(200, 120, 80, 255)); + nvgText(saw_nvg, x0 + border * 2, y + text_height - border * 2, + "Oscillator", NULL); + y += text_height; + + if (has_cursor && saw_lbutton_down) + track->instrument = INSTRUMENT_OSCILLATOR; + } + + { + b8 has_cursor = saw_mouse_x >= x0 && saw_mouse_x < x0 + width && + saw_mouse_y >= y && saw_mouse_y < y + text_height; + + if (has_cursor) + nvgFillColor(saw_nvg, nvgRGBA(255, 255, 255, 255)); + else + nvgFillColor(saw_nvg, nvgRGBA(200, 120, 80, 255)); + nvgText(saw_nvg, x0 + border * 2, y + text_height - border * 2, + "Sampler", NULL); + y += text_height; + + if (has_cursor && saw_lbutton_down) + track->instrument = INSTRUMENT_SAMPLER; + } +} + +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; @@ -1042,31 +1131,32 @@ 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; + if (!saw_lbutton_down && + osc->value_input != OSCILLATOR_INPUT_NONE) { + osc->value_input = OSCILLATOR_INPUT_NONE; + osc->value_buffer = 0; #ifndef __EMSCRIPTEN__ sapp_lock_mouse(0); #endif } - for (i64 input_index = TRACK_INPUT_INSTRUMENT; - input_index <= TRACK_INPUT_RELEASE; ++input_index) { + i64 next_y = 0; + + for (i64 input_index = OSCILLATOR_INPUT_WAVE; + input_index <= OSCILLATOR_INPUT_RELEASE; ++input_index) { // TODO // Implement Unison and Spread. - if (input_index == TRACK_INPUT_UNISON || - input_index == TRACK_INPUT_SPREAD) + if (input_index == OSCILLATOR_INPUT_UNISON || + input_index == OSCILLATOR_INPUT_SPREAD) continue; - if ((track->value_input == TRACK_INPUT_NONE || - track->value_input == input_index) && + if ((osc->value_input == OSCILLATOR_INPUT_NONE || + osc->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 < @@ -1084,57 +1174,49 @@ static void saw_ui_track(saw_track_t *track, i64 x0, i64 y0, } if (saw_lbutton_click && - track->value_input == TRACK_INPUT_NONE) { + osc->value_input == OSCILLATOR_INPUT_NONE) { #ifndef __EMSCRIPTEN__ sapp_lock_mouse(1); #endif - track->value_input = input_index; + osc->value_input = input_index; switch (input_index) { - case TRACK_INPUT_INSTRUMENT: - track->value_buffer = track->instrument * 500; + case OSCILLATOR_INPUT_WAVE: + osc->value_buffer = osc->wave * 500; break; - case TRACK_INPUT_UNISON: - track->value_buffer = track->unison * 100; + case OSCILLATOR_INPUT_WARP: + osc->value_buffer = osc->warp * 10000; break; - case TRACK_INPUT_WARP: - track->value_buffer = track->warp * 10000; + case OSCILLATOR_INPUT_PHASE: + osc->value_buffer = osc->phase * 10000; break; - case TRACK_INPUT_PHASE: - track->value_buffer = track->phase * 10000; + case OSCILLATOR_INPUT_STEREO_WIDTH: + osc->value_buffer = osc->stereo_width * 10000; break; - case TRACK_INPUT_SPREAD: - track->value_buffer = track->spread * 10000; + case OSCILLATOR_INPUT_VOLUME: + osc->value_buffer = osc->volume * 10000; break; - case TRACK_INPUT_STEREO_WIDTH: - track->value_buffer = track->stereo_width * 10000; + case OSCILLATOR_INPUT_SUSTAIN: + osc->value_buffer = osc->envelope.sustain * 10000; break; - case TRACK_INPUT_VOLUME: - track->value_buffer = track->volume * 10000; + case OSCILLATOR_INPUT_ATTACK: + osc->value_buffer = osc->envelope.attack * 100000; break; - case TRACK_INPUT_SUSTAIN: - track->value_buffer = track->envelope.sustain * 10000; + case OSCILLATOR_INPUT_DECAY: + osc->value_buffer = osc->envelope.decay * 100000; 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; + case OSCILLATOR_INPUT_RELEASE: + osc->value_buffer = osc->envelope.release * 100000; break; default:; @@ -1142,7 +1224,7 @@ static void saw_ui_track(saw_track_t *track, i64 x0, i64 y0, } } - if (input_index == TRACK_INPUT_VOLUME) + if (input_index == OSCILLATOR_INPUT_VOLUME) next_y += header_offset; next_y += text_height; } @@ -1150,29 +1232,25 @@ static void saw_ui_track(saw_track_t *track, i64 x0, i64 y0, // Draw text // - nvgBeginPath(saw_nvg); + next_y = text_height; + nvgFontSize(saw_nvg, text_height - border); nvgFontFaceId(saw_nvg, saw_font_text); nvgFillColor(saw_nvg, nvgRGBA(255, 255, 255, 255)); + char buf_wave[][100] = { "Sine", "Saw up", "Saw down", + "Sqr up", "Sqr down", "Kick" }; 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", "Saw up", "Saw down", - "Sqr up", "Sqr down", "Kick" }; - nvgText(saw_nvg, x0 + border * 2, - frame_height - y0 - height + next_y - border * 2, "Instr.", + frame_height - y0 - height + next_y - border * 2, "Wave", 0); - if (track->instrument >= 0 && track->instrument < INSTRUMENT_COUNT) + if (osc->wave >= 0 && osc->wave < WAVE_COUNT) nvgText(saw_nvg, x0 + column_width + border * 2, frame_height - y0 - height + next_y - border * 2, - buf_instr[track->instrument], 0); + buf_wave[osc->wave], 0); next_y += text_height; char buf[100]; - sprintf(buf, "%.3f", (f32) track->warp); + sprintf(buf, "%.3f", (f32) osc->warp); nvgText(saw_nvg, x0 + border * 2, frame_height - y0 - height + next_y - border * 2, "Warp", 0); @@ -1180,7 +1258,7 @@ static void saw_ui_track(saw_track_t *track, i64 x0, i64 y0, frame_height - y0 - height + next_y - border * 2, buf, 0); next_y += text_height; - sprintf(buf, "%.3f", (f32) track->phase); + sprintf(buf, "%.3f", (f32) osc->phase); nvgText(saw_nvg, x0 + border * 2, frame_height - y0 - height + next_y - border * 2, "Phase", 0); @@ -1188,25 +1266,7 @@ static void saw_ui_track(saw_track_t *track, i64 x0, i64 y0, 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); + sprintf(buf, "%.3f", (f32) osc->stereo_width); nvgText(saw_nvg, x0 + border * 2, frame_height - y0 - height + next_y - border * 2, "Stereo", 0); @@ -1214,7 +1274,7 @@ static void saw_ui_track(saw_track_t *track, i64 x0, i64 y0, frame_height - y0 - height + next_y - border * 2, buf, 0); next_y += text_height; - sprintf(buf, "%.3f", (f32) track->volume); + sprintf(buf, "%.3f", (f32) osc->volume); nvgText(saw_nvg, x0 + border * 2, frame_height - y0 - height + next_y - border * 2, "Volume", 0); @@ -1227,7 +1287,7 @@ static void saw_ui_track(saw_track_t *track, i64 x0, i64 y0, "Envelope", 0); next_y += text_height; - sprintf(buf, "%.3f", (f32) track->envelope.sustain); + sprintf(buf, "%.3f", (f32) osc->envelope.sustain); nvgText(saw_nvg, x0 + column_width / 4 + border * 2, frame_height - y0 - height + next_y - border * 2, "Sustain", 0); @@ -1235,7 +1295,7 @@ static void saw_ui_track(saw_track_t *track, i64 x0, i64 y0, frame_height - y0 - height + next_y - border * 2, buf, 0); next_y += text_height; - sprintf(buf, "%.1f ms", (f32) (track->envelope.attack * 1000)); + sprintf(buf, "%.1f ms", (f32) (osc->envelope.attack * 1000)); nvgText(saw_nvg, x0 + column_width / 4 + border * 2, frame_height - y0 - height + next_y - border * 2, "Attack", 0); @@ -1243,7 +1303,7 @@ static void saw_ui_track(saw_track_t *track, i64 x0, i64 y0, frame_height - y0 - height + next_y - border * 2, buf, 0); next_y += text_height; - sprintf(buf, "%.1f ms", (f32) (track->envelope.decay * 1000)); + sprintf(buf, "%.1f ms", (f32) (osc->envelope.decay * 1000)); nvgText(saw_nvg, x0 + column_width / 4 + border * 2, frame_height - y0 - height + next_y - border * 2, "Decay", 0); @@ -1251,15 +1311,66 @@ static void saw_ui_track(saw_track_t *track, i64 x0, i64 y0, frame_height - y0 - height + next_y - border * 2, buf, 0); next_y += text_height; - sprintf(buf, "%.1f ms", (f32) (track->envelope.release * 1000)); + sprintf(buf, "%.1f ms", (f32) (osc->envelope.release * 1000)); nvgText(saw_nvg, x0 + column_width / 4 + border * 2, frame_height - y0 - height + next_y - border * 2, "Release", 0); nvgText(saw_nvg, x0 + column_width + border * 2, frame_height - y0 - height + next_y - border * 2, buf, 0); next_y += text_height; +} - nvgFill(saw_nvg); +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; + + nvgFontSize(saw_nvg, text_height - border); + nvgFontFaceId(saw_nvg, saw_font_text); + nvgFillColor(saw_nvg, nvgRGBA(255, 255, 255, 255)); + + 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; + + b8 has_cursor = saw_mouse_x >= x && saw_mouse_y >= y && + saw_mouse_x < x + s && saw_mouse_y < y + s; + + char xmark[] = "\uf00d"; + + nvgFontSize(saw_nvg, text_height); + nvgFontFaceId(saw_nvg, saw_font_icons); + + if (has_cursor) + nvgFillColor(saw_nvg, nvgRGBA(240, 200, 100, 255)); + else + nvgFillColor(saw_nvg, nvgRGBA(240, 200, 100, 160)); + + nvgText(saw_nvg, x + border, y + s - border, xmark, + xmark + (sizeof xmark - 1)); + + if (has_cursor && saw_lbutton_click) + track->instrument = INSTRUMENT_NONE; + } + + switch (track->instrument) { + case INSTRUMENT_OSCILLATOR: + saw_ui_oscillator(&track->oscillator, x0, y0, width, + height - header_offset - text_height); + break; + + default: + saw_ui_choose_instrument(track, x0, y0, width, + height - header_offset - text_height); + } } static void saw_ui_roll(saw_roll_t *roll, i64 x0, i64 y0, i64 width, @@ -1816,20 +1927,21 @@ static void saw_init(void) { for (i32 i = 0; i < TRACK_COUNT; i++) saw_tracks[i] = (saw_track_t) { - .instrument = INSTRUMENT_SINE, - .warp = .0, - .phase = .0, - .unison = 1, - .spread = .1, - .stereo_width = .2, - .volume = 1., - .envelope = { - .sustain = .15, - .attack = .007, - .decay = .3, - .release = .4, - }, - .value_input = TRACK_INPUT_NONE, + .instrument = INSTRUMENT_OSCILLATOR, + .oscillator = { + .wave = WAVE_SINE, + .warp = .0, + .phase = .0, + .stereo_width = .2, + .volume = 1., + .envelope = { + .sustain = .15, + .attack = .007, + .decay = .3, + .release = .4, + }, + .value_input = OSCILLATOR_INPUT_NONE, + } }; // Determine the project file name @@ -1957,30 +2069,38 @@ static void saw_init(void) { for (i64 i = 0; i < total_tracks; i++) { saw_track_t *track = saw_tracks + i; - i64 warp, phase, spread, stereo_width, volume, sustain, attack, - decay, release; - SCAN_(" instrument %d", 1, &track->instrument); - SCAN_(" warp %lld", 1, &warp); - SCAN_(" phase %lld", 1, &phase); - SCAN_(" unison %d", 1, &track->unison); - SCAN_(" spread %lld", 1, &spread); - SCAN_(" stereo_width %lld", 1, &stereo_width); - SCAN_(" volume %lld", 1, &volume); - SCAN_(" sustain %lld", 1, &sustain); - SCAN_(" attack %lld", 1, &attack); - SCAN_(" decay %lld", 1, &decay); - SCAN_(" release %lld", 1, &release); - - track->warp = warp * 0.0001 - 1.; - track->phase = phase * 0.0001; - track->spread = spread * 0.0001; - track->stereo_width = stereo_width * 0.0001; - track->volume = volume * 0.0001; - track->envelope.sustain = sustain * 0.0001; - track->envelope.attack = attack * 0.0001; - track->envelope.decay = decay * 0.0001; - track->envelope.release = release * 0.0001; + + switch (track->instrument) { + case INSTRUMENT_OSCILLATOR: { + saw_oscillator_t *osc = &track->oscillator; + + i64 warp, phase, stereo_width, volume, sustain, attack, + decay, release; + + SCAN_(" wave %d", 1, &osc->wave); + SCAN_(" warp %lld", 1, &warp); + SCAN_(" phase %lld", 1, &phase); + + SCAN_(" stereo_width %lld", 1, &stereo_width); + SCAN_(" volume %lld", 1, &volume); + SCAN_(" sustain %lld", 1, &sustain); + SCAN_(" attack %lld", 1, &attack); + SCAN_(" decay %lld", 1, &decay); + SCAN_(" release %lld", 1, &release); + + osc->warp = warp * 0.0001 - 1.; + osc->phase = phase * 0.0001; + osc->stereo_width = stereo_width * 0.0001; + osc->volume = volume * 0.0001; + osc->envelope.sustain = sustain * 0.0001; + osc->envelope.attack = attack * 0.0001; + osc->envelope.decay = decay * 0.0001; + osc->envelope.release = release * 0.0001; + } break; + + default:; + } } #undef SCAN_ @@ -1990,6 +2110,10 @@ 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. + saw_audio_render(); i64 frame_width = sapp_width(); @@ -2031,112 +2155,104 @@ static void saw_frame(void) { saw_compose.ui_offset_y += saw_mouse_dy; } - if (saw_current_track != -1 && - saw_tracks[saw_current_track].value_input != - TRACK_INPUT_NONE) { + if (saw_current_track != -1) { // Value input // saw_track_t *track = saw_tracks + saw_current_track; - track->value_buffer -= saw_shift_on ? saw_mouse_dy * 300 - : saw_ctrl_on ? saw_mouse_dy - : saw_mouse_dy * 20; - - // TODO - // Unify value input logic. - - // Change input value buffer for selected value. - // - switch (track->value_input) { - case TRACK_INPUT_INSTRUMENT: - track->instrument = (i64) (track->value_buffer * .002 + - 0.5); - if (track->instrument < 0) - track->instrument = 0; - if (track->instrument >= INSTRUMENT_COUNT) - track->instrument = INSTRUMENT_COUNT - 1; - 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; + switch (saw_tracks[saw_current_track].instrument) { + case INSTRUMENT_OSCILLATOR: { + saw_oscillator_t *osc = &track->oscillator; - 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; + if (osc->value_input == OSCILLATOR_INPUT_NONE) + 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; + osc->value_buffer -= saw_shift_on ? saw_mouse_dy * 300 + : saw_ctrl_on ? saw_mouse_dy + : saw_mouse_dy * 20; + + // TODO + // Unify value input logic. + + // Change input value buffer for selected value. + // + switch (osc->value_input) { + case OSCILLATOR_INPUT_WAVE: + osc->wave = (i64) (osc->value_buffer * .002 + 0.5); + if (osc->wave < 0) + osc->wave = 0; + if (osc->wave >= WAVE_COUNT) + osc->wave = WAVE_COUNT - 1; + break; + + case OSCILLATOR_INPUT_WARP: + osc->warp = osc->value_buffer * .0001; + if (osc->warp < -1.) + osc->warp = -1.; + if (osc->warp > 1.) + osc->warp = 1.; + break; + + case OSCILLATOR_INPUT_PHASE: + osc->value_buffer = (f64) ((i64) osc->value_buffer % + 10000); + while (osc->value_buffer < 0) + osc->value_buffer += 10000; + osc->phase = osc->value_buffer * .0001; + break; + + case OSCILLATOR_INPUT_STEREO_WIDTH: + osc->stereo_width = osc->value_buffer * .0001; + if (osc->stereo_width < 0.) + osc->stereo_width = 0.; + if (osc->stereo_width > 2.) + osc->stereo_width = 2.; + break; + + case OSCILLATOR_INPUT_VOLUME: + osc->volume = osc->value_buffer * .0001; + if (osc->volume < 0.) + osc->volume = 0.; + if (osc->volume > 2.) + osc->volume = 2.; + break; + + case OSCILLATOR_INPUT_SUSTAIN: + osc->envelope.sustain = osc->value_buffer * .0001; + if (osc->envelope.sustain < 0.) + osc->envelope.sustain = 0.; + if (osc->envelope.sustain > 1.) + osc->envelope.sustain = 1.; + break; + + case OSCILLATOR_INPUT_ATTACK: + osc->envelope.attack = osc->value_buffer * .00001; + if (osc->envelope.attack < 0.) + osc->envelope.attack = 0.; + if (osc->envelope.attack > 60.) + osc->envelope.attack = 60.; + break; + + case OSCILLATOR_INPUT_DECAY: + osc->envelope.decay = osc->value_buffer * .00001; + if (osc->envelope.decay < 0.) + osc->envelope.decay = 0.; + if (osc->envelope.decay > 60.) + osc->envelope.decay = 60.; + break; + + case OSCILLATOR_INPUT_RELEASE: + osc->envelope.release = osc->value_buffer * .00001; + if (osc->envelope.release < 0.) + osc->envelope.release = 0.; + if (osc->envelope.release > 60.) + osc->envelope.release = 60.; + break; + + default:; + } + } break; default:; } @@ -2314,25 +2430,32 @@ static void saw_cleanup(void) { saw_track_t *track = saw_tracks + i; fprintf(f, "instrument %d\n", track->instrument); - fprintf(f, "warp %lld\n", - (i64) ((1. + track->warp) * 10000 + .5)); - fprintf(f, "phase %lld\n", - (i64) (track->phase * 10000 + .5)); - fprintf(f, "unison %d\n", track->unison); - fprintf(f, "spread %lld\n", - (i64) (track->spread * 10000 + .5)); - fprintf(f, "stereo_width %lld\n", - (i64) (track->stereo_width * 10000 + .5)); - fprintf(f, "volume %lld\n", - (i64) (track->volume * 10000 + .5)); - fprintf(f, "sustain %lld\n", - (i64) (track->envelope.sustain * 10000 + .5)); - fprintf(f, "attack %lld\n", - (i64) (track->envelope.attack * 10000 + .5)); - fprintf(f, "decay %lld\n", - (i64) (track->envelope.decay * 10000 + .5)); - fprintf(f, "release %lld\n\n", - (i64) (track->envelope.release * 10000 + .5)); + + switch (track->instrument) { + case INSTRUMENT_OSCILLATOR: { + saw_oscillator_t *osc = &track->oscillator; + + fprintf(f, "wave %d\n", osc->wave); + fprintf(f, "warp %lld\n", + (i64) ((1. + osc->warp) * 10000 + .5)); + fprintf(f, "phase %lld\n", + (i64) (osc->phase * 10000 + .5)); + fprintf(f, "stereo_width %lld\n", + (i64) (osc->stereo_width * 10000 + .5)); + fprintf(f, "volume %lld\n", + (i64) (osc->volume * 10000 + .5)); + fprintf(f, "sustain %lld\n", + (i64) (osc->envelope.sustain * 10000 + .5)); + fprintf(f, "attack %lld\n", + (i64) (osc->envelope.attack * 10000 + .5)); + fprintf(f, "decay %lld\n", + (i64) (osc->envelope.decay * 10000 + .5)); + fprintf(f, "release %lld\n\n", + (i64) (osc->envelope.release * 10000 + .5)); + } break; + + default:; + } } fclose(f); -- cgit v1.2.3