/* SPDX-License-Identifier: BSD-3-Clause */ /* SPDX-FileCopyrightText: OpenMPT Project Developers and Contributors */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "SoundDeviceCallback.hpp" #include "mpt/audio/span.hpp" #include "openmpt/base/Types.hpp" #include "openmpt/soundbase/Dither.hpp" #include "openmpt/soundbase/CopyMix.hpp" #include #include #include OPENMPT_NAMESPACE_BEGIN namespace SoundDevice { template class BufferIO { private: mpt::audio_span_interleaved const m_src; mpt::audio_span_interleaved const m_dst; std::size_t m_countFramesReadProcessed; std::size_t m_countFramesWriteProcessed; const BufferFormat m_bufferFormat; public: inline BufferIO(Tsample *dst, const Tsample *src, std::size_t numFrames, BufferFormat bufferFormat) : m_src(src, bufferFormat.InputChannels, numFrames) , m_dst(dst, bufferFormat.Channels, numFrames) , m_countFramesReadProcessed(0) , m_countFramesWriteProcessed(0) , m_bufferFormat(bufferFormat) { return; } template inline void Read(audio_span_dst dst) { assert(m_countFramesReadProcessed + dst.size_frames() <= m_src.size_frames()); ConvertBufferToBufferMixInternal(dst, mpt::make_audio_span_with_offset(m_src, m_countFramesReadProcessed), m_bufferFormat.InputChannels, dst.size_frames()); m_countFramesReadProcessed += dst.size_frames(); } template inline void ReadFixedPoint(audio_span_dst dst) { assert(m_countFramesReadProcessed + dst.size_frames() <= m_src.size_frames()); ConvertBufferToBufferMixInternalFixed(dst, mpt::make_audio_span_with_offset(m_src, m_countFramesReadProcessed), m_bufferFormat.InputChannels, dst.size_frames()); m_countFramesReadProcessed += dst.size_frames(); } template inline void Write(audio_span_src src, TDither &dither) { assert(m_countFramesWriteProcessed + src.size_frames() <= m_dst.size_frames()); if(m_bufferFormat.WantsClippedOutput) { ConvertBufferMixInternalToBuffer(mpt::make_audio_span_with_offset(m_dst, m_countFramesWriteProcessed), src, dither, m_bufferFormat.Channels, src.size_frames()); } else { ConvertBufferMixInternalToBuffer(mpt::make_audio_span_with_offset(m_dst, m_countFramesWriteProcessed), src, dither, m_bufferFormat.Channels, src.size_frames()); } m_countFramesWriteProcessed += src.size_frames(); } template inline void WriteFixedPoint(audio_span_src src, TDither &dither) { assert(m_countFramesWriteProcessed + src.size_frames() <= m_dst.size_frames()); if(m_bufferFormat.WantsClippedOutput) { ConvertBufferMixInternalFixedToBuffer(mpt::make_audio_span_with_offset(m_dst, m_countFramesWriteProcessed), src, dither, m_bufferFormat.Channels, src.size_frames()); } else { ConvertBufferMixInternalFixedToBuffer(mpt::make_audio_span_with_offset(m_dst, m_countFramesWriteProcessed), src, dither, m_bufferFormat.Channels, src.size_frames()); } m_countFramesWriteProcessed += src.size_frames(); } inline ~BufferIO() { // fill remaining buffer with silence while(m_countFramesWriteProcessed < m_dst.size_frames()) { for(std::size_t channel = 0; channel < m_dst.size_channels(); ++channel) { m_dst(channel, m_countFramesWriteProcessed) = SC::sample_cast(static_cast(0)); } m_countFramesWriteProcessed += 1; } } }; template class CallbackBuffer { private: std::variant< BufferIO, BufferIO, BufferIO, BufferIO, BufferIO, BufferIO, BufferIO> m_BufferIO; TDithers &m_Dithers; std::size_t m_NumFrames; public: template explicit inline CallbackBuffer(Tsample *dst, const Tsample *src, std::size_t numFrames, TDithers &dithers, BufferFormat bufferFormat) : m_BufferIO(BufferIO{dst, src, numFrames, bufferFormat}) , m_Dithers(dithers) , m_NumFrames(numFrames) { return; } inline std::size_t GetNumFrames() const { return m_NumFrames; } template inline void Read(audio_span_dst dst) { std::visit( [&](auto &bufferIO) { bufferIO.Read(dst); }, m_BufferIO); } template inline void ReadFixedPoint(audio_span_dst dst) { std::visit( [&](auto &bufferIO) { bufferIO.template ReadFixedPoint(dst); }, m_BufferIO); } template inline void Write(audio_span_src src) { std::visit( [&](auto &bufferIO) { std::visit( [&](auto &ditherInstance) { bufferIO.Write(src, ditherInstance); }, m_Dithers.Variant()); }, m_BufferIO); } template inline void WriteFixedPoint(audio_span_src src) { std::visit( [&](auto &bufferIO) { std::visit( [&](auto &ditherInstance) { bufferIO.template WriteFixedPoint(src, ditherInstance); }, m_Dithers.Variant()); }, m_BufferIO); } }; template class CallbackBufferHandler : public ICallback { private: TDithers m_Dithers; protected: template explicit CallbackBufferHandler(Trd &rd) : m_Dithers(rd) { return; } protected: inline TDithers &Dithers() { return m_Dithers; } private: template inline void SoundCallbackLockedProcessImpl(BufferFormat bufferFormat, std::size_t numFrames, Tsample *buffer, const Tsample *inputBuffer) { CallbackBuffer callbackBuffer{buffer, inputBuffer, numFrames, m_Dithers, bufferFormat}; SoundCallbackLockedCallback(callbackBuffer); } public: inline void SoundCallbackLockedProcess(BufferFormat bufferFormat, std::size_t numFrames, uint8 *buffer, const uint8 *inputBuffer) final { SoundCallbackLockedProcessImpl(bufferFormat, numFrames, buffer, inputBuffer); } inline void SoundCallbackLockedProcess(BufferFormat bufferFormat, std::size_t numFrames, int8 *buffer, const int8 *inputBuffer) final { SoundCallbackLockedProcessImpl(bufferFormat, numFrames, buffer, inputBuffer); } inline void SoundCallbackLockedProcess(BufferFormat bufferFormat, std::size_t numFrames, int16 *buffer, const int16 *inputBuffer) final { SoundCallbackLockedProcessImpl(bufferFormat, numFrames, buffer, inputBuffer); } inline void SoundCallbackLockedProcess(BufferFormat bufferFormat, std::size_t numFrames, int24 *buffer, const int24 *inputBuffer) final { SoundCallbackLockedProcessImpl(bufferFormat, numFrames, buffer, inputBuffer); } inline void SoundCallbackLockedProcess(BufferFormat bufferFormat, std::size_t numFrames, int32 *buffer, const int32 *inputBuffer) final { SoundCallbackLockedProcessImpl(bufferFormat, numFrames, buffer, inputBuffer); } inline void SoundCallbackLockedProcess(BufferFormat bufferFormat, std::size_t numFrames, float *buffer, const float *inputBuffer) final { SoundCallbackLockedProcessImpl(bufferFormat, numFrames, buffer, inputBuffer); } inline void SoundCallbackLockedProcess(BufferFormat bufferFormat, std::size_t numFrames, double *buffer, const double *inputBuffer) final { SoundCallbackLockedProcessImpl(bufferFormat, numFrames, buffer, inputBuffer); } virtual void SoundCallbackLockedCallback(CallbackBuffer &buffer) = 0; }; } // namespace SoundDevice OPENMPT_NAMESPACE_END