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}
50
51impl Note {
52 pub fn from_name(name: impl AsRef<str>) -> Result<Self> {
54 Pitch::from_name(name).map(Self::from_pitch)
55 }
56
57 pub fn from_number(number: FloatType) -> Result<Self> {
59 Pitch::from_number(number).map(Self::from_pitch)
60 }
61
62 pub fn from_pitch(pitch: Pitch) -> Self {
64 Self {
65 pitch,
66 duration: None,
67 notation: Notation::default(),
68 }
69 }
70
71 pub fn pitch(&self) -> &Pitch {
73 &self.pitch
74 }
75
76 pub fn set_pitch(&mut self, pitch: Pitch) {
79 self.pitch = pitch;
80 }
81
82 pub fn pitch_name(&self) -> String {
84 self.pitch.name()
85 }
86
87 pub fn pitch_name_with_octave(&self) -> String {
89 self.pitch.name_with_octave()
90 }
91
92 pub fn step(&self) -> char {
94 self.pitch.step().as_char()
95 }
96
97 pub fn octave(&self) -> crate::defaults::Octave {
99 self.pitch.octave()
100 }
101
102 pub fn pitches(&self) -> Vec<Pitch> {
104 vec![self.pitch.clone()]
105 }
106
107 pub fn full_name(&self) -> String {
110 match self.duration.as_ref() {
111 Some(duration) => format!("{} {} Note", self.pitch.full_name(), duration.full_name()),
112 None => format!("{} Note", self.pitch.full_name()),
113 }
114 }
115
116 pub fn duration(&self) -> Option<&Duration> {
118 self.duration.as_ref()
119 }
120
121 pub fn set_duration(&mut self, duration: Duration) {
123 self.duration = Some(duration);
124 }
125
126 pub fn with_duration(mut self, duration: Duration) -> Self {
128 self.set_duration(duration);
129 self
130 }
131
132 pub fn grace_note(&self, appoggiatura: bool) -> Self {
150 let written = self.duration.clone().unwrap_or_default();
151 self.clone()
152 .with_duration(written.grace_duration_as(appoggiatura))
153 }
154
155 pub fn transpose(&self, interval: &Interval) -> Result<Self> {
158 Ok(Self {
159 pitch: interval.transpose_pitch(&self.pitch)?,
160 duration: self.duration.clone(),
161 notation: self.notation.clone(),
162 })
163 }
164
165 pub fn beams(&self) -> &Beams {
170 &self.notation.beams
171 }
172
173 pub fn beams_mut(&mut self) -> &mut Beams {
175 &mut self.notation.beams
176 }
177
178 pub fn set_beams(&mut self, beams: Beams) {
180 self.notation.beams = beams;
181 }
182
183 pub fn tie(&self) -> Option<&Tie> {
185 self.notation.tie.as_ref()
186 }
187
188 pub fn set_tie(&mut self, tie: Option<Tie>) {
190 self.notation.tie = tie;
191 }
192
193 pub fn notehead(&self) -> Notehead {
195 self.notation.notehead
196 }
197
198 pub fn set_notehead(&mut self, notehead: Notehead) {
200 self.notation.notehead = notehead;
201 }
202
203 pub fn notehead_fill(&self) -> Option<bool> {
207 self.notation.notehead_fill
208 }
209
210 pub fn set_notehead_fill(&mut self, fill: Option<bool>) {
212 self.notation.notehead_fill = fill;
213 }
214
215 pub fn notehead_parenthesis(&self) -> bool {
217 self.notation.notehead_parenthesis
218 }
219
220 pub fn set_notehead_parenthesis(&mut self, parenthesis: bool) {
222 self.notation.notehead_parenthesis = parenthesis;
223 }
224
225 pub fn stem_direction(&self) -> StemDirection {
227 self.notation.stem_direction
228 }
229
230 pub fn set_stem_direction(&mut self, direction: StemDirection) {
232 self.notation.stem_direction = direction;
233 }
234
235 pub fn color(&self) -> Option<&str> {
238 self.notation.color.as_deref()
239 }
240
241 pub fn set_color(&mut self, color: Option<String>) {
243 self.notation.color = color;
244 }
245
246 pub fn size(&self) -> Option<NoteSize> {
249 self.notation.size
250 }
251
252 pub fn set_size(&mut self, size: Option<NoteSize>) {
254 self.notation.size = size;
255 }
256
257 pub fn volume(&self) -> Volume {
261 self.notation.volume.clone().unwrap_or_default()
262 }
263
264 pub fn set_volume(&mut self, volume: Option<Volume>) {
266 self.notation.volume = volume;
267 }
268
269 pub fn stored_instrument(&self) -> Option<&Instrument> {
272 self.notation.stored_instrument.as_deref()
273 }
274
275 pub fn set_stored_instrument(&mut self, instrument: Option<Instrument>) {
277 self.notation.stored_instrument = instrument.map(Box::new);
278 }
279
280 pub fn instrument(&self) -> Option<&Instrument> {
284 self.stored_instrument()
285 }
286
287 pub fn has_volume_information(&self) -> bool {
292 self.notation.volume.is_some()
293 }
294
295 pub fn expressions(&self) -> &[Expression] {
298 &self.notation.expressions
299 }
300
301 pub fn expressions_mut(&mut self) -> &mut Vec<Expression> {
303 &mut self.notation.expressions
304 }
305
306 pub fn hidden(&self) -> bool {
310 self.notation.hidden
311 }
312
313 pub fn set_hidden(&mut self, hidden: bool) {
315 self.notation.hidden = hidden;
316 }
317
318 pub fn id(&self) -> Option<&str> {
322 self.notation.id.as_deref()
323 }
324
325 pub fn set_id(&mut self, id: Option<String>) {
327 self.notation.id = id;
328 }
329
330 pub fn articulations(&self) -> &[Articulation] {
333 &self.notation.articulations
334 }
335
336 pub fn articulations_mut(&mut self) -> &mut Vec<Articulation> {
338 &mut self.notation.articulations
339 }
340
341 pub fn lyrics(&self) -> &[Lyric] {
343 &self.notation.lyrics
344 }
345
346 pub fn lyrics_mut(&mut self) -> &mut Vec<Lyric> {
348 &mut self.notation.lyrics
349 }
350
351 pub fn lyric(&self) -> Option<String> {
354 verses::joined(&self.notation.lyrics)
355 }
356
357 pub fn set_lyric(&mut self, lyric: Option<&str>) -> Result<()> {
361 verses::set(&mut self.notation.lyrics, lyric);
362 Ok(())
363 }
364
365 pub fn add_lyric(
374 &mut self,
375 text: &str,
376 number: Option<IntegerType>,
377 apply_raw: bool,
378 ) -> Result<()> {
379 verses::add(&mut self.notation.lyrics, text, number, apply_raw);
380 Ok(())
381 }
382
383 pub fn insert_lyric(&mut self, text: &str, index: usize, apply_raw: bool) -> Result<()> {
388 verses::insert(&mut self.notation.lyrics, text, index, apply_raw);
389 Ok(())
390 }
391}
392
393impl FromStr for Note {
394 type Err = crate::error::Error;
395
396 fn from_str(value: &str) -> Result<Self> {
397 Self::from_name(value)
398 }
399}
400
401impl TryFrom<&str> for Note {
402 type Error = crate::error::Error;
403
404 fn try_from(value: &str) -> Result<Self> {
405 Self::from_name(value)
406 }
407}
408
409impl TryFrom<String> for Note {
410 type Error = crate::error::Error;
411
412 fn try_from(value: String) -> Result<Self> {
413 Self::from_name(value)
414 }
415}
416
417impl From<Pitch> for Note {
418 fn from(value: Pitch) -> Self {
419 Self::from_pitch(value)
420 }
421}
422
423impl From<&Pitch> for Note {
424 fn from(value: &Pitch) -> Self {
425 Self::from_pitch(value.clone())
426 }
427}
428
429impl TryFrom<IntegerType> for Note {
430 type Error = crate::error::Error;
431
432 fn try_from(value: IntegerType) -> Result<Self> {
433 Self::from_number(value as FloatType)
434 }
435}
436
437impl Display for Note {
438 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
439 write!(f, "{}", self.pitch_name_with_octave())
440 }
441}
442
443pub trait IntoNote {
448 const FROM_INTEGER_PITCH: bool = false;
450
451 fn try_into_note(self) -> Result<Note>;
453}
454
455impl IntoNote for Note {
456 fn try_into_note(self) -> Result<Note> {
457 Ok(self)
458 }
459}
460
461impl IntoNote for &Note {
462 fn try_into_note(self) -> Result<Note> {
463 Ok(self.clone())
464 }
465}
466
467impl IntoNote for Pitch {
468 fn try_into_note(self) -> Result<Note> {
469 Ok(Note::from_pitch(self))
470 }
471}
472
473impl IntoNote for &Pitch {
474 fn try_into_note(self) -> Result<Note> {
475 Ok(Note::from_pitch(self.clone()))
476 }
477}
478
479impl IntoNote for String {
480 fn try_into_note(self) -> Result<Note> {
481 Note::from_name(self)
482 }
483}
484
485impl IntoNote for &String {
486 fn try_into_note(self) -> Result<Note> {
487 Note::from_name(self.as_str())
488 }
489}
490
491impl IntoNote for &str {
492 fn try_into_note(self) -> Result<Note> {
493 Note::from_name(self)
494 }
495}
496
497impl IntoNote for IntegerType {
498 const FROM_INTEGER_PITCH: bool = true;
499
500 fn try_into_note(self) -> Result<Note> {
501 Note::from_number(self as FloatType)
502 }
503}
504
505#[cfg(test)]
506mod tests {
507 #[test]
508 fn a_note_keeps_the_instrument_it_is_played_on() {
509 let mut note = super::Note::from_name("C4").unwrap();
510 assert!(note.instrument().is_none());
511 let piccolo = crate::Instrument::of_kind("Piccolo").unwrap();
512 note.set_stored_instrument(Some(piccolo.clone()));
513 assert_eq!(note.stored_instrument(), Some(&piccolo));
514 assert_eq!(note.instrument(), Some(&piccolo));
515 note.set_stored_instrument(None);
516 assert!(note.instrument().is_none());
517 }
518
519 #[test]
520 fn a_note_is_built_from_a_name_or_a_pitch_and_carries_beams_and_lyrics() {
521 use super::Note;
522 use crate::notation::{BeamType, Beams, Lyric};
523 use crate::pitch::Pitch;
524
525 let note = Note::try_from("Eb4".to_string()).unwrap();
526 assert_eq!(note.pitch_name(), "Eb");
527 let pitch = Pitch::from_name("G#3").unwrap();
528 let mut from_pitch = Note::from(&pitch);
529 assert_eq!(from_pitch.pitch_name(), "G#");
530 assert_eq!(from_pitch.notehead_fill(), None);
531 from_pitch.set_notehead_fill(Some(true));
532 assert_eq!(from_pitch.notehead_fill(), Some(true));
533
534 assert!(from_pitch.beams().is_empty());
535 from_pitch.beams_mut().append(BeamType::Start, None);
536 assert_eq!(from_pitch.beams().beams().len(), 1);
537 from_pitch.set_beams(Beams::default());
538 assert!(from_pitch.beams().is_empty());
539
540 from_pitch.lyrics_mut().push(Lyric::new("la"));
541 assert_eq!(from_pitch.lyrics().len(), 1);
542 assert_eq!(from_pitch.lyrics()[0].text(), "la");
543 }
544
545 #[test]
546 fn full_name_step_and_octave_match_music21() {
547 let flat = Note::from_name("Eb4").unwrap();
548 assert_eq!(flat.full_name(), "E-flat in octave 4 Note");
549 assert_eq!(flat.step(), 'E');
550 assert_eq!(flat.octave(), Some(4));
551 assert_eq!(flat.pitches()[0].name_with_octave(), "Eb4");
552 let dotted = Note::from_name("C#5")
553 .unwrap()
554 .with_duration(crate::Duration::new(1.5).unwrap());
555 assert_eq!(
556 dotted.full_name(),
557 "C-sharp in octave 5 Dotted Quarter Note"
558 );
559 let bare = Note::from_name("G").unwrap();
560 assert_eq!(bare.octave(), None);
561 assert_eq!(bare.full_name(), "G Note");
562 }
563 use super::{IntoNote, Note};
564 use crate::defaults::IntegerType;
565 use crate::pitch::Pitch;
566
567 #[test]
568 fn into_note_accepts_note_like_inputs() {
569 fn from_integer_pitch<T: IntoNote>() -> bool {
570 T::FROM_INTEGER_PITCH
571 }
572
573 assert!(!from_integer_pitch::<&str>());
574 assert!(from_integer_pitch::<IntegerType>());
575
576 let note = Note::from_name("C4").unwrap();
577 assert_eq!(
578 note.clone()
579 .try_into_note()
580 .unwrap()
581 .pitch_name_with_octave(),
582 "C4"
583 );
584
585 let borrowed_note = Note::from_name("D4").unwrap();
586 assert_eq!(
587 (&borrowed_note)
588 .try_into_note()
589 .unwrap()
590 .pitch_name_with_octave(),
591 "D4"
592 );
593
594 let pitch = Pitch::from_name("E4").unwrap();
595 assert_eq!(
596 pitch.try_into_note().unwrap().pitch_name_with_octave(),
597 "E4"
598 );
599
600 let borrowed_pitch = Pitch::from_name("F4").unwrap();
601 assert_eq!(
602 (&borrowed_pitch)
603 .try_into_note()
604 .unwrap()
605 .pitch_name_with_octave(),
606 "F4"
607 );
608
609 assert_eq!(
610 "G4".to_string()
611 .try_into_note()
612 .unwrap()
613 .pitch_name_with_octave(),
614 "G4"
615 );
616
617 let owned_name = "A4".to_string();
618 assert_eq!(
619 (&owned_name)
620 .try_into_note()
621 .unwrap()
622 .pitch_name_with_octave(),
623 "A4"
624 );
625
626 assert_eq!("B4".try_into_note().unwrap().pitch_name_with_octave(), "B4");
627
628 assert_eq!(
629 (60 as IntegerType)
630 .try_into_note()
631 .unwrap()
632 .pitch_name_with_octave(),
633 "C4"
634 );
635 }
636
637 #[test]
638 fn transposing_a_note_keeps_its_duration() {
639 let note = Note::from_name("C4")
640 .unwrap()
641 .with_duration(crate::Duration::half());
642 let moved = note
643 .transpose(&crate::Interval::from_name("M3").unwrap())
644 .unwrap();
645 assert_eq!(moved.pitch_name_with_octave(), "E4");
646 assert_eq!(moved.duration().unwrap().quarter_length(), 2.0);
647 }
648
649 #[test]
650 fn setting_a_pitch_keeps_the_duration_and_the_notation() {
651 let mut note = Note::from_name("C4")
652 .unwrap()
653 .with_duration(crate::Duration::half());
654 note.set_notehead(crate::Notehead::Diamond);
655 note.set_pitch(crate::Pitch::from_name("Eb5").unwrap());
656 assert_eq!(note.pitch_name_with_octave(), "Eb5");
657 assert_eq!(note.duration().unwrap().quarter_length(), 2.0);
658 assert_eq!(note.notehead(), crate::Notehead::Diamond);
659 }
660
661 #[test]
662 fn a_numbered_lyric_replaces_the_verse_that_has_that_number() {
663 let mut note = Note::from_name("C4").unwrap();
664 note.add_lyric("hello", None, false).unwrap();
665 note.add_lyric("bye", Some(3), false).unwrap();
666 assert_eq!(
667 note.lyrics()
668 .iter()
669 .map(|lyric| (lyric.number(), lyric.text()))
670 .collect::<Vec<_>>(),
671 [(1, "hello".to_string()), (3, "bye".to_string())]
672 );
673
674 note.add_lyric("ciao", Some(3), false).unwrap();
677 assert_eq!(note.lyrics().len(), 2);
678 assert_eq!(note.lyrics()[1].text(), "ciao");
679 assert_eq!(note.lyrics()[1].number(), 3);
680
681 let mut hyphenated = Note::from_name("C4").unwrap();
683 hyphenated.set_lyric(Some("hel-")).unwrap();
684 assert_eq!(hyphenated.lyrics()[0].raw_text(), "hel-");
685 assert_eq!(hyphenated.lyric().as_deref(), Some("hel"));
686 }
687
688 #[test]
689 fn inserting_a_lyric_moves_the_verses_after_it_down() {
690 let mut note = Note::from_name("C4").unwrap();
691 note.add_lyric("second", None, false).unwrap();
692 note.insert_lyric("first", 0, false).unwrap();
693 note.insert_lyric("newSecond", 1, false).unwrap();
694 assert_eq!(
695 note.lyrics()
696 .iter()
697 .map(|lyric| (lyric.number(), lyric.text()))
698 .collect::<Vec<_>>(),
699 [
700 (1, "first".to_string()),
701 (2, "newSecond".to_string()),
702 (3, "second".to_string())
703 ]
704 );
705 note.insert_lyric("last", 99, false).unwrap();
707 assert_eq!(note.lyrics()[3].number(), 4);
708 assert_eq!(note.lyrics()[3].text(), "last");
709 }
710
711 #[test]
712 fn note_supports_rust_conversion_traits() {
713 let parsed: Note = "C#4".parse().unwrap();
714 assert_eq!(parsed.to_string(), "C#4");
715
716 let from_pitch = Note::from(Pitch::from_name("D4").unwrap());
717 assert_eq!(from_pitch.pitch_name_with_octave(), "D4");
718
719 let from_integer = Note::try_from(60 as IntegerType).unwrap();
720 assert_eq!(from_integer.pitch_name_with_octave(), "C4");
721 }
722}