1
votes

I am quite new to audio processing and my C++ programming skills are also on basic level. I have to create recording function and I receive data signal from device in form of callback. I would like someone to assist me with basic theory how should I manage WAV memory because I am lost. For now my code looks like this:

Functions I am currently using:

template <typename T>
void write(std::ofstream& stream, const T& t) {
  stream.write((const char*)&t, sizeof(T));
}

template <typename T>
void writeFormat(std::ofstream& stream) {
  write<short>(stream, 1);
}

template <>
void writeFormat<float>(std::ofstream& stream) {
  write<short>(stream, 3);
}

template <typename SampleType>
void writeWAVData(
  char const* outFile,
  SampleType* buf,
  size_t bufSize,
  int sampleRate,
  short channels)
{
  std::ofstream stream(outFile, std::ios::binary|ios::app|ios::ate);

  stream.write("RIFF", 4);                                        // Start writting RIFF
  write<int>(stream, 0);                                          // (file-size)-8 - FOR NOW IGNORED
  stream.write("WAVE", 4);                                        // File type

  stream.write("fmt ", 4);                                        // Start Writting format chunk "fmt"
  write<int>(stream, 16);                                         // Chunk Data Size 16 + extra format bytes
  writeFormat<SampleType>(stream);                                // Format (compression code)
  write<short>(stream, channels);                                 // Channels
  write<int>(stream, sampleRate);                                 // Sample Rate
  write<int>(stream, sampleRate * channels * sizeof(SampleType)); // Byterate (byte/per sec)
  write<short>(stream, channels * sizeof(SampleType));            // Frame size (block align)
  write<short>(stream, 8 * sizeof(SampleType));                   // Bits per sample 

  stream.write("data", 4);                                        // Start writting chunk for extra format bytes
  stream.write((const char*)&bufSize, 0);                         //  - FOR NOW IGNORED
  stream.write((const char*)buf, 0);                              //  - FOR NOW IGNORED
}

General idea what I want to do is:

  1. Create *.wav file.
  2. Write header chunk.
  3. Add new data at the end of file as long user doesn't stop it.
  4. When user clicks stop, go back to the header memory and edit field under "RIFF" and "data" chunks with right value.

First Question: So I have buffer storing 256 samples so in loop, every 256 I try to write buffer with new data to the file like in code below. After reading *.wav documentaiton http://www.sonicspot.com/guide/wavefiles.html I understand that *.wav file should have RIFF header at start of each chunk. But if I write buffer with 256 samples and place RIFF chunk before it what's difference if I would enter 512 samples instead? Does every sample need RIFF chunk before it?

for (int j = 0 ; j < 256 ; j++)
{
    if (j == 255) 
        writeWAVData("mySound0.wav", (int*)bufferInfos[0].buffers[doubleBufferIndex], buffSize, 44100, 1);
}

Where:

  • bufferInfos[] - holds table of various buffers but I want to save data from only one now
  • bufferInfos[0].buffers[doubleBufferIndex] - is a pointer to first buffer data block
  • doubleBufferIndex - index of pan, takes values 0-1, left, right, left, right etc

Second question: is about channel parameter because it's a bit confusing. My signal consists of values received in turns: left pan, right pan, left pan, right pan... so that would mean I have 2 channels - left and right?

Third question: My signal from device is 24bit... shouldn't I just write in the bits per sample 24 then or how should it include this information.

1
Did you read the answer to your previous question? (stackoverflow.com/questions/28229815/…) It seems to me that this question has quite some overlap. Specifically, we told you that you can't put the file size in the header until the recording finishes.MSalters
Wanted to form question differently. Response for last question was correct but still I wasn't sure of some things so I wanted added another one. It's connected to the same topic co it might overlap a bit sorry.F1sher

1 Answers

2
votes

The RIFF header appears once per file, at the beginning. You attempt to include multiple.

Conventionally, the WAVE header appears once per recording. The .WAV format allows multiple, but that would be similar to an album.

You indeed have two channels, obviously.

And yes, if you have 24 bits per sample, then you must put that in, and write exactly 3 bytes per sample. That is to say,

template <typename T>
void write(std::ofstream& stream, const T& t) {
  stream.write((const char*)&t, sizeof(T));
}

is unlikely to do that. And sizeof(SampleType) probably isn't 3 either.