1. Refactoring of code so as to move audio input from a separate thread to

the main GUI thread (thanks to G4WJS).

2.. Also, for the record, some example code for using QAudioInput instead 
of PortAudio.  This code is not presently active, and will need to be 
changed to accommodate the changes in #1, above.  But the basic ideas 
are here...


git-svn-id: svn+ssh://svn.code.sf.net/p/wsjt/wsjt/branches/wsjtx@3509 ab8295b8-cf94-4d9e-aec4-7959e3be5d79
This commit is contained in:
Joe Taylor 2013-07-30 00:51:42 +00:00
parent a90d9e2829
commit 3fcb73b107
8 changed files with 426 additions and 152 deletions

View File

@ -2,6 +2,8 @@
#include <QDebug> #include <QDebug>
#include <QSettings> #include <QSettings>
#include <portaudio.h> #include <portaudio.h>
#include <QAudioDeviceInfo>
#include <QAudioInput>
#define MAXDEVICES 100 #define MAXDEVICES 100
@ -35,6 +37,25 @@ void DevSetup::initDlg()
QString catPortDriver = settings.value("CATdriver","None").toString(); QString catPortDriver = settings.value("CATdriver","None").toString();
settings.endGroup(); settings.endGroup();
/*
QList<QAudioDeviceInfo> InDevices;
QList<QAudioDeviceInfo> OutDevices;
QAudioDeviceInfo deviceInfo;
InDevices = deviceInfo.availableDevices(QAudio::AudioInput);
OutDevices = deviceInfo.availableDevices(QAudio::AudioOutput);
foreach (const QAudioDeviceInfo &deviceInfo, InDevices) {
ui.comboBoxSndIn->addItem(deviceInfo.deviceName(),
qVariantFromValue(deviceInfo));
}
foreach (const QAudioDeviceInfo &deviceInfo, OutDevices) {
ui.comboBoxSndOut->addItem(deviceInfo.deviceName(),
qVariantFromValue(deviceInfo));
}
*/
int k,id; int k,id;
int numDevices=Pa_GetDeviceCount(); int numDevices=Pa_GetDeviceCount();

View File

