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 MimiProcessingParameter
s 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
activeSession
property on theProcessingController
allowing the session to be easily referenced. - Only a single session can be activated at one time.
- Deactivation clears the
activeSession
property. It does not directly affect the applied Mimi processing. - Activating and deactivating a session triggers
MimiObserver
notifications 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 MimiProcessingParameter
s, and therefore is the gateway to parameter access.
Responsibilities¶
- Owner of all Processing Parameters, providing access to;
isEnabled
,intensity
andpreset
. - Exposes the current data source configuration for the
preset
parameter. - 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 Applicator
s.
Responsibilities¶
In general terms, a MimiProcessingParameter
is responsible for:
- Providing access to the current parameter value.
- Applying values to a collection of subscribed
Applicators
using 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 Applicator
s follows a specific sequence as executed by the MimiProcessingParameter
:
- The
Applicator
s are iterated through and are requested to apply the new value.- If any
Applicator
fails 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
Applicator
returnsMimiApplicatorResult.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 Applicator
s 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 Applicator
s 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 theMimiProcessingParameter
state. - An
Observer
is only informed of events reflecting committed changes to theMimiProcessingParameter
state; it cannot influence theMimiProcessingParameter
state.
In the Android MSDK, the concept of the Applicator
is represented by the MimiParameterApplicator
type.
Responsibilities¶
- Provides an
apply
function which will allow theApplicator
to asynchronously apply a value your processing system, returning the appropriateMimiApplicatorResult
instance. - 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 Applicator
s¶
After activation, you will need to define and add Applicator
s to each of the MimiProcessingParameter
s: 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 Applicator
s 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 Applicator s 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
}
}