Skip to main content

music21/
spanner.rs

1//! Spanners: marks that join several notes, music21's `spanner` module.
2//!
3//! music21 keeps a spanner as an object holding the very notes it joins. A
4//! stream here owns what it holds, so a spanner names its notes by where they
5//! stand instead: by their positions in [`Stream::leaves`] of the stream the
6//! spanner belongs to, first to last.
7//!
8//! [`Stream::leaves`]: crate::Stream::leaves
9
10use crate::defaults::FloatType;
11use crate::display::Drawn;
12use crate::notation::Placement;
13
14/// Which of music21's spanner classes a spanner is.
15#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
16#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
17#[non_exhaustive]
18pub enum SpannerKind {
19    /// A curve joining notes played in one breath or bow: music21's `Slur`.
20    Slur,
21    /// A hairpin opening out, growing louder: music21's `Crescendo`.
22    Crescendo,
23    /// A hairpin closing, growing softer: music21's `Diminuendo`.
24    Diminuendo,
25    /// An octave line, `8va` or `15mb`: music21's `Ottava`.
26    Ottava,
27    /// A bracket or line over notes, as a *ligatura* or a passage to be
28    /// played together: music21's `Line`.
29    Line,
30    /// How long a pedal is held: music21's `PedalMark`.
31    PedalMark,
32    /// The wavy line carrying a trill on past its note: music21's
33    /// `TrillExtension`.
34    TrillExtension,
35    /// One arpeggio across several chords, as across both hands' staves:
36    /// music21's `ArpeggioMarkSpanner`.
37    ArpeggioMark,
38    /// A glissando or a slide from one note to the next: music21's
39    /// `Glissando`.
40    Glissando,
41    /// A tremolo alternating between two notes: music21's `TremoloSpanner`.
42    TremoloSpanner,
43    /// Notes sung to one syllable as one figure, as chant writes them:
44    /// music21's volpiano `Neume`.
45    Neume,
46    /// Rests of several measures drawn as one: music21's
47    /// `MultiMeasureRest`.
48    MultiMeasureRest,
49}
50
51impl SpannerKind {
52    /// music21's class name for the kind.
53    pub fn class_name(self) -> &'static str {
54        match self {
55            Self::Slur => "Slur",
56            Self::Crescendo => "Crescendo",
57            Self::Diminuendo => "Diminuendo",
58            Self::Ottava => "Ottava",
59            Self::Line => "Line",
60            Self::PedalMark => "PedalMark",
61            Self::ArpeggioMark => "ArpeggioMarkSpanner",
62            Self::TrillExtension => "TrillExtension",
63            Self::Glissando => "Glissando",
64            Self::TremoloSpanner => "TremoloSpanner",
65            Self::Neume => "Neume",
66            Self::MultiMeasureRest => "MultiMeasureRest",
67        }
68    }
69
70    /// The class spanners of this kind are counted with where music21 numbers
71    /// them for a score: a crescendo and a diminuendo are both hairpins,
72    /// `DynamicWedge`, and share their numbers.
73    pub fn numbering_class(self) -> &'static str {
74        match self {
75            Self::Crescendo | Self::Diminuendo => "DynamicWedge",
76            other => other.class_name(),
77        }
78    }
79
80    /// Whether this is a hairpin: music21's `DynamicWedge`.
81    pub fn is_wedge(self) -> bool {
82        matches!(self, Self::Crescendo | Self::Diminuendo)
83    }
84}
85
86/// A mark joining several notes: music21's `Spanner`.
87#[derive(Clone, Debug, PartialEq, Eq)]
88#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
89#[must_use]
90pub struct Spanner {
91    kind: SpannerKind,
92    /// Each element joined, by position, or nothing for one that stands in
93    /// no stream at all -- which music21 allows, and still counts.
94    spanned: Vec<Option<usize>>,
95    #[cfg_attr(feature = "serde", serde(default))]
96    placement: Drawn<Option<Placement>>,
97    #[cfg_attr(feature = "serde", serde(default))]
98    line_type: Drawn<Option<String>>,
99    #[cfg_attr(feature = "serde", serde(default))]
100    spread: Drawn<Option<FloatType>>,
101    #[cfg_attr(feature = "serde", serde(default))]
102    shift: Option<OctaveShift>,
103    #[cfg_attr(feature = "serde", serde(default))]
104    ends: Drawn<LineEnds>,
105    #[cfg_attr(feature = "serde", serde(default))]
106    pedal: Option<Pedal>,
107    #[cfg_attr(feature = "serde", serde(default))]
108    arpeggio: crate::expressions::ArpeggioType,
109    #[cfg_attr(feature = "serde", serde(default))]
110    glissando: Option<Glissando>,
111    #[cfg_attr(feature = "serde", serde(default))]
112    marks: Option<u8>,
113    #[cfg_attr(feature = "serde", serde(default))]
114    offset: Drawn<FloatType>,
115    #[cfg_attr(feature = "serde", serde(default))]
116    multi_rest: Option<MultiRest>,
117    /// The number a score tells it from others of its kind by: music21's
118    /// `idLocal`, MusicXML's `number`.
119    #[cfg_attr(feature = "serde", serde(default))]
120    id_local: Drawn<Option<String>>,
121    /// Whether the reader that made it saw it to its end: music21's
122    /// `completeStatus`, which only some of its readers set.
123    #[cfg_attr(feature = "serde", serde(default))]
124    complete: Drawn<bool>,
125    /// Whether the reader put it in the score itself rather than in the
126    /// part holding what it joins, as music21's MEI reader does.
127    #[cfg_attr(feature = "serde", serde(default))]
128    in_score: Drawn<bool>,
129    /// What it joins that no stream holds, each by its place among what it
130    /// joins: an ABC slur over a grace note holds the note music21 made
131    /// before copying it as a grace.
132    #[cfg_attr(feature = "serde", serde(default))]
133    unplaced: Drawn<Vec<(usize, crate::stream::StreamElement)>>,
134}
135
136/// How a rest of several measures is drawn and counted: music21's
137/// `MultiMeasureRest.useSymbols`, `maxSymbols` and `numRests`.
138#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
139#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
140pub struct MultiRest {
141    /// Whether it is drawn with rest symbols, a breve or a long, rather
142    /// than a bar with a number over it.
143    pub use_symbols: bool,
144    /// How many measures at most are drawn with symbols.
145    pub max_symbols: u32,
146    /// How many measures it is said to last where that is not how many
147    /// rests it joins.
148    pub count: Option<usize>,
149}
150
151impl Default for MultiRest {
152    /// music21's defaults: symbols, up to eleven of them.
153    fn default() -> Self {
154        Self {
155            use_symbols: true,
156            max_symbols: 11,
157            count: None,
158        }
159    }
160}
161
162/// How a glissando is played: music21's `Glissando.slideType`.
163#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)]
164#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
165pub enum SlideType {
166    /// Through every semitone between, which is how music21's starts out.
167    #[default]
168    Chromatic,
169    /// With no steps at all, a slide or a smear.
170    Continuous,
171    /// Through the notes of the scale, as a harp plays one.
172    Diatonic,
173    /// Over the white keys.
174    White,
175    /// Over the black keys.
176    Black,
177}
178
179impl SlideType {
180    /// music21's name for it: `chromatic`, `continuous`, `diatonic`,
181    /// `white` or `black`.
182    pub fn as_str(self) -> &'static str {
183        match self {
184            Self::Chromatic => "chromatic",
185            Self::Continuous => "continuous",
186            Self::Diatonic => "diatonic",
187            Self::White => "white",
188            Self::Black => "black",
189        }
190    }
191
192    /// Reads music21's name for a slide, whatever its case.
193    ///
194    /// # Errors
195    ///
196    /// A name that is none of the five, as music21's `SpannerException`.
197    pub fn from_name(name: &str) -> crate::error::Result<Self> {
198        let lower = name.to_lowercase();
199        [
200            Self::Chromatic,
201            Self::Continuous,
202            Self::Diatonic,
203            Self::White,
204            Self::Black,
205        ]
206        .into_iter()
207        .find(|kind| kind.as_str() == lower)
208        .ok_or_else(|| crate::error::Error::Value(format!("not a valid value: {name}")))
209    }
210}
211
212/// What a glissando says beside the notes it joins: how it is played and
213/// the words written along it, music21's `slideType` and `label`.
214#[derive(Clone, Debug, PartialEq, Eq, Hash, Default)]
215#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
216pub struct Glissando {
217    /// How it is played.
218    pub slide_type: SlideType,
219    /// The words along the line, *gliss.*, where it has any.
220    pub label: Option<String>,
221}
222
223/// Which of music21's pedal objects a [`PedalObject`] is.
224#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
225#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
226pub enum PedalObjectKind {
227    /// The pedal let up and put down again at once: music21's
228    /// `PedalBounce`.
229    Bounce,
230    /// Where the pedal line stops being drawn while the pedalling goes on,
231    /// usually beside *simile*: music21's `PedalGapStart`.
232    GapStart,
233    /// Where the pedal line is drawn again: music21's `PedalGapEnd`.
234    GapEnd,
235}
236
237impl PedalObjectKind {
238    /// music21's class name for it.
239    pub fn class_name(self) -> &'static str {
240        match self {
241            Self::Bounce => "PedalBounce",
242            Self::GapStart => "PedalGapStart",
243            Self::GapEnd => "PedalGapEnd",
244        }
245    }
246
247    /// Reads music21's class name for one.
248    pub fn from_class_name(name: &str) -> Option<Self> {
249        [Self::Bounce, Self::GapStart, Self::GapEnd]
250            .into_iter()
251            .find(|kind| kind.class_name() == name)
252    }
253}
254
255/// A moment inside a held pedal -- a bounce, or a gap in its line -- which
256/// stands in the stream at its own offset and is joined by the pedal mark
257/// it belongs to: music21's `PedalObject`.
258#[derive(Clone, Debug, PartialEq, Eq, Hash)]
259#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
260#[must_use]
261pub struct PedalObject {
262    kind: PedalObjectKind,
263    #[cfg_attr(feature = "serde", serde(default))]
264    placement: Drawn<Option<Placement>>,
265}
266
267impl PedalObject {
268    /// A pedal object of a kind.
269    pub fn new(kind: PedalObjectKind) -> Self {
270        Self {
271            kind,
272            placement: Drawn(None),
273        }
274    }
275
276    /// Which kind it is.
277    pub fn kind(&self) -> PedalObjectKind {
278        self.kind
279    }
280
281    /// Which side of the staff it is drawn on, where the score says.
282    pub fn placement(&self) -> Option<Placement> {
283        self.placement.0
284    }
285
286    /// Says which side of the staff it is drawn on.
287    pub fn set_placement(&mut self, placement: Option<Placement>) {
288        self.placement.0 = placement;
289    }
290}
291
292/// How a line's ends are drawn: music21's `startTick`, `endTick`,
293/// `startHeight` and `endHeight`.
294#[derive(Clone, Copy, Debug, PartialEq, Default)]
295#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
296pub struct LineEnds {
297    /// The tick at the start.
298    pub start: LineEnd,
299    /// The tick at the end.
300    pub end: LineEnd,
301    /// How long the tick at the start is, in tenths of a staff space.
302    pub start_height: Option<FloatType>,
303    /// How long the tick at the end is, in tenths of a staff space.
304    pub end_height: Option<FloatType>,
305}
306
307/// The tick at one end of a line.
308#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)]
309#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
310pub enum LineEnd {
311    /// A tick up.
312    Up,
313    /// A tick down, which is how music21's lines start out.
314    #[default]
315    Down,
316    /// An arrowhead.
317    Arrow,
318    /// A tick both ways.
319    Both,
320    /// No tick at all.
321    None,
322}
323
324impl LineEnd {
325    /// music21's name for it, which is MusicXML's too: `up`, `down`,
326    /// `arrow`, `both` or `none`.
327    pub fn as_str(self) -> &'static str {
328        match self {
329            Self::Up => "up",
330            Self::Down => "down",
331            Self::Arrow => "arrow",
332            Self::Both => "both",
333            Self::None => "none",
334        }
335    }
336
337    /// Reads music21's name for a tick, whatever its case.
338    pub fn from_name(name: &str) -> crate::error::Result<Self> {
339        Ok(match name.to_lowercase().as_str() {
340            "up" => Self::Up,
341            "down" => Self::Down,
342            "arrow" => Self::Arrow,
343            "both" => Self::Both,
344            "none" => Self::None,
345            other => {
346                return Err(crate::error::Error::Value(format!(
347                    "not a valid value: {other}"
348                )));
349            }
350        })
351    }
352}
353
354/// Which pedal a pedal mark holds down: music21's `PedalType`.
355#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
356#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
357pub enum PedalType {
358    /// The sustaining pedal.
359    Sustain,
360    /// The sostenuto pedal, which holds only the notes already down.
361    Sostenuto,
362    /// The soft pedal.
363    Soft,
364    /// A practice piano's silent pedal.
365    Silent,
366}
367
368/// How a pedal mark is drawn: music21's `PedalForm`.
369#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
370#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
371pub enum PedalForm {
372    /// A bracket under the notes held.
373    Line,
374    /// *Ped.* where it goes down and a star where it comes up.
375    Symbol,
376    /// *Ped.* where it goes down and nothing where it comes up.
377    SymbolAlt,
378    /// *Ped.* where it goes down and a line from there.
379    SymbolLine,
380}
381
382/// A pedal mark's pedal and how it is drawn: music21's `pedalType`,
383/// `pedalForm` and `abbreviated`, the first two of which a score need not
384/// say.
385#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)]
386#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
387pub struct Pedal {
388    /// Which pedal is held.
389    pub pedal_type: Option<PedalType>,
390    /// How the mark is drawn.
391    pub form: Option<PedalForm>,
392    /// Whether the symbol is shortened, *P.* for *Ped.*
393    pub abbreviated: bool,
394}
395
396impl PedalType {
397    /// music21's name for it: `sustain`, `sostenuto`, `soft` or `silent`.
398    pub fn as_str(self) -> &'static str {
399        match self {
400            Self::Sustain => "sustain",
401            Self::Sostenuto => "sostenuto",
402            Self::Soft => "soft",
403            Self::Silent => "silent",
404        }
405    }
406
407    /// Reads music21's name for a pedal.
408    pub fn from_name(name: &str) -> Option<Self> {
409        [Self::Sustain, Self::Sostenuto, Self::Soft, Self::Silent]
410            .into_iter()
411            .find(|kind| kind.as_str() == name)
412    }
413}
414
415impl PedalForm {
416    /// music21's name for it: `line`, `symbol`, `symbolalt` or
417    /// `symbolline`.
418    pub fn as_str(self) -> &'static str {
419        match self {
420            Self::Line => "line",
421            Self::Symbol => "symbol",
422            Self::SymbolAlt => "symbolalt",
423            Self::SymbolLine => "symbolline",
424        }
425    }
426
427    /// Reads music21's name for a form.
428    pub fn from_name(name: &str) -> Option<Self> {
429        [Self::Line, Self::Symbol, Self::SymbolAlt, Self::SymbolLine]
430            .into_iter()
431            .find(|form| form.as_str() == name)
432    }
433
434    /// Whether a line is drawn from where the pedal goes down.
435    pub fn has_line(self) -> bool {
436        matches!(self, Self::Line | Self::SymbolLine)
437    }
438}
439
440/// How far and which way an octave line moves the notes under it:
441/// music21's `Ottava.type`.
442#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
443#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
444pub struct OctaveShift {
445    size: u8,
446    up: bool,
447    transposing: bool,
448}
449
450impl OctaveShift {
451    /// A shift by music21's name for it: `8va`, `8vb`, `15ma`, `15mb`,
452    /// `22da` or `22db`. `transposing` says whether the notes under it are
453    /// written where they sound, as music21's `transposing` says.
454    pub fn from_name(name: &str, transposing: bool) -> crate::error::Result<Self> {
455        let (size, up) = match name.to_lowercase().as_str() {
456            "8va" => (8, true),
457            "8vb" => (8, false),
458            "15ma" => (15, true),
459            "15mb" => (15, false),
460            "22da" => (22, true),
461            "22db" => (22, false),
462            other => {
463                return Err(crate::error::Error::Value(format!(
464                    "cannot create Ottava of type: {other}"
465                )));
466            }
467        };
468        Ok(Self {
469            size,
470            up,
471            transposing,
472        })
473    }
474
475    /// music21's name for the shift, `8va`.
476    pub fn name(&self) -> &'static str {
477        match (self.size, self.up) {
478            (8, true) => "8va",
479            (8, false) => "8vb",
480            (15, true) => "15ma",
481            (15, false) => "15mb",
482            (_, true) => "22da",
483            (_, false) => "22db",
484        }
485    }
486
487    /// 8, 15 or 22: music21's `shiftMagnitude`.
488    pub fn magnitude(&self) -> u8 {
489        self.size
490    }
491
492    /// Whether the notes sound higher than written: an `8va` does.
493    pub fn up(&self) -> bool {
494        self.up
495    }
496
497    /// Whether the notes under the line are written where they sound:
498    /// music21's `transposing`.
499    pub fn transposing(&self) -> bool {
500        self.transposing
501    }
502
503    /// Says whether the notes under the line are written where they sound.
504    /// This moves no notes; [`crate::Stream::to_sounding_pitch`] and
505    /// [`crate::Stream::to_written_pitch`] move them and say so.
506    pub fn set_transposing(&mut self, transposing: bool) {
507        self.transposing = transposing;
508    }
509
510    /// How far the notes under the line sound from where they are written,
511    /// one, two or three octaves up or down: music21's `interval()`.
512    pub fn interval(&self) -> crate::interval::Interval {
513        let name = if self.up {
514            format!("P{}", self.size)
515        } else {
516            format!("P-{}", self.size)
517        };
518        crate::interval::Interval::from_name(&name)
519            .expect("a perfect octave, fifteenth or twenty-second is an interval")
520    }
521}
522
523impl Spanner {
524    /// A spanner of a kind joining the elements at these positions.
525    ///
526    /// ```
527    /// use music21::{Spanner, SpannerKind};
528    ///
529    /// let line = Spanner::new(SpannerKind::Line, vec![2, 5]);
530    /// assert_eq!(line.len(), 2);
531    /// assert_eq!(line.spanned(), [Some(2), Some(5)]);
532    /// ```
533    pub fn new(kind: SpannerKind, spanned: Vec<usize>) -> Self {
534        Self::with_unplaced(kind, spanned.into_iter().map(Some).collect())
535    }
536
537    /// A spanner of a kind joining elements some of which stand nowhere: a
538    /// score read from a file may leave a spanner holding a note no stream
539    /// holds. It still counts that note among its own, so the ends and the
540    /// length are those of the whole list.
541    pub fn with_unplaced(kind: SpannerKind, spanned: Vec<Option<usize>>) -> Self {
542        Self {
543            kind,
544            spanned,
545            placement: Drawn(None),
546            line_type: Drawn(None),
547            spread: Drawn(None),
548            shift: None,
549            ends: Drawn(LineEnds::default()),
550            pedal: None,
551            arpeggio: crate::expressions::ArpeggioType::Normal,
552            glissando: None,
553            marks: None,
554            offset: Drawn(0.0),
555            multi_rest: None,
556            id_local: Drawn(None),
557            complete: Drawn(false),
558            in_score: Drawn(false),
559            unplaced: Drawn(Vec::new()),
560        }
561    }
562
563    /// One rest of several measures over the rests at these positions,
564    /// drawn with symbols as music21's starts out.
565    pub fn multi_measure_rest(spanned: Vec<usize>) -> Self {
566        let mut rest = Self::new(SpannerKind::MultiMeasureRest, spanned);
567        rest.multi_rest = Some(MultiRest::default());
568        rest
569    }
570
571    /// How a rest of several measures is drawn and counted.
572    pub fn multi_rest(&self) -> Option<MultiRest> {
573        self.multi_rest
574    }
575
576    /// Says how a rest of several measures is drawn and counted.
577    pub fn set_multi_rest(&mut self, multi_rest: Option<MultiRest>) {
578        self.multi_rest = multi_rest;
579    }
580
581    /// How many measures a rest of several lasts: the count it was given,
582    /// or else how many rests it joins. music21's `numRests`.
583    pub fn num_rests(&self) -> usize {
584        self.multi_rest
585            .and_then(|rest| rest.count)
586            .unwrap_or(self.spanned.len())
587    }
588
589    /// A glissando over the elements at these positions, drawn as a wavy
590    /// line and played chromatically, as music21's starts out.
591    pub fn glissando(spanned: Vec<usize>) -> Self {
592        let mut glissando = Self::new(SpannerKind::Glissando, spanned);
593        glissando.line_type = Drawn(Some("wavy".to_string()));
594        glissando.glissando = Some(Glissando::default());
595        glissando
596    }
597
598    /// How a glissando is played and what is written along it.
599    pub fn glissando_details(&self) -> Option<&Glissando> {
600        self.glissando.as_ref()
601    }
602
603    /// Says how a glissando is played and what is written along it.
604    pub fn set_glissando_details(&mut self, glissando: Option<Glissando>) {
605        self.glissando = glissando;
606    }
607
608    /// A tremolo alternating between the elements at these positions, with
609    /// so many strokes through the stems.
610    ///
611    /// # Errors
612    ///
613    /// More than eight strokes, as music21's `TremoloException`.
614    pub fn tremolo(marks: u8, spanned: Vec<usize>) -> crate::error::Result<Self> {
615        let mut tremolo = Self::new(SpannerKind::TremoloSpanner, spanned);
616        tremolo.set_number_of_marks(Some(marks))?;
617        Ok(tremolo)
618    }
619
620    /// How many strokes a tremolo between notes is written with: music21's
621    /// `numberOfMarks`.
622    pub fn number_of_marks(&self) -> Option<u8> {
623        self.marks
624    }
625
626    /// Says how many strokes a tremolo between notes is written with.
627    ///
628    /// # Errors
629    ///
630    /// More than eight, as music21's `TremoloException`.
631    pub fn set_number_of_marks(&mut self, marks: Option<u8>) -> crate::error::Result<()> {
632        if marks.is_some_and(|marks| marks > 8) {
633            return Err(crate::error::Error::Value(
634                "Number of marks must be a number from 0 to 8".to_string(),
635            ));
636        }
637        self.marks = marks;
638        Ok(())
639    }
640
641    /// Where the spanner itself stands in the stream holding it: nought for
642    /// one a score is read with. A pedal mark drawn as a sign and a line
643    /// says where its line resumes by it.
644    pub fn offset(&self) -> FloatType {
645        self.offset.0
646    }
647
648    /// Says where the spanner itself stands in the stream holding it.
649    pub fn set_offset(&mut self, offset: FloatType) {
650        self.offset.0 = offset;
651    }
652
653    /// One arpeggio across the chords at these positions.
654    pub fn arpeggio_mark(arpeggio: crate::expressions::ArpeggioType, spanned: Vec<usize>) -> Self {
655        let mut mark = Self::new(SpannerKind::ArpeggioMark, spanned);
656        mark.arpeggio = arpeggio;
657        mark
658    }
659
660    /// Which way an arpeggio across several chords is spread.
661    pub fn arpeggio(&self) -> crate::expressions::ArpeggioType {
662        self.arpeggio
663    }
664
665    /// Says which way an arpeggio across several chords is spread.
666    pub fn set_arpeggio(&mut self, arpeggio: crate::expressions::ArpeggioType) {
667        self.arpeggio = arpeggio;
668    }
669
670    /// A line over the elements at these positions, solid with a tick down
671    /// at each end, as music21's starts out.
672    pub fn line(spanned: Vec<usize>) -> Self {
673        let mut line = Self::new(SpannerKind::Line, spanned);
674        line.line_type = Drawn(Some("solid".to_string()));
675        line
676    }
677
678    /// How a line's ends are drawn.
679    pub fn ends(&self) -> LineEnds {
680        self.ends.0
681    }
682
683    /// Says how a line's ends are drawn.
684    pub fn set_ends(&mut self, ends: LineEnds) {
685        self.ends.0 = ends;
686    }
687
688    /// A pedal held under the elements at these positions.
689    pub fn pedal_mark(pedal: Pedal, spanned: Vec<usize>) -> Self {
690        let mut mark = Self::new(SpannerKind::PedalMark, spanned);
691        mark.pedal = Some(pedal);
692        mark
693    }
694
695    /// Which pedal a pedal mark holds and how it is drawn.
696    pub fn pedal(&self) -> Option<Pedal> {
697        self.pedal
698    }
699
700    /// Says which pedal a pedal mark holds and how it is drawn.
701    pub fn set_pedal(&mut self, pedal: Option<Pedal>) {
702        self.pedal = pedal;
703    }
704
705    /// An octave line over the elements at these positions, drawn above them
706    /// as music21's starts out.
707    ///
708    /// ```
709    /// use music21::{OctaveShift, Spanner};
710    ///
711    /// let ottava = Spanner::ottava(OctaveShift::from_name("8va", true)?, vec![0, 1]);
712    /// let shift = ottava.shift().expect("an ottava shifts");
713    /// assert_eq!(shift.name(), "8va");
714    /// assert!(shift.up());
715    /// # Ok::<(), music21::Error>(())
716    /// ```
717    pub fn ottava(shift: OctaveShift, spanned: Vec<usize>) -> Self {
718        let mut ottava = Self::new(SpannerKind::Ottava, spanned);
719        ottava.placement = Drawn(Some(Placement::Above));
720        ottava.shift = Some(shift);
721        ottava
722    }
723
724    /// How far and which way an octave line moves its notes.
725    pub fn shift(&self) -> Option<OctaveShift> {
726        self.shift
727    }
728
729    /// Says how far and which way an octave line moves its notes.
730    pub fn set_shift(&mut self, shift: Option<OctaveShift>) {
731        self.shift = shift;
732    }
733
734    /// A slur over the elements at these positions.
735    ///
736    /// ```
737    /// use music21::{Note, Spanner, SpannerKind, Stream};
738    ///
739    /// let mut stream = Stream::new();
740    /// for name in ["C4", "D4", "E4"] {
741    ///     stream.push(Note::from_name(name)?);
742    /// }
743    /// // The slur names its notes by their places in `Stream::leaves`.
744    /// stream.add_spanner(Spanner::slur(vec![0, 1, 2]));
745    /// let slur = &stream.spanners()[0];
746    /// assert_eq!(slur.kind(), SpannerKind::Slur);
747    /// assert!(slur.is_first(0) && slur.is_last(2));
748    /// # Ok::<(), music21::Error>(())
749    /// ```
750    pub fn slur(spanned: Vec<usize>) -> Self {
751        Self::new(SpannerKind::Slur, spanned)
752    }
753
754    /// A hairpin over the elements at these positions, drawn below them and
755    /// opening fifteen tenths wide, as music21's starts out.
756    ///
757    /// ```
758    /// use music21::{Spanner, SpannerKind};
759    ///
760    /// let hairpin = Spanner::wedge(SpannerKind::Crescendo, vec![0, 3]);
761    /// assert!(hairpin.kind().is_wedge());
762    /// assert_eq!(hairpin.kind().class_name(), "Crescendo");
763    /// ```
764    pub fn wedge(kind: SpannerKind, spanned: Vec<usize>) -> Self {
765        let mut wedge = Self::new(kind, spanned);
766        wedge.placement = Drawn(Some(Placement::Below));
767        wedge.spread = Drawn(Some(15.0));
768        wedge
769    }
770
771    /// How wide a hairpin opens, in tenths of a staff space: music21's
772    /// `spread`.
773    pub fn spread(&self) -> Option<FloatType> {
774        self.spread.0
775    }
776
777    /// Says how wide a hairpin opens.
778    pub fn set_spread(&mut self, spread: Option<FloatType>) {
779        self.spread.0 = spread;
780    }
781
782    /// Which kind of spanner this is.
783    pub fn kind(&self) -> SpannerKind {
784        self.kind
785    }
786
787    /// The positions of the elements it joins, first to last, nothing for
788    /// one that stands in no stream.
789    ///
790    /// ```
791    /// use music21::Spanner;
792    ///
793    /// let slur = Spanner::slur(vec![4, 5, 6]);
794    /// assert_eq!(slur.spanned(), [Some(4), Some(5), Some(6)]);
795    /// ```
796    pub fn spanned(&self) -> &[Option<usize>] {
797        &self.spanned
798    }
799
800    /// The positions of the elements it joins, to be moved where an edit
801    /// has moved them.
802    pub(crate) fn spanned_mut(&mut self) -> &mut Vec<Option<usize>> {
803        &mut self.spanned
804    }
805
806    /// Moves each place it names to where `moved` says that element now
807    /// stands, indexed by the old place: nothing for one no longer held.
808    pub(crate) fn move_places(&mut self, moved: &[Option<usize>]) {
809        for place in &mut self.spanned {
810            *place = place.and_then(|old| moved.get(old).copied().flatten());
811        }
812    }
813
814    /// Joins an element once where moving its places has made it join one
815    /// twice, keeping the first.
816    pub(crate) fn drop_repeated_places(&mut self) {
817        let mut seen: Vec<usize> = Vec::new();
818        self.spanned.retain(|place| match place {
819            Some(place) if seen.contains(place) => false,
820            Some(place) => {
821                seen.push(*place);
822                true
823            }
824            None => true,
825        });
826    }
827
828    /// How many elements it joins, those standing nowhere included.
829    pub fn len(&self) -> usize {
830        self.spanned.len()
831    }
832
833    /// Whether it joins nothing at all.
834    pub fn is_empty(&self) -> bool {
835        self.spanned.is_empty()
836    }
837
838    /// Whether the element at a position is the first it joins: music21's
839    /// `isFirst`.
840    pub fn is_first(&self, position: usize) -> bool {
841        self.spanned.first() == Some(&Some(position))
842    }
843
844    /// Whether the element at a position is the last it joins: music21's
845    /// `isLast`.
846    pub fn is_last(&self, position: usize) -> bool {
847        self.spanned.last() == Some(&Some(position))
848    }
849
850    /// Whether the element at a position is among those it joins:
851    /// music21's `hasSpannedElement`.
852    pub fn has_spanned_element(&self, position: usize) -> bool {
853        self.spanned.contains(&Some(position))
854    }
855
856    /// Joins the elements at these positions too, after those it joins
857    /// already, in the order given: music21's `addSpannedElements`, which
858    /// joins an element once however often it is added.
859    ///
860    /// ```
861    /// use music21::Spanner;
862    ///
863    /// let mut slur = Spanner::slur(vec![1]);
864    /// slur.add_spanned_elements([2, 3, 1]);
865    /// assert_eq!(slur.spanned(), [Some(1), Some(2), Some(3)]);
866    /// ```
867    pub fn add_spanned_elements(&mut self, positions: impl IntoIterator<Item = usize>) {
868        for position in positions {
869            if !self.has_spanned_element(position) {
870                self.spanned.push(Some(position));
871            }
872        }
873    }
874
875    /// Joins the element at a position first, before the rest: music21's
876    /// `insertFirstSpannedElement`. One it joins already stays where it
877    /// is.
878    pub fn insert_first_spanned_element(&mut self, position: usize) {
879        if !self.has_spanned_element(position) {
880            self.spanned.insert(0, Some(position));
881        }
882    }
883
884    /// Joins the element at `new` where it joined the one at `old`:
885    /// music21's `replaceSpannedElement`. Where it joins `new` already it
886    /// just lets `old` go, and where it does not join `old` nothing
887    /// changes.
888    ///
889    /// ```
890    /// use music21::Spanner;
891    ///
892    /// let mut slur = Spanner::slur(vec![1, 2, 3]);
893    /// slur.replace_spanned_element(3, 4);
894    /// assert_eq!(slur.spanned(), [Some(1), Some(2), Some(4)]);
895    /// ```
896    pub fn replace_spanned_element(&mut self, old: usize, new: usize) {
897        if self.has_spanned_element(new) {
898            self.spanned.retain(|place| *place != Some(old));
899            return;
900        }
901        for place in &mut self.spanned {
902            if *place == Some(old) {
903                *place = Some(new);
904            }
905        }
906    }
907
908    /// Which side of the notes it is drawn on, where the score says.
909    pub fn placement(&self) -> Option<Placement> {
910        self.placement.0
911    }
912
913    /// Says which side of the notes it is drawn on.
914    pub fn set_placement(&mut self, placement: Option<Placement>) {
915        self.placement.0 = placement;
916    }
917
918    /// The number a score tells it from others of its kind by: music21's
919    /// `idLocal`.
920    pub fn id_local(&self) -> Option<&str> {
921        self.id_local.0.as_deref()
922    }
923
924    /// Sets the number it is told apart by, or clears it.
925    pub fn set_id_local(&mut self, id_local: Option<String>) {
926        self.id_local.0 = id_local;
927    }
928
929    /// What it joins that no stream holds, each by its place among what it
930    /// joins, where [`Spanner::spanned`] says nothing.
931    pub fn unplaced_elements(&self) -> &[(usize, crate::stream::StreamElement)] {
932        &self.unplaced.0
933    }
934
935    /// Says what it joins at `place` that no stream holds.
936    pub fn set_unplaced_element(&mut self, place: usize, element: crate::stream::StreamElement) {
937        self.unplaced.0.retain(|(held, _)| *held != place);
938        self.unplaced.0.push((place, element));
939        self.unplaced.0.sort_by_key(|(held, _)| *held);
940    }
941
942    /// Whether the reader put it in the score itself, after its last
943    /// measure, rather than in the part holding what it joins: music21's
944    /// MEI reader appends its slurs to the score.
945    pub fn stands_in_score(&self) -> bool {
946        self.in_score.0
947    }
948
949    /// Says whether it stands in the score itself.
950    pub fn set_stands_in_score(&mut self, in_score: bool) {
951        self.in_score.0 = in_score;
952    }
953
954    /// Whether the reader that made it saw it to its end: music21's
955    /// `completeStatus`.
956    pub fn complete(&self) -> bool {
957        self.complete.0
958    }
959
960    /// Says whether it was seen to its end.
961    pub fn set_complete(&mut self, complete: bool) {
962        self.complete.0 = complete;
963    }
964
965    /// How its line is drawn where that is not solid, `dashed` or `dotted`:
966    /// music21's `style.lineType`.
967    pub fn line_type(&self) -> Option<&str> {
968        self.line_type.0.as_deref()
969    }
970
971    /// Says how its line is drawn.
972    pub fn set_line_type(&mut self, line_type: Option<String>) {
973        self.line_type.0 = line_type;
974    }
975}
976
977#[cfg(test)]
978mod tests {
979    use super::*;
980
981    #[test]
982    fn a_spanner_knows_its_ends() {
983        let slur = Spanner::slur(vec![3, 4, 5]);
984        assert!(slur.is_first(3));
985        assert!(slur.is_last(5));
986        assert!(!slur.is_first(4) && !slur.is_last(4));
987        assert_eq!(slur.kind().class_name(), "Slur");
988    }
989
990    #[test]
991    fn an_element_is_joined_once_in_the_order_added() {
992        // music21's own example: g, then f# and e, then d- and c.
993        let mut line = Spanner::new(SpannerKind::Line, vec![]);
994        line.add_spanned_elements([1]);
995        line.add_spanned_elements([2, 3]);
996        line.add_spanned_elements([4, 5, 2]);
997        assert_eq!(
998            line.spanned(),
999            [Some(1), Some(2), Some(3), Some(4), Some(5)]
1000        );
1001        assert!(line.has_spanned_element(4));
1002        assert!(!line.has_spanned_element(6));
1003    }
1004
1005    #[test]
1006    fn an_element_inserted_first_goes_before_the_rest() {
1007        let mut line = Spanner::new(SpannerKind::Line, vec![2, 3, 4, 5]);
1008        line.insert_first_spanned_element(1);
1009        assert_eq!(
1010            line.spanned(),
1011            [Some(1), Some(2), Some(3), Some(4), Some(5)]
1012        );
1013        // One joined already is neither added again nor moved.
1014        line.insert_first_spanned_element(4);
1015        assert_eq!(
1016            line.spanned(),
1017            [Some(1), Some(2), Some(3), Some(4), Some(5)]
1018        );
1019
1020        let mut empty = Spanner::new(SpannerKind::Line, vec![]);
1021        empty.insert_first_spanned_element(7);
1022        assert_eq!(empty.spanned(), [Some(7)]);
1023    }
1024
1025    #[test]
1026    fn a_replaced_element_keeps_its_place() {
1027        let mut slur = Spanner::slur(vec![1, 2, 3]);
1028        slur.replace_spanned_element(1, 9);
1029        assert_eq!(slur.spanned(), [Some(9), Some(2), Some(3)]);
1030        // Nothing joined at the old place changes nothing.
1031        slur.replace_spanned_element(6, 7);
1032        assert_eq!(slur.spanned(), [Some(9), Some(2), Some(3)]);
1033        // A replacement it joins already lets the old one go.
1034        slur.replace_spanned_element(2, 3);
1035        assert_eq!(slur.spanned(), [Some(9), Some(3)]);
1036    }
1037
1038    #[test]
1039    fn a_multi_measure_rest_counts_its_rests() {
1040        let mut rest = Spanner::multi_measure_rest(vec![1, 2, 3]);
1041        assert_eq!(rest.num_rests(), 3);
1042        assert!(rest.multi_rest().is_some_and(|said| said.use_symbols));
1043
1044        rest.set_multi_rest(Some(MultiRest {
1045            count: Some(10),
1046            ..MultiRest::default()
1047        }));
1048        assert_eq!(rest.num_rests(), 10);
1049    }
1050}