• WANTED: Happy members who like to discuss audio and other topics related to our interest. Desire to learn and share knowledge of science required as is 20 years of participation in forums (not all true). Come here to have fun, be ready to be teased and not take online life too seriously. We now measure and review equipment for free! Click here for details.

HOWTO: SoX audio tool as a signal generator

miero

Active Member
Joined
Aug 1, 2018
Messages
153
Likes
144
#1
SoX tool might be a very good reason to start learning how to use a command line. It allows to generate simple signals such as sine or square, combine them in various ways and apply many filters in a row using just several text keywords and numbers.

Initially SoX was created for Linux operating system but it is available also on other operating systems nowadays.

For example Windows 10 supports installing seamlessly integrated Ubuntu Linux distribution that will enable to use this guide: https://www.microsoft.com/en-us/p/ubuntu/9nblggh4msv6

A command line can be accessed from a console if there is no GUI on a machine or using a terminal application. On a Windows OS there are SSH or telnet clients (for example Putty) that allow a remote connection to a Linux machine (for example RaspberryPi).

For example, in a Debian based Linux distributions the SoX can be installed using following command:
Code:
sudo apt-get install sox libsox-fmt-all bc
This command will install also additional sox libraries (e.g. mp3 support) and a precision calculator 'bc' that will be used in examples bellow.

SoX provides 3 tools:
- sox, tool that can generate or convert audio files
- play, tool that can play files or generated signals to a sound card
- rec, tool that can record audio data to a file

Let's start with a simple command that generates 30 second sine tone of frequency 1kHz and volume -10dBFS with 48kHz sample rate and writes it to sin1k.wav file:
Rich (BB code):
sox -V -r 48000 -n -b 16 -c 2 sin1k.wav synth 30 sin 1000 vol -10dB
Briefly to used arguments:
-V ... this argument can be omitted, but it enables verbose output, so we can check input/output parameters and effect that are used​
-r 48000 -n ... (input specification) sets sample rate 48k for this session and specifies that there is no input file​
-b 16 -c 2 sin1k.wav ... (output specification) 16 bit output file with two channels named sin1k.wav​
synth 30 sin 1000 ... (1st effect) synthesizes 30 seconds of sine signal at frequency 1000Hz with max. amplitude​
vol -10dB ... (2nd effect) applies 10dB attenuation to a generated signal​
Let's see an example output of that command:
Rich (BB code):
$ sox -V -r 48000 -n -b 16 -c 2 sin1k.wav synth 30 sin 1000 vol -10dB
sox:      SoX v14.4.2

Input File     : '' (null)
Channels       : 1
Sample Rate    : 48000
Precision      : 32-bit

Output File    : 'sin1k.wav'
Channels       : 2
Sample Rate    : 48000
Precision      : 16-bit
Sample Encoding: 16-bit Signed Integer PCM
Endian Type    : little
Reverse Nibbles: no
Reverse Bits   : no
Comment        : 'Processed by SoX'

sox INFO sox: effects chain: input        48000Hz  1 channels
sox INFO sox: effects chain: synth        48000Hz  1 channels
sox INFO sox: effects chain: vol          48000Hz  1 channels
sox INFO sox: effects chain: channels     48000Hz  2 channels
sox INFO sox: effects chain: dither       48000Hz  2 channels
sox INFO sox: effects chain: output       48000Hz  2 channels
Notice: The SoX applies dither effect automatically if outputs data to 16 bit precision.

