C++ 处理.wav文件时输出失真
我想处理一个.wav文件,例如降低振幅; 当我使用下面的代码时,输出会失真,这是不愉快的C++ 处理.wav文件时输出失真,c++,endianness,riff,C++,Endianness,Riff,我想处理一个.wav文件,例如降低振幅; 当我使用下面的代码时,输出会失真,这是不愉快的 #include <iostream> #include <fstream> #include <string> using namespace std; int main() { char* wav_mem; ifstream wav_file; wav_file.open("1.wav", ios::binary | ios::ate);
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main()
{
char* wav_mem;
ifstream wav_file;
wav_file.open("1.wav", ios::binary | ios::ate);
int file_size = wav_file.tellg();
wav_mem = new char[file_size];
wav_file.seekg(0, ios::beg);
wav_file.read(wav_mem, file_size);
int16_t sample = 0;
wav_file.close();
for(int i = 44; i <= file_size; i += 2)
{
sample = ((wav_mem[i + 1] << 8) | (wav_mem[i]));
sample = (int16_t)(sample * 0.5);
wav_mem[i] = sample;
wav_mem[i+1] = (sample >> 8);
}
ofstream out_file;
out_file.open("out.wav", ios::binary);
out_file.write(wav_mem, file_size);
}
#包括
#包括
#包括
使用名称空间std;
int main()
{
字符*wav_mem;
ifstream wav_文件;
打开(“1.wav”,ios::binary | ios::ate);
int file_size=wav_file.tellg();
wav_mem=新字符[文件大小];
seekg(0,ios::beg);
读取(wav_mem,文件大小);
int16_t样本=0;
wav_file.close();
对于(int i=44;i 8);
}
流式输出文件;
out_file.open(“out.wav”,ios::binary);
out_file.write(wav_mem,文件大小);
}
如何修复失真?假设您对
.wav
文件本身的操作是正确的(否则我不知道这是否是问题所在),一些潜在的缺陷可能是:
int
中收集tellg
的输出可能会导致溢出。可能使用auto
来获得正确的类型wav_mem[i+1]=(样本>>8)
当循环中的i==file_size
可能导致溢出访问(超出wav_mem
的长度)时事实上,由于您的
wav_mem=new char[file_size];
行,您只能以定义的方式访问[0,file_size)
索引。因此,当i=file_size
时,wav_mem[i]和wav_mem[i+1]
将是UB。我认为问题可能在于对有符号整数使用位移位运算符。的实际行为将tellg
中提到的溢出和wav_mem[I+1]中未定义的行为放在一边。
我认为这一行是主要问题:
sample = (int16_t)(sample * 0.5);
在幕后,sample
在此转换为double。来回转换为double和从double转换可能会导致较小(但我认为可以听到)的舍入错误,我认为这可能是失真的来源。而不是这种用法:
sample /= 2;
我解决了这个问题,当我试图将两个字节转换为16位时,我弄乱了样本,下面是最后的代码:
#include <iostream>
#include <fstream>
#include <string>
#include <string.h>
using namespace std;
int main()
{
ifstream wav_file;
ofstream out_file;
wav_file.open("input.wav",ios::binary|ios::ate);
size_t file_size = wav_file.tellg();
char * wav_buf = new char[file_size];
wav_file.seekg (0,ios::beg);
wav_file.read (wav_buf, file_size);
wav_file.close();
int16_t wav_smpl(0);
char * wav_out = new char[file_size];
memcpy(wav_out, wav_buf, 44);
for (size_t i = 0 ; i < file_size ; i += 2)
{
memcpy(&wav_smpl , wav_buf + (i + 44) , 2);
wav_smpl *= 3;
memcpy(wav_out + (i + 44) , &wav_smpl , 2);
}
out_file.open("output.wav",ios::binary);
out_file.write(wav_out, file_size);
out_file.close();
return 0;
}
#包括
#包括
#包括
#包括
使用名称空间std;
int main()
{
ifstream wav_文件;
流式输出文件;
打开(“input.wav”,ios::binary | ios::ate);
size_t file_size=wav_file.tellg();
char*wav_buf=新字符[文件大小];
wav_file.seekg(0,ios::beg);
wav_file.read(wav_buf,文件大小);
wav_file.close();
int16_t wav_smpl(0);
char*wav_out=新字符[文件大小];
memcpy(wav_out,wav_buf,44);
对于(大小i=0;i<文件大小;i+=2)
{
memcpy(&wav_smpl,wav_buf+(i+44),2);
wav_smpl*=3;
memcpy(wav_out+(i+44)和wav_smpl,2);
}
out_file.open(“output.wav”,ios::binary);
输出文件。写入(wav输出,文件大小);
out_file.close();
返回0;
}
Aside:declare and init all-in-go:char*wav_mem=new char[file_size];
int file_size=wav_file.tellg();
Aside:not use use c-style cast use:sample=static_cast(sample*0.5)
尝试uint8\u t
对于wav\u mem
,或者更好,使用int16\u t
作为缓冲区,并将其重新转换为char*
或void*
仅用于文件操作,避免使用((wav\u mem[i+1]我不这么认为。这两种方法都产生了完全相同的样本值。不过,我同意,如果这是唯一的一个,那么后者更优雅。对于一个完整的例子,我看到了几年前我为C++类设置的一个RePO:它对一个有噪声的音频片段应用了低通滤波器。光谱减法
用于更复杂的噪声消除。