SoDaRadio-5.0.3-master:8901fb5
BaseBandRX.cxx
Go to the documentation of this file.
1 /*
2  Copyright (c) 2012, Matthew H. Reilly (kb1vc)
3  All rights reserved.
4 
5  Redistribution and use in source and binary forms, with or without
6  modification, are permitted provided that the following conditions are
7  met:
8 
9  Redistributions of source code must retain the above copyright
10  notice, this list of conditions and the following disclaimer.
11  Redistributions in binary form must reproduce the above copyright
12  notice, this list of conditions and the following disclaimer in
13  the documentation and/or other materials provided with the
14  distribution.
15 
16  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20  HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28 
29 #include "BaseBandRX.hxx"
30 #include "OSFilter.hxx"
31 #include <fstream>
32 #include <stdio.h>
33 #include <fcntl.h>
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 
38  DatMBox * _rx_stream, CmdMBox * _cmd_stream,
39  AudioIfc * _audio_ifc) : SoDa::SoDaThread("BaseBandRX")
40 {
41  audio_ifc = _audio_ifc;
42  rx_stream = _rx_stream;
44 
45  cmd_stream = _cmd_stream;
47 
48  // set up some convenient defaults
50  // what is the default sample rate and buffer size?
51  // the audio rate is set and welded, as we have statically calculated
52  // filter parameters.
54  rf_sample_rate = params->getRXRate();
56  rf_buffer_size = params->getRFBufferSize();
57  // setup the resampler now...
58  float rsgain = ((float) rf_buffer_size);
60  // and the WBFM resampler -- same shape, different state
63 
66 
67  // initial af gain
68  af_gain = 1.0;
69  af_sidetone_gain = 1.0;
70  cur_af_gain = &af_gain;
71  unsigned int i, j;
72  // prime the audio stream so that we don't fall behind
73  // right away.
74  for(j = 0; j < 6; j++) {
76  for(i = 0; i < audio_buffer_size; i++) {
77  sidetone_silence[i] = 0.0;
78  }
79  if(j < 5) { // don't pend the last buffer, as we use it for background silence
81  }
82  }
83  // create hilbert transformer
85 
86  // initialize the sample for the NBFM and WBFM demodulator
87  last_phase_samp = 0.0;
88 
89  // setup the catchup mechanism that adjusts to differences
90  // between the radio's clock frequency and the sound system's clock
91  in_catchup = false;
92  in_fallback = false;
93  // setup the random number generator. Note that randomness
94  // isn't nearly as important as an apparently long period.
95  // The RNG is used to "steal" an audio sample out of the
96  // stream in a pattern that won't be perceptible to human
97  // hearing.
98  srandom(0x13245);
99  // we could do something mod(audio_buffer_size) but 2304 is
100  // a tough point to make. Since superlative randomness isn't
101  // all that important, doing mod 2^k where 2^k is the largest
102  // power of two less than the audio buffer size will ensure
103  // reasonable distribution of the dropouts. (The trick is to
104  // make the period undetectable.)
105  for(catchup_rand_mask = 0x1;
107  catchup_rand_mask = ((catchup_rand_mask << 1) | 1));
109 
110  // debug help
111  dbg_ctr = 0;
112 
114  debugMsg("audio_rx_stream_enabled = true\n");
116 
117  // log all audio to an output file (debug only....?)
118  audio_save_enable = false;
119  //audio_file.open("soda_audio.bin", std::ios::out | std::ios::binary);
120  //audio_file2.open("soda_audio_iq_fm.bin", std::ios::out | std::ios::binary);
121 }
122 
124 {
125  (void) mod;
126  // now allocate a new audio buffer from the buffer ring
127  float * audio_buffer = getFreeAudioBuffer();
128  float demod_out[rf_buffer_size];
129  unsigned int i;
130 
131  std::complex<float> * dbuf = rxbuf->getComplexBuf();
132 
133  // Interestingly, arctan based demodulation (see Lyons p 486 for instance)
134  // performs much better than the approximation that avoids the atan call.
135  // Texts that talk about atan generally don't talk about the problem of
136  // rollover, where the sign changes from atan(samp[n]) and atan(samp[n+1]).
137  // In this case, dphase will be much bigger than M_PI, and it should be
138  // "corrected". We're really trying to find the angular diference between
139  // samples, so the wraparound is important.
140  for(i = 0; i < rf_buffer_size; i++) {
141  // do the atan demod
142  // measure the phase of the incoming signal.
143  float phase = arg(dbuf[i]);
144  float dphase = phase - last_phase_samp;
145  if(dphase < -M_PI) dphase += 2.0 * M_PI;
146  if(dphase > M_PI) dphase -= 2.0 * M_PI;
147  demod_out[i] = af_gain * dphase;
148  last_phase_samp = phase;
149  }
150  // now downsample it
151  wbfm_resampler->apply(demod_out, audio_buffer);
152  // do a median filter to eliminate the pops.
153  // better not. fmMedianFilter.apply(audio_buffer, audio_buffer, audio_buffer_size);
154  // gain was arrived at by trial and error.
155  fm_audio_filter->apply(audio_buffer, audio_buffer, 0.0012);
156  // then send it to the audio port.
157  pendAudioBuffer(audio_buffer);
158 }
159 
160 void SoDa::BaseBandRX::demodulateNBFM(std::complex<float> * dbuf, SoDa::Command::ModulationType mod, float af_gain)
161 {
162  (void) mod;
163  // now allocate a new audio buffer from the buffer ring
164  float * audio_buffer = getFreeAudioBuffer();
165  std::complex<float> demod_out[audio_buffer_size];
166 
167  // Interestingly, arctan based demodulation (see Lyons p 486 for instance)
168  // performs much better than the approximation that avoids the atan call.
169  // Texts that talk about atan generally don't talk about the problem of
170  // rollover, where the sign changes from atan(samp[n]) and atan(samp[n+1]).
171  // In this case, dphase will be much bigger than M_PI, and it should be
172  // "corrected". We're really trying to find the angular diference between
173  // samples, so the wraparound is important.
174  unsigned int i;
175  for(i = 0; i < audio_buffer_size; i++) {
176  // do the atan demod
177  // measure the phase of the incoming signal.
178  float phase = arg(dbuf[i]);
179  float dphase = phase - last_phase_samp;
180  if(dphase < -M_PI) dphase += 2.0 * M_PI;
181  if(dphase > M_PI) dphase -= 2.0 * M_PI;
182  demod_out[i] = af_gain * dphase;
183  last_phase_samp = phase;
184  }
185 
186  cur_audio_filter->apply(demod_out, demod_out, 25.0);
187 
188  if(audio_save_enable) {
189  audio_file2.write((char*) demod_out, audio_buffer_size * sizeof(std::complex<float>));
190  }
191  for(i = 0; i < audio_buffer_size; i++) {
192  audio_buffer[i] = demod_out[i].real();
193  }
194  // do a median filter to eliminate the pops.
195  // maybe not... fmMedianFilter.apply(audio_buffer, audio_buffer, audio_buffer_size);
196 
197  // then send it to the audio port.
198  pendAudioBuffer(audio_buffer);
199 }
200 
202 {
203  // now allocate a new audio buffer from the buffer ring
204  float * audio_buffer = getFreeAudioBuffer();
205 
206  // shift the Q channel by pi/2
207  // note that this hilbert filter transforms the Q channel and delays the I channel
208  hilbert->applyIQ(dbuf, dbuf);
209 
210  // then add/subtract I/Q to a single real channel
211  float sbmul = ((mod == SoDa::Command::LSB) || (mod == SoDa::Command::CW_L)) ? 1.0 : -1.0;
212  unsigned int i;
213  for(i = 0; i < audio_buffer_size; i++) {
214  audio_buffer[i] = (float) (dbuf[i].real() + sbmul * dbuf[i].imag());
215  }
216  // then send it to the audio port.
217  pendAudioBuffer(audio_buffer);
218 }
219 
220 void SoDa::BaseBandRX::demodulateAM(std::complex<float> * dbuf)
221 {
222  // now allocate a new audio buffer from the buffer ring
223  float * audio_buffer = getFreeAudioBuffer();
224 
225  unsigned int i;
226  float maxval = 0.0;
227  float sumsq = 0.0;
228  for(i = 0; i < audio_buffer_size; i++) {
229  float v = 0.5 * abs(dbuf[i]);
230  if(v > maxval) maxval = v;
231  sumsq += v * v;
232  audio_buffer[i] = v;
233  }
234  sumsq = sqrt(sumsq / ((float) audio_buffer_size));
235  // if((dbg_ctr & 0xff) == 0) {
236  // std::cerr << boost::format("maxval = %f rms = %f\n") % maxval % sumsq;
237  // }
238 
239  // audio is biased above DC... it really really needs to get its DC component removed.
240  am_audio_filter->apply(audio_buffer, audio_buffer);
241 
242  // then send it to the audio port.
243  pendAudioBuffer(audio_buffer);
244 }
245 
247 {
248  // First we downsample and apply the audio filter unless this is a WBFM signal.
249  std::complex<float> dbufi[audio_buffer_size];
250  std::complex<float> dbufo[audio_buffer_size];
251  // Note that audio_buffer_size must be (sample_length / decimation rate)
252 
254  rf_resampler->apply(rxbuf->getComplexBuf(), dbufi);
255 
256  // now do the low pass filter
258  am_pre_filter->apply(dbufi, dbufo, *cur_af_gain);
259  }
260  else {
261  cur_audio_filter->apply(dbufi, dbufo, *cur_af_gain);
262  }
263  }
264  else if(rx_modulation == SoDa::Command::NBFM) {
265  // first, bandpass the RF down to about 25 kHz wide...
266  std::complex<float> * rfbuf = rxbuf->getComplexBuf();
267  nbfm_pre_filter->apply(rfbuf, rfbuf, 1.0);
268  rf_resampler->apply(rfbuf, dbufo);
269  }
270 
271 
272  switch(rx_modulation) {
273  case SoDa::Command::LSB:
274  case SoDa::Command::CW_L:
276  break;
277  case SoDa::Command::USB:
278  case SoDa::Command::CW_U:
280  break;
281  case SoDa::Command::NBFM:
283  break;
284  case SoDa::Command::WBFM:
286  break;
287  case SoDa::Command::AM:
288  demodulateAM(dbufo);
289  break;
290  default:
291  // all other modes are unsupported just for now.
292  throw(new SoDa::SoDaException("Unsupported Modulation Mode in RX", this));
293  break;
294  }
295 }
296 
298  std::pair<double, double> fshape = cur_audio_filter->getFilterEdges();
299  switch (rx_modulation) {
300  case SoDa::Command::USB:
301  case SoDa::Command::CW_U:
303  fshape.first, fshape.second));
304  break;
305  case SoDa::Command::LSB:
306  case SoDa::Command::CW_L:
308  -fshape.first, -fshape.second));
309  break;
310  case SoDa::Command::AM:
312  -fshape.second, fshape.second));
313  break;
314  default:
316  -100, 100));
317 
318  }
319 }
320 
322 {
325  switch (cmd->target) {
328  repAFFilterShape();
329  break;
331  txmod = SoDa::Command::ModulationType(cmd->iparms[0]);
332  if((txmod == SoDa::Command::CW_L) || (txmod == SoDa::Command::CW_U)) {
334  }
335  else {
336  sidetone_stream_enabled = false;
337  }
338  break;
339  case SoDa::Command::TX_STATE: // SET TX_ON
340  if(cmd->iparms[0] == 1) {
341  // flush the audio buffers that have RX info that we
342  // aren't going to need anymore.
343  debugMsg("In TX ON");
346  debugMsg("sidetone mode\n");
348  }
349  else {
350  audio_rx_stream_enabled = false;
351  debugMsg("audio_rx_stream_enabled = false\n");
352  audio_ifc->sleepOut();
353  }
354  }
355  if(cmd->iparms[0] == 2) { // the CTRL unit has done the setup....
356  debugMsg("In RX ON");
357  cur_af_gain = &af_gain;
359  debugMsg("audio_rx_stream_enabled = true\n");
360  // audio_rx_stream_needs_start = true;
362  audio_ifc->wakeOut();
363  }
364  break;
365  case SoDa::Command::RX_AF_FILTER: // set af filter bw.
366  fbw = (SoDa::Command::AudioFilterBW) cmd->iparms[0];
367  if(filter_map.find(fbw) != filter_map.end()) {
369  af_filter_selection = fbw;
370  }
371  else {
372  // if unsupported -- use widest.
375  }
376  {
380  }
381  break;
382  case SoDa::Command::RX_AF_GAIN: // set audio gain.
383  af_gain = powf(10.0, 0.25 * (cmd->dparms[0] - 50.0));
385  50. + 4.0 * log10(af_gain)));
386  break;
387  case SoDa::Command::RX_AF_SIDETONE_GAIN: // set audio gain.
388  af_sidetone_gain = powf(10.0, 0.25 * (cmd->dparms[0] - 50.0));
390  50. + 4.0 * log10(af_sidetone_gain)));
391  break;
392  default:
393  break;
394  }
395 }
396 
398 {
399  switch (cmd->target) {
400  case SoDa::Command::RX_AF_FILTER: // set af filter bw.
403  break;
404  case SoDa::Command::RX_AF_GAIN: // set af filter bw.
406  50.0 + 4.0 * log10(af_gain)));
407  break;
408  case SoDa::Command::DBG_REP: // report status
410  us = SoDa::Command::UnitSelector(cmd->iparms[0]);
411  if(us == SoDa::Command::BaseBandRX) {
412  std::cerr << boost::format("%s ready_buffers.size = %d free_buffers.size = %d\n") % getObjName() % readyAudioBuffers() % free_buffers.size();
413  }
414  break;
415  default:
416  break;
417  }
418 
419 }
420 
422 {
423  (void) cmd;
424 }
425 
427 {
428  bool exitflag = false;
429  SoDaBuf * rxbuf;
430  Command * cmd;
431 
432  int rxbufcount = 0;
433  int afbufcount = 0;
434 
435  int trim_count = 0;
436  int add_count = 0;
437 
438  int null_audio_buf_count = 0;
439  int sleep_count = 0;
440  int catchup_count = 0;
441 
442  int restart_count = 0;
443  while(!exitflag) {
444  bool did_work = false;
445  bool did_audio_work = false;
446  if((cmd = cmd_stream->get(cmd_subs)) != NULL) {
447  // process the command.
448  execCommand(cmd);
449  did_work = true;
450  exitflag |= (cmd->target == Command::STOP);
451  cmd_stream->free(cmd);
452  }
453 
455  if(readyAudioBuffers()) {
456  if(!in_catchup && (readyAudioBuffers() > 8)) {
457  // If we've fallen 8 buffers behind, (about 400mS)
458  // then go into catchup mode, where we'll gain about 0.4 mS
459  // on each 2304 sample frame.
460  in_catchup = true;
461  in_fallback = false;
462  catchup_count++;
463  }
464  if(in_catchup && (readyAudioBuffers() < 2)) {
465  in_catchup = false;
466  }
467 #if 0
468  if(!in_fallback && (readyAudioBuffers() < 3)) {
469  in_fallback = true;
470  in_catchup = false;
471  fallback_count++;
472  }
473  if(in_fallback && (readyAudioBuffers() > 5)) {
474  in_fallback = false;
475  }
476 #endif
477  int rbsize = readyAudioBuffers();
478  if((audio_rx_stream_needs_start && (rbsize > 1)) ||
479  (!audio_rx_stream_needs_start && (rbsize > 1))) {
480 
482  audio_ifc->wakeOut();
484  restart_count++;
485  }
486 
487  while(1) {
489  float * outb = getNextAudioBuffer();
490  if(outb == NULL) {
491  break;
492  }
493 
494  did_work = true;
495  did_audio_work = true;
496 
497  if(in_catchup) {
498  // this is where the random generator comes in.
499  int trim = (random() & catchup_rand_mask);
500  // drop out one "randomly" selected sample in the first (power of two) part of the buffer.
501  audio_ifc->send(outb, trim);
502  audio_ifc->send(&(outb[trim+1]), (audio_buffer_size - (trim + 1)));
503  trim_count++;
504  }
505  else if(in_fallback) {
506  // duplicate one "randomly" selected sample in the first (power of two) part of the buffer.
507  int dup = (random() & catchup_rand_mask);
508  audio_ifc->send(outb, dup);
509  audio_ifc->send(&(outb[dup]), (audio_buffer_size - dup));
510  add_count++;
511  }
512  else {
514  }
515 
516  // is this a problem? Is it possible to free the buffer too soon?
517  freeAudioBuffer(outb);
518 
519  afbufcount++;
520  }
521  else {
522  null_audio_buf_count++;
523  if(rbsize > 10) {
524  // what is the state of the audio ifc?
525  debugMsg(boost::format("ALSA State [%s] rbsize = %d\n") % audio_ifc->currentPlaybackState() % rbsize);
526  }
527  break;
528  }
529  }
530  }
531  }
532  int bcount = 0;
533  for(bcount = 0; (bcount < 2) && ((rxbuf = rx_stream->get(rx_subs)) != NULL); bcount++) {
534  if(rxbuf == NULL) break;
535  did_work = true;
536  // demodulate the buffer.
537  demodulate(rxbuf);
538  // now free the buffer up.
539  rx_stream->free(rxbuf);
540  rxbufcount++;
541  }
542  }
543 
544  if(!did_audio_work && !did_work) {
545  usleep(1000);
546  sleep_count++;
547  }
548  }
549  // close(outdump);
550 
551  if(audio_save_enable) {
552  audio_file.close();
553  audio_file2.close();
554  }
555 }
556 
557 
559  boost::mutex::scoped_lock lock(free_lock);
560  free_buffers.push(b);
561 }
562 
564  float * ret;
565  boost::mutex::scoped_lock lock(free_lock);
566  if(free_buffers.empty()) {
567  ret = new float[audio_buffer_size];
568  }
569  else {
570  ret = free_buffers.front();
571  free_buffers.pop();
572  }
573  return ret;
574 }
575 
577 {
578  boost::mutex::scoped_lock lock(ready_lock);
579  return ready_buffers.size();
580 }
581 
583 {
584  {
585  boost::mutex::scoped_lock lock(ready_lock);
586  ready_buffers.push(b);
587  }
588  if(audio_save_enable) {
589  audio_file.write((char*) b, audio_buffer_size * sizeof(float));
590  }
591 }
592 
594 {
595  boost::mutex::scoped_lock lock(ready_lock);
596  if(ready_buffers.empty()) return NULL;
597  float * ret;
598  ret = ready_buffers.front();
599  ready_buffers.pop();
600  return ret;
601 }
602 
604 {
605  boost::mutex::scoped_lock lock(ready_lock);
606  while(!ready_buffers.empty()) {
607  float * v = ready_buffers.front();
608  ready_buffers.pop();
609  freeAudioBuffer(v);
610  }
611  return;
612 }
613 
615 {
616  // Each filter is 512 samples long... (a really big filter)
617  // The Overlap and Save buffer needs to be long enough to make this all
618  // work
619 
620  filter_map[SoDa::Command::BW_2000] = new SoDa::OSFilter(200.0, 300.0, 2300.0, 2400.0, 512, 1.0, audio_sample_rate, audio_buffer_size);
621  filter_map[SoDa::Command::BW_500] = new SoDa::OSFilter(300.0, 400.0, 900.0, 1000.0, 512, 1.0, audio_sample_rate, audio_buffer_size);
622 
623  filter_map[SoDa::Command::BW_100] = new SoDa::OSFilter(300.0, 400.0, 500.0, 600.0, 512, 1.0, audio_sample_rate, audio_buffer_size);
624 
625  filter_map[SoDa::Command::BW_6000] = new SoDa::OSFilter(200.0, 300.0, 6300.0, 6400.0, 512, 1.0, audio_sample_rate, audio_buffer_size);
626  filter_map[SoDa::Command::BW_PASS] = new SoDa::OSFilter(0.0, 10.0, 15000.0, 18000.0, 512, 1.0, audio_sample_rate, audio_buffer_size);
627 
628  fm_audio_filter = new SoDa::OSFilter(50.0, 100.0, 8000.0, 9000.0, 512, 1.0, audio_sample_rate, audio_buffer_size);
630 
631  am_pre_filter = new SoDa::OSFilter(0.0, 0.0, 8000.0, 9000.0, 512, 1.0, audio_sample_rate, audio_buffer_size);
632 
633  nbfm_pre_filter = new SoDa::OSFilter(0.0, 0.0, 25000.0, 32000.0, 512, 1.0, rf_sample_rate, rf_buffer_size);
634 
635 
636 }
The Thread baseclass for all SoDa thread objects.
Definition: SoDaBase.hxx:284
This is an overlap-and-save frequency domain implementation of a general FIR filter widget...
void debugMsg(const std::string &msg, unsigned int threshold=1)
Definition: Debug.hxx:64
turn transmitter on and off.
Definition: Command.hxx:197
RX audio gain setting.
Definition: Command.hxx:175
UnitSelector
a selector to identify a particular unit for debug reports
Definition: Command.hxx:488
T * get(unsigned int subscriber_id)
Definition: MultiMBox.hxx:110
unsigned int rf_buffer_size
size of input RF buffer chunk
Definition: BaseBandRX.hxx:174
void demodulateSSB(std::complex< float > *drxbuf, SoDa::Command::ModulationType mod)
demodulate the input stream as an SSB signal place the resulting audio buffer on the audio output que...
Definition: BaseBandRX.cxx:201
std::string & getObjName()
get the name of this object
Definition: SoDaBase.hxx:182
SoDa::OSFilter * am_audio_filter
After AM demod, we do a second filter.
Definition: BaseBandRX.hxx:258
bool in_fallback
when true, the audio server has gotten ahead...
Definition: BaseBandRX.hxx:232
float af_gain
audio gain setting for RX mode
Definition: BaseBandRX.hxx:268
Set the modulation mode for the receive chain.
Definition: Command.hxx:251
float * getNextAudioBuffer()
return the next queued audio buffer to pass to the audio output device
Definition: BaseBandRX.cxx:593
void demodulateAM(std::complex< float > *drxbuf)
demodulate the input stream as an amplitude modulated signal place the resulting audio buffer on the ...
Definition: BaseBandRX.cxx:220
Resampler for 625KHz to 48KHz data stream, built on rational ReSampler class.
BaseBandRX(Params *params, DatMBox *rx_stream, CmdMBox *cmd_stream, AudioIfc *audio_ifc)
the constructor
Definition: BaseBandRX.cxx:37
int iparms[4]
integer parameters
Definition: Command.hxx:668
double getAudioSampleRate() const
Definition: Params.hxx:104
bool audio_rx_stream_enabled
if true, send pending audio buffers to output
Definition: BaseBandRX.hxx:177
Set the modulation mode for the transmit chain.
Definition: Command.hxx:259
virtual int send(void *buf, unsigned int len)=0
send – send a buffer to the audio output
This class handles command line parameters and built-ins.
Definition: Params.hxx:42
The SoDa Exception class.
Definition: SoDaBase.hxx:217
In several places we have a real valued signal x(t) that needs to be converted to an analytic signal ...
void flushAudioBuffers()
empty the queue of pending audio buffers, we&#39;re going into TX mode.
Definition: BaseBandRX.cxx:603
void demodulateWBFM(SoDaBuf *rxbuf, SoDa::Command::ModulationType mod, float af_gain)
demodulate the input stream as a wideband frequency modulated signal place the resulting audio buffer...
Definition: BaseBandRX.cxx:123
CmdTarget target
the thing we&#39;re touching
Definition: Command.hxx:673
Initiate a debug dump.
Definition: Command.hxx:353
SoDa::ReSample625to48 * wbfm_resampler
downsample the RF input to 48KS/s for WBFM unit
Definition: BaseBandRX.hxx:246
void demodulate(SoDaBuf *rxbuf)
apply the currently selected demodulation scheme to the input RX buffer place the resulting audio buf...
Definition: BaseBandRX.cxx:246
double getRXRate() const
Sample rates and all that other stuff are fixed.
Definition: Params.hxx:98
The Buffer Class.
Definition: SoDaBase.hxx:72
void apply(std::complex< float > *in, std::complex< float > *out)
Perform the resampling on a complex float buffer.
bool sidetone_stream_enabled
if true, send CW sidetone to audio output
Definition: BaseBandRX.hxx:179
virtual std::string currentPlaybackState()
Definition: AudioIfc.hxx:165
unsigned int getRFBufferSize() const
Definition: Params.hxx:105
std::queue< float * > free_buffers
a pool of free audio buffers
Definition: BaseBandRX.hxx:235
On receipt of a STOP command, all threads should exit their run loop.
Definition: Command.hxx:371
SoDa::OSFilter * am_pre_filter
Before AM demod, we do some (6KHz) prefilter.
Definition: BaseBandRX.hxx:256
double audio_sample_rate
sample rate of audio output – assumed 48KHz
Definition: BaseBandRX.hxx:175
std::complex< float > * getComplexBuf()
Return a pointer to the storage buffer of complex floats.
Definition: SoDaBase.hxx:133
SoDa::Command::AudioFilterBW af_filter_selection
currently audio filter selector
Definition: BaseBandRX.hxx:253
This is a list of all the commands that can "do something" to one or more components in the SoDa radi...
Definition: Command.hxx:47
virtual bool sendBufferReady(unsigned int len)=0
sendBufferReady – is there enough space in the audio device send buffer for a call from send...
boost::mutex free_lock
lock for the free_buffers pool
Definition: BaseBandRX.hxx:238
unsigned int getAFBufferSize() const
Definition: Params.hxx:106
DatMBox * rx_stream
mailbox producing rx sample stream from USRP
Definition: BaseBandRX.hxx:183
CmdMBox * cmd_stream
mailbox producing command stream from user
Definition: BaseBandRX.hxx:184
AudioFilterBW
these are the possible audio filter bandwidths
Definition: Command.hxx:483
ModulationType
modulation selector targets take one of these values
Definition: Command.hxx:478
SoDa::OSFilter * fm_audio_filter
audio filter for FM (wider passband)
Definition: BaseBandRX.hxx:255
SoDa::Command::ModulationType rx_modulation
current receive modulation mode (USB,LSB,CW_U,CW_L,NBFM,WBFM,AM,...)
Definition: BaseBandRX.hxx:181
unsigned int audio_buffer_size
size of output audio buffer chunk
Definition: BaseBandRX.hxx:173
SoDa::HilbertTransformer * hilbert
hilbert transform object for SSB/CW widgets
Definition: BaseBandRX.hxx:265
void freeAudioBuffer(float *b)
add an audio buffer to the free list, we&#39;ve dispatched it.
Definition: BaseBandRX.cxx:558
unsigned int applyIQ(std::complex< float > *inbuf, std::complex< float > *outbuf, float gain=1.0)
Perform a hilbert transform on the QUADRATURE signal in the input buffer.
unsigned int dbg_ctr
debug counter, used to support one-time or infrequent bulletins
Definition: BaseBandRX.hxx:279
SoDa::OSFilter * nbfm_pre_filter
Before NBFM demod, we do some (15KHz) prefilter – rf rate.
Definition: BaseBandRX.hxx:257
void demodulateNBFM(std::complex< float > *drxbuf, SoDa::Command::ModulationType mod, float af_gain)
demodulate the input stream as a narrowband frequency modulated signal place the resulting audio buff...
Definition: BaseBandRX.cxx:160
void buildFilterMap()
build the audio filter map for selected bandwidths
Definition: BaseBandRX.cxx:614
boost::mutex ready_lock
lock for the ready_buffers_pool
Definition: BaseBandRX.hxx:239
unsigned int cmd_subs
mailbox subscription ID for command stream
Definition: BaseBandRX.hxx:186
void free(T *m)
Definition: MultiMBox.hxx:118
double rf_sample_rate
sample rate of RF input from USRP – assumed 625KHz
Definition: BaseBandRX.hxx:176
void execGetCommand(Command *cmd)
execute GET commands from the command channel
Definition: BaseBandRX.cxx:397
int readyAudioBuffers()
return number audio buffers available
Definition: BaseBandRX.cxx:576
double dparms[4]
double float parameters
Definition: Command.hxx:669
Overlap-and-save filter class.
Definition: OSFilter.hxx:50
SoDa::OSFilter * cur_audio_filter
currently selected audio filter
Definition: BaseBandRX.hxx:254
virtual void sleepOut()=0
stop the output stream so that we don&#39;t encounter a buffer underflow while the reciever is muted...
virtual void wakeOut()=0
start the output stream
std::map< SoDa::Command::AudioFilterBW, SoDa::OSFilter * > filter_map
map filter selectors to the filter objects
Definition: BaseBandRX.hxx:262
AudioIfc * audio_ifc
pointer to the audio interface (output) object
Definition: BaseBandRX.hxx:188
std::ofstream audio_file
Definition: BaseBandRX.hxx:284
void execSetCommand(Command *cmd)
handle SET commands from the command channel
Definition: BaseBandRX.cxx:321
SoDa::ReSample625to48 * rf_resampler
downsample the RF input to 48KS/s
Definition: BaseBandRX.hxx:244
void pendAudioBuffer(float *b)
put an audio buffer on the "pending for output" list
Definition: BaseBandRX.cxx:582
Generic Audio Interface Class.
Definition: AudioIfc.hxx:44
std::ofstream audio_file2
Definition: BaseBandRX.hxx:285
RX audio gain for sidetone (CW) monitor.
Definition: Command.hxx:182
unsigned int apply(std::complex< float > *inbuf, std::complex< float > *outbuf, float outgain=1.0)
run the filter on a complex input stream
Definition: OSFilter.cxx:334
float af_sidetone_gain
audio gain setting for TX/CW mode
Definition: BaseBandRX.hxx:269
void repAFFilterShape()
send a report of the lower and upper edges of the IF passband based on the current filter and modulat...
Definition: BaseBandRX.cxx:297
std::pair< double, double > getFilterEdges()
Definition: OSFilter.hxx:117
bool in_catchup
when true, the audio server has fallen behind...
Definition: BaseBandRX.hxx:231
float * getFreeAudioBuffer()
remove a buffer from the free list, or allocate one if the free list is empty.
Definition: BaseBandRX.cxx:563
float * cur_af_gain
pointer to the gain setting for this mode
Definition: BaseBandRX.hxx:270
void put(T *m)
Definition: MultiMBox.hxx:97
float last_phase_samp
history value used to calculate dPhase/dt in FM atan based discriminator.
Definition: BaseBandRX.hxx:273
unsigned int catchup_rand_mask
a mask to use for fast selection of a random index into an audio buffer.
Definition: BaseBandRX.hxx:233
std::queue< float * > ready_buffers
a list of audio buffers ready to send to the output
Definition: BaseBandRX.hxx:236
unsigned int rx_subs
mailbox subscription ID for rx data stream
Definition: BaseBandRX.hxx:185
void execCommand(Command *cmd)
Execute (dispatch) a message removed from the command stream to one of the basic Command handler func...
Definition: SoDaBase.hxx:335
void run()
the run method – does the work of the audio receiver process
Definition: BaseBandRX.cxx:426
bool audio_rx_stream_needs_start
if true, the audio output device needs a wakeup
Definition: BaseBandRX.hxx:178
void execRepCommand(Command *cmd)
handle Report commands from the command channel
Definition: BaseBandRX.cxx:421
float * sidetone_silence
a sequence of zero samples to stuff silence into the audio
Definition: BaseBandRX.hxx:241