1use crate::defaults::FloatType;
11use crate::display::Drawn;
12use crate::notation::Placement;
13
14#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
16#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
17pub enum SpannerKind {
18 Slur,
20 Crescendo,
22 Diminuendo,
24 Ottava,
26 Line,
29 PedalMark,
31 TrillExtension,
34 ArpeggioMark,
37 Glissando,
40 TremoloSpanner,
42 Neume,
45}
46
47impl SpannerKind {
48 pub fn class_name(self) -> &'static str {
50 match self {
51 Self::Slur => "Slur",
52 Self::Crescendo => "Crescendo",
53 Self::Diminuendo => "Diminuendo",
54 Self::Ottava => "Ottava",
55 Self::Line => "Line",
56 Self::PedalMark => "PedalMark",
57 Self::ArpeggioMark => "ArpeggioMarkSpanner",
58 Self::TrillExtension => "TrillExtension",
59 Self::Glissando => "Glissando",
60 Self::TremoloSpanner => "TremoloSpanner",
61 Self::Neume => "Neume",
62 }
63 }
64
65 pub fn numbering_class(self) -> &'static str {
69 match self {
70 Self::Crescendo | Self::Diminuendo => "DynamicWedge",
71 other => other.class_name(),
72 }
73 }
74
75 pub fn is_wedge(self) -> bool {
77 matches!(self, Self::Crescendo | Self::Diminuendo)
78 }
79}
80
81#[derive(Clone, Debug, PartialEq, Eq)]
83#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
84#[must_use]
85pub struct Spanner {
86 kind: SpannerKind,
87 spanned: Vec<Option<usize>>,
90 #[cfg_attr(feature = "serde", serde(default))]
91 placement: Drawn<Option<Placement>>,
92 #[cfg_attr(feature = "serde", serde(default))]
93 line_type: Drawn<Option<String>>,
94 #[cfg_attr(feature = "serde", serde(default))]
95 spread: Drawn<Option<FloatType>>,
96 #[cfg_attr(feature = "serde", serde(default))]
97 shift: Option<OctaveShift>,
98 #[cfg_attr(feature = "serde", serde(default))]
99 ends: Drawn<LineEnds>,
100 #[cfg_attr(feature = "serde", serde(default))]
101 pedal: Option<Pedal>,
102 #[cfg_attr(feature = "serde", serde(default))]
103 arpeggio: crate::expressions::ArpeggioType,
104 #[cfg_attr(feature = "serde", serde(default))]
105 glissando: Option<Glissando>,
106 #[cfg_attr(feature = "serde", serde(default))]
107 marks: Option<u8>,
108 #[cfg_attr(feature = "serde", serde(default))]
109 offset: Drawn<FloatType>,
110}
111
112#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)]
114#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
115pub enum SlideType {
116 #[default]
118 Chromatic,
119 Continuous,
121 Diatonic,
123 White,
125 Black,
127}
128
129impl SlideType {
130 pub fn as_str(self) -> &'static str {
133 match self {
134 Self::Chromatic => "chromatic",
135 Self::Continuous => "continuous",
136 Self::Diatonic => "diatonic",
137 Self::White => "white",
138 Self::Black => "black",
139 }
140 }
141
142 pub fn from_name(name: &str) -> crate::error::Result<Self> {
148 let lower = name.to_lowercase();
149 [
150 Self::Chromatic,
151 Self::Continuous,
152 Self::Diatonic,
153 Self::White,
154 Self::Black,
155 ]
156 .into_iter()
157 .find(|kind| kind.as_str() == lower)
158 .ok_or_else(|| crate::error::Error::Value(format!("not a valid value: {name}")))
159 }
160}
161
162#[derive(Clone, Debug, PartialEq, Eq, Hash, Default)]
165#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
166pub struct Glissando {
167 pub slide_type: SlideType,
169 pub label: Option<String>,
171}
172
173#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
175#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
176pub enum PedalObjectKind {
177 Bounce,
180 GapStart,
183 GapEnd,
185}
186
187impl PedalObjectKind {
188 pub fn class_name(self) -> &'static str {
190 match self {
191 Self::Bounce => "PedalBounce",
192 Self::GapStart => "PedalGapStart",
193 Self::GapEnd => "PedalGapEnd",
194 }
195 }
196
197 pub fn from_class_name(name: &str) -> Option<Self> {
199 [Self::Bounce, Self::GapStart, Self::GapEnd]
200 .into_iter()
201 .find(|kind| kind.class_name() == name)
202 }
203}
204
205#[derive(Clone, Debug, PartialEq, Eq, Hash)]
209#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
210#[must_use]
211pub struct PedalObject {
212 kind: PedalObjectKind,
213 #[cfg_attr(feature = "serde", serde(default))]
214 placement: Drawn<Option<Placement>>,
215}
216
217impl PedalObject {
218 pub fn new(kind: PedalObjectKind) -> Self {
220 Self {
221 kind,
222 placement: Drawn(None),
223 }
224 }
225
226 pub fn kind(&self) -> PedalObjectKind {
228 self.kind
229 }
230
231 pub fn placement(&self) -> Option<Placement> {
233 self.placement.0
234 }
235
236 pub fn set_placement(&mut self, placement: Option<Placement>) {
238 self.placement.0 = placement;
239 }
240}
241
242#[derive(Clone, Copy, Debug, PartialEq, Default)]
245#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
246pub struct LineEnds {
247 pub start: LineEnd,
249 pub end: LineEnd,
251 pub start_height: Option<FloatType>,
253 pub end_height: Option<FloatType>,
255}
256
257#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)]
259#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
260pub enum LineEnd {
261 Up,
263 #[default]
265 Down,
266 Arrow,
268 Both,
270 None,
272}
273
274impl LineEnd {
275 pub fn as_str(self) -> &'static str {
278 match self {
279 Self::Up => "up",
280 Self::Down => "down",
281 Self::Arrow => "arrow",
282 Self::Both => "both",
283 Self::None => "none",
284 }
285 }
286
287 pub fn from_name(name: &str) -> crate::error::Result<Self> {
289 Ok(match name.to_lowercase().as_str() {
290 "up" => Self::Up,
291 "down" => Self::Down,
292 "arrow" => Self::Arrow,
293 "both" => Self::Both,
294 "none" => Self::None,
295 other => {
296 return Err(crate::error::Error::Value(format!(
297 "not a valid value: {other}"
298 )));
299 }
300 })
301 }
302}
303
304#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
306#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
307pub enum PedalType {
308 Sustain,
310 Sostenuto,
312 Soft,
314 Silent,
316}
317
318#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
320#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
321pub enum PedalForm {
322 Line,
324 Symbol,
326 SymbolAlt,
328 SymbolLine,
330}
331
332#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)]
336#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
337pub struct Pedal {
338 pub pedal_type: Option<PedalType>,
340 pub form: Option<PedalForm>,
342 pub abbreviated: bool,
344}
345
346impl PedalType {
347 pub fn as_str(self) -> &'static str {
349 match self {
350 Self::Sustain => "sustain",
351 Self::Sostenuto => "sostenuto",
352 Self::Soft => "soft",
353 Self::Silent => "silent",
354 }
355 }
356
357 pub fn from_name(name: &str) -> Option<Self> {
359 [Self::Sustain, Self::Sostenuto, Self::Soft, Self::Silent]
360 .into_iter()
361 .find(|kind| kind.as_str() == name)
362 }
363}
364
365impl PedalForm {
366 pub fn as_str(self) -> &'static str {
369 match self {
370 Self::Line => "line",
371 Self::Symbol => "symbol",
372 Self::SymbolAlt => "symbolalt",
373 Self::SymbolLine => "symbolline",
374 }
375 }
376
377 pub fn from_name(name: &str) -> Option<Self> {
379 [Self::Line, Self::Symbol, Self::SymbolAlt, Self::SymbolLine]
380 .into_iter()
381 .find(|form| form.as_str() == name)
382 }
383
384 pub fn has_line(self) -> bool {
386 matches!(self, Self::Line | Self::SymbolLine)
387 }
388}
389
390#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
393#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
394pub struct OctaveShift {
395 size: u8,
396 up: bool,
397 transposing: bool,
398}
399
400impl OctaveShift {
401 pub fn from_name(name: &str, transposing: bool) -> crate::error::Result<Self> {
405 let (size, up) = match name.to_lowercase().as_str() {
406 "8va" => (8, true),
407 "8vb" => (8, false),
408 "15ma" => (15, true),
409 "15mb" => (15, false),
410 "22da" => (22, true),
411 "22db" => (22, false),
412 other => {
413 return Err(crate::error::Error::Value(format!(
414 "cannot create Ottava of type: {other}"
415 )));
416 }
417 };
418 Ok(Self {
419 size,
420 up,
421 transposing,
422 })
423 }
424
425 pub fn name(&self) -> &'static str {
427 match (self.size, self.up) {
428 (8, true) => "8va",
429 (8, false) => "8vb",
430 (15, true) => "15ma",
431 (15, false) => "15mb",
432 (_, true) => "22da",
433 (_, false) => "22db",
434 }
435 }
436
437 pub fn magnitude(&self) -> u8 {
439 self.size
440 }
441
442 pub fn up(&self) -> bool {
444 self.up
445 }
446
447 pub fn transposing(&self) -> bool {
450 self.transposing
451 }
452
453 pub fn set_transposing(&mut self, transposing: bool) {
457 self.transposing = transposing;
458 }
459
460 pub fn interval(&self) -> crate::interval::Interval {
463 let name = if self.up {
464 format!("P{}", self.size)
465 } else {
466 format!("P-{}", self.size)
467 };
468 crate::interval::Interval::from_name(&name)
469 .expect("a perfect octave, fifteenth or twenty-second is an interval")
470 }
471}
472
473impl Spanner {
474 pub fn new(kind: SpannerKind, spanned: Vec<usize>) -> Self {
476 Self::with_unplaced(kind, spanned.into_iter().map(Some).collect())
477 }
478
479 pub fn with_unplaced(kind: SpannerKind, spanned: Vec<Option<usize>>) -> Self {
484 Self {
485 kind,
486 spanned,
487 placement: Drawn(None),
488 line_type: Drawn(None),
489 spread: Drawn(None),
490 shift: None,
491 ends: Drawn(LineEnds::default()),
492 pedal: None,
493 arpeggio: crate::expressions::ArpeggioType::Normal,
494 glissando: None,
495 marks: None,
496 offset: Drawn(0.0),
497 }
498 }
499
500 pub fn glissando(spanned: Vec<usize>) -> Self {
503 let mut glissando = Self::new(SpannerKind::Glissando, spanned);
504 glissando.line_type = Drawn(Some("wavy".to_string()));
505 glissando.glissando = Some(Glissando::default());
506 glissando
507 }
508
509 pub fn glissando_details(&self) -> Option<&Glissando> {
511 self.glissando.as_ref()
512 }
513
514 pub fn set_glissando_details(&mut self, glissando: Option<Glissando>) {
516 self.glissando = glissando;
517 }
518
519 pub fn tremolo(marks: u8, spanned: Vec<usize>) -> crate::error::Result<Self> {
526 let mut tremolo = Self::new(SpannerKind::TremoloSpanner, spanned);
527 tremolo.set_number_of_marks(Some(marks))?;
528 Ok(tremolo)
529 }
530
531 pub fn number_of_marks(&self) -> Option<u8> {
534 self.marks
535 }
536
537 pub fn set_number_of_marks(&mut self, marks: Option<u8>) -> crate::error::Result<()> {
543 if marks.is_some_and(|marks| marks > 8) {
544 return Err(crate::error::Error::Value(
545 "Number of marks must be a number from 0 to 8".to_string(),
546 ));
547 }
548 self.marks = marks;
549 Ok(())
550 }
551
552 pub fn offset(&self) -> FloatType {
556 self.offset.0
557 }
558
559 pub fn set_offset(&mut self, offset: FloatType) {
561 self.offset.0 = offset;
562 }
563
564 pub fn arpeggio_mark(arpeggio: crate::expressions::ArpeggioType, spanned: Vec<usize>) -> Self {
566 let mut mark = Self::new(SpannerKind::ArpeggioMark, spanned);
567 mark.arpeggio = arpeggio;
568 mark
569 }
570
571 pub fn arpeggio(&self) -> crate::expressions::ArpeggioType {
573 self.arpeggio
574 }
575
576 pub fn set_arpeggio(&mut self, arpeggio: crate::expressions::ArpeggioType) {
578 self.arpeggio = arpeggio;
579 }
580
581 pub fn line(spanned: Vec<usize>) -> Self {
584 let mut line = Self::new(SpannerKind::Line, spanned);
585 line.line_type = Drawn(Some("solid".to_string()));
586 line
587 }
588
589 pub fn ends(&self) -> LineEnds {
591 self.ends.0
592 }
593
594 pub fn set_ends(&mut self, ends: LineEnds) {
596 self.ends.0 = ends;
597 }
598
599 pub fn pedal_mark(pedal: Pedal, spanned: Vec<usize>) -> Self {
601 let mut mark = Self::new(SpannerKind::PedalMark, spanned);
602 mark.pedal = Some(pedal);
603 mark
604 }
605
606 pub fn pedal(&self) -> Option<Pedal> {
608 self.pedal
609 }
610
611 pub fn set_pedal(&mut self, pedal: Option<Pedal>) {
613 self.pedal = pedal;
614 }
615
616 pub fn ottava(shift: OctaveShift, spanned: Vec<usize>) -> Self {
619 let mut ottava = Self::new(SpannerKind::Ottava, spanned);
620 ottava.placement = Drawn(Some(Placement::Above));
621 ottava.shift = Some(shift);
622 ottava
623 }
624
625 pub fn shift(&self) -> Option<OctaveShift> {
627 self.shift
628 }
629
630 pub fn set_shift(&mut self, shift: Option<OctaveShift>) {
632 self.shift = shift;
633 }
634
635 pub fn slur(spanned: Vec<usize>) -> Self {
637 Self::new(SpannerKind::Slur, spanned)
638 }
639
640 pub fn wedge(kind: SpannerKind, spanned: Vec<usize>) -> Self {
643 let mut wedge = Self::new(kind, spanned);
644 wedge.placement = Drawn(Some(Placement::Below));
645 wedge.spread = Drawn(Some(15.0));
646 wedge
647 }
648
649 pub fn spread(&self) -> Option<FloatType> {
652 self.spread.0
653 }
654
655 pub fn set_spread(&mut self, spread: Option<FloatType>) {
657 self.spread.0 = spread;
658 }
659
660 pub fn kind(&self) -> SpannerKind {
662 self.kind
663 }
664
665 pub fn spanned(&self) -> &[Option<usize>] {
668 &self.spanned
669 }
670
671 pub(crate) fn spanned_mut(&mut self) -> &mut Vec<Option<usize>> {
674 &mut self.spanned
675 }
676
677 pub(crate) fn move_places(&mut self, moved: &[Option<usize>]) {
680 for place in &mut self.spanned {
681 *place = place.and_then(|old| moved.get(old).copied().flatten());
682 }
683 }
684
685 pub(crate) fn drop_repeated_places(&mut self) {
688 let mut seen: Vec<usize> = Vec::new();
689 self.spanned.retain(|place| match place {
690 Some(place) if seen.contains(place) => false,
691 Some(place) => {
692 seen.push(*place);
693 true
694 }
695 None => true,
696 });
697 }
698
699 pub fn len(&self) -> usize {
701 self.spanned.len()
702 }
703
704 pub fn is_empty(&self) -> bool {
706 self.spanned.is_empty()
707 }
708
709 pub fn is_first(&self, position: usize) -> bool {
712 self.spanned.first() == Some(&Some(position))
713 }
714
715 pub fn is_last(&self, position: usize) -> bool {
718 self.spanned.last() == Some(&Some(position))
719 }
720
721 pub fn placement(&self) -> Option<Placement> {
723 self.placement.0
724 }
725
726 pub fn set_placement(&mut self, placement: Option<Placement>) {
728 self.placement.0 = placement;
729 }
730
731 pub fn line_type(&self) -> Option<&str> {
734 self.line_type.0.as_deref()
735 }
736
737 pub fn set_line_type(&mut self, line_type: Option<String>) {
739 self.line_type.0 = line_type;
740 }
741}
742
743#[cfg(test)]
744mod tests {
745 use super::*;
746
747 #[test]
748 fn a_spanner_knows_its_ends() {
749 let slur = Spanner::slur(vec![3, 4, 5]);
750 assert!(slur.is_first(3));
751 assert!(slur.is_last(5));
752 assert!(!slur.is_first(4) && !slur.is_last(4));
753 assert_eq!(slur.kind().class_name(), "Slur");
754 }
755}