将回声效果添加到 .wav 文件

Posted

技术标签:

【中文标题】将回声效果添加到 .wav 文件【英文标题】:adding echo effect to a .wav file 【发布时间】:2014-05-19 19:35:48 【问题描述】:

我用 C++ 编写了以下代码(示例代码)来修改原始 .wav 文件中存在的数据并将修改后的数据写入新创建的文件。该程序为声音提供“回声效果”(注意:- 这是为只有 2 个通道的 wav 文件编写的)。

#include <iostream>
#include <conio.h>
#include <fstream>
#ifndef endl
#define endl "\n"
#endif

#define  wav_eco(filin, fileout, eco_rate)                      \
char temp[2];                                                  \
char ch[eco_rate][2], ch2[eco_rate][2];                        \
int i,j;                                                       \
    for(i=0; i<eco_rate; i++)                                           \
        for(j=0; j<2; j++)                                              \
            ch2[i][j] = 0;                                                      \
while(!filin.eof())                                                             \
                                                                               \
    for(i=0; i<eco_rate && !filin.eof(); i++)                                   \
    filin.read((char*)&ch[i], sizeof(char[2]));                                 \
    for(i=0; i<eco_rate; i++)                                                   \
                                                                               \
                temp[0]  = ch[i][0];                            \
                temp[1]  = ch[i][1];                            \
                ch[i][0]+=ch2[i][0];                            \
                ch[i][1]+=ch2[i][1];                            \
                fileout.write((char*)&ch[i], sizeof(char[2]));                  \
                ch2[i][0] = temp[0];                                            \
                ch2[i][1] = temp[1];                                            \
                                                                               \
    

 using namespace std;
 struct WAVEFILEHEADER

char ChunkId[4];
int ChunkSize;
char Format[4];
char SubChunkFmt[4];
int SubChunkFmtSize;
short int AudioFormat;
short int NumChannels;

int SampleRate;
int ByteRate;
short int BlockAlign;
short int BitsPerSample;

char ChunkData[4];
int SubChunkDataSize;
;

int main()

fstream filin("C:\\Users\\chess.Admin-PC.000\\Music\\ExampleRead.wav", ios::in|ios::binary);
fstream fileout("C:\\Users\\chess.Admin-PC.000\\Music\\ExampleWrite.wav",ios::out| ios::binary);
WAVEFILEHEADER wav;
filin.read((char*)&wav,sizeof(wav));
    //to display the contents of the header 
cout<<wav.ByteRate
    <<endl<<wav.ChunkSize
    <<endl<<wav.SampleRate// no of samples per second
    <<endl<<wav.SubChunkDataSize
    <<endl<<wav.SubChunkFmtSize
    <<endl<<wav.ChunkData
    <<endl<<wav.ChunkId
    <<endl<<wav.Format
    <<endl<<wav.SubChunkFmt
    <<endl<<wav.AudioFormat
    <<endl<<wav.AudioFormat
    <<endl<<wav.BitsPerSample//no of bits per second
    <<endl<<wav.BlockAlign
    <<endl<<wav.NumChannels
    <<endl<<endl<<sizeof(wav); /* size of the wav variable*/
getch();
fileout.write((char*)&wav, sizeof(wav));/// write the header to output file 
wav_eco(filin,fileout,10000)  ///modify the data and update the output file
filin.close();
fileout.close();
return 0;


/*algorithm implemented by the wav_eco function(this is not some stranded algorithm. I wrote it myself)  :-
1) obtain the 'echo_rate' of the samples
2) read the data present in the original wav file 
3) write this data, by adding each sample from the previously obtained data to the data that was read now
4) follow steps 2 and 3 until eof is reached  
  */

程序运行良好,当我使用 windows 媒体播放器播放输出文件时,我得到了回声效果,但另外我得到了“嘶嘶”的声音。是什么原因造成的,我必须以什么方式修改上面的代码来避免它?是否可以简化wav_eco() 宏以减少程序的计算时间?

我对嘶嘶声的猜测是因为添加了ch[i][0] += ch2[i][0]; ch[i][1]+=ch2[i][1];。它是否以错误的方式修改声音? (这是我第一次编辑声音)

【问题讨论】:

抱歉拼写错误:eco 而不是 echo 它通过回收声音使声音文件对环境更加友好。 ;-) WAV 数据格式是什么? 8 位还是 16 位? PCM还是别的?每种格式需要不同的算术。 十六位。它包含 2 个频道 【参考方案1】:

此.wav 文件有多种格式,格式列表为here。只有知道格式(无论是 8 位还是 16 位),才能回答上述问题。调试问题中给出的代码,我们不需要bit_rate,所以我们不需要知道格式是否为PCM等。所以如果文件是16位,那么wav_echo()的以下代码可以是使用:

#define  wav_echo2_16(filin, fileout, eco_rate)                     \
short int temp;                                                 \
short int ch[eco_rate], ch2[eco_rate];                          \
int i,j;                                                        \
    for(i=0; i<eco_rate; i++)                                   \
            ch2[i] = 0;                                         \
while(!filin.eof())                                             \
                                                               \
    for(i=0; i<eco_rate && !filin.eof(); i++)                   \
    filin.read((char*)&ch[i], sizeof(short int));               \
    for(i=0; i<eco_rate; i++)                                   \
                                                               \
                temp  = ch[i];                                  \
                ch[i]+=ch2[i];                                  \
                fileout.write((char*)&ch[i], sizeof(short int));\
                ch2[i] = temp;                                  \
                                                               \
                                                                \

上面的宏wav_echo2_16()为16位文件提供了回声效果(注意echo_rate常数应该是偶数,因为有2个通道)。 下面显示了 8 位格式的代码:

#define  wav_echo2_8(filin, fileout, eco_rate)\
char temp;\
char ch[eco_rate], ch2[eco_rate];\
int i,j;\
    for(i=0; i<eco_rate; i++)\
            ch2[i] = 0;\
while(!filin.eof())\
\
    for(i=0; i<eco_rate && !filin.eof(); i++)\
    filin.read((char*)&ch[i], sizeof(char));\
    for(i=0; i<eco_rate; i++)\
            \
                temp  = ch[i];\
                ch[i]+=ch2[i];\
                fileout.write((char*)&ch[i], sizeof(char));\
                ch2[i] = temp;\
            \
            \

将 8 位宏用于 16 位格式会导致嘶嘶声!

【讨论】:

【参考方案2】:

您正在尝试一次添加 8 位的 16 位值。您需要检测低字节的溢出并将其转移到高字节加法中,或者从一开始就使用 16 位算法。

【讨论】:

谢谢!修改后,嘶嘶声消失了。

以上是关于将回声效果添加到 .wav 文件的主要内容,如果未能解决你的问题,请参考以下文章

通过 C 中的 FFT 将 1000Hz 噪声添加到 wav 文件

读入声音文件,添加回声,并写入新的声音文件

在 NAudio 中添加 WAV 标头

在exe中添加wav

从资源中添加 .wav 文件(WPF C#)

如何为awk添加回声?