Forgot to include four files.

git-svn-id: svn+ssh://svn.code.sf.net/p/wsjt/wsjt/branches/wsjtx@3526 ab8295b8-cf94-4d9e-aec4-7959e3be5d79
This commit is contained in:
Joe Taylor 2013-08-05 17:41:12 +00:00
parent 37f9eada62
commit 324169661e
5 changed files with 437 additions and 1 deletions

93
Detector.cpp Normal file
View File

@ -0,0 +1,93 @@
#include "Detector.hpp"
#include <algorithm>
#include <QDateTime>
#include <QDebug>
#include "commons.h"
Detector::Detector (unsigned frameRate, unsigned periodLengthInSeconds, unsigned bytesPerSignal, QObject * parent)
: QIODevice (parent)
, m_frameRate (frameRate)
, m_period (periodLengthInSeconds)
, m_bytesPerSignal (bytesPerSignal)
, m_monitoring (false)
, m_starting (false)
{
clear ();
}
bool Detector::reset ()
{
clear ();
return QIODevice::reset ();
}
void Detector::clear ()
{
// set index to roughly where we are in time (1s resolution)
jt9com_.kin = secondInPeriod () * m_frameRate;
// fill buffer with zeros
std::fill (jt9com_.d2, jt9com_.d2 + sizeof (jt9com_.d2) / sizeof (jt9com_.d2[0]), 0);
}
qint64 Detector::writeData (char const * data, qint64 maxSize)
{
Q_ASSERT (!(maxSize % sizeof (jt9com_.d2[0]))); // no torn frames
Q_ASSERT (!(reinterpret_cast<size_t> (data) % __alignof__ (frame_t))); // data is aligned as frame_t would be
frame_t const * frames (reinterpret_cast<frame_t const *> (data));
qint64 framesAcceptable (sizeof (jt9com_.d2) / sizeof (jt9com_.d2[0]) - jt9com_.kin);
qint64 framesAccepted (std::min (maxSize / sizeof (jt9com_.d2[0]), framesAcceptable));
if (framesAccepted < maxSize / sizeof (jt9com_.d2[0]))
{
qDebug () << "dropped " << maxSize / sizeof (jt9com_.d2[0]) - framesAccepted << " frames of data on the floor!\n";
}
std::copy (frames, frames + framesAccepted, &jt9com_.d2[jt9com_.kin]);
unsigned lastSignalIndex (jt9com_.kin * sizeof (jt9com_.d2[0]) / m_bytesPerSignal);
jt9com_.kin += framesAccepted;
unsigned currentSignalIndex (jt9com_.kin * sizeof (jt9com_.d2[0]) / m_bytesPerSignal);
if (currentSignalIndex != lastSignalIndex && m_monitoring)
{
Q_EMIT bytesWritten (currentSignalIndex * m_bytesPerSignal);
}
if (!secondInPeriod ())
{
if (!m_starting)
{
// next samples will be in new period so wrap around to
// start of buffer
//
// we don't bother calling reset () since we expect to fill
// the whole buffer and don't need to waste cycles zeroing
jt9com_.kin = 0;
m_starting = true;
}
}
else if (m_starting)
{
m_starting = false;
}
return maxSize; // we drop any data past the end of
// the buffer on the floor until the
// next period starts
}
unsigned Detector::secondInPeriod () const
{
// we take the time of the data as the following assuming no latency
// delivering it to us (not true but close enough for us)
qint64 now (QDateTime::currentMSecsSinceEpoch ());
unsigned secondInToday ((now % 86400000LL) / 1000);
return secondInToday % m_period;
}

67
Detector.hpp Normal file
View File

