0

我已经在互联网上搜索了几天以找到以下问题的解决方案。

在我的程序中,我将两个 16 位 .wav 文件中的数据块读取到声音缓冲区(类型为 的数组short)中,我在堆上为其分配内存。将数据转换double为 fftw 函数并进行处理,然后按比例缩小并short转换为在将输出文件写入磁盘之前放入集合缓冲区。通过这种方式,我减少了访问硬盘的次数,因为我正在读取几块数据(即在文件中移动)并且不想在每次迭代中写入磁盘。

这是我正在做的事情:

short* sound_buffer_zero;
short* sound_buffer_one;
short* collection_buffer_one;
sound_buffer_zero = (short *) fftw_malloc(sizeof(short) * BUFFERSIZE); 
sound_buffer_one = (short *) fftw_malloc(sizeof(short) * BUFFERSIZE);
collection_buffer_one = (short *) fftw_malloc(sizeof(short) * COLLECTIONLENGTH);

// read BUFFERSIZE samples from file into sound_buffer
inFileZero.read((char*)sound_buffer_zero, sizeof(short)*BUFFERSIZE);
inFileOne.read((char*)sound_buffer_one, sizeof(short)*BUFFERSIZE);

// typecast the short int values of sound_buffer into double values
// and write them to in_
for(int p = 0; p < BUFFERSIZE; ++p) {
    *(in_zero + p) = (double)*(sound_buffer_zero + p);
    *(in_one + p) = (double)*(sound_buffer_one + p);
}

// cross correlation in the frequency domain
// FFT on input zero (output is f_zero)
fftw_execute(p_zero);

// FFT on input one (output is f_one)
fftw_execute(p_one);

// complex multiplication (output is almost_one, also array of type double)
fastCplxConjProd(almost_one, f_zero, f_one, COMPLEXLENGTH);

// IFFT on almost_one (output is out_one, array of double)
fftw_execute(pi_one);

// finalize the output array (sort the parts correctly, output is final_one, array of double)
// last half without first value becomes first half of final array
for(int i = ARRAYLENGTH/2 + 1; i < ARRAYLENGTH; ++i) {
    *(final_one + i - (ARRAYLENGTH/2 + 1)) = *(out_one + i);
}
// first half becomes second half of final array
for(int i = 0; i < ARRAYLENGTH/2; ++i) {
    *(final_one + i + (ARRAYLENGTH/2 - 1)) = *(out_one + i);
}

short* scaling_vector; 
scaling_vector = (short *) fftw_malloc(sizeof(short) * ARRAYLENGTH-1);

// fill the scaling_vector with the numbers from 1, 2, 3, ..., BUFFERSIZE, ..., 3, 2, 1
for(short i = 0; i < BUFFERSIZE; ++i) {
    *(scaling_vector + i) = i + 1;
    if(i + BUFFERSIZE > ARRAYLENGTH-1) break;
    *(scaling_vector + i + BUFFERSIZE) = BUFFERSIZE - i - 1;
}

// scale values in relation to their position in the output array
// to values suitable for short int for storage
for(int i = 0; i < ARRAYLENGTH-1; ++i) {
    *(final_one + i) = *(final_one + i) * SCALEFACTOR; // #define SCALEFACTOR SHRT_MAX/pow(2,42)
    *(final_one + i) = *(final_one + i) / *(scaling_vector + i);
}

// transform the double values of final_ into rounded short int values
// and write them to the collection buffer
for(int p = 0; p < ARRAYLENGTH-1; ++p) {
    *(collection_buffer_one + collectioncount*(ARRAYLENGTH) + p) = (short)round(*(final_one + p));
}

// write collection_buffer to disk
 outFileOne.write((char*)collection_buffer_one, sizeof(short)*collectioncount*(ARRAYLENGTH));

在互相关中计算的值具有类型double并且具有正号或负号。通过缩小它们,符号不会改变。但是当我将它们转换short为到达 collection_array 的数字时,它们都是正数。

