Skip to content

Commit

Permalink
Merge pull request #26585 from RomanPudashkin/musesampler_solo_mute_a…
Browse files Browse the repository at this point in the history
…rtifacts_fix

Fix #23446: Playback artifact when solo-ing instruments (MuseSounds)
  • Loading branch information
RomanPudashkin authored Feb 21, 2025
2 parents b83d712 + 4c05404 commit 9c76b47
Show file tree
Hide file tree
Showing 8 changed files with 63 additions and 60 deletions.
4 changes: 4 additions & 0 deletions src/framework/audio/internal/worker/eventaudiosource.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,10 @@ void EventAudioSource::setIsActive(const bool active)
return;
}

if (m_synth->isActive() == active) {
return;
}

m_synth->setIsActive(active);
m_synth->flushSound();
}
Expand Down
67 changes: 34 additions & 33 deletions src/framework/audio/internal/worker/mixer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,12 @@ RetVal<MixerChannelPtr> Mixer::addChannel(const TrackId trackId, ITrackAudioInpu
return;
}

ITrackAudioInputPtr source = std::static_pointer_cast<ITrackAudioInput>(channel->source());

if (channel->muted()) {
if (source) {
source->setIsActive(false);
}
if (m_nonMutedTrackCount != 0) {
m_nonMutedTrackCount--;
}
Expand All @@ -92,8 +97,8 @@ RetVal<MixerChannelPtr> Mixer::addChannel(const TrackId trackId, ITrackAudioInpu

m_nonMutedTrackCount++;

ITrackAudioInputPtr source = std::static_pointer_cast<ITrackAudioInput>(channel->source());
if (source) {
source->setIsActive(isActive());
source->seek(currentTime());
}
});
Expand Down Expand Up @@ -206,26 +211,25 @@ samples_t Mixer::process(float* outBuffer, samples_t samplesPerChannel)

prepareAuxBuffers(outBufferSize);

samples_t masterChannelSampleCount = 0;

for (auto& pair : tracksData) {
const std::vector<float>& trackBuffer = pair.second;

bool outBufferIsSilent = false;
mixOutputFromChannel(outBuffer, trackBuffer.data(), samplesPerChannel, outBufferIsSilent);
masterChannelSampleCount = std::max(samplesPerChannel, masterChannelSampleCount);
auto channelIt = m_trackChannels.find(pair.first);
if (channelIt == m_trackChannels.cend()) {
continue;
}

if (!outBufferIsSilent) {
const MixerChannelPtr channel = channelIt->second;
if (!channel->isSilent()) {
m_isSilence = false;
} else if (m_isSilence) {
continue;
}

const AuxSendsParams& auxSends = m_trackChannels.at(pair.first)->outputParams().auxSends;
writeTrackToAuxBuffers(trackBuffer.data(), auxSends, samplesPerChannel);
const std::vector<float>& trackBuffer = pair.second;
mixOutputFromChannel(outBuffer, trackBuffer.data(), samplesPerChannel);
writeTrackToAuxBuffers(trackBuffer.data(), channel->outputParams().auxSends, samplesPerChannel);
}

if (m_masterParams.muted || masterChannelSampleCount == 0 || m_isSilence) {
if (m_masterParams.muted || samplesPerChannel == 0 || m_isSilence) {
notifyNoAudioSignal();
return 0;
}
Expand All @@ -239,7 +243,7 @@ samples_t Mixer::process(float* outBuffer, samples_t samplesPerChannel)
}
}

return masterChannelSampleCount;
return samplesPerChannel;
}

void Mixer::processTrackChannels(size_t outBufferSize, size_t samplesPerChannel, TracksData& outTracksData)
Expand Down Expand Up @@ -272,7 +276,7 @@ void Mixer::processTrackChannels(size_t outBufferSize, size_t samplesPerChannel,
continue;
}

