Smithery Logo
MCPsSkillsDocsPricing
Login
Smithery Logo

Accelerating the Agent Economy

Resources

DocumentationPrivacy PolicySystem Status

Company

PricingAboutBlog

Connect

© 2026 Smithery. All rights reserved.

    yebot

    daw-compatibility-guide

    yebot/daw-compatibility-guide
    Coding
    3
    1 installs

    About

    SKILL.md

    Install

    Install via Skills CLI

    or add to your agent
    • Claude Code
      Claude Code
    • Codex
      Codex
    • OpenClaw
      OpenClaw
    • Cursor
      Cursor
    • Amp
      Amp
    • GitHub Copilot
      GitHub Copilot
    • Gemini CLI
      Gemini CLI
    • Kilo Code
      Kilo Code
    • Junie
      Junie
    • Replit
      Replit
    • Windsurf
      Windsurf
    • Cline
      Cline
    • Continue
      Continue
    • OpenCode
      OpenCode
    • OpenHands
      OpenHands
    • Roo Code
      Roo Code
    • Augment
      Augment
    • Goose
      Goose
    • Trae
      Trae
    • Zencoder
      Zencoder
    • Antigravity
      Antigravity
    ├─
    ├─
    └─

    About

    DAW-specific quirks, known issues, and workarounds for Logic Pro, Ableton Live, Pro Tools, Cubase, Reaper, FL Studio, Bitwig with format-specific requirements (AU/VST3/AAX)...

    SKILL.md

    DAW Compatibility Guide

    Comprehensive guide to DAW-specific quirks, known issues, and workarounds for ensuring your JUCE plugin works correctly across all major digital audio workstations.

    Overview

    Each DAW has unique behaviors, assumptions, and quirks that can affect plugin operation. This guide documents common issues and proven solutions for Logic Pro, Ableton Live, Pro Tools, Cubase, Reaper, FL Studio, Bitwig, and others.

    When to Use This Guide

    • Debugging DAW-specific issues reported by users
    • Testing plugin compatibility across multiple DAWs
    • Implementing DAW-specific workarounds
    • Understanding format-specific requirements (AU, VST3, AAX)
    • Planning cross-DAW automation and state compatibility

    Logic Pro (macOS - AU/VST3)

    Overview

    • Formats: Audio Unit (preferred), VST3
    • Strictness: Very strict AU validation (auval)
    • Automation: Sample-accurate, works well
    • Unique Features: AU-specific validation, side-chain routing

    AU Validation Requirements

    Issue: Logic requires plugins to pass auval validation.

    Requirements:

    // PluginProcessor.h - Ensure these are set correctly
    #define JucePlugin_Name                 "MyPlugin"
    #define JucePlugin_Desc                 "Description"
    #define JucePlugin_Manufacturer         "YourCompany"
    #define JucePlugin_ManufacturerCode     'Manu'  // 4 characters, unique!
    #define JucePlugin_PluginCode           'Plug'  // 4 characters, unique!
    #define JucePlugin_AUMainType           'aufx'  // Effect
    // OR 'aumu' for MIDI effect
    // OR 'aumf' for instrument
    #define JucePlugin_AUSubType            JucePlugin_PluginCode
    #define JucePlugin_AUExportPrefix       MyPluginAU
    #define JucePlugin_AUExportPrefixQuoted "MyPluginAU"
    

    Validation Command:

    auval -v aufx Plug Manu
    

    Common auval Failures:

    1. Failure: "FATAL ERROR: AudioUnitInitialize failed"

      // Cause: prepareToPlay() throws exception or asserts
      void prepareToPlay(double sampleRate, int samplesPerBlock) override {
          // ❌ Don't do this:
          jassert(sampleRate == 44100.0);  // Fails in auval!
      
          // ✅ Do this:
          if (sampleRate < 8000.0 || sampleRate > 192000.0)
              return;  // Handle gracefully
      }
      
    2. Failure: "FATAL ERROR: Property size is incorrect"

      // Cause: Incorrect I/O configuration
      bool isBusesLayoutSupported(const BusesLayout& layouts) const override {
          // Be permissive for auval
          if (layouts.getMainOutputChannelSet().isDisabled())
              return false;  // Must have output
      
          return true;  // Allow any channel config for auval
      }
      
    3. Failure: "FATAL ERROR: Render called with null buffer"

      void processBlock(AudioBuffer<float>& buffer, MidiBuffer&) override {
          // auval sometimes passes zero-size buffers
          if (buffer.getNumSamples() == 0)
              return;  // Early exit for empty blocks
      }
      

    Run auval successfully:

    # Full validation (takes ~5 minutes)
    auval -v aufx Plug Manu
    
    # Strict validation (recommended)
    auval -strict -v aufx Plug Manu
    
    # If it passes, you'll see:
    # * * * * * * * * * * * * * * * * * * * * * * * * * * * *
    # AU VALIDATION SUCCEEDED
    # * * * * * * * * * * * * * * * * * * * * * * * * * * * *
    

    Logic-Specific Issues

    Issue: Automation writes incorrectly or doesn't play back

    Cause: Parameter smoothing interfering with Logic's automation.

    Solution:

    // Don't smooth parameters that Logic is automating
    void processBlock(AudioBuffer<float>& buffer, MidiBuffer&) override {
        // ❌ Always smoothing
        float cutoff = smoother.getNextValue(*cutoffParam);
    
        // ✅ Only smooth if parameter changed recently
        if (cutoffParam->load() != lastCutoffValue) {
            smoother.setTargetValue(*cutoffParam);
            lastCutoffValue = *cutoffParam;
        }
        float cutoff = smoother.getNextValue();
    }
    

    Issue: Offline bounce doesn't match realtime

    Cause: Tempo/time info assumptions.

    Solution:

    void processBlock(AudioBuffer<float>& buffer, MidiBuffer&) override {
        // ✅ Always query tempo from host
        auto playHead = getPlayHead();
        if (playHead != nullptr) {
            juce::AudioPlayHead::CurrentPositionInfo posInfo;
            playHead->getCurrentPosition(posInfo);
    
            float bpm = posInfo.bpm;
            double ppqPosition = posInfo.ppqPosition;
            bool isPlaying = posInfo.isPlaying;
    
            // Use this info, don't cache tempo!
        }
    }
    

    Issue: Side-chain input doesn't work (AU)

    Cause: AU side-chain requires special bus configuration.

    Solution:

    MyPluginProcessor::MyPluginProcessor()
        : AudioProcessor(BusesProperties()
            .withInput ("Input",  AudioChannelSet::stereo(), true)
            .withOutput("Output", AudioChannelSet::stereo(), true)
            .withInput ("Sidechain", AudioChannelSet::stereo(), false))  // Optional
    {
    }
    
    void processBlock(AudioBuffer<float>& buffer, MidiBuffer&) override {
        // Get sidechain bus
        auto mainInputOutput = getBusBuffer(buffer, true, 0);
        auto sidechain = getBusBuffer(buffer, true, 1);  // Second input bus
    
        if (!sidechain.getNumChannels())
            return;  // No sidechain connected
    
        // Process with sidechain...
    }
    

    Ableton Live (VST3/AU)

    Overview

    • Formats: VST3 (Windows/macOS), AU (macOS)
    • Automation: Works well, supports breakpoint automation
    • Unique Features: Max for Live integration, Device Racks, Macro mapping

    Live-Specific Issues

    Issue: Plugin doesn't appear in Live's browser

    Cause: VST3 not in correct folder or not scanned.

    Solution:

    # macOS VST3 path
    ~/Library/Audio/Plug-Ins/VST3/MyPlugin.vst3
    
    # Windows VST3 path
    C:\Program Files\Common Files\VST3\MyPlugin.vst3
    
    # Rescan in Live:
    # Preferences → Plug-Ins → "Rescan" button
    

    Issue: Undo/Redo causes parameter jumps

    Cause: Live's undo system conflicts with plugin parameter changes.

    Solution:

    // Mark parameter changes as gestures to prevent undo conflicts
    void parameterValueChanged(int parameterIndex, float newValue) override {
        // Notify host of parameter change
        auto* param = getParameters()[parameterIndex];
        param->beginChangeGesture();
        param->setValueNotifyingHost(newValue);
        param->endChangeGesture();
    }
    

    Issue: Plugin latency not compensated correctly

    Cause: Plugin doesn't report latency.

    Solution:

    int getLatencySamples() const override {
        return latencyInSamples;  // Report actual latency
    }
    
    void prepareToPlay(double sampleRate, int samplesPerBlock) override {
        // Update latency if it changes
        latencyInSamples = calculateLatency();
        setLatencySamples(latencyInSamples);
    }
    

    Issue: Freeze/Flatten produces incorrect audio

    Cause: Non-deterministic behavior or offline/realtime mismatch.

    Solution:

    • Ensure processBlock is deterministic
    • Reset all state in prepareToPlay()
    • Don't use system time or random numbers without seeding
    void prepareToPlay(double sampleRate, int samplesPerBlock) override {
        // ✅ Reset all state for deterministic processing
        filter.reset();
        envelope.reset();
        rng.setSeed(12345);  // Seeded random for determinism
    }
    

    Issue: Macro mapping doesn't work

    Cause: Parameter range or normalization issues.

    Solution:

    // Ensure parameters use normalized 0-1 range internally
    auto param = std::make_unique<AudioParameterFloat>(
        "cutoff",
        "Cutoff",
        NormalisableRange<float>(20.0f, 20000.0f, 0.01f, 0.3f),  // Skew
        1000.0f
    );
    
    // Live's macros expect normalized parameter access to work
    

    Pro Tools (AAX)

    Overview

    • Format: AAX (PACE/iLok signed)
    • Strictness: Very strict, requires code signing
    • Automation: Sample-accurate, very robust
    • Unique Features: AudioSuite (offline processing), HDX DSP

    AAX Requirements

    Issue: Plugin doesn't load - "damaged" or "unsigned" error

    Cause: AAX requires PACE signing with iLok account.

    Solution:

    1. Sign up for PACE iLok developer account
    2. Get Developer ID certificate from PACE
    3. Sign AAX bundle:
      wraptool sign --verbose \
          --account <your-ilok-account> \
          --password <password> \
          --wcguid <your-wcguid> \
          --dsig1-compat \
          --in MyPlugin.aaxplugin \
          --out MyPlugin.aaxplugin
      

    AAX Manifest:

    // Required in CMakeLists.txt
    juce_add_plugin(MyPlugin
        COMPANY_NAME "YourCompany"
        PLUGIN_MANUFACTURER_CODE Manu
        PLUGIN_CODE Plug
        FORMATS AAX
        AAX_IDENTIFIER com.yourcompany.myplugin
    )
    

    Pro Tools-Specific Issues

    Issue: Plugin doesn't appear in correct category

    Cause: AAX category not set.

    Solution:

    #define JucePlugin_AAXCategory AAX_ePlugInCategory_EQ  // For EQ
    // Other categories:
    // AAX_ePlugInCategory_Dynamics
    // AAX_ePlugInCategory_PitchShift
    // AAX_ePlugInCategory_Reverb
    // AAX_ePlugInCategory_Delay
    // AAX_ePlugInCategory_Modulation
    // AAX_ePlugInCategory_Harmonic
    // AAX_ePlugInCategory_SWGenerators
    

    Issue: AudioSuite (offline processing) produces different results

    Cause: AudioSuite processes entire selection at once.

    Solution:

    void processBlock(AudioBuffer<float>& buffer, MidiBuffer&) override {
        // AudioSuite may pass very large buffers (entire selection)
        // Must handle variable buffer sizes gracefully
    
        int numSamples = buffer.getNumSamples();
        // Process in chunks if needed for stability
        const int chunkSize = 512;
    
        for (int start = 0; start < numSamples; start += chunkSize) {
            int count = std::min(chunkSize, numSamples - start);
            AudioBuffer<float> chunk(buffer.getArrayOfWritePointers(),
                                      buffer.getNumChannels(),
                                      start, count);
            processChunk(chunk);
        }
    }
    

    Issue: Session doesn't restore plugin state correctly

    Cause: State serialization issue specific to AAX.

    Solution:

    void getStateInformation(MemoryBlock& destData) override {
        // AAX is very strict about state format
        // Use XML or ValueTree (both work reliably)
        auto state = apvts.copyState();
        std::unique_ptr<XmlElement> xml(state.createXml());
    
        // Ensure proper encoding
        copyXmlToBinary(*xml, destData);
    }
    

    Issue: Delay compensation not working

    Cause: Pro Tools requires explicit latency reporting.

    Solution:

    // Report latency during initialization
    void prepareToPlay(double sampleRate, int samplesPerBlock) override {
        int latency = calculatePluginLatency();
        setLatencySamples(latency);
    }
    
    // Update if latency changes (rare)
    void parameterChanged(const String& paramID, float newValue) override {
        if (paramID == "quality" && qualityAffectsLatency) {
            int newLatency = calculatePluginLatency();
            setLatencySamples(newLatency);
        }
    }
    

    FL Studio (Windows - VST3)

    Overview

    • Format: VST3 (VST2 deprecated)
    • Automation: Works but has quirks
    • Unique Features: Piano Roll, native wrapper

    FL Studio-Specific Issues

    Issue: Plugin state lost on crash

    Cause: FL Studio caches state, but doesn't always flush on crash.

    Solution:

    // Save state more frequently
    void processBlock(AudioBuffer<float>& buffer, MidiBuffer&) override {
        static int counter = 0;
        if (++counter % 44100 == 0) {  // Every ~1 second @ 44.1kHz
            updateHostDisplay();  // Hint to FL to save state
        }
    }
    

    Issue: Multiple instances interfere with each other

    Cause: Shared static data or singletons.

    Solution:

    // ❌ Don't use static/global state
    static float globalGain = 1.0f;  // BAD! Shared across instances
    
    // ✅ Instance variables only
    class MyPluginProcessor : public AudioProcessor {
        float instanceGain = 1.0f;  // Each instance has its own
    };
    

    Issue: Wrapper shows generic UI instead of custom UI

    Cause: FL's wrapper can create generic UI if custom editor fails.

    Solution:

    AudioProcessorEditor* createEditor() override {
        // Ensure editor constructor doesn't throw
        try {
            return new MyPluginEditor(*this);
        } catch (...) {
            jassertfalse;  // Debug: why did it fail?
            return nullptr;  // FL will show generic UI
        }
    }
    

    Issue: Preset browser doesn't show presets

    Cause: FL looks for presets in specific format/location.

    Solution:

    # FL Studio preset path (Windows)
    Documents\Image-Line\FL Studio\Presets\Plugin database\Generators\[Your Plugin]
    
    # Save presets as .fst (FL's format)
    # Or implement VST3 preset format (.vstpreset)
    

    Cubase/Nuendo (VST3)

    Overview

    • Format: VST3 (Steinberg's own format)
    • Automation: Excellent, sample-accurate
    • Unique Features: Expression maps, VST3 spec reference implementation

    Cubase-Specific Issues

    Issue: Plugin doesn't load or shows "failed to load" error

    Cause: VST3 bundle structure incorrect.

    Solution:

    # Correct VST3 bundle structure:
    MyPlugin.vst3/
      Contents/
        Resources/  # Optional: icons, documentation
        x86_64-win/
          MyPlugin.vst3  # Windows 64-bit
        x86-win/
          MyPlugin.vst3  # Windows 32-bit (optional)
        MacOS/
          MyPlugin  # macOS universal binary (arm64 + x86_64)
    
    # Verify bundle with:
    pluginval --strictness-level 10 MyPlugin.vst3
    

    Issue: Automation doesn't write or playback correctly

    Cause: Parameter flags not set correctly.

    Solution:

    auto param = std::make_unique<AudioParameterFloat>(
        "cutoff",
        "Cutoff",
        NormalisableRange<float>(20.0f, 20000.0f),
        1000.0f
    );
    
    // Ensure automation is enabled
    // (JUCE does this by default, but verify)
    

    Issue: Side-chain routing doesn't work

    Cause: VST3 side-chain requires specific bus configuration.

    Solution:

    MyPluginProcessor()
        : AudioProcessor(BusesProperties()
            .withInput("Input", AudioChannelSet::stereo(), true)
            .withOutput("Output", AudioChannelSet::stereo(), true)
            .withInput("Sidechain", AudioChannelSet::stereo(), false))  // Aux input
    {
    }
    
    bool isBusesLayoutSupported(const BusesLayout& layouts) const override {
        // Main input/output must match
        if (layouts.getMainInputChannelSet() != layouts.getMainOutputChannelSet())
            return false;
    
        // Sidechain is optional
        return true;
    }
    

    Issue: Expression maps don't trigger MIDI correctly

    Cause: Plugin doesn't handle MIDI correctly.

    Solution:

    void processBlock(AudioBuffer<float>& buffer, MidiBuffer& midi) override {
        // Ensure MIDI messages are processed at correct sample positions
        for (const auto metadata : midi) {
            auto message = metadata.getMessage();
            int samplePosition = metadata.samplePosition;
    
            // Process MIDI at exact sample position
            handleMidiMessage(message, samplePosition);
        }
    }
    

    Reaper (VST3/AU)

    Overview

    • Formats: VST3 (all platforms), AU (macOS)
    • Automation: Highly flexible, supports both VST3 and AU
    • Unique Features: Extremely permissive, good for testing

    Reaper-Specific Issues

    Issue: Plugin loads but doesn't process audio

    Cause: Reaper allows unusual configurations that other DAWs don't.

    Solution:

    bool isBusesLayoutSupported(const BusesLayout& layouts) const override {
        // Reaper may try unusual layouts - be permissive
        auto mainIn = layouts.getMainInputChannelSet();
        auto mainOut = layouts.getMainOutputChannelSet();
    
        // Require at least mono or stereo
        if (mainIn == AudioChannelSet::disabled() ||
            mainOut == AudioChannelSet::disabled())
            return false;
    
        // Allow flexible channel counts
        return true;
    }
    

    Issue: Offline render (Export) doesn't match realtime

    Cause: Reaper's offline render can use different buffer sizes.

    Solution:

    void prepareToPlay(double sampleRate, int samplesPerBlock) override {
        // Don't assume fixed buffer size - handle variable sizes
        maxBufferSize = samplesPerBlock;
    
        // Allocate for worst case
        workBuffer.setSize(2, samplesPerBlock);
    }
    
    void processBlock(AudioBuffer<float>& buffer, MidiBuffer&) override {
        // Handle any buffer size up to max
        jassert(buffer.getNumSamples() <= maxBufferSize);
    }
    

    Issue: Plugin delay compensation incorrect

    Cause: Reaper is very strict about latency reporting.

    Solution:

    void prepareToPlay(double sampleRate, int samplesPerBlock) override {
        // Calculate and report latency accurately
        int latency = fftSize / 2;  // Example: FFT-based effect
        setLatencySamples(latency);
    }
    
    // If latency changes dynamically
    void setFFTSize(int newSize) {
        fftSize = newSize;
        setLatencySamples(fftSize / 2);
        // Reaper will adjust compensation
    }
    

    Bitwig Studio (VST3)

    Overview

    • Format: VST3
    • Automation: Excellent, supports modulation
    • Unique Features: Modulation system, Grid, Operator devices

    Bitwig-Specific Issues

    Issue: Bitwig's modulators don't affect plugin parameters

    Cause: Parameter update rate too slow.

    Solution:

    // Bitwig can modulate at audio rate - ensure parameters respond
    void processBlock(AudioBuffer<float>& buffer, MidiBuffer&) override {
        auto cutoffParam = apvts.getRawParameterValue("cutoff");
    
        // Read parameter every sample if Bitwig is modulating
        for (int i = 0; i < buffer.getNumSamples(); ++i) {
            float cutoff = cutoffParam->load();  // Audio-rate read
            // Process sample with current value
        }
    }
    
    // Or use parameter smoothing:
    smoother.reset(sampleRate, 0.005);  // 5ms smoothing
    for (int i = 0; i < buffer.getNumSamples(); ++i) {
        float cutoff = smoother.getNextValue(cutoffParam->load());
    }
    

    Issue: Plugin conflicts with Bitwig's Grid devices

    Cause: Unusual buffer configurations.

    Solution:

    // Be very permissive with channel layouts for Bitwig
    bool isBusesLayoutSupported(const BusesLayout& layouts) const override {
        // Bitwig may use unusual channel counts for CV/modulation
        return !layouts.getMainOutputChannelSet().isDisabled();
    }
    

    Studio One (VST3)

    Overview

    • Format: VST3
    • Automation: Works well
    • Unique Features: Scratch pads, arranger track

    Studio One-Specific Issues

    Issue: Plugin doesn't save/recall with song

    Cause: State information issue.

    Solution:

    void getStateInformation(MemoryBlock& destData) override {
        // Studio One is strict about state consistency
        auto state = apvts.copyState();
        std::unique_ptr<XmlElement> xml(state.createXml());
        copyXmlToBinary(*xml, destData);
    }
    
    void setStateInformation(const void* data, int sizeInBytes) override {
        // Validate before loading
        std::unique_ptr<XmlElement> xml(getXmlFromBinary(data, sizeInBytes));
        if (!xml || !xml->hasTagName(apvts.state.getType()))
            return;  // Invalid state, don't crash
    
        apvts.replaceState(ValueTree::fromXml(*xml));
    }
    

    Common Cross-DAW Issues

    Issue: Plugin crashes on load in specific DAW

    Debugging Steps:

    1. Check Console.app (macOS) or Event Viewer (Windows) for crash logs
    2. Run plugin in debugger attached to DAW
    3. Use Address Sanitizer to detect memory errors:
      cmake -B build -DCMAKE_CXX_FLAGS="-fsanitize=address"
      
    4. Verify thread safety - most crashes are threading issues

    Common Causes:

    • Accessing UI from audio thread (or vice versa)
    • Static initialization order issues
    • Missing null checks
    • Buffer overruns

    Solution Template:

    void processBlock(AudioBuffer<float>& buffer, MidiBuffer&) override {
        // ✅ Validate inputs
        if (buffer.getNumSamples() == 0)
            return;
    
        if (buffer.getNumChannels() == 0)
            return;
    
        // ✅ Null checks for all pointers
        if (auto* param = cutoffParam.load())
            float cutoff = param->load();
    
        // ✅ Bounds checking
        jassert(buffer.getNumSamples() <= maxBufferSize);
    }
    

    Issue: Automation sounds different in different DAWs

    Cause: Different automation smoothing or timing.

    Solution:

    // Implement your own parameter smoothing
    class ParameterSmoother {
    public:
        void reset(double sampleRate, double timeSeconds = 0.05) {
            rampLength = static_cast<int>(sampleRate * timeSeconds);
            currentValue = targetValue = 0.0f;
            counter = 0;
        }
    
        void setTarget(float target) {
            targetValue = target;
            counter = rampLength;
        }
    
        float getNext() {
            if (counter > 0) {
                currentValue += (targetValue - currentValue) / counter;
                --counter;
            } else {
                currentValue = targetValue;
            }
            return currentValue;
        }
    
    private:
        float currentValue = 0.0f, targetValue = 0.0f;
        int rampLength = 0, counter = 0;
    };
    
    // Use consistently across all DAWs
    void processBlock(AudioBuffer<float>& buffer, MidiBuffer&) override {
        smoother.setTarget(cutoffParam->load());
    
        for (int i = 0; i < buffer.getNumSamples(); ++i) {
            float smoothedCutoff = smoother.getNext();
            // Use smoothedCutoff for consistent automation across DAWs
        }
    }
    

    Issue: State doesn't transfer between DAW sessions

    Cause: Incompatible serialization formats.

    Solution:

    // Use JUCE's ValueTree for reliable cross-DAW state
    void getStateInformation(MemoryBlock& destData) override {
        ValueTree state("PluginState");
        state.setProperty("version", 1, nullptr);
    
        // Add parameter state
        state.appendChild(apvts.copyState(), nullptr);
    
        // Add custom state
        ValueTree customState("CustomState");
        customState.setProperty("uiWidth", uiWidth, nullptr);
        state.appendChild(customState, nullptr);
    
        // Serialize to XML (most compatible)
        std::unique_ptr<XmlElement> xml(state.createXml());
        copyXmlToBinary(*xml, destData);
    }
    
    void setStateInformation(const void* data, int sizeInBytes) override {
        std::unique_ptr<XmlElement> xml(getXmlFromBinary(data, sizeInBytes));
        if (!xml || !xml->hasTagName("PluginState"))
            return;
    
        ValueTree state = ValueTree::fromXml(*xml);
    
        // Check version for compatibility
        int version = state.getProperty("version", 0);
        if (version > 1)
            return;  // Future version, don't load
    
        // Restore state...
    }
    

    Format-Specific Considerations

    AU (Audio Unit) - macOS Only

    Advantages:

    • Native to macOS
    • Best integration with Logic Pro, GarageBand
    • Sample-accurate automation

    Disadvantages:

    • Strict validation (auval)
    • macOS-only
    • Limited to Apple ecosystem

    Best Practices:

    // Always pass auval before shipping
    // Test on multiple macOS versions (10.13+)
    // Verify on both Intel and Apple Silicon
    

    VST3 - Cross-Platform

    Advantages:

    • Cross-platform (macOS, Windows, Linux)
    • Open specification
    • Supported by most DAWs

    Disadvantages:

    • Some DAWs still prefer AU (macOS)
    • Complex specification
    • Side-chain setup can be tricky

    Best Practices:

    // Validate with pluginval at strictness level 10
    // Test side-chain routing thoroughly
    // Ensure bundle structure is correct
    

    AAX - Pro Tools Only

    Advantages:

    • Pro Tools integration
    • Professional studios standard

    Disadvantages:

    • Requires PACE/iLok signing ($$)
    • Pro Tools-only
    • Strict requirements

    Best Practices:

    # Always code-sign AAX bundles
    # Test AudioSuite mode separately
    # Verify delay compensation
    

    Testing Strategy for DAW Compatibility

    Minimum Test Matrix

    DAW Format Platform Priority
    Logic Pro AU, VST3 macOS High
    Ableton Live VST3 macOS, Windows High
    Pro Tools AAX macOS, Windows High
    Reaper VST3 macOS, Windows, Linux Medium
    FL Studio VST3 Windows Medium
    Cubase VST3 macOS, Windows Medium
    Bitwig VST3 macOS, Windows, Linux Low
    Studio One VST3 macOS, Windows Low

    Quick Compatibility Checklist

    For each DAW:

    • ✅ Plugin loads without errors
    • ✅ Audio processes correctly
    • ✅ Automation writes and plays back
    • ✅ State saves and restores
    • ✅ Offline render matches realtime
    • ✅ No crashes after 5 minutes of use

    Emergency Fixes for Specific DAWs

    If plugin works everywhere except Logic:

    # Run auval and fix reported issues
    auval -strict -v aufx Plug Manu
    
    # Common fix: handle zero-size buffers
    if (buffer.getNumSamples() == 0) return;
    

    If plugin works everywhere except FL Studio:

    // Check for shared static state
    // Ensure each instance is independent
    

    If plugin works everywhere except Pro Tools:

    // Verify AAX signing
    # Check certificate:
    codesign --display --verbose=4 MyPlugin.aaxplugin
    
    // Ensure AudioSuite handles large buffers
    

    Summary

    Key Takeaways:

    • Test on at least 3 major DAWs before release
    • Use automated validation tools (auval, pluginval)
    • Implement consistent parameter smoothing
    • Handle edge cases gracefully (zero-size buffers, unusual layouts)
    • Use standard state serialization (ValueTree → XML)
    • Report latency accurately for delay compensation
    • Be permissive with bus layouts for compatibility

    DAW-Specific Priorities:

    1. Logic Pro (macOS): Pass auval validation
    2. Ableton Live: Test Freeze/Flatten and undo/redo
    3. Pro Tools: Sign with PACE, test AudioSuite
    4. Reaper: Handle flexible configurations
    5. FL Studio: Avoid shared state between instances

    Related Resources

    • /run-daw-tests command - Automated DAW compatibility testing
    • TESTING_STRATEGY.md - Comprehensive testing approach
    • RELEASE_CHECKLIST.md - Pre-release DAW validation
    • JUCE Forum - Search for DAW-specific issues

    Remember: Every DAW is different, but following best practices (realtime safety, robust state management, proper latency reporting) will prevent 90% of compatibility issues. The remaining 10% require DAW-specific testing and workarounds documented here.

    Recommended Servers
    EasyWeek
    EasyWeek
    Microsoft Learn MCP
    Microsoft Learn MCP
    Excalidraw
    Excalidraw
    Repository
    yebot/rad-cc-plugins
    Files