added rx audio level and moved from linear to dB

This commit is contained in:
DJ2LS 2023-10-31 15:29:33 +01:00
parent 3f49b63930
commit 5632310b8c
12 changed files with 118 additions and 39 deletions

View file

@ -17,17 +17,22 @@ import {
getNewMessagesByDXCallsign,
} from "../js/chatHandler";
import { sendTestFrame, setTxAudioLevel } from "../js/sock.js";
import { sendTestFrame, setTxAudioLevel, setRxAudioLevel } from "../js/sock.js";
function tuneAudio() {
sendTestFrame();
}
function set_audio_level() {
function set_tx_audio_level() {
saveSettingsToFile();
setTxAudioLevel(settings.tx_audio_level);
}
function set_rx_audio_level() {
saveSettingsToFile();
setRxAudioLevel(settings.rx_audio_level);
}
function deleteChat() {
//console.log(chat.selectedCallsign)
deleteChatByCallsign(chat.selectedCallsign);
@ -1194,6 +1199,21 @@ const transmissionSpeedChartDataMessageInfo = computed(() => ({
Transmit
</button>
</div>
<div class="input-group input-group-sm mb-1">
<span class="input-group-text">RX Level</span>
<span class="input-group-text">{{ settings.rx_audio_level }}</span>
<span class="input-group-text w-75">
<input
type="range"
class="form-range"
min="-30"
max="20"
step="1"
id="audioLevelRX"
@click="set_rx_audio_level()"
v-model="settings.rx_audio_level"
/></span>
</div>
<div class="input-group input-group-sm mb-1">
<span class="input-group-text">TX Level</span>
<span class="input-group-text">{{ settings.tx_audio_level }}</span>
@ -1201,11 +1221,11 @@ const transmissionSpeedChartDataMessageInfo = computed(() => ({
<input
type="range"
class="form-range"
min="0"
max="250"
min="-30"
max="20"
step="1"
id="audioLevelTX"
@click="set_audio_level()"
@click="set_tx_audio_level()"
v-model="settings.tx_audio_level"
/></span>
</div>

View file

@ -184,6 +184,7 @@ export function startModem() {
tuning_range_fmin: settings.tuning_range_fmin,
tuning_range_fmax: settings.tuning_range_fmax,
tx_audio_level: settings.tx_audio_level,
rx_audio_level: settings.rx_audio_level,
respond_to_cq: settings.respond_to_cq,
rx_buffer_size: settings.rx_buffer_size,
enable_explorer: settings.enable_explorer,

View file

@ -55,7 +55,8 @@ const configDefaultSettings =
"daemon_port": 3001,\
"rx_audio" : "",\
"tx_audio" : "",\
"tx_audio_level" : 100,\
"tx_audio_level" : 0,\
"rx_audio_level" : 0,\
"mycall": "AA0AA-0",\
"myssid": "0",\
"mygrid": "JN40aa",\

View file

@ -31,6 +31,8 @@ const split_char = "0;1;";
// global to keep track of Modem connection error emissions
var modemShowConnectStateError = 1;
var setTxAudioLevelOnce = true;
var setRxAudioLevelOnce = true;
// network connection Timeout
setTimeout(connectModem, 2000);
@ -172,6 +174,7 @@ client.on("data", function (socketdata) {
stateStore.mode = data["mode"];
stateStore.bandwidth = data["bandwidth"];
stateStore.tx_audio_level = data["audio_level"];
stateStore.rx_audio_level = data["audio_level"];
// if audio level is different from config one, send new audio level to modem
//console.log(parseInt(stateStore.tx_audio_level))
//console.log(parseInt(settings.tx_audio_level))
@ -185,6 +188,16 @@ client.on("data", function (socketdata) {
setTxAudioLevel(settings.tx_audio_level);
}
if (
parseInt(stateStore.rx_audio_level) !==
parseInt(settings.rx_audio_level) &&
setRxAudioLevelOnce === true
) {
setRxAudioLevelOnce = false;
console.log(setRxAudioLevelOnce);
setRxAudioLevel(settings.rx_audio_level);
}
stateStore.dbfs_level = data["audio_dbfs"];
stateStore.ptt_state = data["ptt_state"];
stateStore.speed_level = data["speed_level"];
@ -541,6 +554,11 @@ export function setTxAudioLevel(value) {
'{"type" : "set", "command" : "tx_audio_level", "value" : "' + value + '"}';
writeTncCommand(command);
}
export function setRxAudioLevel(value) {
var command =
'{"type" : "set", "command" : "rx_audio_level", "value" : "' + value + '"}';
writeTncCommand(command);
}
// Send Message
export function sendMessage(obj) {

View file

@ -6,6 +6,7 @@ export const useSettingsStore = defineStore("settingsStore", () => {
var tx_audio = ref();
var rx_audio = ref();
var tx_audio_level = ref();
var rx_audio_level = ref();
// network
var modem_host = ref("127.0.0.1");
@ -159,6 +160,7 @@ export const useSettingsStore = defineStore("settingsStore", () => {
tx_audio: tx_audio.value,
rx_audio: rx_audio.value,
tx_audio_level: tx_audio_level.value,
rx_audio_level: rx_audio_level.value,
};
return config_export;
@ -227,5 +229,6 @@ export const useSettingsStore = defineStore("settingsStore", () => {
getSerialDevices,
serial_devices,
tx_audio_level,
rx_audio_level,
};
});

View file

@ -41,6 +41,8 @@ export const useStateStore = defineStore("stateStore", () => {
var hamlib_status = ref("");
var tx_audio_level = ref("");
var rx_audio_level = ref("");
var alc = ref("");
var is_codec2_traffic = ref("");
@ -159,6 +161,7 @@ export const useStateStore = defineStore("stateStore", () => {
audio_recording,
hamlib_status,
tx_audio_level,
rx_audio_level,
alc,
updateTncState,
arq_transmission_percent,

View file

@ -58,6 +58,7 @@ class CONFIG:
'rx': data[3],
'tx': data[4],
'txaudiolevel': data[14],
'rxaudiolevel': data[26],
'auto_tune': data[19]
}

View file

@ -501,6 +501,8 @@ class DAEMON:
if data[25] == "True":
options.append("--morse")
options.append("--rx-audio-level")
options.append(data[26])
# safe data to config file
config.write_entire_config(data)

View file

@ -190,10 +190,17 @@ if __name__ == "__main__":
PARSER.add_argument(
"--tx-audio-level",
dest="tx_audio_level",
default=50,
default=0,
help="Set the tx audio level at an early stage",
type=int,
)
PARSER.add_argument(
"--rx-audio-level",
dest="rx_audio_level",
default=0,
help="Set the rx audio level at an early stage",
type=int,
)
PARSER.add_argument(
"--rx-buffer-size",
dest="rx_buffer_size",
@ -315,6 +322,7 @@ if __name__ == "__main__":
ModemParam.tuning_range_fmin = ARGS.tuning_range_fmin
ModemParam.tuning_range_fmax = ARGS.tuning_range_fmax
AudioParam.tx_audio_level = ARGS.tx_audio_level
AudioParam.rx_audio_level = ARGS.rx_audio_level
Modem.respond_to_cq = ARGS.enable_respond_to_cq
ARQ.rx_buffer_size = ARGS.rx_buffer_size
Modem.enable_explorer = ARGS.enable_explorer
@ -367,7 +375,8 @@ if __name__ == "__main__":
Modem.low_bandwidth_mode = conf.get('Modem', 'narrowband', 'False')
ModemParam.tuning_range_fmin = float(conf.get('Modem', 'fmin', '-50.0'))
ModemParam.tuning_range_fmax = float(conf.get('Modem', 'fmax', '50.0'))
AudioParam.tx_audio_level = int(conf.get('AUDIO', 'txaudiolevel', '100'))
AudioParam.tx_audio_level = int(conf.get('AUDIO', 'txaudiolevel', '0'))
AudioParam.rx_audio_level = int(conf.get('AUDIO', 'rxaudiolevel', '0'))
Modem.respond_to_cq = conf.get('Modem', 'qrv', 'True')
ARQ.rx_buffer_size = int(conf.get('Modem', 'rx_buffer_size', '16'))
Modem.enable_explorer = conf.get('Modem', 'explorer', 'False')

View file

@ -16,19 +16,16 @@ import sys
import threading
import time
from collections import deque
import wave
import codec2
import itertools
import numpy as np
import sock
import sounddevice as sd
import static
from global_instances import ARQ, AudioParam, Beacon, Channel, Daemon, HamlibParam, ModemParam, Station, Statistics, TCIParam, Modem
from static import FRAME_TYPE
import structlog
import ujson as json
import tci
# FIXME used for def transmit_morse
import cw
from queues import DATA_QUEUE_RECEIVED, MODEM_RECEIVED_QUEUE, MODEM_TRANSMIT_QUEUE, RIGCTLD_COMMAND_QUEUE, \
AUDIO_RECEIVED_QUEUE, AUDIO_TRANSMIT_QUEUE, MESH_RECEIVED_QUEUE
@ -462,6 +459,7 @@ class RF:
# self.log.debug("[MDM] callback")
x = np.frombuffer(data_in48k, dtype=np.int16)
x = self.resampler.resample48_to_8(x)
x = set_audio_volume(x, AudioParam.rx_audio_level)
# audio recording for debugging purposes
if AudioParam.audio_record:
@ -815,7 +813,6 @@ class RF:
# self.log.debug("[MDM] mod out shorter than audio buffer", delta=delta)
self.modoutqueue.append(c)
def demodulate_audio(
self,
audiobuffer: codec2.audio_buffer,
@ -848,7 +845,6 @@ class RF:
:rtype: int
"""
nbytes = 0
try:
while self.stream.active:
@ -874,7 +870,7 @@ class RF:
if not ModemParam.channel_busy:
self.log.debug("[MDM] Setting channel_busy since codec2 data detected")
ModemParam.channel_busy=True
ModemParam.channel_busy_delay+=10
ModemParam.channel_busy_delay += 10
self.log.debug(
"[MDM] [demod_audio] modem state", mode=mode_name, rx_status=rx_status,
sync_flag=codec2.api.rx_sync_flags_to_text[rx_status]
@ -883,8 +879,6 @@ class RF:
ModemParam.is_codec2_traffic = False
# decrement codec traffic counter for making state smoother
print(f"{mode_name}: {self.is_codec2_traffic_counter}")
if self.is_codec2_traffic_counter > 0:
self.is_codec2_traffic_counter -= 1
ModemParam.is_codec2_traffic = True
@ -902,7 +896,6 @@ class RF:
# process commands only if Modem.listen = True
if Modem.listen:
# ignore data channel opener frames for avoiding toggle states
# use case: opener already received, but ack got lost and we are receiving
# an opener again
@ -1144,7 +1137,7 @@ class RF:
def get_scatter(self, freedv: ctypes.c_void_p) -> None:
"""
Ask codec2 for data about the received signal and calculate the scatter plot.
Side-effect: sets ModemParam.scatter
Side effect: sets ModemParam.scatter
:param freedv: codec2 instance to query
:type freedv: ctypes.c_void_p
@ -1186,7 +1179,7 @@ class RF:
"""
Ask codec2 for data about the received signal and calculate
the signal-to-noise ratio.
Side-effect: sets ModemParam.snr
Side effect: sets ModemParam.snr
:param freedv: codec2 instance to query
:type freedv: ctypes.c_void_p
@ -1232,7 +1225,7 @@ class RF:
def update_rig_data(self) -> None:
"""
Request information about the current state of the radio via hamlib
Side-effect: sets
Side effect: sets
- HamlibParam.hamlib_frequency
- HamlibParam.hamlib_mode
- HamlibParam.hamlib_bandwidth
@ -1263,6 +1256,7 @@ class RF:
e=e,
)
threading.Event().wait(1)
def calculate_fft(self) -> None:
"""
Calculate an average signal strength of the channel to assess
@ -1465,31 +1459,39 @@ def get_bytes_per_frame(mode: int) -> int:
# get number of bytes per frame for mode
return int(codec2.api.freedv_get_bits_per_modem_frame(freedv) / 8)
def set_audio_volume(datalist, volume: float) -> np.int16:
def set_audio_volume(datalist: np.ndarray, dB: float) -> np.ndarray:
"""
Scale values for the provided audio samples by volume,
`volume` is clipped to the range of 0-200
Scale values for the provided audio samples by dB.
:param datalist: Audio samples to scale
:type datalist: NDArray[np.int16]
:param volume: "Percentage" (0-200) to scale samples
:type volume: float
:type datalist: np.ndarray
:param dB: Decibels to scale samples, constrained to the range [-50, 50]
:type dB: float
:return: Scaled audio samples
:rtype: np.int16
:rtype: np.ndarray
"""
# make sure we have float as data type to avoid crash
try:
volume = float(volume)
except Exception as e:
print(f"[MDM] changing audio volume failed with error: {e}")
volume = 100.0
dB = float(dB)
except ValueError as e:
print(f"[MDM] Changing audio volume failed with error: {e}")
dB = 0.0 # 0 dB means no change
# Clip volume provided to acceptable values
volume = np.clip(volume, 0, 200) # limit to max value of 255
# Scale samples by the ratio of volume / 100.0
data = np.fromstring(datalist, np.int16) * (volume / 100.0) # type: ignore
return data.astype(np.int16)
# Clip dB value to the range [-50, 50]
dB = np.clip(dB, -30, 20)
# Ensure datalist is an np.ndarray
if not isinstance(datalist, np.ndarray):
print("[MDM] Invalid data type for datalist. Expected np.ndarray.")
return datalist
# Convert dB to linear scale
scale_factor = 10 ** (dB / 20)
# Scale samples
scaled_data = datalist * scale_factor
# Clip values to int16 range and convert data type
return np.clip(scaled_data, -32768, 32767).astype(np.int16)
def get_modem_error_state():

View file

@ -256,6 +256,12 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler):
else:
self.modem_set_tx_audio_level(received_json)
# SET RX AUDIO LEVEL
if received_json["type"] == "set" and received_json["command"] == "rx_audio_level":
if TESTMODE:
ThreadedTCPRequestHandler.modem_set_rx_audio_level(None, received_json)
else:
self.modem_set_rx_audio_level(received_json)
# TRANSMIT TEST FRAME
if received_json["type"] == "set" and received_json["command"] == "send_test_frame":
@ -493,6 +499,18 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler):
command=received_json,
)
def modem_set_rx_audio_level(self, received_json):
try:
AudioParam.rx_audio_level = int(received_json["value"])
command_response("rx_audio_level", True)
except Exception as err:
command_response("rx_audio_level", False)
log.warning(
"[SCK] TX audio command execution error",
e=err,
command=received_json,
)
def modem_set_send_test_frame(self, received_json):
try:
DATA_QUEUE_TRANSMIT.put(["SEND_TEST_FRAME"])

View file

@ -50,7 +50,8 @@ class ARQ:
@dataclass
class AudioParam:
tx_audio_level: int = 50
tx_audio_level: int = 0
rx_audio_level: int = 0
audio_input_devices = []
audio_output_devices = []
audio_input_device: int = -2