Sparklines For JUCE AudioBlocks

Overview

Melatonin Audio Sparklines

This is a C++ JUCE module that summarizes and visualizes what's in an AudioBlock.

It's very useful to get a quick idea of what's happening to your audio buffers during development or tests.

Call printSparkline(myBlock); and under the hood, DBG will be called and you'll see something like this in the output console:

Block is 1 channel, 441 samples, min -0.999994, max 0.999994, 100% filled
[0—⎻⎺‾⎺⎻—x—⎼⎽_⎽⎼—]

Motivation

I've been working on unit tests at a low level. It's been going well, but I kept feeling like I didn't have enough insight into what my various buffers and blocks of audio look like.

There's nothing worse than having a test fail and then not really having a way to quickly verify what failed.

I found myself wanting to answer the following, quickly:

  • Is there a signal present, and is it sinusoidal?
  • How many cycles are there?
  • Is all or part of the block empty?
  • Are there any values that are out of bounds?

Basically, I wanted a visual waveform. In my UI, I do have a little helper that I can turn on to show me visually what's in my buffer, a modified version of Jim Credland's buffer debugger.

But a waveform isn't possible in the debugging console and I'm not always working in a UI context. It's trivial to write little helpers to report on zero crossings, etc. But in the context of debugging when you don't know exactly what's wrong, having to manually swap helpers in and out and compile again and again is just not friendly.

One can always write a bunch of float values to the screen, but humans can't reliably parse thousands of float values visually. Have fun counting those zero crossings manually!

Sparklines

I'm a big Edward Tufte fan and one of the things he champions is "data-intense, design-simple, word-sized graphics" which he gave the name "sparkline."

At a glance, you can tell some general characteristics about the data series. Individual data points are not relevant, the trend is!

I figured it might be possible to make an sparkline graph with unicode and saw that not only does unicode have block elements but there are already people doing sparkline bar graphs.

However, the block elements are vertically bottom aligned instead of center aligned, meaning they don't really parse easily as a waveform.

Audio Sparklines

In the end, I chose the following 7 symbols to represent the waveform. Yup, we're decimating the audio down to 3 bits.

_⎽⎼—⎻⎺‾

In addition to the following features:

0 = true 0
x = zero crossing
E = out of bounds (below -1.0 or above 1.0)

Here's what 2 cycles of a healthy sine wave look like (it keeps scrolling right) with all samples represented:

[0———⎻⎻⎻⎻⎻⎻⎻‾‾‾‾‾‾‾‾⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺‾‾‾‾‾‾‾‾‾⎻⎻⎻⎻⎻⎻⎻———x——⎼⎼⎼⎼⎼⎼⎼⎽⎽⎽⎽⎽⎽⎽⎽⎽____________________________________⎽⎽⎽⎽⎽⎽⎽⎽⎼⎼⎼⎼⎼⎼⎼————x——⎻⎻⎻⎻⎻⎻⎻‾‾‾‾‾‾‾‾⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺‾‾‾‾‾‾‾‾‾⎻⎻⎻⎻⎻⎻⎻———x——⎼⎼⎼⎼⎼⎼⎼⎽⎽⎽⎽⎽⎽⎽⎽⎽____________________________________⎽⎽⎽⎽⎽⎽⎽⎽⎼⎼⎼⎼⎼⎼⎼———]

Cool! It's bulky and elongated, but we can see some trends...

Cleaning them up

To do Tufte right, we should increase the amount of signal per surface area. We can collapse the redundant data, leaving us with just the "trend."

[0⎻⎺‾⎺⎻x—⎼⎽_⎽⎼—x⎻⎺‾⎺⎻x—⎼⎽_⎽⎼—] 294 samples (-0.999 to 0.999)

This is useful. We can glean a lot of info from this example:

  • We can quickly visually identify 2 healthy full amplitude cycles.
  • We know the first value is zero.
  • It looks sinusoidal
  • We know there are 294 samples in total
  • We know the amplitude ranges from -0.999 to 0.999.

Normalized

Without normalization, quiet volumes might get something that looks like this:

Block is 2 channels, 128 samples, min -0.0951679, max 0.11609, 50.7812% filled
[—x—0(64)]

Which is....pretty cryptic. Nothing a bit of normalization can't help with, though:

Block is 2 channels, 128 samples, min -0.0951679, max 0.11609, 50.7812% filled
[‾⎺⎻—x—⎼⎽_0(64)]

Now we can see the shape of the waveform and look to the metadata for the scale.

More complex examples

Here's an example of block going out of audio bounds. The E lets you know a sample is out of bounds. We can see a big empty chunk of zeros at the end of the block, and the number 234 tells us exactly how many consecutive zeros there are.

[0⎻⎺⎻x—x⎻x—⎼⎽_E_⎽⎼—x⎻⎺‾E‾⎺⎻x—⎼—x⎻⎺⎻x—⎼⎽_E_⎽⎼—0⎻⎺‾E‾⎺⎻x—⎼—x⎻⎺⎻x—⎼⎽_E_⎽⎼—0(234)] 1024 samples (-1.76012, 1.76013)

The collapsed version looks more clearly sinusoidal, but we can see it's going out of bounds. We still have a precise grasp of how many samples in the buffer are empty.

Installation

