Note
Go to the end to download the full example code.
Visualizing audio waveforms#
This section introduces the main ways to visualize audio waveforms in librosa.
What are we visualizing?#
As we’ve seen in the introduction section, a waveform of an audio signal
is a sequence of sample values that represent how air pressure changes over time.
A natural way to visualize this is to simply plot the sample values as a function
of time or sample index using conventional plotting tools in matplotlib.
Note
All of librosa’s display functionality is built on top of matplotlib, and we’ll
assume some degree of familiarity with it. If you’re entirely new to plotting
with matplotlib, you may want to first take a look at the
matplotlib user guide.
import numpy as np
import librosa
import matplotlib.animation as animation
import matplotlib.pyplot as plt
from IPython.display import HTML
# Load the trumpet example at its native sampling rate
y, sr = librosa.loadx("trumpet", sr=None)
HTML(librosa.util.example_info("trumpet", html=True))

This plot is a reasonable starting point, but it hides an important detail: the horizontal axis is in sample indices, not time. This can be easily fixed by converting the sample indices to time values prior to plotting:

We now have an interpretable time axis, and plotting in natural units makes it easier to link data across multiple displays, which we will see in later sections of this tutorial. We can also discern some information about the signal, mostly to do with timing and amplitude. This works well enough when the signal is relatively short and simple (e.g., monophonic like our trumpet example), but longer and more complex signals present a few difficulties:
The visualization becomes dominated by the largest peaks in the signal, and
The plot itself becomes computationally heavy due to the number of sample points.
To illustrate this, let’s load a longer example.
y, sr = librosa.loadx("nutcracker", sr=None)
HTML(librosa.util.example_info("nutcracker", html=True))

It’s now much more difficult to identify meaningful visual structure in the plot. It is also much slower to work with interactively (e.g., using Jupyter / IPython interactive plotting).
To address these issues, librosa provides a few display routines tailored for waveform visualization.
Waveshow#
The primary display function in librosa for plotting waveforms is
librosa.display.waveshow. It handles time axis conversion and decoration for
us, but more importantly, it implements an adaptive envelope plotting algorithm
that reduces the complexity of the display while retaining the visual content of
the plot.
Under the hood, waveshow summarizes the signal into an amplitude envelope, which preserves the overall shape while reducing the amount of data that has to be drawn.
Let’s compare this to the direct plotting approach used above.

The overall structure of the two plots is similar, but waveshow makes it easier to see some of the finer details.
More importantly, the waveshow plot is much more efficient, as it is only plotting the amplitude envelope and not every individual sample.
waveshow still preserves fine detail when you zoom in. At large scales it shows an envelope; at small scales it automatically switches to full-resolution samples in the visible region.
Let’s see an example, comparing the full plot and the waveshow plot, side-by-side.
y, sr = librosa.loadx("trumpet")
times = np.arange(len(y)) / sr
fig, ax = plt.subplots()
# Add some line styling and zordering so that the two plots are distinguishable
ax.plot(times, y, label="Direct plot", linewidth=2, linestyle="-.", zorder=1)
librosa.display.waveshow(y, sr=sr, ax=ax, label="Waveshow plot", alpha=0.5)
ax.legend(loc="upper left")
# We'll zoom in to the middle of the track +- 0.001 seconds
t_mid = len(y)/sr * 0.5
n_frames = 200
window = np.geomspace(t_mid, 0.001, num=n_frames)
def _update(delta):
"""Update the plot for each frame."""
# The `delta` parameter tells us how far in to
# zoom the display around the middle time point
ax.set(xlim=[t_mid - delta, t_mid + delta])
return None
ani = animation.FuncAnimation(fig,
func=_update,
frames=window,
repeat=False,
interval=1000/30)