Main Page | Modules | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals | Related Pages

FEAPI Host Documentation

Introduction

This documentation is a short introduction about how a host for the Feature Extraction plugin API can be implemented, using the C-API directly. For information about the Feature Extraction plugin API itself, please refer to the "FEAPI Documentation".
Please note that the implementation shows only how a fast implementation can be done: there might be many alternative and cleaner ways to implement such an host.



External dependency

This particular host application example uses libsndfile for all operations on audio files. This library is not included in the FEAPI package itself and has to be downloaded separately (see http://www.mega-nerd.com/libsndfile/).
Once you downloaded and compiled the libsndfile to a static library (see the libsndfile docs), copy over the following files into the FEAPI tree:

Host implementation using the C interface

The following code snippets should give you an example of the calling conventions etc. of such a host. The complete code can be found in the example file FEAPIExampleHost_C.cpp.
First, both the standard FEAPI directory and the current working directory are searched for plugin DLLs with the local function FindPlugins, as declared in FEAPIHostUtilities.h (to parse the working directory is a simplified method; note that the specific directories to be parsed by a host should comply to the platform specific recommendation in the API documentation and should probably also contain other directories specified by the user):

    // find plugins in directory
    iNumPlugins     = FindPlugins (&stPluginFileNames);

For the plugin to be selected for processing, the library can be loaded with the function LoadPluginModule and the API function pointers can be retrieved with the function GetFunctionPointers, both declared in FEAPIHostUtilities.h:

    hLibraryHandle  = 0;
    LoadPluginModule (pCurrentPlugin->acFilename, &hLibraryHandle);
    if (!hLibraryHandle)
        return -1;
    else
        GetFunctionPointers (hLibraryHandle, &stPluginFunctions);

Function GetFunctionPointers verifies the API compliance and writes the function pointers to ::stPluginFunctions.
Now we are ready to create a new instance of the plugin:

    // create plug instance 
    fprintf (stdout, "Opening new plugin instance...");
    if (stPluginFunctions.pFunCreateInstance (   &hPluginInstance) == FEAPI_kNoError)
        fprintf (stdout, "  Succeeded\n");
    else
        fprintf (stdout, "  Failed\n");

After that, information about some basic plugin properties can be retrieved:

    fprintf (stdout, "Plugin API version: %d.", pCurrentPlugin->iMajorVersion);
    fprintf (stdout, "%d.", stPluginFunctions.pFunGetApiVersion ( FEAPI_kMinorVersion));
    fprintf (stdout, "%d\n", stPluginFunctions.pFunGetApiVersion ( FEAPI_kSubVersion));
    
    fprintf (stdout, "Minimum supported sample rate: %1.1e\n", stPluginFunctions.pFunGetPluginProperty (hPluginInstance, FEAPI_kMinSampleRate));
    fprintf (stdout, "Maximum supported sample rate: %1.1e\n", stPluginFunctions.pFunGetPluginProperty (hPluginInstance, FEAPI_kMaxSampleRate));
    fprintf (stdout, "Minimum number of supported channels: %u\n", (int)stPluginFunctions.pFunGetPluginProperty (hPluginInstance, FEAPI_kMinChannels));
    fprintf (stdout, "Maximum number of supported channels: %u\n", (int)stPluginFunctions.pFunGetPluginProperty (hPluginInstance, FEAPI_kMaxChannels));
    fprintf (stdout, "Minimum supported frame size: %u\n", (int)stPluginFunctions.pFunGetPluginProperty (hPluginInstance, FEAPI_kMinFrameSize));
    fprintf (stdout, "Maximum supported frame size: %u\n", (int)stPluginFunctions.pFunGetPluginProperty (hPluginInstance, FEAPI_kMaxFrameSize));
    fprintf (stdout, "Preferred frame size: %d\n", (int)stPluginFunctions.pFunGetPluginProperty (hPluginInstance, FEAPI_kOptFrameSize));

With the available information it is now possible to initialize the plugin:

    fprintf (stdout, "Initializing new plugin instance...");
    if (stPluginFunctions.pFunInitializePlugin (   hPluginInstance, 
                               (float)sfInputInfo.samplerate, 
                               sfInputInfo.channels,
                               pCurrentPlugin->iMajorVersion,
                               0) == FEAPI_kNoError)
        fprintf (stdout, "  Succeeded\n");
    else
        fprintf (stdout, "  Failed\n");

and to request detailed information about the plugin parameters:

    stPluginFunctions.pFunGetPluginName (hPluginInstance, acResult);
    fprintf (stdout, "Plugin Name: %s\n", acResult);
    
    stPluginFunctions.pFunGetPluginId (hPluginInstance, acResult);
    fprintf (stdout, "Plugin Id: %s\n", acResult);

    stPluginFunctions.pFunGetPluginVendor (hPluginInstance, acResult);
    fprintf (stdout, "Plugin Vendor: %s\n", acResult);

    fprintf (stdout, "Plugin Vendor version: %d.", stPluginFunctions.pFunGetPluginVendorVersion (hPluginInstance, FEAPI_kMajorVersion));
    fprintf (stdout, "%d.", stPluginFunctions.pFunGetPluginVendorVersion (hPluginInstance, FEAPI_kMinorVersion));
    fprintf (stdout, "%d\n", stPluginFunctions.pFunGetPluginVendorVersion (hPluginInstance, FEAPI_kSubVersion));

    stPluginFunctions.pFunGetPluginCopyright (hPluginInstance, acResult);
    fprintf (stdout, "Plugin Copyright: %s\n", acResult);

    stPluginFunctions.pFunGetPluginDescription (hPluginInstance, acResult);
    fprintf (stdout, "Plugin Description: %s\n", acResult);
    
    iNumInputs = stPluginFunctions.pFunGetNumberOfInputs (hPluginInstance);
    fprintf (stdout, "Number of input channels: %d\n", iNumInputs);

    for (i = 0; i < iNumInputs; i++)
    {
        stPluginFunctions.pFunGetInputDescription (hPluginInstance, i, &stSignalDescription);
        fprintf (stdout, "Information about the input %d:\n", i);
        fprintf (stdout, "\tInput name: %s\n", stSignalDescription.acName);
        fprintf (stdout, "\tInput description: %s\n", stSignalDescription.acDescription);
        fprintf (stdout, "\tInput unit: %s\n", stSignalDescription.acUnit);
        fprintf (stdout, "\tInput range: %e - %e\n", stSignalDescription.fRangeMin, stSignalDescription.fRangeMax);
        fprintf (stdout, "\tInput sample rate: %f\n", stSignalDescription.fSampleRate);
        fprintf (stdout, "\n");
    }
    
    iNumParameters = stPluginFunctions.pFunGetNumberOfParameters (hPluginInstance);
    fprintf (stdout, "Number of parameters: %d\n", iNumParameters);

    for (i = 0; i < iNumParameters; i++)
    {
        stPluginFunctions.pFunGetParameterDescription (hPluginInstance, i, &stParameterDescription);
        fprintf (stdout, "Information about the parameter %d:\n", i);
        fprintf (stdout, "\tParameter name: %s\n", stParameterDescription.acName);
        fprintf (stdout, "\tParameter description: %s\n", stParameterDescription.acDescription);
        fprintf (stdout, "\tParameter unit: %s\n", stParameterDescription.acUnit);
        fprintf (stdout, "\tParameter range: %e - %e\n", stParameterDescription.fRangeMin, stParameterDescription.fRangeMax);
        fprintf (stdout, "\tParameter default: %e\n", stParameterDescription.fDefaultValue);
        fprintf (stdout, "\tParameter quantized to: %e\n", stParameterDescription.fQuantizedTo);
        fprintf (stdout, "\tParameter changeable in real-time: %s\n", (stParameterDescription.bIsChangeableInRealTime)? "Yes" : "No");
        fprintf (stdout, "\n");
    }

Then, the actual processing can take place. Since in this host implementation the input buffer size does not matter, we ask the plugin about its preferred buffer size. Therefore, we call

        iNumOfFramesNeeded  = (int)stPluginFunctions.pFunGetPluginProperty (hPluginInstance, 
                                                                       FEAPI_kOptFrameSize);

In the next step, the process function can be called with the requested amount of input audio data:

        //processing
        stPluginFunctions.pFunProcess (  hPluginInstance, 
                                        (const float**)ppfDataSorted, 
                                        ptInputTimeStamp,
                                        iNumFramesRead);

Now, the current results can be retrieved, if available. First, the size of the results is queried to assure that the host buffers have sufficient size to hold the result values. Then, all results are retrieved and printed to an output text file if requested:

        // get results
        for (i = 0; i < iNumResults; i++)
        {
            // get size of result with index i
            while ((iValue = stPluginFunctions.pFunGetSizeOfResult (hPluginInstance, i) > 0))
            {
                // adjust memory allocation if required (make sure this is not called often)
                if (iValue > iMaxResultSizeInValues)
                {
                    iMaxResultSizeInValues  = iValue;
                    ppfResult[i]            = (float*) realloc (ppfResult[i], sizeof(*ppfResult[i]) * iMaxResultSizeInValues);
                }
                
                // get results
                stPluginFunctions.pFunGetResult (   hPluginInstance, 
                                                    i, 
                                                    ppfResult[i], 
                                                    &tOutputTimeStamp);
                
                // print result to text file if requested
                if (pFOutputFile)
                {
                    for (j = 0; j < iValue; j++)
                        fprintf (pFOutputFile, "\t%1.10g", ppfResult[i][j]);
                    fprintf (pFOutputFile, "\n");
                }

After all audio data has been processed and no more audio data is available, the plugin should be noticed about this circumstance:

    // no new audio data available or canceled by user; let the plug notice...
    stPluginFunctions.pFunProcessDone (hPluginInstance);

After this, the last results can be retrieved (if available) in the same way as described above. Finally, the plugin instance can be destroyed and the library unloaded:

    fprintf(stdout, "\nDestroying plugin instance...");
    if (stPluginFunctions.pFunDestroyInstance (&hPluginInstance) == 0)
        fprintf (stdout, "  Succeeded\n");
    else
        fprintf (stdout, "  Failed\n");

    UnloadPluginModule (hLibraryHandle);





Contact

web: http://feapi.sourceforge.net
feapi mailing list: feapi-discussion@lists.sourceforge.net

Generated on Fri Mar 23 10:28:52 2007 for FEAPI Host Documentation by  doxygen 1.3.9.1