mirror of
https://github.com/saitohirga/WSJT-X.git
synced 2024-10-31 15:47:10 -04:00
542ffe8311
where possible audio devices that disappear are not forgotten until the user selects another device, this should allow temporarily missing devices or forgetting to switch on devices before starting WSJT-X to be handled more cleanly. If all else fails, visiting the Settings dialog and clicking OK should get things going again. Note that we still do not have a reliable way of detecting failed audio out devices, in that case selecting another device and then returning to the original should work. Enumerating audio devices is expensive and on Linux may take many seconds per device. To avoid lengthy blocking behaviour until it is absolutely necessary, audio devices are not enumerated until one of the "Settings->Audio" device drop-down lists is opened. Elsewhere when devices must be discovered the enumeration stops as soon as the configured device is discovered. A status bar message is posted when audio devices are being enumerated as a reminder that the UI may block while this is happening. The message box warning about unaccounted-for input audio samples now only triggers when >5 seconds of audio appears to be missing or over provided. Hopefully this will make the warning less annoying for those that are using audio sources with high and/or variable latencies. A status bar message is still posted for any amount of audio input samples unaccounted for >1/5 second, this message appearing a lot should be considered as notification that there is a problem with the audio sub-system, system load is too high, or time synchronization is stepping the PC clock rather than adjusting the frequency to maintain monotonic clock ticks.
126 lines
4.5 KiB
C++
126 lines
4.5 KiB
C++
#include "Detector.hpp"
|
|
#include <QDateTime>
|
|
#include <QtAlgorithms>
|
|
#include <QDebug>
|
|
#include <math.h>
|
|
#include "commons.h"
|
|
|
|
#include "moc_Detector.cpp"
|
|
|
|
extern "C" {
|
|
void fil4_(qint16*, qint32*, qint16*, qint32*);
|
|
}
|
|
|
|
extern dec_data_t dec_data;
|
|
|
|
Detector::Detector (unsigned frameRate, double periodLengthInSeconds,
|
|
unsigned downSampleFactor, QObject * parent)
|
|
: AudioDevice (parent)
|
|
, m_frameRate (frameRate)
|
|
, m_period (periodLengthInSeconds)
|
|
, m_downSampleFactor (downSampleFactor)
|
|
, m_samplesPerFFT {max_buffer_size}
|
|
, m_buffer ((downSampleFactor > 1) ?
|
|
new short [max_buffer_size * downSampleFactor] : nullptr)
|
|
, m_bufferPos (0)
|
|
{
|
|
(void)m_frameRate; // quell compiler warning
|
|
clear ();
|
|
}
|
|
|
|
void Detector::setBlockSize (unsigned n)
|
|
{
|
|
m_samplesPerFFT = n;
|
|
}
|
|
|
|
bool Detector::reset ()
|
|
{
|
|
clear ();
|
|
// don't call base class reset because it calls seek(0) which causes
|
|
// a warning
|
|
return isOpen ();
|
|
}
|
|
|
|
void Detector::clear ()
|
|
{
|
|
// set index to roughly where we are in time (1ms resolution)
|
|
// qint64 now (QDateTime::currentMSecsSinceEpoch ());
|
|
// unsigned msInPeriod ((now % 86400000LL) % (m_period * 1000));
|
|
// dec_data.params.kin = qMin ((msInPeriod * m_frameRate) / 1000, static_cast<unsigned> (sizeof (dec_data.d2) / sizeof (dec_data.d2[0])));
|
|
dec_data.params.kin = 0;
|
|
m_bufferPos = 0;
|
|
|
|
// fill buffer with zeros (G4WJS commented out because it might cause decoder hangs)
|
|
// qFill (dec_data.d2, dec_data.d2 + sizeof (dec_data.d2) / sizeof (dec_data.d2[0]), 0);
|
|
}
|
|
|
|
qint64 Detector::writeData (char const * data, qint64 maxSize)
|
|
{
|
|
static unsigned mstr0=999999;
|
|
qint64 ms0 = QDateTime::currentMSecsSinceEpoch() % 86400000;
|
|
unsigned mstr = ms0 % int(1000.0*m_period); // ms into the nominal Tx start time
|
|
if(mstr < mstr0) { //When mstr has wrapped around to 0, restart the buffer
|
|
dec_data.params.kin = 0;
|
|
m_bufferPos = 0;
|
|
}
|
|
mstr0=mstr;
|
|
|
|
// no torn frames
|
|
Q_ASSERT (!(maxSize % static_cast<qint64> (bytesPerFrame ())));
|
|
// these are in terms of input frames (not down sampled)
|
|
size_t framesAcceptable ((sizeof (dec_data.d2) /
|
|
sizeof (dec_data.d2[0]) - dec_data.params.kin) * m_downSampleFactor);
|
|
size_t framesAccepted (qMin (static_cast<size_t> (maxSize /
|
|
bytesPerFrame ()), framesAcceptable));
|
|
|
|
if (framesAccepted < static_cast<size_t> (maxSize / bytesPerFrame ())) {
|
|
qDebug () << "dropped " << maxSize / bytesPerFrame () - framesAccepted
|
|
<< " frames of data on the floor!"
|
|
<< dec_data.params.kin << mstr;
|
|
}
|
|
|
|
for (unsigned remaining = framesAccepted; remaining; ) {
|
|
size_t numFramesProcessed (qMin (m_samplesPerFFT *
|
|
m_downSampleFactor - m_bufferPos, remaining));
|
|
|
|
if(m_downSampleFactor > 1) {
|
|
store (&data[(framesAccepted - remaining) * bytesPerFrame ()],
|
|
numFramesProcessed, &m_buffer[m_bufferPos]);
|
|
m_bufferPos += numFramesProcessed;
|
|
|
|
if(m_bufferPos==m_samplesPerFFT*m_downSampleFactor) {
|
|
qint32 framesToProcess (m_samplesPerFFT * m_downSampleFactor);
|
|
qint32 framesAfterDownSample (m_samplesPerFFT);
|
|
if(m_downSampleFactor > 1 && dec_data.params.kin>=0 &&
|
|
dec_data.params.kin < (NTMAX*12000 - framesAfterDownSample)) {
|
|
fil4_(&m_buffer[0], &framesToProcess, &dec_data.d2[dec_data.params.kin],
|
|
&framesAfterDownSample);
|
|
dec_data.params.kin += framesAfterDownSample;
|
|
} else {
|
|
// qDebug() << "framesToProcess = " << framesToProcess;
|
|
// qDebug() << "dec_data.params.kin = " << dec_data.params.kin;
|
|
// qDebug() << "secondInPeriod = " << secondInPeriod();
|
|
// qDebug() << "framesAfterDownSample" << framesAfterDownSample;
|
|
}
|
|
Q_EMIT framesWritten (dec_data.params.kin);
|
|
m_bufferPos = 0;
|
|
}
|
|
|
|
} else {
|
|
store (&data[(framesAccepted - remaining) * bytesPerFrame ()],
|
|
numFramesProcessed, &dec_data.d2[dec_data.params.kin]);
|
|
m_bufferPos += numFramesProcessed;
|
|
dec_data.params.kin += numFramesProcessed;
|
|
if (m_bufferPos == static_cast<unsigned> (m_samplesPerFFT)) {
|
|
Q_EMIT framesWritten (dec_data.params.kin);
|
|
m_bufferPos = 0;
|
|
}
|
|
}
|
|
remaining -= numFramesProcessed;
|
|
}
|
|
|
|
// we drop any data past the end of the buffer on the floor until
|
|
// the next period starts
|
|
return maxSize;
|
|
}
|