123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136 |
- import Vex from "vexflow";
- import VF = Vex.Flow;
- import { Staff } from "../../VoiceData/Staff";
- import { SourceMeasure } from "../../VoiceData/SourceMeasure";
- import { VexFlowMeasure } from "./VexFlowMeasure";
- import { VexFlowStaffEntry } from "./VexFlowStaffEntry";
- import { VexFlowConverter } from "./VexFlowConverter";
- import { StaffLine } from "../StaffLine";
- import { GraphicalVoiceEntry } from "../GraphicalVoiceEntry";
- import { VexFlowVoiceEntry } from "./VexFlowVoiceEntry";
- import { Arpeggio } from "../../VoiceData/Arpeggio";
- import { Voice } from "../../VoiceData/Voice";
- import log from "loglevel";
- export class VexFlowTabMeasure extends VexFlowMeasure {
- constructor(staff: Staff, sourceMeasure: SourceMeasure = undefined, staffLine: StaffLine = undefined) {
- super(staff, sourceMeasure, staffLine);
- this.isTabMeasure = true;
- }
- /**
- * Reset all the geometric values and parameters of this measure and put it in an initialized state.
- * This is needed to evaluate a measure a second time by system builder.
- */
- public resetLayout(): void {
- // Take into account some space for the begin and end lines of the stave
- // Will be changed when repetitions will be implemented
- //this.beginInstructionsWidth = 20 / UnitInPixels;
- //this.endInstructionsWidth = 20 / UnitInPixels;
- const stafflineCount: number = this.ParentStaff.StafflineCount ?? 6; // if undefined, 6 by default (same as Vexflow default)
- this.stave = new VF.TabStave(0, 0, 0, {
- space_above_staff_ln: 0,
- space_below_staff_ln: 0,
- num_lines: stafflineCount
- });
- // also see VexFlowMusicSheetDrawer.drawSheet() for some other vexflow default value settings (like default font scale)
- this.updateInstructionWidth();
- }
- public graphicalMeasureCreatedCalculations(): void {
- for (let idx: number = 0, len: number = this.staffEntries.length; idx < len; ++idx) {
- const graphicalStaffEntry: VexFlowStaffEntry = (this.staffEntries[idx] as VexFlowStaffEntry);
- // create vex flow Notes:
- for (const gve of graphicalStaffEntry.graphicalVoiceEntries) {
- if (gve.notes[0].sourceNote.isRest()) {
- const ghostNotes: VF.GhostNote[] = VexFlowConverter.GhostNotes(gve.notes[0].sourceNote.Length);
- (gve as VexFlowVoiceEntry).vfStaveNote = ghostNotes[0];
- (gve as VexFlowVoiceEntry).vfGhostNotes = ghostNotes; // we actually need multiple ghost notes sometimes, see #1062 Sep. 23 2021 comment
- } else {
- (gve as VexFlowVoiceEntry).vfStaveNote = VexFlowConverter.CreateTabNote(gve);
- }
- }
- }
- if (this.rules.TupletNumbersInTabs) { // default false, don't show tuplets in tab measures
- this.finalizeTuplets();
- }
- const voices: Voice[] = this.getVoicesWithinMeasure();
- for (const voice of voices) {
- if (!voice) {
- continue;
- }
- // add a vexFlow voice for this voice:
- this.vfVoices[voice.VoiceId] = new VF.Voice({
- beat_value: this.parentSourceMeasure.Duration.Denominator,
- num_beats: this.parentSourceMeasure.Duration.Numerator,
- resolution: VF.RESOLUTION,
- }).setMode(VF.Voice.Mode.SOFT);
- const restFilledEntries: GraphicalVoiceEntry[] = this.getRestFilledVexFlowStaveNotesPerVoice(voice);
- // create vex flow voices and add tickables to it:
- for (const voiceEntry of restFilledEntries) {
- if (voiceEntry.parentVoiceEntry) {
- if (voiceEntry.parentVoiceEntry.IsGrace && !voiceEntry.parentVoiceEntry.GraceAfterMainNote) {
- continue;
- }
- }
- const vexFlowVoiceEntry: VexFlowVoiceEntry = voiceEntry as VexFlowVoiceEntry;
- if (voiceEntry.notes.length === 0 || !voiceEntry.notes[0] || !voiceEntry.notes[0].sourceNote.PrintObject) {
- // GhostNote, don't add modifiers like in-measure clefs
- if (vexFlowVoiceEntry.vfGhostNotes) {
- for (const ghostNote of vexFlowVoiceEntry.vfGhostNotes) {
- this.vfVoices[voice.VoiceId].addTickable(ghostNote);
- }
- } else {
- this.vfVoices[voice.VoiceId].addTickable(vexFlowVoiceEntry.vfStaveNote);
- }
- continue;
- }
- // don't add non-tab fingerings for tab measures (doesn't work yet for tabnotes in vexflow, see VexFlowMeasure.createFingerings())
- // if (voiceEntry.parentVoiceEntry && this.rules.RenderFingerings) {
- // this.createFingerings(voiceEntry);
- // }
- // add Arpeggio
- if (voiceEntry.parentVoiceEntry && voiceEntry.parentVoiceEntry.Arpeggio) {
- const arpeggio: Arpeggio = voiceEntry.parentVoiceEntry.Arpeggio;
- // TODO right now our arpeggio object has all arpeggio notes from arpeggios across all voices.
- // see VoiceGenerator. Doesn't matter for Vexflow for now though
- if (voiceEntry.notes && voiceEntry.notes.length > 1) {
- const type: VF.Stroke.Type = VexFlowConverter.StrokeTypeFromArpeggioType(arpeggio.type);
- const stroke: VF.Stroke = new VF.Stroke(type, {
- all_voices: this.rules.ArpeggiosGoAcrossVoices
- // default: false. This causes arpeggios to always go across all voices, which is often unwanted.
- // also, this can cause infinite height of stroke, see #546
- });
- //if (arpeggio.notes.length === vexFlowVoiceEntry.notes.length) { // different workaround for endless y bug
- if (this.rules.RenderArpeggios) {
- vexFlowVoiceEntry.vfStaveNote.addStroke(0, stroke);
- }
- } else {
- log.debug(`[OSMD] arpeggio in measure ${this.MeasureNumber} could not be drawn.
- voice entry had less than two notes, arpeggio is likely between voice entries, not currently supported in Vexflow.`);
- // TODO: create new arpeggio with all the arpeggio's notes (arpeggio.notes), perhaps with GhostNotes in a new vfStaveNote. not easy.
- }
- }
- if (vexFlowVoiceEntry.vfGhostNotes) {
- for (const ghostNote of vexFlowVoiceEntry.vfGhostNotes) {
- this.vfVoices[voice.VoiceId].addTickable(ghostNote);
- }
- } else {
- this.vfVoices[voice.VoiceId].addTickable(vexFlowVoiceEntry.vfStaveNote);
- }
- }
- }
- //this.createArticulations();
- //this.createOrnaments();
- }
- }
|