@ -86,11 +86,11 @@ MainWindow::MainWindow(QSharedMemory *shdmem, QString *thekey, \
SLOT(doubleClickOnCall2(bool,bool))); SLOT(doubleClickOnCall2(bool,bool)));
setWindowTitle(Program_Title_Version); setWindowTitle(Program_Title_Version);
connect(&soundInThread, SIGNAL(readyForFFT(int)), connect(&m_soundInput, SIGNAL(readyForFFT(int)),
this, SLOT(dataSink(int))); this, SLOT(dataSink(int)));
connect(&soundInThread, SIGNAL(error(QString)), this, connect(&m_soundInput, SIGNAL(error(QString)), this,
SLOT(showSoundInError(QString))); SLOT(showSoundInError(QString)));
connect(&soundInThread, SIGNAL(status(QString)), this, connect(&m_soundInput, SIGNAL(status(QString)), this,
SLOT(showStatusMessage(QString))); SLOT(showStatusMessage(QString)));
createStatusBar(); createStatusBar();
@ -302,13 +302,12 @@ MainWindow::MainWindow(QSharedMemory *shdmem, QString *thekey, \
watcher2 = new QFutureWatcher<void>; watcher2 = new QFutureWatcher<void>;
connect(watcher2, SIGNAL(finished()),this,SLOT(diskWriteFinished())); connect(watcher2, SIGNAL(finished()),this,SLOT(diskWriteFinished()));
soundInThread.setInputDevice(m_paInDevice); m_soundInput.start(m_paInDevice);
soundInThread.start(QThread::HighestPriority);
soundOutThread.setOutputDevice(m_paOutDevice); soundOutThread.setOutputDevice(m_paOutDevice);
soundOutThread.setTxFreq(m_txFreq); soundOutThread.setTxFreq(m_txFreq);
soundOutThread.setTune(false); soundOutThread.setTune(false);
m_monitoring=!m_monitorStartOFF; // Start with Monitoring ON/OFF m_monitoring=!m_monitorStartOFF; // Start with Monitoring ON/OFF
soundInThread.setMonitoring(m_monitoring); m_soundInput.setMonitoring(m_monitoring);
m_diskData=false; m_diskData=false;
// Create "m_worked", a dictionary of all calls in wsjtx.log // Create "m_worked", a dictionary of all calls in wsjtx.log
@ -373,10 +372,6 @@ MainWindow::MainWindow(QSharedMemory *shdmem, QString *thekey, \
MainWindow::~MainWindow() MainWindow::~MainWindow()
{ {
writeSettings(); writeSettings();
if (soundInThread.isRunning()) {
soundInThread.quit();
soundInThread.wait(3000);
}
if (soundOutThread.isRunning()) { if (soundOutThread.isRunning()) {
soundOutThread.quitExecution=true; soundOutThread.quitExecution=true;
soundOutThread.wait(3000); soundOutThread.wait(3000);
@ -712,7 +707,7 @@ void MainWindow::dataSink(int k)
watcher2->setFuture(*future2); watcher2->setFuture(*future2);
} }
} }
soundInThread.m_dataSinkBusy=false; // m_soundInput.m_dataSinkBusy=false;
} }
void MainWindow::showSoundInError(const QString& errorMsg) void MainWindow::showSoundInError(const QString& errorMsg)
@ -832,10 +827,8 @@ void MainWindow::on_actionDeviceSetup_triggered() //Setup Dialog
m_After73=dlg.m_After73; m_After73=dlg.m_After73;
if(dlg.m_restartSoundIn) { if(dlg.m_restartSoundIn) {
soundInThread.quit(); m_soundInput.stop();
soundInThread.wait(1000); m_soundInput.start(m_paInDevice);
soundInThread.setInputDevice(m_paInDevice);
soundInThread.start(QThread::HighestPriority);
} }
if(dlg.m_restartSoundOut) { if(dlg.m_restartSoundOut) {
@ -870,7 +863,7 @@ void MainWindow::on_actionDeviceSetup_triggered() //Setup Dialog
void MainWindow::on_monitorButton_clicked() //Monitor void MainWindow::on_monitorButton_clicked() //Monitor
{ {
m_monitoring=true; m_monitoring=true;
soundInThread.setMonitoring(true); m_soundInput.setMonitoring(true);
m_diskData=false; m_diskData=false;
} }
@ -1132,7 +1125,7 @@ void MainWindow::OnExit()
void MainWindow::on_stopButton_clicked() //stopButton void MainWindow::on_stopButton_clicked() //stopButton
{ {
m_monitoring=false; m_monitoring=false;
soundInThread.setMonitoring(m_monitoring); m_soundInput.setMonitoring(m_monitoring);
m_loopall=false; m_loopall=false;
} }
@ -1173,7 +1166,7 @@ void MainWindow::on_actionWide_Waterfall_triggered() //Display Waterfalls
void MainWindow::on_actionOpen_triggered() //Open File void MainWindow::on_actionOpen_triggered() //Open File
{ {
m_monitoring=false; m_monitoring=false;
soundInThread.setMonitoring(m_monitoring); m_soundInput.setMonitoring(m_monitoring);
QString fname; QString fname;
fname=QFileDialog::getOpenFileName(this, "Open File", m_path, fname=QFileDialog::getOpenFileName(this, "Open File", m_path,
"WSJT Files (*.wav)"); "WSJT Files (*.wav)");
@ -1787,7 +1780,7 @@ void MainWindow::guiUpdate()
signalMeter->setValue(0); signalMeter->setValue(0);
m_monitoring=false; m_monitoring=false;
soundInThread.setMonitoring(false); m_soundInput.setMonitoring(false);
btxok=true; btxok=true;
m_transmitting=true; m_transmitting=true;
ui->pbTxMode->setEnabled(false); ui->pbTxMode->setEnabled(false);
@ -1907,7 +1900,7 @@ void MainWindow::startTx2()
soundOutThread.start(QThread::HighestPriority); soundOutThread.start(QThread::HighestPriority);
signalMeter->setValue(0); signalMeter->setValue(0);
m_monitoring=false; m_monitoring=false;
soundInThread.setMonitoring(false); m_soundInput.setMonitoring(false);
btxok=true; btxok=true;
m_transmitting=true; m_transmitting=true;
ui->pbTxMode->setEnabled(false); ui->pbTxMode->setEnabled(false);
@ -1927,7 +1920,7 @@ void MainWindow::stopTx()
lab1->setText(""); lab1->setText("");
ptt0Timer->start(200); //Sequencer delay ptt0Timer->start(200); //Sequencer delay
m_monitoring=true; m_monitoring=true;
soundInThread.setMonitoring(true); m_soundInput.setMonitoring(true);
} }
void MainWindow::stopTx2() void MainWindow::stopTx2()
@ -2534,7 +2527,7 @@ void MainWindow::on_actionJT9_1_triggered()
m_TRperiod=60; m_TRperiod=60;
m_nsps=6912; m_nsps=6912;
m_hsymStop=173; m_hsymStop=173;
soundInThread.setPeriod(m_TRperiod,m_nsps); m_soundInput.setPeriod(m_TRperiod,m_nsps);
soundOutThread.setPeriod(m_TRperiod,m_nsps); soundOutThread.setPeriod(m_TRperiod,m_nsps);
lab3->setStyleSheet("QLabel{background-color: #ff6ec7}"); lab3->setStyleSheet("QLabel{background-color: #ff6ec7}");
lab3->setText(m_mode); lab3->setText(m_mode);
@ -2553,7 +2546,7 @@ void MainWindow::on_actionJT65_triggered()
m_TRperiod=60; m_TRperiod=60;
m_nsps=6912; //For symspec only m_nsps=6912; //For symspec only
m_hsymStop=173; m_hsymStop=173;
soundInThread.setPeriod(m_TRperiod,m_nsps); m_soundInput.setPeriod(m_TRperiod,m_nsps);
soundOutThread.setPeriod(m_TRperiod,m_nsps); soundOutThread.setPeriod(m_TRperiod,m_nsps);
lab3->setStyleSheet("QLabel{background-color: #ffff00}"); lab3->setStyleSheet("QLabel{background-color: #ffff00}");
lab3->setText(m_mode); lab3->setText(m_mode);
@ -2572,7 +2565,7 @@ void MainWindow::on_actionJT9_JT65_triggered()
m_TRperiod=60; m_TRperiod=60;
m_nsps=6912; m_nsps=6912;
m_hsymStop=173; m_hsymStop=173;
soundInThread.setPeriod(m_TRperiod,m_nsps); m_soundInput.setPeriod(m_TRperiod,m_nsps);
soundOutThread.setPeriod(m_TRperiod,m_nsps); soundOutThread.setPeriod(m_TRperiod,m_nsps);
lab3->setStyleSheet("QLabel{background-color: #ffa500}"); lab3->setStyleSheet("QLabel{background-color: #ffa500}");
lab3->setText(m_mode); lab3->setText(m_mode);

View File

@ -337,7 +337,7 @@ private:
QDateTime m_dateTimeQSO; QDateTime m_dateTimeQSO;
SoundInThread soundInThread; //Instantiate the audio threads SoundInput m_soundInput; //Instantiate the audio objects
SoundOutThread soundOutThread; SoundOutThread soundOutThread;
QSharedMemory *mem_jt9; QSharedMemory *mem_jt9;
// Multiple instances: // Multiple instances:

View File

@ -33,18 +33,10 @@ extern struct {
} jt9com_; } jt9com_;
} }
typedef struct
{
int kin; //Parameters sent to/from the portaudio callback function
int ncall;
bool bzero;
bool monitoring;
} paUserData;
//--------------------------------------------------------------- a2dCallback //--------------------------------------------------------------- a2dCallback
extern "C" int a2dCallback( const void *inputBuffer, void *outputBuffer, int a2dCallback( const void *inputBuffer, void * /* outputBuffer */,
unsigned long framesToProcess, unsigned long framesToProcess,
const PaStreamCallbackTimeInfo* timeInfo, const PaStreamCallbackTimeInfo * /* timeInfo */,
PaStreamCallbackFlags statusFlags, PaStreamCallbackFlags statusFlags,
void *userData ) void *userData )
@ -53,10 +45,7 @@ extern "C" int a2dCallback( const void *inputBuffer, void *outputBuffer,
// that could mess up the system like calling malloc() or free(). // that could mess up the system like calling malloc() or free().
{ {
paUserData *udata=(paUserData*)userData; SoundInput::CallbackData * udata = reinterpret_cast<SoundInput::CallbackData *>(userData);
(void) outputBuffer; //Prevent unused variable warnings.
(void) timeInfo;
(void) userData;
int nbytes,k; int nbytes,k;
udata->ncall++; udata->ncall++;
@ -79,22 +68,31 @@ extern "C" int a2dCallback( const void *inputBuffer, void *outputBuffer,
return paContinue; return paContinue;
} }
void SoundInThread::run() //SoundInThread::run() SoundInput::SoundInput()
: m_inStream(0),
m_dataSinkBusy(false),
m_TRperiod(60),
m_nsps(6912),
m_monitoring(false),
m_intervalTimer(this)
{ {
quitExecution = false; connect(&m_intervalTimer, &QTimer::timeout, this, &SoundInput::intervalNotify);
}
void SoundInput::start(qint32 device)
{
stop();
//---------------------------------------------------- Soundcard Setup //---------------------------------------------------- Soundcard Setup
PaError paerr; PaError paerr;
PaStreamParameters inParam; PaStreamParameters inParam;
PaStream *inStream;
paUserData udata;
udata.kin=0; //Buffer pointer m_callbackData.kin=0; //Buffer pointer
udata.ncall=0; //Number of callbacks m_callbackData.ncall=0; //Number of callbacks
udata.bzero=false; //Flag to request reset of kin m_callbackData.bzero=false; //Flag to request reset of kin
udata.monitoring=m_monitoring; m_callbackData.monitoring=m_monitoring;
inParam.device=m_nDevIn; //### Input Device Number ### inParam.device=device; //### Input Device Number ###
inParam.channelCount=1; //Number of analog channels inParam.channelCount=1; //Number of analog channels
inParam.sampleFormat=paInt16; //Get i*2 from Portaudio inParam.sampleFormat=paInt16; //Get i*2 from Portaudio
inParam.suggestedLatency=0.05; inParam.suggestedLatency=0.05;
@ -106,7 +104,7 @@ void SoundInThread::run() //SoundInThread::run()
// return; // return;
} }
qDebug() << ""; qDebug() << "";
paerr=Pa_OpenStream(&inStream, //Input stream paerr=Pa_OpenStream(&m_inStream, //Input stream
&inParam, //Input parameters &inParam, //Input parameters
NULL, //No output parameters NULL, //No output parameters
12000.0, //Sample rate 12000.0, //Sample rate
@ -114,95 +112,75 @@ void SoundInThread::run() //SoundInThread::run()
// paClipOff+paDitherOff, //No clipping or dithering // paClipOff+paDitherOff, //No clipping or dithering
paClipOff, //No clipping paClipOff, //No clipping
a2dCallback, //Input callback routine a2dCallback, //Input callback routine
&udata); //userdata &m_callbackData); //userdata
paerr=Pa_StartStream(m_inStream);
paerr=Pa_StartStream(inStream);
if(paerr<0) { if(paerr<0) {
emit error("Failed to start audio input stream."); emit error("Failed to start audio input stream.");
return; return;
} }
m_ntr0 = 99; // initial value higher than any expected
m_nBusy = 0;
m_intervalTimer.start(100);
m_ms0 = QDateTime::currentMSecsSinceEpoch();
m_nsps0 = 0;
}
bool qe = quitExecution; void SoundInput::intervalNotify()
static int ntr0=99; {
int k=0; m_callbackData.monitoring=m_monitoring;
int nsec;
int ntr;
int nBusy=0;
int nstep0=0;
int nsps0=0;
qint64 ms0 = QDateTime::currentMSecsSinceEpoch();
//---------------------------------------------- Soundcard input loop
while (!qe) {
qe = quitExecution;
if (qe) break;
udata.monitoring=m_monitoring;
qint64 ms = QDateTime::currentMSecsSinceEpoch(); qint64 ms = QDateTime::currentMSecsSinceEpoch();
m_SamFacIn=1.0; m_SamFacIn=1.0;
if(udata.ncall>100) { if(m_callbackData.ncall>100) {
m_SamFacIn=udata.ncall*FRAMES_PER_BUFFER*1000.0/(12000.0*(ms-ms0-50)); m_SamFacIn=m_callbackData.ncall*FRAMES_PER_BUFFER*1000.0/(12000.0*(ms-m_ms0-50));
} }
ms=ms % 86400000; ms=ms % 86400000;
nsec = ms/1000; // Time according to this computer int nsec = ms/1000; // Time according to this computer
ntr = nsec % m_TRperiod; int ntr = nsec % m_TRperiod;
// Reset buffer pointer and symbol number at start of minute // Reset buffer pointer and symbol number at start of minute
if(ntr < ntr0 or !m_monitoring or m_nsps!=nsps0) { if(ntr < m_ntr0 or !m_monitoring or m_nsps!=m_nsps0) {
nstep0=0; m_nstep0=0;
nsps0=m_nsps; m_nsps0=m_nsps;
udata.bzero=true; m_callbackData.bzero=true;
} }
k=udata.kin; int k=m_callbackData.kin;
if(m_monitoring) { if(m_monitoring) {
int kstep=m_nsps/2; int kstep=m_nsps/2;
// m_step=k/kstep; // m_step=k/kstep;
m_step=(k-1)/kstep; m_step=(k-1)/kstep;
if(m_step != nstep0) { if(m_step != m_nstep0) {
if(m_dataSinkBusy) { if(m_dataSinkBusy) {
nBusy++; m_nBusy++;
} else { } else {
// m_dataSinkBusy=true; // m_dataSinkBusy=true;
// emit readyForFFT(k); //Signal to compute new FFTs // emit readyForFFT(k); //Signal to compute new FFTs
emit readyForFFT(k-1); //Signal to compute new FFTs emit readyForFFT(k-1); //Signal to compute new FFTs
} }
nstep0=m_step; m_nstep0=m_step;
} }
} }
msleep(100); m_ntr0=ntr;
ntr0=ntr;
}
Pa_StopStream(inStream);
Pa_CloseStream(inStream);
} }
void SoundInThread::setInputDevice(int n) //setInputDevice() SoundInput::~SoundInput()
{ {
if (isRunning()) return; if (m_inStream)
this->m_nDevIn=n;
}
void SoundInThread::quit() //quit()
{ {
quitExecution = true; Pa_CloseStream(m_inStream), m_inStream = 0;
}
} }
void SoundInThread::setMonitoring(bool b) //setMonitoring() void SoundInput::stop()
{
m_intervalTimer.stop();
if (m_inStream)
{
Pa_StopStream(m_inStream);
Pa_CloseStream(m_inStream), m_inStream = 0;
}
}
void SoundInput::setMonitoring(bool b)
{ {
m_monitoring = b; m_monitoring = b;
} }
void SoundInThread::setPeriod(int ntrperiod, int nsps)
{
m_TRperiod=ntrperiod;
m_nsps=nsps;
}
int SoundInThread::mstep()
{
return m_step;
}
double SoundInThread::samFacIn()
{
return m_SamFacIn;
}

