Previous iterations would use mutexes to prevent changing of the graph mid-render, however several user actions would need to capture these mutexes causing the main thread to hang until the current render job (frame/range of samples) was complete. We now copy the nodes necessary as part of the "compile" process so that the main thread shouldn't need nearly as much blocking while caching occurs.
107 lines
3.0 KiB
C++
107 lines
3.0 KiB
C++
#include "audiorenderbackend.h"
|
|
|
|
#include <QDir>
|
|
#include <QtMath>
|
|
|
|
#include "common/filefunctions.h"
|
|
|
|
AudioRenderBackend::AudioRenderBackend(QObject *parent) :
|
|
RenderBackend(parent)
|
|
{
|
|
}
|
|
|
|
void AudioRenderBackend::SetParameters(const AudioRenderingParams ¶ms)
|
|
{
|
|
// Since we're changing parameters, all the existing threads are invalid and must be removed. They will start again
|
|
// next time this Node has to process anything.
|
|
Close();
|
|
|
|
// Set new parameters
|
|
params_ = params;
|
|
|
|
// Regenerate the cache ID
|
|
RegenerateCacheID();
|
|
}
|
|
|
|
void AudioRenderBackend::InvalidateCache(const rational &start_range, const rational &end_range)
|
|
{
|
|
rational start_range_adj = qMax(rational(0), start_range);
|
|
rational end_range_adj = qMin(SequenceLength(), end_range);
|
|
|
|
// Add the range to the list
|
|
cache_queue_.append(TimeRange(start_range_adj, end_range_adj));
|
|
|
|
// Remove any overlaps so we don't render the same thing twice
|
|
ValidateRanges();
|
|
|
|
// Start caching cycle if it hasn't started already
|
|
CacheNext();
|
|
}
|
|
|
|
void AudioRenderBackend::ConnectViewer(ViewerOutput *node)
|
|
{
|
|
connect(node, SIGNAL(AudioChangedBetween(const rational&, const rational&)), this, SLOT(InvalidateCache(const rational&, const rational&)));
|
|
connect(node, SIGNAL(AudioGraphChanged()), this, SLOT(QueueRecompile()));
|
|
|
|
// FIXME: Hardcoded format
|
|
SetParameters(AudioRenderingParams(node->audio_params(), SAMPLE_FMT_FLT));
|
|
}
|
|
|
|
void AudioRenderBackend::DisconnectViewer(ViewerOutput *node)
|
|
{
|
|
disconnect(node, SIGNAL(AudioChangedBetween(const rational&, const rational&)), this, SLOT(InvalidateCache(const rational&, const rational&)));
|
|
disconnect(node, SIGNAL(AudioGraphChanged()), this, SLOT(QueueRecompile()));
|
|
}
|
|
|
|
bool AudioRenderBackend::GenerateCacheIDInternal(QCryptographicHash &hash)
|
|
{
|
|
if (!params_.is_valid()) {
|
|
return false;
|
|
}
|
|
|
|
// Generate an ID that is more or less guaranteed to be unique to this Sequence
|
|
hash.addData(QString::number(params_.sample_rate()).toUtf8());
|
|
hash.addData(QString::number(params_.channel_layout()).toUtf8());
|
|
hash.addData(QString::number(params_.format()).toUtf8());
|
|
|
|
return true;
|
|
}
|
|
|
|
const AudioRenderingParams &AudioRenderBackend::params()
|
|
{
|
|
return params_;
|
|
}
|
|
|
|
NodeInput *AudioRenderBackend::GetDependentInput()
|
|
{
|
|
return viewer_node()->samples_input();
|
|
}
|
|
|
|
void AudioRenderBackend::ValidateRanges()
|
|
{
|
|
for (int i=0;i<cache_queue_.size();i++) {
|
|
const TimeRange& range1 = cache_queue_.at(i);
|
|
|
|
for (int j=0;j<cache_queue_.size();j++) {
|
|
const TimeRange& range2 = cache_queue_.at(j);
|
|
|
|
if (TimeRange::Overlap(range1, range2) && i != j) {
|
|
// Combine with the first range
|
|
cache_queue_[i] = TimeRange::Combine(range1, range2);
|
|
|
|
// Remove the second range
|
|
cache_queue_.removeAt(j);
|
|
j--;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
QString AudioRenderBackend::CachePathName()
|
|
{
|
|
QDir this_cache_dir = QDir(GetMediaCacheLocation()).filePath(cache_id());
|
|
this_cache_dir.mkpath(".");
|
|
|
|
return this_cache_dir.filePath(QStringLiteral("pcm"));
|
|
}
|