openwebrx/csdr/chain/dablin.py

108 lines
3.5 KiB
Python
Raw Normal View History

2024-01-25 00:10:25 +01:00
from csdr.chain.demodulator import BaseDemodulatorChain, FixedIfSampleRateChain, FixedAudioRateChain, HdAudio, \
2024-01-26 20:50:03 +01:00
MetaProvider, DabServiceSelector, DialFrequencyReceiver
from csdr.module import PickleModule
from csdreti.modules import EtiDecoder
from owrx.dab.dablin import DablinModule
2024-01-24 22:37:20 +01:00
from pycsdr.modules import Downmix, Buffer, Shift, Writer
from pycsdr.types import Format
from typing import Optional
from random import random
import logging
logger = logging.getLogger(__name__)
class MetaProcessor(PickleModule):
def __init__(self, shifter: Shift):
self.shifter = shifter
self.shift = 0.0
self.coarse_increment = -32 / 2048000
self.fine_increment = - (1/3) / 2048000
2024-01-26 20:50:03 +01:00
# carrier spacing is 1kHz, don't drift further than that.
self.max_shift = 1000 / 2048000
super().__init__()
def process(self, data):
2024-01-24 22:37:20 +01:00
result = {}
2024-01-25 18:40:31 +01:00
for key, value in data.items():
if key == "coarse_frequency_shift":
if value > 0:
2024-01-26 20:50:03 +01:00
self._nudgeShift(random() * self.coarse_increment)
2024-01-25 18:40:31 +01:00
else:
2024-01-26 20:50:03 +01:00
self._nudgeShift(random() * -self.coarse_increment)
2024-01-25 18:40:31 +01:00
elif key == "fine_frequency_shift":
if abs(value) > 10:
logger.debug("ffs: %f", value)
2024-01-26 20:50:03 +01:00
self._nudgeShift(self.fine_increment * value)
2024-01-25 18:40:31 +01:00
else:
# pass through everything else
result[key] = value
2024-01-24 22:37:20 +01:00
# don't send out data if there was nothing interesting for the client
if not result:
return
result["mode"] = "DAB"
return result
2024-01-26 20:50:03 +01:00
def _nudgeShift(self, amount):
self.shift += amount
if self.shift > self.max_shift:
self.shift = self.max_shift
elif self.shift < -self.max_shift:
self.shift = -self.max_shift
logger.debug("new shift: %f", self.shift)
self.shifter.setRate(self.shift)
2024-01-26 20:50:03 +01:00
def resetShift(self):
logger.debug("resetting shift")
self.shift = 0
self.shifter.setRate(0)
class Dablin(BaseDemodulatorChain, FixedIfSampleRateChain, FixedAudioRateChain, HdAudio, MetaProvider, DabServiceSelector, DialFrequencyReceiver):
def __init__(self):
shift = Shift(0)
decoder = EtiDecoder()
metaBuffer = Buffer(Format.CHAR)
decoder.setMetaWriter(metaBuffer)
self.processor = MetaProcessor(shift)
self.processor.setReader(metaBuffer.getReader())
2024-01-24 22:37:20 +01:00
# use a dummy to start with. it won't run without.
# will be replaced by setMetaWriter().
self.processor.setWriter(Buffer(Format.CHAR))
2024-01-25 00:10:25 +01:00
self.dablin = DablinModule()
workers = [
shift,
decoder,
2024-01-25 00:10:25 +01:00
self.dablin,
Downmix(Format.FLOAT),
]
super().__init__(workers)
def _connect(self, w1, w2, buffer: Optional[Buffer] = None) -> None:
if isinstance(w2, EtiDecoder):
# eti decoder needs big chunks of data
buffer = Buffer(w1.getOutputFormat(), size=1048576)
super()._connect(w1, w2, buffer)
def getFixedIfSampleRate(self) -> int:
return 2048000
def getFixedAudioRate(self) -> int:
return 48000
def stop(self):
self.processor.stop()
2024-01-24 22:37:20 +01:00
def setMetaWriter(self, writer: Writer) -> None:
self.processor.setWriter(writer)
2024-01-25 00:10:25 +01:00
def setDabServiceId(self, serviceId: int) -> None:
self.dablin.setDabServiceId(serviceId)
2024-01-26 20:50:03 +01:00
def setDialFrequency(self, frequency: int) -> None:
self.processor.resetShift()