summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
authorMitya Selivanov <automainint@guattari.tech>2024-02-14 20:26:49 +0100
committerMitya Selivanov <automainint@guattari.tech>2024-02-14 20:26:49 +0100
commit06c55ae15d5b0ad96dd175677403c38d23f1f66b (patch)
tree0296d9e880a2aea2ea191c89a0e6550f61dfe8c5 /source
parentcdd8f26a12b119219b256f5c8ae4d7f0ab88c985 (diff)
downloadsaw-06c55ae15d5b0ad96dd175677403c38d23f1f66b.zip
Choose instrument UI
Diffstat (limited to 'source')
-rw-r--r--source/saw/main.c745
1 files 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);