1use crate::defaults::{FloatType, IntegerType};
25use crate::error::{Error, Result};
26use crate::expressions::{Ornament, OrnamentKind};
27use crate::interval::{Interval, IntervalDirection};
28use crate::makenotation::op_frac;
29use crate::note::Note;
30use crate::stream::StreamElement;
31
32pub fn ornament_total_quarter_length(
36 busy: &[StreamElement],
37 simple: &[StreamElement],
38) -> FloatType {
39 match simple.first() {
40 Some(note) => note.quarter_length(),
41 None => op_frac(busy.iter().map(StreamElement::quarter_length).sum()),
42 }
43}
44
45pub fn ornament_note_quarter_length(busy: &[StreamElement], simple: &[StreamElement]) -> FloatType {
48 op_frac(ornament_total_quarter_length(busy, simple) / busy.len() as FloatType)
49}
50
51fn note_of(element: &StreamElement) -> Result<&Note> {
53 match element {
54 StreamElement::Note(note) => Ok(note),
55 other => {
56 let class = match other {
57 StreamElement::Rest(_) => "Rest",
58 StreamElement::Chord(_) => "Chord",
59 StreamElement::Unpitched(_) => "Unpitched",
60 StreamElement::PercussionChord(_) => "PercussionChord",
61 StreamElement::ChordSymbol(_) => "ChordSymbol",
62 _ => "Music21Object",
63 };
64 Err(Error::Analysis(format!("a {class} has no single pitch")))
65 }
66 }
67}
68
69#[derive(Clone, Debug, PartialEq, Eq)]
71#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
72pub struct TrillRecognizer {
73 pub check_nachschlag: bool,
76 pub acceptable_interval: IntegerType,
79 pub minimum_length_for_nachschlag: usize,
82}
83
84impl Default for TrillRecognizer {
85 fn default() -> Self {
86 Self {
87 check_nachschlag: false,
88 acceptable_interval: 3,
89 minimum_length_for_nachschlag: 5,
90 }
91 }
92}
93
94impl TrillRecognizer {
95 pub fn recognize(
110 &self,
111 busy: &[StreamElement],
112 simple: &[StreamElement],
113 ) -> Result<Option<Ornament>> {
114 if busy.len() <= 2 {
115 return Ok(None);
116 }
117 let (StreamElement::Note(first), StreamElement::Note(second)) = (&busy[0], &busy[1]) else {
118 return Ok(None);
119 };
120 if (first.pitch().midi() - second.pitch().midi()).abs() > self.acceptable_interval {
121 return Ok(None);
122 }
123 let mut alternating = true;
124 let mut reached = 0;
125 for (index, element) in busy.iter().enumerate() {
126 reached = index;
127 let StreamElement::Note(note) = element else {
128 return Ok(None);
129 };
130 let expected = if index % 2 == 0 { first } else { second };
131 if note.pitch() != expected.pitch() {
132 alternating = false;
133 break;
134 }
135 }
136 let nachschlag = if alternating {
137 false
138 } else if !self.check_nachschlag {
139 return Ok(None);
140 } else if busy.len() >= self.minimum_length_for_nachschlag
141 && reached as FloatType >= busy.len() as FloatType / 2.0
142 {
143 true
144 } else {
145 return Ok(None);
146 };
147
148 let (start, end) = match simple.first() {
149 None => (first, second),
150 Some(written) => {
151 let midi = note_of(written)?.pitch().midi();
152 if midi != first.pitch().midi() && midi != second.pitch().midi() {
153 return Ok(None);
154 }
155 if midi == second.pitch().midi() {
156 (second, first)
157 } else {
158 (first, second)
159 }
160 }
161 };
162 let mut trill = Ornament::of_kind(if start.pitch().midi() <= end.pitch().midi() {
163 OrnamentKind::Trill
164 } else {
165 OrnamentKind::InvertedTrill
166 });
167 trill.set_quarter_length(ornament_note_quarter_length(busy, simple));
168 trill.set_nachschlag(nachschlag);
169 if let Some(accidental) = end.pitch().written_accidental() {
170 trill.set_accidental(Some(accidental.clone()))?;
171 }
172 Ok(Some(trill))
173 }
174}
175
176#[derive(Clone, Debug, PartialEq)]
178#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
179pub struct TurnRecognizer {
180 pub acceptable_intervals: Vec<Interval>,
183}
184
185impl Default for TurnRecognizer {
186 fn default() -> Self {
187 Self {
188 acceptable_intervals: ["M2", "M-2", "m2", "m-2", "A2", "A-2"]
189 .iter()
190 .map(|name| Interval::from_name(*name).expect("a second"))
191 .collect(),
192 }
193 }
194}
195
196impl TurnRecognizer {
197 pub fn is_acceptable_interval(&self, step: &Interval) -> bool {
199 self.acceptable_intervals.contains(step)
200 }
201
202 pub fn recognize(
215 &self,
216 busy: &[StreamElement],
217 simple: &[StreamElement],
218 ) -> Result<Option<Ornament>> {
219 if busy.len() != 4 {
220 return Ok(None);
221 }
222 if let Some(written) = simple.first() {
223 let played: FloatType = busy.iter().map(StreamElement::quarter_length).sum();
224 if (written.quarter_length() - played).abs() > 0.1 {
225 return Ok(None);
226 }
227 }
228 let main = note_of(&busy[1])?.pitch().midi();
229 if main != note_of(&busy[3])?.pitch().midi() {
230 return Ok(None);
231 }
232 if let Some(written) = simple.first()
233 && note_of(written)?.pitch().midi() != main
234 {
235 return Ok(None);
236 }
237 let mut steps = Vec::new();
238 for pair in busy.windows(2) {
239 let step =
240 Interval::between_pitches(note_of(&pair[0])?.pitch(), note_of(&pair[1])?.pitch())?;
241 if !self.is_acceptable_interval(&step) {
242 return Ok(None);
243 }
244 steps.push(step);
245 }
246 if steps[0].direction() != steps[1].direction()
247 || steps[1].direction() == steps[2].direction()
248 {
249 return Ok(None);
250 }
251 let mut turn =
252 Ornament::of_kind(if steps[0].direction() == IntervalDirection::Descending {
253 OrnamentKind::Turn
254 } else {
255 OrnamentKind::InvertedTurn
256 });
257 turn.set_quarter_length(ornament_note_quarter_length(busy, simple));
258 Ok(Some(turn))
259 }
260}
261
262#[cfg(test)]
263mod tests {
264 use super::*;
265 use crate::duration::Duration;
266 use crate::key::KeySignature;
267 use crate::rest::Rest;
268
269 fn notes(names: &[&str], length: FloatType) -> Vec<StreamElement> {
270 names
271 .iter()
272 .map(|name| {
273 StreamElement::Note(
274 Note::from_name(name)
275 .unwrap()
276 .with_duration(Duration::new(length).unwrap()),
277 )
278 })
279 .collect()
280 }
281
282 fn quarter(name: &str) -> Vec<StreamElement> {
283 notes(&[name], 1.0)
284 }
285
286 #[test]
288 fn turns_are_recognized_as_music21_recognizes_them() {
289 let recognizer = TurnRecognizer::default();
290 let kind = |busy: &[StreamElement], simple: &[StreamElement]| {
291 recognizer
292 .recognize(busy, simple)
293 .unwrap()
294 .map(|turn| turn.kind())
295 };
296 let even = notes(&["G", "F#", "E", "F#"], 0.25);
297 assert_eq!(kind(&even, &[]), Some(OrnamentKind::Turn));
298 assert_eq!(kind(&even, &quarter("F#")), Some(OrnamentKind::Turn));
299 assert_eq!(kind(&even, &quarter("G-")), Some(OrnamentKind::Turn));
300 assert_eq!(kind(&even, &quarter("G")), None);
301 assert_eq!(kind(&even, &quarter("A")), None);
302 let mut rubato = notes(&["G", "F#", "E", "F#"], 0.25);
303 for (element, length) in rubato.iter_mut().zip([0.25, 0.15, 0.2, 0.4]) {
304 if let StreamElement::Note(note) = element {
305 note.set_duration(Duration::new(length).unwrap());
306 }
307 }
308 assert_eq!(kind(&rubato, &[]), Some(OrnamentKind::Turn));
309 assert_eq!(
310 kind(¬es(&["E", "F#", "G", "F#"], 0.25), &[]),
311 Some(OrnamentKind::InvertedTurn)
312 );
313 for wrong in [
314 &["G", "F#", "E", "D"][..],
315 &["E", "G", "A", "G"],
316 &["G", "F#", "G", "F#"],
317 &["G", "F#", "E", "F#", "E"],
318 &["G", "F#", "E"],
319 ] {
320 assert_eq!(kind(¬es(wrong, 0.25), &[]), None, "{wrong:?}");
321 }
322 assert_eq!(
324 kind(¬es(&["G", "F#", "E", "F#"], 1.0), &quarter("F#")),
325 None
326 );
327 }
328
329 #[test]
331 fn trills_are_recognized_as_music21_recognizes_them() {
332 let plain = TrillRecognizer::default();
333 let size = |trill: &Ornament, from: &str| {
334 trill
335 .size(
336 &crate::pitch::Pitch::from_name(from).unwrap(),
337 &KeySignature::new(0),
338 )
339 .unwrap()
340 .directed_name()
341 };
342 let gaga = notes(&["G", "A", "G", "A"], 0.25);
343 let trill = plain.recognize(&gaga, &[]).unwrap().unwrap();
344 assert_eq!(trill.kind(), OrnamentKind::Trill);
345 assert_eq!(size(&trill, "G"), "M2");
346 let trill = plain.recognize(&gaga, &quarter("A")).unwrap().unwrap();
347 assert_eq!(trill.kind(), OrnamentKind::InvertedTrill);
348 assert_eq!(size(&trill, "A"), "M-2");
349 assert!(plain.recognize(&gaga, &quarter("G##")).unwrap().is_some());
350 assert!(plain.recognize(&gaga, &quarter("E")).unwrap().is_none());
351 let mut with_rest = gaga.clone();
352 with_rest[2] = StreamElement::Rest(Rest::new(Duration::new(0.25).unwrap()));
353 assert!(plain.recognize(&with_rest, &[]).unwrap().is_none());
354
355 let a_g = notes(&["A", "G#", "A", "G#", "A"], 0.4);
356 let trill = plain.recognize(&a_g, &[]).unwrap().unwrap();
357 assert_eq!(trill.kind(), OrnamentKind::InvertedTrill);
358 assert_eq!(size(&trill, "A"), "m-2");
359
360 let nachschlag = notes(&["C5", "B", "C5", "B", "C5", "D5", "E5", "F5"], 0.125);
361 assert!(plain.recognize(&nachschlag, &[]).unwrap().is_none());
362 let checking = TrillRecognizer {
363 check_nachschlag: true,
364 ..TrillRecognizer::default()
365 };
366 let trill = checking.recognize(&nachschlag, &[]).unwrap().unwrap();
367 assert!(trill.nachschlag());
368 assert_eq!(size(&trill, "C5"), "m-2");
369
370 assert!(plain.recognize(¬es(&["A"], 0.5), &[]).unwrap().is_none());
371 assert!(
372 plain
373 .recognize(¬es(&["A", "G"], 0.5), &[])
374 .unwrap()
375 .is_none()
376 );
377 assert!(
378 plain
379 .recognize(¬es(&["A", "C", "A", "C"], 0.5), &[])
380 .unwrap()
381 .is_none()
382 );
383 assert!(
384 plain
385 .recognize(¬es(&["F", "E", "F", "G"], 0.5), &[])
386 .unwrap()
387 .is_none()
388 );
389 }
390}