restore demodulation of digital voice modes
This commit is contained in:
parent
5032f4b66d
commit
aecb79a4d4
@ -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:
|
||||
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:
|
||||
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
|
||||
|
@ -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))
|
||||
|
32
owrx/dsp.py
32
owrx/dsp.py
@ -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
|
||||
|
@ -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] != ""}
|
||||
|
Loading…
Reference in New Issue
Block a user