### Install Build Dependencies on Ubuntu Source: https://github.com/vcvrack/rack/wiki/Extended-build-instructions Installs required development libraries for building Rack on Ubuntu 17.10. ```bash sudo apt-get install libx11-dev libxrandr-dev libxinerama-dev libxcursor-dev libgl1-mesa-dev libglu1-mesa-dev zlib1g-dev libasound2-dev libgtk2.0-dev curl ``` -------------------------------- ### Initialize Git Submodules Source: https://github.com/vcvrack/rack/wiki/Extended-build-instructions Command used to initialize and update submodules, which may trigger environment errors on certain Windows setups. ```bash git submodule update --init --recursive ``` -------------------------------- ### Create a VCV Rack Module Class Source: https://context7.com/vcvrack/rack/llms.txt Implement audio processing and module configuration by overriding the `process()` method and using `config*()` methods. Ensure necessary headers are included. ```cpp #include "rack.hpp" struct MyVCO : Module { enum ParamIds { FREQ_PARAM, FM_PARAM, NUM_PARAMS }; enum InputIds { FM_INPUT, NUM_INPUTS }; enum OutputIds { SINE_OUTPUT, SAW_OUTPUT, NUM_OUTPUTS }; enum LightIds { BLINK_LIGHT, NUM_LIGHTS }; float phase = 0.f; MyVCO() { // Configure module with params, inputs, outputs, lights config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); // Configure parameter with range, default, name, unit configParam(FREQ_PARAM, -4.f, 4.f, 0.f, "Frequency", " Hz", 2.f, dsp::FREQ_C4); configParam(FM_PARAM, -1.f, 1.f, 0.f, "FM Amount", "%", 0.f, 100.f); // Configure inputs and outputs with names configInput(FM_INPUT, "Frequency modulation"); configOutput(SINE_OUTPUT, "Sine wave"); configOutput(SAW_OUTPUT, "Sawtooth wave"); // Configure bypass routing (input -> output when bypassed) configBypass(FM_INPUT, SINE_OUTPUT); } void process(const ProcessArgs& args) override { // Read parameter and input values float freq = dsp::FREQ_C4 * std::pow(2.f, params[FREQ_PARAM].getValue()); float fm = inputs[FM_INPUT].getVoltage() * params[FM_PARAM].getValue(); freq *= std::pow(2.f, fm); // Advance phase phase += freq * args.sampleTime; if (phase >= 1.f) phase -= 1.f; // Generate outputs outputs[SINE_OUTPUT].setVoltage(5.f * std::sin(2.f * M_PI * phase)); outputs[SAW_OUTPUT].setVoltage(10.f * phase - 5.f); // Set light brightness lights[BLINK_LIGHT].setBrightness(phase); } }; ``` -------------------------------- ### Initialize and Register Plugin Models Source: https://context7.com/vcvrack/rack/llms.txt Implement the init() callback to register your plugin and its models with unique slugs. This function is called when Rack loads your plugin. ```cpp // Global plugin instance pointer Plugin* pluginInstance; void init(Plugin* p) { pluginInstance = p; // Register models with unique slugs p->addModel(createModel("MyVCO")); p->addModel(createModel("MyFilter")); p->addModel(createModel("MyMixer")); } // Optional: Called before plugin is unloaded void destroy() { // Cleanup resources } // Optional: Save plugin-wide settings json_t* settingsToJson() { json_t* rootJ = json_object(); json_object_set_new(rootJ, "defaultTheme", json_integer(0)); return rootJ; } // Optional: Load plugin-wide settings void settingsFromJson(json_t* rootJ) { json_t* themeJ = json_object_get(rootJ, "defaultTheme"); if (themeJ) defaultTheme = json_integer_value(themeJ); } ``` -------------------------------- ### Create a VCV Rack Module Widget Source: https://context7.com/vcvrack/rack/llms.txt Manage the visual representation of your module using `ModuleWidget`. Helper functions are available to add UI components like knobs, ports, and lights. Custom context menu items can also be added. ```cpp struct MyVCOWidget : ModuleWidget { MyVCOWidget(MyVCO* module) { setModule(module); // Set panel from SVG (supports light/dark themes) setPanel(createPanel( asset::plugin(pluginInstance, "res/MyVCO.svg"), asset::plugin(pluginInstance, "res/MyVCO-dark.svg") )); // Add screws addChild(createWidget(Vec(RACK_GRID_WIDTH, 0))); addChild(createWidget(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); // Add knobs (centered at position) addParam(createParamCentered(mm2px(Vec(15.24, 30.0)), module, MyVCO::FREQ_PARAM)); addParam(createParamCentered(mm2px(Vec(15.24, 50.0)), module, MyVCO::FM_PARAM)); // Add input/output ports addInput(createInputCentered(mm2px(Vec(15.24, 70.0)), module, MyVCO::FM_INPUT)); addOutput(createOutputCentered(mm2px(Vec(10.0, 100.0)), module, MyVCO::SINE_OUTPUT)); addOutput(createOutputCentered(mm2px(Vec(20.0, 100.0)), module, MyVCO::SAW_OUTPUT)); // Add LED light addChild(createLightCentered>(mm2px(Vec(15.24, 15.0)), module, MyVCO::BLINK_LIGHT)); } // Add custom context menu items void appendContextMenu(Menu* menu) override { MyVCO* module = getModule(); menu->addChild(new MenuSeparator); menu->addChild(createMenuItem("Reset Phase", "", [=]() { module->phase = 0.f; })); } }; ``` -------------------------------- ### Add UI Switches and Buttons Source: https://context7.com/vcvrack/rack/llms.txt Use these helper functions to register various switch and button types within a module's constructor. ```cpp // Toggle switches addParam(createParamCentered(pos, module, PARAM_ID)); // 2-position addParam(createParamCentered(pos, module, PARAM_ID)); // 3-position addParam(createParamCentered(pos, module, PARAM_ID)); // 3-position // Momentary buttons addParam(createParamCentered(pos, module, PARAM_ID)); addParam(createParamCentered(pos, module, PARAM_ID)); addParam(createParamCentered(pos, module, PARAM_ID)); addParam(createParamCentered(pos, module, PARAM_ID)); // Latching button addParam(createParamCentered(pos, module, PARAM_ID)); // Button with LED addParam(createLightParamCentered>>( pos, module, PARAM_ID, LIGHT_ID)); // Bezel button with LED addParam(createLightParamCentered>( pos, module, PARAM_ID, LIGHT_ID)); ``` -------------------------------- ### Handle Polyphonic Cable Input and Output Source: https://context7.com/vcvrack/rack/llms.txt Use getChannels() to determine input polyphony and setChannels() to set output polyphony. The process() function iterates through each channel for processing. ```cpp void process(const ProcessArgs& args) override { // Get number of input channels (0 if disconnected) int channels = inputs[AUDIO_INPUT].getChannels(); // If disconnected, still process 1 channel if (channels == 0) channels = 1; // Set output polyphony to match input outputs[AUDIO_OUTPUT].setChannels(channels); // Process each channel for (int c = 0; c < channels; c++) { // getPolyVoltage returns channel 0 voltage if input is monophonic float in = inputs[AUDIO_INPUT].getPolyVoltage(c); // getNormalVoltage returns default if disconnected float cv = inputs[CV_INPUT].getNormalVoltage(5.f, c); float out = processChannel(in, cv); outputs[AUDIO_OUTPUT].setVoltage(out, c); } } ``` -------------------------------- ### Plugin Registration API Source: https://context7.com/vcvrack/rack/llms.txt Methods for registering plugins and models during the initialization phase of VCV Rack. ```APIDOC ## Plugin Registration ### Description Register your plugin and models in the `init()` callback function. This is called when Rack loads your plugin. ### Methods - **init(Plugin* p)**: Called when the plugin is loaded. Use `p->addModel()` to register modules. - **destroy()**: Optional cleanup method called before the plugin is unloaded. - **settingsToJson()**: Optional method to serialize plugin-wide settings to JSON. - **settingsFromJson(json_t* rootJ)**: Optional method to load plugin-wide settings from JSON. ``` -------------------------------- ### Implement Ring Buffers Source: https://context7.com/vcvrack/rack/llms.txt Provides lock-free storage for audio delay lines. Ensure buffer sizes are defined as constants and bounds are checked before reading or writing. ```cpp struct DelayModule : Module { static const size_t BUFFER_SIZE = 48000; // 1 second at 48kHz dsp::RingBuffer buffer; dsp::DoubleRingBuffer smoothBuffer; void process(const ProcessArgs& args) override { float in = inputs[AUDIO_INPUT].getVoltage(); // Simple delay using RingBuffer if (!buffer.full()) { buffer.push(in); } float delayTime = params[TIME_PARAM].getValue(); size_t delaySamples = delayTime * args.sampleRate; delaySamples = std::min(delaySamples, buffer.size()); // Read delayed sample float out = 0.f; if (buffer.size() >= delaySamples) { // Access buffer.data directly for reading size_t readIndex = (buffer.end - delaySamples) % BUFFER_SIZE; out = buffer.data[readIndex]; } outputs[AUDIO_OUTPUT].setVoltage(out); } }; ``` -------------------------------- ### Component Library: Available Knobs Source: https://context7.com/vcvrack/rack/llms.txt Add various knob components to your module using the createParamCentered function. Options include standard round knobs, snap knobs, Davies 1900h style, Rogan style, trimpots, and sliders. ```cpp // Standard round knobs (small to huge) addParam(createParamCentered(pos, module, PARAM_ID)); addParam(createParamCentered(pos, module, PARAM_ID)); addParam(createParamCentered(pos, module, PARAM_ID)); addParam(createParamCentered(pos, module, PARAM_ID)); addParam(createParamCentered(pos, module, PARAM_ID)); // Snap knob (for discrete values) addParam(createParamCentered(pos, module, PARAM_ID)); // Davies 1900h style knobs addParam(createParamCentered(pos, module, PARAM_ID)); addParam(createParamCentered(pos, module, PARAM_ID)); addParam(createParamCentered(pos, module, PARAM_ID)); addParam(createParamCentered(pos, module, PARAM_ID)); // Rogan style knobs (various sizes and colors) addParam(createParamCentered(pos, module, PARAM_ID)); addParam(createParamCentered(pos, module, PARAM_ID)); addParam(createParamCentered(pos, module, PARAM_ID)); // Trimpots addParam(createParamCentered(pos, module, PARAM_ID)); // Sliders addParam(createParamCentered(pos, module, PARAM_ID)); addParam(createParamCentered(pos, module, PARAM_ID)); ``` -------------------------------- ### Build Rack with Plugin Manager Source: https://github.com/vcvrack/rack/wiki/Extended-build-instructions Enables the plugin manager during the build process. Use with caution as it may overwrite development files. ```bash make RELEASE=1 ``` -------------------------------- ### Component Library: Available Ports Source: https://context7.com/vcvrack/rack/llms.txt Add input and output ports to your module using createInputCentered and createOutputCentered. Available port styles include standard jacks, dark variants, auto-themed, and other specific styles like PJ3410 and CL1362. ```cpp // Standard jack ports addInput(createInputCentered(pos, module, INPUT_ID)); addOutput(createOutputCentered(pos, module, OUTPUT_ID)); // Dark variant addInput(createInputCentered(pos, module, INPUT_ID)); // Auto-themed (switches with dark mode) addInput(createInputCentered(pos, module, INPUT_ID)); // Other port styles addInput(createInputCentered(pos, module, INPUT_ID)); addInput(createInputCentered(pos, module, INPUT_ID)); ``` -------------------------------- ### Rebuild All Plugins Source: https://github.com/vcvrack/rack/wiki/Extended-build-instructions Compiles all plugins in the Rack directory, utilizing parallel processing based on available CPU cores. ```bash make allplugins -j$(nproc) ``` -------------------------------- ### Create Context Menus Source: https://context7.com/vcvrack/rack/llms.txt Implement appendContextMenu to add custom menu items, checkboxes, and submenus to a module's right-click menu. ```cpp void appendContextMenu(Menu* menu) override { MyModule* module = getModule(); menu->addChild(new MenuSeparator); // Simple menu item with action menu->addChild(createMenuItem("Reset", "Ctrl+R", [=]() { module->reset(); })); // Checkbox menu item menu->addChild(createBoolMenuItem("Enable Feature", "", [=]() { return module->featureEnabled; }, [=](bool enabled) { module->featureEnabled = enabled; } )); // Submenu with indexed options menu->addChild(createIndexSubmenuItem("Mode", {"Normal", "Inverted", "Bipolar"}, [=]() { return module->mode; }, [=](int mode) { module->mode = mode; } )); // Custom submenu menu->addChild(createSubmenuItem("Advanced", "", [=](Menu* menu) { menu->addChild(createMenuItem("Option A", "", [=]() { /* action */ })); menu->addChild(createMenuItem("Option B", "", [=]() { /* action */ })); } )); // Easy bool pointer binding menu->addChild(createBoolPtrMenuItem("Smooth Output", "", &module->smooth)); } ``` -------------------------------- ### Add Module Lights Source: https://context7.com/vcvrack/rack/llms.txt Register simple or multi-color lights using the addChild method. ```cpp // Simple colored lights (various sizes) addChild(createLightCentered>(pos, module, LIGHT_ID)); addChild(createLightCentered>(pos, module, LIGHT_ID)); addChild(createLightCentered>(pos, module, LIGHT_ID)); // Multi-color lights (use consecutive light IDs) addChild(createLightCentered>(pos, module, LIGHT_ID)); addChild(createLightCentered>(pos, module, LIGHT_ID)); ``` -------------------------------- ### Process Polyphonic Audio with SIMD Optimization Source: https://context7.com/vcvrack/rack/llms.txt For SIMD-optimized processing, use getPolyVoltageSimd and setVoltageSimd to process multiple channels (typically 4) at once. Ensure channels are handled correctly, defaulting to 1 if disconnected. ```cpp void processSIMD(const ProcessArgs& args) { int channels = std::max(1, inputs[AUDIO_INPUT].getChannels()); outputs[AUDIO_OUTPUT].setChannels(channels); // Process 4 channels at a time using SIMD for (int c = 0; c < channels; c += 4) { simd::float_4 in = inputs[AUDIO_INPUT].getPolyVoltageSimd(c); simd::float_4 gain = params[GAIN_PARAM].getValue(); simd::float_4 out = in * gain; outputs[AUDIO_OUTPUT].setVoltageSimd(out, c); } } ``` -------------------------------- ### Implement VU Metering Source: https://context7.com/vcvrack/rack/llms.txt Displays signal levels using peak or RMS modes. The updateLights method should be called less frequently than the main process loop to save CPU. ```cpp struct MeterModule : Module { dsp::VuMeter2 vuMeter; MeterModule() { config(0, 1, 0, 12); // 12 lights for meter vuMeter.mode = dsp::VuMeter2::PEAK; // or RMS vuMeter.lambda = 30.f; // Smoothing speed } void process(const ProcessArgs& args) override { float signal = inputs[AUDIO_INPUT].getVoltage() / 5.f; // Normalize to ~1.0 vuMeter.process(args.sampleTime, signal); } // Call this less frequently (e.g., every 512 samples) void updateLights() { // 12 LEDs with 3dB increments from -33dB to 0dB for (int i = 0; i < 12; i++) { float dbMin = -3.f * (12 - i); float dbMax = -3.f * (11 - i); float brightness = vuMeter.getBrightness(dbMin, dbMax); lights[METER_LIGHT + i].setBrightness(brightness); } } }; ``` -------------------------------- ### Implement Triggers and Gates Source: https://context7.com/vcvrack/rack/llms.txt Utilities for detecting signal edges, generating pulses, and managing timing. Schmitt triggers provide hysteresis to prevent noise-induced re-triggering. ```cpp struct TriggerModule : Module { dsp::SchmittTrigger trigger; dsp::BooleanTrigger buttonTrigger; dsp::PulseGenerator pulse; dsp::ClockDivider divider; dsp::Timer timer; TriggerModule() { config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); divider.setDivision(4); // Divide by 4 } void process(const ProcessArgs& args) override { // Schmitt Trigger - detect rising edge with hysteresis // Default thresholds: low=0, high=1 if (trigger.process(inputs[TRIG_INPUT].getVoltage(), 0.1f, 2.f)) { // Trigger detected! Start a 1ms pulse pulse.trigger(1e-3f); } // Boolean Trigger - detect button press bool buttonPressed = params[BUTTON_PARAM].getValue() > 0.f; if (buttonTrigger.process(buttonPressed)) { // Button just pressed } // Pulse Generator - output pulse bool pulseHigh = pulse.process(args.sampleTime); outputs[PULSE_OUTPUT].setVoltage(pulseHigh ? 10.f : 0.f); // Clock Divider - runs every N calls if (divider.process()) { // This runs every 4th sample // Useful for reducing CPU on expensive operations } // Timer - accumulate time float elapsed = timer.process(args.sampleTime); if (elapsed > 1.f) { timer.reset(); // One second has passed } } }; ``` -------------------------------- ### Implement Inter-Module Communication Source: https://context7.com/vcvrack/rack/llms.txt Use the expander system to pass data between adjacent modules by defining a message structure and managing buffers. ```cpp struct ExpanderMessage { float voltage; bool gate; }; struct MainModule : Module { MainModule() { config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); // Allocate message buffers for right expander rightExpander.producerMessage = new ExpanderMessage; rightExpander.consumerMessage = new ExpanderMessage; } ~MainModule() { delete static_cast(rightExpander.producerMessage); delete static_cast(rightExpander.consumerMessage); } void process(const ProcessArgs& args) override { // Check if expander module is connected and is the correct type if (rightExpander.module && rightExpander.module->model == modelExpanderModule) { // Write to producer message (will become consumer on next frame) ExpanderMessage* msg = static_cast(rightExpander.producerMessage); msg->voltage = outputs[AUDIO_OUTPUT].getVoltage(); msg->gate = outputs[GATE_OUTPUT].getVoltage() > 0.f; // Request message flip at end of timestep rightExpander.requestMessageFlip(); } } }; struct ExpanderModule : Module { void process(const ProcessArgs& args) override { // Read from left module's expander if (leftExpander.module && leftExpander.module->model == modelMainModule) { // Read consumer message (producer from main module's perspective) ExpanderMessage* msg = static_cast( leftExpander.module->rightExpander.consumerMessage); float voltage = msg->voltage; bool gate = msg->gate; // Process expanded signals... } } }; ``` -------------------------------- ### Persist module state with JSON Source: https://context7.com/vcvrack/rack/llms.txt Override dataToJson and dataFromJson to serialize and deserialize module data. Use onSave to handle external file persistence if necessary. ```cpp struct StatefulModule : Module { std::string samplePath; int mode = 0; std::vector waveform; json_t* dataToJson() override { json_t* rootJ = json_object(); // Save string json_object_set_new(rootJ, "samplePath", json_string(samplePath.c_str())); // Save integer json_object_set_new(rootJ, "mode", json_integer(mode)); // Save array json_t* waveformJ = json_array(); for (float sample : waveform) { json_array_append_new(waveformJ, json_real(sample)); } json_object_set_new(rootJ, "waveform", waveformJ); return rootJ; } void dataFromJson(json_t* rootJ) override { // Load string json_t* pathJ = json_object_get(rootJ, "samplePath"); if (pathJ) samplePath = json_string_value(pathJ); // Load integer json_t* modeJ = json_object_get(rootJ, "mode"); if (modeJ) mode = json_integer_value(modeJ); // Load array json_t* waveformJ = json_object_get(rootJ, "waveform"); if (waveformJ) { waveform.clear(); size_t i; json_t* sampleJ; json_array_foreach(waveformJ, i, sampleJ) { waveform.push_back(json_real_value(sampleJ)); } } } // Called when user saves patch - ensure files are written void onSave(const SaveEvent& e) override { // Save any patch storage files here } }; ``` -------------------------------- ### Implement a Biquad Filter Source: https://context7.com/vcvrack/rack/llms.txt Utilize the dsp::BiquadFilter class for standard filter types. Set filter parameters like cutoff frequency, Q factor, and gain. Recalculate filter coefficients using filter.reset() when the sample rate changes. ```cpp #include "rack.hpp" struct MyFilter : Module { dsp::BiquadFilter filter; void process(const ProcessArgs& args) override { float cutoff = params[CUTOFF_PARAM].getValue(); // 0 to 1 float resonance = params[RES_PARAM].getValue(); // 0.5 to 10 // Set filter parameters // f: normalized frequency (cutoff / sampleRate), must be < 0.5 // Q: resonance/quality factor // V: gain (for shelf/peak filters) filter.setParameters( dsp::BiquadFilter::LOWPASS, cutoff * 0.49f, // Keep below Nyquist resonance, 1.f // Gain (unused for lowpass) ); float in = inputs[AUDIO_INPUT].getVoltage(); float out = filter.process(in); outputs[AUDIO_OUTPUT].setVoltage(out); } void onSampleRateChange(const SampleRateChangeEvent& e) override { // Recalculate filter coefficients when sample rate changes filter.reset(); } }; // Available filter types: // LOWPASS_1POLE, HIGHPASS_1POLE - Simple 1-pole filters // LOWPASS, HIGHPASS - 2-pole resonant filters // LOWSHELF, HIGHSHELF - Shelving EQ // BANDPASS - Band-pass filter // PEAK - Parametric EQ peak // NOTCH - Notch/band-reject filter ``` -------------------------------- ### Port Polyphony API Source: https://context7.com/vcvrack/rack/llms.txt Methods for handling polyphonic audio signals within VCV Rack modules. ```APIDOC ## Port Polyphony Handling ### Description Ports support up to 16 polyphonic channels. Use these methods to manage channel counts and voltage processing. ### Methods - **getChannels()**: Returns the number of input channels. - **setChannels(int channels)**: Sets the output polyphony. - **getPolyVoltage(int channel)**: Returns voltage for a specific channel. - **getNormalVoltage(float default, int channel)**: Returns default voltage if the port is disconnected. - **setVoltage(float voltage, int channel)**: Sets the output voltage for a specific channel. - **getPolyVoltageSimd(int channel)**: Returns SIMD-optimized voltage for 4 channels at once. - **setVoltageSimd(T voltage, int channel)**: Sets SIMD-optimized output voltage for 4 channels at once. ``` -------------------------------- ### Implement RC Filters and Slew Limiters Source: https://context7.com/vcvrack/rack/llms.txt Use these components to smooth control signals and manage rate-of-change. Ensure sample rate and time are passed correctly from the process arguments. ```cpp struct SmoothModule : Module { dsp::RCFilter rcFilter; dsp::SlewLimiter slew; dsp::ExponentialFilter expFilter; void process(const ProcessArgs& args) override { float in = inputs[CV_INPUT].getVoltage(); // RC Filter - simple lowpass // setCutoffFreq takes ratio of cutoff to sample rate rcFilter.setCutoffFreq(100.f / args.sampleRate); rcFilter.process(in); outputs[RC_OUTPUT].setVoltage(rcFilter.lowpass()); // Also available: rcFilter.highpass() // Slew Limiter - limits rate of change slew.setRiseFall(10.f, 10.f); // 10 V/s rise and fall float slewOut = slew.process(args.sampleTime, in); outputs[SLEW_OUTPUT].setVoltage(slewOut); // Exponential Filter - smooth with time constant expFilter.setTau(0.01f); // 10ms time constant float expOut = expFilter.process(args.sampleTime, in); outputs[EXP_OUTPUT].setVoltage(expOut); } }; ``` -------------------------------- ### SIMD Optimized Processing with float_4 Source: https://context7.com/vcvrack/rack/llms.txt Utilize simd::float_4 and SSE instructions for vectorized math operations, processing 4 channels simultaneously for significant performance gains. Available SIMD functions include math, rounding, comparison, and utility operations. ```cpp #include "rack.hpp" using simd::float_4; struct SIMDModule : Module { void process(const ProcessArgs& args) override { int channels = std::max(1, inputs[AUDIO_INPUT].getChannels()); outputs[AUDIO_OUTPUT].setChannels(channels); // Process 4 channels at once for (int c = 0; c < channels; c += 4) { // Load 4 channels float_4 in = inputs[AUDIO_INPUT].getPolyVoltageSimd(c); float_4 freq = params[FREQ_PARAM].getValue(); // SIMD math functions float_4 phase = simd::fmod(in * freq, 1.f); float_4 sine = simd::sin(phase * 2.f * M_PI); float_4 clamped = simd::clamp(sine, -1.f, 1.f); // Conditional per-element float_4 sign = simd::sgn(in); float_4 result = simd::ifelse(in > 0.f, sine, clamped); // Store 4 channels outputs[AUDIO_OUTPUT].setVoltageSimd(result * 5.f, c); } } }; // Available SIMD functions: // Math: sin, cos, tan, atan, atan2, exp, log, log10, log2, pow, sqrt, rsqrt // Rounding: floor, ceil, round, trunc, fmod // Comparison: fmin, fmax, clamp // Utility: abs, fabs, sgn, ifelse, rescale, crossfade ``` -------------------------------- ### Fix MinGW envsubst Error Source: https://github.com/vcvrack/rack/wiki/Extended-build-instructions Workaround for a bug in the bundled envsubst.exe within MSYS2 MinGW 64-bit shell. ```bash mv /mingw64/bin/envsubst.exe /mingw64/bin/envsubst.exe.old ``` ```bash pacman -S gettext ``` -------------------------------- ### Batch Update Git Plugins Source: https://github.com/vcvrack/rack/wiki/Extended-build-instructions Updates all plugins in the directory by iterating through subdirectories and performing a git pull. ```bash for d in *;do cd "$d";git pull;cd ..;done ``` -------------------------------- ### Sample Rate Conversion with Speex Resampler Source: https://context7.com/vcvrack/rack/llms.txt Use dsp::SampleRateConverter, dsp::Decimator, and dsp::Upsampler for efficient audio resampling. Upsample for anti-aliased processing before applying effects and downsample back to the original rate. ```cpp struct OversampledModule : Module { static const int OVERSAMPLE = 4; dsp::SampleRateConverter<1> src; dsp::Decimator decimator; dsp::Upsampler upsampler; void process(const ProcessArgs& args) override { float in = inputs[AUDIO_INPUT].getVoltage(); // Upsample for anti-aliased processing float upsampled[OVERSAMPLE]; upsampler.process(in, upsampled); // Process at higher sample rate (e.g., for waveshaping) for (int i = 0; i < OVERSAMPLE; i++) { upsampled[i] = std::tanh(upsampled[i] * 0.5f) * 2.f; } // Downsample back to original rate float out = decimator.process(upsampled); outputs[AUDIO_OUTPUT].setVoltage(out); } }; ``` -------------------------------- ### Biquad Filter API Source: https://context7.com/vcvrack/rack/llms.txt DSP utility for implementing various filter types including lowpass, highpass, and shelving filters. ```APIDOC ## Biquad Filter ### Description The `dsp::BiquadFilter` provides standard filter types with configurable cutoff, Q factor, and gain. ### Methods - **setParameters(Type type, float f, float Q, float V)**: Configures the filter. `f` is normalized frequency (cutoff / sampleRate). - **process(float in)**: Processes a single sample through the filter. - **reset()**: Resets filter coefficients. ### Filter Types - LOWPASS_1POLE, HIGHPASS_1POLE - LOWPASS, HIGHPASS - LOWSHELF, HIGHSHELF - BANDPASS - PEAK - NOTCH ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.