Skip to content

LayoutControl.c

Examples

/****************************************************************************
 *
 *      LayoutControl
 *      -------------------------------
 *
 ****************************************************************************
 *
 *  Description: Pump a .wav file through a .awb layout. Set/get module variables with control API
 *
 *          This example shows how to load an .awb from an file, and then
 *          how to get and set module variables with the Control Interface API.
 *          The example will stream an audio file called in_s32_stereo.raw
 *          and write the processed output to out_s32_stereo.raw
 *
 *          This example meets all the conditions to achieve 0 blocks of
 *          latency in the AWE Core OS audio path. See the Latency section
 *          of the docs for more info.
 *
 *  Copyright: (c) 2020 DSP Concepts, Inc. All rights reserved.
 *                                  3235 Kifer Road
 *                                  Santa Clara, CA 95054-1527
 *
 *
 ***************************************************************************/

#include "AWECoreOS.h"
#include "ModuleList.h"
#include <errno.h>
#include <math.h>
#include <float.h>
#include <stdlib.h>
// Defines
#define true    1
#define false   0

// Passthrough layout releated includes
#include "passthrough_InitAWB.h"
#include "PassthroughSubcanvasContainer_ControlInterface.h"

const char inFilename[] =  "../Audio/in_s32_stereo.raw";    // input audio file: stereo 32-bit fixed-point
const char outFilename[] = "../Audio/out_s32_stereo.raw";   // output audio file: stereo 32-bit fixed-point
const char awbFilename[] = "../Designs/PassthroughSubcanvasContainer.awb";    // Awb file that is used
const char awbFilename_subcanvas[] = "../Designs/ControlAppSubcanvas.awb";    // Awb file that is used

// Input/output audio files and buffers
INT32 * inputBuffer, * outputBuffer;
FILE *fin;
FILE *fout;


// Declare an AWEOSInstance pointer.
AWEOSInstance *g_AWEOSInstance;

// Declare an AWEOSConfigParameters structure. The members of this structure determine the configuration of the AWEInstance members.
// For this example, it will be populated with defaults
static AWEOSConfigParameters configParams;


// Declare a module descriptor table. This module descriptor table includes the modules as defined in ModuleList.h (which we will ship)
static const void* moduleDescriptorTable[] =
{
    LISTOFCLASSOBJECTS
};
UINT32 moduleDescriptorTableSize = sizeof(moduleDescriptorTable) / sizeof(moduleDescriptorTable[0]);


// Floating-point comparison function used for verification
// Inspired by: http://floating-point-gui.de/errors/comparison/
int awe_isNearlyEqual(float a, float b, float epsilon)
{
    float absA = fabsf(a);
    float absB = fabsf(b);
    float diff = fabsf(a - b);

    if (a == b) { // to handle infinities
        return 1;
    } else if (a == 0 || b == 0 || diff < FLT_MIN) {
        // a or b is zero or both are extremely close to it
        // relative error is less meaningful here
        return diff < (epsilon * FLT_MIN);
    } else { // use relative error
        if ((absA + absB) < FLT_MAX)
        {
            return diff / (absA + absB) < epsilon;
        }
        else
        {
            return diff / FLT_MAX < epsilon;
        }
    }
}



void destroyExample()
{
    INT32 ret;

    fclose(fin);
    fclose(fout);
    free(inputBuffer);
    free(outputBuffer);
    inputBuffer = NULL;
    outputBuffer = NULL;

    ret = aweOS_destroy(&g_AWEOSInstance);
    if (ret != E_SUCCESS)
    {
        printf("aweOS_destroy returned error = %d (%s)\n", ret, aweOS_errorToString(ret));
    }
}

