import { WavyLine } from "../../VoiceData/Expressions/ContinuousExpressions/WavyLine"; import { BoundingBox } from "../BoundingBox"; import { GraphicalStaffEntry } from "../GraphicalStaffEntry"; import { GraphicalWavyLine } from "../GraphicalWavyLine"; import { VexFlowVoiceEntry } from "./VexFlowVoiceEntry"; import Vex from "vexflow"; export class VexflowVibratoBracket extends GraphicalWavyLine { /** Defines the note where the pedal starts */ public startNote: Vex.Flow.StemmableNote; /** Defines the note where the pedal ends */ public endNote: Vex.Flow.StemmableNote; public startVfVoiceEntry: VexFlowVoiceEntry; public endVfVoiceEntry: VexFlowVoiceEntry; //Line where vexflow renders the bracket. VF default is 1 public line: number = 1; private isVibrato: boolean = false; private toEndOfStopStave: boolean = false; public get ToEndOfStopStave(): boolean { return this.toEndOfStopStave; } constructor(wavyLine: WavyLine, parentBBox: BoundingBox, tabVibrato: boolean = false) { super(wavyLine, parentBBox); this.isVibrato = tabVibrato; } /** * Set a start note using a staff entry * @param graphicalStaffEntry the staff entry that holds the start note */ public setStartNote(graphicalStaffEntry: GraphicalStaffEntry): boolean { 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. for (const gve of graphicalStaffEntry.graphicalVoiceEntries) { const vve: VexFlowVoiceEntry = (gve as VexFlowVoiceEntry); if (vve?.vfStaveNote) { this.endNote = vve.vfStaveNote; this.endVfVoiceEntry = vve; const parentMeasureStaffEntries: GraphicalStaffEntry[] = this.endVfVoiceEntry.parentStaffEntry.parentMeasure.staffEntries; const lastStaffEntry: GraphicalStaffEntry = parentMeasureStaffEntries[parentMeasureStaffEntries.length - 1]; //If this is the last staff entry of the stave (measure), render line to end of measure this.toEndOfStopStave = (lastStaffEntry === this.endVfVoiceEntry.parentStaffEntry); return true; } } return false; // couldn't find an endNote } public CalculateBoundingBox(): void { const vfBracket: any = this.getVibratoBracket(); //Double the height of the wave, coverted to units this.boundingBox.Size.height = vfBracket.render_options.wave_height * 0.2; } public getVibratoBracket(): Vex.Flow.VibratoBracket { const bracket: Vex.Flow.VibratoBracket = new Vex.Flow.VibratoBracket({ start: this.startNote, stop: this.endNote, toEndOfStopStave: this.toEndOfStopStave }); bracket.setLine(this.line); if (this.isVibrato) { //Render options for vibrato style (bracket as any).render_options.vibrato_width = 20; } else { (bracket as any).render_options.wave_girth = 4; } return bracket; } }