Sorting Algorithm Visualization & Sonification Plugin for Max for Live

Category:Tech BlogTags:
#Max/MSP#Max for Live#Ableton Live#JavaScript#Sorting Algorithm
Published: 2022 - 2 - 20
Quick Sort / 32 Notes / 32nd Note Dotted
Melody: Selection Sort / 16 Notes / 16th Note Triplet / Drums: Merge Sort / 64 Notes / 16th Note

I built Soni.f(y, sorts) — a Max for Live device that converts the operations of sorting algorithms into MIDI note sequences, making them playable as an instrument inside Ableton Live.

Visualizing and sonifying sorting algorithms is a popular way to build intuition about algorithmic behavior. Countless developers and educators have produced videos and interactive demos on this theme.

Here are some well-known examples:

15
Sorting
Algorithms
in
6
Minutes
(Timo
Bingmann,
2013)

Each comparison and swap is mapped to a pitch, creating a distinctive sonic fingerprint for each algorithm. Tens of millions of views.

AlgoRhythmics
(Sapientia
University)

Sorting algorithms performed as folk dances — a wonderfully embodied take on algorithmic structure. (https://www.youtube.com/user/AlgoRhythmics)

sorting.at
(Carlo
Zapponi)

VisuAlgo
(National
University
of
Singapore)

Step-by-step animated explanations of sorting and other algorithms.
https://visualgo.net/en/sorting

These are all polished visualizations and videos in their own right, designed to be watched. My goal was to take this concept one step further and implement it as a Max for Live device — making sorting algorithms playable as a real-time MIDI instrument inside Ableton Live.

Max/MSP

Max/MSP is a visual programming environment by Cycling '74, widely used for music, video, and interactive media. Programs are built as patches (.maxpat) by wiring together objects in a dataflow style.

One of Max's strengths is its [js] object, which lets you embed JavaScript directly in a patch for logic-heavy tasks that would be awkward to express visually.

Max
for
Live
(M4L)

Max for Live (M4L) integrates Max into Ableton Live, allowing you to build custom MIDI effects, audio effects, and instruments that run directly in a Live set and are distributed as .amxd files.

Cycling '74 was acquired by Ableton in 2017. Max for Live is now available as part of Ableton Live Suite or as a separate license. (Cycling '74 Joins Ableton, 2017)

Soni.f(y, sorts) screenshot

Soni.f(y, sorts) maps each step of a sorting algorithm (comparisons, swaps, insertions) to a MIDI note, which is then routed to any instrument in Ableton Live.

Supported
Algorithms

  • Selection Sort
  • Insertion Sort
  • Quick Sort
  • Merge Sort
  • Heap Sort
Heap Sort / 32 Notes / 16th Note
Insertion Sort / 64 Notes / 64th Note
Merge Sort / 64 Notes / 32nd Note Triplet
Quick Sort / 16 Notes / 16th Note Dotted
Selection Sort / 64 Notes / 128th Note

Overview

[Input sequence (MIDI note numbers)]
        ↓
[sort.js — inside Max [js] object]
  · Runs the full sort, recording every operation in stepHistory[]
        ↓
[One step replayed per bang]
  outlet0 : current sequence state
  outlet1 : accessed note + adjacent notes → MIDI out
  outlet2 : index pointer sequence
        ↓
[Ableton Live MIDI instrument]

The patch loads sort.js into a [js] object via [js sort.js]. When it receives the sort message it pre-computes the entire sort and stores all operations in a history array. Each subsequent bang replays one step from that history, outputting the accessed MIDI notes to Live. When the history is exhausted, outlet 6 fires a bang to signal completion.

Max's [js] object runs ECMAScript 5-compatible JavaScript (Max JS Object Reference).

The core data structure is stepHistory — an array that records every elementary operation performed during the sort:

inlets = 2;
outlets = 7;

var availableAlgorithms = [
  "bubble",
  "selection",
  "insertion",
  "quick",
  "merge",
];
var selectedAlgorithm = "bubble";
var stepHistory = Array();

// swap two elements (type 0)
function swap(array, i, j, saveHistory) {
  var tmp = array[i];
  array[i] = array[j];
  array[j] = tmp;
  if (saveHistory) stepHistory.push([0, i, j]);
}

// copy element at j to position i (type 1)
function insert(array, i, j, saveHistory) {
  array[i] = array[j];
  if (saveHistory) stepHistory.push([1, i, j]);
}

// write a specific value to position i (type 2)
function insertValue(array, i, value, saveHistory) {
  array[i] = value;
  if (saveHistory) stepHistory.push([2, i, value]);
}

Each sort function (bubbleSort, selection_sort, insertionSort, quickSort, mergeSort) calls these primitives with saveHistory = true, accumulating every atomic operation into stepHistory.

Playback
via
bang

function bang() {
  if (bangCount === 0) playSequence = inputArray.slice(); // reset on first step

  if (bangCount === stepHistory.length) {
    outlet(6, "bang"); // signal sort complete
    bangCount = 0;
    return;
  }

  var op = stepHistory[bangCount];
  // re-apply swap / insert / insertValue to playSequence
  // ...

  // output accessed note and its neighbors as MIDI
  outlet(1, [
    playSequence[Math.max(0, idx - 1)],
    playSequence[idx],
    playSequence[Math.min(playSequence.length - 1, idx + 1)],
  ]);
  outlet(0, playSequence); // current state
  bangCount++;
}

Separating the sort computation from its playback means the tempo is fully independent — you can use Ableton Live's transport, a [metro] object, or any other bang source to step through the sort at any speed.

  1. Drop sonify-sorts.amxd onto a MIDI track in Ableton Live.
  2. Set the input sequence (a list of MIDI note numbers, e.g. a shuffled scale) on the device.
  3. Choose an algorithm and press sort to pre-compute the step history.
  4. Turn on play to step through the sort in sync with tempo. Each step outputs MIDI notes.
  5. Route the MIDI output to any Live instrument (synth, sampler, etc.) and listen to the algorithm play itself.

Sorting algorithm visualizations are a staple of CS education. Implementing this as a Max for Live device makes it possible to experience and perform sorting algorithms as "music" inside Ableton Live.

Using Max's [js] object means complex algorithm logic can be written in familiar JavaScript rather than having to express it through visual patching — a significant advantage. The differences between algorithms — the rhythm patterns and note density of each sort — translate into distinctly different musical textures, which makes for an interesting way to compare algorithms from a musical perspective.

Read more articles