C++中的音频处理

Jam*_*ton 3 c++ audio signal-processing

我希望这是发布此内容的正确位置,有人可以提供帮助.

我是一名音乐技术专业的学生,​​我最近学习了C++,因为它对我的职业生涯有很大帮助,因为它可以用于视频游戏行业.

无论如何进入主题.我想要创建的是一个程序(在C++中),它允许用户加载一个16位线性PCM WAVE文件.然后我想操纵该波形文件中的音频样本数据.我想要删除每个第n个样本,或者在某个参数内随机化它们(±10%).然后将其写为新的WAVE文件.

我对WAVE文件和RIFF标题的结构比较熟悉.我现在也使用Xcode作为我的IDE(因为我的macbook pro是我的工作计算机),但如果需要,我可以使用代码块在我的PC上编码.

所以简单来说它应该显示类似的东西?我知道这里有错误,所以你知道我在追求什么:

#include <iostream>
using namespace std;

class main()    //function start
{
    string fileinput;   //variable
    string outlocation; //variable

    cout << "please type file path directory: \n \n";
    cin >> fileinput;   //navigate to file by typing

    cout << "Where would you like to save new file? \n \n";
    cin >> outlocation; //select output by typing

    // Then all the maths and manipulation is done

    cout << "Your file has been created at ";
    cout << outlocation;
    cout << "\n \n";

    system("pause");

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

是否可以在Xcode中执行此操作,如果有的话?我需要哪些图书馆?我知道这不是简单的事情,所以任何帮助都将不胜感激.

谢谢你的帮助和时间.

詹姆士

wim*_*ica 5

如果您知道RIFF文件结构,您可能也已经知道PCM音频如何存储在其中.

常见的格式是16位立体声pcm.在这种情况下,每个样本是2个字节,并且两个样本属于一起(左+右).但是您需要检查格式块的确切格式.但我现在认为你正在操纵一个16位立体声pcm wav文件.

您可以使用16位整数类型(short,_int16,int16_t)操作样本.例如,要减小音量,您可以将每个样本除以某个数字.但是,如果将它除以2,它并不会自动意味着它会变得大一半.看这篇文章.

如果您只是操作示例,则RIFF标题不会更改,因此您可以从源中复制它们.

如果要删除或添加样本,数据块的大小将更改,并且还会更改riff-header中整个文件的大小.例如,您可以删除每10个样本,然后从数据块中复制9*4 = 36个字节,跳过4个字节,复制36个字节,依此类推.但如果你这样做,那听起来会非常糟糕.听到结果的最好方法是操纵正弦波.如果正弦不完全正确,则很容易听到.要以正确的方式丢弃样本,您可能需要使用快速傅里叶变换(FFT).

作为基于您的评论的添加,我添加以下内容:

有关文件I/O的快速操作,请参阅C++二进制文件I/O. 你的链接描述RIFF格式看起来正确的,但不完整.根据该描述,报头总是44个字节.但是可以向标题添加更多信息.

你应该做的是跳过前12个字节(虽然你可以使用它来验证文件是否真的是一个波形文件).然后在循环中读取下一个块的名称和大小.如果它是一个你知道的块('fmt'或'data')你可以处理它,否则跳过它.

所以它看起来像这样:

ifstream myFile ("example.wav", ios::in | ios::binary);
char buffer[12];
myFile.read (buffer, 12); // skip RIFF header

char chunkName[5];
unsigned long chunksize;
while (myFile.read (chunkName, 4)) {
    chunkName[4]='\0'; // add trailing zero
    myFile.read((char*)&chunksize, 4);

    // if chunkname is 'fmt ' or 'data' process it here,
    // otherwise skip any unknown chunk:
    myFile.seekg(chunksize, ios_base::cur);
}
Run Code Online (Sandbox Code Playgroud)