AFV initial commit

This commit is contained in:
Roland Rossgotterer
2019-09-14 21:18:26 +02:00
committed by Mat Sutcliffe
parent 7030302e73
commit b5a2f2ad13
100 changed files with 6821 additions and 25 deletions

View File

@@ -0,0 +1,34 @@
#include "bufferedwaveprovider.h"
#include <QDebug>
BufferedWaveProvider::BufferedWaveProvider(const QAudioFormat &format, QObject *parent) :
ISampleProvider(parent)
{
// Set buffer size to 10 secs
m_maxBufferSize = format.bytesForDuration(10 * 1000 * 1000);
}
void BufferedWaveProvider::addSamples(const QVector<qint16> &samples)
{
int delta = m_audioBuffer.size() + samples.size() - m_maxBufferSize;
if(delta > 0)
{
m_audioBuffer.remove(0, delta);
}
m_audioBuffer.append(samples);
}
int BufferedWaveProvider::readSamples(QVector<qint16> &samples, qint64 count)
{
qint64 len = qMin(count, static_cast<qint64>(m_audioBuffer.size()));
samples = m_audioBuffer.mid(0, len);
// if (len != 0) qDebug() << "Reading" << count << "samples." << m_audioBuffer.size() << "currently in the buffer.";
m_audioBuffer.remove(0, len);
return len;
}
void BufferedWaveProvider::clearBuffer()
{
m_audioBuffer.clear();
}

View File

@@ -0,0 +1,30 @@
#ifndef BLACKSOUND_BUFFEREDWAVEPROVIDER_H
#define BLACKSOUND_BUFFEREDWAVEPROVIDER_H
#include "blacksound/blacksoundexport.h"
#include "blacksound/sampleprovider/sampleprovider.h"
#include <QAudioFormat>
#include <QByteArray>
#include <QVector>
class BLACKSOUND_EXPORT BufferedWaveProvider : public ISampleProvider
{
Q_OBJECT
public:
BufferedWaveProvider(const QAudioFormat &format, QObject *parent = nullptr);
void addSamples(const QVector<qint16> &samples);
virtual int readSamples(QVector<qint16> &samples, qint64 count) override;
int getBufferedBytes() const { return m_audioBuffer.size(); }
void clearBuffer();
private:
QVector<qint16> m_audioBuffer;
qint32 m_maxBufferSize;
};
#endif // BUFFEREDWAVEPROVIDER_H

View File

@@ -0,0 +1,51 @@
#include "equalizersampleprovider.h"
EqualizerSampleProvider::EqualizerSampleProvider(ISampleProvider *sourceProvider, EqualizerPresets preset, QObject *parent) :
ISampleProvider(parent)
{
m_sourceProvider = sourceProvider;
setupPreset(preset);
}
int EqualizerSampleProvider::readSamples(QVector<qint16> &samples, qint64 count)
{
int samplesRead = m_sourceProvider->readSamples(samples, count);
if (m_bypass) return samplesRead;
for (int n = 0; n < samplesRead; n++)
{
// TODO stereo implementation
for (int band = 0; band < m_filters.size(); band++)
{
float s = samples[n] / 32768.0f;
s = m_filters[band].process(s);
samples[n] = s * 32768;
}
samples[n] *= m_outputGain;
}
return samplesRead;
}
void EqualizerSampleProvider::setupPreset(EqualizerPresets preset)
{
switch (preset)
{
case VHFEmulation:
m_filters.push_back(BiQuadFilter(BiQuadFilterType::HighPass, 44100, 450, 1.0f));
m_filters.push_back(BiQuadFilter(BiQuadFilterType::Peak, 44100, 2200, 0.25, 13.0f));
m_filters.push_back(BiQuadFilter(BiQuadFilterType::LowPass, 44100, 3000, 1.0f));
break;
}
}
double EqualizerSampleProvider::outputGain() const
{
return m_outputGain;
}
void EqualizerSampleProvider::setOutputGain(double outputGain)
{
m_outputGain = outputGain;
}

