[AFV] Add HF simulation

This commit is contained in:
Roland Rossgotterer
2019-09-30 09:48:04 +02:00
committed by Mat Sutcliffe
parent 2c1067b27e
commit 1f2d4a10b1
9 changed files with 66 additions and 16 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 "blackcore/afv/audio/receiversampleprovider.h"
#include <QtMath> #include <QtMath>
#include <QDebug> #include <QDebug>
@@ -22,9 +23,10 @@ namespace BlackCore
{ {
namespace Audio namespace Audio
{ {
CallsignSampleProvider::CallsignSampleProvider(const QAudioFormat &audioFormat, QObject *parent) : CallsignSampleProvider::CallsignSampleProvider(const QAudioFormat &audioFormat, const CReceiverSampleProvider *receiver, QObject *parent) :
ISampleProvider(parent), ISampleProvider(parent),
m_audioFormat(audioFormat), m_audioFormat(audioFormat),
m_receiver(receiver),
m_decoder(audioFormat.sampleRate(), 1) m_decoder(audioFormat.sampleRate(), 1)
{ {
Q_ASSERT(audioFormat.channelCount() == 1); Q_ASSERT(audioFormat.channelCount() == 1);
@@ -36,6 +38,9 @@ namespace BlackCore
m_whiteNoise = new CResourceSoundSampleProvider(Samples::instance().whiteNoise(), m_mixer); m_whiteNoise = new CResourceSoundSampleProvider(Samples::instance().whiteNoise(), m_mixer);
m_whiteNoise->setLooping(true); m_whiteNoise->setLooping(true);
m_whiteNoise->setGain(0.0); m_whiteNoise->setGain(0.0);
m_hfWhiteNoise = new CResourceSoundSampleProvider(Samples::instance().hfWhiteNoise(), m_mixer);
m_hfWhiteNoise->setLooping(true);
m_hfWhiteNoise->setGain(0.0);
m_acBusNoise = new CSawToothGenerator(400, m_mixer); m_acBusNoise = new CSawToothGenerator(400, m_mixer);
m_audioInput = new CBufferedWaveProvider(audioFormat, m_mixer); m_audioInput = new CBufferedWaveProvider(audioFormat, m_mixer);
@@ -48,6 +53,7 @@ namespace BlackCore
m_mixer->addMixerInput(m_whiteNoise); m_mixer->addMixerInput(m_whiteNoise);
m_mixer->addMixerInput(m_acBusNoise); m_mixer->addMixerInput(m_acBusNoise);
m_mixer->addMixerInput(m_hfWhiteNoise);
m_mixer->addMixerInput(m_voiceEq); m_mixer->addMixerInput(m_voiceEq);
m_timer.setInterval(100); m_timer.setInterval(100);
@@ -165,23 +171,41 @@ namespace BlackCore
{ {
m_crackleSoundProvider->setGain(0.0); m_crackleSoundProvider->setGain(0.0);
m_whiteNoise->setGain(0.0); m_whiteNoise->setGain(0.0);
m_hfWhiteNoise->setGain(0.0);
m_acBusNoise->setGain(0.0); m_acBusNoise->setGain(0.0);
m_simpleCompressorEffect->setEnabled(false); m_simpleCompressorEffect->setEnabled(false);
m_voiceEq->setBypassEffects(true); m_voiceEq->setBypassEffects(true);
} }
else else
{ {
double crackleFactor = static_cast<double>(((qExp(m_distanceRatio) * qPow(m_distanceRatio, -4.0)) / 350) - 0.00776652); if (m_receiver->getFrequencyHz() < 30000000)
{
float crackleFactor = (float)(((qExp(m_distanceRatio) * qPow(m_distanceRatio, -4.0)) / 350) - 0.00776652);
if (crackleFactor < 0.00) { crackleFactor = 0.0f; } if (crackleFactor < 0.0f) { crackleFactor = 0.0f; }
if (crackleFactor > 0.20) { crackleFactor = 0.20f; } if (crackleFactor > 0.20f) { crackleFactor = 0.20f; }
m_crackleSoundProvider->setGain(crackleFactor * 2); m_hfWhiteNoise->setGain(m_hfWhiteNoiseGainMin);
m_whiteNoise->setGain(m_whiteNoiseGainMin); m_acBusNoise->setGain(m_acBusGainMin + 0.001f);
m_acBusNoise->setGain(m_acBusGainMin); m_simpleCompressorEffect->setEnabled(true);
m_simpleCompressorEffect->setEnabled(true); m_voiceEq->setBypassEffects(false);
m_voiceEq->setBypassEffects(false); m_voiceEq->setOutputGain(0.38f);
m_voiceEq->setOutputGain(1.0 - crackleFactor * 3.7); m_whiteNoise->setGain(0.0);
}
else
{
float crackleFactor = (float)(((qExp(m_distanceRatio) * qPow(m_distanceRatio, -4.0)) / 350) - 0.00776652);
if (crackleFactor < 0.0f) { crackleFactor = 0.0f; }
if (crackleFactor > 0.20f) { crackleFactor = 0.20f; }
m_crackleSoundProvider->setGain(crackleFactor * 2);
m_whiteNoise->setGain(m_whiteNoiseGainMin);
m_acBusNoise->setGain(m_acBusGainMin);
m_simpleCompressorEffect->setEnabled(true);
m_voiceEq->setBypassEffects(false);
m_voiceEq->setOutputGain(1.0 - crackleFactor * 3.7);
}
} }
} }

View File

@@ -33,6 +33,8 @@ namespace BlackCore
{ {
namespace Audio namespace Audio
{ {
class CReceiverSampleProvider;
//! Callsign provide //! Callsign provide
class CallsignSampleProvider : public BlackSound::SampleProvider::ISampleProvider class CallsignSampleProvider : public BlackSound::SampleProvider::ISampleProvider
{ {
@@ -40,7 +42,7 @@ namespace BlackCore
public: public:
//! Ctor //! Ctor
CallsignSampleProvider(const QAudioFormat &audioFormat, 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<qint16> &samples, qint64 count) override;
@@ -70,6 +72,7 @@ namespace BlackCore
QAudioFormat m_audioFormat; QAudioFormat m_audioFormat;
const double m_whiteNoiseGainMin = 0.17; //0.01; const double m_whiteNoiseGainMin = 0.17; //0.01;
const double m_hfWhiteNoiseGainMin = 0.6; //0.01;
const double m_acBusGainMin = 0.0028; //0.002; const double m_acBusGainMin = 0.0028; //0.002;
const int m_frameCount = 960; const int m_frameCount = 960;
const int m_idleTimeoutMs = 500; const int m_idleTimeoutMs = 500;
@@ -82,9 +85,11 @@ namespace BlackCore
float m_distanceRatio = 1.0; float m_distanceRatio = 1.0;
const CReceiverSampleProvider *m_receiver = nullptr;
BlackSound::SampleProvider::CMixingSampleProvider *m_mixer = nullptr; BlackSound::SampleProvider::CMixingSampleProvider *m_mixer = nullptr;
BlackSound::SampleProvider::CResourceSoundSampleProvider *m_crackleSoundProvider = nullptr; BlackSound::SampleProvider::CResourceSoundSampleProvider *m_crackleSoundProvider = nullptr;
BlackSound::SampleProvider::CResourceSoundSampleProvider *m_whiteNoise = nullptr; BlackSound::SampleProvider::CResourceSoundSampleProvider *m_whiteNoise = nullptr;
BlackSound::SampleProvider::CResourceSoundSampleProvider *m_hfWhiteNoise = nullptr;
BlackSound::SampleProvider::CSawToothGenerator *m_acBusNoise = nullptr; BlackSound::SampleProvider::CSawToothGenerator *m_acBusNoise = nullptr;
BlackSound::SampleProvider::CSimpleCompressorEffect *m_simpleCompressorEffect = nullptr; BlackSound::SampleProvider::CSimpleCompressorEffect *m_simpleCompressorEffect = nullptr;
BlackSound::SampleProvider::CEqualizerSampleProvider *m_voiceEq = nullptr; BlackSound::SampleProvider::CEqualizerSampleProvider *m_voiceEq = nullptr;

View File

@@ -31,7 +31,7 @@ namespace BlackCore
for (int i = 0; i < voiceInputNumber; i++) for (int i = 0; i < voiceInputNumber; i++)
{ {
auto voiceInput = new CallsignSampleProvider(audioFormat, m_mixer); auto voiceInput = new CallsignSampleProvider(audioFormat, this, m_mixer);
m_voiceInputs.push_back(voiceInput); m_voiceInputs.push_back(voiceInput);
m_mixer->addMixerInput(voiceInput); m_mixer->addMixerInput(voiceInput);
} }
@@ -198,8 +198,10 @@ namespace BlackCore
} }
} }
uint CReceiverSampleProvider::getFrequencyHz() const
{
return m_frequencyHz;
}
} // ns } // ns
} // ns } // ns

View File

@@ -72,6 +72,9 @@ namespace BlackCore
//! \remark those callsigns are transmitting and "I do receive them" //! \remark those callsigns are transmitting and "I do receive them"
const BlackMisc::Aviation::CCallsignSet &getReceivingCallsigns() { return m_receivingCallsigns; } const BlackMisc::Aviation::CCallsignSet &getReceivingCallsigns() { return m_receivingCallsigns; }
//! Get frequency in Hz
uint getFrequencyHz() const;
signals: signals:
//! Receving callsigns have changed //! Receving callsigns have changed
void receivingCallsignsChanged(const TransceiverReceivingCallsignsChangedArgs &args); void receivingCallsignsChanged(const TransceiverReceivingCallsignsChangedArgs &args);

View File

@@ -93,7 +93,7 @@ namespace BlackCore
if (m_connection->isConnected()) { emit this->connectionStatusChanged(Connected); } if (m_connection->isConnected()) { emit this->connectionStatusChanged(Connected); }
else { emit this->connectionStatusChanged(Disconnected); } else { emit this->connectionStatusChanged(Disconnected); }
m_connection->getAllAliasedStations(); m_aliasedStations = m_connection->getAllAliasedStations();
} }
void CAfvClient::disconnectFrom() void CAfvClient::disconnectFrom()
@@ -225,6 +225,17 @@ namespace BlackCore
// Fix rounding issues like 128074999 Hz -> 128075000 Hz // Fix rounding issues like 128074999 Hz -> 128075000 Hz
quint32 roundedFrequencyHz = static_cast<quint32>(qRound(frequencyHz / 1000.0)) * 1000; quint32 roundedFrequencyHz = static_cast<quint32>(qRound(frequencyHz / 1000.0)) * 1000;
auto it = std::find_if(m_aliasedStations.begin(), m_aliasedStations.end(), [roundedFrequencyHz](const StationDto & d)
{
return d.frequencyAlias == roundedFrequencyHz;
});
if (it != m_aliasedStations.end())
{
qDebug() << "Aliasing" << frequencyHz << "Hz [VHF] to" << it->frequency << "Hz [HF]";
roundedFrequencyHz = it->frequency;
}
if (m_transceivers.size() >= id + 1) if (m_transceivers.size() >= id + 1)
{ {
if (m_transceivers[id].frequencyHz != roundedFrequencyHz) if (m_transceivers[id].frequencyHz != roundedFrequencyHz)

View File

@@ -232,6 +232,7 @@ namespace BlackCore
QTimer m_voiceServerPositionTimer; QTimer m_voiceServerPositionTimer;
QVector<TransceiverDto> m_transceivers; QVector<TransceiverDto> m_transceivers;
QSet<quint16> m_enabledTransceivers; QSet<quint16> m_enabledTransceivers;
QVector<StationDto> m_aliasedStations;
Audio::InputVolumeStreamArgs m_inputVolumeStream; Audio::InputVolumeStreamArgs m_inputVolumeStream;
Audio::OutputVolumeStreamArgs m_outputVolumeStream; Audio::OutputVolumeStreamArgs m_outputVolumeStream;

View File

@@ -26,7 +26,8 @@ namespace BlackSound
Samples::Samples() : Samples::Samples() :
m_crackle(CFileUtils::soundFilePathAndFileName(fnCrackle())), m_crackle(CFileUtils::soundFilePathAndFileName(fnCrackle())),
m_click(CFileUtils::soundFilePathAndFileName(fnClick())), m_click(CFileUtils::soundFilePathAndFileName(fnClick())),
m_whiteNoise(CFileUtils::soundFilePathAndFileName(fnWhiteNoise())) m_whiteNoise(CFileUtils::soundFilePathAndFileName(fnWhiteNoise())),
m_hfWhiteNoise(CFileUtils::soundFilePathAndFileName(fnHfWhiteNoise()))
{ {
this->initSounds(); this->initSounds();
} }

View File

@@ -36,6 +36,7 @@ namespace BlackSound
const CResourceSound &crackle() const { return m_crackle; } const CResourceSound &crackle() const { return m_crackle; }
const CResourceSound &click() const { return m_click; } const CResourceSound &click() const { return m_click; }
const CResourceSound &whiteNoise() const { return m_whiteNoise; } const CResourceSound &whiteNoise() const { return m_whiteNoise; }
const CResourceSound hfWhiteNoise() const { return m_hfWhiteNoise; }
//! @} //! @}
//! Play the click sound //! Play the click sound
@@ -45,6 +46,7 @@ namespace BlackSound
static const QString &fnCrackle() { static const QString f = "afv_crackle_f32.wav"; return f; } static const QString &fnCrackle() { static const QString f = "afv_crackle_f32.wav"; return f; }
static const QString &fnClick() { static const QString f = "afv_click_f32.wav"; return f; } static const QString &fnClick() { static const QString f = "afv_click_f32.wav"; return f; }
static const QString &fnWhiteNoise() { static const QString f = "afv_whitenoise_f32.wav"; return f; } static const QString &fnWhiteNoise() { static const QString f = "afv_whitenoise_f32.wav"; return f; }
static const QString &fnHfWhiteNoise() { static const QString f = "afv_hf_whiteNoise_f32.wav"; return f; }
//! @} //! @}
private: private:
@@ -54,6 +56,7 @@ namespace BlackSound
CResourceSound m_crackle; CResourceSound m_crackle;
CResourceSound m_click; CResourceSound m_click;
CResourceSound m_whiteNoise; CResourceSound m_whiteNoise;
CResourceSound m_hfWhiteNoise;
BlackMisc::CSetting<BlackMisc::Audio::TSettings> m_audioSettings { this, &Samples::onSettingsChanged }; BlackMisc::CSetting<BlackMisc::Audio::TSettings> m_audioSettings { this, &Samples::onSettingsChanged };

Binary file not shown.