该数组被声明为short,而不是unsigned short,并且在缩放后值处于short可以容纳的范围内(您必须相信我,因为我不想发布所有代码以保持帖子可读)。我不关心小数部分的截断,我不需要进一步计算,但符号应该保持不变。

这是输入和输出值的一个小示例(显示的是数组中的前 10 个值):

input: 157
input: 4058
input: -1526
input: 1444
input: -774
input: -1507
input: -1615
input: -1895
input: -987
input: -1729

// converted to double
as double: 157
as double: 4058
as double: -1526
as double: 1444
as double: -774
as double: -1507
as double: -1615
as double: -1895
as double: -987
as double: -1729

// after the computations 
after scaling: -2.99445
after scaling: -42.6612
after scaling: -57.0962
after scaling: 41.0415
after scaling: -18.3168
after scaling: 43.5853
after scaling: -14.3663
after scaling: -3.58456
after scaling: -46.3902
after scaling: 16.0804

// in the collection array and before writing to disk
collection [short(round*(final_one))]: 3
collection [short(round*(final_one))]: 43
collection [short(round*(final_one))]: 57
collection [short(round*(final_one))]: 41
collection [short(round*(final_one))]: 18
collection [short(round*(final_one))]: 44
collection [short(round*(final_one))]: 14
collection [short(round*(final_one))]: 4
collection [short(round*(final_one))]: 46
collection [short(round*(final_one))]: 16

我的问题是,为什么没有保留标志?我错过了一些内部转换吗?我没有在其他帖子中找到我的问题的答案。如果我错过了,请告诉我,如果我为您遗漏了重要信息。谢谢你的帮助!

干杯,芒果

这是测试输出的代码:

//contents of sound_buffer (input from file):
// test output
for(int i = 0; i < 10; ++i) {
    cout << "input: " << *(sound_buffer_zero + i) << endl;
}

// content of in_ after converting to double
// test output
for(int i = 0; i < 10; ++i) {
    cout << "as double: " << *(in_zero + i) << endl;
}

// contents of final_ after the scaling
// test output 
for(int i = 0; i < 10; ++i) {
    cout << "after scaling: " << *(final_one + i) << endl;
}

// contents of collection_buffer after converting to short
// test output
for(int i = 0; i < 10; ++i) {
    cout << "collection [short(round*(final_one))]: " << *(collection_buffer_one + i) << endl;
}

感谢aleguna,我发现这些符号在以下计算中消失了。我完全错过了我所做的那一步final_one = fabs(final_one)。我已经把它放在了一个测试中,完全忘记了它。

谢谢大家的评论和回答。事实证明,我只是愚蠢。对不起。

4

3 回答 3

3

你在哪个平台上运行这个?我在 linux x86, gcc 3.4.2 上做了一点测试

   #include <iostream>
   #include <math.h>

   int main (int,  char*[])
   {
       double a = -2.99445;
       short b = (short)round(a);

       std::cout << "a = " << a << " b = " << b << std::endl;
      return 0;
   }

输出

a = -2.99445 b = -3

所以我可以想到两种情况

  1. 您还没有向我们展示缩放和转换为short 之间的一些代码
  2. 您运行一些具有非标准双重表示的奇异平台
于 2012-10-29T12:22:52.470 回答
0

在完全没有优化的情况下编译时,以下内容如何在您的平台上运行?

#include <stdlib.h>
#include <stdio.h>

double a[10] = { 
  -2.99445,
  -42.6612,
  -57.0962,
  41.0415,
  -18.3168,
  43.5853,
  -14.3663,
  -3.58456,
  -46.3902,
  16.0804
};

int main(){
  int i;
  for (i=0;i<10;++i){
    short k = (short)*(a + i);
    printf("%d\n", k);
  }

}

给我以下结果:

-2
-42
-57
41
-18
43
-14
-3
-46
16
于 2012-10-29T12:26:12.840 回答
-2

通常,short 是 2 字节长,而 double 是 8 字节长。将 double 转换为 short 会导致高字节丢失。即使 2 个字节对于没有符号的实际数据就足够了,您也会丢失通过符号扩展存储在高位字节中的符号信息。

于 2012-10-29T11:52:10.503 回答