From 6581a3bd3c34cf77a1a604baca92b5b0d76d61b0 Mon Sep 17 00:00:00 2001 From: Dimitri Diakopoulos Date: Thu, 21 May 2015 20:48:05 -0700 Subject: [PATCH] handle common mono=>stereo; stereo=>mono mixing for wav encoding --- examples/src/Main.cpp | 4 +-- include/libnyquist/WavEncoder.h | 1 + src/WavEncoder.cpp | 52 +++++++++++++++++++++++++++++---- 3 files changed, 50 insertions(+), 7 deletions(-) diff --git a/examples/src/Main.cpp b/examples/src/Main.cpp index aea2ddf..567a578 100644 --- a/examples/src/Main.cpp +++ b/examples/src/Main.cpp @@ -33,13 +33,13 @@ int main() //auto result = loader.Load(fileData, "test_data/1ch/44100/8/test.wav"); //auto result = loader.Load(fileData, "test_data/1ch/44100/16/test.wav"); //auto result = loader.Load(fileData, "test_data/1ch/44100/24/test.wav"); - //auto result = loader.Load(fileData, "test_data/1ch/44100/32/test.wav"); + auto result = loader.Load(fileData, "test_data/1ch/44100/32/test.wav"); //auto result = loader.Load(fileData, "test_data/1ch/44100/64/test.wav"); //auto result = loader.Load(fileData, "test_data/2ch/44100/8/test.wav"); //auto result = loader.Load(fileData, "test_data/2ch/44100/16/test.wav"); //auto result = loader.Load(fileData, "test_data/2ch/44100/24/test.wav"); - auto result = loader.Load(fileData, "test_data/2ch/44100/32/test.wav"); + //auto result = loader.Load(fileData, "test_data/2ch/44100/32/test.wav"); //auto result = loader.Load(fileData, "test_data/2ch/44100/64/test.wav"); //auto result = loader.Load(fileData, "test_data/ad_hoc/6_channel_44k_16b.wav"); diff --git a/include/libnyquist/WavEncoder.h b/include/libnyquist/WavEncoder.h index 60a2034..a7dd72d 100644 --- a/include/libnyquist/WavEncoder.h +++ b/include/libnyquist/WavEncoder.h @@ -47,6 +47,7 @@ class WavEncoder UnsupportedSamplerate, UnsupportedChannelConfiguration, UnsupportedBitdepth, + UnsupportedChannelMix, BufferTooBig, }; diff --git a/src/WavEncoder.cpp b/src/WavEncoder.cpp index 658abe4..ec046c2 100644 --- a/src/WavEncoder.cpp +++ b/src/WavEncoder.cpp @@ -42,7 +42,13 @@ WavEncoder::~WavEncoder() {} int WavEncoder::WriteFile(const EncoderParams p, const AudioData * d, const std::string & path) { - if (d->samples.size() <= 32) + // Cast away const because we know what we are doing (Hopefully?) + float * sampleData = const_cast(d->samples.data()); + size_t sampleDataSize = d->samples.size(); + + std::vector sampleDataOptionalMix; + + if (sampleDataSize <= 32) { return EncoderError::InsufficientSampleData; } @@ -52,8 +58,44 @@ int WavEncoder::WriteFile(const EncoderParams p, const AudioData * d, const std: return EncoderError::UnsupportedChannelConfiguration; } + // Handle Channel Mixing -- + + // Mono => Stereo + if (d->channelCount == 1 && p.channelCount == 2) + { + sampleDataOptionalMix.resize(sampleDataSize * 2); + MonoToStereo(sampleData, sampleDataOptionalMix.data(), sampleDataSize); // Mix + + // Re-point data + sampleData = sampleDataOptionalMix.data(); + sampleDataSize = sampleDataOptionalMix.size(); + } + + // Stereo => Mono + else if (d->channelCount == 2 && p.channelCount == 1) + { + sampleDataOptionalMix.resize(sampleDataSize / 2); + StereoToMono(sampleData, sampleDataOptionalMix.data(), sampleDataSize); // Mix + + // Re-point data + sampleData = sampleDataOptionalMix.data(); + sampleDataSize = sampleDataOptionalMix.size(); + + } + + else if (d->channelCount == p.channelCount) + { + // No op + } + + else + { + return EncoderError::UnsupportedChannelMix; + } + // -- End Channel Mixing + auto maxFileSizeInBytes = std::numeric_limits::max(); - auto samplesSizeInBytes = (d->samples.size() * GetFormatBitsPerSample(p.targetFormat)) / 8; + auto samplesSizeInBytes = (sampleDataSize * GetFormatBitsPerSample(p.targetFormat)) / 8; // 64 arbitrary if ((samplesSizeInBytes - 64) >= maxFileSizeInBytes) @@ -100,7 +142,7 @@ int WavEncoder::WriteFile(const EncoderParams p, const AudioData * d, const std: if (p.targetFormat == PCM_FLT) { uint32_t four = 4; - uint32_t dataSz = int(d->samples.size() / d->channelCount); + uint32_t dataSz = int(sampleDataSize / p.channelCount); fout.write(GenerateChunkCodeChar('f', 'a', 'c', 't'), 4); fout.write(reinterpret_cast(&four), 4); fout.write(reinterpret_cast(&dataSz), 4); // Number of samples (per channel) @@ -117,14 +159,14 @@ int WavEncoder::WriteFile(const EncoderParams p, const AudioData * d, const std: { // At most need this number of bytes in our copy std::vector samplesCopy(samplesSizeInBytes); - ConvertFromFloat32(samplesCopy.data(), d->samples.data(), d->samples.size(), p.targetFormat, p.dither); + ConvertFromFloat32(samplesCopy.data(), sampleData, sampleDataSize, p.targetFormat, p.dither); fout.write(reinterpret_cast(samplesCopy.data()), samplesSizeInBytes); } else { // Handle PCM_FLT. Coming in from AudioData ensures we start with 32 bits, so we're fine // since we've also rejected formats with more than 32 bits above. - fout.write(reinterpret_cast(d->samples.data()), samplesSizeInBytes); + fout.write(reinterpret_cast(sampleData), samplesSizeInBytes); } // Padding byte