cppMusicTools
April 28, 2026 · View on GitHub
A collection of C++ tools for MIDI and music development, built with the JUCE framework.
MidiTools
A namespace containing a Chord class, a Scale class, and utility functions for handling MIDI notes and chords.
The Chord Class
MidiTools::Chord represents a musical chord. It can be constructed from a chord-name string (e.g. "CM", "Am7", "F#M") and exposes its constituent semitones as degrees (indices 0–6). Raw MIDI note arrays are used internally for the "chord played as is" mode.
The Scale Class
MidiTools::Scale represents a diatonic or non-diatonic scale. Construct it with a root semitone (0–11) and a Scale::Type enum value. getNotes() returns the semitone set; fromScaleAndDegree() builds a Chord voiced from a given scale degree.
Arpeggiator
The Arpeggiator class drives a MIDI arpeggio engine. It takes a Chord, an octave, and a pattern string and generates time-stamped MIDI events.
How It Works
Call prepareToPlay(sampleRate) once, then call processBlock(numSamples, midiChannel) every audio block. The method returns a juce::MidiBuffer containing any note-on / note-off events that fall inside the block.
The arpeggiator maintains a position (pos) in the pattern string that advances one musical step per call to the internal getNext() function. All state (global octave, global velocity, scope stack, root-relative flag) persists between calls.
Pattern String Syntax
The pattern string is read character by character. A step is any single note command. Prefix commands are consumed before the note command of the same step and modify how that note (or subsequent notes) sounds.
Note Commands
| Command | Description |
|---|---|
1 – 9 | Plays a specific degree of the chord/scale (1 = root, 2 = second, …). |
+ | Advances to the next chord degree (wraps). |
- | Goes back to the previous chord degree (wraps). |
? | Plays a random valid degree from the chord. |
= | Repeats the last played degree. |
_ | Sustains the previous note (no new note-on). |
. | Rest — no note is played. |
Pitch Prefix Commands
| Command | Description |
|---|---|
# | Raises the next note by one semitone (local, one step only). |
b | Lowers the next note by one semitone (local, one step only). |
Velocity Prefix Commands
Velocity levels 1–8 map to MIDI velocities 16–127.
| Command | Description |
|---|---|
vN | Local — sets velocity for the next note only (N = 1–8). |
v+ | Local — increases velocity one level for the next note only. |
v- | Local — decreases velocity one level for the next note only. |
VN | Global — sets velocity for all subsequent notes until the next V command. |
V+ | Global — increases velocity one level for all subsequent notes. |
V- | Global — decreases velocity one level for all subsequent notes. |
Octave Prefix Commands
| Command | Description |
|---|---|
oN | Local — sets octave to N (0–7) for the next note only. |
o+ | Local — increases octave by one for the next note only. |
o- | Local — decreases octave by one for the next note only. |
ON | Global — sets octave to N for all subsequent notes. |
O+ | Global — increases octave by one for all subsequent notes. |
O- | Global — decreases octave by one for all subsequent notes. |
Block Commands
Block commands wrap one or more steps and alter the evaluation context for everything inside them.
Local Modifier Scope ( … )
When the parser encounters ( it pushes the current global octave and global velocity onto an internal scope stack. When it encounters ) it pops the stack, restoring both values. Any O+/O-/V+/V- (or absolute ON/VN) used inside the parentheses therefore have no lasting effect outside the block.
1 2 (O+ 1 2 3) 1 2
Steps 3–5 are played one octave higher; the global octave is restored for steps 6 and 7. Parentheses may be nested.
Root-Relative Notes " … " (single-note / scale mode only)
In scale chord-method mode the arpeggiator normally voices notes relative to the degree of the currently pressed MIDI note within the selected scale. Steps placed between double-quotes are instead voiced relative to degree 0 of the scale (the scale root), regardless of which key is held.
1 2 "1 2 3" 4
Steps 3–5 always follow the root of the scale; steps 1, 2, 4 follow the pressed note's degree as usual.
The root chord is supplied by the host via setRootChord(). In non-scale modes the "…" block has no effect.
Note:
"is a block delimiter and is not a note command. Use=to repeat the last degree.
Public API (selected)
| Method | Description |
|---|---|
setChord(chord) | Sets the chord the arpeggiator voices against. |
setRootChord(chord) | Sets the chord used inside "…" root-relative blocks. |
setPattern(string) | Sets a new pattern string and resets position and scope state. |
setTempo(bpm) | Sets the tempo in BPM. |
setSubdivision(index) | Sets the note subdivision (0 = 1/4, 4 = 1/16, …). |
setChordMethod(index) | 0 = notes played, 1 = chord as is, 2 = scale/single note. |
setBaseOctaveFromNote(midi) | Derives the base octave from an incoming MIDI note number. |
numSteps() | Returns the number of musical steps in the current pattern. |
getPatternIndexForStep(n) | Maps a step index to its character position in the pattern string. |
getLastPlayedNote() | Returns the last MIDI note number that was output (-1 if none). |
makeEuclidianPattern(hits, steps, rot) | Generates a Euclidean rhythm pattern string. |
makeRandomPattern() | Generates a random but balanced pattern string. |
reset() | Resets position, octave, velocity, and scope state. |
turnOff() | Generates a note-off for the last played note and resets state. |