Skip to content

Commit

Permalink
Implement DAT exporter for Moho
Browse files Browse the repository at this point in the history
  • Loading branch information
DanielSWolf committed Jun 27, 2019
1 parent 6f0e3ef commit fef283d
Show file tree
Hide file tree
Showing 6 changed files with 123 additions and 2 deletions.
2 changes: 2 additions & 0 deletions rhubarb/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,8 @@ target_link_libraries(rhubarb-core

# ... rhubarb-exporters
add_library(rhubarb-exporters
src/exporters/DatExporter.cpp
src/exporters/DatExporter.h
src/exporters/Exporter.h
src/exporters/exporterTools.cpp
src/exporters/exporterTools.h
Expand Down
72 changes: 72 additions & 0 deletions rhubarb/src/exporters/DatExporter.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#include "DatExporter.h"
#include "animation/targetShapeSet.h"
#include <boost/lexical_cast.hpp>

using std::chrono::duration;
using std::chrono::duration_cast;
using std::string;

DatExporter::DatExporter(const ShapeSet& targetShapeSet, double frameRate, bool convertToPrestonBlair) :
frameRate(frameRate),
convertToPrestonBlair(convertToPrestonBlair),
prestonBlairShapeNames {
{ Shape::A, "MBP" },
{ Shape::B, "etc" },
{ Shape::C, "E" },
{ Shape::D, "AI" },
{ Shape::E, "O" },
{ Shape::F, "U" },
{ Shape::G, "FV" },
{ Shape::H, "L" },
{ Shape::X, "rest" },
}
{
// Animation works with a fixed frame rate of 100.
// Downsampling to much less than 25 fps may result in dropped frames.
// Upsampling to more than 100 fps doesn't make sense.
const double minFrameRate = 24.0;
const double maxFrameRate = 100.0;

if (frameRate < minFrameRate || frameRate > maxFrameRate) {
throw std::runtime_error(fmt::format("Frame rate must be between {} and {} fps.", minFrameRate, maxFrameRate));
}

if (convertToPrestonBlair) {
for (Shape shape : targetShapeSet) {
if (prestonBlairShapeNames.find(shape) == prestonBlairShapeNames.end()) {
throw std::runtime_error(fmt::format("Mouth shape {} cannot be converted to Preston Blair shape names."));
}
}
}
}

void DatExporter::exportAnimation(const ExporterInput& input, std::ostream& outputStream) {
outputStream << "MohoSwitch1" << "\n";

// Output shapes with start times
int lastFrameNumber = 0;
for (auto& timedShape : input.animation) {
const int frameNumber = toFrameNumber(timedShape.getStart());
if (frameNumber == lastFrameNumber) continue;

const string shapeName = toString(timedShape.getValue());
outputStream << frameNumber << " " << shapeName << "\n";
lastFrameNumber = frameNumber;
}

// Output closed mouth with end time
int frameNumber = toFrameNumber(input.animation.getRange().getEnd());
if (frameNumber == lastFrameNumber) ++frameNumber;
const string shapeName = toString(convertToTargetShapeSet(Shape::X, input.targetShapeSet));
outputStream << frameNumber << " " << shapeName << "\n";
}

string DatExporter::toString(Shape shape) const {
return convertToPrestonBlair
? prestonBlairShapeNames.at(shape)
: boost::lexical_cast<std::string>(shape);
}

int DatExporter::toFrameNumber(centiseconds time) const {
return 1 + static_cast<int>(frameRate * duration_cast<duration<double>>(time).count());
}
21 changes: 21 additions & 0 deletions rhubarb/src/exporters/DatExporter.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#pragma once

#include "Exporter.h"
#include "core/Shape.h"
#include <map>
#include <string>

// Exporter for Moho's switch data file format
class DatExporter : public Exporter {
public:
DatExporter(const ShapeSet& targetShapeSet, double frameRate, bool convertToPrestonBlair);
void exportAnimation(const ExporterInput& input, std::ostream& outputStream) override;

private:
int toFrameNumber(centiseconds time) const;
std::string toString(Shape shape) const;

double frameRate;
bool convertToPrestonBlair;
std::map<Shape, std::string> prestonBlairShapeNames;
};
1 change: 1 addition & 0 deletions rhubarb/src/rhubarb/ExportFormat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ string ExportFormatConverter::getTypeName() {

EnumConverter<ExportFormat>::member_data ExportFormatConverter::getMemberData() {
return member_data {
{ ExportFormat::Dat, "dat" },
{ ExportFormat::Tsv, "tsv" },
{ ExportFormat::Xml, "xml" },
{ ExportFormat::Json, "json" }
Expand Down
1 change: 1 addition & 0 deletions rhubarb/src/rhubarb/ExportFormat.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "tools/EnumConverter.h"

enum class ExportFormat {
Dat,
Tsv,
Xml,
Json
Expand Down
28 changes: 26 additions & 2 deletions rhubarb/src/rhubarb/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "tools/textFiles.h"
#include "lib/rhubarbLib.h"
#include "ExportFormat.h"
#include "exporters/DatExporter.h"
#include "exporters/TsvExporter.h"
#include "exporters/XmlExporter.h"
#include "exporters/JsonExporter.h"
Expand Down Expand Up @@ -82,8 +83,15 @@ unique_ptr<Recognizer> createRecognizer(RecognizerType recognizerType) {
}
}

unique_ptr<Exporter> createExporter(ExportFormat exportFormat) {
unique_ptr<Exporter> createExporter(
ExportFormat exportFormat,
const ShapeSet& targetShapeSet,
double datFrameRate,
bool datUsePrestonBlair
) {
switch (exportFormat) {
case ExportFormat::Dat:
return make_unique<DatExporter>(targetShapeSet, datFrameRate, datUsePrestonBlair);
case ExportFormat::Tsv:
return make_unique<TsvExporter>();
case ExportFormat::Xml:
Expand Down Expand Up @@ -172,6 +180,16 @@ int main(int platformArgc, char* platformArgv[]) {
false, string(), "string", cmd
);

tclap::SwitchArg datUsePrestonBlair(
"", "datUsePrestonBlair", "Only for dat exporter: uses the Preston Blair mouth shape names.",
cmd, false
);

tclap::ValueArg<double> datFrameRate(
"", "datFrameRate", "Only for dat exporter: the desired frame rate.",
false, 24.0, "number", cmd
);

auto exportFormats = vector<ExportFormat>(ExportFormatConverter::get().getValues());
tclap::ValuesConstraint<ExportFormat> exportFormatConstraint(exportFormats);
tclap::ValueArg<ExportFormat> exportFormat(
Expand Down Expand Up @@ -222,6 +240,13 @@ int main(int platformArgc, char* platformArgv[]) {
path inputFilePath(inputFileName.getValue());
ShapeSet targetShapeSet = getTargetShapeSet(extendedShapes.getValue());

unique_ptr<Exporter> exporter = createExporter(
exportFormat.getValue(),
targetShapeSet,
datFrameRate.getValue(),
datUsePrestonBlair.getValue()
);

logging::log(StartEntry(inputFilePath));
logging::debugFormat("Command line: {}",
join(args | transformed([](string arg) { return fmt::format("\"{}\"", arg); }), " "));
Expand All @@ -246,7 +271,6 @@ int main(int platformArgc, char* platformArgv[]) {
logging::info("Done animating.");

// Export animation
unique_ptr<Exporter> exporter = createExporter(exportFormat.getValue());
optional<boost::filesystem::ofstream> outputFile;
if (outputFileName.isSet()) {
outputFile = boost::in_place(outputFileName.getValue());
Expand Down

0 comments on commit fef283d

Please sign in to comment.