It might be useful to inspect parameters of generated file, so let's check it using stats effect:
Rich (BB code):
$ sox -V sin1k.wav -n stats
sox:      SoX v14.4.2
sox INFO formats: detected file format type `wav'

Input File     : 'sin1k.wav'
Channels       : 2
Sample Rate    : 48000
Precision      : 16-bit
Duration       : 00:00:30.00 = 1440000 samples ~ 2250 CDDA sectors
File Size      : 5.76M
Bit Rate       : 1.54M
Sample Encoding: 16-bit Signed Integer PCM
Endian Type    : little
Reverse Nibbles: no
Reverse Bits   : no


Output File    : '' (null)
Channels       : 2
Sample Rate    : 48000
Precision      : 16-bit
Duration       : 00:00:30.00 = 1440000 samples ~ 2250 CDDA sectors
sox INFO sox: effects chain: input        48000Hz  2 channels
sox INFO sox: effects chain: stats        48000Hz  2 channels
sox INFO sox: effects chain: output       48000Hz  2 channels
             Overall     Left      Right
DC offset   0.000000  0.000000  0.000000
Min level  -0.316254 -0.316254 -0.316254
Max level   0.316254  0.316254  0.316254
Pk lev dB     -10.00    -10.00    -10.00
RMS lev dB    -13.01    -13.01    -13.01
RMS Pk dB     -13.00    -13.00    -13.00
RMS Tr dB     -13.05    -13.05    -13.05
Crest factor       -      1.41      1.41
Flat factor     0.00      0.00      0.00
Pk count       12.7k     12.8k     12.7k
Bit-depth      15/16     15/16     15/16
Num samples    1.44M
Length s      30.000
Scale max   1.000000
Window s       0.050
Let's play that file!
Rich (BB code):
$ play -V sin1k.wav
play:      SoX v14.4.2
play INFO formats: detected file format type `wav'

Input File     : 'sin1k.wav'
Channels       : 2
Sample Rate    : 48000
Precision      : 16-bit
Duration       : 00:00:30.00 = 1440000 samples ~ 2250 CDDA sectors
File Size      : 5.76M
Bit Rate       : 1.54M
Sample Encoding: 16-bit Signed Integer PCM
Endian Type    : little
Reverse Nibbles: no
Reverse Bits   : no


Output File    : 'default' (pulseaudio)
Channels       : 2
Sample Rate    : 48000
Precision      : 32-bit
Duration       : 00:00:30.00 = 1440000 samples ~ 2250 CDDA sectors
Sample Encoding: 32-bit Signed Integer PCM
Endian Type    : little
Reverse Nibbles: no
Reverse Bits   : no

play INFO sox: effects chain: input        48000Hz  2 channels
play INFO sox: effects chain: output       48000Hz  2 channels
In:100%  00:00:30.00 [00:00:00.00] Out:1.44M [      |      ]        Clip:0
Done.
The command terminates itself after playing the whole file (30 seconds), but this command and all other commands running in a console can be interrupted earlier by pressing Ctrl+C key combination.

Notice: the play command does not need output arguments; it choose default sound card and plays audio into it.

