Generate Swept Sine Chirp Signals with FFmpeg
Generating a swept-sine chirp signal—a tone that graduates in
frequency over time—is a fundamental task in audio testing, acoustic
measurement, and sound synthesis. This article demonstrates how to use
FFmpeg’s custom audio evaluation source (aevalsrc) to
programmatically generate both linear and logarithmic swept-sine chirp
signals directly from your command line without requiring external audio
files.
Understanding the
aevalsrc Filter
FFmpeg’s aevalsrc is an audio source filter that
generates an audio signal by evaluating a mathematical expression for
each sample. To create a chirp signal, we must express the change in
frequency over time as a phase function inside a sine wave:
\[\text{Output} = \sin(\theta(t))\]
Where \(\theta(t)\) is the instantaneous phase at time \(t\). Because frequency is the rate of change of phase, the phase is the integral of the frequency function over time:
\[\theta(t) = 2\pi \int f(t) \, dt\]
Method 1: Creating a Linear Chirp
In a linear chirp, the frequency increases at a constant rate over a specified duration.
The Formula
For a start frequency \(f_0\), an end frequency \(f_1\), and a duration \(T\), the instantaneous frequency is: \[f(t) = f_0 + \left(\frac{f_1 - f_0}{T}\right)t\]
Integrating this gives the phase formula used in FFmpeg: \[\theta(t) = 2\pi \left( f_0 \cdot t + \frac{f_1 - f_0}{2T} \cdot t^2 \right)\]
The FFmpeg Command
To generate a 10-second linear chirp sweeping from 20 Hz to 20,000 Hz at a sample rate of 48 kHz, use the following command:
ffmpeg -f lavfi -i "aevalsrc=sin(2*PI*(20*t + (20000-20)/(2*10)*t*t)):s=48000:d=10" output_linear.wavExpression Breakdown:
-f lavfi: Specifies the Libavfilter virtual input device.aevalsrc=...: Evaluates the mathematical formula.2*PI: Represents \(2\pi\).20*t: Represents the starting frequency \(f_0\) multiplied by timet.(20000-20)/(2*10)*t*t: Calculates the \(\frac{f_1 - f_0}{2T} \cdot t^2\) portion of the phase equation (simplifies to999 * t * t).s=48000: Sets the audio sample rate to 48,000 Hz.d=10: Sets the duration of the output to 10 seconds.
Method 2: Creating an Exponential (Logarithmic) Chirp
An exponential (or logarithmic) sweep is often preferred for acoustic measurements because human hearing perceives pitch changes logarithmically, spending equal time in each octave of the sweep.
The Formula
For a start frequency \(f_0\) and an end frequency \(f_1\) over a duration \(T\), the frequency increases exponentially: \[f(t) = f_0 \cdot \left(\frac{f_1}{f_0}\right)^{\frac{t}{T}}\]
Integrating this yields the phase formula: \[\theta(t) = 2\pi \cdot f_0 \cdot \frac{T}{\ln(f_1 / f_0)} \cdot \left( \left(\frac{f_1}{f_0}\right)^{\frac{t}{T}} - 1 \right)\]
The FFmpeg Command
Using the same parameters (\(f_0 = 20\text{ Hz}\), \(f_1 = 20,000\text{ Hz}\), \(T = 10\text{ seconds}\)), we pre-calculate the constants to keep the FFmpeg expression clean: * \(\frac{f_1}{f_0} = \frac{20000}{20} = 1000\) * \(\ln(1000) \approx 6.907755\) * \(\frac{T}{\ln(1000)} = \frac{10}{6.907755} \approx 1.447648\) * \(f_0 \cdot 1.447648 = 20 \cdot 1.447648 \approx 28.95296\) * \(\left(\frac{f_1}{f_0}\right)^{\frac{1}{T}} = 1000^{0.1} \approx 1.995262\)
Using these constants, the FFmpeg command is:
ffmpeg -f lavfi -i "aevalsrc=sin(2*PI*28.95296*(pow(1.995262,t)-1)):s=48000:d=10" output_logarithmic.wavExpression Breakdown:
pow(1.995262, t): Raises the growth factor to the power of timetinside FFmpeg.-1: Offsets the integration constant so the phase starts at zero.28.95296: The scaled frequency factor computed during the integration step.
Adding Multiple Channels
By default, aevalsrc generates a single mono channel. If
you need a stereo chirp file, map the expression to two channels
separated by a colon (:) inside the aevalsrc
parameter:
ffmpeg -f lavfi -i "aevalsrc=sin(2*PI*(20*t + 999*t*t)):sin(2*PI*(20*t + 999*t*t)):s=48000:d=10" output_stereo.wav