1use crate::defaults::{FloatType, UnsignedIntegerType};
16use crate::error::{Error, Result};
17
18const OFFSET_TOLERANCE: FloatType = 1e-9;
20
21const VALID_DENOMINATORS: [UnsignedIntegerType; 8] = [1, 2, 4, 8, 16, 32, 64, 128];
23
24#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
27#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
28pub enum OffsetAlign {
29 #[default]
32 Quantize,
33 Start,
35 End,
37}
38
39#[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 parts: Vec<MeterTerminal>,
53 #[cfg_attr(feature = "serde", serde(default))]
57 summed_numerator: bool,
58}
59
60impl MeterTerminal {
61 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 pub fn from_ratio_string(ratio: &str) -> Result<Self> {
81 let (numerator, denominator) = split_ratio(ratio)?;
82 Self::new(numerator, denominator)
83 }
84
85 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 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 #[must_use]
129 pub fn summed_numerator(&self) -> bool {
130 self.summed_numerator
131 }
132
133 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 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 pub fn with_weight(&self, weight: FloatType) -> Self {
157 let mut out = self.clone();
158 out.set_weight(weight);
159 out
160 }
161
162 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 return Ok(parts.remove(0));
176 }
177 Self::joining(parts, written)
178 }
179
180 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 #[must_use]
198 pub fn numerator(&self) -> UnsignedIntegerType {
199 self.numerator
200 }
201
202 #[must_use]
204 pub fn denominator(&self) -> UnsignedIntegerType {
205 self.denominator
206 }
207
208 #[must_use]
210 pub fn quarter_length(&self) -> FloatType {
211 FloatType::from(self.numerator) * (4.0 / FloatType::from(self.denominator))
212 }
213
214 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 #[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 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 #[must_use]
266 pub fn parts(&self) -> &[MeterTerminal] {
267 &self.parts
268 }
269
270 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 #[must_use]
289 pub fn len(&self) -> usize {
290 self.parts.len()
291 }
292
293 #[must_use]
295 pub fn is_empty(&self) -> bool {
296 self.parts.is_empty()
297 }
298
299 #[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 #[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 pub fn flatten(&self) -> Result<Self> {
326 Self::joining(self.flattened(), "a flattened span")
329 }
330
331 #[must_use]
333 pub fn flat_weights(&self) -> Vec<FloatType> {
334 self.flattened().iter().map(MeterTerminal::weight).collect()
335 }
336
337 #[must_use]
341 pub fn ratio_equal(&self, other: &Self) -> bool {
342 self.numerator == other.numerator && self.denominator == other.denominator
343 }
344
345 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 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 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 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 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 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 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 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 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 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 #[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 #[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 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 #[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 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 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 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 #[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 #[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 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 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 #[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 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 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 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 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 #[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
903impl 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 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
937fn 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
955fn 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
962fn 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
981fn 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
1001fn 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
1024fn 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
1046fn 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
1069fn 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
1091fn 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
1112fn division_options_algorithmic(
1120 numerator: UnsignedIntegerType,
1121 denominator: UnsignedIntegerType,
1122) -> Vec<Vec<String>> {
1123 let mut options: Vec<Vec<String>> = Vec::new();
1124
1125 if numerator > 3 && numerator.is_multiple_of(3) {
1127 options.push(vec![format!("3/{denominator}"); (numerator / 3) as usize]);
1128 }
1129 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
1158fn 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 #[test]
1192 fn levels_are_read_as_music21_reads_them() {
1193 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 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 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 assert!(bar.is_uniform_partition(0));
1225 assert!(bar.is_uniform_partition(1));
1226 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 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 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 #[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 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 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 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 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 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 #[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 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 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 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 #[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 assert_eq!(bar.offset_to_address(1.5).unwrap().len(), 2);
1419 assert!(bar.offset_to_address(-1.0).is_err());
1420 }
1421
1422 #[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 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 #[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 assert_eq!(quarters.weight(), 1.0);
1457
1458 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}