Showing progress bar

This commit is contained in:
Daniel Wolf 2016-01-08 10:53:35 +01:00
parent f14feefeb0
commit 31cb3b195c
6 changed files with 123 additions and 12 deletions

View File

@ -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)

72
src/ProgressBar.cpp Normal file
View File

@ -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;
}

25
src/ProgressBar.h Normal file
View File

@ -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;
};

View File

@ -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) {

View File

@ -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());

View File

@ -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);