/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ***/ #include "audiovisualwaveform.h" #include #include "config/config.h" OLIVE_NAMESPACE_ENTER const int AudioVisualWaveform::kSumSampleRate = 200; void AudioVisualWaveform::AddSum(const float *samples, int nb_samples, int nb_channels) { data_.append(SumSamples(samples, nb_samples, nb_channels)); } /* void AudioVisualWaveform::AddSamples(SampleBufferPtr samples) { if (!params_.is_valid()) { } int chunk_size = (audio_params_.sample_rate() / waveform_params.sample_rate()); qint64 start_offset = sizeof(SampleSummer::Info) + 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) { wave_file.resize(end_offset); } wave_file.seek(start_offset); for (int i=0;isample_count();i+=chunk_size) { QVector summary = SumSamples(samples, i, qMin(chunk_size, samples->sample_count_per_channel() - i)); wave_file.write(reinterpret_cast(summary.constData()), summary.size() * sizeof(SampleSummer::Sum)); } } */ void AudioVisualWaveform::OverwriteSamples(SampleBufferPtr samples, int sample_rate, const rational &start) { if (!channels_) { qWarning() << "Failed to write samples - channel count is zero"; } int start_index = time_to_samples(start); int samples_length = time_to_samples(static_cast(samples->sample_count()) / static_cast(sample_rate)); int end_index = start_index + samples_length; if (data_.size() < end_index) { data_.resize(end_index); } int chunk_size = sample_rate / kSumSampleRate; for (int i=0; i summary = SumSamples(samples, src_index, qMin(chunk_size, samples->sample_count() - src_index)); memcpy(&data_.data()[i + start_index], summary.constData(), summary.size() * sizeof(SamplePerChannel)); } } void AudioVisualWaveform::OverwriteSums(const AudioVisualWaveform &sums, const rational &start) { int start_index = time_to_samples(start); int end_index = start_index + sums.data_.size(); if (data_.size() < end_index) { data_.resize(end_index); } memcpy(&data_[start_index], sums.data_.constData(), sums.data_.size() * sizeof(SamplePerChannel)); } AudioVisualWaveform AudioVisualWaveform::Mid(const rational &time) const { int sample_index = time_to_samples(time); // Create a copy of this waveform chop the early section off AudioVisualWaveform copy = *this; copy.data_ = data_.mid(sample_index); return copy; } void AudioVisualWaveform::Append(const AudioVisualWaveform &waveform) { data_.append(waveform.data_); } void AudioVisualWaveform::TrimIn(const rational &time) { data_ = data_.mid(time_to_samples(time)); } void AudioVisualWaveform::TrimOut(const rational &time) { data_.resize(data_.size() - time_to_samples(time)); } void AudioVisualWaveform::PrependSilence(const rational &time) { int added_samples = time_to_samples(time); // Resize buffer for extra space data_.resize(data_.size() + added_samples); // Shift all data forward for (int i=data_.size()-1; i>=added_samples; i--) { data_[i] = data_[i - added_samples]; } // Fill remainder with silence for (int i=0;i AudioVisualWaveform::SumSamples(const float *samples, int nb_samples, int nb_channels) { return SumSamplesInternal(samples, nb_samples, nb_channels); } QVector AudioVisualWaveform::SumSamples(const qfloat16 *samples, int nb_samples, int nb_channels) { return SumSamplesInternal(samples, nb_samples, nb_channels); } QVector AudioVisualWaveform::SumSamples(SampleBufferPtr samples, int start_index, int length) { QVector summed_samples(samples->audio_params().channel_count()); int end_index = start_index + length; for (int i=start_index;iaudio_params().channel_count();channel++) { ClampMinMax(summed_samples[channel], samples->data()[channel][i]); } } return summed_samples; } QVector AudioVisualWaveform::ReSumSamples(const SamplePerChannel* samples, int nb_samples, int nb_channels) { QVector summed_samples(nb_channels); for (int i=0;i summed_samples[channel].max) { summed_samples[channel].max = sample.max; } } return summed_samples; } void AudioVisualWaveform::DrawSample(QPainter *painter, const QVector& sample, int x, int y, int height) { int channel_height = height / sample.size(); int channel_half_height = channel_height / 2; for (int i=0;idrawLine(x, channel_bottom - diff, x, channel_bottom); } else { int channel_mid = y + channel_height * i + channel_half_height; painter->drawLine(x, channel_mid + qRound(sample.at(i).min * static_cast(channel_half_height)), x, channel_mid + qRound(sample.at(i).max * static_cast(channel_half_height))); } } } void AudioVisualWaveform::DrawWaveform(QPainter *painter, const QRect& rect, const double& scale, const AudioVisualWaveform &samples) { int sample_index, next_sample_index = 0; QVector summary; int summary_index = -1; const QRect& viewport = painter->viewport(); QPoint top_left = painter->transform().map(viewport.topLeft()); int start = qMax(rect.x(), -top_left.x()); int end = qMin(rect.right(), -top_left.x() + viewport.width()); QVector lines; for (int i=start;i(kSumSampleRate) * static_cast(i - rect.x() + 1) / scale) * samples.channel_count()); if (summary_index != sample_index) { summary = AudioVisualWaveform::ReSumSamples(&samples.data_.at(sample_index), qMax(samples.channel_count(), next_sample_index - sample_index), samples.channel_count()); summary_index = sample_index; } DrawSample(painter, summary, i, rect.y(), rect.height()); } painter->drawLines(lines); } int AudioVisualWaveform::time_to_samples(const rational &time) const { return time_to_samples(time.toDouble()); } int AudioVisualWaveform::time_to_samples(const double &time) const { return qFloor(time * kSumSampleRate) * channels_; } template QVector AudioVisualWaveform::SumSamplesInternal(const T *samples, int nb_samples, int nb_channels) { QVector summed_samples(nb_channels); for (int i=0;i(summed_samples[i%nb_channels], samples[i]); } return summed_samples; } template void AudioVisualWaveform::ClampMinMax(AudioVisualWaveform::SamplePerChannel &sum, T value) { if (value < sum.min) { sum.min = value; } if (value > sum.max) { sum.max = value; } } OLIVE_NAMESPACE_EXIT