tone-rhythm
Generate an array of Tone.Transport times given an array of musical rhythms in
various formats that Tone.js understands.
Written for exclusive use with Tone.js.
Features
- Works with latest version of Tone (v0.12.8 - v13.4.0)
- Works in-browser (transpiled) or in node (ES6)
- Light footprint (3.6kB minified)
- Intuitive for musicians
- Has a fully-documented API with examples below.
Why use tone-rhythm?
As a musician developing music applications, I wanted an API that would allow me to put rhythms along with a melody into Tone.Part
. The example on Tone's docs shows how this is expected:
var synth = new Tone.FMSynth().toMaster()
synth.triggerAttackRelease('C4', '4n', '8n')
synth.triggerAttackRelease('E4', '8n', Tone.Time('4n') + Tone.Time('8n'))
synth.triggerAttackRelease('G4', '16n', '2n')
synth.triggerAttackRelease('B4', '16n', Tone.Time('2n') + Tone.Time('8t'))
synth.triggerAttackRelease('G4', '16', Tone.Time('2n') + Tone.Time('8t')*2)
synth.triggerAttackRelease('E4', '2n', '0:3')
The third parameter in triggerAttackRelease
is the start time of the note we're triggering. Musicians don't normally consider where a note is in a timeline when composing music. I needed a way to calculate this ahead of time.
I found enlightenment after reading Music Theory using Tone.js - Play Rhythms. Based on the author's work, I created algorithms that accumulate rhythmic values in an array of durations to generate start times. The result feels much more intuitive to me (please see the examples below.)
Getting Started
Prerequisites
Tone.js (v0.12.x or higher)
Installing
npm install tone-rhythm
Or clone the repo and copy dist/tone-rhythm.min.js
into your project.
Usage
ES6 / Webpack
import ToneTime from 'tone/Tone/type/Time';
import { toneRhythm } from 'tone-rhythm';
const {
getBarsBeats,
addTimes,
getTransportTimes,
mergeMusicDataPart
} = toneRhythm(ToneTime);
Browser
Via node_modules:
<head>
<script src="https://unpkg.com/tone@13.4.9/build/Tone.js"></script>
<script src="node_modules/tone-rhythm/dist/tone-rhythm.min.js"></script>
</head>
Via https://unpkg.com/tone-rhythm
<head>
<script src="https://unpkg.com/tone@13.4.9/build/Tone.js"></script>
<script src="https://unpkg.com/tone-rhythm@2.0.0/dist/tone-rhythm.min.js"></script>
</head>
In your js file(s):
const {
getBarsBeats,
addTimes,
getTransportTimes,
mergeMusicDataPart
} = toneRhythm.toneRhythm(Tone.Time);
(Legacy) Pre-bundled with Tone 0.12.8
See docs/tone-rhythm@0.0.2.md.
API
Values which can populate a rhythms array:
- '4n' - a 'notation' value
- ['4n', '8t'] - an array of 'notation' values which will be added together
- ['r', '2n'] - an array that has 'r' at first index will be a rest
- ['r', '2n', '8t'] - (see above about 'r') and the remaining values will be added together
It's not recommended to use Tone's seconds format.
See documentation and below for tone-rhythm library usage.
Examples ("Maria" by Leonard Bernstein)
toneRhythm.getTransportTimes
Given an array of durations (see API), return transport times. Array<String|Number>
const mariaDurations = ['8n', '8n', ['2n', '4n'], '8n', '4t', '4t', '4t', '4t', '4t', '4t', '8n', ['2n', '4n'], '8n', '8n', '8n', '8n', '8n', ['4n', '8n'], '8n', '8n', '8n', '8n', '8n', '4n', '4n', ['2n', '4n', '8n'], '8n', '8n', ['2n', '4n'], '8n', '4t', '4t', '4t', '4t', '4t', '4t', '8n', ['2n', '4n'], '8n', '8n', '8n', '8n', '8n', ['4n', '8n'], '8n', '8n', '8n', '8n', '8n', '4n', '4n', ['2n', '4n', '8n']];
const mariaTransportTimes = toneRhythm.getTransportTimes(mariaDurations);
toneRhythm.mergeMusicDataPart
Returns array of objects for consumption by Tone.Part.
const mariaPitches = ["Eb4", "A4", "Bb4", "Eb4", "A4", "Bb4", "C5", "A4", "Bb4", "C5", "A4", "Bb4", "Bb4", "A4", "G4", "F4", "Eb4", "F4", "Bb4", "Ab4", "G4", "F4", "Eb4", "F4", "Eb4", "G4", "Eb4", "A4", "Bb4", "Eb4", "A4", "Bb4", "C5", "A4", "Bb4", "C5", "D5", "Bb4", "D5", "Eb5", "D5", "C5", "Bb4", "D5", "D5", "Eb5", "D5", "C5", "Bb4", "D5", "Eb5", "F5"];
const mergedData = mergeMusicDataPart({
rhythms: mariaDurations,
notes: mariaPitches,
startTime: '0:3:2'
});
Use in Tone.Part
const melodyPart = new Tone.Part((time, value) => {
piano.triggerAttackRelease(value.note, value.duration, time);
}, mergedData).start(0);
Contributing
Running the tests:
npm run dev
- build in dev mode and watch for changesnpm run test
- opens the tests in-browser
Acknowledgments
Thank you https://www.guitarland.com and the creator of Tone.js.
Documentation created with jsdoc2md