2013-10-20 55 views
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 ] 
+1

我編輯了自己的冠軍。請參閱:「[應該在其標題中包含」標籤「](http://meta.stackexchange.com/questions/19190/)」,其中的共識是「不,他們不應該」。 –

+0

我認爲你會優化你的循環,就像你優化其他任何東西一樣:找出哪些部分是慢的,然後加快它們。只要看一下代碼就不會有多大幫助:在做出改變之後,你如何知道自己是否改進了一些東西?你怎麼知道你沒有破壞代碼? –

+0

對不起,我已經重寫了這個問題,以便說明問題。 –

回答

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; 
    }