What’s the purpose of using postMessageToList and IncomingMessageCallback? To use the queue? Why?

void postMessageToList (const juce::MidiMessage& message, const juce::String& source)
        (new IncomingMessageCallback (this, message, source))->post();

MessageManager::MessageBase::post() adds the object to a queue[inherited by CallbackMessage]

The MessageManager class will eventually find this object in the queue and call the IncomingMessageCallback::messageCallback() function on the message thread. Once this function has been called, the IncomingMessageCallback object will be deleted.

class IncomingMessageCallback   : public juce::CallbackMessage
        IncomingMessageCallback (MainContentComponent* o, const juce::MidiMessage& m, const juce::String& s)
           : owner (o), message (m), source (s)

        void messageCallback() override
            if (owner != nullptr)
                owner->addMessageToList (message, source); //below

        Component::SafePointer<MainContentComponent> owner;
//automatically becomes null if the component is deleted. [must be component type]
        juce::MidiMessage message;
        juce::String source;


1 Like

Didn’t know this existed - thanks!
Looks like the purpose of this is to be able to do GUI updates after receiving a MIDI message from an external device - if you try to update the GUI off the back of receiving a MIDI message you won’t be on the message thread which is not allowed, so this will get you onto the message thread where you can deal with the update.

I’ve been doing this using postCommandMessage() but this looks much cleaner.

Isn’t MessageManager::callAsync() the preferred method these days?

you can’t pass parameters to that - this will actually get the MIDI message that you’re processing over to you.

You actually can, the callAsync takes a lambda, in which you can capture (by copy!) any parameter you need.

But creating the lambda is not realtime safe, because it allocates AFAIK.

1 Like

wasn’t aware of that - is that a more recent addition I take it? useful to know though

I typed to fast and just repeated stuff I read somewhere. A google search yielded, that a std::function does not necessarily allocate:

When assigning a lambda with significant captures to a std::function, it will do a dynamic memory allocation!

from: https://blog.demofox.org/2015/02/25/avoiding-the-performance-hazzards-of-stdfunction/

If someone has a more reliable source, if it is fine to call callAsync() from a realtime thread, that would be useful.

EDIT: found this thread here:

Result inconclusive unfortunately. Everybody has to find out, if it works for their use case or build some huge solution around it.

David did a very good talk in one of the audio programmer meetups about async updates on a real-time thread: https://www.youtube.com/watch?v=rYdAxs7w0Nk

1 Like

What do you mean "won’t be on the message thread "?

Just checked what MSVC seems to do:

// size in pointers of std::function and std::any (roughly 3 pointers larger than std::string when building debug)
constexpr int _Small_object_num_ptrs = 6 + 16 / sizeof(void*);

constexpr size_t _Space_size = (_Small_object_num_ptrs - 1) * sizeof(void*);

template <class _Impl> // determine whether _Impl must be dynamically allocated
_INLINE_VAR constexpr bool _Is_large = sizeof(_Impl) > _Space_size || alignof(_Impl) > alignof(max_align_t)
                                       || !_Impl::_Nothrow_move::value;

That would give 56 bytes for x64 and 36 bytes for x86 as the limits for small buffer optimization.

an application has a “main thread” - this is often referred to as the message thread as it has a message pump on it that delivers messages in an event driven system. you can create other threads for async processing - one is created to handle incoming MIDI messages when you open a MIDI port. messages coming in on these “worker threads” need to be handled by the message thread if they’re to do GUI updates (amongst other things).