npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

tone-rhythm

v2.0.0

Published

Generate an array of Tone.Transport times for use in Tone.Part

Downloads

91

Readme

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()

//schedule a series of notes to play as soon as the page loads
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

// tone is a required peer dependency
import ToneTime from 'tone/Tone/type/Time';

import { toneRhythm } from 'tone-rhythm';
// any or all methods can be used in the instantiated toneRhythm:
const {
    getBarsBeats,
    addTimes,
    getTransportTimes,
    mergeMusicDataPart
} = toneRhythm(ToneTime);

Browser

Via node_modules:

<head>
  <!-- Get tone from unpkg CDN: -->
  <script src="https://unpkg.com/[email protected]/build/Tone.js"></script>
  <!-- Import `tone-rhythm.min.js` from node_modules: -->
  <script src="node_modules/tone-rhythm/dist/tone-rhythm.min.js"></script>
  <!-- OR simply provide your path/to/tone-rhythm.min.js -->
</head>

Via https://unpkg.com/tone-rhythm

<head>
  <!-- Get tone from unpkg CDN: -->
  <script src="https://unpkg.com/[email protected]/build/Tone.js"></script>
  <!-- Get tone-rhythm from unpkg CDN: -->
  <script src="https://unpkg.com/[email protected]/dist/tone-rhythm.min.js"></script>
  <!-- OR simply provide your path/to/tone-rhythm.min.js -->
</head>

In your js file(s):

const {
  getBarsBeats,
  addTimes,
  getTransportTimes,
  mergeMusicDataPart
} = toneRhythm.toneRhythm(Tone.Time); // both `toneRhythm` and `Tone.Time` are available globally from imports above

(Legacy) Pre-bundled with Tone 0.12.8

See docs/[email protected].

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); /* ->
  Result:
[0, "0:0:2", "0:1:0", "1:0:0", "1:0:2", "1:1:0.667", "1:1:3.334", "1:2:2", "1:3:0.667", "1:3:3.334", "2:0:2", "2:1:0", "3:0:0", "3:0:2", "3:1:0", "3:1:2", "3:2:0", "3:2:2", "4:0:0", "4:0:2", "4:1:0", "4:1:2", "4:2:0", "4:2:2", "4:3:2", "5:0:2", "6:0:0", "6:0:2", "6:1:0", "7:0:0", "7:0:2", "7:1:0.667", "7:1:3.334", "7:2:2", "7:3:0.667", "7:3:3.334", "8:0:2", "8:1:0", "9:0:0", "9:0:2", "9:1:0", "9:1:2", "9:2:0", "9:2:2", "10:0:0", "10:0:2", "10:1:0", "10:1:2", "10:2:0", "10:2:2", "10:3:2", "11:0:2"]
*/

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'
}); /* -> [
  {time: "0:3:2", duration: "8n", note: "Eb4", idx: 0},
  {time: "1:0:0", duration: "8n", note: "A4", idx: 1},
  {time: "1:0:2", duration: "0:3:0", note: "Bb4", idx: 2},
  {time: "1:3:2", duration: "8n", note: "Eb4", idx: 3},
  {time: "2:0:0", duration: "4t", note: "A4", idx: 4},
  {time: "2:0:2.667", duration: "4t", note: "Bb4", idx: 5},
  ...
]
*/

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 changes
  • npm run test - opens the tests in-browser

Acknowledgments

Thank you https://www.guitarland.com and the creator of Tone.js.

Documentation created with jsdoc2md