1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2024-11-25 17:28:50 -05:00

DSD demod: migrated to external DSDcc library (ex DSDplus)

This commit is contained in:
f4exb 2016-04-21 02:13:57 +02:00
parent ecd91fce79
commit 17de736f36
27 changed files with 60 additions and 4657 deletions

View File

@ -48,6 +48,7 @@ find_package(PkgConfig)
find_package(Boost)
find_package(FFTW3F)
find_package(LibDSDcc)
find_package(LibMbe)
IF(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|AMD64|x86")
@ -373,10 +374,6 @@ qt5_use_modules(sdrangel Widgets Multimedia)
add_subdirectory(plugins)
if(LIBMBE_FOUND)
add_subdirectory(dsdplus)
endif(LIBMBE_FOUND)
if(LIBUSB_FOUND AND UNIX)
add_subdirectory(fcdhid)
add_subdirectory(fcdlib)

View File

@ -115,6 +115,23 @@ There is an automated skew rate compensation in place. During rate readjustemnt
Note that this plugin does not require any of the hardware support libraries nor the libusb library. It is alwasys available in the list of devices as `SDRdaemon[0]` even if no physical device is connected.
<h1>Channel plugins with special conditions</h1>
<h2>DSD (Digital Speech Decoder)</h2>
This is the `demoddsd` plugin. At present it can be used to decode the following digital speech formats:
- DMR/MOTOTRBO
- D-Star
It is based on the [DSDcc](https://github.com/f4exb/dsdcc) C++ library which is a rewrite of the original [DSD](https://github.com/szechyjs/dsd) program. So you will need to have DSDcc installed in your system. Please follow instructions in [DSDcc readme](https://github.com/f4exb/dsdcc/blob/master/Readme.md) to build and install DSDcc. If you install it in a custom location say `/opt/install/dsdcc` you will need to add these defines to the cmake command: `-DLIBDSDCC_INCLUDE_DIR=/opt/install/dsdcc/include/dsdcc -DLIBDSDCC_LIBRARIES=/opt/install/dsdcc/lib/libdsdcc.so`
Please note that it also needs [mbelib](https://github.com/szechyjs/mbelib) and that mbelib comes with some copyright issues (see next). If you have mbelib installed in a custom location, say `/opt/install/mbelib` you will need to add these defines to the cmake command: `-DLIBMBE_INCLUDE_DIR=/opt/install/mbelib/include -DLIBMBE_LIBRARY=/opt/install/mbelib/lib/libmbe.so`
While DSDcc is intended to be patent-free, `mbelib` that it uses describes functions that may be covered by one or more U.S. patents owned by DVSI Inc. The source code itself should not be infringing as it merely describes possible methods of implementation. Compiling or using `mbelib` may infringe on patents rights in your jurisdiction and/or require licensing. It is unknown if DVSI will sell licenses for software that uses `mbelib`.
If you are not comfortable with this just do not install DSDcc and/or mbelib and the plugin will not be compiled and added to SDRangel. For packaged distributions just remove `libdemoddsd.so` or `libdemoddsd.dll` from the installed package.
<h1>Software build</h1>
<h2>Ubuntu</h2>

View File

@ -0,0 +1,30 @@
# Find libdsdcc
if(NOT LIBDSDCC_FOUND)
pkg_check_modules (LIBDSDCC_PKG libdsdcc)
find_path(LIBDSDCC_INCLUDE_DIR NAMES dsd_decoder.h
PATHS
${LIBDSDCC_PKG_INCLUDE_DIRS}
/usr/include
/usr/local/include
)
find_library(LIBDSDCC_LIBRARIES NAMES dsdcc
PATHS
${LIBDSDCC_PKG_LIBRARY_DIRS}
/usr/lib
/usr/local/lib
)
if(LIBDSDCC_INCLUDE_DIR AND LIBDSDCC_LIBRARIES)
set(LIBDSDCC_FOUND TRUE CACHE INTERNAL "libdsdcc found")
message(STATUS "Found libdsdcc: ${LIBDSDCC_INCLUDE_DIR}, ${LIBDSDCC_LIBRARIES}")
else(LIBDSDCC_INCLUDE_DIR AND LIBDSDCC_LIBRARIES)
set(LIBDSDCC_FOUND FALSE CACHE INTERNAL "libdsdcc found")
message(STATUS "libdsdcc not found.")
endif(LIBDSDCC_INCLUDE_DIR AND LIBDSDCC_LIBRARIES)
mark_as_advanced(LIBDSDCC_INCLUDE_DIR LIBDSDCC_LIBRARIES)
endif(NOT LIBDSDCC_FOUND)

View File

@ -11,7 +11,7 @@ ENDIF (LIBMBE_INCLUDE_DIR AND LIBMBE_LIBRARY)
IF (LIBMBE_FOUND)
IF (NOT LibMbe_FIND_QUIETLY)
MESSAGE (STATUS "Found LibMbe: ${LIBMBE_LIBRARY}")
MESSAGE (STATUS "Found LibMbe: ${LIBMBE_INCLUDE_DIR}, ${LIBMBE_LIBRARY}")
ENDIF (NOT LibMbe_FIND_QUIETLY)
ELSE (LIBMBE_FOUND)
IF (LibMbe_FIND_REQUIRED)

View File

@ -1,39 +0,0 @@
project(dsdplus)
set(dsdplus_SOURCES
descramble.cpp
dmr_data.cpp
dmr_voice.cpp
dsd_decoder.cpp
dsd_filters.cpp
dsd_mbe.cpp
dsd_opts.cpp
dsd_state.cpp
dstar.cpp
)
set(dsdplus_HEADERS
descramble.h
dmr_data.h
dmr_voice.h
dsd_decoder.h
dsd_filters.h
dsd_mbe.h
dsd_opts.h
dsd_state.h
dstar.h
)
include_directories(
${PROJECT_SOURCE_DIR}
${CMAKE_CURRENT_BINARY_DIR}
${LIBMBE_INCLUDE_DIR}
)
add_library(dsdplus SHARED
${dsdplus_SOURCES}
)
target_link_libraries(dsdplus ${LIBMBE_LIBRARY})
install(TARGETS dsdplus DESTINATION lib)

View File

@ -1,350 +0,0 @@
///////////////////////////////////////////////////////////////////////////////////
// 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
/* descramble.h */
// Functions for processing the radio-header:
// descramble
// deinterleave
// FECdecoder
// (C) 2011 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.
*/
// This code was originally written by JOnathan Naylor, G4KLX, as part
// of the "pcrepeatercontroller" project
// More info:
// http://groups.yahoo.com/group/pcrepeatercontroller
// Changes:
// Convert C++ to C
// Version 20111106: initial release
// F4EXB: Convert back to C++ !
#include <string.h>
#include "descramble.h"
namespace DSDplus
{
const int Descramble::SCRAMBLER_TABLE_BITS[] = {
0,0,0,0,1,1,1,0,1,1,1,1,0,0,1,0,1,1,0,0,1,0,0,1,0,0,0,0,0,0,1,0,
0,0,1,0,0,1,1,0,0,0,1,0,1,1,1,0,1,0,1,1,0,1,1,0,0,0,0,0,1,1,0,0,
1,1,0,1,0,1,0,0,1,1,1,0,0,1,1,1,1,0,1,1,0,1,0,0,0,0,1,0,1,0,1,0,
1,1,1,1,1,0,1,0,0,1,0,1,0,0,0,1,1,0,1,1,1,0,0,0,1,1,1,1,1,1,1,0,
0,0,0,1,1,1,0,1,1,1,1,0,0,1,0,1,1,0,0,1,0,0,1,0,0,0,0,0,0,1,0,0,
0,1,0,0,1,1,0,0,0,1,0,1,1,1,0,1,0,1,1,0,1,1,0,0,0,0,0,1,1,0,0,1,
1,0,1,0,1,0,0,1,1,1,0,0,1,1,1,1,0,1,1,0,1,0,0,0,0,1,0,1,0,1,0,1,
1,1,1,1,0,1,0,0,1,0,1,0,0,0,1,1,0,1,1,1,0,0,0,1,1,1,1,1,1,1,0,0,
0,0,1,1,1,0,1,1,1,1,0,0,1,0,1,1,0,0,1,0,0,1,0,0,0,0,0,0,1,0,0,0,
1,0,0,1,1,0,0,0,1,0,1,1,1,0,1,0,1,1,0,1,1,0,0,0,0,0,1,1,0,0,1,1,
0,1,0,1,0,0,1,1,1,0,0,1,1,1,1,0,1,1,0,1,0,0,0,0,1,0,1,0,1,0,1,1,
1,1,1,0,1,0,0,1,0,1,0,0,0,1,1,0,1,1,1,0,0,0,1,1,1,1,1,1,1,0,0,0,
0,1,1,1,0,1,1,1,1,0,0,1,0,1,1,0,0,1,0,0,1,0,0,0,0,0,0,1,0,0,0,1,
0,0,1,1,0,0,0,1,0,1,1,1,0,1,0,1,1,0,1,1,0,0,0,0,0,1,1,0,0,1,1,0,
1,0,1,0,0,1,1,1,0,0,1,1,1,1,0,1,1,0,1,0,0,0,0,1,0,1,0,1,0,1,1,1,
1,1,0,1,0,0,1,0,1,0,0,0,1,1,0,1,1,1,0,0,0,1,1,1,1,1,1,1,0,0,0,0,
1,1,1,0,1,1,1,1,0,0,1,0,1,1,0,0,1,0,0,1,0,0,0,0,0,0,1,0,0,0,1,0,
0,1,1,0,0,0,1,0,1,1,1,0,1,0,1,1,0,1,1,0,0,0,0,0,1,1,0,0,1,1,0,1,
0,1,0,0,1,1,1,0,0,1,1,1,1,0,1,1,0,1,0,0,0,0,1,0,1,0,1,0,1,1,1,1,
1,0,1,0,0,1,0,1,0,0,0,1,1,0,1,1,1,0,0,0,1,1,1,1,1,1,1,0,0,0,0,1,
1,1,0,1,1,1,1,0,0,1,0,1,1,0,0,1,0,0,1,0,0,0,0,0,0,1,0,0,0,1,0,0,
1,1,0,0,0,1,0,1,1,1,0,1,0,1,1,0,1,1,0,0,0,0,0,1,1,0,0,1,1,0,1,0,
1,0,0,1,1,1,0,0,1,1,1,1,0,1,1,0};
int Descramble::traceBack(int * out, int * m_pathMemory0, int * m_pathMemory1,
int * m_pathMemory2, int * m_pathMemory3)
{
enum FEC_STATE
{
S0, S1, S2, S3
} state;
int loop;
int length = 0;
state = S0;
for (loop = 329; loop >= 0; loop--, length++)
{
switch (state)
{
case S0: // if state S0
if (m_pathMemory0[loop])
{
state = S2; // lower path
}
else
{
state = S0; // upper path
}
; // end else - if
out[loop] = 0;
break;
case S1: // if state S1
if (m_pathMemory1[loop])
{
state = S2; // lower path
}
else
{
state = S0; // upper path
}
; // end else - if
out[loop] = 1;
break;
case S2: // if state S2
if (m_pathMemory2[loop])
{
state = S3; // lower path
}
else
{
state = S1; // upper path
}
; // end else - if
out[loop] = 0;
break;
case S3: // if state S3
if (m_pathMemory3[loop])
{
state = S3; // lower path
}
else
{
state = S1; // upper path
}
; // end else - if
out[loop] = 1;
break;
}; // end switch
}; // end for
return (length);
} // end function
void Descramble::viterbiDecode(int n, int *data, int *m_pathMemory0, int *m_pathMemory1,
int *m_pathMemory2, int *m_pathMemory3, int *m_pathMetric)
{
int tempMetric[4];
int metric[8];
int loop;
int m1;
int m2;
metric[0] = (data[1] ^ 0) + (data[0] ^ 0);
metric[1] = (data[1] ^ 1) + (data[0] ^ 1);
metric[2] = (data[1] ^ 1) + (data[0] ^ 0);
metric[3] = (data[1] ^ 0) + (data[0] ^ 1);
metric[4] = (data[1] ^ 1) + (data[0] ^ 1);
metric[5] = (data[1] ^ 0) + (data[0] ^ 0);
metric[6] = (data[1] ^ 0) + (data[0] ^ 1);
metric[7] = (data[1] ^ 1) + (data[0] ^ 0);
// Pres. state = S0, Prev. state = S0 & S2
m1 = metric[0] + m_pathMetric[0];
m2 = metric[4] + m_pathMetric[2];
if (m1 < m2)
{
m_pathMemory0[n] = 0;
tempMetric[0] = m1;
}
else
{
m_pathMemory0[n] = 1;
tempMetric[0] = m2;
}; // end else - if
// Pres. state = S1, Prev. state = S0 & S2
m1 = metric[1] + m_pathMetric[0];
m2 = metric[5] + m_pathMetric[2];
if (m1 < m2)
{
m_pathMemory1[n] = 0;
tempMetric[1] = m1;
}
else
{
m_pathMemory1[n] = 1;
tempMetric[1] = m2;
}; // end else - if
// Pres. state = S2, Prev. state = S2 & S3
m1 = metric[2] + m_pathMetric[1];
m2 = metric[6] + m_pathMetric[3];
if (m1 < m2)
{
m_pathMemory2[n] = 0;
tempMetric[2] = m1;
}
else
{
m_pathMemory2[n] = 1;
tempMetric[2] = m2;
}
// Pres. state = S3, Prev. state = S1 & S3
m1 = metric[3] + m_pathMetric[1];
m2 = metric[7] + m_pathMetric[3];
if (m1 < m2)
{
m_pathMemory3[n] = 0;
tempMetric[3] = m1;
}
else
{
m_pathMemory3[n] = 1;
tempMetric[3] = m2;
}; // end else - if
for (loop = 0; loop < 4; loop++)
{
m_pathMetric[loop] = tempMetric[loop];
}; // end for
} // end function ViterbiDecode
int Descramble::FECdecoder(int * in, int * out)
{
int outLen;
int m_pathMemory0[330];
memset(m_pathMemory0, 0, 330 * sizeof(int));
int m_pathMemory1[330];
memset(m_pathMemory1, 0, 330 * sizeof(int));
int m_pathMemory2[330];
memset(m_pathMemory2, 0, 330 * sizeof(int));
int m_pathMemory3[330];
memset(m_pathMemory3, 0, 330 * sizeof(int));
int m_pathMetric[4];
int loop, loop2;
int n = 0;
for (loop = 0; loop < 4; loop++)
{
m_pathMetric[loop] = 0;
}; // end for
for (loop2 = 0; loop2 < 660; loop2 += 2, n++)
{
int data[2];
if (in[loop2])
{
data[1] = 1;
}
else
{
data[1] = 0;
}; // end else - if
if (in[loop2 + 1])
{
data[0] = 1;
}
else
{
data[0] = 0;
}; // end else - if
viterbiDecode(n, data, m_pathMemory0, m_pathMemory1, m_pathMemory2,
m_pathMemory3, m_pathMetric);
}; // end for
outLen = traceBack(out, m_pathMemory0, m_pathMemory1, m_pathMemory2,
m_pathMemory3);
// Swap endian-ness
// code removed (done converting bits into octets), done in main program
//for (loop=0;loop<330;loop+=8) {
// int temp;
// temp=out[loop];out[loop]=out[loop+7];out[loop+7]=temp;
// temp=out[loop+1];out[loop+1]=out[loop+6];out[loop+6]=temp;
// temp=out[loop+2];out[loop+2]=out[loop+5];out[loop+5]=temp;
// temp=out[loop+3];out[loop+3]=out[loop+4];out[loop+4]=temp;
//}
return (outLen);
} // end function FECdecoder
void Descramble::deinterleave(int * in, int * out)
{
int k = 0;
int loop = 0;
// function starts here
// init vars
k = 0;
for (loop = 0; loop < 660; loop++)
{
out[k] = in[loop];
k += 24;
if (k >= 672)
{
k -= 671;
}
else if (k >= 660)
{
k -= 647;
}; // end elsif - if
}; // end for
} // end function deinterleave
void Descramble::scramble (int * in,int * out)
{
int loop = 0;
int m_count = 0;
for (loop = 0; loop < 660; loop++)
{
out[loop] = in[loop] ^ SCRAMBLER_TABLE_BITS[m_count++];
if (m_count >= SCRAMBLER_TABLE_BITS_LENGTH)
{
m_count = 0U;
}; // end if
}; // end for
}
} // namespace DSDplus

View File

@ -1,44 +0,0 @@
///////////////////////////////////////////////////////////////////////////////////
// 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef DSDPLUS_DESCRAMBLE_H_
#define DSDPLUS_DESCRAMBLE_H_
namespace DSDplus
{
class Descramble
{
public:
// Descramble();
// ~Descramble();
static void scramble (int * in,int * out);
static void deinterleave (int * in, int * out);
static int FECdecoder (int * in, int * out);
private:
static int traceBack (int * out, int * m_pathMemory0, int * m_pathMemory1, int * m_pathMemory2, int * m_pathMemory3);
static void viterbiDecode (int n, int *data, int *m_pathMemory0, int *m_pathMemory1, int *m_pathMemory2, int *m_pathMemory3, int *m_pathMetric);
static const int SCRAMBLER_TABLE_BITS_LENGTH=720;
static const int SCRAMBLER_TABLE_BITS[];
};
} // namespace DSDplus
#endif /* DSDPLUS_DESCRAMBLE_H_ */

View File

@ -1,231 +0,0 @@
///////////////////////////////////////////////////////////////////////////////////
// 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#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)
{
fprintf(stderr, "%s %s\n", 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

View File

@ -1,49 +0,0 @@
///////////////////////////////////////////////////////////////////////////////////
// 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#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_ */

View File

@ -1,488 +0,0 @@
///////////////////////////////////////////////////////////////////////////////////
// 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include "dmr_voice.h"
#include "dsd_decoder.h"
namespace DSDplus
{
/*
* DMR AMBE interleave schedule
*/
const int DSDDMRVoice::rW[36] = {
0, 1, 0, 1, 0, 1,
0, 1, 0, 1, 0, 1,
0, 1, 0, 1, 0, 1,
0, 1, 0, 1, 0, 2,
0, 2, 0, 2, 0, 2,
0, 2, 0, 2, 0, 2
};
const int DSDDMRVoice::rX[36] = {
23, 10, 22, 9, 21, 8,
20, 7, 19, 6, 18, 5,
17, 4, 16, 3, 15, 2,
14, 1, 13, 0, 12, 10,
11, 9, 10, 8, 9, 7,
8, 6, 7, 5, 6, 4
};
const int DSDDMRVoice::rY[36] = {
0, 2, 0, 2, 0, 2,
0, 2, 0, 3, 0, 3,
1, 3, 1, 3, 1, 3,
1, 3, 1, 3, 1, 3,
1, 3, 1, 3, 1, 3,
1, 3, 1, 3, 1, 3
};
const int DSDDMRVoice::rZ[36] = {
5, 3, 4, 2, 3, 1,
2, 0, 1, 13, 0, 12,
22, 11, 21, 10, 20, 9,
19, 8, 18, 7, 17, 6,
16, 5, 15, 4, 14, 3,
13, 2, 12, 1, 11, 0
};
DSDDMRVoice::DSDDMRVoice(DSDDecoder *dsdDecoder) :
m_dsdDecoder(dsdDecoder),
m_symbolIndex(0),
m_dibitIndex(0),
mutecurrentslot(0),
m_slotIndex(-1)
{
}
DSDDMRVoice::~DSDDMRVoice()
{
}
void DSDDMRVoice::init()
{
mutecurrentslot = 0;
msMode = 0;
dibit_p = m_dsdDecoder->m_state.dibit_buf_p - 144;
m_symbolIndex = 0;
preProcess();
m_symbolIndex = 144; // reposition symbol index in frame
}
void DSDDMRVoice::process()
{
m_majorBlock = m_symbolIndex / 288; // frame (major block) index
m_dibitIndex = m_symbolIndex % 288; // index of symbol in frame
int symbolIndex = getSlotIndex(m_dibitIndex); // returns symbol index in current slot. Updates m_slotIndex.
switch(m_slotIndex)
{
case 0:
processSlot0(symbolIndex);
break;
case 1:
processSlot1(symbolIndex);
break;
case 2:
processSlot2(symbolIndex);
break;
case 3:
processSlot3(symbolIndex);
break;
case 4:
processSlot4(symbolIndex);
break;
case 5:
processSlot5(symbolIndex);
break;
case 6:
processSlot6(symbolIndex);
break;
case 7:
processSlot7(symbolIndex);
break;
case 8:
processSlot8(symbolIndex);
break;
case 9:
processSlot9(symbolIndex);
break;
case 10: // this is the post-process case
postProcess(symbolIndex);
break;
default:
m_dsdDecoder->m_fsmState = DSDDecoder::DSDLookForSync;
break;
}
m_symbolIndex++;
}
void DSDDMRVoice::preProcess()
{
// copy in memory to dibit cache
memcpy((void *) m_dibitCache, (const void *) dibit_p, 144 * sizeof(int));
m_dibitIndex = 54-1; // set cache pointer - skip slot 0
m_dibitIndex += 12; // advance cache pointer
processSlot1(12-1);
m_dibitIndex += 36; // advance cache pointer
processSlot2(36-1);
m_dibitIndex += 18; // advance cache pointer
processSlot3(18-1);
m_dibitIndex += 24; // advance cache pointer
processSlot4(24-1);
m_dibitIndex += 18; // advance cache pointer
processSlot5(18-1);
m_dibitIndex += 36; // advance cache pointer
processSlot6(36-1);
m_dibitIndex += 12; // advance cache pointer
processSlot7(12-1);
m_dibitIndex += 54; // advance cache pointer - skip slot 8
processSlot9(24-1);
m_dibitIndex += 24; // advance cache pointer
processSlot9(24-1);
m_symbolIndex = 144; // advance the main symbol index
}
void DSDDMRVoice::postProcess(int symbolIndex)
{
//fprintf(stderr, "DSDDMRVoice::postProcess: m_symbolIndex: %d", m_symbolIndex);
m_dsdDecoder->getDibit(); // get dibit from symbol but do nothing with it
if (symbolIndex == 54+12+54-1) // very last symbol -> go back to search sync state
{
fprintf(stderr, "DSDDMRVoice::postProcess: end of frame\n");
m_dsdDecoder->m_fsmState = DSDDecoder::DSDLookForSync;
}
}
void DSDDMRVoice::processSlot0(int symbolIndex) // Slot0 is a 54 symbol slot
{
m_dsdDecoder->getDibit(); // get dibit from symbol but do nothing with it
}
void DSDDMRVoice::processSlot8(int symbolIndex) // Slot8 is a 54 symbol slot
{
m_dsdDecoder->getDibit(); // get dibit from symbol but do nothing with it
}
void DSDDMRVoice::processSlot1(int symbolIndex) // Slot1 is a 12 symbol slot
{
if (m_majorBlock > 0) // 0:1 reads from 144 in memory dibits. Handled by upper layer.
{
int dibit = m_dsdDecoder->getDibit(); // get dibit from symbol and store it in cache
m_dibitCache[m_dibitIndex] = dibit;
}
if (symbolIndex == 12-1) // last symbol -> launch process
{
int *dibitCache = &m_dibitCache[m_dibitIndex - symbolIndex]; // move back to start of corresponding cache section
// CACH
for (int i = 0; i < 12; i++)
{
int dibit = dibitCache[i];
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;
}
}
void DSDDMRVoice::processSlot2(int symbolIndex) // Slot2 is a 36 symbol slot
{
if (m_majorBlock > 0) // 0:2 reads from 144 in memory dibits. Handled by upper layer.
{
int dibit = m_dsdDecoder->getDibit(); // get dibit from symbol and store it in cache
m_dibitCache[m_dibitIndex] = dibit;
}
if (symbolIndex == 36-1) // last symbol -> launch process
{
int *dibitCache = &m_dibitCache[m_dibitIndex - symbolIndex]; // move back to start of corresponding cache section
w = rW;
x = rX;
y = rY;
z = rZ;
for (int i = 0; i < 36; i++)
{
int dibit = dibitCache[i];
ambe_fr[*w][*x] = (1 & (dibit >> 1)); // bit 1
ambe_fr[*y][*z] = (1 & dibit); // bit 0
w++;
x++;
y++;
z++;
}
}
}
void DSDDMRVoice::processSlot3(int symbolIndex) // Slot3 is a 18 symbol slot
{
if (m_majorBlock > 0) // 0:3 reads from 144 in memory dibits. Handled by upper layer.
{
int dibit = m_dsdDecoder->getDibit(); // get dibit from symbol and store it in cache
m_dibitCache[m_dibitIndex] = dibit;
}
if (symbolIndex == 18-1) // last symbol -> launch process
{
int *dibitCache = &m_dibitCache[m_dibitIndex - symbolIndex]; // move back to start of corresponding cache section
w = rW;
x = rX;
y = rY;
z = rZ;
for (int i = 0; i < 18; i++)
{
int dibit = dibitCache[i];
ambe_fr2[*w][*x] = (1 & (dibit >> 1)); // bit 1
ambe_fr2[*y][*z] = (1 & dibit); // bit 0
w++;
x++;
y++;
z++;
}
}
}
void DSDDMRVoice::processSlot4(int symbolIndex) // Slot4 is a 24 symbol slot
{
if (m_majorBlock > 0) // 0:3 reads from 144 in memory dibits. Handled by upper layer.
{
int dibit = m_dsdDecoder->getDibit(); // get dibit from symbol and store it in cache
m_dibitCache[m_dibitIndex] = dibit;
}
if (symbolIndex == 24-1) // last symbol -> launch process
{
int *dibitCache = &m_dibitCache[m_dibitIndex - symbolIndex]; // move back to start of corresponding cache section
for (int i = 0; i < 24; i++)
{
int dibit = dibitCache[i];
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))
{
mutecurrentslot = 1;
if (m_dsdDecoder->m_state.currentslot == 0)
{
sprintf(m_dsdDecoder->m_state.slot0light, "[slot0]");
}
else
{
sprintf(m_dsdDecoder->m_state.slot1light, "[slot1]");
}
}
else if ((strcmp(sync, DMR_BS_VOICE_SYNC) == 0)
|| (strcmp(sync, DMR_MS_VOICE_SYNC) == 0))
{
mutecurrentslot = 0;
if (m_dsdDecoder->m_state.currentslot == 0)
{
sprintf(m_dsdDecoder->m_state.slot0light, "[SLOT0]");
}
else
{
sprintf(m_dsdDecoder->m_state.slot1light, "[SLOT1]");
}
}
if ((strcmp(sync, DMR_MS_VOICE_SYNC) == 0)
|| (strcmp(sync, DMR_MS_DATA_SYNC) == 0))
{
msMode = 1;
}
if ((m_majorBlock == 0) && (m_dsdDecoder->m_opts.errorbars == 1))
{
fprintf(stderr, "%s %s VOICE e:", m_dsdDecoder->m_state.slot0light, m_dsdDecoder->m_state.slot1light);
}
}
}
void DSDDMRVoice::processSlot5(int symbolIndex) // Slot5 is a 18 symbol slot
{
int dibit = m_dsdDecoder->getDibit(); // get dibit from symbol and store it in cache
m_dibitCache[m_dibitIndex] = dibit;
if (symbolIndex == 18-1) // last symbol -> launch process
{
int *dibitCache = &m_dibitCache[m_dibitIndex - symbolIndex]; // move back to start of corresponding cache section
for (int i = 0; i < 18; i++)
{
int dibit = dibitCache[i];
ambe_fr2[*w][*x] = (1 & (dibit >> 1)); // bit 1
ambe_fr2[*y][*z] = (1 & dibit); // bit 0
w++;
x++;
y++;
z++;
}
if (mutecurrentslot == 0)
{
if (m_dsdDecoder->m_state.firstframe == 1)
{ // we don't know if anything received before the first sync after no carrier is valid
m_dsdDecoder->m_state.firstframe = 0;
}
else
{
if (m_dsdDecoder->m_opts.errorbars == 1) {
fprintf(stderr, "\nMBE: ");
}
m_dsdDecoder->m_mbeDecoder.processFrame(0, ambe_fr, 0);
if (m_dsdDecoder->m_opts.errorbars == 1) {
fprintf(stderr, ".");
}
m_dsdDecoder->m_mbeDecoder.processFrame(0, ambe_fr2, 0);
if (m_dsdDecoder->m_opts.errorbars == 1) {
fprintf(stderr, ".");
}
}
}
}
}
void DSDDMRVoice::processSlot6(int symbolIndex) // Slot6 is a 36 symbol slot
{
int dibit = m_dsdDecoder->getDibit(); // get dibit from symbol and store it in cache
m_dibitCache[m_dibitIndex] = dibit;
if (symbolIndex == 36-1) // last symbol -> launch process
{
int *dibitCache = &m_dibitCache[m_dibitIndex - symbolIndex]; // move back to start of corresponding cache section
// current slot frame 3
w = rW;
x = rX;
y = rY;
z = rZ;
for (int i = 0; i < 36; i++)
{
int dibit = dibitCache[i];
ambe_fr3[*w][*x] = (1 & (dibit >> 1)); // bit 1
ambe_fr3[*y][*z] = (1 & dibit); // bit 0
w++;
x++;
y++;
z++;
}
if (mutecurrentslot == 0)
{
m_dsdDecoder->m_mbeDecoder.processFrame(0, ambe_fr3, 0);
if (m_dsdDecoder->m_opts.errorbars == 1) {
fprintf(stderr, "\n");
}
}
}
}
void DSDDMRVoice::processSlot7(int symbolIndex) // Slot7 is a 12 symbol slot
{
int dibit = m_dsdDecoder->getDibit(); // get dibit from symbol and store it in cache
m_dibitCache[m_dibitIndex] = dibit;
if (symbolIndex == 12-1) // last symbol -> launch process
{
int *dibitCache = &m_dibitCache[m_dibitIndex - symbolIndex]; // move back to start of corresponding cache section
// CACH
for (int i = 0; i < 12; i++)
{
int dibit = dibitCache[i];
cachdata[i] = dibit;
}
cachdata[12] = 0;
}
}
void DSDDMRVoice::processSlot9(int symbolIndex) // Slot9 is a 24 symbol slot
{
int dibit = m_dsdDecoder->getDibit(); // get dibit from symbol and store it in cache
m_dibitCache[m_dibitIndex] = dibit;
if (symbolIndex == 24-1) // last symbol -> launch process
{
int *dibitCache = &m_dibitCache[m_dibitIndex - symbolIndex]; // move back to start of corresponding cache section
for (int i = 0; i < 24; i++)
{
int dibit = dibitCache[i];
syncdata[i] = dibit;
sync[i] = (dibit | 1) + 48;
}
sync[24] = 0;
syncdata[24] = 0;
}
}
} // namespace dsdplus

View File

@ -1,166 +0,0 @@
///////////////////////////////////////////////////////////////////////////////////
// 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
/*
* DMR voice frames
* 6 Major blocks of 10 slots. 2 groups of slots of 144 bytes each.
* Map is as follows in number of bytes
*
* 0 ... 5
* A 0 54 ... 54 <- AMBE DMR slot 0 frame 2 1/2 + frame 3: skipped
* 1 12 12 <- CACH data
* 2 36 36 <- AMBE DMR slot 1 frame 1
* 3 18 18 <- AMBE DMR slot 1 frame 2 1/2
* 4 24 24 <- SYNC data
* B 5 18 18 <- AMBE DMR slot 1 frame 2 1/2
* 6 36 36 <- AMBE DMR slot 1 frame 3
* 7 12 12 <- CACH data
* 8 54 54 <- AMBE DMR slot 0 frame 1 + frame 2 1/2: skipped
* 9 24 24 <- SYNC data
*
* The A group of the first major block is already in memory and is processed
* at initialization time
* Then dibits for each slot are stored in cache and processed right after the
* last dibit for the slot has been added.
* For skipped slots the dibits are simply thrown away
*
* The DMR slot 0 is ignored. Only the DMR slot 1 is processed (listening to one conversation at a time)
*
*/
#ifndef DSDPLUS_DMR_VOICE_H_
#define DSDPLUS_DMR_VOICE_H_
namespace DSDplus
{
class DSDDecoder;
class DSDDMRVoice
{
public:
DSDDMRVoice(DSDDecoder *dsdDecoder);
~DSDDMRVoice();
void init();
void process();
private:
int getSlotIndex(int symbolInMajorBlockIndex) //!< calculates current slot index and returns symbol index in the slot
{
if (m_majorBlock > 5) // this is the post-process case
{
m_slotIndex = 10;
return symbolInMajorBlockIndex;
}
if (symbolInMajorBlockIndex < 54)
{
m_slotIndex = 0;
return symbolInMajorBlockIndex;
}
else if (symbolInMajorBlockIndex < 54+12)
{
m_slotIndex = 1;
return symbolInMajorBlockIndex - 54;
}
else if (symbolInMajorBlockIndex < 54+12+36)
{
m_slotIndex = 2;
return symbolInMajorBlockIndex - 54+12;
}
else if (symbolInMajorBlockIndex < 54+12+36+18)
{
m_slotIndex = 3;
return symbolInMajorBlockIndex - 54+12+36;
}
else if (symbolInMajorBlockIndex < 54+12+36+18+24)
{
m_slotIndex = 4;
return symbolInMajorBlockIndex - 54+12+36+18;
}
else if (symbolInMajorBlockIndex < 54+12+36+18+24+18)
{
m_slotIndex = 5;
return symbolInMajorBlockIndex - 54+12+36+18+24;
}
else if (symbolInMajorBlockIndex < 54+12+36+18+24+18+36)
{
m_slotIndex = 6;
return symbolInMajorBlockIndex - 54+12+36+18+24+18;
}
else if (symbolInMajorBlockIndex < 54+12+36+18+24+18+36+12)
{
m_slotIndex = 7;
return symbolInMajorBlockIndex - 54+12+36+18+24+18+36;
}
else if (symbolInMajorBlockIndex < 54+12+36+18+24+18+36+12+54)
{
m_slotIndex = 8;
return symbolInMajorBlockIndex - 54+12+36+18+24+18+36+12;
}
else if (symbolInMajorBlockIndex < 54+12+36+18+24+18+36+12+54+24)
{
m_slotIndex = 9;
return symbolInMajorBlockIndex - 54+12+36+18+24+18+36+12+54;
}
else // cannot go there if using this function in its valid context (input is a remainder of division by 288)
{
m_slotIndex = -1; // invalid slot
return 0;
}
}
void preProcess(); //!< process the 144 in memory dibits in initial phase
void postProcess(int symbolIndex); //!< skip 54 + 12 + 54 symbols at the end of the last slot (block 5 slot 9)
void processSlot0(int symbolIndex);
void processSlot1(int symbolIndex);
void processSlot2(int symbolIndex);
void processSlot3(int symbolIndex);
void processSlot4(int symbolIndex);
void processSlot5(int symbolIndex);
void processSlot6(int symbolIndex);
void processSlot7(int symbolIndex);
void processSlot8(int symbolIndex);
void processSlot9(int symbolIndex);
DSDDecoder *m_dsdDecoder;
// extracts AMBE frames from DMR frame
int m_symbolIndex; //!< Current absolute symbol index
int m_slotIndex; //!< Slot index in major block 0..9 //i;
int m_majorBlock; //!< Major block index 0..5 //j;
int *dibit_p;
char ambe_fr[4][24];
char ambe_fr2[4][24];
char ambe_fr3[4][24];
const int *w, *x, *y, *z;
char sync[25];
char syncdata[25];
char cachdata[13];
int mutecurrentslot;
int msMode;
int m_dibitCache[288]; // has to handle a complete frame (288 dibits)
int m_dibitIndex; // index in dibit cache
static const int rW[36];
static const int rX[36];
static const int rY[36];
static const int rZ[36];
};
}
#endif /* DSDPLUS_DMR_VOICE_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -1,157 +0,0 @@
///////////////////////////////////////////////////////////////////////////////////
// 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef DSDPLUS_DSD_DECODER_H_
#define DSDPLUS_DSD_DECODER_H_
#include "dsd_opts.h"
#include "dsd_state.h"
#include "dsd_filters.h"
#include "dsd_mbe.h"
#include "dmr_voice.h"
#include "dmr_data.h"
#include "dstar.h"
/*
* Frame sync patterns
*/
#define INV_P25P1_SYNC "333331331133111131311111"
#define P25P1_SYNC "111113113311333313133333"
#define X2TDMA_BS_VOICE_SYNC "113131333331313331113311"
#define X2TDMA_BS_DATA_SYNC "331313111113131113331133"
#define X2TDMA_MS_DATA_SYNC "313113333111111133333313"
#define X2TDMA_MS_VOICE_SYNC "131331111333333311111131"
#define DSTAR_HD "131313131333133113131111"
#define INV_DSTAR_HD "313131313111311331313333"
#define DSTAR_SYNC "313131313133131113313111"
#define INV_DSTAR_SYNC "131313131311313331131333"
#define NXDN_MS_DATA_SYNC "313133113131111333"
#define INV_NXDN_MS_DATA_SYNC "131311331313333111"
#define NXDN_MS_VOICE_SYNC "313133113131113133"
#define INV_NXDN_MS_VOICE_SYNC "131311331313331311"
#define INV_NXDN_BS_DATA_SYNC "131311331313333131"
#define NXDN_BS_DATA_SYNC "313133113131111313"
#define INV_NXDN_BS_VOICE_SYNC "131311331313331331"
#define NXDN_BS_VOICE_SYNC "313133113131113113"
#define DMR_BS_DATA_SYNC "313333111331131131331131"
#define DMR_BS_VOICE_SYNC "131111333113313313113313"
#define DMR_MS_DATA_SYNC "311131133313133331131113"
#define DMR_MS_VOICE_SYNC "133313311131311113313331"
#define INV_PROVOICE_SYNC "31313111333133133311331133113311"
#define PROVOICE_SYNC "13131333111311311133113311331133"
#define INV_PROVOICE_EA_SYNC "13313133113113333311313133133311"
#define PROVOICE_EA_SYNC "31131311331331111133131311311133"
namespace DSDplus
{
class DSDDecoder
{
friend class DSDMBEDecoder;
friend class DSDDMRVoice;
friend class DSDDMRData;
friend class DSDDstar;
public:
typedef enum
{
DSDLookForSync,
DSDNoSync,
DSDprocessFrame,
DSDprocessNXDNVoice,
DSDprocessNXDNData,
DSDprocessDSTAR,
DSDprocessDSTAR_HD,
DSDprocessDMRvoice,
DSDprocessDMRdata,
DSDprocessX2TDMAvoice,
DSDprocessX2TDMAdata,
DSDprocessProVoice,
DSDprocessUnknown
} DSDFSMState;
DSDDecoder();
~DSDDecoder();
void run(short sample);
short *getAudio(int& nbSamples)
{
nbSamples = m_state.audio_out_nb_samples;
return m_state.audio_out_buf;
}
void resetAudio()
{
m_state.audio_out_nb_samples = 0;
m_state.audio_out_buf_p = m_state.audio_out_buf;
}
DSDOpts *getOpts() { return &m_opts; }
DSDState *getState() { return &m_state; }
private:
bool pushSample(short sample, int have_sync); //!< push a new sample into the decoder. Returns true if a new symbol is available
int getDibit(); //!< get dibit from the last retrieved symbol. Returns the dibit as its dibit value: 0,1,2,3
int getFrameSync();
void resetSymbol();
void resetFrameSync();
void printFrameSync(const char *frametype, int offset, char *modulation);
void noCarrier();
void printFrameInfo();
void processFrame();
static int comp(const void *a, const void *b);
DSDOpts m_opts;
DSDState m_state;
DSDFSMState m_fsmState;
// symbol engine
int m_symbol; //!< the last retrieved symbol
int m_sampleIndex; //!< the current sample index for the symbol in progress
int m_sum;
int m_count;
// sync engine:
int m_sync; //!< The current sync type
int m_dibit, m_synctest_pos, m_lastt;
char m_synctest[25];
char m_synctest18[19];
char m_synctest32[33];
char m_modulation[8];
char *m_synctest_p;
char m_synctest_buf[10240];
int m_lmin, m_lmax, m_lidx;
int m_lbuf[24], m_lbuf2[24];
int m_lsum;
char m_spectrum[64];
int m_t;
int m_hasSync; //!< tells whether we are in synced phase
// Other
DSDFilters m_dsdFilters;
// MBE decoder
DSDMBEDecoder m_mbeDecoder;
// Frame decoders
DSDDMRVoice m_dsdDMRVoice;
DSDDMRData m_dsdDMRData;
DSDDstar m_dsdDstar;
};
} // namespace dsdplus
#endif /* DSDPLUS_DSD_DECODER_H_ */

View File

@ -1,145 +0,0 @@
///////////////////////////////////////////////////////////////////////////////////
// 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include "dsd_filters.h"
namespace DSDplus
{
// DMR filter
const float DSDFilters::xcoeffs[] =
{ -0.0083649323f, -0.0265444850f, -0.0428141462f, -0.0537571943f,
-0.0564141052f, -0.0489161045f, -0.0310068662f, -0.0043393881f,
+0.0275375106f, +0.0595423283f, +0.0857543325f, +0.1003565948f,
+0.0986944931f, +0.0782804830f, +0.0395670487f, -0.0136691535f,
-0.0744390415f, -0.1331834575f, -0.1788967208f, -0.2005995448f,
-0.1889627181f, -0.1378439993f, -0.0454976231f, +0.0847488694f,
+0.2444859269f, +0.4209222342f, +0.5982295474f, +0.7593684540f,
+0.8881539892f, +0.9712773915f, +0.9999999166f, +0.9712773915f,
+0.8881539892f, +0.7593684540f, +0.5982295474f, +0.4209222342f,
+0.2444859269f, +0.0847488694f, -0.0454976231f, -0.1378439993f,
-0.1889627181f, -0.2005995448f, -0.1788967208f, -0.1331834575f,
-0.0744390415f, -0.0136691535f, +0.0395670487f, +0.0782804830f,
+0.0986944931f, +0.1003565948f, +0.0857543325f, +0.0595423283f,
+0.0275375106f, -0.0043393881f, -0.0310068662f, -0.0489161045f,
-0.0564141052f, -0.0537571943f, -0.0428141462f, -0.0265444850f,
-0.0083649323f, };
// NXDN filter
const float DSDFilters::nxcoeffs[] =
{ +0.031462429f, +0.031747267f, +0.030401148f, +0.027362877f, +0.022653298f,
+0.016379869f, +0.008737200f, +0.000003302f, -0.009468531f,
-0.019262057f, -0.028914291f, -0.037935027f, -0.045828927f,
-0.052119261f, -0.056372283f, -0.058221106f, -0.057387924f,
-0.053703443f, -0.047122444f, -0.037734535f, -0.025769308f,
-0.011595336f, +0.004287292f, +0.021260954f, +0.038610717f,
+0.055550276f, +0.071252765f, +0.084885375f, +0.095646450f,
+0.102803611f, +0.105731303f, +0.103946126f, +0.097138329f,
+0.085197939f, +0.068234131f, +0.046586711f, +0.020828821f,
-0.008239664f, -0.039608255f, -0.072081234f, -0.104311776f,
-0.134843790f, -0.162160200f, -0.184736015f, -0.201094346f,
-0.209863285f, -0.209831516f, -0.200000470f, -0.179630919f,
-0.148282051f, -0.105841323f, -0.052543664f, +0.011020985f,
+0.083912428f, +0.164857408f, +0.252278939f, +0.344336996f,
+0.438979335f, +0.534000832f, +0.627109358f, +0.715995947f,
+0.798406824f, +0.872214756f, +0.935487176f, +0.986548646f,
+1.024035395f, +1.046939951f, +1.054644241f, +1.046939951f,
+1.024035395f, +0.986548646f, +0.935487176f, +0.872214756f,
+0.798406824f, +0.715995947f, +0.627109358f, +0.534000832f,
+0.438979335f, +0.344336996f, +0.252278939f, +0.164857408f,
+0.083912428f, +0.011020985f, -0.052543664f, -0.105841323f,
-0.148282051f, -0.179630919f, -0.200000470f, -0.209831516f,
-0.209863285f, -0.201094346f, -0.184736015f, -0.162160200f,
-0.134843790f, -0.104311776f, -0.072081234f, -0.039608255f,
-0.008239664f, +0.020828821f, +0.046586711f, +0.068234131f,
+0.085197939f, +0.097138329f, +0.103946126f, +0.105731303f,
+0.102803611f, +0.095646450f, +0.084885375f, +0.071252765f,
+0.055550276f, +0.038610717f, +0.021260954f, +0.004287292f,
-0.011595336f, -0.025769308f, -0.037734535f, -0.047122444f,
-0.053703443f, -0.057387924f, -0.058221106f, -0.056372283f,
-0.052119261f, -0.045828927f, -0.037935027f, -0.028914291f,
-0.019262057f, -0.009468531f, +0.000003302f, +0.008737200f,
+0.016379869f, +0.022653298f, +0.027362877f, +0.030401148f,
+0.031747267f, +0.031462429f, };
DSDFilters::DSDFilters()
{
for (int i=0; i < NZEROS+1; i++) {
xv[i] = 0.0f;
}
for (int i=0; i < NXZEROS+1; i++) {
nxv[i] = 0.0f;
}
}
DSDFilters::~DSDFilters()
{
}
short DSDFilters::dmr_filter(short sample)
{
return dsd_input_filter(sample, 1);
}
short DSDFilters::nxdn_filter(short sample)
{
return dsd_input_filter(sample, 2);
}
short DSDFilters::dsd_input_filter(short sample, int mode)
{
float sum;
int i;
float gain;
int zeros;
float *v;
const float *coeffs;
switch (mode)
{
case 1:
gain = ngain;
v = xv;
coeffs = xcoeffs;
zeros = NZEROS;
break;
case 2:
gain = nxgain;
v = nxv;
coeffs = nxcoeffs;
zeros = NXZEROS;
break;
default:
return sample;
}
for (i = 0; i < zeros; i++) {
v[i] = v[i + 1];
}
v[zeros] = sample; // unfiltered sample in
sum = 0.0f;
for (i = 0; i <= zeros; i++) {
sum += (coeffs[i] * v[i]);
}
return sum / ngain; // filtered sample out
}
} // namespace dsdplus

View File

@ -1,49 +0,0 @@
///////////////////////////////////////////////////////////////////////////////////
// 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef DSDPLUS_DSD_FILTERS_H_
#define DSDPLUS_DSD_FILTERS_H_
#define NZEROS 60
#define NXZEROS 134
namespace DSDplus
{
class DSDFilters
{
public:
DSDFilters();
~DSDFilters();
static const float ngain = 7.423339364f;
static const float xcoeffs[];
static const float nxgain = 15.95930463f;
static const float nxcoeffs[];
short dsd_input_filter(short sample, int mode);
short dmr_filter(short sample);
short nxdn_filter(short sample);
private:
float xv[NZEROS+1];
float nxv[NXZEROS+1];
};
}
#endif /* DSDPLUS_DSD_FILTERS_H_ */

View File

@ -1,319 +0,0 @@
///////////////////////////////////////////////////////////////////////////////////
// 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include <string.h>
#include <math.h>
#include "dsd_mbe.h"
#include "dsd_decoder.h"
extern "C" {
#include <mbelib.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(stderr, "%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 data 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) || (m_dsdDecoder->m_opts.upsample != 0)) // upsampling to 48k
{
if (m_dsdDecoder->m_state.audio_out_nb_samples + 960 >= m_dsdDecoder->m_state.audio_out_buf_size)
{
m_dsdDecoder->resetAudio();
}
m_dsdDecoder->m_state.audio_out_float_buf_p = m_dsdDecoder->m_state.audio_out_float_buf;
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 = m_dsdDecoder->m_state.audio_out_float_buf;
// 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++;
if (m_dsdDecoder->m_opts.stereo) // produce second channel
{
*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_nb_samples++;
m_dsdDecoder->m_state.audio_out_float_buf_p++;
}
m_dsdDecoder->m_state.audio_out_float_buf_p += m_dsdDecoder->m_opts.playoffset;
}
else // leave at 8k
{
if (m_dsdDecoder->m_state.audio_out_nb_samples + 160 >= m_dsdDecoder->m_state.audio_out_buf_size)
{
m_dsdDecoder->resetAudio();
}
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++;
if (m_dsdDecoder->m_opts.stereo) // produce second channel
{
*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_nb_samples++;
m_dsdDecoder->m_state.audio_out_temp_buf_p++;
m_dsdDecoder->m_state.audio_out_idx++;
m_dsdDecoder->m_state.audio_out_idx2++;
}
}
}
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;
}
}
}
}

View File

@ -1,45 +0,0 @@
///////////////////////////////////////////////////////////////////////////////////
// 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#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_ */

View File

@ -1,67 +0,0 @@
///////////////////////////////////////////////////////////////////////////////////
// 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include "dsd_opts.h"
namespace DSDplus
{
DSDOpts::DSDOpts()
{
onesymbol = 10;
errorbars = 1;
datascope = 0;
symboltiming = 0;
verbose = 2;
p25enc = 0;
p25lc = 0;
p25status = 0;
p25tg = 0;
scoperate = 15;
split = 0;
playoffset = 0;
audio_gain = 0;
audio_out = 1;
resume = 0;
frame_dstar = 0;
frame_x2tdma = 1;
frame_p25p1 = 1;
frame_nxdn48 = 0;
frame_nxdn96 = 1;
frame_dmr = 1;
frame_provoice = 0;
mod_c4fm = 1;
mod_qpsk = 1;
mod_gfsk = 1;
uvquality = 3;
inverted_x2tdma = 1; // most transmitter + scanner + sound card combinations show inverted signals for this
inverted_dmr = 0; // most transmitter + scanner + sound card combinations show non-inverted signals for this
mod_threshold = 26;
ssize = 36;
msize = 15;
delay = 0;
use_cosine_filter = 1;
unmute_encrypted_p25 = 0;
upsample = 0;
stereo = 0;
}
DSDOpts::~DSDOpts()
{
}
} // namespace dsdplus

View File

@ -1,69 +0,0 @@
///////////////////////////////////////////////////////////////////////////////////
// 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef DSDPLUS_DSD_OPTS_H_
#define DSDPLUS_DSD_OPTS_H_
namespace DSDplus
{
class DSDOpts
{
public:
DSDOpts();
~DSDOpts();
int onesymbol;
int errorbars;
int datascope;
int symboltiming;
int verbose;
int p25enc;
int p25lc;
int p25status;
int p25tg;
int scoperate;
int split;
int playoffset;
float audio_gain;
int audio_out;
int resume;
int frame_dstar;
int frame_x2tdma;
int frame_p25p1;
int frame_nxdn48;
int frame_nxdn96;
int frame_dmr;
int frame_provoice;
int mod_c4fm;
int mod_qpsk;
int mod_gfsk;
int uvquality;
int inverted_x2tdma;
int inverted_dmr;
int mod_threshold;
int ssize;
int msize;
int delay;
int use_cosine_filter;
int unmute_encrypted_p25;
int upsample; //!< force audio upsampling to 48k
int stereo; //!< double each audio sample to produce L+R channels
};
} // namespace dsdplus
#endif /* DSDPLUS_DSD_OPTS_H_ */

View File

@ -1,140 +0,0 @@
///////////////////////////////////////////////////////////////////////////////////
// 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include "dsd_state.h"
namespace DSDplus
{
DSDState::DSDState()
{
int i, j;
repeat = 0;
dibit_buf = (int *) malloc(sizeof(int) * 1000000);
memset(dibit_buf, 0, sizeof(int) * 200);
dibit_buf_p = dibit_buf + 200;
audio_out_buf = (short *) malloc(sizeof(short) * 2 * 48000); // 1s of L+R S16LE samples
memset(audio_out_buf, 0, sizeof(short) * 2 * 48000);
audio_out_buf_p = audio_out_buf;
audio_out_nb_samples = 0;
audio_out_buf_size = 48000; // given in number of unique samples
audio_out_float_buf = (float *) malloc(sizeof(float) * 960); // 1 frame of 160 samples upampled 6 times
memset(audio_out_float_buf, 0, sizeof(float) * 960);
audio_out_float_buf_p = audio_out_float_buf;
audio_out_temp_buf_p = audio_out_temp_buf;
audio_out_idx = 0;
audio_out_idx2 = 0;
center = 0;
jitter = -1;
synctype = -1;
min = -15000;
max = 15000;
lmid = 0;
umid = 0;
minref = -12000;
maxref = 12000;
lastsample = 0;
for (i = 0; i < 128; i++)
{
sbuf[i] = 0;
}
sidx = 0;
for (i = 0; i < 1024; i++)
{
maxbuf[i] = 15000;
}
for (i = 0; i < 1024; i++)
{
minbuf[i] = -15000;
}
midx = 0;
err_str[0] = 0;
sprintf(fsubtype, " ");
sprintf(ftype, " ");
symbolcnt = 0;
rf_mod = 0;
numflips = 0;
lastsynctype = -1;
lastp25type = 0;
offset = 0;
carrier = 0;
for (i = 0; i < 25; i++)
{
for (j = 0; j < 16; j++)
{
tg[i][j] = 48;
}
}
tgcount = 0;
lasttg = 0;
lastsrc = 0;
nac = 0;
errs = 0;
errs2 = 0;
mbe_file_type = -1;
optind = 0;
numtdulc = 0;
firstframe = 0;
sprintf(slot0light, " slot0 ");
sprintf(slot1light, " slot1 ");
aout_gain = 25;
memset(aout_max_buf, 0, sizeof(float) * 200);
aout_max_buf_p = aout_max_buf;
aout_max_buf_idx = 0;
samplesPerSymbol = 10;
symbolCenter = 4;
sprintf(algid, "________");
sprintf(keyid, "________________");
currentslot = 0;
cur_mp = (mbe_parms *) malloc(sizeof(mbe_parms));
prev_mp = (mbe_parms *) malloc(sizeof(mbe_parms));
prev_mp_enhanced = (mbe_parms *) malloc(sizeof(mbe_parms));
mbe_initMbeParms(cur_mp, prev_mp, prev_mp_enhanced);
p25kid = 0;
output_finished = 0;
output_offset = 0;
output_num_samples = 0;
output_samples = 0;
output_length = 0;
output_buffer = 0;
}
DSDState::~DSDState()
{
free(prev_mp_enhanced);
free(prev_mp);
free(cur_mp);
free(audio_out_float_buf);
free(audio_out_buf);
free(dibit_buf);
}
} // namespace dsdplus

View File

@ -1,112 +0,0 @@
///////////////////////////////////////////////////////////////////////////////////
// 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef DSDPLUS_DSD_STATE_H_
#define DSDPLUS_DSD_STATE_H_
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
extern "C" {
#include <mbelib.h>
}
namespace DSDplus
{
class DSDState
{
public:
DSDState();
~DSDState();
int *dibit_buf;
int *dibit_buf_p;
int repeat;
short *audio_out_buf; //!< final result
short *audio_out_buf_p;
int audio_out_nb_samples;
int audio_out_buf_size;
float *audio_out_float_buf; //!< output of upsampler
float *audio_out_float_buf_p;
float audio_out_temp_buf[160]; //!< output of decoder
float *audio_out_temp_buf_p;
int audio_out_idx;
int audio_out_idx2;
int center;
int jitter;
int synctype;
int min;
int max;
int lmid;
int umid;
int minref;
int maxref;
int lastsample;
int sbuf[128];
int sidx;
int maxbuf[1024];
int minbuf[1024];
int midx;
char err_str[64];
char fsubtype[16];
char ftype[16];
int symbolcnt;
int rf_mod;
int numflips;
int lastsynctype;
int lastp25type;
int offset;
int carrier;
char tg[25][16];
int tgcount;
int lasttg;
int lastsrc;
int nac;
int errs;
int errs2;
int mbe_file_type;
int optind;
int numtdulc;
int firstframe;
char slot0light[8];
char slot1light[8];
float aout_gain;
float aout_max_buf[200];
float *aout_max_buf_p;
int aout_max_buf_idx;
int samplesPerSymbol;
int symbolCenter;
char algid[9];
char keyid[17];
int currentslot;
mbe_parms *cur_mp;
mbe_parms *prev_mp;
mbe_parms *prev_mp_enhanced;
int p25kid;
short *output_buffer;
int output_offset;
float *output_samples;
int output_num_samples;
int output_length;
int output_finished;
};
} // namespace dsdplus
#endif /* DSDPLUS_DSD_STATE_H_ */

View File

@ -1,392 +0,0 @@
///////////////////////////////////////////////////////////////////////////////////
// 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include <string.h>
#include "dstar.h"
#include "dsd_decoder.h"
#include "descramble.h"
namespace DSDplus
{
const int DSDDstar::dW[72] = {
// 0-11
0, 0,
3, 2,
1, 1,
0, 0,
1, 1,
0, 0,
// 12-23
3, 2,
1, 1,
3, 2,
1, 1,
0, 0,
3, 2,
// 24-35
0, 0,
3, 2,
1, 1,
0, 0,
1, 1,
0, 0,
// 36-47
3, 2,
1, 1,
3, 2,
1, 1,
0, 0,
3, 2,
// 48-59
0, 0,
3, 2,
1, 1,
0, 0,
1, 1,
0, 0,
// 60-71
3, 2,
1, 1,
3, 3,
2, 1,
0, 0,
3, 3,
};
const int DSDDstar::dX[72] = {
// 0-11
10, 22,
11, 9,
10, 22,
11, 23,
8, 20,
9, 21,
// 12-23
10, 8,
9, 21,
8, 6,
7, 19,
8, 20,
9, 7,
// 24-35
6, 18,
7, 5,
6, 18,
7, 19,
4, 16,
5, 17,
// 36-47
6, 4,
5, 17,
4, 2,
3, 15,
4, 16,
5, 3,
// 48-59
2, 14,
3, 1,
2, 14,
3, 15,
0, 12,
1, 13,
// 60-71
2, 0,
1, 13,
0, 12,
10, 11,
0, 12,
1, 13,
};
DSDDstar::DSDDstar(DSDDecoder *dsdDecoder) :
m_dsdDecoder(dsdDecoder)
{
}
DSDDstar::~DSDDstar()
{
}
void DSDDstar::init()
{
if (m_dsdDecoder->m_opts.errorbars == 1) {
fprintf(stderr, "e:");
}
if (m_dsdDecoder->m_state.synctype == 18) {
framecount = 0;
m_dsdDecoder->m_state.synctype = 6;
} else if (m_dsdDecoder->m_state.synctype == 19) {
framecount = 0;
m_dsdDecoder->m_state.synctype = 7;
} else {
framecount = 1; //just saw a sync frame; there should be 20 not 21 till the next
}
sync_missed = 0;
bitbuffer = 0;
m_symbolIndex = 0;
m_symbolIndexHD = 0;
}
void DSDDstar::initVoiceFrame()
{
memset(ambe_fr, 0, 96);
// voice frame
w = dW;
x = dX;
}
void DSDDstar::initDataFrame()
{
}
void DSDDstar::process()
{
if (m_symbolIndex < 72) // voice frame
{
if (m_symbolIndex == 0) {
initVoiceFrame();
}
processVoice();
}
else if (m_symbolIndex < 97) // data frame
{
if (m_symbolIndex == 72) {
initDataFrame();
}
processData();
}
else
{
m_dsdDecoder->m_fsmState = DSDDecoder::DSDLookForSync; // end
}
m_symbolIndex++;
}
void DSDDstar::processHD()
{
int dibit = m_dsdDecoder->getDibit(); // get dibit from symbol and store it in HD cache
radioheaderbuffer[m_symbolIndexHD] = dibit;
if (m_symbolIndexHD == 660-1)
{
dstar_header_decode();
m_dsdDecoder->m_fsmState = DSDDecoder::DSDprocessDSTAR; // go to DSTAR
}
m_symbolIndexHD++;
}
void DSDDstar::processVoice()
{
int dibit = m_dsdDecoder->getDibit(); // get dibit from symbol and store it in cache
m_dibitCache[m_symbolIndex] = dibit;
if (m_symbolIndex == 72-1) // last dibit in voice frame
{
for (int i = 0; i < 72; i++)
{
int dibit = m_dibitCache[i];
bitbuffer <<= 1;
if (dibit == 1) {
bitbuffer |= 0x01;
}
if ((bitbuffer & 0x00FFFFFF) == 0x00AAB468)
{
// we're slipping bits
fprintf(stderr, "sync in voice after i=%d, restarting\n", i);
//ugh just start over
i = 0;
w = dW;
x = dX;
framecount = 1;
continue;
}
ambe_fr[*w][*x] = (1 & dibit);
w++;
x++;
}
m_dsdDecoder->m_mbeDecoder.processFrame(0, ambe_fr, 0);
}
}
void DSDDstar::processData()
{
bool terminate = false;
int dibit = m_dsdDecoder->getDibit(); // get dibit from symbol and store it in cache
m_dibitCache[m_symbolIndex] = dibit;
if (m_symbolIndex == 97-1) // last dibit in data frame
{
for (int i = 73; i < 97; i++)
{
int dibit = m_dibitCache[i];
bitbuffer <<= 1;
if (dibit == 1) {
bitbuffer |= 0x01;
}
if ((bitbuffer & 0x00FFFFFF) == 0x00AAB468)
{
// looking if we're slipping bits
if (i != 96)
{
fprintf(stderr, "sync after i=%d\n", i);
break;
}
}
}
slowdata[0] = (bitbuffer >> 16) & 0x000000FF;
slowdata[1] = (bitbuffer >> 8) & 0x000000FF;
slowdata[2] = (bitbuffer) & 0x000000FF;
slowdata[3] = 0;
if ((bitbuffer & 0x00FFFFFF) == 0x00AAB468)
{
//We got sync!
//printf("Sync on framecount = %d\n", framecount);
sync_missed = 0;
}
else if ((bitbuffer & 0x00FFFFFF) == 0xAAAAAA)
{
//End of transmission
printf("End of transmission\n");
terminate = true;
}
else if (framecount % 21 == 0)
{
printf("Missed sync on framecount = %d, value = %x/%x/%x\n",
framecount, slowdata[0], slowdata[1], slowdata[2]);
sync_missed++;
}
else if (framecount != 0 && (bitbuffer & 0x00FFFFFF) != 0x000000)
{
slowdata[0] ^= 0x70;
slowdata[1] ^= 0x4f;
slowdata[2] ^= 0x93;
//printf("unscrambled- %s",slowdata);
}
else if (framecount == 0)
{
//printf("never scrambled-%s\n",slowdata);
}
if (terminate)
{
m_dsdDecoder->m_fsmState = DSDDecoder::DSDLookForSync; // end
}
else if (sync_missed < 3)
{
m_symbolIndex = 0; // restart a frame sequence
framecount++;
}
else
{
m_dsdDecoder->m_fsmState = DSDDecoder::DSDLookForSync; // end
}
}
}
void DSDDstar::dstar_header_decode()
{
int radioheaderbuffer2[660];
unsigned char radioheader[41];
int octetcount, bitcount, loop;
unsigned char bit2octet[] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};
unsigned int FCSinheader;
unsigned int FCScalculated;
int len;
Descramble::scramble(radioheaderbuffer, radioheaderbuffer2);
Descramble::deinterleave(radioheaderbuffer2, radioheaderbuffer);
len = Descramble::FECdecoder(radioheaderbuffer, radioheaderbuffer2);
memset(radioheader, 0, 41);
// note we receive 330 bits, but we only use 328 of them (41 octets)
// bits 329 and 330 are unused
octetcount = 0;
bitcount = 0;
for (loop = 0; loop < 328; loop++)
{
if (radioheaderbuffer2[loop])
{
radioheader[octetcount] |= bit2octet[bitcount];
};
bitcount++;
// increase octetcounter and reset bitcounter every 8 bits
if (bitcount >= 8)
{
octetcount++;
bitcount = 0;
}
}
// print header
printf("\nDSTAR HEADER: ");
//printf("FLAG1: %02X - FLAG2: %02X - FLAG3: %02X\n", radioheader[0],
// radioheader[1], radioheader[2]);
printf("RPT 2: %c%c%c%c%c%c%c%c ", radioheader[3], radioheader[4],
radioheader[5], radioheader[6], radioheader[7], radioheader[8],
radioheader[9], radioheader[10]);
printf("RPT 1: %c%c%c%c%c%c%c%c ", radioheader[11], radioheader[12],
radioheader[13], radioheader[14], radioheader[15], radioheader[16],
radioheader[17], radioheader[18]);
printf("YOUR: %c%c%c%c%c%c%c%c ", radioheader[19], radioheader[20],
radioheader[21], radioheader[22], radioheader[23], radioheader[24],
radioheader[25], radioheader[26]);
printf("MY: %c%c%c%c%c%c%c%c/%c%c%c%c\n", radioheader[27], radioheader[28],
radioheader[29], radioheader[30], radioheader[31], radioheader[32],
radioheader[33], radioheader[34], radioheader[35], radioheader[36],
radioheader[37], radioheader[38]);
//FCSinheader = ((radioheader[39] << 8) | radioheader[40]) & 0xFFFF;
//FCScalculated = calc_fcs((unsigned char*) radioheader, 39);
//printf("Check sum = %04X ", FCSinheader);
//if (FCSinheader == FCScalculated) {
// printf("(OK)\n");
//} else {
// printf("(NOT OK- Calculated FCS = %04X)\n", FCScalculated);
//}; // end else - if
}
} // namespace DSDplus

