summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
Diffstat (limited to 'source')
-rw-r--r--source/saw/main.c837
1 files changed, 512 insertions, 325 deletions
diff --git a/source/saw/main.c b/source/saw/main.c
index 865b0ab..bdbb5ad 100644
--- a/source/saw/main.c
+++ b/source/saw/main.c
@@ -1,3 +1,9 @@
+// ================================================================
+//
+// Headers
+//
+// ================================================================
+
#include "../kit/math.h"
#include "../kit/time.h"
#include "../kit/string_ref.h"
@@ -24,14 +30,31 @@
#include <stdio.h>
#include <stdlib.h>
+// Fonts data
#include "fonts.inl.h"
+// ================================================================
+//
+// Definitions
+//
+// ================================================================
+
+// Program version
+//
+
#define VERSION_MAJOR 0
#define VERSION_MINOR 0
#define VERSION_BABY 2
#define VERSION_DEV 1
+// Constants
+//
+
enum {
+ // TODO
+ // Use 28224000 for time rate, divisible by common sample rates
+ // like 192000, 44100 etc.
+
CHANNEL_COUNT = 2,
SAMPLE_RATE = 44100,
@@ -42,8 +65,8 @@ enum {
UNISON_COUNT = 100,
SHEET_SIZE = 200,
- ROLL_DEFAULT_RATE = 8,
- ROLL_DEFAULT_OFFSET_Y = 710,
+ ROLL_DEFAULT_RATE = 8,
+ ROLL_DEFAULT_UI_OFFSET_Y = 710,
INSTRUMENT_SINE = 0,
INSTRUMENT_SAW_UP,
@@ -65,8 +88,16 @@ enum {
TRACK_INPUT_ATTACK,
TRACK_INPUT_DECAY,
TRACK_INPUT_RELEASE,
+
+ EDIT_MODE_HAND = 0,
+ EDIT_MODE_ERASE,
+ EDIT_MODE_PAN,
+ EDIT_MODE_CLONE,
};
+// Data types
+//
+
typedef struct {
b8 enabled;
i64 time;
@@ -93,8 +124,8 @@ typedef struct {
i64 time;
i64 duration;
i64 loop_duration;
- i64 offset_x;
- i64 offset_y;
+ i64 ui_offset_x;
+ i64 ui_offset_y;
// dynamic properties
//
@@ -102,8 +133,8 @@ typedef struct {
b8 grid_input;
i32 grid_note;
i32 grid_time;
- b8 offset_x_input;
- b8 offset_y_input;
+ b8 ui_offset_x_input;
+ b8 ui_offset_y_input;
b8 loop_input;
} saw_roll_t;
@@ -138,34 +169,46 @@ typedef struct {
b8 grid_input;
i32 grid_roll;
i32 grid_cell;
- b8 offset_input;
- i64 offset_x;
- i64 offset_y;
+ b8 ui_offset_input;
+ i64 ui_offset_x;
+ i64 ui_offset_y;
b8 duplicate_input;
} saw_compose_t;
static struct NVGcontext *saw_nvg;
-static ma_device saw_ma;
+static ma_device saw_audio_device;
-static char saw_project_file_buf[4096];
-static str_t saw_project_file;
-static i32 saw_font_text = -1;
-static i32 saw_font_icons = -1;
-static mt64_state_t saw_mt64;
+// Input events
+//
-static i32 saw_mouse_x = 0;
-static i32 saw_mouse_y = 0;
-static b8 saw_lbutton_click = 0;
-static b8 saw_lbutton_down = 0;
-static b8 saw_rbutton_click = 0;
-static b8 saw_rbutton_down = 0;
-static b8 saw_mbutton_click = 0;
-static b8 saw_mbutton_down = 0;
+static i64 saw_mouse_x = 0;
+static i64 saw_mouse_y = 0;
+static i64 saw_mouse_dx = 0;
+static i64 saw_mouse_dy = 0;
+static b8 saw_lbutton_click = 0;
+static b8 saw_lbutton_down = 0;
+static b8 saw_rbutton_click = 0;
+static b8 saw_rbutton_down = 0;
+static b8 saw_mbutton_click = 0;
+static b8 saw_mbutton_down = 0;
+static b8 saw_shift_on = 0;
+static b8 saw_ctrl_on = 0;
+static b8 saw_key_pressed[512] = { 0 };
+
+// Global state
+//
static b8 saw_playback_on = 0;
static i64 saw_playback_frame = 0;
static i64 saw_current_track = 0;
static i64 saw_current_roll = 0;
+static i64 saw_edit_mode = EDIT_MODE_HAND;
+
+static char saw_project_file_buf[4096];
+static str_t saw_project_file;
+static i32 saw_font_text = -1;
+static i32 saw_font_icons = -1;
+static mt64_state_t saw_mt64; // RNG
static saw_voice_t saw_voices[VOICE_COUNT] = { 0 };
static saw_roll_t saw_rolls[ROLL_COUNT];
@@ -176,15 +219,15 @@ static saw_compose_t saw_compose = {
.grid_input = 0,
.grid_roll = 0,
.grid_cell = 0,
- .offset_input = 0,
- .offset_x = 0,
- .offset_y = 0,
+ .ui_offset_input = 0,
+ .ui_offset_x = 0,
+ .ui_offset_y = 0,
.duplicate_input = 0,
};
// ================================================================
//
-// Audio
+// Sound
//
// ================================================================
@@ -316,9 +359,8 @@ static f64 saw_oscillator(i32 type, f64 frequency, f64 phase,
static void saw_audio(ma_device *device, void *void_out_,
void const *void_in_, ma_uint32 frame_count) {
- // FIXME
+ // TODO
// Render to audio buffer separately.
- //
saw_playback(frame_count);
@@ -378,10 +420,21 @@ static void saw_audio(ma_device *device, void *void_out_,
//
// ================================================================
+static void saw_reset_ui_offset(void) {
+ if (saw_current_roll != -1) {
+ saw_rolls[saw_current_roll].ui_offset_x = 0;
+ saw_rolls[saw_current_roll].ui_offset_y =
+ ROLL_DEFAULT_UI_OFFSET_Y;
+ }
+
+ saw_compose.ui_offset_x = 0;
+ saw_compose.ui_offset_y = 0;
+}
+
static void saw_ui_header(i64 x0, u64 y0, u64 width, i64 height) {
i64 frame_height = sapp_height();
- i64 border = 12;
+ i64 border = 14;
nvgFontSize(saw_nvg, height - border * 2);
nvgFontFaceId(saw_nvg, saw_font_icons);
@@ -398,46 +451,81 @@ static void saw_ui_header(i64 x0, u64 y0, u64 width, i64 height) {
char panning[] = "\uf047";
char clone[] = "\uf24d";
- u8 color[] = { 220, 220, 220, 255 };
-
-#define ICON_(i_) \
- do { \
- b8 has_cursor = saw_mouse_x >= x && saw_mouse_x < x + height && \
- saw_mouse_y >= frame_height - y0 - height && \
- saw_mouse_y < frame_height - y0; \
- if (has_cursor) \
- nvgFillColor(saw_nvg, nvgRGBA(255, 255, 220, 255)); \
- nvgText(saw_nvg, x, h, (i_), (i_) + (sizeof(i_) - 1)); \
- if (has_cursor) \
- nvgFillColor(saw_nvg, \
- nvgRGBA(color[0], color[1], color[2], color[3])); \
- x += height; \
+ u8 color_active[] = { 220, 220, 220, 255 };
+ u8 color_hover[] = { 255, 255, 220, 255 };
+ u8 color_selected[] = { 255, 255, 255, 255 };
+
+ b8 has_cursor = 0;
+
+#define ICON_(i_, selected_) \
+ do { \
+ has_cursor = saw_mouse_x >= x && saw_mouse_x < x + height && \
+ saw_mouse_y >= frame_height - y0 - height && \
+ saw_mouse_y < frame_height - y0; \
+ if (has_cursor) \
+ nvgFillColor(saw_nvg, \
+ nvgRGBA(color_hover[0], color_hover[1], \
+ color_hover[2], color_hover[3])); \
+ else if (selected_) \
+ nvgFillColor(saw_nvg, \
+ nvgRGBA(color_selected[0], color_selected[1], \
+ color_selected[2], color_selected[3])); \
+ else \
+ nvgFillColor(saw_nvg, \
+ nvgRGBA(color_active[0], color_active[1], \
+ color_active[2], color_active[3])); \
+ nvgText(saw_nvg, x, h, (i_), (i_) + (sizeof(i_) - 1)); \
+ x += height; \
} while (0)
- nvgFillColor(saw_nvg,
- nvgRGBA(color[0], color[1], color[2], color[3]));
+ // Global actions
+ //
- ICON_(backward_fast);
+ ICON_(backward_fast, 0);
+ if (has_cursor && saw_lbutton_click)
+ saw_playback_frame = 0;
if (saw_playback_on)
- ICON_(stop);
+ ICON_(stop, 0);
else
- ICON_(play);
+ ICON_(play, 0);
+ if (has_cursor && saw_lbutton_click)
+ saw_playback_on = !saw_playback_on;
+
+ ICON_(anchor, 0);
+ if (has_cursor && saw_lbutton_click)
+ saw_reset_ui_offset();
+
+ // Editing mode
+ //
- ICON_(anchor);
- ICON_(hand_pointer);
+ x += height / 2;
- color[0] = 220;
- color[1] = 220;
- color[2] = 220;
- color[3] = 160;
+ color_active[0] = 220;
+ color_active[1] = 180;
+ color_active[2] = 80;
+ color_active[3] = 160;
- nvgFillColor(saw_nvg,
- nvgRGBA(color[0], color[1], color[2], color[3]));
+ color_selected[0] = 220;
+ color_selected[1] = 180;
+ color_selected[2] = 80;
+ color_selected[3] = 255;
- ICON_(eraser);
- ICON_(panning);
- ICON_(clone);
+ ICON_(hand_pointer, saw_edit_mode == EDIT_MODE_HAND);
+ if (has_cursor && saw_lbutton_click)
+ saw_edit_mode = EDIT_MODE_HAND;
+
+ ICON_(eraser, saw_edit_mode == EDIT_MODE_ERASE);
+ if (has_cursor && saw_lbutton_click)
+ saw_edit_mode = EDIT_MODE_ERASE;
+
+ ICON_(panning, saw_edit_mode == EDIT_MODE_PAN);
+ if (has_cursor && saw_lbutton_click)
+ saw_edit_mode = EDIT_MODE_PAN;
+
+ ICON_(clone, saw_edit_mode == EDIT_MODE_CLONE);
+ if (has_cursor && saw_lbutton_click)
+ saw_edit_mode = EDIT_MODE_CLONE;
#undef ICON_
}
@@ -475,11 +563,11 @@ static void saw_ui_compose(i64 x0, i64 y0, i64 width, i64 height) {
i64 top = frame_height - y0 - height + track_height;
i64 bottom = frame_height - y0;
- i64 dx = x0 + saw_compose.offset_x;
+ i64 dx = x0 + saw_compose.ui_offset_x;
i64 l = dx + (roll->time * grid_scale) / SAMPLE_RATE;
i64 r = l + (roll->duration * grid_scale) / SAMPLE_RATE;
i64 u = frame_height - y0 - height + track_height +
- saw_compose.offset_y + roll->track * track_height;
+ saw_compose.ui_offset_y + roll->track * track_height;
i64 d = u + track_height;
i64 s = grid_scale / grid_rate;
@@ -521,15 +609,16 @@ static void saw_ui_compose(i64 x0, i64 y0, i64 width, i64 height) {
nvgFill(saw_nvg);
if (has_cursor) {
- if (saw_rbutton_down) {
+ if (saw_rbutton_down ||
+ (saw_edit_mode == EDIT_MODE_ERASE && saw_lbutton_down)) {
if (saw_current_roll == saw_compose.rolls[i])
saw_current_roll = -1;
saw_compose.rolls[i] = -1;
roll->enabled = 0;
} else {
- if (saw_lbutton_click) {
+ if (saw_edit_mode == EDIT_MODE_HAND && saw_lbutton_click) {
if (saw_current_roll == saw_compose.rolls[i]) {
- i64 cell = ((saw_mouse_x - saw_compose.offset_x) *
+ i64 cell = ((saw_mouse_x - saw_compose.ui_offset_x) *
grid_rate) /
grid_scale;
i64 c0 = (roll->time * grid_rate) / SAMPLE_RATE;
@@ -558,24 +647,26 @@ static void saw_ui_compose(i64 x0, i64 y0, i64 width, i64 height) {
// Placing new sheet
//
- if (!hover_any && saw_lbutton_down &&
- saw_mouse_x >= x0 + saw_compose.offset_x &&
+ if (!hover_any && saw_edit_mode == EDIT_MODE_HAND &&
+ saw_lbutton_down &&
+ saw_mouse_x >= x0 + saw_compose.ui_offset_x &&
saw_mouse_x < x0 + width) {
if (!saw_compose.grid_input &&
saw_mouse_y >= frame_height - y0 - height &&
saw_mouse_y < frame_height - y0 - height + track_height)
- saw_playback_frame = ((saw_mouse_x - saw_compose.offset_x) *
+ saw_playback_frame = ((saw_mouse_x - saw_compose.ui_offset_x) *
SAMPLE_RATE) /
grid_scale;
- else if (saw_lbutton_click &&
+ else if (saw_edit_mode == EDIT_MODE_HAND && saw_lbutton_click &&
saw_mouse_y >=
frame_height - y0 - height + track_height &&
saw_mouse_y < frame_height - y0) {
- i64 track = (saw_mouse_y - saw_compose.offset_y - frame_height +
- y0 + height) /
+ i64 track = (saw_mouse_y - saw_compose.ui_offset_y -
+ frame_height + y0 + height) /
track_height -
1;
- i64 cell = ((saw_mouse_x - saw_compose.offset_x) * grid_rate) /
+ i64 cell = ((saw_mouse_x - saw_compose.ui_offset_x) *
+ grid_rate) /
grid_scale;
i64 frame = (cell * SAMPLE_RATE) / grid_rate;
@@ -587,10 +678,10 @@ static void saw_ui_compose(i64 x0, i64 y0, i64 width, i64 height) {
break;
}
- i64 x = x0 + saw_compose.offset_x +
+ i64 x = x0 + saw_compose.ui_offset_x +
(frame * grid_scale) / SAMPLE_RATE;
i64 y = frame_height - y0 - height + track_height +
- saw_compose.offset_y + track * track_height;
+ saw_compose.ui_offset_y + track * track_height;
if (track < 0 || track >= TRACK_COUNT || x < x0 ||
x >= x0 + width || y < frame_height - y0 - height ||
@@ -616,16 +707,16 @@ static void saw_ui_compose(i64 x0, i64 y0, i64 width, i64 height) {
.time = frame,
.duration = (ROLL_DEFAULT_RATE * SAMPLE_RATE) / grid_rate,
.loop_duration = 0,
- .offset_x = 0,
- .offset_y = ROLL_DEFAULT_OFFSET_Y,
-
- .last_index = -1,
- .grid_input = 0,
- .grid_note = 0,
- .grid_time = 0,
- .offset_x_input = 0,
- .offset_y_input = 0,
- .loop_input = 0,
+ .ui_offset_x = 0,
+ .ui_offset_y = ROLL_DEFAULT_UI_OFFSET_Y,
+
+ .last_index = -1,
+ .grid_input = 0,
+ .grid_note = 0,
+ .grid_time = 0,
+ .ui_offset_x_input = 0,
+ .ui_offset_y_input = 0,
+ .loop_input = 0,
};
saw_current_roll = n;
@@ -644,11 +735,12 @@ static void saw_ui_compose(i64 x0, i64 y0, i64 width, i64 height) {
if (saw_current_roll == -1)
break;
- i64 track = (saw_mouse_y - saw_compose.offset_y - frame_height +
- y0 + height) /
+ i64 track = (saw_mouse_y - saw_compose.ui_offset_y -
+ frame_height + y0 + height) /
track_height -
1;
- i64 cell = ((saw_mouse_x - saw_compose.offset_x) * grid_rate) /
+ i64 cell = ((saw_mouse_x - saw_compose.ui_offset_x) *
+ grid_rate) /
grid_scale;
if (cell < 0 || track < 0 || track >= TRACK_COUNT)
@@ -700,22 +792,25 @@ static void saw_ui_compose(i64 x0, i64 y0, i64 width, i64 height) {
// Panning input
//
- if (saw_mbutton_click) {
+ if (saw_mbutton_click ||
+ (saw_edit_mode == EDIT_MODE_PAN && saw_lbutton_click)) {
if (saw_mouse_x >= x0 &&
saw_mouse_y >= frame_height - y0 - height + track_height &&
saw_mouse_x < x0 + width && saw_mouse_y < frame_height - y0)
- saw_compose.offset_input = 1;
+ saw_compose.ui_offset_input = 1;
}
- if (!saw_mbutton_down)
- saw_compose.offset_input = 0;
+ if (!(saw_mbutton_down ||
+ (saw_edit_mode == EDIT_MODE_PAN && saw_lbutton_down)))
+ saw_compose.ui_offset_input = 0;
// Track stretching input
//
if (saw_compose.grid_input) {
- if (saw_lbutton_down) {
- i64 cell = ((saw_mouse_x - saw_compose.offset_x) * grid_rate) /
+ if (saw_edit_mode == EDIT_MODE_HAND && saw_lbutton_down) {
+ i64 cell = ((saw_mouse_x - saw_compose.ui_offset_x) *
+ grid_rate) /
grid_scale;
saw_roll_t *p = saw_rolls + saw_compose.grid_roll;
@@ -768,7 +863,7 @@ static void saw_ui_compose(i64 x0, i64 y0, i64 width, i64 height) {
// Playback indicator
//
- i64 x = x0 + saw_compose.offset_x - border * 2 +
+ i64 x = x0 + saw_compose.ui_offset_x - border * 2 +
(saw_playback_frame * grid_scale + SAMPLE_RATE / 2) /
SAMPLE_RATE;
i64 w = border * 4;
@@ -784,17 +879,17 @@ static void saw_ui_compose(i64 x0, i64 y0, i64 width, i64 height) {
//
if (!hover_any && !saw_compose.grid_input &&
- saw_mouse_x >= x0 + saw_compose.offset_x) {
- i64 track = (saw_mouse_y - saw_compose.offset_y - frame_height +
- y0 + height) /
+ saw_mouse_x >= x0 + saw_compose.ui_offset_x) {
+ i64 track = (saw_mouse_y - saw_compose.ui_offset_y -
+ frame_height + y0 + height) /
track_height -
1;
- i64 cell = ((saw_mouse_x - saw_compose.offset_x) * grid_rate) /
+ i64 cell = ((saw_mouse_x - saw_compose.ui_offset_x) * grid_rate) /
grid_scale;
- i64 x = x0 + saw_compose.offset_x +
+ i64 x = x0 + saw_compose.ui_offset_x +
(cell * grid_scale) / grid_rate;
i64 y = frame_height - y0 - height + track_height +
- saw_compose.offset_y + track * track_height;
+ saw_compose.ui_offset_y + track * track_height;
i64 w = grid_scale / grid_rate;
if (track >= 0 && track < TRACK_COUNT && x >= x0 &&
@@ -812,11 +907,11 @@ static void saw_ui_compose(i64 x0, i64 y0, i64 width, i64 height) {
// Cursor indicator
//
- if (saw_mouse_x >= x0 + saw_compose.offset_x &&
+ if (saw_mouse_x >= x0 + saw_compose.ui_offset_x &&
saw_mouse_x < x0 + width &&
saw_mouse_y >= frame_height - y0 - height &&
saw_mouse_y < frame_height - y0) {
- i64 dx = x0 + saw_compose.offset_x;
+ i64 dx = x0 + saw_compose.ui_offset_x;
i64 s = grid_scale / grid_rate;
i64 x = dx + ((saw_mouse_x - dx + s / 2) / s) * s;
i64 w = border * 4;
@@ -854,9 +949,9 @@ static void saw_ui_track(saw_track_t *track, i64 x0, i64 y0,
for (i64 input_index = TRACK_INPUT_INSTRUMENT;
input_index <= TRACK_INPUT_RELEASE; ++input_index) {
- // FIXME
+ // TODO
// Implement Unison and Spread.
- //
+
if (input_index == TRACK_INPUT_UNISON ||
input_index == TRACK_INPUT_SPREAD)
continue;
@@ -956,11 +1051,11 @@ static void saw_ui_track(saw_track_t *track, i64 x0, i64 y0,
title.values, title.values + title.size);
next_y = header_offset + text_height;
- char buf_instr[][100] = { "Sine", "Saw up", "Saw down",
- "Square up", "Square down", "Kick" };
+ 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,
- "Instrument", 0);
+ frame_height - y0 - height + next_y - border * 2, "Instr.",
+ 0);
if (track->instrument >= 0 && track->instrument < INSTRUMENT_COUNT)
nvgText(saw_nvg, x0 + column_width + border * 2,
frame_height - y0 - height + next_y - border * 2,
@@ -1099,25 +1194,45 @@ static void saw_ui_roll(saw_roll_t *roll, i64 x0, i64 y0, i64 width,
char repeat[] = "\uf363";
- nvgFontSize(saw_nvg, header_height - 4);
+ i64 border = 5;
+ nvgFontSize(saw_nvg, header_height - border * 2);
nvgFontFaceId(saw_nvg, saw_font_icons);
- nvgFillColor(saw_nvg, nvgRGBA(180, 80, 40, 200));
- nvgText(saw_nvg, x - header_height * 2 + 2, y + header_height - 2,
- repeat, repeat + (sizeof repeat - 1));
-
- i64 w0 = (roll->loop_duration * roll->rate * sheet_scale +
+ if (roll->loop_duration == 0)
+ nvgFillColor(saw_nvg, nvgRGBA(80, 80, 80, 160));
+ else
+ nvgFillColor(saw_nvg, nvgRGBA(180, 80, 40, 200));
+ nvgText(saw_nvg, x - header_height * 2 + border,
+ y + header_height - border, repeat,
+ repeat + (sizeof repeat - 1));
+
+ i64 rw = (roll->loop_duration * roll->rate * sheet_scale +
SAMPLE_RATE / 2) /
SAMPLE_RATE;
+ i64 rx = roll->ui_offset_x;
- nvgBeginPath(saw_nvg);
- nvgRect(saw_nvg, x, y, w0, h);
- nvgRect(saw_nvg, x, y + h * 4, w0, h);
- nvgFillColor(saw_nvg, nvgRGBA(180, 80, 40, 160));
- nvgFill(saw_nvg);
+ if (rx < 0) {
+ rw += rx;
+ rx = 0;
+ }
+
+ if (rw > w - rx)
+ rw = w - rx;
+
+ if (rw > 0) {
+ nvgBeginPath(saw_nvg);
+ nvgRect(saw_nvg, x + rx, y, rw, h);
+ nvgRect(saw_nvg, x + rx, y + h * 4, rw, h);
+ nvgFillColor(saw_nvg, nvgRGBA(180, 80, 40, 160));
+ nvgFill(saw_nvg);
+ }
nvgBeginPath(saw_nvg);
- nvgRect(saw_nvg, x + w0, y, w - w0, h);
- nvgRect(saw_nvg, x + w0, y + h * 4, w - w0, h);
+ if (rx > 0) {
+ nvgRect(saw_nvg, x, y, rx, h);
+ nvgRect(saw_nvg, x, y + h * 4, rx, h);
+ }
+ nvgRect(saw_nvg, x + rx + rw, y, w - rx - rw, h);
+ nvgRect(saw_nvg, x + rx + rw, y + h * 4, w - rx - rw, h);
nvgFillColor(saw_nvg, nvgRGBA(80, 80, 80, 160));
nvgFill(saw_nvg);
@@ -1128,7 +1243,7 @@ static void saw_ui_roll(saw_roll_t *roll, i64 x0, i64 y0, i64 width,
if (roll->loop_input && saw_lbutton_down) {
i64 t = (saw_mouse_x - x0 - pianokey_width - sheet_offset -
- roll->offset_x + sheet_scale / 2) /
+ roll->ui_offset_x + sheet_scale / 2) /
sheet_scale;
if (t <= 0)
@@ -1150,7 +1265,7 @@ static void saw_ui_roll(saw_roll_t *roll, i64 x0, i64 y0, i64 width,
for (i64 pitch = 0; pitch < PITCH_COUNT; pitch++) {
i64 x = x0 + border;
i64 y = frame_height - y0 - (pitch + 1) * pianokey_height +
- border + roll->offset_y;
+ border + roll->ui_offset_y;
i64 w = pianokey_width - border * 2;
i64 h = pianokey_height - border * 2;
@@ -1178,12 +1293,14 @@ static void saw_ui_roll(saw_roll_t *roll, i64 x0, i64 y0, i64 width,
hover_any = 1;
if (!roll->pitch_turned_off[pitch] &&
- (saw_lbutton_click ||
- (saw_lbutton_down && roll->last_index != pitch)))
+ ((saw_edit_mode == EDIT_MODE_HAND && saw_lbutton_click) ||
+ (saw_edit_mode == EDIT_MODE_HAND && saw_lbutton_down &&
+ roll->last_index != pitch)))
saw_play_voice(saw_tracks + roll->track, roll, pitch,
SAMPLE_RATE / roll->rate);
- if (saw_rbutton_click)
+ if (saw_rbutton_click ||
+ (saw_edit_mode == EDIT_MODE_ERASE && saw_lbutton_click))
roll->pitch_turned_off[pitch] =
!roll->pitch_turned_off[pitch];
@@ -1197,20 +1314,23 @@ static void saw_ui_roll(saw_roll_t *roll, i64 x0, i64 y0, i64 width,
// Panning input
//
- if (saw_mbutton_click) {
+ if (saw_mbutton_click || (saw_edit_mode == EDIT_MODE_PAN &&
+ saw_lbutton_click && !roll->loop_input)) {
if (saw_mouse_x >= x0 + pianokey_width + sheet_offset &&
saw_mouse_y >= frame_height - y0 - height + text_height &&
saw_mouse_x < x0 + width && saw_mouse_y < frame_height - y0)
- roll->offset_x_input = 1;
+ roll->ui_offset_x_input = 1;
if (saw_mouse_x >= x0 &&
saw_mouse_y >= frame_height - y0 - height + text_height &&
saw_mouse_x < x0 + width && saw_mouse_y < frame_height - y0)
- roll->offset_y_input = 1;
+ roll->ui_offset_y_input = 1;
}
- if (!saw_mbutton_down) {
- roll->offset_x_input = 0;
- roll->offset_y_input = 0;
+ if (!(saw_mbutton_down ||
+ (saw_edit_mode == EDIT_MODE_PAN && saw_lbutton_down &&
+ !roll->loop_input))) {
+ roll->ui_offset_x_input = 0;
+ roll->ui_offset_y_input = 0;
}
// Draw music sheet
@@ -1218,7 +1338,7 @@ static void saw_ui_roll(saw_roll_t *roll, i64 x0, i64 y0, i64 width,
for (i64 pitch = 0; pitch < PITCH_COUNT; pitch++) {
i64 y = frame_height - y0 - (pitch + 1) * pianokey_height +
- roll->offset_y;
+ roll->ui_offset_y;
if (y > frame_height - y0 - pianokey_height)
continue;
@@ -1230,7 +1350,7 @@ static void saw_ui_roll(saw_roll_t *roll, i64 x0, i64 y0, i64 width,
for (i64 t = 0; t < (roll->duration * roll->rate) / SAMPLE_RATE;
t++) {
i64 x = x0 + pianokey_width + sheet_offset + t * sheet_scale +
- roll->offset_x;
+ roll->ui_offset_x;
if (x >= x0 + width - sheet_scale - border)
break;
@@ -1284,7 +1404,7 @@ static void saw_ui_roll(saw_roll_t *roll, i64 x0, i64 y0, i64 width,
//
if (!roll->grid_input && !turned_off && has_cursor &&
- saw_lbutton_click)
+ saw_edit_mode == EDIT_MODE_HAND && saw_lbutton_click)
for (i64 n = 0; n < SHEET_SIZE; n++)
if (!roll->notes[n].enabled) {
roll->notes[n] = (saw_roll_note_t) {
@@ -1312,14 +1432,14 @@ static void saw_ui_roll(saw_roll_t *roll, i64 x0, i64 y0, i64 width,
continue;
i64 y = frame_height - y0 - (note->pitch + 1) * pianokey_height +
- roll->offset_y;
+ roll->ui_offset_y;
if (y + pianokey_height > frame_height - y0)
continue;
if (y < frame_height - y0 - height + text_height + header_height)
continue;
- i64 x = x0 + pianokey_width + sheet_offset + roll->offset_x +
+ i64 x = x0 + pianokey_width + sheet_offset + roll->ui_offset_x +
(note->time * roll->rate * sheet_scale +
SAMPLE_RATE / 2) /
SAMPLE_RATE;
@@ -1377,7 +1497,9 @@ static void saw_ui_roll(saw_roll_t *roll, i64 x0, i64 y0, i64 width,
// Note input
//
- if (has_cursor && saw_rbutton_down)
+ if (has_cursor &&
+ (saw_rbutton_down ||
+ (saw_edit_mode == EDIT_MODE_ERASE && saw_lbutton_down)))
note->enabled = 0;
}
@@ -1385,9 +1507,9 @@ static void saw_ui_roll(saw_roll_t *roll, i64 x0, i64 y0, i64 width,
//
if (roll->grid_input) {
- if (saw_lbutton_down) {
+ if (saw_edit_mode == EDIT_MODE_HAND && saw_lbutton_down) {
i64 t = (saw_mouse_x - x0 - pianokey_width - sheet_offset -
- roll->offset_x) /
+ roll->ui_offset_x) /
sheet_scale;
saw_roll_note_t *p = roll->notes + roll->grid_note;
@@ -1442,7 +1564,7 @@ static void saw_ui_roll(saw_roll_t *roll, i64 x0, i64 y0, i64 width,
frame -= ((frame - roll->time) / roll->loop_duration) *
roll->loop_duration;
- i64 x = x0 + pianokey_width + sheet_offset + roll->offset_x -
+ i64 x = x0 + pianokey_width + sheet_offset + roll->ui_offset_x -
border * 2 +
((frame - roll->time) * roll->rate * sheet_scale +
SAMPLE_RATE / 2) /
@@ -1465,7 +1587,7 @@ static void saw_ui_roll(saw_roll_t *roll, i64 x0, i64 y0, i64 width,
saw_mouse_x < x0 + width &&
saw_mouse_y >= frame_height - y0 - height &&
saw_mouse_y < frame_height - y0) {
- i64 dx = x0 + pianokey_width + sheet_offset + roll->offset_x;
+ i64 dx = x0 + pianokey_width + sheet_offset + roll->ui_offset_x;
i64 x = dx +
((saw_mouse_x - dx + sheet_scale / 2) / sheet_scale) *
sheet_scale;
@@ -1516,12 +1638,13 @@ static void saw_init(void) {
config.dataCallback = saw_audio;
config.pUserData = NULL;
- if (ma_device_init(NULL, &config, &saw_ma) != MA_SUCCESS) {
+ if (ma_device_init(NULL, &config, &saw_audio_device) !=
+ MA_SUCCESS) {
printf("ma_device_init failed.\n");
return;
}
- ma_device_start(&saw_ma);
+ ma_device_start(&saw_audio_device);
// Load fonts
//
@@ -1554,15 +1677,15 @@ static void saw_init(void) {
.time = 0,
.duration = (48 * SAMPLE_RATE) / ROLL_DEFAULT_RATE,
.loop_duration = 0,
- .offset_x = 0,
- .offset_y = ROLL_DEFAULT_OFFSET_Y,
-
- .grid_input = 0,
- .grid_note = 0,
- .grid_time = 0,
- .offset_x_input = 0,
- .offset_y_input = 0,
- .loop_input = 0,
+ .ui_offset_x = 0,
+ .ui_offset_y = ROLL_DEFAULT_UI_OFFSET_Y,
+
+ .grid_input = 0,
+ .grid_note = 0,
+ .grid_time = 0,
+ .ui_offset_x_input = 0,
+ .ui_offset_y_input = 0,
+ .loop_input = 0,
};
}
@@ -1692,7 +1815,8 @@ static void saw_init(void) {
SCAN_(" time %lld", 1, &roll->time);
SCAN_(" duration %lld", 1, &roll->duration);
SCAN_(" loop_duration %lld", 1, &roll->loop_duration);
- SCAN_(" offset %lld %lld", 2, &roll->offset_x, &roll->offset_y);
+ SCAN_(" ui_offset %lld %lld", 2, &roll->ui_offset_x,
+ &roll->ui_offset_y);
}
i32 total_tracks;
@@ -1734,8 +1858,8 @@ static void saw_init(void) {
}
static void saw_frame(void) {
- // FIXME
- // - Adjust sleep depending on how much compute we need
+ // TODO
+ // Adjust sleep depending on how much compute we need
// Sleep to prevent high CPU load
thrd_sleep(&(struct timespec) { .tv_nsec = 10000000 }, NULL);
@@ -1744,7 +1868,7 @@ static void saw_frame(void) {
i64 frame_height = sapp_height();
glViewport(0, 0, frame_width, frame_height);
- glClearColor(.15f, .12f, .10f, 1.f);
+ glClearColor(.11f, .09f, .08f, 1.f);
#ifdef SOKOL_GLCORE33
glClearDepth(1.);
#else
@@ -1753,10 +1877,148 @@ static void saw_frame(void) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT |
GL_STENCIL_BUFFER_BIT);
- nvgBeginFrame(saw_nvg, frame_width, frame_height, sapp_dpi_scale());
+ // Process input
+ //
+ {
+ if (saw_key_pressed[SAPP_KEYCODE_SPACE])
+ saw_playback_on = !saw_playback_on;
+ if (saw_key_pressed[SAPP_KEYCODE_ENTER])
+ saw_playback_frame = 0;
+ if (saw_key_pressed[SAPP_KEYCODE_ESCAPE])
+ saw_reset_ui_offset();
+ if (saw_key_pressed[SAPP_KEYCODE_D] ||
+ (saw_edit_mode == EDIT_MODE_CLONE && saw_lbutton_click))
+ saw_compose.duplicate_input = 1;
+
+ // Panning control
+ //
+ for (i64 i = 0; i < ROLL_COUNT; i++) {
+ if (saw_rolls[i].ui_offset_x_input)
+ saw_rolls[i].ui_offset_x += saw_mouse_dx;
+ if (saw_rolls[i].ui_offset_y_input)
+ saw_rolls[i].ui_offset_y += saw_mouse_dy;
+ }
+ if (saw_compose.ui_offset_input) {
+ saw_compose.ui_offset_x += saw_mouse_dx;
+ saw_compose.ui_offset_y += saw_mouse_dy;
+ }
+
+ if (saw_current_track != -1 &&
+ saw_tracks[saw_current_track].value_input !=
+ TRACK_INPUT_NONE) {
+ // 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;
+
+ 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:;
+ }
+ }
+ }
// Render UI
//
+
+ nvgBeginFrame(saw_nvg, frame_width, frame_height, sapp_dpi_scale());
{
// Adjust UI layout
//
@@ -1820,19 +2082,27 @@ static void saw_frame(void) {
);
}
}
-
nvgEndFrame(saw_nvg);
// Cleanup input state.
//
+ {
+ saw_mouse_dx = 0;
+ saw_mouse_dy = 0;
+
+ saw_lbutton_click = 0;
+ saw_rbutton_click = 0;
+ saw_mbutton_click = 0;
+
+ saw_shift_on = 0;
+ saw_ctrl_on = 0;
- saw_lbutton_click = 0;
- saw_rbutton_click = 0;
- saw_mbutton_click = 0;
+ memset(saw_key_pressed, 0, sizeof saw_key_pressed);
+ }
}
static void saw_cleanup(void) {
- ma_device_uninit(&saw_ma);
+ ma_device_uninit(&saw_audio_device);
#ifdef SOKOL_GLCORE33
nvgDeleteGL3(saw_nvg);
@@ -1899,8 +2169,8 @@ static void saw_cleanup(void) {
fprintf(f, "time %lld\n", roll->time);
fprintf(f, "duration %lld\n", roll->duration);
fprintf(f, "loop_duration %lld\n", roll->loop_duration);
- fprintf(f, "offset %lld %lld\n\n", roll->offset_x,
- roll->offset_y);
+ fprintf(f, "ui_offset %lld %lld\n\n",
+ roll->ui_offset_x, roll->ui_offset_y);
}
// Save tracks
@@ -1937,144 +2207,23 @@ static void saw_cleanup(void) {
}
static void saw_event(sapp_event const *event) {
- // FIXME
- // Do input processing in frame update procedure.
- //
-
switch (event->type) {
case SAPP_EVENTTYPE_MOUSE_MOVE:
- saw_mouse_x = event->mouse_x;
- saw_mouse_y = event->mouse_y;
-
- for (i64 i = 0; i < ROLL_COUNT; i++) {
- // Panning control
- //
- if (saw_rolls[i].offset_x_input)
- saw_rolls[i].offset_x += event->mouse_dx;
- if (saw_rolls[i].offset_y_input)
- saw_rolls[i].offset_y += event->mouse_dy;
- }
-
- if (saw_compose.offset_input) {
- // Panning control
- //
- saw_compose.offset_x += event->mouse_dx;
- saw_compose.offset_y += event->mouse_dy;
- }
-
- if (saw_current_track != -1) {
- // Value control
- //
-
- 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;
-
- // 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;
+ saw_shift_on = (event->modifiers & SAPP_MODIFIER_SHIFT) != 0;
+ saw_ctrl_on = (event->modifiers & SAPP_MODIFIER_CTRL) != 0;
- 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;
+ saw_mouse_dx += (i64) floor(event->mouse_dx + .5);
+ saw_mouse_dy += (i64) floor(event->mouse_dy + .5);
- 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:;
- }
- }
+ saw_mouse_x = (i64) floor(event->mouse_x + .5);
+ saw_mouse_y = (i64) floor(event->mouse_y + .5);
break;
case SAPP_EVENTTYPE_MOUSE_DOWN:
+ saw_shift_on = (event->modifiers & SAPP_MODIFIER_SHIFT) != 0;
+ saw_ctrl_on = (event->modifiers & SAPP_MODIFIER_CTRL) != 0;
+
switch (event->mouse_button) {
case SAPP_MOUSEBUTTON_LEFT:
saw_lbutton_down = 1;
@@ -2090,59 +2239,81 @@ static void saw_event(sapp_event const *event) {
break;
default:;
}
+
break;
case SAPP_EVENTTYPE_MOUSE_UP:
+ saw_shift_on = (event->modifiers & SAPP_MODIFIER_SHIFT) != 0;
+ saw_ctrl_on = (event->modifiers & SAPP_MODIFIER_CTRL) != 0;
+
switch (event->mouse_button) {
case SAPP_MOUSEBUTTON_LEFT: saw_lbutton_down = 0; break;
case SAPP_MOUSEBUTTON_RIGHT: saw_rbutton_down = 0; break;
case SAPP_MOUSEBUTTON_MIDDLE: saw_mbutton_down = 0; break;
default:;
}
+
break;
case SAPP_EVENTTYPE_MOUSE_LEAVE:
+ saw_shift_on = (event->modifiers & SAPP_MODIFIER_SHIFT) != 0;
+ saw_ctrl_on = (event->modifiers & SAPP_MODIFIER_CTRL) != 0;
+
saw_lbutton_down = 0;
saw_rbutton_down = 0;
saw_mbutton_down = 0;
+
break;
case SAPP_EVENTTYPE_KEY_DOWN:
- if (!event->key_repeat) {
- switch (event->key_code) {
- case SAPP_KEYCODE_SPACE:
- // Playback control
- saw_playback_on = !saw_playback_on;
- break;
-
- case SAPP_KEYCODE_ENTER:
- // Reset playback time
- saw_playback_frame = 0;
- break;
+ saw_shift_on = (event->modifiers & SAPP_MODIFIER_SHIFT) != 0;
+ saw_ctrl_on = (event->modifiers & SAPP_MODIFIER_CTRL) != 0;
- case SAPP_KEYCODE_ESCAPE:
- // Reset panning
- //
+ if (!event->key_repeat && event->key_code >= 0 &&
+ event->key_code <
+ sizeof saw_key_pressed / sizeof *saw_key_pressed)
+ saw_key_pressed[event->key_code] = 1;
- if (saw_current_roll != -1) {
- saw_rolls[saw_current_roll].offset_x = 0;
- saw_rolls[saw_current_roll].offset_y =
- ROLL_DEFAULT_OFFSET_Y;
- }
+ break;
- saw_compose.offset_x = 0;
- saw_compose.offset_y = 0;
+ // Touch events.
+ // We treat touch as left mouse button and cursor.
+ //
- break;
+ case SAPP_EVENTTYPE_TOUCHES_BEGAN:
+ if (event->num_touches >= 1) {
+ saw_mouse_x = (i64) floor(event->touches[0].pos_x + .5);
+ saw_mouse_y = (i64) floor(event->touches[0].pos_y + .5);
+ saw_lbutton_down = 1;
+ saw_lbutton_click = 1;
+ }
+ break;
- case SAPP_KEYCODE_D:
- // Duplicate selected track
- saw_compose.duplicate_input = 1;
- break;
+ case SAPP_EVENTTYPE_TOUCHES_MOVED:
+ if (event->num_touches >= 1) {
+ i64 x = (i64) floor(event->touches[0].pos_x + .5);
+ i64 y = (i64) floor(event->touches[0].pos_y + .5);
+ saw_mouse_dx += x - saw_mouse_x;
+ saw_mouse_dy += y - saw_mouse_y;
+ saw_mouse_x = x;
+ saw_mouse_y = y;
+ }
+ break;
- default:;
- }
+ case SAPP_EVENTTYPE_TOUCHES_ENDED:
+ if (event->num_touches >= 1) {
+ i64 x = (i64) floor(event->touches[0].pos_x + .5);
+ i64 y = (i64) floor(event->touches[0].pos_y + .5);
+ saw_mouse_dx += x - saw_mouse_x;
+ saw_mouse_dy += y - saw_mouse_y;
+ saw_mouse_x = x;
+ saw_mouse_y = y;
}
+ saw_lbutton_down = 0;
+ break;
+
+ case SAPP_EVENTTYPE_TOUCHES_CANCELLED:
+ saw_lbutton_down = 0;
break;
default:;
@@ -2165,11 +2336,24 @@ static void log_(char const *tag, u32 log_level, u32 log_item_id,
sapp_desc sokol_main(i32 argc, char **argv) {
b8 print_version = 0;
+ b8 print_help = 0;
for (i32 i = 0; i < argc; i++)
if (strcmp(argv[i], "--version") == 0)
print_version = 1;
- else if (i > 0 && saw_project_file.size == 0)
+ else if (strcmp(argv[i], "--help") == 0)
+ print_help = 1;
+ else if (argv[i][0] == '-' && argv[i][1] != '-' &&
+ argv[i][1] != '\0') {
+ for (i32 k = 1; argv[i][k] != '\0'; k++)
+ if (argv[i][k] == 'V')
+ print_version = 1;
+ else if (argv[i][k] == 'H')
+ print_help = 1;
+ else
+ printf("Unknown command line argument: \"-%c\"\n",
+ argv[i][k]);
+ } else if (i > 0 && saw_project_file.size == 0)
saw_project_file = kit_str(strlen(argv[i]), argv[i]);
else if (i > 0)
printf("Unknown command line argument: \"%s\"\n", argv[i]);
@@ -2185,9 +2369,12 @@ sapp_desc sokol_main(i32 argc, char **argv) {
" - Music sequencer standalone application.\n",
VERSION_MAJOR, VERSION_MINOR, VERSION_BABY);
+ if (print_help)
+ printf("Usage:\n%s [PROJECT_FILE]\n", argv[0]);
+
fflush(stdout);
- if (print_version)
+ if (print_version || print_help)
exit(0);
return (sapp_desc) {