mirror of
https://github.com/swift-project/pilotclient.git
synced 2026-04-10 05:55:33 +08:00
[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:
committed by
Mat Sutcliffe
parent
fbb126370c
commit
240df93406
@@ -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();
|
||||||
|
|||||||
@@ -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; }
|
||||||
|
|||||||
@@ -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");
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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; }
|
||||||
|
|||||||
@@ -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++)
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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; }
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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; }
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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; }
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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; }
|
||||||
|
|||||||
Reference in New Issue
Block a user