renderer: switched audio rendering over to planar buffers
While planar audio cannot be used for playback, it's much easier for processing. This should lead to cleaner and easier to write code in the future.
This commit is contained in:
@@ -35,7 +35,7 @@ NodeValueTable AudioRenderWorker::RenderBlock(const TrackOutput *track, const Ti
|
||||
QList<Block*> active_blocks = track->BlocksAtTimeRange(range);
|
||||
|
||||
// All these blocks will need to output to a buffer so we create one here
|
||||
QByteArray block_range_buffer(audio_params_.time_to_bytes(range.length()), 0);
|
||||
SampleBufferPtr block_range_buffer = SampleBuffer::CreateAllocated(audio_params_, audio_params_.time_to_samples(range.length()));
|
||||
|
||||
NodeValueTable merged_table;
|
||||
|
||||
@@ -46,69 +46,56 @@ NodeValueTable AudioRenderWorker::RenderBlock(const TrackOutput *track, const Ti
|
||||
|
||||
// Destination buffer
|
||||
NodeValueTable table = ProcessNode(NodeDependency(b, range_for_block));
|
||||
QByteArray samples_from_this_block = table.Take(NodeParam::kSamples).toByteArray();
|
||||
QVariant sample_val = table.Take(NodeParam::kSamples);
|
||||
|
||||
if (!samples_from_this_block.isEmpty()) {
|
||||
// Stretch samples here
|
||||
rational abs_speed = qAbs(b->speed());
|
||||
if (sample_val.isNull()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (abs_speed != 1) {
|
||||
QByteArray speed_adjusted_samples;
|
||||
SampleBufferPtr samples_from_this_block = sample_val.value<SampleBufferPtr>();
|
||||
|
||||
double clip_speed = abs_speed.toDouble();
|
||||
// Stretch samples here
|
||||
rational abs_speed = qAbs(b->speed());
|
||||
|
||||
int sample_count = audio_params_.bytes_to_samples(samples_from_this_block.size());
|
||||
if (abs_speed != 1) {
|
||||
samples_from_this_block->speed(abs_speed.toDouble());
|
||||
}
|
||||
|
||||
for (double i=0;i<sample_count;i+=clip_speed) {
|
||||
int sample_index = qFloor(i);
|
||||
int byte_index = audio_params_.samples_to_bytes(sample_index);
|
||||
if (b->is_reversed()) {
|
||||
// Reverse the audio buffer
|
||||
samples_from_this_block->reverse();
|
||||
}
|
||||
|
||||
QByteArray sample_at_this_index = samples_from_this_block.mid(byte_index, audio_params_.samples_to_bytes(1));
|
||||
speed_adjusted_samples.append(sample_at_this_index);
|
||||
}
|
||||
int destination_offset = audio_params_.time_to_samples(range_for_block.in() - range.in()) * sizeof(float);
|
||||
int max_dest_sz = audio_params_.time_to_samples(range_for_block.length()) * sizeof(float);
|
||||
int input_sz = samples_from_this_block->sample_count_per_channel() * sizeof(float);
|
||||
int actual_copy_size = qMin(max_dest_sz, input_sz);
|
||||
|
||||
samples_from_this_block = speed_adjusted_samples;
|
||||
for (int i=0;i<audio_params_.channel_count();i++) {
|
||||
memcpy(block_range_buffer->data()[i] + destination_offset,
|
||||
samples_from_this_block->data()[i],
|
||||
actual_copy_size);
|
||||
|
||||
if (input_sz < max_dest_sz) {
|
||||
memset(block_range_buffer->data()[i] + destination_offset + input_sz, 0, max_dest_sz - input_sz);
|
||||
}
|
||||
}
|
||||
|
||||
if (b->is_reversed()) {
|
||||
// Reverse the audio buffer
|
||||
AudioManager::ReverseBuffer(samples_from_this_block.data(), samples_from_this_block.size(), audio_params_.samples_to_bytes(1));
|
||||
}
|
||||
{
|
||||
// Save waveform to file
|
||||
Block* src_block = static_cast<Block*>(copy_map_->value(b));
|
||||
QDir local_appdata_dir(Config::Current()["DiskCachePath"].toString());
|
||||
QDir waveform_loc = local_appdata_dir.filePath("waveform");
|
||||
waveform_loc.mkpath(".");
|
||||
QFile wave_file(waveform_loc.filePath(QString::number(reinterpret_cast<quintptr>(src_block))));
|
||||
|
||||
int destination_offset = audio_params_.time_to_bytes(range_for_block.in() - range.in());
|
||||
int actual_copy_size = qMin(audio_params_.time_to_bytes(range_for_block.length()), samples_from_this_block.size());
|
||||
if (wave_file.open(QFile::ReadWrite)) {
|
||||
// We use S32 as a size-compatible substitute for SampleSummer::Sum which is 4 bytes in size
|
||||
AudioRenderingParams waveform_params(SampleSummer::kSumSampleRate, audio_params_.channel_layout(), SampleFormat::SAMPLE_FMT_S32);
|
||||
int chunk_size = (audio_params().sample_rate() / waveform_params.sample_rate());
|
||||
|
||||
if (destination_offset < 0
|
||||
|| destination_offset + actual_copy_size > block_range_buffer.size()) {
|
||||
qCritical() << "Tried to copy audio beyond the size of the destination buffer";
|
||||
qCritical() << " Destination size:" << block_range_buffer.size();
|
||||
qCritical() << " Destination offset:" << destination_offset;
|
||||
qCritical() << " Copy size:" << actual_copy_size;
|
||||
abort();
|
||||
} else {
|
||||
memcpy(block_range_buffer.data()+destination_offset,
|
||||
samples_from_this_block.data(),
|
||||
actual_copy_size);
|
||||
|
||||
// Save waveform to file
|
||||
Block* src_block = static_cast<Block*>(copy_map_->value(b));
|
||||
QDir local_appdata_dir(Config::Current()["DiskCachePath"].toString());
|
||||
QDir waveform_loc = local_appdata_dir.filePath("waveform");
|
||||
waveform_loc.mkpath(".");
|
||||
QFile wave_file(waveform_loc.filePath(QString::number(reinterpret_cast<quintptr>(src_block))));
|
||||
wave_file.open(QFile::ReadWrite);
|
||||
|
||||
// FIXME: Assumes 32-bit float
|
||||
float* flt_samples = reinterpret_cast<float*>(samples_from_this_block.data());
|
||||
int nb_sample = samples_from_this_block.size() / sizeof(float);
|
||||
|
||||
// FIXME: Hardcoded sample rate
|
||||
// We use S16 here as a size-compatible substitute for qfloat16/half
|
||||
AudioRenderingParams waveform_params(SampleSummer::kSumSampleRate, audio_params_.channel_layout(), SampleFormat::SAMPLE_FMT_S16);
|
||||
int chunk_size = (audio_params().sample_rate() / waveform_params.sample_rate()) * waveform_params.channel_count();
|
||||
|
||||
qint64 start_offset = waveform_params.time_to_bytes(range_for_block.in() - b->in()) * 2;
|
||||
qint64 length_offset = waveform_params.time_to_bytes(range_for_block.length()) * 2;
|
||||
qint64 start_offset = waveform_params.time_to_bytes(range_for_block.in() - b->in());
|
||||
qint64 length_offset = waveform_params.time_to_bytes(range_for_block.length());
|
||||
qint64 end_offset = start_offset + length_offset;
|
||||
|
||||
if (wave_file.size() < end_offset) {
|
||||
@@ -117,10 +104,10 @@ NodeValueTable AudioRenderWorker::RenderBlock(const TrackOutput *track, const Ti
|
||||
|
||||
wave_file.seek(start_offset);
|
||||
|
||||
for (int i=0;i<nb_sample;i+=chunk_size) {
|
||||
QVector<SampleSummer::Sum> summary = SampleSummer::SumSamples(&flt_samples[i],
|
||||
qMin(chunk_size, nb_sample - i),
|
||||
audio_params().channel_count());
|
||||
for (int i=0;i<samples_from_this_block->sample_count_per_channel();i+=chunk_size) {
|
||||
QVector<SampleSummer::Sum> summary = SampleSummer::SumSamples(samples_from_this_block,
|
||||
i,
|
||||
qMin(chunk_size, samples_from_this_block->sample_count_per_channel() - i));
|
||||
|
||||
wave_file.write(reinterpret_cast<const char*>(summary.constData()),
|
||||
summary.size() * sizeof(SampleSummer::Sum));
|
||||
@@ -137,7 +124,7 @@ NodeValueTable AudioRenderWorker::RenderBlock(const TrackOutput *track, const Ti
|
||||
NodeValueTable::Merge({merged_table, table});
|
||||
}
|
||||
|
||||
merged_table.Push(NodeParam::kSamples, block_range_buffer);
|
||||
merged_table.Push(NodeParam::kSamples, QVariant::fromValue(block_range_buffer));
|
||||
|
||||
return merged_table;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user