simplified and optimized samplebuffer
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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 ¶ms, const QString& cache_path, Footage::LoopMode loop_mode, RenderMode::Mode mode)
|
||||
Decoder::RetrieveAudioStatus Decoder::RetrieveAudio(SampleBuffer &dest, const TimeRange &range, const AudioParams ¶ms, 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
@@ -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 ¶ms);
|
||||
bool RetrieveAudioFromConform(SampleBuffer &sample_buffer, const QVector<QString> &conform_filenames, const TimeRange &range, Footage::LoopMode loop_mode, const AudioParams ¶ms);
|
||||
|
||||
CodecStream stream_;
|
||||
|
||||
|
||||
+1
-1
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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_);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -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())) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 ¶m_a_in, const QString ¶m_b_in, const SampleBufferPtr input, SampleBufferPtr output, int index) const
|
||||
void MathNodeBase::ProcessSamplesInternal(const NodeValueRow &values, MathNodeBase::Operation operation, const QString ¶m_a_in, const QString ¶m_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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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));
|
||||
|
||||
|
||||
@@ -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 ¶ms, int sample_count)
|
||||
virtual SampleBuffer CreateSampleBuffer(const AudioParams ¶ms, int sample_count)
|
||||
{
|
||||
// Return dummy by default
|
||||
return SampleBuffer::Create();
|
||||
return SampleBuffer();
|
||||
}
|
||||
|
||||
SampleBufferPtr CreateSampleBuffer(const AudioParams ¶ms, const rational &length)
|
||||
SampleBuffer CreateSampleBuffer(const AudioParams ¶ms, const rational &length)
|
||||
{
|
||||
if (params.is_valid()) {
|
||||
return CreateSampleBuffer(params, params.time_to_samples(length));
|
||||
} else {
|
||||
return SampleBuffer::Create();
|
||||
return SampleBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -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>(); }
|
||||
|
||||
@@ -58,7 +58,7 @@ void AudioPlaybackCache::SetParameters(const AudioParams ¶ms)
|
||||
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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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_;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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());
|
||||
|
||||
|
||||
@@ -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 ¶ms, int sample_count) override
|
||||
virtual SampleBuffer CreateSampleBuffer(const AudioParams ¶ms, 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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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_;
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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_;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
Reference in New Issue
Block a user