audio: use std vectors and size_t for sample indices

This commit is contained in:
itsmattkc
2022-09-01 12:52:23 -07:00
parent 4f53869b98
commit 21231540fd
4 changed files with 72 additions and 68 deletions
+60 -56
View File
@@ -39,50 +39,50 @@ AudioVisualWaveform::AudioVisualWaveform() :
}
}
void AudioVisualWaveform::OverwriteSamplesFromBuffer(const SampleBuffer &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, size_t &start_index, size_t &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);
int end_index = start_index + samples_length;
size_t end_index = start_index + samples_length;
if (data.size() < end_index) {
data.resize(end_index);
}
double chunk_size = double(sample_rate) / double(target_rate);
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());
for (size_t i=0; i<samples_length; i+=channels_) {
size_t src_start = qRound((double(i) * chunk_size)) / channels_;
size_t src_end = qMin(size_t(qRound64((double(i + channels_) * chunk_size))) / channels_, samples.sample_count());
Sample summary = SumSamples(samples,
src_start,
src_end - src_start);
memcpy(&data.data()[i + start_index],
summary.constData(),
summary.data(),
summary.size() * sizeof(SamplePerChannel));
}
}
void AudioVisualWaveform::OverwriteSamplesFromMipmap(const AudioVisualWaveform::Sample &input, double input_sample_rate, int &input_start, int &input_length, const rational &start, double output_rate, AudioVisualWaveform::Sample &output_data)
void AudioVisualWaveform::OverwriteSamplesFromMipmap(const AudioVisualWaveform::Sample &input, double input_sample_rate, size_t &input_start, size_t &input_length, const rational &start, double output_rate, AudioVisualWaveform::Sample &output_data)
{
int start_index = time_to_samples(start, output_rate);
int samples_length = time_to_samples(static_cast<double>(input_length / channels_) / input_sample_rate, output_rate);
size_t start_index = time_to_samples(start, output_rate);
size_t samples_length = time_to_samples(static_cast<double>(input_length / channels_) / input_sample_rate, output_rate);
int end_index = start_index + samples_length;
size_t end_index = start_index + samples_length;
if (output_data.size() < end_index) {
output_data.resize(end_index);
}
// We guarantee mipmaps are powers of two so integer division should be perfectly accurate here
int chunk_size = input_sample_rate / output_rate;
size_t chunk_size = input_sample_rate / output_rate;
for (int i=0; i<samples_length; i+=channels_) {
Sample summary = ReSumSamples(&input.constData()[input_start + (i*chunk_size)], chunk_size * channels_, channels_);
for (size_t i=0; i<samples_length; i+=channels_) {
Sample summary = ReSumSamples(&input.data()[input_start + (i*chunk_size)], chunk_size * channels_, channels_);
memcpy(&output_data.data()[i + start_index],
summary.constData(),
summary.data(),
summary.size() * sizeof(SamplePerChannel));
}
@@ -100,14 +100,14 @@ void AudioVisualWaveform::OverwriteSamples(const SampleBuffer &samples, int samp
// Old less optimized code. Keeping this around as a reference, but the below code is at least
// 10x faster so this shouldn't be used in production.
//
// int input_start, input_length;
// size_t input_start, input_length;
// for (auto it=mipmapped_data_.begin(); it!=mipmapped_data_.end(); it++) {
// OverwriteSamplesFromBuffer(samples, sample_rate, start, it->first.toDouble(), it->second, input_start, input_length);
// }
// Process the largest mipmap directly for the samples
auto current_mipmap = mipmapped_data_.rbegin();
int input_start, input_length;
size_t input_start, input_length;
OverwriteSamplesFromBuffer(samples, sample_rate, start, current_mipmap->first.toDouble(), current_mipmap->second, input_start, input_length);
while (true) {
@@ -139,16 +139,16 @@ void AudioVisualWaveform::OverwriteSums(const AudioVisualWaveform &sums, const r
double rate_dbl = rate.toDouble();
// Get our destination sample
int our_start_index = time_to_samples(dest, rate_dbl);
size_t our_start_index = time_to_samples(dest, rate_dbl);
// Get our source sample
int their_start_index = time_to_samples(offset, rate_dbl);
size_t their_start_index = time_to_samples(offset, rate_dbl);
if (their_start_index >= their_arr.size()) {
continue;
}
// Determine how much we're copying
int copy_len = their_arr.size() - their_start_index;
size_t copy_len = their_arr.size() - their_start_index;
if (!length.isNull()) {
copy_len = qMin(copy_len, time_to_samples(length, rate_dbl));
if (copy_len == 0) {
@@ -157,13 +157,13 @@ void AudioVisualWaveform::OverwriteSums(const AudioVisualWaveform &sums, const r
}
// Determine end index of our array
int end_index = our_start_index + copy_len;
size_t end_index = our_start_index + copy_len;
if (our_arr.size() < end_index) {
our_arr.resize(end_index);
}
memcpy(reinterpret_cast<char*>(our_arr.data()) + our_start_index * sizeof(SamplePerChannel),
reinterpret_cast<const char*>(their_arr.constData()) + their_start_index * sizeof(SamplePerChannel),
reinterpret_cast<const char*>(their_arr.data()) + their_start_index * sizeof(SamplePerChannel),
copy_len * sizeof(SamplePerChannel));
}
@@ -180,9 +180,9 @@ void AudioVisualWaveform::OverwriteSilence(const rational &start, const rational
double rate_dbl = rate.toDouble();
// Get our destination sample
int our_start_index = time_to_samples(start, rate_dbl);
int our_length_index = time_to_samples(length, rate_dbl);
int our_end_index = our_start_index + our_length_index;
size_t our_start_index = time_to_samples(start, rate_dbl);
size_t our_length_index = time_to_samples(length, rate_dbl);
size_t our_end_index = our_start_index + our_length_index;
if (our_arr.size() < our_end_index) {
our_arr.resize(our_end_index);
@@ -192,27 +192,31 @@ void AudioVisualWaveform::OverwriteSilence(const rational &start, const rational
}
}
void AudioVisualWaveform::TrimIn(const rational &length)
void AudioVisualWaveform::TrimIn(rational length)
{
if (length == 0) {
return;
}
bool negative = (length < 0);
if (negative) {
length = -length;
}
for (auto it=mipmapped_data_.begin(); it!=mipmapped_data_.end(); it++) {
rational rate = it->first;
double rate_dbl = rate.toDouble();
Sample& data = it->second;
int chop_length = time_to_samples(length, rate_dbl);
size_t chop_length = time_to_samples(length, rate_dbl);
if (chop_length == 0) {
continue;
}
if (chop_length > 0) {
data = data.mid(chop_length);
if (!negative) {
data = Sample(data.begin() + chop_length, data.end());
} else {
data.insert(0, -chop_length, SamplePerChannel());
data.insert(data.begin(), chop_length, SamplePerChannel());
}
}
@@ -248,7 +252,7 @@ void AudioVisualWaveform::Resize(const rational &length)
double rate_dbl = rate.toDouble();
Sample& data = it->second;
int chop_length = time_to_samples(length, rate_dbl);
size_t chop_length = time_to_samples(length, rate_dbl);
data.resize(chop_length);
}
@@ -269,10 +273,10 @@ AudioVisualWaveform::Sample AudioVisualWaveform::GetSummaryFromTime(const ration
double rate_dbl = using_mipmap->first.toDouble();
int start_sample = time_to_samples(start, rate_dbl);
int sample_length = time_to_samples(length, rate_dbl);
size_t start_sample = time_to_samples(start, rate_dbl);
size_t sample_length = time_to_samples(length, rate_dbl);
const QVector<AudioVisualWaveform::SamplePerChannel> &mipmap_data = using_mipmap->second;
const Sample &mipmap_data = using_mipmap->second;
// Determine if the array actually has this sample
sample_length = qMin(sample_length, mipmap_data.size() - start_sample);
@@ -280,14 +284,14 @@ AudioVisualWaveform::Sample AudioVisualWaveform::GetSummaryFromTime(const ration
// Based on the above `min`, if sample length <= 0, that means start_sample >= the size of the
// array and nothing can be returned.
if (sample_length > 0) {
return ReSumSamples(&mipmap_data.constData()[start_sample], sample_length, channels_);
return ReSumSamples(&mipmap_data.data()[start_sample], sample_length, channels_);
}
// Return null samples
return AudioVisualWaveform::Sample(channel_count(), {0, 0});
}
void ExpandMinMaxChannel(const float *a, int start, int length, float &min_val, float &max_val)
void ExpandMinMaxChannel(const float *a, size_t start, size_t length, float &min_val, float &max_val)
{
#if defined(Q_PROCESSOR_X86) || defined(Q_PROCESSOR_ARM)
// SSE optimized
@@ -298,7 +302,7 @@ void ExpandMinMaxChannel(const float *a, int start, int length, float &min_val,
// loop over 'a' and compare current elements with min and max 4 by 4.
// we need to make sure we don't read out of boundaries should 'a' length be not mod. 4
for(int i = 4; i < length-4; i+=4) {
for(size_t i = 4; i < length-4; i+=4) {
__m128 cur = _mm_loadu_ps(a + start + i);
max = _mm_max_ps(max, cur);
min = _mm_min_ps(min, cur);
@@ -311,7 +315,7 @@ void ExpandMinMaxChannel(const float *a, int start, int length, float &min_val,
// min and max will contain 4 min and max. To get the absolute min and max
// we need to compare the 4 values over themselves by shuffling each time.
for (int i = 0; i < 3; i++) {
for (size_t i = 0; i < 3; i++) {
max = _mm_max_ps(max, _mm_shuffle_ps(max, max, 0x93));
min = _mm_min_ps(min, _mm_shuffle_ps(min, min, 0x93));
}
@@ -323,15 +327,15 @@ void ExpandMinMaxChannel(const float *a, int start, int length, float &min_val,
// I bet you don't find annotated low level code very often.
#else
// Standard unoptimized function
int end = start + length;
for (int i=start; i<end; i++) {
size_t end = start + length;
for (size_t i=start; i<end; i++) {
min_val = std::min(min_val, a[i]);
max_val = std::max(max_val, a[i]);
}
#endif
}
AudioVisualWaveform::Sample AudioVisualWaveform::SumSamples(const SampleBuffer &samples, int start_index, int length)
AudioVisualWaveform::Sample AudioVisualWaveform::SumSamples(const SampleBuffer &samples, size_t start_index, size_t length)
{
int channels = samples.audio_params().channel_count();
AudioVisualWaveform::Sample summed_samples(channels);
@@ -341,7 +345,7 @@ AudioVisualWaveform::Sample AudioVisualWaveform::SumSamples(const SampleBuffer &
}
// for reference: this approximation is n x faster (and less accurate) for a n-tracks clip
// for (int i=start_index; i<end_index; i++) {
// for (size_t i=start_index; i<end_index; i++) {
// ExpandMinMax(summed_samples[i%channels], samples->data(i%channels)[i]);
// }
@@ -349,12 +353,12 @@ AudioVisualWaveform::Sample AudioVisualWaveform::SumSamples(const SampleBuffer &
}
AudioVisualWaveform::Sample AudioVisualWaveform::ReSumSamples(const SamplePerChannel* samples,
int nb_samples,
size_t nb_samples,
int nb_channels)
{
AudioVisualWaveform::Sample summed_samples(nb_channels);
for (int i=0;i<nb_samples;i+=nb_channels) {
for (size_t i=0;i<nb_samples;i+=nb_channels) {
for (int j=0;j<nb_channels;j++) {
const AudioVisualWaveform::SamplePerChannel& sample = samples[i + j];
@@ -373,14 +377,14 @@ AudioVisualWaveform::Sample AudioVisualWaveform::ReSumSamples(const SamplePerCha
void AudioVisualWaveform::DrawSample(QPainter *painter, const Sample& sample, int x, int y, int height, bool rectified)
{
if (sample.isEmpty()) {
if (sample.empty()) {
return;
}
int channel_height = height / sample.size();
int channel_half_height = channel_height / 2;
for (int i=0;i<sample.size();i++) {
for (size_t i=0;i<sample.size();i++) {
float max = qMin(sample.at(i).max, 1.0f);
float min = qMax(sample.at(i).min, -1.0f);
@@ -418,27 +422,27 @@ void AudioVisualWaveform::DrawWaveform(QPainter *painter, const QRect& rect, con
double rate_dbl = rate.toDouble();
const Sample& arr = using_mipmap->second;
int start_sample_index = samples.time_to_samples(start_time, rate_dbl);
size_t start_sample_index = samples.time_to_samples(start_time, rate_dbl);
if (start_sample_index >= arr.size()) {
return;
}
int next_sample_index = start_sample_index;
int sample_index;
size_t next_sample_index = start_sample_index;
size_t sample_index;
Sample summary;
int summary_index = -1;
size_t 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());
size_t start = qMax(rect.x(), -top_left.x());
size_t end = qMin(rect.right(), -top_left.x() + viewport.width());
bool rectified = OLIVE_CONFIG("RectifiedWaveforms").toBool();
for (int i=start;i<end;i++) {
for (size_t i=start;i<end;i++) {
sample_index = next_sample_index;
if (sample_index == arr.size()) {
@@ -450,7 +454,7 @@ void AudioVisualWaveform::DrawWaveform(QPainter *painter, const QRect& rect, con
if (summary_index != sample_index) {
summary = AudioVisualWaveform::ReSumSamples(&arr.at(sample_index),
qMax(samples.channel_count(), next_sample_index - sample_index),
qMax(size_t(samples.channel_count()), next_sample_index - sample_index),
samples.channel_count());
summary_index = sample_index;
}
@@ -459,12 +463,12 @@ void AudioVisualWaveform::DrawWaveform(QPainter *painter, const QRect& rect, con
}
}
int AudioVisualWaveform::time_to_samples(const rational &time, double sample_rate) const
size_t AudioVisualWaveform::time_to_samples(const rational &time, double sample_rate) const
{
return time_to_samples(time.toDouble(), sample_rate);
}
int AudioVisualWaveform::time_to_samples(const double &time, double sample_rate) const
size_t AudioVisualWaveform::time_to_samples(const double &time, double sample_rate) const
{
return qFloor(time * sample_rate) * channels_;
}
+8 -8
View File
@@ -43,7 +43,7 @@ public:
float max;
};
using Sample = QVector<SamplePerChannel>;
using Sample = std::vector<SamplePerChannel>;
int channel_count() const
{
@@ -90,7 +90,7 @@ public:
void OverwriteSilence(const rational &start, const rational &length);
void TrimIn(const rational &length);
void TrimIn(rational length);
AudioVisualWaveform Mid(const rational &offset) const;
AudioVisualWaveform Mid(const rational &offset, const rational &length) const;
@@ -101,9 +101,9 @@ public:
Sample GetSummaryFromTime(const rational& start, const rational& length) const;
static Sample SumSamples(const SampleBuffer &samples, int start_index, int length);
static Sample SumSamples(const SampleBuffer &samples, size_t start_index, size_t length);
static Sample ReSumSamples(const SamplePerChannel *samples, int nb_samples, int nb_channels);
static Sample ReSumSamples(const SamplePerChannel *samples, size_t nb_samples, int nb_channels);
static void DrawSample(QPainter* painter, const Sample &sample, int x, int y, int height, bool rectified);
@@ -114,12 +114,12 @@ public:
static const rational kMaximumSampleRate;
private:
void OverwriteSamplesFromBuffer(const SampleBuffer &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, size_t &start_index, size_t &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);
void OverwriteSamplesFromMipmap(const Sample& input, double input_sample_rate, size_t &input_start, size_t &input_length, const rational& start, double output_rate, Sample &output_data);
int time_to_samples(const rational& time, double sample_rate) const;
int time_to_samples(const double& time, double sample_rate) const;
size_t time_to_samples(const rational& time, double sample_rate) const;
size_t time_to_samples(const double& time, double sample_rate) const;
std::map<rational, Sample>::const_iterator GetMipmapForScale(double scale) const;
+1 -1
View File
@@ -81,7 +81,7 @@ AudioVisualWaveform::Sample AudioWaveformCache::GetSummaryFromTime(const rationa
AudioVisualWaveform::Sample result;
for (auto it=sample.cbegin(); it!=sample.cend(); it++) {
result.append(it.value());
result.insert(result.end(), it.value().begin(), it.value().end());
}
return result;
+3 -3
View File
@@ -315,8 +315,8 @@ NodeValueTable RenderProcessor::GenerateBlockTable(const Track *track, const Tim
TimeRange range_for_block(qMax(b->in(), range.in()),
qMin(b->out(), range.out()));
int destination_offset = audio_params.time_to_samples(range_for_block.in() - range.in());
int max_dest_sz = audio_params.time_to_samples(range_for_block.length());
qint64 destination_offset = audio_params.time_to_samples(range_for_block.in() - range.in());
qint64 max_dest_sz = audio_params.time_to_samples(range_for_block.length());
// Destination buffer
NodeValueTable table = GenerateTable(b, Track::TransformRangeForBlock(b, range_for_block));
@@ -380,7 +380,7 @@ NodeValueTable RenderProcessor::GenerateBlockTable(const Track *track, const Tim
}
}
int copy_length = qMin(max_dest_sz, samples_from_this_block.sample_count());
qint64 copy_length = qMin(max_dest_sz, qint64(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++) {