SourceMeasure.ts 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. import {Fraction} from "../../Common/DataObjects/fraction";
  2. import {VerticalSourceStaffEntryContainer} from "./VerticalSourceStaffEntryContainer";
  3. import {SourceStaffEntry} from "./SourceStaffEntry";
  4. import {RepetitionInstruction} from "./Instructions/RepetitionInstruction";
  5. import {Staff} from "./Staff";
  6. import {VoiceEntry} from "./VoiceEntry";
  7. import {Voice} from "./Voice";
  8. import {MusicSheet} from "../MusicSheet";
  9. import {MultiExpression} from "./Expressions/multiExpression";
  10. import {MultiTempoExpression} from "./Expressions/multiTempoExpression";
  11. export class SourceMeasure {
  12. constructor(completeNumberOfStaves: number) {
  13. this.completeNumberOfStaves = completeNumberOfStaves;
  14. this.implicitMeasure = false;
  15. this.breakSystemAfter = false;
  16. this.endsPiece = false;
  17. this.firstInstructionsStaffEntries = new Array(completeNumberOfStaves);
  18. this.lastInstructionsStaffEntries = new Array(completeNumberOfStaves);
  19. for (let i: number = 0; i < completeNumberOfStaves; i++) {
  20. this.staffMeasureErrors.push(false);
  21. this.staffLinkedExpressions.push([]);
  22. }
  23. }
  24. public measureListIndex: number;
  25. public endsPiece: boolean;
  26. private measureNumber: number;
  27. //private parentMusicPart: SourceMusicPart;
  28. private absoluteTimestamp: Fraction;
  29. private completeNumberOfStaves: number;
  30. private duration: Fraction;
  31. private staffLinkedExpressions: MultiExpression[][] = [];
  32. private tempoExpressions: MultiTempoExpression[] = [];
  33. private verticalSourceStaffEntryContainers: VerticalSourceStaffEntryContainer[] = [];
  34. private implicitMeasure: boolean;
  35. private breakSystemAfter: boolean;
  36. private staffMeasureErrors: boolean[] = [];
  37. private firstInstructionsStaffEntries: SourceStaffEntry[];
  38. private lastInstructionsStaffEntries: SourceStaffEntry[];
  39. private firstRepetitionInstructions: RepetitionInstruction[] = [];
  40. private lastRepetitionInstructions: RepetitionInstruction[] = [];
  41. public get MeasureNumber(): number {
  42. return this.measureNumber;
  43. }
  44. public set MeasureNumber(value: number) {
  45. this.measureNumber = value;
  46. }
  47. public get AbsoluteTimestamp(): Fraction {
  48. return this.absoluteTimestamp;
  49. }
  50. public set AbsoluteTimestamp(value: Fraction) {
  51. this.absoluteTimestamp = value;
  52. }
  53. public get CompleteNumberOfStaves(): number {
  54. return this.completeNumberOfStaves;
  55. }
  56. public get Duration(): Fraction {
  57. return this.duration;
  58. }
  59. public set Duration(value: Fraction) {
  60. this.duration = value;
  61. }
  62. public get ImplicitMeasure(): boolean {
  63. return this.implicitMeasure;
  64. }
  65. public set ImplicitMeasure(value: boolean) {
  66. this.implicitMeasure = value;
  67. }
  68. public get BreakSystemAfter(): boolean {
  69. return this.breakSystemAfter;
  70. }
  71. public set BreakSystemAfter(value: boolean) {
  72. this.breakSystemAfter = value;
  73. }
  74. public get StaffLinkedExpressions(): MultiExpression[][] {
  75. return this.staffLinkedExpressions;
  76. }
  77. public get TempoExpressions(): MultiTempoExpression[] {
  78. return this.tempoExpressions;
  79. }
  80. public get VerticalSourceStaffEntryContainers(): VerticalSourceStaffEntryContainer[] {
  81. return this.verticalSourceStaffEntryContainers;
  82. }
  83. public get FirstInstructionsStaffEntries(): SourceStaffEntry[] {
  84. return this.firstInstructionsStaffEntries;
  85. }
  86. public get LastInstructionsStaffEntries(): SourceStaffEntry[] {
  87. return this.lastInstructionsStaffEntries;
  88. }
  89. public get FirstRepetitionInstructions(): RepetitionInstruction[] {
  90. return this.firstRepetitionInstructions;
  91. }
  92. public get LastRepetitionInstructions(): RepetitionInstruction[] {
  93. return this.lastRepetitionInstructions;
  94. }
  95. public getErrorInMeasure(staffIndex: number): boolean {
  96. return this.staffMeasureErrors[staffIndex];
  97. }
  98. public setErrorInStaffMeasure(staffIndex: number, hasError: boolean): void {
  99. this.staffMeasureErrors[staffIndex] = hasError;
  100. }
  101. public getNextMeasure(measures: SourceMeasure[]): SourceMeasure {
  102. return measures[this.measureListIndex + 1];
  103. }
  104. public getPreviousMeasure(measures: SourceMeasure[]): SourceMeasure {
  105. if (this.measureListIndex > 1) {
  106. return measures[this.measureListIndex - 1];
  107. }
  108. return undefined;
  109. }
  110. public findOrCreateStaffEntry(
  111. inMeasureTimestamp: Fraction, inSourceMeasureStaffIndex: number, staff: Staff
  112. ): {createdNewContainer: boolean, staffEntry: SourceStaffEntry} {
  113. // FIXME Andrea: debug & Test
  114. let staffEntry: SourceStaffEntry = undefined;
  115. // Find:
  116. let existingVerticalSourceStaffEntryContainer: VerticalSourceStaffEntryContainer;
  117. for (let container of this.verticalSourceStaffEntryContainers) {
  118. if (container.Timestamp.Equals(inMeasureTimestamp)) {
  119. existingVerticalSourceStaffEntryContainer = container;
  120. break;
  121. }
  122. }
  123. if (existingVerticalSourceStaffEntryContainer !== undefined) {
  124. if (existingVerticalSourceStaffEntryContainer.StaffEntries[inSourceMeasureStaffIndex] !== undefined) {
  125. staffEntry = existingVerticalSourceStaffEntryContainer.StaffEntries[inSourceMeasureStaffIndex];
  126. } else {
  127. staffEntry = new SourceStaffEntry(existingVerticalSourceStaffEntryContainer, staff);
  128. existingVerticalSourceStaffEntryContainer.StaffEntries[inSourceMeasureStaffIndex] = staffEntry;
  129. }
  130. return {createdNewContainer: false, staffEntry: staffEntry};
  131. }
  132. let last: VerticalSourceStaffEntryContainer = this.verticalSourceStaffEntryContainers[this.verticalSourceStaffEntryContainers.length - 1];
  133. if (this.verticalSourceStaffEntryContainers.length === 0 || last.Timestamp.lt(inMeasureTimestamp)) {
  134. let container: VerticalSourceStaffEntryContainer = new VerticalSourceStaffEntryContainer(
  135. this, inMeasureTimestamp.clone(), this.completeNumberOfStaves
  136. );
  137. this.verticalSourceStaffEntryContainers.push(container);
  138. staffEntry = new SourceStaffEntry(container, staff);
  139. container.StaffEntries[inSourceMeasureStaffIndex] = staffEntry;
  140. } else {
  141. for (
  142. let i: number = this.verticalSourceStaffEntryContainers.length - 1;
  143. i >= 0; i--
  144. ) {
  145. if (this.verticalSourceStaffEntryContainers[i].Timestamp.lt(inMeasureTimestamp)) {
  146. let container: VerticalSourceStaffEntryContainer = new VerticalSourceStaffEntryContainer(
  147. this, inMeasureTimestamp.clone(), this.completeNumberOfStaves
  148. );
  149. this.verticalSourceStaffEntryContainers.splice(i + 1, 0, container);
  150. staffEntry = new SourceStaffEntry(container, staff);
  151. container.StaffEntries[inSourceMeasureStaffIndex] = staffEntry;
  152. break;
  153. }
  154. if (i === 0) {
  155. let container: VerticalSourceStaffEntryContainer = new VerticalSourceStaffEntryContainer(
  156. this, inMeasureTimestamp.clone(), this.completeNumberOfStaves
  157. );
  158. this.verticalSourceStaffEntryContainers.splice(i, 0, container);
  159. staffEntry = new SourceStaffEntry(container, staff);
  160. container.StaffEntries[inSourceMeasureStaffIndex] = staffEntry;
  161. break;
  162. }
  163. }
  164. }
  165. //Logging.debug("created new container: ", staffEntry, this.verticalSourceStaffEntryContainers);
  166. return {createdNewContainer: true, staffEntry: staffEntry};
  167. }
  168. public findOrCreateVoiceEntry(sse: SourceStaffEntry, voice: Voice): { createdVoiceEntry: boolean, voiceEntry: VoiceEntry } {
  169. let ve: VoiceEntry = undefined;
  170. let createdNewVoiceEntry: boolean = false;
  171. for (let voiceEntry of sse.VoiceEntries) {
  172. if (voiceEntry.ParentVoice === voice) {
  173. ve = voiceEntry;
  174. break;
  175. }
  176. }
  177. if (ve === undefined) {
  178. ve = new VoiceEntry(sse.Timestamp, voice, sse);
  179. sse.VoiceEntries.push(ve);
  180. createdNewVoiceEntry = true;
  181. }
  182. return { createdVoiceEntry: createdNewVoiceEntry, voiceEntry: ve };
  183. }
  184. public getPreviousSourceStaffEntryFromIndex(
  185. verticalIndex: number, horizontalIndex: number
  186. ): SourceStaffEntry {
  187. for (let i: number = horizontalIndex - 1; i >= 0; i--) {
  188. if (this.verticalSourceStaffEntryContainers[i][verticalIndex] !== undefined) {
  189. return this.verticalSourceStaffEntryContainers[i][verticalIndex];
  190. }
  191. }
  192. return undefined;
  193. }
  194. public getVerticalContainerIndexByTimestamp(musicTimestamp: Fraction): number {
  195. for (let idx: number = 0, len: number = this.VerticalSourceStaffEntryContainers.length; idx < len; ++idx) {
  196. if (this.VerticalSourceStaffEntryContainers[idx].Timestamp.Equals(musicTimestamp)) {
  197. return idx; // this.verticalSourceStaffEntryContainers.indexOf(verticalSourceStaffEntryContainer);
  198. }
  199. }
  200. return -1;
  201. }
  202. public getVerticalContainerByTimestamp(musicTimestamp: Fraction): VerticalSourceStaffEntryContainer {
  203. for (let idx: number = 0, len: number = this.VerticalSourceStaffEntryContainers.length; idx < len; ++idx) {
  204. let verticalSourceStaffEntryContainer: VerticalSourceStaffEntryContainer = this.VerticalSourceStaffEntryContainers[idx];
  205. if (verticalSourceStaffEntryContainer.Timestamp.Equals(musicTimestamp)) {
  206. return verticalSourceStaffEntryContainer;
  207. }
  208. }
  209. return undefined;
  210. }
  211. public checkForEmptyVerticalContainer(index: number): void {
  212. let undefinedCounter: number = 0;
  213. for (let i: number = 0; i < this.completeNumberOfStaves; i++) {
  214. if (this.verticalSourceStaffEntryContainers[index][i] === undefined) {
  215. undefinedCounter++;
  216. }
  217. }
  218. if (undefinedCounter === this.completeNumberOfStaves) {
  219. this.verticalSourceStaffEntryContainers.splice(index, 1);
  220. }
  221. }
  222. public reverseCheck(musicSheet: MusicSheet, maxInstDuration: Fraction): Fraction {
  223. let maxDuration: Fraction = new Fraction(0, 1);
  224. let instrumentsDurations: Fraction[] = [];
  225. for (let i: number = 0; i < musicSheet.Instruments.length; i++) {
  226. let instrumentDuration: Fraction = new Fraction(0, 1);
  227. let inSourceMeasureInstrumentIndex: number = musicSheet.getGlobalStaffIndexOfFirstStaff(musicSheet.Instruments[i]);
  228. for (let j: number = 0; j < musicSheet.Instruments[i].Staves.length; j++) {
  229. let lastStaffEntry: SourceStaffEntry = this.getLastSourceStaffEntryForInstrument(inSourceMeasureInstrumentIndex + j);
  230. if (lastStaffEntry !== undefined && !lastStaffEntry.hasTie()) {
  231. let verticalContainerIndex: number = this.verticalSourceStaffEntryContainers.indexOf(lastStaffEntry.VerticalContainerParent);
  232. for (let m: number = verticalContainerIndex - 1; m >= 0; m--) {
  233. let previousStaffEntry: SourceStaffEntry = this.verticalSourceStaffEntryContainers[m][inSourceMeasureInstrumentIndex + j];
  234. if (previousStaffEntry !== undefined && previousStaffEntry.hasTie()) {
  235. if (instrumentDuration.lt(Fraction.plus(previousStaffEntry.Timestamp, previousStaffEntry.calculateMaxNoteLength()))) {
  236. instrumentDuration = Fraction.plus(previousStaffEntry.Timestamp, previousStaffEntry.calculateMaxNoteLength());
  237. break;
  238. }
  239. }
  240. }
  241. }
  242. }
  243. instrumentsDurations.push(instrumentDuration);
  244. }
  245. for (let idx: number = 0, len: number = instrumentsDurations.length; idx < len; ++idx) {
  246. let instrumentsDuration: Fraction = instrumentsDurations[idx];
  247. if (maxDuration.lt(instrumentsDuration)) {
  248. maxDuration = instrumentsDuration;
  249. }
  250. }
  251. return Fraction.max(maxDuration, maxInstDuration);
  252. }
  253. public calculateInstrumentsDuration(musicSheet: MusicSheet, instrumentMaxTieNoteFractions: Fraction[]): Fraction[] {
  254. let instrumentsDurations: Fraction[] = [];
  255. for (let i: number = 0; i < musicSheet.Instruments.length; i++) {
  256. let instrumentDuration: Fraction = new Fraction(0, 1);
  257. let inSourceMeasureInstrumentIndex: number = musicSheet.getGlobalStaffIndexOfFirstStaff(musicSheet.Instruments[i]);
  258. for (let j: number = 0; j < musicSheet.Instruments[i].Staves.length; j++) {
  259. let lastStaffEntry: SourceStaffEntry = this.getLastSourceStaffEntryForInstrument(inSourceMeasureInstrumentIndex + j);
  260. if (lastStaffEntry !== undefined && lastStaffEntry.Timestamp !== undefined) {
  261. if (instrumentDuration.lt(Fraction.plus(lastStaffEntry.Timestamp, lastStaffEntry.calculateMaxNoteLength()))) {
  262. instrumentDuration = Fraction.plus(lastStaffEntry.Timestamp, lastStaffEntry.calculateMaxNoteLength());
  263. }
  264. }
  265. }
  266. if (instrumentDuration.lt(instrumentMaxTieNoteFractions[i])) {
  267. instrumentDuration = instrumentMaxTieNoteFractions[i];
  268. }
  269. instrumentsDurations.push(instrumentDuration);
  270. }
  271. return instrumentsDurations;
  272. }
  273. public getEntriesPerStaff(staffIndex: number): SourceStaffEntry[] {
  274. let sourceStaffEntries: SourceStaffEntry[] = [];
  275. for (let container of this.VerticalSourceStaffEntryContainers) {
  276. let sse: SourceStaffEntry = container.StaffEntries[staffIndex];
  277. if (sse !== undefined) { sourceStaffEntries.push(sse); }
  278. }
  279. return sourceStaffEntries;
  280. }
  281. private getLastSourceStaffEntryForInstrument(instrumentIndex: number): SourceStaffEntry {
  282. for (let i: number = this.verticalSourceStaffEntryContainers.length - 1; i >= 0; i--) {
  283. if (this.verticalSourceStaffEntryContainers[i][instrumentIndex] !== undefined) {
  284. return this.verticalSourceStaffEntryContainers[i][instrumentIndex];
  285. }
  286. }
  287. //return undefined;
  288. }
  289. }