View File

@ -1,68 +0,0 @@
///////////////////////////////////////////////////////////////////////////////////
// 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef DSDPLUS_DSTAR_H_
#define DSDPLUS_DSTAR_H_
namespace DSDplus
{
class DSDDecoder;
class DSDDstar
{
public:
DSDDstar(DSDDecoder *dsdDecoder);
~DSDDstar();
void init();
void process();
void processHD();
private:
void initVoiceFrame();
void initDataFrame();
void processVoice();
void processData();
void dstar_header_decode();
DSDDecoder *m_dsdDecoder;
int m_symbolIndex; //!< Current symbol index in non HD sequence
int m_symbolIndexHD; //!< Current symbol index in HD sequence
int m_dibitCache[97]; // has to handle a voice + data frame (97 dibits)
int m_dibitIndex; // index in dibit cache
// DSTAR
char ambe_fr[4][24];
unsigned char data[9];
unsigned int bits[4];
int framecount;
int sync_missed;
unsigned char slowdata[4];
unsigned int bitbuffer;
const int *w, *x;
// DSTAR-HD
int radioheaderbuffer[660];
// constants
static const int dW[72];
static const int dX[72];
};
} // namespace DSDplus
#endif /* DSDPLUS_DSTAR_H_ */

View File

@ -10,6 +10,6 @@ add_subdirectory(udpsrc)
add_subdirectory(demodwfm)
add_subdirectory(chanalyzer)
if(LIBMBE_FOUND)
if(LIBDSDCC_FOUND AND LIBMBE_FOUND)
add_subdirectory(demoddsd)
endif(LIBMBE_FOUND)
endif(LIBDSDCC_FOUND AND LIBMBE_FOUND)

