summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source/saw/main.c229
1 files changed, 122 insertions, 107 deletions
diff --git a/source/saw/main.c b/source/saw/main.c
index 8250850..9945480 100644
--- a/source/saw/main.c
+++ b/source/saw/main.c
@@ -41,6 +41,16 @@ typedef struct {
saw_sheet_note_t notes[SHEET_SIZE];
} saw_sheet_t;
+typedef struct {
+ i32 last_index;
+ i8 turned_off[ROLL_SIZE];
+ saw_sheet_t sheet;
+ i8 grid_input;
+ i32 grid_note;
+ i32 grid_pitch;
+ i32 grid_time;
+} saw_roll_t;
+
static struct NVGcontext *saw_nvg;
static ma_device saw_ma;
@@ -56,16 +66,17 @@ static i32 saw_voice_pitch[VOICE_COUNT] = { 0 };
static i64 saw_voice_time[VOICE_COUNT] = { 0 };
static f64 saw_voice_duration[VOICE_COUNT] = { 0 };
-static i32 saw_roll_last_index = -1;
-static i8 saw_roll_turned_off[ROLL_SIZE] = { 0 };
-static saw_sheet_t saw_roll_sheet = { .rate = 6, .notes = { 0 } };
-static i8 saw_roll_playing = 0;
-static i64 saw_roll_frame = 0;
+static i8 saw_playback_on = 0;
+static i64 saw_playback_frame = 0;
-static i8 saw_grid_input = 0;
-static i32 saw_grid_note = 0;
-static i32 saw_grid_pitch = 0;
-static i32 saw_grid_time = 0;
+static saw_roll_t saw_rolls[1] = { { .last_index = -1,
+ .turned_off = { 0 },
+ .sheet = { .rate = 6,
+ .notes = { 0 } },
+ .grid_input = 0,
+ .grid_note = 0,
+ .grid_pitch = 0,
+ .grid_time = 0 } };
#ifdef __GNUC__
# pragma GCC diagnostic push
@@ -94,17 +105,19 @@ static f64 saw_envelope(f64 t, f64 attack, f64 decay, f64 sustain,
return 0.;
}
-static void saw_roll_playback(i32 frame_count) {
- if (!saw_roll_playing)
+static void saw_playback(i32 frame_count) {
+ if (!saw_playback_on)
return;
+ saw_roll_t *roll = saw_rolls;
+
for (i32 i = 0; i < SHEET_SIZE; i++) {
- saw_sheet_note_t *p = saw_roll_sheet.notes + i;
+ saw_sheet_note_t *p = roll->sheet.notes + i;
if (!p->enabled)
continue;
- i64 frame = (p->time * SAW_SAMPLE_RATE) / saw_roll_sheet.rate;
- if (saw_roll_frame + frame_count <= frame ||
- saw_roll_frame > frame)
+ i64 frame = (p->time * SAW_SAMPLE_RATE) / roll->sheet.rate;
+ if (saw_playback_frame + frame_count <= frame ||
+ saw_playback_frame > frame)
continue;
if (saw_voice_on[VOICE_COUNT - 1])
continue;
@@ -119,15 +132,15 @@ static void saw_roll_playback(i32 frame_count) {
saw_voice_on[0] = 1;
saw_voice_pitch[0] = p->pitch;
saw_voice_time[0] = 0;
- saw_voice_duration[0] = ((f64) p->duration) / saw_roll_sheet.rate;
+ saw_voice_duration[0] = ((f64) p->duration) / roll->sheet.rate;
}
- saw_roll_frame += frame_count;
+ saw_playback_frame += frame_count;
}
static void saw_audio(ma_device *device, void *void_out_,
void const *void_in_, ma_uint32 frame_count) {
- saw_roll_playback(frame_count);
+ saw_playback(frame_count);
f32 *out = (f32 *) void_out_;
@@ -173,49 +186,12 @@ static void saw_audio(ma_device *device, void *void_out_,
# pragma GCC diagnostic pop
#endif
-static void saw_init(void) {
- sapp_set_window_title("saw");
-
-#ifdef SOKOL_GLCORE33
- saw_nvg = nvgCreateGL3(NVG_ANTIALIAS | NVG_STENCIL_STROKES);
-#else
- saw_nvg = nvgCreateGLES3(NVG_ANTIALIAS | NVG_STENCIL_STROKES);
-#endif
-
- ma_device_config config = ma_device_config_init(
- ma_device_type_playback);
-
- config.playback.format = ma_format_f32;
- config.playback.channels = SAW_CHANNEL_COUNT;
- config.sampleRate = SAW_SAMPLE_RATE;
- config.dataCallback = saw_audio;
- config.pUserData = NULL;
-
- if (ma_device_init(NULL, &config, &saw_ma) != MA_SUCCESS) {
- printf("ma_device_init failed.\n");
- return;
- }
-
- ma_device_start(&saw_ma);
-}
-
-static void saw_frame(void) {
- i32 width = sapp_width();
- i32 height = sapp_height();
-
- glViewport(0, 0, width, height);
- glClearColor(.23f, .19f, .16f, 1.f);
- glClearDepth(1.);
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT |
- GL_STENCIL_BUFFER_BIT);
-
- nvgBeginFrame(saw_nvg, width, height, sapp_dpi_scale());
-
+static void saw_ui_roll(saw_roll_t *roll, i64 x0, i64 y0, i64 width,
+ i64 height) {
// Piano roll
//
- i32 x0 = 20;
- i32 y0 = 20;
+ i32 frame_height = sapp_height();
i32 pianokey_height = 35;
i32 pianokey_width = 100;
@@ -228,13 +204,14 @@ static void saw_frame(void) {
for (i32 pitch = 0; pitch < ROLL_SIZE; pitch++) {
i32 x = x0 + roll_border;
- i32 y = height - y0 - (pitch + 1) * pianokey_height + roll_border;
+ i32 y = frame_height - y0 - (pitch + 1) * pianokey_height +
+ roll_border;
i32 w = pianokey_width - roll_border * 2;
i32 h = pianokey_height - roll_border * 2;
- if (y > height - pianokey_height)
+ if (y > y0 + height)
continue;
- if (y < 0)
+ if (y < y0)
break;
nvgBeginPath(saw_nvg);
@@ -243,7 +220,7 @@ static void saw_frame(void) {
i8 has_cursor = saw_mouse_x >= x && saw_mouse_x < x + w &&
saw_mouse_y >= y && saw_mouse_y < y + h;
- nvgFillColor(saw_nvg, saw_roll_turned_off[pitch]
+ nvgFillColor(saw_nvg, roll->turned_off[pitch]
? nvgRGBA(220, 220, 220, 160)
: has_cursor ? nvgRGBA(200, 200, 255, 255)
: nvgRGBA(220, 220, 220, 255));
@@ -255,9 +232,9 @@ static void saw_frame(void) {
if (has_cursor) {
hover_any = 1;
- if (!saw_roll_turned_off[pitch] &&
+ if (!roll->turned_off[pitch] &&
(saw_lbutton_click ||
- (saw_lbutton_down && saw_roll_last_index != pitch)) &&
+ (saw_lbutton_down && roll->last_index != pitch)) &&
!saw_voice_on[VOICE_COUNT - 1]) {
for (i32 n = VOICE_COUNT - 1; n > 0; --n) {
saw_voice_on[n] = saw_voice_on[n - 1];
@@ -273,24 +250,24 @@ static void saw_frame(void) {
}
if (saw_rbutton_click)
- saw_roll_turned_off[pitch] = !saw_roll_turned_off[pitch];
+ roll->turned_off[pitch] = !roll->turned_off[pitch];
- saw_roll_last_index = pitch;
+ roll->last_index = pitch;
}
}
if (!hover_any)
- saw_roll_last_index = -1;
+ roll->last_index = -1;
// Draw music sheet
//
for (i32 pitch = 0; pitch < ROLL_SIZE; pitch++) {
- i32 y = height - y0 - (pitch + 1) * pianokey_height;
+ i32 y = frame_height - y0 - (pitch + 1) * pianokey_height;
- if (y > height - pianokey_height)
+ if (y > y0 + height - pianokey_height)
continue;
- if (y < 0)
+ if (y < y0)
break;
i32 h = pianokey_height;
@@ -298,13 +275,13 @@ static void saw_frame(void) {
for (i32 t = 0;; t++) {
i32 x = x0 + pianokey_width + sheet_offset + t * sheet_scale;
- if (x >= width - roll_border)
+ if (x >= x0 + width - roll_border)
break;
i32 note = -1;
for (i32 n = 0; n < SHEET_SIZE; n++) {
- saw_sheet_note_t *p = saw_roll_sheet.notes + n;
+ saw_sheet_note_t *p = roll->sheet.notes + n;
if (p->enabled && p->pitch == pitch && t >= p->time &&
t < p->time + p->duration) {
note = n;
@@ -327,7 +304,7 @@ static void saw_frame(void) {
has_cursor = saw_mouse_x >= x && saw_mouse_x < x + w &&
saw_mouse_y >= y && saw_mouse_y < y + h;
- nvgFillColor(saw_nvg, saw_roll_turned_off[pitch]
+ nvgFillColor(saw_nvg, roll->turned_off[pitch]
? nvgRGBA(160, 150, 120, 100)
: has_cursor
? nvgRGBA(180, 180, 220, 160)
@@ -337,27 +314,27 @@ static void saw_frame(void) {
// Empty cell input
//
- if (!saw_grid_input && !saw_roll_turned_off[pitch] &&
+ if (!roll->grid_input && !roll->turned_off[pitch] &&
has_cursor && saw_lbutton_click) {
for (i32 n = 0; n < SHEET_SIZE; n++)
- if (!saw_roll_sheet.notes[n].enabled) {
- saw_roll_sheet.notes[n] = (saw_sheet_note_t) {
+ if (!roll->sheet.notes[n].enabled) {
+ roll->sheet.notes[n] = (saw_sheet_note_t) {
.enabled = 1, .time = t, .duration = 1, .pitch = pitch
};
- saw_grid_input = 1;
- saw_grid_note = n;
- saw_grid_pitch = pitch;
- saw_grid_time = t;
+ roll->grid_input = 1;
+ roll->grid_note = n;
+ roll->grid_pitch = pitch;
+ roll->grid_time = t;
break;
}
}
} else {
- i32 w = sheet_scale * saw_roll_sheet.notes[note].duration;
+ i32 w = sheet_scale * roll->sheet.notes[note].duration;
has_cursor = saw_mouse_x >= x && saw_mouse_x < x + w &&
saw_mouse_y >= y && saw_mouse_y < y + h;
- if (t == saw_roll_sheet.notes[note].time) {
+ if (t == roll->sheet.notes[note].time) {
// Draw note
//
@@ -374,7 +351,7 @@ static void saw_frame(void) {
//
if (has_cursor && saw_rbutton_down)
- saw_roll_sheet.notes[note].enabled = 0;
+ roll->sheet.notes[note].enabled = 0;
}
}
}
@@ -383,63 +360,101 @@ static void saw_frame(void) {
// Note stretching input
//
- if (saw_grid_input) {
+ if (roll->grid_input) {
if (saw_lbutton_down) {
i32 t = (saw_mouse_x - x0 - pianokey_width - sheet_offset) /
sheet_scale;
if (t >= 0) {
- saw_sheet_note_t *p = saw_roll_sheet.notes + saw_grid_note;
- if (saw_grid_time <= t) {
- p->time = saw_grid_time;
- p->duration = 1 + t - saw_grid_time;
+ saw_sheet_note_t *p = roll->sheet.notes + roll->grid_note;
+ if (roll->grid_time <= t) {
+ p->time = roll->grid_time;
+ p->duration = 1 + t - roll->grid_time;
} else {
p->time = t;
- p->duration = saw_grid_time - t;
+ p->duration = roll->grid_time - t;
}
}
- saw_sheet_note_t *p = saw_roll_sheet.notes + saw_grid_note;
+ saw_sheet_note_t *p = roll->sheet.notes + roll->grid_note;
for (i32 n = 0; n < SHEET_SIZE; n++) {
- if (n == saw_grid_note)
+ if (n == roll->grid_note)
continue;
- saw_sheet_note_t *q = saw_roll_sheet.notes + n;
+ saw_sheet_note_t *q = roll->sheet.notes + n;
if (!q->enabled || q->pitch != p->pitch)
continue;
- if (q->time < saw_grid_time &&
+ if (q->time < roll->grid_time &&
q->time + q->duration > p->time) {
p->time = q->time + q->duration;
- p->duration = saw_grid_time > p->time
- ? saw_grid_time - p->time
+ p->duration = roll->grid_time > p->time
+ ? roll->grid_time - p->time
: 1;
}
- if (q->time > saw_grid_time &&
+ if (q->time > roll->grid_time &&
q->time < p->time + p->duration) {
- p->time = saw_grid_time;
- p->duration = q->time - saw_grid_time;
+ p->time = roll->grid_time;
+ p->duration = q->time - roll->grid_time;
assert(p->duration > 0);
}
}
} else
- saw_grid_input = 0;
+ roll->grid_input = 0;
}
// Playback indicator
//
- f64 playback_time = ((f64) saw_roll_frame) / SAW_SAMPLE_RATE;
+ f64 playback_time = ((f64) saw_playback_frame) / SAW_SAMPLE_RATE;
i32 x = x0 + pianokey_width + sheet_offset - roll_border * 2 +
- (i32) (playback_time * saw_roll_sheet.rate * sheet_scale +
- .5);
- i32 y = 0;
+ (i32) (playback_time * roll->sheet.rate * sheet_scale + .5);
i32 w = roll_border * 4;
- i32 h = height - y0;
nvgBeginPath(saw_nvg);
- nvgRect(saw_nvg, x, y, w, h);
+ nvgRect(saw_nvg, x, y0, w, height);
nvgFillColor(saw_nvg, nvgRGBA(240, 240, 80, 220));
nvgFill(saw_nvg);
+}
+
+static void saw_init(void) {
+ sapp_set_window_title("saw");
+
+#ifdef SOKOL_GLCORE33
+ saw_nvg = nvgCreateGL3(NVG_ANTIALIAS | NVG_STENCIL_STROKES);
+#else
+ saw_nvg = nvgCreateGLES3(NVG_ANTIALIAS | NVG_STENCIL_STROKES);
+#endif
+
+ ma_device_config config = ma_device_config_init(
+ ma_device_type_playback);
+
+ config.playback.format = ma_format_f32;
+ config.playback.channels = SAW_CHANNEL_COUNT;
+ config.sampleRate = SAW_SAMPLE_RATE;
+ config.dataCallback = saw_audio;
+ config.pUserData = NULL;
+
+ if (ma_device_init(NULL, &config, &saw_ma) != MA_SUCCESS) {
+ printf("ma_device_init failed.\n");
+ return;
+ }
+
+ ma_device_start(&saw_ma);
+}
+
+static void saw_frame(void) {
+ i32 frame_width = sapp_width();
+ i32 frame_height = sapp_height();
+
+ glViewport(0, 0, frame_width, frame_height);
+ glClearColor(.23f, .19f, .16f, 1.f);
+ glClearDepth(1.);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT |
+ GL_STENCIL_BUFFER_BIT);
+
+ nvgBeginFrame(saw_nvg, frame_width, frame_height, sapp_dpi_scale());
+
+ saw_ui_roll(saw_rolls, 0, 0, frame_width, frame_height);
nvgEndFrame(saw_nvg);
@@ -493,9 +508,9 @@ static void saw_event(sapp_event const *event) {
if (!event->key_repeat) {
switch (event->key_code) {
case SAPP_KEYCODE_SPACE:
- saw_roll_playing = !saw_roll_playing;
+ saw_playback_on = !saw_playback_on;
break;
- case SAPP_KEYCODE_ENTER: saw_roll_frame = 0; break;
+ case SAPP_KEYCODE_ENTER: saw_playback_frame = 0; break;
default:;
}
}