int main()
{

    //Call this function with an arg to the user declared AWEOSConfigParameters structure.
    //This populates the configParams structure with DSPC defined default values.
    aweOS_getParamDefaults(&configParams);

    //Allocate a fastheapA
    #define FASTHEAP_A_SIZE 420000
    static UINT32 fastHeapA[FASTHEAP_A_SIZE];
    configParams.pFastHeapA = fastHeapA;
    configParams.fastHeapASize = FASTHEAP_A_SIZE;

    //Allocate a fastheapB
    #define FASTHEAP_B_SIZE 420000
    static UINT32 fastHeapB[FASTHEAP_B_SIZE];
    configParams.pFastHeapB = fastHeapB;
    configParams.fastHeapBSize = FASTHEAP_B_SIZE;

    //Allocate a slowheap
    #define SLOWHEAP_SIZE 420000
    static UINT32 slowHeap[SLOWHEAP_SIZE];
    configParams.pSlowHeap = slowHeap;
    configParams.slowHeapSize = SLOWHEAP_SIZE;
    INT32 ret;

    //Initialize the AWEOSInstance with the parameters that were previously set in the config structure
    ret = aweOS_init(&g_AWEOSInstance, &configParams, moduleDescriptorTable, moduleDescriptorTableSize);

    //Check if the aweOS_init succeeded. If it didn't then terminate the executable.
    if (E_SUCCESS == ret)
    {
        printf("aweOS Initialised \n");
    }
    else
    {
        printf("aweOS init failed. exiting application with error = %d %s\n", ret, aweOS_errorToString(ret));
        exit(1);
    }

    //Load the AWB from file
    UINT32 position=0;
    ret = aweOS_loadAWBFile(g_AWEOSInstance, awbFilename, &position);

    if (E_SUCCESS == ret)
    {
        printf("Loaded layout loaded from file %s\n", awbFilename);
    }
    else
    {
        if (E_NOSUCHFILE == ret || E_CANTOPEN == ret)
        {
            printf("Layout %s load unsuccessful with Error = %d %s \n", awbFilename, ret, aweOS_errorToString(ret));
        }
        else
        {
            printf("Layout %s load unsuccessful in the positions %u with Error = %d %s \n", awbFilename, position, ret, aweOS_errorToString(ret));
        }
        exit(1);
    }

    //Check if the layout is valid
    ret = aweOS_layoutIsValid(g_AWEOSInstance);
    if (1 != ret)
    {
        printf("Error: Loaded layout is not valid: error = %d %s\n", ret, aweOS_errorToString(ret));
        exit(1);
    }

    //Check if the Audio has started
    ret = aweOS_audioIsStarted(g_AWEOSInstance);
    if (1 != ret)
    {
        printf("Error: Audio not started: error = %d %s\n", ret, aweOS_errorToString(ret));
        exit(1);
    }

    // Get the layout I/O configuration Input, Output and block size
    // Input and output blocksizes are the same in all layouts
    UINT32 layoutInChannels, layoutOutChannels, layoutBlockSize;
    FLOAT32 SR;
    ret = aweOS_layoutGetChannelCount(g_AWEOSInstance, &layoutInChannels, &layoutOutChannels);
    if (E_SUCCESS != ret)
    {
        printf("Error: GetChannelCount failed: error = %d %s\n", ret, aweOS_errorToString(ret));
        exit(1);
    }
    ret = aweOS_layoutGetBlockSize(g_AWEOSInstance, &layoutBlockSize);
    if (E_SUCCESS != ret)
    {
        printf("Error: GetBlockSize failed: error = %d %s\n", ret, aweOS_errorToString(ret));
        exit(1);
    }
    ret = aweOS_layoutGetSampleRate(g_AWEOSInstance, &SR);
    if (E_SUCCESS != ret)
    {
        printf("Error: GetSampleRate failed: error = %d %s\n", ret, aweOS_errorToString(ret));
        exit(1);
    }
    printf("Layout loaded with inputChannels=%u, outputChannels=%u, blockSize=%u, SR=%f\n", layoutInChannels, layoutOutChannels, layoutBlockSize, SR);


    //Prepare the stereo input and output buffers
    UINT32 inSize, outSize;
    const INT32 inputChannels = 2;
    const INT32 outputChannels = 2;

    //The system is hardcoded for 2 channels.
    //Prepare the stereo input and output buffers, and open files
    inSize = inputChannels * layoutBlockSize;
    outSize = outputChannels * layoutBlockSize;

    inputBuffer = malloc(inSize * sizeof(INT32));
    outputBuffer = malloc(outSize * sizeof(INT32));

    fin = fopen(inFilename, "rb");
    if (NULL == fin )
    {
        printf("Error opening input file %s\n", inFilename);
        printf("Error %d \n", errno);
        exit(1);
    }
    else
    {
        printf("Opening input file %s\n", inFilename);
    }

    fout = fopen(outFilename, "wb");
    if (NULL == fout)
    {
        printf("Error opening input file %s\n", outFilename);
        printf("Error %d \n", errno);
        exit(1);
    }
    else
    {
        printf("Opening output file %s\n", outFilename);
    }

    //Set Scaler1 gain attributes
    float scaler1Gain;
    float scaler1TargetGain;
    float sinkValue;
    float meter1Values[AWE_Meter1_value_SIZE];
    long count = 0;
    long subcount = 0;
    int numSamplesRead = 0;
    float subCanvasSetValue;
    UINT32 classId;

    //NOTE: All handle/ID/size macros passed into the aweOS_ctrl API's are found in the ControlInterface header file, "passthrough_ControlInterface.h"
    //This header file was generated by Designer, alongside the corresponding .awb layout "passthrough_InitAWB.h".

    //Check that the layout has the correct control modules in it
    //Scaler module check
    ret = aweOS_ctrlGetModuleClass(g_AWEOSInstance, AWE_Scaler1_gain_HANDLE, &classId);
    if (E_SUCCESS == ret)
    {
        // Check that module assigned this object ID is of module class Scaler
        if (AWE_Scaler1_classID != classId )
        {
            printf("Error: Scaler1 module not found in layout (%u)\n", AWE_Scaler1_classID );
            exit(1);
        }
    }
    else
    {
        printf("Error: aweOS_ctrlGetModuleClass with error = %d %s\n", ret,aweOS_errorToString(ret));
    }

    // Meter module check
    ret = aweOS_ctrlGetModuleClass(g_AWEOSInstance, AWE_Meter1_value_HANDLE, &classId);
    if (E_SUCCESS == ret)
    {
        // Check that module assigned this object ID is of module class Meter
        if (AWE_Meter1_classID != classId)
        {
            printf("Error: Meter module not found in layout (%u)\n",AWE_Meter1_classID);
            exit(1);
        }
    }
    else
    {
        printf("Error: aweOS_ctrlGetModuleClass with error = %d %s\n", ret, aweOS_errorToString(ret));
    }


    ret = aweOS_ctrlGetValue(g_AWEOSInstance, AWE_Scaler1_gain_HANDLE, &scaler1Gain, 0, AWE_Scaler1_gain_SIZE);
    if (E_SUCCESS == ret)
    {
        printf("\nGetValue: Default scaler1Gain = %f, error = %d\n", scaler1Gain, ret);
    }
    else
    {
        printf("Error: aweOS_ctrlGetValue with error = %d %s\n", ret, aweOS_errorToString(ret));
    }
    //Set the gain to -10 dB
    scaler1Gain = -10.0;
    ret = aweOS_ctrlSetValue(g_AWEOSInstance, AWE_Scaler1_gain_HANDLE, ( void *)&scaler1Gain, 0, AWE_Scaler1_gain_SIZE);
    if (E_SUCCESS == ret)
    {
        printf("SetValue: scaler1Gain = %f, error = %d\n", scaler1Gain, ret);
    }
    else
    {
        printf("Error: aweOS_ctrlSetValue with error = %d %s\n", ret, aweOS_errorToString(ret));
    }


    ret = aweOS_ctrlGetValue(g_AWEOSInstance, AWE_Scaler1_gain_HANDLE, &scaler1Gain, 0, AWE_Scaler1_gain_SIZE);
    if (E_SUCCESS == ret)
    {
        printf("GetValue: scaler1Gain = %f, error = %d\n", scaler1Gain, ret);
    }
    else
    {
        printf("Error: aweOS_ctrlGetValue with error = %d %s\n", ret, aweOS_errorToString(ret));
    }

    ret = aweOS_ctrlGetValue(g_AWEOSInstance, AWE_Scaler1_targetGain_HANDLE, &scaler1TargetGain, 0, AWE_Scaler1_targetGain_SIZE);
    if (E_SUCCESS == ret)
    {
        printf("GetValue: scalerTarget1Gain = %f, error = %d\n", scaler1TargetGain, ret);
    }
    else
    {
        printf("Error: aweOS_ctrlGetValue with error = %d %s\n", ret, aweOS_errorToString(ret));
    }

    //Process the input data
    printf("\nStarting to process [%s] into [%s]\n\n", inFilename, outFilename);

    while ((numSamplesRead = fread(inputBuffer, sizeof(int), inSize, fin)) > 0)
    {
        INT32 i, j;
        INT32 numOutFrames;

        for (i = 0; i < inputChannels; i++)
        {
            ret = aweOS_audioImportSamples(g_AWEOSInstance, inputBuffer + i, inputChannels, i, Sample32bit);
            if (ret != E_SUCCESS)
            {
                printf("Error: aweOS_audioImportSamples() failed: error = %d %s exiting application\n", ret, aweOS_errorToString(ret));
                exit(1);
            }
        }

        aweOS_audioPumpAll(g_AWEOSInstance);

        for (i = 0; i < outputChannels; i++)
        {
            ret = aweOS_audioExportSamples(g_AWEOSInstance, outputBuffer + i, outputChannels, i, Sample32bit);
            if (ret != E_SUCCESS)
            {
                printf("Error: aweOS_audioExportSamples() failed: error = %d %s exiting application\n", ret, aweOS_errorToString(ret));
                exit(1);
            }
        }

        count++;
        // Print the Meter1 value every 1024 pump cycles
        if (1024 == count)
        {
            subcount++;
            count = 0;
            ret = aweOS_ctrlGetValue(g_AWEOSInstance, AWE_Meter1_value_HANDLE, &meter1Values, 0, AWE_Meter1_value_SIZE);
            if (E_SUCCESS == ret)
            {
                printf("GetValue: meter1Value = %f, error = %d\n", meter1Values[0], ret);
            }
            else
            {
                printf("Error: aweOS_ctrlGetValue with error = %d %s\n", ret, aweOS_errorToString(ret));
            }


            if (subcount == 2)
            {
                printf("\n ---- LATE LOADING SUBCANVAS AWB. ---- \n\n");
                //late load the subcanvas AWB. SubcanvasSinkValue should now be 3
                ret = aweOS_loadSubcanvasAWBfromFile(g_AWEOSInstance, AWE_Subcanvas1____SC_ID, awbFilename_subcanvas, &position);
                if (ret != E_SUCCESS)
                {
                    printf("Failed to reload the subcanvas AWB with error %d \n", ret);
                    destroyExample();
                    exit(1);
                }
                else
                {
                    printf("\n --- SETTING subcanvasSinkValue VALUE TO 8.0f --- \n");
                    subCanvasSetValue = 8.0f;
                    ret = aweOS_ctrlSetValue(g_AWEOSInstance, AWE_DC1_value_HANDLE, &subCanvasSetValue, 0, AWE_DC1_value_SIZE);
                    if (ret != E_SUCCESS)
                    {
                        printf("Failed to set subcanvasSetValue with error %d \n", ret);
                    }
                }
            }

        }

        fwrite(outputBuffer, sizeof(int), outSize, fout);

    //Perform inline verification
    //Channel 1 is expected to be attenuated by -10 dB
    //Channel 2 is expected to be passed through without modification
#define EPSILON 0.1f
        numOutFrames = numSamplesRead / outputChannels;
        for (j = 0; j < numOutFrames; j++)
        {
            float expectedValueChannel1 = powf(10.0, scaler1Gain / 20.0) * (float)inputBuffer[inputChannels * j];
            float expectedValueChannel2 = (float)inputBuffer[inputChannels * j + 1];
            if (awe_isNearlyEqual(expectedValueChannel1, (float)outputBuffer[outputChannels * j], EPSILON) == 0)
            {
                printf("Verification error. Expected %f on channel 1 but got %f, sample %d\n", expectedValueChannel1,
                (float)outputBuffer[outputChannels * j], j);
                destroyExample();
                exit(1);
            }

            if (awe_isNearlyEqual(expectedValueChannel2, (float)outputBuffer[outputChannels * j + 1], EPSILON) == 0)
            {
                printf("Verification error. Expected %f on channel 2 but got %f\n, sample %d\n", expectedValueChannel2,
                (float)outputBuffer[outputChannels * j + 1], j);
                destroyExample();
                exit(1);
            }
        }
        // There is no latency introduced through this audio path

    }
    printf("\n");

    //verify that the subcanvas sink value was actually set to 8.0f in the pump loop...
    ret = aweOS_ctrlGetValue(g_AWEOSInstance, AWE_Sink1_value_HANDLE, &sinkValue, 0, AWE_Sink1_value_SIZE);
    if (ret == E_SUCCESS)
    {
        printf("GetValue: subcanvasSinkValue = %f, error = %d\n", sinkValue, ret);
        if (sinkValue != subCanvasSetValue)
        {
            printf("ERROR: The subcanvas sink value does not match the set value (8.0f) Exiting..\n");
            destroyExample();
            exit(1);
        }
    }
    else
    {
        printf("Getting subcanvas sink failed on aweOS_ctrlGetValue with error %d \n", ret);
    }

    ret = aweOS_ctrlGetValue(g_AWEOSInstance, AWE_Scaler1_gain_HANDLE, &scaler1Gain, 0, AWE_Scaler1_gain_SIZE);
    if (E_SUCCESS == ret)
    {
        printf("GetValue: scaler1Gain = %f, error = %d\n", scaler1Gain, ret);
    }
    else
    {
        printf("Error: aweOS_ctrlGetValue with error = %d %s\n", ret, aweOS_errorToString(ret));
    }


    ret = aweOS_ctrlGetValue(g_AWEOSInstance, AWE_Scaler1_targetGain_HANDLE, &scaler1TargetGain, 0, AWE_Scaler1_targetGain_SIZE);
    if (E_SUCCESS == ret)
    {
        printf("GetValue: scalerTarget1Gain = %f, error = %d\n", scaler1TargetGain, ret);
    }
    else
    {
        printf("Error: aweOS_ctrlGetValue with error = %d %s\n", ret, aweOS_errorToString(ret));
    }

    UINT32 avgCycles;
    ret = aweOS_getAverageLayoutCycles(g_AWEOSInstance, 0, &avgCycles);
    printf("Processed %ld audio frames -- average cycles per pump = %u\n", count, avgCycles);

    //Clean up
    destroyExample();
    return 0;
}

Filename: LayoutControl.c