Skip to main content

music21/meter/
sequence.rs

1//! How a bar divides: music21's `MeterTerminal` and `MeterSequence`.
2//!
3//! A terminal is a span of a bar written as a ratio, with a weight. A
4//! sequence is a terminal that is made of other terminals, so a bar of `4/4`
5//! partitioned in two is `{1/2+1/2}`, and either half may be partitioned
6//! again. music21 hangs four of these off every time signature — the beats,
7//! the beams, the accents and what is displayed — and this is the part of it
8//! that is arithmetic rather than notation.
9//!
10//! What a sequence may be partitioned into is not free: music21 keeps a list
11//! of the ways each meter is conventionally divided, in priority order, and
12//! partitioning by a count takes the first of those with that many parts.
13//! That is why `5/8` in two is `{2/8+3/8}` and not `{2.5/8+2.5/8}`.
14
15use crate::defaults::{FloatType, UnsignedIntegerType};
16use crate::error::{Error, Result};
17
18/// How close two quarter lengths must be to count as the same boundary.
19const OFFSET_TOLERANCE: FloatType = 1e-9;
20
21/// The denominators music21 will write a meter in.
22const VALID_DENOMINATORS: [UnsignedIntegerType; 8] = [1, 2, 4, 8, 16, 32, 64, 128];
23
24/// How an offset is matched against the boundaries of a level: music21's
25/// `align` argument to `offsetToDepth`.
26#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
27#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
28pub enum OffsetAlign {
29    /// Move the offset back to the start of the finest part holding it, then
30    /// count the levels beginning there. music21's default.
31    #[default]
32    Quantize,
33    /// Count only the levels whose part begins exactly at the offset.
34    Start,
35    /// Count the levels whose part ends exactly at the offset.
36    End,
37}
38
39/// One span of a bar: a ratio, and how strongly it is felt.
40///
41/// A span is a value: every method that divides or weighs it hands back a
42/// new span and leaves this one as it was, as music21's immutable
43/// `MeterTerminal` and `MeterSequence` do.
44#[derive(Clone, Debug)]
45#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
46pub struct MeterTerminal {
47    numerator: UnsignedIntegerType,
48    denominator: UnsignedIntegerType,
49    weight: FloatType,
50    /// What this span is itself divided into, if anything. A terminal with
51    /// parts is music21's `MeterSequence`; one without is a leaf.
52    parts: Vec<MeterTerminal>,
53    /// Whether this was written with its numerators summed over one
54    /// denominator, `3+2/8`, rather than part by part, `3/8+2/8`: music21's
55    /// `summedNumerator`.
56    #[cfg_attr(feature = "serde", serde(default))]
57    summed_numerator: bool,
58}
59
60impl MeterTerminal {
61    /// A span of `numerator/denominator`, undivided, weighing one. A
62    /// numerator of nought is a span of no length, which is what music21's
63    /// `MeterTerminal()` given nothing is.
64    pub fn new(numerator: UnsignedIntegerType, denominator: UnsignedIntegerType) -> Result<Self> {
65        if denominator == 0 {
66            return Err(Error::Meter(
67                "a meter terminal denominator must be non-zero".to_string(),
68            ));
69        }
70        Ok(Self {
71            numerator,
72            denominator,
73            weight: 1.0,
74            parts: Vec::new(),
75            summed_numerator: false,
76        })
77    }
78
79    /// The same, read from `"3/8"`.
80    pub fn from_ratio_string(ratio: &str) -> Result<Self> {
81        let (numerator, denominator) = split_ratio(ratio)?;
82        Self::new(numerator, denominator)
83    }
84
85    /// A span written as parts joined by `+`, each part a ratio: music21's
86    /// `MeterSequence('2/4+2/4')`, which is a bar of four quarters divided in
87    /// two. A part written as a bare numerator takes the denominator of the
88    /// next part that gives one, so `3+2/8` is three eighths and two eighths.
89    ///
90    /// The span itself is written over the denominator its parts share, or
91    /// the least one they all divide into: `3/4+2/4+1/8` is `11/8`.
92    ///
93    /// A span written with a bare numerator is one whose numerators were
94    /// summed, and says so: [`Self::summed_numerator`].
95    pub fn from_partition_string(written: &str) -> Result<Self> {
96        let mut parts = Vec::new();
97        let tokens: Vec<&str> = written.split('+').map(str::trim).collect();
98        // Read from the right, so a bare numerator can take the denominator
99        // of the part that follows it.
100        let mut denominators: Vec<UnsignedIntegerType> = vec![0; tokens.len()];
101        let mut carried = None;
102        for (index, token) in tokens.iter().enumerate().rev() {
103            if let Some((_, denominator)) = token.split_once('/') {
104                carried = Some(parse_number(denominator)?);
105            }
106            denominators[index] = carried.ok_or_else(|| {
107                Error::Meter(format!(
108                    "cannot read a denominator from {token:?} in {written:?}"
109                ))
110            })?;
111        }
112
113        parts.reserve(tokens.len());
114        for (token, denominator) in tokens.iter().zip(denominators) {
115            let numerator = parse_number(token.split('/').next().unwrap_or(token))?;
116            parts.push(Self::new(numerator, denominator)?);
117        }
118        let mut span = Self::from_parts(parts, written)?;
119        span.summed_numerator = tokens.iter().any(|token| !token.contains('/'));
120        Ok(span)
121    }
122
123    /// Whether this span was written with its numerators summed over one
124    /// denominator, as `3+2/8` is and `3/8+2/8` is not: music21's
125    /// `summedNumerator`. The two are the same parts; what differs is how
126    /// the meter is printed, and that a bar written this way is beamed in the
127    /// parts it was written in.
128    #[must_use]
129    pub fn summed_numerator(&self) -> bool {
130        self.summed_numerator
131    }
132
133    /// The same span, saying whether its numerators are written summed:
134    /// music21's `modify(summedNumerator=...)`.
135    pub fn with_summed_numerator(&self, summed: bool) -> Self {
136        let mut out = self.clone();
137        out.summed_numerator = summed;
138        out
139    }
140
141    /// A span of `numerator/denominator` divided into `parts`, taken as
142    /// given: music21's `makeSequence`, which does not check that the parts
143    /// come to the ratio. No parts at all is an undivided span.
144    pub fn sequence(
145        numerator: UnsignedIntegerType,
146        denominator: UnsignedIntegerType,
147        parts: Vec<Self>,
148    ) -> Result<Self> {
149        let mut span = Self::new(numerator, denominator)?;
150        span.parts = parts;
151        Ok(span)
152    }
153
154    /// The same span with a different weight: music21's
155    /// `MeterTerminal.modify(weight=...)` and `MeterSequence.withWeight`.
156    pub fn with_weight(&self, weight: FloatType) -> Self {
157        let mut out = self.clone();
158        out.set_weight(weight);
159        out
160    }
161
162    /// A span made of the parts given, which is what they come to: music21's
163    /// `MeterSequence` given a list of spans. The span is written over the
164    /// denominator its parts share, or the least one they all divide into.
165    ///
166    /// One part alone is that part, undivided, as music21 reads `'4/4'`.
167    pub fn from_parts_given(parts: Vec<Self>) -> Result<Self> {
168        Self::from_parts(parts, "a list of spans")
169    }
170
171    fn from_parts(mut parts: Vec<Self>, written: &str) -> Result<Self> {
172        if parts.len() == 1 {
173            // One part joined to nothing is just that span, as music21 reads
174            // `MeterSequence('4/4')` -- the sequence wrapping is the caller's.
175            return Ok(parts.remove(0));
176        }
177        Self::joining(parts, written)
178    }
179
180    /// A span written over what its parts come to, divided into them: the
181    /// ratio is read off the parts rather than given, which is music21's
182    /// `_updateRatio`.
183    fn joining(parts: Vec<Self>, written: &str) -> Result<Self> {
184        let shared = parts
185            .iter()
186            .map(Self::denominator)
187            .reduce(num::integer::lcm)
188            .ok_or_else(|| Error::Meter(format!("{written:?} is no meter at all")))?;
189        let total = parts
190            .iter()
191            .map(|part| part.numerator() * (shared / part.denominator()))
192            .sum();
193        Self::sequence(total, shared, parts)
194    }
195
196    /// The numerator this span is written with.
197    #[must_use]
198    pub fn numerator(&self) -> UnsignedIntegerType {
199        self.numerator
200    }
201
202    /// The denominator this span is written with.
203    #[must_use]
204    pub fn denominator(&self) -> UnsignedIntegerType {
205        self.denominator
206    }
207
208    /// How long this span is in quarter notes.
209    #[must_use]
210    pub fn quarter_length(&self) -> FloatType {
211        FloatType::from(self.numerator) * (4.0 / FloatType::from(self.denominator))
212    }
213
214    /// Every index it takes to reach the terminal sounding at an offset:
215    /// music21's `offsetToAddress`. Its length is how deep that terminal
216    /// lies, so a span nothing divides answers one index.
217    pub fn offset_to_address(&self, offset: FloatType) -> Result<Vec<usize>> {
218        let length = self.quarter_length();
219        if offset.is_nan() || offset < 0.0 || offset >= length {
220            return Err(Error::Meter(format!(
221                "cannot access from qLenPos {}",
222                super::offset_repr(offset)
223            )));
224        }
225        let index = self.offset_to_index(offset)?;
226        let mut address = vec![index];
227        let (start, _) = self.offset_to_span(offset, false)?;
228        let part = &self.parts[index];
229        if !part.is_empty() {
230            address.extend(part.offset_to_address(offset - start)?);
231        }
232        Ok(address)
233    }
234
235    /// How strongly this span is felt: music21's `weight`.
236    ///
237    /// A span with parts weighs what its parts weigh together, so weight is
238    /// kept on the terminals and read back up the tree.
239    #[must_use]
240    pub fn weight(&self) -> FloatType {
241        if self.parts.is_empty() {
242            self.weight
243        } else {
244            self.parts.iter().map(Self::weight).sum()
245        }
246    }
247
248    /// A span with parts shares the weight out among them in proportion to
249    /// how long each is, as music21 does: the four quarters of a bar weighing
250    /// one take a quarter each, where `{3/4+1/4}` takes three quarters and a
251    /// quarter.
252    fn set_weight(&mut self, weight: FloatType) {
253        self.weight = weight;
254        let whole = self.quarter_length();
255        if self.parts.is_empty() || whole == 0.0 {
256            return;
257        }
258        for part in &mut self.parts {
259            let share = part.quarter_length() / whole;
260            part.set_weight(weight * share);
261        }
262    }
263
264    /// What this span is divided into. Empty where it is a leaf.
265    #[must_use]
266    pub fn parts(&self) -> &[MeterTerminal] {
267        &self.parts
268    }
269
270    /// The same span with the part at `index` replaced by `value`, which has
271    /// to be written over the same ratio: music21's `setIndex`.
272    pub fn set_index(&self, index: usize, value: Self) -> Result<Self> {
273        let current = self
274            .parts
275            .get(index)
276            .ok_or_else(|| Error::Meter(format!("MeterSequence does not have entry {index}.")))?;
277        if !value.ratio_equal(current) {
278            return Err(Error::Meter(format!(
279                "cannot insert {value} into space of {current}"
280            )));
281        }
282        let mut out = self.clone();
283        out.parts[index] = value;
284        Ok(out)
285    }
286
287    /// How many parts this span has at its top level, music21's `len`.
288    #[must_use]
289    pub fn len(&self) -> usize {
290        self.parts.len()
291    }
292
293    /// Whether this span is divided at all.
294    #[must_use]
295    pub fn is_empty(&self) -> bool {
296        self.parts.is_empty()
297    }
298
299    /// How many levels of division this span has: music21's `depth`. A leaf
300    /// is nought.
301    #[must_use]
302    pub fn depth(&self) -> usize {
303        self.parts
304            .iter()
305            .map(|part| 1 + part.depth())
306            .max()
307            .unwrap_or(0)
308    }
309
310    /// Every leaf of this span, in order, which is what `flatten` is made
311    /// of: music21's `_getFlatList`.
312    #[must_use]
313    pub fn flattened(&self) -> Vec<MeterTerminal> {
314        if self.parts.is_empty() {
315            return vec![self.clone()];
316        }
317        self.parts
318            .iter()
319            .flat_map(MeterTerminal::flattened)
320            .collect()
321    }
322
323    /// This span divided into all of its leaves at once, however deeply
324    /// each was divided: music21's `flatten`.
325    pub fn flatten(&self) -> Result<Self> {
326        // Written over what the leaves come to, so a `4/4` bar in eighths
327        // flattens to `8/8`, as music21's does.
328        Self::joining(self.flattened(), "a flattened span")
329    }
330
331    /// What each leaf of this span weighs: music21's `flatWeight`.
332    #[must_use]
333    pub fn flat_weights(&self) -> Vec<FloatType> {
334        self.flattened().iter().map(MeterTerminal::weight).collect()
335    }
336
337    /// Whether another span is written over the same ratio: music21's
338    /// `ratioEqual`. Two spans may weigh differently and be divided
339    /// differently and still be the same meter.
340    #[must_use]
341    pub fn ratio_equal(&self, other: &Self) -> bool {
342        self.numerator == other.numerator && self.denominator == other.denominator
343    }
344
345    /// This span divided into the parts named, as `["2/8", "3/8"]`: music21's
346    /// `partitionedByList` given ratios.
347    ///
348    /// The parts must come to what this span already is; a partition that
349    /// lengthened or shortened the bar would not be one.
350    pub fn partitioned_by_parts(&self, parts: &[&str]) -> Result<Self> {
351        let mut built = Vec::with_capacity(parts.len());
352        for part in parts {
353            built.push(MeterTerminal::from_ratio_string(part)?);
354        }
355        let total: FloatType = built.iter().map(MeterTerminal::quarter_length).sum();
356        if (total - self.quarter_length()).abs() > OFFSET_TOLERANCE {
357            return Err(Error::Meter(format!(
358                "Cannot set partition by {}",
359                python_list(parts)
360            )));
361        }
362        let mut out = self.clone();
363        out.parts = built;
364        out.set_weight(self.weight());
365        Ok(out)
366    }
367
368    /// This span divided into `count` parts, the way music21 divides it:
369    /// music21's `partitionedByCount`.
370    ///
371    /// The first of [`Self::partition_options`] with that many parts wins. A
372    /// count nothing divides into leaves the first option standing, which is
373    /// music21's `loadDefault`.
374    pub fn partitioned_by_count(&self, count: usize, load_default: bool) -> Result<Self> {
375        let options = self.partition_options();
376        let chosen = options.iter().find(|option| option.len() == count);
377        let chosen = match chosen {
378            Some(option) => option.clone(),
379            None => {
380                if !load_default || options.is_empty() {
381                    return Err(Error::Meter(format!(
382                        "Cannot set partition by {count} ({}/{})",
383                        self.numerator, self.denominator
384                    )));
385                }
386                options[0].clone()
387            }
388        };
389        let borrowed: Vec<&str> = chosen.iter().map(String::as_str).collect();
390        self.partitioned_by_parts(&borrowed)
391    }
392
393    /// This span divided by a list of numerators, as `[3, 1]` for
394    /// `{3/4+1/4}`: music21's `partitionedByList`.
395    ///
396    /// music21 reads the list against this span's own denominator where the
397    /// numerators come to its numerator, and against a finer one where they
398    /// come to a multiple of it — `[1, 1, 1, 1]` of a `2/4` bar is four
399    /// eighths, not four quarters.
400    ///
401    /// Failing both, it looks for a division of its own whose numerators are
402    /// the ones asked for, which is how `[1, 1]` of a `4/4` bar comes out as
403    /// two halves and `[1]` as a whole.
404    pub fn partitioned_by_list(&self, numerators: &[UnsignedIntegerType]) -> Result<Self> {
405        if numerators.is_empty() {
406            return Err(Error::Meter(
407                "cannot partition a meter into nothing".to_string(),
408            ));
409        }
410        let total: UnsignedIntegerType = numerators.iter().sum();
411        for multiple in 1..=8 {
412            if total != self.numerator * multiple {
413                continue;
414            }
415            let denominator = self.denominator * multiple;
416            let parts: Vec<String> = numerators
417                .iter()
418                .map(|numerator| format!("{numerator}/{denominator}"))
419                .collect();
420            let borrowed: Vec<&str> = parts.iter().map(String::as_str).collect();
421            return self.partitioned_by_parts(&borrowed);
422        }
423        let asked: Vec<UnsignedIntegerType> = numerators.to_vec();
424        let matching = self.partition_options().into_iter().find(|option| {
425            option
426                .iter()
427                .map(|part| {
428                    part.split('/')
429                        .next()
430                        .and_then(|numerator| numerator.parse().ok())
431                })
432                .collect::<Option<Vec<UnsignedIntegerType>>>()
433                == Some(asked.clone())
434        });
435        if let Some(option) = matching {
436            let borrowed: Vec<&str> = option.iter().map(String::as_str).collect();
437            return self.partitioned_by_parts(&borrowed);
438        }
439        Err(Error::Meter(format!(
440            "Cannot set partition by {} ({}/{})",
441            python_list(numerators),
442            self.numerator,
443            self.denominator
444        )))
445    }
446
447    /// This span with every part divided again, the way music21 divides it
448    /// when nobody has said how: music21's `subdividedPartitionsEqual`.
449    ///
450    /// `divisions` says how many parts each part becomes; `None` asks for
451    /// the division each part conventionally takes — two for a part written
452    /// in a binary numerator, three for one written in three, and threes for
453    /// the compound numerators. A part nothing divides into is an error,
454    /// which is what music21 raises and what a meter written in notes
455    /// shorter than a 128th is forgiven.
456    pub fn subdivided_partitions_equal(&self, divisions: Option<usize>) -> Result<Self> {
457        let mut out = self.clone();
458        for part in &mut out.parts {
459            let count = match divisions {
460                Some(count) => count,
461                None => match part.numerator {
462                    1 | 2 | 4 | 8 | 16 | 32 | 64 => 2,
463                    3 => 3,
464                    6 | 9 | 12 | 15 | 18 | 21 | 24 | 27 => (part.numerator / 3) as usize,
465                    other => other as usize,
466                },
467            };
468            *part = part.partitioned_by_count(count, false)?;
469        }
470        Ok(out)
471    }
472
473    /// The part a path of indices names, and the parts it holds.
474    fn part_at(&self, path: &[usize]) -> &Self {
475        path.iter().fold(self, |span, index| &span.parts[*index])
476    }
477
478    fn part_at_mut(&mut self, path: &[usize]) -> &mut Self {
479        path.iter()
480            .fold(self, |span, index| &mut span.parts[*index])
481    }
482
483    /// Divides the parts of every span named, and answers where those parts
484    /// now are: music21's `_subdivideNested`, which is one level of
485    /// [`Self::subdivided_nested_hierarchy`].
486    fn subdivide_parts_of(
487        &mut self,
488        spans: &[Vec<usize>],
489        divisions: Option<usize>,
490    ) -> Result<Vec<Vec<usize>>> {
491        let mut deeper = Vec::new();
492        for path in spans {
493            let span = self.part_at_mut(path);
494            *span = span.subdivided_partitions_equal(divisions)?;
495            for index in 0..span.len() {
496                let mut child = path.clone();
497                child.push(index);
498                deeper.push(child);
499            }
500        }
501        Ok(deeper)
502    }
503
504    /// This span nested down to a depth: music21's
505    /// `subdividedNestedHierarchy`.
506    ///
507    /// The whole span becomes one part, that part is divided by two, by three
508    /// or by its own numerator, and every division after that is by two or
509    /// three again — so a bar of four quarters at depth two is two halves of
510    /// two quarters each. Whatever partitions the span had are gone.
511    ///
512    /// `normalize_denominators` keeps the parts of a level written over one
513    /// denominator: where they differ, the longer ones are divided again
514    /// until they agree, which is why six eighths come out as sixteenths.
515    ///
516    /// ```
517    /// use music21::meter::MeterTerminal;
518    ///
519    /// let bar = MeterTerminal::new(4, 4)?.subdivided_nested_hierarchy(2, None, true)?;
520    /// assert_eq!(bar.to_string(), "{{{1/4+1/4}+{1/4+1/4}}}");
521    /// # Ok::<(), music21::Error>(())
522    /// ```
523    pub fn subdivided_nested_hierarchy(
524        &self,
525        depth: usize,
526        first_partition_form: Option<UnsignedIntegerType>,
527        normalize_denominators: bool,
528    ) -> Result<Self> {
529        let mut out = self.partitioned_by_count(1, false)?;
530        if depth == 0 {
531            return Ok(out);
532        }
533        let form = first_partition_form.unwrap_or(self.numerator);
534        let first = match form {
535            1 | 2 | 4 | 8 | 16 | 32 => 2,
536            3 => 3,
537            other => other as usize,
538        };
539        out = out.subdivided_partitions_equal(Some(first))?;
540        out.subdivide_nested_below_the_first(depth, normalize_denominators)?;
541        Ok(out)
542    }
543
544    /// The same, with the first division taken from another sequence rather
545    /// than from a count: music21's `subdivideNestedHierarchy` handed a
546    /// `MeterSequence` as its `firstPartitionForm`.
547    ///
548    /// This is how a bar whose beats are not all one length is nested — the
549    /// five eighths of `3+2/8` divide first into a three and a two, which no
550    /// count can say. The form has to come to the same length as this span.
551    ///
552    /// ```
553    /// use music21::meter::MeterTerminal;
554    ///
555    /// let beats = MeterTerminal::from_partition_string("3/8+2/8")?;
556    /// let bar = MeterTerminal::new(5, 8)?.subdivided_nested_hierarchy_by(2, &beats, true)?;
557    /// assert_eq!(bar.to_string(), "{{{1/8+1/8+1/8}+{1/8+1/8}}}");
558    /// # Ok::<(), music21::Error>(())
559    /// ```
560    pub fn subdivided_nested_hierarchy_by(
561        &self,
562        depth: usize,
563        first_partition_form: &Self,
564        normalize_denominators: bool,
565    ) -> Result<Self> {
566        let mut out = self.partitioned_by_count(1, false)?;
567        if depth == 0 {
568            return Ok(out);
569        }
570        let ratio = |span: &Self| format!("{}/{}", span.numerator, span.denominator);
571        let written: Vec<String> = if first_partition_form.parts.is_empty() {
572            vec![ratio(first_partition_form)]
573        } else {
574            first_partition_form.parts.iter().map(ratio).collect()
575        };
576        let borrowed: Vec<&str> = written.iter().map(String::as_str).collect();
577        out.parts[0] = out.parts[0].partitioned_by_parts(&borrowed)?;
578        out.subdivide_nested_below_the_first(depth, normalize_denominators)?;
579        Ok(out)
580    }
581
582    /// Every level of a nested hierarchy below the first division, which is
583    /// by two or three however the first was made.
584    fn subdivide_nested_below_the_first(
585        &mut self,
586        depth: usize,
587        normalize_denominators: bool,
588    ) -> Result<()> {
589        let mut frontier = vec![vec![0]];
590        for _ in 1..depth {
591            frontier = self.subdivide_parts_of(&frontier, None)?;
592            if !normalize_denominators {
593                continue;
594            }
595            // Where a level is written over more than one denominator, the
596            // longer parts are divided again until it is written over one.
597            loop {
598                let denominators: Vec<UnsignedIntegerType> = frontier
599                    .iter()
600                    .map(|path| self.part_at(path).denominator())
601                    .collect();
602                let Some(shortest) = denominators.iter().min().copied() else {
603                    break;
604                };
605                if denominators
606                    .iter()
607                    .all(|denominator| *denominator == shortest)
608                {
609                    break;
610                }
611                let mut evened = Vec::new();
612                for path in &frontier {
613                    if self.part_at(path).denominator() == shortest {
614                        evened.extend(self.subdivide_parts_of(std::slice::from_ref(path), None)?);
615                    } else {
616                        evened.push(path.clone());
617                    }
618                }
619                frontier = evened;
620            }
621        }
622        Ok(())
623    }
624
625    /// The ways music21 conventionally divides this meter, in the order it
626    /// prefers them: music21's `getPartitionOptions`.
627    #[must_use]
628    pub fn partition_options(&self) -> Vec<Vec<String>> {
629        let mut options = division_options_algorithmic(self.numerator, self.denominator);
630        options.extend(division_options_preset(self.numerator, self.denominator));
631        let mut seen = Vec::new();
632        options.retain(|option| {
633            if option.is_empty() || seen.contains(option) {
634                return false;
635            }
636            seen.push(option.clone());
637            true
638        });
639        options
640    }
641
642    /// The terminals at one level of this sequence: music21's `getLevelList`.
643    ///
644    /// A part that is not divided is taken as it stands. A part that is gets
645    /// recursed into while there are levels left to descend, and at the level
646    /// asked for is either kept whole or, when `flat`, flattened into a
647    /// single terminal carrying that part's own weight.
648    #[must_use]
649    pub fn level_list(&self, level: usize, flat: bool) -> Vec<MeterTerminal> {
650        let mut out = Vec::new();
651        for part in &self.parts {
652            if part.parts.is_empty() {
653                out.push(part.clone());
654            } else if level > 0 {
655                out.extend(part.level_list(level - 1, flat));
656            } else if flat {
657                let mut flattened = part.clone();
658                flattened.weight = part.weight();
659                flattened.parts.clear();
660                out.push(flattened);
661            } else {
662                out.push(part.clone());
663            }
664        }
665        out
666    }
667
668    /// One level of this sequence as a sequence of its own: music21's
669    /// `getLevel`.
670    pub fn level(&self, level: usize, flat: bool) -> Result<Self> {
671        let mut out = Self::new(self.numerator, self.denominator)?;
672        out.weight = self.weight;
673        out.parts = self.level_list(level, flat);
674        Ok(out)
675    }
676
677    /// Where each terminal of a level starts and ends, in quarter lengths
678    /// from the start of this span: music21's `getLevelSpan`.
679    #[must_use]
680    pub fn level_span(&self, level: usize) -> Vec<(FloatType, FloatType)> {
681        let mut spans = Vec::new();
682        let mut position = 0.0;
683        for part in self.level_list(level, true) {
684            let end = position + part.quarter_length();
685            spans.push((position, end));
686            position = end;
687        }
688        spans
689    }
690
691    /// How many levels of this sequence start at an offset: music21's
692    /// `offsetToDepth`.
693    ///
694    /// A level counts when one of its parts begins where the offset does.
695    /// Under [`OffsetAlign::Quantize`] the offset is first moved back to the
696    /// start of the finest part holding it, so an offset inside a part still
697    /// counts the levels that part begins.
698    pub fn offset_to_depth(&self, offset: FloatType, align: OffsetAlign) -> Result<usize> {
699        let length = self.quarter_length();
700        if offset.is_nan() || offset < 0.0 || offset >= length {
701            return Err(Error::Meter(format!(
702                "cannot access from qLenPos {}",
703                super::offset_repr(offset)
704            )));
705        }
706        let depth = self.depth();
707        if depth == 0 {
708            return Ok(0);
709        }
710        let finest = self.level(depth - 1, true)?;
711        let index = finest.offset_to_index(offset)?;
712        let spans = self.level_span(depth - 1);
713        let position = match align {
714            OffsetAlign::Quantize => spans[index].0,
715            OffsetAlign::Start | OffsetAlign::End => offset,
716        };
717        let mut score = 0;
718        for level in 0..depth {
719            for (start, end) in self.level_span(level) {
720                let boundary = match align {
721                    OffsetAlign::Start | OffsetAlign::Quantize => start,
722                    OffsetAlign::End => end,
723                };
724                if (boundary - position).abs() < OFFSET_TOLERANCE {
725                    score += 1;
726                }
727            }
728        }
729        Ok(score)
730    }
731
732    /// This span with the terminals of a level weighed, looping the weights
733    /// given over them: music21's `withLevelWeight`.
734    ///
735    /// A level with no terminals, or no weights to give it, is an error
736    /// rather than a silent nothing.
737    pub fn with_level_weight(&self, level: usize, weights: &[FloatType]) -> Result<Self> {
738        if weights.is_empty() {
739            return Err(Error::Meter(
740                "a weight has to be given to weigh a level with".to_string(),
741            ));
742        }
743        let mut out = self.clone();
744        let mut index = 0;
745        Self::weigh(&mut out.parts, level, weights, &mut index);
746        if index == 0 {
747            return Err(Error::Meter(format!(
748                "this meter has no level {level} to weigh"
749            )));
750        }
751        Ok(out)
752    }
753
754    /// Walks the terminals of a level in order, weighing each in turn. A part
755    /// with parts of its own at the level asked for is read as one terminal,
756    /// so it uses up a weight but has nowhere to keep it, as music21's does.
757    fn weigh(parts: &mut [MeterTerminal], level: usize, weights: &[FloatType], index: &mut usize) {
758        for part in parts.iter_mut() {
759            if part.parts.is_empty() {
760                part.weight = weights[*index % weights.len()];
761                *index += 1;
762            } else if level == 0 {
763                *index += 1;
764            } else {
765                Self::weigh(&mut part.parts, level - 1, weights, index);
766            }
767        }
768    }
769
770    /// Whether every part of a level is the same ratio: music21's
771    /// `isUniformPartition`.
772    #[must_use]
773    pub fn is_uniform_partition(&self, depth: usize) -> bool {
774        let mut numerator = None;
775        let mut denominator = None;
776        for part in self.level_list(depth, false) {
777            if *numerator.get_or_insert(part.numerator) != part.numerator
778                || *denominator.get_or_insert(part.denominator) != part.denominator
779            {
780                return false;
781            }
782        }
783        true
784    }
785
786    /// The parts written out without the braces around them: music21's
787    /// `partitionDisplay`, so a bar of `2/4+6/8` reads as it was written.
788    #[must_use]
789    pub fn partition_display(&self) -> String {
790        self.parts
791            .iter()
792            .map(MeterTerminal::to_string)
793            .collect::<Vec<String>>()
794            .join("+")
795    }
796
797    /// This span divided into `count` parts, as a new sequence: music21's
798    /// `subdivideByCount`. The weight of this span goes with it, and a count
799    /// it cannot be divided into is an error.
800    pub fn subdivide_by_count(&self, count: usize) -> Result<Self> {
801        let mut out = Self::new(self.numerator, self.denominator)?;
802        out.weight = self.weight();
803        out.partitioned_by_count(count, false)
804    }
805
806    /// This span divided the way another sequence is divided: music21's
807    /// `partitionedByOtherMeterSequence`. The two have to be written over
808    /// the same ratio, and the answer keeps the weight this span had.
809    pub fn partitioned_by_other(&self, other: &Self) -> Result<Self> {
810        if !self.ratio_equal(other) {
811            return Err(Error::Meter(
812                "Cannot set partition for unequal MeterSequences".to_string(),
813            ));
814        }
815        let mut out = self.clone();
816        out.parts = other.parts.clone();
817        out.set_weight(self.weight());
818        Ok(out)
819    }
820
821    /// What each terminal of a level weighs: music21's `getLevelWeight`.
822    #[must_use]
823    pub fn level_weight(&self, level: usize) -> Vec<FloatType> {
824        self.level_list(level, true)
825            .iter()
826            .map(MeterTerminal::weight)
827            .collect()
828    }
829
830    /// This span divided by a list of numerators, as a new sequence:
831    /// music21's `subdivideByList`.
832    pub fn subdivide_by_list(&self, numerators: &[UnsignedIntegerType]) -> Result<Self> {
833        let mut out = Self::new(self.numerator, self.denominator)?;
834        out.weight = self.weight();
835        out.partitioned_by_list(numerators)
836    }
837
838    /// Which part an offset in quarter notes falls in: music21's
839    /// `offsetToIndex`. An offset outside the span is an error.
840    pub fn offset_to_index(&self, offset: FloatType) -> Result<usize> {
841        let offset = super::offset_within(offset, self.quarter_length())?;
842        let mut start = 0.0;
843        for (index, part) in self.parts.iter().enumerate() {
844            let end = start + part.quarter_length();
845            if offset >= start - OFFSET_TOLERANCE && offset < end - OFFSET_TOLERANCE {
846                return Ok(index);
847            }
848            start = end;
849        }
850        Ok(self.parts.len().saturating_sub(1))
851    }
852
853    /// Where the part an offset falls in begins and ends: music21's
854    /// `offsetToSpan`. With `permit_meter_modulus` an offset past the end of
855    /// the span is read within it.
856    pub fn offset_to_span(
857        &self,
858        offset: FloatType,
859        permit_meter_modulus: bool,
860    ) -> Result<(FloatType, FloatType)> {
861        let length = self.quarter_length();
862        let offset = if permit_meter_modulus && offset >= length {
863            offset.rem_euclid(length)
864        } else {
865            offset
866        };
867        let index = self.offset_to_index(offset)?;
868        let mut start = 0.0;
869        for (position, part) in self.parts.iter().enumerate() {
870            let end = start + part.quarter_length();
871            if position == index {
872                return Ok((start, end));
873            }
874            start = end;
875        }
876        Ok((0.0, length))
877    }
878
879    /// The weight of the part an offset falls in: music21's `offsetToWeight`.
880    pub fn offset_to_weight(&self, offset: FloatType) -> Result<FloatType> {
881        let index = self.offset_to_index(offset)?;
882        Ok(self
883            .parts
884            .get(index)
885            .map_or(self.weight, MeterTerminal::weight))
886    }
887
888    /// How this span is written: `3/4` undivided, `{1/4+1/4+1/4}` divided.
889    #[must_use]
890    pub fn partition_string(&self) -> String {
891        if self.parts.is_empty() {
892            return format!("{}/{}", self.numerator, self.denominator);
893        }
894        let inner: Vec<String> = self
895            .parts
896            .iter()
897            .map(MeterTerminal::partition_string)
898            .collect();
899        format!("{{{}}}", inner.join("+"))
900    }
901}
902
903/// Two spans are equal when they are written over the same ratio, written
904/// the same way and divided into equal parts; a span nothing divides weighs
905/// the same as well. A span with parts weighs what they weigh, so its own
906/// weight is not compared twice.
907impl PartialEq for MeterTerminal {
908    fn eq(&self, other: &Self) -> bool {
909        self.numerator == other.numerator
910            && self.denominator == other.denominator
911            && self.summed_numerator == other.summed_numerator
912            && self.parts == other.parts
913            && (!self.parts.is_empty() || self.weight == other.weight)
914    }
915}
916
917impl std::hash::Hash for MeterTerminal {
918    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
919        self.numerator.hash(state);
920        self.denominator.hash(state);
921        self.summed_numerator.hash(state);
922        if self.parts.is_empty() {
923            // Nought and minus nought are equal, so they hash alike.
924            let weight = if self.weight == 0.0 { 0.0 } else { self.weight };
925            weight.to_bits().hash(state);
926        }
927        self.parts.hash(state);
928    }
929}
930
931impl std::fmt::Display for MeterTerminal {
932    fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
933        formatter.write_str(&self.partition_string())
934    }
935}
936
937/// A list of parts as Python prints it, since music21 names a partition it
938/// cannot set by printing the list it was handed: `['3/4', '1/8']` for the
939/// written parts, `[1, 1]` for their numerators.
940fn python_list<T: std::fmt::Display>(parts: &[T]) -> String {
941    let quote = |part: &T| {
942        let written = part.to_string();
943        if written.parse::<FloatType>().is_ok() {
944            written
945        } else {
946            format!("'{written}'")
947        }
948    };
949    format!(
950        "[{}]",
951        parts.iter().map(quote).collect::<Vec<String>>().join(", ")
952    )
953}
954
955/// One of the numbers a meter is written with.
956fn parse_number(text: &str) -> Result<UnsignedIntegerType> {
957    text.trim()
958        .parse()
959        .map_err(|_| Error::Meter(format!("{text:?} is not a number a meter is written with")))
960}
961
962/// `"3/8"` as the two numbers it is written with.
963fn split_ratio(ratio: &str) -> Result<(UnsignedIntegerType, UnsignedIntegerType)> {
964    let trimmed = ratio.trim();
965    let (numerator, denominator) = trimmed.split_once('/').ok_or_else(|| {
966        Error::Meter(format!(
967            "a meter terminal is written numerator/denominator, not {ratio:?}"
968        ))
969    })?;
970    let read = |part: &str, label: &str| {
971        part.trim()
972            .parse::<UnsignedIntegerType>()
973            .map_err(|_| Error::Meter(format!("cannot read a {label} from {part:?} in {ratio:?}")))
974    };
975    Ok((
976        read(numerator, "numerator")?,
977        read(denominator, "denominator")?,
978    ))
979}
980
981/// The same ratio in shorter notes, while the denominator allows: music21's
982/// `divisionOptionsFractionsUpward`.
983fn fractions_upward(
984    numerator: UnsignedIntegerType,
985    denominator: UnsignedIntegerType,
986) -> Vec<String> {
987    let largest = VALID_DENOMINATORS[VALID_DENOMINATORS.len() - 1];
988    let mut out = Vec::new();
989    if denominator >= largest {
990        return out;
991    }
992    let (mut numerator, mut denominator) = (numerator * 2, denominator * 2);
993    while denominator <= largest {
994        out.push(format!("{numerator}/{denominator}"));
995        numerator *= 2;
996        denominator *= 2;
997    }
998    out
999}
1000
1001/// The same ratio in longer notes, while it stays whole: music21's
1002/// `divisionOptionsFractionsDownward`.
1003fn fractions_downward(
1004    numerator: UnsignedIntegerType,
1005    denominator: UnsignedIntegerType,
1006) -> Vec<String> {
1007    let smallest = VALID_DENOMINATORS[0];
1008    let mut out = Vec::new();
1009    if denominator <= smallest || !numerator.is_multiple_of(2) {
1010        return out;
1011    }
1012    let (mut numerator, mut denominator) = (numerator / 2, denominator / 2);
1013    loop {
1014        out.push(format!("{numerator}/{denominator}"));
1015        if !numerator.is_multiple_of(2) || denominator <= smallest {
1016            break;
1017        }
1018        numerator /= 2;
1019        denominator /= 2;
1020    }
1021    out
1022}
1023
1024/// One unit at a time, then twice as many half as long: music21's
1025/// `divisionOptionsAdditiveMultiplesUpward`, which stops at sixteen parts or
1026/// at the numerator where that is larger.
1027fn additive_multiples_upward(
1028    numerator: UnsignedIntegerType,
1029    denominator: UnsignedIntegerType,
1030) -> Vec<Vec<String>> {
1031    let mut out = Vec::new();
1032    if numerator <= 1 {
1033        return out;
1034    }
1035    let largest = VALID_DENOMINATORS[VALID_DENOMINATORS.len() - 1];
1036    let limit = if numerator > 16 { numerator } else { 16 };
1037    let (mut denominator, mut count) = (denominator, numerator);
1038    while denominator <= largest && count <= limit {
1039        out.push(vec![format!("1/{denominator}"); count as usize]);
1040        denominator *= 2;
1041        count *= 2;
1042    }
1043    out
1044}
1045
1046/// The bar halved, and halved again while it stays even: music21's
1047/// `divisionOptionsAdditiveMultiplesEvenDivision`. A `4/4` bar reads
1048/// `1/2+1/2`, written in the note value a half of it actually is.
1049fn additive_multiples_even_division(
1050    numerator: UnsignedIntegerType,
1051    denominator: UnsignedIntegerType,
1052) -> Vec<Vec<String>> {
1053    let mut out = Vec::new();
1054    if !numerator.is_multiple_of(2) || denominator < 2 {
1055        return out;
1056    }
1057    let (mut count, mut denominator) = (numerator / 2, denominator / 2);
1058    while denominator >= 1 && count > 1 {
1059        out.push(vec![format!("1/{denominator}"); count as usize]);
1060        if !count.is_multiple_of(2) || denominator == 1 {
1061            break;
1062        }
1063        denominator /= 2;
1064        count /= 2;
1065    }
1066    out
1067}
1068
1069/// Even groupings in the bar's own note value: music21's
1070/// `divisionOptionsAdditiveMultiples`, which reads `6/4` as `3/4+3/4`.
1071fn additive_multiples(
1072    numerator: UnsignedIntegerType,
1073    denominator: UnsignedIntegerType,
1074) -> Vec<Vec<String>> {
1075    let mut out = Vec::new();
1076    if numerator <= 3 || !numerator.is_multiple_of(2) {
1077        return out;
1078    }
1079    let mut divisor = 2;
1080    while numerator.is_multiple_of(divisor) {
1081        let count = numerator / divisor;
1082        if count <= 1 {
1083            break;
1084        }
1085        out.push(vec![format!("{count}/{denominator}"); divisor as usize]);
1086        divisor *= 2;
1087    }
1088    out
1089}
1090
1091/// A single unit split into smaller ones: music21's
1092/// `divisionOptionsAdditiveMultiplesDownward`, which only ever applies where
1093/// the numerator is one.
1094fn additive_multiples_downward(
1095    numerator: UnsignedIntegerType,
1096    denominator: UnsignedIntegerType,
1097) -> Vec<Vec<String>> {
1098    let largest = VALID_DENOMINATORS[VALID_DENOMINATORS.len() - 1];
1099    let mut out = Vec::new();
1100    if denominator >= largest || numerator != 1 {
1101        return out;
1102    }
1103    let (mut count, mut denominator) = (2usize, denominator * 2);
1104    while denominator <= largest {
1105        out.push(vec![format!("{numerator}/{denominator}"); count]);
1106        denominator *= 2;
1107        count *= 2;
1108    }
1109    out
1110}
1111
1112/// The ways music21 divides a meter, in the order it prefers them:
1113/// music21's `divisionOptionsAlgo`.
1114///
1115/// The order is the behaviour, not decoration:
1116/// [`MeterTerminal::partition_by_count`] takes the first option of the right
1117/// length, so these pieces are composed in the same sequence music21
1118/// composes them in.
1119fn division_options_algorithmic(
1120    numerator: UnsignedIntegerType,
1121    denominator: UnsignedIntegerType,
1122) -> Vec<Vec<String>> {
1123    let mut options: Vec<Vec<String>> = Vec::new();
1124
1125    // Compound meters divide into threes first: 6/8 is two dotted beats.
1126    if numerator > 3 && numerator.is_multiple_of(3) {
1127        options.push(vec![format!("3/{denominator}"); (numerator / 3) as usize]);
1128    }
1129    // The odd meters music21 keeps a grouping for.
1130    let groupings: &[&[UnsignedIntegerType]] = match numerator {
1131        5 => &[&[2, 3], &[3, 2]],
1132        7 => &[&[2, 2, 3], &[3, 2, 2], &[2, 3, 2]],
1133        10 => &[&[2, 2, 3, 3]],
1134        _ => &[],
1135    };
1136    for grouping in groupings {
1137        options.push(
1138            grouping
1139                .iter()
1140                .map(|count| format!("{count}/{denominator}"))
1141                .collect(),
1142        );
1143    }
1144    options.extend(additive_multiples_upward(numerator, denominator));
1145    options.extend(additive_multiples_even_division(numerator, denominator));
1146    options.push(vec![format!("{numerator}/{denominator}")]);
1147    options.extend(additive_multiples(numerator, denominator));
1148    options.extend(additive_multiples_downward(numerator, denominator));
1149    for written in fractions_downward(numerator, denominator) {
1150        options.push(vec![written]);
1151    }
1152    for written in fractions_upward(numerator, denominator) {
1153        options.push(vec![written]);
1154    }
1155    options
1156}
1157
1158/// The divisions music21 keeps by hand because no rule produces them: only
1159/// the two extra readings of a five.
1160fn division_options_preset(
1161    numerator: UnsignedIntegerType,
1162    denominator: UnsignedIntegerType,
1163) -> Vec<Vec<String>> {
1164    if numerator != 5 {
1165        return Vec::new();
1166    }
1167    vec![
1168        vec![
1169            format!("2/{denominator}"),
1170            format!("2/{denominator}"),
1171            format!("1/{denominator}"),
1172        ],
1173        vec![
1174            format!("2/{denominator}"),
1175            format!("1/{denominator}"),
1176            format!("2/{denominator}"),
1177        ],
1178    ]
1179}
1180
1181#[cfg(test)]
1182mod tests {
1183    use super::MeterTerminal;
1184    use super::OffsetAlign;
1185
1186    /// music21's own `divisionOptionsAlgo(4, 4)`, in its order.
1187    ///
1188    /// The order is what decides a partition: `partition_by_count` takes the
1189    /// first option of the length asked for, so `4/4` in two is `1/2+1/2`
1190    /// and not `2/4+2/4`, which comes later in the same list.
1191    #[test]
1192    fn levels_are_read_as_music21_reads_them() {
1193        // Read off music21 11.0.0b9: TimeSignature("4/4").beatSequence.
1194        let bar = MeterTerminal::new(4, 4)
1195            .unwrap()
1196            .partitioned_by_parts(&["4/4"])
1197            .unwrap()
1198            .partitioned_by_count(4, true)
1199            .unwrap()
1200            .subdivided_partitions_equal(None)
1201            .unwrap();
1202        assert_eq!(bar.to_string(), "{{1/8+1/8}+{1/8+1/8}+{1/8+1/8}+{1/8+1/8}}");
1203
1204        // getLevelList(0, True) is four quarters; (1, True) is eight eighths.
1205        let first: Vec<String> = bar
1206            .level_list(0, true)
1207            .iter()
1208            .map(MeterTerminal::to_string)
1209            .collect();
1210        assert_eq!(first, ["1/4", "1/4", "1/4", "1/4"]);
1211        let second: Vec<String> = bar
1212            .level_list(1, true)
1213            .iter()
1214            .map(MeterTerminal::to_string)
1215            .collect();
1216        assert_eq!(second, ["1/8"; 8]);
1217
1218        // music21 reads this bar as two levels deep.
1219        assert_eq!(bar.depth(), 2);
1220        assert_eq!(bar.level_span(0).len(), 4);
1221        assert_eq!(bar.level_span(0)[1], (1.0, 2.0));
1222
1223        // Every part of either level is the same ratio.
1224        assert!(bar.is_uniform_partition(0));
1225        assert!(bar.is_uniform_partition(1));
1226        // music21 reads the depth at an offset as 2, 1, 2 across the first beat.
1227        assert_eq!(bar.offset_to_depth(0.0, OffsetAlign::Quantize).unwrap(), 2);
1228        assert_eq!(bar.offset_to_depth(0.5, OffsetAlign::Quantize).unwrap(), 1);
1229        assert_eq!(bar.offset_to_depth(1.0, OffsetAlign::Quantize).unwrap(), 2);
1230    }
1231
1232    #[test]
1233    fn a_bar_written_in_unequal_parts_is_not_uniform() {
1234        let bar = MeterTerminal::new(5, 8)
1235            .unwrap()
1236            .partitioned_by_parts(&["2/8", "3/8"])
1237            .unwrap();
1238        assert!(!bar.is_uniform_partition(0));
1239        assert_eq!(bar.partition_display(), "2/8+3/8");
1240        assert_eq!(bar.depth(), 1);
1241    }
1242
1243    #[test]
1244    fn subdividing_leaves_the_span_alone_and_returns_a_new_one() {
1245        let beat = MeterTerminal::new(1, 4).unwrap().with_weight(0.5);
1246        let divided = beat.subdivide_by_count(2).unwrap();
1247        assert_eq!(divided.to_string(), "{1/8+1/8}");
1248        // music21's subdivide does not happen in place, and carries the
1249        // weight of the span it divided.
1250        assert!(beat.is_empty());
1251        assert!((divided.weight() - 0.5).abs() < 1e-9);
1252
1253        let listed = MeterTerminal::new(5, 8)
1254            .unwrap()
1255            .subdivide_by_list(&[2, 3])
1256            .unwrap();
1257        assert_eq!(listed.to_string(), "{2/8+3/8}");
1258    }
1259
1260    #[test]
1261    fn the_options_come_in_the_order_music21_offers_them() {
1262        use super::division_options_algorithmic;
1263
1264        let offered: Vec<Vec<String>> = division_options_algorithmic(4, 4)
1265            .into_iter()
1266            .take(6)
1267            .collect();
1268        assert_eq!(
1269            offered,
1270            vec![
1271                vec!["1/4"; 4],
1272                vec!["1/8"; 8],
1273                vec!["1/16"; 16],
1274                vec!["1/2"; 2],
1275                vec!["4/4"],
1276                vec!["2/4"; 2],
1277            ]
1278        );
1279
1280        // A compound meter is offered its threes first, and a five the two
1281        // groupings music21 keeps for it.
1282        assert_eq!(division_options_algorithmic(6, 8)[0], vec!["3/8"; 2]);
1283        assert_eq!(
1284            division_options_algorithmic(5, 8)[0],
1285            vec!["2/8".to_string(), "3/8".to_string()]
1286        );
1287    }
1288
1289    /// music21's own examples, which is what this has to reproduce.
1290    #[test]
1291    fn a_bar_divides_the_way_music21_divides_it() {
1292        let four_four = MeterTerminal::from_ratio_string("4/4").unwrap();
1293        let four_four = four_four.partitioned_by_count(2, true).unwrap();
1294        assert_eq!(four_four.partition_string(), "{1/2+1/2}");
1295        let four_four = four_four.partitioned_by_count(4, true).unwrap();
1296        assert_eq!(four_four.partition_string(), "{1/4+1/4+1/4+1/4}");
1297
1298        // Irregular meters take the grouping music21 keeps for them.
1299        let five_eight = MeterTerminal::from_ratio_string("5/8").unwrap();
1300        let five_eight = five_eight.partitioned_by_count(2, true).unwrap();
1301        assert_eq!(five_eight.partition_string(), "{2/8+3/8}");
1302        let five_eight = five_eight.partitioned_by_count(3, true).unwrap();
1303        assert_eq!(five_eight.partition_string(), "{2/8+2/8+1/8}");
1304
1305        // A count nothing divides into falls back to the first option.
1306        let also_five = MeterTerminal::from_ratio_string("5/8")
1307            .unwrap()
1308            .partitioned_by_count(11, true)
1309            .unwrap();
1310        assert_eq!(also_five.partition_string(), "{2/8+3/8}");
1311        assert!(
1312            MeterTerminal::from_ratio_string("5/8")
1313                .unwrap()
1314                .partitioned_by_count(11, false)
1315                .is_err()
1316        );
1317
1318        // Compound meters divide into threes first.
1319        let six_eight = MeterTerminal::from_ratio_string("6/8")
1320            .unwrap()
1321            .partitioned_by_count(2, true)
1322            .unwrap();
1323        assert_eq!(six_eight.partition_string(), "{3/8+3/8}");
1324    }
1325
1326    #[test]
1327    fn a_partition_must_come_to_what_the_bar_is() {
1328        let bar = MeterTerminal::from_ratio_string("4/4").unwrap();
1329        let bar = bar.partitioned_by_parts(&["3/4", "1/8", "1/8"]).unwrap();
1330        assert_eq!(bar.partition_string(), "{3/4+1/8+1/8}");
1331        assert!(bar.partitioned_by_parts(&["3/4", "1/8", "5/8"]).is_err());
1332
1333        // A list of numerators is read against a finer note value where it
1334        // comes to a multiple of the meter's own.
1335        let halves = MeterTerminal::from_ratio_string("2/4").unwrap();
1336        let halves = halves.partitioned_by_list(&[1, 1]).unwrap();
1337        assert_eq!(halves.partition_string(), "{1/4+1/4}");
1338        let halves = halves.partitioned_by_list(&[1, 1, 1, 1]).unwrap();
1339        assert_eq!(halves.partition_string(), "{1/8+1/8+1/8+1/8}");
1340        assert!(halves.partitioned_by_list(&[1, 1, 1]).is_err());
1341    }
1342
1343    #[test]
1344    fn an_offset_finds_the_part_it_falls_in() {
1345        let bar = MeterTerminal::from_ratio_string("4/4")
1346            .unwrap()
1347            .partitioned_by_count(4, true)
1348            .unwrap();
1349        assert_eq!(bar.offset_to_index(0.0).unwrap(), 0);
1350        assert_eq!(bar.offset_to_index(1.5).unwrap(), 1);
1351        assert_eq!(bar.offset_to_index(3.99).unwrap(), 3);
1352        assert_eq!(bar.offset_to_span(1.5, false).unwrap(), (1.0, 2.0));
1353        // Past the bar is an error, or the same offset read within it.
1354        assert!(bar.offset_to_index(4.0).is_err());
1355        assert!(bar.offset_to_index(-0.5).is_err());
1356        assert_eq!(bar.offset_to_span(5.5, true).unwrap(), (1.0, 2.0));
1357    }
1358
1359    #[test]
1360    fn a_span_says_how_deep_and_how_flat_it_is() {
1361        let bar = MeterTerminal::from_ratio_string("4/4").unwrap();
1362        assert_eq!(bar.depth(), 0);
1363        let bar = bar.partitioned_by_count(2, true).unwrap();
1364        assert_eq!(bar.depth(), 1);
1365        let first = bar.parts()[0].partitioned_by_count(2, true).unwrap();
1366        let bar = bar.set_index(0, first).unwrap();
1367        assert_eq!(bar.depth(), 2);
1368        assert_eq!(bar.partition_string(), "{{1/4+1/4}+1/2}");
1369        assert_eq!(bar.flattened().len(), 3);
1370        assert!((bar.flattened()[0].quarter_length() - 1.0).abs() < 1e-9);
1371    }
1372
1373    /// Read off music21's own `MeterSequence`.
1374    #[test]
1375    fn parts_joined_by_a_plus_are_read_as_a_partition() {
1376        let joined = MeterTerminal::from_partition_string("2/4+2/4").unwrap();
1377        assert_eq!(joined.to_string(), "{2/4+2/4}");
1378        assert_eq!((joined.numerator(), joined.denominator()), (4, 4));
1379        assert_eq!(joined.len(), 2);
1380
1381        // A bare numerator takes the denominator of the part after it.
1382        let shared = MeterTerminal::from_partition_string("3+2/8").unwrap();
1383        assert_eq!(shared.to_string(), "{3/8+2/8}");
1384        assert_eq!((shared.numerator(), shared.denominator()), (5, 8));
1385
1386        // Mixed denominators are written over the least they all divide into.
1387        let mixed = MeterTerminal::from_partition_string("3/4+2/4+1/8").unwrap();
1388        assert_eq!(mixed.to_string(), "{3/4+2/4+1/8}");
1389        assert_eq!((mixed.numerator(), mixed.denominator()), (11, 8));
1390        assert!((mixed.quarter_length() - 5.5).abs() < 1e-9);
1391
1392        // One part joined to nothing is the span itself, undivided.
1393        let alone = MeterTerminal::from_partition_string("4/4").unwrap();
1394        assert_eq!(alone.to_string(), "4/4");
1395        assert!(alone.is_empty());
1396
1397        assert!(MeterTerminal::from_partition_string("2+2").is_err());
1398        assert!(MeterTerminal::from_partition_string("half/4").is_err());
1399    }
1400
1401    /// music21's own example: a bar of four quarters whose second quarter is
1402    /// divided into sixteenths.
1403    #[test]
1404    fn an_address_says_every_index_down_to_the_terminal() {
1405        let bar = MeterTerminal::new(4, 4)
1406            .unwrap()
1407            .partitioned_by_count(4, true)
1408            .unwrap();
1409        let second = bar.parts()[1].partitioned_by_count(4, true).unwrap();
1410        let bar = bar.set_index(1, second).unwrap();
1411        assert_eq!(bar.to_string(), "{1/4+{1/16+1/16+1/16+1/16}+1/4+1/4}");
1412
1413        assert_eq!(bar.offset_to_address(0.0).unwrap(), [0]);
1414        assert_eq!(bar.offset_to_address(1.0).unwrap(), [1, 0]);
1415        assert_eq!(bar.offset_to_address(1.5).unwrap(), [1, 2]);
1416        assert_eq!(bar.offset_to_address(3.0).unwrap(), [3]);
1417        // How deep the terminal lies is how long its address is.
1418        assert_eq!(bar.offset_to_address(1.5).unwrap().len(), 2);
1419        assert!(bar.offset_to_address(-1.0).is_err());
1420    }
1421
1422    /// Every expectation here was read off music21.
1423    #[test]
1424    fn a_span_flattens_to_what_its_leaves_come_to() {
1425        let bar = MeterTerminal::new(4, 4)
1426            .unwrap()
1427            .partitioned_by_count(4, true)
1428            .unwrap()
1429            .subdivided_partitions_equal(Some(2))
1430            .unwrap();
1431
1432        let flat = bar.flatten().unwrap();
1433        assert_eq!(flat.to_string(), "{1/8+1/8+1/8+1/8+1/8+1/8+1/8+1/8}");
1434        // Written over what the leaves come to, not over the bar it came from.
1435        assert_eq!((flat.numerator(), flat.denominator()), (8, 8));
1436        assert_eq!(bar.flat_weights(), vec![0.125; 8]);
1437        assert_eq!(bar.level_weight(0), vec![0.25; 4]);
1438        assert_eq!(bar.level_weight(1), vec![0.125; 8]);
1439    }
1440
1441    /// Every expectation here was read off music21.
1442    #[test]
1443    fn a_span_takes_the_division_and_the_shape_of_another() {
1444        let quarters = MeterTerminal::new(4, 4)
1445            .unwrap()
1446            .partitioned_by_count(4, true)
1447            .unwrap();
1448        let halves = MeterTerminal::new(4, 4)
1449            .unwrap()
1450            .partitioned_by_count(2, true)
1451            .unwrap();
1452
1453        let quarters = quarters.partitioned_by_other(&halves).unwrap();
1454        assert_eq!(quarters.to_string(), "{1/2+1/2}");
1455        // The weight it had, which its new parts share out between them.
1456        assert_eq!(quarters.weight(), 1.0);
1457
1458        // A division cannot relength the bar, whichever way it is asked for.
1459        let three = MeterTerminal::new(3, 4).unwrap();
1460        assert!(quarters.partitioned_by_other(&three).is_err());
1461
1462        let thirds = MeterTerminal::from_partition_string("1/4+1/4+1/4").unwrap();
1463        let sixths = MeterTerminal::from_partition_string("3/8+3/8").unwrap();
1464
1465        assert!(thirds.ratio_equal(&MeterTerminal::new(3, 4).unwrap()));
1466        assert!(!thirds.ratio_equal(&sixths));
1467    }
1468}