Choir.js is a music composition assistant designed for inspiration and education. The core feature is automatic note generation, e.g., useful for adding a voice to a short musical passage. Choir.js visualizes the notes in simple musical scores and can play them back.
Choir.js itself does not understand chord progression or harmony. Instead, a good melody already inherently encodes them to some extent, though not in a unique way. By defining scales and vertical interval-relations between voices (and the addition of randomness), Choir.js can produce countless harmonizing (or intentionally disharmonizing) accompaniments.
It's your job to figure out how to tweak scales and intervals to create pleasing musical passages. You decide what sounds good. You are the composer, and Choir.js is only your inspiring little assistant implementing your rules.
Learn how to setup up a voice for note generation.
A random composition from scratch. Some rhythmic patterns were inserted manually.
Example of how to compose a four-chord progression with random voices.
- Define a musical scale or mode, set the range, and generate a random melody.
- Input your own melody.
- Input the root notes of a chord progression.
- Refine inter-voice relations, change instruments, adjust volume and panning, change playback speed, experiment with scales.
- Explore how all of these impacts the perception of harmony and musical expression.
- Manual note editing (text input with simple syntax)
- Random rhythm generation
- Automated voiced generation
- Scale and key visualization
- Voice range setting
- Audio playback with different instruments
- Multi-channel mixer (fade, pan, solo, mute)
- Tooltips
- Tutorial
Choir.js focuses on providing a simple graphical interface with audio feedback for automated note generation. At the current stage, the underlying routines unfortunately depend on the GUI modules. Nonetheless, many code segments are designed for reuse. For example, take a look at NoteGenerator.js if you are interested in the core algorithm behind note generation.
Score visualizing uses VexFlow 4.2.2. Audio playback employs Tone.js 15.0.4.
If you want to run Choir.js locally, you must launch a simple server, e.g.,
python -m RangeHTTPServer or python -m SimpleHTTPServer
in the root folder, since the browser usually restrict access to externally linked samples. This is achieved through baseUrl = document.location in samples/Instrument.js, which should work for most online hosted cases. For hosting locally, you might have to change to window.location.origin, or hard code the baseUrl path and directly open index.html with your browser without the need to launch a server.
Samples stored in samples/external are taken from https://github.com/nbrosowsky/tonejs-instruments. A copy of the reference list is stored in samples/sample-source-info.txt. Samples stored in samples/mine were recorded by me. Feel free to use them without restrictions.
The following algorithm is used to generate the notes (denoted as melody below) for a voice
In general, the algorithm is a Markov chain, for which the pitch probabilities depend on the voice's own previous pitch, and the pitches of all other voices played at the time position the note is generated.
| Symbol | Meaning |
|---|---|
| Melody / sequence of notes | |
| Note candidates | |
| Interval matrix | |
| Probability | |
| Potential | |
| Disjunction | |
| Jump penalty | |
| Voice coupling | |
| Voice IDs | |
| Note index in sequence |
|
| Index of pitch candidate |
A melody is a sequence of notes. Each note is defined by a pitch and duration. Let's assume all durations are already known (or chosen randomly), and only describe the generation of
Pitch candidates,
The Interval Matrix
The probability
with
The potential
The first term is the self-coupling, which adds an increasing penalty the larger the interval jump. This is achieved through a harmonic potential, reading
with jump penalty
where