Add demodulation toggle for digital voice

This commit is contained in:
Smittix
2026-02-10 12:02:08 +00:00
parent 9bfbd6231d
commit 0a02325c0c
3 changed files with 21 additions and 3 deletions
+5 -1
View File
@@ -52,6 +52,7 @@ dmr_active_device: Optional[int] = None
_active_ffmpeg_stdin: Optional[object] = None # set by stream endpoint
VALID_PROTOCOLS = ['auto', 'dmr', 'p25', 'p25p2', 'nxdn', 'dstar', 'provoice']
VALID_DEMODS = ['nfm', 'fm']
# Classic dsd flags
_DSD_PROTOCOL_FLAGS = {
@@ -489,11 +490,14 @@ def start_dmr() -> Response:
device = validate_device_index(data.get('device', 0))
protocol = str(data.get('protocol', 'auto')).lower()
ppm = validate_ppm(data.get('ppm', 0))
demod = str(data.get('demod', 'nfm')).lower()
except (ValueError, TypeError) as e:
return jsonify({'status': 'error', 'message': f'Invalid parameter: {e}'}), 400
if protocol not in VALID_PROTOCOLS:
return jsonify({'status': 'error', 'message': f'Invalid protocol. Use: {", ".join(VALID_PROTOCOLS)}'}), 400
if demod not in VALID_DEMODS:
return jsonify({'status': 'error', 'message': f'Invalid demod. Use: {", ".join(VALID_DEMODS)}'}), 400
if protocol == 'p25p2' and not is_fme:
return jsonify({'status': 'error', 'message': 'P25 Phase 2 requires dsd-fme.'}), 400
@@ -521,7 +525,7 @@ def start_dmr() -> Response:
# internally via its own frame-sync detection.
rtl_cmd = [
rtl_fm_path,
'-M', 'fm',
'-M', demod,
'-f', str(freq_hz),
'-s', '48000',
'-g', str(gain),
+5 -2
View File
@@ -70,6 +70,7 @@ function startDmr() {
const gain = parseInt(document.getElementById('dmrGain')?.value || 40);
const ppm = parseInt(document.getElementById('dmrPPM')?.value || 0);
const relaxCrc = document.getElementById('dmrRelaxCrc')?.checked || false;
const demod = document.getElementById('dmrDemod')?.value || 'nfm';
const device = typeof getSelectedDevice === 'function' ? getSelectedDevice() : 0;
// Use protocol name for device reservation so panel shows "D-STAR", "P25", etc.
@@ -83,14 +84,14 @@ function startDmr() {
// Save settings to localStorage for persistence
try {
localStorage.setItem(DMR_SETTINGS_KEY, JSON.stringify({
frequency, protocol, gain, ppm, relaxCrc
frequency, protocol, gain, ppm, relaxCrc, demod
}));
} catch (e) { /* localStorage unavailable */ }
fetch('/dmr/start', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ frequency, protocol, gain, device, ppm, relaxCrc })
body: JSON.stringify({ frequency, protocol, gain, device, ppm, relaxCrc, demod })
})
.then(r => r.json())
.then(data => {
@@ -617,11 +618,13 @@ function restoreDmrSettings() {
const gainEl = document.getElementById('dmrGain');
const ppmEl = document.getElementById('dmrPPM');
const crcEl = document.getElementById('dmrRelaxCrc');
const demodEl = document.getElementById('dmrDemod');
if (freqEl && s.frequency != null) freqEl.value = s.frequency;
if (protoEl && s.protocol) protoEl.value = s.protocol;
if (gainEl && s.gain != null) gainEl.value = s.gain;
if (ppmEl && s.ppm != null) ppmEl.value = s.ppm;
if (crcEl && s.relaxCrc != null) crcEl.checked = s.relaxCrc;
if (demodEl && s.demod) demodEl.value = s.demod;
} catch (e) { /* localStorage unavailable */ }
}
+11
View File
@@ -29,6 +29,17 @@
</select>
</div>
<div class="form-group">
<label>Demodulation</label>
<select id="dmrDemod">
<option value="nfm" selected>NFM (recommended)</option>
<option value="fm">FM (wide)</option>
</select>
<span style="font-size: 0.75em; color: var(--text-muted); display: block; margin-top: 2px;">
Narrow FM often improves digital voice decode on 12.5 kHz channels.
</span>
</div>
<div class="form-group">
<label>Gain</label>
<input type="number" id="dmrGain" value="40" min="0" max="50" style="width: 100%;">