implement wfm demodulator chain

This commit is contained in:
Jakob Ketterl 2020-08-08 21:29:25 +02:00
parent da3f59fb9b
commit 448e266097
6 changed files with 67 additions and 5 deletions

View File

@ -165,6 +165,7 @@ class dsp(object):
def __init__(self, output):
self.samp_rate = 250000
self.output_rate = 11025
self.hd_output_rate = 44100
self.fft_size = 1024
self.fft_fps = 5
self.center_freq = 0
@ -273,6 +274,13 @@ class dsp(object):
]
else:
chain += ["csdr convert_f_s16"]
elif which == "wfm":
chain += ["csdr fmdemod_quadri_cf", "csdr limit_ff"]
chain += last_decimation_block
chain += [
"csdr deemphasis_wfm_ff {audio_rate} 50e-6",
"csdr convert_f_s16"
]
elif self.isDigitalVoice(which):
chain += ["csdr fmdemod_quadri_cf", "dc_block "]
chain += last_decimation_block
@ -305,7 +313,7 @@ class dsp(object):
chain += ["csdr amdemod_cf", "csdr fastdcblock_ff"]
chain += last_decimation_block
chain += ["csdr agc_ff", "csdr limit_ff", "csdr convert_f_s16"]
elif which == "freedv":
elif self.isFreeDV(which):
chain += ["csdr realpart_cf"]
chain += last_decimation_block
chain += [
@ -585,13 +593,18 @@ class dsp(object):
def get_output_rate(self):
return self.output_rate
def get_hd_output_rate(self):
return self.hd_output_rate
def get_audio_rate(self):
if self.isDigitalVoice() or self.isPacket() or self.isPocsag():
return 48000
elif self.isWsjtMode() or self.isJs8():
return 12000
elif self.get_demodulator() == "freedv":
elif self.isFreeDV():
return 8000
elif self.isHdAudio():
return self.get_hd_output_rate()
return self.get_output_rate()
def isDigitalVoice(self, demodulator=None):
@ -619,6 +632,16 @@ class dsp(object):
demodulator = self.get_secondary_demodulator()
return demodulator == "pocsag"
def isFreeDV(self, demodulator=None):
if demodulator is None:
demodulator = self.get_demodulator()
return demodulator == "freedv"
def isHdAudio(self, demodulator=None):
if demodulator is None:
demodulator = self.get_demodulator()
return demodulator == "wfm"
def set_output_rate(self, output_rate):
if self.output_rate == output_rate:
return
@ -626,6 +649,12 @@ class dsp(object):
self.calculate_decimation()
self.restart()
def set_hd_output_rate(self, hd_output_rate):
if self.hd_output_rate == hd_output_rate:
return
self.hd_output_rate = hd_output_rate
self.restart()
def set_demodulator(self, demodulator):
if demodulator in ["usb", "lsb", "cw"]:
demodulator = "ssb"
@ -685,7 +714,7 @@ class dsp(object):
def set_squelch_level(self, squelch_level):
self.squelch_level = squelch_level
# no squelch required on digital voice modes
actual_squelch = -150 if self.isDigitalVoice() or self.isPacket() or self.isPocsag() or self.get_demodulator() == "freedv" else self.squelch_level
actual_squelch = -150 if self.isDigitalVoice() or self.isPacket() or self.isPocsag() or self.isFreeDV() else self.squelch_level
if self.running:
self.pipes["squelch_pipe"].write("%g\n" % (self.convertToLinear(actual_squelch)))
@ -818,9 +847,10 @@ class dsp(object):
threading.Thread(target=watch_thread).start()
if self.output.supports_type("audio"):
audio_type = "hd_audio" if self.isHdAudio() else "audio"
if self.output.supports_type(audio_type):
self.output.send_output(
"audio",
audio_type,
partial(
self.process.stdout.read,
self.get_fft_bytes_to_read() if self.demodulator == "fft" else self.get_audio_bytes_to_read(),

View File

@ -238,6 +238,28 @@ AudioEngine.prototype.pushAudio = function(data) {
}
};
AudioEngine.prototype.pushHdAudio = function(data) {
if (!this.audioNode) return;
this.audioBytes.add(data.byteLength);
var buffer;
if (this.compression === "adpcm") {
//resampling & ADPCM
buffer = this.audioCodec.decode(new Uint8Array(data));
} else {
buffer = new Int16Array(data);
}
buffer = this.hdResampler.process(buffer);
if (this.audioNode.port) {
// AudioWorklets supported
this.audioNode.port.postMessage(buffer);
} else {
// silently drop excess samples
if (this.getBuffersize() + buffer.length <= this.maxBufferSize) {
this.audioBuffers.push(buffer);
}
}
}
AudioEngine.prototype.setCompression = function(compression) {
this.compression = compression;
};

View File

@ -829,6 +829,10 @@ function on_ws_recv(evt) {
secondary_demod_waterfall_add(waterfall_f32);
}
break;
case 4:
// hd audio data
audioEngine.pushHdAudio(data);
break;
default:
console.warn('unknown type of binary message: ' + type)
}

View File

@ -299,6 +299,9 @@ class OpenWebRxReceiverClient(OpenWebRxClient):
def write_dsp_data(self, data):
self.send(bytes([0x02]) + data)
def write_hd_audio(self, data):
self.send(bytes([0x04]) + data)
def write_s_meter_level(self, level):
self.send({"type": "smeter", "value": level})

View File

@ -95,6 +95,7 @@ class DspManager(csdr.output):
self.props.wireProperty("digimodes_fft_size", self.dsp.set_secondary_fft_size),
self.props.wireProperty("samp_rate", self.dsp.set_samp_rate),
self.props.wireProperty("output_rate", self.dsp.set_output_rate),
self.props.wireProperty("hd_output_rate", self.dsp.set_hd_output_rate),
self.props.wireProperty("offset_freq", self.dsp.set_offset_freq),
self.props.wireProperty("center_freq", self.dsp.set_center_freq),
self.props.wireProperty("squelch_level", self.dsp.set_squelch_level),
@ -147,6 +148,7 @@ class DspManager(csdr.output):
logger.debug("adding new output of type %s", t)
writers = {
"audio": self.handler.write_dsp_data,
"hd_audio": self.handler.write_hd_audio,
"smeter": self.handler.write_s_meter_level,
"secondary_fft": self.handler.write_secondary_fft,
"secondary_demod": self.handler.write_secondary_demod,

View File

@ -40,6 +40,7 @@ class DigitalMode(Mode):
class Modes(object):
mappings = [
AnalogMode("nfm", "FM", bandpass=Bandpass(-4000, 4000)),
AnalogMode("wfm", "WFM", bandpass=Bandpass(-16000, 16000)),
AnalogMode("am", "AM", bandpass=Bandpass(-4000, 4000)),
AnalogMode("lsb", "LSB", bandpass=Bandpass(-3000, -300)),
AnalogMode("usb", "USB", bandpass=Bandpass(300, 3000)),