diff --git a/csdr/chain/drm.py b/csdr/chain/drm.py new file mode 100644 index 0000000..be06eed --- /dev/null +++ b/csdr/chain/drm.py @@ -0,0 +1,16 @@ +from csdr.chain.demodulator import BaseDemodulatorChain, FixedIfSampleRateChain, FixedAudioRateChain +from pycsdr.modules import Convert +from pycsdr.types import Format +from owrx.drm import DrmModule + + +class Drm(BaseDemodulatorChain, FixedIfSampleRateChain, FixedAudioRateChain): + def __init__(self): + workers = [Convert(Format.COMPLEX_FLOAT, Format.COMPLEX_SHORT), DrmModule()] + super().__init__(workers) + + def getFixedIfSampleRate(self) -> int: + return 48000 + + def getFixedAudioRate(self) -> int: + return 48000 diff --git a/csdr/module.py b/csdr/module.py index efd5c1f..6b7b7e9 100644 --- a/csdr/module.py +++ b/csdr/module.py @@ -4,6 +4,7 @@ from pycsdr.types import Format from abc import ABCMeta, abstractmethod from threading import Thread from io import BytesIO +from subprocess import Popen, PIPE import pickle @@ -89,3 +90,39 @@ class PickleModule(ThreadModule): @abstractmethod def process(self, input): pass + + +class PopenModule(AutoStartModule, metaclass=ABCMeta): + def __init__(self): + self.process = None + super().__init__() + + @abstractmethod + def getCommand(self): + pass + + def start(self): + self.process = Popen(self.getCommand(), stdin=PIPE, stdout=PIPE) + Thread(target=self.pump(self.reader.read, self.process.stdin.write)).start() + Thread(target=self.pump(self.process.stdout.read, self.writer.write)).start() + + def stop(self): + if self.process is not None: + self.process.terminate() + self.process.wait() + self.process = None + self.reader.stop() + + def pump(self, read, write): + def copy(): + while True: + data = None + try: + data = read() + except ValueError: + pass + if data is None or isinstance(data, bytes) and len(data) == 0: + break + write(data) + + return copy diff --git a/owrx/drm.py b/owrx/drm.py new file mode 100644 index 0000000..f8d59de --- /dev/null +++ b/owrx/drm.py @@ -0,0 +1,14 @@ +from csdr.module import PopenModule +from pycsdr.types import Format + + +class DrmModule(PopenModule): + def getInputFormat(self) -> Format: + return Format.COMPLEX_FLOAT + + def getOutputFormat(self) -> Format: + return Format.SHORT + + def getCommand(self): + # dream -c 6 --sigsrate 48000 --audsrate 48000 -I - -O - + return ["dream", "-c", "6", "--sigsrate", "48000", "--audsrate", "48000", "-I", "-", "-O", "-"] diff --git a/owrx/dsp.py b/owrx/dsp.py index 81c0e09..6763b8e 100644 --- a/owrx/dsp.py +++ b/owrx/dsp.py @@ -13,6 +13,7 @@ from csdr.chain.clientaudio import ClientAudioChain from csdr.chain.analog import NFm, WFm, Am, Ssb from csdr.chain.digiham import DigihamChain, Dmr, Dstar, Nxdn, Ysf from csdr.chain.m17 import M17Chain +from csdr.chain.drm import Drm from csdr.chain.fft import FftChain from csdr.chain.digimodes import AudioChopperDemodulator, PacketDemodulator, PocsagDemodulator from pycsdr.modules import Buffer, Writer @@ -444,6 +445,8 @@ class DspManager(Output, SdrSourceEventClient): return Nxdn(self.props["digital_voice_codecserver"]) elif demod == "m17": return M17Chain() + elif demod == "drm": + return Drm() def setDemodulator(self, mod): demodulator = self._getDemodulator(mod) diff --git a/owrx/m17.py b/owrx/m17.py index d4c6944..e58402a 100644 --- a/owrx/m17.py +++ b/owrx/m17.py @@ -1,42 +1,13 @@ -from csdr.module import AutoStartModule +from csdr.module import PopenModule from pycsdr.types import Format -from subprocess import Popen, PIPE -import threading -class M17Module(AutoStartModule): - def __init__(self): - self.process = None - super().__init__() - +class M17Module(PopenModule): def getInputFormat(self) -> Format: return Format.SHORT def getOutputFormat(self) -> Format: return Format.SHORT - def start(self): - self.process = Popen(["m17-demod"], stdin=PIPE, stdout=PIPE) - threading.Thread(target=self.pump(self.reader.read, self.process.stdin.write)).start() - threading.Thread(target=self.pump(self.process.stdout.read, self.writer.write)).start() - - def stop(self): - if self.process is not None: - self.process.terminate() - self.process.wait() - self.process = None - self.reader.stop() - - def pump(self, read, write): - def copy(): - while True: - data = None - try: - data = read() - except ValueError: - pass - if data is None or isinstance(data, bytes) and len(data) == 0: - break - write(data) - - return copy + def getCommand(self): + return ["m17-demod"]