Skip to content

Libtester.c

Examples

/****************************************************************************
 *
 *      Libtester
 *      -------------------------------
 *
 ****************************************************************************
 *
 *  Description:    AWECoreOS Library Test App
 *      The sample application 'Libtester' is intended to show basic usage of AWECoreOS.
 *      An AWECoreOS Instance is configured and initialized, and processing can be done by specifying
 *      input files, or with simulated real-time audio on Linux. Run the app with no options for usage. 
 *      Includes an ethernet/TCPIP tuning interface to connect to AWE Server on port 15002 or
 *      user defined port (15002 - 15098). 
 *
 *  Copyright: (c) 2020 DSP Concepts, Inc. All rights reserved.
 *                                  3235 Kifer Road
 *                                  Santa Clara, CA 95054-1527
 *
 *
 ***************************************************************************/

#include "AWECoreOS.h"
#include "AWEPluginLoader.h"
#include "AWEPluginTypes.h"
#include "ModuleList.h"
#include "AWECoreUtils.h"

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <math.h>
#include <float.h>
#include <unistd.h>
#include <sys/types.h> 
#include <pthread.h>
#include <sched.h>
#include <signal.h>
#include <time.h>
#include <sys/time.h>
#include <semaphore.h>

// Defines 
#define true    1
#define false   0

#define FASTHEAP_A_SIZE 4200000
#define FASTHEAP_B_SIZE 4200000
#define SLOWHEAP_SIZE 4200000

// Global heaps (dynamically allocated based on the size argument
UINT32 *fastHeapA;
UINT32 *fastHeapB;
UINT32 *slowHeap;
UINT32 heapSizeFastA = FASTHEAP_A_SIZE;
UINT32 heapSizeFastB = FASTHEAP_B_SIZE;
UINT32 heapSizeSlow = SLOWHEAP_SIZE;

// Global thread handles and mutexes
pthread_t audioCallbackThreadHandle;
pthread_mutex_t audioThreadMutex;
pthread_cond_t audioThreadCond;

sem_t pumpSem;


// Global variables
INT32 audioStarted = 0;
INT32 exitAudioCallbackThread = 0;
INT32 pumpActive = 0;

static UINT32 quiet = false;

// Static counter to count the number of audio frames processes(in terms of fundamental block size)
static unsigned long long count = 0;
// USed to mask out warning, so that aweOS_audioPumpAll() prints the errors only once in the loop per run.
// ErrMask gets reset in the aweOSuser_audioStop()
static UINT32 ErrMask = false;

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

UINT8 *inputBuffer1, *outputBuffer1;

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]);

void destroyApp()
{
    INT32 ret; 
    // destroy function does most of the teardown of the system for us
    ret = aweOS_destroy(&g_AWEOSInstance);
    if (E_SUCCESS != ret) 
    {   
        printf("aweOS_destroy: failed with the error = %d %s\n", ret, aweOS_errorToString(ret));
    }

    // Destroy local objects
    free(inputBuffer);
    free(outputBuffer);
    free(fastHeapA);
    free(fastHeapB);
    free(slowHeap);

    sem_destroy(&pumpSem);
    pthread_cond_destroy(&audioThreadCond);
    pthread_mutex_destroy(&audioThreadMutex);

    awe_PluginLoader_free();
}

void sig_handler(int signo)
{   
    if (signo == SIGINT || signo == SIGPIPE || signo == SIGKILL)
    {
        // Cought termination signal
        destroyApp();
    }
    if (!quiet)
    {
        printf("Exiting Libtester\n");
    }
    exit(0);    
}

void copyright()
{
    AWEOSVersionInfo_t versionInfo;
    aweOS_getVersion(&versionInfo);
    printf("%s\nAWE Core OS Libtester Copyright (c) DSP Concepts 2013-2022\n", versionInfo.textVer);
}

static void usage(const char *program)
{
    printf(
        "Usage: %s [args]\n"
        "       -load:<file>                 AWB file to load\n"
        "       -in:<file>                   input file to process\n"
        "       -out:<file>                  output file\n"
        "       -sr:sampling_rate            value in Hz, default 48KHz\n"
        "       -pf:profile_frequency        value in Hz, default 10MHz\n"
        "       -cf:cpu_frequency            value in Hz, default 1GHz\n"
        "       -profStatus                  set profiling status (0 - disable, 1 - enable, 2 - enable module level only, 3 - enable top level only)\n"
        "       -bsize:N                     default 32, Audio block size for the system\n"
        "       -inchans:N                   default 2, number of input channels\n"
        "       -outchans:N                  default 2, number of output channels\n"
        "       -wait                        default disabled, sets up the integrated socket interface and waits for the designer to connect\n"
        "       -tport                       default 15002, port number for socket interface. User can choose between 15002 - 15098\n"
        "       -tlog                        enable tuning packet logging\n"
        "       -quiet                       works in quiet mode, displays only necessary messages\n"
        "       -hsizefasta:N                fast A heap size in words, default %d\n"
        "       -hsizefastb:N                fast B heap size in words, default %d\n"
        "       -hsizeslow:N                 slow heap size in words, default %d\n"
        "       -plugin:<file>               Load module classes from a plugin library. May be specified multiple times.\n"
        "                                    (Must provide a full filesystem path for libraries not present in the ld path.)\n"
        "This program exercises the AWECoreOS library.\n",
        program,FASTHEAP_A_SIZE,FASTHEAP_B_SIZE,SLOWHEAP_SIZE);
        exit(0);
}


