1use crate::articulations::Articulation;
2use crate::defaults::{FloatType, IntegerType};
3use crate::duration::Duration;
4use crate::error::Result;
5use crate::expressions::Expression;
6use crate::instrument::Instrument;
7use crate::interval::Interval;
8use crate::notation::{Beams, Lyric, NoteSize, Notehead, StemDirection, Tie, verses};
9use crate::pitch::Pitch;
10use crate::volume::Volume;
11
12use std::fmt::{Display, Formatter};
13use std::str::FromStr;
14
15#[derive(Clone, Debug)]
16#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
17#[must_use]
19pub struct Note {
20 pub(crate) pitch: Pitch,
21 duration: Option<Duration>,
22 #[cfg_attr(feature = "serde", serde(default))]
23 notation: Notation,
24}
25
26#[derive(Clone, Debug, Default, PartialEq)]
29#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
30struct Notation {
31 tie: Option<Tie>,
32 notehead: Notehead,
33 notehead_fill: Option<bool>,
34 notehead_parenthesis: bool,
35 stem_direction: StemDirection,
36 color: Option<String>,
37 #[cfg_attr(feature = "serde", serde(default))]
38 size: Option<NoteSize>,
39 volume: Option<Volume>,
40 lyrics: Vec<Lyric>,
41 beams: Beams,
42 stored_instrument: Option<Box<Instrument>>,
44 expressions: Vec<Expression>,
45 articulations: Vec<Articulation>,
46 hidden: bool,
47 #[cfg_attr(feature = "serde", serde(default))]
48 id: Option<String>,
49 #[cfg_attr(feature = "serde", serde(default))]
52 midi_tick_start: crate::display::Drawn<Option<u64>>,
53 #[cfg_attr(feature = "serde", serde(default))]
57 quantization_errors: crate::display::Drawn<(Option<FloatType>, Option<FloatType>)>,
58}
59
60impl Note {
61 pub fn from_name(name: impl AsRef<str>) -> Result<Self> {
63 Pitch::from_name(name).map(Self::from_pitch)
64 }
65
66 pub fn from_number(number: FloatType) -> Result<Self> {
68 Pitch::from_number(number).map(Self::from_pitch)
69 }
70
71 pub fn from_pitch(pitch: Pitch) -> Self {
73 Self {
74 pitch,
75 duration: None,
76 notation: Notation::default(),
77 }
78 }
79
80 pub fn pitch(&self) -> &Pitch {
82 &self.pitch
83 }
84
85 pub fn set_pitch(&mut self, pitch: Pitch) {
88 self.pitch = pitch;
89 }
90
91 pub fn pitch_name(&self) -> String {
93 self.pitch.name()
94 }
95
96 pub fn pitch_name_with_octave(&self) -> String {
98 self.pitch.name_with_octave()
99 }
100
101 pub fn step(&self) -> char {
103 self.pitch.step().as_char()
104 }
105
106 pub fn octave(&self) -> crate::defaults::Octave {
108 self.pitch.octave()
109 }
110
111 pub fn pitches(&self) -> Vec<Pitch> {
113 vec![self.pitch.clone()]
114 }
115
116 pub fn full_name(&self) -> String {
119 match self.duration.as_ref() {
120 Some(duration) => format!("{} {} Note", self.pitch.full_name(), duration.full_name()),
121 None => format!("{} Note", self.pitch.full_name()),
122 }
123 }
124
125 pub fn duration(&self) -> Option<&Duration> {
127 self.duration.as_ref()
128 }
129
130 pub fn set_duration(&mut self, duration: Duration) {
132 self.duration = Some(duration);
133 }
134
135 pub fn with_duration(mut self, duration: Duration) -> Self {
137 self.set_duration(duration);
138 self
139 }
140
141 pub fn grace_note(&self, appoggiatura: bool) -> Self {
159 let written = self.duration.clone().unwrap_or_default();
160 self.clone()
161 .with_duration(written.grace_duration_as(appoggiatura))
162 }
163
164 pub fn transpose(&self, interval: &Interval) -> Result<Self> {
167 Ok(Self {
168 pitch: interval.transpose_pitch(&self.pitch)?,
169 duration: self.duration.clone(),
170 notation: self.notation.clone(),
171 })
172 }
173
174 pub fn beams(&self) -> &Beams {
179 &self.notation.beams
180 }
181
182 pub fn beams_mut(&mut self) -> &mut Beams {
184 &mut self.notation.beams
185 }
186
187 pub fn set_beams(&mut self, beams: Beams) {
189 self.notation.beams = beams;
190 }
191
192 pub fn tie(&self) -> Option<&Tie> {
194 self.notation.tie.as_ref()
195 }
196
197 pub fn set_tie(&mut self, tie: Option<Tie>) {
199 self.notation.tie = tie;
200 }
201
202 pub fn notehead(&self) -> Notehead {
204 self.notation.notehead
205 }
206
207 pub fn set_notehead(&mut self, notehead: Notehead) {
209 self.notation.notehead = notehead;
210 }
211
212 pub fn notehead_fill(&self) -> Option<bool> {
216 self.notation.notehead_fill
217 }
218
219 pub fn set_notehead_fill(&mut self, fill: Option<bool>) {
221 self.notation.notehead_fill = fill;
222 }
223
224 pub fn notehead_parenthesis(&self) -> bool {
226 self.notation.notehead_parenthesis
227 }
228
229 pub fn set_notehead_parenthesis(&mut self, parenthesis: bool) {
231 self.notation.notehead_parenthesis = parenthesis;
232 }
233
234 pub fn stem_direction(&self) -> StemDirection {
236 self.notation.stem_direction
237 }
238
239 pub fn set_stem_direction(&mut self, direction: StemDirection) {
241 self.notation.stem_direction = direction;
242 }
243
244 pub fn color(&self) -> Option<&str> {
247 self.notation.color.as_deref()
248 }
249
250 pub fn set_color(&mut self, color: Option<String>) {
252 self.notation.color = color;
253 }
254
255 pub fn size(&self) -> Option<NoteSize> {
258 self.notation.size
259 }
260
261 pub fn set_size(&mut self, size: Option<NoteSize>) {
263 self.notation.size = size;
264 }
265
266 pub fn volume(&self) -> Volume {
270 self.notation.volume.clone().unwrap_or_default()
271 }
272
273 pub fn set_volume(&mut self, volume: Option<Volume>) {
275 self.notation.volume = volume;
276 }
277
278 pub fn stored_instrument(&self) -> Option<&Instrument> {
281 self.notation.stored_instrument.as_deref()
282 }
283
284 pub fn set_stored_instrument(&mut self, instrument: Option<Instrument>) {
286 self.notation.stored_instrument = instrument.map(Box::new);
287 }
288
289 pub fn instrument(&self) -> Option<&Instrument> {
293 self.stored_instrument()
294 }
295
296 pub fn has_volume_information(&self) -> bool {
301 self.notation.volume.is_some()
302 }
303
304 pub fn expressions(&self) -> &[Expression] {
307 &self.notation.expressions
308 }
309
310 pub fn expressions_mut(&mut self) -> &mut Vec<Expression> {
312 &mut self.notation.expressions
313 }
314
315 pub fn hidden(&self) -> bool {
319 self.notation.hidden
320 }
321
322 pub fn set_hidden(&mut self, hidden: bool) {
324 self.notation.hidden = hidden;
325 }
326
327 pub fn id(&self) -> Option<&str> {
331 self.notation.id.as_deref()
332 }
333
334 pub fn set_id(&mut self, id: Option<String>) {
336 self.notation.id = id;
337 }
338
339 pub fn midi_tick_start(&self) -> Option<u64> {
342 self.notation.midi_tick_start.0
343 }
344
345 pub fn set_midi_tick_start(&mut self, tick: Option<u64>) {
347 self.notation.midi_tick_start.0 = tick;
348 }
349
350 pub fn quantization_errors(&self) -> (Option<FloatType>, Option<FloatType>) {
354 self.notation.quantization_errors.0
355 }
356
357 pub fn set_quantization_errors(&mut self, errors: (Option<FloatType>, Option<FloatType>)) {
359 self.notation.quantization_errors.0 = errors;
360 }
361
362 pub fn articulations(&self) -> &[Articulation] {
365 &self.notation.articulations
366 }
367
368 pub fn articulations_mut(&mut self) -> &mut Vec<Articulation> {
370 &mut self.notation.articulations
371 }
372
373 pub fn lyrics(&self) -> &[Lyric] {
375 &self.notation.lyrics
376 }
377
378 pub fn lyrics_mut(&mut self) -> &mut Vec<Lyric> {
380 &mut self.notation.lyrics
381 }
382
383 pub fn lyric(&self) -> Option<String> {
386 verses::joined(&self.notation.lyrics)
387 }
388
389 pub fn set_lyric(&mut self, lyric: Option<&str>) -> Result<()> {
393 verses::set(&mut self.notation.lyrics, lyric);
394 Ok(())
395 }
396
397 pub fn add_lyric(
406 &mut self,
407 text: &str,
408 number: Option<IntegerType>,
409 apply_raw: bool,
410 ) -> Result<()> {
411 verses::add(&mut self.notation.lyrics, text, number, apply_raw);
412 Ok(())
413 }
414
415 pub fn insert_lyric(&mut self, text: &str, index: usize, apply_raw: bool) -> Result<()> {
420 verses::insert(&mut self.notation.lyrics, text, index, apply_raw);
421 Ok(())
422 }
423}
424
425impl FromStr for Note {
426 type Err = crate::error::Error;
427
428 fn from_str(value: &str) -> Result<Self> {
429 Self::from_name(value)
430 }
431}
432
433impl TryFrom<&str> for Note {
434 type Error = crate::error::Error;
435
436 fn try_from(value: &str) -> Result<Self> {
437 Self::from_name(value)
438 }
439}
440
441impl TryFrom<String> for Note {
442 type Error = crate::error::Error;
443
444 fn try_from(value: String) -> Result<Self> {
445 Self::from_name(value)
446 }
447}
448
449impl From<Pitch> for Note {
450 fn from(value: Pitch) -> Self {
451 Self::from_pitch(value)
452 }
453}
454
455impl From<&Pitch> for Note {
456 fn from(value: &Pitch) -> Self {
457 Self::from_pitch(value.clone())
458 }
459}
460
461impl TryFrom<IntegerType> for Note {
462 type Error = crate::error::Error;
463
464 fn try_from(value: IntegerType) -> Result<Self> {
465 Self::from_number(value as FloatType)
466 }
467}
468
469impl Display for Note {
470 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
471 write!(f, "{}", self.pitch_name_with_octave())
472 }
473}
474
475pub trait IntoNote {
480 const FROM_INTEGER_PITCH: bool = false;
482
483 fn try_into_note(self) -> Result<Note>;
485}
486
487impl IntoNote for Note {
488 fn try_into_note(self) -> Result<Note> {
489 Ok(self)
490 }
491}
492
493impl IntoNote for &Note {
494 fn try_into_note(self) -> Result<Note> {
495 Ok(self.clone())
496 }
497}
498
499impl IntoNote for Pitch {
500 fn try_into_note(self) -> Result<Note> {
501 Ok(Note::from_pitch(self))
502 }
503}
504
505impl IntoNote for &Pitch {
506 fn try_into_note(self) -> Result<Note> {
507 Ok(Note::from_pitch(self.clone()))
508 }
509}
510
511impl IntoNote for String {
512 fn try_into_note(self) -> Result<Note> {
513 Note::from_name(self)
514 }
515}
516
517impl IntoNote for &String {
518 fn try_into_note(self) -> Result<Note> {
519 Note::from_name(self.as_str())
520 }
521}
522
523impl IntoNote for &str {
524 fn try_into_note(self) -> Result<Note> {
525 Note::from_name(self)
526 }
527}
528
529impl IntoNote for IntegerType {
530 const FROM_INTEGER_PITCH: bool = true;
531
532 fn try_into_note(self) -> Result<Note> {
533 Note::from_number(self as FloatType)
534 }
535}
536
537#[cfg(test)]
538mod tests {
539 #[test]
540 fn a_note_keeps_the_instrument_it_is_played_on() {
541 let mut note = super::Note::from_name("C4").unwrap();
542 assert!(note.instrument().is_none());
543 let piccolo = crate::Instrument::of_kind("Piccolo").unwrap();
544 note.set_stored_instrument(Some(piccolo.clone()));
545 assert_eq!(note.stored_instrument(), Some(&piccolo));
546 assert_eq!(note.instrument(), Some(&piccolo));
547 note.set_stored_instrument(None);
548 assert!(note.instrument().is_none());
549 }
550
551 #[test]
552 fn a_note_is_built_from_a_name_or_a_pitch_and_carries_beams_and_lyrics() {
553 use super::Note;
554 use crate::notation::{BeamType, Beams, Lyric};
555 use crate::pitch::Pitch;
556
557 let note = Note::try_from("Eb4".to_string()).unwrap();
558 assert_eq!(note.pitch_name(), "Eb");
559 let pitch = Pitch::from_name("G#3").unwrap();
560 let mut from_pitch = Note::from(&pitch);
561 assert_eq!(from_pitch.pitch_name(), "G#");
562 assert_eq!(from_pitch.notehead_fill(), None);
563 from_pitch.set_notehead_fill(Some(true));
564 assert_eq!(from_pitch.notehead_fill(), Some(true));
565
566 assert!(from_pitch.beams().is_empty());
567 from_pitch.beams_mut().append(BeamType::Start, None);
568 assert_eq!(from_pitch.beams().beams().len(), 1);
569 from_pitch.set_beams(Beams::default());
570 assert!(from_pitch.beams().is_empty());
571
572 from_pitch.lyrics_mut().push(Lyric::new("la"));
573 assert_eq!(from_pitch.lyrics().len(), 1);
574 assert_eq!(from_pitch.lyrics()[0].text(), "la");
575 }
576
577 #[test]
578 fn full_name_step_and_octave_match_music21() {
579 let flat = Note::from_name("Eb4").unwrap();
580 assert_eq!(flat.full_name(), "E-flat in octave 4 Note");
581 assert_eq!(flat.step(), 'E');
582 assert_eq!(flat.octave(), Some(4));
583 assert_eq!(flat.pitches()[0].name_with_octave(), "Eb4");
584 let dotted = Note::from_name("C#5")
585 .unwrap()
586 .with_duration(crate::Duration::new(1.5).unwrap());
587 assert_eq!(
588 dotted.full_name(),
589 "C-sharp in octave 5 Dotted Quarter Note"
590 );
591 let bare = Note::from_name("G").unwrap();
592 assert_eq!(bare.octave(), None);
593 assert_eq!(bare.full_name(), "G Note");
594 }
595 use super::{IntoNote, Note};
596 use crate::defaults::IntegerType;
597 use crate::pitch::Pitch;
598
599 #[test]
600 fn into_note_accepts_note_like_inputs() {
601 fn from_integer_pitch<T: IntoNote>() -> bool {
602 T::FROM_INTEGER_PITCH
603 }
604
605 assert!(!from_integer_pitch::<&str>());
606 assert!(from_integer_pitch::<IntegerType>());
607
608 let note = Note::from_name("C4").unwrap();
609 assert_eq!(
610 note.clone()
611 .try_into_note()
612 .unwrap()
613 .pitch_name_with_octave(),
614 "C4"
615 );
616
617 let borrowed_note = Note::from_name("D4").unwrap();
618 assert_eq!(
619 (&borrowed_note)
620 .try_into_note()
621 .unwrap()
622 .pitch_name_with_octave(),
623 "D4"
624 );
625
626 let pitch = Pitch::from_name("E4").unwrap();
627 assert_eq!(
628 pitch.try_into_note().unwrap().pitch_name_with_octave(),
629 "E4"
630 );
631
632 let borrowed_pitch = Pitch::from_name("F4").unwrap();
633 assert_eq!(
634 (&borrowed_pitch)
635 .try_into_note()
636 .unwrap()
637 .pitch_name_with_octave(),
638 "F4"
639 );
640
641 assert_eq!(
642 "G4".to_string()
643 .try_into_note()
644 .unwrap()
645 .pitch_name_with_octave(),
646 "G4"
647 );
648
649 let owned_name = "A4".to_string();
650 assert_eq!(
651 (&owned_name)
652 .try_into_note()
653 .unwrap()
654 .pitch_name_with_octave(),
655 "A4"
656 );
657
658 assert_eq!("B4".try_into_note().unwrap().pitch_name_with_octave(), "B4");
659
660 assert_eq!(
661 (60 as IntegerType)
662 .try_into_note()
663 .unwrap()
664 .pitch_name_with_octave(),
665 "C4"
666 );
667 }
668
669 #[test]
670 fn transposing_a_note_keeps_its_duration() {
671 let note = Note::from_name("C4")
672 .unwrap()
673 .with_duration(crate::Duration::half());
674 let moved = note
675 .transpose(&crate::Interval::from_name("M3").unwrap())
676 .unwrap();
677 assert_eq!(moved.pitch_name_with_octave(), "E4");
678 assert_eq!(moved.duration().unwrap().quarter_length(), 2.0);
679 }
680
681 #[test]
682 fn setting_a_pitch_keeps_the_duration_and_the_notation() {
683 let mut note = Note::from_name("C4")
684 .unwrap()
685 .with_duration(crate::Duration::half());
686 note.set_notehead(crate::Notehead::Diamond);
687 note.set_pitch(crate::Pitch::from_name("Eb5").unwrap());
688 assert_eq!(note.pitch_name_with_octave(), "Eb5");
689 assert_eq!(note.duration().unwrap().quarter_length(), 2.0);
690 assert_eq!(note.notehead(), crate::Notehead::Diamond);
691 }
692
693 #[test]
694 fn a_numbered_lyric_replaces_the_verse_that_has_that_number() {
695 let mut note = Note::from_name("C4").unwrap();
696 note.add_lyric("hello", None, false).unwrap();
697 note.add_lyric("bye", Some(3), false).unwrap();
698 assert_eq!(
699 note.lyrics()
700 .iter()
701 .map(|lyric| (lyric.number(), lyric.text()))
702 .collect::<Vec<_>>(),
703 [(1, "hello".to_string()), (3, "bye".to_string())]
704 );
705
706 note.add_lyric("ciao", Some(3), false).unwrap();
709 assert_eq!(note.lyrics().len(), 2);
710 assert_eq!(note.lyrics()[1].text(), "ciao");
711 assert_eq!(note.lyrics()[1].number(), 3);
712
713 let mut hyphenated = Note::from_name("C4").unwrap();
715 hyphenated.set_lyric(Some("hel-")).unwrap();
716 assert_eq!(hyphenated.lyrics()[0].raw_text(), "hel-");
717 assert_eq!(hyphenated.lyric().as_deref(), Some("hel"));
718 }
719
720 #[test]
721 fn inserting_a_lyric_moves_the_verses_after_it_down() {
722 let mut note = Note::from_name("C4").unwrap();
723 note.add_lyric("second", None, false).unwrap();
724 note.insert_lyric("first", 0, false).unwrap();
725 note.insert_lyric("newSecond", 1, false).unwrap();
726 assert_eq!(
727 note.lyrics()
728 .iter()
729 .map(|lyric| (lyric.number(), lyric.text()))
730 .collect::<Vec<_>>(),
731 [
732 (1, "first".to_string()),
733 (2, "newSecond".to_string()),
734 (3, "second".to_string())
735 ]
736 );
737 note.insert_lyric("last", 99, false).unwrap();
739 assert_eq!(note.lyrics()[3].number(), 4);
740 assert_eq!(note.lyrics()[3].text(), "last");
741 }
742
743 #[test]
744 fn note_supports_rust_conversion_traits() {
745 let parsed: Note = "C#4".parse().unwrap();
746 assert_eq!(parsed.to_string(), "C#4");
747
748 let from_pitch = Note::from(Pitch::from_name("D4").unwrap());
749 assert_eq!(from_pitch.pitch_name_with_octave(), "D4");
750
751 let from_integer = Note::try_from(60 as IntegerType).unwrap();
752 assert_eq!(from_integer.pitch_name_with_octave(), "C4");
753 }
754}