Processing¶
This guide explains how to add a custom Audio Processing component with MimiCore inside MSDK, providing your users with "Mimified" audio.
Architecture Overview¶
The Processing APIs can be divided into four main components:
- Processing Controller - The root entry point and context for Processing API access.
- Processing Session - The provider of access to processing Processing Parameters when activated.
- Processing Parameters - Individual parameter objects that provides state, data and mutation.
- Processing Applicators - Responsible for applying the Processing Parameter values to external systems.
The following section describes the components in the Processing APIs.
Figure: Processing System Components
ProcessingController¶
Overview¶
The ProcessingController is a controller owned and initialized by MimiCore.
It is responsible for the activation and deactivation of Processing Sessions, and therefore can be used as the source of truth for the active ProcessingSession instance.
Responsibilities¶
- Centralized location for accessing Processing APIs.
- Owner of active Processing Session
- Provides activation and deactivation of Processing Session.
Activation¶
As the ProcessingController owns the ProcessingSession status; it is the location where processing can be "activated" or "deactivated".
Once there is an activated ProcessingSession, it is possible to access the MimiProcessingParameters and configure them appropriately for use.
Lifecycle¶
The ProcessingController is responsible for handling the ProcessingSession lifecycle in terms of activation and deactivation.
- Activating a session will set the
activeSessionproperty on theProcessingControllerallowing the session to be easily referenced. - Only a single session can be activated at one time.
- Deactivation clears the
activeSessionproperty. It does not directly affect the applied Mimi processing. - Activating and deactivating a session triggers
MimiObservernotifications to observers.
ProcessingSession¶
Provides access to the Processing Parameters.
Overview¶
As described in the previous section, a ProcessingSession is owned by a ProcessingController.
The ProcessingSession itself owns the MimiProcessingParameters, and therefore is the gateway to parameter access.
Responsibilities¶
- Owner of all Processing Parameters, providing access to;
isEnabled,intensityandpreset. - Exposes the current data source configuration for the
presetparameter. - Provides the ability for processing to be "interrupted" and automatically disabled due to external events (such as the hearing test launching).
Upon activation, the ProcessingSession will be initialized and the previously applied parameter values are restored to their respective parameters. At this point the parameters are ready for use.
Processing Parameter¶
The focal point for state.
Overview¶
A MimiProcessingParameter represents an individual parameter that can be used to control Mimi processing functionality. It encompasses a value that can be mutated and applied asynchronously to subscribed components called Applicators.
Responsibilities¶
In general terms, a MimiProcessingParameter is responsible for:
- Providing access to the current parameter value.
- Applying values to an
Applicatorusing the value application sequence. - Loading values from remote data sources asynchronously (such as preset data).
- Providing state and value updates to a collection of subscribed observers.
MSDK ProcessingParameter instances¶
The ProcessingSession defines the following MimiProcessingParameter instances to provide access and control of the Mimi processing:
isEnabled- Whether Mimi processing is enabled or disabled.intensity- Intensity of Mimi processing.preset- Preset data model for use by a Mimi processor.
Parameter value application sequence summary¶
The internal process of updating a MimiProcessingParameter value or transferring the existing value to the Applicator follows a specific sequence as executed by the MimiProcessingParameter:
- The
Applicatoris requested to apply the new value.- If any
Applicatorfails to apply the value (by returningMimiApplicatorResult.Failure), the application sequence fails and observers are notified of the failure. - If successful (the
ApplicatorreturnsMimiApplicatorResult.Success), the value is updated and observers are notified of the new value.
- If any
- A return result value is given for the request.
Applicator¶
Arguably the most relevant Processing API component for integrators is the Applicator.
An Applicator is an accessory of a MimiProcessingParameter that is capable of performing the value application logic for its associated MimiProcessingParameter.
In simple terms, its role is to apply MimiProcessingParameter values to an external system. When there is a request to update a MimiProcessingParameter value, its Applicator is requested to apply this value.
For example, it will send Bluetooth commands to your device to set the isEnabled state.
While an Applicator appears quite similar to an Observer, the two components have distinct roles:
- An Applicator is responsible for the value application logic of a
MimiProcessingParameter- the result of which influences theMimiProcessingParameterstate. - An
Observeris only informed of events reflecting committed changes to theMimiProcessingParameterstate; it cannot influence theMimiProcessingParameterstate.
Responsibilities¶
- Provides an
onApplyfunction which will allow theApplicatorto asynchronously apply a value your processing system, returning the appropriateMimiApplicatorResultinstance. - Ability to set a “Delivery Timeout” to specify a time duration which if exceeded is considered erroneous and will cause a value application sequence to fail.
Getting Started¶
This section highlights some important APIs used to integrate your processing system with the MSDK.
Configuration and Activation¶
When activating a ProcessingSession, you need to provide a MimiProcessingConfiguration to define its configuration.
Example
Activate a ProcessingSession with a MimiProcessingConfiguration
First define a MimiProcessingConfiguration instance:
Then activate the ProcessingSession:
MimiProcessingConfiguration Overview¶
The MimiProcessingConfiguration defines the configuration of a ProcessingSession and provides the ability to configure the personalization preset data source.
It can be expressed directly through class instantiation, or using the fluent DSL syntax.
Example
Define MimiProcessingConfiguration with "Fine Tuning" personalization:
val configuration = MimiProcessingConfiguration.Basic(
soundPersonalization = SoundPersonalizationConfiguration(
mode = PersonalizationModeConfiguration.FineTuning(Fitting(TODO("Fitting is defined by your Processing system"))),
parameterConfiguration = SoundPersonalizationParametersConfiguration(
isEnabled = ProcessingParameterConfiguration(
YOUR_APPLY_TIMEOUT, // TODO Define a timeout appropriate for your system
isEnabledApplicator::apply // TODO Reference your isEnabled Applicator function
),
intensity = ProcessingParameterConfiguration(
YOUR_APPLY_TIMEOUT,
intensityApplicator::apply // TODO Reference your intensity Applicator function
),
preset = ProcessingParameterConfiguration(
YOUR_APPLY_TIMEOUT,
presetApplicator::apply // TODO Reference your preset Applicator function
),
)
)
)
Warning
The Processing Configuration DSL is experimental and requires opt-in, as it may have unannounced changes in future releases.
Read more in the Preset Parameter Data Sources guide.
Synchronizing your Processor¶
When a ProcessingSession is activated, an Applicator will not automatically receive the current MimiProcessingParameter value. For the MimiProcessingParameter to receive the initial value, you need to call synchronizeApplicator() for each Parameter.
Example
After activating the ProcessingSession
// Make each Applicator receive the current value from their respective ProcessingParameter
val isEnabledSyncResult : ProcessingParameterResult? = session.soundPersonalization?.media?.isEnabled?.synchronizeApplicator()
val presetSyncResult : ProcessingParameterResult? = session.soundPersonalization?.media?.preset?.synchronizeApplicator()
val intensitySyncResult : ProcessingParameterResult? = session.soundPersonalization?.media?.intensity?.synchronizeApplicatorr()
Common MimiProcessingParameter operations¶
MimiProcessingParameter Value operations¶
The following operations are provided on the MimiProcessingParameter and execute the value application sequence, and return a ProcessingParameterResult indicating whether the operation was successful.
| Function | Behavior | Notes |
|---|---|---|
apply(value) |
The apply function attempts to update the MimiProcessingParameter with the given value by updating all registered, out-of-date Applicator instances. |
|
synchronizeApplicator() |
The synchronizeApplicator function attempts to update the Applicator instance with the current MimiProcessingParameter value. |
|
load() |
The load function will attempt to refresh the value from the data source, and then automatically execute the value application sequence with that value. |
Only available for applicable if the MimiProcessingParameter has a MimiProcessingParameterDataSource |
Reading the MimiProcessingParameter state¶
| Property/Function | Behavior | Notes |
|---|---|---|
value |
The value property holds the latest successfully applied Parameter value. It is updated at the end of the value application sequence |
|
observe() |
An Observer which provides callbacks for observing and value and state changes related to the MimiProcessingParameter. It has the following events: Applying - the request value is currently being applied to the Applicators. Failed - the most recent value application failed. Applied - the most recent value application was successful. Loading - the value is being retrieved from the data source. |
Important: You should not use observe to apply values to your processing system; that is the responsibility of an Applicator. |
Example
Get the current parameter value:
Example
Observe changes in the MimiProcessingParameter state:
// Acquire the active ProcessSession (assumes already activated!)
val activeSession : ProcessingSession = requireNotNull(MimiCore.processingController.activeSession.state.value)
// Observer for a MimiProcessingParameter
activeSession.soundPersonalization?.media?.isEnabled?.observe {
when(val updateState = it.updateState) {
ProcessingParameterUpdateState.Applied -> TODO() // add your code here to handle when value application succeeds
is ProcessingParameterUpdateState.Applying -> TODO() // add your code here to handle when a value application is in progress
is ProcessingParameterUpdateState.Failed -> TODO() // add your code here to handle when a value application fails
ProcessingParameterUpdateState.Loading -> TODO() // add your code here to handle when a value application is loading from the data source
}
}