I found that the app was calling the function to add the slider and the parameter multiple times, so I added a check to make sure it only runs one time and it seems to be past that error. I think it had to do with pointer ownership. However, the process still doesn’t complete, leaving me with a new error:
Here’s the callstack from an FL Studio call:
NoneApp.vst3!juce::ValueTree::setPropertyExcludingListener(juce::ValueTree::Listener * listenerToExclude, const juce::Identifier & name, const juce::var & newValue, juce::UndoManager * undoManager) Line 766 C++
NoneApp.vst3!juce::ValueTree::setProperty(const juce::Identifier & name, const juce::var & newValue, juce::UndoManager * undoManager) Line 760 C++
> NoneApp.vst3!juce::AudioProcessorValueTreeState::ParameterAdapter::flushToTree(const juce::Identifier & key, juce::UndoManager * um) Line 146 C++
NoneApp.vst3!juce::AudioProcessorValueTreeState::flushParameterValuesToValueTree() Line 473 C++
NoneApp.vst3!juce::AudioProcessorValueTreeState::timerCallback() Line 480 C++
NoneApp.vst3!juce::Timer::TimerThread::callTimers() Line 119 C++
NoneApp.vst3!juce::Timer::TimerThread::CallTimersMessage::messageCallback() Line 181 C++
NoneApp.vst3!juce::InternalMessageQueue::dispatchMessage(juce::MessageManager::MessageBase * message) Line 202 C++
NoneApp.vst3!juce::InternalMessageQueue::dispatchMessages() Line 240 C++
NoneApp.vst3!juce::InternalMessageQueue::messageWndProc(HWND__ * h, unsigned int message, unsigned __int64 wParam, __int64 lParam) Line 163 C++
user32.dll!UserCallWinProcCheckWow() Unknown
user32.dll!DispatchMessageWorker() Unknown
FLEngine_x64.dll!000000000282fae8() Unknown
It crashes on this line:
jassert (object != nullptr); // Trying to add a property to a null ValueTree will fail!
Clearly, at this point the ValueTree is null. Two calls up from that, I see the tree as:
- tree {object={referencedObject=0x0000000000000000 <NULL> } listeners={listeners={values={elements={data=0x0000000000000000 {...} } ...} } } } juce::ValueTree
- object {referencedObject=0x0000000000000000 <NULL> } juce::ReferenceCountedObjectPtr<juce::ValueTree::SharedObject>
- referencedObject 0x0000000000000000 <NULL> juce::ValueTree::SharedObject *
+ juce::ReferenceCountedObject <struct at NULL> juce::ReferenceCountedObject
+ type {name={text={data=??? } } } const juce::Identifier
+ properties {values={values={elements={data=??? } numAllocated=??? numUsed=??? } } } juce::NamedValueSet
+ children {values={elements={data=??? } numAllocated=??? numUsed=??? } } juce::ReferenceCountedArray<juce::ValueTree::SharedObject,juce::DummyCriticalSection>
+ valueTreesWithListeners {data={values={elements={data=??? } numAllocated=??? numUsed=??? } } } juce::SortedSet<juce::ValueTree *,juce::DummyCriticalSection>
parent <Unable to read memory>
leakDetector574 {...} juce::LeakedObjectDetector<juce::ValueTree::SharedObject>
- listeners {listeners={values={elements={data=0x0000000000000000 {???} } numAllocated=0 numUsed=0 } } } juce::ListenerList<juce::ValueTree::Listener,juce::Array<juce::ValueTree::Listener *,juce::DummyCriticalSection,0>>
- listeners {values={elements={data=0x0000000000000000 {???} } numAllocated=0 numUsed=0 } } juce::Array<juce::ValueTree::Listener *,juce::DummyCriticalSection,0>
- values {elements={data=0x0000000000000000 {???} } numAllocated=0 numUsed=0 } juce::ArrayBase<juce::ValueTree::Listener *,juce::DummyCriticalSection>
juce::DummyCriticalSection {...} juce::DummyCriticalSection
+ elements {data=0x0000000000000000 {???} } juce::HeapBlock<juce::ValueTree::Listener *,0>
numAllocated 0 int
numUsed 0 int
I construct the value tree in PluginProcessor.h/cpp
, first with the variable:
juce::AudioProcessorValueTreeState processorValueTreeState;
and then with the initialization in the initilization list:
processorValueTreeState(*this, nullptr)
I send a pointer to that value to a function, which runs:
auto* rangedAudioParameter =
static_cast<juce::RangedAudioParameter*>(*state.second->clientParameter);
std::unique_ptr<juce::RangedAudioParameter> parameterPtr =
std::unique_ptr<juce::RangedAudioParameter>(rangedAudioParameter);
processorValueTreeState->createAndAddParameter(move(parameterPtr));
The parameter pointer is raw until casting it to a unique_ptr here, so I don’t see ownership issues. I have an overloaded cast for clientParameter
that acts like a factory and returns the parameter object.
The parameter when added to the ValueTree seems to be well-formed as well, and looks like:
- parameterPtr unique_ptr {notifyAppCommand=void <lambda>(float newValue){__this=0x00000000013b4e10 {currentValue=1.00000000 defaultValue=1.00000000 ...} } ...} std::unique_ptr<juce::RangedAudioParameter,std::default_delete<juce::RangedAudioParameter>>
- [ptr] 0x000000000c826190 {notifyAppCommand=void <lambda>(float newValue){__this=0x00000000013b4e10 {currentValue=1.00000000 defaultValue=1.00000000 ...} } ...} juce::RangedAudioParameter * {none::ParameterFloat}
- [none::ParameterFloat] {notifyAppCommand=void <lambda>(float newValue){__this=0x00000000013b4e10 {currentValue=1.00000000 defaultValue=1.00000000 ...} } ...} none::ParameterFloat
+ juce::AudioParameterFloat {range={start=0.00999999978 end=30.0000000 interval=0.00000000 ...} value=1.00000000 defaultValue=1.00000000 ...} juce::AudioParameterFloat
+ notifyAppCommand void <lambda>(float newValue){__this=0x00000000013b4e10 {currentValue=1.00000000 defaultValue=1.00000000 ...} } std::function<void __cdecl(float)>
minValue 0.00999999978 const float
maxValue 30.0000000 const float
defaultValue 1.00000000 const float
currentValue 1.00000000 float
+ normalisableRange {start=0.00999999978 end=30.0000000 interval=0.00000000 ...} const juce::NormalisableRange<float>
+ parameterId "FrequencyModSpeed" std::string
- juce::AudioProcessorParameterWithID {paramID={text={data=0x000000000c8237f0 "FrequencyModSpeed" } } name={text={data=0x000000000c823320 "FrequencyModSpeed" } } ...} juce::AudioProcessorParameterWithID
+ juce::AudioProcessorParameter {processor=0x0000000000000000 <NULL> parameterIndex=-1 listenerLock={lock=0x000000000c8261a4 <Invalid characters in string.> } ...} juce::AudioProcessorParameter
+ paramID {text={data=0x000000000c8237f0 "FrequencyModSpeed" } } const juce::String
+ name {text={data=0x000000000c823320 "FrequencyModSpeed" } } const juce::String
+ label {text={data=0x00007ff98d04a118 "" } } const juce::String
category genericParameter (0) const juce::AudioProcessorParameter::Category
leakDetector67 {...} juce::LeakedObjectDetector<juce::AudioProcessorParameterWithID>
+ [deleter] default_delete std::_Compressed_pair<std::default_delete<juce::RangedAudioParameter>,juce::RangedAudioParameter *,1>
+ [Raw View] {_Mypair=default_delete } std::unique_ptr<juce::RangedAudioParameter,std::default_delete<juce::RangedAudioParameter>>