diff --git a/Let me provide the SEARCH/REPLACE blocks.carla.h b/Let me provide the SEARCH/REPLACE blocks.carla.h deleted file mode 100644 index c39cfcf..0000000 --- a/Let me provide the SEARCH/REPLACE blocks.carla.h +++ /dev/null @@ -1,83 +0,0 @@ -#ifndef CARLA_H -#define CARLA_H - -#include -#include -#include - -// Carla plugin types we support -typedef enum { - PLUGIN_TYPE_NONE, - PLUGIN_TYPE_LV2, - PLUGIN_TYPE_VST2, - PLUGIN_TYPE_VST3, - PLUGIN_TYPE_CLAP, - PLUGIN_TYPE_INTERNAL // Our built-in plugins (gain, etc.) -} PluginType; - -// Plugin descriptor -typedef struct { - char name[256]; - char uri[512]; - PluginType type; - int carla_plugin_id; // Carla's internal plugin ID - int num_parameters; - float *parameters; // Current parameter values - char **parameter_names; -} PluginInfo; - -// Rack for a single channel -typedef struct { - int num_plugins; - PluginInfo plugins[16]; // Max 16 plugins per channel - float volume; // Channel volume (0.0 - 2.0) - bool bypassed; -} ChannelRack; - -// Carla host state -typedef struct { - bool initialized; - ChannelRack channel_racks[8]; // One rack per channel (MAX_CHANNELS) - jack_client_t *client; - // For plugin scanning - char **available_plugins; - int num_available_plugins; -} CarlaHost; - -// Initialize Carla host -int carla_init(CarlaHost *host, jack_client_t *client); - -// Cleanup Carla host -void carla_cleanup(CarlaHost *host); - -// Add a plugin to a channel's rack -int carla_add_plugin(CarlaHost *host, int channel, const char *uri, PluginType type); - -// Remove a plugin from a channel's rack -int carla_remove_plugin(CarlaHost *host, int channel, int plugin_index); - -// Set plugin parameter -int carla_set_parameter(CarlaHost *host, int channel, int plugin_index, int param_index, float value); - -// Get plugin parameter -float carla_get_parameter(CarlaHost *host, int channel, int plugin_index, int param_index); - -// Set channel volume -void carla_set_channel_volume(CarlaHost *host, int channel, float volume); - -// Get channel volume -float carla_get_channel_volume(CarlaHost *host, int channel); - -// Process audio through the rack (called from audio thread) -void carla_process(CarlaHost *host, int channel, float *in_buffer, float *out_buffer, jack_nframes_t nframes); - -// Scan for available plugins -int carla_scan_plugins(CarlaHost *host); - -// Get available plugin names for fuzzy search -const char** carla_get_available_plugins(CarlaHost *host, int *count); - -// Get plugin display name -const char* carla_get_plugin_name(CarlaHost *host, int channel, int plugin_index); - -#endif // CARLA_H diff --git a/carla.o b/carla.o new file mode 100644 index 0000000..a17ded2 Binary files /dev/null and b/carla.o differ diff --git a/cli.o b/cli.o index c1d6851..c57bb64 100644 Binary files a/cli.o and b/cli.o differ diff --git a/Let me produce the SEARCH/REPLACE block now.test_stress.c b/config.c similarity index 100% rename from Let me produce the SEARCH/REPLACE block now.test_stress.c rename to config.c diff --git a/Let's craft the blocks.test_tui.c b/config.h similarity index 100% rename from Let's craft the blocks.test_tui.c rename to config.h diff --git a/dispatcher.o b/dispatcher.o new file mode 100644 index 0000000..a71931d Binary files /dev/null and b/dispatcher.o differ diff --git a/engine.o b/engine.o index fa66d02..76df87c 100644 Binary files a/engine.o and b/engine.o differ diff --git a/fs.o b/fs.o new file mode 100644 index 0000000..0705c50 Binary files /dev/null and b/fs.o differ diff --git a/gui.o b/gui.o index dd5e706..c6c2e1e 100644 Binary files a/gui.o and b/gui.o differ diff --git a/jack-looper b/jack-looper index 1377b81..5d8ca57 100755 Binary files a/jack-looper and b/jack-looper differ diff --git a/lib/microui.o b/lib/microui.o index 440b141..2802bf7 100644 Binary files a/lib/microui.o and b/lib/microui.o differ diff --git a/main.o b/main.o index 9e0ea41..7e37124 100644 Binary files a/main.o and b/main.o differ diff --git a/samples/clip_0.wav b/samples/clip_0.wav index b0ca7d1..331a580 100644 Binary files a/samples/clip_0.wav and b/samples/clip_0.wav differ diff --git a/stress_test.c b/stress_test.c deleted file mode 100644 index 067f82b..0000000 --- a/stress_test.c +++ /dev/null @@ -1,381 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include "dispatcher.h" -#include - -static volatile int keep_running = 1; - -static void handle_sigint(int sig) { - (void)sig; - keep_running = 0; -} - -// Helper: create a dispatcher with initial state -static DispatchFn setup_dispatcher(AppState *state) { - // Initialize default state - memset(state, 0, sizeof(AppState)); - state->transport_state = TRANSPORT_STOPPED; - state->clock_source = CLOCK_SOURCE_INTERNAL; - state->bpm = 120.0; - state->samples_per_beat = (48000 * 60.0) / 120.0; - state->quantize_mode = QUANTIZE_OFF; - state->quantize_threshold = 0; - for (int i = 0; i < MAX_CLIPS; i++) { - state->clips[i].state = CLIP_EMPTY; - state->clips[i].buffer_size = 0; - state->clips[i].write_position = 0; - state->clips[i].read_position = 0; - } - state->undo.undo_index = 0; - state->undo.redo_index = 0; - - DispatchFn dispatch = dispatcher_init(state); - assert(dispatch != NULL); - dispatcher_start(); - return dispatch; -} - -static void teardown_dispatcher(DispatchFn dispatch) { - (void)dispatch; - dispatcher_stop(); -} - -// Helper to build an Action -static Action make_action(ActionType type, int int_arg, jack_nframes_t nframes_arg) { - Action action; - memset(&action, 0, sizeof(action)); - action.type = type; - // Set the appropriate union member based on type - switch (type) { - case ACTION_TRIGGER_CLIP: - action.data.trigger_clip.clip_index = int_arg; - break; - case ACTION_TRIGGER_SCENE: - action.data.trigger_scene.scene_index = int_arg; - break; - case ACTION_RESET_CLIP: - action.data.reset_clip.clip_index = int_arg; - break; - case ACTION_SET_QUANTIZE_MODE: - action.data.set_quantize_mode.mode = (QuantizeMode)int_arg; - break; - case ACTION_SET_QUANTIZE_THRESHOLD: - action.data.set_quantize_threshold.threshold = nframes_arg; - break; - case ACTION_SET_CLOCK_SOURCE: - action.data.set_clock_source.source = (ClockSource)int_arg; - break; - case ACTION_SET_BPM: - action.data.set_bpm.bpm = (double)int_arg; - break; - case ACTION_SAVE_CLIP: - action.data.save_clip.clip_index = int_arg; - break; - case ACTION_LOAD_CLIP: - action.data.load_clip.clip_index = int_arg; - break; - case ACTION_MIDI_NOTE_ON: - action.data.midi_note_on.note = int_arg; - action.data.midi_note_on.time = nframes_arg; - break; - case ACTION_MIDI_SCENE_LAUNCH: - action.data.midi_scene_launch.scene_index = int_arg; - action.data.midi_scene_launch.time = nframes_arg; - break; - case ACTION_PROCESS_AUDIO: - action.data.process_audio.nframes = nframes_arg; - break; - default: - // For actions with no data (TRANSPORT_PLAY, etc.), nothing to set - break; - } - return action; -} - -// Stress test 1: Rapid clip triggers via dispatch -static void stress_rapid_triggers(void) { - printf("Stress test 1: Rapid clip triggers...\n"); - AppState state; - DispatchFn dispatch = setup_dispatcher(&state); - - int num_ops = 10000; - for (int i = 0; i < num_ops; i++) { - int clip_idx = i % MAX_CLIPS; - Action action = make_action(ACTION_TRIGGER_CLIP, clip_idx, 0); - dispatch(action); - } - - // Give dispatcher time to process - usleep(100000); - - // Verify some clips were triggered (state changed) - AppState current = dispatcher_get_state(); - int triggered = 0; - for (int i = 0; i < MAX_CLIPS; i++) { - if (current.clips[i].state != CLIP_EMPTY) triggered++; - } - printf(" Triggered %d clips\n", triggered); - - teardown_dispatcher(dispatch); - printf(" PASSED\n"); -} - -// Stress test 2: Mix of clip and scene triggers -static void stress_mixed_triggers(void) { - printf("Stress test 2: Mixed clip/scene triggers...\n"); - AppState state; - DispatchFn dispatch = setup_dispatcher(&state); - - int num_ops = 5000; - for (int i = 0; i < num_ops; i++) { - if (i % 3 == 0) { - int scene_idx = (i / 3) % MAX_SCENES; - Action action = make_action(ACTION_TRIGGER_SCENE, scene_idx, 0); - dispatch(action); - } else { - int clip_idx = i % MAX_CLIPS; - Action action = make_action(ACTION_TRIGGER_CLIP, clip_idx, 0); - dispatch(action); - } - } - - usleep(100000); - - teardown_dispatcher(dispatch); - printf(" PASSED\n"); -} - -// Stress test 3: Queue overflow (should not crash) -static void stress_queue_overflow(void) { - printf("Stress test 3: Queue overflow (should drop gracefully)...\n"); - AppState state; - DispatchFn dispatch = setup_dispatcher(&state); - - // Submit more than queue capacity (256) - int num_ops = 500; - for (int i = 0; i < num_ops; i++) { - Action action = make_action(ACTION_TRIGGER_CLIP, i % MAX_CLIPS, 0); - dispatch(action); - } - - usleep(100000); - - teardown_dispatcher(dispatch); - printf(" PASSED (no crash)\n"); -} - -// Stress test 4: Undo/Redo stress -static void stress_undo_redo(void) { - printf("Stress test 4: Undo/Redo stress...\n"); - AppState state; - DispatchFn dispatch = setup_dispatcher(&state); - - int num_ops = 1000; - for (int i = 0; i < num_ops; i++) { - int clip_idx = i % MAX_CLIPS; - Action action = make_action(ACTION_TRIGGER_CLIP, clip_idx, 0); - dispatch(action); - usleep(1000); - - // Undo every other operation - if (i % 2 == 0) { - Action undo_action = make_action(ACTION_UNDO, 0, 0); - dispatch(undo_action); - usleep(1000); - } - } - - // Redo some - for (int i = 0; i < 100; i++) { - Action redo_action = make_action(ACTION_REDO, 0, 0); - dispatch(redo_action); - usleep(1000); - } - - usleep(50000); - - teardown_dispatcher(dispatch); - printf(" PASSED\n"); -} - -// Stress test 5: Transport state changes -static void stress_transport(void) { - printf("Stress test 5: Transport state changes...\n"); - AppState state; - DispatchFn dispatch = setup_dispatcher(&state); - - int num_ops = 5000; - for (int i = 0; i < num_ops; i++) { - Action action; - memset(&action, 0, sizeof(action)); - switch (i % 5) { - case 0: - action.type = ACTION_TRANSPORT_PLAY; - break; - case 1: - action.type = ACTION_TRANSPORT_PAUSE; - break; - case 2: - action.type = ACTION_TRANSPORT_STOP; - break; - case 3: - action.type = ACTION_TRANSPORT_TOGGLE_PLAY; - break; - case 4: - action.type = ACTION_SET_CLOCK_SOURCE; - action.data.set_clock_source.source = CLOCK_SOURCE_MIDI; - break; - } - dispatch(action); - usleep(100); - } - - usleep(50000); - - teardown_dispatcher(dispatch); - printf(" PASSED\n"); -} - -// Stress test 6: Quantize mode changes -static void stress_quantize(void) { - printf("Stress test 6: Quantize mode changes...\n"); - AppState state; - DispatchFn dispatch = setup_dispatcher(&state); - - int num_ops = 5000; - for (int i = 0; i < num_ops; i++) { - QuantizeMode mode = (QuantizeMode)(i % 3); - Action mode_action = make_action(ACTION_SET_QUANTIZE_MODE, (int)mode, 0); - dispatch(mode_action); - Action thresh_action = make_action(ACTION_SET_QUANTIZE_THRESHOLD, 0, (jack_nframes_t)(i * 100)); - dispatch(thresh_action); - usleep(100); - } - - usleep(50000); - - teardown_dispatcher(dispatch); - printf(" PASSED\n"); -} - -// Stress test 7: Reset clips while triggering -static void stress_reset_while_triggering(void) { - printf("Stress test 7: Reset clips while triggering...\n"); - AppState state; - DispatchFn dispatch = setup_dispatcher(&state); - - int num_ops = 2000; - for (int i = 0; i < num_ops; i++) { - int clip_idx = i % MAX_CLIPS; - Action trigger_action = make_action(ACTION_TRIGGER_CLIP, clip_idx, 0); - dispatch(trigger_action); - usleep(500); - - if (i % 10 == 0) { - Action reset_action = make_action(ACTION_RESET_CLIP, clip_idx, 0); - dispatch(reset_action); - usleep(500); - } - } - - usleep(50000); - - teardown_dispatcher(dispatch); - printf(" PASSED\n"); -} - -// Stress test 8: Concurrent dispatch from multiple threads -typedef struct { - DispatchFn dispatch; - int thread_id; - int num_ops; -} ThreadArg; - -static void* thread_worker(void *arg) { - ThreadArg *targ = (ThreadArg *)arg; - for (int i = 0; i < targ->num_ops; i++) { - int clip_idx = (targ->thread_id * 1000 + i) % MAX_CLIPS; - Action action = make_action(ACTION_TRIGGER_CLIP, clip_idx, 0); - targ->dispatch(action); - } - return NULL; -} - -static void stress_concurrent(void) { - printf("Stress test 8: Concurrent dispatch from multiple threads...\n"); - AppState state; - DispatchFn dispatch = setup_dispatcher(&state); - - int num_threads = 4; - int ops_per_thread = 2500; - pthread_t threads[num_threads]; - ThreadArg args[num_threads]; - - for (int t = 0; t < num_threads; t++) { - args[t].dispatch = dispatch; - args[t].thread_id = t; - args[t].num_ops = ops_per_thread; - pthread_create(&threads[t], NULL, thread_worker, &args[t]); - } - - for (int t = 0; t < num_threads; t++) { - pthread_join(threads[t], NULL); - } - - usleep(100000); - - teardown_dispatcher(dispatch); - printf(" PASSED\n"); -} - -// Stress test 9: Repeated init/start/stop cycles -static void stress_create_destroy(void) { - printf("Stress test 9: Repeated init/start/stop cycles...\n"); - - for (int i = 0; i < 100; i++) { - AppState state; - DispatchFn dispatch = setup_dispatcher(&state); - - // Do some operations - for (int j = 0; j < 10; j++) { - Action trigger_action = make_action(ACTION_TRIGGER_CLIP, j % MAX_CLIPS, 0); - dispatch(trigger_action); - Action toggle_action; - memset(&toggle_action, 0, sizeof(toggle_action)); - toggle_action.type = ACTION_TRANSPORT_TOGGLE_PLAY; - dispatch(toggle_action); - Action mode_action = make_action(ACTION_SET_QUANTIZE_MODE, j % 3, 0); - dispatch(mode_action); - } - - usleep(1000); - teardown_dispatcher(dispatch); - } - - printf(" PASSED\n"); -} - -int main(void) { - signal(SIGINT, handle_sigint); - - printf("Running JACK Looper stress tests...\n\n"); - - stress_rapid_triggers(); - stress_mixed_triggers(); - stress_queue_overflow(); - stress_undo_redo(); - stress_transport(); - stress_quantize(); - stress_reset_while_triggering(); - stress_concurrent(); - stress_create_destroy(); - - printf("\nAll stress tests passed!\n"); - return 0; -} diff --git a/test_cli b/test_cli index 41e7e89..3bf3c98 100755 Binary files a/test_cli and b/test_cli differ diff --git a/test_cli.o b/test_cli.o index a47a695..0ddaaaa 100644 Binary files a/test_cli.o and b/test_cli.o differ diff --git a/test_double_process.c b/test_double_process.c deleted file mode 100644 index 2d4a6b0..0000000 --- a/test_double_process.c +++ /dev/null @@ -1,78 +0,0 @@ -// TODO: Remove this test after debugging the double status line issue -// test_double_process.c -#include "engine.h" -#include -#include -#include - -void test_command_processed_only_once(void) { - printf("Test: Command processed only once...\n"); - - Engine engine; - memset(&engine, 0, sizeof(engine)); - engine.sample_rate = 48000; - engine.control_channel = 0; - engine.quantize_mode = QUANTIZE_OFF; - engine.quantize_threshold = 0; - engine.queued_triggers = NULL; - - // Initialize command queue - command_queue_init(&engine.command_queue); - - // Initialize clips - for (int i = 0; i < MAX_CLIPS; i++) { - engine.clips[i].state = CLIP_EMPTY; - engine.clips[i].buffer = NULL; - engine.clips[i].buffer_size = 0; - engine.clips[i].write_position = 0; - engine.clips[i].read_position = 0; - } - - // Submit a trigger command - engine_trigger_clip(&engine, 0); - - // Check queue state - CommandQueue *q = &engine.command_queue; - unsigned int write = atomic_load(&q->write_index); - unsigned int read = atomic_load(&q->read_index); - printf(" Queue before process: write=%u, read=%u, pending=%u\n", - write, read, write - read); - assert(write - read == 1); // One command pending - - // Process once - engine_process_commands(&engine); - printf(" After first process: state=%d (expected %d=CLIP_RECORDING)\n", - engine.clips[0].state, CLIP_RECORDING); - assert(engine.clips[0].state == CLIP_RECORDING); - - // Check queue state after first process - write = atomic_load(&q->write_index); - read = atomic_load(&q->read_index); - printf(" Queue after first process: write=%u, read=%u, pending=%u\n", - write, read, write - read); - assert(write - read == 0); // No commands pending - - // Process again (simulating audio thread calling it) - engine_process_commands(&engine); - printf(" After second process: state=%d (expected %d=CLIP_RECORDING)\n", - engine.clips[0].state, CLIP_RECORDING); - - // If state changed, the command was processed twice - if (engine.clips[0].state != CLIP_RECORDING) { - printf(" BUG: State changed to %d on second process!\n", engine.clips[0].state); - } else { - printf(" OK: State unchanged after second process\n"); - } - - // Cleanup - for (int i = 0; i < MAX_CLIPS; i++) { - free(engine.clips[i].buffer); - } - - printf("PASSED\n"); -} - -int main(void) { - test_command_processed_only_once(); - return 0; -} diff --git a/test_engine b/test_engine index c58f580..acd0ffc 100755 Binary files a/test_engine and b/test_engine differ diff --git a/test_engine.o b/test_engine.o index 41aa807..103aa52 100644 Binary files a/test_engine.o and b/test_engine.o differ diff --git a/test_gui b/test_gui index b6000ea..e5c824e 100755 Binary files a/test_gui and b/test_gui differ diff --git a/test_gui.o b/test_gui.o index 78b3acb..4ba224b 100644 Binary files a/test_gui.o and b/test_gui.o differ diff --git a/test_stress b/test_stress index a6115e2..79d0c01 100755 Binary files a/test_stress and b/test_stress differ diff --git a/test_stress.o b/test_stress.o index 486ea58..64d369c 100644 Binary files a/test_stress.o and b/test_stress.o differ diff --git a/test_tui b/test_tui index 4fcf4da..c37c631 100755 Binary files a/test_tui and b/test_tui differ diff --git a/test_tui.o b/test_tui.o index 7abecfb..9620676 100644 Binary files a/test_tui.o and b/test_tui.o differ diff --git a/test_wav_io b/test_wav_io index 84dfa7c..f6b03f1 100755 Binary files a/test_wav_io and b/test_wav_io differ diff --git a/test_wav_io.o b/test_wav_io.o index 969ef82..a5517b9 100644 Binary files a/test_wav_io.o and b/test_wav_io.o differ diff --git a/transport.o b/transport.o index faa85c1..5b866bb 100644 Binary files a/transport.o and b/transport.o differ diff --git a/tui.o b/tui.o index cea944b..7b40eac 100644 Binary files a/tui.o and b/tui.o differ diff --git a/wav_io.o b/wav_io.o index e009144..c441662 100644 Binary files a/wav_io.o and b/wav_io.o differ