1use crate::common::stringtools::camel_case_to_hyphen;
14use crate::defaults::{FloatType, IntegerType};
15use crate::interval::ChromaticInterval;
16
17#[derive(Clone, Debug, PartialEq, Eq, Hash)]
21#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
22pub enum Finger {
23 Number(IntegerType),
25 Written(String),
27}
28
29impl Finger {
30 pub fn from_written(text: &str) -> Self {
33 text.trim()
34 .parse()
35 .map_or_else(|_| Self::Written(text.to_string()), Self::Number)
36 }
37}
38
39struct KindRow {
41 kind: ArticulationKind,
42 class: &'static str,
43 parents: &'static [&'static str],
46 volume_shift: FloatType,
47 length_shift: FloatType,
48 tie_attach: &'static str,
49 fields: &'static [&'static str],
52}
53
54#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
56#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
57pub enum ArticulationKind {
58 Articulation,
60 Caesura,
62 DynamicArticulation,
64 LengthArticulation,
66 PitchArticulation,
68 TechnicalIndication,
70 TimbreArticulation,
72 Accent,
74 Bowing,
76 BreathMark,
78 DetachedLegato,
80 Fingering,
82 FretIndication,
84 HandbellIndication,
86 Harmonic,
88 HarpIndication,
90 IndeterminateSlide,
92 OrganIndication,
94 Staccato,
96 Tenuto,
98 Unstress,
100 WindIndication,
102 BrassIndication,
104 Doit,
106 DownBow,
108 Falloff,
110 FretBend,
112 FretTap,
114 HarpFingerNails,
116 OpenString,
118 OrganHeel,
120 OrganToe,
122 Pizzicato,
124 Plop,
126 Scoop,
128 Staccatissimo,
130 Stopped,
132 Stress,
134 StringIndication,
136 StringThumbPosition,
138 StrongAccent,
140 TonguingIndication,
142 UpBow,
144 WoodwindIndication,
146 DoubleTongue,
148 FrettedPluck,
150 NailPizzicato,
152 SnapPizzicato,
154 StringHarmonic,
156 TripleTongue,
158 Spiccato,
160 StringFingering,
162}
163
164const KINDS: [KindRow; 52] = [
167 KindRow {
168 kind: ArticulationKind::Articulation,
169 class: "Articulation",
170 parents: &[],
171 volume_shift: 0.0,
172 length_shift: 1.0,
173 tie_attach: "first",
174 fields: &[],
175 },
176 KindRow {
177 kind: ArticulationKind::Caesura,
178 class: "Caesura",
179 parents: &["Articulation"],
180 volume_shift: 0.0,
181 length_shift: 1.0,
182 tie_attach: "first",
183 fields: &[],
184 },
185 KindRow {
186 kind: ArticulationKind::DynamicArticulation,
187 class: "DynamicArticulation",
188 parents: &["Articulation"],
189 volume_shift: 0.0,
190 length_shift: 1.0,
191 tie_attach: "first",
192 fields: &[],
193 },
194 KindRow {
195 kind: ArticulationKind::LengthArticulation,
196 class: "LengthArticulation",
197 parents: &["Articulation"],
198 volume_shift: 0.0,
199 length_shift: 1.0,
200 tie_attach: "last",
201 fields: &[],
202 },
203 KindRow {
204 kind: ArticulationKind::PitchArticulation,
205 class: "PitchArticulation",
206 parents: &["Articulation"],
207 volume_shift: 0.0,
208 length_shift: 1.0,
209 tie_attach: "first",
210 fields: &[],
211 },
212 KindRow {
213 kind: ArticulationKind::TechnicalIndication,
214 class: "TechnicalIndication",
215 parents: &["Articulation"],
216 volume_shift: 0.0,
217 length_shift: 1.0,
218 tie_attach: "first",
219 fields: &[],
220 },
221 KindRow {
222 kind: ArticulationKind::TimbreArticulation,
223 class: "TimbreArticulation",
224 parents: &["Articulation"],
225 volume_shift: 0.0,
226 length_shift: 1.0,
227 tie_attach: "first",
228 fields: &[],
229 },
230 KindRow {
231 kind: ArticulationKind::Accent,
232 class: "Accent",
233 parents: &["DynamicArticulation", "Articulation"],
234 volume_shift: 0.1,
235 length_shift: 1.0,
236 tie_attach: "first",
237 fields: &[],
238 },
239 KindRow {
240 kind: ArticulationKind::Bowing,
241 class: "Bowing",
242 parents: &["TechnicalIndication", "Articulation"],
243 volume_shift: 0.0,
244 length_shift: 1.0,
245 tie_attach: "first",
246 fields: &[],
247 },
248 KindRow {
249 kind: ArticulationKind::BreathMark,
250 class: "BreathMark",
251 parents: &["LengthArticulation", "Articulation"],
252 volume_shift: 0.0,
253 length_shift: 0.7,
254 tie_attach: "last",
255 fields: &["symbol"],
256 },
257 KindRow {
258 kind: ArticulationKind::DetachedLegato,
259 class: "DetachedLegato",
260 parents: &["LengthArticulation", "Articulation"],
261 volume_shift: 0.0,
262 length_shift: 0.9,
263 tie_attach: "last",
264 fields: &[],
265 },
266 KindRow {
267 kind: ArticulationKind::Fingering,
268 class: "Fingering",
269 parents: &["TechnicalIndication", "Articulation"],
270 volume_shift: 0.0,
271 length_shift: 1.0,
272 tie_attach: "first",
273 fields: &["alternate", "fingerNumber", "substitution"],
274 },
275 KindRow {
276 kind: ArticulationKind::FretIndication,
277 class: "FretIndication",
278 parents: &["TechnicalIndication", "Articulation"],
279 volume_shift: 0.0,
280 length_shift: 1.0,
281 tie_attach: "first",
282 fields: &["number"],
283 },
284 KindRow {
285 kind: ArticulationKind::HandbellIndication,
286 class: "HandbellIndication",
287 parents: &["TechnicalIndication", "Articulation"],
288 volume_shift: 0.0,
289 length_shift: 1.0,
290 tie_attach: "first",
291 fields: &[],
292 },
293 KindRow {
294 kind: ArticulationKind::Harmonic,
295 class: "Harmonic",
296 parents: &["TechnicalIndication", "Articulation"],
297 volume_shift: 0.0,
298 length_shift: 1.0,
299 tie_attach: "first",
300 fields: &[],
301 },
302 KindRow {
303 kind: ArticulationKind::HarpIndication,
304 class: "HarpIndication",
305 parents: &["TechnicalIndication", "Articulation"],
306 volume_shift: 0.0,
307 length_shift: 1.0,
308 tie_attach: "first",
309 fields: &[],
310 },
311 KindRow {
312 kind: ArticulationKind::IndeterminateSlide,
313 class: "IndeterminateSlide",
314 parents: &["PitchArticulation", "Articulation"],
315 volume_shift: 0.0,
316 length_shift: 1.0,
317 tie_attach: "first",
318 fields: &[],
319 },
320 KindRow {
321 kind: ArticulationKind::OrganIndication,
322 class: "OrganIndication",
323 parents: &["TechnicalIndication", "Articulation"],
324 volume_shift: 0.0,
325 length_shift: 1.0,
326 tie_attach: "first",
327 fields: &["substitution"],
328 },
329 KindRow {
330 kind: ArticulationKind::Staccato,
331 class: "Staccato",
332 parents: &["LengthArticulation", "Articulation"],
333 volume_shift: 0.05,
334 length_shift: 0.7,
335 tie_attach: "last",
336 fields: &[],
337 },
338 KindRow {
339 kind: ArticulationKind::Tenuto,
340 class: "Tenuto",
341 parents: &["LengthArticulation", "Articulation"],
342 volume_shift: -0.05,
343 length_shift: 1.1,
344 tie_attach: "last",
345 fields: &[],
346 },
347 KindRow {
348 kind: ArticulationKind::Unstress,
349 class: "Unstress",
350 parents: &["DynamicArticulation", "Articulation"],
351 volume_shift: -0.05,
352 length_shift: 1.0,
353 tie_attach: "first",
354 fields: &[],
355 },
356 KindRow {
357 kind: ArticulationKind::WindIndication,
358 class: "WindIndication",
359 parents: &["TechnicalIndication", "Articulation"],
360 volume_shift: 0.0,
361 length_shift: 1.0,
362 tie_attach: "first",
363 fields: &[],
364 },
365 KindRow {
366 kind: ArticulationKind::BrassIndication,
367 class: "BrassIndication",
368 parents: &["WindIndication", "TechnicalIndication", "Articulation"],
369 volume_shift: 0.0,
370 length_shift: 1.0,
371 tie_attach: "first",
372 fields: &[],
373 },
374 KindRow {
375 kind: ArticulationKind::Doit,
376 class: "Doit",
377 parents: &["IndeterminateSlide", "PitchArticulation", "Articulation"],
378 volume_shift: 0.0,
379 length_shift: 1.0,
380 tie_attach: "last",
381 fields: &[],
382 },
383 KindRow {
384 kind: ArticulationKind::DownBow,
385 class: "DownBow",
386 parents: &["Bowing", "TechnicalIndication", "Articulation"],
387 volume_shift: 0.0,
388 length_shift: 1.0,
389 tie_attach: "first",
390 fields: &[],
391 },
392 KindRow {
393 kind: ArticulationKind::Falloff,
394 class: "Falloff",
395 parents: &["IndeterminateSlide", "PitchArticulation", "Articulation"],
396 volume_shift: 0.0,
397 length_shift: 1.0,
398 tie_attach: "last",
399 fields: &[],
400 },
401 KindRow {
402 kind: ArticulationKind::FretBend,
403 class: "FretBend",
404 parents: &["FretIndication", "TechnicalIndication", "Articulation"],
405 volume_shift: 0.0,
406 length_shift: 1.0,
407 tie_attach: "first",
408 fields: &["bendAlter", "number", "preBend", "release", "withBar"],
409 },
410 KindRow {
411 kind: ArticulationKind::FretTap,
412 class: "FretTap",
413 parents: &["FretIndication", "TechnicalIndication", "Articulation"],
414 volume_shift: 0.0,
415 length_shift: 1.0,
416 tie_attach: "first",
417 fields: &["number"],
418 },
419 KindRow {
420 kind: ArticulationKind::HarpFingerNails,
421 class: "HarpFingerNails",
422 parents: &["HarpIndication", "TechnicalIndication", "Articulation"],
423 volume_shift: 0.0,
424 length_shift: 1.0,
425 tie_attach: "first",
426 fields: &[],
427 },
428 KindRow {
429 kind: ArticulationKind::OpenString,
430 class: "OpenString",
431 parents: &["Bowing", "TechnicalIndication", "Articulation"],
432 volume_shift: 0.0,
433 length_shift: 1.0,
434 tie_attach: "first",
435 fields: &[],
436 },
437 KindRow {
438 kind: ArticulationKind::OrganHeel,
439 class: "OrganHeel",
440 parents: &["OrganIndication", "TechnicalIndication", "Articulation"],
441 volume_shift: 0.0,
442 length_shift: 1.0,
443 tie_attach: "first",
444 fields: &["substitution"],
445 },
446 KindRow {
447 kind: ArticulationKind::OrganToe,
448 class: "OrganToe",
449 parents: &["OrganIndication", "TechnicalIndication", "Articulation"],
450 volume_shift: 0.0,
451 length_shift: 1.0,
452 tie_attach: "first",
453 fields: &["substitution"],
454 },
455 KindRow {
456 kind: ArticulationKind::Pizzicato,
457 class: "Pizzicato",
458 parents: &["Bowing", "TechnicalIndication", "Articulation"],
459 volume_shift: 0.0,
460 length_shift: 1.0,
461 tie_attach: "first",
462 fields: &[],
463 },
464 KindRow {
465 kind: ArticulationKind::Plop,
466 class: "Plop",
467 parents: &["IndeterminateSlide", "PitchArticulation", "Articulation"],
468 volume_shift: 0.0,
469 length_shift: 1.0,
470 tie_attach: "first",
471 fields: &[],
472 },
473 KindRow {
474 kind: ArticulationKind::Scoop,
475 class: "Scoop",
476 parents: &["IndeterminateSlide", "PitchArticulation", "Articulation"],
477 volume_shift: 0.0,
478 length_shift: 1.0,
479 tie_attach: "first",
480 fields: &[],
481 },
482 KindRow {
483 kind: ArticulationKind::Staccatissimo,
484 class: "Staccatissimo",
485 parents: &["Staccato", "LengthArticulation", "Articulation"],
486 volume_shift: 0.05,
487 length_shift: 0.5,
488 tie_attach: "last",
489 fields: &[],
490 },
491 KindRow {
492 kind: ArticulationKind::Stopped,
493 class: "Stopped",
494 parents: &["WindIndication", "TechnicalIndication", "Articulation"],
495 volume_shift: 0.0,
496 length_shift: 1.0,
497 tie_attach: "first",
498 fields: &[],
499 },
500 KindRow {
501 kind: ArticulationKind::Stress,
502 class: "Stress",
503 parents: &["DynamicArticulation", "LengthArticulation", "Articulation"],
504 volume_shift: 0.05,
505 length_shift: 1.1,
506 tie_attach: "last",
507 fields: &[],
508 },
509 KindRow {
510 kind: ArticulationKind::StringIndication,
511 class: "StringIndication",
512 parents: &["Bowing", "TechnicalIndication", "Articulation"],
513 volume_shift: 0.0,
514 length_shift: 1.0,
515 tie_attach: "first",
516 fields: &["number"],
517 },
518 KindRow {
519 kind: ArticulationKind::StringThumbPosition,
520 class: "StringThumbPosition",
521 parents: &["Bowing", "TechnicalIndication", "Articulation"],
522 volume_shift: 0.0,
523 length_shift: 1.0,
524 tie_attach: "first",
525 fields: &[],
526 },
527 KindRow {
528 kind: ArticulationKind::StrongAccent,
529 class: "StrongAccent",
530 parents: &["Accent", "DynamicArticulation", "Articulation"],
531 volume_shift: 0.15,
532 length_shift: 1.0,
533 tie_attach: "first",
534 fields: &["pointDirection"],
535 },
536 KindRow {
537 kind: ArticulationKind::TonguingIndication,
538 class: "TonguingIndication",
539 parents: &["WindIndication", "TechnicalIndication", "Articulation"],
540 volume_shift: 0.0,
541 length_shift: 1.0,
542 tie_attach: "first",
543 fields: &[],
544 },
545 KindRow {
546 kind: ArticulationKind::UpBow,
547 class: "UpBow",
548 parents: &["Bowing", "TechnicalIndication", "Articulation"],
549 volume_shift: 0.0,
550 length_shift: 1.0,
551 tie_attach: "first",
552 fields: &[],
553 },
554 KindRow {
555 kind: ArticulationKind::WoodwindIndication,
556 class: "WoodwindIndication",
557 parents: &["WindIndication", "TechnicalIndication", "Articulation"],
558 volume_shift: 0.0,
559 length_shift: 1.0,
560 tie_attach: "first",
561 fields: &[],
562 },
563 KindRow {
564 kind: ArticulationKind::DoubleTongue,
565 class: "DoubleTongue",
566 parents: &[
567 "TonguingIndication",
568 "WindIndication",
569 "TechnicalIndication",
570 "Articulation",
571 ],
572 volume_shift: 0.0,
573 length_shift: 1.0,
574 tie_attach: "first",
575 fields: &[],
576 },
577 KindRow {
578 kind: ArticulationKind::FrettedPluck,
579 class: "FrettedPluck",
580 parents: &[
581 "FretIndication",
582 "Fingering",
583 "TechnicalIndication",
584 "Articulation",
585 ],
586 volume_shift: 0.0,
587 length_shift: 1.0,
588 tie_attach: "first",
589 fields: &["alternate", "fingerNumber", "number", "substitution"],
590 },
591 KindRow {
592 kind: ArticulationKind::NailPizzicato,
593 class: "NailPizzicato",
594 parents: &["Pizzicato", "Bowing", "TechnicalIndication", "Articulation"],
595 volume_shift: 0.0,
596 length_shift: 1.0,
597 tie_attach: "first",
598 fields: &[],
599 },
600 KindRow {
601 kind: ArticulationKind::SnapPizzicato,
602 class: "SnapPizzicato",
603 parents: &["Pizzicato", "Bowing", "TechnicalIndication", "Articulation"],
604 volume_shift: 0.0,
605 length_shift: 1.0,
606 tie_attach: "first",
607 fields: &[],
608 },
609 KindRow {
610 kind: ArticulationKind::StringHarmonic,
611 class: "StringHarmonic",
612 parents: &["Bowing", "Harmonic", "TechnicalIndication", "Articulation"],
613 volume_shift: 0.0,
614 length_shift: 1.0,
615 tie_attach: "first",
616 fields: &["harmonicType", "pitchType"],
617 },
618 KindRow {
619 kind: ArticulationKind::TripleTongue,
620 class: "TripleTongue",
621 parents: &[
622 "TonguingIndication",
623 "WindIndication",
624 "TechnicalIndication",
625 "Articulation",
626 ],
627 volume_shift: 0.0,
628 length_shift: 1.0,
629 tie_attach: "first",
630 fields: &[],
631 },
632 KindRow {
633 kind: ArticulationKind::Spiccato,
634 class: "Spiccato",
635 parents: &[
636 "Staccato",
637 "LengthArticulation",
638 "Accent",
639 "DynamicArticulation",
640 "Articulation",
641 ],
642 volume_shift: 0.1,
643 length_shift: 0.7,
644 tie_attach: "first",
645 fields: &[],
646 },
647 KindRow {
648 kind: ArticulationKind::StringFingering,
649 class: "StringFingering",
650 parents: &[
651 "StringIndication",
652 "Bowing",
653 "Fingering",
654 "TechnicalIndication",
655 "Articulation",
656 ],
657 volume_shift: 0.0,
658 length_shift: 1.0,
659 tie_attach: "first",
660 fields: &["alternate", "fingerNumber", "number", "substitution"],
661 },
662];
663
664impl ArticulationKind {
665 pub const ALL: [ArticulationKind; 52] = [
667 ArticulationKind::Articulation,
668 ArticulationKind::Caesura,
669 ArticulationKind::DynamicArticulation,
670 ArticulationKind::LengthArticulation,
671 ArticulationKind::PitchArticulation,
672 ArticulationKind::TechnicalIndication,
673 ArticulationKind::TimbreArticulation,
674 ArticulationKind::Accent,
675 ArticulationKind::Bowing,
676 ArticulationKind::BreathMark,
677 ArticulationKind::DetachedLegato,
678 ArticulationKind::Fingering,
679 ArticulationKind::FretIndication,
680 ArticulationKind::HandbellIndication,
681 ArticulationKind::Harmonic,
682 ArticulationKind::HarpIndication,
683 ArticulationKind::IndeterminateSlide,
684 ArticulationKind::OrganIndication,
685 ArticulationKind::Staccato,
686 ArticulationKind::Tenuto,
687 ArticulationKind::Unstress,
688 ArticulationKind::WindIndication,
689 ArticulationKind::BrassIndication,
690 ArticulationKind::Doit,
691 ArticulationKind::DownBow,
692 ArticulationKind::Falloff,
693 ArticulationKind::FretBend,
694 ArticulationKind::FretTap,
695 ArticulationKind::HarpFingerNails,
696 ArticulationKind::OpenString,
697 ArticulationKind::OrganHeel,
698 ArticulationKind::OrganToe,
699 ArticulationKind::Pizzicato,
700 ArticulationKind::Plop,
701 ArticulationKind::Scoop,
702 ArticulationKind::Staccatissimo,
703 ArticulationKind::Stopped,
704 ArticulationKind::Stress,
705 ArticulationKind::StringIndication,
706 ArticulationKind::StringThumbPosition,
707 ArticulationKind::StrongAccent,
708 ArticulationKind::TonguingIndication,
709 ArticulationKind::UpBow,
710 ArticulationKind::WoodwindIndication,
711 ArticulationKind::DoubleTongue,
712 ArticulationKind::FrettedPluck,
713 ArticulationKind::NailPizzicato,
714 ArticulationKind::SnapPizzicato,
715 ArticulationKind::StringHarmonic,
716 ArticulationKind::TripleTongue,
717 ArticulationKind::Spiccato,
718 ArticulationKind::StringFingering,
719 ];
720}
721
722impl ArticulationKind {
723 fn row(self) -> &'static KindRow {
724 KINDS
725 .iter()
726 .find(|row| row.kind == self)
727 .expect("every kind has a row")
728 }
729
730 pub fn class_name(self) -> &'static str {
732 self.row().class
733 }
734
735 pub fn from_class_name(class: &str) -> Option<Self> {
737 KINDS
738 .iter()
739 .find(|row| row.class == class)
740 .map(|row| row.kind)
741 }
742
743 pub fn parents(self) -> &'static [&'static str] {
746 self.row().parents
747 }
748
749 pub fn has_field(self, field: &str) -> bool {
752 self.row().fields.contains(&field)
753 }
754}
755
756#[derive(Clone, Debug)]
770#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
771#[must_use]
772pub struct Articulation {
773 kind: ArticulationKind,
774 placement: Option<String>,
775 volume_shift: FloatType,
776 length_shift: FloatType,
777 tie_attach: String,
778 display_text: Option<String>,
779 finger: Option<Finger>,
780 substitution: bool,
781 alternate: bool,
782 number: IntegerType,
783 point_direction: Option<String>,
784 symbol: Option<String>,
785 harmonic_type: Option<String>,
786 pitch_type: Option<String>,
787 bend_alter: Option<ChromaticInterval>,
788 pre_bend: bool,
789 release: Option<FloatType>,
790 with_bar: Option<String>,
791}
792
793impl PartialEq for Articulation {
794 fn eq(&self, other: &Self) -> bool {
795 self.kind == other.kind
796 }
797}
798
799impl Default for Articulation {
800 fn default() -> Self {
802 Self::of_kind(ArticulationKind::Articulation)
803 }
804}
805
806impl Articulation {
807 pub fn of_kind(kind: ArticulationKind) -> Self {
809 let row = kind.row();
810 Self {
811 kind,
812 placement: None,
813 volume_shift: row.volume_shift,
814 length_shift: row.length_shift,
815 tie_attach: row.tie_attach.to_string(),
816 display_text: None,
817 finger: None,
818 substitution: false,
819 alternate: false,
820 number: 0,
821 point_direction: kind.has_field("pointDirection").then(|| "up".to_string()),
822 symbol: None,
823 harmonic_type: kind
824 .has_field("harmonicType")
825 .then(|| "natural".to_string()),
826 pitch_type: None,
827 bend_alter: None,
828 pre_bend: false,
829 release: None,
830 with_bar: None,
831 }
832 }
833
834 pub fn kind(&self) -> ArticulationKind {
836 self.kind
837 }
838
839 pub fn is_a(&self, class: &str) -> bool {
842 self.kind.class_name() == class || self.kind.parents().contains(&class)
843 }
844
845 pub fn name(&self) -> String {
848 camel_case_to_hyphen(self.kind.class_name(), ' ')
849 }
850
851 pub fn placement(&self) -> Option<&str> {
853 self.placement.as_deref()
854 }
855
856 pub fn set_placement(&mut self, placement: Option<String>) {
858 self.placement = placement;
859 }
860
861 pub fn volume_shift(&self) -> FloatType {
865 self.volume_shift
866 }
867
868 pub fn set_volume_shift(&mut self, shift: FloatType) {
870 self.volume_shift = shift.clamp(-1.0, 1.0);
871 }
872
873 pub fn length_shift(&self) -> FloatType {
876 self.length_shift
877 }
878
879 pub fn set_length_shift(&mut self, shift: FloatType) {
881 self.length_shift = shift;
882 }
883
884 pub fn tie_attach(&self) -> &str {
887 &self.tie_attach
888 }
889
890 pub fn set_tie_attach(&mut self, attach: impl Into<String>) {
892 self.tie_attach = attach.into();
893 }
894
895 pub fn display_text(&self) -> Option<&str> {
897 self.display_text.as_deref()
898 }
899
900 pub fn set_display_text(&mut self, text: Option<String>) {
902 self.display_text = text;
903 }
904
905 pub fn finger(&self) -> Option<&Finger> {
907 self.finger.as_ref()
908 }
909
910 pub fn set_finger(&mut self, finger: Option<Finger>) {
912 self.finger = finger;
913 }
914
915 pub fn substitution(&self) -> bool {
917 self.substitution
918 }
919
920 pub fn set_substitution(&mut self, substitution: bool) {
922 self.substitution = substitution;
923 }
924
925 pub fn alternate(&self) -> bool {
927 self.alternate
928 }
929
930 pub fn set_alternate(&mut self, alternate: bool) {
932 self.alternate = alternate;
933 }
934
935 pub fn number(&self) -> IntegerType {
938 self.number
939 }
940
941 pub fn set_number(&mut self, number: IntegerType) {
943 self.number = number;
944 }
945
946 pub fn point_direction(&self) -> Option<&str> {
948 self.point_direction.as_deref()
949 }
950
951 pub fn set_point_direction(&mut self, direction: Option<String>) {
953 self.point_direction = direction;
954 }
955
956 pub fn symbol(&self) -> Option<&str> {
958 self.symbol.as_deref()
959 }
960
961 pub fn set_symbol(&mut self, symbol: Option<String>) {
963 self.symbol = symbol;
964 }
965
966 pub fn harmonic_type(&self) -> Option<&str> {
968 self.harmonic_type.as_deref()
969 }
970
971 pub fn set_harmonic_type(&mut self, harmonic_type: Option<String>) {
973 self.harmonic_type = harmonic_type;
974 }
975
976 pub fn pitch_type(&self) -> Option<&str> {
978 self.pitch_type.as_deref()
979 }
980
981 pub fn set_pitch_type(&mut self, pitch_type: Option<String>) {
983 self.pitch_type = pitch_type;
984 }
985
986 pub fn bend_alter(&self) -> Option<&ChromaticInterval> {
988 self.bend_alter.as_ref()
989 }
990
991 pub fn set_bend_alter(&mut self, alter: Option<ChromaticInterval>) {
993 self.bend_alter = alter;
994 }
995
996 pub fn pre_bend(&self) -> bool {
998 self.pre_bend
999 }
1000
1001 pub fn set_pre_bend(&mut self, pre_bend: bool) {
1003 self.pre_bend = pre_bend;
1004 }
1005
1006 pub fn release(&self) -> Option<FloatType> {
1009 self.release
1010 }
1011
1012 pub fn set_release(&mut self, release: Option<FloatType>) {
1014 self.release = release;
1015 }
1016
1017 pub fn with_bar(&self) -> Option<&str> {
1019 self.with_bar.as_deref()
1020 }
1021
1022 pub fn set_with_bar(&mut self, with_bar: Option<String>) {
1024 self.with_bar = with_bar;
1025 }
1026}
1027
1028#[cfg(test)]
1029mod tests {
1030 use super::*;
1031
1032 #[test]
1034 fn an_articulation_answers_what_music21_s_answers() {
1035 let staccato = Articulation::of_kind(ArticulationKind::Staccato);
1036 assert_eq!(staccato.name(), "staccato");
1037 assert_eq!(staccato.length_shift(), 0.7);
1038 assert_eq!(staccato.tie_attach(), "last");
1039 assert_eq!(
1040 Articulation::of_kind(ArticulationKind::SnapPizzicato).name(),
1041 "snap pizzicato"
1042 );
1043
1044 let mut first = Articulation::of_kind(ArticulationKind::StrongAccent);
1045 let mut second = Articulation::of_kind(ArticulationKind::StrongAccent);
1046 first.set_placement(Some("above".to_string()));
1047 second.set_placement(Some("below".to_string()));
1048 assert_eq!(first, second);
1049 assert_ne!(first, Articulation::of_kind(ArticulationKind::Accent));
1050 assert_eq!(first.point_direction(), Some("up"));
1051
1052 let spiccato = Articulation::of_kind(ArticulationKind::Spiccato);
1053 assert!(spiccato.is_a("Staccato") && spiccato.is_a("Accent"));
1054 assert_eq!(
1055 (spiccato.volume_shift(), spiccato.length_shift()),
1056 (0.1, 0.7)
1057 );
1058
1059 let mut accent = Articulation::of_kind(ArticulationKind::Accent);
1060 accent.set_volume_shift(3.0);
1061 assert_eq!(accent.volume_shift(), 1.0);
1062 accent.set_volume_shift(-3.0);
1063 assert_eq!(accent.volume_shift(), -1.0);
1064
1065 assert!(ArticulationKind::FrettedPluck.has_field("fingerNumber"));
1066 assert!(ArticulationKind::FrettedPluck.has_field("number"));
1067 assert!(!ArticulationKind::Accent.has_field("number"));
1068 assert_eq!(
1069 Articulation::of_kind(ArticulationKind::StringHarmonic).harmonic_type(),
1070 Some("natural")
1071 );
1072 }
1073}