[AFV] Change output format and processing to 32 bit float

32 bit float is what is used in C# reference and has a much higher
dynamic range. 16 bit integer was clipping very often with all the VHF
simulation applied.
This commit is contained in:
Roland Rossgotterer
2019-10-01 11:58:02 +02:00
committed by Mat Sutcliffe
parent fbb126370c
commit 240df93406
29 changed files with 77 additions and 80 deletions

View File

@@ -10,12 +10,25 @@
namespace BlackSound
{
QVector<float> convertBytesTo32BitFloatPCM(const QByteArray input)
{
int inputSamples = input.size() / 2; // 16 bit input, so 2 bytes per sample
QVector<float> output;
output.fill(0, inputSamples);
for (int n = 0; n < inputSamples; n++)
{
output[n] = *reinterpret_cast<const qint16 *>(input.data() + n * 2);
output[n] /= 32767.0;
}
return output;
}
QVector<qint16> convertBytesTo16BitPCM(const QByteArray input)
{
int inputSamples = input.size() / 2; // 16 bit input, so 2 bytes per sample
QVector<qint16> output;
output.fill(0, inputSamples);
for (int n = 0; n < inputSamples; n++)
{
output[n] = *reinterpret_cast<const qint16 *>(input.data() + n * 2);
@@ -30,11 +43,11 @@ namespace BlackSound
return {};
}
QVector<qint16> convertFromMonoToStereo(const QVector<qint16> &mono)
QVector<float> convertFromMonoToStereo(const QVector<float> &mono)
{
QVector<qint16> stereo;
QVector<float> stereo;
stereo.reserve(mono.size() * 2);
for (qint16 sample : mono)
for (float sample : mono)
{
stereo << sample;
stereo << sample;
@@ -53,9 +66,9 @@ namespace BlackSound
return mono;
}
QVector<double> convertFromShortToDouble(const QVector<qint16> &input)
QVector<float> convertFromShortToFloat(const QVector<qint16> &input)
{
QVector<double> output;
QVector<float> output;
for (auto sample : input)
{
output.push_back(sample / 32768.0);
@@ -63,14 +76,4 @@ namespace BlackSound
return output;
}
QVector<qint16> convertFromDoubleToShort(const QVector<double> &input)
{
QVector<qint16> output;
for (auto sample : input)
{
output.push_back(sample * 32768);
}
return output;
}
} // ns

View File

@@ -18,12 +18,12 @@
namespace BlackSound
{
//! Conversion functions @{
BLACKSOUND_EXPORT QVector<float> convertBytesTo32BitFloatPCM(const QByteArray input);
BLACKSOUND_EXPORT QVector<qint16> convertBytesTo16BitPCM(const QByteArray input);
BLACKSOUND_EXPORT QVector<qint16> convertFloatBytesTo16BitPCM(const QByteArray input);
BLACKSOUND_EXPORT QVector<qint16> convertFromMonoToStereo(const QVector<qint16> &mono);
BLACKSOUND_EXPORT QVector<float> convertFromMonoToStereo(const QVector<float> &mono);
BLACKSOUND_EXPORT QVector<qint16> convertFromStereoToMono(const QVector<qint16> &stereo);
BLACKSOUND_EXPORT QVector<double> convertFromShortToDouble(const QVector<qint16> &input);
BLACKSOUND_EXPORT QVector<qint16> convertFromDoubleToShort(const QVector<double> &input);
BLACKSOUND_EXPORT QVector<float> convertFromShortToFloat(const QVector<qint16> &input);
//! @}
} // ns

View File

@@ -13,7 +13,7 @@ namespace BlackSound
m_maxBufferSize = format.bytesForDuration(10 * 1000 * 1000);
}
void CBufferedWaveProvider::addSamples(const QVector<qint16> &samples)
void CBufferedWaveProvider::addSamples(const QVector<float> &samples)
{
int delta = m_audioBuffer.size() + samples.size() - m_maxBufferSize;
if (delta > 0)
@@ -23,7 +23,7 @@ namespace BlackSound
m_audioBuffer.append(samples);
}
int CBufferedWaveProvider::readSamples(QVector<qint16> &samples, qint64 count)
int CBufferedWaveProvider::readSamples(QVector<float> &samples, qint64 count)
{
qint64 len = qMin(count, static_cast<qint64>(m_audioBuffer.size()));
samples = m_audioBuffer.mid(0, len);

View File

@@ -32,10 +32,10 @@ namespace BlackSound
CBufferedWaveProvider(const QAudioFormat &format, QObject *parent = nullptr);
//! Add samples
void addSamples(const QVector<qint16> &samples);
void addSamples(const QVector<float> &samples);
//! ISampleProvider::readSamples
virtual int readSamples(QVector<qint16> &samples, qint64 count) override;
virtual int readSamples(QVector<float> &samples, qint64 count) override;
//! Bytes from buffer
int getBufferedBytes() const { return m_audioBuffer.size(); }
@@ -44,7 +44,7 @@ namespace BlackSound
void clearBuffer();
private:
QVector<qint16> m_audioBuffer;
QVector<float> m_audioBuffer;
qint32 m_maxBufferSize;
};
} // ns

View File

@@ -13,25 +13,19 @@ namespace BlackSound
setupPreset(preset);
}
int CEqualizerSampleProvider::readSamples(QVector<qint16> &samples, qint64 count)
int CEqualizerSampleProvider::readSamples(QVector<float> &samples, qint64 count)
{
int samplesRead = m_sourceProvider->readSamples(samples, count);
if (m_bypass) return samplesRead;
QVector<double> doubleSamples = convertFromShortToDouble(samples);
for (int n = 0; n < samplesRead; n++)
{
// TODO stereo implementation
for (int band = 0; band < m_filters.size(); band++)
{
doubleSamples[n] = m_filters[band].transform(doubleSamples[n]);
samples[n] = m_filters[band].transform(samples[n]);
}
doubleSamples[n] *= m_outputGain;
samples[n] *= m_outputGain;
}
samples = convertFromDoubleToShort(doubleSamples);
return samplesRead;
}