void usrLogging(AWEOSInstance* pAWEOS, INT32 level, UINT32 type, void* payload, INT32 payloadSizeInBytes)
{
    // Simple logging function always writes payload to stdout
    struct timeval ts;
    char timeCh[25];

    // Get current time for log
    gettimeofday(&ts, NULL);
    snprintf(timeCh, 25, "%ld.%03ld: ", ts.tv_sec, ts.tv_usec / 1000);

    if (payloadSizeInBytes > 0)
    {
        printf("%s%s\n", timeCh, (char *)payload);
    }

}

void usrPluginLogging(INT32 level, UINT32 type, const char* fmt, va_list args)
{
    char buffer[256];
    const size_t buffer_size = sizeof(buffer) / sizeof(buffer[0]);

    int len = vsnprintf(buffer, buffer_size - 1, fmt, args);
    if (len > 0) {
        len = len < buffer_size ? (len + 1) : buffer_size;
        usrLogging(NULL, level, type, (void*)buffer, len);
    }
}

INT32 usrEventRegister(AWEOSInstance* pAWEOS,  INT32 eventType, UINT32 moduleObjId, INT32 payloadSizeInBytes, void** userHandle)
{
    // This function does nothing, but it could use the eventHandle->userHandle struct
    // to open a file to write events, or whatever else is needed
    printf("Got an event registration callback for objectId %u, eventType %d. Size of event payloads will be %d bytes\n", 
        moduleObjId, eventType, payloadSizeInBytes);

    // Allcoate some dummy stuff to the userHandle(TODO)

    return E_SUCCESS;
}

INT32 usrEventDeregister(AWEOSInstance* pAWEOS, INT32 eventType, UINT32 moduleObjId, void** userHandle)
{
    // This function would normally free any memory allocated by the register function
    printf("Got an event deregistration callback for objectId %u\n", moduleObjId);

    // (TODO) free dummy stuff
    return E_SUCCESS;
}

INT32 usrEventTrigger(AWEOSInstance* pAWEOS, INT32 eventType, UINT32 moduleObjId, void* payload, INT32 payloadSizeInBytes, void* userHandle)
{
    // This function gets called when an event is triggered by an Event Module in the layout. 
    // Normally the BSP would react to specific eventTypes and objectIds in specific 
    // ways (e.g. pass wakeword detection on to another system),
    // but here we are just printing the details of the event, assuming the payload is ASCII characters
    // if eventType is 10. Also one specific objectId case is handled

    struct timeval ts;
    char timeCh[25];

    // Get current time for log
    gettimeofday(&ts, NULL);
    snprintf(timeCh, 25, "%ld.%03ld: ", ts.tv_sec, ts.tv_usec / 1000);    

    if (eventType == 10)
    {
        printf("%sGot an event trigger callback for objectId %u\n    ascii payload: %s\n", timeCh, moduleObjId, (char *)payload);
    }
    else if (moduleObjId == 31111 && payloadSizeInBytes == 2 * sizeof(FLOAT32))
    {
        // Just an example of handling for a specific objectId event (RMS overflow)
        printf("%sGot a RMS overflow event: objectId %u, RMS = %f, threshold = %f\n", timeCh, moduleObjId, ((FLOAT32*)payload)[0], ((FLOAT32*)payload)[1]);
    }
    else
    {
        printf("%sGot an event trigger callback for objectId %u, eventType %d\n", timeCh, moduleObjId, eventType);
    }

    return E_SUCCESS;
}    

