3

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

Paul R
  • 208,748
  • 37
  • 389
  • 560
  • 1
    Yes - this should be quite straightforward - you just need a suitable library for converting between WAV file data and raw PCM samples in memory. – Paul R Mar 21 '11 at 14:53

3 Answers3

5

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);
}
wimh
  • 15,072
  • 6
  • 47
  • 98
  • Okay but I am still unsure how to write this? Its been suggested that I need an audio file reader and store everything in a buffer. Then manipulate the samples and export out. But putting this to code, especially when i'm still new to this is difficult. Also if im just changing the sample values and not removing any, I dont think I need to change anything in the RIFF header? – James Branston Mar 22 '11 at 13:04
  • I think it is better for you to split this into smaller tasks. Do not try to write this at once, but first parse the RIFF headers and display information about it on the screen. If you are new to this, it is also better for you to start yourself and ask for help when you are stuck. But if you let others create all the code, you will learn nothing. Regarding your comment, you can only store everything in a buffer, if the file is not too large. Otherwise you will run out of memory. But you can also put just a part of the file in a buffer, and manipulate that. But that might be more difficult. – wimh Mar 22 '11 at 21:32
  • Okay so I've been looking at the resources on WAVE and RIFF using this website:[link](https://ccrma.stanford.edu/courses/422/projects/WaveFormat/) . I knew most of this in theory but never went around programming it and such. I've looked around abit and have been studying a code which lead me to write this: [link](http://img42.imageshack.us/i/screenshot20110323at133.png/) I used a picture because using the code (or pastebin) messed up the formatting of my annotations. But this code has nothing to go into it yet. How do I get it to read audio so it can display this information? fload? – James Branston Mar 23 '11 at 13:39
  • I have added some more info above. – wimh Mar 23 '11 at 21:52
0

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

Shelwien
  • 2,160
  • 15
  • 17
0

See libsndfile.

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

moala
  • 5,094
  • 9
  • 45
  • 66