mirror of
https://github.com/g4klx/DMRGateway
synced 2026-02-04 21:35:42 +08:00
First workable version of the speech module.
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -14,5 +14,3 @@ MMDVMHost
|
|||||||
*.user
|
*.user
|
||||||
*.VC.db
|
*.VC.db
|
||||||
.vs
|
.vs
|
||||||
*.ambe
|
|
||||||
GitVersion.h
|
|
||||||
|
|||||||
BIN
Audio/fr_FR.ambe
Normal file
BIN
Audio/fr_FR.ambe
Normal file
Binary file not shown.
12
Audio/fr_FR.indx
Normal file
12
Audio/fr_FR.indx
Normal file
@@ -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
|
||||||
@@ -23,7 +23,7 @@ Directory=./Audio
|
|||||||
|
|
||||||
[XLX Network]
|
[XLX Network]
|
||||||
Address=xlx950.epf.lu
|
Address=xlx950.epf.lu
|
||||||
Port=55555
|
Port=62030
|
||||||
# Local=3351
|
# Local=3351
|
||||||
# Options=
|
# Options=
|
||||||
Password=passw0rd
|
Password=passw0rd
|
||||||
|
|||||||
151
Voice.cpp
151
Voice.cpp
@@ -27,6 +27,21 @@
|
|||||||
|
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
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;
|
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) :
|
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_seqNo(0U),
|
||||||
m_streamId(0U),
|
m_streamId(0U),
|
||||||
m_sent(0U),
|
m_sent(0U),
|
||||||
|
m_positions(NULL),
|
||||||
m_ambe(NULL),
|
m_ambe(NULL),
|
||||||
m_data(),
|
m_data(),
|
||||||
m_it(),
|
m_it()
|
||||||
m_start(),
|
|
||||||
m_length()
|
|
||||||
{
|
{
|
||||||
m_embeddedLC.setLC(m_lc);
|
m_embeddedLC.setLC(m_lc);
|
||||||
|
|
||||||
|
m_positions = new CPositions[12U];
|
||||||
|
::memset(m_positions, 0x00U, 12U * sizeof(CPositions));
|
||||||
|
|
||||||
#if defined(_WIN32) || defined(_WIN64)
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
m_indxFile = directory + "\\" + language + ".indx";
|
m_indxFile = directory + "\\" + language + ".indx";
|
||||||
m_ambeFile = directory + "\\" + language + ".ambe";
|
m_ambeFile = directory + "\\" + language + ".ambe";
|
||||||
@@ -66,6 +83,7 @@ CVoice::~CVoice()
|
|||||||
m_data.clear();
|
m_data.clear();
|
||||||
|
|
||||||
delete[] m_ambe;
|
delete[] m_ambe;
|
||||||
|
delete[] m_positions;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CVoice::open()
|
bool CVoice::open()
|
||||||
@@ -105,8 +123,43 @@ bool CVoice::open()
|
|||||||
unsigned int start = ::atoi(p2) * 9U;
|
unsigned int start = ::atoi(p2) * 9U;
|
||||||
unsigned int length = ::atoi(p3) * 9U;
|
unsigned int length = ::atoi(p3) * 9U;
|
||||||
|
|
||||||
m_start[p1] = start;
|
if (::strcmp(p1, "0") == 0) {
|
||||||
m_length[p1] = length;
|
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)
|
void CVoice::linkedTo(unsigned int id)
|
||||||
{
|
{
|
||||||
for (std::vector<CDMRData*>::iterator it = m_data.begin(); it != m_data.end(); ++it)
|
char number[10U];
|
||||||
delete *it;
|
::sprintf(number, "%04u", id);
|
||||||
|
|
||||||
m_data.clear();
|
std::vector<unsigned int> 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;
|
createVoice(words);
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CVoice::unlinked()
|
void CVoice::unlinked()
|
||||||
{
|
{
|
||||||
|
std::vector<unsigned int> words;
|
||||||
|
words.push_back(POSITION_DISCONNECTED);
|
||||||
|
|
||||||
|
createVoice(words);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CVoice::createVoice(const std::vector<unsigned int>& words)
|
||||||
|
{
|
||||||
|
unsigned int ambeLength = 0U;
|
||||||
|
for (std::vector<unsigned int>::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<unsigned int>::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<CDMRData*>::iterator it = m_data.begin(); it != m_data.end(); ++it)
|
for (std::vector<CDMRData*>::iterator it = m_data.begin(); it != m_data.end(); ++it)
|
||||||
delete *it;
|
delete *it;
|
||||||
|
|
||||||
@@ -156,20 +231,19 @@ void CVoice::unlinked()
|
|||||||
createHeaderTerminator(DT_VOICE_LC_HEADER);
|
createHeaderTerminator(DT_VOICE_LC_HEADER);
|
||||||
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 buffer[DMR_FRAME_LENGTH_BYTES];
|
||||||
|
|
||||||
unsigned char* p = m_ambe + start;
|
unsigned int n = 0U;
|
||||||
for (unsigned int i = 0U; i < length; i++, p += 27U) {
|
for (unsigned int i = 0U; i < ambeLength; i += 27U) {
|
||||||
|
unsigned char* p = ambeData + i;
|
||||||
|
|
||||||
CDMRData* data = new CDMRData;
|
CDMRData* data = new CDMRData;
|
||||||
|
|
||||||
data->setSlotNo(m_slot);
|
data->setSlotNo(m_slot);
|
||||||
data->setFLCO(FLCO_GROUP);
|
data->setFLCO(FLCO_GROUP);
|
||||||
data->setSrcId(m_lc.getSrcId());
|
data->setSrcId(m_lc.getSrcId());
|
||||||
data->setDstId(m_lc.getDstId());
|
data->setDstId(m_lc.getDstId());
|
||||||
data->setN();
|
data->setN(n);
|
||||||
data->setSeqNo(m_seqNo++);
|
data->setSeqNo(m_seqNo++);
|
||||||
data->setStreamId(m_streamId);
|
data->setStreamId(m_streamId);
|
||||||
|
|
||||||
@@ -179,26 +253,33 @@ void CVoice::unlinked()
|
|||||||
::memcpy(buffer + 24U, p + 18U, 9U);
|
::memcpy(buffer + 24U, p + 18U, 9U);
|
||||||
|
|
||||||
if (n == 0U) {
|
if (n == 0U) {
|
||||||
CSync::addDMRAudioSync(buffer);
|
CSync::addDMRAudioSync(buffer, true);
|
||||||
data->setDataType(DT_VOICE_SYNC);
|
data->setDataType(DT_VOICE_SYNC);
|
||||||
} else {
|
} else {
|
||||||
|
unsigned char lcss = m_embeddedLC.getData(buffer, n);
|
||||||
|
|
||||||
CDMREMB emb;
|
CDMREMB emb;
|
||||||
emb.setColorCode(COLOR_CODE);
|
emb.setColorCode(COLOR_CODE);
|
||||||
emb.setPI(false);
|
emb.setPI(false);
|
||||||
emb.setLCSS();
|
emb.setLCSS(lcss);
|
||||||
emb.getData(buffer);
|
emb.getData(buffer);
|
||||||
|
|
||||||
m_embeddedLC.getData(buffer, n);
|
|
||||||
|
|
||||||
data->setDataType(DT_VOICE);
|
data->setDataType(DT_VOICE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
n++;
|
||||||
|
if (n >= 6U)
|
||||||
|
n = 0U;
|
||||||
|
|
||||||
data->setData(buffer);
|
data->setData(buffer);
|
||||||
|
|
||||||
m_data.push_back(data);
|
m_data.push_back(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
createHeaderTerminator(DT_TERMINATOR_WITH_LC);
|
createHeaderTerminator(DT_TERMINATOR_WITH_LC);
|
||||||
|
createHeaderTerminator(DT_TERMINATOR_WITH_LC);
|
||||||
|
|
||||||
|
delete[] ambeData;
|
||||||
|
|
||||||
m_status = VS_WAITING;
|
m_status = VS_WAITING;
|
||||||
m_timer.start();
|
m_timer.start();
|
||||||
|
|||||||
10
Voice.h
10
Voice.h
@@ -25,7 +25,6 @@
|
|||||||
#include "DMRLC.h"
|
#include "DMRLC.h"
|
||||||
#include "Timer.h"
|
#include "Timer.h"
|
||||||
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@@ -35,6 +34,11 @@ enum VOICE_STATUS {
|
|||||||
VS_SENDING
|
VS_SENDING
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct CPositions {
|
||||||
|
unsigned int m_start;
|
||||||
|
unsigned int m_length;
|
||||||
|
};
|
||||||
|
|
||||||
class CVoice {
|
class CVoice {
|
||||||
public:
|
public:
|
||||||
CVoice(const std::string& directory, const std::string& language, unsigned int id, unsigned int slot, unsigned int tg);
|
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_streamId;
|
||||||
unsigned int m_sent;
|
unsigned int m_sent;
|
||||||
unsigned char* m_ambe;
|
unsigned char* m_ambe;
|
||||||
|
CPositions* m_positions;
|
||||||
std::vector<CDMRData*> m_data;
|
std::vector<CDMRData*> m_data;
|
||||||
std::vector<CDMRData*>::const_iterator m_it;
|
std::vector<CDMRData*>::const_iterator m_it;
|
||||||
std::unordered_map<std::string, unsigned int> m_start;
|
|
||||||
std::unordered_map<std::string, unsigned int> m_length;
|
|
||||||
|
|
||||||
void createHeaderTerminator(unsigned char type);
|
void createHeaderTerminator(unsigned char type);
|
||||||
|
void createVoice(const std::vector<unsigned int>& words);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user