void* audioCallbackSimulator(void * args)
{
    // Simple real-time audio simulator. Would be ALSA, PortAudio, etc callback
    // Will not achieve exact realtime interrupts
    struct timespec ts;
    struct timespec ts_tmp;
    long time_nsec;
    long long accumulated_time1;
    long long accumulated_time2;
    long long overshoot = 0.0; 

    (void) args;

    pthread_mutex_lock(&audioThreadMutex);
    audioStarted = 1;
    pthread_cond_signal(&audioThreadCond);
    pthread_mutex_unlock(&audioThreadMutex);

    // Calculate sleep time for fundamental blocksize
    time_nsec = (long) ((float)1000000000L * ((float)configParams.fundamentalBlockSize / configParams.sampleRate));

    ts.tv_sec = 0;
    ts_tmp.tv_sec = 0;
    ts_tmp.tv_nsec = 0;

    // Set this thread to run at real time priority
    int max_priority = sched_get_priority_max(SCHED_FIFO);
    struct sched_param audio_sched_param = {0};
    pthread_t currentHandle = pthread_self();
    int target_priority = max_priority - 2;
    audio_sched_param.sched_priority = target_priority;
    pthread_setschedparam(currentHandle, SCHED_FIFO, &audio_sched_param);

    int policy;
    pthread_getschedparam(currentHandle, &policy, &audio_sched_param);
    if ((SCHED_FIFO != policy) ||
      (audio_sched_param.sched_priority != target_priority)) 
    {
        printf("Warning: Failed to increase priority of audio simulation thread to %d\nTry running as root\n", target_priority);
    }

    while (!exitAudioCallbackThread)
    {
        // Check if the previous pump is active (overflow detection)
        // Workaround for the AWECore overflow detection failure
        if (!pumpActive)
        {
            // Kick off the audio thread
            sem_post(&pumpSem);

            // Might need to post more than once due to clock resolution 
            while (overshoot > time_nsec)
            {        
                overshoot -= time_nsec;
                sem_post(&pumpSem);
            }
        }
        else
        {
            overshoot = 0.0;
        }

        ts.tv_nsec = time_nsec;

        clock_gettime(CLOCK_MONOTONIC, &ts_tmp);
        accumulated_time1 = ((long long)ts_tmp.tv_sec*1000000000) + ts_tmp.tv_nsec + time_nsec;

        while(1)
        {
            clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, NULL);

            clock_gettime(CLOCK_MONOTONIC, &ts_tmp);

            accumulated_time2 = ((long long)ts_tmp.tv_sec*1000000000) + ts_tmp.tv_nsec;

            if (accumulated_time2 >= accumulated_time1)
            {
                overshoot += (accumulated_time2 - accumulated_time1);
                break;
            }
            else
            {
                ts.tv_nsec = (long)(accumulated_time1 - accumulated_time2);
            }
        }
    }

    return NULL;

}


INT32 aweOSuser_audioStart(AWEOSInstance *pAWEOS)
{
    INT32 ret;
    UINT32 layoutInChannels, layoutOutChannels, blockSize;
    FLOAT32 sampleRate;

    // Audio start callback. Can be used to start audio stream from audio framework.
    // Could be ALSA, Pulse, Jack, Portaudio, etc. 

    ret = aweOS_layoutGetChannelCount(pAWEOS, &layoutInChannels, &layoutOutChannels);
    if (E_SUCCESS != ret) 
    {
        printf("Failed to get layout channel counts: ret = %d: %s\n", ret, aweOS_errorToString(ret));
    }

    ret = aweOS_layoutGetBlockSize(pAWEOS, &blockSize);
    if (E_SUCCESS != ret) 
    {
        printf("Failed to get layout block size: ret = %d: %s\n", ret, aweOS_errorToString(ret));
    }   

    ret = aweOS_layoutGetSampleRate(pAWEOS, &sampleRate);
    if (E_SUCCESS != ret) 
    {
        printf("Failed to get layout sample rate: ret = %d: %s\n", ret, aweOS_errorToString(ret));
    }       

    printf("Loaded layout with inChans = %u, outChans = %u, blockSize = %u, sampleRate = %f\n", layoutInChannels, layoutOutChannels, blockSize, sampleRate);    

    // Kick off real-time audio simulation thread
    exitAudioCallbackThread = 0;
    ret = pthread_create(&audioCallbackThreadHandle, NULL, audioCallbackSimulator, NULL);   
    if (0 != ret) 
    {
        printf("Error creating audio callback simulator! ret = %d\n", ret);
        return 0;
    }

    // Reset the count to 0, at the start of audio processing
    count = 0;

    // Wait for thread to have been created
    pthread_mutex_lock(&audioThreadMutex);
    while (1 != audioStarted)
    {
        pthread_cond_wait(&audioThreadCond, &audioThreadMutex);
    }
    pthread_mutex_unlock(&audioThreadMutex);    


    if (!quiet)
    {
        printf("\n\nAudio Started\n");
    }
    return 0;
}


INT32 aweOSuser_audioStop(AWEOSInstance *pAWEOS)
{   
    // Audio stop callback. Can be used to clean up audio stream.
    if (audioStarted)
    {
        INT32 ret;

        exitAudioCallbackThread = 1;
        ret = pthread_join(audioCallbackThreadHandle, NULL);
        if (0 != ret) 
        {
            printf("Failed to join audio simulator thread: ret = %d\n", ret);
        }

        audioStarted = 0;
        ErrMask = false;
        if (!quiet)
        {
            UINT32 avgCycles;
            ret = aweOS_getAverageLayoutCycles(pAWEOS, 0, &avgCycles);
            if (E_SUCCESS != ret) 
            {
                printf("Failed to get average cycles: ret = %d: %s\n", ret, aweOS_errorToString(ret));
            }                   
            printf("\nAudio Stopped\n");
            printf("Processed %llu audio frames with I/O block size of %u -- average cycles: %f\n", count, configParams.fundamentalBlockSize, 
                (avgCycles >> 8) * (configParams.coreSpeed / configParams.profileSpeed));
        }
    }

    return 0;
}


