Note.ts 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. import {VoiceEntry, StemDirectionType} from "./VoiceEntry";
  2. import {SourceStaffEntry} from "./SourceStaffEntry";
  3. import {Fraction} from "../../Common/DataObjects/Fraction";
  4. import {NoteEnum, Pitch} from "../../Common/DataObjects/Pitch";
  5. import {Beam} from "./Beam";
  6. import {Tuplet} from "./Tuplet";
  7. import {Tie} from "./Tie";
  8. import {Staff} from "./Staff";
  9. import {Slur} from "./Expressions/ContinuousExpressions/Slur";
  10. import {NoteState} from "../Graphical/DrawingEnums";
  11. import {Notehead} from "./Notehead";
  12. import {Arpeggio} from "./Arpeggio";
  13. import {NoteType} from "./NoteType";
  14. import { SourceMeasure } from "./SourceMeasure";
  15. import { TechnicalInstruction } from "./Instructions";
  16. import { PlaybackNote } from "../Playback/PlaybackNote";
  17. /**
  18. * Represents a single pitch with a duration (length)
  19. */
  20. export class Note {
  21. constructor(voiceEntry: VoiceEntry, parentStaffEntry: SourceStaffEntry, length: Fraction, pitch: Pitch, sourceMeasure: SourceMeasure, isRest?: boolean) {
  22. this.voiceEntry = voiceEntry;
  23. this.parentStaffEntry = parentStaffEntry;
  24. this.length = length;
  25. this.pitch = pitch;
  26. this.sourceMeasure = sourceMeasure;
  27. this.isRestFlag = isRest ?? false;
  28. this.noteTremoloType = '';
  29. this.glissandoType = '';
  30. this.slideType = '';
  31. if (pitch) {
  32. this.halfTone = pitch.getHalfTone();
  33. } else {
  34. this.halfTone = 0;
  35. }
  36. }
  37. /**
  38. * The transposed (!!!) HalfTone of this note.
  39. */
  40. public noteTremoloType: string;
  41. public glissandoType: string;
  42. public slideType: string;
  43. public halfTone: number;
  44. public state: NoteState;
  45. private voiceEntry: VoiceEntry;
  46. private parentStaffEntry: SourceStaffEntry;
  47. private length: Fraction;
  48. private playbackNote: PlaybackNote;
  49. private sourceMeasure: SourceMeasure;
  50. /** The length/duration given in the <type> tag. different from length for tuplets/tremolos. */
  51. private typeLength: Fraction;
  52. /** The NoteType given in the XML, e.g. quarter, which can be a normal quarter or tuplet quarter -> can have different length/fraction */
  53. private noteTypeXml: NoteType;
  54. public DotsXml: number;
  55. /** The amount of notes the tuplet of this note (if there is one) replaces. */
  56. private normalNotes: number;
  57. private isRestFlag: boolean;
  58. /**
  59. * The untransposed (!!!) source data.
  60. */
  61. private pitch: Pitch;
  62. /** The transposed pitch, if the score is transposed, otherwise undefined. */
  63. public TransposedPitch: Pitch;
  64. public displayStepUnpitched: NoteEnum;
  65. public displayOctaveUnpitched: number;
  66. public get NoteAsString(): string {
  67. return this.pitch.toString();
  68. }
  69. private beam: Beam;
  70. private tuplet: Tuplet;
  71. private tie: Tie;
  72. private slurs: Slur[] = [];
  73. private playbackInstrumentId: string = undefined;
  74. private notehead: Notehead = undefined;
  75. /** States whether the note should be displayed. False if xmlNode.attribute("print-object").value = "no". */
  76. private printObject: boolean = true;
  77. /** The Arpeggio this note is part of. */
  78. private arpeggio: Arpeggio;
  79. /** States whether this is a cue note (Stichnote) (smaller size). */
  80. private isCueNote: boolean;
  81. public IsGraceNote: boolean;
  82. /** The stem direction asked for in XML. Not necessarily final or wanted stem direction. */
  83. private stemDirectionXml: StemDirectionType;
  84. /** The number of tremolo strokes this note has (16th tremolo = 2 strokes).
  85. * Could be a Tremolo object in future when there is more data like tremolo between two notes.
  86. */
  87. private tremoloStrokes: number;
  88. /** Color of the stem given in the XML Stem tag. RGB Hexadecimal, like #00FF00.
  89. * This is not used for rendering, which takes VoiceEntry.StemColor.
  90. * It is merely given in the note's stem element in XML and stored here for reference.
  91. * So, to read or change the stem color of a note, modify note.ParentVoiceEntry.StemColor.
  92. */
  93. private stemColorXml: string;
  94. /** Color of the notehead given in the XML Notehead tag. RGB Hexadecimal, like #00FF00.
  95. * This should not be changed, instead noteheadColor is used and modifiable for Rendering.
  96. * Needs to be stored here and not in Note.Notehead,
  97. * because Note.Notehead is undefined for normal Noteheads to save space and time.
  98. */
  99. private noteheadColorXml: string;
  100. /** Color of the notehead currently set/desired for next render. RGB Hexadecimal, like #00FF00.
  101. * Needs to be stored here and not in Note.Notehead,
  102. * because Note.Notehead is undefined for normal Noteheads to save space and time.
  103. */
  104. private noteheadColor: string;
  105. private noteheadColorCurrentlyRendered: string;
  106. public Fingering: TechnicalInstruction; // this is also stored in VoiceEntry.TechnicalInstructions
  107. public StringInstruction: TechnicalInstruction; // this is also stored in VoiceEntry.TechnicalInstructions
  108. // note that there is also TabNote.StringNumber, so we can't use that identifier here
  109. /** Used by GraphicalNote.FromNote(note) and osmd.rules.GNote(note) to get a GraphicalNote from a Note.
  110. * Note that we don't want the data model (Note) to be dependent on the graphical implementation (GraphicalNote),
  111. * and have (potentially circular) import dependencies of graphical parts, which also applies to other non-graphical classes.
  112. * That's why we don't save a GraphicalNote reference directly in Note.
  113. */
  114. public NoteToGraphicalNoteObjectId: number; // used with EngravingRules.NoteToGraphicalNoteMap
  115. public get TremoloType(): string {
  116. return this.noteTremoloType
  117. }
  118. public set TremoloType(value: string){
  119. this.noteTremoloType = value
  120. }
  121. public get ParentVoiceEntry(): VoiceEntry {
  122. return this.voiceEntry;
  123. }
  124. public set ParentVoiceEntry(value: VoiceEntry) {
  125. this.voiceEntry = value;
  126. }
  127. public get ParentStaffEntry(): SourceStaffEntry {
  128. return this.parentStaffEntry;
  129. }
  130. public get ParentStaff(): Staff {
  131. return this.parentStaffEntry.ParentStaff;
  132. }
  133. public get Length(): Fraction {
  134. return this.length;
  135. }
  136. public set PlaybackNote(value: PlaybackNote) {
  137. this.playbackNote = value;
  138. }
  139. public get PlaybackNote(): PlaybackNote {
  140. return this.playbackNote;
  141. }
  142. public set Length(value: Fraction) {
  143. this.length = value;
  144. }
  145. public get SourceMeasure(): SourceMeasure {
  146. return this.sourceMeasure;
  147. }
  148. public get TypeLength(): Fraction {
  149. return this.typeLength;
  150. }
  151. public set TypeLength(value: Fraction) {
  152. this.typeLength = value;
  153. }
  154. public get NoteTypeXml(): NoteType {
  155. return this.noteTypeXml;
  156. }
  157. public set NoteTypeXml(value: NoteType) {
  158. this.noteTypeXml = value;
  159. }
  160. public get NormalNotes(): number {
  161. return this.normalNotes;
  162. }
  163. public set NormalNotes(value: number) {
  164. this.normalNotes = value;
  165. }
  166. public get Pitch(): Pitch {
  167. return this.pitch;
  168. }
  169. public get NoteBeam(): Beam {
  170. return this.beam;
  171. }
  172. public set NoteBeam(value: Beam) {
  173. this.beam = value;
  174. }
  175. public set Notehead(value: Notehead) {
  176. this.notehead = value;
  177. }
  178. public get Notehead(): Notehead {
  179. return this.notehead;
  180. }
  181. public get NoteTuplet(): Tuplet {
  182. return this.tuplet;
  183. }
  184. public set NoteTuplet(value: Tuplet) {
  185. this.tuplet = value;
  186. }
  187. public get NoteTie(): Tie {
  188. return this.tie;
  189. }
  190. public set NoteTie(value: Tie) {
  191. this.tie = value;
  192. }
  193. public get NoteSlurs(): Slur[] {
  194. return this.slurs;
  195. }
  196. public set NoteSlurs(value: Slur[]) {
  197. this.slurs = value;
  198. }
  199. public get PlaybackInstrumentId(): string {
  200. return this.playbackInstrumentId;
  201. }
  202. public set PlaybackInstrumentId(value: string) {
  203. this.playbackInstrumentId = value;
  204. }
  205. public get PrintObject(): boolean {
  206. return this.printObject;
  207. }
  208. public set PrintObject(value: boolean) {
  209. this.printObject = value;
  210. }
  211. public get Arpeggio(): Arpeggio {
  212. return this.arpeggio;
  213. }
  214. public set Arpeggio(value: Arpeggio) {
  215. this.arpeggio = value;
  216. }
  217. public get IsCueNote(): boolean {
  218. return this.isCueNote;
  219. }
  220. public set IsCueNote(value: boolean) {
  221. this.isCueNote = value;
  222. }
  223. public get StemDirectionXml(): StemDirectionType {
  224. return this.stemDirectionXml;
  225. }
  226. public set StemDirectionXml(value: StemDirectionType) {
  227. this.stemDirectionXml = value;
  228. }
  229. public get TremoloStrokes(): number {
  230. return this.tremoloStrokes;
  231. }
  232. public set TremoloStrokes(value: number) {
  233. this.tremoloStrokes = value;
  234. }
  235. public get StemColorXml(): string {
  236. return this.stemColorXml;
  237. }
  238. public set StemColorXml(value: string) {
  239. this.stemColorXml = value;
  240. }
  241. public get NoteheadColorXml(): string {
  242. return this.noteheadColorXml;
  243. }
  244. public set NoteheadColorXml(value: string) {
  245. this.noteheadColorXml = value;
  246. }
  247. /** The desired notehead color for the next render. */
  248. public get NoteheadColor(): string {
  249. return this.noteheadColor;
  250. }
  251. public set NoteheadColor(value: string) {
  252. this.noteheadColor = value;
  253. }
  254. public get NoteheadColorCurrentlyRendered(): string {
  255. return this.noteheadColorCurrentlyRendered;
  256. }
  257. public set NoteheadColorCurrentlyRendered(value: string) {
  258. this.noteheadColorCurrentlyRendered = value;
  259. }
  260. public isRest(): boolean {
  261. return this.isRestFlag;
  262. }
  263. /** Note: May be dangerous to use if ParentStaffEntry.VerticalContainerParent etc is not set.
  264. * better calculate this directly when you have access to the note's measure.
  265. * whole rest: length = measure length. (4/4 in a 4/4 time signature, 3/4 in a 3/4 time signature, 1/4 in a 1/4 time signature, etc.)
  266. */
  267. public isWholeRest(): boolean {
  268. return this.isRest() && this.Length.RealValue === this.sourceMeasure.ActiveTimeSignature.RealValue;
  269. }
  270. public ToString(): string {
  271. if (this.pitch) {
  272. return this.Pitch.ToString() + ", length: " + this.length.toString();
  273. } else {
  274. return "rest note, length: " + this.length.toString();
  275. }
  276. }
  277. public getAbsoluteTimestamp(): Fraction {
  278. return Fraction.plus(
  279. this.voiceEntry.Timestamp,
  280. this.sourceMeasure.AbsoluteTimestamp
  281. );
  282. }
  283. public checkForDoubleSlur(slur: Slur): boolean {
  284. for (let idx: number = 0, len: number = this.slurs.length; idx < len; ++idx) {
  285. const noteSlur: Slur = this.slurs[idx];
  286. if (
  287. noteSlur.StartNote !== undefined &&
  288. noteSlur.EndNote !== undefined &&
  289. slur.StartNote !== undefined &&
  290. slur.StartNote === noteSlur.StartNote &&
  291. noteSlur.EndNote === this
  292. ) { return true; }
  293. }
  294. return false;
  295. }
  296. }
  297. export enum Appearance {
  298. Normal,
  299. Grace,
  300. Cue
  301. }