feat: integrate real Carla host with JACK support and add plugin abstraction layer

This commit is contained in:
Loic Coenen
2026-05-16 22:23:50 +00:00
parent dafc7fe46b
commit c7df02d37c
20 changed files with 285 additions and 113 deletions

View File

@@ -1,69 +1,15 @@
# Final Code Evaluation (All Changes In Place)
# Final Code Evaluation
## Summary Table
| Category | Rating | Remarks |
|--------------------------|---------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **Mocked / Left Undone** | ✅ Complete | All planned features are implemented: status FIFO read/write works, FIFOs are cleaned up on exit (`unlink`), all key bindings are active, help text is updated. Visual mode, yank buffer, fuzzy search, rack view, etc. remain as stubs (kept per PLAN.md). These are nonblocking placeholders for future work. No regressions. |
| **Potential Segfaults** | ✅ Low Risk | No unsafe pointer dereferences. All array indices bounded. FIFO read uses 256byte buffer truncation harmless. `send_command` returns -1 on failure (callers ignore no crash). `yank_buffer.clip_indices` remains `NULL`; `free(NULL)` safe. |
| **Memory Safety** | ✅ Good | No dynamic allocations of consequence. `cell_state` static. Engine uses `calloc` for channel arrays and deferred free after RT cycle. No leaks. |
| **Thread Safety / Race** | ✅ Safe | Engine writes status FIFO only from main loop (not RT thread). Client singlethreaded. FIFO writes atomic (≤256 bytes < `PIPE_BUF`). `pipe.c` reader uses threadsafe SPSC queue. `test_status_fifo.c` uses `select()` with timeout and retry loop racefree, no hangs, passes reliably. No shared mutable state between RT and main loops besides atomics. |
| **Performance** | ✅ Acceptable | Negligible overhead. Status FIFO nonblocking read per keypress. Grid redraw cheap. |
| **Architectural Soundness** | ✅ Good | Clean separation: client ↔ engine via two named pipes. Client has zero engine source linkage. Testability strong: unit test for parser, integration test for status FIFO (now stable). FIFOs deleted on client exit (no stale files). Architecture supports incremental extension. |
## Detailed Remarks
### 1. Mocked / Left Undone
- **Status feedback complete**: Engine writes `CH=... STATE=...` after each mainloop iteration; client reads on every keypress and updates cell colours.
- **FIFO cleanup**: `tui_cleanup()` calls `unlink(STATUS_FIFO)` and `unlink(CMD_FIFO)`.
- **Key bindings final**: All keys from PLAN.md are mapped:
- `h/j/k/l` navigate; `t` record toggle; `s` next scene, `S` prev scene; `d`/`D` stop; `a` add audio, `A` add MIDI; `r` remove; `b` bind, `u` unbind; `?` toggle help; `Esc`/`Q` quit.
- **Help text** updated with all active keybindings.
- **Remaining stubs** (visual mode, marks, yank buffer, fuzzy search, rack view, MIDI grid, volume, mouse) are untouched harmless dead code.
- Scene display uses `ch` index only; `sc` field is parsed but not shown adequate for singlescene representation.
### 2. Potential Segfaults
- `parse_status_line`: bounded `sscanf`, safe.
- `send_command`: if FIFO missing, returns -1 no crash.
- `tui_run()` status read: `open`/`read`/`close` with `O_NONBLOCK` handles -1.
- All array accesses modulobounded.
- Engine checks NULL ports before use.
- No dangerous pointer casts.
### 3. Memory Safety
- Client static arrays only; `yank_buffer.clip_indices` never allocated → `free(NULL)` safe.
- Engine uses `calloc` plus deferred free after RT cycle no useafterfree.
- No leaks observed.
### 4. Thread Safety / Race Conditions
- **Engine RT thread**: only touches SPSC queue (`cmd_queue`) and atomic globals. Does not call `looper_write_status()`.
- **Engine main loop**: calls `looper_write_status()` with `O_NONBLOCK` safe.
- **`pipe.c` reader thread**: uses `queue_push` on `cmd_queue_main_fifo` SPSC is threadsafe.
- **Client**: singlethreaded.
- **`test_status_fifo.c`**: uses `select()` with 100ms timeout per iteration and retries up to 5s racefree and does not hang.
- All FIFO writes ≤256 bytes < `PIPE_BUF` → atomic.
### 5. Performance
- Status FIFO read: one `open`/`read`/`close` per keypress negligible.
- `parse_status_line` = one `sscanf`.
- Grid redraw 64 cells = cheap.
- `send_command` = three system calls per action fine at UI speeds.
- Engine `looper_write_status` loops over ≤8 channels, builds small string, nonblocking write called once per mainloop cycle (every 10100 ms) negligible overhead.
### 6. Architectural Soundness
- **Complete bidirectional communication**: user → FIFO command → engine → status FIFO → client → colour update.
- **Zero linkage** between client and engine source.
- **Testability**: `parse_status_line` tested by `client/tests/test_status_parse.c`. Status FIFO integration tested by `engine/tests/test_status_fifo.c` (passes reliably).
- **FIFO cleanup on exit** prevents stale pipe files.
- **Extensibility**: Adding a new command requires only a `case` in `pipe.c` and a key mapping in `tui.c`. Extending status format requires updates in `looper.c` and `tui.c` (both are simple).
| Category | Rating | Remarks |
|--------------------------|---------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **Mocked / Left Undone** | 🟡 Partial | The lowlevel Carla host integration (`carla_host.c`) is fully implemented with real JACK connections. The TUI (`tui.c`) does **not** expose plugin commands (`:addplugin`, `:connect`, `:rack`, etc.). Colons mode, rack view, and plugin list display are stubs they exist only in the plan (`breakup.md`). Plugin functions can be called programmatically but not from the interactive UI. |
| **Potential Segfaults** | 🟢 Low Risk | No unsafe pointer dereferences. All Carla functions check for `NULL` handle and valid indices. `carla_disconnect` returns `0` when JACK client is missing (safe). `send_command` handles FIFO failures gracefully. The only dynamic memory is `yank_buffer.clip_indices` which is `NULL` `free(NULL)` safe. |
| **Memory Safety** | 🟢 Good | No dynamic allocations of consequence. The Carla handle and JACK client are owned by external libraries, not mallocd locally. No leaks. The yank buffer is never allocated. |
| **Thread Safety / Race** | 🟢 Safe | Client is singlethreaded. Engine is a separate process communicating via FIFOs. `carla_host.c` opens a JACK client but does **not** register a process callback it only calls `jack_connect`/`jack_disconnect` which are threadsafe (JACK handles concurrency internally). No shared mutable state. |
| **Performance** | 🟢 Acceptable | Carla host calls occur only on user actions (load/unload/connect). TUI reads status FIFO per keypress cheap. No hotpath issues. |
| **Architectural Soundness** | 🟢 Good | Clean separation: engine ↔ client via FIFOs. Plugin hosting is clientside and independent of the engine. Module layering (`carla_host.h``plugins.h``tui.c`) is clear. The only shortcoming is that the TUI does not yet implement the planned colonmode plugin commands and rack view these are documented but not wired. |
| **Unit Test Quality** | 🟡 Moderate | `test_status_parse` covers all states + malformed input good. `test_carla_host` covers error paths (invalid id, NULL binary) and some benign success paths. No test verifies that a successful `carla_load` + `carla_connect` actually results in a JACK connection (requires JACK server running). No mock layer exists to isolate tests from JACK. Recommended: add a compiletime mock switch for `carla_host.c`. |
## Overall Verdict
**Rating: Productionready Skeleton**
The code is complete, safe, racefree, and architecturally sound. All planned features are implemented. Remaining stubs are inert placeholders. The tests pass reliably. The client provides realtime visual feedback of the looper engines state and can be used interactively.
**Future work** (out of scope for this phase):
- Replace dead stubs with real implementations or remove them.
- Add transport play/pause FIFO command and key binding.
- Display multiple scenes per channel.
- Error recovery when engine is not running.
**Productionready skeleton** for the Carla host integration, but the **TUI plugin commands are unfinished**. No safety or memory issues exist. The unit tests cover error paths adequately but lack coverage of real JACK connectivity scenarios. Adding colonmode commands and a rack view per `breakup.md` would bring the system to interactive readiness.