| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434 |
- import {Fraction} from "../../Common/DataObjects/Fraction";
- import {Voice} from "./Voice";
- import {SourceStaffEntry} from "./SourceStaffEntry";
- import {Note} from "./Note";
- import {Pitch} from "../../Common/DataObjects/Pitch";
- import {LyricsEntry} from "./Lyrics/LyricsEntry";
- import {TechnicalInstruction} from "./Instructions/TechnicalInstruction";
- import {OrnamentContainer} from "./OrnamentContainer";
- import {KeyInstruction} from "./Instructions/KeyInstruction";
- import {OrnamentEnum} from "./OrnamentContainer";
- import {AccidentalEnum} from "../../Common/DataObjects/Pitch";
- import { Dictionary } from "typescript-collections";
- import {Arpeggio} from "./Arpeggio";
- import { SourceMeasure } from "./SourceMeasure";
- import { Articulation } from "./Articulation";
- /**
- * A [[VoiceEntry]] contains the notes in a voice at a timestamp.
- */
- export class VoiceEntry {
- /**
- *
- * @param timestamp The relative timestamp within the source measure.
- * @param parentVoice
- * @param parentSourceStaffEntry
- * @param isGrace States whether the VoiceEntry has (only) grace notes.
- * @param graceNoteSlash States whether the grace note(s) have a slash (Acciaccatura, played before the beat)
- */
- constructor(timestamp: Fraction, parentVoice: Voice, parentSourceStaffEntry: SourceStaffEntry,
- isGrace: boolean = false, graceNoteSlash: boolean = false, graceSlur: boolean = false) {
- this.timestamp = timestamp;
- this.parentVoice = parentVoice;
- this.parentSourceStaffEntry = parentSourceStaffEntry;
- this.isGrace = isGrace;
- this.graceAfterMainNote = false;
- this.graceNoteSlash = graceNoteSlash;
- this.graceSlur = graceSlur;
- // add currentVoiceEntry to staff entry:
- if (parentSourceStaffEntry !== undefined) {
- const list: VoiceEntry[] = parentSourceStaffEntry.VoiceEntries;
- if (list.indexOf(this) === -1) {
- list.push(this);
- }
- }
- }
- private parentVoice: Voice;
- private parentSourceStaffEntry: SourceStaffEntry;
- private timestamp: Fraction;
- private notes: Note[] = [];
- private isGrace: boolean;
- /** States whether the grace notes come after a main note (at end of measure). */
- private graceAfterMainNote: boolean;
- private graceNoteSlash: boolean;
- private graceSlur: boolean; // TODO grace slur system could be refined to be non-binary
- private articulations: Articulation[] = [];
- private technicalInstructions: TechnicalInstruction[] = [];
- private lyricsEntries: Dictionary<number, LyricsEntry> = new Dictionary<number, LyricsEntry>();
- /** The Arpeggio consisting of this VoiceEntry's notes. Undefined if no arpeggio exists. */
- private arpeggio: Arpeggio;
- private ornamentContainer: OrnamentContainer;
- private wantedStemDirection: StemDirectionType = StemDirectionType.Undefined;
- /** Stem direction specified in the xml stem element. */
- private stemDirectionXml: StemDirectionType = StemDirectionType.Undefined;
- private stemDirection: StemDirectionType = StemDirectionType.Undefined;
- /** Color of the stem given in XML. RGB Hexadecimal, like #00FF00. */
- private stemColorXml: string;
- /** Color of the stem currently set. RGB Hexadecimal, like #00FF00. */
- private stemColor: string;
- public get ParentSourceStaffEntry(): SourceStaffEntry {
- return this.parentSourceStaffEntry;
- }
- public get ParentVoice(): Voice {
- return this.parentVoice;
- }
- public get Timestamp(): Fraction {
- return this.timestamp;
- }
- public set Timestamp(value: Fraction) {
- this.timestamp = value;
- }
- public get Notes(): Note[] {
- return this.notes;
- }
- public get IsGrace(): boolean {
- return this.isGrace;
- }
- public set IsGrace(value: boolean) {
- this.isGrace = value;
- }
- public get GraceAfterMainNote(): boolean {
- return this.graceAfterMainNote;
- }
- public set GraceAfterMainNote(value: boolean) {
- this.graceAfterMainNote = value;
- }
- public get GraceNoteSlash(): boolean {
- return this.graceNoteSlash;
- }
- public set GraceNoteSlash(value: boolean) {
- this.graceNoteSlash = value;
- }
- public get GraceSlur(): boolean {
- return this.graceSlur;
- }
- public set GraceSlur(value: boolean) {
- this.graceSlur = value;
- }
- public get Articulations(): Articulation[] {
- return this.articulations;
- }
- public get TechnicalInstructions(): TechnicalInstruction[] {
- return this.technicalInstructions;
- }
- public get LyricsEntries(): Dictionary<number, LyricsEntry> {
- return this.lyricsEntries;
- }
- public get Arpeggio(): Arpeggio {
- return this.arpeggio;
- }
- public set Arpeggio(value: Arpeggio) {
- this.arpeggio = value;
- }
- public get OrnamentContainer(): OrnamentContainer {
- return this.ornamentContainer;
- }
- public set OrnamentContainer(value: OrnamentContainer) {
- this.ornamentContainer = value;
- }
- // WantedStemDirection provides the stem direction to VexFlow in case of more than 1 voice
- // for optimal graphical appearance
- public set WantedStemDirection(value: StemDirectionType) {
- this.wantedStemDirection = value;
- }
- public get WantedStemDirection(): StemDirectionType {
- return this.wantedStemDirection;
- }
- public set StemDirectionXml(value: StemDirectionType) {
- this.stemDirectionXml = value;
- }
- public get StemDirectionXml(): StemDirectionType {
- return this.stemDirectionXml;
- }
- // StemDirection holds the actual value of the stem
- public set StemDirection(value: StemDirectionType) {
- this.stemDirection = value;
- }
- public get StemDirection(): StemDirectionType {
- return this.stemDirection;
- }
- public get StemColorXml(): string {
- return this.stemColorXml;
- }
- public set StemColorXml(value: string) {
- this.stemColorXml = value;
- }
- public get StemColor(): string {
- return this.stemColor;
- }
- public set StemColor(value: string) {
- this.stemColor = value;
- }
- public hasArticulation(articulation: Articulation): boolean {
- for (const existingArticulation of this.articulations) {
- if (existingArticulation.Equals(articulation)) {
- return true;
- }
- }
- return false;
- }
- public static isSupportedArticulation(articulation: ArticulationEnum): boolean {
- switch (articulation) {
- case ArticulationEnum.accent:
- case ArticulationEnum.strongaccent:
- case ArticulationEnum.invertedstrongaccent:
- case ArticulationEnum.staccato:
- case ArticulationEnum.staccatissimo:
- case ArticulationEnum.spiccato:
- case ArticulationEnum.tenuto:
- case ArticulationEnum.fermata:
- case ArticulationEnum.invertedfermata:
- case ArticulationEnum.breathmark:
- case ArticulationEnum.caesura:
- case ArticulationEnum.lefthandpizzicato:
- case ArticulationEnum.naturalharmonic:
- case ArticulationEnum.snappizzicato:
- case ArticulationEnum.upbow:
- case ArticulationEnum.downbow:
- case ArticulationEnum.bend:
- return true;
- default:
- return false;
- }
- }
- public hasTie(): boolean {
- for (let idx: number = 0, len: number = this.Notes.length; idx < len; ++idx) {
- const note: Note = this.Notes[idx];
- if (note.NoteTie) { return true; }
- }
- return false;
- }
- public hasSlur(): boolean {
- for (let idx: number = 0, len: number = this.Notes.length; idx < len; ++idx) {
- const note: Note = this.Notes[idx];
- if (note.NoteSlurs.length > 0) { return true; }
- }
- return false;
- }
- public isStaccato(): boolean {
- for (const articulation of this.Articulations) {
- if (articulation.articulationEnum === ArticulationEnum.staccato) {
- return true;
- }
- }
- return false;
- }
- public isAccent(): boolean {
- for (const articulation of this.Articulations) {
- if (articulation.articulationEnum === ArticulationEnum.accent || articulation.articulationEnum === ArticulationEnum.strongaccent) {
- return true;
- }
- }
- return false;
- }
- public getVerseNumberForLyricEntry(lyricsEntry: LyricsEntry): number {
- let verseNumber: number = 1;
- this.lyricsEntries.forEach((key: number, value: LyricsEntry): void => {
- if (lyricsEntry === value) {
- verseNumber = key;
- }
- });
- return verseNumber;
- }
- //public createVoiceEntriesForOrnament(activeKey: KeyInstruction): VoiceEntry[] {
- // return this.createVoiceEntriesForOrnament(this, activeKey);
- //}
- public createVoiceEntriesForOrnament(voiceEntryWithOrnament: VoiceEntry, activeKey: KeyInstruction): VoiceEntry[] {
- if (!voiceEntryWithOrnament) {
- voiceEntryWithOrnament = this;
- }
- const voiceEntries: VoiceEntry[] = [];
- if (!voiceEntryWithOrnament.ornamentContainer) {
- return;
- }
- const baseNote: Note = this.notes[0];
- const baselength: Fraction = baseNote.Length;
- const baseVoice: Voice = voiceEntryWithOrnament.ParentVoice;
- const baseTimestamp: Fraction = voiceEntryWithOrnament.Timestamp;
- let currentTimestamp: Fraction = Fraction.createFromFraction(baseTimestamp);
- //let length: Fraction;
- switch (voiceEntryWithOrnament.ornamentContainer.GetOrnament) {
- case OrnamentEnum.Trill: {
- const length: Fraction = new Fraction(baselength.Numerator, baselength.Denominator * 8);
- const higherPitch: Pitch = baseNote.Pitch.getTransposedPitch(1);
- let alteration: AccidentalEnum = activeKey.getAlterationForPitch(higherPitch);
- if (voiceEntryWithOrnament.OrnamentContainer.AccidentalAbove !== AccidentalEnum.NONE) {
- alteration = voiceEntryWithOrnament.ornamentContainer.AccidentalAbove;
- }
- for (let i: number = 0; i < 8; i++) {
- currentTimestamp = Fraction.plus(baseTimestamp, new Fraction(i * length.Numerator, length.Denominator));
- if ((i % 2) === 0) {
- this.createBaseVoiceEntry(currentTimestamp, length, baseVoice, baseNote, voiceEntries);
- } else {
- this.createAlteratedVoiceEntry(currentTimestamp, length, baseVoice, baseNote.SourceMeasure, higherPitch, alteration, voiceEntries);
- }
- }
- break;
- }
- case OrnamentEnum.Turn: {
- const length: Fraction = new Fraction(baselength.Numerator, baselength.Denominator * 4);
- const lowerPitch: Pitch = baseNote.Pitch.getTransposedPitch(-1);
- const lowerAlteration: AccidentalEnum = activeKey.getAlterationForPitch(lowerPitch);
- const higherPitch: Pitch = baseNote.Pitch.getTransposedPitch(1);
- const higherAlteration: AccidentalEnum = activeKey.getAlterationForPitch(higherPitch);
- this.createAlteratedVoiceEntry(
- currentTimestamp, length, baseVoice, baseNote.SourceMeasure, higherPitch, higherAlteration, voiceEntries
- );
- currentTimestamp.Add(length);
- this.createBaseVoiceEntry(currentTimestamp, length, baseVoice, baseNote, voiceEntries);
- currentTimestamp.Add(length);
- this.createAlteratedVoiceEntry(
- currentTimestamp, length, baseVoice, baseNote.SourceMeasure, lowerPitch, lowerAlteration, voiceEntries
- );
- currentTimestamp.Add(length);
- this.createBaseVoiceEntry(currentTimestamp, length, baseVoice, baseNote, voiceEntries);
- break;
- }
- case OrnamentEnum.InvertedTurn: {
- const length: Fraction = new Fraction(baselength.Numerator, baselength.Denominator * 4);
- const lowerPitch: Pitch = baseNote.Pitch.getTransposedPitch(-1);
- const lowerAlteration: AccidentalEnum = activeKey.getAlterationForPitch(lowerPitch);
- const higherPitch: Pitch = baseNote.Pitch.getTransposedPitch(1);
- const higherAlteration: AccidentalEnum = activeKey.getAlterationForPitch(higherPitch);
- this.createAlteratedVoiceEntry(
- currentTimestamp, length, baseVoice, baseNote.SourceMeasure, lowerPitch, lowerAlteration, voiceEntries
- );
- currentTimestamp.Add(length);
- this.createBaseVoiceEntry(currentTimestamp, length, baseVoice, baseNote, voiceEntries);
- currentTimestamp.Add(length);
- this.createAlteratedVoiceEntry(
- currentTimestamp, length, baseVoice, baseNote.SourceMeasure, higherPitch, higherAlteration, voiceEntries
- );
- currentTimestamp.Add(length);
- this.createBaseVoiceEntry(currentTimestamp, length, baseVoice, baseNote, voiceEntries);
- break;
- }
- case OrnamentEnum.DelayedTurn: {
- const length: Fraction = new Fraction(baselength.Numerator, baselength.Denominator * 2);
- const lowerPitch: Pitch = baseNote.Pitch.getTransposedPitch(-1);
- const lowerAlteration: AccidentalEnum = activeKey.getAlterationForPitch(lowerPitch);
- const higherPitch: Pitch = baseNote.Pitch.getTransposedPitch(1);
- const higherAlteration: AccidentalEnum = activeKey.getAlterationForPitch(higherPitch);
- this.createBaseVoiceEntry(currentTimestamp, length, baseVoice, baseNote, voiceEntries);
- currentTimestamp = Fraction.plus(baseTimestamp, length);
- length.Denominator = baselength.Denominator * 8;
- this.createAlteratedVoiceEntry(currentTimestamp, length, baseVoice, baseNote.SourceMeasure, higherPitch, higherAlteration, voiceEntries);
- currentTimestamp.Add(length);
- this.createBaseVoiceEntry(currentTimestamp, length, baseVoice, baseNote, voiceEntries);
- currentTimestamp.Add(length);
- this.createAlteratedVoiceEntry(currentTimestamp, length, baseVoice, baseNote.SourceMeasure, lowerPitch, lowerAlteration, voiceEntries);
- currentTimestamp.Add(length);
- this.createBaseVoiceEntry(currentTimestamp, length, baseVoice, baseNote, voiceEntries);
- break;
- }
- case OrnamentEnum.DelayedInvertedTurn: {
- const length: Fraction = new Fraction(baselength.Numerator, baselength.Denominator * 2);
- const lowerPitch: Pitch = baseNote.Pitch.getTransposedPitch(-1);
- const lowerAlteration: AccidentalEnum = activeKey.getAlterationForPitch(lowerPitch);
- const higherPitch: Pitch = baseNote.Pitch.getTransposedPitch(1);
- const higherAlteration: AccidentalEnum = activeKey.getAlterationForPitch(higherPitch);
- this.createBaseVoiceEntry(currentTimestamp, length, baseVoice, baseNote, voiceEntries);
- currentTimestamp = Fraction.plus(baseTimestamp, length);
- length.Denominator = baselength.Denominator * 8;
- this.createAlteratedVoiceEntry(currentTimestamp, length, baseVoice, baseNote.SourceMeasure, lowerPitch, lowerAlteration, voiceEntries);
- currentTimestamp.Add(length);
- this.createBaseVoiceEntry(currentTimestamp, length, baseVoice, baseNote, voiceEntries);
- currentTimestamp.Add(length);
- this.createAlteratedVoiceEntry(currentTimestamp, length, baseVoice, baseNote.SourceMeasure, higherPitch, higherAlteration, voiceEntries);
- currentTimestamp.Add(length);
- this.createBaseVoiceEntry(currentTimestamp, length, baseVoice, baseNote, voiceEntries);
- break;
- }
- case OrnamentEnum.Mordent: {
- const length: Fraction = new Fraction(baselength.Numerator, baselength.Denominator * 4);
- const higherPitch: Pitch = baseNote.Pitch.getTransposedPitch(1);
- const alteration: AccidentalEnum = activeKey.getAlterationForPitch(higherPitch);
- this.createBaseVoiceEntry(currentTimestamp, length, baseVoice, baseNote, voiceEntries);
- currentTimestamp.Add(length);
- this.createAlteratedVoiceEntry(currentTimestamp, length, baseVoice, baseNote.SourceMeasure, higherPitch, alteration, voiceEntries);
- length.Denominator = baselength.Denominator * 2;
- currentTimestamp = Fraction.plus(baseTimestamp, length);
- this.createBaseVoiceEntry(currentTimestamp, length, baseVoice, baseNote, voiceEntries);
- break;
- }
- case OrnamentEnum.InvertedMordent: {
- const length: Fraction = new Fraction(baselength.Numerator, baselength.Denominator * 4);
- const lowerPitch: Pitch = baseNote.Pitch.getTransposedPitch(-1);
- const alteration: AccidentalEnum = activeKey.getAlterationForPitch(lowerPitch);
- this.createBaseVoiceEntry(currentTimestamp, length, baseVoice, baseNote, voiceEntries);
- currentTimestamp.Add(length);
- this.createAlteratedVoiceEntry(currentTimestamp, length, baseVoice, baseNote.SourceMeasure, lowerPitch, alteration, voiceEntries);
- length.Denominator = baselength.Denominator * 2;
- currentTimestamp = Fraction.plus(baseTimestamp, length);
- this.createBaseVoiceEntry(currentTimestamp, length, baseVoice, baseNote, voiceEntries);
- break;
- }
- default:
- throw new RangeError();
- }
- return voiceEntries;
- }
- private createBaseVoiceEntry(
- currentTimestamp: Fraction, length: Fraction, baseVoice: Voice, baseNote: Note, voiceEntries: VoiceEntry[]
- ): void {
- const voiceEntry: VoiceEntry = new VoiceEntry(currentTimestamp, baseVoice, baseNote.ParentStaffEntry);
- const pitch: Pitch = new Pitch(baseNote.Pitch.FundamentalNote, baseNote.Pitch.Octave, baseNote.Pitch.Accidental);
- const note: Note = new Note(voiceEntry, undefined, length, pitch, baseNote.SourceMeasure);
- voiceEntry.Notes.push(note);
- voiceEntries.push(voiceEntry);
- }
- private createAlteratedVoiceEntry(
- currentTimestamp: Fraction, length: Fraction, baseVoice: Voice, sourceMeasure: SourceMeasure, higherPitch: Pitch,
- alteration: AccidentalEnum, voiceEntries: VoiceEntry[]
- ): void {
- const voiceEntry: VoiceEntry = new VoiceEntry(currentTimestamp, baseVoice, undefined);
- const pitch: Pitch = new Pitch(higherPitch.FundamentalNote, higherPitch.Octave, alteration);
- const note: Note = new Note(voiceEntry, undefined, length, pitch, sourceMeasure);
- voiceEntry.Notes.push(note);
- voiceEntries.push(voiceEntry);
- }
- }
- export enum ArticulationEnum {
- accent,
- strongaccent,
- marcatoup,
- marcatodown,
- invertedstrongaccent,
- staccato,
- staccatissimo,
- spiccato,
- tenuto,
- fermata,
- invertedfermata,
- breathmark,
- caesura,
- lefthandpizzicato,
- naturalharmonic,
- snappizzicato,
- upbow,
- downbow,
- scoop,
- plop,
- doit,
- falloff,
- stress,
- unstress,
- detachedlegato,
- otherarticulation,
- bend
- }
- export enum StemDirectionType {
- Undefined = -1,
- Up = 0,
- Down = 1,
- None = 2,
- Double = 3
- }
|