0

我有以下卷积算法:

public class Spatializer : MonoBehaviour 
{   
    const int MAX_TAPS = 128;
    static float[,,] IRs = null;

    // http://stackoverflow.com/questions/7237907/1d-fast-convolution-without-fft
    public static float[] Spatialize( float[] srcMono, int toneme, bool loop )
    {
        if( IRs == null )
            LoadIRs( );

        int inSamps = srcMono.Length;
        int outSamps = inSamps + ( loop ? 0 : MAX_TAPS-1 );

        float [] L = new float[ outSamps ];
        float [] R = new float[ outSamps ];

        int i,j,k;
        float x_i;
        for ( i = 0; i < inSamps; i++)
        {
            x_i = srcMono[ i ];
            for ( j = 0; j < MAX_TAPS; j++)
            {
                k = i + j;
                if( k >= inSamps )
                    if( loop )
                        k %= inSamps;

                L[ k ] += x_i * IRs[ toneme, 0, j ];
                R[ k ] += x_i * IRs[ toneme, 1, j ];
            }
        }

        float[] outputInterleaved = new float[ 2 * outSamps ];
        int outPtr = 0;

        for ( i = 0; i < outSamps; i++)
        {
            outputInterleaved[ outPtr++ ] = L[ i ];
            outputInterleaved[ outPtr++ ] = R[ i ];
        }

        return outputInterleaved;
    }



    static void LoadIRs( )
    {
        IRs = new float[ 12, 2, MAX_TAPS ];

        // !!! get wav from file
        float [] wav = new float[ ... ];
        float step = ...;

        // de-interleave and resample
        for( int toneme = 0; toneme < 12; toneme++ ) 
        {   
            for( int tap=0; tap < MAX_TAPS; tap++ )
            {
                int n = (int)Mathf.RoundToInt( (float)tap * step );

                IRs[ toneme, 0, tap ] = wav[ 2 * n ];
                IRs[ toneme, 1, tap ] = wav[ 2 * n + 1 ];
            }
        }
    }


}

我怀疑如果我只需要在卷积循环中访问一维数组会快得多,因为从一维数组中访问一个元素将比从三维数组中访问一个元素涉及更少的循环。维数组。

        // extract array we want OUTSIDE loop
        float [] IR_L = IRs[ toneme, 0 ];  // BAD SYNTAX <-- how to do this?
        float [] IR_R = IRs[ toneme, 1 ];  // BAD SYNTAX <-- how to do this?

        for ( i = 0; i < inSamps; i++)
        {
            x_i = srcMono[ i ];
            for ( j = 0; j < MAX_TAPS; j++)
            {
                k = i + j;
                if( k >= inSamps )
                    if( loop )
                        k %= inSamps;

                L[ k ] += x_i * IR_L[ j ];
                R[ k ] += x_i * IR_R[ j ];
            }
        }

以上是伪代码,因为我不知道如何去实现它,甚至是否可能。

所以我的问题是:我可以提取

float [] IR_L = IRs[ toneme, 0 ]; // BAD SYNTAX <-- how to do this?

所以而不是写

IRs[ toneme, 0, j ] 

在内部循环中,我可以写

IR_L[ j ]
4

1 回答 1

0

由于浏览了 Basilevs 的那个极好的链接,我已经从内部循环中删除了分支。

我找到了数组问题的答案:解决方法是使用锯齿数组;[][] 而不是 [,]。常识是 [][] 执行得更快,而 [,] 允许更整洁和更简洁的代码。就我而言,我需要 [] []。

这是最终的卷积算法——它的执行速度至少比原始算法快四倍:

const int MAX_TAPS = 128;
static float[,][] IRs = null;

public static float[] Spatialize( float[] srcMono, int toneme, bool loop )
{
    if( IRs == null )
        LoadIRs( );

    int inSamps = srcMono.Length;
    int convSamps = inSamps + MAX_TAPS;

    float [] destL = new float[ convSamps ];
    float [] destR = new float[ convSamps ];

    float [] filtL = IRs[ toneme, 0 ];
    float [] filtR = IRs[ toneme, 1 ];

    int i,j,k;
    float x_i;
    for ( i = 0; i < inSamps; i++)
    {
        x_i = srcMono[ i ];
        k = i;
        for ( j = 0; j < MAX_TAPS; j++, k++ )
        {
            // think: k = i + j;
            destL[ k ] += x_i * filtL[ j ];
            destR[ k ] += x_i * filtR[ j ];
        }
    }

    // circular convolution?
    if( loop ) {
        for ( j = 0; j < MAX_TAPS; j++ ) {
            destL[ j ] += destL[ inSamps + j ];
            destR[ j ] += destR[ inSamps + j ];
        }
    }

    int outSamps = loop ? inSamps : convSamps;

    float[] outputInterleaved = new float[ 2 * outSamps ];
    int outPtr = 0;

    for ( i = 0; i < outSamps; i++)
    {
        outputInterleaved[ outPtr++ ] = destL[ i ];
        outputInterleaved[ outPtr++ ] = destR[ i ];
    }

    return outputInterleaved;
}

static void LoadIRs( )
{
    IRs = new float[ 12, 2] [];

            // !!! fill wav[] from file

    for( int toneme = 0; toneme < 12; toneme++ ) 
    {           
        // de-interleave and resample
        float [] L = new float[ MAX_TAPS ];
        float [] R = new float[ MAX_TAPS ];

        for( int tap=0; tap < MAX_TAPS; tap++ )
        {
            int n = (int)Mathf.RoundToInt( (float)tap * step );

            L[ tap ] = wav[ 2 * n ];
            R[ tap ] = wav[ 2 * n + 1 ];
        }

        IRs[ toneme, 0 ] = L;
        IRs[ toneme, 1 ] = R;
    }
于 2013-10-20T15:22:47.783 回答