Analyze and compute rhythmic patterns
npm install rhythmicon-rhythm
This Node package implements class Rhythm to store, analyze and manipulate rhythms.
- Background
- Install
- Usage
- Rhythm
- clone()
- Factory methods
- fromPattern(pattern)
- fromDurations(durations)
- fromEuclidean(beats, pulses)
- fromTracy(number)
- fromHex(number)
- Accessor methods
- beats()
- beatPulses()
- first()
- empty()
- durations()
- divisor()
- repetitions()
- condense()
- shuffled()
- odd()
- core()
- rotations()
- beatRotations()
- toString()
- toDurations()
- toTracy()
- toHex()
- Comparator methods
- compare(rhythm)
- equivalent(rhythm)
- equals(rhythm)
- rotated(rhythm)
- includes(rhythm)
- Modifying methods
- beat(...durations)
- rest(duration)
- replace(...rhythm)
- deflate(divisor)
- inflate(n)
- repeat(n)
- cut(n)
- complement()
- shuffle()
- unshuffle()
- rotate(pulses)
- rotateBeats(beats)
- normalize()
- Static methods
- isBeat(value)
- isDurationsString(str)
- parse(rhythm)
- Maintainers
- Contributing
- License
Class Rhythm implements a simplified model of musical rhythms. Every rhythm is an array of pulses, each being either a beat (value 1) or a rest (value 0). For instance the tresillo rhythm is array [1,0,0,1,0,0,1,0]. A rhythm can also be encoded as pattern string (x--x--x-) and as durations (array [3,3,2] or string 3+3+2). Rhythms can further be:
- repeated and cut (e.g. x-x-x- can be cut to x-)
- inflated and deflated by a divisor (e.g. x-x and x---x- with divisor 2).
- rotated (e.g. xx- is rotated -xx and x-x)
- shuffled and unshuffled (e.g x-xx-- is shuffle of xxx-)
- normalized to a core rhythm
- rhythmicon-vue is a JavaScript library of Vue components to display and interact with rhythmic patterns
- rhythmicon further contains a collection of rhythms and a web application to analyze and modify rhythmic patterns
- tonal is a JavaScript library for tonal elements of music (note, intervals, chords, scales, modes, keys). The library also contains the limited class @tonaljs/rhythm-pattern for rhythmic patterns.
This package comes as single file without dependencies.
``bash`
npm install rhythmicon-rhythm
~~~js
import Rhythm from "rhythmicon-rhythm"
const r = new Rhytm("x--x--x-")
console.log(Rhythm has ${r.beats()} in ${r.length} pulses)
~~~
This is a subclass of Array so all of its properties and methods can be used. Please make sure the Array will contain only 0 and 1 elements when using low-level Array methods.
The constructor creates a new Rhythm object like new Array. If passed a single string or Array argument, this argument is used to build the rhythm from.
``js
new Rhyth("x--x--x-")
new Rhythm("|RL-RRL--|")
new Rhyth([1,0,0,1,0,0,1,0])
new Rhyth("A","_","_","+","_","_","B","_")
Rhythm(n) // empty rhythm of length n
`
#### clone
This instance method returns a copy of the Rhythm instance.
Create a Rhythm from a pattern string.
Create a rhythm from an Array or string of durations.
Create an euclidean rhythm with beats number of beats in pulses number of pulses.
Create a rhythm from its reversed [Tracy Number], being an octal number (sequence of
digits 0 to 7) of the reverse rhythm bits. Each digit represents three pulses:0=---, 1=x--, 2=-x-, 3=xx-, 4=--x, 5=x-x, 6=xx- to 7=xxx.
[Tracy Number]: https://www.tbray.org/ongoing/When/202x/2025/12/02/Bell-Combinatorics
The following ("member const") methods don't modify instances.
Get the number of beats in this rhythm.
Get an array of index numbers of beats in this rhythm.
Get the position the the first beat, or undefined if the rhythm is empty.
~~~js
rhythm.first() === rhythm.beatPulses()[0]
~~~
Get whether the rhytm contains no beats.
Return an array of durations between beats, starting with the first beat.
Get greatest common divisor of all durations. Returns 1 if the rhythm cannot be
deflated or if the first pulse is not a beat. Returns the length of the rhytm
for an empty rhythm.
Get number of repetitions.
Get whether the rhythm cannot be deflated and has no repetitions.
Check whether the rhythm is shuffled. That is the pulses can be organized in groups of three pulses where the second pulse of each group is a rest.
~~~js
Rhythm.fromPattern("x--x-x").shuffled() // true
Rhythm.fromPattern("xx-x-x").shuffled() // false
~~~
Check whether the rhythm is odd (cannot be split at beats into two parts of equal length).
Check whether the rhythm is normalized to its core rhythm.
Calculate all rotations by pulse. Returns a Set of pattern strings.
Calculate all rotations by beat. Returns a Set of pattern strings.
Stringify the rhythm with "x" for beat and "-" for rest.
Stringify the durations of the beat, separated by sep (+ by default) and
preceded by more of this character if the first pulse is not a beat.
Get the reversed tracy number (octal representation), if the rhythm length is
divideable by three.
Compare two rhythms, first by length, then lexicographically by its durations.
The argument is parsed if it is no Rhythm object.
Check whether this rhythm is equivalent to another, possibly under rotation.
The argument is parsed if it is no Rhythm object.
Whether the rythm is equal to another rythm (same length, same pulses). The
argument is parsed if it is no Rhythm object.
Get the rotation number if this rhythm is equivalent to another, or undefined otherwise.
Whether a rhythm has same length and same beats (plus maybe more) than another rhythm.
Add one or more beats with given duration(s) or one pulse if no parameter is given.
Add a rest with given duration in pulses.
Change the rhytm in-place. Takes same arguments as the constructor, except a single number is read is one pulse instead of a number of pulses.
Deflate the rhythm if it has a divisor > 1. The optional parameter must be a prime of the divisor.
Inflate the rhythm. Each pulse is replaced by n pulses with default n=2.
Repeat the rhythm n times (default 2 to duplicate it).
Reduce the rhythm by removal of all repetitions or to a smaller number n of repetitions. Does nothing if n is larger than repetitions().
cut(n) results in the same as cut().repeat(n)
~~~js
Rhythm.fromPattern("x-x-x-x-").cut() // => Rhythm[1,0]
Rhythm.fromPattern("x-x-x-x-").cut(1) // => Rhythm[1,0,1,0]
Rhythm.fromPattern("x-x-x-x-").cut(2) // => Rhythm[1,0,1,0]
Rhythm.fromPattern("x-x-x-x-").cut(3) // => Rhythm[1,0,1,0,1,0]
~~~
Convert rhythm into its complement by swapping beats and rests.
If the rhythm can be grouped into groups of two pulses, each of these groups is replaced by three pulses, the second one being a rest.
~~~js
Rhythm.fromPattern("x-xx").shuffle() // => "x--x-x"
~~~
Remove the middle rest of each triple group if the rhythm is shuffled. Does nothing otherwise.
Rotate the rhythm pulses number of pulses to the right (1 by default), or to the left if pulses is negative.
`js`
Rhythm.fromPattern("x--x-").rotate(1) // => Rhythm[0,1,0,0,1]
Rotate the rhythm one or more beats to the right.
If the first pulse is not a beat, the rhythm is first rotated to do so, so rotation by zero
beats will rotate the first beat to the first pulse.
Normalize to a core rhythm by rotating, deflation, and cutting repetitions.
Return whether a variable is read as beat. This is true for every true
value except for the characters space, underscore, dot, zero, and minus.
Return whether a string specifies a rhythm in form of durations with optional rotation.
~~~js
if (Rhythm.isDurationString(s)) {
rhythm = Rhythm.fromDurations(s)
}
~~~
Read a string, an Array`, or a list of values as rhythm and returns an Array of pulses.
- @nichtich (Jakob Voß)
Contributions are welcome! Best use the rhythmicon issue tracker for questions, bug reports, and/or feature requests!
MIT license