diff options
-rwxr-xr-x[-rw-r--r--] | saw.c | 173 |
1 files changed, 111 insertions, 62 deletions
@@ -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 |