1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207
|
#include "soundout.h"
#ifdef Q_OS_WIN32
#include <windows.h>
#endif
#define FRAMES_PER_BUFFER 256
#include <portaudio.h>
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<framesToProcess; i++ ) {
short int i2a=iwave[ic++];
short int i2b=iwave[ic++];
if(ic > 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<framesToProcess; i++ ) {
*wptr++ = 0;
*wptr++ = 0;
ic++; ic++;
}
}
if(ic > 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;
}
|