VexFlowMusicSheetCalculator.ts 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. import {MusicSheetCalculator} from "../MusicSheetCalculator";
  2. import {VexFlowGraphicalSymbolFactory} from "./VexFlowGraphicalSymbolFactory";
  3. import {StaffMeasure} from "../StaffMeasure";
  4. import {StaffLine} from "../StaffLine";
  5. import {VoiceEntry} from "../../VoiceData/VoiceEntry";
  6. import {MusicSystem} from "../MusicSystem";
  7. import {GraphicalNote} from "../GraphicalNote";
  8. import {GraphicalStaffEntry} from "../GraphicalStaffEntry";
  9. import {GraphicalMusicPage} from "../GraphicalMusicPage";
  10. import {GraphicalTie} from "../GraphicalTie";
  11. import {Tie} from "../../VoiceData/Tie";
  12. import {SourceMeasure} from "../../VoiceData/SourceMeasure";
  13. import {MultiExpression} from "../../VoiceData/Expressions/multiExpression";
  14. import {RepetitionInstruction} from "../../VoiceData/Instructions/RepetitionInstruction";
  15. import {Beam} from "../../VoiceData/Beam";
  16. import {ClefInstruction} from "../../VoiceData/Instructions/ClefInstruction";
  17. import {OctaveEnum} from "../../VoiceData/Expressions/ContinuousExpressions/octaveShift";
  18. import {Fraction} from "../../../Common/DataObjects/fraction";
  19. import {LyricsEntry} from "../../VoiceData/Lyrics/LyricsEntry";
  20. import {LyricWord} from "../../VoiceData/Lyrics/LyricsWord";
  21. import {OrnamentContainer} from "../../VoiceData/OrnamentContainer";
  22. import {ArticulationEnum} from "../../VoiceData/VoiceEntry";
  23. import {Tuplet} from "../../VoiceData/Tuplet";
  24. import Dictionary from "typescript-collections/dist/lib/Dictionary";
  25. import {VexFlowMeasure} from "./VexFlowMeasure";
  26. import {VexFlowTextMeasurer} from "./VexFlowTextMeasurer";
  27. import Vex = require("vexflow");
  28. export class VexFlowMusicSheetCalculator extends MusicSheetCalculator {
  29. constructor() {
  30. super(new VexFlowGraphicalSymbolFactory());
  31. MusicSheetCalculator.TextMeasurer = new VexFlowTextMeasurer();
  32. }
  33. protected clearRecreatedObjects(): void {
  34. super.clearRecreatedObjects();
  35. for (let staffMeasures of this.graphicalMusicSheet.MeasureList) {
  36. for (let staffMeasure of staffMeasures) {
  37. (<VexFlowMeasure>staffMeasure).clean();
  38. }
  39. }
  40. }
  41. //protected clearSystemsAndMeasures(): void {
  42. // for (let measure of measures) {
  43. //
  44. // }
  45. //}
  46. /**
  47. * Calculates the x layout of the staff entries within the staff measures belonging to one source measure.
  48. * All staff entries are x-aligned throughout all vertically aligned staff measures.
  49. * This method is called within calculateXLayout.
  50. * The staff entries are aligned with minimum needed x distances.
  51. * The MinimumStaffEntriesWidth of every measure will be set - needed for system building.
  52. * @param measures
  53. * @returns the minimum required x width of the source measure (=list of staff measures)
  54. */
  55. protected calculateMeasureXLayout(measures: StaffMeasure[]): number {
  56. // Finalize beams
  57. for (let measure of measures) {
  58. (measure as VexFlowMeasure).finalizeBeams();
  59. }
  60. // Format the voices
  61. let allVoices: Vex.Flow.Voice[] = [];
  62. let formatter: Vex.Flow.Formatter = new Vex.Flow.Formatter();
  63. for (let measure of measures) {
  64. let mvoices: { [voiceID: number]: Vex.Flow.Voice; } = (measure as VexFlowMeasure).vfVoices;
  65. let voices: Vex.Flow.Voice[] = [];
  66. for (let voiceID in mvoices) {
  67. if (mvoices.hasOwnProperty(voiceID)) {
  68. voices.push(mvoices[voiceID]);
  69. allVoices.push(mvoices[voiceID]);
  70. }
  71. }
  72. if (voices.length === 0) {
  73. console.warn("Found a measure with no voices... Continuing anyway.", mvoices);
  74. continue;
  75. }
  76. formatter.joinVoices(voices);
  77. }
  78. let firstMeasure: VexFlowMeasure = measures[0] as VexFlowMeasure;
  79. let width: number = formatter.preCalculateMinTotalWidth(allVoices) / firstMeasure.unit;
  80. for (let measure of measures) {
  81. measure.minimumStaffEntriesWidth = width;
  82. (measure as VexFlowMeasure).formatVoices = undefined;
  83. }
  84. firstMeasure.formatVoices = (w: number) => {
  85. formatter.format(allVoices, w);
  86. };
  87. return width;
  88. }
  89. protected updateStaffLineBorders(staffLine: StaffLine): void {
  90. return;
  91. }
  92. protected calculateMeasureNumberPlacement(musicSystem: MusicSystem): void {
  93. return;
  94. }
  95. /**
  96. * Can be used to calculate stem directions, helper(ledger) lines, and overlapping note x-displacement.
  97. * Is Excecuted per voice entry of a staff entry.
  98. * After that layoutStaffEntry is called.
  99. * @param voiceEntry
  100. * @param graphicalNotes
  101. * @param graphicalStaffEntry
  102. * @param hasPitchedNote
  103. * @param isGraceStaffEntry
  104. */
  105. protected layoutVoiceEntry(voiceEntry: VoiceEntry, graphicalNotes: GraphicalNote[], graphicalStaffEntry: GraphicalStaffEntry,
  106. hasPitchedNote: boolean, isGraceStaffEntry: boolean): void {
  107. return;
  108. }
  109. /**
  110. * Do all layout calculations that have to be done per staff entry, like dots, ornaments, arpeggios....
  111. * This method is called after the voice entries are handled by layoutVoiceEntry().
  112. * @param graphicalStaffEntry
  113. */
  114. protected layoutStaffEntry(graphicalStaffEntry: GraphicalStaffEntry): void {
  115. (graphicalStaffEntry.parentMeasure as VexFlowMeasure).layoutStaffEntry(graphicalStaffEntry);
  116. }
  117. /**
  118. * calculates the y positions of the staff lines within a system and
  119. * furthermore the y positions of the systems themselves.
  120. */
  121. protected calculateSystemYLayout(): void {
  122. for (let idx: number = 0, len: number = this.graphicalMusicSheet.MusicPages.length; idx < len; ++idx) {
  123. let graphicalMusicPage: GraphicalMusicPage = this.graphicalMusicSheet.MusicPages[idx];
  124. if (!this.leadSheet) {
  125. let globalY: number = 0;
  126. for (let idx2: number = 0, len2: number = graphicalMusicPage.MusicSystems.length; idx2 < len2; ++idx2) {
  127. let musicSystem: MusicSystem = graphicalMusicPage.MusicSystems[idx2];
  128. // calculate y positions of stafflines within system
  129. let y: number = 0;
  130. for (let line of musicSystem.StaffLines) {
  131. line.PositionAndShape.RelativePosition.y = y;
  132. y += 10;
  133. }
  134. // set y positions of systems using the previous system and a fixed distance.
  135. musicSystem.PositionAndShape.BorderBottom = y + 10;
  136. musicSystem.PositionAndShape.RelativePosition.y = globalY;
  137. globalY += y + 10;
  138. }
  139. }
  140. }
  141. }
  142. /**
  143. * Is called at the begin of the method for creating the vertically aligned staff measures belonging to one source measure.
  144. */
  145. protected initStaffMeasuresCreation(): void {
  146. return;
  147. }
  148. protected handleTie(tie: Tie, startGraphicalStaffEntry: GraphicalStaffEntry, staffIndex: number, measureIndex: number): void {
  149. return;
  150. }
  151. protected layoutGraphicalTie(tie: GraphicalTie, tieIsAtSystemBreak: boolean): void {
  152. return;
  153. }
  154. protected calculateSingleStaffLineLyricsPosition(staffLine: StaffLine, lyricVersesNumber: number[]): void {
  155. return;
  156. }
  157. protected calculateSingleOctaveShift(sourceMeasure: SourceMeasure, multiExpression: MultiExpression, measureIndex: number, staffIndex: number): void {
  158. return;
  159. }
  160. protected calculateWordRepetitionInstruction(repetitionInstruction: RepetitionInstruction, measureIndex: number): void {
  161. return;
  162. }
  163. protected calculateMoodAndUnknownExpression(multiExpression: MultiExpression, measureIndex: number, staffIndex: number): void {
  164. return;
  165. }
  166. protected createGraphicalTieNote(beams: Beam[], activeClef: ClefInstruction,
  167. octaveShiftValue: OctaveEnum, graphicalStaffEntry: GraphicalStaffEntry, duration: Fraction, numberOfDots: number,
  168. openTie: Tie, isLastTieNote: boolean): void {
  169. return;
  170. }
  171. /**
  172. * Is called if a note is part of a beam.
  173. * @param graphicalNote
  174. * @param beam
  175. * @param openBeams a list of all currently open beams
  176. */
  177. protected handleBeam(graphicalNote: GraphicalNote, beam: Beam, openBeams: Beam[]): void {
  178. (graphicalNote.parentStaffEntry.parentMeasure as VexFlowMeasure).handleBeam(graphicalNote, beam);
  179. }
  180. protected handleVoiceEntryLyrics(lyricsEntries: Dictionary<number, LyricsEntry>, voiceEntry: VoiceEntry,
  181. graphicalStaffEntry: GraphicalStaffEntry, openLyricWords: LyricWord[]): void {
  182. return;
  183. }
  184. protected handleVoiceEntryOrnaments(ornamentContainer: OrnamentContainer, voiceEntry: VoiceEntry, graphicalStaffEntry: GraphicalStaffEntry): void {
  185. return;
  186. }
  187. protected handleVoiceEntryArticulations(articulations: ArticulationEnum[], voiceEntry: VoiceEntry, graphicalStaffEntry: GraphicalStaffEntry): void {
  188. return;
  189. }
  190. /**
  191. * Is called if a note is part of a tuplet.
  192. * @param graphicalNote
  193. * @param tuplet
  194. * @param openTuplets a list of all currently open tuplets
  195. */
  196. protected handleTuplet(graphicalNote: GraphicalNote, tuplet: Tuplet, openTuplets: Tuplet[]): void {
  197. return;
  198. }
  199. }