This is an explanation of how it works the 4th iteration of the scorejs prototype. All the examples shown are valid code (at least for today ;-)
The library makes two big assumptions:
- an score is made by combining indivisible entities called
elements
: an object with aduration
property. Currently the only type of elements supported arenotes
(an element withpitch
property) - The
notes
(or anyelement
) can be combined in two ways: sequentially or simultaneously. The resulting structures can be re-combined also in that two ways.
This is an example:
var melody = score.seq(score.note(1, 'C'), score.note(1, 'D'), score.note(1, 'E'))
var chord = score.sim(score.note(1, 'C'), score.note(1, 'E'), score.note(1, 'G'))
var song = score.sim(melody, chord)
The other important requirement (for me) is that the score (or score fragments) should be expressed in a declarative way. A serializable json
format is the preferred way to express the above:
var melody = score(
['seq', ['note', 1, 'C'], ['note', 1, 'D'], ['note', 1, 'E']]
)
var chord = score(
['sim', ['note', 1, 'C'], ['note', 1, 'E'], ['note', 1, 'G']]
)
var song = score(['sim', melody, chord])
Since write this is not very practical, some helper functions are implemented:
var melody = score.phrase('C D E', 1)
var chord = score.chord('C E G', 1)
And since simultaneously
is the default combination of the score
function, the above example can be written as:
var song = score(['phrase', 'C D E', 1], ['chord', 'C E G', 1])
With this system (and the help of a couple of -currently implemented- helper functions) you can write something like this:
var song2 = score(
['melody', '4/4', 'c2 d2 e2 (f2 g2) | a2 b2 | c3'],
['harmony', '4/4', 'Cmaj7 | Dm7 G7 | Cmaj7'])
The map
function allows to create element transformations. For example:
var medioForte = score.map(function (element) {
element.velocity = 50
return element
})
The above code has the problem that it mutates the original element, so it's not mapping it. It should be written like this:
var medioForte = score.map(function (element) {
return score.el(element, { velocity: 50 })
})
At can be used like this:
var song = score(
[medioForte, ['phrase', 'C D E']],
['chord', 'C E Bb']
)
Functions currently implented: trans
(to transpose notes), inst
to assign instrument to notes, vel
to set note velocity, and tempo
to convert duration to seconds. Also some helpers: phrase
to make a sequence of notes, chord
to build a fragment of simultaneous notes and melody
and harmony
to parse measutres.
Any score can be converted to an array of time ordered events with the events
function:
score.events(score(['phrase', 'C D E'])) // => [
// { pitch: 'C', time: 0, duration: 1 }
// { pitch: 'D', time: 1, duration: 1 }
// { pitch: 'E', time: 2, duration: 1 } ]