Showing progress bar
This commit is contained in:
parent
f14feefeb0
commit
31cb3b195c
|
@ -102,6 +102,7 @@ set(SOURCE_FILES
|
|||
src/stringTools.cpp
|
||||
src/NiceCmdLineOutput.cpp
|
||||
src/TablePrinter.cpp
|
||||
src/ProgressBar.cpp
|
||||
)
|
||||
add_executable(rhubarb ${SOURCE_FILES})
|
||||
target_link_libraries(rhubarb ${Boost_LIBRARIES} cppFormat sphinxbase pocketSphinx)
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
#include "ProgressBar.h"
|
||||
#include <algorithm>
|
||||
#include <future>
|
||||
#include <chrono>
|
||||
#include <format.h>
|
||||
#include <iostream>
|
||||
|
||||
using std::string;
|
||||
|
||||
ProgressBar::ProgressBar() {
|
||||
updateLoopFuture = std::async(std::launch::async, &ProgressBar::updateLoop, this);
|
||||
}
|
||||
|
||||
ProgressBar::~ProgressBar() {
|
||||
done = true;
|
||||
updateLoopFuture.wait();
|
||||
}
|
||||
|
||||
void ProgressBar::reportProgress(double value) {
|
||||
// Make sure value is in [0..1] range
|
||||
value = std::max(0.0, std::min(1.0, value));
|
||||
|
||||
currentProgress = value;
|
||||
}
|
||||
|
||||
void ProgressBar::updateLoop() {
|
||||
const int blockCount = 20;
|
||||
const std::chrono::milliseconds animationInterval(1000 / 8);
|
||||
const string animation = "|/-\\";
|
||||
|
||||
while (!done) {
|
||||
int progressBlockCount = static_cast<int>(currentProgress * blockCount);
|
||||
int percent = static_cast<int>(currentProgress * 100);
|
||||
string text = fmt::format("[{0}{1}] {2:3}% {3}",
|
||||
string(progressBlockCount, '#'), string(blockCount - progressBlockCount, '-'),
|
||||
percent,
|
||||
animation[animationIndex++ % animation.size()]);
|
||||
updateText(text);
|
||||
|
||||
std::this_thread::sleep_for(animationInterval);
|
||||
}
|
||||
|
||||
updateText("");
|
||||
}
|
||||
|
||||
void ProgressBar::updateText(const string& text) {
|
||||
// Get length of common portion
|
||||
int commonPrefixLength = 0;
|
||||
int commonLength = std::min(currentText.size(), text.size());
|
||||
while (commonPrefixLength < commonLength && text[commonPrefixLength] == currentText[commonPrefixLength]) {
|
||||
commonPrefixLength++;
|
||||
}
|
||||
|
||||
// Construct output string
|
||||
string output;
|
||||
|
||||
// ... backtrack to the first differing character
|
||||
output.append(currentText.size() - commonPrefixLength, '\b');
|
||||
|
||||
// ... add new suffix
|
||||
output.append(text, commonPrefixLength, text.size() - commonPrefixLength);
|
||||
|
||||
// ... if the new text is shorter than the old one: delete overlapping characters
|
||||
int overlapCount = currentText.size() - text.size();
|
||||
if (overlapCount > 0) {
|
||||
output.append(overlapCount, ' ');
|
||||
output.append(overlapCount, '\b');
|
||||
}
|
||||
|
||||
std::cerr << output;
|
||||
currentText = text;
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <atomic>
|
||||
#include <future>
|
||||
|
||||
class ProgressBar {
|
||||
public:
|
||||
ProgressBar();
|
||||
~ProgressBar();
|
||||
void reportProgress(double value);
|
||||
|
||||
private:
|
||||
void updateLoop();
|
||||
void updateText(const std::string& text);
|
||||
|
||||
std::future<void> updateLoopFuture;
|
||||
std::atomic<double> currentProgress { 0 };
|
||||
std::atomic<bool> done { false };
|
||||
|
||||
std::string currentText;
|
||||
int animationIndex = 0;
|
||||
};
|
||||
|
||||
|
24
src/main.cpp
24
src/main.cpp
|
@ -6,9 +6,9 @@
|
|||
#include "audioInput/WaveFileReader.h"
|
||||
#include "phoneExtraction.h"
|
||||
#include "mouthAnimation.h"
|
||||
#include "platformTools.h"
|
||||
#include "appInfo.h"
|
||||
#include "NiceCmdLineOutput.h"
|
||||
#include "ProgressBar.h"
|
||||
|
||||
using std::exception;
|
||||
using std::string;
|
||||
|
@ -81,14 +81,26 @@ int main(int argc, char *argv[]) {
|
|||
// Parse command line
|
||||
cmd.parse(argc, argv);
|
||||
|
||||
// Create audio streams
|
||||
unique_ptr<AudioStream> audioStream = createAudioStream(inputFileName.getValue());
|
||||
|
||||
// Detect phones
|
||||
map<centiseconds, Phone> phones = detectPhones(std::move(audioStream));
|
||||
const int columnWidth = 30;
|
||||
std::cerr << std::left;
|
||||
std::cerr << std::setw(columnWidth) << "Analyzing input file";
|
||||
unique_ptr<AudioStream> audioStream = createAudioStream(inputFileName.getValue());
|
||||
map<centiseconds, Phone> phones;
|
||||
{
|
||||
ProgressBar progressBar;
|
||||
phones = detectPhones(
|
||||
std::move(audioStream),
|
||||
[&progressBar](double progress) { progressBar.reportProgress(progress); });
|
||||
}
|
||||
std::cerr << "Done" << std::endl;
|
||||
|
||||
// Generate mouth shapes
|
||||
std::cerr << std::setw(columnWidth) << "Generating mouth shapes";
|
||||
map<centiseconds, Shape> shapes = animate(phones);
|
||||
std::cerr << "Done" << std::endl;
|
||||
|
||||
std::cerr << std::endl;
|
||||
|
||||
// Print XML
|
||||
ptree xmlTree = createXmlTree(inputFileName.getValue(), phones, shapes);
|
||||
|
@ -99,7 +111,7 @@ int main(int argc, char *argv[]) {
|
|||
// Error parsing command-line args.
|
||||
cmd.getOutput()->failure(cmd, e);
|
||||
return 1;
|
||||
} catch (TCLAP::ExitException& e) {
|
||||
} catch (TCLAP::ExitException&) {
|
||||
// A built-in TCLAP command (like --help) has finished. Exit application.
|
||||
return 0;
|
||||
} catch (const exception& e) {
|
||||
|
|
|
@ -18,6 +18,7 @@ using std::shared_ptr;
|
|||
using std::string;
|
||||
using std::map;
|
||||
using boost::filesystem::path;
|
||||
using std::function;
|
||||
|
||||
unique_ptr<AudioStream> to16kHzMono(unique_ptr<AudioStream> stream) {
|
||||
// Downmix, if required
|
||||
|
@ -75,7 +76,7 @@ int16_t floatSampleToInt16(float sample) {
|
|||
return static_cast<int16_t>(((sample + 1) / 2) * (INT16_MAX - INT16_MIN) + INT16_MIN);
|
||||
}
|
||||
|
||||
void processAudioStream(AudioStream& audioStream16kHzMono, ps_decoder_t& recognizer) {
|
||||
void processAudioStream(AudioStream& audioStream16kHzMono, ps_decoder_t& recognizer, function<void(double)> reportProgress) {
|
||||
// Start recognition
|
||||
int error = ps_start_utt(&recognizer);
|
||||
if (error) throw runtime_error("Error starting utterance processing.");
|
||||
|
@ -85,6 +86,7 @@ void processAudioStream(AudioStream& audioStream16kHzMono, ps_decoder_t& recogni
|
|||
const int capacity = 1600; // 0.1 second capacity
|
||||
buffer.reserve(capacity);
|
||||
int sampleCount = 0;
|
||||
reportProgress(0);
|
||||
do {
|
||||
// Read to buffer
|
||||
buffer.clear();
|
||||
|
@ -99,6 +101,7 @@ void processAudioStream(AudioStream& audioStream16kHzMono, ps_decoder_t& recogni
|
|||
if (searchedFrameCount < 0) throw runtime_error("Error analyzing raw audio data.");
|
||||
|
||||
sampleCount += buffer.size();
|
||||
reportProgress(static_cast<double>(sampleCount) / audioStream16kHzMono.getFrameCount());
|
||||
} while (buffer.size());
|
||||
error = ps_end_utt(&recognizer);
|
||||
if (error) throw runtime_error("Error ending utterance processing.");
|
||||
|
@ -153,7 +156,7 @@ void sphinxErrorCallback(void* user_data, err_lvl_t errorLevel, const char* form
|
|||
*errorString += message;
|
||||
}
|
||||
|
||||
map<centiseconds, Phone> detectPhones(unique_ptr<AudioStream> audioStream) {
|
||||
map<centiseconds, Phone> detectPhones(unique_ptr<AudioStream> audioStream, function<void(double)> reportProgress) {
|
||||
// Discard Pocketsphinx output
|
||||
err_set_logfp(nullptr);
|
||||
|
||||
|
@ -173,7 +176,7 @@ map<centiseconds, Phone> detectPhones(unique_ptr<AudioStream> audioStream) {
|
|||
audioStream = to16kHzMono(std::move(audioStream));
|
||||
|
||||
// Process data
|
||||
processAudioStream(*audioStream.get(), *recognizer.get());
|
||||
processAudioStream(*audioStream.get(), *recognizer.get(), reportProgress);
|
||||
|
||||
// Collect results into map
|
||||
return getPhones(*recognizer.get());
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <chrono>
|
||||
#include <ratio>
|
||||
#include <memory>
|
||||
#include "audioInput/AudioStream.h"
|
||||
#include "Phone.h"
|
||||
#include "centiseconds.h"
|
||||
|
||||
std::map<centiseconds, Phone> detectPhones(std::unique_ptr<AudioStream> audioStream);
|
||||
std::map<centiseconds, Phone> detectPhones(std::unique_ptr<AudioStream> audioStream, std::function<void(double)> reportProgress);
|
||||
|
|
Loading…
Reference in New Issue