Audio Manipulation In C++

2019-05-14 15:42发布

问题:

I hope this is the right place to post this and somebody can help.

I am a music technology student and I've recently picked up learning C++ as it would greatly help my career knowing a programming language, especially this one since it is used in the video games industry.

Anyways onto the main topic. What I want to create is a program (in C++) that lets the user load a 16bit linear PCM WAVE file. Then I want to manipulate the audio sample data within that wave file. I want to either remove every nth sample or randomise them within a certain parameter (±10%). Then write it as a new WAVE file.

I am familier with the structure of WAVE files and the RIFF header. I also at the moment use Xcode as my IDE (since my macbook pro is my work computer), but I can code on my PC if necessary using codeblocks.

So in simple terms it should display something similar to this? I know there are errors in this, just so you get an idea of what I'm after:

#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;
}

Is it possible to do this in Xcode, if at all? What libraries would I need? I understand this is not simple stuff, so any help will be greatly appreciated.

Thankyou for your help and time.

James

回答1:

If you know the RIFF file structure, you might also already know how PCM audio is stored in it.

A common format is 16-bit stereo pcm. In that case each sample is 2 bytes, and two samples belong together (left+right). But you need to check the format chunk for the exact format. But I asume for now you are manipulating a 16-bit stereo pcm wav file.

You can manipulate the samples using a 16 bit integer type (short, _int16, int16_t). For example to decrease the volume, you can divide every sample by some number. But if you divide it by 2, it does not automatically mean it will become half as loud. See this post.

If you just manipulate samples, the RIFF headers do not change, so you can copy them from the source.

If you want to remove or add samples, the size of the data chunk will change, and also the size of the whole file in the riff-header. You could simply for example drop every 10th sample, then you would copy 9*4=36 bytes from the data chunk, skip 4 bytes, copy 36 bytes and so on. But if you do something like that, it will sound very bad. The best way to hear the result is to manipulate a sine wave. If the sine is not fully correct, it will be easy to hear it. To drop samples the right way, you probably need to use a Fast Fourier Transform (FFT).

As an addition based on your comments I add the following:

See C++ Binary File I/O for a quick howto on file I/O. Your link describing the RIFF format looks correct but is not complete. According to that description the header is always 44 bytes. But it is possible to add more information to the header.

What you should do is skip the first 12 bytes (although you can use it to verify if a file is really a wave file). And then in a loop read the name and size of the next chunk. If it is a chunk you know ('fmt ' or 'data') you can process it, otherwise skip it.

So it can look like this for example:

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);
}


回答2:

Here're the (relatively) portable sources of my wav2pcm and pcm2wav utils: http://nishi.dreamhosters.com/u/wav2pcm_v0.rar



回答3:

See libsndfile.

http://en.wikipedia.org/wiki/Libsndfile