不确定是否规范化加载为每个2字节的双值
Unsure of normalising double values loaded as 2 bytes each
我用来将.wav文件数据读取到2D数组中的代码:
int signal_frame_width = wavHeader.SamplesPerSec / 100; //10ms frame
int total_number_of_frames = numSamples / signal_frame_width;
double** loadedSignal = new double *[total_number_of_frames]; //array that contains the whole signal
int iteration = 0;
int16_t* buffer = new int16_t[signal_frame_width];
while ((bytesRead = fread(buffer, sizeof(buffer[0]), signal_frame_width, wavFile)) > 0)
{
loadedSignal[iteration] = new double[signal_frame_width];
for(int i = 0; i < signal_frame_width; i++){
//value normalisation:
int16_t c = (buffer[i + 1] << 8) | buffer[i];
double normalisedValue = c/32768.0;
loadedSignal[iteration][i] = normalisedValue;
}
iteration++;
}
问题出在这一部分,我不完全理解它是如何工作的:
int16_t c = (buffer[i + 1] << 8) | buffer[i];
这是从这里取的例子。我只处理16位.wav文件。正如您所看到的,我的缓冲区正在加载(例如采样频率=44.1kHz)441个元素(每个元素都是2字节的带符号样本)。我应该如何更改上述代码?
构建代码的原始示例使用了一个数组,其中每个单独的元素表示一个字节。因此,它需要将两个连续的字节组合成一个16位的值,这就是这行的作用:
int16_t c = (buffer[i + 1] << 8) | buffer[i];
它将索引i+1
处的字节(此处假定为最高有效字节)左移8个位置,然后将索引i
处的字节与之进行"或"运算。例如,如果是buffer[i+1]==0x12
和buffer[i]==0x34
,则会得到
buffer[i+1] << 8 == 0x12 << 8 == 0x1200
0x1200 | buffer[i] == 0x1200 | 0x34 == 0x1234
(|
运算符是位OR。)
请注意,您需要小心WAV文件是小端还是大端(但最初的文章很好地解释了这一点)。
现在,如果将结果值存储在一个有符号的16位整数中,则会得到一个介于−32768和+32767之间的值。实际归一化步骤中的点(除以32768)只是将值范围降低到[-1.0,1.0)
在上面的例子中,您似乎已经在读取一个16位值的缓冲区。请注意,只有当您的平台的端序与您正在使用的WAV文件的端序相匹配时,您的代码才能工作。但如果这个假设是正确的,那么你就不需要你不理解的代码行。您可以直接将每个数组元素转换为一个二重:
double normalisedValue = buffer[i]/32768.0;
如果buffer
是一个字节数组,那么这段代码将把两个连续的字节解释为一个16位整数(假设小端编码)。|
运算符将对两个字节的位执行逐位OR。由于我们希望将两个字节解释为单个2字节整数,因此我们必须将其中一个字节的位向左移动8位(1字节)。哪一个取决于它们是按小端序还是大端序排列。Little endian意味着最低有效字节位于第一位,因此我们将第二个字节向左移动8位。
示例:
First byte: 0101 1100
Second byte: 1111 0100
现在移位第二个字节:
Second "byte": 1111 0100 0000 0000
First "byte": 0000 0000 0101 1100
逐位OR运算(如果其中一个为1,则为1。如果两者都为0,则为0):16位整数:1111 0100 0101 1100
然而,在您的情况下,文件中的字节已经被解释为16位int,使用平台的任何endianness。所以你不需要这一步。然而,为了正确解释文件中的字节,必须采用与写入时相同的字节顺序。因此,通常会添加此步骤,以确保代码的工作独立于平台的端序,而不是依赖于文件的预期字节顺序(因为大多数文件格式都会指定字节顺序)。
- 是否可以保证按字节的零 int 是零的表示形式?
- 将对象的字节复制到数组并再次复制回来是否安全
- 是否通过向封闭对象的地址添加字节偏移量来访问子对象
- C++11:16 字节原子<>变量是否在 16 字节边界上自动对齐,从而允许CMPXCHG16B指令?
- 我是否正确打包字节以进行放气压缩?
- 在 c++ 中使用联合时是否可以跳过字节?
- 如果由不同的线程写入 8 字节,那么现代英特尔 x86 上的 8 字节读取是否保证理智?
- 是否强制转换void**并将第一个字节设置为nullptr
- 检查 IP 第一个八位字节是否不以 127 / 224 或 255 开头
- 使用字节数组具有单字节对齐方式的结构是否安全
- 是否值得使用位移在单个字节中存储多个小数据成员?
- 额外的字节是否在C++中初始化为 0?
- 当字节在文件上写入0时,是否可以保持写作时间稳定
- 在字节数组上转换具有虚函数的结构是否安全?
- 将二进制字节 (char*) 转换为 uint64_t*,是否安全
- 位在字节序中是否重要
- 字节序是否会影响写入奇数字节
- x86-64上检查指针范围是否跨越N字节对齐地址的最快方法
- 如何检查准备从windows套接字读取的字节是否超过1个
- 如何检查内存块中的所有字节是否为零