int main(int argc, char **argv)
{
    // Setup signal handler
    if (signal(SIGINT, sig_handler) == SIG_ERR)
    {
        printf("Can't catch SIGINT (%d)\n", SIGINT);
    }

    //Print the DSPC copyright 
    copyright();

    //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); 

    //Tuning port id set to default 15002
    INT32 tuningPort = 15002;

    const char *awbpath = NULL;
    const char *infile = NULL;
    const char *outfile = NULL;

    UINT32 profileStatus = 1;
    UINT32 waitFlag = false;
    UINT32 tlog = false;

    //local variables buffer sizes
    UINT32 layoutInChannels, layoutOutChannels, layoutBlockSize;
    FLOAT32 layoutSampleRate = 0;
    UINT32 inSize, outSize;
    UINT32 i,j;
    INT32 ret;
    enum awe_PluginLoader_Status pluginLoaderStatus;

    // Check if the argc == 1, meaing that there are not input parameters supplied with the program.
    // Print the usage information, to help the user.
    if (1 == argc)
    {
        usage(argv[0]);

    }
    else
    {
        {
            const awe_PluginLoaderMethods methods = {.vlog = usrPluginLogging};
            pluginLoaderStatus = awe_PluginLoader_initWithMethods(0, &methods);
            if (pluginLoaderStatus != AWE_PLUGIN_LOADER_SUCCESS)
            {
                fprintf(stderr, "The plugin loader encountered an error on initialization (%d). Plugin loading is disabled.\n", pluginLoaderStatus);
            }
        }

        printf("\nEntered parameters\n");
        for (i = 1; i < argc; i++)
        {
            const char *arg = argv[i];

            if (0 == strncmp(arg, "-profStatus:", 12))
            {
                profileStatus = atoi(arg + 12);
                printf("profStatus: %u\n", profileStatus);
            }
            else if (0 == strncmp(arg, "-bsize:", 7))
            {
                configParams.fundamentalBlockSize = atoi(arg + 7);
                printf("-bsize:     %u\n",configParams.fundamentalBlockSize);
            }
            else if (0 == strncmp(arg, "-inchans:", 9))
            {
                configParams.inChannels = atoi(arg + 9);
                printf("-inchans:   %u\n",configParams.inChannels);
            }
            else if (0 == strncmp(arg, "-outchans:", 10))
            {
                configParams.outChannels = atoi(arg + 10);
                printf("-outchans:  %u\n",configParams.outChannels);
            }
            else if(0 == strncmp(arg, "-sr:", 4))
            {
                configParams.sampleRate = (float)atof(arg + 4);
                printf("-sr:        %f\n",configParams.sampleRate);
            }           
            else if (0 == strncmp(arg, "-cf:", 4))
            {
                configParams.coreSpeed = (float)atof(arg + 4);
                printf("-cf:        %f\n",configParams.coreSpeed);
            }
            else if (0 == strncmp(arg, "-pf:", 4))
            {
                configParams.profileSpeed = (float)atof(arg + 4);
                printf("-pf:        %f\n",configParams.profileSpeed);
            }
            else if (0 == strncmp(arg, "-load:", 6))
            {
                awbpath = arg + 6;
                printf("-load:      %s\n",awbpath);     
            }
            else if (0 == strncmp(arg, "-in:", 4))
            {
                infile = arg + 4;
                printf("-in:        %s\n",infile);      
            }
            else if (0 == strncmp(arg, "-out:", 5))
            {
                outfile = arg + 5;
                printf("-out:       %s\n",outfile);
            }
            else if (0 == strncmp(arg, "-wait", 5))
            {
                waitFlag = true;
                printf("-wait:      %u\n",waitFlag);
            }
            else if (0 == strncmp(arg, "-tport:", 7))
            {
                tuningPort = atoi(arg + 7);
                printf("-tport:     %d\n",tuningPort);
            }
            else if (0 == strncmp(arg, "-tlog", 5))
            {
                tlog = true;
                printf("-tlog:      %u\n",tlog);
            }
            else if (0 == strncmp(arg, "-hsizefasta:", 12))
            {
                heapSizeFastA = atoi(arg + 12);
                printf("-hsizefasta:     %u\n",heapSizeFastA);
            }
            else if (0 == strncmp(arg, "-hsizefastb:", 12))
            {
                heapSizeFastB = atoi(arg + 12);
                printf("-hsizefastb:     %u\n",heapSizeFastB);
            }
            else if (0 == strncmp(arg, "-hsizeslow:", 11))
            {
                heapSizeSlow = atoi(arg + 11);
                printf("-hsizeslow:      %u\n",heapSizeSlow);
            }
            else if (0 == strncmp(arg, "-quiet", 6))
            {
                quiet = true;
                printf("-quiet:     %u\n",quiet);
            }
            else if (0 == strncmp(arg, "-plugin:", 8))
            {
                const char *plugin = arg + 8;

                if (pluginLoaderStatus == AWE_PLUGIN_LOADER_SUCCESS)
                {
                    enum awe_PluginLoader_Status status = awe_PluginLoader_load(NULL, plugin);
                    if (status == AWE_PLUGIN_LOADER_SUCCESS)
                    {
                        printf("-plugin:    %s (loaded)\n", plugin);
                    }
                    else
                    {
                        printf("-plugin:    %s (ignored... load error %d: %s)\n", plugin, status, awe_PluginLoader_statusToString(status));
                    }
                }
                else
                {
                    printf("-plugin:    %s (ignored... loading disabled)\n", plugin);
                }
            }
            else
            {
                printf("main: unknown option '%s'\n", arg);
            }
        }
    }

    // Error Conditions that need to checked
    // Error1 not in "wait for ever" mode. Input and output files are required to be specified
    if (!waitFlag )
    {
        if ((!awbpath) || (!outfile) || (!infile))
        {
            printf("Please rerun with the missing file arguments defined\n");
            printf("    -load:  %s\n", awbpath ? awbpath : "Missing");
            printf("    -in:    %s\n", infile ? infile : "Missing");
            printf("    -out:   %s\n", outfile ? outfile : "Missing");
            exit(1);
        }
    }

    if (!quiet)
    {
        printf("\naweOS initialised with the following parameters\n");
        printf("Name:       %s\n",configParams.pName);
        printf("-cf:        %f Hz\n",configParams.coreSpeed);
        printf("-pf:        %f Hz\n",configParams.profileSpeed);
        printf("num of Threads:%u\n",configParams.numThreads);
        printf("-sr:        %f Hz\n",configParams.sampleRate);
        printf("-bsize:     %u\n",configParams.fundamentalBlockSize);
        printf("-inchans:   %u\n",configParams.inChannels);
        printf("-outchans:  %u\n",configParams.outChannels);
        printf("-tport:     %d\n",tuningPort);
        printf("-hsizefasta:     %u\n",heapSizeFastA);
        printf("-hsizefastb:     %u\n",heapSizeFastB);
        printf("-hsizeslow:      %u\n",heapSizeSlow);
        if (profileStatus)
        {
            printf("-profStatus: Profiling is enabled\n");
        }
        else 
        {
            printf("-profStatus: Profiling is disabled\n");
        }

        if (waitFlag)
        {
            printf("-wait:      Set up the integrated tuning interface and wait for the designer to connect\n");
        }
        else 
        {
            printf("-wait:      No tuning interface. Process the audio i/o files and the supplied design\n");
        }

        if (tlog)
        {
            printf("-tlog:      Tuning log is enabled\n");
        }
        else 
        {
            printf("-tlog:      Tuning log is disabled\n");
        }

        printf("The following i/o files are used\n");
        printf("-load:      %s\n",awbpath ? awbpath : "undefined");
        printf("-in:        %s\n",infile ? infile : "undefined");
        printf("-out:       %s\n",outfile ? outfile : "undefined");
    }   


    // Larger packet buffer size can improve tuning interface speed
    configParams.packetBufferSize = 4105;

    //Allocate a fastheapA 
    fastHeapA = malloc(heapSizeFastA * sizeof(UINT32));
    configParams.pFastHeapA = fastHeapA;
    configParams.fastHeapASize = heapSizeFastA;

    //Allocate a fastheapB
    fastHeapB = malloc(heapSizeFastB * sizeof(UINT32));
    configParams.pFastHeapB = fastHeapB;
    configParams.fastHeapBSize = heapSizeFastB;

    //Allocate a slowheap
    slowHeap  = malloc(heapSizeSlow  * sizeof(UINT32));
    configParams.pSlowHeap = slowHeap;
    configParams.slowHeapSize = heapSizeSlow;

    printf("\n\n");
    if (true == waitFlag)
    { 
        configParams.cbAudioStart = aweOSuser_audioStart;
        configParams.cbAudioStop = aweOSuser_audioStop;

        pthread_mutex_init(&audioThreadMutex, NULL);
        pthread_cond_init (&audioThreadCond, NULL);     

        sem_init(&pumpSem, 0, 0);
    }

    //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) 
    {
        if (!quiet)
            printf("aweOS Initialised\n\n");
    }
    else 
    {
        printf("aweOS init failed. exiting application with error = %d %s\n",ret, aweOS_errorToString(ret));
        exit(1);
    }

    // After the AWEOSInstance is init. set the profiling status
    ret = aweOS_setProfilingStatus(g_AWEOSInstance, profileStatus);
    if (E_SUCCESS == ret) 
    {   
        if (!quiet)
        {
            printf("aweOS profiling is disabled\n");
        }

    }
    else 
    {
        printf("aweOS_setProfilingStatus: profiling status set failed. exiting application with error = %d %s\n",ret, aweOS_errorToString(ret));
        exit(1);
    }

    // Register logging callback for framework log messages
    aweOS_registerLoggingCallback(g_AWEOSInstance, usrLogging, AWE_LOG_LEVEL_INFO, AWE_LOG_ALL_TYPE_MASK);
    if (ret) 
    {   
        if (!quiet)
        {
            printf("Failed to register logging callback, ret = %d %s\n", ret, aweOS_errorToString(ret));
        }

    }

    // Register event callbacks that can be triggered by Event Modules in the layout
    ret = aweOS_registerEventCallbacks(g_AWEOSInstance, usrEventTrigger, usrEventRegister, usrEventDeregister);
    if (ret) 
    {   
        if (!quiet)
        {
            printf("Failed to register event callbacks, ret = %d %s\n", ret, aweOS_errorToString(ret));
        }

    }


    if (tlog)
    {
        ret = aweOS_tuningLoggingEnable(g_AWEOSInstance, NULL, NULL, TUNING_LOG_INFO);
        if (E_SUCCESS == ret) 
        {   
            if (!quiet)
            {
                printf("aweOS integrated tuning interface logging enabled, with the mode set to TUNING_LOG_INFO\n");
            }

        }
        else 
        {
            printf("aweOS_tuningLoggingEnable: failed with the error = %d %s\n",ret, aweOS_errorToString(ret));
        }
    }

    // Register loaded plugins
    {
        size_t pluginCount = awe_PluginLoader_count();
        for (size_t i = 0; i < pluginCount; i++)
        {
            const AWEPlugin *plugin = NULL;
            enum awe_PluginLoader_Status status = awe_PluginLoader_get(&plugin, i);
            if (status == AWE_PLUGIN_LOADER_SUCCESS)
            {
                ret = aweOS_appendModules(g_AWEOSInstance, plugin->modules.count, plugin->modules.array);
                if (ret != 0)
                {
                    return ret;
                }
            }
        }
    }

    if ( NULL != awbpath )
    {
        UINT32 position;
        fin = fopen(awbpath, "rb");     
        if (NULL == fin )
        {
            printf("Error opening input file %s\n", awbpath);
            printf("Error string: %s \nPlease check the path\n", strerror(errno));
            exit(1);
        }

        //Load the AWB from the file
        ret = aweOS_loadAWBFile(g_AWEOSInstance,awbpath, &position);
        if (E_SUCCESS == ret) 
        {
            if (!quiet)
            {
                printf("The layout %s loaded with parameters\n", awbpath);
            }
        }
        else 
        {
            printf("The layout %s download unsuccessful in the positions %u with Error = %d \n", awbpath, position, ret);
            exit(1);
        }

        // Get the layout I/O configuration Input, Output and block size
        ret = aweOS_layoutGetChannelCount(g_AWEOSInstance, &layoutInChannels, &layoutOutChannels);
        if (E_SUCCESS != ret)
        {
            printf("Error: aweOS_layoutGetChannelCount failed: error = %d %s\n", ret, aweOS_errorToString(ret));
            exit(1);
        }

        ret = aweOS_layoutGetBlockSize(g_AWEOSInstance, &layoutBlockSize);
        if (E_SUCCESS != ret)
        {
            printf("Error: aweOS_layoutGetBlockSize failed: error = %d %s\n", ret, aweOS_errorToString(ret));
            exit(1);
        }
        ret = aweOS_layoutGetSampleRate(g_AWEOSInstance, &layoutSampleRate);
        if (E_SUCCESS != ret)
        {
            printf("Error: aweOS_layoutGetSampleRate failed: error = %d %s\n", ret, aweOS_errorToString(ret));
            exit(1);
        }
        if (!quiet)
        {
            printf("sr:       %f\ninchans:  %u\noutchans: %u\nbsize:    %u\n\n", layoutSampleRate, layoutInChannels, layoutOutChannels, layoutBlockSize);
        }


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

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

    }

    if (true == waitFlag)
    {
        //Prepare the stereo input and output buffers for the waitFlag == true condition
        // The I/O buffers are allocated based on the target info / configParams 
        inSize = configParams.inChannels * configParams.fundamentalBlockSize;
        outSize = configParams.outChannels * configParams.fundamentalBlockSize;

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

#ifndef PI
#define PI 3.141592653589793
#endif 
    // Fill audio input buffers with sin waves scaled by -12 dB
        for (i = 0; i < configParams.fundamentalBlockSize; i++)
        {
            for (j = 0; j < configParams.inChannels; j++) 
            {
                inputBuffer[i * configParams.inChannels + j] = float_to_fract32(sinf(2.f*PI*(j+1)*(configParams.sampleRate/configParams.fundamentalBlockSize) * (i / configParams.sampleRate))) >> 2;
            }
        }

        //Open the aweOS integrated tuning interface. Note that this cannot be called before a succesful initialization. If called without succesful init, will fail/
        ret = aweOS_tuningSocketOpen(&g_AWEOSInstance, tuningPort, 1);
        if (E_SUCCESS != ret)
        {
            printf("Failed to open aweOS integrated tuning interface on Port number: %d with the error = %d %s \n", tuningPort, ret,aweOS_errorToString(ret));
        }
        else
        {
            if (!quiet)
            {
                printf("aweOS integrated tuning interface is open on Port number: %d\n", tuningPort);
            }
        }

        // Set this thread to run at real time priority
        int max_priority = sched_get_priority_max(SCHED_FIFO);
        struct sched_param audio_sched_param = {0};
        pthread_t currentHandle = pthread_self();
        int target_priority = max_priority - 3;     // let the audio simulator run at a higher priority
        audio_sched_param.sched_priority = target_priority;
        pthread_setschedparam(currentHandle, SCHED_FIFO, &audio_sched_param);

        int policy;
        pthread_getschedparam(currentHandle, &policy, &audio_sched_param);
        if ((SCHED_FIFO != policy) ||
          (audio_sched_param.sched_priority != target_priority)) 
        {
            printf("Warning: Failed to increase priority of audio thread to %d\nTry running as root\n", target_priority);
        }

        while (1)
        {
            // Wait for signal to run thread
            sem_wait(&pumpSem);

            // Set the pumpActive global flag
            pumpActive = 1;

            if (aweOS_audioIsStarted(g_AWEOSInstance) && aweOS_layoutIsValid(g_AWEOSInstance))
            {

                for (i = 0; i < configParams.inChannels ; i++)
                {
                    // Import new samples
                    ret = aweOS_audioImportSamples(g_AWEOSInstance, &inputBuffer[i], configParams.inChannels, i, Sample32bit);
                    if (E_SUCCESS != ret)
                    {  
                        printf("Error: aweOS_audioImportSamples() failed: error = %d %s \n", ret,  aweOS_errorToString(ret));
                    }
                }

                ret = aweOS_audioPumpAll(g_AWEOSInstance);
                if (E_SUCCESS != ret)
                {   
                    if (ErrMask == 0)
                    {
                        printf("Warning: aweOS_audioPumpAll(): %d %s \n", ret, aweOS_errorToString(ret));
                        ErrMask = true;
                    }   
                }

                for (i = 0; i < configParams.outChannels ; i++)
                {
                    // Export samples
                    ret = aweOS_audioExportSamples(g_AWEOSInstance, &outputBuffer[i], configParams.outChannels, i, Sample32bit);
                    if (E_SUCCESS != ret)
                    {  
                        printf("Error: aweOS_audioExportSamples() failed: error = %d %s \n", ret, aweOS_errorToString(ret));
                    }
                }                   
                count++;
            }

            // Clear the pumpActive global flag
            pumpActive = 0;
        }
        return 0;

    } 
    else  // if (true != waitFlag)
    {
        // In the option, the input .wav file is process and out put is coppied into a output .wav file
        // Input channels sample rate and sample size are derived from the input .wav file 
        // Output channels are derived from the layout.
        INT32 numSamplesRead = 0;
        UINT32 wfNumChannels=0 , wfSampleSize =0, wfNumSamples = 0, outSampleSize = 0;
        FLOAT32 wfSampleRate=0;
        SampleType wfsampleType, outsampleType;
        UINT32 chOffset=0;

        ret = aweOS_wavFileOpen(infile, &wfSampleRate, &wfNumChannels, &wfSampleSize, &wfNumSamples, &fin);
        if (E_SUCCESS != ret)
        {
            printf("Error opening input file %s return with error: %d %s\n", infile, ret, aweOS_errorToString(ret));
            exit(1);
        }
        else
        {
            if (!quiet)
            {
                printf("Opening input file %s with paramerters\n", infile);
                printf("sr:           %f \nchannels:     %u \nsampleWidth:  %u \nTotalSamples: %u\n\n", wfSampleRate, wfNumChannels ,wfSampleSize, wfNumSamples);
            }
        }
        //Check for some paramters incomming from the i/o wave file againt the layout parameters
        if (wfSampleRate != layoutSampleRate)
        {
            printf("Warning: Mismatch in sampleRate \nInput file %s sr: %f and Layout %s sr: %f\n",infile, wfSampleRate, awbpath, layoutSampleRate);
        }

        if (wfNumChannels != layoutInChannels)
        {
            printf("Warning: Mismatch in number of input channels \nInput file %s inchans: %u and Layout %s inchans: %u\n",infile, wfNumChannels, awbpath, layoutInChannels );
        }

        if (4 == wfSampleSize)
        {
            wfsampleType = Sample32bit;
        }
        else if (2 == wfSampleSize)
        {
            wfsampleType = Sample16bit;
        }
        else
        {
            printf("Error processing input file %s unspported sample type: %u\n", infile, wfSampleSize);
            printf("Currently only 2 bytes and 4 bytes sample sizes supported\n");
            exit(1);
        }
        // These outsampleType and outSampleSize are used to create the .wav output. export samples etc
        outsampleType = wfsampleType;
        outSampleSize = wfSampleSize;

        // Create the output file with the following parameters
        // number of channels = Layout output channels
        // sample rate = input file sample rate (input .wav)
        // sample size = input sample size (input .wav)
        ret = aweOS_wavFileCreate(outfile, wfSampleRate, layoutOutChannels, outSampleSize, &fout);
        if (E_SUCCESS != ret)
        {
            printf("\nError creating the output file %s return with error: %d %s\n", outfile, ret , aweOS_errorToString(ret));
            exit(1);
        }
        else
        {
            if (!quiet)
            {
                printf("\nCreating the output file %s with paramerters\n", outfile);
                printf("sr:          %f (from input .wav)\nchannels:    %u (from layout)\nsampleWidth: %u (from input .wav)\n", wfSampleRate, layoutOutChannels, outSampleSize);
            }
        }

        //Prepare the stereo input and output buffers for the waitFlag != true condition
        //The I/O buffers are allocated based on size of data coming from the the input .wav file and layout
        // inputbuffer : based of the no of incoming channels from the input .wav file
        // outpubuffer : based  on the the no of output channels in the layout
        inSize = wfNumChannels * configParams.fundamentalBlockSize;
        outSize = layoutOutChannels * configParams.fundamentalBlockSize;

        inputBuffer1 = malloc(inSize * wfSampleSize);
        outputBuffer1 = malloc(outSize * outSampleSize);

        //Process the input data
        if (!quiet)
        {
            printf("\nStarting to process [%s] into [%s]\n\n", infile, outfile);
        }

        while ((numSamplesRead = aweOS_wavFileRead(fin, inputBuffer1, inSize, wfSampleSize)) > 0) 
        {
            if (aweOS_audioIsStarted(g_AWEOSInstance) && aweOS_layoutIsValid(g_AWEOSInstance))
            {   
                for (i = 0, chOffset = 0; i < wfNumChannels; i++, chOffset += wfSampleSize) 
                {   
                    if (Sample32bit == wfsampleType) 
                    {
                        ret = aweOS_audioImportSamples(g_AWEOSInstance, (INT32 *)(inputBuffer1 + chOffset), wfNumChannels, i, wfsampleType);
                    }
                    else // Sample16bit                     
                    {
                        ret = aweOS_audioImportSamples(g_AWEOSInstance, (INT16 *)(inputBuffer1 + chOffset), wfNumChannels, i, wfsampleType);
                    }

                    if (E_SUCCESS != ret)
                    {
                        printf("Error: aweOS_audioImportSamples() failed: error = %d %s exiting application\n", ret, aweOS_errorToString(ret));
                        exit(1);
                    }
                }

                ret = aweOS_audioPumpAll(g_AWEOSInstance);  
                if (E_SUCCESS != ret)
                {  
                    if (ErrMask == false)
                    {
                        printf("Warning: aweOS_audioPumpAll(): %d %s \n", ret, aweOS_errorToString(ret));
                        ErrMask = true;
                    }   
                }               

                for (i = 0, chOffset = 0; i < layoutOutChannels; i++, chOffset += outSampleSize) 
                {
                    if (Sample32bit == outsampleType)
                    {
                        ret = aweOS_audioExportSamples(g_AWEOSInstance, (INT32 *)(outputBuffer1 + chOffset), layoutOutChannels, i, outsampleType);
                    }
                    else // Sample16bit
                    {
                        ret = aweOS_audioExportSamples(g_AWEOSInstance, (INT16 *)(outputBuffer1 + chOffset), layoutOutChannels, i, outsampleType);
                    }

                    if (E_SUCCESS != ret)
                    {
                        printf("Error: aweOS_audioExportSamples() failed: error = %d %s exiting application\n", ret, aweOS_errorToString(ret));
                        exit(1);
                    }
                }               

                count++;
                ret = aweOS_wavFileWrite(fout, outputBuffer1, outSize, outSampleSize);
            }
        }// end of while

        printf("\n");   
        printf("Processed Audio Frames: %llu (block size %u)copied it to output file: %s\n", count, configParams.fundamentalBlockSize, outfile);
        //Clean up
        destroyApp();

        ret = aweOS_wavFileClose(fin);
        if (E_SUCCESS != ret) 
        {   
            printf("aweOS_wavFileClose: failed with the error = %d %s\n", ret, aweOS_errorToString(ret));
        }

        ret = aweOS_wavFileClose(fout);
        if (E_SUCCESS != ret) 
        {   
            printf("aweOS_wavFileClose: failed with the error = %d %s\n", ret, aweOS_errorToString(ret));
        }        
    } // end of if (true != waitFlag)

    return 0;
} // end of main ()

Filename: Libtester.c


Updated on 2026-02-10 at 15:44:54 -0500