123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373 |
- import { Fraction } from "../../Common/DataObjects/Fraction";
- import {Voice} from "./Voice";
- import {SourceStaffEntry} from "./SourceStaffEntry";
- import {Note} from "./Note";
- import {LyricsEntry} from "./Lyrics/LyricsEntry";
- import {TechnicalInstruction} from "./Instructions/TechnicalInstruction";
- import {OrnamentContainer} from "./OrnamentContainer";
- import { Dictionary } from "typescript-collections";
- import {Arpeggio} from "./Arpeggio";
- import { PlaybackEntry } from "../Playback/PlaybackEntry";
- import { Articulation } from "./Articulation";
- import { PlaybackNote } from "../Playback/PlaybackNote";
- /**
- * 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, addToStaffEntry: boolean = true,
- 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;
- if (!isGrace) {
- parentVoice.VoiceEntries.push(this);
- }
- // add currentVoiceEntry to staff entry:
- if (addToStaffEntry && parentSourceStaffEntry !== undefined) {
- const list: VoiceEntry[] = parentSourceStaffEntry.VoiceEntries;
- if (list.indexOf(this) === -1) {
- list.push(this);
- }
- }
- // ToDo: at this moment there are no notes added to the voice entry
- this.mainPlaybackEntry = new PlaybackEntry(this);
- this.PlaybackEntries.push(this.mainPlaybackEntry);
- }
- private parentVoice: Voice;
- private parentSourceStaffEntry: SourceStaffEntry;
- private timestamp: Fraction;
- private notes: Note[] = [];
- private graceVoiceEntriesBefore: VoiceEntry[] = [];
- private graceVoiceEntriesAfter: VoiceEntry[] = [];
- 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 playbackEntries: PlaybackEntry[] = [];
- private fermata: Articulation;
- private technicalInstructions: TechnicalInstruction[] = [];
- private lyricsEntries: Dictionary<string, LyricsEntry> = new Dictionary<string, 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;
- private mainPlaybackEntry: PlaybackEntry;
- private volumeModifier: Articulation;
- private durationModifier: Articulation;
- 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 addNote(note: Note): void {
- this.notes.push(note);
- // only add playback notes when these are no rests and are not tied notes (besides the first note of a tie)
- if (!note.isRest() &&
- (note.NoteTie === undefined || note.NoteTie.StartNote === note)) {
- this.MainPlaybackEntry.Notes.push(new PlaybackNote(this.MainPlaybackEntry, note));
- }
- }
- public get GraceVoiceEntriesBefore(): VoiceEntry[] {
- return this.graceVoiceEntriesBefore;
- }
- public set GraceVoiceEntriesBefore(value: VoiceEntry[] ) {
- this.graceVoiceEntriesBefore = value;
- for (const ve of this.graceVoiceEntriesBefore) {
- ve.parentSourceStaffEntry = this.ParentSourceStaffEntry;
- }
- }
- public get GraceVoiceEntriesAfter(): VoiceEntry[] {
- return this.graceVoiceEntriesAfter;
- }
- public set GraceVoiceEntriesAfter(value: VoiceEntry[] ) {
- this.graceVoiceEntriesAfter = value;
- for (const ve of this.graceVoiceEntriesAfter) {
- ve.parentSourceStaffEntry = this.ParentSourceStaffEntry;
- }
- }
- 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;
- }
- /** Stores all playback entries (e.g. extra grace and ornament entries).
- * Also holds the main playback entry.
- * The entries are sorted in ascending timestamp.
- */
- public get PlaybackEntries(): PlaybackEntry[] {
- return this.playbackEntries;
- }
- public get Fermata(): Articulation {
- return this.fermata;
- }
- public get MainPlaybackEntry(): PlaybackEntry {
- return this.mainPlaybackEntry;
- }
- public set MainPlaybackEntry(value: PlaybackEntry) {
- this.mainPlaybackEntry = value;
- }
- public removeMainPlaybackEntry(): void {
- if (this.mainPlaybackEntry !== undefined) {
- this.removePlaybackEntry(this.mainPlaybackEntry);
- }
- }
- public removePlaybackEntry(value: PlaybackEntry): void {
- if (this.mainPlaybackEntry === value) {
- this.mainPlaybackEntry = undefined;
- }
- const index: number = this.playbackEntries.indexOf(value);
- if (index > -1) {
- this.playbackEntries.splice(index, 1);
- }
- }
- public set Articulations(value: Articulation[]) {
- this.articulations = value;
- }
- public get TechnicalInstructions(): TechnicalInstruction[] {
- return this.technicalInstructions;
- }
- public get LyricsEntries(): Dictionary<string, 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 get VolumeModifier(): Articulation {
- return this.volumeModifier;
- }
- public set VolumeModifier(value: Articulation) {
- this.volumeModifier = value;
- }
- public get DurationModifier(): Articulation {
- return this.durationModifier;
- }
- public set DurationModifier(value: Articulation) {
- this.durationModifier = 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.softaccent:
- 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): string {
- let verseNumber: string = "1";
- this.lyricsEntries.forEach((key: string, value: LyricsEntry): void => {
- if (lyricsEntry === value) {
- verseNumber = key;
- }
- });
- return verseNumber;
- }
- }
- export enum ArticulationEnum {
- accent,
- strongaccent,
- softaccent,
- 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
- }
|