diff --git a/include/vrv/doc.h b/include/vrv/doc.h index 48876eec45e..5361e886203 100644 --- a/include/vrv/doc.h +++ b/include/vrv/doc.h @@ -276,7 +276,7 @@ class Doc : public Object { * Extract a timemap from the document to a JSON string. * Run trough all the layers and fill the timemap file content. */ - bool ExportTimemap(std::string &output, bool includeRests, bool includeMeasures); + bool ExportTimemap(std::string &output, bool includeRests, bool includeMeasures, bool useFractions); /** * Extract expansionMap from the document to JSON string. diff --git a/include/vrv/horizontalaligner.h b/include/vrv/horizontalaligner.h index fc288230103..fb5a0f005b5 100644 --- a/include/vrv/horizontalaligner.h +++ b/include/vrv/horizontalaligner.h @@ -68,7 +68,8 @@ class Fraction { public: // Constructors - make them explicit to avoid type conversion - explicit Fraction(int num = 0, int denom = 1); + explicit Fraction(); + explicit Fraction(int num, int denom = 1); explicit Fraction(data_DURATION duration); // Enable implicit conversion constructor for `int` diff --git a/include/vrv/timemap.h b/include/vrv/timemap.h index 2545af4fca6..dc5bee98dfc 100644 --- a/include/vrv/timemap.h +++ b/include/vrv/timemap.h @@ -15,6 +15,12 @@ //---------------------------------------------------------------------------- +#include "horizontalaligner.h" + +//---------------------------------------------------------------------------- + +#include "jsonxx.h" + namespace vrv { class Object; @@ -28,7 +34,7 @@ class Object; */ struct TimemapEntry { double tempo = -1000.0; - double qstamp; + double tstamp; std::vector notesOn; std::vector notesOff; std::vector restsOn; @@ -59,12 +65,14 @@ class Timemap { /** * Return (and possibly add) an entry for the given time. */ - TimemapEntry &GetEntry(double time) { return m_map[time]; } + TimemapEntry &GetEntry(const Fraction &time) { return m_map[time]; } /** * Write the current timemap to a JSON string */ - void ToJson(std::string &output, bool includetRests, bool includetMeasures); + void ToJson(std::string &output, bool includeRests, bool includeMeasures, bool useFractions); + + static jsonxx::Array ToArray(const Fraction &fraction); private: // @@ -72,7 +80,7 @@ class Timemap { // private: /** The map with time values as keys */ - std::map m_map; + std::map m_map; }; // class Timemap diff --git a/src/doc.cpp b/src/doc.cpp index 8d1f276e609..f5664d709ef 100644 --- a/src/doc.cpp +++ b/src/doc.cpp @@ -542,7 +542,7 @@ void Doc::ExportMIDI(smf::MidiFile *midiFile) } } -bool Doc::ExportTimemap(std::string &output, bool includeRests, bool includeMeasures) +bool Doc::ExportTimemap(std::string &output, bool includeRests, bool includeMeasures, bool useFractions) { if (!this->HasTimemap()) { // generate MIDI timemap before progressing @@ -558,7 +558,7 @@ bool Doc::ExportTimemap(std::string &output, bool includeRests, bool includeMeas generateTimemap.SetCueExclusion(this->GetOptions()->m_midiNoCue.GetValue()); this->Process(generateTimemap); - timemap.ToJson(output, includeRests, includeMeasures); + timemap.ToJson(output, includeRests, includeMeasures, useFractions); return true; } diff --git a/src/horizontalaligner.cpp b/src/horizontalaligner.cpp index a219ab9323b..198d529eb98 100644 --- a/src/horizontalaligner.cpp +++ b/src/horizontalaligner.cpp @@ -38,6 +38,12 @@ namespace vrv { // Fraction //---------------------------------------------------------------------------- +Fraction::Fraction() +{ + m_numerator = 0; + m_denominator = 1; +} + Fraction::Fraction(int num, int denom) : m_numerator(num), m_denominator(denom) { if (denom == 0) { diff --git a/src/midifunctor.cpp b/src/midifunctor.cpp index 1677485613d..a3b4a4c8fad 100644 --- a/src/midifunctor.cpp +++ b/src/midifunctor.cpp @@ -955,11 +955,11 @@ void GenerateTimemapFunctor::AddTimemapEntry(const Object *object) /*********** start values ***********/ - TimemapEntry &startEntry = m_timemap->GetEntry(realTimeStart); + TimemapEntry &startEntry = m_timemap->GetEntry(scoreTimeStart); // Should check if value for realTimeStart already exists and if so, then // ensure that it is equal to scoreTimeStart: - startEntry.qstamp = scoreTimeStart.ToDouble(); + startEntry.tstamp = realTimeStart; // Store the element ID in list to turn on at given time - note or rest if (!isRest) startEntry.notesOn.push_back(object->GetID()); @@ -970,11 +970,11 @@ void GenerateTimemapFunctor::AddTimemapEntry(const Object *object) /*********** end values ***********/ - TimemapEntry &endEntry = m_timemap->GetEntry(realTimeEnd); + TimemapEntry &endEntry = m_timemap->GetEntry(scoreTimeEnd); // Should check if value for realTimeEnd already exists and if so, then // ensure that it is equal to scoreTimeEnd: - endEntry.qstamp = scoreTimeEnd.ToDouble(); + endEntry.tstamp = realTimeEnd; // Store the element ID in list to turn off at given time - notes or rest if (!isRest) endEntry.notesOff.push_back(object->GetID()); @@ -989,11 +989,11 @@ void GenerateTimemapFunctor::AddTimemapEntry(const Object *object) Fraction scoreTimeStart = m_scoreTimeOffset; double realTimeStart = round(m_realTimeOffsetMilliseconds); - TimemapEntry &startEntry = m_timemap->GetEntry(realTimeStart); + TimemapEntry &startEntry = m_timemap->GetEntry(scoreTimeStart); // Should check if value for realTimeStart already exists and if so, then // ensure that it is equal to scoreTimeStart: - startEntry.qstamp = scoreTimeStart.ToDouble(); + startEntry.tstamp = realTimeStart; // Add the measureOn startEntry.measureOn = measure->GetID(); diff --git a/src/timemap.cpp b/src/timemap.cpp index 6e48ff16795..6e6f8decd6c 100644 --- a/src/timemap.cpp +++ b/src/timemap.cpp @@ -37,17 +37,22 @@ void Timemap::Reset() m_map.clear(); } -void Timemap::ToJson(std::string &output, bool includeRests, bool includeMeasures) +void Timemap::ToJson(std::string &output, bool includeRests, bool includeMeasures, bool useFractions) { double currentTempo = -1000.0; double newTempo; jsonxx::Array timemap; - for (auto &[tstamp, entry] : m_map) { + for (auto &[qstamp, entry] : m_map) { jsonxx::Object o; - o << "tstamp" << tstamp; - o << "qstamp" << entry.qstamp; + if (useFractions) { + o << "qfrac" << Timemap::ToArray(qstamp); + } + else { + o << "qstamp" << qstamp.ToDouble(); + } + o << "tstamp" << entry.tstamp; // on / off if (!entry.notesOn.empty()) { @@ -80,7 +85,7 @@ void Timemap::ToJson(std::string &output, bool includeRests, bool includeMeasure newTempo = entry.tempo; if (newTempo != currentTempo) { currentTempo = newTempo; - o << "tempo" << std::to_string(currentTempo); + o << "tempo" << currentTempo; } } @@ -94,4 +99,12 @@ void Timemap::ToJson(std::string &output, bool includeRests, bool includeMeasure output = timemap.json(); } +jsonxx::Array Timemap::ToArray(const Fraction &fraction) +{ + jsonxx::Array array; + array << fraction.GetNumerator(); + array << fraction.GetDenominator(); + return array; +} + } // namespace vrv diff --git a/src/toolkit.cpp b/src/toolkit.cpp index afc211b406d..2d314b5cb55 100644 --- a/src/toolkit.cpp +++ b/src/toolkit.cpp @@ -1799,6 +1799,7 @@ std::string Toolkit::RenderToTimemap(const std::string &jsonOptions) { bool includeMeasures = false; bool includeRests = false; + bool useFractions = false; jsonxx::Object json; @@ -1811,13 +1812,14 @@ std::string Toolkit::RenderToTimemap(const std::string &jsonOptions) if (json.has("includeMeasures")) includeMeasures = json.get("includeMeasures"); if (json.has("includeRests")) includeRests = json.get("includeRests"); + if (json.has("useFractions")) useFractions = json.get("useFractions"); } } this->ResetLogBuffer(); std::string output; - m_doc.ExportTimemap(output, includeRests, includeMeasures); + m_doc.ExportTimemap(output, includeRests, includeMeasures, useFractions); return output; }