View File

@@ -0,0 +1,41 @@
#ifndef EQUALIZERSAMPLEPROVIDER_H
#define EQUALIZERSAMPLEPROVIDER_H
#include "blacksound/blacksoundexport.h"
#include "blacksound/sampleprovider/sampleprovider.h"
#include "blacksound/dsp/biquadfilter.h"
#include <QSharedPointer>
#include <QVector>
enum EqualizerPresets
{
VHFEmulation = 1
};
class BLACKSOUND_EXPORT EqualizerSampleProvider : public ISampleProvider
{
Q_OBJECT
public:
EqualizerSampleProvider(ISampleProvider *sourceProvider, EqualizerPresets preset, QObject *parent = nullptr);
virtual int readSamples(QVector<qint16> &samples, qint64 count) override;
void setBypassEffects(bool value) { m_bypass = value; }
double outputGain() const;
void setOutputGain(double outputGain);
private:
void setupPreset(EqualizerPresets preset);
ISampleProvider *m_sourceProvider;
int m_channels = 1;
bool m_bypass = false;
double m_outputGain = 1.0;
QVector<BiQuadFilter> m_filters;
};
#endif // EQUALIZERSAMPLEPROVIDER_H

View File

@@ -0,0 +1,36 @@
#include "mixingsampleprovider.h"
int MixingSampleProvider::readSamples(QVector<qint16> &samples, qint64 count)
{
samples.clear();
samples.fill(0, count);
int outputLen = 0;
QVector<ISampleProvider*> finishedProviders;
for (int i = 0; i < m_sources.size(); i++)
{
ISampleProvider *sampleProvider = m_sources.at(i);
QVector<qint16> sourceBuffer;
int len = sampleProvider->readSamples(sourceBuffer, count);
for (int n = 0; n < len; n++)
{
samples[n] += sourceBuffer[n];
}
outputLen = qMax(len, outputLen);
if (sampleProvider->isFinished())
{
finishedProviders.push_back(sampleProvider);
}
}
for (ISampleProvider *sampleProvider : finishedProviders)
{
sampleProvider->deleteLater();
m_sources.removeAll(sampleProvider);
}
return outputLen;
}

View File

@@ -0,0 +1,21 @@
#ifndef MIXINGSAMPLEPROVIDER_H
#define MIXINGSAMPLEPROVIDER_H
#include "blacksound/blacksoundexport.h"
#include "blacksound/sampleprovider/sampleprovider.h"
#include <QSharedPointer>
#include <QVector>
class BLACKSOUND_EXPORT MixingSampleProvider : public ISampleProvider
{
public:
MixingSampleProvider(QObject * parent = nullptr) : ISampleProvider(parent) {}
void addMixerInput(ISampleProvider *provider) { m_sources.append(provider); }
virtual int readSamples(QVector<qint16> &samples, qint64 count) override;
private:
QVector<ISampleProvider*> m_sources;
};
#endif // MIXINGSAMPLEPROVIDER_H

View File

@@ -0,0 +1,24 @@
#include "pinknoisegenerator.h"
int PinkNoiseGenerator::readSamples(QVector<qint16> &samples, qint64 count)
{
samples.clear();
samples.fill(0, count);
for (int sampleCount = 0; sampleCount < count; sampleCount++)
{
double white = 2 * random.generateDouble() - 1;
pinkNoiseBuffer[0] = 0.99886*pinkNoiseBuffer[0] + white*0.0555179;
pinkNoiseBuffer[1] = 0.99332*pinkNoiseBuffer[1] + white*0.0750759;
pinkNoiseBuffer[2] = 0.96900*pinkNoiseBuffer[2] + white*0.1538520;
pinkNoiseBuffer[3] = 0.86650*pinkNoiseBuffer[3] + white*0.3104856;
pinkNoiseBuffer[4] = 0.55000*pinkNoiseBuffer[4] + white*0.5329522;
pinkNoiseBuffer[5] = -0.7616*pinkNoiseBuffer[5] - white*0.0168980;
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;
}
return count;
}

