Skip to content
This repository has been archived by the owner on Apr 5, 2021. It is now read-only.

An Rx-based interface for programming musical automata in JavaScript. (WIP)

Notifications You must be signed in to change notification settings

fennifith/music-automata-api

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

29 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

The goal of this project is to create an API that can be used to schedule and organize automated music generation using ReactiveX and the observable pattern.

Inspiration

This was mainly inspired by the work of Lars Dietrich. I can only speculate as to how it was put together, but (with the exception of Titan) a large amount of it does appear to be scripted, and most of the work seems to have been put into the visualization rather than automating the music itself. Which is perfectly fine.

65 Days of Static is also doing work that is perhaps closer to what this project hopes to accomplish. This video shows a lot of what they have achieved, and many of their tweets show this in practical use.

Some of the actual music generation strategies are based on this article by Paul D. Reiners about the relationship between cellular automata and music.

Design

To gain some insight into how this can be used, think of music generation as a series of mutations upon an existing set of data. For example, a random integer value could be transformed into a chord, and made to conform to a specific beat pattern before then being passed to an instrument to play. While it may be common to do so, these are not mutations that need to happen at the exact time that the note is played, and should happen independently.

In this API, something that can accept or output a note is referred to as a "Block". Blocks are notified when a note is sent to them, and have the ability to modify the note, remove it, or create new notes before passing them along. Together, the blocks build a sort of tree structure along which notes are passed. For example, consider a set of blocks that are organized like below:

       [keyboard]
        /      \
    [piano]  [arpeggiator]
                 \
                [synth]

Here, all notes are created from keyboard input. They are then passed directly to the blocks "piano" and "arpeggiator". The "piano" block simply plays the notes it receives. The "arpeggiator" mutates them - into an arpeggio - and passes the result of that mutation to the "synth" block which, again, plays them.

Using this API, here is an example of what such a structure might look like:

let synth = new Block()
    .on('noteStart', (note) => {
        audioApi.playMidiNote(note.midi, synthInstrument);
    });

let arpeggiator = new Block()
    .on('note', (note) => {
        arpeggiator.forward(note);
        arpeggiator.forward(note.mutate({ midi: note.midi + 4 }));
        arpeggiator.forward(note.mutate({ midi: note.midi + 7 }));
    })
    .to(synth);

let piano = new Block()
    .on('noteStart', (note) => {
        audioApi.playMidiNote(note.midi, pianoInstrument);
    });

let keyboard = new Block()
    .to(piano)
    .to(arpeggiator);

About

An Rx-based interface for programming musical automata in JavaScript. (WIP)

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published