work on some todos

This commit is contained in:
Jakob Ketterl 2021-09-27 17:29:51 +02:00
parent 5b1000df87
commit edace3d451
3 changed files with 94 additions and 45 deletions

View File

@ -83,3 +83,14 @@ class FftChain(Chain):
self._setBlockSize(self.sampleRate / self.fps) self._setBlockSize(self.sampleRate / self.fps)
else: else:
self._setBlockSize(self.sampleRate / self.fps / fftAverages) self._setBlockSize(self.sampleRate / self.fps / fftAverages)
def setCompression(self, compression: str) -> None:
if compression == "adpcm" and not self.compressFftAdpcm:
self.compressFftAdpcm = FftAdpcm(self.size)
# should always be at the end
self.append(self.compressFftAdpcm)
elif compression == "none" and self.compressFftAdpcm:
self.compressFftAdpcm.stop()
self.compressFftAdpcm = None
# should always be at that position (right?)
self.remove(3)

View File

@ -36,6 +36,10 @@ class ClientDemodulatorChain(Chain):
inputRate = demod.getFixedAudioRate() if isinstance(demod, FixedAudioRateChain) else outputRate inputRate = demod.getFixedAudioRate() if isinstance(demod, FixedAudioRateChain) else outputRate
oRate = hdOutputRate if isinstance(demod, HdAudio) else outputRate oRate = hdOutputRate if isinstance(demod, HdAudio) else outputRate
self.clientAudioChain = ClientAudioChain(demod.getOutputFormat(), inputRate, oRate, audioCompression) self.clientAudioChain = ClientAudioChain(demod.getOutputFormat(), inputRate, oRate, audioCompression)
self.secondaryFftSize = 2048
self.secondaryFftOverlapFactor = 0.3
self.secondaryFftFps = 9
self.secondaryFftCompression = "adpcm"
self.secondaryFftChain = None self.secondaryFftChain = None
self.metaWriter = None self.metaWriter = None
self.secondaryFftWriter = None self.secondaryFftWriter = None
@ -157,14 +161,18 @@ class ClientDemodulatorChain(Chain):
self.secondaryFftChain = None self.secondaryFftChain = None
if self.secondaryDemodulator is not None and self.secondaryFftChain is None: if self.secondaryDemodulator is not None and self.secondaryFftChain is None:
# TODO eliminate constants self._createSecondaryFftChain()
self.secondaryFftChain = FftChain(self._getSelectorOutputRate(), 2048, 0.3, 9, "adpcm")
self.secondaryFftChain.setReader(self.selectorBuffer.getReader())
self.secondaryFftChain.setWriter(self.secondaryFftWriter)
if self.secondaryFftChain is not None: if self.secondaryFftChain is not None:
self.secondaryFftChain.setSampleRate(rate) self.secondaryFftChain.setSampleRate(rate)
def _createSecondaryFftChain(self):
if self.secondaryFftChain is not None:
self.secondaryFftChain.stop()
self.secondaryFftChain = FftChain(self._getSelectorOutputRate(), self.secondaryFftSize, self.secondaryFftOverlapFactor, self.secondaryFftFps, self.secondaryFftCompression)
self.secondaryFftChain.setReader(self.selectorBuffer.getReader())
self.secondaryFftChain.setWriter(self.secondaryFftWriter)
def _syncSquelch(self): def _syncSquelch(self):
if not self.demodulator.supportsSquelch() or (self.secondaryDemodulator is not None and not self.secondaryDemodulator.supportsSquelch()): if not self.demodulator.supportsSquelch() or (self.secondaryDemodulator is not None and not self.secondaryDemodulator.supportsSquelch()):
self.selector.setSquelchLevel(-150) self.selector.setSquelchLevel(-150)
@ -245,7 +253,6 @@ class ClientDemodulatorChain(Chain):
return return
self.sampleRate = sampleRate self.sampleRate = sampleRate
self.selector.setInputRate(sampleRate) self.selector.setInputRate(sampleRate)
# TODO update secondary FFT
def setPowerWriter(self, writer: Writer) -> None: def setPowerWriter(self, writer: Writer) -> None:
self.selector.setPowerWriter(writer) self.selector.setPowerWriter(writer)
@ -278,8 +285,12 @@ class ClientDemodulatorChain(Chain):
self.demodulator.setSlotFilter(filter) self.demodulator.setSlotFilter(filter)
def setSecondaryFftSize(self, size: int) -> None: def setSecondaryFftSize(self, size: int) -> None:
# TODO if size == self.secondaryFftSize:
pass return
self.secondaryFftSize = size
if not self.secondaryFftChain:
return
self._createSecondaryFftChain()
def setSecondaryFrequencyOffset(self, freq: int) -> None: def setSecondaryFrequencyOffset(self, freq: int) -> None:
if self.secondaryFrequencyOffset == freq: if self.secondaryFrequencyOffset == freq:
@ -290,6 +301,35 @@ class ClientDemodulatorChain(Chain):
return return
self.secondarySelector.setFrequencyOffset(self.secondaryFrequencyOffset) self.secondarySelector.setFrequencyOffset(self.secondaryFrequencyOffset)
def setSecondaryFftCompression(self, compression: str) -> None:
if compression == self.secondaryFftCompression:
return
self.secondaryFftCompression = compression
if not self.secondaryFftChain:
return
self.secondaryFftChain.setCompression(self.secondaryFftCompression)
def setSecondaryFftOverlapFactor(self, overlap: float) -> None:
if overlap == self.secondaryFftOverlapFactor:
return
self.secondaryFftOverlapFactor = overlap
if not self.secondaryFftChain:
return
self.secondaryFftChain.setVOverlapFactor(self.secondaryFftOverlapFactor)
def setSecondaryFftFps(self, fps: int) -> None:
if fps == self.secondaryFftFps:
return
self.secondaryFftFps = fps
if not self.secondaryFftChain:
return
self.secondaryFftChain.setFps(self.secondaryFftFps)
def getSecondaryFftOutputFormat(self) -> Format:
if self.secondaryFftCompression == "adpcm":
return Format.CHAR
return Format.SHORT
class ModulationValidator(OrValidator): class ModulationValidator(OrValidator):
""" """
@ -307,6 +347,9 @@ class DspManager(SdrSourceEventClient):
self.props = PropertyStack() self.props = PropertyStack()
# current audio mode. should be "audio" or "hd_audio" depending on what demodulatur is in use.
self.audioOutput = None
# local demodulator properties not forwarded to the sdr # local demodulator properties not forwarded to the sdr
# ensure strict validation since these can be set from the client # ensure strict validation since these can be set from the client
# and are used to build executable commands # and are used to build executable commands
@ -361,34 +404,6 @@ class DspManager(SdrSourceEventClient):
self.readers = {} self.readers = {}
# wire audio output
buffer = Buffer(self.chain.getOutputFormat())
self.chain.setWriter(buffer)
# TODO check for hd audio
self.wireOutput("audio", buffer)
# wire power level output
buffer = Buffer(Format.FLOAT)
self.chain.setPowerWriter(buffer)
self.wireOutput("smeter", buffer)
# wire meta output
buffer = Buffer(Format.CHAR)
self.chain.setMetaWriter(buffer)
self.wireOutput("meta", buffer)
# wire secondary FFT
# TODO format is different depending on compression
buffer = Buffer(Format.CHAR)
self.chain.setSecondaryFftWriter(buffer)
self.wireOutput("secondary_fft", buffer)
# wire secondary demodulator
buffer = Buffer(Format.CHAR)
self.chain.setSecondaryWriter(buffer)
# TODO there's multiple outputs depending on the modulation right now
self.wireOutput("secondary_demod", buffer)
if "start_mod" in self.props: if "start_mod" in self.props:
self.setDemodulator(self.props["start_mod"]) self.setDemodulator(self.props["start_mod"])
mode = Modes.findByModulation(self.props["start_mod"]) mode = Modes.findByModulation(self.props["start_mod"])
@ -404,8 +419,9 @@ class DspManager(SdrSourceEventClient):
self.subscriptions = [ self.subscriptions = [
self.props.wireProperty("audio_compression", self.setAudioCompression), self.props.wireProperty("audio_compression", self.setAudioCompression),
# probably unused: self.props.wireProperty("fft_compression", self.chain.setSecondaryFftCompression),
# self.props.wireProperty("fft_compression", self.dsp.set_fft_compression), self.props.wireProperty("fft_voverlap_factor", self.chain.setSecondaryFftOverlapFactor),
self.props.wireProperty("fft_fps", self.chain.setSecondaryFftFps),
self.props.wireProperty("digimodes_fft_size", self.chain.setSecondaryFftSize), self.props.wireProperty("digimodes_fft_size", self.chain.setSecondaryFftSize),
self.props.wireProperty("samp_rate", self.chain.setSampleRate), self.props.wireProperty("samp_rate", self.chain.setSampleRate),
self.props.wireProperty("output_rate", self.chain.setOutputRate), self.props.wireProperty("output_rate", self.chain.setOutputRate),
@ -437,6 +453,26 @@ class DspManager(SdrSourceEventClient):
self.props.wireProperty("secondary_offset_freq", self.chain.setSecondaryFrequencyOffset), self.props.wireProperty("secondary_offset_freq", self.chain.setSecondaryFrequencyOffset),
] ]
# wire power level output
buffer = Buffer(Format.FLOAT)
self.chain.setPowerWriter(buffer)
self.wireOutput("smeter", buffer)
# wire meta output
buffer = Buffer(Format.CHAR)
self.chain.setMetaWriter(buffer)
self.wireOutput("meta", buffer)
# wire secondary FFT
buffer = Buffer(self.chain.getSecondaryFftOutputFormat())
self.chain.setSecondaryFftWriter(buffer)
self.wireOutput("secondary_fft", buffer)
# wire secondary demodulator
buffer = Buffer(Format.CHAR)
self.chain.setSecondaryWriter(buffer)
self.wireOutput("secondary_demod", buffer)
self.startOnAvailable = False self.startOnAvailable = False
self.sdrSource.addClient(self) self.sdrSource.addClient(self)
@ -487,13 +523,14 @@ class DspManager(SdrSourceEventClient):
raise ValueError("unsupported demodulator: {}".format(mod)) raise ValueError("unsupported demodulator: {}".format(mod))
self.chain.setDemodulator(demodulator) self.chain.setDemodulator(demodulator)
output = "hd_audio" if isinstance(demodulator, HdAudio) else "audio"
if output != self.audioOutput:
self.audioOutput = output
# re-wire the audio to the correct client API # re-wire the audio to the correct client API
buffer = Buffer(self.chain.getOutputFormat()) buffer = Buffer(self.chain.getOutputFormat())
self.chain.setWriter(buffer) self.chain.setWriter(buffer)
if isinstance(demodulator, HdAudio): self.wireOutput(self.audioOutput, buffer)
self.wireOutput("hd_audio", buffer)
else:
self.wireOutput("audio", buffer)
def sendSecondaryConfig(self): def sendSecondaryConfig(self):
self.handler.write_secondary_dsp_config( self.handler.write_secondary_dsp_config(

View File

@ -47,11 +47,12 @@ class SpectrumThread(SdrSourceEventClient):
self.sdrSource.addClient(self) self.sdrSource.addClient(self)
self.subscriptions += [ self.subscriptions += [
self.props.filter("fft_size", "fft_compression").wire(self.restart), self.props.filter("fft_size").wire(self.restart),
# these props can be set on the fly # these props can be set on the fly
self.props.wireProperty("samp_rate", self.dsp.setSampleRate), self.props.wireProperty("samp_rate", self.dsp.setSampleRate),
self.props.wireProperty("fft_fps", self.dsp.setFps), self.props.wireProperty("fft_fps", self.dsp.setFps),
self.props.wireProperty("fft_voverlap_factor", self.dsp.setVOverlapFactor), self.props.wireProperty("fft_voverlap_factor", self.dsp.setVOverlapFactor),
self.props.wireProperty("fft_compression", self.dsp.setCompression),
] ]
buffer = Buffer(self.dsp.getOutputFormat()) buffer = Buffer(self.dsp.getOutputFormat())