| 
									
										
										
										
											2012-05-22 17:09:48 +00:00
										 |  |  | #include "soundout.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-16 15:02:40 +01:00
										 |  |  | #ifdef Q_OS_WIN32
 | 
					
						
							|  |  |  | #include <windows.h>
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-22 17:09:48 +00:00
										 |  |  | #define FRAMES_PER_BUFFER 256
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <portaudio.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | extern float gran();                  //Noise generator (for tests only)
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-04 16:42:51 +00:00
										 |  |  | extern short int iwave[2*60*11025];   //Wave file for Tx audio
 | 
					
						
							| 
									
										
										
										
											2012-05-22 17:09:48 +00:00
										 |  |  | extern int nwave; | 
					
						
							|  |  |  | extern bool btxok; | 
					
						
							| 
									
										
										
										
											2014-01-10 20:11:30 +00:00
										 |  |  | extern bool bTune; | 
					
						
							| 
									
										
										
										
											2014-01-16 18:47:28 +00:00
										 |  |  | extern bool bIQxt; | 
					
						
							| 
									
										
										
										
											2014-01-15 21:44:12 +00:00
										 |  |  | extern int iqAmp; | 
					
						
							|  |  |  | extern int iqPhase; | 
					
						
							|  |  |  | extern int txPower; | 
					
						
							| 
									
										
										
										
											2012-05-22 17:09:48 +00:00
										 |  |  | extern double outputLatency; | 
					
						
							| 
									
										
										
										
											2014-01-15 21:44:12 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-22 17:09:48 +00:00
										 |  |  | typedef struct   //Parameters sent to or received from callback function | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2012-08-31 15:51:58 +00:00
										 |  |  |   int nTRperiod; | 
					
						
							| 
									
										
										
										
											2012-05-22 17:09:48 +00:00
										 |  |  | } paUserData; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | //--------------------------------------------------------------- d2aCallback
 | 
					
						
							| 
									
										
										
										
											2021-04-09 17:47:49 +01:00
										 |  |  | extern "C" int d2aCallback(const void * /*inputBuffer*/, void *outputBuffer, | 
					
						
							| 
									
										
										
										
											2012-05-22 17:09:48 +00:00
										 |  |  |                            unsigned long framesToProcess, | 
					
						
							| 
									
										
										
										
											2021-04-09 17:47:49 +01:00
										 |  |  |                            const PaStreamCallbackTimeInfo* /*timeInfo*/, | 
					
						
							|  |  |  |                            PaStreamCallbackFlags /*statusFlags*/, | 
					
						
							| 
									
										
										
										
											2012-05-22 17:09:48 +00:00
										 |  |  |                            void *userData ) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   paUserData *udata=(paUserData*)userData; | 
					
						
							|  |  |  |   short *wptr = (short*)outputBuffer; | 
					
						
							| 
									
										
										
										
											2012-09-13 19:34:50 +00:00
										 |  |  |   unsigned int i; | 
					
						
							| 
									
										
										
										
											2013-11-04 16:42:51 +00:00
										 |  |  |   static int n; | 
					
						
							| 
									
										
										
										
											2012-05-22 17:09:48 +00:00
										 |  |  |   static int ic=0; | 
					
						
							|  |  |  |   static bool btxok0=false; | 
					
						
							| 
									
										
										
										
											2014-01-16 19:28:52 +00:00
										 |  |  |   static bool bTune0=false; | 
					
						
							| 
									
										
										
										
											2012-08-31 18:29:54 +00:00
										 |  |  |   static int nStart=0; | 
					
						
							| 
									
										
										
										
											2014-01-16 19:28:52 +00:00
										 |  |  |   static double phi=0.; | 
					
						
							|  |  |  |   double tsec,tstart,dphi; | 
					
						
							| 
									
										
										
										
											2012-05-22 17:09:48 +00:00
										 |  |  |   int nsec; | 
					
						
							| 
									
										
										
										
											2012-08-31 15:51:58 +00:00
										 |  |  |   int nTRperiod=udata->nTRperiod; | 
					
						
							| 
									
										
										
										
											2012-05-22 17:09:48 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |   // Get System time
 | 
					
						
							|  |  |  |   qint64 ms = QDateTime::currentMSecsSinceEpoch() % 86400000; | 
					
						
							|  |  |  |   tsec = 0.001*ms; | 
					
						
							|  |  |  |   nsec = ms/1000; | 
					
						
							| 
									
										
										
										
											2014-01-16 18:47:28 +00:00
										 |  |  |   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; | 
					
						
							| 
									
										
										
										
											2014-01-10 20:11:30 +00:00
										 |  |  |   static int nsec0=0; | 
					
						
							| 
									
										
										
										
											2014-01-16 19:28:52 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |   if(bTune) { | 
					
						
							|  |  |  |     ic=0; | 
					
						
							|  |  |  |     dphi=6.28318530718*1270.46/11025.0; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if(bTune0 and !bTune) btxok=false; | 
					
						
							|  |  |  |   bTune0=bTune; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-01-10 20:11:30 +00:00
										 |  |  |   if(nsec!=nsec0) { | 
					
						
							| 
									
										
										
										
											2014-01-16 18:47:28 +00:00
										 |  |  | //    qDebug() << txPower << iqAmp << iqPhase << amp << xAmp << yAmp << dPhase << bTune;
 | 
					
						
							| 
									
										
										
										
											2014-01-16 19:28:52 +00:00
										 |  |  | //    qDebug() << "A" << nsec%60 << bTune << btxok;
 | 
					
						
							| 
									
										
										
										
											2014-01-20 15:55:49 +00:00
										 |  |  | //    ic=0;
 | 
					
						
							| 
									
										
										
										
											2014-01-10 20:11:30 +00:00
										 |  |  |     nsec0=nsec; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-22 17:09:48 +00:00
										 |  |  |   if(btxok and !btxok0) {       //Start (or re-start) a transmission
 | 
					
						
							| 
									
										
										
										
											2012-08-31 15:51:58 +00:00
										 |  |  |     n=nsec/nTRperiod; | 
					
						
							|  |  |  |     tstart=tsec - n*nTRperiod - 1.0; | 
					
						
							| 
									
										
										
										
											2012-05-22 17:09:48 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if(tstart<1.0) { | 
					
						
							| 
									
										
										
										
											2012-08-31 18:29:54 +00:00
										 |  |  |       ic=0;                      //Start of Tx cycle, set starting index to 0
 | 
					
						
							|  |  |  |       nStart=n; | 
					
						
							| 
									
										
										
										
											2012-05-22 17:09:48 +00:00
										 |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2012-08-31 18:29:54 +00:00
										 |  |  |       if(n != nStart) { //Late start in new Tx cycle: compute starting index
 | 
					
						
							| 
									
										
										
										
											2012-05-22 17:09:48 +00:00
										 |  |  |         ic=(int)(tstart*11025.0); | 
					
						
							| 
									
										
										
										
											2013-11-04 16:42:51 +00:00
										 |  |  |         ic=2*ic; | 
					
						
							| 
									
										
										
										
											2012-08-31 18:29:54 +00:00
										 |  |  |         nStart=n; | 
					
						
							| 
									
										
										
										
											2012-05-22 17:09:48 +00:00
										 |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   btxok0=btxok; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if(btxok) { | 
					
						
							|  |  |  |     for(i=0 ; i<framesToProcess; i++ )  { | 
					
						
							| 
									
										
										
										
											2013-11-04 16:42:51 +00:00
										 |  |  |         short int i2a=iwave[ic++]; | 
					
						
							|  |  |  |         short int i2b=iwave[ic++]; | 
					
						
							|  |  |  |       if(ic > nwave) {i2a=0; i2b=0;} | 
					
						
							| 
									
										
										
										
											2012-05-22 17:09:48 +00:00
										 |  |  | //      i2 = 500.0*(i2/32767.0 + 5.0*gran());      //Add noise (tests only!)
 | 
					
						
							| 
									
										
										
										
											2014-01-16 18:47:28 +00:00
										 |  |  | //    if(bIQxt) {
 | 
					
						
							|  |  |  |       if(1) { | 
					
						
							| 
									
										
										
										
											2014-01-16 19:28:52 +00:00
										 |  |  |         if(bTune) { | 
					
						
							|  |  |  |           phi += dphi; | 
					
						
							|  |  |  |         } else { | 
					
						
							| 
									
										
										
										
											2014-08-13 18:50:44 +00:00
										 |  |  |           phi=qAtan2(qreal(i2b),qreal(i2a)); | 
					
						
							| 
									
										
										
										
											2014-01-16 19:28:52 +00:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2014-01-16 18:47:28 +00:00
										 |  |  |         i2a=xAmp*qCos(phi); | 
					
						
							| 
									
										
										
										
											2014-01-16 19:28:52 +00:00
										 |  |  |         i2b=yAmp*qSin(phi + dPhase); | 
					
						
							| 
									
										
										
										
											2014-01-16 18:47:28 +00:00
										 |  |  | //        qDebug() << xAmp << yAmp << phi << i2a << i2b;
 | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | //      i2a=0.01*txPower*i2a;
 | 
					
						
							|  |  |  | //      i2b=0.01*txPower*i2b;
 | 
					
						
							| 
									
										
										
										
											2014-08-12 19:12:29 +00:00
										 |  |  |       *wptr++ = i2b;                     //left
 | 
					
						
							|  |  |  |       *wptr++ = i2a;                     //right
 | 
					
						
							| 
									
										
										
										
											2012-05-22 17:09:48 +00:00
										 |  |  |     } | 
					
						
							|  |  |  |   } else { | 
					
						
							|  |  |  |     for(i=0 ; i<framesToProcess; i++ )  { | 
					
						
							|  |  |  |       *wptr++ = 0; | 
					
						
							|  |  |  |       *wptr++ = 0; | 
					
						
							| 
									
										
										
										
											2013-11-04 16:42:51 +00:00
										 |  |  |       ic++; ic++; | 
					
						
							| 
									
										
										
										
											2012-05-22 17:09:48 +00:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if(ic > nwave) { | 
					
						
							|  |  |  |     btxok=0; | 
					
						
							|  |  |  |     ic=0; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-16 15:02:40 +01:00
										 |  |  | 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
 | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-22 17:09:48 +00:00
										 |  |  | void SoundOutThread::run() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2021-06-16 15:02:40 +01:00
										 |  |  |   COMWrapper c; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-22 17:09:48 +00:00
										 |  |  |   PaError paerr; | 
					
						
							|  |  |  |   PaStreamParameters outParam; | 
					
						
							|  |  |  |   PaStream *outStream; | 
					
						
							|  |  |  |   paUserData udata; | 
					
						
							|  |  |  |   quitExecution = false; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-16 15:02:40 +01:00
										 |  |  |   auto device_info = Pa_GetDeviceInfo (m_nDevOut); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-22 17:09:48 +00:00
										 |  |  |   outParam.device=m_nDevOut;                 //Output device number
 | 
					
						
							|  |  |  |   outParam.channelCount=2;                   //Number of analog channels
 | 
					
						
							|  |  |  |   outParam.sampleFormat=paInt16;             //Send short ints to PortAudio
 | 
					
						
							| 
									
										
										
										
											2021-06-16 15:02:40 +01:00
										 |  |  |   outParam.suggestedLatency=device_info->defaultLowOutputLatency; | 
					
						
							| 
									
										
										
										
											2012-05-22 17:09:48 +00:00
										 |  |  |   outParam.hostApiSpecificStreamInfo=NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-31 15:51:58 +00:00
										 |  |  |   udata.nTRperiod=m_TRperiod; | 
					
						
							| 
									
										
										
										
											2012-05-22 17:09:48 +00:00
										 |  |  |   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; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2012-08-31 15:51:58 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | void SoundOutThread::setPeriod(int n) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   m_TRperiod=n; | 
					
						
							|  |  |  | } |