Skip to content

Commit

Permalink
Merge pull request #108 from SirBob01/feat/rework-jukebox
Browse files Browse the repository at this point in the history
Rewrite Jukebox subsystem
  • Loading branch information
SirBob01 authored Sep 25, 2024
2 parents ce8bfe0 + dc5e6bc commit f2dbfd2
Show file tree
Hide file tree
Showing 32 changed files with 336 additions and 372 deletions.
6 changes: 3 additions & 3 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@
[submodule "submodules/Catch2"]
path = submodules/Catch2
url = [email protected]:catchorg/Catch2.git
[submodule "submodules/libsndfile"]
path = submodules/libsndfile
url = [email protected]:libsndfile/libsndfile.git
[submodule "submodules/tinyobjloader"]
path = submodules/tinyobjloader
url = [email protected]:tinyobjloader/tinyobjloader.git
[submodule "submodules/spirv-reflect"]
path = submodules/spirv-reflect
url = [email protected]:KhronosGroup/SPIRV-Reflect.git
[submodule "submodules/libsndfile"]
path = submodules/libsndfile
url = [email protected]:libsndfile/libsndfile.git
15 changes: 14 additions & 1 deletion src/Application.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,19 @@ namespace Dynamo {
settings.window_width,
settings.window_height);
_jukebox = std::make_unique<Sound::Jukebox>();

// Run audio on a separate thread
_audio_thread = std::thread([&]() {
while (is_running()) {
_jukebox->update();
}
});
}

Application::~Application() {
if (_audio_thread.joinable()) {
_audio_thread.join();
}
}