View File

@ -1,34 +1,32 @@
#ifndef SOUNDIN_H #ifndef SOUNDIN_H
#define SOUNDIN_H #define SOUNDIN_H
#include <portaudio.h>
#include <QtCore> #include <QtCore>
#include <QScopedPointer>
#include <QDebug> #include <QDebug>
extern "C" int a2dCallback( const void *, void *, unsigned long, PaStreamCallbackTimeInfo const *, PaStreamCallbackFlags, void *);
// Thread gets audio data from soundcard and signals when a buffer of // Gets audio data from soundcard and signals when a buffer of
// specified size is available. // specified size is available.
class SoundInThread : public QThread class SoundInput : public QObject
{ {
Q_OBJECT Q_OBJECT
bool quitExecution; // if true, thread exits gracefully
protected:
virtual void run();
public: public:
bool m_dataSinkBusy; SoundInput();
~SoundInput();
SoundInThread():
quitExecution(false),
m_dataSinkBusy(false)
{
}
void setInputDevice(qint32 n);
void setMonitoring(bool b); void setMonitoring(bool b);
void setPeriod(int ntrperiod, int nsps); void setPeriod(int ntrperiod, int nsps) /* this can be called while processing samples */
int mstep(); {
double samFacIn(); m_TRperiod=ntrperiod;
m_nsps=nsps;
}
int mstep() const {return m_step;}
double samFacIn() const {return m_SamFacIn;}
signals: signals:
void readyForFFT(int k); void readyForFFT(int k);
@ -36,15 +34,35 @@ signals:
void status(const QString& message); void status(const QString& message);
public slots: public slots:
void quit(); void start(qint32 device);
void intervalNotify();
void stop();
private: private:
PaStream * m_inStream;
bool m_dataSinkBusy;
double m_SamFacIn; //(Input sample rate)/12000.0 double m_SamFacIn; //(Input sample rate)/12000.0
qint32 m_step; qint32 m_step;
qint32 m_nDevIn;
qint32 m_TRperiod; qint32 m_TRperiod;
qint32 m_TRperiod0; qint32 m_TRperiod0;
qint32 m_nsps; qint32 m_nsps;
bool m_monitoring; bool m_monitoring;
qint64 m_ms0;
int m_ntr0;
int m_nBusy;
int m_nstep0;
int m_nsps0;
QTimer m_intervalTimer;
struct CallbackData
{
int kin; //Parameters sent to/from the portaudio callback function
int ncall;
bool bzero;
bool monitoring;
} m_callbackData;
friend int a2dCallback(void const *, void *, unsigned long, PaStreamCallbackTimeInfo const *, PaStreamCallbackFlags, void *);
}; };
#endif // SOUNDIN_H #endif // SOUNDIN_H

