123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354 |
- import {MusicSystem} from "./MusicSystem";
- import {GraphicalStaffEntry} from "./GraphicalStaffEntry";
- import {SourceMeasure} from "../VoiceData/SourceMeasure";
- import {StaffLine} from "./StaffLine";
- import {Staff} from "../VoiceData/Staff";
- import {GraphicalObject} from "./GraphicalObject";
- import {ClefInstruction} from "../VoiceData/Instructions/ClefInstruction";
- import {KeyInstruction} from "../VoiceData/Instructions/KeyInstruction";
- import {RhythmInstruction} from "../VoiceData/Instructions/RhythmInstruction";
- import {Fraction} from "../../Common/DataObjects/Fraction";
- import {Voice} from "../VoiceData/Voice";
- import {VoiceEntry} from "../VoiceData/VoiceEntry";
- import {SystemLinesEnum} from "./SystemLinesEnum";
- import {BoundingBox} from "./BoundingBox";
- import {PointF2D} from "../../Common/DataObjects/PointF2D";
- /**
- * Represents a measure in the music sheet (one measure in one staff line)
- */
- export abstract class GraphicalMeasure extends GraphicalObject {
- protected firstInstructionStaffEntry: GraphicalStaffEntry;
- protected lastInstructionStaffEntry: GraphicalStaffEntry;
- constructor(staff: Staff = undefined, parentSourceMeasure: SourceMeasure = undefined, staffLine: StaffLine = undefined) {
- super();
- this.parentStaff = staff;
- this.parentSourceMeasure = parentSourceMeasure;
- this.parentStaffLine = staffLine;
- if (staffLine) {
- this.parentStaff = staffLine.ParentStaff;
- this.PositionAndShape = new BoundingBox(this, staffLine.PositionAndShape);
- } else {
- this.PositionAndShape = new BoundingBox(this);
- }
- this.PositionAndShape.BorderBottom = 4;
- if (this.parentSourceMeasure) {
- this.measureNumber = this.parentSourceMeasure.MeasureNumber;
- }
- this.staffEntries = [];
- }
- public parentSourceMeasure: SourceMeasure;
- public staffEntries: GraphicalStaffEntry[];
- /**
- * The x-width of possibly existing: repetition start line, clef, key, rhythm.
- */
- public beginInstructionsWidth: number;
- /**
- * The minimum possible x-width of all staff entries without overlapping.
- */
- public minimumStaffEntriesWidth: number;
- /**
- * Will be set by music system builder while building systems.
- */
- public staffEntriesScaleFactor: number;
- /**
- * The x-width of possibly existing: repetition end line, clef.
- */
- public endInstructionsWidth: number;
- public hasError: boolean;
- private parentStaff: Staff;
- private parentMusicSystem: MusicSystem;
- private measureNumber: number = -1;
- private parentStaffLine: StaffLine;
- public get ParentStaff(): Staff {
- return this.parentStaff;
- }
- public get ParentMusicSystem(): MusicSystem {
- return this.parentMusicSystem;
- }
- public set ParentMusicSystem(value: MusicSystem) {
- this.parentMusicSystem = value;
- }
- public get MeasureNumber(): number {
- return this.measureNumber;
- }
- public get FirstInstructionStaffEntry(): GraphicalStaffEntry {
- return this.firstInstructionStaffEntry;
- }
- public set FirstInstructionStaffEntry(value: GraphicalStaffEntry) {
- this.firstInstructionStaffEntry = value;
- }
- public get LastInstructionStaffEntry(): GraphicalStaffEntry {
- return this.lastInstructionStaffEntry;
- }
- public set LastInstructionStaffEntry(value: GraphicalStaffEntry) {
- this.lastInstructionStaffEntry = value;
- }
- public get ParentStaffLine(): StaffLine {
- return this.parentStaffLine;
- }
- public set ParentStaffLine(value: StaffLine) {
- this.parentStaffLine = value;
- if (this.parentStaffLine) {
- this.PositionAndShape.Parent = this.parentStaffLine.PositionAndShape;
- }
- }
- /**
- * Reset all the geometric values and parameters of this measure and put it in an initialized state.
- * This is needed to evaluate a measure a second time by system builder.
- */
- public resetLayout(): void {
- throw new Error("not implemented");
- }
- /**
- * Return the x-width of a given measure line.
- * @param line
- */
- public getLineWidth(line: SystemLinesEnum): number {
- throw new Error("not implemented");
- }
- /**
- * Add the given clef to the begin of the measure.
- * This has to update/increase BeginInstructionsWidth.
- * @param clef
- */
- public addClefAtBegin(clef: ClefInstruction): void {
- throw new Error("not implemented");
- }
- /**
- * Add the given key to the begin of the measure.
- * This has to update/increase BeginInstructionsWidth.
- * @param currentKey - The new valid key.
- * @param previousKey - The old cancelled key. Needed to show which accidentals are not valid any more.
- * @param currentClef - The valid clef. Needed to put the accidentals on the right y-positions.
- */
- public addKeyAtBegin(currentKey: KeyInstruction, previousKey: KeyInstruction, currentClef: ClefInstruction): void {
- throw new Error("not implemented");
- }
- /**
- * Add the given rhythm to the begin of the measure.
- * This has to update/increase BeginInstructionsWidth.
- * @param rhythm
- */
- public addRhythmAtBegin(rhythm: RhythmInstruction): void {
- throw new Error("not implemented");
- }
- /**
- * Add the given clef to the end of the measure.
- * This has to update/increase EndInstructionsWidth.
- * @param clef
- */
- public addClefAtEnd(clef: ClefInstruction): void {
- throw new Error("not implemented");
- }
- /**
- * Set the x-position relative to the staffline (y-Position is always 0 relative to the staffline).
- * @param xPos
- */
- public setPositionInStaffline(xPos: number): void {
- this.PositionAndShape.RelativePosition = new PointF2D(xPos, 0);
- }
- /**
- * Set the overall x-width of the measure.
- * @param width
- */
- public setWidth(width: number): void {
- this.PositionAndShape.BorderRight = width;
- }
- /**
- * This method is called after the StaffEntriesScaleFactor has been set.
- * Here the final x-positions of the staff entries have to be set.
- * (multiply the minimal positions with the scaling factor, considering the BeginInstructionsWidth).
- */
- public layoutSymbols(): void {
- throw new Error("not implemented");
- }
- public findGraphicalStaffEntryFromTimestamp(relativeTimestamp: Fraction): GraphicalStaffEntry {
- for (let idx: number = 0, len: number = this.staffEntries.length; idx < len; ++idx) {
- const graphicalStaffEntry: GraphicalStaffEntry = this.staffEntries[idx];
- if (graphicalStaffEntry.relInMeasureTimestamp.Equals(relativeTimestamp)) {
- return graphicalStaffEntry;
- }
- }
- return undefined;
- }
- /**
- * Iterate from start to end and find the [[GraphicalStaffEntry]] with the same absolute timestamp.
- * @param absoluteTimestamp
- * @returns {any}
- */
- public findGraphicalStaffEntryFromVerticalContainerTimestamp(absoluteTimestamp: Fraction): GraphicalStaffEntry {
- for (let idx: number = 0, len: number = this.staffEntries.length; idx < len; ++idx) {
- const graphicalStaffEntry: GraphicalStaffEntry = this.staffEntries[idx];
- if (graphicalStaffEntry.sourceStaffEntry.VerticalContainerParent.getAbsoluteTimestamp().Equals(absoluteTimestamp)) {
- return graphicalStaffEntry;
- }
- }
- return undefined;
- }
- /**
- * Check if the all the [[GraphicalMeasure]]'s [[StaffEntry]]s (their minimum Length) have the same duration with the [[SourceMeasure]].
- * @returns {boolean}
- */
- public hasSameDurationWithSourceMeasureParent(): boolean {
- const duration: Fraction = new Fraction(0, 1);
- for (let idx: number = 0, len: number = this.staffEntries.length; idx < len; ++idx) {
- const graphicalStaffEntry: GraphicalStaffEntry = this.staffEntries[idx];
- duration.Add(graphicalStaffEntry.findStaffEntryMinNoteLength());
- }
- return duration.Equals(this.parentSourceMeasure.Duration);
- }
- /**
- * Check a whole [[Measure]] for the presence of multiple Voices (used for Stem direction).
- * @returns {boolean}
- */
- public hasMultipleVoices(): boolean {
- if (this.staffEntries.length === 0) {
- return false;
- }
- const voices: Voice[] = [];
- for (let idx: number = 0, len: number = this.staffEntries.length; idx < len; ++idx) {
- const staffEntry: GraphicalStaffEntry = this.staffEntries[idx];
- for (let idx2: number = 0, len2: number = staffEntry.sourceStaffEntry.VoiceEntries.length; idx2 < len2; ++idx2) {
- const voiceEntry: VoiceEntry = staffEntry.sourceStaffEntry.VoiceEntries[idx2];
- if (voices.indexOf(voiceEntry.ParentVoice) < 0) {
- voices.push(voiceEntry.ParentVoice);
- }
- }
- }
- if (voices.length > 1) {
- return true;
- }
- return false;
- }
- public isVisible(): boolean {
- return this.ParentStaff.ParentInstrument.Visible;
- }
- public getGraphicalMeasureDurationFromStaffEntries(): Fraction {
- let duration: Fraction = new Fraction(0, 1);
- const voices: Voice[] = [];
- for (let idx: number = 0, len: number = this.staffEntries.length; idx < len; ++idx) {
- const graphicalStaffEntry: GraphicalStaffEntry = this.staffEntries[idx];
- for (let idx2: number = 0, len2: number = graphicalStaffEntry.sourceStaffEntry.VoiceEntries.length; idx2 < len2; ++idx2) {
- const voiceEntry: VoiceEntry = graphicalStaffEntry.sourceStaffEntry.VoiceEntries[idx2];
- if (voices.indexOf(voiceEntry.ParentVoice) < 0) {
- voices.push(voiceEntry.ParentVoice);
- }
- }
- }
- for (let idx: number = 0, len: number = voices.length; idx < len; ++idx) {
- const voice: Voice = voices[idx];
- const voiceDuration: Fraction = new Fraction(0, 1);
- for (const graphicalStaffEntry of this.staffEntries) {
- for (const gve of graphicalStaffEntry.graphicalVoiceEntries) {
- if (gve.parentVoiceEntry.ParentVoice === voice && gve.notes.length > 0) {
- voiceDuration.Add(gve.notes[0].graphicalNoteLength);
- }
- }
- }
- if (duration.lt(voiceDuration)) {
- duration = Fraction.createFromFraction(voiceDuration);
- }
- }
- return duration;
- }
- public addGraphicalStaffEntry(graphicalStaffEntry: GraphicalStaffEntry): void {
- this.staffEntries.push(graphicalStaffEntry);
- }
- /**
- * Add a [[StaffEntry]] (along with its [[BoundingBox]]) to the current Measure.
- * @param staffEntry
- */
- public addGraphicalStaffEntryAtTimestamp(staffEntry: GraphicalStaffEntry): void {
- if (staffEntry) {
- if (this.staffEntries.length === 0 || this.staffEntries[this.staffEntries.length - 1].relInMeasureTimestamp.lt(staffEntry.relInMeasureTimestamp)) {
- this.staffEntries.push(staffEntry);
- } else {
- for (let i: number = this.staffEntries.length - 1; i >= 0; i--) {
- if (this.staffEntries[i].relInMeasureTimestamp.lt(staffEntry.relInMeasureTimestamp)) {
- this.staffEntries.splice(i + 1, 0, staffEntry);
- break;
- }
- if (i === 0) {
- this.staffEntries.splice(i, 0, staffEntry);
- }
- }
- }
- }
- }
- public beginsWithLineRepetition(): boolean {
- const sourceMeasure: SourceMeasure = this.parentSourceMeasure;
- if (!sourceMeasure) {
- return false;
- }
- return sourceMeasure.beginsWithLineRepetition();
- }
- /**
- * Check if this Measure is a Repetition Ending.
- * @returns {boolean}
- */
- public endsWithLineRepetition(): boolean {
- const sourceMeasure: SourceMeasure = this.parentSourceMeasure;
- if (!sourceMeasure) {
- return false;
- }
- return sourceMeasure.endsWithLineRepetition();
- }
- /**
- * Check if a Repetition starts at the next Measure.
- * @returns {boolean}
- */
- public beginsWithWordRepetition(): boolean {
- const sourceMeasure: SourceMeasure = this.parentSourceMeasure;
- if (!sourceMeasure) {
- return false;
- }
- return sourceMeasure.beginsWithWordRepetition();
- }
- /**
- * Check if this Measure is a Repetition Ending.
- */
- public endsWithWordRepetition(): boolean {
- const sourceMeasure: SourceMeasure = this.parentSourceMeasure;
- if (!sourceMeasure) {
- return false;
- }
- return sourceMeasure.endsWithWordRepetition();
- }
- }
|