Skip to content

Commit

Permalink
easyscore support for ghostnote
Browse files Browse the repository at this point in the history
  • Loading branch information
rvilarl committed Dec 24, 2021
1 parent da0ad7a commit c3b67d4
Show file tree
Hide file tree
Showing 13 changed files with 207 additions and 95 deletions.
5 changes: 2 additions & 3 deletions src/articulation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,9 @@ import { Glyph } from './glyph';
import { Modifier } from './modifier';
import { ModifierContextState } from './modifiercontext';
import { Note } from './note';
import { StaveNote } from './stavenote';
import { StemmableNote } from './stemmablenote';
import { Stave } from './stave';
import { Stem } from './stem';
import { StemmableNote } from './stemmablenote';
import { Tables } from './tables';
import { isGraceNote, isStaveNote, isTabNote } from './typeguard';
import { defined, log, RuntimeError } from './util';
Expand Down Expand Up @@ -267,7 +266,7 @@ export class Articulation extends Modifier {
return true;
}

static easyScoreHook({ articulations }: { articulations: string }, note: StaveNote, builder: Builder): void {
static easyScoreHook({ articulations }: { articulations: string }, note: StemmableNote, builder: Builder): void {
if (!articulations) return;

const articNameToCode: Record<string, string> = {
Expand Down
28 changes: 14 additions & 14 deletions src/beam.ts
Original file line number Diff line number Diff line change
Expand Up @@ -555,18 +555,20 @@ export class Beam extends Element {
// iterate through notes, calculating y shift and stem extension
for (let i = 1; i < notes.length; ++i) {
const note = notes[i];
const adjustedStemTipY =
this.getSlopeY(note.getStemX(), firstNote.getStemX(), firstNote.getStemExtents().topY, slope) + yShiftTemp;

const stemTipY = note.getStemExtents().topY;
// beam needs to be shifted up to accommodate note
if (stemTipY * stemDirection < adjustedStemTipY * stemDirection) {
const diff = Math.abs(stemTipY - adjustedStemTipY);
yShiftTemp += diff * -stemDirection;
totalStemExtension += diff * i;
} else {
// beam overshoots note, account for the difference
totalStemExtension += (stemTipY - adjustedStemTipY) * stemDirection;
if (note.hasStem() || note.isRest()) {
const adjustedStemTipY =
this.getSlopeY(note.getStemX(), firstNote.getStemX(), firstNote.getStemExtents().topY, slope) + yShiftTemp;

const stemTipY = note.getStemExtents().topY;
// beam needs to be shifted up to accommodate note
if (stemTipY * stemDirection < adjustedStemTipY * stemDirection) {
const diff = Math.abs(stemTipY - adjustedStemTipY);
yShiftTemp += diff * -stemDirection;
totalStemExtension += diff * i;
} else {
// beam overshoots note, account for the difference
totalStemExtension += (stemTipY - adjustedStemTipY) * stemDirection;
}
}
}

Expand Down Expand Up @@ -705,8 +707,6 @@ export class Beam extends Element {
const totalBeamWidth = (beam_count - 1) * beamWidth * 1.5 + beamWidth;
stem.setVisibility(true).setStemlet(true, totalBeamWidth + stemlet_extension);
}
} else {
throw new RuntimeError('NoStem', 'stem undefined.');
}
}
}
Expand Down
25 changes: 14 additions & 11 deletions src/easyscore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import { Music } from './music';
import { Note } from './note';
import { Grammar, Match, Parser, Result, Rule, RuleFunction } from './parser';
import { RenderContext } from './rendercontext';
import { StaveNote } from './stavenote';
import { Stem } from './stem';
import { StemmableNote } from './stemmablenote';
import { TupletOptions } from './tuplet';
import { defined, log, RuntimeError } from './util';
import { Voice } from './voice';
Expand All @@ -22,7 +22,7 @@ function L(...args: any[]): void {
}

// eslint-disable-next-line
export type CommitHook = (obj: any, note: StaveNote, builder: Builder) => void;
export type CommitHook = (obj: any, note: StemmableNote, builder: Builder) => void;

export class EasyScoreGrammar implements Grammar {
builder: Builder;
Expand Down Expand Up @@ -175,7 +175,7 @@ export class EasyScoreGrammar implements Grammar {
return { token: '[0-9whq]+' };
}
TYPES(): Rule {
return { token: '[rRsSmMhH]' };
return { token: '[rRsSmMhHgG]' };
}
LPAREN(): Rule {
return { token: '[(]' };
Expand Down Expand Up @@ -227,7 +227,7 @@ export class Piece {
}

export interface BuilderElements {
notes: StaveNote[];
notes: StemmableNote[];
accidentals: (Accidental | undefined)[][];
}

Expand Down Expand Up @@ -358,8 +358,11 @@ export class Builder {
);
const auto_stem = stem === 'auto'; // StaveNoteStruct expects the underscore & lowercase.

// Build a StaveNote using the information we gathered.
const note = factory.StaveNote({ keys, duration, dots, type, clef, auto_stem });
// Build a GhostNote or StaveNote using the information we gathered.
const note =
type?.toLowerCase() == 'g'
? factory.GhostNote({ duration, dots })
: factory.StaveNote({ keys, duration, dots, type, clef, auto_stem });
if (!auto_stem) note.setStemDirection(stem === 'up' ? Stem.UP : Stem.DOWN);

// Attach accidentals.
Expand Down Expand Up @@ -404,7 +407,7 @@ export interface EasyScoreDefaults extends Record<string, any> {
/**
* Commit hook used by EasyScore.setOptions().
*/
function setId(options: { id?: string }, note: StaveNote) {
function setId(options: { id?: string }, note: StemmableNote) {
if (options.id === undefined) return;
note.setAttribute('id', options.id);
}
Expand All @@ -415,7 +418,7 @@ const commaSeparatedRegex = /\s*,\s*/;
/**
* Commit hook used by EasyScore.setOptions().
*/
function setClass(options: { class?: string }, note: StaveNote) {
function setClass(options: { class?: string }, note: StemmableNote) {
if (options.class === undefined) return;
options.class.split(commaSeparatedRegex).forEach((className: string) => note.addClass(className));
}
Expand Down Expand Up @@ -497,17 +500,17 @@ export class EasyScore {
return result;
}

beam(notes: StaveNote[], options?: { autoStem?: boolean; secondaryBeamBreaks?: number[] }): StaveNote[] {
beam(notes: StemmableNote[], options?: { autoStem?: boolean; secondaryBeamBreaks?: number[] }): StemmableNote[] {
this.factory.Beam({ notes, options });
return notes;
}

tuplet(notes: StaveNote[], options?: TupletOptions): StaveNote[] {
tuplet(notes: StemmableNote[], options?: TupletOptions): StemmableNote[] {
this.factory.Tuplet({ notes, options });
return notes;
}

notes(line: string, options: BuilderOptions = {}): StaveNote[] {
notes(line: string, options: BuilderOptions = {}): StemmableNote[] {
options = { clef: this.defaults.clef, stem: this.defaults.stem, ...options };
this.parse(line, options);
return this.builder.getElements().notes;
Expand Down
4 changes: 2 additions & 2 deletions src/frethandfinger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { Builder } from './easyscore';
import { Font, FontInfo, FontStyle, FontWeight } from './font';
import { Modifier } from './modifier';
import { ModifierContextState } from './modifiercontext';
import { StaveNote } from './stavenote';
import { StemmableNote } from './stemmablenote';
import { RuntimeError } from './util';

export class FretHandFinger extends Modifier {
Expand Down Expand Up @@ -102,7 +102,7 @@ export class FretHandFinger extends Modifier {
return true;
}

static easyScoreHook({ fingerings }: { fingerings?: string } = {}, note: StaveNote, builder: Builder): void {
static easyScoreHook({ fingerings }: { fingerings?: string } = {}, note: StemmableNote, builder: Builder): void {
fingerings
?.split(',')
.map((fingeringString: string) => {
Expand Down
9 changes: 6 additions & 3 deletions src/ghostnote.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
//
// ## Description

import { Annotation } from './annotation';
import { ModifierContext } from './modifiercontext';
import { NoteStruct } from './note';
import { Stave } from './stave';
Expand Down Expand Up @@ -61,12 +62,14 @@ export class GhostNote extends StemmableNote {
}

draw(): void {
// Draw the modifiers
// Draw Annotations
this.setRendered();
for (let i = 0; i < this.modifiers.length; ++i) {
const modifier = this.modifiers[i];
modifier.setContext(this.getContext());
modifier.drawWithStyle();
if (modifier instanceof Annotation) {
modifier.setContext(this.getContext());
modifier.drawWithStyle();
}
}
}
}
43 changes: 43 additions & 0 deletions src/note.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
// [VexFlow](https://vexflow.com) - Copyright (c) Mohit Muthanna 2010.
// MIT License

import { Accidental } from './accidental';
import { Beam } from './beam';
import { Dot } from './dot';
import { Font } from './font';
import { Fraction } from './fraction';
import { GlyphProps } from './glyph';
Expand Down Expand Up @@ -558,6 +560,47 @@ export abstract class Note extends Tickable {
return this;
}

// Helper function to add an accidental to a key
addAccidental(index: number, accidental: Modifier): this {
return this.addModifier(accidental, index);
}

// Helper function to add an articulation to a key
addArticulation(index: number, articulation: Modifier): this {
return this.addModifier(articulation, index);
}

// Helper function to add an annotation to a key
addAnnotation(index: number, annotation: Modifier): this {
return this.addModifier(annotation, index);
}

// Helper function to add a dot on a specific key
addDot(index: number): this {
const dot = new Dot();
dot.setDotShiftY(this.glyph.dot_shiftY);
this.dots++;
return this.addModifier(dot, index);
}

// Convenience method to add dot to all keys in note
addDotToAll(): this {
for (let i = 0; i < this.keys.length; ++i) {
this.addDot(i);
}
return this;
}

// Get all accidentals in the `ModifierContext`
getAccidentals(): Accidental[] {
return this.checkModifierContext().getMembers(Accidental.CATEGORY) as Accidental[];
}

// Get all dots in the `ModifierContext`
getDots(): Dot[] {
return this.checkModifierContext().getMembers(Dot.CATEGORY) as Dot[];
}

/** Get the coordinates for where modifiers begin. */
// eslint-disable-next-line
getModifierStartXY(position?: number, index?: number, options?: any): { x: number; y: number } {
Expand Down
43 changes: 0 additions & 43 deletions src/stavenote.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,8 @@
//
// See `tests/stavenote_tests.ts` for usage examples.

import { Accidental } from './accidental';
import { Beam } from './beam';
import { BoundingBox } from './boundingbox';
import { Dot } from './dot';
import { ElementStyle } from './element';
import { Modifier } from './modifier';
import { ModifierContextState } from './modifiercontext';
Expand Down Expand Up @@ -871,47 +869,6 @@ export class StaveNote extends StemmableNote {
return this.keyProps[index].line;
}

// Helper function to add an accidental to a key
addAccidental(index: number, accidental: Modifier): this {
return this.addModifier(accidental, index);
}

// Helper function to add an articulation to a key
addArticulation(index: number, articulation: Modifier): this {
return this.addModifier(articulation, index);
}

// Helper function to add an annotation to a key
addAnnotation(index: number, annotation: Modifier): this {
return this.addModifier(annotation, index);
}

// Helper function to add a dot on a specific key
addDot(index: number): this {
const dot = new Dot();
dot.setDotShiftY(this.glyph.dot_shiftY);
this.dots++;
return this.addModifier(dot, index);
}

// Convenience method to add dot to all keys in note
addDotToAll(): this {
for (let i = 0; i < this.keys.length; ++i) {
this.addDot(i);
}
return this;
}

// Get all accidentals in the `ModifierContext`
getAccidentals(): Accidental[] {
return this.checkModifierContext().getMembers(Accidental.CATEGORY) as Accidental[];
}

// Get all dots in the `ModifierContext`
getDots(): Dot[] {
return this.checkModifierContext().getMembers(Dot.CATEGORY) as Dot[];
}

// Get the width of the note if it is displaced. Used for `Voice`
// formatting
getVoiceShiftWidth(): number {
Expand Down
Loading

0 comments on commit c3b67d4

Please sign in to comment.