diff --git a/src/animation/animationRules.cpp b/src/animation/animationRules.cpp index 54899a7..0ec2091 100644 --- a/src/animation/animationRules.cpp +++ b/src/animation/animationRules.cpp @@ -17,12 +17,12 @@ constexpr Shape X = Shape::X; Timeline animatePhone(optional phone, centiseconds duration, centiseconds previousDuration) { // Returns a timeline with a single shape set - auto single = [&](ShapeSet value) { + auto single = [duration](ShapeSet value) { return Timeline { { 0_cs, duration, value } }; }; // Returns a timeline with two shape sets, timed as a diphthong - auto diphthong = [&](ShapeSet first, ShapeSet second) { + auto diphthong = [duration](ShapeSet first, ShapeSet second) { centiseconds firstDuration = duration_cast(duration * 0.6); return Timeline { { 0_cs, firstDuration, first }, @@ -31,17 +31,27 @@ Timeline animatePhone(optional phone, centiseconds duration, ce }; // Returns a timeline with two shape sets, timed as a plosive - auto plosive = [&](ShapeSet first, ShapeSet second) { + auto plosive = [duration, previousDuration](ShapeSet first, ShapeSet second) { + centiseconds minOcclusionDuration = 4_cs; centiseconds maxOcclusionDuration = 12_cs; - centiseconds leftOverlap = clamp(previousDuration / 2, 4_cs, maxOcclusionDuration); - centiseconds rightOverlap = min(duration, maxOcclusionDuration - leftOverlap); + centiseconds occlusionDuration = clamp(previousDuration / 2, minOcclusionDuration, maxOcclusionDuration); return Timeline { - { -leftOverlap, rightOverlap, first }, - { rightOverlap, duration, second } + { -occlusionDuration, 0_cs, first }, + { 0_cs, duration, second } }; }; - if (!phone) return single({ X }); + // Returns the result of `animatePhone` when called with identical arguments + // except for a different phone. + auto like = [duration, previousDuration](optional referencePhone) { + return animatePhone(referencePhone, duration, previousDuration); + }; + + static const ShapeSet any = { A, B, C, D, E, F, G, H, X }; + + if (!phone) { + return single({ X }); + } switch (*phone) { case Phone::AO: return single({ E }); @@ -50,23 +60,23 @@ Timeline animatePhone(optional phone, centiseconds duration, ce case Phone::UW: return single({ F }); case Phone::EH: return duration < 20_cs ? single({ C }) : single({ D }); case Phone::IH: return single({ B }); - case Phone::UH: return single({ E }); + case Phone::UH: return single({ F }); case Phone::AH: return single({ C }); case Phone::Schwa: return single({ { B, C, D, E, F } }); - case Phone::AE: return single({ D }); - case Phone::EY: return duration < 20_cs ? diphthong({ C }, { B }) : diphthong({ D }, { B }); - case Phone::AY: return diphthong({ D }, { B }); - case Phone::OW: return diphthong({ E }, { F }); - case Phone::AW: return diphthong({ D }, { F }); + case Phone::AE: return single({ C }); + case Phone::EY: return diphthong({ C }, { B }); + case Phone::AY: return duration < 20_cs ? diphthong({ C }, { B }) : diphthong({ D }, { B }); + case Phone::OW: return single({ F }); + case Phone::AW: return duration < 20_cs ? diphthong({ C }, { F }) : diphthong({ D }, { F }); case Phone::OY: return diphthong({ F }, { B }); - case Phone::ER: return duration < 7_cs ? single({ B }) : single({ E }); + case Phone::ER: return duration < 7_cs ? like(Phone::Schwa) : single({ F }); case Phone::P: - case Phone::B: return plosive({ A }, { A, B, C, D, E, F, G, H, X }); + case Phone::B: return plosive({ A }, any); case Phone::T: - case Phone::D: - case Phone::K: return single({ B, F }); - case Phone::G: return single({ B, C, E, F }); + case Phone::D: return plosive({ B, C, F, G, H }, any); + case Phone::K: + case Phone::G: return plosive({ B, C, E, F, G, H }, any); case Phone::CH: case Phone::JH: return single({ B, F }); case Phone::F: @@ -77,13 +87,13 @@ Timeline animatePhone(optional phone, centiseconds duration, ce case Phone::Z: case Phone::SH: case Phone::ZH: return single({ B, F }); - case Phone::HH: return single({ B, C, D, E, F }); + case Phone::HH: return single(any); case Phone::M: return single({ A }); - case Phone::N: return single({ B, C, F }); - case Phone::NG: return single({ B, C, D, E, F }); - case Phone::L: return single({ E, F, H }); - case Phone::R: return single({ B, F }); - case Phone::Y: return single({ B }); + case Phone::N: return single({ B, C, F, G, H }); + case Phone::NG: return single({ B, C, E, F, G }); + case Phone::L: return duration < 20_cs ? single({ B, C, D, E, F, G, H }) : single({ H }); + case Phone::R: return single({ B, C, E, F }); + case Phone::Y: return single({ B, C, F }); case Phone::W: return single({ F }); case Phone::Breath: diff --git a/src/animation/animationRules.h b/src/animation/animationRules.h index f6a9a2e..e21bb74 100644 --- a/src/animation/animationRules.h +++ b/src/animation/animationRules.h @@ -6,6 +6,7 @@ #include "Timeline.h" #include "Phone.h" +// A set of mouth shapes that can be used to represent a certain sound using ShapeSet = std::set; Timeline animatePhone(boost::optional phone, centiseconds duration, centiseconds previousDuration);