| 
									
										
										
										
											2012-05-22 17:09:48 +00:00
										 |  |  | #include "soundout.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-29 13:42:09 +00:00
										 |  |  | #define FRAMES_PER_BUFFER 1024
 | 
					
						
							| 
									
										
										
										
											2012-05-22 17:09:48 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | extern "C" { | 
					
						
							|  |  |  | #include <portaudio.h>
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | extern float gran();                  //Noise generator (for tests only)
 | 
					
						
							| 
									
										
										
										
											2012-10-05 17:13:21 +00:00
										 |  |  | extern int itone[85];                 //Tx audio tones for 85 symbols
 | 
					
						
							| 
									
										
										
										
											2013-03-25 01:24:47 +00:00
										 |  |  | extern int icw[250];                  //Dits for CW ID
 | 
					
						
							| 
									
										
										
										
											2012-11-28 23:55:32 +00:00
										 |  |  | extern bool btxok; | 
					
						
							|  |  |  | extern bool btxMute; | 
					
						
							| 
									
										
										
										
											2012-05-22 17:09:48 +00:00
										 |  |  | extern double outputLatency; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | typedef struct   //Parameters sent to or received from callback function | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2012-10-26 14:03:43 +00:00
										 |  |  |   double txsnrdb; | 
					
						
							|  |  |  |   int    nsps; | 
					
						
							|  |  |  |   int    ntrperiod; | 
					
						
							|  |  |  |   int    ntxfreq; | 
					
						
							| 
									
										
										
										
											2012-11-13 20:23:03 +00:00
										 |  |  |   int    ncall; | 
					
						
							| 
									
										
										
										
											2012-10-26 14:03:43 +00:00
										 |  |  |   bool   txMute; | 
					
						
							|  |  |  |   bool   bRestart; | 
					
						
							| 
									
										
										
										
											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; | 
					
						
							| 
									
										
										
										
											2012-10-05 17:13:21 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-05 17:17:37 +00:00
										 |  |  |   static double twopi=2.0*3.141592653589793238462; | 
					
						
							| 
									
										
										
										
											2012-10-28 15:47:43 +00:00
										 |  |  |   static double baud; | 
					
						
							| 
									
										
										
										
											2012-10-05 17:13:21 +00:00
										 |  |  |   static double phi=0.0; | 
					
						
							|  |  |  |   static double dphi; | 
					
						
							|  |  |  |   static double freq; | 
					
						
							| 
									
										
										
										
											2012-10-26 14:03:43 +00:00
										 |  |  |   static double snr; | 
					
						
							|  |  |  |   static double fac; | 
					
						
							| 
									
										
										
										
											2013-03-25 01:24:47 +00:00
										 |  |  |   static int ic=0,j=0; | 
					
						
							| 
									
										
										
										
											2012-10-05 17:13:21 +00:00
										 |  |  |   static short int i2; | 
					
						
							| 
									
										
										
										
											2013-03-25 01:39:20 +00:00
										 |  |  |   int isym,nspd; | 
					
						
							| 
									
										
										
										
											2012-10-05 17:13:21 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-11-13 20:23:03 +00:00
										 |  |  |   udata->ncall++; | 
					
						
							| 
									
										
										
										
											2012-10-05 17:13:21 +00:00
										 |  |  |   if(udata->bRestart) { | 
					
						
							|  |  |  |  // Time according to this computer
 | 
					
						
							|  |  |  |     qint64 ms = QDateTime::currentMSecsSinceEpoch() % 86400000; | 
					
						
							|  |  |  |     int mstr = ms % (1000*udata->ntrperiod ); | 
					
						
							|  |  |  |     if(mstr<1000) return 0; | 
					
						
							| 
									
										
										
										
											2012-10-29 13:42:09 +00:00
										 |  |  |     ic=(mstr-1000)*48; | 
					
						
							| 
									
										
										
										
											2012-10-05 17:13:21 +00:00
										 |  |  |     udata->bRestart=false; | 
					
						
							| 
									
										
										
										
											2012-11-13 20:23:03 +00:00
										 |  |  |     srand(mstr);                                //Initialize random seed
 | 
					
						
							| 
									
										
										
										
											2012-10-05 17:13:21 +00:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2012-10-29 13:42:09 +00:00
										 |  |  |   isym=ic/(4*udata->nsps);                      //Actual fsample=48000
 | 
					
						
							| 
									
										
										
										
											2012-10-26 14:03:43 +00:00
										 |  |  |   if(udata->txsnrdb < 0.0) { | 
					
						
							| 
									
										
										
										
											2012-11-12 21:30:00 +00:00
										 |  |  |     snr=pow(10.0,0.05*(udata->txsnrdb-6.0)); | 
					
						
							| 
									
										
										
										
											2012-10-26 14:03:43 +00:00
										 |  |  |     fac=3000.0; | 
					
						
							|  |  |  |     if(snr>1.0) fac=3000.0/snr; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-25 01:24:47 +00:00
										 |  |  |   if(isym>=85 and icw[0]>0) {              //Output the CW ID
 | 
					
						
							|  |  |  |     freq=udata->ntxfreq; | 
					
						
							|  |  |  |     dphi=twopi*freq/48000.0; | 
					
						
							|  |  |  | //    float wpm=20.0;
 | 
					
						
							|  |  |  | //    int nspd=1.2*48000.0/wpm;
 | 
					
						
							| 
									
										
										
										
											2013-03-25 01:39:20 +00:00
										 |  |  | //    nspd=3072;                           //18.75 wpm
 | 
					
						
							|  |  |  |     nspd=2048;                             //28.125 wpm
 | 
					
						
							| 
									
										
										
										
											2013-03-25 01:24:47 +00:00
										 |  |  |     int ic0=85*4*udata->nsps; | 
					
						
							|  |  |  |     for(int i=0 ; i<framesToProcess; i++ )  { | 
					
						
							|  |  |  |       phi += dphi; | 
					
						
							|  |  |  |       if(phi>twopi) phi -= twopi; | 
					
						
							|  |  |  |       i2=32767.0*sin(phi); | 
					
						
							|  |  |  |       j=(ic-ic0)/nspd; | 
					
						
							|  |  |  |       if(icw[j]==0) i2=0; | 
					
						
							|  |  |  |       if(udata->txsnrdb < 0.0) { | 
					
						
							|  |  |  |         int i4=fac*(gran() + i2*snr/32768.0); | 
					
						
							|  |  |  |         if(i4>32767) i4=32767; | 
					
						
							|  |  |  |         if(i4<-32767) i4=-32767; | 
					
						
							|  |  |  |         i2=i4; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       if(!btxok or btxMute)  i2=0; | 
					
						
							|  |  |  |       *wptr++ = i2;                   //left
 | 
					
						
							|  |  |  | #ifdef unix
 | 
					
						
							|  |  |  |       *wptr++ = i2;                   //right
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  |       ic++; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return paContinue; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if(isym>=85 and itone[0]>=0) return paComplete; | 
					
						
							|  |  |  |   baud=12000.0/udata->nsps; | 
					
						
							|  |  |  |   freq=udata->ntxfreq + itone[isym]*baud; | 
					
						
							|  |  |  |   dphi=twopi*freq/48000.0; | 
					
						
							| 
									
										
										
										
											2012-10-26 14:03:43 +00:00
										 |  |  |   for(uint i=0 ; i<framesToProcess; i++ )  { | 
					
						
							| 
									
										
										
										
											2012-10-05 17:13:21 +00:00
										 |  |  |     phi += dphi; | 
					
						
							|  |  |  |     if(phi>twopi) phi -= twopi; | 
					
						
							|  |  |  |     i2=32767.0*sin(phi); | 
					
						
							| 
									
										
										
										
											2012-10-26 14:03:43 +00:00
										 |  |  |     if(udata->txsnrdb < 0.0) { | 
					
						
							|  |  |  |       int i4=fac*(gran() + i2*snr/32768.0); | 
					
						
							|  |  |  |       if(i4>32767) i4=32767; | 
					
						
							|  |  |  |       if(i4<-32767) i4=-32767; | 
					
						
							|  |  |  |       i2=i4; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2012-11-28 23:55:32 +00:00
										 |  |  |     if(!btxok or btxMute)  i2=0; | 
					
						
							| 
									
										
										
										
											2012-07-04 16:27:57 +00:00
										 |  |  |     *wptr++ = i2;                   //left
 | 
					
						
							| 
									
										
										
										
											2013-03-24 22:34:57 +00:00
										 |  |  | #ifdef unix
 | 
					
						
							|  |  |  |     *wptr++ = i2;                   //right
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2012-07-04 16:27:57 +00:00
										 |  |  |     ic++; | 
					
						
							| 
									
										
										
										
											2012-05-22 17:09:48 +00:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2013-03-25 01:24:47 +00:00
										 |  |  |   return paContinue; | 
					
						
							| 
									
										
										
										
											2012-05-22 17:09:48 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void SoundOutThread::run() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   PaError paerr; | 
					
						
							|  |  |  |   PaStreamParameters outParam; | 
					
						
							|  |  |  |   PaStream *outStream; | 
					
						
							|  |  |  |   paUserData udata; | 
					
						
							|  |  |  |   quitExecution = false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   outParam.device=m_nDevOut;                 //Output device number
 | 
					
						
							| 
									
										
										
										
											2012-07-04 16:27:57 +00:00
										 |  |  |   outParam.channelCount=1;                   //Number of analog channels
 | 
					
						
							| 
									
										
										
										
											2012-05-22 17:09:48 +00:00
										 |  |  |   outParam.sampleFormat=paInt16;             //Send short ints to PortAudio
 | 
					
						
							|  |  |  |   outParam.suggestedLatency=0.05; | 
					
						
							|  |  |  |   outParam.hostApiSpecificStreamInfo=NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-29 13:42:09 +00:00
										 |  |  |   paerr=Pa_IsFormatSupported(NULL,&outParam,48000.0); | 
					
						
							| 
									
										
										
										
											2012-05-22 17:09:48 +00:00
										 |  |  |   if(paerr<0) { | 
					
						
							|  |  |  |     qDebug() << "PortAudio says requested output format not supported."; | 
					
						
							| 
									
										
										
										
											2012-07-02 20:52:56 +00:00
										 |  |  |     qDebug() << paerr << m_nDevOut; | 
					
						
							| 
									
										
										
										
											2012-05-22 17:09:48 +00:00
										 |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-26 14:03:43 +00:00
										 |  |  |   udata.txsnrdb=99.0; | 
					
						
							| 
									
										
										
										
											2012-10-05 17:13:21 +00:00
										 |  |  |   udata.nsps=m_nsps; | 
					
						
							|  |  |  |   udata.ntrperiod=m_TRperiod; | 
					
						
							| 
									
										
										
										
											2012-10-05 19:14:45 +00:00
										 |  |  |   udata.ntxfreq=m_txFreq; | 
					
						
							| 
									
										
										
										
											2012-11-13 20:23:03 +00:00
										 |  |  |   udata.ncall=0; | 
					
						
							| 
									
										
										
										
											2012-10-05 17:13:21 +00:00
										 |  |  |   udata.txMute=m_txMute; | 
					
						
							|  |  |  |   udata.bRestart=true; | 
					
						
							| 
									
										
										
										
											2012-05-22 17:09:48 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |   paerr=Pa_OpenStream(&outStream,           //Output stream
 | 
					
						
							|  |  |  |         NULL,                               //No input parameters
 | 
					
						
							|  |  |  |         &outParam,                          //Output parameters
 | 
					
						
							| 
									
										
										
										
											2012-10-29 13:42:09 +00:00
										 |  |  |         48000.0,                            //Sample rate
 | 
					
						
							| 
									
										
										
										
											2012-05-22 17:09:48 +00:00
										 |  |  |         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; | 
					
						
							| 
									
										
										
										
											2012-11-13 20:23:03 +00:00
										 |  |  |   qint64 ms0 = QDateTime::currentMSecsSinceEpoch(); | 
					
						
							| 
									
										
										
										
											2012-05-22 17:09:48 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | //---------------------------------------------- Soundcard output loop
 | 
					
						
							|  |  |  |   while (!qe) { | 
					
						
							|  |  |  |     qe = quitExecution; | 
					
						
							|  |  |  |     if (qe) break; | 
					
						
							| 
									
										
										
										
											2012-10-05 17:13:21 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-26 14:03:43 +00:00
										 |  |  |     udata.txsnrdb=m_txsnrdb; | 
					
						
							| 
									
										
										
										
											2012-10-05 17:13:21 +00:00
										 |  |  |     udata.nsps=m_nsps; | 
					
						
							|  |  |  |     udata.ntrperiod=m_TRperiod; | 
					
						
							| 
									
										
										
										
											2012-10-05 19:14:45 +00:00
										 |  |  |     udata.ntxfreq=m_txFreq; | 
					
						
							| 
									
										
										
										
											2012-10-05 17:13:21 +00:00
										 |  |  |     udata.txMute=m_txMute; | 
					
						
							| 
									
										
										
										
											2012-11-13 20:23:03 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     m_SamFacOut=1.0; | 
					
						
							|  |  |  |     if(udata.ncall>400) { | 
					
						
							|  |  |  |       qint64 ms = QDateTime::currentMSecsSinceEpoch(); | 
					
						
							|  |  |  |       m_SamFacOut=udata.ncall*FRAMES_PER_BUFFER*1000.0/(48000.0*(ms-ms0-50)); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2013-03-24 22:34:57 +00:00
										 |  |  |     //qDebug() << "btxok = " << btxok << "btxMute = " << btxMute;
 | 
					
						
							| 
									
										
										
										
											2012-05-22 17:09:48 +00:00
										 |  |  |     msleep(100); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   Pa_StopStream(outStream); | 
					
						
							|  |  |  |   Pa_CloseStream(outStream); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void SoundOutThread::setOutputDevice(int n)      //setOutputDevice()
 | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   if (isRunning()) return; | 
					
						
							|  |  |  |   this->m_nDevOut=n; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2012-09-24 19:11:31 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-09-26 00:48:49 +00:00
										 |  |  | void SoundOutThread::setPeriod(int ntrperiod, int nsps) | 
					
						
							| 
									
										
										
										
											2012-09-24 19:11:31 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2012-09-26 00:48:49 +00:00
										 |  |  |   m_TRperiod=ntrperiod; | 
					
						
							|  |  |  |   m_nsps=nsps; | 
					
						
							| 
									
										
										
										
											2012-09-24 19:11:31 +00:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2012-10-05 19:14:45 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | void SoundOutThread::setTxFreq(int n) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   m_txFreq=n; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2012-10-26 14:03:43 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void SoundOutThread::setTxSNR(double snr) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   m_txsnrdb=snr; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2012-11-13 20:23:03 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | double SoundOutThread::samFacOut() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   return m_SamFacOut; | 
					
						
							|  |  |  | } |