From 9847614871e861c216425b95a8300dba37b0f6e6 Mon Sep 17 00:00:00 2001 From: grm Date: Sun, 2 Mar 2025 13:53:54 +0200 Subject: Also improve midi and add tt for templating --- b.c | 93 +++++++++++-------- src/b.h | 35 ++++--- src/gui.h | 16 ++++ src/midi.c | 20 +--- src/sound.c | 3 +- src/synth_engine.h | 7 +- src/synth_engine_v2.c | 2 +- src/synth_gui.c | 40 ++++---- src/tt.c | 124 +++++++++++++++++++++++++ src/web.c | 248 +++++++++++++++++++++++++++----------------------- 10 files changed, 389 insertions(+), 199 deletions(-) create mode 100644 src/gui.h create mode 100644 src/tt.c diff --git a/b.c b/b.c index 3056ebf..6ac5db6 100644 --- a/b.c +++ b/b.c @@ -3,6 +3,7 @@ #include #define BUILD_DIR "build/" +#define TEMPLATE_DIR BUILD_DIR"templates/" int debug_level = 0; @@ -25,59 +26,40 @@ debug_or_release(B_Cmd* cmd) void inlcude_dirs(B_Cmd* cmd) { - b_cmd_append(cmd, "-I./src/"); + b_cmd_append(cmd, "-I./src/", "-I./"TEMPLATE_DIR); } void -cflags(B_Cmd* cmd) +cflags_common(B_Cmd* cmd) { b_cmd_append(cmd, "-Wall", "-Wextra"); debug_or_release(cmd); - b_cmd_append(cmd, "-march=native"); - b_cmd_append(cmd, "-fno-math-errno", "-funroll-loops"); - b_cmd_append(cmd, "-flto", "-pthread"); - b_cmd_append(cmd, "-lportaudio", "-lrt", "-lm", "-lasound", "-lraylib", "-lportmidi", "-ljack", "-lfftw3f", "-lsndfile", "-lconfig", "-lmicrohttpd", "-lpthread", "-lwebsockets"); - - inlcude_dirs(cmd); + b_cmd_append(cmd, "-march=native", "-lm"); + b_cmd_append(cmd, "-fno-math-errno", "-funroll-loops", "-flto"); } -void cxxflags(B_Cmd *cmd) +void +synth_libs(B_Cmd *cmd) { - b_cmd_append(cmd, "-Wall", "-Wextra"); - b_cmd_append(cmd, "-Wno-string-plus-int", "-Wno-nullability-completeness", "-Wno-unused-function", "-Wno-missing-field-initializers", "-Wno-unused-parameter", "-Wno-unused-variable"); - - debug_or_release(cmd); - - b_cmd_append(cmd, "-march=native"); - b_cmd_append(cmd, "-fno-math-errno", "-funroll-loops"); - b_cmd_append(cmd, "-flto", "-pthread"); + b_cmd_append(cmd, "-lportaudio", "-lrt", "-lasound", "-lraylib", "-lportmidi", + "-lfftw3f", "-lsndfile", "-lconfig", "-lpthread", + "-lwebsockets"); inlcude_dirs(cmd); - //b_cmd_append(cmd, "-O3"); -} - -void cxx(B_Cmd *cmd) -{ - b_cmd_append(cmd, "clang"); - cxxflags(cmd); } void cc(B_Cmd *cmd) { b_cmd_append(cmd, "clang"); - cflags(cmd); + cflags_common(cmd); } -void libs(B_Cmd *cmd) -{ - b_cmd_append(cmd, "-lSDL2", "-lm", "-lvulkan", "-lshaderc_shared", "-lstdc++"); -} +bool force = false; bool -build_c(bool force, - B_Cmd* cmd, +build_c(B_Cmd* cmd, const char** input_paths, size_t input_paths_len, const char** dep_paths, @@ -85,11 +67,13 @@ build_c(bool force, const char* output_path) { int rebuild_is_needed = - b_needs_rebuild(output_path, input_paths, input_paths_len); + b_needs_rebuild(B_COMPILE, output_path, input_paths, input_paths_len); int dep_rebuild = 0; if (rebuild_is_needed == 0) - dep_rebuild = b_needs_rebuild(output_path, dep_paths, dep_paths_len); + dep_rebuild = + b_needs_rebuild(B_COMPILE, output_path, dep_paths, dep_paths_len); + if (rebuild_is_needed < 0 || dep_rebuild < 0) return false; @@ -98,7 +82,8 @@ build_c(bool force, cc(cmd); b_cmd_append(cmd, "-o", output_path); b_da_append_many(cmd, input_paths, input_paths_len); - libs(cmd); + if (0 == strcmp(output_path, BUILD_DIR"synth")) + synth_libs(cmd); return b_cmd_run_sync(*cmd); } @@ -106,6 +91,30 @@ build_c(bool force, return true; } +bool build_templates(B_Cmd *cmd, const char **templates, size_t len) { + char dest[1024] = ""; + for (size_t i = 0; i < len; i++) { + cmd->count = 0; + char *base = strdup(templates[i]); + strcpy(dest, TEMPLATE_DIR); + strcat(dest, basename(base)); + strcat(dest, ".h"); + if (b_needs_rebuild1(B_TEMPLATE, dest, templates[i]) == 0 && + force == false) { + b_log(B_INFO, "%s is up-to-date", dest); + continue; + } + char tmp[1024] = ""; + strcat(tmp, "build/tt "); + strcat(tmp, templates[i]); + strcat(tmp, " > "); + strcat(tmp, dest); + b_cmd_append(cmd, "bash", "-c", tmp); + b_cmd_run_sync(*cmd); + } + return true; +} + int main(int argc, char *argv[]) { @@ -113,7 +122,6 @@ main(int argc, char *argv[]) const char *program_name = b_shift_args(&argc, &argv); (void)program_name; - bool force = false; while (argc > 0) { const char *flag = b_shift_args(&argc, &argv); @@ -148,6 +156,7 @@ main(int argc, char *argv[]) "src/types.h", "src/web.h", "src/gui.h", + BUILD_DIR"templates/index.html.h", }; const char* synth_paths[] = { @@ -174,11 +183,23 @@ main(int argc, char *argv[]) "src/web.c", }; + const char *templates[] = { + "tmpl/index.html" + }; + B_Cmd cmd = {0}; b_mkdir_if_not_exists(BUILD_DIR); + b_mkdir_if_not_exists(TEMPLATE_DIR); + + if (!build_c(&cmd, (const char *[]){"src/tt.c"}, 1, NULL, 0, + BUILD_DIR "tt")) + return 1; + + if (!build_templates(&cmd, templates, B_ARRAY_LEN(templates))) + return 1; - if (!build_c(force, &cmd, synth_paths, B_ARRAY_LEN(synth_paths), synth_deps, + if (!build_c(&cmd, synth_paths, B_ARRAY_LEN(synth_paths), synth_deps, B_ARRAY_LEN(synth_deps), BUILD_DIR "synth")) return 1; diff --git a/src/b.h b/src/b.h index 0b3bf2e..a6dba68 100644 --- a/src/b.h +++ b/src/b.h @@ -50,7 +50,8 @@ typedef enum { B_INFO, B_CMD, - B_BUILDING, + B_COMPILE, + B_TEMPLATE, B_CHANGE, B_WARNING, B_ERROR, @@ -195,8 +196,8 @@ void b_temp_rewind(size_t checkpoint); int is_path1_modified_after_path2(const char *path1, const char *path2); bool b_rename(const char *old_path, const char *new_path); -int b_needs_rebuild(const char *output_path, const char **input_paths, size_t input_paths_count); -int b_needs_rebuild1(const char *output_path, const char *input_path); +int b_needs_rebuild(B_Log_Level log, const char *output_path, const char **input_paths, size_t input_paths_count); +int b_needs_rebuild1(B_Log_Level log, const char *output_path, const char *input_path); int b_file_exists(const char *file_path); // TODO: add MinGW support for Go Rebuild Urself™ Technology @@ -246,7 +247,7 @@ int b_file_exists(const char *file_path); assert(argc >= 1); \ const char *binary_path = argv[0]; \ \ - int rebuild_is_needed = b_needs_rebuild(binary_path, &source_path, 1); \ + int rebuild_is_needed = b_needs_rebuild(B_COMPILE, binary_path, &source_path, 1); \ if (rebuild_is_needed < 0) exit(1); \ if (rebuild_is_needed) { \ B_String_Builder sb = {0}; \ @@ -506,22 +507,25 @@ void b_log(B_Log_Level level, const char *fmt, ...) { switch (level) { case B_INFO: - fprintf(stderr, "[INFO] "); + fprintf(stderr, " [INFO] "); break; case B_CMD: - fprintf(stderr, "[CMD] "); + fprintf(stderr, " [CMD] "); break; - case B_BUILDING: - fprintf(stderr, "[BUILDING] "); + case B_COMPILE: + fprintf(stderr, " [COMPILE] "); + break; + case B_TEMPLATE: + fprintf(stderr, "[TEMPLATE] "); break; case B_CHANGE: - fprintf(stderr, "[CHANGE] "); + fprintf(stderr, " [CHANGE] "); break; case B_WARNING: - fprintf(stderr, "[WARNING] "); + fprintf(stderr, " [WARNING] "); break; case B_ERROR: - fprintf(stderr, "[ERROR] "); + fprintf(stderr, " [ERROR] "); break; default: B_ASSERT(0 && "unreachable"); @@ -734,14 +738,14 @@ const char *b_temp_sv_to_cstr(B_String_View sv) return result; } -int b_needs_rebuild(const char *output_path, const char **input_paths, size_t input_paths_count) +int b_needs_rebuild(B_Log_Level log, const char *output_path, const char **input_paths, size_t input_paths_count) { struct stat statbuf = {0}; if (stat(output_path, &statbuf) < 0) { // NOTE: if output does not exist it 100% must be rebuilt if (errno == ENOENT) { - b_log(B_BUILDING, "%s", output_path); + b_log(log, "%s", output_path); return 1; } b_log(B_ERROR, "could not stat %s: %s", output_path, strerror(errno)); @@ -760,6 +764,7 @@ int b_needs_rebuild(const char *output_path, const char **input_paths, size_t in // NOTE: if even a single input_path is fresher than output_path that's 100% rebuild if (input_path_time > output_path_time) { b_log(B_CHANGE, "%s", input_path); + b_log(log, "%s", output_path); return 1; } } @@ -767,9 +772,9 @@ int b_needs_rebuild(const char *output_path, const char **input_paths, size_t in return 0; } -int b_needs_rebuild1(const char *output_path, const char *input_path) +int b_needs_rebuild1(B_Log_Level log, const char *output_path, const char *input_path) { - return b_needs_rebuild(output_path, &input_path, 1); + return b_needs_rebuild(log, output_path, &input_path, 1); } bool b_rename(const char *old_path, const char *new_path) diff --git a/src/gui.h b/src/gui.h new file mode 100644 index 0000000..f151e35 --- /dev/null +++ b/src/gui.h @@ -0,0 +1,16 @@ +#ifndef GUI_H +#define GUI_H + +typedef enum screen_e { + SCREEN_MAIN = 0, + SCREEN_AUDIOMIDISETUP, + SCREEN_ERR +} screen_e; + +typedef struct synth_gui { + screen_e screen; + int audiomidi_initialized; +} synth_gui; + + +#endif /* GUI_H */ diff --git a/src/midi.c b/src/midi.c index 429e9df..a015de4 100644 --- a/src/midi.c +++ b/src/midi.c @@ -161,22 +161,14 @@ init_midi(midi_t *m, synth_t *synth) printf("midi devs: %d\n", Pm_CountDevices()); const PmDeviceInfo *info; - int i, c=0; + int i=0; for (i = 0; i < Pm_CountDevices(); i++) { info = Pm_GetDeviceInfo(i); if (!info->input) { continue; } printf("%d: %s [input: %d output: %d opened: %d is_virt:%d] (interf: %s) -- %d\n", i, info->name, info->input, info->output, info->opened, info->is_virtual, info->interf, Pm_GetDefaultInputDeviceID()); - if (synth->midi_device_id == c) { - break; - } - c++; - //if (!strcmp("MPK225 MIDI", info->name) && !info->input) break; - //if (!strcmp("MPK225 Port A", info->name) && info->input == 1) break; - //if (!strcmp("CH345 MIDI 1", info->name) && info->input == 1) break; - //if (!strcmp("Midi Through Port-0", info->name) && info->input == 1) break; - //if (!strcmp("DigitalKBD MIDI 1", info->name) && info->input == 1) break; + if (!strcmp(synth->midi_device.name, info->name) && !info->input) break; } Pt_Start(1, midiCallback, m); @@ -190,6 +182,7 @@ init_midi(midi_t *m, synth_t *synth) enable = 1; } +// unused int get_midi_device_id(const char * name) { @@ -211,23 +204,20 @@ get_midi_device_id(const char * name) char * get_midi_devices() { - //Pm_Initialize(); int i; char *ret = (char *)malloc(sizeof(char) * 4096); - strcpy(ret, ""); + strcpy(ret, "Select Midi Device;"); const PmDeviceInfo *info; for (i = 0; i < Pm_CountDevices(); i++) { info = Pm_GetDeviceInfo(i); if (!info->input) { continue; } - printf("!!!!!!!!!!!!!!!!!!!!!!!!! ==> %s ========\n", info->name); strcat(ret, info->name); strcat(ret, ";"); } ret[strlen(ret) - 1] = '\0'; - //Pm_Terminate(); - + return ret; } diff --git a/src/sound.c b/src/sound.c index 2b2ca12..d4b0242 100644 --- a/src/sound.c +++ b/src/sound.c @@ -101,7 +101,8 @@ init_sound(synth_t * synth, PaStreamCallback *streamCallback, const char* device deviceInfo->name); if (strcmp(device_name, "default")) { printf("Trying to use default device\n"); - init_sound(synth, streamCallback, "default"); + strcpy(synth->soundcard.name, "default"); + init_sound(synth, streamCallback, synth->soundcard.name); } return; } diff --git a/src/synth_engine.h b/src/synth_engine.h index 21e427c..f771073 100644 --- a/src/synth_engine.h +++ b/src/synth_engine.h @@ -22,6 +22,11 @@ typedef struct soundcard_t { int id; } soundcard_t; +typedef struct midi_device_t { + char name[2048]; + int id; +} midi_device_t; + typedef struct lfo_t { float freq; float amp; @@ -136,7 +141,7 @@ typedef struct { int sound_active; soundcard_t soundcard; - int midi_device_id; + midi_device_t midi_device; synth_viz viz; diff --git a/src/synth_engine_v2.c b/src/synth_engine_v2.c index d4b7509..4d9721c 100644 --- a/src/synth_engine_v2.c +++ b/src/synth_engine_v2.c @@ -569,8 +569,8 @@ init_synth(void) strcpy(synth->soundcard.name, "default"); init_sound(synth, sound_gen, synth->soundcard.name); + strcpy(synth->midi_device.name, "Midi Through Port-0"); synth->midi = (midi_t *)malloc(sizeof(midi_t)); - synth->midi_device_id = get_midi_device_id("Midi Through Port-0"); init_midi(synth->midi, synth); synth->gui.screen = SCREEN_MAIN; diff --git a/src/synth_gui.c b/src/synth_gui.c index 43cfda1..d1dc78e 100644 --- a/src/synth_gui.c +++ b/src/synth_gui.c @@ -708,17 +708,21 @@ void get_nth_entry(const char *str, int n, char *result) { } char *soundcards = NULL; +char *midi_devices = NULL; void draw_audiomidisetup(synth_t *synth, const char *midi_devices) { static int edit_midi = 0; static int edit_sound = 0; - static int pick = 0; + static int midi_pick = 0; + static int soundcard_pick = 0; if (synth->gui.audiomidi_initialized == 0) { soundcards = get_soundcards(); - pick = 0; + midi_devices = get_midi_devices(); + soundcard_pick = 0; + midi_pick = 0; synth->gui.audiomidi_initialized = 1; printf("================ AUDIOMIDISETUP GUI INITIALIZED!\n"); } @@ -734,38 +738,38 @@ draw_audiomidisetup(synth_t *synth, const char *midi_devices) if (GuiButton((Rectangle){WIDTH - 100 - 50, 50 + 24 + 6 + 24 + 6 + 24 + 6 + 24 + 6, 100, 24}, "apply")) { - if (pick != 0) { - get_nth_entry(soundcards, pick, synth->soundcard.name); - printf("CHANGING TO %s\n", synth->soundcard.name); + if (soundcard_pick != 0) { + get_nth_entry(soundcards, soundcard_pick, synth->soundcard.name); + printf("[AUDIO] CHANGING TO %s\n", synth->soundcard.name); change_soundcard(synth); } + if (midi_pick != 0) { + get_nth_entry(midi_devices, midi_pick, synth->midi_device.name); + printf("[MIDI] CHANGING TO %s\n", synth->midi_device.name); + change_midi_device(synth); + } synth->gui.screen = SCREEN_MAIN; } - // audio dev + // midi dev if (GuiDropdownBox((Rectangle){WIDTH - 300 - 50, 12 + 24 + 6, 300, 24}, - soundcards, &pick, edit_sound)) { - edit_sound = !edit_sound; + midi_devices, &midi_pick, edit_midi)) { + edit_midi = !edit_midi; } - /* if (old_soundcard_id != synth->soundcard_id) { */ - /* old_soundcard_id = synth->soundcard_id; */ - /* get_nth_entry(soundcards, pick, synth->soundcard_name); */ - /* } */ - // midi dev + // audio dev if (GuiDropdownBox((Rectangle){WIDTH - 300 - 50, - 12, 200, + 12, 300, 24}, - midi_devices, &synth->midi_device_id, edit_midi)) { - edit_midi = !edit_midi; + soundcards, &soundcard_pick, edit_sound)) { + edit_sound = !edit_sound; } /* if (old_midi_device_id != synth->midi_device_id) { */ /* old_midi_device_id = synth->midi_device_id; */ - /* change_midi_device(synth); */ /* } */ @@ -778,6 +782,7 @@ draw_main(synth_t *synth) { if (synth->gui.audiomidi_initialized != 0) { if (soundcards) free(soundcards); + if (midi_devices) free(midi_devices); synth->gui.audiomidi_initialized = 0; } BeginDrawing(); @@ -891,7 +896,6 @@ rayrun(synth_t *synth){ draw_audiomidisetup(synth, midi_devices); //---------------------------------------------------------------------------------- - current_time = Pa_GetStreamTime(synth->stream); //printf("%f :: %ld\n", current_time - prev_time, phase); diff --git a/src/tt.c b/src/tt.c new file mode 100644 index 0000000..01c9614 --- /dev/null +++ b/src/tt.c @@ -0,0 +1,124 @@ +#include +#include +#include +#include +#include +#include + +#define DEFAULT_DELIMITER "$" + +void compile_c_code(char * s) { + printf("%.*s\n", (int) strlen(s), s); +} + +void compile_byte_array(char * s) { + printf("write(OUT, \""); + uint64_t slen = strlen(s); + for (uint64_t i = 0; i < slen; ++i) { + printf("\\x%02x", s[i]); + } + printf("\", %lu);\n", strlen(s)); +} + +char *read_file_to_string(const char *filename) { + FILE *file = fopen(filename, "rb"); + if (!file) { + perror("Error opening file"); + return NULL; + } + + fseek(file, 0, SEEK_END); + long file_size = ftell(file); + rewind(file); + + char *buffer = (char *)malloc(file_size + 1); + if (!buffer) { + perror("Memory allocation failed"); + fclose(file); + return NULL; + } + + fread(buffer, 1, file_size, file); + buffer[file_size] = '\0'; + + fclose(file); + return buffer; +} + +#define CHARSET_SIZE 128 // Covering standard ASCII characters + +int print_good_delimiters(const char * s) { + int seen[CHARSET_SIZE] = {0}; // Array to track seen characters + + size_t len = strlen(s); + for (size_t i = 0; i < len; i++) { + if (s[i] >= 0 && (int)s[i] < CHARSET_SIZE) { + seen[(int)s[i]] = 1; + } + } + + // Define the characters to check: A-Za-z0-9 and common symbols + char *valid_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()-_=+[{]}\\|;:'\",<.>/?`~"; + + int flag = 0; + printf("Good options for delimiters:\n"); + for (int i = 0; valid_chars[i] != '\0'; i++) { + if (!seen[(unsigned char)valid_chars[i]]) { + putchar(valid_chars[i]); + flag++; + } + } + if (!flag) { + printf(" :( none found, compromises shall be made"); + } + putchar('\n'); + + return 0; +} + + +int main(int argc, char *argv[]) +{ + if (argc < 2) { + fprintf(stderr, "Usage: %s