summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMitya Selivanov <automainint@guattari.tech>2023-09-29 12:12:08 +0200
committerMitya Selivanov <automainint@guattari.tech>2023-09-29 12:12:08 +0200
commit262d062e1c77d201a0e76d4bc615541a3dc87aeb (patch)
tree40396764f29358992bb0c37a6e707f08dfc36c3f
parent97ee833f60fd378e519421d17458ea743904e96b (diff)
downloadsaw-262d062e1c77d201a0e76d4bc615541a3dc87aeb.zip
UI: Instrument settings
-rw-r--r--TODO2
-rw-r--r--build_and_test.sh4
-rw-r--r--source/saw/main.c547
3 files changed, 404 insertions, 149 deletions
diff --git a/TODO b/TODO
index 380137b..401279d 100644
--- a/TODO
+++ b/TODO
@@ -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,