Typedoc API Reference, Examples and Demos can be found here. The API Reference is not commented but is mostly self explanatory and gives idea of full API.
This library allows you to view and play music scores (notation) in the browser.
I'm not a professional musician. I began learning classical guitar on my own, later taking lessons in classical guitar. I've also studied music theory independently.
This is a work in progress project. Expect changes, bugs, or unexpected behavior.
Breaking: Version 2 is major update and brought many changes.
Enough changes until next major update!
Breaking: Version 3 is another major update and brought some important changes.
npm i @tspro/web-music-score
// Import core module, it does not contain much.
import * as Core from "@tspro/web-music-score/core";
// Import audio module, it can play notes.
import * as Audio from "@tspro/web-music-score/audio";
// Import theory module, it contains all music theory stuff.
import * as Theory from "@tspro/web-music-score/theory";
// Import score module, it contains music score stuff.
import * as Score from "@tspro/web-music-score/score";
// Import react-ui module, it contains all react components.
// React is peer dependency "^18.0.0 || ^19.0.0".
import * as ScoreUI from "@tspro/web-music-score/react-ui";
// Import pieces module, it contains demo songs.
import * as Pieces from "@tspro/web-music-score/pieces";
// You can also use require
const Core = require("@tspro/web-music-score/core");
// etc.
This is an experimental module that can be used in html page via unpkg CDN.
It declares global variable WebMusicScore
that contains Core
, Audio
, Theory
, Score
,
and Pieces
as corresponding subpath modules (excluding react-ui
and audio-cg
).
<script src="https://unpkg.com/@tspro/web-music-score@3"></script>
<script src="https://unpkg.com/@tspro/web-music-score@3.0.0"></script>
<script src="https://unpkg.com/@tspro/web-music-score@3.0.0/dist/iife/index.global.js"></script>
<!--
Use one of above. It is recommended to use version number (e.g. @3.0.0 or at least @3).
This way if there is breaking change between versions your code does not stop working.
-->
<script>
const { Core, Audio, Theory, Score, Pieces } = window.WebMusicScore;
// ...
</script>
Following is the main interface explained.
Documents are created using DocumentBuilder
.
let builder = new Score.DocumentBuilder();
// Here build document, e.g.
builder
.addMEasure()
.addNote(0, "C3", Theory.NoteLength.Quarter)
// etc.
// When ready, get document:
let doc = builder.getDocument();
Setting score configuration takes place in first measure of next row.
builder.setScoreConfiguration(staffPreset: Score.StaffPreset);
staffPreset
can be:
Score.StaffPreset.Treble
: Staff with treble (G-) clef.Score.StaffPreset.Bass
: Staff with bass (F-) clef.Score.StaffPreset.Grand
: Both treble and bas staves.Score.StaffPreset.GuitarTreble
: Same as Treble
but one octave down.Score.StaffPreset.GuitarTab
: Guitar tab only.Score.StaffPreset.GuitarCombined
: Treble and tab for guitar.// Example
builder.setScoreConfiguration(Score.StaffPreset.GuitarCombined);
builder.setScoreConfiguration(config: Score.StaffConfig | Score.TabConfig);
builder.setScoreConfiguration(config: (Score.StaffConfig | Score.TabConfig)[]);
config
is StaffConfig
, TabConfig
or array of combination.
StaffConfig
contains following properties:
type
: "staff"clef
: Clef can be Score.Clef.G
or Score.Clef.F
.isOctaveDown
: boolean (optional)name
: staff name.minNote
: string (optional), minimum note allowed in staff.maxNote
: string (optional), maximum note allowed in staff.voiceIds
: number[] (optional), array of voice ids are visible on this staff.isGrand
: boolean (optional), use this to create grand staff.TabConfig
contains following properties:
type
: "tab"name
: tab name.tuning
: string | string[] (optional), tuning name or array of 6 note names for tuning.voiceIds
: number[] (optional), array of voice ids are visible on this tab.// Example: Staff and tab for guitar
builder.setScoreConfiguration([
{ type: "staff", clef: Score.Clef.G, isOctaveDown: true },
{ type: "tab", tuning: "Drop D" }
]);
// Example: Grand staff
builder.setScoreConfiguration([
{ type: "staff", clef: Score.Clef.G, isGrand: true },
{ type: "staff", clef: Score.Clef.F, isGrand: true }
]);
builder.setMesuresPerRow(measuresPerRow: number)
measuresPerRow
can be integer >= 1, or Infinity (default).
builder.setHeader(title?: string, composer?: string, arranger?: string);
// Example
builder.setHeader("Demo Song");
builder.addMeasure();
builder.endRow();
Manually induce row change. Next measure that is added will begin new row.
builder.setKeySignature(tonic: string, scaleType: Theory.ScaleType);
// Example: Am
builder.setKeySignature("A", Theory.ScaleType.Aeolian);
tonic
is scale tonic/root note, e.g. "C" (in "C Major").
scaleType
can be
Theory.ScaleType.Major
Theory.ScaleType.NaturalMinor
Theory.ScaleType.HarmonicMinor
Theory.ScaleType.Ionian
Theory.ScaleType.Dorian
Theory.ScaleType.Phrygian
Theory.ScaleType.Lydian
Theory.ScaleType.Mixolydian
Theory.ScaleType.Aeolian
Theory.ScaleType.Locrian
Theory.ScaleType.MajorPentatonic
Theory.ScaleType.MinorPentatonic
Theory.ScaleType.MajorHexatonicBlues
Theory.ScaleType.MinorHexatonicBlues
Theory.ScaleType.HeptatonicBlues
builder.setTimeSignature(timeSignature: string);
// Example
builder.setTimeSignature("3/4");
timeSignature can be:
"2/4"
"3/4"
"4/4"
"6/8"
"9/8"
builder.setTempo(beatsPerMinute: number, beatLength?: Theory.NoteLength, dotted?: boolean);
// Example
builder.setTempo(100, Theory.NoteLength.Quarter);
beatsPerMinute
is self explanatory.
beatLength
tells the length of each beat, e.g. Theory.NoteLength.Quarter.
dotted
tells if beatLength
is dotted.
builder.addNote(voiceId: number, note: string, noteLength: Theory.NoteLength, noteOptions?: Score.NoteOptions);
builder.addChord(voiceId: number, notes: string[], noteLength: Theory.NoteLength, noteOptions?: Score.NoteOptions);
// Examples
builder.addNote(0, "C4", Theory.NoteLength.Half, { dotted: true });
builder.addChord(1, ["C3", "E3", "G3"], Theory.NoteLength.Whole, { arpeggio: Score.Arpeggio.Down });
voiceId
can be 0
, 1
, 2
or 3
.
note
is note name, e.g. "G#3"
, "Db3"
.
notes
: array of notes string[]
(e.g. ["C3", "E3"]
)
noteLength
can be:
Theory.NoteLength.Whole
Theory.NoteLength.Half
Theory.NoteLength.Quarter
Theory.NoteLength.Eighth
Theory.NoteLength.Sixteenth
Theory.NoteLength.ThirtySecond
Theory.NoteLength.SixtyFourth
noteOptions
is optional object of note options (e.g. { dotted: true }
):
Note option | Type | |
---|---|---|
dotted | boolean |
Create dotted note. |
stem | Score.Stem.Auto/Up/Down |
Set stem direction. |
arpeggio | Score.Arpeggio.Up/Down | boolean |
Play column in arpeggio. |
staccato | boolean |
Play column in staccato. |
diamond | boolean |
Diamond shaped note head. |
triplet | boolean |
Set this note part of triplet. |
string | number | number[] |
String number for guitar tab. Array of string numbers for chord. |
builder.addRest(voideId: number, restLength: Theory.NoteLength, restOptions?: Score.RestOptions);
// Example
builder.addRest(0, Theory.NoteLength.Sixteenth);
voiceId
can be 0
, 1
, 2
or 3
.
restLength
is length of rest, similar as noteLength above.
restOptions
is optional object of rest options (e.g. { hide: true }
):
Rest option | Type | |
---|---|---|
dotted | boolean |
Create dotted rest. |
staffPos | string |
Staff positions (e.g. "C3" ). |
hide | boolean |
Add invisible rest. |
triplet | boolean |
Set this rest part of triplet. |
builder.addFermata(fermata?: Score.Fermata);
// Example
builder.addFermata(Score.Fermata.AtMeasureEnd);
fermata
is typeof Score.Fermata
and can be:
Score.Fermata.AtNote
: Adds fermata anchored to previously added note, chord or rest.Score.Fermata.AtMeasureEnd
: Adds fermata at the end of measure.Add navigational element to measure.
builder.addNavigation(navigation: Score.Navigation, ...args?);
// Examples
builder.addNavigation(Score.Navigation.StartRepeat);
builder.addNavigation(Score.Navigation.EndRepeat, 3);
builder.addNavigation(Score.Navigation.Ending, 1, 2);
navigation
can be:
Score.Navigation.DC_al_Fine
Score.Navigation.DC_al_Coda
Score.Navigation.DS_al_Fine
Score.Navigation.DS_al_Coda
Score.Navigation.Coda
Score.Navigation.toCoda
Score.Navigation.Segno
Score.Navigation.Fine
Score.Navigation.StartRepeat
Score.Navigation.EndRepeat
Score.Navigation.Ending
Score.Navigation.EndRepeat
takes optional second arg which is number of times to repeat (once if omitted).
Score.Navigation.Ending
takes variable number of number args, each is a passage number.
Add text label anchored to previously added note, chord or rest.
builder.addLabel(label: Score.Label, text: string);
// Example
builder.addLabel(Score.Label.Chord, "Am);
label
can be:
Score.Label.Note
: Used to label notes and is positioned below note.Score.Label.Chord
: Used to label chords and is positioned on top.Add annotation text anchored to previously added note, chord or rest.
builder.addAnnotation(annotation: Score.Annotation, text: string);
// Example
builder.addAnnotation(Score.Annotation.Tempo, "accel.");
annotation
can be:
Score.Annotation.Dynamics
: text
could be for example "fff"
, "cresc."
, "dim."
, etc.Score.Annotation.Tempo
: text
could be for example "accel."
, "rit."
, "a tempo"
, etc.There are alternatives to these functions:
addFermata
=> addFermataTo
addNavigation
=> addNavigationTo
addAnnotation
=> addAnnotationTo
addLabel
=> addLabelTo
.First argument of these alterate functions is:
staffTabOrGroups: Score.StaffTabOrGroups
.
StaffTabOrGroups
can be:
number
: staff/tab index, 0=top staff/tab, etc.string
: staff/tab name.string
: staff group name.(number | string)[]
: an array of staff/tab indices, names or group names.// Example: add label to top staff/tab.
builder.addLabelTo(0, Score.Label.Chord, "Am");
builder.addStaffGroup(groupName: string, staffsTabsAndGroups: number | string | (number | string)[], verticalPosition: Score.VerticalPosition);
Arguments are:
groupName
: Name of new staff group.staffsTabsAndGroups
: single value or an array of staves, tabs and groups (index or name).verticalPosition
(optional): Can be Score.VerticalPosition.Above
/Below
/Both
/Auto
(default).// Example: create staff group to add elements below top staff/tab.
// Add staff group
builder.addStaffGroup("grp1", [0], Score.VertocalPosition.Below);
// Use group
builder.addLabelTo("grp1", Score.Label.Note, "C");
Adds extension line to element, for example to previously added annotation.
builder.addExtension(extensionLength: number, visible?: boolean);
// Example
builder.addAnnotation(Score.Annotation.Tempo, "accel.").addExtension(Theory.NoteLength.Whole * 2, true);
extensionLength
is number
but Theory.NoteLength
values can be used as number and multiplied to set desired extension length.
visible
sets visibility of extension line, visible by default (if omitted).
// Add tie
builder.addConnective(connective: Score.Connetive.Tie, span?: Score.ConnectiveSpan, noteAnchor?: Score.NoteAnchor);
// Add slur
builder.addConnective(connective: Score.Connetive.Slur, span?: Score.ConnectiveSpan, noteAnchor?: Score.NoteAnchor);
// Add slide
builder.addConnective(connective: Score.Connetive.Slide, noteAnchor?: Score.NoteAnchor);
span
describes how many notes the connective is across.
It is integer >= 2 (for tie it can be also Score.TieType.Stub|ToMeasureEnd
).
Default value is 2.noteAnchor
describes the attach point of connective to note.
It can be Score.NoteAnchor.Auto|Above|Center|Below|StemTip
.
Default value is Score.NoteAnchor.Auto
.This library has preliminary guitar tabs rendering.
Create document with Score.StaffPreset.GuitarTab
or Score.StaffPreset.GuitarCombined
, or set score configuration with TabConfig.
Add notes with { string: number | number[] }
to specify which string the fret number is rendered in guitar tab.
// Single note
builder.addNote(0, "G3", Theory.NoteLength.Eighth, { string: 3 });
// Multi note
builder.addChord(0, ["E4", "C3"], Theory.NoteLength.Eighth, { string: [1, 5] });
DocumentBuilder
operations can be queued.
let doc = new Score.DocumentBuilder()
.addScoreConfiguration({ type: "staff", clef: Score.Clef.G, isOctavewDown: true })
.setMeasuresPerRow(4)
.addMeasure()
.addNote(1, "C3", Theory.NoteLength.Quarter)
.addChord(1, ["C3", "E3", "G3"], Theory.NoteLength.Quarter).addLabel(Score.Label.Chord, "C")
.addRest(1, Theory.NoteLength.Quarter)
// etc.
.getDEocument();
Beams are detected and added automatically.
Default instrument is Synthesizer
.
Classical Guitar
is available via audio-cg
module.
It was included as separate module because it contains over 1MB of audio samples bundled in it.
import { registerClassicalGuitar } from "@tspro/web-music-score/audio-cg";
registerClassicalGuitar();
// Simple play
doc.play();
// More playback options:
let player = new MPlayer(doc);
player.play();
player.pause();
player.stop();
MPlayer.stopAll();
// Draw document
<ScoreUI.MusicScoreView doc={doc} />
// Add playback buttons
<ScoreUI.PlaybackButtons doc={doc} buttonLayout={ScoreUI.PlaybackButtonsLayout.PlayStopSingle}/> // Single Play/Stopo button
<ScoreUI.PlaybackButtons doc={doc} buttonLayout={ScoreUI.PlaybackButtonsLayout.PlayStop}/> // Play and Stop buttons
<ScoreUI.PlaybackButtons doc={doc} buttonLayout={ScoreUI.PlaybackButtonsLayout.PlayPauseStop}/> // Play, Pause and Stop buttons
Bootstrap is used for better visual appearance, but it needs to be installed and loaded.
<!-- Add canvas -->
<canvas id="canvasId"></canvas>
<!-- Add play button -->
<button id="playButtonId"></button>
<!-- Add pause button -->
<button id="pauseButtonId"></button>
<!-- Add stop button -->
<button id="stopButtonId"></button>
<!-- Or add combined play/stop button -->
<button id="playStopButtonId"></button>
// Draw document
let r = new Score.MRenderer().
setCanvas("canvasId").
setDocument(doc).
draw();
// Add playback buttons
let p = new Score.MPlaybackButtons().
setPlayButton("playButtonId").
setPauseButton("pauseButtonId").
setStopButton("stopButtonId").
setDocument(doc);
// You can also set combined play/stop button.
p.setPlayStopButton("playStopButtonId")
// You can also pass HTMLButtonElement instead of element id.
p.setPlayButton(playButtonElement)
try {
// Do your music stuff
}
catch (e) {
if(e instanceof Core.MusicError) {
// There was music error.
}
}
While designed for compatibility in mind, the library has not been explicitly tested against specific Node.js or browser versions.
Found a bug or unexpected behavior?
You can also suggest a feature or impovement.
Thanks for helping improve the project!
This project is licensed under the MIT License.
It also bundles the Tone.js library, which is licensed under the MIT License.