Compare commits
26 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
72aad99d20 | ||
|
38cc900b1c | ||
|
db0efc14f5 | ||
|
72e05f5276 | ||
|
e088006b4d | ||
|
483d954b95 | ||
|
a92f587734 | ||
|
8f0b33eb83 | ||
|
14eb71c8de | ||
|
1a9bcdeb07 | ||
|
6cce1ccdaa | ||
|
f0933472c9 | ||
|
fc5fb9166e | ||
|
59de2628c3 | ||
|
44c1e00509 | ||
|
4a68c9d3da | ||
|
2d183ffeac | ||
|
808418c723 | ||
|
c3cac092bd | ||
|
8797615720 | ||
|
b3cdc568d9 | ||
|
666c286485 | ||
|
d431e37d7b | ||
|
566b747928 | ||
|
22f0d90896 | ||
|
6b4432982e |
138
csdr/__init__.py
138
csdr/__init__.py
@ -59,7 +59,6 @@ class Dsp(DirewolfConfigSubscriber):
|
||||
self.fft_compression = "none"
|
||||
self.demodulator = "nfm"
|
||||
self.name = "csdr"
|
||||
self.base_bufsize = 512
|
||||
self.decimation = None
|
||||
self.last_decimation = None
|
||||
self.nc_port = None
|
||||
@ -109,23 +108,24 @@ class Dsp(DirewolfConfigSubscriber):
|
||||
chain = ["nc -v 127.0.0.1 {nc_port}"]
|
||||
if which == "fft":
|
||||
chain += [
|
||||
"csdr fft_cc {fft_size} {fft_block_size}",
|
||||
"csdr logpower_cf -70"
|
||||
"csdr++ fft {fft_size} {fft_block_size}",
|
||||
"csdr++ logpower -70"
|
||||
if self.fft_averages == 0
|
||||
else "csdr logaveragepower_cf -70 {fft_size} {fft_averages}",
|
||||
"csdr fft_exchange_sides_ff {fft_size}",
|
||||
else "csdr++ logaveragepower {fft_size} {fft_averages} --add -70",
|
||||
"csdr++ fftswap {fft_size}",
|
||||
]
|
||||
if self.fft_compression == "adpcm":
|
||||
chain += ["csdr compress_fft_adpcm_f_u8 {fft_size}"]
|
||||
chain += ["csdr++ fftadpcm {fft_size}"]
|
||||
return chain
|
||||
chain += ["csdr shift_addfast_cc --fifo {shift_pipe}"]
|
||||
chain += ["csdr++ shift --fifo {shift_pipe}"]
|
||||
if self.decimation > 1:
|
||||
chain += ["csdr fir_decimate_cc {decimation} {ddc_transition_bw} HAMMING"]
|
||||
chain += ["csdr bandpass_fir_fft_cc --fifo {bpf_pipe} {bpf_transition_bw} HAMMING"]
|
||||
chain += ["csdr++ firdecimate {decimation} {ddc_transition_bw} --window hamming"]
|
||||
chain += ["csdr++ bandpass --fft --fifo {bpf_pipe} {bpf_transition_bw} --window hamming"]
|
||||
if self.output.supports_type("smeter"):
|
||||
chain += [
|
||||
"csdr squelch_and_smeter_cc --fifo {squelch_pipe} --outfifo {smeter_pipe} 5 {smeter_report_every}"
|
||||
]
|
||||
if self.isSquelchActive():
|
||||
chain += ["csdr++ squelch --fifo {squelch_pipe} --outfifo {smeter_pipe} 5 {smeter_report_every}"]
|
||||
else:
|
||||
chain += ["csdr++ power --outfifo {smeter_pipe} 5 {smeter_report_every}"]
|
||||
if self.secondary_demodulator:
|
||||
if self.output.supports_type("secondary_fft"):
|
||||
chain += ["csdr tee {iqtee_pipe}"]
|
||||
@ -137,38 +137,38 @@ class Dsp(DirewolfConfigSubscriber):
|
||||
last_decimation_block = []
|
||||
if self.last_decimation >= 2.0:
|
||||
# activate prefilter if signal has been oversampled, e.g. WFM
|
||||
last_decimation_block = ["csdr fractional_decimator_ff {last_decimation} 12 --prefilter"]
|
||||
last_decimation_block = ["csdr++ fractionaldecimator --format float {last_decimation} --prefilter"]
|
||||
elif self.last_decimation != 1.0:
|
||||
last_decimation_block = ["csdr fractional_decimator_ff {last_decimation}"]
|
||||
last_decimation_block = ["csdr++ fractionaldecimator --format float {last_decimation}"]
|
||||
if which == "nfm":
|
||||
chain += ["csdr fmdemod_quadri_cf", "csdr limit_ff"]
|
||||
chain += ["csdr++ fmdemod", "csdr++ limit"]
|
||||
chain += last_decimation_block
|
||||
chain += [
|
||||
"csdr deemphasis_nfm_ff {audio_rate}",
|
||||
"csdr agc_ff --profile slow --max 3",
|
||||
"csdr++ deemphasis --nfm {audio_rate}",
|
||||
"csdr++ agc --format float --profile slow --max 3",
|
||||
]
|
||||
if self.get_audio_rate() != self.get_output_rate():
|
||||
chain += [
|
||||
"sox -t raw -r {audio_rate} -e floating-point -b 32 -c 1 --buffer 32 - -t raw -r {output_rate} -e signed-integer -b 16 -c 1 - "
|
||||
]
|
||||
else:
|
||||
chain += ["csdr convert_f_s16"]
|
||||
chain += ["csdr++ convert -i float -o s16"]
|
||||
elif which == "wfm":
|
||||
chain += [
|
||||
"csdr fmdemod_quadri_cf",
|
||||
"csdr limit_ff",
|
||||
"csdr++ fmdemod",
|
||||
"csdr++ limit",
|
||||
]
|
||||
chain += last_decimation_block
|
||||
chain += ["csdr deemphasis_wfm_ff {audio_rate} {wfm_deemphasis_tau}", "csdr convert_f_s16"]
|
||||
chain += ["csdr++ deemphasis --wfm {audio_rate} {wfm_deemphasis_tau}", "csdr++ convert -i float -o s16"]
|
||||
elif self.isDigitalVoice(which):
|
||||
chain += ["csdr fmdemod_quadri_cf"]
|
||||
chain += ["csdr++ fmdemod"]
|
||||
chain += last_decimation_block
|
||||
chain += ["dc_block"]
|
||||
# m17
|
||||
if which == "m17":
|
||||
chain += [
|
||||
"csdr limit_ff",
|
||||
"csdr convert_f_s16",
|
||||
"csdr++ limit",
|
||||
"csdr++ convert -i float -o s16",
|
||||
"m17-demod",
|
||||
]
|
||||
else:
|
||||
@ -197,87 +197,87 @@ class Dsp(DirewolfConfigSubscriber):
|
||||
chain += ["ysf_decoder --fifo {meta_pipe}", "mbe_synthesizer -y {codecserver_arg}"]
|
||||
chain += ["digitalvoice_filter"]
|
||||
chain += [
|
||||
"CSDR_FIXED_BUFSIZE=32 csdr agc_s16 --max 30 --initial 3",
|
||||
"sox -t raw -r 8000 -e signed-integer -b 16 -c 1 --buffer 32 - -t raw -r {output_rate} -e signed-integer -b 16 -c 1 - ",
|
||||
"csdr++ agc --format s16 --max 30 --initial 3",
|
||||
"sox --buffer 320 -t raw -r 8000 -e signed-integer -b 16 -c 1 - -t raw -r {output_rate} -e signed-integer -b 16 -c 1 - ",
|
||||
]
|
||||
elif which == "am":
|
||||
chain += ["csdr amdemod_cf", "csdr fastdcblock_ff"]
|
||||
chain += ["csdr++ amdemod", "csdr++ dcblock"]
|
||||
chain += last_decimation_block
|
||||
chain += [
|
||||
"csdr agc_ff --profile slow --initial 200",
|
||||
"csdr convert_f_s16",
|
||||
"csdr++ agc --format float --profile slow --initial 200",
|
||||
"csdr++ convert -i float -o s16",
|
||||
]
|
||||
elif self.isFreeDV(which):
|
||||
chain += ["csdr realpart_cf"]
|
||||
chain += ["csdr++ realpart"]
|
||||
chain += last_decimation_block
|
||||
chain += [
|
||||
"csdr agc_ff",
|
||||
"csdr convert_f_s16",
|
||||
"csdr++ agc --format float",
|
||||
"csdr++ convert -i float -o s16",
|
||||
"freedv_rx 1600 - -",
|
||||
"csdr agc_s16 --max 30 --initial 3",
|
||||
"csdr++ agc --format s16 --max 30 --initial 3",
|
||||
"sox -t raw -r 8000 -e signed-integer -b 16 -c 1 --buffer 32 - -t raw -r {output_rate} -e signed-integer -b 16 -c 1 - ",
|
||||
]
|
||||
elif self.isDrm(which):
|
||||
if self.last_decimation != 1.0:
|
||||
# we are still dealing with complex samples here, so the regular last_decimation_block doesn't fit
|
||||
chain += ["csdr fractional_decimator_cc {last_decimation}"]
|
||||
chain += ["csdr++ fractionaldecimator --format complex {last_decimation}"]
|
||||
chain += [
|
||||
"csdr convert_f_s16",
|
||||
"csdr++ convert -i float -o s16",
|
||||
"dream -c 6 --sigsrate 48000 --audsrate 48000 -I - -O -",
|
||||
"sox -t raw -r 48000 -e signed-integer -b 16 -c 2 - -t raw -r {output_rate} -e signed-integer -b 16 -c 1 - ",
|
||||
]
|
||||
elif which == "ssb":
|
||||
chain += ["csdr realpart_cf"]
|
||||
chain += ["csdr++ realpart"]
|
||||
chain += last_decimation_block
|
||||
chain += ["csdr agc_ff"]
|
||||
chain += ["csdr++ agc --format float"]
|
||||
# fixed sample rate necessary for the wsjt-x tools. fix with sox...
|
||||
if self.get_audio_rate() != self.get_output_rate():
|
||||
chain += [
|
||||
"sox -t raw -r {audio_rate} -e floating-point -b 32 -c 1 --buffer 32 - -t raw -r {output_rate} -e signed-integer -b 16 -c 1 - "
|
||||
]
|
||||
else:
|
||||
chain += ["csdr convert_f_s16"]
|
||||
chain += ["csdr++ convert -i float -o s16"]
|
||||
|
||||
if self.audio_compression == "adpcm":
|
||||
chain += ["csdr encode_ima_adpcm_i16_u8"]
|
||||
chain += ["csdr++ adpcm -e --sync"]
|
||||
return chain
|
||||
|
||||
def secondary_chain(self, which):
|
||||
chain = ["cat {input_pipe}"]
|
||||
if which == "fft":
|
||||
chain += [
|
||||
"csdr fft_cc {secondary_fft_input_size} {secondary_fft_block_size}",
|
||||
"csdr logpower_cf -70"
|
||||
"csdr++ fft {secondary_fft_input_size} {secondary_fft_block_size}",
|
||||
"csdr++ logpower -70"
|
||||
if self.fft_averages == 0
|
||||
else "csdr logaveragepower_cf -70 {secondary_fft_size} {fft_averages}",
|
||||
"csdr fft_exchange_sides_ff {secondary_fft_input_size}",
|
||||
else "csdr++ logaveragepower {secondary_fft_size} {fft_averages} --add -70",
|
||||
"csdr++ fftswap {secondary_fft_input_size}",
|
||||
]
|
||||
if self.fft_compression == "adpcm":
|
||||
chain += ["csdr compress_fft_adpcm_f_u8 {secondary_fft_size}"]
|
||||
chain += ["csdr++ fftadpcm {secondary_fft_size}"]
|
||||
return chain
|
||||
elif which == "bpsk31" or which == "bpsk63":
|
||||
return chain + [
|
||||
"csdr shift_addfast_cc --fifo {secondary_shift_pipe}",
|
||||
"csdr bandpass_fir_fft_cc -{secondary_bpf_cutoff} {secondary_bpf_cutoff} {secondary_bpf_cutoff}",
|
||||
"csdr simple_agc_cc 0.001 0.5",
|
||||
"csdr timing_recovery_cc GARDNER {secondary_samples_per_bits} 0.5 2 --add_q",
|
||||
"CSDR_FIXED_BUFSIZE=1 csdr dbpsk_decoder_c_u8",
|
||||
"CSDR_FIXED_BUFSIZE=1 csdr psk31_varicode_decoder_u8_u8",
|
||||
"csdr++ shift --fifo {secondary_shift_pipe}",
|
||||
"csdr++ bandpass --low -{secondary_bpf_cutoff} --high {secondary_bpf_cutoff} {secondary_bpf_cutoff}",
|
||||
"csdr++ agc --format complex",
|
||||
"csdr++ timingrecovery --algorithm gardner {secondary_samples_per_bits} 0.5 2 --add_q",
|
||||
"csdr++ dbpskdecode",
|
||||
"csdr++ varicodedecode",
|
||||
]
|
||||
elif self.isWsjtMode(which) or self.isJs8(which):
|
||||
chain += ["csdr realpart_cf"]
|
||||
chain += ["csdr++ realpart"]
|
||||
if self.last_decimation != 1.0:
|
||||
chain += ["csdr fractional_decimator_ff {last_decimation}"]
|
||||
return chain + ["csdr agc_ff", "csdr convert_f_s16"]
|
||||
chain += ["csdr++ fractionaldecimator --format float {last_decimation}"]
|
||||
return chain + ["csdr++ agc --format float", "csdr++ convert -i float -o s16"]
|
||||
elif which == "packet":
|
||||
chain += ["csdr fmdemod_quadri_cf"]
|
||||
chain += ["csdr++ fmdemod"]
|
||||
if self.last_decimation != 1.0:
|
||||
chain += ["csdr fractional_decimator_ff {last_decimation}"]
|
||||
return chain + ["csdr convert_f_s16", "direwolf -c {direwolf_config} -r {audio_rate} -t 0 -q d -q h 1>&2"]
|
||||
chain += ["csdr++ fractionaldecimator --format float {last_decimation}"]
|
||||
return chain + ["csdr++ convert -i float -o s16", "direwolf -c {direwolf_config} -r {audio_rate} -t 0 -q d -q h 1>&2"]
|
||||
elif which == "pocsag":
|
||||
chain += ["csdr fmdemod_quadri_cf"]
|
||||
chain += ["csdr++ fmdemod"]
|
||||
if self.last_decimation != 1.0:
|
||||
chain += ["csdr fractional_decimator_ff {last_decimation}"]
|
||||
chain += ["csdr++ fractionaldecimator --format float {last_decimation}"]
|
||||
return chain + ["fsk_demodulator -i", "pocsag_decoder"]
|
||||
|
||||
def set_secondary_demodulator(self, what):
|
||||
@ -290,8 +290,8 @@ class Dsp(DirewolfConfigSubscriber):
|
||||
def secondary_fft_block_size(self):
|
||||
base = (self.samp_rate / self.decimation) / (self.fft_fps * 2)
|
||||
if self.fft_averages == 0:
|
||||
return base
|
||||
return base / self.fft_averages
|
||||
return round(base)
|
||||
return round(base / self.fft_averages)
|
||||
|
||||
def secondary_decimation(self):
|
||||
return 1 # currently unused
|
||||
@ -594,9 +594,9 @@ class Dsp(DirewolfConfigSubscriber):
|
||||
|
||||
def fft_block_size(self):
|
||||
if self.fft_averages == 0:
|
||||
return self.samp_rate / self.fft_fps
|
||||
return round(self.samp_rate / self.fft_fps)
|
||||
else:
|
||||
return self.samp_rate / self.fft_fps / self.fft_averages
|
||||
return round(self.samp_rate / self.fft_fps / self.fft_averages)
|
||||
|
||||
def set_offset_freq(self, offset_freq):
|
||||
if offset_freq is None:
|
||||
@ -629,15 +629,14 @@ class Dsp(DirewolfConfigSubscriber):
|
||||
def convertToLinear(self, db):
|
||||
return float(math.pow(10, db / 10))
|
||||
|
||||
def isSquelchActive(self):
|
||||
return not self.isDigitalVoice() and not self.isPacket() and not self.isPocsag() and not self.isFreeDV() and not self.isDrm()
|
||||
|
||||
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.isFreeDV() or self.isDrm()
|
||||
else self.squelch_level
|
||||
)
|
||||
if self.running:
|
||||
actual_squelch = self.squelch_level if self.isSquelchActive() else -150
|
||||
if self.running and "squelch_pipe" in self.pipes:
|
||||
self.pipes["squelch_pipe"].write("%g\n" % (self.convertToLinear(actual_squelch)))
|
||||
|
||||
def set_codecserver(self, s):
|
||||
@ -757,7 +756,6 @@ class Dsp(DirewolfConfigSubscriber):
|
||||
bpf_transition_bw=float(self.bpf_transition_bw) / self.if_samp_rate(),
|
||||
ddc_transition_bw=self.ddc_transition_bw(),
|
||||
flowcontrol=int(self.samp_rate * 2),
|
||||
start_bufsize=self.base_bufsize * self.decimation,
|
||||
nc_port=self.nc_port,
|
||||
output_rate=self.get_output_rate(),
|
||||
smeter_report_every=int(self.if_samp_rate() / 6000),
|
||||
@ -769,7 +767,7 @@ class Dsp(DirewolfConfigSubscriber):
|
||||
logger.debug("Command = %s", command)
|
||||
|
||||
out = subprocess.PIPE if self.output.supports_type("audio") else subprocess.DEVNULL
|
||||
self.process = subprocess.Popen(command, stdout=out, shell=True, start_new_session=True)
|
||||
self.process = subprocess.Popen(command, stdout=out, shell=True, start_new_session=True, bufsize=128)
|
||||
|
||||
def watch_thread():
|
||||
rc = self.process.wait()
|
||||
|
@ -282,7 +282,7 @@ AudioEngine.prototype.processAudio = function(data, resampler) {
|
||||
var buffer;
|
||||
if (this.compression === "adpcm") {
|
||||
//resampling & ADPCM
|
||||
buffer = this.audioCodec.decode(new Uint8Array(data));
|
||||
buffer = this.audioCodec.decodeWithSync(new Uint8Array(data));
|
||||
} else {
|
||||
buffer = new Int16Array(data);
|
||||
}
|
||||
@ -328,6 +328,10 @@ ImaAdpcmCodec.prototype.reset = function() {
|
||||
this.stepIndex = 0;
|
||||
this.predictor = 0;
|
||||
this.step = 0;
|
||||
this.synchronized = 0;
|
||||
this.syncWord = "SYNC";
|
||||
this.syncCounter = 0;
|
||||
this.skip = 0;
|
||||
};
|
||||
|
||||
ImaAdpcmCodec.imaIndexTable = [ -1, -1, -1, -1, 2, 4, 6, 8, -1, -1, -1, -1, 2, 4, 6, 8 ];
|
||||
@ -353,6 +357,43 @@ ImaAdpcmCodec.prototype.decode = function(data) {
|
||||
return output;
|
||||
};
|
||||
|
||||
ImaAdpcmCodec.prototype.decodeWithSync = function(data) {
|
||||
var output = new Int16Array(data.length * 2);
|
||||
var index = this.skip;
|
||||
var oi = 0;
|
||||
while (index < data.length) {
|
||||
while (this.synchronized < 4 && index < data.length) {
|
||||
if (data[index] === this.syncWord.charCodeAt(this.synchronized)) {
|
||||
this.synchronized++;
|
||||
} else {
|
||||
this.synchronized = 0;
|
||||
}
|
||||
index++;
|
||||
if (this.synchronized === 4) {
|
||||
if (index + 4 < data.length) {
|
||||
var syncData = new Int16Array(data.buffer.slice(index, index + 4));
|
||||
this.stepIndex = syncData[0];
|
||||
this.predictor = syncData[1];
|
||||
}
|
||||
this.syncCounter = 1000;
|
||||
index += 4;
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (index < data.length) {
|
||||
if (this.syncCounter-- < 0) {
|
||||
this.synchronized = 0;
|
||||
break;
|
||||
}
|
||||
output[oi++] = this.decodeNibble(data[index] & 0x0F);
|
||||
output[oi++] = this.decodeNibble(data[index] >> 4);
|
||||
index++;
|
||||
}
|
||||
}
|
||||
this.skip = index - data.length;
|
||||
return output.slice(0, oi);
|
||||
};
|
||||
|
||||
ImaAdpcmCodec.prototype.decodeNibble = function(nibble) {
|
||||
this.stepIndex += ImaAdpcmCodec.imaIndexTable[nibble];
|
||||
this.stepIndex = Math.min(Math.max(this.stepIndex, 0), 88);
|
||||
|
@ -21,7 +21,7 @@ class FifiSdrSource(DirectSource):
|
||||
return super().getEventNames() + ["device"]
|
||||
|
||||
def getFormatConversion(self):
|
||||
return ["csdr convert_s16_f", "csdr gain_ff 5"]
|
||||
return ["csdr++ convert -i s16 -o float", "csdr++ gain 5"]
|
||||
|
||||
def sendRockProgFrequency(self, frequency):
|
||||
process = Popen(["rockprog", "--vco", "-w", "--freq={}".format(frequency / 1e6)])
|
||||
|
@ -23,8 +23,8 @@ class Resampler(DirectSource):
|
||||
def getCommand(self):
|
||||
return [
|
||||
"nc -v 127.0.0.1 {nc_port}".format(nc_port=self.sdr.getPort()),
|
||||
"csdr shift_addfast_cc {shift}".format(shift=self.shift),
|
||||
"csdr fir_decimate_cc {decimation} {ddc_transition_bw} HAMMING".format(
|
||||
"csdr++ shift {shift}".format(shift=self.shift),
|
||||
"csdr++ firdecimate {decimation} {ddc_transition_bw} --window hamming".format(
|
||||
decimation=self.decimation, ddc_transition_bw=self.transition_bw
|
||||
),
|
||||
] + self.getNmuxCommand()
|
||||
|
Loading…
Reference in New Issue
Block a user