confirmed working with P/invoke on windows .NET Core C#

main
Patrick W3AXL 1 year ago
parent d6c59be715
commit a9a2a17d23

5
.gitignore vendored

@ -32,4 +32,7 @@
*.app *.app
# Build directory # Build directory
build/ build/
# VS stuff
.vs/

@ -16,6 +16,11 @@ project(dvmvocoder)
set(CMAKE_STATIC_LIBRARY_PREFIX "") set(CMAKE_STATIC_LIBRARY_PREFIX "")
set(CMAKE_SHARED_LIBRARY_PREFIX "") set(CMAKE_SHARED_LIBRARY_PREFIX "")
# Set up export symbols (Windows only)
if(WIN32)
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
endif()
# #
# Build Vocoder as a Shared Library (dll or so) # Build Vocoder as a Shared Library (dll or so)
# #

@ -16,301 +16,328 @@
#include "MBEDecoder.h" #include "MBEDecoder.h"
using namespace edac; using namespace edac;
using namespace vocoder;
namespace vocoder {
// ---------------------------------------------------------------------------
// Constants // ---------------------------------------------------------------------------
// --------------------------------------------------------------------------- // Constants
// ---------------------------------------------------------------------------
const int MBEDecoder::dW[72] = { 0,0,3,2,1,1,0,0,1,1,0,0,3,2,1,1,3,2,1,1,0,0,3,2,0,0,3,2,1,1,0,0,1,1,0,0,3,2,1,1,3,2,1,1,0,0,3,2,0,0,3,2,1,1,0,0,1,1,0,0,3,2,1,1,3,3,2,1,0,0,3,3, };
const int MBEDecoder::dW[72] = { 0,0,3,2,1,1,0,0,1,1,0,0,3,2,1,1,3,2,1,1,0,0,3,2,0,0,3,2,1,1,0,0,1,1,0,0,3,2,1,1,3,2,1,1,0,0,3,2,0,0,3,2,1,1,0,0,1,1,0,0,3,2,1,1,3,3,2,1,0,0,3,3, };
const int MBEDecoder::dX[72] = { 10,22,11,9,10,22,11,23,8,20,9,21,10,8,9,21,8,6,7,19,8,20,9,7,6,18,7,5,6,18,7,19,4,16,5,17,6,4,5,17,4,2,3,15,4,16,5,3,2,14,3,1,2,14,3,15,0,12,1,13,2,0,1,13,0,12,10,11,0,12,1,13, };
const int MBEDecoder::dX[72] = { 10,22,11,9,10,22,11,23,8,20,9,21,10,8,9,21,8,6,7,19,8,20,9,7,6,18,7,5,6,18,7,19,4,16,5,17,6,4,5,17,4,2,3,15,4,16,5,3,2,14,3,1,2,14,3,15,0,12,1,13,2,0,1,13,0,12,10,11,0,12,1,13, };
const int MBEDecoder::rW[36] = {
0, 1, 0, 1, 0, 1, const int MBEDecoder::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, 1,
0, 1, 0, 1, 0, 2, 0, 1, 0, 1, 0, 1,
0, 2, 0, 2, 0, 2, 0, 1, 0, 1, 0, 2,
0, 2, 0, 2, 0, 2 0, 2, 0, 2, 0, 2,
}; 0, 2, 0, 2, 0, 2
};
const int MBEDecoder::rX[36] = {
23, 10, 22, 9, 21, 8, const int MBEDecoder::rX[36] = {
20, 7, 19, 6, 18, 5, 23, 10, 22, 9, 21, 8,
17, 4, 16, 3, 15, 2, 20, 7, 19, 6, 18, 5,
14, 1, 13, 0, 12, 10, 17, 4, 16, 3, 15, 2,
11, 9, 10, 8, 9, 7, 14, 1, 13, 0, 12, 10,
8, 6, 7, 5, 6, 4 11, 9, 10, 8, 9, 7,
}; 8, 6, 7, 5, 6, 4
};
// bit 0
const int MBEDecoder::rY[36] = { // bit 0
0, 2, 0, 2, 0, 2, const int MBEDecoder::rY[36] = {
0, 2, 0, 3, 0, 3, 0, 2, 0, 2, 0, 2,
1, 3, 1, 3, 1, 3, 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,
1, 3, 1, 3, 1, 3 1, 3, 1, 3, 1, 3,
}; 1, 3, 1, 3, 1, 3
};
const int MBEDecoder::rZ[36] = {
5, 3, 4, 2, 3, 1, const int MBEDecoder::rZ[36] = {
2, 0, 1, 13, 0, 12, 5, 3, 4, 2, 3, 1,
22, 11, 21, 10, 20, 9, 2, 0, 1, 13, 0, 12,
19, 8, 18, 7, 17, 6, 22, 11, 21, 10, 20, 9,
16, 5, 15, 4, 14, 3, 19, 8, 18, 7, 17, 6,
13, 2, 12, 1, 11, 0 16, 5, 15, 4, 14, 3,
}; 13, 2, 12, 1, 11, 0
};
// ---------------------------------------------------------------------------
// Public Class Members // ---------------------------------------------------------------------------
// --------------------------------------------------------------------------- // Public Class Members
// ---------------------------------------------------------------------------
/* Initializes a new instance of the MBEDecoder class. */
/* Initializes a new instance of the MBEDecoder class. */
MBEDecoder::MBEDecoder(MBE_DECODER_MODE mode) :
m_mbelibParms(NULL), MBEDecoder::MBEDecoder(MBE_DECODER_MODE mode) :
m_mbeMode(mode), m_mbelibParms(NULL),
m_gainAdjust(1.0f) m_mbeMode(mode),
{ m_gainAdjust(1.0f)
m_mbelibParms = new mbelibParms();
mbe_initMbeParms(m_mbelibParms->m_cur_mp, m_mbelibParms->m_prev_mp, m_mbelibParms->m_prev_mp_enhanced);
::memset(gainMaxBuf, 0, sizeof(float) * 200);
gainMaxBufPtr = gainMaxBuf;
gainMaxIdx = 0;
}
/* Finalizes a instance of the MBEDecoder class. */
MBEDecoder::~MBEDecoder()
{
delete m_mbelibParms;
}
/* Decodes the given MBE codewords to deinterleaved MBE bits using the decoder mode. */
int32_t MBEDecoder::decodeBits(uint8_t* codeword, char* mbeBits)
{
int32_t errs = 0;
float samples[160U];
::memset(samples, 0x00U, 160U * sizeof(float));
switch (m_mbeMode)
{
case DECODE_DMR_AMBE:
{ {
char ambe_d[49U]; m_mbelibParms = new mbelibParms();
char ambe_fr[4][24]; mbe_initMbeParms(m_mbelibParms->m_cur_mp, m_mbelibParms->m_prev_mp, m_mbelibParms->m_prev_mp_enhanced);
::memset(ambe_d, 0x00U, 49U);
::memset(ambe_fr, 0x00U, 96U);
const int* w, *x, *y, *z;
w = rW;
x = rX;
y = rY;
z = rZ;
for (int i = 0; i < 9; ++i) {
for (int j = 0; j < 8; j += 2) {
ambe_fr[*y][*z] = (1 & (codeword[i] >> (7 - (j + 1))));
ambe_fr[*w][*x] = (1 & (codeword[i] >> (7 - j)));
w++;
x++;
y++;
z++;
}
}
errs = mbe_eccAmbe3600x2450C0(ambe_fr); ::memset(gainMaxBuf, 0, sizeof(float) * 200);
mbe_demodulateAmbe3600x2450Data(ambe_fr); gainMaxBufPtr = gainMaxBuf;
gainMaxIdx = 0;
}
errs += mbe_eccAmbe3600x2450Data(ambe_fr, ambe_d); /* Finalizes a instance of the MBEDecoder class. */
::memcpy(mbeBits, ambe_d, 49U); MBEDecoder::~MBEDecoder()
{
delete m_mbelibParms;
} }
break;
case DECODE_88BIT_IMBE: /* Decodes the given MBE codewords to deinterleaved MBE bits using the decoder mode. */
int32_t MBEDecoder::decodeBits(uint8_t* codeword, char* mbeBits)
{ {
char imbe_d[88U]; int32_t errs = 0;
::memset(imbe_d, 0x00U, 88U); float samples[160U];
::memset(samples, 0x00U, 160U * sizeof(float));
switch (m_mbeMode)
{
case DECODE_DMR_AMBE:
{
char ambe_d[49U];
char ambe_fr[4][24];
::memset(ambe_d, 0x00U, 49U);
::memset(ambe_fr, 0x00U, 96U);
const int* w, *x, *y, *z;
w = rW;
x = rX;
y = rY;
z = rZ;
for (int i = 0; i < 9; ++i) {
for (int j = 0; j < 8; j += 2) {
ambe_fr[*y][*z] = (1 & (codeword[i] >> (7 - (j + 1))));
ambe_fr[*w][*x] = (1 & (codeword[i] >> (7 - j)));
w++;
x++;
y++;
z++;
}
}
for (int i = 0; i < 11; ++i) { errs = mbe_eccAmbe3600x2450C0(ambe_fr);
for (int j = 0; j < 8; j++) { mbe_demodulateAmbe3600x2450Data(ambe_fr);
imbe_d[j + (8 * i)] = (1 & (codeword[i] >> (7 - j)));
errs += mbe_eccAmbe3600x2450Data(ambe_fr, ambe_d);
::memcpy(mbeBits, ambe_d, 49U);
}
break;
case DECODE_88BIT_IMBE:
{
char imbe_d[88U];
::memset(imbe_d, 0x00U, 88U);
for (int i = 0; i < 11; ++i) {
for (int j = 0; j < 8; j++) {
imbe_d[j + (8 * i)] = (1 & (codeword[i] >> (7 - j)));
}
} }
::memcpy(mbeBits, imbe_d, 88U);
}
break;
} }
::memcpy(mbeBits, imbe_d, 88U); return errs;
} }
break;
}
return errs;
}
/* Decodes the given MBE codewords to PCM samples using the decoder mode. */ /* Decodes the given MBE codewords to PCM samples using the decoder mode. */
int32_t MBEDecoder::decodeF(uint8_t* codeword, float samples[]) int32_t MBEDecoder::decodeF(uint8_t* codeword, float samples[])
{
int32_t errs = 0;
switch (m_mbeMode)
{ {
case DECODE_DMR_AMBE: int32_t errs = 0;
{ switch (m_mbeMode)
char ambe_d[49U]; {
char ambe_fr[4][24]; case DECODE_DMR_AMBE:
::memset(ambe_d, 0x00U, 49U); {
::memset(ambe_fr, 0x00U, 96U); char ambe_d[49U];
char ambe_fr[4][24];
const int* w, *x, *y, *z; ::memset(ambe_d, 0x00U, 49U);
::memset(ambe_fr, 0x00U, 96U);
w = rW;
x = rX; const int* w, *x, *y, *z;
y = rY;
z = rZ; w = rW;
x = rX;
for (int i = 0; i < 9; ++i) { y = rY;
for (int j = 0; j < 8; j += 2) { z = rZ;
ambe_fr[*y][*z] = (1 & (codeword[i] >> (7 - (j + 1))));
ambe_fr[*w][*x] = (1 & (codeword[i] >> (7 - j))); for (int i = 0; i < 9; ++i) {
w++; for (int j = 0; j < 8; j += 2) {
x++; ambe_fr[*y][*z] = (1 & (codeword[i] >> (7 - (j + 1))));
y++; ambe_fr[*w][*x] = (1 & (codeword[i] >> (7 - j)));
z++; w++;
x++;
y++;
z++;
}
} }
}
int ambeErrs; int ambeErrs;
char ambeErrStr[64U]; char ambeErrStr[64U];
::memset(ambeErrStr, 0x20U, 64U); ::memset(ambeErrStr, 0x20U, 64U);
mbe_processAmbe3600x2450FrameF(samples, &ambeErrs, &errs, ambeErrStr, ambe_fr, ambe_d, m_mbelibParms->m_cur_mp, m_mbelibParms->m_prev_mp, m_mbelibParms->m_prev_mp_enhanced, 3); mbe_processAmbe3600x2450FrameF(samples, &ambeErrs, &errs, ambeErrStr, ambe_fr, ambe_d, m_mbelibParms->m_cur_mp, m_mbelibParms->m_prev_mp, m_mbelibParms->m_prev_mp_enhanced, 3);
} }
break; break;
case DECODE_88BIT_IMBE: case DECODE_88BIT_IMBE:
{ {
char imbe_d[88U]; char imbe_d[88U];
::memset(imbe_d, 0x00U, 88U); ::memset(imbe_d, 0x00U, 88U);
for (int i = 0; i < 11; ++i) { for (int i = 0; i < 11; ++i) {
for (int j = 0; j < 8; j++) { for (int j = 0; j < 8; j++) {
imbe_d[j + (8 * i)] = (1 & (codeword[i] >> (7 - j))); imbe_d[j + (8 * i)] = (1 & (codeword[i] >> (7 - j)));
}
} }
}
int ambeErrs; int ambeErrs;
char ambeErrStr[64U]; char ambeErrStr[64U];
::memset(ambeErrStr, 0x20U, 64U); ::memset(ambeErrStr, 0x20U, 64U);
mbe_processImbe4400DataF(samples, &ambeErrs, &errs, ambeErrStr, imbe_d, m_mbelibParms->m_cur_mp, m_mbelibParms->m_prev_mp, m_mbelibParms->m_prev_mp_enhanced, 3); mbe_processImbe4400DataF(samples, &ambeErrs, &errs, ambeErrStr, imbe_d, m_mbelibParms->m_cur_mp, m_mbelibParms->m_prev_mp, m_mbelibParms->m_prev_mp_enhanced, 3);
} }
break; break;
}
return errs;
} }
return errs; /* Decodes the given MBE codewords to PCM samples using the decoder mode. */
}
/* Decodes the given MBE codewords to PCM samples using the decoder mode. */ int32_t MBEDecoder::decode(uint8_t* codeword, int16_t samples[])
{
float samplesF[160U];
::memset(samplesF, 0x00U, 160U * sizeof(float));
int32_t errs = decodeF(codeword, samplesF);
float* sampleFPtr = samplesF;
if (m_autoGain) {
// detect max level
float max = 0.0f;
for (int n = 0; n < 160; n++) {
float out = fabsf(*sampleFPtr);
if (out > max) {
max = out;
}
sampleFPtr++;
}
int32_t MBEDecoder::decode(uint8_t* codeword, int16_t samples[]) *gainMaxBufPtr = max;
{ gainMaxBufPtr++;
float samplesF[160U]; gainMaxIdx++;
::memset(samplesF, 0x00U, 160U * sizeof(float));
int32_t errs = decodeF(codeword, samplesF);
float* sampleFPtr = samplesF; if (gainMaxIdx > 24) {
if (m_autoGain) { gainMaxIdx = 0;
// detect max level gainMaxBufPtr = gainMaxBuf;
float max = 0.0f;
for (int n = 0; n < 160; n++) {
float out = fabsf(*sampleFPtr);
if (out > max) {
max = out;
} }
sampleFPtr++; // lookup max history
} for (int i = 0; i < 25; i++) {
float a = gainMaxBuf[i];
*gainMaxBufPtr = max; if (a > max) {
gainMaxBufPtr++; max = a;
gainMaxIdx++; }
}
if (gainMaxIdx > 24) { // determine optimal gain level
gainMaxIdx = 0; float gainFactor = 0.0f, gainDelta = 0.0f;
gainMaxBufPtr = gainMaxBuf; if (max > static_cast<float>(0)) {
} gainFactor = (static_cast<float>(30000) / max);
}
else {
gainFactor = static_cast<float>(50);
}
// lookup max history if (gainFactor < m_gainAdjust) {
for (int i = 0; i < 25; i++) { m_gainAdjust = gainFactor;
float a = gainMaxBuf[i]; gainDelta = static_cast<float>(0);
if (a > max) {
max = a;
} }
} else {
if (gainFactor > static_cast<float>(50)) {
gainFactor = static_cast<float>(50);
}
// determine optimal gain level gainDelta = gainFactor - m_gainAdjust;
float gainFactor = 0.0f, gainDelta = 0.0f;
if (max > static_cast<float>(0)) {
gainFactor = (static_cast<float>(30000) / max);
}
else {
gainFactor = static_cast<float>(50);
}
if (gainFactor < m_gainAdjust) { if (gainDelta > (static_cast<float>(0.05) * m_gainAdjust)) {
m_gainAdjust = gainFactor; gainDelta = (static_cast<float>(0.05) * m_gainAdjust);
gainDelta = static_cast<float>(0); }
}
else {
if (gainFactor > static_cast<float>(50)) {
gainFactor = static_cast<float>(50);
} }
gainDelta = gainFactor - m_gainAdjust; gainDelta /= static_cast<float>(160);
if (gainDelta > (static_cast<float>(0.05) * m_gainAdjust)) { // adjust output gain
gainDelta = (static_cast<float>(0.05) * m_gainAdjust); sampleFPtr = samplesF;
for (int n = 0; n < 160; n++) {
*sampleFPtr = (m_gainAdjust + (static_cast<float>(n) * gainDelta)) * (*sampleFPtr);
sampleFPtr++;
} }
}
gainDelta /= static_cast<float>(160); m_gainAdjust += (static_cast<float>(160) * gainDelta);
}
// adjust output gain int16_t* samplePtr = samples;
sampleFPtr = samplesF; sampleFPtr = samplesF;
for (int n = 0; n < 160; n++) { for (int n = 0; n < 160; n++) {
*sampleFPtr = (m_gainAdjust + (static_cast<float>(n) * gainDelta)) * (*sampleFPtr); float smp = *sampleFPtr;
if (!m_autoGain) {
smp *= m_gainAdjust;
}
// audio clipping
if (smp > 32760) {
smp = 32760;
}
else if (smp < -32760) {
smp = -32760;
}
*samplePtr = (int16_t)(smp);
samplePtr++;
sampleFPtr++; sampleFPtr++;
} }
m_gainAdjust += (static_cast<float>(160) * gainDelta); return errs;
} }
int16_t* samplePtr = samples; // Extern methods for C#/C++ interop
sampleFPtr = samplesF; MBEDecoder* MBEDecoder_Create(MBE_DECODER_MODE mode)
for (int n = 0; n < 160; n++) { {
float smp = *sampleFPtr; return new MBEDecoder(mode);
if (!m_autoGain) { }
smp *= m_gainAdjust;
}
// audio clipping int32_t MBEDecoder_Decode(MBEDecoder* pDecoder, uint8_t* codeword, int16_t* samples)
if (smp > 32760) { {
smp = 32760; if (pDecoder != NULL)
} {
else if (smp < -32760) { return pDecoder->decode(codeword, samples);
smp = -32760;
} }
return -1;
}
*samplePtr = (int16_t)(smp); void MBEDecoder_Delete(MBEDecoder* pDecoder)
{
samplePtr++; if (pDecoder != NULL)
sampleFPtr++; {
delete pDecoder;
pDecoder = NULL;
}
} }
return errs; } // namespace vocoder
}

