Directories | |
| interface | |
| macos | |
| shader.packs | |
| shader_generator | |
Files | |
| acmx.cpp | |
| ACMX2 — Real-time GPU-accelerated video glitch engine. | |
| audio.cpp | |
| audio.hpp | |
| audio_transfer.cpp | |
| dnn.cpp | |
| dnn.hpp | |
| file_audio.cpp | |
| FFmpeg-based audio file decoder for audio-reactive shaders. | |
| file_audio.hpp | |
| File-based audio input for audio-reactive shaders. | |
| program.cpp | |
| program.hpp | |
| shader_selection_shm.hpp | |
| version_info.hpp | |
To regenerate local docs in a versioned folder and refresh docs/latest:
This keeps docs/index.html as a stable redirect to the newest generated docs.
The command-line engine for acidcam-gpu. Applies GLSL shaders to live camera feeds, video files, or static images in real time, with optional CUDA-accelerated GPU filters when built on NVIDIA hardware. Supports 3D model rendering, audio reactivity, MIDI control, shader playlists, and multipass shader chains.
NVIDIA GPUs are not required. ACMX2 is built around an OpenGL/SDL2 shader pipeline that runs on NVIDIA, AMD, Intel, and Apple GPUs. The CUDA GPU-filter stack is opt-in at compile time via -DWITH_CUDA=ON and only requires NVIDIA hardware + CUDA-enabled OpenCV when you choose to enable it.
Lossless hardware HEVC output can be configured with:
The past week has brought significant expansions to the ONNX/DNN model system and output capabilities:
Recent Qt interface updates focus on session usability and repeatability:
The shader editor provides line numbers, GLSL syntax highlighting, current-line and matching-bracket highlighting, and a line/column status display. It automatically indents new blocks, inserts matching brackets and quotes, and supports smart Home, four-space Tab/Shift+Tab indentation, duplicate line (Ctrl+D), toggle comment (Ctrl+/), and move line (Alt+Up/Alt+Down). The current-line and syntax colors follow the active light or dark interface theme, including theme changes made while an editor window is open.
The Edit and View menus also provide undo/redo, find next/previous, replace, Go to Line (Ctrl+G), selection indentation, font zoom, and persistent word-wrap, font-size, and window-geometry settings. On macOS these menus are embedded in each editor window rather than being placed in the system-wide menu bar.
Use List > Find in Files (Ctrl+Shift+F) from the main interface to search the active shader directory recursively. The query is a Qt regular expression, with optional case sensitivity, and searches .glsl, .frag, and .vert files. Each result includes its relative file, line number, matched text, and source line. Double-click a result or choose Open Result to open that shader at the exact line and column with the match selected.
Launch ACMX2 from the interface, open a shader from the library, edit it, and save normally. The editor sends the saved shader's canonical path and stable library index through the existing interface shared-memory channel. The render process notices the new request on its next frame and recompiles only that shader; it does not rebuild or reload the rest of the library.
Successful compilation replaces the shader immediately. ACMX2 prepares the new program and all known uniform locations before swapping it into the live library, including the 3D variant when dual mode is active. If compilation or linking fails, the last valid program remains in use and the driver-provided error string appears in the interface log. Fix the source and save again to retry without stopping the session.
Shader-library paths are directories. When both manifests exist, ACMX2 and its Qt interface use library.json; otherwise they fall back to index.txt. When the Qt interface loads an older library that only has index.txt, it automatically creates an equivalent library.json and leaves the original text manifest unchanged. The JSON format is:
On Linux, files ending in .comp are compiled as OpenGL compute shaders when OpenGL 4.3 or newer is available. They can be selected normally or mixed with fragment shaders in --shader-pass lists. On an OpenGL 4.1 context each compute entry becomes a no-op passthrough, preserving all manifest, playlist, and multipass indices. The version 4 whole-library binary cache records each entry's program type and stores compute binaries alongside fragment/vertex pairs. Per-program fragment and compute caches use source- and driver-specific keys, so unchanged programs can be restored without recompilation.
A compute shader receives the same uniforms and texture bindings listed below. It reads the current pass from samp and writes to an RGBA16F image on image unit 0. Dispatch dimensions are derived from the declared local workgroup size. Input and history textures can retain the source video's dimensions when the output resolution differs, so compute shaders should derive normalized UVs from the output pixel and use textureLod(..., uv, 0.0) to scale those inputs. Do not pass gl_GlobalInvocationID.xy directly to texelFetch(samp, ...) unless the coordinates are first scaled using textureSize(samp, 0). The invocation ID addresses the output image, not necessarily the input texture; using it directly renders only the source-sized lower-left region and leaves the rest black when a smaller video is rendered at a larger resolution. Use a resolution-independent helper for current-pass reads:
A minimal shader is:
The New Shader Library dialog can create library.json directly. If a library contains only index.txt, its first interface load creates the JSON manifest automatically. Sorting, adding or removing shaders, live reload, cache builds, and Remove Broken all operate on the selected manifest.
Legacy libraries can also be converted from the command line:
The converter accepts either a library directory or an index.txt path. It keeps the original text file and refuses to replace an existing library.json unless --force is supplied. Use --output <file> to choose another output path. The script depends only on Perl core modules, including JSON::PP.
ACMX2 builds and runs on macOS using OpenGL 4.1 backed by Metal. CUDA is not available on macOS, so the engine automatically builds with -DWITH_CUDA=OFF. Shader-based effects work fully; only the CUDA GPU-filter pipeline is omitted.
The Apple Metal-backed OpenGL 4.1 driver does not support glProgramBinary, so the shader binary cache is disabled at runtime on macOS. The interface disables Run from Cache, hides Rebuild Shader Cache and the compile-health column, and passes --no-cache for normal launches so shaders compile from source on every run. Live editor saves remain supported and request an in-place source recompile without attempting to save a binary cache.
Quick start (one command from an empty directory):
This installs Homebrew packages, clones libmx2 and acidcam-gpu (which contains ACMX2), builds everything, and installs to /usr/local/bin/.
Or step by step:
Install Homebrew packages:
Required: cmake, pkg-config, sdl2, sdl2_ttf, sdl2_mixer, sdl2_image, glm, opencv, ffmpeg, qt6
Build and install:
Download the macOS-compatible shader pack (the default library contains shaders that crash the Apple GL driver):
Run:
See macos/README.md for full details, troubleshooting, and CMake flags.
Build ACMX2 from an MSYS2 UCRT64 shell. Install the UCRT64 C++ toolchain, CMake/Ninja, pkg-config, SDL2, OpenCV, FFmpeg, GLM, and any enabled optional audio, MIDI, WebP, TIFF, or YAML dependencies. Build and install libmx2 into the same prefix first; the repository-local MXWrite/ source is built automatically with ACMX2.
The installed executable resolves its data from <prefix>/share/acmx2/data, so it does not require --path when kept in the installed prefix layout. Runtime interface control uses Windows named shared memory and a named mutex. Compute shaders are enabled when the Windows OpenGL driver exposes OpenGL 4.3 or newer.
Windows --silent processing uses a hidden native OpenGL window. It suppresses the preview but still requires an interactive Windows desktop and a working graphics driver.
Basic checks after copying the required runtime DLLs beside the executable or adding their directory to PATH:
ACMX2 is part of the acidcam-gpu project. See the main README for full build instructions.
The Qt6 GUI is built separately:
CUDA, audio, and MIDI support are all optional at compile time. Each subsystem is gated by a CMake option and a corresponding preprocessor definition:
| Option | Default | Definition | Disables |
|---|---|---|---|
| WITH_CUDA | Linux: ON; macOS/Windows: OFF | ACMX2_WITH_CUDA | CUDA GPU filters, zero-copy CUDA/GL interop, FFmpeg CUDA hw-decode, --gpu-filter, --gpu-buffer, --cuda-device, --list-cuda-devices |
| AUDIO | OFF | AUDIO_ENABLED | RtAudio capture, audio reactivity, --enable-audio, --audio-file, --record-audio, audio controls |
| MIDI | OFF | MIDI_ENABLED | RtMidi input, --midi-map, --midi-device, --list-midi, MIDI overlay |
If you do not have an NVIDIA GPU, do not want to install the CUDA toolkit, or want to build against a stock OpenCV that was not compiled with CUDA support, turn WITH_CUDA off. The engine falls back to pure OpenGL/SDL2 rendering; shader-based effects still work, only the CUDA GPU filter stack is omitted.
You can combine the flags freely — for example an OpenGL-only build with audio:
Or to enable ONNX/DNN model loading:
Note: -DWITH_OPENCV_DNN=ON requires the yaml-cpp package to be installed for YAML configuration file parsing. It can be combined with -DWITH_CUDA=OFF; DNN inference will then use the OpenCV CPU backend. With CUDA enabled, ACMX2 benchmarks CPU and CUDA once per loaded model and keeps the faster backend. Set ACMX2_DNN_BACKEND=cpu, cuda, or cuda_fp16 to override automatic selection.
Generic ONNX YAML files may enable runtime-dynamic spatial dimensions:
Set either width or height to 0 to derive that dimension from the source aspect ratio, or set both to 0 to use the source dimensions. Dynamic sizes are rounded to alignment because style-transfer networks commonly downsample by four. ACMX2 re-plans and re-benchmarks the selected backend if the resolved input dimensions change. Dynamic configurations at 256×256 or below also apply an edge-preserving bilateral filter before upscaling. CUDA-selected models use cv::cuda::bilateralFilter; CPU-selected models use the equivalent CPU filter. Override its defaults with:
The model directory includes four optional dynamic quality tiers for every YAML-configured style model:
At startup, the Qt6 interface probes the installed acmx2 binary with --check-cuda, --check-audio, and --check-midi and automatically disables menu entries (GPU Filter Settings, Audio Settings, MIDI Settings) and CLI arguments corresponding to features that were not compiled in. You can also run the probes manually:
make install places files under CMAKE_INSTALL_PREFIX (default /usr/local):
| Path | Contents |
|---|---|
| bin/acmx2 | Main engine binary |
| bin/acmx2_interface | Qt6 GUI launcher |
| share/acmx2/data/ | Assets (icon, fonts, models, shaders, textures) |
| share/acmx2/acmx2.png | Application icon |
| share/applications/acmx2.desktop | Desktop entry for acmx2 |
| share/applications/acmx2-interface.desktop | Desktop entry for acmx2_interface |
Both acmx2 and acmx2_interface automatically locate the installed data directory at <prefix>/share/acmx2/ when the local ./data directory is not present. You can still override the assets path with -p <dir>.
When running inside a Distrobox container, export the applications to the host desktop:
Camera with a shader library:
Process a video file with GPU filters and record output:
Single shader, fullscreen, with audio reactivity:
3D mode with a model:
Silent (headless) batch processing:
Silent HDR batch processing:
Build shader cache:
Process a video with audio-reactive shaders driven by a music file:
Same as above, but stop when the audio track ends:
| Short | Long | Value | Description |
|---|---|---|---|
| -v, -h | --help, --version | Display the full program information, arguments, and keyboard controls, then exit | |
| -p | --path | <dir> | Assets path |
| -r | --resolution | WxH | Window resolution (e.g. 1920x1080) |
| -d | --device | <index> | Camera device index |
| -c | --camera-res | WxH | Camera capture resolution |
| -i | --input | <file> | Input video file |
| -g | --graphic | <file> | Input image file |
| -o | --output | <file> | Output video file |
| -b | --bitrate | <crf> | Output bitrate in CRF |
| -u | --fps | <fps> | Frames per second |
| -e | --prefix | <path> | Snapshot save prefix |
| -a | --repeat | Loop/repeat video playback | |
| -n / -N | --fullscreen | Fullscreen window (Escape to quit) | |
| -m | --cuda-device | <index> | CUDA device index |
| --interface-shm | Enable Qt interface shared-memory control channel (off by default for normal CLI runs) | ||
| --duration | <seconds> | Recording duration limit in seconds (float); stop recording and exit after elapsed | |
| --encode-preset | <name> | Encoder preset: ultrafast..veryslow or NVENC p1..p7 | |
| --encode-tune | <name> | Encoder tune, including NVENC hq, uhq, ll, ull, and lossless | |
| --encode-crf | <0-51> | Encoder CRF quality override (default: 18) | |
| --encode-codec | <mode> | Encoder codec mode: auto, software, nvenc, h264_nvenc, or hevc_nvenc | |
| --encode-params | <string> | Additional FFmpeg-style video encoder options passed through MXWrite | |
| --encode-realtime | Enable low-latency realtime encoding flags | ||
| --no-drop | Video-file processing: never drop frames; block when the encoder queue is full |
| Short | Long | Value | Description |
|---|---|---|---|
| -s | --shaders | <directory> | Shader library directory (library.json preferred, index.txt fallback) |
| -f | --fragment | <file> | Single fragment shader file |
| --shader | <index> | Initial shader index in library | |
| --shader-pass | <indices> | Shader pass indices (comma-separated, e.g. 0,1,2) | |
| --playlist | <file> | Shader playlist text file (one shader name per line) | |
| --build | <path> | Build shader cache for specified library path and exit | |
| --no-cache | Disable shader caching (always recompile shaders) | ||
| --time-speed | <float> | Constant time_f speed multiplier (default: 1.0) | |
| --normalized | Advance time_f by time-speed / FPS per rendered frame, independent of wall-clock rendering speed |
| Long | Value | Description |
|---|---|---|
| --gpu-filter | <indices> | GPU filter indices (comma-separated) |
| --gpu-buffer | <size> | GPU frame buffer size (4–32) |
| --list-filters | List available GPU filters and exit | |
| --list-cuda-devices | List available CUDA devices and exit | |
| --disable-counter | Disable timer and FPS counter overlay | |
| --silent | Process video or a graphics file without a window. Valid for -i/--input video and -g/--graphic image files; requires -o/--output. Graphics input also requires a positive --duration. Camera input is not supported. |
| Long | Value | Description |
|---|---|---|
| --texture-cache | Enable texture cache (camera, video, and graphic modes) | |
| --cache-delay | <frames> | Texture cache delay in frames |
| --texture-cache-size | <frames> | Texture cache ring size (1–64, default 8) |
| --texture-cache-array | Bind the cache as sampler2DArray history instead of separate samplers | |
| --copy-audio | Copy audio track from input to output | |
| --enable-3d | Enable 3D cube rendering | |
| --model | <file> | 3D model file (.mxmod) |
| Short | Long | Value | Description |
|---|---|---|---|
| -w | --enable-audio | Enable audio reactivity | |
| -l | --channels | <num> | Audio channels |
| -q | --sense | <float> | Audio sensitivity |
| -y | --pass-through | Enable audio pass-through | |
| --audio-input | <index> | Audio input device (default or index) | |
| --audio-output | <index> | Audio output device (default or index) | |
| --list-devices | List audio devices and exit | ||
| --record-audio | <file> | Record captured audio to WAV file | |
| --record-gain | <float> | Recording volume gain 0.0–2.0 (default: 1.0) | |
| --audio-file | <file> | Use audio from a file for reactivity instead of the microphone; the audio track is muxed into the output video | |
| --audio-trunc | Stop playback when the audio file reaches the end | ||
| --audio-repeat | Restart audio file playback from the beginning when it reaches the end | ||
| --audio-warm-rate | <float> | Startup audio warmup rate in 1/sec (default: 0.5; 0 disables warmup) | |
| --enable-audio-buffers | <N> | Allocate one FFT history sampler1DArray with N GPU-limited layers |
| Long | Value | Description |
|---|---|---|
| --midi-map | <file> | MIDI config file (.midi_cfg) |
| --midi-device | <index> | MIDI input device index |
| --list-midi | List available MIDI input devices and exit |
ACMX2 automatically enables its HDR path when the input video is tagged as BT.2020 HDR with PQ (SMPTE ST.2084) or HLG (ARIB STD-B67) transfer characteristics, or when the decoded stream is a 10-bit BT.2020 format such as yuv420p10le or p010le.
On ingest, the program preserves the source HDR encoding long enough to upload each frame into a 16-bit RGBA texture. A dedicated HDR decode shader converts PQ or HLG into linear BT.2020 before the normal shader chain and optional CUDA filters run. After the last effect pass, a matching HDR encode shader converts the result back to the same HDR transfer family as the source.
HDR exports are written as HEVC Main10, not H.264. The output path feeds MXWrite a BT.2020 HDR frame that is quantized to a 10-bit P010 HEVC stream, with BT.2020 primaries and the original PQ or HLG transfer preserved. If the input contains mastering-display or content-light metadata, ACMX2 forwards that HDR metadata to the encoded output.
That gives you an end-to-end HDR round-trip: HDR in, effects in linear BT.2020, HDR out. The terminal log reports this explicitly when active, for example HDR output mode enabled: HEVC Main10 + BT.2020 + PQ.
--silent is the headless rendering mode for video and graphics-file input. It creates an off-screen context, does not open a visible SDL window, and skips playback pacing so the job runs as fast as possible instead of real time. Because a graphics file has no natural end, silent graphics mode requires a positive --duration.
While recording, headless progress lines include the current encoded output file size after the elapsed time. Graphics-file mode prints progress after about one second of output frames or 500 ms of wall time, whichever occurs first, followed by a final 100% update.
Typical use:
Render ten seconds from a still image:
HDR files use the same flag set and automatically stay in HDR:
Because progress is printed to stdout in headless mode, --silent is suitable for shell pipelines and logs:
| Key | Action |
|---|---|
| Up | Previous shader (or previous playlist shader if playlist enabled) |
| Down | Next shader (or next playlist shader if playlist enabled) |
| K | Toggle shader lock (prevent Up/Down from switching shaders) |
| R | Toggle random multipass mode (generates random 1–5 shader chain with crossfade; press again to restore previous state) |
| G | Generate a new random shader chain (while in random multipass mode) |
| Left | Previous GPU filter (if GPU filters enabled) |
| Right | Next GPU filter (if GPU filters enabled) |
| Space | Toggle shader processing bypass |
| P | Toggle playlist mode / Pause video (Video/Image modes) |
| L | Toggle video freeze (Video/Image modes) |
| Z | Take snapshot |
| M | Toggle multi-shader pass (if --shader-pass set) |
| 3 | Toggle 2D/3D mode (if --enable-3d active) |
| E | Toggle watermark |
| F9 | Toggle overlay (timer/FPS counter) visibility |
| Key | Action |
|---|---|
| U (hold) | Increase time step |
| I (hold) | Decrease time step |
| T | Toggle time on/off (Audio build) |
| Q | Toggle audio-reactive time (Audio build) |
| Home | Toggle audio delta time scaling (Audio build) |
| Page up/page Down | Increase / Decrease Time speed |
| Key | Action |
|---|---|
| Insert | Increase audio sensitivity |
| Delete | Decrease audio sensitivity |
| Key | Action |
|---|---|
| W / A / S / D | Look around |
| V | Toggle view rotation |
| O | Toggle scale oscillation |
| X | Reset camera distance |
| + / - | Increase / decrease camera distance |
| B | Increase movement speed |
| N | Decrease movement speed |
| C | Toggle wave effect |
Fragment and compute shaders receive the following uniforms automatically. Uniforms that are not declared in a shader are silently ignored.
| Uniform | Type | Description |
|---|---|---|
| samp | sampler2D | Main video/camera texture |
| alpha | float | Alpha value (oscillates 0.0–1.0) |
| iTime | float | Elapsed time in seconds since start |
| time_f | float | Time multiplier (adjustable with U/I keys and --time-speed) |
| iFrame | int | Frame counter |
| iTimeDelta | float | Time since last frame (seconds) |
| iResolution | vec2 | Window resolution (width, height) |
| iMouse | vec4 | Mouse position (x, y, clickStartX, clickStartY) |
| iMouseClick | vec2 | Last mouse click position |
| iDate | vec4 | Current date/time (year, month, day, secondsOfDay) |
| iFrameRate | float | Frame rate |
| iChannelTime[0..3] | float | Per-channel time |
| iChannelResolution[0..3] | vec3 | Per-channel resolution |
| Uniform | Type | Description |
|---|---|---|
| samp1–samp8 | sampler2D | Cached frame textures from the texture cache ring buffer |
| textures[SIZE] | sampler2D[] | Scalable oldest-to-newest cache view in the default binding mode |
| history | sampler2DArray | Optional ring-layer view, mapped oldest-to-newest with history_head |
Shaders can support both cache representations with the injected USE_HISTORY_TEXTURE_ARRAY macro:
A sampler2DArray is one OpenGL texture object whose layers are equally sized 2D images. The engine binds the entire history cache to one texture unit instead of binding samp1 through samp8 separately, which simplifies the host-side OpenGL state and leaves more texture units available for other inputs.
The history layer is the third texture-coordinate component:
Unlike dynamically indexing an array of sampler uniforms, the layer number is a normal texture coordinate. GLSL 3.30 can therefore select it at runtime without an eight-way switch, allowing the driver to emit a native array-texture fetch on NVIDIA RTX and other supporting hardware.
The array is updated as a ring rather than shifted every frame. history_head identifies the physical layer containing logical history index zero; adding it preserves the oldest-to-newest shader contract while uploading only one array layer per frame.
All layers must have identical dimensions and internal formats. Cache frames already match the active framebuffer or viewport, so the texture cache naturally satisfies that requirement. Enable this representation with --texture-cache-array.
Legacy sampler declarations may remain in a shader while it is being migrated. GLSL compilers perform dead-code elimination from the fragment output, so an unused samp1–samp8 or textures[SIZE] declaration is removed from the linked program. It performs no texture fetch, consumes no texture unit in the linked shader, and allocates no texture storage by itself.
An optimized-out uniform has no active location:
OpenGL silently ignores a glUniform* call whose location is -1, so the engine can continue querying legacy names during the transition. Shaders can support both paths and be migrated one at a time:
The engine defines USE_HISTORY_TEXTURE_ARRAY as 0 or 1, so use #if rather than #ifdef. The inactive branch is removed at preprocessing time and adds no runtime branching. Mass conversion is optional; the repository utility is available when a clean, array-only shader library is desired:
| Uniform | Type | Description |
|---|---|---|
| value_alpha_r | float | Oscillating red color alpha |
| value_alpha_g | float | Oscillating green color alpha |
| value_alpha_b | float | Oscillating blue color alpha |
| alpha_r | float | Red color alpha (same as value_alpha_r) |
| alpha_g | float | Green color alpha (same as value_alpha_g) |
| alpha_b | float | Blue color alpha (same as value_alpha_b) |
| alpha_value | float | Current alpha value |
| index_value | float | Current shader index in the library |
| optx | vec4 | Option vector (0.5, 0.5, 0.5, 0.5) |
| random_var | vec4 | Random variable vector |
| restore_black | float | Restore black flag (0.0 or 1.0) |
| inc_value | vec4 | Incrementing value vector |
| inc_valuex | vec4 | Secondary incrementing value vector |
| Uniform | Type | Description |
|---|---|---|
| amp | float | Amplitude scaled by sensitivity |
| uamp | float | Raw untouched amplitude |
| iamp | float | Estimated dominant frequency (Hz) |
| amp_peak | float | Highest sample value in the buffer |
| amp_rms | float | Root mean square energy |
| amp_smooth | float | Exponentially smoothed amplitude |
| amp_low | float | Low-frequency energy (<300 Hz) |
| amp_mid | float | Mid-frequency energy (300–3000 Hz) |
| amp_high | float | High-frequency energy (>3000 Hz) |
| iSampleRate | float | Audio sample rate (44100.0) |
| spectrum | sampler1D | FFT frequency-magnitude spectrum (256 bins, GL_TEXTURE9) |
| spectrum0 | sampler1D | Current-frame alias of the live spectrum |
| spectrum_history | sampler1DArray | Runtime-sized FFT history array enabled by --enable-audio-buffers <N> |
| spectrum_history_head | int | Physical layer containing the newest history frame |
| spectrum_history_size | int | Allocated history-array layer count |
The spectrum uniform is a 1D texture (GL_R32F, 256 texels) holding the FFT magnitudes of the current audio frame. Texel coordinate x = 0.0 is the DC bin and x = 1.0 is the Nyquist frequency (22 050 Hz at 44 100 Hz sample rate). Sampling uses GL_LINEAR filtering and GL_CLAMP_TO_EDGE wrapping. Example usage:
History age is a dynamic array coordinate, so one sampler binding supports any requested depth up to GL_MAX_ARRAY_TEXTURE_LAYERS:
Here, frequency is in [0,1] and age is 0 for the newest frame, 1 for the preceding frame, and so on. spectrum0 remains a current-frame sampler1D compatibility alias, but the engine no longer binds separate spectrum1...spectrumN uniforms. Those names belong to the legacy shader interface used by older ACMX2 releases; there is no current command-line mode that restores them. Convert those legacy lookups with:
| Uniform | Type | Description |
|---|---|---|
| slider1 | float | MIDI CC knob value mapped to 0.0–1.0 |
| slider2 | float | MIDI CC knob value mapped to 0.0–1.0 |
| slider3 | float | MIDI CC knob value mapped to 0.0–1.0 |
| slider4 | float | MIDI CC knob value mapped to 0.0–1.0 |
These uniforms are optional. If a shader does not declare them they are silently skipped. Map physical MIDI knobs to Slider 1–4 in the midi-map tool, then use uniform float slider1; etc. in your GLSL code to receive live 0.0–1.0 values.
Route application audio into ACMX2 for reactive effects:
Then select Virtual_Audio.monitor as the audio input device.
See the full tables in the main acidcam-gpu README.