@ -0,0 +1,67 @@
#ifndef DETECTOR_HPP__
#define DETECTOR_HPP__
#include <inttypes.h>
#include <QIODevice>
//
// output device that distributes data in predefined chunks via a signal
//
// the underlying device for this abstraction is just the buffer that
// stores samples throughout a receiving period
//
class Detector : public QIODevice
{
Q_OBJECT;
Q_PROPERTY (bool monitoring READ isMonitoring WRITE setMonitoring);
private:
Q_DISABLE_COPY (Detector);
public:
//
// if the data buffer were not global storage and fixed size then we
// might want maximum size passed as constructor arguments
//
Detector (unsigned frameRate, unsigned periodLengthInSeconds, unsigned bytesPerSignal, QObject * parent = 0);
bool open ()
{
// we only support data consumption and want it as fast as possible
return QIODevice::open (QIODevice::WriteOnly | QIODevice::Unbuffered);
}
bool isSequential () const
{
return true;
}
bool isMonitoring () const {return m_monitoring;}
void setMonitoring (bool newState) {m_monitoring = newState;}
bool reset ();
protected:
qint64 readData (char * /* data */, qint64 /* maxSize */)
{
return -1; // we don't produce data
}
qint64 writeData (char const * data, qint64 maxSize);
private:
typedef int16_t frame_t;
void clear (); // discard buffer contents
unsigned secondInPeriod () const;
unsigned m_frameRate;
unsigned m_period;
unsigned m_bytesPerSignal;
bool m_monitoring;
bool m_starting;
};
#endif

195
Modulator.cpp Normal file
View File

@ -0,0 +1,195 @@
#include "Modulator.hpp"
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <limits>
#include <QDateTime>
extern float gran(); // Noise generator (for tests only)
double const Modulator::m_twoPi = 2.0 * 3.141592653589793238462;
// float wpm=20.0;
// unsigned m_nspd=1.2*48000.0/wpm;
// m_nspd=3072; //18.75 WPM
unsigned const Modulator::m_nspd = 2048 + 512; // 22.5 WPM
Modulator::Modulator (unsigned frameRate, unsigned periodLengthInSeconds, QObject * parent)
: QIODevice (parent)
, m_frameRate (frameRate)
, m_period (periodLengthInSeconds)
, m_state (Idle)
, m_phi (0.)
, m_ic (0)
, m_isym0 (std::numeric_limits<unsigned>::max ()) // ensure we set up first symbol tone
{
}
bool Modulator::open (std::vector<int> const * symbols, std::vector<int> const * cw, double framesPerSymbol, unsigned frequency, double dBSNR)
{
m_symbols.reset (symbols); // take over ownership (cannot throw)
m_cw.reset (cw); // take over ownership (cannot throw)
m_addNoise = dBSNR < 0.;
m_nsps = framesPerSymbol;
m_frequency = frequency;
m_amp = std::numeric_limits<frame_t>::max ();
m_state = Idle;
// noise generator parameters
if (m_addNoise)
{
m_snr = std::pow (10.0, 0.05 * (dBSNR - 6.0));
m_fac = 3000.0;
if (m_snr > 1.0)
{
m_fac = 3000.0 / m_snr;
}
}
return QIODevice::open (QIODevice::ReadOnly);
}
qint64 Modulator::readData (char * data, qint64 maxSize)
{
frame_t * frames (reinterpret_cast<frame_t *> (data));
unsigned numFrames (maxSize / sizeof (frame_t));
switch (m_state)
{
case Idle:
{
// Time according to this computer
qint64 ms = QDateTime::currentMSecsSinceEpoch() % 86400000;
unsigned mstr = ms % (1000 * m_period);
if (mstr < 1000) // send silence up to first second
{
std::fill (frames, frames + numFrames, 0); // silence
return numFrames * sizeof (frame_t);
}
m_ic = (mstr - 1000) * 48;
std::srand (mstr); // Initialize random seed
m_state = Active;
}
// fall through
case Active:
{
unsigned isym (m_tuning ? 0 : m_ic / (4.0 * m_nsps)); // Actual fsample=48000
if (isym >= m_symbols->size () && (*m_cw)[0] > 0)
{
// Output the CW ID
m_dphi = m_twoPi * m_frequency / m_frameRate;
unsigned const ic0 = m_symbols->size () * 4 * m_nsps;
unsigned j (0);
for (unsigned i = 0; i < numFrames; ++i)
{
m_phi += m_dphi;
if (m_phi > m_twoPi)
{
m_phi -= m_twoPi;
}
frame_t frame = std::numeric_limits<frame_t>::max () * std::sin (m_phi);
j = (m_ic - ic0) / m_nspd + 1;
if (!(*m_cw)[j])
{
frame = 0;
}
frame = postProcessFrame (frame);
*frames++ = frame; //left
++m_ic;
}
if (j > static_cast<unsigned> ((*m_cw)[0]))
{
m_state = Done;
}
return numFrames * sizeof (frame_t);
}
double const baud (12000.0 / m_nsps);
// fade out parameters (no fade out for tuning)
unsigned const i0 = m_tuning ? 999 * m_nsps : (m_symbols->size () - 0.017) * 4.0 * m_nsps;
unsigned const i1 = m_tuning ? 999 * m_nsps : m_symbols->size () * 4.0 * m_nsps;
for (unsigned i = 0; i < numFrames; ++i)
{
isym = m_tuning ? 0 : m_ic / (4.0 * m_nsps); //Actual fsample=48000
if (isym != m_isym0)
{
double toneFrequency = m_frequency + (*m_symbols)[isym] * baud;
m_dphi = m_twoPi * toneFrequency / m_frameRate;
m_isym0 = isym;
}
m_phi += m_dphi;
if (m_phi > m_twoPi)
{
m_phi -= m_twoPi;
}
if (m_ic > i0)
{
m_amp = 0.98 * m_amp;
}
if (m_ic > i1)
{
m_amp = 0.0;
}
frame_t frame (m_amp * std::sin (m_phi));
frame = postProcessFrame (frame);
*frames++ = frame; //left
++m_ic;
}
if (m_amp == 0.0) // TODO G4WJS: compare double with zero might not be wise
{
if ((*m_cw)[0] == 0)
{
// no CW ID to send
m_state = Done;
return numFrames * sizeof (frame_t);
}
m_phi = 0.0;
}
// done for this chunk - continue on next call
return numFrames * sizeof (frame_t);
}
case Done:
break;
}
Q_ASSERT (m_state == Done);
return 0;
}
Modulator::frame_t Modulator::postProcessFrame (frame_t frame) const
{
if (m_muted) // silent frame
{
return 0;
}
if (m_addNoise)
{
int i4 = m_fac * (gran () + frame * m_snr / 32768.0);
if (i4 > std::numeric_limits<frame_t>::max ())
{
i4 = std::numeric_limits<frame_t>::max ();
}
if (i4 < std::numeric_limits<frame_t>::min ())
{
i4 = std::numeric_limits<frame_t>::min ();
}
frame = i4;
}
return frame;
}

