Apply master gain outside audio devices (#7135)

This commit is contained in:
saker
2024-03-10 23:06:46 -04:00
committed by GitHub
parent c991a85eef
commit 3ae13ae45e
25 changed files with 49 additions and 104 deletions

View File

@@ -96,11 +96,7 @@ public:
protected:
// subclasses can re-implement this for being used in conjunction with
// processNextBuffer()
virtual void writeBuffer( const surroundSampleFrame * /* _buf*/,
const fpp_t /*_frames*/,
const float /*_master_gain*/ )
{
}
virtual void writeBuffer(const surroundSampleFrame* /* _buf*/, const fpp_t /*_frames*/) {}
// called by according driver for fetching new sound-data
fpp_t getNextBuffer( surroundSampleFrame * _ab );
@@ -109,7 +105,6 @@ protected:
// returns num of bytes in outbuf
int convertToS16( const surroundSampleFrame * _ab,
const fpp_t _frames,
const float _master_gain,
int_sample_t * _output_buffer,
const bool _convert_endian = false );

View File

@@ -65,9 +65,7 @@ private:
SF_INFO m_sfinfo;
SNDFILE* m_sf;
void writeBuffer(surroundSampleFrame const* _ab,
fpp_t const frames,
float master_gain) override;
void writeBuffer(surroundSampleFrame const* _ab, fpp_t const frames) override;
bool startEncoding();
void finishEncoding();

View File

@@ -58,9 +58,7 @@ public:
}
protected:
void writeBuffer( const surroundSampleFrame * /* _buf*/,
const fpp_t /*_frames*/,
const float /*_master_gain*/ ) override;
void writeBuffer(const surroundSampleFrame* /* _buf*/, const fpp_t /*_frames*/) override;
private:
void flushRemainingBuffers();

View File

@@ -58,9 +58,7 @@ public:
private:
void writeBuffer( const surroundSampleFrame * _ab,
const fpp_t _frames,
const float _master_gain ) override;
void writeBuffer(const surroundSampleFrame* _ab, const fpp_t _frames) override;
bool startEncoding();
void finishEncoding();

View File

@@ -56,9 +56,7 @@ public:
private:
void writeBuffer( const surroundSampleFrame * _ab,
const fpp_t _frames,
float _master_gain ) override;
void writeBuffer(const surroundSampleFrame* _ab, const fpp_t _frames) override;
bool startEncoding();
void finishEncoding();

View File

@@ -48,9 +48,7 @@ public:
std::shared_ptr<const SampleBuffer> createSampleBuffer();
private:
void writeBuffer( const surroundSampleFrame * _ab,
const fpp_t _frames,
const float _master_gain ) override;
void writeBuffer(const surroundSampleFrame* _ab, const fpp_t _frames) override;
using BufferList = QList<QPair<sampleFrame*, fpp_t>>;
BufferList m_buffers;

View File

@@ -45,6 +45,8 @@ bool sanitize( sampleFrame * src, int frames );
/*! \brief Add samples from src to dst */
void add( sampleFrame* dst, const sampleFrame* src, int frames );
/*! \brief Multiply samples from `dst` by `coeff` */
void multiply(sampleFrame* dst, float coeff, int frames);
/*! \brief Add samples from src multiplied by coeffSrc to dst */
void addMultiplied( sampleFrame* dst, const sampleFrame* src, float coeffSrc, int frames );

View File

@@ -24,6 +24,7 @@
#include "AudioEngine.h"
#include "MixHelpers.h"
#include "denormals.h"
#include "lmmsconfig.h"
@@ -433,6 +434,8 @@ void AudioEngine::renderStageMix()
Mixer *mixer = Engine::mixer();
mixer->masterMix(m_outputBufferWrite);
MixHelpers::multiply(m_outputBufferWrite, m_masterGain, m_framesPerPeriod);
emit nextAudioBuffer(m_outputBufferRead);
// and trigger LFOs

View File