Good citizen don't litter, and they certainly don't copy and paste C++ code. It's 2021, remember?

Set up a git submodule in your project tracking the main branch. I usually stick mine in a modules directory.

git submodule add -b main https://github.com/sudara/melatonin_audio_sparklines modules/melatonin_audio_sparklines
git commit -m "Added melatonin_audio_sparklines submodule."

To update melatonin_inspector, you can:

git submodule update --remote --merge modules/melatonin_audio_sparklines

If you use CMake (my condolences), inform JUCE about the module in your CMakeLists.txt:

juce_add_module("modules/melatonin_audio_sparklines")

Include the header where needed:

#include "melatonin_audio_sparklines/melatonin_audio_sparklines.h"

Usage

Just print your sparkline:

melatonin::printSparkline(myAudioBlock);

This will call DBG() for you.

If you are lucky you'll see a healthy looking wave, like this cutie little square wave:

[0⎺‾⎺x⎽_⎽]

Get your sparkline in its full sample-by-sample verbose glory:

melatonin::printSparkline(myAudioBlock, false);

If you don't want the output normalized:

melatonin::printSparkline(myAudioBlock, true, false);

Xcode gotcha

If you are using Xcode exclusively, plop this somewhere

#define MELATONIN_SPARKLINE_XCODE=1

MacOS font rendering flips the height of ⎺ and ‾, but it's fine in MacOS CLion, etc.

Caveats

Tested on VS2019 on Windows, Xcode on MacOS and CLion on Windows and MacOS.

Don't like how they look?

I'm not a fan of VS2019 with the default Consolas font. Everywhere else it seems to look good! Open an issue if not.

Reminder: Don't leave printSparkline in your audio path

Not only does DBG itself allocate, but the whole name of the game is string manipulation here, so if you are sticking a printSparkline in your audio callback, expect those sweet sweet dropouts.

You might also like...
JUCE is an open-source cross-platform C++ application framework for desktop and mobile applications, including VST, VST3, AU, AUv3, RTAS and AAX audio plug-ins.
JUCE is an open-source cross-platform C++ application framework for desktop and mobile applications, including VST, VST3, AU, AUv3, RTAS and AAX audio plug-ins.

JUCE is an open-source cross-platform C++ application framework for creating high quality desktop and mobile applications, including VST, VST3, AU, AU

Juce tutorial for beginners, with DSP introduction.

JUCE Tutorial Juce tutorial for beginners, with DSP basics. My teaching materials :D Warning: working in progress lesson 0: Setup lesson 1: Basic Basi

Comments
Owner
Sudara Williams
Sudara Williams
JUCE is an open-source cross-platform C++ application framework for desktop and mobile applications, including VST, VST3, AU, AUv3, RTAS and AAX audio plug-ins.

JUCE is an open-source cross-platform C++ application framework for creating high quality desktop and mobile applications, including VST, VST3, AU, AU

JUCE 4.6k Nov 21, 2022
JUCE is an open-source cross-platform C++ application framework for desktop and mobile applications, including VST, VST3, AU, AUv3, RTAS and AAX audio plug-ins.

JUCE is an open-source cross-platform C++ application framework used for rapidly developing high quality desktop and mobile applications, including VS

JUCE 4.6k Nov 19, 2022
A basic infrastructure for a polyphonic synthesiser, written with the JUCE framework.

JuceSynthBase This JUCE module is a complete infrastructure for a polyphonic synthesizer, providing voice management, MIDI management, and some more a

Ben Vining 14 May 28, 2021
Fully resizing juce peak meter module with optional fader overlay.

Sound Meter Juce peak meter module with optional fader overlay. by Marcel Huibers | Sound Development 2021 | Published under the MIT License Features:

Sound Development 17 Nov 22, 2022
A template for experimenting with JUCE's hosting code

juce-wrapper This is a JUCE based plug-in that loads and wraps a single VST, VST3, or AU plug-in (in this case an instrument plug-in, which requires M

Shane Dunne 6 Nov 16, 2022
End to end test framework designed for Juce applications

JUCE End to End test framework What is it? This package provides a mechanism to end-to-end test a JUCE application Prerequisites CMake. Must be 3.18 o

Focusrite Audio Engineering Ltd. 53 Nov 6, 2022
JUCE Signal Generator

JUCE Signal Generator Application This project serves as a re-introduction to JUCE programming (I haven't used it since under-grad, circa 2012). Build

Tom Wilson 1 Dec 22, 2021
Resources for JUCE-based audio development on the Raspberry Pi

JUCE4Pi Resources for JUCE-based audio development on the Raspberry Pi Raspberry Pi / Linux git clone https://github.com/juce-framework/JUCE.git sudo

null 11 Oct 4, 2022
This is a simple reverb plugin made with the JUCE DSP module.

Simple Reverb This is a simple reverb plugin made with the JUCE DSP module. Building $ git clone https://github.com/szkkng/SimpleReverb.git --recursiv

suzuki kengo 57 Nov 18, 2022
A set of tools allowing JUCE 6.1 + Cmake to build a CLAP

JUCE6/CMake Clap Support This is a set of code which, combined with a JUCE6/CMake project, allows you to build a (buggy, feature incomplete, work in p

Paul 0 Feb 15, 2022