/* * AudioReadTarget.h * ----------------- * Purpose: Callback class implementations for audio data read via CSoundFile::Read. * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "BuildSettings.h" #include "Sndfile.h" #include "../soundbase/SampleFormat.h" #include "../soundbase/SampleFormatConverters.h" #include "../soundbase/SampleFormatCopy.h" #include "../soundbase/SampleBuffer.h" #include "../soundbase/Dither.h" #include "MixerLoops.h" #include "Mixer.h" OPENMPT_NAMESPACE_BEGIN template class AudioReadTargetBuffer : public IAudioReadTarget { private: std::size_t countRendered; Dither &dither; protected: Tbuffer outputBuffer; public: AudioReadTargetBuffer(Tbuffer buf, Dither &dither_) : countRendered(0) , dither(dither_) , outputBuffer(buf) { MPT_ASSERT(SampleFormat(SampleFormatTraits::sampleFormat()).IsValid()); } std::size_t GetRenderedCount() const { return countRendered; } public: void DataCallback(MixSampleInt *MixSoundBuffer, std::size_t channels, std::size_t countChunk) override { dither.WithDither( [&](auto &ditherInstance) { ConvertBufferMixFixedToBuffer(advance_audio_buffer(outputBuffer, countRendered), audio_buffer_interleaved(MixSoundBuffer, channels, countChunk), ditherInstance, channels, countChunk); } ); countRendered += countChunk; } void DataCallback(MixSampleFloat *MixSoundBuffer, std::size_t channels, std::size_t countChunk) override { dither.WithDither( [&](auto &ditherInstance) { ConvertBufferMixFloatToBuffer(advance_audio_buffer(outputBuffer, countRendered), audio_buffer_interleaved(MixSoundBuffer, channels, countChunk), ditherInstance, channels, countChunk); } ); countRendered += countChunk; } }; #if defined(LIBOPENMPT_BUILD) template void ApplyGainBeforeConversionIfAppropriateFixed(MixSampleInt *MixSoundBuffer, std::size_t channels, std::size_t countChunk, float gainFactor) { // Apply final output gain for non floating point output ApplyGain(MixSoundBuffer, channels, countChunk, mpt::saturate_round(gainFactor * (1<<16))); } template<> void ApplyGainBeforeConversionIfAppropriateFixed(MixSampleInt * /*MixSoundBuffer*/, std::size_t /*channels*/, std::size_t /*countChunk*/, float /*gainFactor*/) { // nothing } template void ApplyGainAfterConversionIfAppropriateFixed(audio_buffer_interleaved /*buffer*/, std::size_t /*countRendered*/, std::size_t /*channels*/, std::size_t /*countChunk*/, float /*gainFactor*/) { // nothing } template void ApplyGainAfterConversionIfAppropriateFixed(audio_buffer_planar /*buffer*/, std::size_t /*countRendered*/, std::size_t /*channels*/, std::size_t /*countChunk*/, float /*gainFactor*/) { // nothing } template<> void ApplyGainAfterConversionIfAppropriateFixed(audio_buffer_interleaved buffer, std::size_t countRendered, std::size_t channels, std::size_t countChunk, float gainFactor) { // Apply final output gain for floating point output after conversion so we do not suffer underflow or clipping ApplyGain(buffer, countRendered, channels, countChunk, gainFactor); } template<> void ApplyGainAfterConversionIfAppropriateFixed(audio_buffer_planar buffer, std::size_t countRendered, std::size_t channels, std::size_t countChunk, float gainFactor) { // Apply final output gain for floating point output after conversion so we do not suffer underflow or clipping ApplyGain(buffer, countRendered, channels, countChunk, gainFactor); } inline void ApplyGainBeforeConversionIfAppropriateFloat(MixSampleFloat *MixSoundBuffer, std::size_t channels, std::size_t countChunk, float gainFactor) { // Apply final output gain for non floating point output ApplyGain(MixSoundBuffer, channels, countChunk, gainFactor); } template class AudioReadTargetGainBuffer : public AudioReadTargetBuffer { private: typedef AudioReadTargetBuffer Tbase; private: const float gainFactor; public: AudioReadTargetGainBuffer(Tbuffer buf, Dither &dither, float gainFactor_) : Tbase(buf, dither) , gainFactor(gainFactor_) { return; } public: void DataCallback(MixSampleInt *MixSoundBuffer, std::size_t channels, std::size_t countChunk) override { const std::size_t countRendered_ = Tbase::GetRenderedCount(); ApplyGainBeforeConversionIfAppropriateFixed(MixSoundBuffer, channels, countChunk, gainFactor); Tbase::DataCallback(MixSoundBuffer, channels, countChunk); ApplyGainAfterConversionIfAppropriateFixed(Tbase::outputBuffer, countRendered_, channels, countChunk, gainFactor); } void DataCallback(MixSampleFloat *MixSoundBuffer, std::size_t channels, std::size_t countChunk) override { ApplyGainBeforeConversionIfAppropriateFloat(MixSoundBuffer, channels, countChunk, gainFactor); Tbase::DataCallback(MixSoundBuffer, channels, countChunk); } }; #endif // LIBOPENMPT_BUILD OPENMPT_NAMESPACE_END