Override parent methods¶
The Auditory front-end framework was developed to maximise code reusing. Many of the existing
processors, although they carry out different processing tasks, have common
attributes in terms of e.g., number of inputs, number of outputs, how to call
their processing methods, … Hence all aspects of initialisation (and re-
initialisation following a response to feedback) and input/output routing have
been implemented for common-cases as methods of the parent Processor
class.
If your processor does not behave similarly to others in one of these regards,
then this approach allows you to redefine the specific method in your new
children processor class definition. In the object oriented jargon, this
procedure is called method overriding.
In the following, we list the methods that might need overriding and how to do
so. Subsections for each methods will start with a description of what the
method does and a note explaining in which cases the method needs to be
overridden, such that you can quickly identify if this is necessary for your
processor. Some examples of existing processors that override a given method
will also be given so they can be used as examples. Note that all non- static
methods from the parent Processor
class can be overridden if necessary. The
following list only concerns methods that were written with overriding in mind
to deal with particular cases.
Note
Overridden methods need to have the same method attribute(s) as the parent method they are overriding.
Initialisation methods¶
verifyParameters
¶
This method is called at the end of the Processor
super-constructor. It
ensures that user-provided parameters are valid. The current implementation of
the Auditory front-end relies on the user being responsible and aware of which type or values
are suitable for a given parameter. Therefore, we do not perform a systematic
check of all parameters. Sometimes though, you might want to verify that user-
provided parameters are correct in order to avoid Matlab returning an error at a
later stage. For example, ihcProc.verifyParameters
will check that the inner
hair-cell model name entered by the user is part of the list of valid names.
Another use for the verifyParameters
method is to solve conflicts between
parameters. For example, the auditory filterbank in gammatoneProc
can be
instantiated in three different ways (e.g., by providing a range of frequency
and a number of channels, or directly a vector of centre frequencies). The user-
provided parameters for this processor are therefore potentially “over-
determining” the position of centre frequencies. To make sure that there is no
conflict, some priority rules are defined in gammatoneProc.verifyParameters
to ensure that a unique and non-ambiguous vector of centre frequencies is
generated.
Note
This method does nothing by default. Override it if you need to perform specific checks on external parameters (i.e., the user-provided parameters extended by the default values) before instantiating your processor.
To override this method, place it in a methods block with the
Access=protected
attribute. The method takes only an instance of the
processor object (say, pObj
) as input argument, and does not return any
output.
If you are checking that parameters have valid values, replace those which are
invalid with their default value in pObj.parameters.map
(see e.g.,
ihcProc.verifyParameters
). It is a good practice here to inform the user by
returning a warning, so that he/she knows that the default value is used
instead.
If you are solving conflicts between parameters, set up a priority rule and only
retain user-provided parameters that have higher priority according to this rule
(see e.g., gammatoneProc.verifyParameters
). Mention explicitly this rule in
the help line of your processor constructor.
prepareForProcessing
¶
This method performs the remaining initialisation steps that we purposely did
not include in the constructor as they initialise properties that are
susceptible to change when receiving feedback. It also includes initialisation
steps that can be performed only once processors have been linked together in a
“processing tree”. For example, ildProc
needs to know the original sampling
frequency of the signal before its cross-correlation was computed to provide lag
values in seconds. But to access the cross-correlation processor and request
that value, the two processors need to be linked together already, which does
not happen at the level of instantiation but later. Hence this method will be
called for each processors once they all have been inter-linked, but also
whenever feedback is received.
Note
Override this method if your processor has properties or internal parameters that can be changed via user feedback or that comes directly from preceding processors in the processing tree.
This method should have the Hidden=true
method attribute. Hidden methods are
sometimes used in the Auditory front-end when we need public access to it (i.e., other
objects than the processor itself should be able to call the method) but when it
is not deemed necessary to have the user call it. The user can still call the
method by explicitly writing its name, but the method will not appear in the
list of methods returned by Matlab script methods(.)
nor by Matlab’s
automatic completion.
The method only takes an instance of the processor as input argument and does
not return outputs. In the method, you should initialise all internal parameters
that are susceptible to changes from user feedback. Note that this includes the
processor’s output sampling frequency FsHzOut
if this frequency depends on
the processor parameters. A good example is
ratemapProc.prepareForProcessing
, which initialises internal parameters
(framing windows), the output sampling frequency and some filters.
instantiateOutput
¶
This method is called just after a processor has been instantiated to create a signal object that will contain the output of this new processor and add the signal to the data object.
Note
Override this method if your output signal object constructor needs additional
input arguments (e.g., for a FeatureSignal
), if your processor generates
more than one type of output, or if your processor can generate either mono or
stereo output (e.g., the current preProc
). There is no processor in the
current implementation that generates two different outputs. However, the pre-
processor can generate either mono or stereo outputs depending on the number
of channels in the input signal (see preProc.instantiateOutput
for an
example).
This method should have the Hidden=true
method attribute. It takes as input
an instance of your processor and a instance of a data object to add the signal
to. It returns the output signal object(s) as a cell array with the usual
convention that first column is left channel (or mono) and right column is right
channel. Different lines are for different types of signals.
Warning
Because there is no such processor at the moment, creating a new processor that returns two different types of output (and not just left/right channels) might involve additional changes. This is left to the developers responsibility to test and adjust existing code.
Input/output routing methods¶
When the manager creates a processing “tree”, it also populates the Input
and Output
properties of each processors with handles to their respective
input and output signal objects. The methods defined in the parent Processor
should cover most cases already, and it is unlikely that you will have to
override them for your own processor. For these two methods, it is important to
remember the internal convention when storing multiple signals in a cell array:
columns are for audio channels (first column is left or mono and second column
is right). Different lines are for different types of signals.
The way Input
and Output
properties are routed should be in accordance
with how they are used in the initiateProcessing
method, which will be
described in the next subsection.
addInput
¶
This method takes an instance of the processor and a cell array of handles to
dependent processors (i.e., processors one level below in the processing tree)
and does not return any arguments. Instead, it will populate the Input
property of your processor with a cell array of handles to the signals that are
outputs to the dependent processors. The current implementation of
Processor.addInput
works for three cases, which overall cover all currently
existing processors in the Auditory front-end:
- There is a single dependent processor which has a single output.
- There are two dependent processors each with single output corresponding to the left and right channels of a same input signal.
- There is a single dependent processor which produces two outputs: a left and
a right channel (such as
preProc
for stereo signals).
Note
Override this method if your processor input signals are related to its dependent processors in a different way than the three scenarios listed above.
This method should have the Hidden=true
attribute. You should just route the
output of your dependent processors to the input of your new processor
adequately. Again, it was not necessary thus far to override this method, hence
no examples can be provided here. Additionally, this functionality has not been
tested, so it might imply some minor reworking of other code components.
addOutput
¶
This method adds a signal object (or a cell array of signals) to the Output
property of your processor.
Note
Override this method if your processor has multiple outputs of different types. If your processor returns two outputs as the left and right channel of a same representation, it is not necessary to override this method.
This method should have the Hidden=true
method attribute. It takes as input
an instance of the processor and a single or a cell array of signal objects.
Processing method¶
initiateProcessing
¶
This method is closely linked to the addInput
, addOutput
and
processChunk
methods. It is a wrapper to the actual processing method that
routes elements of the cell arrays Input
and Output
to actual inputs and
outputs of the processChunk
method and call that method. It also appends the
new chunk(s) of output to the corresponding output signal(s).
The parent implementation considers two cases: monaural and binaural (i.e., a “left” and a “right” inputs) which produce single outputs.
Note
Override this method if your processor is not part of the two cases above or
if your implementation of the processChunk
has a different signature than
the standard.
A good example of an overridden initiateProcessing
method can be found in
preProc.initiateProcessing
, as the processing method of the pre-processor
does not have a standard signature as it returns two outputs (left and right
channels).