2012-05-22 13:09:48 -04:00
|
|
|
#include "soundin.h"
|
|
|
|
#include <stdexcept>
|
|
|
|
|
|
|
|
#define FRAMES_PER_BUFFER 1024
|
2012-10-03 11:42:13 -04:00
|
|
|
#define NSMAX 22000
|
2012-05-22 13:09:48 -04:00
|
|
|
|
|
|
|
extern "C" {
|
|
|
|
#include <portaudio.h>
|
|
|
|
extern struct {
|
2012-10-16 19:32:15 -04:00
|
|
|
float ss[184*NSMAX]; //This is "common/jt9com/..." in fortran
|
2012-09-28 19:59:50 -04:00
|
|
|
float savg[NSMAX];
|
2012-11-21 12:42:53 -05:00
|
|
|
float c0[2*1800*1500];
|
2012-10-16 19:32:15 -04:00
|
|
|
short int d2[1800*12000];
|
2012-09-25 12:04:38 -04:00
|
|
|
int nutc; //UTC as integer, HHMM
|
2012-10-16 19:32:15 -04:00
|
|
|
int ndiskdat; //1 ==> data read from *.wav file
|
2012-09-25 16:26:12 -04:00
|
|
|
int ntrperiod; //TR period (seconds)
|
2012-09-25 12:04:38 -04:00
|
|
|
int mousefqso; //User-selected QSO freq (kHz)
|
|
|
|
int newdat; //1 ==> new data, must do long FFT
|
2012-10-19 15:26:07 -04:00
|
|
|
int npts8; //npts in c0() array
|
2012-11-21 12:42:53 -05:00
|
|
|
int nfa; //Low decode limit (Hz)
|
|
|
|
int nfb; //High decode limit (Hz)
|
2012-09-25 12:04:38 -04:00
|
|
|
int ntol; //+/- decoding range around fQSO (Hz)
|
2012-07-04 12:27:57 -04:00
|
|
|
int kin;
|
2012-11-19 13:23:39 -05:00
|
|
|
int nzhsym;
|
2012-11-21 12:42:53 -05:00
|
|
|
int nsave;
|
|
|
|
int nagain;
|
|
|
|
int ndepth;
|
|
|
|
int nrxlog;
|
|
|
|
int nfsample;
|
|
|
|
char datetime[20];
|
2012-10-03 11:42:13 -04:00
|
|
|
} jt9com_;
|
2012-05-22 13:09:48 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
int kin; //Parameters sent to/from the portaudio callback function
|
2012-11-13 15:23:03 -05:00
|
|
|
int ncall;
|
2012-05-22 13:09:48 -04:00
|
|
|
bool bzero;
|
2012-11-01 15:54:40 -04:00
|
|
|
bool monitoring;
|
2012-05-22 13:09:48 -04:00
|
|
|
} paUserData;
|
|
|
|
|
|
|
|
//--------------------------------------------------------------- a2dCallback
|
|
|
|
extern "C" int a2dCallback( const void *inputBuffer, void *outputBuffer,
|
|
|
|
unsigned long framesToProcess,
|
|
|
|
const PaStreamCallbackTimeInfo* timeInfo,
|
|
|
|
PaStreamCallbackFlags statusFlags,
|
|
|
|
void *userData )
|
|
|
|
|
|
|
|
// This routine called by the PortAudio engine when samples are available.
|
|
|
|
// It may be called at interrupt level, so don't do anything
|
|
|
|
// that could mess up the system like calling malloc() or free().
|
|
|
|
|
|
|
|
{
|
|
|
|
paUserData *udata=(paUserData*)userData;
|
|
|
|
(void) outputBuffer; //Prevent unused variable warnings.
|
|
|
|
(void) timeInfo;
|
|
|
|
(void) userData;
|
2012-07-04 13:48:57 -04:00
|
|
|
int nbytes,k;
|
2012-05-22 13:09:48 -04:00
|
|
|
|
2012-11-13 15:23:03 -05:00
|
|
|
udata->ncall++;
|
2012-05-22 13:09:48 -04:00
|
|
|
if( (statusFlags&paInputOverflow) != 0) {
|
|
|
|
qDebug() << "Input Overflow";
|
|
|
|
}
|
2012-07-04 12:27:57 -04:00
|
|
|
if(udata->bzero) { //Start of a new Rx sequence
|
2012-05-22 13:09:48 -04:00
|
|
|
udata->kin=0; //Reset buffer pointer
|
|
|
|
udata->bzero=false;
|
|
|
|
}
|
|
|
|
|
2012-07-05 12:16:03 -04:00
|
|
|
nbytes=2*framesToProcess; //Bytes per frame
|
2012-07-04 12:27:57 -04:00
|
|
|
k=udata->kin;
|
2012-11-01 15:54:40 -04:00
|
|
|
if(udata->monitoring) {
|
|
|
|
memcpy(&jt9com_.d2[k],inputBuffer,nbytes); //Copy all samples to d2
|
|
|
|
}
|
2012-05-22 13:09:48 -04:00
|
|
|
udata->kin += framesToProcess;
|
2012-10-03 11:42:13 -04:00
|
|
|
jt9com_.kin=udata->kin;
|
2012-07-04 12:27:57 -04:00
|
|
|
|
2012-05-22 13:09:48 -04:00
|
|
|
return paContinue;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SoundInThread::run() //SoundInThread::run()
|
|
|
|
{
|
|
|
|
quitExecution = false;
|
|
|
|
|
|
|
|
//---------------------------------------------------- Soundcard Setup
|
|
|
|
PaError paerr;
|
|
|
|
PaStreamParameters inParam;
|
|
|
|
PaStream *inStream;
|
|
|
|
paUserData udata;
|
|
|
|
|
|
|
|
udata.kin=0; //Buffer pointer
|
2012-11-13 15:23:03 -05:00
|
|
|
udata.ncall=0; //Number of callbacks
|
2012-05-22 13:09:48 -04:00
|
|
|
udata.bzero=false; //Flag to request reset of kin
|
2012-11-01 15:54:40 -04:00
|
|
|
udata.monitoring=m_monitoring;
|
2012-05-22 13:09:48 -04:00
|
|
|
|
|
|
|
inParam.device=m_nDevIn; //### Input Device Number ###
|
2012-07-04 12:27:57 -04:00
|
|
|
inParam.channelCount=1; //Number of analog channels
|
2012-07-05 12:16:03 -04:00
|
|
|
inParam.sampleFormat=paInt16; //Get i*2 from Portaudio
|
2012-05-22 13:09:48 -04:00
|
|
|
inParam.suggestedLatency=0.05;
|
|
|
|
inParam.hostApiSpecificStreamInfo=NULL;
|
|
|
|
|
2012-09-24 19:36:38 -04:00
|
|
|
paerr=Pa_IsFormatSupported(&inParam,NULL,12000.0);
|
2012-05-22 13:09:48 -04:00
|
|
|
if(paerr<0) {
|
|
|
|
emit error("PortAudio says requested soundcard format not supported.");
|
|
|
|
// return;
|
|
|
|
}
|
2013-03-24 10:05:31 -04:00
|
|
|
qDebug() << "";
|
2012-05-22 13:09:48 -04:00
|
|
|
paerr=Pa_OpenStream(&inStream, //Input stream
|
|
|
|
&inParam, //Input parameters
|
|
|
|
NULL, //No output parameters
|
2012-09-24 19:36:38 -04:00
|
|
|
12000.0, //Sample rate
|
2012-05-22 13:09:48 -04:00
|
|
|
FRAMES_PER_BUFFER, //Frames per buffer
|
2012-07-05 12:16:03 -04:00
|
|
|
// paClipOff+paDitherOff, //No clipping or dithering
|
2012-05-22 13:09:48 -04:00
|
|
|
paClipOff, //No clipping
|
2012-11-01 15:54:40 -04:00
|
|
|
a2dCallback, //Input callback routine
|
2012-05-22 13:09:48 -04:00
|
|
|
&udata); //userdata
|
|
|
|
|
|
|
|
paerr=Pa_StartStream(inStream);
|
|
|
|
if(paerr<0) {
|
|
|
|
emit error("Failed to start audio input stream.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool qe = quitExecution;
|
2012-09-25 20:48:49 -04:00
|
|
|
static int ntr0=99;
|
2012-05-22 13:09:48 -04:00
|
|
|
int k=0;
|
|
|
|
int nsec;
|
2012-09-25 16:26:12 -04:00
|
|
|
int ntr;
|
2012-05-22 13:09:48 -04:00
|
|
|
int nBusy=0;
|
2012-07-04 12:27:57 -04:00
|
|
|
int nstep0=0;
|
2012-10-05 13:41:04 -04:00
|
|
|
int nsps0=0;
|
2012-11-13 15:23:03 -05:00
|
|
|
qint64 ms0 = QDateTime::currentMSecsSinceEpoch();
|
2012-05-22 13:09:48 -04:00
|
|
|
|
|
|
|
//---------------------------------------------- Soundcard input loop
|
|
|
|
while (!qe) {
|
|
|
|
qe = quitExecution;
|
|
|
|
if (qe) break;
|
2012-11-01 15:54:40 -04:00
|
|
|
udata.monitoring=m_monitoring;
|
2012-11-13 15:23:03 -05:00
|
|
|
qint64 ms = QDateTime::currentMSecsSinceEpoch();
|
|
|
|
m_SamFacIn=1.0;
|
|
|
|
if(udata.ncall>100) {
|
|
|
|
m_SamFacIn=udata.ncall*FRAMES_PER_BUFFER*1000.0/(12000.0*(ms-ms0-50));
|
|
|
|
}
|
|
|
|
ms=ms % 86400000;
|
2012-05-22 13:09:48 -04:00
|
|
|
nsec = ms/1000; // Time according to this computer
|
2012-09-25 16:26:12 -04:00
|
|
|
ntr = nsec % m_TRperiod;
|
2012-05-22 13:09:48 -04:00
|
|
|
|
|
|
|
// Reset buffer pointer and symbol number at start of minute
|
2012-10-05 13:41:04 -04:00
|
|
|
if(ntr < ntr0 or !m_monitoring or m_nsps!=nsps0) {
|
2012-07-04 12:27:57 -04:00
|
|
|
nstep0=0;
|
2012-10-05 13:41:04 -04:00
|
|
|
nsps0=m_nsps;
|
2012-05-22 13:09:48 -04:00
|
|
|
udata.bzero=true;
|
|
|
|
}
|
|
|
|
k=udata.kin;
|
|
|
|
if(m_monitoring) {
|
2012-09-25 20:48:49 -04:00
|
|
|
int kstep=m_nsps/2;
|
2012-10-05 13:13:21 -04:00
|
|
|
// m_step=k/kstep;
|
|
|
|
m_step=(k-1)/kstep;
|
2012-07-04 12:27:57 -04:00
|
|
|
if(m_step != nstep0) {
|
2012-05-22 13:09:48 -04:00
|
|
|
if(m_dataSinkBusy) {
|
|
|
|
nBusy++;
|
|
|
|
} else {
|
2012-07-04 12:27:57 -04:00
|
|
|
// m_dataSinkBusy=true;
|
2012-10-05 13:13:21 -04:00
|
|
|
// emit readyForFFT(k); //Signal to compute new FFTs
|
|
|
|
emit readyForFFT(k-1); //Signal to compute new FFTs
|
2012-05-22 13:09:48 -04:00
|
|
|
}
|
2012-07-04 12:27:57 -04:00
|
|
|
nstep0=m_step;
|
2012-05-22 13:09:48 -04:00
|
|
|
}
|
|
|
|
}
|
2012-09-25 20:48:49 -04:00
|
|
|
msleep(100);
|
2012-09-25 16:26:12 -04:00
|
|
|
ntr0=ntr;
|
2012-05-22 13:09:48 -04:00
|
|
|
}
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2012-09-25 20:48:49 -04:00
|
|
|
void SoundInThread::setPeriod(int ntrperiod, int nsps)
|
2012-09-24 15:11:31 -04:00
|
|
|
{
|
2012-09-25 20:48:49 -04:00
|
|
|
m_TRperiod=ntrperiod;
|
|
|
|
m_nsps=nsps;
|
2012-09-24 15:11:31 -04:00
|
|
|
}
|
2012-05-22 13:09:48 -04:00
|
|
|
|
2012-07-04 12:27:57 -04:00
|
|
|
int SoundInThread::mstep()
|
2012-05-22 13:09:48 -04:00
|
|
|
{
|
2012-07-04 12:27:57 -04:00
|
|
|
return m_step;
|
2012-05-22 13:09:48 -04:00
|
|
|
}
|
2012-11-13 15:23:03 -05:00
|
|
|
|
|
|
|
double SoundInThread::samFacIn()
|
|
|
|
{
|
|
|
|
return m_SamFacIn;
|
|
|
|
}
|