import Vex from "vexflow"; import { BoundingBox } from "../BoundingBox"; import { GraphicalStaffEntry } from "../GraphicalStaffEntry"; import { VexFlowVoiceEntry } from "./VexFlowVoiceEntry"; import { GraphicalPedal } from "../GraphicalPedal"; import { Pedal } from "../../VoiceData/Expressions/ContinuousExpressions/Pedal"; import { MusicSymbol } from "../MusicSymbol"; import { GraphicalMeasure } from "../GraphicalMeasure"; import { VexFlowMeasure } from "./VexFlowMeasure"; /** * The vexflow adaptation of a pedal marking */ export class VexFlowPedal extends GraphicalPedal { /** Defines the note where the pedal starts */ public startNote: Vex.Flow.StemmableNote; /** Defines the note where the pedal ends */ public endNote: Vex.Flow.StemmableNote; private vfStyle: Vex.Flow.PedalMarking.Styles = Vex.Flow.PedalMarking.Styles.BRACKET; public DepressText: string; public ReleaseText: string; public startVfVoiceEntry: VexFlowVoiceEntry; public endVfVoiceEntry: VexFlowVoiceEntry; public endMeasure: GraphicalMeasure; public ChangeBegin: boolean = false; public ChangeEnd: boolean = false; private line: number = -3; public EndSymbolPositionAndShape: BoundingBox = undefined; /** * Create a new vexflow pedal marking * @param pedal the object read by the ExpressionReader * @param parent the bounding box of the parent */ constructor(pedal: Pedal, parent: BoundingBox, openBegin: boolean = false, openEnd: boolean = false) { super(pedal, parent); this.ChangeBegin = pedal.ChangeBegin; this.ChangeEnd = pedal.ChangeEnd; switch (this.pedalSymbol) { case MusicSymbol.PEDAL_SYMBOL: //This renders the pedal symbols in VF. this.vfStyle = Vex.Flow.PedalMarking.Styles.TEXT; this.EndSymbolPositionAndShape = new BoundingBox(this, parent); break; case MusicSymbol.PEDAL_MIXED: if (openBegin && openEnd) { this.vfStyle = (Vex.Flow.PedalMarking.Styles as any).BRACKET_OPEN_BOTH; } else if (openBegin) { this.vfStyle = (Vex.Flow.PedalMarking.Styles as any).BRACKET_OPEN_BEGIN; } else if (openEnd) { this.vfStyle = (Vex.Flow.PedalMarking.Styles as any).MIXED_OPEN_END; } else { this.vfStyle = Vex.Flow.PedalMarking.Styles.MIXED; } break; case MusicSymbol.PEDAL_BRACKET: default: if (openBegin && openEnd) { this.vfStyle = (Vex.Flow.PedalMarking.Styles as any).BRACKET_OPEN_BOTH; } else if (openBegin) { this.vfStyle = (Vex.Flow.PedalMarking.Styles as any).BRACKET_OPEN_BEGIN; } else if (openEnd) { this.vfStyle = (Vex.Flow.PedalMarking.Styles as any).BRACKET_OPEN_END; } else { this.vfStyle = Vex.Flow.PedalMarking.Styles.BRACKET; } break; } } /** * Set a start note using a staff entry * @param graphicalStaffEntry the staff entry that holds the start note */ public setStartNote(graphicalStaffEntry: GraphicalStaffEntry): boolean { if(!graphicalStaffEntry){ return false; } for (const gve of graphicalStaffEntry.graphicalVoiceEntries) { const vve: VexFlowVoiceEntry = (gve as VexFlowVoiceEntry); if (vve?.vfStaveNote) { this.startNote = vve.vfStaveNote; this.startVfVoiceEntry = vve; return true; } } return false; // couldn't find a startNote } /** * Set an end note using a staff entry * @param graphicalStaffEntry the staff entry that holds the end note */ public setEndNote(graphicalStaffEntry: GraphicalStaffEntry): boolean { // this is duplicate code from setStartNote, but if we make one general method, we add a lot of branching. if (!graphicalStaffEntry) { return false; } for (const gve of graphicalStaffEntry.graphicalVoiceEntries) { const vve: VexFlowVoiceEntry = (gve as VexFlowVoiceEntry); if (vve?.vfStaveNote) { this.endNote = vve.vfStaveNote; this.endVfVoiceEntry = vve; return true; } } return false; // couldn't find an endNote } public setEndMeasure(graphicalMeasure: GraphicalMeasure): void { this.endMeasure = graphicalMeasure; } public CalculateBoundingBox(): void { //TODO? } public setLine(line: number): void { this.line = line; } /** * Get the actual vexflow Pedal Marking used for drawing */ public getPedalMarking(): Vex.Flow.PedalMarking { const pedalMarking: Vex.Flow.PedalMarking = new Vex.Flow.PedalMarking([this.startNote, this.endNote]); if (this.endMeasure) { (pedalMarking as any).setEndStave((this.endMeasure as VexFlowMeasure).getVFStave()); } pedalMarking.setStyle(this.vfStyle); pedalMarking.setLine(this.line); pedalMarking.setCustomText(this.DepressText, this.ReleaseText); //If our end note is at the end of a stave, set that value if(this.endVfVoiceEntry?.parentStaffEntry === this.endVfVoiceEntry?.parentStaffEntry?.parentMeasure?.staffEntries.last() || !this.endVfVoiceEntry){ (pedalMarking as any).EndsStave = true; } (pedalMarking as any).ChangeBegin = this.ChangeBegin; (pedalMarking as any).ChangeEnd = this.ChangeEnd; return pedalMarking; } }