Commit Graph

34 Commits (dependabot/github_actions/develop/actions/setup-python-7)

Author SHA1 Message Date
Steve Pinkham f522b46fa8 fix(audio): re-block captured RX audio into whole DSP blocks
With blocksize=0 PortAudio picks the capture block size per device. On
the devices measured for the previous commit it happened to deliver
multiple-of-6 block sizes, but other hardware returns 512/1024-class
blocks. codec2's resample48_to_8 asserts len(input) % 6 == 0
(FDMDV_OS_48), so on such a device every captured block raised
AssertionError, the DSP chain never ran, and RX was completely deaf.

The fix decouples the capture block size from the DSP block size
instead of pinning the stream back to blocksize=4800, which is the
configuration that negotiates a two-period ring on snd-aloop and drops
audio continuously (the deaf-on-loopback case the previous commit
fixed). Captured audio is appended to a carry buffer and the DSP chain
runs once per whole RX_DSP_BLOCK_48K (4800 samples, 100 ms) available;
the remainder carries into the next captured block, so the sample
stream handed to the resampler stays gapless (its filter memory spans
blocks) and always has a valid length, whatever the device delivers.

Running the DSP only on whole 4800-sample blocks also fixes three
silent degradations that short blocks caused:

- calculate_fft pads its input to 800 samples at 8 kHz, so short
  blocks fed the waterfall, channel-busy detection and audio_dbfs
  mostly zeros
- enqueue_streaming_audio_chunks zero-pads every block up to 2400
  samples and emits one chunk per block regardless of size, so short
  blocks streamed mostly silence and flooded the RX audio queue
- normalize_audio (rx_auto_audio_level, on by default) normalizes per
  block, so shorter blocks made the auto level faster and jumpier

Tests: the old test captured 4800-frame blocks, a multiple of 6, which
is exactly why this was never caught. The capture size is now 512 and
TestRxAudioReblocking covers odd sizes never reaching the resampler,
exact block accounting including the carried remainder, sample-stream
preservation (nothing dropped, duplicated or reordered), and every
re-blocked block being accepted end to end by the real codec2
resampler. Against the pre-fix code 5 of the 6 tests fail; with the
fix all pass.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-24 21:34:19 -04:00
Steve Pinkham 3a56ebdb35 perf(audio): lower RX latency with blocksize=0 and set the input ring depth explicitly
blocksize=4800 makes PortAudio hand the RX callback fixed 100 ms blocks,
so received audio sits in the input buffer for up to 100 ms before the
demodulator can see it, and that delay is paid again on every ARQ
turnaround. With blocksize=0 PortAudio delivers whatever is available
(small blocks in the 10 to 50 ms range in our measurements), cutting the
RX buffering delay to a fraction of the old fixed block.

On its own, blocksize=0 also shrinks the negotiated input ring. We
measured 40 ms total where blocksize=4800 had negotiated 200 ms on a
CM108 USB codec, which makes short processing stalls more likely to
drop audio. The explicit latency=0.2 closes that gap: it requests a
200 ms ring built from small periods, so the stream keeps the old depth
while gaining the low latency.

The explicit ring depth also makes the negotiation deterministic on
virtual devices. On snd-aloop (the ALSA loopback used for hardware-free
testing) the default "high" latency maps to only two periods. At 100 ms
periods that double buffer misses its service deadline on a fixed cycle
and the capture stream drops audio continuously from the moment it
opens, leaving the modem deaf on that device class. With an explicit
depth the same stream runs clean; we measured buffer 12000 frames with
2400 frame periods and zero overflows, identically on two machines.

TX stays at blocksize=2400; only the RX side changes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 07:20:19 -04:00
Steve Pinkham d8da991d61 perf(audio): run RX DSP off the real-time input callback
The sounddevice RX callback did all of the RX DSP inline: resample 48->8 kHz,
an FFT for the spectrum / channel-busy detection, optional level normalisation,
and a push into every decode mode's demod buffer. Running that on the real-time
audio thread means any delay in it -- a long GIL hold by another thread, a slow
resample on a constrained CPU -- can push the callback past its deadline and
overflow the capture stream.

