GraphicalStaffEntry.ts 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. import {SourceStaffEntry} from "../VoiceData/SourceStaffEntry";
  2. import {BoundingBox} from "./BoundingBox";
  3. import {Fraction} from "../../Common/DataObjects/Fraction";
  4. import {VerticalGraphicalStaffEntryContainer} from "./VerticalGraphicalStaffEntryContainer";
  5. import {Note} from "../VoiceData/Note";
  6. import {Slur} from "../VoiceData/Expressions/ContinuousExpressions/Slur";
  7. import {Voice} from "../VoiceData/Voice";
  8. import {VoiceEntry} from "../VoiceData/VoiceEntry";
  9. import {LinkedVoice} from "../VoiceData/LinkedVoice";
  10. import {GraphicalTie} from "./GraphicalTie";
  11. import {GraphicalObject} from "./GraphicalObject";
  12. import {StaffMeasure} from "./StaffMeasure";
  13. import {GraphicalNote} from "./GraphicalNote";
  14. import {GraphicalChordSymbolContainer} from "./GraphicalChordSymbolContainer";
  15. import {GraphicalLyricEntry} from "./GraphicalLyricEntry";
  16. import {AbstractGraphicalInstruction} from "./AbstractGraphicalInstruction";
  17. import {GraphicalStaffEntryLink} from "./GraphicalStaffEntryLink";
  18. import {CollectionUtil} from "../../Util/CollectionUtil";
  19. export abstract class GraphicalStaffEntry extends GraphicalObject {
  20. constructor(parentMeasure: StaffMeasure, sourceStaffEntry: SourceStaffEntry = undefined, staffEntryParent: GraphicalStaffEntry = undefined) {
  21. super();
  22. this.parentMeasure = parentMeasure;
  23. this.notes = [];
  24. this.graceStaffEntriesBefore = [];
  25. this.graceStaffEntriesAfter = [];
  26. this.sourceStaffEntry = sourceStaffEntry;
  27. if (staffEntryParent !== undefined) {
  28. this.staffEntryParent = staffEntryParent;
  29. this.parentVerticalContainer = staffEntryParent.parentVerticalContainer;
  30. this.PositionAndShape = new BoundingBox(this, staffEntryParent.PositionAndShape);
  31. } else {
  32. this.PositionAndShape = new BoundingBox(this, parentMeasure.PositionAndShape);
  33. }
  34. if (sourceStaffEntry !== undefined) {
  35. this.relInMeasureTimestamp = sourceStaffEntry.Timestamp;
  36. }
  37. }
  38. public graphicalChordContainer: GraphicalChordSymbolContainer;
  39. public graphicalLink: GraphicalStaffEntryLink;
  40. public relInMeasureTimestamp: Fraction;
  41. public sourceStaffEntry: SourceStaffEntry;
  42. public parentMeasure: StaffMeasure;
  43. public notes: GraphicalNote[][];
  44. public graceStaffEntriesBefore: GraphicalStaffEntry[];
  45. public graceStaffEntriesAfter: GraphicalStaffEntry[];
  46. public staffEntryParent: GraphicalStaffEntry;
  47. public parentVerticalContainer: VerticalGraphicalStaffEntryContainer;
  48. private graphicalInstructions: AbstractGraphicalInstruction[] = [];
  49. private graphicalTies: GraphicalTie[] = [];
  50. private lyricsEntries: GraphicalLyricEntry[] = [];
  51. public get GraphicalInstructions(): AbstractGraphicalInstruction[] {
  52. return this.graphicalInstructions;
  53. }
  54. public get GraphicalTies(): GraphicalTie[] {
  55. return this.graphicalTies;
  56. }
  57. public get LyricsEntries(): GraphicalLyricEntry[] {
  58. return this.lyricsEntries;
  59. }
  60. public getAbsoluteTimestamp(): Fraction {
  61. let result: Fraction = this.parentMeasure.parentSourceMeasure.AbsoluteTimestamp.clone();
  62. if (this.relInMeasureTimestamp !== undefined) {
  63. result.Add(this.relInMeasureTimestamp);
  64. }
  65. return result;
  66. }
  67. public findEndTieGraphicalNoteFromNote(tieNote: Note): GraphicalNote {
  68. for (let idx: number = 0, len: number = this.notes.length; idx < len; ++idx) {
  69. let graphicalNotes: GraphicalNote[] = this.notes[idx];
  70. for (let idx2: number = 0, len2: number = graphicalNotes.length; idx2 < len2; ++idx2) {
  71. let graphicalNote: GraphicalNote = graphicalNotes[idx2];
  72. let note: Note = graphicalNote.sourceNote;
  73. if (
  74. note.Pitch !== undefined && note.Pitch.FundamentalNote === tieNote.Pitch.FundamentalNote
  75. && note.Pitch.Octave === tieNote.Pitch.Octave && note.getAbsoluteTimestamp() === tieNote.getAbsoluteTimestamp()
  76. ) {
  77. return graphicalNote;
  78. }
  79. }
  80. }
  81. return undefined;
  82. }
  83. public findEndTieGraphicalNoteFromNoteWithStartingSlur(tieNote: Note, slur: Slur): GraphicalNote {
  84. for (let idx: number = 0, len: number = this.notes.length; idx < len; ++idx) {
  85. let graphicalNotes: GraphicalNote[] = this.notes[idx];
  86. for (let idx2: number = 0, len2: number = graphicalNotes.length; idx2 < len2; ++idx2) {
  87. let graphicalNote: GraphicalNote = graphicalNotes[idx2];
  88. let note: Note = graphicalNote.sourceNote;
  89. if (note.NoteTie !== undefined && note.NoteSlurs.indexOf(slur) !== -1) {
  90. return graphicalNote;
  91. }
  92. }
  93. }
  94. return undefined;
  95. }
  96. public findEndTieGraphicalNoteFromNoteWithEndingSlur(tieNote: Note): GraphicalNote {
  97. for (let idx: number = 0, len: number = this.notes.length; idx < len; ++idx) {
  98. let graphicalNotes: GraphicalNote[] = this.notes[idx];
  99. for (let idx2: number = 0, len2: number = graphicalNotes.length; idx2 < len2; ++idx2) {
  100. let graphicalNote: GraphicalNote = graphicalNotes[idx2];
  101. let note: Note = graphicalNote.sourceNote;
  102. if (
  103. note.Pitch !== undefined && note.Pitch.FundamentalNote === tieNote.Pitch.FundamentalNote
  104. && note.Pitch.Octave === tieNote.Pitch.Octave && this.getAbsoluteTimestamp() === tieNote.getAbsoluteTimestamp()
  105. ) {
  106. return graphicalNote;
  107. }
  108. }
  109. }
  110. return undefined;
  111. }
  112. public findGraphicalNoteFromGraceNote(graceNote: Note): GraphicalNote {
  113. for (let idx: number = 0, len: number = this.notes.length; idx < len; ++idx) {
  114. let graphicalNotes: GraphicalNote[] = this.notes[idx];
  115. for (let idx2: number = 0, len2: number = graphicalNotes.length; idx2 < len2; ++idx2) {
  116. let graphicalNote: GraphicalNote = graphicalNotes[idx2];
  117. if (graphicalNote.sourceNote === graceNote) {
  118. return graphicalNote;
  119. }
  120. }
  121. }
  122. return undefined;
  123. }
  124. public findGraphicalNoteFromNote(baseNote: Note): GraphicalNote {
  125. for (let idx: number = 0, len: number = this.notes.length; idx < len; ++idx) {
  126. let graphicalNotes: GraphicalNote[] = this.notes[idx];
  127. for (let idx2: number = 0, len2: number = graphicalNotes.length; idx2 < len2; ++idx2) {
  128. let graphicalNote: GraphicalNote = graphicalNotes[idx2];
  129. if (graphicalNote.sourceNote === baseNote && this.getAbsoluteTimestamp() === baseNote.getAbsoluteTimestamp()) {
  130. return graphicalNote;
  131. }
  132. }
  133. }
  134. return undefined;
  135. }
  136. public getGraphicalNoteDurationFromVoice(voice: Voice): Fraction {
  137. for (let idx: number = 0, len: number = this.notes.length; idx < len; ++idx) {
  138. let graphicalNotes: GraphicalNote[] = this.notes[idx];
  139. if (graphicalNotes[0].sourceNote.ParentVoiceEntry.ParentVoice === voice) {
  140. return graphicalNotes[0].graphicalNoteLength;
  141. }
  142. }
  143. return new Fraction(0, 1);
  144. }
  145. public findLinkedNotes(notLinkedNotes: GraphicalNote[]): void {
  146. if (this.sourceStaffEntry !== undefined && this.sourceStaffEntry.Link !== undefined) {
  147. for (let idx: number = 0, len: number = this.notes.length; idx < len; ++idx) {
  148. let graphicalNotes: GraphicalNote[] = this.notes[idx];
  149. for (let idx2: number = 0, len2: number = graphicalNotes.length; idx2 < len2; ++idx2) {
  150. let graphicalNote: GraphicalNote = graphicalNotes[idx2];
  151. if (graphicalNote.parentStaffEntry === this) {
  152. notLinkedNotes.push(graphicalNote);
  153. }
  154. }
  155. }
  156. }
  157. }
  158. public findVoiceEntryGraphicalNotes(voiceEntry: VoiceEntry): GraphicalNote[] {
  159. for (let idx: number = 0, len: number = this.notes.length; idx < len; ++idx) {
  160. let graphicalNotes: GraphicalNote[] = this.notes[idx];
  161. for (let idx2: number = 0, len2: number = graphicalNotes.length; idx2 < len2; ++idx2) {
  162. let graphicalNote: GraphicalNote = graphicalNotes[idx2];
  163. if (graphicalNote.sourceNote.ParentVoiceEntry === voiceEntry) {
  164. return graphicalNotes;
  165. }
  166. }
  167. }
  168. return undefined;
  169. }
  170. public isVoiceEntryPartOfLinkedVoiceEntry(voiceEntry: VoiceEntry): boolean {
  171. if (this.sourceStaffEntry.Link !== undefined) {
  172. for (let idx: number = 0, len: number = this.sourceStaffEntry.Link.LinkStaffEntries.length; idx < len; ++idx) {
  173. let sEntry: SourceStaffEntry = this.sourceStaffEntry.Link.LinkStaffEntries[idx];
  174. if (sEntry.VoiceEntries.indexOf(voiceEntry) !== -1 && sEntry !== this.sourceStaffEntry) {
  175. return true;
  176. }
  177. }
  178. }
  179. return false;
  180. }
  181. public getMainVoice(): Voice {
  182. for (let idx: number = 0, len: number = this.sourceStaffEntry.VoiceEntries.length; idx < len; ++idx) {
  183. let voiceEntry: VoiceEntry = this.sourceStaffEntry.VoiceEntries[idx];
  184. if (!(voiceEntry.ParentVoice instanceof LinkedVoice)) {
  185. return voiceEntry.ParentVoice;
  186. }
  187. }
  188. return this.notes[0][0].sourceNote.ParentVoiceEntry.ParentVoice;
  189. }
  190. public findStaffEntryMinNoteLength(): Fraction {
  191. let minLength: Fraction = new Fraction(Number.MAX_VALUE, 1);
  192. for (let idx: number = 0, len: number = this.notes.length; idx < len; ++idx) {
  193. let graphicalNotes: GraphicalNote[] = this.notes[idx];
  194. for (let idx2: number = 0, len2: number = graphicalNotes.length; idx2 < len2; ++idx2) {
  195. let graphicalNote: GraphicalNote = graphicalNotes[idx2];
  196. let calNoteLen: Fraction = graphicalNote.graphicalNoteLength;
  197. if (calNoteLen < minLength && calNoteLen.Numerator > 0) {
  198. minLength = calNoteLen;
  199. }
  200. }
  201. }
  202. return minLength;
  203. }
  204. public findStaffEntryMaxNoteLength(): Fraction {
  205. let maxLength: Fraction = new Fraction(0, 1);
  206. for (let idx: number = 0, len: number = this.notes.length; idx < len; ++idx) {
  207. let graphicalNotes: GraphicalNote[] = this.notes[idx];
  208. for (let idx2: number = 0, len2: number = graphicalNotes.length; idx2 < len2; ++idx2) {
  209. let graphicalNote: GraphicalNote = graphicalNotes[idx2];
  210. let calNoteLen: Fraction = graphicalNote.graphicalNoteLength;
  211. if (calNoteLen > maxLength && calNoteLen.Numerator > 0) {
  212. maxLength = calNoteLen;
  213. }
  214. }
  215. }
  216. return maxLength;
  217. }
  218. public findOrCreateGraphicalNotesListFromVoiceEntry(voiceEntry: VoiceEntry): GraphicalNote[] {
  219. let graphicalNotes: GraphicalNote[];
  220. if (this.notes.length === 0) {
  221. graphicalNotes = [];
  222. this.notes.push(graphicalNotes);
  223. } else {
  224. for (let i: number = 0; i < this.notes.length; i++) {
  225. if (this.notes[i][0].sourceNote.ParentVoiceEntry.ParentVoice === voiceEntry.ParentVoice) {
  226. return this.notes[i];
  227. }
  228. }
  229. graphicalNotes = [];
  230. this.notes.push(graphicalNotes);
  231. }
  232. return graphicalNotes;
  233. }
  234. public findOrCreateGraphicalNotesListFromGraphicalNote(graphicalNote: GraphicalNote): GraphicalNote[] {
  235. let graphicalNotes: GraphicalNote[];
  236. let tieStartSourceStaffEntry: SourceStaffEntry = graphicalNote.sourceNote.ParentStaffEntry;
  237. if (this.sourceStaffEntry !== tieStartSourceStaffEntry) {
  238. graphicalNotes = this.findOrCreateGraphicalNotesListFromVoiceEntry(graphicalNote.sourceNote.ParentVoiceEntry);
  239. } else {
  240. if (this.notes.length === 0) {
  241. graphicalNotes = [];
  242. this.notes.push(graphicalNotes);
  243. } else {
  244. for (let i: number = 0; i < this.notes.length; i++) {
  245. if (this.notes[i][0].sourceNote.ParentVoiceEntry.ParentVoice === graphicalNote.sourceNote.ParentVoiceEntry.ParentVoice) {
  246. return this.notes[i];
  247. }
  248. }
  249. graphicalNotes = [];
  250. this.notes.push(graphicalNotes);
  251. }
  252. }
  253. return graphicalNotes;
  254. }
  255. public addGraphicalNoteToListAtCorrectYPosition(graphicalNotes: GraphicalNote[], graphicalNote: GraphicalNote): void {
  256. if (graphicalNotes.length === 0 ||
  257. graphicalNote.PositionAndShape.RelativePosition.y < CollectionUtil.last(graphicalNotes).PositionAndShape.RelativePosition.Y) {
  258. graphicalNotes.push(graphicalNote);
  259. } else {
  260. for (let i: number = graphicalNotes.length - 1; i >= 0; i--) {
  261. if (graphicalNotes[i].PositionAndShape.RelativePosition.y > graphicalNote.PositionAndShape.RelativePosition.y) {
  262. graphicalNotes.splice(i + 1, 0, graphicalNote);
  263. break;
  264. }
  265. if (i === 0) {
  266. graphicalNotes.splice(0, 0, graphicalNote);
  267. break;
  268. }
  269. }
  270. }
  271. }
  272. }