Fixed SoundEffects example allocating effect processor resources based on source channel count instead of engine channel count.

This commit is contained in:
binary1248 2024-06-23 17:16:58 +02:00 committed by Lukas Dürrenberger
parent 6ab03cc3ee
commit be63ffa8d4
2 changed files with 42 additions and 21 deletions

View File

@ -758,12 +758,19 @@ protected:
music.setEffectProcessor( music.setEffectProcessor(
[coefficients, [coefficients,
enabled = getEnabled(), enabled = getEnabled(),
state = std::vector<State>(music.getChannelCount())](const float* inputFrames, state = std::vector<State>()](const float* inputFrames,
unsigned int& inputFrameCount, unsigned int& inputFrameCount,
float* outputFrames, float* outputFrames,
unsigned int& outputFrameCount, unsigned int& outputFrameCount,
unsigned int frameChannelCount) mutable unsigned int frameChannelCount) mutable
{ {
// IMPORTANT: The channel count of the audio engine currently sourcing data from this sound
// will always be provided in frameChannelCount, this can be different from the channel count
// of the audio source so make sure to size your buffers according to the engine and not the source
// Ensure we have as many state objects as the audio engine has channels
if (state.size() < frameChannelCount)
state.resize(frameChannelCount - state.size());
for (auto frame = 0u; frame < outputFrameCount; ++frame) for (auto frame = 0u; frame < outputFrameCount; ++frame)
{ {
for (auto channel = 0u; channel < frameChannelCount; ++channel) for (auto channel = 0u; channel < frameChannelCount; ++channel)
@ -856,7 +863,6 @@ struct Echo : Processing
static constexpr auto wet = 0.8f; static constexpr auto wet = 0.8f;
static constexpr auto dry = 1.f; static constexpr auto dry = 1.f;
const auto channelCount = music.getChannelCount();
const auto sampleRate = music.getSampleRate(); const auto sampleRate = music.getSampleRate();
const auto delayInFrames = static_cast<unsigned int>(static_cast<float>(sampleRate) * delay); const auto delayInFrames = static_cast<unsigned int>(static_cast<float>(sampleRate) * delay);
@ -868,13 +874,20 @@ struct Echo : Processing
music.setEffectProcessor( music.setEffectProcessor(
[delayInFrames, [delayInFrames,
enabled = getEnabled(), enabled = getEnabled(),
buffer = std::vector<float>(delayInFrames * channelCount, 0.f), buffer = std::vector<float>(),
cursor = 0u](const float* inputFrames, cursor = 0u](const float* inputFrames,
unsigned int& inputFrameCount, unsigned int& inputFrameCount,
float* outputFrames, float* outputFrames,
unsigned int& outputFrameCount, unsigned int& outputFrameCount,
unsigned int frameChannelCount) mutable unsigned int frameChannelCount) mutable
{ {
// IMPORTANT: The channel count of the audio engine currently sourcing data from this sound
// will always be provided in frameChannelCount, this can be different from the channel count
// of the audio source so make sure to size your buffers according to the engine and not the source
// Ensure we have enough space to store the delayed frames for all of the audio engine's channels
if (buffer.size() < delayInFrames * frameChannelCount)
buffer.resize(delayInFrames * frameChannelCount - buffer.size(), 0.f);
for (auto frame = 0u; frame < outputFrameCount; ++frame) for (auto frame = 0u; frame < outputFrameCount; ++frame)
{ {
for (auto channel = 0u; channel < frameChannelCount; ++channel) for (auto channel = 0u; channel < frameChannelCount; ++channel)
@ -910,27 +923,27 @@ public:
static constexpr auto sustain = 0.7f; // [0.f; 1.f] static constexpr auto sustain = 0.7f; // [0.f; 1.f]
const auto channelCount = music.getChannelCount();
const auto sampleRate = music.getSampleRate();
std::vector<ReverbFilter<float>> filters;
filters.reserve(channelCount);
for (auto i = 0u; i < channelCount; ++i)
filters.emplace_back(sampleRate, sustain);
// We use a mutable lambda to tie the lifetime of the state to the lambda itself // We use a mutable lambda to tie the lifetime of the state to the lambda itself
// This is necessary since the Echo object will be destroyed before the Music object // This is necessary since the Echo object will be destroyed before the Music object
// While the Music object exists, it is possible that the audio engine will try to call // While the Music object exists, it is possible that the audio engine will try to call
// this lambda hence we need to always have a usable state until the Music and the // this lambda hence we need to always have a usable state until the Music and the
// associated lambda are destroyed // associated lambda are destroyed
music.setEffectProcessor( music.setEffectProcessor(
[filters, enabled = getEnabled()](const float* inputFrames, [sampleRate = music.getSampleRate(),
filters = std::vector<ReverbFilter<float>>(),
enabled = getEnabled()](const float* inputFrames,
unsigned int& inputFrameCount, unsigned int& inputFrameCount,
float* outputFrames, float* outputFrames,
unsigned int& outputFrameCount, unsigned int& outputFrameCount,
unsigned int frameChannelCount) mutable unsigned int frameChannelCount) mutable
{ {
// IMPORTANT: The channel count of the audio engine currently sourcing data from this sound
// will always be provided in frameChannelCount, this can be different from the channel count
// of the audio source so make sure to size your buffers according to the engine and not the source
// Ensure we have as many filter objects as the audio engine has channels
while (filters.size() < frameChannelCount)
filters.emplace_back(sampleRate, sustain);
for (auto frame = 0u; frame < outputFrameCount; ++frame) for (auto frame = 0u; frame < outputFrameCount; ++frame)
{ {
for (auto channel = 0u; channel < frameChannelCount; ++channel) for (auto channel = 0u; channel < frameChannelCount; ++channel)

View File

@ -108,6 +108,14 @@ public:
/// count or write more frames than the output frame count /// count or write more frames than the output frame count
/// will result in undefined behaviour. /// will result in undefined behaviour.
/// ///
/// It is important to note that the channel count of the
/// audio engine currently sourcing data from this sound
/// will always be provided in frameChannelCount. This can
/// be different from the channel count of the sound source
/// so make sure to size necessary processing buffers
/// according to the engine channel count and not the sound
/// source channel count.
///
/// When done processing the frames, the input and output /// When done processing the frames, the input and output
/// frame counts must be updated to reflect the actual /// frame counts must be updated to reflect the actual
/// number of frames that were read from the input and /// number of frames that were read from the input and