/* * 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++]); } }