if (pair.second->muted()) {
if (pair.second->muted() && pair.second->isSilent()) {
pair.second->notifyNoAudioSignal();
continue;
}
Expand All @@ -290,7 +294,7 @@ void Mixer::processTrackChannels(size_t outBufferSize, size_t samplesPerChannel,
continue;
}

if (pair.second->muted()) {
if (pair.second->muted() && pair.second->isSilent()) {
pair.second->notifyNoAudioSignal();
continue;
}
Expand Down Expand Up @@ -321,8 +325,16 @@ void Mixer::setIsActive(bool arg)

AbstractAudioSource::setIsActive(arg);

for (const auto& channel : m_trackChannels) {
channel.second->setIsActive(arg);
for (auto& channel : m_trackChannels) {
if (!channel.second->muted()) {
channel.second->setIsActive(arg);
}
}

for (auto& aux : m_auxChannelInfoList) {
if (!aux.channel->muted()) {
aux.channel->setIsActive(arg);
}
}
}

Expand Down Expand Up @@ -429,14 +441,12 @@ void Mixer::setTracksToProcessWhenIdle(std::unordered_set<TrackId>&& trackIds)
m_tracksToProcessWhenIdle = std::move(trackIds);
}

void Mixer::mixOutputFromChannel(float* outBuffer, const float* inBuffer, unsigned int samplesCount, bool& outBufferIsSilent)
void Mixer::mixOutputFromChannel(float* outBuffer, const float* inBuffer, unsigned int samplesCount) const
{
IF_ASSERT_FAILED(outBuffer && inBuffer) {
return;
}

outBufferIsSilent = true;

if (m_masterParams.muted) {
return;
}
Expand All @@ -448,10 +458,6 @@ void Mixer::mixOutputFromChannel(float* outBuffer, const float* inBuffer, unsign
size_t idx = samplePos + audioChNum;
float sample = inBuffer[idx];
outBuffer[idx] += sample;

if (outBufferIsSilent && !RealIsNull(sample)) {
outBufferIsSilent = false;
}
}
}
}
Expand Down Expand Up @@ -516,8 +522,9 @@ void Mixer::processAuxChannels(float* buffer, samples_t samplesPerChannel)
float* auxBuffer = aux.buffer.data();
aux.channel->process(auxBuffer, samplesPerChannel);

static bool isSilent = false;
mixOutputFromChannel(buffer, auxBuffer, samplesPerChannel, isSilent);
if (!aux.channel->isSilent()) {
mixOutputFromChannel(buffer, auxBuffer, samplesPerChannel);
}
}
}

Expand All @@ -527,14 +534,11 @@ void Mixer::completeOutput(float* buffer, samples_t samplesPerChannel)
return;
}

m_isSilence = true;

float totalSquaredSum = 0.f;
float volume = muse::db_to_linear(m_masterParams.volume);

