| name | daw-compatibility-guide |
| description | 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). Use when troubleshooting DAW compatibility, fixing host-specific bugs, implementing DAW workarounds, passing auval validation, or debugging automation issues. |
| allowed-tools | Read, Grep, Glob |
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:
#define JucePlugin_Name "MyPlugin"
#define JucePlugin_Desc "Description"
#define JucePlugin_Manufacturer "YourCompany"
#define JucePlugin_ManufacturerCode 'Manu'
#define JucePlugin_PluginCode 'Plug'
#define JucePlugin_AUMainType 'aufx'
#define JucePlugin_AUSubType JucePlugin_PluginCode
#define JucePlugin_AUExportPrefix MyPluginAU
#define JucePlugin_AUExportPrefixQuoted "MyPluginAU"
Validation Command:
auval -v aufx Plug Manu
Common auval Failures:
-
Failure: "FATAL ERROR: AudioUnitInitialize failed"
void prepareToPlay(double sampleRate, int samplesPerBlock) override {
jassert(sampleRate == 44100.0);
if (sampleRate < 8000.0 || sampleRate > 192000.0)
return;
}
-
Failure: "FATAL ERROR: Property size is incorrect"
bool isBusesLayoutSupported(const BusesLayout& layouts) const override {
if (layouts.getMainOutputChannelSet().isDisabled())
return false;
return true;
}
-
Failure: "FATAL ERROR: Render called with null buffer"
void processBlock(AudioBuffer<float>& buffer, MidiBuffer&) override {
if (buffer.getNumSamples() == 0)
return;
}
Run auval successfully:
auval -v aufx Plug Manu
auval -strict -v aufx Plug Manu
Logic-Specific Issues
Issue: Automation writes incorrectly or doesn't play back
Cause: Parameter smoothing interfering with Logic's automation.
Solution:
void processBlock(AudioBuffer<float>& buffer, MidiBuffer&) override {
float cutoff = smoother.getNextValue(*cutoffParam);
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 {
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;
}
}
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))
{
}
void processBlock(AudioBuffer<float>& buffer, MidiBuffer&) override {
auto mainInputOutput = getBusBuffer(buffer, true, 0);
auto sidechain = getBusBuffer(buffer, true, 1);
if (!sidechain.getNumChannels())
return;
}
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:
~/Library/Audio/Plug-Ins/VST3/MyPlugin.vst3
C:\Program Files\Common Files\VST3\MyPlugin.vst3
Issue: Undo/Redo causes parameter jumps
Cause: Live's undo system conflicts with plugin parameter changes.
Solution:
void parameterValueChanged(int parameterIndex, float newValue) override {
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;
}
void prepareToPlay(double sampleRate, int samplesPerBlock) override {
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 {
filter.reset();
envelope.reset();
rng.setSeed(12345);
}
Issue: Macro mapping doesn't work
Cause: Parameter range or normalization issues.
Solution:
auto param = std::make_unique<AudioParameterFloat>(
"cutoff",
"Cutoff",
NormalisableRange<float>(20.0f, 20000.0f, 0.01f, 0.3f),
1000.0f
);
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:
- Sign up for PACE iLok developer account
- Get Developer ID certificate from PACE
- 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:
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
Issue: AudioSuite (offline processing) produces different results
Cause: AudioSuite processes entire selection at once.
Solution:
void processBlock(AudioBuffer<float>& buffer, MidiBuffer&) override {
int numSamples = buffer.getNumSamples();
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 {
auto state = apvts.copyState();
std::unique_ptr<XmlElement> xml(state.createXml());
copyXmlToBinary(*xml, destData);
}
Issue: Delay compensation not working
Cause: Pro Tools requires explicit latency reporting.
Solution:
void prepareToPlay(double sampleRate, int samplesPerBlock) override {
int latency = calculatePluginLatency();
setLatencySamples(latency);
}
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:
void processBlock(AudioBuffer<float>& buffer, MidiBuffer&) override {
static int counter = 0;
if (++counter % 44100 == 0) {
updateHostDisplay();
}
}
Issue: Multiple instances interfere with each other
Cause: Shared static data or singletons.
Solution:
static float globalGain = 1.0f;
class MyPluginProcessor : public AudioProcessor {
float instanceGain = 1.0f;
};
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 {
try {
return new MyPluginEditor(*this);
} catch (...) {
jassertfalse;
return nullptr;
}
}
Issue: Preset browser doesn't show presets
Cause: FL looks for presets in specific format/location.
Solution:
Documents\Image-Line\FL Studio\Presets\Plugin database\Generators\[Your Plugin]
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:
MyPlugin.vst3/
Contents/
Resources/
x86_64-win/
MyPlugin.vst3
x86-win/
MyPlugin.vst3
MacOS/
MyPlugin
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
);
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))
{
}
bool isBusesLayoutSupported(const BusesLayout& layouts) const override {
if (layouts.getMainInputChannelSet() != layouts.getMainOutputChannelSet())
return false;
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 {
for (const auto metadata : midi) {
auto message = metadata.getMessage();
int samplePosition = metadata.samplePosition;
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 {
auto mainIn = layouts.getMainInputChannelSet();
auto mainOut = layouts.getMainOutputChannelSet();
if (mainIn == AudioChannelSet::disabled() ||
mainOut == AudioChannelSet::disabled())
return false;
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 {
maxBufferSize = samplesPerBlock;
workBuffer.setSize(2, samplesPerBlock);
}
void processBlock(AudioBuffer<float>& buffer, MidiBuffer&) override {
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 {
int latency = fftSize / 2;
setLatencySamples(latency);
}
void setFFTSize(int newSize) {
fftSize = newSize;
setLatencySamples(fftSize / 2);
}
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:
void processBlock(AudioBuffer<float>& buffer, MidiBuffer&) override {
auto cutoffParam = apvts.getRawParameterValue("cutoff");
for (int i = 0; i < buffer.getNumSamples(); ++i) {
float cutoff = cutoffParam->load();
}
}
smoother.reset(sampleRate, 0.005);
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:
bool isBusesLayoutSupported(const BusesLayout& layouts) const override {
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 {
auto state = apvts.copyState();
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(apvts.state.getType()))
return;
apvts.replaceState(ValueTree::fromXml(*xml));
}
Common Cross-DAW Issues
Issue: Plugin crashes on load in specific DAW
Debugging Steps:
- Check Console.app (macOS) or Event Viewer (Windows) for crash logs
- Run plugin in debugger attached to DAW
- Use Address Sanitizer to detect memory errors:
cmake -B build -DCMAKE_CXX_FLAGS="-fsanitize=address"
- 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 {
if (buffer.getNumSamples() == 0)
return;
if (buffer.getNumChannels() == 0)
return;
if (auto* param = cutoffParam.load())
float cutoff = param->load();
jassert(buffer.getNumSamples() <= maxBufferSize);
}
Issue: Automation sounds different in different DAWs
Cause: Different automation smoothing or timing.
Solution:
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;
};
void processBlock(AudioBuffer<float>& buffer, MidiBuffer&) override {
smoother.setTarget(cutoffParam->load());
for (int i = 0; i < buffer.getNumSamples(); ++i) {
float smoothedCutoff = smoother.getNext();
}
}
Issue: State doesn't transfer between DAW sessions
Cause: Incompatible serialization formats.
Solution:
void getStateInformation(MemoryBlock& destData) override {
ValueTree state("PluginState");
state.setProperty("version", 1, nullptr);
state.appendChild(apvts.copyState(), nullptr);
ValueTree customState("CustomState");
customState.setProperty("uiWidth", uiWidth, nullptr);
state.appendChild(customState, nullptr);
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);
int version = state.getProperty("version", 0);
if (version > 1)
return;
}
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:
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:
AAX - Pro Tools Only
Advantages:
- Pro Tools integration
- Professional studios standard
Disadvantages:
- Requires PACE/iLok signing ($$)
- Pro Tools-only
- Strict requirements
Best Practices:
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:
auval -strict -v aufx Plug Manu
if (buffer.getNumSamples() == 0) return;
If plugin works everywhere except FL Studio:
If plugin works everywhere except Pro Tools:
# Check certificate:
codesign --display --verbose=4 MyPlugin.aaxplugin
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:
- Logic Pro (macOS): Pass
auval validation
- Ableton Live: Test Freeze/Flatten and undo/redo
- Pro Tools: Sign with PACE, test AudioSuite
- Reaper: Handle flexible configurations
- 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.