Attention
This is the documentation stub to the upcoming TBD V2 release.
It is incomplete and subject to future changes.
TBD Events¶
In order to facilitate efficient communication between TBD components, without each component needing to make many assumptions about the other (loose coupling) as well as allowing multiple components to respond to changes of some firmware state, TBD provides an event system. Some of the core ideas of this event system are
no knowledge about the module emitting the event required (loose coupling)
events and event handlers are represented by simple functions
events are dispatched internally and over serial/network connections
internal event distribution is very efficient by linking event emission and handling at compile time (no queues and dynamic lookups required)
emitting and distributing incoming events through serial/network communication is handled with as little dynamic overhead as possible (through table lookups)
new event distribution channels like additional serial hardware can be easily added and require no config
Event Basics¶
Warning
The simple event dispatching mechanism is not intended for multi-threaded use cases. A non blocking thread safe distribution mechanism could be implemented in future versions of the TBD Sound Core library.
A good example for the use of an event can be found in the tbd_sound_registry module. This module allows the
dynamic switching between different sound plugins. Several parts of a TBD system need to listen to this event in order
to be informed about plugin switching:
web UIs
front panel software
the plugin presets manager
In order to allow these parts of the system to respond to such changes, tbd_sound_registry emits the
sound_processor_changed event whenever a sound plugin change occurs.
In order to to this an event is declared in the emitting module by declaring a simple function (with no implementation), where the function arguments are the event payload which is used to convey additional information about what just happened:
[[tbd::event]]
void sound_processor_changed(const uint_par& channels, const uint_par& new_plugin_id);
Event functions need to be marked with the [[tbd::event]] annotation and the function arguments have to be
reflectable. By default the event name (the name responders will use to identify an event) corresponds to the event
function name. If desired this can be changed by adding an event_name parameter to the annotation:
[[tbd_event(event_name="true_event_name")]]
Actually emitting this event is done by simply invoking the event function:
// ... some state changed
sound_processor_changed(some_channels, some_plugin_id);
// ... event has been dispatched at this point, but we do not know if all responders have processed it
An internal component (within the TBD audio core) that wants to listen for said event (like tbd_presets) simply
needs to implement a responder function for said event:
[[tbd::responder(event="sound_processor_changed")]]
Error respond_to_sound_processor_change(const uint_par& channels, const uint_par& new_plugin_id) {
// ... do something
return TBD_OK;
}
A responder needs to
be marked as a responder via the
[[tbd::responder(event_name="some_event")]]annotation.have the same argument signature as the event itself
return
voidortbd::error
Note
Neither event declarations nor responders need to be made public. In fact they don’t even need to reside in headers. This way no one can accidentally call the responder directly or emit the event from outside the owning component.