[THIS MAY BREAK THINGS, BE AWARE] Merge Win32 support and C++ dvmbridge into master. (#67)

* experimental support for WIN32 compilation (tested only with VS2022);

* fix up incorrect return;

* make debug compile verbose; ensure ws2_32.lib is included;

* initial commit of vocoder library to main source tree; initial commit of C++ port of bridge (non-functional);

* calculate the length of the preamble tone and properly write it;

* implement MDC callback to detect MDC unit ID; implement UDP audio reception; implement local audio reception;

* very alpha working verison;

* correct buffer size;

* correct issue with enabled Tx mode not properly being set on the network; correct issue with DMR not setting the appropriate frame length after packing AMBE bits; correct false call starts by faking the txStreamId (this isn't correct but works for now); fix issue with P25 non-GROUP LCOs causing audio breaks; correct bad logic for call lockup thread;

* cleanup and properly align log messages;

* implement missing Rx/Tx manual gain control; fix missing srcId overrides;

* eliminate the __ALLOC_VLA macro (this really only works on VS2022, GCC explodes in a fit of horror);

* fix missing comment;

* fix bad CFLAGS; correct missing dl library when linking dvmbridge on linux; fix various typos and bad variable types in bridge;

* fix some bad memset calls not taking array size into account; fix some missing parens;

* implement missing cal options;

* don't start the timer till the first LDU1 for cal mode;

* I'm just full of bad mistakes today;

* ignore logging excessive sync frame errors;

* update modem submodule;

* Add DVM-V24 Firmware Submodule And Enable Building It (#66)

* Added v24 firmware as a submodule

* Added v24 firmware compilation

* V24 doesn't have make clean, so remove it from cmake

* Added V24 firmware to tarballs

* Fix my 1D107 error...

---------

Co-authored-by: faulty <faulty@evilcomputing.net>

* correct compilation flags for Win32; add support to dump sample levels on bridge (this is useful for tuning the vox level); add various fixes for local audio flag; add various fixes for not starting loops until completely running; ensure audio input/output device settings are output to the log; fix issue with Rx and Tx gain controls not being applied appropriately;

* fix compilation issues for RPI_ARM; ensure math constants are defined; remove unused command line arguments;

---------

Co-authored-by: Jim <25770089+faultywarrior@users.noreply.github.com>
Co-authored-by: faulty <faulty@evilcomputing.net>
pull/69/head
Bryan Biedenkapp 2 years ago committed by GitHub
parent 37e058731c
commit 65fa91b7cb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -39,11 +39,23 @@ endif (ENABLE_TCP_SSL)
option(CROSS_COMPILE_ARM "Cross-compile for 32-bit ARM" off) option(CROSS_COMPILE_ARM "Cross-compile for 32-bit ARM" off)
option(CROSS_COMPILE_AARCH64 "Cross-compile for 64-bit ARM" off) option(CROSS_COMPILE_AARCH64 "Cross-compile for 64-bit ARM" off)
option(CROSS_COMPILE_RPI_ARM "Cross-compile for (old RPi) 32-bit ARM" off) option(CROSS_COMPILE_RPI_ARM "Cross-compile for (old RPi) 32-bit ARM" off)
option(COMPILE_WIN32 "Compile for Win32" off)
if (COMPILE_WIN32)
set(ARCH amd64)
set(CMAKE_SYSTEM_PROCESSOR amd64)
# No TUI for this
set(ENABLE_TUI_SUPPORT OFF)
message(CHECK_START "Enable TUI support - no; for simplicity WIN32 does not support TUI.")
set(ENABLE_TCP_SSL OFF)
message(CHECK_START "Enable TCP SSL support - no; for simplicity WIN32 does not support TCP SSL.")
else()
set(CMAKE_C_COMPILER /usr/bin/gcc) set(CMAKE_C_COMPILER /usr/bin/gcc)
set(CMAKE_CXX_COMPILER /usr/bin/g++) set(CMAKE_CXX_COMPILER /usr/bin/g++)
set(ARCH amd64) set(ARCH amd64)
set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE amd64) set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE amd64)
endif (COMPILE_WIN32)
if (CROSS_COMPILE_ARM) if (CROSS_COMPILE_ARM)
set(CMAKE_C_COMPILER /usr/bin/arm-linux-gnueabihf-gcc) set(CMAKE_C_COMPILER /usr/bin/arm-linux-gnueabihf-gcc)
@ -123,19 +135,19 @@ if(NOT CMAKE_BUILD_TYPE)
endif(NOT CMAKE_BUILD_TYPE) endif(NOT CMAKE_BUILD_TYPE)
message(CHECK_START "Build Type is ${CMAKE_BUILD_TYPE}") message(CHECK_START "Build Type is ${CMAKE_BUILD_TYPE}")
if (CMAKE_BUILD_TYPE MATCHES Debug) if (CMAKE_BUILD_TYPE MATCHES Debug)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O0 -Wall -Wno-overloaded-virtual -std=c++14") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O0 -Wall")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O0 -Wall -Wno-overloaded-virtual -std=c++14") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O0 -Wall -Wno-overloaded-virtual -std=c++14")
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -g -O0 -Wall -Wno-overloaded-virtual -std=c++14") set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -g -O0 -Wall")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -g -O0 -Wall -Wno-overloaded-virtual -std=c++14") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -g -O0 -Wall -Wno-overloaded-virtual -std=c++14")
elseif(CMAKE_BUILD_TYPE MATCHES Release) elseif(CMAKE_BUILD_TYPE MATCHES Release)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O3 -Wall -Wno-overloaded-virtual -std=c++14 -s") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O3 -Wall -s")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O3 -Wall -Wno-overloaded-virtual -std=c++14 -s") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O3 -Wall -Wno-overloaded-virtual -std=c++14 -s")
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -g -O3 -Wall -Wno-overloaded-virtual -std=c++14 -s") set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -g -O3 -Wall -s")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -g -O3 -Wall -Wno-overloaded-virtual -std=c++14 -s") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -g -O3 -Wall -Wno-overloaded-virtual -std=c++14 -s")
else() else()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O3 -Wall -Wno-overloaded-virtual -std=c++14") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O3 -Wall")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O3 -Wall -Wno-overloaded-virtual -std=c++14") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O3 -Wall -Wno-overloaded-virtual -std=c++14")
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -g -O3 -Wall -Wno-overloaded-virtual -std=c++14") set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -g -O3 -Wall")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -g -O3 -Wall -Wno-overloaded-virtual -std=c++14") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -g -O3 -Wall -Wno-overloaded-virtual -std=c++14")
endif() endif()
if (CROSS_COMPILE_ARM) if (CROSS_COMPILE_ARM)
@ -144,6 +156,15 @@ if (CROSS_COMPILE_ARM)
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -Wno-psabi") set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -Wno-psabi")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -Wno-psabi") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -Wno-psabi")
endif (CROSS_COMPILE_ARM) endif (CROSS_COMPILE_ARM)
if (CROSS_COMPILE_RPI_ARM)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -std=c99")
endif (CROSS_COMPILE_RPI_ARM)
if (COMPILE_WIN32)
set(CMAKE_C_FLAGS "/EHsc /D_WIN32 /D_DISABLE_CONSTEXPR_MUTEX_CONSTRUCTOR")
set(CMAKE_CXX_FLAGS "/EHsc /D_WIN32 /D_DISABLE_CONSTEXPR_MUTEX_CONSTRUCTOR")
endif (COMPILE_WIN32)
set(CMAKE_INSTALL_PREFIX "/usr/local") set(CMAKE_INSTALL_PREFIX "/usr/local")
@ -230,7 +251,8 @@ install(TARGETS dvmfne DESTINATION ${CMAKE_INSTALL_PREFIX}/bin)
if (ENABLE_TUI_SUPPORT AND (NOT DISABLE_MONITOR)) if (ENABLE_TUI_SUPPORT AND (NOT DISABLE_MONITOR))
install(TARGETS dvmmon DESTINATION ${CMAKE_INSTALL_PREFIX}/bin) install(TARGETS dvmmon DESTINATION ${CMAKE_INSTALL_PREFIX}/bin)
endif (ENABLE_TUI_SUPPORT AND (NOT DISABLE_MONITOR)) endif (ENABLE_TUI_SUPPORT AND (NOT DISABLE_MONITOR))
install(FILES configs/config.example.yml configs/fne-config.example.yml configs/monitor-config.example.yml configs/iden_table.dat configs/RSSI.dat configs/rid_acl.example.dat configs/talkgroup_rules.example.yml DESTINATION ${CMAKE_INSTALL_PREFIX}/etc) install(TARGETS dvmbridge DESTINATION ${CMAKE_INSTALL_PREFIX}/bin)
install(FILES configs/config.example.yml configs/fne-config.example.yml configs/monitor-config.example.yml configs/iden_table.dat configs/RSSI.dat configs/rid_acl.example.dat configs/talkgroup_rules.example.yml configs/bridge-config.example.yml DESTINATION ${CMAKE_INSTALL_PREFIX}/etc)
install(PROGRAMS tools/start-dvm.sh tools/stop-dvm.sh tools/dvm-watchdog.sh tools/stop-watchdog.sh tools/fne-watchdog.sh tools/start-dvm-fne.sh DESTINATION ${CMAKE_INSTALL_PREFIX}/bin) install(PROGRAMS tools/start-dvm.sh tools/stop-dvm.sh tools/dvm-watchdog.sh tools/stop-watchdog.sh tools/fne-watchdog.sh tools/start-dvm-fne.sh DESTINATION ${CMAKE_INSTALL_PREFIX}/bin)
install(CODE "execute_process(COMMAND bash \"-c\" \"sed -i 's/filePath: ./filePath: \\\\/var\\\\/log\\\\//' /usr/local/etc/config.example.yml\")") install(CODE "execute_process(COMMAND bash \"-c\" \"sed -i 's/filePath: ./filePath: \\\\/var\\\\/log\\\\//' /usr/local/etc/config.example.yml\")")
install(CODE "execute_process(COMMAND bash \"-c\" \"sed -i 's/activityFilePath: ./activityFilePath: \\\\/var\\\\/log\\\\//' /usr/local/etc/config.example.yml\")") install(CODE "execute_process(COMMAND bash \"-c\" \"sed -i 's/activityFilePath: ./activityFilePath: \\\\/var\\\\/log\\\\//' /usr/local/etc/config.example.yml\")")
@ -248,12 +270,14 @@ if (NOT TARGET strip)
COMMAND arm-linux-gnueabihf-strip -s dvmhost COMMAND arm-linux-gnueabihf-strip -s dvmhost
COMMAND arm-linux-gnueabihf-strip -s dvmfne COMMAND arm-linux-gnueabihf-strip -s dvmfne
COMMAND arm-linux-gnueabihf-strip -s dvmcmd COMMAND arm-linux-gnueabihf-strip -s dvmcmd
COMMAND arm-linux-gnueabihf-strip -s dvmmon) COMMAND arm-linux-gnueabihf-strip -s dvmmon
COMMAND arm-linux-gnueabihf-strip -s dvmbridge)
else() else()
add_custom_target(strip add_custom_target(strip
COMMAND arm-linux-gnueabihf-strip -s dvmhost COMMAND arm-linux-gnueabihf-strip -s dvmhost
COMMAND arm-linux-gnueabihf-strip -s dvmfne COMMAND arm-linux-gnueabihf-strip -s dvmfne
COMMAND arm-linux-gnueabihf-strip -s dvmcmd) COMMAND arm-linux-gnueabihf-strip -s dvmcmd
COMMAND arm-linux-gnueabihf-strip -s dvmbridge)
endif (ENABLE_TUI_SUPPORT AND (NOT DISABLE_MONITOR)) endif (ENABLE_TUI_SUPPORT AND (NOT DISABLE_MONITOR))
elseif (CROSS_COMPILE_AARCH64) elseif (CROSS_COMPILE_AARCH64)
if (ENABLE_TUI_SUPPORT AND (NOT DISABLE_MONITOR)) if (ENABLE_TUI_SUPPORT AND (NOT DISABLE_MONITOR))
@ -261,24 +285,28 @@ if (NOT TARGET strip)
COMMAND aarch64-linux-gnu-strip -s dvmhost COMMAND aarch64-linux-gnu-strip -s dvmhost
COMMAND aarch64-linux-gnu-strip -s dvmfne COMMAND aarch64-linux-gnu-strip -s dvmfne
COMMAND aarch64-linux-gnu-strip -s dvmcmd COMMAND aarch64-linux-gnu-strip -s dvmcmd
COMMAND aarch64-linux-gnu-strip -s dvmmon) COMMAND aarch64-linux-gnu-strip -s dvmmon
COMMAND aarch64-linux-gnu-strip -s dvmbridge)
else() else()
add_custom_target(strip add_custom_target(strip
COMMAND aarch64-linux-gnu-strip -s dvmhost COMMAND aarch64-linux-gnu-strip -s dvmhost
COMMAND aarch64-linux-gnu-strip -s dvmfne COMMAND aarch64-linux-gnu-strip -s dvmfne
COMMAND aarch64-linux-gnu-strip -s dvmcmd) COMMAND aarch64-linux-gnu-strip -s dvmcmd
COMMAND aarch64-linux-gnu-strip -s dvmbridge)
endif (ENABLE_TUI_SUPPORT AND (NOT DISABLE_MONITOR)) endif (ENABLE_TUI_SUPPORT AND (NOT DISABLE_MONITOR))
elseif (CROSS_COMPILE_RPI_ARM) elseif (CROSS_COMPILE_RPI_ARM)
if (NOT WITH_RPI_ARM_TOOLS) if (NOT WITH_RPI_ARM_TOOLS)
add_custom_target(strip add_custom_target(strip
COMMAND ${CMAKE_CURRENT_BINARY_DIR}/_deps/rpitools-src/arm-bcm2708/arm-linux-gnueabihf/bin/arm-linux-gnueabihf-strip -s dvmhost COMMAND ${CMAKE_CURRENT_BINARY_DIR}/_deps/rpitools-src/arm-bcm2708/arm-linux-gnueabihf/bin/arm-linux-gnueabihf-strip -s dvmhost
COMMAND ${CMAKE_CURRENT_BINARY_DIR}/_deps/rpitools-src/arm-bcm2708/arm-linux-gnueabihf/bin/arm-linux-gnueabihf-strip -s dvmfne COMMAND ${CMAKE_CURRENT_BINARY_DIR}/_deps/rpitools-src/arm-bcm2708/arm-linux-gnueabihf/bin/arm-linux-gnueabihf-strip -s dvmfne
COMMAND ${CMAKE_CURRENT_BINARY_DIR}/_deps/rpitools-src/arm-bcm2708/arm-linux-gnueabihf/bin/arm-linux-gnueabihf-strip -s dvmcmd) COMMAND ${CMAKE_CURRENT_BINARY_DIR}/_deps/rpitools-src/arm-bcm2708/arm-linux-gnueabihf/bin/arm-linux-gnueabihf-strip -s dvmcmd
COMMAND ${CMAKE_CURRENT_BINARY_DIR}/_deps/rpitools-src/arm-bcm2708/arm-linux-gnueabihf/bin/arm-linux-gnueabihf-strip -s dvmbridge)
else() else()
add_custom_target(strip add_custom_target(strip
COMMAND ${RPI_ARM_TOOLS}/arm-bcm2708/arm-linux-gnueabihf/bin/arm-linux-gnueabihf-strip -s dvmhost COMMAND ${RPI_ARM_TOOLS}/arm-bcm2708/arm-linux-gnueabihf/bin/arm-linux-gnueabihf-strip -s dvmhost
COMMAND ${RPI_ARM_TOOLS}/arm-bcm2708/arm-linux-gnueabihf/bin/arm-linux-gnueabihf-strip -s dvmfne COMMAND ${RPI_ARM_TOOLS}/arm-bcm2708/arm-linux-gnueabihf/bin/arm-linux-gnueabihf-strip -s dvmfne
COMMAND ${RPI_ARM_TOOLS}/arm-bcm2708/arm-linux-gnueabihf/bin/arm-linux-gnueabihf-strip -s dvmcmd) COMMAND ${RPI_ARM_TOOLS}/arm-bcm2708/arm-linux-gnueabihf/bin/arm-linux-gnueabihf-strip -s dvmcmd
COMMAND ${RPI_ARM_TOOLS}/arm-bcm2708/arm-linux-gnueabihf/bin/arm-linux-gnueabihf-strip -s dvmbridge)
endif () endif ()
else() else()
if (ENABLE_TUI_SUPPORT AND (NOT DISABLE_MONITOR)) if (ENABLE_TUI_SUPPORT AND (NOT DISABLE_MONITOR))
@ -286,12 +314,14 @@ if (NOT TARGET strip)
COMMAND strip -s dvmhost COMMAND strip -s dvmhost
COMMAND strip -s dvmfne COMMAND strip -s dvmfne
COMMAND strip -s dvmcmd COMMAND strip -s dvmcmd
COMMAND strip -s dvmmon) COMMAND strip -s dvmmon
COMMAND strip -s dvmbridge)
else() else()
add_custom_target(strip add_custom_target(strip
COMMAND strip -s dvmhost COMMAND strip -s dvmhost
COMMAND strip -s dvmfne COMMAND strip -s dvmfne
COMMAND strip -s dvmcmd) COMMAND strip -s dvmcmd
COMMAND strip -s dvmbridge)
endif (ENABLE_TUI_SUPPORT AND (NOT DISABLE_MONITOR)) endif (ENABLE_TUI_SUPPORT AND (NOT DISABLE_MONITOR))
endif (CROSS_COMPILE_ARM) endif (CROSS_COMPILE_ARM)
endif (NOT TARGET strip) endif (NOT TARGET strip)
@ -317,6 +347,7 @@ if (NOT TARGET tarball)
COMMAND cp -v dvmcmd ${CMAKE_INSTALL_PREFIX_TARBALL}/dvm/bin COMMAND cp -v dvmcmd ${CMAKE_INSTALL_PREFIX_TARBALL}/dvm/bin
COMMAND cp -v dvmmon ${CMAKE_INSTALL_PREFIX_TARBALL}/dvm/bin COMMAND cp -v dvmmon ${CMAKE_INSTALL_PREFIX_TARBALL}/dvm/bin
COMMAND cp -v dvmfne ${CMAKE_INSTALL_PREFIX_TARBALL}/dvm/bin COMMAND cp -v dvmfne ${CMAKE_INSTALL_PREFIX_TARBALL}/dvm/bin
COMMAND cp -v dvmbridge ${CMAKE_INSTALL_PREFIX_TARBALL}/dvm/bin
COMMAND cp ../tools/*.sh ${CMAKE_INSTALL_PREFIX_TARBALL}/dvm COMMAND cp ../tools/*.sh ${CMAKE_INSTALL_PREFIX_TARBALL}/dvm
COMMAND chmod +x ${CMAKE_INSTALL_PREFIX_TARBALL}/dvm/*.sh COMMAND chmod +x ${CMAKE_INSTALL_PREFIX_TARBALL}/dvm/*.sh
COMMAND cp -v ../configs/*.yml ${CMAKE_INSTALL_PREFIX_TARBALL}/dvm COMMAND cp -v ../configs/*.yml ${CMAKE_INSTALL_PREFIX_TARBALL}/dvm
@ -347,6 +378,7 @@ if (NOT TARGET tarball)
COMMAND cp -v dvmhost ${CMAKE_INSTALL_PREFIX_TARBALL}/dvm/bin COMMAND cp -v dvmhost ${CMAKE_INSTALL_PREFIX_TARBALL}/dvm/bin
COMMAND cp -v dvmcmd ${CMAKE_INSTALL_PREFIX_TARBALL}/dvm/bin COMMAND cp -v dvmcmd ${CMAKE_INSTALL_PREFIX_TARBALL}/dvm/bin
COMMAND cp -v dvmfne ${CMAKE_INSTALL_PREFIX_TARBALL}/dvm/bin COMMAND cp -v dvmfne ${CMAKE_INSTALL_PREFIX_TARBALL}/dvm/bin
COMMAND cp -v dvmbridge ${CMAKE_INSTALL_PREFIX_TARBALL}/dvm/bin
COMMAND cp ../tools/*.sh ${CMAKE_INSTALL_PREFIX_TARBALL}/dvm COMMAND cp ../tools/*.sh ${CMAKE_INSTALL_PREFIX_TARBALL}/dvm
COMMAND chmod +x ${CMAKE_INSTALL_PREFIX_TARBALL}/dvm/*.sh COMMAND chmod +x ${CMAKE_INSTALL_PREFIX_TARBALL}/dvm/*.sh
COMMAND cp -v ../configs/*.yml ${CMAKE_INSTALL_PREFIX_TARBALL}/dvm COMMAND cp -v ../configs/*.yml ${CMAKE_INSTALL_PREFIX_TARBALL}/dvm
@ -387,6 +419,7 @@ add_custom_target(old_install
COMMAND install -m 755 dvmcmd ${CMAKE_LEGACY_INSTALL_PREFIX}/bin COMMAND install -m 755 dvmcmd ${CMAKE_LEGACY_INSTALL_PREFIX}/bin
COMMAND install -m 755 dvmmon ${CMAKE_LEGACY_INSTALL_PREFIX}/bin COMMAND install -m 755 dvmmon ${CMAKE_LEGACY_INSTALL_PREFIX}/bin
COMMAND install -m 755 dvmfne ${CMAKE_LEGACY_INSTALL_PREFIX}/bin COMMAND install -m 755 dvmfne ${CMAKE_LEGACY_INSTALL_PREFIX}/bin
COMMAND install -m 755 dvmbridge ${CMAKE_LEGACY_INSTALL_PREFIX}/bin
COMMAND install -m 644 ../configs/config.example.yml ${CMAKE_LEGACY_INSTALL_PREFIX}/config.example.yml COMMAND install -m 644 ../configs/config.example.yml ${CMAKE_LEGACY_INSTALL_PREFIX}/config.example.yml
COMMAND install -m 644 ../configs/fne-config.example.yml ${CMAKE_LEGACY_INSTALL_PREFIX}/fne-config.example.yml COMMAND install -m 644 ../configs/fne-config.example.yml ${CMAKE_LEGACY_INSTALL_PREFIX}/fne-config.example.yml
COMMAND install -m 644 ../configs/monitor-config.example.yml ${CMAKE_LEGACY_INSTALL_PREFIX}/monitor-config.example.yml COMMAND install -m 644 ../configs/monitor-config.example.yml ${CMAKE_LEGACY_INSTALL_PREFIX}/monitor-config.example.yml
@ -394,6 +427,7 @@ add_custom_target(old_install
COMMAND install -m 644 ../configs/RSSI.dat ${CMAKE_LEGACY_INSTALL_PREFIX}/RSSI.dat COMMAND install -m 644 ../configs/RSSI.dat ${CMAKE_LEGACY_INSTALL_PREFIX}/RSSI.dat
COMMAND install -m 644 ../configs/rid_acl.example.dat ${CMAKE_LEGACY_INSTALL_PREFIX}/rid_acl.dat COMMAND install -m 644 ../configs/rid_acl.example.dat ${CMAKE_LEGACY_INSTALL_PREFIX}/rid_acl.dat
COMMAND install -m 644 ../configs/talkgroup_rules.example.yml ${CMAKE_LEGACY_INSTALL_PREFIX}/talkgroup_rules.example.yml COMMAND install -m 644 ../configs/talkgroup_rules.example.yml ${CMAKE_LEGACY_INSTALL_PREFIX}/talkgroup_rules.example.yml
COMMAND install -m 644 ../configs/bridge-config.example.yml ${CMAKE_LEGACY_INSTALL_PREFIX}/bridge-config.example.yml
COMMAND install -m 755 ../tools/start-dvm.sh ${CMAKE_LEGACY_INSTALL_PREFIX} COMMAND install -m 755 ../tools/start-dvm.sh ${CMAKE_LEGACY_INSTALL_PREFIX}
COMMAND install -m 755 ../tools/stop-dvm.sh ${CMAKE_LEGACY_INSTALL_PREFIX} COMMAND install -m 755 ../tools/stop-dvm.sh ${CMAKE_LEGACY_INSTALL_PREFIX}
COMMAND install -m 755 ../tools/dvm-watchdog.sh ${CMAKE_LEGACY_INSTALL_PREFIX} COMMAND install -m 755 ../tools/dvm-watchdog.sh ${CMAKE_LEGACY_INSTALL_PREFIX}
@ -433,6 +467,7 @@ add_custom_target(old_install-service
COMMAND chown dvmhost:dvmhost ${CMAKE_LEGACY_INSTALL_PREFIX}/RSSI.dat COMMAND chown dvmhost:dvmhost ${CMAKE_LEGACY_INSTALL_PREFIX}/RSSI.dat
COMMAND chown dvmhost:dvmhost ${CMAKE_LEGACY_INSTALL_PREFIX}/rid_acl.dat COMMAND chown dvmhost:dvmhost ${CMAKE_LEGACY_INSTALL_PREFIX}/rid_acl.dat
COMMAND chown dvmhost:dvmhost ${CMAKE_LEGACY_INSTALL_PREFIX}/talkgroup_rules.example.yml COMMAND chown dvmhost:dvmhost ${CMAKE_LEGACY_INSTALL_PREFIX}/talkgroup_rules.example.yml
COMMAND chown dvmhost:dvmhost ${CMAKE_LEGACY_INSTALL_PREFIX}/bridge-config.example.yml
COMMAND chown dvmhost:dvmhost ${CMAKE_LEGACY_INSTALL_PREFIX}/log COMMAND chown dvmhost:dvmhost ${CMAKE_LEGACY_INSTALL_PREFIX}/log
COMMAND cp ../linux/dvmhost.service /lib/systemd/system/ COMMAND cp ../linux/dvmhost.service /lib/systemd/system/
COMMAND bash \"-c\" \"sed -i 's/\\\\/usr\\\\/local\\\\/bin/\\\\/opt\\\\/dvm\\\\/bin/' /lib/systemd/system/dvmhost.service\" COMMAND bash \"-c\" \"sed -i 's/\\\\/usr\\\\/local\\\\/bin/\\\\/opt\\\\/dvm\\\\/bin/' /lib/systemd/system/dvmhost.service\"

@ -0,0 +1,76 @@
{
"configurations": [
{
"name": "x64-Debug",
"generator": "Ninja",
"configurationType": "Debug",
"inheritEnvironments": [ "msvc_x64_x64" ],
"buildRoot": "${projectDir}\\out\\build\\${name}",
"installRoot": "${projectDir}\\out\\install\\${name}",
"cmakeCommandArgs": "",
"buildCommandArgs": "-v",
"ctestCommandArgs": "",
"variables": [
{
"name": "COMPILE_WIN32",
"value": "True",
"type": "BOOL"
}
]
},
{
"name": "x64-RelWithDebInfo",
"generator": "Ninja",
"configurationType": "RelWithDebInfo",
"buildRoot": "${projectDir}\\out\\build\\${name}",
"installRoot": "${projectDir}\\out\\install\\${name}",
"cmakeCommandArgs": "",
"buildCommandArgs": "",
"ctestCommandArgs": "",
"inheritEnvironments": [ "msvc_x64_x64" ],
"variables": [
{
"name": "COMPILE_WIN32",
"value": "True",
"type": "BOOL"
}
]
},
{
"name": "x86-Debug",
"generator": "Ninja",
"configurationType": "Debug",
"buildRoot": "${projectDir}\\out\\build\\${name}",
"installRoot": "${projectDir}\\out\\install\\${name}",
"cmakeCommandArgs": "",
"buildCommandArgs": "-v",
"ctestCommandArgs": "",
"inheritEnvironments": [ "msvc_x86" ],
"variables": [
{
"name": "COMPILE_WIN32",
"value": "True",
"type": "BOOL"
}
]
},
{
"name": "x86-RelWithDebInfo",
"generator": "Ninja",
"configurationType": "RelWithDebInfo",
"buildRoot": "${projectDir}\\out\\build\\${name}",
"installRoot": "${projectDir}\\out\\install\\${name}",
"cmakeCommandArgs": "",
"buildCommandArgs": "",
"ctestCommandArgs": "",
"inheritEnvironments": [ "msvc_x86" ],
"variables": [
{
"name": "COMPILE_WIN32",
"value": "True",
"type": "BOOL"
}
]
}
]
}

@ -7,6 +7,7 @@ Please feel free to reach out to us for help, comments or otherwise, on our Disc
This project generates a few executables: This project generates a few executables:
- `dvmhost` host software that connects to the DVM modems (both air interface for repeater and hotspot or P25 DFSI for commerical P25 hardware) and is the primary data processing application for digital modes. [See configuration](#dvmhost-configuration) to configure and calibrate. - `dvmhost` host software that connects to the DVM modems (both air interface for repeater and hotspot or P25 DFSI for commerical P25 hardware) and is the primary data processing application for digital modes. [See configuration](#dvmhost-configuration) to configure and calibrate.
- `dvmfne` a network "core", this provides a central server for `dvmhost` instances to connect to and be networked with, allowing relay of traffic and other data between `dvmhost` instances and other `dvmfne` instances. [See configuration](#dvmfne-configuration) to configure. - `dvmfne` a network "core", this provides a central server for `dvmhost` instances to connect to and be networked with, allowing relay of traffic and other data between `dvmhost` instances and other `dvmfne` instances. [See configuration](#dvmfne-configuration) to configure.
- `dvmbridge` a analog/PCM audio bridge, this provides the capability for analog or PCM audio resources to be connected to a `dvmfne` instance, allowing realtime vocoding of traffic.
- `dvmcmd` a simple command-line utility to send remote control commands to a `dvmhost` or `dvmfne` instance with REST API configured. - `dvmcmd` a simple command-line utility to send remote control commands to a `dvmhost` or `dvmfne` instance with REST API configured.
- `dvmmon` a TUI utility that allows semi-realtime console-based monitoring of `dvmhost` instances (this tool is only available when project wide TUI support is enabled!). - `dvmmon` a TUI utility that allows semi-realtime console-based monitoring of `dvmhost` instances (this tool is only available when project wide TUI support is enabled!).
@ -194,6 +195,29 @@ usage: ./dvmfne [-vhf][--syslog][-c <configuration file>]
-- stop handling options -- stop handling options
``` ```
### dvmbridge Command Line Parameters
```
usage: ./dvmbridge [-vhf][-i <input audio device id>][-o <output audio device id>][-c <configuration file>]
-v show version information
-h show this screen
-f foreground mode
-i input audio device
-o output audio device
-c <file> specifies the configuration file to use
-- stop handling options
Audio Input Devices:
... <list of audio input devices> ...
Audio Output Devices:
... <list of audio output devices> ...
```
### dvmcmd Command Line Parameters ### dvmcmd Command Line Parameters
``` ```

@ -0,0 +1,136 @@
#
# Digital Voice Modem - Bridge
#
# @package DVM / Bridge
#
# Flag indicating whether the host will run as a background or foreground task.
daemon: true
#
# Logging Configuration
#
# Logging Levels:
# 1 - Debug
# 2 - Message
# 3 - Informational
# 4 - Warning
# 5 - Error
# 6 - Fatal
#
log:
# Console display logging level (used when in foreground).
displayLevel: 1
# File logging level.
fileLevel: 1
# Flag indicating file logs should be sent to syslog instead of a file.
useSyslog: false
# Full path for the directory to store the log files.
filePath: .
# Full path for the directory to store the activity log files.
activityFilePath: .
# Log filename prefix.
fileRoot: dvmbridge
#
# Network Configuration
#
network:
# Network Peer ID
id: 9000123
# Hostname/IP address of FNE master to connect to.
address: 127.0.0.1
# Port number to connect to.
port: 62031
# FNE access password.
password: RPT1234
# Flag indicating whether or not host endpoint networking is encrypted.
encrypted: false
# AES-256 32-byte Preshared Key
# (This field *must* be 32 hex bytes in length or 64 characters
# 0 - 9, A - F.)
presharedKey: "000102030405060708090A0B0C0D0E0F000102030405060708090A0B0C0D0E0F"
# Flag indicating whether or not verbose debug logging is enabled.
debug: false
# Enable PCM audio over UDP.
udpAudio: false
# Enable meta data such as dstId and srcId in the UDP data
udpMetaData: false
# PCM over UDP send port.
udpSendPort: 34001
# PCM over UDP send address destination.
udpSendAddress: "127.0.0.1"
# PCM over UDP receive port.
udpReceivePort: 32001
# PCM over UDP receive address.
udpReceiveAddress: "127.0.0.1"
# Source "Radio ID" for transmitted audio frames.
sourceId: 1234567
# Flag indicating the source "Radio ID" will be overridden from the detected
# MDC1200 pre- PTT ID.
overrideSourceIdFromMDC: false
# Flag indicating the source "Radio ID" will be overridden from the received
# UDP SRC ID.
overrideSourceIdFromUDP: false
# Talkgroup ID for transmitted/received audio frames.
destinationId: 1
# Slot for received/transmitted audio frames.
slot: 1
system:
# Textual Name
identity: BRIDGE
# PCM audio gain for received (from digital network) audio frames.
# - This is used to apply gain to the decoded IMBE/AMBE audio, post-decoding.
rxAudioGain: 1.0
# Vocoder audio gain for decoded (from digital network) audio frames.
# - This is used to apply gain to the decoded IMBE/AMBE audio in the vocoder.
# - (Not used when utilizing external USB vocoder!)
vocoderDecoderAudioGain: 3.0
# Flag indicating AGC should be used for frames received/decoded.
# - This is used to apply automatic gain control to decoded IMBE/AMBE audio in the vocoder.
# - (Not used when utilizing external USB vocoder!)
vocoderDecoderAutoGain: false
# PCM audio gain for transmitted (to digital network) audio frames.
# - This is used to apply gain to the encoded IMBE/AMBE audio, pre-encoding.
txAudioGain: 1.0
# Vocoder audio gain for transmitted/encoded (to digital network) audio frames.
# - This is used to apply gain to the encoded IMBE/AMBE audio in the vocoder.
# - (Not used when utilizing external USB vocoder!)
vocoderEncoderAudioGain: 3.0
# Audio transmit mode (1 - DMR, 2 - P25).
txMode: 1
# Relative sample level for VOX to activate.
voxSampleLevel: 80.0
# Amount of time (ms) from loss of active VOX level to drop audio.
dropTimeMs: 180
# Enables detection of MDC1200 packets on the PCM side of the bridge.
# (This is useful for pre-MDC to set the transmitting source ID.)
detectAnalogMDC1200: false
# Flag indicating whether the analog preamble leader is enabled.
# (This enables a leader control tone before audio frames from the
# network are sent.)
preambleLeaderTone: false
# Frequency of preamble tone.
preambleTone: 2175
# Amount of time (ms) to transmit preamble tone.
preambleLength: 200
# Flag indicating the detected VOX sample level should be dumped to the log (useful for setting VOX levels).
dumpSampleLevel: false
# Flag indicating whether a network grant demand packet will be sent before audio.
grantDemand: false
# Enable local audio over speakers.
localAudio: true

@ -14,9 +14,20 @@ include(src/CompilerOptions.cmake)
# #
include(src/common/CMakeLists.txt) include(src/common/CMakeLists.txt)
add_library(common STATIC ${common_SRC} ${common_INCLUDE}) add_library(common STATIC ${common_SRC} ${common_INCLUDE})
if (COMPILE_WIN32)
target_link_libraries(common PRIVATE asio::asio Threads::Threads)
else ()
target_link_libraries(common PRIVATE asio::asio Threads::Threads util) target_link_libraries(common PRIVATE asio::asio Threads::Threads util)
endif (COMPILE_WIN32)
target_include_directories(common PRIVATE src src/common) target_include_directories(common PRIVATE src src/common)
#
## vocoder
#
include(src/vocoder/CMakeLists.txt)
add_library(vocoder STATIC ${vocoder_SRC} ${vocoder_INCLUDE})
target_include_directories(vocoder PRIVATE src src/vocoder)
# #
## dvmhost ## dvmhost
# #
@ -29,8 +40,12 @@ endif (ENABLE_SETUP_TUI)
add_executable(dvmhost ${common_INCLUDE} ${dvmhost_SRC}) add_executable(dvmhost ${common_INCLUDE} ${dvmhost_SRC})
if (ENABLE_SETUP_TUI) if (ENABLE_SETUP_TUI)
target_link_libraries(dvmhost PRIVATE common ${OPENSSL_LIBRARIES} asio::asio finalcut Threads::Threads util) target_link_libraries(dvmhost PRIVATE common ${OPENSSL_LIBRARIES} asio::asio finalcut Threads::Threads util)
else ()
if (COMPILE_WIN32)
target_link_libraries(dvmhost PRIVATE common ${OPENSSL_LIBRARIES} asio::asio Threads::Threads)
else () else ()
target_link_libraries(dvmhost PRIVATE common ${OPENSSL_LIBRARIES} asio::asio Threads::Threads util) target_link_libraries(dvmhost PRIVATE common ${OPENSSL_LIBRARIES} asio::asio Threads::Threads util)
endif (COMPILE_WIN32)
endif (ENABLE_SETUP_TUI) endif (ENABLE_SETUP_TUI)
target_include_directories(dvmhost PRIVATE ${OPENSSL_INCLUDE_DIR} src src/host) target_include_directories(dvmhost PRIVATE ${OPENSSL_INCLUDE_DIR} src src/host)
@ -81,3 +96,15 @@ include(src/remote/CMakeLists.txt)
add_executable(dvmcmd ${common_INCLUDE} ${dvmcmd_SRC}) add_executable(dvmcmd ${common_INCLUDE} ${dvmcmd_SRC})
target_link_libraries(dvmcmd PRIVATE common ${OPENSSL_LIBRARIES} asio::asio Threads::Threads) target_link_libraries(dvmcmd PRIVATE common ${OPENSSL_LIBRARIES} asio::asio Threads::Threads)
target_include_directories(dvmcmd PRIVATE ${OPENSSL_INCLUDE_DIR} src src/remote) target_include_directories(dvmcmd PRIVATE ${OPENSSL_INCLUDE_DIR} src src/remote)
#
## dvmbridge
#
include(src/bridge/CMakeLists.txt)
add_executable(dvmbridge ${common_INCLUDE} ${bridge_SRC})
if (COMPILE_WIN32)
target_link_libraries(dvmbridge PRIVATE common vocoder ${OPENSSL_LIBRARIES} asio::asio Threads::Threads)
else ()
target_link_libraries(dvmbridge PRIVATE common vocoder ${OPENSSL_LIBRARIES} dl asio::asio Threads::Threads)
endif (COMPILE_WIN32)
target_include_directories(dvmbridge PRIVATE ${OPENSSL_INCLUDE_DIR} src src/host src/bridge)

@ -0,0 +1,155 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Digital Voice Modem - Bridge
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright (C) 2024 Bryan Biedenkapp, N2PLL
*
*/
#include "ActivityLog.h"
#include "common/network/BaseNetwork.h"
#include "common/Log.h" // for CurrentLogFileLevel() and LogGetNetwork()
#if defined(_WIN32)
#include "common/Clock.h"
#else
#include <sys/time.h>
#endif // defined(_WIN32)
#if defined(CATCH2_TEST_COMPILATION)
#include <catch2/catch_test_macros.hpp>
#endif
#include <cstdio>
#include <cstdarg>
#include <ctime>
#include <cassert>
#include <cstring>
// ---------------------------------------------------------------------------
// Constants
// ---------------------------------------------------------------------------
#define EOL "\r\n"
const uint32_t ACT_LOG_BUFFER_LEN = 501U;
// ---------------------------------------------------------------------------
// Global Variables
// ---------------------------------------------------------------------------
static std::string m_actFilePath;
static std::string m_actFileRoot;
static FILE* m_actFpLog = nullptr;
static struct tm m_actTm;
// ---------------------------------------------------------------------------
// Global Functions
// ---------------------------------------------------------------------------
/* Helper to open the activity log file, file handle. */
static bool ActivityLogOpen()
{
if (CurrentLogFileLevel() == 0U)
return true;
time_t now;
::time(&now);
struct tm* tm = ::gmtime(&now);
if (tm->tm_mday == m_actTm.tm_mday && tm->tm_mon == m_actTm.tm_mon && tm->tm_year == m_actTm.tm_year) {
if (m_actFpLog != nullptr)
return true;
}
else {
if (m_actFpLog != nullptr)
::fclose(m_actFpLog);
}
char filename[200U];
::sprintf(filename, "%s/%s-%04d-%02d-%02d.activity.log", LogGetFilePath().c_str(), LogGetFileRoot().c_str(), tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday);
m_actFpLog = ::fopen(filename, "a+t");
m_actTm = *tm;
return m_actFpLog != nullptr;
}
/* Initializes the activity log. */
bool ActivityLogInitialise(const std::string& filePath, const std::string& fileRoot)
{
#if defined(CATCH2_TEST_COMPILATION)
return true;
#endif
m_actFilePath = filePath;
m_actFileRoot = fileRoot;
return ::ActivityLogOpen();
}
/* Finalizes the activity log. */
void ActivityLogFinalise()
{
#if defined(CATCH2_TEST_COMPILATION)
return;
#endif
if (m_actFpLog != nullptr)
::fclose(m_actFpLog);
}
/* Writes a new entry to the activity log. */
void ActivityLog(const char* msg, ...)
{
#if defined(CATCH2_TEST_COMPILATION)
return;
#endif
assert(msg != nullptr);
char buffer[ACT_LOG_BUFFER_LEN];
time_t now;
::time(&now);
struct tm* tm = ::localtime(&now);
struct timeval nowMillis;
::gettimeofday(&nowMillis, NULL);
::sprintf(buffer, "A: %04d-%02d-%02d %02d:%02d:%02d.%03lu ", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, nowMillis.tv_usec / 1000U);
va_list vl, vl_len;
va_start(vl, msg);
va_copy(vl_len, vl);
size_t len = ::vsnprintf(nullptr, 0U, msg, vl_len);
::vsnprintf(buffer + ::strlen(buffer), len + 1U, msg, vl);
va_end(vl_len);
va_end(vl);
bool ret = ::ActivityLogOpen();
if (!ret)
return;
if (LogGetNetwork() != nullptr) {
network::BaseNetwork* network = (network::BaseNetwork*)LogGetNetwork();;
network->writeActLog(buffer);
}
if (CurrentLogFileLevel() == 0U)
return;
::fprintf(m_actFpLog, "%s\n", buffer);
::fflush(m_actFpLog);
if (2U >= g_logDisplayLevel && g_logDisplayLevel != 0U) {
::fprintf(stdout, "%s" EOL, buffer);
::fflush(stdout);
}
}

@ -0,0 +1,45 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Digital Voice Modem - Bridge
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright (C) 2024 Bryan Biedenkapp, N2PLL
*
*/
/**
* @file ActivityLog.h
* @ingroup bridge
* @file ActivityLog.cpp
* @ingroup bridge
*/
#if !defined(__ACTIVITY_LOG_H__)
#define __ACTIVITY_LOG_H__
#include "Defines.h"
#include <string>
// ---------------------------------------------------------------------------
// Global Functions
// ---------------------------------------------------------------------------
/**
* @brief Initializes the activity log.
* @param filePath File path for the log file.
* @param fileRoot Root name for log file.
*/
extern HOST_SW_API bool ActivityLogInitialise(const std::string& filePath, const std::string& fileRoot);
/**
* @brief Finalizes the activity log.
*/
extern HOST_SW_API void ActivityLogFinalise();
/**
* @brief Writes a new entry to the activity log.
* @param msg String format.
*
* This is a variable argument function.
*/
extern HOST_SW_API void ActivityLog(const char* msg, ...);
#endif // __ACTIVITY_LOG_H__

@ -0,0 +1,272 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Digital Voice Modem - Bridge
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright (C) 2024 Bryan Biedenkapp, N2PLL
*
*/
#include "Defines.h"
#include "common/Log.h"
#include "bridge/ActivityLog.h"
#define MINIAUDIO_IMPLEMENTATION
#include "audio/miniaudio.h"
#include "BridgeMain.h"
#include "HostBridge.h"
using namespace network;
using namespace lookups;
#include <cstdio>
#include <cstdarg>
#include <vector>
#include <signal.h>
// ---------------------------------------------------------------------------
// Macros
// ---------------------------------------------------------------------------
#define IS(s) (::strcmp(argv[i], s) == 0)
// ---------------------------------------------------------------------------
// Global Variables
// ---------------------------------------------------------------------------
int g_signal = 0;
std::string g_progExe = std::string(__EXE_NAME__);
std::string g_iniFile = std::string(DEFAULT_CONF_FILE);
std::string g_lockFile = std::string(DEFAULT_LOCK_FILE);
bool g_foreground = false;
bool g_killed = false;
bool g_hideMessages = false;
int g_inputDevice = -1;
int g_outputDevice = -1;
uint8_t* g_gitHashBytes = nullptr;
// ---------------------------------------------------------------------------
// Global Functions
// ---------------------------------------------------------------------------
#if !defined(CATCH2_TEST_COMPILATION)
/* Internal signal handler. */
static void sigHandler(int signum)
{
g_signal = signum;
g_killed = true;
}
#endif
/* Helper to print a fatal error message and exit. */
void fatal(const char* msg, ...)
{
char buffer[400U];
::memset(buffer, 0x20U, 400U);
va_list vl;
va_start(vl, msg);
::vsprintf(buffer, msg, vl);
va_end(vl);
::fprintf(stderr, "%s: %s\n", g_progExe.c_str(), buffer);
exit(EXIT_FAILURE);
}
/* Helper to pring usage the command line arguments. (And optionally an error.) */
void usage(const char* message, const char* arg)
{
::fprintf(stdout, __PROG_NAME__ " %s (built %s)\r\n", __VER__, __BUILD__);
::fprintf(stdout, "Copyright (c) 2017-2024 Bryan Biedenkapp, N2PLL and DVMProject (https://github.com/dvmproject) Authors.\n");
::fprintf(stdout, "Portions Copyright (c) 2015-2021 by Jonathan Naylor, G4KLX and others\n\n");
if (message != nullptr) {
::fprintf(stderr, "%s: ", g_progExe.c_str());
::fprintf(stderr, message, arg);
::fprintf(stderr, "\n\n");
}
::fprintf(stdout,
"usage: %s [-vhf]"
"[-i <input audio device id>]"
"[-o <output audio device id>]"
"[-c <configuration file>]"
"\n\n"
" -v show version information\n"
" -h show this screen\n"
" -f foreground mode\n"
"\n"
" -i input audio device\n"
" -o output audio device\n"
"\n"
" -c <file> specifies the configuration file to use\n"
"\n"
" -- stop handling options\n",
g_progExe.c_str());
ma_context context;
if (ma_context_init(NULL, 0, NULL, &context) != MA_SUCCESS) {
fprintf(stderr, "Failed to initialize audio context.\n");
exit(EXIT_FAILURE);
}
ma_device_info* playbackDevices;
ma_device_info* captureDevices;
ma_uint32 playbackDeviceCount, captureDeviceCount;
ma_result result = ma_context_get_devices(&context, &playbackDevices, &playbackDeviceCount, &captureDevices, &captureDeviceCount);
if (result != MA_SUCCESS) {
fprintf(stderr, "Failed to retrieve audio device information.\n");
exit(EXIT_FAILURE);
}
fprintf(stdout, "\nAudio Input Devices:\n");
for (uint32_t i = 0; i < captureDeviceCount; ++i) {
fprintf(stdout, " %u: %s\n", i, captureDevices[i].name);
}
fprintf(stdout, "\n");
fprintf(stdout, "Audio Output Devices:\n");
for (uint32_t i = 0; i < playbackDeviceCount; ++i) {
fprintf(stdout, " %u: %s\n", i, playbackDevices[i].name);
}
ma_context_uninit(&context);
exit(EXIT_FAILURE);
}
/* Helper to validate the command line arguments. */
int checkArgs(int argc, char* argv[])
{
int i, p = 0;
// iterate through arguments
for (i = 1; i <= argc; i++)
{
if (argv[i] == nullptr) {
break;
}
if (*argv[i] != '-') {
continue;
}
else if (IS("--")) {
++p;
break;
}
else if (IS("-f")) {
g_foreground = true;
}
else if (IS("-i")) {
if ((argc - 1) <= 0)
usage("error: %s", "must specify the input audio device to use");
g_inputDevice = ::atoi(argv[++i]);
p += 2;
}
else if (IS("-o")) {
if ((argc - 1) <= 0)
usage("error: %s", "must specify the output audio device to use");
g_outputDevice = ::atoi(argv[++i]);
p += 2;
}
else if (IS("-c")) {
if (argc-- <= 0)
usage("error: %s", "must specify the configuration file to use");
g_iniFile = std::string(argv[++i]);
if (g_iniFile.empty())
usage("error: %s", "configuration file cannot be blank!");
p += 2;
}
else if (IS("-v")) {
::fprintf(stdout, __PROG_NAME__ " %s (built %s)\r\n", __VER__, __BUILD__);
::fprintf(stdout, "Copyright (c) 2017-2024 Bryan Biedenkapp, N2PLL and DVMProject (https://github.com/dvmproject) Authors.\n");
::fprintf(stdout, "Portions Copyright (c) 2015-2021 by Jonathan Naylor, G4KLX and others\n\n");
if (argc == 2)
exit(EXIT_SUCCESS);
}
else if (IS("-h")) {
usage(nullptr, nullptr);
if (argc == 2)
exit(EXIT_SUCCESS);
}
else {
usage("unrecognized option `%s'", argv[i]);
}
}
if (p < 0 || p > argc) {
p = 0;
}
return ++p;
}
// ---------------------------------------------------------------------------
// Program Entry Point
// ---------------------------------------------------------------------------
#if !defined(CATCH2_TEST_COMPILATION)
int main(int argc, char** argv)
{
g_gitHashBytes = new uint8_t[4U];
::memset(g_gitHashBytes, 0x00U, 4U);
uint32_t hash = ::strtoul(__GIT_VER_HASH__, 0, 16);
__SET_UINT32(hash, g_gitHashBytes, 0U);
if (argv[0] != nullptr && *argv[0] != 0)
g_progExe = std::string(argv[0]);
if (argc > 1) {
// check arguments
int i = checkArgs(argc, argv);
if (i < argc) {
argc -= i;
argv += i;
}
else {
argc--;
argv++;
}
}
::signal(SIGINT, sigHandler);
::signal(SIGTERM, sigHandler);
#if !defined(_WIN32)
::signal(SIGHUP, sigHandler);
#endif // !defined(_WIN32)
int ret = 0;
do {
g_signal = 0;
g_killed = false;
HostBridge*bridge = new HostBridge(g_iniFile);
ret = bridge->run();
delete bridge;
if (g_signal == 2)
::LogInfoEx(LOG_HOST, "Exited on receipt of SIGINT");
if (g_signal == 15)
::LogInfoEx(LOG_HOST, "Exited on receipt of SIGTERM");
if (g_signal == 1)
::LogInfoEx(LOG_HOST, "Restarting on receipt of SIGHUP");
} while (g_signal == 1);
::LogFinalise();
::ActivityLogFinalise();
return ret;
}
#endif

@ -0,0 +1,58 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Digital Voice Modem - Bridge
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright (C) 2024 Bryan Biedenkapp, N2PLL
*
*/
/**
* @file BridgeMain.h
* @ingroup bridge
* @file BridgeMain.cpp
* @ingroup bridge
*/
#if !defined(__BRIDGE_MAIN_H__)
#define __BRIDGE_MAIN_H__
#include "Defines.h"
#include <string>
// ---------------------------------------------------------------------------
// Externs
// ---------------------------------------------------------------------------
/** @brief */
extern int g_signal;
/** @brief */
extern std::string g_progExe;
/** @brief */
extern std::string g_iniFile;
/** @brief */
extern std::string g_lockFile;
/** @brief (Global) Flag indicating foreground operation. */
extern bool g_foreground;
/** @brief (Global) Flag indicating the FNE should stop immediately. */
extern bool g_killed;
/** @brief Audio Input Device Index. */
extern int g_inputDevice;
/** @brief Audio Output Device Index. */
extern int g_outputDevice;
extern uint8_t* g_gitHashBytes;
/**
* @brief Helper to trigger a fatal error message. This will cause the program to terminate
* immediately with an error message.
*
* @param msg String format.
*
* This is a variable argument function.
*/
extern HOST_SW_API void fatal(const char* msg, ...);
#endif // __BRIDGE_MAIN_H__

@ -0,0 +1,24 @@
# SPDX-License-Identifier: GPL-2.0-only
#/*
# * Digital Voice Modem - Bridge
# * GPLv2 Open Source. Use is subject to license terms.
# * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
# *
# * Copyright (C) 2024 Bryan Biedenkapp, N2PLL
# *
# */
file(GLOB bridge_SRC
"src/host/network/Network.h"
"src/host/network/Network.cpp"
"src/bridge/audio/*.h"
"src/bridge/audio/*.c"
"src/bridge/mdc/*.h"
"src/bridge/mdc/*.c"
"src/bridge/network/*.h"
"src/bridge/network/*.cpp"
"src/bridge/*.h"
"src/bridge/*.cpp"
)

@ -0,0 +1,41 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Digital Voice Modem - Bridge
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright (C) 2024 Bryan Biedenkapp, N2PLL
*
*/
/**
* @defgroup bridge Bridge
* @brief Digital Voice Modem - Bridge
* @details Analog audio bridge, this provides facilities to convert analog audio into digital audio.
* @ingroup bridge
*
* @file Defines.h
* @ingroup bridge
*/
#if !defined(__DEFINES_H__)
#define __DEFINES_H__
#include "common/Defines.h"
// ---------------------------------------------------------------------------
// Constants
// ---------------------------------------------------------------------------
#undef __PROG_NAME__
#define __PROG_NAME__ "Digital Voice Modem (DVM) Bridge"
#undef __EXE_NAME__
#define __EXE_NAME__ "bridge"
#undef __NETVER__
#define __NETVER__ "BRIDGE_R" VERSION_MAJOR VERSION_REV VERSION_MINOR
#undef DEFAULT_CONF_FILE
#define DEFAULT_CONF_FILE "bridge-config.yml"
#undef DEFAULT_LOCK_FILE
#define DEFAULT_LOCK_FILE "/tmp/dvmbridge.lock"
#endif // __DEFINES_H__

File diff suppressed because it is too large Load Diff

@ -0,0 +1,435 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Digital Voice Modem - Bridge
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright (C) 2024 Bryan Biedenkapp, N2PLL
*
*/
/**
* @file HostBridge.h
* @ingroup bridge
* @file HostBridge.cpp
* @ingroup bridge
*/
#if !defined(__HOST_BRIDGE_H__)
#define __HOST_BRIDGE_H__
#include "Defines.h"
#include "common/dmr/data/EmbeddedData.h"
#include "common/dmr/lc/LC.h"
#include "common/dmr/lc/PrivacyLC.h"
#include "common/network/udp/Socket.h"
#include "common/yaml/Yaml.h"
#include "common/RingBuffer.h"
#include "common/Timer.h"
#include "vocoder/MBEDecoder.h"
#include "vocoder/MBEEncoder.h"
#define MINIAUDIO_IMPLEMENTATION
#include "audio/miniaudio.h"
#include "mdc/mdc_decode.h"
#include "network/PeerNetwork.h"
#include <string>
#include <unordered_map>
#include <vector>
#include <mutex>
#if defined(_WIN32)
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#else
#include <pthread.h>
#endif // defined(_WIN32)
// ---------------------------------------------------------------------------
// Constants
// ---------------------------------------------------------------------------
#define MBE_SAMPLES_LENGTH 160
#define NO_BIT_STEAL 0
#define ECMODE_NOISE_SUPPRESS 0x40
#define ECMODE_AGC 0x2000
#define DECSTATE_SIZE 2048
#define ENCSTATE_SIZE 6144
const uint8_t FULL_RATE_MODE = 0x00U;
const uint8_t HALF_RATE_MODE = 0x01U;
const uint8_t TX_MODE_DMR = 1U;
const uint8_t TX_MODE_P25 = 2U;
// ---------------------------------------------------------------------------
// Global Functions
// ---------------------------------------------------------------------------
/**
* @brief Helper callback, called when audio data is available.
* @param device
* @param output
* @param input
* @param frameCount
*/
void audioCallback(ma_device* device, void* output, const void* input, ma_uint32 frameCount);
/**
* @brief Helper callback, called when MDC packets are detected.
* @param frameCount
* @param op MDC Opcode.
* @param arg MDC Argument.
* @param unitID Unit ID.
* @param extra0 1st extra byte.
* @param extra1 2nd extra byte.
* @param extra2 3rd extra byte.
* @param extra3 4th extra byte.
* @param context
*/
void mdcPacketDetected(int frameCount, mdc_u8_t op, mdc_u8_t arg, mdc_u16_t unitID,
mdc_u8_t extra0, mdc_u8_t extra1, mdc_u8_t extra2, mdc_u8_t extra3, void* context);
// ---------------------------------------------------------------------------
// Class Declaration
// ---------------------------------------------------------------------------
/**
* @brief This class implements the core service logic.
* @ingroup bridge
*/
class HOST_SW_API HostBridge {
public:
/**
* @brief Initializes a new instance of the HostBridge class.
* @param confFile Full-path to the configuration file.
*/
HostBridge(const std::string& confFile);
/**
* @brief Finalizes a instance of the HostBridge class.
*/
~HostBridge();
/**
* @brief Executes the main host processing loop.
* @returns int Zero if successful, otherwise error occurred.
*/
int run();
private:
friend void ::audioCallback(ma_device* device, void* output, const void* input, ma_uint32 frameCount);
friend void ::mdcPacketDetected(int frameCount, mdc_u8_t op, mdc_u8_t arg, mdc_u16_t unitID,
mdc_u8_t extra0, mdc_u8_t extra1, mdc_u8_t extra2, mdc_u8_t extra3, void* context);
const std::string& m_confFile;
yaml::Node m_conf;
network::PeerNetwork* m_network;
network::udp::Socket* m_udpAudioSocket;
bool m_udpAudio;
bool m_udpMetadata;
uint16_t m_udpSendPort;
std::string m_udpSendAddress;
uint16_t m_udpReceivePort;
std::string m_udpReceiveAddress;
uint32_t m_srcId;
uint32_t m_srcIdOverride;
bool m_overrideSrcIdFromMDC;
bool m_overrideSrcIdFromUDP;
uint32_t m_dstId;
uint8_t m_slot;
std::string m_identity;
float m_rxAudioGain;
float m_vocoderDecoderAudioGain;
bool m_vocoderDecoderAutoGain;
float m_txAudioGain;
float m_vocoderEncoderAudioGain;
uint8_t m_txMode;
float m_voxSampleLevel;
uint16_t m_dropTimeMS;
Timer m_dropTime;
bool m_detectAnalogMDC1200;
bool m_preambleLeaderTone;
uint16_t m_preambleTone;
uint16_t m_preambleLength;
bool m_grantDemand;
bool m_localAudio;
ma_context m_maContext;
ma_device_info* m_maPlaybackDevices;
ma_device_info* m_maCaptureDevices;
ma_device_config m_maDeviceConfig;
ma_device m_maDevice;
ma_waveform m_maSineWaveform;
ma_waveform_config m_maSineWaveConfig;
RingBuffer<short> m_inputAudio;
RingBuffer<short> m_outputAudio;
vocoder::MBEDecoder* m_decoder;
vocoder::MBEEncoder* m_encoder;
mdc_decoder_t* m_mdcDecoder;
dmr::data::EmbeddedData m_dmrEmbeddedData;
dmr::lc::LC m_rxDMRLC;
dmr::lc::PrivacyLC m_rxDMRPILC;
uint8_t* m_ambeBuffer;
uint32_t m_ambeCount;
uint32_t m_dmrSeqNo;
uint8_t m_dmrN;
p25::lc::LC m_rxP25LC;
uint8_t* m_netLDU1;
uint8_t* m_netLDU2;
uint32_t m_p25SeqNo;
uint8_t m_p25N;
bool m_audioDetect;
bool m_trafficFromUDP;
uint32_t m_udpSrcId;
uint32_t m_udpDstId;
bool m_callInProgress;
bool m_ignoreCall;
uint8_t m_callAlgoId;
uint64_t m_rxStartTime;
uint32_t m_rxStreamId;
uint32_t m_txStreamId;
uint8_t m_detectedSampleCnt;
bool m_dumpSampleLevel;
bool m_running;
bool m_debug;
static std::mutex m_audioMutex;
#if defined(_WIN32)
void* m_decoderState;
uint16_t m_dcMode;
void* m_encoderState;
uint16_t m_ecMode;
HINSTANCE m_ambeDLL;
bool m_useExternalVocoder;
int m_frameLengthInBits;
int m_frameLengthInBytes;
typedef void(__cdecl* Tambe_init_dec)(void* state, short mode);
/**
* @brief Initialize the AMBE decoder.
* @param[out] state Buffer containing the decoder state to initialize.
* @param mode AMBE mode; FULL (0) or HALF (1).
*/
Tambe_init_dec ambe_init_dec;
typedef short(__cdecl* Tambe_get_dec_mode)(void* state);
/**
* @brief Get the current operating state of the AMBE decoder.
* @param[out] state Buffer containing the decoder state.
* @returns short Operational mode.
*/
Tambe_get_dec_mode ambe_get_dec_mode;
typedef uint32_t(__cdecl* Tambe_voice_dec)(short* samples, short sampleLength, short* packedCodeword, short bitSteal, uint16_t cmode, short n, void* state);
/**
* @brief Decode AMBE codeword into PCM samples.
* @param[out] samples Audio Output (in short samples)
* @param[in] sampleLength Length of sample buffer.
* @param[in] packedCodeword AMBE codewords.
* @param[in] bitSteal
* @param[in] cmode
* @param[in] n
* @param[in] state Buffer containing the decoder state.
* @returns uint32_t
*/
Tambe_voice_dec ambe_voice_dec;
typedef void(__cdecl* Tambe_init_enc)(void* state, short mode, short initialize);
/**
* @brief Initialize the AMBE decoder.
* @param[out] state Buffer containing the ebncoder state to initialize.
* @param mode AMBE mode; FULL (0) or HALF (1).
* @param initialize Flag to initialize encoder state fully, 1 to initialize, 0 to not.
*/
Tambe_init_enc ambe_init_enc;
typedef short(__cdecl* Tambe_get_enc_mode)(void* state);
/**
* @brief Get the current operating state of the AMBE encoder.
* @param[out] state Buffer containing the decoder state.
* @returns short Operational mode.
*/
Tambe_get_enc_mode ambe_get_enc_mode;
typedef uint32_t(__cdecl* Tambe_voice_enc)(short* packedCodeword, short bitSteal, short* samples, short sampleLength, uint16_t cmode, short n, short, void* state);
/**
* @brief Decode AMBE codeword into PCM samples.
* @param[out] packedCodeword AMBE codewords.
* @param[in] bitSteal
* @param[in] samples Audio Output (in short samples)
* @param[in] sampleLength Length of sample buffer.
* @param[in] cmode
* @param[in] n
* @param[in]
* @param[in] state Buffer containing the decoder state.
* @returns uint32_t
*/
Tambe_voice_enc ambe_voice_enc;
/**
* @brief Helper to initialize the use of the external AMBE.DLL binary for DVSI USB-3000.
*/
void initializeAMBEDLL();
/**
* @brief Helper to unpack the codeword bytes into codeword bits for use with the AMBE decoder.
* @param[out] codewordBits Codeword bits.
* @param[in] codeword Codeword bytes.
* @param lengthInBytes Length of codeword in bytes.
* @param lengthBits Length of codeword in bits.
*/
void unpackBytesToBits(short* codewordBits, const uint8_t* codeword, int lengthBytes, int lengthBits);
/**
* @brief Helper to unpack the codeword bytes into codeword bits for use with the AMBE decoder.
* @param[out] codewordBits Codeword bits.
* @param[in] codeword Codeword bytes.
* @param lengthInBytes Length of codeword in bytes.
* @param lengthBits Length of codeword in bits.
*/
void unpackBytesToBits(uint8_t* codewordBits, const uint8_t* codeword, int lengthBytes, int lengthBits);
/**
* @brief Decodes the given MBE codewords to PCM samples using the decoder mode.
* @param[in] codeword
* @param codewordLength
* @param[out] samples
* @returns int
*/
int ambeDecode(const uint8_t* codeword, uint32_t codewordLength, short* samples);
/**
* @brief Helper to pack the codeword bits into codeword bytes for use with the AMBE encoder.
* @param[in] codewordBits Codeword bits.
* @param[out] codeword Codeword bytes.
* @param lengthInBytes Length of codeword in bytes.
* @param lengthBits Length of codeword in bits.
*/
void packBitsToBytes(const short* codewordBits, uint8_t* codeword, int lengthBytes, int lengthBits);
/**
* @brief Helper to pack the codeword bits into codeword bytes for use with the AMBE encoder.
* @param[in] codewordBits Codeword bits.
* @param[out] codeword Codeword bytes.
* @param lengthInBytes Length of codeword in bytes.
* @param lengthBits Length of codeword in bits.
*/
void packBitsToBytes(const uint8_t* codewordBits, uint8_t* codeword, int lengthBytes, int lengthBits);
/**
* @brief Encodes the given PCM samples using the encoder mode to MBE codewords.
* @param[in] samples
* @param sampleLength
* @param[out] codeword
* @returns int
*/
void ambeEncode(const short* samples, uint32_t sampleLength, uint8_t* codeword);
#endif // defined(_WIN32)
/**
* @brief Reads basic configuration parameters from the INI.
* @returns bool True, if configuration was read successfully, otherwise false.
*/
bool readParams();
/**
* @brief Initializes network connectivity.
* @returns bool True, if network connectivity was initialized, otherwise false.
*/
bool createNetwork();
/**
* @brief Helper to process UDP audio.
*/
void processUDPAudio();
/**
* @brief Helper to process DMR network traffic.
* @param buffer
* @param length
*/
void processDMRNetwork(uint8_t* buffer, uint32_t length);
/**
* @brief Helper to decode DMR network traffic audio frames.
* @param ambe
* @param srcId
* @param dstId
* @param dmrN
*/
void decodeDMRAudioFrame(uint8_t* ambe, uint32_t srcId, uint32_t dstId, uint8_t dmrN);
/**
* @brief Helper to encode DMR network traffic audio frames.
* @param pcm
* @param forcedSrcId
* @param forcedDstId
*/
void encodeDMRAudioFrame(uint8_t* pcm, uint32_t forcedSrcId = 0U, uint32_t forcedDstId = 0U);
/**
* @brief Helper to process P25 network traffic.
* @param buffer
* @param length
*/
void processP25Network(uint8_t* buffer, uint32_t length);
/**
* @brief Helper to decode P25 network traffic audio frames.
* @param ldu
* @param srcId
* @param dstId
* @param p25N
*/
void decodeP25AudioFrame(uint8_t* ldu, uint32_t srcId, uint32_t dstId, uint8_t p25N);
/**
* @brief Helper to encode P25 network traffic audio frames.
* @param pcm
* @param forcedSrcId
* @param forcedDstId
*/
void encodeP25AudioFrame(uint8_t* pcm, uint32_t forcedSrcId = 0U, uint32_t forcedDstId = 0U);
/**
* @brief Helper to generate the preamble tone.
*/
void generatePreambleTone();
/**
* @brief Entry point to audio processing thread.
* @param arg Instance of the thread_t structure.
* @returns void* (Ignore)
*/
static void* threadAudioProcess(void* arg);
/**
* @brief Entry point to network processing thread.
* @param arg Instance of the thread_t structure.
* @returns void* (Ignore)
*/
static void* threadNetworkProcess(void* arg);
/**
* @brief Entry point to call lockup handler thread.
* @param arg Instance of the thread_t structure.
* @returns void* (Ignore)
*/
static void* threadCallLockup(void* arg);
};
#endif // __HOST_BRIDGE_H__

@ -0,0 +1,54 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Digital Voice Modem - Bridge
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright (C) 2024 Bryan Biedenkapp, N2PLL
*
*/
/**
* @file SampleTimeConversion.h
* @ingroup bridge
*/
#if !defined(__SAMPLE_TIME_CONVERSION_H__)
#define __SAMPLE_TIME_CONVERSION_H__
#include "Defines.h"
// ---------------------------------------------------------------------------
// Class Declaration
// ---------------------------------------------------------------------------
/**
* @brief
* @ingroup bridge
*/
class HOST_SW_API SampleTimeConvert {
public:
/**
* @brief (ms) to sample count conversion
* @param sampleRate Sample rate.
* @param channels Number of audio channels.
* @param ms Number of milliseconds.
* @returns int Number of samples.
*/
static int ToSamples(uint32_t sampleRate, uint8_t channels, int ms)
{
return (int)(((long)ms) * sampleRate * channels / 1000);
}
/**
* @brief Sample count to (ms) conversion
* @param sampleRate Sample rate.
* @param channels Number of audio channels.
* @param samples Number of samples.
* @returns int Number of milliseconds.
*/
static int ToMS(uint32_t sampleRate, uint8_t channels, int samples)
{
return (int)(((float)samples / (float)sampleRate / (float)channels) * 1000);
}
};
#endif // __SAMPLE_TIME_CONVERSION_H__

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -0,0 +1,88 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Digital Voice Modem - Bridge
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
*/
/*-
* mdc_common.c
* Author: Matthew Kaufman (matthew@eeph.com)
*
* Copyright (c) 2011 Matthew Kaufman All rights reserved.
*
* This file is part of Matthew Kaufman's MDC Encoder/Decoder Library
*
* The MDC Encoder/Decoder Library is free software; you can
* redistribute it and/or modify it under the terms of version 2 of
* the GNU General Public License as published by the Free Software
* Foundation.
*
* If you cannot comply with the terms of this license, contact
* the author for alternative license arrangements or do not use
* or redistribute this software.
*
* The MDC Encoder/Decoder Library 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 software; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
* USA.
*
* or see http://www.gnu.org/copyleft/gpl.html
*
-*/
#include "mdc/mdc_types.h"
// ---------------------------------------------------------------------------
// Global Functions
// ---------------------------------------------------------------------------
/* */
mdc_u16_t _flip(mdc_u16_t crc, mdc_int_t bitnum)
{
mdc_u16_t crcout, j;
j = 1;
crcout = 0;
for (mdc_u16_t i = 1 << (bitnum - 1); i; i >>= 1) {
if (crc & i)
crcout |= j;
j <<= 1;
}
return crcout;
}
/* */
mdc_u16_t _docrc(mdc_u8_t *p, int len)
{
mdc_int_t bit;
mdc_u16_t crc = 0x0000;
for (mdc_int_t i = 0; i < len; i++) {
mdc_u16_t c = (mdc_u16_t)*p++;
c = _flip(c, 8);
for (mdc_int_t j = 0x80; j; j >>= 1) {
bit = crc & 0x8000;
crc <<= 1;
if (c & j)
bit ^= 0x8000;
if (bit)
crc ^= 0x1021;
}
}
crc = _flip(crc, 16);
crc ^= 0xffff;
crc &= 0xFFFF;
return crc;
}

@ -0,0 +1,507 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Digital Voice Modem - Bridge
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
*/
/*-
* mdc_decode.c
* Decodes a specific format of 1200 BPS XOR-precoded MSK data burst
* from input audio samples.
*
* Author: Matthew Kaufman (matthew@eeph.com)
*
* Copyright (c) 2005, 2010 Matthew Kaufman All rights reserved.
*
* This file is part of Matthew Kaufman's MDC Encoder/Decoder Library
*
* The MDC Encoder/Decoder Library is free software; you can
* redistribute it and/or modify it under the terms of version 2 of
* the GNU General Public License as published by the Free Software
* Foundation.
*
* If you cannot comply with the terms of this license, contact
* the author for alternative license arrangements or do not use
* or redistribute this software.
*
* The MDC Encoder/Decoder Library 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 software; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
* USA.
*
* or see http://www.gnu.org/copyleft/gpl.html
*
-*/
#include <stdlib.h>
#include "mdc_decode.h"
// ---------------------------------------------------------------------------
// Global Functions
// ---------------------------------------------------------------------------
/* Create a new mdc_decoder object. */
mdc_decoder_t* mdc_decoder_new(int sampleRate)
{
mdc_decoder_t* decoder;
decoder = (mdc_decoder_t*)malloc(sizeof(mdc_decoder_t));
if(!decoder)
return (mdc_decoder_t*)0L;
if (sampleRate == 8000) {
decoder->incru = 644245094;
}
else if (sampleRate == 16000) {
decoder->incru = 322122547;
}
else if (sampleRate == 22050) {
decoder->incru = 233739716;
}
else if (sampleRate == 32000) {
decoder->incru = 161061274;
}
else if (sampleRate == 44100) {
decoder->incru = 116869858;
}
else if (sampleRate == 48000) {
decoder->incru = 107374182;
}
else {
// WARNING: lower precision than above
decoder->incru = 1200 * 2 * (0x80000000 / sampleRate);
}
decoder->good = 0;
decoder->indouble = 0;
decoder->level = 0;
for(mdc_int_t i = 0; i < MDC_ND; i++)
{
decoder->du[i].thu = i * 2 * (0x80000000 / MDC_ND);
decoder->du[i].xorb = 0;
decoder->du[i].invert = 0;
decoder->du[i].shstate = -1;
decoder->du[i].shcount = 0;
#ifdef MDC_FOURPOINT
decoder->du[i].nlstep = i;
#endif
}
decoder->callback = (mdc_decoder_callback_t)0L;
return decoder;
}
/* */
static void _clearbits(mdc_decoder_t* decoder, mdc_int_t x)
{
for (mdc_int_t i = 0; i < 112; i++)
decoder->du[x].bits[i] = 0;
}
#ifdef MDC_ECC
/* */
static void _gofix(mdc_u8_t *data)
{
int csr[7];
int fixi, fixj;
int syn = 0;
for(int i = 0; i < 7; i++)
csr[i] = 0;
for (int i = 0; i < 7; i++)
{
for (int j = 0; j <= 7; j++)
{
for (int k = 6; k > 0; k--)
csr[k] = csr[k-1];
csr[0] = (data[i] >> j) & 0x01;
int b = csr[0] + csr[2] + csr[5] + csr[6];
syn <<= 1;
if ((b & 0x01) ^ ((data[i+7] >> j) & 0x01)) {
syn |= 1;
}
int ec = 0;
if (syn & 0x80) ++ec;
if (syn & 0x20) ++ec;
if (syn & 0x04) ++ec;
if (syn & 0x02) ++ec;
if (ec >= 3) {
syn ^= 0xa6;
fixi = i;
fixj = j-7;
if(fixj < 0) {
--fixi;
fixj += 8;
}
if (fixi >= 0)
data[fixi] ^= 1 << fixj; // flip
}
}
}
}
#endif
/* */
static void _procbits(mdc_decoder_t* decoder, int x)
{
mdc_int_t lbits[112];
mdc_int_t lbc = 0;
mdc_u8_t data[14];
mdc_u16_t ccrc;
mdc_u16_t rcrc;
for (mdc_int_t i = 0; i < 16; i++) {
for (mdc_int_t j = 0; j < 7; j++) {
mdc_int_t k = (j * 16) + i;
lbits[lbc] = decoder->du[x].bits[k];
++lbc;
}
}
for (mdc_int_t i = 0; i < 14; i++) {
data[i] = 0;
for (mdc_int_t j = 0; j < 8; j++) {
mdc_int_t k = (i * 8) + j;
if (lbits[k])
data[i] |= 1<<j;
}
}
#ifdef MDC_ECC
_gofix(data);
#endif
ccrc = _docrc(data, 4);
rcrc = data[5] << 8 | data[4];
if (ccrc == rcrc) {
if (decoder->du[x].shstate == 2) {
decoder->extra0 = data[0];
decoder->extra1 = data[1];
decoder->extra2 = data[2];
decoder->extra3 = data[3];
for(mdc_int_t k = 0; k < MDC_ND; k++)
decoder->du[k].shstate = -1;
decoder->good = 2;
decoder->indouble = 0;
}
else {
if (!decoder->indouble) {
decoder->good = 1;
decoder->op = data[0];
decoder->arg = data[1];
decoder->unitID = (data[2] << 8) | data[3];
switch (data[0])
{
/* list of opcode that mean 'double packet' */
case OP_DOUBLE_PACKET_TYPE1:
case OP_DOUBLE_PACKET_TYPE2:
decoder->good = 0;
decoder->indouble = 1;
decoder->du[x].shstate = 2;
decoder->du[x].shcount = 0;
_clearbits(decoder, x);
break;
default:
for (mdc_int_t k = 0; k < MDC_ND; k++)
decoder->du[k].shstate = -1; // only in the single-packet case, double keeps rest going
break;
}
}
else {
// any subsequent good decoder allowed to attempt second half
decoder->du[x].shstate = 2;
decoder->du[x].shcount = 0;
_clearbits(decoder, x);
}
}
}
else {
decoder->du[x].shstate = -1;
}
if (decoder->good) {
if (decoder->callback) {
(decoder->callback)((int)decoder->good, (mdc_u8_t)decoder->op, (mdc_u8_t)decoder->arg, (mdc_u16_t)decoder->unitID,
(mdc_u8_t)decoder->extra0, (mdc_u8_t)decoder->extra1, (mdc_u8_t)decoder->extra2, (mdc_u8_t)decoder->extra3,
decoder->callback_context);
decoder->good = 0;
}
}
}
/* */
static int _onebits(mdc_u32_t n)
{
int i = 0;
while(n) {
++i;
n &= (n-1);
}
return i;
}
/* */
static void _shiftin(mdc_decoder_t* decoder, int x)
{
int bit = decoder->du[x].xorb;
int gcount;
switch (decoder->du[x].shstate)
{
case -1:
decoder->du[x].synchigh = 0;
decoder->du[x].synclow = 0;
decoder->du[x].shstate = 0;
// deliberately fall through
case 0:
decoder->du[x].synchigh <<= 1;
if (decoder->du[x].synclow & 0x80000000)
decoder->du[x].synchigh |= 1;
decoder->du[x].synclow <<= 1;
if (bit)
decoder->du[x].synclow |= 1;
gcount = _onebits(0x000000ff & (0x00000007 ^ decoder->du[x].synchigh));
gcount += _onebits(0x092a446f ^ decoder->du[x].synclow);
if (gcount <= MDC_GDTHRESH) {
decoder->du[x].shstate = 1;
decoder->du[x].shcount = 0;
_clearbits(decoder, x);
}
else if (gcount >= (40 - MDC_GDTHRESH)) {
decoder->du[x].shstate = 1;
decoder->du[x].shcount = 0;
decoder->du[x].xorb = !(decoder->du[x].xorb);
decoder->du[x].invert = !(decoder->du[x].invert);
_clearbits(decoder, x);
}
return;
case 1:
case 2:
decoder->du[x].bits[decoder->du[x].shcount] = bit;
decoder->du[x].shcount++;
if (decoder->du[x].shcount > 111) {
_procbits(decoder, x);
}
return;
default:
return;
}
}
#ifdef MDC_FOURPOINT
/* */
static void _nlproc(mdc_decoder_t* decoder, int x)
{
mdc_float_t vnow;
mdc_float_t vpast;
switch (decoder->du[x].nlstep)
{
case 3:
vnow = ((-0.60 * decoder->du[x].nlevel[3]) + (.97 * decoder->du[x].nlevel[1]));
vpast = ((-0.60 * decoder->du[x].nlevel[7]) + (.97 * decoder->du[x].nlevel[9]));
break;
case 8:
vnow = ((-0.60 * decoder->du[x].nlevel[8]) + (.97 * decoder->du[x].nlevel[6]));
vpast = ((-0.60 * decoder->du[x].nlevel[2]) + (.97 * decoder->du[x].nlevel[4]));
break;
default:
return;
}
decoder->du[x].xorb = (vnow > vpast) ? 1 : 0;
if (decoder->du[x].invert)
decoder->du[x].xorb = !(decoder->du[x].xorb);
_shiftin(decoder, x);
}
#endif
/* Process incoming samples using an mdc_decoder object. */
int mdc_decoder_process_samples(mdc_decoder_t* decoder, mdc_sample_t* samples, int numSamples)
{
mdc_sample_t sample;
#ifndef MDC_FIXEDMATH
mdc_float_t value;
#else
mdc_int_t value;
#endif
if (!decoder)
return -1;
for (mdc_int_t i = 0; i < numSamples; i++) {
sample = samples[i];
#ifdef MDC_FIXEDMATH
#if defined(MDC_SAMPLE_FORMAT_U8)
value = ((mdc_int_t)sample) - 127;
#elif defined(MDC_SAMPLE_FORMAT_U16)
value = ((mdc_int_t)sample) - 32767;
#elif defined(MDC_SAMPLE_FORMAT_S16)
value = (mdc_int_t) sample;
#elif defined(MDC_SAMPLE_FORMAT_FLOAT)
#error "fixed-point math not allowed with float sample format"
#else
#error "no known sample format set"
#endif // sample format
#endif // is MDC_FIXEDMATH
#ifndef MDC_FIXEDMATH
#if defined(MDC_SAMPLE_FORMAT_U8)
value = (((mdc_float_t)sample) - 128.0)/256;
#elif defined(MDC_SAMPLE_FORMAT_U16)
value = (((mdc_float_t)sample) - 32768.0)/65536.0;
#elif defined(MDC_SAMPLE_FORMAT_S16)
value = ((mdc_float_t)sample) / 65536.0;
#elif defined(MDC_SAMPLE_FORMAT_FLOAT)
value = sample;
#else
#error "no known sample format set"
#endif // sample format
#endif // not MDC_FIXEDMATH
#if defined(MDC_ONEPOINT)
for (mdc_int_t j = 0; j < MDC_ND; j++) {
mdc_u32_t lthu = decoder->du[j].thu;
decoder->du[j].thu += decoder->incru;
// wrapped
if (decoder->du[j].thu < lthu) {
if (value > 0)
decoder->du[j].xorb = 1;
else
decoder->du[j].xorb = 0;
if (decoder->du[j].invert)
decoder->du[j].xorb = !(decoder->du[j].xorb);
_shiftin(decoder, j);
}
}
#elif defined(MDC_FOURPOINT)
#ifdef MDC_FIXEDMATH
#error "fixed-point math not allowed for fourpoint strategy"
#endif
for (mdc_int_t j = 0; j < MDC_ND; j++)
{
//decoder->du[j].th += (5.0 * decoder->incr);
mdc_u32_t lthu = decoder->du[j].thu;
decoder->du[j].thu += 5 * decoder->incru;
// if (decoder->du[j].th >= TWOPI)
// wrapped
if (decoder->du[j].thu < lthu) {
decoder->du[j].nlstep++;
if(decoder->du[j].nlstep > 9)
decoder->du[j].nlstep = 0;
decoder->du[j].nlevel[decoder->du[j].nlstep] = value;
_nlproc(decoder, j);
//decoder->du[j].th -= TWOPI;
}
}
#else
#error "no decode strategy chosen"
#endif
}
if (decoder->good)
return decoder->good;
return 0;
}
/* Retrieve last successfully decoded data packet from decoder object. */
int mdc_decoder_get_packet(mdc_decoder_t* decoder, mdc_u8_t* op, mdc_u8_t* arg, mdc_u16_t* unitID)
{
if (!decoder)
return -1;
if (decoder->good != 1)
return -1;
if (op)
*op = decoder->op;
if (arg)
*arg = decoder->arg;
if (unitID)
*unitID = decoder->unitID;
decoder->good = 0;
return 0;
}
/* Retrieve last successfully decoded double-length packet from decoder object. */
int mdc_decoder_get_double_packet(mdc_decoder_t* decoder, mdc_u8_t* op, mdc_u8_t* arg, mdc_u16_t* unitID,
mdc_u8_t* extra0, mdc_u8_t* extra1, mdc_u8_t* extra2, mdc_u8_t* extra3)
{
if (!decoder)
return -1;
if (decoder->good != 2)
return -1;
if (op)
*op = decoder->op;
if (arg)
*arg = decoder->arg;
if (unitID)
*unitID = decoder->unitID;
if (extra0)
*extra0 = decoder->extra0;
if (extra1)
*extra1 = decoder->extra1;
if (extra2)
*extra2 = decoder->extra2;
if (extra3)
*extra3 = decoder->extra3;
decoder->good = 0;
return 0;
}
/* Set a callback function to be called upon successful decode. */
int mdc_decoder_set_callback(mdc_decoder_t* decoder, mdc_decoder_callback_t callbackFunction, void* context)
{
if (!decoder)
return -1;
decoder->callback = callbackFunction;
decoder->callback_context = context;
return 0;
}

@ -0,0 +1,203 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Digital Voice Modem - Bridge
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
*/
/**
* @file mdc_decode.h
* @ingroup bridge
* @file mdc_decode.c
* @ingroup bridge
*/
/*-
* mdc_decode.h
* header for mdc_decode.c
*
* Author: Matthew Kaufman (matthew@eeph.com)
*
* Copyright (c) 2005, 2010 Matthew Kaufman All rights reserved.
*
* This file is part of Matthew Kaufman's MDC Encoder/Decoder Library
*
* The MDC Encoder/Decoder Library is free software; you can
* redistribute it and/or modify it under the terms of version 2 of
* the GNU General Public License as published by the Free Software
* Foundation.
*
* If you cannot comply with the terms of this license, contact
* the author for alternative license arrangements or do not use
* or redistribute this software.
*
* The MDC Encoder/Decoder Library 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 software; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
* USA.
*
* or see http://www.gnu.org/copyleft/gpl.html
*
-*/
#if !defined(__MDC_DECODE_H__)
#define __MDC_DECODE_H__
// #define MDC_FIXEDMATH // if you want this, define before mdc_types.h
#include "mdc_types.h"
#define MDC_GDTHRESH 5 // "good bits" threshold
#define MDC_ECC
#define MDC_FOURPOINT // recommended 4-point method, requires high sample rates (16000 or higher)
#undef MDC_ONEPOINT // alternative 1-point method
#ifdef MDC_FOURPOINT
#define MDC_ND 5 // recommended for four-point method
#endif
#ifdef MDC_ONEPOINT
#define MDC_ND 4 // recommended for one-point method
#endif
typedef void (*mdc_decoder_callback_t)(int frameCount, // 1 or 2 - if 2 then extra0-3 are valid
mdc_u8_t op, mdc_u8_t arg, mdc_u16_t unitID,
mdc_u8_t extra0, mdc_u8_t extra1, mdc_u8_t extra2, mdc_u8_t extra3,
void *context);
// ---------------------------------------------------------------------------
// Structure Declaration
// ---------------------------------------------------------------------------
/**
* @brief
*/
typedef struct
{
// mdc_float_t th;
mdc_u32_t thu;
// mdc_int_t zc; - deprecated
mdc_int_t xorb;
mdc_int_t invert;
#ifdef MDC_FOURPOINT
#ifdef MDC_FIXEDMATH
#error "fixed-point math not allowed for fourpoint strategy"
#endif // MDC_FIXEDMATH
mdc_int_t nlstep;
mdc_float_t nlevel[10];
#endif // MDC_FOURPOINT
#ifdef PLL
mdc_u32_t plt;
#endif
mdc_u32_t synclow;
mdc_u32_t synchigh;
mdc_int_t shstate;
mdc_int_t shcount;
mdc_int_t bits[112];
} mdc_decode_unit_t;
// ---------------------------------------------------------------------------
// Structure Declaration
// ---------------------------------------------------------------------------
/**
* @brief
*/
typedef struct {
mdc_decode_unit_t du[MDC_ND];
// mdc_float_t hyst;
// mdc_float_t incr;
mdc_u32_t incru;
#ifdef PLL
mdc_u32_t zthu;
mdc_int_t zprev;
mdc_float_t vprev;
#endif
mdc_int_t level;
mdc_int_t good;
mdc_int_t indouble;
mdc_u8_t op;
mdc_u8_t arg;
mdc_u16_t unitID;
mdc_u8_t extra0;
mdc_u8_t extra1;
mdc_u8_t extra2;
mdc_u8_t extra3;
mdc_decoder_callback_t callback;
void *callback_context;
} mdc_decoder_t;
// ---------------------------------------------------------------------------
// Global Functions
// ---------------------------------------------------------------------------
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Create a new mdc_decoder object.
* @param sampleRate The sampling rate in Hz.
* @returns mdc_decoder_t* An mdc_decoder object or null if failure.
*/
mdc_decoder_t* mdc_decoder_new(int sampleRate);
/**
* @brief Process incoming samples using an mdc_decoder object.
* @param[in] decoder Instance of the mdc_decoder object.
* @param[out] samples Samples (in format set in mdc_types.h).
* @param[out] numSamples Count of the number of samples in buffer.
* @returns int 0 if more samples are needed
* -1 if an error occurs
* 1 if a decoded single packet is available to read (if no callback set)
* 2 if a decoded double packet is available to read (if no callback set)
*/
int mdc_decoder_process_samples(mdc_decoder_t* decoder, mdc_sample_t* samples, int numSamples);
/**
* @brief Retrieve last successfully decoded data packet from decoder object.
* @param[in] decoder Instance of the mdc_decoder object.
* @param[out] op MDC Opcode.
* @param[out] arg MDC Argument.
* @param[out] unitID Unit ID.
* @returns int -1 for error, 0 otherwise
*/
int mdc_decoder_get_packet(mdc_decoder_t* decoder, mdc_u8_t* op, mdc_u8_t* arg, mdc_u16_t* unitID);
/**
* @brief Retrieve last successfully decoded double-length packet from decoder object.
* @param[in] decoder Instance of the mdc_decoder object.
* @param[out] op MDC Opcode.
* @param[out] arg MDC Argument.
* @param[out] unitID Unit ID.
* @param[out] extra0 1st extra byte.
* @param[out] extra1 2nd extra byte.
* @param[out] extra2 3rd extra byte.
* @param[out] extra3 4th extra byte.
* @returns int -1 for error, 0 otherwise
*/
int mdc_decoder_get_double_packet(mdc_decoder_t* decoder, mdc_u8_t* op, mdc_u8_t* arg, mdc_u16_t* unitID,
mdc_u8_t* extra0, mdc_u8_t* extra1, mdc_u8_t* extra2, mdc_u8_t* extra3);
/**
* @brief Set a callback function to be called upon successful decode
* if this is set, the functions mdc_decoder_get_packet and mdc_decoder_get_double_packet
* will no longer be functional, instead the callback function is called immediately when
* a successful decode happens (from within the context of mdc_decoder_process_samples).
* @param[in] decoder Instance of the mdc_decoder object.
* @param callbackFunction
* @param context
* @returns int -1 for error, 0 otherwise
*/
int mdc_decoder_set_callback(mdc_decoder_t* decoder, mdc_decoder_callback_t callbackFunction, void* context);
#ifdef __cplusplus
}
#endif
#endif // __MDC_DECODE_H__

@ -0,0 +1,574 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Digital Voice Modem - Bridge
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
*/
/*-
* mdc_encode.c
* Encodes a specific format from 1200 BPS MSK data burst
* to output audio samples.
*
* 9 October 2010 - typedefs for easier porting
* 27 July 2016 - additional reduced-amplitude sin tables
*
* Author: Matthew Kaufman (matthew@eeph.com)
*
* Copyright (c) 2005, 2010 Matthew Kaufman All rights reserved.
*
* This file is part of Matthew Kaufman's MDC Encoder/Decoder Library
*
* The MDC Encoder/Decoder Library is free software; you can
* redistribute it and/or modify it under the terms of version 2 of
* the GNU General Public License as published by the Free Software
* Foundation.
*
* If you cannot comply with the terms of this license, contact
* the author for alternative license arrangements or do not use
* or redistribute this software.
*
* The MDC Encoder/Decoder Library 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 software; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
* USA.
*
* or see http://www.gnu.org/copyleft/gpl.html
*
-*/
#include <stdlib.h>
#include "mdc_encode.h"
#if defined(MDC_SAMPLE_FORMAT_U8)
#if defined(MDC_ENCODE_FULL_AMPLITUDE)
static mdc_sample_t sintable[] = {
127, 130, 133, 136, 139, 142, 145, 148, 151, 154, 157, 160, 163, 166, 169, 172,
175, 178, 180, 183, 186, 189, 191, 194, 196, 199, 201, 204, 206, 209, 211, 213,
215, 218, 220, 222, 224, 226, 227, 229, 231, 233, 234, 236, 237, 239, 240, 241,
242, 244, 245, 246, 247, 247, 248, 249, 250, 250, 251, 251, 251, 252, 252, 252,
252, 252, 252, 252, 251, 251, 251, 250, 250, 249, 248, 247, 247, 246, 245, 244,
242, 241, 240, 239, 237, 236, 234, 233, 231, 229, 227, 226, 224, 222, 220, 218,
215, 213, 211, 209, 206, 204, 201, 199, 196, 194, 191, 189, 186, 183, 180, 178,
175, 172, 169, 166, 163, 160, 157, 154, 151, 148, 145, 142, 139, 136, 133, 130,
127, 124, 121, 118, 115, 112, 109, 106, 103, 100, 97, 94, 91, 88, 85, 82,
79, 76, 74, 71, 68, 65, 63, 60, 58, 55, 53, 50, 48, 45, 43, 41,
39, 36, 34, 32, 30, 28, 27, 25, 23, 21, 20, 18, 17, 15, 14, 13,
12, 10, 9, 8, 7, 7, 6, 5, 4, 4, 3, 3, 3, 2, 2, 2,
2, 2, 2, 2, 3, 3, 3, 4, 4, 5, 6, 7, 7, 8, 9, 10,
12, 13, 14, 15, 17, 18, 20, 21, 23, 25, 27, 28, 30, 32, 34, 36,
39, 41, 43, 45, 48, 50, 53, 55, 58, 60, 63, 65, 68, 71, 74, 76,
79, 82, 85, 88, 91, 94, 97, 100, 103, 106, 109, 112, 115, 118, 121, 124 };
#else
static mdc_sample_t sintable[] = {
128, 130, 132, 134, 136, 138, 140, 142, 144, 146, 148, 150, 152, 154, 156, 158,
160, 162, 164, 166, 168, 170, 172, 172, 174, 176, 178, 180, 182, 182, 184, 186,
188, 190, 190, 192, 194, 194, 196, 198, 198, 200, 200, 202, 202, 204, 204, 206,
206, 206, 208, 208, 208, 210, 210, 210, 212, 212, 212, 212, 212, 212, 212, 212,
212, 212, 212, 212, 212, 212, 212, 212, 212, 210, 210, 210, 208, 208, 208, 206,
206, 206, 204, 204, 202, 202, 200, 200, 198, 198, 196, 194, 194, 192, 190, 190,
188, 186, 184, 182, 182, 180, 178, 176, 174, 172, 172, 170, 168, 166, 164, 162,
160, 158, 156, 154, 152, 150, 148, 146, 144, 142, 140, 138, 136, 134, 132, 130,
128, 126, 124, 122, 120, 118, 116, 114, 112, 110, 108, 106, 104, 102, 100, 98,
96, 94, 92, 90, 88, 86, 84, 82, 80, 78, 76, 76, 74, 72, 70, 68,
68, 66, 64, 64, 62, 60, 60, 58, 56, 56, 54, 54, 52, 52, 50, 50,
48, 48, 48, 46, 46, 46, 44, 44, 44, 44, 44, 42, 42, 42, 42, 42,
42, 42, 42, 42, 42, 42, 44, 44, 44, 44, 44, 46, 46, 46, 48, 48,
48, 50, 50, 52, 52, 54, 54, 56, 56, 58, 60, 60, 62, 64, 64, 66,
68, 68, 70, 72, 74, 76, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94,
96, 98, 100, 102, 104, 106, 108, 110, 112, 114, 116, 118, 120, 122, 124, 126 };
#endif
#elif defined(MDC_SAMPLE_FORMAT_U16)
#if defined(MDC_ENCODE_FULL_AMPLITUDE)
static mdc_sample_t sintable[] = {
32768, 33552, 34337, 35120, 35902, 36682, 37460, 38235,
39007, 39775, 40538, 41297, 42051, 42799, 43542, 44277,
45006, 45728, 46441, 47147, 47843, 48531, 49209, 49877,
50535, 51182, 51819, 52443, 53056, 53657, 54245, 54820,
55381, 55930, 56464, 56984, 57489, 57980, 58455, 58915,
59359, 59787, 60199, 60594, 60972, 61334, 61678, 62005,
62314, 62606, 62879, 63134, 63371, 63590, 63790, 63971,
64134, 64278, 64402, 64508, 64595, 64662, 64710, 64739,
64749, 64739, 64710, 64662, 64595, 64508, 64402, 64278,
64134, 63971, 63790, 63590, 63371, 63134, 62879, 62606,
62314, 62005, 61678, 61334, 60972, 60594, 60199, 59787,
59359, 58915, 58455, 57980, 57489, 56984, 56464, 55930,
55381, 54820, 54245, 53657, 53056, 52443, 51819, 51182,
50535, 49877, 49209, 48531, 47843, 47147, 46441, 45728,
45006, 44277, 43542, 42799, 42051, 41297, 40538, 39775,
39007, 38235, 37460, 36682, 35902, 35120, 34337, 33552,
32768, 31983, 31198, 30415, 29633, 28853, 28075, 27300,
26528, 25760, 24997, 24238, 23484, 22736, 21993, 21258,
20529, 19807, 19094, 18388, 17692, 17004, 16326, 15658,
15000, 14353, 13716, 13092, 12479, 11878, 11290, 10715,
10154, 9605, 9071, 8551, 8046, 7555, 7080, 6620,
6176, 5748, 5336, 4941, 4563, 4201, 3857, 3530,
3221, 2929, 2656, 2401, 2164, 1945, 1745, 1564,
1401, 1257, 1133, 1027, 940, 873, 825, 796,
787, 796, 825, 873, 940, 1027, 1133, 1257,
1401, 1564, 1745, 1945, 2164, 2401, 2656, 2929,
3221, 3530, 3857, 4201, 4563, 4941, 5336, 5748,
6176, 6620, 7080, 7555, 8046, 8551, 9071, 9605,
10154, 10715, 11290, 11878, 12479, 13092, 13716, 14353,
15000, 15658, 16326, 17004, 17692, 18388, 19094, 19807,
20529, 21258, 21993, 22736, 23484, 24238, 24997, 25760,
26528, 27300, 28075, 28853, 29633, 30415, 31198, 31983 };
#else
static mdc_sample_t sintable[] = {
32768, 33314, 33861, 34407, 34952, 35495, 36037, 36577, 37115, 37650, 38182, 38710, 39236, 39757, 40274, 40787,
41295, 41797, 42294, 42786, 43271, 43750, 44223, 44688, 45147, 45598, 46041, 46476, 46903, 47322, 47731, 48132,
48523, 48905, 49278, 49640, 49992, 50334, 50665, 50985, 51295, 51593, 51880, 52155, 52419, 52671, 52910, 53138,
53354, 53557, 53747, 53925, 54090, 54243, 54382, 54508, 54622, 54722, 54809, 54882, 54942, 54989, 55023, 55043,
55050, 55043, 55023, 54989, 54942, 54882, 54809, 54722, 54622, 54508, 54382, 54243, 54090, 53925, 53747, 53557,
53354, 53138, 52910, 52671, 52419, 52155, 51880, 51593, 51295, 50985, 50665, 50334, 49992, 49640, 49278, 48905,
48523, 48132, 47731, 47322, 46903, 46476, 46041, 45598, 45147, 44688, 44223, 43750, 43271, 42786, 42294, 41797,
41295, 40787, 40274, 39757, 39236, 38710, 38182, 37650, 37115, 36577, 36037, 35495, 34952, 34407, 33861, 33314,
32768, 32222, 31675, 31129, 30584, 30041, 29499, 28959, 28421, 27886, 27354, 26826, 26300, 25779, 25262, 24749,
24241, 23739, 23242, 22750, 22265, 21786, 21313, 20848, 20389, 19938, 19495, 19060, 18633, 18214, 17805, 17404,
17013, 16631, 16258, 15896, 15544, 15202, 14871, 14551, 14241, 13943, 13656, 13381, 13117, 12865, 12626, 12398,
12182, 11979, 11789, 11611, 11446, 11293, 11154, 11028, 10914, 10814, 10727, 10654, 10594, 10547, 10513, 10493,
10486, 10493, 10513, 10547, 10594, 10654, 10727, 10814, 10914, 11028, 11154, 11293, 11446, 11611, 11789, 11979,
12182, 12398, 12626, 12865, 13117, 13381, 13656, 13943, 14241, 14551, 14871, 15202, 15544, 15896, 16258, 16631,
17013, 17404, 17805, 18214, 18633, 19060, 19495, 19938, 20389, 20848, 21313, 21786, 22265, 22750, 23242, 23739,
24241, 24749, 25262, 25779, 26300, 26826, 27354, 27886, 28421, 28959, 29499, 30041, 30584, 31129, 31675, 32222 };
#endif
#elif defined(MDC_SAMPLE_FORMAT_S16)
#if defined(MDC_ENCODE_FULL_AMPLITUDE)
static mdc_sample_t sintable[] = {
0, 784, 1569, 2352, 3134, 3914, 4692, 5467,
6239, 7007, 7770, 8529, 9283, 10031, 10774, 11509,
12238, 12960, 13673, 14379, 15075, 15763, 16441, 17109,
17767, 18414, 19051, 19675, 20288, 20889, 21477, 22052,
22613, 23162, 23696, 24216, 24721, 25212, 25687, 26147,
26591, 27019, 27431, 27826, 28204, 28566, 28910, 29237,
29546, 29838, 30111, 30366, 30603, 30822, 31022, 31203,
31366, 31510, 31634, 31740, 31827, 31894, 31942, 31971,
31981, 31971, 31942, 31894, 31827, 31740, 31634, 31510,
31366, 31203, 31022, 30822, 30603, 30366, 30111, 29838,
29546, 29237, 28910, 28566, 28204, 27826, 27431, 27019,
26591, 26147, 25687, 25212, 24721, 24216, 23696, 23162,
22613, 22052, 21477, 20889, 20288, 19675, 19051, 18414,
17767, 17109, 16441, 15763, 15075, 14379, 13673, 12960,
12238, 11509, 10774, 10031, 9283, 8529, 7770, 7007,
6239, 5467, 4692, 3914, 3134, 2352, 1569, 784,
0, -784, -1569, -2352, -3134, -3914, -4692, -5467,
-6239, -7007, -7770, -8529, -9283, -10031, -10774, -11509,
-12238, -12960, -13673, -14379, -15075, -15763, -16441, -17109,
-17767, -18414, -19051, -19675, -20288, -20889, -21477, -22052,
-22613, -23162, -23696, -24216, -24721, -25212, -25687, -26147,
-26591, -27019, -27431, -27826, -28204, -28566, -28910, -29237,
-29546, -29838, -30111, -30366, -30603, -30822, -31022, -31203,
-31366, -31510, -31634, -31740, -31827, -31894, -31942, -31971,
-31981, -31971, -31942, -31894, -31827, -31740, -31634, -31510,
-31366, -31203, -31022, -30822, -30603, -30366, -30111, -29838,
-29546, -29237, -28910, -28566, -28204, -27826, -27431, -27019,
-26591, -26147, -25687, -25212, -24721, -24216, -23696, -23162,
-22613, -22052, -21477, -20889, -20288, -19675, -19051, -18414,
-17767, -17109, -16441, -15763, -15075, -14379, -13673, -12960,
-12238, -11509, -10774, -10031, -9283, -8529, -7770, -7007,
-6239, -5467, -4692, -3914, -3134, -2352, -1569, -784 };
#else
static mdc_sample_t sintable[] = {
0, 546, 1093, 1639, 2184, 2727, 3269, 3809, 4347, 4882, 5414, 5942, 6468, 6989, 7506, 8019,
8527, 9029, 9526, 10018, 10503, 10982, 11455, 11920, 12379, 12830, 13273, 13708, 14135, 14554, 14963, 15364,
15755, 16137, 16510, 16872, 17224, 17566, 17897, 18217, 18527, 18825, 19112, 19387, 19651, 19903, 20142, 20370,
20586, 20789, 20979, 21157, 21322, 21475, 21614, 21740, 21854, 21954, 22041, 22114, 22174, 22221, 22255, 22275,
22282, 22275, 22255, 22221, 22174, 22114, 22041, 21954, 21854, 21740, 21614, 21475, 21322, 21157, 20979, 20789,
20586, 20370, 20142, 19903, 19651, 19387, 19112, 18825, 18527, 18217, 17897, 17566, 17224, 16872, 16510, 16137,
15755, 15364, 14963, 14554, 14135, 13708, 13273, 12830, 12379, 11920, 11455, 10982, 10503, 10018, 9526, 9029,
8527, 8019, 7506, 6989, 6468, 5942, 5414, 4882, 4347, 3809, 3269, 2727, 2184, 1639, 1093, 546,
0, -546, -1093, -1639, -2184, -2727, -3269, -3809, -4347, -4882, -5414, -5942, -6468, -6989, -7506, -8019,
-8527, -9029, -9526, -10018, -10503, -10982, -11455, -11920, -12379, -12830, -13273, -13708, -14135, -14554, -14963, -15364,
-15755, -16137, -16510, -16872, -17224, -17566, -17897, -18217, -18527, -18825, -19112, -19387, -19651, -19903, -20142, -20370,
-20586, -20789, -20979, -21157, -21322, -21475, -21614, -21740, -21854, -21954, -22041, -22114, -22174, -22221, -22255, -22275,
-22282, -22275, -22255, -22221, -22174, -22114, -22041, -21954, -21854, -21740, -21614, -21475, -21322, -21157, -20979, -20789,
-20586, -20370, -20142, -19903, -19651, -19387, -19112, -18825, -18527, -18217, -17897, -17566, -17224, -16872, -16510, -16137,
-15755, -15364, -14963, -14554, -14135, -13708, -13273, -12830, -12379, -11920, -11455, -10982, -10503, -10018, -9526, -9029,
-8527, -8019, -7506, -6989, -6468, -5942, -5414, -4882, -4347, -3809, -3269, -2727, -2184, -1639, -1093, -546 };
#endif
#elif defined(MDC_SAMPLE_FORMAT_FLOAT)
#if defined(MDC_ENCODE_FULL_AMPLITUDE)
static mdc_sample_t sintable[] = {
0.000000, 0.024541, 0.049068, 0.073565, 0.098017, 0.122411, 0.146730, 0.170962,
0.195090, 0.219101, 0.242980, 0.266713, 0.290285, 0.313682, 0.336890, 0.359895,
0.382683, 0.405241, 0.427555, 0.449611, 0.471397, 0.492898, 0.514103, 0.534998,
0.555570, 0.575808, 0.595699, 0.615232, 0.634393, 0.653173, 0.671559, 0.689541,
0.707107, 0.724247, 0.740951, 0.757209, 0.773010, 0.788346, 0.803208, 0.817585,
0.831470, 0.844854, 0.857729, 0.870087, 0.881921, 0.893224, 0.903989, 0.914210,
0.923880, 0.932993, 0.941544, 0.949528, 0.956940, 0.963776, 0.970031, 0.975702,
0.980785, 0.985278, 0.989177, 0.992480, 0.995185, 0.997290, 0.998795, 0.999699,
1.000000, 0.999699, 0.998795, 0.997290, 0.995185, 0.992480, 0.989177, 0.985278,
0.980785, 0.975702, 0.970031, 0.963776, 0.956940, 0.949528, 0.941544, 0.932993,
0.923880, 0.914210, 0.903989, 0.893224, 0.881921, 0.870087, 0.857729, 0.844854,
0.831470, 0.817585, 0.803208, 0.788346, 0.773010, 0.757209, 0.740951, 0.724247,
0.707107, 0.689541, 0.671559, 0.653173, 0.634393, 0.615232, 0.595699, 0.575808,
0.555570, 0.534998, 0.514103, 0.492898, 0.471397, 0.449611, 0.427555, 0.405241,
0.382683, 0.359895, 0.336890, 0.313682, 0.290285, 0.266713, 0.242980, 0.219101,
0.195090, 0.170962, 0.146730, 0.122411, 0.098017, 0.073565, 0.049068, 0.024541,
0.000000, -0.024541, -0.049068, -0.073565, -0.098017, -0.122411, -0.146730, -0.170962,
-0.195090, -0.219101, -0.242980, -0.266713, -0.290285, -0.313682, -0.336890, -0.359895,
-0.382683, -0.405241, -0.427555, -0.449611, -0.471397, -0.492898, -0.514103, -0.534998,
-0.555570, -0.575808, -0.595699, -0.615232, -0.634393, -0.653173, -0.671559, -0.689541,
-0.707107, -0.724247, -0.740951, -0.757209, -0.773010, -0.788346, -0.803208, -0.817585,
-0.831470, -0.844854, -0.857729, -0.870087, -0.881921, -0.893224, -0.903989, -0.914210,
-0.923880, -0.932993, -0.941544, -0.949528, -0.956940, -0.963776, -0.970031, -0.975702,
-0.980785, -0.985278, -0.989177, -0.992480, -0.995185, -0.997290, -0.998795, -0.999699,
-1.000000, -0.999699, -0.998795, -0.997290, -0.995185, -0.992480, -0.989177, -0.985278,
-0.980785, -0.975702, -0.970031, -0.963776, -0.956940, -0.949528, -0.941544, -0.932993,
-0.923880, -0.914210, -0.903989, -0.893224, -0.881921, -0.870087, -0.857729, -0.844854,
-0.831470, -0.817585, -0.803208, -0.788346, -0.773010, -0.757209, -0.740951, -0.724247,
-0.707107, -0.689541, -0.671559, -0.653173, -0.634393, -0.615232, -0.595699, -0.575808,
-0.555570, -0.534998, -0.514103, -0.492898, -0.471397, -0.449611, -0.427555, -0.405241,
-0.382683, -0.359895, -0.336890, -0.313682, -0.290285, -0.266713, -0.242980, -0.219101,
-0.195090, -0.170962, -0.146730, -0.122411, -0.098017, -0.073565, -0.049068, -0.024541 };
#else
static mdc_sample_t sintable[] = {
0.000000, 0.016688, 0.033366, 0.050024, 0.066652, 0.083239, 0.099777, 0.116254,
0.132661, 0.148989, 0.165227, 0.181365, 0.197394, 0.213304, 0.229085, 0.244729,
0.260225, 0.275564, 0.290737, 0.305736, 0.320550, 0.335171, 0.349590, 0.363798,
0.377788, 0.391550, 0.405076, 0.418357, 0.431387, 0.444158, 0.456660, 0.468888,
0.480833, 0.492488, 0.503847, 0.514902, 0.525647, 0.536076, 0.546181, 0.555958,
0.565399, 0.574500, 0.583255, 0.591659, 0.599706, 0.607393, 0.614713, 0.621663,
0.628238, 0.634435, 0.640250, 0.645679, 0.650719, 0.655368, 0.659621, 0.663477,
0.666934, 0.669989, 0.672640, 0.674886, 0.676726, 0.678158, 0.679181, 0.679795,
0.680000, 0.679795, 0.679181, 0.678158, 0.676726, 0.674886, 0.672640, 0.669989,
0.666934, 0.663477, 0.659621, 0.655368, 0.650719, 0.645679, 0.640250, 0.634435,
0.628238, 0.621663, 0.614713, 0.607393, 0.599706, 0.591659, 0.583255, 0.574500,
0.565399, 0.555958, 0.546181, 0.536076, 0.525647, 0.514902, 0.503847, 0.492488,
0.480833, 0.468888, 0.456660, 0.444158, 0.431387, 0.418357, 0.405076, 0.391550,
0.377788, 0.363798, 0.349590, 0.335171, 0.320550, 0.305736, 0.290737, 0.275564,
0.260225, 0.244729, 0.229085, 0.213304, 0.197394, 0.181365, 0.165227, 0.148989,
0.132661, 0.116254, 0.099777, 0.083239, 0.066652, 0.050024, 0.033366, 0.016688,
0.000000, -0.016688, -0.033366, -0.050024, -0.066652, -0.083239, -0.099777, -0.116254,
-0.132661, -0.148989, -0.165227, -0.181365, -0.197394, -0.213304, -0.229085, -0.244729,
-0.260225, -0.275564, -0.290737, -0.305736, -0.320550, -0.335171, -0.349590, -0.363798,
-0.377788, -0.391550, -0.405076, -0.418357, -0.431387, -0.444158, -0.456660, -0.468888,
-0.480833, -0.492488, -0.503847, -0.514902, -0.525647, -0.536076, -0.546181, -0.555958,
-0.565399, -0.574500, -0.583255, -0.591659, -0.599706, -0.607393, -0.614713, -0.621663,
-0.628238, -0.634435, -0.640250, -0.645679, -0.650719, -0.655368, -0.659621, -0.663477,
-0.666934, -0.669989, -0.672640, -0.674886, -0.676726, -0.678158, -0.679181, -0.679795,
-0.680000, -0.679795, -0.679181, -0.678158, -0.676726, -0.674886, -0.672640, -0.669989,
-0.666934, -0.663477, -0.659621, -0.655368, -0.650719, -0.645679, -0.640250, -0.634435,
-0.628238, -0.621663, -0.614713, -0.607393, -0.599706, -0.591659, -0.583255, -0.574500,
-0.565399, -0.555958, -0.546181, -0.536076, -0.525647, -0.514902, -0.503847, -0.492488,
-0.480833, -0.468888, -0.456660, -0.444158, -0.431387, -0.418357, -0.405076, -0.391550,
-0.377788, -0.363798, -0.349590, -0.335171, -0.320550, -0.305736, -0.290737, -0.275564,
-0.260225, -0.244729, -0.229085, -0.213304, -0.197394, -0.181365, -0.165227, -0.148989,
-0.132661, -0.116254, -0.099777, -0.083239, -0.066652, -0.050024, -0.033366, -0.016688 };
#endif
#else
#error "no known sample format defined"
#endif
// ---------------------------------------------------------------------------
// Global Functions
// ---------------------------------------------------------------------------
/* Create a new mdc_encoder object. */
mdc_encoder_t* mdc_encoder_new(int sampleRate)
{
mdc_encoder_t* encoder;
encoder = (mdc_encoder_t*)malloc(sizeof(mdc_encoder_t));
if (!encoder)
return (mdc_encoder_t*)0L;
encoder->loaded = 0;
encoder->preamble_set = 0;
if (sampleRate == 8000) {
encoder->incru = 644245094;
encoder->incru18 = 966367642;
}
else if (sampleRate == 16000) {
encoder->incru = 322122547;
encoder->incru18 = 483183820;
}
else if (sampleRate == 22050) {
encoder->incru = 233739716;
encoder->incru18 = 350609575;
}
else if (sampleRate == 32000) {
encoder->incru = 161061274;
encoder->incru18 = 241591910;
}
else if (sampleRate == 44100) {
encoder->incru = 116869858;
encoder->incru18 = 175304788;
}
else if (sampleRate == 48000) {
encoder->incru = 107374182;
encoder->incru18 = 161061274;
}
else {
// WARNING: lower precision than above
encoder->incru = 1200 * 2 * (0x80000000 / sampleRate);
encoder->incru18 = 1800 * 2 * (0x80000000 / sampleRate);
}
return encoder;
}
/* */
int mdc_encoder_set_preamble(mdc_encoder_t* encoder, int preambleLength)
{
if (!encoder)
return -1;
if (preambleLength < 0)
return -1;
encoder->preamble_set = preambleLength;
return 0;
}
/* */
static mdc_u8_t* _enc_leader(mdc_u8_t* data)
{
data[0] = 0x55;
data[1] = 0x55;
data[2] = 0x55;
data[3] = 0x55;
data[4] = 0x55;
data[5] = 0x55;
data[6] = 0x55;
data[7] = 0x07;
data[8] = 0x09;
data[9] = 0x2a;
data[10] = 0x44;
data[11] = 0x6f;
return &(data[12]);
}
/* */
static mdc_u8_t* _enc_str(mdc_u8_t* data)
{
mdc_u16_t ccrc;
mdc_int_t k, m;
mdc_int_t csr[7];
mdc_int_t b;
mdc_int_t lbits[112];
ccrc = _docrc(data, 4);
data[4] = ccrc & 0x00ff;
data[5] = (ccrc >> 8) & 0x00ff;
data[6] = 0;
for (mdc_int_t i = 0; i < 7; i++)
csr[i] = 0;
for (mdc_int_t i = 0; i < 7; i++) {
data[i + 7] = 0;
for (mdc_int_t j = 0; j <= 7; j++) {
for (k = 6; k > 0; k--)
csr[k] = csr[k - 1];
csr[0] = (data[i] >> j) & 0x01;
b = csr[0] + csr[2] + csr[5] + csr[6];
data[i + 7] |= (b & 0x01) << j;
}
}
k = 0;
m = 0;
for(mdc_int_t i = 0; i < 14; i++) {
for(mdc_int_t j = 0; j <= 7; j++) {
b = 0x01 & (data[i] >> j);
lbits[k] = b;
k += 16;
if (k > 111)
k = ++m;
}
}
k = 0;
for (mdc_int_t i = 0; i < 14; i++) {
data[i] = 0;
for(mdc_int_t j = 7; j >= 0; j--) {
if (lbits[k])
data[i] |= 1<<j;
++k;
}
}
return &(data[14]);
}
/* Set up a normal-length MDC packet for transmission. */
int mdc_encoder_set_packet(mdc_encoder_t* encoder, mdc_u8_t op, mdc_u8_t arg, mdc_u16_t unitID)
{
mdc_u8_t* dp;
if (!encoder)
return -1;
if (encoder->loaded)
return -1;
encoder->state = 0;
dp = _enc_leader(encoder->data);
dp[0] = op;
dp[1] = arg;
dp[2] = (unitID >> 8) & 0x00ff;
dp[3] = unitID & 0x00ff;
_enc_str(dp);
encoder->loaded = 26;
return 0;
}
/* Set up a double-length MDC packet for transmission. */
int mdc_encoder_set_double_packet(mdc_encoder_t* encoder, mdc_u8_t op, mdc_u8_t arg, mdc_u16_t unitID,
mdc_u8_t extra0, mdc_u8_t extra1, mdc_u8_t extra2, mdc_u8_t extra3)
{
mdc_u8_t* dp;
if (!encoder)
return -1;
if (encoder->loaded)
return -1;
encoder->state = 0;
dp = _enc_leader(encoder->data);
dp[0] = op;
dp[1] = arg;
dp[2] = (unitID >> 8) & 0x00ff;
dp[3] = unitID & 0x00ff;
dp = _enc_str(dp);
dp[0] = extra0;
dp[1] = extra1;
dp[2] = extra2;
dp[3] = extra3;
_enc_str(dp);
encoder->loaded = 40;
return 0;
}
/* */
static mdc_sample_t _enc_get_samp(mdc_encoder_t* encoder)
{
mdc_int_t b;
mdc_int_t ofs;
mdc_u32_t lthu = encoder->thu;
encoder->thu += encoder->incru;
// wrap
if (encoder->thu < lthu) {
encoder->ipos++;
if (encoder->ipos > 7) {
encoder->ipos = 0;
if (encoder->preamble_count == 0)
encoder->bpos++;
else
encoder->preamble_count--;
if (encoder->bpos >= encoder->loaded) {
encoder->state = 0;
return sintable[0];
}
}
b = 0x01 & (encoder->data[encoder->bpos] >> (7-(encoder->ipos)));
if (b != encoder->lb) {
encoder->xorb = 1;
encoder->lb = b;
}
else
encoder->xorb = 0;
}
if (encoder->xorb)
encoder->tthu += encoder->incru18;
else
encoder->tthu += encoder->incru;
ofs = (int)(encoder->tthu >> 24);
return sintable[ofs];
}
/* Get generated output audio samples from encoder. */
int mdc_encoder_get_samples(mdc_encoder_t* encoder, mdc_sample_t* buffer, int bufferSize)
{
if (!encoder)
return -1;
if (!(encoder->loaded))
return 0;
if (encoder->state == 0) {
encoder->tthu = 0;
encoder->thu = 0;
encoder->bpos = 0;
encoder->ipos = 0;
encoder->state = 1;
encoder->xorb = 1;
encoder->lb = 0;
encoder->preamble_count = encoder->preamble_set;
}
mdc_int_t i = 0;
while ((i < bufferSize) && encoder->state) {
buffer[i++] = _enc_get_samp(encoder);
}
#ifdef FILL_FINAL
while (i < bufferSize) {
buffer[i++] = sintable[0];
}
#endif
if (encoder->state == 0)
encoder->loaded = 0;
return i;
}

@ -0,0 +1,143 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Digital Voice Modem - Bridge
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
*/
/**
* @file mdc_encode.h
* @ingroup bridge
* @file mdc_encode.c
* @ingroup bridge
*/
/*-
* mdc_encode.h
* header for mdc_encode.c
*
* 9 October 2010 - typedefs for easier porting
*
* Author: Matthew Kaufman (matthew@eeph.com)
*
* Copyright (c) 2005 Matthew Kaufman All rights reserved.
*
* This file is part of Matthew Kaufman's MDC Encoder/Decoder Library
*
* The MDC Encoder/Decoder Library is free software; you can
* redistribute it and/or modify it under the terms of version 2 of
* the GNU General Public License as published by the Free Software
* Foundation.
*
* If you cannot comply with the terms of this license, contact
* the author for alternative license arrangements or do not use
* or redistribute this software.
*
* The MDC Encoder/Decoder Library 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 software; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
* USA.
*
* or see http://www.gnu.org/copyleft/gpl.html
*
-*/
#if !defined(__MDC_ENCODE_H__)
#define __MDC_ENCODE_H__
#include "mdc/mdc_types.h"
//#define FILL_FINAL // fills the end of the last block with zeros, rather than returning fewer samples than requested
//#define MDC_ENCODE_FULL_AMPLITUDE // encode at 100% amplitude (default is 68% amplitude for recommended deviation)
// ---------------------------------------------------------------------------
// Structure Declaration
// ---------------------------------------------------------------------------
/**
* @brief
*/
typedef struct {
mdc_int_t loaded;
mdc_int_t bpos;
mdc_int_t ipos;
mdc_int_t preamble_set;
mdc_int_t preamble_count;
mdc_u32_t thu;
mdc_u32_t tthu;
mdc_u32_t incru;
mdc_u32_t incru18;
mdc_int_t state;
mdc_int_t lb;
mdc_int_t xorb;
mdc_u8_t data[14 + 14 + 5 + 7];
} mdc_encoder_t;
// ---------------------------------------------------------------------------
// Global Functions
// ---------------------------------------------------------------------------
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Create a new mdc_encoder object.
* @param sampleRate The sampling rate in Hz.
* @returns mdc_encoder_t* An mdc_encoder object or null if failure.
*/
mdc_encoder_t* mdc_encoder_new(int sampleRate);
/**
* @brief
* @param[in] encoder Instance of mdc_encoder object.
* @param preambleLength length of additional preamble (in bytes) - preamble time is 6.66 msec * preambleLength.
* @returns int -1 for error, 0 otherwise
*/
int mdc_encoder_set_preamble(mdc_encoder_t* encoder, int preambleLength);
/**
* @brief Set up a normal-length MDC packet for transmission.
* @param[in] encoder Instance of mdc_encoder object.
* @param op MDC Opcode.
* @param arg MDC Argument.
* @param unitID Unit ID.
* @returns int -1 for error, 0 otherwise
*/
int mdc_encoder_set_packet(mdc_encoder_t* encoder, mdc_u8_t op, mdc_u8_t arg, mdc_u16_t unitID);
/**
* @brief Set up a double-length MDC packet for transmission.
* @param[in] encoder Instance of mdc_encoder object.
* @param op MDC Opcode.
* @param arg MDC Argument.
* @param unitID Unit ID.
* @param extra0 1st extra byte.
* @param extra1 2nd extra byte.
* @param extra2 3rd extra byte.
* @param extra3 4th extra byte.
* @returns int -1 for error, 0 otherwise
*/
int mdc_encoder_set_double_packet(mdc_encoder_t* encoder, mdc_u8_t op, mdc_u8_t arg,
mdc_u16_t unitID, mdc_u8_t extra0, mdc_u8_t extra1, mdc_u8_t extra2, mdc_u8_t extra3);
/**
* @brief Get generated output audio samples from encoder.
* @param[out] buffer Sample buffer to write into.
* @param[out] bufferSize The size (in samples) of the sample buffer.
* @returns int -1 for error, otherwise returns the number of samples written
* into the buffer (will be equal to bufferSize unless the end has
* been reached, in which case the last block may be less than
* bufferSize and all subsequent calls will return zero, until
* a new packet is loaded for transmission
*/
int mdc_encoder_get_samples(mdc_encoder_t* encoder, mdc_sample_t* buffer, int bufferSize);
#ifdef __cplusplus
}
#endif
#endif // __MDC_ENCODE_H__

@ -0,0 +1,511 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Digital Voice Modem - Bridge
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright (C) 2024 Bryan Biedenkapp, N2PLL
*
*/
/**
* @file mdc_types.h
* @ingroup bridge
*/
/*-
* mdc_types.h
* common typedef header for mdc_decode.h, mdc_encode.h
*
* Author: Matthew Kaufman (matthew@eeph.com)
*
* Copyright (c) 2010 Matthew Kaufman All rights reserved.
*
* This file is part of Matthew Kaufman's MDC Encoder/Decoder Library
*
* The MDC Encoder/Decoder Library is free software; you can
* redistribute it and/or modify it under the terms of version 2 of
* the GNU General Public License as published by the Free Software
* Foundation.
*
* If you cannot comply with the terms of this license, contact
* the author for alternative license arrangements or do not use
* or redistribute this software.
*
* The MDC Encoder/Decoder Library 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 software; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
* USA.
*
* or see http://www.gnu.org/copyleft/gpl.html
*
-*/
#if !defined(__MDC_TYPES_H__)
#define __MDC_TYPES_H__
// ---------------------------------------------------------------------------
// Types
// ---------------------------------------------------------------------------
typedef int mdc_s32;
typedef unsigned int mdc_u32_t;
typedef short mdc_s16_t;
typedef unsigned short mdc_u16_t;
typedef char mdc_s8_t;
typedef unsigned char mdc_u8_t;
typedef int mdc_int_t;
#ifndef MDC_FIXEDMATH
typedef double mdc_float_t;
#endif // MDC_FIXEDMATH
/* to change the data type, set this typedef: */
typedef short mdc_sample_t;
#define MDC_SAMPLE_FORMAT_S16
// ---------------------------------------------------------------------------
// Constants
// ---------------------------------------------------------------------------
/*
* Single Packets
*/
/// <summary>
/// Emergency
/// </summary>
/// <remarks>
/// Supports the following arguments:
/// PTT_PRE (0x80)
/// EMERG_UNKNW (0x81)
///
/// Opcode Bits:
/// 8 = Command/Data Packet = Command
/// 7 = Ack/No Ack Required = No Ack
/// 6 = Inbound/Outbound Packet = Outbound
/// </remarks>
#define OP_EMERGENCY 0x00U
/// <summary>
/// Emergency Acknowledge
/// </summary>
/// <remarks>
/// Has no arguments, should always have NO_ARG.
///
/// Opcode Bits:
/// 8 = Command/Data Packet = Command
/// 7 = Ack/No Ack Required = No Ack
/// 6 = Inbound/Outbound Packet = Inbound
/// </remarks>
#define OP_EMERGENCY_ACK 0x20U
/// <summary>
/// PTT ID
/// </summary>
/// <remarks>
/// Supports the following arguments:
/// NO_ARG (0x00) value indicates Post- ID
/// PTT_PRE (0x80) value indicated Pre- ID
///
/// Opcode Bits:
/// 8 = Command/Data Packet = Command
/// 7 = Ack/No Ack Required = No Ack
/// 6 = Inbound/Outbound Packet = Inbound
/// </remarks>
#define OP_PTT_ID 0x01U
/// <summary>
/// Radio Check
/// </summary>
/// <remarks>
/// Always takes the argument RADIO_CHECK (0x85).
///
/// Opcode Bits:
/// 8 = Command/Data Packet = Command
/// 7 = Ack/No Ack Required = Ack
/// 6 = Inbound/Outbound Packet = Outbound
/// </remarks>
#define OP_RADIO_CHECK 0x63U
/// <summary>
/// Radio Check Acknowledge
/// </summary>
/// <remarks>
/// Has no arguments, should always have NO_ARG.
///
/// Opcode Bits:
/// 8 = Command/Data Packet = Command
/// 7 = Ack/No Ack Required = No Ack
/// 6 = Inbound/Outbound Packet = Inbound
/// </remarks>
#define OP_RADIO_CHECK_ACK 0x03U
/// <summary>
/// Message
/// </summary>
/// <remarks>
/// Argument contains the ID of the given message. This opcode
/// optionally supports setting of bit 7 for required acknowledgement
/// of receipt.
///
/// Opcode Bits:
/// 8 = Command/Data Packet = Command
/// 7 = Ack/No Ack Required = No Ack (or) Ack
/// 6 = Inbound/Outbound Packet = Inbound
/// </remarks>
#define OP_MESSAGE 0x07U
#define OP_MESSAGE_WITH_ACK 0x47U
/// <summary>
/// Message/Status Acknowledge
/// </summary>
/// <remarks>
/// Always takes the argument NO_ARG.
///
/// Opcode Bits:
/// 8 = Command/Data Packet = Command
/// 7 = Ack/No Ack Required = No Ack
/// 6 = Inbound/Outbound Packet = Outbound
/// </remarks>
#define OP_MESSAGE_ACK 0x23U
/// <summary>
/// Status Request
/// </summary>
/// <remarks>
/// Always takes the argument STATUS_REQ (0x06).
///
/// Opcode Bits:
/// 8 = Command/Data Packet = Command
/// 7 = Ack/No Ack Required = No Ack
/// 6 = Inbound/Outbound Packet = Outbound
/// </remarks>
#define OP_STATUS_REQUEST 0x22U
/// <summary>
/// Status Response
/// </summary>
/// <remarks>
/// Argument contains the ID of the given status.
///
/// Opcode Bits:
/// 8 = Command/Data Packet = Command
/// 7 = Ack/No Ack Required = No Ack
/// 6 = Inbound/Outbound Packet = Inbound
/// </remarks>
#define OP_STATUS_RESPONSE 0x06U
/// <summary>
/// Remote Monitor
/// </summary>
/// <remarks>
/// Always takes the argument REMOTE_MONITOR (0x8A).
///
/// Opcode Bits:
/// 8 = Command/Data Packet = Command
/// 7 = Ack/No Ack Required = No Ack
/// 6 = Inbound/Outbound Packet = Inbound
/// </remarks>
#define OP_REMOTE_MONITOR 0x11U
/// <summary>
/// Selective Radio Inhibit
/// </summary>
/// <remarks>
/// Supports the following arguments:
/// NO_ARG (0x00) value indicates Unit ID to inhibit
/// CANCEL_INHIBIT (0x0C) value indicates Unit ID to uninhibit
///
/// Opcode Bits:
/// 8 = Command/Data Packet = Command
/// 7 = Ack/No Ack Required = No Ack
/// 6 = Inbound/Outbound Packet = Outbound
/// </remarks>
#define OP_RADIO_INHIBIT 0x2BU
/// <summary>
/// Selective Radio Inhibit Acknowledge
/// </summary>
/// <remarks>
/// Supports the following arguments:
/// NO_ARG (0x00) value indicates the Unit ID acknowledges the inhibit
/// CANCEL_INHIBIT (0x0C) value indicates the Unit ID acknowledges is uninhibited
///
/// Opcode Bits:
/// 8 = Command/Data Packet = Command
/// 7 = Ack/No Ack Required = No Ack
/// 6 = Inbound/Outbound Packet = Inbound
/// </remarks>
#define OP_RADIO_INHIBIT_ACK 0x0BU
/// <summary>
/// Repeater Access Code
/// </summary>
/// <remarks>
/// This operand is doubled to 0x41?
///
/// Always takes the argument RTT (0x01).
///
/// Opcode Bits:
/// 8 = Command/Data Packet = Command
/// 7 = Ack/No Ack Required = Ack
/// 6 = Inbound/Outbound Packet = Inbound
/// </remarks>
#define OP_RAC 0x30U
/// <summary>
/// Request to Talk
/// </summary>
/// <remarks>
/// This operand is doubled to 0x41?
///
/// Always takes the argument RTT (0x01).
///
/// Opcode Bits:
/// 8 = Command/Data Packet = Command
/// 7 = Ack/No Ack Required = Ack
/// 6 = Inbound/Outbound Packet = Inbound
/// </remarks>
#define OP_RTT_1 0x40U
#define OP_RTT_2 0x41U
/// <summary>
/// Request to Talk Acknowledge
/// </summary>
/// <remarks>
/// Has no arguments, should always have NO_ARG.
///
/// Opcode Bits:
/// 8 = Command/Data Packet = Command
/// 7 = Ack/No Ack Required = No Ack
/// 6 = Inbound/Outbound Packet = Outbound
/// </remarks>
#define OP_RTT_ACK 0x23U
/// <summary>
/// Simple Status
/// </summary>
/// <remarks>
/// Argument contains the ID of the given status.
///
/// Opcode Bits:
/// 8 = Command/Data Packet = Command
/// 7 = Ack/No Ack Required = No Ack
/// 6 = Inbound/Outbound Packet = Inbound
/// </remarks>
#define OP_SIMPLE_STATUS 0x46U
/*
* Double Packets
*/
/// <summary>
/// Double Packet Operation (0x35)
/// </summary>
/// <remarks>
/// Supports the following arguments:
/// DOUBLE_PACKET_FROM (0x89) value indicates who transmitted the double packet
///
/// Opcode Bits:
/// 8 = Command/Data Packet = Command
/// 7 = Ack/No Ack Required = No Ack
/// 6 = Inbound/Outbound Packet = Outbound
/// </remarks>
#define OP_DOUBLE_PACKET_TYPE1 0x35U
/// <summary>
/// Double Packet Operation (0x55)
///
/// Opcode Bits:
/// 8 = Command/Data Packet = Command
/// 7 = Ack/No Ack Required = Ack
/// 6 = Inbound/Outbound Packet = Inbound
/// </summary>
#define OP_DOUBLE_PACKET_TYPE2 0x55U
/// <summary>
/// Call Alert/Page
/// </summary>
/// <remarks>
/// Supports the following arguments:
/// CALL_ALERT_TO (0x0D) value indicates the intended target of the call
///
/// The DOUBLE_PACKET_FROM (0x89) of the DOUBLE_PACKET_TYPE1 frame will contain the unit ID that transmitted
/// the call alert. This opcode expects an ack, regardless of the bit 7 setting.
///
/// Opcode Bits:
/// 8 = Command/Data Packet = Data
/// 7 = Ack/No Ack Required = No Ack
/// 6 = Inbound/Outbound Packet = Inbound
/// </remarks>
#define OP_CALL_ALERT_ACK_EXPECTED 0x83U
/// <summary>
/// Call Alert/Page
/// </summary>
/// <remarks>
/// Supports the following arguments:
/// CALL_ALERT_TO (0x0D) value indicates the intended target of the call
///
/// The DOUBLE_PACKET_FROM (0x89) of the DOUBLE_PACKET_TYPE1 frame will contain the unit ID that transmitted
/// the call alert. This opcode does not expect an ack, regardless of the bit 7 setting.
///
/// Opcode Bits:
/// 8 = Command/Data Packet = Data
/// 7 = Ack/No Ack Required = No Ack
/// 6 = Inbound/Outbound Packet = Inbound
/// </remarks>
#define OP_CALL_ALERT_NOACK_EXPECTED 0x81U
/// <summary>
/// Call Alert/Page Acknowledge
/// </summary>
/// <remarks>
/// Supports the following arguments:
/// NO_ARG (0x00) value indicates the unit ID which initiated the call
///
/// The DOUBLE_PACKET_FROM (0x89) of the DOUBLE_PACKET_TYPE1 frame will contain the unit ID that transmitted
/// the acknowledge.
///
/// Opcode Bits:
/// 8 = Command/Data Packet = Data
/// 7 = Ack/No Ack Required = No Ack
/// 6 = Inbound/Outbound Packet = Outbound
/// </remarks>
#define OP_CALL_ALERT_ACK 0xA0U
/// <summary>
/// Voice Selective Call
/// </summary>
/// <remarks>
/// This opcode is doubled to operand 0x82 as well as 0x80?
///
/// Supports the following arguments:
/// SELECTIVE_CALL_TO (0x15) value indicates the intended target of the call
///
/// The DOUBLE_PACKET_FROM (0x89) of the DOUBLE_PACKET_TYPE1 frame will contain the unit ID that transmitted
/// the call alert.
///
/// Opcode Bits:
/// 8 = Command/Data Packet = Data
/// 7 = Ack/No Ack Required = No Ack
/// 6 = Inbound/Outbound Packet = Inbound
/// </remarks>
#define OP_SELECTIVE_CALL_1 0x80U
#define OP_SELECTIVE_CALL_2 0x82U
/// <summary>
/// Over-the-Air Rekey
/// </summary>
/// <remarks>
/// Supports the following arguments:
/// OTAR_UNK1 0x74 ?
/// OTAR_UNK2 0x76 ?
///
/// The DOUBLE_PACKET_FROM (0x89) of the DOUBLE_PACKET_TYPE1 frame will contain the unit ID that transmitted
/// the call alert.
///
/// Opcode Bits:
/// 8 = Command/Data Packet = Command
/// 7 = Ack/No Ack Required = No Ack
/// 6 = Inbound/Outbound Packet = Outbound
/// </remarks>
#define OP_OTAR 0x86U
/// <summary>
/// No Argument
/// </summary>
#define ARG_NO_ARG 0x00U
/*
* Single Packets
*/
/// <summary>
/// Emergency Argument (unknown use)
/// </summary>
#define ARG_EMERG_UNKNW 0x81U
/// <summary>
/// PTT ID Pre-
/// </summary>
#define ARG_PTT_PRE 0x80U
/// <summary>
/// Radio Check
/// </summary>
#define ARG_RADIO_CHECK 0x85U
/// <summary>
/// Status Request
/// </summary>
#define ARG_STATUS_REQ 0x06U
/// <summary>
/// Remote Monitor
/// </summary>
#define ARG_REMOTE_MONITOR 0x8AU
/// <summary>
/// Cancel Selective Radio Inhibit
/// </summary>
#define ARG_CANCEL_INHIBIT 0x0CU
/// <summary>
/// Request to Talk
/// </summary>
#define ARG_RTT 0x01U
/*
* Double Packets
*/
/// <summary>
/// Double To Argument
/// </summary>
/// <remarks>Unit ID represents what radio ID the call is targeting</remarks>
#define ARG_DOUBLE_PACKET_TO 0x89U
/// <summary>
/// Call Alert Argument
/// </summary>
/// <remarks>Unit ID represents what radio ID the call originated from</remarks>
#define ARG_CALL_ALERT 0x0DU
/// <summary>
/// OTAR Argument Unknown 0xC6
/// </summary>
#define ARG_OTAR_DOUBLE 0xC6U
/// <summary>
/// OTAR Argument Unknown 0x74
/// </summary>
#define ARG_OTAR_UNK1 0x74U
/// <summary>
/// OTAR Argument Unknown 0x76
/// </summary>
#define ARG_OTAR_UNK2 0x76U
// ---------------------------------------------------------------------------
// Global Functions
// ---------------------------------------------------------------------------
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief
* @param crc
* @param bitnum
* @returns mdc_u16_t
*/
mdc_u16_t _flip(mdc_u16_t crc, mdc_int_t bitnum);
/**
* @brief
* @param p
* @param len
* @returns mdc_u16_t
*/
mdc_u16_t _docrc(mdc_u8_t* p, int len);
#ifdef __cplusplus
}
#endif
#endif // __MDC_TYPES_H__

@ -0,0 +1,360 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Digital Voice Modem - Bridge
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright (C) 2024 Bryan Biedenkapp, N2PLL
*
*/
#include "bridge/Defines.h"
#include "common/dmr/data/EMB.h"
#include "common/dmr/lc/FullLC.h"
#include "common/dmr/SlotType.h"
#include "common/network/json/json.h"
#include "common/p25/dfsi/DFSIDefines.h"
#include "common/p25/dfsi/LC.h"
#include "common/Utils.h"
#include "network/PeerNetwork.h"
using namespace network;
#include <cassert>
// ---------------------------------------------------------------------------
// Public Class Members
// ---------------------------------------------------------------------------
/* Initializes a new instance of the PeerNetwork class. */
PeerNetwork::PeerNetwork(const std::string& address, uint16_t port, uint16_t localPort, uint32_t peerId, const std::string& password,
bool duplex, bool debug, bool dmr, bool p25, bool nxdn, bool slot1, bool slot2, bool allowActivityTransfer, bool allowDiagnosticTransfer, bool updateLookup, bool saveLookup) :
Network(address, port, localPort, peerId, password, duplex, debug, dmr, p25, nxdn, slot1, slot2, allowActivityTransfer, allowDiagnosticTransfer, updateLookup, saveLookup)
{
assert(!address.empty());
assert(port > 0U);
assert(!password.empty());
}
/* Writes P25 LDU1 frame data to the network. */
bool PeerNetwork::writeP25LDU1(const p25::lc::LC& control, const p25::data::LowSpeedData& lsd, const uint8_t* data, p25::defines::FrameType::E frameType)
{
if (m_status != NET_STAT_RUNNING && m_status != NET_STAT_MST_RUNNING)
return false;
bool resetSeq = false;
if (m_p25StreamId == 0U) {
resetSeq = true;
m_p25StreamId = createStreamId();
}
uint32_t messageLength = 0U;
UInt8Array message = createP25_LDU1Message_Raw(messageLength, control, lsd, data, frameType);
if (message == nullptr) {
return false;
}
return writeMaster({ NET_FUNC::PROTOCOL, NET_SUBFUNC::PROTOCOL_SUBFUNC_P25 }, message.get(), messageLength, pktSeq(resetSeq), m_p25StreamId);
}
/* Writes P25 LDU2 frame data to the network. */
bool PeerNetwork::writeP25LDU2(const p25::lc::LC& control, const p25::data::LowSpeedData& lsd, const uint8_t* data)
{
if (m_status != NET_STAT_RUNNING && m_status != NET_STAT_MST_RUNNING)
return false;
bool resetSeq = false;
if (m_p25StreamId == 0U) {
resetSeq = true;
m_p25StreamId = createStreamId();
}
uint32_t messageLength = 0U;
UInt8Array message = createP25_LDU2Message_Raw(messageLength, control, lsd, data);
if (message == nullptr) {
return false;
}
return writeMaster({ NET_FUNC::PROTOCOL, NET_SUBFUNC::PROTOCOL_SUBFUNC_P25 }, message.get(), messageLength, pktSeq(resetSeq), m_p25StreamId);
}
/* Helper to send a DMR terminator with LC message. */
void PeerNetwork::writeDMRTerminator(dmr::data::NetData& data, uint32_t* seqNo, uint8_t* dmrN, dmr::data::EmbeddedData& embeddedData)
{
using namespace dmr;
using namespace dmr::defines;
uint8_t n = (uint8_t)((*seqNo - 3U) % 6U);
uint32_t fill = 6U - n;
uint8_t* buffer = nullptr;
if (n > 0U) {
for (uint32_t i = 0U; i < fill; i++) {
// generate DMR AMBE data
buffer = new uint8_t[DMR_FRAME_LENGTH_BYTES];
::memcpy(buffer, SILENCE_DATA, DMR_FRAME_LENGTH_BYTES);
uint8_t lcss = embeddedData.getData(buffer, n);
// generated embedded signalling
data::EMB emb = data::EMB();
emb.setColorCode(0U);
emb.setLCSS(lcss);
emb.encode(buffer);
// generate DMR network frame
data.setData(buffer);
writeDMR(data);
seqNo++;
dmrN++;
delete[] buffer;
}
}
buffer = new uint8_t[DMR_FRAME_LENGTH_BYTES];
// generate DMR LC
lc::LC dmrLC = lc::LC();
dmrLC.setFLCO(FLCO::GROUP);
dmrLC.setSrcId(data.getSrcId());
dmrLC.setDstId(data.getDstId());
// generate the Slot Type
SlotType slotType = SlotType();
slotType.setDataType(DataType::TERMINATOR_WITH_LC);
slotType.encode(buffer);
lc::FullLC fullLC = lc::FullLC();
fullLC.encode(dmrLC, buffer, DataType::TERMINATOR_WITH_LC);
// generate DMR network frame
data.setData(buffer);
writeDMR(data);
seqNo = 0;
dmrN = 0;
}
// ---------------------------------------------------------------------------
// Protected Class Members
// ---------------------------------------------------------------------------
/* Writes configuration to the network. */
bool PeerNetwork::writeConfig()
{
if (m_loginStreamId == 0U) {
LogWarning(LOG_NET, "BUGBUG: tried to write network authorisation with no stream ID?");
return false;
}
const char* software = __NETVER__;
json::object config = json::object();
// identity and frequency
config["identity"].set<std::string>(m_identity); // Identity
config["rxFrequency"].set<uint32_t>(m_rxFrequency); // Rx Frequency
config["txFrequency"].set<uint32_t>(m_txFrequency); // Tx Frequency
// system info
json::object sysInfo = json::object();
sysInfo["latitude"].set<float>(m_latitude); // Latitude
sysInfo["longitude"].set<float>(m_longitude); // Longitude
sysInfo["height"].set<int>(m_height); // Height
sysInfo["location"].set<std::string>(m_location); // Location
config["info"].set<json::object>(sysInfo);
// channel data
json::object channel = json::object();
channel["txPower"].set<uint32_t>(m_power); // Tx Power
channel["txOffsetMhz"].set<float>(m_txOffsetMhz); // Tx Offset (Mhz)
channel["chBandwidthKhz"].set<float>(m_chBandwidthKhz); // Ch. Bandwidth (khz)
channel["channelId"].set<uint8_t>(m_channelId); // Channel ID
channel["channelNo"].set<uint32_t>(m_channelNo); // Channel No
config["channel"].set<json::object>(channel);
// RCON
json::object rcon = json::object();
rcon["password"].set<std::string>(m_restApiPassword); // REST API Password
rcon["port"].set<uint16_t>(m_restApiPort); // REST API Port
config["rcon"].set<json::object>(rcon);
config["software"].set<std::string>(std::string(software)); // Software ID
json::value v = json::value(config);
std::string json = v.serialize();
CharArray __buffer = std::make_unique<char[]>(json.length() + 9U);
char* buffer = __buffer.get();
::memcpy(buffer + 0U, TAG_REPEATER_CONFIG, 4U);
::sprintf(buffer + 8U, "%s", json.c_str());
if (m_debug) {
Utils::dump(1U, "Network Message, Configuration", (uint8_t*)buffer, json.length() + 8U);
}
return writeMaster({ NET_FUNC::RPTC, NET_SUBFUNC::NOP }, (uint8_t*)buffer, json.length() + 8U, pktSeq(), m_loginStreamId);
}
// ---------------------------------------------------------------------------
// Private Class Members
// ---------------------------------------------------------------------------
/* Creates an P25 LDU1 frame message. */
UInt8Array PeerNetwork::createP25_LDU1Message_Raw(uint32_t& length, const p25::lc::LC& control, const p25::data::LowSpeedData& lsd,
const uint8_t* data, p25::defines::FrameType::E frameType)
{
using namespace p25::defines;
using namespace p25::dfsi::defines;
assert(data != nullptr);
p25::dfsi::LC dfsiLC = p25::dfsi::LC(control, lsd);
uint8_t* buffer = new uint8_t[P25_LDU1_PACKET_LENGTH + PACKET_PAD];
::memset(buffer, 0x00U, P25_LDU1_PACKET_LENGTH + PACKET_PAD);
// construct P25 message header
createP25_MessageHdr(buffer, DUID::LDU1, control, lsd, frameType);
// pack DFSI data
uint32_t count = MSG_HDR_SIZE;
uint8_t imbe[RAW_IMBE_LENGTH_BYTES];
dfsiLC.setFrameType(DFSIFrameType::LDU1_VOICE1);
::memcpy(imbe, data + 10U, RAW_IMBE_LENGTH_BYTES);
dfsiLC.encodeLDU1(buffer + 24U, imbe);
count += DFSI_LDU1_VOICE1_FRAME_LENGTH_BYTES;
dfsiLC.setFrameType(DFSIFrameType::LDU1_VOICE2);
::memcpy(imbe, data + 26U, RAW_IMBE_LENGTH_BYTES);
dfsiLC.encodeLDU1(buffer + 46U, imbe);
count += DFSI_LDU1_VOICE2_FRAME_LENGTH_BYTES;
dfsiLC.setFrameType(DFSIFrameType::LDU1_VOICE3);
::memcpy(imbe, data + 55U, RAW_IMBE_LENGTH_BYTES);
dfsiLC.encodeLDU1(buffer + 60U, imbe);
count += DFSI_LDU1_VOICE3_FRAME_LENGTH_BYTES;
dfsiLC.setFrameType(DFSIFrameType::LDU1_VOICE4);
::memcpy(imbe, data + 80U, RAW_IMBE_LENGTH_BYTES);
dfsiLC.encodeLDU1(buffer + 77U, imbe);
count += DFSI_LDU1_VOICE4_FRAME_LENGTH_BYTES;
dfsiLC.setFrameType(DFSIFrameType::LDU1_VOICE5);
::memcpy(imbe, data + 105U, RAW_IMBE_LENGTH_BYTES);
dfsiLC.encodeLDU1(buffer + 94U, imbe);
count += DFSI_LDU1_VOICE5_FRAME_LENGTH_BYTES;
dfsiLC.setFrameType(DFSIFrameType::LDU1_VOICE6);
::memcpy(imbe, data + 130U, RAW_IMBE_LENGTH_BYTES);
dfsiLC.encodeLDU1(buffer + 111U, imbe);
count += DFSI_LDU1_VOICE6_FRAME_LENGTH_BYTES;
dfsiLC.setFrameType(DFSIFrameType::LDU1_VOICE7);
::memcpy(imbe, data + 155U, RAW_IMBE_LENGTH_BYTES);
dfsiLC.encodeLDU1(buffer + 128U, imbe);
count += DFSI_LDU1_VOICE7_FRAME_LENGTH_BYTES;
dfsiLC.setFrameType(DFSIFrameType::LDU1_VOICE8);
::memcpy(imbe, data + 180U, RAW_IMBE_LENGTH_BYTES);
dfsiLC.encodeLDU1(buffer + 145U, imbe);
count += DFSI_LDU1_VOICE8_FRAME_LENGTH_BYTES;
dfsiLC.setFrameType(DFSIFrameType::LDU1_VOICE9);
::memcpy(imbe, data + 204U, RAW_IMBE_LENGTH_BYTES);
dfsiLC.encodeLDU1(buffer + 162U, imbe);
count += DFSI_LDU1_VOICE9_FRAME_LENGTH_BYTES;
buffer[23U] = count;
if (m_debug)
Utils::dump(1U, "Network Message, P25 LDU1", buffer, (P25_LDU1_PACKET_LENGTH + PACKET_PAD));
length = (P25_LDU1_PACKET_LENGTH + PACKET_PAD);
return UInt8Array(buffer);
}
/* Creates an P25 LDU2 frame message. */
UInt8Array PeerNetwork::createP25_LDU2Message_Raw(uint32_t& length, const p25::lc::LC& control, const p25::data::LowSpeedData& lsd,
const uint8_t* data)
{
using namespace p25::defines;
using namespace p25::dfsi::defines;
assert(data != nullptr);
p25::dfsi::LC dfsiLC = p25::dfsi::LC(control, lsd);
uint8_t* buffer = new uint8_t[P25_LDU2_PACKET_LENGTH + PACKET_PAD];
::memset(buffer, 0x00U, P25_LDU2_PACKET_LENGTH + PACKET_PAD);
// construct P25 message header
createP25_MessageHdr(buffer, DUID::LDU2, control, lsd, FrameType::DATA_UNIT);
// pack DFSI data
uint32_t count = MSG_HDR_SIZE;
uint8_t imbe[RAW_IMBE_LENGTH_BYTES];
dfsiLC.setFrameType(DFSIFrameType::LDU2_VOICE10);
::memcpy(imbe, data + 10U, RAW_IMBE_LENGTH_BYTES);
dfsiLC.encodeLDU2(buffer + 24U, imbe);
count += DFSI_LDU2_VOICE10_FRAME_LENGTH_BYTES;
dfsiLC.setFrameType(DFSIFrameType::LDU2_VOICE11);
::memcpy(imbe, data + 26U, RAW_IMBE_LENGTH_BYTES);
dfsiLC.encodeLDU2(buffer + 46U, imbe);
count += DFSI_LDU2_VOICE11_FRAME_LENGTH_BYTES;
dfsiLC.setFrameType(DFSIFrameType::LDU2_VOICE12);
::memcpy(imbe, data + 55U, RAW_IMBE_LENGTH_BYTES);
dfsiLC.encodeLDU2(buffer + 60U, imbe);
count += DFSI_LDU2_VOICE12_FRAME_LENGTH_BYTES;
dfsiLC.setFrameType(DFSIFrameType::LDU2_VOICE13);
::memcpy(imbe, data + 80U, RAW_IMBE_LENGTH_BYTES);
dfsiLC.encodeLDU2(buffer + 77U, imbe);
count += DFSI_LDU2_VOICE13_FRAME_LENGTH_BYTES;
dfsiLC.setFrameType(DFSIFrameType::LDU2_VOICE14);
::memcpy(imbe, data + 105U, RAW_IMBE_LENGTH_BYTES);
dfsiLC.encodeLDU2(buffer + 94U, imbe);
count += DFSI_LDU2_VOICE14_FRAME_LENGTH_BYTES;
dfsiLC.setFrameType(DFSIFrameType::LDU2_VOICE15);
::memcpy(imbe, data + 130U, RAW_IMBE_LENGTH_BYTES);
dfsiLC.encodeLDU2(buffer + 111U, imbe);
count += DFSI_LDU2_VOICE15_FRAME_LENGTH_BYTES;
dfsiLC.setFrameType(DFSIFrameType::LDU2_VOICE16);
::memcpy(imbe, data + 155U, RAW_IMBE_LENGTH_BYTES);
dfsiLC.encodeLDU2(buffer + 128U, imbe);
count += DFSI_LDU2_VOICE16_FRAME_LENGTH_BYTES;
dfsiLC.setFrameType(DFSIFrameType::LDU2_VOICE17);
::memcpy(imbe, data + 180U, RAW_IMBE_LENGTH_BYTES);
dfsiLC.encodeLDU2(buffer + 145U, imbe);
count += DFSI_LDU2_VOICE17_FRAME_LENGTH_BYTES;
dfsiLC.setFrameType(DFSIFrameType::LDU2_VOICE18);
::memcpy(imbe, data + 204U, RAW_IMBE_LENGTH_BYTES);
dfsiLC.encodeLDU2(buffer + 162U, imbe);
count += DFSI_LDU2_VOICE18_FRAME_LENGTH_BYTES;
buffer[23U] = count;
if (m_debug)
Utils::dump(1U, "Network Message, P25 LDU2", buffer, (P25_LDU2_PACKET_LENGTH + PACKET_PAD));
length = (P25_LDU2_PACKET_LENGTH + PACKET_PAD);
return UInt8Array(buffer);
}

@ -0,0 +1,128 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Digital Voice Modem - Bridge
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright (C) 2024 Bryan Biedenkapp, N2PLL
*
*/
/**
* @defgroup bridge_network Networking
* @brief Implementation for the bridge networking.
* @ingroup bridge
*
* @file PeerNetwork.h
* @ingroup bridge_network
* @file PeerNetwork.cpp
* @ingroup bridge_network
*/
#if !defined(__PEER_NETWORK_H__)
#define __PEER_NETWORK_H__
#include "Defines.h"
#include "common/dmr/data/EmbeddedData.h"
#include "host/network/Network.h"
#include <string>
#include <cstdint>
namespace network
{
// ---------------------------------------------------------------------------
// Class Declaration
// Implements the core peer networking logic.
// ---------------------------------------------------------------------------
class HOST_SW_API PeerNetwork : public Network {
public:
/**
* @brief Initializes a new instance of the PeerNetwork class.
* @param address Network Hostname/IP address to connect to.
* @param port Network port number.
* @param local
* @param peerId Unique ID on the network.
* @param password Network authentication password.
* @param duplex Flag indicating full-duplex operation.
* @param debug Flag indicating whether network debug is enabled.
* @param dmr Flag indicating whether DMR is enabled.
* @param p25 Flag indicating whether P25 is enabled.
* @param nxdn Flag indicating whether NXDN is enabled.
* @param slot1 Flag indicating whether DMR slot 1 is enabled for network traffic.
* @param slot2 Flag indicating whether DMR slot 2 is enabled for network traffic.
* @param allowActivityTransfer Flag indicating that the system activity logs will be sent to the network.
* @param allowDiagnosticTransfer Flag indicating that the system diagnostic logs will be sent to the network.
* @param updateLookup Flag indicating that the system will accept radio ID and talkgroup ID lookups from the network.
*/
PeerNetwork(const std::string& address, uint16_t port, uint16_t localPort, uint32_t peerId, const std::string& password,
bool duplex, bool debug, bool dmr, bool p25, bool nxdn, bool slot1, bool slot2, bool allowActivityTransfer, bool allowDiagnosticTransfer, bool updateLookup, bool saveLookup);
/**
* @brief Writes P25 LDU1 frame data to the network.
* @param[in] control Instance of p25::lc::LC containing link control data.
* @param[in] lsd Instance of p25::data::LowSpeedData containing low speed data.
* @param[in] data Buffer containing P25 LDU1 data to send.
* @param[in] frameType DVM P25 frame type.
* @returns bool True, if message was sent, otherwise false.
*/
bool writeP25LDU1(const p25::lc::LC& control, const p25::data::LowSpeedData& lsd, const uint8_t* data,
p25::defines::FrameType::E frameType) override;
/**
* @brief Writes P25 LDU2 frame data to the network.
* @param[in] control Instance of p25::lc::LC containing link control data.
* @param[in] lsd Instance of p25::data::LowSpeedData containing low speed data.
* @param[in] data Buffer containing P25 LDU2 data to send.
* @returns bool True, if message was sent, otherwise false.
*/
bool writeP25LDU2(const p25::lc::LC& control, const p25::data::LowSpeedData& lsd, const uint8_t* data) override;
/**
* @brief Helper to send a DMR terminator with LC message.
* @param data
* @param seqNo
* @param dmrN
* @param embeddedData
*/
void writeDMRTerminator(dmr::data::NetData& data, uint32_t* seqNo, uint8_t* dmrN, dmr::data::EmbeddedData& embeddedData);
protected:
/**
* @brief Writes configuration to the network.
* @returns bool True, if configuration was sent, otherwise false.
*/
bool writeConfig() override;
private:
/**
* @brief Creates an P25 LDU1 frame message.
*
* The data packed into a P25 LDU1 frame message is near standard DFSI messaging, just instead of
* 9 individual frames, they are packed into a single message one right after another.
*
* @param[out] length Length of network message buffer.
* @param[in] control Instance of p25::lc::LC containing link control data.
* @param[in] lsd Instance of p25::data::LowSpeedData containing low speed data.
* @param[in] data Buffer containing P25 LDU1 data to send.
* @param[in] frameType DVM P25 frame type.
* @returns UInt8Array Buffer containing the built network message.
*/
UInt8Array createP25_LDU1Message_Raw(uint32_t& length, const p25::lc::LC& control, const p25::data::LowSpeedData& lsd,
const uint8_t* data, p25::defines::FrameType::E frameType);
/**
* @brief Creates an P25 LDU2 frame message.
*
* The data packed into a P25 LDU2 frame message is near standard DFSI messaging, just instead of
* 9 individual frames, they are packed into a single message one right after another.
*
* @param[out] length Length of network message buffer.
* @param[in] control Instance of p25::lc::LC containing link control data.
* @param[in] lsd Instance of p25::data::LowSpeedData containing low speed data.
* @param[in] data Buffer containing P25 LDU2 data to send.
* @returns UInt8Array Buffer containing the built network message.
*/
UInt8Array createP25_LDU2Message_Raw(uint32_t& length, const p25::lc::LC& control, const p25::data::LowSpeedData& lsd,
const uint8_t* data);
};
} // namespace network
#endif // __PEER_NETWORK_H__

@ -4,7 +4,7 @@
* GPLv2 Open Source. Use is subject to license terms. * GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* Copyright (C) 2023 Bryan Biedenkapp, N2PLL * Copyright (C) 2023,2024 Bryan Biedenkapp, N2PLL
* *
*/ */
#include "Defines.h" #include "Defines.h"
@ -26,6 +26,31 @@ static const uint64_t NTP_SCALE_FRAC = 4294967296ULL;
// Global Functions // Global Functions
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
#if defined(_WIN32)
/* Gets the current time of day, putting it into *TV. */
int gettimeofday(struct timeval* tv, struct timezone* tzp)
{
// Note: some broken versions only have 8 trailing zero's, the correct epoch has 9 trailing zero's
// This magic number is the number of 100 nanosecond intervals since January 1, 1601 (UTC)
// until 00:00:00 January 1, 1970
static const uint64_t EPOCH = ((uint64_t)116444736000000000ULL);
SYSTEMTIME system_time;
FILETIME file_time;
uint64_t time;
GetSystemTime(&system_time);
SystemTimeToFileTime(&system_time, &file_time);
time = ((uint64_t)file_time.dwLowDateTime);
time += ((uint64_t)file_time.dwHighDateTime) << 32;
tv->tv_sec = (long)((time - EPOCH) / 10000000L);
tv->tv_usec = (long)(system_time.wMilliseconds * 1000);
return 0;
}
#endif // defined(_WIN32)
/* */ /* */
static inline uint32_t ntpDiffMS(uint64_t older, uint64_t newer) static inline uint32_t ntpDiffMS(uint64_t older, uint64_t newer)

@ -4,7 +4,7 @@
* GPLv2 Open Source. Use is subject to license terms. * GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* Copyright (C) 2023 Bryan Biedenkapp, N2PLL * Copyright (C) 2023,2024 Bryan Biedenkapp, N2PLL
* *
*/ */
/** /**
@ -22,9 +22,28 @@
#include "common/Defines.h" #include "common/Defines.h"
#if defined(_WIN32)
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <WinSock2.h>
#else
#include <sys/time.h> #include <sys/time.h>
#endif // defined(_WIN32)
#include <chrono> #include <chrono>
#if defined(_WIN32)
// ---------------------------------------------------------------------------
// Global Functions
// ---------------------------------------------------------------------------
/**
* @brief Gets the current time of day, putting it into *TV.
* @param tv
* @param tzp
* @returns int
*/
extern HOST_SW_API int gettimeofday(struct timeval* tv, struct timezone* tzp);
#endif // defined(_WIN32)
namespace system_clock namespace system_clock
{ {
/* /*

@ -11,8 +11,12 @@
#include "Log.h" #include "Log.h"
#include "network/BaseNetwork.h" #include "network/BaseNetwork.h"
#if defined(_WIN32)
#include "Clock.h"
#else
#include <sys/time.h> #include <sys/time.h>
#include <syslog.h> #include <syslog.h>
#endif // defined(_WIN32)
#if defined(CATCH2_TEST_COMPILATION) #if defined(CATCH2_TEST_COMPILATION)
#include <catch2/catch_test_macros.hpp> #include <catch2/catch_test_macros.hpp>
@ -107,6 +111,7 @@ static bool LogOpen()
return m_fpLog != nullptr; return m_fpLog != nullptr;
} }
else { else {
#if !defined(_WIN32)
switch (m_fileLevel) { switch (m_fileLevel) {
case 1U: case 1U:
setlogmask(LOG_UPTO(LOG_DEBUG)); setlogmask(LOG_UPTO(LOG_DEBUG));
@ -128,6 +133,9 @@ static bool LogOpen()
openlog(m_fileRoot.c_str(), LOG_CONS | LOG_PID | LOG_NDELAY, LOG_DAEMON); openlog(m_fileRoot.c_str(), LOG_CONS | LOG_PID | LOG_NDELAY, LOG_DAEMON);
return true; return true;
#else
return false;
#endif // !defined(_WIN32)
} }
} }
@ -167,8 +175,12 @@ bool LogInitialise(const std::string& filePath, const std::string& fileRoot, uin
m_fileLevel = fileLevel; m_fileLevel = fileLevel;
g_logDisplayLevel = displayLevel; g_logDisplayLevel = displayLevel;
g_disableTimeDisplay = disableTimeDisplay; g_disableTimeDisplay = disableTimeDisplay;
#if defined(_WIN32)
g_useSyslog = false;
#else
if (!g_useSyslog) if (!g_useSyslog)
g_useSyslog = useSyslog; g_useSyslog = useSyslog;
#endif // defined(_WIN32)
return ::LogOpen(); return ::LogOpen();
} }
@ -181,8 +193,10 @@ void LogFinalise()
#endif #endif
if (m_fpLog != nullptr) if (m_fpLog != nullptr)
::fclose(m_fpLog); ::fclose(m_fpLog);
#if !defined(_WIN32)
if (g_useSyslog) if (g_useSyslog)
closelog(); closelog();
#endif // !defined(_WIN32)
} }
/* Writes a new entry to the diagnostics log. */ /* Writes a new entry to the diagnostics log. */
@ -258,6 +272,7 @@ void Log(uint32_t level, const char *module, const char* fmt, ...)
::fprintf(m_fpLog, "%s\n", buffer); ::fprintf(m_fpLog, "%s\n", buffer);
::fflush(m_fpLog); ::fflush(m_fpLog);
} else { } else {
#if !defined(_WIN32)
// convert our log level into syslog level // convert our log level into syslog level
int syslogLevel = LOG_INFO; int syslogLevel = LOG_INFO;
switch (level) { switch (level) {
@ -282,6 +297,7 @@ void Log(uint32_t level, const char *module, const char* fmt, ...)
} }
syslog(syslogLevel, "%s", buffer); syslog(syslogLevel, "%s", buffer);
#endif // !defined(_WIN32)
} }
} }
@ -294,8 +310,10 @@ void Log(uint32_t level, const char *module, const char* fmt, ...)
if (level >= 6U && level < 9999U) { if (level >= 6U && level < 9999U) {
if (m_fpLog != nullptr) if (m_fpLog != nullptr)
::fclose(m_fpLog); ::fclose(m_fpLog);
#if !defined(_WIN32)
if (g_useSyslog) if (g_useSyslog)
::closelog(); ::closelog();
#endif // !defined(_WIN32)
exit(1); exit(1);
} }
} }

@ -5,6 +5,7 @@
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* Copyright (C) 2015,2016 Jonathan Naylor, G4KLX * Copyright (C) 2015,2016 Jonathan Naylor, G4KLX
* Copyright (C) 2024 Bryan Biedenkapp, N2PLL
* *
*/ */
#include "StopWatch.h" #include "StopWatch.h"
@ -19,9 +20,18 @@
/* Initializes a new instance of the StopWatch class. */ /* Initializes a new instance of the StopWatch class. */
StopWatch::StopWatch() : StopWatch::StopWatch() :
#if defined(_WIN32)
m_frequencyS(),
m_frequencyMS(),
m_start()
#else
m_startMS(0ULL) m_startMS(0ULL)
#endif // defined(_WIN32)
{ {
/* stub */ #if defined(_WIN32)
::QueryPerformanceFrequency(&m_frequencyS);
m_frequencyMS.QuadPart = m_frequencyS.QuadPart / 1000ULL;
#endif // defined(_WIN32)
} }
/* Finalizes a instance of the StopWatch class. */ /* Finalizes a instance of the StopWatch class. */
@ -35,32 +45,55 @@ StopWatch::~StopWatch()
ulong64_t StopWatch::time() const ulong64_t StopWatch::time() const
{ {
#if defined(_WIN32)
LARGE_INTEGER now;
::QueryPerformanceCounter(&now);
return (ulong64_t)(now.QuadPart / m_frequencyMS.QuadPart);
#else
struct timeval now; struct timeval now;
::gettimeofday(&now, NULL); ::gettimeofday(&now, NULL);
return now.tv_sec * 1000ULL + now.tv_usec / 1000ULL; return now.tv_sec * 1000ULL + now.tv_usec / 1000ULL;
#endif // defined(_WIN32)
} }
/* Starts the stopwatch. */ /* Starts the stopwatch. */
ulong64_t StopWatch::start() ulong64_t StopWatch::start()
{ {
#if defined(_WIN32)
::QueryPerformanceCounter(&m_start);
return (ulong64_t)(m_start.QuadPart / m_frequencyS.QuadPart);
#else
struct timespec now; struct timespec now;
::clock_gettime(CLOCK_MONOTONIC, &now); ::clock_gettime(CLOCK_MONOTONIC, &now);
m_startMS = now.tv_sec * 1000ULL + now.tv_nsec / 1000000ULL; m_startMS = now.tv_sec * 1000ULL + now.tv_nsec / 1000000ULL;
return m_startMS; return m_startMS;
#endif // defined(_WIN32)
} }
/* Gets the elapsed time since the stopwatch started. */ /* Gets the elapsed time since the stopwatch started. */
uint32_t StopWatch::elapsed() uint32_t StopWatch::elapsed()
{ {
#if defined(_WIN32)
LARGE_INTEGER now;
::QueryPerformanceCounter(&now);
LARGE_INTEGER temp;
temp.QuadPart = (now.QuadPart - m_start.QuadPart) * 1000;
return (uint32_t)(temp.QuadPart / m_frequencyS.QuadPart);
#else
struct timespec now; struct timespec now;
::clock_gettime(CLOCK_MONOTONIC, &now); ::clock_gettime(CLOCK_MONOTONIC, &now);
ulong64_t nowMS = now.tv_sec * 1000ULL + now.tv_nsec / 1000000ULL; ulong64_t nowMS = now.tv_sec * 1000ULL + now.tv_nsec / 1000000ULL;
return nowMS - m_startMS; return nowMS - m_startMS;
#endif // defined(_WIN32)
} }

@ -5,6 +5,7 @@
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* Copyright (C) 2015,2016 Jonathan Naylor, G4KLX * Copyright (C) 2015,2016 Jonathan Naylor, G4KLX
* Copyright (C) 2024 Bryan Biedenkapp, N2PLL
* *
*/ */
/** /**
@ -22,7 +23,12 @@
#include "common/Defines.h" #include "common/Defines.h"
#if defined(_WIN32)
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#else
#include <sys/time.h> #include <sys/time.h>
#endif // defined(_WIN32)
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Class Declaration // Class Declaration
@ -61,7 +67,13 @@ public:
uint32_t elapsed(); uint32_t elapsed();
private: private:
#if defined(_WIN32)
LARGE_INTEGER m_frequencyS;
LARGE_INTEGER m_frequencyMS;
LARGE_INTEGER m_start;
#else
ulong64_t m_startMS; ulong64_t m_startMS;
#endif // defined(_WIN32)
}; };
#endif // __STOPWATCH_H__ #endif // __STOPWATCH_H__

@ -13,7 +13,9 @@
#include <cerrno> #include <cerrno>
#include <signal.h> #include <signal.h>
#if !defined(_WIN32)
#include <unistd.h> #include <unistd.h>
#endif // !defined(_WIN32)
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Public Class Members // Public Class Members
@ -40,11 +42,19 @@ bool Thread::run()
return m_started; return m_started;
m_started = true; m_started = true;
#if defined(_WIN32)
m_thread = ::CreateThread(NULL, 0, &helper, this, 0, NULL);
if (m_thread == NULL) {
LogError(LOG_NET, "Error returned from CreateThread, err: %lu", ::GetLastError());
return false;
}
#else
int err = ::pthread_create(&m_thread, NULL, helper, this); int err = ::pthread_create(&m_thread, NULL, helper, this);
if (err != 0) { if (err != 0) {
LogError(LOG_NET, "Error returned from pthread_create, err: %d", errno); LogError(LOG_NET, "Error returned from pthread_create, err: %d", errno);
return false; return false;
} }
#endif // defined(_WIN32)
return true; return true;
} }
@ -53,7 +63,12 @@ bool Thread::run()
void Thread::wait() void Thread::wait()
{ {
#if defined(_WIN32)
::WaitForSingleObject(m_thread, INFINITE);
::CloseHandle(m_thread);
#else
::pthread_join(m_thread, NULL); ::pthread_join(m_thread, NULL);
#endif // defined(_WIN32)
} }
/* Set thread name visible in the kernel and its interfaces. */ /* Set thread name visible in the kernel and its interfaces. */
@ -62,11 +77,15 @@ void Thread::setName(std::string name)
{ {
if (!m_started) if (!m_started)
return; return;
#if defined(_WIN32)
// WIN32 doesn't have a way to set thread names (easily, or consistently anyway)
#else
if (pthread_kill(m_thread, 0) != 0) if (pthread_kill(m_thread, 0) != 0)
return; return;
#ifdef _GNU_SOURCE #ifdef _GNU_SOURCE
::pthread_setname_np(m_thread, name.c_str()); ::pthread_setname_np(m_thread, name.c_str());
#endif // _GNU_SOURCE #endif // _GNU_SOURCE
#endif // defined(_WIN32)
} }
/* /*
@ -79,7 +98,11 @@ void Thread::detach()
{ {
if (!m_started) if (!m_started)
return; return;
#if defined(_WIN32)
::CloseHandle(m_thread);
#else
::pthread_detach(m_thread); ::pthread_detach(m_thread);
#endif // defined(_WIN32)
} }
/* Executes the specified start routine to run as a thread. */ /* Executes the specified start routine to run as a thread. */
@ -91,11 +114,22 @@ bool Thread::runAsThread(void* obj, void *(*startRoutine)(void *), thread_t* thr
thread->obj = obj; thread->obj = obj;
#if defined(_WIN32)
HANDLE hnd = ::CreateThread(NULL, 0, reinterpret_cast<LPTHREAD_START_ROUTINE>((void*)startRoutine), thread, CREATE_SUSPENDED, NULL);
if (hnd == NULL) {
LogError(LOG_NET, "Error returned from CreateThread, err: %lu", ::GetLastError());
return false;
}
thread->thread = hnd;
::ResumeThread(hnd);
#else
if (::pthread_create(&thread->thread, NULL, startRoutine, thread) != 0) { if (::pthread_create(&thread->thread, NULL, startRoutine, thread) != 0) {
LogError(LOG_NET, "Error returned from pthread_create, err: %d", errno); LogError(LOG_NET, "Error returned from pthread_create, err: %d", errno);
delete thread; delete thread;
return false; return false;
} }
#endif // defined(_WIN32)
return true; return true;
} }
@ -104,11 +138,21 @@ bool Thread::runAsThread(void* obj, void *(*startRoutine)(void *), thread_t* thr
void Thread::sleep(uint32_t ms, uint32_t us) void Thread::sleep(uint32_t ms, uint32_t us)
{ {
#if defined(_WIN32)
if (us > 0U) {
::Sleep(1);
}
else {
::Sleep(ms);
}
#else
if (us > 0U) { if (us > 0U) {
::usleep(us); ::usleep(us);
} else { }
else {
::usleep(ms * 1000U); ::usleep(ms * 1000U);
} }
#endif // defined(_WIN32)
} }
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@ -117,10 +161,18 @@ void Thread::sleep(uint32_t ms, uint32_t us)
/* Internal helper thats used as the entry point for the thread. */ /* Internal helper thats used as the entry point for the thread. */
#if defined(_WIN32)
DWORD Thread::helper(LPVOID arg)
#else
void* Thread::helper(void* arg) void* Thread::helper(void* arg)
#endif // defined(_WIN32)
{ {
Thread* p = (Thread*)arg; Thread* p = (Thread*)arg;
p->entry(); p->entry();
#if defined(_WIN32)
return 0UL;
#else
return nullptr; return nullptr;
#endif // defined(_WIN32)
} }

@ -25,7 +25,18 @@
#include <string> #include <string>
#if defined(_WIN32)
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#else
#include <pthread.h> #include <pthread.h>
#endif // defined(_WIN32)
#if defined(_WIN32)
/* Thread identifiers. The structure of the attribute type is not
exposed on purpose. */
typedef HANDLE pthread_t;
#endif // defined(_WIN32)
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Structure Declaration // Structure Declaration
@ -111,7 +122,11 @@ private:
* @param arg * @param arg
* @returns void* * @returns void*
*/ */
#if defined(_WIN32)
static DWORD __stdcall helper(LPVOID arg);
#else
static void* helper(void* arg); static void* helper(void* arg);
#endif // defined(_WIN32)
public: public:
/** /**

@ -5,7 +5,7 @@
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* Copyright (C) 2009,2014,2015,2016 Jonathan Naylor, G4KLX * Copyright (C) 2009,2014,2015,2016 Jonathan Naylor, G4KLX
* Copyright (C) 2018-2019 Bryan Biedenkapp, N2PLL * Copyright (C) 2018-2024 Bryan Biedenkapp, N2PLL
* *
*/ */
#include "Utils.h" #include "Utils.h"
@ -14,6 +14,10 @@
#include <cstdio> #include <cstdio>
#include <cassert> #include <cassert>
#if defined(_WIN32)
#include <WS2tcpip.h>
#endif // defined(_WIN32)
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Constants/Macros // Constants/Macros
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@ -25,6 +29,30 @@ const uint8_t BITS_TABLE[] = {
B6(0), B6(1), B6(1), B6(2) B6(0), B6(1), B6(1), B6(2)
}; };
// ---------------------------------------------------------------------------
// Global Functions
// ---------------------------------------------------------------------------
#if defined(_WIN32)
/* IP address from uint32_t value. */
uint32_t __IP_FROM_STR(const std::string& value)
{
struct sockaddr_in sa;
inet_pton(AF_INET, value.c_str(), &(sa.sin_addr));
uint8_t ip[4U];
::memset(ip, 0x00U, 4U);
ip[3U] = ((uint32_t)sa.sin_addr.s_addr >> 24) & 0xFFU;
ip[2U] = ((uint32_t)sa.sin_addr.s_addr >> 16) & 0xFFU;
ip[1U] = ((uint32_t)sa.sin_addr.s_addr >> 8) & 0xFFU;
ip[0U] = ((uint32_t)sa.sin_addr.s_addr >> 0) & 0xFFU;
return (ip[0U] << 24) | (ip[1U] << 16) | (ip[2U] << 8) | (ip[3U] << 0);
}
#endif // defined(_WIN32)
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Static Class Members // Static Class Members
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------

@ -5,7 +5,7 @@
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* Copyright (C) 2009,2014,2015 Jonathan Naylor, G4KLX * Copyright (C) 2009,2014,2015 Jonathan Naylor, G4KLX
* Copyright (C) 2018-2019 Bryan Biedenkapp, N2PLL * Copyright (C) 2018-2024 Bryan Biedenkapp, N2PLL
* *
*/ */
/** /**
@ -26,7 +26,9 @@
#include <cstring> #include <cstring>
#include <string> #include <string>
#if !defined(_WIN32)
#include <arpa/inet.h> #include <arpa/inet.h>
#endif // !defined(WIN32)
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Constants // Constants
@ -108,6 +110,7 @@ inline std::string __IP_FROM_UINT(const uint32_t& value) {
* @param value String representation of the IP address. * @param value String representation of the IP address.
* @return uint32_t Packed IP address. * @return uint32_t Packed IP address.
*/ */
#if !defined(_WIN32)
inline uint32_t __IP_FROM_STR(const std::string& value) { inline uint32_t __IP_FROM_STR(const std::string& value) {
struct sockaddr_in sa; struct sockaddr_in sa;
inet_pton(AF_INET, value.c_str(), &(sa.sin_addr)); inet_pton(AF_INET, value.c_str(), &(sa.sin_addr));
@ -122,6 +125,9 @@ inline uint32_t __IP_FROM_STR(const std::string& value) {
return (ip[0U] << 24) | (ip[1U] << 16) | (ip[2U] << 8) | (ip[3U] << 0); return (ip[0U] << 24) | (ip[1U] << 16) | (ip[2U] << 8) | (ip[3U] << 0);
} }
#else
extern HOST_SW_API uint32_t __IP_FROM_STR(const std::string& value);
#endif // !defined(_WIN32)
/** /**
* @brief Helper to lower-case an input string. * @brief Helper to lower-case an input string.
@ -250,6 +256,11 @@ inline std::string strtoupper(const std::string value) {
* @ingroup utils * @ingroup utils
*/ */
typedef std::unique_ptr<uint8_t[]> UInt8Array; typedef std::unique_ptr<uint8_t[]> UInt8Array;
/**
* @brief Unique char array.
* @ingroup utils
*/
typedef std::unique_ptr<char[]> CharArray;
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Class Declaration // Class Declaration

@ -117,6 +117,7 @@ namespace dmr
const uint32_t DMR_PDU_UNCODED_LENGTH_BYTES = 24U; const uint32_t DMR_PDU_UNCODED_LENGTH_BYTES = 24U;
const uint32_t MI_LENGTH_BYTES = 4U; // This was guessed based on OTA data captures -- the message indicator seems to be the same length as a source/destination address const uint32_t MI_LENGTH_BYTES = 4U; // This was guessed based on OTA data captures -- the message indicator seems to be the same length as a source/destination address
const uint32_t RAW_AMBE_LENGTH_BYTES = 9U;
/** @} */ /** @} */
/** @name Thresholds */ /** @name Thresholds */

@ -237,7 +237,8 @@ bool BaseNetwork::announceAffiliationUpdate(const std::unordered_map<uint32_t, u
if (m_status != NET_STAT_RUNNING && m_status != NET_STAT_MST_RUNNING) if (m_status != NET_STAT_RUNNING && m_status != NET_STAT_MST_RUNNING)
return false; return false;
uint8_t buffer[4U + (affs.size() * 8U)]; UInt8Array __buffer = std::make_unique<uint8_t[]>(4U + (affs.size() * 8U));
uint8_t* buffer = __buffer.get();
::memset(buffer, 0x00U, 4U + (affs.size() * 8U)); ::memset(buffer, 0x00U, 4U + (affs.size() * 8U));
__SET_UINT32(affs.size(), buffer, 0U); __SET_UINT32(affs.size(), buffer, 0U);
@ -260,7 +261,8 @@ bool BaseNetwork::announceSiteVCs(const std::vector<uint32_t> peers)
if (m_status != NET_STAT_RUNNING && m_status != NET_STAT_MST_RUNNING) if (m_status != NET_STAT_RUNNING && m_status != NET_STAT_MST_RUNNING)
return false; return false;
uint8_t buffer[4U + (peers.size() * 4U)]; UInt8Array __buffer = std::make_unique<uint8_t[]>(4U + (peers.size() * 4U));
uint8_t* buffer = __buffer.get();
::memset(buffer, 0x00U, 4U + (peers.size() * 4U)); ::memset(buffer, 0x00U, 4U + (peers.size() * 4U));
__SET_UINT32(peers.size(), buffer, 0U); __SET_UINT32(peers.size(), buffer, 0U);

@ -28,21 +28,41 @@ using namespace network::tcp;
Socket::Socket() : Socket::Socket() :
m_localAddress(), m_localAddress(),
m_localPort(0U), m_localPort(0U),
#if defined(_WIN32)
m_fd(INVALID_SOCKET),
#else
m_fd(-1), m_fd(-1),
#endif // defined(_WIN32)
m_counter(0U) m_counter(0U)
{ {
/* stub */ #if defined(_WIN32)
WSAData data;
int wsaRet = ::WSAStartup(MAKEWORD(2, 2), &data);
if (wsaRet != 0) {
::LogError(LOG_NET, "Error from WSAStartup, err: %d", wsaRet);
}
#endif // defined(_WIN32)
} }
/* Initializes a new instance of the Socket class. */ /* Initializes a new instance of the Socket class. */
#if defined(_WIN32)
Socket::Socket(const SOCKET fd) noexcept :
#else
Socket::Socket(const int fd) noexcept : Socket::Socket(const int fd) noexcept :
#endif // defined(_WIN32)
m_localAddress(), m_localAddress(),
m_localPort(0U), m_localPort(0U),
m_fd(fd), m_fd(fd),
m_counter(0U) m_counter(0U)
{ {
/* stub */ #if defined(_WIN32)
WSAData data;
int wsaRet = ::WSAStartup(MAKEWORD(2, 2), &data);
if (wsaRet != 0) {
::LogError(LOG_NET, "Error from WSAStartup, err: %d", wsaRet);
}
#endif // defined(_WIN32)
} }
/* Initializes a new instance of the Socket class. */ /* Initializes a new instance of the Socket class. */
@ -56,8 +76,18 @@ Socket::Socket(const int domain, const int type, const int protocol) : Socket()
Socket::~Socket() Socket::~Socket()
{ {
#if defined(_WIN32)
::shutdown(m_fd, SD_SEND);
if (m_fd != INVALID_SOCKET) {
::closesocket(m_fd);
m_fd = INVALID_SOCKET;
}
::WSACleanup();
#else
static_cast<void>(::shutdown(m_fd, SHUT_RDWR)); static_cast<void>(::shutdown(m_fd, SHUT_RDWR));
static_cast<void>(::close(m_fd)); static_cast<void>(::close(m_fd));
#endif // defined(_WIN32)
} }
/* Accepts a pending connection request. */ /* Accepts a pending connection request. */
@ -71,9 +101,17 @@ int Socket::accept(sockaddr* address, socklen_t* addrlen) noexcept
pfd.revents = 0; pfd.revents = 0;
// return immediately // return immediately
#if defined(_WIN32)
int ret = WSAPoll(&pfd, 1, 0);
#else
int ret = ::poll(&pfd, 1, 0); int ret = ::poll(&pfd, 1, 0);
#endif // defined(_WIN32)
if (ret < 0) { if (ret < 0) {
#if defined(_WIN32)
LogError(LOG_NET, "Error returned from TCP poll, err: %lu", ::GetLastError());
#else
LogError(LOG_NET, "Error returned from TCP poll, err: %d", errno); LogError(LOG_NET, "Error returned from TCP poll, err: %d", errno);
#endif // defined(_WIN32)
return -1; return -1;
} }
@ -133,9 +171,17 @@ ssize_t Socket::listen(const std::string& ipAddr, const uint16_t port, int backl
pfd.revents = 0; pfd.revents = 0;
// return immediately // return immediately
#if defined(_WIN32)
int ret = WSAPoll(&pfd, 1, 0);
#else
int ret = ::poll(&pfd, 1, 0); int ret = ::poll(&pfd, 1, 0);
#endif // defined(_WIN32)
if (ret < 0) { if (ret < 0) {
#if defined(_WIN32)
LogError(LOG_NET, "Error returned from TCP poll, err: %lu", ::GetLastError());
#else
LogError(LOG_NET, "Error returned from TCP poll, err: %d", errno); LogError(LOG_NET, "Error returned from TCP poll, err: %d", errno);
#endif // defined(_WIN32)
return -1; return -1;
} }
@ -143,7 +189,11 @@ ssize_t Socket::listen(const std::string& ipAddr, const uint16_t port, int backl
return 0; return 0;
m_counter++; m_counter++;
#if defined(_WIN32)
return ::recv(pfd.fd, (char*)buffer, length, 0);
#else
return ::read(pfd.fd, (char*)buffer, length); return ::read(pfd.fd, (char*)buffer, length);
#endif // defined(_WIN32)
} }
/* Write data to the socket. */ /* Write data to the socket. */
@ -156,7 +206,11 @@ ssize_t Socket::write(const uint8_t* buffer, size_t length) noexcept
if (m_fd < 0) if (m_fd < 0)
return -1; return -1;
#if defined(_WIN32)
return ::send(m_fd, (char*)buffer, length, 0);
#else
return ::send(m_fd, buffer, length, 0); return ::send(m_fd, buffer, length, 0);
#endif // defined(_WIN32)
} }
/* Gets the numeric representation of an address from a sockaddr_storage socket address structure. */ /* Gets the numeric representation of an address from a sockaddr_storage socket address structure. */
@ -255,10 +309,17 @@ bool Socket::isNone(const sockaddr_storage& addr)
bool Socket::initSocket(const int domain, const int type, const int protocol) bool Socket::initSocket(const int domain, const int type, const int protocol)
{ {
m_fd = ::socket(domain, type, protocol); m_fd = ::socket(domain, type, protocol);
#if defined(_WIN32)
if (m_fd == INVALID_SOCKET) {
LogError(LOG_NET, "Cannot create the TCP socket, err: %lu", ::GetLastError());
return false;
}
#else
if (m_fd < 0) { if (m_fd < 0) {
LogError(LOG_NET, "Cannot create the TCP socket, err: %d", errno); LogError(LOG_NET, "Cannot create the TCP socket, err: %d", errno);
return false; return false;
} }
#endif // defined(_WIN32)
return true; return true;
} }
@ -276,7 +337,11 @@ bool Socket::bind(const std::string& ipAddr, const uint16_t port)
socklen_t length = sizeof(addr); socklen_t length = sizeof(addr);
bool retval = true; bool retval = true;
if (::bind(m_fd, reinterpret_cast<sockaddr*>(&addr), length) < 0) { if (::bind(m_fd, reinterpret_cast<sockaddr*>(&addr), length) < 0) {
#if defined(_WIN32)
LogError(LOG_NET, "Cannot bind the TCP address, err: %lu", ::GetLastError());
#else
LogError(LOG_NET, "Cannot bind the TCP address, err: %d", errno); LogError(LOG_NET, "Cannot bind the TCP address, err: %d", errno);
#endif // defined(_WIN32)
retval = false; retval = false;
} }

@ -23,16 +23,28 @@
#include "Defines.h" #include "Defines.h"
#include "common/Log.h" #include "common/Log.h"
#if defined(_WIN32)
#include <ws2tcpip.h>
#include <Winsock2.h>
#else
#include <arpa/inet.h> #include <arpa/inet.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <netinet/tcp.h> #include <netinet/tcp.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <poll.h> #include <poll.h>
#include <unistd.h> #include <unistd.h>
#endif // defined(_WIN32)
#include <cstdlib> #include <cstdlib>
#include <ctime> #include <ctime>
#if defined(_WIN32)
#ifndef _SSIZE_T_DECLARED
typedef SSIZE_T ssize_t;
#define _SSIZE_T_DECLARED
#endif
#endif // defined(_WIN32)
namespace network namespace network
{ {
namespace tcp namespace tcp
@ -61,7 +73,11 @@ namespace network
* @brief Initializes a new instance of the Socket class. * @brief Initializes a new instance of the Socket class.
* @param fd File descriptor for existing socket. * @param fd File descriptor for existing socket.
*/ */
#if defined(_WIN32)
Socket(const SOCKET fd) noexcept;
#else
Socket(const int fd) noexcept; Socket(const int fd) noexcept;
#endif // defined(_WIN32)
/** /**
* @brief Initializes a new instance of the Socket class. * @brief Initializes a new instance of the Socket class.
* @param domain Address family type. * @param domain Address family type.
@ -142,7 +158,11 @@ namespace network
std::string m_localAddress; std::string m_localAddress;
uint16_t m_localPort; uint16_t m_localPort;
#if defined(_WIN32)
SOCKET m_fd;
#else
int m_fd; int m_fd;
#endif // defined(_WIN32)
uint32_t m_counter; uint32_t m_counter;

@ -53,7 +53,11 @@ namespace network
* @param client Address for client. * @param client Address for client.
* @param clientLen Length of sockaddr_in structure. * @param clientLen Length of sockaddr_in structure.
*/ */
#if defined(_WIN32)
TcpClient(const SOCKET fd, sockaddr_in& client, int clientLen) noexcept(false) : Socket(fd),
#else
TcpClient(const int fd, sockaddr_in& client, int clientLen) noexcept(false) : Socket(fd), TcpClient(const int fd, sockaddr_in& client, int clientLen) noexcept(false) : Socket(fd),
#endif // defined(_WIN32)
m_sockaddr() m_sockaddr()
{ {
::memcpy(reinterpret_cast<char*>(&m_sockaddr), reinterpret_cast<char*>(&client), clientLen); ::memcpy(reinterpret_cast<char*>(&m_sockaddr), reinterpret_cast<char*>(&client), clientLen);
@ -75,7 +79,11 @@ namespace network
int ret = ::connect(m_fd, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)); int ret = ::connect(m_fd, reinterpret_cast<sockaddr*>(&addr), sizeof(addr));
if (ret < 0) { if (ret < 0) {
#if defined(_WIN32)
LogError(LOG_NET, "Failed to connect to server, err: %lu", ::GetLastError());
#else
LogError(LOG_NET, "Failed to connect to server, err: %d", errno); LogError(LOG_NET, "Failed to connect to server, err: %d", errno);
#endif // defined(_WIN32)
} }
} }
@ -95,7 +103,11 @@ namespace network
{ {
int reuse = 1; int reuse = 1;
if (::setsockopt(m_fd, IPPROTO_TCP, TCP_NODELAY, (char*)& reuse, sizeof(reuse)) != 0) { if (::setsockopt(m_fd, IPPROTO_TCP, TCP_NODELAY, (char*)& reuse, sizeof(reuse)) != 0) {
#if defined(_WIN32)
LogError(LOG_NET, "Cannot set the TCP socket option, err: %lu", ::GetLastError());
#else
LogError(LOG_NET, "Cannot set the TCP socket option, err: %d", errno); LogError(LOG_NET, "Cannot set the TCP socket option, err: %d", errno);
#endif // defined(_WIN32)
throw std::runtime_error("Cannot set the TCP socket option"); throw std::runtime_error("Cannot set the TCP socket option");
} }
} }

@ -45,10 +45,17 @@ namespace network
TcpListener() noexcept(false) : Socket(AF_INET, SOCK_STREAM, 0) TcpListener() noexcept(false) : Socket(AF_INET, SOCK_STREAM, 0)
{ {
int reuse = 1; int reuse = 1;
#if defined(_WIN32)
if (::setsockopt(m_fd, SOL_SOCKET, SO_REUSEADDR, (char*)&reuse, sizeof(reuse)) != 0) {
LogError(LOG_NET, "Cannot set the TCP socket option, err: %lu", ::GetLastError());
throw std::runtime_error("Cannot set the TCP socket option");
}
#else
if (::setsockopt(m_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, (char*)& reuse, sizeof(reuse)) != 0) { if (::setsockopt(m_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, (char*)& reuse, sizeof(reuse)) != 0) {
LogError(LOG_NET, "Cannot set the TCP socket option, err: %d", errno); LogError(LOG_NET, "Cannot set the TCP socket option, err: %d", errno);
throw std::runtime_error("Cannot set the TCP socket option"); throw std::runtime_error("Cannot set the TCP socket option");
} }
#endif // defined(_WIN32)
} }
/** /**
* @brief Initializes a new instance of the TcpListener class. * @brief Initializes a new instance of the TcpListener class.
@ -58,7 +65,11 @@ namespace network
explicit TcpListener(const uint16_t port, const std::string& address = "0.0.0.0") noexcept(false) : TcpListener() explicit TcpListener(const uint16_t port, const std::string& address = "0.0.0.0") noexcept(false) : TcpListener()
{ {
if (!bind(address, port)) { if (!bind(address, port)) {
#if defined(_WIN32)
LogError(LOG_NET, "Cannot to bind TCP server, err: %lu", ::GetLastError());
#else
LogError(LOG_NET, "Cannot to bind TCP server, err: %d", errno); LogError(LOG_NET, "Cannot to bind TCP server, err: %d", errno);
#endif // defined(_WIN32)
throw std::runtime_error("Cannot to bind TCP server"); throw std::runtime_error("Cannot to bind TCP server");
} }
} }
@ -71,7 +82,11 @@ namespace network
TcpListener(const std::string& ipAddr, const uint16_t port, const int backlog) noexcept(false) : TcpListener(port, ipAddr) TcpListener(const std::string& ipAddr, const uint16_t port, const int backlog) noexcept(false) : TcpListener(port, ipAddr)
{ {
if (listen(ipAddr, port, backlog) < 0) { if (listen(ipAddr, port, backlog) < 0) {
#if defined(_WIN32)
LogError(LOG_NET, "Failed to listen on TCP server, err: %lu", ::GetLastError());
#else
LogError(LOG_NET, "Failed to listen on TCP server, err: %d", errno); LogError(LOG_NET, "Failed to listen on TCP server, err: %d", errno);
#endif // defined(_WIN32)
throw std::runtime_error("Failed to listen on TCP server."); throw std::runtime_error("Failed to listen on TCP server.");
} }
} }
@ -84,10 +99,17 @@ namespace network
{ {
sockaddr_in client = {}; sockaddr_in client = {};
socklen_t clientLen = sizeof(client); socklen_t clientLen = sizeof(client);
#if defined(_WIN32)
SOCKET fd = Socket::accept(reinterpret_cast<sockaddr*>(&client), &clientLen);
if (fd == INVALID_SOCKET) {
return nullptr;
}
#else
int fd = Socket::accept(reinterpret_cast<sockaddr*>(&client), &clientLen); int fd = Socket::accept(reinterpret_cast<sockaddr*>(&client), &clientLen);
if (fd < 0) { if (fd < 0) {
return nullptr; return nullptr;
} }
#endif // defined(_WIN32)
return new TcpClient(fd, client, clientLen); return new TcpClient(fd, client, clientLen);
} }

@ -20,7 +20,9 @@ using namespace network::udp;
#include <cerrno> #include <cerrno>
#include <cstring> #include <cstring>
#if !defined(_WIN32)
#include <ifaddrs.h> #include <ifaddrs.h>
#endif // !defined(_WIN32)
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Constants // Constants
@ -38,7 +40,11 @@ Socket::Socket(const std::string& address, uint16_t port) :
m_localAddress(address), m_localAddress(address),
m_localPort(port), m_localPort(port),
m_af(AF_UNSPEC), m_af(AF_UNSPEC),
#if defined(_WIN32)
m_fd(INVALID_SOCKET),
#else
m_fd(-1), m_fd(-1),
#endif // defined(_WIN32)
m_aes(nullptr), m_aes(nullptr),
m_isCryptoWrapped(false), m_isCryptoWrapped(false),
m_presharedKey(nullptr), m_presharedKey(nullptr),
@ -46,6 +52,14 @@ Socket::Socket(const std::string& address, uint16_t port) :
{ {
m_aes = new crypto::AES(crypto::AESKeyLength::AES_256); m_aes = new crypto::AES(crypto::AESKeyLength::AES_256);
m_presharedKey = new uint8_t[AES_WRAPPED_PCKT_KEY_LEN]; m_presharedKey = new uint8_t[AES_WRAPPED_PCKT_KEY_LEN];
#if defined(_WIN32)
WSAData data;
int wsaRet = ::WSAStartup(MAKEWORD(2, 2), &data);
if (wsaRet != 0) {
::LogError(LOG_NET, "Error from WSAStartup, err: %d", wsaRet);
}
#endif // defined(_WIN32)
} }
/* Initializes a new instance of the Socket class. */ /* Initializes a new instance of the Socket class. */
@ -54,7 +68,11 @@ Socket::Socket(uint16_t port) :
m_localAddress(), m_localAddress(),
m_localPort(port), m_localPort(port),
m_af(AF_UNSPEC), m_af(AF_UNSPEC),
#if defined(_WIN32)
m_fd(INVALID_SOCKET),
#else
m_fd(-1), m_fd(-1),
#endif // defined(_WIN32)
m_aes(nullptr), m_aes(nullptr),
m_isCryptoWrapped(false), m_isCryptoWrapped(false),
m_presharedKey(nullptr), m_presharedKey(nullptr),
@ -62,6 +80,14 @@ Socket::Socket(uint16_t port) :
{ {
m_aes = new crypto::AES(crypto::AESKeyLength::AES_256); m_aes = new crypto::AES(crypto::AESKeyLength::AES_256);
m_presharedKey = new uint8_t[AES_WRAPPED_PCKT_KEY_LEN]; m_presharedKey = new uint8_t[AES_WRAPPED_PCKT_KEY_LEN];
#if defined(_WIN32)
WSAData data;
int wsaRet = ::WSAStartup(MAKEWORD(2, 2), &data);
if (wsaRet != 0) {
::LogError(LOG_NET, "Error from WSAStartup, err: %d", wsaRet);
}
#endif // defined(_WIN32)
} }
/* Finalizes a instance of the Socket class. */ /* Finalizes a instance of the Socket class. */
@ -72,6 +98,10 @@ Socket::~Socket()
delete m_aes; delete m_aes;
if (m_presharedKey != nullptr) if (m_presharedKey != nullptr)
delete[] m_presharedKey; delete[] m_presharedKey;
#if defined(_WIN32)
::WSACleanup();
#endif // defined(_WIN32)
} }
/* Opens UDP socket connection. */ /* Opens UDP socket connection. */
@ -133,10 +163,17 @@ bool Socket::open(const uint32_t af, const std::string& address, const uint16_t
void Socket::close() void Socket::close()
{ {
#if defined(_WIN32)
if (m_fd != INVALID_SOCKET) {
::closesocket(m_fd);
m_fd = INVALID_SOCKET;
}
#else
if (m_fd >= 0) { if (m_fd >= 0) {
::close(m_fd); ::close(m_fd);
m_fd = -1; m_fd = -1;
} }
#endif // defined(_WIN32)
} }
/* Read data from the UDP socket. */ /* Read data from the UDP socket. */
@ -146,8 +183,13 @@ ssize_t Socket::read(uint8_t* buffer, uint32_t length, sockaddr_storage& address
assert(buffer != nullptr); assert(buffer != nullptr);
assert(length > 0U); assert(length > 0U);
#if defined(_WIN32)
if (m_fd == INVALID_SOCKET)
return -1;
#else
if (m_fd < 0) if (m_fd < 0)
return -1; return -1;
#endif // defined(_WIN32)
// check that the readfrom() won't block // check that the readfrom() won't block
struct pollfd pfd; struct pollfd pfd;
@ -156,9 +198,17 @@ ssize_t Socket::read(uint8_t* buffer, uint32_t length, sockaddr_storage& address
pfd.revents = 0; pfd.revents = 0;
// return immediately // return immediately
#if defined(_WIN32)
int ret = WSAPoll(&pfd, 1, 0);
#else
int ret = ::poll(&pfd, 1, 0); int ret = ::poll(&pfd, 1, 0);
#endif // defined(_WIN32)
if (ret < 0) { if (ret < 0) {
#if defined(_WIN32)
LogError(LOG_NET, "Error returned from UDP poll, err: %lu", ::GetLastError());
#else
LogError(LOG_NET, "Error returned from UDP poll, err: %d", errno); LogError(LOG_NET, "Error returned from UDP poll, err: %d", errno);
#endif // defined(_WIN32)
return -1; return -1;
} }
@ -168,7 +218,11 @@ ssize_t Socket::read(uint8_t* buffer, uint32_t length, sockaddr_storage& address
socklen_t size = sizeof(sockaddr_storage); socklen_t size = sizeof(sockaddr_storage);
ssize_t len = ::recvfrom(pfd.fd, (char*)buffer, length, 0, (sockaddr*)& address, &size); ssize_t len = ::recvfrom(pfd.fd, (char*)buffer, length, 0, (sockaddr*)& address, &size);
if (len <= 0) { if (len <= 0) {
#if defined(_WIN32)
LogError(LOG_NET, "Error returned from recvfrom, err: %lu", ::GetLastError());
#else
LogError(LOG_NET, "Error returned from recvfrom, err: %d", errno); LogError(LOG_NET, "Error returned from recvfrom, err: %d", errno);
#endif // defined(_WIN32)
if (len == -1 && errno == ENOTSOCK) { if (len == -1 && errno == ENOTSOCK) {
LogMessage(LOG_NET, "Re-opening UDP port on %u", m_localPort); LogMessage(LOG_NET, "Re-opening UDP port on %u", m_localPort);
@ -239,6 +293,16 @@ bool Socket::write(const uint8_t* buffer, uint32_t length, const sockaddr_storag
assert(buffer != nullptr); assert(buffer != nullptr);
assert(length > 0U); assert(length > 0U);
#if defined(_WIN32)
if (m_fd == INVALID_SOCKET) {
if (lenWritten != nullptr) {
*lenWritten = -1;
}
//LogError(LOG_NET, "tried to write datagram with no file descriptor? this shouldn't happen BUGBUG");
return false;
}
#else
if (m_fd < 0) { if (m_fd < 0) {
if (lenWritten != nullptr) { if (lenWritten != nullptr) {
*lenWritten = -1; *lenWritten = -1;
@ -247,6 +311,7 @@ bool Socket::write(const uint8_t* buffer, uint32_t length, const sockaddr_storag
//LogError(LOG_NET, "tried to write datagram with no file descriptor? this shouldn't happen BUGBUG"); //LogError(LOG_NET, "tried to write datagram with no file descriptor? this shouldn't happen BUGBUG");
return false; return false;
} }
#endif // defined(_WIN32)
bool result = false; bool result = false;
UInt8Array out = nullptr; UInt8Array out = nullptr;
@ -301,7 +366,11 @@ bool Socket::write(const uint8_t* buffer, uint32_t length, const sockaddr_storag
ssize_t sent = ::sendto(m_fd, (char*)out.get(), length, 0, (sockaddr*)& address, addrLen); ssize_t sent = ::sendto(m_fd, (char*)out.get(), length, 0, (sockaddr*)& address, addrLen);
if (sent < 0) { if (sent < 0) {
#if defined(_WIN32)
LogError(LOG_NET, "Error returned from sendto, err: %lu", ::GetLastError());
#else
LogError(LOG_NET, "Error returned from sendto, err: %d", errno); LogError(LOG_NET, "Error returned from sendto, err: %d", errno);
#endif // defined(_WIN32)
if (lenWritten != nullptr) { if (lenWritten != nullptr) {
*lenWritten = -1; *lenWritten = -1;
@ -425,7 +494,8 @@ bool Socket::write(BufferVector& buffers, ssize_t* lenWritten) noexcept
// Utils::dump(1U, "Socket::write() crypted", crypted, cryptedLen); // Utils::dump(1U, "Socket::write() crypted", crypted, cryptedLen);
// finalize // finalize
uint8_t out[cryptedLen + 2U]; UInt8Array __outBuf = std::make_unique<uint8_t[]>(cryptedLen + 2U);
uint8_t* out = __outBuf.get();
::memcpy(out + 2U, crypted, cryptedLen); ::memcpy(out + 2U, crypted, cryptedLen);
__SET_UINT16B(AES_WRAPPED_PCKT_MAGIC, out, 0U); __SET_UINT16B(AES_WRAPPED_PCKT_MAGIC, out, 0U);
@ -558,6 +628,9 @@ int Socket::lookup(const std::string& hostname, uint16_t port, sockaddr_storage&
std::string Socket::getLocalAddress() std::string Socket::getLocalAddress()
{ {
#if defined(_WIN32)
return std::string(); // this breaks shit...
#else
struct ifaddrs *ifaddr, *ifa; struct ifaddrs *ifaddr, *ifa;
int n; int n;
char host[NI_MAXHOST]; char host[NI_MAXHOST];
@ -593,6 +666,7 @@ std::string Socket::getLocalAddress()
freeifaddrs(ifaddr); freeifaddrs(ifaddr);
return address; return address;
#endif // defined(_WIN32)
} }
/* */ /* */
@ -716,10 +790,17 @@ bool Socket::isNone(const sockaddr_storage& addr)
bool Socket::initSocket(const int domain, const int type, const int protocol) noexcept(false) bool Socket::initSocket(const int domain, const int type, const int protocol) noexcept(false)
{ {
m_fd = ::socket(domain, type, protocol); m_fd = ::socket(domain, type, protocol);
#if defined(_WIN32)
if (m_fd == INVALID_SOCKET) {
LogError(LOG_NET, "Cannot create the UDP socket, err: %lu", ::GetLastError());
return false;
}
#else
if (m_fd < 0) { if (m_fd < 0) {
LogError(LOG_NET, "Cannot create the UDP socket, err: %d", errno); LogError(LOG_NET, "Cannot create the UDP socket, err: %d", errno);
return false; return false;
} }
#endif // defined(_WIN32)
m_af = domain; m_af = domain;
return true; return true;
@ -738,7 +819,11 @@ bool Socket::bind(const std::string& ipAddr, const uint16_t port) noexcept(false
socklen_t length = sizeof(addr); socklen_t length = sizeof(addr);
bool retval = true; bool retval = true;
if (::bind(m_fd, reinterpret_cast<sockaddr*>(&addr), length) < 0) { if (::bind(m_fd, reinterpret_cast<sockaddr*>(&addr), length) < 0) {
#if defined(_WIN32)
LogError(LOG_NET, "Cannot bind the UDP address, err: %lu", ::GetLastError());
#else
LogError(LOG_NET, "Cannot bind the UDP address, err: %d", errno); LogError(LOG_NET, "Cannot bind the UDP address, err: %d", errno);
#endif // defined(_WIN32)
retval = false; retval = false;
} }

@ -27,6 +27,11 @@
#include <string> #include <string>
#include <vector> #include <vector>
#if defined(_WIN32)
#pragma comment(lib, "Ws2_32.lib")
#include <ws2tcpip.h>
#include <Winsock2.h>
#else
#include <netdb.h> #include <netdb.h>
#include <sys/time.h> #include <sys/time.h>
#include <sys/types.h> #include <sys/types.h>
@ -36,6 +41,7 @@
#include <netinet/in.h> #include <netinet/in.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include <errno.h> #include <errno.h>
#endif // defined(_WIN32)
#define AES_WRAPPED_PCKT_MAGIC 0xC0FEU #define AES_WRAPPED_PCKT_MAGIC 0xC0FEU
#define AES_WRAPPED_PCKT_KEY_LEN 32 #define AES_WRAPPED_PCKT_KEY_LEN 32
@ -49,6 +55,13 @@ enum IPMATCHTYPE {
IMT_ADDRESS_ONLY //! Address Only IMT_ADDRESS_ONLY //! Address Only
}; };
#if defined(_WIN32)
#ifndef _SSIZE_T_DECLARED
typedef SSIZE_T ssize_t;
#define _SSIZE_T_DECLARED
#endif
#endif // defined(_WIN32)
namespace network namespace network
{ {
namespace udp namespace udp
@ -83,6 +96,60 @@ namespace network
} }
/** \endcond */ /** \endcond */
#endif #endif
#if defined(_WIN32)
/** \cond */
/* Structure for scatter/gather I/O. */
struct iovec {
void* iov_base; /* Pointer to data. */
size_t iov_len; /* Length of data. */
};
/* Structure describing messages sent by
`sendmsg' and received by `recvmsg'. */
struct msghdr {
void* msg_name; /* Address to send to/receive from. */
socklen_t msg_namelen; /* Length of address data. */
struct iovec* msg_iov; /* Vector of data to send/receive into. */
size_t msg_iovlen; /* Number of elements in the vector. */
void* msg_control; /* Ancillary data (eg BSD filedesc passing). */
size_t msg_controllen; /* Ancillary data buffer length.
!! The type should be socklen_t but the
definition of the kernel is incompatible
with this. */
int msg_flags; /* Flags on received message. */
};
/* For `sendmmsg'. */
struct mmsghdr {
struct msghdr msg_hdr; /* Actual message header. */
unsigned int msg_len; /* Number of received or sent bytes for the entry. */
};
/* Send a VLEN messages as described by VMESSAGES to socket FD.
Returns the number of datagrams successfully written or -1 for errors.
This function is a cancellation point and therefore not marked with
__THROW. */
static inline int sendmmsg(SOCKET sockfd, struct mmsghdr* msgvec, unsigned int vlen, int flags)
{
ssize_t n = 0;
for (unsigned int i = 0; i < vlen; i++) {
ssize_t ret = ::sendto(sockfd, (char*)&msgvec[i].msg_hdr.msg_iov->iov_base, msgvec[i].msg_hdr.msg_iov->iov_len, 0, (sockaddr*)&msgvec[i].msg_hdr.msg_name, msgvec[i].msg_hdr.msg_namelen);
if (ret < 0)
break;
n += ret;
}
if (n == 0)
return -1;
return int(n);
}
/** \endcond */
#endif
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Structure Declaration // Structure Declaration
@ -253,7 +320,11 @@ namespace network
uint16_t m_localPort; uint16_t m_localPort;
uint32_t m_af; uint32_t m_af;
#if defined(_WIN32)
SOCKET m_fd;
#else
int m_fd; int m_fd;
#endif // defined(_WIN32)
crypto::AES* m_aes; crypto::AES* m_aes;
bool m_isCryptoWrapped; bool m_isCryptoWrapped;

@ -7,6 +7,7 @@
* Copyright (C) 2024 Bryan Biedenkapp, N2PLL * Copyright (C) 2024 Bryan Biedenkapp, N2PLL
* *
*/ */
#if !defined(_WIN32)
#include "Defines.h" #include "Defines.h"
#include "network/viface/VIFace.h" #include "network/viface/VIFace.h"
#include "Log.h" #include "Log.h"
@ -725,3 +726,4 @@ std::string VIFace::ioctlGetIPv4(uint64_t request) const
return std::string(addr); return std::string(addr);
} }
#endif // !defined(_WIN32)

@ -19,6 +19,7 @@
*/ */
#if !defined(__VIFACE_H__) #if !defined(__VIFACE_H__)
#define __VIFACE_H__ #define __VIFACE_H__
#if !defined(_WIN32)
#include "common/Defines.h" #include "common/Defines.h"
@ -244,4 +245,5 @@ namespace network
} // namespace viface } // namespace viface
} // namespace network } // namespace network
#endif // !defined(WIN32)
#endif // __VIFACE_H__ #endif // __VIFACE_H__

@ -323,7 +323,8 @@ void LC::encodeLDU1(uint8_t* data, const uint8_t* imbe)
// encode RS (24,12,13) FEC // encode RS (24,12,13) FEC
m_rs.encode241213(rs); m_rs.encode241213(rs);
uint8_t dfsiFrame[frameLength]; UInt8Array __dfsiFrame = std::make_unique<uint8_t[]>(frameLength);
uint8_t* dfsiFrame = __dfsiFrame.get();
dfsiFrame[0U] = m_frameType; // Frame Type dfsiFrame[0U] = m_frameType; // Frame Type
@ -563,7 +564,8 @@ void LC::encodeLDU2(uint8_t* data, const uint8_t* imbe)
// encode RS (24,16,9) FEC // encode RS (24,16,9) FEC
m_rs.encode24169(rs); m_rs.encode24169(rs);
uint8_t dfsiFrame[frameLength]; UInt8Array __dfsiFrame = std::make_unique<uint8_t[]>(frameLength);
uint8_t* dfsiFrame = __dfsiFrame.get();
dfsiFrame[0U] = m_frameType; // Frame Type dfsiFrame[0U] = m_frameType; // Frame Type

@ -34,7 +34,8 @@ bool MBT_IOSP_ACK_RSP::decodeMBT(const data::DataHeader& dataHeader, const data:
{ {
assert(blocks != nullptr); assert(blocks != nullptr);
uint8_t pduUserData[P25_PDU_UNCONFIRMED_LENGTH_BYTES * dataHeader.getBlocksToFollow()]; UInt8Array __pduUserData = std::make_unique<uint8_t[]>(P25_PDU_UNCONFIRMED_LENGTH_BYTES * dataHeader.getBlocksToFollow());
uint8_t* pduUserData = __pduUserData.get();
::memset(pduUserData, 0x00U, P25_PDU_UNCONFIRMED_LENGTH_BYTES * dataHeader.getBlocksToFollow()); ::memset(pduUserData, 0x00U, P25_PDU_UNCONFIRMED_LENGTH_BYTES * dataHeader.getBlocksToFollow());
bool ret = AMBT::decode(dataHeader, blocks, pduUserData); bool ret = AMBT::decode(dataHeader, blocks, pduUserData);

@ -34,7 +34,8 @@ bool MBT_IOSP_CALL_ALRT::decodeMBT(const data::DataHeader& dataHeader, const dat
{ {
assert(blocks != nullptr); assert(blocks != nullptr);
uint8_t pduUserData[P25_PDU_UNCONFIRMED_LENGTH_BYTES * dataHeader.getBlocksToFollow()]; UInt8Array __pduUserData = std::make_unique<uint8_t[]>(P25_PDU_UNCONFIRMED_LENGTH_BYTES * dataHeader.getBlocksToFollow());
uint8_t* pduUserData = __pduUserData.get();
::memset(pduUserData, 0x00U, P25_PDU_UNCONFIRMED_LENGTH_BYTES * dataHeader.getBlocksToFollow()); ::memset(pduUserData, 0x00U, P25_PDU_UNCONFIRMED_LENGTH_BYTES * dataHeader.getBlocksToFollow());
bool ret = AMBT::decode(dataHeader, blocks, pduUserData); bool ret = AMBT::decode(dataHeader, blocks, pduUserData);

@ -35,7 +35,8 @@ bool MBT_IOSP_EXT_FNCT::decodeMBT(const data::DataHeader& dataHeader, const data
{ {
assert(blocks != nullptr); assert(blocks != nullptr);
uint8_t pduUserData[P25_PDU_UNCONFIRMED_LENGTH_BYTES * dataHeader.getBlocksToFollow()]; UInt8Array __pduUserData = std::make_unique<uint8_t[]>(P25_PDU_UNCONFIRMED_LENGTH_BYTES * dataHeader.getBlocksToFollow());
uint8_t* pduUserData = __pduUserData.get();
::memset(pduUserData, 0x00U, P25_PDU_UNCONFIRMED_LENGTH_BYTES * dataHeader.getBlocksToFollow()); ::memset(pduUserData, 0x00U, P25_PDU_UNCONFIRMED_LENGTH_BYTES * dataHeader.getBlocksToFollow());
bool ret = AMBT::decode(dataHeader, blocks, pduUserData); bool ret = AMBT::decode(dataHeader, blocks, pduUserData);

@ -35,7 +35,8 @@ bool MBT_IOSP_GRP_AFF::decodeMBT(const data::DataHeader& dataHeader, const data:
{ {
assert(blocks != nullptr); assert(blocks != nullptr);
uint8_t pduUserData[P25_PDU_UNCONFIRMED_LENGTH_BYTES * dataHeader.getBlocksToFollow()]; UInt8Array __pduUserData = std::make_unique<uint8_t[]>(P25_PDU_UNCONFIRMED_LENGTH_BYTES * dataHeader.getBlocksToFollow());
uint8_t* pduUserData = __pduUserData.get();
::memset(pduUserData, 0x00U, P25_PDU_UNCONFIRMED_LENGTH_BYTES * dataHeader.getBlocksToFollow()); ::memset(pduUserData, 0x00U, P25_PDU_UNCONFIRMED_LENGTH_BYTES * dataHeader.getBlocksToFollow());
bool ret = AMBT::decode(dataHeader, blocks, pduUserData); bool ret = AMBT::decode(dataHeader, blocks, pduUserData);

@ -35,7 +35,8 @@ bool MBT_IOSP_MSG_UPDT::decodeMBT(const data::DataHeader& dataHeader, const data
{ {
assert(blocks != nullptr); assert(blocks != nullptr);
uint8_t pduUserData[P25_PDU_UNCONFIRMED_LENGTH_BYTES * dataHeader.getBlocksToFollow()]; UInt8Array __pduUserData = std::make_unique<uint8_t[]>(P25_PDU_UNCONFIRMED_LENGTH_BYTES * dataHeader.getBlocksToFollow());
uint8_t* pduUserData = __pduUserData.get();
::memset(pduUserData, 0x00U, P25_PDU_UNCONFIRMED_LENGTH_BYTES * dataHeader.getBlocksToFollow()); ::memset(pduUserData, 0x00U, P25_PDU_UNCONFIRMED_LENGTH_BYTES * dataHeader.getBlocksToFollow());
bool ret = AMBT::decode(dataHeader, blocks, pduUserData); bool ret = AMBT::decode(dataHeader, blocks, pduUserData);

@ -35,7 +35,8 @@ bool MBT_IOSP_STS_UPDT::decodeMBT(const data::DataHeader& dataHeader, const data
{ {
assert(blocks != nullptr); assert(blocks != nullptr);
uint8_t pduUserData[P25_PDU_UNCONFIRMED_LENGTH_BYTES * dataHeader.getBlocksToFollow()]; UInt8Array __pduUserData = std::make_unique<uint8_t[]>(P25_PDU_UNCONFIRMED_LENGTH_BYTES * dataHeader.getBlocksToFollow());
uint8_t* pduUserData = __pduUserData.get();
::memset(pduUserData, 0x00U, P25_PDU_UNCONFIRMED_LENGTH_BYTES * dataHeader.getBlocksToFollow()); ::memset(pduUserData, 0x00U, P25_PDU_UNCONFIRMED_LENGTH_BYTES * dataHeader.getBlocksToFollow());
bool ret = AMBT::decode(dataHeader, blocks, pduUserData); bool ret = AMBT::decode(dataHeader, blocks, pduUserData);

@ -56,7 +56,8 @@ bool MBT_ISP_AUTH_RESP_M::decodeMBT(const data::DataHeader& dataHeader, const da
{ {
assert(blocks != nullptr); assert(blocks != nullptr);
uint8_t pduUserData[P25_PDU_UNCONFIRMED_LENGTH_BYTES * dataHeader.getBlocksToFollow()]; UInt8Array __pduUserData = std::make_unique<uint8_t[]>(P25_PDU_UNCONFIRMED_LENGTH_BYTES * dataHeader.getBlocksToFollow());
uint8_t* pduUserData = __pduUserData.get();
::memset(pduUserData, 0x00U, P25_PDU_UNCONFIRMED_LENGTH_BYTES * dataHeader.getBlocksToFollow()); ::memset(pduUserData, 0x00U, P25_PDU_UNCONFIRMED_LENGTH_BYTES * dataHeader.getBlocksToFollow());
bool ret = AMBT::decode(dataHeader, blocks, pduUserData); bool ret = AMBT::decode(dataHeader, blocks, pduUserData);

@ -34,7 +34,8 @@ bool MBT_ISP_AUTH_SU_DMD::decodeMBT(const data::DataHeader& dataHeader, const da
{ {
assert(blocks != nullptr); assert(blocks != nullptr);
uint8_t pduUserData[P25_PDU_UNCONFIRMED_LENGTH_BYTES * dataHeader.getBlocksToFollow()]; UInt8Array __pduUserData = std::make_unique<uint8_t[]>(P25_PDU_UNCONFIRMED_LENGTH_BYTES * dataHeader.getBlocksToFollow());
uint8_t* pduUserData = __pduUserData.get();
::memset(pduUserData, 0x00U, P25_PDU_UNCONFIRMED_LENGTH_BYTES * dataHeader.getBlocksToFollow()); ::memset(pduUserData, 0x00U, P25_PDU_UNCONFIRMED_LENGTH_BYTES * dataHeader.getBlocksToFollow());
bool ret = AMBT::decode(dataHeader, blocks, pduUserData); bool ret = AMBT::decode(dataHeader, blocks, pduUserData);

@ -34,7 +34,8 @@ bool MBT_ISP_CAN_SRV_REQ::decodeMBT(const data::DataHeader& dataHeader, const da
{ {
assert(blocks != nullptr); assert(blocks != nullptr);
uint8_t pduUserData[P25_PDU_UNCONFIRMED_LENGTH_BYTES * dataHeader.getBlocksToFollow()]; UInt8Array __pduUserData = std::make_unique<uint8_t[]>(P25_PDU_UNCONFIRMED_LENGTH_BYTES * dataHeader.getBlocksToFollow());
uint8_t* pduUserData = __pduUserData.get();
::memset(pduUserData, 0x00U, P25_PDU_UNCONFIRMED_LENGTH_BYTES * dataHeader.getBlocksToFollow()); ::memset(pduUserData, 0x00U, P25_PDU_UNCONFIRMED_LENGTH_BYTES * dataHeader.getBlocksToFollow());
bool ret = AMBT::decode(dataHeader, blocks, pduUserData); bool ret = AMBT::decode(dataHeader, blocks, pduUserData);

@ -34,7 +34,8 @@ bool MBT_ISP_GRP_AFF_Q_RSP::decodeMBT(const data::DataHeader& dataHeader, const
{ {
assert(blocks != nullptr); assert(blocks != nullptr);
uint8_t pduUserData[P25_PDU_UNCONFIRMED_LENGTH_BYTES * dataHeader.getBlocksToFollow()]; UInt8Array __pduUserData = std::make_unique<uint8_t[]>(P25_PDU_UNCONFIRMED_LENGTH_BYTES * dataHeader.getBlocksToFollow());
uint8_t* pduUserData = __pduUserData.get();
::memset(pduUserData, 0x00U, P25_PDU_UNCONFIRMED_LENGTH_BYTES * dataHeader.getBlocksToFollow()); ::memset(pduUserData, 0x00U, P25_PDU_UNCONFIRMED_LENGTH_BYTES * dataHeader.getBlocksToFollow());
bool ret = AMBT::decode(dataHeader, blocks, pduUserData); bool ret = AMBT::decode(dataHeader, blocks, pduUserData);

@ -195,7 +195,9 @@ int main(int argc, char** argv)
::signal(SIGINT, sigHandler); ::signal(SIGINT, sigHandler);
::signal(SIGTERM, sigHandler); ::signal(SIGTERM, sigHandler);
#if !defined(_WIN32)
::signal(SIGHUP, sigHandler); ::signal(SIGHUP, sigHandler);
#endif // !defined(_WIN32)
int ret = 0; int ret = 0;

@ -20,16 +20,20 @@
#include "FNEMain.h" #include "FNEMain.h"
using namespace network; using namespace network;
#if !defined(_WIN32)
using namespace network::viface; using namespace network::viface;
#endif // !defined(_WIN32)
using namespace lookups; using namespace lookups;
#include <cstdio> #include <cstdio>
#include <algorithm> #include <algorithm>
#include <functional> #include <functional>
#if !defined(_WIN32)
#include <sys/utsname.h> #include <sys/utsname.h>
#include <unistd.h> #include <unistd.h>
#include <pwd.h> #include <pwd.h>
#endif // !defined(_WIN32)
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Constants // Constants
@ -51,7 +55,9 @@ HostFNE::HostFNE(const std::string& confFile) :
m_diagNetwork(nullptr), m_diagNetwork(nullptr),
m_vtunEnabled(false), m_vtunEnabled(false),
m_packetDataMode(PacketDataMode::PROJECT25), m_packetDataMode(PacketDataMode::PROJECT25),
#if !defined(_WIN32)
m_tun(nullptr), m_tun(nullptr),
#endif // !defined(_WIN32)
m_dmrEnabled(false), m_dmrEnabled(false),
m_p25Enabled(false), m_p25Enabled(false),
m_nxdnEnabled(false), m_nxdnEnabled(false),
@ -106,6 +112,7 @@ int HostFNE::run()
::fatal("unable to open the activity log file\n"); ::fatal("unable to open the activity log file\n");
} }
#if !defined(_WIN32)
// handle POSIX process forking // handle POSIX process forking
if (m_daemon) { if (m_daemon) {
// create new process // create new process
@ -138,6 +145,7 @@ int HostFNE::run()
::close(STDOUT_FILENO); ::close(STDOUT_FILENO);
::close(STDERR_FILENO); ::close(STDERR_FILENO);
} }
#endif // !defined(_WIN32)
::LogInfo(__BANNER__ "\r\n" __PROG_NAME__ " " __VER__ " (built " __BUILD__ ")\r\n" \ ::LogInfo(__BANNER__ "\r\n" __PROG_NAME__ " " __VER__ " (built " __BUILD__ ")\r\n" \
"Copyright (c) 2017-2024 Bryan Biedenkapp, N2PLL and DVMProject (https://github.com/dvmproject) Authors.\r\n" \ "Copyright (c) 2017-2024 Bryan Biedenkapp, N2PLL and DVMProject (https://github.com/dvmproject) Authors.\r\n" \
@ -192,18 +200,22 @@ int HostFNE::run()
return EXIT_FAILURE; return EXIT_FAILURE;
if (!Thread::runAsThread(this, threadDiagNetwork)) if (!Thread::runAsThread(this, threadDiagNetwork))
return EXIT_FAILURE; return EXIT_FAILURE;
#if !defined(_WIN32)
if (!Thread::runAsThread(this, threadVirtualNetworking)) if (!Thread::runAsThread(this, threadVirtualNetworking))
return EXIT_FAILURE; return EXIT_FAILURE;
#endif // !defined(_WIN32)
/* /*
** Main execution loop ** Main execution loop
*/ */
#if defined(_WIN32)
::LogInfoEx(LOG_HOST, "[ OK ] FNE is up and running on Win32");
#else
struct utsname utsinfo; struct utsname utsinfo;
::memset(&utsinfo, 0, sizeof(utsinfo)); ::memset(&utsinfo, 0, sizeof(utsinfo));
::uname(&utsinfo); ::uname(&utsinfo);
::LogInfoEx(LOG_HOST, "[ OK ] FNE is up and running on %s %s %s", utsinfo.sysname, utsinfo.release, utsinfo.machine); ::LogInfoEx(LOG_HOST, "[ OK ] FNE is up and running on %s %s %s", utsinfo.sysname, utsinfo.release, utsinfo.machine);
#endif // defined(_WIN32)
while (!g_killed) { while (!g_killed) {
uint32_t ms = stopWatch.elapsed(); uint32_t ms = stopWatch.elapsed();
@ -277,7 +289,7 @@ int HostFNE::run()
m_peerListLookup->stop(); m_peerListLookup->stop();
delete m_peerListLookup; delete m_peerListLookup;
} }
#if !defined(_WIN32)
if (m_tun != nullptr) { if (m_tun != nullptr) {
if (m_tun->isUp()) { if (m_tun->isUp()) {
m_tun->down(); m_tun->down();
@ -285,7 +297,7 @@ int HostFNE::run()
delete m_tun; delete m_tun;
} }
#endif // !defined(_WIN32)
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
@ -581,7 +593,11 @@ void* HostFNE::threadMasterNetwork(void* arg)
{ {
thread_t* th = (thread_t*)arg; thread_t* th = (thread_t*)arg;
if (th != nullptr) { if (th != nullptr) {
#if defined(_WIN32)
::CloseHandle(th->thread);
#else
::pthread_detach(th->thread); ::pthread_detach(th->thread);
#endif // defined(_WIN32)
std::string threadName("fne:network-loop"); std::string threadName("fne:network-loop");
HostFNE* fne = static_cast<HostFNE*>(th->obj); HostFNE* fne = static_cast<HostFNE*>(th->obj);
@ -620,7 +636,11 @@ void* HostFNE::threadDiagNetwork(void* arg)
{ {
thread_t* th = (thread_t*)arg; thread_t* th = (thread_t*)arg;
if (th != nullptr) { if (th != nullptr) {
#if defined(_WIN32)
::CloseHandle(th->thread);
#else
::pthread_detach(th->thread); ::pthread_detach(th->thread);
#endif // defined(_WIN32)
std::string threadName("fne:diag-network-loop"); std::string threadName("fne:diag-network-loop");
HostFNE* fne = static_cast<HostFNE*>(th->obj); HostFNE* fne = static_cast<HostFNE*>(th->obj);
@ -764,7 +784,7 @@ bool HostFNE::createPeerNetworks()
bool HostFNE::createVirtualNetworking() bool HostFNE::createVirtualNetworking()
{ {
yaml::Node vtunConf = m_conf["vtun"]; yaml::Node vtunConf = m_conf["vtun"];
#if !defined(_WIN32)
bool vtunEnabled = vtunConf["enabled"].as<bool>(false); bool vtunEnabled = vtunConf["enabled"].as<bool>(false);
if (vtunEnabled) { if (vtunEnabled) {
m_vtunEnabled = vtunEnabled; m_vtunEnabled = vtunEnabled;
@ -798,10 +818,11 @@ bool HostFNE::createVirtualNetworking()
m_tun->up(); m_tun->up();
} }
#endif // !defined(_WIN32)
return true; return true;
} }
#if !defined(_WIN32)
/* Entry point to virtual networking thread. */ /* Entry point to virtual networking thread. */
void* HostFNE::threadVirtualNetworking(void* arg) void* HostFNE::threadVirtualNetworking(void* arg)
@ -860,6 +881,7 @@ void* HostFNE::threadVirtualNetworking(void* arg)
return nullptr; return nullptr;
} }
#endif // !defined(_WIN32)
/* Processes any peer network traffic. */ /* Processes any peer network traffic. */

@ -91,7 +91,9 @@ private:
bool m_vtunEnabled; bool m_vtunEnabled;
PacketDataMode m_packetDataMode; PacketDataMode m_packetDataMode;
#if !defined(_WIN32)
network::viface::VIFace* m_tun; network::viface::VIFace* m_tun;
#endif // !defined(_WIN32)
bool m_dmrEnabled; bool m_dmrEnabled;
bool m_p25Enabled; bool m_p25Enabled;
@ -153,13 +155,14 @@ private:
* @returns bool True, if network connectivity was initialized, otherwise false. * @returns bool True, if network connectivity was initialized, otherwise false.
*/ */
bool createVirtualNetworking(); bool createVirtualNetworking();
#if !defined(_WIN32)
/** /**
* @brief Entry point to virtual networking thread. * @brief Entry point to virtual networking thread.
* @param arg Instance of the thread_t structure. * @param arg Instance of the thread_t structure.
* @returns void* (Ignore) * @returns void* (Ignore)
*/ */
static void* threadVirtualNetworking(void* arg); static void* threadVirtualNetworking(void* arg);
#endif // !defined(_WIN32)
/** /**
* @brief Processes any peer network traffic. * @brief Processes any peer network traffic.
* @param peerNetwork Instance of PeerNetwork to process traffic for. * @param peerNetwork Instance of PeerNetwork to process traffic for.

@ -147,7 +147,11 @@ void* DiagNetwork::threadedNetworkRx(void* arg)
{ {
NetPacketRequest* req = (NetPacketRequest*)arg; NetPacketRequest* req = (NetPacketRequest*)arg;
if (req != nullptr) { if (req != nullptr) {
#if defined(_WIN32)
::CloseHandle(req->thread);
#else
::pthread_detach(req->thread); ::pthread_detach(req->thread);
#endif // defined(_WIN32)
FNENetwork* network = static_cast<FNENetwork*>(req->obj); FNENetwork* network = static_cast<FNENetwork*>(req->obj);
if (network == nullptr) { if (network == nullptr) {
@ -205,7 +209,8 @@ void* DiagNetwork::threadedNetworkRx(void* arg)
// validate peer (simple validation really) // validate peer (simple validation really)
if (connection->connected() && connection->address() == ip) { if (connection->connected() && connection->address() == ip) {
uint8_t rawPayload[req->length - 11U]; UInt8Array __rawPayload = std::make_unique<uint8_t[]>(req->length - 11U);
uint8_t* rawPayload = __rawPayload.get();
::memset(rawPayload, 0x00U, req->length - 11U); ::memset(rawPayload, 0x00U, req->length - 11U);
::memcpy(rawPayload, req->buffer + 11U, req->length - 11U); ::memcpy(rawPayload, req->buffer + 11U, req->length - 11U);
std::string payload(rawPayload, rawPayload + (req->length - 11U)); std::string payload(rawPayload, rawPayload + (req->length - 11U));
@ -239,7 +244,8 @@ void* DiagNetwork::threadedNetworkRx(void* arg)
// validate peer (simple validation really) // validate peer (simple validation really)
if (connection->connected() && connection->address() == ip) { if (connection->connected() && connection->address() == ip) {
uint8_t rawPayload[req->length - 11U]; UInt8Array __rawPayload = std::make_unique<uint8_t[]>(req->length - 11U);
uint8_t* rawPayload = __rawPayload.get();
::memset(rawPayload, 0x00U, req->length - 11U); ::memset(rawPayload, 0x00U, req->length - 11U);
::memcpy(rawPayload, req->buffer + 11U, req->length - 11U); ::memcpy(rawPayload, req->buffer + 11U, req->length - 11U);
std::string payload(rawPayload, rawPayload + (req->length - 11U)); std::string payload(rawPayload, rawPayload + (req->length - 11U));
@ -277,7 +283,8 @@ void* DiagNetwork::threadedNetworkRx(void* arg)
// validate peer (simple validation really) // validate peer (simple validation really)
if (connection->connected() && connection->address() == ip) { if (connection->connected() && connection->address() == ip) {
uint8_t rawPayload[req->length - 11U]; UInt8Array __rawPayload = std::make_unique<uint8_t[]>(req->length - 11U);
uint8_t* rawPayload = __rawPayload.get();
::memset(rawPayload, 0x00U, req->length - 11U); ::memset(rawPayload, 0x00U, req->length - 11U);
::memcpy(rawPayload, req->buffer + 11U, req->length - 11U); ::memcpy(rawPayload, req->buffer + 11U, req->length - 11U);
std::string payload(rawPayload, rawPayload + (req->length - 11U)); std::string payload(rawPayload, rawPayload + (req->length - 11U));

@ -366,7 +366,7 @@ void FNENetwork::close()
::memset(buffer, 0x00U, 1U); ::memset(buffer, 0x00U, 1U);
for (auto peer : m_peers) { for (auto peer : m_peers) {
writePeer(peer.first, { NET_FUNC::MST_CLOSING, NET_SUBFUNC::NOP }, buffer, 1U, (ushort)0U, 0U); writePeer(peer.first, { NET_FUNC::MST_CLOSING, NET_SUBFUNC::NOP }, buffer, 1U, (uint16_t)0U, 0U);
} }
} }
@ -387,7 +387,11 @@ void* FNENetwork::threadedNetworkRx(void* arg)
{ {
NetPacketRequest* req = (NetPacketRequest*)arg; NetPacketRequest* req = (NetPacketRequest*)arg;
if (req != nullptr) { if (req != nullptr) {
#if defined(_WIN32)
::CloseHandle(req->thread);
#else
::pthread_detach(req->thread); ::pthread_detach(req->thread);
#endif // defined(_WIN32)
uint64_t now = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count(); uint64_t now = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
@ -627,7 +631,8 @@ void* FNENetwork::threadedNetworkRx(void* arg)
if (connection->connectionState() == NET_STAT_WAITING_AUTHORISATION) { if (connection->connectionState() == NET_STAT_WAITING_AUTHORISATION) {
// get the hash from the frame message // get the hash from the frame message
uint8_t hash[req->length - 8U]; UInt8Array __hash = std::make_unique<uint8_t[]>(req->length - 8U);
uint8_t* hash = __hash.get();
::memset(hash, 0x00U, req->length - 8U); ::memset(hash, 0x00U, req->length - 8U);
::memcpy(hash, req->buffer + 8U, req->length - 8U); ::memcpy(hash, req->buffer + 8U, req->length - 8U);
@ -724,7 +729,8 @@ void* FNENetwork::threadedNetworkRx(void* arg)
connection->lastPing(now); connection->lastPing(now);
if (connection->connectionState() == NET_STAT_WAITING_CONFIG) { if (connection->connectionState() == NET_STAT_WAITING_CONFIG) {
uint8_t rawPayload[req->length - 8U]; UInt8Array __rawPayload = std::make_unique<uint8_t[]>(req->length - 8U);
uint8_t* rawPayload = __rawPayload.get();
::memset(rawPayload, 0x00U, req->length - 8U); ::memset(rawPayload, 0x00U, req->length - 8U);
::memcpy(rawPayload, req->buffer + 8U, req->length - 8U); ::memcpy(rawPayload, req->buffer + 8U, req->length - 8U);
std::string payload(rawPayload, rawPayload + (req->length - 8U)); std::string payload(rawPayload, rawPayload + (req->length - 8U));
@ -968,7 +974,8 @@ void* FNENetwork::threadedNetworkRx(void* arg)
// validate peer (simple validation really) // validate peer (simple validation really)
if (connection->connected() && connection->address() == ip) { if (connection->connected() && connection->address() == ip) {
uint8_t rawPayload[req->length - 11U]; UInt8Array __rawPayload = std::make_unique<uint8_t[]>(req->length - 11U);
uint8_t* rawPayload = __rawPayload.get();
::memset(rawPayload, 0x00U, req->length - 11U); ::memset(rawPayload, 0x00U, req->length - 11U);
::memcpy(rawPayload, req->buffer + 11U, req->length - 11U); ::memcpy(rawPayload, req->buffer + 11U, req->length - 11U);
std::string payload(rawPayload, rawPayload + (req->length - 11U)); std::string payload(rawPayload, rawPayload + (req->length - 11U));
@ -1002,7 +1009,8 @@ void* FNENetwork::threadedNetworkRx(void* arg)
// validate peer (simple validation really) // validate peer (simple validation really)
if (connection->connected() && connection->address() == ip) { if (connection->connected() && connection->address() == ip) {
uint8_t rawPayload[req->length - 11U]; UInt8Array __rawPayload = std::make_unique<uint8_t[]>(req->length - 11U);
uint8_t* rawPayload = __rawPayload.get();
::memset(rawPayload, 0x00U, req->length - 11U); ::memset(rawPayload, 0x00U, req->length - 11U);
::memcpy(rawPayload, req->buffer + 11U, req->length - 11U); ::memcpy(rawPayload, req->buffer + 11U, req->length - 11U);
std::string payload(rawPayload, rawPayload + (req->length - 11U)); std::string payload(rawPayload, rawPayload + (req->length - 11U));
@ -1379,7 +1387,11 @@ void* FNENetwork::threadedACLUpdate(void* arg)
{ {
ACLUpdateRequest* req = (ACLUpdateRequest*)arg; ACLUpdateRequest* req = (ACLUpdateRequest*)arg;
if (req != nullptr) { if (req != nullptr) {
#if defined(_WIN32)
::CloseHandle(req->thread);
#else
::pthread_detach(req->thread); ::pthread_detach(req->thread);
#endif // defined(_WIN32)
FNENetwork* network = static_cast<FNENetwork*>(req->obj); FNENetwork* network = static_cast<FNENetwork*>(req->obj);
if (network == nullptr) { if (network == nullptr) {
@ -1453,7 +1465,8 @@ void FNENetwork::writeWhitelistRIDs(uint32_t peerId)
// build dataset // build dataset
uint16_t bufSize = 4U + (listSize * 4U); uint16_t bufSize = 4U + (listSize * 4U);
uint8_t payload[bufSize]; UInt8Array __payload = std::make_unique<uint8_t[]>(bufSize);
uint8_t* payload = __payload.get();
::memset(payload, 0x00U, bufSize); ::memset(payload, 0x00U, bufSize);
__SET_UINT32(listSize, payload, 0U); __SET_UINT32(listSize, payload, 0U);
@ -1526,7 +1539,8 @@ void FNENetwork::writeBlacklistRIDs(uint32_t peerId)
// build dataset // build dataset
uint16_t bufSize = 4U + (listSize * 4U); uint16_t bufSize = 4U + (listSize * 4U);
uint8_t payload[bufSize]; UInt8Array __payload = std::make_unique<uint8_t[]>(bufSize);
uint8_t* payload = __payload.get();
::memset(payload, 0x00U, bufSize); ::memset(payload, 0x00U, bufSize);
__SET_UINT32(listSize, payload, 0U); __SET_UINT32(listSize, payload, 0U);
@ -1607,7 +1621,8 @@ void FNENetwork::writeTGIDs(uint32_t peerId)
} }
// build dataset // build dataset
uint8_t payload[4U + (tgidList.size() * 5U)]; UInt8Array __payload = std::make_unique<uint8_t[]>(4U + (tgidList.size() * 5U));
uint8_t* payload = __payload.get();
::memset(payload, 0x00U, 4U + (tgidList.size() * 5U)); ::memset(payload, 0x00U, 4U + (tgidList.size() * 5U));
__SET_UINT32(tgidList.size(), payload, 0U); __SET_UINT32(tgidList.size(), payload, 0U);
@ -1667,7 +1682,8 @@ void FNENetwork::writeDeactiveTGIDs(uint32_t peerId)
} }
// build dataset // build dataset
uint8_t payload[4U + (tgidList.size() * 5U)]; UInt8Array __payload = std::make_unique<uint8_t[]>(4U + (tgidList.size() * 5U));
uint8_t* payload = __payload.get();
::memset(payload, 0x00U, 4U + (tgidList.size() * 5U)); ::memset(payload, 0x00U, 4U + (tgidList.size() * 5U));
__SET_UINT32(tgidList.size(), payload, 0U); __SET_UINT32(tgidList.size(), payload, 0U);

@ -101,7 +101,8 @@ bool PeerNetwork::writeConfig()
json::value v = json::value(config); json::value v = json::value(config);
std::string json = v.serialize(); std::string json = v.serialize();
char buffer[json.length() + 9U]; CharArray __buffer = std::make_unique<char[]>(json.length() + 9U);
char* buffer = __buffer.get();
::memcpy(buffer + 0U, TAG_REPEATER_CONFIG, 4U); ::memcpy(buffer + 0U, TAG_REPEATER_CONFIG, 4U);
::snprintf(buffer + 8U, json.length() + 1U, "%s", json.c_str()); ::snprintf(buffer + 8U, json.length() + 1U, "%s", json.c_str());

@ -61,7 +61,8 @@ bool TagDMRData::processFrame(const uint8_t* data, uint32_t len, uint32_t peerId
{ {
hrc::hrc_t pktTime = hrc::now(); hrc::hrc_t pktTime = hrc::now();
uint8_t buffer[len]; UInt8Array __buffer = std::make_unique<uint8_t[]>(len);
uint8_t* buffer = __buffer.get();
::memset(buffer, 0x00U, len); ::memset(buffer, 0x00U, len);
::memcpy(buffer, data, len); ::memcpy(buffer, data, len);
@ -275,7 +276,8 @@ bool TagDMRData::processFrame(const uint8_t* data, uint32_t len, uint32_t peerId
m_network->m_frameQueue->flushQueue(); m_network->m_frameQueue->flushQueue();
} }
uint8_t outboundPeerBuffer[len]; UInt8Array __outboundPeerBuffer = std::make_unique<uint8_t[]>(len);
uint8_t* outboundPeerBuffer = __outboundPeerBuffer.get();
::memset(outboundPeerBuffer, 0x00U, len); ::memset(outboundPeerBuffer, 0x00U, len);
::memcpy(outboundPeerBuffer, buffer, len); ::memcpy(outboundPeerBuffer, buffer, len);
@ -319,7 +321,8 @@ bool TagDMRData::processFrame(const uint8_t* data, uint32_t len, uint32_t peerId
continue; continue;
} }
uint8_t outboundPeerBuffer[len]; UInt8Array __outboundPeerBuffer = std::make_unique<uint8_t[]>(len);
uint8_t* outboundPeerBuffer = __outboundPeerBuffer.get();
::memset(outboundPeerBuffer, 0x00U, len); ::memset(outboundPeerBuffer, 0x00U, len);
::memcpy(outboundPeerBuffer, buffer, len); ::memcpy(outboundPeerBuffer, buffer, len);

@ -57,7 +57,8 @@ bool TagNXDNData::processFrame(const uint8_t* data, uint32_t len, uint32_t peerI
{ {
hrc::hrc_t pktTime = hrc::now(); hrc::hrc_t pktTime = hrc::now();
uint8_t buffer[len]; UInt8Array __buffer = std::make_unique<uint8_t[]>(len);
uint8_t* buffer = __buffer.get();
::memset(buffer, 0x00U, len); ::memset(buffer, 0x00U, len);
::memcpy(buffer, data, len); ::memcpy(buffer, data, len);
@ -228,7 +229,8 @@ bool TagNXDNData::processFrame(const uint8_t* data, uint32_t len, uint32_t peerI
m_network->m_frameQueue->flushQueue(); m_network->m_frameQueue->flushQueue();
} }
uint8_t outboundPeerBuffer[len]; UInt8Array __outboundPeerBuffer = std::make_unique<uint8_t[]>(len);
uint8_t* outboundPeerBuffer = __outboundPeerBuffer.get();
::memset(outboundPeerBuffer, 0x00U, len); ::memset(outboundPeerBuffer, 0x00U, len);
::memcpy(outboundPeerBuffer, buffer, len); ::memcpy(outboundPeerBuffer, buffer, len);
@ -272,7 +274,8 @@ bool TagNXDNData::processFrame(const uint8_t* data, uint32_t len, uint32_t peerI
continue; continue;
} }
uint8_t outboundPeerBuffer[len]; UInt8Array __outboundPeerBuffer = std::make_unique<uint8_t[]>(len);
uint8_t* outboundPeerBuffer = __outboundPeerBuffer.get();
::memset(outboundPeerBuffer, 0x00U, len); ::memset(outboundPeerBuffer, 0x00U, len);
::memcpy(outboundPeerBuffer, buffer, len); ::memcpy(outboundPeerBuffer, buffer, len);

@ -67,7 +67,8 @@ bool TagP25Data::processFrame(const uint8_t* data, uint32_t len, uint32_t peerId
{ {
hrc::hrc_t pktTime = hrc::now(); hrc::hrc_t pktTime = hrc::now();
uint8_t buffer[len]; UInt8Array __buffer = std::make_unique<uint8_t[]>(len);
uint8_t* buffer = __buffer.get();
::memset(buffer, 0x00U, len); ::memset(buffer, 0x00U, len);
::memcpy(buffer, data, len); ::memcpy(buffer, data, len);
@ -309,7 +310,8 @@ bool TagP25Data::processFrame(const uint8_t* data, uint32_t len, uint32_t peerId
m_network->m_frameQueue->flushQueue(); m_network->m_frameQueue->flushQueue();
} }
uint8_t outboundPeerBuffer[len]; UInt8Array __outboundPeerBuffer = std::make_unique<uint8_t[]>(len);
uint8_t* outboundPeerBuffer = __outboundPeerBuffer.get();
::memset(outboundPeerBuffer, 0x00U, len); ::memset(outboundPeerBuffer, 0x00U, len);
::memcpy(outboundPeerBuffer, buffer, len); ::memcpy(outboundPeerBuffer, buffer, len);
@ -353,7 +355,8 @@ bool TagP25Data::processFrame(const uint8_t* data, uint32_t len, uint32_t peerId
continue; continue;
} }
uint8_t outboundPeerBuffer[len]; UInt8Array __outboundPeerBuffer = std::make_unique<uint8_t[]>(len);
uint8_t* outboundPeerBuffer = __outboundPeerBuffer.get();
::memset(outboundPeerBuffer, 0x00U, len); ::memset(outboundPeerBuffer, 0x00U, len);
::memcpy(outboundPeerBuffer, buffer, len); ::memcpy(outboundPeerBuffer, buffer, len);

@ -30,7 +30,9 @@ using namespace p25::sndcp;
#include <cassert> #include <cassert>
#include <chrono> #include <chrono>
#if !defined(_WIN32)
#include <netinet/ip.h> #include <netinet/ip.h>
#endif // !defined(_WIN32)
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Static Class Members // Static Class Members
@ -318,6 +320,7 @@ bool P25PacketData::processFrame(const uint8_t* data, uint32_t len, uint32_t pee
void P25PacketData::processPacketFrame(const uint8_t* data, uint32_t len, bool alreadyQueued) void P25PacketData::processPacketFrame(const uint8_t* data, uint32_t len, bool alreadyQueued)
{ {
#if !defined(_WIN32)
struct ip* ipHeader = (struct ip*)data; struct ip* ipHeader = (struct ip*)data;
char srcIp[INET_ADDRSTRLEN]; char srcIp[INET_ADDRSTRLEN];
@ -357,7 +360,8 @@ void P25PacketData::processPacketFrame(const uint8_t* data, uint32_t len, bool a
rspHeader.calculateLength(pktLen); rspHeader.calculateLength(pktLen);
uint32_t pduLength = rspHeader.getPDULength(); uint32_t pduLength = rspHeader.getPDULength();
uint8_t pduUserData[pduLength]; UInt8Array __pduUserData = std::make_unique<uint8_t[]>(pduLength);
uint8_t* pduUserData = __pduUserData.get();
::memset(pduUserData, 0x00U, pduLength); ::memset(pduUserData, 0x00U, pduLength);
::memcpy(pduUserData + 4U, data, pktLen); ::memcpy(pduUserData + 4U, data, pktLen);
#if DEBUG_P25_PDU_DATA #if DEBUG_P25_PDU_DATA
@ -367,6 +371,7 @@ void P25PacketData::processPacketFrame(const uint8_t* data, uint32_t len, bool a
} }
Thread::sleep(1750); Thread::sleep(1750);
#endif // !defined(_WIN32)
} }
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@ -402,6 +407,7 @@ void P25PacketData::dispatch(uint32_t peerId)
switch (sap) { switch (sap) {
case PDUSAP::ARP: case PDUSAP::ARP:
{ {
#if !defined(_WIN32)
// is the host virtual tunneling enabled? // is the host virtual tunneling enabled?
if (!m_network->m_host->m_vtunEnabled) if (!m_network->m_host->m_vtunEnabled)
break; break;
@ -433,10 +439,14 @@ void P25PacketData::dispatch(uint32_t peerId)
m_arpTable[srcHWAddr] = srcProtoAddr; m_arpTable[srcHWAddr] = srcProtoAddr;
} }
} }
#else
break;
#endif // !defined(_WIN32)
} }
break; break;
case PDUSAP::PACKET_DATA: case PDUSAP::PACKET_DATA:
{ {
#if !defined(_WIN32)
// is the host virtual tunneling enabled? // is the host virtual tunneling enabled?
if (!m_network->m_host->m_vtunEnabled) if (!m_network->m_host->m_vtunEnabled)
break; break;
@ -460,7 +470,8 @@ void P25PacketData::dispatch(uint32_t peerId)
LogMessage(LOG_NET, "P25, PDU -> VTUN, IP Data, srcIp = %s, dstIp = %s, pktLen = %u, proto = %02X", srcIp, dstIp, pktLen, proto); LogMessage(LOG_NET, "P25, PDU -> VTUN, IP Data, srcIp = %s, dstIp = %s, pktLen = %u, proto = %02X", srcIp, dstIp, pktLen, proto);
uint8_t ipFrame[pktLen]; UInt8Array __ipFrame = std::make_unique<uint8_t[]>(pktLen);
uint8_t* ipFrame = __ipFrame.get();
::memset(ipFrame, 0x00U, pktLen); ::memset(ipFrame, 0x00U, pktLen);
::memcpy(ipFrame, status->pduUserData + dataPktOffset, pktLen); ::memcpy(ipFrame, status->pduUserData + dataPktOffset, pktLen);
#if DEBUG_P25_PDU_DATA #if DEBUG_P25_PDU_DATA
@ -469,6 +480,7 @@ void P25PacketData::dispatch(uint32_t peerId)
if (!m_network->m_host->m_tun->write(ipFrame, pktLen)) { if (!m_network->m_host->m_tun->write(ipFrame, pktLen)) {
LogError(LOG_NET, P25_PDU_STR ", failed to write IP frame to virtual tunnel, len %u", pktLen); LogError(LOG_NET, P25_PDU_STR ", failed to write IP frame to virtual tunnel, len %u", pktLen);
} }
#endif // !defined(_WIN32)
} }
break; break;
case PDUSAP::SNDCP_CTRL_DATA: case PDUSAP::SNDCP_CTRL_DATA:
@ -633,6 +645,7 @@ bool P25PacketData::processSNDCPControl(RxStatus* status)
void P25PacketData::write_PDU_ARP(uint32_t addr) void P25PacketData::write_PDU_ARP(uint32_t addr)
{ {
#if !defined(_WIN32)
if (!m_network->m_host->m_vtunEnabled) if (!m_network->m_host->m_vtunEnabled)
return; return;
@ -672,11 +685,13 @@ void P25PacketData::write_PDU_ARP(uint32_t addr)
rspHeader.calculateLength(P25_PDU_ARP_PCKT_LENGTH); rspHeader.calculateLength(P25_PDU_ARP_PCKT_LENGTH);
uint32_t pduLength = rspHeader.getPDULength(); uint32_t pduLength = rspHeader.getPDULength();
uint8_t pduUserData[pduLength]; UInt8Array __pduUserData = std::make_unique<uint8_t[]>(pduLength);
uint8_t* pduUserData = __pduUserData.get();
::memset(pduUserData, 0x00U, pduLength); ::memset(pduUserData, 0x00U, pduLength);
::memcpy(pduUserData + P25_PDU_HEADER_LENGTH_BYTES, arpPacket, P25_PDU_ARP_PCKT_LENGTH); ::memcpy(pduUserData + P25_PDU_HEADER_LENGTH_BYTES, arpPacket, P25_PDU_ARP_PCKT_LENGTH);
dispatchUserFrameToFNE(rspHeader, true, pduUserData); dispatchUserFrameToFNE(rspHeader, true, pduUserData);
#endif // !defined(_WIN32)
} }
/* Helper write ARP reply to the network. */ /* Helper write ARP reply to the network. */
@ -728,7 +743,8 @@ void P25PacketData::write_PDU_ARP_Reply(uint32_t targetAddr, uint32_t requestorL
rspHeader.calculateLength(P25_PDU_ARP_PCKT_LENGTH); rspHeader.calculateLength(P25_PDU_ARP_PCKT_LENGTH);
uint32_t pduLength = rspHeader.getPDULength(); uint32_t pduLength = rspHeader.getPDULength();
uint8_t pduUserData[pduLength]; UInt8Array __pduUserData = std::make_unique<uint8_t[]>(pduLength);
uint8_t* pduUserData = __pduUserData.get();
::memset(pduUserData, 0x00U, pduLength); ::memset(pduUserData, 0x00U, pduLength);
::memcpy(pduUserData + P25_PDU_HEADER_LENGTH_BYTES, arpPacket, P25_PDU_ARP_PCKT_LENGTH); ::memcpy(pduUserData + P25_PDU_HEADER_LENGTH_BYTES, arpPacket, P25_PDU_ARP_PCKT_LENGTH);

@ -266,7 +266,8 @@ namespace network
} }
case 0: case 0:
while (contentLength > 0 && !_NO_MORE()) { while (contentLength > 0 && !_NO_MORE()) {
contentLength -= (iv[1].iov_len = std::min(contentLength, (int)iv[0].iov_len - len)); //contentLength -= (iv[1].iov_len = std::min(contentLength, (int)iv[0].iov_len - len));
contentLength -= (iv[1].iov_len = (((contentLength) < ((int)iv[0].iov_len - len)) ? (contentLength) : ((int)iv[0].iov_len - len)));
if (resp) if (resp)
resp->append(&header[len], iv[1].iov_len); resp->append(&header[len], iv[1].iov_len);
len += iv[1].iov_len; len += iv[1].iov_len;

@ -14,7 +14,11 @@
#include "common/network/BaseNetwork.h" #include "common/network/BaseNetwork.h"
#include "common/Log.h" // for CurrentLogFileLevel() and LogGetNetwork() #include "common/Log.h" // for CurrentLogFileLevel() and LogGetNetwork()
#if defined(_WIN32)
#include "common/Clock.h"
#else
#include <sys/time.h> #include <sys/time.h>
#endif // defined(_WIN32)
#if defined(CATCH2_TEST_COMPILATION) #if defined(CATCH2_TEST_COMPILATION)
#include <catch2/catch_test_macros.hpp> #include <catch2/catch_test_macros.hpp>
@ -115,16 +119,18 @@ void ActivityLog(const char *mode, const bool sourceRf, const char* msg, ...)
assert(msg != nullptr); assert(msg != nullptr);
char buffer[ACT_LOG_BUFFER_LEN]; char buffer[ACT_LOG_BUFFER_LEN];
struct timeval now; time_t now;
::gettimeofday(&now, NULL); ::time(&now);
struct tm* tm = ::localtime(&now);
struct tm* tm = ::gmtime(&now.tv_sec); struct timeval nowMillis;
::gettimeofday(&nowMillis, NULL);
if (strcmp(mode, "") == 0) { if (strcmp(mode, "") == 0) {
::sprintf(buffer, "A: %04d-%02d-%02d %02d:%02d:%02d.%03lu ", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, now.tv_usec / 1000U); ::sprintf(buffer, "A: %04d-%02d-%02d %02d:%02d:%02d.%03lu ", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, nowMillis.tv_usec / 1000U);
} }
else { else {
::sprintf(buffer, "A: %04d-%02d-%02d %02d:%02d:%02d.%03lu %s %s ", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, now.tv_usec / 1000U, mode, (sourceRf) ? "RF" : "Net"); ::sprintf(buffer, "A: %04d-%02d-%02d %02d:%02d:%02d.%03lu %s %s ", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, nowMillis.tv_usec / 1000U, mode, (sourceRf) ? "RF" : "Net");
} }
va_list vl, vl_len; va_list vl, vl_len;

@ -11,10 +11,14 @@
#include <cstdio> #include <cstdio>
#if defined(_WIN32)
#include <conio.h>
#else
#include <cstring> #include <cstring>
#include <termios.h> #include <termios.h>
#include <unistd.h> #include <unistd.h>
#include <sys/select.h> #include <sys/select.h>
#endif // defined(_WIN32)
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Public Class Members // Public Class Members
@ -22,10 +26,16 @@
/* Initializes a new instance of the Console class. */ /* Initializes a new instance of the Console class. */
#if !defined(_WIN32)
Console::Console() : Console::Console() :
m_termios() m_termios()
#else
Console::Console()
#endif // !defined(_WIN32)
{ {
#if !defined(_WIN32)
::memset(&m_termios, 0x00U, sizeof(termios)); ::memset(&m_termios, 0x00U, sizeof(termios));
#endif // !defined(_WIN32)
} }
/* Finalizes a instance of the Console class. */ /* Finalizes a instance of the Console class. */
@ -36,6 +46,7 @@ Console::~Console() = default;
bool Console::open() bool Console::open()
{ {
#if !defined(_WIN32)
termios tios; termios tios;
int n = ::tcgetattr(STDIN_FILENO, &tios); int n = ::tcgetattr(STDIN_FILENO, &tios);
@ -53,7 +64,7 @@ bool Console::open()
::fprintf(stderr, "tcsetattr: returned %d\r\n", n); ::fprintf(stderr, "tcsetattr: returned %d\r\n", n);
return false; return false;
} }
#endif // !defined(_WIN32)
return true; return true;
} }
@ -61,15 +72,23 @@ bool Console::open()
void Console::close() void Console::close()
{ {
#if !defined(_WIN32)
int n = ::tcsetattr(STDIN_FILENO, TCSANOW, &m_termios); int n = ::tcsetattr(STDIN_FILENO, TCSANOW, &m_termios);
if (n != 0) if (n != 0)
::fprintf(stderr, "tcsetattr: returned %d\r\n", n); ::fprintf(stderr, "tcsetattr: returned %d\r\n", n);
#endif // !defined(_WIN32)
} }
/* Retrieves a character input on the keyboard. */ /* Retrieves a character input on the keyboard. */
int Console::getChar() int Console::getChar()
{ {
#if defined(_WIN32)
if (::_kbhit() == 0)
return -1;
return ::_getch();
#else
fd_set fds; fd_set fds;
FD_ZERO(&fds); FD_ZERO(&fds);
FD_SET(STDIN_FILENO, &fds); FD_SET(STDIN_FILENO, &fds);
@ -94,6 +113,7 @@ int Console::getChar()
} }
return c; return c;
#endif // defined(_WIN32)
} }
/* Retrieves an array of characters input on the keyboard. */ /* Retrieves an array of characters input on the keyboard. */

@ -18,7 +18,9 @@
#include "Defines.h" #include "Defines.h"
#if !defined(_WIN32)
#include <termios.h> #include <termios.h>
#endif // !defined(_WIN32)
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Class Declaration // Class Declaration
@ -67,7 +69,9 @@ public:
int getLine(char line[], int max, char mask); int getLine(char line[], int max, char mask);
private: private:
#if !defined(_WIN32)
termios m_termios; termios m_termios;
#endif // !defined(_WIN32)
}; };
#endif // __CONSOLE_H__ #endif // __CONSOLE_H__

@ -39,7 +39,11 @@ void* Host::threadDMRReader1(void* arg)
{ {
thread_t* th = (thread_t*)arg; thread_t* th = (thread_t*)arg;
if (th != nullptr) { if (th != nullptr) {
#if defined(_WIN32)
::CloseHandle(th->thread);
#else
::pthread_detach(th->thread); ::pthread_detach(th->thread);
#endif // defined(_WIN32)
std::string threadName("dmrd:frame1-r"); std::string threadName("dmrd:frame1-r");
Host* host = static_cast<Host*>(th->obj); Host* host = static_cast<Host*>(th->obj);
@ -168,7 +172,11 @@ void* Host::threadDMRWriter1(void* arg)
{ {
thread_t* th = (thread_t*)arg; thread_t* th = (thread_t*)arg;
if (th != nullptr) { if (th != nullptr) {
#if defined(_WIN32)
::CloseHandle(th->thread);
#else
::pthread_detach(th->thread); ::pthread_detach(th->thread);
#endif // defined(_WIN32)
std::string threadName("dmrd:frame1-w"); std::string threadName("dmrd:frame1-w");
Host* host = static_cast<Host*>(th->obj); Host* host = static_cast<Host*>(th->obj);
@ -292,7 +300,11 @@ void* Host::threadDMRReader2(void* arg)
{ {
thread_t* th = (thread_t*)arg; thread_t* th = (thread_t*)arg;
if (th != nullptr) { if (th != nullptr) {
#if defined(_WIN32)
::CloseHandle(th->thread);
#else
::pthread_detach(th->thread); ::pthread_detach(th->thread);
#endif // defined(_WIN32)
std::string threadName("dmrd:frame2-r"); std::string threadName("dmrd:frame2-r");
Host* host = static_cast<Host*>(th->obj); Host* host = static_cast<Host*>(th->obj);
@ -420,7 +432,11 @@ void* Host::threadDMRWriter2(void* arg)
{ {
thread_t* th = (thread_t*)arg; thread_t* th = (thread_t*)arg;
if (th != nullptr) { if (th != nullptr) {
#if defined(_WIN32)
::CloseHandle(th->thread);
#else
::pthread_detach(th->thread); ::pthread_detach(th->thread);
#endif // defined(_WIN32)
std::string threadName("dmrd:frame2-w"); std::string threadName("dmrd:frame2-w");
Host* host = static_cast<Host*>(th->obj); Host* host = static_cast<Host*>(th->obj);

@ -26,7 +26,11 @@ void* Host::threadNXDNReader(void* arg)
{ {
thread_t* th = (thread_t*)arg; thread_t* th = (thread_t*)arg;
if (th != nullptr) { if (th != nullptr) {
#if defined(_WIN32)
::CloseHandle(th->thread);
#else
::pthread_detach(th->thread); ::pthread_detach(th->thread);
#endif // defined(_WIN32)
std::string threadName("nxdd:frame-r"); std::string threadName("nxdd:frame-r");
Host* host = static_cast<Host*>(th->obj); Host* host = static_cast<Host*>(th->obj);
@ -117,7 +121,11 @@ void* Host::threadNXDNWriter(void* arg)
{ {
thread_t* th = (thread_t*)arg; thread_t* th = (thread_t*)arg;
if (th != nullptr) { if (th != nullptr) {
#if defined(_WIN32)
::CloseHandle(th->thread);
#else
::pthread_detach(th->thread); ::pthread_detach(th->thread);
#endif // defined(_WIN32)
std::string threadName("nxdd:frame-w"); std::string threadName("nxdd:frame-w");
Host* host = static_cast<Host*>(th->obj); Host* host = static_cast<Host*>(th->obj);

@ -26,7 +26,12 @@ void* Host::threadP25Reader(void* arg)
{ {
thread_t* th = (thread_t*)arg; thread_t* th = (thread_t*)arg;
if (th != nullptr) { if (th != nullptr) {
#if defined(_WIN32)
::CloseHandle(th->thread);
#else
::pthread_detach(th->thread); ::pthread_detach(th->thread);
#endif // defined(_WIN32)
std::string threadName("p25d:frame-r"); std::string threadName("p25d:frame-r");
Host* host = static_cast<Host*>(th->obj); Host* host = static_cast<Host*>(th->obj);
@ -158,7 +163,11 @@ void* Host::threadP25Writer(void* arg)
{ {
thread_t* th = (thread_t*)arg; thread_t* th = (thread_t*)arg;
if (th != nullptr) { if (th != nullptr) {
#if defined(_WIN32)
::CloseHandle(th->thread);
#else
::pthread_detach(th->thread); ::pthread_detach(th->thread);
#endif // defined(_WIN32)
std::string threadName("p25d:frame-w"); std::string threadName("p25d:frame-w");
Host* host = static_cast<Host*>(th->obj); Host* host = static_cast<Host*>(th->obj);

@ -30,8 +30,10 @@ using namespace lookups;
#include <functional> #include <functional>
#include <memory> #include <memory>
#if !defined(_WIN32)
#include <sys/utsname.h> #include <sys/utsname.h>
#include <unistd.h> #include <unistd.h>
#endif // !defined(_WIN32)
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Static Class Members // Static Class Members
@ -190,6 +192,7 @@ int Host::run()
::fatal("unable to open the activity log file\n"); ::fatal("unable to open the activity log file\n");
} }
#if !defined(_WIN32)
// handle POSIX process forking // handle POSIX process forking
if (m_daemon) { if (m_daemon) {
// create new process // create new process
@ -226,6 +229,7 @@ int Host::run()
::close(STDOUT_FILENO); ::close(STDOUT_FILENO);
::close(STDERR_FILENO); ::close(STDERR_FILENO);
} }
#endif // !defined(_WIN32)
::LogInfo(__BANNER__ "\r\n" __PROG_NAME__ " " __VER__ " (built " __BUILD__ ")\r\n" \ ::LogInfo(__BANNER__ "\r\n" __PROG_NAME__ " " __VER__ " (built " __BUILD__ ")\r\n" \
"Copyright (c) 2017-2024 Bryan Biedenkapp, N2PLL and DVMProject (https://github.com/dvmproject) Authors.\r\n" \ "Copyright (c) 2017-2024 Bryan Biedenkapp, N2PLL and DVMProject (https://github.com/dvmproject) Authors.\r\n" \
@ -831,12 +835,15 @@ int Host::run()
/* /*
** Main execution loop ** Main execution loop
*/ */
#if defined(_WIN32)
::LogInfoEx(LOG_HOST, "[ OK ] Host is up and running on Win32");
#else
struct utsname utsinfo; struct utsname utsinfo;
::memset(&utsinfo, 0, sizeof(utsinfo)); ::memset(&utsinfo, 0, sizeof(utsinfo));
::uname(&utsinfo); ::uname(&utsinfo);
::LogInfoEx(LOG_HOST, "[ OK ] Host is up and running on %s %s %s", utsinfo.sysname, utsinfo.release, utsinfo.machine); ::LogInfoEx(LOG_HOST, "[ OK ] Host is up and running on %s %s %s", utsinfo.sysname, utsinfo.release, utsinfo.machine);
#endif // defined(_WIN32)
while (!killed) { while (!killed) {
if (m_modem->hasLockout() && m_state != HOST_STATE_LOCKOUT) if (m_modem->hasLockout() && m_state != HOST_STATE_LOCKOUT)
setState(HOST_STATE_LOCKOUT); setState(HOST_STATE_LOCKOUT);
@ -1591,7 +1598,11 @@ void* Host::threadModem(void* arg)
{ {
thread_t* th = (thread_t*)arg; thread_t* th = (thread_t*)arg;
if (th != nullptr) { if (th != nullptr) {
#if defined(_WIN32)
::CloseHandle(th->thread);
#else
::pthread_detach(th->thread); ::pthread_detach(th->thread);
#endif // defined(_WIN32)
std::string threadName("host:modem"); std::string threadName("host:modem");
Host* host = static_cast<Host*>(th->obj); Host* host = static_cast<Host*>(th->obj);
@ -1648,7 +1659,11 @@ void* Host::threadWatchdog(void* arg)
{ {
thread_t* th = (thread_t*)arg; thread_t* th = (thread_t*)arg;
if (th != nullptr) { if (th != nullptr) {
#if defined(_WIN32)
::CloseHandle(th->thread);
#else
::pthread_detach(th->thread); ::pthread_detach(th->thread);
#endif // defined(_WIN32)
std::string threadName("host:watchdog"); std::string threadName("host:watchdog");
Host* host = static_cast<Host*>(th->obj); Host* host = static_cast<Host*>(th->obj);
@ -1750,7 +1765,11 @@ void* Host::threadSiteData(void* arg)
{ {
thread_t* th = (thread_t*)arg; thread_t* th = (thread_t*)arg;
if (th != nullptr) { if (th != nullptr) {
#if defined(_WIN32)
::CloseHandle(th->thread);
#else
::pthread_detach(th->thread); ::pthread_detach(th->thread);
#endif // defined(_WIN32)
std::string threadName("host:site-data"); std::string threadName("host:site-data");
Host* host = static_cast<Host*>(th->obj); Host* host = static_cast<Host*>(th->obj);
@ -1815,7 +1834,11 @@ void* Host::threadPresence(void* arg)
{ {
thread_t* th = (thread_t*)arg; thread_t* th = (thread_t*)arg;
if (th != nullptr) { if (th != nullptr) {
#if defined(_WIN32)
::CloseHandle(th->thread);
#else
::pthread_detach(th->thread); ::pthread_detach(th->thread);
#endif // defined(_WIN32)
std::string threadName("host:presence"); std::string threadName("host:presence");
Host* host = static_cast<Host*>(th->obj); Host* host = static_cast<Host*>(th->obj);

@ -47,7 +47,12 @@
#include <functional> #include <functional>
#include <mutex> #include <mutex>
#if defined(_WIN32)
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#else
#include <pthread.h> #include <pthread.h>
#endif // defined(_WIN32)
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Class Prototypes // Class Prototypes

@ -266,7 +266,9 @@ int main(int argc, char** argv)
::signal(SIGINT, sigHandler); ::signal(SIGINT, sigHandler);
::signal(SIGTERM, sigHandler); ::signal(SIGTERM, sigHandler);
#if !defined(_WIN32)
::signal(SIGHUP, sigHandler); ::signal(SIGHUP, sigHandler);
#endif // !defined(_WIN32)
int ret = 0; int ret = 0;

@ -1476,7 +1476,8 @@ bool Modem::writeP25Frame(const uint8_t* data, uint32_t length)
return false; return false;
} }
uint8_t buffer[MAX_LENGTH]; UInt8Array __buffer = std::make_unique<uint8_t[]>(MAX_LENGTH);
uint8_t* buffer = __buffer.get();
if (length < 252U) { if (length < 252U) {
buffer[0U] = DVM_SHORT_FRAME_START; buffer[0U] = DVM_SHORT_FRAME_START;

@ -403,7 +403,8 @@ int ModemV24::write(const uint8_t* data, uint32_t length)
} }
if (modemCommand == CMD_P25_DATA) { if (modemCommand == CMD_P25_DATA) {
uint8_t buffer[length]; UInt8Array __buffer = std::make_unique<uint8_t[]>(length);
uint8_t* buffer = __buffer.get();
::memset(buffer, 0x00U, length); ::memset(buffer, 0x00U, length);
::memcpy(buffer, data + 2U, length); ::memcpy(buffer, data + 2U, length);
@ -475,7 +476,8 @@ int ModemV24::writeSerial()
m_txP25Queue.get(lengthTagTs, 11U); m_txP25Queue.get(lengthTagTs, 11U);
// Get the actual data // Get the actual data
uint8_t buffer[len]; UInt8Array __buffer = std::make_unique<uint8_t[]>(len);
uint8_t* buffer = __buffer.get();
m_txP25Queue.get(buffer, len); m_txP25Queue.get(buffer, len);
// Sanity check on data tag // Sanity check on data tag
@ -541,7 +543,8 @@ void ModemV24::convertToAir(const uint8_t *data, uint32_t length)
::memset(buffer, 0x00U, P25_PDU_FRAME_LENGTH_BYTES + 2U); ::memset(buffer, 0x00U, P25_PDU_FRAME_LENGTH_BYTES + 2U);
// get the DFSI data (skip the 0x00 padded byte at the start) // get the DFSI data (skip the 0x00 padded byte at the start)
uint8_t dfsiData[length - 1U]; UInt8Array __dfsiData = std::make_unique<uint8_t[]>(length - 1U);
uint8_t* dfsiData = __dfsiData.get();
::memset(dfsiData, 0x00U, length - 1U); ::memset(dfsiData, 0x00U, length - 1U);
::memcpy(dfsiData, data + 1U, length - 1U); ::memcpy(dfsiData, data + 1U, length - 1U);
@ -609,7 +612,7 @@ void ModemV24::convertToAir(const uint8_t *data, uint32_t length)
// buffer for decoded VHDR data // buffer for decoded VHDR data
uint8_t vhdr[DFSI_VHDR_LEN]; uint8_t vhdr[DFSI_VHDR_LEN];
uint offset = 0U; uint32_t offset = 0U;
for (uint32_t i = 0; i < DFSI_VHDR_RAW_LEN; i++, offset += 6) for (uint32_t i = 0; i < DFSI_VHDR_RAW_LEN; i++, offset += 6)
Utils::hex2Bin(raw[i], vhdr, offset); Utils::hex2Bin(raw[i], vhdr, offset);

@ -7,6 +7,7 @@
* Copyright (C) 2020,2021 Jonathan Naylor, G4KLX * Copyright (C) 2020,2021 Jonathan Naylor, G4KLX
* *
*/ */
#if !defined(_WIN32)
#include "common/Log.h" #include "common/Log.h"
#include "modem/port/PseudoPTYPort.h" #include "modem/port/PseudoPTYPort.h"
@ -75,3 +76,4 @@ void PseudoPTYPort::close()
UARTPort::close(); UARTPort::close();
::unlink(m_symlink.c_str()); ::unlink(m_symlink.c_str());
} }
#endif // !defined(_WIN32)

@ -15,6 +15,7 @@
*/ */
#if !defined(__PSEUDO_PTY_PORT_H__) #if !defined(__PSEUDO_PTY_PORT_H__)
#define __PSEUDO_PTY_PORT_H__ #define __PSEUDO_PTY_PORT_H__
#if !defined(_WIN32)
#include "Defines.h" #include "Defines.h"
#include "modem/port/UARTPort.h" #include "modem/port/UARTPort.h"
@ -66,4 +67,5 @@ namespace modem
} // namespace port } // namespace port
} // namespace modem } // namespace modem
#endif // !defined(_WIN32)
#endif // __PSEUDO_PTY_PORT_H__ #endif // __PSEUDO_PTY_PORT_H__

@ -6,7 +6,7 @@
* *
* Copyright (C) 2002-2004,2007-2009,2011-2013,2015-2017,2020,2021 Jonathan Naylor, G4KLX * Copyright (C) 2002-2004,2007-2009,2011-2013,2015-2017,2020,2021 Jonathan Naylor, G4KLX
* Copyright (C) 1999-2001 Thomas Sailor, HB9JNX * Copyright (C) 1999-2001 Thomas Sailor, HB9JNX
* Copyright (C) 2020-2021 Bryan Biedenkapp, N2PLL * Copyright (C) 2020-2024 Bryan Biedenkapp, N2PLL
* *
*/ */
#include "Defines.h" #include "Defines.h"
@ -18,6 +18,10 @@ using namespace modem::port;
#include <cstring> #include <cstring>
#include <cassert> #include <cassert>
#if defined(_WIN32)
#include <setupapi.h>
#include <winioctl.h>
#else
#include <sys/types.h> #include <sys/types.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
@ -25,6 +29,7 @@ using namespace modem::port;
#include <fcntl.h> #include <fcntl.h>
#include <unistd.h> #include <unistd.h>
#include <termios.h> #include <termios.h>
#endif // defined(_WIN32)
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Public Class Members // Public Class Members
@ -37,7 +42,11 @@ UARTPort::UARTPort(const std::string& device, SERIAL_SPEED speed, bool assertRTS
m_device(device), m_device(device),
m_speed(speed), m_speed(speed),
m_assertRTS(assertRTS), m_assertRTS(assertRTS),
#if defined(_WIN32)
m_fd(INVALID_HANDLE_VALUE)
#else
m_fd(-1) m_fd(-1)
#endif // defined(_WIN32)
{ {
assert(!device.empty()); assert(!device.empty());
} }
@ -52,7 +61,84 @@ bool UARTPort::open()
{ {
if (m_isOpen) if (m_isOpen)
return true; return true;
#if defined(_WIN32)
assert(m_fd == INVALID_HANDLE_VALUE);
DWORD errCode;
std::string baseName = m_device.substr(4U); // Convert "\\.\COM10" to "COM10"
m_fd = ::CreateFileA(m_device.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (m_fd == INVALID_HANDLE_VALUE) {
::LogError(LOG_HOST, "Cannot open device - %s, err=%04lx", m_device.c_str(), ::GetLastError());
return false;
}
DCB dcb;
if (::GetCommState(m_fd, &dcb) == 0) {
::LogError(LOG_HOST, "Cannot get the attributes for %s, err=%04lx", m_device.c_str(), ::GetLastError());
::ClearCommError(m_fd, &errCode, NULL);
::CloseHandle(m_fd);
return false;
}
dcb.BaudRate = DWORD(m_speed);
dcb.ByteSize = 8;
dcb.Parity = NOPARITY;
dcb.fParity = FALSE;
dcb.StopBits = ONESTOPBIT;
dcb.fInX = FALSE;
dcb.fOutX = FALSE;
dcb.fOutxCtsFlow = FALSE;
dcb.fOutxDsrFlow = FALSE;
dcb.fDsrSensitivity = FALSE;
dcb.fDtrControl = DTR_CONTROL_DISABLE;
dcb.fRtsControl = RTS_CONTROL_DISABLE;
if (::SetCommState(m_fd, &dcb) == 0) {
::LogError(LOG_HOST, "Cannot set the attributes for %s, err=%04lx", m_device.c_str(), ::GetLastError());
::ClearCommError(m_fd, &errCode, NULL);
::CloseHandle(m_fd);
return false;
}
COMMTIMEOUTS timeouts;
if (!::GetCommTimeouts(m_fd, &timeouts)) {
::LogError(LOG_HOST, "Cannot get the timeouts for %s, err=%04lx", m_device.c_str(), ::GetLastError());
::ClearCommError(m_fd, &errCode, NULL);
::CloseHandle(m_fd);
return false;
}
timeouts.ReadIntervalTimeout = MAXDWORD;
timeouts.ReadTotalTimeoutMultiplier = 0UL;
timeouts.ReadTotalTimeoutConstant = 0UL;
if (!::SetCommTimeouts(m_fd, &timeouts)) {
::LogError(LOG_HOST, "Cannot set the timeouts for %s, err=%04lx", m_device.c_str(), ::GetLastError());
::ClearCommError(m_fd, &errCode, NULL);
::CloseHandle(m_fd);
return false;
}
if (::EscapeCommFunction(m_fd, CLRDTR) == 0) {
::LogError(LOG_HOST, "Cannot clear DTR for %s, err=%04lx", m_device.c_str(), ::GetLastError());
::ClearCommError(m_fd, &errCode, NULL);
::CloseHandle(m_fd);
return false;
}
if (::EscapeCommFunction(m_fd, m_assertRTS ? SETRTS : CLRRTS) == 0) {
::LogError(LOG_HOST, "Cannot set/clear RTS for %s, err=%04lx", m_device.c_str(), ::GetLastError());
::ClearCommError(m_fd, &errCode, NULL);
::CloseHandle(m_fd);
return false;
}
::ClearCommError(m_fd, &errCode, NULL);
return true;
#else
assert(m_fd == -1); assert(m_fd == -1);
#if defined(__APPLE__) #if defined(__APPLE__)
@ -72,6 +158,7 @@ bool UARTPort::open()
} }
return setTermios(); return setTermios();
#endif // defined(_WIN32)
} }
/* Reads data from the serial port. */ /* Reads data from the serial port. */
@ -79,6 +166,26 @@ bool UARTPort::open()
int UARTPort::read(uint8_t* buffer, uint32_t length) int UARTPort::read(uint8_t* buffer, uint32_t length)
{ {
assert(buffer != nullptr); assert(buffer != nullptr);
#if defined(_WIN32)
assert(m_fd != INVALID_HANDLE_VALUE);
if (length == 0U)
return 0;
uint32_t offset = 0U;
while (offset < length) {
int ret = readNonblock(buffer + offset, length - offset);
if (ret < 0) {
return ret;
} else if (ret == 0) {
if (offset == 0U)
return 0;
} else {
offset += ret;
}
}
#else
assert(m_fd != -1); assert(m_fd != -1);
if (length == 0U) if (length == 0U)
@ -123,7 +230,7 @@ int UARTPort::read(uint8_t* buffer, uint32_t length)
offset += len; offset += len;
} }
} }
#endif // defined(_WIN32)
return length; return length;
} }
@ -132,7 +239,28 @@ int UARTPort::read(uint8_t* buffer, uint32_t length)
int UARTPort::write(const uint8_t* buffer, uint32_t length) int UARTPort::write(const uint8_t* buffer, uint32_t length)
{ {
assert(buffer != nullptr); assert(buffer != nullptr);
#if defined(_WIN32)
if (m_isOpen && m_fd == INVALID_HANDLE_VALUE)
return 0;
assert(m_fd != INVALID_HANDLE_VALUE);
if (length == 0U)
return 0;
uint32_t ptr = 0U;
while (ptr < length) {
DWORD bytes = 0UL;
BOOL ret = ::WriteFile(m_fd, buffer + ptr, length - ptr, &bytes, NULL);
if (!ret) {
::LogError(LOG_HOST, "Error from WriteFile for %s: %04lx", m_device.c_str(), ::GetLastError());
return -1;
}
ptr += bytes;
}
#else
if (m_isOpen && m_fd == -1) if (m_isOpen && m_fd == -1)
return 0; return 0;
@ -156,7 +284,7 @@ int UARTPort::write(const uint8_t* buffer, uint32_t length)
if (n > 0) if (n > 0)
ptr += n; ptr += n;
} }
#endif // defined(_WIN32)
return length; return length;
} }
@ -164,6 +292,15 @@ int UARTPort::write(const uint8_t* buffer, uint32_t length)
void UARTPort::close() void UARTPort::close()
{ {
#if defined(_WIN32)
if (!m_isOpen && m_fd == INVALID_HANDLE_VALUE)
return;
assert(m_fd != INVALID_HANDLE_VALUE);
::CloseHandle(m_fd);
m_fd = INVALID_HANDLE_VALUE;
#else
if (!m_isOpen && m_fd == -1) if (!m_isOpen && m_fd == -1)
return; return;
@ -171,6 +308,7 @@ void UARTPort::close()
::close(m_fd); ::close(m_fd);
m_fd = -1; m_fd = -1;
#endif // defined(_WIN32)
m_isOpen = false; m_isOpen = false;
} }
@ -200,11 +338,51 @@ UARTPort::UARTPort(SERIAL_SPEED speed, bool assertRTS) :
m_isOpen(false), m_isOpen(false),
m_speed(speed), m_speed(speed),
m_assertRTS(assertRTS), m_assertRTS(assertRTS),
#if defined(_WIN32)
m_fd(INVALID_HANDLE_VALUE)
#else
m_fd(-1) m_fd(-1)
#endif // defined(_WIN32)
{ {
/* stub */ /* stub */
} }
#if defined(_WIN32)
/* Helper on Windows to read from serial port non-blocking. */
int UARTPort::readNonblock(unsigned char* buffer, unsigned int length)
{
assert(m_fd != INVALID_HANDLE_VALUE);
assert(buffer != NULL);
if (length == 0U)
return 0;
DWORD errors;
COMSTAT status;
if (::ClearCommError(m_fd, &errors, &status) == 0) {
::LogError(LOG_HOST, "Error from ClearCommError for %s, err=%04lx", m_device.c_str(), ::GetLastError());
return -1;
}
if (status.cbInQue == 0UL)
return 0;
DWORD readLength = status.cbInQue;
if (length < readLength)
readLength = length;
DWORD bytes = 0UL;
BOOL ret = ::ReadFile(m_fd, buffer, readLength, &bytes, NULL);
if (!ret) {
::LogError(LOG_HOST, "Error from ReadFile for %s: %04lx", m_device.c_str(), ::GetLastError());
return -1;
}
return int(bytes);
}
#endif // defined(_WIN32)
/* Checks it the serial port can be written to. */ /* Checks it the serial port can be written to. */
bool UARTPort::canWrite() bool UARTPort::canWrite()
@ -232,6 +410,7 @@ bool UARTPort::canWrite()
bool UARTPort::setTermios() bool UARTPort::setTermios()
{ {
#if !defined(_WIN32)
termios termios; termios termios;
if (::tcgetattr(m_fd, &termios) < 0) { if (::tcgetattr(m_fd, &termios) < 0) {
::LogError(LOG_HOST, "Cannot get the attributes for %s", m_device.c_str()); ::LogError(LOG_HOST, "Cannot get the attributes for %s", m_device.c_str());
@ -324,6 +503,7 @@ bool UARTPort::setTermios()
#if defined(__APPLE__) #if defined(__APPLE__)
setNonblock(false); setNonblock(false);
#endif #endif
#endif // !defined(_WIN32)
m_isOpen = true; m_isOpen = true;
return true; return true;

@ -6,7 +6,7 @@
* *
* Copyright (C) 2002-2004,2007-2009,2011-2013,2015-2017,2020,2021 Jonathan Naylor, G4KLX * Copyright (C) 2002-2004,2007-2009,2011-2013,2015-2017,2020,2021 Jonathan Naylor, G4KLX
* Copyright (C) 1999-2001 Thomas Sailor, HB9JNX * Copyright (C) 1999-2001 Thomas Sailor, HB9JNX
* Copyright (C) 2020-2021 Bryan Biedenkapp, N2PLL * Copyright (C) 2020-2024 Bryan Biedenkapp, N2PLL
* *
*/ */
/** /**
@ -24,6 +24,10 @@
#include <string> #include <string>
#if defined(_WIN32)
#include <windows.h>
#endif // defined(_WIN32)
namespace modem namespace modem
{ {
namespace port namespace port
@ -125,8 +129,21 @@ namespace modem
std::string m_device; std::string m_device;
SERIAL_SPEED m_speed; SERIAL_SPEED m_speed;
bool m_assertRTS; bool m_assertRTS;
#if defined(_WIN32)
HANDLE m_fd;
#else
int m_fd; int m_fd;
#endif // defined(_WIN32)
#if defined(_WIN32)
/**
* @brief Helper on Windows to read from serial port non-blocking.
* @param[in] buffer Buffer containing data to write to port.
* @param length Length of data to write to port.
* @returns int Actual length of data written to the port.
*/
int readNonblock(uint8_t* buffer, uint32_t length);
#endif // defined(_WIN32)
/** /**
* @brief Checks it the serial port can be written to. * @brief Checks it the serial port can be written to.
* @returns bool True, if port can be written to, otherwise false. * @returns bool True, if port can be written to, otherwise false.

@ -166,13 +166,15 @@ void V24UDPPort::clock(uint32_t ms)
// copy message // copy message
uint32_t messageLength = ret - RTP_HEADER_LENGTH_BYTES; uint32_t messageLength = ret - RTP_HEADER_LENGTH_BYTES;
uint8_t message[messageLength]; UInt8Array __message = std::make_unique<uint8_t[]>(messageLength);
uint8_t* message = __message.get();
::memset(message, 0x00U, messageLength); ::memset(message, 0x00U, messageLength);
::memcpy(message, data + RTP_HEADER_LENGTH_BYTES, messageLength); ::memcpy(message, data + RTP_HEADER_LENGTH_BYTES, messageLength);
if (udp::Socket::match(addr, m_addr)) { if (udp::Socket::match(addr, m_addr)) {
uint8_t reply[messageLength + 4U]; UInt8Array __reply = std::make_unique<uint8_t[]>(messageLength + 4U);
uint8_t* reply = __reply.get();
reply[0U] = DVM_SHORT_FRAME_START; reply[0U] = DVM_SHORT_FRAME_START;
reply[1U] = messageLength & 0xFFU; reply[1U] = messageLength & 0xFFU;
@ -333,7 +335,11 @@ void* V24UDPPort::threadedCtrlNetworkRx(void* arg)
{ {
V24PacketRequest* req = (V24PacketRequest*)arg; V24PacketRequest* req = (V24PacketRequest*)arg;
if (req != nullptr) { if (req != nullptr) {
#if defined(_WIN32)
::CloseHandle(req->thread);
#else
::pthread_detach(req->thread); ::pthread_detach(req->thread);
#endif // defined(_WIN32)
V24UDPPort* network = static_cast<V24UDPPort*>(req->obj); V24UDPPort* network = static_cast<V24UDPPort*>(req->obj);
if (network == nullptr) { if (network == nullptr) {

@ -798,7 +798,8 @@ bool Network::writeConfig()
json::value v = json::value(config); json::value v = json::value(config);
std::string json = v.serialize(); std::string json = v.serialize();
char buffer[json.length() + 9U]; CharArray __buffer = std::make_unique<char[]>(json.length() + 9U);
char* buffer = __buffer.get();
::memcpy(buffer + 0U, TAG_REPEATER_CONFIG, 4U); ::memcpy(buffer + 0U, TAG_REPEATER_CONFIG, 4U);
::snprintf(buffer + 8U, json.length() + 1U, "%s", json.c_str()); ::snprintf(buffer + 8U, json.length() + 1U, "%s", json.c_str());

@ -825,7 +825,8 @@ void Data::writeRF_PDU_User(data::DataHeader& dataHeader, bool extendedAddress,
uint32_t bitLength = ((dataHeader.getBlocksToFollow() + 1U) * P25_PDU_FEC_LENGTH_BITS) + P25_PREAMBLE_LENGTH_BITS; uint32_t bitLength = ((dataHeader.getBlocksToFollow() + 1U) * P25_PDU_FEC_LENGTH_BITS) + P25_PREAMBLE_LENGTH_BITS;
uint32_t offset = P25_PREAMBLE_LENGTH_BITS; uint32_t offset = P25_PREAMBLE_LENGTH_BITS;
uint8_t data[bitLength / 8U]; UInt8Array __data = std::make_unique<uint8_t[]>(bitLength / 8U);
uint8_t* data = __data.get();
::memset(data, 0x00U, bitLength / 8U); ::memset(data, 0x00U, bitLength / 8U);
uint8_t block[P25_PDU_FEC_LENGTH_BYTES]; uint8_t block[P25_PDU_FEC_LENGTH_BYTES];
::memset(block, 0x00U, P25_PDU_FEC_LENGTH_BYTES); ::memset(block, 0x00U, P25_PDU_FEC_LENGTH_BYTES);
@ -1460,7 +1461,8 @@ void Data::writeNet_PDU_Buffered()
uint32_t bitLength = ((m_netDataHeader.getBlocksToFollow() + 1U) * P25_PDU_FEC_LENGTH_BITS) + P25_PREAMBLE_LENGTH_BITS; uint32_t bitLength = ((m_netDataHeader.getBlocksToFollow() + 1U) * P25_PDU_FEC_LENGTH_BITS) + P25_PREAMBLE_LENGTH_BITS;
uint32_t offset = P25_PREAMBLE_LENGTH_BITS; uint32_t offset = P25_PREAMBLE_LENGTH_BITS;
uint8_t data[bitLength / 8U]; UInt8Array __data = std::make_unique<uint8_t[]>(bitLength / 8U);
uint8_t* data = __data.get();
::memset(data, 0x00U, bitLength / 8U); ::memset(data, 0x00U, bitLength / 8U);
uint8_t block[P25_PDU_FEC_LENGTH_BYTES]; uint8_t block[P25_PDU_FEC_LENGTH_BYTES];
::memset(block, 0x00U, P25_PDU_FEC_LENGTH_BYTES); ::memset(block, 0x00U, P25_PDU_FEC_LENGTH_BYTES);
@ -1549,7 +1551,8 @@ void Data::writeRF_PDU_Buffered()
uint32_t bitLength = ((m_rfDataHeader.getBlocksToFollow() + 1U) * P25_PDU_FEC_LENGTH_BITS) + P25_PREAMBLE_LENGTH_BITS; uint32_t bitLength = ((m_rfDataHeader.getBlocksToFollow() + 1U) * P25_PDU_FEC_LENGTH_BITS) + P25_PREAMBLE_LENGTH_BITS;
uint32_t offset = P25_PREAMBLE_LENGTH_BITS; uint32_t offset = P25_PREAMBLE_LENGTH_BITS;
uint8_t data[bitLength / 8U]; UInt8Array __data = std::make_unique<uint8_t[]>(bitLength / 8U);
uint8_t* data = __data.get();
::memset(data, 0x00U, bitLength / 8U); ::memset(data, 0x00U, bitLength / 8U);
uint8_t block[P25_PDU_FEC_LENGTH_BYTES]; uint8_t block[P25_PDU_FEC_LENGTH_BYTES];
::memset(block, 0x00U, P25_PDU_FEC_LENGTH_BYTES); ::memset(block, 0x00U, P25_PDU_FEC_LENGTH_BYTES);
@ -1674,7 +1677,8 @@ void Data::writeRF_PDU_Ack_Response(uint8_t ackClass, uint8_t ackType, uint8_t a
uint32_t bitLength = (1U * P25_PDU_FEC_LENGTH_BITS) + P25_PREAMBLE_LENGTH_BITS; uint32_t bitLength = (1U * P25_PDU_FEC_LENGTH_BITS) + P25_PREAMBLE_LENGTH_BITS;
uint32_t offset = P25_PREAMBLE_LENGTH_BITS; uint32_t offset = P25_PREAMBLE_LENGTH_BITS;
uint8_t data[bitLength / 8U]; UInt8Array __data = std::make_unique<uint8_t[]>(bitLength / 8U);
uint8_t* data = __data.get();
::memset(data, 0x00U, bitLength / 8U); ::memset(data, 0x00U, bitLength / 8U);
uint8_t block[P25_PDU_FEC_LENGTH_BYTES]; uint8_t block[P25_PDU_FEC_LENGTH_BYTES];
::memset(block, 0x00U, P25_PDU_FEC_LENGTH_BYTES); ::memset(block, 0x00U, P25_PDU_FEC_LENGTH_BYTES);

@ -34,7 +34,9 @@ using namespace lookups;
#include <cstdio> #include <cstdio>
#include <algorithm> #include <algorithm>
#if !defined(_WIN32)
#include <unistd.h> #include <unistd.h>
#endif // !defined(_WIN32)
#if !defined(CATCH2_TEST_COMPILATION) #if !defined(CATCH2_TEST_COMPILATION)
@ -1729,7 +1731,11 @@ bool HostSetup::writeFifoLength()
void HostSetup::sleep(uint32_t ms) void HostSetup::sleep(uint32_t ms)
{ {
#if defined(_WIN32)
::Sleep(ms);
#else
::usleep(ms * 1000); ::usleep(ms * 1000);
#endif // defined(_WIN32)
} }
/* Read the configuration area on the air interface modem. */ /* Read the configuration area on the air interface modem. */

@ -0,0 +1,19 @@
# SPDX-License-Identifier: GPL-2.0-only
#/*
# * Digital Voice Modem - Remote Command Client
# * GPLv2 Open Source. Use is subject to license terms.
# * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
# *
# * Copyright (C) 2024 Bryan Biedenkapp, N2PLL
# *
# */
file(GLOB vocoder_SRC
"src/vocoder/imbe/*.cpp"
"src/vocoder/*.cpp"
"src/vocoder/*.c"
)
file(GLOB vocoder_INCLUDE
"src/vocoder/imbe/*.h"
"src/vocoder/*.h"
)

@ -0,0 +1,316 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Digital Voice Modem - MBE Vocoder
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright (C) 2019-2021 Doug McLain
* Copyright (C) 2021 Bryan Biedenkapp, N2PLL
*
*/
#include <iostream>
#include <string.h>
#include <math.h>
#include "common/edac/Golay24128.h"
#include "vocoder/MBEDecoder.h"
using namespace edac;
using namespace vocoder;
// ---------------------------------------------------------------------------
// Constants
// ---------------------------------------------------------------------------
const int MBEDecoder::dW[72] = { 0,0,3,2,1,1,0,0,1,1,0,0,3,2,1,1,3,2,1,1,0,0,3,2,0,0,3,2,1,1,0,0,1,1,0,0,3,2,1,1,3,2,1,1,0,0,3,2,0,0,3,2,1,1,0,0,1,1,0,0,3,2,1,1,3,3,2,1,0,0,3,3, };
const int MBEDecoder::dX[72] = { 10,22,11,9,10,22,11,23,8,20,9,21,10,8,9,21,8,6,7,19,8,20,9,7,6,18,7,5,6,18,7,19,4,16,5,17,6,4,5,17,4,2,3,15,4,16,5,3,2,14,3,1,2,14,3,15,0,12,1,13,2,0,1,13,0,12,10,11,0,12,1,13, };
const int MBEDecoder::rW[36] = {
0, 1, 0, 1, 0, 1,
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 MBEDecoder::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 MBEDecoder::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 MBEDecoder::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
};
// ---------------------------------------------------------------------------
// Public Class Members
// ---------------------------------------------------------------------------
/* Initializes a new instance of the MBEDecoder class. */
MBEDecoder::MBEDecoder(MBE_DECODER_MODE mode) :
m_mbelibParms(NULL),
m_mbeMode(mode),
m_gainAdjust(1.0f)
{
m_mbelibParms = new mbelibParms();
mbe_initMbeParms(m_mbelibParms->m_cur_mp, m_mbelibParms->m_prev_mp, m_mbelibParms->m_prev_mp_enhanced);
::memset(gainMaxBuf, 0, sizeof(float) * 200);
gainMaxBufPtr = gainMaxBuf;
gainMaxIdx = 0;
}
/* Finalizes a instance of the MBEDecoder class. */
MBEDecoder::~MBEDecoder()
{
delete m_mbelibParms;
}
/* Decodes the given MBE codewords to deinterleaved MBE bits using the decoder mode. */
int32_t MBEDecoder::decodeBits(uint8_t* codeword, char* mbeBits)
{
int32_t errs = 0;
float samples[160U];
::memset(samples, 0x00U, 160U * sizeof(float));
switch (m_mbeMode)
{
case DECODE_DMR_AMBE:
{
char ambe_d[49U];
char ambe_fr[4][24];
::memset(ambe_d, 0x00U, 49U);
::memset(ambe_fr, 0x00U, 96U);
const int* w, *x, *y, *z;
w = rW;
x = rX;
y = rY;
z = rZ;
for (int i = 0; i < 9; ++i) {
for (int j = 0; j < 8; j += 2) {
ambe_fr[*y][*z] = (1 & (codeword[i] >> (7 - (j + 1))));
ambe_fr[*w][*x] = (1 & (codeword[i] >> (7 - j)));
w++;
x++;
y++;
z++;
}
}
errs = mbe_eccAmbe3600x2450C0(ambe_fr);
mbe_demodulateAmbe3600x2450Data(ambe_fr);
errs += mbe_eccAmbe3600x2450Data(ambe_fr, ambe_d);
::memcpy(mbeBits, ambe_d, 49U);
}
break;
case DECODE_88BIT_IMBE:
{
char imbe_d[88U];
::memset(imbe_d, 0x00U, 88U);
for (int i = 0; i < 11; ++i) {
for (int j = 0; j < 8; j++) {
imbe_d[j + (8 * i)] = (1 & (codeword[i] >> (7 - j)));
}
}
::memcpy(mbeBits, imbe_d, 88U);
}
break;
}
return errs;
}
/* Decodes the given MBE codewords to PCM samples using the decoder mode. */
int32_t MBEDecoder::decodeF(uint8_t* codeword, float samples[])
{
int32_t errs = 0;
switch (m_mbeMode)
{
case DECODE_DMR_AMBE:
{
char ambe_d[49U];
char ambe_fr[4][24];
::memset(ambe_d, 0x00U, 49U);
::memset(ambe_fr, 0x00U, 96U);
const int* w, *x, *y, *z;
w = rW;
x = rX;
y = rY;
z = rZ;
for (int i = 0; i < 9; ++i) {
for (int j = 0; j < 8; j += 2) {
ambe_fr[*y][*z] = (1 & (codeword[i] >> (7 - (j + 1))));
ambe_fr[*w][*x] = (1 & (codeword[i] >> (7 - j)));
w++;
x++;
y++;
z++;
}
}
int ambeErrs;
char ambeErrStr[64U];
::memset(ambeErrStr, 0x20U, 64U);
mbe_processAmbe3600x2450FrameF(samples, &ambeErrs, &errs, ambeErrStr, ambe_fr, ambe_d, m_mbelibParms->m_cur_mp, m_mbelibParms->m_prev_mp, m_mbelibParms->m_prev_mp_enhanced, 3);
}
break;
case DECODE_88BIT_IMBE:
{
char imbe_d[88U];
::memset(imbe_d, 0x00U, 88U);
for (int i = 0; i < 11; ++i) {
for (int j = 0; j < 8; j++) {
imbe_d[j + (8 * i)] = (1 & (codeword[i] >> (7 - j)));
}
}
int ambeErrs;
char ambeErrStr[64U];
::memset(ambeErrStr, 0x20U, 64U);
mbe_processImbe4400DataF(samples, &ambeErrs, &errs, ambeErrStr, imbe_d, m_mbelibParms->m_cur_mp, m_mbelibParms->m_prev_mp, m_mbelibParms->m_prev_mp_enhanced, 3);
}
break;
}
return errs;
}
/* Decodes the given MBE codewords to PCM samples using the decoder mode. */
int32_t MBEDecoder::decode(uint8_t* codeword, int16_t samples[])
{
float samplesF[160U];
::memset(samplesF, 0x00U, 160U * sizeof(float));
int32_t errs = decodeF(codeword, samplesF);
float* sampleFPtr = samplesF;
if (m_autoGain) {
// detect max level
float max = 0.0f;
for (int n = 0; n < 160; n++) {
float out = fabsf(*sampleFPtr);
if (out > max) {
max = out;
}
sampleFPtr++;
}
*gainMaxBufPtr = max;
gainMaxBufPtr++;
gainMaxIdx++;
if (gainMaxIdx > 24) {
gainMaxIdx = 0;
gainMaxBufPtr = gainMaxBuf;
}
// lookup max history
for (int i = 0; i < 25; i++) {
float a = gainMaxBuf[i];
if (a > max) {
max = a;
}
}
// determine optimal gain level
float gainFactor = 0.0f, gainDelta = 0.0f;
if (max > static_cast<float>(0)) {
gainFactor = (static_cast<float>(30000) / max);
}
else {
gainFactor = static_cast<float>(50);
}
if (gainFactor < m_gainAdjust) {
m_gainAdjust = gainFactor;
gainDelta = static_cast<float>(0);
}
else {
if (gainFactor > static_cast<float>(50)) {
gainFactor = static_cast<float>(50);
}
gainDelta = gainFactor - m_gainAdjust;
if (gainDelta > (static_cast<float>(0.05) * m_gainAdjust)) {
gainDelta = (static_cast<float>(0.05) * m_gainAdjust);
}
}
gainDelta /= static_cast<float>(160);
// adjust output gain
sampleFPtr = samplesF;
for (int n = 0; n < 160; n++) {
*sampleFPtr = (m_gainAdjust + (static_cast<float>(n) * gainDelta)) * (*sampleFPtr);
sampleFPtr++;
}
m_gainAdjust += (static_cast<float>(160) * gainDelta);
}
int16_t* samplePtr = samples;
sampleFPtr = samplesF;
for (int n = 0; n < 160; n++) {
float smp = *sampleFPtr;
if (!m_autoGain) {
smp *= m_gainAdjust;
}
// audio clipping
if (smp > 32760) {
smp = 32760;
}
else if (smp < -32760) {
smp = -32760;
}
*samplePtr = (int16_t)(smp);
samplePtr++;
sampleFPtr++;
}
return errs;
}

@ -0,0 +1,141 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Digital Voice Modem - MBE Vocoder
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright (C) 2019-2021 Doug McLain
* Copyright (C) 2021 Bryan Biedenkapp, N2PLL
*
*/
/**
* @file MBEDecoder.h
* @ingroup vocoder
* @file MBEDecoder.cpp
* @ingroup vocoder
*/
#if !defined(__MBE_DECODER_H__)
#define __MBE_DECODER_H__
extern "C" {
#include "mbe.h"
}
#include "common/Defines.h"
#include <stdlib.h>
#include <queue>
namespace vocoder
{
// ---------------------------------------------------------------------------
// Structure Declaration
// ---------------------------------------------------------------------------
struct mbelibParms
{
mbe_parms* m_cur_mp;
mbe_parms* m_prev_mp;
mbe_parms* m_prev_mp_enhanced;
/// <summary></summary>
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));
}
/// <summary></summary>
~mbelibParms()
{
free(m_prev_mp_enhanced);
free(m_prev_mp);
free(m_cur_mp);
}
};
// ---------------------------------------------------------------------------
// Constants
// ---------------------------------------------------------------------------
/**
* @brief Vocoder Decoding Mode
*/
enum MBE_DECODER_MODE {
DECODE_DMR_AMBE, //! DMR AMBE
DECODE_88BIT_IMBE //! 88-bit IMBE (P25)
};
// ---------------------------------------------------------------------------
// Class Declaration
// ---------------------------------------------------------------------------
/**
* @brief Implements MBE audio decoding.
*/
class HOST_SW_API MBEDecoder
{
public:
/**
* @brief Initializes a new instance of the MBEDecoder class.
* @param mode Decoder mode.
*/
MBEDecoder(MBE_DECODER_MODE mode);
/**
* @brief Finalizes a instance of the MBEDecoder class.
*/
~MBEDecoder();
/**
* @brief Decodes the given MBE codewords to deinterleaved MBE bits using the decoder mode.
* @param[in] codeword MBE codeword.
* @param[out] mbeBits
* @returns int32_t
*/
int32_t decodeBits(uint8_t* codeword, char* mbeBits);
/**
* @brief Decodes the given MBE codewords to PCM samples using the decoder mode.
* @param[in] codeword MBE codeword.
* @param[out] samples PCM Samples (in float format).
* @returns int32_t
*/
int32_t decodeF(uint8_t* codeword, float samples[]);
/**
* @brief Decodes the given MBE codewords to PCM samples using the decoder mode.
* @param[in] codeword MBE codeword.
* @param[out] samples PCM Samples (in short format).
* @returns int32_t
*/
int32_t decode(uint8_t* codeword, int16_t samples[]);
private:
mbelibParms* m_mbelibParms;
MBE_DECODER_MODE m_mbeMode;
static const int dW[72];
static const int dX[72];
static const int rW[36];
static const int rX[36];
static const int rY[36];
static const int rZ[36];
float gainMaxBuf[200];
float* gainMaxBufPtr;
int gainMaxIdx;
public:
/**
* @brief Gain adjustment.
*/
__PROPERTY(float, gainAdjust, GainAdjust);
/**
* @brief Flag indicating automatic gain adjustment is enabled.
*/
__PROPERTY(bool, autoGain, AutoGain);
};
} // namespace vocoder
#endif // __MBE_DECODER_H__

@ -0,0 +1,718 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Digital Voice Modem - MBE Vocoder
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright (C) 2019-2021 Doug McLain
* Copyright (C) 2021 Bryan Biedenkapp, N2PLL
*
*/
#define _USE_MATH_DEFINES
#include <math.h>
/*
* AMBE halfrate encoder - Copyright 2016 Max H. Parke KA1RBI
* Copyright (C) 2021 by Bryan Biedenkapp N2PLL
*
* This file is part of OP25 and part of GNU Radio
*
* This 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, or (at your option)
* any later version.
*
* This software 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 software; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "common/Defines.h"
#include "common/edac/AMBEFEC.h"
#include "common/edac/Golay24128.h"
#include "common/Utils.h"
#include "vocoder/MBEEncoder.h"
#include "vocoder/ambe3600x2450_const.h"
#include "vocoder/ambe3600x2400_const.h"
#include <cassert>
using namespace edac;
using namespace vocoder;
#ifdef _MSC_VER
#pragma warning(disable: 4244)
#endif
// ---------------------------------------------------------------------------
// Constants
// ---------------------------------------------------------------------------
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
};
// ---------------------------------------------------------------------------
// Global Functions
// ---------------------------------------------------------------------------
/**
* @brief
* @param[in] imbe_param
* @param b
* @param cur_mp Current MBE parameters.
* @param prev_mp Previous MBE parameters.
* @param gainAdjust Gain adjustment.
*/
static void encodeAMBE(const IMBE_PARAM* imbe_param, int b[], mbe_parms* cur_mp, mbe_parms* prev_mp, float gainAdjust)
{
static const float SQRT_2 = sqrtf(2.0);
static const int b0_lmax = sizeof(b0_lookup) / sizeof(b0_lookup[0]);
// int b[9];
// 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];
int L = (int)AmbeLtable[b[0]];
// 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]];
}
float m_float2[NUM_HARMS_MAX];
for (int l = 1; l <= L; l++) {
m_float2[l - 1] = (float)imbe_param->sa[l - 1];
m_float2[l - 1] = m_float2[l - 1] * m_float2[l - 1];
}
float en_min = 0;
b[1] = 0;
int vuv_max = 17;
for (int n = 0; n < vuv_max; n++) {
float En = 0;
for (int l = 1; l <= L; l++) {
int jl = (int)((float)l * (float)16.0 * AmbeW0table[b[0]]);
int kl = 12;
if (l <= 36)
kl = (l + 2) / 3;
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)imbe_param->num_harms;
float log_l_2 = 0.5 * log2f(num_harms_f); // fixme: table lookup
float 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 < imbe_param->num_harms; i1++) {
float sa = (float)imbe_param->sa[i1];
if (sa < 1) sa = 1.0;
if (imbe_param->v_uv_dsn[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;
float diff_gain = gain - 0.5 * prev_mp->gamma;
diff_gain -= gainAdjust;
float error;
int error_index;
int max_dg = 32;
for (int i1 = 0; i1 < max_dg; i1++) {
float diff = fabsf(diff_gain - AmbeDg[i1]);
if ((i1 == 0) || (diff < error)) {
error = diff;
error_index = i1;
}
}
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 < imbe_param->num_harms; 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 < imbe_param->num_harms; i1++) {
float kl = l_prev_l * (float)(i1 + 1);
int kl_floor = (int)kl;
float kl_frac = kl - kl_floor;
T[i1] = lsa[i1] - 0.65 * (1.0 - kl_frac) * prev_mp->log2Ml[kl_floor + 0] \
- 0.65 * kl_frac * prev_mp->log2Ml[kl_floor + 1 + 0];
}
// DCT
const int* J = AmbeLmprbl[imbe_param->num_harms];
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;
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;
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 = 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++) {
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++) {
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++) {
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 = 8;
for (int n = 0; n < max_8; n++) {
float err = 0.0;
float diff;
for (int j = 1; j <= J[ii - 1] - 2 && j <= 4; j++) {
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;
}
mbe_dequantizeAmbe2250Parms(cur_mp, prev_mp, b);
mbe_moveMbeParms(cur_mp, prev_mp);
}
/**
* @brief
* @param bits
* @param b
*/
static void encode49bit(uint8_t bits[49], const int b[9])
{
bits[0] = (b[0] >> 6) & 1;
bits[1] = (b[0] >> 5) & 1;
bits[2] = (b[0] >> 4) & 1;
bits[3] = (b[0] >> 3) & 1;
bits[4] = (b[1] >> 4) & 1;
bits[5] = (b[1] >> 3) & 1;
bits[6] = (b[1] >> 2) & 1;
bits[7] = (b[1] >> 1) & 1;
bits[8] = (b[2] >> 4) & 1;
bits[9] = (b[2] >> 3) & 1;
bits[10] = (b[2] >> 2) & 1;
bits[11] = (b[2] >> 1) & 1;
bits[12] = (b[3] >> 8) & 1;
bits[13] = (b[3] >> 7) & 1;
bits[14] = (b[3] >> 6) & 1;
bits[15] = (b[3] >> 5) & 1;
bits[16] = (b[3] >> 4) & 1;
bits[17] = (b[3] >> 3) & 1;
bits[18] = (b[3] >> 2) & 1;
bits[19] = (b[3] >> 1) & 1;
bits[20] = (b[4] >> 6) & 1;
bits[21] = (b[4] >> 5) & 1;
bits[22] = (b[4] >> 4) & 1;
bits[23] = (b[4] >> 3) & 1;
bits[24] = (b[5] >> 4) & 1;
bits[25] = (b[5] >> 3) & 1;
bits[26] = (b[5] >> 2) & 1;
bits[27] = (b[5] >> 1) & 1;
bits[28] = (b[6] >> 3) & 1;
bits[29] = (b[6] >> 2) & 1;
bits[30] = (b[6] >> 1) & 1;
bits[31] = (b[7] >> 3) & 1;
bits[32] = (b[7] >> 2) & 1;
bits[33] = (b[7] >> 1) & 1;
bits[34] = (b[8] >> 2) & 1;
bits[35] = b[1] & 1;
bits[36] = b[2] & 1;
bits[37] = (b[0] >> 2) & 1;
bits[38] = (b[0] >> 1) & 1;
bits[39] = b[0] & 1;
bits[40] = b[3] & 1;
bits[41] = (b[4] >> 2) & 1;
bits[42] = (b[4] >> 1) & 1;
bits[43] = b[4] & 1;
bits[44] = b[5] & 1;
bits[45] = b[6] & 1;
bits[46] = b[7] & 1;
bits[47] = (b[8] >> 1) & 1;
bits[48] = b[8] & 1;
}
/**
* @brief
* @param[in] in
* @param out
*/
static void encodeDmrAMBE(const uint8_t* in, uint8_t* out)
{
unsigned int aOrig = 0U;
unsigned int bOrig = 0U;
unsigned int cOrig = 0U;
unsigned int MASK = 0x000800U;
for (unsigned int i = 0U; i < 12U; i++, MASK >>= 1) {
unsigned int n1 = i;
unsigned int n2 = i + 12U;
if (READ_BIT(in, n1))
aOrig |= MASK;
if (READ_BIT(in, n2))
bOrig |= MASK;
}
MASK = 0x1000000U;
for (unsigned int i = 0U; i < 25U; i++, MASK >>= 1) {
unsigned int n = i + 24U;
if (READ_BIT(in, n))
cOrig |= MASK;
}
unsigned int a = Golay24128::encode24128(aOrig);
// The PRNG
unsigned int p = PRNG_TABLE[aOrig] >> 1;
unsigned int b = Golay24128::encode23127(bOrig) >> 1;
b ^= p;
MASK = 0x800000U;
for (unsigned int i = 0U; i < 24U; i++, MASK >>= 1) {
unsigned int aPos = AMBE_A_TABLE[i];
WRITE_BIT(out, aPos, a & MASK);
}
MASK = 0x400000U;
for (unsigned int i = 0U; i < 23U; i++, MASK >>= 1) {
unsigned int bPos = AMBE_B_TABLE[i];
WRITE_BIT(out, bPos, b & MASK);
}
MASK = 0x1000000U;
for (unsigned int i = 0U; i < 25U; i++, MASK >>= 1) {
unsigned int cPos = AMBE_C_TABLE[i];
WRITE_BIT(out, cPos, cOrig & MASK);
}
}
// ---------------------------------------------------------------------------
// Public Class Members
// ---------------------------------------------------------------------------
/* Initializes a new instance of the MBEEncoder class. */
MBEEncoder::MBEEncoder(MBE_ENCODER_MODE mode) :
m_mbeMode(mode),
m_gainAdjust(0.0f)
{
mbe_parms enh_mp;
mbe_initMbeParms(&m_curMBEParms, &m_prevMBEParms, &enh_mp);
}
/* Encodes the given MBE bits to deinterleaved MBE bits using the decoder mode. */
void MBEEncoder::encodeBits(uint8_t* bits, uint8_t* codeword)
{
assert(bits != nullptr);
assert(codeword != nullptr);
int32_t errs = 0;
float samples[160U];
::memset(samples, 0x00U, 160U * sizeof(float));
switch (m_mbeMode)
{
case ENCODE_DMR_AMBE:
{
// build 49-bit AMBE bytes
uint8_t rawAmbe[9U];
::memset(rawAmbe, 0x00U, 9U);
for (int i = 0; i < 9; ++i) {
for (int j = 0; j < 8; ++j) {
rawAmbe[i] |= (bits[(i * 8) + j] << (7 - j));
}
}
// build DMR AMBE bytes
uint8_t dmrAMBE[9U];
::memset(dmrAMBE, 0x00U, 9U);
encodeDmrAMBE(rawAmbe, dmrAMBE);
::memcpy(codeword, dmrAMBE, 9U);
}
break;
case ENCODE_88BIT_IMBE:
{
uint8_t rawImbe[11U];
::memset(rawImbe, 0x00U, 11U);
for (int i = 0; i < 11; ++i) {
for (int j = 0; j < 8; ++j) {
rawImbe[i] |= (bits[(i * 8) + j] << (7 - j));
}
}
::memcpy(codeword, rawImbe, 11U);
}
break;
}
}
/* Encodes the given PCM samples using the encoder mode to MBE codewords. */
void MBEEncoder::encode(int16_t* samples, uint8_t* codeword)
{
assert(samples != nullptr);
assert(codeword != nullptr);
int16_t frame_vector[8]; // result ignored
// first do speech analysis to generate mbe model parameters
m_vocoder.imbe_encode(frame_vector, samples);
if (m_mbeMode == ENCODE_88BIT_IMBE) {
if (m_gainAdjust >= 1.0f) {
m_vocoder.set_gain_adjust(m_gainAdjust);
}
uint32_t offset = 0U;
int16_t mask = 0x0800;
for (uint32_t i = 0U; i < 12U; i++, mask >>= 1, offset++)
WRITE_BIT(codeword, offset, (frame_vector[0U] & mask) != 0);
mask = 0x0800;
for (uint32_t i = 0U; i < 12U; i++, mask >>= 1, offset++)
WRITE_BIT(codeword, offset, (frame_vector[1U] & mask) != 0);
mask = 0x0800;
for (uint32_t i = 0U; i < 12U; i++, mask >>= 1, offset++)
WRITE_BIT(codeword, offset, (frame_vector[2U] & mask) != 0);
mask = 0x0800;
for (uint32_t i = 0U; i < 12U; i++, mask >>= 1, offset++)
WRITE_BIT(codeword, offset, (frame_vector[3U] & mask) != 0);
mask = 0x0400;
for (uint32_t i = 0U; i < 11U; i++, mask >>= 1, offset++)
WRITE_BIT(codeword, offset, (frame_vector[4U] & mask) != 0);
mask = 0x0400;
for (uint32_t i = 0U; i < 11U; i++, mask >>= 1, offset++)
WRITE_BIT(codeword, offset, (frame_vector[5U] & mask) != 0);
mask = 0x0400;
for (uint32_t i = 0U; i < 11U; i++, mask >>= 1, offset++)
WRITE_BIT(codeword, offset, (frame_vector[6U] & mask) != 0);
mask = 0x0040;
for (uint32_t i = 0U; i < 7U; i++, mask >>= 1, offset++)
WRITE_BIT(codeword, offset, (frame_vector[7U] & mask) != 0);
}
else {
int b[9];
// halfrate audio encoding - output rate is 2450 (49 bits)
encodeAMBE(m_vocoder.param(), b, &m_curMBEParms, &m_prevMBEParms, m_gainAdjust);
uint8_t bits[49U];
::memset(bits, 0x00U, 49U);
encode49bit(bits, b);
// build 49-bit AMBE bytes
uint8_t rawAmbe[9U];
::memset(rawAmbe, 0x00U, 9U);
for (int i = 0; i < 9; ++i) {
for (int j = 0; j < 8; ++j) {
rawAmbe[i] |= (bits[(i * 8) + j] << (7 - j));
}
}
// build DMR AMBE bytes
uint8_t dmrAMBE[9U];
::memset(dmrAMBE, 0x00U, 9U);
encodeDmrAMBE(rawAmbe, dmrAMBE);
::memcpy(codeword, dmrAMBE, 9U);
}
}

@ -0,0 +1,84 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Digital Voice Modem - MBE Vocoder
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright (C) 2019-2021 Doug McLain
* Copyright (C) 2021 Bryan Biedenkapp, N2PLL
*
*/
/**
* @file MBEEncoder.h
* @ingroup vocoder
* @file MBEEncoder.cpp
* @ingroup vocoder
*/
#if !defined(__MBE_ENCODER_H__)
#define __MBE_ENCODER_H__
#include "common/Defines.h"
#include "mbe.h"
#include "imbe/imbe_vocoder.h"
#include <stdint.h>
namespace vocoder
{
// ---------------------------------------------------------------------------
// Constants
// ---------------------------------------------------------------------------
/**
* @brief Vocoder Encoding Mode
*/
enum MBE_ENCODER_MODE {
ENCODE_DMR_AMBE, //! DMR AMBE
ENCODE_88BIT_IMBE, //! 88-bit IMBE (P25)
};
// ---------------------------------------------------------------------------
// Class Declaration
// ---------------------------------------------------------------------------
/**
* @brief Implements MBE audio encoding.
*/
class HOST_SW_API MBEEncoder {
public:
/**
* @brief Initializes a new instance of the MBEEncoder class.
* @param mode Encoder mode.
*/
MBEEncoder(MBE_ENCODER_MODE mode);
/**
* @brief Encodes the given MBE bits to deinterleaved MBE bits using the encoder mode.
* @param[in] bits
* @param[out] codeword
*/
void encodeBits(uint8_t* bits, uint8_t* codeword);
/**
* @brief Encodes the given PCM samples using the encoder mode to MBE codewords.
* @param[in] samples PCM samples (in short format)
* @param[out] codeword MBE codewords.
*/
void encode(int16_t* samples, uint8_t* codeword);
private:
imbe_vocoder m_vocoder;
mbe_parms m_curMBEParms;
mbe_parms m_prevMBEParms;
MBE_ENCODER_MODE m_mbeMode;
public:
/**
* @brief Gain adjustment.
*/
__PROPERTY(float, gainAdjust, GainAdjust);
};
} // namespace vocoder
#endif // __MBE_ENCODER_H__

@ -0,0 +1,404 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Digital Voice Modem - MBE Vocoder
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
*/
/*
* 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 <stdlib.h>
#define _USE_MATH_DEFINES
#include <math.h>
#include "vocoder/mbe.h"
#ifdef _MSC_VER
#pragma warning(disable: 4244)
#pragma warning(disable: 4305)
#endif
#if defined(__GNUC__) || defined(__GNUG__)
#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
#endif
// ---------------------------------------------------------------------------
// Externs
// ---------------------------------------------------------------------------
/*
** these are all declared by include in ambe3600x2450.c
*/
extern const float AmbeW0table[120];
extern const float AmbeLtable[120];
extern const int AmbeVuv[32][8];
extern const int AmbeLmprbl[57][4];
extern const float AmbeDg[32];
extern const float AmbePRBA24[512][3];
extern const float AmbePRBA58[128][4];
extern const float AmbeHOCb5[32][4];
extern const float AmbeHOCb6[16][4];
extern const float AmbeHOCb7[16][4];
extern const float AmbeHOCb8[8][4];
// ---------------------------------------------------------------------------
// Global Functions
// ---------------------------------------------------------------------------
/* */
int mbe_dequantizeAmbe2250Parms(mbe_parms* cur_mp, mbe_parms* prev_mp, const int* b)
{
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;
//char tmpstr[13];
int silence;
int Ji[5], jl;
float deltaGamma, BigGamma;
float unvc, rconst;
b0 = b[0];
b1 = b[1];
b2 = b[2];
b3 = b[3];
b4 = b[4];
b5 = b[5];
b6 = b[6];
b7 = b[7];
b8 = b[8];
silence = 0;
// copy repeat from prev_mp
cur_mp->repeat = prev_mp->repeat;
if ((b0 >= 120) && (b0 <= 123)) {
#ifdef AMBE_DEBUG
fprintf(stderr, "MBE: AMBE: Erasure Frame");
#endif
return (2);
}
else if ((b0 == 124) || (b0 == 125)) {
#ifdef AMBE_DEBUG
fprintf(stderr, "MBE: AMBE: Silence Frame");
#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, "MBE: AMBE: Tone Frame");
#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 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) {
cur_mp->Vl[l] = AmbeVuv[b1][jl];
}
#ifdef AMBE_DEBUG
fprintf(stderr, "MBE: AMBE: jl[%i]:%i Vl[%i]:%i", l, jl, l, cur_mp->Vl[l]);
#endif
}
#ifdef AMBE_DEBUG
fprintf(stderr, "MBE: AMBE: b0:%i w0:%f L:%i b1:%i", b0, cur_mp->w0, L, b1);
#endif
deltaGamma = AmbeDg[b2];
cur_mp->gamma = deltaGamma + ((float)0.5 * prev_mp->gamma);
#ifdef AMBE_DEBUG
fprintf(stderr, "MBE: AMBE: b2: %i, deltaGamma: %f gamma: %f gamma-1: %f", b2, deltaGamma, cur_mp->gamma, prev_mp->gamma);
#endif
// decode PRBA vectors
Gm[1] = 0;
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, "MBE: AMBE: 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", 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, "MBE: AMBE: R%i: %f", i, Ri[i]);
#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
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, "MBE: AMBE: Ji[1]: %i Ji[2]: %i Ji[3]: %i Ji[4]: %i", Ji[1], Ji[2], Ji[3], Ji[4]);
fprintf(stderr, "MBE: AMBE: b5: %i b6: %i b7: %i b8: %i", 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
fprintf(stderr, "MBE: AMBE: 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
fprintf(stderr, "MBE: AMBE: 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
fprintf(stderr, "MBE: AMBE: 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
fprintf(stderr, "MBE: AMBE: C4,%i: %f", k, Cik[4][k]);
#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, "MBE: AMBE: %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, "MBE: AMBE: Tl[%i]: %f", 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, "MBE: AMBE: 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, "MBE: AMBE: 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
fprintf(stderr, "MBE: AMBE: Sum43: %f", 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
fprintf(stderr, "MBE: AMBE: flokl[%i]: %f, intkl[%i]: %i", l, flokl[l], l, intkl[l]);
fprintf(stderr, "MBE: AMBE: deltal[%i]: %f", l, deltal[l]);
fprintf(stderr, "MBE: AMBE: prev_mp->log2Ml[%i]: %f", l, prev_mp->log2Ml[intkl[l]]);
fprintf(stderr, "MBE: AMBE: BigGamma: %f c1: %f c2: %f Sum43: %f Tl[%i]: %f log2Ml[%i]: %f Ml[%i]: %f", BigGamma, c1, c2, Sum43, l, Tl[l], l, cur_mp->log2Ml[l], l, cur_mp->Ml[l]);
#endif
}
return (0);
}
/* */
int mbe_dequantizeAmbeTone(mbe_tone* tone, const int* u)
{
int bitchk1, bitchk2;
int AD, ID1, ID2, ID3, ID4;
bitchk1 = (u[0] >> 6) & 0x3f;
bitchk2 = (u[3] & 0xf);
if ((bitchk1 != 63) || (bitchk2 != 0))
return -1; // Not a valid tone frame
AD = ((u[0] & 0x3f) << 1) + ((u[3] >> 4) & 0x1);
ID1 = ((u[1] & 0xfff) >> 4);
ID2 = ((u[1] & 0xf) << 4) + ((u[2] >> 7) & 0xf);
ID3 = ((u[2] & 0x7f) << 1) + ((u[3] >> 13) & 0x1);
ID4 = ((u[3] & 0x1fe0) >> 5);
if ((ID1 == ID2) && (ID1 == ID3) && (ID1 == ID4) &&
(((ID1 >= 5) && (ID1 <= 122)) || ((ID1 >= 128) && (ID1 <= 163)) || (ID1 == 255))) {
if (tone->ID == ID1) {
tone->AD = AD;
}
else {
tone->n = 0;
tone->ID = ID1;
tone->AD = AD;
}
return 0; // valid in-range tone frequency
}
return -1;
}

@ -0,0 +1,656 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Digital Voice Modem - MBE Vocoder
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
*/
/*
* 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 <stdlib.h>
#include <stdio.h>
#define _USE_MATH_DEFINES
#include <math.h>
#include "vocoder/mbe.h"
#include "vocoder/ambe3600x2400_const.h"
#ifdef _MSC_VER
#pragma warning(disable: 4244)
#endif
#if defined(__GNUC__) || defined(__GNUG__)
#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
#endif
// ---------------------------------------------------------------------------
// Global Functions
// ---------------------------------------------------------------------------
/* */
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, L9, 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;
// 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, "MBE: AMBE: index: %d, was <5, invalid!", b1);
silence = 1;
}
else if ((b1 >= 5) && (b1 <= 122)) {
fprintf(stderr, "MBE: AMBE: index: %d, Single tone hz: %f", b1, (float)b1 * 31.25);
}
else if ((b1 > 122) && (b1 < 128)) {
fprintf(stderr, "MBE: AMBE: index: %d, was >122 and <128, invalid!", b1);
silence = 1;
}
else if ((b1 >= 128) && (b1 <= 163)) {
fprintf(stderr, "MBE: AMBE: index: %d, Dual tone?", b1);
// note: dual tone index is different on ambe(dstar) and ambe2+
}
else {
fprintf(stderr, "MBE: AMBE: index: %d, was >163, invalid!", b1);
silence = 1;
}
if (silence == 1) {
#ifdef AMBE_DEBUG
fprintf(stderr, "MBE: AMBE: Silence Frame");
#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
fprintf(stderr, "MBE: AMBE: Tone Frame");
#endif
return (3);
}
// 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
// w0 guess
f0 = powf(2, (-4.311767578125 - (2.1336e-2 * ((float)b0 + 0.5))));
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 = AmbePlusLtable[b0];
// L formula from patent filings
//L=(int)((float)0.4627 / f0);
cur_mp->L = L;
}
L9 = L - 9;
// 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];
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
fprintf(stderr, "MBE: AMBE: jl[%i]:%i Vl[%i]:%i", l, jl, l, cur_mp->Vl[l]);
#endif
}
#ifdef AMBE_DEBUG
fprintf(stderr, "MBE: AMBE: b0:%i w0:%f L:%i b1:%i", 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];
deltaGamma = AmbePlusDg[b2];
cur_mp->gamma = deltaGamma + ((float)0.5 * prev_mp->gamma);
#ifdef AMBE_DEBUG
fprintf(stderr, "MBE: AMBE: b2: %i, deltaGamma: %f gamma: %f gamma-1: %f", 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
fprintf(stderr, "MBE: AMBE: 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", 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, "MBE: AMBE: R%i: %f ", i, Ri[i]);
#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
fprintf(stderr, "MBE: AMBE: Ji[1]: %i Ji[2]: %i Ji[3]: %i Ji[4]: %i", Ji[1], Ji[2], Ji[3], Ji[4]);
fprintf(stderr, "MBE: AMBE: b5: %i b6: %i b7: %i b8: %i", 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
fprintf(stderr, "MBE: AMBE: 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
fprintf(stderr, "MBE: AMBE: 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
fprintf(stderr, "MBE: AMBE: 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
fprintf(stderr, "MBE: AMBE: C4,%i: %f ", k, Cik[4][k]);
#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, "MBE: AMBE: 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, "MBE: AMBE: Tl[%i]: %f", 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, "MBE: AMBE: 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, "MBE: AMBE: 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
fprintf(stderr, "MBE: AMBE: Sum43: %f", 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
fprintf(stderr, "MBE: AMBE: flokl[%i]: %f, intkl[%i]: %i", l, flokl[l], l, intkl[l]);
fprintf(stderr, "MBE: AMBE: deltal[%i]: %f", l, deltal[l]);
fprintf(stderr, "MBE: AMBE: prev_mp->log2Ml[%i]: %f", l, prev_mp->log2Ml[intkl[l]]);
fprintf(stderr, "MBE: AMBE: BigGamma: %f c1: %f c2: %f Sum43: %f Tl[%i]: %f log2Ml[%i]: %f Ml[%i]: %f", 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* errs, 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);
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* errs, 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, errs, 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* errs, 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)
{
*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, errs, errs2, err_str, ambe_d, cur_mp, prev_mp, prev_mp_enhanced, uvquality);
}
/* */
void mbe_processAmbe3600x2400Frame(short* aout_buf, int* errs, 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, errs, errs2, err_str, ambe_fr, ambe_d, cur_mp, prev_mp, prev_mp_enhanced, uvquality);
mbe_floatToShort(float_buf, aout_buf);
}

@ -0,0 +1,903 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Digital Voice Modem - MBE Vocoder
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
*/
/**
* @file ambe3600x2400_const.h
* @ingroup vocoder
*/
/*
* 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.
*/
#if !defined(__AMBE3600x2400_CONST_H__)
#define __AMBE3600x2400_CONST_H__
#ifdef _MSC_VER
#pragma warning(disable: 4305)
#endif
// ---------------------------------------------------------------------------
// Constants
// ---------------------------------------------------------------------------
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 // __AMBE3600x2400_CONST_H__

@ -0,0 +1,600 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Digital Voice Modem - MBE Vocoder
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
*/
/*
* 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 <stdlib.h>
#include <stdio.h>
#define _USE_MATH_DEFINES
#include <math.h>
#include "vocoder/mbe.h"
#include "vocoder/ambe3600x2450_const.h"
#ifdef _MSC_VER
#pragma warning(disable: 4244)
#endif
#if defined(__GNUC__) || defined(__GNUG__)
#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
#endif
// ---------------------------------------------------------------------------
// Global Functions
// ---------------------------------------------------------------------------
/* */
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, L9, 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;
// 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
fprintf(stderr, "MBE: AMBE: Erasure Frame");
#endif
return (2);
}
else if ((b0 == 124) || (b0 == 125)) {
// if w0 bits are 1111100 or 1111101, frame is silence
#ifdef AMBE_DEBUG
fprintf(stderr, "MBE: AMBE: Silence Frame");
#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
fprintf(stderr, "MBE: AMBE: Tone Frame");
#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;
}
L9 = L - 9;
// 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
fprintf(stderr, "MBE: AMBE: jl[%i]:%i Vl[%i]:%i", l, jl, l, cur_mp->Vl[l]);
#endif
}
#ifdef AMBE_DEBUG
fprintf(stderr, "MBE: AMBE: b0:%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
fprintf(stderr, "MBE: AMBE: 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
fprintf(stderr, "MBE: AMBE: 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, "MBE: AMBE: R%i: %f ", i, Ri[i]);
#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
fprintf(stderr, "MBE: AMBE: Ji[1]: %i Ji[2]: %i Ji[3]: %i Ji[4]: %i", Ji[1], Ji[2], Ji[3], Ji[4]);
fprintf(stderr, "MBE: AMBE: b5: %i b6: %i b7: %i b8: %i", 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
fprintf(stderr, "MBE: AMBE: 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
fprintf(stderr, "MBE: AMBE: 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
fprintf(stderr, "MBE: AMBE: 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
fprintf(stderr, "MBE: AMBE: C4,%i: %f ", k, Cik[4][k]);
#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, "MBE: AMBE: 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, "MBE: AMBE: Tl[%i]: %f", 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, "MBE: AMBE: 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, "MBE: AMBE: 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
fprintf(stderr, "MBE: AMBE: Sum43: %f", 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
fprintf(stderr, "MBE: AMBE: flokl[%i]: %f, intkl[%i]: %i", l, flokl[l], l, intkl[l]);
fprintf(stderr, "MBE: AMBE: deltal[%i]: %f", l, deltal[l]);
fprintf(stderr, "MBE: AMBE: prev_mp->log2Ml[%i]: %f", l, prev_mp->log2Ml[intkl[l]]);
fprintf(stderr, "MBE: AMBE: BigGamma: %f c1: %f c2: %f Sum43: %f Tl[%i]: %f log2Ml[%i]: %f Ml[%i]: %f", 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* errs, 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* errs, 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, errs, 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* errs, 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)
{
*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, errs, errs2, err_str, ambe_d, cur_mp, prev_mp, prev_mp_enhanced, uvquality);
}
/* */
void mbe_processAmbe3600x2450Frame(short* aout_buf, int* errs, 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, errs, errs2, err_str, ambe_fr, ambe_d, cur_mp, prev_mp, prev_mp_enhanced, uvquality);
mbe_floatToShort(float_buf, aout_buf);
}

@ -0,0 +1,991 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Digital Voice Modem - MBE Vocoder
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
*/
/**
* @file ambe3600x2450_const.h
* @ingroup vocoder
*/
/*
* 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.
*/
#if !defined(__AMBE3600x2450_CONST_H__)
#define __AMBE3600x2450_CONST_H__
#ifdef _MSC_VER
#pragma warning(disable: 4305)
#endif
// ---------------------------------------------------------------------------
// Constants
// ---------------------------------------------------------------------------
/*
* 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 // __AMBE3600x2450_CONST_H__

@ -0,0 +1,179 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Digital Voice Modem - MBE Vocoder
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
*/
/*
* 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.
*/
#define _USE_MATH_DEFINES
#include <math.h>
#include "vocoder/ecc_const.h"
// ---------------------------------------------------------------------------
// Global Functions
// ---------------------------------------------------------------------------
/* */
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);
}

@ -0,0 +1,124 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Digital Voice Modem - MBE Vocoder
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
*/
/**
* @file ecc_const.h
* @ingroup vocoder
*/
/*
* 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.
*/
#if !defined(__ECC_CONST_H__)
#define __ECC_CONST_H__
// ---------------------------------------------------------------------------
// Constants
// ---------------------------------------------------------------------------
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 // __ECC_CONST_H__

@ -0,0 +1,183 @@
/*
* Project 25 IMBE Encoder/Decoder Fixed-Point implementation
* Developed by Pavel Yazev E-mail: pyazev@gmail.com
* Version 1.0 (c) Copyright 2009
*
* This 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, or (at your option)
* any later version.
*
* The software 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; see the file COPYING. If not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Boston, MA
* 02110-1301, USA.
*/
#include "vocoder/imbe/typedef.h"
#include "vocoder/imbe/basic_op.h"
#include "vocoder/imbe/imbe.h"
#include "vocoder/imbe/aux_sub.h"
#include "vocoder/imbe/tbls.h"
// ---------------------------------------------------------------------------
// Global Functions
// ---------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// PURPOSE:
// Return pointer to bit allocation array
// according to the number of harmonics
//
// INPUT:
// num_harms - The number of harmonics
//
// OUTPUT:
// None
//
// RETURN:
// Pointer to bits allocation array
//
//-----------------------------------------------------------------------------
const UWord16* get_bit_allocation_arr(Word16 num_harms)
{
Word16 offset_in_word, index;
if (num_harms == NUM_HARMS_MIN)
return &bit_allocation_tbl[0];
else {
index = num_harms - NUM_HARMS_MIN - 1;
offset_in_word = bit_allocation_offset_tbl[index >> 2] + ((3 + (index >> 2)) * (index & 0x3));
return &bit_allocation_tbl[offset_in_word];
}
}
//-----------------------------------------------------------------------------
// PURPOSE:
// Unpack bit allocation table's item
//
// INPUT:
// num_harms - The number of harmonics
// ptr - Pointer to buffer to place bit allocation data
//
// OUTPUT:
// Unpacked bit allocation table
//
// RETURN:
// None
//
//-----------------------------------------------------------------------------
void get_bit_allocation(Word16 num_harms, Word16* ptr)
{
const UWord16* bat_ptr;
Word16 i, tmp;
bat_ptr = get_bit_allocation_arr(num_harms);
for (i = 0; i < num_harms - 1; i += 4) {
tmp = *bat_ptr++;
ptr[3] = tmp & 0xF; tmp >>= 4;
ptr[2] = tmp & 0xF; tmp >>= 4;
ptr[1] = tmp & 0xF; tmp >>= 4;
ptr[0] = tmp & 0xF;
ptr += 4;
}
}
//-----------------------------------------------------------------------------
// PURPOSE:
// Set the elements of a 16 bit input vector to zero.
//
// INPUT:
// vec - Pointer to vector
// n - size of vec
//
// OUTPUT:
// None
//
// RETURN:
// None
//
//-----------------------------------------------------------------------------
void v_zap(Word16* vec, Word16 n)
{
while (n--)
*vec++ = 0;
}
//-----------------------------------------------------------------------------
// PURPOSE:
// Copy the contents of one 16 bit input vector to another
//
// INPUT:
// vec1 - Pointer to the destination vector
// vec2 - Pointer to the source vector
// n - size of data should be copied
//
// OUTPUT:
// Copy of the source vector
//
// RETURN:
// None
//
//-----------------------------------------------------------------------------
void v_equ(Word16* vec1, Word16* vec2, Word16 n)
{
while (n--)
*vec1++ = *vec2++;
}
//-----------------------------------------------------------------------------
// PURPOSE:
// Compute the sum of square magnitude of a 16 bit input vector
// with saturation and truncation. Output is a 32 bit number.
//
// INPUT:
// vec - Pointer to the vector
// n - size of input vectors
//
// OUTPUT:
// none
//
// RETURN:
// 32 bit long signed integer result
//
//-----------------------------------------------------------------------------
Word32 L_v_magsq(Word16* vec, Word16 n)
{
Word32 L_magsq = 0;
while (n--) {
L_magsq = L_mac(L_magsq, *vec, *vec);
vec++;
}
return L_magsq;
}
//-----------------------------------------------------------------------------
// PURPOSE:
// Copy the contents of one 16 bit input vector to another with shift
//
// INPUT:
// vec1 - Pointer to the destination vector
// vec2 - Pointer to the source vector
// scale - right shift factor
// n - size of data should be copied
//
// OUTPUT:
// Copy of the source vector
//
// RETURN:
// None
//
//-----------------------------------------------------------------------------
void v_equ_shr(Word16* vec1, Word16* vec2, Word16 scale, Word16 n)
{
while (n--)
*vec1++ = shr(*vec2++, scale);
}

@ -0,0 +1,134 @@
/*
* Project 25 IMBE Encoder/Decoder Fixed-Point implementation
* Developed by Pavel Yazev E-mail: pyazev@gmail.com
* Version 1.0 (c) Copyright 2009
*
* This 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, or (at your option)
* any later version.
*
* The software 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; see the file COPYING. If not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Boston, MA
* 02110-1301, USA.
*/
#ifndef __AUX_SUB_H__
#define __AUX_SUB_H__
// ---------------------------------------------------------------------------
// Global Functions
// ---------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// PURPOSE:
// Return pointer to bit allocation array
// according to the number of harmonics
//
// INPUT:
// num_harms - The number of harmonics
//
// OUTPUT:
// None
//
// RETURN:
// Pointer to bits allocation array
//
//-----------------------------------------------------------------------------
const UWord16 *get_bit_allocation_arr(Word16 num_harms);
//-----------------------------------------------------------------------------
// PURPOSE:
// Unpack bit allocation table's item
//
// INPUT:
// num_harms - The number of harmonics
// ptr - Pointer to buffer to place bit allocation data
//
// OUTPUT:
// Unpacked bit allocation table
//
// RETURN:
// None
//
//-----------------------------------------------------------------------------
void get_bit_allocation(Word16 num_harms, Word16 *ptr);
//-----------------------------------------------------------------------------
// PURPOSE:
// Set the elements of a 16 bit input vector to zero.
//
// INPUT:
// vec - Pointer to vector
// n - size of vec
//
// OUTPUT:
// None
//
// RETURN:
// None
//
//-----------------------------------------------------------------------------
void v_zap(Word16 *vec, Word16 n);
//-----------------------------------------------------------------------------
// PURPOSE:
// Copy the contents of one 16 bit input vector to another
//
// INPUT:
// vec1 - Pointer to the destination vector
// vec2 - Pointer to the source vector
// n - size of data should be copied
//
// OUTPUT:
// Copy of the source vector
//
// RETURN:
// None
//
//-----------------------------------------------------------------------------
void v_equ(Word16 *vec1, Word16 *vec2, Word16 n);
//-----------------------------------------------------------------------------
// PURPOSE:
// Compute the sum of square magnitude of a 16 bit input vector
// with saturation and truncation. Output is a 32 bit number.
//
// INPUT:
// vec - Pointer to the vector
// n - size of input vectors
//
// OUTPUT:
// none
//
// RETURN:
// 32 bit long signed integer result
//
//-----------------------------------------------------------------------------
Word32 L_v_magsq(Word16 *vec, Word16 n);
//-----------------------------------------------------------------------------
// PURPOSE:
// Copy the contents of one 16 bit input vector to another with shift
//
// INPUT:
// vec1 - Pointer to the destination vector
// vec2 - Pointer to the source vector
// scale - right shift factor
// n - size of data should be copied
//
// OUTPUT:
// Copy of the source vector
//
// RETURN:
// None
//
//-----------------------------------------------------------------------------
void v_equ_shr(Word16 *vec1, Word16 *vec2, Word16 scale, Word16 n);
#endif // __AUX_SUB_H__

File diff suppressed because it is too large Load Diff

@ -0,0 +1,82 @@
/*
* Project 25 IMBE Encoder/Decoder Fixed-Point implementation
* Developed by Pavel Yazev E-mail: pyazev@gmail.com
* Version 1.0 (c) Copyright 2009
*
* This 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, or (at your option)
* any later version.
*
* The software 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; see the file COPYING. If not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Boston, MA
* 02110-1301, USA.
*/
#ifndef __BASIC_OP_H__
#define __BASIC_OP_H__
// ---------------------------------------------------------------------------
// Constants and Globals
// ---------------------------------------------------------------------------
extern Flag Overflow;
extern Flag Carry;
#define MAX_32 (Word32)0x7fffffffL
#define MIN_32 (Word32)0x80000000L
#define MAX_16 (Word16)0x7fff
#define MIN_16 (Word16)0x8000
// ---------------------------------------------------------------------------
// Global Functions
// ---------------------------------------------------------------------------
Word16 add(Word16 var1, Word16 var2); /* Short add, 1 */
Word16 sub(Word16 var1, Word16 var2); /* Short sub, 1 */
Word16 abs_s(Word16 var1); /* Short abs, 1 */
Word16 shl(Word16 var1, Word16 var2); /* Short shift left, 1 */
Word16 shr(Word16 var1, Word16 var2); /* Short shift right, 1 */
Word16 mult(Word16 var1, Word16 var2); /* Short mult, 1 */
Word32 L_mult(Word16 var1, Word16 var2); /* Long mult, 1 */
Word16 negate(Word16 var1); /* Short negate, 1 */
Word16 extract_h(Word32 L_var1); /* Extract high, 1 */
Word16 extract_l(Word32 L_var1); /* Extract low, 1 */
Word16 L_round(Word32 L_var1); /* Round, 1 */
Word32 L_mac(Word32 L_var3, Word16 var1, Word16 var2); /* Mac, 1 */
Word32 L_msu(Word32 L_var3, Word16 var1, Word16 var2); /* Msu, 1 */
Word32 L_macNs(Word32 L_var3, Word16 var1, Word16 var2); /* Mac without
sat, 1 */
Word32 L_msuNs(Word32 L_var3, Word16 var1, Word16 var2); /* Msu without
sat, 1 */
Word32 L_add(Word32 L_var1, Word32 L_var2); /* Long add, 2 */
Word32 L_sub(Word32 L_var1, Word32 L_var2); /* Long sub, 2 */
Word32 L_add_c(Word32 L_var1, Word32 L_var2); /* Long add with c, 2 */
Word32 L_sub_c(Word32 L_var1, Word32 L_var2); /* Long sub with c, 2 */
Word32 L_negate(Word32 L_var1); /* Long negate, 2 */
Word16 mult_r(Word16 var1, Word16 var2); /* Mult with round, 2 */
Word32 L_shl(Word32 L_var1, Word16 var2); /* Long shift left, 2 */
Word32 L_shr(Word32 L_var1, Word16 var2); /* Long shift right, 2*/
Word16 shr_r(Word16 var1, Word16 var2); /* Shift right with
round, 2 */
Word16 mac_r(Word32 L_var3, Word16 var1, Word16 var2); /* Mac with
rounding,2 */
Word16 msu_r(Word32 L_var3, Word16 var1, Word16 var2); /* Msu with
rounding,2 */
Word32 L_deposit_h(Word16 var1); /* 16 bit var1 -> MSB, 2 */
Word32 L_deposit_l(Word16 var1); /* 16 bit var1 -> LSB, 2 */
Word32 L_shr_r(Word32 L_var1, Word16 var2); /* Long shift right with
round, 3 */
Word32 L_abs(Word32 L_var1); /* Long abs, 3 */
Word32 L_sat(Word32 L_var1); /* Long saturation, 4 */
Word16 norm_s(Word16 var1); /* Short norm, 15 */
Word16 div_s(Word16 var1, Word16 var2); /* Short division, 18 */
Word16 norm_l(Word32 L_var1); /* Long norm, 30 */
#endif // __BASIC_OP_H__

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save

Powered by TurnKey Linux.