Renamed many symbols named "shapes" to "animation" to make the intent clearer

This commit is contained in:
Daniel Wolf 2016-12-29 15:17:45 +01:00
parent 876fa024ad
commit b02f37e961
20 changed files with 45 additions and 45 deletions

View File

@ -28,10 +28,10 @@ Shape getPauseShape(Shape previous, Shape next, centiseconds duration) {
return Shape::X; return Shape::X;
} }
JoiningContinuousTimeline<Shape> animatePauses(const JoiningContinuousTimeline<Shape>& shapes) { JoiningContinuousTimeline<Shape> animatePauses(const JoiningContinuousTimeline<Shape>& animation) {
JoiningContinuousTimeline<Shape> result(shapes); JoiningContinuousTimeline<Shape> result(animation);
for_each_adjacent(shapes.begin(), shapes.end(), [&](const Timed<Shape>& previous, const Timed<Shape>& pause, const Timed<Shape>& next) { for_each_adjacent(animation.begin(), animation.end(), [&](const Timed<Shape>& previous, const Timed<Shape>& pause, const Timed<Shape>& next) {
if (pause.getValue() != Shape::X) return; if (pause.getValue() != Shape::X) return;
result.set(pause.getTimeRange(), getPauseShape(previous.getValue(), next.getValue(), pause.getDuration())); result.set(pause.getTimeRange(), getPauseShape(previous.getValue(), next.getValue(), pause.getDuration()));

View File

@ -4,4 +4,4 @@
#include "ContinuousTimeline.h" #include "ContinuousTimeline.h"
// Takes an existing animation and modifies the pauses (X shapes) to look better. // Takes an existing animation and modifies the pauses (X shapes) to look better.
JoiningContinuousTimeline<Shape> animatePauses(const JoiningContinuousTimeline<Shape>& shapes); JoiningContinuousTimeline<Shape> animatePauses(const JoiningContinuousTimeline<Shape>& animation);

View File

@ -12,7 +12,7 @@ using boost::optional;
// * When speaking, we anticipate vowels, trying to form their shape before the actual vowel. // * When speaking, we anticipate vowels, trying to form their shape before the actual vowel.
// So whenever we come across a one-shape vowel, we backtrack a little, spreating that shape to the left. // So whenever we come across a one-shape vowel, we backtrack a little, spreating that shape to the left.
JoiningContinuousTimeline<Shape> animateRough(const ContinuousTimeline<ShapeRule>& shapeRules) { JoiningContinuousTimeline<Shape> animateRough(const ContinuousTimeline<ShapeRule>& shapeRules) {
JoiningContinuousTimeline<Shape> shapes(shapeRules.getRange(), Shape::X); JoiningContinuousTimeline<Shape> animation(shapeRules.getRange(), Shape::X);
Shape referenceShape = Shape::X; Shape referenceShape = Shape::X;
// Animate forwards // Animate forwards
@ -21,7 +21,7 @@ JoiningContinuousTimeline<Shape> animateRough(const ContinuousTimeline<ShapeRule
const ShapeRule shapeRule = it->getValue(); const ShapeRule shapeRule = it->getValue();
const ShapeSet shapeSet = std::get<ShapeSet>(shapeRule); const ShapeSet shapeSet = std::get<ShapeSet>(shapeRule);
const Shape shape = getClosestShape(referenceShape, shapeSet); const Shape shape = getClosestShape(referenceShape, shapeSet);
shapes.set(it->getTimeRange(), shape); animation.set(it->getTimeRange(), shape);
const auto phone = std::get<optional<Phone>>(shapeRule); const auto phone = std::get<optional<Phone>>(shapeRule);
const bool anticipateShape = phone && isVowel(*phone) && shapeSet.size() == 1; const bool anticipateShape = phone && isVowel(*phone) && shapeSet.size() == 1;
if (anticipateShape) { if (anticipateShape) {
@ -41,7 +41,7 @@ JoiningContinuousTimeline<Shape> animateRough(const ContinuousTimeline<ShapeRule
// Overwrite forward-animated shape with backwards-animated, anticipating shape // Overwrite forward-animated shape with backwards-animated, anticipating shape
const Shape anticipatingShape = getClosestShape(referenceShape, std::get<ShapeSet>(reverseIt->getValue())); const Shape anticipatingShape = getClosestShape(referenceShape, std::get<ShapeSet>(reverseIt->getValue()));
shapes.set(reverseIt->getTimeRange(), anticipatingShape); animation.set(reverseIt->getTimeRange(), anticipatingShape);
// Make sure the new, backwards-animated shape still resembles the anticipated shape // Make sure the new, backwards-animated shape still resembles the anticipated shape
if (getBasicShape(anticipatingShape) != getBasicShape(anticipatedShape)) break; if (getBasicShape(anticipatingShape) != getBasicShape(anticipatedShape)) break;
@ -53,5 +53,5 @@ JoiningContinuousTimeline<Shape> animateRough(const ContinuousTimeline<ShapeRule
referenceShape = anticipateShape ? shape : relax(shape); referenceShape = anticipateShape ? shape : relax(shape);
} }
return shapes; return animation;
} }

View File

@ -29,9 +29,9 @@ ContinuousTimeline<ShapeRule> convertToTargetShapeSet(const ContinuousTimeline<S
return result; return result;
} }
JoiningContinuousTimeline<Shape> convertToTargetShapeSet(const JoiningContinuousTimeline<Shape>& shapes, const ShapeSet& targetShapeSet) { JoiningContinuousTimeline<Shape> convertToTargetShapeSet(const JoiningContinuousTimeline<Shape>& animation, const ShapeSet& targetShapeSet) {
JoiningContinuousTimeline<Shape> result(shapes); JoiningContinuousTimeline<Shape> result(animation);
for (const auto& timedShape : shapes) { for (const auto& timedShape : animation) {
result.set(timedShape.getTimeRange(), convertToTargetShapeSet(timedShape.getValue(), targetShapeSet)); result.set(timedShape.getTimeRange(), convertToTargetShapeSet(timedShape.getValue(), targetShapeSet));
} }
return result; return result;

View File

@ -12,5 +12,5 @@ ShapeSet convertToTargetShapeSet(const ShapeSet& shapes, const ShapeSet& targetS
// Replaces each shape in each rule with the closest shape that occurs in the target shape set. // Replaces each shape in each rule with the closest shape that occurs in the target shape set.
ContinuousTimeline<ShapeRule> convertToTargetShapeSet(const ContinuousTimeline<ShapeRule>& shapeRules, const ShapeSet& targetShapeSet); ContinuousTimeline<ShapeRule> convertToTargetShapeSet(const ContinuousTimeline<ShapeRule>& shapeRules, const ShapeSet& targetShapeSet);
// Replaces each shape in the specified timeline with the closest shape that occurs in the target shape set. // Replaces each shape in the specified animation with the closest shape that occurs in the target shape set.
JoiningContinuousTimeline<Shape> convertToTargetShapeSet(const JoiningContinuousTimeline<Shape>& shapes, const ShapeSet& targetShapeSet); JoiningContinuousTimeline<Shape> convertToTargetShapeSet(const JoiningContinuousTimeline<Shape>& animation, const ShapeSet& targetShapeSet);

View File

@ -85,8 +85,8 @@ JoiningContinuousTimeline<Shape> retime(const JoiningContinuousTimeline<Shape>&
return targetShapes; return targetShapes;
} }
JoiningContinuousTimeline<Shape> retime(const JoiningContinuousTimeline<Shape>& shapes, TimeRange sourceRange, TimeRange targetRange) { JoiningContinuousTimeline<Shape> retime(const JoiningContinuousTimeline<Shape>& animation, TimeRange sourceRange, TimeRange targetRange) {
const auto sourceShapes = JoiningContinuousTimeline<Shape>(sourceRange, Shape::X, shapes); const auto sourceShapes = JoiningContinuousTimeline<Shape>(sourceRange, Shape::X, animation);
return retime(sourceShapes, targetRange); return retime(sourceShapes, targetRange);
} }
@ -96,10 +96,10 @@ enum class MouthState {
Open Open
}; };
JoiningContinuousTimeline<Shape> optimizeTiming(const JoiningContinuousTimeline<Shape>& shapes) { JoiningContinuousTimeline<Shape> optimizeTiming(const JoiningContinuousTimeline<Shape>& animation) {
// Identify segments with idle, closed, and open mouth shapes // Identify segments with idle, closed, and open mouth shapes
JoiningContinuousTimeline<MouthState> segments(shapes.getRange(), MouthState::Idle); JoiningContinuousTimeline<MouthState> segments(animation.getRange(), MouthState::Idle);
for (const auto& timedShape : shapes) { for (const auto& timedShape : animation) {
const Shape shape = timedShape.getValue(); const Shape shape = timedShape.getValue();
const MouthState mouthState = shape == Shape::X ? MouthState::Idle : shape == Shape::A ? MouthState::Closed : MouthState::Open; const MouthState mouthState = shape == Shape::X ? MouthState::Idle : shape == Shape::A ? MouthState::Closed : MouthState::Open;
segments.set(timedShape.getTimeRange(), mouthState); segments.set(timedShape.getTimeRange(), mouthState);
@ -112,7 +112,7 @@ JoiningContinuousTimeline<Shape> optimizeTiming(const JoiningContinuousTimeline<
// Make sure all open and closed segments are long enough to register visually. // Make sure all open and closed segments are long enough to register visually.
// We don't care about idle shapes at this point. // We don't care about idle shapes at this point.
JoiningContinuousTimeline<Shape> result(shapes.getRange(), Shape::X); JoiningContinuousTimeline<Shape> result(animation.getRange(), Shape::X);
// ... we're filling the result timeline from right to left, so `resultStart` points to the earliest shape already written // ... we're filling the result timeline from right to left, so `resultStart` points to the earliest shape already written
centiseconds resultStart = result.getRange().getEnd(); centiseconds resultStart = result.getRange().getEnd();
for (auto segmentIt = segments.rbegin(); segmentIt != segments.rend(); ++segmentIt) { for (auto segmentIt = segments.rbegin(); segmentIt != segments.rend(); ++segmentIt) {
@ -122,7 +122,7 @@ JoiningContinuousTimeline<Shape> optimizeTiming(const JoiningContinuousTimeline<
if (segmentTargetEnd - segmentIt->getStart() >= minSegmentDuration) { if (segmentTargetEnd - segmentIt->getStart() >= minSegmentDuration) {
// The segment is long enough; we don't have to extend it to the left. // The segment is long enough; we don't have to extend it to the left.
const TimeRange targetRange(segmentIt->getStart(), segmentTargetEnd); const TimeRange targetRange(segmentIt->getStart(), segmentTargetEnd);
const auto retimedSegment = retime(shapes, segmentIt->getTimeRange(), targetRange); const auto retimedSegment = retime(animation, segmentIt->getTimeRange(), targetRange);
for (const auto& timedShape : retimedSegment) { for (const auto& timedShape : retimedSegment) {
result.set(timedShape); result.set(timedShape);
} }
@ -148,7 +148,7 @@ JoiningContinuousTimeline<Shape> optimizeTiming(const JoiningContinuousTimeline<
size_t remainingShortSegmentCount = std::distance(shortSegmentIt, end); size_t remainingShortSegmentCount = std::distance(shortSegmentIt, end);
const centiseconds segmentDuration = (resultStart - shortSegmentsTargetStart) / remainingShortSegmentCount; const centiseconds segmentDuration = (resultStart - shortSegmentsTargetStart) / remainingShortSegmentCount;
const TimeRange segmentTargetRange(resultStart - segmentDuration, resultStart); const TimeRange segmentTargetRange(resultStart - segmentDuration, resultStart);
const auto retimedSegment = retime(shapes, shortSegmentIt->getTimeRange(), segmentTargetRange); const auto retimedSegment = retime(animation, shortSegmentIt->getTimeRange(), segmentTargetRange);
for (const auto& timedShape : retimedSegment) { for (const auto& timedShape : retimedSegment) {
result.set(timedShape); result.set(timedShape);
} }

View File

@ -5,4 +5,4 @@
// Changes the timing of an existing animation to reduce jitter and to make sure all shapes register visually. // Changes the timing of an existing animation to reduce jitter and to make sure all shapes register visually.
// In some cases, shapes may be omitted. // In some cases, shapes may be omitted.
JoiningContinuousTimeline<Shape> optimizeTiming(const JoiningContinuousTimeline<Shape>& shapes); JoiningContinuousTimeline<Shape> optimizeTiming(const JoiningContinuousTimeline<Shape>& animation);

View File

@ -1,14 +1,14 @@
#include "tweening.h" #include "tweening.h"
#include "animationRules.h" #include "animationRules.h"
JoiningContinuousTimeline<Shape> insertTweens(const JoiningContinuousTimeline<Shape>& shapes) { JoiningContinuousTimeline<Shape> insertTweens(const JoiningContinuousTimeline<Shape>& animation) {
centiseconds minTweenDuration = 4_cs; centiseconds minTweenDuration = 4_cs;
centiseconds maxTweenDuration = 8_cs; centiseconds maxTweenDuration = 8_cs;
JoiningContinuousTimeline<Shape> result(shapes); JoiningContinuousTimeline<Shape> result(animation);
for (auto first = shapes.begin(), second = std::next(shapes.begin()); for (auto first = animation.begin(), second = std::next(animation.begin());
first != shapes.end() && second != shapes.end(); first != animation.end() && second != animation.end();
++first, ++second) ++first, ++second)
{ {
auto pair = getTween(first->getValue(), second->getValue()); auto pair = getTween(first->getValue(), second->getValue());

View File

@ -4,4 +4,4 @@
#include "ContinuousTimeline.h" #include "ContinuousTimeline.h"
// Takes an existing animation and inserts inbetween shapes for smoother results. // Takes an existing animation and inserts inbetween shapes for smoother results.
JoiningContinuousTimeline<Shape> insertTweens(const JoiningContinuousTimeline<Shape>& shapes); JoiningContinuousTimeline<Shape> insertTweens(const JoiningContinuousTimeline<Shape>& animation);

View File

@ -3,7 +3,7 @@
#include "EnumConverter.h" #include "EnumConverter.h"
#include <set> #include <set>
// The classic Hanna-Barbera mouth shapes A-F phus the common supplements G-H // The classic Hanna-Barbera mouth shapes A-F plus the common supplements G-H
// For reference, see http://sunewatts.dk/lipsync/lipsync/article_02.php // For reference, see http://sunewatts.dk/lipsync/lipsync/article_02.php
// For visual examples, see https://flic.kr/s/aHsj86KR4J. Their shapes "BMP".."L" map to A..H. // For visual examples, see https://flic.kr/s/aHsj86KR4J. Their shapes "BMP".."L" map to A..H.
enum class Shape { enum class Shape {

View File

@ -7,5 +7,5 @@
class Exporter { class Exporter {
public: public:
virtual ~Exporter() {} virtual ~Exporter() {}
virtual void exportShapes(const boost::filesystem::path& inputFilePath, const JoiningContinuousTimeline<Shape>& shapes, const ShapeSet& targetShapeSet, std::ostream& outputStream) = 0; virtual void exportAnimation(const boost::filesystem::path& inputFilePath, const JoiningContinuousTimeline<Shape>& animation, const ShapeSet& targetShapeSet, std::ostream& outputStream) = 0;
}; };

View File

@ -25,17 +25,17 @@ string escapeJsonString(const string& s) {
return result; return result;
} }
void JsonExporter::exportShapes(const boost::filesystem::path& inputFilePath, const JoiningContinuousTimeline<Shape>& shapes, const ShapeSet& targetShapeSet, std::ostream& outputStream) { void JsonExporter::exportAnimation(const boost::filesystem::path& inputFilePath, const JoiningContinuousTimeline<Shape>& animation, const ShapeSet& targetShapeSet, std::ostream& outputStream) {
// Export as JSON. // Export as JSON.
// I'm not using a library because the code is short enough without one and it lets me control the formatting. // I'm not using a library because the code is short enough without one and it lets me control the formatting.
outputStream << "{\n"; outputStream << "{\n";
outputStream << " \"metadata\": {\n"; outputStream << " \"metadata\": {\n";
outputStream << " \"soundFile\": \"" << escapeJsonString(inputFilePath.string()) << "\",\n"; outputStream << " \"soundFile\": \"" << escapeJsonString(inputFilePath.string()) << "\",\n";
outputStream << " \"duration\": " << formatDuration(shapes.getRange().getDuration()) << "\n"; outputStream << " \"duration\": " << formatDuration(animation.getRange().getDuration()) << "\n";
outputStream << " },\n"; outputStream << " },\n";
outputStream << " \"mouthCues\": [\n"; outputStream << " \"mouthCues\": [\n";
bool isFirst = true; bool isFirst = true;
for (auto& timedShape : dummyShapeIfEmpty(shapes, targetShapeSet)) { for (auto& timedShape : dummyShapeIfEmpty(animation, targetShapeSet)) {
if (!isFirst) outputStream << ",\n"; if (!isFirst) outputStream << ",\n";
isFirst = false; isFirst = false;
outputStream << " { \"start\": " << formatDuration(timedShape.getStart()) outputStream << " { \"start\": " << formatDuration(timedShape.getStart())

View File

@ -4,5 +4,5 @@
class JsonExporter : public Exporter { class JsonExporter : public Exporter {
public: public:
void exportShapes(const boost::filesystem::path& inputFilePath, const JoiningContinuousTimeline<Shape>& shapes, const ShapeSet& targetShapeSet, std::ostream& outputStream) override; void exportAnimation(const boost::filesystem::path& inputFilePath, const JoiningContinuousTimeline<Shape>& animation, const ShapeSet& targetShapeSet, std::ostream& outputStream) override;
}; };

View File

@ -1,14 +1,14 @@
#include "TsvExporter.h" #include "TsvExporter.h"
#include "targetShapeSet.h" #include "targetShapeSet.h"
void TsvExporter::exportShapes(const boost::filesystem::path& inputFilePath, const JoiningContinuousTimeline<Shape>& shapes, const ShapeSet& targetShapeSet, std::ostream& outputStream) { void TsvExporter::exportAnimation(const boost::filesystem::path& inputFilePath, const JoiningContinuousTimeline<Shape>& animation, const ShapeSet& targetShapeSet, std::ostream& outputStream) {
UNUSED(inputFilePath); UNUSED(inputFilePath);
// Output shapes with start times // Output shapes with start times
for (auto& timedShape : shapes) { for (auto& timedShape : animation) {
outputStream << formatDuration(timedShape.getStart()) << "\t" << timedShape.getValue() << "\n"; outputStream << formatDuration(timedShape.getStart()) << "\t" << timedShape.getValue() << "\n";
} }
// Output closed mouth with end time // Output closed mouth with end time
outputStream << formatDuration(shapes.getRange().getEnd()) << "\t" << convertToTargetShapeSet(Shape::X, targetShapeSet) << "\n"; outputStream << formatDuration(animation.getRange().getEnd()) << "\t" << convertToTargetShapeSet(Shape::X, targetShapeSet) << "\n";
} }

View File

@ -4,6 +4,6 @@
class TsvExporter : public Exporter { class TsvExporter : public Exporter {
public: public:
void exportShapes(const boost::filesystem::path& inputFilePath, const JoiningContinuousTimeline<Shape>& shapes, const ShapeSet& targetShapeSet, std::ostream& outputStream) override; void exportAnimation(const boost::filesystem::path& inputFilePath, const JoiningContinuousTimeline<Shape>& animation, const ShapeSet& targetShapeSet, std::ostream& outputStream) override;
}; };

View File

@ -6,15 +6,15 @@
using std::string; using std::string;
using boost::property_tree::ptree; using boost::property_tree::ptree;
void XmlExporter::exportShapes(const boost::filesystem::path& inputFilePath, const JoiningContinuousTimeline<Shape>& shapes, const ShapeSet& targetShapeSet, std::ostream& outputStream) { void XmlExporter::exportAnimation(const boost::filesystem::path& inputFilePath, const JoiningContinuousTimeline<Shape>& animation, const ShapeSet& targetShapeSet, std::ostream& outputStream) {
ptree tree; ptree tree;
// Add metadata // Add metadata
tree.put("rhubarbResult.metadata.soundFile", inputFilePath.string()); tree.put("rhubarbResult.metadata.soundFile", inputFilePath.string());
tree.put("rhubarbResult.metadata.duration", formatDuration(shapes.getRange().getDuration())); tree.put("rhubarbResult.metadata.duration", formatDuration(animation.getRange().getDuration()));
// Add mouth cues // Add mouth cues
for (auto& timedShape : dummyShapeIfEmpty(shapes, targetShapeSet)) { for (auto& timedShape : dummyShapeIfEmpty(animation, targetShapeSet)) {
ptree& mouthCueElement = tree.add("rhubarbResult.mouthCues.mouthCue", timedShape.getValue()); ptree& mouthCueElement = tree.add("rhubarbResult.mouthCues.mouthCue", timedShape.getValue());
mouthCueElement.put("<xmlattr>.start", formatDuration(timedShape.getStart())); mouthCueElement.put("<xmlattr>.start", formatDuration(timedShape.getStart()));
mouthCueElement.put("<xmlattr>.end", formatDuration(timedShape.getEnd())); mouthCueElement.put("<xmlattr>.end", formatDuration(timedShape.getEnd()));

View File

@ -4,5 +4,5 @@
class XmlExporter : public Exporter { class XmlExporter : public Exporter {
public: public:
void exportShapes(const boost::filesystem::path& inputFilePath, const JoiningContinuousTimeline<Shape>& shapes, const ShapeSet& targetShapeSet, std::ostream& outputStream) override; void exportAnimation(const boost::filesystem::path& inputFilePath, const JoiningContinuousTimeline<Shape>& animation, const ShapeSet& targetShapeSet, std::ostream& outputStream) override;
}; };

View File

@ -2,9 +2,9 @@
#include "targetShapeSet.h" #include "targetShapeSet.h"
// Makes sure there is at least one mouth shape // Makes sure there is at least one mouth shape
std::vector<Timed<Shape>> dummyShapeIfEmpty(const JoiningTimeline<Shape>& shapes, const ShapeSet& targetShapeSet) { std::vector<Timed<Shape>> dummyShapeIfEmpty(const JoiningTimeline<Shape>& animation, const ShapeSet& targetShapeSet) {
std::vector<Timed<Shape>> result; std::vector<Timed<Shape>> result;
std::copy(shapes.begin(), shapes.end(), std::back_inserter(result)); std::copy(animation.begin(), animation.end(), std::back_inserter(result));
if (result.empty()) { if (result.empty()) {
// Add zero-length empty mouth // Add zero-length empty mouth
result.push_back(Timed<Shape>(0_cs, 0_cs, convertToTargetShapeSet(Shape::X, targetShapeSet))); result.push_back(Timed<Shape>(0_cs, 0_cs, convertToTargetShapeSet(Shape::X, targetShapeSet)));

View File

@ -4,4 +4,4 @@
#include "Timeline.h" #include "Timeline.h"
// Makes sure there is at least one mouth shape // Makes sure there is at least one mouth shape
std::vector<Timed<Shape>> dummyShapeIfEmpty(const JoiningTimeline<Shape>& shapes, const ShapeSet& targetShapeSet); std::vector<Timed<Shape>> dummyShapeIfEmpty(const JoiningTimeline<Shape>& animation, const ShapeSet& targetShapeSet);

View File

@ -163,7 +163,7 @@ int main(int argc, char *argv[]) {
// Export animation // Export animation
unique_ptr<Exporter> exporter = createExporter(exportFormat.getValue()); unique_ptr<Exporter> exporter = createExporter(exportFormat.getValue());
exporter->exportShapes(inputFilePath, animation, targetShapeSet, std::cout); exporter->exportAnimation(inputFilePath, animation, targetShapeSet, std::cout);
logging::info("Exiting application normally."); logging::info("Exiting application normally.");
} catch (...) { } catch (...) {