diff --git a/CHANGELOG.md b/CHANGELOG.md index c466bc4..d4e388b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## Unreleased * **Added** basic support for non-English recordings through phonetic recognition ([issue #45](https://github.com/DanielSWolf/rhubarb-lip-sync/issues/45)). +* **Fixed** a bug that prevented the progress bar from reaching 100% ([issue #48](https://github.com/DanielSWolf/rhubarb-lip-sync/issues/48)). ## Version 1.8.0 diff --git a/rhubarb/CMakeLists.txt b/rhubarb/CMakeLists.txt index 0fef2b7..0c0fd8c 100644 --- a/rhubarb/CMakeLists.txt +++ b/rhubarb/CMakeLists.txt @@ -467,6 +467,8 @@ add_library(rhubarb-tools src/tools/parallel.h src/tools/platformTools.cpp src/tools/platformTools.h + src/tools/progress.cpp + src/tools/progress.h src/tools/ProgressBar.cpp src/tools/ProgressBar.h src/tools/stringTools.cpp diff --git a/rhubarb/src/audio/processing.cpp b/rhubarb/src/audio/processing.cpp index 39cc8db..316efd7 100644 --- a/rhubarb/src/audio/processing.cpp +++ b/rhubarb/src/audio/processing.cpp @@ -1,4 +1,5 @@ #include "processing.h" +#include using std::function; using std::vector; diff --git a/rhubarb/src/audio/processing.h b/rhubarb/src/audio/processing.h index 8ece651..dc09c56 100644 --- a/rhubarb/src/audio/processing.h +++ b/rhubarb/src/audio/processing.h @@ -3,7 +3,7 @@ #include #include #include "AudioClip.h" -#include "tools/ProgressBar.h" +#include "tools/progress.h" void process16bitAudioClip(const AudioClip& audioClip, std::function&)> processBuffer, size_t bufferCapacity, ProgressSink& progressSink); void process16bitAudioClip(const AudioClip& audioClip, std::function&)> processBuffer, ProgressSink& progressSink); diff --git a/rhubarb/src/audio/voiceActivityDetection.h b/rhubarb/src/audio/voiceActivityDetection.h index 7820680..0e5bcb9 100644 --- a/rhubarb/src/audio/voiceActivityDetection.h +++ b/rhubarb/src/audio/voiceActivityDetection.h @@ -1,6 +1,6 @@ #pragma once #include "AudioClip.h" #include "time/BoundedTimeline.h" -#include "tools/ProgressBar.h" +#include "tools/progress.h" JoiningBoundedTimeline detectVoiceActivity(const AudioClip& audioClip, int maxThreadCount, ProgressSink& progressSink); diff --git a/rhubarb/src/lib/rhubarbLib.h b/rhubarb/src/lib/rhubarbLib.h index ca40a06..ae841a6 100644 --- a/rhubarb/src/lib/rhubarbLib.h +++ b/rhubarb/src/lib/rhubarbLib.h @@ -3,7 +3,7 @@ #include "core/Shape.h" #include "time/ContinuousTimeline.h" #include "audio/AudioClip.h" -#include "tools/ProgressBar.h" +#include "tools/progress.h" #include #include "animation/targetShapeSet.h" #include "recognition/Recognizer.h" diff --git a/rhubarb/src/recognition/Recognizer.h b/rhubarb/src/recognition/Recognizer.h index 05c445d..0903680 100644 --- a/rhubarb/src/recognition/Recognizer.h +++ b/rhubarb/src/recognition/Recognizer.h @@ -2,7 +2,7 @@ #include "audio/AudioClip.h" #include "core/Phone.h" -#include "tools/ProgressBar.h" +#include "tools/progress.h" #include "time/BoundedTimeline.h" class Recognizer { diff --git a/rhubarb/src/recognition/pocketSphinxTools.h b/rhubarb/src/recognition/pocketSphinxTools.h index 568ccbe..9a72199 100644 --- a/rhubarb/src/recognition/pocketSphinxTools.h +++ b/rhubarb/src/recognition/pocketSphinxTools.h @@ -3,7 +3,7 @@ #include "time/BoundedTimeline.h" #include "core/Phone.h" #include "audio/AudioClip.h" -#include "tools/ProgressBar.h" +#include "tools/progress.h" #include extern "C" { diff --git a/rhubarb/src/rhubarb/sinks.cpp b/rhubarb/src/rhubarb/sinks.cpp index 07dadbe..ef62778 100644 --- a/rhubarb/src/rhubarb/sinks.cpp +++ b/rhubarb/src/rhubarb/sinks.cpp @@ -16,6 +16,7 @@ using boost::optional; NiceStderrSink::NiceStderrSink(Level minLevel) : minLevel(minLevel), + progress(0.0), innerSink(make_shared(make_shared())) {} @@ -26,7 +27,8 @@ void NiceStderrSink::receive(const logging::Entry& entry) { startProgressIndication(); } else if (const ProgressEntry* progressEntry = dynamic_cast(&entry)) { assert(progressBar); - progressBar->reportProgress(progressEntry->getProgress()); + progress = progressEntry->getProgress(); + progressBar->reportProgress(progress); } else if (dynamic_cast(&entry)) { interruptProgressIndication(); std::cerr << "Done." << std::endl; @@ -44,7 +46,6 @@ void NiceStderrSink::receive(const logging::Entry& entry) { void NiceStderrSink::startProgressIndication() { std::cerr << "Progress: "; progressBar = boost::in_place(); - progressBar->setClearOnDestruction(false); } void NiceStderrSink::interruptProgressIndication() { @@ -54,8 +55,7 @@ void NiceStderrSink::interruptProgressIndication() { void NiceStderrSink::resumeProgressIndication() { std::cerr << "Progress (cont'd): "; - progressBar = boost::in_place(); - progressBar->setClearOnDestruction(false); + progressBar = boost::in_place(progress); } QuietStderrSink::QuietStderrSink(Level minLevel) : diff --git a/rhubarb/src/rhubarb/sinks.h b/rhubarb/src/rhubarb/sinks.h index 5e053db..9bf47e3 100644 --- a/rhubarb/src/rhubarb/sinks.h +++ b/rhubarb/src/rhubarb/sinks.h @@ -17,6 +17,7 @@ private: void resumeProgressIndication(); logging::Level minLevel; + double progress; boost::optional progressBar; std::shared_ptr innerSink; }; diff --git a/rhubarb/src/tools/ProgressBar.cpp b/rhubarb/src/tools/ProgressBar.cpp index 404a6b8..4f913d7 100644 --- a/rhubarb/src/tools/ProgressBar.cpp +++ b/rhubarb/src/tools/ProgressBar.cpp @@ -3,55 +3,26 @@ #include #include #include -#include #include #include using std::string; -ProgressForwarder::ProgressForwarder(std::function callback) : - callback(callback) +double sanitizeProgress(double progress) { + // Make sure value is in [0..1] range + return std::isnan(progress) + ? 0.0 + : boost::algorithm::clamp(progress, 0.0, 1.0); +} + +ProgressBar::ProgressBar(double progress) : + ProgressBar(std::cerr, progress) {} -void ProgressForwarder::reportProgress(double value) { - callback(value); -} - -ProgressMerger::ProgressMerger(ProgressSink& sink) : - sink(sink) -{} - -ProgressSink& ProgressMerger::addSink(double weight) { - std::lock_guard lock(mutex); - - totalWeight += weight; - int sinkIndex = weightedValues.size(); - weightedValues.push_back(0); - forwarders.push_back(ProgressForwarder([weight, sinkIndex, this](double progress) { - weightedValues[sinkIndex] = progress * weight; - report(); - })); - return forwarders.back(); -} - -void ProgressMerger::report() { - std::lock_guard lock(mutex); - - if (totalWeight != 0) { - double weightedSum = 0; - for (double weightedValue : weightedValues) { - weightedSum += weightedValue; - } - double progress = weightedSum / totalWeight; - sink.reportProgress(progress); - } else { - sink.reportProgress(0); - } -} - -ProgressBar::ProgressBar(std::ostream& stream) : +ProgressBar::ProgressBar(std::ostream& stream, double progress) : stream(stream) { + currentProgress = sanitizeProgress(progress); updateLoopFuture = std::async(std::launch::async, &ProgressBar::updateLoop, this); } @@ -61,37 +32,42 @@ ProgressBar::~ProgressBar() { } void ProgressBar::reportProgress(double value) { - // Make sure value is in [0..1] range - value = boost::algorithm::clamp(value, 0.0, 1.0); - if (std::isnan(value)) { - value = 0.0; - } - - currentProgress = value; + currentProgress = sanitizeProgress(value); } void ProgressBar::updateLoop() { - const int blockCount = 20; const std::chrono::milliseconds animationInterval(1000 / 8); - const string animation = "|/-\\"; while (!done) { - int progressBlockCount = static_cast(currentProgress * blockCount); - int percent = static_cast(currentProgress * 100); - string text = fmt::format("[{0}{1}] {2:3}% {3}", - string(progressBlockCount, '#'), string(blockCount - progressBlockCount, '-'), - percent, - animation[animationIndex++ % animation.size()]); - updateText(text); - + update(); std::this_thread::sleep_for(animationInterval); } if (clearOnDestruction) { updateText(""); + } else { + update(false); } } +void ProgressBar::update(bool showSpinner) { + const int blockCount = 20; + const string animation = "|/-\\"; + + int progressBlockCount = static_cast(currentProgress * blockCount); + const double epsilon = 0.0001; + int percent = static_cast(currentProgress * 100 + epsilon); + const string spinner = showSpinner + ? string(1, animation[animationIndex++ % animation.size()]) + : ""; + string text = fmt::format("[{0}{1}] {2:3}% {3}", + string(progressBlockCount, '#'), string(blockCount - progressBlockCount, '-'), + percent, + spinner + ); + updateText(text); +} + void ProgressBar::updateText(const string& text) { // Get length of common portion int commonPrefixLength = 0; diff --git a/rhubarb/src/tools/ProgressBar.h b/rhubarb/src/tools/ProgressBar.h index 0c005c7..347b330 100644 --- a/rhubarb/src/tools/ProgressBar.h +++ b/rhubarb/src/tools/ProgressBar.h @@ -2,49 +2,13 @@ #include #include -#include -#include -#include -#include -#include #include - -class ProgressSink { -public: - virtual ~ProgressSink() {} - virtual void reportProgress(double value) = 0; -}; - -class NullProgressSink : public ProgressSink { -public: - void reportProgress(double) override {} -}; - -class ProgressForwarder : public ProgressSink { -public: - ProgressForwarder(std::function callback); - void reportProgress(double value) override; -private: - std::function callback; -}; - -class ProgressMerger { -public: - ProgressMerger(ProgressSink& sink); - ProgressSink& addSink(double weight); -private: - void report(); - - ProgressSink& sink; - std::mutex mutex; - double totalWeight = 0; - std::list forwarders; - std::vector weightedValues; -}; +#include "progress.h" class ProgressBar : public ProgressSink { public: - ProgressBar(std::ostream& stream = std::cerr); + explicit ProgressBar(double progress = 0.0); + ProgressBar(std::ostream& stream, double progress = 0.0); ~ProgressBar(); void reportProgress(double value) override; @@ -58,6 +22,7 @@ public: private: void updateLoop(); + void update(bool showSpinner = true); void updateText(const std::string& text); std::future updateLoopFuture; @@ -67,5 +32,5 @@ private: std::ostream& stream; std::string currentText; int animationIndex = 0; - bool clearOnDestruction = true; + bool clearOnDestruction = false; }; diff --git a/rhubarb/src/tools/parallel.h b/rhubarb/src/tools/parallel.h index cca4164..de8c5d5 100644 --- a/rhubarb/src/tools/parallel.h +++ b/rhubarb/src/tools/parallel.h @@ -1,7 +1,8 @@ #pragma once #include -#include "ProgressBar.h" +#include +#include "progress.h" #include template diff --git a/rhubarb/src/tools/progress.cpp b/rhubarb/src/tools/progress.cpp new file mode 100644 index 0000000..34c5848 --- /dev/null +++ b/rhubarb/src/tools/progress.cpp @@ -0,0 +1,45 @@ +#include "progress.h" + +#include + +using std::string; + +ProgressForwarder::ProgressForwarder(std::function callback) : + callback(callback) +{} + +void ProgressForwarder::reportProgress(double value) { + callback(value); +} + +ProgressMerger::ProgressMerger(ProgressSink& sink) : + sink(sink) +{} + +ProgressSink& ProgressMerger::addSink(double weight) { + std::lock_guard lock(mutex); + + totalWeight += weight; + int sinkIndex = weightedValues.size(); + weightedValues.push_back(0); + forwarders.push_back(ProgressForwarder([weight, sinkIndex, this](double progress) { + weightedValues[sinkIndex] = progress * weight; + report(); + })); + return forwarders.back(); +} + +void ProgressMerger::report() { + std::lock_guard lock(mutex); + + if (totalWeight != 0) { + double weightedSum = 0; + for (double weightedValue : weightedValues) { + weightedSum += weightedValue; + } + double progress = weightedSum / totalWeight; + sink.reportProgress(progress); + } else { + sink.reportProgress(0); + } +} diff --git a/rhubarb/src/tools/progress.h b/rhubarb/src/tools/progress.h new file mode 100644 index 0000000..23f4965 --- /dev/null +++ b/rhubarb/src/tools/progress.h @@ -0,0 +1,39 @@ +#pragma once + +#include +#include +#include +#include + +class ProgressSink { +public: + virtual ~ProgressSink() {} + virtual void reportProgress(double value) = 0; +}; + +class NullProgressSink : public ProgressSink { +public: + void reportProgress(double) override {} +}; + +class ProgressForwarder : public ProgressSink { +public: + ProgressForwarder(std::function callback); + void reportProgress(double value) override; +private: + std::function callback; +}; + +class ProgressMerger { +public: + ProgressMerger(ProgressSink& sink); + ProgressSink& addSink(double weight); +private: + void report(); + + ProgressSink& sink; + std::mutex mutex; + double totalWeight = 0; + std::list forwarders; + std::vector weightedValues; +};