View File

@@ -0,0 +1,29 @@
#ifndef PINKNOISEGENERATOR_H
#define PINKNOISEGENERATOR_H
#include "blacksound/blacksoundexport.h"
#include "blacksound/sampleprovider/sampleprovider.h"
#include <QRandomGenerator>
#include <QVector>
#include <array>
class BLACKSOUND_EXPORT PinkNoiseGenerator : public ISampleProvider
{
Q_OBJECT
public:
PinkNoiseGenerator(QObject *parent = nullptr) : ISampleProvider(parent) {}
virtual int readSamples(QVector<qint16> &samples, qint64 count) override;
void setGain(double gain) { m_gain = gain; }
private:
QRandomGenerator random;
std::array<double, 7> pinkNoiseBuffer = {0};
double m_gain = 0.0;
};
#endif // PINKNOISEGENERATOR_H

View File

@@ -0,0 +1,22 @@
#include "resourcesound.h"
#include "audioutilities.h"
ResourceSound::ResourceSound(const QString &audioFileName)
{
m_wavFile = new WavFile;
m_wavFile->open(audioFileName);
if (m_wavFile->fileFormat().sampleType() == QAudioFormat::Float)
{
m_samples = convertFloatBytesTo16BitPCM(m_wavFile->audioData());
}
else
{
m_samples = convertBytesTo16BitPCM(m_wavFile->audioData());
}
}
const QVector<qint16>& ResourceSound::audioData()
{
return m_samples;
}

View File

@@ -0,0 +1,22 @@
#ifndef RESOURCESOUND_H
#define RESOURCESOUND_H
#include "blacksound/blacksoundexport.h"
#include "blacksound/wav/wavfile.h"
#include <QString>
#include <QVector>
class ResourceSound
{
public:
ResourceSound(const QString &audioFileName);
const QVector<qint16> &audioData();
private:
WavFile *m_wavFile;
QVector<qint16> m_samples;
};
#endif // RESOURCESOUND_H

View File

@@ -0,0 +1,76 @@
#include "resourcesoundsampleprovider.h"
#include <QDebug>
ResourceSoundSampleProvider::ResourceSoundSampleProvider(const ResourceSound &resourceSound, QObject *parent) :
ISampleProvider(parent),
m_resourceSound(resourceSound)
{
tempBuffer.resize(tempBufferSize);
}
int ResourceSoundSampleProvider::readSamples(QVector<qint16> &samples, qint64 count)
{
if (count > tempBufferSize)
{
qDebug() << "Count too large for temp buffer";
return 0;
}
qint64 availableSamples = m_resourceSound.audioData().size() - position;
qint64 samplesToCopy = qMin(availableSamples, count);
samples.clear();
samples.fill(0, samplesToCopy);
for (qint64 i = 0; i < samplesToCopy; i++)
{
tempBuffer[i] = m_resourceSound.audioData().at(position + i);
}
if (m_gain != 1.0f)
{
for (int i = 0; i < samplesToCopy; i++)
{
tempBuffer[i] *= m_gain;
}
}
for (qint64 i = 0; i < samplesToCopy; i++)
{
samples[i] = tempBuffer.at(i);
}
position += samplesToCopy;
if (position > availableSamples - 1)
{
if (m_looping) { position = 0; }
else { m_isFinished = true; }
}
return (int)samplesToCopy;
}
bool ResourceSoundSampleProvider::isFinished()
{
return m_isFinished;
}
bool ResourceSoundSampleProvider::looping() const
{
return m_looping;
}
void ResourceSoundSampleProvider::setLooping(bool looping)
{
m_looping = looping;
}
float ResourceSoundSampleProvider::gain() const
{
return m_gain;
}
void ResourceSoundSampleProvider::setGain(float gain)
{
m_gain = gain;
}

View File

