restore demodulation of digital voice modes

This commit is contained in:
Jakob Ketterl 2021-08-26 15:58:02 +02:00
parent 5032f4b66d
commit aecb79a4d4
4 changed files with 71 additions and 12 deletions

View File

@ -49,19 +49,31 @@ class Chain:
self.workers[index].stop()
self.workers[index] = newWorker
error = None
if index == 0:
if self.reader is not None:
newWorker.setReader(self.reader)
else:
previousWorker = self.workers[index - 1]
self._connect(previousWorker, newWorker)
try:
previousWorker = self.workers[index - 1]
self._connect(previousWorker, newWorker)
except ValueError as e:
# store error for later raising, but still attempt the second connection
error = e
if index == len(self.workers) - 1:
if self.writer is not None:
newWorker.setWriter(self.writer)
else:
nextWorker = self.workers[index + 1]
self._connect(newWorker, nextWorker)
try:
nextWorker = self.workers[index + 1]
self._connect(newWorker, nextWorker)
except ValueError as e:
error = e
if error is not None:
raise e
def append(self, newWorker):
previousWorker = None

View File

@ -3,11 +3,9 @@ from pycsdr.modules import AudioResampler, Convert, AdpcmEncoder, Limit
from pycsdr.types import Format
class ClientAudioChain(Chain):
def __init__(self, format: Format, inputRate: int, clientRate: int, compression: str):
class Converter(Chain):
def __init__(self, format: Format, inputRate: int, clientRate: int):
workers = []
self.inputRate = inputRate
self.clientRate = clientRate
if inputRate != clientRate:
# we only have an audio resampler for float ATM so if we need to resample, we need to convert
if format != Format.FLOAT:
@ -15,20 +13,39 @@ class ClientAudioChain(Chain):
workers += [AudioResampler(inputRate, clientRate), Limit(), Convert(Format.FLOAT, Format.SHORT)]
elif format != Format.SHORT:
workers += [Convert(format, Format.SHORT)]
super().__init__(workers)
class ClientAudioChain(Chain):
def __init__(self, format: Format, inputRate: int, clientRate: int, compression: str):
self.format = format
self.inputRate = inputRate
self.clientRate = clientRate
workers = [self._buildConverter()]
if compression == "adpcm":
workers += [AdpcmEncoder(sync=True)]
super().__init__(workers)
def _buildConverter(self):
return Converter(self.format, self.inputRate, self.clientRate)
def setFormat(self, format: Format) -> None:
pass
if format == self.format:
return
self.format = format
self.replace(0, self._buildConverter())
def setInputRate(self, inputRate: int) -> None:
if inputRate == self.inputRate:
return
self.inputRate = inputRate
self.replace(0, self._buildConverter())
def setClientRate(self, clientRate: int) -> None:
if clientRate == self.clientRate:
return
self.clientRate = clientRate
self.replace(0, self._buildConverter())
def setAudioCompression(self, compression: str) -> None:
index = self.indexOf(lambda x: isinstance(x, AdpcmEncoder))

View File

@ -14,7 +14,7 @@ from csdr.chain.demodulator import BaseDemodulatorChain
from csdr.chain.selector import Selector
from csdr.chain.clientaudio import ClientAudioChain
from csdr.chain.analog import NFm, WFm, Am, Ssb
from csdr.chain.digiham import Dmr, Dstar, Nxdn, Ysf
from csdr.chain.digiham import DigihamChain, Dmr, Dstar, Nxdn, Ysf
from pycsdr.modules import Buffer, Writer
from pycsdr.types import Format
from typing import Union
@ -34,9 +34,18 @@ class ClientDemodulatorChain(Chain):
self.selector.setBandpass(-4000, 4000)
self.demodulator = demod
self.clientAudioChain = ClientAudioChain(Format.FLOAT, outputRate, outputRate, audioCompression)
self.metaWriter = None
self.squelchLevel = -150
super().__init__([self.selector, self.demodulator, self.clientAudioChain])
def setDemodulator(self, demodulator: BaseDemodulatorChain):
try:
self.clientAudioChain.setFormat(demodulator.getOutputFormat())
except ValueError:
# this will happen if the new format does not match the current demodulator.
# it's expected and should be mended when swapping out the demodulator in the next step
pass
self.replace(1, demodulator)
if self.demodulator is not None:
@ -58,8 +67,11 @@ class ClientDemodulatorChain(Chain):
if not demodulator.supportsSquelch():
self.selector.setSquelchLevel(-150)
else:
self.selector.setSquelchLevel(self.squelchLevel)
self.clientAudioChain.setFormat(demodulator.getOutputFormat())
if self.metaWriter is not None and isinstance(demodulator, DigihamChain):
demodulator.setMetaWriter(self.metaWriter)
def setLowCut(self, lowCut):
self.selector.setLowCut(lowCut)
@ -78,6 +90,9 @@ class ClientDemodulatorChain(Chain):
self.clientAudioChain.setAudioCompression(compression)
def setSquelchLevel(self, level: float) -> None:
if level == self.squelchLevel:
return
self.squelchLevel = level
if not self.demodulator.supportsSquelch():
return
self.selector.setSquelchLevel(level)
@ -95,6 +110,13 @@ class ClientDemodulatorChain(Chain):
def setPowerWriter(self, writer: Writer) -> None:
self.selector.setPowerWriter(writer)
def setMetaWriter(self, writer: Writer) -> None:
if writer is self.metaWriter:
return
self.metaWriter = writer
if isinstance(self.demodulator, DigihamChain):
self.demodulator.setMetaWriter(self.metaWriter)
def setSampleRate(self, sampleRate: int) -> None:
if sampleRate == self.sampleRate:
return
@ -182,6 +204,12 @@ class DspManager(Output, SdrSourceEventClient):
reader = buffer.getReader()
self.send_output("smeter", reader.read)
# wire meta output
buffer = Buffer(Format.CHAR)
self.chain.setMetaWriter(buffer)
reader = buffer.getReader()
self.send_output("meta", reader.read)
def set_dial_freq(changes):
if (
"center_freq" not in self.props

View File

@ -171,7 +171,9 @@ class MetaParser(Parser):
}
self.currentMetaData = None
def parse(self, raw: str):
def parse(self, raw: memoryview):
raw = raw.tobytes().decode("utf-8").rstrip("\n")
for meta in raw.split("\n"):
fields = meta.split(";")
meta = {v[0]: ":".join(v[1:]) for v in map(lambda x: x.split(":"), fields) if v[0] != ""}