Skip to content

Commit

Permalink
music21 0.10.3 -- better articulations
Browse files Browse the repository at this point in the history
  • Loading branch information
Myke Cuthbert committed Mar 7, 2021
1 parent d71958e commit c3e5fcc
Show file tree
Hide file tree
Showing 7 changed files with 2,823 additions and 6,118 deletions.
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "music21j",
"version": "0.10.2",
"version": "0.10.3",
"description": "A toolkit for computer-aided musicology, Javascript version",
"main": "src/music21_modules.js",
"files": [
Expand Down
8,776 changes: 2,677 additions & 6,099 deletions releases/music21.debug.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion releases/music21.debug.js.map

Large diffs are not rendered by default.

69 changes: 61 additions & 8 deletions src/music21/articulations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,62 @@ import Vex from 'vexflow';
import * as common from './common';
import * as prebase from './prebase';

export enum ArticulationPlacement {
ABOVE = 'above',
BELOW = 'below',
LEFT = 'left',
RIGHT = 'right',
STEM_SIDE = 'stemSide',
NOTE_SIDE = 'noteSide',
}

export const ArticulationPlacementToVexFlowModifierPosition = new Map(
[
[ArticulationPlacement.ABOVE, Vex.Flow.Modifier.Position.ABOVE],
[ArticulationPlacement.BELOW, Vex.Flow.Modifier.Position.BELOW],
[ArticulationPlacement.LEFT, Vex.Flow.Modifier.Position.LEFT],
[ArticulationPlacement.RIGHT, Vex.Flow.Modifier.Position.RIGHT],
]
);

export interface VexflowArticulationParams {
stemDirection?: string;
}

/**
* This works the same for music21 Articulations and Expressions
*/
export function setPlacementOnVexFlowArticulation(
vfa: Vex.Flow.Articulation|Vex.Flow.Ornament,
placement: ArticulationPlacement,
stemDirection: string,
) {
if (placement === undefined) {
return;
}
if ((!stemDirection || stemDirection === 'none')
&& (placement === ArticulationPlacement.STEM_SIDE
|| placement === ArticulationPlacement.NOTE_SIDE)) {
placement = ArticulationPlacement.ABOVE;
}
if (placement === ArticulationPlacement.STEM_SIDE) {
if (stemDirection === 'up') {
placement = ArticulationPlacement.ABOVE;
} else {
placement = ArticulationPlacement.BELOW;
}
} else if (placement === ArticulationPlacement.NOTE_SIDE) {
if (stemDirection === 'up') {
placement = ArticulationPlacement.BELOW;
} else {
placement = ArticulationPlacement.ABOVE;
}
}
if (ArticulationPlacementToVexFlowModifierPosition.has(placement)) {
vfa.setPosition(ArticulationPlacementToVexFlowModifierPosition.get(placement));
}
}

/**
* Represents a single articulation, usually in the `.articulations` Array
* on a {@link music21.note.Note} or something like that.
Expand All @@ -28,9 +84,8 @@ export class Articulation extends prebase.ProtoM21Object {
static get className() { return 'music21.articulation.Articulation'; }

name: string;
placement: string = 'above';
placement: ArticulationPlacement = ArticulationPlacement.NOTE_SIDE;
vexflowModifier: string;
setPosition; // ?
dynamicScale: number = 1.0;
lengthScale: number = 1.0;

Expand All @@ -39,11 +94,9 @@ export class Articulation extends prebase.ProtoM21Object {
*
* @returns {Vex.Flow.Articulation}
*/
vexflow(): Vex.Flow.Articulation {
vexflow({stemDirection}: VexflowArticulationParams = {}): Vex.Flow.Articulation {
const vfa = new Vex.Flow.Articulation(this.vexflowModifier);
if (this.setPosition) {
vfa.setPosition(this.setPosition);
}
setPlacementOnVexFlowArticulation(vfa, this.placement, stemDirection);
return vfa;
}
}
Expand Down Expand Up @@ -194,8 +247,8 @@ export class Spiccato extends Staccato {
* @class Marcato
* @memberof music21.articulations
*
* is both a DynamicArticulation and a LengthArticulation
* TODO(msc): check that `.classes` reflects that
* should be both a DynamicArticulation and a LengthArticulation
* TODO(msc): check that `.classes` reflects that in music21j
*/
export class Marcato extends DynamicArticulation {
static get className() { return 'music21.articulation.Marcato'; }
Expand Down
86 changes: 80 additions & 6 deletions src/music21/expressions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@

import Vex from 'vexflow';
import * as base from './base';
import {
ArticulationPlacement,
setPlacementOnVexFlowArticulation,
VexflowArticulationParams,
} from './articulations';

/**
* Expressions can be note attached (`music21.note.Note.expressions[]`) or floating...
Expand All @@ -26,7 +31,7 @@ export class Expression extends base.Music21Object {

name: string = 'expression';
vexflowModifier: string = '';
setPosition: number = undefined;
placement: ArticulationPlacement = ArticulationPlacement.ABOVE;

/**
* Renders this Expression as a Vex.Flow.Articulation
Expand All @@ -35,11 +40,9 @@ export class Expression extends base.Music21Object {
*
* @returns {Vex.Flow.Articulation}
*/
vexflow() {
vexflow({stemDirection}: VexflowArticulationParams = {}): Vex.Flow.Articulation {
const vfe = new Vex.Flow.Articulation(this.vexflowModifier);
if (this.setPosition) {
vfe.setPosition(this.setPosition);
}
setPlacementOnVexFlowArticulation(vfe, this.placement, stemDirection);
return vfe;
}
}
Expand All @@ -58,6 +61,77 @@ export class Fermata extends Expression {
super();
this.name = 'fermata';
this.vexflowModifier = 'a@a';
this.setPosition = 3;
}
}


export class Ornament extends Expression {
static get className() { return 'music21.expressions.Ornament'; }

name: string = 'ornament';
vexflow({stemDirection}: VexflowArticulationParams = {}): Vex.Flow.Articulation {
const vfe = new Vex.Flow.Ornament(this.vexflowModifier);
setPlacementOnVexFlowArticulation(vfe, this.placement, stemDirection);
return vfe;
}
}


export class Trill extends Ornament {
static get className() { return 'music21.expressions.Trill'; }

constructor() {
super();
this.name = 'trill';
this.vexflowModifier = 'tr';
}
}

export class Turn extends Ornament {
static get className() { return 'music21.expressions.Turn'; }

constructor() {
super();
this.name = 'turn';
this.vexflowModifier = 'turn';
}
}

export class InvertedTurn extends Turn {
static get className() { return 'music21.expressions.InvertedTurn'; }

constructor() {
super();
this.name = 'invertedTurn';
this.vexflowModifier = 'turn_inverted';
}
}

export class GeneralMordent extends Ornament {
static get className() { return 'music21.expressions.GeneralMordent'; }
}


/**
* note that Vexflow's definition of mordent/inverted mordent is backwards
* from music theory. -- see music21p for more details.
*/
export class Mordent extends GeneralMordent {
static get className() { return 'music21.expressions.Mordent'; }

constructor() {
super();
this.name = 'mordent';
this.vexflowModifier = 'mordent_inverted';
}
}

export class InvertedMordent extends GeneralMordent {
static get className() { return 'music21.expressions.InvertedMordent'; }

constructor() {
super();
this.name = 'invertedMordent';
this.vexflowModifier = 'mordent';
}
}
4 changes: 2 additions & 2 deletions src/music21/note.ts
Original file line number Diff line number Diff line change
Expand Up @@ -509,10 +509,10 @@ export class NotRest extends GeneralNote {
}
}
for (const art of this.articulations) {
vfn.addArticulation(0, art.vexflow());
vfn.addArticulation(0, art.vexflow({stemDirection: useStemDirection}));
}
for (const exp of this.expressions) {
vfn.addArticulation(0, exp.vexflow());
vfn.addArticulation(0, exp.vexflow({stemDirection: useStemDirection}));
}
if (this.noteheadColor !== undefined) {
vfn.setStyle({ fillStyle: this.noteheadColor, strokeStyle: this.noteheadColor });
Expand Down

0 comments on commit c3e5fcc

Please sign in to comment.