From db24efcfa42e1b4f75845899c50bceb6b0a08665 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 13 Jun 2025 16:18:00 +0200 Subject: [PATCH] Remove the inner class, since we're only working with a single stereo stream. --- Core/HW/GranularMixer.cpp | 30 ++++------- Core/HW/GranularMixer.h | 106 +++++++++++++++++--------------------- 2 files changed, 57 insertions(+), 79 deletions(-) diff --git a/Core/HW/GranularMixer.cpp b/Core/HW/GranularMixer.cpp index 4760452212..761f4a57db 100644 --- a/Core/HW/GranularMixer.cpp +++ b/Core/HW/GranularMixer.cpp @@ -79,7 +79,10 @@ GranularMixer::GranularMixer() { } // Executed from sound stream thread -void GranularMixer::MixerFifo::Mix(s16* samples, u32 num_samples, int outSampleRate) { +std::size_t GranularMixer::Mix(s16 *samples, u32 num_samples, int outSampleRate) { + if (!samples) + return 0; + memset(samples, 0, num_samples * 2 * sizeof(s16)); constexpr u32 INDEX_HALF = 0x80000000; constexpr DT_s FADE_IN_RC = DT_s(0.008); constexpr DT_s FADE_OUT_RC = DT_s(0.064); @@ -101,13 +104,13 @@ void GranularMixer::MixerFifo::Mix(s16* samples, u32 num_samples, int outSampleR const float fade_out_mul = -std::expm1(-DT_s(1.0) / (out_sample_rate * FADE_OUT_RC)); // Calculate the ideal length of the granule queue. - const std::size_t buffer_size_ms = 40; // TODO: Actually take from the audio backend. - const std::size_t buffer_size_samples = std::llround(buffer_size_ms * in_sample_rate / 1000.0); + const u32 buffer_size_ms = 40; // TODO: Actually take from the audio backend. + const u32 buffer_size_samples = std::llround(buffer_size_ms * in_sample_rate / 1000.0); // Limit the possible queue sizes to any number between 4 and 64. const u32 buffer_size_granules = - std::clamp((buffer_size_samples) / (GRANULE_SIZE >> 1), static_cast(4), - static_cast(MAX_GRANULE_QUEUE_SIZE)); + std::clamp((buffer_size_samples) / (GRANULE_SIZE >> 1), static_cast(4), + static_cast(MAX_GRANULE_QUEUE_SIZE)); m_granule_queue_size.store(buffer_size_granules, std::memory_order_relaxed); @@ -174,17 +177,10 @@ void GranularMixer::MixerFifo::Mix(s16* samples, u32 num_samples, int outSampleR samples += 2; } -} - -std::size_t GranularMixer::Mix(s16* samples, u32 num_samples, int outSampleRate) { - if (!samples) - return 0; - memset(samples, 0, num_samples * 2 * sizeof(s16)); - m_dma_mixer.Mix(samples, num_samples, outSampleRate); return num_samples; } -void GranularMixer::MixerFifo::PushSamples(const s32 *samples, u32 num_samples, float volume) { +void GranularMixer::PushSamples(const s32 *samples, u32 num_samples, float volume) { // TODO: This can be massively sped up. Although hardly likely to be a bottleneck. while (num_samples-- > 0) { const s16 l = clampfloat_s16(samples[0] * volume); @@ -202,11 +198,7 @@ void GranularMixer::MixerFifo::PushSamples(const s32 *samples, u32 num_samples, } } -void GranularMixer::PushSamples(const s32 *samples, u32 num_samples, float volume) { - m_dma_mixer.PushSamples(samples, num_samples, volume); -} - -void GranularMixer::MixerFifo::Enqueue() { +void GranularMixer::Enqueue() { // import numpy as np // import scipy.signal as signal // window = np.convolve(np.ones(128), signal.windows.dpss(128 + 1, 4)) @@ -235,7 +227,7 @@ void GranularMixer::MixerFifo::Enqueue() { m_queue_looping.store(false, std::memory_order_relaxed); } -void GranularMixer::MixerFifo::Dequeue(Granule* granule) { +void GranularMixer::Dequeue(Granule* granule) { const std::size_t granule_queue_size = m_granule_queue_size.load(std::memory_order_relaxed); const std::size_t head = m_queue_head.load(std::memory_order_acquire); std::size_t tail = m_queue_tail.load(std::memory_order_acquire); diff --git a/Core/HW/GranularMixer.h b/Core/HW/GranularMixer.h index 39fae20893..57bf53be7e 100644 --- a/Core/HW/GranularMixer.h +++ b/Core/HW/GranularMixer.h @@ -34,71 +34,57 @@ public: void PushSamples(const s32* samples, u32 num_samples, float volume); private: - const std::size_t SURROUND_CHANNELS = 6; + static constexpr std::size_t MAX_GRANULE_QUEUE_SIZE = 128; + static constexpr std::size_t GRANULE_QUEUE_MASK = MAX_GRANULE_QUEUE_SIZE - 1; - class MixerFifo final { - static constexpr std::size_t MAX_GRANULE_QUEUE_SIZE = 128; - static constexpr std::size_t GRANULE_QUEUE_MASK = MAX_GRANULE_QUEUE_SIZE - 1; + struct StereoPair final { + float l = 0.f; + float r = 0.f; - struct StereoPair final { - float l = 0.f; - float r = 0.f; + constexpr StereoPair() = default; + constexpr StereoPair(const StereoPair&) = default; + constexpr StereoPair& operator=(const StereoPair&) = default; + constexpr StereoPair(StereoPair&&) = default; + constexpr StereoPair& operator=(StereoPair&&) = default; - constexpr StereoPair() = default; - constexpr StereoPair(const StereoPair&) = default; - constexpr StereoPair& operator=(const StereoPair&) = default; - constexpr StereoPair(StereoPair&&) = default; - constexpr StereoPair& operator=(StereoPair&&) = default; + constexpr StereoPair(float mono) : l(mono), r(mono) {} + constexpr StereoPair(float left, float right) : l(left), r(right) {} + constexpr StereoPair(s16 left, s16 right) : l(left), r(right) {} - constexpr StereoPair(float mono) : l(mono), r(mono) {} - constexpr StereoPair(float left, float right) : l(left), r(right) {} - constexpr StereoPair(s16 left, s16 right) : l(left), r(right) {} + StereoPair operator+(const StereoPair& other) const { + return StereoPair(l + other.l, r + other.r); + } - StereoPair operator+(const StereoPair& other) const { - return StereoPair(l + other.l, r + other.r); - } - - StereoPair operator*(float f) const { - return StereoPair(l * f, r * f); - } - }; - - static constexpr std::size_t GRANULE_SIZE = 256; - static constexpr std::size_t GRANULE_OVERLAP = GRANULE_SIZE / 2; - static constexpr std::size_t GRANULE_MASK = GRANULE_SIZE - 1; - static constexpr std::size_t GRANULE_BITS = countr_one_replacement(GRANULE_MASK); - static constexpr std::size_t GRANULE_FRAC_BITS = 32 - GRANULE_BITS; - - using Granule = std::array; - - public: - MixerFifo(GranularMixer* mixer, bool little_endian) : m_mixer(mixer) {} - void PushSamples(const s32* samples, u32 num_samples, float volume); - void Mix(s16* samples, u32 num_samples, int outSampleRate); - - private: - GranularMixer* m_mixer; - - Granule m_next_buffer{}; - u32 m_next_buffer_index = 0; - - u32 m_current_index = 0; - Granule m_front; - Granule m_back; - - std::atomic m_granule_queue_size{ 20 }; - Granule m_queue[MAX_GRANULE_QUEUE_SIZE]; - - std::atomic m_queue_head{}; - std::atomic m_queue_tail{}; - std::atomic m_queue_looping{ false }; - float m_fade_volume = 1.0; - - void Enqueue(); - void Dequeue(Granule* granule); - - StereoPair m_quantization_error; + StereoPair operator*(float f) const { + return StereoPair(l * f, r * f); + } }; - MixerFifo m_dma_mixer{ this, false }; + static constexpr u32 GRANULE_SIZE = 256; + static constexpr u32 GRANULE_OVERLAP = GRANULE_SIZE / 2; + static constexpr u32 GRANULE_MASK = GRANULE_SIZE - 1; + static constexpr u32 GRANULE_BITS = countr_one_replacement(GRANULE_MASK); + static constexpr u32 GRANULE_FRAC_BITS = 32 - GRANULE_BITS; + + using Granule = std::array; + + Granule m_next_buffer{}; + u32 m_next_buffer_index = 0; + + u32 m_current_index = 0; + Granule m_front; + Granule m_back; + + std::atomic m_granule_queue_size{ 20 }; + Granule m_queue[MAX_GRANULE_QUEUE_SIZE]; + + std::atomic m_queue_head{}; + std::atomic m_queue_tail{}; + std::atomic m_queue_looping{ false }; + float m_fade_volume = 1.0; + + void Enqueue(); + void Dequeue(Granule* granule); + + StereoPair m_quantization_error; };