Skip to main content

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