ASX Version4.13.09

dual_mono_record/main.c

This is an example of how to use the ASX Recorder to record dual mono inputs.All record streams on AudioScience audio adapters record, at a minimum, either mono or stereo files on the same device. Mono recording always records the left channel to an audio file. So to record the right channel of a line in, the channels must be swapped somewhere in the record path. This can be done using the Channel Mode control that is present on the record node of most AudioScience adapters.

Configuration Steps

The following steps should be performed to setup recording of 4 independent mono streams. We are going to record in the following configuration:

Record 1 <- Line In 1 Left
Record 2 <- Line In 1 Right
Record 3 <- Line In 2 Left
Record 4 <- Line In 2 Right

1. Find multiplexer controls on Record nodes and set sources as follows:

Record 1 <- Line In 1
Record 2 <- Line In 1
Record 3 <- Line In 2
Record 4 <- Line In 2

2. Find channel mode controls and set up as follows:

Record 1, Channel Mode = "normal"
Record 2, Channel Mode = "swap"
Record 3, Channel Mode = "normal"
Record 4, Channel Mode = "swap"

3. Open record devices

4. Set record streams to record 4 mono files

5. Start recording.

These instructions remain the same whether the functionality is implemented with Microsoft Multimedia waveXXXX() and mixerXXX() calls, HPI or ASX calls. The next section details ASX recording instructions.

/* $Header: /home/eliot/asi/repo/cvsrepo/Repository/apps/asx/examples/dual_mono_record/main.c,v 1.5 2004/10/13 18:16:08 as-tfe Exp $ */
#include "stdio.h"
#include "stdlib.h"
#include "asx.h"
#include "asxstring.h"

ASX_HANDLE hSystem=0;

int CheckError(ASX_HANDLE hObj, int nLine);
void PrintControlName(ASX_HANDLE hControl);

