Skip to content

Commit

Permalink
Rename jngl::audio::mixer to jngl::Mixer
Browse files Browse the repository at this point in the history
  • Loading branch information
jhasse committed Sep 7, 2023
1 parent 33fcf96 commit 7bd7fb0
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 67 deletions.
2 changes: 1 addition & 1 deletion src/audio.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,6 @@ void resumeAudioDevice();
class Audio;

Audio& GetAudio();
std::shared_ptr<audio::mixer> getMixer();
std::shared_ptr<Mixer> getMixer();

} // namespace jngl
95 changes: 41 additions & 54 deletions src/audio/mixer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,84 +3,74 @@
#include <atomic_queue/atomic_queue.h>

#include <algorithm>
#include <memory>
#include <vector>
#include <atomic>
#include <memory>
#include <mutex>
#include <vector>

namespace jngl::audio {

struct mixer_impl final : mixer, std::enable_shared_from_this<mixer_impl> {
void add(std::shared_ptr<Stream> stream) override;

void remove(Stream* stream) override {
gc();
streamsToStop.push(stream);
}

std::size_t read(float* data, std::size_t sample_count) override;

void rewind() override {
assert(false);
}

private:
void gc() {
Stream* tmp;
while (streamsToRemoveOnMainThread.try_pop(tmp)) {
auto it = std::find_if(streamsOnMainThread.begin(), streamsOnMainThread.end(),
[tmp](const auto& stream) { return stream.get() == tmp; });
assert(it != streamsOnMainThread.end());
streamsOnMainThread.erase(it);
}
}
std::vector<std::shared_ptr<Stream>> streamsOnMainThread;
namespace jngl {

struct Mixer::Impl {
atomic_queue::AtomicQueue<Stream*, 10> streamsToRemoveOnMainThread;
atomic_queue::AtomicQueue<Stream*, 10> newStreams;
atomic_queue::AtomicQueue<Stream*, 10> streamsToStop;
};

constexpr static size_t MAX_ACTIVE_STREAMS = 256;
size_t numberOfActiveStreams = 0;
Stream* activeStreams[MAX_ACTIVE_STREAMS]; //< only used on mixer thread

constexpr static size_t BUFFER_SIZE = 996;
float buffer[BUFFER_SIZE];
Mixer::Mixer() : impl(std::make_unique<Impl>()) {
}
Mixer::~Mixer() = default;

atomic_queue::AtomicQueue<Stream*, 10> newStreams;
void Mixer::gc() {
Stream* tmp;
while (impl->streamsToRemoveOnMainThread.try_pop(tmp)) {
auto it = std::find_if(streamsOnMainThread.begin(), streamsOnMainThread.end(),
[tmp](const auto& stream) { return stream.get() == tmp; });
assert(it != streamsOnMainThread.end());
streamsOnMainThread.erase(it);
}
}

atomic_queue::AtomicQueue<Stream*, 10> streamsToStop;
void Mixer::remove(Stream* stream) {
gc();
impl->streamsToStop.push(stream);
}

std::atomic<std::size_t> played_{ 0 };
};
void Mixer::rewind() {
assert(false);
}

void mixer_impl::add(std::shared_ptr<Stream> stream) {
void Mixer::add(std::shared_ptr<Stream> stream) {
gc();
newStreams.push(stream.get());
impl->newStreams.push(stream.get());
streamsOnMainThread.emplace_back(std::move(stream));
}

std::size_t mixer_impl::read(float* data, std::size_t sample_count) {
size_t Mixer::read(float* data, size_t sample_count) {
if (sample_count > BUFFER_SIZE) {
size_t first = read(data, BUFFER_SIZE);
return first + read(data + BUFFER_SIZE, sample_count - BUFFER_SIZE);
}

Stream* tmp;
while (numberOfActiveStreams < MAX_ACTIVE_STREAMS && newStreams.try_pop(tmp)) {
while (numberOfActiveStreams < MAX_ACTIVE_STREAMS && impl->newStreams.try_pop(tmp)) {
activeStreams[numberOfActiveStreams++] = tmp;
}
while (streamsToStop.try_pop(tmp)) {
while (impl->streamsToStop.try_pop(tmp)) {
auto it = std::find(activeStreams, activeStreams + numberOfActiveStreams, tmp);
if (it != activeStreams + numberOfActiveStreams) {
*it = activeStreams[--numberOfActiveStreams]; // move the last element to the one to be erased
streamsToRemoveOnMainThread.push(tmp);
*it = activeStreams[--numberOfActiveStreams]; // move the last element to the one to be
// erased
impl->streamsToRemoveOnMainThread.push(tmp);
}
}

std::fill(data, data + sample_count, 0.f);

for (auto it = activeStreams; it != activeStreams + numberOfActiveStreams;) {
auto& stream = *it;
if (!stream) continue;
if (!stream) {
continue;
}

auto read = stream->read(buffer, sample_count);

Expand All @@ -94,8 +84,9 @@ std::size_t mixer_impl::read(float* data, std::size_t sample_count) {
}

if (read < sample_count) {
streamsToRemoveOnMainThread.push(*it);
*it = activeStreams[--numberOfActiveStreams]; // move the last element to the one to be erased
impl->streamsToRemoveOnMainThread.push(*it);
*it = activeStreams[--numberOfActiveStreams]; // move the last element to the one to be
// erased
} else {
++it;
}
Expand All @@ -106,8 +97,4 @@ std::size_t mixer_impl::read(float* data, std::size_t sample_count) {
return sample_count;
}

mixer_ptr make_mixer() {
return std::make_shared<mixer_impl>();
}

} // namespace jngl::audio
} // namespace jngl
38 changes: 30 additions & 8 deletions src/audio/mixer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,38 @@
#include "Stream.hpp"

#include <memory>
#include <vector>

namespace jngl::audio {
namespace jngl {

struct mixer : Stream {
virtual void add(std::shared_ptr<Stream> stream) = 0;
virtual void remove(Stream*) = 0;
};
class Mixer : public Stream {
public:
Mixer();
~Mixer() override;

void add(std::shared_ptr<Stream> stream);
void remove(Stream*);

void rewind() override;
size_t read(float*, size_t) override;

private:
void gc();

struct Impl;
std::unique_ptr<Impl> impl;

using mixer_ptr = std::shared_ptr<mixer>;
size_t numberOfActiveStreams = 0;

mixer_ptr make_mixer();
constexpr static size_t BUFFER_SIZE = 996;
float buffer[BUFFER_SIZE] = { 0 };

constexpr static size_t MAX_ACTIVE_STREAMS = 256;
Stream* activeStreams[MAX_ACTIVE_STREAMS] = { nullptr }; //< only used on mixer thread

std::atomic<std::size_t> played_{ 0 };

std::vector<std::shared_ptr<Stream>> streamsOnMainThread;
};

} // namespace jngl::audio
} // namespace jngl
8 changes: 4 additions & 4 deletions src/jngl/SoundFile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ std::unordered_map<std::string, std::shared_ptr<SoundFile>> sounds;
class Audio {
public:
Audio()
: mixer(jngl::audio::make_mixer()), pitchControl(audio::pitch(mixer)),
: mixer(std::make_shared<Mixer>()), pitchControl(audio::pitch(mixer)),
volumeControl(volume(pitchControl)), engine(volumeControl) {
}
Audio(const Audio&) = delete;
Expand Down Expand Up @@ -73,13 +73,13 @@ class Audio {
void setVolume(float volume) {
volumeControl->gain(volume);
}
std::shared_ptr<audio::mixer> getMixer() {
std::shared_ptr<Mixer> getMixer() {
return mixer;
}

private:
std::vector<std::shared_ptr<Sound>> sounds_;
std::shared_ptr<audio::mixer> mixer;
std::shared_ptr<Mixer> mixer;
std::shared_ptr<audio::pitch_control> pitchControl;
std::shared_ptr<audio::volume_control> volumeControl;
audio::engine engine;
Expand Down Expand Up @@ -248,7 +248,7 @@ Audio& GetAudio() {
return audio;
}

std::shared_ptr<audio::mixer> getMixer() {
std::shared_ptr<Mixer> getMixer() {
return GetAudio().getMixer();
}

Expand Down

0 comments on commit 7bd7fb0

Please sign in to comment.