All Projects → isaaclyman → blackswan-js

isaaclyman / blackswan-js

Licence: MIT License
A library for expressive music composition in JavaScript.

Programming Languages

typescript
32286 projects
javascript
184084 projects - #8 most used programming language

Projects that are alternatives of or similar to blackswan-js

cl-patterns
Library for writing patterns to generate or process (a)musical sequences of mathematically (un)related (non-)compound values in Lisp.
Stars: ✭ 62 (+63.16%)
Mutual labels:  music-composition, synth
Daw
GridSound (0.33.0) wants to be an open source online digital audio workstation following the new WebAudio API 🎛🎹🎵✨
Stars: ✭ 804 (+2015.79%)
Mutual labels:  synth, web-audio
chords
Text-based chord progression editor
Stars: ✭ 25 (-34.21%)
Mutual labels:  music-composition, web-audio
Awesome Web Audio
A list of resources and projects to help learn about audio
Stars: ✭ 73 (+92.11%)
Mutual labels:  synth, web-audio
Webaudiofont
Use full GM set of musical instruments to play MIDI and single sounds or effects. Support for reverberation and equaliser. No plugins, no Flash. Pure HTML5 implementation compatible with desktop and mobile browser. See live examples.
Stars: ✭ 600 (+1478.95%)
Mutual labels:  music-composition, synth
Javascriptmusic
Live coding music and synthesis in Javascript / AssemblyScript (WebAssembly)
Stars: ✭ 193 (+407.89%)
Mutual labels:  music-composition, synth
Comet
Web Synthesis on steroids
Stars: ✭ 18 (-52.63%)
Mutual labels:  synth, web-audio
TSynth-Teensy4.1
TSynth for Teensy 4.1
Stars: ✭ 101 (+165.79%)
Mutual labels:  synth
neodigm55
An eclectic low-code vanilla JavaScript UX micro-library for those that defiantly think for themselves.
Stars: ✭ 14 (-63.16%)
Mutual labels:  web-audio
music-machine
Create music using a generative music grammar.
Stars: ✭ 37 (-2.63%)
Mutual labels:  music-composition
fastidious-envelope-generator
Envelope generator (aka ADSR) for the Web Audio API that aims to be free of artifacts and handle edge cases well
Stars: ✭ 56 (+47.37%)
Mutual labels:  web-audio
cycle-audio-graph
Audio graph driver for Cycle.js based on virtual-audio-graph
Stars: ✭ 19 (-50%)
Mutual labels:  web-audio
glicol
(Audio) graph-oriented live coding language and music DSP library written in Rust
Stars: ✭ 853 (+2144.74%)
Mutual labels:  web-audio
monome-rack
VCV Rack plugin for monome Eurorack modules
Stars: ✭ 161 (+323.68%)
Mutual labels:  music-composition
audio-context-timers
A replacement for setInterval() and setTimeout() which works in unfocused windows.
Stars: ✭ 12 (-68.42%)
Mutual labels:  web-audio
react-orchestra
A declarative toolbox to build interactive musical instruments on web and mobile.
Stars: ✭ 72 (+89.47%)
Mutual labels:  music-composition
wafxr
sound effects for the web
Stars: ✭ 52 (+36.84%)
Mutual labels:  web-audio
snestracker
Super Nintendo Entertainment System Music Software. Super Famicom Music Software
Stars: ✭ 161 (+323.68%)
Mutual labels:  music-composition
react-redux-webaudio
An event manager for the Web Audio API, integrated with react-redux.
Stars: ✭ 23 (-39.47%)
Mutual labels:  web-audio
negasonic
This ain't Sonic Pi, but it works on the browser: www.negasonic.org
Stars: ✭ 73 (+92.11%)
Mutual labels:  web-audio

blackswan.js

A library for expressive music composition in JavaScript

About

blackswan.js is named after "Black Swan Song" by the British band Athlete. Its intended use is for writing songs. Any song written in blackswan.js can easily be played back in compatible browsers (up-to-date Chrome is a sure bet). It has a simple piano synth built in and is easy to use if you have basic JavaScript skills.

Principles

  • Writing a song in blackswan.js is more like writing sheet music than sound programming.
  • A decent almost-piano is baked in.
  • Structured improvisation is a first-class feature.
  • For power users, the synth and improviser are user-swappable with minimal headache.

Installation

Via NPM:

npm install --save blackswan-js

import blackswan from 'blackswan-js'

Alternately, you can add a <script> tag referencing "dist/blackswan.js" and the blackswan global will be attached to the window object.

Basic Features

After including blackswan.js in a page (or importing it from the NPM package):

// Create a song with a title, time signature and tempo (BPM)
var song = blackswan.song('My First Song');
song.setTimeSignature(4, 4);
song.setTempo(120);

// Now let's set up a chord to use later
// blackswan.chord: pass in all the notes to be played simultaneously, a
//  duration (note value, e.g. 0.25 for a quarter note), and optional
//  configuration parameters
// Here we only want to set the notes, not the duration or config, so
//  we use fn.bind(scope, param1..paramN)
var cMajorChord = blackswan.chord.bind(null, ['c4', 'e4', 'g4']);

// Here's a riff we can use later
// blackswan.sequence: pass in an array of rests, notes, chords, etc.
//  in the order that they should be played
// Sequences are single-threaded, but multiple sequences can be
//  played at once
// Sequences start at the beginning of an imaginary measure
//  in the given time signature
var lowerRiff = blackswan.sequence([
  // blackswan.rest: pass in the note value to rest for
  blackswan.rest(1/4),
  // blackswan.note: pass in the note name (as before), a duration (note
  //  value) and optional configuration parameters
  blackswan.note('c3', 1/2, blackswan.as.Staccato),
  blackswan.note('e3', 1/4, blackswan.as.Staccato),
  blackswan.note('c3', 1, blackswan.as.Staccato)
]);

