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.wav

Expression Breakdown:


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.wav

Expression Breakdown:


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