VexFlowGraphicalNote.ts 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. import Vex from "vexflow";
  2. import {GraphicalNote} from "../GraphicalNote";
  3. import {Note} from "../../VoiceData/Note";
  4. import {ClefInstruction} from "../../VoiceData/Instructions/ClefInstruction";
  5. import {VexFlowConverter} from "./VexFlowConverter";
  6. import {Pitch} from "../../../Common/DataObjects/Pitch";
  7. import {Fraction} from "../../../Common/DataObjects/Fraction";
  8. import {OctaveEnum, OctaveShift} from "../../VoiceData/Expressions/ContinuousExpressions/OctaveShift";
  9. import { GraphicalVoiceEntry } from "../GraphicalVoiceEntry";
  10. import { KeyInstruction } from "../../VoiceData/Instructions/KeyInstruction";
  11. import { EngravingRules } from "../EngravingRules";
  12. /**
  13. * The VexFlow version of a [[GraphicalNote]].
  14. */
  15. export class VexFlowGraphicalNote extends GraphicalNote {
  16. constructor(note: Note, parent: GraphicalVoiceEntry, activeClef: ClefInstruction,
  17. octaveShift: OctaveEnum = OctaveEnum.NONE, rules: EngravingRules,
  18. graphicalNoteLength: Fraction = undefined) {
  19. super(note, parent, rules, graphicalNoteLength);
  20. this.clef = activeClef;
  21. this.octaveShift = octaveShift;
  22. if (note.Pitch) {
  23. // TODO: Maybe shift to Transpose function when available
  24. const drawPitch: Pitch = note.isRest() ? note.Pitch : OctaveShift.getPitchFromOctaveShift(note.Pitch, octaveShift);
  25. this.vfpitch = VexFlowConverter.pitch(drawPitch, note.isRest(), this.clef, this.sourceNote.Notehead);
  26. this.vfpitch[1] = undefined;
  27. }
  28. }
  29. public octaveShift: OctaveEnum;
  30. // The pitch of this note as given by VexFlowConverter.pitch
  31. public vfpitch: [string, string, ClefInstruction];
  32. // The corresponding VexFlow StaveNote (plus its index in the chord)
  33. public vfnote: [Vex.Flow.StemmableNote, number];
  34. public vfnoteIndex: number;
  35. // The current clef
  36. private clef: ClefInstruction;
  37. /**
  38. * Update the pitch of this note. Necessary in order to display accidentals correctly.
  39. * This is called by VexFlowGraphicalSymbolFactory.addGraphicalAccidental.
  40. * @param pitch
  41. */
  42. public setAccidental(pitch: Pitch): void {
  43. // if (this.vfnote) {
  44. // let pitchAcc: AccidentalEnum = pitch.Accidental;
  45. // const acc: string = Pitch.accidentalVexflow(pitch.Accidental);
  46. // if (acc) {
  47. // alert(acc);
  48. // this.vfnote[0].addAccidental(this.vfnote[1], new Vex.Flow.Accidental(acc));
  49. // }
  50. // } else {
  51. // revert octave shift, as the placement of the note is independent of octave brackets
  52. const drawPitch: Pitch = this.drawPitch(pitch);
  53. // recalculate the pitch, and this time don't ignore the accidental:
  54. this.vfpitch = VexFlowConverter.pitch(drawPitch, this.sourceNote.isRest(), this.clef, this.sourceNote.Notehead);
  55. this.DrawnAccidental = drawPitch.Accidental;
  56. //}
  57. }
  58. public drawPitch(pitch: Pitch): Pitch {
  59. return OctaveShift.getPitchFromOctaveShift(pitch, this.octaveShift);
  60. }
  61. public Transpose(keyInstruction: KeyInstruction, activeClef: ClefInstruction, halfTones: number, octaveEnum: OctaveEnum): Pitch {
  62. const tranposedPitch: Pitch = super.Transpose(keyInstruction, activeClef, halfTones, octaveEnum);
  63. const drawPitch: Pitch = OctaveShift.getPitchFromOctaveShift(tranposedPitch, this.octaveShift);
  64. this.vfpitch = VexFlowConverter.pitch(drawPitch, this.sourceNote.isRest(), this.clef, this.sourceNote.Notehead);
  65. this.vfpitch[1] = undefined;
  66. return drawPitch;
  67. }
  68. /**
  69. * Set the VexFlow StaveNote corresponding to this GraphicalNote, together with its index in the chord.
  70. * @param note
  71. * @param index
  72. */
  73. public setIndex(note: Vex.Flow.StemmableNote, index: number): void {
  74. this.vfnote = [note, index];
  75. this.vfnoteIndex = index;
  76. }
  77. public notehead(vfNote: Vex.Flow.StemmableNote = undefined): {line: number} {
  78. let vfnote: any = vfNote;
  79. if (!vfnote) {
  80. vfnote = (this.vfnote[0] as any);
  81. }
  82. const noteheads: any = vfnote.note_heads;
  83. if (noteheads && noteheads.length > this.vfnoteIndex && noteheads[this.vfnoteIndex]) {
  84. return vfnote.note_heads[this.vfnoteIndex];
  85. } else {
  86. return { line: 0 };
  87. }
  88. }
  89. /**
  90. * Gets the clef for this note
  91. */
  92. public Clef(): ClefInstruction {
  93. return this.clef;
  94. }
  95. /**
  96. * Gets the id of the SVGGElement containing this note, given the SVGRenderer is used.
  97. * This is for low-level rendering hacks and should be used with caution.
  98. */
  99. public getSVGId(): string {
  100. if (!this.vfnote) {
  101. return undefined; // e.g. MultiRestMeasure
  102. }
  103. return this.vfnote[0].getAttribute("id");
  104. }
  105. /**
  106. * Gets the SVGGElement containing this note, given the SVGRenderer is used.
  107. * This is for low-level rendering hacks and should be used with caution.
  108. */
  109. public getSVGGElement(): SVGGElement {
  110. if (!this.vfnote) {
  111. return undefined; // e.g. MultiRestMeasure
  112. }
  113. return this.vfnote[0].getAttribute("el");
  114. }
  115. }