Hi, I’m a new entry in the JUCE world and audio programming in general and I encountered a problem in one of my first projects.
I’m porting a rather simple onset detector, from another framework and I’m developing a demo application to understand interaction with JUCE.
The AudioProcessor of my demo app owns a OnsetDetector object, initializes it an provides audio blocks that will be buffered and analysed.
When the object detects the beginning of a note (onset) it has to communicate this event in an async fashion. For this I implemented a OnsetDetector::Listener class similarly to Button::Listener which contains a pure virtual callback function:
virtual void onsetDetected (OnsetDetector *) = 0;
OnsetDetector keeps a ListenerList (same as Button) and, when the onset is detected, it uses the ListenerList::call method:
listeners.call([this] (Listener& l) { l.onsetDetected (this); });
(Button uses callChecked instead, however I still have to understand what a BailoutChecker is, maybe I’m spinning too many plates at this point)
Now, for my demo the OnsetDetector Object is owned by the AudioProcessor and I would like to change color of a Component in the Editor when the onset is detected. I’ve read about AbstractFifo and updating regularly the Editor to pull parameter values from the Processor but it seems overkill for my purpose right now. It also seems inappropriate for an async event like this one.
I tried using only the listener in 2 progressive steps:
- Implementing the
onsetDetected()method and registering the listener in the Processor works fine but I obviously cannot access editor elements. Logging shows that it works. - Leaving the
OnsetDetectorpublic in the Processor, implementingonsetDetected()in the Editor and registering the Editor as listener to the detector only works partially:
The callback method in the editor receives the call, it lights up a virual light bulb (change color of a Rectangle) for 100ms and than it switches it off (I call repaint twice: on turn on phase and turnoff). It works but it keeps violating an assertion in juce_Component.cpp(r:1839):
JUCE_ASSERT_MESSAGE_MANAGER_IS_LOCKED
Explained 2 lines before as: If component methods are being called from threads other than the message thread, you’ll need to use a MessageManagerLock object to make sure it’s thread-safe.
- Does this mean that the callback is called by the audio thread? (if so, this is unacceptable right?)
- Is there a chance of making it work correctly (maybe with a MessageManagerLock) or am I going for a bad paradigm by using listeners like this?
- Why does the “lightbulb” still work, even if the app is failing what seems like a crucial assertion?
I hope I haven’t bored you to death, this is as concise as I can get since the introduction to the environment feels like relevant context.
I’m hoping that you can answer so this bit can be less of vodoo programming for me, thank you.
