You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
147 lines
4.4 KiB
147 lines
4.4 KiB
/*
|
|
* Copyright (C) 2014 by Jonathan Naylor, G4KLX
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; version 2 of the License.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*/
|
|
|
|
#include "DongleThread.h"
|
|
#include "DStarDefines.h"
|
|
#include "Bleeper.h"
|
|
|
|
// A 3 kHz low pass filter at a sample rate of 48000 samples/sec. Calculated by the fir1 command in
|
|
// MATLAB.
|
|
const wxFloat32 FIR_TAPS[] = {
|
|
0.001215122399171F, 0.001363519692447F, 0.001447384226195F, 0.001287712318712F, 0.000614680825630F,
|
|
-0.000833383976996F, -0.003176495118124F, -0.006261958697776F, -0.009578203328048F, -0.012249770207721F,
|
|
-0.013132705407240F, -0.011005254575316F, -0.004822958879920F, 0.006013373011413F, 0.021438048217733F,
|
|
0.040605942188804F, 0.061921094815680F, 0.083217403172960F, 0.102067175368858F, 0.116163746412471F,
|
|
0.123705527541065F, 0.123705527541065F, 0.116163746412471F, 0.102067175368858F, 0.083217403172960F,
|
|
0.061921094815680F, 0.040605942188804F, 0.021438048217733F, 0.006013373011413F, -0.004822958879920F,
|
|
-0.011005254575316F, -0.013132705407240F, -0.012249770207721F, -0.009578203328048F, -0.006261958697776F,
|
|
-0.003176495118124F, -0.000833383976996F, 0.000614680825630F, 0.001287712318712F, 0.001447384226195F,
|
|
0.001363519692447F, 0.001215122399171F};
|
|
|
|
const unsigned int FIR_LEN = 42U;
|
|
|
|
const wxFloat32 UPSAMPLE_AMP = 6.0F;
|
|
const wxFloat32 DOWNSAMPLE_AMP = 0.9F;
|
|
|
|
CDongleThread::CDongleThread() :
|
|
wxThread(wxTHREAD_JOINABLE),
|
|
m_encodeCallback(NULL),
|
|
m_decodeCallback(NULL),
|
|
m_encodeAudio(DSTAR_RADIO_BLOCK_SIZE * 30U),
|
|
m_decodeData(VOICE_FRAME_LENGTH_BYTES * 30U),
|
|
m_bleep(true),
|
|
m_killed(false),
|
|
m_filter(FIR_TAPS, FIR_LEN)
|
|
{
|
|
}
|
|
|
|
CDongleThread::~CDongleThread()
|
|
{
|
|
}
|
|
|
|
void CDongleThread::setEncodeCallback(IEncodeCallback* callback)
|
|
{
|
|
wxASSERT(callback != NULL);
|
|
|
|
m_encodeCallback = callback;
|
|
}
|
|
|
|
void CDongleThread::setDecodeCallback(IDecodeCallback* callback)
|
|
{
|
|
wxASSERT(callback != NULL);
|
|
|
|
m_decodeCallback = callback;
|
|
}
|
|
|
|
unsigned int CDongleThread::getEncodeSpace() const
|
|
{
|
|
return m_encodeAudio.freeSpace();
|
|
}
|
|
|
|
unsigned int CDongleThread::getDecodeSpace() const
|
|
{
|
|
return m_decodeData.freeSpace();
|
|
}
|
|
|
|
unsigned int CDongleThread::writeEncode(const wxFloat32* audio, unsigned int length)
|
|
{
|
|
wxASSERT(audio != NULL);
|
|
|
|
return m_encodeAudio.addData(audio, length);
|
|
}
|
|
|
|
unsigned int CDongleThread::writeDecode(const unsigned char* ambe, unsigned int length)
|
|
{
|
|
wxASSERT(ambe != NULL);
|
|
|
|
return m_decodeData.addData(ambe, length);
|
|
}
|
|
|
|
void CDongleThread::setBleep(bool on)
|
|
{
|
|
m_bleep = on;
|
|
}
|
|
|
|
void CDongleThread::kill()
|
|
{
|
|
m_killed = true;
|
|
|
|
Wait();
|
|
}
|
|
|
|
void CDongleThread::reset()
|
|
{
|
|
m_filter.reset();
|
|
}
|
|
|
|
void CDongleThread::sendBleep()
|
|
{
|
|
wxFloat32 audio[DSTAR_RADIO_BLOCK_SIZE];
|
|
unsigned int n;
|
|
|
|
CBleeper bleep(DSTAR_RADIO_SAMPLE_RATE, DSTAR_BLEEP_FREQ, DSTAR_BLEEP_LENGTH, DSTAR_BLEEP_AMPL);
|
|
|
|
while ((n = bleep.getAudio(audio, DSTAR_RADIO_BLOCK_SIZE)) > 0U)
|
|
m_decodeCallback->decodeCallback(audio, n);
|
|
}
|
|
|
|
// Convert from 8000 samples/sec to 48000 samples/sec
|
|
void CDongleThread::upSample(const wxFloat32* audioIn, wxFloat32* audioOut)
|
|
{
|
|
unsigned int out = 0U;
|
|
for (unsigned int in = 0U; in < DSTAR_AUDIO_BLOCK_SIZE; in++) {
|
|
audioOut[out++] = m_filter.process(audioIn[in]) * UPSAMPLE_AMP;
|
|
|
|
audioOut[out++] = m_filter.process(0.0F) * UPSAMPLE_AMP;
|
|
audioOut[out++] = m_filter.process(0.0F) * UPSAMPLE_AMP;
|
|
audioOut[out++] = m_filter.process(0.0F) * UPSAMPLE_AMP;
|
|
audioOut[out++] = m_filter.process(0.0F) * UPSAMPLE_AMP;
|
|
audioOut[out++] = m_filter.process(0.0F) * UPSAMPLE_AMP;
|
|
}
|
|
}
|
|
|
|
// Convert from 48000 samples/sec to 8000 samples/sec
|
|
void CDongleThread::downSample(const wxFloat32* audioIn, wxFloat32* audioOut)
|
|
{
|
|
unsigned int in = 0U;
|
|
for (unsigned int out = 0U; out < DSTAR_AUDIO_BLOCK_SIZE; out++) {
|
|
audioOut[out] = m_filter.process(audioIn[in++]) * DOWNSAMPLE_AMP;
|
|
|
|
m_filter.process(audioIn[in++]);
|
|
m_filter.process(audioIn[in++]);
|
|
m_filter.process(audioIn[in++]);
|
|
m_filter.process(audioIn[in++]);
|
|
m_filter.process(audioIn[in++]);
|
|
}
|
|
}
|