File: soundout.cpp

package info (click to toggle)
wsjtx 2.7.0%2Brepack-1
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 70,440 kB
  • sloc: cpp: 75,379; f90: 46,460; python: 27,241; ansic: 13,367; fortran: 2,382; makefile: 197; sh: 133
file content (207 lines) | stat: -rwxr-xr-x 5,363 bytes parent folder | download
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;
}