From a448a8e4628224cb6f466986af4d0207266d36e3 Mon Sep 17 00:00:00 2001 From: f4exb Date: Sun, 10 Apr 2016 18:58:40 +0200 Subject: [PATCH] DSDplus library: interim state #3 --- dsdplus/dmr_data.cpp | 231 ++++++++++++++++++++++++++++++++ dsdplus/dmr_data.h | 49 +++++++ dsdplus/dsd_decoder.cpp | 4 +- dsdplus/dsd_decoder.h | 3 + dsdplus/dsd_mbe.cpp | 290 ++++++++++++++++++++++++++++++++++++++++ dsdplus/dsd_mbe.h | 45 +++++++ 6 files changed, 621 insertions(+), 1 deletion(-) create mode 100644 dsdplus/dmr_data.cpp create mode 100644 dsdplus/dmr_data.h create mode 100644 dsdplus/dsd_mbe.cpp create mode 100644 dsdplus/dsd_mbe.h diff --git a/dsdplus/dmr_data.cpp b/dsdplus/dmr_data.cpp new file mode 100644 index 000000000..170e83ba9 --- /dev/null +++ b/dsdplus/dmr_data.cpp @@ -0,0 +1,231 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2016 Edouard Griffiths, F4EXB. // +// // +// 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 as version 3 of the License, or // +// // +// 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 V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#include "dmr_data.h" +#include "dsd_decoder.h" + +namespace DSDplus +{ + +DSDDMRData::DSDDMRData(DSDDecoder *dsdDecoder) : + m_dsdDecoder(dsdDecoder) +{ +} + +DSDDMRData::~DSDDMRData() +{ +} + +void DSDDMRData::init() +{ + cc[4] = 0; + bursttype[4] = 0; + dibit_p = m_dsdDecoder->m_state.dibit_buf_p - 90; + + preProcess(); + + m_symbolIndex = 0; // reset +} + +void DSDDMRData::preProcess() +{ + int dibit; + + // CACH + for (int i = 0; i < 12; i++) + { + dibit = *dibit_p; + dibit_p++; + + if (m_dsdDecoder->m_opts.inverted_dmr == 1) + { + dibit = (dibit ^ 2); + } + + cachdata[i] = dibit; + + if (i == 2) + { + m_dsdDecoder->m_state.currentslot = (1 & (dibit >> 1)); // bit 1 + if (m_dsdDecoder->m_state.currentslot == 0) + { + m_dsdDecoder->m_state.slot0light[0] = '['; + m_dsdDecoder->m_state.slot0light[6] = ']'; + m_dsdDecoder->m_state.slot1light[0] = ' '; + m_dsdDecoder->m_state.slot1light[6] = ' '; + } + else + { + m_dsdDecoder->m_state.slot1light[0] = '['; + m_dsdDecoder->m_state.slot1light[6] = ']'; + m_dsdDecoder->m_state.slot0light[0] = ' '; + m_dsdDecoder->m_state.slot0light[6] = ' '; + } + } + } + + cachdata[12] = 0; + + // current slot + dibit_p += 49; + + // slot type + dibit = *dibit_p; + dibit_p++; + + if (m_dsdDecoder->m_opts.inverted_dmr == 1) + { + dibit = (dibit ^ 2); + } + + cc[0] = (1 & (dibit >> 1)) + 48; // bit 1 + cc[1] = (1 & dibit) + 48; // bit 0 + + dibit = *dibit_p; + dibit_p++; + + if (m_dsdDecoder->m_opts.inverted_dmr == 1) + { + dibit = (dibit ^ 2); + } + + cc[2] = (1 & (dibit >> 1)) + 48; // bit 1 + cc[3] = (1 & dibit) + 48; // bit 0 + + dibit = *dibit_p; + dibit_p++; + + if (m_dsdDecoder->m_opts.inverted_dmr == 1) + { + dibit = (dibit ^ 2); + } + + bursttype[0] = (1 & (dibit >> 1)) + 48; // bit 1 + bursttype[1] = (1 & dibit) + 48; // bit 0 + + dibit = *dibit_p; + dibit_p++; + + if (m_dsdDecoder->m_opts.inverted_dmr == 1) + { + dibit = (dibit ^ 2); + } + + bursttype[2] = (1 & (dibit >> 1)) + 48; // bit 1 + bursttype[3] = (1 & dibit) + 48; // bit 0 + + // parity bit + dibit_p++; + + if (strcmp(bursttype, "0000") == 0) + { + sprintf(m_dsdDecoder->m_state.fsubtype, " PI Header "); + } + else if (strcmp(bursttype, "0001") == 0) + { + sprintf(m_dsdDecoder->m_state.fsubtype, " VOICE Header "); + } + else if (strcmp(bursttype, "0010") == 0) + { + sprintf(m_dsdDecoder->m_state.fsubtype, " TLC "); + } + else if (strcmp(bursttype, "0011") == 0) + { + sprintf(m_dsdDecoder->m_state.fsubtype, " CSBK "); + } + else if (strcmp(bursttype, "0100") == 0) + { + sprintf(m_dsdDecoder->m_state.fsubtype, " MBC Header "); + } + else if (strcmp(bursttype, "0101") == 0) + { + sprintf(m_dsdDecoder->m_state.fsubtype, " MBC "); + } + else if (strcmp(bursttype, "0110") == 0) + { + sprintf(m_dsdDecoder->m_state.fsubtype, " DATA Header "); + } + else if (strcmp(bursttype, "0111") == 0) + { + sprintf(m_dsdDecoder->m_state.fsubtype, " RATE 1/2 DATA"); + } + else if (strcmp(bursttype, "1000") == 0) + { + sprintf(m_dsdDecoder->m_state.fsubtype, " RATE 3/4 DATA"); + } + else if (strcmp(bursttype, "1001") == 0) + { + sprintf(m_dsdDecoder->m_state.fsubtype, " Slot idle "); + } + else if (strcmp(bursttype, "1010") == 0) + { + sprintf(m_dsdDecoder->m_state.fsubtype, " Rate 1 DATA "); + } + else + { + sprintf(m_dsdDecoder->m_state.fsubtype, " "); + } + + // signaling data or sync + for (int i = 0; i < 24; i++) + { + dibit = *dibit_p; + dibit_p++; + + if (m_dsdDecoder->m_opts.inverted_dmr == 1) + { + dibit = (dibit ^ 2); + } + + syncdata[i] = dibit; + sync[i] = (dibit | 1) + 48; + } + + sync[24] = 0; + syncdata[24] = 0; + + if ((strcmp(sync, DMR_BS_DATA_SYNC) == 0) + || (strcmp(sync, DMR_MS_DATA_SYNC) == 0)) + { + if (m_dsdDecoder->m_state.currentslot == 0) + { + sprintf(m_dsdDecoder->m_state.slot0light, "[slot0]"); + } + else + { + sprintf(m_dsdDecoder->m_state.slot1light, "[slot1]"); + } + } + + if (m_dsdDecoder->m_opts.errorbars == 1) + { + printf("%s %s ", m_dsdDecoder->m_state.slot0light, m_dsdDecoder->m_state.slot1light); + } +} + +void DSDDMRData::process() +{ + m_dsdDecoder->getDibit(); // get dibit from symbol but do nothing with it + + if (m_symbolIndex == 120 -1) // last dibit to skip + { + m_dsdDecoder->m_fsmState = DSDDecoder::DSDLookForSync; // go back to search sync state + } + + m_symbolIndex++; +} + +} // namespace DSDplus diff --git a/dsdplus/dmr_data.h b/dsdplus/dmr_data.h new file mode 100644 index 000000000..d832dc278 --- /dev/null +++ b/dsdplus/dmr_data.h @@ -0,0 +1,49 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2016 Edouard Griffiths, F4EXB. // +// // +// 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 as version 3 of the License, or // +// // +// 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 V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#ifndef DSDPLUS_DMR_DATA_H_ +#define DSDPLUS_DMR_DATA_H_ + +namespace DSDplus +{ + +class DSDDecoder; + +class DSDDMRData +{ +public: + DSDDMRData(DSDDecoder *dsdDecoder); + ~DSDDMRData(); + + void init(); + void process(); + +private: + void preProcess(); //!< process the 90 in memory dibits in initial phase + + DSDDecoder *m_dsdDecoder; + int m_symbolIndex; //!< Current absolute symbol index + int *dibit_p; + char sync[25]; + char syncdata[25]; + char cachdata[13]; + char cc[5]; + char bursttype[5]; +}; + +} + +#endif /* DSDPLUS_DMR_DATA_H_ */ diff --git a/dsdplus/dsd_decoder.cpp b/dsdplus/dsd_decoder.cpp index 27807b034..03d7cdd99 100644 --- a/dsdplus/dsd_decoder.cpp +++ b/dsdplus/dsd_decoder.cpp @@ -25,7 +25,8 @@ DSDDecoder::DSDDecoder() : m_fsmState(DSDLookForSync), m_hasSync(0), m_mbeDecoder(this), - m_dsdDMRVoice(this) + m_dsdDMRVoice(this), + m_dsdDMRData(this) { resetSymbol(); resetFrameSync(); @@ -1624,6 +1625,7 @@ void DSDDecoder::processFrame() else { m_state.err_str[0] = 0; + m_dsdDMRData.init(); m_fsmState = DSDprocessDMRdata; } } diff --git a/dsdplus/dsd_decoder.h b/dsdplus/dsd_decoder.h index b26a762a2..e3728b663 100644 --- a/dsdplus/dsd_decoder.h +++ b/dsdplus/dsd_decoder.h @@ -22,6 +22,7 @@ #include "dsd_filters.h" #include "dsd_mbe.h" #include "dmr_voice.h" +#include "dmr_data.h" /* * Frame sync patterns @@ -65,6 +66,7 @@ class DSDDecoder { friend class DSDMBEDecoder; friend class DSDDMRVoice; + friend class DSDDMRData; public: typedef enum { @@ -129,6 +131,7 @@ private: DSDMBEDecoder m_mbeDecoder; // Frame decoders DSDDMRVoice m_dsdDMRVoice; + DSDDMRData m_dsdDMRData; }; } // namespace dsdplus diff --git a/dsdplus/dsd_mbe.cpp b/dsdplus/dsd_mbe.cpp new file mode 100644 index 000000000..08d8639b2 --- /dev/null +++ b/dsdplus/dsd_mbe.cpp @@ -0,0 +1,290 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2016 Edouard Griffiths, F4EXB. // +// // +// 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 as version 3 of the License, or // +// // +// 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 V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include "dsd_mbe.h" +#include "dsd_decoder.h" + +namespace DSDplus +{ + +DSDMBEDecoder::DSDMBEDecoder(DSDDecoder *dsdDecoder) : + m_dsdDecoder(dsdDecoder) +{ +} + +DSDMBEDecoder::~DSDMBEDecoder() +{ +} + +void DSDMBEDecoder::processFrame(char imbe_fr[8][23], char ambe_fr[4][24], char imbe7100_fr[7][24]) +{ +// for (int i = 0; i < 88; i++) +// { +// imbe_d[i] = 0; +// } + memset((void *) imbe_d, 0, 88); + + if ((m_dsdDecoder->m_state.synctype == 0) || (m_dsdDecoder->m_state.synctype == 1)) + { + mbe_processImbe7200x4400Framef(m_dsdDecoder->m_state.audio_out_temp_buf, &m_dsdDecoder->m_state.errs, + &m_dsdDecoder->m_state.errs2, m_dsdDecoder->m_state.err_str, imbe_fr, imbe_d, m_dsdDecoder->m_state.cur_mp, + m_dsdDecoder->m_state.prev_mp, m_dsdDecoder->m_state.prev_mp_enhanced, m_dsdDecoder->m_opts.uvquality); + } + else if ((m_dsdDecoder->m_state.synctype == 14) || (m_dsdDecoder->m_state.synctype == 15)) + { + mbe_processImbe7100x4400Framef(m_dsdDecoder->m_state.audio_out_temp_buf, &m_dsdDecoder->m_state.errs, + &m_dsdDecoder->m_state.errs2, m_dsdDecoder->m_state.err_str, imbe7100_fr, imbe_d, + m_dsdDecoder->m_state.cur_mp, m_dsdDecoder->m_state.prev_mp, m_dsdDecoder->m_state.prev_mp_enhanced, + m_dsdDecoder->m_opts.uvquality); + } + else if ((m_dsdDecoder->m_state.synctype == 6) || (m_dsdDecoder->m_state.synctype == 7)) + { + mbe_processAmbe3600x2400Framef(m_dsdDecoder->m_state.audio_out_temp_buf, &m_dsdDecoder->m_state.errs, + &m_dsdDecoder->m_state.errs2, m_dsdDecoder->m_state.err_str, ambe_fr, ambe_d, m_dsdDecoder->m_state.cur_mp, + m_dsdDecoder->m_state.prev_mp, m_dsdDecoder->m_state.prev_mp_enhanced, m_dsdDecoder->m_opts.uvquality); + } + else + { + mbe_processAmbe3600x2450Framef(m_dsdDecoder->m_state.audio_out_temp_buf, &m_dsdDecoder->m_state.errs, + &m_dsdDecoder->m_state.errs2, m_dsdDecoder->m_state.err_str, ambe_fr, ambe_d, m_dsdDecoder->m_state.cur_mp, + m_dsdDecoder->m_state.prev_mp, m_dsdDecoder->m_state.prev_mp_enhanced, m_dsdDecoder->m_opts.uvquality); + } + + if (m_dsdDecoder->m_opts.errorbars == 1) + { + fprintf(m_dsdDecoder->m_state.logfile, "%s", m_dsdDecoder->m_state.err_str); + } + + processAudio(); +// if (m_dsdDecoder->m_opts.wav_out_f != NULL) +// { +// writeSynthesizedVoice(opts, state); +// } +// +// if (m_dsdDecoder->m_opts.audio_out == 1) +// { +// playSynthesizedVoice(opts, state); +// } +} + +void DSDMBEDecoder::processAudio() +{ + int i, n; + float aout_abs, max, gainfactor, gaindelta, maxbuf; + + if (m_dsdDecoder->m_opts.audio_gain == (float) 0) + { + // detect max level + max = 0; + m_dsdDecoder->m_state.audio_out_temp_buf_p = m_dsdDecoder->m_state.audio_out_temp_buf; + + for (n = 0; n < 160; n++) + { + aout_abs = fabsf(*m_dsdDecoder->m_state.audio_out_temp_buf_p); + + if (aout_abs > max) + { + max = aout_abs; + } + + m_dsdDecoder->m_state.audio_out_temp_buf_p++; + } + + *m_dsdDecoder->m_state.aout_max_buf_p = max; + m_dsdDecoder->m_state.aout_max_buf_p++; + m_dsdDecoder->m_state.aout_max_buf_idx++; + + if (m_dsdDecoder->m_state.aout_max_buf_idx > 24) + { + m_dsdDecoder->m_state.aout_max_buf_idx = 0; + m_dsdDecoder->m_state.aout_max_buf_p = m_dsdDecoder->m_state.aout_max_buf; + } + + // lookup max history + for (i = 0; i < 25; i++) + { + maxbuf = m_dsdDecoder->m_state.aout_max_buf[i]; + + if (maxbuf > max) + { + max = maxbuf; + } + } + + // determine optimal gain level + if (max > (float) 0) + { + gainfactor = ((float) 30000 / max); + } + else + { + gainfactor = (float) 50; + } + + if (gainfactor < m_dsdDecoder->m_state.aout_gain) + { + m_dsdDecoder->m_state.aout_gain = gainfactor; + gaindelta = (float) 0; + } + else + { + if (gainfactor > (float) 50) + { + gainfactor = (float) 50; + } + + gaindelta = gainfactor - m_dsdDecoder->m_state.aout_gain; + + if (gaindelta > ((float) 0.05 * m_dsdDecoder->m_state.aout_gain)) + { + gaindelta = ((float) 0.05 * m_dsdDecoder->m_state.aout_gain); + } + } + + gaindelta /= (float) 160; + } + else + { + gaindelta = (float) 0; + } + + if (m_dsdDecoder->m_opts.audio_gain >= 0) + { + // adjust output gain + m_dsdDecoder->m_state.audio_out_temp_buf_p = m_dsdDecoder->m_state.audio_out_temp_buf; + + for (n = 0; n < 160; n++) + { + *m_dsdDecoder->m_state.audio_out_temp_buf_p = (m_dsdDecoder->m_state.aout_gain + + ((float) n * gaindelta)) * (*m_dsdDecoder->m_state.audio_out_temp_buf_p); + m_dsdDecoder->m_state.audio_out_temp_buf_p++; + } + + m_dsdDecoder->m_state.aout_gain += ((float) 160 * gaindelta); + } + + // copy audio datat to output buffer and upsample if necessary + m_dsdDecoder->m_state.audio_out_temp_buf_p = m_dsdDecoder->m_state.audio_out_temp_buf; + + if (m_dsdDecoder->m_opts.split == 0) + { + for (n = 0; n < 160; n++) + { + upsample(*m_dsdDecoder->m_state.audio_out_temp_buf_p); + m_dsdDecoder->m_state.audio_out_temp_buf_p++; + m_dsdDecoder->m_state.audio_out_float_buf_p += 6; + m_dsdDecoder->m_state.audio_out_idx += 6; + m_dsdDecoder->m_state.audio_out_idx2 += 6; + } + + m_dsdDecoder->m_state.audio_out_float_buf_p -= (960 + m_dsdDecoder->m_opts.playoffset); + + // copy to output (short) buffer + for (n = 0; n < 960; n++) + { + if (*m_dsdDecoder->m_state.audio_out_float_buf_p > (float) 32760) + { + *m_dsdDecoder->m_state.audio_out_float_buf_p = (float) 32760; + } + else if (*m_dsdDecoder->m_state.audio_out_float_buf_p < (float) -32760) + { + *m_dsdDecoder->m_state.audio_out_float_buf_p = (float) -32760; + } + + *m_dsdDecoder->m_state.audio_out_buf_p = (short) *m_dsdDecoder->m_state.audio_out_float_buf_p; + m_dsdDecoder->m_state.audio_out_buf_p++; + m_dsdDecoder->m_state.audio_out_float_buf_p++; + } + + m_dsdDecoder->m_state.audio_out_float_buf_p += m_dsdDecoder->m_opts.playoffset; + } + else + { + for (n = 0; n < 160; n++) + { + if (*m_dsdDecoder->m_state.audio_out_temp_buf_p > (float) 32760) + { + *m_dsdDecoder->m_state.audio_out_temp_buf_p = (float) 32760; + } + else if (*m_dsdDecoder->m_state.audio_out_temp_buf_p < (float) -32760) + { + *m_dsdDecoder->m_state.audio_out_temp_buf_p = (float) -32760; + } + + *m_dsdDecoder->m_state.audio_out_buf_p = (short) *m_dsdDecoder->m_state.audio_out_temp_buf_p; + m_dsdDecoder->m_state.audio_out_buf_p++; + m_dsdDecoder->m_state.audio_out_temp_buf_p++; + m_dsdDecoder->m_state.audio_out_idx++; + m_dsdDecoder->m_state.audio_out_idx2++; + } + } + + // TODO: flag audio is uvailable +} + +void DSDMBEDecoder::upsample(float invalue) +{ + int i, j, sum; + float *outbuf1, c, d; + + outbuf1 = m_dsdDecoder->m_state.audio_out_float_buf_p; + outbuf1--; + c = *outbuf1; + d = invalue; + // basic triangle interpolation + outbuf1++; + *outbuf1 = ((invalue * (float) 0.166) + (c * (float) 0.834)); + outbuf1++; + *outbuf1 = ((invalue * (float) 0.332) + (c * (float) 0.668)); + outbuf1++; + *outbuf1 = ((invalue * (float) 0.5) + (c * (float) 0.5)); + outbuf1++; + *outbuf1 = ((invalue * (float) 0.668) + (c * (float) 0.332)); + outbuf1++; + *outbuf1 = ((invalue * (float) 0.834) + (c * (float) 0.166)); + outbuf1++; + *outbuf1 = d; + outbuf1++; + + if (m_dsdDecoder->m_state.audio_out_idx2 > 24) + { + // smoothing + outbuf1 -= 16; + for (j = 0; j < 4; j++) + { + for (i = 0; i < 6; i++) + { + sum = 0; + outbuf1 -= 2; + sum += *outbuf1; + outbuf1 += 2; + sum += *outbuf1; + outbuf1 += 2; + sum += *outbuf1; + outbuf1 -= 2; + *outbuf1 = (sum / (float) 3); + outbuf1++; + } + outbuf1 -= 8; + } + } +} + + +} diff --git a/dsdplus/dsd_mbe.h b/dsdplus/dsd_mbe.h new file mode 100644 index 000000000..c35c7aa32 --- /dev/null +++ b/dsdplus/dsd_mbe.h @@ -0,0 +1,45 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2016 Edouard Griffiths, F4EXB. // +// // +// 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 as version 3 of the License, or // +// // +// 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 V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#ifndef DSDPLUS_DSD_MBE_H_ +#define DSDPLUS_DSD_MBE_H_ + +namespace DSDplus +{ + +class DSDDecoder; + +class DSDMBEDecoder +{ +public: + DSDMBEDecoder(DSDDecoder *dsdDecoder); + ~DSDMBEDecoder(); + + void processFrame(char imbe_fr[8][23], char ambe_fr[4][24], char imbe7100_fr[7][24]); + +private: + void processAudio(); + void upsample(float invalue); + + DSDDecoder *m_dsdDecoder; + char imbe_d[88]; + char ambe_d[49]; + +}; + +} + +#endif /* DSDPLUS_DSD_MBE_H_ */