SourceMeasure.ts 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417
  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. import {KeyInstruction} from "./Instructions/KeyInstruction";
  12. import {AbstractNotationInstruction} from "./Instructions/AbstractNotationInstruction";
  13. import {Repetition} from "../MusicSource/Repetition";
  14. import {BaseIdClass} from "../../Util/BaseIdClass";
  15. export class SourceMeasure extends BaseIdClass {
  16. constructor(completeNumberOfStaves: number) {
  17. super();
  18. this.completeNumberOfStaves = completeNumberOfStaves;
  19. this.implicitMeasure = false;
  20. this.breakSystemAfter = false;
  21. this.endsPiece = false;
  22. this.firstInstructionsStaffEntries = new Array(completeNumberOfStaves);
  23. this.lastInstructionsStaffEntries = new Array(completeNumberOfStaves);
  24. for (let i: number = 0; i < completeNumberOfStaves; i++) {
  25. this.staffMeasureErrors.push(false);
  26. this.staffLinkedExpressions.push([]);
  27. }
  28. }
  29. public measureListIndex: number;
  30. public endsPiece: boolean;
  31. private measureNumber: number;
  32. private absoluteTimestamp: Fraction;
  33. private completeNumberOfStaves: number;
  34. private duration: Fraction;
  35. private staffLinkedExpressions: MultiExpression[][] = [];
  36. private tempoExpressions: MultiTempoExpression[] = [];
  37. private verticalSourceStaffEntryContainers: VerticalSourceStaffEntryContainer[] = [];
  38. private implicitMeasure: boolean;
  39. private breakSystemAfter: boolean;
  40. private staffMeasureErrors: boolean[] = [];
  41. private firstInstructionsStaffEntries: SourceStaffEntry[];
  42. private lastInstructionsStaffEntries: SourceStaffEntry[];
  43. private firstRepetitionInstructions: RepetitionInstruction[] = [];
  44. private lastRepetitionInstructions: RepetitionInstruction[] = [];
  45. public get MeasureNumber(): number {
  46. return this.measureNumber;
  47. }
  48. public set MeasureNumber(value: number) {
  49. this.measureNumber = value;
  50. }
  51. public get AbsoluteTimestamp(): Fraction {
  52. return this.absoluteTimestamp;
  53. }
  54. public set AbsoluteTimestamp(value: Fraction) {
  55. this.absoluteTimestamp = value;
  56. }
  57. public get CompleteNumberOfStaves(): number {
  58. return this.completeNumberOfStaves;
  59. }
  60. public get Duration(): Fraction {
  61. return this.duration;
  62. }
  63. public set Duration(value: Fraction) {
  64. this.duration = value;
  65. }
  66. public get ImplicitMeasure(): boolean {
  67. return this.implicitMeasure;
  68. }
  69. public set ImplicitMeasure(value: boolean) {
  70. this.implicitMeasure = value;
  71. }
  72. public get BreakSystemAfter(): boolean {
  73. return this.breakSystemAfter;
  74. }
  75. public set BreakSystemAfter(value: boolean) {
  76. this.breakSystemAfter = value;
  77. }
  78. public get StaffLinkedExpressions(): MultiExpression[][] {
  79. return this.staffLinkedExpressions;
  80. }
  81. public get TempoExpressions(): MultiTempoExpression[] {
  82. return this.tempoExpressions;
  83. }
  84. public get VerticalSourceStaffEntryContainers(): VerticalSourceStaffEntryContainer[] {
  85. return this.verticalSourceStaffEntryContainers;
  86. }
  87. public get FirstInstructionsStaffEntries(): SourceStaffEntry[] {
  88. return this.firstInstructionsStaffEntries;
  89. }
  90. public get LastInstructionsStaffEntries(): SourceStaffEntry[] {
  91. return this.lastInstructionsStaffEntries;
  92. }
  93. public get FirstRepetitionInstructions(): RepetitionInstruction[] {
  94. return this.firstRepetitionInstructions;
  95. }
  96. public get LastRepetitionInstructions(): RepetitionInstruction[] {
  97. return this.lastRepetitionInstructions;
  98. }
  99. public getErrorInMeasure(staffIndex: number): boolean {
  100. return this.staffMeasureErrors[staffIndex];
  101. }
  102. public setErrorInStaffMeasure(staffIndex: number, hasError: boolean): void {
  103. this.staffMeasureErrors[staffIndex] = hasError;
  104. }
  105. public getNextMeasure(measures: SourceMeasure[]): SourceMeasure {
  106. return measures[this.measureListIndex + 1];
  107. }
  108. public getPreviousMeasure(measures: SourceMeasure[]): SourceMeasure {
  109. if (this.measureListIndex > 1) {
  110. return measures[this.measureListIndex - 1];
  111. }
  112. return undefined;
  113. }
  114. public findOrCreateStaffEntry(inMeasureTimestamp: Fraction, inSourceMeasureStaffIndex: number,
  115. staff: Staff): {createdNewContainer: boolean, staffEntry: SourceStaffEntry} {
  116. // FIXME Andrea: debug & Test
  117. let staffEntry: SourceStaffEntry = undefined;
  118. // Find:
  119. let existingVerticalSourceStaffEntryContainer: VerticalSourceStaffEntryContainer;
  120. for (let container of this.verticalSourceStaffEntryContainers) {
  121. if (container.Timestamp.Equals(inMeasureTimestamp)) {
  122. existingVerticalSourceStaffEntryContainer = container;
  123. break;
  124. }
  125. }
  126. if (existingVerticalSourceStaffEntryContainer !== undefined) {
  127. if (existingVerticalSourceStaffEntryContainer.StaffEntries[inSourceMeasureStaffIndex] !== undefined) {
  128. staffEntry = existingVerticalSourceStaffEntryContainer.StaffEntries[inSourceMeasureStaffIndex];
  129. } else {
  130. staffEntry = new SourceStaffEntry(existingVerticalSourceStaffEntryContainer, staff);
  131. existingVerticalSourceStaffEntryContainer.StaffEntries[inSourceMeasureStaffIndex] = staffEntry;
  132. }
  133. return {createdNewContainer: false, staffEntry: staffEntry};
  134. }
  135. let last: VerticalSourceStaffEntryContainer = this.verticalSourceStaffEntryContainers[this.verticalSourceStaffEntryContainers.length - 1];
  136. if (this.verticalSourceStaffEntryContainers.length === 0 || last.Timestamp.lt(inMeasureTimestamp)) {
  137. let container: VerticalSourceStaffEntryContainer = new VerticalSourceStaffEntryContainer(
  138. this, inMeasureTimestamp.clone(), this.completeNumberOfStaves
  139. );
  140. this.verticalSourceStaffEntryContainers.push(container);
  141. staffEntry = new SourceStaffEntry(container, staff);
  142. container.StaffEntries[inSourceMeasureStaffIndex] = staffEntry;
  143. } else {
  144. for (
  145. let i: number = this.verticalSourceStaffEntryContainers.length - 1;
  146. i >= 0; i--
  147. ) {
  148. if (this.verticalSourceStaffEntryContainers[i].Timestamp.lt(inMeasureTimestamp)) {
  149. let container: VerticalSourceStaffEntryContainer = new VerticalSourceStaffEntryContainer(
  150. this, inMeasureTimestamp.clone(), this.completeNumberOfStaves
  151. );
  152. this.verticalSourceStaffEntryContainers.splice(i + 1, 0, container);
  153. staffEntry = new SourceStaffEntry(container, staff);
  154. container.StaffEntries[inSourceMeasureStaffIndex] = staffEntry;
  155. break;
  156. }
  157. if (i === 0) {
  158. let container: VerticalSourceStaffEntryContainer = new VerticalSourceStaffEntryContainer(
  159. this, inMeasureTimestamp.clone(), this.completeNumberOfStaves
  160. );
  161. this.verticalSourceStaffEntryContainers.splice(i, 0, container);
  162. staffEntry = new SourceStaffEntry(container, staff);
  163. container.StaffEntries[inSourceMeasureStaffIndex] = staffEntry;
  164. break;
  165. }
  166. }
  167. }
  168. //Logging.debug("created new container: ", staffEntry, this.verticalSourceStaffEntryContainers);
  169. return {createdNewContainer: true, staffEntry: staffEntry};
  170. }
  171. public findOrCreateVoiceEntry(sse: SourceStaffEntry, voice: Voice): { createdVoiceEntry: boolean, voiceEntry: VoiceEntry } {
  172. let ve: VoiceEntry = undefined;
  173. let createdNewVoiceEntry: boolean = false;
  174. for (let voiceEntry of sse.VoiceEntries) {
  175. if (voiceEntry.ParentVoice === voice) {
  176. ve = voiceEntry;
  177. break;
  178. }
  179. }
  180. if (ve === undefined) {
  181. ve = new VoiceEntry(sse.Timestamp, voice, sse);
  182. sse.VoiceEntries.push(ve);
  183. createdNewVoiceEntry = true;
  184. }
  185. return {createdVoiceEntry: createdNewVoiceEntry, voiceEntry: ve};
  186. }
  187. public getPreviousSourceStaffEntryFromIndex(verticalIndex: number, horizontalIndex: number): SourceStaffEntry {
  188. for (let i: number = horizontalIndex - 1; i >= 0; i--) {
  189. if (this.verticalSourceStaffEntryContainers[i][verticalIndex] !== undefined) {
  190. return this.verticalSourceStaffEntryContainers[i][verticalIndex];
  191. }
  192. }
  193. return undefined;
  194. }
  195. public getVerticalContainerIndexByTimestamp(musicTimestamp: Fraction): number {
  196. for (let idx: number = 0, len: number = this.VerticalSourceStaffEntryContainers.length; idx < len; ++idx) {
  197. if (this.VerticalSourceStaffEntryContainers[idx].Timestamp.Equals(musicTimestamp)) {
  198. return idx; // this.verticalSourceStaffEntryContainers.indexOf(verticalSourceStaffEntryContainer);
  199. }
  200. }
  201. return -1;
  202. }
  203. public getVerticalContainerByTimestamp(musicTimestamp: Fraction): VerticalSourceStaffEntryContainer {
  204. for (let idx: number = 0, len: number = this.VerticalSourceStaffEntryContainers.length; idx < len; ++idx) {
  205. let verticalSourceStaffEntryContainer: VerticalSourceStaffEntryContainer = this.VerticalSourceStaffEntryContainers[idx];
  206. if (verticalSourceStaffEntryContainer.Timestamp.Equals(musicTimestamp)) {
  207. return verticalSourceStaffEntryContainer;
  208. }
  209. }
  210. return undefined;
  211. }
  212. public checkForEmptyVerticalContainer(index: number): void {
  213. let undefinedCounter: number = 0;
  214. for (let i: number = 0; i < this.completeNumberOfStaves; i++) {
  215. if (this.verticalSourceStaffEntryContainers[index][i] === undefined) {
  216. undefinedCounter++;
  217. }
  218. }
  219. if (undefinedCounter === this.completeNumberOfStaves) {
  220. this.verticalSourceStaffEntryContainers.splice(index, 1);
  221. }
  222. }
  223. public reverseCheck(musicSheet: MusicSheet, maxInstDuration: Fraction): Fraction {
  224. let maxDuration: Fraction = new Fraction(0, 1);
  225. let instrumentsDurations: Fraction[] = [];
  226. for (let i: number = 0; i < musicSheet.Instruments.length; i++) {
  227. let instrumentDuration: Fraction = new Fraction(0, 1);
  228. let inSourceMeasureInstrumentIndex: number = musicSheet.getGlobalStaffIndexOfFirstStaff(musicSheet.Instruments[i]);
  229. for (let j: number = 0; j < musicSheet.Instruments[i].Staves.length; j++) {
  230. let lastStaffEntry: SourceStaffEntry = this.getLastSourceStaffEntryForInstrument(inSourceMeasureInstrumentIndex + j);
  231. if (lastStaffEntry !== undefined && !lastStaffEntry.hasTie()) {
  232. let verticalContainerIndex: number = this.verticalSourceStaffEntryContainers.indexOf(lastStaffEntry.VerticalContainerParent);
  233. for (let m: number = verticalContainerIndex - 1; m >= 0; m--) {
  234. let previousStaffEntry: SourceStaffEntry = this.verticalSourceStaffEntryContainers[m][inSourceMeasureInstrumentIndex + j];
  235. if (previousStaffEntry !== undefined && previousStaffEntry.hasTie()) {
  236. if (instrumentDuration.lt(Fraction.plus(previousStaffEntry.Timestamp, previousStaffEntry.calculateMaxNoteLength()))) {
  237. instrumentDuration = Fraction.plus(previousStaffEntry.Timestamp, previousStaffEntry.calculateMaxNoteLength());
  238. break;
  239. }
  240. }
  241. }
  242. }
  243. }
  244. instrumentsDurations.push(instrumentDuration);
  245. }
  246. for (let idx: number = 0, len: number = instrumentsDurations.length; idx < len; ++idx) {
  247. let instrumentsDuration: Fraction = instrumentsDurations[idx];
  248. if (maxDuration.lt(instrumentsDuration)) {
  249. maxDuration = instrumentsDuration;
  250. }
  251. }
  252. return Fraction.max(maxDuration, maxInstDuration);
  253. }
  254. public calculateInstrumentsDuration(musicSheet: MusicSheet, instrumentMaxTieNoteFractions: Fraction[]): Fraction[] {
  255. let instrumentsDurations: Fraction[] = [];
  256. for (let i: number = 0; i < musicSheet.Instruments.length; i++) {
  257. let instrumentDuration: Fraction = new Fraction(0, 1);
  258. let inSourceMeasureInstrumentIndex: number = musicSheet.getGlobalStaffIndexOfFirstStaff(musicSheet.Instruments[i]);
  259. for (let j: number = 0; j < musicSheet.Instruments[i].Staves.length; j++) {
  260. let lastStaffEntry: SourceStaffEntry = this.getLastSourceStaffEntryForInstrument(inSourceMeasureInstrumentIndex + j);
  261. if (lastStaffEntry !== undefined && lastStaffEntry.Timestamp !== undefined) {
  262. if (instrumentDuration.lt(Fraction.plus(lastStaffEntry.Timestamp, lastStaffEntry.calculateMaxNoteLength()))) {
  263. instrumentDuration = Fraction.plus(lastStaffEntry.Timestamp, lastStaffEntry.calculateMaxNoteLength());
  264. }
  265. }
  266. }
  267. if (instrumentDuration.lt(instrumentMaxTieNoteFractions[i])) {
  268. instrumentDuration = instrumentMaxTieNoteFractions[i];
  269. }
  270. instrumentsDurations.push(instrumentDuration);
  271. }
  272. return instrumentsDurations;
  273. }
  274. public getEntriesPerStaff(staffIndex: number): SourceStaffEntry[] {
  275. let sourceStaffEntries: SourceStaffEntry[] = [];
  276. for (let container of this.VerticalSourceStaffEntryContainers) {
  277. let sse: SourceStaffEntry = container.StaffEntries[staffIndex];
  278. if (sse !== undefined) {
  279. sourceStaffEntries.push(sse);
  280. }
  281. }
  282. return sourceStaffEntries;
  283. }
  284. public hasBeginInstructions(): boolean {
  285. for (let staffIndex: number = 0, len: number = this.FirstInstructionsStaffEntries.length; staffIndex < len; staffIndex++) {
  286. let beginInstructionsStaffEntry: SourceStaffEntry = this.FirstInstructionsStaffEntries[staffIndex];
  287. if (beginInstructionsStaffEntry !== undefined && beginInstructionsStaffEntry.Instructions.length > 0) {
  288. return true;
  289. }
  290. }
  291. return false;
  292. }
  293. public beginsWithLineRepetition(): boolean {
  294. for (let idx: number = 0, len: number = this.FirstRepetitionInstructions.length; idx < len; ++idx) {
  295. let instr: RepetitionInstruction = this.FirstRepetitionInstructions[idx];
  296. if (instr.parentRepetition !== undefined && instr === instr.parentRepetition.startMarker && !instr.parentRepetition.FromWords) {
  297. return true;
  298. }
  299. }
  300. return false;
  301. }
  302. public endsWithLineRepetition(): boolean {
  303. for (let idx: number = 0, len: number = this.LastRepetitionInstructions.length; idx < len; ++idx) {
  304. let instruction: RepetitionInstruction = this.LastRepetitionInstructions[idx];
  305. let rep: Repetition = instruction.parentRepetition;
  306. if (rep === undefined) {
  307. continue;
  308. }
  309. if (rep.FromWords) {
  310. continue;
  311. }
  312. for (let idx2: number = 0, len2: number = rep.BackwardJumpInstructions.length; idx2 < len2; ++idx2) {
  313. let backJumpInstruction: RepetitionInstruction = rep.BackwardJumpInstructions[idx2];
  314. if (instruction === backJumpInstruction) {
  315. return true;
  316. }
  317. }
  318. }
  319. return false;
  320. }
  321. public beginsWithWordRepetition(): boolean {
  322. for (let idx: number = 0, len: number = this.FirstRepetitionInstructions.length; idx < len; ++idx) {
  323. let instruction: RepetitionInstruction = this.FirstRepetitionInstructions[idx];
  324. if (instruction.parentRepetition !== undefined &&
  325. instruction === instruction.parentRepetition.startMarker && instruction.parentRepetition.FromWords) {
  326. return true;
  327. }
  328. }
  329. return false;
  330. }
  331. public endsWithWordRepetition(): boolean {
  332. for (let idx: number = 0, len: number = this.LastRepetitionInstructions.length; idx < len; ++idx) {
  333. let instruction: RepetitionInstruction = this.LastRepetitionInstructions[idx];
  334. let rep: Repetition = instruction.parentRepetition;
  335. if (rep === undefined) {
  336. continue;
  337. }
  338. if (!rep.FromWords) {
  339. continue;
  340. }
  341. for (let idx2: number = 0, len2: number = rep.BackwardJumpInstructions.length; idx2 < len2; ++idx2) {
  342. let backJumpInstruction: RepetitionInstruction = rep.BackwardJumpInstructions[idx2];
  343. if (instruction === backJumpInstruction) {
  344. return true;
  345. }
  346. }
  347. if (instruction === rep.forwardJumpInstruction) {
  348. return true;
  349. }
  350. }
  351. return false;
  352. }
  353. public getKeyInstruction(staffIndex: number): KeyInstruction {
  354. if (this.FirstInstructionsStaffEntries[staffIndex] !== undefined) {
  355. let sourceStaffEntry: SourceStaffEntry = this.FirstInstructionsStaffEntries[staffIndex];
  356. for (let idx: number = 0, len: number = sourceStaffEntry.Instructions.length; idx < len; ++idx) {
  357. let abstractNotationInstruction: AbstractNotationInstruction = sourceStaffEntry.Instructions[idx];
  358. if (abstractNotationInstruction instanceof KeyInstruction) {
  359. return <KeyInstruction>abstractNotationInstruction;
  360. }
  361. }
  362. }
  363. return undefined;
  364. }
  365. private getLastSourceStaffEntryForInstrument(instrumentIndex: number): SourceStaffEntry {
  366. let entry: SourceStaffEntry;
  367. for (let i: number = this.verticalSourceStaffEntryContainers.length - 1; i >= 0; i--) {
  368. entry = this.verticalSourceStaffEntryContainers[i].StaffEntries[instrumentIndex];
  369. if (entry) {
  370. break;
  371. }
  372. }
  373. return entry;
  374. }
  375. }