OK, so I have a wrapper class Player
that encapsulates the Tracktion Engine classes. All interactions with TE are wrapped including loading an edit, and it also has a te::Edit::LoadContext
member named loadContext
.
te::Engine engine { ProjectInfo::projectName, std::make_unique<ExtendedUIBehaviour>(), nullptr };
std::unique_ptr<te::Edit> edit = nullptr;
te::Edit::LoadContext loadContext;
It has a simple getter to grab a reference to the LoadContext member:
te::Edit::LoadContext& getLoadContext() { return loadContext; }
The Player class has a public loadEdit(String, String)
method that eventually calls this private load method internally (which is identical to the te::loadEditFromFile()
method, except it resets/adds the LoadContext to the options):
std::unique_ptr<te::Edit> Player::loadEditFromFile(te::Engine& engine, const juce::File& editFile)
{
loadContext.progress = 0;
loadContext.shouldExit = false;
loadContext.completed = false;
auto editState = te::loadEditFromFile(engine, editFile, {});
auto id = te::ProjectItemID::fromProperty(editState, te::IDs::projectID);
if (!id.isValid())
id = te::ProjectItemID::createNewID(0);
te::Edit::Options options =
{
engine,
editState,
id,
te::Edit::forEditing,
&loadContext,
te::Edit::getDefaultNumUndoLevels(),
[editFile] { return editFile; },
{}
};
return std::make_unique<te::Edit>(options);
}
Now in the subclass of ThreadWithProgressWindow
:
class LoadEditProgressWindow : public juce::ThreadWithProgressWindow
{
public:
LoadEditProgressWindow(Player& p) : ThreadWithProgressWindow("Loading...", true, true), player(p)
{
}
~LoadEditProgressWindow() override
{
}
void run() override
{
while (!threadShouldExit())
{
auto& loadContext = player.getLoadContext();
auto progress = loadContext.progress.load();
auto completed = loadContext.completed.load();
setProgress(progress);
//DBG("Progress: " + String(progress));
if (completed) break;
sleep(10);
}
}
private:
Player& player;
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (LoadEditProgressWindow)
};
Finally, in a button handler I am opening the progress window and then starting the load of the edit:
LoadEditProgressWindow loadProgressWindow { player };
loadProgressWindow.launchThread();
// Load the edit into the player
player.loadEdit(editFilePath, projectFilePath);
If I debug the output of progress
from within the window’s run()
method I basically get a bunch of 0’s and then finally 1 and it closes because completed
is true when progress is 1.
But as I mentioned before, I think the actual issue here is that all JUCE UI becomes unresponsive during the load of te::Edit because loading happens on the message thread, and when it is loading, the message thread is busy with creating the corresponding audio graph, and can’t handle other messages such as repaint()
calls.
I tried loading an edit on another thread but hit an error message that seemed to indicate it needs to be loaded from the message thread. Maybe there is a way to load an edit on a different thread to keep UI responsive, but I haven’t found it yet.