# plugin module ## Owned files - PluginProcessor.h, PluginProcessor.cpp ## Rules - Keep this the JUCE `AudioProcessor` boundary: APVTS, engine, RAVE, presets and state. - Declare the full parameter layout in `createParameterLayout()`. - Use `juce::ScopedNoDenormals` in `processBlock`. - Guard `getRawParameterValue` and `getParameter` results before dereferencing them. - Return silently on null or invalid state XML and invalid ValueTrees. - Use raw `new` only for JUCE-owned objects (`createEditor`, `createPluginFilter`). - Hold the engine control lock across preset and state changes; preserve parameter IDs and normalized values for saved-project compatibility. - Factory presets reset sound parameters before applying overrides, while preserving UI scale. - Save one copy of each custom state section. LFO shape arrays are stored as JSON text inside XML. - RAVE is an ordinary parameter that enables a render-time boost; it does not rewrite other parameters. ## IF-THEN - IF state XML is null or invalid THEN return without touching the APVTS. - IF a parameter is missing from a preset load THEN skip it with an `if (auto* param = ...)` guard. ## Examples ```cpp // BAD: dereferences a possibly null XML result auto xml = getXmlFromBinary (data, size); auto state = juce::ValueTree::fromXml (*xml); ``` ```cpp // GOOD: null guard, silent return std::unique_ptr xml (getXmlFromBinary (data, size)); if (xml == nullptr) return; juce::ValueTree state = juce::ValueTree::fromXml (*xml); if (! state.isValid()) return; ``` This file overrides /AGENTS.md where they conflict.