Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/129.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 处理.wav文件时输出失真_C++_Endianness_Riff - Fatal编程技术网

C++ 处理.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);

我想处理一个.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);
    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:它对一个有噪声的音频片段应用了低通滤波器。光谱减法
    用于更复杂的噪声消除。