| 
									
										
										
										
											2012-05-22 17:09:48 +00:00
										 |  |  | #include "soundout.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define FRAMES_PER_BUFFER 256
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | extern "C" { | 
					
						
							|  |  |  | #include <portaudio.h>
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | extern float gran();                  //Noise generator (for tests only)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | extern short int iwave[60*11025];     //Wave file for Tx audio
 | 
					
						
							|  |  |  | extern int nwave; | 
					
						
							|  |  |  | extern bool btxok; | 
					
						
							|  |  |  | extern double outputLatency; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 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
 | 
					
						
							|  |  |  | 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,n; | 
					
						
							|  |  |  |   static int ic=0; | 
					
						
							|  |  |  |   static bool btxok0=false; | 
					
						
							| 
									
										
										
										
											2012-08-31 18:29:54 +00:00
										 |  |  |   static int nStart=0; | 
					
						
							| 
									
										
										
										
											2012-05-22 17:09:48 +00:00
										 |  |  |   double tsec,tstart; | 
					
						
							|  |  |  |   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; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   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); | 
					
						
							| 
									
										
										
										
											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++ )  { | 
					
						
							|  |  |  |       short int i2=iwave[ic]; | 
					
						
							|  |  |  |       if(ic > nwave) i2=0; | 
					
						
							|  |  |  | //      i2 = 500.0*(i2/32767.0 + 5.0*gran());      //Add noise (tests only!)
 | 
					
						
							|  |  |  |       if(!btxok) i2=0; | 
					
						
							|  |  |  |       *wptr++ = i2;                   //left
 | 
					
						
							|  |  |  |       *wptr++ = i2;                   //right
 | 
					
						
							|  |  |  |       ic++; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } else { | 
					
						
							|  |  |  |     for(i=0 ; i<framesToProcess; i++ )  { | 
					
						
							|  |  |  |       *wptr++ = 0; | 
					
						
							|  |  |  |       *wptr++ = 0; | 
					
						
							|  |  |  |       ic++; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if(ic > nwave) { | 
					
						
							|  |  |  |     btxok=0; | 
					
						
							|  |  |  |     ic=0; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void SoundOutThread::run() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   PaError paerr; | 
					
						
							|  |  |  |   PaStreamParameters outParam; | 
					
						
							|  |  |  |   PaStream *outStream; | 
					
						
							|  |  |  |   paUserData udata; | 
					
						
							|  |  |  |   quitExecution = false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   outParam.device=m_nDevOut;                 //Output device number
 | 
					
						
							|  |  |  |   outParam.channelCount=2;                   //Number of analog channels
 | 
					
						
							|  |  |  |   outParam.sampleFormat=paInt16;             //Send short ints to PortAudio
 | 
					
						
							|  |  |  |   outParam.suggestedLatency=0.05; | 
					
						
							|  |  |  |   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; | 
					
						
							|  |  |  | } |