So it’s cricket season here and that means lots of sitting in front of the TV watching cricket and listening to the commentary by the clowns on Channel 9 when I would much rather be watching cricket and listening to the commentary by the clowns on ABC Grandstand.

The only problem is the audio delay. The digital TV broadcast lags behind the radio so that you hear the action before you see it, something like 10 seconds before. The delay is less with a digital radio but still in the order of 7 seconds or so. To make matters worse, the delay is dependent on the make of TV and digital radio you’re using.

But we are in luck! Because the radio precedes the video it should be possible to buffer up the audio from the radio, delay it by however long is needed and replay it back in sync with the video from the TV! Then all you need to do is mute the TV and you’re all set: watching cricket and listening to the commentary from the radio all in sync.

I bought a Raspberry Pi a few months back and decided this is something worth doing with the Pi. It is basically an embedded linux computer that runs at 700MHz+ with an ethernet port, 2 USB ports, a HDMI output and a stereo audio output.

The only problem is that the Raspberry Pi doesn’t have an an audio input. That’s where a USB audio interface comes into play! I happened to have an old Giffin iMic laying around, this has a line in and a line out and is perfect for the job.

Note that there are currently a few bugs in the Raspberry Pi kernel drivers for the USB interface that I found made it impractical to simultaneously run the audio input and output through the iMic over the USB interface. This resulted in lots of audio pops and breakups, so I resorted to using the audio input from the iMic over USB and the audio output from the built-in output on the Raspberry Pi.

The code should work with any USB input that is supported by the latest Raspbian “wheezy” image, but may need some fine tuning if you change the configuration of your Raspberry Pi.

I found that there was very little I needed to set up to get this to work, it uses perl, aplay and arecord from alsa utilities group which are all part of the standard Raspbian “wheezy” image. In fact it should work on any linux system fast enough to handle simultaneous input and output audio streams.

Download the code here:

audiodelay

The code is released under GPL V3 and comes with no warranty!

The code is sort of based on the idea I found here a perl script called “Sports Radio Delay”, but my code is different in that it uses separate threads for the input and output audio streams and a thread safe queue as a FIFO to pass the audio data between the input and output threads and also to implement the delay.

Usage and Troubleshooting
Having the latest version of the Raspberry Pi software helps:

$ sudo apt-get update && sudo apt-get upgrade

Having the latest firmware also helps with the USB performance, follow the instructions here.

Make the script executable:

$ chomd +x audiodelay

Run it, eg delay the audio input for 6.4 seconds

$ ./audiodelay 6.4

Now you’re all set, just hook your radio analogue output to the input on your audio source, hook the audio output from the Raspberry Pi to the audio input on your stereo and you’re all set.

The header of the script contains a few trouble shooting pointers on to how to modify the code to suit your audio interfaces and adjust the input and output levels.

Oh yeah, I am running my Raspberry Pi over clocked to 950MHz, with a headless command line only interface and as user “pi”, so your milage and permissions may vary.

I keep my Pi in an Adafruit Pi Box enclosure for safe keeping, and I’ve put some DRAM heat spreaders on the CPU and ethernet chip to try and keep them cooler.

13 thoughts on “Raspberry Pi Audio Delay”

  1. since Mac is basically linux, can you make an app that will run on mac sierra?

  2. It should be possible to make an app for the Mac to do the same thing as the script. The script may even work on a Mac with only minimal changes, but I’ll leave it up to others to do that…

  3. Tom,

    I’m very interested in this project. I’m a little unclear as to how you are adjusting the delay. Is it possible to pause and then start the audio to sync it?

  4. The delay is adjusted at start up using man-in-the-loop feedback, ie by trial and error. You set the delay at the command line, see if the delay is ok, if not try again with a different number. The code does not permit pausing. If I remember correctly the code takes the delay you specify at start up and creates a FIFO that many seconds deep in terms of audio samples. Then it tips samples in one end and waits for them to come out the other end of the tube, just like a pipeline delay. The system is asynchronous so the audio will eventually get out of sync with whatever you are trying to synchronise it to because clocks drift with time, then you’ll need to stop it and resynchronise it. It’s not very clever! Feel free to take the code and add extra features if you like.

  5. Oh and also…

    Any thoughts on how to use a potentiometer to adjust the delay?

    Thanks

  6. Hi Scott,

    Yes that Adafruit USB audio interface should work. As far as I can remember, the code is independent of the hardware so as long as the audio in and out works the code should work. You may need to change the code to use the appropriate device.

    As far as using a potentiometer to adjust the delay – no I don’t have any ideas how to do it.

    You can read a potentiometer easily enough with an A/D added on to the Raspberry Pi, you can build or find hardware and code to do that. You can use digital I/O, an RC circuit and a counter in the Raspberry Pi to do it too, but that’s a bit trickier and not as reliable/predictable.

    But the code is written to use a fixed delay at start up, it creates a fixed length FIFO pipeline equal in length to the delay you want and puts audio samples in one end and reads them out the other. It’s not written to use a variable delay like I think you’re trying to get with a potentiometer. This code needs to be stopped and restarted to change the delay which will interrupt the audio.

    Not saying it can’t be done, just that the code I have here isn’t written to give you a variable delay while running.

    Good luck!

  7. I just tried your perl script with my rp3/stretch… works great…

    Not sure… I have the input going to the usb mic and the output through the rp3 headphone jack??? Correct???

    Thanks
    Scott

  8. Input using USB, output using the built in audio output sounds right for the code as is.

    Mind you there’s nothing stopping you from doing input and output through the USB interface. I tried it like that back when I wrote the script and found it didn’t work well, but that was back when the USB audio drivers on the RPi were buggy, it might work better now, especially on the RPi3.

    Tom

  9. Hi!

    Interesting project! Is this setup usable for smaller delays too? is it possible på setup a short delay of 0.2 seconds, or is there a minimum delay inbuilt in the system?

  10. Hello,

    It might be possible to make the script work with only a short delay, but I haven’t used it in 8 years so I don’t know. The code checks the command line for a delay > 1.5 seconds then subtracts 0.8 seconds from that, and I can’t for the life of me remember why I did that… probably to tune the actual delay to the time requested due to latencies running on a Gen 1 Raspberry Pi. Latencies might not be a problem on newer hardware.

    It is just a perl script so it can be edited to remove where it checks the delay is greater than 1.5 seconds (line 104) and experiment with the removing the 0.8 offset (line 106) or add a new line at line 113 to hard code the delay to 0.2 seconds, eg:

    $delay = 0.2;

    and see what happens.

    Tom

Leave a Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.