From 95173111087639ad8555723041e80994cfef5e08 Mon Sep 17 00:00:00 2001 From: Vicente Higino Date: Mon, 22 Jun 2026 00:28:01 -0300 Subject: [PATCH] feat(cli): Implement CLI rendering support and load files directly from args --- src/musializer.c | 70 +++++++++++++++++++++++++++++++++++++------ src/plug.c | 77 +++++++++++++++++++++++++++++++++++++++--------- src/plug.h | 8 +++-- 3 files changed, 130 insertions(+), 25 deletions(-) diff --git a/src/musializer.c b/src/musializer.c index 7987af5..52de426 100644 --- a/src/musializer.c +++ b/src/musializer.c @@ -10,8 +10,9 @@ #endif // _WIN32 #include "./hotreload.h" +#include "./thirdparty/nob.h" -int main(void) +int main(int argc, char **argv) { #ifndef _WIN32 // NOTE: This is needed because if the pipe between Musializer and FFmpeg breaks @@ -24,7 +25,53 @@ int main(void) #endif // _WIN32 if (!reload_libplug()) return 1; - + nob_shift(argv, argc); + bool isCLI = argc > 0; + char *input_path = NULL; + char *render_path = NULL; + bool cli_rendering = false; + Nob_File_Paths input_paths = {0}; + if (isCLI) + { + const char *command_name = nob_shift(argv, argc); + if (strcmp(command_name, "--render") == 0 || strcmp(command_name, "-r") == 0) + { + cli_rendering = true; + input_path = argc > 0 ? nob_shift(argv, argc) : NULL; + if (input_path == NULL) + { + nob_log(NOB_ERROR, "Error: No music file provided."); + return 1; + } + render_path = argc > 0 ? nob_shift(argv, argc) : NULL; + if (render_path == NULL) + { + char buffer[512]; + snprintf(buffer, sizeof(buffer), "%s", input_path); + char *dot = strrchr(buffer, '.'); + if (dot != NULL) + { + strcpy(dot, ".mp4"); + } + else + { + strcat(buffer, ".mp4"); + } + render_path = strdup(buffer); + } + nob_log(NOB_INFO, "Music path: %s", input_path); + nob_log(NOB_INFO, "Render path: %s", render_path); + } + else + { + nob_da_append(&input_paths, command_name); + while (argc > 0) + { + input_path = nob_shift(argv, argc); + nob_da_append(&input_paths, input_path); + } + } + } SetConfigFlags(FLAG_WINDOW_RESIZABLE | FLAG_WINDOW_ALWAYS_RUN); size_t factor = 80; InitWindow(factor*16, factor*9, "Musializer"); @@ -39,14 +86,19 @@ int main(void) SetExitKey(KEY_NULL); InitAudioDevice(); - plug_init(); - while (!WindowShouldClose()) { - if (IsKeyPressed(KEY_H)) { - void *state = plug_pre_reload(); - if (!reload_libplug()) return 1; - plug_post_reload(state); + plug_init(&input_paths); + if (cli_rendering) { + plug_start_cli_rendering_track(input_path, render_path); + } + else { + while (!WindowShouldClose()) { + if (IsKeyPressed(KEY_H)) { + void *state = plug_pre_reload(); + if (!reload_libplug()) return 1; + plug_post_reload(state); + } + plug_update(); } - plug_update(); } CloseAudioDevice(); diff --git a/src/plug.c b/src/plug.c index 84d0ef2..71499a9 100644 --- a/src/plug.c +++ b/src/plug.c @@ -1429,6 +1429,25 @@ static bool toolbar(Track *track, Rectangle boundary) return interacted; } +static void add_track(const char *file_path) +{ + Music music = LoadMusicStream(file_path); + if (IsMusicValid(music)) + { + AttachAudioStreamProcessor(music.stream, callback); + char *file_path_copy = strdup(file_path); + assert(file_path_copy != NULL); + nob_da_append(&p->tracks, (CLITERAL(Track){ + .file_path = file_path_copy, + .music = music, + })); + } + else + { + popup_tray_push(&p->pt); + } +} + static void preview_screen(void) { int w = GetScreenWidth(); @@ -1600,19 +1619,7 @@ static void preview_screen(void) char const *filter_params[] = {"*.wav", "*.ogg", "*.mp3", "*.qoa", "*.xm", "*.mod", "*.flac"}; char *input_path = tinyfd_openFileDialog("Path to music file", "./", NOB_ARRAY_LEN(filter_params), filter_params, "music file", allow_multiple_selects); if (input_path) { - Music music = LoadMusicStream(input_path); - if (IsMusicValid(music)) { - AttachAudioStreamProcessor(music.stream, callback); - char *file_path = strdup(input_path); - assert(file_path != NULL); - nob_da_append(&p->tracks, (CLITERAL(Track) { - .file_path = file_path, - .music = music, - })); - } else { - popup_tray_push(&p->pt); - } - + add_track(input_path); if (current_track() == NULL && p->tracks.count > 0) { p->current_track = 0; PlayMusicStream(p->tracks.items[0].music); @@ -1862,7 +1869,7 @@ static void unload_assets() } } -MUSIALIZER_PLUG void plug_init(void) +MUSIALIZER_PLUG void plug_init(Nob_File_Paths *paths) { p = malloc(sizeof(*p)); assert(p != NULL && "Buy more RAM lol"); @@ -1871,6 +1878,15 @@ MUSIALIZER_PLUG void plug_init(void) load_assets(); p->screen = LoadRenderTexture(RENDER_WIDTH, RENDER_HEIGHT); p->current_track = -1; + da_foreach(const char *, i, paths) + { + add_track(*i); + if (current_track() == NULL && p->tracks.count > 0) + { + p->current_track = 0; + PlayMusicStream(p->tracks.items[0].music); + } + } // TODO: restore master volume between sessions SetMasterVolume(0.5); @@ -1923,6 +1939,39 @@ MUSIALIZER_PLUG void plug_update(void) EndDrawing(); } +MUSIALIZER_PLUG void plug_start_cli_rendering_track(const char *input_path, const char *output_path) +{ + if (input_path == NULL || output_path == NULL) + return; + Music music = LoadMusicStream(input_path); + if (!IsMusicValid(music)) + return; + AttachAudioStreamProcessor(music.stream, callback); + char *file_path = strdup(input_path); + assert(file_path != NULL); + nob_da_append(&p->tracks, (CLITERAL(Track){ + .file_path = file_path, + .music = music, + })); + p->current_track = 0; + fft_clean(); + // TODO: LoadWave is pretty slow on big files + p->wave = LoadWave(input_path); + p->wave_cursor = 0; + p->wave_samples = LoadWaveSamples(p->wave); + // TODO: set the rendering output path based on the input path + // Basically output into the same folder + p->ffmpeg = ffmpeg_start_rendering(output_path, p->screen.texture.width, p->screen.texture.height, RENDER_FPS, input_path); + SetTargetFPS(0); + p->rendering = true; + p->cancel_rendering = false; + SetTraceLogLevel(LOG_WARNING); + while (p->rendering) + { + plug_update(); + } +} + // TODO: About Page that includes current commit, version and the platforms // We may also include licenses and contributors there. // TODO: Actual Fullscreen Mode diff --git a/src/plug.h b/src/plug.h index 89bcfe7..f05b472 100644 --- a/src/plug.h +++ b/src/plug.h @@ -1,13 +1,17 @@ #ifndef PLUG_H_ #define PLUG_H_ +#define NOB_STRIP_PREFIX +#include "thirdparty/nob.h" + #define LIST_OF_PLUGS \ - PLUG(plug_init, void, void) \ + PLUG(plug_init, void, Nob_File_Paths*) \ PLUG(plug_pre_reload, void*, void) \ PLUG(plug_post_reload, void, void*) \ PLUG(plug_load_resource, void*, const char*, size_t*) \ PLUG(plug_free_resource, void, void*) \ - PLUG(plug_update, void, void) + PLUG(plug_update, void, void) \ + PLUG(plug_start_cli_rendering_track, void, const char *, const char *) #define PLUG(name, ret, ...) typedef ret (name##_t)(__VA_ARGS__); LIST_OF_PLUGS