-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 6ee0548
Showing
18 changed files
with
11,966 additions
and
0 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
# VexABC | ||
|
||
ABC notation parser and renderer for VexFlow | ||
|
||
Copyright (c) 2012 Mikael Nousiainen | ||
|
||
## See VexABC in action and try it | ||
|
||
* [VexABC interactive editor](http://test.incompleteopus.net/vexabc/test/editor.html) | ||
* [VexABC tests](http://test.incompleteopus.net/vexabc/test/test.html) | ||
|
||
## VexABC features | ||
|
||
* VexABC is a work in progress, which means that many features of the ABC music standard are incomplete or completely missing | ||
* Many of the basic constructs and features of the ABC music standard are already working | ||
* See the [VexABC tests](http://test.incompleteopus.net/vexabc/test/test.html) to find out features implemented and working | ||
* Currently, only one voice and a single stave can be used | ||
* Multi-voice and multi-stave (system) support will be implemented eventually | ||
* The current VexFlow API imposes some restrictions on how notation can be rendered | ||
* Clefs, key signatures and time signatures can be rendered only at the beginning of a measure | ||
* Voltas (e.g. variant endings) can only begin and end on measure boundaries | ||
* Slurs are not supported | ||
* Grace notes are not supported | ||
* Some ABC decorations can not be rendered yet | ||
* VexABC aims to implement [ABC music standard 2.1](http://abcnotation.com/wiki/abc:standard:v2.1) | ||
|
||
## VexABC dependencies | ||
|
||
Main dependencies: | ||
* [VexFlow](http://github.com/0xfe/vexflow/) (latest GIT master branch) to render the notation | ||
* [PEG.js](http://github.com/dmajda/pegjs/) (latest GIT master branch) for parsing ABC notation text | ||
* jQuery 1.8 | ||
|
||
Test dependencies: | ||
* QUnit 1.10.0 for running unit tests | ||
* Twitter Bootstrap 2.2 is used in the web pages for tests | ||
|
||
## What is ABC notation? | ||
|
||
ABC notation is a text-based music notation system. | ||
|
||
* [ABC notation home](http://abcnotation.com/) | ||
* [ABC notation examples](http://abcnotation.com/examples) | ||
* [ABC music standard 2.1](http://abcnotation.com/wiki/abc:standard:v2.1) | ||
|
||
## What is VexFlow? | ||
|
||
VexFlow is an open-source web-based music notation rendering API. | ||
|
||
* [VexFlow Home](http://vexflow.com/) | ||
* [VexFlow GitHub repository](http://github.com/0xfe/vexflow/) | ||
* [VexFlow Google Group](https://groups.google.com/forum/?fromgroups#!forum/vexflow) | ||
|
||
## What is PEG.js? | ||
|
||
PEG.js is a simple parser generator for JavaScript. | ||
|
||
* [PEG.js Home](http://pegjs.majda.cz/) | ||
* [PEG.js GitHub repository](http://github.com/dmajda/pegjs/) | ||
|
||
## VexABC license | ||
|
||
Mozilla Public License, version 2.0 - http://www.mozilla.org/MPL/2.0/ | ||
|
||
* [License FAQ](http://www.mozilla.org/MPL/2.0/FAQ.html) | ||
|
Large diffs are not rendered by default.
Oops, something went wrong.
Large diffs are not rendered by default.
Oops, something went wrong.
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,328 @@ | ||
/* | ||
* VexABC - ABC notation parser and renderer for VexFlow | ||
* | ||
* Copyright (c) 2012 Mikael Nousiainen | ||
* | ||
* This Source Code Form is subject to the terms of the Mozilla Public | ||
* License, v. 2.0. If a copy of the MPL was not distributed with this | ||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||
*/ | ||
|
||
VexAbc.Def = function() { | ||
}; | ||
|
||
VexAbc.Util = function() { | ||
}; | ||
|
||
VexAbc.Def.DURATION_RESOLUTION = 262144; | ||
VexAbc.Def.DEFAULT_VOICE_ID = "default"; | ||
|
||
VexAbc.Util.isDataNotePitchEqual = function(dataNote1, dataNote2) { | ||
return ((dataNote1.pitch == dataNote2.pitch) && (dataNote1.octave == dataNote2.octave)); | ||
} | ||
|
||
VexAbc.Util.findEqualDataNotePitchIndices = function(dataNotes1, dataNotes2, fromIndices) { | ||
var result = { | ||
firstIndices: [], | ||
secondIndices: [] | ||
}; | ||
|
||
var length; | ||
if (fromIndices) { | ||
length = fromIndices.length; | ||
} else { | ||
length = dataNotes2.length; | ||
} | ||
|
||
for (var i = 0; i < length; i++) { | ||
var index; | ||
if (fromIndices) { | ||
index = fromIndices[i]; | ||
} else { | ||
index = i; | ||
} | ||
|
||
var dataNote1 = dataNotes1[index]; | ||
|
||
for (var j = 0; j < dataNotes2.length; j++) { | ||
var dataNote2 = dataNotes2[j]; | ||
|
||
if (VexAbc.Util.isDataNotePitchEqual(dataNote1, dataNote2)) { | ||
result.firstIndices.push(index); | ||
result.secondIndices.push(j); | ||
} | ||
} | ||
} | ||
|
||
return result; | ||
} | ||
|
||
VexAbc.Def.fractionDurationToVexFlowDuration = {}; | ||
|
||
// TODO: This kind of array definition is really inflexible, so find a better way to deduce duration! | ||
VexAbc.Def.fractionDurationToVexFlowDuration[VexAbc.Def.DURATION_RESOLUTION / 1] = | ||
{ value: "1", dots: 0 }; | ||
VexAbc.Def.fractionDurationToVexFlowDuration[VexAbc.Def.DURATION_RESOLUTION / 2 + VexAbc.Def.DURATION_RESOLUTION / 4 + VexAbc.Def.DURATION_RESOLUTION / 8 + VexAbc.Def.DURATION_RESOLUTION / 16] = | ||
{ value: "2", dots: 3 }; | ||
VexAbc.Def.fractionDurationToVexFlowDuration[VexAbc.Def.DURATION_RESOLUTION / 2 + VexAbc.Def.DURATION_RESOLUTION / 4 + VexAbc.Def.DURATION_RESOLUTION / 8] = | ||
{ value: "2", dots: 2 }; | ||
VexAbc.Def.fractionDurationToVexFlowDuration[VexAbc.Def.DURATION_RESOLUTION / 2 + VexAbc.Def.DURATION_RESOLUTION / 4] = | ||
{ value: "2", dots: 1 }; | ||
VexAbc.Def.fractionDurationToVexFlowDuration[VexAbc.Def.DURATION_RESOLUTION / 2] = | ||
{ value: "2", dots: 0 }; | ||
VexAbc.Def.fractionDurationToVexFlowDuration[VexAbc.Def.DURATION_RESOLUTION / 4 + VexAbc.Def.DURATION_RESOLUTION / 8 + VexAbc.Def.DURATION_RESOLUTION / 16 + VexAbc.Def.DURATION_RESOLUTION / 32] = | ||
{ value: "4", dots: 3 }; | ||
VexAbc.Def.fractionDurationToVexFlowDuration[VexAbc.Def.DURATION_RESOLUTION / 4 + VexAbc.Def.DURATION_RESOLUTION / 8 + VexAbc.Def.DURATION_RESOLUTION / 16] = | ||
{ value: "4", dots: 2 }; | ||
VexAbc.Def.fractionDurationToVexFlowDuration[VexAbc.Def.DURATION_RESOLUTION / 4 + VexAbc.Def.DURATION_RESOLUTION / 8] = | ||
{ value: "4", dots: 1 }; | ||
VexAbc.Def.fractionDurationToVexFlowDuration[VexAbc.Def.DURATION_RESOLUTION / 4] = | ||
{ value: "4", dots: 0 }; | ||
VexAbc.Def.fractionDurationToVexFlowDuration[VexAbc.Def.DURATION_RESOLUTION / 8 + VexAbc.Def.DURATION_RESOLUTION / 16 + VexAbc.Def.DURATION_RESOLUTION / 32 + VexAbc.Def.DURATION_RESOLUTION / 64] = | ||
{ value: "8", dots: 3 }; | ||
VexAbc.Def.fractionDurationToVexFlowDuration[VexAbc.Def.DURATION_RESOLUTION / 8 + VexAbc.Def.DURATION_RESOLUTION / 16 + VexAbc.Def.DURATION_RESOLUTION / 32] = | ||
{ value: "8", dots: 2 }; | ||
VexAbc.Def.fractionDurationToVexFlowDuration[VexAbc.Def.DURATION_RESOLUTION / 8 + VexAbc.Def.DURATION_RESOLUTION / 16] = | ||
{ value: "8", dots: 1 }; | ||
VexAbc.Def.fractionDurationToVexFlowDuration[VexAbc.Def.DURATION_RESOLUTION / 8] = | ||
{ value: "8", dots: 0 }; | ||
VexAbc.Def.fractionDurationToVexFlowDuration[VexAbc.Def.DURATION_RESOLUTION / 16 + VexAbc.Def.DURATION_RESOLUTION / 32 + VexAbc.Def.DURATION_RESOLUTION / 64 + VexAbc.Def.DURATION_RESOLUTION / 128] = | ||
{ value: "16", dots: 3 }; | ||
VexAbc.Def.fractionDurationToVexFlowDuration[VexAbc.Def.DURATION_RESOLUTION / 16 + VexAbc.Def.DURATION_RESOLUTION / 32 + VexAbc.Def.DURATION_RESOLUTION / 64] = | ||
{ value: "16", dots: 2 }; | ||
VexAbc.Def.fractionDurationToVexFlowDuration[VexAbc.Def.DURATION_RESOLUTION / 16 + VexAbc.Def.DURATION_RESOLUTION / 32] = | ||
{ value: "16", dots: 1 }; | ||
VexAbc.Def.fractionDurationToVexFlowDuration[VexAbc.Def.DURATION_RESOLUTION / 16] = | ||
{ value: "16", dots: 0 }; | ||
VexAbc.Def.fractionDurationToVexFlowDuration[VexAbc.Def.DURATION_RESOLUTION / 32 + VexAbc.Def.DURATION_RESOLUTION / 64 + VexAbc.Def.DURATION_RESOLUTION / 128 + VexAbc.Def.DURATION_RESOLUTION / 256] = | ||
{ value: "32", dots: 3 }; | ||
VexAbc.Def.fractionDurationToVexFlowDuration[VexAbc.Def.DURATION_RESOLUTION / 32 + VexAbc.Def.DURATION_RESOLUTION / 64 + VexAbc.Def.DURATION_RESOLUTION / 128] = | ||
{ value: "32", dots: 2 }; | ||
VexAbc.Def.fractionDurationToVexFlowDuration[VexAbc.Def.DURATION_RESOLUTION / 32 + VexAbc.Def.DURATION_RESOLUTION / 64] = | ||
{ value: "32", dots: 1 }; | ||
VexAbc.Def.fractionDurationToVexFlowDuration[VexAbc.Def.DURATION_RESOLUTION / 32] = | ||
{ value: "32", dots: 0 }; | ||
VexAbc.Def.fractionDurationToVexFlowDuration[VexAbc.Def.DURATION_RESOLUTION / 64 + VexAbc.Def.DURATION_RESOLUTION / 128 + VexAbc.Def.DURATION_RESOLUTION / 256 + VexAbc.Def.DURATION_RESOLUTION / 512] = | ||
{ value: "64", dots: 3 }; | ||
VexAbc.Def.fractionDurationToVexFlowDuration[VexAbc.Def.DURATION_RESOLUTION / 64 + VexAbc.Def.DURATION_RESOLUTION / 128 + VexAbc.Def.DURATION_RESOLUTION / 256] = | ||
{ value: "64", dots: 2 }; | ||
VexAbc.Def.fractionDurationToVexFlowDuration[VexAbc.Def.DURATION_RESOLUTION / 64 + VexAbc.Def.DURATION_RESOLUTION / 128] = | ||
{ value: "64", dots: 1 }; | ||
VexAbc.Def.fractionDurationToVexFlowDuration[VexAbc.Def.DURATION_RESOLUTION / 64] = | ||
{ value: "64", dots: 0 }; | ||
|
||
// TODO: How to handle unknown durations? | ||
VexAbc.Util.convertFractionDurationToVexFlowDuration = function(multiplier, noteValue) { | ||
var factor = VexAbc.Def.DURATION_RESOLUTION / noteValue; | ||
var durationTicks = multiplier * factor; | ||
|
||
var result = VexAbc.Def.fractionDurationToVexFlowDuration[durationTicks]; | ||
if (!result) { | ||
return null; | ||
} | ||
|
||
result.beamable = (durationTicks < (VexAbc.Def.DURATION_RESOLUTION / 4)); | ||
|
||
return result; | ||
} | ||
|
||
VexAbc.Util.isBeamedDuration = function(multiplier, noteValue) { | ||
var factor = VexAbc.Def.DURATION_RESOLUTION / noteValue; | ||
var durationTicks = multiplier * factor; | ||
return (durationTicks < (VexAbc.Def.DURATION_RESOLUTION / 4)); | ||
} | ||
|
||
// Aim for stave center :) | ||
VexAbc.Def.restNoteKeyForClef = { | ||
"treble": "b/4", | ||
"alto": "c/4", | ||
"tenor": "a/3", | ||
"bass": "d/3", | ||
"perc": "b/4" | ||
}; | ||
|
||
VexAbc.Util.getRestNoteKeyForClef = function(clef) { | ||
var key = VexAbc.Def.restNoteKeyForClef[clef]; | ||
if (!key) { | ||
return "b/4"; | ||
} | ||
|
||
return key; | ||
} | ||
|
||
VexAbc.Def.abcDecorationToVexFlowArticulation = { | ||
"staccato": "a.", // staccato | ||
"staccatissimo": "av", // staccatissimo (non-standard) | ||
"accent": "a>", // accent | ||
"emphasis": "a>", // accent | ||
">": "a>", // accent | ||
"tenuto": "a-", // tenuto | ||
"marcato": "a^", // marcato (marcatissimo?) (non-standard) | ||
"+": "a+", // left hand pizzicato | ||
"plus": "a+", // left hand pizzicato | ||
"snap": "ao", // snap pizzicato | ||
"thumb:": "ao", // snap pizzicato | ||
"fermata": "a@a", // fermata above staff | ||
"invertedfermata": "a@u", // fermata below staff | ||
"upbow": "a|", // up-bown - up stroke | ||
"downbow": "am" // down-bow - down stroke | ||
}; | ||
|
||
VexAbc.Util.convertAbcDecorationToVexFlowArticulation = function (decoration) { | ||
return VexAbc.Def.abcDecorationToVexFlowArticulation[decoration]; | ||
} | ||
|
||
VexAbc.Def.vexFlowAnnotationStyle = { | ||
"text": { | ||
fontName: "Times", | ||
fontSize: 12, | ||
fontWeight: "", | ||
verticalPosition: "above", | ||
justification: "center" | ||
}, | ||
"dynamics": { | ||
fontName: "Times", | ||
fontSize: 14, | ||
fontWeight: "italic", | ||
verticalPosition: "below", | ||
justification: "center" | ||
}, | ||
"other": { | ||
fontName: "Times", | ||
fontSize: 14, | ||
fontWeight: "italic", | ||
verticalPosition: "above", | ||
justification: "center" | ||
}, | ||
"chordSymbol": { | ||
fontName: "Times", | ||
fontSize: 14, | ||
fontWeight: "bold", | ||
verticalPosition: "above", | ||
justification: "center" | ||
}, | ||
"fingering": { | ||
fontName: "Times", | ||
fontSize: 10, | ||
fontWeight: "", | ||
verticalPosition: "above", | ||
justification: "center" | ||
} | ||
}; | ||
|
||
VexAbc.Util.getVexFlowAnnotationStyle = function(id) { | ||
return VexAbc.Def.vexFlowAnnotationStyle[id]; | ||
} | ||
|
||
VexAbc.Def.abcDecorationToVexFlowAnnotation = { | ||
"0": { | ||
type: "annotation", | ||
style: "fingering", | ||
value: "0" | ||
}, | ||
"1": { | ||
type: "annotation", | ||
style: "fingering", | ||
value: "1" | ||
}, | ||
"2": { | ||
type: "annotation", | ||
style: "fingering", | ||
value: "2" | ||
}, | ||
"3": { | ||
type: "annotation", | ||
style: "fingering", | ||
value: "3" | ||
}, | ||
"4": { | ||
type: "annotation", | ||
style: "fingering", | ||
value: "4" | ||
}, | ||
"5": { | ||
type: "annotation", | ||
style: "fingering", | ||
value: "5" | ||
}, | ||
"pppp": { | ||
type: "annotation", | ||
style: "dynamics", | ||
value: "pppp" | ||
}, | ||
"ppp": { | ||
type: "annotation", | ||
style: "dynamics", | ||
value: "ppp" | ||
}, | ||
"pp": { | ||
type: "annotation", | ||
style: "dynamics", | ||
value: "pp" | ||
}, | ||
"p": { | ||
type: "annotation", | ||
style: "dynamics", | ||
value: "p" | ||
}, | ||
"mp": { | ||
type: "annotation", | ||
style: "dynamics", | ||
value: "mp" | ||
}, | ||
"mf": { | ||
type: "annotation", | ||
style: "dynamics", | ||
value: "mf" | ||
}, | ||
"f": { | ||
type: "annotation", | ||
style: "dynamics", | ||
value: "f" | ||
}, | ||
"ff": { | ||
type: "annotation", | ||
style: "dynamics", | ||
value: "ff" | ||
}, | ||
"fff": { | ||
type: "annotation", | ||
style: "dynamics", | ||
value: "fff" | ||
}, | ||
"ffff": { | ||
type: "annotation", | ||
style: "dynamics", | ||
value: "ffff" | ||
}, | ||
"sfz": { | ||
type: "annotation", | ||
style: "dynamics", | ||
value: "sfz" | ||
}, | ||
"trill": { | ||
type: "annotation", | ||
style: "other", | ||
value: "tr" | ||
} | ||
}; | ||
|
||
VexAbc.Util.convertAbcDecorationToVexFlowAnnotation = function (decoration) { | ||
return VexAbc.Def.abcDecorationToVexFlowAnnotation[decoration]; | ||
} | ||
|
||
/* | ||
TODO: decorations using text annotations: | ||
!D.S.! the letters D.S. (=Da Segno) | ||
!D.C.! the letters D.C. (=either Da Coda or Da Capo) | ||
!dacoda! the word "Da" followed by a Coda sign | ||
!dacapo! the words "Da Capo" | ||
!fine! the word "fine" | ||
TODO: VexFlow probably supports these too: | ||
!segno! 2 ornate s-like symbols separated by a diagonal line | ||
!coda! a ring with a cross in it | ||
*/ | ||
|
Oops, something went wrong.