@@ -178,6 +178,15 @@ struct AddSwappedMultipliedOp
const float m_coeff;
};
void multiply(sampleFrame* dst, float coeff, int frames)
{
for (int i = 0; i < frames; ++i)
{
dst[i][0] *= coeff;
dst[i][1] *= coeff;
}
}
void addSwappedMultiplied( sampleFrame* dst, const sampleFrame* src, float coeffSrc, int frames )
{
run<>( dst, src, frames, AddSwappedMultipliedOp(coeffSrc) );

View File

@@ -323,10 +323,7 @@ void AudioAlsa::run()
}
outbuf_size = frames * channels();
convertToS16( temp, frames,
audioEngine()->masterGain(),
outbuf,
m_convertEndian );
convertToS16(temp, frames, outbuf, m_convertEndian);
}
int min_len = std::min(len, outbuf_size - outbuf_pos);
memcpy( ptr, outbuf + outbuf_pos,

View File

@@ -66,10 +66,7 @@ AudioDevice::~AudioDevice()
void AudioDevice::processNextBuffer()
{
const fpp_t frames = getNextBuffer( m_buffer );
if( frames )
{
writeBuffer( m_buffer, frames, audioEngine()->masterGain() );
}
if (frames) { writeBuffer(m_buffer, frames); }
else
{
m_inProcess = false;
@@ -211,7 +208,6 @@ fpp_t AudioDevice::resample( const surroundSampleFrame * _src,
int AudioDevice::convertToS16( const surroundSampleFrame * _ab,
const fpp_t _frames,
const float _master_gain,
int_sample_t * _output_buffer,
const bool _convert_endian )
{
@@ -222,8 +218,8 @@ int AudioDevice::convertToS16( const surroundSampleFrame * _ab,
{
for( ch_cnt_t chnl = 0; chnl < channels(); ++chnl )
{
temp = static_cast<int_sample_t>( AudioEngine::clip( _ab[frame][chnl] * _master_gain ) * OUTPUT_SAMPLE_MULTIPLIER );
temp = static_cast<int_sample_t>(AudioEngine::clip(_ab[frame][chnl]) * OUTPUT_SAMPLE_MULTIPLIER);
( _output_buffer + frame * channels() )[chnl] =
( temp & 0x00ff ) << 8 |
( temp & 0xff00 ) >> 8;
@@ -236,11 +232,8 @@ int AudioDevice::convertToS16( const surroundSampleFrame * _ab,
{
for( ch_cnt_t chnl = 0; chnl < channels(); ++chnl )
{
( _output_buffer + frame * channels() )[chnl] =
static_cast<int_sample_t>(
AudioEngine::clip( _ab[frame][chnl] *
_master_gain ) *
OUTPUT_SAMPLE_MULTIPLIER );
(_output_buffer + frame * channels())[chnl]
= static_cast<int_sample_t>(AudioEngine::clip(_ab[frame][chnl]) * OUTPUT_SAMPLE_MULTIPLIER);
}
}
}

View File

@@ -89,7 +89,7 @@ bool AudioFileFlac::startEncoding()
return true;
}
void AudioFileFlac::writeBuffer(surroundSampleFrame const* _ab, fpp_t const frames, float master_gain)
void AudioFileFlac::writeBuffer(surroundSampleFrame const* _ab, fpp_t const frames)
{
OutputSettings::BitDepth depth = getOutputSettings().getBitDepth();
float clipvalue = std::nextafterf( -1.0f, 0.0f );
@@ -104,7 +104,7 @@ void AudioFileFlac::writeBuffer(surroundSampleFrame const* _ab, fpp_t const fram
// Clip the negative side to just above -1.0 in order to prevent it from changing sign
// Upstream issue: https://github.com/erikd/libsndfile/issues/309
// When this commit is reverted libsndfile-1.0.29 must be made a requirement for FLAC
buf[frame*channels() + channel] = std::max(clipvalue, _ab[frame][channel] * master_gain);
buf[frame*channels() + channel] = std::max(clipvalue, _ab[frame][channel]);
}
}
sf_writef_float(m_sf, static_cast<float*>(buf.data()), frames);
@@ -112,7 +112,7 @@ void AudioFileFlac::writeBuffer(surroundSampleFrame const* _ab, fpp_t const fram
else // integer PCM encoding
{
auto buf = std::vector<int_sample_t>(frames * channels());
convertToS16(_ab, frames, master_gain, buf.data(), !isLittleEndian());
convertToS16(_ab, frames, buf.data(), !isLittleEndian());
sf_writef_short(m_sf, static_cast<short*>(buf.data()), frames);
}

View File

@@ -53,21 +53,18 @@ AudioFileMP3::~AudioFileMP3()
tearDownEncoder();
}
void AudioFileMP3::writeBuffer( const surroundSampleFrame * _buf,
const fpp_t _frames,
const float _master_gain )
void AudioFileMP3::writeBuffer(const surroundSampleFrame* _buf, const fpp_t _frames)
{
if (_frames < 1)
{
return;
}
// TODO Why isn't the gain applied by the driver but inside the device?
std::vector<float> interleavedDataBuffer(_frames * 2);
for (fpp_t i = 0; i < _frames; ++i)
{
interleavedDataBuffer[2*i] = _buf[i][0] * _master_gain;
interleavedDataBuffer[2*i + 1] = _buf[i][1] * _master_gain;
interleavedDataBuffer[2*i] = _buf[i][0];
interleavedDataBuffer[2*i + 1] = _buf[i][1];
}
size_t minimumBufferSize = 1.25 * _frames + 7200;

View File

@@ -185,12 +185,7 @@ bool AudioFileOgg::startEncoding()
return true;
}
void AudioFileOgg::writeBuffer( const surroundSampleFrame * _ab,
const fpp_t _frames,
const float _master_gain )
void AudioFileOgg::writeBuffer(const surroundSampleFrame* _ab, const fpp_t _frames)
{
int eos = 0;
@@ -201,7 +196,7 @@ void AudioFileOgg::writeBuffer( const surroundSampleFrame * _ab,
{
for( ch_cnt_t chnl = 0; chnl < channels(); ++chnl )
{
buffer[chnl][frame] = _ab[frame][chnl] * _master_gain;
buffer[chnl][frame] = _ab[frame][chnl];
}
}
@@ -258,7 +253,7 @@ void AudioFileOgg::finishEncoding()
if( m_ok )
{
// just for flushing buffers...
writeBuffer( nullptr, 0, 0.0f );
writeBuffer(nullptr, 0);
// clean up
ogg_stream_clear( &m_os );

View File

@@ -93,12 +93,7 @@ bool AudioFileWave::startEncoding()
return true;
}
void AudioFileWave::writeBuffer( const surroundSampleFrame * _ab,
const fpp_t _frames,
const float _master_gain )
void AudioFileWave::writeBuffer(const surroundSampleFrame* _ab, const fpp_t _frames)
{
OutputSettings::BitDepth bitDepth = getOutputSettings().getBitDepth();
@@ -109,8 +104,7 @@ void AudioFileWave::writeBuffer( const surroundSampleFrame * _ab,
{
for( ch_cnt_t chnl = 0; chnl < channels(); ++chnl )
{
buf[frame*channels()+chnl] = _ab[frame][chnl] *
_master_gain;
buf[frame * channels() + chnl] = _ab[frame][chnl];
}
}
sf_writef_float( m_sf, buf, _frames );
@@ -119,8 +113,7 @@ void AudioFileWave::writeBuffer( const surroundSampleFrame * _ab,
else
{
auto buf = new int_sample_t[_frames * channels()];
convertToS16( _ab, _frames, _master_gain, buf,
!isLittleEndian() );
convertToS16(_ab, _frames, buf, !isLittleEndian());
sf_writef_short( m_sf, buf, _frames );
delete[] buf;

View File

@@ -344,13 +344,12 @@ int AudioJack::processCallback(jack_nframes_t nframes)
while (done < nframes && !m_stopped)
{
jack_nframes_t todo = std::min<jack_nframes_t>(nframes - done, m_framesToDoInCurBuf - m_framesDoneInCurBuf);
const float gain = audioEngine()->masterGain();
for (int c = 0; c < channels(); ++c)
{
jack_default_audio_sample_t* o = m_tempOutBufs[c];
for (jack_nframes_t frame = 0; frame < todo; ++frame)
{
o[done + frame] = m_outBuf[m_framesDoneInCurBuf + frame][c] * gain;
o[done + frame] = m_outBuf[m_framesDoneInCurBuf + frame][c];
}
}
done += todo;

View File

@@ -303,7 +303,7 @@ void AudioOss::run()
break;
}
int bytes = convertToS16( temp, frames, audioEngine()->masterGain(), outbuf, m_convertEndian );
int bytes = convertToS16(temp, frames, outbuf, m_convertEndian);
if( write( m_audioFD, outbuf, bytes ) != bytes )
{
break;

View File

@@ -298,15 +298,11 @@ int AudioPortAudio::process_callback(
const int min_len = std::min(static_cast<int>(_framesPerBuffer),
m_outBufSize - m_outBufPos);
float master_gain = audioEngine()->masterGain();
for( fpp_t frame = 0; frame < min_len; ++frame )
{
for( ch_cnt_t chnl = 0; chnl < channels(); ++chnl )
{
( _outputBuffer + frame * channels() )[chnl] =
AudioEngine::clip( m_outBuf[frame][chnl] *
master_gain );
(_outputBuffer + frame * channels())[chnl] = AudioEngine::clip(m_outBuf[frame][chnl]);
}
}

View File

@@ -278,10 +278,7 @@ void AudioPulseAudio::streamWriteCallback( pa_stream *s, size_t length )
m_quit = true;
break;
}
int bytes = convertToS16( temp, frames,
audioEngine()->masterGain(),
pcmbuf,
m_convertEndian );
int bytes = convertToS16(temp, frames, pcmbuf, m_convertEndian);
if( bytes > 0 )
{
pa_stream_write( m_s, pcmbuf, bytes, nullptr, 0,

View File

@@ -85,11 +85,7 @@ std::shared_ptr<const SampleBuffer> AudioSampleRecorder::createSampleBuffer()
return std::make_shared<const SampleBuffer>(std::move(bigBuffer), sampleRate());
}
void AudioSampleRecorder::writeBuffer( const surroundSampleFrame * _ab,
const fpp_t _frames, const float )
void AudioSampleRecorder::writeBuffer(const surroundSampleFrame* _ab, const fpp_t _frames)
{
auto buf = new sampleFrame[_frames];
for( fpp_t frame = 0; frame < _frames; ++frame )

View File

@@ -261,13 +261,6 @@ void AudioSdl::sdlAudioCallback( Uint8 * _buf, int _len )
m_currentBufferFramesCount
- m_currentBufferFramePos);
const float gain = audioEngine()->masterGain();
for (uint f = 0; f < min_frames_count; f++)
{
(m_outBuf + m_currentBufferFramePos)[f][0] *= gain;
(m_outBuf + m_currentBufferFramePos)[f][1] *= gain;
}
memcpy( _buf, m_outBuf + m_currentBufferFramePos, min_frames_count*sizeof(sampleFrame) );
_buf += min_frames_count*sizeof(sampleFrame);
_len -= min_frames_count*sizeof(sampleFrame);
@@ -291,10 +284,7 @@ void AudioSdl::sdlAudioCallback( Uint8 * _buf, int _len )
m_convertedBufSize = frames * channels()
* sizeof( int_sample_t );
convertToS16( m_outBuf, frames,
audioEngine()->masterGain(),
(int_sample_t *)m_convertedBuf,
m_outConvertEndian );
convertToS16(m_outBuf, frames, reinterpret_cast<int_sample_t*>(m_convertedBuf), m_outConvertEndian);
}
const int min_len = std::min(_len, m_convertedBufSize
- m_convertedBufPos);

View File

@@ -167,8 +167,7 @@ void AudioSndio::run()
break;
}
uint bytes = convertToS16( temp, frames,
audioEngine()->masterGain(), outbuf, m_convertEndian );
uint bytes = convertToS16(temp, frames, outbuf, m_convertEndian);
if( sio_write( m_hdl, outbuf, bytes ) != bytes )
{
break;

View File

@@ -286,8 +286,6 @@ void AudioSoundIo::writeCallback(int frameCountMin, int frameCountMax)
int bytesPerSample = m_outstream->bytes_per_sample;
int err;
const float gain = audioEngine()->masterGain();
int framesLeft = frameCountMax;
while (framesLeft > 0)
@@ -328,7 +326,7 @@ void AudioSoundIo::writeCallback(int frameCountMin, int frameCountMax)
for (int channel = 0; channel < layout->channel_count; channel += 1)
{
float sample = gain * m_outBuf[m_outBufFrameIndex][channel];
float sample = m_outBuf[m_outBufFrameIndex][channel];
memcpy(areas[channel].ptr, &sample, bytesPerSample);
areas[channel].ptr += areas[channel].step;
}

View File

@@ -603,10 +603,6 @@ void MixerView::updateFaders()
{
Mixer * m = getMixer();
// apply master gain
m->mixerChannel(0)->m_peakLeft *= Engine::audioEngine()->masterGain();
m->mixerChannel(0)->m_peakRight *= Engine::audioEngine()->masterGain();
for (int i = 0; i < m_mixerChannelViews.size(); ++i)
{
const float opl = m_mixerChannelViews[i]->m_fader->getPeak_L();

View File

@@ -143,14 +143,14 @@ void Oscilloscope::paintEvent( QPaintEvent * )
{
AudioEngine const * audioEngine = Engine::audioEngine();
float master_output = audioEngine->masterGain();
float masterOutput = audioEngine->masterGain();
const fpp_t frames = audioEngine->framesPerPeriod();
AudioEngine::StereoSample peakValues = audioEngine->getPeakValues(m_buffer, frames);
const float max_level = qMax<float>( peakValues.left, peakValues.right );
// Set the color of the line according to the maximum level
float const maxLevelWithAppliedMasterGain = max_level * master_output;
float const maxLevelWithAppliedMasterGain = max_level * masterOutput;
p.setPen(QPen(determineLineColor(maxLevelWithAppliedMasterGain), 0.7));
p.setRenderHint( QPainter::Antialiasing );
@@ -158,7 +158,7 @@ void Oscilloscope::paintEvent( QPaintEvent * )
// now draw all that stuff
int w = width() - 4;
const qreal xd = static_cast<qreal>(w) / frames;
const qreal half_h = -( height() - 6 ) / 3.0 * static_cast<qreal>(master_output) - 1;
const qreal half_h = -(height() - 6) / 3.0 * static_cast<qreal>(masterOutput) - 1;
int x_base = 2;
const qreal y_base = height() / 2 - 0.5;