Make the callback real-time-safe: it now only copies the captured block onto a
queue and returns. A dedicated worker thread (rx_audio_processing_worker) drains
the queue and runs the same DSP. The audio thread's work is now bounded and
constant.

This is also a prerequisite for lowering the input blocksize (next commit): a
smaller blocksize means a shallower capture ring, which only stays safe once the
DSP is off the real-time thread.

The DSP itself is unchanged -- the processing is moved verbatim, not altered.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 07:20:19 -04:00
as3ii f88f5fe2a3
Increased max line length to 120, reformatted everything
In practice, in this commit I've increased from 100 to 120 the maximum
allowed line length for python files and re-run ruff's formatter.
2026-01-10 19:11:26 +01:00
DJ2LS 68a4bdcff9
Merge branch 'develop' into ls-audio 2026-01-08 17:27:47 +01:00
DJ2LS 04366b0cb6
Merge branch 'develop' into ls-norm 2026-01-08 16:28:45 +01:00
as3ii 444c0d37cf
Removed f-strings without placeholders (ruff F541) 2025-11-13 22:45:07 +01:00
as3ii 6f7288335f
Switched from editing `sys.path` to proper PEP8 imports
See: https://peps.python.org/pep-0008/#imports

Here absolute imports have been used to avoid the error
`ImportError: attempted relative import with no known parent package`.
2025-11-13 19:49:38 +01:00
as3ii 23f1aab5aa
Removed references to pylint and useless file encoding 2025-11-13 16:32:23 +01:00
as3ii 66b2c6bf4e
Run `ruff format`
This applies mostly the same rules that `black` used.

This commit should not have introduced any logical or functional
changes, only fixing style consistency
2025-11-13 15:53:43 +01:00
DJ2LS efaf4cd146
Merge branch 'develop' into ls-audio 2025-08-31 09:36:26 +02:00
DJ2LS d7bb61eff7
Merge branch 'develop' into ls-norm 2025-08-31 09:36:03 +02:00
DJ2LS dfde101d2d possible fix for #980 2025-08-31 09:35:19 +02:00
DJ2LS 935e131e47 adjusted payloads 2025-06-26 10:51:39 +02:00
DJ2LS 5de53bfadf adjusted streaming 2025-06-04 14:06:26 +02:00
DJ2LS afafd71fb5 adjusted streaming 2025-06-02 15:58:37 +02:00
DJ2LS 1560304601 adjusted streaming 2025-06-02 15:36:19 +02:00
DJ2LS 2b6aeb26d3 attempt of streaming audio to gui 2025-06-02 12:16:46 +02:00
DJ2LS 708ed22c0a first success with test 2025-05-25 12:01:49 +02:00
DJ2LS e5208cffff adjustments to modem tests - still not working yet. but we have first benefits of new modem structure 2025-05-19 08:54:24 +02:00
DJ2LS 4e458110de more work 2025-04-29 13:01:16 +02:00
DJ2LS 653afee648 first commit containing introduction of context object 2025-04-28 21:43:29 +02:00
DJ2LS d5133f2d8d make this work a setting 2025-04-20 12:11:16 +02:00
DJ2LS 6ec1fd3b79 audio_normalized for rx 2025-04-17 20:36:03 +02:00
DJ2LS 35520dcca8 more docstrings 2025-03-12 13:53:46 +01:00
DJ2LS 96e73ea0fd fixing resampler 2025-03-12 11:58:54 +01:00
DJ2LS 8cedd62758 removed tci support 2025-03-11 10:56:59 +01:00
DJ2LS ff35b05a17 add audio normalisation - disabled for now 2025-01-19 13:59:41 +01:00
DJ2LS e4875f2aea add audio normalisation - disabled for now 2025-01-19 12:29:40 +01:00
DJ2LS 5c339f51c1 sending sine now respects audio level 2024-10-01 08:20:41 +02:00
DJ2LS 6ccd680458 send tune tone 2024-09-30 15:08:41 +02:00
DJ2LS e147ad0cfa increased audio input blocksize 2024-05-16 16:50:49 +02:00
DJ2LS acb5b03d51 more clean server shutdown 2024-04-21 13:24:04 +02:00
DJ2LS d5097b8b94 another folder renaming 2024-04-18 11:04:25 +02:00