[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

@@ -11,6 +11,7 @@
#include "callsignsampleprovider.h" #include "callsignsampleprovider.h"
#include "callsigndelaycache.h" #include "callsigndelaycache.h"
#include "blacksound/sampleprovider/samples.h" #include "blacksound/sampleprovider/samples.h"
#include "blacksound/audioutilities.h"
#include "blackcore/afv/audio/receiversampleprovider.h" #include "blackcore/afv/audio/receiversampleprovider.h"
#include <QtMath> #include <QtMath>
#include <QDebug> #include <QDebug>
@@ -60,7 +61,7 @@ namespace BlackCore
connect(&m_timer, &QTimer::timeout, this, &CallsignSampleProvider::timerElapsed); connect(&m_timer, &QTimer::timeout, this, &CallsignSampleProvider::timerElapsed);
} }
int CallsignSampleProvider::readSamples(QVector<qint16> &samples, qint64 count) int CallsignSampleProvider::readSamples(QVector<float> &samples, qint64 count)
{ {
int noOfSamples = m_mixer->readSamples(samples, count); int noOfSamples = m_mixer->readSamples(samples, count);
@@ -103,7 +104,7 @@ namespace BlackCore
if (delayMs > 0) if (delayMs > 0)
{ {
int phaseDelayLength = (m_audioFormat.sampleRate() / 1000) * delayMs; int phaseDelayLength = (m_audioFormat.sampleRate() / 1000) * delayMs;
QVector<qint16> phaseDelay(phaseDelayLength * 2, 0); QVector<float> phaseDelay(phaseDelayLength * 2, 0);
m_audioInput->addSamples(phaseDelay); m_audioInput->addSamples(phaseDelay);
} }
} }
@@ -131,7 +132,7 @@ namespace BlackCore
setEffects(); setEffects();
QVector<qint16> audio = decodeOpus(audioDto.audio); QVector<qint16> audio = decodeOpus(audioDto.audio);
m_audioInput->addSamples(audio); m_audioInput->addSamples(BlackSound::convertFromShortToFloat(audio));
m_lastPacketLatch = audioDto.lastPacket; m_lastPacketLatch = audioDto.lastPacket;
if (audioDto.lastPacket && !m_underflow) { CallsignDelayCache::instance().success(m_callsign); } if (audioDto.lastPacket && !m_underflow) { CallsignDelayCache::instance().success(m_callsign); }
m_lastSamplesAddedUtc = QDateTime::currentDateTimeUtc(); m_lastSamplesAddedUtc = QDateTime::currentDateTimeUtc();

View File

@@ -44,7 +44,7 @@ namespace BlackCore
//! Ctor //! Ctor
CallsignSampleProvider(const QAudioFormat &audioFormat, const BlackCore::Afv::Audio::CReceiverSampleProvider *receiver, QObject *parent = nullptr); CallsignSampleProvider(const QAudioFormat &audioFormat, const BlackCore::Afv::Audio::CReceiverSampleProvider *receiver, QObject *parent = nullptr);
int readSamples(QVector<qint16> &samples, qint64 count) override; int readSamples(QVector<float> &samples, qint64 count) override;
//! The callsign //! The callsign
const QString &callsign() const { return m_callsign; } const QString &callsign() const { return m_callsign; }

View File

