Commit 6206d93f authored by Archit Tamarapu's avatar Archit Tamarapu
Browse files

add support for a panning matrix in CLI via a text file

parent 09a68043
Loading
Loading
Loading
Loading
Loading
+142 −12
Original line number Diff line number Diff line
@@ -133,10 +133,12 @@ typedef struct
    bool sceneDescriptionInput;
    float inputGainGlobal; /* Linear gain (not in dB) */
#ifdef REND_CFG_LFE
    bool pan_lfe;
    bool lfePanningEnabled;
    float lfeConfigGain; /* Linear gain (not in dB) */
    float lfeConfigAzimuth;
    float lfeConfigElevation;
    bool lfeCustomRoutingEnabled;
    char inLfePanningMatrixFile[RENDERER_MAX_CLI_ARG_LENGTH];
#endif
} CmdlnArgs;

@@ -152,7 +154,12 @@ typedef enum
    CmdLnOptionId_renderConfigFile,
    CmdLnOptionId_noDiegeticPan,
    CmdLnOptionId_orientationTracking,
#ifdef REND_CFG_LFE
    CmdlnOptionId_lfePosition,
    CmdlnOptionId_lfeMatrix,
#else
    CmdLnOptionId_customLfeRouting,
#endif
    CmdLnOptionId_noDelayCmp,
    CmdLnOptionId_quietModeEnabled,
    CmdLnOptionId_inputMetadata,
