SourceStaffEntry.ts 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. import {Fraction} from "../../Common/DataObjects/Fraction";
  2. import {VerticalSourceStaffEntryContainer} from "./VerticalSourceStaffEntryContainer";
  3. import {Staff} from "./Staff";
  4. import {AbstractNotationInstruction} from "./Instructions/AbstractNotationInstruction";
  5. import {VoiceEntry} from "./VoiceEntry";
  6. import {Note} from "./Note";
  7. import {StaffEntryLink} from "./StaffEntryLink";
  8. import {ChordSymbolContainer} from "./ChordSymbolContainer";
  9. import {ClefInstruction} from "./Instructions/ClefInstruction";
  10. import {KeyInstruction} from "./Instructions/KeyInstruction";
  11. import {RhythmInstruction} from "./Instructions/RhythmInstruction";
  12. /**
  13. * A [[SourceStaffEntry]] is a container spanning all the [[VoiceEntry]]s at one timestamp for one [[StaffLine]].
  14. */
  15. export class SourceStaffEntry {
  16. constructor(verticalContainerParent: VerticalSourceStaffEntryContainer, parentStaff: Staff) {
  17. this.verticalContainerParent = verticalContainerParent;
  18. this.parentStaff = parentStaff;
  19. }
  20. private parentStaff: Staff;
  21. private verticalContainerParent: VerticalSourceStaffEntryContainer;
  22. private voiceEntries: VoiceEntry[] = [];
  23. private staffEntryLink: StaffEntryLink;
  24. private instructions: AbstractNotationInstruction[] = [];
  25. private chordSymbolContainers: ChordSymbolContainer[] = [];
  26. public get ParentStaff(): Staff {
  27. return this.parentStaff;
  28. }
  29. public get VerticalContainerParent(): VerticalSourceStaffEntryContainer {
  30. return this.verticalContainerParent;
  31. }
  32. public get Timestamp(): Fraction {
  33. if (this.VerticalContainerParent) {
  34. return this.VerticalContainerParent.Timestamp;
  35. }
  36. return undefined;
  37. }
  38. public get AbsoluteTimestamp(): Fraction {
  39. if (this.VerticalContainerParent) {
  40. return Fraction.plus(this.VerticalContainerParent.ParentMeasure.AbsoluteTimestamp, this.VerticalContainerParent.Timestamp);
  41. }
  42. return undefined;
  43. }
  44. public get VoiceEntries(): VoiceEntry[] {
  45. return this.voiceEntries;
  46. }
  47. public set VoiceEntries(value: VoiceEntry[]) {
  48. this.voiceEntries = value;
  49. }
  50. public get Link(): StaffEntryLink {
  51. return this.staffEntryLink;
  52. }
  53. public set Link(value: StaffEntryLink) {
  54. this.staffEntryLink = value;
  55. }
  56. public get Instructions(): AbstractNotationInstruction[] {
  57. return this.instructions;
  58. }
  59. public set Instructions(value: AbstractNotationInstruction[]) {
  60. this.instructions = value;
  61. }
  62. public get ChordContainers(): ChordSymbolContainer[] {
  63. return this.chordSymbolContainers;
  64. }
  65. public set ChordContainers(value: ChordSymbolContainer[]) {
  66. this.chordSymbolContainers = value;
  67. }
  68. // public removeAllInstructionsOfType(type: AbstractNotationInstruction): number {
  69. // let i: number = 0;
  70. // let ret: number = 0;
  71. // while (i < this.instructions.length) {
  72. // let instruction: AbstractNotationInstruction = this.instructions[i];
  73. // if (instruction instanceof type) {
  74. // this.instructions.splice(i, 1);
  75. // ret++;
  76. // } else {
  77. // i++;
  78. // }
  79. // }
  80. // return ret;
  81. // }
  82. //
  83. // public removeFirstInstructionOfType(type: AbstractNotationInstruction): boolean {
  84. // for (let i: number = 0; i < this.instructions.length; i++) {
  85. // if (this.instructions[i] instanceof type) {
  86. // this.instructions.splice(i, 1);
  87. // return true;
  88. // }
  89. // }
  90. // return false;
  91. // }
  92. public removeAllInstructionsOfTypeClefInstruction(): number {
  93. let i: number = 0;
  94. let ret: number = 0;
  95. while (i < this.instructions.length) {
  96. if (this.instructions[i] instanceof ClefInstruction) {
  97. this.instructions.splice(i, 1);
  98. ret++;
  99. } else {
  100. i++;
  101. }
  102. }
  103. return ret;
  104. }
  105. /**
  106. * Similar to RemoveAllInstructionsOfType but faster,
  107. * because it stops searching when the first instruction of the given type is found.
  108. * @returns {boolean}
  109. */
  110. public removeFirstInstructionOfTypeClefInstruction(): boolean {
  111. for (let i: number = 0; i < this.instructions.length; i++) {
  112. if (this.instructions[i] instanceof ClefInstruction) {
  113. this.instructions.splice(i, 1);
  114. return true;
  115. }
  116. }
  117. return false;
  118. }
  119. public removeAllInstructionsOfTypeKeyInstruction(): number {
  120. let i: number = 0;
  121. let ret: number = 0;
  122. while (i < this.instructions.length) {
  123. if (this.instructions[i] instanceof KeyInstruction) {
  124. this.instructions.splice(i, 1);
  125. ret++;
  126. } else {
  127. i++;
  128. }
  129. }
  130. return ret;
  131. }
  132. /**
  133. * Similar to RemoveAllInstructionsOfType but faster,
  134. * because it stops searching when the first instruction of the given type is found.
  135. * @returns {boolean}
  136. */
  137. public removeFirstInstructionOfTypeKeyInstruction(): boolean {
  138. for (let i: number = 0; i < this.instructions.length; i++) {
  139. if (this.instructions[i] instanceof KeyInstruction) {
  140. this.instructions.splice(i, 1);
  141. return true;
  142. }
  143. }
  144. return false;
  145. }
  146. public removeAllInstructionsOfTypeRhythmInstruction(): number {
  147. let i: number = 0;
  148. let ret: number = 0;
  149. while (i < this.instructions.length) {
  150. if (this.instructions[i] instanceof RhythmInstruction) {
  151. this.instructions.splice(i, 1);
  152. ret++;
  153. } else {
  154. i++;
  155. }
  156. }
  157. return ret;
  158. }
  159. public removeFirstInstructionOfTypeRhythmInstruction(): boolean {
  160. for (let i: number = 0; i < this.instructions.length; i++) {
  161. if (this.instructions[i] instanceof RhythmInstruction) {
  162. this.instructions.splice(i, 1);
  163. return true;
  164. }
  165. }
  166. return false;
  167. }
  168. /**
  169. * Calculate the [[SourceStaffEntry]]'s minimum NoteLength.
  170. * @returns {Fraction}
  171. */
  172. public calculateMinNoteLength(): Fraction {
  173. let duration: Fraction = new Fraction(Number.MAX_VALUE, 1);
  174. for (let idx: number = 0, len: number = this.VoiceEntries.length; idx < len; ++idx) {
  175. const voiceEntry: VoiceEntry = this.VoiceEntries[idx];
  176. for (let idx2: number = 0, len2: number = voiceEntry.Notes.length; idx2 < len2; ++idx2) {
  177. const note: Note = voiceEntry.Notes[idx2];
  178. if (note.Length.lt(duration)) {
  179. duration = note.Length;
  180. }
  181. }
  182. }
  183. return duration;
  184. }
  185. public calculateMaxNoteLength(): Fraction {
  186. let duration: Fraction = new Fraction(0, 1);
  187. for (let idx: number = 0, len: number = this.VoiceEntries.length; idx < len; ++idx) {
  188. const voiceEntry: VoiceEntry = this.VoiceEntries[idx];
  189. for (let idx2: number = 0, len2: number = voiceEntry.Notes.length; idx2 < len2; ++idx2) {
  190. const note: Note = voiceEntry.Notes[idx2];
  191. if (note.NoteTie) {
  192. // only add notes from this and after this sse!!
  193. const tieRestDuration: Fraction = Fraction.createFromFraction(note.Length);
  194. let addFollowingNotes: boolean = false;
  195. for (const n of note.NoteTie.Notes) {
  196. if (n === note) {
  197. addFollowingNotes = true;
  198. continue;
  199. }
  200. if (addFollowingNotes) {
  201. tieRestDuration.Add(n.Length);
  202. }
  203. }
  204. if (duration.lt(tieRestDuration)) {
  205. duration = tieRestDuration;
  206. }
  207. } else if (duration.lt(note.Length)) {
  208. duration = note.Length;
  209. }
  210. }
  211. }
  212. return duration;
  213. }
  214. public hasNotes(): boolean {
  215. for (let idx: number = 0, len: number = this.VoiceEntries.length; idx < len; ++idx) {
  216. const voiceEntry: VoiceEntry = this.VoiceEntries[idx];
  217. if (voiceEntry.Notes.length > 0) {
  218. return true;
  219. }
  220. }
  221. return false;
  222. }
  223. public hasTie(): boolean {
  224. for (let idx: number = 0, len: number = this.VoiceEntries.length; idx < len; ++idx) {
  225. const voiceEntry: VoiceEntry = this.VoiceEntries[idx];
  226. if (voiceEntry.hasTie()) {
  227. return true;
  228. }
  229. }
  230. return false;
  231. }
  232. public findLinkedNotes(linkedNotes: Note[]): void {
  233. for (let idx: number = 0, len: number = this.voiceEntries.length; idx < len; ++idx) {
  234. const voiceEntry: VoiceEntry = this.voiceEntries[idx];
  235. for (let idx2: number = 0, len2: number = voiceEntry.Notes.length; idx2 < len2; ++idx2) {
  236. const note: Note = voiceEntry.Notes[idx2];
  237. if (note.ParentStaffEntry === this) {
  238. linkedNotes.push(note);
  239. }
  240. }
  241. }
  242. }
  243. }