1
0

AudioReadTarget.h 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. /*
  2. * AudioReadTarget.h
  3. * -----------------
  4. * Purpose: Callback class implementations for audio data read via CSoundFile::Read.
  5. * Notes : (currently none)
  6. * Authors: OpenMPT Devs
  7. * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
  8. */
  9. #pragma once
  10. #include "openmpt/all/BuildSettings.hpp"
  11. #include "Sndfile.h"
  12. #include "mpt/audio/span.hpp"
  13. #include "openmpt/soundbase/SampleFormat.hpp"
  14. #include "openmpt/soundbase/CopyMix.hpp"
  15. #include "openmpt/soundbase/Dither.hpp"
  16. #include "MixerLoops.h"
  17. #include "Mixer.h"
  18. #include "../common/Dither.h"
  19. #include <type_traits>
  20. OPENMPT_NAMESPACE_BEGIN
  21. template <typename Taudio_span, typename TDithers = DithersOpenMPT>
  22. class AudioTargetBuffer
  23. : public IAudioTarget
  24. {
  25. private:
  26. std::size_t countRendered;
  27. TDithers &dithers;
  28. protected:
  29. Taudio_span outputBuffer;
  30. public:
  31. AudioTargetBuffer(Taudio_span buf, TDithers &dithers_)
  32. : countRendered(0)
  33. , dithers(dithers_)
  34. , outputBuffer(buf)
  35. {
  36. return;
  37. }
  38. std::size_t GetRenderedCount() const { return countRendered; }
  39. public:
  40. void Process(mpt::audio_span_interleaved<MixSampleInt> buffer) override
  41. {
  42. std::visit(
  43. [&](auto &ditherInstance)
  44. {
  45. ConvertBufferMixInternalFixedToBuffer<MixSampleIntTraits::mix_fractional_bits, false>(mpt::make_audio_span_with_offset(outputBuffer, countRendered), buffer, ditherInstance, buffer.size_channels(), buffer.size_frames());
  46. },
  47. dithers.Variant()
  48. );
  49. countRendered += buffer.size_frames();
  50. }
  51. void Process(mpt::audio_span_interleaved<MixSampleFloat> buffer) override
  52. {
  53. std::visit(
  54. [&](auto &ditherInstance)
  55. {
  56. ConvertBufferMixInternalToBuffer<false>(mpt::make_audio_span_with_offset(outputBuffer, countRendered), buffer, ditherInstance, buffer.size_channels(), buffer.size_frames());
  57. },
  58. dithers.Variant()
  59. );
  60. countRendered += buffer.size_frames();
  61. }
  62. };
  63. template <typename Taudio_span, typename TDithers = DithersOpenMPT>
  64. class AudioTargetBufferWithGain
  65. : public AudioTargetBuffer<Taudio_span>
  66. {
  67. private:
  68. using Tbase = AudioTargetBuffer<Taudio_span>;
  69. private:
  70. const float gainFactor;
  71. public:
  72. AudioTargetBufferWithGain(Taudio_span buf, TDithers &dithers, float gainFactor_)
  73. : Tbase(buf, dithers)
  74. , gainFactor(gainFactor_)
  75. {
  76. return;
  77. }
  78. public:
  79. void Process(mpt::audio_span_interleaved<MixSampleInt> buffer) override
  80. {
  81. const std::size_t countRendered_ = Tbase::GetRenderedCount();
  82. if constexpr(!std::is_floating_point<typename Taudio_span::sample_type>::value)
  83. {
  84. int32 gainFactor16_16 = mpt::saturate_round<int32>(gainFactor * (1 << 16));
  85. if(gainFactor16_16 != (1<<16))
  86. {
  87. // only apply gain when != +/- 0dB
  88. // no clipping prevention is done here
  89. for(std::size_t frame = 0; frame < buffer.size_frames(); ++frame)
  90. {
  91. for(std::size_t channel = 0; channel < buffer.size_channels(); ++channel)
  92. {
  93. buffer(channel, frame) = Util::muldiv(buffer(channel, frame), gainFactor16_16, 1 << 16);
  94. }
  95. }
  96. }
  97. }
  98. Tbase::Process(buffer);
  99. if constexpr(std::is_floating_point<typename Taudio_span::sample_type>::value)
  100. {
  101. if(gainFactor != 1.0f)
  102. {
  103. // only apply gain when != +/- 0dB
  104. for(std::size_t frame = 0; frame < buffer.size_frames(); ++frame)
  105. {
  106. for(std::size_t channel = 0; channel < buffer.size_channels(); ++channel)
  107. {
  108. Tbase::outputBuffer(channel, countRendered_ + frame) *= gainFactor;
  109. }
  110. }
  111. }
  112. }
  113. }
  114. void Process(mpt::audio_span_interleaved<MixSampleFloat> buffer) override
  115. {
  116. if(gainFactor != 1.0f)
  117. {
  118. // only apply gain when != +/- 0dB
  119. for(std::size_t frame = 0; frame < buffer.size_frames(); ++frame)
  120. {
  121. for(std::size_t channel = 0; channel < buffer.size_channels(); ++channel)
  122. {
  123. buffer(channel, frame) *= gainFactor;
  124. }
  125. }
  126. }
  127. Tbase::Process(buffer);
  128. }
  129. };
  130. OPENMPT_NAMESPACE_END