From 1861a0a21edc9d52af569bff18772929f3777257 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Tue, 2 May 2017 21:02:37 +0100 Subject: [PATCH] First workable version of the speech module. --- .gitignore | 2 - Audio/fr_FR.ambe | Bin 0 -> 3834 bytes Audio/fr_FR.indx | 12 ++++ DMRGateway.ini | 2 +- Voice.cpp | 151 ++++++++++++++++++++++++++++++++++++----------- Voice.h | 10 +++- 6 files changed, 136 insertions(+), 41 deletions(-) create mode 100644 Audio/fr_FR.ambe create mode 100644 Audio/fr_FR.indx diff --git a/.gitignore b/.gitignore index 690a1f9..44bad9c 100644 --- a/.gitignore +++ b/.gitignore @@ -14,5 +14,3 @@ MMDVMHost *.user *.VC.db .vs -*.ambe -GitVersion.h diff --git a/Audio/fr_FR.ambe b/Audio/fr_FR.ambe new file mode 100644 index 0000000000000000000000000000000000000000..ea7f83617d0fd6bc6ce88d725221144b9f6e88dd GIT binary patch literal 3834 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 literal 0 HcmV?d00001 diff --git a/Audio/fr_FR.indx b/Audio/fr_FR.indx new file mode 100644 index 0000000..524c04a --- /dev/null +++ b/Audio/fr_FR.indx @@ -0,0 +1,12 @@ +0 0 32 +1 32 16 +2 48 30 +3 78 30 +4 108 32 +5 140 37 +6 177 33 +7 210 34 +8 244 41 +9 285 39 +connected 324 45 +disconnected 369 57 diff --git a/DMRGateway.ini b/DMRGateway.ini index 8bbf3d6..4c6e82f 100644 --- a/DMRGateway.ini +++ b/DMRGateway.ini @@ -23,7 +23,7 @@ Directory=./Audio [XLX Network] Address=xlx950.epf.lu -Port=55555 +Port=62030 # Local=3351 # Options= Password=passw0rd diff --git a/Voice.cpp b/Voice.cpp index 8cbebae..1b6829c 100644 --- a/Voice.cpp +++ b/Voice.cpp @@ -27,6 +27,21 @@ #include +const unsigned char SILENCE[] = {0xACU, 0xAAU, 0x40U, 0x20U, 0x00U, 0x44U, 0x40U, 0x80U, 0x80U}; + +const unsigned int POSITION_0 = 0U; +const unsigned int POSITION_1 = 1U; +const unsigned int POSITION_2 = 2U; +const unsigned int POSITION_3 = 3U; +const unsigned int POSITION_4 = 4U; +const unsigned int POSITION_5 = 5U; +const unsigned int POSITION_6 = 6U; +const unsigned int POSITION_7 = 7U; +const unsigned int POSITION_8 = 8U; +const unsigned int POSITION_9 = 9U; +const unsigned int POSITION_CONNECTED = 10U; +const unsigned int POSITION_DISCONNECTED = 11U; + const unsigned char COLOR_CODE = 3U; CVoice::CVoice(const std::string& directory, const std::string& language, unsigned int id, unsigned int slot, unsigned int tg) : @@ -41,14 +56,16 @@ m_stopWatch(), m_seqNo(0U), m_streamId(0U), m_sent(0U), +m_positions(NULL), m_ambe(NULL), m_data(), -m_it(), -m_start(), -m_length() +m_it() { m_embeddedLC.setLC(m_lc); + m_positions = new CPositions[12U]; + ::memset(m_positions, 0x00U, 12U * sizeof(CPositions)); + #if defined(_WIN32) || defined(_WIN64) m_indxFile = directory + "\\" + language + ".indx"; m_ambeFile = directory + "\\" + language + ".ambe"; @@ -66,6 +83,7 @@ CVoice::~CVoice() m_data.clear(); delete[] m_ambe; + delete[] m_positions; } bool CVoice::open() @@ -105,8 +123,43 @@ bool CVoice::open() unsigned int start = ::atoi(p2) * 9U; unsigned int length = ::atoi(p3) * 9U; - m_start[p1] = start; - m_length[p1] = length; + if (::strcmp(p1, "0") == 0) { + m_positions[POSITION_0].m_start = start; + m_positions[POSITION_0].m_length = length; + } else if (::strcmp(p1, "1") == 0) { + m_positions[POSITION_1].m_start = start; + m_positions[POSITION_1].m_length = length; + } else if (::strcmp(p1, "2") == 0) { + m_positions[POSITION_2].m_start = start; + m_positions[POSITION_2].m_length = length; + } else if (::strcmp(p1, "3") == 0) { + m_positions[POSITION_3].m_start = start; + m_positions[POSITION_3].m_length = length; + } else if (::strcmp(p1, "4") == 0) { + m_positions[POSITION_4].m_start = start; + m_positions[POSITION_4].m_length = length; + } else if (::strcmp(p1, "5") == 0) { + m_positions[POSITION_5].m_start = start; + m_positions[POSITION_5].m_length = length; + } else if (::strcmp(p1, "6") == 0) { + m_positions[POSITION_6].m_start = start; + m_positions[POSITION_6].m_length = length; + } else if (::strcmp(p1, "7") == 0) { + m_positions[POSITION_7].m_start = start; + m_positions[POSITION_7].m_length = length; + } else if (::strcmp(p1, "8") == 0) { + m_positions[POSITION_8].m_start = start; + m_positions[POSITION_8].m_length = length; + } else if (::strcmp(p1, "9") == 0) { + m_positions[POSITION_9].m_start = start; + m_positions[POSITION_9].m_length = length; + } else if (::strcmp(p1, "connected") == 0) { + m_positions[POSITION_CONNECTED].m_start = start; + m_positions[POSITION_CONNECTED].m_length = length; + } else if (::strcmp(p1, "disconnected") == 0) { + m_positions[POSITION_DISCONNECTED].m_start = start; + m_positions[POSITION_DISCONNECTED].m_length = length; + } } } @@ -118,32 +171,54 @@ bool CVoice::open() void CVoice::linkedTo(unsigned int id) { - for (std::vector::iterator it = m_data.begin(); it != m_data.end(); ++it) - delete *it; + char number[10U]; + ::sprintf(number, "%04u", id); - m_data.clear(); + std::vector words; + words.push_back(POSITION_CONNECTED); + words.push_back(number[0U] - '0'); + words.push_back(number[1U] - '0'); + words.push_back(number[2U] - '0'); + words.push_back(number[3U] - '0'); - m_streamId = ::rand() + 1U; - m_seqNo = 0U; - - createHeaderTerminator(DT_VOICE_LC_HEADER); - createHeaderTerminator(DT_VOICE_LC_HEADER); - createHeaderTerminator(DT_VOICE_LC_HEADER); - - unsigned int length = 0U; - unsigned char* ambe = new unsigned char[10000U]; - - - delete[] ambe; - - createHeaderTerminator(DT_TERMINATOR_WITH_LC); - - m_status = VS_WAITING; - m_timer.start(); + createVoice(words); } void CVoice::unlinked() { + std::vector words; + words.push_back(POSITION_DISCONNECTED); + + createVoice(words); +} + +void CVoice::createVoice(const std::vector& words) +{ + unsigned int ambeLength = 0U; + for (std::vector::const_iterator it = words.begin(); it != words.end(); ++it) + ambeLength += m_positions[*it].m_length; + + // Ensure that the AMBE is an integer number of DMR frames + if ((ambeLength % 27U) != 0U) { + unsigned int frames = ambeLength / 27U; + frames++; + ambeLength = frames * 27U; + } + + unsigned char* ambeData = new unsigned char[ambeLength]; + + // Fill the AMBE data with silence + for (unsigned int i = 0U; i < ambeLength; i += 9U) + ::memcpy(ambeData + i, SILENCE, 9U); + + unsigned int pos = 0U; + for (std::vector::const_iterator it = words.begin(); it != words.end(); ++it) { + unsigned int start = m_positions[*it].m_start; + unsigned int length = m_positions[*it].m_length; + ::memcpy(ambeData + pos, m_ambe + start, length); + pos += length; + } + for (std::vector::iterator it = m_data.begin(); it != m_data.end(); ++it) delete *it; @@ -156,20 +231,19 @@ void CVoice::unlinked() createHeaderTerminator(DT_VOICE_LC_HEADER); createHeaderTerminator(DT_VOICE_LC_HEADER); - unsigned int start = m_start["disconnected"]; - unsigned int length = m_length["disconnected"] / 9U; - unsigned char buffer[DMR_FRAME_LENGTH_BYTES]; - unsigned char* p = m_ambe + start; - for (unsigned int i = 0U; i < length; i++, p += 27U) { + unsigned int n = 0U; + for (unsigned int i = 0U; i < ambeLength; i += 27U) { + unsigned char* p = ambeData + i; + CDMRData* data = new CDMRData; data->setSlotNo(m_slot); data->setFLCO(FLCO_GROUP); data->setSrcId(m_lc.getSrcId()); data->setDstId(m_lc.getDstId()); - data->setN(); + data->setN(n); data->setSeqNo(m_seqNo++); data->setStreamId(m_streamId); @@ -179,26 +253,33 @@ void CVoice::unlinked() ::memcpy(buffer + 24U, p + 18U, 9U); if (n == 0U) { - CSync::addDMRAudioSync(buffer); + CSync::addDMRAudioSync(buffer, true); data->setDataType(DT_VOICE_SYNC); } else { + unsigned char lcss = m_embeddedLC.getData(buffer, n); + CDMREMB emb; emb.setColorCode(COLOR_CODE); emb.setPI(false); - emb.setLCSS(); + emb.setLCSS(lcss); emb.getData(buffer); - m_embeddedLC.getData(buffer, n); - data->setDataType(DT_VOICE); } + n++; + if (n >= 6U) + n = 0U; + data->setData(buffer); m_data.push_back(data); } createHeaderTerminator(DT_TERMINATOR_WITH_LC); + createHeaderTerminator(DT_TERMINATOR_WITH_LC); + + delete[] ambeData; m_status = VS_WAITING; m_timer.start(); diff --git a/Voice.h b/Voice.h index abda07b..3280955 100644 --- a/Voice.h +++ b/Voice.h @@ -25,7 +25,6 @@ #include "DMRLC.h" #include "Timer.h" -#include #include #include @@ -35,6 +34,11 @@ enum VOICE_STATUS { VS_SENDING }; +struct CPositions { + unsigned int m_start; + unsigned int m_length; +}; + class CVoice { public: CVoice(const std::string& directory, const std::string& language, unsigned int id, unsigned int slot, unsigned int tg); @@ -62,12 +66,12 @@ private: unsigned int m_streamId; unsigned int m_sent; unsigned char* m_ambe; + CPositions* m_positions; std::vector m_data; std::vector::const_iterator m_it; - std::unordered_map m_start; - std::unordered_map m_length; void createHeaderTerminator(unsigned char type); + void createVoice(const std::vector& words); }; #endif