@ -138,9 +138,17 @@ namespace vocoder
}; };
// Extern methods for C#/C++ interop // Extern methods for C#/C++ interop
extern "C" MBEDecoder* MBEDecoder_Create(MBE_DECODER_MODE mode) { return new MBEDecoder(mode); } extern "C" {
extern "C" int32_t MBEDecoder_Decode(MBEDecoder* pDecoder, uint8_t* codeword, int16_t* samples) { return pDecoder->decode(codeword, samples); } #ifdef _WIN32
extern "C" void MBEDecoder_Delete(MBEDecoder* pDecoder) { delete pDecoder; } extern __declspec(dllexport) MBEDecoder* MBEDecoder_Create(MBE_DECODER_MODE mode);
extern __declspec(dllexport) int32_t MBEDecoder_Decode(MBEDecoder* pDecoder, uint8_t* codeword, int16_t* samples);
extern __declspec(dllexport) void MBEDecoder_Delete(MBEDecoder* pDecoder);
#else
extern MBEDecoder* MBEDecoder_Create(MBE_DECODER_MODE mode);
extern int32_t MBEDecoder_Decode(MBEDecoder* pDecoder, uint8_t* codeword, int16_t* samples);
extern void MBEDecoder_Delete(MBEDecoder* pDecoder);
#endif
}
} // namespace vocoder } // namespace vocoder

