A REPL where music is simply streams of input in node. Uses the awesome soundfonts of midi-js-soundfonts. Supports optional MIDI input.
npm install -g node-keyboard
Note: Installing node-keyboard will clone a soundfont library during install, resulting in an 800MB download.
node-keyboard
Inside the REPL, the examples in the example folder are loaded as getters with the prefix example_. E.g. example_01_scales.chromatic({ key: 'b', ms: 100 })
- MIDI In support by
midiIn, pipe to audio via.pipe(toAudio) - Create a stream of notes using
from - Delay playing across a cycle of intervals via
.pipe(delay(...)) - Select instrument or play with a random one via
.pipe(on(...))
Pipe the midiIn stream to a number of writable outputs. (To function, your MIDI device must be on when node starts.)
toAudio will play the notes
midiIn.pipe(toAudio)toRepl will output the notes in the REPL
midiIn.pipe(toRepl)toPiano will draw the piano for each note played
midiIn.pipe(toPiano)toLogger will console log the note (pipe after toAudio to see more information about the played note)
midiIn.pipe(toLogger)Or pipe them through each other
midiIn.pipe(toPiano).pipe(toAudio)
And remove from MIDI input via midiIn.unpipe() (or CTRL+C)
Create an [infinite] stream of notes from an array using from (supports notes as variables).
from(c, e, g).pipe(toAudio) // Hit CTRL+C (SIGINT) to unpipe immediatelyNote: supports all notes A0 to Cs8/Db8 (Cs8 is the syntax-friendly version of 'C#8')
Use delay(...args) to return a transform stream that will emit after the given delays (where the delays are cycled)
from(c1, g1, c2, g2, c3, g3).pipe(delay(250, 250, 500)).pipe(toAudio)Use on(instrument) to return a transform stream that will ensure the given instrument is used.
from(c,e,g).pipe(on('guitar')).pipe(delay(200)).pipe(toAudio)Note: Breaking via CTRL+C will stop the stream by unpiping everything
Functionality, without the streams.
instrumentslist all instruments availablescaleslist all scales supported
###Side effects
play(note)plays a note. Eg.
[c,e,g].forEach(play)piano(note)draws the piano playing that note Eg.
[c,e,g].forEach((note, i) => setTimeout(() => piano(note), 400 * i))log(note)logs the note tostdout. (Includes the instrument if chained afterplay) Eg.
[f,a,c].map(play).forEach(log)chord(name)projects a chord name out to an array of notes. Eg.
chord('cm9')
// [ 'c4', 'eb4', 'g4', 'bb4', 'd5' ]scale(note, name)projects a note through the named scale Eg.
scale('a', 'flamenco')
// [ 'a5', 'bb5', 'c#6', 'd6', 'e6', 'f6', 'g#6' ]sequence(note, ...semitones)projects a note through the given semitone sequence Eg.
sequence(c, 2, 1, 2, 2, 1, 2, 2) // c minor scale
// [ 'c3', 'd3', 'eb3', 'f3', 'g3', 'g#3', 'a#3', 'c4' ]instrument([name]])returns mapping function to play on instrument. If no parameter provided it chooses a random instrument. Eg.:
[c,e,g].map(instrument('guitar')).forEach(play)interval(...intervals)returns mapping function to project intervals. Eg.
[c,e,g].map(interval('P1','P5')).reduce((acc, cur) => acc.concat(cur), [])
// [ 'c3', 'g3', 'e3', 'b3', 'g3', 'd4' ]only(...numbers)returns filter predicate to filter out to required interval positions. Eg.
scale(c, 'major').filter(only(1,3,5,7)).map(play) // Cmaj7- RxJS support and examples via node-keyboard-rx
- Mouse support (OSX only) at node-keyboard-mouse
- Twitter support at node-keyboard-twitter
- MongoDB support at node-keyboard-mongo
- Object to chords - shape mappings at node-keyboard-shapes
- Reusing a stream and repiping it through transformers E.g.
let guitar = from(c,e,g).pipe(on('guitar')).pipe(delay(200))
guitar.pipe(toAudio)
// CTRL+C
guitar.pipe(toAudio) // works
// CTRL+C
guitar.pipe(on()).pipe(toAudio) // works first time only
// CTRL+C
guitar.pipe(on()).pipe(toAudio) // won't play the guitar stream's final on() is still piped to the previous on()I spoke on node-keyboard at EmpireNode in November 2016 
(see commit log for earlier releases)2.5.0Support for switching instruments2.5.5Addingevery2.6.0Persistent history for the REPL2.6.1Adding eslint and ensuringplayreturns input
2.7.0Support for MIDI input2.8.0Support for notes as first-class objects (Symbol-like)2.9.0Support for midi streams:midiIn,toRepl,toAudioandtoPiano3.0.0Upgraded to stream-first, all stream variables are now factory functions (to reuse). Support for fromArray. Deprecated older array functionality.3.1.0RenamedfromArraytofrom, allowfromto continue forever, limitedwithDelayto have a highWaterMark of 1 and play first immediately, brought in SIGINT support to unpipe streams when CTRL+C pressed3.2.0RenamedwithDelaytodelay. AddedtoLogger. Addedonto play instruments.3.3.0Added base functionschord(),scale, functorsinstrument()anfinterval(), and propertiesinstrumentsandscales. Many bug fixes.3.4.0Migrated to using getters for writable streams for brevity3.5.0Support foronly()3.6.0Subscription removal on SIGINT for Rx, support forpianofunction, support forrunInThisContext, and stream getter bugfix3.7.0Support forlogfunction, removal ofrunInThisContext(not necessary)3.8.0Errors no longer thrown, just shown. Support for examples3.9.0Removed Rx support and turned it into a plugin
-
When no octave is provided (e.g.
play(a)) then 3rd octave (a3220Hz) (starting atc3on an 8-octave piano) is the default. -
a0,bb0(a#0) andb0are the only notes belowc1 -
Sharp can be denoated by
swhen not surrounding note by strings (i.e.as4 ==== 'a#4'). Double-sharp is denoted withxas inax3(enharmonicallyb3). Double-flat is denoted withbbas inbbb3(enharmonicallya3)
- The fantastic midi-js-soundfonts library for all the underlying recordings
- The stunning teoria library for note, chord and scale support

