MusicSystemBuilder.ts 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798
  1. import {StaffMeasure} from "./StaffMeasure";
  2. import {GraphicalMusicPage} from "./GraphicalMusicPage";
  3. import {EngravingRules} from "./EngravingRules";
  4. import {RhythmInstruction} from "../VoiceData/Instructions/RhythmInstruction";
  5. import {KeyInstruction} from "../VoiceData/Instructions/KeyInstruction";
  6. import {ClefInstruction} from "../VoiceData/Instructions/ClefInstruction";
  7. import {SourceMeasure} from "../VoiceData/SourceMeasure";
  8. import {MusicSystem} from "./MusicSystem";
  9. import {BoundingBox} from "./BoundingBox";
  10. import {Staff} from "../VoiceData/Staff";
  11. import {Instrument} from "../Instrument";
  12. import {PointF2D} from "../../Common/DataObjects/PointF2D";
  13. import {StaffLine} from "./StaffLine";
  14. import {GraphicalLine} from "./GraphicalLine";
  15. import {SourceStaffEntry} from "../VoiceData/SourceStaffEntry";
  16. import {AbstractNotationInstruction} from "../VoiceData/Instructions/AbstractNotationInstruction";
  17. import {SystemLinesEnum} from "./SystemLinesEnum";
  18. import {GraphicalMusicSheet} from "./GraphicalMusicSheet";
  19. import {IGraphicalSymbolFactory} from "../Interfaces/IGraphicalSymbolFactory";
  20. import {MusicSheetCalculator} from "./MusicSheetCalculator";
  21. import {MidiInstrument} from "../VoiceData/Instructions/ClefInstruction";
  22. import {CollectionUtil} from "../../Util/collectionUtil";
  23. import {SystemLinePosition} from "./SystemLinePosition";
  24. export class MusicSystemBuilder {
  25. private measureList: StaffMeasure[][];
  26. private graphicalMusicSheet: GraphicalMusicSheet;
  27. private currentMusicPage: GraphicalMusicPage;
  28. private currentPageHeight: number;
  29. private currentSystemParams: SystemBuildParameters;
  30. private numberOfVisibleStaffLines: number;
  31. private rules: EngravingRules;
  32. private measureListIndex: number;
  33. private visibleStaffIndices: number[];
  34. private activeRhythm: RhythmInstruction[];
  35. private activeKeys: KeyInstruction[];
  36. private activeClefs: ClefInstruction[];
  37. private globalSystemIndex: number = 0;
  38. private leadSheet: boolean = false;
  39. private symbolFactory: IGraphicalSymbolFactory;
  40. public initialize(
  41. graphicalMusicSheet: GraphicalMusicSheet, measureList: StaffMeasure[][], numberOfStaffLines: number, symbolFactory: IGraphicalSymbolFactory
  42. ): void {
  43. this.leadSheet = graphicalMusicSheet.LeadSheet;
  44. this.graphicalMusicSheet = graphicalMusicSheet;
  45. this.rules = this.graphicalMusicSheet.ParentMusicSheet.rules;
  46. this.measureList = measureList;
  47. this.symbolFactory = symbolFactory;
  48. this.currentMusicPage = this.createMusicPage();
  49. this.currentPageHeight = 0.0;
  50. this.numberOfVisibleStaffLines = numberOfStaffLines;
  51. this.activeRhythm = new Array(this.numberOfVisibleStaffLines);
  52. this.activeKeys = new Array(this.numberOfVisibleStaffLines);
  53. this.activeClefs = new Array(this.numberOfVisibleStaffLines);
  54. this.initializeActiveInstructions(this.measureList[0]);
  55. }
  56. public buildMusicSystems(): void {
  57. let previousMeasureEndsSystem: boolean = false;
  58. let systemMaxWidth: number = this.getFullPageSystemWidth();
  59. this.measureListIndex = 0;
  60. this.currentSystemParams = new SystemBuildParameters();
  61. this.currentSystemParams.currentSystem = this.initMusicSystem();
  62. this.layoutSystemStaves();
  63. this.currentSystemParams.currentSystem.createMusicSystemLabel(
  64. this.rules.InstrumentLabelTextHeight,
  65. this.rules.SystemLabelsRightMargin,
  66. this.rules.LabelMarginBorderFactor
  67. );
  68. this.currentPageHeight += this.currentSystemParams.currentSystem.PositionAndShape.RelativePosition.y;
  69. let numberOfMeasures: number = 0;
  70. for (let idx: number = 0, len: number = this.measureList.length; idx < len; ++idx) {
  71. if (this.measureList[idx].length > 0) {
  72. numberOfMeasures++;
  73. }
  74. }
  75. while (this.measureListIndex < numberOfMeasures) {
  76. let staffMeasures: StaffMeasure[] = this.measureList[this.measureListIndex];
  77. for (let idx: number = 0, len: number = staffMeasures.length; idx < len; ++idx) {
  78. staffMeasures[idx].resetLayout();
  79. }
  80. let sourceMeasure: SourceMeasure = staffMeasures[0].parentSourceMeasure;
  81. let sourceMeasureEndsSystem: boolean = sourceMeasure.BreakSystemAfter;
  82. let isSystemStartMeasure: boolean = this.currentSystemParams.IsSystemStartMeasure();
  83. let isFirstSourceMeasure: boolean = sourceMeasure === this.graphicalMusicSheet.ParentMusicSheet.getFirstSourceMeasure();
  84. let currentMeasureBeginInstructionsWidth: number = this.rules.MeasureLeftMargin;
  85. let currentMeasureEndInstructionsWidth: number = 0;
  86. let measureStartLine: SystemLinesEnum = this.getMeasureStartLine();
  87. currentMeasureBeginInstructionsWidth += this.getLineWidth(staffMeasures[0], measureStartLine, isSystemStartMeasure);
  88. if (!this.leadSheet) {
  89. currentMeasureBeginInstructionsWidth += this.addBeginInstructions(staffMeasures, isSystemStartMeasure, isFirstSourceMeasure);
  90. currentMeasureEndInstructionsWidth += this.addEndInstructions(staffMeasures);
  91. }
  92. let currentMeasureVarWidth: number = 0;
  93. for (let i: number = 0; i < this.numberOfVisibleStaffLines; i++) {
  94. currentMeasureVarWidth = Math.max(currentMeasureVarWidth, staffMeasures[i].minimumStaffEntriesWidth);
  95. }
  96. let measureEndLine: SystemLinesEnum = this.getMeasureEndLine();
  97. currentMeasureEndInstructionsWidth += this.getLineWidth(staffMeasures[0], measureEndLine, isSystemStartMeasure);
  98. let nextMeasureBeginInstructionWidth: number = this.rules.MeasureLeftMargin;
  99. if (this.measureListIndex + 1 < this.measureList.length) {
  100. let nextStaffMeasures: StaffMeasure[] = this.measureList[this.measureListIndex + 1];
  101. let nextSourceMeasure: SourceMeasure = nextStaffMeasures[0].parentSourceMeasure;
  102. if (nextSourceMeasure.hasBeginInstructions()) {
  103. nextMeasureBeginInstructionWidth += this.addBeginInstructions(nextStaffMeasures, false, false);
  104. }
  105. }
  106. let totalMeasureWidth: number = currentMeasureBeginInstructionsWidth + currentMeasureEndInstructionsWidth + currentMeasureVarWidth;
  107. let measureFitsInSystem: boolean = this.currentSystemParams.currentWidth + totalMeasureWidth + nextMeasureBeginInstructionWidth < systemMaxWidth;
  108. if (isSystemStartMeasure || measureFitsInSystem) {
  109. this.addMeasureToSystem(
  110. staffMeasures, measureStartLine, measureEndLine, totalMeasureWidth,
  111. currentMeasureBeginInstructionsWidth, currentMeasureVarWidth, currentMeasureEndInstructionsWidth
  112. );
  113. this.updateActiveClefs(sourceMeasure, staffMeasures);
  114. this.measureListIndex++;
  115. } else {
  116. this.finalizeCurrentAndCreateNewSystem(staffMeasures, previousMeasureEndsSystem);
  117. }
  118. previousMeasureEndsSystem = sourceMeasureEndsSystem;
  119. }
  120. this.finalizeCurrentAndCreateNewSystem(this.measureList[this.measureList.length - 1], true);
  121. }
  122. private setMeasureWidth(staffMeasures: StaffMeasure[], width: number, beginInstrWidth: number, endInstrWidth: number): void {
  123. for (let idx: number = 0, len: number = staffMeasures.length; idx < len; ++idx) {
  124. let measure: StaffMeasure = staffMeasures[idx];
  125. measure.setWidth(width);
  126. if (beginInstrWidth > 0) {
  127. measure.beginInstructionsWidth = beginInstrWidth;
  128. }
  129. if (endInstrWidth > 0) {
  130. measure.endInstructionsWidth = endInstrWidth;
  131. }
  132. }
  133. }
  134. private finalizeCurrentAndCreateNewSystem(measures: StaffMeasure[], isPartEndingSystem: boolean = false): void {
  135. this.adaptRepetitionLineWithIfNeeded();
  136. if (!isPartEndingSystem) {
  137. this.checkAndCreateExtraInstructionMeasure(measures);
  138. }
  139. this.stretchMusicSystem(isPartEndingSystem);
  140. if (this.currentPageHeight + this.currentSystemParams.currentSystem.PositionAndShape.Size.height + this.rules.SystemDistance <= this.rules.PageHeight) {
  141. this.currentPageHeight += this.currentSystemParams.currentSystem.PositionAndShape.Size.height + this.rules.SystemDistance;
  142. if (
  143. this.currentPageHeight + this.currentSystemParams.currentSystem.PositionAndShape.Size.height
  144. + this.rules.SystemDistance >= this.rules.PageHeight
  145. ) {
  146. this.currentMusicPage = this.createMusicPage();
  147. this.currentPageHeight = this.rules.PageTopMargin + this.rules.TitleTopDistance;
  148. }
  149. } else {
  150. this.currentMusicPage = this.createMusicPage();
  151. this.currentPageHeight = this.rules.PageTopMargin + this.rules.TitleTopDistance;
  152. }
  153. this.currentSystemParams = new SystemBuildParameters();
  154. if (this.measureListIndex < this.measureList.length) {
  155. this.currentSystemParams.currentSystem = this.initMusicSystem();
  156. this.layoutSystemStaves();
  157. }
  158. }
  159. private adaptRepetitionLineWithIfNeeded(): void {
  160. let systemMeasures: MeasureBuildParameters[] = this.currentSystemParams.systemMeasures;
  161. if (systemMeasures.length >= 1) {
  162. let measures: StaffMeasure[] =
  163. this.currentSystemParams.currentSystem.GraphicalMeasures[this.currentSystemParams.currentSystem.GraphicalMeasures.length - 1];
  164. let measureParams: MeasureBuildParameters = systemMeasures[systemMeasures.length - 1];
  165. let diff: number = 0.0;
  166. if (measureParams.endLine === SystemLinesEnum.DotsBoldBoldDots) {
  167. measureParams.endLine = SystemLinesEnum.DotsThinBold;
  168. diff = measures[0].getLineWidth(SystemLinesEnum.DotsBoldBoldDots) / 2 - measures[0].getLineWidth(SystemLinesEnum.DotsThinBold);
  169. }
  170. this.currentSystemParams.currentSystemFixWidth -= diff;
  171. for (let idx: number = 0, len: number = measures.length; idx < len; ++idx) {
  172. let measure: StaffMeasure = measures[idx];
  173. measure.endInstructionsWidth -= diff;
  174. }
  175. }
  176. }
  177. private addMeasureToSystem(
  178. staffMeasures: StaffMeasure[], measureStartLine: SystemLinesEnum, measureEndLine: SystemLinesEnum,
  179. totalMeasureWidth: number, currentMeasureBeginInstructionsWidth: number, currentVarWidth: number, currentMeasureEndInstructionsWidth: number
  180. ): void {
  181. this.currentSystemParams.systemMeasures.push({beginLine: measureStartLine, endLine: measureEndLine});
  182. this.setMeasureWidth(
  183. staffMeasures, totalMeasureWidth, currentMeasureBeginInstructionsWidth, currentMeasureEndInstructionsWidth
  184. );
  185. this.addStaveMeasuresToSystem(staffMeasures);
  186. this.currentSystemParams.currentWidth += totalMeasureWidth;
  187. this.currentSystemParams.currentSystemFixWidth += currentMeasureBeginInstructionsWidth + currentMeasureEndInstructionsWidth;
  188. this.currentSystemParams.currentSystemVarWidth += currentVarWidth;
  189. this.currentSystemParams.systemMeasureIndex++;
  190. }
  191. private createMusicPage(): GraphicalMusicPage {
  192. let page: GraphicalMusicPage = new GraphicalMusicPage(this.graphicalMusicSheet);
  193. this.graphicalMusicSheet.MusicPages.push(page);
  194. page.PositionAndShape.BorderLeft = 0.0;
  195. page.PositionAndShape.BorderRight = this.graphicalMusicSheet.ParentMusicSheet.pageWidth;
  196. page.PositionAndShape.BorderTop = 0.0;
  197. page.PositionAndShape.BorderBottom = this.rules.PageHeight;
  198. page.PositionAndShape.RelativePosition = new PointF2D(0.0, 0.0);
  199. return page;
  200. }
  201. private initMusicSystem(): MusicSystem {
  202. let musicSystem: MusicSystem = this.symbolFactory.createMusicSystem(this.currentMusicPage, this.globalSystemIndex++);
  203. this.currentMusicPage.MusicSystems.push(musicSystem);
  204. let boundingBox: BoundingBox = musicSystem.PositionAndShape;
  205. this.currentMusicPage.PositionAndShape.ChildElements.push(boundingBox);
  206. return musicSystem;
  207. }
  208. private getFullPageSystemWidth(): number {
  209. return this.currentMusicPage.PositionAndShape.Size.width - this.rules.PageLeftMargin
  210. - this.rules.PageRightMargin - this.rules.SystemLeftMargin - this.rules.SystemRightMargin;
  211. }
  212. private layoutSystemStaves(): void {
  213. let systemWidth: number = this.getFullPageSystemWidth();
  214. let musicSystem: MusicSystem = this.currentSystemParams.currentSystem;
  215. let boundingBox: BoundingBox = musicSystem.PositionAndShape;
  216. boundingBox.BorderLeft = 0.0;
  217. boundingBox.BorderRight = systemWidth;
  218. boundingBox.BorderTop = 0.0;
  219. let staffList: Staff[] = [];
  220. let instruments: Instrument[] = this.graphicalMusicSheet.ParentMusicSheet.Instruments;
  221. for (let idx: number = 0, len: number = instruments.length; idx < len; ++idx) {
  222. let instrument: Instrument = instruments[idx];
  223. if (instrument.Voices.length === 0 || !instrument.Visible) {
  224. continue;
  225. }
  226. for (let idx2: number = 0, len2: number = instrument.Staves.length; idx2 < len2; ++idx2) {
  227. let staff: Staff = instrument.Staves[idx2];
  228. staffList.push(staff);
  229. }
  230. }
  231. let multiLyrics: boolean = false;
  232. if (this.leadSheet) {
  233. for (let idx: number = 0, len: number = staffList.length; idx < len; ++idx) {
  234. let staff: Staff = staffList[idx];
  235. if (staff.ParentInstrument.LyricVersesNumbers.length > 1) {
  236. multiLyrics = true;
  237. break;
  238. }
  239. }
  240. }
  241. let yOffsetSum: number = 0;
  242. for (let i: number = 0; i < staffList.length; i++) {
  243. this.addStaffLineToMusicSystem(musicSystem, yOffsetSum, staffList[i]);
  244. yOffsetSum += this.rules.StaffHeight;
  245. if (i + 1 < staffList.length) {
  246. let yOffset: number = 0;
  247. if (this.leadSheet && !multiLyrics) {
  248. yOffset = 2.5;
  249. } else {
  250. if (staffList[i].ParentInstrument === staffList[i + 1].ParentInstrument) {
  251. yOffset = this.rules.BetweenStaffDistance;
  252. } else {
  253. yOffset = this.rules.StaffDistance;
  254. }
  255. }
  256. yOffsetSum += yOffset;
  257. }
  258. }
  259. boundingBox.BorderBottom = yOffsetSum;
  260. }
  261. private addStaffLineToMusicSystem(musicSystem: MusicSystem, relativeYPosition: number, staff: Staff): void {
  262. if (musicSystem !== undefined) {
  263. let staffLine: StaffLine = this.symbolFactory.createStaffLine(musicSystem, staff);
  264. musicSystem.StaffLines.push(staffLine);
  265. let boundingBox: BoundingBox = staffLine.PositionAndShape;
  266. musicSystem.PositionAndShape.ChildElements.push(boundingBox);
  267. let relativePosition: PointF2D = new PointF2D();
  268. if (musicSystem.Parent.MusicSystems[0] === musicSystem && musicSystem.Parent === musicSystem.Parent.Parent.MusicPages[0]) {
  269. relativePosition.x = this.rules.FirstSystemMargin;
  270. } else {
  271. relativePosition.x = 0.0;
  272. }
  273. relativePosition.y = relativeYPosition;
  274. boundingBox.RelativePosition = relativePosition;
  275. if (musicSystem.Parent.MusicSystems[0] === musicSystem && musicSystem.Parent === musicSystem.Parent.Parent.MusicPages[0]) {
  276. boundingBox.BorderRight = musicSystem.PositionAndShape.Size.width - this.rules.FirstSystemMargin;
  277. } else {
  278. boundingBox.BorderRight = musicSystem.PositionAndShape.Size.width;
  279. }
  280. boundingBox.BorderLeft = 0.0;
  281. boundingBox.BorderTop = 0.0;
  282. boundingBox.BorderBottom = this.rules.StaffHeight;
  283. for (let i: number = 0; i < 5; i++) {
  284. let start: PointF2D = new PointF2D();
  285. start.x = 0.0;
  286. start.y = i * this.rules.StaffHeight / 4;
  287. let end: PointF2D = new PointF2D();
  288. end.x = staffLine.PositionAndShape.Size.width;
  289. end.y = i * this.rules.StaffHeight / 4;
  290. if (this.leadSheet) {
  291. start.y = end.y = 0;
  292. }
  293. staffLine.StaffLines[i] = new GraphicalLine(start, end, this.rules.StaffLineWidth);
  294. }
  295. }
  296. }
  297. private initializeActiveInstructions(measureList: StaffMeasure[]): void {
  298. let firstSourceMeasure: SourceMeasure = this.graphicalMusicSheet.ParentMusicSheet.getFirstSourceMeasure();
  299. if (firstSourceMeasure !== undefined) {
  300. this.visibleStaffIndices = this.graphicalMusicSheet.getVisibleStavesIndecesFromSourceMeasure(measureList);
  301. for (let i: number = 0, len: number = this.visibleStaffIndices.length; i < len; i++) {
  302. let staffIndex: number = this.visibleStaffIndices[i];
  303. let graphicalMeasure: StaffMeasure = this.graphicalMusicSheet.getGraphicalMeasureFromSourceMeasureAndIndex(firstSourceMeasure, staffIndex);
  304. this.activeClefs[i] = <ClefInstruction>firstSourceMeasure.FirstInstructionsStaffEntries[staffIndex].Instructions[0];
  305. let keyInstruction: KeyInstruction = KeyInstruction.copy(
  306. <KeyInstruction>firstSourceMeasure.FirstInstructionsStaffEntries[staffIndex].Instructions[1]);
  307. keyInstruction = this.transposeKeyInstruction(keyInstruction, graphicalMeasure);
  308. this.activeKeys[i] = keyInstruction;
  309. this.activeRhythm[i] = <RhythmInstruction>firstSourceMeasure.FirstInstructionsStaffEntries[staffIndex].Instructions[2];
  310. }
  311. }
  312. }
  313. private transposeKeyInstruction(keyInstruction: KeyInstruction, graphicalMeasure: StaffMeasure): KeyInstruction {
  314. if (this.graphicalMusicSheet.ParentMusicSheet.Transpose !== 0
  315. && graphicalMeasure.ParentStaff.ParentInstrument.MidiInstrumentId !== MidiInstrument.Percussion
  316. && MusicSheetCalculator.transposeCalculator !== undefined
  317. ) {
  318. MusicSheetCalculator.transposeCalculator.transposeKey(
  319. keyInstruction,
  320. this.graphicalMusicSheet.ParentMusicSheet.Transpose
  321. );
  322. }
  323. return keyInstruction;
  324. }
  325. private addBeginInstructions(measures: StaffMeasure[], isSystemFirstMeasure: boolean, isFirstSourceMeasure: boolean): number {
  326. let measureCount: number = measures.length;
  327. if (measureCount === 0) {
  328. return 0;
  329. }
  330. let totalBeginInstructionLengthX: number = 0.0;
  331. let sourceMeasure: SourceMeasure = measures[0].parentSourceMeasure;
  332. for (let idx: number = 0; idx < measureCount; ++idx) {
  333. let measure: StaffMeasure = measures[idx];
  334. let staffIndex: number = this.visibleStaffIndices[idx];
  335. let beginInstructionsStaffEntry: SourceStaffEntry = sourceMeasure.FirstInstructionsStaffEntries[staffIndex];
  336. let beginInstructionLengthX: number = this.AddInstructionsAtMeasureBegin(
  337. beginInstructionsStaffEntry, measure,
  338. idx, isFirstSourceMeasure,
  339. isSystemFirstMeasure
  340. );
  341. totalBeginInstructionLengthX = Math.max(totalBeginInstructionLengthX, beginInstructionLengthX);
  342. }
  343. return totalBeginInstructionLengthX;
  344. }
  345. private addEndInstructions(measures: StaffMeasure[]): number {
  346. let measureCount: number = measures.length;
  347. if (measureCount === 0) {
  348. return 0;
  349. }
  350. let totalEndInstructionLengthX: number = 0.5;
  351. let sourceMeasure: SourceMeasure = measures[0].parentSourceMeasure;
  352. for (let idx: number = 0; idx < measureCount; idx++) {
  353. let measure: StaffMeasure = measures[idx];
  354. let staffIndex: number = this.visibleStaffIndices[idx];
  355. let endInstructionsStaffEntry: SourceStaffEntry = sourceMeasure.LastInstructionsStaffEntries[staffIndex];
  356. let endInstructionLengthX: number = this.addInstructionsAtMeasureEnd(endInstructionsStaffEntry, measure);
  357. totalEndInstructionLengthX = Math.max(totalEndInstructionLengthX, endInstructionLengthX);
  358. }
  359. return totalEndInstructionLengthX;
  360. }
  361. private AddInstructionsAtMeasureBegin(firstEntry: SourceStaffEntry, measure: StaffMeasure,
  362. visibleStaffIdx: number, isFirstSourceMeasure: boolean, isSystemStartMeasure: boolean): number {
  363. let instructionsLengthX: number = 0;
  364. let currentClef: ClefInstruction = undefined;
  365. let currentKey: KeyInstruction = undefined;
  366. let currentRhythm: RhythmInstruction = undefined;
  367. if (firstEntry !== undefined) {
  368. for (let idx: number = 0, len: number = firstEntry.Instructions.length; idx < len; ++idx) {
  369. let abstractNotationInstruction: AbstractNotationInstruction = firstEntry.Instructions[idx];
  370. if (abstractNotationInstruction instanceof ClefInstruction) {
  371. currentClef = <ClefInstruction>abstractNotationInstruction;
  372. } else if (abstractNotationInstruction instanceof KeyInstruction) {
  373. currentKey = <KeyInstruction>abstractNotationInstruction;
  374. } else if (abstractNotationInstruction instanceof RhythmInstruction) {
  375. currentRhythm = <RhythmInstruction>abstractNotationInstruction;
  376. }
  377. }
  378. }
  379. if (isSystemStartMeasure) {
  380. if (currentClef === undefined) {
  381. currentClef = this.activeClefs[visibleStaffIdx];
  382. }
  383. if (currentKey === undefined) {
  384. currentKey = this.activeKeys[visibleStaffIdx];
  385. }
  386. if (isFirstSourceMeasure && currentRhythm === undefined) {
  387. currentRhythm = this.activeRhythm[visibleStaffIdx];
  388. }
  389. }
  390. let clefAdded: boolean = false;
  391. let keyAdded: boolean = false;
  392. let rhythmAdded: boolean = false;
  393. if (currentClef !== undefined) {
  394. measure.addClefAtBegin(currentClef);
  395. clefAdded = true;
  396. } else {
  397. currentClef = this.activeClefs[visibleStaffIdx];
  398. }
  399. if (currentKey !== undefined) {
  400. currentKey = this.transposeKeyInstruction(currentKey, measure);
  401. let previousKey: KeyInstruction = isSystemStartMeasure ? undefined : this.activeKeys[visibleStaffIdx];
  402. measure.addKeyAtBegin(currentKey, previousKey, currentClef);
  403. keyAdded = true;
  404. }
  405. if (currentRhythm !== undefined) {
  406. measure.addRhythmAtBegin(currentRhythm);
  407. rhythmAdded = true;
  408. }
  409. if (clefAdded || keyAdded || rhythmAdded) {
  410. instructionsLengthX += measure.beginInstructionsWidth;
  411. if (rhythmAdded) {
  412. instructionsLengthX += this.rules.RhythmRightMargin;
  413. }
  414. }
  415. return instructionsLengthX;
  416. }
  417. private addInstructionsAtMeasureEnd(lastEntry: SourceStaffEntry, measure: StaffMeasure): number {
  418. if (lastEntry === undefined || lastEntry.Instructions === undefined || lastEntry.Instructions.length === 0) {
  419. return 0;
  420. }
  421. for (let idx: number = 0, len: number = lastEntry.Instructions.length; idx < len; ++idx) {
  422. let abstractNotationInstruction: AbstractNotationInstruction = lastEntry.Instructions[idx];
  423. if (abstractNotationInstruction instanceof ClefInstruction) {
  424. let activeClef: ClefInstruction = <ClefInstruction>abstractNotationInstruction;
  425. measure.addClefAtEnd(activeClef);
  426. }
  427. }
  428. return this.rules.MeasureRightMargin + measure.endInstructionsWidth;
  429. }
  430. private updateActiveClefs(measure: SourceMeasure, staffMeasures: StaffMeasure[]): void {
  431. for (let visStaffIdx: number = 0, len: number = staffMeasures.length; visStaffIdx < len; visStaffIdx++) {
  432. let staffIndex: number = this.visibleStaffIndices[visStaffIdx];
  433. let firstEntry: SourceStaffEntry = measure.FirstInstructionsStaffEntries[staffIndex];
  434. if (firstEntry !== undefined) {
  435. for (let idx: number = 0, len2: number = firstEntry.Instructions.length; idx < len2; ++idx) {
  436. let abstractNotationInstruction: AbstractNotationInstruction = firstEntry.Instructions[idx];
  437. if (abstractNotationInstruction instanceof ClefInstruction) {
  438. this.activeClefs[visStaffIdx] = <ClefInstruction>abstractNotationInstruction;
  439. } else if (abstractNotationInstruction instanceof KeyInstruction) {
  440. this.activeKeys[visStaffIdx] = <KeyInstruction>abstractNotationInstruction;
  441. } else if (abstractNotationInstruction instanceof RhythmInstruction) {
  442. this.activeRhythm[visStaffIdx] = <RhythmInstruction>abstractNotationInstruction;
  443. }
  444. }
  445. }
  446. let entries: SourceStaffEntry[] = measure.getEntriesPerStaff(staffIndex);
  447. for (let idx: number = 0, len2: number = entries.length; idx < len2; ++idx) {
  448. let staffEntry: SourceStaffEntry = entries[idx];
  449. if (staffEntry.Instructions !== undefined) {
  450. for (let idx2: number = 0, len3: number = staffEntry.Instructions.length; idx2 < len3; ++idx2) {
  451. let abstractNotationInstruction: AbstractNotationInstruction = staffEntry.Instructions[idx2];
  452. if (abstractNotationInstruction instanceof ClefInstruction) {
  453. this.activeClefs[visStaffIdx] = <ClefInstruction>abstractNotationInstruction;
  454. }
  455. }
  456. }
  457. }
  458. let lastEntry: SourceStaffEntry = measure.LastInstructionsStaffEntries[staffIndex];
  459. if (lastEntry !== undefined) {
  460. let instructions: AbstractNotationInstruction[] = lastEntry.Instructions;
  461. for (let idx: number = 0, len3: number = instructions.length; idx < len3; ++idx) {
  462. let abstractNotationInstruction: AbstractNotationInstruction = instructions[idx];
  463. if (abstractNotationInstruction instanceof ClefInstruction) {
  464. this.activeClefs[visStaffIdx] = <ClefInstruction>abstractNotationInstruction;
  465. }
  466. }
  467. }
  468. }
  469. }
  470. private checkAndCreateExtraInstructionMeasure(measures: StaffMeasure[]): void {
  471. let firstStaffEntries: SourceStaffEntry[] = measures[0].parentSourceMeasure.FirstInstructionsStaffEntries;
  472. let visibleInstructionEntries: SourceStaffEntry[] = [];
  473. for (let idx: number = 0, len: number = measures.length; idx < len; ++idx) {
  474. let measure: StaffMeasure = measures[idx];
  475. visibleInstructionEntries.push(firstStaffEntries[measure.ParentStaff.idInMusicSheet]);
  476. }
  477. let maxMeasureWidth: number = 0;
  478. for (let visStaffIdx: number = 0, len: number = visibleInstructionEntries.length; visStaffIdx < len; ++visStaffIdx) {
  479. let sse: SourceStaffEntry = visibleInstructionEntries[visStaffIdx];
  480. if (sse === undefined) {
  481. continue;
  482. }
  483. let instructions: AbstractNotationInstruction[] = sse.Instructions;
  484. let keyInstruction: KeyInstruction = undefined;
  485. let rhythmInstruction: RhythmInstruction = undefined;
  486. for (let idx2: number = 0, len2: number = instructions.length; idx2 < len2; ++idx2) {
  487. let instruction: AbstractNotationInstruction = instructions[idx2];
  488. if (instruction instanceof KeyInstruction && (<KeyInstruction>instruction).Key !== this.activeKeys[visStaffIdx].Key) {
  489. keyInstruction = <KeyInstruction>instruction;
  490. }
  491. if (instruction instanceof RhythmInstruction && (<RhythmInstruction>instruction) !== this.activeRhythm[visStaffIdx]) {
  492. rhythmInstruction = <RhythmInstruction>instruction;
  493. }
  494. }
  495. if (keyInstruction !== undefined || rhythmInstruction !== undefined) {
  496. let measureWidth: number = this.addExtraInstructionMeasure(visStaffIdx, keyInstruction, rhythmInstruction);
  497. maxMeasureWidth = Math.max(maxMeasureWidth, measureWidth);
  498. }
  499. }
  500. if (maxMeasureWidth > 0) {
  501. this.currentSystemParams.systemMeasures.push({
  502. beginLine: SystemLinesEnum.None,
  503. endLine: SystemLinesEnum.None,
  504. });
  505. this.currentSystemParams.currentWidth += maxMeasureWidth;
  506. this.currentSystemParams.currentSystemFixWidth += maxMeasureWidth;
  507. }
  508. }
  509. private addExtraInstructionMeasure(visStaffIdx: number, keyInstruction: KeyInstruction, rhythmInstruction: RhythmInstruction): number {
  510. let currentSystem: MusicSystem = this.currentSystemParams.currentSystem;
  511. let measures: StaffMeasure[] = [];
  512. let measure: StaffMeasure = this.symbolFactory.createExtraStaffMeasure(currentSystem.StaffLines[visStaffIdx]);
  513. measures.push(measure);
  514. if (keyInstruction !== undefined) {
  515. measure.addKeyAtBegin(keyInstruction, this.activeKeys[visStaffIdx], this.activeClefs[visStaffIdx]);
  516. }
  517. if (rhythmInstruction !== undefined) {
  518. measure.addRhythmAtBegin(rhythmInstruction);
  519. }
  520. measure.PositionAndShape.BorderLeft = 0.0;
  521. measure.PositionAndShape.BorderTop = 0.0;
  522. measure.PositionAndShape.BorderBottom = this.rules.StaffHeight;
  523. let width: number = this.rules.MeasureLeftMargin + measure.beginInstructionsWidth + this.rules.MeasureRightMargin;
  524. measure.PositionAndShape.BorderRight = width;
  525. currentSystem.StaffLines[visStaffIdx].Measures.push(measure);
  526. measure.ParentStaffLine = currentSystem.StaffLines[visStaffIdx];
  527. currentSystem.StaffLines[visStaffIdx].PositionAndShape.ChildElements.push(measure.PositionAndShape);
  528. return width;
  529. }
  530. private addStaveMeasuresToSystem(staffMeasures: StaffMeasure[]): void {
  531. if (staffMeasures[0] !== undefined) {
  532. let gmeasures: StaffMeasure[] = [];
  533. for (let i: number = 0; i < staffMeasures.length; i++) {
  534. gmeasures.push(staffMeasures[i]);
  535. }
  536. let currentSystem: MusicSystem = this.currentSystemParams.currentSystem;
  537. for (let visStaffIdx: number = 0; visStaffIdx < this.numberOfVisibleStaffLines; visStaffIdx++) {
  538. let measure: StaffMeasure = gmeasures[visStaffIdx];
  539. currentSystem.StaffLines[visStaffIdx].Measures.push(measure);
  540. measure.ParentStaffLine = currentSystem.StaffLines[visStaffIdx];
  541. currentSystem.StaffLines[visStaffIdx].PositionAndShape.ChildElements.push(measure.PositionAndShape);
  542. }
  543. currentSystem.AddStaffMeasures(gmeasures);
  544. }
  545. }
  546. private getMeasureStartLine(): SystemLinesEnum {
  547. let thisMeasureBeginsLineRep: boolean = this.thisMeasureBeginsLineRepetition();
  548. if (thisMeasureBeginsLineRep) {
  549. let isSystemStartMeasure: boolean = this.currentSystemParams.IsSystemStartMeasure();
  550. let isGlobalFirstMeasure: boolean = this.measureListIndex === 0;
  551. if (this.previousMeasureEndsLineRepetition() && !isSystemStartMeasure) {
  552. return SystemLinesEnum.DotsBoldBoldDots;
  553. }
  554. if (!isGlobalFirstMeasure) {
  555. return SystemLinesEnum.BoldThinDots;
  556. }
  557. }
  558. return SystemLinesEnum.None;
  559. }
  560. private getMeasureEndLine(): SystemLinesEnum {
  561. if (this.nextMeasureBeginsLineRepetition() && this.thisMeasureEndsLineRepetition()) {
  562. return SystemLinesEnum.DotsBoldBoldDots;
  563. }
  564. if (this.thisMeasureEndsLineRepetition()) {
  565. return SystemLinesEnum.DotsThinBold;
  566. }
  567. if (this.measureListIndex === this.measureList.length - 1 || this.measureList[this.measureListIndex][0].parentSourceMeasure.endsPiece) {
  568. return SystemLinesEnum.ThinBold;
  569. }
  570. if (this.nextMeasureHasKeyInstructionChange() || this.thisMeasureEndsWordRepetition() || this.nextMeasureBeginsWordRepetition()) {
  571. return SystemLinesEnum.DoubleThin;
  572. }
  573. return SystemLinesEnum.SingleThin;
  574. }
  575. private getLineWidth(measure: StaffMeasure, systemLineEnum: SystemLinesEnum, isSystemStartMeasure: boolean): number {
  576. let width: number = measure.getLineWidth(systemLineEnum);
  577. if (systemLineEnum === SystemLinesEnum.DotsBoldBoldDots) {
  578. width /= 2;
  579. }
  580. if (isSystemStartMeasure && systemLineEnum === SystemLinesEnum.BoldThinDots) {
  581. width += this.rules.DistanceBetweenLastInstructionAndRepetitionBarline;
  582. }
  583. return width;
  584. }
  585. private previousMeasureEndsLineRepetition(): boolean {
  586. if (this.measureListIndex === 0) {
  587. return false;
  588. }
  589. for (let idx: number = 0, len: number = this.measureList[this.measureListIndex - 1].length; idx < len; ++idx) {
  590. let measure: StaffMeasure = this.measureList[this.measureListIndex - 1][idx];
  591. if (measure.endsWithLineRepetition()) {
  592. return true;
  593. }
  594. }
  595. return false;
  596. }
  597. private thisMeasureBeginsLineRepetition(): boolean {
  598. for (let idx: number = 0, len: number = this.measureList[this.measureListIndex].length; idx < len; ++idx) {
  599. let measure: StaffMeasure = this.measureList[this.measureListIndex][idx];
  600. if (measure.beginsWithLineRepetition()) {
  601. return true;
  602. }
  603. }
  604. return false;
  605. }
  606. private nextMeasureBeginsLineRepetition(): boolean {
  607. let nextMeasureIndex: number = this.measureListIndex + 1;
  608. if (nextMeasureIndex >= this.graphicalMusicSheet.ParentMusicSheet.SourceMeasures.length) {
  609. return false;
  610. }
  611. for (let idx: number = 0, len: number = this.measureList[nextMeasureIndex].length; idx < len; ++idx) {
  612. let measure: StaffMeasure = this.measureList[nextMeasureIndex][idx];
  613. if (measure.beginsWithLineRepetition()) {
  614. return true;
  615. }
  616. }
  617. return false;
  618. }
  619. private thisMeasureEndsLineRepetition(): boolean {
  620. for (let idx: number = 0, len: number = this.measureList[this.measureListIndex].length; idx < len; ++idx) {
  621. let measure: StaffMeasure = this.measureList[this.measureListIndex][idx];
  622. if (measure.endsWithLineRepetition()) {
  623. return true;
  624. }
  625. }
  626. return false;
  627. }
  628. private nextMeasureBeginsWordRepetition(): boolean {
  629. let nextMeasureIndex: number = this.measureListIndex + 1;
  630. if (nextMeasureIndex >= this.graphicalMusicSheet.ParentMusicSheet.SourceMeasures.length) {
  631. return false;
  632. }
  633. for (let idx: number = 0, len: number = this.measureList[nextMeasureIndex].length; idx < len; ++idx) {
  634. let measure: StaffMeasure = this.measureList[nextMeasureIndex][idx];
  635. if (measure.beginsWithWordRepetition()) {
  636. return true;
  637. }
  638. }
  639. return false;
  640. }
  641. private thisMeasureEndsWordRepetition(): boolean {
  642. for (let idx: number = 0, len: number = this.measureList[this.measureListIndex].length; idx < len; ++idx) {
  643. let measure: StaffMeasure = this.measureList[this.measureListIndex][idx];
  644. if (measure.endsWithWordRepetition()) {
  645. return true;
  646. }
  647. }
  648. return false;
  649. }
  650. private nextMeasureHasKeyInstructionChange(): boolean {
  651. return this.getNextMeasureKeyInstruction() !== undefined;
  652. }
  653. private getNextMeasureKeyInstruction(): KeyInstruction {
  654. if (this.measureListIndex < this.measureList.length - 1) {
  655. for (let visIndex: number = 0; visIndex < this.measureList[this.measureListIndex].length; visIndex++) {
  656. let sourceMeasure: SourceMeasure = this.measureList[this.measureListIndex + 1][visIndex].parentSourceMeasure;
  657. if (sourceMeasure === undefined) {
  658. return undefined;
  659. }
  660. return sourceMeasure.getKeyInstruction(this.visibleStaffIndices[visIndex]);
  661. }
  662. }
  663. return undefined;
  664. }
  665. private calculateXScalingFactor(systemFixWidth: number, systemVarWidth: number): number {
  666. if (Math.abs(systemVarWidth - 0) < 0.00001 || Math.abs(systemFixWidth - 0) < 0.00001) {
  667. return 1.0;
  668. }
  669. let systemEndX: number;
  670. let currentSystem: MusicSystem = this.currentSystemParams.currentSystem;
  671. systemEndX = currentSystem.StaffLines[0].PositionAndShape.Size.width;
  672. let scalingFactor: number = (systemEndX - systemFixWidth) / systemVarWidth;
  673. return scalingFactor;
  674. }
  675. private stretchMusicSystem(isPartEndingSystem: boolean): void {
  676. let scalingFactor: number = this.calculateXScalingFactor(
  677. this.currentSystemParams.currentSystemFixWidth, this.currentSystemParams.currentSystemVarWidth
  678. );
  679. if (isPartEndingSystem) {
  680. scalingFactor = Math.min(scalingFactor, this.rules.LastSystemMaxScalingFactor);
  681. }
  682. let currentSystem: MusicSystem = this.currentSystemParams.currentSystem;
  683. for (let visStaffIdx: number = 0, len: number = currentSystem.StaffLines.length; visStaffIdx < len; ++visStaffIdx) {
  684. let staffLine: StaffLine = currentSystem.StaffLines[visStaffIdx];
  685. let currentXPosition: number = 0.0;
  686. for (let measureIndex: number = 0; measureIndex < staffLine.Measures.length; measureIndex++) {
  687. let measure: StaffMeasure = staffLine.Measures[measureIndex];
  688. measure.setPositionInStaffline(currentXPosition);
  689. measure.setWidth(measure.beginInstructionsWidth + measure.minimumStaffEntriesWidth * scalingFactor + measure.endInstructionsWidth);
  690. if (measureIndex < this.currentSystemParams.systemMeasures.length) {
  691. let startLine: SystemLinesEnum = this.currentSystemParams.systemMeasures[measureIndex].beginLine;
  692. let lineWidth: number = measure.getLineWidth(SystemLinesEnum.BoldThinDots);
  693. switch (startLine) {
  694. case SystemLinesEnum.BoldThinDots:
  695. let xPosition: number = currentXPosition;
  696. if (measureIndex === 0) {
  697. xPosition = currentXPosition + measure.beginInstructionsWidth - lineWidth;
  698. }
  699. currentSystem.createVerticalLineForMeasure(xPosition, lineWidth, startLine, SystemLinePosition.MeasureBegin, measureIndex, measure);
  700. break;
  701. default:
  702. }
  703. }
  704. measure.staffEntriesScaleFactor = scalingFactor;
  705. measure.layoutSymbols();
  706. let nextMeasureHasRepStartLine: boolean = measureIndex + 1 < this.currentSystemParams.systemMeasures.length
  707. && this.currentSystemParams.systemMeasures[measureIndex + 1].beginLine === SystemLinesEnum.BoldThinDots;
  708. if (!nextMeasureHasRepStartLine) {
  709. let endLine: SystemLinesEnum = SystemLinesEnum.SingleThin;
  710. if (measureIndex < this.currentSystemParams.systemMeasures.length) {
  711. endLine = this.currentSystemParams.systemMeasures[measureIndex].endLine;
  712. }
  713. let lineWidth: number = measure.getLineWidth(endLine);
  714. let xPos: number = measure.PositionAndShape.RelativePosition.x + measure.PositionAndShape.BorderRight - lineWidth;
  715. if (endLine === SystemLinesEnum.DotsBoldBoldDots) {
  716. xPos -= lineWidth / 2;
  717. }
  718. currentSystem.createVerticalLineForMeasure(xPos, lineWidth, endLine, SystemLinePosition.MeasureEnd, measureIndex, measure);
  719. }
  720. currentXPosition = measure.PositionAndShape.RelativePosition.x + measure.PositionAndShape.BorderRight;
  721. }
  722. }
  723. if (isPartEndingSystem) {
  724. this.decreaseMusicSystemBorders();
  725. }
  726. }
  727. private decreaseMusicSystemBorders(): void {
  728. let currentSystem: MusicSystem = this.currentSystemParams.currentSystem;
  729. let bb: BoundingBox = CollectionUtil.last(currentSystem.StaffLines[0].Measures).PositionAndShape;
  730. let width: number = bb.RelativePosition.x + bb.Size.width;
  731. for (let idx: number = 0, len: number = currentSystem.StaffLines.length; idx < len; ++idx) {
  732. let staffLine: StaffLine = currentSystem.StaffLines[idx];
  733. staffLine.PositionAndShape.BorderRight = width;
  734. for (let idx2: number = 0, len2: number = staffLine.StaffLines.length; idx2 < len2; ++idx2) {
  735. let graphicalLine: GraphicalLine = staffLine.StaffLines[idx2];
  736. graphicalLine.End = new PointF2D(width, graphicalLine.End.y);
  737. }
  738. }
  739. currentSystem.PositionAndShape.BorderRight = width + this.currentSystemParams.maxLabelLength + this.rules.SystemLabelsRightMargin;
  740. }
  741. }
  742. export class SystemBuildParameters {
  743. public currentSystem: MusicSystem;
  744. public systemMeasures: MeasureBuildParameters[] = [];
  745. public systemMeasureIndex: number = 0;
  746. public currentWidth: number = 0;
  747. public currentSystemFixWidth: number = 0;
  748. public currentSystemVarWidth: number = 0;
  749. public maxLabelLength: number = 0;
  750. public IsSystemStartMeasure(): boolean {
  751. return this.systemMeasureIndex === 0;
  752. }
  753. }
  754. export class MeasureBuildParameters {
  755. public beginLine: SystemLinesEnum;
  756. public endLine: SystemLinesEnum;
  757. }