@@ -0,0 +1,35 @@
#ifndef RESOURCESOUNDSAMPLEPROVIDER_H
#define RESOURCESOUNDSAMPLEPROVIDER_H
#include "blacksound/blacksoundexport.h"
#include "sampleprovider.h"
#include "resourcesound.h"
class BLACKSOUND_EXPORT ResourceSoundSampleProvider : public ISampleProvider
{
Q_OBJECT
public:
ResourceSoundSampleProvider(const ResourceSound &resourceSound, QObject *parent = nullptr);
virtual int readSamples(QVector<qint16> &samples, qint64 count) override;
virtual bool isFinished() override;
bool looping() const;
void setLooping(bool looping);
float gain() const;
void setGain(float gain);
private:
float m_gain = 1.0f;
bool m_looping = false;
ResourceSound m_resourceSound;
qint64 position = 0;
const int tempBufferSize = 9600; //9600 = 200ms
QVector<qint16> tempBuffer;
bool m_isFinished = false;
};
#endif // RESOURCESOUNDSAMPLEPROVIDER_H

View File

@@ -0,0 +1,21 @@
#ifndef SAMPLEPROVIDER_H
#define SAMPLEPROVIDER_H
#include "blacksound/blacksoundexport.h"
#include <QObject>
#include <QVector>
class BLACKSOUND_EXPORT ISampleProvider : public QObject
{
Q_OBJECT
public:
ISampleProvider(QObject *parent = nullptr) : QObject(parent) {}
virtual ~ISampleProvider() {}
virtual int readSamples(QVector<qint16> &samples, qint64 count) = 0;
virtual bool isFinished() { return false; }
};
#endif // SAMPLEPROVIDER_H

View File

@@ -0,0 +1,22 @@
SOURCES += \
$$PWD/bufferedwaveprovider.cpp \
$$PWD/mixingsampleprovider.cpp \
$$PWD/equalizersampleprovider.cpp \
$$PWD/pinknoisegenerator.cpp \
$$PWD/resourcesound.cpp \
$$PWD/resourcesoundsampleprovider.cpp \
$$PWD/samples.cpp \
$$PWD/sawtoothgenerator.cpp \
$$PWD/simplecompressoreffect.cpp \
HEADERS += \
$$PWD/bufferedwaveprovider.h \
$$PWD/mixingsampleprovider.h \
$$PWD/resourcesound.h \
$$PWD/resourcesoundsampleprovider.h \
$$PWD/sampleprovider.h \
$$PWD/equalizersampleprovider.h \
$$PWD/pinknoisegenerator.h \
$$PWD/samples.h \
$$PWD/sawtoothgenerator.h \
$$PWD/simplecompressoreffect.h \

View File

@@ -0,0 +1,29 @@
#include "samples.h"
#include "blackmisc/directoryutils.h"
Samples &Samples::instance()
{
static Samples samples;
return samples;
}
Samples::Samples() :
m_crackle(BlackMisc::CDirectoryUtils::soundFilesDirectory() + "/Crackle_f32.wav"),
m_click(BlackMisc::CDirectoryUtils::soundFilesDirectory() + "/Click_f32.wav"),
m_whiteNoise(BlackMisc::CDirectoryUtils::soundFilesDirectory() + "/WhiteNoise_f32.wav")
{ }
ResourceSound Samples::click() const
{
return m_click;
}
ResourceSound Samples::crackle() const
{
return m_crackle;
}
ResourceSound Samples::whiteNoise() const
{
return m_whiteNoise;
}

View File

@@ -0,0 +1,24 @@
#ifndef SAMPLES_H
#define SAMPLES_H
#include "blacksound/blacksoundexport.h"
#include "resourcesound.h"
class BLACKSOUND_EXPORT Samples
{
public:
static Samples &instance();
ResourceSound crackle() const;
ResourceSound click() const;
ResourceSound whiteNoise() const;
private:
Samples();
ResourceSound m_crackle;
ResourceSound m_click;
ResourceSound m_whiteNoise;
};
#endif // SAMPLES_H

View File

