Note.ts 10 KB

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