diff --git a/README.md b/README.md index 96e345d..3a96d17 100644 --- a/README.md +++ b/README.md @@ -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 -``` \ No newline at end of file +``` + +There's an outstanding bug where running live causes a buffer under-run in alsa - still working on that. \ No newline at end of file diff --git a/sdrplay_sample b/sdrplay_sample index e1cfb64..f782c05 100755 --- a/sdrplay_sample +++ b/sdrplay_sample @@ -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