Skip to content

Commit

Permalink
Apply channel gains on the producer side of the RingBuffer
Browse files Browse the repository at this point in the history
  • Loading branch information
Paul-Licameli committed May 16, 2024
1 parent 03cdb98 commit 4cfb930
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 27 deletions.
60 changes: 38 additions & 22 deletions libraries/lib-audio-io/AudioIO.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2086,12 +2086,19 @@ void AudioIO::TransformPlayBuffers(
const auto numPlaybackSequences = mPlaybackSequences.size();
// mPlaybackBuffers correspond many-to-one with mPlaybackSequences
size_t iBuffer = 0;
const auto factor = decayFactor(mRate);
const bool silent =
mForceFadeOut.load(std::memory_order_relaxed) || IsPaused();
size_t iTrack = 0;
for (const auto vt : mPlaybackSequences) {
Finally Do{ [&]{ ++iTrack; } };
if (!vt)
continue;
const auto pGroup = vt->FindChannelGroup();
if (!pGroup)
continue;
// Check for asynchronous user changes in mute, solo, pause status
const bool drop = (silent || SequenceShouldBeSilent(*vt));

// Loop over the blocks of unflushed data, at most two
size_t discardable = 0;
Expand Down Expand Up @@ -2123,6 +2130,33 @@ void AudioIO::TransformPlayBuffers(
auto discarded = ringBuffer.Unput(discardable);
// assert(discarded == discardable);
}
// Iterate the two blocks again, only after latency has been shifted out,
// which maybe changes the extent of those blocks in memory, and apply
// the per-track pan, mute, gain, and solo, with microfading
for (unsigned iBlock : {0, 1}) {
size_t len = 0;
for (size_t iChannel = 0; iChannel < mNumPlaybackChannels; ++iChannel) {
const float goal = (drop ? 0.0f : vt->GetChannelGain(iChannel));
auto &laggingChannelGain = mOldChannelGains[iTrack][iChannel];
// if no microfades, jump in volume.
float diff = (mbMicroFades ? goal - laggingChannelGain : 0.0f);
auto &ringBuffer = *mPlaybackBuffers[iBuffer + iChannel];
const auto pair = ringBuffer.GetUnflushed(iBlock);
// Playback RingBuffers have float format: see AllocateBuffers
auto pFloats = reinterpret_cast<float*>(pair.first);
// The lengths of corresponding unflushed blocks should be
// the same for all channels
if (len == 0)
len = pair.second;
else
assert(len == pair.second);
for (size_t ii = 0; ii < len; ++ii) {
pFloats[ii] *= (goal - diff);
diff *= factor;
}
laggingChannelGain = goal - diff;
}
}
iBuffer += mNumPlaybackChannels;
}
}
Expand Down Expand Up @@ -2582,31 +2616,17 @@ void AudioIoCallback::AddToOutputChannel(unsigned int chan,
float * outputMeterFloats,
float * outputFloats,
const float * tempBuf,
bool drop,
const unsigned long len,
const PlayableSequence &ps,
float &laggingChannelGain)
const unsigned long len)
{
const auto numPlaybackChannels = mNumPlaybackChannels;
const auto factor = decayFactor(mRate);

float gain = ps.GetChannelGain(chan);
if (drop || mForceFadeOut.load(std::memory_order_relaxed) || IsPaused())
gain = 0.0;

const float goal = gain;
// if no microfades, jump in volume.
float diff = (mbMicroFades ? goal - laggingChannelGain : 0.0f);
for (size_t i = 0; i < len; ++i) {
const auto term = (goal - diff) * tempBuf[i];
const auto term = tempBuf[i];
outputFloats[numPlaybackChannels * i + chan] += term;
if (outputMeterFloats != outputFloats)
// The level shown in output meters also sums the track level
// microfaded for gain, pan, and mute, but before applying master gain
outputMeterFloats[numPlaybackChannels * i + chan] += term;
diff *= factor;
}
laggingChannelGain = goal - diff;
};

// Limit values to -1.0..+1.0
Expand Down Expand Up @@ -2684,9 +2704,6 @@ bool AudioIoCallback::FillOutputBuffers(
for (unsigned tt = 0; tt < numPlaybackSequences; ++tt) {
auto vt = mPlaybackSequences[tt].get();

// Check for asynchronous user changes in mute, solo, pause status
const bool drop = SequenceShouldBeSilent(*vt);

decltype(framesPerBuffer) len = 0;

for (size_t c = 0; c < mNumPlaybackChannels; ++c) {
Expand Down Expand Up @@ -2725,12 +2742,11 @@ bool AudioIoCallback::FillOutputBuffers(
// the device. For example mono channels output to both left and right
// output channels.
if (len > 0) {
auto &gains = mOldChannelGains[tt];
AddToOutputChannel(0, outputMeterFloats, outputFloats,
tempBufs[0], drop, len, *vt, gains[0]);
tempBufs[0], len);

AddToOutputChannel(1, outputMeterFloats, outputFloats,
tempBufs[1], drop, len, *vt, gains[1]);
tempBufs[1], len);

// Output volume emulation
const auto factor = decayFactor(mRate);
Expand Down
7 changes: 2 additions & 5 deletions libraries/lib-audio-io/AudioIO.h
Original file line number Diff line number Diff line change
Expand Up @@ -194,14 +194,11 @@ class AUDIO_IO_API AudioIoCallback /* not final */
/*!
@param[in,out] channelGain
*/
void AddToOutputChannel( unsigned int chan, // index into gains
void AddToOutputChannel(unsigned int chan,
float * outputMeterFloats,
float * outputFloats,
const float * tempBuf,
bool drop,
unsigned long len,
const PlayableSequence &ps,
float &laggingChannelGain
unsigned long len
);
bool FillOutputBuffers(
float *outputBuffer,
Expand Down

0 comments on commit 4cfb930

Please sign in to comment.