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
+10 -10
View File
@@ -40,10 +40,10 @@ AudioVisualWaveform::AudioVisualWaveform() :
}
}
void AudioVisualWaveform::OverwriteSamplesFromBuffer(SampleBufferPtr samples, int sample_rate, const rational &start, double target_rate, Sample& data, int &start_index, int &samples_length)
void AudioVisualWaveform::OverwriteSamplesFromBuffer(const SampleBuffer &samples, int sample_rate, const rational &start, double target_rate, Sample& data, int &start_index, int &samples_length)
{
start_index = time_to_samples(start, target_rate);
samples_length = time_to_samples(static_cast<double>(samples->sample_count()) / static_cast<double>(sample_rate), target_rate);
samples_length = time_to_samples(static_cast<double>(samples.sample_count()) / static_cast<double>(sample_rate), target_rate);
int end_index = start_index + samples_length;
if (data.size() < end_index) {
@@ -54,7 +54,7 @@ void AudioVisualWaveform::OverwriteSamplesFromBuffer(SampleBufferPtr samples, in
for (int i=0; i<samples_length; i+=channels_) {
int src_start = qRound((double(i) * chunk_size)) / channels_;
int src_end = qMin(qRound((double(i + channels_) * chunk_size)) / channels_, samples->sample_count());
int src_end = qMin(qRound((double(i + channels_) * chunk_size)) / channels_, samples.sample_count());
Sample summary = SumSamples(samples,
src_start,
@@ -91,7 +91,7 @@ void AudioVisualWaveform::OverwriteSamplesFromMipmap(const AudioVisualWaveform::
input_length = samples_length;
}
void AudioVisualWaveform::OverwriteSamples(SampleBufferPtr samples, int sample_rate, const rational &start)
void AudioVisualWaveform::OverwriteSamples(const SampleBuffer &samples, int sample_rate, const rational &start)
{
if (!channels_) {
qWarning() << "Failed to write samples - channel count is zero";
@@ -125,7 +125,7 @@ void AudioVisualWaveform::OverwriteSamples(SampleBufferPtr samples, int sample_r
current_mipmap->second);
}
rational sample_length(samples->sample_count(), sample_rate);
rational sample_length(samples.sample_count(), sample_rate);
length_ = qMax(length_, start + sample_length);
}
@@ -277,7 +277,7 @@ AudioVisualWaveform::Sample AudioVisualWaveform::GetSummaryFromTime(const ration
return AudioVisualWaveform::Sample(channel_count(), {0, 0});
}
void ExpandMinMaxChannel(float *a, int start, int length, float &min_val, float &max_val)
void ExpandMinMaxChannel(const float *a, int start, int length, float &min_val, float &max_val)
{
#if defined(Q_PROCESSOR_X86) || defined(Q_PROCESSOR_ARM)
// SSE optimized
@@ -321,13 +321,13 @@ void ExpandMinMaxChannel(float *a, int start, int length, float &min_val, float
#endif
}
AudioVisualWaveform::Sample AudioVisualWaveform::SumSamples(SampleBufferPtr samples, int start_index, int length)
AudioVisualWaveform::Sample AudioVisualWaveform::SumSamples(const SampleBuffer &samples, int start_index, int length)
{
int channels = samples->audio_params().channel_count();
int channels = samples.audio_params().channel_count();
AudioVisualWaveform::Sample summed_samples(channels);
for (int channel=0; channel<samples->audio_params().channel_count(); channel++) {
ExpandMinMaxChannel(samples->data(channel), start_index, length, summed_samples[channel].min, summed_samples[channel].max);
for (int channel=0; channel<samples.audio_params().channel_count(); channel++) {
ExpandMinMaxChannel(samples.data(channel), start_index, length, summed_samples[channel].min, summed_samples[channel].max);
}
// for reference: this approximation is n x faster (and less accurate) for a n-tracks clip
+3 -3
View File
@@ -65,7 +65,7 @@ public:
*
* Starting at `start`, writes samples over anything in the buffer, expanding it if necessary.
*/
void OverwriteSamples(SampleBufferPtr samples, int sample_rate, const rational& start = 0);
void OverwriteSamples(const SampleBuffer &samples, int sample_rate, const rational& start = 0);
/**
* @brief Replaces sums at a certain range in this visual waveform
@@ -98,7 +98,7 @@ public:
Sample GetSummaryFromTime(const rational& start, const rational& length) const;
static Sample SumSamples(SampleBufferPtr samples, int start_index, int length);
static Sample SumSamples(const SampleBuffer &samples, int start_index, int length);
static Sample ReSumSamples(const SamplePerChannel *samples, int nb_samples, int nb_channels);
@@ -111,7 +111,7 @@ public:
static const rational kMaximumSampleRate;
private:
void OverwriteSamplesFromBuffer(SampleBufferPtr samples, int sample_rate, const rational& start, double target_rate, Sample &data, int &start_index, int &samples_length);
void OverwriteSamplesFromBuffer(const SampleBuffer &samples, int sample_rate, const rational& start, double target_rate, Sample &data, int &start_index, int &samples_length);
void OverwriteSamplesFromMipmap(const Sample& input, double input_sample_rate, int &input_start, int &input_length, const rational& start, double output_rate, Sample &output_data);
+6 -6
View File
@@ -109,7 +109,7 @@ FramePtr Decoder::RetrieveVideo(const rational &timecode, const RetrieveVideoPar
return RetrieveVideoInternal(timecode, divider, cancelled);
}
Decoder::RetrieveAudioStatus Decoder::RetrieveAudio(SampleBufferPtr dest, const TimeRange &range, const AudioParams &params, const QString& cache_path, Footage::LoopMode loop_mode, RenderMode::Mode mode)
Decoder::RetrieveAudioStatus Decoder::RetrieveAudio(SampleBuffer &dest, const TimeRange &range, const AudioParams &params, const QString& cache_path, Footage::LoopMode loop_mode, RenderMode::Mode mode)
{
QMutexLocker locker(&mutex_);
@@ -272,14 +272,14 @@ bool Decoder::ConformAudioInternal(const QVector<QString> &filenames, const Audi
return false;
}
bool Decoder::RetrieveAudioFromConform(SampleBufferPtr sample_buffer, const QVector<QString> &conform_filenames, const TimeRange& range, Footage::LoopMode loop_mode, const AudioParams &input_params)
bool Decoder::RetrieveAudioFromConform(SampleBuffer &sample_buffer, const QVector<QString> &conform_filenames, const TimeRange& range, Footage::LoopMode loop_mode, const AudioParams &input_params)
{
PlanarFileDevice input;
if (input.open(conform_filenames, QFile::ReadOnly)) {
qint64 read_index = input_params.time_to_bytes(range.in()) / input_params.channel_count();
qint64 write_index = 0;
const qint64 buffer_length_in_bytes = sample_buffer->sample_count() * input_params.bytes_per_sample_per_channel();
const qint64 buffer_length_in_bytes = sample_buffer.sample_count() * input_params.bytes_per_sample_per_channel();
while (write_index < buffer_length_in_bytes) {
if (loop_mode == Footage::kLoopModeLoop) {
@@ -297,15 +297,15 @@ bool Decoder::RetrieveAudioFromConform(SampleBufferPtr sample_buffer, const QVec
if (read_index < 0) {
// Reading before 0, write silence here until audio data would actually start
write_count = qMin(-read_index, buffer_length_in_bytes);
sample_buffer->silence_bytes(write_index, write_index + write_count);
sample_buffer.silence_bytes(write_index, write_index + write_count);
} else if (read_index >= input.size()) {
// Reading after data length, write silence until the end of the buffer
write_count = buffer_length_in_bytes - write_index;
sample_buffer->silence_bytes(write_index, write_index + write_count);
sample_buffer.silence_bytes(write_index, write_index + write_count);
} else {
write_count = qMin(input.size() - read_index, buffer_length_in_bytes - write_index);
input.seek(read_index);
input.read(reinterpret_cast<char**>(sample_buffer->to_raw_ptrs()), write_count, write_index);
input.read(reinterpret_cast<char**>(sample_buffer.to_raw_ptrs().data()), write_count, write_index);
}
read_index += write_count;
+2 -2
View File
@@ -201,7 +201,7 @@ public:
*
* This function is thread safe and can only run while the decoder is open. \see Open()
*/
RetrieveAudioStatus RetrieveAudio(SampleBufferPtr dest, const TimeRange& range, const AudioParams& params, const QString &cache_path, Footage::LoopMode loop_mode, RenderMode::Mode mode);
RetrieveAudioStatus RetrieveAudio(SampleBuffer &dest, const TimeRange& range, const AudioParams& params, const QString &cache_path, Footage::LoopMode loop_mode, RenderMode::Mode mode);
/**
* @brief Determine the last time this decoder instance was used in any way
@@ -307,7 +307,7 @@ signals:
private:
void UpdateLastAccessed();
bool RetrieveAudioFromConform(SampleBufferPtr sample_buffer, const QVector<QString> &conform_filenames, const TimeRange &range, Footage::LoopMode loop_mode, const AudioParams &params);
bool RetrieveAudioFromConform(SampleBuffer &sample_buffer, const QVector<QString> &conform_filenames, const TimeRange &range, Footage::LoopMode loop_mode, const AudioParams &params);
CodecStream stream_;
+1 -1
View File
@@ -183,7 +183,7 @@ public slots:
virtual bool Open() = 0;
virtual bool WriteFrame(olive::FramePtr frame, olive::rational time) = 0;
virtual bool WriteAudio(olive::SampleBufferPtr audio) = 0;
virtual bool WriteAudio(const olive::SampleBuffer &audio) = 0;
virtual bool WriteSubtitle(const SubtitleBlock *sub_block) = 0;
virtual void Close() = 0;
+2 -2
View File
@@ -515,7 +515,7 @@ bool FFmpegDecoder::ConformAudioInternal(const QVector<QString> &filenames, cons
// Resample audio to our destination parameters
nb_samples = swr_convert(resampler,
reinterpret_cast<uint8_t**>(data.to_raw_ptrs()),
reinterpret_cast<uint8_t**>(data.to_raw_ptrs().data()),
nb_samples,
const_cast<const uint8_t**>(frame->data),
frame->nb_samples);
@@ -526,7 +526,7 @@ bool FFmpegDecoder::ConformAudioInternal(const QVector<QString> &filenames, cons
nb_bytes_per_channel = params.samples_to_bytes(nb_samples) / nb_channels;
// Write to files
wave_out.write(const_cast<const char**>(reinterpret_cast<char**>(data.to_raw_ptrs())), nb_bytes_per_channel);
wave_out.write(const_cast<const char**>(reinterpret_cast<char**>(data.to_raw_ptrs().data())), nb_bytes_per_channel);
}
// Free buffer
+9 -9
View File
@@ -266,26 +266,26 @@ fail:
return success;
}
bool FFmpegEncoder::WriteAudio(SampleBufferPtr audio)
bool FFmpegEncoder::WriteAudio(const SampleBuffer &audio)
{
bool result = true;
// Create input buffer
int input_sample_count = 0;
uint8_t** input_data = nullptr;
if (audio) {
input_sample_count = audio->sample_count();
if (audio.is_allocated()) {
input_sample_count = audio.sample_count();
int input_linesize;
av_samples_alloc_array_and_samples(&input_data, &input_linesize, audio->audio_params().channel_count(),
input_sample_count, FFmpegUtils::GetFFmpegSampleFormat(audio->audio_params().format()), 0);
av_samples_alloc_array_and_samples(&input_data, &input_linesize, audio.audio_params().channel_count(),
input_sample_count, FFmpegUtils::GetFFmpegSampleFormat(audio.audio_params().format()), 0);
for (int i=0; i<audio->audio_params().channel_count(); i++) {
memcpy(input_data[i], audio->data(i), input_sample_count * audio->audio_params().bytes_per_sample_per_channel());
for (int i=0; i<audio.audio_params().channel_count(); i++) {
memcpy(input_data[i], audio.data(i), input_sample_count * audio.audio_params().bytes_per_sample_per_channel());
}
}
result = WriteAudioData(audio ? audio->audio_params() : params().audio_params(), const_cast<const uint8_t**>(input_data), input_sample_count);
result = WriteAudioData(audio.audio_params().is_valid() ? audio.audio_params() : params().audio_params(), const_cast<const uint8_t**>(input_data), input_sample_count);
if (input_data) {
av_freep(&input_data[0]);
@@ -774,7 +774,7 @@ void FFmpegEncoder::FlushEncoders()
}
if (audio_codec_ctx_) {
WriteAudio(nullptr);
WriteAudio(SampleBuffer());
FlushCodecCtx(audio_codec_ctx_, audio_stream_);
}
+1 -1
View File
@@ -47,7 +47,7 @@ public:
virtual bool WriteFrame(olive::FramePtr frame, olive::rational time) override;
virtual bool WriteAudio(olive::SampleBufferPtr audio) override;
virtual bool WriteAudio(const olive::SampleBuffer &audio) override;
bool WriteAudioData(const AudioParams &audio_params, const uint8_t **data, int input_sample_count);
+1 -1
View File
@@ -62,7 +62,7 @@ bool OIIOEncoder::WriteFrame(FramePtr frame, rational time)
return true;
}
bool OIIOEncoder::WriteAudio(SampleBufferPtr audio)
bool OIIOEncoder::WriteAudio(const SampleBuffer &audio)
{
// Do nothing
return false;
+1 -1
View File
@@ -35,7 +35,7 @@ public slots:
virtual bool Open() override;
virtual bool WriteFrame(olive::FramePtr frame, olive::rational time) override;
virtual bool WriteAudio(SampleBufferPtr audio) override;
virtual bool WriteAudio(const SampleBuffer &audio) override;
virtual bool WriteSubtitle(const SubtitleBlock *sub_block) override;
virtual void Close() override;
+28 -33
View File
@@ -20,6 +20,8 @@
#include "samplebuffer.h"
#include "common/cpuoptimize.h"
namespace olive {
SampleBuffer::SampleBuffer() :
@@ -27,25 +29,18 @@ SampleBuffer::SampleBuffer() :
{
}
SampleBufferPtr SampleBuffer::Create()
SampleBuffer::SampleBuffer(const AudioParams &audio_params, const rational &length) :
audio_params_(audio_params)
{
return std::make_shared<SampleBuffer>();
sample_count_per_channel_ = audio_params_.time_to_samples(length);
allocate();
}
SampleBufferPtr SampleBuffer::CreateAllocated(const AudioParams &audio_params, const rational &length)
SampleBuffer::SampleBuffer(const AudioParams &audio_params, int samples_per_channel) :
audio_params_(audio_params),
sample_count_per_channel_(samples_per_channel)
{
return CreateAllocated(audio_params, audio_params.time_to_samples(length));
}
SampleBufferPtr SampleBuffer::CreateAllocated(const AudioParams &audio_params, int samples_per_channel)
{
SampleBufferPtr buffer = Create();
buffer->set_audio_params(audio_params);
buffer->set_sample_count(samples_per_channel);
buffer->allocate();
return buffer;
allocate();
}
const AudioParams &SampleBuffer::audio_params() const
@@ -104,14 +99,11 @@ void SampleBuffer::allocate()
for (int i=0; i<audio_params_.channel_count(); i++) {
data_[i].resize(sample_count_per_channel_);
}
update_raw();
}
void SampleBuffer::destroy()
{
data_.clear();
raw_ptrs_.clear();
}
void SampleBuffer::reverse()
@@ -157,29 +149,40 @@ void SampleBuffer::speed(double speed)
}
data_ = output_data;
update_raw();
}
void SampleBuffer::transform_volume(float f)
{
for (int i=0;i<audio_params().channel_count();i++) {
for (int j=0;j<sample_count_per_channel_;j++) {
data_[i][j] *= f;
}
transform_volume_for_channel(i, f);
}
}
void SampleBuffer::transform_volume_for_channel(int channel, float volume)
{
for (int i=0;i<sample_count_per_channel_;i++) {
data_[channel][i] *= volume;
float *cdat = data_[channel].data();
int unopt_start = 0;
#if defined(Q_PROCESSOR_X86) || defined(Q_PROCESSOR_ARM)
__m128 mult = _mm_load1_ps(&volume);
unopt_start = (sample_count_per_channel_ / 4) * 4;
for (int j=0; j<unopt_start; j+=4) {
float *here = cdat + j;
__m128 samples = _mm_loadu_ps(here);
__m128 multiplied = _mm_mul_ps(samples, mult);
_mm_storeu_ps(here, multiplied);
}
#endif
for (int j=unopt_start; j<sample_count_per_channel_; j++) {
cdat[j] *= volume;
}
}
void SampleBuffer::transform_volume_for_sample(int sample_index, float volume)
{
for (int i=0;i<audio_params().channel_count();i++) {
data_[i][sample_index] *= volume;
transform_volume_for_sample_on_channel(sample_index, i, volume);
}
}
@@ -220,12 +223,4 @@ void SampleBuffer::set(int channel, const float *data, int sample_offset, int sa
memcpy(&data_[channel].data()[sample_offset], data, sizeof(float) * sample_length);
}
void SampleBuffer::update_raw()
{
raw_ptrs_.resize(data_.size());
for (int i=0; i<raw_ptrs_.size(); i++) {
raw_ptrs_[i] = data_[i].data();
}
}
}
+9 -15
View File
@@ -27,9 +27,6 @@
namespace olive {
class SampleBuffer;
using SampleBufferPtr = std::shared_ptr<SampleBuffer>;
/**
* @brief A buffer of audio samples
*
@@ -42,12 +39,8 @@ class SampleBuffer
{
public:
SampleBuffer();
static SampleBufferPtr Create();
static SampleBufferPtr CreateAllocated(const AudioParams& audio_params, const rational& length);
static SampleBufferPtr CreateAllocated(const AudioParams& audio_params, int samples_per_channel);
DISABLE_COPY_MOVE(SampleBuffer)
SampleBuffer(const AudioParams& audio_params, const rational& length);
SampleBuffer(const AudioParams& audio_params, int samples_per_channel);
const AudioParams& audio_params() const;
void set_audio_params(const AudioParams& params);
@@ -69,9 +62,13 @@ public:
return data_.at(channel).constData();
}
float **to_raw_ptrs()
QVector<float *> to_raw_ptrs()
{
return raw_ptrs_.data();
QVector<float *> r(data_.size());
for (int i=0; i<r.size(); i++) {
r[i] = data_[i].data();
}
return r;
}
bool is_allocated() const;
@@ -96,19 +93,16 @@ public:
}
private:
void update_raw();
AudioParams audio_params_;
int sample_count_per_channel_;
QVector< QVector<float> > data_;
QVector<float*> raw_ptrs_;
};
}
Q_DECLARE_METATYPE(olive::SampleBufferPtr)
Q_DECLARE_METATYPE(olive::SampleBuffer)
#endif // SAMPLEBUFFER_H
+1 -1
View File
@@ -108,7 +108,7 @@ void Core::DeclareTypesForQt()
qRegisterMetaType<NodeValueTable>();
qRegisterMetaType<NodeValueDatabase>();
qRegisterMetaType<FramePtr>();
qRegisterMetaType<SampleBufferPtr>();
qRegisterMetaType<SampleBuffer>();
qRegisterMetaType<AudioParams>();
qRegisterMetaType<NodeKeyframe::Type>();
qRegisterMetaType<Decoder::RetrieveState>();
+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>(); }
+4 -4
View File
@@ -58,7 +58,7 @@ void AudioPlaybackCache::SetParameters(const AudioParams &params)
emit ParametersChanged();
}
void AudioPlaybackCache::WritePCM(const TimeRange &range, const TimeRangeList &valid_ranges, SampleBufferPtr samples)
void AudioPlaybackCache::WritePCM(const TimeRange &range, const TimeRangeList &valid_ranges, const SampleBuffer &samples)
{
// Ensure if we have enough segments to write this data, creating more if not
qint64 length_diff = params_.time_to_bytes_per_channel(range.out()) - playlist_.GetLength();
@@ -72,7 +72,7 @@ void AudioPlaybackCache::WritePCM(const TimeRange &range, const TimeRangeList &v
TimeRangeList ranges_we_validated;
// Calculate buffer size per channel
qint64 buffer_size_per_channel = samples ? samples->sample_count() * params_.bytes_per_sample_per_channel() : 0;
qint64 buffer_size_per_channel = samples.sample_count() * params_.bytes_per_sample_per_channel();
// Write each valid range to the segments
foreach (const TimeRange& r, valid_ranges) {
@@ -114,7 +114,7 @@ void AudioPlaybackCache::WritePCM(const TimeRange &range, const TimeRangeList &v
if (possible_write_length > 0) {
// Assume `samples` is valid if we're here, or else `buffer_size_per_channel` and
// therefore `possible_write_length` will be 0.
seg_file.write(reinterpret_cast<const char*>(samples->data(i)) + src_offset, possible_write_length);
seg_file.write(reinterpret_cast<const char*>(samples.data(i)) + src_offset, possible_write_length);
}
if (possible_write_length < total_write_length) {
@@ -167,7 +167,7 @@ void AudioPlaybackCache::WriteSilence(const TimeRange &range)
{
// WritePCM will automatically fill non-existent bytes with silence, so we just have to send
// it an empty sample buffer
WritePCM(range, {range}, nullptr);
WritePCM(range, {range}, SampleBuffer());
}
void AudioPlaybackCache::ShiftEvent(const rational &from_in_time, const rational &to_in_time)
+1 -1
View File
@@ -66,7 +66,7 @@ public:
void SetParameters(const AudioParams& params);
void WritePCM(const TimeRange &range, const TimeRangeList &valid_ranges, SampleBufferPtr samples);
void WritePCM(const TimeRange &range, const TimeRangeList &valid_ranges, const SampleBuffer &samples);
void WriteWaveform(const TimeRange &range, const TimeRangeList &valid_ranges, const AudioVisualWaveform *waveform);
+3 -4
View File
@@ -30,7 +30,6 @@ class SampleJob : public AcceleratedJob {
public:
SampleJob()
{
samples_ = nullptr;
}
SampleJob(const NodeValue& value)
@@ -43,18 +42,18 @@ public:
samples_ = row[from].toSamples();
}
SampleBufferPtr samples() const
const SampleBuffer &samples() const
{
return samples_;
}
bool HasSamples() const
{
return samples_ && samples_->is_allocated();
return samples_.is_allocated();
}
private:
SampleBufferPtr samples_;
SampleBuffer samples_;
};
+1 -1
View File
@@ -207,7 +207,7 @@ void PreviewAutoCacher::AudioRendered()
// WritePCM is tolerant to its buffer being null, it will just write silence instead
viewer_node_->audio_playback_cache()->WritePCM(range,
valid_ranges,
watcher->Get().value<SampleBufferPtr>());
watcher->Get().value<SampleBuffer>());
}
viewer_node_->audio_playback_cache()->WriteWaveform(range, valid_ranges, &waveform);
+24 -28
View File
@@ -200,11 +200,11 @@ void RenderProcessor::Run()
ResolveJobs(sample_val, time);
SampleBufferPtr samples = sample_val.toSamples();
if (samples && ticket_->property("enablewaveforms").toBool()) {
SampleBuffer samples = sample_val.toSamples();
if (samples.is_allocated() && ticket_->property("enablewaveforms").toBool()) {
AudioVisualWaveform vis;
vis.set_channel_count(samples->audio_params().channel_count());
vis.OverwriteSamples(samples, samples->audio_params().sample_rate());
vis.set_channel_count(samples.audio_params().channel_count());
vis.OverwriteSamples(samples, samples.audio_params().sample_rate());
ticket_->setProperty("waveform", QVariant::fromValue(vis));
}
@@ -275,9 +275,8 @@ NodeValueTable RenderProcessor::GenerateBlockTable(const Track *track, const Tim
QVector<Block*> active_blocks = track->BlocksAtTimeRange(range);
// All these blocks will need to output to a buffer so we create one here
SampleBufferPtr block_range_buffer = SampleBuffer::CreateAllocated(audio_params,
audio_params.time_to_samples(range.length()));
block_range_buffer->silence();
SampleBuffer block_range_buffer(audio_params, range.length());
block_range_buffer.silence();
NodeValueTable merged_table;
@@ -292,10 +291,10 @@ NodeValueTable RenderProcessor::GenerateBlockTable(const Track *track, const Tim
// Destination buffer
NodeValueTable table = GenerateTable(b, track->GetValueHintForInput(Track::kBlockInput, track->GetArrayIndexFromBlock(b)),Track::TransformRangeForBlock(b, range_for_block));
SampleBufferPtr samples_from_this_block = table.Take(NodeValue::kSamples).toSamples();
SampleBuffer samples_from_this_block = table.Take(NodeValue::kSamples).toSamples();
ClipBlock *clip_cast = dynamic_cast<ClipBlock*>(b);
if (samples_from_this_block) {
if (samples_from_this_block.is_allocated()) {
// If this is a clip, we might have extra speed/reverse information
if (clip_cast) {
double speed_value = clip_cast->speed();
@@ -303,12 +302,12 @@ NodeValueTable RenderProcessor::GenerateBlockTable(const Track *track, const Tim
if (qIsNull(speed_value)) {
// Just silence, don't think there's any other practical application of 0 speed audio
samples_from_this_block->silence();
samples_from_this_block.silence();
} else if (!qFuzzyCompare(speed_value, 1.0)) {
if (clip_cast->maintain_audio_pitch()) {
AudioProcessor processor;
if (processor.Open(samples_from_this_block->audio_params(), samples_from_this_block->audio_params(), speed_value)) {
if (processor.Open(samples_from_this_block.audio_params(), samples_from_this_block.audio_params(), speed_value)) {
AudioProcessor::Buffer out;
// FIXME: This is not the best way to do this, the TempoProcessor works best
@@ -317,7 +316,7 @@ NodeValueTable RenderProcessor::GenerateBlockTable(const Track *track, const Tim
// well on export (assuming audio is all generated at once on export), but
// users may hear clicks and pops in the audio during preview due to this
// approach.
int r = processor.Convert(samples_from_this_block->to_raw_ptrs(), samples_from_this_block->sample_count(), nullptr);
int r = processor.Convert(samples_from_this_block.to_raw_ptrs().data(), samples_from_this_block.sample_count(), nullptr);
if (r < 0) {
qCritical() << "Failed to change tempo of audio:" << r;
@@ -327,16 +326,13 @@ NodeValueTable RenderProcessor::GenerateBlockTable(const Track *track, const Tim
processor.Convert(nullptr, 0, &out);
if (!out.empty()) {
int nb_samples = out.front().size() * samples_from_this_block->audio_params().bytes_per_sample_per_channel();
int nb_samples = out.front().size() * samples_from_this_block.audio_params().bytes_per_sample_per_channel();
if (nb_samples) {
SampleBufferPtr new_samples = SampleBuffer::Create();
new_samples->set_audio_params(samples_from_this_block->audio_params());
new_samples->set_sample_count(nb_samples);
new_samples->allocate();
SampleBuffer new_samples(samples_from_this_block.audio_params(), nb_samples);
for (int i=0; i<out.size(); i++) {
memcpy(new_samples->data(i), out[i].data(), out[i].size());
memcpy(new_samples.data(i), out[i].data(), out[i].size());
}
samples_from_this_block = new_samples;
@@ -346,20 +342,20 @@ NodeValueTable RenderProcessor::GenerateBlockTable(const Track *track, const Tim
}
} else {
// Multiply time
samples_from_this_block->speed(speed_value);
samples_from_this_block.speed(speed_value);
}
}
if (reversed) {
samples_from_this_block->reverse();
samples_from_this_block.reverse();
}
}
int copy_length = qMin(max_dest_sz, samples_from_this_block->sample_count());
int copy_length = qMin(max_dest_sz, samples_from_this_block.sample_count());
// Copy samples into destination buffer
for (int i=0; i<samples_from_this_block->audio_params().channel_count(); i++) {
block_range_buffer->set(i, samples_from_this_block->data(i), destination_offset, copy_length);
for (int i=0; i<samples_from_this_block.audio_params().channel_count(); i++) {
block_range_buffer.set(i, samples_from_this_block.data(i), destination_offset, copy_length);
}
NodeValueTable::Merge({merged_table, table});
@@ -372,7 +368,7 @@ NodeValueTable RenderProcessor::GenerateBlockTable(const Track *track, const Tim
waveform_info.block = clip_cast;
waveform_info.range = range_for_block - b->in();
if (!(waveform_info.silence = !samples_from_this_block.get())) {
if (!(waveform_info.silence = !samples_from_this_block.is_allocated())) {
// Generate a visual waveform from the samples acquired from this block
AudioVisualWaveform visual_waveform;
visual_waveform.set_channel_count(audio_params.channel_count());
@@ -483,7 +479,7 @@ void RenderProcessor::ProcessVideoFootage(TexturePtr destination, const FootageJ
}
}
void RenderProcessor::ProcessAudioFootage(SampleBufferPtr destination, const FootageJob &stream, const TimeRange &input_time)
void RenderProcessor::ProcessAudioFootage(SampleBuffer &destination, const FootageJob &stream, const TimeRange &input_time)
{
DecoderPtr decoder = ResolveDecoderFromInput(stream.decoder(), Decoder::CodecStream(stream.filename(), stream.audio_params().stream_index()));
@@ -526,9 +522,9 @@ void RenderProcessor::ProcessShader(TexturePtr destination, const Node *node, co
render_ctx_->BlitToTexture(shader, job, destination.get());
}
void RenderProcessor::ProcessSamples(SampleBufferPtr destination, const Node *node, const TimeRange &range, const SampleJob &job)
void RenderProcessor::ProcessSamples(SampleBuffer &destination, const Node *node, const TimeRange &range, const SampleJob &job)
{
if (!job.samples() || !job.samples()->is_allocated()) {
if (!job.samples().is_allocated()) {
return;
}
@@ -536,7 +532,7 @@ void RenderProcessor::ProcessSamples(SampleBufferPtr destination, const Node *no
const AudioParams& audio_params = GetCacheAudioParams();
for (int i=0;i<job.samples()->sample_count();i++) {
for (int i=0;i<job.samples().sample_count();i++) {
// Calculate the exact rational time at this sample
double sample_to_second = static_cast<double>(i) / static_cast<double>(audio_params.sample_rate());
+4 -4
View File
@@ -46,11 +46,11 @@ 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 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 ProcessColorTransform(TexturePtr destination, const Node *node, const ColorTransformJob& job) override;
@@ -63,9 +63,9 @@ protected:
return render_ctx_->CreateTexture(p);
}
virtual SampleBufferPtr CreateSampleBuffer(const AudioParams &params, int sample_count) override
virtual SampleBuffer CreateSampleBuffer(const AudioParams &params, int sample_count) override
{
return SampleBuffer::CreateAllocated(params, sample_count);
return SampleBuffer(params, sample_count);
}
virtual void ConvertToReferenceSpace(TexturePtr destination, TexturePtr source, const QString &input_cs) override;
+3 -3
View File
@@ -192,7 +192,7 @@ bool ExportTask::FrameDownloaded(FramePtr f, const QByteArray &hash, const QVect
return true;
}
bool ExportTask::AudioDownloaded(const TimeRange &range, SampleBufferPtr samples)
bool ExportTask::AudioDownloaded(const TimeRange &range, const SampleBuffer &samples)
{
TimeRange adjusted_range = range;
@@ -221,7 +221,7 @@ bool ExportTask::EncodeSubtitle(const SubtitleBlock *sub)
}
}
bool ExportTask::WriteAudioLoop(const TimeRange& time, SampleBufferPtr samples)
bool ExportTask::WriteAudioLoop(const TimeRange& time, const SampleBuffer &samples)
{
if (!encoder_->WriteAudio(samples)) {
SetError(encoder_->GetError());
@@ -232,7 +232,7 @@ bool ExportTask::WriteAudioLoop(const TimeRange& time, SampleBufferPtr samples)
for (auto it=audio_map_.begin(); it!=audio_map_.end(); it++) {
TimeRange t = it.key();
SampleBufferPtr s = it.value();
SampleBuffer s = it.value();
if (t.in() == audio_time_) {
// Erase from audio map since we're just about to write it
+3 -3
View File
@@ -40,7 +40,7 @@ protected:
virtual bool FrameDownloaded(FramePtr frame, const QByteArray& hash, const QVector<rational>& times) override;
virtual bool AudioDownloaded(const TimeRange& range, SampleBufferPtr samples) override;
virtual bool AudioDownloaded(const TimeRange& range, const SampleBuffer &samples) override;
virtual bool EncodeSubtitle(const SubtitleBlock *sub) override;
@@ -50,11 +50,11 @@ protected:
}
private:
bool WriteAudioLoop(const TimeRange &time, SampleBufferPtr samples);
bool WriteAudioLoop(const TimeRange &time, const SampleBuffer &samples);
QHash<rational, FramePtr> time_map_;
QHash<TimeRange, SampleBufferPtr> audio_map_;
QHash<TimeRange, SampleBuffer> audio_map_;
ColorManager* color_manager_;
+1 -1
View File
@@ -97,7 +97,7 @@ bool PreCacheTask::FrameDownloaded(FramePtr frame, const QByteArray &hash, const
return true;
}
bool PreCacheTask::AudioDownloaded(const TimeRange &range, SampleBufferPtr samples)
bool PreCacheTask::AudioDownloaded(const TimeRange &range, const SampleBuffer &samples)
{
// Pre-cache doesn't cache any audio
+1 -1
View File
@@ -40,7 +40,7 @@ protected:
virtual bool FrameDownloaded(FramePtr frame, const QByteArray& hash, const QVector<rational>& times) override;
virtual bool AudioDownloaded(const TimeRange& range, SampleBufferPtr samples) override;
virtual bool AudioDownloaded(const TimeRange& range, const SampleBuffer &samples) override;
private:
Project* project_;
+1 -1
View File
@@ -195,7 +195,7 @@ bool RenderTask::Render(ColorManager* manager,
TimeRange range = watcher->property("range").value<TimeRange>();
if (!AudioDownloaded(range, watcher->Get().value<SampleBufferPtr>())) {
if (!AudioDownloaded(range, watcher->Get().value<SampleBuffer>())) {
result = false;
}
+1 -1
View File
@@ -53,7 +53,7 @@ protected:
virtual bool FrameDownloaded(FramePtr frame, const QByteArray& hash, const QVector<rational>& times) = 0;
virtual bool AudioDownloaded(const TimeRange& range, SampleBufferPtr samples) = 0;
virtual bool AudioDownloaded(const TimeRange& range, const SampleBuffer &samples) = 0;
virtual bool EncodeSubtitle(const SubtitleBlock *subtitle);
+2 -2
View File
@@ -75,7 +75,7 @@ void AudioMonitor::Stop()
// loop will stop itself since file_ and waveform_ are null.
}
void AudioMonitor::PushSampleBuffer(SampleBufferPtr d)
void AudioMonitor::PushSampleBuffer(const SampleBuffer &d)
{
if (!params_.channel_count()) {
return;
@@ -83,7 +83,7 @@ void AudioMonitor::PushSampleBuffer(SampleBufferPtr d)
QVector<double> v(params_.channel_count(), 0);
AudioVisualWaveform::Sample summed = AudioVisualWaveform::SumSamples(d, 0, d->sample_count());
AudioVisualWaveform::Sample summed = AudioVisualWaveform::SumSamples(d, 0, d.sample_count());
AudioVisualWaveformSampleToInternalValues(summed, v);
+2 -2
View File
@@ -59,7 +59,7 @@ public:
}
}
static void PushSampleBufferOnAll(SampleBufferPtr d)
static void PushSampleBufferOnAll(const SampleBuffer &d)
{
foreach (AudioMonitor *m, instances_) {
m->PushSampleBuffer(d);
@@ -71,7 +71,7 @@ public slots:
void Stop();
void PushSampleBuffer(SampleBufferPtr samples);
void PushSampleBuffer(const SampleBuffer &samples);
void StartWaveform(const AudioVisualWaveform *waveform, const rational& start, int playback_speed);
+8 -7
View File
@@ -511,16 +511,16 @@ void ViewerWidget::ReceivedAudioBufferForPlayback()
audio_playback_queue_.pop_front();
if (watcher->HasResult()) {
SampleBufferPtr samples = watcher->Get().value<SampleBufferPtr>();
if (samples) {
SampleBuffer samples = watcher->Get().value<SampleBuffer>();
if (samples.is_allocated()) {
// If the samples must be reversed, reverse them now
if (playback_speed_ < 0) {
samples->reverse();
samples.reverse();
}
// Convert to packed data for audio output
AudioProcessor::Buffer buf;
int r = audio_processor_.Convert(samples->to_raw_ptrs(), samples->sample_count(), &buf);
int r = audio_processor_.Convert(samples.to_raw_ptrs().data(), samples.sample_count(), &buf);
// TempoProcessor may have emptied the array
if (r >= 0) {
@@ -556,8 +556,9 @@ void ViewerWidget::ReceivedAudioBufferForScrubbing()
RenderTicketWatcher *watcher = static_cast<RenderTicketWatcher *>(sender());
if (watcher->HasResult()) {
if (SampleBufferPtr samples = watcher->Get().value<SampleBufferPtr>()) {
if (samples->audio_params().channel_count() > 0) {
SampleBuffer samples = watcher->Get().value<SampleBuffer>();
if (samples.is_allocated()) {
if (samples.audio_params().channel_count() > 0) {
/* Fade code
const int kFadeSz = qMin(200, samples->sample_count()/4);
for (int i=0; i<kFadeSz; i++) {
@@ -567,7 +568,7 @@ void ViewerWidget::ReceivedAudioBufferForScrubbing()
}*/
AudioProcessor::Buffer buf;
int r = audio_processor_.Convert(samples->to_raw_ptrs(), samples->sample_count(), &buf);
int r = audio_processor_.Convert(samples.to_raw_ptrs().data(), samples.sample_count(), &buf);
if (r >= 0) {
if (!buf.empty()) {