int main(int argc, char* argv[])
{
    char *pszName;
    ASX_HANDLE hAdapter;
    ASX_HANDLE hMixer;
    ASX_HANDLE hRecorder[4];
    ASX_HANDLE hChannelMode[4];
    ASX_HANDLE hMux[4];
    int nAdapterToUse=0;
    int i,nLen;
    char szFilenames[][16]={ "test1.wav","test2.wav","test3.wav","test4.wav"};

    // create the system
    ASX_System_Create(ASX_SYSTEM_TYPE_HPI,&hSystem);
    CheckError(hSystem, __LINE__);

    // get the adapter
    ASX_System_GetAdapter(hSystem,nAdapterToUse,&hAdapter);
    CheckError(hAdapter, __LINE__);

    ASX_Adapter_GetName(hAdapter,0,0,&nLen);
    CheckError(hAdapter, __LINE__);
    pszName = (char *)malloc(nLen);
    ASX_Adapter_GetName(hAdapter,pszName,nLen,&nLen);
    CheckError(hAdapter, __LINE__);
    printf("Adapter [%d] is %s \n", nAdapterToUse,pszName);

    // get the mixer handle
    ASX_Adapter_GetMixer( hAdapter, &hMixer );
    CheckError(hAdapter, __LINE__);

    // Grab a recorder, channel mode and mux control for each recorder.
    for(i=0; i<4; i++)
    {
        // get a record object
        ASX_Mixer_GetControlByNodeTypeAndIndex(
            hMixer,
            0,0,
            asxNODE_RECORDER,i,
            asxCONTROL_RECORDER,
            &hRecorder[i]);
        CheckError(hMixer, __LINE__);

        // print out some control details
        PrintControlName(hRecorder[i]);

        // get multiplexer object
        ASX_Mixer_GetControlByNodeTypeAndIndex(
            hMixer,
            0,0,
            asxNODE_RECORDER,i,
            asxCONTROL_MULTIPLEXER,
            &hMux[i]);
        CheckError(hMixer, __LINE__);

        // set the multiplexer to the correct line in
        switch(i)
        {
            case 0:
            case 1:
                ASX_Multiplexer_Set( hMux[i], asxNODE_LINE_IN, 0);
                CheckError(hMux[i], __LINE__);
                break;
            case 2:
            case 3:
                ASX_Multiplexer_Set( hMux[i], asxNODE_LINE_IN, 1);
                CheckError(hMux[i], __LINE__);
                break;
        }

        // get channel mode object
        ASX_Mixer_GetControlByNodeTypeAndIndex(
            hMixer,
            0,0,
            asxNODE_RECORDER,i,
            asxCONTROL_CHANNEL_MODE,
            &hChannelMode[i]);
        CheckError(hMixer, __LINE__);

        // set the channel mode
        switch(i)
        {
            case 0:
            case 2:
                ASX_ChannelMode_Set( hChannelMode[i], asxCHANNELMODE_NORMAL);
                CheckError(hChannelMode[i], __LINE__);
                break;
            case 1:
            case 3:
                ASX_ChannelMode_Set( hChannelMode[i], asxCHANNELMODE_SWAP);
                CheckError(hChannelMode[i], __LINE__);
                break;
        }
    }

    // open the player and pass in the file to be played
    for(i=0; i<4; i++)
    {
        printf("Open recorder %d\n",i);
        ASX_Recorder_Open(
            hRecorder[i], 
            szFilenames[i],
            asxFILE_FORMAT_WAV,     // file format
            asxFILE_MODE_CREATE,    // file mode (create vs append)
            1,                      // channels = 1 or 2 at present
            asxAUDIO_FORMAT_PCM16,  // sample format
            44100,                  // sample rate = 8000 to 192000 Hz
            0,                      // 8000 to 384000 bps (MPEG only)
            asxRECORD_MODE_DONT_CARE    // MPEG mode
            );
        CheckError(hRecorder[i], __LINE__);
    }

    // start recording all files
    for(i=0; i<4; i++)
    {
        ASX_Recorder_Start( hRecorder[i] );
        CheckError(hRecorder[i], __LINE__);
    }

    // wait for recording completion
    printf("Hit enter to end recording\n");
    getchar();

    for(i=0; i<4; i++)
    {
        ASX_Recorder_Stop( hRecorder[i] );
        CheckError(hRecorder[i], __LINE__);
    }

    printf("Recording complete.\n");

    // close the file being recorded
    for(i=0; i<4; i++)
    {
        ASX_Recorder_Close(hRecorder[i]);
        CheckError(hRecorder[i], __LINE__);
    }

    printf("Press ENTER to exit\n");
    getchar();
    ASX_System_Delete(hSystem);
    return 0;
}

void PrintControlName(ASX_HANDLE hControl)
{
    char *pszName;
    int nLen;
    enum asxCONTROL eControl;

    ASX_Control_GetType(hControl, &eControl);
    ASXSTRING_EnumToString(eControl,0,0,&nLen);
    pszName=(char *)malloc(nLen);
    ASXSTRING_EnumToString(eControl,pszName,nLen,&nLen);
    printf("Control : %s\n",pszName);

    free(pszName);
}

int CheckError(ASX_HANDLE hObj, int nLine)
{
    int nError;
    int asxSubSystemErrorCode=0;
    char *pszAsxErrorString;
    char *pszAsxSubSystemErrorString;
    int nLen1,nLen2;

    ASX_Error_GetLast( hObj, &nError, &asxSubSystemErrorCode);
    if(!nError)
        return 0;
    ASX_Error_GetLastString( hObj, 0,0,&nLen1,0,0,&nLen2);
    pszAsxErrorString = (char *)malloc(nLen1);
    pszAsxSubSystemErrorString = (char *)malloc(nLen2);
    ASX_Error_GetLastString( hObj, pszAsxErrorString,nLen1,&nLen1,pszAsxSubSystemErrorString,nLen2,&nLen2);
    printf("Error: #%d, %s - Subsystem Error: #%ld, %s \n",
        nError,
        pszAsxErrorString,
        asxSubSystemErrorCode,
        pszAsxSubSystemErrorString );
    printf("When called from source %s line %d\n",__FILE__,nLine);

    printf("Press ENTER to exit\n");
    getchar();
    free(pszAsxErrorString);
    free(pszAsxSubSystemErrorString);
    ASX_System_Delete(hSystem);
    exit(1);
    return 1;
}