bwall
September 28, 2020, 9:58pm
1
I am using the following code to render, which works great! But, now that I am rendering longer Edits, I would like to have a progress bar.
File renderFile{ File::getSpecialLocation(File::userDesktopDirectory).getNonexistentChildFile("render", ".wav") };
te::EditTimeRange range{ 0.0, (edit->getLength() + 2.0) };// add 2.0 seconds to render tail
juce::BigInteger tracksToDo{ 0 };
for (auto i = 0; i < te::getAllTracks(*edit).size(); i++)
tracksToDo.setBit(i);
if (te::Renderer::renderToFile("Render", renderFile, *edit, range, tracksToDo))
AlertWindow::showMessageBoxAsync(AlertWindow::InfoIcon,
"Rendered",
renderFile.getFullPathName());
How would I go about adding the progress bar to my AlertWindow?
If you call renderToFile
with useThread=true
then it will callback into your app with UIBehaviour::runTaskWithProgressBar
Our implementation looks like this:
void runTaskWithProgressBar (ThreadPoolJobWithProgress& t)
{
jassert (currentTask == nullptr); // must stop or wait for others to finish first.
CRASH_TRACER
TransportControl::stopAllTransports (mainWindow.engine, false, true);
stopBackgroundTasks();
currentTask = &t;
TaskRunner runner (currentTask);
InterrupterComponent c (t);
addAndMakeVisible (&c);
c.setBounds (getLocalBounds());
JUCE_TRY
{
while (runner.isThreadRunning())
if (! MessageManager::getInstance()->runDispatchLoopUntil (10))
break;
}
JUCE_CATCH_EXCEPTION
c.exitModalState (0);
c.setVisible (false);
currentTask = nullptr;
}
Out component has a 30 hz callback that updates the progress:
void timerCallback() override
{
const String newText (task.getJobName());
progress = task.getCurrentTaskProgress();
if (newText != text)
{
text = newText;
repaint (boxArea);
}
}
1 Like
bwall
September 29, 2020, 6:59pm
3
Thanks so much for pointing me in the right direction?
The code below is working for me, …no timer required.
void runTaskWithProgressBar(te::ThreadPoolJobWithProgress& t) override
{
TaskRunner runner(t);
while (runner.isThreadRunning())
if (!MessageManager::getInstance()->runDispatchLoopUntil(10))
break;
}
//==============================================================================
struct TaskRunner : public Thread
{
TaskRunner(te::ThreadPoolJobWithProgress& t) : Thread(t.getJobName()), task(t)
{
startThread();
}
~TaskRunner()
{
task.signalJobShouldExit();
waitForThreadToExit(10000);
}
void run() override
{
double progress{ 0.0 };
AlertWindow w("Rendering", {}, AlertWindow::NoIcon);
w.addProgressBarComponent(progress);
w.setVisible(true);
while (!threadShouldExit())
{
if (task.runJob() == ThreadPoolJob::jobHasFinished)
break;
progress = task.getCurrentTaskProgress();
}
}
te::ThreadPoolJobWithProgress& task;
};
And to provide context for others—the above code is part of my ExtendedUIBehavior
class which derives from tracktion_engine::UIBehavior
and must be populated to provide functions used by plugins and rendering.
Aren’t you hitting asserts creating the AlertWindow in a thread? I’d think you should make progress a member variable and then create the AlertWindow in the constructor rather than in the thread.
bwall
September 29, 2020, 8:51pm
5
You are, of course, absolutely right! I had been doing only release builds. Doing a debug build showed the jassert.
When I put the AlertWindow
in the TaskRunner
constructor, the window never appears. So I moved it to runTaskWithProgressBar()
.
So, below is my modified solution;
void runTaskWithProgressBar(te::ThreadPoolJobWithProgress& t) override
{
double progress{ 0.0 };
TaskRunner runner(t, progress);
AlertWindow w("Rendering", {}, AlertWindow::NoIcon);
w.addProgressBarComponent(progress);
w.setVisible(true);
while (runner.isThreadRunning())
if (!MessageManager::getInstance()->runDispatchLoopUntil(10))
break;
}
//==============================================================================
struct TaskRunner : public Thread
{
TaskRunner(te::ThreadPoolJobWithProgress& t, double& prog) : Thread(t.getJobName()), task(t), progress(prog)
{
startThread();
}
~TaskRunner()
{
task.signalJobShouldExit();
waitForThreadToExit(10000);
}
void run() override
{
while (!threadShouldExit())
{
progress = task.getCurrentTaskProgress();
if (task.runJob() == ThreadPoolJob::jobHasFinished)
break;
}
}
te::ThreadPoolJobWithProgress& task;
double& progress;
};
Hopefully this code contains no more oversights!
Thank you, again!