Clicks and pops detection

Clicks and pops on audio

Click and pop sounds are some of the most frequent audio problems. They can appear from electro-acoustic sources (damaged cables, hits on the microphone while singing, etc.) or digital ones (clocking issues, size of audio buffer, etc.) supposing some of the most disturbing types of audio degradation. In this tutorial, we will learn how to detect clicks and pops with Essentia.

Generating synthetic clicks

Let’s start by creating and visualizing synthetic clicks with different amplitudes:

from IPython.display import Audio

from essentia.standard import MonoLoader, ClickDetector, FrameGenerator
from essentia import array
import matplotlib.pyplot as plt
import numpy as np

plt.rcParams["figure.figsize"] =(12,9)
sr = 44100

audio_file = '../../../test/audio/recorded/vignesh.wav'
audio = MonoLoader(filename=audio_file)()

click_locs = [
    len(audio) // 4,
    len(audio) // 2,
    len(audio) * 3 // 4
]

# Create synthetic clicks with different amplitudes.
for click_loc, amp in zip(click_locs, [.5, .15, .05]):
    audio[click_loc] += amp

ground_truth = array(click_locs) / sr

for click_loc in ground_truth:
    l1 = plt.axvline(click_loc, color='g', alpha=.5)

time_axis = np.arange(len(audio)) / sr
plt.plot(time_axis, audio)

l1.set_label('Click locations')
plt.legend()
plt.title('Signal with synthetic clicks with different amplitudes')
Text(0.5, 1.0, 'Signal with synthetic clicks with different amplitudes')
_images/tutorial_audioproblems_clickdetector_3_1.png

Now we can listen to the degraded audio. Notice that the clicks are decreasing in amplitude, so each click is more difficult to perceive than the previous one.

Audio(audio, rate=sr)

Detecting clicks

The ClickDetector algorithm implements Vaseghi’s detection algorithm, which uses the prediction error from a frame-wise LPC analysis to detect impulsive peaks [1]. The detection threshold is obtained from a robust estimate of the prediction error power [2] plus a gain parameter that can be adjusted by the user.

For each frame, the algorithm returns the starting and ending locations of the detected clicks and pops (which may coincide in the case of ideal one-sample clicks). For convenience, the results are expressed in seconds from the beginning of the audio (not the frame). Thus, the algorithm has to be reset() before processing a new audio stream (e.g., a new song).

# Analysis parameters.
frame_size = 512
hop_size = 256

clickDetector = ClickDetector(frameSize=frame_size, hopSize=hop_size)

starts, ends = [], []
for frame in FrameGenerator(
    audio, frameSize=frame_size, hopSize=hop_size, startFromZero=True
):
    frame_starts, frame_ends = clickDetector(frame)
    starts.extend(list(frame_starts))
    ends.extend(list(frame_ends))

Finally, we can plot the detections and the ground truth:

fig, ax = plt.subplots(len(ground_truth))

for idx, click_loc in enumerate(ground_truth):
    # Print the detection location.
    l1 = ax[idx].axvline(starts[idx], color='r', alpha=.5)
    ax[idx].axvline(ends[idx], color='r', alpha=.5)

    # Print the ground truth location.
    l2 = ax[idx].axvline(click_loc, color='g', alpha=.5)

    # Print the waveform.
    ax[idx].plot(time_axis, audio, marker='o')
    ax[idx].set_xlim([click_loc - .001, click_loc + .001])

fig.suptitle('Detection of synthetic clicks', fontsize=18)
fig.legend(
    (l1, l2), ("Prediction", "Ground truth"), fontsize=12, loc="lower center"
)
<matplotlib.legend.Legend at 0x7fc45b478af0>
_images/tutorial_audioproblems_clickdetector_9_1.png

References

[1] Vaseghi, S. V., & Rayner, P. J. W. (1990). Detection and suppression of impulsive noise in speech communication systems. IEE Proceedings I (Communications, Speech and Vision), 137(1), 38-46.

[2] Vaseghi, S. V. (2008). Advanced digital signal processing and noise reduction. John Wiley & Sons. Page 355.