for (audioch_t audioChNum = 0; audioChNum < m_audioChannelsCount; ++audioChNum) {
float singleChannelSquaredSum = 0.f;

gain_t totalGain = dsp::balanceGain(m_masterParams.balance, audioChNum) * volume;

for (samples_t s = 0; s < samplesPerChannel; ++s) {
Expand All @@ -543,10 +547,6 @@ void Mixer::completeOutput(float* buffer, samples_t samplesPerChannel)
float resultSample = buffer[idx] * totalGain;
buffer[idx] = resultSample;

if (m_isSilence && !RealIsNull(resultSample)) {
m_isSilence = false;
}

float squaredSample = resultSample * resultSample;
totalSquaredSum += squaredSample;
singleChannelSquaredSum += squaredSample;
Expand All @@ -556,6 +556,7 @@ void Mixer::completeOutput(float* buffer, samples_t samplesPerChannel)
m_audioSignalNotifier.updateSignalValues(audioChNum, rms);
}

m_isSilence = RealIsNull(totalSquaredSum);
m_audioSignalNotifier.notifyAboutChanges();

if (!m_limiter->isActive()) {
Expand Down
2 changes: 1 addition & 1 deletion src/framework/audio/internal/worker/mixer.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ class Mixer : public AbstractAudioSource, public Injectable, public async::Async
using TracksData = std::map<TrackId, std::vector<float> >;

void processTrackChannels(size_t outBufferSize, size_t samplesPerChannel, TracksData& outTracksData);
void mixOutputFromChannel(float* outBuffer, const float* inBuffer, unsigned int samplesCount, bool& outBufferIsSilent);
void mixOutputFromChannel(float* outBuffer, const float* inBuffer, unsigned int samplesCount) const;
void prepareAuxBuffers(size_t outBufferSize);
void writeTrackToAuxBuffers(const float* trackBuffer, const AuxSendsParams& auxSends, samples_t samplesPerChannel);
void processAuxChannels(float* buffer, samples_t samplesPerChannel);
Expand Down
16 changes: 12 additions & 4 deletions src/framework/audio/internal/worker/mixerchannel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -192,11 +192,13 @@ samples_t MixerChannel::process(float* buffer, samples_t samplesPerChannel)

samples_t processedSamplesCount = samplesPerChannel;

if (m_audioSource && !m_params.muted) {
processedSamplesCount = m_audioSource->process(buffer, samplesPerChannel);
if (m_audioSource) {
if (!m_params.muted || !m_isSilent) {
processedSamplesCount = m_audioSource->process(buffer, samplesPerChannel);
}
}

if (processedSamplesCount == 0 || m_params.muted) {
if (processedSamplesCount == 0 || (m_params.muted && m_isSilent)) {
std::fill(buffer, buffer + samplesPerChannel * audioChannelsCount(), 0.f);
notifyNoAudioSignal();

Expand All @@ -215,7 +217,7 @@ samples_t MixerChannel::process(float* buffer, samples_t samplesPerChannel)
return processedSamplesCount;
}

void MixerChannel::completeOutput(float* buffer, unsigned int samplesCount) const
void MixerChannel::completeOutput(float* buffer, unsigned int samplesCount)
{
unsigned int channelsCount = audioChannelsCount();
float volume = muse::db_to_linear(m_params.volume);
Expand All @@ -241,6 +243,7 @@ void MixerChannel::completeOutput(float* buffer, unsigned int samplesCount) cons
m_audioSignalNotifier.updateSignalValues(audioChNum, rms);
}

m_isSilent = RealIsNull(totalSquaredSum);
m_audioSignalNotifier.notifyAboutChanges();

if (!m_compressor->isActive()) {
Expand All @@ -251,6 +254,11 @@ void MixerChannel::completeOutput(float* buffer, unsigned int samplesCount) cons
m_compressor->process(totalRms, buffer, channelsCount, samplesCount);
}

bool MixerChannel::isSilent() const
{
return m_isSilent;
}

void MixerChannel::notifyNoAudioSignal()
{
unsigned int channelsCount = audioChannelsCount();
Expand Down
6 changes: 5 additions & 1 deletion src/framework/audio/internal/worker/mixerchannel.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ class MixerChannel : public ITrackAudioOutput, public Injectable, public async::
bool muted() const;
async::Notification mutedChanged() const;

bool isSilent() const;

void notifyNoAudioSignal();

const AudioOutputParams& outputParams() const override;
Expand All @@ -65,7 +67,7 @@ class MixerChannel : public ITrackAudioOutput, public Injectable, public async::
samples_t process(float* buffer, samples_t samplesPerChannel) override;

private:
void completeOutput(float* buffer, unsigned int samplesCount) const;
void completeOutput(float* buffer, unsigned int samplesCount);

TrackId m_trackId = -1;

Expand All @@ -78,6 +80,8 @@ class MixerChannel : public ITrackAudioOutput, public Injectable, public async::

dsp::CompressorPtr m_compressor = nullptr;

bool m_isSilent = true;

async::Notification m_mutedChanged;
mutable async::Channel<AudioOutputParams> m_paramsChanges;
mutable AudioSignalsNotifier m_audioSignalNotifier;
Expand Down
23 changes: 5 additions & 18 deletions src/framework/audio/internal/worker/sequenceplayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ SequencePlayer::SequencePlayer(IGetTracks* getTracks, IClockPtr clock, const mod
});

m_clock->statusChanged().onReceive(this, [this](const PlaybackStatus status) {
setAllTracksActive(status == PlaybackStatus::Running);
audioEngine()->mixer()->setIsActive(status == PlaybackStatus::Running);
});
}

Expand All @@ -48,7 +48,7 @@ void SequencePlayer::play()

audioEngine()->setMode(RenderMode::RealTimeMode);
m_clock->start();
setAllTracksActive(true);
audioEngine()->mixer()->setIsActive(true);
}

void SequencePlayer::seek(const secs_t newPosition)
Expand All @@ -66,7 +66,7 @@ void SequencePlayer::stop()

audioEngine()->setMode(RenderMode::IdleMode);
m_clock->stop();
setAllTracksActive(false);
audioEngine()->mixer()->setIsActive(false);
}

void SequencePlayer::pause()
Expand All @@ -75,7 +75,7 @@ void SequencePlayer::pause()

audioEngine()->setMode(RenderMode::IdleMode);
m_clock->pause();
setAllTracksActive(false);
audioEngine()->mixer()->setIsActive(false);
}

