#include "soundout.h" #ifdef Q_OS_WIN32 #include #endif #define FRAMES_PER_BUFFER 256 #include extern float gran(); //Noise generator (for tests only) extern short int iwave[2*60*11025]; //Wave file for Tx audio extern int nwave; extern bool btxok; extern bool bTune; extern bool bIQxt; extern int iqAmp; extern int iqPhase; extern int txPower; extern double outputLatency; typedef struct //Parameters sent to or received from callback function { int nTRperiod; } paUserData; //--------------------------------------------------------------- d2aCallback extern "C" int d2aCallback(const void * /*inputBuffer*/, void *outputBuffer, unsigned long framesToProcess, const PaStreamCallbackTimeInfo* /*timeInfo*/, PaStreamCallbackFlags /*statusFlags*/, void *userData ) { paUserData *udata=(paUserData*)userData; short *wptr = (short*)outputBuffer; unsigned int i; static int n; static int ic=0; static bool btxok0=false; static bool bTune0=false; static int nStart=0; static double phi=0.; double tsec,tstart,dphi; int nsec; int nTRperiod=udata->nTRperiod; // Get System time qint64 ms = QDateTime::currentMSecsSinceEpoch() % 86400000; tsec = 0.001*ms; nsec = ms/1000; qreal dPhase=iqPhase/5729.57795131; qreal amp=1.0 + 0.0001*iqAmp; qreal xAmp=txPower*295.00*qSqrt(2.0 - amp*amp); qreal yAmp=txPower*295.00*amp; static int nsec0=0; if(bTune) { ic=0; dphi=6.28318530718*1270.46/11025.0; } if(bTune0 and !bTune) btxok=false; bTune0=bTune; if(nsec!=nsec0) { // qDebug() << txPower << iqAmp << iqPhase << amp << xAmp << yAmp << dPhase << bTune; // qDebug() << "A" << nsec%60 << bTune << btxok; // ic=0; nsec0=nsec; } if(btxok and !btxok0) { //Start (or re-start) a transmission n=nsec/nTRperiod; tstart=tsec - n*nTRperiod - 1.0; if(tstart<1.0) { ic=0; //Start of Tx cycle, set starting index to 0 nStart=n; } else { if(n != nStart) { //Late start in new Tx cycle: compute starting index ic=(int)(tstart*11025.0); ic=2*ic; nStart=n; } } } btxok0=btxok; if(btxok) { for(i=0 ; i nwave) {i2a=0; i2b=0;} // i2 = 500.0*(i2/32767.0 + 5.0*gran()); //Add noise (tests only!) // if(bIQxt) { if(1) { if(bTune) { phi += dphi; } else { phi=qAtan2(qreal(i2b),qreal(i2a)); } i2a=xAmp*qCos(phi); i2b=yAmp*qSin(phi + dPhase); // qDebug() << xAmp << yAmp << phi << i2a << i2b; } // i2a=0.01*txPower*i2a; // i2b=0.01*txPower*i2b; *wptr++ = i2b; //left *wptr++ = i2a; //right } } else { for(i=0 ; i nwave) { btxok=0; ic=0; } return 0; } namespace { struct COMWrapper { explicit COMWrapper () { #ifdef Q_OS_WIN32 // required because Qt only does this for GUI thread CoInitializeEx (nullptr, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE); #endif } ~COMWrapper () { #ifdef Q_OS_WIN32 CoUninitialize (); #endif } }; } void SoundOutThread::run() { COMWrapper c; PaError paerr; PaStreamParameters outParam; PaStream *outStream; paUserData udata; quitExecution = false; auto device_info = Pa_GetDeviceInfo (m_nDevOut); outParam.device=m_nDevOut; //Output device number outParam.channelCount=2; //Number of analog channels outParam.sampleFormat=paInt16; //Send short ints to PortAudio outParam.suggestedLatency=device_info->defaultLowOutputLatency; outParam.hostApiSpecificStreamInfo=NULL; udata.nTRperiod=m_TRperiod; paerr=Pa_IsFormatSupported(NULL,&outParam,11025.0); if(paerr<0) { qDebug() << "PortAudio says requested output format not supported."; qDebug() << paerr; return; } paerr=Pa_OpenStream(&outStream, //Output stream NULL, //No input parameters &outParam, //Output parameters 11025.0, //Sample rate FRAMES_PER_BUFFER, //Frames per buffer paClipOff, //No clipping d2aCallback, //output callbeck routine &udata); //userdata paerr=Pa_StartStream(outStream); if(paerr<0) { qDebug() << "Failed to start audio output stream."; return; } const PaStreamInfo* p=Pa_GetStreamInfo(outStream); outputLatency = p->outputLatency; bool qe = quitExecution; //---------------------------------------------- Soundcard output loop while (!qe) { qe = quitExecution; if (qe) break; msleep(100); } Pa_StopStream(outStream); Pa_CloseStream(outStream); } void SoundOutThread::setOutputDevice(int n) //setOutputDevice() { if (isRunning()) return; this->m_nDevOut=n; } void SoundOutThread::setPeriod(int n) { m_TRperiod=n; }