VexFlowTabMeasure.ts 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. import Vex = require("vexflow");
  2. import { Staff } from "../../VoiceData/Staff";
  3. import { SourceMeasure } from "../../VoiceData/SourceMeasure";
  4. import { VexFlowMeasure } from "./VexFlowMeasure";
  5. import { VexFlowStaffEntry } from "./VexFlowStaffEntry";
  6. import { VexFlowConverter } from "./VexFlowConverter";
  7. import { StaffLine } from "../StaffLine";
  8. import { GraphicalVoiceEntry } from "../GraphicalVoiceEntry";
  9. import { VexFlowVoiceEntry } from "./VexFlowVoiceEntry";
  10. import { Arpeggio } from "../../VoiceData/Arpeggio";
  11. import { Voice } from "../../VoiceData/Voice";
  12. import * as log from "loglevel";
  13. export class VexFlowTabMeasure extends VexFlowMeasure {
  14. constructor(staff: Staff, sourceMeasure: SourceMeasure = undefined, staffLine: StaffLine = undefined) {
  15. super(staff, sourceMeasure, staffLine);
  16. }
  17. /**
  18. * Reset all the geometric values and parameters of this measure and put it in an initialized state.
  19. * This is needed to evaluate a measure a second time by system builder.
  20. */
  21. public resetLayout(): void {
  22. // Take into account some space for the begin and end lines of the stave
  23. // Will be changed when repetitions will be implemented
  24. //this.beginInstructionsWidth = 20 / UnitInPixels;
  25. //this.endInstructionsWidth = 20 / UnitInPixels;
  26. this.stave = new Vex.Flow.TabStave(0, 0, 0, {
  27. space_above_staff_ln: 0,
  28. space_below_staff_ln: 0,
  29. });
  30. this.updateInstructionWidth();
  31. }
  32. public graphicalMeasureCreatedCalculations(): void {
  33. for (let idx: number = 0, len: number = this.staffEntries.length; idx < len; ++idx) {
  34. const graphicalStaffEntry: VexFlowStaffEntry = (this.staffEntries[idx] as VexFlowStaffEntry);
  35. // create vex flow Notes:
  36. for (const gve of graphicalStaffEntry.graphicalVoiceEntries) {
  37. if (gve.notes[0].sourceNote.isRest()) {
  38. (gve as VexFlowVoiceEntry).vfStaveNote = VexFlowConverter.GhostNote(gve.notes[0].sourceNote.Length);
  39. } else {
  40. (gve as VexFlowVoiceEntry).vfStaveNote = VexFlowConverter.CreateTabNote(gve);
  41. }
  42. }
  43. }
  44. this.finalizeTuplets();
  45. const voices: Voice[] = this.getVoicesWithinMeasure();
  46. for (const voice of voices) {
  47. if (voice === undefined) {
  48. continue;
  49. }
  50. // add a vexFlow voice for this voice:
  51. this.vfVoices[voice.VoiceId] = new Vex.Flow.Voice({
  52. beat_value: this.parentSourceMeasure.Duration.Denominator,
  53. num_beats: this.parentSourceMeasure.Duration.Numerator,
  54. resolution: Vex.Flow.RESOLUTION,
  55. }).setMode(Vex.Flow.Voice.Mode.SOFT);
  56. const restFilledEntries: GraphicalVoiceEntry[] = this.getRestFilledVexFlowStaveNotesPerVoice(voice);
  57. // create vex flow voices and add tickables to it:
  58. for (const voiceEntry of restFilledEntries) {
  59. if (voiceEntry.parentVoiceEntry) {
  60. if (voiceEntry.parentVoiceEntry.IsGrace && !voiceEntry.parentVoiceEntry.GraceAfterMainNote) {
  61. continue;
  62. }
  63. }
  64. const vexFlowVoiceEntry: VexFlowVoiceEntry = voiceEntry as VexFlowVoiceEntry;
  65. if (voiceEntry.notes.length === 0 || !voiceEntry.notes[0] || !voiceEntry.notes[0].sourceNote.PrintObject) {
  66. // GhostNote, don't add modifiers like in-measure clefs
  67. this.vfVoices[voice.VoiceId].addTickable(vexFlowVoiceEntry.vfStaveNote);
  68. continue;
  69. }
  70. // add fingering
  71. if (voiceEntry.parentVoiceEntry && this.rules.RenderFingerings) {
  72. this.createFingerings(voiceEntry);
  73. }
  74. // add Arpeggio
  75. if (voiceEntry.parentVoiceEntry && voiceEntry.parentVoiceEntry.Arpeggio !== undefined) {
  76. const arpeggio: Arpeggio = voiceEntry.parentVoiceEntry.Arpeggio;
  77. // TODO right now our arpeggio object has all arpeggio notes from arpeggios across all voices.
  78. // see VoiceGenerator. Doesn't matter for Vexflow for now though
  79. if (voiceEntry.notes && voiceEntry.notes.length > 1) {
  80. const type: Vex.Flow.Stroke.Type = VexFlowConverter.StrokeTypeFromArpeggioType(arpeggio.type);
  81. const stroke: Vex.Flow.Stroke = new Vex.Flow.Stroke(type, {
  82. all_voices: this.rules.ArpeggiosGoAcrossVoices
  83. // default: false. This causes arpeggios to always go across all voices, which is often unwanted.
  84. // also, this can cause infinite height of stroke, see #546
  85. });
  86. //if (arpeggio.notes.length === vexFlowVoiceEntry.notes.length) { // different workaround for endless y bug
  87. if (this.rules.RenderArpeggios) {
  88. vexFlowVoiceEntry.vfStaveNote.addStroke(0, stroke);
  89. }
  90. } else {
  91. log.debug(`[OSMD] arpeggio in measure ${this.MeasureNumber} could not be drawn.
  92. voice entry had less than two notes, arpeggio is likely between voice entries, not currently supported in Vexflow.`);
  93. // TODO: create new arpeggio with all the arpeggio's notes (arpeggio.notes), perhaps with GhostNotes in a new vfStaveNote. not easy.
  94. }
  95. }
  96. this.vfVoices[voice.VoiceId].addTickable(vexFlowVoiceEntry.vfStaveNote);
  97. }
  98. }
  99. //this.createArticulations();
  100. //this.createOrnaments();
  101. }
  102. }