// Defining a set of notes to use for later improvisation
// blackswan.scale: pass in an array of notes (or chords, as nested arrays of notes)
//  to improvise with and an optional configuration object
var lowerScale = blackswan.scale([
  'b2', 'c3', 'e3', 'f3', 'g3', 'c4',
], {
  // durations: an array of note durations, in note values, that the
  //  improviser may select from for each note. To make some durations more
  //  common than others, repeat them in the array. For example, in this case,
  //  a quarter note will be twice as common as a half note or a whole note,
  //  when using the default improviser.
  // Default is [1/4].
  durations: [1/4, 1/4, 1/2, 1],
  // style: an array of blackswan.as configuration parameters
  // Default is [].
  style: [blackswan.as.Staccato]
});

// blackswan.song.at: pass in the measure to start from
song.at(0)
// blackswan.song.at.repeats: pass in a note or chord and a configuration
//  object
// "every": how frequently to repeat (as a note value). Here, the cMajorChord
//   will be repeated every whole note. Since it lasts a whole note, there is no
//   rest between chords.
// "times": how many times to repeat
  .repeats(cMajorChord(1, blackswan.as.Staccato), { every: 1, times: 21 });

// blackswan.song.at.plays: pass in a note, chord, or riff
song.at(1)
  .plays(lowerRiff);

// blackswan.song.at.improvises: pass in a scale and a duration (note value)
song.at(3)
  .improvises(lowerScale, 8);

// blackswan.song.play: plays your song
song.play();

Advanced features

// You can sub in your own functions for creating gain nodes and oscillator nodes,
//  playing a note, and improvising:

blackswan.settings.setGain(function (frequency, style, masterGain) {
  // `frequency` is a number in hertz.
  // `style` is an array of blackswan.as style values.
  // `masterGain` is the master GainNode for the entire composition, and the final
  //   node before AudioContext.destination.
  // Return a GainNode.
  // You can chain nodes as desired, but you *must* connect the final node
  //  to masterGain.
  //  E.g.: GainNode -> DynamicsCompressorNode -> masterGain
});

blackswan.settings.setOscillator(function (frequency, style, gainNode) {
  // `frequency` is a number in hertz.
  // `style` is an array of blackswan.as style values.
  // `gainNode` is a GainNode connected to the master GainNode.
  //   E.g.: gainNode -> masterGain -> AudioContext.destination
  // Return an OscillatorNode.
  // You can chain nodes as desired, but you *must* connect the final node
  //  to gainNode.
  //  E.g.: OscillatorNode -> GainNode -> ConvolverNode -> DelayNode -> gainNode
  // The start() and stop() methods of the OscillatorNode will be used to
  //  schedule the note.
});

blackswan.settings.setPlayer(function (note, startSeconds, stopSeconds) {
  // `note` is an object with the following properties:
  //   Frequency: a number in hertz
  //   GetNoteNodes: a function that has no arguments and returns an object with
  //    the following properties:
  //      Gain: the final GainNode that a note will pass through before reaching
  //       the master GainNode, which is connected to AudioContext.destination.
  //      Oscillator: an OscillatorNode that has not had ".stop()" called on it
  //   Play: a function that accepts a note, startSeconds and stopSeconds and
  //    plays a note. (Yes, this is the function we're building right now.)
  //   Style: an array of blackswan.as style values
  // `startSeconds` is a number in seconds indicating when the note should start
  // `stopSeconds` is a number in seconds indicating when the note should stop
  // Play the note and do not return anything.
});

blackswan.settings.setImproviser(function (scale, duration) {
  // `scale` is an object with the following properties:
  //   Config: an object with the following properties:
  //     durations: an array of note values
  //     style: an array of blackswan.as style values
  //   Playables: an array of strings and/or arrays of strings. Each string is a note
  //    name e.g. 'c4' in either case. Strings are meant to be notes, and arrays
  //    of strings are meant to be chords.
  // `duration` is the duration (note value) that should be improvised over.
  // Return an array of blackswan.note(...), blackswan.chord(...), and/or
  //  blackswan.rest(...)
});

let song = blackswan.song('Advanced Features');

// blackswan.song.at.callback: execute a function when the given measure is reached
song.at(4.5).callback(function(song) {
  // Display a message, progress an animation, whatever you want here.
  // If you put song.play() here, your song will start over.
  song.play();

  song.at(4.5).callback(function (song) {
    // This will trigger 4.5 measures from *now*, not from the beginning of the song.
  });
});

Styles

blackswan.as currently has the following style values:

None,
Legato,
Staccato,
Pianissimo,
Piano,
MezzoPiano,
MezzoForte,
Forte,
Fortissimo

Acknowledgements

  • Thanks to MDN, without whose excellent documentation this would not have been possible.
  • Thanks to mohayonao for web-audio-scheduler, which is used by blackswan's callback feature. Thanks to Chris Wilson, who inspired web-audio-scheduler, for writing up an event-scheduling solution that has enough precision to work with web audio.
  • Thanks to the TypeScript community. TypeScript made BlackSwan manageable as a weekend hobby project.
  • Thanks to Alejandro Mantecon Guillen for writing about the annoying clicks that come from suddenly starting or stopping Web Audio oscillators and how to fix them.
  • Thanks to Sebastian Zimmer for building a lookahead limiter that prevents clipping when playing multiple oscillators simultaneously. Thanks to Christian Floisand for inspiring it.
  • Thanks to everyone who has written about the Web Audio API on blogs, Stack Overflow and elsewhere. This library was easy to write because of the extraordinary professional generosity of the software development community.
Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].