210
soundin_1.cpp Normal file
View File

@ -0,0 +1,210 @@
#include "soundin.h"
#include <stdexcept>
#define FRAMES_PER_BUFFER 1024
//#define NSMAX 1365
#define NSMAX 6827
#define NTMAX 120
extern "C" {
#include <portaudio.h>
extern struct {
float ss[184*NSMAX]; //This is "common/jt9com/..." in fortran
float savg[NSMAX];
// float c0[2*NTMAX*1500];
short int d2[NTMAX*12000];
int nutc; //UTC as integer, HHMM
int ndiskdat; //1 ==> data read from *.wav file
int ntrperiod; //TR period (seconds)
int mousefqso; //User-selected QSO freq (kHz)
int newdat; //1 ==> new data, must do long FFT
int npts8; //npts in c0() array
int nfa; //Low decode limit (Hz)
int nfb; //High decode limit (Hz)
int ntol; //+/- decoding range around fQSO (Hz)
int kin;
int nzhsym;
int nsave;
int nagain;
int ndepth;
int ntxmode;
int nmode;
char datetime[20];
} jt9com_;
}
QString reportAudioError(QAudio::Error audioError)
{
switch (audioError) {
case QAudio::NoError: Q_ASSERT(false);
case QAudio::OpenError: return QObject::tr(
"An error opening the audio device has occurred.");
case QAudio::IOError: return QObject::tr(
"An error occurred during read/write of audio device.");
case QAudio::UnderrunError: return QObject::tr(
"Audio data not being fed to the audio device fast enough.");
case QAudio::FatalError: return QObject::tr(
"Non-recoverable error, audio device not usable at this time.");
}
Q_ASSERT(false);
return "";
}
typedef struct
{
int kin; //Parameters sent to/from the portaudio callback function
int ncall;
bool bzero;
bool monitoring;
} paUserData;
void SoundInThread::run() //SoundInThread::run()
{
quitExecution = false;
//---------------------------------------------------- Soundcard Setup
quitExecutionMutex.lock();
quitExecution = false;
quitExecutionMutex.unlock();
//### Temporary: hardwired device selection
QAudioDeviceInfo DeviceInfo;
QList<QAudioDeviceInfo> m_InDevices;
QAudioDeviceInfo m_InDeviceInfo;
m_InDevices = DeviceInfo.availableDevices(QAudio::AudioInput);
inputDevice = m_InDevices.at(0);
//###
const char* pcmCodec = "audio/pcm";
QAudioFormat audioFormat = inputDevice.preferredFormat();
audioFormat.setChannelCount(1);
audioFormat.setCodec(pcmCodec);
audioFormat.setSampleRate(12000);
audioFormat.setSampleType(QAudioFormat::SignedInt);
audioFormat.setSampleSize(16);
if (!audioFormat.isValid()) {
emit error(tr("Requested audio format is not available."));
return;
}
QAudioInput audioInput(inputDevice, audioFormat);
if (audioInput.error() != QAudio::NoError) {
emit error(reportAudioError(audioInput.error()));
return;
}
QIODevice* stream = audioInput.start();
bool qe = quitExecution;
static int ntr0=99;
int k=0;
int nsec;
int ntr;
int nBusy=0;
int nstep0=0;
int nsps0=0;
qint16 buf0[4096];
//---------------------------------------------- Soundcard input loop
while (!qe) {
quitExecutionMutex.lock();
qe = quitExecution;
quitExecutionMutex.unlock();
if (qe) break;
// Error checking...
if (audioInput.error() != QAudio::NoError) {
emit error(reportAudioError(audioInput.error()));
return;
}
// udata.monitoring=m_monitoring;
qint64 ms = QDateTime::currentMSecsSinceEpoch();
ms=ms % 86400000;
nsec = ms/1000; // Time according to this computer
ntr = nsec % m_TRperiod;
// Reset buffer pointer and symbol number at start of minute
if(ntr < ntr0 or !m_monitoring or m_nsps!=nsps0) {
nstep0=0;
nsps0=m_nsps;
// udata.bzero=true;
k=0;
}
// k=udata.kin;
// How many new samples have been acquired?
const qint32 bytesReady = audioInput.bytesReady();
Q_ASSERT(bytesReady >= 0);
Q_ASSERT(bytesReady % 2 == 0);
if (bytesReady == 0) {
msleep(50);
continue;
}
// Get the new samples
qint32 bytesRead;
bytesRead = stream->read((char*)buf0, bytesReady);
Q_ASSERT(bytesRead <= bytesReady);
if (bytesRead < 0) {
emit error(tr("audio stream QIODevice::read returned -1."));
return;
}
Q_ASSERT(bytesRead % 2 == 0);
// memcpy(jt9com_.d2[k],buf0,bytesRead);
// k+=bytesRead/2;
for(int i=0; i<bytesRead/2; i++) {
jt9com_.d2[k++]=buf0[i];
}
if(m_monitoring) {
int kstep=m_nsps/2;
m_step=(k-1)/kstep;
if(m_step != nstep0) {
if(m_dataSinkBusy) {
nBusy++;
} else {
emit readyForFFT(k-1); //Signal to compute new FFTs
}
nstep0=m_step;
}
}
msleep(100);
ntr0=ntr;
}
// Pa_StopStream(inStream);
// Pa_CloseStream(inStream);
}
void SoundInThread::setInputDevice(int n) //setInputDevice()
{
if (isRunning()) return;
this->m_nDevIn=n;
}
void SoundInThread::quit() //quit()
{
quitExecution = true;
}
void SoundInThread::setMonitoring(bool b) //setMonitoring()
{
m_monitoring = b;
}
void SoundInThread::setPeriod(int ntrperiod, int nsps)
{
m_TRperiod=ntrperiod;
m_nsps=nsps;
}
int SoundInThread::mstep()
{
return m_step;
}

