summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-x[-rw-r--r--]saw.c173
1 files changed, 111 insertions, 62 deletions
diff --git a/saw.c b/saw.c
index 0abda6c..9ab93ec 100644..100755
--- a/saw.c
+++ b/saw.c
@@ -3,16 +3,31 @@
#/
#/ saw.c
#/
-#/ Music sequencer and audio editor.
-#/
-#/ (C) 2024 Mitya Selivanov <guattari.tech>, MIT License
+#/ Music sequencer and audio editor.
+#/ Experimental, work in progress.
#/
#/ ----------------------------------------------------------------
#/
+#/ Qualities
+#/
+#/ - Single source file
+#/ - All dependencies are included with the code
+#/ - No configuration required
+#/ - Cross-platform thanks to sokol and miniaudio
+#/
+#/ NOTE
+#/ You can build the project easily using this two commands:
+#/ > gcc -o buildme -DBUILDME saw.c
+#/ > ./buildme
+#/ Or, on Windows, with MSVC compiler:
+#/ > cl.exe -Febuildme.exe -DBUILDME saw.c
+#/ > buildme.exe
+#/
#/ To-Do list
#/
#/ - Code
#/ - Self-compiling single-source code
+#/ - Fetching dependencies
#/ - Logging routines
#/ - Tools
#/ - Transactional undo and redo
@@ -45,6 +60,7 @@
#/ - Limiter
#/ - Sample rendering
#/ - UI
+#/ - Show an indicator when a track is playing without an attached synth
#/ - Panning and scaling
#/ - Grid size changing
#/ - Selection and copy-paste
@@ -63,6 +79,7 @@
#/ - Custom font and localization
#/ - Data
#/ - Floating point number format without data loss
+#/ - Clipboard integration
#/ - WAV export
#/ - Project load and store
#/ - Automatic serialization
@@ -79,6 +96,7 @@
#/
#/ - Sampler clicking
#/ - Windows and macOS compilation issues
+#/ - Different build types don't work without manual full rebuild because they store object files in the same folder
#/
#/ Done features
#/
@@ -107,29 +125,31 @@
#/ - Sample loading
#/ - Drag & drop in web
#/
-#/ ================================================================
+#/ ----------------------------------------------------------------
#/
-#/ Self-compilation shell script
+#/ (C) 2024 Mitya Selivanov <guattari.tech>, MIT License
#/
#/ ================================================================
+#/
+#/ Self-compilation shell script
+#/
SRC=${0##*./}
-gcc -DBUILDME=1 -o buildme $SRC && ./buildme $@ && rm buildme
-exit $? */
+gcc -o buildme -DBUILDME=1 $SRC && ./buildme $@ && rm buildme
+exit $? # */
#endif
-
// ================================================================
//
// GLOBAL COMPILATION OPTIONS
//
// ================================================================
-
-//#define BUILDME 1
-//#define DEPENDENCIES 1
-//#define EXE 1
-//#define TESTS 1
-
+// Define one of the options for the linter
+#if !BUILDME && \
+ !DEPENDENCIES && \
+ !EXE && \
+ !TESTS
+#define EXE 1
+#endif
#define _GNU_SOURCE
-
// ================================================================
//
// BUILD SYSTEM
@@ -138,10 +158,11 @@ exit $? */
#if BUILDME
-#include "kit/allocator.c"
-#include "kit/array_ref.c"
-#include "kit/dynamic_array.c"
-#include "kit/file.c"
+typedef int i32;
+typedef long long i64;
+typedef unsigned u32;
+typedef char c8;
+typedef signed char b8;
#include <stdio.h>
#include <stdlib.h>
@@ -149,6 +170,14 @@ exit $? */
#include <stdarg.h>
#include <assert.h>
+#if defined(_WIN32) && !defined(__CYGWIN__)
+# define WIN32_LEAN_AND_MEAN
+# define NOMINMAX
+# include <windows.h>
+#else
+# include <sys/stat.h>
+#endif
+
#define PROJECT "saw"
#define SOURCE "saw.c"
@@ -159,11 +188,13 @@ exit $? */
#define REQUIRE_GRAPHICS 1
#define REQUIRE_OPENGL 1
#define REQUIRE_VULKAN 0
-#if defined(_WIN32) && !defined(__CYGWIN__)
-#define STATIC_RUNTIME 1
+#if defined(__linux__) || defined(__EMSCRIPTEN__)
+// Static C runtime is too unstable on Linux. Sad
+#define STATIC_RUNTIME 0
#else
-#define STATIC_RUNTIME 0
+#define STATIC_RUNTIME 1
#endif
+// TODO Add command line option for the C runtime.
enum {
LINUX,
@@ -291,6 +322,26 @@ b8 check_compiler(c8 *name) {
return 1;
}
+b8 file_exists(c8 *name) {
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ if (PathFileExistsA(buf))
+ return 1;
+#else
+ struct stat info;
+ if (stat(name, &info) == 0 && (S_ISREG(info.st_mode) || S_ISDIR(info.st_mode)))
+ return 1;
+#endif
+ return 0;
+}
+
+void create_folder_recursive(c8 *path) {
+ #if defined(_WIN32) && !defined(__CYGWIN__)
+ system(fmt("if not exist %s mkdir %s", destination, destination));
+ #else
+ system(fmt("mkdir %s -p", destination));
+ #endif
+}
+
enum {
MAX_LENGTH = 200,
};
@@ -408,7 +459,7 @@ i32 main(i32 argc, c8 **argv) {
fflush(stdout);
- // Find C compiler
+ // Find the C compiler
//
if (compiler_c[0] != '\0') {
@@ -586,11 +637,7 @@ i32 main(i32 argc, c8 **argv) {
//
destination[0] == '\0' && (destination = "build");
-
- if (OS == WINDOWS)
- system(fmt("if not exist %s mkdir %s", destination, destination));
- else
- system(fmt("mkdir %s -p", destination));
+ create_folder_recursive(destination);
// Print info
//
@@ -601,8 +648,9 @@ i32 main(i32 argc, c8 **argv) {
// Code generation
//
+ // TODO Add command line option for code generation.
- if (path_type(SZ("build_fonts.inl.h")) == PATH_NONE) {
+ if (!file_exists("build_fonts.inl.h")) {
printf("Code generation\n");
fflush(stdout);
@@ -664,7 +712,9 @@ i32 main(i32 argc, c8 **argv) {
c8 *deps = fmt("%s" DLM "thirdparty%s", destination, postfix_obj);
- if (path_type(str(strlen(deps), deps)) == PATH_NONE) {
+ if (!file_exists(deps)) {
+ // TODO Add command line option for complete rebuild.
+
printf("Rebuild dependencies\n");
fflush(stdout);
@@ -848,17 +898,13 @@ i32 main(i32 argc, c8 **argv) {
#define VERSION_BABY 3
#define VERSION_DEV 1
-// Constants
+// Configuration
//
-#define EPS 0.00001
-#define REFERENCE_PITCH 440.0 // A_4
+#define EPS 0.00001
+#define REFERENCE_PITCH 440.0 // A_4
#define EQUAL_TEMPERAMENT_FACTOR 1.05946309436 // 2^(1/12)
-#define GLOBAL_VOLUME 2.0
-
-#define SPACES SZ(" \t\n\r")
-#define DELIM SZ(" \t\n\r}")
-#define NUMS SZ(" \t\n\r+-0123456789.")
+#define GLOBAL_VOLUME 2.0
enum {
CHANNEL_COUNT = 2,
@@ -884,6 +930,13 @@ enum {
ROLL_DEFAULT_RATE = 8,
ROLL_DEFAULT_UI_OFFSET_Y = 2000,
+ SAMPLER_OUTLINE_SIZE = 64,
+};
+
+// Constants
+//
+
+enum {
TUNING_EQUAL_TEMPERAMENT = 0,
TUNING_PYTHAGOREAN,
@@ -899,8 +952,6 @@ enum {
INSTRUMENT_OSCILLATOR,
INSTRUMENT_SAMPLER,
- SAMPLER_OUTLINE_SIZE = 64,
-
EDIT_MODE_HAND = 0,
EDIT_MODE_ERASE,
EDIT_MODE_PAN,
@@ -913,7 +964,7 @@ enum {
UI_MAIN = 0,
UI_DEV,
- UI_TAB_COUNT,
+ NUM_UI_TABS,
};
// Data types
@@ -982,7 +1033,7 @@ typedef DA(u8) da_u8_t;
typedef DA(f32) da_f32_t;
typedef struct {
- da_f32_t data;
+ da_f32_t data; // FIXME Remove dynamic memory management.
da_f32_t outline;
f64 begin;
f64 end;
@@ -1057,7 +1108,7 @@ typedef struct {
// ================================================================
//
-// Global state
+// Global state
//
// NOTE
// At some point we want to move all global data into a struct
@@ -1166,7 +1217,7 @@ i32 ui_tab = UI_MAIN;
// ================================================================
//
-// Sound
+// Sound
//
// NOTE
// When music and signal processing procedures become stable enough
@@ -1678,10 +1729,14 @@ void sampler_cleanup(Sampler *sampler) {
// ================================================================
//
-// Data
+// Data
//
// ================================================================
+#define SPACES SZ(" \t\n\r")
+#define DELIM SZ(" \t\n\r}")
+#define NUMS SZ(" \t\n\r+-0123456789.")
+
ib_token_t parse_sign(ib_token_t tok, i64 *sign) {
assert(sign != NULL);
if (sign == NULL)
@@ -2334,11 +2389,7 @@ void project_print_to_file(str_t file_name) {
// ================================================================
//
-// UI
-//
-// TODO
-// - UI library and tests.
-// - Grid widget.
+// UI
//
// ================================================================
@@ -3611,8 +3662,8 @@ void ui_roll(Roll *roll, f64 x0, f64 y0, f64 width,
nvgText(nvg, x + w / 3, y + h / 2, "\uf52d", NULL);
}
- c8 buf[64];
- c8 const *note_names[12] = {
+ c8 buf[64];
+ c8 *note_names[12] = {
"A", "Bb", "H", "C", "Db", "D",
"Eb", "E", "F", "Gb", "G", "Ab",
};
@@ -3947,7 +3998,7 @@ void ui_roll(Roll *roll, f64 x0, f64 y0, f64 width,
// ================================================================
//
-// Event handling
+// Event handling
//
// ================================================================
@@ -4172,7 +4223,7 @@ void frame(void) {
// Tabs
//
if (key_pressed[SAPP_KEYCODE_TAB])
- ui_tab = (ui_tab + 1) % UI_TAB_COUNT;
+ ui_tab = (ui_tab + 1) % NUM_UI_TABS;
}
// Render UI
@@ -4255,7 +4306,7 @@ void frame(void) {
// Grid widget testing
//
- static const i64 time_rate = 256;
+ static i64 const time_rate = 256;
static UI_Grid_Item items[100] = { 0 };
static UI_Grid grid = {
@@ -4344,8 +4395,7 @@ void cleanup(void) {
}
#ifdef __EMSCRIPTEN__
-void fetch_drop(
- sapp_html5_fetch_response const *response) {
+void fetch_drop(sapp_html5_fetch_response const *response) {
assert(response != NULL);
if (response == NULL || !response->succeeded) {
@@ -4360,9 +4410,8 @@ void fetch_drop(
}
#endif
-void event(sapp_event const *event) {
- // Resume the audio only after a user action. This is required
- // for the browser compatibility.
+void handle_event(sapp_event const *event) {
+ // Resume the audio only after a user action. This is required for the browser compatibility.
//
{
if (playback_suspended &&
@@ -4650,7 +4699,7 @@ sapp_desc sokol_main(i32 argc, c8 **argv) {
.init_cb = init,
.frame_cb = frame,
.cleanup_cb = cleanup,
- .event_cb = event,
+ .event_cb = handle_event,
.logger.func = logger,
};
}
@@ -4675,5 +4724,5 @@ i32 main(i32 argc, char **argv) {
// ================================================================
#else
-#error Define either of: BUILDME=1, DEPENDENCIES=1, TESTS=1, EXE=1
+#error Build options not provided. Try: gcc -DBUILDME saw.c
#endif