Initial extraction: C++ MixerEngine standalone daemon
Extracted from op-pedal mixer-engine branch. Core components: - MixerEngine / MixerChannelStrip / MixerBus — cleaned of LV2/Pedalboard/IHost/MidiMapper deps - MixerControlServer — Unix domain socket JSON control interface - main.cpp — JACK audio I/O client with headless fallback - CMake build — auto-fetches nlohmann/json, links JACK - 9 core tests passing Architecture: JACK ports → MixerEngine::process() → JACK ports, controlled via Unix socket JSON commands.
This commit is contained in:
@@ -0,0 +1,123 @@
|
||||
# OPLabs Mixer Engine — Standalone Daemon
|
||||
|
||||
C++ standalone audio mixer daemon, extracted from the op-pedal mixer-engine branch. JACK audio I/O with Unix socket JSON control.
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
JACK Ports → MixerEngine::process() → JACK Ports
|
||||
↕
|
||||
MixerControlServer (Unix socket)
|
||||
↕
|
||||
FastAPI bridge (future) / socat / nc
|
||||
↕
|
||||
React Mixer Console (browser)
|
||||
```
|
||||
|
||||
### Processing Pipeline (per audio cycle)
|
||||
|
||||
1. Clear all bus buffers
|
||||
2. For each channel: apply HPF → volume/pan → accumulate to routed buses
|
||||
3. Process aux sends (pre/post fader)
|
||||
4. Route buses to buses according to routing matrix
|
||||
5. Process each bus (apply volume, compute VU)
|
||||
6. Write to physical outputs per output routing table
|
||||
|
||||
## Dependencies
|
||||
|
||||
- **JACK** (libjack-jackd2-dev on Debian, jack-audio-connection-kit-devel on Fedora)
|
||||
- **CMake** >= 3.16
|
||||
- **C++17** compiler
|
||||
- **nlohmann/json** (auto-fetched by CMake)
|
||||
|
||||
## Build
|
||||
|
||||
```bash
|
||||
git clone <repo-url> oplabs-mixer-daemon
|
||||
cd oplabs-mixer-daemon
|
||||
mkdir build && cd build
|
||||
cmake ..
|
||||
make -j$(nproc)
|
||||
```
|
||||
|
||||
## Run
|
||||
|
||||
```bash
|
||||
# Start JACK first
|
||||
jackd -d alsa -r 48000 -p 256 -n 3 &
|
||||
|
||||
# Run the daemon (auto-connects to JACK)
|
||||
./mixer-daemon
|
||||
|
||||
# With custom config
|
||||
./mixer-daemon --inputs 4 --outputs 2 --buffer-size 128
|
||||
```
|
||||
|
||||
### Command-line Options
|
||||
|
||||
| Option | Default | Description |
|
||||
|--------|---------|-------------|
|
||||
| `--socket <path>` | `/tmp/mixer-daemon.sock` | Unix socket path |
|
||||
| `--inputs <N>` | 2 | Number of JACK input channels |
|
||||
| `--outputs <N>` | 2 | Number of JACK output channels |
|
||||
| `--sample-rate <N>` | 48000 | Audio sample rate (overridden by JACK) |
|
||||
| `--buffer-size <N>` | 256 | Audio buffer size in frames (overridden by JACK) |
|
||||
| `--help` | | Show help |
|
||||
|
||||
### Headless Mode
|
||||
|
||||
If JACK is not running, the daemon starts in headless mode — no audio I/O, but the control socket is active for testing.
|
||||
|
||||
## Control Protocol
|
||||
|
||||
The daemon listens on a Unix domain socket. Send one JSON command per line, receive one JSON response per line.
|
||||
|
||||
```bash
|
||||
# Get full mixer state
|
||||
echo '{"cmd":"getState"}' | nc -U /tmp/mixer-daemon.sock
|
||||
|
||||
# Set channel volume
|
||||
echo '{"cmd":"setChannelVolume","channel":0,"volume":-6.0}' | nc -U /tmp/mixer-daemon.sock
|
||||
|
||||
# Get VU levels
|
||||
echo '{"cmd":"getVU"}' | nc -U /tmp/mixer-daemon.sock
|
||||
|
||||
# Auto-create channels
|
||||
echo '{"cmd":"autoCreateChannels","inputs":4,"outputs":2}' | nc -U /tmp/mixer-daemon.sock
|
||||
```
|
||||
|
||||
### Commands
|
||||
|
||||
| Command | Parameters | Description |
|
||||
|---------|------------|-------------|
|
||||
| `getState` | — | Full mixer state as JSON |
|
||||
| `getVU` | — | VU levels per channel and bus |
|
||||
| `setChannelVolume` | `channel`, `volume` | Set channel fader (-96..+12 dB) |
|
||||
| `setChannelPan` | `channel`, `pan` | Set pan (-1.0 left to 1.0 right) |
|
||||
| `setChannelMute` | `channel`, `mute` | Mute toggle |
|
||||
| `setChannelSolo` | `channel`, `solo` | Solo toggle |
|
||||
| `setChannelLabel` | `channel`, `label` | Set channel name |
|
||||
| `setBusVolume` | `busId`, `volume` | Set bus fader (-96..+12 dB) |
|
||||
| `setBusMute` | `busId`, `mute` | Bus mute toggle |
|
||||
| `routeChannelToBus` | `channel`, `busId`, `level` | Route channel to bus |
|
||||
| `routeBusToBus` | `sourceBusId`, `targetBusId`, `level` | Route bus to bus |
|
||||
| `removeRoute` | `sourceId`, `targetBusId` | Remove a route |
|
||||
| `autoCreateChannels` | `inputs`, `outputs` | Recreate all channels for N inputs |
|
||||
| `addChannel` | `physicalInput` | Add a new channel strip |
|
||||
| `removeChannel` | `channel` | Remove a channel strip |
|
||||
|
||||
## Run Tests
|
||||
|
||||
```bash
|
||||
cd build && ctest
|
||||
# or
|
||||
./mixer-test
|
||||
```
|
||||
|
||||
## Integration
|
||||
|
||||
The daemon is designed to sit behind a FastAPI Python bridge that translates HTTP/WebSocket to Unix socket commands. That bridge then serves the React Mixer Console UI.
|
||||
|
||||
## License
|
||||
|
||||
Copyright (c) 2026 Ourpad Network. See LICENSE file.
|
||||
Reference in New Issue
Block a user