Audio data consistency


After reading 16bit WAV data into an AudioBuffer and writing the same buffer back into another WAV file I found the written audio data differs from the original. Like: 0x7EE1 became 0x7EE2

...and that's strange as even 24bit audio data should be perfectly fitted in a 32bit float buffer without any rounding. The below code works perfectly for me, but thought to ask if there is any reason why the 2 way conversion alters the original data?

For the "roundToInt (const FloatType value)" template I found this disclaimer: "Note that this routine gets its speed at the expense of some accuracy."

...but what If I'm not allowed to alter the data? Is there a good way to use a more precise algorithm in the writer?

​int32 bitsPerSample = 16;

int32 sampleValue = static_cast<int32>(audioBuffer->getSample(0, 0) * (std::exp2(bitsPerSample - 1)));

switch (bitsPerSample) {
  case 24:
    *(output++) = sampleValue & 0xff;
    sampleValue >>= 8;
  case 16:
    *(output++) = sampleValue & 0xff;
    sampleValue >>= 8;
    *(output++) = sampleValue & 0xff;

Why are you not allowed to alter the data?

Alternatives could be just copying the file, or implementing a more precise algorithm yourself if you fancy?

Thanks Timur for your answer.

Here is an example: 

You want to split an audio file into 2 different audio files keeping the raw audio data unchanged. How would you do it? As if you read them then Juce will convert the integer data to float/double. When you write it back to the other files it will convert the data to integer but that will not equal to the input data, what is pretty much strange based on the fact 32bit float can exactly cover 24bit integer without modifying the original data.

The code above will do the conversion back nicely, and I can use that RAW data to concatenate to an opened AudioWriter. But then the AudioWrapper's header handling won't work because it uses some private variables to calculate the datasize ("uint64 lengthInSamples, bytesWritten;"). The easiest would be just implement a method instead of "AudioFormatWriter::writeFromAudioSampleBuffer()" or "AudioFormatWriter::writeFromFloatArrays()" but as the AudioFormatWriter's destructor will write the header of the audio file based on the private member variables "uint64 lengthInSamples, bytesWritten;" it won't work.

Please let me know if I'm wrong somewhere, as my problem is still on so looking for your ideas!

See this:

It's designed that way for exactly this purpose.