Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Scroll Documents: Update page title prefix

...

Each audio module has an associated header file ModClassName.h containing a class definition, and a source file ModClassName.c containing the associated class structure and functions.  The header and source files are generated by MATLAB, but it is important to understand their contents and how all of the pieces fit together.

Data types and Structure Definitions

Let's begin by looking at the class definition for the smoothly varying scaler found in ModScalerSmoothedExample.h:

...

Framework.h contains the primary data types and definitions used by Audio Weaver.  Most of the definitions are used internally by the Server, but a few apply to audio modules.

Module Instance Structure

Following the instance header are all of the module specific variables.  Only 8 types of module variables are currently supported:

...

All scalar module variables must precede arrays in the instance structure.  This is due to the manner in which audio modules are allocated and initialized by the Server.  The MATLAB module generation scripts automatically reorder variables (using the function awe_reorder_variables.m).  Detailed description of awe_reorder_variables.m is found in Reordering of Render Variables.

The module instance descriptor is also defined within Framework.h:

...

  • ClassModule_GetWires(S) — returns a pointer to the array of wires associated with the module.  The wires are ordered as input wires, output wires, and then scratch wires.

  • ClassModule_GetNInWires(S) — returns the number of input wires.

  • ClassModule_GetNOutWires(S) — returns the number of output wires

  • ClassModule_GetNScratchWires(S) — returns the number of scratch wires

  • ClassModule_GetModuleState(S) — returns the module's run-time state.  ACTIVE=0, BYPASSED=1, MUTED=2, and INACTIVE=3.

Pins and Wires

A wire in Audio Weaver contains more than just audio samples.  A wire is defined as:

...

You'll note that the pin descriptor does not specify the type of data (float, int, or fract32) contained in the wire.  This allows a wire containing floating-point data to be reused for integer data as long as the number of channels, block size, and sample rate are identical.

Examples

The absolute value module has a single input and output pin, and can handle an arbitrary number of channels, block size, and sample rate.  S is a pointer to the module instance.  The processing code is:

...

Both of the module examples use a set of "vector" functions to perform the actual computation.  It is possible to perform the computation within the module's processing function – many modules do this.  For some modules, however, we have chosen to use vector functions since smaller functions may be more easily optimized in assembly and a single function may be reused by multiple modules.  For example, Vec_Scale() is used by the scaler_module.m, scalern_module.m, and scaler_db_module.m.  Thus, by optimizing a single function vector for a target processor we obtain 3 optimized modules.

Class Object and Constructor Functions

The module constructor function is called in response to a create_module command sent from the Server to the target.  A module's constructor function is called once per module instance and is responsible for allocating memory for the module and copying arguments from the create_module command into the instance structure. 

...

The Biquad module was used as an example to illustrate the constructor function because it requires an array to be allocated.  If the Constructor function pointer in the module's class structure is set to NULL, then the generic module constructor is called.  The generic constructor simply calls BaseClassModule_Constructor() and is sufficient for modules that do not require additional memory allocation outside of the instance structure or other custom initialization.  The generic constructor is sufficient for a large number of modules and reduces the code size of the target executable.

Memory Allocation using awe_fwMalloc()

Dynamic memory allocation is accomplished in Audio Weaver by the function awe_fwMalloc().  To avoid memory fragmentation, memory can only be allocated but never individually freed.  You can only free all memory completely using the destroy command and then start again.

...

Most modules supplied with Audio Weaver take advantage of this overflow behavior to smoothly transition from internal to external memory once the heaps have filled up.

Module Function Details
Anchor
ModuleFunctionDetails
ModuleFunctionDetails

Each audio module has a set of 5 functions associated with it.  This section describes the arguments to each of the functions.

Constructor Function
Anchor
ConstructorFunction
ConstructorFunction

This function is usually generated by MATLAB but at times it needs to be hand written – especially if the module does more than just allocate memory.  Audio Weaver names the constructor function using the convention

...

The module constructor function is typically called by the framework in response to a message received from the PC over the tuning interface or from a message stored in a file system.  After a module constructor function is called, the framework checks if the module has an associated Set function.  If so, the Set function is called immediately with a mask of 0xFFFFFFFF. 

Info

There is no need to manually call the Set function within the Constructor.  The framework takes care of this.

Processing Function
Anchor
ProcessingFunction
ProcessingFunction

The processing function has the signature

...

The processing function does not return an error code.  If you need to track error conditions, do this by adding an error code to the instance structure and then tracking it in the inspector.

Set Function
Anchor
SetFunction
SetFunction

This function implements a module's control functionality and typically converts high-level variables to low-level variables.  The PeakHold module has the function signature

...

The second argument to the Set function is a bit mask that specifies which module variable(s) have changed.  The bit mask is set by the Server when module variables are updated while tuning.  The bit mask may also be set by control code running on the target.  Use of the bit mask is optional and is only really necessary when the module writer needs to distinguish between heavy duty changes requiring significant amounts of computation and lightweight changes.

A bit mask of 0xFFFFFFFF is used to force all variables in the Set function to update. This value of the bit mask is used in a call to the Set function after the module is constructed but before it is pumped for the first time. This ensures that all module variables are updated before they are used.

A special case of the bit mask is when it is equal to 0. When the module is constructed, after calling the module’s constructor function, set function is called immediately by the framework with a bit mask of 0xFFFFFFFF. User can use this in the Set function, if needed, to trigger action immediately after memory is allocated. Note that the module's array variables have not been set at this point. After the module constructor is called, each array variable is separately written and
the module's set function is called with the mask set based on the array written. Mask value of each variable/array in a module’s instance can be found in module header file (for example in ModPeakHoldExample.h).

When the destroy tuning command is processed by the AWECore, the Set function of every module is called with a mask of 0. This allows the module to do any necessary clean up operations. For example, if your module does file I/O you could close the file at this time. Or you might free memory that is dynamically allocated outside of the Audio Weaver heaps.

In the bit mask, bit N is set when the Nth module variable is set.  The bit counting includes the 8 word module instance header and thus the first tunable module variable is numbered 8.  The module header file contains a set of #define's indicating the bit value for each variable.  For example, ModPeakHoldModPeakHoldExample.h contains:

Code Block
#define MASK_PeakHold_Reset 0x00000100
#define MASK_PeakHold_attackTime 0x00000200
#define MASK_PeakHold_decayTime 0x00000400
#define MASK_PeakHold_decayCoef 0x00000800
#define MASK_PeakHold_attackCoef 0x00001000
#define MASK_PeakHold_peakHold 0x00002000
#define MASK_PeakHold_peakDecay 0x00004000

A few more things to keep in mind regarding masks.  When an array variable is set, the bit mask corresponding to the array is set as expected.  However, the Set function is not told which portion of the array has been changed.  Finally, since the mask is only 32 bits in length, it is possible to run out of unique bits if the instance structure is very long.  The high bit of the mask, bit 31, has special meaning.  When this bit is set, it indicates that at least one of the high order instance variables has changed.  However, you don't know precisely which one.

Get Function
Anchor
GetFunction
GetFunction

This function is rarely used in practice and translates low-level variables to higher-level variables.  This function has the same signature as the Set function

...

When called, the function should update instance variables and can use the mask argument to determine which variables should be updated.

BypassFunction
Anchor
BypassFunction
BypassFunction

This function implements a module's bypass functionality.  The function signature is identical to the processing function

...