simplified and optimized samplebuffer

This commit is contained in:
itsmattkc
2022-05-09 14:55:51 -07:00
parent 58c4600d04
commit bb0fedabba
47 changed files with 214 additions and 252 deletions
+18 -15
View File
@@ -67,45 +67,48 @@ void PanNode::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeV
Q_UNUSED(globals)
// Create a sample job
SampleJob job(kSamplesInput, value);
if (job.HasSamples()) {
bool push_job = false;
SampleBuffer samples = value[kSamplesInput].toSamples();
if (samples.is_allocated()) {
bool pushed_job = false;
// This node is only compatible with stereo audio
if (job.samples()->audio_params().channel_count() == 2) {
if (samples.audio_params().channel_count() == 2) {
// If the input is static, we can just do it now which will be faster
if (IsInputStatic(kPanningInput)) {
float pan_volume = job.GetValue(kPanningInput).toDouble();
float pan_volume = value[kPanningInput].toDouble();
if (!qIsNull(pan_volume)) {
if (pan_volume > 0) {
job.samples()->transform_volume_for_channel(0, 1.0f - pan_volume);
samples.transform_volume_for_channel(0, 1.0f - pan_volume);
} else {
job.samples()->transform_volume_for_channel(1, 1.0f + pan_volume);
samples.transform_volume_for_channel(1, 1.0f + pan_volume);
}
}
} else {
// Requires job
push_job = true;
pushed_job = true;
table->Push(NodeValue::kSamples, SampleJob(kSamplesInput, value), this);
}
}
table->Push(NodeValue::kSamples, push_job ? QVariant::fromValue(job) : QVariant::fromValue(job.samples()), this);
if (!pushed_job) {
table->Push(value[kSamplesInput]);
}
}
}
void PanNode::ProcessSamples(const NodeValueRow &values, const SampleBufferPtr input, SampleBufferPtr output, int index) const
void PanNode::ProcessSamples(const NodeValueRow &values, const SampleBuffer &input, SampleBuffer &output, int index) const
{
float pan_val = values[kPanningInput].toDouble();
for (int i=0;i<input->audio_params().channel_count();i++) {
output->data(i)[index] = input->data(i)[index];
for (int i=0;i<input.audio_params().channel_count();i++) {
output.data(i)[index] = input.data(i)[index];
}
if (pan_val > 0) {
output->data(0)[index] *= (1.0F - pan_val);
output.data(0)[index] *= (1.0F - pan_val);
} else if (pan_val < 0) {
output->data(1)[index] *= (1.0F - qAbs(pan_val));
output.data(1)[index] *= (1.0F - qAbs(pan_val));
}
}
+1 -1
View File
@@ -40,7 +40,7 @@ public:
virtual void Value(const NodeValueRow& value, const NodeGlobals &globals, NodeValueTable *table) const override;
virtual void ProcessSamples(const NodeValueRow &values, const SampleBufferPtr input, SampleBufferPtr output, int index) const override;
virtual void ProcessSamples(const NodeValueRow &values, const SampleBuffer &input, SampleBuffer &output, int index) const override;
virtual void Retranslate() override;
+1 -1
View File
@@ -73,7 +73,7 @@ void VolumeNode::Value(const NodeValueRow &value, const NodeGlobals &globals, No
table);
}
void VolumeNode::ProcessSamples(const NodeValueRow &values, const SampleBufferPtr input, SampleBufferPtr output, int index) const
void VolumeNode::ProcessSamples(const NodeValueRow &values, const SampleBuffer &input, SampleBuffer &output, int index) const
{
return ProcessSamplesInternal(values, kOpMultiply, kSamplesInput, kVolumeInput, input, output, index);
}
+1 -1
View File
@@ -40,7 +40,7 @@ public:
virtual void Value(const NodeValueRow& value, const NodeGlobals &globals, NodeValueTable *table) const override;
virtual void ProcessSamples(const NodeValueRow &values, const SampleBufferPtr input, SampleBufferPtr output, int index) const override;
virtual void ProcessSamples(const NodeValueRow &values, const SampleBuffer &input, SampleBuffer &output, int index) const override;
virtual void Retranslate() override;
@@ -60,27 +60,27 @@ void CrossDissolveTransition::ShaderJobEvent(const NodeValueRow &value, ShaderJo
job.SetAlphaChannelRequired(GenerateJob::kAlphaForceOn);
}
void CrossDissolveTransition::SampleJobEvent(SampleBufferPtr from_samples, SampleBufferPtr to_samples, SampleBufferPtr out_samples, double time_in) const
void CrossDissolveTransition::SampleJobEvent(const SampleBuffer &from_samples, const SampleBuffer &to_samples, SampleBuffer &out_samples, double time_in) const
{
for (int i=0; i<out_samples->sample_count(); i++) {
double this_sample_time = out_samples->audio_params().samples_to_time(i).toDouble() + time_in;
for (int i=0; i<out_samples.sample_count(); i++) {
double this_sample_time = out_samples.audio_params().samples_to_time(i).toDouble() + time_in;
double progress = GetTotalProgress(this_sample_time);
for (int j=0; j<out_samples->audio_params().channel_count(); j++) {
out_samples->data(j)[i] = 0;
for (int j=0; j<out_samples.audio_params().channel_count(); j++) {
out_samples.data(j)[i] = 0;
if (from_samples) {
if (i < from_samples->sample_count()) {
out_samples->data(j)[i] += from_samples->data(j)[i] * TransformCurve(1.0 - progress);
if (from_samples.is_allocated()) {
if (i < from_samples.sample_count()) {
out_samples.data(j)[i] += from_samples.data(j)[i] * TransformCurve(1.0 - progress);
}
}
if (to_samples) {
if (to_samples.is_allocated()) {
// Offset input samples from the end
int in_index = i - (out_samples->sample_count() - to_samples->sample_count());
int in_index = i - (out_samples.sample_count() - to_samples.sample_count());
if (in_index >= 0) {
out_samples->data(j)[i] += to_samples->data(j)[in_index] * TransformCurve(progress);
out_samples.data(j)[i] += to_samples.data(j)[in_index] * TransformCurve(progress);
}
}
}
@@ -45,7 +45,7 @@ public:
protected:
virtual void ShaderJobEvent(const NodeValueRow &value, ShaderJob& job) const override;
virtual void SampleJobEvent(SampleBufferPtr from_samples, SampleBufferPtr to_samples, SampleBufferPtr out_samples, double time_in) const override;
virtual void SampleJobEvent(const SampleBuffer &from_samples, const SampleBuffer &to_samples, SampleBuffer &out_samples, double time_in) const override;
};
+6 -23
View File
@@ -206,25 +206,22 @@ void TransitionBlock::Value(const NodeValueRow &value, const NodeGlobals &global
push_job = QVariant::fromValue(job);
} else if (data_type == NodeValue::kSamples) {
// This must be an audio transition
SampleBufferPtr from_samples = out_buffer.toSamples();
SampleBufferPtr to_samples = in_buffer.toSamples();
SampleBuffer from_samples = out_buffer.toSamples();
SampleBuffer to_samples = in_buffer.toSamples();
if (from_samples || to_samples) {
if (from_samples.is_allocated() || to_samples.is_allocated()) {
double time_in = globals.time().in().toDouble();
double time_out = globals.time().out().toDouble();
const AudioParams& params = (from_samples) ? from_samples->audio_params() : to_samples->audio_params();
const AudioParams& params = (from_samples.is_allocated()) ? from_samples.audio_params() : to_samples.audio_params();
SampleBufferPtr out_samples;
SampleBuffer out_samples;
if (params.is_valid()) {
int nb_samples = params.time_to_samples(time_out - time_in);
out_samples = SampleBuffer::CreateAllocated(params, nb_samples);
out_samples = SampleBuffer(params, nb_samples);
SampleJobEvent(from_samples, to_samples, out_samples, time_in);
} else {
// Create dummy sample buffer
out_samples = SampleBuffer::Create();
}
job_type = NodeValue::kSamples;
@@ -251,20 +248,6 @@ void TransitionBlock::InvalidateCache(const TimeRange &range, const QString &fro
super::InvalidateCache(r, from, element, options);
}
void TransitionBlock::ShaderJobEvent(const NodeValueRow &value, ShaderJob &job) const
{
Q_UNUSED(value)
Q_UNUSED(job)
}
void TransitionBlock::SampleJobEvent(SampleBufferPtr from_samples, SampleBufferPtr to_samples, SampleBufferPtr out_samples, double time_in) const
{
Q_UNUSED(from_samples)
Q_UNUSED(to_samples)
Q_UNUSED(out_samples)
Q_UNUSED(time_in)
}
double TransitionBlock::TransformCurve(double linear) const
{
switch (static_cast<CurveType>(GetStandardValue(kCurveInput).toInt())) {
+2 -2
View File
@@ -73,9 +73,9 @@ public:
static const QString kCenterInput;
protected:
virtual void ShaderJobEvent(const NodeValueRow &value, ShaderJob& job) const;
virtual void ShaderJobEvent(const NodeValueRow &value, ShaderJob& job) const {}
virtual void SampleJobEvent(SampleBufferPtr from_samples, SampleBufferPtr to_samples, SampleBufferPtr out_samples, double time_in) const;
virtual void SampleJobEvent(const SampleBuffer &from_samples, const SampleBuffer &to_samples, SampleBuffer &out_samples, double time_in) const {}
double TransformCurve(double linear) const;
+2 -12
View File
@@ -72,14 +72,8 @@ void HashTraverser::ProcessVideoFootage(TexturePtr destination, const FootageJob
texture_ids_.insert(destination.get(), hash_.result());
}
void HashTraverser::ProcessAudioFootage(SampleBufferPtr destination, const FootageJob &stream, const TimeRange &input_time)
void HashTraverser::ProcessAudioFootage(SampleBuffer &destination, const FootageJob &stream, const TimeRange &input_time)
{
Hash(FileFunctions::GetUniqueFileIdentifier(stream.filename()));
Hash(stream.loop_mode());
Hash(stream.audio_params().stream_index());
Hash(input_time);
texture_ids_.insert(destination.get(), hash_.result());
}
void HashTraverser::ProcessShader(TexturePtr destination, const Node *node, const TimeRange &range, const ShaderJob &job)
@@ -104,9 +98,8 @@ void HashTraverser::ProcessColorTransform(TexturePtr destination, const Node *no
texture_ids_.insert(destination.get(), hash_.result());
}
void HashTraverser::ProcessSamples(SampleBufferPtr destination, const Node *node, const TimeRange &range, const SampleJob &job)
void HashTraverser::ProcessSamples(SampleBuffer &destination, const Node *node, const TimeRange &range, const SampleJob &job)
{
texture_ids_.insert(destination.get(), hash_.result());
}
void HashTraverser::ProcessFrameGeneration(TexturePtr destination, const Node *node, const GenerateJob &job)
@@ -146,9 +139,6 @@ void HashTraverser::HashNodeValue(const NodeValue &value)
if (value_type == NodeValue::kTexture) {
TexturePtr texture = value.toTexture();
id_for_buffer = texture_ids_.value(texture.get());
} else {
SampleBufferPtr samples = value.toSamples();
id_for_buffer = texture_ids_.value(samples.get());
}
if (!id_for_buffer.isEmpty()) {
+2 -2
View File
@@ -35,13 +35,13 @@ public:
protected:
virtual void ProcessVideoFootage(TexturePtr destination, const FootageJob &stream, const rational &input_time) override;
virtual void ProcessAudioFootage(SampleBufferPtr destination, const FootageJob &stream, const TimeRange &input_time) override;
virtual void ProcessAudioFootage(SampleBuffer &destination, const FootageJob &stream, const TimeRange &input_time) override;
virtual void ProcessShader(TexturePtr destination, const Node *node, const TimeRange &range, const ShaderJob& job) override;
virtual void ProcessColorTransform(TexturePtr destination, const Node *node, const ColorTransformJob& job) override;
virtual void ProcessSamples(SampleBufferPtr destination, const Node *node, const TimeRange &range, const SampleJob &job) override;
virtual void ProcessSamples(SampleBuffer &destination, const Node *node, const TimeRange &range, const SampleJob &job) override;
virtual void ProcessFrameGeneration(TexturePtr destination, const Node *node, const GenerateJob& job) override;
+1 -1
View File
@@ -109,7 +109,7 @@ void MathNode::Value(const NodeValueRow &value, const NodeGlobals &globals, Node
table);
}
void MathNode::ProcessSamples(const NodeValueRow &values, const SampleBufferPtr input, SampleBufferPtr output, int index) const
void MathNode::ProcessSamples(const NodeValueRow &values, const SampleBuffer &input, SampleBuffer &output, int index) const
{
return ProcessSamplesInternal(values, GetOperation(), kParamAIn, kParamBIn, input, output, index);
}
+1 -1
View File
@@ -54,7 +54,7 @@ public:
virtual void Value(const NodeValueRow& value, const NodeGlobals &globals, NodeValueTable *table) const override;
virtual void ProcessSamples(const NodeValueRow &values, const SampleBufferPtr input, SampleBufferPtr output, int index) const override;
virtual void ProcessSamples(const NodeValueRow &values, const SampleBuffer &input, SampleBuffer &output, int index) const override;
static const QString kMethodIn;
static const QString kParamAIn;
+22 -21
View File
@@ -298,18 +298,18 @@ void MathNodeBase::ValueInternal(Operation operation, Pairing pairing, const QSt
case kPairSampleSample:
{
SampleBufferPtr samples_a = val_a.toSamples();
SampleBufferPtr samples_b = val_b.toSamples();
SampleBuffer samples_a = val_a.toSamples();
SampleBuffer samples_b = val_b.toSamples();
int max_samples = qMax(samples_a->sample_count(), samples_b->sample_count());
int min_samples = qMin(samples_a->sample_count(), samples_b->sample_count());
int max_samples = qMax(samples_a.sample_count(), samples_b.sample_count());
int min_samples = qMin(samples_a.sample_count(), samples_b.sample_count());
SampleBufferPtr mixed_samples = SampleBuffer::CreateAllocated(samples_a->audio_params(), max_samples);
SampleBuffer mixed_samples = SampleBuffer(samples_a.audio_params(), max_samples);
for (int i=0;i<mixed_samples->audio_params().channel_count();i++) {
for (int i=0;i<mixed_samples.audio_params().channel_count();i++) {
// Mix samples that are in both buffers
for (int j=0;j<min_samples;j++) {
mixed_samples->data(i)[j] = PerformAll<float, float>(operation, samples_a->data(i)[j], samples_b->data(i)[j]);
mixed_samples.data(i)[j] = PerformAll<float, float>(operation, samples_a.data(i)[j], samples_b.data(i)[j]);
}
}
@@ -317,11 +317,11 @@ void MathNodeBase::ValueInternal(Operation operation, Pairing pairing, const QSt
// Fill in remainder space with 0s
int remainder = max_samples - min_samples;
SampleBufferPtr larger_buffer = (max_samples == samples_a->sample_count()) ? samples_a : samples_b;
const SampleBuffer &larger_buffer = (max_samples == samples_a.sample_count()) ? samples_a : samples_b;
for (int i=0;i<mixed_samples->audio_params().channel_count();i++) {
memcpy(&mixed_samples->data(i)[min_samples],
&larger_buffer->data(i)[min_samples],
for (int i=0;i<mixed_samples.audio_params().channel_count();i++) {
memcpy(&mixed_samples.data(i)[min_samples],
&larger_buffer.data(i)[min_samples],
remainder * sizeof(float));
}
}
@@ -396,24 +396,25 @@ void MathNodeBase::ValueInternal(Operation operation, Pairing pairing, const QSt
float number = RetrieveNumber(number_val);
SampleJob job(val_a.type() == NodeValue::kSamples ? val_a : val_b);
job.InsertValue(number_param, NodeValue(NodeValue::kFloat, number, this));
SampleBuffer buffer = val_a.type() == NodeValue::kSamples ? val_a.toSamples() : val_b.toSamples();
if (job.HasSamples()) {
if (buffer.is_allocated()) {
if (IsInputStatic(number_param)) {
if (!NumberIsNoOp(operation, number)) {
for (int i=0;i<job.samples()->audio_params().channel_count();i++) {
for (int i=0;i<buffer.audio_params().channel_count();i++) {
#if defined(Q_PROCESSOR_X86) || defined(Q_PROCESSOR_ARM)
// Use SSE instructions for optimization
PerformAllOnFloatBufferSSE(operation, job.samples()->data(i), number, 0, job.samples()->sample_count());
PerformAllOnFloatBufferSSE(operation, buffer.data(i), number, 0, buffer.sample_count());
#else
PerformAllOnFloatBuffer(operation, job.samples()->data(i), number, 0, job.samples()->sample_count());
PerformAllOnFloatBuffer(operation, buffer.data(i), number, 0, buffer.sample_count());
#endif
}
}
output->Push(NodeValue::kSamples, QVariant::fromValue(job.samples()), this);
output->Push(NodeValue::kSamples, QVariant::fromValue(buffer), this);
} else {
SampleJob job(val_a.type() == NodeValue::kSamples ? val_a : val_b);
job.InsertValue(number_param, NodeValue(NodeValue::kFloat, number, this));
output->Push(NodeValue::kSamples, QVariant::fromValue(job), this);
}
}
@@ -426,7 +427,7 @@ void MathNodeBase::ValueInternal(Operation operation, Pairing pairing, const QSt
}
}
void MathNodeBase::ProcessSamplesInternal(const NodeValueRow &values, MathNodeBase::Operation operation, const QString &param_a_in, const QString &param_b_in, const SampleBufferPtr input, SampleBufferPtr output, int index) const
void MathNodeBase::ProcessSamplesInternal(const NodeValueRow &values, MathNodeBase::Operation operation, const QString &param_a_in, const QString &param_b_in, const olive::SampleBuffer &input, olive::SampleBuffer &output, int index) const
{
// This function is only used for sample+number pairing
NodeValue number_val = values[param_a_in];
@@ -441,8 +442,8 @@ void MathNodeBase::ProcessSamplesInternal(const NodeValueRow &values, MathNodeBa
float number_flt = RetrieveNumber(number_val);
for (int i=0;i<output->audio_params().channel_count();i++) {
output->data(i)[index] = PerformAll<float, float>(operation, input->data(i)[index], number_flt);
for (int i=0;i<output.audio_params().channel_count();i++) {
output.data(i)[index] = PerformAll<float, float>(operation, input.data(i)[index], number_flt);
}
}
+1 -1
View File
@@ -121,7 +121,7 @@ protected:
void ValueInternal(Operation operation, Pairing pairing, const QString& param_a_in, const NodeValue &val_a, const QString& param_b_in, const NodeValue& val_b, const NodeGlobals &globals, NodeValueTable *output) const;
void ProcessSamplesInternal(const NodeValueRow &values, Operation operation, const QString& param_a_in, const QString& param_b_in, const SampleBufferPtr input, SampleBufferPtr output, int index) const;
void ProcessSamplesInternal(const NodeValueRow &values, Operation operation, const QString& param_a_in, const QString& param_b_in, const SampleBuffer &input, SampleBuffer &output, int index) const;
};
+1 -1
View File
@@ -1525,7 +1525,7 @@ ShaderCode Node::GetShaderCode(const ShaderRequest &request) const
return ShaderCode(QString(), QString());
}
void Node::ProcessSamples(const NodeValueRow &, const SampleBufferPtr, SampleBufferPtr, int) const
void Node::ProcessSamples(const NodeValueRow &, const SampleBuffer &, SampleBuffer &, int) const
{
}
+1 -1
View File
@@ -691,7 +691,7 @@ public:
/**
* @brief If Value() pushes a ShaderJob, this is the function that will process them.
*/
virtual void ProcessSamples(const NodeValueRow &values, const SampleBufferPtr input, SampleBufferPtr output, int index) const;
virtual void ProcessSamples(const NodeValueRow &values, const SampleBuffer &input, SampleBuffer &output, int index) const;
/**
* @brief If Value() pushes a GenerateJob, override this function for the image to create
+2 -2
View File
@@ -400,7 +400,7 @@ void NodeTraverser::ResolveJobs(NodeValue &val, const TimeRange &range)
} else if (job.type() == Track::kAudio) {
SampleBufferPtr buffer = CreateSampleBuffer(GetCacheAudioParams(), range.length());
SampleBuffer buffer = CreateSampleBuffer(GetCacheAudioParams(), range.length());
ProcessAudioFootage(buffer, job, range);
val.set_value(buffer);
@@ -409,7 +409,7 @@ void NodeTraverser::ResolveJobs(NodeValue &val, const TimeRange &range)
} else if (val.canConvert<SampleJob>()) {
SampleJob job = val.value<SampleJob>();
SampleBufferPtr output_buffer = CreateSampleBuffer(job.samples()->audio_params(), job.samples()->sample_count());
SampleBuffer output_buffer = CreateSampleBuffer(job.samples().audio_params(), job.samples().sample_count());
ProcessSamples(output_buffer, val.source(), range, job);
val.set_value(QVariant::fromValue(output_buffer));
+6 -6
View File
@@ -85,13 +85,13 @@ protected:
virtual void ProcessVideoFootage(TexturePtr destination, const FootageJob &stream, const rational &input_time){}
virtual void ProcessAudioFootage(SampleBufferPtr destination, const FootageJob &stream, const TimeRange &input_time){}
virtual void ProcessAudioFootage(SampleBuffer &destination, const FootageJob &stream, const TimeRange &input_time){}
virtual void ProcessShader(TexturePtr destination, const Node *node, const TimeRange &range, const ShaderJob& job){}
virtual void ProcessColorTransform(TexturePtr destination, const Node *node, const ColorTransformJob& job){}
virtual void ProcessSamples(SampleBufferPtr destination, const Node *node, const TimeRange &range, const SampleJob &job){}
virtual void ProcessSamples(SampleBuffer &destination, const Node *node, const TimeRange &range, const SampleJob &job){}
virtual void ProcessFrameGeneration(TexturePtr destination, const Node *node, const GenerateJob& job){}
@@ -102,18 +102,18 @@ protected:
return CreateDummyTexture(p);
}
virtual SampleBufferPtr CreateSampleBuffer(const AudioParams &params, int sample_count)
virtual SampleBuffer CreateSampleBuffer(const AudioParams &params, int sample_count)
{
// Return dummy by default
return SampleBuffer::Create();
return SampleBuffer();
}
SampleBufferPtr CreateSampleBuffer(const AudioParams &params, const rational &length)
SampleBuffer CreateSampleBuffer(const AudioParams &params, const rational &length)
{
if (params.is_valid()) {
return CreateSampleBuffer(params, params.time_to_samples(length));
} else {
return SampleBuffer::Create();
return SampleBuffer();
}
}
+1 -1
View File
@@ -307,7 +307,7 @@ public:
static void ValidateVectorString(QStringList* list, int count);
TexturePtr toTexture() const { return value<TexturePtr>(); }
SampleBufferPtr toSamples() const { return value<SampleBufferPtr>(); }
SampleBuffer toSamples() const { return value<SampleBuffer>(); }
bool toBool() const { return value<bool>(); }
double toDouble() const { return value<double>(); }
int64_t toInt() const { return value<int64_t>(); }