From 955d126058f13b14f457d55cae9233092813115c Mon Sep 17 00:00:00 2001 From: Doug McLain Date: Thu, 5 Jan 2023 19:05:53 -0500 Subject: [PATCH] Add IMBE transcode for P25 --- Controller.cpp | 72 ++++++++++++++++++++++++++++++++++++++++++++ Controller.h | 9 +++++- Makefile | 2 +- TranscoderPacket.cpp | 23 ++++++++++++-- TranscoderPacket.h | 5 ++- 5 files changed, 106 insertions(+), 5 deletions(-) diff --git a/Controller.cpp b/Controller.cpp index a4e31eb..94a2370 100644 --- a/Controller.cpp +++ b/Controller.cpp @@ -1,5 +1,6 @@ // tcd - a hybid transcoder using DVSI hardware and Codec2 software // Copyright © 2021 Thomas A. Early N7TAE +// Copyright © 2021 Doug McLain AD8DP // 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 @@ -23,6 +24,7 @@ #include #include + #include "TranscoderPacket.h" #include "Controller.h" @@ -54,6 +56,7 @@ bool CController::Start() reflectorFuture = std::async(std::launch::async, &CController::ReadReflectorThread, this); c2Future = std::async(std::launch::async, &CController::ProcessC2Thread, this); swambe2Future = std::async(std::launch::async, &CController::ProcessSWAMBE2Thread,this); + imbeFuture = std::async(std::launch::async, &CController::ProcessIMBEThread,this); return false; } @@ -260,6 +263,9 @@ void CController::ReadReflectorThread() else dmrsf_device->AddPacket(packet); break; + case ECodecType::p25: + imbe_queue.push(packet); + break; case ECodecType::c2_1600: case ECodecType::c2_3200: codec2_queue.push(packet); @@ -308,6 +314,7 @@ void CController::AudiotoCodec2(std::shared_ptr packet) void CController::Codec2toAudio(std::shared_ptr packet) { uint8_t ambe2[9]; + uint8_t imbe[11]; if (packet->IsSecond()) { @@ -354,6 +361,8 @@ void CController::Codec2toAudio(std::shared_ptr packet) md380_encode_fec(ambe2, packet->GetAudioSamples()); packet->SetDMRData(ambe2); + p25vocoder.encode_4400((int16_t*)packet->GetAudioSamples(), imbe); + packet->SetP25Data(imbe); } void CController::ProcessC2Thread() @@ -373,6 +382,7 @@ void CController::ProcessC2Thread() case ECodecType::dstar: case ECodecType::dmr: + case ECodecType::p25: // codec_in was AMBE, so we need to calculate the the M17 data AudiotoCodec2(packet); break; @@ -413,6 +423,7 @@ void CController::SWAMBE2toAudio(std::shared_ptr packet) packet->SetAudioSamples(tmp, false); dstar_device->AddPacket(packet); codec2_queue.push(packet); + imbe_queue.push(packet); } void CController::ProcessSWAMBE2Thread() @@ -426,6 +437,7 @@ void CController::ProcessSWAMBE2Thread() case ECodecType::c2_1600: case ECodecType::c2_3200: case ECodecType::dstar: + case ECodecType::p25: AudiotoSWAMBE2(packet); break; @@ -436,6 +448,64 @@ void CController::ProcessSWAMBE2Thread() } } +void CController::AudiotoIMBE(std::shared_ptr packet) +{ + const auto m = packet->GetModule(); + uint8_t imbe[11]; + int16_t tmp[160]; + const int16_t *p = packet->GetAudioSamples(); + const uint32_t g = abs(gain); + + for(int i = 0; i < 160; ++i){ + if(gain < 0){ + tmp[i] = p[i] / g; + } + else{ + tmp[i] = p[i] * g; + } + } + + p25vocoder.encode_4400(tmp, imbe); + packet->SetP25Data(imbe); + + // we might be all done... + send_mux.lock(); + if (packet->AllCodecsAreSet() && packet->HasNotBeenSent()) SendToReflector(packet); + send_mux.unlock(); +} + +void CController::IMBEtoAudio(std::shared_ptr packet) +{ + int16_t tmp[160] = {0}; + p25vocoder.decode_4400(tmp, (uint8_t*)packet->GetP25Data()); + packet->SetAudioSamples(tmp, false); + dstar_device->AddPacket(packet); + codec2_queue.push(packet); + swambe2_queue.push(packet); +} + +void CController::ProcessIMBEThread() +{ + while (keep_running) + { + auto packet = imbe_queue.pop(); + + switch (packet->GetCodecIn()) + { + case ECodecType::c2_1600: + case ECodecType::c2_3200: + case ECodecType::dstar: + case ECodecType::dmr: + AudiotoIMBE(packet); + break; + + case ECodecType::p25: + IMBEtoAudio(packet); + break; + } + } +} + void CController::SendToReflector(std::shared_ptr packet) { // open a socket to the reflector channel @@ -455,6 +525,7 @@ void CController::RouteDstPacket(std::shared_ptr packet) { // codec_in is dstar, the audio has just completed, so now calc the M17 and DMR codec2_queue.push(packet); + imbe_queue.push(packet); if(swambe2) swambe2_queue.push(packet); else @@ -473,6 +544,7 @@ void CController::RouteDmrPacket(std::shared_ptr packet) if (ECodecType::dmr == packet->GetCodecIn()) { codec2_queue.push(packet); + imbe_queue.push(packet); dstar_device->AddPacket(packet); } else diff --git a/Controller.h b/Controller.h index 81375e1..265af22 100644 --- a/Controller.h +++ b/Controller.h @@ -2,6 +2,7 @@ // tcd - a hybid transcoder using DVSI hardware and Codec2 software // Copyright © 2021 Thomas A. Early N7TAE +// Copyright © 2021 Doug McLain AD8DP // 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 @@ -23,6 +24,7 @@ #include #include #include +#include #include "codec2.h" #include "DV3000.h" @@ -44,7 +46,7 @@ public: protected: std::atomic keep_running; - std::future reflectorFuture, c2Future, swambe2Future; + std::future reflectorFuture, c2Future, swambe2Future, imbeFuture; std::unordered_map audio_store; std::unordered_map data_store; CUnixDgramReader reader; @@ -54,9 +56,11 @@ protected: CPacketQueue codec2_queue; CPacketQueue swambe2_queue; + CPacketQueue imbe_queue; std::mutex send_mux; int16_t gain; bool swambe2; + imbe_vocoder p25vocoder; bool DiscoverFtdiDevices(std::list> &found); bool InitVocoders(); @@ -64,9 +68,12 @@ protected: void ReadReflectorThread(); void ProcessC2Thread(); void ProcessSWAMBE2Thread(); + void ProcessIMBEThread(); void Codec2toAudio(std::shared_ptr packet); void AudiotoCodec2(std::shared_ptr packet); void SWAMBE2toAudio(std::shared_ptr packet); void AudiotoSWAMBE2(std::shared_ptr packet); + void IMBEtoAudio(std::shared_ptr packet); + void AudiotoIMBE(std::shared_ptr packet); void SendToReflector(std::shared_ptr packet); }; diff --git a/Makefile b/Makefile index 7e8ceca..92359e7 100644 --- a/Makefile +++ b/Makefile @@ -14,7 +14,7 @@ else CFLAGS = -W -Werror -Icodec2 -MMD -MD -std=c++11 endif -LDFLAGS = -lftd2xx -lmd380_vocoder -pthread +LDFLAGS = -lftd2xx -lmd380_vocoder -limbe_vocoder -pthread SRCS = $(wildcard *.cpp) $(wildcard codec2/*.cpp) OBJS = $(SRCS:.cpp=.o) diff --git a/TranscoderPacket.cpp b/TranscoderPacket.cpp index 76df4a0..c9f46ad 100644 --- a/TranscoderPacket.cpp +++ b/TranscoderPacket.cpp @@ -19,7 +19,7 @@ #include "TranscoderPacket.h" -CTranscoderPacket::CTranscoderPacket(const STCPacket &tcp) : dstar_set(false), dmr_set(false), m17_set(false), not_sent(true) +CTranscoderPacket::CTranscoderPacket(const STCPacket &tcp) : dstar_set(false), dmr_set(false), p25_set(false), m17_set(false), not_sent(true) { tcpacket.module = tcp.module; tcpacket.is_last = tcp.is_last; @@ -34,6 +34,9 @@ CTranscoderPacket::CTranscoderPacket(const STCPacket &tcp) : dstar_set(false), d case ECodecType::dmr: SetDMRData(tcp.dmr); break; + case ECodecType::p25: + SetP25Data(tcp.p25); + break; case ECodecType::c2_1600: case ECodecType::c2_3200: SetM17Data(tcp.m17); @@ -59,6 +62,11 @@ const uint8_t *CTranscoderPacket::GetDMRData() const return tcpacket.dmr; } +const uint8_t *CTranscoderPacket::GetP25Data() const +{ + return tcpacket.p25; +} + const uint8_t *CTranscoderPacket::GetM17Data() const { return tcpacket.m17; @@ -87,6 +95,12 @@ void CTranscoderPacket::SetDMRData(const uint8_t *dmr) dmr_set = true; } +void CTranscoderPacket::SetP25Data(const uint8_t *p25) +{ + memcpy(tcpacket.p25, p25, 11); + p25_set = true; +} + void CTranscoderPacket::SetAudioSamples(const int16_t *sample, bool swap) { for (unsigned int i=0; i<160; i++) @@ -138,6 +152,11 @@ bool CTranscoderPacket::DMRIsSet() const return dmr_set; } +bool CTranscoderPacket::P25IsSet() const +{ + return p25_set; +} + bool CTranscoderPacket::M17IsSet() const { return m17_set; @@ -145,7 +164,7 @@ bool CTranscoderPacket::M17IsSet() const bool CTranscoderPacket::AllCodecsAreSet() const { - return (dstar_set && dmr_set && m17_set); + return (dstar_set && dmr_set && m17_set && p25_set); } void CTranscoderPacket::Sent() diff --git a/TranscoderPacket.h b/TranscoderPacket.h index 4986b41..b76162f 100644 --- a/TranscoderPacket.h +++ b/TranscoderPacket.h @@ -35,9 +35,11 @@ public: // codec const uint8_t *GetDStarData() const; const uint8_t *GetDMRData() const; + const uint8_t *GetP25Data() const; const uint8_t *GetM17Data() const; void SetDStarData(const uint8_t *dstar); void SetDMRData(const uint8_t *dmr); + void SetP25Data(const uint8_t *p25); void SetM17Data(const uint8_t *m17); void SetAudioSamples(const int16_t *samples, bool swap); @@ -53,6 +55,7 @@ public: bool IsSecond() const; bool DStarIsSet() const; bool DMRIsSet() const; + bool P25IsSet() const; bool M17IsSet() const; bool AllCodecsAreSet() const; void Sent(); @@ -64,5 +67,5 @@ public: private: STCPacket tcpacket; int16_t audio[160]; - std::atomic_bool dstar_set, dmr_set, m17_set, not_sent; + std::atomic_bool dstar_set, dmr_set, p25_set, m17_set, not_sent; };