Note.ts 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  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 isDotNote: boolean; // 添加是否是附点音符字段
  116. public get TremoloType(): string {
  117. return this.noteTremoloType
  118. }
  119. public set TremoloType(value: string){
  120. this.noteTremoloType = value
  121. }
  122. public get ParentVoiceEntry(): VoiceEntry {
  123. return this.voiceEntry;
  124. }
  125. public set ParentVoiceEntry(value: VoiceEntry) {
  126. this.voiceEntry = value;
  127. }
  128. public get ParentStaffEntry(): SourceStaffEntry {
  129. return this.parentStaffEntry;
  130. }
  131. public get ParentStaff(): Staff {
  132. return this.parentStaffEntry.ParentStaff;
  133. }
  134. public get Length(): Fraction {
  135. return this.length;
  136. }
  137. public set PlaybackNote(value: PlaybackNote) {
  138. this.playbackNote = value;
  139. }
  140. public get PlaybackNote(): PlaybackNote {
  141. return this.playbackNote;
  142. }
  143. public set Length(value: Fraction) {
  144. this.length = value;
  145. }
  146. public get SourceMeasure(): SourceMeasure {
  147. return this.sourceMeasure;
  148. }
  149. public get TypeLength(): Fraction {
  150. return this.typeLength;
  151. }
  152. public set TypeLength(value: Fraction) {
  153. this.typeLength = value;
  154. }
  155. public get NoteTypeXml(): NoteType {
  156. return this.noteTypeXml;
  157. }
  158. public set NoteTypeXml(value: NoteType) {
  159. this.noteTypeXml = value;
  160. }
  161. public get NormalNotes(): number {
  162. return this.normalNotes;
  163. }
  164. public set NormalNotes(value: number) {
  165. this.normalNotes = value;
  166. }
  167. public get Pitch(): Pitch {
  168. return this.pitch;
  169. }
  170. public get NoteBeam(): Beam {
  171. return this.beam;
  172. }
  173. public set NoteBeam(value: Beam) {
  174. this.beam = value;
  175. }
  176. public set Notehead(value: Notehead) {
  177. this.notehead = value;
  178. }
  179. public get Notehead(): Notehead {
  180. return this.notehead;
  181. }
  182. public get NoteTuplet(): Tuplet {
  183. return this.tuplet;
  184. }
  185. public set NoteTuplet(value: Tuplet) {
  186. this.tuplet = value;
  187. }
  188. public get NoteTie(): Tie {
  189. return this.tie;
  190. }
  191. public set NoteTie(value: Tie) {
  192. this.tie = value;
  193. }
  194. public get NoteSlurs(): Slur[] {
  195. return this.slurs;
  196. }
  197. public set NoteSlurs(value: Slur[]) {
  198. this.slurs = value;
  199. }
  200. public get PlaybackInstrumentId(): string {
  201. return this.playbackInstrumentId;
  202. }
  203. public set PlaybackInstrumentId(value: string) {
  204. this.playbackInstrumentId = value;
  205. }
  206. public get PrintObject(): boolean {
  207. return this.printObject;
  208. }
  209. public set PrintObject(value: boolean) {
  210. this.printObject = value;
  211. }
  212. public get Arpeggio(): Arpeggio {
  213. return this.arpeggio;
  214. }
  215. public set Arpeggio(value: Arpeggio) {
  216. this.arpeggio = value;
  217. }
  218. public get IsCueNote(): boolean {
  219. return this.isCueNote;
  220. }
  221. public set IsCueNote(value: boolean) {
  222. this.isCueNote = value;
  223. }
  224. public get StemDirectionXml(): StemDirectionType {
  225. return this.stemDirectionXml;
  226. }
  227. public set StemDirectionXml(value: StemDirectionType) {
  228. this.stemDirectionXml = value;
  229. }
  230. public get TremoloStrokes(): number {
  231. return this.tremoloStrokes;
  232. }
  233. public set TremoloStrokes(value: number) {
  234. this.tremoloStrokes = value;
  235. }
  236. public get StemColorXml(): string {
  237. return this.stemColorXml;
  238. }
  239. public set StemColorXml(value: string) {
  240. this.stemColorXml = value;
  241. }
  242. public get NoteheadColorXml(): string {
  243. return this.noteheadColorXml;
  244. }
  245. public set NoteheadColorXml(value: string) {
  246. this.noteheadColorXml = value;
  247. }
  248. /** The desired notehead color for the next render. */
  249. public get NoteheadColor(): string {
  250. return this.noteheadColor;
  251. }
  252. public set NoteheadColor(value: string) {
  253. this.noteheadColor = value;
  254. }
  255. public get NoteheadColorCurrentlyRendered(): string {
  256. return this.noteheadColorCurrentlyRendered;
  257. }
  258. public set NoteheadColorCurrentlyRendered(value: string) {
  259. this.noteheadColorCurrentlyRendered = value;
  260. }
  261. public isRest(): boolean {
  262. return this.isRestFlag;
  263. }
  264. /** Note: May be dangerous to use if ParentStaffEntry.VerticalContainerParent etc is not set.
  265. * better calculate this directly when you have access to the note's measure.
  266. * 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.)
  267. */
  268. public isWholeRest(): boolean {
  269. return this.isRest() && this.Length.RealValue === this.sourceMeasure.ActiveTimeSignature.RealValue;
  270. }
  271. public ToString(): string {
  272. if (this.pitch) {
  273. return this.Pitch.ToString() + ", length: " + this.length.toString();
  274. } else {
  275. return "rest note, length: " + this.length.toString();
  276. }
  277. }
  278. public getAbsoluteTimestamp(): Fraction {
  279. return Fraction.plus(
  280. this.voiceEntry.Timestamp,
  281. this.sourceMeasure.AbsoluteTimestamp
  282. );
  283. }
  284. public checkForDoubleSlur(slur: Slur): boolean {
  285. for (let idx: number = 0, len: number = this.slurs.length; idx < len; ++idx) {
  286. const noteSlur: Slur = this.slurs[idx];
  287. if (
  288. noteSlur.StartNote !== undefined &&
  289. noteSlur.EndNote !== undefined &&
  290. slur.StartNote !== undefined &&
  291. slur.StartNote === noteSlur.StartNote &&
  292. noteSlur.EndNote === this
  293. ) { return true; }
  294. }
  295. return false;
  296. }
  297. }
  298. export enum Appearance {
  299. Normal,
  300. Grace,
  301. Cue
  302. }