void SequencePlayer::resume()
Expand All @@ -84,7 +84,7 @@ void SequencePlayer::resume()

audioEngine()->setMode(RenderMode::RealTimeMode);
m_clock->resume();
setAllTracksActive(true);
audioEngine()->mixer()->setIsActive(true);
}

msecs_t SequencePlayer::duration() const
Expand Down Expand Up @@ -147,19 +147,6 @@ Channel<PlaybackStatus> SequencePlayer::playbackStatusChanged() const
return m_clock->statusChanged();
}

void SequencePlayer::setAllTracksActive(bool active)
{
IF_ASSERT_FAILED(m_getTracks) {
return;
}

for (const auto& pair : m_getTracks->allTracks()) {
if (pair.second->inputHandler) {
pair.second->inputHandler->setIsActive(active);
}
}
}

void SequencePlayer::seekAllTracks(const msecs_t newPositionMsecs)
{
IF_ASSERT_FAILED(m_getTracks) {
Expand Down
1 change: 0 additions & 1 deletion src/framework/audio/internal/worker/sequenceplayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@ class SequencePlayer : public ISequencePlayer, public Injectable, public async::
async::Channel<secs_t> playbackPositionChanged() const override;

private:
void setAllTracksActive(bool active);
void seekAllTracks(const msecs_t newPositionMsecs);

IGetTracks* m_getTracks = nullptr;
Expand Down
4 changes: 2 additions & 2 deletions src/framework/vst/internal/vstaudioclient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -422,7 +422,7 @@ bool VstAudioClient::fillOutputBufferInstrument(samples_t sampleCount, float* ou
float sample = bus.channelBuffers32[audioChannelIndex][sampleIndex];
output[offset + audioChannelIndex] += sample * m_volumeGain;

if (isSilence && !RealIsNull(sample)) {
if (isSilence && sample != 0.f) {
isSilence = false;
}
}
Expand Down Expand Up @@ -450,7 +450,7 @@ bool VstAudioClient::fillOutputBufferFx(samples_t sampleCount, float* output)
float sample = bus.channelBuffers32[audioChannelIndex][sampleIndex];
output[offset + audioChannelIndex] = sample * m_volumeGain;

if (isSilence && !RealIsNull(sample)) {
if (isSilence && sample != 0.f) {
isSilence = false;
}
}
Expand Down

0 comments on commit 9c76b47

Please sign in to comment.