In this section, we'll be looking at different techniques for triggering a recording or a playback, and optionally how to make it stop after a certain period of time.
The first method we'll cover is also the bluntest: how to start a recording or playback directly when powering up the Raspberry Pi. There isn't really a standardized way of auto-starting regular user applications on boot, so we'll have to improvise a bit to come up with our own way of doing what we want.
The Raspbian boot process is basically a collection of shell scripts being run one after the other, with each script performing some important task. One of the last scripts to run is /etc/rc.local
, which is a good starting point for our custom auto-run solution. Right now, the script doesn't do much, it just prints out the IP address of the Pi.
You can try running the script any time using the following command:
pi@raspberrypi ~ $ /etc/rc.local
We could just jam our list of commands right in there, but let's try to make our solution a little more elegant. We want the system to check whether there's an autorun script in our home directory, and if it exists, run it as the pi
user. This will make sure our script doesn't accidentally wipe our entire SD card or write huge WAV files in random locations:
rc.local
:pi@raspberrypi ~ $ sudo nano /etc/rc.local
if [ -x /home/pi/autorun.sh ]; then sudo -u pi /home/pi/autorun.sh fi
The preceding shell script means if there is an executable file named autorun.sh
in the pi
user's home directory, then run that script as the pi
user (not as root
, which would be the normal behavior for boot scripts).
If we run /etc/rc.local
right now, nothing new would happen-not until we create the autorun.sh
script in our home directory and make it executable.
pi@raspberrypi ~ $ nano ~/autorun.sh
#!/bin/sh
line, you're free to put anything in this script. Just keep in mind that you won't be able to use aliases here-you'll have to enter full commands. Here's an example record and playback script:#!/bin/sh
#
# Auto-run script for Raspberry Pi.
# Use chmod +x ~/autorun.sh to enable.
PLAYORREC=P # Set to P for Playback or R for Record
INPUTFILE="playme.wav"
OUTPUTFILE="myrec.wav"
MICROPHONE="-t alsa plughw:1"
SPEAKERS="-t alsa plughw:0"
case "$PLAYORREC" in
P|p) sox ~/"$INPUTFILE" $SPEAKERS ;;
R|r) sox $MICROPHONE ~/"$OUTPUTFILE" ;;
*) echo "Set the PLAYORREC variable to P for Playback or R for Record" ;;
esac
#!/bin/sh
line is called a shebang and is used to tell the system that any text that follows is to be passed on to the default shell (which is dash
during boot and bash
for logins on Raspbian) as a script.#
characters are comments, used only to convey information to anyone reading the script.PLAYORREC
variable is used to switch between the two operating modes of the script.INPUTFILE
is what will be played if we are in the playback mode, and OUTPUTFILE
is where we will record to if we are in the record mode. MICROPHONE
and SPEAKERS
lets us update the script easily for different audio gadgets.PLAYORREC
variable (which is P
at the moment) against three possible cases:PLAYORREC
contains a capital P
or a lowercase p
), then run this sox
playback command a hint to the user about it.PLAYORREC
contains a capital R
or a lowercase r
, then run this sox
record command.PLAYORREC
contains anything else or is left blank, then display a hint to user about it.
sox
command is launched with the values of the variables inserted as arguments, and we assume that the file specified is located in the pi
user's home directory.autorun.sh
script and exited the editor, there's one last thing we need to do before we can actually run it. We need to give the script executable permission with the chmod
command:pi@raspberrypi ~ $ chmod +x ~/autorun.sh
pi@raspberrypi ~ $ ~/autorun.sh
If everything works fine now, it should also run fine when you reboot.
One major improvement we could do to the script is to have tmux
start the playback or recording process in the background. That way we'll be able to log in remotely to check on sox
as it runs. Simply change the two sox
command lines as follows:
P|p) tmux new-session -s autostart -n $PLAYORREC -d "sox ~/"$INPUTFILE" $SPEAKERS" ;; R|r) tmux new-session -s autostart -n $PLAYORREC -d "sox $MICROPHONE ~/"$OUTPUTFILE"" ;;
Here we tell tmux
to create a new session named autostart
, create a new window named P
or R
depending on the mode, and start in a detached state. Then we specify the command we'd like to run inside the tmux
session surrounded by double quotes. Because $INPUTFILE
and $OUTPUTFILE
are also surrounded by double quotes, we have to escape those characters by prefixing them with the character.
The easiest way to temporarily disable the script when you don't need to play or record anything on boot is to remove the executable permission from the script:
pi@raspberrypi ~ $ chmod -x ~/autorun.sh
When we simply want to postpone the start of something for a few minutes, hours, or days, the at
command is a good fit.
Add it to the system using the following command:
pi@raspberrypi ~ $ sudo apt-get install at --no-install-recommends
The at
command can optionally send e-mails with status reports, but since that would require a small local mail server to be installed and running, we've told apt-get
not to install the additional recommended packages here.
Let's start with a demonstration of the basic at
facilities. First, we specify the time we want something to occur:
pi@raspberrypi ~ $ at now + 5 minutes
Next, at
will enter command input mode where we enter the commands we would like to execute, one per line:
at> sox ~/playme.wav -d at> echo "Finished playing at $(date)" >> ~/at.log
We then press Ctrl + D to signal that we are done with our command list, and we'll get an output with our job's ID number and the exact time it has been scheduled to start.
After five minutes have passed, your job will start running in the background. Note that there won't be any visible output from the application on your console. If you need to be sure that your command ran, you could write a line to a log file, as was done in the previous example.
Alternatively, you may schedule commands for an exact date and time:
pi@raspberrypi ~ $ at 9am 1 April 2016
Jobs in the queue waiting to be executed can be viewed using the following command:
pi@raspberrypi ~ $ atq
Once you know the job ID, you can remove it from the queue by replacing #
with your job ID:
pi@raspberrypi ~ $ atrm #
Another nifty trick is to specify a shell script to be executed instead of entering the commands manually:
pi@raspberrypi ~ $ at now + 30 minutes -f ~/autorun.sh
The Raspberry Pi board lacks a real-time clock (RTC), which computers use to keep track of the current time. Instead, the Pi has to ask other computers over the network what time it is when it boots up. Alternatively, it can obtain the correct time from a GPS module, as described in the Using GPS as a time source section of Chapter 5, Taking Your Pi Off-Road. The Pi is equally unable to keep track of the time that passes while it's powered off.
If we need to time something but know we won't have network access, we can combine the technique discussed in the Start on power up section with the at
command. This allows us to implement the idea Start the playback 1 hour after I plug in the Pi.
All we have to do is modify one line in our /etc/rc.local
script to add an at
timer:
if [ -x /home/pi/autorun.sh ]; then sudo -u pi at now + 1 hour -f /home/pi/autorun.sh fi
An automated SoX recording will continue to run until the Pi runs out of SD card space. We can use the trim
effect to stop the recording (or playback) after a certain amount of time has elapsed:
pi@raspberrypi ~ $ sox -t alsa plughw:1 myrec.wav trim 0 00:30:00
The previous command will record thirty minutes of audio to myrec.wav
and then stop. The first zero tells the trim effect to start measuring from the beginning of the file. The position where you want to cut the recording is then specified as hours:minutes:seconds
.
Another function useful for long recordings is to be able to split it into multiple files, each file with a certain duration. The following command will produce multiple WAV files, each file being one hour in length:
pi@raspberrypi ~ $ sox -t alsa plughw:1 myrec.wav trim 0 01:00:00 : newfile : restart
Wouldn't it be cool if the Pi could listen for activity in the room and only start recording when something or someone makes a sound? Once again SoX comes to the rescue.
Our noise detection method works in two simple steps:
First, let's calibrate the microphone and figure out a good amplitude threshold value:
pi@raspberrypi ~ $ sox -t alsa plughw:1 -n stat trim 0 00:00:01 : restart
This command starts monitoring your microphone, but the -n
argument tells SoX
to discard the output since we are only interested in the statistics produced by the stat
effect. The trim
effect then cuts of the monitoring after one second, the important statistics are printed, and a new monitoring second starts thanks to the restart
argument.
Now, keep your eyes on the Maximum amplitude value in the statistics output. As long as you stay quiet, the value shouldn't fluctuate too much from one readout to the other.
Next, make a loud noise and watch the Maximum amplitude value jump. Now try moving further away from the microphone and say something in your normal tone of voice. If there was a significant change in amplitude value, write that value down as a rough starting point for your threshold value. If not, try raising the capture volume of your microphone in alsamixer
until you see a significant increase in the amplitude value.
Alright, now all we need to do is translate the theory into program logic with the following script:
#!/bin/bash # # Noise activated recorder script for Raspberry Pi. # Use chmod +x ~/noisedetect.sh to enable. THRESHOLD=0.010000 noise_compare() { awk -v NOISE=$1 -v THRESHOLD=$2 'BEGIN {if (NOISE > THRESHOLD) exit 0; exit 1}' } while true ; do NOISE=$(sox -t alsa plughw:1 -n stat trim 0 00:00:01 2>&1 > /dev/null | grep 'Maximum amplitude' | cut -d ':' -f 2 | tr -d ' ') if noise_compare $NOISE $THRESHOLD; then echo "Noise detected ($NOISE) - Recording..." sox -t alsa plughw:1 $(date +%Y%m%d-%H%M%S).wav trim 0 00:05:00 fi done noise-detect.sh
The THRESHOLD
variable holds, of course, the threshold amplitude value that you found out by calibrating your microphone. Next comes the noise_compare
function. A function is a piece of code that can be called from other places in a script. In this case, we use it to compare two floating point numbers by passing them to the awk
command, since bash
doesn't have this ability built in.
Then we enter an infinite loop, which means our script will continue to run until we press Ctrl + C to break out of the loop. Next, we chain together a series of commands to extract the Maximum amplitude value from sox
and store it in the NOISE
variable, which is then compared with our THRESHOLD
variable with the help of the noise_compare
function.
If the NOISE
value is larger than the THRESHOLD
value, we start a 5-minute recording with the current date and time as the filename.
Now that you know how to do sound detection, you can easily swap out the sox
recording command to play an alarm bell or send an e-mail warning about a possible noisy intruder, as described in the Sending e-mail updates section of Chapter 5, Taking Your Pi Off-Road.
3.145.179.225