81
Modulator.hpp Normal file
View File

@ -0,0 +1,81 @@
#ifndef MODULATOR_HPP__
#define MODULATOR_HPP__
#include <vector>
#include <QIODevice>
#include <QScopedPointer>
//
// Input device that generates PCM audio frames that encode a message
// and an optional CW ID.
//
// Output can be muted while underway, preserving waveform timing when
// transmission is resumed.
//
class Modulator : public QIODevice
{
Q_OBJECT;
Q_PROPERTY (unsigned frequency READ frequency WRITE setFrequency);
Q_PROPERTY (bool tuning READ isTuning WRITE tune);
Q_PROPERTY (bool muted READ isMuted WRITE mute);
private:
Q_DISABLE_COPY (Modulator);
public:
Modulator (unsigned frameRate, unsigned periodLengthInSeconds, QObject * parent = 0);
bool isTuning () const {return m_tuning;}
Q_SLOT void tune (bool newState = true) {m_tuning = newState;}
bool isMuted () const {return m_muted;}
Q_SLOT void mute (bool newState = true) {m_muted = newState;}
unsigned frequency () const {return m_frequency;}
Q_SLOT void setFrequency (unsigned newFrequency) {m_frequency = newFrequency;}
bool open (std::vector<int> const * symbols, std::vector<int> const * cw, double framesPerSymbol, unsigned frequency, double dBSNR = 99.);
bool isSequential () const
{
return true;
}
protected:
qint64 readData (char * data, qint64 maxSize);
qint64 writeData (char const * /* data */, qint64 /* maxSize */)
{
return -1; // we don't consume data
}
private:
typedef short frame_t;
frame_t postProcessFrame (frame_t frame) const;
QScopedPointer<std::vector<int> const> m_symbols;
QScopedPointer<std::vector<int> const> m_cw;
static double const m_twoPi;
static unsigned const m_nspd; // CW ID WPM factor
int m_frameRate;
int m_period;
double m_nsps;
double m_frequency;
double m_snr;
enum {Idle, Active, Done} m_state;
bool m_tuning;
bool m_muted;
bool m_addNoise;
double m_phi;
double m_dphi;
double m_amp;
unsigned m_ic;
double m_fac;
unsigned m_isym0;
};
#endif

View File

@ -1,4 +1,4 @@
//--------------------------------------------------------------- MainWindow
//---------------------------------------------------------------- MainWindow
#include "mainwindow.h"
#include "ui_mainwindow.h"