I don't want to play on a default audio ouput (pulseaudio in my case), but I want to play directly to a hardware to get a bit-perfect output. So I can execute following command that sets a shell variable that will reroute output of play command to 3rd ALSA sound card (Linux only, cards are numbered from 0).
Rich (BB code):
$ AUDIODEV=hw:2,0 play -V sin1k.wav
play WARN alsa: can't encode 0-bit Unknown or not applicable
play:      SoX v14.4.2
play INFO formats: detected file format type `wav'

Input File     : 'sin1k.wav'
Channels       : 2
Sample Rate    : 48000
Precision      : 16-bit
Duration       : 00:00:30.00 = 1440000 samples ~ 2250 CDDA sectors
File Size      : 5.76M
Bit Rate       : 1.54M
Sample Encoding: 16-bit Signed Integer PCM
Endian Type    : little
Reverse Nibbles: no
Reverse Bits   : no


Output File    : 'hw:2,0' (alsa)
Channels       : 2
Sample Rate    : 48000
Precision      : 16-bit
Duration       : 00:00:30.00 = 1440000 samples ~ 2250 CDDA sectors
Sample Encoding: 16-bit Signed Integer PCM
Endian Type    : little
Reverse Nibbles: no
Reverse Bits   : no

play INFO sox: effects chain: input        48000Hz  2 channels
play INFO sox: effects chain: output       48000Hz  2 channels
In:100%  00:00:30.00 [00:00:00.00] Out:1.44M [      |      ]        Clip:0
Done.
In the last example of this introductory post let's generate continuous sine signal on the fly and play it directly to a sound card:
Rich (BB code):
AUDIODEV=hw:2,0 play -V -r 48000 -n -b 16 -c 2 synth sin 1000 vol -10dB
play:      SoX v14.4.2

Input File     : '' (null)
Channels       : 1
Sample Rate    : 48000
Precision      : 32-bit

Output File    : 'hw:2,0' (alsa)
Channels       : 2
Sample Rate    : 48000
Precision      : 16-bit
Sample Encoding: 16-bit Signed Integer PCM
Endian Type    : little
Reverse Nibbles: no
Reverse Bits   : no

play INFO sox: effects chain: input        48000Hz  1 channels
play INFO sox: effects chain: synth        48000Hz  1 channels
play INFO sox: effects chain: vol          48000Hz  1 channels
play INFO sox: effects chain: channels     48000Hz  2 channels
play INFO sox: effects chain: dither       48000Hz  2 channels
play INFO sox: effects chain: output       48000Hz  2 channels

In:0.00% 00:00:02.90 [00:00:00.00] Out:135k  [  ====|====  ]        Clip:0
Aborted.
You can see the output of play command that I aborted with Ctrl+C before 3rd second.
 
Last edited:

miero

Active Member
Joined
Aug 1, 2018
Messages
153
Likes
144
#2
The SoX is a versatile tool so let's try to generate and play more signals...

Sinus 1kHz at -60dBFS @48000fs:
Code:
play -V -r 48000 -n synth sin 1000 vol -60dB

IMD CCIF tone 19kHz/20kHz, 1:1 @44100fs:
Code:
play -V -r 44100 -n synth sin 19000 sin 20000 remix 1,2 channels 2

IMD SMPTE tone 60Hz/7kHz, 4:1 @96000fs:
Code:
play -V -r 96000 -n synth sin 60 sin 7000 remix 1v4,2v1 channels 2

Amplitude sweep at 1kHz with 60 second duration that fades in during 59 seconds and with explicit dither to 16 bit precision:
Code:
play -V -r 48000 -n synth 60 sin 1000 fade 59 dither -p 16

Frequency sweep from 20Hz to 20kHz with 30 second duration:
Code:
play -V -r 44100 -n synth 30 sin 20+20000

Twin frequency sweeps from 0-19kHz and 1kHz-20kHz:
Code:
play -V -r 44100 -n synth 30 sin 0+19000 sin 1000+20000 remix 1,2 channels 2

J-test 24-bit @48000fs:
Code:
JL=$(bc -l <<< "dbbit=20*l(2)/l(10); 24*dbbit")
play -V -D -r 48000 -n synth square 12000 square 250 square 0.00001 remix 1v0.5,2p-$JL,3i-$JL channels 2
Notice: -D argument disables implict dithering

How does this works? It generates 3 square signals and combines them together:
1/4fs square at half volume​
1/192fs square on volume level of the least significant bit plus one of the desired precision​
inverted very slow square to simulate a negative DC offset on volume level of the least significant bit plus one of the desired precision​
Is it nice, isn't it? :)


J-test 16-bit @44100fs:
Code:
JL=$(bc -l <<< "dbbit=20*l(2)/l(10); 16*dbbit")
play -V -D -r 44100 -n synth square 11025 square 229.6875 square 0.00001 remix 1v0.5,2p-$JL,3i-$JL channels 2
Visit http://sox.sourceforge.net/sox.html for a complete SoX reference manual.
 
Last edited:

miero

Active Member
Joined
Aug 1, 2018
Messages
153
Likes
144
#3
... and one more nice SoX effect - spectrogram!

Let's try it on IMD CCIF sweep signal:
Code:
sox -V -r 44100 -n -n synth 30 sin 0+19000 sin 1000+20000 remix 1,2 spectrogram -o imd-ccif-sweep.png
imd-ccif-sweep.png


And on 16-bit J-test signal:
Code:
sox -V -D -r 44100 -n -n synth 30 square 11025 square 229.6875 square 0.00001 remix 1v0.5,2p-$JL,3i-$JL spectrogram -o j-test16.png -z 140
Notice: increased z-axis range -z 140 for spectrogram effect is used to improve visibility of the small square signal.

j-test16.png
 
Last edited:

Guermantes

Senior Member
Joined
Feb 19, 2018
Messages
357
Likes
347
Location
Brisbane, Australia
#5
Very nice. I wasn't aware of SoX's synthesis functionality.

Just a typo, I think, in this code snippet where you have left out the bit depth argument (-b 16):

Code:
sox -V -r 48000 -n -c 2 sin1k.wav synth 30 sin 1000 vol -10dB
Briefly to used arguments:
-V ... this argument can be omitted, but it enables verbose output, so we can check input/output parameters and effect that are used​
-r 48000 -n ... (input specification) sets sample rate 48k for this session and specifies that there is no input file​
-b 16 -c 2 sin1k.wav ... (output specification) 16 bit output file with two channels named sin1k.wav​
synth 30 sin 1000 ... (1st effect) synthesizes 30 seconds of sine signal at frequency 1000Hz with max. amplitude​
vol -10dB ... (2nd effect) applies 10dB attenuation to a generated signal​
 

miero

Active Member
Joined
Aug 1, 2018
Messages
153
Likes
144
#6
Multi-tones contains more sine frequencies and there are several definitions of commonly used multi-tones...

Following code snippet is a shell script that generates many multitones into separate WAV files. It can be pasted to a console to be executed immediately or it can be saved into a file and then executed.
Code:
#!/bin/bash
# Multi-tone frequencies taken from http://www.tmr-audio.de/pdf/jon_risch_biwiring.pdf

# SYSid Spectral
SYSID="80 100 120 160 200 240 300 400 500 700 900 1200 1500 2000 3000"
# Audio Precision System One DSP and System Two Multitone
APONE="16.15 21.53 26.92 43.07 53.83 64.60 80.75 102.28 123.82 156.12 199.18 253.02 317.61 398.36 500.65 635.23 802.11 1001.3 1248.9 1598.8 1997.2 2503.2 3154.6 3999.8 4995.7 6352.3 7999.6 10002 12500 16005 19999"
# Audio Precision codec test signal
APCODEC="16.15 21.53 26.92 43.07 53.83 64.60 80.75 102.28 123.82 156.12 199.18 253.02 317.61 398.36 500.65 635.23 802.11 1001.3 1248.9 1598.8 1997.2 2503.2 3154.6 3999.8 4995.7 6352.3 7999.6 10002 12500 16005 19999"
# Phi 6 Spectral
PHI6="100 261.8 685.4 1794.4 4697.9 12299"
# Phi 12 Revised Spectral
PHI12="$PHI6 122 348.2 987 2870.4 6765 16358"
# Phi Low-High Split Band Spectral
PHILOWHIGH="100 116.18 134.98 156.80 182.19 4697.9 5927.8 7479.7 9437.9 11909"
# Phi Low-Mid Split Band Spectral
PHILOWMID="100 116.18 134.98 156.80 182.19 986.99 1245.4 1571.4 1982.8 2502.0"
# Phi Tri-Band Spectral
PHITRIBAND="100 116.18 134.98 156.80 986.99 1245.4 1571.4 1982.8 6764.9 7618.5 8579.8 9662.5"

# Generate all multi-tones defined above
ALL="SYSID APONE APCODEC PHI6 PHI12 PHILOWHIGH PHILOWMID PHITRIBAND"
for MULTITONE in $ALL; do
    # [shell trick] take a multi-tone by a name in MULTITONE variable and replace all its spaces with " sin " text
    FREQS="sin ${!MULTITONE// / sin }"
    # each tone is generated on a separate channel, mix all of them into single channel and then save it into 2 channel WAV file
    sox -V -r 44100 -n -c 2 multitone-$MULTITONE.wav synth 60 $FREQS channels 1
done
Check the spectrogram of the last one (one channel only):
multitone-PHITRIBAND.png
 
Last edited:
Joined
Jun 14, 2018
Messages
19
Likes
43
Location
Heidelberg, Germany
#7
Wow as well. I was not aware of SoX's spectrogram functionality. My main use was (and sometimes still is) to perform digital de-emphasis:
Code:
sox input_with_emphasis.wav output_de_emphasis.wav deemph
Very useful if you want to rip old (198x) CDs with emphasis …
 

edechamps

Active Member
Joined
Nov 21, 2018
Messages
211
Likes
580
Location
London, United Kingdom
#8
Nice cheat sheet. I use SoX as a building block not only as a way to generate test signals (as people might have noticed in my reviews), but also for filtering recorded capture data for further processing. It's used heavily in my modest audio measurement toolbox which combines SoX for basic processing along with Python (Numpy/Scipy/Matplotlib) for some specialized processing and visualization.
 

Similar threads

Top Bottom