Tomer Aberbach

Schoenberg: The MIDI Esoteric Programming Language

Published ·

Schoenberg is an esoteric programming language where programs are written as MIDI files. A MIDI file is basically digital sheet music that tells a computer which notes to play when and how loudly.

The programming language interpreter, and transpilers between Schoenberg and brainfuck programs, can be found on GitHub.

Semantics permalinkSemantics

The operational semantics of a Schoenberg program directly match those of a brainfuck program. Since brainfuck is Turing-complete, so is Schoenberg.

Like brainfuck, Schoenberg operates on an array of memory cells, each initialized to zero. There is a pointer, initially pointing to the first memory cell, and there are commands for moving the pointer, modifying the current cell, outputting the current cell, and looping.

Syntax permalinkSyntax

Since Schoenberg programs are MIDI files, its syntax is not text-based.

Instead, commands are controlled by pitch class distance, velocity, and overlap. Rhythm has no effect on a program’s behavior unless it causes notes to overlap.

CommandDescriptionSyntaxamountBrainfuck
DecrementDecrement the pointer cell by amountPlay a note 1 pitch class away from the current notevel+132\left\lceil \frac{\text{vel} + 1}{32} \right\rceil-
IncrementIncrement the pointer cell by amountPlay a note 2 pitch classes away from the current notevel+132\left\lceil \frac{\text{vel} + 1}{32} \right\rceil+
Move leftMove the pointer left amount timesPlay a note 3 pitch classes away from the current notevel+164\left\lceil \frac{\text{vel} + 1}{64} \right\rceil<
Move rightMove the pointer right amount timesPlay a note 4 pitch classes away from the current notevel+164\left\lceil \frac{\text{vel} + 1}{64} \right\rceil>
OutputOutput the pointer cellPlay a note 5 pitch classes away from the current noteN/A.
InputInput a byte into the pointer cellPlay a note 6 pitch classes away from the current noteN/A,
Loop startJump past the matching loop end if the pointer cell is 0Play a note that overlaps the current note (a “loop note”)N/A[
Loop endJump back to the matching loop start if the pointer cell is not 0Stop playing an active loop noteN/A]

Additionally:

  • Playing the same note twice in a row, corresponding to a pitch class distance of 0, is a no-op. However, playing and overlapping two different notes with the same pitch class (e.g. in different octaves) can be used to start loops without adding other commands.
  • When playing multiple notes at exactly the same time (e.g. a chord), the chronology of the notes is considered to be the ascending pitch order.

Every MIDI file is a syntactically valid Schoenberg program, although most don’t do anything useful.

Sample programs permalinkSample programs

I wrote (composed?) echo.mid from scratch in Ableton and transpiled the rest from brainfuck.

MIDIDescriptionAudio (synthesized using TiMidity)Source
hello_world.midPrints Hello, World!Esolang Wiki
cell_width.midPrints the interpreter’s cell widthEsolang Wiki
echo.midPrints the input, like echoMe
wc.midCounts input lines, words, and bytes, like wcDaniel B. Cristofani
fib.midPrints the entire Fibonacci sequenceDaniel B. Cristofani
bubble_sort.midSorts the input bytes using bubble sortDaniel B. Cristofani
insertion_sort.midSorts the input bytes using insertion sortDaniel B. Cristofani
quick_sort.midSorts the input bytes using quick sortDaniel B. Cristofani
brainfuck_interpreter.midRuns a brainfuck program on its input, which should be separated by an exclamation pointDaniel B. Cristofani

All the programs can be found on GitHub.

FAQ permalinkFAQ

What’s with the name? permalinkWhat’s with the name?

The programming language is named after Arnold Schoenberg (1874–1951), who is widely considered to be the father of atonal music.

Writing tonal music, the basis of Western music composition, requires limiting yourself to the pitch classes of a chosen key, but this is incredibly hard to do when writing Schoenberg programs.

For example, if you want to decrement the pointer cell, then the next note must be 1 pitch class away. This leaves you with only two options for the next note’s pitch class, but it’s possible neither of those pitch classes is in the chosen key.

As a result, Schoenberg programs tend to be atonal.

How did you come up with the idea? permalinkHow did you come up with the idea?

I was inspired by Piet, an esoteric programming language where programs look like abstract paintings.

The concept of a program language where programs are written in an artistic medium was intriguing to me, so I decided to create my own programming language based on music composition, the artistic medium I have the most experience with.

Is it useful for anything? permalinkIs it useful for anything?

Like most esoteric programming languages, Schoenberg is mostly a meme and mostly useless.

It could be used for steganography though. For example, you could create a brainfuck program that outputs some text and further conceal the message by transpiling it to a Schoenberg program.

Is there a one-to-one mapping between brainfuck and Schoenberg programs? permalinkIs there a one-to-one mapping between brainfuck and Schoenberg programs?

No, there is a one-to-many mapping for many reasons. Here are a few:

  • Schoenberg programs can be transposed without affecting behavior.
  • Schoenberg’s syntax allows specifying most commands in more than one way.
  • Note length can often be changed without affecting behavior.

Why did you write it in Rust? permalinkWhy did you write it in Rust?

Rust is pretty well-suited for writing interpreters, compilers, transpilers, etc. because of its “algebraic data type” style enums. It also has a user-friendly and performant MIDI parsing and writing library called midly.

Plus, I’ve rarely used Rust and this seemed like a good opportunity to learn more about it.

Is there an IDE? permalinkIs there an IDE?

Any MIDI editor is a Schoenberg IDE!

I personally use Ableton because that’s what I use for non-Schoenberg music production, but GarageBand and FL Studio are also good options.