@@ -36,22 +36,20 @@ namespace BlackCore
int sampleBytes = m_outputFormat.sampleSize() / 8; int sampleBytes = m_outputFormat.sampleSize() / 8;
int channelCount = m_outputFormat.channelCount(); int channelCount = m_outputFormat.channelCount();
qint64 count = maxlen / (sampleBytes * channelCount); qint64 count = maxlen / (sampleBytes * channelCount);
QVector<qint16> buffer; QVector<float> buffer;
m_sampleProvider->readSamples(buffer, count); m_sampleProvider->readSamples(buffer, count);
for (const qint16 sample : buffer) for (float sample : buffer)
{ {
qint16 sampleInput = sample; float absSample = qAbs(sample);
sampleInput = qAbs(sampleInput); if (absSample > m_maxSampleOutput) { m_maxSampleOutput = absSample; }
if (sampleInput > m_maxSampleOutput) { m_maxSampleOutput = sampleInput; }
} }
m_sampleCount += buffer.size(); m_sampleCount += buffer.size();
if (m_sampleCount >= SampleCountPerEvent) if (m_sampleCount >= SampleCountPerEvent)
{ {
OutputVolumeStreamArgs outputVolumeStreamArgs; OutputVolumeStreamArgs outputVolumeStreamArgs;
qint16 maxInt = std::numeric_limits<qint16>::max(); outputVolumeStreamArgs.PeakRaw = m_maxSampleOutput / 1.0;
outputVolumeStreamArgs.PeakRaw = m_maxSampleOutput / maxInt;
outputVolumeStreamArgs.PeakDB = static_cast<float>(20 * std::log10(outputVolumeStreamArgs.PeakRaw)); outputVolumeStreamArgs.PeakDB = static_cast<float>(20 * std::log10(outputVolumeStreamArgs.PeakRaw));
const double db = qBound(m_minDb, outputVolumeStreamArgs.PeakDB, m_maxDb); const double db = qBound(m_minDb, outputVolumeStreamArgs.PeakDB, m_maxDb);
double ratio = (db - m_minDb) / (m_maxDb - m_minDb); double ratio = (db - m_minDb) / (m_maxDb - m_minDb);
@@ -91,8 +89,8 @@ namespace BlackCore
QAudioFormat outputFormat; QAudioFormat outputFormat;
outputFormat.setSampleRate(48000); outputFormat.setSampleRate(48000);
outputFormat.setChannelCount(1); outputFormat.setChannelCount(1);
outputFormat.setSampleSize(16); outputFormat.setSampleSize(32);
outputFormat.setSampleType(QAudioFormat::SignedInt); outputFormat.setSampleType(QAudioFormat::Float);
outputFormat.setByteOrder(QAudioFormat::LittleEndian); outputFormat.setByteOrder(QAudioFormat::LittleEndian);
outputFormat.setCodec("audio/pcm"); outputFormat.setCodec("audio/pcm");

View File

@@ -60,7 +60,7 @@ namespace BlackCore
static constexpr int SampleCountPerEvent = 4800; static constexpr int SampleCountPerEvent = 4800;
QAudioFormat m_outputFormat; QAudioFormat m_outputFormat;
double m_maxSampleOutput = 0; float m_maxSampleOutput = 0.0;
int m_sampleCount = 0; int m_sampleCount = 0;
const double m_maxDb = 0; const double m_maxDb = 0;
const double m_minDb = -40; const double m_minDb = -40;

View File

@@ -82,7 +82,7 @@ namespace BlackCore
} }
} }
int CReceiverSampleProvider::readSamples(QVector<qint16> &samples, qint64 count) int CReceiverSampleProvider::readSamples(QVector<float> &samples, qint64 count)
{ {
int numberOfInUseInputs = activeCallsigns(); int numberOfInUseInputs = activeCallsigns();

View File

@@ -57,7 +57,7 @@ namespace BlackCore
//! @} //! @}
//! \copydoc BlackSound::SampleProvider::ISampleProvider::readSamples //! \copydoc BlackSound::SampleProvider::ISampleProvider::readSamples
virtual int readSamples(QVector<qint16> &samples, qint64 count) override; virtual int readSamples(QVector<float> &samples, qint64 count) override;
void addOpusSamples(const IAudioDto &audioDto, uint frequency, float distanceRatio); void addOpusSamples(const IAudioDto &audioDto, uint frequency, float distanceRatio);
void addSilentSamples(const IAudioDto &audioDto, uint frequency, float distanceRatio); void addSilentSamples(const IAudioDto &audioDto, uint frequency, float distanceRatio);

View File

@@ -85,7 +85,7 @@ namespace BlackCore
} }
} }
int CSoundcardSampleProvider::readSamples(QVector<qint16> &samples, qint64 count) int CSoundcardSampleProvider::readSamples(QVector<float> &samples, qint64 count)
{ {
return m_mixer->readSamples(samples, count); return m_mixer->readSamples(samples, count);
} }

View File

@@ -43,7 +43,7 @@ namespace BlackCore
void pttUpdate(bool active, const QVector<TxTransceiverDto> &txTransceivers); void pttUpdate(bool active, const QVector<TxTransceiverDto> &txTransceivers);
//! \copydoc ISampleProvider::readSamples //! \copydoc ISampleProvider::readSamples
virtual int readSamples(QVector<qint16> &samples, qint64 count) override; virtual int readSamples(QVector<float> &samples, qint64 count) override;
//! Add OPUS samples //! Add OPUS samples
void addOpusSamples(const IAudioDto &audioDto, const QVector<RxTransceiverDto> &rxTransceivers); void addOpusSamples(const IAudioDto &audioDto, const QVector<RxTransceiverDto> &rxTransceivers);

View File

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

View File

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

View File

@@ -13,7 +13,7 @@ namespace BlackSound
m_maxBufferSize = format.bytesForDuration(10 * 1000 * 1000); 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; int delta = m_audioBuffer.size() + samples.size() - m_maxBufferSize;
if (delta > 0) if (delta > 0)
@@ -23,7 +23,7 @@ namespace BlackSound
m_audioBuffer.append(samples); 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())); qint64 len = qMin(count, static_cast<qint64>(m_audioBuffer.size()));
samples = m_audioBuffer.mid(0, len); samples = m_audioBuffer.mid(0, len);

View File

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

View File

@@ -13,25 +13,19 @@ namespace BlackSound
setupPreset(preset); 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); int samplesRead = m_sourceProvider->readSamples(samples, count);
if (m_bypass) return samplesRead; if (m_bypass) return samplesRead;
QVector<double> doubleSamples = convertFromShortToDouble(samples);
for (int n = 0; n < samplesRead; n++) for (int n = 0; n < samplesRead; n++)
{ {
// TODO stereo implementation
for (int band = 0; band < m_filters.size(); band++) 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; return samplesRead;
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -20,7 +20,7 @@ namespace BlackSound
m_sourceProvider(sourceProvider) 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); int samplesRead = m_sourceProvider->readSamples(samples, count);
@@ -28,7 +28,7 @@ namespace BlackSound
{ {
for (int n = 0; n < samplesRead; n++) 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; return samplesRead;

View File

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