diff --git a/BREAKING-CHANGES.txt b/BREAKING-CHANGES.txt index 8c4f50a01e..846adb4a48 100644 --- a/BREAKING-CHANGES.txt +++ b/BREAKING-CHANGES.txt @@ -4,11 +4,33 @@ JUCE breaking changes Develop ======= +Change +------ +AudioProcessorValueTreeState::getRawParameterValue now returns a +std::atomic* instead of a float*. + +Possible Issues +--------------- +Existing code which explicitly mentions the type of the returned value, or +interacts with the dereferenced float in ways unsupported by the std::atomic +wrapper, will fail to compile. Certain evaluation-reordering compiler +optimisations may no longer be possible. + +Workaround +---------- +Update your code to deal with a std::atomic* instead of a float*. + +Rationale +--------- +Returning a std::atomic* allows the JUCE framework to have much stronger +guarantees about thread safety. + + Change ------ Removed a workaround from the ASIOAudioIODevice::getOutputLatencyInSamples() -and ASIOAudioIODevice::getInputLatencyInSamples() methods which was adding -an arbitrary amount to the reported latencies to compensate for dodgy, old +and ASIOAudioIODevice::getInputLatencyInSamples() methods which was adding an +arbitrary amount to the reported latencies to compensate for dodgy, old drivers. Possible Issues @@ -17,8 +39,8 @@ Code which relied on these altered values may now behave differently. Workaround ---------- -Update your code to deal with the new, correct values reported from the -drivers directly. +Update your code to deal with the new, correct values reported from the drivers +directly. Rationale --------- @@ -37,8 +59,8 @@ Possible Issues AudioProcessor subclasses which have overridden the default implementations of get/setProgramStateInformation (which simply call through to get/setStateInformation) may be unable to load previously saved state; state -previously saved via a call to getProgramStateInformation will be presented -to setStateInformation. +previously saved via a call to getProgramStateInformation will be presented to +setStateInformation. Workaround ---------- diff --git a/modules/juce_audio_processors/utilities/juce_AudioProcessorValueTreeState.cpp b/modules/juce_audio_processors/utilities/juce_AudioProcessorValueTreeState.cpp index ad36c5aa0d..cd0185c261 100644 --- a/modules/juce_audio_processors/utilities/juce_AudioProcessorValueTreeState.cpp +++ b/modules/juce_audio_processors/utilities/juce_AudioProcessorValueTreeState.cpp @@ -124,8 +124,8 @@ public: return parameter.getText (normalise (value), 0); } - float getDenormalisedValue() const { return unnormalisedValue; } - float& getRawDenormalisedValue() { return unnormalisedValue; } + float getDenormalisedValue() const { return unnormalisedValue; } + std::atomic& getRawDenormalisedValue() { return unnormalisedValue; } bool flushToTree (const Identifier& key, UndoManager* um) { @@ -139,12 +139,12 @@ public: if ((float) *valueProperty != unnormalisedValue) { ScopedValueSetter svs (ignoreParameterChangedCallbacks, true); - tree.setProperty (key, unnormalisedValue, um); + tree.setProperty (key, unnormalisedValue.load(), um); } } else { - tree.setProperty (key, unnormalisedValue, nullptr); + tree.setProperty (key, unnormalisedValue.load(), nullptr); } return true; @@ -188,7 +188,7 @@ private: RangedAudioParameter& parameter; ListenerList listeners; - float unnormalisedValue{}; + std::atomic unnormalisedValue{}; std::atomic needsUpdate { true }; bool listenersNeedCalling { true }, ignoreParameterChangedCallbacks { false }; }; @@ -355,7 +355,7 @@ RangedAudioParameter* AudioProcessorValueTreeState::getParameter (StringRef para return nullptr; } -float* AudioProcessorValueTreeState::getRawParameterValue (StringRef paramID) const noexcept +std::atomic* AudioProcessorValueTreeState::getRawParameterValue (StringRef paramID) const noexcept { if (auto* p = getParameterAdapter (paramID)) return &p->getRawDenormalisedValue(); @@ -791,7 +791,7 @@ struct ParameterAdapterTests : public UnitTest adapter.setDenormalisedValue (value); expectEquals (adapter.getDenormalisedValue(), value); - expectEquals (adapter.getRawDenormalisedValue(), value); + expectEquals (adapter.getRawDenormalisedValue().load(), value); }; test ({ -20, -10 }, -15); @@ -1044,7 +1044,7 @@ public: const auto value = 0.5f; param->setValueNotifyingHost (value); - expectEquals (*proc.state.getRawParameterValue (key), value); + expectEquals (proc.state.getRawParameterValue (key)->load(), value); } beginTest ("After adding an APVTS::Parameter, its value is the default value"); @@ -1062,7 +1062,7 @@ public: nullptr, nullptr)); - expectEquals (*proc.state.getRawParameterValue (key), value); + expectEquals (proc.state.getRawParameterValue (key)->load(), value); } beginTest ("Listeners receive notifications when parameters change"); @@ -1138,7 +1138,7 @@ public: value = newValue; expectEquals (param->getValue(), newValue); - expectEquals (*proc.state.getRawParameterValue (key), newValue); + expectEquals (proc.state.getRawParameterValue (key)->load(), newValue); } beginTest ("When the parameter value is changed, custom parameter values are updated"); @@ -1154,7 +1154,7 @@ public: value = newValue; expectEquals (paramPtr->getCurrentChoiceName(), choices[int (newValue)]); - expectEquals (*proc.state.getRawParameterValue (key), newValue); + expectEquals (proc.state.getRawParameterValue (key)->load(), newValue); } beginTest ("When the parameter value is changed, listeners are notified"); diff --git a/modules/juce_audio_processors/utilities/juce_AudioProcessorValueTreeState.h b/modules/juce_audio_processors/utilities/juce_AudioProcessorValueTreeState.h index f1ee8a434a..f06a70ba41 100644 --- a/modules/juce_audio_processors/utilities/juce_AudioProcessorValueTreeState.h +++ b/modules/juce_audio_processors/utilities/juce_AudioProcessorValueTreeState.h @@ -285,7 +285,7 @@ public: Note that calling this method from within AudioProcessorValueTreeState::Listener::parameterChanged() is not guaranteed to return an up-to-date value for the parameter. */ - float* getRawParameterValue (StringRef parameterID) const noexcept; + std::atomic* getRawParameterValue (StringRef parameterID) const noexcept; //============================================================================== /** A listener class that can be attached to an AudioProcessorValueTreeState.