@@ -0,0 +1,23 @@
#include "sawtoothgenerator.h"
#include <cmath>
SawToothGenerator::SawToothGenerator(double frequency, QObject *parent) :
ISampleProvider(parent),
m_frequency(frequency)
{}
int SawToothGenerator::readSamples(QVector<qint16> &samples, qint64 count)
{
samples.clear();
samples.fill(0, count);
for (int sampleCount = 0; sampleCount < count; sampleCount++)
{
double multiple = 2 * m_frequency / m_sampleRate;
double sampleSaw = std::fmod((m_nSample * multiple), 2) - 1;
double sampleValue = m_gain * sampleSaw;
samples[sampleCount] = sampleValue * 32768;
m_nSample++;
}
return count;
}

View File

@@ -0,0 +1,30 @@
#ifndef SAWTOOTHGENERATOR_H
#define SAWTOOTHGENERATOR_H
#include "blacksound/blacksoundexport.h"
#include "blacksound/sampleprovider/sampleprovider.h"
#include <QRandomGenerator>
#include <QVector>
#include <array>
class BLACKSOUND_EXPORT SawToothGenerator : public ISampleProvider
{
Q_OBJECT
public:
SawToothGenerator(double frequency, QObject *parent = nullptr);
virtual int readSamples(QVector<qint16> &samples, qint64 count) override;
void setGain(double gain) { m_gain = gain; }
private:
double m_gain = 0.0;
double m_frequency = 0.0;
double m_sampleRate = 48000;
int m_nSample = 0;
};
#endif // SAWTOOTHGENERATOR_H

View File

@@ -0,0 +1,45 @@
#include "simplecompressoreffect.h"
#include <QDebug>
SimpleCompressorEffect::SimpleCompressorEffect(ISampleProvider *source, QObject *parent) :
ISampleProvider(parent),
m_sourceStream(source)
{
m_simpleCompressor.setAttack(5.0);
m_simpleCompressor.setRelease(10.0);
m_simpleCompressor.setSampleRate(48000.0);
m_simpleCompressor.setThresh(16.0);
m_simpleCompressor.setRatio(6.0);
m_simpleCompressor.setMakeUpGain(16.0);
m_timer.start(3000);
}
int SimpleCompressorEffect::readSamples(QVector<qint16> &samples, qint64 count)
{
int samplesRead = m_sourceStream->readSamples(samples, count);
if (m_enabled)
{
for (int sample = 0; sample < samplesRead; sample+=channels)
{
double in1 = samples.at(sample) / 32768.0;
double in2 = (channels == 1) ? 0 : samples.at(sample+1);
m_simpleCompressor.process(in1, in2);
samples[sample] = in1 * 32768.0;
if (channels > 1)
samples[sample + 1] = in2 * 32768.0f;
}
}
return samplesRead;
}
void SimpleCompressorEffect::setEnabled(bool enabled)
{
m_enabled = enabled;
}
void SimpleCompressorEffect::setMakeUpGain(double gain)
{
m_simpleCompressor.setMakeUpGain(gain);
}

View File

@@ -0,0 +1,32 @@
#ifndef SIMPLECOMPRESSOREFFECT_H
#define SIMPLECOMPRESSOREFFECT_H
#include "blacksound/blacksoundexport.h"
#include "sampleprovider.h"
#include "blacksound/dsp/SimpleComp.h"
#include <QObject>
#include <QTimer>
class BLACKSOUND_EXPORT SimpleCompressorEffect : public ISampleProvider
{
Q_OBJECT
public:
SimpleCompressorEffect(ISampleProvider *source, QObject *parent = nullptr);
virtual int readSamples(QVector<qint16> &samples, qint64 count) override;
void setEnabled(bool enabled);
void setMakeUpGain(double gain);
private:
QTimer m_timer;
ISampleProvider *m_sourceStream;
bool m_enabled = true;
chunkware_simple::SimpleComp m_simpleCompressor;
const int channels = 1;
};
#endif // SIMPLECOMPRESSOREFFECT_H