bool Application::is_running() const { return _display->is_open(); }
Expand All @@ -19,7 +32,7 @@ namespace Dynamo {
Sound::Jukebox &Application::get_jukebox() { return *_jukebox; }

void Application::update() {
// Update subsystems
// Poll for input
_display->get_input().poll();

// Tick
Expand Down
4 changes: 4 additions & 0 deletions src/Application.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include <functional>
#include <string>
#include <thread>

#include "./Sound/Jukebox.hpp"
#include "Clock.hpp"
Expand Down Expand Up @@ -46,6 +47,8 @@ namespace Dynamo {
std::unique_ptr<Display> _display;
std::unique_ptr<Sound::Jukebox> _jukebox;

std::thread _audio_thread;

Clock _clock;

public:
Expand All @@ -55,6 +58,7 @@ namespace Dynamo {
* @param settings
*/
Application(const ApplicationSettings &settings);
~Application();

/**
* @brief Check if the application is running.
Expand Down
31 changes: 31 additions & 0 deletions src/Assets/Sound.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#include "./Sound.hpp"
#include "../Utils/Log.hpp"

namespace Dynamo {
Sound::Sound load(const std::string filepath) {
SndfileHandle file(filepath.c_str(), SFM_READ, 0, 1, 0);
if (file.error()) {
Log::error("Could not load sound file `{}`: {}",
filepath,
file.strError());
}

unsigned frames = file.frames();
unsigned channels = file.channels();
unsigned sample_rate = file.samplerate();

// Read the PCM data
Sound::WaveForm interleaved(frames * channels);
file.readf(interleaved.data(), interleaved.size());

// De-interleave the data into the final waveform buffer
Sound::WaveForm waveform(frames * channels);
for (unsigned f = 0; f < frames; f++) {
for (unsigned c = 0; c < channels; c++) {
waveform[c * frames + f] = interleaved[f * channels + c];
}
}

return Sound::Sound(waveform, channels, sample_rate);
}
} // namespace Dynamo
15 changes: 15 additions & 0 deletions src/Assets/Sound.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#pragma once

#include <sndfile.hh>

#include "../Sound/Sound.hpp"

namespace Dynamo {
/**
* @brief Load a sound file.
*
* @param filepath
* @return Sound::Sound
*/
Sound::Sound load(const std::string filepath);
} // namespace Dynamo
1 change: 0 additions & 1 deletion src/Dynamo.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
#include "./Math/Vec3.hpp"
#include "./Utils/Allocator.hpp"
#include "./Utils/Bits.hpp"
#include "./Utils/ChannelData.hpp"
#include "./Utils/IdTracker.hpp"
#include "./Utils/Log.hpp"
#include "./Utils/Random.hpp"
Expand Down
24 changes: 14 additions & 10 deletions src/Sound/Chunk.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
#pragma once

#include <optional>

#include "./Filter.hpp"
#include "./Material.hpp"
#include "./Sound.hpp"

Expand All @@ -14,29 +17,30 @@ namespace Dynamo::Sound {
* to receive enough data when requested, causing glitches.
*
*/
static constexpr unsigned MAX_CHUNK_LENGTH = 1 << 9;
static constexpr unsigned MAX_CHUNK_LENGTH = 1 << 12;

/**
* @brief A chunk contains information to process a sound in small sections
* every tick.
* @brief A unit of Sound with associated processing data.
*
* @tparam Material Playback properties.
*/
template <typename Material>
struct Chunk {
static_assert(std::is_convertible<Material, StaticMaterial>::value ||
std::is_convertible<Material, DynamicMaterial>::value);
/**
* @brief Reference to the Sound data.
*
*/
std::reference_wrapper<Sound> sound;
SoundRef sound;

/**
* @brief Material properties.
*
*/
MaterialRef material;

/**
* @brief Reference to the playback material.
* @brief Optional filter.
*
*/
std::reference_wrapper<Material> material;
std::optional<FilterRef> filter;

/**
* @brief Frame offset of the chunk.
Expand Down
2 changes: 1 addition & 1 deletion src/Sound/Convolver.cpp → src/Sound/DSP/Convolver.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#include "./Convolver.hpp"
#include "../Math/Fourier.hpp"
#include "../../Math/Fourier.hpp"

namespace Dynamo::Sound {
void Convolver::initialize(WaveSample *ir, unsigned M) {
Expand Down
8 changes: 4 additions & 4 deletions src/Sound/Convolver.hpp → src/Sound/DSP/Convolver.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
#include <array>
#include <vector>

#include "../Math/Complex.hpp"
#include "../Utils/Bits.hpp"
#include "../../Math/Complex.hpp"
#include "../../Utils/Bits.hpp"

#include "./Chunk.hpp"
#include "./Sound.hpp"
#include "../Chunk.hpp"
#include "../Sound.hpp"

namespace Dynamo::Sound {
/**
Expand Down
8 changes: 4 additions & 4 deletions src/Sound/HRTF.cpp → src/Sound/DSP/HRTF.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#include "HRTF.hpp"
#include "../Math/Common.hpp"
#include "../Math/Delaunay.hpp"
#include "../Math/Triangle2.hpp"
#include "Sound/DSP/HRTF.hpp"
#include "../../Math/Common.hpp"
#include "../../Math/Delaunay.hpp"
#include "../../Math/Triangle2.hpp"

namespace Dynamo::Sound {
HRTF::HRTF() {
Expand Down
10 changes: 5 additions & 5 deletions src/Sound/HRTF.hpp → src/Sound/DSP/HRTF.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@
#include <unordered_map>
#include <vector>

#include "../Math/Quaternion.hpp"
#include "../Math/Vec2.hpp"
#include "../Math/Vec3.hpp"
#include "../../Math/Quaternion.hpp"
#include "../../Math/Vec2.hpp"
#include "../../Math/Vec3.hpp"

#include "./Data/HRIR.hpp"
#include "./Sound.hpp"
#include "../Data/HRIR.hpp"
#include "../Sound.hpp"

namespace Dynamo::Sound {
/**
Expand Down
File renamed without changes.
2 changes: 1 addition & 1 deletion src/Sound/Resample.hpp → src/Sound/DSP/Resample.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

#include <array>

#include "./Sound.hpp"
#include "../Sound.hpp"

namespace Dynamo::Sound {
/**
Expand Down
38 changes: 38 additions & 0 deletions src/Sound/Filter.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#pragma once

#include "./Listener.hpp"
#include "./Material.hpp"
#include "./Sound.hpp"

namespace Dynamo::Sound {
/**
* @brief Abstract audio filter node.
*
*/
class Filter {
public:
virtual ~Filter() = default;

/**
* @brief Apply the filter to a sound
*
* @param src Source sound buffer
* @param offset Source frame start index
* @param length Length of the chunk to be processed
* @param material Material properties of the sound
* @param listener Listener
* @return Sound&
*/
virtual const Sound &apply(Sound &src,
const unsigned offset,
const unsigned length,
const Material &material,
const ListenerProperties &listener) = 0;
};

/**
* @brief Filter reference.
*
*/
using FilterRef = std::reference_wrapper<Filter>;
} // namespace Dynamo::Sound
13 changes: 7 additions & 6 deletions src/Sound/Filters/Attenuation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,31 @@

namespace Dynamo::Sound {
Attenuation::Attenuation(float inner_radius, float cutoff_radius) :
_inner_radius(inner_radius), _cutoff_radius(cutoff_radius) {}
_inner_radius(inner_radius), _outer_radius(cutoff_radius),
_denominator(1 / (_outer_radius - _inner_radius)) {}

float Attenuation::linear(float distance) {
if (distance < _inner_radius) {
return 1;
}
if (distance > _cutoff_radius) {
if (distance > _outer_radius) {
return 0;
}
return (_cutoff_radius - distance) / (_cutoff_radius - _inner_radius);
return (_outer_radius - distance) * _denominator;
}

Sound &Attenuation::apply(Sound &src,
const unsigned src_offset,
const unsigned offset,
const unsigned length,
const DynamicMaterial &material,
const Material &material,
const ListenerProperties &listener) {
_output.resize(length, src.channels());
float distance = (material.position - listener.position).length();
float gain = linear(distance);

for (unsigned c = 0; c < _output.channels(); c++) {
for (unsigned f = 0; f < _output.frames(); f++) {
_output[c][f] = src[c][f + src_offset] * gain;
_output[c][f] = src[c][f + offset] * gain;
}
}
return _output;
Expand Down
33 changes: 10 additions & 23 deletions src/Sound/Filters/Attenuation.hpp
Original file line number Diff line number Diff line change
@@ -1,31 +1,18 @@
#pragma once

#include "./Filter.hpp"
#include "../Filter.hpp"

namespace Dynamo::Sound {
/**
* @brief Distance attenuation filter allows a sound to decrease in volume
* as it moves further away from the listener
* @brief Attenuate volume as a sound moves away from the listener.
*
*/
class Attenuation : public DynamicFilter {
/**
* @brief Output buffer
*
*/
class Attenuation : public Filter {
Sound _output;

/**
* @brief Minimum distance to attenuate
*
*/
float _inner_radius;

/**
* @brief Maximum distance to attenuate where the audio is cutoff
*
*/
float _cutoff_radius;
float _outer_radius;
float _denominator;

/**
* @brief Linear attenuation function
Expand All @@ -39,15 +26,15 @@ namespace Dynamo::Sound {
/**
* @brief Construct a new Attenuation filter object
*
* @param inner_radius Minimum distance to start attenuation
* @param cutoff_radius Maximum distance to cutoff the sound
* @param inner_radius Minimum distance to start attenuation
* @param outer_radius Maximum distance to cutoff the sound
*/
Attenuation(float inner_radius, float cutoff_radius);
Attenuation(float inner_radius, float outer_radius);

Sound &apply(Sound &src,
const unsigned src_offset,
const unsigned offset,
const unsigned length,
const DynamicMaterial &material,
const Material &material,
const ListenerProperties &listener) override;
};
} // namespace Dynamo::Sound
Loading

0 comments on commit f2dbfd2

Please sign in to comment.