View File

@@ -38,7 +38,7 @@ namespace BlackSound
CEqualizerSampleProvider(ISampleProvider *sourceProvider, EqualizerPresets preset, QObject *parent = nullptr);
//! \copydoc ISampleProvider::readSamples
virtual int readSamples(QVector<qint16> &samples, qint64 count) override;
virtual int readSamples(QVector<float> &samples, qint64 count) override;
//! Bypassing?
void setBypassEffects(bool value) { m_bypass = value; }

View File

@@ -12,7 +12,7 @@ namespace BlackSound
{
namespace SampleProvider
{
int CMixingSampleProvider::readSamples(QVector<qint16> &samples, qint64 count)
int CMixingSampleProvider::readSamples(QVector<float> &samples, qint64 count)
{
samples.clear();
samples.fill(0, count);
@@ -22,7 +22,7 @@ namespace BlackSound
for (int i = 0; i < m_sources.size(); i++)
{
ISampleProvider *sampleProvider = m_sources.at(i);
QVector<qint16> sourceBuffer;
QVector<float> sourceBuffer;
int len = sampleProvider->readSamples(sourceBuffer, count);
for (int n = 0; n < len; n++)

View File

@@ -30,7 +30,7 @@ namespace BlackSound
void addMixerInput(ISampleProvider *provider) { m_sources.append(provider); }
//! \copydoc ISampleProvider::readSamples
virtual int readSamples(QVector<qint16> &samples, qint64 count) override;
virtual int readSamples(QVector<float> &samples, qint64 count) override;
private:
QVector<ISampleProvider *> m_sources;

View File

@@ -14,7 +14,7 @@ namespace BlackSound
{
namespace SampleProvider
{
int CPinkNoiseGenerator::readSamples(QVector<qint16> &samples, qint64 count)
int CPinkNoiseGenerator::readSamples(QVector<float> &samples, qint64 count)
{
samples.clear();
samples.fill(0, count);
@@ -32,7 +32,7 @@ namespace BlackSound
double pink = pinkNoiseBuffer[0] + pinkNoiseBuffer[1] + pinkNoiseBuffer[2] + pinkNoiseBuffer[3] + pinkNoiseBuffer[4] + pinkNoiseBuffer[5] + pinkNoiseBuffer[6] + white * 0.5362;
pinkNoiseBuffer[6] = white * 0.115926;
double sampleValue = (m_gain * (pink / 5));
samples[sampleCount] = sampleValue * 32768;
samples[sampleCount] = sampleValue;
}
return count;
}

View File

@@ -33,7 +33,7 @@ namespace BlackSound
CPinkNoiseGenerator(QObject *parent = nullptr) : ISampleProvider(parent) {}
//! Read samples
virtual int readSamples(QVector<qint16> &samples, qint64 count) override;
virtual int readSamples(QVector<float> &samples, qint64 count) override;
//! Gain
void setGain(double gain) { m_gain = gain; }

View File

@@ -29,11 +29,12 @@ namespace BlackSound
{
if (wavFile.fileFormat().sampleType() == QAudioFormat::Float)
{
m_samples = convertFloatBytesTo16BitPCM(wavFile.audioData());
// Not implemented
// m_samples = convertFloatBytesTo16BitPCM(wavFile.audioData());
}
else
{
m_samples = convertBytesTo16BitPCM(wavFile.audioData());
m_samples = convertBytesTo32BitFloatPCM(wavFile.audioData());
}
m_fn = audioFileName;
}

View File

@@ -29,7 +29,7 @@ namespace BlackSound
CResourceSound(const QString &audioFileName);
//! Audio data
const QVector<qint16> &audioData() const { return m_samples; }
const QVector<float> &audioData() const { return m_samples; }
//! Corresponding file
const QString &getFileName() { return m_fn; }
@@ -39,7 +39,7 @@ namespace BlackSound
private:
QString m_fn; //!< file name
QVector<qint16> m_samples;
QVector<float> m_samples;
};
} // ns
} // ns

View File

@@ -13,7 +13,7 @@ namespace BlackSound
m_tempBuffer.resize(m_tempBufferSize);
}
int CResourceSoundSampleProvider::readSamples(QVector<qint16> &samples, qint64 count)
int CResourceSoundSampleProvider::readSamples(QVector<float> &samples, qint64 count)
{
if (count > m_tempBufferSize)
{
@@ -35,7 +35,7 @@ namespace BlackSound
{
for (int i = 0; i < samplesToCopy; i++)
{
m_tempBuffer[i] = static_cast<qint16>(qRound(m_gain * m_tempBuffer[i]));
m_tempBuffer[i] *= m_gain;
}
}

View File

@@ -27,7 +27,7 @@ namespace BlackSound
CResourceSoundSampleProvider(const CResourceSound &resourceSound, QObject *parent = nullptr);
//! copydoc ISampleProvider::readSamples
virtual int readSamples(QVector<qint16> &samples, qint64 count) override;
virtual int readSamples(QVector<float> &samples, qint64 count) override;
//! copydoc ISampleProvider::isFinished
virtual bool isFinished() const override { return m_isFinished; }
@@ -43,8 +43,8 @@ namespace BlackSound
//! @}
//! Temp buffer @{
QVector<qint16> getTempBuffer() const { return m_tempBuffer; }
void setTempBuffer(const QVector<qint16> &value) { m_tempBuffer = value; }
QVector<float> getTempBuffer() const { return m_tempBuffer; }
void setTempBuffer(const QVector<float> &value) { m_tempBuffer = value; }
//! @}
private:
@@ -54,7 +54,7 @@ namespace BlackSound
CResourceSound m_resourceSound;
qint64 m_position = 0;
const int m_tempBufferSize = 9600; //9600 = 200ms
QVector<qint16> m_tempBuffer;
QVector<float> m_tempBuffer;
bool m_isFinished = false;
};
} // ns

View File

@@ -32,7 +32,7 @@ namespace BlackSound
virtual ~ISampleProvider() override {}
//! Read samples
virtual int readSamples(QVector<qint16> &samples, qint64 count) = 0;
virtual int readSamples(QVector<float> &samples, qint64 count) = 0;
//! Finished?
virtual bool isFinished() const { return false; }

View File

@@ -18,7 +18,7 @@ namespace BlackSound
m_frequency(frequency)
{}
int CSawToothGenerator::readSamples(QVector<qint16> &samples, qint64 count)
int CSawToothGenerator::readSamples(QVector<float> &samples, qint64 count)
{
samples.clear();
samples.fill(0, static_cast<int>(count));
@@ -28,7 +28,7 @@ namespace BlackSound
double multiple = 2 * m_frequency / m_sampleRate;
double sampleSaw = std::fmod((m_nSample * multiple), 2) - 1;
double sampleValue = m_gain * sampleSaw;
samples[sampleCount] = static_cast<qint16>(qRound(sampleValue * 32768));
samples[sampleCount] = static_cast<float>(sampleValue);
m_nSample++;
}
return static_cast<int>(count);

View File

@@ -31,7 +31,7 @@ namespace BlackSound
CSawToothGenerator(double frequency, QObject *parent = nullptr);
//! \copydoc ISampleProvider::readSamples
virtual int readSamples(QVector<qint16> &samples, qint64 count) override;
virtual int readSamples(QVector<float> &samples, qint64 count) override;
//! Set the gain
void setGain(double gain) { m_gain = gain; }

View File

@@ -27,7 +27,7 @@ namespace BlackSound
m_timer.start(3000);
}
int CSimpleCompressorEffect::readSamples(QVector<qint16> &samples, qint64 count)
int CSimpleCompressorEffect::readSamples(QVector<float> &samples, qint64 count)
{
int samplesRead = m_sourceStream->readSamples(samples, count);
@@ -35,12 +35,12 @@ namespace BlackSound
{
for (int sample = 0; sample < samplesRead; sample += channels)
{
double in1 = samples.at(sample) / 32768.0;
double in1 = samples.at(sample);
double in2 = (channels == 1) ? 0 : samples.at(sample + 1);
m_simpleCompressor.process(in1, in2);
samples[sample] = in1 * 32768.0;
samples[sample] = in1;
if (channels > 1)
samples[sample + 1] = in2 * 32768.0f;
samples[sample + 1] = in2;
}
}
return samplesRead;

View File

@@ -32,7 +32,7 @@ namespace BlackSound
CSimpleCompressorEffect(ISampleProvider *source, QObject *parent = nullptr);
//! \copydoc ISampleProvider::readSamples
virtual int readSamples(QVector<qint16> &samples, qint64 count) override;
virtual int readSamples(QVector<float> &samples, qint64 count) override;
//! Enable
void setEnabled(bool enabled);

View File

@@ -20,7 +20,7 @@ namespace BlackSound
m_sourceProvider(sourceProvider)
{ }
int CVolumeSampleProvider::readSamples(QVector<qint16> &samples, qint64 count)
int CVolumeSampleProvider::readSamples(QVector<float> &samples, qint64 count)
{
int samplesRead = m_sourceProvider->readSamples(samples, count);
@@ -28,7 +28,7 @@ namespace BlackSound
{
for (int n = 0; n < samplesRead; n++)
{
samples[n] = static_cast<qint16>(qRound(samples[n] * m_volume));
samples[n] *= static_cast<float>(m_volume);
}
}
return samplesRead;

View File

@@ -28,7 +28,7 @@ namespace BlackSound
CVolumeSampleProvider(ISampleProvider *sourceProvider, QObject *parent = nullptr);
//! \copydoc ISampleProvider::readSamples
virtual int readSamples(QVector<qint16> &samples, qint64 count) override;
virtual int readSamples(QVector<float> &samples, qint64 count) override;
//! Volume @{
double volume() const { return m_volume; }