redact_composer_musical/rhythm/
mod.rs1use std::cmp::Ordering;
2use std::ops::{Add, Range};
3
4use crate::rhythm::DivType::Div;
5use crate::timing::TimeSignature;
6use rand::distributions::WeightedIndex;
7use rand::{seq::SliceRandom, Rng};
8
9#[cfg(feature = "serde")]
10use serde::{Deserialize, Serialize};
11
12#[cfg(feature = "redact-composer")]
13use redact_composer_core::{derive::Element, timing::Timing};
14
15#[cfg(test)]
16mod test;
17
18#[derive(Debug, Copy, Clone, PartialEq, Eq)]
20#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
21pub struct Subdivision {
22 pub start: i32,
24 pub end: i32,
26 pub is_rest: bool,
28}
29
30impl Subdivision {
31 pub fn timing(&self) -> Range<i32> {
33 self.start..self.end
34 }
35}
36
37impl From<Subdivision> for Range<i32> {
38 fn from(value: Subdivision) -> Self {
39 value.timing()
40 }
41}
42
43impl From<&Subdivision> for Range<i32> {
44 fn from(value: &Subdivision) -> Self {
45 value.timing()
46 }
47}
48
49#[cfg(feature = "redact-composer")]
50impl From<&Subdivision> for Timing {
51 fn from(value: &Subdivision) -> Self {
52 value.timing().into()
53 }
54}
55
56#[cfg(feature = "redact-composer")]
57impl From<Subdivision> for Timing {
58 fn from(value: Subdivision) -> Self {
59 value.timing().into()
60 }
61}
62
63impl From<Range<i32>> for Subdivision {
64 fn from(value: Range<i32>) -> Self {
65 Subdivision {
66 start: value.start,
67 end: value.end,
68 is_rest: false,
69 }
70 }
71}
72
73impl From<&Range<i32>> for Subdivision {
74 fn from(value: &Range<i32>) -> Self {
75 Subdivision {
76 start: value.start,
77 end: value.end,
78 is_rest: false,
79 }
80 }
81}
82
83impl From<i32> for Subdivision {
84 fn from(value: i32) -> Self {
85 Subdivision {
86 start: 0,
87 end: value,
88 is_rest: false,
89 }
90 }
91}
92
93impl From<&i32> for Subdivision {
94 fn from(value: &i32) -> Self {
95 Subdivision {
96 start: 0,
97 end: *value,
98 is_rest: false,
99 }
100 }
101}
102
103impl<I: IntoIterator<Item = T>, T: Into<Subdivision>> From<I> for Rhythm {
104 fn from(value: I) -> Self {
105 let mut stuff = value
106 .into_iter()
107 .map(Into::into)
108 .collect::<Vec<Subdivision>>();
109 stuff.sort_by_key(|div| div.start);
110
111 let result = stuff
112 .into_iter()
113 .scan(None::<Subdivision>, |opt_prev, item| {
114 let next = match opt_prev {
115 None => {
116 vec![item]
117 }
118 Some(prev) => {
119 if item.start == 0 {
120 vec![Subdivision {
121 start: prev.end,
122 end: item.end + prev.end,
123 is_rest: false,
124 }]
125 } else if item.end <= prev.end {
126 vec![]
127 } else if item.start > prev.end {
128 vec![
129 Subdivision {
130 start: prev.end,
131 end: item.start,
132 is_rest: true,
133 },
134 Subdivision {
135 start: item.start,
136 end: item.end,
137 is_rest: item.is_rest,
138 },
139 ]
140 } else {
141 vec![Subdivision {
142 start: prev.end,
143 end: item.end,
144 is_rest: item.is_rest,
145 }]
146 }
147 }
148 };
149
150 if let Some(next) = next.last() {
151 opt_prev.replace(*next);
152 }
153
154 Some(next)
155 })
156 .flatten()
157 .collect::<Vec<_>>();
158
159 Rhythm(result)
160 }
161}
162
163#[derive(Debug)]
165pub enum DivType {
166 Div(i32),
168 Rest(i32),
170}
171
172impl From<DivType> for Subdivision {
173 fn from(value: DivType) -> Self {
174 match value {
175 Div(len) => Subdivision {
176 start: 0,
177 end: len,
178 is_rest: false,
179 },
180 DivType::Rest(len) => Subdivision {
181 start: 0,
182 end: len,
183 is_rest: true,
184 },
185 }
186 }
187}
188
189impl Add<Rhythm> for Rhythm {
190 type Output = Rhythm;
191
192 fn add(self, mut rhs: Rhythm) -> Self::Output {
193 let first_length = self.len();
194 let mut new_subdivisions = self.0.into_iter().collect::<Vec<_>>();
195 new_subdivisions.append(&mut rhs.offset(first_length).0);
196
197 Rhythm(new_subdivisions)
198 }
199}
200
201#[derive(Debug, Clone)]
203#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
204#[cfg_attr(feature = "redact-composer", derive(Element))]
205pub struct Rhythm(pub Vec<Subdivision>);
206impl Rhythm {
207 pub fn new() -> Rhythm {
209 Rhythm(vec![])
210 }
211
212 pub fn iter(&self) -> impl Iterator<Item = &Subdivision> {
214 self.0.iter().filter(|div| !div.is_rest)
215 }
216
217 pub fn iter_including_rests(&self) -> impl Iterator<Item = &Subdivision> {
219 self.0.iter()
220 }
221
222 pub fn balanced_timing(
224 length: i32,
225 subdivisions: i32,
226 time_signature: &TimeSignature,
227 rng: &mut impl Rng,
228 ) -> Rhythm {
229 let ts = time_signature;
230 let mut rhythm = vec![length];
231
232 let lengths = [ts.bar(), ts.beat(), ts.half_beat(), ts.quarter_beat()];
233
234 while (rhythm.len() as i32) < subdivisions {
235 let longest = rhythm
236 .iter()
237 .copied()
238 .enumerate()
239 .max_by(|(_, a), (_, b)| a.cmp(b))
240 .unwrap();
241 let opt_subdivision = lengths.iter().find(|s| longest.1 / *s > 1);
242
243 if let Some(subdivision) = opt_subdivision {
244 rhythm.remove(longest.0);
245
246 let split_length = (longest.1 / subdivision) / 2 * subdivision;
247 rhythm.push(split_length);
248 rhythm.push(longest.1 - split_length);
249 } else {
250 break;
251 }
252 }
253
254 if (rhythm.len() as i32) != subdivisions {
255 panic!("Couldn't divide into desired number of subdivisions")
256 }
257
258 rhythm.shuffle(rng);
259
260 Rhythm::from(rhythm)
261 }
262
263 pub fn random(
265 length: i32,
266 time_signature: &TimeSignature,
267 division_probability: impl Fn(i32) -> f32,
268 rest_probability: impl Fn(i32) -> f32,
269 rng: &mut impl Rng,
270 ) -> Rhythm {
271 let ts = time_signature;
272 let mut rhythm_build = vec![(length, false)];
273
274 let div_choices = |div: i32| match div {
275 div if div > ts.bar() => {
276 let mut bar_divisions = vec![ts.bar(); (div / ts.bar()) as usize];
277 if div % ts.bar() != 0 {
278 bar_divisions.push(div % ts.bar());
279 }
280
281 Some(vec![bar_divisions])
282 }
283 div if div > ts.beats(2) => Some(vec![
284 vec![ts.beats(2), div - ts.beats(2)],
285 vec![ts.beat(), div - ts.beat()],
286 ]),
287 div if div == ts.beats(2) => Some(vec![
288 vec![ts.triplet(); 3],
289 vec![ts.beat() + ts.half_beat(), ts.half_beat()],
290 vec![ts.beat(), div - ts.beat()],
291 ]),
292 div if div >= ts.beat() => Some(vec![vec![ts.half_beat(), div - ts.half_beat()]]),
293 div if div >= ts.half_beat() => {
294 Some(vec![vec![ts.quarter_beat(), div - ts.quarter_beat()]])
295 }
296 _ => None,
297 };
298
299 while !rhythm_build.iter().all(|(_, stop_dividing)| *stop_dividing) {
300 rhythm_build = rhythm_build
301 .into_iter()
302 .flat_map(|(current_division, stop_dividing)| {
303 if !stop_dividing
304 && rng.gen_bool(
305 division_probability(current_division)
306 .clamp(0.0, 1.0)
307 .into(),
308 )
309 {
310 if let Some(choices) = div_choices(current_division) {
311 let choice = choices.choose(rng).unwrap();
312
313 choice.iter().map(|b| (*b, false)).collect::<Vec<_>>()
314 } else {
315 vec![(current_division, true)]
316 }
317 } else {
318 vec![(current_division, true)]
319 }
320 })
321 .collect();
322 }
323
324 Self(
325 rhythm_build
326 .into_iter()
327 .scan((0, 0), |acc, (x, _)| {
328 acc.0 = acc.1;
329 acc.1 = acc.0 + x;
330
331 Some(Subdivision {
332 start: acc.0,
333 end: acc.1,
334 is_rest: rng.gen_bool(rest_probability(x).clamp(0.0, 1.0).into()),
335 })
336 })
337 .collect(),
338 )
339 }
340
341 pub fn random_with_subdivisions_weights(
344 length: i32,
345 subdivision_weights: &[(Vec<i32>, i32)],
346 rng: &mut impl Rng,
347 ) -> Rhythm {
348 let mut timings = vec![];
349 let mut sum = 0;
350
351 if subdivision_weights
352 .iter()
353 .all(|(t, _)| t.iter().sum::<i32>() > length)
354 {
355 return Rhythm::new();
356 }
357
358 while sum < length {
359 let remaining = length - sum;
360 let sizeable_choices = subdivision_weights
361 .iter()
362 .filter(|(t, _)| t.iter().sum::<i32>() <= remaining)
363 .collect::<Vec<_>>();
364 let dist = WeightedIndex::new(sizeable_choices.iter().map(|(_, i)| i)).unwrap();
365
366 let choice = &sizeable_choices[rng.sample(dist)].0;
367
368 timings.push(choice.clone());
369 sum += choice.iter().sum::<i32>();
370 }
371
372 timings.shuffle(rng);
373
374 Rhythm(
375 timings
376 .into_iter()
377 .flatten()
378 .scan((0, 0), |acc, x| {
379 acc.0 = acc.1;
380 acc.1 = acc.0 + x;
381 Some(*acc)
382 })
383 .map(|t| Subdivision {
384 start: t.0,
385 end: t.1,
386 is_rest: false,
387 })
388 .collect::<Vec<_>>(),
389 )
390 }
391
392 pub fn offset(&mut self, amount: i32) -> Rhythm {
394 Rhythm(
395 self.0
396 .iter()
397 .map(|s| Subdivision {
398 start: s.start + amount,
399 end: s.end + amount,
400 is_rest: s.is_rest,
401 })
402 .collect::<Vec<_>>(),
403 )
404 }
405
406 pub fn frame(&self, frame_size: i32) -> Rhythm {
410 let mut divs = self
411 .0
412 .iter()
413 .take_while(|div| div.start < frame_size)
414 .copied()
415 .collect::<Vec<_>>();
416
417 if let Some(last) = divs.last_mut() {
418 let copied_end = last.end;
419 match last.end.cmp(&frame_size) {
420 Ordering::Less => {
421 if last.is_rest {
422 last.end = frame_size;
423 } else {
424 divs.push(Subdivision {
425 start: copied_end,
426 end: frame_size,
427 is_rest: true,
428 });
429 }
430 }
431 Ordering::Greater => {
432 last.end = frame_size;
433 }
434 Ordering::Equal => {}
435 }
436
437 Rhythm(divs)
438 } else {
439 Rhythm(Vec::new())
440 }
441 }
442
443 pub fn repeat_every(&self, length: i32) -> Rhythm {
445 self.frame(length)
446 }
447
448 #[allow(clippy::len_without_is_empty)]
450 pub fn len(&self) -> i32 {
451 self.0.last().map(|r| r.end).unwrap_or_default()
452 }
453
454 pub fn over(&self, range: impl Into<Range<i32>>) -> Vec<Subdivision> {
457 self.iter_over(range.into()).collect()
458 }
459
460 pub fn iter_over<'a>(
464 &'a self,
465 range: impl Into<Range<i32>> + 'a,
466 ) -> impl Iterator<Item = Subdivision> + '_ {
467 let rhythm_length = self.len();
468 let range = range.into();
469
470 self.0
471 .iter()
472 .cycle()
473 .scan(range.start, move |offset, subdivision| {
474 if let Some(last_division) = self.0.last() {
475 let offset_subdivision = Subdivision {
476 start: *offset + subdivision.start,
477 end: *offset + subdivision.end,
478 is_rest: subdivision.is_rest,
479 };
480
481 if subdivision == last_division {
482 *offset += rhythm_length;
483 }
484
485 if offset_subdivision.end <= range.end {
486 Some(offset_subdivision)
487 } else {
488 None
489 }
490 } else {
491 None
492 }
493 })
494 .filter(|div| !div.is_rest)
495 }
496}
497
498impl Default for Rhythm {
499 fn default() -> Self {
500 Rhythm::new()
501 }
502}