1. Fix a longstanding (and evidently latent) bug in widegraph.cpp.

2. Add basic proof-of-concept code that uses QAudioInput instead of
PortAudio for sound input.  By default, this test code is not active,
and it compiles using PortAudio.  To compile using QAudio, uncomment
the line

#DEFINES += QAUDIO_INPUT

in wsjtx.pro.  Note that device selection in the QAudio code is presently
hard-wired to use the default input device.  You can change this 
choice on line 267 in soundin.cpp.



git-svn-id: svn+ssh://svn.code.sf.net/p/wsjt/wsjt/branches/wsjtx@3510 ab8295b8-cf94-4d9e-aec4-7959e3be5d79
This commit is contained in:
Joe Taylor 2013-07-30 20:36:14 +00:00
parent 4e8a3f54c9
commit d45f47caa0
5 changed files with 279 additions and 4 deletions

View File

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

View File

@ -1,3 +1,4 @@
#ifndef QAUDIO_INPUT
#include "soundin.h"
#include <stdexcept>
@ -184,3 +185,203 @@ void SoundInput::setMonitoring(bool b)
{
m_monitoring = b;
}
#else // QAUDIO_INPUT
#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 "";
}
SoundInput::SoundInput()
: m_dataSinkBusy(false),
m_TRperiod(60),
m_nsps(6912),
m_monitoring(false),
m_intervalTimer(this)
{
connect(&m_intervalTimer, &QTimer::timeout, this, &SoundInput::intervalNotify);
}
void SoundInput::start(qint32 device)
{
stop();
//---------------------------------------------------- Soundcard Setup
m_callbackData.kin=0; //Buffer pointer
m_callbackData.ncall=0; //Number of callbacks
m_callbackData.bzero=false; //Flag to request reset of kin
m_callbackData.monitoring=m_monitoring;
//### 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;
}
audioInput = new QAudioInput(inputDevice, audioFormat);
// audioInput2=audioInput;
if (audioInput->error() != QAudio::NoError) {
emit error(reportAudioError(audioInput->error()));
return;
}
stream = audioInput->start();
m_ntr0 = 99; // initial value higher than any expected
m_nBusy = 0;
m_intervalTimer.start(100);
m_ms0 = QDateTime::currentMSecsSinceEpoch();
m_nsps0 = 0;
}
void SoundInput::intervalNotify()
{
m_callbackData.monitoring=m_monitoring;
qint64 ms = QDateTime::currentMSecsSinceEpoch();
ms=ms % 86400000;
int nsec = ms/1000; // Time according to this computer
int ntr = nsec % m_TRperiod;
static int k=0;
// Reset buffer pointer and symbol number at start of minute
if(ntr < m_ntr0 or !m_monitoring or m_nsps!=m_nsps0) {
m_nstep0=0;
m_nsps0=m_nsps;
m_callbackData.bzero=true;
k=0;
}
// int k=m_callbackData.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);
return;
}
// Get the new samples
qint32 bytesRead;
qint16 buf0[4096];
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/kstep;
m_step=(k-1)/kstep;
if(m_step != m_nstep0) {
if(m_dataSinkBusy) {
m_nBusy++;
} else {
// m_dataSinkBusy=true;
// emit readyForFFT(k); //Signal to compute new FFTs
emit readyForFFT(k-1); //Signal to compute new FFTs
}
m_nstep0=m_step;
}
}
m_ntr0=ntr;
}
SoundInput::~SoundInput()
{
/*
if (m_inStream)
{
Pa_CloseStream(m_inStream), m_inStream = 0;
}
*/
}
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;
}
#endif // QAUDIO_INPUT

View File

@ -1,3 +1,4 @@
#ifndef QAUDIO_INPUT
#ifndef SOUNDIN_H
#define SOUNDIN_H
@ -66,3 +67,72 @@ private:
friend int a2dCallback(void const *, void *, unsigned long, PaStreamCallbackTimeInfo const *, PaStreamCallbackFlags, void *);
};
#endif // SOUNDIN_H
#else // QAUDIO_INPUT
#ifndef SOUNDIN_H
#define SOUNDIN_H
#include <QtCore>
#include <QScopedPointer>
#include <QDebug>
#include <QAudioDeviceInfo>
#include <QAudioInput>
// Gets audio data from soundcard and signals when a buffer of
// specified size is available.
class SoundInput : public QObject
{
Q_OBJECT
public:
SoundInput();
~SoundInput();
void setMonitoring(bool b);
void setPeriod(int ntrperiod, int nsps) /* this can be called while processing samples */
{
m_TRperiod=ntrperiod;
m_nsps=nsps;
}
int mstep() const {return m_step;}
double samFacIn() const {return m_SamFacIn;}
signals:
void readyForFFT(int k);
void error(const QString& message);
void status(const QString& message);
public slots:
void start(qint32 device);
void intervalNotify();
void stop();
private:
bool m_dataSinkBusy;
double m_SamFacIn; //(Input sample rate)/12000.0
qint32 m_step;
qint32 m_TRperiod;
qint32 m_TRperiod0;
qint32 m_nsps;
bool m_monitoring;
qint64 m_ms0;
int m_ntr0;
int m_nBusy;
int m_nstep0;
int m_nsps0;
QTimer m_intervalTimer;
QAudioDeviceInfo inputDevice; // audioinput device name
QAudioInput* audioInput;
QIODevice* stream;
struct CallbackData
{
int kin; //Parameters sent to/from the portaudio callback function
int ncall;
bool bzero;
bool monitoring;
} m_callbackData;
};
#endif // SOUNDIN_H
#endif // QAUDIO_INPUT

View File

@ -2,6 +2,8 @@
#include "ui_widegraph.h"
#include "commons.h"
#define MAX_SCREENSIZE 2048
WideGraph::WideGraph(QWidget *parent) :
QDialog(parent),
ui(new Ui::WideGraph)
@ -10,7 +12,7 @@ WideGraph::WideGraph(QWidget *parent) :
this->setWindowFlags(Qt::Dialog);
this->installEventFilter(parent); //Installing the filter
ui->widePlot->setCursor(Qt::CrossCursor);
this->setMaximumWidth(2048);
this->setMaximumWidth(MAX_SCREENSIZE);
this->setMaximumHeight(880);
ui->widePlot->setMaximumHeight(800);
ui->widePlot->m_bCurrent=false;
@ -85,7 +87,7 @@ void WideGraph::dataSink2(float s[], float df3, int ihsym,
int ndiskdata)
{
static float splot[NSMAX];
static float swide[2048];
static float swide[MAX_SCREENSIZE];
int nbpp = ui->widePlot->binsPerPixel();
static int n=0;
@ -105,6 +107,7 @@ void WideGraph::dataSink2(float s[], float df3, int ihsym,
n=0;
int i=int(ui->widePlot->startFreq()/df3 + 0.5);
int jz=5000.0/(nbpp*df3);
if(jz>MAX_SCREENSIZE) jz=MAX_SCREENSIZE;
for (int j=0; j<jz; j++) {
float sum=0;
for (int k=0; k<nbpp; k++) {

View File

@ -4,7 +4,7 @@
#
#-------------------------------------------------
QT += core gui network
QT += core gui network multimedia
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
CONFIG += thread
#CONFIG += console
@ -16,6 +16,7 @@ VERSION = 1.1
TEMPLATE = app
#DEFINES = QT4
DEFINES = QT5
#DEFINES += QAUDIO_INPUT
win32 {
DEFINES += WIN32