53
soundin_1.h Normal file
View File

@ -0,0 +1,53 @@
#ifndef SOUNDIN_H
#define SOUNDIN_H
#include <QtCore>
#include <QDebug>
#include <QAudioDeviceInfo>
#include <QAudioInput>
#include <valarray>
// Thread gets audio data from soundcard and signals when a buffer of
// specified size is available.
class SoundInThread : public QThread
{
Q_OBJECT
bool quitExecution; // if true, thread exits gracefully
QMutex quitExecutionMutex; // protects the quitExecution variable
QAudioDeviceInfo inputDevice; // audioinput device name
protected:
virtual void run();
public:
bool m_dataSinkBusy;
SoundInThread():
quitExecution(false),
m_dataSinkBusy(false)
{
}
void setInputDevice(qint32 n);
void setMonitoring(bool b);
void setPeriod(int ntrperiod, int nsps);
int mstep();
signals:
void readyForFFT(int k);
void error(const QString& message);
void status(const QString& message);
public slots:
void quit();
private:
qint32 m_step;
qint32 m_nDevIn;
qint32 m_TRperiod;
qint32 m_TRperiod0;
qint32 m_nsps;
bool m_monitoring;
};
#endif // SOUNDIN_H

View File

@ -10,6 +10,7 @@ CONFIG += thread
#CONFIG += console #CONFIG += console
TARGET = wsjtx TARGET = wsjtx
#DESTDIR = ../qt4_install
DESTDIR = ../wsjtx_install DESTDIR = ../wsjtx_install
VERSION = 1.1 VERSION = 1.1
TEMPLATE = app TEMPLATE = app