SDRAngel  4.11.5
Developer docs for <a href="https://github.com/f4exb/sdrangel">SDRangel<\a>, an Open Source Qt5 / OpenGL 3.0+ SDR and signal analyzer frontend to various hardware.
ambeworker.cpp
Go to the documentation of this file.
1 // Copyright (C) 2019 F4EXB //
3 // written by Edouard Griffiths //
4 // //
5 // This program is free software; you can redistribute it and/or modify //
6 // it under the terms of the GNU General Public License as published by //
7 // the Free Software Foundation as version 3 of the License, or //
8 // (at your option) any later version. //
9 // //
10 // This program is distributed in the hope that it will be useful, //
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of //
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
13 // GNU General Public License V3 for more details. //
14 // //
15 // You should have received a copy of the GNU General Public License //
16 // along with this program. If not, see <http://www.gnu.org/licenses/>. //
18 
19 #include <algorithm>
20 #include <chrono>
21 #include <thread>
22 
23 #include "audio/audiofifo.h"
24 #include "ambeworker.h"
25 
28 
30  m_running(false),
31  m_currentGainIn(0),
32  m_currentGainOut(0),
33  m_upsamplerLastValue(0.0f),
34  m_phase(0),
35  m_upsampling(1),
36  m_volume(1.0f)
37 {
38  m_audioBuffer.resize(48000);
39  m_audioBufferFill = 0;
40  m_audioFifo = 0;
41  std::fill(m_dvAudioSamples, m_dvAudioSamples+SerialDV::MBE_AUDIO_BLOCK_SIZE, 0);
42  setVolumeFactors();
43 }
44 
46 {}
47 
48 bool AMBEWorker::open(const std::string& deviceRef)
49 {
50  return m_dvController.open(deviceRef);
51 }
52 
54 {
55  m_dvController.close();
56 }
57 
59 {
60  m_running = true;
61  qDebug("AMBEWorker::process: started");
62 
63  while (m_running)
64  {
65  std::this_thread::sleep_for(std::chrono::seconds(1));
66  }
67 
68  qDebug("AMBEWorker::process: stopped");
69  emit finished();
70 }
71 
73 {
74  m_running = false;
75 }
76 
78 {
79  Message* message;
81  AudioFifo *audioFifo = 0;
82 
83  while ((message = m_inputMessageQueue.pop()) != 0)
84  {
85  if (MsgMbeDecode::match(*message))
86  {
87  MsgMbeDecode *decodeMsg = (MsgMbeDecode *) message;
88  int dBVolume = (decodeMsg->getVolumeIndex() - 30) / 4;
89  float volume = pow(10.0, dBVolume / 10.0f);
90  int upsampling = decodeMsg->getUpsampling();
91  upsampling = upsampling > 6 ? 6 : upsampling < 1 ? 1 : upsampling;
92 
93  if ((volume != m_volume) || (upsampling != m_upsampling))
94  {
95  m_volume = volume;
96  m_upsampling = upsampling;
98  }
99 
100  m_upsampleFilter.useHP(decodeMsg->getUseHP());
101 
102  if (m_dvController.decode(m_dvAudioSamples, decodeMsg->getMbeFrame(), decodeMsg->getMbeRate()))
103  {
104  if (upsampling > 1) {
105  upsample(upsampling, m_dvAudioSamples, SerialDV::MBE_AUDIO_BLOCK_SIZE, decodeMsg->getChannels());
106  } else {
107  noUpsample(m_dvAudioSamples, SerialDV::MBE_AUDIO_BLOCK_SIZE, decodeMsg->getChannels());
108  }
109 
110  audioFifo = decodeMsg->getAudioFifo();
111 
112  if (audioFifo && (m_audioBufferFill >= m_audioBuffer.size() - 960))
113  {
114  uint res = audioFifo->write((const quint8*)&m_audioBuffer[0], m_audioBufferFill);
115 
116  if (res != m_audioBufferFill) {
117  qDebug("AMBEWorker::handleInputMessages: %u/%u audio samples written", res, m_audioBufferFill);
118  }
119 
120  m_audioBufferFill = 0;
121  }
122  }
123  else
124  {
125  qDebug("AMBEWorker::handleInputMessages: MsgMbeDecode: decode failed");
126  }
127  }
128 
129  delete message;
130 
131  if (m_inputMessageQueue.size() > 100)
132  {
133  qDebug("AMBEWorker::handleInputMessages: MsgMbeDecode: too many messages in queue. Flushing...");
135  break;
136  }
137  }
138 
139  if (audioFifo)
140  {
141  uint res = audioFifo->write((const quint8*)&m_audioBuffer[0], m_audioBufferFill);
142 
143  if (res != m_audioBufferFill) {
144  qDebug("AMBEWorker::handleInputMessages: %u/%u audio samples written", res, m_audioBufferFill);
145  }
146 
147  m_audioBufferFill = 0;
148  }
149 
150  m_timestamp = QDateTime::currentDateTime();
151 }
152 
153 void AMBEWorker::pushMbeFrame(const unsigned char *mbeFrame,
154  int mbeRateIndex,
155  int mbeVolumeIndex,
156  unsigned char channels,
157  bool useHP,
158  int upsampling,
159  AudioFifo *audioFifo)
160 {
161  m_audioFifo = audioFifo;
162  m_inputMessageQueue.push(MsgMbeDecode::create(mbeFrame, mbeRateIndex, mbeVolumeIndex, channels, useHP, upsampling, audioFifo));
163 }
164 
166 {
167  if (m_audioFifo == 0) {
168  return true;
169  }
170 
171  return m_timestamp.time().msecsTo(QDateTime::currentDateTime().time()) > 1000; // 1 second inactivity timeout
172 }
173 
175 {
176  return m_audioFifo == audioFifo;
177 }
178 
179 void AMBEWorker::upsample(int upsampling, short *in, int nbSamplesIn, unsigned char channels)
180 {
181  for (int i = 0; i < nbSamplesIn; i++)
182  {
183  //float cur = m_upsampleFilter.usesHP() ? m_upsampleFilter.runHP((float) m_compressor.compress(in[i])) : (float) m_compressor.compress(in[i]);
184  float cur = m_upsampleFilter.usesHP() ? m_upsampleFilter.runHP((float) in[i]) : (float) in[i];
185  float prev = m_upsamplerLastValue;
186  qint16 upsample;
187 
188  for (int j = 1; j <= upsampling; j++)
189  {
190  upsample = (qint16) m_upsampleFilter.runLP(cur*m_upsamplingFactors[j] + prev*m_upsamplingFactors[upsampling-j]);
191  m_audioBuffer[m_audioBufferFill].l = channels & 1 ? m_compressor.compress(upsample) : 0;
192  m_audioBuffer[m_audioBufferFill].r = (channels>>1) & 1 ? m_compressor.compress(upsample) : 0;
193 
194  if (m_audioBufferFill < m_audioBuffer.size() - 1) {
196  }
197  }
198 
199  m_upsamplerLastValue = cur;
200  }
201 
202  if (m_audioBufferFill >= m_audioBuffer.size() - 1) {
203  qDebug("AMBEWorker::upsample(%d): audio buffer is full check its size", upsampling);
204  }
205 }
206 
207 void AMBEWorker::noUpsample(short *in, int nbSamplesIn, unsigned char channels)
208 {
209  for (int i = 0; i < nbSamplesIn; i++)
210  {
211  float cur = m_upsampleFilter.usesHP() ? m_upsampleFilter.runHP((float) in[i]) : (float) in[i];
212  m_audioBuffer[m_audioBufferFill].l = channels & 1 ? cur*m_upsamplingFactors[0] : 0;
213  m_audioBuffer[m_audioBufferFill].r = (channels>>1) & 1 ? cur*m_upsamplingFactors[0] : 0;
214 
215  if (m_audioBufferFill < m_audioBuffer.size() - 1) {
217  }
218  }
219 
220  if (m_audioBufferFill >= m_audioBuffer.size() - 1) {
221  qDebug("AMBEWorker::noUpsample: audio buffer is full check its size");
222  }
223 }
224 
226 {
228 
229  for (int i = 1; i <= m_upsampling; i++) {
231  }
232 }
MBEAudioInterpolatorFilter m_upsampleFilter
Definition: ambeworker.h:149
Message * pop()
Pop message from queue.
AudioCompressor m_compressor
Definition: ambeworker.h:153
AudioFifo * getAudioFifo()
Definition: ambeworker.h:59
void push(Message *message, bool emitSignal=true)
Push message onto queue.
int size()
Returns queue size.
float runHP(const float &sample)
Definition: filtermbe.cpp:42
bool hasFifo(AudioFifo *audioFifo)
Definition: ambeworker.cpp:174
bool getUseHP() const
Definition: ambeworker.h:57
float runLP(const float &sample)
Definition: filtermbe.cpp:47
void clear()
Empty queue.
SerialDV::DVController m_dvController
Definition: ambeworker.h:138
void handleInputMessages()
Definition: ambeworker.cpp:77
static MsgMbeDecode * create(const unsigned char *mbeFrame, int mbeRateIndex, int volumeIndex, unsigned char channels, bool useHP, int upsampling, AudioFifo *audioFifo)
Definition: ambeworker.h:61
float m_volume
Definition: ambeworker.h:151
float m_upsamplerLastValue
Definition: ambeworker.h:147
void setVolumeFactors()
Definition: ambeworker.cpp:225
#define MESSAGE_CLASS_DEFINITION(Name, BaseClass)
Definition: message.h:52
short m_dvAudioSamples[SerialDV::MBE_AUDIO_BLOCK_SIZE]
Definition: ambeworker.h:144
int getUpsampling() const
Definition: ambeworker.h:58
unsigned char getChannels() const
Definition: ambeworker.h:56
volatile bool m_running
Definition: ambeworker.h:141
void noUpsample(short *in, int nbSamplesIn, unsigned char channels)
Definition: ambeworker.cpp:207
int32_t i
Definition: decimators.h:244
SerialDV::DVRate getMbeRate() const
Definition: ambeworker.h:54
void pushMbeFrame(const unsigned char *mbeFrame, int mbeRateIndex, int mbeVolumeIndex, unsigned char channels, bool useHP, int upsampling, AudioFifo *audioFifo)
Definition: ambeworker.cpp:153
static bool match(const Message *message)
Definition: message.cpp:45
void finished()
QDateTime m_timestamp
Definition: ambeworker.h:140
uint m_audioBufferFill
Definition: ambeworker.h:146
float m_upsamplingFactors[7]
Definition: ambeworker.h:152
void useHP(bool useHP)
Definition: filtermbe.h:70
void process()
Definition: ambeworker.cpp:58
void upsample(int upsampling, short *in, int nbSamplesIn, unsigned char channels)
Definition: ambeworker.cpp:179
AudioVector m_audioBuffer
Definition: ambeworker.h:145
void stop()
Definition: ambeworker.cpp:72
MessageQueue m_inputMessageQueue
Queue for asynchronous inbound communication.
Definition: ambeworker.h:125
int16_t compress(int16_t sample)
int m_upsampling
Definition: ambeworker.h:150
const unsigned char * getMbeFrame() const
Definition: ambeworker.h:53
bool open(const std::string &deviceRef)
Either serial device or ip:port.
Definition: ambeworker.cpp:48
uint32_t write(const quint8 *data, uint32_t numSamples)
Definition: audiofifo.cpp:66
bool isAvailable()
Definition: ambeworker.cpp:165
AudioFifo * m_audioFifo
Definition: ambeworker.h:139
int getVolumeIndex() const
Definition: ambeworker.h:55
void close()
Definition: ambeworker.cpp:53