Skip to main content

music21/meter/
mod.rs

1//! Time signatures, ported from music21's `meter` package.
2//!
3//! [`TimeSignature`] covers the part of music21's meter handling that is a pure
4//! function of the numerator and denominator: how long a bar is, how many beats
5//! it carries, how long each beat is, and how that beat subdivides.
6//!
7//! music21 derives all of this from a `MeterSequence` partition tree, and so
8//! does this: a meter carries the four sequences music21 hangs off one — the
9//! display, the beats, the beams and the accents — and answers from them.
10//! [`TimeSignature::beams_for`] beams a run of notes against the beam
11//! sequence, and the weights come off the accent sequence, so a caller who
12//! sets them reads their own back. The partition rule is music21's
13//! `_setDefaultBeatPartitions`, verified
14//! against upstream by the `meter_parity` fixture.
15
16pub mod sequence;
17
18pub use sequence::{MeterTerminal, OffsetAlign};
19
20use crate::defaults::{FloatType, UnsignedIntegerType};
21use crate::duration::Duration;
22use crate::duration::DurationType;
23use crate::error::{Error, Result};
24use crate::notation::{BeamType, Beams};
25
26/// What a partition of `count` parts is called: music21's `partitionStr`,
27/// `"Duple"` for two and `"Triple"` for three. Counts above eight are spelled
28/// `"<n>-uple"`, as music21 spells them.
29#[must_use]
30pub fn partition_name(count: usize) -> String {
31    BEAT_COUNT_NAMES
32        .get(count)
33        .map_or_else(|| format!("{count}-uple"), |name| (*name).to_string())
34}
35
36/// Names music21 gives a partition count, indexed by the count itself.
37///
38/// Index 0 is music21's `Empty`, which a valid time signature never reaches.
39const BEAT_COUNT_NAMES: [&str; 9] = [
40    "Empty",
41    "Single",
42    "Duple",
43    "Triple",
44    "Quadruple",
45    "Quintuple",
46    "Sextuple",
47    "Septuple",
48    "Octuple",
49];
50
51/// How the beat of a meter subdivides.
52///
53/// Mirrors music21's `beatDivisionCountName`.
54#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
55#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
56pub enum BeatDivision {
57    /// A single-beat meter, which music21 reports as `Other` rather than as a
58    /// division — there is no lower level to divide.
59    Other,
60    /// Beats divide in two.
61    Simple,
62    /// Beats divide in three.
63    Compound,
64}
65
66impl BeatDivision {
67    /// Returns music21's name for this division.
68    pub fn music21_name(&self) -> &'static str {
69        match self {
70            Self::Other => "Other",
71            Self::Simple => "Simple",
72            Self::Compound => "Compound",
73        }
74    }
75
76    /// Returns the number of divisions in one beat.
77    ///
78    /// Matches music21's `beatDivisionCount`, which reports `1` rather than
79    /// raising for a single-beat meter.
80    pub fn count(&self) -> UnsignedIntegerType {
81        match self {
82            Self::Other => 1,
83            Self::Simple => 2,
84            Self::Compound => 3,
85        }
86    }
87}
88
89/// A time signature, such as `4/4` or `6/8`.
90///
91/// ```
92/// use music21::TimeSignature;
93///
94/// let six_eight = TimeSignature::from_ratio_string("6/8")?;
95/// assert_eq!(six_eight.beat_count(), 2);
96/// assert_eq!(six_eight.beat_quarter_length(), 1.5);
97/// assert_eq!(six_eight.classification(), "Compound Duple");
98/// # Ok::<(), music21::Error>(())
99/// ```
100/// Not `Copy`, `Eq` or `Hash`: a meter is about to carry the partitions it
101/// is felt in, and those weigh their parts in floats.
102#[derive(Clone, Debug, PartialEq)]
103#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
104#[must_use]
105pub struct TimeSignature {
106    numerator: UnsignedIntegerType,
107    denominator: UnsignedIntegerType,
108    favor_compound: bool,
109    display_sequence: MeterTerminal,
110    beat_sequence: MeterTerminal,
111    beam_sequence: MeterTerminal,
112    accent_sequence: MeterTerminal,
113    /// How the signature is drawn where it is not drawn as numbers.
114    #[cfg_attr(feature = "serde", serde(default))]
115    symbol: Option<String>,
116    #[cfg_attr(feature = "serde", serde(default))]
117    symbolize_denominator: bool,
118    #[cfg_attr(feature = "serde", serde(default))]
119    color: crate::display::Color,
120    /// Whether this is an earlier measure's meter standing a second time.
121    #[cfg_attr(feature = "serde", serde(default))]
122    restated: crate::display::Drawn<bool>,
123    #[cfg_attr(feature = "serde", serde(default))]
124    hidden: crate::display::Drawn<bool>,
125    /// A bar length written over the meter's own: music21's
126    /// `_overriddenBarDuration`, which contradicts the meter on purpose.
127    #[cfg_attr(feature = "serde", serde(default))]
128    overridden_bar_duration: Option<Duration>,
129}
130
131impl Default for TimeSignature {
132    /// Returns `4/4`, matching music21's default `TimeSignature()`.
133    fn default() -> Self {
134        Self::common()
135    }
136}
137
138/// The largest numerator a [`TimeSignature`] takes. A meter is built with
139/// a part for each beat it counts, so the limit bounds the work one
140/// signature costs; meters in use count far fewer.
141pub const MAX_NUMERATOR: UnsignedIntegerType = 10_000;
142
143impl TimeSignature {
144    /// Creates a time signature from a numerator and denominator.
145    ///
146    /// Both must be non-zero, and the numerator no more than
147    /// [`MAX_NUMERATOR`]. The denominator need not be a power of two —
148    /// music21 accepts irrational meters such as `4/3`, and so does this.
149    pub fn new(numerator: UnsignedIntegerType, denominator: UnsignedIntegerType) -> Result<Self> {
150        if numerator == 0 {
151            return Err(Error::Meter(
152                "time signature numerator must be non-zero".to_string(),
153            ));
154        }
155        if denominator == 0 {
156            return Err(Error::Meter(
157                "time signature denominator must be non-zero".to_string(),
158            ));
159        }
160        if numerator > MAX_NUMERATOR {
161            return Err(Error::Meter(format!(
162                "time signature numerator {numerator} is more than {MAX_NUMERATOR}"
163            )));
164        }
165        let mut signature = Self {
166            numerator,
167            denominator,
168            favor_compound: favor_compound(numerator, denominator, None),
169            display_sequence: whole_bar(numerator, denominator)?,
170            beat_sequence: whole_bar(numerator, denominator)?,
171            beam_sequence: whole_bar(numerator, denominator)?,
172            accent_sequence: whole_bar(numerator, denominator)?,
173            symbol: None,
174            symbolize_denominator: false,
175            color: crate::display::Drawn(None),
176            restated: crate::display::Drawn(false),
177            hidden: crate::display::Drawn(false),
178            overridden_bar_duration: None,
179        };
180        signature.set_default_partitions()?;
181        Ok(signature)
182    }
183
184    /// How the signature is drawn where it is not drawn as numbers: music21's
185    /// `symbol`, `common` for the C of `4/4` or `cut` for the struck C of
186    /// `2/2`, and nothing where it is written as numbers.
187    pub fn symbol(&self) -> Option<&str> {
188        self.symbol.as_deref()
189    }
190
191    /// Says how the signature is drawn, or that it is written as numbers.
192    pub fn set_symbol(&mut self, symbol: Option<String>) {
193        self.symbol = symbol.filter(|symbol| !symbol.is_empty());
194    }
195
196    /// Whether this is the meter an earlier measure states, standing again
197    /// in a later one, rather than a meter of its own.
198    ///
199    /// music21 holds a meter as an object, and one object may stand in
200    /// several measures: its ABC reader gives a measure the meter in force
201    /// back, the very object, after cutting an overlong measure in two.
202    /// music21's `makeTies` then finds that meter only where it stands last,
203    /// which decides where it cuts, so a reader that restates a meter says
204    /// so here. Two meters differing only in this are equal.
205    pub fn is_restated(&self) -> bool {
206        self.restated.0
207    }
208
209    /// Says whether this is an earlier measure's meter standing again.
210    pub fn set_restated(&mut self, restated: bool) {
211        self.restated.0 = restated;
212    }
213
214    /// Whether the denominator is drawn as a note rather than a number:
215    /// music21's `symbolizeDenominator`.
216    pub fn symbolize_denominator(&self) -> bool {
217        self.symbolize_denominator
218    }
219
220    /// Says whether the denominator is drawn as a note.
221    pub fn set_symbolize_denominator(&mut self, symbolize: bool) {
222        self.symbolize_denominator = symbolize;
223    }
224
225    /// The colour the signature is drawn in, if one was said. Two meters
226    /// differing only in colour are equal.
227    pub fn color(&self) -> Option<&str> {
228        self.color.0.as_deref()
229    }
230
231    /// Sets the colour the signature is drawn in.
232    pub fn set_color(&mut self, color: Option<String>) {
233        self.color.0 = color;
234    }
235
236    /// Whether the signature is left off the page while still in force:
237    /// music21's `style.hideObjectOnPrint`. Two meters differing only in
238    /// this are equal.
239    pub fn is_hidden(&self) -> bool {
240        self.hidden.0
241    }
242
243    /// Says whether the signature is left off the page.
244    pub fn set_hidden(&mut self, hidden: bool) {
245        self.hidden.0 = hidden;
246    }
247
248    /// How the bar is written, before anything divides it: music21's
249    /// `displaySequence`. A meter written additively as `"3/8+2/8"` is two
250    /// parts here, and that is what makes the beats fall where they are
251    /// written rather than where the numerator alone would put them.
252    #[must_use]
253    pub fn display_sequence(&self) -> &MeterTerminal {
254        &self.display_sequence
255    }
256
257    /// How the bar is counted: music21's `beatSequence`, one part per beat,
258    /// each divided again into what the beat is felt in.
259    #[must_use]
260    pub fn beat_sequence(&self) -> &MeterTerminal {
261        &self.beat_sequence
262    }
263
264    /// How the bar is beamed: music21's `beamSequence`, the groups a run of
265    /// short notes is written in.
266    #[must_use]
267    pub fn beam_sequence(&self) -> &MeterTerminal {
268        &self.beam_sequence
269    }
270
271    /// How the bar is weighted: music21's `accentSequence`, one part per
272    /// accent partition, each carrying the weight [`Self::accent_weights`]
273    /// gives it.
274    #[must_use]
275    pub fn accent_sequence(&self) -> &MeterTerminal {
276        &self.accent_sequence
277    }
278
279    /// Whether the bar is felt in compound beats: music21's `favorCompound`,
280    /// which is what counts a `6/8` in two and a `slow 6/8` in six.
281    #[must_use]
282    pub fn favors_compound(&self) -> bool {
283        self.favor_compound
284    }
285
286    /// Counts the bar the way a sequence says: music21's `beatSequence`
287    /// assigned, as `ts.beatSequence = ts.beatSequence.partitioned(2)`.
288    pub fn set_beat_sequence(&mut self, sequence: MeterTerminal) {
289        self.beat_sequence = sequence;
290    }
291
292    /// Beams the bar the way a sequence says: music21's `beamSequence`
293    /// assigned.
294    pub fn set_beam_sequence(&mut self, sequence: MeterTerminal) {
295        self.beam_sequence = sequence;
296    }
297
298    /// Weighs the bar the way a sequence says: music21's `accentSequence`
299    /// assigned.
300    pub fn set_accent_sequence(&mut self, sequence: MeterTerminal) {
301        self.accent_sequence = sequence;
302    }
303
304    /// Writes the bar the way a sequence says: music21's `displaySequence`
305    /// assigned.
306    pub fn set_display_sequence(&mut self, sequence: MeterTerminal) {
307        self.display_sequence = sequence;
308    }
309
310    /// Writes the bar a different way without changing what it counts:
311    /// music21's `setDisplay`.
312    ///
313    /// A bar of `3/4` set to display as `"2/8+2/8+2/8"` is still three
314    /// quarters long and still counted in three; what changes is how it is
315    /// written. The value has to come to the same length as the bar, since a
316    /// bar cannot be written as something it is not.
317    pub fn set_display(&mut self, value: &str) -> Result<()> {
318        let parts = Self::parts(value)?;
319        let denominator = parts
320            .iter()
321            .map(|(_, part)| *part)
322            .max()
323            .unwrap_or(self.denominator);
324        let numerator = parts
325            .iter()
326            .fold(0, |sum: UnsignedIntegerType, (count, part)| {
327                sum.saturating_add(count.saturating_mul(denominator / part))
328            });
329        let display = whole_bar(numerator, denominator)?;
330        if (display.quarter_length() - self.bar_quarter_length()).abs() > OFFSET_TOLERANCE {
331            return Err(Error::Meter(format!(
332                "cannot write a {} bar as {value:?}: that is {} quarter lengths, not {}",
333                self.ratio_string(),
334                display.quarter_length(),
335                self.bar_quarter_length()
336            )));
337        }
338        if parts.len() > 1 {
339            let written: Vec<String> = parts
340                .iter()
341                .map(|(count, part)| format!("{count}/{part}"))
342                .collect();
343            let borrowed: Vec<&str> = written.iter().map(String::as_str).collect();
344            self.display_sequence = display.partitioned_by_parts(&borrowed)?;
345            return Ok(());
346        }
347        self.display_sequence = display;
348        Ok(())
349    }
350
351    /// Divides the beats into `count` parts, leaving each part undivided:
352    /// the `divisions` a meter is built with.
353    ///
354    /// This is not [`Self::set_beat_count`]: music21 partitions the beats
355    /// here and stops, so `TimeSignature("6/8", 2)` is `{3/8+3/8}` where
356    /// counting a `6/8` in two gives `{{1/8+1/8+1/8}+{1/8+1/8+1/8}}`.
357    pub fn divide_beats(&mut self, count: UnsignedIntegerType) -> Result<()> {
358        if count == 0 {
359            return Err(Error::Meter(
360                "a bar cannot be divided into no parts".to_string(),
361            ));
362        }
363        let divided = whole_bar(self.numerator, self.denominator)?
364            .partitioned_by_count(count as usize, false)?;
365        // music21 divides the beats, the accents and the beams alike here,
366        // and leaves the display saying what the bar was written as.
367        self.beat_sequence = divided.clone();
368        self.accent_sequence = divided.clone();
369        self.beam_sequence = divided;
370        Ok(())
371    }
372
373    /// Counts the bar in a different number of beats: music21's settable
374    /// `beatCount`.
375    ///
376    /// The beats are repartitioned and each divided again, so a `6/8`
377    /// counted in six is six eighths rather than two dotted quarters. A
378    /// count the bar cannot be divided into is an error.
379    pub fn set_beat_count(&mut self, count: UnsignedIntegerType) -> Result<()> {
380        if count == 0 {
381            return Err(Error::Meter(
382                "a bar cannot be counted in no beats".to_string(),
383            ));
384        }
385        let mut beats = MeterTerminal::new(self.numerator, self.denominator)?
386            .partitioned_by_count(count as usize, false)?;
387        if beats.len() > 1 {
388            beats = beats.subdivided_partitions_equal(None)?;
389        }
390        self.beat_sequence = beats;
391        Ok(())
392    }
393
394    /// Builds the beam, beat and accent partitions the way music21 does when
395    /// nobody has said how: `_setDefaultBeamPartitions`,
396    /// `_setDefaultBeatPartitions` and `_setDefaultAccentWeights`.
397    fn set_default_partitions(&mut self) -> Result<()> {
398        self.set_default_beam_partitions()?;
399        self.set_default_beat_partitions()?;
400        self.set_default_accent_weights();
401        Ok(())
402    }
403
404    /// music21's `_setDefaultBeamPartitions`: a short bar of short notes is
405    /// beamed all together, and anything else in the groups its numerator is
406    /// felt in.
407    ///
408    /// A meter written additively is beamed by these rules too — music21
409    /// beams `"3/8+2/8"` as `{2/8+3/8}`, by the rule for a five, and not in
410    /// the parts it was written in. One written with its numerators summed,
411    /// `"3+2/8"`, is the exception: it is left in the parts it was written in.
412    fn set_default_beam_partitions(&mut self) -> Result<()> {
413        let numerator = self.numerator;
414        let denominator = self.denominator;
415        if self.beam_sequence.summed_numerator() {
416            return Ok(());
417        }
418        if (denominator == 8 && matches!(numerator, 1..=3))
419            || (denominator == 16 && matches!(numerator, 1..=5))
420            || (denominator == 32 && matches!(numerator, 1..=11))
421        {
422            return Ok(());
423        }
424        let beams = &self.beam_sequence;
425        self.beam_sequence = match numerator {
426            2..=4 => {
427                let mut beams = beams.partitioned_by_count(numerator as usize, false)?;
428                if denominator == 4 {
429                    for index in 0..beams.len() {
430                        let divided = beams.parts()[index].subdivide_by_count(2)?;
431                        beams = beams.set_index(index, divided)?;
432                    }
433                }
434                beams
435            }
436            5 => {
437                let mut beams = beams.partitioned_by_list(&[2, 3])?;
438                if denominator == 4 {
439                    for (index, count) in [2, 3].into_iter().enumerate() {
440                        let divided = beams.parts()[index].subdivide_by_count(count)?;
441                        beams = beams.set_index(index, divided)?;
442                    }
443                }
444                beams
445            }
446            7 => beams.partitioned_by_count(3, false)?,
447            // Every compound numerator is beamed in threes.
448            other if other >= 6 && other.is_multiple_of(3) => {
449                beams.partitioned_by_list(&vec![3; (other / 3) as usize])?
450            }
451            _ => return Ok(()),
452        };
453        Ok(())
454    }
455
456    /// music21's `_setDefaultBeatPartitions`: the top-level count of the bar,
457    /// then each beat divided into what it is felt in.
458    ///
459    /// A meter written additively is counted in the parts it was written in,
460    /// each keeping the note it was written in — `"2/4+3/8"` is counted
461    /// `{{1/4+1/4}+{1/8+1/8+1/8}}`.
462    fn set_default_beat_partitions(&mut self) -> Result<()> {
463        let numerator = self.numerator;
464        let compound = self.favor_compound;
465        let beats = &self.beat_sequence;
466        self.beat_sequence = if self.display_sequence.len() == 1 {
467            match numerator {
468                2 => beats.partitioned_by_count(2, false)?,
469                6 if compound => beats.partitioned_by_count(2, false)?,
470                3 if compound => beats.partitioned_by_count(1, false)?,
471                3 => beats.partitioned_by_list(&[1, 1, 1])?,
472                9 if compound => beats.partitioned_by_list(&[3, 3, 3])?,
473                4 => beats.partitioned_by_count(4, false)?,
474                12 if compound => beats.partitioned_by_count(4, false)?,
475                other if other >= 15 && other.is_multiple_of(3) && compound => {
476                    beats.partitioned_by_list(&vec![3; (other / 3) as usize])?
477                }
478                other => beats.partitioned_by_count(other as usize, false)?,
479            }
480        } else {
481            let written: Vec<String> = self
482                .display_sequence
483                .parts()
484                .iter()
485                .map(|part| format!("{}/{}", part.numerator(), part.denominator()))
486                .collect();
487            let borrowed: Vec<&str> = written.iter().map(String::as_str).collect();
488            beats.partitioned_by_parts(&borrowed)?
489        };
490        if self.beat_sequence.len() > 1 {
491            // music21 forgives a bar written in notes shorter than a 128th
492            // for being too short to divide again, and nothing else.
493            match self.beat_sequence.subdivided_partitions_equal(None) {
494                Ok(divided) => self.beat_sequence = divided,
495                Err(error) if self.denominator >= 128 => {
496                    let _ = error;
497                }
498                Err(error) => return Err(error),
499            }
500        }
501        Ok(())
502    }
503
504    /// music21's `_setDefaultAccentWeights`, read off the weights this meter
505    /// already gives its accent partitions rather than derived a second time
506    /// from a nested hierarchy: one part per weight, carrying that weight.
507    fn set_default_accent_weights(&mut self) {
508        let weights = self.default_accent_weights();
509        let ones = vec![1; weights.len()];
510        let Ok(partitioned) = self.accent_sequence.partitioned_by_list(&ones) else {
511            return;
512        };
513        let weighed: Vec<MeterTerminal> = partitioned
514            .parts()
515            .iter()
516            .zip(weights)
517            .map(|(part, weight)| part.with_weight(weight))
518            .collect();
519        if let Ok(sequence) =
520            MeterTerminal::sequence(partitioned.numerator(), partitioned.denominator(), weighed)
521        {
522            self.accent_sequence = sequence.with_summed_numerator(partitioned.summed_numerator());
523        }
524    }
525
526    /// Parses a `"numerator/denominator"` string such as `"6/8"`.
527    ///
528    /// music21 writes more than a bare ratio here. A word before the ratio
529    /// says how the beat is felt — `"slow 6/8"` is counted in six and
530    /// `"fast 6/8"` in two — and a meter can be written additively, as
531    /// `"3/8+2/8"` or `"3+2/8"`, where a numerator with no denominator of
532    /// its own takes the next one written. What the parts add up to is the
533    /// meter this returns; how they are grouped is [`Self::parts`].
534    pub fn from_ratio_string(ratio: &str) -> Result<Self> {
535        let parts = Self::parts(ratio)?;
536        if parts.iter().any(|(_, part)| *part == 0) {
537            return Err(Error::Meter(format!(
538                "time signature denominator must be non-zero: {ratio}"
539            )));
540        }
541        let word = division_word(ratio);
542        let summed = ratio.split('+').any(|part| !part.contains('/'));
543        let denominator = parts[0].1;
544        if parts.iter().all(|(_, part)| *part == denominator) {
545            let numerator = parts
546                .iter()
547                .fold(0, |sum: UnsignedIntegerType, (count, _)| {
548                    sum.saturating_add(*count)
549                });
550            let mut signature = Self::new(numerator, denominator)?;
551            signature.write_as(&parts, word, summed)?;
552            return Ok(signature);
553        }
554        // Parts measured in different notes: what they come to together is
555        // the meter, over the shortest note any of them is written in.
556        let denominator = parts
557            .iter()
558            .map(|(_, part)| *part)
559            .max()
560            .unwrap_or(denominator);
561        let numerator = parts
562            .iter()
563            .fold(0, |sum: UnsignedIntegerType, (count, part)| {
564                sum.saturating_add(count.saturating_mul(denominator / part))
565            });
566        let mut signature = Self::new(numerator, denominator)?;
567        signature.write_as(&parts, word, summed)?;
568        Ok(signature)
569    }
570
571    /// Records how the meter was written — the parts it was written in, and
572    /// the word saying how it is counted — and rebuilds what depends on
573    /// either.
574    fn write_as(
575        &mut self,
576        parts: &[(UnsignedIntegerType, UnsignedIntegerType)],
577        word: Option<&str>,
578        summed: bool,
579    ) -> Result<()> {
580        self.favor_compound = favor_compound(self.numerator, self.denominator, word);
581        self.beat_sequence = whole_bar(self.numerator, self.denominator)?;
582        self.beam_sequence = whole_bar(self.numerator, self.denominator)?;
583        self.accent_sequence = whole_bar(self.numerator, self.denominator)?;
584        if parts.len() > 1 {
585            // music21 reads every sequence out of the one string, and a
586            // sequence read from its parts weighs one for each of them --
587            // which is not what partitioning a bar into the same parts
588            // gives, since that shares out the one the bar weighed. The
589            // beams and the beats begin as written; the rules by numerator
590            // then either replace those parts or leave them standing.
591            let written = parts
592                .iter()
593                .map(|(count, part)| format!("{count}/{part}"))
594                .collect::<Vec<_>>()
595                .join("+");
596            let loaded = MeterTerminal::from_partition_string(&written)?;
597            self.display_sequence = loaded.clone();
598            self.beat_sequence = loaded.clone();
599            self.beam_sequence = loaded;
600        }
601        // Every sequence is read from the one string, so each says how that
602        // string was written.
603        for sequence in [
604            &mut self.display_sequence,
605            &mut self.beat_sequence,
606            &mut self.beam_sequence,
607            &mut self.accent_sequence,
608        ] {
609            *sequence = sequence.with_summed_numerator(summed);
610        }
611        self.set_default_partitions()
612    }
613
614    /// Whether the meter was written with its numerators summed over one
615    /// denominator, `3+2/8`, rather than part by part: music21's
616    /// `summedNumerator`, which it reads off how the bar is displayed.
617    #[must_use]
618    pub fn summed_numerator(&self) -> bool {
619        self.display_sequence.summed_numerator()
620    }
621
622    /// Says whether the numerators are written summed, which changes how the
623    /// meter is printed and nothing about how it is counted.
624    pub fn set_summed_numerator(&mut self, summed: bool) {
625        self.display_sequence = self.display_sequence.with_summed_numerator(summed);
626    }
627
628    /// The `(numerator, denominator)` pairs a meter string is written in,
629    /// in the order written: music21's `slashMixedToFraction`.
630    ///
631    /// `"3/8+2/8"` is two parts and `"6/8"` is one. A part written as a bare
632    /// numerator takes the denominator of the next part that has one, which
633    /// is how `"3+2/8"` is two eighth-note parts; a string whose last part
634    /// says no denominator at all says nothing about how it is measured, and
635    /// is refused.
636    pub fn parts(ratio: &str) -> Result<Vec<(UnsignedIntegerType, UnsignedIntegerType)>> {
637        let unworded = without_division_word(ratio);
638        let written = unworded.trim();
639        if written.is_empty() {
640            return Err(Error::Meter("a time signature says nothing".to_string()));
641        }
642        let mut pre: Vec<(UnsignedIntegerType, Option<UnsignedIntegerType>)> = Vec::new();
643        for part in written.split('+') {
644            let part = part.trim();
645            match part.split_once('/') {
646                Some((numerator, denominator)) => pre.push((
647                    Self::count(numerator, "numerator", written)?,
648                    Some(Self::count(denominator, "denominator", written)?),
649                )),
650                None => pre.push((Self::count(part, "numerator", written)?, None)),
651            }
652        }
653        let mut out = Vec::with_capacity(pre.len());
654        for (index, (numerator, denominator)) in pre.iter().enumerate() {
655            let denominator = match denominator {
656                Some(denominator) => *denominator,
657                None => pre[index + 1..]
658                    .iter()
659                    .find_map(|(_, later)| *later)
660                    .ok_or_else(|| {
661                        Error::Meter(format!(
662                            "cannot match a denominator to every numerator in {written:?}"
663                        ))
664                    })?,
665            };
666            out.push((*numerator, denominator));
667        }
668        Ok(out)
669    }
670
671    /// One number out of a meter string, with the word music21 allows before
672    /// it — `"slow 6"` is six — taken off first.
673    fn count(part: &str, label: &str, ratio: &str) -> Result<UnsignedIntegerType> {
674        let digits = part
675            .trim()
676            .rsplit(|character: char| character.is_whitespace())
677            .next()
678            .unwrap_or("")
679            .trim();
680        digits
681            .parse::<UnsignedIntegerType>()
682            .map_err(|_| Error::Meter(format!("cannot read a {label} from {part:?} in {ratio:?}")))
683    }
684
685    /// Returns common time, `4/4`.
686    pub fn common() -> Self {
687        Self::new(4, 4).expect("4/4 is a meter")
688    }
689
690    /// Returns cut time, `2/2`.
691    pub fn cut() -> Self {
692        Self::new(2, 2).expect("2/2 is a meter")
693    }
694
695    /// Returns the numerator.
696    pub fn numerator(&self) -> UnsignedIntegerType {
697        self.numerator
698    }
699
700    /// Returns the denominator.
701    pub fn denominator(&self) -> UnsignedIntegerType {
702        self.denominator
703    }
704
705    /// Returns the `"numerator/denominator"` spelling.
706    pub fn ratio_string(&self) -> String {
707        // music21 reads this off the display sequence, so a bar written
708        // additively says what it was written as. The parts come back in
709        // the order they were written, which is what makes `2/8+3/8` and
710        // `3/8+2/8` different meters rather than two spellings of `5/8`.
711        if self.display_sequence.len() > 1 {
712            return self.display_sequence.partition_display();
713        }
714        format!("{}/{}", self.numerator, self.denominator)
715    }
716
717    /// Returns the length of one bar in quarter lengths.
718    pub fn bar_quarter_length(&self) -> FloatType {
719        FloatType::from(self.numerator) * 4.0 / FloatType::from(self.denominator)
720    }
721
722    /// Returns the length of one bar as a [`Duration`]: the one written
723    /// with [`TimeSignature::set_bar_duration`] where there is one, else the
724    /// meter's own.
725    pub fn bar_duration(&self) -> Duration {
726        if let Some(written) = &self.overridden_bar_duration {
727            return written.clone();
728        }
729        Duration::new(self.bar_quarter_length())
730            .expect("a non-zero numerator and denominator give a positive finite bar length")
731    }
732
733    /// Writes a bar length over the meter's own, or clears it with `None`:
734    /// music21's `barDuration` setter. Only the bar this meter reports
735    /// changes; its beats and partitions stay the meter's.
736    ///
737    /// ```
738    /// use music21::{Duration, TimeSignature};
739    ///
740    /// let mut meter = TimeSignature::new(3, 8)?;
741    /// meter.set_bar_duration(Some(Duration::new(1.75)?));
742    /// assert_eq!(meter.bar_duration().quarter_length(), 1.75);
743    /// # Ok::<(), music21::Error>(())
744    /// ```
745    pub fn set_bar_duration(&mut self, written: Option<Duration>) {
746        self.overridden_bar_duration = written;
747    }
748
749    /// The bar length written over the meter's own with
750    /// [`TimeSignature::set_bar_duration`], if any.
751    pub fn written_bar_duration(&self) -> Option<&Duration> {
752        self.overridden_bar_duration.as_ref()
753    }
754
755    /// Where an element falls in the bar this meter measures: music21's
756    /// `getMeasureOffsetOrMeterModulusOffset`, given the two offsets music21
757    /// reads off the stream.
758    ///
759    /// `element_offset` is the element's offset in its measure, or in its
760    /// stream where it has no measure; `meter_offset` is the meter's own.
761    /// Still inside the bar, the element's offset is the answer. Past it,
762    /// the meter's place is taken off and the rest wraps at the bar:
763    ///
764    /// ```text
765    ///   3/4 at 0:  element at 4.0  ->  (4.0 - 0.0) % 3.0 = 1.0
766    ///   3/4 at 1:  element at 2.5  ->  (2.5 - 1.0) % 3.0 = 1.5
767    /// ```
768    pub fn offset_in_bar(&self, element_offset: FloatType, meter_offset: FloatType) -> FloatType {
769        // music21 wraps at `barDuration`, a length written over the meter's
770        // own included.
771        let bar = self.bar_duration().quarter_length();
772
773        // music21 adds to test and subtracts to wrap; the two differ where
774        // the meter does not start the bar.
775        // music21 counts in fractions, so a meter at a third of a beat
776        // still wraps on whole bars.
777        let op_frac = crate::makenotation::op_frac;
778        if op_frac(element_offset + meter_offset) < bar {
779            return element_offset;
780        }
781        op_frac(op_frac(element_offset - meter_offset).rem_euclid(bar))
782    }
783
784    /// Returns how many beats one bar carries.
785    ///
786    /// This is music21's `beatCount`, which follows the numerator rather than
787    /// the denominator — except at `3`, where `3/4` is three beats but `3/8` is
788    /// one.
789    pub fn beat_count(&self) -> UnsignedIntegerType {
790        self.beat_sequence.len() as UnsignedIntegerType
791    }
792
793    /// Returns music21's name for the beat count, such as `"Duple"`.
794    ///
795    /// Counts above eight are spelled as `"<n>-uple"`, as music21 does.
796    pub fn beat_count_name(&self) -> String {
797        partition_name(self.beat_count() as usize)
798    }
799
800    /// Returns the length of the first beat in quarter lengths: music21's
801    /// `beatDuration`. Where the beats differ in length, as in `3/16+1/4`,
802    /// this is the first of them; [`Self::beat_duration_at`] reads any beat.
803    pub fn beat_quarter_length(&self) -> FloatType {
804        let (start, end) = self.beat_spans()[0];
805        end - start
806    }
807
808    /// Returns the length of the first beat as a [`Duration`].
809    pub fn beat_duration(&self) -> Duration {
810        Duration::new(self.beat_quarter_length())
811            .expect("a beat of a meter is a positive finite length")
812    }
813
814    /// Returns how the beat subdivides.
815    pub fn beat_division(&self) -> BeatDivision {
816        let parts = self.beat_sequence.parts();
817        if parts.len() <= 1 {
818            return BeatDivision::Other;
819        }
820        let mut counts = parts.iter().map(MeterTerminal::len);
821        let Some(first) = counts.next() else {
822            return BeatDivision::Other;
823        };
824        if first == 0 || !counts.all(|count| count == first) {
825            // The beats of a bar written additively need not divide alike;
826            // music21 reports such a meter as Other and counts one.
827            return BeatDivision::Other;
828        }
829        match first {
830            2 => BeatDivision::Simple,
831            3 => BeatDivision::Compound,
832            _ => BeatDivision::Other,
833        }
834    }
835
836    /// Returns the number of divisions in one beat.
837    pub fn beat_division_count(&self) -> UnsignedIntegerType {
838        self.beat_division().count()
839    }
840
841    /// Returns `true` when beats divide in three.
842    pub fn is_compound(&self) -> bool {
843        self.beat_division() == BeatDivision::Compound
844    }
845
846    /// Returns music21's `classification`, such as `"Compound Duple"`.
847    pub fn classification(&self) -> String {
848        format!(
849            "{} {}",
850            self.beat_division().music21_name(),
851            self.beat_count_name()
852        )
853    }
854
855    /// Returns music21's `beatDivisionCountName`: `Simple`, `Compound` or
856    /// `Other`.
857    pub fn beat_division_count_name(&self) -> &'static str {
858        self.beat_division().music21_name()
859    }
860
861    /// Returns whether two time signatures have the same numerator and
862    /// denominator: music21's `ratioEqual`, so `4/4` and `2/2` differ.
863    pub fn ratio_equal(&self, other: &TimeSignature) -> bool {
864        self.numerator == other.numerator && self.denominator == other.denominator
865    }
866
867    /// Returns how many quarter lengths one unit of the denominator lasts:
868    /// `0.5` in `6/8`, `2.0` in `2/2`.
869    pub fn beat_length_to_quarter_length_ratio(&self) -> FloatType {
870        4.0 / FloatType::from(self.denominator)
871    }
872
873    /// Returns how many denominator units make one quarter length, the
874    /// inverse of [`Self::beat_length_to_quarter_length_ratio`].
875    pub fn quarter_length_to_beat_length_ratio(&self) -> FloatType {
876        FloatType::from(self.denominator) / 4.0
877    }
878
879    /// Returns the quarter length of each division of one beat, in order:
880    /// two eighths in `4/4`, three in `6/8`, the whole dotted-quarter beat
881    /// in `3/8` where the beat does not divide.
882    ///
883    /// Read off the beat sequence as music21 reads it: the divisions of
884    /// every beat must agree, but the beats need not, so `2+3/8` divides
885    /// into eighths though its beats are a quarter and a dotted quarter.
886    ///
887    /// # Errors
888    ///
889    /// Beats that divide differently, as the quarters and eighths of
890    /// `2/4+3/8` do, which music21 refuses too.
891    pub fn beat_division_quarter_lengths(&self) -> Result<Vec<FloatType>> {
892        let beat_sequence = self.beat_sequence();
893        let beats = match beat_sequence.parts() {
894            [] => std::slice::from_ref(beat_sequence),
895            beats => beats,
896        };
897
898        // A beat with parts divides into them; one without is its own
899        // division.
900        let divisions = |beat: &MeterTerminal| -> Vec<FloatType> {
901            match beat.parts() {
902                [] => vec![beat.quarter_length()],
903                parts => parts.iter().map(MeterTerminal::quarter_length).collect(),
904            }
905        };
906
907        let every: Vec<FloatType> = beats.iter().flat_map(divisions).collect();
908        if every.windows(2).any(|pair| pair[0] != pair[1]) {
909            return Err(Error::Meter(format!(
910                "non uniform beat division: {every:?}"
911            )));
912        }
913        Ok(beats.first().map(divisions).unwrap_or_default())
914    }
915
916    /// Returns [`Self::beat_division_quarter_lengths`] as durations: music21's
917    /// `beatDivisionDurations`.
918    pub fn beat_division_durations(&self) -> Result<Vec<Duration>> {
919        self.beat_division_quarter_lengths()?
920            .into_iter()
921            .map(Duration::new)
922            .collect()
923    }
924
925    /// Returns each division of the beat halved: music21's
926    /// `beatSubDivisionDurations`, four sixteenths in `4/4`.
927    pub fn beat_sub_division_durations(&self) -> Result<Vec<Duration>> {
928        let mut out = Vec::new();
929        for quarter_length in self.beat_division_quarter_lengths()? {
930            let half = Duration::new(quarter_length / 2.0)?;
931            out.push(half.clone());
932            out.push(half);
933        }
934        Ok(out)
935    }
936
937    /// Returns the quarter-length offset of a one-based, possibly fractional
938    /// beat: music21's `getOffsetFromBeat`, so beat `2.5` of `4/4` is `1.5`
939    /// and beat `1.5` of `6/8` is `0.75`. A beat past the bar is an error.
940    pub fn offset_from_beat(&self, beat: FloatType) -> Result<FloatType> {
941        let whole = beat.floor();
942        if !beat.is_finite() || whole < 1.0 || whole > FloatType::from(self.beat_count()) {
943            return Err(Error::Meter(format!(
944                "requested beat value ({beat}) not found in the {} beats of {}",
945                self.beat_count(),
946                self.ratio_string()
947            )));
948        }
949        let (start, end) = self.beat_spans()[whole as usize - 1];
950        let fraction = snapped_fraction(beat - whole);
951        Ok(start + fraction * (end - start))
952    }
953
954    /// Returns the one-based beat containing `offset` and how far into that
955    /// beat it lies, in quarter lengths: music21's `getBeatProgress`.
956    pub fn beat_progress(&self, offset: FloatType) -> Result<(UnsignedIntegerType, FloatType)> {
957        let index = self.beat_index(offset)?;
958        let (start, _) = self.beat_spans()[index];
959        // Through `opFrac`, as music21's: a third of a beat is a sixth.
960        Ok((
961            index as UnsignedIntegerType + 1,
962            crate::makenotation::op_frac(offset - start),
963        ))
964    }
965
966    /// Returns the position within the bar as a fractional beat: music21's
967    /// `getBeatProportion`, `2.5` for the second eighth of beat two in `4/4`
968    /// and `1.333…` for the second eighth of `6/8`.
969    pub fn beat_proportion(&self, offset: FloatType) -> Result<FloatType> {
970        let (beat, progress) = self.beat_progress(offset)?;
971        let (start, end) = self.beat_spans()[beat as usize - 1];
972        Ok(crate::makenotation::op_frac(
973            FloatType::from(beat) + progress / (end - start),
974        ))
975    }
976
977    /// Returns [`Self::beat_proportion`] the way music21's
978    /// `getBeatProportionStr` writes it: the beat alone on the beat, otherwise
979    /// the beat and the fraction of it elapsed, `2 1/2`, with the fraction's
980    /// denominator limited to 16.
981    pub fn beat_proportion_string(&self, offset: FloatType) -> Result<String> {
982        let (beat, progress) = self.beat_progress(offset)?;
983        let (start, end) = self.beat_spans()[beat as usize - 1];
984        let proportion = progress / (end - start);
985        if proportion == 0.0 {
986            return Ok(beat.to_string());
987        }
988        let (numerator, denominator) = closest_fraction(proportion, 16);
989        Ok(format!("{beat} {numerator}/{denominator}"))
990    }
991
992    /// Where each beat starts and ends, in quarter lengths from the start of
993    /// the bar. The beats of a meter written additively are not all the same
994    /// length, so this is read off the beat sequence rather than divided out.
995    fn beat_spans(&self) -> Vec<(FloatType, FloatType)> {
996        let mut spans = Vec::new();
997        let mut position = 0.0;
998        for part in self.beat_sequence.parts() {
999            let end = position + part.quarter_length();
1000            spans.push((position, end));
1001            position = end;
1002        }
1003        if spans.is_empty() {
1004            spans.push((0.0, self.bar_quarter_length()));
1005        }
1006        spans
1007    }
1008
1009    /// How long the beat holding an offset is: music21's `getBeatDuration`.
1010    ///
1011    /// A meter written additively answers differently along the bar — the
1012    /// first beat of `2/4+3/8` is two quarters long and the second is three
1013    /// eighths.
1014    pub fn beat_duration_at(&self, offset: FloatType) -> Result<Duration> {
1015        let index = self.beat_index(offset)?;
1016        let (start, end) = self.beat_spans()[index];
1017        Duration::new(end - start)
1018    }
1019
1020    /// Which beat holds an offset, counted from nought.
1021    fn beat_index(&self, offset: FloatType) -> Result<usize> {
1022        if !offset.is_finite() || offset < 0.0 || offset >= self.bar_quarter_length() {
1023            return Err(Error::Meter(format!(
1024                "offset {offset} is outside a {} bar of {} quarter lengths",
1025                self.ratio_string(),
1026                self.bar_quarter_length()
1027            )));
1028        }
1029        let spans = self.beat_spans();
1030        for (index, (start, end)) in spans.iter().enumerate() {
1031            let _ = start;
1032            if offset < end - OFFSET_TOLERANCE {
1033                return Ok(index);
1034            }
1035        }
1036        Ok(spans.len() - 1)
1037    }
1038
1039    /// Returns the quarter-length offset of each beat within one bar.
1040    pub fn beat_offsets(&self) -> Vec<FloatType> {
1041        self.beat_spans()
1042            .into_iter()
1043            .map(|(start, _)| start)
1044            .collect()
1045    }
1046
1047    /// Returns the one-based beat containing `offset` quarter lengths into a bar.
1048    ///
1049    /// Matches music21's `getBeat`. Offsets at or beyond the end of the bar are
1050    /// rejected rather than wrapping.
1051    pub fn beat_at_offset(&self, offset: FloatType) -> Result<UnsignedIntegerType> {
1052        if !offset.is_finite() || offset < 0.0 || offset >= self.bar_quarter_length() {
1053            return Err(Error::Meter(format!(
1054                "offset {offset} is outside a {} bar of {} quarter lengths",
1055                self.ratio_string(),
1056                self.bar_quarter_length()
1057            )));
1058        }
1059        Ok(self.beat_index(offset)? as UnsignedIntegerType + 1)
1060    }
1061}
1062
1063/// The fraction closest to `value` with a denominator no larger than
1064/// `max_denominator`, as Python's `Fraction.limit_denominator` finds it for
1065/// the proportions music21 prints. Ties go to the smaller denominator.
1066fn closest_fraction(value: FloatType, max_denominator: u32) -> (u32, u32) {
1067    let mut best = (value.round() as u32, 1);
1068    let mut best_error = (value - value.round()).abs();
1069    for denominator in 2..=max_denominator {
1070        let numerator = (value * FloatType::from(denominator)).round();
1071        let error = (value - numerator / FloatType::from(denominator)).abs();
1072        if error < best_error {
1073            best = (numerator as u32, denominator);
1074            best_error = error;
1075        }
1076    }
1077    best
1078}
1079
1080impl std::fmt::Display for TimeSignature {
1081    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1082        f.write_str(&self.ratio_string())
1083    }
1084}
1085
1086/// How far an offset may sit from a partition boundary and still be read as
1087/// on it.
1088const OFFSET_TOLERANCE: FloatType = 1e-9;
1089
1090/// The shortest accent partition music21 can write, a 128th note.
1091const SHORTEST_PARTITION: FloatType = 4.0 / 128.0;
1092
1093/// The longest, a whole note.
1094const LONGEST_PARTITION: FloatType = 4.0;
1095
1096impl TimeSignature {
1097    /// How music21's default accent hierarchy divides the bar, three levels
1098    /// deep: how many parts the bar divides into, how many each of those
1099    /// divides into, and how many each of those divides into.
1100    ///
1101    /// music21 builds the hierarchy by subdividing a `MeterSequence`. The top
1102    /// level takes the beat count, except that one, two, four, eight, sixteen
1103    /// and thirty-two beats divide in two and three beats divide in three; a
1104    /// single beat takes the numerator's place in that rule. Below that, each
1105    /// span divides the way music21 divides a span by default: two or more
1106    /// triples into its triples, an even count of anything in two, a single
1107    /// unit in two, and an odd count into its units.
1108    fn accent_hierarchy(
1109        &self,
1110    ) -> (
1111        UnsignedIntegerType,
1112        UnsignedIntegerType,
1113        UnsignedIntegerType,
1114    ) {
1115        let beats = self.beat_count();
1116        let first = if beats > 1 { beats } else { self.numerator };
1117        let top = match first {
1118            1 | 2 | 4 | 8 | 16 | 32 => 2,
1119            3 => 3,
1120            other => other,
1121        };
1122        // A unit too short to count is shorter than a 128th, so the bar is
1123        // one partition.
1124        let Some((span, unit)) = split_span(self.numerator, self.denominator, top) else {
1125            return (1, 1, 1);
1126        };
1127        let second = default_division(span, unit);
1128        let Some((span, unit)) = split_span(span, unit, second) else {
1129            return (1, 1, 1);
1130        };
1131        let third = default_division(span, unit);
1132        // music21 partitions the accent sequence into that many equal parts
1133        // written as whole numbers of a note value, and gives up — leaving
1134        // the bar as one partition — when a part would be longer than a
1135        // whole note or shorter than a 128th.
1136        let partition = self.bar_quarter_length() / FloatType::from(top * second * third);
1137        if !(SHORTEST_PARTITION..=LONGEST_PARTITION).contains(&partition) {
1138            return (1, 1, 1);
1139        }
1140        (top, second, third)
1141    }
1142
1143    /// The length of one partition of music21's default accent hierarchy, the
1144    /// finest level the accent weights are given at.
1145    pub fn accent_partition_quarter_length(&self) -> FloatType {
1146        let parts = self.accent_sequence.parts();
1147        if parts.len() > 1 {
1148            return parts[0].quarter_length();
1149        }
1150        let (top, second, third) = self.accent_hierarchy();
1151        self.bar_quarter_length() / FloatType::from(top * second * third)
1152    }
1153
1154    /// The accent weight of every partition of the bar, music21's default
1155    /// `accentSequence`: `1.0` on the downbeat, halving with every level of
1156    /// the hierarchy a partition's start is not a boundary of, so `4/4` reads
1157    /// `1.0, 0.125, 0.25, 0.125, 0.5, 0.125, 0.25, 0.125`.
1158    pub fn accent_weights(&self) -> Vec<FloatType> {
1159        let carried: Vec<FloatType> = self
1160            .accent_sequence
1161            .parts()
1162            .iter()
1163            .map(MeterTerminal::weight)
1164            .collect();
1165        if carried.len() > 1 {
1166            return carried;
1167        }
1168        self.default_accent_weights()
1169    }
1170
1171    /// The weights music21's default hierarchy gives the bar, which is what
1172    /// the accent sequence is built carrying. Kept apart from
1173    /// [`Self::accent_weights`], which reads the sequence, so that weights a
1174    /// caller has set are the ones read back.
1175    fn default_accent_weights(&self) -> Vec<FloatType> {
1176        if !self.beat_sequence.is_uniform_partition(0)
1177            && let Some(weights) = self.accent_weights_from_the_beats()
1178        {
1179            return weights;
1180        }
1181        let (top, second, third) = self.accent_hierarchy();
1182        let count = top * second * third;
1183        (0..count)
1184            .map(|index| {
1185                let depth = 1
1186                    + UnsignedIntegerType::from(index.is_multiple_of(third))
1187                    + UnsignedIntegerType::from(index.is_multiple_of(second * third))
1188                    + UnsignedIntegerType::from(index == 0);
1189                FloatType::from(2u32.pow(depth - 1)) / 8.0
1190            })
1191            .collect()
1192    }
1193
1194    /// The default weights of a bar whose beats are not all one length,
1195    /// `3+2/8` say, which no rule over the numerator can give: the bar is
1196    /// nested three levels deep beginning from the beats as they are, and
1197    /// each partition weighs by how many of those levels begin where it does.
1198    /// This is the branch of music21's `_setDefaultAccentWeights` that is
1199    /// handed the beat sequence itself.
1200    ///
1201    /// `None` where the bar cannot be nested that far, which music21 also
1202    /// gives up on; the rule for a uniform bar answers then.
1203    fn accent_weights_from_the_beats(&self) -> Option<Vec<FloatType>> {
1204        let nested = MeterTerminal::new(self.numerator, self.denominator)
1205            .ok()?
1206            .subdivided_nested_hierarchy_by(3, &self.beat_sequence, true)
1207            .ok()?;
1208        let levels = nested.depth();
1209        if levels == 0 {
1210            return None;
1211        }
1212        let starts: Vec<Vec<FloatType>> = (0..levels)
1213            .map(|level| {
1214                nested
1215                    .level_span(level)
1216                    .into_iter()
1217                    .map(|(start, _)| start)
1218                    .collect()
1219            })
1220            .collect();
1221        // A partition of the finest level weighs by how many levels have a
1222        // part beginning where it begins.
1223        let depths: Vec<usize> = starts[levels - 1]
1224            .iter()
1225            .map(|start| {
1226                starts
1227                    .iter()
1228                    .filter(|level| {
1229                        level
1230                            .iter()
1231                            .any(|other| (other - start).abs() < OFFSET_TOLERANCE)
1232                    })
1233                    .count()
1234            })
1235            .collect();
1236        let deepest = depths.iter().copied().max()?;
1237        Some(
1238            depths
1239                .into_iter()
1240                .map(|depth| {
1241                    FloatType::from(2u32.pow(depth as u32 - 1))
1242                        / FloatType::from(2u32.pow(deepest as u32 - 1))
1243                })
1244                .collect(),
1245        )
1246    }
1247
1248    /// Whether an offset in quarter lengths starts an accent partition:
1249    /// music21's `getAccent`, which is false for any offset off the grid,
1250    /// beyond the bar included.
1251    pub fn accent(&self, offset: FloatType) -> bool {
1252        let parts = match self.accent_sequence.parts() {
1253            [] => std::slice::from_ref(&self.accent_sequence),
1254            parts => parts,
1255        };
1256        let mut position = 0.0;
1257        for part in parts {
1258            if (position - offset).abs() < OFFSET_TOLERANCE {
1259                return true;
1260            }
1261            position += part.quarter_length();
1262        }
1263        false
1264    }
1265
1266    /// The accent weight at an offset in quarter lengths: music21's
1267    /// `getAccentWeight`, the weight of the partition the offset falls in.
1268    /// An offset outside the bar is an error.
1269    pub fn accent_weight(&self, offset: FloatType) -> Result<FloatType> {
1270        self.accent_weight_with(offset, false, false)
1271    }
1272
1273    /// The accent weight at an offset, read at a level of the accent
1274    /// sequence: music21's `getAccentWeight` with its `level`.
1275    pub fn accent_weight_at_level(
1276        &self,
1277        offset: FloatType,
1278        level: usize,
1279        force_position_match: bool,
1280        permit_meter_modulus: bool,
1281    ) -> Result<FloatType> {
1282        let bar = self.bar_quarter_length();
1283        let offset = if permit_meter_modulus {
1284            offset.rem_euclid(bar)
1285        } else {
1286            offset
1287        };
1288        let offset = offset_within(offset, bar)?;
1289        let terminals = self.accent_sequence.level_list(level, true);
1290        if terminals.len() <= 1 {
1291            return self.accent_weight_with(offset, force_position_match, permit_meter_modulus);
1292        }
1293        let spans = self.accent_sequence.level_span(level);
1294        let smallest = terminals
1295            .iter()
1296            .map(MeterTerminal::weight)
1297            .fold(FloatType::INFINITY, FloatType::min);
1298        for (index, (start, end)) in spans.iter().enumerate() {
1299            if offset < end - OFFSET_TOLERANCE {
1300                if force_position_match && (offset - start).abs() >= OFFSET_TOLERANCE {
1301                    return Ok(smallest * 0.5);
1302                }
1303                return Ok(terminals[index].weight());
1304            }
1305        }
1306        Ok(terminals[terminals.len() - 1].weight())
1307    }
1308
1309    /// Weighs the accent partitions of a level, looping the weights given
1310    /// over them: music21's `setAccentWeight`.
1311    pub fn set_accent_weight(&mut self, weights: &[FloatType], level: usize) -> Result<()> {
1312        self.accent_sequence = self.accent_sequence.with_level_weight(level, weights)?;
1313        Ok(())
1314    }
1315
1316    /// [`Self::accent_weight`] with music21's two options. With
1317    /// `force_position_match` an offset that does not start a partition
1318    /// answers half the smallest weight rather than its partition's; with
1319    /// `permit_meter_modulus` an offset beyond the bar is read within it.
1320    pub fn accent_weight_with(
1321        &self,
1322        offset: FloatType,
1323        force_position_match: bool,
1324        permit_meter_modulus: bool,
1325    ) -> Result<FloatType> {
1326        let bar = self.bar_quarter_length();
1327        let offset = if permit_meter_modulus {
1328            offset.rem_euclid(bar)
1329        } else {
1330            offset
1331        };
1332        let offset = offset_within(offset, bar)?;
1333        let weights = self.accent_weights();
1334        let partition = self.accent_partition_quarter_length();
1335        let index = ((offset + OFFSET_TOLERANCE) / partition).floor() as usize;
1336        let index = index.min(weights.len() - 1);
1337        if force_position_match
1338            && (offset - index as FloatType * partition).abs() >= OFFSET_TOLERANCE
1339        {
1340            let smallest = weights
1341                .iter()
1342                .copied()
1343                .fold(FloatType::INFINITY, FloatType::min);
1344            return Ok(smallest * 0.5);
1345        }
1346        Ok(weights[index])
1347    }
1348
1349    /// The mean accent weight of what a stream holds: music21's
1350    /// `averageBeatStrength`, each element weighed where it falls in the
1351    /// bar, with an element off the accent grid counting half the smallest
1352    /// weight. Only the stream's own elements are weighed, not what the
1353    /// measures or voices inside it hold; `notes_only` weighs its notes and
1354    /// chords alone. A stream with nothing to weigh weighs nothing.
1355    pub fn average_beat_strength(&self, stream: &crate::Stream, notes_only: bool) -> FloatType {
1356        let bar = self.bar_quarter_length();
1357        let offsets: Vec<FloatType> = stream
1358            .events()
1359            .iter()
1360            .filter(|event| !notes_only || crate::makenotation::is_not_rest(event.element()))
1361            .map(crate::stream::StreamEvent::offset)
1362            .collect();
1363        if offsets.is_empty() {
1364            return 0.0;
1365        }
1366        let total: FloatType = offsets
1367            .iter()
1368            .map(|offset| {
1369                self.accent_weight_with(offset.rem_euclid(bar), true, false)
1370                    .unwrap_or(0.0)
1371            })
1372            .sum();
1373        total / offsets.len() as FloatType
1374    }
1375
1376    /// How many levels of the beat hierarchy start at an offset: music21's
1377    /// `getBeatDepth`, which quantizes the offset to the beat's division and
1378    /// then counts the beat level and the division level. A meter of one beat
1379    /// has one level and answers one everywhere in the bar; an offset outside
1380    /// the bar is an error.
1381    pub fn beat_depth(&self, offset: FloatType) -> Result<u8> {
1382        let bar = self.bar_quarter_length();
1383        if offset.is_nan() || offset < 0.0 || offset >= bar {
1384            return Err(Error::Meter(format!(
1385                "cannot access from qLenPos {}",
1386                offset_repr(offset)
1387            )));
1388        }
1389        let depth = self
1390            .beat_sequence
1391            .offset_to_depth(offset, crate::meter::OffsetAlign::Quantize)?;
1392        Ok(depth as u8)
1393    }
1394}
1395
1396/// A fractional beat read as the fraction it suggests: music21's
1397/// `addFloatPrecision`, which snaps a third, two thirds, a sixth or five
1398/// sixths written as decimals onto the fraction itself.
1399///
1400/// It is what makes the offset of beat 2.33 the same as the offset of beat
1401/// two and a third.
1402#[must_use]
1403pub fn snapped_fraction(value: FloatType) -> FloatType {
1404    const GRAIN: FloatType = 1e-2;
1405    let thirds = [1.0 / 3.0, 2.0 / 3.0, 1.0 / 6.0, 5.0 / 6.0];
1406    for candidate in thirds {
1407        if (value - candidate).abs() <= GRAIN {
1408            return candidate;
1409        }
1410    }
1411    value
1412}
1413
1414/// One of a run of notes to be beamed: where it sits in the bar, how long it
1415/// lasts, what it is written as, and whether it sounds.
1416///
1417/// A rest is beamed alongside the notes — music21 works its beams out and
1418/// then declines to write them on it — so what matters here is the written
1419/// value and whether the thing sounds, not what kind of object it is.
1420#[derive(Clone, Copy, Debug, PartialEq)]
1421pub struct BeamedNote {
1422    /// Where it starts, in quarter lengths from the start of its measure.
1423    pub offset: FloatType,
1424    /// How long it lasts, in quarter lengths.
1425    pub quarter_length: FloatType,
1426    /// The value it is written as, which says how many beams it can carry.
1427    pub duration_type: DurationType,
1428    /// Whether it sounds. A rest carries no beam however it is written.
1429    pub sounds: bool,
1430}
1431
1432impl TimeSignature {
1433    /// Beams a run of notes: music21's `getBeams`.
1434    ///
1435    /// The notes are taken as adjoining, which is how music21 takes them —
1436    /// their offsets are read only against `measure_start_offset`, for a run
1437    /// that begins part way through a bar. `measure_padding` is the measure's
1438    /// `paddingRight` where the run came from one, and `None` where it did
1439    /// not; a run that ends an incomplete measure does not get its last beam
1440    /// stopped.
1441    ///
1442    /// A run of one is beamed as nothing at all, as music21 does.
1443    pub fn beams_for(
1444        &self,
1445        notes: &[BeamedNote],
1446        measure_start_offset: FloatType,
1447        measure_padding: Option<FloatType>,
1448    ) -> Result<Vec<Option<Beams>>> {
1449        if notes.len() <= 1 {
1450            return Ok(notes.iter().map(|_| None).collect());
1451        }
1452
1453        // music21's `naiveBeams`: the fullest set of beams each written value
1454        // can carry, with what each one does left undecided.
1455        let mut beamed: Vec<Option<Beams>> = notes
1456            .iter()
1457            .map(|note| Beams::naive(Some(note.duration_type), note.sounds))
1458            .collect();
1459        crate::notation::remove_sandwiched_unbeamables(&mut beamed);
1460
1461        for depth in 0..Beams::LEVELS {
1462            for index in 0..notes.len() {
1463                self.fix_one_beam(
1464                    &mut beamed,
1465                    notes,
1466                    index,
1467                    depth,
1468                    measure_start_offset,
1469                    measure_padding,
1470                )?;
1471            }
1472        }
1473
1474        crate::notation::sanitize_partial_beams(&mut beamed);
1475        crate::notation::merge_connecting_partial_beams(&mut beamed);
1476        Ok(beamed)
1477    }
1478
1479    /// What one note's beam does at one depth: music21's
1480    /// `fixBeamsOneElementDepth`.
1481    fn fix_one_beam(
1482        &self,
1483        beamed: &mut [Option<Beams>],
1484        notes: &[BeamedNote],
1485        index: usize,
1486        depth: usize,
1487        measure_start_offset: FloatType,
1488        measure_padding: Option<FloatType>,
1489    ) -> Result<()> {
1490        let beam_number = depth as u32 + 1;
1491        let carries = |beams: Option<&Beams>| {
1492            beams.is_some_and(|beams| {
1493                beams
1494                    .numbers()
1495                    .into_iter()
1496                    .flatten()
1497                    .any(|n| n == beam_number)
1498            })
1499        };
1500        if !carries(beamed[index].as_ref()) {
1501            return Ok(());
1502        }
1503
1504        let note = notes[index];
1505        let start = note.offset + measure_start_offset;
1506        let end = start + note.quarter_length;
1507        let start_next = end;
1508
1509        let is_first = index == 0;
1510        let is_last = index + 1 == notes.len();
1511
1512        // Everything the neighbours are asked, read before this one is
1513        // written to: music21 reads them off a list it is editing.
1514        let previous_is_none = is_first || beamed[index - 1].is_none();
1515        let next_is_none = is_last || beamed[index + 1].is_none();
1516        let previous_carries = !is_first && carries(beamed[index - 1].as_ref());
1517        let next_carries = !is_last && carries(beamed[index + 1].as_ref());
1518        let previous_broke = !is_first
1519            && beamed[index - 1].as_ref().is_some_and(|beams| {
1520                beams.by_number(beam_number).is_some_and(|beam| {
1521                    matches!(beam.beam_type(), Some(BeamType::Stop))
1522                        || (matches!(beam.beam_type(), Some(BeamType::PartialBeam))
1523                            && beam.direction() == Some(crate::notation::BeamDirection::Left))
1524                })
1525            });
1526
1527        let archetype = self.beam_sequence.level(depth, true)?;
1528        let (span_start, span_end) = archetype.offset_to_span(start, false)?;
1529        let span_next_start = if next_is_none {
1530            0.0
1531        } else {
1532            archetype.offset_to_span(start_next, false)?.0
1533        };
1534
1535        let same = |a: FloatType, b: FloatType| (a - b).abs() < OFFSET_TOLERANCE;
1536
1537        // A note that fills its span exactly is not beamed at that level.
1538        if same(end, span_end)
1539            && (same(start, span_start) || (previous_is_none && beam_number == 1))
1540        {
1541            beamed[index] = None;
1542            return Ok(());
1543        }
1544
1545        let ends_the_measure = is_last && measure_padding.is_none_or(|padding| padding == 0.0);
1546
1547        let (beam_type, direction) = if is_first && measure_start_offset == 0.0 {
1548            if next_is_none || !next_carries {
1549                (
1550                    BeamType::PartialBeam,
1551                    Some(crate::notation::BeamDirection::Right),
1552                )
1553            } else {
1554                (BeamType::Start, None)
1555            }
1556        } else if ends_the_measure {
1557            if previous_is_none || !previous_carries {
1558                (
1559                    BeamType::PartialBeam,
1560                    Some(crate::notation::BeamDirection::Left),
1561                )
1562            } else {
1563                (BeamType::Stop, None)
1564            }
1565        } else if previous_is_none || !previous_carries {
1566            // Neither the first nor the last, and nothing to beam back to.
1567            if beam_number == 1 && next_is_none {
1568                beamed[index] = None;
1569                return Ok(());
1570            } else if (next_is_none && beam_number > 1) || start_next >= span_end - OFFSET_TOLERANCE
1571            {
1572                // music21 writes these as two branches. They answer alike,
1573                // and the second subsumes the first: with nothing after it,
1574                // a note runs to the end of its span or past it.
1575                (
1576                    BeamType::PartialBeam,
1577                    Some(crate::notation::BeamDirection::Left),
1578                )
1579            } else if next_is_none || !next_carries {
1580                (
1581                    BeamType::PartialBeam,
1582                    Some(crate::notation::BeamDirection::Right),
1583                )
1584            } else {
1585                (BeamType::Start, None)
1586            }
1587        } else if previous_broke {
1588            if next_is_none {
1589                (
1590                    BeamType::PartialBeam,
1591                    Some(crate::notation::BeamDirection::Left),
1592                )
1593            } else if next_carries {
1594                (BeamType::Start, None)
1595            } else {
1596                (
1597                    BeamType::PartialBeam,
1598                    Some(crate::notation::BeamDirection::Right),
1599                )
1600            }
1601        } else if next_is_none || !next_carries {
1602            (BeamType::Stop, None)
1603        } else if start_next < span_end - OFFSET_TOLERANCE {
1604            (BeamType::Continue, None)
1605        } else if start_next >= span_next_start - OFFSET_TOLERANCE {
1606            (BeamType::Stop, None)
1607        } else {
1608            return Err(Error::Meter("cannot match beamType".to_string()));
1609        };
1610
1611        if let Some(beams) = beamed[index].as_mut() {
1612            beams.set_by_number(beam_number, beam_type, direction)?;
1613        }
1614        Ok(())
1615    }
1616}
1617
1618/// A whole bar as a sequence of one part, which is what music21 starts each
1619/// of a meter's four sequences as: `6/8` undivided is `{6/8}`, not a bare
1620/// span, so a sequence nobody has divided still has one part.
1621fn whole_bar(
1622    numerator: UnsignedIntegerType,
1623    denominator: UnsignedIntegerType,
1624) -> Result<MeterTerminal> {
1625    let whole = format!("{numerator}/{denominator}");
1626    MeterTerminal::new(numerator, denominator)?.partitioned_by_parts(&[whole.as_str()])
1627}
1628
1629/// The word music21 allows beside a ratio, saying how the bar is counted:
1630/// `"slow 6/8"` is counted in six and `"fast 6/8"` in two. music21 looks for
1631/// it anywhere in the string and in any case, so `"6/8 Fast"` says it too.
1632fn division_word(ratio: &str) -> Option<&'static str> {
1633    let lower = ratio.to_ascii_lowercase();
1634    if lower.contains("slow") {
1635        Some("slow")
1636    } else if lower.contains("fast") {
1637        Some("fast")
1638    } else {
1639        None
1640    }
1641}
1642
1643/// The ratio with the word saying how it is counted taken out.
1644fn without_division_word(ratio: &str) -> String {
1645    let mut out = ratio.to_string();
1646    for word in ["slow", "fast"] {
1647        while let Some(at) = out.to_ascii_lowercase().find(word) {
1648            out.replace_range(at..at + word.len(), " ");
1649        }
1650    }
1651    out
1652}
1653
1654/// Whether a bar is felt in compound beats: music21's `favorCompound`.
1655///
1656/// The word written before the ratio decides it where there is one. Where
1657/// there is not, a bare three written in quarters or longer is felt slow,
1658/// which is what counts `3/4` in three while `3/8` is counted in one.
1659fn favor_compound(
1660    numerator: UnsignedIntegerType,
1661    denominator: UnsignedIntegerType,
1662    word: Option<&str>,
1663) -> bool {
1664    match word {
1665        Some("slow") => false,
1666        Some("fast") => true,
1667        _ => !(numerator == 3 && denominator < 8),
1668    }
1669}
1670
1671/// The time signature that fits what a measure holds: music21's
1672/// `bestTimeSignature`.
1673///
1674/// The shortest note value in the measure that is not a tuplet is the
1675/// denominator, halved until it divides the measure's length evenly, and the
1676/// count of it in the measure is the numerator, reduced to lowest terms with
1677/// the whole and half taken up to quarters. A measure that reads as `3/4` is
1678/// `6/8` instead when that weighs its notes at least as strongly, and one
1679/// that reads as `6/4` is whichever of `6/4`, `12/8` and `3/2` weighs them
1680/// most. A measure whose length is no binary fraction — tuplets — takes the
1681/// fraction itself.
1682pub fn best_time_signature(measure: &crate::Stream) -> Result<TimeSignature> {
1683    let elements = measure.recurse();
1684    let sum = elements
1685        .iter()
1686        .filter(|(_, element)| element.as_stream().is_none())
1687        .map(|(offset, element)| offset + element.quarter_length())
1688        .fold(0.0, FloatType::max);
1689
1690    // The shortest sounding value that is not a tuplet, with its dots.
1691    let mut min_dur = 4.0;
1692    let mut min_dots = 0;
1693    for (_, element) in &elements {
1694        let sounds =
1695            element.is_note_or_chord() || matches!(element, crate::stream::StreamElement::Rest(_));
1696        let quarter_length = element.quarter_length();
1697        if sounds && quarter_length != 0.0 && quarter_length < min_dur && is_binary(quarter_length)
1698        {
1699            min_dur = quarter_length;
1700            min_dots = element.duration().map_or(0, Duration::dots);
1701        }
1702    }
1703
1704    let (numerator, denominator) = if is_binary(sum) {
1705        binary_signature(sum, min_dur, min_dots)?
1706    } else {
1707        let (numerator, denominator) = crate::duration::limited_fraction(sum, 65535)
1708            .ok_or_else(|| Error::Meter("Cannot find a good match for this measure".to_string()))?;
1709        (
1710            numerator as UnsignedIntegerType,
1711            denominator as UnsignedIntegerType,
1712        )
1713    };
1714    let (numerator, denominator) = simplified_signature(numerator, denominator)
1715        .ok_or_else(|| Error::Meter("Cannot find a good match for this measure".to_string()))?;
1716
1717    let strength =
1718        |ratio: (UnsignedIntegerType, UnsignedIntegerType)| -> Result<(TimeSignature, FloatType)> {
1719            let signature = TimeSignature::new(ratio.0, ratio.1)?;
1720            let strength = signature.average_beat_strength(measure, true);
1721            Ok((signature, strength))
1722        };
1723    match (numerator, denominator) {
1724        // Three-four or six-eight, whichever weighs the notes more strongly.
1725        (3, 4) => {
1726            let (three_four, simple) = strength((3, 4))?;
1727            let (six_eight, compound) = strength((6, 8))?;
1728            Ok(if simple <= compound {
1729                six_eight
1730            } else {
1731                three_four
1732            })
1733        }
1734        // Six-four, twelve-eight or three-two, the same way.
1735        (6, 4) => {
1736            let (six_four, first) = strength((6, 4))?;
1737            let (twelve_eight, second) = strength((12, 8))?;
1738            let (three_two, third) = strength((3, 2))?;
1739            let most = first.max(second).max(third);
1740            Ok(if most == first {
1741                six_four
1742            } else if most == third {
1743                three_two
1744            } else {
1745                twelve_eight
1746            })
1747        }
1748        _ => TimeSignature::new(numerator, denominator),
1749    }
1750}
1751
1752/// The numerator and denominator of a measure whose length is a binary
1753/// fraction: the shortest value halved, dot and all, until it divides the
1754/// length evenly, named as a note value for the denominator and counted for
1755/// the numerator, in lowest terms.
1756fn binary_signature(
1757    sum: FloatType,
1758    min_dur: FloatType,
1759    min_dots: u32,
1760) -> Result<(UnsignedIntegerType, UnsignedIntegerType)> {
1761    let no_match = || Error::Meter("Cannot find a good match for this measure".to_string());
1762    let smallest_type = crate::duration::DurationType::from_music21_name("128th")
1763        .expect("music21 names the 128th note");
1764    let limit = smallest_type.quarter_length();
1765    let dot_multiplier =
1766        FloatType::from(2u32.pow(min_dots + 1) - 1) / FloatType::from(2u32.pow(min_dots));
1767
1768    let mut min_test = min_dur;
1769    let mut remaining = 10;
1770    while remaining > 0 {
1771        let parts = sum / min_test;
1772        if parts.floor() == parts || min_test <= limit {
1773            break;
1774        }
1775        min_test /= 2.0 * dot_multiplier;
1776        remaining -= 1;
1777    }
1778    let mut remaining = 10;
1779    while remaining > 0 {
1780        if min_test < limit {
1781            min_test = limit;
1782            break;
1783        }
1784        let (duration_type, matched) =
1785            crate::duration::quarter_length_to_closest_type(min_test).map_err(|_| no_match())?;
1786        if matched || duration_type == smallest_type {
1787            break;
1788        }
1789        min_test /= 2.0 * dot_multiplier;
1790        remaining -= 1;
1791    }
1792    let (duration_type, matched) =
1793        crate::duration::quarter_length_to_closest_type(min_test).map_err(|_| no_match())?;
1794    if !matched {
1795        return Err(Error::Meter(format!(
1796            "cannot find a type for denominator {min_test}"
1797        )));
1798    }
1799    let mut float_denominator = duration_type.type_number().unwrap_or(1.0);
1800    let mut multiplier = 1.0;
1801    let mut numerator_float = 0.0;
1802    while remaining > 0 {
1803        numerator_float = multiplier * sum / min_test;
1804        if numerator_float == numerator_float.floor() {
1805            break;
1806        }
1807        multiplier *= 2.0;
1808        remaining -= 1;
1809    }
1810    float_denominator *= multiplier;
1811    let numerator = numerator_float as UnsignedIntegerType;
1812    let denominator = float_denominator as UnsignedIntegerType;
1813    let divisor = num::integer::gcd(numerator, denominator).max(1);
1814    Ok((numerator / divisor, denominator / divisor))
1815}
1816
1817/// The rare signatures written the usual way: sixteen-sixteen and one-one
1818/// are four-four, and a whole or half denominator is written in quarters.
1819/// Nothing when the quarters are too many to count.
1820fn simplified_signature(
1821    numerator: UnsignedIntegerType,
1822    denominator: UnsignedIntegerType,
1823) -> Option<(UnsignedIntegerType, UnsignedIntegerType)> {
1824    if numerator == denominator && !matches!(numerator, 2 | 4) {
1825        Some((4, 4))
1826    } else if numerator != denominator && denominator == 1 {
1827        Some((numerator.checked_mul(4)?, 4))
1828    } else if numerator != denominator && denominator == 2 {
1829        Some((numerator.checked_mul(2)?, 4))
1830    } else {
1831        Some((numerator, denominator))
1832    }
1833}
1834
1835/// Whether a quarter length is a binary fraction music21 keeps as a float
1836/// rather than turning into a `Fraction`: one whose exact denominator is a
1837/// power of two no larger than its `DENOM_LIMIT`.
1838fn is_binary(quarter_length: FloatType) -> bool {
1839    (quarter_length * 32768.0).fract() == 0.0
1840}
1841
1842/// A span of `count` units of `1/unit`, divided into `parts` equal spans, as
1843/// a count of a unit: `6/8` in two is `3/8`, and `1/4` in two is `1/8`.
1844/// Nothing when the unit is too short to count.
1845fn split_span(
1846    count: UnsignedIntegerType,
1847    unit: UnsignedIntegerType,
1848    parts: UnsignedIntegerType,
1849) -> Option<(UnsignedIntegerType, UnsignedIntegerType)> {
1850    if count.is_multiple_of(parts) {
1851        Some((count / parts, unit))
1852    } else {
1853        Some((count, unit.checked_mul(parts)?))
1854    }
1855}
1856
1857/// How music21 divides a span by default when nothing says otherwise: its
1858/// `MeterSequence.subdivide` with no count given, which takes the first of
1859/// the span's division options.
1860fn default_division(count: UnsignedIntegerType, unit: UnsignedIntegerType) -> UnsignedIntegerType {
1861    let _ = unit;
1862    if count > 3 && count.is_multiple_of(3) {
1863        count / 3
1864    } else if count == 1 || count.is_multiple_of(2) {
1865        2
1866    } else {
1867        count
1868    }
1869}
1870
1871/// An offset written the way music21 writes one in a message: a whole number
1872/// as `3.0`, anything else as it is.
1873pub(crate) fn offset_repr(offset: FloatType) -> String {
1874    if offset.fract() == 0.0 {
1875        format!("{offset:.1}")
1876    } else {
1877        offset.to_string()
1878    }
1879}
1880
1881/// The offset back when it lies within `0..length`, or music21's error for
1882/// one that does not.
1883fn offset_within(offset: FloatType, length: FloatType) -> Result<FloatType> {
1884    if offset.is_nan() || offset < 0.0 || offset >= length {
1885        return Err(Error::Meter(format!(
1886            "cannot access from qLenPos {} where total duration is {}",
1887            offset_repr(offset),
1888            offset_repr(length)
1889        )));
1890    }
1891    Ok(offset)
1892}
1893
1894#[cfg(test)]
1895mod tests {
1896
1897    #[test]
1898    fn a_meter_counting_more_beats_than_the_limit_is_refused() {
1899        use super::{MAX_NUMERATOR, TimeSignature};
1900
1901        assert!(TimeSignature::new(MAX_NUMERATOR, 4).is_ok());
1902        assert!(TimeSignature::new(MAX_NUMERATOR + 1, 4).is_err());
1903        assert!(TimeSignature::from_ratio_string("99999999/1").is_err());
1904        assert!(TimeSignature::from_ratio_string("6000/4+6000/4").is_err());
1905        assert!(TimeSignature::from_ratio_string("4000000000/4+4000000000/4").is_err());
1906        assert!(TimeSignature::from_ratio_string("4000000000/4+1/8").is_err());
1907    }
1908
1909    #[test]
1910    fn a_meter_with_a_part_over_nought_is_refused() {
1911        use super::TimeSignature;
1912
1913        assert!(TimeSignature::from_ratio_string("3/8+2/0").is_err());
1914        assert!(TimeSignature::from_ratio_string("3/0+2/8").is_err());
1915    }
1916
1917    #[test]
1918    fn a_meter_of_the_shortest_units_is_one_accent() {
1919        use super::TimeSignature;
1920
1921        let signature = TimeSignature::new(1, 1 << 31).unwrap();
1922        assert_eq!(signature.accent_weights(), [1.0]);
1923    }
1924
1925    #[test]
1926    fn an_offset_past_the_bar_wraps_from_where_the_meter_stands() {
1927        // music21's own examples: a 3/4 bar and a 5/4 stream, the meter at 0.
1928        let three = TimeSignature::from_ratio_string("3/4").unwrap();
1929        assert_eq!(three.offset_in_bar(2.0, 0.0), 2.0);
1930        assert_eq!(three.offset_in_bar(4.0, 0.0), 1.0);
1931        let five = TimeSignature::from_ratio_string("5/4").unwrap();
1932        assert_eq!(five.offset_in_bar(3.0, 0.0), 3.0);
1933        assert_eq!(five.offset_in_bar(5.0, 0.0), 0.0);
1934
1935        // A meter a beat into the bar: the sum decides, the difference wraps.
1936        assert_eq!(three.offset_in_bar(1.5, 1.0), 1.5);
1937        assert_eq!(three.offset_in_bar(2.5, 1.0), 1.5);
1938    }
1939
1940    #[test]
1941    fn beat_divisions_are_read_off_the_beats_as_music21_reads_them() {
1942        // music21 asks only that the divisions agree: every beat of 2+3/8
1943        // divides into eighths, though the beats themselves differ.
1944        let cases: [(&str, &[FloatType], &[FloatType]); 9] = [
1945            ("2+3/8", &[0.5, 0.5], &[0.25; 4]),
1946            ("3+3+2/8", &[0.5; 3], &[0.25; 6]),
1947            ("5/8", &[0.25, 0.25], &[0.125; 4]),
1948            ("7/8", &[0.25, 0.25], &[0.125; 4]),
1949            ("4/4", &[0.5, 0.5], &[0.25; 4]),
1950            ("6/8", &[0.5; 3], &[0.25; 6]),
1951            ("5/4", &[0.5, 0.5], &[0.25; 4]),
1952            ("9/8", &[0.5; 3], &[0.25; 6]),
1953            ("3/2", &[1.0, 1.0], &[0.5; 4]),
1954        ];
1955        for (ratio, divisions, subdivisions) in cases {
1956            let meter = TimeSignature::from_ratio_string(ratio).unwrap();
1957            let lengths = |durations: Vec<Duration>| -> Vec<FloatType> {
1958                durations.iter().map(Duration::quarter_length).collect()
1959            };
1960            assert_eq!(
1961                lengths(meter.beat_division_durations().unwrap()),
1962                divisions,
1963                "{ratio}"
1964            );
1965            assert_eq!(
1966                lengths(meter.beat_sub_division_durations().unwrap()),
1967                subdivisions,
1968                "{ratio}"
1969            );
1970        }
1971
1972        // Divisions that differ are refused, as music21 refuses them.
1973        for ratio in ["3/4+3/8", "2/4+3/8", "1/4+1/8"] {
1974            let meter = TimeSignature::from_ratio_string(ratio).unwrap();
1975            assert!(meter.beat_division_durations().is_err(), "{ratio}");
1976        }
1977    }
1978    /// music21 writes a word before the ratio to say how the beat is felt,
1979    /// and writes an additive meter as parts that add up. Both were read as
1980    /// nonsense here, which is ten of music21's own meter examples.
1981    #[test]
1982    fn a_meter_is_read_as_music21_writes_it() {
1983        use crate::meter::TimeSignature;
1984
1985        // The word before the ratio is not decoration: music21 counts a
1986        // `slow 6/8` in six and a plain one in two, so the two are different
1987        // meters that happen to be written over the same numbers.
1988        let plain = TimeSignature::from_ratio_string("6/8").unwrap();
1989        let slow = TimeSignature::from_ratio_string("slow 6/8").unwrap();
1990        assert_eq!(TimeSignature::from_ratio_string("fast 6/8").unwrap(), plain);
1991        assert_ne!(slow, plain);
1992        assert_eq!(
1993            (slow.numerator(), slow.denominator()),
1994            (plain.numerator(), plain.denominator())
1995        );
1996        assert_eq!(plain.beat_sequence().len(), 2);
1997        assert_eq!(slow.beat_sequence().len(), 6);
1998
1999        let additive = TimeSignature::from_ratio_string("3/8+2/8").unwrap();
2000        assert_eq!((additive.numerator(), additive.denominator()), (5, 8));
2001        assert_eq!(
2002            TimeSignature::parts("3/8+2/8").unwrap(),
2003            vec![(3, 8), (2, 8)]
2004        );
2005        // A numerator with no denominator of its own takes the next one.
2006        assert_eq!(TimeSignature::parts("3+2/8").unwrap(), vec![(3, 8), (2, 8)]);
2007        assert_eq!(
2008            TimeSignature::parts("3+2+5/8+3/4").unwrap(),
2009            vec![(3, 8), (2, 8), (5, 8), (3, 4)]
2010        );
2011        // Parts in different notes come to what they add up to.
2012        let mixed = TimeSignature::from_ratio_string("3/8+1/4").unwrap();
2013        assert_eq!((mixed.numerator(), mixed.denominator()), (5, 8));
2014
2015        assert!(TimeSignature::parts("3+2+5").is_err());
2016        assert!(TimeSignature::from_ratio_string("").is_err());
2017        assert!(TimeSignature::from_ratio_string("3.0/4.0").is_err());
2018    }
2019
2020    #[test]
2021    fn a_summed_numerator_is_beamed_as_it_was_written() {
2022        use crate::meter::TimeSignature;
2023
2024        // Read off music21 11.0.0b9: `summedNumerator` and the parts of
2025        // `beamSequence`. A bar written part by part is beamed by the rule
2026        // for its numerator where there is one, and as written where there
2027        // is not; one written with its numerators summed is left alone.
2028        let expected = [
2029            ("3+2/8", true, "{3/8+2/8}"),
2030            ("3/8+2/8", false, "{2/8+3/8}"),
2031            ("2+3/8", true, "{2/8+3/8}"),
2032            ("3+2+2/8", true, "{3/8+2/8+2/8}"),
2033            ("3/8+2/8+2/8", false, "{2/8+2/8+3/8}"),
2034            ("2+2+3/16", true, "{2/16+2/16+3/16}"),
2035            ("3/16+2/16", false, "{3/16+2/16}"),
2036            ("6/8", false, "{3/8+3/8}"),
2037        ];
2038        for (written, summed, beams) in expected {
2039            let signature = TimeSignature::from_ratio_string(written).unwrap();
2040            assert_eq!(signature.summed_numerator(), summed, "{written}");
2041            assert_eq!(signature.beam_sequence().to_string(), beams, "{written}");
2042        }
2043
2044        let mut signature = TimeSignature::from_ratio_string("3/8+2/8").unwrap();
2045        signature.set_summed_numerator(true);
2046        assert!(signature.summed_numerator());
2047        assert!(signature.display_sequence().summed_numerator());
2048    }
2049
2050    #[test]
2051    fn the_sequences_are_partitioned_as_music21_partitions_them() {
2052        use crate::meter::TimeSignature;
2053
2054        // Read off music21 11.0.0b9 directly: `str(TimeSignature(r).beatSequence)`
2055        // and `.beamSequence` for each meter below.
2056        let expected = [
2057            ("1/4", "{1/4}", "{1/4}"),
2058            ("2/4", "{{1/8+1/8}+{1/8+1/8}}", "{{1/8+1/8}+{1/8+1/8}}"),
2059            (
2060                "3/4",
2061                "{{1/8+1/8}+{1/8+1/8}+{1/8+1/8}}",
2062                "{{1/8+1/8}+{1/8+1/8}+{1/8+1/8}}",
2063            ),
2064            (
2065                "4/4",
2066                "{{1/8+1/8}+{1/8+1/8}+{1/8+1/8}+{1/8+1/8}}",
2067                "{{1/8+1/8}+{1/8+1/8}+{1/8+1/8}+{1/8+1/8}}",
2068            ),
2069            (
2070                "5/4",
2071                "{{1/8+1/8}+{1/8+1/8}+{1/8+1/8}+{1/8+1/8}+{1/8+1/8}}",
2072                "{{1/4+1/4}+{1/4+1/4+1/4}}",
2073            ),
2074            ("6/4", "{{1/4+1/4+1/4}+{1/4+1/4+1/4}}", "{3/4+3/4}"),
2075            ("2/2", "{{1/4+1/4}+{1/4+1/4}}", "{1/2+1/2}"),
2076            ("3/2", "{{1/4+1/4}+{1/4+1/4}+{1/4+1/4}}", "{1/2+1/2+1/2}"),
2077            ("3/8", "{3/8}", "{3/8}"),
2078            (
2079                "5/8",
2080                "{{1/16+1/16}+{1/16+1/16}+{1/16+1/16}+{1/16+1/16}+{1/16+1/16}}",
2081                "{2/8+3/8}",
2082            ),
2083            ("6/8", "{{1/8+1/8+1/8}+{1/8+1/8+1/8}}", "{3/8+3/8}"),
2084            (
2085                "9/8",
2086                "{{1/8+1/8+1/8}+{1/8+1/8+1/8}+{1/8+1/8+1/8}}",
2087                "{3/8+3/8+3/8}",
2088            ),
2089            (
2090                "12/8",
2091                "{{1/8+1/8+1/8}+{1/8+1/8+1/8}+{1/8+1/8+1/8}+{1/8+1/8+1/8}}",
2092                "{3/8+3/8+3/8+3/8}",
2093            ),
2094            (
2095                "5/16",
2096                "{{1/32+1/32}+{1/32+1/32}+{1/32+1/32}+{1/32+1/32}+{1/32+1/32}}",
2097                "{5/16}",
2098            ),
2099            (
2100                "slow 6/8",
2101                "{{1/16+1/16}+{1/16+1/16}+{1/16+1/16}+{1/16+1/16}+{1/16+1/16}+{1/16+1/16}}",
2102                "{3/8+3/8}",
2103            ),
2104            ("fast 6/8", "{{1/8+1/8+1/8}+{1/8+1/8+1/8}}", "{3/8+3/8}"),
2105            ("6/8 fast", "{{1/8+1/8+1/8}+{1/8+1/8+1/8}}", "{3/8+3/8}"),
2106            (
2107                "6/8 Slow",
2108                "{{1/16+1/16}+{1/16+1/16}+{1/16+1/16}+{1/16+1/16}+{1/16+1/16}+{1/16+1/16}}",
2109                "{3/8+3/8}",
2110            ),
2111            ("3/8+2/8", "{{1/8+1/8+1/8}+{1/8+1/8}}", "{2/8+3/8}"),
2112            ("2/4+3/8", "{{1/4+1/4}+{1/8+1/8+1/8}}", "{2/8+2/8+3/8}"),
2113        ];
2114        for (ratio, beats, beams) in expected {
2115            let signature = TimeSignature::from_ratio_string(ratio).unwrap();
2116            assert_eq!(
2117                signature.beat_sequence().to_string(),
2118                beats,
2119                "beats of {ratio}"
2120            );
2121            assert_eq!(
2122                signature.beam_sequence().to_string(),
2123                beams,
2124                "beams of {ratio}"
2125            );
2126        }
2127    }
2128
2129    /// Read off music21's default `accentSequence` and `getBeatDepth`.
2130    #[test]
2131    fn accent_weights_and_beat_depths_follow_the_default_hierarchy() {
2132        let weights = |ratio: &str| {
2133            TimeSignature::from_ratio_string(ratio)
2134                .unwrap()
2135                .accent_weights()
2136        };
2137        assert_eq!(
2138            weights("4/4"),
2139            [1.0, 0.125, 0.25, 0.125, 0.5, 0.125, 0.25, 0.125]
2140        );
2141        assert_eq!(
2142            weights("6/8"),
2143            [
2144                1.0, 0.125, 0.25, 0.125, 0.25, 0.125, 0.5, 0.125, 0.25, 0.125, 0.25, 0.125
2145            ]
2146        );
2147        assert_eq!(
2148            weights("12/8"),
2149            [
2150                1.0, 0.125, 0.125, 0.25, 0.125, 0.125, 0.5, 0.125, 0.125, 0.25, 0.125, 0.125
2151            ]
2152        );
2153        assert_eq!(weights("3/4").len(), 12);
2154        assert_eq!(weights("24/8").len(), 24);
2155        assert_eq!(
2156            TimeSignature::new(1, 4)
2157                .unwrap()
2158                .accent_partition_quarter_length(),
2159            0.125
2160        );
2161
2162        let three_four = TimeSignature::new(3, 4).unwrap();
2163        let read: Vec<FloatType> = (0..3)
2164            .map(|beat| three_four.accent_weight(FloatType::from(beat)).unwrap())
2165            .collect();
2166        assert_eq!(read, [1.0, 0.5, 0.5]);
2167        let beyond = three_four.accent_weight(3.0).unwrap_err().to_string();
2168        assert!(beyond.ends_with("cannot access from qLenPos 3.0 where total duration is 3.0"));
2169        // A bar whose parts would be longer than a whole note, or shorter
2170        // than a 128th, is one partition.
2171        assert_eq!(weights("16/1"), [1.0]);
2172        assert_eq!(weights("1/32"), [1.0]);
2173        assert_eq!(
2174            TimeSignature::new(24, 4)
2175                .unwrap()
2176                .accent_partition_quarter_length(),
2177            1.0
2178        );
2179        assert_eq!(
2180            three_four.accent_weight_with(4.0, false, true).unwrap(),
2181            0.5
2182        );
2183        assert_eq!(
2184            three_four.accent_weight_with(0.1, true, false).unwrap(),
2185            0.0625
2186        );
2187        assert_eq!(
2188            three_four.accent_weight_with(0.1, false, false).unwrap(),
2189            1.0
2190        );
2191        assert!(three_four.accent(2.0));
2192        assert!(!three_four.accent(0.1));
2193        assert!(!three_four.accent(3.0));
2194
2195        assert_eq!(three_four.beat_depth(0.0).unwrap(), 2);
2196        assert_eq!(three_four.beat_depth(0.25).unwrap(), 2);
2197        assert_eq!(three_four.beat_depth(0.5).unwrap(), 1);
2198        assert_eq!(three_four.beat_depth(1.0).unwrap(), 2);
2199        assert!(three_four.beat_depth(3.0).is_err());
2200        assert_eq!(
2201            TimeSignature::new(3, 8).unwrap().beat_depth(0.5).unwrap(),
2202            1
2203        );
2204        assert_eq!(
2205            TimeSignature::new(6, 8).unwrap().beat_depth(1.0).unwrap(),
2206            1
2207        );
2208        assert_eq!(
2209            TimeSignature::new(6, 8).unwrap().beat_depth(1.5).unwrap(),
2210            2
2211        );
2212    }
2213
2214    /// music21's own `bestTimeSignature` examples.
2215    #[test]
2216    fn the_best_time_signature_fits_what_the_measure_holds() {
2217        use crate::{Note, Pitch, Stream};
2218
2219        let measure = |lengths: &[FloatType]| {
2220            let mut stream = Stream::new();
2221            for length in lengths {
2222                let mut note = Note::from_pitch(Pitch::from_name("C4").unwrap());
2223                note.set_duration(Duration::new(*length).unwrap());
2224                stream.push(note);
2225            }
2226            stream
2227        };
2228        let best = |lengths: &[FloatType]| {
2229            best_time_signature(&measure(lengths))
2230                .unwrap()
2231                .ratio_string()
2232        };
2233        assert_eq!(best(&[1.0, 1.0, 0.5, 0.5]), "3/4");
2234        assert_eq!(best(&[0.75, 0.25, 0.5, 0.75, 0.25, 0.5]), "6/8");
2235        assert_eq!(best(&[2.0, 2.0, 2.0]), "3/2");
2236        assert_eq!(best(&[0.75, 0.25, 0.5, 0.75, 0.25, 0.5, 1.5, 1.5]), "12/8");
2237        assert_eq!(best(&[1.0, 2.0, 1.0, 2.0]), "6/4");
2238        assert_eq!(best(&[1.0, 0.375]), "11/32");
2239        assert_eq!(best(&[3.5, 5.5]), "9/4");
2240        assert_eq!(best(&[1.0, 1.0, 1.0, 1.0]), "4/4");
2241        assert_eq!(best(&[4.0]), "4/4");
2242        // Tuplets are passed over when the shortest value is looked for.
2243        assert_eq!(best(&[1.0 / 3.0, 1.0 / 3.0, 1.0 / 3.0, 1.0]), "2/4");
2244    }
2245
2246    #[test]
2247    fn a_measure_too_long_for_any_signature_has_none() {
2248        use crate::{Note, Pitch, Stream};
2249
2250        let mut note = Note::from_pitch(Pitch::from_name("C4").unwrap());
2251        note.set_duration(Duration::new(4_294_967_296.0).unwrap());
2252        let mut measure = Stream::new();
2253        measure.push(note);
2254        assert!(best_time_signature(&measure).is_err());
2255    }
2256
2257    /// music21's own `averageBeatStrength` example: `C4 D4 E8 F8` under
2258    /// six-eight and three-four.
2259    #[test]
2260    fn beat_strength_is_averaged_over_a_stream() {
2261        use crate::{Note, Pitch, Stream};
2262
2263        let mut stream = Stream::new();
2264        for (name, length) in [("C4", 1.0), ("D4", 1.0), ("E4", 0.5), ("F4", 0.5)] {
2265            let mut note = Note::from_pitch(Pitch::from_name(name).unwrap());
2266            note.set_duration(Duration::new(length).unwrap());
2267            stream.push(note);
2268        }
2269        assert_eq!(
2270            TimeSignature::new(6, 8)
2271                .unwrap()
2272                .average_beat_strength(&stream, true),
2273            0.4375
2274        );
2275        assert_eq!(
2276            TimeSignature::new(3, 4)
2277                .unwrap()
2278                .average_beat_strength(&stream, true),
2279            0.5625
2280        );
2281        stream.insert(0.0, TimeSignature::new(3, 4).unwrap());
2282        stream.insert(0.0, TimeSignature::new(6, 8).unwrap());
2283        assert_eq!(
2284            TimeSignature::new(6, 8)
2285                .unwrap()
2286                .average_beat_strength(&stream, false),
2287            0.625
2288        );
2289        assert_eq!(
2290            TimeSignature::new(4, 4)
2291                .unwrap()
2292                .average_beat_strength(&Stream::new(), true),
2293            0.0
2294        );
2295    }
2296
2297    /// music21 weighs a measure's own notes, so one whose notes all stand in
2298    /// a voice weighs nothing, and a half and a quarter there read as six-
2299    /// eight where the same two notes in the measure itself read as
2300    /// three-four.
2301    #[test]
2302    fn a_measure_weighs_its_own_notes_and_not_its_voices() {
2303        use crate::stream::StreamKind;
2304        use crate::{Note, Pitch, Stream};
2305
2306        let mut voice = Stream::with_kind(StreamKind::Voice);
2307        for (name, length) in [("C5", 2.0), ("B4", 1.0)] {
2308            let mut note = Note::from_pitch(Pitch::from_name(name).unwrap());
2309            note.set_duration(Duration::new(length).unwrap());
2310            voice.push(note);
2311        }
2312        let mut plain = voice.clone();
2313        plain.set_kind(StreamKind::Measure);
2314        let mut voiced = Stream::with_kind(StreamKind::Measure);
2315        voiced.insert(0.0, voice);
2316
2317        let three_four = TimeSignature::new(3, 4).unwrap();
2318        assert_eq!(three_four.average_beat_strength(&voiced, true), 0.0);
2319        assert_eq!(best_time_signature(&plain).unwrap().ratio_string(), "3/4");
2320        assert_eq!(best_time_signature(&voiced).unwrap().ratio_string(), "6/8");
2321    }
2322
2323    #[test]
2324    fn a_signature_reports_its_two_numbers_and_its_bar() {
2325        let six_eight = TimeSignature::new(6, 8).unwrap();
2326        assert_eq!((six_eight.numerator(), six_eight.denominator()), (6, 8));
2327        assert_eq!(six_eight.bar_duration().quarter_length(), 3.0);
2328    }
2329
2330    /// music21 reads the progress through `opFrac`, so a third of a beat
2331    /// is a sixth exactly, not the float the subtraction leaves.
2332    #[test]
2333    fn beat_progress_is_read_through_op_frac() {
2334        let six_eight = TimeSignature::new(6, 8).unwrap();
2335        let (beat, progress) = six_eight.beat_progress(5.0 / 3.0).unwrap();
2336        assert_eq!(beat, 2);
2337        assert_eq!(progress, crate::makenotation::op_frac(1.0 / 6.0));
2338    }
2339
2340    #[test]
2341    fn a_written_bar_length_stands_over_the_meters_own() {
2342        let mut three_eight = TimeSignature::new(3, 8).unwrap();
2343        three_eight.set_bar_duration(Some(Duration::new(1.75).unwrap()));
2344        assert_eq!(three_eight.bar_duration().quarter_length(), 1.75);
2345        // The meter itself is unchanged: only the bar it reports.
2346        assert_eq!(three_eight.bar_quarter_length(), 1.5);
2347
2348        three_eight.set_bar_duration(None);
2349        assert_eq!(three_eight.bar_duration().quarter_length(), 1.5);
2350    }
2351
2352    #[test]
2353    fn division_helpers_match_music21() {
2354        let quarter_lengths = |durations: Vec<Duration>| -> Vec<FloatType> {
2355            durations.into_iter().map(|d| d.quarter_length()).collect()
2356        };
2357        let cases: [(&str, FloatType, &str, &[FloatType], usize); 7] = [
2358            ("4/4", 1.0, "Simple", &[0.5, 0.5], 4),
2359            ("6/8", 0.5, "Compound", &[0.5, 0.5, 0.5], 6),
2360            ("2/2", 2.0, "Simple", &[1.0, 1.0], 4),
2361            ("3/8", 0.5, "Other", &[1.5], 2),
2362            ("7/8", 0.5, "Simple", &[0.25, 0.25], 4),
2363            ("12/16", 0.25, "Compound", &[0.25, 0.25, 0.25], 6),
2364            ("1/4", 1.0, "Other", &[1.0], 2),
2365        ];
2366        for (ratio, beat_to_quarter, division_name, divisions, sub_divisions) in cases {
2367            let ts = ts(ratio);
2368            assert_eq!(
2369                ts.beat_length_to_quarter_length_ratio(),
2370                beat_to_quarter,
2371                "{ratio}"
2372            );
2373            assert_eq!(
2374                ts.quarter_length_to_beat_length_ratio(),
2375                1.0 / beat_to_quarter,
2376                "{ratio}"
2377            );
2378            assert_eq!(ts.beat_division_count_name(), division_name, "{ratio}");
2379            assert_eq!(
2380                quarter_lengths(ts.beat_division_durations().unwrap()),
2381                divisions,
2382                "{ratio}"
2383            );
2384            let subs = quarter_lengths(ts.beat_sub_division_durations().unwrap());
2385            assert_eq!(subs.len(), sub_divisions, "{ratio}");
2386            assert!(subs.iter().all(|ql| *ql == divisions[0] / 2.0), "{ratio}");
2387        }
2388        assert!(ts("4/4").ratio_equal(&ts("4/4")));
2389        assert!(!ts("4/4").ratio_equal(&ts("2/2")));
2390    }
2391
2392    #[test]
2393    fn beat_positions_match_music21() {
2394        let common = ts("4/4");
2395        let cases: [(FloatType, UnsignedIntegerType, FloatType, FloatType, &str); 7] = [
2396            (0.0, 1, 0.0, 1.0, "1"),
2397            (0.5, 1, 0.5, 1.5, "1 1/2"),
2398            (1.25, 2, 0.25, 2.25, "2 1/4"),
2399            (2.75, 3, 0.75, 3.75, "3 3/4"),
2400            (3.0, 4, 0.0, 4.0, "4"),
2401            (3.75, 4, 0.75, 4.75, "4 3/4"),
2402            (3.9, 4, 0.9, 4.9, "4 9/10"),
2403        ];
2404        for (offset, beat, progress, proportion, text) in cases {
2405            let (actual_beat, actual_progress) = common.beat_progress(offset).unwrap();
2406            assert_eq!(actual_beat, beat, "{offset}");
2407            assert!((actual_progress - progress).abs() < 1e-9, "{offset}");
2408            assert!(
2409                (common.beat_proportion(offset).unwrap() - proportion).abs() < 1e-9,
2410                "{offset}"
2411            );
2412            assert_eq!(
2413                common.beat_proportion_string(offset).unwrap(),
2414                text,
2415                "{offset}"
2416            );
2417        }
2418
2419        let compound = ts("6/8");
2420        assert_eq!(compound.beat_proportion_string(0.5).unwrap(), "1 1/3");
2421        assert_eq!(compound.beat_proportion_string(1.0).unwrap(), "1 2/3");
2422        assert_eq!(compound.beat_proportion_string(2.5).unwrap(), "2 2/3");
2423        assert!((compound.beat_proportion(2.0).unwrap() - 7.0 / 3.0).abs() < 1e-9);
2424        assert_eq!(ts("3/8").beat_proportion_string(1.0).unwrap(), "1 2/3");
2425        assert!(common.beat_progress(4.0).is_err());
2426    }
2427
2428    #[test]
2429    fn offset_from_beat_matches_music21() {
2430        let common = ts("4/4");
2431        for (beat, offset) in [
2432            (1.0, 0.0),
2433            (1.5, 0.5),
2434            (2.5, 1.5),
2435            (3.25, 2.25),
2436            (4.75, 3.75),
2437        ] {
2438            assert_eq!(common.offset_from_beat(beat).unwrap(), offset, "{beat}");
2439        }
2440        assert!(common.offset_from_beat(5.0).is_err());
2441        assert!(common.offset_from_beat(0.5).is_err());
2442        let compound = ts("6/8");
2443        assert_eq!(compound.offset_from_beat(1.5).unwrap(), 0.75);
2444        assert_eq!(compound.offset_from_beat(2.5).unwrap(), 2.25);
2445        assert!((compound.offset_from_beat(2.999).unwrap() - 2.9985).abs() < 1e-9);
2446        assert_eq!(ts("3/8").offset_from_beat(1.5).unwrap(), 0.75);
2447    }
2448
2449    #[test]
2450    fn closest_fraction_limits_the_denominator_like_python() {
2451        assert_eq!(closest_fraction(0.5, 16), (1, 2));
2452        assert_eq!(closest_fraction(1.0 / 3.0, 16), (1, 3));
2453        assert_eq!(closest_fraction(0.9, 16), (9, 10));
2454        assert_eq!(closest_fraction(0.75, 16), (3, 4));
2455        assert_eq!(closest_fraction(0.1234, 16), (1, 8));
2456    }
2457    use super::*;
2458
2459    fn ts(ratio: &str) -> TimeSignature {
2460        TimeSignature::from_ratio_string(ratio).expect("valid time signature")
2461    }
2462
2463    #[test]
2464    fn common_and_cut_time_match_their_ratios() {
2465        assert_eq!(TimeSignature::common().ratio_string(), "4/4");
2466        assert_eq!(TimeSignature::cut().ratio_string(), "2/2");
2467        assert_eq!(TimeSignature::default(), TimeSignature::common());
2468    }
2469
2470    #[test]
2471    fn bar_and_beat_lengths_follow_the_ratio() {
2472        assert_eq!(ts("4/4").bar_quarter_length(), 4.0);
2473        assert_eq!(ts("5/16").bar_quarter_length(), 1.25);
2474        assert_eq!(ts("3/8").bar_quarter_length(), 1.5);
2475        assert_eq!(ts("6/8").beat_quarter_length(), 1.5);
2476        assert_eq!(ts("4/4").beat_quarter_length(), 1.0);
2477        assert_eq!(ts("2/2").beat_duration().quarter_length(), 2.0);
2478    }
2479
2480    #[test]
2481    fn compound_meters_beat_in_threes() {
2482        for (ratio, beats, division) in [
2483            ("6/8", 2, BeatDivision::Compound),
2484            ("9/8", 3, BeatDivision::Compound),
2485            ("12/8", 4, BeatDivision::Compound),
2486            ("15/8", 5, BeatDivision::Compound),
2487            ("18/8", 6, BeatDivision::Compound),
2488            ("24/8", 8, BeatDivision::Compound),
2489        ] {
2490            assert_eq!(ts(ratio).beat_count(), beats, "{ratio}");
2491            assert_eq!(ts(ratio).beat_division(), division, "{ratio}");
2492            assert!(ts(ratio).is_compound(), "{ratio}");
2493        }
2494    }
2495
2496    #[test]
2497    fn three_is_the_one_denominator_sensitive_numerator() {
2498        // 3/2 and 3/4 read as three beats; 3/8 and shorter read as one.
2499        assert_eq!(ts("3/2").beat_count(), 3);
2500        assert_eq!(ts("3/4").beat_count(), 3);
2501        assert_eq!(ts("3/8").beat_count(), 1);
2502        assert_eq!(ts("3/16").beat_count(), 1);
2503        assert_eq!(ts("3/32").beat_count(), 1);
2504        // The cut is at an eighth rather than at a power of two: music21
2505        // counts 3/3 and 3/6 in three, and 3/12 in one.
2506        assert_eq!(ts("3/3").beat_count(), 3);
2507        assert_eq!(ts("3/6").beat_count(), 3);
2508        assert_eq!(ts("3/12").beat_count(), 1);
2509        // Every other numerator ignores the denominator entirely.
2510        for denominator in [2, 4, 8, 16] {
2511            assert_eq!(TimeSignature::new(6, denominator).unwrap().beat_count(), 2);
2512            assert_eq!(TimeSignature::new(5, denominator).unwrap().beat_count(), 5);
2513        }
2514    }
2515
2516    #[test]
2517    fn a_bar_written_in_unequal_parts_is_counted_along_its_own_beats() {
2518        use crate::meter::TimeSignature;
2519
2520        // Read off music21 11.0.0b9. `2/4+3/8` is two beats, of two quarters
2521        // and of three eighths, so nothing here is the bar divided evenly.
2522        let mixed = TimeSignature::from_ratio_string("2/4+3/8").unwrap();
2523        assert_eq!(mixed.bar_quarter_length(), 3.5);
2524        assert_eq!(mixed.beat_count(), 2);
2525        assert_eq!(mixed.beat_offsets(), vec![0.0, 2.0]);
2526        assert_eq!(mixed.beat_at_offset(2.5).unwrap(), 2);
2527        assert_eq!(mixed.beat_duration_at(0.0).unwrap().quarter_length(), 2.0);
2528        assert_eq!(mixed.beat_duration_at(2.5).unwrap().quarter_length(), 1.5);
2529        assert_eq!(mixed.offset_from_beat(2.0).unwrap(), 2.0);
2530        // Half way through the first beat is half of *that* beat, not half of
2531        // an averaged one.
2532        assert_eq!(mixed.offset_from_beat(1.5).unwrap(), 1.0);
2533        assert_eq!(mixed.beat_proportion_string(2.5).unwrap(), "2 1/3");
2534        assert_eq!(mixed.beat_depth(0.0).unwrap(), 2);
2535
2536        let other = TimeSignature::from_ratio_string("3/8+2/8").unwrap();
2537        assert_eq!(other.beat_offsets(), vec![0.0, 1.5]);
2538        assert_eq!(other.offset_from_beat(2.0).unwrap(), 1.5);
2539        assert_eq!(other.offset_from_beat(1.5).unwrap(), 0.75);
2540        // The bar is 2.5 long, so 2.5 is past the end of it.
2541        assert!(other.beat_proportion_string(2.5).is_err());
2542
2543        // An evenly divided bar answers exactly as it did.
2544        let common = TimeSignature::common();
2545        assert_eq!(common.beat_offsets(), vec![0.0, 1.0, 2.0, 3.0]);
2546        assert_eq!(common.offset_from_beat(2.0).unwrap(), 1.0);
2547        assert_eq!(common.offset_from_beat(1.5).unwrap(), 0.5);
2548        assert_eq!(common.beat_proportion_string(2.5).unwrap(), "3 1/2");
2549    }
2550
2551    #[test]
2552    fn a_bar_whose_beats_differ_answers_its_first_beat_length() {
2553        use crate::meter::TimeSignature;
2554
2555        // music21 answers the first beat's length here and reports the
2556        // division as Other, counting one.
2557        let mixed = TimeSignature::from_ratio_string("2/4+3/8").unwrap();
2558        assert_eq!(mixed.beat_quarter_length(), 2.0);
2559        assert_eq!(mixed.beat_duration().quarter_length(), 2.0);
2560        assert!(mixed.beat_division_durations().is_err());
2561        assert_eq!(mixed.beat_division_count(), 1);
2562        assert_eq!(mixed.beat_division_count_name(), "Other");
2563        assert_eq!(mixed.classification(), "Other Duple");
2564
2565        let other = TimeSignature::from_ratio_string("3/8+2/8").unwrap();
2566        assert_eq!(other.beat_quarter_length(), 1.5);
2567        assert_eq!(other.beat_division_count(), 1);
2568        assert_eq!(other.classification(), "Other Duple");
2569
2570        // An evenly divided bar still answers, and answers as it did.
2571        assert_eq!(TimeSignature::common().beat_quarter_length(), 1.0);
2572        assert_eq!(
2573            TimeSignature::from_ratio_string("6/8")
2574                .unwrap()
2575                .beat_quarter_length(),
2576            1.5
2577        );
2578    }
2579
2580    #[test]
2581    fn weights_a_caller_sets_are_the_weights_read_back() {
2582        use crate::meter::TimeSignature;
2583
2584        let mut common = TimeSignature::common();
2585        let default = common.accent_weights();
2586        assert_eq!(default[0], 1.0);
2587
2588        // music21 loops a shorter list over the partitions.
2589        common.set_accent_weight(&[0.8, 0.2], 0).unwrap();
2590        let set = common.accent_weights();
2591        assert_eq!(set.len(), default.len());
2592        assert!((set[0] - 0.8).abs() < 1e-9);
2593        assert!((set[1] - 0.2).abs() < 1e-9);
2594        assert!((set[2] - 0.8).abs() < 1e-9);
2595
2596        // And the reading at an offset comes off the same sequence.
2597        assert!((common.accent_weight(0.0).unwrap() - 0.8).abs() < 1e-9);
2598
2599        // A fresh meter is untouched by that.
2600        assert_eq!(TimeSignature::common().accent_weights()[0], 1.0);
2601    }
2602
2603    #[test]
2604    fn a_bar_can_be_counted_in_a_different_number_of_beats() {
2605        use crate::meter::TimeSignature;
2606
2607        // Read off music21 11.0.0b9 by assigning to `beatCount`.
2608        for (ratio, count, partitioned) in [
2609            (
2610                "6/8",
2611                6,
2612                "{{1/16+1/16}+{1/16+1/16}+{1/16+1/16}+{1/16+1/16}+{1/16+1/16}+{1/16+1/16}}",
2613            ),
2614            ("6/8", 2, "{{1/8+1/8+1/8}+{1/8+1/8+1/8}}"),
2615            ("4/4", 2, "{{1/4+1/4}+{1/4+1/4}}"),
2616            ("3/4", 1, "{3/4}"),
2617            (
2618                "2/4",
2619                4,
2620                "{{1/16+1/16}+{1/16+1/16}+{1/16+1/16}+{1/16+1/16}}",
2621            ),
2622        ] {
2623            let mut signature = TimeSignature::from_ratio_string(ratio).unwrap();
2624            signature.set_beat_count(count).unwrap();
2625            assert_eq!(
2626                signature.beat_sequence().to_string(),
2627                partitioned,
2628                "{ratio} in {count}"
2629            );
2630            assert_eq!(signature.beat_count(), count, "{ratio} in {count}");
2631        }
2632    }
2633
2634    #[test]
2635    fn a_bar_can_be_written_a_different_way_than_it_is_counted() {
2636        use crate::meter::TimeSignature;
2637
2638        // music21's own `setDisplay` docstring: a 3/4 written in three
2639        // groups of two eighths.
2640        let mut signature = TimeSignature::from_ratio_string("3/4").unwrap();
2641        let counted = signature.beat_sequence().to_string();
2642        signature.set_display("2/8+2/8+2/8").unwrap();
2643        assert_eq!(signature.display_sequence().to_string(), "{2/8+2/8+2/8}");
2644        assert_eq!(
2645            signature.display_sequence().partition_display(),
2646            "2/8+2/8+2/8"
2647        );
2648        // What it counts is untouched; only how it is written changed.
2649        assert_eq!(signature.beat_sequence().to_string(), counted);
2650        assert_eq!(signature.beat_count(), 3);
2651        // music21 reads `ratioString` off the display sequence, so there it
2652        // becomes "2/8+2/8+2/8". The crate still writes it from the
2653        // numerator and the denominator; see issues.md.
2654
2655        // A bar cannot be written as a length it is not.
2656        assert!(signature.set_display("2/4").is_err());
2657
2658        // The sequences can be partitioned through.
2659        let mut common = TimeSignature::common();
2660        common.set_beat_sequence(
2661            common
2662                .beat_sequence()
2663                .partitioned_by_count(2, true)
2664                .unwrap(),
2665        );
2666        assert_eq!(common.beat_count(), 2);
2667    }
2668
2669    #[test]
2670    fn the_divisions_a_meter_is_built_with_partition_its_beats() {
2671        use crate::meter::TimeSignature;
2672
2673        // Read off music21 11.0.0b9: TimeSignature(ratio, divisions).
2674        for (ratio, divisions, partitioned) in [
2675            ("3/4", 1, "{3/4}"),
2676            ("6/8", 2, "{3/8+3/8}"),
2677            ("4/4", 2, "{1/2+1/2}"),
2678            ("3/4", 3, "{1/4+1/4+1/4}"),
2679        ] {
2680            let mut signature = TimeSignature::from_ratio_string(ratio).unwrap();
2681            signature.divide_beats(divisions).unwrap();
2682            assert_eq!(
2683                signature.beat_sequence().to_string(),
2684                partitioned,
2685                "{ratio} in {divisions}"
2686            );
2687        }
2688
2689        // Unlike counting the bar, which divides each beat again.
2690        let mut counted = TimeSignature::from_ratio_string("6/8").unwrap();
2691        counted.set_beat_count(2).unwrap();
2692        assert_eq!(
2693            counted.beat_sequence().to_string(),
2694            "{{1/8+1/8+1/8}+{1/8+1/8+1/8}}"
2695        );
2696    }
2697
2698    #[test]
2699    fn a_fractional_beat_is_read_as_the_fraction_it_suggests() {
2700        use crate::meter::TimeSignature;
2701
2702        // Read off music21 11.0.0b9: getOffsetFromBeat snaps through
2703        // addFloatPrecision, so a third written as .33 is a third.
2704        // A 6/8 beat lasts 1.5, so beat 2.33 starts a third of the way
2705        // into the second beat: 1.5 + 1.5/3. music21 answers 2.0 and 2.5.
2706        let compound = TimeSignature::from_ratio_string("6/8").unwrap();
2707        assert!((compound.offset_from_beat(2.33).unwrap() - 2.0).abs() < 1e-9);
2708        assert!((compound.offset_from_beat(2.66).unwrap() - 2.5).abs() < 1e-9);
2709        assert!((compound.offset_from_beat(1.66).unwrap() - 1.0).abs() < 1e-9);
2710
2711        // A simple beat lasts one quarter, so the same beats land on thirds
2712        // of it: music21 answers 4/3, 5/3 and 2/3 for a 4/4 bar.
2713        let simple = TimeSignature::common();
2714        let third = 1.0 / 3.0;
2715        assert!((simple.offset_from_beat(2.33).unwrap() - (1.0 + third)).abs() < 1e-9);
2716        assert!((simple.offset_from_beat(2.66).unwrap() - (1.0 + 2.0 * third)).abs() < 1e-9);
2717        assert!((simple.offset_from_beat(1.66).unwrap() - (2.0 * third)).abs() < 1e-9);
2718
2719        // The divisions reach the accents and the beams, not the beats alone.
2720        let mut divided = TimeSignature::common();
2721        divided.divide_beats(4).unwrap();
2722        assert_eq!(divided.beat_sequence().to_string(), "{1/4+1/4+1/4+1/4}");
2723        assert_eq!(divided.accent_sequence().to_string(), "{1/4+1/4+1/4+1/4}");
2724        assert_eq!(divided.beam_sequence().to_string(), "{1/4+1/4+1/4+1/4}");
2725        assert_eq!(divided.display_sequence().to_string(), "{4/4}");
2726
2727        // Weighing them then loops over four parts, not eight.
2728        divided.set_accent_weight(&[0.8, 0.2], 0).unwrap();
2729        let weights = divided.accent_weights();
2730        assert_eq!(weights.len(), 4);
2731        assert!((weights[0] - 0.8).abs() < 1e-9);
2732        assert!((weights[1] - 0.2).abs() < 1e-9);
2733    }
2734
2735    #[test]
2736    fn classification_joins_division_and_count() {
2737        assert_eq!(ts("4/4").classification(), "Simple Quadruple");
2738        assert_eq!(ts("6/8").classification(), "Compound Duple");
2739        assert_eq!(ts("3/8").classification(), "Other Single");
2740        assert_eq!(ts("5/4").classification(), "Simple Quintuple");
2741        assert_eq!(ts("13/8").classification(), "Simple 13-uple");
2742        assert_eq!(ts("21/16").classification(), "Compound Septuple");
2743    }
2744
2745    #[test]
2746    fn beat_offsets_partition_the_bar() {
2747        assert_eq!(ts("4/4").beat_offsets(), [0.0, 1.0, 2.0, 3.0]);
2748        assert_eq!(ts("6/8").beat_offsets(), [0.0, 1.5]);
2749        assert_eq!(ts("5/8").beat_offsets(), [0.0, 0.5, 1.0, 1.5, 2.0]);
2750    }
2751
2752    #[test]
2753    fn beat_at_offset_is_one_based_and_bounded() {
2754        assert_eq!(ts("4/4").beat_at_offset(1.5).unwrap(), 2);
2755        assert_eq!(ts("6/8").beat_at_offset(1.5).unwrap(), 2);
2756        assert_eq!(ts("5/8").beat_at_offset(1.5).unwrap(), 4);
2757        assert_eq!(ts("4/4").beat_at_offset(0.0).unwrap(), 1);
2758        assert!(ts("4/4").beat_at_offset(4.0).is_err());
2759        assert!(ts("4/4").beat_at_offset(-0.5).is_err());
2760        assert!(ts("4/4").beat_at_offset(FloatType::NAN).is_err());
2761    }
2762
2763    #[test]
2764    fn irrational_denominators_are_accepted_as_music21_accepts_them() {
2765        let four_three = ts("4/3");
2766        assert!((four_three.bar_quarter_length() - 16.0 / 3.0).abs() < 1e-12);
2767        assert_eq!(four_three.beat_count(), 4);
2768    }
2769
2770    #[test]
2771    fn malformed_ratios_error_instead_of_panicking() {
2772        for ratio in [
2773            "", "4", "4/", "/4", "4/4/4", "x/4", "4/x", "0/4", "4/0", "-1/4",
2774        ] {
2775            assert!(
2776                TimeSignature::from_ratio_string(ratio).is_err(),
2777                "{ratio:?} should not parse"
2778            );
2779        }
2780    }
2781
2782    #[test]
2783    fn display_is_the_ratio_string() {
2784        assert_eq!(ts("7/8").to_string(), "7/8");
2785    }
2786
2787    #[test]
2788    fn a_meter_says_how_it_was_written() {
2789        use crate::meter::TimeSignature;
2790
2791        // music21 reads `ratioString` off the display sequence.
2792        let written = TimeSignature::from_ratio_string("2/4+3/8").unwrap();
2793        assert_eq!(written.ratio_string(), "2/4+3/8");
2794        assert_eq!(written.to_string(), "2/4+3/8");
2795        // What it comes to is unchanged.
2796        assert_eq!((written.numerator(), written.denominator()), (7, 8));
2797
2798        // The order it was written in is part of what it is, which is what
2799        // stops these being two spellings of one meter.
2800        let two_three = TimeSignature::from_ratio_string("2/8+3/8").unwrap();
2801        let three_two = TimeSignature::from_ratio_string("3/8+2/8").unwrap();
2802        assert_eq!(two_three.ratio_string(), "2/8+3/8");
2803        assert_eq!(three_two.ratio_string(), "3/8+2/8");
2804        assert_ne!(two_three, three_two);
2805        // Though they do come to the same ratio, which is music21's
2806        // `ratioEqual`.
2807        assert!(two_three.ratio_equal(&three_two));
2808
2809        // The string re-reads as the meter it came from.
2810        let again = TimeSignature::from_ratio_string(&written.ratio_string()).unwrap();
2811        assert_eq!(again.ratio_string(), written.ratio_string());
2812
2813        // The word before the ratio is not part of the string, though it
2814        // does still make a different meter.
2815        let slow = TimeSignature::from_ratio_string("slow 6/8").unwrap();
2816        let fast = TimeSignature::from_ratio_string("6/8").unwrap();
2817        assert_eq!(slow.ratio_string(), "6/8");
2818        assert_eq!(fast.ratio_string(), "6/8");
2819        assert_ne!(slow, fast);
2820
2821        // A bar written as one ratio is unmoved.
2822        assert_eq!(TimeSignature::common().ratio_string(), "4/4");
2823    }
2824}