music21j-port
Version:
A toolkit for computer-aided musicology, Javascript version
1,306 lines (1,121 loc) • 39.4 kB
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Music21j Source: music21/note.js</title>
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link type="text/css" rel="stylesheet" href="styles/sunlight.default.css">
<link type="text/css" rel="stylesheet" href="styles/site.spruce.css">
</head>
<body>
<div class="container-fluid">
<div class="navbar navbar-fixed-top navbar-inverse">
<div class="navbar-inner">
<a class="brand" href="index.html">Music21j</a>
<ul class="nav">
<li class="dropdown">
<a href="namespaces.list.html" class="dropdown-toggle" data-toggle="dropdown">Namespaces<b
class="caret"></b></a>
<ul class="dropdown-menu ">
<li>
<a href="music21.html">music21</a>
</li>
<li>
<a href="music21.articulations.html">music21.articulations</a>
</li>
<li>
<a href="music21.audioSearch.html">music21.audioSearch</a>
</li>
<li>
<a href="music21.base.html">music21.base</a>
</li>
<li>
<a href="music21.beam.html">music21.beam</a>
</li>
<li>
<a href="music21.chord.html">music21.chord</a>
</li>
<li>
<a href="music21.clef.html">music21.clef</a>
</li>
<li>
<a href="music21.common.html">music21.common</a>
</li>
<li>
<a href="music21.duration.html">music21.duration</a>
</li>
<li>
<a href="music21.dynamics.html">music21.dynamics</a>
</li>
<li>
<a href="music21.expressions.html">music21.expressions</a>
</li>
<li>
<a href="music21.fromPython.html">music21.fromPython</a>
</li>
<li>
<a href="music21.instrument.html">music21.instrument</a>
</li>
<li>
<a href="music21.interval.html">music21.interval</a>
</li>
<li>
<a href="music21.key.html">music21.key</a>
</li>
<li>
<a href="music21.keyboard.html">music21.keyboard</a>
</li>
<li>
<a href="music21.meter.html">music21.meter</a>
</li>
<li>
<a href="music21.miditools.html">music21.miditools</a>
</li>
<li>
<a href="music21.note.html">music21.note</a>
</li>
<li>
<a href="music21.pitch.html">music21.pitch</a>
</li>
<li>
<a href="music21.prebase.html">music21.prebase</a>
</li>
<li>
<a href="music21.renderOptions.html">music21.renderOptions</a>
</li>
<li>
<a href="music21.roman.html">music21.roman</a>
</li>
<li>
<a href="music21.scale.html">music21.scale</a>
</li>
<li>
<a href="music21.sites.html">music21.sites</a>
</li>
<li>
<a href="music21.stream.html">music21.stream</a>
</li>
<li>
<a href="music21.tempo.html">music21.tempo</a>
</li>
<li>
<a href="music21.tie.html">music21.tie</a>
</li>
<li>
<a href="music21.tinyNotation.html">music21.tinyNotation</a>
</li>
<li>
<a href="music21.vfShow.html">music21.vfShow</a>
</li>
<li>
<a href="music21.webmidi.html">music21.webmidi</a>
</li>
</ul>
</li>
<li class="dropdown">
<a href="classes.list.html" class="dropdown-toggle" data-toggle="dropdown">Classes<b
class="caret"></b></a>
<ul class="dropdown-menu ">
<li>
<a href="music21.articulations.Accent.html">music21.articulations.Accent</a>
</li>
<li>
<a href="music21.articulations.Articulation.html">music21.articulations.Articulation</a>
</li>
<li>
<a href="music21.articulations.DynamicArticulation.html">music21.articulations.DynamicArticulation</a>
</li>
<li>
<a href="music21.articulations.LengthArticulation.html">music21.articulations.LengthArticulation</a>
</li>
<li>
<a href="music21.articulations.Marcato.html">music21.articulations.Marcato</a>
</li>
<li>
<a href="music21.articulations.PitchArticulation.html">music21.articulations.PitchArticulation</a>
</li>
<li>
<a href="music21.articulations.Spiccato.html">music21.articulations.Spiccato</a>
</li>
<li>
<a href="music21.articulations.Staccatissimo.html">music21.articulations.Staccatissimo</a>
</li>
<li>
<a href="music21.articulations.Staccato.html">music21.articulations.Staccato</a>
</li>
<li>
<a href="music21.articulations.StrongAccent.html">music21.articulations.StrongAccent</a>
</li>
<li>
<a href="music21.articulations.Tenuto.html">music21.articulations.Tenuto</a>
</li>
<li>
<a href="music21.articulations.TimbreArticulation.html">music21.articulations.TimbreArticulation</a>
</li>
<li>
<a href="music21.base.Music21Object.html">music21.base.Music21Object</a>
</li>
<li>
<a href="music21.beam.Beam.html">music21.beam.Beam</a>
</li>
<li>
<a href="music21.beam.Beams.html">music21.beam.Beams</a>
</li>
<li>
<a href="music21.chord.Chord.html">music21.chord.Chord</a>
</li>
<li>
<a href="music21.clef.AltoClef.html">music21.clef.AltoClef</a>
</li>
<li>
<a href="music21.clef.BassClef.html">music21.clef.BassClef</a>
</li>
<li>
<a href="music21.clef.Clef.html">music21.clef.Clef</a>
</li>
<li>
<a href="music21.clef.MezzoSopranoClef.html">music21.clef.MezzoSopranoClef</a>
</li>
<li>
<a href="music21.clef.PercussionClef.html">music21.clef.PercussionClef</a>
</li>
<li>
<a href="music21.clef.SopranoClef.html">music21.clef.SopranoClef</a>
</li>
<li>
<a href="music21.clef.TenorClef.html">music21.clef.TenorClef</a>
</li>
<li>
<a href="music21.clef.Treble8vaClef.html">music21.clef.Treble8vaClef</a>
</li>
<li>
<a href="music21.clef.Treble8vbClef.html">music21.clef.Treble8vbClef</a>
</li>
<li>
<a href="music21.clef.TrebleClef.html">music21.clef.TrebleClef</a>
</li>
<li>
<a href="music21.duration.Duration.html">music21.duration.Duration</a>
</li>
<li>
<a href="music21.duration.Tuplet.html">music21.duration.Tuplet</a>
</li>
<li>
<a href="music21.dynamics.Dynamic.html">music21.dynamics.Dynamic</a>
</li>
<li>
<a href="music21.expressions.Expression.html">music21.expressions.Expression</a>
</li>
<li>
<a href="music21.expressions.Fermata.html">music21.expressions.Fermata</a>
</li>
<li>
<a href="music21.fromPython.Converter.html">music21.fromPython.Converter</a>
</li>
<li>
<a href="music21.instrument.Instrument.html">music21.instrument.Instrument</a>
</li>
<li>
<a href="music21.interval.ChromaticInterval.html">music21.interval.ChromaticInterval</a>
</li>
<li>
<a href="music21.interval.DiatonicInterval.html">music21.interval.DiatonicInterval</a>
</li>
<li>
<a href="music21.interval.GenericInterval.html">music21.interval.GenericInterval</a>
</li>
<li>
<a href="music21.interval.Interval.html">music21.interval.Interval</a>
</li>
<li>
<a href="music21.key.Key.html">music21.key.Key</a>
</li>
<li>
<a href="music21.key.KeySignature.html">music21.key.KeySignature</a>
</li>
<li>
<a href="music21.keyboard.BlackKey.html">music21.keyboard.BlackKey</a>
</li>
<li>
<a href="music21.keyboard.Key.html">music21.keyboard.Key</a>
</li>
<li>
<a href="music21.keyboard.Keyboard.html">music21.keyboard.Keyboard</a>
</li>
<li>
<a href="music21.keyboard.WhiteKey.html">music21.keyboard.WhiteKey</a>
</li>
<li>
<a href="music21.meter.TimeSignature.html">music21.meter.TimeSignature</a>
</li>
<li>
<a href="music21.miditools.Event.html">music21.miditools.Event</a>
</li>
<li>
<a href="music21.miditools.MidiPlayer.html">music21.miditools.MidiPlayer</a>
</li>
<li>
<a href="music21.note.GeneralNote.html">music21.note.GeneralNote</a>
</li>
<li>
<a href="music21.note.Lyric.html">music21.note.Lyric</a>
</li>
<li>
<a href="music21.note.Note.html">music21.note.Note</a>
</li>
<li>
<a href="music21.note.NotRest.html">music21.note.NotRest</a>
</li>
<li>
<a href="music21.note.Rest.html">music21.note.Rest</a>
</li>
<li>
<a href="music21.pitch.Accidental.html">music21.pitch.Accidental</a>
</li>
<li>
<a href="music21.pitch.Pitch.html">music21.pitch.Pitch</a>
</li>
<li>
<a href="music21.prebase.ProtoM21Object.html">music21.prebase.ProtoM21Object</a>
</li>
<li>
<a href="music21.renderOptions.RenderOptions.html">music21.renderOptions.RenderOptions</a>
</li>
<li>
<a href="music21.roman.RomanNumeral.html">music21.roman.RomanNumeral</a>
</li>
<li>
<a href="music21.stream.Measure.html">music21.stream.Measure</a>
</li>
<li>
<a href="music21.stream.Part.html">music21.stream.Part</a>
</li>
<li>
<a href="music21.stream.Score.html">music21.stream.Score</a>
</li>
<li>
<a href="music21.stream.Stream.html">music21.stream.Stream</a>
</li>
<li>
<a href="music21.stream.Voice.html">music21.stream.Voice</a>
</li>
<li>
<a href="music21.tempo.Metronome.html">music21.tempo.Metronome</a>
</li>
<li>
<a href="music21.tie.Tie.html">music21.tie.Tie</a>
</li>
<li>
<a href="music21.vfShow.Renderer.html">music21.vfShow.Renderer</a>
</li>
<li>
<a href="music21.vfShow.RenderStack.html">music21.vfShow.RenderStack</a>
</li>
<li>
<a href="Notation.html">Notation</a>
</li>
<li>
<a href="Page.html">Page</a>
</li>
<li>
<a href="Recorder.html">Recorder</a>
</li>
</ul>
</li>
<li class="dropdown">
<a href="global.html" class="dropdown-toggle" data-toggle="dropdown">Global<b
class="caret"></b></a>
<ul class="dropdown-menu ">
<li>
<a href="global.html#getM21attribute">getM21attribute</a>
</li>
<li>
<a href="global.html#layout">layout</a>
</li>
<li>
<a href="global.html#midiNumDiffFromFrequency">midiNumDiffFromFrequency</a>
</li>
<li>
<a href="global.html#recorderWorkerJs">recorderWorkerJs</a>
</li>
<li>
<a href="global.html#unpickler">unpickler</a>
</li>
<li>
<a href="global.html#warnBanner">warnBanner</a>
</li>
</ul>
</li>
</ul>
</div>
</div>
<div class="row-fluid">
<div class="span12">
<div id="main">
<h1 class="page-title">Source: music21/note.js</h1>
<section>
<article>
<pre
class="sunlight-highlight-javascript linenums">/**
* music21j -- Javascript reimplementation of Core music21p features.
* music21/note -- Note, Rest, NotRest, GeneralNote
*
* Copyright (c) 2013-17, Michael Scott Cuthbert and cuthbertLab
* Based on music21 (music21p), Copyright (c) 2006–17, Michael Scott Cuthbert and cuthbertLab
*
*/
import * as MIDI from 'MIDI';
import * as Vex from 'vexflow';
import { prebase } from './prebase.js';
import { base } from './base.js';
import { debug } from './debug.js';
import { pitch } from './pitch.js';
import { beam } from './beam.js';
import { common } from './common.js';
/**
* Module for note classes. See the namespace {@link music21.note}
*
* @requires music21/common
* @requires music21/prebase
* @requires music21/base
* @requires music21/pitch
* @requires music21/beam
* @exports music21/note
*/
/**
* Namespace for notes (single pitch) or rests, and some things like Lyrics that go on notes.
*
* @namespace music21.note
* @memberof music21
* @property {Array} noteheadTypeNames - an Array of allowable notehead names.
* @property {Array} stemDirectionNames - an Array of allowable stemDirection names.
*/
export const note = {};
note.noteheadTypeNames = [
'arrow down',
'arrow up',
'back slashed',
'circle dot',
'circle-x',
'circled',
'cluster',
'cross',
'diamond',
'do',
'fa',
'inverted triangle',
'la',
'left triangle',
'mi',
'none',
'normal',
'other',
're',
'rectangle',
'slash',
'slashed',
'so',
'square',
'ti',
'triangle',
'x',
];
note.stemDirectionNames = [
'double',
'down',
'noStem',
'none',
'unspecified',
'up',
];
/**
* Class for a single Lyric attached to a {@link music21.note.GeneralNote}
*
* @class Lyric
* @memberOf music21.note
* @extends music21.prebase.ProtoM21Object
* @param {string} text - the text of the lyric
* @param {number} number=1 - the lyric number
* @param {string} syllabic=undefined - placement of the syllable ('begin', 'middle', 'end', 'single'); undefined = interpret from text
* @param {boolean} applyRaw=false - true = display the text exactly as it is or, false = use "-" etc. to determine syllabic
* @param {string} identifier=undefined - identifier for the lyric.
* @property {string} lyricConnector='-' - what to place between two lyrics that are syllabic.
* @property {string} text - the text of the lyric syllable.
* @property {string} syllabic - see above
* @property {boolean} applyRaw - see above
* @property {string} identifier - see above; gets .number if undefined
* @property {number} number - see above
* @property {string} rawText - text + any connectors
*/
export class Lyric extends prebase.ProtoM21Object {
constructor(text, number = 1, syllabic, applyRaw, identifier) {
super();
this.lyricConnector = '-'; // override to place something else between two notes...
this.text = text;
this._number = number;
this.syllabic = syllabic;
this.applyRaw = applyRaw || false;
this.setTextAndSyllabic(this.text, this.applyRaw);
this._identifier = identifier;
this.style = {
fillStyle: 'black',
strokeStyle: 'black',
fontFamily: 'Serif',
fontSize: 12,
fontWeight: '',
};
}
get identifier() {
return this._identifier || this._number;
}
set identifier(i) {
this._identifier = i;
}
// a property just to match m21p
get number() {
return this._number;
}
set number(n) {
this._number = n;
}
/**
* get rawText - gets the raw text.
*
* @return {string} raw text
*/
get rawText() {
if (this.syllabic === 'begin') {
return this.text + this.lyricConnector;
} else if (this.syllabic === 'middle') {
return this.lyricConnector + this.text + this.lyricConnector;
} else if (this.syllabic === 'end') {
return this.lyricConnector + this.text;
} else {
return this.text;
}
}
set rawText(t) {
this.setTextAndSyllabic(t, true);
}
/**
* setTextAndSyllabic - Given a setting for rawText and applyRaw,
* sets the syllabic type for a lyric based on the rawText
*
* @param {string} rawText text
* @param {boolean} applyRaw = false if hyphens should not be applied
* @return {undefined}
*/
setTextAndSyllabic(rawText, applyRaw = false) {
if (rawText === undefined) {
this.text = undefined;
return this;
}
if (
!applyRaw
&& rawText.indexOf(this.lyricConnector) === 0
&& rawText.slice(-1) === this.lyricConnector
) {
this.text = rawText.slice(1, -1);
this.syllabic = 'middle';
} else if (!applyRaw && rawText.indexOf(this.lyricConnector) === 0) {
this.text = rawText.slice(1);
this.syllabic = 'end';
} else if (!applyRaw && rawText.slice(-1) === this.lyricConnector) {
this.text = rawText.slice(0, -1);
this.syllabic = 'begin';
} else {
this.text = rawText;
if (this.syllabic === undefined) {
this.syllabic = 'single';
}
}
return this;
}
}
note.Lyric = Lyric;
/* Notes and rests etc... */
/**
* Superclass for all Note values
*
* @class GeneralNote
* @memberof music21.note
* @extends music21.base.Music21Object
* @param {(number|undefined)} [ql=1.0] - quarterLength of the note
* @property {boolean} [isChord=false] - is this a chord
* @property {number} quarterLength - shortcut to `.duration.quarterLength`
* @property {Object} activeVexflowNote - most recent Vex.Flow.StaveNote object to be made from this note (could change); default, undefined
* @property {Array<music21.expressions.Expression>} expressions - array of attached expressions
* @property {Array<music21.articulations.Articulation>} articulations - array of attached articulations
* @property {string} lyric - the text of the first {@link music21.note.Lyric} object; can also set one.
* @property {Array<music21.note.Lyric>} lyrics - array of attached lyrics
* @property {number} [volume=60] - how loud is this note, 0-127, before articulations
* @property {number} midiVolume - how loud is this note, taking into account articulations
* @property {music21.note.Tie|undefined} [tie=undefined] - a tie object
*/
export class GeneralNote extends base.Music21Object {
constructor(ql) {
super();
this.isChord = false;
if (ql !== undefined) {
this.duration.quarterLength = ql;
} else {
this.duration.quarterLength = 1.0;
}
this.volume = 60;
this.activeVexflowNote = undefined;
this.expressions = [];
this.articulations = [];
this.lyrics = [];
this.tie = undefined;
/* TODO: editorial objects, color, addLyric, insertLyric, hasLyrics */
/* Later: augmentOrDiminish, getGrace, */
}
get lyric() {
if (this.lyrics.length > 0) {
return this.lyrics[0].text;
} else {
return undefined;
}
}
set lyric(value) {
this.lyrics = [];
if (value !== undefined && value !== false) {
this.lyrics.push(new note.Lyric(value));
}
}
get midiVolume() {
let volume = this.volume;
if (volume === undefined) {
volume = 60;
}
if (this.articulations !== undefined) {
this.articulations.forEach(a => {
volume *= a.dynamicScale;
if (volume > 127) {
volume = 127;
} else if (isNaN(volume)) {
volume = 60;
}
});
}
volume = Math.floor(volume);
return volume;
}
/**
* Add a {@link music21.note.Lyric} object to the Note
*
* @memberof music21.note.GeneralNote
* @param {string} text - text to be added
* @param {number} [lyricNumber] - integer specifying lyric (defaults to the current `.lyrics.length` + 1)
* @param {boolean} [applyRaw=false] - if `true`, do not parse the text for cluses about syllable placement.
* @param {string} [lyricIdentifier] - an optional identifier
*/
addLyric(text, lyricNumber, applyRaw = false, lyricIdentifier) {
if (lyricNumber === undefined) {
const maxLyrics = this.lyrics.length + 1;
const newLyric = new note.Lyric(
text,
maxLyrics,
undefined,
applyRaw,
lyricIdentifier
);
this.lyrics.push(newLyric);
} else {
let foundLyric = false;
for (let i = 0; i < this.lyrics.length; i++) {
const thisLyric = this.lyrics[i];
if (thisLyric.number === lyricNumber) {
thisLyric.text = text;
foundLyric = true;
break;
}
}
if (foundLyric === false) {
const newLyric = new note.Lyric(
text,
lyricNumber,
undefined,
applyRaw,
lyricIdentifier
);
this.lyrics.push(newLyric);
}
}
}
/**
* Change stem direction according to clef. Does nothing for GeneralNote; overridden in subclasses.
*
* @memberof music21.note.GeneralNote
* @param {music21.clef.Clef} [clef] - clef to set the stem direction of.
* @returns {undefined}
*/
setStemDirectionFromClef(clef) {
return undefined;
}
/**
* Sets the vexflow accidentals (if any), the dots, and the stem direction
*
* @memberof music21.note.GeneralNote
* @param {Vex.Flow.StaveNote} vfn - a Vex.Flow note
* @param {object
*/
vexflowAccidentalsAndDisplay(vfn, options) {
if (this.duration.dots > 0) {
for (let i = 0; i < this.duration.dots; i++) {
vfn.addDotToAll();
}
}
if (debug) {
console.log(this.stemDirection);
}
if (this.stemDirection === 'noStem') {
vfn.hasStem = () => false; // need to override...
// vfn.render_options.stem_height = 0;
} else {
// correct VexFlow stem length for notes far from the center line;
let staveDNNSpacing = 5;
if (options.stave) {
staveDNNSpacing = Math.floor(
options.stave.options.spacing_between_lines_px / 2
);
}
if (options.clef !== undefined && this.pitch !== undefined) {
const midLine = options.clef.lowestLine + 4;
// console.log(midLine);
const absDNNfromCenter = Math.abs(
this.pitch.diatonicNoteNum - midLine
);
const absOverOctave = absDNNfromCenter - 7;
// console.log(absOverOctave);
if (absOverOctave > 0 && vfn.getStemLength !== undefined) {
const stemHeight
= absOverOctave * staveDNNSpacing + vfn.getStemLength();
vfn.setStemLength(stemHeight);
}
}
}
}
/**
* Play the current element as a MIDI note.
*
* @memberof music21.note.GeneralNote
* @param {number} [tempo=120] - tempo in bpm
* @param {(base.Music21Object)} [nextElement] - for determining the length to play in case of tied notes, etc.
* @param {Object} [options] - other options (currently just `{instrument: {@link music21.instrument.Instrument} }`)
* @returns {Number} - delay time in milliseconds until the next element (may be ignored)
*/
playMidi(tempo = 120, nextElement, options) {
// returns the number of milliseconds to the next element in
// case that can't be determined otherwise.
if (options === undefined) {
let inst;
if (this.activeSite !== undefined) {
inst = this.activeSite.instrument;
}
options = { instrument: inst };
}
const volume = this.midiVolume;
let channel = 0;
if (options !== undefined && options.instrument !== undefined) {
channel = options.instrument.midiChannel;
}
let milliseconds = 60 * 1000 / tempo;
const ql = this.duration.quarterLength;
milliseconds = 60 * ql * 1000 / tempo;
let midNum;
if (this.isClassOrSubclass('Note')) {
// Note, not rest
midNum = this.pitch.midi;
let stopTime = milliseconds / 1000;
if (
nextElement !== undefined
&& nextElement.isClassOrSubclass('Note')
) {
if (nextElement.pitch.midi !== this.pitch.midi) {
stopTime += 60 * 0.25 / tempo; // legato -- play 16th note longer
} else if (
this.tie !== undefined
&& (this.tie.type === 'start' || this.tie.type === 'continue')
) {
stopTime += 60 * nextElement.duration.quarterLength / tempo;
// this does not take into account 3 or more notes tied.
// TODO: look ahead at next nexts, etc.
}
} else if (nextElement === undefined) {
// let last note ring an extra beat...
stopTime += 60 * 1 / tempo;
}
// console.log(stopTime);
// console.log(this.tie);
if (this.tie === undefined || this.tie.type === 'start') {
// console.log(volume);
MIDI.noteOn(channel, midNum, volume, 0);
MIDI.noteOff(channel, midNum, stopTime);
} // else { console.log ('not going to play ', this.nameWithOctave); }
} else if (this.isClassOrSubclass('Chord')) {
// TODO: Tied Chords.
for (let j = 0; j < this._notes.length; j++) {
midNum = this._notes[j].pitch.midi;
MIDI.noteOn(channel, midNum, volume, 0);
MIDI.noteOff(channel, midNum, milliseconds / 1000);
}
} // it's a note.Rest -- do nothing -- milliseconds takes care of it...
return milliseconds;
}
}
note.GeneralNote = GeneralNote;
/**
* Specifies that a GeneralNote is not a rest (Unpitched, Note, Chord).
*
* @class NotRest
* @memberof music21.note
* @extends music21.note.GeneralNote
* @param {number} [ql=1.0] - length in quarter notes
* @property {music21.beam.Beams} beams - a link to a beam object
* @property {string} [notehead='normal'] - notehead type
* @property {string} [noteheadFill='default'] - notehead fill (to be moved to style...)
* @property {string|undefined} [noteheadColor=undefined] - notehead color
* @property {boolean} [noteheadParenthesis=false] - put a parenthesis around the notehead?
* @property {string|undefined} [stemDirection=undefined] - One of ['up','down','noStem', undefined] -- 'double' not supported
*/
export class NotRest extends GeneralNote {
constructor(ql) {
super(ql);
this.notehead = 'normal';
this.noteheadFill = 'default';
this.noteheadColor = 'black';
this.noteheadParenthesis = false;
this.volume = undefined; // not a real object yet.
this.beams = new beam.Beams();
/* TODO: this.duration.linkage -- need durationUnits */
this.stemDirection = undefined;
/* TODO: check stemDirection, notehead, noteheadFill, noteheadParentheses */
}
}
note.NotRest = NotRest;
/* ------- Note ----------- */
/**
* A very, very important class! music21.note.Note objects combine a {@link music21.pitch.Pitch}
* object to describe pitch (highness/lowness) with a {@link music21.duration.Duration} object
* that defines length, with additional features for drawing the Note, playing it back, etc.
*
* Together with {@link music21.stream.Stream} one of the two most important
* classes in `music21`.
*
* See {@link music21.note.NotRest}, {@link music21.note.GeneralNote}, {@link music21.base.Music21Object}
* and {@link music21.prebase.ProtoM21Object} (or in general, the **extends** list below) for other
* things you can do with a `Note` object.
*
* Missing from music21p: `microtone, pitchClass, pitchClassString, transpose(), fullName`.
*
* @class Note
* @memberof music21.note
* @extends music21.note.NotRest
* @param {(string|music21.pitch.Pitch|undefined)} [nn='C4'] - pitch name ("C", "D#", "E-") w/ or w/o octave ("C#4"), or a pitch.Pitch object
* @param {(number|undefined)} [ql=1.0] - length in quarter notes
* @property {Boolean} [isNote=true] - is it a Note? Yes!
* @property {Boolean} [isRest=false] - is it a Rest? No!
* @property {music21.pitch.Pitch} pitch - the {@link music21.pitch.Pitch} associated with the Note.
* @property {string} name - shortcut to `.pitch.name`
* @property {string} nameWithOctave - shortcut to `.pitch.nameWithOctave`
* @property {string} step - shortcut to `.pitch.step`
* @property {number} octave - shortcut to `.pitch.octave`
*/
export class Note extends NotRest {
constructor(nn, ql) {
super(ql);
this.isNote = true; // for speed
this.isRest = false; // for speed
if (
nn !== undefined
&& nn.isClassOrSubclass !== undefined
&& nn.isClassOrSubclass('Pitch') === true
) {
this.pitch = nn;
} else {
this.pitch = new pitch.Pitch(nn);
}
}
get name() {
return this.pitch.name;
}
set name(nn) {
this.pitch.name = nn;
}
get nameWithOctave() {
return this.pitch.nameWithOctave;
}
set nameWithOctave(nn) {
this.pitch.nameWithOctave = nn;
}
get step() {
return this.pitch.step;
}
set step(nn) {
this.pitch.step = nn;
}
// no Frequency
get octave() {
return this.pitch.octave;
}
set octave(nn) {
this.pitch.octave = nn;
}
/* TODO: transpose, fullName, microtone, pitchclass, pitchClassString */
/**
* Change stem direction according to clef.
*
* @memberof music21.note.Note
* @param {music21.clef.Clef} [clef] - clef to set the stem direction of.
* @returns {music21.note.Note} Original object, for chaining methods
*/
setStemDirectionFromClef(clef) {
if (clef === undefined) {
return this;
} else {
const midLine = clef.lowestLine + 4;
const DNNfromCenter = this.pitch.diatonicNoteNum - midLine;
// console.log(DNNfromCenter, this.pitch.nameWithOctave);
if (DNNfromCenter >= 0) {
this.stemDirection = 'down';
} else {
this.stemDirection = 'up';
}
return this;
}
}
/**
* Returns a `Vex.Flow.StaveNote` that approximates this note.
*
* @memberof music21.note.Note
* @param {Object} [options={}] - `{clef: {@link music21.clef.Clef} }`
* clef to set the stem direction of.
* @returns {Vex.Flow.StaveNote}
*/
vexflowNote(options) {
const params = {};
common.merge(params, options);
const clef = params.clef;
// fixup stem direction -- must happen before Vex.Flow.Note is created...
if (
this.activeSite !== undefined
&& this.activeSite.renderOptions.stemDirection !== undefined
&& note.stemDirectionNames.includes(
this.activeSite.renderOptions.stemDirection
)
) {
this.stemDirection = this.activeSite.renderOptions.stemDirection;
} else if (
this.stemDirection === undefined
&& options.clef !== undefined
) {
this.setStemDirectionFromClef(options.clef);
}
if (this.duration === undefined) {
// console.log(this);
return undefined;
}
const vfd = this.duration.vexflowDuration;
if (vfd === undefined) {
return undefined;
}
const vexflowKey = this.pitch.vexflowName(clef);
const vfnStemDirection
= this.stemDirection === 'down'
? Vex.Flow.StaveNote.STEM_DOWN
: Vex.Flow.StaveNote.STEM_UP;
// const vfnStemDirection = -1;
const vfn = new Vex.Flow.StaveNote({
keys: [vexflowKey],
duration: vfd,
stem_direction: vfnStemDirection,
});
this.vexflowAccidentalsAndDisplay(vfn, params); // clean up stuff...
if (this.pitch.accidental !== undefined) {
if (
this.pitch.accidental.vexflowModifier !== 'n'
&& this.pitch.accidental.displayStatus !== false
) {
vfn.addAccidental(
0,
new Vex.Flow.Accidental(
this.pitch.accidental.vexflowModifier
)
);
} else if (
this.pitch.accidental.displayType === 'always'
|| this.pitch.accidental.displayStatus === true
) {
vfn.addAccidental(
0,
new Vex.Flow.Accidental(
this.pitch.accidental.vexflowModifier
)
);
}
}
if (this.articulations[0] !== undefined) {
for (let i = 0; i < this.articulations.length; i++) {
const art = this.articulations[i];
// 0 refers to the first pitch (for chords etc.)...
vfn.addArticulation(0, art.vexflow());
}
}
if (this.expressions[0] !== undefined) {
for (let j = 0; j < this.expressions.length; j++) {
const exp = this.expressions[j];
// 0 refers to the first pitch (for chords etc.)...
vfn.addArticulation(0, exp.vexflow());
}
}
if (this.noteheadColor !== undefined) {
vfn.setStyle({ fillStyle: this.noteheadColor, strokeStyle: this.noteheadColor });
}
this.activeVexflowNote = vfn;
return vfn;
}
}
note.Note = Note;
/* ------ TODO: Unpitched ------ */
/* ------ Rest ------ */
/**
* Represents a musical rest.
*
* @class Rest
* @memberof music21.note
* @extends music21.note.GeneralNote
* @param {number} [ql=1.0] - length in number of quarterNotes
* @property {Boolean} [isNote=false]
* @property {Boolean} [isRest=true]
* @property {string} [name='rest']
* @property {number} [lineShift=undefined] - number of lines to shift up or down from default
* @property {string|undefined} [color='black'] - color of the rest
*/
export class Rest extends GeneralNote {
constructor(ql) {
super(ql);
this.isNote = false; // for speed
this.isRest = true; // for speed
this.name = 'rest'; // for note compatibility
this.lineShift = undefined;
this.color = 'black';
}
/**
* Returns a `Vex.Flow.StaveNote` that approximates this rest.
* Corrects for bug in VexFlow that renders a whole rest too low.
*
* @memberof music21.note.Rest
* @returns {Vex.Flow.StaveNote}
*/
vexflowNote(options) {
let keyLine = 'b/4';
if (this.duration.type === 'whole') {
if (
this.activeSite !== undefined
&& this.activeSite.renderOptions.staffLines !== 1
) {
keyLine = 'd/5';
}
}
if (this.lineShift !== undefined) {
const p = new pitch.Pitch('B4');
let ls = this.lineShift;
if (this.duration.type === 'whole') {
ls += 2;
}
p.diatonicNoteNum += ls;
keyLine = p.vexflowName(undefined);
}
const vfn = new Vex.Flow.StaveNote({
keys: [keyLine],
duration: this.duration.vexflowDuration + 'r',
});
if (this.duration.dots > 0) {
for (let i = 0; i < this.duration.dots; i++) {
vfn.addDotToAll();
}
}
if (this.color !== undefined) {
vfn.setStyle({ fillStyle: this.color, strokeStyle: this.color });
}
this.activeVexflowNote = vfn;
return vfn;
}
}
note.Rest = Rest;
/* ------ SpacerRest ------ */
</pre>
</article>
</section>
</div>
<div class="clearfix"></div>
<footer>
<span class="copyright">
Music21j, Copyright © 2013-2018 Michael Scott Cuthbert and cuthbertLab.
</span>
<br />
<span class="jsdoc-message">
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
on Wed Jul 4th 2018 using the <a
href="https://github.com/terryweiss/docstrap">DocStrap template</a>.
</span>
</footer>
</div>
<br clear="both">
</div>
</div>
<!--<script src="scripts/sunlight.js"></script>-->
<script src="scripts/docstrap.lib.js"></script>
<script src="scripts/bootstrap-dropdown.js"></script>
<script src="scripts/toc.js"></script>
<script>
$( function () {
$( "[id*='$']" ).each( function () {
var $this = $( this );
$this.attr( "id", $this.attr( "id" ).replace( "$", "__" ) );
} );
$( "#toc" ).toc( {
anchorName : function ( i, heading, prefix ) {
return $( heading ).attr( "id" ) || ( prefix + i );
},
selectors : "h1,h2,h3,h4",
showAndHide : false,
scrollTo : "100px"
} );
$( "#toc>ul" ).addClass( "nav nav-pills nav-stacked" );
$( "#main span[id^='toc']" ).addClass( "toc-shim" );
$( '.dropdown-toggle' ).dropdown();
// $( ".tutorial-section pre, .readme-section pre" ).addClass( "sunlight-highlight-javascript" ).addClass( "linenums" );
$( ".tutorial-section pre, .readme-section pre" ).each( function () {
var $this = $( this );
var example = $this.find( "code" );
exampleText = example.html();
var lang = /{ (.*?)}/.exec( exampleText );
if ( lang && lang[1] ) {
exampleText = exampleText.replace( lang[0], "" );
example.html( exampleText );
lang = lang[1];
} else {
lang = "javascript";
}
if ( lang ) {
$this
.addClass( "sunlight-highlight-" + lang )
.addClass( "linenums" )
.html( example.html() );
}
} );
Sunlight.highlightAll( {
lineNumbers : true,
showMenu : true,
enableDoclinks : true
} );
} );
</script>
<!--Navigation and Symbol Display-->
<!--Google Analytics-->
</body>
</html>