@@ -229,10 +236,10 @@ static const CmdLnParser_Option cliOptions[] = {
    },
    {
#ifdef REND_CFG_LFE
        .id = CmdLnOptionId_customLfeRouting,
        .match = "lfe_config",
        .matchShort = "lfe",
        .description = "LFE Routing configuration. Comma-delimited triplet of [gain, azimuth, elevation] where gain is linear (like --gain, -g) and azimuth, elevation are in degrees.\nIf specified, overrides routing of input LFE to output LFE for outputs that have the LFE channel available.",
        .id = CmdlnOptionId_lfePosition,
        .match = "lfe_position",
        .matchShort = "lp",
        .description = "Output LFE position. Comma-delimited triplet of [gain, azimuth, elevation] where gain is linear (like --gain, -g) and azimuth, elevation are in degrees.\nIf specified, overrides the default behavior which attempts to map input to output LFE channel(s)",
#else
        /* TODO(sgi): Replace with more configurable input, e.g. ask for a list of triplets: (gain, azimuth, elevation) to place LFE signal */
        /* rename to "lfeHandling" */
@@ -242,6 +249,12 @@ static const CmdLnParser_Option cliOptions[] = {
        .description = "[flag] If set, renderer tries to render LFE into other channels in an optimal way when rendering to configs w/o LFE",
#endif
    },
#ifdef REND_CFG_LFE
    { .id = CmdlnOptionId_lfeMatrix,
      .match = "lfe_matrix",
      .matchShort = "lm",
      .description = "LFE panning matrix. File (CSV table) containing a matrix of dimensions [ num_input_lfe x num_output_channels ] with elements specifying linear routing gain (like --gain, -g). \nIf specified, overrides the output LFE position option and the default behavior which attempts to map input to output LFE channel(s)" },
#endif
    {
        .id = CmdLnOptionId_noDelayCmp,
        .match = "no_delay_cmp",
@@ -347,6 +360,12 @@ static void parseMetadata(
    IsmPositionProvider *positionProvider,
    MasaFileReader **masaReaders );

#ifdef REND_CFG_LFE
static ivas_error parseLfePanMtxFile(
    const char *lfeRoutingMatrixFilePath,
    IVAS_REND_LfePanMtx *lfePanMtx );
#endif

static void convert_backslash( char *str );

static void remove_cr( char *str );
@@ -563,6 +582,9 @@ int main(
    convert_backslash( args.inputFilePath );
    convert_backslash( args.outputFilePath );
    convert_backslash( args.headRotationFilePath );
#ifdef REND_CFG_LFE
    convert_backslash( args.inLfePanningMatrixFile );
#endif

    if ( !isEmptyString( args.headRotationFilePath ) )
    {
@@ -669,6 +691,21 @@ int main(
        }
    }

#ifdef REND_CFG_LFE
    IVAS_REND_LfePanMtx lfePanMatrix;

    /* parse input LFE panning matrix */
    if ( args.lfeCustomRoutingEnabled && !isEmptyString( args.inLfePanningMatrixFile ) )
    {
        /* TODO tmu: how should we handle this on CLI for multiple MC inputs? */
        if ( ( error = parseLfePanMtxFile( args.inLfePanningMatrixFile, &lfePanMatrix ) ) != IVAS_ERR_OK )
        {
            fprintf( stderr, "Error: %s\n", ivas_error_to_string( error ) );
            exit( -1 );
        }
    }
#endif

    for ( i = 0; i < args.inConfig.numMultiChannelBuses; ++i )
    {
        if ( ( error = IVAS_REND_AddInput( hIvasRend, args.inConfig.multiChannelBuses[i].audioConfig, &mcIds[i] ) ) != IVAS_ERR_OK )
@@ -693,7 +730,23 @@ int main(
        }

#ifdef REND_CFG_LFE
        if ( args.pan_lfe )
        /* set panning matrix for input LFE */
        if ( args.lfeCustomRoutingEnabled )
        {
            if ( args.lfePanningEnabled )
            {
                fprintf( stdout, "Warning LFE position specified as well as panning matrix! Ignoring position and using gains from panning matrix\n" );
                args.lfePanningEnabled = false;
            }

            if ( ( error = IVAS_REND_SetInputLfeMtx( hIvasRend, mcIds[i], (const IVAS_REND_LfePanMtx *) &lfePanMatrix ) ) != IVAS_ERR_OK )
            {
                fprintf( stderr, "Error: %s\n", ivas_error_to_string( error ) );
                exit( -1 );
            }
        }
        /* set panning gains for input LFE */
        else if ( args.lfePanningEnabled )
        {
            if ( ( error = IVAS_REND_SetInputLfePos( hIvasRend, mcIds[i], args.lfeConfigGain, args.lfeConfigAzimuth, args.lfeConfigElevation ) ) != IVAS_ERR_OK )
            {
@@ -1366,7 +1419,7 @@ static IVAS_REND_AudioConfig parseAudioConfig(
}

#ifdef REND_CFG_LFE
static bool parseLfeConfig(
static bool parseLfePositionConfig(
    const char *value,
    float *lfeGain,
    float *lfeAzimuth,
@@ -1511,10 +1564,13 @@ static CmdlnArgs defaultArgs(
    args.inputGainGlobal = 1.0f;

#ifdef REND_CFG_LFE
    args.pan_lfe = false;
    args.lfePanningEnabled = false;
    args.lfeConfigGain = 1.0f;
    args.lfeConfigAzimuth = 0;
    args.lfeConfigElevation = 0;

    args.lfeCustomRoutingEnabled = false;
    clearString( args.inLfePanningMatrixFile );
#endif
    return args;
}
@@ -1608,20 +1664,28 @@ static void parseOption(
                exit( -1 );
            }
            break;
        case CmdLnOptionId_customLfeRouting:
#ifdef REND_CFG_LFE
        case CmdlnOptionId_lfePosition:
            assert( numOptionValues == 1 );
            if ( !parseLfeConfig( optionValues[0], &args->lfeConfigGain, &args->lfeConfigAzimuth, &args->lfeConfigElevation ) )
            if ( !parseLfePositionConfig( optionValues[0], &args->lfeConfigGain, &args->lfeConfigAzimuth, &args->lfeConfigElevation ) )
            {
                fprintf( stderr, "Unknown or invalid option for LFE configuration: %s\n", optionValues[0] );
                fprintf( stderr, "Unknown or invalid option for LFE position: %s\n", optionValues[0] );
                exit( -1 );
            }
            args->pan_lfe = true;
            args->lfePanningEnabled = true;
            break;
#else
        case CmdLnOptionId_customLfeRouting:
            assert( 0 && "Not yet implemented in CLI" );
#endif
            break;
#ifdef REND_CFG_LFE
        case CmdlnOptionId_lfeMatrix:
            assert( numOptionValues == 1 );
            strncpy( args->inLfePanningMatrixFile, optionValues[0], RENDERER_MAX_CLI_ARG_LENGTH - 1 );
            args->lfeCustomRoutingEnabled = true;
            break;
#endif
        case CmdLnOptionId_noDelayCmp:
            assert( numOptionValues == 0 );
            args->delayCompensationEnabled = false;
@@ -2381,6 +2445,72 @@ static void printSupportedAudioConfigs()
    return;
}

#ifdef REND_CFG_LFE
static ivas_error parseLfePanMtxFile(
    const char *lfeRoutingMatrixFilePath,
    IVAS_REND_LfePanMtx *lfePanMtx )
{
    int16_t lfe_in, ch_out;
    const char *tok;
    char line[200]; /* > (10 chars * IVAS_MAX_OUTPUT_CHANNELS) i.e. "-999,     " */
    FILE *mtxFile;

    if ( strlen( lfeRoutingMatrixFilePath ) < 1 )
    {
        return IVAS_ERR_FAILED_FILE_OPEN;
    }

    mtxFile = fopen( lfeRoutingMatrixFilePath, "r" );

    if ( !mtxFile )
    {
        return IVAS_ERR_FAILED_FILE_OPEN;
    }

    /* set default panning matrix to all zeros
       any subsequent issue in file reading will gracefully exit the function */
    for ( lfe_in = 0; lfe_in < IVAS_MAX_INPUT_LFE_CHANNELS; lfe_in++ )
    {
        set_zero( ( *lfePanMtx )[lfe_in], IVAS_MAX_OUTPUT_CHANNELS );
    }

    for ( lfe_in = 0, ch_out = 0; lfe_in < IVAS_MAX_INPUT_LFE_CHANNELS; lfe_in++ )
    {
        /* if EOF or a blank line is encountered, simply return */
        if ( ( fgets( line, 200, mtxFile ) == NULL ) && ( strcmp( line, "\n" ) == 0 ) && ( strcmp( line, "\r\n" ) == 0 ) )
        {
            fclose( mtxFile );
            return IVAS_ERR_OK;
        }

        for ( tok = strtok( line, "," ); tok && *tok; tok = strtok( NULL, ",\n" ) )
        {
            while ( *tok == ' ' )
            {
                tok++;
            }

            if ( *tok == '\0' )
            {
                continue;
            }
            if ( ch_out > IVAS_MAX_OUTPUT_CHANNELS )
            {
                break;
            }
            else
            {
                ( *lfePanMtx )[lfe_in][ch_out] = (float) atof( tok );
                ch_out++;
            }
        }
    }

    fclose( mtxFile );
    return IVAS_ERR_OK;
}
#endif

// VE2AT: possibly move these functions to cmdln_parser.c ?
static void convert_backslash(
    char *str )
+2 −2
Original line number Diff line number Diff line
@@ -3047,7 +3047,7 @@ ivas_error IVAS_REND_SetInputGain(
ivas_error IVAS_REND_SetInputLfeMtx(
    IVAS_REND_HANDLE hIvasRend,
    const IVAS_REND_InputId inputId,
    const IVAS_REND_LfePanMtx lfePanMtx )
    const IVAS_REND_LfePanMtx *lfePanMtx )
{
    int16_t i;
    input_base *pInputBase;
@@ -3076,7 +3076,7 @@ ivas_error IVAS_REND_SetInputLfeMtx(
    /* copy LFE panning matrix */
    for ( i = 0; i < IVAS_MAX_INPUT_LFE_CHANNELS; i++ )
    {
        mvr2r( lfePanMtx[i], pInputMc->lfeRouting.lfePanMtx[i], IVAS_MAX_OUTPUT_CHANNELS );
        mvr2r( ( *lfePanMtx )[i], pInputMc->lfeRouting.lfePanMtx[i], IVAS_MAX_OUTPUT_CHANNELS );
    }

    if ( ( error = updateMcPanGains( pInputMc, hIvasRend->outputConfig ) ) != IVAS_ERR_OK )
+1 −1
Original line number Diff line number Diff line
@@ -201,7 +201,7 @@ ivas_error IVAS_REND_SetInputGain(
ivas_error IVAS_REND_SetInputLfeMtx(
    IVAS_REND_HANDLE hIvasRend,                     /* i/o: Renderer handle                                     */
    const IVAS_REND_InputId inputId,                /* i  : ID of the input                                     */
    const IVAS_REND_LfePanMtx lfePanMtx             /* i  : LFE panning matrix                                  */
    const IVAS_REND_LfePanMtx *lfePanMtx            /* i  : LFE panning matrix                                  */
);
#endif