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 a collection of subscribed
Applicatorsusing 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 Applicators follows a specific sequence as executed by the MimiProcessingParameter:
- The
Applicators are iterated through and are requested to apply the new value.- If any
Applicatorfails to apply the value (by returningMimiApplicatorResult.Failure), the application sequence is abandoned with an error and observers are notified of the failure. - If successful (each
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.
Note: If no Applicators are present - then value is immediately updated and the result is successful.
Important: A given MimiProcessingParameter executes each value application sequence sequentially - it does not perform concurrent updates.
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 Applicators are requested to apply this value.
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.
In the Android MSDK, the concept of the Applicator is represented by the MimiParameterApplicator type.
Responsibilities¶
- Provides an
applyfunction which will allow theApplicatorto asynchronously apply a value your processing system, returning the appropriateMimiApplicatorResultinstance. - Ability to be removed from a
MimiProcessingParameter. - 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(
personalization = PersonalizationConfiguration(
mode = FineTuning(Fitting(TODO("Fitting is defined by your Processing system")))
)
)
Alternatively, using the Processing Configuration DSL:
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.
Defining and adding Applicators¶
After activation, you will need to define and add Applicators to each of the MimiProcessingParameters: isEnabled, intensity and preset.
To add an Applicator, use the addApplicator function which adds an "out-of-date" Applicator.
Note
When adding an Applicator, it will not automatically receive the current value and likewise; it has no effect on the current MimiProcessingParameter value.
Example
Adding Applicators to each MimiProcessingParameter:
// Define a timeout for the value application sequence
// TODO Example only: tune this value to your processing system
val applyTimeout = Duration.ofSeconds(15)
val isEnabledApplicator : MimiParameterApplicator = session.isEnabled.addApplicator(applyTimeout) { value ->
// TODO - Implement your logic to apply the given isEnabled value in your processing system
// For example: Send Bluetooth commands to your device to set the isEnabled state.
MimiApplicatorResult.Success
}
val presetApplicator : MimiParameterApplicator = session.preset.addApplicator(applyTimeout) { value ->
// TODO - Implement your logic to apply the given preset value in your processing system
// For example: Send Bluetooth commands to your device to set the preset.
MimiApplicatorResult.Success
}
val intensityApplicator : MimiParameterApplicator = session.intensity.addApplicator(applyTimeout) { value ->
// TODO - Implement your logic to apply the given intensity value in your processing system
// For example: Send Bluetooth commands to your device to set the intensity.
MimiApplicatorResult.Success
}
// Make each Applicator receive the current value from their respective ProcessingParameter
val isEnabledSyncResult : ProcessingParameterResult = session.isEnabled.synchronizeApplicators()
val presetSyncResult : ProcessingParameterResult = session.preset.synchronizeApplicators()
val intensitySyncResult : ProcessingParameterResult = session.intensity.synchronizeApplicators()
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. |
|
synchronizeApplicators() |
The synchronizeApplicators function attempts to update all registered, out-of-date Applicators instances 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)
// Observer for a MimiProcessingParameter
activeSession.isEnabled.processingParameter.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
}
}