openwebrx-clone/owrx/audio/chopper.py

92 lines
3.0 KiB
Python
Raw Normal View History

from owrx.modes import Modes, AudioChopperMode
2021-09-27 22:27:01 +00:00
from owrx.audio import AudioChopperProfile
from itertools import groupby
from owrx.audio import ProfileSourceSubscriber
from owrx.audio.wav import AudioWriter
2021-08-31 20:46:11 +00:00
from owrx.audio.queue import QueueJob
2021-09-06 18:00:14 +00:00
from csdr.module import ThreadModule
2021-09-06 13:05:33 +00:00
from pycsdr.types import Format
2021-09-27 22:27:01 +00:00
from abc import ABC, abstractmethod
2021-08-31 14:54:37 +00:00
import pickle
import logging
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)
2021-09-27 22:27:01 +00:00
class AudioChopperParser(ABC):
@abstractmethod
def parse(self, profile: AudioChopperProfile, frequency: int, line: bytes):
pass
2021-09-06 18:00:14 +00:00
class AudioChopper(ThreadModule, ProfileSourceSubscriber):
2021-09-27 22:27:01 +00:00
def __init__(self, mode_str: str, parser: AudioChopperParser):
2021-08-31 14:54:37 +00:00
self.parser = parser
2021-08-31 20:46:11 +00:00
self.dialFrequency = None
self.doRun = True
self.writers = []
mode = Modes.findByModulation(mode_str)
if mode is None or not isinstance(mode, AudioChopperMode):
raise ValueError("Mode {} is not an audio chopper mode".format(mode_str))
self.profile_source = mode.get_profile_source()
super().__init__()
2021-09-06 13:05:33 +00:00
def getInputFormat(self) -> Format:
return Format.SHORT
def getOutputFormat(self) -> Format:
return Format.CHAR
def stop_writers(self):
while self.writers:
self.writers.pop().stop()
def setup_writers(self):
self.stop_writers()
sorted_profiles = sorted(self.profile_source.getProfiles(), key=lambda p: p.getInterval())
groups = {interval: list(group) for interval, group in groupby(sorted_profiles, key=lambda p: p.getInterval())}
2021-05-01 14:51:02 +00:00
writers = [
2021-08-31 14:54:37 +00:00
AudioWriter(self, interval, profiles) for interval, profiles in groups.items()
2021-05-01 14:51:02 +00:00
]
2021-04-11 18:10:49 +00:00
for w in writers:
w.start()
2021-04-11 18:10:49 +00:00
self.writers = writers
def run(self) -> None:
logger.debug("Audio chopper starting up")
self.setup_writers()
self.profile_source.subscribe(self)
while self.doRun:
data = None
try:
2021-08-31 14:54:37 +00:00
data = self.reader.read()
except ValueError:
pass
2021-08-31 14:54:37 +00:00
if data is None:
self.doRun = False
else:
for w in self.writers:
2021-08-31 14:54:37 +00:00
w.write(data.tobytes())
logger.debug("Audio chopper shutting down")
self.profile_source.unsubscribe(self)
self.stop_writers()
def onProfilesChanged(self):
logger.debug("profile change received, resetting writers...")
self.setup_writers()
2021-08-31 20:46:11 +00:00
def setDialFrequency(self, frequency: int) -> None:
self.dialFrequency = frequency
def createJob(self, profile, filename):
return QueueJob(profile, self.dialFrequency, self, filename)
def sendResult(self, result):
for line in result.lines:
data = self.parser.parse(result.profile, result.frequency, line)
if data is not None and self.writer is not None:
self.writer.write(pickle.dumps(data))