File diff suppressed because it is too large Load Diff

@ -81,9 +81,17 @@ namespace vocoder
}; };
// Extern methods for C#/C++ interop // Extern methods for C#/C++ interop
extern "C" MBEEncoder* MBEEncoder_Create(MBE_ENCODER_MODE mode) { return new MBEEncoder(mode); } extern "C" {
extern "C" void MBEEncoder_Encode(MBEEncoder* pEncoder, int16_t* samples, uint8_t* codeword) { pEncoder->encode(samples, codeword); } #ifdef _WIN32
extern "C" void MBEEncoder_Delete(MBEEncoder* pEncoder) { delete pEncoder; } __declspec(dllexport) MBEEncoder* MBEEncoder_Create(MBE_ENCODER_MODE mode);
__declspec(dllexport) void MBEEncoder_Encode(MBEEncoder* pEncoder, int16_t* samples, uint8_t* codeword);
__declspec(dllexport) void MBEEncoder_Delete(MBEEncoder* pEncoder);
#else
MBEEncoder* MBEEncoder_Create(MBE_ENCODER_MODE mode);
void MBEEncoder_Encode(MBEEncoder* pEncoder, int16_t* samples, uint8_t* codeword);
void MBEEncoder_Delete(MBEEncoder* pEncoder);
#endif
}
} // namespace vocoder } // namespace vocoder

Loading…
Cancel
Save

Powered by TurnKey Linux.