Skip to content

Commit

Permalink
audio: Resample sounds during load, not during runtime
Browse files Browse the repository at this point in the history
This improves performance a lot, especially when playing lots of sounds
with a "wrong" sample rate.
  • Loading branch information
jhasse committed Sep 28, 2024
1 parent 3c8e398 commit 5088006
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 18 deletions.
11 changes: 2 additions & 9 deletions src/Sound.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@

#include "audio.hpp"
#include "audio/Track.hpp"
#include "audio/constants.hpp"
#include "audio/effect/loop.hpp"
#include "audio/effect/pitch.hpp"
#include "audio/effect/volume.hpp"

#include <cassert>
Expand All @@ -20,14 +18,9 @@ struct Sound::Impl {
std::shared_ptr<audio::volume_control> volumeControl;
};

Sound::Sound(std::vector<float>& bufferData, long frequency)
Sound::Sound(const std::vector<float>& bufferData)
: impl(new Impl{ load_raw(bufferData)->play(), {}, {} }) {
std::shared_ptr<Stream> stream = impl->track;
if (frequency != jngl::audio::frequency) {
stream =
audio::pitch(std::move(stream), static_cast<float>(frequency) / jngl::audio::frequency);
}
impl->stream = impl->volumeControl = audio::volume(std::move(stream));
impl->stream = impl->volumeControl = audio::volume(impl->track);
}

Sound::~Sound() = default;
Expand Down
4 changes: 2 additions & 2 deletions src/Sound.hpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2019-2023 Jan Niklas Hasse <jhasse@bixense.com>
// Copyright 2019-2024 Jan Niklas Hasse <jhasse@bixense.com>
// For conditions of distribution and use, see copyright notice in LICENSE.txt

#pragma once
Expand All @@ -13,7 +13,7 @@ struct SoundParams;

class Sound {
public:
Sound(std::vector<float>& bufferData, long frequency);
explicit Sound(const std::vector<float>& bufferData);
Sound(const Sound&) = delete;
Sound& operator=(const Sound&) = delete;
Sound(Sound&&) = default;
Expand Down
50 changes: 44 additions & 6 deletions src/jngl/SoundFile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

#include "../Sound.hpp"
#include "../audio.hpp"
#include "../audio/constants.hpp"
#include "../audio/effect/pitch.hpp"
#include "../audio/effect/volume.hpp"
#include "../audio/engine.hpp"
Expand Down Expand Up @@ -122,7 +123,6 @@ SoundFile::SoundFile(const std::string& filename, std::launch) {
});

const vorbis_info* const pInfo = ov_info(&oggFile, -1);
frequency = pInfo->rate;

int bitStream;
while (true) {
Expand All @@ -144,6 +144,45 @@ SoundFile::SoundFile(const std::string& filename, std::launch) {
buffer_[start + i * 2 + 1] = buffer[pInfo->channels == 1 ? 0 : 1][i];
}
}
if (pInfo->rate != jngl::audio::frequency) {
float resampleFactor =
static_cast<float>(jngl::audio::frequency) / static_cast<float>(pInfo->rate);
auto newSize = static_cast<size_t>(static_cast<float>(buffer_.size()) * resampleFactor);
if (newSize % 2 != 0) {
++newSize;
}
std::vector<float> resampledData(newSize);

// Process left channel
for (size_t i = 0; i < newSize / 2; ++i) {
float originalIndex = static_cast<float>(i * 2) / resampleFactor;

auto index = static_cast<size_t>(originalIndex);
float fraction = originalIndex - static_cast<float>(index);

size_t originalLeftIndex = (index / 2) * 2;

const float b =
(originalLeftIndex + 2 < buffer_.size()) ? buffer_[originalLeftIndex + 2] : 0;
resampledData[i * 2] = buffer_[originalLeftIndex] * (1.0f - fraction) + b * fraction;
}

// Process right channel
for (size_t i = 0; i < newSize / 2; ++i) {
float originalIndex = static_cast<float>(i * 2 + 1) / resampleFactor;

auto index = static_cast<size_t>(originalIndex);
float fraction = originalIndex - static_cast<float>(index);

size_t originalRightIndex = (index / 2) * 2 + 1;

const float b =
(originalRightIndex + 2 < buffer_.size()) ? buffer_[originalRightIndex + 2] : 0;
resampledData[i * 2 + 1] =
buffer_[originalRightIndex] * (1.0f - fraction) + b * fraction;
}
buffer_ = std::move(resampledData);
}

debug("OK (");
debug(buffer_.size() * sizeof(float) / 1024. / 1024.);
Expand All @@ -164,7 +203,6 @@ SoundFile::SoundFile(SoundFile&& other) noexcept {
SoundFile& SoundFile::operator=(SoundFile&& other) noexcept {
sound_ = std::move(other.sound_);
buffer_ = std::move(other.buffer_);
frequency = other.frequency;
return *this;
}

Expand All @@ -173,7 +211,7 @@ void SoundFile::play() {
}

void SoundFile::play(Channel& channel) {
sound_ = std::make_shared<Sound>(buffer_, frequency);
sound_ = std::make_shared<Sound>(buffer_);
Audio::handle().play(channel, sound_);
}

Expand Down Expand Up @@ -203,7 +241,7 @@ void SoundFile::loop(Channel& channel) {
if (sound_ && sound_->isLooping()) {
return;
}
sound_ = std::make_shared<Sound>(buffer_, frequency);
sound_ = std::make_shared<Sound>(buffer_);
sound_->loop();
Audio::handle().play(channel, sound_);
}
Expand All @@ -218,8 +256,8 @@ void SoundFile::load() {
}

std::chrono::milliseconds SoundFile::length() const {
assert(frequency > 0);
return std::chrono::milliseconds{ buffer_.size() * 1000 / frequency / 2 /* stereo */ };
return std::chrono::milliseconds{ buffer_.size() * 1000 / jngl::audio::frequency /
2 /* stereo */ };
}

float SoundFile::progress() const {
Expand Down
1 change: 0 additions & 1 deletion src/jngl/SoundFile.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,6 @@ class SoundFile {
private:
std::shared_ptr<Sound> sound_;
std::vector<float> buffer_;
long frequency = -1; //< Hz
};

} // namespace jngl

0 comments on commit 5088006

Please sign in to comment.