Fixed choppy audio from partial buffer reads, updated README to be more helpful.

This commit is contained in:
Jono Targett 2023-05-11 09:59:41 +09:30
parent f9480cd3c1
commit 53ffbb8afe
2 changed files with 60 additions and 11 deletions

View File

@ -3,7 +3,7 @@
This repository is a demo - it isn't a fully fleshed out system and isn't intended to be. Things might break. It also makes use of some 3rd-party code that we don't have a commercial licence for, so legally this can only be used for demonstration purposes, and only interally.
# Getting started
- Use a debian-based 64-bit system. No way around it; this project is not cross-platform.
- Install the SDRPlay device driver & install the project dependencies.
- `./SDRplay_RSP_API-Linux-3.07.1.run`
- Follow the prompts, there is some audience participation getting the driver installed.
@ -23,17 +23,67 @@ The NESDR Smart is a good starting place as it has a command line utility alread
## SDRPlay radio
The script `./sdrplay_sample` was built to mimic the interface provided by `rtl_sdr`, and is nearly a slot in replacement but for the SDRPlay hardware. It is used for producing raw I/Q samples from the radio device, which (assuming you tune to a frequency where an FM radio station is available) can be piped into the FM demodulator `fm_demod.py`, which itself outputs raw PCM audio.
To run the whole chain at once, tuning to a radio station frequency, demodulating the IQ samples to PCM and rendering to the system audio sink, run the following:
To capture raw IQ samples from the device, follow the below example (omitting the comments).
```bash
# FM broadcasting is in the VHF Band II space -
# in Australia this is 87.5 MHz to 108 MHz. You can specify the
# frequency as either a plan integer (87500000) or using a suffix:
export station="87.5M"
# FM broadcasting is in the VHF Band II space - in Australia this is 87.5 MHz to 108 MHz.
# You can specify the frequency as either a plain integer (87500000) or using a suffix:
station="87.5M"
# You'll want to replace that number with an actual radio station.
./sdrplay_sample -d sdrplay --format CS16 -f ${station} -s 384k | \
./sdrplay_sample \
-v \ # Enable verbose output.
-d sdrplay \ # Connect to first radio of sdrplay driver;
--format CS16 \ # Sample format of complex signed 16-bit int;
-f ${station} \ # Tune to FM station frequency;
-s 384k \ # Sampling rate 384 kHz;
-n 4M \ # Collect 4 million samples (~10 seconds);
-o output.iq # Save IQ samples to file.
# To find the formats, frequencies, sampling rates etc that are supported by the
# radio device, run:
./sdrplay_sample -v --list-devices
```
To demodulate the received IQ samples into raw PCM audio, do:
```bash
./fm_demod.py \
-f CS16 \ # Sample format must match IQ samples;
-s 384k \ # Sampling rate must match IQ samples;
-d 32k \ # Output rate - see notes.
< test.iq \ # IQ sample input file,
> test.raw # Write PCM to file.
# The output rate is a bit finicky as it needs to satisfy multiple requirements.
# - must be an integer divisor of the sampling rate;
# - must be a supported input format for the system sound card.
#
# A good ratio to aim for is for sampling-rate / output-rate = 10. This might not
# always be possible, but near enough will work. Higher and you're wasting samples
# and too low you will face audio problems.
```
Finally, to play the PCM file through the system audio out, use the `sox` utility. Most of the parameters are required to be fixed values, so only the modifiable ones are explained.
```bash
sox \
-t raw \
-r 32000 \ # Sample rate (must match demodulator output rate)
-b 16 \
-c 2 \
-L \
-e signed-integer \
test.raw \ # Input audio file
-d # Output to default audio device
```
To run the whole chain in realtime without using intermediary files, tuning to a radio station frequency, demodulating the IQ samples to PCM and rendering to the system audio sink, run the following:
```bash
./sdrplay_sample -d sdrplay --format CS16 -f ${station} -s 384k -o - | \
./fm_demod.py -f CS16 -s 384k -d 32k | \
sox -t raw -r 32000 -b 16 -c 2 -L -e signed-integer - -d
```
```
There's an outstanding bug where running live causes a buffer under-run in alsa - still working on that.

View File

@ -164,15 +164,14 @@ if args.d:
if args.verbose:
print('Rx:', result.ret, result.flags, result.timeNs, file=sys.stderr)
if result.ret != samples:
continue
if result.ret < 1:
print('Stream read failed, exiting.', file=sys.stderr)
keep_going = False
if outfile:
outfile.write(struct.pack(PACKINGS[format] % len(buffer), *buffer))
received = int(result.ret * 2)
outfile.write(struct.pack(PACKINGS[format] % received, *buffer[:received]))
if sample_count > 0:
total_samples += result.ret