From 97189204dbfd4229fa6a3b1017d9314c7b8df36b Mon Sep 17 00:00:00 2001 From: Doug McLain Date: Mon, 12 Oct 2026 12:23:45 -0400 Subject: [PATCH] Add new no-hardware branch --- Configure.cpp | 211 +++++ Configure.h | 46 + Controller.cpp | 530 ++++++++++++ Controller.h | 83 ++ IP.cpp | 308 +++++++ IP.h | 74 ++ LICENSE | 674 +++++++++++++++ Main.cpp | 48 + Makefile | 45 + PacketQueue.h | 88 ++ README.md | 71 ++ TCPacketDef.h | 33 + TCSocket.cpp | 521 +++++++++++ TCSocket.h | 82 ++ Timer.h | 38 + TranscoderPacket.cpp | 200 +++++ TranscoderPacket.h | 73 ++ codec2/codebooks.cpp | 964 +++++++++++++++++++++ codec2/codec2.cpp | 1732 +++++++++++++++++++++++++++++++++++++ codec2/codec2.h | 98 +++ codec2/codec2_internal.h | 67 ++ codec2/defines.h | 127 +++ codec2/kiss_fft.cpp | 435 ++++++++++ codec2/kiss_fft.h | 35 + codec2/lpc.cpp | 311 +++++++ codec2/lpc.h | 47 + codec2/nlp.cpp | 520 +++++++++++ codec2/nlp.h | 87 ++ codec2/pack.cpp | 139 +++ codec2/qbase.cpp | 247 ++++++ codec2/qbase.h | 39 + codec2/quantise.cpp | 897 +++++++++++++++++++ codec2/quantise.h | 68 ++ config/tcd.ini | 20 + config/tcd.mk | 6 + config/tcd.service | 12 + mbe/ambe3600x2400.cpp | 756 ++++++++++++++++ mbe/ambe3600x2400_const.h | 884 +++++++++++++++++++ mbe/ambe3600x2450.cpp | 681 +++++++++++++++ mbe/ambe3600x2450_const.h | 971 +++++++++++++++++++++ mbe/dstar_pitch.h | 29 + mbe/ecc.cpp | 173 ++++ mbe/ecc_const.h | 112 +++ mbe/mbelib.cpp | 501 +++++++++++ mbe/mbelib.h | 114 +++ mbe/mbelib_const.h | 371 ++++++++ mbe/mbelib_parms.h | 44 + mbe/mbevocoder.cpp | 1343 ++++++++++++++++++++++++++++ mbe/mbevocoder.h | 63 ++ mbe/mbevocoder_api.h | 104 +++ mbe/vocoder_tables.h | 491 +++++++++++ 51 files changed, 15613 insertions(+) create mode 100644 Configure.cpp create mode 100644 Configure.h create mode 100644 Controller.cpp create mode 100644 Controller.h create mode 100644 IP.cpp create mode 100644 IP.h create mode 100644 LICENSE create mode 100644 Main.cpp create mode 100644 Makefile create mode 100644 PacketQueue.h create mode 100644 README.md create mode 100644 TCPacketDef.h create mode 100644 TCSocket.cpp create mode 100644 TCSocket.h create mode 100644 Timer.h create mode 100644 TranscoderPacket.cpp create mode 100644 TranscoderPacket.h create mode 100644 codec2/codebooks.cpp create mode 100644 codec2/codec2.cpp create mode 100644 codec2/codec2.h create mode 100644 codec2/codec2_internal.h create mode 100644 codec2/defines.h create mode 100644 codec2/kiss_fft.cpp create mode 100644 codec2/kiss_fft.h create mode 100644 codec2/lpc.cpp create mode 100644 codec2/lpc.h create mode 100644 codec2/nlp.cpp create mode 100644 codec2/nlp.h create mode 100644 codec2/pack.cpp create mode 100644 codec2/qbase.cpp create mode 100644 codec2/qbase.h create mode 100644 codec2/quantise.cpp create mode 100644 codec2/quantise.h create mode 100644 config/tcd.ini create mode 100644 config/tcd.mk create mode 100644 config/tcd.service create mode 100644 mbe/ambe3600x2400.cpp create mode 100644 mbe/ambe3600x2400_const.h create mode 100644 mbe/ambe3600x2450.cpp create mode 100644 mbe/ambe3600x2450_const.h create mode 100644 mbe/dstar_pitch.h create mode 100644 mbe/ecc.cpp create mode 100644 mbe/ecc_const.h create mode 100644 mbe/mbelib.cpp create mode 100644 mbe/mbelib.h create mode 100644 mbe/mbelib_const.h create mode 100644 mbe/mbelib_parms.h create mode 100644 mbe/mbevocoder.cpp create mode 100644 mbe/mbevocoder.h create mode 100644 mbe/mbevocoder_api.h create mode 100644 mbe/vocoder_tables.h diff --git a/Configure.cpp b/Configure.cpp new file mode 100644 index 0000000..c0c57ee --- /dev/null +++ b/Configure.cpp @@ -0,0 +1,211 @@ +/* + * Copyright (c) 2023 by Thomas A. Early N7TAE + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include "Configure.h" + +// ini file keywords +#define USRPTXGAIN "UsrpTxGain" +#define USRPRXGAIN "UsrpRxGain" +#define DMRGAININ "DmrYsfGainIn" +#define DMRGAINOUT "DmrYsfGainOut" +#define DSTARGAININ "DStarGainIn" +#define DSTARGAINOUT "DStarGainOut" +#define MODULES "Modules" +#define SERVERADDRESS "ServerAddress" +#define PORT "Port" + +static inline void split(const std::string &s, char delim, std::vector &v) +{ + std::istringstream iss(s); + std::string item; + while (std::getline(iss, item, delim)) + v.push_back(item); +} + +// trim from start (in place) +static inline void ltrim(std::string &s) { + s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](int ch) { + return !std::isspace(ch); + })); +} + +// trim from end (in place) +static inline void rtrim(std::string &s) { + s.erase(std::find_if(s.rbegin(), s.rend(), [](int ch) { + return !std::isspace(ch); + }).base(), s.end()); +} + +// trim from both ends (in place) +static inline void trim(std::string &s) { + ltrim(s); + rtrim(s); +} + +bool CConfigure::ReadData(const std::string &path) +// returns true on failure +{ + std::regex IPv4RegEx = std::regex("^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\.){3,3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9]){1,1}$", std::regex::extended); + std::regex IPv6RegEx = std::regex("^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}(:[0-9a-fA-F]{1,4}){1,1}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|([0-9a-fA-F]{1,4}:){1,1}(:[0-9a-fA-F]{1,4}){1,6}|:((:[0-9a-fA-F]{1,4}){1,7}|:))$", std::regex::extended); + + std::string modstmp, porttmp; + + std::ifstream cfgfile(path.c_str(), std::ifstream::in); + if (! cfgfile.is_open()) { + std::cerr << "ERROR: '" << path << "' was not found!" << std::endl; + return true; + } + + std::string line; + while (std::getline(cfgfile, line)) + { + trim(line); + if (3 > line.size()) + continue; // can't be anything + if ('#' == line.at(0)) + continue; // skip comments + + std::vector tokens; + split(line, '=', tokens); + // check value for end-of-line comment + if (2 > tokens.size()) + { + std::cout << "WARNING: '" << line << "' does not contain an equal sign, skipping" << std::endl; + continue; + } + auto pos = tokens[1].find('#'); + if (std::string::npos != pos) + { + tokens[1].assign(tokens[1].substr(0, pos)); + rtrim(tokens[1]); // whitespace between the value and the end-of-line comment + } + // trim whitespace from around the '=' + rtrim(tokens[0]); + ltrim(tokens[1]); + const std::string key(tokens[0]); + const std::string value(tokens[1]); + if (key.empty() || value.empty()) + { + std::cout << "WARNING: missing key or value: '" << line << "'" << std::endl; + continue; + } + if (0 == key.compare(SERVERADDRESS)) + address.assign(value); + else if (0 == key.compare(PORT)) + porttmp.assign(value); + else if (0 == key.compare(MODULES)) + modstmp.assign(value); + else if (0 == key.compare(DSTARGAININ)) + dstar_in = getSigned(key, value); + else if (0 == key.compare(DSTARGAINOUT)) + dstar_out = getSigned(key, value); + else if (0 == key.compare(DMRGAININ)) + dmr_in = getSigned(key, value); + else if (0 == key.compare(DMRGAINOUT)) + dmr_out = getSigned(key, value); + else if (0 == key.compare(USRPTXGAIN)) + usrp_tx = getSigned(key, value); + else if (0 == key.compare(USRPRXGAIN)) + usrp_rx = getSigned(key, value); + else + badParam(key); + } + cfgfile.close(); + + for (auto c : modstmp) + { + if (isalpha(c)) + { + if (islower(c)) + c = toupper(c); + if (std::string::npos == tcmods.find(c)) + tcmods.append(1, c); + } + } + if (tcmods.empty()) + { + std::cerr << "ERROR: no identifable module letters in '" << modstmp << "'. Halt." << std::endl; + return true; + } + + if (! std::regex_match(address, IPv4RegEx) && ! std::regex_match(address, IPv6RegEx)) + { + std::cerr << "ERROR: '" << address << "' is malformed, Halt." << std::endl; + return true; + } + + port = std::strtoul(porttmp.c_str(), nullptr, 10); + if (port < 1025 || port > 49000) + { + std::cerr << "ERROR: Port '" << porttmp << "' must be between >1024 and <49000. Halt." << std::endl; + return true; + } + + std::cout << MODULES << " = " << tcmods << std::endl; + std::cout << SERVERADDRESS << " = " << address << std::endl; + std::cout << PORT << " = " << port << std::endl; + std::cout << DSTARGAININ << " = " << dstar_in << std::endl; + std::cout << DSTARGAINOUT << " = " << dstar_out << std::endl; + std::cout << DMRGAININ << " = " << dmr_in << std::endl; + std::cout << DMRGAINOUT << " = " << dmr_out << std::endl; + std::cout << USRPTXGAIN << " = " << usrp_tx << std::endl; + std::cout << USRPRXGAIN << " = " << usrp_rx << std::endl; + + return false; +} + +int CConfigure::getSigned(const std::string &key, const std::string &value) const +{ + auto i = std::stoi(value.c_str()); + if (i < -24) + { + std::cout << "WARNING: " << key << " = " << value << " is too low. Limit to -24!" << std::endl; + i = -24; + } + else if (i > 24) + { + std::cout << "WARNING: " << key << " = " << value << " is too high. Limit to 24!" << std::endl; + i = 24; + } + return i; +} + +void CConfigure::badParam(const std::string &key) const +{ + std::cout << "WARNING: Unexpected parameter: '" << key << "'" << std::endl; +} + +int CConfigure::GetGain(EGainType gt) const +{ + switch (gt) + { + case EGainType::dmrin: return dmr_in; + case EGainType::dmrout: return dmr_out; + case EGainType::dstarin: return dstar_in; + case EGainType::dstarout: return dstar_out; + case EGainType::usrptx: return usrp_tx; + case EGainType::usrprx: return usrp_rx; + default: return 0; + } +} diff --git a/Configure.h b/Configure.h new file mode 100644 index 0000000..f5313df --- /dev/null +++ b/Configure.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2023 by Thomas A. Early N7TAE + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#pragma once + +#include +#include +#include + +enum class EGainType { dmrin, dmrout, dstarin, dstarout, usrptx, usrprx }; + +#define IS_TRUE(a) ((a)=='t' || (a)=='T' || (a)=='1') + +class CConfigure +{ +public: + bool ReadData(const std::string &path); + int GetGain(EGainType gt) const; + std::string GetTCMods(void) const { return tcmods; } + std::string GetAddress(void) const { return address; } + unsigned GetPort(void) const { return port; } + +private: + // CFGDATA data; + std::string tcmods, address; + uint16_t port; + int dstar_in, dstar_out, dmr_in, dmr_out, usrp_tx, usrp_rx; + + int getSigned(const std::string &key, const std::string &value) const; + void badParam(const std::string &key) const; +}; diff --git a/Controller.cpp b/Controller.cpp new file mode 100644 index 0000000..75cd0b0 --- /dev/null +++ b/Controller.cpp @@ -0,0 +1,530 @@ +// 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 +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// 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. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "TranscoderPacket.h" +#include "Controller.h" +#include "Configure.h" + +extern CConfigure g_Conf; + +int32_t CController::calcNumerator(int32_t db) const +{ + float num = 256.0f * powf(10.0f, (float(db)/20.0f)); + + return int32_t(roundf(num)); +} + +CController::CController() : keep_running(true) {} + +bool CController::Start() +{ + usrp_rx_num = calcNumerator(g_Conf.GetGain(EGainType::usrprx)); + usrp_tx_num = calcNumerator(g_Conf.GetGain(EGainType::usrptx)); + + if (InitVocoders() || tcClient.Open(g_Conf.GetAddress(), g_Conf.GetTCMods(), g_Conf.GetPort())) + { + keep_running = false; + return true; + } + reflectorFuture = std::async(std::launch::async, &CController::ReadReflectorThread, this); + c2Future = std::async(std::launch::async, &CController::ProcessC2Thread, this); + imbeFuture = std::async(std::launch::async, &CController::ProcessIMBEThread, this); + ambeFuture = std::async(std::launch::async, &CController::ProcessAMBEThread, this); + usrpFuture = std::async(std::launch::async, &CController::ProcessUSRPThread, this); + swambe2Future = std::async(std::launch::async, &CController::ProcessSWAMBE2Thread,this); + return false; +} + +void CController::Stop() +{ + keep_running = false; + + if (reflectorFuture.valid()) + reflectorFuture.get(); + if (c2Future.valid()) + c2Future.get(); + + tcClient.Close(); +} + +bool CController::InitVocoders() +{ + // M17 "devices", one for each module + const std::string modules(g_Conf.GetTCMods()); + for ( auto c : modules) + { + c2_16[c] = std::unique_ptr(new CCodec2(false)); + c2_32[c] = std::unique_ptr(new CCodec2(true)); + } + + md380_init(); + ambe_in_num = calcNumerator(g_Conf.GetGain(EGainType::dmrin)); + ambe_out_num = calcNumerator(g_Conf.GetGain(EGainType::dmrout)); + dstar_in_num = calcNumerator(g_Conf.GetGain(EGainType::dstarin)); + dstar_out_num = calcNumerator(g_Conf.GetGain(EGainType::dstarout)); + return false; +} + +// Encapsulate the incoming STCPacket into a CTranscoderPacket and push it into the appropriate queue +// based on packet's codec_in. +void CController::ReadReflectorThread() +{ + while (keep_running) + { + // preemptively check the connection(s)... + tcClient.ReConnect(); + + std::queue> queue; + // wait up to 100 ms to read something on the unix port + tcClient.Receive(queue, 100); + while (! queue.empty()) + { + // create a shared pointer to a new packet + // there is only one CTranscoderPacket created for each new STCPacket received from the reflector + auto packet = std::make_shared(*queue.front()); + queue.pop(); + switch (packet->GetCodecIn()) + { + case ECodecType::dstar: + ambe_queue.push(packet); + break; + case ECodecType::dmr: + swambe2_queue.push(packet); + break; + case ECodecType::p25: + imbe_queue.push(packet); + break; + case ECodecType::usrp: + usrp_queue.push(packet); + break; + case ECodecType::c2_1600: + case ECodecType::c2_3200: + codec2_queue.push(packet); + break; + default: + Dump(packet, "ERROR: Received a reflector packet with unknown Codec:"); + break; + } + } + } +} + +// This is only called when codec_in was dstar or dmr. Obviously, the incoming +// ambe packet was already decoded to audio. +// This might complete the packet. If so, send it back to the reflector +void CController::AudiotoCodec2(std::shared_ptr packet) +{ + // the second half is silent in case this is frame is last. + uint8_t m17data[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0x00, 0x01, 0x43, 0x09, 0xe4, 0x9c, 0x08, 0x21 }; + const auto m = packet->GetModule(); + if (packet->IsSecond()) + { + // get the first half from the store + memcpy(m17data, data_store[packet->GetModule()], 8); + // and then calculate the second half + c2_32[m]->codec2_encode(m17data+8, packet->GetAudioSamples()); + packet->SetM17Data(m17data); + } + else /* the packet is first */ + { + // calculate the first half... + c2_32[m]->codec2_encode(m17data, packet->GetAudioSamples()); + // and then copy the calculated data to the data_store + memcpy(data_store[packet->GetModule()], m17data, 8); + // set the m17_is_set flag if this is the last packet + packet->SetM17Data(m17data); + } + + // we might be all done... + send_mux.lock(); + if (packet->AllCodecsAreSet() && packet->HasNotBeenSent()) SendToReflector(packet); + send_mux.unlock(); +} + +// The original incoming coded was M17, so we will calculate the audio and then +// push the packet onto both the dstar and the dmr queue. +void CController::Codec2toAudio(std::shared_ptr packet) +{ + uint8_t ambe[9]; + uint8_t imbe[11]; + + if (packet->IsSecond()) + { + if (packet->GetCodecIn() == ECodecType::c2_1600) + { + // we've already calculated the audio in the previous packet + // copy the audio from local audio store + packet->SetAudioSamples(audio_store[packet->GetModule()], false); + } + else /* codec_in is ECodecType::c2_3200 */ + { + int16_t tmp[160]; + // decode the second 8 data bytes + // and put it in the packet + c2_32[packet->GetModule()]->codec2_decode(tmp, packet->GetM17Data()+8); + packet->SetAudioSamples(tmp, false); + } + } + else /* it's a "first packet" */ + { + const auto m = packet->GetModule(); + if (packet->GetCodecIn() == ECodecType::c2_1600) + { + // c2_1600 encodes 40 ms of audio, 320 points, so... + // we need some temporary audio storage for decoding c2_1600: + int16_t tmp[320]; + // decode it into the temporary storage + c2_16[m]->codec2_decode(tmp, packet->GetM17Data()); // 8 bytes input produces 320 audio points + // move the first and second half + // the first half is for the packet + packet->SetAudioSamples(tmp, false); + // and the second half goes into the audio store + memcpy(audio_store[packet->GetModule()], &(tmp[160]), 320); + } + else /* codec_in is ECodecType::c2_3200 */ + { + int16_t tmp[160]; + c2_32[m]->codec2_decode(tmp, packet->GetM17Data()); + packet->SetAudioSamples(tmp, false); + } + } + // the only thing left is to encode the two ambe, so push the packet onto both AMBE queues + ambevocoder.encode_2400x1200((int16_t *)packet->GetAudioSamples(), ambe); + packet->SetDStarData(ambe); + md380_encode_fec(ambe, (int16_t *)packet->GetAudioSamples()); + packet->SetDMRData(ambe); + p25vocoder.encode_4400((int16_t*)packet->GetAudioSamples(), imbe); + packet->SetP25Data(imbe); + packet->SetUSRPData((int16_t*)packet->GetAudioSamples()); +} + +void CController::ProcessC2Thread() +{ + while (keep_running) + { + auto packet = codec2_queue.pop(); + + switch (packet->GetCodecIn()) + { + case ECodecType::c2_1600: + case ECodecType::c2_3200: + // this is an original M17 packet, so decode it to audio + // Codec2toAudio will send it on for AMBE processing + Codec2toAudio(packet); + break; + + case ECodecType::dstar: + case ECodecType::dmr: + case ECodecType::p25: + case ECodecType::usrp: + // codec_in was AMBE, so we need to calculate the the M17 data + AudiotoCodec2(packet); + break; + } + } +} + +void CController::AudiotoAMBE(std::shared_ptr packet) +{ + uint8_t ambe[9]; + const int16_t *p = packet->GetAudioSamples(); + + if (dstar_in_num != 256) + { + int16_t tmp[160]; + for(int i = 0; i < 160; ++i) + tmp[i] = int16_t((p[i] * dstar_in_num) >> 8); + ambevocoder.encode_2400x1200(tmp, ambe); + } + else + ambevocoder.encode_2400x1200((int16_t *)p, ambe); + + packet->SetDStarData(ambe); + + // we might be all done... + send_mux.lock(); + if (packet->AllCodecsAreSet() && packet->HasNotBeenSent()) SendToReflector(packet); + send_mux.unlock(); +} + +void CController::AMBEtoAudio(std::shared_ptr packet) +{ + int16_t tmp[160]; + uint8_t ambe[9]; + ambevocoder.decode_2400x1200(tmp, (uint8_t *)packet->GetDStarData()); + if (dstar_out_num != 256) + { + for (int i=0; i<160; i++) + tmp[i] = (tmp[i] * dstar_out_num) >> 8; + } + packet->SetAudioSamples(tmp, false); + codec2_queue.push(packet); + swambe2_queue.push(packet); + imbe_queue.push(packet); + usrp_queue.push(packet); +} + +void CController::ProcessAMBEThread() +{ + while (keep_running) + { + auto packet = ambe_queue.pop(); + + switch (packet->GetCodecIn()) + { + case ECodecType::c2_1600: + case ECodecType::c2_3200: + case ECodecType::dmr: + case ECodecType::p25: + case ECodecType::usrp: + AudiotoAMBE(packet); + break; + + case ECodecType::dstar: + AMBEtoAudio(packet); + break; + } + } +} + +void CController::AudiotoSWAMBE2(std::shared_ptr packet) +{ + uint8_t ambe[9]; + const int16_t *p = packet->GetAudioSamples(); + + if (ambe_in_num != 256) + { + int16_t tmp[160]; + for(int i = 0; i < 160; ++i) + tmp[i] = int16_t((p[i] * ambe_in_num) >> 8); + md380_encode_fec(ambe, tmp); + } + else + md380_encode_fec(ambe, (int16_t *)p); + + packet->SetDMRData(ambe); + + // we might be all done... + send_mux.lock(); + if (packet->AllCodecsAreSet() && packet->HasNotBeenSent()) SendToReflector(packet); + send_mux.unlock(); +} + +void CController::SWAMBE2toAudio(std::shared_ptr packet) +{ + int16_t tmp[160]; + uint8_t ambe[9]; + md380_decode_fec((uint8_t *)packet->GetDMRData(), tmp); + if (ambe_out_num != 256) + { + for (int i=0; i<160; i++) + tmp[i] = (tmp[i] * ambe_out_num) >> 8; + } + packet->SetAudioSamples(tmp, false); + codec2_queue.push(packet); + imbe_queue.push(packet); + ambe_queue.push(packet); + usrp_queue.push(packet); +} + +void CController::ProcessSWAMBE2Thread() +{ + while (keep_running) + { + auto packet = swambe2_queue.pop(); + + switch (packet->GetCodecIn()) + { + case ECodecType::c2_1600: + case ECodecType::c2_3200: + case ECodecType::dstar: + case ECodecType::p25: + case ECodecType::usrp: + AudiotoSWAMBE2(packet); + break; + + case ECodecType::dmr: + SWAMBE2toAudio(packet); + break; + } + } +} + +void CController::AudiotoIMBE(std::shared_ptr packet) +{ + uint8_t imbe[11]; + + p25vocoder.encode_4400((int16_t *)packet->GetAudioSamples(), 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); + ambe_queue.push(packet); + codec2_queue.push(packet); + swambe2_queue.push(packet); + usrp_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: + case ECodecType::usrp: + AudiotoIMBE(packet); + break; + + case ECodecType::p25: + IMBEtoAudio(packet); + break; + } + } +} + +void CController::AudiotoUSRP(std::shared_ptr packet) +{ + const int16_t *p = packet->GetAudioSamples(); + + if (usrp_tx_num != 256) + { + int16_t tmp[160]; + for(int i = 0; i < 160; ++i) + tmp[i] = int16_t((p[i] * usrp_tx_num) >> 8); + packet->SetUSRPData(tmp); + } + else + packet->SetUSRPData(p); + + + // we might be all done... + send_mux.lock(); + if (packet->AllCodecsAreSet() && packet->HasNotBeenSent()) SendToReflector(packet); + send_mux.unlock(); +} + +void CController::USRPtoAudio(std::shared_ptr packet) +{ + const int16_t *p = packet->GetUSRPData(); + + if (usrp_rx_num != 256) + { + int16_t tmp[160]; + for(int i = 0; i < 160; ++i) + tmp[i] = int16_t((p[i] * usrp_rx_num) >> 8); + packet->SetAudioSamples(tmp, false); + } + else + packet->SetAudioSamples(p, false); + + codec2_queue.push(packet); + ambe_queue.push(packet); + swambe2_queue.push(packet); + imbe_queue.push(packet); +} + +void CController::ProcessUSRPThread() +{ + while (keep_running) + { + auto packet = usrp_queue.pop(); + + switch (packet->GetCodecIn()) + { + case ECodecType::c2_1600: + case ECodecType::c2_3200: + case ECodecType::dstar: + case ECodecType::dmr: + case ECodecType::p25: + AudiotoUSRP(packet); + break; + + case ECodecType::usrp: + USRPtoAudio(packet); + break; + } + } +} + +void CController::SendToReflector(std::shared_ptr packet) +{ + // send the packet over the socket + while (tcClient.Send(packet->GetTCPacket())) + { + tcClient.ReConnect(); + } + packet->Sent(); +} + +void CController::Dump(const std::shared_ptr p, const std::string &title) const +{ + std::stringstream line; + line << title << " Mod='" << p->GetModule() << "' SID=" << std::showbase << std::hex << ntohs(p->GetStreamId()) << std::noshowbase; + + ECodecType in = p->GetCodecIn(); + if (p->DStarIsSet()) + line << " DStar"; + if (ECodecType::dstar == in) + line << '*'; + if (p->DMRIsSet()) + line << " DMR"; + if (ECodecType::dmr == in) + line << '*'; + if (p->M17IsSet()) + line << " M17"; + if (ECodecType::c2_1600 == in) + line << "**"; + else if (ECodecType::c2_3200 == in) + line << '*'; + if (p->P25IsSet()) + line << " P25"; + if (ECodecType::p25 == in) + line << "*"; + if (p->USRPIsSet()) + line << " USRP"; + if (ECodecType::usrp == in) + line << "*"; + if (p->IsSecond()) + line << " IsSecond"; + if (p->IsLast()) + line << " IsLast"; + + std::cout << line.str() << std::dec << std::endl; +} diff --git a/Controller.h b/Controller.h new file mode 100644 index 0000000..f41a3e0 --- /dev/null +++ b/Controller.h @@ -0,0 +1,83 @@ +#pragma once + +// 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 +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// 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. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include +#include +#include +#include +#include +#include +#include +#include +#include "PacketQueue.h" +#include "codec2.h" +#include "TCSocket.h" +#include "mbe/mbevocoder_api.h" + +class CController +{ +public: + std::mutex dstar_mux, dmrst_mux; + + CController(); + bool Start(); + void Stop(); + void Dump(const std::shared_ptr packet, const std::string &title) const; + +protected: + std::atomic keep_running; + std::future reflectorFuture, c2Future, imbeFuture, ambeFuture, swambe2Future, usrpFuture; + std::unordered_map audio_store; + std::unordered_map data_store; + CTCClient tcClient; + std::unordered_map> c2_16, c2_32; + + CPacketQueue codec2_queue; + CPacketQueue imbe_queue; + CPacketQueue ambe_queue; + CPacketQueue swambe2_queue; + CPacketQueue usrp_queue; + std::mutex send_mux; + int32_t dstar_in_num, dstar_out_num, ambe_in_num, ambe_out_num, usrp_rx_num, usrp_tx_num; + imbe_vocoder p25vocoder; + MBEVocoder ambevocoder; + + int32_t calcNumerator(int32_t db) const; + + bool InitVocoders(); + // processing threads + void ReadReflectorThread(); + void ProcessC2Thread(); + + void ProcessIMBEThread(); + void ProcessAMBEThread(); + void ProcessSWAMBE2Thread(); + void ProcessUSRPThread(); + void Codec2toAudio(std::shared_ptr packet); + void AudiotoCodec2(std::shared_ptr packet); + void IMBEtoAudio(std::shared_ptr packet); + void AudiotoIMBE(std::shared_ptr packet); + void AMBEtoAudio(std::shared_ptr packet); + void AudiotoAMBE(std::shared_ptr packet); + void USRPtoAudio(std::shared_ptr packet); + void AudiotoUSRP(std::shared_ptr packet); + void SendToReflector(std::shared_ptr packet); + void SWAMBE2toAudio(std::shared_ptr packet); + void AudiotoSWAMBE2(std::shared_ptr packet); +}; diff --git a/IP.cpp b/IP.cpp new file mode 100644 index 0000000..c3519e8 --- /dev/null +++ b/IP.cpp @@ -0,0 +1,308 @@ + +// urfd -- The universal reflector +// Copyright © 2021 Thomas A. Early N7TAE +// +// 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, either version 3 of the License, or +// (at your option) any later version. +// +// 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. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include +#include +#include +#include +#include "IP.h" + +CIp::CIp() : is_set(false) +{ + Clear(); +} + +CIp::CIp(const char *address, int family, int type, uint16_t port) : is_set(true) +{ + Clear(); + if (0 == strncasecmp(address, "none", 4)) + { + is_set = false; + return; + } + struct addrinfo hints, *result; + bzero(&hints, sizeof(struct addrinfo)); + hints.ai_family = family; + hints.ai_socktype = type; + if (0 == getaddrinfo(address, (port ? std::to_string(port).c_str() : nullptr), &hints, &result)) + { + memcpy(&addr, result->ai_addr, result->ai_addrlen); + addr.ss_family = result->ai_family; + freeaddrinfo(result); + } + SetPort(port); +} +CIp::CIp(const int family, const uint16_t port, const char *address) : is_set(true) +{ + Initialize(family, port, address); +} + +void CIp::Initialize(const int family, const uint16_t port, const char *address) +{ + Clear(); + if (0 == strncasecmp(address, "none", 4)) + { + is_set = false; + return; + } + is_set = true; + addr.ss_family = family; + if (AF_INET == family) + { + auto addr4 = (struct sockaddr_in *)&addr; + addr4->sin_port = htons(port); + if (address) + { + if (0 == strncasecmp(address, "loc", 3)) + inet_pton(AF_INET, "127.0.0.1", &(addr4->sin_addr)); + else if (0 == strncasecmp(address, "any", 3)) + inet_pton(AF_INET, "0.0.0.0", &(addr4->sin_addr)); + else + { + if (1 > inet_pton(AF_INET, address, &(addr4->sin_addr))) + { + std::cerr << "Address Initialization Error: '" << address << "' is not a valdid IPV4 address!" << std::endl; + is_set = false; + } + } + } + } + else if (AF_INET6 == family) + { + auto addr6 = (struct sockaddr_in6 *)&addr; + addr6->sin6_port = htons(port); + if (address) + { + if (0 == strncasecmp(address, "loc", 3)) + inet_pton(AF_INET6, "::1", &(addr6->sin6_addr)); + else if (0 == strncasecmp(address, "any", 3)) + inet_pton(AF_INET6, "::", &(addr6->sin6_addr)); + else + { + if (1 > inet_pton(AF_INET6, address, &(addr6->sin6_addr))) + { + std::cerr << "Address Initialization Error: '" << address << "' is not a valid IPV6 address!" << std::endl; + is_set = false; + } + } + } + } + else + { + std::cerr << "Error: Wrong address family type:" << family << " for [" << (address ? address : "NULL") << "]:" << port << std::endl; + is_set = false; + } +} + +bool CIp::operator==(const CIp &rhs) const // compares ports, addresses and families +{ + // if anything is not equal, then we are done + if (addr.ss_family != rhs.addr.ss_family) + return false; + if (AF_INET == addr.ss_family) + { + auto l = (struct sockaddr_in *)&addr; + auto r = (struct sockaddr_in *)&rhs.addr; + if (l->sin_addr.s_addr == r->sin_addr.s_addr) + return l->sin_port == r->sin_port; + else + return false; + } + else if (AF_INET6 == addr.ss_family) + { + auto l = (struct sockaddr_in6 *)&addr; + auto r = (struct sockaddr_in6 *)&rhs.addr; + if (0 == memcmp(&(l->sin6_addr), &(r->sin6_addr), sizeof(struct in6_addr))) + return l->sin6_port == r->sin6_port; + else + return false; + } + return false; +} + +bool CIp::operator!=(const CIp &rhs) const // compares ports, addresses and families +{ + // if anything is not equal, then we are done + if (addr.ss_family != rhs.addr.ss_family) + return true; + if (AF_INET == addr.ss_family) + { + auto l = (struct sockaddr_in *)&addr; + auto r = (struct sockaddr_in *)&rhs.addr; + if (l->sin_addr.s_addr != r->sin_addr.s_addr) + return true; + else + return l->sin_port != r->sin_port; + } + else if (AF_INET6 == addr.ss_family) + { + auto l = (struct sockaddr_in6 *)&addr; + auto r = (struct sockaddr_in6 *)&rhs.addr; + if (0 != memcmp(&(l->sin6_addr), &(r->sin6_addr), sizeof(struct in6_addr))) + return true; + else + return l->sin6_port != r->sin6_port; + } + return true; +} + +bool CIp::AddressIsZero() const +{ + if (AF_INET == addr.ss_family) + { + auto addr4 = (struct sockaddr_in *)&addr; + return (addr4->sin_addr.s_addr == 0U); + } + else + { + auto addr6 = (struct sockaddr_in6 *)&addr; + for (unsigned int i=0; i<16; i++) + { + if (addr6->sin6_addr.s6_addr[i]) + return false; + } + return true; + } +} + +void CIp::ClearAddress() +{ + if (AF_INET == addr.ss_family) + { + auto addr4 = (struct sockaddr_in *)&addr; + addr4->sin_addr.s_addr = 0U; + strcpy(straddr, "0.0.0.0"); + } + else + { + auto addr6 = (struct sockaddr_in6 *)&addr; + memset(&(addr6->sin6_addr.s6_addr), 0, 16); + strcpy(straddr, "::"); + } +} + +const char *CIp::GetAddress() const +{ + if (straddr[0]) + return straddr; + + if (AF_INET == addr.ss_family) + { + auto addr4 = (struct sockaddr_in *)&addr; + inet_ntop(AF_INET, &(addr4->sin_addr), straddr, INET6_ADDRSTRLEN); + } + else if (AF_INET6 == addr.ss_family) + { + auto addr6 = (struct sockaddr_in6 *)&addr; + inet_ntop(AF_INET6, &(addr6->sin6_addr), straddr, INET6_ADDRSTRLEN); + } + else + { + std::cerr << "CIp::GetAddress: unknown socket family=" << addr.ss_family << std::endl; + } + return straddr; +} + +std::ostream &operator<<(std::ostream &stream, const CIp &Ip) +{ + const char *sz = Ip; + if (AF_INET6 == Ip.GetFamily()) + stream << "[" << sz << "]"; + else + stream << sz; + const uint16_t port = Ip.GetPort(); + if (port) + stream << ":" << port; + return stream; +} + +uint32_t CIp::GetAddr() const +{ + if (AF_INET6 == addr.ss_family) + { + auto addr6 = (struct sockaddr_in6 *)&addr; + // hash the results + auto *a = (const uint32_t *)&(addr6->sin6_addr.s6_addr); + return a[0] ^ a[1] ^ a[2] ^ a[3]; + } + else + { + auto addr4 = (struct sockaddr_in *)&addr; + return addr4->sin_addr.s_addr; + } +} + +int CIp::GetFamily() const +{ + return addr.ss_family; +} + +uint16_t CIp::GetPort() const +{ + if (AF_INET == addr.ss_family) + { + auto addr4 = (struct sockaddr_in *)&addr; + return ntohs(addr4->sin_port); + } + else if (AF_INET6 == addr.ss_family) + { + auto addr6 = (struct sockaddr_in6 *)&addr; + return ntohs(addr6->sin6_port); + } + else + return 0; +} + +void CIp::SetPort(const uint16_t newport) +{ + if (AF_INET == addr.ss_family) + { + auto addr4 = (struct sockaddr_in *)&addr; + addr4->sin_port = htons(newport); + } + else if (AF_INET6 == addr.ss_family) + { + auto addr6 = (struct sockaddr_in6 *)&addr; + addr6->sin6_port = htons(newport); + } +} + +struct sockaddr *CIp::GetPointer() +{ + memset(straddr, 0, INET6_ADDRSTRLEN); // things might change + return (struct sockaddr *)&addr; +} + +const struct sockaddr *CIp::GetCPointer() const +{ + return (const struct sockaddr *)&addr; +} + +size_t CIp::GetSize() const +{ + if (AF_INET == addr.ss_family) + return sizeof(struct sockaddr_in); + else + return sizeof(struct sockaddr_in6); +} + +void CIp::Clear() +{ + memset(&addr, 0, sizeof(struct sockaddr_storage)); + memset(straddr, 0, INET6_ADDRSTRLEN); + is_set = false; +} diff --git a/IP.h b/IP.h new file mode 100644 index 0000000..9e989fc --- /dev/null +++ b/IP.h @@ -0,0 +1,74 @@ +#pragma once + + +// urfd -- The universal reflector +// Copyright © 2021 Thomas A. Early N7TAE +// +// 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, either version 3 of the License, or +// (at your option) any later version. +// +// 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. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +class CIp +{ +public: + // constructors + CIp(); + CIp(const char *address, int family = AF_UNSPEC, int type = SOCK_DGRAM, uint16_t port = 0U); + CIp(const int family, const uint16_t port = 0U, const char *address = nullptr); + + // initializer for empty constructor + void Initialize(const int family, const uint16_t port = 0U, const char *address = nullptr); + + // comparison operators + bool operator==(const CIp &rhs) const; + bool operator!=(const CIp &rhs) const; + + // state methods + bool IsSet() const { return is_set; } + bool AddressIsZero() const; + void ClearAddress(); + const char *GetAddress() const; + operator const char *() const { return GetAddress(); } + friend std::ostream &operator<<(std::ostream &stream, const CIp &Ip); + int GetFamily() const; + uint16_t GetPort() const; + size_t GetSize() const; + uint32_t GetAddr() const; + + // modifiers + void SetPort(const uint16_t newport); + + // for i/o + struct sockaddr *GetPointer(); + const struct sockaddr *GetCPointer() const; + + void Clear(); + +private: + struct sockaddr_storage addr; + mutable char straddr[INET6_ADDRSTRLEN]; + bool is_set; +}; + +std::ostream &operator<<(std::ostream &stream, const CIp &Ip); diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..f288702 --- /dev/null +++ b/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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, either version 3 of the License, or + (at your option) any later version. + + 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. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/Main.cpp b/Main.cpp new file mode 100644 index 0000000..af9a432 --- /dev/null +++ b/Main.cpp @@ -0,0 +1,48 @@ +// tcd - a hybrid transcoder using DVSI hardware and Codec2 software +// Copyright © 2021,2023 Thomas A. Early N7TAE +// +// 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, either version 3 of the License, or +// (at your option) any later version. +// +// 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. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include +#include + +#include "Controller.h" +#include "Configure.h" + +// the global objects +CConfigure g_Conf; +CController g_Cont; + +int main(int argc, char *argv[]) +{ + if (2 != argc) + { + std::cerr << "ERROR: Usage: " << argv[0] << " PATHTOINIFILE" << std::endl; + return EXIT_FAILURE; + } + + if (g_Conf.ReadData(argv[1])) + return EXIT_FAILURE; + + if (g_Cont.Start()) + return EXIT_FAILURE; + + std::cout << "Hybrid Transcoder version 0.1.0 successfully started" << std::endl; + + pause(); + + g_Cont.Stop(); + + return EXIT_SUCCESS; +} diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..252f0f2 --- /dev/null +++ b/Makefile @@ -0,0 +1,45 @@ +#Copyright (C) 2021 by Thomas A. Early, N7TAE + +include tcd.mk + +GCC = g++ + +ifeq ($(debug), true) +CFLAGS = -ggdb3 -W -Werror -Icodec2 -MMD -MD -std=c++17 +else +CFLAGS = -W -Werror -Icodec2 -MMD -MD -std=c++17 +endif + +LDFLAGS = -limbe_vocoder -lmd380_vocoder -pthread + +SRCS = $(wildcard *.cpp) $(wildcard codec2/*.cpp) $(wildcard mbe/*.cpp) +OBJS = $(SRCS:.cpp=.o) +DEPS = $(SRCS:.cpp=.d) +EXE = tcd + +$(EXE) : $(OBJS) + $(GCC) $(OBJS) $(LDFLAGS) -o $@ + +%.o : %.cpp + $(GCC) $(CFLAGS) -c $< -o $@ + +clean : + $(RM) $(EXE) $(OBJS) $(DEPS) + +-include $(DEPS) + +# The install and uninstall targets need to be run by root +install : $(EXE) + cp $(EXE) $(BINDIR) + cp $(EXE).service /etc/systemd/system/ + systemctl enable $(EXE) + systemctl daemon-reload + systemctl start $(EXE) + +uninstall : + systemctl stop $(EXE) + systemctl disable $(EXE) + systemctl daemon-reload + rm -f /etc/systemd/system/$(EXE).service + rm -f $(BINDIR)/$(EXE) + systemctl daemon-reload diff --git a/PacketQueue.h b/PacketQueue.h new file mode 100644 index 0000000..d45735e --- /dev/null +++ b/PacketQueue.h @@ -0,0 +1,88 @@ +#pragma once + +// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved. + +// tcd - a hybrid transcoder using DVSI hardware and Codec2 software +// Copyright © 2021 Thomas A. Early N7TAE +// +// 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, either version 3 of the License, or +// (at your option) any later version. +// +// 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. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include +#include +#include +#include + +#include "TranscoderPacket.h" + +// for holding CTranscoder packets while the vocoders are working their magic +// thread safe +class CPacketQueue +{ +public: + CPacketQueue() : keep_running(true) {} + + std::shared_ptr pop() + { + std::shared_ptr rval; // the return value + + std::unique_lock lock(mx); + + while (keep_running && q.empty()) + cv.wait(lock); + + if (keep_running) + { + rval = q.front(); + q.pop(); + } + else + { + while (! q.empty()) + q.pop(); + } + + return rval; + } + + std::size_t push(std::shared_ptr item) + { + std::unique_lock lock(mx); + bool was_empty = q.empty(); + q.push(item); + + if (was_empty) + cv.notify_one(); + + return q.size(); + } + + bool IsEmpty() + { + std::lock_guard lock(mx); + return q.empty(); + } + + void Shutdown() + { + std::lock_guard lock(mx); + keep_running = false; + cv.notify_all(); + } + +private: + std::mutex mx; + std::condition_variable cv; + std::queue> q; + std::atomic keep_running; +}; diff --git a/README.md b/README.md new file mode 100644 index 0000000..7c3a98e --- /dev/null +++ b/README.md @@ -0,0 +1,71 @@ +# tcd + +tcd is a hybrid digital voice transcoder for ham radio used by the new URF reflector. + +## Introduction + +This will build a new kind of hybrid transcoder that uses only software for vocoding digital voice streams used in DStar/DMR/YSF/NXDN *and* David Rowe's open-source Codec2 used in M17 as well as the open-source P25 vocoder, IMBE used in P25. + +This is the only transcoder that will work with the [URF reflector](https://github.com/nostar/urfd). + +This software is loosely based on LX3JL's **ambed**, but is easily different enough to be considered an entirely original work. Here are some major differences with ambed: + +- *TCP Sockets* are used to communicate between the reflector and this transcoder. This guarantees that packets moving between the reflector and transcoder are never lost and the arrive at their destination in order. +- Each configured module has a dedicated encoding and decoding instance running on a different thread. This prevents overloading when processing multiple voice streams and provides the best possible performance for the reflector's clients. + +## Constraints and Requirements + +Only systemd-based operating systems are supported. Debian or Ubuntu is recommended. If you want to install this on a non-systemd based OS, you are on your own. Also, by default, *tcd* is built without gdb support. + +## Download the repository + +In the parent directory of you *urfd* repository: + +```bash +git clone https://github.com/nostar/tcd.git +cd tcd +``` + +To be perfectly clear, the urfd reflector repository clone and this clone **must be in the same directory**. If your transcoder is a remote installation, you still need to `git clone https://github.com/nostar/urfd.git` even though you won't compile anything in the *urfd* repository. Both *tcd* and *urfd* repositories need to be in the same directory as several of the source files in *tcd* are symbolic links to the adjacent *urfd* reflector source code. + +## Compiling and configuring *tcd* + + Copy the three configuration files to the working directory: + +```bash +cp config/* . +``` + +Use your favorite text editor to edit the following files: +- *tcd.mk* defines some compile time options. Once you've set these options, do `make` to compile *tcd*. If you change `BINDIR`, you need to also change the `ExecStart` in your *tcd.service* file. + +- *tcd.ini* defines run-time options. It is especially important that the `Modules` line for the tcd.ini file is exactly the same as the same line in the urfd.ini file! The `ServerAddress` is the url of the server. If the transcoder is local, this is usually `127.0.0.1` or `::1`. If the transcoder is remote, this is the IP address of the server. Suggested values for vocoder gains are provided. +- *tcd.service* is the systemd service file. You will need to modify the `ExecStart` line to successfully start *tcd* by specifying the path to your *tcd* executable and your tcd.ini file. + +## Transcoding options + +The md380_vocoder library for arm32 linux OS is located here: +https://github.com/nostar/md380_vocoder + +The md380_vocoder library for all Intel/AMD 64-bit and ARM 64-bit platforms (including Android) is located here: +https://github.com/nostar/md380_vocoder_dynarmic + +## Installing *tcd* when the transcoder is local + +It is easiest to install and uninstall *tcd* using the ./radmin scripts in your urfd repo. If you want to do this manually: + +```bash +sudo make install +sudo make uninstall +``` + +## Installing *tcd when the transcoder is remote + +Use: +- `make` to compile *tcd*. +- `sudo make install` to install and run *tcd*. +- `sudo systemctl *something*` is used to manage the running *tcd*, where `*something*` might be `start`, `stop` or other verbs. +- `sudo journalctl -u tcd -f` to monitor the logs. +- `sudo make uninstall` to uninstall *tcd*. + +When started, *tcd* will establish a TCP connection for each transcoded reflector module. If the TCP connection is lost, *tcd* will block until the connection is reestablished. A message will be printed every 10 seconds suggesting that the reflector needs to be restarted. diff --git a/TCPacketDef.h b/TCPacketDef.h new file mode 100644 index 0000000..68c251c --- /dev/null +++ b/TCPacketDef.h @@ -0,0 +1,33 @@ +#pragma once + +// Copyright © 2021 Thomas A. Early N7TAE +// +// 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, either version 3 of the License, or +// (at your option) any later version. +// +// 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. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include + +enum class ECodecType : std::uint8_t { none = 0, dstar = 1, dmr = 2, c2_1600 = 3, c2_3200 = 4, p25 = 5, usrp = 6, ping = 0xff }; + +using STCPacket = struct tcpacket_tag { + uint32_t sequence; + char module; + bool is_last; + uint16_t streamid; + ECodecType codec_in; + uint8_t dstar[9]; + uint8_t dmr[9]; + uint8_t m17[16]; + uint8_t p25[11]; + int16_t usrp[160]; +}; diff --git a/TCSocket.cpp b/TCSocket.cpp new file mode 100644 index 0000000..93819d8 --- /dev/null +++ b/TCSocket.cpp @@ -0,0 +1,521 @@ +// urfd -- The universal reflector +// Copyright © 2024 Thomas A. Early N7TAE +// +// 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, either version 3 of the License, or +// (at your option) any later version. +// +// 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. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "TCSocket.h" + +void CTCSocket::Close() +{ + for (auto &item : m_Pfd) + { + if (item.fd >= 0) + { + Close(item.fd); + } + } + m_Pfd.clear(); +} + +void CTCSocket::Close(char mod) +{ + auto pos = m_Modules.find(mod); + if (std::string::npos == pos) + { + std::cerr << "Could not find module '" << mod << "'" << std::endl; + return; + } + if (m_Pfd[pos].fd < 0) + { + std::cerr << "Close(" << mod << ") is already closed" << std::endl; + return; + } + Close(m_Pfd[pos].fd); + m_Pfd[pos].fd = -1; +} + +void CTCSocket::Close(int fd) +{ + if (fd < 0) + { + return; + } + for (auto &p : m_Pfd) + { + if (fd == p.fd) + { + if (shutdown(p.fd, SHUT_RDWR)) + { + perror("shutdown"); + } + else + { + if (close(p.fd)) + { + std::cerr << "Error while closing " << fd << ": "; + perror("close"); + } + else + p.fd = -1; + } + return; + } + } + std::cerr << "Could not find a file descriptor with a value of " << fd << std::endl; +} + +int CTCSocket::GetFD(char module) const +{ + auto pos = m_Modules.find(module); + if (std::string::npos == pos) + return -1; + return m_Pfd[pos].fd; +} + +char CTCSocket::GetMod(int fd) const +{ + for (unsigned i=0; i fds.fd) + return true; + } + return false; +} + +bool CTCSocket::Send(const STCPacket *packet) +{ + auto pos = m_Modules.find(packet->module); + if (pos == std::string::npos) + { + if(packet->codec_in == ECodecType::ping) + { + pos = 0; // There is at least one transcoding module, use it to send the ping + } + else + { + std::cerr << "Can't Send() this packet to unconfigured module '" << packet->module << "'" << std::endl; + return true; + } + } + unsigned count = 0; + auto data = (const unsigned char *)packet; + do { + auto n = send(m_Pfd[pos].fd, data+count, sizeof(STCPacket)-count, 0); + if (n <= 0) + { + if (0 == n) + { + std::cerr << "CTCSocket::Send: socket on module '" << packet->module << "' has been closed!" << std::endl; + } + else + { + perror("CTCSocket::Send"); + } + Close(packet->module); + return true; + } + count += n; + } while (count < sizeof(STCPacket)); + return false; +} + +bool CTCSocket::receive(int fd, STCPacket *packet) +{ + auto n = recv(fd, packet, sizeof(STCPacket), MSG_WAITALL); + if (n < 0) + { + perror("Receive recv"); + Close(fd); + return true; + } + + if (0 == n) + { + return true; + } + + if (n != sizeof(STCPacket)) + std::cout << "receive() only read " << n << " bytes of the transcoder packet from module '" << GetMod(fd) << "'" << std::endl; + return false; +} + +// returns true if there is data to return +bool CTCServer::Receive(char module, STCPacket *packet, int ms) +{ + bool rv = false; + const auto pos = m_Modules.find(module); + if (pos == std::string::npos) + { + std::cerr << "Can't receive on unconfigured module '" << module << "'" << std::endl; + return rv; + } + + auto pfds = &m_Pfd[pos]; + if (pfds->fd < 0) + { + return rv; + } + + auto n = poll(pfds, 1, ms); + if (n < 0) + { + perror("Recieve poll"); + Close(pfds->fd); + return rv; + } + + if (0 == n) + return rv; // timeout + + if (pfds->revents & POLLIN) + { + rv = receive(pfds->fd, packet); + } + + // It's possible that even if we read the data, the socket can have an error after the read... + // So we'll check... + if (pfds->revents & POLLERR || pfds->revents & POLLHUP) + { + if (pfds->revents & POLLERR) + std::cerr << "POLLERR received on module '" << module << "', closing socket" << std::endl; + if (pfds->revents & POLLHUP) + std::cerr << "POLLHUP received on module '" << module << "', closing socket" << std::endl; + Close(pfds->fd); + } + if (pfds->revents & POLLNVAL) + { + std::cerr << "POLLNVAL received on module " << module << "'" << std::endl; + } + + if (rv) + Close(pfds->fd); + + if(packet->codec_in == ECodecType::ping) + return false; + else + return !rv; +} + +bool CTCServer::Open(const std::string &address, const std::string &modules, uint16_t port) +{ + m_Modules.assign(modules); + + m_Ip = CIp(address.c_str(), AF_UNSPEC, SOCK_STREAM, port); + + m_Pfd.resize(m_Modules.size()); + for (auto &pf : m_Pfd) + { + pf.fd = -1; + pf.events = POLLIN; + pf.revents = 0; + } + + return Accept(); +} + +bool CTCServer::Accept() +{ + auto fd = socket(m_Ip.GetFamily(), SOCK_STREAM, 0); + if (fd < 0) + { + perror("Open socket"); + return true; + } + + int yes = 1; + auto rv = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)); + if (rv < 0) + { + close(fd); + perror("Open setsockopt"); + return true; + } + + rv = bind(fd, m_Ip.GetCPointer(), m_Ip.GetSize()); + if (rv < 0) + { + close(fd); + perror("Open bind"); + return true; + } + + rv = listen(fd, 3); + if (rv < 0) + { + perror("Open listen"); + close(fd); + Close(); + return true; + } + + std::string wmod; + for (const char c : m_Modules) + { + if (GetFD(c) < 0) + wmod.append(1, c); + } + + std::cout << "Waiting at " << m_Ip << " for transcoder connection"; + if (wmod.size() > 1) + { + std::cout << "s for modules "; + } + else + { + std::cout << " for module "; + } + std::cout << wmod << "..." << std::endl; + + while (AnyAreClosed()) + { + if (acceptone(fd)) + { + close(fd); + Close(); + return true; + } + } + + close(fd); + + return false; +} + +bool CTCServer::acceptone(int fd) +{ + CIp their_addr; // connector's address information + + socklen_t sin_size = sizeof(struct sockaddr_storage); + + auto newfd = accept(fd, their_addr.GetPointer(), &sin_size); + if (newfd < 0) + { + perror("Accept accept"); + return true; + } + + char mod; + int rv = recv(newfd, &mod, 1, MSG_WAITALL); // block to get the identification byte + if (rv != 1) + { + if (rv < 0) + perror("Accept recv"); + else + std::cerr << "recv got no identification byte!" << std::endl; + close(newfd); + return true; + } + + const auto pos = m_Modules.find(mod); + if (std::string::npos == pos) + { + std::cerr << "New connection for module '" << mod << "', but it's not configured!" << std::endl; + std::cerr << "The transcoded modules need to be configured identically for both urfd and tcd." << std::endl; + close(newfd); + return true; + } + + std::cout << "File descriptor " << newfd << " opened TCP port for module '" << mod << "' on " << their_addr << std::endl; + + m_Pfd[pos].fd = newfd; + + return false; +} + +bool CTCClient::Open(const std::string &address, const std::string &modules, uint16_t port) +{ + m_Address.assign(address); + m_Modules.assign(modules); + m_Port = port; + + m_Pfd.resize(m_Modules.size()); + for (auto &pf : m_Pfd) + { + pf.fd = -1; + pf.events = POLLIN; + } + + std::cout << "Connecting to the TCP server..." << std::endl; + + for (char c : modules) + { + if (Connect(c)) + { + return true; + } + } + return false; +} + +bool CTCClient::Connect(char module) +{ + const auto pos = m_Modules.find(module); + if (pos == std::string::npos) + { + std::cerr << "CTCClient::Connect: could not find module '" << module << "' in configured modules!" << std::endl; + return true; + } + CIp ip(m_Address.c_str(), AF_UNSPEC, SOCK_STREAM, m_Port); + + auto fd = socket(ip.GetFamily(), SOCK_STREAM, 0); + if (fd < 0) + { + std::cerr << "Could not open socket for module '" << module << "'" << std::endl; + perror("TC client socket"); + return true; + } + + int yes = 1; + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int))) + { + std::cerr << "Moudule " << module << " error:"; + perror("setsockopt"); + close(fd); + return true; + } + + unsigned count = 0; + while (connect(fd, ip.GetCPointer(), ip.GetSize())) + { + if (ECONNREFUSED == errno) + { + if (0 == ++count % 100) std::cout << "Connection refused! Restart the reflector." << std::endl; + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } + else + { + std::cerr << "Module " << module << " error: "; + perror("connect"); + close(fd); + return true; + } + } + + int sent = send(fd, &module, 1, 0); // send the identification byte + if (sent < 0) + { + std::cerr << "Error sending ID byte to module '" << module << "':" << std::endl; + perror("send"); + close(fd); + return true; + } + else if (0 == sent) + { + std::cerr << "Could not set ID byte to module '" << module << "'" << std::endl; + close(fd); + return true; + } + + std::cout << "File descriptor " << fd << " on " << ip << " opened for module '" << module << "'" << std::endl; + + m_Pfd[pos].fd = fd; + + return false; +} + +void CTCClient::ReConnect() // and sometimes ping +{ + static std::chrono::system_clock::time_point start = std::chrono::system_clock::now(); + auto now = std::chrono::system_clock::now(); + std::chrono::duration secs = now - start; + + for (char m : m_Modules) + { + if (0 > GetFD(m)) + { + std::cout << "Reconnecting module " << m << "..." << std::endl; + if (Connect(m)) + { + raise(SIGINT); + } + } + } + + if(secs.count() > 5.0) + { + STCPacket ping; + ping.codec_in = ECodecType::ping; + Send(&ping); + start = now; + } +} + +void CTCClient::Receive(std::queue> &queue, int ms) +{ + for (auto &pfd : m_Pfd) + pfd.revents = 0; + + auto rv = poll(m_Pfd.data(), m_Pfd.size(), ms); + + if (rv < 0) + { + perror("Receive poll"); + return; + } + + if (0 == rv) + return; + + for (auto &pfd : m_Pfd) + { + if (pfd.fd < 0) + continue; + + if (pfd.revents & POLLIN) + { + auto p_tcpack = std::make_unique(); + if (receive(pfd.fd, p_tcpack.get())) + { + p_tcpack.reset(); + Close(pfd.fd); + } + else + { + queue.push(std::move(p_tcpack)); + } + } + + if (pfd.revents & POLLERR || pfd.revents & POLLHUP) + { + std::cerr << "IO ERROR on Receive module " << GetMod(pfd.fd) << std::endl; + Close(pfd.fd); + } + if (pfd.revents & POLLNVAL) + { + std::cerr << "POLLNVAL received on fd " << pfd.fd << ", resetting to -1" << std::endl; + pfd.fd = -1; + } + } +} diff --git a/TCSocket.h b/TCSocket.h new file mode 100644 index 0000000..a22dc5b --- /dev/null +++ b/TCSocket.h @@ -0,0 +1,82 @@ +// urfd -- The universal reflector +// Copyright © 2024 Thomas A. Early N7TAE +// +// 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, either version 3 of the License, or +// (at your option) any later version. +// +// 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. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +#include "IP.h" +#include "TCPacketDef.h" + +class CTCSocket +{ +public: + CTCSocket() {} + virtual ~CTCSocket() { Close(); } + + virtual bool Open(const std::string &address, const std::string &modules, uint16_t port) = 0; + void Close(); // close all open sockets + void Close(char module); // close a specific module + void Close(int fd); // close a specific file descriptor + + // All bool functions, except Server Receive, return true if there was an error + bool Send(const STCPacket *packet); + + int GetFD(char module) const; // can return -1! + char GetMod(int fd) const; + +protected: + bool receive(int fd, STCPacket *packet); + std::vector m_Pfd; + std::string m_Modules; +}; + +class CTCServer : public CTCSocket +{ +public: + CTCServer() : CTCSocket() {} + ~CTCServer() {} + bool Open(const std::string &address, const std::string &modules, uint16_t port); + // Returns true if there is data + bool Receive(char module, STCPacket *packet, int ms); + bool AnyAreClosed() const; + bool Accept(); + +private: + CIp m_Ip; + bool acceptone(int fd); +}; + +class CTCClient : public CTCSocket +{ +public: + CTCClient() : CTCSocket(), m_Port(0) {} + ~CTCClient() {} + bool Open(const std::string &address, const std::string &modules, uint16_t port); + void Receive(std::queue> &queue, int ms); + void ReConnect(); + +private: + std::string m_Address; + uint16_t m_Port; + bool Connect(char module); +}; diff --git a/Timer.h b/Timer.h new file mode 100644 index 0000000..9215eb9 --- /dev/null +++ b/Timer.h @@ -0,0 +1,38 @@ +// urfd -- The universal reflector +// Copyright © 2021 Thomas A. Early N7TAE +// +// 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, either version 3 of the License, or +// (at your option) any later version. +// +// 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. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include +#include + +class CTimer +{ +public: + CTimer() { start(); } + ~CTimer() {} + void start() + { + starttime = std::chrono::steady_clock::now(); + } + double time() const + { + std::chrono::duration elapsed(std::chrono::steady_clock::now() - starttime); + return elapsed.count(); + } +private: + std::chrono::steady_clock::time_point starttime; +}; diff --git a/TranscoderPacket.cpp b/TranscoderPacket.cpp new file mode 100644 index 0000000..97414d7 --- /dev/null +++ b/TranscoderPacket.cpp @@ -0,0 +1,200 @@ +// tcd - a hybid transcoder using DVSI hardware and Codec2 software +// Copyright © 2021 Thomas A. Early N7TAE + +// 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, either version 3 of the License, or +// (at your option) any later version. + +// 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. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include +#include + +#include "TranscoderPacket.h" + +CTranscoderPacket::CTranscoderPacket(const STCPacket &tcp) : dstar_set(false), dmr_set(false), p25_set(false), m17_set(false), usrp_set(false), not_sent(true) +{ + tcpacket.module = tcp.module; + tcpacket.is_last = tcp.is_last; + tcpacket.streamid = tcp.streamid; + tcpacket.codec_in = tcp.codec_in; + tcpacket.sequence = tcp.sequence; + switch (tcp.codec_in) + { + case ECodecType::dstar: + SetDStarData(tcp.dstar); + break; + case ECodecType::dmr: + SetDMRData(tcp.dmr); + break; + case ECodecType::p25: + SetP25Data(tcp.p25); + break; + case ECodecType::usrp: + SetUSRPData(tcp.usrp); + break; + case ECodecType::c2_1600: + case ECodecType::c2_3200: + SetM17Data(tcp.m17); + break; + default: + std::cerr << "Trying to allocate CTranscoderPacket with an unknown codec type!" << std::endl; + break; + } +} + +char CTranscoderPacket::GetModule() const +{ + return tcpacket.module; +} + +const uint8_t *CTranscoderPacket::GetDStarData() const +{ + return tcpacket.dstar; +} + +const uint8_t *CTranscoderPacket::GetDMRData() const +{ + return tcpacket.dmr; +} + +const uint8_t *CTranscoderPacket::GetP25Data() const +{ + return tcpacket.p25; +} + +const int16_t *CTranscoderPacket::GetUSRPData() const +{ + return tcpacket.usrp; +} + +const uint8_t *CTranscoderPacket::GetM17Data() const +{ + return tcpacket.m17; +} + +const STCPacket *CTranscoderPacket::GetTCPacket() const +{ + return &tcpacket; +} + +void CTranscoderPacket::SetM17Data(const uint8_t *data) +{ + memcpy(tcpacket.m17, data, 16); + m17_set = true; +} + +void CTranscoderPacket::SetDStarData(const uint8_t *dstar) +{ + memcpy(tcpacket.dstar, dstar, 9); + dstar_set = true; +} + +void CTranscoderPacket::SetDMRData(const uint8_t *dmr) +{ + memcpy(tcpacket.dmr, dmr, 9); + dmr_set = true; +} + +void CTranscoderPacket::SetP25Data(const uint8_t *p25) +{ + memcpy(tcpacket.p25, p25, 11); + p25_set = true; +} + +void CTranscoderPacket::SetUSRPData(const int16_t *usrp) +{ + for(int i = 0; i < 160; ++i){ + tcpacket.usrp[i] = usrp[i]; + } + usrp_set = true; +} + +void CTranscoderPacket::SetAudioSamples(const int16_t *sample, bool swap) +{ + for (unsigned int i=0; i<160; i++) + audio[i] = swap ? ntohs(sample[i]) : sample[i]; +} + +const int16_t *CTranscoderPacket::GetAudioSamples() const +{ + return audio; +} + +ECodecType CTranscoderPacket::GetCodecIn() const +{ + return tcpacket.codec_in; +} + +uint16_t CTranscoderPacket::GetStreamId() const +{ + return tcpacket.streamid; +} + +uint32_t CTranscoderPacket::GetSequence() const +{ + return tcpacket.sequence; +} + +bool CTranscoderPacket::IsLast() const +{ + return tcpacket.is_last; +} + +bool CTranscoderPacket::IsSecond() const +{ + return (1 == tcpacket.sequence % 2); +} + +bool CTranscoderPacket::DStarIsSet() const +{ + return dstar_set; +} + +bool CTranscoderPacket::DMRIsSet() const +{ + return dmr_set; +} + +bool CTranscoderPacket::P25IsSet() const +{ + return p25_set; +} + +bool CTranscoderPacket::USRPIsSet() const +{ + return usrp_set; +} + +bool CTranscoderPacket::M17IsSet() const +{ + return m17_set; +} + +bool CTranscoderPacket::AllCodecsAreSet() +{ +#ifdef SW_MODES_ONLY + dstar_set = true; +#ifndef USE_SW_AMBE2 + dmr_set = true; +#endif +#endif + return (dstar_set && dmr_set && m17_set && p25_set && usrp_set); +} + +void CTranscoderPacket::Sent() +{ + not_sent = false; +} + +bool CTranscoderPacket::HasNotBeenSent() const +{ + return not_sent; +} diff --git a/TranscoderPacket.h b/TranscoderPacket.h new file mode 100644 index 0000000..4a49b40 --- /dev/null +++ b/TranscoderPacket.h @@ -0,0 +1,73 @@ +#pragma once + + +// tcd - a hybid transcoder using DVSI hardware and Codec2 software +// Copyright © 2021 Thomas A. Early N7TAE + +// 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, either version 3 of the License, or +// (at your option) any later version. + +// 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. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include +#include +#include + +#include "TCPacketDef.h" + +class CTranscoderPacket +{ +public: + // constructor + CTranscoderPacket(const STCPacket &tcp); + + // this packet's refector module; + char GetModule() const; + + // codec + const uint8_t *GetDStarData() const; + const uint8_t *GetDMRData() const; + const uint8_t *GetP25Data() const; + const uint8_t *GetM17Data() const; + const int16_t *GetUSRPData() 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 SetUSRPData(const int16_t *usrp); + void SetAudioSamples(const int16_t *samples, bool swap); + + // audio + const int16_t *GetAudioSamples() const; + + // state of packet + ECodecType GetCodecIn() const; + uint16_t GetStreamId() const; + uint32_t GetSequence() const; + bool IsLast() const; + bool IsSecond() const; + bool DStarIsSet() const; + bool DMRIsSet() const; + bool P25IsSet() const; + bool M17IsSet() const; + bool USRPIsSet() const; + bool AllCodecsAreSet(); + void Sent(); + bool HasNotBeenSent() const; + + // the all important packet + const STCPacket *GetTCPacket() const; + +private: + STCPacket tcpacket; + int16_t audio[160]; + std::atomic_bool dstar_set, dmr_set, p25_set, m17_set, usrp_set, not_sent; +}; diff --git a/codec2/codebooks.cpp b/codec2/codebooks.cpp new file mode 100644 index 0000000..bf319ce --- /dev/null +++ b/codec2/codebooks.cpp @@ -0,0 +1,964 @@ +/* + * This intermediary file and the files that used to create it are under + * The LGPL. See the file COPYING. + */ + +#include "defines.h" + +/* codebook/lsp1.txt */ +static float codes00[] = +{ + 225, + 250, + 275, + 300, + 325, + 350, + 375, + 400, + 425, + 450, + 475, + 500, + 525, + 550, + 575, + 600 +}; +/* codebook/lsp2.txt */ +static float codes01[] = +{ + 325, + 350, + 375, + 400, + 425, + 450, + 475, + 500, + 525, + 550, + 575, + 600, + 625, + 650, + 675, + 700 +}; +/* codebook/lsp3.txt */ +static float codes02[] = +{ + 500, + 550, + 600, + 650, + 700, + 750, + 800, + 850, + 900, + 950, + 1000, + 1050, + 1100, + 1150, + 1200, + 1250 +}; +/* codebook/lsp4.txt */ +static float codes03[] = +{ + 700, + 800, + 900, + 1000, + 1100, + 1200, + 1300, + 1400, + 1500, + 1600, + 1700, + 1800, + 1900, + 2000, + 2100, + 2200 +}; +/* codebook/lsp5.txt */ +static float codes04[] = +{ + 950, + 1050, + 1150, + 1250, + 1350, + 1450, + 1550, + 1650, + 1750, + 1850, + 1950, + 2050, + 2150, + 2250, + 2350, + 2450 +}; +/* codebook/lsp6.txt */ +static float codes05[] = +{ + 1100, + 1200, + 1300, + 1400, + 1500, + 1600, + 1700, + 1800, + 1900, + 2000, + 2100, + 2200, + 2300, + 2400, + 2500, + 2600 +}; +/* codebook/lsp7.txt */ +static float codes06[] = +{ + 1500, + 1600, + 1700, + 1800, + 1900, + 2000, + 2100, + 2200, + 2300, + 2400, + 2500, + 2600, + 2700, + 2800, + 2900, + 3000 +}; +/* codebook/lsp8.txt */ +static float codes07[] = +{ + 2300, + 2400, + 2500, + 2600, + 2700, + 2800, + 2900, + 3000 +}; +/* codebook/lsp9.txt */ +static float codes08[] = +{ + 2500, + 2600, + 2700, + 2800, + 2900, + 3000, + 3100, + 3200 +}; +/* codebook/lsp10.txt */ +static float codes09[] = +{ + 2900, + 3100, + 3300, + 3500 +}; + +const struct lsp_codebook lsp_cb[] = +{ + /* codebook/lsp1.txt */ + { + 1, + 4, + 16, + codes00 + }, + /* codebook/lsp2.txt */ + { + 1, + 4, + 16, + codes01 + }, + /* codebook/lsp3.txt */ + { + 1, + 4, + 16, + codes02 + }, + /* codebook/lsp4.txt */ + { + 1, + 4, + 16, + codes03 + }, + /* codebook/lsp5.txt */ + { + 1, + 4, + 16, + codes04 + }, + /* codebook/lsp6.txt */ + { + 1, + 4, + 16, + codes05 + }, + /* codebook/lsp7.txt */ + { + 1, + 4, + 16, + codes06 + }, + /* codebook/lsp8.txt */ + { + 1, + 3, + 8, + codes07 + }, + /* codebook/lsp9.txt */ + { + 1, + 3, + 8, + codes08 + }, + /* codebook/lsp10.txt */ + { + 1, + 2, + 4, + codes09 + }, + { 0, 0, 0, 0 } +}; + +/* codebook/dlsp1.txt */ +static float codes10[] = +{ + 25, + 50, + 75, + 100, + 125, + 150, + 175, + 200, + 225, + 250, + 275, + 300, + 325, + 350, + 375, + 400, + 425, + 450, + 475, + 500, + 525, + 550, + 575, + 600, + 625, + 650, + 675, + 700, + 725, + 750, + 775, + 800 +}; +/* codebook/dlsp2.txt */ +static float codes11[] = +{ + 25, + 50, + 75, + 100, + 125, + 150, + 175, + 200, + 225, + 250, + 275, + 300, + 325, + 350, + 375, + 400, + 425, + 450, + 475, + 500, + 525, + 550, + 575, + 600, + 625, + 650, + 675, + 700, + 725, + 750, + 775, + 800 +}; +/* codebook/dlsp3.txt */ +static float codes12[] = +{ + 25, + 50, + 75, + 100, + 125, + 150, + 175, + 200, + 225, + 250, + 275, + 300, + 325, + 350, + 375, + 400, + 425, + 450, + 475, + 500, + 525, + 550, + 575, + 600, + 625, + 650, + 675, + 700, + 725, + 750, + 775, + 800 +}; +/* codebook/dlsp4.txt */ +static float codes13[] = +{ + 25, + 50, + 75, + 100, + 125, + 150, + 175, + 200, + 250, + 300, + 350, + 400, + 450, + 500, + 550, + 600, + 650, + 700, + 750, + 800, + 850, + 900, + 950, + 1000, + 1050, + 1100, + 1150, + 1200, + 1250, + 1300, + 1350, + 1400 +}; +/* codebook/dlsp5.txt */ +static float codes14[] = +{ + 25, + 50, + 75, + 100, + 125, + 150, + 175, + 200, + 250, + 300, + 350, + 400, + 450, + 500, + 550, + 600, + 650, + 700, + 750, + 800, + 850, + 900, + 950, + 1000, + 1050, + 1100, + 1150, + 1200, + 1250, + 1300, + 1350, + 1400 +}; +/* codebook/dlsp6.txt */ +static float codes15[] = +{ + 25, + 50, + 75, + 100, + 125, + 150, + 175, + 200, + 250, + 300, + 350, + 400, + 450, + 500, + 550, + 600, + 650, + 700, + 750, + 800, + 850, + 900, + 950, + 1000, + 1050, + 1100, + 1150, + 1200, + 1250, + 1300, + 1350, + 1400 +}; +/* codebook/dlsp7.txt */ +static float codes16[] = +{ + 25, + 50, + 75, + 100, + 125, + 150, + 175, + 200, + 225, + 250, + 275, + 300, + 325, + 350, + 375, + 400, + 425, + 450, + 475, + 500, + 525, + 550, + 575, + 600, + 625, + 650, + 675, + 700, + 725, + 750, + 775, + 800 +}; +/* codebook/dlsp8.txt */ +static float codes17[] = +{ + 25, + 50, + 75, + 100, + 125, + 150, + 175, + 200, + 225, + 250, + 275, + 300, + 325, + 350, + 375, + 400, + 425, + 450, + 475, + 500, + 525, + 550, + 575, + 600, + 625, + 650, + 675, + 700, + 725, + 750, + 775, + 800 +}; +/* codebook/dlsp9.txt */ +static float codes18[] = +{ + 25, + 50, + 75, + 100, + 125, + 150, + 175, + 200, + 225, + 250, + 275, + 300, + 325, + 350, + 375, + 400, + 425, + 450, + 475, + 500, + 525, + 550, + 575, + 600, + 625, + 650, + 675, + 700, + 725, + 750, + 775, + 800 +}; +/* codebook/dlsp10.txt */ +static float codes19[] = +{ + 25, + 50, + 75, + 100, + 125, + 150, + 175, + 200, + 225, + 250, + 275, + 300, + 325, + 350, + 375, + 400, + 425, + 450, + 475, + 500, + 525, + 550, + 575, + 600, + 625, + 650, + 675, + 700, + 725, + 750, + 775, + 800 +}; + +const struct lsp_codebook lsp_cbd[] = +{ + /* codebook/dlsp1.txt */ + { + 1, + 5, + 32, + codes10 + }, + /* codebook/dlsp2.txt */ + { + 1, + 5, + 32, + codes11 + }, + /* codebook/dlsp3.txt */ + { + 1, + 5, + 32, + codes12 + }, + /* codebook/dlsp4.txt */ + { + 1, + 5, + 32, + codes13 + }, + /* codebook/dlsp5.txt */ + { + 1, + 5, + 32, + codes14 + }, + /* codebook/dlsp6.txt */ + { + 1, + 5, + 32, + codes15 + }, + /* codebook/dlsp7.txt */ + { + 1, + 5, + 32, + codes16 + }, + /* codebook/dlsp8.txt */ + { + 1, + 5, + 32, + codes17 + }, + /* codebook/dlsp9.txt */ + { + 1, + 5, + 32, + codes18 + }, + /* codebook/dlsp10.txt */ + { + 1, + 5, + 32, + codes19 + }, + { 0, 0, 0, 0 } +}; + + +/* codebook/gecb.txt */ +static float codes30[] = +{ + 2.71, 12.0184, + 0.04675, -2.73881, + 0.120993, 8.38895, + -1.58028, -0.892307, + 1.19307, -1.91561, + 0.187101, -3.27679, + 0.332251, -7.66455, + -1.47944, 31.2461, + 1.52761, 27.7095, + -0.524379, 5.25012, + 0.55333, 7.4388, + -0.843451, -1.95299, + 2.26389, 8.61029, + 0.143143, 2.36549, + 0.616506, 1.28427, + -1.71133, 22.0967, + 1.00813, 17.3965, + -0.106718, 1.41891, + -0.136246, 14.2736, + -1.70909, -20.5319, + 1.65787, -3.39107, + 0.138049, -4.95785, + 0.536729, -1.94375, + 0.196307, 36.8519, + 1.27248, 22.5565, + -0.670219, -1.90604, + 0.382092, 6.40113, + -0.756911, -4.90102, + 1.82931, 4.6138, + 0.318794, 0.73683, + 0.612815, -2.07505, + -0.410151, 24.7871, + 1.77602, 13.1909, + 0.106457, -0.104492, + 0.192206, 10.1838, + -1.82442, -7.71565, + 0.931346, 4.34835, + 0.308813, -4.086, + 0.397143, -11.8089, + -0.048715, 41.2273, + 0.877342, 35.8503, + -0.759794, 0.476634, + 0.978593, 7.67467, + -1.19506, 3.03883, + 2.63989, -3.41106, + 0.191127, 3.60351, + 0.402932, 1.0843, + -2.15202, 18.1076, + 1.5468, 8.32271, + -0.143089, -4.07592, + -0.150142, 5.86674, + -1.40844, -3.2507, + 1.56615, -10.4132, + 0.178171, -10.2267, + 0.362164, -0.028556, + -0.070125, 24.3907, + 0.594752, 17.4828, + -0.28698, -6.90407, + 0.464818, 10.2055, + -1.00684, -14.3572, + 2.32957, -3.69161, + 0.335745, 2.40714, + 1.01966, -3.15565, + -1.25945, 7.9919, + 2.38369, 19.6806, + -0.094947, -2.41374, + 0.20933, 6.66477, + -2.22103, 1.37986, + 1.29239, 2.04633, + 0.243626, -0.890741, + 0.428773, -7.19366, + -1.11374, 41.3414, + 2.6098, 31.1405, + -0.446468, 2.53419, + 0.490104, 4.62757, + -1.11723, -3.24174, + 1.79156, 8.41493, + 0.156012, 0.183336, + 0.532447, 3.15455, + -0.764484, 18.514, + 0.952395, 11.7713, + -0.332567, 0.346987, + 0.202165, 14.7168, + -2.12924, -15.559, + 1.35358, -1.92679, + -0.010963, -16.3364, + 0.399053, -2.79057, + 0.750657, 31.1483, + 0.655743, 24.4819, + -0.45321, -0.735879, + 0.2869, 6.5467, + -0.715673, -12.3578, + 1.54849, 3.87217, + 0.271874, 0.802339, + 0.502073, -4.85485, + -0.497037, 17.7619, + 1.19116, 13.9544, + 0.01563, 1.33157, + 0.341867, 8.93537, + -2.31601, -5.39506, + 0.75861, 1.9645, + 0.24132, -3.23769, + 0.267151, -11.2344, + -0.273126, 32.6248, + 1.75352, 40.432, + -0.784011, 3.04576, + 0.705987, 5.66118, + -1.3864, 1.35356, + 2.37646, 1.67485, + 0.242973, 4.73218, + 0.491227, 0.354061, + -1.60676, 8.65895, + 1.16711, 5.9871, + -0.137601, -12.0417, + -0.251375, 10.3972, + -1.43151, -8.90411, + 0.98828, -13.209, + 0.261484, -6.35497, + 0.395932, -0.702529, + 0.283704, 26.8996, + 0.420959, 15.4418, + -0.355804, -13.7278, + 0.527372, 12.3985, + -1.16956, -15.9985, + 1.90669, -5.81605, + 0.354492, 3.85157, + 0.82576, -4.16264, + -0.49019, 13.0572, + 2.25577, 13.5264, + -0.004956, -3.23713, + 0.026709, 7.86645, + -1.81037, -0.451183, + 1.08383, -0.18362, + 0.135836, -2.26658, + 0.375812, -5.51225, + -1.96644, 38.6829, + 1.97799, 24.5655, + -0.704656, 6.35881, + 0.480786, 7.05175, + -0.976417, -2.42273, + 2.50215, 6.75935, + 0.083588, 3.2588, + 0.543629, 0.910013, + -1.23196, 23.0915, + 0.785492, 14.807, + -0.213554, 1.688, + 0.004748, 18.1718, + -1.54719, -16.1168, + 1.50104, -3.28114, + 0.080133, -4.63472, + 0.476592, -2.18093, + 0.44247, 40.304, + 1.07277, 27.592, + -0.594738, -4.16681, + 0.42248, 7.61609, + -0.927521, -7.27441, + 1.99162, 1.29636, + 0.291307, 2.39878, + 0.721081, -1.95062, + -0.804256, 24.9295, + 1.64839, 19.1197, + 0.060852, -0.590639, + 0.266085, 9.10325, + -1.9574, -2.88461, + 1.11693, 2.6724, + 0.35458, -2.74854, + 0.330733, -14.1561, + -0.527851, 39.5756, + 0.991152, 43.195, + -0.589619, 1.26919, + 0.787401, 8.73071, + -1.0138, 1.02507, + 2.8254, 1.89538, + 0.24089, 2.74557, + 0.427195, 2.54446, + -1.95311, 12.244, + 1.44862, 12.0607, + -0.210492, -3.37906, + -0.056713, 10.204, + -1.65237, -5.10274, + 1.29475, -12.2708, + 0.111608, -8.67592, + 0.326634, -1.16763, + 0.021781, 31.1258, + 0.455335, 21.4684, + -0.37544, -3.37121, + 0.39362, 11.302, + -0.851456, -19.4149, + 2.10703, -2.22886, + 0.373233, 1.92406, + 0.884438, -1.72058, + -0.975127, 9.84013, + 2.0033, 17.3954, + -0.036915, -1.11137, + 0.148456, 5.39997, + -1.91441, 4.77382, + 1.44791, 0.537122, + 0.194979, -1.03818, + 0.495771, -9.95502, + -1.05899, 32.9471, + 2.01122, 32.4544, + -0.30965, 4.71911, + 0.436082, 4.63552, + -1.23711, -1.25428, + 2.02274, 9.42834, + 0.190342, 1.46077, + 0.479017, 2.48479, + -1.07848, 16.2217, + 1.20764, 9.65421, + -0.258087, -1.67236, + 0.071852, 13.416, + -1.87723, -16.072, + 1.28957, -4.87118, + 0.067713, -13.4427, + 0.435551, -4.1655, + 0.46614, 30.5895, + 0.904895, 21.598, + -0.518369, -2.53205, + 0.337363, 5.63726, + -0.554975, -17.4005, + 1.69188, 1.14574, + 0.227934, 0.889297, + 0.587303, -5.72973, + -0.262133, 18.6666, + 1.39505, 17.0029, + -0.01909, 4.30838, + 0.304235, 12.6699, + -2.07406, -6.46084, + 0.920546, 1.21296, + 0.284927, -1.78547, + 0.209724, -16.024, + -0.636067, 31.5768, + 1.34989, 34.6775, + -0.971625, 5.30086, + 0.590249, 4.44971, + -1.56787, 3.60239, + 2.1455, 4.51666, + 0.296022, 4.12017, + 0.445299, 0.868772, + -1.44193, 14.1284, + 1.35575, 6.0074, + -0.012814, -7.49657, + -0.43, 8.50012, + -1.20469, -7.11326, + 1.10102, -6.83682, + 0.196463, -6.234, + 0.436747, -1.12979, + 0.141052, 22.8549, + 0.290821, 18.8114, + -0.529536, -7.73251, + 0.63428, 10.7898, + -1.33472, -20.3258, + 1.81564, -1.90332, + 0.394778, 3.79758, + 0.732682, -8.18382, + -0.741244, 11.7683 +}; + +const struct lsp_codebook ge_cb[] = +{ + /* codebook/gecb.txt */ + { + 2, + 8, + 256, + codes30 + }, + { 0, 0, 0, 0 } +}; diff --git a/codec2/codec2.cpp b/codec2/codec2.cpp new file mode 100644 index 0000000..4774b0c --- /dev/null +++ b/codec2/codec2.cpp @@ -0,0 +1,1732 @@ +/*---------------------------------------------------------------------------*\ + + FILE........: codec2.c + AUTHOR......: David Rowe + DATE CREATED: 21/8/2010 + + Codec2 fully quantised encoder and decoder functions. If you want use + codec2, the codec2_xxx functions are for you. + +\*---------------------------------------------------------------------------*/ + +/* + Copyright (C) 2010 David Rowe + + All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 2.1, as + published by the free Software Foundation. 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. + + You should have received a copy of the GNU Lesser General Public License + along with this program; if not, see . +*/ + +#include +#include +#include +#include +#include +#include + +#include "nlp.h" +#include "lpc.h" +#include "quantise.h" +#include "codec2.h" +#include "codec2_internal.h" + +#define HPF_BETA 0.125 +#define BPF_N 101 + +CKissFFT kiss; + +/*---------------------------------------------------------------------------* \ + + FUNCTION HEADERS + +\*---------------------------------------------------------------------------*/ + + + + +/*---------------------------------------------------------------------------*\ + + FUNCTIONS + +\*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*\ + + FUNCTION....: codec2_create + AUTHOR......: David Rowe + DATE CREATED: 21/8/2010 + + Create and initialise an instance of the codec. Returns a pointer + to the codec states or NULL on failure. One set of states is + sufficient for a full duuplex codec (i.e. an encoder and decoder). + You don't need separate states for encoders and decoders. See + c2enc.c and c2dec.c for examples. + +\*---------------------------------------------------------------------------*/ + +CCodec2::CCodec2(bool is_3200) +{ + c2.mode = is_3200 ? 3200 : 1600; + + /* store constants in a few places for convenience */ + + c2.c2const = c2const_create(8000, N_S); + c2.Fs = c2.c2const.Fs; + int n_samp = c2.n_samp = c2.c2const.n_samp; + int m_pitch = c2.m_pitch = c2.c2const.m_pitch; + + c2.Pn.resize(2*n_samp); + c2.Sn_.resize(2*n_samp); + c2.w.resize(m_pitch); + c2.Sn.resize(m_pitch); + + for(int i=0; i Aw[FFT_ENC]; + + /* only need to zero these out due to (unused) snr calculation */ + + for(i=0; i<2; i++) + for(j=1; j<=MAX_AMP; j++) + model[i].A[j] = 0.0; + + /* unpack bits from channel ------------------------------------*/ + + /* this will partially fill the model params for the 2 x 10ms + frames */ + + model[0].voiced = qt.unpack(bits, &nbit, 1); + model[1].voiced = qt.unpack(bits, &nbit, 1); + + Wo_index = qt.unpack(bits, &nbit, WO_BITS); + model[1].Wo = qt.decode_Wo(&c2.c2const, Wo_index, WO_BITS); + model[1].L = PI/model[1].Wo; + + e_index = qt.unpack(bits, &nbit, E_BITS); + e[1] = qt.decode_energy(e_index, E_BITS); + + for(i=0; i Aw[FFT_ENC]; + + /* only need to zero these out due to (unused) snr calculation */ + + for(i=0; i<4; i++) + for(j=1; j<=MAX_AMP; j++) + model[i].A[j] = 0.0; + + /* unpack bits from channel ------------------------------------*/ + + /* this will partially fill the model params for the 4 x 10ms + frames */ + + model[0].voiced = qt.unpack(bits, &nbit, 1); + + model[1].voiced = qt.unpack(bits, &nbit, 1); + Wo_index = qt.unpack(bits, &nbit, WO_BITS); + model[1].Wo = qt.decode_Wo(&c2.c2const, Wo_index, WO_BITS); + model[1].L = PI/model[1].Wo; + + e_index = qt.unpack(bits, &nbit, E_BITS); + e[1] = qt.decode_energy(e_index, E_BITS); + + model[2].voiced = qt.unpack(bits, &nbit, 1); + + model[3].voiced = qt.unpack(bits, &nbit, 1); + Wo_index = qt.unpack(bits, &nbit, WO_BITS); + model[3].Wo = qt.decode_Wo(&c2.c2const, Wo_index, WO_BITS); + model[3].L = PI/model[3].Wo; + + e_index = qt.unpack(bits, &nbit, E_BITS); + e[3] = qt.decode_energy(e_index, E_BITS); + + for(i=0; i Aw[], float gain) +{ + int i; + + /* LPC based phase synthesis */ + std::complex H[MAX_AMP+1]; + sample_phase(model, H, Aw); + phase_synth_zero_order(c2.n_samp, model, &c2.ex_phase, H); + + postfilter(model, &c2.bg_est); + synthesise(c2.n_samp, &(c2.fftr_inv_cfg), c2.Sn_.data(), model, c2.Pn.data(), 1); + + for(i=0; i 32767.0) + speech[i] = 32767; + else if (c2.Sn_[i] < -32767.0) + speech[i] = -32767; + else + speech[i] = c2.Sn_[i]; + } + +} + + +/*---------------------------------------------------------------------------* \ + + FUNCTION....: analyse_one_frame() + AUTHOR......: David Rowe + DATE CREATED: 23/8/2010 + + Extract sinusoidal model parameters from 80 speech samples (10ms of + speech). + +\*---------------------------------------------------------------------------*/ + +void CCodec2::analyse_one_frame(MODEL *model, const short *speech) +{ + std::complex Sw[FFT_ENC]; + float pitch; + int i; + int n_samp = c2.n_samp; + int m_pitch = c2.m_pitch; + + /* Read input speech */ + + for(i=0; iWo = TWO_PI/pitch; + model->L = PI/model->Wo; + + /* estimate model parameters */ + two_stage_pitch_refinement(&c2.c2const, model, Sw); + + /* estimate phases when doing ML experiments */ + estimate_amplitudes(model, Sw, 0); + est_voicing_mbe(&c2.c2const, model, Sw, c2.W); +} + + +/*---------------------------------------------------------------------------* \ + + FUNCTION....: ear_protection() + AUTHOR......: David Rowe + DATE CREATED: Nov 7 2012 + + Limits output level to protect ears when there are bit errors or the input + is overdriven. This doesn't correct or mask bit errors, just reduces the + worst of their damage. + +\*---------------------------------------------------------------------------*/ + +void CCodec2::ear_protection(float in_out[], int n) +{ + float max_sample, over, gain; + int i; + + /* find maximum sample in frame */ + + max_sample = 0.0; + for(i=0; i max_sample) + max_sample = in_out[i]; + + /* determine how far above set point */ + + over = max_sample/30000.0; + + /* If we are x dB over set point we reduce level by 2x dB, this + attenuates major excursions in amplitude (likely to be caused + by bit errors) more than smaller ones */ + + if (over > 1.0) + { + gain = 1.0/(over*over); + for(i=0; i H[], + std::complex A[] /* LPC analysis filter in freq domain */ +) +{ + int m, b; + float r; + + r = TWO_PI/(FFT_ENC); + + /* Sample phase at harmonics */ + + for(m=1; m<=model->L; m++) + { + b = (int)(m*model->Wo/r + 0.5); + H[m] = std::conj(A[b]); + } +} + + +/*---------------------------------------------------------------------------*\ + + phase_synth_zero_order() + + Synthesises phases based on SNR and a rule based approach. No phase + parameters are required apart from the SNR (which can be reduced to a + 1 bit V/UV decision per frame). + + The phase of each harmonic is modelled as the phase of a synthesis + filter excited by an impulse. In many Codec 2 modes the synthesis + filter is a LPC filter. Unlike the first order model the position + of the impulse is not transmitted, so we create an excitation pulse + train using a rule based approach. + + Consider a pulse train with a pulse starting time n=0, with pulses + repeated at a rate of Wo, the fundamental frequency. A pulse train + in the time domain is equivalent to harmonics in the frequency + domain. We can make an excitation pulse train using a sum of + sinsusoids: + + for(m=1; m<=L; m++) + ex[n] = cos(m*Wo*n) + + Note: the Octave script ../octave/phase.m is an example of this if + you would like to try making a pulse train. + + The phase of each excitation harmonic is: + + arg(E[m]) = mWo + + where E[m] are the complex excitation (freq domain) samples, + arg(x), just returns the phase of a complex sample x. + + As we don't transmit the pulse position for this model, we need to + synthesise it. Now the excitation pulses occur at a rate of Wo. + This means the phase of the first harmonic advances by N_SAMP samples + over a synthesis frame of N_SAMP samples. For example if Wo is pi/20 + (200 Hz), then over a 10ms frame (N_SAMP=80 samples), the phase of the + first harmonic would advance (pi/20)*80 = 4*pi or two complete + cycles. + + We generate the excitation phase of the fundamental (first + harmonic): + + arg[E[1]] = Wo*N_SAMP; + + We then relate the phase of the m-th excitation harmonic to the + phase of the fundamental as: + + arg(E[m]) = m*arg(E[1]) + + This E[m] then gets passed through the LPC synthesis filter to + determine the final harmonic phase. + + Comparing to speech synthesised using original phases: + + - Through headphones speech synthesised with this model is not as + good. Through a loudspeaker it is very close to original phases. + + - If there are voicing errors, the speech can sound clicky or + staticy. If V speech is mistakenly declared UV, this model tends to + synthesise impulses or clicks, as there is usually very little shift or + dispersion through the LPC synthesis filter. + + - When combined with LPC amplitude modelling there is an additional + drop in quality. I am not sure why, theory is interformant energy + is raised making any phase errors more obvious. + + NOTES: + + 1/ This synthesis model is effectively the same as a simple LPC-10 + vocoders, and yet sounds much better. Why? Conventional wisdom + (AMBE, MELP) says mixed voicing is required for high quality + speech. + + 2/ I am pretty sure the Lincoln Lab sinusoidal coding guys (like xMBE + also from MIT) first described this zero phase model, I need to look + up the paper. + + 3/ Note that this approach could cause some discontinuities in + the phase at the edge of synthesis frames, as no attempt is made + to make sure that the phase tracks are continuous (the excitation + phases are continuous, but not the final phases after filtering + by the LPC spectra). Technically this is a bad thing. However + this may actually be a good thing, disturbing the phase tracks a + bit. More research needed, e.g. test a synthesis model that adds + a small delta-W to make phase tracks line up for voiced + harmonics. + +\*---------------------------------------------------------------------------*/ + +void CCodec2::phase_synth_zero_order( + int n_samp, + MODEL *model, + float *ex_phase, /* excitation phase of fundamental */ + std::complex H[] /* L synthesis filter freq domain samples */ + +) +{ + int m; + float new_phi; + std::complex Ex[MAX_AMP+1]; /* excitation samples */ + std::complex A_[MAX_AMP+1]; /* synthesised harmonic samples */ + + /* + Update excitation fundamental phase track, this sets the position + of each pitch pulse during voiced speech. After much experiment + I found that using just this frame's Wo improved quality for UV + sounds compared to interpolating two frames Wo like this: + + ex_phase[0] += (*prev_Wo+model->Wo)*N_SAMP/2; + */ + + ex_phase[0] += (model->Wo)*n_samp; + ex_phase[0] -= TWO_PI*floorf(ex_phase[0]/TWO_PI + 0.5); + + for(m=1; m<=model->L; m++) + { + + /* generate excitation */ + + if (model->voiced) + { + Ex[m] = std::polar(1.0f, ex_phase[0] * m); + } + else + { + + /* When a few samples were tested I found that LPC filter + phase is not needed in the unvoiced case, but no harm in + keeping it. + */ + float phi = TWO_PI*(float)codec2_rand()/CODEC2_RAND_MAX; + Ex[m] = std::polar(1.0f, phi); + } + + /* filter using LPC filter */ + + A_[m].real(H[m].real() * Ex[m].real() - H[m].imag() * Ex[m].imag()); + A_[m].imag(H[m].imag() * Ex[m].real() + H[m].real() * Ex[m].imag()); + + /* modify sinusoidal phase */ + + new_phi = atan2f(A_[m].imag(), A_[m].real()+1E-12); + model->phi[m] = new_phi; + } + +} + +/*---------------------------------------------------------------------------*\ + + postfilter() + + The post filter is designed to help with speech corrupted by + background noise. The zero phase model tends to make speech with + background noise sound "clicky". With high levels of background + noise the low level inter-formant parts of the spectrum will contain + noise rather than speech harmonics, so modelling them as voiced + (i.e. a continuous, non-random phase track) is inaccurate. + + Some codecs (like MBE) have a mixed voicing model that breaks the + spectrum into voiced and unvoiced regions. Several bits/frame + (5-12) are required to transmit the frequency selective voicing + information. Mixed excitation also requires accurate voicing + estimation (parameter estimators always break occasionally under + exceptional conditions). + + In our case we use a post filter approach which requires no + additional bits to be transmitted. The decoder measures the average + level of the background noise during unvoiced frames. If a harmonic + is less than this level it is made unvoiced by randomising it's + phases. + + This idea is rather experimental. Some potential problems that may + happen: + + 1/ If someone says "aaaaaaaahhhhhhhhh" will background estimator track + up to speech level? This would be a bad thing. + + 2/ If background noise suddenly dissapears from the source speech does + estimate drop quickly? What is noise suddenly re-appears? + + 3/ Background noise with a non-flat sepctrum. Current algorithm just + comsiders spectrum as a whole, but this could be broken up into + bands, each with their own estimator. + + 4/ Males and females with the same level of background noise. Check + performance the same. Changing Wo affects width of each band, may + affect bg energy estimates. + + 5/ Not sure what happens during long periods of voiced speech + e.g. "sshhhhhhh" + +\*---------------------------------------------------------------------------*/ + +#define BG_THRESH 40.0 // only consider low levels signals for bg_est +#define BG_BETA 0.1 // averaging filter constant +#define BG_MARGIN 6.0 // harmonics this far above BG noise are + // randomised. Helped make bg noise less + // spikey (impulsive) for mmt1, but speech was + // perhaps a little rougher. + +void CCodec2::postfilter( MODEL *model, float *bg_est ) +{ + int m, uv; + float e, thresh; + + /* determine average energy across spectrum */ + + e = 1E-12; + for(m=1; m<=model->L; m++) + e += model->A[m]*model->A[m]; + + assert(e > 0.0); + e = 10.0*log10f(e/model->L); + + /* If beneath threhold, update bg estimate. The idea + of the threshold is to prevent updating during high level + speech. */ + + if ((e < BG_THRESH) && !model->voiced) + *bg_est = *bg_est*(1.0 - BG_BETA) + e*BG_BETA; + + /* now mess with phases during voiced frames to make any harmonics + less then our background estimate unvoiced. + */ + + uv = 0; + thresh = exp10f((*bg_est + BG_MARGIN)/20.0); + if (model->voiced) + for(m=1; m<=model->L; m++) + if (model->A[m] < thresh) + { + model->phi[m] = (TWO_PI/CODEC2_RAND_MAX)*(float)codec2_rand(); + uv++; + } +} + +C2CONST CCodec2::c2const_create(int Fs, float framelength_s) +{ + C2CONST c2const; + + assert((Fs == 8000) || (Fs = 16000)); + c2const.Fs = Fs; + c2const.n_samp = round(Fs*framelength_s); + c2const.max_amp = floor(Fs*P_MAX_S/2); + c2const.p_min = floor(Fs*P_MIN_S); + c2const.p_max = floor(Fs*P_MAX_S); + c2const.m_pitch = floor(Fs*M_PITCH_S); + c2const.Wo_min = TWO_PI/c2const.p_max; + c2const.Wo_max = TWO_PI/c2const.p_min; + + if (Fs == 8000) + { + c2const.nw = 279; + } + else + { + c2const.nw = 511; /* actually a bit shorter in time but lets us maintain constant FFT size */ + } + + c2const.tw = Fs*TW_S; + + /* + fprintf(stderr, "max_amp: %d m_pitch: %d\n", c2const.n_samp, c2const.m_pitch); + fprintf(stderr, "p_min: %d p_max: %d\n", c2const.p_min, c2const.p_max); + fprintf(stderr, "Wo_min: %f Wo_max: %f\n", c2const.Wo_min, c2const.Wo_max); + fprintf(stderr, "nw: %d tw: %d\n", c2const.nw, c2const.tw); + */ + + return c2const; +} + +/*---------------------------------------------------------------------------*\ + + FUNCTION....: make_analysis_window + AUTHOR......: David Rowe + DATE CREATED: 11/5/94 + + Init function that generates the time domain analysis window and it's DFT. + +\*---------------------------------------------------------------------------*/ + +void CCodec2::make_analysis_window(C2CONST *c2const, FFT_STATE *fft_fwd_cfg, float w[], float W[]) +{ + float m; + std::complex wshift[FFT_ENC]; + int i,j; + int m_pitch = c2const->m_pitch; + int nw = c2const->nw; + + /* + Generate Hamming window centered on M-sample pitch analysis window + + 0 M/2 M-1 + |-------------|-------------| + |-------|-------| + nw samples + + All our analysis/synthsis is centred on the M/2 sample. + */ + + m = 0.0; + for(i=0; i temp[FFT_ENC]; + + for(i=0; i(0.0f, 0.0f); + } + for(i=0; i Sw[], float Sn[], float w[]) +{ + int i; + int m_pitch = c2const->m_pitch; + int nw = c2const->nw; + + for(i=0; i(0.0f, 0.0f); + } + + /* Centre analysis window on time axis, we need to arrange input + to FFT this way to make FFT phases correct */ + + /* move 2nd half to start of FFT input vector */ + + for(i=0; i Sw[]) +{ + float pmin,pmax,pstep; /* pitch refinment minimum, maximum and step */ + + /* Coarse refinement */ + + pmax = TWO_PI/model->Wo + 5; + pmin = TWO_PI/model->Wo - 5; + pstep = 1.0; + hs_pitch_refinement(model, Sw, pmin, pmax, pstep); + + /* Fine refinement */ + + pmax = TWO_PI/model->Wo + 1; + pmin = TWO_PI/model->Wo - 1; + pstep = 0.25; + hs_pitch_refinement(model,Sw,pmin,pmax,pstep); + + /* Limit range */ + + if (model->Wo < TWO_PI/c2const->p_max) + model->Wo = TWO_PI/c2const->p_max; + if (model->Wo > TWO_PI/c2const->p_min) + model->Wo = TWO_PI/c2const->p_min; + + model->L = floorf(PI/model->Wo); + + /* trap occasional round off issues with floorf() */ + if (model->Wo*model->L >= 0.95*PI) + { + model->L--; + } + assert(model->Wo*model->L < PI); +} + +/*---------------------------------------------------------------------------*\ + + FUNCTION....: hs_pitch_refinement + AUTHOR......: David Rowe + DATE CREATED: 27/5/94 + + Harmonic sum pitch refinement function. + + pmin pitch search range minimum + pmax pitch search range maximum + step pitch search step size + model current pitch estimate in model.Wo + + model refined pitch estimate in model.Wo + +\*---------------------------------------------------------------------------*/ + +void CCodec2::hs_pitch_refinement(MODEL *model, std::complex Sw[], float pmin, float pmax, float pstep) +{ + int m; /* loop variable */ + int b; /* bin for current harmonic centre */ + float E; /* energy for current pitch*/ + float Wo; /* current "test" fundamental freq. */ + float Wom; /* Wo that maximises E */ + float Em; /* mamimum energy */ + float r, one_on_r; /* number of rads/bin */ + float p; /* current pitch */ + + /* Initialisation */ + + model->L = PI/model->Wo; /* use initial pitch est. for L */ + Wom = model->Wo; + Em = 0.0; + r = TWO_PI/FFT_ENC; + one_on_r = 1.0/r; + + /* Determine harmonic sum for a range of Wo values */ + + for(p=pmin; p<=pmax; p+=pstep) + { + E = 0.0; + Wo = TWO_PI/p; + + /* Sum harmonic magnitudes */ + for(m=1; m<=model->L; m++) + { + b = (int)(m*Wo*one_on_r + 0.5); + E += Sw[b].real() * Sw[b].real() + Sw[b].imag() * Sw[b].imag(); + } + /* Compare to see if this is a maximum */ + + if (E > Em) + { + Em = E; + Wom = Wo; + } + } + + model->Wo = Wom; +} + +/*---------------------------------------------------------------------------*\ + + FUNCTION....: estimate_amplitudes + AUTHOR......: David Rowe + DATE CREATED: 27/5/94 + + Estimates the complex amplitudes of the harmonics. + +\*---------------------------------------------------------------------------*/ + +void CCodec2::estimate_amplitudes(MODEL *model, std::complex Sw[], int est_phase) +{ + int i,m; /* loop variables */ + int am,bm; /* bounds of current harmonic */ + float den; /* denominator of amplitude expression */ + + float r = TWO_PI/FFT_ENC; + float one_on_r = 1.0/r; + + for(m=1; m<=model->L; m++) + { + /* Estimate ampltude of harmonic */ + + den = 0.0; + am = (int)((m - 0.5)*model->Wo*one_on_r + 0.5); + bm = (int)((m + 0.5)*model->Wo*one_on_r + 0.5); + + for(i=am; iA[m] = sqrtf(den); + + if (est_phase) + { + int b = (int)(m*model->Wo/r + 0.5); /* DFT bin of centre of current harmonic */ + + /* Estimate phase of harmonic, this is expensive in CPU for + embedded devicesso we make it an option */ + + model->phi[m] = atan2f(Sw[b].imag(), Sw[b].real()); + } + } +} + +/*---------------------------------------------------------------------------*\ + + est_voicing_mbe() + + Returns the error of the MBE cost function for a fiven F0. + + Note: I think a lot of the operations below can be simplified as + W[].imag = 0 and has been normalised such that den always equals 1. + +\*---------------------------------------------------------------------------*/ + +float CCodec2::est_voicing_mbe( C2CONST *c2const, MODEL *model, std::complex Sw[], float W[]) +{ + int l,al,bl,m; /* loop variables */ + std::complex Am; /* amplitude sample for this band */ + int offset; /* centers Hw[] about current harmonic */ + float den; /* denominator of Am expression */ + float error; /* accumulated error between original and synthesised */ + float Wo; + float sig, snr; + float elow, ehigh, eratio; + float sixty; + std::complex Ew(0, 0); + + int l_1000hz = model->L*1000.0/(c2const->Fs/2); + sig = 1E-4; + for(l=1; l<=l_1000hz; l++) + { + sig += model->A[l]*model->A[l]; + } + + Wo = model->Wo; + error = 1E-4; + + /* Just test across the harmonics in the first 1000 Hz */ + + for(l=1; l<=l_1000hz; l++) + { + Am = std::complex(0.0f, 0.0f); + den = 0.0; + al = ceilf((l - 0.5)*Wo*FFT_ENC/TWO_PI); + bl = ceilf((l + 0.5)*Wo*FFT_ENC/TWO_PI); + + /* Estimate amplitude of harmonic assuming harmonic is totally voiced */ + + offset = FFT_ENC/2 - l*Wo*FFT_ENC/TWO_PI + 0.5; + for(m=al; m V_THRESH) + model->voiced = 1; + else + model->voiced = 0; + + /* post processing, helps clean up some voicing errors ------------------*/ + + /* + Determine the ratio of low freqency to high frequency energy, + voiced speech tends to be dominated by low frequency energy, + unvoiced by high frequency. This measure can be used to + determine if we have made any gross errors. + */ + + int l_2000hz = model->L*2000.0/(c2const->Fs/2); + int l_4000hz = model->L*4000.0/(c2const->Fs/2); + elow = ehigh = 1E-4; + for(l=1; l<=l_2000hz; l++) + { + elow += model->A[l]*model->A[l]; + } + for(l=l_2000hz; l<=l_4000hz; l++) + { + ehigh += model->A[l]*model->A[l]; + } + eratio = 10.0*log10f(elow/ehigh); + + /* Look for Type 1 errors, strongly V speech that has been + accidentally declared UV */ + + if (model->voiced == 0) + if (eratio > 10.0) + model->voiced = 1; + + /* Look for Type 2 errors, strongly UV speech that has been + accidentally declared V */ + + if (model->voiced == 1) + { + if (eratio < -10.0) + model->voiced = 0; + + /* A common source of Type 2 errors is the pitch estimator + gives a low (50Hz) estimate for UV speech, which gives a + good match with noise due to the close harmoonic spacing. + These errors are much more common than people with 50Hz3 + pitch, so we have just a small eratio threshold. */ + + sixty = 60.0*TWO_PI/c2const->Fs; + if ((eratio < -4.0) && (model->Wo <= sixty)) + model->voiced = 0; + } + //printf(" v: %d snr: %f eratio: %3.2f %f\n",model->voiced,snr,eratio,dF0); + + return snr; +} + +/*---------------------------------------------------------------------------*\ + + FUNCTION....: make_synthesis_window + AUTHOR......: David Rowe + DATE CREATED: 11/5/94 + + Init function that generates the trapezoidal (Parzen) sythesis window. + +\*---------------------------------------------------------------------------*/ + +void CCodec2::make_synthesis_window(C2CONST *c2const, float Pn[]) +{ + int i; + float win; + int n_samp = c2const->n_samp; + int tw = c2const->tw; + + /* Generate Parzen window in time domain */ + + win = 0.0; + for(i=0; i Sw_[FFT_DEC/2+1]; /* DFT of synthesised signal */ + float sw_[FFT_DEC]; /* synthesised signal */ + + if (shift) + { + /* Update memories */ + for(i=0; iL; l++) + { + b = (int)(l*model->Wo*FFT_DEC/TWO_PI + 0.5); + if (b > ((FFT_DEC/2)-1)) + { + b = (FFT_DEC/2)-1; + } + Sw_[b] = std::polar(model->A[l], model->phi[l]); + } + + /* Perform inverse DFT */ + + kiss.fftri(*fftr_inv_cfg, Sw_,sw_); + + /* Overlap add to previous samples */ + + for(i=0; ivoiced && !prev->voiced && !next->voiced) + { + interp->voiced = 0; + } + + /* Wo depends on voicing of this and adjacent frames */ + + if (interp->voiced) + { + if (prev->voiced && next->voiced) + interp->Wo = (1.0 - weight)*prev->Wo + weight*next->Wo; + if (!prev->voiced && next->voiced) + interp->Wo = next->Wo; + if (prev->voiced && !next->voiced) + interp->Wo = prev->Wo; + } + else + { + interp->Wo = Wo_min; + } + interp->L = PI/interp->Wo; +} + +/*---------------------------------------------------------------------------*\ + + FUNCTION....: interp_energy() + AUTHOR......: David Rowe + DATE CREATED: 22 May 2012 + + Interpolates centre 10ms sample of energy given two samples 20ms + apart. + +\*---------------------------------------------------------------------------*/ + +float CCodec2::interp_energy(float prev_e, float next_e) +{ + //return powf(10.0, (log10f(prev_e) + log10f(next_e))/2.0); + return sqrtf(prev_e * next_e); //looks better is math. identical and faster math +} + +/*---------------------------------------------------------------------------*\ + + FUNCTION....: interpolate_lsp_ver2() + AUTHOR......: David Rowe + DATE CREATED: 22 May 2012 + + Weighted interpolation of LSPs. + +\*---------------------------------------------------------------------------*/ + +void CCodec2::interpolate_lsp_ver2(float interp[], float prev[], float next[], float weight, int order) +{ + int i; + + for(i=0; i. +*/ + +#ifndef __CODEC2__ +#define __CODEC2__ + +#include + +#include "codec2_internal.h" +#include "defines.h" +#include "kiss_fft.h" +#include "nlp.h" +#include "quantise.h" + +#define CODEC2_MODE_3200 0 +#define CODEC2_MODE_1600 2 + +#ifndef CODEC2_MODE_EN_DEFAULT +#define CODEC2_MODE_EN_DEFAULT 1 +#endif + +#define CODEC2_RAND_MAX 32767 + +class CCodec2 +{ +public: + CCodec2(bool is_3200); + ~CCodec2(); + void codec2_encode(unsigned char *bits, const short *speech_in); + void codec2_decode(short *speech_out, const unsigned char *bits); + int codec2_samples_per_frame(); + int codec2_bits_per_frame(); + +private: + // merged from other files + void sample_phase(MODEL *model, std::complex filter_phase[], std::complex A[]); + void phase_synth_zero_order(int n_samp, MODEL *model, float *ex_phase, std::complex filter_phase[]); + void postfilter(MODEL *model, float *bg_est); + + C2CONST c2const_create(int Fs, float framelength_ms); + + void make_analysis_window(C2CONST *c2const, FFT_STATE *fft_fwd_cfg, float w[], float W[]); + void dft_speech(C2CONST *c2const, FFT_STATE &fft_fwd_cfg, std::complex Sw[], float Sn[], float w[]); + void two_stage_pitch_refinement(C2CONST *c2const, MODEL *model, std::complex Sw[]); + void estimate_amplitudes(MODEL *model, std::complex Sw[], int est_phase); + float est_voicing_mbe(C2CONST *c2const, MODEL *model, std::complex Sw[], float W[]); + void make_synthesis_window(C2CONST *c2const, float Pn[]); + void synthesise(int n_samp, FFTR_STATE *fftr_inv_cfg, float Sn_[], MODEL *model, float Pn[], int shift); + int codec2_rand(void); + void hs_pitch_refinement(MODEL *model, std::complex Sw[], float pmin, float pmax, float pstep); + + void interp_Wo(MODEL *interp, MODEL *prev, MODEL *next, float Wo_min); + void interp_Wo2(MODEL *interp, MODEL *prev, MODEL *next, float weight, float Wo_min); + float interp_energy(float prev, float next); + void interpolate_lsp_ver2(float interp[], float prev[], float next[], float weight, int order); + + void analyse_one_frame(MODEL *model, const short *speech); + void synthesise_one_frame(short speech[], MODEL *model, std::complex Aw[], float gain); + void codec2_encode_3200(unsigned char *bits, const short *speech); + void codec2_encode_1600(unsigned char *bits, const short *speech); + void codec2_decode_3200(short *speech, const unsigned char *bits); + void codec2_decode_1600(short *speech, const unsigned char *bits); + void ear_protection(float in_out[], int n); + void lsp_to_lpc(float *freq, float *ak, int lpcrdr); + + void (CCodec2::*encode)(unsigned char *bits, const short *speech); + void (CCodec2::*decode)(short *speech, const unsigned char *bits); + Cnlp nlp; + CQuantize qt; + CODEC2 c2; +}; + +#endif diff --git a/codec2/codec2_internal.h b/codec2/codec2_internal.h new file mode 100644 index 0000000..1b037e1 --- /dev/null +++ b/codec2/codec2_internal.h @@ -0,0 +1,67 @@ +/*---------------------------------------------------------------------------*\ + + FILE........: codec2_internal.h + AUTHOR......: David Rowe + DATE CREATED: April 16 2012 + + Header file for Codec2 internal states, exposed via this header + file to assist in testing. + +\*---------------------------------------------------------------------------*/ + +/* + Copyright (C) 2012 David Rowe + + All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 2.1, as + published by the Free Software Foundation. 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. + + You should have received a copy of the GNU Lesser General Public License + along with this program; if not, see . +*/ + +#ifndef __CODEC2_INTERNAL__ +#define __CODEC2_INTERNAL__ + +#include "kiss_fft.h" + +using CODEC2 = struct codec2_tag { + int mode; + int Fs; + int n_samp; + int m_pitch; + int gray; /* non-zero for gray encoding */ + int lpc_pf; /* LPC post filter on */ + int bass_boost; /* LPC post filter bass boost */ + int smoothing; /* enable smoothing for channels with errors */ + float ex_phase; /* excitation model phase track */ + float bg_est; /* background noise estimate for post filter */ + float prev_f0_enc; /* previous frame's f0 estimate */ + float prev_e_dec; /* previous frame's LPC energy */ + float beta; /* LPC post filter parameters */ + float gamma; + float xq_enc[2]; /* joint pitch and energy VQ states */ + float xq_dec[2]; + float W[FFT_ENC]; /* DFT of w[] */ + float hpf_states[2]; /* high pass filter states */ + float prev_lsps_dec[LPC_ORD]; /* previous frame's LSPs */ + float *softdec; /* optional soft decn bits from demod */ + MODEL prev_model_dec; /* previous frame's model parameters */ + C2CONST c2const; + FFT_STATE fft_fwd_cfg; /* forward FFT config */ + FFTR_STATE fftr_fwd_cfg; /* forward real FFT config */ + FFTR_STATE fftr_inv_cfg; /* inverse FFT config */ + std::vector w; /* [m_pitch] time domain hamming window */ + std::vector Pn; /* [2*n_samp] trapezoidal synthesis window */ + std::vector Sn; /* [m_pitch] input speech */ + std::vector Sn_; /* [2*n_samp] synthesised output speech */ + std::vector bpf_buf; /* buffer for band pass filter */ +}; + +#endif diff --git a/codec2/defines.h b/codec2/defines.h new file mode 100644 index 0000000..f201313 --- /dev/null +++ b/codec2/defines.h @@ -0,0 +1,127 @@ +/*---------------------------------------------------------------------------*\ + + FILE........: defines.h + AUTHOR......: David Rowe + DATE CREATED: 23/4/93 + + Defines and structures used throughout the codec. + +\*---------------------------------------------------------------------------*/ + +/* + Copyright (C) 2009 David Rowe + + All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 2.1, as + published by the Free Software Foundation. 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. + + You should have received a copy of the GNU Lesser General Public License + along with this program; if not, see . +*/ + +#ifndef __DEFINES__ +#define __DEFINES__ + +#include +#include + +/*---------------------------------------------------------------------------*\ + + DEFINES + +\*---------------------------------------------------------------------------*/ + +/* General defines */ + +#define N_S 0.01 /* internal proc frame length in secs */ +#define TW_S 0.005 /* trapezoidal synth window overlap */ +#define MAX_AMP 160 /* maximum number of harmonics */ +#ifndef PI +#define PI 3.141592654 /* mathematical constant */ +#endif +#define TWO_PI 6.283185307 /* mathematical constant */ +#define MAX_STR 2048 /* maximum string size */ + +#define FFT_ENC 512 /* size of FFT used for encoder */ +#define FFT_DEC 512 /* size of FFT used in decoder */ +#define V_THRESH 6.0 /* voicing threshold in dB */ +#define LPC_ORD 10 /* LPC order */ +#define LPC_ORD_LOW 6 /* LPC order for lower rates */ + +/* Pitch estimation defines */ + +#define M_PITCH_S 0.0400 /* pitch analysis window in s */ +#define P_MIN_S 0.0025 /* minimum pitch period in s */ +#define P_MAX_S 0.0200 /* maximum pitch period in s */ +#define MAXFACTORS 32 // e.g. an fft of length 128 has 4 factors + // as far as kissfft is concerned 4*4*4*2 + +/*---------------------------------------------------------------------------*\ + + TYPEDEFS + +\*---------------------------------------------------------------------------*/ + +/* Structure to hold constants calculated at run time based on sample rate */ + +using C2CONST = struct c2const_tag +{ + int Fs; /* sample rate of this instance */ + int n_samp; /* number of samples per 10ms frame at Fs */ + int max_amp; /* maximum number of harmonics */ + int m_pitch; /* pitch estimation window size in samples */ + int p_min; /* minimum pitch period in samples */ + int p_max; /* maximum pitch period in samples */ + float Wo_min; + float Wo_max; + int nw; /* analysis window size in samples */ + int tw; /* trapezoidal synthesis window overlap */ +}; + +/* Structure to hold model parameters for one frame */ + +using MODEL = struct model_tag +{ + float Wo; /* fundamental frequency estimate in radians */ + int L; /* number of harmonics */ + float A[MAX_AMP+1]; /* amplitiude of each harmonic */ + float phi[MAX_AMP+1]; /* phase of each harmonic */ + int voiced; /* non-zero if this frame is voiced */ +}; + +/* describes each codebook */ + +struct lsp_codebook +{ + int k; /* dimension of vector */ + int log2m; /* number of bits in m */ + int m; /* elements in codebook */ + float *cb; /* The elements */ +}; + +using FFT_STATE = struct fft_state_tag +{ + int nfft; + bool inverse; + int factors[2*MAXFACTORS]; + std::vector> twiddles; +}; + +using FFTR_STATE = struct fftr_state_tag +{ + FFT_STATE substate; + std::vector> tmpbuf; + std::vector> super_twiddles; +}; + +extern const struct lsp_codebook lsp_cb[]; +extern const struct lsp_codebook lsp_cbd[]; +extern const struct lsp_codebook ge_cb[]; + +#endif diff --git a/codec2/kiss_fft.cpp b/codec2/kiss_fft.cpp new file mode 100644 index 0000000..cefb846 --- /dev/null +++ b/codec2/kiss_fft.cpp @@ -0,0 +1,435 @@ +/* +Copyright (c) 2003-2010, Mark Borgerding + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + * Neither the author nor the names of any contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include + +#include "defines.h" +#include "kiss_fft.h" + +void CKissFFT::kf_bfly2(std::complex *Fout, const size_t fstride, FFT_STATE &st, int m) +{ + std::complex *Fout2; + std::complex *tw1 = st.twiddles.data(); + std::complex t; + Fout2 = Fout + m; + do + { + t = *Fout2 * *tw1; + tw1 += fstride; + *Fout2 = *Fout - t; + *Fout += t; + ++Fout2; + ++Fout; + } + while (--m); +} + +void CKissFFT::kf_bfly3(std::complex * Fout, const size_t fstride, FFT_STATE &st, int m) +{ + const size_t m2 = 2 * m; + std::complex *tw1,*tw2; + std::complex scratch[5]; + std::complex epi3; + epi3 = st.twiddles[fstride*m]; + + tw1 = tw2 = st.twiddles.data(); + + do + { + scratch[1] = Fout[m] * *tw1; + scratch[2] = Fout[m2] * *tw2; + + scratch[3] = scratch[1] + scratch[2]; + scratch[0] = scratch[1] - scratch[2]; + tw1 += fstride; + tw2 += fstride*2; + + Fout[m] = *Fout - (0.5f * scratch[3]); + + scratch[0] *= epi3.imag(); + + *Fout += scratch[3]; + + Fout[m2].real(Fout[m].real() + scratch[0].imag()); + Fout[m2].imag(Fout[m].imag() - scratch[0].real()); + + Fout[m].real(Fout[m].real() - scratch[0].imag()); + Fout[m].imag(Fout[m].imag() + scratch[0].real()); + + ++Fout; + } + while(--m); +} + +void CKissFFT::kf_bfly4(std::complex *Fout, const size_t fstride, FFT_STATE &st, int m) +{ + std::complex *tw1,*tw2,*tw3; + std::complex scratch[6]; + int k = m; + const int m2 = 2 * m; + const int m3 = 3 * m; + + + tw3 = tw2 = tw1 = st.twiddles.data(); + + do + { + scratch[0] = Fout[m] * *tw1; + scratch[1] = Fout[m2] * *tw2; + scratch[2] = Fout[m3] * *tw3; + + scratch[5] = *Fout - scratch[1]; + *Fout += scratch[1]; + scratch[3] = scratch[0] + scratch[2]; + scratch[4] = scratch[0] - scratch[2]; + Fout[m2] = *Fout - scratch[3]; + tw1 += fstride; + tw2 += fstride*2; + tw3 += fstride*3; + *Fout += scratch[3]; + + if(st.inverse) + { + Fout[m].real(scratch[5].real() - scratch[4].imag()); + Fout[m].imag(scratch[5].imag() + scratch[4].real()); + Fout[m3].real(scratch[5].real() + scratch[4].imag()); + Fout[m3].imag(scratch[5].imag() - scratch[4].real()); + } + else + { + Fout[m].real(scratch[5].real() + scratch[4].imag()); + Fout[m].imag(scratch[5].imag() - scratch[4].real()); + Fout[m3].real(scratch[5].real() - scratch[4].imag()); + Fout[m3].imag(scratch[5].imag() + scratch[4].real()); + } + ++Fout; + } + while(--k); +} + +void CKissFFT::kf_bfly5(std::complex * Fout, const size_t fstride, FFT_STATE &st, int m) +{ + std::complex scratch[13]; + std::complex *twiddles = st.twiddles.data(); + auto ya = twiddles[fstride*m]; + auto yb = twiddles[fstride*2*m]; + + auto Fout0 = Fout; + auto Fout1 = Fout0 + m; + auto Fout2 = Fout0 + 2 * m; + auto Fout3 = Fout0 + 3 * m; + auto Fout4 = Fout0 + 4 * m; + + auto tw = st.twiddles.data(); + for (int u=0; u *Fout, const size_t fstride, FFT_STATE &st, int m, int p) +{ + auto twiddles = st.twiddles.data(); + std::complex t; + int Norig = st.nfft; + + std::vector> scratch(p); + + for (int u=0; u= Norig) twidx-=Norig; + t = scratch[q] * twiddles[twidx]; + Fout[k] += t; + } + k += m; + } + } + scratch.clear(); +} + +void CKissFFT::kf_work(std::complex *Fout, const std::complex *f, const size_t fstride, int in_stride, int *factors, FFT_STATE &st) +{ + auto Fout_beg = Fout; + const int p = *factors++; /* the radix */ + const int m = *factors++; /* stage's fft length/p */ + const std::complex *Fout_end = Fout + p*m; + + if (m==1) + { + do + { + *Fout = *f; + f += fstride*in_stride; + } + while( ++Fout != Fout_end ); + } + else + { + do + { + // recursive call: + // DFT of size m*p performed by doing + // p instances of smaller DFTs of size m, + // each one takes a decimated version of the input + kf_work( Fout, f, fstride*p, in_stride, factors, st); + f += fstride*in_stride; + } + while( (Fout += m) != Fout_end ); + } + + Fout=Fout_beg; + + // recombine the p smaller DFTs + switch (p) + { + case 2: + kf_bfly2(Fout,fstride,st,m); + break; + case 3: + kf_bfly3(Fout,fstride,st,m); + break; + case 4: + kf_bfly4(Fout,fstride,st,m); + break; + case 5: + kf_bfly5(Fout,fstride,st,m); + break; + default: + kf_bfly_generic(Fout,fstride,st,m,p); + break; + } +} + +/* facbuf is populated by p1,m1,p2,m2, ... + where + p[i] * m[i] = m[i-1] + m0 = n */ +void CKissFFT::kf_factor(int n,int * facbuf) +{ + int p=4; + double floor_sqrt; + floor_sqrt = floorf( sqrtf((double)n) ); + + /*factor out powers of 4, powers of 2, then any remaining primes */ + do + { + while (n % p) + { + switch (p) + { + case 4: + p = 2; + break; + case 2: + p = 3; + break; + default: + p += 2; + break; + } + if (p > floor_sqrt) + p = n; /* no more factors, skip to end */ + } + n /= p; + *facbuf++ = p; + *facbuf++ = n; + } + while (n > 1); +} + +void CKissFFT::fft_alloc(FFT_STATE &state, const int nfft, bool inverse_fft) +{ + state.twiddles.resize(nfft); + + state.nfft = nfft; + state.inverse = inverse_fft; + + for (int i=0; i *fin, std::complex *fout, int in_stride) +{ + if (fin == fout) + { + //NOTE: this is not really an in-place FFT algorithm. + //It just performs an out-of-place FFT into a temp buffer + std::vector> tmpbuf(st.nfft); + kf_work(tmpbuf.data(), fin, true, in_stride, st.factors, st); + memcpy(fout, tmpbuf.data(), sizeof(std::complex)*st.nfft); + tmpbuf.clear(); + } + else + { + kf_work(fout, fin, 1, in_stride, st.factors, st); + } +} + +void CKissFFT::fft(FFT_STATE &cfg, const std::complex *fin, std::complex *fout) +{ + fft_stride(cfg, fin, fout, 1); +} + +int CKissFFT::fft_next_fast_size(int n) +{ + while(1) + { + int m = n; + while ( (m % 2) == 0 ) m /= 2; + while ( (m % 3) == 0 ) m /= 3; + while ( (m % 5) == 0 ) m /= 5; + if (m <= 1) + break; /* n is completely factorable by twos, threes, and fives */ + n++; + } + return n; +} + +void CKissFFT::fftr_alloc(FFTR_STATE &st, int nfft, const bool inverse_fft) +{ + nfft >>= 1; + + fft_alloc(st.substate, nfft, inverse_fft); + st.tmpbuf.resize(nfft); + st.super_twiddles.resize(nfft); + + for (int i=0; i *freqdata) +{ + assert(st.substate.inverse == false); + + auto ncfft = st.substate.nfft; + + /*perform the parallel fft of two real signals packed in real,imag*/ + fft( st.substate, (const std::complex*)timedata, st.tmpbuf.data()); + /* The real part of the DC element of the frequency spectrum in st->tmpbuf + * contains the sum of the even-numbered elements of the input time sequence + * The imag part is the sum of the odd-numbered elements + * + * The sum of tdc.r and tdc.i is the sum of the input time sequence. + * yielding DC of input time sequence + * The difference of tdc.r - tdc.i is the sum of the input (dot product) [1,-1,1,-1... + * yielding Nyquist bin of input time sequence + */ + + auto tdc = st.tmpbuf[0]; + freqdata[0].real(tdc.real() + tdc.imag()); + freqdata[ncfft].real(tdc.real() - tdc.imag()); + freqdata[ncfft].imag(0.f); + freqdata[0].imag(0.f); + + for (int k=1; k <= ncfft/2; ++k) + { + auto fpk = st.tmpbuf[k]; + auto fpnk = std::conj(st.tmpbuf[ncfft-k]); + + auto f1k = fpk + fpnk; + auto f2k = fpk - fpnk; + auto tw = f2k * st.super_twiddles[k-1]; + + freqdata[k] = 0.5f * (f1k + tw); + freqdata[ncfft-k].real(0.5f * (f1k.real() - tw.real())); + freqdata[ncfft-k].imag(0.5f * (tw.imag() - f1k.imag())); + } +} + +void CKissFFT::fftri(FFTR_STATE &st, const std::complex *freqdata, float *timedata) +{ + assert(st.substate.inverse == true); + + auto ncfft = st.substate.nfft; + + st.tmpbuf[0].real(freqdata[0].real() + freqdata[ncfft].real()); + st.tmpbuf[0].imag(freqdata[0].real() - freqdata[ncfft].real()); + + for (int k=1; k <= ncfft/2; ++k) + { + auto fk = freqdata[k]; + auto fnkc = std::conj(freqdata[ncfft - k]); + + auto fek = fk + fnkc; + auto tmp = fk - fnkc; + auto fok = tmp * st.super_twiddles[k-1]; + st.tmpbuf[k] = fek + fok; + st.tmpbuf[ncfft - k] = std::conj(fek - fok); + } + fft (st.substate, st.tmpbuf.data(), (std::complex *)timedata); +} diff --git a/codec2/kiss_fft.h b/codec2/kiss_fft.h new file mode 100644 index 0000000..7626617 --- /dev/null +++ b/codec2/kiss_fft.h @@ -0,0 +1,35 @@ +#ifndef KISS_FFT_H +#define KISS_FFT_H + +#include + +#include +#include +#include +#include + +#include "defines.h" + +/* for real ffts, we need an even size */ +#define kiss_fftr_next_fast_size_real(n) (kiss_fft_next_fast_size( ((n)+1) >> 1) << 1 ) + +class CKissFFT +{ +public: + void fft_alloc(FFT_STATE &state, const int nfft, const bool inverse_fft); + void fft(FFT_STATE &cfg, const std::complex *fin, std::complex *fout); + void fft_stride(FFT_STATE &cfg, const std::complex *fin, std::complex *fout, int fin_stride); + int fft_next_fast_size(int n); + void fftr_alloc(FFTR_STATE &state, int nfft, const bool inverse_fft); + void fftr(FFTR_STATE &cfg,const float *timedata,std::complex *freqdata); + void fftri(FFTR_STATE &cfg,const std::complex *freqdata,float *timedata); +private: + void kf_bfly2(std::complex *Fout, const size_t fstride, FFT_STATE &st, int m); + void kf_bfly3(std::complex *Fout, const size_t fstride, FFT_STATE &st, int m); + void kf_bfly4(std::complex *Fout, const size_t fstride, FFT_STATE &st, int m); + void kf_bfly5(std::complex *Fout, const size_t fstride, FFT_STATE &st, int m); + void kf_bfly_generic(std::complex *Fout, const size_t fstride, FFT_STATE &st, int m, int p); + void kf_work(std::complex *Fout, const std::complex *f, const size_t fstride, int in_stride, int *factors, FFT_STATE &st); + void kf_factor(int n, int *facbuf); +}; +#endif diff --git a/codec2/lpc.cpp b/codec2/lpc.cpp new file mode 100644 index 0000000..10f2c09 --- /dev/null +++ b/codec2/lpc.cpp @@ -0,0 +1,311 @@ +/*---------------------------------------------------------------------------*\ + + FILE........: lpc.c + AUTHOR......: David Rowe + DATE CREATED: 30 Sep 1990 (!) + + Linear Prediction functions written in C. + +\*---------------------------------------------------------------------------*/ + +/* + Copyright (C) 2009-2012 David Rowe + + All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 2.1, as + published by the Free Software Foundation. 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. + + You should have received a copy of the GNU Lesser General Public License + along with this program; if not, see . +*/ + +#define LPC_MAX_N 512 /* maximum no. of samples in frame */ +#define PI 3.141592654 /* mathematical constant */ + +#define ALPHA 1.0 +#define BETA 0.94 + +#include +#include +#include "defines.h" +#include "lpc.h" + +/*---------------------------------------------------------------------------*\ + + pre_emp() + + Pre-emphasise (high pass filter with zero close to 0 Hz) a frame of + speech samples. Helps reduce dynamic range of LPC spectrum, giving + greater weight and hense a better match to low energy formants. + + Should be balanced by de-emphasis of the output speech. + +\*---------------------------------------------------------------------------*/ + +void Clpc::pre_emp( + float Sn_pre[], /* output frame of speech samples */ + float Sn[], /* input frame of speech samples */ + float *mem, /* Sn[-1]single sample memory */ + int Nsam /* number of speech samples to use */ +) +{ + int i; + + for(i=0; i 1.0) + k = 0.0; + + a[i][i] = k; + + for(j=1; j<=i-1; j++) + a[i][j] = a[i-1][j] + k*a[i-1][i-j]; /* Equation 38c, Makhoul */ + + e *= (1-k*k); /* Equation 38d, Makhoul */ + } + + for(i=1; i<=order; i++) + lpcs[i] = a[order][i]; + lpcs[0] = 1.0; +} + +/*---------------------------------------------------------------------------*\ + + inverse_filter() + + Inverse Filter, A(z). Produces an array of residual samples from an array + of input samples and linear prediction coefficients. + + The filter memory is stored in the first order samples of the input array. + +\*---------------------------------------------------------------------------*/ + +void Clpc::inverse_filter( + float Sn[], /* Nsam input samples */ + float a[], /* LPCs for this frame of samples */ + int Nsam, /* number of samples */ + float res[], /* Nsam residual samples */ + int order /* order of LPC */ +) +{ + int i,j; /* loop variables */ + + for(i=0; i. +*/ + +#ifndef __LPC__ +#define __LPC__ + +#define LPC_MAX_ORDER 20 + +class Clpc { +public: + void autocorrelate(float Sn[], float Rn[], int Nsam, int order); + void levinson_durbin(float R[], float lpcs[], int order); +private: + void pre_emp(float Sn_pre[], float Sn[], float *mem, int Nsam); + void de_emp(float Sn_se[], float Sn[], float *mem, int Nsam); + void hanning_window(float Sn[], float Wn[], int Nsam); + void inverse_filter(float Sn[], float a[], int Nsam, float res[], int order); + void synthesis_filter(float res[], float a[], int Nsam, int order, float Sn_[]); + void find_aks(float Sn[], float a[], int Nsam, int order, float *E); + void weight(float ak[], float gamma, int order, float akw[]); +}; + +#endif diff --git a/codec2/nlp.cpp b/codec2/nlp.cpp new file mode 100644 index 0000000..753e96b --- /dev/null +++ b/codec2/nlp.cpp @@ -0,0 +1,520 @@ +/*---------------------------------------------------------------------------*\ + + FILE........: nlp.c + AUTHOR......: David Rowe + DATE CREATED: 23/3/93 + + Non Linear Pitch (NLP) estimation functions. + +\*---------------------------------------------------------------------------*/ + +/* + Copyright (C) 2009 David Rowe + + All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 2.1, as + published by the Free Software Foundation. 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. + + You should have received a copy of the GNU Lesser General Public License + along with this program; if not, see . +*/ + +#include +#include +#include + +#include "defines.h" +#include "nlp.h" +#include "kiss_fft.h" + +extern CKissFFT kiss; + +/*---------------------------------------------------------------------------*\ + + GLOBALS + +\*---------------------------------------------------------------------------*/ + +/* 48 tap 600Hz low pass FIR filter coefficients */ + +static const float nlp_fir[] = +{ + -1.0818124e-03, + -1.1008344e-03, + -9.2768838e-04, + -4.2289438e-04, + 5.5034190e-04, + 2.0029849e-03, + 3.7058509e-03, + 5.1449415e-03, + 5.5924666e-03, + 4.3036754e-03, + 8.0284511e-04, + -4.8204610e-03, + -1.1705810e-02, + -1.8199275e-02, + -2.2065282e-02, + -2.0920610e-02, + -1.2808831e-02, + 3.2204775e-03, + 2.6683811e-02, + 5.5520624e-02, + 8.6305944e-02, + 1.1480192e-01, + 1.3674206e-01, + 1.4867556e-01, + 1.4867556e-01, + 1.3674206e-01, + 1.1480192e-01, + 8.6305944e-02, + 5.5520624e-02, + 2.6683811e-02, + 3.2204775e-03, + -1.2808831e-02, + -2.0920610e-02, + -2.2065282e-02, + -1.8199275e-02, + -1.1705810e-02, + -4.8204610e-03, + 8.0284511e-04, + 4.3036754e-03, + 5.5924666e-03, + 5.1449415e-03, + 3.7058509e-03, + 2.0029849e-03, + 5.5034190e-04, + -4.2289438e-04, + -9.2768838e-04, + -1.1008344e-03, + -1.0818124e-03 +}; + +static const float fdmdv_os_filter[]= { + -0.0008215855034550382, + -0.0007833023901802921, + 0.001075563790768233, + 0.001199092367787555, + -0.001765309502928316, + -0.002055372115328064, + 0.002986877604154257, + 0.003462567920638414, + -0.004856570111126334, + -0.005563143845031497, + 0.007533613299748122, + 0.008563932468880897, + -0.01126857129039911, + -0.01280782411693687, + 0.01651443896361847, + 0.01894875110322284, + -0.02421604439474981, + -0.02845107338464062, + 0.03672973563400258, + 0.04542046150312214, + -0.06189165826716491, + -0.08721876380763803, + 0.1496157094199961, + 0.4497962274137046, + 0.4497962274137046, + 0.1496157094199961, + -0.08721876380763803, + -0.0618916582671649, + 0.04542046150312216, + 0.03672973563400257, + -0.02845107338464062, + -0.02421604439474984, + 0.01894875110322284, + 0.01651443896361848, + -0.01280782411693687, + -0.0112685712903991, + 0.008563932468880899, + 0.007533613299748123, + -0.005563143845031501, + -0.004856570111126346, + 0.003462567920638419, + 0.002986877604154259, + -0.002055372115328063, + -0.001765309502928318, + 0.001199092367787557, + 0.001075563790768233, + -0.0007833023901802925, + -0.0008215855034550383 +}; + +/*---------------------------------------------------------------------------*\ + + nlp_create() + + Initialisation function for NLP pitch estimator. + +\*---------------------------------------------------------------------------*/ + +void Cnlp::nlp_create(C2CONST *c2const) +{ + int i; + int m = c2const->m_pitch; + int Fs = c2const->Fs; + + assert((Fs == 8000) || (Fs == 16000)); + snlp.Fs = Fs; + + snlp.m = m; + + /* if running at 16kHz allocate storage for decimating filter memory */ + + if (Fs == 16000) + { + snlp.Sn16k.resize(FDMDV_OS_TAPS_16K + c2const->n_samp); + for(i=0; i Sw[], /* Freq domain version of Sn[] */ +// float W[], /* Freq domain window */ + float *prev_f0 /* previous pitch f0 in Hz, memory for pitch tracking */ +) +{ + float notch; /* current notch filter output */ + std::complex Fw[PE_FFT_SIZE]; /* DFT of squared signal (input/output) */ + float gmax; + int gmax_bin; + int m, i, j; + float best_f0; + + m = snlp.m; + + /* Square, notch filter at DC, and LP filter vector */ + + /* If running at 16 kHz decimate to 8 kHz, as NLP ws designed for + Fs = 8kHz. The decimating filter introduces about 3ms of delay, + that shouldn't be a problem as pitch changes slowly. */ + + if (snlp.Fs == 8000) + { + /* Square latest input samples */ + + for(i=m-n; i gmax) + { + gmax = Fw[i].real(); + gmax_bin = i; + } + } + + best_f0 = post_process_sub_multiples(Fw, pmax, gmax, gmax_bin, prev_f0); + + /* Shift samples in buffer to make room for new samples */ + + for(i=0; i Fw[], int pmax, float gmax, int gmax_bin, float *prev_f0) +{ + int min_bin, cmax_bin; + int mult; + float thresh, best_f0; + int b, bmin, bmax, lmax_bin; + float lmax; + int prev_f0_bin; + + /* post process estimate by searching submultiples */ + + mult = 2; + min_bin = PE_FFT_SIZE*DEC/pmax; + cmax_bin = gmax_bin; + prev_f0_bin = *prev_f0*(PE_FFT_SIZE*DEC)/SAMPLE_RATE; + + while(gmax_bin/mult >= min_bin) + { + + b = gmax_bin/mult; /* determine search interval */ + bmin = 0.8*b; + bmax = 1.2*b; + if (bmin < min_bin) + bmin = min_bin; + + /* lower threshold to favour previous frames pitch estimate, + this is a form of pitch tracking */ + + if ((prev_f0_bin > bmin) && (prev_f0_bin < bmax)) + thresh = CNLP*0.5*gmax; + else + thresh = CNLP*gmax; + + lmax = 0; + lmax_bin = bmin; + for (b=bmin; b<=bmax; b++) /* look for maximum in interval */ + if (Fw[b].real() > lmax) + { + lmax = Fw[b].real(); + lmax_bin = b; + } + + if (lmax > thresh) + if ((lmax > Fw[lmax_bin-1].real()) && (lmax > Fw[lmax_bin+1].real())) + { + cmax_bin = lmax_bin; + } + + mult++; + } + + best_f0 = (float)cmax_bin*SAMPLE_RATE/(PE_FFT_SIZE*DEC); + + return best_f0; +} + +/*---------------------------------------------------------------------------*\ + + FUNCTION....: fdmdv_16_to_8() + AUTHOR......: David Rowe + DATE CREATED: 9 May 2012 + + Changes the sample rate of a signal from 16 to 8 kHz. + + n is the number of samples at the 8 kHz rate, there are FDMDV_OS*n + samples at the 48 kHz rate. As above however a memory of + FDMDV_OS_TAPS samples is reqd for in16k[] (see t16_8.c unit test as example). + + Low pass filter the 16 kHz signal at 4 kHz using the same filter as + the upsampler, then just output every FDMDV_OS-th filtered sample. + + Note: this function copied from fdmdv.c, included in nlp.c as a convenience + to avoid linking with another source file. + +\*---------------------------------------------------------------------------*/ + +void Cnlp::fdmdv_16_to_8(float out8k[], float in16k[], int n) +{ + float acc; + int i,j,k; + + for(i=0, k=0; k *inout) +{ + std::complex in[512]; + // decide whether to use the local stack based buffer for in + // or to allow kiss_fft to allocate RAM + // second part is just to play safe since first method + // is much faster and uses less RAM + if (cfg.nfft <= 512) + { + memcpy(in, inout, cfg.nfft*sizeof(std::complex)); + kiss.fft(cfg, in, inout); + } + else + { + kiss.fft(cfg, inout, inout); + } +} diff --git a/codec2/nlp.h b/codec2/nlp.h new file mode 100644 index 0000000..e531a90 --- /dev/null +++ b/codec2/nlp.h @@ -0,0 +1,87 @@ +/*---------------------------------------------------------------------------*\ + + FILE........: nlp.c + AUTHOR......: David Rowe + DATE CREATED: 23/3/93 + + Non Linear Pitch (NLP) estimation functions. + +\*---------------------------------------------------------------------------*/ + +/* + Copyright (C) 2009 David Rowe + + All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 2.1, as + published by the Free Software Foundation. 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. + + You should have received a copy of the GNU Lesser General Public License + along with this program; if not, see . +*/ + +#ifndef __NLP__ +#define __NLP__ + +#include +#include + +#include "defines.h" + +/*---------------------------------------------------------------------------*\ + + DEFINES + +\*---------------------------------------------------------------------------*/ + +#define PMAX_M 320 /* maximum NLP analysis window size */ +#define COEFF 0.95 /* notch filter parameter */ +#define PE_FFT_SIZE 512 /* DFT size for pitch estimation */ +#define DEC 5 /* decimation factor */ +#define SAMPLE_RATE 8000 +#define PI 3.141592654 /* mathematical constant */ +#define T 0.1 /* threshold for local minima candidate */ +#define F0_MAX 500 +#define CNLP 0.3 /* post processor constant */ +#define NLP_NTAP 48 /* Decimation LPF order */ + +/* 8 to 16 kHz sample rate conversion */ + +#define FDMDV_OS 2 /* oversampling rate */ +#define FDMDV_OS_TAPS_16K 48 /* number of OS filter taps at 16kHz */ +#define FDMDV_OS_TAPS_8K (FDMDV_OS_TAPS_16K/FDMDV_OS) /* number of OS filter taps at 8kHz */ + + +using NLP = struct nlp_tag +{ + int Fs; /* sample rate in Hz */ + int m; + float w[PMAX_M/DEC]; /* DFT window */ + float sq[PMAX_M]; /* squared speech samples */ + float mem_x,mem_y; /* memory for notch filter */ + float mem_fir[NLP_NTAP]; /* decimation FIR filter memory */ + FFT_STATE fft_cfg; /* kiss FFT config */ + std::vector Sn16k; /* Fs=16kHz input speech vector */ +}; + + +class Cnlp { +public: + void nlp_create(C2CONST *c2const); + void nlp_destroy(); + float nlp(float Sn[], int n, float *pitch_samples, float *prev_f0); + void codec2_fft_inplace(FFT_STATE &cfg, std::complex *inout); + +private: + float post_process_sub_multiples(std::complex Fw[], int pmax, float gmax, int gmax_bin, float *prev_f0); + void fdmdv_16_to_8(float out8k[], float in16k[], int n); + + NLP snlp; +}; + +#endif diff --git a/codec2/pack.cpp b/codec2/pack.cpp new file mode 100644 index 0000000..8382f95 --- /dev/null +++ b/codec2/pack.cpp @@ -0,0 +1,139 @@ +/* + Copyright (C) 2010 Perens LLC + + All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 2.1, as + published by the Free Software Foundation. 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. + + You should have received a copy of the GNU Lesser General Public License + along with this program; if not, see . +*/ + +#include "defines.h" +#include "quantise.h" +#include + +/* Compile-time constants */ +/* Size of unsigned char in bits. Assumes 8 bits-per-char. */ +static const unsigned int WordSize = 8; + +/* Mask to pick the bit component out of bitIndex. */ +static const unsigned int IndexMask = 0x7; + +/* Used to pick the word component out of bitIndex. */ +static const unsigned int ShiftRight = 3; + +/** Pack a bit field into a bit string, encoding the field in Gray code. + * + * The output is an array of unsigned char data. The fields are efficiently + * packed into the bit string. The Gray coding is a naive attempt to reduce + * the effect of single-bit errors, we expect to do a better job as the + * codec develops. + * + * This code would be simpler if it just set one bit at a time in the string, + * but would hit the same cache line more often. I'm not sure the complexity + * gains us anything here. + * + * Although field is currently of int type rather than unsigned for + * compatibility with the rest of the code, indices are always expected to + * be >= 0. + */ +void CQuantize::pack( + unsigned char *bitArray, /* The output bit string. */ + unsigned int *bitIndex, /* Index into the string in BITS, not bytes.*/ + int field, /* The bit field to be packed. */ + unsigned int fieldWidth /* Width of the field in BITS, not bytes. */ +) +{ + pack_natural_or_gray(bitArray, bitIndex, field, fieldWidth, 1); +} + +void CQuantize::pack_natural_or_gray( + unsigned char *bitArray, /* The output bit string. */ + unsigned int *bitIndex, /* Index into the string in BITS, not bytes.*/ + int field, /* The bit field to be packed. */ + unsigned int fieldWidth, /* Width of the field in BITS, not bytes. */ + unsigned int gray /* non-zero for gray coding */ +) +{ + if (gray) + { + /* Convert the field to Gray code */ + field = (field >> 1) ^ field; + } + + do + { + unsigned int bI = *bitIndex; + unsigned int bitsLeft = WordSize - (bI & IndexMask); + unsigned int sliceWidth = bitsLeft < fieldWidth ? bitsLeft : fieldWidth; + unsigned int wordIndex = bI >> ShiftRight; + + bitArray[wordIndex] |= ((unsigned char)((field >> (fieldWidth - sliceWidth)) << (bitsLeft - sliceWidth))); + + *bitIndex = bI + sliceWidth; + fieldWidth -= sliceWidth; + } + while ( fieldWidth != 0 ); +} + +/** Unpack a field from a bit string, converting from Gray code to binary. + * + */ +int CQuantize::unpack( + const unsigned char *bitArray, /* The input bit string. */ + unsigned int *bitIndex, /* Index into the string in BITS, not bytes.*/ + unsigned int fieldWidth/* Width of the field in BITS, not bytes. */ +) +{ + return unpack_natural_or_gray(bitArray, bitIndex, fieldWidth, 1); +} + +/** Unpack a field from a bit string, to binary, optionally using + * natural or Gray code. + * + */ +int CQuantize::unpack_natural_or_gray( + const unsigned char *bitArray, /* The input bit string. */ + unsigned int *bitIndex, /* Index into the string in BITS, not bytes.*/ + unsigned int fieldWidth,/* Width of the field in BITS, not bytes. */ + unsigned int gray /* non-zero for Gray coding */ +) +{ + unsigned int field = 0; + unsigned int t; + + do + { + unsigned int bI = *bitIndex; + unsigned int bitsLeft = WordSize - (bI & IndexMask); + unsigned int sliceWidth = bitsLeft < fieldWidth ? bitsLeft : fieldWidth; + + field |= (((bitArray[bI >> ShiftRight] >> (bitsLeft - sliceWidth)) & ((1 << sliceWidth) - 1)) << (fieldWidth - sliceWidth)); + + *bitIndex = bI + sliceWidth; + fieldWidth -= sliceWidth; + } + while ( fieldWidth != 0 ); + + if (gray) + { + /* Convert from Gray code to binary. Works for maximum 8-bit fields. */ + t = field ^ (field >> 8); + t ^= (t >> 4); + t ^= (t >> 2); + t ^= (t >> 1); + } + else + { + t = field; + } + + return t; +} diff --git a/codec2/qbase.cpp b/codec2/qbase.cpp new file mode 100644 index 0000000..a94ef46 --- /dev/null +++ b/codec2/qbase.cpp @@ -0,0 +1,247 @@ +#include +#include + +#include "qbase.h" + +/*---------------------------------------------------------------------------*\ + + quantise + + Quantises vec by choosing the nearest vector in codebook cb, and + returns the vector index. The squared error of the quantised vector + is added to se. + +\*---------------------------------------------------------------------------*/ + +long CQbase::quantise(const float *cb, float vec[], float w[], int k, int m, float *se) +/* float cb[][K]; current VQ codebook */ +/* float vec[]; vector to quantise */ +/* float w[]; weighting vector */ +/* int k; dimension of vectors */ +/* int m; size of codebook */ +/* float *se; accumulated squared error */ +{ + float e; /* current error */ + long besti; /* best index so far */ + float beste; /* best error so far */ + long j; + int i; + float diff; + + besti = 0; + beste = 1E32; + for(j=0; jWo/PI)*4000.0/50.0)/log10f(2); + x[1] = 10.0*log10f(1e-4 + e); + + compute_weights2(x, xq, w); + for (i=0; iWo_min; + float Wo_max = c2const->Wo_max; + + for (i=0; iWo = powf(2.0, xq[0])*(PI*50.0)/4000.0; + + /* bit errors can make us go out of range leading to all sorts of + probs like seg faults */ + + if (model->Wo > Wo_max) model->Wo = Wo_max; + if (model->Wo < Wo_min) model->Wo = Wo_min; + + model->L = PI/model->Wo; /* if we quantise Wo re-compute L */ + + *e = exp10f(xq[1]/10.0); +} + +void CQbase::compute_weights2(const float *x, const float *xp, float *w) +{ + w[0] = 30; + w[1] = 1; + if (x[1]<0) + { + w[0] *= .6; + w[1] *= .3; + } + if (x[1]<-10) + { + w[0] *= .3; + w[1] *= .3; + } + /* Higher weight if pitch is stable */ + if (fabsf(x[0]-xp[0])<.2) + { + w[0] *= 2; + w[1] *= 1.5; + } + else if (fabsf(x[0]-xp[0])>.5) /* Lower if not stable */ + { + w[0] *= .5; + } + + /* Lower weight for low energy */ + if (x[1] < xp[1]-10) + { + w[1] *= .5; + } + if (x[1] < xp[1]-20) + { + w[1] *= .5; + } + + //w[0] = 30; + //w[1] = 1; + + /* Square the weights because it's applied on the squared error */ + w[0] *= w[0]; + w[1] *= w[1]; + +} + +int CQbase::find_nearest_weighted(const float *codebook, int nb_entries, float *x, const float *w, int ndim) +{ + int i, j; + float min_dist = 1e15; + int nearest = 0; + + for (i=0; iWo_min; + float Wo_max = c2const->Wo_max; + float norm; + + norm = (log10f(Wo) - log10f(Wo_min))/(log10f(Wo_max) - log10f(Wo_min)); + index = floorf(Wo_levels * norm + 0.5); + if (index < 0 ) index = 0; + if (index > (Wo_levels-1)) index = Wo_levels-1; + + return index; +} + +/*---------------------------------------------------------------------------*\ + + FUNCTION....: decode_log_Wo() + AUTHOR......: David Rowe + DATE CREATED: 22/8/2010 + + Decodes Wo using a WO_LEVELS quantiser in the log domain. + +\*---------------------------------------------------------------------------*/ + +float CQbase::decode_log_Wo(C2CONST *c2const, int index, int bits) +{ + float Wo_min = c2const->Wo_min; + float Wo_max = c2const->Wo_max; + float step; + float Wo; + int Wo_levels = 1<. + +*/ + +#include +#include +#include +#include +#include +#include + +#include "defines.h" +#include "quantise.h" +#include "lpc.h" +#include "kiss_fft.h" + +extern CKissFFT kiss; + +#define LSP_DELTA1 0.01 /* grid spacing for LSP root searches */ + +/*---------------------------------------------------------------------------*\ + + FUNCTIONS + +\*---------------------------------------------------------------------------*/ + +int CQuantize::lsp_bits(int i) +{ + return lsp_cb[i].log2m; +} + +int CQuantize::lspd_bits(int i) +{ + return lsp_cbd[i].log2m; +} + + + +/*---------------------------------------------------------------------------*\ + + encode_lspds_scalar() + + Scalar/VQ LSP difference quantiser. + +\*---------------------------------------------------------------------------*/ + +void CQuantize::encode_lspds_scalar(int indexes[], float lsp[], int order) +{ + int i,k,m; + float lsp_hz[order]; + float lsp__hz[order]; + float dlsp[order]; + float dlsp_[order]; + float wt[order]; + const float *cb; + float se; + + for(i=0; i Ww[FFT_ENC/2+1]; /* weighting spectrum */ + float Rw[FFT_ENC/2+1]; /* R = WA */ + float e_before, e_after, gain; + float Pfw; + float max_Rw, min_Rw; + float coeff; + + /* Determine weighting filter spectrum W(exp(jw)) ---------------*/ + + for(i=0; i max_Rw) + max_Rw = Rw[i]; + if (Rw[i] < min_Rw) + min_Rw = Rw[i]; + + } + + /* create post filter mag spectrum and apply ------------------*/ + + /* measure energy before post filtering */ + + e_before = 1E-4; + for(i=0; i Aw[] /* output power spectrum */ +) +{ + int i,m; /* loop variables */ + int am,bm; /* limits of current band */ + float r; /* no. rads/bin */ + float Em; /* energy in band */ + float Am; /* spectral amplitude sample */ + float signal, noise; + + r = TWO_PI/(FFT_ENC); + + /* Determine DFT of A(exp(jw)) --------------------------------------------*/ + { + float a[FFT_ENC]; /* input to FFT for power spectrum */ + + for(i=0; iL; m++) + { + am = (int)((m - 0.5)*model->Wo/r + 0.5); + bm = (int)((m + 0.5)*model->Wo/r + 0.5); + + // FIXME: With arm_rfft_fast_f32 we have to use this + // otherwise sometimes a to high bm is calculated + // which causes trouble later in the calculation + // chain + // it seems for some reason model->Wo is calculated somewhat too high + if (bm>FFT_ENC/2) + { + bm = FFT_ENC/2; + } + Em = 0.0; + + for(i=am; iA[m]*model->A[m]; + noise += (model->A[m] - Am)*(model->A[m] - Am); + + /* This code significantly improves perf of LPC model, in + particular when combined with phase0. The LPC spectrum tends + to track just under the peaks of the spectral envelope, and + just above nulls. This algorithm does the reverse to + compensate - raising the amplitudes of spectral peaks, while + attenuating the null. This enhances the formants, and + supresses the energy between formants. */ + + if (sim_pf) + { + if (Am > model->A[m]) + Am *= 0.7; + if (Am < model->A[m]) + Am *= 1.4; + } + model->A[m] = Am; + } + *snr = 10.0*log10f(signal/noise); +} + +/*---------------------------------------------------------------------------*\ + + FUNCTION....: encode_Wo() + AUTHOR......: David Rowe + DATE CREATED: 22/8/2010 + + Encodes Wo using a WO_LEVELS quantiser. + +\*---------------------------------------------------------------------------*/ + +int CQuantize::encode_Wo(C2CONST *c2const, float Wo, int bits) +{ + int index, Wo_levels = 1<Wo_min; + float Wo_max = c2const->Wo_max; + float norm; + + norm = (Wo - Wo_min)/(Wo_max - Wo_min); + index = floorf(Wo_levels * norm + 0.5); + if (index < 0 ) index = 0; + if (index > (Wo_levels-1)) index = Wo_levels-1; + + return index; +} + +/*---------------------------------------------------------------------------*\ + + FUNCTION....: decode_Wo() + AUTHOR......: David Rowe + DATE CREATED: 22/8/2010 + + Decodes Wo using a WO_LEVELS quantiser. + +\*---------------------------------------------------------------------------*/ + +float CQuantize::decode_Wo(C2CONST *c2const, int index, int bits) +{ + float Wo_min = c2const->Wo_min; + float Wo_max = c2const->Wo_max; + float step; + float Wo; + int Wo_levels = 1<Wo < (PI*150.0/4000)) + { + model->A[1] *= 0.032; + } +} + +/*---------------------------------------------------------------------------*\ + + FUNCTION....: encode_energy() + AUTHOR......: David Rowe + DATE CREATED: 22/8/2010 + + Encodes LPC energy using an E_LEVELS quantiser. + +\*---------------------------------------------------------------------------*/ + +int CQuantize::encode_energy(float e, int bits) +{ + int index, e_levels = 1< (e_levels-1)) index = e_levels-1; + + return index; +} + +/*---------------------------------------------------------------------------*\ + + FUNCTION....: decode_energy() + AUTHOR......: David Rowe + DATE CREATED: 22/8/2010 + + Decodes energy using a E_LEVELS quantiser. + +\*---------------------------------------------------------------------------*/ + +float CQuantize::decode_energy(int index, int bits) +{ + float e_min = E_MIN_DB; + float e_max = E_MAX_DB; + float step; + float e; + int e_levels = 1<= -1.0)) + { + xr = xl - delta ; /* interval spacing */ + psumr = cheb_poly_eva(pt,xr,order);/* poly(xl-delta_x) */ + temp_psumr = psumr; + temp_xr = xr; + + /* if no sign change increment xr and re-evaluate + poly(xr). Repeat til sign change. if a sign change has + occurred the interval is bisected and then checked again + for a sign change which determines in which interval the + zero lies in. If there is no sign change between poly(xm) + and poly(xl) set interval between xm and xr else set + interval between xl and xr and repeat till root is located + within the specified limits */ + + if(((psumr*psuml)<0.0) || (psumr == 0.0)) + { + roots++; + + psumm=psuml; + for(k=0; k<=nb; k++) + { + xm = (xl+xr)/2; /* bisect the interval */ + psumm=cheb_poly_eva(pt,xm,order); + if(psumm*psuml>0.) + { + psuml=psumm; + xl=xm; + } + else + { + psumr=psumm; + xr=xm; + } + } + + /* once zero is found, reset initial interval to xr */ + freq[j] = (xm); + xl = xm; + flag = 0; /* reset flag for next search */ + } + else + { + psuml=temp_psumr; + xl=temp_xr; + } + } + } + + /* convert from x domain to radians */ + + for(i=0; i. +*/ + +#ifndef __QUANTISE__ +#define __QUANTISE__ + +#include + +#include "qbase.h" + +class CQuantize : public CQbase { +public: + void aks_to_M2(FFTR_STATE *fftr_fwd_cfg, float ak[], int order, MODEL *model, float E, float *snr, int sim_pf, int pf, int bass_boost, float beta, float gamma, std::complex Aw[]); + + int encode_Wo(C2CONST *c2const, float Wo, int bits); + float decode_Wo(C2CONST *c2const, int index, int bits); + void encode_lsps_scalar(int indexes[], float lsp[], int order); + void decode_lsps_scalar(float lsp[], int indexes[], int order); + void encode_lspds_scalar(int indexes[], float lsp[], int order); + void decode_lspds_scalar(float lsp[], int indexes[], int order); + + int encode_energy(float e, int bits); + float decode_energy(int index, int bits); + + void pack(unsigned char * bits, unsigned int *nbit, int index, unsigned int index_bits); + void pack_natural_or_gray(unsigned char * bits, unsigned int *nbit, int index, unsigned int index_bits, unsigned int gray); + int unpack(const unsigned char * bits, unsigned int *nbit, unsigned int index_bits); + int unpack_natural_or_gray(const unsigned char * bits, unsigned int *nbit, unsigned int index_bits, unsigned int gray); + + int lsp_bits(int i); + int lspd_bits(int i); + + void apply_lpc_correction(MODEL *model); + float speech_to_uq_lsps(float lsp[], float ak[], float Sn[], float w[], int m_pitch, int order); + int check_lsp_order(float lsp[], int lpc_order); + void bw_expand_lsps(float lsp[], int order, float min_sep_low, float min_sep_high); + +private: + void compute_weights(const float *x, float *w, int ndim); + int find_nearest(const float *codebook, int nb_entries, float *x, int ndim); + void lpc_post_filter(FFTR_STATE *fftr_fwd_cfg, float Pw[], float ak[], int order, float beta, float gamma, int bass_boost, float E); + int lpc_to_lsp (float *a, int lpcrdr, float *freq, int nb, float delta); + float cheb_poly_eva(float *coef,float x,int order); +}; + +#endif diff --git a/config/tcd.ini b/config/tcd.ini new file mode 100644 index 0000000..5758c86 --- /dev/null +++ b/config/tcd.ini @@ -0,0 +1,20 @@ +# Transcoder Ini file +# +# this is a comment + +Port = 10100 +ServerAddress = 127.0.0.1 +# VERY IMPORTANT: This need to be idential to the same line in [Transcder] section of the urfd ini file! +# This will either be a single module (for DVSI-3000), or up to three modules (for DVSI-3003). +Modules = A + + +# All gain values are in dB. +# Gain values are limited to -24 to +24. Typical values will usually be less. +# Below are suggested values. +DStarGainIn = 16 +DStarGainOut = -16 +DmrYsfGainIn = -3 +DmrYsfGainOut = 0 +UsrpTxGain = 12 +UsrpRxGain = -6 diff --git a/config/tcd.mk b/config/tcd.mk new file mode 100644 index 0000000..49c89c6 --- /dev/null +++ b/config/tcd.mk @@ -0,0 +1,6 @@ +# This is where the executable will be installed `make install` +BINDIR = /usr/local/bin + +# set to true to build a transcoder that supports gdb +debug = false + diff --git a/config/tcd.service b/config/tcd.service new file mode 100644 index 0000000..2248f59 --- /dev/null +++ b/config/tcd.service @@ -0,0 +1,12 @@ +[Unit] +Description=tcd +Requires=network.target +After=systemd-user-session.service network.target + +[Service] +Type=simple +ExecStart=/usr/local/bin/tcd /PATH_TO_INI_FILE +Restart=always + +[Install] +WantedBy=multi-user.target diff --git a/mbe/ambe3600x2400.cpp b/mbe/ambe3600x2400.cpp new file mode 100644 index 0000000..3d8ea37 --- /dev/null +++ b/mbe/ambe3600x2400.cpp @@ -0,0 +1,756 @@ +/* + * Copyright (C) 2010 mbelib Author + * GPG Key ID: 0xEA5EFE2C (9E7A 5527 9CDC EBF7 BF1B D772 4F98 E863 EA5E FE2C) + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include + +#include "mbelib.h" +#include "ambe3600x2400_const.h" +#include "dstar_pitch.h" + +void +mbe_dumpAmbe2400Data (char *ambe_d) +{ + + int i; + char *ambe; + + ambe = ambe_d; + for (i = 0; i < 49; i++) + { + printf ("%i", *ambe); + ambe++; + } + printf (" "); +} + +void +mbe_dumpAmbe3600x2400Frame (char ambe_fr[4][24]) +{ + + int j; + + // c0 + printf ("ambe_fr c0: "); + for (j = 23; j >= 0; j--) + { + printf ("%i", ambe_fr[0][j]); + } + printf (" "); + // c1 + printf ("ambe_fr c1: "); + for (j = 22; j >= 0; j--) + { + printf ("%i", ambe_fr[1][j]); + } + printf (" "); + // c2 + printf ("ambe_fr c2: "); + for (j = 10; j >= 0; j--) + { + printf ("%i", ambe_fr[2][j]); + } + printf (" "); + // c3 + printf ("ambe_fr c3: "); + for (j = 13; j >= 0; j--) + { + printf ("%i", ambe_fr[3][j]); + } + printf (" "); +} + +int +mbe_eccAmbe3600x2400C0 (char ambe_fr[4][24]) +{ + + int j, errs; + char in[23], out[23]; + + for (j = 0; j < 23; j++) + { + in[j] = ambe_fr[0][j + 1]; + } + errs = mbe_golay2312 (in, out); + // ambe_fr[0][0] should be the C0 golay24 parity bit. + // TODO: actually test that here... + for (j = 0; j < 23; j++) + { + ambe_fr[0][j + 1] = out[j]; + } + + return (errs); +} + +int +mbe_eccAmbe3600x2400Data (char ambe_fr[4][24], char *ambe_d) +{ + + int j, errs; + char *ambe, gin[24], gout[24]; + + ambe = ambe_d; + // just copy C0 + for (j = 23; j > 11; j--) + { + *ambe = ambe_fr[0][j]; + ambe++; + } + + // ecc and copy C1 + for (j = 0; j < 23; j++) + { + gin[j] = ambe_fr[1][j]; + } + errs = mbe_golay2312 (gin, gout); + for (j = 22; j > 10; j--) + { + *ambe = gout[j]; + ambe++; + } + + // just copy C2 + for (j = 10; j >= 0; j--) + { + *ambe = ambe_fr[2][j]; + ambe++; + } + + // just copy C3 + for (j = 13; j >= 0; j--) + { + *ambe = ambe_fr[3][j]; + ambe++; + } + + return (errs); +} + +int +mbe_decodeAmbe2400Parms (char *ambe_d, mbe_parms * cur_mp, mbe_parms * prev_mp) +{ + + int ji, i, j, k, l, L, m, am, ak; + int intkl[57]; + int b0, b1, b2, b3, b4, b5, b6, b7, b8; + float f0, Cik[5][18], flokl[57], deltal[57]; + float Sum42, Sum43, Tl[57], Gm[9], Ri[9], sum, c1, c2; + int silence; + int Ji[5], jl; + float deltaGamma, BigGamma; + float unvc, rconst; + + silence = 0; + +#ifdef AMBE_DEBUG + printf ("\n"); +#endif + + // copy repeat from prev_mp + cur_mp->repeat = prev_mp->repeat; + + // check if frame is tone or other; this matches section 7.2 on the P25 Half rate vocoder annex doc + b0 = 0; + b0 |= ambe_d[0]<<6; + b0 |= ambe_d[1]<<5; + b0 |= ambe_d[2]<<4; + b0 |= ambe_d[3]<<3; + b0 |= ambe_d[4]<<2; + b0 |= ambe_d[5]<<1; + b0 |= ambe_d[48]; + + if ((b0&0x7E) == 0x7E) // frame is tone + { + // find tone index + // Cx# 0000000000001111111111112222222222233333333333333 + // + // IDX 0000000000111111111122222222223333333333444444444 + // idx 0123456789012345678901234567890123456789012345678 + // exm 1111110101001110100000001000000000000000001100000 : t=0111100 + // ex2 1111110110101110100000000000000000000000000000000 : t=1100010 + // ex3 1111110010101110110000001000000000000000000110000 : t=0000110 + // tt1 1111110010011110100000001000000000000000000101000 : t=0000101 + // tt3 1111110010011110000000001000000000000000000101000 + // ton HHHHHHDEF410======......P.................32==... + // vol 765430 21 + //DEF indexes the following tables for tone bits 5-7 + int t7tab[8] = {1,0,0,0,0,1,1,1}; + int t6tab[8] = {0,0,0,1,1,1,1,0}; + int t5tab[8] = {0,0,1,0,1,1,0,1}; + // V V V V V G G G V = verified, G = guessed (and unused by all normal tone indices) + b1 = 0; + b1 |= t7tab[((ambe_d[6]<<2)|(ambe_d[7]<<1)|ambe_d[8])]<<7; //t7 128 + b1 |= t6tab[((ambe_d[6]<<2)|(ambe_d[7]<<1)|ambe_d[8])]<<6; //t6 64 + b1 |= t5tab[((ambe_d[6]<<2)|(ambe_d[7]<<1)|ambe_d[8])]<<5; //t5 32 + b1 |= ambe_d[9]<<4; //t4 16 e verified + b1 |= ambe_d[42]<<3; //t3 8 d verified + b1 |= ambe_d[43]<<2; //t2 4 c verified + b1 |= ambe_d[10]<<1; //t1 2 b verified + b1 |= ambe_d[11]; //t0 1 a verified + + b2 = 0; + b2 |= ambe_d[12]<<7; //v7 128 h verified + b2 |= ambe_d[13]<<6; //v6 64 g verified + b2 |= ambe_d[14]<<5; //v5 32 f verified + b2 |= ambe_d[15]<<4; //v4 16 e guess based on data + b2 |= ambe_d[16]<<3; //v3 8 d guess based on data + b2 |= ambe_d[44]<<2; //v2 4 c guess based on data + b2 |= ambe_d[45]<<1; //v1 2 b guess based on data + b2 |= ambe_d[17]; //v0 1 a guess based on data + // the order of the last 3 bits may really be 17,44,45 not 44,45,17 as above + + fprintf(stderr,"Tone volume: %d; ", b2); + if (b1 < 5) + { + fprintf(stderr, "index: %d, was <5, invalid!\n", b1); + silence = 1; + } + else if ((b1 >= 5) && (b1 <= 122)) + { + fprintf(stderr, "index: %d, Single tone hz: %f\n", b1, (float)b1*31.25); + } + else if ((b1 > 122) && (b1 < 128)) + { + fprintf(stderr, "index: %d, was >122 and <128, invalid!\n", b1); + silence = 1; + } + else if ((b1 >= 128) && (b1 <= 163)) + { + fprintf(stderr, "index: %d, Dual tone\n", b1); + // note: dual tone index is different on ambe(dstar) and ambe2+ + } + else + { + fprintf(stderr, "index: %d, was >163, invalid!\n", b1); + silence = 1; + } + + if(silence == 1) + { +#ifdef AMBE_DEBUG + printf ("Silence Frame\n"); +#endif + cur_mp->w0 = ((float) 2 * M_PI) / (float) 32; + f0 = (float) 1 / (float) 32; + L = 14; + cur_mp->L = 14; + for (l = 1; l <= L; l++) + { + cur_mp->Vl[l] = 0; + } + } +#ifdef AMBE_DEBUG + printf ("Tone Frame\n"); +#endif + return (3); + } + //fprintf(stderr,"Voice Frame, Pitch = %f\n", powf(2, ((float)b0+195.626)/-46.368)*8000); // was 45.368 + //fprintf(stderr,"Voice Frame, rawPitch = %02d, Pitch = %f\n", b0, powf(2, ((-1*(float)(17661/((int)1<<12))) - (2.1336e-2 * ((float)b0+0.5))))*8000); + //fprintf(stderr,"Voice Frame, Pitch = %f, ", powf(2, (-4.311767578125 - (2.1336e-2 * ((float)b0+0.5))))*8000); + + // decode fundamental frequency w0 from b0 is already done + + if (silence == 0) + { + // w0 from specification document + //f0 = AmbeW0table[b0]; + //cur_mp->w0 = f0 * (float) 2 *M_PI; + // w0 from patent filings + //f0 = powf (2, ((float) b0 + (float) 195.626) / -(float) 46.368); // was 45.368 + f0 = powf(2, -DSTAR_F0_C0 - DSTAR_F0_C1 * ((float)b0 + 0.5f)); + cur_mp->w0 = f0 * (float) 2 *M_PI; + } + + unvc = (float) 0.2046 / sqrtf (cur_mp->w0); + //unvc = (float) 1; + //unvc = (float) 0.2046 / sqrtf (f0); + + // decode L + L = 0; + if (silence == 0) + { + // L from specification document + // lookup L in tabl3 + L = DSTAR_L(b0); // QSO One: the chip-measured harmonic count (dstar_pitch.h 3); was AmbePlusLtable[b0] + // L formula from patent filings + //L=(int)((float)0.4627 / f0); + cur_mp->L = L; + } + + // decode V/UV parameters + // load b1 from ambe_d + //TODO: use correct table (i.e. 0x0000 0x0005 0x0050 0x0055 etc) + b1 = 0; + b1 |= ambe_d[38]<<3; + b1 |= ambe_d[39]<<2; + b1 |= ambe_d[40]<<1; + b1 |= ambe_d[41]; + //fprintf(stderr,"V/UV = %d, ", b1); + for (l = 1; l <= L; l++) + { + // jl from specification document + jl = (int) ((float) l * (float) 16.0 * f0); + // jl from patent filings? + //jl = (int)(((float)l * (float)16.0 * f0) + 0.25); + + if (silence == 0) + { + cur_mp->Vl[l] = AmbePlusVuv[b1][jl]; + } +#ifdef AMBE_DEBUG + printf ("jl[%i]:%i Vl[%i]:%i\n", l, jl, l, cur_mp->Vl[l]); +#endif + } +#ifdef AMBE_DEBUG + printf ("\nb0:%i w0:%f L:%i b1:%i\n", b0, cur_mp->w0, L, b1); +#endif + + // decode gain vector + // load b2 from ambe_d + b2 = 0; + b2 |= ambe_d[6]<<5; + b2 |= ambe_d[7]<<4; + b2 |= ambe_d[8]<<3; + b2 |= ambe_d[9]<<2; + b2 |= ambe_d[42]<<1; + b2 |= ambe_d[43]; + //fprintf(stderr,"Gain = %d,\n", b2); + deltaGamma = AmbePlusDg[b2]; + cur_mp->gamma = deltaGamma + ((float) 0.5 * prev_mp->gamma); +#ifdef AMBE_DEBUG + printf ("b2: %i, deltaGamma: %f gamma: %f gamma-1: %f\n", b2, deltaGamma, cur_mp->gamma, prev_mp->gamma); +#endif + + + // decode PRBA vectors + Gm[1] = 0; + + // load b3 from ambe_d + b3 = 0; + b3 |= ambe_d[10]<<8; + b3 |= ambe_d[11]<<7; + b3 |= ambe_d[12]<<6; + b3 |= ambe_d[13]<<5; + b3 |= ambe_d[14]<<4; + b3 |= ambe_d[15]<<3; + b3 |= ambe_d[16]<<2; + b3 |= ambe_d[44]<<1; + b3 |= ambe_d[45]; + Gm[2] = AmbePlusPRBA24[b3][0]; + Gm[3] = AmbePlusPRBA24[b3][1]; + Gm[4] = AmbePlusPRBA24[b3][2]; + + // load b4 from ambe_d + b4 = 0; + b4 |= ambe_d[17]<<6; + b4 |= ambe_d[18]<<5; + b4 |= ambe_d[19]<<4; + b4 |= ambe_d[20]<<3; + b4 |= ambe_d[21]<<2; + b4 |= ambe_d[46]<<1; + b4 |= ambe_d[47]; + Gm[5] = AmbePlusPRBA58[b4][0]; + Gm[6] = AmbePlusPRBA58[b4][1]; + Gm[7] = AmbePlusPRBA58[b4][2]; + Gm[8] = AmbePlusPRBA58[b4][3]; + +#ifdef AMBE_DEBUG + printf ("b3: %i Gm[2]: %f Gm[3]: %f Gm[4]: %f b4: %i Gm[5]: %f Gm[6]: %f Gm[7]: %f Gm[8]: %f\n", b3, Gm[2], Gm[3], Gm[4], b4, Gm[5], Gm[6], Gm[7], Gm[8]); +#endif + + // compute Ri + for (i = 1; i <= 8; i++) + { + sum = 0; + for (m = 1; m <= 8; m++) + { + if (m == 1) + { + am = 1; + } + else + { + am = 2; + } + sum = sum + ((float) am * Gm[m] * cosf ((M_PI * (float) (m - 1) * ((float) i - (float) 0.5)) / (float) 8)); + } + Ri[i] = sum; +#ifdef AMBE_DEBUG + printf ("R%i: %f ", i, Ri[i]); +#endif + } +#ifdef AMBE_DEBUG + printf ("\n"); +#endif + + // generate first to elements of each Ci,k block from PRBA vector + rconst = ((float) 1 / ((float) 2 * M_SQRT2)); + Cik[1][1] = (float) 0.5 *(Ri[1] + Ri[2]); + Cik[1][2] = rconst * (Ri[1] - Ri[2]); + Cik[2][1] = (float) 0.5 *(Ri[3] + Ri[4]); + Cik[2][2] = rconst * (Ri[3] - Ri[4]); + Cik[3][1] = (float) 0.5 *(Ri[5] + Ri[6]); + Cik[3][2] = rconst * (Ri[5] - Ri[6]); + Cik[4][1] = (float) 0.5 *(Ri[7] + Ri[8]); + Cik[4][2] = rconst * (Ri[7] - Ri[8]); + + // decode HOC + + // load b5 from ambe_d + b5 = 0; + b5 |= ambe_d[22]<<3; + b5 |= ambe_d[23]<<2; + b5 |= ambe_d[25]<<1; + b5 |= ambe_d[26]; + + // load b6 from ambe_d + b6 = 0; + b6 |= ambe_d[27]<<3; + b6 |= ambe_d[28]<<2; + b6 |= ambe_d[29]<<1; + b6 |= ambe_d[30]; + + // load b7 from ambe_d + b7 = 0; + b7 |= ambe_d[31]<<3; + b7 |= ambe_d[32]<<2; + b7 |= ambe_d[33]<<1; + b7 |= ambe_d[34]; + + // load b8 from ambe_d + b8 = 0; + b8 |= ambe_d[35]<<3; + b8 |= ambe_d[36]<<2; + b8 |= ambe_d[37]<<1; + //b8 |= 0; // least significant bit of hoc3 unused here, and according to the patent is forced to 0 when not used + + // lookup Ji + Ji[1] = AmbePlusLmprbl[L][0]; + Ji[2] = AmbePlusLmprbl[L][1]; + Ji[3] = AmbePlusLmprbl[L][2]; + Ji[4] = AmbePlusLmprbl[L][3]; +#ifdef AMBE_DEBUG + printf ("Ji[1]: %i Ji[2]: %i Ji[3]: %i Ji[4]: %i\n", Ji[1], Ji[2], Ji[3], Ji[4]); + printf ("b5: %i b6: %i b7: %i b8: %i\n", b5, b6, b7, b8); +#endif + + // Load Ci,k with the values from the HOC tables + // there appear to be a couple typos in eq. 37 so we will just do what makes sense + // (3 <= k <= Ji and k<=6) + for (k = 3; k <= Ji[1]; k++) + { + if (k > 6) + { + Cik[1][k] = 0; + } + else + { + Cik[1][k] = AmbePlusHOCb5[b5][k - 3]; +#ifdef AMBE_DEBUG + printf ("C1,%i: %f ", k, Cik[1][k]); +#endif + } + } + for (k = 3; k <= Ji[2]; k++) + { + if (k > 6) + { + Cik[2][k] = 0; + } + else + { + Cik[2][k] = AmbePlusHOCb6[b6][k - 3]; +#ifdef AMBE_DEBUG + printf ("C2,%i: %f ", k, Cik[2][k]); +#endif + } + } + for (k = 3; k <= Ji[3]; k++) + { + if (k > 6) + { + Cik[3][k] = 0; + } + else + { + Cik[3][k] = AmbePlusHOCb7[b7][k - 3]; +#ifdef AMBE_DEBUG + printf ("C3,%i: %f ", k, Cik[3][k]); +#endif + } + } + for (k = 3; k <= Ji[4]; k++) + { + if (k > 6) + { + Cik[4][k] = 0; + } + else + { + Cik[4][k] = AmbePlusHOCb8[b8][k - 3]; +#ifdef AMBE_DEBUG + printf ("C4,%i: %f ", k, Cik[4][k]); +#endif + } + } +#ifdef AMBE_DEBUG + printf ("\n"); +#endif + + // inverse DCT each Ci,k to give ci,j (Tl) + l = 1; + for (i = 1; i <= 4; i++) + { + ji = Ji[i]; + for (j = 1; j <= ji; j++) + { + sum = 0; + for (k = 1; k <= ji; k++) + { + if (k == 1) + { + ak = 1; + } + else + { + ak = 2; + } +#ifdef AMBE_DEBUG + printf ("j: %i Cik[%i][%i]: %f ", j, i, k, Cik[i][k]); +#endif + sum = sum + ((float) ak * Cik[i][k] * cosf ((M_PI * (float) (k - 1) * ((float) j - (float) 0.5)) / (float) ji)); + } + Tl[l] = sum; +#ifdef AMBE_DEBUG + printf ("Tl[%i]: %f\n", l, Tl[l]); +#endif + l++; + } + } + + // determine log2Ml by applying ci,j to previous log2Ml + + // fix for when L > L(-1) + if (cur_mp->L > prev_mp->L) + { + for (l = (prev_mp->L) + 1; l <= cur_mp->L; l++) + { + prev_mp->Ml[l] = prev_mp->Ml[prev_mp->L]; + prev_mp->log2Ml[l] = prev_mp->log2Ml[prev_mp->L]; + } + } + prev_mp->log2Ml[0] = prev_mp->log2Ml[1]; + prev_mp->Ml[0] = prev_mp->Ml[1]; + + // Part 1 + Sum43 = 0; + for (l = 1; l <= cur_mp->L; l++) + { + + // eq. 40 + flokl[l] = ((float) prev_mp->L / (float) cur_mp->L) * (float) l; + intkl[l] = (int) (flokl[l]); +#ifdef AMBE_DEBUG + printf ("flok%i: %f, intk%i: %i ", l, flokl[l], l, intkl[l]); +#endif + // eq. 41 + deltal[l] = flokl[l] - (float) intkl[l]; +#ifdef AMBE_DEBUG + printf ("delta%i: %f ", l, deltal[l]); +#endif + // eq 43 + Sum43 = Sum43 + ((((float) 1 - deltal[l]) * prev_mp->log2Ml[intkl[l]]) + (deltal[l] * prev_mp->log2Ml[intkl[l] + 1])); + } + Sum43 = ((DSTAR_SPEC_PRED / (float) cur_mp->L) * Sum43); // QSO One: 0.8, measured on a real chip (dstar_pitch.h) +#ifdef AMBE_DEBUG + printf ("\n"); + printf ("Sum43: %f\n", Sum43); +#endif + + // Part 2 + Sum42 = 0; + for (l = 1; l <= cur_mp->L; l++) + { + Sum42 += Tl[l]; + } + Sum42 = Sum42 / (float) cur_mp->L; + BigGamma = cur_mp->gamma - ((float) 0.5 * (log ((float) cur_mp->L) / log ((float) 2))) - Sum42; + //BigGamma=cur_mp->gamma - ((float)0.5 * log((float)cur_mp->L)) - Sum42; + + // Part 3 + for (l = 1; l <= cur_mp->L; l++) + { + c1 = (DSTAR_SPEC_PRED * ((float) 1 - deltal[l]) * prev_mp->log2Ml[intkl[l]]); + c2 = (DSTAR_SPEC_PRED * deltal[l] * prev_mp->log2Ml[intkl[l] + 1]); + cur_mp->log2Ml[l] = Tl[l] + c1 + c2 - Sum43 + BigGamma; + // inverse log to generate spectral amplitudes + if (cur_mp->Vl[l] == 1) + { + cur_mp->Ml[l] = exp ((float) 0.693 * cur_mp->log2Ml[l]); + } + else + { + cur_mp->Ml[l] = unvc * exp ((float) 0.693 * cur_mp->log2Ml[l]); + } +#ifdef AMBE_DEBUG + printf ("flokl[%i]: %f, intkl[%i]: %i ", l, flokl[l], l, intkl[l]); + printf ("deltal[%i]: %f ", l, deltal[l]); + printf ("prev_mp->log2Ml[%i]: %f\n", l, prev_mp->log2Ml[intkl[l]]); + printf ("BigGamma: %f c1: %f c2: %f Sum43: %f Tl[%i]: %f log2Ml[%i]: %f Ml[%i]: %f\n", BigGamma, c1, c2, Sum43, l, Tl[l], l, cur_mp->log2Ml[l], l, cur_mp->Ml[l]); +#endif + } + + return (0); +} + +void +mbe_demodulateAmbe3600x2400Data (char ambe_fr[4][24]) +{ + int i, j, k; + unsigned short pr[115]; + unsigned short foo = 0; + + // create pseudo-random modulator + for (i = 23; i >= 12; i--) + { + foo <<= 1; + foo |= ambe_fr[0][i]; + } + pr[0] = (16 * foo); + for (i = 1; i < 24; i++) + { + pr[i] = (173 * pr[i - 1]) + 13849 - (65536 * (((173 * pr[i - 1]) + 13849) / 65536)); + } + for (i = 1; i < 24; i++) + { + pr[i] = pr[i] / 32768; + } + + // demodulate ambe_fr with pr + k = 1; + for (j = 22; j >= 0; j--) + { + ambe_fr[1][j] = ((ambe_fr[1][j]) ^ pr[k]); + k++; + } +} + +void +mbe_processAmbe2400Dataf (float *aout_buf, int *errs2, char *err_str, char ambe_d[49], mbe_parms * cur_mp, mbe_parms * prev_mp, mbe_parms * prev_mp_enhanced, int uvquality) +{ + + int i, bad; + + for (i = 0; i < *errs2; i++) + { + *err_str = '='; + err_str++; + } + + bad = mbe_decodeAmbe2400Parms (ambe_d, cur_mp, prev_mp); + if (bad == 2) + { + // Erasure frame + *err_str = 'E'; + err_str++; + cur_mp->repeat = 0; + } + else if (bad == 3) + { + // Tone Frame + *err_str = 'T'; + err_str++; + cur_mp->repeat = 0; + } + else if (*errs2 > 3) + { + mbe_useLastMbeParms (cur_mp, prev_mp); + cur_mp->repeat++; + *err_str = 'R'; + err_str++; + } + else + { + cur_mp->repeat = 0; + } + + if (bad == 0) + { + if (cur_mp->repeat <= 3) + { + mbe_moveMbeParms (cur_mp, prev_mp); + mbe_spectralAmpEnhance (cur_mp); + { + int l; + const float gv = powf (10.0f, DSTAR_DEC_VOICED_DB / 20.0f); + const float gu = powf (10.0f, DSTAR_DEC_UNVOICED_DB / 20.0f); + const float fhz = cur_mp->w0 / (2.0f * (float) M_PI) * 8000.0f; + const float gp = powf (10.0f, DSTAR_DEC_PITCH_DB_PER_OCT * log2f (fhz / DSTAR_DEC_PITCH_REF_HZ) / 20.0f); + for (l = 1; l <= cur_mp->L; l++) + cur_mp->Ml[l] *= (cur_mp->Vl[l] ? gv : gu) * gp; + } + mbe_synthesizeSpeechf (aout_buf, cur_mp, prev_mp_enhanced, uvquality); + mbe_moveMbeParms (cur_mp, prev_mp_enhanced); + } + else + { + *err_str = 'M'; + err_str++; + mbe_synthesizeSilencef (aout_buf); + mbe_initMbeParms (cur_mp, prev_mp, prev_mp_enhanced); + } + } + else + { + mbe_synthesizeSilencef (aout_buf); + mbe_initMbeParms (cur_mp, prev_mp, prev_mp_enhanced); + } + *err_str = 0; +} + +void +mbe_processAmbe2400Data (short *aout_buf, int *errs2, char *err_str, char ambe_d[49], mbe_parms * cur_mp, mbe_parms * prev_mp, mbe_parms * prev_mp_enhanced, int uvquality) +{ + float float_buf[160]; + + mbe_processAmbe2400Dataf (float_buf, errs2, err_str, ambe_d, cur_mp, prev_mp, prev_mp_enhanced, uvquality); + mbe_floattoshort (float_buf, aout_buf); +} + +void +mbe_processAmbe3600x2400Framef (float *aout_buf, int *errs2, char *err_str, char ambe_fr[4][24], char ambe_d[49], mbe_parms * cur_mp, mbe_parms * prev_mp, mbe_parms * prev_mp_enhanced, int uvquality) +{ + + int errs = 0; + *errs2 = 0; + errs = mbe_eccAmbe3600x2400C0 (ambe_fr); + mbe_demodulateAmbe3600x2400Data (ambe_fr); + *errs2 = errs; + *errs2 += mbe_eccAmbe3600x2400Data (ambe_fr, ambe_d); + + mbe_processAmbe2400Dataf (aout_buf, errs2, err_str, ambe_d, cur_mp, prev_mp, prev_mp_enhanced, uvquality); +} + +void +mbe_processAmbe3600x2400Frame (short *aout_buf, int *errs2, char *err_str, char ambe_fr[4][24], char ambe_d[49], mbe_parms * cur_mp, mbe_parms * prev_mp, mbe_parms * prev_mp_enhanced, int uvquality) +{ + float float_buf[160]; + + mbe_processAmbe3600x2400Framef (float_buf, errs2, err_str, ambe_fr, ambe_d, cur_mp, prev_mp, prev_mp_enhanced, uvquality); + mbe_floattoshort (float_buf, aout_buf); +} diff --git a/mbe/ambe3600x2400_const.h b/mbe/ambe3600x2400_const.h new file mode 100644 index 0000000..d203fe0 --- /dev/null +++ b/mbe/ambe3600x2400_const.h @@ -0,0 +1,884 @@ +/* + * Copyright (C) 2010 mbelib Author + * GPG Key ID: 0xEA5EFE2C (9E7A 5527 9CDC EBF7 BF1B D772 4F98 E863 EA5E FE2C) + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _AMBE3600x2400_CONST_H +#define _AMBE3600x2400_CONST_H + +extern "C" { +const float AmbePlusLtable[126] = { + 9, 9, 9, 9, 9, 9, + 10, 10, 10, 10, 10, 10, + 11, 11, 11, 11, 11, 11, + 12, 12, 12, 12, 12, 13, + 13, 13, 13, 13, 14, 14, + 14, 14, 15, 15, 15, 15, + 16, 16, 16, 16, 17, 17, + 17, 17, 18, 18, 18, 18, + 19, 19, 19, 20, 20, 20, + 21, 21, 21, 22, 22, 22, + 23, 23, 23, 24, 24, 24, + 25, 25, 26, 26, 26, 27, + 27, 28, 28, 29, 29, 30, + 30, 30, 31, 31, 32, 32, + 33, 33, 34, 34, 35, 36, + 36, 37, 37, 38, 38, 39, + 40, 40, 41, 42, 42, 43, + 43, 44, 45, 46, 46, 47, + 48, 48, 49, 50, 51, 52, + 52, 53, 54, 55, 56, 56, + 56, 56, 56, 56, 56, 56 // last line is padded +}; + +/* + * V/UV Quantization Vectors + */ +const int AmbePlusVuv[16][8] = { + {0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 1, 1}, + {0, 0, 0, 0, 1, 1, 0, 0}, + {0, 0, 0, 0, 1, 1, 1, 1}, + {0, 0, 1, 1, 0, 0, 0, 0}, + {0, 0, 1, 1, 0, 0, 1, 1}, + {0, 0, 1, 1, 1, 1, 0, 0}, + {0, 0, 1, 1, 1, 1, 1, 1}, + {1, 1, 0, 0, 0, 0, 0, 0}, + {1, 1, 0, 0, 0, 0, 1, 1}, + {1, 1, 0, 0, 1, 1, 0, 0}, + {1, 1, 0, 0, 1, 1, 1, 1}, + {1, 1, 1, 1, 0, 0, 0, 0}, + {1, 1, 1, 1, 0, 0, 1, 1}, + {1, 1, 1, 1, 1, 1, 0, 0}, + {1, 1, 1, 1, 1, 1, 1, 1} +}; + +/* + * Log Magnitude Prediction Residual Block Lengths + */ +const int AmbePlusLmprbl[57][4] = { + {0, 0, 0, 0,}, + {0, 0, 0, 0,}, + {0, 0, 0, 0,}, + {0, 0, 0, 0,}, + {0, 0, 0, 0,}, + {0, 0, 0, 0,}, + {0, 0, 0, 0,}, + {0, 0, 0, 0,}, + {0, 0, 0, 0,}, + {2, 2, 2, 3,}, + {2, 2, 3, 3,}, + {2, 3, 3, 3,}, + {2, 3, 3, 4,}, + {3, 3, 3, 4,}, + {3, 3, 4, 4,}, + {3, 3, 4, 5,}, + {3, 4, 4, 5,}, + {3, 4, 5, 5,}, + {4, 4, 5, 5,}, + {4, 4, 5, 6,}, + {4, 4, 6, 6,}, + {4, 5, 6, 6,}, + {4, 5, 6, 7,}, + {5, 5, 6, 7,}, + {5, 5, 7, 7,}, + {5, 6, 7, 7,}, + {5, 6, 7, 8,}, + {5, 6, 8, 8,}, + {6, 6, 8, 8,}, + {6, 6, 8, 9,}, + {6, 7, 8, 9,}, + {6, 7, 9, 9,}, + {6, 7, 9, 10,}, + {7, 7, 9, 10,}, + {7, 8, 9, 10,}, + {7, 8, 10, 10,}, + {7, 8, 10, 11,}, + {8, 8, 10, 11,}, + {8, 9, 10, 11,}, + {8, 9, 11, 11,}, + {8, 9, 11, 12,}, + {8, 9, 11, 13,}, + {8, 9, 12, 13,}, + {8, 10, 12, 13,}, + {9, 10, 12, 13,}, + {9, 10, 12, 14,}, + {9, 10, 13, 14,}, + {9, 11, 13, 14,}, + {10, 11, 13, 14,}, + {10, 11, 13, 15,}, + {10, 11, 14, 15,}, + {10, 12, 14, 15,}, + {10, 12, 14, 16,}, + {11, 12, 14, 16,}, + {11, 12, 15, 16,}, + {11, 12, 15, 17,}, + {11, 13, 15, 17} +}; + +/* + * Gain Quantizer Levels + */ +const float AmbePlusDg[64] = { +0.000000, 0.118200, 0.215088, 0.421167, 0.590088, 0.749075, 0.879395, 0.996388, +1.092285, 1.171577, 1.236572, 1.313450, 1.376465, 1.453342, 1.516357, 1.600346, +1.669189, 1.742847, 1.803223, 1.880234, 1.943359, 2.025067, 2.092041, 2.178042, +2.248535, 2.331718, 2.399902, 2.492343, 2.568115, 2.658677, 2.732910, 2.816496, +2.885010, 2.956386, 3.014893, 3.078890, 3.131348, 3.206615, 3.268311, 3.344785, +3.407471, 3.484885, 3.548340, 3.623339, 3.684814, 3.764509, 3.829834, 3.915298, +3.985352, 4.072560, 4.144043, 4.231251, 4.302734, 4.399066, 4.478027, 4.572883, +4.650635, 4.760785, 4.851074, 4.972361, 5.071777, 5.226203, 5.352783, 5.352783}; + +/* + * PRBA24 Vector Quantizer Levels + */ +const float AmbePlusPRBA24[512][3] = { + {-1.250000, -0.312500, -0.625000}, + {-0.750000, -0.437500, -0.437500}, + {-0.437500, -0.375000, -0.312500}, + {-0.437500, -0.625000, -0.500000}, + {-1.000000, -0.187500, -0.187500}, + {-0.625000, -0.625000, -0.125000}, + {-0.500000, -0.187500, -0.187500}, + {-0.375000, -0.437500, -0.187500}, + {-1.062500, -0.750000, -0.125000}, + {-0.625000, -0.312500, -0.062500}, + {-0.500000, -1.000000, -0.062500}, + {-0.375000, -0.312500, -0.062500}, + {-0.687500, -0.250000, 0.187500}, + {-0.437500, -0.500000, 0.375000}, + {-0.375000, -0.375000, 0.062500}, + {-0.312500, -0.187500, 0.000000}, + {-0.625000, -0.187500, -0.187500}, + {-0.500000, -0.062500, -0.250000}, + {-0.500000, -0.125000, -0.437500}, + {-0.312500, -0.062500, -0.312500}, + {-0.562500, -0.187500, -0.062500}, + {-0.375000, -0.187500, -0.062500}, + {-0.375000, -0.125000, -0.187500}, + {-0.312500, -0.187500, -0.125000}, + {-0.562500, 0.000000, 0.125000}, + {-0.437500, 0.000000, 0.062500}, + {-0.312500, -0.125000, 0.125000}, + {-0.312500, -0.062500, 0.000000}, + {-0.937500, -0.062500, 0.125000}, + {-0.750000, -0.125000, 0.375000}, + {-0.437500, -0.062500, 0.250000}, + {-0.375000, -0.062500, 0.625000}, + {-0.875000, 0.062500, -0.312500}, + {-0.500000, 0.125000, -0.375000}, + {-0.312500, 0.062500, -0.250000}, + {-0.312500, 0.000000, -0.312500}, + {-0.687500, 0.125000, -0.187500}, + {-0.437500, 0.062500, -0.062500}, + {-0.375000, 0.125000, -0.125000}, + {-0.312500, 0.062500, -0.125000}, + {-0.687500, 0.062500, -0.062500}, + {-0.437500, 0.187500, 0.062500}, + {-0.312500, 0.062500, 0.000000}, + {-0.250000, 0.000000, 0.125000}, + {-1.312500, 0.062500, 0.312500}, + {-0.562500, 0.125000, 0.250000}, + {-0.375000, 0.062500, 0.375000}, + {-0.312500, 0.125000, 0.125000}, + {-1.250000, 0.187500, -0.250000}, + {-0.687500, 0.437500, -0.375000}, + {-0.562500, 0.250000, -0.250000}, + {-0.312500, 0.375000, -0.562500}, + {-0.812500, 0.437500, -0.062500}, + {-0.625000, 0.187500, -0.062500}, + {-0.500000, 0.375000, -0.062500}, + {-0.375000, 0.375000, -0.250000}, + {-0.812500, 0.187500, 0.187500}, + {-0.562500, 0.625000, 0.062500}, + {-0.500000, 0.312500, 0.125000}, + {-0.312500, 0.312500, 0.062500}, + {-0.500000, 0.250000, 0.625000}, + {-0.375000, 0.250000, 0.312500}, + {-0.312500, 0.500000, 0.500000}, + {-0.312500, 0.500000, 0.250000}, + {-0.250000, -0.437500, -0.375000}, + {-0.250000, -0.250000, -0.312500}, + {-0.250000, -0.687500, -0.312500}, + {-0.125000, -0.500000, -0.250000}, + {-0.250000, -0.375000, -0.125000}, + {-0.125000, -0.312500, -0.187500}, + {-0.125000, -0.250000, -0.250000}, + {-0.062500, -0.187500, -0.125000}, + {-0.187500, -0.187500, -0.062500}, + {-0.187500, -0.500000, 0.000000}, + {-0.125000, -0.375000, -0.062500}, + {-0.062500, -0.250000, 0.000000}, + {-0.250000, -0.312500, 0.250000}, + {-0.187500, -0.250000, 0.125000}, + {-0.187500, -0.250000, 0.000000}, + {-0.125000, -0.625000, 0.187500}, + {-0.187500, -0.062500, -0.250000}, + {-0.125000, -0.062500, -0.187500}, + {-0.062500, 0.000000, -0.312500}, + {-0.062500, 0.000000, -0.812500}, + {-0.250000, -0.125000, -0.062500}, + {-0.250000, -0.062500, -0.125000}, + {-0.187500, 0.000000, -0.062500}, + {-0.125000, -0.062500, -0.062500}, + {-0.187500, 0.000000, 0.125000}, + {-0.187500, -0.062500, 0.062500}, + {-0.125000, -0.125000, 0.125000}, + {-0.125000, -0.187500, 0.062500}, + {-0.187500, -0.062500, 0.437500}, + {-0.187500, -0.125000, 0.187500}, + {-0.125000, 0.000000, 0.187500}, + {-0.062500, 0.000000, 0.375000}, + {-0.187500, 0.000000, -0.187500}, + {-0.187500, 0.125000, -0.125000}, + {-0.187500, 0.125000, -0.187500}, + {-0.125000, 0.125000, -0.375000}, + {-0.250000, 0.187500, 0.000000}, + {-0.125000, 0.000000, -0.125000}, + {-0.062500, 0.000000, -0.062500}, + {-0.062500, 0.125000, -0.062500}, + {-0.187500, 0.125000, 0.125000}, + {-0.187500, 0.062500, 0.000000}, + {-0.125000, 0.125000, 0.062500}, + {-0.062500, 0.000000, 0.000000}, + {-0.250000, 0.062500, 0.250000}, + {-0.125000, 0.125000, 0.312500}, + {-0.125000, 0.125000, 0.125000}, + {-0.062500, 0.000000, 0.125000}, + {-0.250000, 0.250000, -0.187500}, + {-0.187500, 0.687500, -0.187500}, + {-0.125000, 0.250000, -0.125000}, + {-0.062500, 0.375000, -0.312500}, + {-0.187500, 0.187500, -0.062500}, + {-0.187500, 0.437500, -0.062500}, + {-0.125000, 0.375000, 0.062500}, + {-0.062500, 0.500000, 0.000000}, + {-0.250000, 0.250000, 0.187500}, + {-0.125000, 0.562500, 0.250000}, + {-0.125000, 0.437500, 0.125000}, + {-0.062500, 0.312500, 0.125000}, + {-0.250000, 0.187500, 0.437500}, + {-0.187500, 0.250000, 0.312500}, + {-0.062500, 0.312500, 0.250000}, + {-0.062500, 0.437500, 0.562500}, + {-0.062500, -0.375000, -0.250000}, + {0.000000, -0.250000, -0.375000}, + {0.062500, -0.250000, -0.312500}, + {0.062500, -0.375000, -0.312500}, + {0.000000, -0.312500, -0.125000}, + {0.000000, -0.250000, -0.062500}, + {0.062500, -0.500000, -0.125000}, + {0.062500, -0.250000, -0.187500}, + {0.000000, -0.437500, 0.000000}, + {0.000000, -0.250000, 0.000000}, + {0.000000, -0.187500, 0.062500}, + {0.062500, -0.375000, 0.000000}, + {-0.062500, -0.187500, 0.125000}, + {-0.062500, -0.375000, 0.062500}, + {0.000000, -0.250000, 0.187500}, + {0.000000, -0.312500, 0.125000}, + {-0.062500, -0.125000, -0.250000}, + {0.000000, -0.125000, -0.500000}, + {0.000000, -0.062500, -0.250000}, + {0.062500, -0.187500, -0.187500}, + {-0.062500, -0.125000, -0.062500}, + {-0.062500, -0.187500, 0.000000}, + {0.000000, -0.125000, -0.125000}, + {0.000000, -0.187500, -0.125000}, + {-0.062500, -0.062500, 0.125000}, + {0.000000, -0.125000, 0.000000}, + {0.062500, -0.062500, 0.000000}, + {0.062500, -0.125000, 0.000000}, + {-0.062500, -0.125000, 0.437500}, + {0.000000, -0.062500, 0.250000}, + {0.000000, -0.125000, 0.187500}, + {0.062500, -0.187500, 0.312500}, + {-0.062500, 0.062500, -0.187500}, + {-0.062500, 0.000000, -0.125000}, + {0.062500, 0.062500, -0.125000}, + {0.062500, 0.062500, -0.312500}, + {0.000000, 0.062500, -0.062500}, + {0.000000, 0.000000, 0.000000}, + {0.062500, 0.000000, -0.125000}, + {0.062500, 0.125000, -0.125000}, + {0.000000, 0.062500, 0.125000}, + {0.000000, 0.125000, 0.062500}, + {0.062500, 0.000000, 0.125000}, + {0.062500, 0.062500, 0.000000}, + {-0.062500, 0.062500, 0.187500}, + {-0.062500, 0.062500, 0.437500}, + {0.000000, 0.062500, 0.250000}, + {0.062500, 0.125000, 0.187500}, + {0.000000, 0.250000, -0.250000}, + {0.000000, 0.375000, -0.062500}, + {0.000000, 0.187500, -0.125000}, + {0.062500, 0.500000, -0.187500}, + {0.000000, 0.250000, 0.000000}, + {0.000000, 0.187500, 0.062500}, + {0.062500, 0.312500, 0.062500}, + {0.062500, 0.187500, 0.000000}, + {-0.062500, 0.187500, 0.187500}, + {0.000000, 0.250000, 0.125000}, + {0.062500, 0.375000, 0.187500}, + {0.062500, 0.250000, 0.250000}, + {-0.062500, 0.187500, 0.500000}, + {0.000000, 0.312500, 0.375000}, + {0.000000, 0.125000, 0.312500}, + {0.062500, 0.187500, 0.250000}, + {0.125000, -0.125000, -0.312500}, + {0.125000, -0.312500, -0.187500}, + {0.187500, -0.375000, -0.250000}, + {0.187500, -0.187500, -0.125000}, + {0.125000, -0.187500, -0.062500}, + {0.125000, -0.687500, -0.062500}, + {0.125000, -0.187500, -0.062500}, + {0.187500, -0.375000, -0.062500}, + {0.062500, -0.250000, 0.062500}, + {0.125000, -0.187500, 0.000000}, + {0.125000, -0.187500, 0.125000}, + {0.187500, -0.250000, 0.125000}, + {0.062500, -0.187500, 0.187500}, + {0.125000, -0.312500, 0.250000}, + {0.125000, -0.375000, 0.125000}, + {0.187500, -0.187500, 0.187500}, + {0.062500, -0.125000, -0.125000}, + {0.062500, 0.000000, -0.187500}, + {0.125000, -0.062500, -0.187500}, + {0.125000, -0.125000, -0.062500}, + {0.062500, -0.062500, 0.062500}, + {0.125000, -0.062500, 0.000000}, + {0.125000, -0.125000, 0.000000}, + {0.187500, -0.062500, 0.000000}, + {0.062500, 0.000000, 0.187500}, + {0.125000, -0.125000, 0.125000}, + {0.125000, -0.062500, 0.125000}, + {0.187500, -0.125000, 0.125000}, + {0.062500, -0.062500, 0.250000}, + {0.062500, 0.000000, 0.437500}, + {0.187500, -0.125000, 0.375000}, + {0.187500, -0.125000, 0.250000}, + {0.062500, 0.125000, -0.500000}, + {0.125000, 0.125000, -0.125000}, + {0.125000, 0.000000, -0.125000}, + {0.187500, 0.000000, -0.312500}, + {0.062500, 0.062500, 0.062500}, + {0.062500, 0.125000, 0.000000}, + {0.187500, 0.062500, -0.062500}, + {0.187500, 0.125000, 0.062500}, + {0.125000, 0.125000, 0.125000}, + {0.125000, 0.000000, 0.125000}, + {0.187500, 0.000000, 0.062500}, + {0.187500, 0.125000, 0.125000}, + {0.062500, 0.125000, 0.375000}, + {0.125000, 0.062500, 0.687500}, + {0.125000, 0.062500, 0.187500}, + {0.125000, 0.000000, 0.250000}, + {0.062500, 0.187500, -0.125000}, + {0.125000, 0.187500, -0.250000}, + {0.187500, 0.312500, -0.312500}, + {0.187500, 0.250000, -0.125000}, + {0.062500, 0.437500, 0.000000}, + {0.125000, 0.250000, 0.000000}, + {0.187500, 0.187500, 0.062500}, + {0.187500, 0.187500, -0.062500}, + {0.062500, 0.187500, 0.187500}, + {0.125000, 0.375000, 0.062500}, + {0.187500, 0.250000, 0.125000}, + {0.187500, 0.250000, 0.187500}, + {0.125000, 0.312500, 0.375000}, + {0.187500, 0.687500, 0.312500}, + {0.187500, 0.187500, 0.250000}, + {0.187500, 0.312500, 0.250000}, + {0.187500, -0.562500, -0.250000}, + {0.187500, -0.937500, -0.687500}, + {0.312500, -0.312500, -0.375000}, + {0.312500, -0.500000, -0.625000}, + {0.187500, -0.312500, 0.000000}, + {0.187500, -0.250000, -0.250000}, + {0.250000, -0.312500, -0.125000}, + {0.312500, -0.187500, 0.000000}, + {0.187500, -0.437500, 0.062500}, + {0.250000, -0.250000, 0.000000}, + {0.250000, -0.312500, 0.125000}, + {0.250000, -1.000000, 0.125000}, + {0.187500, -0.312500, 0.437500}, + {0.187500, -0.625000, 0.187500}, + {0.187500, -0.250000, 0.187500}, + {0.312500, -0.312500, 0.250000}, + {0.187500, -0.062500, -0.187500}, + {0.187500, -0.125000, -0.437500}, + {0.250000, -0.187500, -0.125000}, + {0.250000, -0.125000, -0.250000}, + {0.250000, -0.187500, -0.062500}, + {0.250000, -0.062500, -0.062500}, + {0.250000, -0.062500, -0.125000}, + {0.312500, -0.125000, -0.062500}, + {0.187500, -0.187500, 0.062500}, + {0.250000, -0.062500, 0.000000}, + {0.250000, -0.125000, 0.000000}, + {0.250000, -0.125000, 0.125000}, + {0.250000, -0.062500, 0.312500}, + {0.250000, -0.187500, 0.312500}, + {0.250000, -0.062500, 0.250000}, + {0.312500, -0.187500, 0.187500}, + {0.187500, 0.125000, -0.187500}, + {0.187500, 0.062500, -0.125000}, + {0.312500, 0.062500, -0.312500}, + {0.312500, 0.062500, -0.187500}, + {0.250000, -0.062500, 0.062500}, + {0.250000, 0.000000, -0.062500}, + {0.250000, 0.062500, 0.000000}, + {0.312500, 0.000000, 0.000000}, + {0.187500, 0.000000, 0.187500}, + {0.187500, 0.062500, 0.125000}, + {0.312500, 0.000000, 0.125000}, + {0.312500, 0.062500, 0.187500}, + {0.187500, 0.062500, 0.187500}, + {0.250000, 0.062500, 0.312500}, + {0.250000, 0.000000, 0.250000}, + {0.250000, 0.062500, 0.437500}, + {0.250000, 0.250000, -0.187500}, + {0.250000, 0.250000, -0.062500}, + {0.250000, 0.125000, -0.062500}, + {0.312500, 0.625000, -0.062500}, + {0.187500, 0.312500, 0.062500}, + {0.250000, 0.375000, -0.062500}, + {0.250000, 0.125000, 0.062500}, + {0.312500, 0.187500, -0.062500}, + {0.250000, 0.437500, 0.125000}, + {0.250000, 0.187500, 0.187500}, + {0.250000, 0.187500, 0.062500}, + {0.312500, 0.250000, 0.187500}, + {0.187500, 0.187500, 0.375000}, + {0.250000, 0.187500, 0.250000}, + {0.250000, 0.312500, 0.437500}, + {0.250000, 0.375000, 0.625000}, + {0.312500, -0.250000, -0.125000}, + {0.312500, -0.312500, -0.187500}, + {0.312500, -0.187500, -0.062500}, + {0.437500, -0.625000, -0.250000}, + {0.312500, -0.312500, 0.062500}, + {0.312500, -0.312500, 0.000000}, + {0.312500, -0.375000, -0.062500}, + {0.375000, -0.250000, 0.062500}, + {0.312500, -0.437500, 0.187500}, + {0.312500, -0.187500, 0.062500}, + {0.312500, -0.312500, 0.125000}, + {0.375000, -0.250000, 0.125000}, + {0.375000, -0.375000, 0.375000}, + {0.375000, -0.250000, 0.437500}, + {0.375000, -0.250000, 0.250000}, + {0.375000, -0.312500, 0.625000}, + {0.375000, -0.125000, -0.062500}, + {0.375000, -0.125000, -0.125000}, + {0.375000, -0.062500, -0.125000}, + {0.437500, 0.000000, -0.312500}, + {0.312500, -0.125000, 0.062500}, + {0.312500, 0.000000, 0.000000}, + {0.375000, -0.062500, 0.000000}, + {0.375000, -0.187500, 0.000000}, + {0.312500, -0.062500, 0.062500}, + {0.375000, -0.062500, 0.187500}, + {0.375000, -0.125000, 0.125000}, + {0.437500, -0.062500, 0.062500}, + {0.312500, -0.125000, 0.312500}, + {0.375000, -0.062500, 0.562500}, + {0.375000, -0.187500, 0.250000}, + {0.437500, -0.062500, 0.187500}, + {0.312500, 0.000000, -0.187500}, + {0.312500, 0.000000, -0.062500}, + {0.375000, 0.062500, -0.187500}, + {0.375000, 0.125000, -0.250000}, + {0.312500, 0.062500, -0.062500}, + {0.375000, 0.062500, 0.000000}, + {0.375000, 0.125000, 0.000000}, + {0.437500, 0.000000, 0.000000}, + {0.312500, 0.062500, 0.062500}, + {0.312500, 0.125000, 0.125000}, + {0.375000, 0.000000, 0.062500}, + {0.437500, 0.125000, 0.062500}, + {0.312500, 0.062500, 0.250000}, + {0.375000, 0.000000, 0.312500}, + {0.375000, 0.000000, 0.187500}, + {0.375000, 0.125000, 0.187500}, + {0.312500, 0.187500, -0.437500}, + {0.312500, 0.187500, -0.250000}, + {0.437500, 0.500000, -0.375000}, + {0.437500, 0.250000, -0.187500}, + {0.312500, 0.250000, -0.125000}, + {0.312500, 0.187500, 0.062500}, + {0.312500, 0.312500, 0.000000}, + {0.375000, 0.125000, -0.125000}, + {0.312500, 0.250000, 0.062500}, + {0.375000, 0.312500, 0.125000}, + {0.375000, 0.187500, 0.125000}, + {0.437500, 0.312500, 0.250000}, + {0.312500, 0.437500, 0.312500}, + {0.375000, 0.125000, 0.375000}, + {0.375000, 0.750000, 0.687500}, + {0.437500, 0.125000, 0.625000}, + {0.437500, -0.250000, -0.312500}, + {0.437500, -0.250000, -0.187500}, + {0.500000, -0.375000, -0.312500}, + {0.562500, -0.250000, -0.125000}, + {0.437500, -0.250000, 0.000000}, + {0.500000, -0.500000, -0.062500}, + {0.500000, -0.312500, -0.125000}, + {0.562500, -0.375000, 0.000000}, + {0.437500, -0.312500, 0.187500}, + {0.437500, -0.375000, 0.125000}, + {0.500000, -0.187500, 0.062500}, + {0.625000, -0.250000, 0.187500}, + {0.437500, -0.375000, 0.312500}, + {0.500000, -0.250000, 0.375000}, + {0.562500, -0.562500, 0.312500}, + {0.625000, -0.437500, 0.187500}, + {0.437500, -0.187500, -0.250000}, + {0.437500, -0.187500, -0.062500}, + {0.437500, -0.062500, -0.125000}, + {0.625000, -0.187500, -0.125000}, + {0.437500, -0.125000, 0.000000}, + {0.500000, -0.125000, -0.062500}, + {0.562500, -0.125000, 0.000000}, + {0.562500, -0.062500, -0.062500}, + {0.437500, -0.062500, 0.125000}, + {0.500000, -0.187500, 0.125000}, + {0.562500, -0.062500, 0.125000}, + {0.625000, -0.187500, 0.187500}, + {0.437500, -0.062500, 0.375000}, + {0.500000, -0.125000, 0.187500}, + {0.562500, -0.125000, 0.562500}, + {0.562500, -0.125000, 0.250000}, + {0.437500, 0.062500, -0.187500}, + {0.500000, 0.125000, -0.187500}, + {0.562500, 0.000000, -0.187500}, + {0.625000, 0.000000, -0.312500}, + {0.437500, 0.062500, -0.062500}, + {0.500000, 0.062500, 0.000000}, + {0.500000, 0.125000, -0.062500}, + {0.500000, -0.062500, 0.000000}, + {0.437500, 0.062500, 0.187500}, + {0.500000, 0.000000, 0.125000}, + {0.500000, 0.062500, 0.125000}, + {0.562500, 0.125000, 0.000000}, + {0.437500, 0.062500, 0.500000}, + {0.500000, -0.062500, 0.312500}, + {0.562500, 0.000000, 0.250000}, + {0.562500, 0.062500, 0.375000}, + {0.437500, 0.312500, -0.125000}, + {0.437500, 0.187500, -0.125000}, + {0.562500, 0.500000, -0.125000}, + {0.562500, 0.312500, -0.125000}, + {0.437500, 0.250000, -0.062500}, + {0.437500, 0.250000, 0.062500}, + {0.500000, 0.250000, -0.062500}, + {0.625000, 0.125000, -0.125000}, + {0.500000, 0.375000, 0.062500}, + {0.500000, 0.125000, 0.125000}, + {0.500000, 0.562500, 0.125000}, + {0.562500, 0.187500, 0.125000}, + {0.500000, 0.187500, 0.250000}, + {0.500000, 0.625000, 0.375000}, + {0.500000, 0.250000, 0.187500}, + {0.562500, 0.312500, 0.375000}, + {0.625000, -0.312500, -0.187500}, + {0.625000, -0.187500, -0.312500}, + {0.812500, -0.437500, -0.437500}, + {1.375000, -0.187500, -0.375000}, + {0.687500, -0.312500, -0.062500}, + {0.875000, -0.250000, -0.062500}, + {1.062500, -0.187500, 0.062500}, + {1.062500, -0.437500, -0.062500}, + {0.625000, -0.250000, 0.125000}, + {0.750000, -0.125000, 0.062500}, + {0.812500, -0.312500, 0.125000}, + {1.187500, -0.125000, 0.312500}, + {0.625000, -0.312500, 0.562500}, + {0.812500, -0.250000, 0.312500}, + {0.875000, -0.500000, 0.312500}, + {1.000000, -0.312500, 0.500000}, + {0.625000, -0.062500, -0.187500}, + {0.687500, 0.062500, -0.187500}, + {0.812500, -0.062500, -0.187500}, + {1.062500, -0.125000, -0.187500}, + {0.625000, 0.062500, -0.062500}, + {0.687500, -0.125000, -0.062500}, + {0.875000, -0.125000, 0.000000}, + {1.437500, 0.000000, 0.000000}, + {0.625000, 0.000000, 0.062500}, + {0.687500, -0.062500, 0.187500}, + {0.750000, 0.062500, 0.000000}, + {0.812500, 0.000000, 0.125000}, + {0.625000, 0.062500, 0.250000}, + {0.687500, -0.062500, 0.375000}, + {0.687500, 0.000000, 0.500000}, + {0.937500, -0.062500, 0.250000}, + {0.687500, 0.187500, -0.312500}, + {0.750000, 0.187500, -0.500000}, + {1.000000, 0.187500, -0.312500}, + {1.750000, 0.125000, -0.250000}, + {0.750000, 0.187500, -0.125000}, + {0.875000, 0.187500, -0.062500}, + {0.937500, 0.125000, 0.000000}, + {1.187500, 0.187500, -0.187500}, + {0.625000, 0.187500, 0.250000}, + {0.625000, 0.187500, 0.125000}, + {0.687500, 0.187500, 0.000000}, + {0.937500, 0.250000, 0.250000}, + {0.687500, 0.187500, 0.437500}, + {0.750000, 0.062500, 0.312500}, + {0.937500, 0.125000, 0.437500}, + {1.437500, 0.187500, 0.437500}, + {0.625000, 0.250000, -0.062500}, + {0.687500, 0.375000, 0.000000}, + {1.062500, 0.937500, -0.250000}, + {1.375000, 0.375000, -0.250000}, + {0.812500, 0.312500, 0.125000}, + {0.875000, 0.500000, 0.000000}, + {1.062500, 0.375000, 0.062500}, + {1.500000, 0.437500, 0.125000}, + {0.625000, 0.375000, 0.250000}, + {0.875000, 0.375000, 0.312500}, + {1.125000, 0.625000, 0.187500}, + {1.187500, 0.250000, 0.187500}, + {0.687500, 0.437500, 0.437500}, + {0.750000, 0.375000, 0.687500}, + {0.937500, 0.750000, 0.500000}, + {1.312500, 0.687500, 0.625000} +}; + +/* + * PRBA58 Vector Quantizer Levels + */ +const float AmbePlusPRBA58[128][4] = { + {-0.460938, -0.265625, -0.281250, -0.062500}, + {-0.367188, -0.117188, -0.078125, -0.054688}, + {-0.250000, -0.312500, -0.164063, -0.101563}, + {-0.156250, -0.078125, -0.085938, -0.203125}, + {-0.468750, -0.085938, -0.171875, 0.164063}, + {-0.210938, -0.039063, -0.117188, 0.085938}, + {-0.187500, -0.156250, -0.289063, 0.070313}, + {-0.179688, -0.117188, -0.148438, -0.046875}, + {-0.320313, -0.031250, 0.140625, -0.132813}, + {-0.289063, -0.140625, 0.179688, 0.015625}, + {-0.179688, -0.226563, -0.007813, -0.101563}, + {-0.156250, -0.031250, 0.015625, -0.093750}, + {-0.390625, -0.273438, 0.046875, 0.031250}, + {-0.195313, -0.203125, -0.070313, 0.039063}, + {-0.171875, -0.156250, -0.039063, 0.171875}, + {-0.156250, -0.085938, 0.085938, 0.125000}, + {-0.304688, 0.054688, -0.210938, -0.085938}, + {-0.265625, 0.140625, -0.031250, -0.132813}, + {-0.242188, 0.078125, -0.031250, 0.015625}, + {-0.203125, 0.000000, -0.085938, -0.070313}, + {-0.453125, 0.171875, -0.062500, 0.031250}, + {-0.289063, 0.125000, -0.156250, 0.093750}, + {-0.179688, 0.257813, -0.054688, 0.273438}, + {-0.171875, 0.226563, -0.109375, 0.015625}, + {-0.312500, -0.007813, 0.000000, 0.085938}, + {-0.265625, 0.265625, 0.046875, 0.101563}, + {-0.234375, 0.109375, 0.125000, -0.046875}, + {-0.171875, -0.015625, 0.093750, 0.007813}, + {-0.414063, 0.046875, 0.101563, 0.203125}, + {-0.179688, 0.093750, 0.210938, 0.125000}, + {-0.179688, -0.007813, 0.007813, 0.273438}, + {-0.171875, 0.085938, 0.007813, 0.132813}, + {-0.062500, -0.117188, -0.257813, -0.156250}, + {-0.054688, -0.226563, -0.109375, -0.015625}, + {-0.046875, -0.164063, -0.070313, -0.117188}, + {-0.039063, -0.031250, -0.093750, -0.085938}, + {-0.156250, -0.031250, -0.015625, 0.039063}, + {-0.085938, 0.015625, -0.179688, 0.164063}, + {-0.078125, -0.078125, -0.070313, 0.046875}, + {-0.046875, -0.195313, -0.062500, 0.109375}, + {-0.093750, -0.046875, 0.109375, -0.101563}, + {-0.054688, -0.007813, 0.007813, -0.007813}, + {-0.039063, -0.132813, 0.031250, -0.031250}, + {-0.023438, -0.148438, 0.195313, -0.085938}, + {-0.148438, -0.109375, 0.023438, 0.000000}, + {-0.039063, -0.085938, 0.031250, 0.085938}, + {-0.039063, -0.226563, 0.117188, 0.070313}, + {-0.015625, -0.015625, 0.156250, 0.156250}, + {-0.109375, 0.132813, -0.109375, -0.140625}, + {-0.093750, 0.023438, -0.187500, -0.007813}, + {-0.093750, 0.382813, -0.062500, -0.101563}, + {-0.023438, 0.101563, -0.062500, -0.007813}, + {-0.140625, 0.195313, -0.273438, 0.132813}, + {-0.109375, 0.125000, -0.117188, 0.062500}, + {-0.085938, 0.015625, -0.078125, 0.031250}, + {-0.031250, 0.203125, -0.023438, 0.125000}, + {-0.125000, 0.156250, 0.078125, -0.140625}, + {-0.117188, 0.085938, 0.312500, -0.101563}, + {-0.093750, 0.062500, 0.007813, -0.078125}, + {-0.046875, 0.046875, 0.148438, -0.023438}, + {-0.125000, 0.148438, 0.007813, 0.015625}, + {-0.085938, 0.046875, 0.054688, 0.039063}, + {-0.054688, 0.140625, 0.117188, 0.101563}, + {-0.054688, 0.039063, -0.015625, 0.109375}, + {0.046875, -0.062500, -0.054688, -0.226563}, + {0.062500, -0.132813, -0.093750, -0.101563}, + {0.078125, -0.015625, -0.132813, -0.023438}, + {0.085938, -0.421875, -0.140625, -0.062500}, + {-0.007813, -0.054688, -0.054688, 0.179688}, + {0.015625, -0.078125, -0.203125, 0.054688}, + {0.015625, -0.093750, -0.078125, 0.023438}, + {0.062500, -0.179688, -0.187500, 0.148438}, + {0.007813, -0.039063, 0.046875, -0.093750}, + {0.023438, 0.031250, 0.117188, -0.179688}, + {0.101563, -0.171875, 0.093750, -0.171875}, + {0.101563, -0.023438, -0.023438, -0.125000}, + {-0.007813, -0.039063, 0.109375, 0.023438}, + {0.046875, -0.015625, 0.015625, 0.078125}, + {0.054688, -0.046875, -0.023438, -0.023438}, + {0.070313, -0.140625, 0.062500, -0.015625}, + {0.007813, 0.070313, -0.031250, -0.210938}, + {0.015625, 0.140625, -0.179688, -0.046875}, + {0.023438, 0.039063, -0.039063, -0.039063}, + {0.054688, 0.117188, -0.007813, -0.101563}, + {0.015625, 0.046875, -0.117188, 0.078125}, + {0.054688, 0.054688, -0.281250, 0.164063}, + {0.062500, 0.273438, -0.125000, 0.085938}, + {0.093750, 0.101563, -0.070313, 0.046875}, + {-0.015625, 0.125000, 0.046875, -0.031250}, + {-0.007813, 0.273438, 0.054688, 0.000000}, + {0.070313, 0.039063, 0.070313, -0.023438}, + {0.109375, 0.195313, 0.093750, -0.218750}, + {0.046875, 0.078125, 0.039063, 0.070313}, + {0.054688, 0.101563, 0.023438, 0.265625}, + {0.070313, 0.125000, 0.273438, 0.031250}, + {0.093750, 0.335938, 0.164063, 0.132813}, + {0.195313, -0.101563, 0.015625, -0.046875}, + {0.234375, -0.171875, -0.164063, -0.125000}, + {0.296875, -0.085938, -0.117188, 0.031250}, + {0.507813, -0.179688, -0.117188, 0.015625}, + {0.109375, -0.179688, -0.046875, 0.046875}, + {0.132813, -0.054688, -0.039063, 0.070313}, + {0.171875, 0.007813, -0.117188, 0.179688}, + {0.429688, 0.015625, -0.039063, 0.218750}, + {0.132813, -0.015625, 0.156250, -0.085938}, + {0.140625, -0.125000, 0.218750, 0.000000}, + {0.265625, -0.250000, 0.101563, -0.085938}, + {0.382813, -0.109375, 0.101563, -0.125000}, + {0.117188, -0.078125, 0.085938, 0.195313}, + {0.218750, -0.210938, 0.054688, 0.140625}, + {0.265625, -0.031250, 0.054688, 0.148438}, + {0.304688, 0.007813, 0.250000, 0.023438}, + {0.117188, 0.289063, -0.226563, -0.109375}, + {0.132813, 0.023438, -0.195313, -0.132813}, + {0.164063, 0.187500, -0.070313, -0.078125}, + {0.281250, 0.046875, -0.101563, -0.250000}, + {0.164063, 0.023438, -0.023438, -0.039063}, + {0.171875, 0.148438, -0.265625, 0.046875}, + {0.210938, 0.031250, -0.156250, 0.000000}, + {0.390625, 0.179688, -0.101563, -0.031250}, + {0.234375, 0.085938, 0.031250, -0.148438}, + {0.250000, 0.265625, 0.156250, -0.070313}, + {0.312500, 0.054688, 0.093750, -0.007813}, + {0.531250, 0.210938, 0.085938, -0.015625}, + {0.117188, 0.179688, 0.054688, 0.031250}, + {0.132813, 0.039063, 0.140625, 0.070313}, + {0.218750, 0.070313, 0.007813, 0.039063}, + {0.226563, 0.242188, 0.007813, 0.148438} +}; + +/* + * Higher Order Coefficients + */ +const float AmbePlusHOCb5[16][4] = { + {-0.617188, -0.015625, 0.015625, -0.023438}, + {-0.507813, -0.382813, -0.312500, -0.117188}, + {-0.328125, 0.046875, 0.007813, -0.015625}, + {-0.320313, -0.281250, -0.023438, -0.023438}, + {-0.171875, 0.140625, -0.179688, -0.007813}, + {-0.148438, 0.226563, 0.039063, -0.039063}, + {-0.140625, -0.007813, -0.007813, -0.015625}, + {-0.109375, -0.101563, 0.179688, -0.062500}, + {-0.109375, -0.109375, -0.031250, 0.187500}, + {-0.109375, -0.218750, -0.273438, -0.140625}, + {0.007813, -0.007813, -0.015625, -0.015625}, + {0.078125, -0.265625, -0.007813, 0.007813}, + {0.101563, 0.054688, -0.210938, -0.007813}, + {0.164063, 0.242188, 0.093750, 0.039063}, + {0.179688, -0.023438, 0.007813, -0.007813}, + {0.460938, 0.015625, -0.015625, 0.007813} +}; + +/* + * Higher Order Coefficients + */ +const float AmbePlusHOCb6[16][4] = { + {-0.429688, -0.046875, 0.039063, 0.000000}, + {-0.296875, 0.187500, 0.125000, 0.015625}, + {-0.203125, -0.218750, -0.039063, -0.007813}, + {-0.179688, 0.007813, -0.007813, 0.000000}, + {-0.171875, 0.265625, -0.085938, -0.039063}, + {-0.046875, -0.070313, 0.203125, -0.023438}, + {-0.023438, 0.125000, 0.031250, -0.023438}, + {-0.007813, 0.000000, -0.195313, -0.007813}, + {0.007813, -0.046875, -0.007813, -0.015625}, + {0.015625, -0.031250, 0.039063, 0.195313}, + {0.031250, -0.273438, -0.015625, -0.007813}, + {0.140625, 0.257813, 0.015625, 0.007813}, + {0.164063, 0.015625, 0.007813, -0.023438}, + {0.210938, -0.148438, -0.187500, 0.039063}, + {0.273438, -0.179688, 0.054688, -0.007813}, + {0.421875, 0.054688, -0.039063, 0.000000} +}; + +/* + * Higher Order Coefficients + */ +const float AmbePlusHOCb7[16][4] = { + {-0.382813, -0.101563, 0.007813, 0.015625}, + {-0.335938, 0.226563, 0.015625, -0.007813}, + {-0.156250, 0.031250, -0.039063, -0.054688}, + {-0.156250, -0.015625, 0.187500, -0.015625}, + {-0.085938, -0.257813, 0.023438, -0.007813}, + {-0.070313, -0.148438, -0.203125, -0.023438}, + {-0.031250, 0.187500, -0.156250, 0.007813}, + {-0.023438, -0.007813, -0.015625, 0.179688}, + {-0.015625, 0.203125, 0.070313, -0.023438}, + {0.000000, -0.039063, -0.007813, -0.023438}, + {0.140625, -0.078125, 0.179688, -0.007813}, + {0.164063, 0.023438, -0.007813, -0.015625}, + {0.187500, -0.007813, -0.218750, -0.007813}, + {0.218750, 0.242188, 0.023438, 0.031250}, + {0.234375, -0.234375, -0.039063, 0.007813}, + {0.445313, 0.054688, -0.007813, 0.000000} +}; + +/* + * Higher Order Coefficients + */ +const float AmbePlusHOCb8[16][4] = { + {-0.453125, 0.179688, 0.078125, -0.015625}, + {-0.414063, -0.179688, -0.031250, 0.015625}, + {-0.281250, 0.187500, -0.203125, 0.046875}, + {-0.210938, -0.007813, -0.031250, -0.031250}, + {-0.148438, -0.031250, 0.218750, -0.054688}, + {-0.140625, -0.085938, 0.039063, 0.187500}, + {-0.117188, 0.234375, 0.031250, -0.054688}, + {-0.062500, -0.273438, -0.007813, -0.015625}, + {-0.054688, 0.093750, -0.078125, 0.078125}, + {-0.023438, -0.062500, -0.210938, -0.054688}, + {0.023438, 0.000000, 0.023438, -0.046875}, + {0.125000, 0.234375, -0.187500, -0.015625}, + {0.164063, -0.054688, -0.093750, 0.070313}, + {0.187500, 0.179688, 0.093750, 0.015625}, + {0.203125, -0.171875, 0.140625, -0.015625}, + {0.421875, -0.039063, -0.046875, -0.007813} +}; +} +#endif diff --git a/mbe/ambe3600x2450.cpp b/mbe/ambe3600x2450.cpp new file mode 100644 index 0000000..ac7cab2 --- /dev/null +++ b/mbe/ambe3600x2450.cpp @@ -0,0 +1,681 @@ +/* + * Copyright (C) 2010 mbelib Author + * GPG Key ID: 0xEA5EFE2C (9E7A 5527 9CDC EBF7 BF1B D772 4F98 E863 EA5E FE2C) + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include + +#include "mbelib.h" +#include "ambe3600x2450_const.h" + +void +mbe_dumpAmbe2450Data (char *ambe_d) +{ + + int i; + char *ambe; + + ambe = ambe_d; + for (i = 0; i < 49; i++) + { + printf ("%i", *ambe); + ambe++; + } + printf (" "); +} + +void +mbe_dumpAmbe3600x2450Frame (char ambe_fr[4][24]) +{ + + int j; + + // c0 + printf ("ambe_fr c0: "); + for (j = 23; j >= 0; j--) + { + printf ("%i", ambe_fr[0][j]); + } + printf (" "); + // c1 + printf ("ambe_fr c1: "); + for (j = 22; j >= 0; j--) + { + printf ("%i", ambe_fr[1][j]); + } + printf (" "); + // c2 + printf ("ambe_fr c2: "); + for (j = 10; j >= 0; j--) + { + printf ("%i", ambe_fr[2][j]); + } + printf (" "); + // c3 + printf ("ambe_fr c3: "); + for (j = 13; j >= 0; j--) + { + printf ("%i", ambe_fr[3][j]); + } + printf (" "); +} + +int +mbe_eccAmbe3600x2450C0 (char ambe_fr[4][24]) +{ + + int j, errs; + char in[23], out[23]; + + for (j = 0; j < 23; j++) + { + in[j] = ambe_fr[0][j + 1]; + } + errs = mbe_golay2312 (in, out); + // ambe_fr[0][0] should be the C0 golay24 parity bit. + // TODO: actually test that here... + for (j = 0; j < 23; j++) + { + ambe_fr[0][j + 1] = out[j]; + } + + return (errs); +} + +int +mbe_eccAmbe3600x2450Data (char ambe_fr[4][24], char *ambe_d) +{ + + int j, errs; + char *ambe, gin[24], gout[24]; + + ambe = ambe_d; + // just copy C0 + for (j = 23; j > 11; j--) + { + *ambe = ambe_fr[0][j]; + ambe++; + } + + // ecc and copy C1 + for (j = 0; j < 23; j++) + { + gin[j] = ambe_fr[1][j]; + } + errs = mbe_golay2312 (gin, gout); + for (j = 22; j > 10; j--) + { + *ambe = gout[j]; + ambe++; + } + + // just copy C2 + for (j = 10; j >= 0; j--) + { + *ambe = ambe_fr[2][j]; + ambe++; + } + + // just copy C3 + for (j = 13; j >= 0; j--) + { + *ambe = ambe_fr[3][j]; + ambe++; + } + + return (errs); +} + +int +mbe_decodeAmbe2450Parms (char *ambe_d, mbe_parms * cur_mp, mbe_parms * prev_mp) +{ + + int ji, i, j, k, l, L, m, am, ak; + int intkl[57]; + int b0, b1, b2, b3, b4, b5, b6, b7, b8; + float f0, Cik[5][18], flokl[57], deltal[57]; + float Sum42, Sum43, Tl[57], Gm[9], Ri[9], sum, c1, c2; + int silence; + int Ji[5], jl; + float deltaGamma, BigGamma; + float unvc, rconst; + + silence = 0; + +#ifdef AMBE_DEBUG + printf ("\n"); +#endif + + // copy repeat from prev_mp + cur_mp->repeat = prev_mp->repeat; + + // decode fundamental frequency w0 from b0 + b0 = 0; + b0 |= ambe_d[0]<<6; + b0 |= ambe_d[1]<<5; + b0 |= ambe_d[2]<<4; + b0 |= ambe_d[3]<<3; + b0 |= ambe_d[37]<<2; + b0 |= ambe_d[38]<<1; + b0 |= ambe_d[39]; + if ((b0 >= 120) && (b0 <= 123)) // if w0 bits are 1111000, 1111001, 1111010 or 1111011, frame is erasure + { +#ifdef AMBE_DEBUG + printf ("Erasure Frame\n"); +#endif + return (2); + } + else if ((b0 == 124) || (b0 == 125)) // if w0 bits are 1111100 or 1111101, frame is silence + { +#ifdef AMBE_DEBUG + printf ("Silence Frame\n"); +#endif + silence = 1; + cur_mp->w0 = ((float) 2 * M_PI) / (float) 32; + f0 = (float) 1 / (float) 32; + L = 14; + cur_mp->L = 14; + for (l = 1; l <= L; l++) + { + cur_mp->Vl[l] = 0; + } + } + else if ((b0 == 126) || (b0 == 127)) // if w0 bits are 1111110 or 1111111, frame is tone + { +#ifdef AMBE_DEBUG + printf ("Tone Frame\n"); +#endif + return (3); + } + + if (silence == 0) + { + // w0 from specification document + f0 = AmbeW0table[b0]; + cur_mp->w0 = f0 * (float) 2 *M_PI; + // w0 from patent filings + //f0 = powf (2, ((float) b0 + (float) 195.626) / -(float) 45.368); + //cur_mp->w0 = f0 * (float) 2 *M_PI; + } + + unvc = (float) 0.2046 / sqrtf (cur_mp->w0); + //unvc = (float) 1; + //unvc = (float) 0.2046 / sqrtf (f0); + + // decode L + if (silence == 0) + { + // L from specification document + // lookup L in tabl3 + L = AmbeLtable[b0]; + // L formula from patent filings + //L=(int)((float)0.4627 / f0); + cur_mp->L = L; + } + + // decode V/UV parameters + // load b1 from ambe_d + b1 = 0; + b1 |= ambe_d[4]<<4; + b1 |= ambe_d[5]<<3; + b1 |= ambe_d[6]<<2; + b1 |= ambe_d[7]<<1; + b1 |= ambe_d[35]; + + for (l = 1; l <= L; l++) + { + // jl from specification document + jl = (int) ((float) l * (float) 16.0 * f0); + // jl from patent filings? + //jl = (int)(((float)l * (float)16.0 * f0) + 0.25); + + if (silence == 0) + { + cur_mp->Vl[l] = AmbeVuv[b1][jl]; + } +#ifdef AMBE_DEBUG + printf ("jl[%i]:%i Vl[%i]:%i\n", l, jl, l, cur_mp->Vl[l]); +#endif + } +#ifdef AMBE_DEBUG + printf ("\nb0:%i w0:%f L:%i b1:%i\n", b0, cur_mp->w0, L, b1); +#endif + + // decode gain vector + // load b2 from ambe_d + b2 = 0; + b2 |= ambe_d[8]<<4; + b2 |= ambe_d[9]<<3; + b2 |= ambe_d[10]<<2; + b2 |= ambe_d[11]<<1; + b2 |= ambe_d[36]; + + deltaGamma = AmbeDg[b2]; + cur_mp->gamma = deltaGamma + ((float) 0.5 * prev_mp->gamma); +#ifdef AMBE_DEBUG + printf ("b2: %i, deltaGamma: %f gamma: %f gamma-1: %f\n", b2, deltaGamma, cur_mp->gamma, prev_mp->gamma); +#endif + + + // decode PRBA vectors + Gm[1] = 0; + + // load b3 from ambe_d + b3 = 0; + b3 |= ambe_d[12]<<8; + b3 |= ambe_d[13]<<7; + b3 |= ambe_d[14]<<6; + b3 |= ambe_d[15]<<5; + b3 |= ambe_d[16]<<4; + b3 |= ambe_d[17]<<3; + b3 |= ambe_d[18]<<2; + b3 |= ambe_d[19]<<1; + b3 |= ambe_d[40]; + Gm[2] = AmbePRBA24[b3][0]; + Gm[3] = AmbePRBA24[b3][1]; + Gm[4] = AmbePRBA24[b3][2]; + + // load b4 from ambe_d + b4 = 0; + b4 |= ambe_d[20]<<6; + b4 |= ambe_d[21]<<5; + b4 |= ambe_d[22]<<4; + b4 |= ambe_d[23]<<3; + b4 |= ambe_d[41]<<2; + b4 |= ambe_d[42]<<1; + b4 |= ambe_d[43]; + Gm[5] = AmbePRBA58[b4][0]; + Gm[6] = AmbePRBA58[b4][1]; + Gm[7] = AmbePRBA58[b4][2]; + Gm[8] = AmbePRBA58[b4][3]; + +#ifdef AMBE_DEBUG + printf ("b3: %i Gm[2]: %f Gm[3]: %f Gm[4]: %f b4: %i Gm[5]: %f Gm[6]: %f Gm[7]: %f Gm[8]: %f\n", b3, Gm[2], Gm[3], Gm[4], b4, Gm[5], Gm[6], Gm[7], Gm[8]); +#endif + + // compute Ri + for (i = 1; i <= 8; i++) + { + sum = 0; + for (m = 1; m <= 8; m++) + { + if (m == 1) + { + am = 1; + } + else + { + am = 2; + } + sum = sum + ((float) am * Gm[m] * cosf ((M_PI * (float) (m - 1) * ((float) i - (float) 0.5)) / (float) 8)); + } + Ri[i] = sum; +#ifdef AMBE_DEBUG + printf ("R%i: %f ", i, Ri[i]); +#endif + } +#ifdef AMBE_DEBUG + printf ("\n"); +#endif + + // generate first to elements of each Ci,k block from PRBA vector + rconst = ((float) 1 / ((float) 2 * M_SQRT2)); + Cik[1][1] = (float) 0.5 *(Ri[1] + Ri[2]); + Cik[1][2] = rconst * (Ri[1] - Ri[2]); + Cik[2][1] = (float) 0.5 *(Ri[3] + Ri[4]); + Cik[2][2] = rconst * (Ri[3] - Ri[4]); + Cik[3][1] = (float) 0.5 *(Ri[5] + Ri[6]); + Cik[3][2] = rconst * (Ri[5] - Ri[6]); + Cik[4][1] = (float) 0.5 *(Ri[7] + Ri[8]); + Cik[4][2] = rconst * (Ri[7] - Ri[8]); + + // decode HOC + + // load b5 from ambe_d + b5 = 0; + b5 |= ambe_d[24]<<4; + b5 |= ambe_d[25]<<3; + b5 |= ambe_d[26]<<2; + b5 |= ambe_d[27]<<1; + b5 |= ambe_d[44]; + + // load b6 from ambe_d + b6 = 0; + b6 |= ambe_d[28]<<3; + b6 |= ambe_d[29]<<2; + b6 |= ambe_d[30]<<1; + b6 |= ambe_d[45]; + + // load b7 from ambe_d + b7 = 0; + b7 |= ambe_d[31]<<3; + b7 |= ambe_d[32]<<2; + b7 |= ambe_d[33]<<1; + b7 |= ambe_d[46]; + + // load b8 from ambe_d + b8 = 0; + b8 |= ambe_d[34]<<2; + b8 |= ambe_d[47]<<1; + b8 |= ambe_d[48]; + + // lookup Ji + Ji[1] = AmbeLmprbl[L][0]; + Ji[2] = AmbeLmprbl[L][1]; + Ji[3] = AmbeLmprbl[L][2]; + Ji[4] = AmbeLmprbl[L][3]; +#ifdef AMBE_DEBUG + printf ("Ji[1]: %i Ji[2]: %i Ji[3]: %i Ji[4]: %i\n", Ji[1], Ji[2], Ji[3], Ji[4]); + printf ("b5: %i b6: %i b7: %i b8: %i\n", b5, b6, b7, b8); +#endif + + // Load Ci,k with the values from the HOC tables + // there appear to be a couple typos in eq. 37 so we will just do what makes sense + // (3 <= k <= Ji and k<=6) + for (k = 3; k <= Ji[1]; k++) + { + if (k > 6) + { + Cik[1][k] = 0; + } + else + { + Cik[1][k] = AmbeHOCb5[b5][k - 3]; +#ifdef AMBE_DEBUG + printf ("C1,%i: %f ", k, Cik[1][k]); +#endif + } + } + for (k = 3; k <= Ji[2]; k++) + { + if (k > 6) + { + Cik[2][k] = 0; + } + else + { + Cik[2][k] = AmbeHOCb6[b6][k - 3]; +#ifdef AMBE_DEBUG + printf ("C2,%i: %f ", k, Cik[2][k]); +#endif + } + } + for (k = 3; k <= Ji[3]; k++) + { + if (k > 6) + { + Cik[3][k] = 0; + } + else + { + Cik[3][k] = AmbeHOCb7[b7][k - 3]; +#ifdef AMBE_DEBUG + printf ("C3,%i: %f ", k, Cik[3][k]); +#endif + } + } + for (k = 3; k <= Ji[4]; k++) + { + if (k > 6) + { + Cik[4][k] = 0; + } + else + { + Cik[4][k] = AmbeHOCb8[b8][k - 3]; +#ifdef AMBE_DEBUG + printf ("C4,%i: %f ", k, Cik[4][k]); +#endif + } + } +#ifdef AMBE_DEBUG + printf ("\n"); +#endif + + // inverse DCT each Ci,k to give ci,j (Tl) + l = 1; + for (i = 1; i <= 4; i++) + { + ji = Ji[i]; + for (j = 1; j <= ji; j++) + { + sum = 0; + for (k = 1; k <= ji; k++) + { + if (k == 1) + { + ak = 1; + } + else + { + ak = 2; + } +#ifdef AMBE_DEBUG + printf ("j: %i Cik[%i][%i]: %f ", j, i, k, Cik[i][k]); +#endif + sum = sum + ((float) ak * Cik[i][k] * cosf ((M_PI * (float) (k - 1) * ((float) j - (float) 0.5)) / (float) ji)); + } + Tl[l] = sum; +#ifdef AMBE_DEBUG + printf ("Tl[%i]: %f\n", l, Tl[l]); +#endif + l++; + } + } + + // determine log2Ml by applying ci,j to previous log2Ml + + // fix for when L > L(-1) + if (cur_mp->L > prev_mp->L) + { + for (l = (prev_mp->L) + 1; l <= cur_mp->L; l++) + { + prev_mp->Ml[l] = prev_mp->Ml[prev_mp->L]; + prev_mp->log2Ml[l] = prev_mp->log2Ml[prev_mp->L]; + } + } + prev_mp->log2Ml[0] = prev_mp->log2Ml[1]; + prev_mp->Ml[0] = prev_mp->Ml[1]; + + // Part 1 + Sum43 = 0; + for (l = 1; l <= cur_mp->L; l++) + { + + // eq. 40 + flokl[l] = ((float) prev_mp->L / (float) cur_mp->L) * (float) l; + intkl[l] = (int) (flokl[l]); +#ifdef AMBE_DEBUG + printf ("flok%i: %f, intk%i: %i ", l, flokl[l], l, intkl[l]); +#endif + // eq. 41 + deltal[l] = flokl[l] - (float) intkl[l]; +#ifdef AMBE_DEBUG + printf ("delta%i: %f ", l, deltal[l]); +#endif + // eq 43 + Sum43 = Sum43 + ((((float) 1 - deltal[l]) * prev_mp->log2Ml[intkl[l]]) + (deltal[l] * prev_mp->log2Ml[intkl[l] + 1])); + } + Sum43 = (((float) 0.65 / (float) cur_mp->L) * Sum43); +#ifdef AMBE_DEBUG + printf ("\n"); + printf ("Sum43: %f\n", Sum43); +#endif + + // Part 2 + Sum42 = 0; + for (l = 1; l <= cur_mp->L; l++) + { + Sum42 += Tl[l]; + } + Sum42 = Sum42 / (float) cur_mp->L; + BigGamma = cur_mp->gamma - ((float) 0.5 * (log ((float) cur_mp->L) / log ((float) 2))) - Sum42; + //BigGamma=cur_mp->gamma - ((float)0.5 * log((float)cur_mp->L)) - Sum42; + + // Part 3 + for (l = 1; l <= cur_mp->L; l++) + { + c1 = ((float) 0.65 * ((float) 1 - deltal[l]) * prev_mp->log2Ml[intkl[l]]); + c2 = ((float) 0.65 * deltal[l] * prev_mp->log2Ml[intkl[l] + 1]); + cur_mp->log2Ml[l] = Tl[l] + c1 + c2 - Sum43 + BigGamma; + // inverse log to generate spectral amplitudes + if (cur_mp->Vl[l] == 1) + { + cur_mp->Ml[l] = exp ((float) 0.693 * cur_mp->log2Ml[l]); + } + else + { + cur_mp->Ml[l] = unvc * exp ((float) 0.693 * cur_mp->log2Ml[l]); + } +#ifdef AMBE_DEBUG + printf ("flokl[%i]: %f, intkl[%i]: %i ", l, flokl[l], l, intkl[l]); + printf ("deltal[%i]: %f ", l, deltal[l]); + printf ("prev_mp->log2Ml[%i]: %f\n", l, prev_mp->log2Ml[intkl[l]]); + printf ("BigGamma: %f c1: %f c2: %f Sum43: %f Tl[%i]: %f log2Ml[%i]: %f Ml[%i]: %f\n", BigGamma, c1, c2, Sum43, l, Tl[l], l, cur_mp->log2Ml[l], l, cur_mp->Ml[l]); +#endif + } + + return (0); +} + +void +mbe_demodulateAmbe3600x2450Data (char ambe_fr[4][24]) +{ + int i, j, k; + unsigned short pr[115]; + unsigned short foo = 0; + + // create pseudo-random modulator + for (i = 23; i >= 12; i--) + { + foo <<= 1; + foo |= ambe_fr[0][i]; + } + pr[0] = (16 * foo); + for (i = 1; i < 24; i++) + { + pr[i] = (173 * pr[i - 1]) + 13849 - (65536 * (((173 * pr[i - 1]) + 13849) / 65536)); + } + for (i = 1; i < 24; i++) + { + pr[i] = pr[i] / 32768; + } + + // demodulate ambe_fr with pr + k = 1; + for (j = 22; j >= 0; j--) + { + ambe_fr[1][j] = ((ambe_fr[1][j]) ^ pr[k]); + k++; + } +} + +void +mbe_processAmbe2450Dataf (float *aout_buf, int *errs2, char *err_str, char ambe_d[49], mbe_parms * cur_mp, mbe_parms * prev_mp, mbe_parms * prev_mp_enhanced, int uvquality) +{ + + int i, bad; + + for (i = 0; i < *errs2; i++) + { + *err_str = '='; + err_str++; + } + + bad = mbe_decodeAmbe2450Parms (ambe_d, cur_mp, prev_mp); + if (bad == 2) + { + // Erasure frame + *err_str = 'E'; + err_str++; + cur_mp->repeat = 0; + } + else if (bad == 3) + { + // Tone Frame + *err_str = 'T'; + err_str++; + cur_mp->repeat = 0; + } + else if (*errs2 > 3) + { + mbe_useLastMbeParms (cur_mp, prev_mp); + cur_mp->repeat++; + *err_str = 'R'; + err_str++; + } + else + { + cur_mp->repeat = 0; + } + + if (bad == 0) + { + if (cur_mp->repeat <= 3) + { + mbe_moveMbeParms (cur_mp, prev_mp); + mbe_spectralAmpEnhance (cur_mp); + mbe_synthesizeSpeechf (aout_buf, cur_mp, prev_mp_enhanced, uvquality); + mbe_moveMbeParms (cur_mp, prev_mp_enhanced); + } + else + { + *err_str = 'M'; + err_str++; + mbe_synthesizeSilencef (aout_buf); + mbe_initMbeParms (cur_mp, prev_mp, prev_mp_enhanced); + } + } + else + { + mbe_synthesizeSilencef (aout_buf); + mbe_initMbeParms (cur_mp, prev_mp, prev_mp_enhanced); + } + *err_str = 0; +} + +void +mbe_processAmbe2450Data (short *aout_buf, int *errs2, char *err_str, char ambe_d[49], mbe_parms * cur_mp, mbe_parms * prev_mp, mbe_parms * prev_mp_enhanced, int uvquality) +{ + float float_buf[160]; + + mbe_processAmbe2450Dataf (float_buf, errs2, err_str, ambe_d, cur_mp, prev_mp, prev_mp_enhanced, uvquality); + mbe_floattoshort (float_buf, aout_buf); +} + +void +mbe_processAmbe3600x2450Framef (float *aout_buf, int *errs2, char *err_str, char ambe_fr[4][24], char ambe_d[49], mbe_parms * cur_mp, mbe_parms * prev_mp, mbe_parms * prev_mp_enhanced, int uvquality) +{ + + int errs = 0; + *errs2 = 0; + errs = mbe_eccAmbe3600x2450C0 (ambe_fr); + mbe_demodulateAmbe3600x2450Data (ambe_fr); + *errs2 = errs; + *errs2 += mbe_eccAmbe3600x2450Data (ambe_fr, ambe_d); + + mbe_processAmbe2450Dataf (aout_buf, errs2, err_str, ambe_d, cur_mp, prev_mp, prev_mp_enhanced, uvquality); +} + +void +mbe_processAmbe3600x2450Frame (short *aout_buf, int *errs2, char *err_str, char ambe_fr[4][24], char ambe_d[49], mbe_parms * cur_mp, mbe_parms * prev_mp, mbe_parms * prev_mp_enhanced, int uvquality) +{ + float float_buf[160]; + + mbe_processAmbe3600x2450Framef (float_buf, errs2, err_str, ambe_fr, ambe_d, cur_mp, prev_mp, prev_mp_enhanced, uvquality); + mbe_floattoshort (float_buf, aout_buf); +} diff --git a/mbe/ambe3600x2450_const.h b/mbe/ambe3600x2450_const.h new file mode 100644 index 0000000..377d789 --- /dev/null +++ b/mbe/ambe3600x2450_const.h @@ -0,0 +1,971 @@ +/* + * Copyright (C) 2010 mbelib Author + * GPG Key ID: 0xEA5EFE2C (9E7A 5527 9CDC EBF7 BF1B D772 4F98 E863 EA5E FE2C) + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _AMBE3600x2250_CONST_H +#define _AMBE3600x2250_CONST_H +extern "C" { +/* + * Fundamental Frequency Quanitization Table + */ + +const float AmbeW0table[120] = { + 0.049971, 0.049215, 0.048471, 0.047739, 0.047010, 0.046299, + 0.045601, 0.044905, 0.044226, 0.043558, 0.042900, 0.042246, + 0.041609, 0.040979, 0.040356, 0.039747, 0.039148, 0.038559, + 0.037971, 0.037399, 0.036839, 0.036278, 0.035732, 0.035198, + 0.034672, 0.034145, 0.033636, 0.033133, 0.032635, 0.032148, + 0.031670, 0.031122, 0.030647, 0.030184, 0.029728, 0.029272, + 0.028831, 0.028395, 0.027966, 0.027538, + 0.027122, 0.026712, 0.026304, 0.025906, 0.025515, 0.025129, + 0.024746, 0.024372, 0.024002, 0.023636, 0.023279, 0.022926, + 0.022581, 0.022236, 0.021900, 0.021570, 0.021240, 0.020920, + 0.020605, 0.020294, 0.019983, 0.019684, 0.019386, 0.019094, + 0.018805, 0.018520, 0.018242, 0.017965, 0.017696, 0.017431, + 0.017170, 0.016911, 0.016657, 0.016409, 0.016163, 0.015923, + 0.015686, 0.015411, 0.015177, 0.014946, + 0.014721, 0.014496, 0.014277, 0.014061, 0.013847, 0.013636, + 0.013430, 0.013227, 0.013025, 0.012829, 0.012634, 0.012444, + 0.012253, 0.012068, 0.011887, 0.011703, 0.011528, 0.011353, + 0.011183, 0.011011, 0.010845, 0.010681, 0.010517, 0.010359, + 0.010202, 0.010050, 0.009895, 0.009747, 0.009600, 0.009453, + 0.009312, 0.009172, 0.009033, 0.008896, 0.008762, 0.008633, + 0.008501, 0.008375, 0.008249, 0.008125 +}; + +const float AmbeLtable[120] = { + 9, 9, 9, 9, 9, 9, + 10, 10, 10, 10, 10, 10, + 11, 11, 11, 11, 11, 11, + 12, 12, 12, 12, 12, 13, + 13, 13, 13, 13, 14, 14, + 14, 14, 15, 15, 15, 15, + 16, 16, 16, 16, 17, 17, + 17, 17, 18, 18, 18, 18, + 19, 19, 19, 20, 20, 20, + 21, 21, 21, 22, 22, 22, + 23, 23, 23, 24, 24, 24, + 25, 25, 26, 26, 26, 27, + 27, 28, 28, 29, 29, 30, + 30, 30, 31, 31, 32, 32, + 33, 33, 34, 34, 35, 36, + 36, 37, 37, 38, 38, 39, + 40, 40, 41, 42, 42, 43, + 43, 44, 45, 46, 46, 47, + 48, 48, 49, 50, 51, 52, + 52, 53, 54, 55, 56, 56 +}; + +/* + * V/UV Quantization Vectors + */ +const int AmbeVuv[32][8] = { + {1, 1, 1, 1, 1, 1, 1, 1}, + {1, 1, 1, 1, 1, 1, 1, 1}, + {1, 1, 1, 1, 1, 1, 1, 0}, + {1, 1, 1, 1, 1, 1, 1, 1}, + {1, 1, 1, 1, 1, 1, 0, 0}, + {1, 1, 0, 1, 1, 1, 1, 1}, + {1, 1, 1, 0, 1, 1, 1, 1}, + {1, 1, 1, 1, 1, 0, 1, 1}, + {1, 1, 1, 1, 0, 0, 0, 0}, + {1, 1, 1, 1, 1, 0, 0, 0}, + {1, 1, 1, 0, 0, 0, 0, 0}, + {1, 1, 1, 0, 0, 0, 0, 1}, + {1, 1, 0, 0, 0, 0, 0, 0}, + {1, 1, 1, 0, 0, 0, 0, 0}, + {1, 0, 0, 0, 0, 0, 0, 0}, + {1, 1, 1, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0} +}; + +/* + * V/UV Quantization Vectors + * alternate version + */ +/* +const int AmbeVuv[32][8] = { + {1, 1, 1, 1, 1, 1, 1, 1}, + {1, 1, 1, 1, 1, 1, 1, 1}, + {1, 1, 1, 1, 1, 1, 1, 0}, + {1, 1, 1, 1, 1, 1, 1, 0}, + {1, 1, 1, 1, 1, 1, 0, 0}, + {1, 1, 0, 1, 1, 1, 1, 1}, + {1, 1, 1, 0, 1, 1, 1, 1}, + {1, 1, 1, 1, 1, 0, 1, 1}, + {1, 1, 1, 1, 0, 0, 0, 0}, + {1, 1, 1, 1, 1, 0, 0, 0}, + {1, 1, 1, 0, 0, 0, 0, 0}, + {1, 1, 1, 0, 0, 0, 0, 1}, + {1, 1, 0, 0, 0, 0, 0, 0}, + {1, 1, 0, 0, 0, 0, 0, 0}, + {1, 0, 0, 0, 0, 0, 0, 0}, + {1, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0} +}; +*/ + +/* + * Log Magnitude Prediction Residual Block Lengths + */ +const int AmbeLmprbl[57][4] = { + {0, 0, 0, 0,}, + {0, 0, 0, 0,}, + {0, 0, 0, 0,}, + {0, 0, 0, 0,}, + {0, 0, 0, 0,}, + {0, 0, 0, 0,}, + {0, 0, 0, 0,}, + {0, 0, 0, 0,}, + {0, 0, 0, 0,}, + {2, 2, 2, 3,}, + {2, 2, 3, 3,}, + {2, 3, 3, 3,}, + {2, 3, 3, 4,}, + {3, 3, 3, 4,}, + {3, 3, 4, 4,}, + {3, 3, 4, 5,}, + {3, 4, 4, 5,}, + {3, 4, 5, 5,}, + {4, 4, 5, 5,}, + {4, 4, 5, 6,}, + {4, 4, 6, 6,}, + {4, 5, 6, 6,}, + {4, 5, 6, 7,}, + {5, 5, 6, 7,}, + {5, 5, 7, 7,}, + {5, 6, 7, 7,}, + {5, 6, 7, 8,}, + {5, 6, 8, 8,}, + {6, 6, 8, 8,}, + {6, 6, 8, 9,}, + {6, 7, 8, 9,}, + {6, 7, 9, 9,}, + {6, 7, 9, 10,}, + {7, 7, 9, 10,}, + {7, 8, 9, 10,}, + {7, 8, 10, 10,}, + {7, 8, 10, 11,}, + {8, 8, 10, 11,}, + {8, 9, 10, 11,}, + {8, 9, 11, 11,}, + {8, 9, 11, 12,}, + {8, 9, 11, 13,}, + {8, 9, 12, 13,}, + {8, 10, 12, 13,}, + {9, 10, 12, 13,}, + {9, 10, 12, 14,}, + {9, 10, 13, 14,}, + {9, 11, 13, 14,}, + {10, 11, 13, 14,}, + {10, 11, 13, 15,}, + {10, 11, 14, 15,}, + {10, 12, 14, 15,}, + {10, 12, 14, 16,}, + {11, 12, 14, 16,}, + {11, 12, 15, 16,}, + {11, 12, 15, 17,}, + {11, 13, 15, 17} +}; + +/* + * Gain Quantizer Levels + */ +const float AmbeDg[32] = { -2.0, -0.67, 0.297941, 0.663728, 1.036829, 1.438136, 1.890077, 2.227970, + 2.478289, 2.667544, 2.793619, 2.893261, 3.020630, 3.138586, 3.237579, 3.322570, + 3.432367, 3.571863, 3.696650, 3.814917, 3.920932, 4.022503, 4.123569, 4.228291, + 4.370569, 4.543700, 4.707695, 4.848879, 5.056757, 5.326468, 5.777581, 6.874496 +}; + +/* + * PRBA24 Vector Quantizer Levels + */ +const float AmbePRBA24[512][3] = { + {0.526055, -0.328567, -0.304727}, + {0.441044, -0.303127, -0.201114}, + {1.030896, -0.324730, -0.397204}, + {0.839696, -0.351933, -0.224909}, + {0.272958, -0.176118, -0.098893}, + {0.221466, -0.160045, -0.061026}, + {0.496555, -0.211499, 0.047305}, + {0.424376, -0.223752, 0.069911}, + {0.264531, -0.353355, -0.330505}, + {0.273650, -0.253004, -0.250241}, + {0.484531, -0.297627, -0.071051}, + {0.410814, -0.224961, -0.084998}, + {0.039519, -0.252904, -0.115128}, + {0.017423, -0.296519, -0.045921}, + {0.225113, -0.224371, 0.037882}, + {0.183424, -0.260492, 0.050491}, + {0.308704, -0.073205, -0.405880}, + {0.213125, -0.101632, -0.333208}, + {0.617735, -0.137299, -0.213670}, + {0.514382, -0.126485, -0.170204}, + {0.130009, -0.076955, -0.229303}, + {0.061740, -0.108259, -0.203887}, + {0.244473, -0.110094, -0.051689}, + {0.230452, -0.076147, -0.028190}, + {0.059837, -0.254595, -0.562704}, + {0.011630, -0.135223, -0.432791}, + {0.207077, -0.152248, -0.148391}, + {0.158078, -0.128800, -0.122150}, + {-0.265982, -0.144742, -0.199894}, + {-0.356479, -0.204740, -0.156465}, + {0.000324, -0.139549, -0.066471}, + {0.001888, -0.170557, -0.025025}, + {0.402913, -0.581478, -0.274626}, + {0.191289, -0.540335, -0.193040}, + {0.632914, -0.401410, -0.006636}, + {0.471086, -0.463144, 0.061489}, + {0.044829, -0.438487, 0.033433}, + {0.015513, -0.539475, -0.006719}, + {0.336218, -0.351311, 0.214087}, + {0.239967, -0.380836, 0.157681}, + {0.347609, -0.901619, -0.688432}, + {0.064067, -0.826753, -0.492089}, + {0.303089, -0.396757, -0.108446}, + {0.235590, -0.446122, 0.006437}, + {-0.236964, -0.652532, -0.135520}, + {-0.418285, -0.793014, -0.034730}, + {-0.038262, -0.516984, 0.273681}, + {-0.037419, -0.958198, 0.214749}, + {0.061624, -0.238233, -0.237184}, + {-0.013944, -0.235704, -0.204811}, + {0.286428, -0.210542, -0.029587}, + {0.257656, -0.261837, -0.056566}, + {-0.235852, -0.310760, -0.165147}, + {-0.334949, -0.385870, -0.197362}, + {0.094870, -0.241144, 0.059122}, + {0.060177, -0.225884, 0.031140}, + {-0.301184, -0.306545, -0.446189}, + {-0.293528, -0.504146, -0.429844}, + {-0.055084, -0.379015, -0.125887}, + {-0.115434, -0.375008, -0.059939}, + {-0.777425, -0.592163, -0.107585}, + {-0.950500, -0.893847, -0.181762}, + {-0.259402, -0.396726, 0.010357}, + {-0.368905, -0.449026, 0.038299}, + {0.279719, -0.063196, -0.184628}, + {0.255265, -0.067248, -0.121124}, + {0.458433, -0.103777, 0.010074}, + {0.437231, -0.092496, -0.031028}, + {0.082265, -0.028050, -0.041262}, + {0.045920, -0.051719, -0.030155}, + {0.271149, -0.043613, 0.112085}, + {0.246881, -0.065274, 0.105436}, + {0.056590, -0.117773, -0.142283}, + {0.058824, -0.104418, -0.099608}, + {0.213781, -0.111974, 0.031269}, + {0.187554, -0.070340, 0.011834}, + {-0.185701, -0.081106, -0.073803}, + {-0.266112, -0.074133, -0.085370}, + {-0.029368, -0.046490, 0.124679}, + {-0.017378, -0.102882, 0.140482}, + {0.114700, 0.092738, -0.244271}, + {0.072922, 0.007863, -0.231476}, + {0.270022, 0.031819, -0.094208}, + {0.254403, 0.024805, -0.050389}, + {-0.182905, 0.021629, -0.168481}, + {-0.225864, -0.010109, -0.130374}, + {0.040089, 0.013969, 0.016028}, + {0.001442, 0.010551, 0.032942}, + {-0.287472, -0.036130, -0.296798}, + {-0.332344, -0.108862, -0.342196}, + {0.012700, 0.022917, -0.052501}, + {-0.040681, -0.001805, -0.050548}, + {-0.718522, -0.061234, -0.278820}, + {-0.879205, -0.213588, -0.303508}, + {-0.234102, -0.065407, 0.013686}, + {-0.281223, -0.076139, 0.046830}, + {0.141967, -0.193679, -0.055697}, + {0.100318, -0.161222, -0.063062}, + {0.265859, -0.132747, 0.078209}, + {0.244805, -0.139776, 0.122123}, + {-0.121802, -0.179976, 0.031732}, + {-0.185318, -0.214011, 0.018117}, + {0.047014, -0.153961, 0.218068}, + {0.047305, -0.187402, 0.282114}, + {-0.027533, -0.415868, -0.333841}, + {-0.125886, -0.334492, -0.290317}, + {-0.030602, -0.190918, 0.097454}, + {-0.054936, -0.209948, 0.158977}, + {-0.507223, -0.295876, -0.217183}, + {-0.581733, -0.403194, -0.208936}, + {-0.299719, -0.289679, 0.297101}, + {-0.363169, -0.362718, 0.436529}, + {-0.124627, -0.042100, -0.157011}, + {-0.161571, -0.092846, -0.183636}, + {0.084520, -0.100217, -0.000901}, + {0.055655, -0.136381, 0.032764}, + {-0.545087, -0.197713, -0.026888}, + {-0.662772, -0.179815, 0.026419}, + {-0.165583, -0.148913, 0.090382}, + {-0.240772, -0.182830, 0.105474}, + {-0.576315, -0.359473, -0.456844}, + {-0.713430, -0.554156, -0.476739}, + {-0.275628, -0.223640, -0.051584}, + {-0.359501, -0.230758, -0.027006}, + {-1.282559, -0.284807, -0.233743}, + {-1.060476, -0.399911, -0.562698}, + {-0.871952, -0.272197, 0.016126}, + {-0.747922, -0.329404, 0.276696}, + {0.643086, 0.046175, -0.660078}, + {0.738204, -0.127844, -0.433708}, + {1.158072, 0.025571, -0.177856}, + {0.974840, -0.009417, -0.112337}, + {0.418014, 0.032741, -0.124545}, + {0.381422, -0.001557, -0.085504}, + {0.768280, 0.056085, 0.095375}, + {0.680004, 0.052035, 0.152318}, + {0.473182, 0.012560, -0.264221}, + {0.345153, 0.036627, -0.248756}, + {0.746238, -0.025880, -0.106050}, + {0.644319, -0.058256, -0.095133}, + {0.185924, -0.022230, -0.070540}, + {0.146068, -0.009550, -0.057871}, + {0.338488, 0.013022, 0.069961}, + {0.298969, 0.047403, 0.052598}, + {0.346002, 0.256253, -0.380261}, + {0.313092, 0.163821, -0.314004}, + {0.719154, 0.103108, -0.252648}, + {0.621429, 0.172423, -0.265180}, + {0.240461, 0.104684, -0.202582}, + {0.206946, 0.139642, -0.138016}, + {0.359915, 0.101273, -0.052997}, + {0.318117, 0.125888, -0.003486}, + {0.150452, 0.050219, -0.409155}, + {0.188753, 0.091894, -0.325733}, + {0.334922, 0.029098, -0.098587}, + {0.324508, 0.015809, -0.135408}, + {-0.042506, 0.038667, -0.208535}, + {-0.083003, 0.094758, -0.174054}, + {0.094773, 0.102653, -0.025701}, + {0.063284, 0.118703, -0.000071}, + {0.355965, -0.139239, -0.191705}, + {0.392742, -0.105496, -0.132103}, + {0.663678, -0.204627, -0.031242}, + {0.609381, -0.146914, 0.079610}, + {0.151855, -0.132843, -0.007125}, + {0.146404, -0.161917, 0.024842}, + {0.400524, -0.135221, 0.232289}, + {0.324931, -0.116605, 0.253458}, + {0.169066, -0.215132, -0.185604}, + {0.128681, -0.189394, -0.160279}, + {0.356194, -0.116992, -0.038381}, + {0.342866, -0.144687, 0.020265}, + {-0.065545, -0.202593, -0.043688}, + {-0.124296, -0.260225, -0.035370}, + {0.083224, -0.235149, 0.153301}, + {0.046256, -0.309608, 0.190944}, + {0.187385, -0.008168, -0.198575}, + {0.190401, -0.018699, -0.136858}, + {0.398009, -0.025700, -0.007458}, + {0.346948, -0.022258, -0.020905}, + {-0.047064, -0.085629, -0.080677}, + {-0.067523, -0.128972, -0.119538}, + {0.186086, -0.016828, 0.070014}, + {0.187364, 0.017133, 0.075949}, + {-0.112669, -0.037433, -0.298944}, + {-0.068276, -0.114504, -0.265795}, + {0.147510, -0.040616, -0.013687}, + {0.133084, -0.062849, -0.032637}, + {-0.416571, -0.041544, -0.125088}, + {-0.505337, -0.044193, -0.157651}, + {-0.154132, -0.075106, 0.050466}, + {-0.148036, -0.059719, 0.121516}, + {0.490555, 0.157659, -0.222208}, + {0.436700, 0.120500, -0.205869}, + {0.754525, 0.269323, 0.045810}, + {0.645077, 0.271923, 0.013942}, + {0.237023, 0.115337, -0.026429}, + {0.204895, 0.121020, -0.008541}, + {0.383999, 0.153963, 0.171763}, + {0.385026, 0.222074, 0.239731}, + {0.198232, 0.072972, -0.108179}, + {0.147882, 0.074743, -0.123341}, + {0.390929, 0.075205, 0.081828}, + {0.341623, 0.089405, 0.069389}, + {-0.003381, 0.159694, -0.016026}, + {-0.043653, 0.206860, -0.040729}, + {0.135515, 0.107824, 0.179310}, + {0.081086, 0.119673, 0.174282}, + {0.192637, 0.400335, -0.341906}, + {0.171196, 0.284921, -0.221516}, + {0.377807, 0.359087, -0.151523}, + {0.411052, 0.297925, -0.099774}, + {-0.010060, 0.261887, -0.149567}, + {-0.107877, 0.287756, -0.116982}, + {0.158003, 0.209727, 0.077988}, + {0.109710, 0.232272, 0.088135}, + {0.000698, 0.209353, -0.395208}, + {-0.094015, 0.230322, -0.279928}, + {0.137355, 0.230881, -0.124115}, + {0.103058, 0.166855, -0.100386}, + {-0.305058, 0.305422, -0.176026}, + {-0.422049, 0.337137, -0.293297}, + {-0.121744, 0.185124, 0.048115}, + {-0.171052, 0.200312, 0.052812}, + {0.224091, -0.010673, -0.019727}, + {0.200266, -0.020167, 0.001798}, + {0.382742, 0.032362, 0.161665}, + {0.345631, -0.019705, 0.164451}, + {0.029431, 0.045010, 0.071518}, + {0.031940, 0.010876, 0.087037}, + {0.181935, 0.039112, 0.202316}, + {0.181810, 0.033189, 0.253435}, + {-0.008677, -0.066679, -0.144737}, + {-0.021768, -0.021288, -0.125903}, + {0.136766, 0.000100, 0.059449}, + {0.135405, -0.020446, 0.103793}, + {-0.289115, 0.039747, -0.012256}, + {-0.338683, 0.025909, -0.034058}, + {-0.016515, 0.048584, 0.197981}, + {-0.046790, 0.011816, 0.199964}, + {0.094214, 0.127422, -0.169936}, + {0.048279, 0.096189, -0.148153}, + {0.217391, 0.081732, 0.013677}, + {0.179656, 0.084671, 0.031434}, + {-0.227367, 0.118176, -0.039803}, + {-0.327096, 0.159747, -0.018931}, + {0.000834, 0.113118, 0.125325}, + {-0.014617, 0.128924, 0.163776}, + {-0.254570, 0.154329, -0.232018}, + {-0.353068, 0.124341, -0.174409}, + {-0.061004, 0.107744, 0.037257}, + {-0.100991, 0.080302, 0.062701}, + {-0.927022, 0.285660, -0.240549}, + {-1.153224, 0.277232, -0.322538}, + {-0.569012, 0.108135, 0.172634}, + {-0.555273, 0.131461, 0.325930}, + {0.518847, 0.065683, -0.132877}, + {0.501324, -0.006585, -0.094884}, + {1.066190, -0.150380, 0.201791}, + {0.858377, -0.166415, 0.081686}, + {0.320584, -0.031499, 0.039534}, + {0.311442, -0.075120, 0.026013}, + {0.625829, -0.019856, 0.346041}, + {0.525271, -0.003948, 0.284868}, + {0.312594, -0.075673, -0.066642}, + {0.295732, -0.057895, -0.042207}, + {0.550446, -0.029110, 0.046850}, + {0.465467, -0.068987, 0.096167}, + {0.122669, -0.051786, 0.044283}, + {0.079669, -0.044145, 0.045805}, + {0.238778, -0.031835, 0.171694}, + {0.200734, -0.072619, 0.178726}, + {0.342512, 0.131270, -0.163021}, + {0.294028, 0.111759, -0.125793}, + {0.589523, 0.121808, -0.049372}, + {0.550506, 0.132318, 0.017485}, + {0.164280, 0.047560, -0.058383}, + {0.120110, 0.049242, -0.052403}, + {0.269181, 0.035000, 0.103494}, + {0.297466, 0.038517, 0.139289}, + {0.094549, -0.030880, -0.153376}, + {0.080363, 0.024359, -0.127578}, + {0.281351, 0.055178, 0.000155}, + {0.234900, 0.039477, 0.013957}, + {-0.118161, 0.011976, -0.034270}, + {-0.157654, 0.027765, -0.005010}, + {0.102631, 0.027283, 0.099723}, + {0.077285, 0.052532, 0.115583}, + {0.329398, -0.278552, 0.016316}, + {0.305993, -0.267896, 0.094952}, + {0.775270, -0.394995, 0.290748}, + {0.583180, -0.252159, 0.285391}, + {0.192226, -0.182242, 0.126859}, + {0.185908, -0.245779, 0.159940}, + {0.346293, -0.250404, 0.355682}, + {0.354160, -0.364521, 0.472337}, + {0.134942, -0.313666, -0.115181}, + {0.126077, -0.286568, -0.039927}, + {0.405618, -0.211792, 0.199095}, + {0.312099, -0.213642, 0.190972}, + {-0.071392, -0.297366, 0.081426}, + {-0.165839, -0.301986, 0.160640}, + {0.147808, -0.290712, 0.298198}, + {0.063302, -0.310149, 0.396302}, + {0.141444, -0.081377, -0.076621}, + {0.115936, -0.104440, -0.039885}, + {0.367023, -0.087281, 0.096390}, + {0.330038, -0.117958, 0.127050}, + {0.002897, -0.062454, 0.025151}, + {-0.052404, -0.082200, 0.041975}, + {0.181553, -0.137004, 0.230489}, + {0.140768, -0.094604, 0.265928}, + {-0.101763, -0.209566, -0.135964}, + {-0.159056, -0.191005, -0.095509}, + {0.045016, -0.081562, 0.075942}, + {0.016808, -0.112482, 0.068593}, + {-0.408578, -0.132377, 0.079163}, + {-0.431534, -0.214646, 0.157714}, + {-0.096931, -0.101938, 0.200304}, + {-0.167867, -0.114851, 0.262964}, + {0.393882, 0.086002, 0.008961}, + {0.338747, 0.048405, -0.004187}, + {0.877844, 0.374373, 0.171008}, + {0.740790, 0.324525, 0.242248}, + {0.200218, 0.070150, 0.085891}, + {0.171760, 0.090531, 0.102579}, + {0.314263, 0.126417, 0.322833}, + {0.313523, 0.065445, 0.403855}, + {0.164261, 0.057745, -0.005490}, + {0.122141, 0.024122, 0.009190}, + {0.308248, 0.078401, 0.180577}, + {0.251222, 0.073868, 0.160457}, + {-0.047526, 0.023725, 0.086336}, + {-0.091643, 0.005539, 0.093179}, + {0.079339, 0.044135, 0.206697}, + {0.104213, 0.011277, 0.240060}, + {0.226607, 0.186234, -0.056881}, + {0.173281, 0.158131, -0.059413}, + {0.339400, 0.214501, 0.052905}, + {0.309166, 0.188181, 0.058028}, + {0.014442, 0.194715, 0.048945}, + {-0.028793, 0.194766, 0.089078}, + {0.069564, 0.206743, 0.193568}, + {0.091532, 0.202786, 0.269680}, + {-0.071196, 0.135604, -0.103744}, + {-0.118288, 0.152837, -0.060151}, + {0.146856, 0.143174, 0.061789}, + {0.104379, 0.143672, 0.056797}, + {-0.541832, 0.250034, -0.017602}, + {-0.641583, 0.278411, -0.111909}, + {-0.094447, 0.159393, 0.164848}, + {-0.113612, 0.120702, 0.221656}, + {0.204918, -0.078894, 0.075524}, + {0.161232, -0.090256, 0.088701}, + {0.378460, -0.033687, 0.309964}, + {0.311701, -0.049984, 0.316881}, + {0.019311, -0.050048, 0.212387}, + {0.002473, -0.062855, 0.278462}, + {0.151448, -0.090652, 0.410031}, + {0.162778, -0.071291, 0.531252}, + {-0.083704, -0.076839, -0.020798}, + {-0.092832, -0.043492, 0.029202}, + {0.136844, -0.077791, 0.186493}, + {0.089536, -0.086826, 0.184711}, + {-0.270255, -0.058858, 0.173048}, + {-0.350416, -0.009219, 0.273260}, + {-0.105248, -0.205534, 0.425159}, + {-0.135030, -0.197464, 0.623550}, + {-0.051717, 0.069756, -0.043829}, + {-0.081050, 0.056947, -0.000205}, + {0.190388, 0.016366, 0.145922}, + {0.142662, 0.002575, 0.159182}, + {-0.352890, 0.011117, 0.091040}, + {-0.367374, 0.056547, 0.147209}, + {-0.003179, 0.026570, 0.282541}, + {-0.069934, -0.005171, 0.337678}, + {-0.496181, 0.026464, 0.019432}, + {-0.690384, 0.069313, -0.004175}, + {-0.146138, 0.046372, 0.161839}, + {-0.197581, 0.034093, 0.241003}, + {-0.989567, 0.040993, 0.049384}, + {-1.151075, 0.210556, 0.237374}, + {-0.335366, -0.058208, 0.480168}, + {-0.502419, -0.093761, 0.675240}, + {0.862548, 0.264137, -0.294905}, + {0.782668, 0.251324, -0.122108}, + {1.597797, 0.463818, -0.133153}, + {1.615756, 0.060653, 0.084764}, + {0.435588, 0.209832, 0.095050}, + {0.431013, 0.165328, 0.047909}, + {1.248164, 0.265923, 0.488086}, + {1.009933, 0.345440, 0.473702}, + {0.477017, 0.194237, -0.058012}, + {0.401362, 0.186915, -0.054137}, + {1.202158, 0.284782, -0.066531}, + {1.064907, 0.203766, 0.046383}, + {0.255848, 0.133398, 0.046049}, + {0.218680, 0.128833, 0.065326}, + {0.490817, 0.182041, 0.286583}, + {0.440714, 0.106576, 0.301120}, + {0.604263, 0.522925, -0.238629}, + {0.526329, 0.377577, -0.198100}, + {1.038632, 0.606242, -0.121253}, + {0.995283, 0.552202, 0.110700}, + {0.262232, 0.313664, -0.086909}, + {0.230835, 0.273385, -0.054268}, + {0.548466, 0.490721, 0.278201}, + {0.466984, 0.355859, 0.289160}, + {0.367137, 0.236160, -0.228114}, + {0.309359, 0.233843, -0.171325}, + {0.465268, 0.276569, 0.010951}, + {0.378124, 0.250237, 0.011131}, + {0.061885, 0.296810, -0.011420}, + {0.000125, 0.350029, -0.011277}, + {0.163815, 0.261191, 0.175863}, + {0.165132, 0.308797, 0.227800}, + {0.461418, 0.052075, -0.016543}, + {0.472372, 0.046962, 0.045746}, + {0.856406, 0.136415, 0.245074}, + {0.834616, 0.003254, 0.372643}, + {0.337869, 0.036994, 0.232513}, + {0.267414, 0.027593, 0.252779}, + {0.584983, 0.113046, 0.583119}, + {0.475406, -0.024234, 0.655070}, + {0.264823, -0.029292, 0.004270}, + {0.246071, -0.019109, 0.030048}, + {0.477401, 0.021039, 0.155448}, + {0.458453, -0.043959, 0.187850}, + {0.067059, -0.061227, 0.126904}, + {0.044608, -0.034575, 0.150205}, + {0.191304, -0.003810, 0.316776}, + {0.153078, 0.029915, 0.361303}, + {0.320704, 0.178950, -0.088835}, + {0.300866, 0.137645, -0.056893}, + {0.553442, 0.162339, 0.131987}, + {0.490083, 0.123682, 0.146163}, + {0.118950, 0.083109, 0.034052}, + {0.099344, 0.066212, 0.054329}, + {0.228325, 0.122445, 0.309219}, + {0.172093, 0.135754, 0.323361}, + {0.064213, 0.063405, -0.058243}, + {0.011906, 0.088795, -0.069678}, + {0.194232, 0.129185, 0.125708}, + {0.155182, 0.174013, 0.144099}, + {-0.217068, 0.112731, 0.093497}, + {-0.307590, 0.171146, 0.110735}, + {-0.014897, 0.138094, 0.232455}, + {-0.036936, 0.170135, 0.279166}, + {0.681886, 0.437121, 0.078458}, + {0.548559, 0.376914, 0.092485}, + {1.259194, 0.901494, 0.256085}, + {1.296139, 0.607949, 0.302184}, + {0.319619, 0.307231, 0.099647}, + {0.287232, 0.359355, 0.186844}, + {0.751306, 0.676688, 0.499386}, + {0.479609, 0.553030, 0.560447}, + {0.276377, 0.214032, -0.003661}, + {0.238146, 0.223595, 0.028806}, + {0.542688, 0.266205, 0.171393}, + {0.460188, 0.283979, 0.158288}, + {0.057385, 0.309853, 0.144517}, + {-0.006881, 0.348152, 0.097310}, + {0.244434, 0.247298, 0.322601}, + {0.253992, 0.335420, 0.402241}, + {0.354006, 0.579776, -0.130176}, + {0.267043, 0.461976, -0.058178}, + {0.534049, 0.626549, 0.046747}, + {0.441835, 0.468260, 0.057556}, + {0.110477, 0.628795, 0.102950}, + {0.031409, 0.489068, 0.090605}, + {0.229564, 0.525640, 0.325454}, + {0.105570, 0.582151, 0.509738}, + {0.005690, 0.521474, -0.157885}, + {0.104463, 0.424022, -0.080647}, + {0.223784, 0.389860, 0.060904}, + {0.159806, 0.340571, 0.062061}, + {-0.173976, 0.573425, 0.027383}, + {-0.376008, 0.587868, 0.133042}, + {-0.051773, 0.348339, 0.231923}, + {-0.122571, 0.473049, 0.251159}, + {0.324321, 0.148510, 0.116006}, + {0.282263, 0.121730, 0.114016}, + {0.690108, 0.256346, 0.418128}, + {0.542523, 0.294427, 0.461973}, + {0.056944, 0.107667, 0.281797}, + {0.027844, 0.106858, 0.355071}, + {0.160456, 0.177656, 0.528819}, + {0.227537, 0.177976, 0.689465}, + {0.111585, 0.097896, 0.109244}, + {0.083994, 0.133245, 0.115789}, + {0.208740, 0.142084, 0.208953}, + {0.156072, 0.143303, 0.231368}, + {-0.185830, 0.214347, 0.309774}, + {-0.311053, 0.240517, 0.328512}, + {-0.041749, 0.090901, 0.511373}, + {-0.156164, 0.098486, 0.478020}, + {0.151543, 0.263073, -0.033471}, + {0.126322, 0.213004, -0.007014}, + {0.245313, 0.217564, 0.120210}, + {0.259136, 0.225542, 0.176601}, + {-0.190632, 0.260214, 0.141755}, + {-0.189271, 0.331768, 0.170606}, + {0.054763, 0.294766, 0.357775}, + {-0.033724, 0.257645, 0.365069}, + {-0.184971, 0.396532, 0.057728}, + {-0.293313, 0.400259, 0.001123}, + {-0.015219, 0.232287, 0.177913}, + {-0.022524, 0.244724, 0.240753}, + {-0.520342, 0.347950, 0.249265}, + {-0.671997, 0.410782, 0.153434}, + {-0.253089, 0.412356, 0.489854}, + {-0.410922, 0.562454, 0.543891} +}; + +/* + * PRBA58 Vector Quantizer Levels + */ +const float AmbePRBA58[128][4] = { + {-0.103660, 0.094597, -0.013149, 0.081501}, + {-0.170709, 0.129958, -0.057316, 0.112324}, + {-0.095113, 0.080892, -0.027554, 0.003371}, + {-0.154153, 0.113437, -0.074522, 0.003446}, + {-0.109553, 0.153519, 0.006858, 0.040930}, + {-0.181931, 0.217882, -0.019042, 0.040049}, + {-0.096246, 0.144191, -0.024147, -0.035120}, + {-0.174811, 0.193357, -0.054261, -0.071700}, + {-0.183241, -0.052840, 0.117923, 0.030960}, + {-0.242634, 0.009075, 0.098007, 0.091643}, + {-0.143847, -0.028529, 0.040171, -0.002812}, + {-0.198809, 0.006990, 0.020668, 0.026641}, + {-0.233172, -0.028793, 0.140130, -0.071927}, + {-0.309313, 0.056873, 0.108262, -0.018930}, + {-0.172782, -0.002037, 0.048755, -0.087065}, + {-0.242901, 0.036076, 0.015064, -0.064366}, + {0.077107, 0.172685, 0.159939, 0.097456}, + {0.024820, 0.209676, 0.087347, 0.105204}, + {0.085113, 0.151639, 0.084272, 0.022747}, + {0.047975, 0.196695, 0.038770, 0.029953}, + {0.113925, 0.236813, 0.176121, 0.016635}, + {0.009708, 0.267969, 0.127660, 0.015872}, + {0.114044, 0.202311, 0.096892, -0.043071}, + {0.047219, 0.260395, 0.050952, -0.046996}, + {-0.055095, 0.034041, 0.200464, 0.039050}, + {-0.061582, 0.069566, 0.113048, 0.027511}, + {-0.025469, 0.040440, 0.132777, -0.039098}, + {-0.031388, 0.064010, 0.067559, -0.017117}, + {-0.074386, 0.086579, 0.228232, -0.055461}, + {-0.107352, 0.120874, 0.137364, -0.030252}, + {-0.036897, 0.089972, 0.155831, -0.128475}, + {-0.059070, 0.097879, 0.084489, -0.075821}, + {-0.050865, -0.025167, -0.086636, 0.011256}, + {-0.051426, 0.013301, -0.144665, 0.038541}, + {-0.073831, -0.028917, -0.142416, -0.025268}, + {-0.083910, 0.015004, -0.227113, -0.002808}, + {-0.030840, -0.009326, -0.070517, -0.041304}, + {-0.022018, 0.029381, -0.124961, -0.031624}, + {-0.064222, -0.014640, -0.108798, -0.092342}, + {-0.038801, 0.038133, -0.188992, -0.094221}, + {-0.154059, -0.183932, -0.019894, 0.082105}, + {-0.188022, -0.113072, -0.117380, 0.090911}, + {-0.243301, -0.207086, -0.053735, -0.001975}, + {-0.275931, -0.121035, -0.161261, 0.004231}, + {-0.118142, -0.157537, -0.036594, -0.008679}, + {-0.153627, -0.111372, -0.103095, -0.009460}, + {-0.173458, -0.180158, -0.057130, -0.103198}, + {-0.208509, -0.127679, -0.149336, -0.109289}, + {0.096310, 0.047927, -0.024094, -0.057018}, + {0.044289, 0.075486, -0.008505, -0.067635}, + {0.076751, 0.025560, -0.066428, -0.102991}, + {0.025215, 0.090417, -0.058616, -0.114284}, + {0.125980, 0.070078, 0.016282, -0.112355}, + {0.070859, 0.118988, 0.001180, -0.116359}, + {0.097520, 0.059219, -0.026821, -0.172850}, + {0.048226, 0.145459, -0.050093, -0.188853}, + {0.007242, -0.135796, 0.147832, -0.034080}, + {0.012843, -0.069616, 0.077139, -0.047909}, + {-0.050911, -0.116323, 0.082521, -0.056362}, + {-0.039630, -0.055678, 0.036066, -0.067992}, + {0.042694, -0.091527, 0.150940, -0.124225}, + {0.029225, -0.039401, 0.071664, -0.113665}, + {-0.025085, -0.099013, 0.074622, -0.138674}, + {-0.031220, -0.035717, 0.020870, -0.143376}, + {0.040638, 0.087903, -0.049500, 0.094607}, + {0.026860, 0.125924, -0.103449, 0.140882}, + {0.075166, 0.110186, -0.115173, 0.067330}, + {0.036642, 0.163193, -0.188762, 0.103724}, + {0.028179, 0.095124, -0.053258, 0.028900}, + {0.002307, 0.148211, -0.096037, 0.046189}, + {0.072227, 0.137595, -0.095629, 0.001339}, + {0.033308, 0.221480, -0.152201, 0.012125}, + {0.003458, -0.085112, 0.041850, 0.113836}, + {-0.040610, -0.044880, 0.029732, 0.177011}, + {0.011404, -0.054324, -0.012426, 0.077815}, + {-0.042413, -0.030930, -0.034844, 0.122946}, + {-0.002206, -0.045698, 0.050651, 0.054886}, + {-0.041729, -0.016110, 0.048005, 0.102125}, + {0.013963, -0.022204, 0.001613, 0.028997}, + {-0.030218, -0.002052, -0.004365, 0.065343}, + {0.299049, 0.046260, 0.076320, 0.070784}, + {0.250160, 0.098440, 0.012590, 0.137479}, + {0.254170, 0.095310, 0.018749, 0.004288}, + {0.218892, 0.145554, -0.035161, 0.069784}, + {0.303486, 0.101424, 0.135996, -0.013096}, + {0.262919, 0.165133, 0.077237, 0.071721}, + {0.319358, 0.170283, 0.054554, -0.072210}, + {0.272983, 0.231181, -0.014471, 0.011689}, + {0.134116, -0.026693, 0.161400, 0.110292}, + {0.100379, 0.026517, 0.086236, 0.130478}, + {0.144718, -0.000895, 0.093767, 0.044514}, + {0.114943, 0.022145, 0.035871, 0.069193}, + {0.122051, 0.011043, 0.192803, 0.022796}, + {0.079482, 0.026156, 0.117725, 0.056565}, + {0.124641, 0.027387, 0.122956, -0.025369}, + {0.090708, 0.027357, 0.064450, 0.013058}, + {0.159781, -0.055202, -0.090597, 0.151598}, + {0.084577, -0.037203, -0.126698, 0.119739}, + {0.192484, -0.100195, -0.162066, 0.104148}, + {0.114579, -0.046270, -0.219547, 0.100067}, + {0.153083, -0.010127, -0.086266, 0.068648}, + {0.088202, -0.010515, -0.102196, 0.046281}, + {0.164494, -0.057325, -0.132860, 0.024093}, + {0.109419, -0.013999, -0.169596, 0.020412}, + {0.039180, -0.209168, -0.035872, 0.087949}, + {0.012790, -0.177723, -0.129986, 0.073364}, + {0.045261, -0.256694, -0.088186, 0.004212}, + {-0.005314, -0.231202, -0.191671, -0.002628}, + {0.037963, -0.153227, -0.045364, 0.003322}, + {0.030800, -0.126452, -0.114266, -0.010414}, + {0.044125, -0.184146, -0.081400, -0.077341}, + {0.029204, -0.157393, -0.172017, -0.089814}, + {0.393519, -0.043228, -0.111365, -0.000740}, + {0.289581, 0.018928, -0.123140, 0.000713}, + {0.311229, -0.059735, -0.198982, -0.081664}, + {0.258659, 0.052505, -0.211913, -0.034928}, + {0.300693, 0.011381, -0.083545, -0.086683}, + {0.214523, 0.053878, -0.101199, -0.061018}, + {0.253422, 0.028496, -0.156752, -0.163342}, + {0.199123, 0.113877, -0.166220, -0.102584}, + {0.249134, -0.165135, 0.028917, 0.051838}, + {0.156434, -0.123708, 0.017053, 0.043043}, + {0.214763, -0.101243, -0.005581, -0.020703}, + {0.140554, -0.072067, -0.015063, -0.011165}, + {0.241791, -0.152048, 0.106403, -0.046857}, + {0.142316, -0.131899, 0.054076, -0.026485}, + {0.206535, -0.086116, 0.046640, -0.097615}, + {0.129759, -0.081874, 0.004693, -0.073169} +}; + +/* + * Higher Order Coefficients + */ +const float AmbeHOCb5[32][4] = { + {0.264108, 0.045976, -0.200999, -0.122344}, + {0.479006, 0.227924, -0.016114, -0.006835}, + {0.077297, 0.080775, -0.068936, 0.041733}, + {0.185486, 0.231840, 0.182410, 0.101613}, + {-0.012442, 0.223718, -0.277803, -0.034370}, + {-0.059507, 0.139621, -0.024708, -0.104205}, + {-0.248676, 0.255502, -0.134894, -0.058338}, + {-0.055122, 0.427253, 0.025059, -0.045051}, + {-0.058898, -0.061945, 0.028030, -0.022242}, + {0.084153, 0.025327, 0.066780, -0.180839}, + {-0.193125, -0.082632, 0.140899, -0.089559}, + {0.000000, 0.033758, 0.276623, 0.002493}, + {-0.396582, -0.049543, -0.118100, -0.208305}, + {-0.287112, 0.096620, 0.049650, -0.079312}, + {-0.543760, 0.171107, -0.062173, -0.010483}, + {-0.353572, 0.227440, 0.230128, -0.032089}, + {0.248579, -0.279824, -0.209589, 0.070903}, + {0.377604, -0.119639, 0.008463, -0.005589}, + {0.102127, -0.093666, -0.061325, 0.052082}, + {0.154134, -0.105724, 0.099317, 0.187972}, + {-0.139232, -0.091146, -0.275479, -0.038435}, + {-0.144169, 0.034314, -0.030840, 0.022207}, + {-0.143985, 0.079414, -0.194701, 0.175312}, + {-0.195329, 0.087467, 0.067711, 0.186783}, + {-0.123515, -0.377873, -0.209929, -0.212677}, + {0.068698, -0.255933, 0.120463, -0.095629}, + {-0.106810, -0.319964, -0.089322, 0.106947}, + {-0.158605, -0.309606, 0.190900, 0.089340}, + {-0.489162, -0.432784, -0.151215, -0.005786}, + {-0.370883, -0.154342, -0.022545, 0.114054}, + {-0.742866, -0.204364, -0.123865, -0.038888}, + {-0.573077, -0.115287, 0.208879, -0.027698} +}; + +/* + * Higher Order Coefficients + */ +const float AmbeHOCb6[16][4] = { + {-0.143886, 0.235528, -0.116707, 0.025541}, + {-0.170182, -0.063822, -0.096934, 0.109704}, + {0.232915, 0.269793, 0.047064, -0.032761}, + {0.153458, 0.068130, -0.033513, 0.126553}, + {-0.440712, 0.132952, 0.081378, -0.013210}, + {-0.480433, -0.249687, -0.012280, 0.007112}, + {-0.088001, 0.167609, 0.148323, -0.119892}, + {-0.104628, 0.102639, 0.183560, 0.121674}, + {0.047408, -0.000908, -0.214196, -0.109372}, + {0.113418, -0.240340, -0.121420, 0.041117}, + {0.385609, 0.042913, -0.184584, -0.017851}, + {0.453830, -0.180745, 0.050455, 0.030984}, + {-0.155984, -0.144212, 0.018226, -0.146356}, + {-0.104028, -0.260377, 0.146472, 0.101389}, + {0.012376, -0.000267, 0.006657, -0.013941}, + {0.165852, -0.103467, 0.119713, -0.075455} +}; + +/* + * Higher Order Coefficients + */ +const float AmbeHOCb7[16][4] = { + {0.182478, 0.271794, -0.057639, 0.026115}, + {0.110795, 0.092854, 0.078125, -0.082726}, + {0.057964, 0.000833, 0.176048, 0.135404}, + {-0.027315, 0.098668, -0.065801, 0.116421}, + {-0.222796, 0.062967, 0.201740, -0.089975}, + {-0.193571, 0.309225, -0.014101, -0.034574}, + {-0.389053, -0.181476, 0.107682, 0.050169}, + {-0.345604, 0.064900, -0.065014, 0.065642}, + {0.319393, -0.055491, -0.220727, -0.067499}, + {0.460572, 0.084686, 0.048453, -0.011050}, + {0.201623, -0.068994, -0.067101, 0.108320}, + {0.227528, -0.173900, 0.092417, -0.066515}, + {-0.016927, 0.047757, -0.177686, -0.102163}, + {-0.052553, -0.065689, 0.019328, -0.033060}, + {-0.144910, -0.238617, -0.195206, -0.063917}, + {-0.024159, -0.338822, 0.003581, 0.060995} +}; + +/* + * Higher Order Coefficients + */ +const float AmbeHOCb8[8][4] = { + {0.323968, 0.008964, -0.063117, 0.027909}, + {0.010900, -0.004030, -0.125016, -0.080818}, + {0.109969, 0.256272, 0.042470, 0.000749}, + {-0.135446, 0.201769, -0.083426, 0.093888}, + {-0.441995, 0.038159, 0.022784, 0.003943}, + {-0.155951, 0.032467, 0.145309, -0.041725}, + {-0.149182, -0.223356, -0.065793, 0.075016}, + {0.096949, -0.096400, 0.083194, 0.049306} +}; +} +#endif diff --git a/mbe/dstar_pitch.h b/mbe/dstar_pitch.h new file mode 100644 index 0000000..4b84482 --- /dev/null +++ b/mbe/dstar_pitch.h @@ -0,0 +1,29 @@ +#ifndef QSO_DSTAR_PITCH_H +#define QSO_DSTAR_PITCH_H +extern "C" { +#define DSTAR_F0_C0 4.24734f +#define DSTAR_F0_C1 0.021762f +#define DSTAR_SPEC_PRED 0.8f +#define DSTAR_GAIN_ADJUST 1.8f +#define DSTAR_GAIN_SMOOTH 0.55f +#define DSTAR_OUT_GAIN_DB 5.4f + +static const unsigned char DSTAR_CHIP_L[120] = { + 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, + 10, 10, 10, 11, 11, 11, 11, 11, 11, 12, 12, 12, + 12, 12, 13, 13, 13, 13, 13, 14, 14, 14, 14, 15, + 15, 15, 15, 15, 16, 16, 16, 16, 17, 17, 17, 17, + 18, 18, 18, 19, 19, 19, 20, 20, 20, 20, 21, 21, + 21, 22, 22, 22, 23, 23, 23, 24, 24, 25, 25, 25, + 26, 26, 27, 27, 27, 28, 28, 29, 29, 30, 30, 30, + 31, 31, 32, 32, 33, 33, 34, 34, 35, 36, 36, 37, + 37, 38, 38, 39, 40, 40, 41, 41, 42, 43, 43, 44, + 45, 45, 46, 47, 47, 48, 49, 50, 50, 51, 52, 53 +}; +#define DSTAR_L(b0) ((int) DSTAR_CHIP_L[((b0) < 0) ? 0 : (((b0) > 119) ? 119 : (b0))]) +#define DSTAR_DEC_VOICED_DB 0.0f +#define DSTAR_DEC_UNVOICED_DB (-4.5f) +#define DSTAR_DEC_PITCH_DB_PER_OCT 1.0f +#define DSTAR_DEC_PITCH_REF_HZ 125.0f +#endif +} diff --git a/mbe/ecc.cpp b/mbe/ecc.cpp new file mode 100644 index 0000000..8134432 --- /dev/null +++ b/mbe/ecc.cpp @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2010 mbelib Author + * GPG Key ID: 0xEA5EFE2C (9E7A 5527 9CDC EBF7 BF1B D772 4F98 E863 EA5E FE2C) + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include "ecc_const.h" +extern "C" { +void +mbe_checkGolayBlock (long int *block) +{ + + static int i, syndrome, eccexpected, eccbits, databits; + long int mask, block_l; + + block_l = *block; + + mask = 0x400000l; + eccexpected = 0; + for (i = 0; i < 12; i++) + { + if ((block_l & mask) != 0l) + { + eccexpected ^= golayGenerator[i]; + } + mask = mask >> 1; + } + eccbits = (int) (block_l & 0x7ffl); + syndrome = eccexpected ^ eccbits; + + databits = (int) (block_l >> 11); + databits = databits ^ golayMatrix[syndrome]; + + *block = (long) databits; +} + +int +mbe_golay2312 (char *in, char *out) +{ + + int i, errs; + long block; + + block = 0; + for (i = 22; i >= 0; i--) + { + block = block << 1; + block = block + in[i]; + } + + mbe_checkGolayBlock (&block); + + for (i = 22; i >= 11; i--) + { + out[i] = (block & 2048) >> 11; + block = block << 1; + } + for (i = 10; i >= 0; i--) + { + out[i] = in[i]; + } + + errs = 0; + for (i = 22; i >= 11; i--) + { + if (out[i] != in[i]) + { + errs++; + } + } + return (errs); +} + +int +mbe_hamming1511 (char *in, char *out) +{ + int i, j, errs, block, syndrome, stmp, stmp2; + + errs = 0; + + block = 0; + for (i = 14; i >= 0; i--) + { + block <<= 1; + block |= in[i]; + } + + syndrome = 0; + for (i = 0; i < 4; i++) + { + syndrome <<= 1; + stmp = block; + stmp &= hammingGenerator[i]; + + stmp2 = (stmp % 2); + for (j = 0; j < 14; j++) + { + stmp >>= 1; + stmp2 ^= (stmp % 2); + } + + syndrome |= stmp2; + } + if (syndrome > 0) + { + errs++; + block ^= hammingMatrix[syndrome]; + } + + for (i = 14; i >= 0; i--) + { + out[i] = (block & 0x4000) >> 14; + block = block << 1; + } + return (errs); +} + +int +mbe_7100x4400hamming1511 (char *in, char *out) +{ + int i, j, errs, block, syndrome, stmp, stmp2; + + errs = 0; + + block = 0; + for (i = 14; i >= 0; i--) + { + block <<= 1; + block |= in[i]; + } + + syndrome = 0; + for (i = 0; i < 4; i++) + { + syndrome <<= 1; + stmp = block; + stmp &= imbe7100x4400hammingGenerator[i]; + + stmp2 = (stmp % 2); + for (j = 0; j < 14; j++) + { + stmp >>= 1; + stmp2 ^= (stmp % 2); + } + + syndrome |= stmp2; + } + if (syndrome > 0) + { + errs++; + block ^= hammingMatrix[syndrome]; + } + + for (i = 14; i >= 0; i--) + { + out[i] = (block & 0x4000) >> 14; + block = block << 1; + } + return (errs); +} +} diff --git a/mbe/ecc_const.h b/mbe/ecc_const.h new file mode 100644 index 0000000..e9c47df --- /dev/null +++ b/mbe/ecc_const.h @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2010 mbelib Author + * GPG Key ID: 0xEA5EFE2C (9E7A 5527 9CDC EBF7 BF1B D772 4F98 E863 EA5E FE2C) + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * constants for ecc.c + */ +#ifndef _ECC_H +#define _ECC_H +extern "C" { +const int hammingGenerator[4] = { + 0x7f08, 0x78e4, 0x66d2, 0x55b1 +}; + +const int imbe7100x4400hammingGenerator[4] = { + 0x7ac8, 0x3d64, 0x1eb2, 0x7591 +}; + +const int hammingMatrix[16] = { + 0x0, 0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80, 0x100, 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000 +}; + +const int golayGenerator[12] = { + 0x63a, 0x31d, 0x7b4, 0x3da, 0x1ed, 0x6cc, 0x366, 0x1b3, 0x6e3, 0x54b, 0x49f, 0x475 +}; + +const int golayMatrix[2048] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 72, 0, 0, 0, 0, 0, 0, 0, 2084, 0, 0, 0, 769, 0, 1024, 144, + 2, 0, 0, 0, 0, 0, 0, 0, 72, 0, 0, 0, 72, 0, 72, 72, 72, 0, 0, 0, 16, 0, 1, 1538, 384, 0, 134, 2048, 1056, 288, + 2576, 5, 72, 0, 0, 0, 0, 0, 0, 0, 1280, 0, 0, 0, 4, 0, 546, 144, 2049, 0, 0, 0, 66, 0, 1, 144, 520, 0, 2056, 144, + 1056, 144, 324, 144, 144, 0, 0, 0, 2688, 0, 1, 32, 22, 0, 272, 3, 1056, 3076, 128, 768, 72, 0, 1, 268, 1056, 1, 1, 2112, 1, 576, + 1056, 1056, 1056, 10, 1, 144, 1056, 0, 0, 0, 0, 0, 0, 0, 1280, 0, 0, 0, 160, 0, 21, 2560, 2, 0, 0, 0, 16, 0, 704, 9, + 2, 0, 2056, 1092, 2, 288, 2, 2, 2, 0, 0, 0, 16, 0, 2050, 132, 545, 0, 1536, 3, 2308, 288, 128, 1040, 72, 0, 16, 16, 16, 288, + 1036, 2112, 16, 288, 65, 648, 16, 288, 288, 288, 2, 0, 0, 0, 1280, 0, 1280, 1280, 1280, 0, 2056, 3, 592, 64, 128, 44, 1280, 0, 2056, 544, + 133, 6, 48, 2112, 1280, 2056, 2056, 256, 2056, 1537, 2056, 144, 2, 0, 100, 3, 8, 536, 128, 2112, 1280, 3, 128, 3, 3, 128, 128, 3, 128, 1152, + 770, 2112, 16, 2112, 1, 2112, 2112, 20, 2056, 3, 1056, 288, 128, 2112, 516, 0, 0, 0, 0, 0, 0, 0, 131, 0, 0, 0, 4, 0, 1024, 2560, + 304, 0, 0, 0, 16, 0, 1024, 320, 520, 0, 1024, 42, 2240, 1024, 1024, 5, 1024, 0, 0, 0, 16, 0, 772, 32, 3072, 0, 2081, 1408, 514, 18, + 128, 5, 72, 0, 16, 16, 16, 2184, 98, 5, 16, 576, 264, 5, 16, 5, 1024, 5, 5, 0, 0, 0, 4, 0, 2128, 32, 520, 0, 4, 4, + 4, 265, 128, 1090, 4, 0, 416, 3073, 520, 6, 520, 520, 520, 576, 19, 256, 4, 2080, 1024, 144, 520, 0, 1034, 32, 321, 32, 128, 32, 32, 576, + 128, 2072, 4, 128, 128, 32, 128, 576, 2052, 130, 16, 1296, 1, 32, 520, 576, 576, 576, 1056, 576, 128, 5, 2306, 0, 0, 0, 16, 0, 40, 2560, + 68, 0, 322, 2560, 1033, 2560, 128, 2560, 2560, 0, 16, 16, 16, 6, 2305, 1184, 16, 129, 548, 256, 16, 88, 1024, 2560, 2, 0, 16, 16, 16, 1089, + 128, 266, 16, 12, 128, 96, 16, 128, 128, 2560, 128, 16, 16, 16, 16, 512, 16, 16, 16, 3074, 16, 16, 16, 288, 128, 5, 16, 0, 513, 200, + 2082, 6, 128, 17, 1280, 1072, 128, 256, 4, 128, 128, 2560, 128, 6, 1088, 256, 16, 6, 6, 6, 520, 256, 2056, 256, 256, 6, 128, 256, 97, 2304, + 128, 1540, 16, 128, 128, 32, 128, 128, 128, 3, 128, 128, 128, 128, 128, 41, 16, 16, 16, 6, 128, 2112, 16, 576, 128, 256, 16, 128, 128, 1032, + 128, 0, 0, 0, 0, 0, 0, 0, 528, 0, 0, 0, 160, 0, 1024, 262, 2049, 0, 0, 0, 66, 0, 1024, 9, 384, 0, 1024, 2048, 28, 1024, + 1024, 608, 1024, 0, 0, 0, 1029, 0, 2050, 32, 384, 0, 272, 2048, 514, 641, 36, 1040, 72, 0, 552, 2048, 384, 84, 384, 384, 384, 2048, 65, 2048, + 2048, 10, 1024, 2048, 384, 0, 0, 0, 66, 0, 140, 32, 2049, 0, 272, 1544, 2049, 64, 2049, 2049, 2049, 0, 66, 66, 66, 2816, 48, 1028, 66, 37, + 640, 256, 66, 10, 1024, 144, 2049, 0, 272, 32, 8, 32, 1600, 32, 32, 272, 272, 196, 272, 10, 272, 32, 2049, 1152, 2052, 529, 66, 10, 1, 32, + 384, 10, 272, 2048, 1056, 10, 10, 10, 516, 0, 0, 0, 160, 0, 2050, 9, 68, 0, 160, 160, 160, 64, 776, 1040, 160, 0, 260, 9, 3584, 9, + 48, 9, 9, 530, 65, 256, 160, 2180, 1024, 9, 2, 0, 2050, 832, 8, 2050, 2050, 1040, 2050, 12, 65, 1040, 160, 1040, 2050, 1040, 1040, 1152, 65, 38, + 16, 512, 2050, 9, 384, 65, 65, 2048, 65, 288, 65, 1040, 516, 0, 513, 2068, 8, 64, 48, 642, 1280, 64, 1030, 256, 160, 64, 64, 64, 2049, 1152, + 48, 256, 66, 48, 48, 9, 48, 256, 2056, 256, 256, 64, 48, 256, 516, 1152, 8, 8, 8, 261, 2050, 32, 8, 2592, 272, 3, 8, 64, 128, 1040, + 516, 1152, 1152, 1152, 8, 1152, 48, 2112, 516, 1152, 65, 256, 516, 10, 516, 516, 516, 0, 0, 0, 2312, 0, 1024, 32, 68, 0, 1024, 81, 514, 1024, + 1024, 136, 1024, 0, 1024, 644, 33, 1024, 1024, 2066, 1024, 1024, 1024, 256, 1024, 1024, 1024, 1024, 1024, 0, 192, 32, 514, 32, 25, 32, 32, 12, 514, 514, + 514, 2368, 1024, 32, 514, 259, 2052, 1096, 16, 512, 1024, 32, 384, 176, 1024, 2048, 514, 1024, 1024, 5, 1024, 0, 513, 32, 1168, 32, 258, 32, 32, 2178, + 104, 256, 4, 532, 1024, 32, 2049, 24, 2052, 256, 66, 193, 1024, 32, 520, 256, 1024, 256, 256, 1024, 1024, 256, 1024, 32, 2052, 32, 32, 32, 32, 32, + 32, 1025, 272, 32, 514, 32, 128, 32, 32, 2052, 2052, 32, 2052, 32, 2052, 32, 32, 576, 2052, 256, 137, 10, 1024, 32, 80, 0, 513, 1026, 68, 400, + 68, 68, 68, 12, 2064, 256, 160, 35, 1024, 2560, 68, 2144, 138, 256, 16, 512, 1024, 9, 68, 256, 1024, 256, 256, 1024, 1024, 256, 1024, 12, 1312, 2177, + 16, 512, 2050, 32, 68, 12, 12, 12, 514, 12, 128, 1040, 257, 512, 16, 16, 16, 512, 512, 512, 16, 12, 65, 256, 16, 512, 1024, 194, 2088, 513, + 513, 256, 513, 3080, 513, 32, 68, 256, 513, 256, 256, 64, 128, 256, 26, 256, 513, 256, 256, 6, 48, 256, 2176, 256, 256, 256, 256, 256, 1024, 256, + 256, 82, 513, 32, 8, 32, 128, 32, 32, 12, 128, 256, 3136, 128, 128, 32, 128, 1152, 2052, 256, 16, 512, 328, 32, 1027, 256, 34, 256, 256, 2065, + 128, 256, 516, 0, 0, 0, 0, 0, 0, 0, 528, 0, 0, 0, 4, 0, 2432, 1057, 2, 0, 0, 0, 1160, 0, 1, 320, 2, 0, 112, 2048, + 2, 524, 2, 2, 2, 0, 0, 0, 290, 0, 1, 132, 3072, 0, 1536, 2048, 145, 18, 36, 768, 72, 0, 1, 2048, 580, 1, 1, 56, 1, 2048, + 264, 2048, 2048, 1216, 1, 2048, 2, 0, 0, 0, 4, 0, 1, 2058, 224, 0, 4, 4, 4, 64, 1048, 768, 4, 0, 1, 544, 2320, 1, 1, 1028, + 1, 1282, 640, 73, 4, 2080, 1, 144, 2, 0, 1, 1104, 8, 1, 1, 768, 1, 168, 2114, 768, 4, 768, 1, 768, 768, 1, 1, 130, 1, 1, + 1, 1, 1, 20, 1, 2048, 1056, 1, 1, 768, 1, 0, 0, 0, 2113, 0, 40, 132, 2, 0, 1536, 280, 2, 64, 2, 2, 2, 0, 260, 544, + 2, 3088, 2, 2, 2, 129, 2, 2, 2, 2, 2, 2, 2, 0, 1536, 132, 8, 132, 336, 132, 132, 1536, 1536, 96, 1536, 2057, 1536, 132, 2, 74, + 2208, 1281, 16, 512, 1, 132, 2, 20, 1536, 2048, 2, 288, 2, 2, 2, 0, 146, 544, 8, 64, 2564, 17, 1280, 64, 289, 3200, 4, 64, 64, 64, + 2, 544, 1088, 544, 544, 392, 1, 544, 2, 20, 2056, 544, 2, 64, 2, 2, 2, 2304, 8, 8, 8, 1058, 1, 132, 8, 20, 1536, 3, 8, 64, + 128, 768, 2096, 20, 1, 544, 8, 1, 1, 2112, 1, 20, 20, 20, 448, 20, 1, 1032, 2, 0, 0, 0, 4, 0, 40, 320, 3072, 0, 4, 4, + 4, 18, 577, 136, 4, 0, 2562, 320, 33, 320, 148, 320, 320, 129, 264, 1552, 4, 2080, 1024, 320, 2, 0, 192, 521, 3072, 18, 3072, 3072, 3072, 18, + 264, 96, 4, 18, 18, 18, 3072, 1060, 264, 130, 16, 512, 1, 320, 3072, 264, 264, 2048, 264, 18, 264, 5, 672, 0, 4, 4, 4, 1664, 258, 17, + 4, 4, 4, 4, 4, 2080, 4, 4, 4, 24, 1088, 130, 4, 2080, 1, 320, 520, 2080, 4, 4, 4, 2080, 2080, 2080, 4, 2304, 560, 130, 4, 76, + 1, 32, 3072, 1025, 4, 4, 4, 18, 128, 768, 4, 130, 1, 130, 130, 1, 1, 130, 1, 576, 264, 130, 4, 2080, 1, 1032, 80, 0, 40, 1026, + 896, 40, 40, 17, 40, 129, 2064, 96, 4, 1284, 40, 2560, 2, 129, 1088, 2060, 16, 512, 40, 320, 2, 129, 129, 129, 2, 129, 2, 2, 2, 2304, + 7, 96, 16, 512, 40, 132, 3072, 96, 1536, 96, 96, 18, 128, 96, 257, 512, 16, 16, 16, 512, 512, 512, 16, 129, 264, 96, 16, 512, 2116, 1032, + 2, 2304, 1088, 17, 4, 17, 40, 17, 17, 522, 4, 4, 4, 64, 128, 17, 4, 1088, 1088, 544, 1088, 6, 1088, 17, 2176, 129, 1088, 256, 4, 2080, + 784, 1032, 2, 2304, 2304, 2304, 8, 2304, 128, 17, 578, 2304, 128, 96, 4, 128, 128, 1032, 128, 2304, 1088, 130, 16, 512, 1, 1032, 292, 20, 34, 1032, + 2561, 1032, 128, 1032, 1032, 0, 0, 0, 528, 0, 528, 528, 528, 0, 11, 2048, 1344, 64, 36, 136, 528, 0, 260, 2048, 33, 162, 2120, 1028, 528, 2048, + 640, 2048, 2048, 273, 1024, 2048, 2, 0, 192, 2048, 8, 1288, 36, 67, 528, 2048, 36, 2048, 2048, 36, 36, 2048, 36, 2048, 1042, 2048, 2048, 512, 1, 2048, + 384, 2048, 2048, 2048, 2048, 2048, 36, 2048, 2048, 0, 3104, 385, 8, 64, 258, 1028, 528, 64, 640, 50, 4, 64, 64, 64, 2049, 24, 640, 1028, 66, 1028, + 1, 1028, 1028, 640, 640, 2048, 640, 64, 640, 1028, 296, 518, 8, 8, 8, 2192, 1, 32, 8, 1025, 272, 2048, 8, 64, 36, 768, 1154, 352, 1, 2048, + 8, 1, 1, 1028, 1, 2048, 640, 2048, 2048, 10, 1, 2048, 80, 0, 260, 1026, 8, 64, 1153, 2336, 528, 64, 2064, 517, 160, 64, 64, 64, 2, 260, + 260, 208, 260, 512, 260, 9, 2, 1064, 260, 2048, 2, 64, 2, 2, 2, 49, 8, 8, 8, 512, 2050, 132, 8, 386, 1536, 2048, 8, 64, 36, 1040, + 257, 512, 260, 2048, 8, 512, 512, 512, 1120, 2048, 65, 2048, 2048, 512, 152, 2048, 2, 64, 8, 8, 8, 64, 64, 64, 8, 64, 64, 64, 8, 64, + 64, 64, 64, 2051, 260, 544, 8, 64, 48, 1028, 2176, 64, 640, 256, 1041, 64, 64, 64, 2, 8, 8, 8, 8, 64, 8, 8, 8, 64, 8, 8, + 8, 64, 64, 64, 8, 1152, 8, 8, 8, 512, 1, 274, 8, 20, 34, 2048, 8, 64, 3328, 161, 516, 0, 192, 1026, 33, 2053, 258, 136, 528, 800, + 2064, 136, 4, 136, 1024, 136, 136, 24, 33, 33, 33, 512, 1024, 320, 33, 70, 1024, 2048, 33, 1024, 1024, 136, 1024, 192, 192, 276, 192, 512, 192, 32, + 3072, 1025, 192, 2048, 514, 18, 36, 136, 257, 512, 192, 2048, 33, 512, 512, 512, 14, 2048, 264, 2048, 2048, 512, 1024, 2048, 80, 24, 258, 2624, 4, 258, + 258, 32, 258, 1025, 4, 4, 4, 64, 258, 136, 4, 24, 24, 24, 33, 24, 258, 1028, 2176, 24, 640, 256, 4, 2080, 1024, 515, 80, 1025, 192, 32, + 8, 32, 258, 32, 32, 1025, 1025, 1025, 4, 1025, 2568, 32, 80, 24, 2052, 130, 1792, 512, 1, 32, 80, 1025, 34, 2048, 80, 388, 80, 80, 80, 1026, + 2064, 1026, 1026, 512, 40, 1026, 68, 2064, 2064, 1026, 2064, 64, 2064, 136, 257, 512, 260, 1026, 33, 512, 512, 512, 2176, 129, 2064, 256, 584, 512, 1024, 52, + 2, 512, 192, 1026, 8, 512, 512, 512, 257, 12, 2064, 96, 257, 512, 257, 257, 257, 512, 512, 512, 16, 512, 512, 512, 512, 512, 34, 2048, 1156, 512, + 512, 512, 257, 164, 513, 1026, 8, 64, 258, 17, 2176, 64, 2064, 256, 4, 64, 64, 64, 1568, 24, 1088, 256, 2176, 512, 2176, 2176, 2176, 256, 34, 256, + 256, 64, 13, 256, 2176, 2304, 8, 8, 8, 512, 1044, 32, 8, 1025, 34, 656, 8, 64, 128, 2054, 257, 512, 34, 69, 8, 512, 512, 512, 2176, 34, + 34, 256, 34, 512, 34, 1032, 80 +}; +} +#endif diff --git a/mbe/mbelib.cpp b/mbe/mbelib.cpp new file mode 100644 index 0000000..4fa834c --- /dev/null +++ b/mbe/mbelib.cpp @@ -0,0 +1,501 @@ +/* + * Copyright (C) 2010 mbelib Author + * GPG Key ID: 0xEA5EFE2C (9E7A 5527 9CDC EBF7 BF1B D772 4F98 E863 EA5E FE2C) + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include + +#include "mbelib.h" +#include "mbelib_const.h" + +/** + * \return A pseudo-random float between [0.0, 1.0]. + * See http://www.azillionmonkeys.com/qed/random.html for further improvements + */ +static float +mbe_rand() +{ + return ((float) rand () / (float) RAND_MAX); +} + +/** + * \return A pseudo-random float between [-pi, +pi]. + */ +static float +mbe_rand_phase() +{ + return mbe_rand() * (((float)M_PI) * 2.0F) - ((float)M_PI); +} + +void +mbe_printVersion (char *str) +{ + sprintf (str, "%s", MBELIB_VERSION); +} + +void +mbe_moveMbeParms (mbe_parms * cur_mp, mbe_parms * prev_mp) +{ + + int l; + + prev_mp->w0 = cur_mp->w0; + prev_mp->L = cur_mp->L; + prev_mp->K = cur_mp->K; // necessary? + prev_mp->Ml[0] = (float) 0; + prev_mp->gamma = cur_mp->gamma; + prev_mp->repeat = cur_mp->repeat; + for (l = 0; l <= 56; l++) + { + prev_mp->Ml[l] = cur_mp->Ml[l]; + prev_mp->Vl[l] = cur_mp->Vl[l]; + prev_mp->log2Ml[l] = cur_mp->log2Ml[l]; + prev_mp->PHIl[l] = cur_mp->PHIl[l]; + prev_mp->PSIl[l] = cur_mp->PSIl[l]; + } +} + +void +mbe_useLastMbeParms (mbe_parms * cur_mp, mbe_parms * prev_mp) +{ + + int l; + + cur_mp->w0 = prev_mp->w0; + cur_mp->L = prev_mp->L; + cur_mp->K = prev_mp->K; // necessary? + cur_mp->Ml[0] = (float) 0; + cur_mp->gamma = prev_mp->gamma; + cur_mp->repeat = prev_mp->repeat; + for (l = 0; l <= 56; l++) + { + cur_mp->Ml[l] = prev_mp->Ml[l]; + cur_mp->Vl[l] = prev_mp->Vl[l]; + cur_mp->log2Ml[l] = prev_mp->log2Ml[l]; + cur_mp->PHIl[l] = prev_mp->PHIl[l]; + cur_mp->PSIl[l] = prev_mp->PSIl[l]; + } +} + +void +mbe_initMbeParms (mbe_parms * cur_mp, mbe_parms * prev_mp, mbe_parms * prev_mp_enhanced) +{ + + int l; + + prev_mp->w0 = 0.09378; + prev_mp->L = 30; + prev_mp->K = 10; + prev_mp->gamma = (float) 0; + for (l = 0; l <= 56; l++) + { + prev_mp->Ml[l] = (float) 0; + prev_mp->Vl[l] = 0; + prev_mp->log2Ml[l] = (float) 0; // log2 of 1 == 0 + prev_mp->PHIl[l] = (float) 0; + prev_mp->PSIl[l] = (M_PI / (float) 2); + } + prev_mp->repeat = 0; + mbe_moveMbeParms (prev_mp, cur_mp); + mbe_moveMbeParms (prev_mp, prev_mp_enhanced); +} + +void +mbe_spectralAmpEnhance (mbe_parms * cur_mp) +{ + + float Rm0, Rm1, R2m0, R2m1, Wl[57]; + int l; + float sum, gamma, M; + + Rm0 = 0; + Rm1 = 0; + for (l = 1; l <= cur_mp->L; l++) + { + Rm0 = Rm0 + (cur_mp->Ml[l] * cur_mp->Ml[l]); + Rm1 = Rm1 + ((cur_mp->Ml[l] * cur_mp->Ml[l]) * cosf (cur_mp->w0 * (float) l)); + } + + R2m0 = (Rm0*Rm0); + R2m1 = (Rm1*Rm1); + + for (l = 1; l <= cur_mp->L; l++) + { + if (cur_mp->Ml[l] != 0) + { + Wl[l] = sqrtf (cur_mp->Ml[l]) * powf ((((float) 0.96 * M_PI * ((R2m0 + R2m1) - ((float) 2 * Rm0 * Rm1 * cosf (cur_mp->w0 * (float) l)))) / (cur_mp->w0 * Rm0 * (R2m0 - R2m1))), (float) 0.25); + + if ((8 * l) <= cur_mp->L) + { + } + else if (Wl[l] > 1.2) + { + cur_mp->Ml[l] = 1.2 * cur_mp->Ml[l]; + } + else if (Wl[l] < 0.5) + { + cur_mp->Ml[l] = 0.5 * cur_mp->Ml[l]; + } + else + { + cur_mp->Ml[l] = Wl[l] * cur_mp->Ml[l]; + } + } + } + + // generate scaling factor + sum = 0; + for (l = 1; l <= cur_mp->L; l++) + { + M = cur_mp->Ml[l]; + if (M < 0) + { + M = -M; + } + sum += (M*M); + } + if (sum == 0) + { + gamma = (float) 1.0; + } + else + { + gamma = sqrtf (Rm0 / sum); + } + + // apply scaling factor + for (l = 1; l <= cur_mp->L; l++) + { + cur_mp->Ml[l] = gamma * cur_mp->Ml[l]; + } +} + +void +mbe_synthesizeSilencef (float *aout_buf) +{ + + int n; + float *aout_buf_p; + + aout_buf_p = aout_buf; + for (n = 0; n < 160; n++) + { + *aout_buf_p = (float) 0; + aout_buf_p++; + } +} + +void +mbe_synthesizeSilence (short *aout_buf) +{ + + int n; + short *aout_buf_p; + + aout_buf_p = aout_buf; + for (n = 0; n < 160; n++) + { + *aout_buf_p = (short) 0; + aout_buf_p++; + } +} + +void +mbe_synthesizeSpeechf (float *aout_buf, mbe_parms * cur_mp, mbe_parms * prev_mp, int uvquality) +{ + + int i, l, n, maxl; + float *Ss, loguvquality; + float C1, C2, C3, C4; + //float deltaphil, deltawl, thetaln, aln; + int numUv; + float cw0, pw0, cw0l, pw0l; + float uvsine, uvrand, uvthreshold, uvthresholdf; + float uvstep, uvoffset; + float qfactor; + float rphase[64], rphase2[64]; + + const int N = 160; + + uvthresholdf = (float) 2700; + uvthreshold = ((uvthresholdf * M_PI) / (float) 4000); + + // voiced/unvoiced/gain settings + uvsine = (float) 1.3591409 *M_E; + uvrand = (float) 2.0; + + if ((uvquality < 1) || (uvquality > 64)) + { + printf ("\nmbelib: Error - uvquality must be within the range 1 - 64, setting to default value of 3\n"); + uvquality = 3; + } + + // calculate loguvquality + if (uvquality == 1) + { + loguvquality = (float) 1 / M_E; + } + else + { + loguvquality = log ((float) uvquality) / (float) uvquality; + } + + // calculate unvoiced step and offset values + uvstep = (float) 1.0 / (float) uvquality; + qfactor = loguvquality; + uvoffset = (uvstep * (float) (uvquality - 1)) / (float) 2; + + // count number of unvoiced bands + numUv = 0; + for (l = 1; l <= cur_mp->L; l++) + { + if (cur_mp->Vl[l] == 0) + { + numUv++; + } + } + + cw0 = cur_mp->w0; + pw0 = prev_mp->w0; + + // init aout_buf + Ss = aout_buf; + for (n = 0; n < N; n++) + { + *Ss = (float) 0; + Ss++; + } + + // eq 128 and 129 + if (cur_mp->L > prev_mp->L) + { + maxl = cur_mp->L; + for (l = prev_mp->L + 1; l <= maxl; l++) + { + prev_mp->Ml[l] = (float) 0; + prev_mp->Vl[l] = 1; + } + } + else + { + maxl = prev_mp->L; + for (l = cur_mp->L + 1; l <= maxl; l++) + { + cur_mp->Ml[l] = (float) 0; + cur_mp->Vl[l] = 1; + } + } + + // update phil from eq 139,140 + for (l = 1; l <= 56; l++) + { + cur_mp->PSIl[l] = prev_mp->PSIl[l] + ((pw0 + cw0) * ((float) (l * N) / (float) 2)); + if (l <= (int) (cur_mp->L / 4)) + { + cur_mp->PHIl[l] = cur_mp->PSIl[l]; + } + else + { + cur_mp->PHIl[l] = cur_mp->PSIl[l] + ((numUv * mbe_rand_phase()) / cur_mp->L); + } + } + + for (l = 1; l <= maxl; l++) + { + cw0l = (cw0 * (float) l); + pw0l = (pw0 * (float) l); + if ((cur_mp->Vl[l] == 0) && (prev_mp->Vl[l] == 1)) + { + Ss = aout_buf; + // init random phase + for (i = 0; i < uvquality; i++) + { + rphase[i] = mbe_rand_phase(); + } + for (n = 0; n < N; n++) + { + C1 = 0; + // eq 131 + C1 = Ws[n + N] * prev_mp->Ml[l] * cosf ((pw0l * (float) n) + prev_mp->PHIl[l]); + C3 = 0; + // unvoiced multisine mix + for (i = 0; i < uvquality; i++) + { + C3 = C3 + cosf ((cw0 * (float) n * ((float) l + ((float) i * uvstep) - uvoffset)) + rphase[i]); + if (cw0l > uvthreshold) + { + C3 = C3 + ((cw0l - uvthreshold) * uvrand * mbe_rand()); + } + } + C3 = C3 * uvsine * Ws[n] * cur_mp->Ml[l] * qfactor; + *Ss = *Ss + C1 + C3; + Ss++; + } + } + else if ((cur_mp->Vl[l] == 1) && (prev_mp->Vl[l] == 0)) + { + Ss = aout_buf; + // init random phase + for (i = 0; i < uvquality; i++) + { + rphase[i] = mbe_rand_phase(); + } + for (n = 0; n < N; n++) + { + C1 = 0; + // eq 132 + C1 = Ws[n] * cur_mp->Ml[l] * cosf ((cw0l * (float) (n - N)) + cur_mp->PHIl[l]); + C3 = 0; + // unvoiced multisine mix + for (i = 0; i < uvquality; i++) + { + C3 = C3 + cosf ((pw0 * (float) n * ((float) l + ((float) i * uvstep) - uvoffset)) + rphase[i]); + if (pw0l > uvthreshold) + { + C3 = C3 + ((pw0l - uvthreshold) * uvrand * mbe_rand()); + } + } + C3 = C3 * uvsine * Ws[n + N] * prev_mp->Ml[l] * qfactor; + *Ss = *Ss + C1 + C3; + Ss++; + } + } +// else if (((cur_mp->Vl[l] == 1) || (prev_mp->Vl[l] == 1)) && ((l >= 8) || (fabsf (cw0 - pw0) >= ((float) 0.1 * cw0)))) + else if ((cur_mp->Vl[l] == 1) || (prev_mp->Vl[l] == 1)) + { + Ss = aout_buf; + for (n = 0; n < N; n++) + { + C1 = 0; + // eq 133-1 + C1 = Ws[n + N] * prev_mp->Ml[l] * cosf ((pw0l * (float) n) + prev_mp->PHIl[l]); + C2 = 0; + // eq 133-2 + C2 = Ws[n] * cur_mp->Ml[l] * cosf ((cw0l * (float) (n - N)) + cur_mp->PHIl[l]); + *Ss = *Ss + C1 + C2; + Ss++; + } + } +/* + // expensive and unnecessary? + else if ((cur_mp->Vl[l] == 1) || (prev_mp->Vl[l] == 1)) + { + Ss = aout_buf; + // eq 137 + deltaphil = cur_mp->PHIl[l] - prev_mp->PHIl[l] - (((pw0 + cw0) * (float) (l * N)) / (float) 2); + // eq 138 + deltawl = ((float) 1 / (float) N) * (deltaphil - ((float) 2 * M_PI * (int) ((deltaphil + M_PI) / (M_PI * (float) 2)))); + for (n = 0; n < N; n++) + { + // eq 136 + thetaln = prev_mp->PHIl[l] + ((pw0l + deltawl) * (float) n) + (((cw0 - pw0) * ((float) (l * n * n)) / (float) (2 * N))); + // eq 135 + aln = prev_mp->Ml[l] + (((float) n / (float) N) * (cur_mp->Ml[l] - prev_mp->Ml[l])); + // eq 134 + *Ss = *Ss + (aln * cosf (thetaln)); + Ss++; + } + } +*/ + else + { + Ss = aout_buf; + // init random phase + for (i = 0; i < uvquality; i++) + { + rphase[i] = mbe_rand_phase(); + } + // init random phase + for (i = 0; i < uvquality; i++) + { + rphase2[i] = mbe_rand_phase(); + } + for (n = 0; n < N; n++) + { + C3 = 0; + // unvoiced multisine mix + for (i = 0; i < uvquality; i++) + { + C3 = C3 + cosf ((pw0 * (float) n * ((float) l + ((float) i * uvstep) - uvoffset)) + rphase[i]); + if (pw0l > uvthreshold) + { + C3 = C3 + ((pw0l - uvthreshold) * uvrand * mbe_rand()); + } + } + C3 = C3 * uvsine * Ws[n + N] * prev_mp->Ml[l] * qfactor; + C4 = 0; + // unvoiced multisine mix + for (i = 0; i < uvquality; i++) + { + C4 = C4 + cosf ((cw0 * (float) n * ((float) l + ((float) i * uvstep) - uvoffset)) + rphase2[i]); + if (cw0l > uvthreshold) + { + C4 = C4 + ((cw0l - uvthreshold) * uvrand * mbe_rand()); + } + } + C4 = C4 * uvsine * Ws[n] * cur_mp->Ml[l] * qfactor; + *Ss = *Ss + C3 + C4; + Ss++; + } + } + } +} + +void +mbe_synthesizeSpeech (short *aout_buf, mbe_parms * cur_mp, mbe_parms * prev_mp, int uvquality) +{ + float float_buf[160]; + + mbe_synthesizeSpeechf (float_buf, cur_mp, prev_mp, uvquality); + mbe_floattoshort (float_buf, aout_buf); +} + +void +mbe_floattoshort (float *float_buf, short *aout_buf) +{ + + short *aout_buf_p; + float *float_buf_p; + int i, again; + float audio; + + again = 7; + aout_buf_p = aout_buf; + float_buf_p = float_buf; + for (i = 0; i < 160; i++) + { + audio = again * *float_buf_p; + if (audio > 32760) + { +#ifdef MBE_DEBUG + printf ("audio clip: %f\n", audio); +#endif + audio = 32760; + } + else if (audio < -32760) + { +#ifdef MBE_DEBUG + printf ("audio clip: %f\n", audio); +#endif + audio = -32760; + } + *aout_buf_p = (short) (audio); + aout_buf_p++; + float_buf_p++; + } +} + diff --git a/mbe/mbelib.h b/mbe/mbelib.h new file mode 100644 index 0000000..5079f22 --- /dev/null +++ b/mbe/mbelib.h @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2010 mbelib Author + * GPG Key ID: 0xEA5EFE2C (9E7A 5527 9CDC EBF7 BF1B D772 4F98 E863 EA5E FE2C) + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _MBELIB_H +#define _MBELIB_H + +#define MBELIB_VERSION "1.3.0" +extern "C" { +struct mbe_parameters +{ + float w0; + int L; + int K; + int Vl[57]; + float Ml[57]; + float log2Ml[57]; + float PHIl[57]; + float PSIl[57]; + float gamma; + int un; + int repeat; +}; + +typedef struct mbe_parameters mbe_parms; + +/* + * Prototypes from ecc.c + */ +void mbe_checkGolayBlock (long int *block); +int mbe_golay2312 (char *in, char *out); +int mbe_hamming1511 (char *in, char *out); +int mbe_7100x4400hamming1511 (char *in, char *out); + +/* + * Prototypes from ambe3600x2400.c + */ +int mbe_eccAmbe3600x2400C0 (char ambe_fr[4][24]); +int mbe_eccAmbe3600x2400Data (char ambe_fr[4][24], char *ambe_d); +int mbe_decodeAmbe2400Parms (char *ambe_d, mbe_parms * cur_mp, mbe_parms * prev_mp); +void mbe_demodulateAmbe3600x2400Data (char ambe_fr[4][24]); +void mbe_processAmbe2400Dataf (float *aout_buf, int *errs2, char *err_str, char ambe_d[49], mbe_parms * cur_mp, mbe_parms * prev_mp, mbe_parms * prev_mp_enhanced, int uvquality); +void mbe_processAmbe2400Data (short *aout_buf, int *errs2, char *err_str, char ambe_d[49], mbe_parms * cur_mp, mbe_parms * prev_mp, mbe_parms * prev_mp_enhanced, int uvquality); +void mbe_processAmbe3600x2400Framef (float *aout_buf, int *errs2, char *err_str, char ambe_fr[4][24], char ambe_d[49], mbe_parms * cur_mp, mbe_parms * prev_mp, mbe_parms * prev_mp_enhanced, int uvquality); +void mbe_processAmbe3600x2400Frame (short *aout_buf, int *errs2, char *err_str, char ambe_fr[4][24], char ambe_d[49], mbe_parms * cur_mp, mbe_parms * prev_mp, mbe_parms * prev_mp_enhanced, int uvquality); + +/* + * Prototypes from ambe3600x2450.c + */ +int mbe_eccAmbe3600x2450C0 (char ambe_fr[4][24]); +int mbe_eccAmbe3600x2450Data (char ambe_fr[4][24], char *ambe_d); +int mbe_decodeAmbe2450Parms (char *ambe_d, mbe_parms * cur_mp, mbe_parms * prev_mp); +void mbe_demodulateAmbe3600x2450Data (char ambe_fr[4][24]); +void mbe_processAmbe2450Dataf (float *aout_buf, int *errs2, char *err_str, char ambe_d[49], mbe_parms * cur_mp, mbe_parms * prev_mp, mbe_parms * prev_mp_enhanced, int uvquality); +void mbe_processAmbe2450Data (short *aout_buf, int *errs2, char *err_str, char ambe_d[49], mbe_parms * cur_mp, mbe_parms * prev_mp, mbe_parms * prev_mp_enhanced, int uvquality); +void mbe_processAmbe3600x2450Framef (float *aout_buf, int *errs2, char *err_str, char ambe_fr[4][24], char ambe_d[49], mbe_parms * cur_mp, mbe_parms * prev_mp, mbe_parms * prev_mp_enhanced, int uvquality); +void mbe_processAmbe3600x2450Frame (short *aout_buf, int *errs2, char *err_str, char ambe_fr[4][24], char ambe_d[49], mbe_parms * cur_mp, mbe_parms * prev_mp, mbe_parms * prev_mp_enhanced, int uvquality); + +/* + * Prototypes from imbe7200x4400.c + */ +void mbe_dumpImbe4400Data (char *imbe_d); +void mbe_dumpImbe7200x4400Data (char *imbe_d); +void mbe_dumpImbe7200x4400Frame (char imbe_fr[8][23]); +int mbe_eccImbe7200x4400C0 (char imbe_fr[8][23]); +int mbe_eccImbe7200x4400Data (char imbe_fr[8][23], char *imbe_d); +int mbe_decodeImbe4400Parms (char *imbe_d, mbe_parms * cur_mp, mbe_parms * prev_mp); +void mbe_demodulateImbe7200x4400Data (char imbe[8][23]); +void mbe_processImbe4400Dataf (float *aout_buf, int *errs2, char *err_str, char imbe_d[88], mbe_parms * cur_mp, mbe_parms * prev_mp, mbe_parms * prev_mp_enhanced, int uvquality); +void mbe_processImbe4400Data (short *aout_buf, int *errs2, char *err_str, char imbe_d[88], mbe_parms * cur_mp, mbe_parms * prev_mp, mbe_parms * prev_mp_enhanced, int uvquality); +void mbe_processImbe7200x4400Framef (float *aout_buf, int *errs2, char *err_str, char imbe_fr[8][23], char imbe_d[88], mbe_parms * cur_mp, mbe_parms * prev_mp, mbe_parms * prev_mp_enhanced, int uvquality); +void mbe_processImbe7200x4400Frame (short *aout_buf, int *errs2, char *err_str, char imbe_fr[8][23], char imbe_d[88], mbe_parms * cur_mp, mbe_parms * prev_mp, mbe_parms * prev_mp_enhanced, int uvquality); + +/* + * Prototypes from imbe7100x4400.c + */ +void mbe_dumpImbe7100x4400Data (char *imbe_d); +void mbe_dumpImbe7100x4400Frame (char imbe_fr[7][24]); +int mbe_eccImbe7100x4400C0 (char imbe_fr[7][24]); +int mbe_eccImbe7100x4400Data (char imbe_fr[7][24], char *imbe_d); +void mbe_demodulateImbe7100x4400Data (char imbe[7][24]); +void mbe_convertImbe7100to7200 (char *imbe_d); +void mbe_processImbe7100x4400Framef (float *aout_buf, int *errs, int *errs2, char *err_str, char imbe_fr[7][24], char imbe_d[88], mbe_parms * cur_mp, mbe_parms * prev_mp, mbe_parms * prev_mp_enhanced, int uvquality); +void mbe_processImbe7100x4400Frame (short *aout_buf, int *errs, int *errs2, char *err_str, char imbe_fr[7][24], char imbe_d[88], mbe_parms * cur_mp, mbe_parms * prev_mp, mbe_parms * prev_mp_enhanced, int uvquality); + +/* + * Prototypes from mbelib.c + */ +void mbe_printVersion (char *str); +void mbe_moveMbeParms (mbe_parms * cur_mp, mbe_parms * prev_mp); +void mbe_useLastMbeParms (mbe_parms * cur_mp, mbe_parms * prev_mp); +void mbe_initMbeParms (mbe_parms * cur_mp, mbe_parms * prev_mp, mbe_parms * prev_mp_enhanced); +void mbe_spectralAmpEnhance (mbe_parms * cur_mp); +void mbe_synthesizeSilencef (float *aout_buf); +void mbe_synthesizeSilence (short *aout_buf); +void mbe_synthesizeSpeechf (float *aout_buf, mbe_parms * cur_mp, mbe_parms * prev_mp, int uvquality); +void mbe_synthesizeSpeech (short *aout_buf, mbe_parms * cur_mp, mbe_parms * prev_mp, int uvquality); +void mbe_floattoshort (float *float_buf, short *aout_buf); + +} +#endif diff --git a/mbe/mbelib_const.h b/mbe/mbelib_const.h new file mode 100644 index 0000000..80215d6 --- /dev/null +++ b/mbe/mbelib_const.h @@ -0,0 +1,371 @@ +/* + * Copyright (C) 2010 mbelib Author + * GPG Key ID: 0xEA5EFE2C (9E7A 5527 9CDC EBF7 BF1B D772 4F98 E863 EA5E FE2C) + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _MBELIB_CONST_H +#define _MBELIB_CONST_H +extern "C" { +/* + * Speech Synthesis Window 8k version + */ +const float Ws[321] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0.02, 0.04, 0.06, 0.08, 0.1, 0.12, 0.14, 0.16, 0.18, + 0.2, 0.22, 0.24, 0.26, 0.28, 0.3, 0.32, 0.34, 0.36, 0.38, + 0.4, 0.42, 0.44, 0.46, 0.48, 0.5, 0.52, 0.54, 0.56, 0.58, + 0.6, 0.62, 0.64, 0.66, 0.68, 0.7, 0.72, 0.74, 0.76, 0.78, + 0.8, 0.82, 0.84, 0.86, 0.88, 0.9, 0.92, 0.94, 0.96, 0.98, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 0.98, 0.96, 0.94, 0.92, 0.9, 0.88, 0.86, 0.84, 0.82, 0.8, + 0.78, 0.76, 0.74, 0.72, 0.7, 0.68, 0.66, 0.64, 0.62, 0.6, + 0.58, 0.56, 0.54, 0.52, 0.5, 0.48, 0.46, 0.44, 0.42, 0.4, + 0.38, 0.36, 0.34, 0.32, 0.3, 0.28, 0.26, 0.24, 0.22, 0.2, + 0.18, 0.16, 0.14, 0.12, 0.1, 0.08, 0.06, 0.04, 0.02, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* + * Speech Synthesis Window, 48k version + */ +/* +const float Ws48k[1926] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0.000, 0.003, 0.007, + 0.010, 0.013, 0.017, + 0.020, 0.023, 0.027, + 0.030, 0.033, 0.037, + 0.040, 0.043, 0.047, + 0.050, 0.053, 0.057, + 0.060, 0.063, 0.067, + 0.070, 0.073, 0.077, + 0.080, 0.083, 0.087, + 0.090, 0.093, 0.097, + 0.100, 0.103, 0.107, + 0.110, 0.113, 0.117, + 0.120, 0.123, 0.127, + 0.130, 0.133, 0.137, + 0.140, 0.143, 0.147, + 0.150, 0.153, 0.157, + 0.160, 0.163, 0.167, + 0.170, 0.173, 0.177, + 0.180, 0.183, 0.187, + 0.190, 0.193, 0.197, + 0.200, 0.203, 0.207, + 0.210, 0.213, 0.217, + 0.220, 0.223, 0.227, + 0.230, 0.233, 0.237, + 0.240, 0.243, 0.247, + 0.250, 0.253, 0.257, + 0.260, 0.263, 0.267, + 0.270, 0.273, 0.277, + 0.280, 0.283, 0.287, + 0.290, 0.293, 0.297, + 0.300, 0.303, 0.307, + 0.310, 0.313, 0.317, + 0.320, 0.323, 0.327, + 0.330, 0.333, 0.337, + 0.340, 0.343, 0.347, + 0.350, 0.353, 0.357, + 0.360, 0.363, 0.367, + 0.370, 0.373, 0.377, + 0.380, 0.383, 0.387, + 0.390, 0.393, 0.397, + 0.400, 0.403, 0.407, + 0.410, 0.413, 0.417, + 0.420, 0.423, 0.427, + 0.430, 0.433, 0.437, + 0.440, 0.443, 0.447, + 0.450, 0.453, 0.457, + 0.460, 0.463, 0.467, + 0.470, 0.473, 0.477, + 0.480, 0.483, 0.487, + 0.490, 0.493, 0.497, + 0.500, 0.503, 0.507, + 0.510, 0.513, 0.517, + 0.520, 0.523, 0.527, + 0.530, 0.533, 0.537, + 0.540, 0.543, 0.547, + 0.550, 0.553, 0.557, + 0.560, 0.563, 0.567, + 0.570, 0.573, 0.577, + 0.580, 0.583, 0.587, + 0.590, 0.593, 0.597, + 0.600, 0.603, 0.607, + 0.610, 0.613, 0.617, + 0.620, 0.623, 0.627, + 0.630, 0.633, 0.637, + 0.640, 0.643, 0.647, + 0.650, 0.653, 0.657, + 0.660, 0.663, 0.667, + 0.670, 0.673, 0.677, + 0.680, 0.683, 0.687, + 0.690, 0.693, 0.697, + 0.700, 0.703, 0.707, + 0.710, 0.713, 0.717, + 0.720, 0.723, 0.727, + 0.730, 0.733, 0.737, + 0.740, 0.743, 0.747, + 0.750, 0.753, 0.757, + 0.760, 0.763, 0.767, + 0.770, 0.773, 0.777, + 0.780, 0.783, 0.787, + 0.790, 0.793, 0.797, + 0.800, 0.803, 0.807, + 0.810, 0.813, 0.817, + 0.820, 0.823, 0.827, + 0.830, 0.833, 0.837, + 0.840, 0.843, 0.847, + 0.850, 0.853, 0.857, + 0.860, 0.863, 0.867, + 0.870, 0.873, 0.877, + 0.880, 0.883, 0.887, + 0.890, 0.893, 0.897, + 0.900, 0.903, 0.907, + 0.910, 0.913, 0.917, + 0.920, 0.923, 0.927, + 0.930, 0.933, 0.937, + 0.940, 0.943, 0.947, + 0.950, 0.953, 0.957, + 0.960, 0.963, 0.967, + 0.970, 0.973, 0.977, + 0.980, 0.983, 0.987, + 0.990, 0.993, 0.997, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 0.997, 0.993, 0.990, + 0.987, 0.983, 0.980, + 0.977, 0.973, 0.970, + 0.967, 0.963, 0.960, + 0.957, 0.953, 0.950, + 0.947, 0.943, 0.940, + 0.937, 0.933, 0.930, + 0.927, 0.923, 0.920, + 0.917, 0.913, 0.910, + 0.907, 0.903, 0.900, + 0.897, 0.893, 0.890, + 0.887, 0.883, 0.880, + 0.877, 0.873, 0.870, + 0.867, 0.863, 0.860, + 0.857, 0.853, 0.850, + 0.847, 0.843, 0.840, + 0.837, 0.833, 0.830, + 0.827, 0.823, 0.820, + 0.817, 0.813, 0.810, + 0.807, 0.803, 0.800, + 0.797, 0.793, 0.790, + 0.787, 0.783, 0.780, + 0.777, 0.773, 0.770, + 0.767, 0.763, 0.760, + 0.757, 0.753, 0.750, + 0.747, 0.743, 0.740, + 0.737, 0.733, 0.730, + 0.727, 0.723, 0.720, + 0.717, 0.713, 0.710, + 0.707, 0.703, 0.700, + 0.697, 0.693, 0.690, + 0.687, 0.683, 0.680, + 0.677, 0.673, 0.670, + 0.667, 0.663, 0.660, + 0.657, 0.653, 0.650, + 0.647, 0.643, 0.640, + 0.637, 0.633, 0.630, + 0.627, 0.623, 0.620, + 0.617, 0.613, 0.610, + 0.607, 0.603, 0.600, + 0.597, 0.593, 0.590, + 0.587, 0.583, 0.580, + 0.577, 0.573, 0.570, + 0.567, 0.563, 0.560, + 0.557, 0.553, 0.550, + 0.547, 0.543, 0.540, + 0.537, 0.533, 0.530, + 0.527, 0.523, 0.520, + 0.517, 0.513, 0.510, + 0.507, 0.503, 0.500, + 0.497, 0.493, 0.490, + 0.487, 0.483, 0.480, + 0.477, 0.473, 0.470, + 0.467, 0.463, 0.460, + 0.457, 0.453, 0.450, + 0.447, 0.443, 0.440, + 0.437, 0.433, 0.430, + 0.427, 0.423, 0.420, + 0.417, 0.413, 0.410, + 0.407, 0.403, 0.400, + 0.397, 0.393, 0.390, + 0.387, 0.383, 0.380, + 0.377, 0.373, 0.370, + 0.367, 0.363, 0.360, + 0.357, 0.353, 0.350, + 0.347, 0.343, 0.340, + 0.337, 0.333, 0.330, + 0.327, 0.323, 0.320, + 0.317, 0.313, 0.310, + 0.307, 0.303, 0.300, + 0.297, 0.293, 0.290, + 0.287, 0.283, 0.280, + 0.277, 0.273, 0.270, + 0.267, 0.263, 0.260, + 0.257, 0.253, 0.250, + 0.247, 0.243, 0.240, + 0.237, 0.233, 0.230, + 0.227, 0.223, 0.220, + 0.217, 0.213, 0.210, + 0.207, 0.203, 0.200, + 0.197, 0.193, 0.190, + 0.187, 0.183, 0.180, + 0.177, 0.173, 0.170, + 0.167, 0.163, 0.160, + 0.157, 0.153, 0.150, + 0.147, 0.143, 0.140, + 0.137, 0.133, 0.130, + 0.127, 0.123, 0.120, + 0.117, 0.113, 0.110, + 0.107, 0.103, 0.100, + 0.097, 0.093, 0.090, + 0.087, 0.083, 0.080, + 0.077, 0.073, 0.070, + 0.067, 0.063, 0.060, + 0.057, 0.053, 0.050, + 0.047, 0.043, 0.040, + 0.037, 0.033, 0.030, + 0.027, 0.023, 0.020, + 0.017, 0.013, 0.010, + 0.007, 0.003, 0.000, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; +*/ +} +#endif diff --git a/mbe/mbelib_parms.h b/mbe/mbelib_parms.h new file mode 100644 index 0000000..d7267c3 --- /dev/null +++ b/mbe/mbelib_parms.h @@ -0,0 +1,44 @@ +/* + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MBELIB_H_ +#define MBELIB_H_ + +#include +extern "C" { +#include "mbelib.h" + + +struct mbelibParms +{ + mbe_parms *m_cur_mp; + mbe_parms *m_prev_mp; + mbe_parms *m_prev_mp_enhanced; + + mbelibParms() + { + m_cur_mp = (mbe_parms *) malloc(sizeof(mbe_parms)); + m_prev_mp = (mbe_parms *) malloc(sizeof(mbe_parms)); + m_prev_mp_enhanced = (mbe_parms *) malloc(sizeof(mbe_parms)); + } + + ~mbelibParms() + { + free(m_prev_mp_enhanced); + free(m_prev_mp); + free(m_cur_mp); + } +}; +} +#endif /* MBELIB_H_ */ diff --git a/mbe/mbevocoder.cpp b/mbe/mbevocoder.cpp new file mode 100644 index 0000000..dc046a1 --- /dev/null +++ b/mbe/mbevocoder.cpp @@ -0,0 +1,1343 @@ +/* + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +#define _USE_MATH_DEFINES +#include +#include +#include + +#include "mbevocoder.h" +#include "vocoder_tables.h" +#include "ambe3600x2400_const.h" +#include "ambe3600x2450_const.h" + +static const short b0_lookup[] = { + 0, 0, 0, 1, 1, 2, 2, 2, + 3, 3, 4, 4, 4, 5, 5, 5, + 6, 6, 7, 7, 7, 8, 8, 8, + 9, 9, 9, 10, 10, 11, 11, 11, + 12, 12, 12, 13, 13, 13, 14, 14, + 14, 15, 15, 15, 16, 16, 16, 17, + 17, 17, 17, 18, 18, 18, 19, 19, + 19, 20, 20, 20, 21, 21, 21, 21, + 22, 22, 22, 23, 23, 23, 24, 24, + 24, 24, 25, 25, 25, 25, 26, 26, + 26, 27, 27, 27, 27, 28, 28, 28, + 29, 29, 29, 29, 30, 30, 30, 30, + 31, 31, 31, 31, 31, 32, 32, 32, + 32, 33, 33, 33, 33, 34, 34, 34, + 34, 35, 35, 35, 35, 36, 36, 36, + 36, 37, 37, 37, 37, 38, 38, 38, + 38, 38, 39, 39, 39, 39, 40, 40, + 40, 40, 40, 41, 41, 41, 41, 42, + 42, 42, 42, 42, 43, 43, 43, 43, + 43, 44, 44, 44, 44, 45, 45, 45, + 45, 45, 46, 46, 46, 46, 46, 47, + 47, 47, 47, 47, 48, 48, 48, 48, + 48, 49, 49, 49, 49, 49, 49, 50, + 50, 50, 50, 50, 51, 51, 51, 51, + 51, 52, 52, 52, 52, 52, 52, 53, + 53, 53, 53, 53, 54, 54, 54, 54, + 54, 54, 55, 55, 55, 55, 55, 56, + 56, 56, 56, 56, 56, 57, 57, 57, + 57, 57, 57, 58, 58, 58, 58, 58, + 58, 59, 59, 59, 59, 59, 59, 60, + 60, 60, 60, 60, 60, 61, 61, 61, + 61, 61, 61, 62, 62, 62, 62, 62, + 62, 63, 63, 63, 63, 63, 63, 63, + 64, 64, 64, 64, 64, 64, 65, 65, + 65, 65, 65, 65, 65, 66, 66, 66, + 66, 66, 66, 67, 67, 67, 67, 67, + 67, 67, 68, 68, 68, 68, 68, 68, + 68, 69, 69, 69, 69, 69, 69, 69, + 70, 70, 70, 70, 70, 70, 70, 71, + 71, 71, 71, 71, 71, 71, 72, 72, + 72, 72, 72, 72, 72, 73, 73, 73, + 73, 73, 73, 73, 73, 74, 74, 74, + 74, 74, 74, 74, 75, 75, 75, 75, + 75, 75, 75, 75, 76, 76, 76, 76, + 76, 76, 76, 76, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 78, 78, 78, + 78, 78, 78, 78, 78, 79, 79, 79, + 79, 79, 79, 79, 79, 80, 80, 80, + 80, 80, 80, 80, 80, 81, 81, 81, + 81, 81, 81, 81, 81, 81, 82, 82, + 82, 82, 82, 82, 82, 82, 83, 83, + 83, 83, 83, 83, 83, 83, 83, 84, + 84, 84, 84, 84, 84, 84, 84, 84, + 85, 85, 85, 85, 85, 85, 85, 85, + 85, 86, 86, 86, 86, 86, 86, 86, + 86, 86, 87, 87, 87, 87, 87, 87, + 87, 87, 87, 88, 88, 88, 88, 88, + 88, 88, 88, 88, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 90, 90, + 90, 90, 90, 90, 90, 90, 90, 90, + 91, 91, 91, 91, 91, 91, 91, 91, + 91, 92, 92, 92, 92, 92, 92, 92, + 92, 92, 92, 93, 93, 93, 93, 93, + 93, 93, 93, 93, 93, 94, 94, 94, + 94, 94, 94, 94, 94, 94, 94, 94, + 95, 95, 95, 95, 95, 95, 95, 95, + 95, 95, 96, 96, 96, 96, 96, 96, + 96, 96, 96, 96, 96, 97, 97, 97, + 97, 97, 97, 97, 97, 97, 97, 98, + 98, 98, 98, 98, 98, 98, 98, 98, + 98, 98, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 100, 100, + 100, 100, 100, 100, 100, 100, 100, 100, + 100, 101, 101, 101, 101, 101, 101, 101, + 101, 101, 101, 101, 102, 102, 102, 102, + 102, 102, 102, 102, 102, 102, 102, 102, + 103, 103, 103, 103, 103, 103, 103, 103, + 103, 103, 103, 103, 104, 104, 104, 104, + 104, 104, 104, 104, 104, 104, 104, 104, + 105, 105, 105, 105, 105, 105, 105, 105, + 105, 105, 105, 105, 106, 106, 106, 106, + 106, 106, 106, 106, 106, 106, 106, 106, + 107, 107, 107, 107, 107, 107, 107, 107, + 107, 107, 107, 107, 107, 108, 108, 108, + 108, 108, 108, 108, 108, 108, 108, 108, + 108, 109, 109, 109, 109, 109, 109, 109, + 109, 109, 109, 109, 109, 109, 110, 110, + 110, 110, 110, 110, 110, 110, 110, 110, + 110, 110, 110, 111, 111, 111, 111, 111, + 111, 111, 111, 111, 111, 111, 111, 111, + 112, 112, 112, 112, 112, 112, 112, 112, + 112, 112, 112, 112, 112, 112, 113, 113, + 113, 113, 113, 113, 113, 113, 113, 113, + 113, 113, 113, 113, 114, 114, 114, 114, + 114, 114, 114, 114, 114, 114, 114, 114, + 114, 115, 115, 115, 115, 115, 115, 115, + 115, 115, 115, 115, 115, 115, 115, 116, + 116, 116, 116, 116, 116, 116, 116, 116, + 116, 116, 116, 116, 116, 116, 117, 117, + 117, 117, 117, 117, 117, 117, 117, 117, + 117, 117, 117, 117, 118, 118, 118, 118, + 118, 118, 118, 118, 118, 118, 118, 118, + 118, 118, 118, 119, 119, 119, 119, 119, + 119, 119, 119 +}; + +static const int m_list[] = {0, 1, 2, 3, 4, 5, 11, 12, 13, 14, 17, 18, 19, 20, 21, 22, 23, 26, 27, 28, 29, 30, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 7, 8, 9, 10, 15, 16, 24, 25, 31, 32, 6}; +static const int d_list[] = {7, 1, 11, 21, 31, 25, 35, 45, 55, 49, 59, 69, 6, 0, 10, 20, 30, 24, 34, 44, 54, 48, 58, 68, 5, 15, 9, 19, 29, 39, 33, 43, 53, 63, 57, 67, 4, 14, 8, 18, 28, 38, 32, 42, 52, 62, 56, 66, 3, 13, 23, 17, 27, 37, 47, 41, 51, 61, 71, 65, 2, 12, 22, 16, 26, 36, 46, 40, 50, 60, 70, 64}; +//static const int alt_d_list[] = {0, 12, 24, 36, 48, 60, 1, 13, 25, 37, 49, 61, 2, 14, 26, 38, 50, 62, 3, 15, 27, 39, 51, 63, 4, 16, 28, 40, 52, 64, 5, 17, 29, 41, 53, 65, 6, 18, 30, 42, 54, 66, 7, 19, 31, 43, 55, 67, 8, 20, 32, 44, 56, 68, 9, 21, 33, 45, 57, 69, 10, 22, 34, 46, 58, 70, 11, 23, 35, 47, 59, 71}; +static const int b_lengths[] = {7,4,6,9,7,4,4,4,3}; + +const int 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 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 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 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 +}; + +// bit 0 +const int 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 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 +}; + + +static inline uint32_t golay_24_encode(uint32_t code_word_in) +{ + static const uint32_t encoding[12] = { + 040006165, + 020003073, + 010007550, + 04003664, + 02001732, + 01006631, + 0403315, + 0201547, + 0106706, + 045227, + 024476, + 014353 + }; + + uint32_t code_word_out = 0; + for(uint16_t i = 0; i < 12; i++) { + uint32_t temp_word = code_word_in & (1 << (11 - i)); + if(temp_word >= 1) { + code_word_out = code_word_out ^ encoding[i]; + } + } + return(code_word_out); +} + +static inline uint32_t golay_23_encode(uint32_t code_word_in) +{ + return golay_24_encode(code_word_in) >> 1; +} + +static inline void store_reg(int reg, uint8_t val[], int len) +{ + for (int i=0; i> (len-1-i)) & 1; + } +} + +static inline int load_reg(const uint8_t val[], int len) +{ + int acc = 0; + for (int i=0; irepeat = prev_mp->repeat; + + if ((b0 >= 120) && (b0 <= 123)) + { +#ifdef AMBE_DEBUG + fprintf (stderr, "AMBE Erasure Frame\n"); +#endif + return (2); + } + else if ((b0 == 124) || (b0 == 125)) + { +#ifdef AMBE_DEBUG + fprintf (stderr, "AMBE Silence Frame\n"); +#endif + silence = 1; + cur_mp->w0 = ((float) 2 * M_PI) / (float) 32; + f0 = (float) 1 / (float) 32; + L = 14; + cur_mp->L = 14; + for (l = 1; l <= L; l++) + { + cur_mp->Vl[l] = 0; + } + } + else if ((b0 == 126) || (b0 == 127)) + { +#ifdef AMBE_DEBUG + fprintf (stderr, "AMBE Tone Frame\n"); +#endif + return (3); + } + + if (silence == 0) + { + if (dstar) + f0 = make_f0(b0); + else + // w0 from specification document + f0 = AmbeW0table[b0]; + cur_mp->w0 = f0 * (float) 2 *M_PI; + // w0 from patent filings + //f0 = powf (2, ((float) b0 + (float) 195.626) / -(float) 45.368); + //cur_mp->w0 = f0 * (float) 2 *M_PI; + } + + unvc = (float) 0.2046 / sqrtf (cur_mp->w0); + //unvc = (float) 1; + //unvc = (float) 0.2046 / sqrtf (f0); + + // decode L + if (silence == 0) + { + // L from specification document + // lookup L in tabl3 + if (dstar) + L = DSTAR_L(b0); + else + L = AmbeLtable[b0]; + // L formula form patent filings + //L=(int)((float)0.4627 / f0); + cur_mp->L = L; + } + + // decode V/UV parameters + for (l = 1; l <= L; l++) + { + // jl from specification document + jl = (int) ((float) l * (float) 16.0 * f0); + // jl from patent filings? + //jl = (int)(((float)l * (float)16.0 * f0) + 0.25); + + if (silence == 0) + { + if (dstar) + cur_mp->Vl[l] = AmbePlusVuv[b1][jl]; + else + cur_mp->Vl[l] = AmbeVuv[b1][jl]; + } +#ifdef AMBE_DEBUG + fprintf (stderr, "jl[%i]:%i Vl[%i]:%i\n", l, jl, l, cur_mp->Vl[l]); +#endif + } +#ifdef AMBE_DEBUG + fprintf (stderr, "\nb0:%i w0:%f L:%i b1:%i\n", b0, cur_mp->w0, L, b1); +#endif + if (dstar) { + deltaGamma = AmbePlusDg[b2]; + cur_mp->gamma = deltaGamma + ((float) 0.5 * prev_mp->gamma); + } else { + deltaGamma = AmbeDg[b2]; + cur_mp->gamma = deltaGamma + ((float) 0.5 * prev_mp->gamma); + } +#ifdef AMBE_DEBUG + fprintf (stderr, "b2: %i, deltaGamma: %f gamma: %f gamma-1: %f\n", b2, deltaGamma, cur_mp->gamma, prev_mp->gamma); +#endif + + + // decode PRBA vectors + Gm[1] = 0; + + if (dstar) { + Gm[2] = AmbePlusPRBA24[b3][0]; + Gm[3] = AmbePlusPRBA24[b3][1]; + Gm[4] = AmbePlusPRBA24[b3][2]; + + Gm[5] = AmbePlusPRBA58[b4][0]; + Gm[6] = AmbePlusPRBA58[b4][1]; + Gm[7] = AmbePlusPRBA58[b4][2]; + Gm[8] = AmbePlusPRBA58[b4][3]; + } else { + Gm[2] = AmbePRBA24[b3][0]; + Gm[3] = AmbePRBA24[b3][1]; + Gm[4] = AmbePRBA24[b3][2]; + + Gm[5] = AmbePRBA58[b4][0]; + Gm[6] = AmbePRBA58[b4][1]; + Gm[7] = AmbePRBA58[b4][2]; + Gm[8] = AmbePRBA58[b4][3]; + } + +#ifdef AMBE_DEBUG + fprintf (stderr, "b3: %i Gm[2]: %f Gm[3]: %f Gm[4]: %f b4: %i Gm[5]: %f Gm[6]: %f Gm[7]: %f Gm[8]: %f\n", b3, Gm[2], Gm[3], Gm[4], b4, Gm[5], Gm[6], Gm[7], Gm[8]); +#endif + + // compute Ri + for (i = 1; i <= 8; i++) + { + sum = 0; + for (m = 1; m <= 8; m++) + { + if (m == 1) + { + am = 1; + } + else + { + am = 2; + } + sum = sum + ((float) am * Gm[m] * cosf ((M_PI * (float) (m - 1) * ((float) i - (float) 0.5)) / (float) 8)); + } + Ri[i] = sum; +#ifdef AMBE_DEBUG + fprintf (stderr, "R%i: %f ", i, Ri[i]); +#endif + } +#ifdef AMBE_DEBUG + fprintf (stderr, "\n"); +#endif + + // generate first to elements of each Ci,k block from PRBA vector + rconst = ((float) 1 / ((float) 2 * M_SQRT2)); + Cik[1][1] = (float) 0.5 *(Ri[1] + Ri[2]); + Cik[1][2] = rconst * (Ri[1] - Ri[2]); + Cik[2][1] = (float) 0.5 *(Ri[3] + Ri[4]); + Cik[2][2] = rconst * (Ri[3] - Ri[4]); + Cik[3][1] = (float) 0.5 *(Ri[5] + Ri[6]); + Cik[3][2] = rconst * (Ri[5] - Ri[6]); + Cik[4][1] = (float) 0.5 *(Ri[7] + Ri[8]); + Cik[4][2] = rconst * (Ri[7] - Ri[8]); + + // decode HOC + + // lookup Ji + if (dstar) { + Ji[1] = AmbePlusLmprbl[L][0]; + Ji[2] = AmbePlusLmprbl[L][1]; + Ji[3] = AmbePlusLmprbl[L][2]; + Ji[4] = AmbePlusLmprbl[L][3]; + } else { + Ji[1] = AmbeLmprbl[L][0]; + Ji[2] = AmbeLmprbl[L][1]; + Ji[3] = AmbeLmprbl[L][2]; + Ji[4] = AmbeLmprbl[L][3]; + } +#ifdef AMBE_DEBUG + fprintf (stderr, "Ji[1]: %i Ji[2]: %i Ji[3]: %i Ji[4]: %i\n", Ji[1], Ji[2], Ji[3], Ji[4]); + fprintf (stderr, "b5: %i b6: %i b7: %i b8: %i\n", b5, b6, b7, b8); +#endif + + // Load Ci,k with the values from the HOC tables + // there appear to be a couple typos in eq. 37 so we will just do what makes sense + // (3 <= k <= Ji and k<=6) + for (k = 3; k <= Ji[1]; k++) + { + if (k > 6) + { + Cik[1][k] = 0; + } + else + { + if (dstar) + Cik[1][k] = AmbePlusHOCb5[b5][k - 3]; + else + Cik[1][k] = AmbeHOCb5[b5][k - 3]; +#ifdef AMBE_DEBUG + fprintf (stderr, "C1,%i: %f ", k, Cik[1][k]); +#endif + } + } + for (k = 3; k <= Ji[2]; k++) + { + if (k > 6) + { + Cik[2][k] = 0; + } + else + { + if (dstar) + Cik[2][k] = AmbePlusHOCb6[b6][k - 3]; + else + Cik[2][k] = AmbeHOCb6[b6][k - 3]; +#ifdef AMBE_DEBUG + fprintf (stderr, "C2,%i: %f ", k, Cik[2][k]); +#endif + } + } + for (k = 3; k <= Ji[3]; k++) + { + if (k > 6) + { + Cik[3][k] = 0; + } + else + { + if (dstar) + Cik[3][k] = AmbePlusHOCb7[b7][k - 3]; + else + Cik[3][k] = AmbeHOCb7[b7][k - 3]; +#ifdef AMBE_DEBUG + fprintf (stderr, "C3,%i: %f ", k, Cik[3][k]); +#endif + } + } + for (k = 3; k <= Ji[4]; k++) + { + if (k > 6) + { + Cik[4][k] = 0; + } + else + { + if (dstar) + Cik[4][k] = AmbePlusHOCb8[b8][k - 3]; + else + Cik[4][k] = AmbeHOCb8[b8][k - 3]; +#ifdef AMBE_DEBUG + fprintf (stderr, "C4,%i: %f ", k, Cik[4][k]); +#endif + } + } +#ifdef AMBE_DEBUG + fprintf (stderr, "\n"); +#endif + + // inverse DCT each Ci,k to give ci,j (Tl) + l = 1; + for (i = 1; i <= 4; i++) + { + ji = Ji[i]; + for (j = 1; j <= ji; j++) + { + sum = 0; + for (k = 1; k <= ji; k++) + { + if (k == 1) + { + ak = 1; + } + else + { + ak = 2; + } +#ifdef AMBE_DEBUG + fprintf (stderr, "j: %i Cik[%i][%i]: %f ", j, i, k, Cik[i][k]); +#endif + sum = sum + ((float) ak * Cik[i][k] * cosf ((M_PI * (float) (k - 1) * ((float) j - (float) 0.5)) / (float) ji)); + } + Tl[l] = sum; +#ifdef AMBE_DEBUG + fprintf (stderr, "Tl[%i]: %f\n", l, Tl[l]); +#endif + l++; + } + } + + // determine log2Ml by applying ci,j to previous log2Ml + + // fix for when L > L(-1) + if (cur_mp->L > prev_mp->L) + { + for (l = (prev_mp->L) + 1; l <= cur_mp->L; l++) + { + prev_mp->Ml[l] = prev_mp->Ml[prev_mp->L]; + prev_mp->log2Ml[l] = prev_mp->log2Ml[prev_mp->L]; + } + } + prev_mp->log2Ml[0] = prev_mp->log2Ml[1]; + prev_mp->Ml[0] = prev_mp->Ml[1]; + + // Part 1 + Sum43 = 0; + for (l = 1; l <= cur_mp->L; l++) + { + + // eq. 40 + flokl[l] = ((float) prev_mp->L / (float) cur_mp->L) * (float) l; + intkl[l] = (int) (flokl[l]); +#ifdef AMBE_DEBUG + fprintf (stderr, "flok%i: %f, intk%i: %i ", l, flokl[l], l, intkl[l]); +#endif + // eq. 41 + deltal[l] = flokl[l] - (float) intkl[l]; +#ifdef AMBE_DEBUG + fprintf (stderr, "delta%i: %f ", l, deltal[l]); +#endif + // eq 43 + Sum43 = Sum43 + ((((float) 1 - deltal[l]) * prev_mp->log2Ml[intkl[l]]) + (deltal[l] * prev_mp->log2Ml[intkl[l] + 1])); + } + Sum43 = (((dstar ? DSTAR_SPEC_PRED : 0.65f) / (float) cur_mp->L) * Sum43); +#ifdef AMBE_DEBUG + fprintf (stderr, "\n"); + fprintf (stderr, "Sum43: %f\n", Sum43); +#endif + + // Part 2 + Sum42 = 0; + for (l = 1; l <= cur_mp->L; l++) + { + Sum42 += Tl[l]; + } + Sum42 = Sum42 / (float) cur_mp->L; + BigGamma = cur_mp->gamma - ((float) 0.5 * (log ((float) cur_mp->L) / log ((float) 2))) - Sum42; + //BigGamma=cur_mp->gamma - ((float)0.5 * log((float)cur_mp->L)) - Sum42; + + // Part 3 + for (l = 1; l <= cur_mp->L; l++) + { + c1 = ((dstar ? DSTAR_SPEC_PRED : 0.65f) * ((float) 1 - deltal[l]) * prev_mp->log2Ml[intkl[l]]); + c2 = ((dstar ? DSTAR_SPEC_PRED : 0.65f) * deltal[l] * prev_mp->log2Ml[intkl[l] + 1]); + cur_mp->log2Ml[l] = Tl[l] + c1 + c2 - Sum43 + BigGamma; + // inverse log to generate spectral amplitudes + if (cur_mp->Vl[l] == 1) + { + cur_mp->Ml[l] = exp ((float) 0.693 * cur_mp->log2Ml[l]); + } + else + { + cur_mp->Ml[l] = unvc * exp ((float) 0.693 * cur_mp->log2Ml[l]); + } +#ifdef AMBE_DEBUG + fprintf (stderr, "flokl[%i]: %f, intkl[%i]: %i ", l, flokl[l], l, intkl[l]); + fprintf (stderr, "deltal[%i]: %f ", l, deltal[l]); + fprintf (stderr, "prev_mp->log2Ml[%i]: %f\n", l, prev_mp->log2Ml[intkl[l]]); + fprintf (stderr, "BigGamma: %f c1: %f c2: %f Sum43: %f Tl[%i]: %f log2Ml[%i]: %f Ml[%i]: %f\n", BigGamma, c1, c2, Sum43, l, Tl[l], l, cur_mp->log2Ml[l], l, cur_mp->Ml[l]); +#endif + } + + return (0); +} + +int +mbe_dequantizeAmbe2400Parms (mbe_parms * cur_mp, mbe_parms * prev_mp, const int *b){ + int dstar = 1; + return (mbe_dequantizeAmbeParms (cur_mp, prev_mp, b, dstar)); +} + +int +mbe_dequantizeAmbe2250Parms (mbe_parms * cur_mp, mbe_parms * prev_mp, const int *b){ + int dstar = 0; + return (mbe_dequantizeAmbeParms (cur_mp, prev_mp, b, dstar)); +} + + +void encode_ambe(const IMBE_PARAM *imbe_param, int b[], mbe_parms*cur_mp, mbe_parms*prev_mp, bool dstar, float gain_adjust, float *gain_state = nullptr) { + static const float SQRT_2 = sqrtf(2.0); + static const int b0_lmax = sizeof(b0_lookup) / sizeof(b0_lookup[0]); + // int b[9]; + + int L; + // The harmonics the rest of this function codes: their count (nh), their + // amplitudes (sa_w) and voicing (vuv_w). For DMR they are the IMBE + // analysis' own values, unchanged. + int nh = imbe_param->num_harms; + float sa_w[NUM_HARMS_MAX]; + short vuv_w[NUM_HARMS_MAX]; + if (dstar) { + float f0_in = 256.0f / (float) imbe_param->ref_pitch; // cycles per sample + int b0 = (int) lrintf((-log2f(f0_in) - DSTAR_F0_C0) / DSTAR_F0_C1 - 0.5f); // nearest code on the chip-measured scale + if (b0 < 0) b0 = 0; + if (b0 > 119) b0 = 119; // 120..127 are erasure / silence / tone codes + b[0] = b0; + L = DSTAR_L(b0); + float f0_c = make_f0(b0); + const int n_in = imbe_param->num_harms; + for (int l = 1; l <= L; l++) { + // position of the decoder's harmonic l on the IMBE harmonic axis (1-based) + float k = (float) l * f0_c / f0_in; + float a; + if (k <= 1.0f) { + a = (float) imbe_param->sa[0]; + } else if (k >= (float) n_in) { + a = (float) imbe_param->sa[n_in - 1] * exp2f(-1.0f * (k - (float) n_in)); + } else { + int k0 = (int) k; // 1-based lower neighbour + float fr = k - (float) k0; + float a0 = (float) imbe_param->sa[k0 - 1]; + float a1 = (float) imbe_param->sa[k0]; + if (a0 < 1.0f) a0 = 1.0f; + if (a1 < 1.0f) a1 = 1.0f; + a = exp2f((1.0f - fr) * log2f(a0) + fr * log2f(a1)); + } + sa_w[l - 1] = a; + int kn = (int) lrintf(k); + if (kn < 1) kn = 1; + if (kn > n_in) kn = n_in; + vuv_w[l - 1] = imbe_param->v_uv_dsn[kn - 1]; + } + nh = L; + } else { + // ref_pitch is Q8_8 in range 19.875 - 123.125 + int b0_i = (imbe_param->ref_pitch >> 5) - 159; + if (b0_i < 0 || b0_i > b0_lmax) { + fprintf(stderr, "encode error b0_i %d\n", b0_i); + return; + } + b[0] = b0_lookup[b0_i]; + L = (int) AmbeLtable[b[0]]; +#if 1 + // adjust b0 until L agrees + while (L != imbe_param->num_harms) { + if (L < imbe_param->num_harms) + b0_i ++; + else if (L > imbe_param->num_harms) + b0_i --; + if (b0_i < 0 || b0_i > b0_lmax) { + fprintf(stderr, "encode error2 b0_i %d\n", b0_i); + return; + } + b[0] = b0_lookup[b0_i]; + L = (int) AmbeLtable[b[0]]; + } +#endif + for (int l = 0; l < nh; l++) { + sa_w[l] = (float) imbe_param->sa[l]; + vuv_w[l] = imbe_param->v_uv_dsn[l]; + } + } + float m_float2[NUM_HARMS_MAX]; + for (int l=1; l <= L; l++) { + m_float2[l-1] = sa_w[l-1] ; + m_float2[l-1] = m_float2[l-1] * m_float2[l-1]; + } + + float en_min = 0; + b[1] = 0; + int vuv_max = (dstar) ? 16 : 17; + for (int n=0; n < vuv_max; n++) { + float En = 0; + for (int l=1; l <= L; l++) { + int jl; + if (dstar) + jl = (int) ((float) l * (float) 16.0 * make_f0(b[0])); + else + jl = (int) ((float) l * (float) 16.0 * AmbeW0table[b[0]]); + int kl = 12; + if (l <= 36) + kl = (l + 2) / 3; + if (dstar) { + if (vuv_w[l-1] != AmbePlusVuv[n][jl]) + En += m_float2[l-1]; + } else { + if (imbe_param->v_uv_dsn[(kl-1)*3] != AmbeVuv[n][jl]) + En += m_float2[l-1]; + } + } + if (n == 0) + en_min = En; + else if (En < en_min) { + b[1] = n; + en_min = En; + } + } + + // log spectral amplitudes + float num_harms_f = (float) nh; + float log_l_2 = 0.5 * log2f(num_harms_f); // fixme: table lookup + float log_l_w0; + if (dstar) + log_l_w0 = 0.5 * log2f(num_harms_f * make_f0(b[0]) * 2.0 * M_PI) + 2.289; + else + log_l_w0 = 0.5 * log2f(num_harms_f * AmbeW0table[b[0]] * 2.0 * M_PI) + 2.289; + float lsa[NUM_HARMS_MAX]; + float lsa_sum=0.0; + + for (int i1 = 0; i1 < nh; i1++) { + float sa = sa_w[i1]; + if (sa < 1) sa = 1.0; + if (vuv_w[i1]) + lsa[i1] = log_l_2 + log2f(sa); + else + lsa[i1] = log_l_w0 + log2f(sa); + lsa_sum += lsa[i1]; + } + + float gain = lsa_sum / num_harms_f; + if (dstar && gain_state) { + if (*gain_state > -98.0f) gain = DSTAR_GAIN_SMOOTH * (*gain_state) + (1.0f - DSTAR_GAIN_SMOOTH) * gain; + *gain_state = gain; + } + float diff_gain; + (void)dstar; + diff_gain = gain - 0.5 * prev_mp->gamma; + + diff_gain -= gain_adjust; + + float error; + int error_index; + int max_dg = (dstar) ? 64 : 32; + for (int i1 = 0; i1 < max_dg; i1++) { + float diff; + if (dstar) + diff = fabsf(diff_gain - AmbePlusDg[i1]); + else + diff = fabsf(diff_gain - AmbeDg[i1]); + //fprintf(stderr, "%2.4f:%2.4f ", diff, error); + if ((i1 == 0) || (diff < error)) { + error = diff; + error_index = i1; + } + } + //fprintf(stderr, "\n"); + b[2] = error_index; + + // prediction residuals + float l_prev_l = (float) (prev_mp->L) / num_harms_f; + //float tmp_s = 0.0; + prev_mp->log2Ml[0] = prev_mp->log2Ml[1]; + for (int i1 = 0; i1 < nh; i1++) { + //float kl = l_prev_l * (float)(i1+1); + //int kl_floor = (int) kl; + //float kl_frac = kl - kl_floor; + //tmp_s += (1.0 - kl_frac) * prev_mp->log2Ml[kl_floor +0] + kl_frac * prev_mp->log2Ml[kl_floor+1 +0]; + } + float T[NUM_HARMS_MAX]; + for (int i1 = 0; i1 < nh; i1++) { + float kl = l_prev_l * (float)(i1+1); + int kl_floor = (int) kl; + float kl_frac = kl - kl_floor; + const float pc = dstar ? DSTAR_SPEC_PRED : 0.65f; + T[i1] = lsa[i1] - pc * (1.0 - kl_frac) * prev_mp->log2Ml[kl_floor +0] \ + - pc * kl_frac * prev_mp->log2Ml[kl_floor+1 +0]; + } + + // DCT + const int * J; + if (dstar) + J = AmbePlusLmprbl[nh]; + else + J = AmbeLmprbl[nh]; + float * c[4]; + int acc = 0; + for (int i=0; i<4; i++) { + c[i] = &T[acc]; + acc += J[i]; + } + float C[4][17]; + for (int i=1; i<=4; i++) { + for (int k=1; k<=J[i-1]; k++) { + float s = 0.0; + for (int j=1; j<=J[i-1]; j++) { + //fixme: lut? + s += (c[i-1][j-1] * cosf((M_PI * (((float)k) - 1.0) * (((float)j) - 0.5)) / (float)J[i-1])); + } + C[i-1][k-1] = s / (float)J[i-1]; + } + } + float R[8]; + R[0] = C[0][0] + SQRT_2 * C[0][1]; + R[1] = C[0][0] - SQRT_2 * C[0][1]; + R[2] = C[1][0] + SQRT_2 * C[1][1]; + R[3] = C[1][0] - SQRT_2 * C[1][1]; + R[4] = C[2][0] + SQRT_2 * C[2][1]; + R[5] = C[2][0] - SQRT_2 * C[2][1]; + R[6] = C[3][0] + SQRT_2 * C[3][1]; + R[7] = C[3][0] - SQRT_2 * C[3][1]; + + // encode PRBA + float G[8]; + for (int m=1; m<=8; m++) { + G[m-1] = 0.0; + for (int i=1; i<=8; i++) { + //fixme: lut? + G[m-1] += (R[i-1] * cosf((M_PI * (((float)m) - 1.0) * (((float)i) - 0.5)) / 8.0)); + } + G[m-1] /= 8.0; + } + for (int i=0; i<512; i++) { + float err=0.0; + float diff; + if (dstar) { + diff = G[1] - AmbePlusPRBA24[i][0]; + err += (diff * diff); + diff = G[2] - AmbePlusPRBA24[i][1]; + err += (diff * diff); + diff = G[3] - AmbePlusPRBA24[i][2]; + err += (diff * diff); + } else { + diff = G[1] - AmbePRBA24[i][0]; + err += (diff * diff); + diff = G[2] - AmbePRBA24[i][1]; + err += (diff * diff); + diff = G[3] - AmbePRBA24[i][2]; + err += (diff * diff); + } + if (i == 0 || err < error) { + error = err; + error_index = i; + } + } + b[3] = error_index; + + // PRBA58 + for (int i=0; i<128; i++) { + float err=0.0; + float diff; + if (dstar) { + diff = G[4] - AmbePlusPRBA58[i][0]; + err += (diff * diff); + diff = G[5] - AmbePlusPRBA58[i][1]; + err += (diff * diff); + diff = G[6] - AmbePlusPRBA58[i][2]; + err += (diff * diff); + diff = G[7] - AmbePlusPRBA58[i][3]; + err += (diff * diff); + } else { + diff = G[4] - AmbePRBA58[i][0]; + err += (diff * diff); + diff = G[5] - AmbePRBA58[i][1]; + err += (diff * diff); + diff = G[6] - AmbePRBA58[i][2]; + err += (diff * diff); + diff = G[7] - AmbePRBA58[i][3]; + err += (diff * diff); + } + if (i == 0 || err < error) { + error = err; + error_index = i; + } + } + b[4] = error_index; + + // higher order coeffs b5 + int ii = 1; + if (J[ii-1] <= 2) { + b[4+ii] = 0.0; + } else { + int max_5 = (dstar) ? 16 : 32; + for (int n=0; n < max_5; n++) { + float err=0.0; + float diff; + for (int j=1; j <= J[ii-1]-2 && j <= 4; j++) { + if (dstar) + diff = AmbePlusHOCb5[n][j-1] - C[ii-1][j+2-1]; + else + diff = AmbeHOCb5[n][j-1] - C[ii-1][j+2-1]; + err += (diff * diff); + } + if (n == 0 || err < error) { + error = err; + error_index = n; + } + } + b[4+ii] = error_index; + } + + // higher order coeffs b6 + ii = 2; + if (J[ii-1] <= 2) { + b[4+ii] = 0.0; + } else { + for (int n=0; n < 16; n++) { + float err=0.0; + float diff; + for (int j=1; j <= J[ii-1]-2 && j <= 4; j++) { + if (dstar) + diff = AmbePlusHOCb6[n][j-1] - C[ii-1][j+2-1]; + else + diff = AmbeHOCb6[n][j-1] - C[ii-1][j+2-1]; + err += (diff * diff); + } + if (n == 0 || err < error) { + error = err; + error_index = n; + } + } + b[4+ii] = error_index; + } + + // higher order coeffs b7 + ii = 3; + if (J[ii-1] <= 2) { + b[4+ii] = 0.0; + } else { + for (int n=0; n < 16; n++) { + float err=0.0; + float diff; + for (int j=1; j <= J[ii-1]-2 && j <= 4; j++) { + if (dstar) + diff = AmbePlusHOCb7[n][j-1] - C[ii-1][j+2-1]; + else + diff = AmbeHOCb7[n][j-1] - C[ii-1][j+2-1]; + err += (diff * diff); + } + if (n == 0 || err < error) { + error = err; + error_index = n; + } + } + b[4+ii] = error_index; + } + + // higher order coeffs b8 + ii = 4; + if (J[ii-1] <= 2) { + b[4+ii] = 0.0; + } else { + int max_8 = (dstar) ? 16 : 8; + const int step_8 = (dstar) ? 2 : 1; + for (int n=0; n < max_8; n += step_8) { + float err=0.0; + float diff; + for (int j=1; j <= J[ii-1]-2 && j <= 4; j++) { + if (dstar) + diff = AmbePlusHOCb8[n][j-1] - C[ii-1][j+2-1]; + else + diff = AmbeHOCb8[n][j-1] - C[ii-1][j+2-1]; + err += (diff * diff); + } + if (n == 0 || err < error) { + error = err; + error_index = n; + } + } + b[4+ii] = error_index; + } + //fprintf (stderr, "B\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\n", b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7], b[8]); + //int rc; + if (dstar) + mbe_dequantizeAmbe2400Parms (cur_mp, prev_mp, b); + else + mbe_dequantizeAmbe2250Parms (cur_mp, prev_mp, b); + mbe_moveMbeParms (cur_mp, prev_mp); +} + + MBEVocoder::MBEVocoder() + { + m_mbelibParms = new mbelibParms(); + m_audio_out_temp_buf_p = m_audio_out_temp_buf; + + memset(m_audio_out_buf, 0, sizeof(short) * 2 * 48000); + m_audio_out_buf_p = m_audio_out_buf; + m_audio_out_nb_samples = 0; + m_audio_out_buf_size = 48000; // given in number of unique samples + + initMbeParms(); + memset(ambe_d, 0, 49); + m_dstar_gain_s = -99.0f; // QSO One: D-Star gain smoothing state (none yet) + } + + MBEVocoder::~MBEVocoder() + { + delete m_mbelibParms; + } + + void MBEVocoder::decode_2400x1200(int16_t *pcm, uint8_t *ambe) + { + int samples = 0; + process_2400x1200(ambe); + int16_t *p = getAudio(samples); + memcpy(pcm, p, samples * sizeof(int16_t)); + resetAudio(); + } + + void MBEVocoder::decode_2450x1150(int16_t *pcm, uint8_t *ambe) + { + int samples = 0; + process_2450x1150(ambe); + int16_t *p = getAudio(samples); + memcpy(pcm, p, samples * sizeof(int16_t)); + resetAudio(); + } + + void MBEVocoder::decode_2450(int16_t *pcm, uint8_t *ambe) + { + int samples = 0; + process_2450(ambe); + int16_t *p = getAudio(samples); + memcpy(pcm, p, samples * sizeof(int16_t)); + resetAudio(); + } + + void MBEVocoder::encode_2400x1200(int16_t *pcm, uint8_t *ambe) + { + int b[9]; + int16_t frame_vector[8]; // result ignored + uint8_t ambe_frame[72]; + + uint8_t pbuf[48]; + uint8_t tbuf[48]; + int tbufp = 0; + memset(ambe, 0, 9); + + vocoder.imbe_encode(frame_vector, pcm); + encode_ambe(vocoder.param(), b, m_mbelibParms->m_cur_mp, m_mbelibParms->m_prev_mp, true, DSTAR_GAIN_ADJUST, &m_dstar_gain_s); + b[8] >>= 1; + + for (int i=0; i < 9; i++) { + store_reg(b[i], &tbuf[tbufp], b_lengths[i]); + tbufp += b_lengths[i]; + } + + for (int i=0; i < 48; i++) + pbuf[i] = tbuf[m_list[i]]; + + int u0 = load_reg(pbuf+0, 12); + int u1 = load_reg(pbuf+12, 12); + + int m1 = PRNG_TABLE[u0]; + int c0 = golay_24_encode(u0); + int c1 = golay_24_encode(u1) ^ m1; + + uint8_t pre_buf[72]; + store_reg(c0, pre_buf, 24); + store_reg(c1, pre_buf+24, 24); + memcpy(pre_buf+48, pbuf+24, 24); + + for (int i=0; i < 72; i++) + ambe_frame[d_list[i]] = pre_buf[i]; + + for(int i = 0; i < 9; ++i){ + for(int j = 0; j < 8; ++j){ + ambe[i] |= (ambe_frame[(i*8)+j] << j); + } + } + } + + void MBEVocoder::encode_2450x1150(int16_t *pcm, uint8_t *ambe) + { + unsigned int aOrig = 0U; + unsigned int bOrig = 0U; + unsigned int cOrig = 0U; + unsigned int MASK = 0x000800U; + uint8_t tmp[9]; + + memset(tmp, 0, 9); + memset(ambe, 0, 9); + encode_2450(pcm, tmp); + + for (unsigned int i = 0U; i < 12U; i++, MASK >>= 1) { + unsigned int n1 = i; + unsigned int n2 = i + 12U; + if (READ_BIT(tmp, n1)) + aOrig |= MASK; + if (READ_BIT(tmp, n2)) + bOrig |= MASK; + } + + MASK = 0x1000000U; + for (unsigned int i = 0U; i < 25U; i++, MASK >>= 1) { + unsigned int n = i + 24U; + if (READ_BIT(tmp, n)) + cOrig |= MASK; + } + + unsigned int a = golay_24_encode(aOrig); + + // The PRNG + unsigned int p = PRNG_TABLE[aOrig] >> 1; + + unsigned int b = golay_23_encode(bOrig); + b ^= p; + + MASK = 0x800000U; + for (unsigned int i = 0U; i < 24U; i++, MASK >>= 1) { + unsigned int aPos = A_TABLE[i]; + WRITE_BIT(ambe, aPos, a & MASK); + } + + MASK = 0x400000U; + for (unsigned int i = 0U; i < 23U; i++, MASK >>= 1) { + unsigned int bPos = B_TABLE[i]; + WRITE_BIT(ambe, bPos, b & MASK); + } + + MASK = 0x1000000U; + for (unsigned int i = 0U; i < 25U; i++, MASK >>= 1) { + unsigned int cPos = C_TABLE[i]; + WRITE_BIT(ambe, cPos, cOrig & MASK); + } + } + + void MBEVocoder::encode_2450(int16_t *pcm, uint8_t *ambe) + { + int b[9]; + int16_t frame_vector[8]; // result ignored + uint8_t ambe_frame[56]; + memset(ambe, 0, 9); + + vocoder.imbe_encode(frame_vector, pcm); + encode_ambe(vocoder.param(), b, m_mbelibParms->m_cur_mp, m_mbelibParms->m_prev_mp, false, 1.0); + memset(ambe_frame, 0, 56); + + ambe_frame[0] = (b[0] >> 6) & 1; + ambe_frame[1] = (b[0] >> 5) & 1; + ambe_frame[2] = (b[0] >> 4) & 1; + ambe_frame[3] = (b[0] >> 3) & 1; + ambe_frame[4] = (b[1] >> 4) & 1; + ambe_frame[5] = (b[1] >> 3) & 1; + ambe_frame[6] = (b[1] >> 2) & 1; + ambe_frame[7] = (b[1] >> 1) & 1; + ambe_frame[8] = (b[2] >> 4) & 1; + ambe_frame[9] = (b[2] >> 3) & 1; + ambe_frame[10] = (b[2] >> 2) & 1; + ambe_frame[11] = (b[2] >> 1) & 1; + ambe_frame[12] = (b[3] >> 8) & 1; + ambe_frame[13] = (b[3] >> 7) & 1; + ambe_frame[14] = (b[3] >> 6) & 1; + ambe_frame[15] = (b[3] >> 5) & 1; + ambe_frame[16] = (b[3] >> 4) & 1; + ambe_frame[17] = (b[3] >> 3) & 1; + ambe_frame[18] = (b[3] >> 2) & 1; + ambe_frame[19] = (b[3] >> 1) & 1; + ambe_frame[20] = (b[4] >> 6) & 1; + ambe_frame[21] = (b[4] >> 5) & 1; + ambe_frame[22] = (b[4] >> 4) & 1; + ambe_frame[23] = (b[4] >> 3) & 1; + ambe_frame[24] = (b[5] >> 4) & 1; + ambe_frame[25] = (b[5] >> 3) & 1; + ambe_frame[26] = (b[5] >> 2) & 1; + ambe_frame[27] = (b[5] >> 1) & 1; + ambe_frame[28] = (b[6] >> 3) & 1; + ambe_frame[29] = (b[6] >> 2) & 1; + ambe_frame[30] = (b[6] >> 1) & 1; + ambe_frame[31] = (b[7] >> 3) & 1; + ambe_frame[32] = (b[7] >> 2) & 1; + ambe_frame[33] = (b[7] >> 1) & 1; + ambe_frame[34] = (b[8] >> 2) & 1; + ambe_frame[35] = b[1] & 1; + ambe_frame[36] = b[2] & 1; + ambe_frame[37] = (b[0] >> 2) & 1; + ambe_frame[38] = (b[0] >> 1) & 1; + ambe_frame[39] = b[0] & 1; + ambe_frame[40] = b[3] & 1; + ambe_frame[41] = (b[4] >> 2) & 1; + ambe_frame[42] = (b[4] >> 1) & 1; + ambe_frame[43] = b[4] & 1; + ambe_frame[44] = b[5] & 1; + ambe_frame[45] = b[6] & 1; + ambe_frame[46] = b[7] & 1; + ambe_frame[47] = (b[8] >> 1) & 1; + ambe_frame[48] = b[8] & 1; + + for(int i = 0; i < 7; ++i){ + for(int j = 0; j < 8; ++j){ + ambe[i] |= (ambe_frame[(i*8)+j] << (7-j)); + } + } + } + + void MBEVocoder::initMbeParms() + { + mbe_initMbeParms(m_mbelibParms->m_cur_mp, m_mbelibParms->m_prev_mp, m_mbelibParms->m_prev_mp_enhanced); + //m_errs = 0; + m_errs2 = 0; + m_err_str[0] = 0; + } + + void MBEVocoder::process_2400x1200(unsigned char *d) + { + char ambe_fr[4][24]; + + memset(ambe_fr, 0, 96); + w = dW; + x = dX; + + for(int i = 0; i < 9; ++i){ + for(int j = 0; j < 8; ++j){ + ambe_fr[*w][*x] = (1 & (d[i] >> j)); + w++; + x++; + } + } + + mbe_processAmbe3600x2400Framef(m_audio_out_temp_buf, &m_errs2, m_err_str, ambe_fr, ambe_d,m_mbelibParms-> m_cur_mp, m_mbelibParms->m_prev_mp, m_mbelibParms->m_prev_mp_enhanced, 3); + static const float kOut = powf(10.0f, DSTAR_OUT_GAIN_DB / 20.0f); + for (int i = 0; i < 160; i++) m_audio_out_temp_buf[i] *= kOut; + processAudio(); + } + + void MBEVocoder::process_2450x1150(unsigned char *d) + { + char ambe_fr[4][24]; + + memset(ambe_fr, 0, 96); + 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 & (d[i] >> (7 - (j+1)))); + ambe_fr[*w][*x] = (1 & (d[i] >> (7 - j))); + w++; + x++; + y++; + z++; + } + } + + mbe_processAmbe3600x2450Framef(m_audio_out_temp_buf, &m_errs2, m_err_str, ambe_fr, ambe_d,m_mbelibParms-> m_cur_mp, m_mbelibParms->m_prev_mp, m_mbelibParms->m_prev_mp_enhanced, 3); + processAudio(); + } + + void MBEVocoder::process_2450(unsigned char *d) + { + char ambe_data[49]; + char dvsi_data[7]; + memset(dvsi_data, 0, 7); + + for(int i = 0; i < 6; ++i){ + for(int j = 0; j < 8; j++){ + ambe_data[j+(8*i)] = (1 & (d[i] >> (7 - j))); + } + } + ambe_data[48] = (1 & (d[6] >> 7)); + processData(ambe_data); + } + + void MBEVocoder::processData(char ambe_data[49]) + { + mbe_processAmbe2450Dataf(m_audio_out_temp_buf, &m_errs2, m_err_str, ambe_data, m_mbelibParms->m_cur_mp,m_mbelibParms->m_prev_mp, m_mbelibParms->m_prev_mp_enhanced, 3); + processAudio(); + } + + short * MBEVocoder::getAudio(int& nbSamples) + { + nbSamples = m_audio_out_nb_samples; + return m_audio_out_buf; + } + + void MBEVocoder::resetAudio() + { + m_audio_out_nb_samples = 0; + m_audio_out_buf_p = m_audio_out_buf; + } + + void MBEVocoder::processAudio() + { + m_audio_out_temp_buf_p = m_audio_out_temp_buf; + + if (m_audio_out_nb_samples + 160 >= m_audio_out_buf_size){ + resetAudio(); + } + + for (int i = 0; i < 160; i++){ + if (*m_audio_out_temp_buf_p > static_cast(32760)){ + *m_audio_out_temp_buf_p = static_cast(32760); + } + else if (*m_audio_out_temp_buf_p < static_cast(-32760)){ + *m_audio_out_temp_buf_p = static_cast(-32760); + } + + *m_audio_out_buf_p = static_cast(*m_audio_out_temp_buf_p); + m_audio_out_buf_p++; + + m_audio_out_nb_samples++; + m_audio_out_temp_buf_p++; + } + } diff --git a/mbe/mbevocoder.h b/mbe/mbevocoder.h new file mode 100644 index 0000000..d748ed7 --- /dev/null +++ b/mbe/mbevocoder.h @@ -0,0 +1,63 @@ +/* + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MBEVOCODER_H +#define MBEVOCODER_H + +#include +#include +#include "mbelib_parms.h" + +class MBEVocoder +{ +public: + MBEVocoder(); + ~MBEVocoder(); + void decode_2400x1200(int16_t *pcm, uint8_t *codec); + void decode_2450x1150(int16_t *pcm, uint8_t *codec); + void decode_2450(int16_t *pcm, uint8_t *codec); + void encode_2400x1200(int16_t *pcm, uint8_t *codec); + void encode_2450x1150(int16_t *pcm, uint8_t *codec); + void encode_2450(int16_t *pcm, uint8_t *codec); + +private: + imbe_vocoder vocoder; + mbelibParms *m_mbelibParms; + int m_errs2; + char m_err_str[64]; + + float m_audio_out_temp_buf[160]; //!< output of decoder + float *m_audio_out_temp_buf_p; + //float m_aout_max_buf[200]; + //float *m_aout_max_buf_p; + //int m_aout_max_buf_idx; + short m_audio_out_buf[2*48000]; //!< final result - 1s of L+R S16LE samples + short *m_audio_out_buf_p; + int m_audio_out_nb_samples; + int m_audio_out_buf_size; + const int *w, *x, *y, *z; + char ambe_d[49]; + float m_dstar_gain_s; + + void initMbeParms(); + void process_2400x1200(unsigned char *d); + void process_2450x1150(unsigned char *d); + void process_2450(unsigned char *d); + void processData(char ambe_data[49]); + short *getAudio(int& nbSamples); + void resetAudio(); + void processAudio(); +}; + +#endif // MBEVOCODER_H diff --git a/mbe/mbevocoder_api.h b/mbe/mbevocoder_api.h new file mode 100644 index 0000000..c1de803 --- /dev/null +++ b/mbe/mbevocoder_api.h @@ -0,0 +1,104 @@ +/* + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MBEVOCODER_API_H +#define MBEVOCODER_API_H + +#include + +extern "C" { + +struct mbe_parameters +{ + float w0; + int L; + int K; + int Vl[57]; + float Ml[57]; + float log2Ml[57]; + float PHIl[57]; + float PSIl[57]; + float gamma; + int un; + int repeat; +}; + +typedef struct mbe_parameters mbe_parms; + +struct mbelibParms +{ + mbe_parms *m_cur_mp; + mbe_parms *m_prev_mp; + mbe_parms *m_prev_mp_enhanced; + + mbelibParms() + { + m_cur_mp = (mbe_parms *) malloc(sizeof(mbe_parms)); + m_prev_mp = (mbe_parms *) malloc(sizeof(mbe_parms)); + m_prev_mp_enhanced = (mbe_parms *) malloc(sizeof(mbe_parms)); + } + + ~mbelibParms() + { + free(m_prev_mp_enhanced); + free(m_prev_mp); + free(m_cur_mp); + } +}; +} + +class MBEVocoder +{ +public: + MBEVocoder(); + ~MBEVocoder(); + void decode_2400x1200(int16_t *pcm, uint8_t *codec); + void decode_2450x1150(int16_t *pcm, uint8_t *codec); + void decode_2450(int16_t *pcm, uint8_t *codec); + void encode_2400x1200(int16_t *pcm, uint8_t *codec); + void encode_2450x1150(int16_t *pcm, uint8_t *codec); + void encode_2450(int16_t *pcm, uint8_t *codec); + +private: + imbe_vocoder vocoder; + mbe_parms cur_mp; + mbe_parms prev_mp; + mbelibParms *m_mbelibParms; + //int m_errs; + int m_errs2; + char m_err_str[64]; + + float m_audio_out_temp_buf[160]; //!< output of decoder + float *m_audio_out_temp_buf_p; + float m_aout_max_buf[200]; + float *m_aout_max_buf_p; + int m_aout_max_buf_idx; + short m_audio_out_buf[2*48000]; //!< final result - 1s of L+R S16LE samples + short *m_audio_out_buf_p; + int m_audio_out_nb_samples; + int m_audio_out_buf_size; + const int *w, *x, *y, *z; + char ambe_d[49]; + + void initMbeParms(); + void process_2400x1200(unsigned char *d); + void process_2450x1150(unsigned char *d); + void process_2450(unsigned char *d); + void processData(char ambe_data[49]); + short *getAudio(int& nbSamples); + void resetAudio(); + void processAudio(); +}; + +#endif // MBEVOCODER_API_H diff --git a/mbe/vocoder_tables.h b/mbe/vocoder_tables.h new file mode 100644 index 0000000..26c7d2a --- /dev/null +++ b/mbe/vocoder_tables.h @@ -0,0 +1,491 @@ +/* + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +extern "C" { +const unsigned char BIT_MASK_TABLE[] = {0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U}; + +#define WRITE_BIT(p,i,b) p[(i)>>3] = (b) ? (p[(i)>>3] | BIT_MASK_TABLE[(i)&7]) : (p[(i)>>3] & ~BIT_MASK_TABLE[(i)&7]) +#define READ_BIT(p,i) (p[(i)>>3] & BIT_MASK_TABLE[(i)&7]) + +const unsigned int A_TABLE[] = {0U, 4U, 8U, 12U, 16U, 20U, 24U, 28U, 32U, 36U, 40U, 44U, + 48U, 52U, 56U, 60U, 64U, 68U, 1U, 5U, 9U, 13U, 17U, 21U}; +const unsigned int B_TABLE[] = {25U, 29U, 33U, 37U, 41U, 45U, 49U, 53U, 57U, 61U, 65U, 69U, + 2U, 6U, 10U, 14U, 18U, 22U, 26U, 30U, 34U, 38U, 42U}; +const unsigned int C_TABLE[] = {46U, 50U, 54U, 58U, 62U, 66U, 70U, 3U, 7U, 11U, 15U, 19U, 23U, + 27U, 31U, 35U, 39U, 43U, 47U, 51U, 55U, 59U, 63U, 67U, 71U}; +const unsigned int PRNG_TABLE[] = { + 0x42CC47U, 0x19D6FEU, 0x304729U, 0x6B2CD0U, 0x60BF47U, 0x39650EU, 0x7354F1U, 0xEACF60U, 0x819C9FU, 0xDE25CEU, + 0xD7B745U, 0x8CC8B8U, 0x8D592BU, 0xF71257U, 0xBCA084U, 0xA5B329U, 0xEE6AFAU, 0xF7D9A7U, 0xBCC21CU, 0x4712D9U, + 0x4F2922U, 0x14FA37U, 0x5D43ECU, 0x564115U, 0x299A92U, 0x20A9EBU, 0x7B707DU, 0x3BE3A4U, 0x20D95BU, 0x6B085AU, + 0x5233A5U, 0x99A474U, 0xC0EDCBU, 0xCB5F12U, 0x918455U, 0xF897ECU, 0xE32E3BU, 0xAA7CC2U, 0xB1E7C9U, 0xFC561DU, + 0xA70DE6U, 0x8DBE73U, 0xD4F608U, 0x57658DU, 0x0E5E56U, 0x458DABU, 0x7E15B8U, 0x376645U, 0x2DFD86U, 0x64EC3BU, + 0x3F1F60U, 0x3481B4U, 0x4DA00FU, 0x067BCEU, 0x1B68B1U, 0xD19328U, 0xCA03FFU, 0xA31856U, 0xF8EB81U, 0xF9F2F8U, + 0xA26067U, 0xA91BB6U, 0xF19A59U, 0x9A6148U, 0x8372B6U, 0xC8E86FU, 0x9399DCU, 0x1A0291U, 0x619142U, 0x6DE9FFU, + 0x367A2CU, 0x7D2511U, 0x6484DAU, 0x2F1F0FU, 0x1E6DB4U, 0x55F6E1U, 0x0EA70AU, 0x061C96U, 0xDD0E45U, 0xB4D738U, + 0xAF64ABU, 0xE47F42U, 0xFDBE9DU, 0xB684ACU, 0xFE5773U, 0xC1E4A2U, 0x8AFD0DU, 0x932ED4U, 0xD814E3U, 0x81853AU, + 0x225EECU, 0x7A6945U, 0x31A112U, 0x2AB2EBU, 0x630974U, 0x785AB5U, 0x11E3CEU, 0x4A715BU, 0x402AA0U, 0x199B7DU, + 0x16C05EU, 0x6F5283U, 0xA4FB10U, 0xBFA8ECU, 0xF633B7U, 0xEC4012U, 0xADD8C9U, 0xD6EB1CU, 0xDD3027U, 0x84A1FAU, + 0xCF9E19U, 0xD64C80U, 0xBC4557U, 0xA7B62EU, 0x6E2DA1U, 0x311F50U, 0x38C68EU, 0x63D5BFU, 0x486E60U, 0x10BFE1U, + 0x5BAD1EU, 0x4A4647U, 0x0157F0U, 0x7ACC29U, 0x73BEEAU, 0x2825D7U, 0xA0940CU, 0xFBCFF9U, 0xB05C62U, 0x892426U, + 0xC6B3DDU, 0xDF3840U, 0x9449B3U, 0xCED3BEU, 0xE7804DU, 0xBC3B90U, 0xF5AA0BU, 0xE6D17EU, 0x2D43B5U, 0x345A04U, + 0x5EA9DBU, 0x07A202U, 0x0C7134U, 0x45C9FDU, 0x5EDA0AU, 0x310193U, 0x6830C4U, 0x62AA3DU, 0x3B59B2U, 0xB04043U, + 0xEB975CU, 0x82BCADU, 0x912E62U, 0xD8F7FBU, 0x82C489U, 0x895F54U, 0xF00FE7U, 0xFBBC2AU, 0xA2E771U, 0xE956C4U, + 0xF6CD1FU, 0x3F8FEAU, 0x0534E1U, 0x4C653CU, 0x17FE8FU, 0x1C4C52U, 0x4515A1U, 0x2E86A9U, 0x3FBD56U, 0x756C87U, + 0x6ED218U, 0x279179U, 0x7C0AA6U, 0xD53B17U, 0x8EE0C8U, 0x85F291U, 0xD94B36U, 0x9298EFU, 0xAB8318U, 0xE07301U, + 0xBB68DFU, 0xB2CB7CU, 0xE910A5U, 0xE101D2U, 0x92BB4BU, 0x59E8B4U, 0x407175U, 0x0B026AU, 0x12989BU, 0x792944U, + 0x2376EDU, 0x2EF5BAU, 0x758663U, 0x7C1ED5U, 0x078D0CU, 0x4EF6ABU, 0x5567F2U, 0x9F7C29U, 0xC68E9CU, 0xC51747U, + 0xBC6422U, 0xB7EFB9U, 0xECFD44U, 0xA50497U, 0xAF178AU, 0xD68C69U, 0xD97DB5U, 0x82670EU, 0xCBB45BU, 0x508D90U, + 0x190A25U, 0x63F0FEU, 0x68E3C7U, 0x317A10U, 0x3A09D9U, 0x6B926EU, 0x004237U, 0x1B79C8U, 0x53EA59U, 0x48B3B7U, + 0x811166U, 0xDE4A79U, 0xF5F988U, 0xAC6057U, 0xE733FEU, 0xFF89ADU, 0xB49830U, 0x8F4BC3U, 0xC6F00EU, 0x9DA135U, + 0x942FE0U, 0xC71C3BU, 0x4DC78FU, 0x3476C4U, 0x7F6C39U, 0x66BFAAU, 0x298657U, 0x725504U, 0x5B4E89U, 0x01FE72U, + 0x0835A3U, 0x53269CU, 0x189D4DU, 0x01CDC2U, 0xEA763BU, 0xF3A56DU, 0xB0BCD4U, 0xE80F13U, 0xE355CAU, 0x98C47DU, + 0x91AB24U, 0xCE38DBU, 0x87A35AU, 0x9CD3A5U, 0xD648F4U, 0xAF7B6FU, 0x24A292U, 0x7D3011U, 0x764B6DU, 0x2DDABEU, + 0x44D123U, 0x5E22D8U, 0x1FB09DU, 0x04A926U, 0x4F5AF3U, 0x064128U, 0x3DB105U, 0x70AAD6U, 0xAA392FU, 0xA1C4B8U, + 0xF8C7C0U, 0xD35D0FU, 0x8A2E9EU, 0xC1B761U, 0xDA44F0U, 0x925E8FU, 0x89CF4EU, 0xE8B4D1U, 0xB32728U, 0xB8FE7FU, + 0x61DCC6U, 0x2A4701U, 0x1614D8U, 0x5DADE2U, 0x46BE37U, 0x0F44DCU, 0x54D549U, 0x5D8E32U, 0x263DAFU, 0x2C237CU, + 0x75E291U, 0xBE5982U, 0xA74A7FU, 0xC493A4U, 0xDFA131U, 0x967A5AU, 0xCCCB8EU, 0xC1D835U, 0x9A02ECU, 0xF331BBU, + 0xE8B812U, 0xA3EBC5U, 0xBA507CU, 0x7080ABU, 0x099BC2U, 0x02285DU, 0x59718CU, 0x50C273U, 0x0B1862U, 0x4A1F8CU, + 0x70A655U, 0x3BF5C2U, 0x666FBBU, 0x6DDE68U, 0x3485C5U, 0x9F161EU, 0xC46F4BU, 0x8CFDF0U, 0x97C625U, 0xDE058EU, + 0xC59CD3U, 0xAEAE20U, 0xF775BCU, 0xFC647FU, 0xBD9F02U, 0xE70C91U, 0xCC1468U, 0x11E7B7U, 0x1AFC36U, 0x435B49U, + 0x080398U, 0x139027U, 0x7B63FEU, 0x607AF9U, 0x29E900U, 0x7293D6U, 0x79026FU, 0x00D930U, 0x0BEAF1U, 0xD3614EU, + 0x90119FU, 0x8B8AE4U, 0xC61969U, 0xBD609AU, 0xB4F247U, 0xEFA954U, 0xE518A9U, 0xBC0362U, 0xD7D0D6U, 0xCE7E8DU, + 0x856F18U, 0x1C94E3U, 0x578726U, 0x0D5F1DU, 0x24ECC0U, 0x7FF713U, 0x3E26AAU, 0x251D6DU, 0x6A8F14U, 0x53648BU, + 0x19757AU, 0x40AEB4U, 0xCB9CA5U, 0x90055AU, 0x9956C3U, 0xE2ED34U, 0xAB3C7DU, 0xB126EAU, 0xFA9513U, 0xA3D2C8U, + 0x886BFDU, 0xD9F836U, 0xD2A2E3U, 0x8D1359U, 0x454804U, 0x5EDBF7U, 0x37637AU, 0x2C3089U, 0x67ABD4U, 0x3E8847U, + 0x3551BAU, 0x4D6331U, 0x46B8C4U, 0x1D299FU, 0x54120EU, 0x5FC0E1U, 0x86D93BU, 0xE56A0EU, 0xFBB1D5U, 0xB2B600U, + 0xA94EABU, 0xE05DF6U, 0x9BE605U, 0x90B798U, 0xC92C6BU, 0xC3DE66U, 0x9AC7BDU, 0xD15448U, 0x6A3FD3U, 0x23ADA3U, + 0x78346CU, 0x7147F5U, 0x2BDC02U, 0x0EAD5BU, 0x553FFCU, 0x1EA425U, 0x07D5F2U, 0x4C4ECBU, 0x554C14U, 0x3EB3F5U, + 0xE4A26AU, 0xED799BU, 0xB6CA85U, 0xFFD25CU, 0xC421BFU, 0x8F3A22U, 0x96AB51U, 0xDC518CU, 0x895217U, 0x8289F2U, + 0xF9B8A9U, 0xF0231CU, 0x2BF1C7U, 0x62C80AU, 0x781B39U, 0x1320E5U, 0x4AB156U, 0x41EB8FU, 0x1848E0U, 0x13D771U, + 0x4886AEU, 0x203C5FU, 0x3B6F40U, 0x76F6A1U, 0xE5457EU, 0xAE1EE7U, 0xD7AC10U, 0xDCB549U, 0x8476EFU, 0x8FC536U, + 0xD49DE9U, 0x9D0ED8U, 0xA63513U, 0xEFE4A6U, 0xB4DF7DU, 0x3E0D00U, 0x779693U, 0x4CA75EU, 0x0568ADU, 0x527BB0U, + 0x59C34BU, 0x00109FU, 0x0A0B14U, 0x73FA61U, 0x38E0BAU, 0x23530FU, 0x6A88D4U, 0xB199DDU, 0x98322AU, 0xC260F3U, + 0xCBF944U, 0x908A0DU, 0xDB11F2U, 0xC28163U, 0xADFABDU, 0xBC694CU, 0xF65243U, 0xAD83BAU, 0xA40D6DU, 0x5F7EF4U, + 0x16E787U, 0x0DF44AU, 0x460EF1U, 0x5E1F24U, 0x15CC3FU, 0x6C77CAU, 0x676401U, 0x3C9CBDU, 0x359FEEU, 0x6A0413U, + 0x02F590U, 0x91EE4DU, 0xDA3C3EU, 0xC305A3U, 0x889658U, 0xF14D99U, 0xFA7F86U, 0xA1E677U, 0xE981E8U, 0xF21A10U, + 0xBB4BD7U, 0x80F1CEU, 0xCB6239U, 0x123BE0U, 0x1D885FU, 0x45921EU, 0x6641E1U, 0x3DE870U, 0x74BBAFU, 0x6F00C6U, + 0x261055U, 0x7DCBA8U, 0x57787AU, 0x0E2167U, 0x05B28CU, 0xCC8819U, 0x975BE2U, 0xBC52B7U, 0xE5E52CU, 0xEB37C9U, + 0xB20E12U, 0xF9DD2FU, 0xE8C6FCU, 0x837701U, 0xD8AD82U, 0xD1BE5AU, 0x0B0525U, 0x0244B4U, 0x79FE5BU, 0x322DCAU, + 0x2B3495U, 0x60876CU, 0x79DCFBU, 0x334C12U, 0x4C7745U, 0x45A4DCU, 0x1E3F23U, 0x175FF2U, 0xC4C0D8U, 0xAFF30DU, + 0xB72AF6U, 0xFCB96BU, 0xA5C338U, 0xAE5295U, 0xF54946U, 0xDCBABBU, 0x87A1A8U, 0xCF2165U, 0xD4DA9EU, 0x9FC90BU, + 0x223070U, 0x6922A4U, 0x30B92FU, 0x3348D6U, 0x695B01U, 0x20C038U, 0x1BB2EFU, 0x523B06U, 0x49EC99U, 0x02D7C8U, + 0x5B4777U, 0x713CA6U, 0xA8AF49U, 0xA3B650U, 0xF84586U, 0xB5DF7FU, 0xAE8CF8U, 0xC72581U, 0x9D3652U, 0x9EEDCFU, + 0xC75D34U, 0xCC0671U, 0xB5B5CAU, 0xFEAC1FU, 0x677EA4U, 0x2DC5F9U, 0x26D63AU, 0x7F1F86U, 0x142855U, 0x0DF2A8U, + 0x42E3B3U, 0x195872U, 0x108B8DU, 0x6AB31CU, 0x632063U, 0x307BAAU, 0xFBC83DU, 0xE201C4U, 0xA91393U, 0x90A82AU, + 0xDAF9E4U, 0x816A55U, 0x88D00AU, 0xD383DBU, 0xFA3A64U, 0xA569A5U, 0xEEE2DEU, 0x76D243U, 0x3D0D90U, 0x649E6DU, + 0x47E76EU, 0x1C7491U, 0x156E49U, 0x4E9DDEU, 0x0604B7U, 0x3D3720U, 0x76FDD9U, 0x6FEC06U, 0x2417B7U, 0xFD04F8U, + 0xF29D29U, 0x886F92U, 0xC1744FU, 0xDAC73CU, 0x939EB1U, 0x880C63U, 0xEBE79EU, 0xB2F285U, 0xB86970U, 0xE11ABBU, + 0xEA822EU, 0x311155U, 0x586AC0U, 0x43F92BU, 0x0A81F6U, 0x5412C5U, 0x5D111CU, 0x26E8CBU, 0x2D7B63U, 0x74213CU, + 0x3F90CDU, 0x2E8B52U, 0x645883U, 0xDFE36CU, 0x96F375U, 0xDD0882U, 0xC40B1BU, 0x8FD6CCU, 0xB464A5U, 0xFC7F3EU, + 0xA7AECBU, 0xAA9511U, 0xF10634U, 0xBA5CEFU, 0x83ED32U, 0x483681U, 0x5015DCU, 0x138D3FU, 0x48DEA2U, 0x616571U, + 0x3AF40CU, 0x33AF97U, 0x681D72U, 0x2246E9U, 0x3BD7B9U, 0x506C46U, 0x0D2FDFU, 0x869338U, 0xDDC061U, 0xD45BD6U, + 0xAF6A0FU, 0xE7B8C0U, 0xFC2371U, 0xBF102EU, 0xA6C9DFU, 0xEDDA40U, 0x943089U, 0x9FA1BFU, 0x459A66U, 0x0C4995U, + 0x175108U, 0x7AE243U, 0x6139B6U, 0x2A2A2DU, 0x73D3D8U, 0x79C183U, 0x204A26U, 0x0B3FFDU, 0x5AA420U, 0x111613U, + 0x8A4FDFU, 0xC3DC2CU, 0xF9A7B5U, 0xB034EAU, 0xEBAC5BU, 0xE0CF94U, 0xBD5465U, 0xF605FAU, 0xCFBEA3U, 0x85AC54U, + 0x9E55DDU, 0xD7C62AU, 0x0CDD73U, 0x252FCDU, 0x76361CU, 0x7DF5D3U, 0x3546E2U, 0x6E5B39U, 0x67A98CU, 0x1CB247U, + 0x57231AU, 0x4AD8A9U, 0x01CA74U, 0x191187U, 0xF2208AU, 0xA9AB50U, 0xA0F8A5U, 0xFB403EU, 0xF2D34BU, 0xA9A880U, + 0xCB393DU, 0xD262EEU, 0x99D0B7U, 0xC04B00U, 0xCB1AC9U, 0xB0B176U, 0x39E3A7U, 0x677EF8U, 0x2ECD58U, 0x359687U, + 0x7E277EU, 0x473D69U, 0x0CEEB0U, 0x55D557U, 0x5F04CEU, 0x0C8EBDU, 0x25BD60U, 0x7E64DBU, 0xB7771EU, 0xACCC05U, + 0xE51CF0U, 0xBF2F2AU, 0x90F497U, 0xC9E7D4U, 0xC25F09U, 0x9B9CBAU, 0xD08767U, 0xEB320CU, 0xA36999U, 0x38FB42U, + 0x7180B3U, 0x22112CU, 0x29AA45U, 0x50F9D2U, 0x1B610AU, 0x0202FDU, 0x4899E4U, 0x57080BU, 0x3E72DAU, 0x65E165U, + 0x6CFA34U, 0xB70BEBU, 0xBC104AU, 0xE4E295U, 0x8F7BECU, 0x96787FU, 0xD583B2U, 0x9E9740U, 0x870C5DU, 0xECFFA6U, + 0xF4E433U, 0xBF35F8U, 0xE00F8DU, 0x699C16U, 0x3265EBU, 0x1B6638U, 0x40F515U, 0x0A8DC6U, 0x131E1BU, 0x5845A0U, + 0x21F670U, 0x2A6E1FU, 0x791D8EU, 0x708651U, 0x2AD7E8U, 0xE37CAFU, 0xD8EE56U, 0x97B3C1U, 0x8E0018U, 0xC51B6FU, + 0x9CC9E6U, 0xB67019U, 0xEF23C8U, 0xE498F2U, 0xBF9927U, 0xF643ECU, 0xCD7051U, 0x04E902U, 0x563AFFU, 0x5D006CU, + 0x04D3A1U, 0x0FCA9AU, 0x72794FU, 0x39A2B4U, 0x228231U, 0x6A19EAU, 0x714E96U, 0x18F705U, 0x4324FCU, 0xC83E3BU, + 0x918D02U, 0xDADCD5U, 0xC2470CU, 0xA135B3U, 0xBABCF2U, 0xF30F4DU, 0xA8549EU, 0xA1C543U, 0xDEFF78U, 0xD42CBCU, + 0x0DB747U, 0x46C6D2U, 0x5F5C89U, 0x144F60U, 0x6FA6F7U, 0x66350EU, 0x2C0A59U, 0x35DAE0U, 0x7EC12FU, 0x0D32FEU, + 0x0429C1U, 0x5FB911U, 0xD642AEU, 0x895167U, 0xC3D8B0U, 0xFAAB89U, 0xB1315AU, 0xA8C0A7U, 0xE3DB24U, 0xB84879U, + 0x913382U, 0xCBA317U, 0x82F8FCU, 0x994BA9U, 0x50C213U, 0x4390CEU, 0x282F5DU, 0x713E30U, 0x7FCDE3U, 0x26565EU, + 0x2D0485U, 0x56BDD4U, 0x1FAE7BU, 0x0475AAU, 0x4DD555U, 0x17CE4CU, 0x9C1D9BU, 0xE52473U, 0xEEF7E4U, 0xB7CD1DU, + 0xF45E42U, 0xEF87E3U, 0x87B43CU, 0x986FADU, 0xD16FD2U, 0x8AD403U, 0x8103A8U, 0xD83A75U, 0x33A826U, 0x2BF39BU, + 0x604049U, 0x7B99A4U, 0x328ABFU, 0x49306AU, 0x407191U, 0x1BEA04U, 0x19D96FU, 0x4001F2U, 0x0FB201U, 0x36E9DCU, + 0xFD7ADFU, 0xE64326U, 0xAF91F9U, 0xF51249U, 0xDC2B16U, 0x87F8D7U, 0xCCE668U, 0xC517B1U, 0x9E8C46U, 0x97BF5FU, + 0xED6498U, 0xA67461U, 0x378FF6U, 0x788C8FU, 0x611514U, 0x0AE6F1U, 0x53FC2BU, 0x596F3EU, 0x0216C5U, 0x4B8508U, + 0x507FBBU, 0x396EE6U, 0x22F535U, 0xE99688U, 0xB10F43U, 0xBA1D36U, 0xC3E2ADU, 0xC07178U, 0x9B28C3U, 0xD69A8BU, + 0xCD817CU, 0x8570E5U, 0xFEEB12U, 0xF5E8CBU, 0xAC10C4U, 0x270335U, 0x7ED8EAU, 0x156B5BU, 0x0E7A14U, 0x46A0C5U, + 0x5D937AU, 0x144AA3U, 0x4F79D5U, 0x6CF35CU, 0x31228FU, 0x7A1932U, 0x628E69U, 0xA9D59CU, 0x926517U, 0xDBBEE2U, + 0x80ADB9U, 0x891424U, 0xD246D7U, 0xD8ED1AU, 0xA17C28U, 0xEA27F5U, 0xF3942EU, 0xB8CE8FU, 0xAB5FD0U, 0x466461U, + 0x1CB7BEU, 0x152F6FU, 0x4E1CC0U, 0x05D799U, 0x1CE66EU, 0x773DF7U, 0x7EAB00U, 0x249048U, 0x6D41D7U, 0x765A26U, + 0x1DA9F9U, 0x8431C8U, 0xCF0203U, 0x96C1DEU, 0x90D86DU, 0xCB6A30U, 0xA23193U, 0xB9A24EU, 0xF05B95U, 0xEB48A0U, + 0xA0D27AU, 0xD8A39FU, 0xD33804U, 0x0A9B79U, 0x01C3AAU, 0x5A5437U, 0x132FD4U, 0x28BC0DU, 0x60253AU, 0x3F57E3U, + 0x3CCC7CU, 0x65DD9DU, 0x4E26C2U, 0x172572U, 0xDCDDADU, 0xC64E64U, 0x8F5553U, 0x94A68AU, 0xFDBE7DU, 0xA66DE4U, + 0xADD68BU, 0xF4C75AU, 0xFE0CC1U, 0x873E34U, 0xC8A72FU, 0xDBD0C2U, 0x124B10U, 0x49998DU, 0x40A8FEU, 0x3A3323U, + 0x316088U, 0x68D95DU, 0x235B06U, 0x3A00B3U, 0x51B178U, 0x4AEA89U, 0x025816U, 0x59C36FU, 0xD092B8U, 0x8B2930U, + 0xE43AC7U, 0xF5E2DEU, 0xBEC121U, 0xA71AF0U, 0xED8B7FU, 0x94B40EU, 0x9F66D1U, 0xD45D68U, 0xCD8CBFU, 0x8617F6U, + 0x5F2545U, 0x75FC98U, 0x2EFF62U, 0x674467U, 0x7C959CU, 0x318F09U, 0x0A7CD2U, 0x4967AFU, 0x11D62CU, 0x1A8CD1U, + 0x431F02U, 0x48A69DU, 0xB3E5ECU, 0xFA7623U, 0xE10E9AU, 0xA99948U, 0xB20215U, 0xD971A6U, 0x80E86BU, 0x8BDA90U, + 0xD60185U, 0x9D907EU, 0x8FFBFBU, 0xE66920U, 0x7D705DU, 0x3483CEU, 0x6F9833U, 0x646BF1U, 0x1DF3E8U, 0x17E017U, + 0x4E1BC6U, 0x050A79U, 0x1E8038U, 0x5773E7U, 0x2C685EU, 0xA1BD89U, 0xFB86B0U, 0xF01477U, 0xA16D8EU, 0xCAFE19U, + 0xD365C1U, 0x9815AEU, 0x839E3FU, 0xCBCDC4U, 0x907611U, 0xB9E70AU, 0xE2BDE7U, 0x2B0E34U, 0x301789U, 0x7BE4DAU, + 0x477707U, 0x0C2FACU, 0x558C79U, 0x5E9743U, 0x0D4496U, 0x04786DU, 0x7FABE0U, 0x3730B3U, 0x3C014AU, 0xE7DADDU, + 0xEEE834U, 0x956163U, 0xDCB2FAU, 0xC78905U, 0x8D5BD4U, 0xD0427BU, 0xDBF12BU, 0xA22AB4U, 0xA93B4DU, 0xFA819AU, + 0xB3D2B3U, 0x287B64U, 0x40289DU, 0x5BB206U, 0x100153U, 0x495CB8U, 0x42CF2DU, 0x3BF4D6U, 0x70248BU, 0x6ABF19U, + 0x23CCF4U, 0x3C4527U, 0x75761AU, 0x8EACC1U, 0x853F44U, 0xD44EBFU, 0xDED5EEU, 0x87C751U, 0xEC3E80U, 0xF72D6FU, + 0xBEB676U, 0xE557A1U, 0xEC4D59U, 0xB6BECEU, 0x9DA527U, 0x443078U, 0x0BCAE9U, 0x12D916U, 0x594087U, 0x6033E8U, + 0x22A831U, 0x7948A2U, 0x70535FU, 0x2BC01CU, 0x62BBA1U, 0x592A7BU, 0x92308EU, 0x8AC395U, 0xC15A50U, 0x9809ABU, + 0xB3B336U, 0xECB245U, 0xE54998U, 0xBEDA1BU, 0xF681E6U, 0xED35F5U, 0x8E2E0CU, 0x87FDD3U, 0x5CC453U, 0x1556ACU, + 0x0E85FDU, 0x64AC42U, 0x3D7F8BU, 0x36447CU, 0x6FD665U, 0x640FB2U, 0x3B3C4BU, 0x52A7C4U, 0x48F7B5U, 0x014C2EU, + 0x9A9FFBU, 0xD19601U, 0xA0250CU, 0xAB7FFFU, 0xF2C822U, 0xB8D1B1U, 0xA302CCU, 0xEAB907U, 0xD1E9B2U, 0x987269U, + 0xC3411CU, 0xCC8897U, 0x141A42U, 0x3F61B8U, 0x66F2A1U, 0x2DCB56U, 0x3618DFU, 0x778208U, 0x2CB3F1U, 0x0468EEU, + 0x5F7B1FU, 0x5693D0U, 0x0D8041U, 0x461B3EU, 0xFFECE7U, 0xB4FD50U, 0xA94798U, 0xE314CFU, 0xB88D76U, 0xB17EADU, + 0xCA7508U, 0xC3E553U, 0x989EA6U, 0xDB0D3DU, 0xC396E8U, 0xA8E683U, 0x717D1EU, 0x7A0EEDU, 0x219730U, 0x288422U, + 0x736ECFU, 0x1BFF14U, 0x04A4A1U, 0x4F177AU, 0x56092BU, 0x1DD884U, 0x64635DU, 0xEF70EAU, 0xA589B3U, 0xF49B54U, + 0xFF50CDU, 0xA66312U, 0x8DFA62U, 0xD628FDU, 0x9F131CU, 0x8582C3U, 0xCCF9DAU, 0xF36A29U, 0xB8B2F4U, 0x618157U, + 0x6A020AU, 0x335999U, 0x79E864U, 0x4272BFU, 0x03259AU, 0x189C40U, 0x51CFB5U, 0x0A752EU, 0x216463U, 0x79BF90U, + 0x721C0DU, 0xAB47FEU, 0xE4D727U, 0xFDEC28U, 0x963FD9U, 0x8DA646U, 0xC594B7U, 0x9E4FE8U, 0x977E60U, 0xECA597U, + 0xAF264EU, 0xB61C79U, 0xFDCDA0U, 0x65D64FU, 0x2E61DCU, 0x553881U, 0x5CAA72U, 0x0351FBU, 0x0A400CU, 0x51FB55U, + 0x3BB9CAU, 0x22223AU, 0x6993B5U, 0x30C8C4U, 0x3B5B1BU, 0xE02B82U, 0xC1B075U, 0x9B23BCU, 0xD25A8BU, 0xC9C852U, + 0x82A3A9U, 0xBB303CU, 0xF42977U, 0xADDA82U, 0xA64418U, 0xFC55E5U, 0xB5AEE6U, 0x0EBD3BU, 0x4765C8U, 0x4CD655U, + 0x17DD2EU, 0x562EEBU, 0x6C3770U, 0x25A585U, 0x3E5EDEU, 0x754F6FU, 0x2C94A1U, 0x23A758U, 0x5A3F4FU, 0xD07C96U, + 0x8BC761U, 0xC254E8U, 0xD92C97U, 0xB0BF06U, 0xEBE0D9U, 0xE25138U, 0xB8CAA7U, 0xBB98DEU, 0xE22109U, 0x896291U, + 0x10F172U, 0x5BCB2FU, 0x401A94U, 0x0CA141U, 0x77B2BAU, 0x7E6BBFU, 0x255964U, 0x6E82D9U, 0x77130AU, 0x3C3877U, + 0x04EAF4U, 0x4FD129U, 0x9C40DBU, 0x959BC6U, 0xCEAC2DU, 0xE774FCU, 0xBC6763U, 0xF6DC12U, 0xEB8DCDU, 0xA00664U, + 0xF9F4B3U, 0xD2EF4AU, 0x895E5DU, 0x800584U, 0x5A972BU, 0x132EFBU, 0x287D84U, 0x63E615U, 0x7297CEU, 0x391D23U, + 0x608E30U, 0x6AF5CDU, 0x11641EU, 0x5C5E93U, 0x4789E0U, 0x0E903DU, 0x956386U, 0xFEF053U, 0xB6E879U, 0xAD0BACU, + 0xE41077U, 0xFF83CAU, 0xB47A99U, 0xCD6870U, 0xCE93E7U, 0x96823EU, 0x9D1941U, 0xC4EBD0U, 0x2BF23FU, 0x3031EEU, + 0x790A71U, 0x229909U, 0x2AC1CEU, 0x717677U, 0x5AEDA0U, 0x039C99U, 0x480646U, 0x515587U, 0x1AEC3CU, 0x296F69U, + 0xE13492U, 0xBA8607U, 0xB39FCCU, 0xEC4CB1U, 0xA77723U, 0x9EA7DEU, 0xD51C0DU, 0xCD0F00U, 0x86D4FBU, 0xDDF56EU, + 0xF46F95U, 0x2FBCD4U, 0x268D6BU, 0x7D52B2U, 0x374165U, 0x26F9DCU, 0x4D2A9BU, 0x141163U, 0x1FD2FCU, 0x40CA2DU, + 0x497952U, 0x3322D3U, 0x7AB32CU, 0xE108F5U, 0xAA5AE2U, 0xB3E31BU, 0xF8B098U, 0x812B65U, 0x8B8936U, 0xD0D08AU, + 0xD94341U, 0x8A7894U, 0xE3A9AFU, 0xF8377AU, 0xB74481U, 0x6FDD0CU, 0x64EE5FU, 0x3D35A2U, 0x163731U, 0x5F8ECCU, + 0x045DC7U, 0x0F4616U, 0x57B6E8U, 0x7CAD79U, 0x253E86U, 0x6EC7CFU, 0x7DD478U, 0xB426A1U, 0xCF2D76U, 0xC3BC5FU, + 0x984780U, 0x935571U, 0xCACCEEU, 0x81BBBFU, 0xB82054U, 0xF371C0U, 0xE9CB3BU, 0xA05826U, 0xFB33F5U, 0x52A218U, + 0x09B88BU, 0x424BF6U, 0x53D22DU, 0x198198U, 0x043A53U, 0x6F2A06U, 0x34F1BDU, 0x3DC260U, 0x664982U, 0x6FB81BU, + 0x15A24CU, 0xDE71F5U, 0xC7482AU, 0x8CDFCBU, 0x9505D4U, 0xDE3405U, 0xA5EFFAU, 0xA4FC63U, 0xFE5704U, 0xB387DDU, + 0xA8BC6AU, 0xC32FB2U, 0x5A7EE5U, 0x11C44CU, 0x489797U, 0x420E62U, 0x19BD79U, 0x30E6BCU, 0x6B6407U, 0x225DDAU, + 0x398EA9U, 0x703534U, 0x0A64F7U, 0x09FA0AU, 0xD4C910U, 0xDF10E5U, 0x86833EU, 0xCDB99BU, 0xE67A40U, 0xBE631BU, + 0xB590AEU, 0xEC8B75U, 0xA73BD0U, 0x9CE08BU, 0xD5F35EU, 0x8E0AE5U, 0x061828U, 0x5D835AU, 0x5660C7U, 0x277914U, + 0x68CAE9U, 0x7190E2U, 0x3A0113U, 0x20FECCU, 0x49ED7DU, 0x127522U, 0x1B06ABU, 0x40855CU, 0x8B9E85U, 0x926FB2U, + 0xF8F56AU, 0xE186A5U, 0xAA1F14U, 0xF10CCBU, 0xF0F7BAU, 0x8F6735U, 0x867CECU, 0xDC9F1FU, 0x978402U, 0x8E54F1U, + 0x45EF3CU, 0x7CFC8FU, 0x3705D2U, 0x6C1248U, 0x64C8BDU, 0x3FF976U, 0x566243U, 0x4DA198U, 0x069B45U, 0x1F0AF6U, + 0x5851BBU, 0x00E248U, 0xAB3BD1U, 0xF2090EU, 0xF9926FU, 0xA2C3F1U, 0xEB7800U, 0xD07B9FU, 0x98A1E6U, 0xC31021U, + 0xC84BB8U, 0x91D84FU, 0x9AEC96U, 0x6337A9U, 0x288468U, 0x369FB3U, 0x774E06U, 0x6C645DU, 0x05B7A9U, 0x4E2E22U, + 0x551DFFU, 0x1CC78CU, 0x47D611U, 0x4F2DF2U, 0x343E6FU, 0xBF8514U, 0xE655C1U, 0xAD5E5AU, 0xB4EDBFU, 0xDFB4E4U, + 0xC1265DU, 0x80DD8BU, 0xDBC852U, 0xD25375U, 0x8920ACU, 0xA2BA53U, 0xFB0BC2U, 0x31401DU, 0x28D33CU, 0x63AAE3U, + 0x18381AU, 0x11238DU, 0x4AD2E4U, 0x434933U, 0x195BABU, 0x56A058U, 0x6FB105U, 0x2C5AAEU, 0x35C97BU, 0xFED9A0U, + 0xA52295U, 0x8D314EU, 0xD6ECA3U, 0x9F5E30U, 0x84456DU, 0xCFB6DEU, 0xD6AF03U, 0xBD2CE9U, 0xE556FCU, 0xEEC707U, + 0xB71CD6U, 0x382F59U, 0x43B720U, 0x02E4F7U, 0x195F4EU, 0x51CC99U, 0x0AA550U, 0x013767U, 0x786CBEU, 0x73DD01U, + 0x2AC6D1U, 0x61159EU, 0x7BA92FU, 0x92BAF4U, 0x896109U, 0xC0521AU, 0x9F9AF7U, 0x942924U, 0xC532B9U, 0xEFE3C2U, + 0xA6D807U, 0xFD0ABCU, 0xF69369U, 0xAFA033U, 0x44738EU, 0x5D694DU, 0x17C8F0U, 0x0C93A3U, 0x45207AU, 0x1EF9C5U, + 0x37EB04U, 0x6850FBU, 0x6305EAU, 0x3B9E15U, 0x782DC4U, 0x41774BU, 0x8AF633U, 0xD18DE4U, 0xD81E5DU, 0x83A69AU, + 0x8AF583U, 0xF06E7CU, 0xBB5FADU, 0xA28416U, 0xE99653U, 0xF06D88U, 0x9FEC35U, 0xC4F7E6U, 0x4C059AU, 0x1F1C19U, + 0x56EFC4U, 0x4D743FU, 0x24612AU, 0x3F9BD1U, 0x748814U, 0x2C13AFU, 0x27F276U, 0x5EE861U, 0x553B88U, 0x0E0A5FU, + 0xC791E6U, 0xD8E2B0U, 0x907A69U, 0xABE9C6U, 0xE09217U, 0xB10168U, 0xBA48F9U, 0xE3FA26U, 0x8861CFU, 0x9230D8U, + 0xDB8B21U, 0xC099B2U, 0x09644FU, 0x52F704U, 0x79AC90U, 0x201F6BU, 0x2E17BEU, 0x77C495U, 0x3CFF48U, 0x172E9BU, + 0x4E9426U, 0x0D8775U, 0x145E98U, 0x5E6D03U, 0xC5F6D6U, 0xAC242DU, 0xF70D3CU, 0xFEDED2U, 0xA5C543U, 0xAE74BCU, + 0xD62EE5U, 0x9D9D72U, 0x80029BU, 0xCB534CU, 0x90E175U, 0x19BAAAU, 0x6A3B6BU, 0x6280D4U, 0x39D385U, 0x724B7AU, + 0x6B78E2U, 0x00A321U, 0x19101CU, 0x5248CFU, 0x0ADB30U, 0x01F0A9U, 0x5A21CEU, 0xB73A17U, 0xACC880U, 0xE55179U, + 0xFE42A6U, 0xB4B987U, 0xC5AF58U, 0xCE1688U, 0x97C533U, 0x9CCE76U, 0xC73F8DU, 0x8E2510U, 0xB4B6C3U, 0x7D4FFEU, + 0x665C3DU, 0x2DC7C0U, 0x70B55BU, 0x5B2C2EU, 0x025FF5U, 0x49D470U, 0x53448AU, 0x1A3FD7U, 0x09AC64U, 0x60BDBDU, + 0x3B467AU, 0xB0D043U, 0xE98B9CU, 0xE33A2DU, 0x9A21E2U, 0xD1C3B3U, 0xCA5A0CU, 0x8709DDU, 0xDCB222U, 0xF5A3AAU, + 0xBF79DDU, 0xA44A04U, 0xEDD193U, 0x3E006AU, 0x373B21U, 0x4CF994U, 0x47C04FU, 0x1F53DAU, 0x5488A1U, 0x4DB86CU, + 0x2623DFU, 0x7D7402U, 0x70CF50U, 0x2B9EFDU, 0x232426U, 0xF8A7D3U, 0x91FEC8U, 0x8A4D39U, 0xC117F6U, 0xD0866FU, + 0x9B3D18U, 0xE36EC1U, 0xE8F576U, 0xB3C5BFU, 0xBA1629U, 0xE1BD50U, 0xA8EC8FU, 0x17763EU, 0x5D45F1U, 0x049CA0U, + 0x0F8F1FU, 0x5630C6U, 0x7DE225U, 0x26FB38U, 0x6F08CBU, 0x7D0316U, 0x34B28DU, 0x2F68E9U, 0xC47B72U, 0x9DC287U, + 0x96915CU, 0xCF0B41U, 0x85F8A2U, 0xBAE17FU, 0xF372CCU, 0xE81991U, 0xA1894AU, 0xFAF2EBU, 0xF16134U, 0x89F845U, + 0x0A8ADBU, 0x53153AU, 0x1806E5U, 0x03FF7CU, 0x6A7C0BU, 0x312692U, 0x399775U, 0x628CACU, 0x6D7FB3U, 0x34EE42U, + 0x5FF49DU, 0x56073CU, 0x8D1C67U, 0x87CDBBU, 0xDEE708U, 0xB574D5U, 0xA4ADB6U, 0xEF9E2BU, 0xF605D0U, 0xBD7545U, + 0xE6EE0EU, 0xCE39FBU, 0x950260U, 0xD8929DU, 0x43D9CEU, 0x086A47U, 0x31B3B1U, 0x7AA068U, 0x221ADFU, 0x294B86U, + 0x72F049U, 0x73E3F8U, 0x083927U, 0x418856U, 0x5AC3C9U, 0x105020U, 0xC969B7U, 0xE2BBEEU, 0xBF2019U, 0xB41181U, + 0xEFCA6AU, 0xA6FD3FU, 0xBC27A4U, 0xD53651U, 0xCE9D9AU, 0x854EA7U, 0xDC5E74U, 0xDFE5A9U, 0x26B61AU, 0x6C0D57U, + 0x77DCECU, 0x3EC639U, 0x2575C3U, 0x682CD6U, 0x13AF1DU, 0x1855ECU, 0x404473U, 0x4BDF8AU, 0x12ACDDU, 0xF93754U, + 0xE207A3U, 0xABD87AU, 0xF04B45U, 0xF03284U, 0xABB05BU, 0x80ABEBU, 0xD95AB4U, 0x92C10DU, 0x8FD2CEU, 0xC42833U, + 0xEC3920U, 0x37C2FDU, 0x7C5106U, 0x654883U, 0x2EAAF8U, 0x37B12DU, 0x5C20B6U, 0x065B42U, 0x07C909U, 0x5C12B4U, + 0x152367U, 0x2EB4FAU, 0x65CF19U, 0xFC5F40U, 0xB294FFU, 0xEBA72EU, 0xE03ED1U, 0x9B6CD0U, 0x92D70FU, 0xC944F6U, + 0x801D60U, 0x9AAE19U, 0xF1F4DEU, 0xA85547U, 0xAB4EB8U, 0x729DE9U, 0x792456U, 0x223697U, 0x4BED0CU, 0x55DE71U, + 0x1C03A2U, 0x07910FU, 0x4CAADCU, 0x356BA0U, 0x3E5033U, 0x67C3EEU, 0x2D9B05U, 0xB62810U, 0xFFF3EBU, 0xC4E03EU, + 0x8558A5U, 0xDE0B48U, 0xD5905BU, 0x8D71A2U, 0xA26A75U, 0xFBD8ECU, 0xB08982U, 0xAB1253U, 0xE2A1ECU, 0x79FB3FU, + 0x116E52U, 0x4A15C9U, 0x43861CU, 0x188FE7U, 0x537DF2U, 0x62E619U, 0x29D7C0U, 0x310C57U, 0x7A1F2EU, 0x25E5B8U, + 0xAC7451U, 0xC76F86U, 0xDE9C9FU, 0x959460U, 0xCF27B1U, 0xC6FC1EU, 0xBDEDCFU, 0xF416B0U, 0xEF0429U, 0xA49FEEU, + 0xBDEA17U, 0xFF7104U, 0x06A3F8U, 0x0D8A63U, 0x5219A6U, 0x5B62DDU, 0x00F348U, 0x6969B3U, 0x731A6EU, 0x38816DU, + 0x61D090U, 0x6A6343U, 0x33F9FEU, 0x18B8A5U, 0xC30340U, 0x8B10DAU, 0x98E80BU, 0xD1FB74U, 0xEA20F5U, 0xA5930AU, + 0xFC8E93U, 0xF75CC4U, 0xAF673DU, 0xA4E6BAU, 0xDF3D43U, 0x960F9CU, 0x0DD68DU, 0x44E572U, 0x1F7EB2U, 0x35AD09U, + 0x6C9554U, 0x6746A7U, 0x365D3AU, 0x7DFCF9U, 0x64A6C4U, 0x0B351FU, 0x118CEAU, 0x58DF61U, 0x836434U, 0x8A36CFU, + 0xF1AB5BU, 0xBA18A0U, 0xA343EDU, 0xE8C27EU, 0xF0F887U, 0xBB2B50U, 0xC03A69U, 0xC9C1A6U, 0x9A5317U, 0x9368C8U, + 0x5CB919U, 0x26A226U, 0x2F01EFU, 0x74D919U, 0x3DCA80U, 0x2631D7U, 0x6D223EU, 0x54BAA1U, 0x1E4950U, 0x47520BU, + 0x4CA79EU, 0x97BC75U, 0xBE3EA8U, 0xED479BU, 0xA4D446U, 0xBA4FF5U, 0xF13C39U, 0xE8A46AU, 0x83D7D7U, 0xDA4C0CU, + 0xD1DDF9U, 0x8AA7F2U, 0xC22427U, 0x793DDCU, 0x30CE45U, 0x2B5522U, 0x6007FBU, 0x39BE6CU, 0x32AD95U, 0x42560BU, + 0x4D426AU, 0x16D1B5U, 0x5F3A04U, 0x442BDBU, 0x2DF082U, 0xF6C225U, 0xFE59FCU, 0xA5880FU, 0xAEB312U, 0xF761C9U, + 0x9C582CU, 0x85CBB7U, 0xCE00C3U, 0xD43118U, 0x9DAB9DU, 0xEAF866U, 0xE3437BU, 0x381288U, 0x738955U, 0x6A3BF6U, + 0x2066ABU, 0x19D570U, 0x52DEC1U, 0x090E1EU, 0x00B5FFU, 0x5BE6E1U, 0x727D38U, 0x284CCFU, 0x639656U, 0xFA8531U, + 0xBD3CA8U, 0xD4EF77U, 0xCFC586U, 0x841489U, 0x9C0F78U, 0xD7BCA7U, 0x8E671EU, 0xA5774DU, 0xFE8481U, 0xF79F32U, + 0xAC0AEFU, 0x65F09CU, 0x5FF301U, 0x144ACAU, 0x0D193FU, 0x468224U, 0x13F0D1U, 0x18694AU, 0x63FA87U, 0x2B81F4U, + 0x30106DU, 0x790A9BU, 0xE2E952U, 0x8970CDU, 0xD003BCU, 0xDB9963U, 0x838AD2U, 0x88731DU, 0xD1E064U, 0xBAFFF3U, + 0xA10F2AU, 0xEC049DU, 0xBFD7D4U, 0xB7EE2BU, 0x4C7CBBU, 0x478760U, 0x1E9415U, 0x554D9EU, 0x4C7E6BU, 0x07E4B0U, + 0x3D35ADU, 0x741E4EU, 0x2F8D93U, 0x26FC20U, 0x7D667DU, 0x16B586U, 0x8B8E02U, 0xC91FD9U, 0xD0456CU, 0x9BF237U, + 0xC0EBCEU, 0xE92849U, 0xB29390U, 0xBBC3E7U, 0xE1787EU, 0xAA6B81U, 0x93B040U, 0xD8005FU, 0x411BAEU, 0x0AC870U, + 0x51F1D1U, 0x5D328EU, 0x362837U, 0x6799E0U, 0x6C4239U, 0x37711AU, 0x3EABC7U, 0x45BA3CU, 0x0D01A9U, 0x16D6F2U, + 0xDDCF17U, 0xC46D8CU, 0x8F3670U, 0xF6A723U, 0xFD5CBCU, 0xA74F5DU, 0xEAF582U, 0xF1A43BU, 0x903768U, 0x8B0CC5U, + 0xC0DC16U, 0x9957CBU, 0x1324F0U, 0x4ABD25U, 0x61AECEU, 0x38545AU, 0x73C701U, 0x68FEF4U, 0x212D6FU, 0x5B3382U, + 0x52C2D1U, 0x09494CU, 0x065ABFU, 0xDFA126U, 0x9CB149U, 0xA56A98U, 0xEE5927U, 0xF4C0F6U, 0xBD33B8U, 0xE62901U, + 0xCFB8D6U, 0x94D32FU, 0x9F40B8U, 0xC69AF1U, 0x8CAB0EU, 0x15309FU, 0x7E6360U, 0x21DA31U, 0x2848BAU, 0x733747U, + 0x72A6D4U, 0x08EDA8U, 0x435F7BU, 0x5A4CD6U, 0x119505U, 0x082658U, 0x433DE3U, 0xB8ED26U, 0xB0D6DDU, 0xEB05C8U, + 0xA2BC13U, 0xA9BEEAU, 0xD6656DU, 0xDF5614U, 0x848F82U, 0xC41C5BU, 0xDF26A4U, 0x94F7A5U, 0xADCC5AU, 0x665B8BU, + 0x3F1234U, 0x34A0EDU, 0x6E7BAAU, 0x076813U, 0x1CD1C4U, 0x55833DU, 0x4E1836U, 0x03A9E2U, 0x58F219U, 0x72418CU, + 0x2B09F7U, 0xA89A72U, 0xF1A1A9U, 0xBA7254U, 0x81EA47U, 0xC899BAU, 0xD20279U, 0x9B13C4U, 0xC0E09FU, 0xCB7E4BU, + 0xB25FF0U, 0xF98431U, 0xE4974EU, 0x2E6CD7U, 0x35FC00U, 0x5CE7A9U, 0x07147EU, 0x060D07U, 0x5D9F98U, 0x56E449U, + 0x0E65A6U, 0x659EB7U, 0x7C8D49U, 0x371790U, 0x6C6623U, 0xE5FD6EU, 0x9E6EBDU, 0x921600U, 0xC985D3U, 0x82DAEEU, + 0x9B7B25U, 0xD0E0F0U, 0xE1924BU, 0xAA091EU, 0xF158F5U, 0xF9E369U, 0x22F1BAU, 0x4B28C7U, 0x509B54U, 0x1B80BDU, + 0x024162U, 0x497B53U, 0x01A88CU, 0x3E1B5DU, 0x7502F2U, 0x6CD12BU, 0x27EB1CU, 0x7E7AC5U, 0xDDA113U, 0x8596BAU, + 0xCE5EEDU, 0xD54D14U, 0x9CF68BU, 0x87A54AU, 0xEE1C31U, 0xB58EA4U, 0xBFD55FU, 0xE66482U, 0xE93FA1U, 0x90AD7CU, + 0x5B04EFU, 0x405713U, 0x09CC48U, 0x13BFEDU, 0x522736U, 0x2914E3U, 0x22CFD8U, 0x7B5E05U, 0x3061E6U, 0x29B37FU, + 0x43BAA8U, 0x5849D1U, 0x91D25EU, 0xCEE0AFU, 0xC73971U, 0x9C2A40U, 0xB7919FU, 0xEF401EU, 0xA452E1U, 0xB5B9B8U, + 0xFEA80FU, 0x8533D6U, 0x8C4115U, 0xD7DA28U, 0x5F6BF3U, 0x043006U, 0x4FA39DU, 0x76DBD9U, 0x394C22U, 0x20C7BFU, + 0x6BB64CU, 0x312C41U, 0x187FB2U, 0x43C46FU, 0x0A55F4U, 0x192E81U, 0xD2BC4AU, 0xCBA5FBU, 0xA15624U, 0xF85DFDU, + 0xF38ECBU, 0xBA3602U, 0xA125F5U, 0xCEFE6CU, 0x97CF3BU, 0x9D55C2U, 0xC4A64DU, 0x4FBFBCU, 0x1468A3U, 0x7D4352U, + 0x6ED19DU, 0x270804U, 0x7D3B76U, 0x76A0ABU, 0x0FF018U, 0x0443D5U, 0x5D188EU, 0x16A93BU, 0x0932E0U, 0xC07015U, + 0xFACB1EU, 0xB39AC3U, 0xE80170U, 0xE3B3ADU, 0xBAEA5EU, 0xD17956U, 0xC042A9U, 0x8A9378U, 0x912DE7U, 0xD86E86U, + 0x83F559U, 0x2AC4E8U, 0x711F37U, 0x7A0D6EU, 0x26B4C9U, 0x6D6710U, 0x547CE7U, 0x1F8CFEU, 0x449720U, 0x4D3483U, + 0x16EF5AU, 0x1EFE2DU, 0x6D44B4U, 0xA6174BU, 0xBF8E8AU, 0xF4FD95U, 0xED6764U, 0x86D6BBU, 0xDC8912U, 0xD10A45U, + 0x8A799CU, 0x83E12AU, 0xF872F3U, 0xB10954U, 0xAA980DU, 0x6083D6U, 0x397163U, 0x3AE8B8U, 0x439BDDU, 0x481046U, + 0x1302BBU, 0x5AFB68U, 0x50E875U, 0x297396U, 0x26824AU, 0x7D98F1U, 0x344BA4U, 0xAF726FU, 0xE6F5DAU, 0x9C0F01U, + 0x971C38U, 0xCE85EFU, 0xC5F626U, 0x946D91U, 0xFFBDC8U, 0xE48637U, 0xAC15A6U, 0xB74C48U, 0x7EEE99U, 0x21B586U, + 0x0A0677U, 0x539FA8U, 0x18CC01U, 0x007652U, 0x4B67CFU, 0x70B43CU, 0x390FF1U, 0x625ECAU, 0x6BD01FU, 0x38E3C4U, + 0xB23870U, 0xCB893BU, 0x8093C6U, 0x994055U, 0xD679A8U, 0x8DAAFBU, 0xA4B176U, 0xFE018DU, 0xF7CA5CU, 0xACD963U, + 0xE762B2U, 0xFE323DU, 0x1589C4U, 0x0C5A92U, 0x4F432BU, 0x17F0ECU, 0x1CAA35U, 0x673B82U, 0x6E54DBU, 0x31C724U, + 0x785CA5U, 0x632C5AU, 0x29B70BU, 0x508490U, 0xDB5D6DU, 0x82CFEEU, 0x89B492U, 0xD22541U, 0xBB2EDCU, 0xA1DD27U, + 0xE04F62U, 0xFB56D9U, 0xB0A50CU, 0xF9BED7U, 0xC24EFAU, 0x8F5529U, 0x55C6D0U, 0x5E3B47U, 0x07383FU, 0x2CA2F0U, + 0x75D161U, 0x3E489EU, 0x25BB0FU, 0x6DA170U, 0x7630B1U, 0x174B2EU, 0x4CD8D7U, 0x470180U, 0x9E2339U, 0xD5B8FEU, + 0xE9EB27U, 0xA2521DU, 0xB941C8U, 0xF0BB23U, 0xAB2AB6U, 0xA271CDU, 0xD9C250U, 0xD3DC83U, 0x8A1D6EU, 0x41A67DU, + 0x58B580U, 0x3B6C5BU, 0x205ECEU, 0x6985A5U, 0x333471U, 0x3E27CAU, 0x65FD13U, 0x0CCE44U, 0x1747EDU, 0x5C143AU, + 0x45AF83U, 0x8F7F54U, 0xF6643DU, 0xFDD7A2U, 0xA68E73U, 0xAF3D8CU, 0xF4E79DU, 0xB5E073U, 0x8F59AAU, 0xC40A3DU, + 0x999044U, 0x922197U, 0xCB7A3AU, 0x60E9E1U, 0x3B90B4U, 0x73020FU, 0x6839DAU, 0x21FA71U, 0x3A632CU, 0x5151DFU, + 0x088A43U, 0x039B80U, 0x4260FDU, 0x18F36EU, 0x33EB97U, 0xEE1848U, 0xE503C9U, 0xBCA4B6U, 0xF7FC67U, 0xEC6FD8U, + 0x849C01U, 0x9F8506U, 0xD616FFU, 0x8D6C29U, 0x86FD90U, 0xFF26CFU, 0xF4150EU, 0x2C9EB1U, 0x6FEE60U, 0x74751BU, + 0x39E696U, 0x429F65U, 0x4B0DB8U, 0x1056ABU, 0x1AE756U, 0x43FC9DU, 0x282F29U, 0x318172U, 0x7A90E7U, 0xE36B1CU, + 0xA878D9U, 0xF2A0E2U, 0xDB133FU, 0x8008ECU, 0xC1D955U, 0xDAE292U, 0x9570EBU, 0xAC9B74U, 0xE68A85U, 0xBF514BU, + 0x34635AU, 0x6FFAA5U, 0x66A93CU, 0x1D12CBU, 0x54C382U, 0x4ED915U, 0x056AECU, 0x5C2D37U, 0x779402U, 0x2607C9U, + 0x2D5D1CU, 0x72ECA6U, 0xBAB7FBU, 0xA12408U, 0xC89C85U, 0xD3CF76U, 0x98542BU, 0xC177B8U, 0xCAAE45U, 0xB29CCEU, + 0xB9473BU, 0xE2D660U, 0xABEDF1U, 0xA03F1EU, 0x7926C4U, 0x1A95F1U, 0x044E2AU, 0x4D49FFU, 0x56B154U, 0x1FA209U, + 0x6419FAU, 0x6F4867U, 0x36D394U, 0x3C2199U, 0x653842U, 0x2EABB7U, 0x95C02CU, 0xDC525CU, 0x87CB93U, 0x8EB80AU, + 0xD423FDU, 0xF152A4U, 0xAAC003U, 0xE15BDAU, 0xF82A0DU, 0xB3B134U, 0xAAB3EBU, 0xC14C0AU, 0x1B5D95U, 0x128664U, + 0x49357AU, 0x002DA3U, 0x3BDE40U, 0x70C5DDU, 0x6954AEU, 0x23AE73U, 0x76ADE8U, 0x7D760DU, 0x064756U, 0x0FDCE3U, + 0xD40E38U, 0x9D37F5U, 0x87E4C6U, 0xECDF1AU, 0xB54EA9U, 0xBE1470U, 0xE7B71FU, 0xEC288EU, 0xB77951U, 0xDFC3A0U, + 0xC490BFU, 0x89095EU, 0x1ABA81U, 0x51E118U, 0x2853EFU, 0x234AB6U, 0x7B8910U, 0x703AC9U, 0x2B6216U, 0x62F127U, + 0x59CAECU, 0x101B59U, 0x4B2082U, 0xC1F2FFU, 0x88696CU, 0xB358A1U, 0xFA9752U, 0xAD844FU, 0xA63CB4U, 0xFFEF60U, + 0xF5F4EBU, 0x8C059EU, 0xC71F45U, 0xDCACF0U, 0x95772BU, 0x4E6622U, 0x67CDD5U, 0x3D9F0CU, 0x3406BBU, 0x6F75F2U, + 0x24EE0DU, 0x3D7E9CU, 0x520542U, 0x4396B3U, 0x09ADBCU, 0x527C45U, 0x5BF292U, 0xA0810BU, 0xE91878U, 0xF20BB5U, + 0xB9F10EU, 0xA1E0DBU, 0xEA33C0U, 0x938835U, 0x989BFEU, 0xC36342U, 0xCA6011U, 0x95FBECU, 0xFD0A6FU, 0x6E11B2U, + 0x25C3C1U, 0x3CFA5CU, 0x7769A7U, 0x0EB266U, 0x058079U, 0x5E1988U, 0x167E17U, 0x0DE5EFU, 0x44B428U, 0x7F0E31U, + 0x349DC6U, 0xEDC41FU, 0xE277A0U, 0xBA6DE1U, 0x99BE1EU, 0xC2178FU, 0x8B4450U, 0x90FF39U, 0xD9EFAAU, 0x823457U, + 0xA88785U, 0xF1DE98U, 0xFA4D73U, 0x3377E6U, 0x68A41DU, 0x43AD48U, 0x1A1AD3U, 0x14C836U, 0x4DF1EDU, 0x0622D0U, + 0x173903U, 0x7C88FEU, 0x27527DU, 0x2E41A5U, 0xF4FADAU, 0xFDBB4BU, 0x8601A4U, 0xCDD235U, 0xD4CB6AU, 0x9F7893U, + 0x862304U, 0xCCB3EDU, 0xB388BAU, 0xBA5B23U, 0xE1C0DCU, 0xE8A00DU, 0x3B3F27U, 0x500CF2U, 0x48D509U, 0x034694U, + 0x5A3CC7U, 0x51AD6AU, 0x0AB6B9U, 0x234544U, 0x785E57U, 0x30DE9AU, 0x2B2561U, 0x6036F4U, 0xDDCF8FU, 0x96DD5BU, + 0xCF46D0U, 0xCCB729U, 0x96A4FEU, 0xDF3FC7U, 0xE44D10U, 0xADC4F9U, 0xB61366U, 0xFD2837U, 0xA4B888U, 0x8EC359U, + 0x5750B6U, 0x5C49AFU, 0x07BA79U, 0x4A2080U, 0x517307U, 0x38DA7EU, 0x62C9ADU, 0x611230U, 0x38A2CBU, 0x33F98EU, + 0x4A4A35U, 0x0153E0U, 0x98815BU, 0xD23A06U, 0xD929C5U, 0x80E079U, 0xEBD7AAU, 0xF20D57U, 0xBD1C4CU, 0xE6A78DU, + 0xEF7472U, 0x954CE3U, 0x9CDF9CU, 0xCF8455U, 0x0437C2U, 0x1DFE3BU, 0x56EC6CU, 0x6F57D5U, 0x25061BU, 0x7E95AAU, + 0x772FF5U, 0x2C7C24U, 0x05C59BU, 0x5A965AU, 0x111D21U, 0x892DBCU, 0xC2F26FU, 0x9B6192U, 0xB81891U, 0xE38B6EU, + 0xEA91B6U, 0xB16221U, 0xF9FB48U, 0xC2C8DFU, 0x890226U, 0x9013F9U, 0xDBE848U, 0x02FB07U, 0x0D62D6U, 0x77906DU, + 0x3E8BB0U, 0x2538C3U, 0x6C614EU, 0x77F39CU, 0x141861U, 0x4D0D7AU, 0x47968FU, 0x1EE544U, 0x157DD1U, 0xCEEEAAU, + 0xA7953FU, 0xBC06D4U, 0xF57E09U, 0xABED3AU, 0xA2EEE3U, 0xD91734U, 0xD2849CU, 0x8BDEC3U, 0xC06F32U, 0xD174ADU, + 0x9BA77CU, 0x201C93U, 0x690C8AU, 0x22F77DU, 0x3BF4E4U, 0x702933U, 0x4B9B5AU, 0x0380C1U, 0x585134U, 0x556AEEU, + 0x0EF9CBU, 0x45A310U, 0x7C12CDU, 0xB7C97EU, 0xAFEA23U, 0xEC72C0U, 0xB7215DU, 0x9E9A8EU, 0xC50BF3U, 0xCC5068U, + 0x97E28DU, 0xDDB916U, 0xC42846U, 0xAF93B9U, 0xF2D020U, 0x796CC7U, 0x223F9EU, 0x2BA429U, 0x5095F0U, 0x18473FU, + 0x03DC8EU, 0x40EFD1U, 0x593620U, 0x1225BFU, 0x6BCF76U, 0x605E40U, 0xBA6599U, 0xF3B66AU, 0xE8AEF7U, 0x851DBCU, + 0x9EC649U, 0xD5D5D2U, 0x8C2C27U, 0x863E7CU, 0xDFB5D9U, 0xF4C002U, 0xA55BDFU, 0xEEE9ECU, 0x75B020U, 0x3C23D3U, + 0x06584AU, 0x4FCB15U, 0x1453A4U, 0x1F306BU, 0x42AB9AU, 0x09FA05U, 0x30415CU, 0x7A53ABU, 0x61AA22U, 0x2839D5U, + 0xF3228CU, 0xDAD032U, 0x89C9E3U, 0x820A2CU, 0xCAB91DU, 0x91A4C6U, 0x985673U, 0xE34DB8U, 0xA8DCE5U, 0xB52756U, + 0xFE358BU, 0xE6EE78U, 0x0DDF75U, 0x5654AFU, 0x5F075AU, 0x04BFC1U, 0x0D2CB4U, 0x56577FU, 0x34C6C2U, 0x2D9D11U, + 0x662F48U, 0x3FB4FFU, 0x34E536U, 0x4F4E89U, 0xC61C58U, 0x988107U, 0xD132A7U, 0xCA6978U, 0x81D881U, 0xB8C296U, + 0xF3114FU, 0xAA2AA8U, 0xA0FB31U, 0xF37142U, 0xDA429FU, 0x819B24U, 0x4888E1U, 0x5333FAU, 0x1AE30FU, 0x40D0D5U, + 0x6F0B68U, 0x36182BU, 0x3DA0F6U, 0x646345U, 0x2F7898U, 0x14CDF3U, 0x5C9666U, 0xC704BDU, 0x8E7F4CU, 0xDDEED3U, + 0xD655BAU, 0xAF062DU, 0xE49EF5U, 0xFDFD02U, 0xB7661BU, 0xA8F7F4U, 0xC18D25U, 0x9A1E9AU, 0x9305CBU, 0x48F414U, + 0x43EFB5U, 0x1B1D6AU, 0x708413U, 0x698780U, 0x2A7C4DU, 0x6168BFU, 0x78F3A2U, 0x130059U, 0x0B1BCCU, 0x40CA07U, + 0x1FF072U, 0x9663E9U, 0xCD9A14U, 0xE499C7U, 0xBF0AEAU, 0xF57239U, 0xECE1E4U, 0xA7BA5FU, 0xDE098FU, 0xD591E0U, + 0x86E271U, 0x8F79AEU, 0xD52817U, 0x1C8350U, 0x2711A9U, 0x684C3EU, 0x71FFE7U, 0x3AE490U, 0x633619U, 0x498FE6U, + 0x10DC37U, 0x1B670DU, 0x4066D8U, 0x09BC13U, 0x328FAEU, 0xFB16FDU, 0xA9C500U, 0xA2FF93U, 0xFB2C5EU, 0xF03565U, + 0x8D86B0U, 0xC65D4BU, 0xDD7DCEU, 0x95E615U, 0x8EB169U, 0xE708FAU, 0xBCDB03U, 0x37C1C4U, 0x6E72FDU, 0x25232AU, + 0x3DB8F3U, 0x5ECA4CU, 0x45430DU, 0x0CF0B2U, 0x57AB61U, 0x5E3ABCU, 0x210087U, 0x2BD343U, 0xF248B8U, 0xB9392DU, + 0xA0A376U, 0xEBB09FU, 0x905908U, 0x99CAF1U, 0xD3F5A6U, 0xCA251FU, 0x813ED0U, 0xF2CD01U, 0xFBD63EU, 0xA046EEU, + 0x29BD51U, 0x76AE98U, 0x3C274FU, 0x055476U, 0x4ECEA5U, 0x573F58U, 0x1C24DBU, 0x47B786U, 0x6ECC7DU, 0x345CE8U, + 0x7D0703U, 0x66B456U, 0xAF3DECU, 0xBC6F31U, 0xD7D0A2U, 0x8EC1CFU, 0x80321CU, 0xD9A9A1U, 0xD2FB7AU, 0xA9422BU, + 0xE05184U, 0xFB8A55U, 0xB22AAAU, 0xE831B3U, 0x63E264U, 0x1ADB8CU, 0x11081BU, 0x4832E2U, 0x0BA1BDU, 0x10781CU, + 0x784BC3U, 0x679052U, 0x2E902DU, 0x752BFCU, 0x7EFC57U, 0x27C58AU, 0xCC57D9U, 0xD40C64U, 0x9FBFB6U, 0x84665BU, + 0xCD7540U, 0xB6CF95U, 0xBF8E6EU, 0xE415FBU, 0xE62690U, 0xBFFE0DU, 0xF04DFEU, 0xC91623U, 0x028520U, 0x19BCD9U, + 0x506E06U, 0x0AEDB6U, 0x23D4E9U, 0x780728U, 0x331997U, 0x3AE84EU, 0x6173B9U, 0x6840A0U, 0x129B67U, 0x598B9EU, + 0xC87009U, 0x877370U, 0x9EEAEBU, 0xF5190EU, 0xAC03D4U, 0xA690C1U, 0xFDE93AU, 0xB47AF7U, 0xAF8044U, 0xC69119U, + 0xDD0ACAU, 0x166977U, 0x4EF0BCU, 0x45E2C9U, 0x3C1D52U, 0x3F8E87U, 0x64D73CU, 0x296574U, 0x327E83U, 0x7A8F1AU, + 0x0114EDU, 0x0A1734U, 0x53EF3BU, 0xD8FCCAU, 0x812715U, 0xEA94A4U, 0xF185EBU, 0xB95F3AU, 0xA26C85U, 0xEBB55CU, + 0xB0862AU, 0x930CA3U, 0xCEDD70U, 0x85E6CDU, 0x9D7196U, 0x562A63U, 0x6D9AE8U, 0x24411DU, 0x7F5246U, 0x76EBDBU, + 0x2DB928U, 0x2712E5U, 0x5E83D7U, 0x15D80AU, 0x0C6BD1U, 0x473170U, 0x54A02FU, 0xB99B9EU, 0xE34841U, 0xEAD090U, + 0xB1E33FU, 0xFA2866U, 0xE31991U, 0x88C208U, 0x8154FFU, 0xDB6FB7U, 0x92BE28U, 0x89A5D9U, 0xE25606U, 0x7BCE37U, + 0x30FDFCU, 0x693E21U, 0x6F2792U, 0x3495CFU, 0x5DCE6CU, 0x465DB1U, 0x0FA46AU, 0x14B75FU, 0x5F2D85U, 0x275C60U, + 0x2CC7FBU, 0xF56486U, 0xFE3C55U, 0xA5ABC8U, 0xECD02BU, 0xD743F2U, 0x9FDAC5U, 0xC0A81CU, 0xC33383U, 0x9A2262U, + 0xB1D93DU, 0xE8DA8DU, 0x232252U, 0x39B19BU, 0x70AAACU, 0x6B5975U, 0x024182U, 0x59921BU, 0x522974U, 0x0B38A5U, + 0x01F33EU, 0x78C1CBU, 0x3758D0U, 0x242F3DU, 0xEDB4EFU, 0xB66672U, 0xBF5701U, 0xC5CCDCU, 0xCE9F77U, 0x9726A2U, + 0xDCA4F9U, 0xC5FF4CU, 0xAE4E87U, 0xB51576U, 0xFDA7E9U, 0xA63C90U, 0x2F6D47U, 0x74D6CFU, 0x1BC538U, 0x0A1D21U, + 0x413EDEU, 0x58E50FU, 0x127480U, 0x6B4BF1U, 0x60992EU, 0x2BA297U, 0x327340U, 0x79E809U, 0xA0DABAU, 0x8A0367U, + 0xD1009DU, 0x98BB98U, 0x836A63U, 0xCE70F6U, 0xF5832DU, 0xB69850U, 0xEE29D3U, 0xE5732EU, 0xBCE0FDU, 0xB75962U, + 0x4C1A13U, 0x0589DCU, 0x1EF165U, 0x5666B7U, 0x4DFDEAU, 0x268E59U, 0x7F1794U, 0x74256FU, 0x29FE7AU, 0x626F81U, + 0x700404U, 0x1996DFU, 0x828FA2U, 0xCB7C31U, 0x9067CCU, 0x9B940EU, 0xE20C17U, 0xE81FE8U, 0xB1E439U, 0xFAF586U, + 0xE17FC7U, 0xA88C18U, 0xD397A1U, 0x5E4276U, 0x04794FU, 0x0FEB88U, 0x5E9271U, 0x3501E6U, 0x2C9A3EU, 0x67EA51U, + 0x7C61C0U, 0x34323BU, 0x6F89EEU, 0x4618F5U, 0x1D4218U, 0xD4F1CBU, 0xCFE876U, 0x841B25U, 0xB888F8U, 0xF3D053U, + 0xAA7386U, 0xA168BCU, 0xF2BB69U, 0xFB8792U, 0x80541FU, 0xC8CF4CU, 0xC3FEB5U, 0x182522U, 0x1117CBU, 0x6A9E9CU, + 0x234D05U, 0x3876FAU, 0x72A42BU, 0x2FBD84U, 0x240ED4U, 0x5DD54BU, 0x56C4B2U, 0x057E65U, 0x4C2D4CU, 0xD7849BU, + 0xBFD762U, 0xA44DF9U, 0xEFFEACU, 0xB6A347U, 0xBD30D2U, 0xC40B29U, 0x8FDB74U, 0x9540E6U, 0xDC330BU, 0xC3BAD8U, + 0x8A89E5U, 0x71533EU, 0x7AC0BBU, 0x2BB140U, 0x212A11U, 0x7838AEU, 0x13C17FU, 0x08D290U, 0x414989U, 0x1AA85EU, + 0x13B2A6U, 0x494131U, 0x625AD8U, 0xBBCF87U, 0xF43516U, 0xED26E9U, 0xA6BF78U, 0x9FCC17U, 0xDD57CEU, 0x86B75DU, + 0x8FACA0U, 0xD43FE3U, 0x9D445EU, 0xA6D584U, 0x6DCF71U, 0x753C6AU, 0x3EA5AFU, 0x67F654U, 0x4C4CC9U, 0x134DBAU, + 0x1AB667U, 0x4125E4U, 0x097E19U, 0x12CA0AU, 0x71D1F3U, 0x78022CU, 0xA33BACU, 0xEAA953U, 0xF17A02U, 0x9B53BDU, + 0xC28074U, 0xC9BB83U, 0x90299AU, 0x9BF04DU, 0xC4C3B4U, 0xAD583BU, 0xB7084AU, 0xFEB3D1U, 0x656004U, 0x2E69FEU, + 0x5FDAF3U, 0x548000U, 0x0D37DDU, 0x472E4EU, 0x5CFD33U, 0x1546F8U, 0x2E164DU, 0x678D96U, 0x3CBEE3U, 0x337768U, + 0xEBE5BDU, 0xC09E47U, 0x990D5EU, 0xD234A9U, 0xC9E720U, 0x887DF7U, 0xD34C0EU, 0xFB9711U, 0xA084E0U, 0xA96C2FU, + 0xF27FBEU, 0xB9E4C1U, 0x001318U, 0x4B02AFU, 0x56B867U, 0x1CEB30U, 0x477289U, 0x4E8152U, 0x358AF7U, 0x3C1AACU, + 0x676159U, 0x24F2C2U, 0x3C6917U, 0x57197CU, 0x8E82E1U, 0x85F112U, 0xDE68CFU, 0xD77BDDU, 0x8C9130U, 0xE400EBU, + 0xFB5B5EU, 0xB0E885U, 0xA9F6D4U, 0xE2277BU, 0x9B9CA2U, 0x108F15U, 0x5A764CU, 0x0B64ABU, 0x00AF32U, 0x599CEDU, + 0x72059DU, 0x29D702U, 0x60ECE3U, 0x7A7D3CU, 0x330625U, 0x0C95D6U, 0x474D0BU, 0x9E7EA8U, 0x95FDF5U, 0xCCA666U, + 0x86179BU, 0xBD8D40U, 0xFCDA65U, 0xE763BFU, 0xAE304AU, 0xF58AD1U, 0xDE9B9CU, 0x86406FU, 0x8DE3F2U, 0x54B801U, + 0x1B28D8U, 0x0213D7U, 0x69C026U, 0x7259B9U, 0x3A6B48U, 0x61B017U, 0x68819FU, 0x135A68U, 0x50D9B1U, 0x49E386U, + 0x02325FU, 0x9A29B0U, 0xD19E23U, 0xAAC77EU, 0xA3558DU, 0xFCAE04U, 0xF5BFF3U, 0xAE04AAU, 0xC44635U, 0xDDDDC5U, + 0x966C4AU, 0xCF373BU, 0xC4A4E4U, 0x1FD47DU, 0x3E4F8AU, 0x64DC43U, 0x2DA574U, 0x3637ADU, 0x7D5C56U, 0x44CFC3U, + 0x0BD688U, 0x52257DU, 0x59BBE7U, 0x03AA1AU, 0x4A5119U, 0xF142C4U, 0xB89A37U, 0xB329AAU, 0xE822D1U, 0xA9D114U, + 0x93C88FU, 0xDA5A7AU, 0xC1A121U, 0x8AB090U, 0xD36B5EU, 0xDC58A7U, 0xA5C0B0U, 0x2F8369U, 0x74389EU, 0x3DAB17U, + 0x26D368U, 0x4F40F9U, 0x141F26U, 0x1DAEC7U, 0x473558U, 0x446721U, 0x1DDEF6U, 0x769D6EU, 0xEF0E8DU, 0xA434D0U, + 0xBFE56BU, 0xF35EBEU, 0x884D45U, 0x819440U, 0xDAA69BU, 0x917D26U, 0x88ECF5U, 0xC3C788U, 0xFB150BU, 0xB02ED6U, + 0x63BF24U, 0x6A6439U, 0x3153D2U, 0x188B03U, 0x43989CU, 0x0923EDU, 0x147232U, 0x5FF99BU, 0x060B4CU, 0x2D10B5U, + 0x76A1A2U, 0x7FFA7BU, 0xA568D4U, 0xECD104U, 0xD7827BU, 0x9C19EAU, 0x8D6831U, 0xC6E2DCU, 0x9F71CFU, 0x950A32U, + 0xEE9BE1U, 0xA3A16CU, 0xB8761FU, 0xF16FC2U, 0x6A9C79U, 0x010FACU, 0x491786U, 0x52F453U, 0x1BEF88U, 0x007C35U, + 0x4B8566U, 0x32978FU, 0x316C18U, 0x697DC1U, 0x62E6BEU, 0x3B142FU, 0xD40DC0U, 0xCFCE11U, 0x86F58EU, 0xDD66F6U, + 0xD53E31U, 0x8E8988U, 0xA5125FU, 0xFC6366U, 0xB7F9B9U, 0xAEAA78U, 0xE513C3U, 0xD69096U, 0x1ECB6DU, 0x4579F8U, + 0x4C6033U, 0x13B34EU, 0x5888DCU, 0x615821U, 0x2AE3F2U, 0x32F0FFU, 0x792B04U, 0x220A91U, 0x0B906AU, 0xD0432BU, + 0xD97294U, 0x82AD4DU, 0xC8BE9AU, 0xD90623U, 0xB2D564U, 0xEBEE9CU, 0xE02D03U, 0xBF35D2U, 0xB686ADU, 0xCCDD2CU, + 0x854CD3U, 0x1EF70AU, 0x55A51DU, 0x4C1CE4U, 0x074F67U, 0x7ED49AU, 0x7476C9U, 0x2F2F75U, 0x26BCBEU, 0x75876BU, + 0x1C5650U, 0x07C885U, 0x48BB7EU, 0x9022F3U, 0x9B11A0U, 0xC2CA5DU, 0xE9C8CEU, 0xA07133U, 0xFBA238U, 0xF0B9E9U, + 0xA84917U, 0x835286U, 0xDAC179U, 0x913830U, 0x822B87U, 0x4BD95EU, 0x30D289U, 0x3C43A0U, 0x67B87FU, 0x6CAA8EU, + 0x353311U, 0x7E4440U, 0x47DFABU, 0x0C8E3FU, 0x1634C4U, 0x5FA7D9U, 0x04CC0AU, 0xAD5DE7U, 0xF64774U, 0xBDB409U, + 0xAC2DD2U, 0xE67E67U, 0xFBC5ACU, 0x90D5F9U, 0xCB0E42U, 0xC23D9FU, 0x99B67DU, 0x9047E4U, 0xEA5DB3U, 0x218E0AU, + 0x38B7D5U, 0x732034U, 0x6AFA2BU, 0x21CBFAU, 0x5A1005U, 0x5B039CU, 0x01A8FBU, 0x4C7822U, 0x574395U, 0x3CD04DU, + 0xA5811AU, 0xEE3BB3U, 0xB76868U, 0xBDF19DU, 0xE64286U, 0xCF1943U, 0x949BF8U, 0xDDA225U, 0xC67156U, 0x8FCACBU, + 0xF59B08U, 0xF605F5U, 0x2B36EFU, 0x20EF1AU, 0x797CC1U, 0x324664U, 0x1985BFU, 0x419CE4U, 0x4A6F51U, 0x13748AU, + 0x58C42FU, 0x631F74U, 0x2A0CA1U, 0x71F51AU, 0xF9E7D7U, 0xA27CA5U, 0xA99F38U, 0xD886EBU, 0x973516U, 0x8E6F1DU, + 0xC5FEECU, 0xDF0133U, 0xB61282U, 0xED8ADDU, 0xE4F954U, 0xBF7AA3U, 0x74617AU, 0x6D904DU, 0x070A95U, 0x1E795AU, + 0x55E0EBU, 0x0EF334U, 0x0F0845U, 0x7098CAU, 0x798313U, 0x2360E0U, 0x687BFDU, 0x71AB0EU, 0xBA10C3U, 0x830370U, + 0xC8FA2DU, 0x93EDB7U, 0x9B3742U, 0xC00689U, 0xA99DBCU, 0xB25E67U, 0xF964BAU, 0xE0F509U, 0xA7AE44U, 0xFF1DB7U, + 0x54C42EU, 0x0DF6F1U, 0x066D90U, 0x5D3C0EU, 0x1487FFU, 0x2F8460U, 0x675E19U, 0x3CEFDEU, 0x37B447U, 0x6E27B0U, + 0x651369U, 0x9CC856U, 0xD77B97U, 0xC9604CU, 0x88B1F9U, 0x939BA2U, 0xFA4856U, 0xB1D1DDU, 0xAAE200U, 0xE33873U, + 0xB829EEU, 0xB0D20DU, 0xCBC190U, 0x407AEBU, 0x19AA3EU, 0x52A1A5U, 0x4B1240U, 0x204B1BU, 0x3ED9A2U, 0x7F2274U, + 0x2437ADU, 0x2DAC8AU, 0x76DF53U, 0x5D45ACU, 0x04F43DU, 0xCEBFE2U, 0xD72CC3U, 0x9C551CU, 0xE7C7E5U, 0xEEDC72U, + 0xB52D1BU, 0xBCB6CCU, 0xE6A454U, 0xA95FA7U, 0x904EFAU, 0xD3A551U, 0xCA3684U, 0x01265FU, 0x5ADD6AU, 0x72CEB1U, + 0x29135CU, 0x60A1CFU, 0x7BBA92U, 0x304921U, 0x2950FCU, 0x42D316U, 0x1AA903U, 0x1138F8U, 0x48E329U, 0xC7D0A6U, + 0xBC48DFU, 0xFD1B08U, 0xE6A0B1U, 0xAE3366U, 0xF55AAFU, 0xFEC898U, 0x879341U, 0x8C22FEU, 0xD5392EU, 0x9EEA61U, + 0x8456D0U, 0x6D450BU, 0x769EF6U, 0x3FADE5U, 0x606508U, 0x6BD6DBU, 0x3ACD46U, 0x101C3DU, 0x5927F8U, 0x02F543U, + 0x096C96U, 0x505FCCU, 0xBB8C71U, 0xA296B2U, 0xE8370FU, 0xF36C5CU, 0xBADF85U, 0xE1063AU, 0xC814FBU, 0x97AF04U, + 0x9CFA15U, 0xC461EAU, 0x87D23BU, 0xBE88B4U, 0x7509CCU, 0x2E721BU, 0x27E1A2U, 0x7C5965U, 0x750A7CU, 0x0F9183U, + 0x44A052U, 0x5D7BE9U, 0x1669ACU, 0x0F9277U, 0x6013CAU, 0x3B0819U, 0xB3FA65U, 0xE0E3E6U, 0xA9103BU, 0xB28BC0U, + 0xDB9ED5U, 0xC0642EU, 0x8B77EBU, 0xD3EC50U, 0xD80D89U, 0xA1179EU, 0xAAC477U, 0xF1F5A0U, 0x386E19U, 0x271D4FU, + 0x6F8596U, 0x541639U, 0x1F6DE8U, 0x4EFE97U, 0x45B706U, 0x1C05D9U, 0x779E30U, 0x6DCF27U, 0x2474DEU, 0x3F664DU, + 0xF69BB0U, 0xAD08FBU, 0x86536FU, 0xDFE094U, 0xD1E841U, 0x883B6AU, 0xC300B7U, 0xE8D164U, 0xB16BD9U, 0xF2788AU, + 0xEBA167U, 0xA192FCU, 0x3A0929U, 0x53DBD2U, 0x08F2C3U, 0x01212DU, 0x5A3ABCU, 0x518B43U, 0x29D11AU, 0x62628DU, + 0x7FFD64U, 0x34ACB3U, 0x6F1E8AU, 0xE64555U, 0x95C494U, 0x9D7F2BU, 0xC62C7AU, 0x8DB485U, 0x94871DU, 0xFF5CDEU, + 0xE6EFE3U, 0xADB730U, 0xF524CFU, 0xFE0F56U, 0xA5DE31U, 0x48C5E8U, 0x53377FU, 0x1AAE86U, 0x01BD59U, 0x4B4678U, + 0x3A50A7U, 0x31E977U, 0x683ACCU, 0x633189U, 0x38C072U, 0x71DAEFU, 0x4B493CU, 0x82B001U, 0x99A3C2U, 0xD2383FU, + 0x8F4AA4U, 0xA4D3D1U, 0xFDA00AU, 0xB62B8FU, 0xACBB75U, 0xE5C028U, 0xF6539BU, 0x9F4242U, 0xC4B985U, 0x4F2FBCU, + 0x167463U, 0x1CC5D2U, 0x65DE1DU, 0x2E3C4CU, 0x35A5F3U, 0x78F622U, 0x234DDDU, 0x0A5C55U, 0x408622U, 0x5BB5FBU, + 0x122E6CU, 0xC1FF95U, 0xC8C4DEU, 0xB3066BU, 0xB83FB0U, 0xE0AC25U, 0xAB775EU, 0xB24793U, 0xD9DC20U, 0x828BFDU, + 0x8F30AFU, 0xD46102U, 0xDCDBD9U, 0x07582CU, 0x6E0137U, 0x75B2C6U, 0x3EE809U, 0x2F7990U, 0x64C2E7U, 0x1C913EU, + 0x170A89U, 0x4C3A40U, 0x45E9D6U, 0x1E42AFU, 0x571370U, 0xE889C1U, 0xA2BA0EU, 0xFB635FU, 0xF070E0U, 0xA9CF39U, + 0x821DDAU, 0xD904C7U, 0x90F734U, 0x82FCE9U, 0xCB4D72U, 0xD09716U, 0x3B848DU, 0x623D78U, 0x696EA3U, 0x30F4BEU, + 0x7A075DU, 0x451E80U, 0x0C8D33U, 0x17E66EU, 0x5E76B5U, 0x050D14U, 0x0E9ECBU, 0x7607BAU, 0xF57524U, 0xACEAC5U, + 0xE7F91AU, 0xFC0083U, 0x9583F4U, 0xCED96DU, 0xC6688AU, 0x9D7353U, 0x92804CU, 0xCB11BDU, 0xA00B62U, 0xA9F8C3U, + 0x72E398U, 0x783244U, 0x2118F7U, 0x4A8B2AU, 0x5B5249U, 0x1061D4U, 0x09FA2FU, 0x428ABAU, 0x1911F1U, 0x31C604U, + 0x6AFD9FU, 0x276D62U, 0xBC2631U, 0xF795B8U, 0xCE4C4EU, 0x855F97U, 0xDDE520U, 0xD6B479U, 0x8D0FB6U, 0x8C1C07U, + 0xF7C6D8U, 0xBE77A9U, 0xA53C36U, 0xEFAFDFU, 0x369648U, 0x1D4411U, 0x40DFE6U, 0x4BEE7EU, 0x103595U, 0x5902C0U, + 0x43D85BU, 0x2AC9AEU, 0x316265U, 0x7AB158U, 0x23A18BU, 0x201A56U, 0xD949E5U, 0x93F2A8U, 0x882313U, 0xC139C6U, + 0xDA8A3CU, 0x97D329U, 0xEC50E2U, 0xE7AA13U, 0xBFBB8CU, 0xB42075U, 0xED5322U, 0x06C8ABU, 0x1DF85CU, 0x542785U, + 0x0FB4BAU, 0x0FCD7BU, 0x544FA4U, 0x7F5414U, 0x26A54BU, 0x6D3EF2U, 0x702D31U, 0x3BD7CCU, 0x13C6DFU, 0xC83D02U, + 0x83AEF9U, 0x9AB77CU, 0xD15507U, 0xC84ED2U, 0xA3DF49U, 0xF9A4BDU, 0xF836F6U, 0xA3ED4BU, 0xEADC98U, 0xD14B05U, + 0x9A30E6U, 0x03A0BFU, 0x4D6B00U, 0x1458D1U, 0x1FC12EU, 0x64932FU, 0x6D28F0U, 0x36BB09U, 0x7FE29FU, 0x6551E6U, + 0x0E0B21U, 0x57AAB8U, 0x54B147U, 0x8D6216U, 0x86DBA9U, 0xDDC968U, 0xB412F3U, 0xAA218EU, 0xE3FC5DU, 0xF86EF0U, + 0xB35523U, 0xCA945FU, 0xC1AFCCU, 0x983C11U, 0xD264FAU, 0x49D7EFU, 0x000C14U, 0x3B1FC1U, 0x7AA75AU, 0x21F4B7U, + 0x2A6FA4U, 0x728E5DU, 0x5D958AU, 0x042713U, 0x4F767DU, 0x54EDACU, 0x1D5E13U, 0x8604C0U, 0xEE91ADU, 0xB5EA36U, + 0xBC79E3U, 0xE77018U, 0xAC820DU, 0x9D19E6U, 0xD6283FU, 0xCEF3A8U, 0x85E0D1U, 0xDA1A47U, 0x538BAEU, 0x389079U, + 0x216360U, 0x6A6B9FU, 0x30D84EU, 0x3903E1U, 0x421230U, 0x0BE94FU, 0x10FBD6U, 0x5B6011U, 0x4215E8U, 0x008EFBU, + 0xF95C07U, 0xF2759CU, 0xADE659U, 0xA49D22U, 0xFF0CB7U, 0x96964CU, 0x8CE591U, 0xC77E92U, 0x9E2F6FU, 0x959CBCU, + 0xCC0601U, 0xE7475AU, 0x3CFCBFU, 0x74EF25U, 0x6717F4U, 0x2E048BU, 0x15DF0AU, 0x5A6CF5U, 0x03716CU, 0x08A33BU, + 0x5098C2U, 0x5B1945U, 0x20C2BCU, 0x69F063U, 0xF22972U, 0xBB1A8DU, 0xE0814DU, 0xCA52F6U, 0x936AABU, 0x98B958U, + 0xC9A2C5U, 0x820306U, 0x9B593BU, 0xF4CAE0U, 0xEE7315U, 0xA7209EU, 0x7C9BCBU, 0x75C930U, 0x0E54A4U, 0x45E75FU, + 0x5CBC12U, 0x173D81U, 0x0F0778U, 0x44D4AFU, 0x3FC596U, 0x363E59U, 0x65ACE8U, 0x6C9737U, 0xA346E6U, 0xD95DD9U, + 0xD0FE10U, 0x8B26E6U, 0xC2357FU, 0xD9CE28U, 0x92DDC1U, 0xAB455EU, 0xE1B6AFU, 0xB8ADF4U, 0xB35861U, 0x68438AU, + 0x41C157U, 0x12B864U, 0x5B2BB9U, 0x45B00AU, 0x0EC3C6U, 0x175B95U, 0x7C2828U, 0x25B3F3U, 0x2E2206U, 0x75580DU, + 0x3DDBD8U, 0x86C223U, 0xCF31BAU, 0xD4AADDU, 0x9FF804U, 0xC64193U, 0xCD526AU, 0xBDA9F4U, 0xB2BD95U, 0xE92E4AU, + 0xA0C5FBU, 0xBBD424U, 0xD20F7DU, 0x093DDAU, 0x01A603U, 0x5A77F0U, 0x514CEDU, 0x089E36U, 0x63A7D3U, 0x7A3448U, + 0x31FF3CU, 0x2BCEE7U, 0x625462U, 0x150799U, 0x1CBC84U, 0xC7ED77U, 0x8C76AAU, 0x95C409U, 0xDF9954U, 0xE62A8FU, + 0xAD213EU, 0xF6F1E1U, 0xFF4A00U, 0xA4191EU, 0x8D82C7U, 0xD7B330U, 0x9C69A9U, 0x057ACEU, 0x42C357U, 0x2B1088U, + 0x303A79U, 0x7BEB76U, 0x63F087U, 0x284358U, 0x7198E1U, 0x5A88B2U, 0x017B7EU, 0x0860CDU, 0x53F510U, 0x9A0F63U, + 0xA00CFEU, 0xEBB535U, 0xF2E6C0U, 0xB97DDBU, 0xEC0F2EU, 0xE796B5U, 0x9C0578U, 0xD47E0BU, 0xCFEF92U, 0x86F564U, + 0x1D16ADU, 0x768F32U, 0x2FFC43U, 0x24669CU, 0x7C752DU, 0x778CE2U, 0x2E1F9BU, 0x45000CU, 0x5EF0D5U, 0x13FB62U, + 0x40282BU, 0x4811D4U, 0xB38344U, 0xB8789FU, 0xE16BEAU, 0xAAB261U, 0xB38194U, 0xF81B4FU, 0xC2CA52U, 0x8BE1B1U, + 0xD0726CU, 0xD903DFU, 0x829982U, 0xE94A79U, 0x7471FDU, 0x36E026U, 0x2FBA93U, 0x640DC8U, 0x3F1431U, 0x16D7B6U, + 0x4D6C6FU, 0x443C18U, 0x1E8781U, 0x55947EU, 0x6C4FBFU, 0x27FFA0U, 0xBEE451U, 0xF5378FU, 0xAE0E2EU, 0xA2CD71U, + 0xC9D7C8U, 0x98661FU, 0x93BDC6U, 0xC88EE5U, 0xC15438U, 0xBA45C3U, 0xF2FE56U, 0xE9290DU, 0x2230E8U, 0x3B9273U, + 0x70C98FU, 0x0958DCU, 0x02A343U, 0x58B0A2U, 0x150A7DU, 0x0E5BC4U, 0x6FC897U, 0x74F33AU, 0x3F23E9U, 0x66A834U, + 0xECDB0FU, 0xB542DAU, 0x9E5131U, 0xC7ABA5U, 0x8C38FEU, 0x97010BU, 0xDED290U, 0xA4CC7DU, 0xAD3D2EU, 0xF6B6B3U, + 0xF9A540U, 0x205ED9U, 0x634EB6U, 0x5A9567U, 0x11A6D8U, 0x0B3F09U}; + +const unsigned int INTERLEAVE_TABLE_5_20[] = { + 0U, 40U, 80U, 120U, 160U, + 2U, 42U, 82U, 122U, 162U, + 4U, 44U, 84U, 124U, 164U, + 6U, 46U, 86U, 126U, 166U, + 8U, 48U, 88U, 128U, 168U, + 10U, 50U, 90U, 130U, 170U, + 12U, 52U, 92U, 132U, 172U, + 14U, 54U, 94U, 134U, 174U, + 16U, 56U, 96U, 136U, 176U, + 18U, 58U, 98U, 138U, 178U, + 20U, 60U, 100U, 140U, 180U, + 22U, 62U, 102U, 142U, 182U, + 24U, 64U, 104U, 144U, 184U, + 26U, 66U, 106U, 146U, 186U, + 28U, 68U, 108U, 148U, 188U, + 30U, 70U, 110U, 150U, 190U, + 32U, 72U, 112U, 152U, 192U, + 34U, 74U, 114U, 154U, 194U, + 36U, 76U, 116U, 156U, 196U, + 38U, 78U, 118U, 158U, 198U}; + +const unsigned int INTERLEAVE_TABLE_9_20[] = { + 0U, 40U, 80U, 120U, 160U, 200U, 240U, 280U, 320U, + 2U, 42U, 82U, 122U, 162U, 202U, 242U, 282U, 322U, + 4U, 44U, 84U, 124U, 164U, 204U, 244U, 284U, 324U, + 6U, 46U, 86U, 126U, 166U, 206U, 246U, 286U, 326U, + 8U, 48U, 88U, 128U, 168U, 208U, 248U, 288U, 328U, + 10U, 50U, 90U, 130U, 170U, 210U, 250U, 290U, 330U, + 12U, 52U, 92U, 132U, 172U, 212U, 252U, 292U, 332U, + 14U, 54U, 94U, 134U, 174U, 214U, 254U, 294U, 334U, + 16U, 56U, 96U, 136U, 176U, 216U, 256U, 296U, 336U, + 18U, 58U, 98U, 138U, 178U, 218U, 258U, 298U, 338U, + 20U, 60U, 100U, 140U, 180U, 220U, 260U, 300U, 340U, + 22U, 62U, 102U, 142U, 182U, 222U, 262U, 302U, 342U, + 24U, 64U, 104U, 144U, 184U, 224U, 264U, 304U, 344U, + 26U, 66U, 106U, 146U, 186U, 226U, 266U, 306U, 346U, + 28U, 68U, 108U, 148U, 188U, 228U, 268U, 308U, 348U, + 30U, 70U, 110U, 150U, 190U, 230U, 270U, 310U, 350U, + 32U, 72U, 112U, 152U, 192U, 232U, 272U, 312U, 352U, + 34U, 74U, 114U, 154U, 194U, 234U, 274U, 314U, 354U, + 36U, 76U, 116U, 156U, 196U, 236U, 276U, 316U, 356U, + 38U, 78U, 118U, 158U, 198U, 238U, 278U, 318U, 358U}; + +const unsigned int INTERLEAVE_TABLE_26_4[] = { + 0U, 4U, 8U, 12U, 16U, 20U, 24U, 28U, 32U, 36U, 40U, 44U, 48U, 52U, 56U, 60U, 64U, 68U, 72U, 76U, 80U, 84U, 88U, 92U, 96U, 100U, + 1U, 5U, 9U, 13U, 17U, 21U, 25U, 29U, 33U, 37U, 41U, 45U, 49U, 53U, 57U, 61U, 65U, 69U, 73U, 77U, 81U, 85U, 89U, 93U, 97U, 101U, + 2U, 6U, 10U, 14U, 18U, 22U, 26U, 30U, 34U, 38U, 42U, 46U, 50U, 54U, 58U, 62U, 66U, 70U, 74U, 78U, 82U, 86U, 90U, 94U, 98U, 102U, + 3U, 7U, 11U, 15U, 19U, 23U, 27U, 31U, 35U, 39U, 43U, 47U, 51U, 55U, 59U, 63U, 67U, 71U, 75U, 79U, 83U, 87U, 91U, 95U, 99U, 103U}; + +const unsigned char WHITENING_DATA[] = {0x93U, 0xD7U, 0x51U, 0x21U, 0x9CU, 0x2FU, 0x6CU, 0xD0U, 0xEFU, 0x0FU, + 0xF8U, 0x3DU, 0xF1U, 0x73U, 0x20U, 0x94U, 0xEDU, 0x1EU, 0x7CU, 0xD8U}; + +}