View File

@ -20,8 +20,8 @@ set(dsddemod_FORMS
include_directories(
.
../../../dsdplus
${CMAKE_CURRENT_BINARY_DIR}
${LIBDSDCC_INCLUDE_DIR}
${LIBMBE_INCLUDE_DIR}
)
@ -41,7 +41,7 @@ add_library(demoddsd SHARED
target_link_libraries(demoddsd
${QT_LIBRARIES}
sdrbase
dsdplus
${LIBDSDCC_LIBRARIES}
${LIBMBE_LIBRARY}
)

View File

@ -22,36 +22,12 @@
DSDDecoder::DSDDecoder()
{
DSDplus::DSDOpts *dsdopts = m_decoder.getOpts();
DSDplus::DSDState *dsdstate = m_decoder.getState();
dsdopts->split = 1;
dsdopts->upsample = 1; // force upsampling of audio to 48k
dsdopts->playoffset = 0;
dsdopts->delay = 0;
// Initialize with auto-detect:
dsdopts->frame_dstar = 1;
dsdopts->frame_x2tdma = 1;
dsdopts->frame_p25p1 = 1;
dsdopts->frame_nxdn48 = 0;
dsdopts->frame_nxdn96 = 1;
dsdopts->frame_dmr = 1;
dsdopts->frame_provoice = 0;
dsdopts->uvquality = 3; // This is gr-dsd default
dsdopts->verbose = 2; // This is gr-dsd default
dsdopts->errorbars = 1; // This is gr-dsd default
// Initialize with auto detection of modulation optimization:
dsdopts->mod_c4fm = 1;
dsdopts->mod_qpsk = 1;
dsdopts->mod_gfsk = 1;
dsdstate->rf_mod = 0;
dsdstate->output_offset = 0;
dsdopts->upsample = 1;
dsdopts->stereo = 1;
m_decoder.setQuiet();
m_decoder.setUpsampling(6); // force upsampling of audio to 48k
m_decoder.setStereo(true); // force copy to L+R channels
m_decoder.setDecodeMode(DSDcc::DSDDecoder::DSDDecodeAuto, true); // Initialize with auto-detect
m_decoder.setUvQuality(3); // This is gr-dsd default
m_decoder.setModulationOptimizations(DSDcc::DSDDecoder::DSDModulationOptimAuto); // Initialize with auto detection of modulation optimization:
}
DSDDecoder::~DSDDecoder()

View File

@ -33,7 +33,7 @@ public:
void resetAudio() { m_decoder.resetAudio(); }
private:
DSDplus::DSDDecoder m_decoder;
DSDcc::DSDDecoder m_decoder;
};
#endif /* PLUGINS_CHANNEL_DEMODDSD_DSDDECODER_H_ */