src/Audio.cpp in gosu-1.3.0 vs src/Audio.cpp in gosu-1.4.0

- old
+ new

@@ -1,35 +1,34 @@ -#include "AudioImpl.hpp" -#include "AudioFile.hpp" - #include <Gosu/Audio.hpp> -#include <Gosu/Math.hpp> #include <Gosu/IO.hpp> -#include <Gosu/Platform.hpp> -#include <Gosu/Utility.hpp> - -#include <cassert> -#include <cstdlib> +#include <Gosu/Math.hpp> +#include "AudioFile.hpp" +#include "AudioImpl.hpp" #include <algorithm> -using namespace std; +#include <cassert> +// These are global variables and not even thread-safe at that, but Gosu::Song is a legacy construct +// that will be replaced by a unified Sound class anyway in #562. +// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) static Gosu::Song* cur_song = nullptr; +// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) static bool cur_song_looping; -struct Gosu::Sample::Impl +struct Gosu::Sample::Impl : Gosu::Noncopyable { ALuint buffer; - Impl(AudioFile&& audio_file) + explicit Impl(AudioFile&& audio_file) + : buffer{} { al_initialize(); alGenBuffers(1, &buffer); alBufferData(buffer, audio_file.format(), &audio_file.decoded_data().front(), static_cast<ALsizei>(audio_file.decoded_data().size()), - audio_file.sample_rate()); + static_cast<ALsizei>(audio_file.sample_rate())); } - + ~Impl() { // It's hard to free things in the right order in Ruby/Gosu. // Make sure buffer isn't deleted after the context/device are shut down. if (!al_initialized()) return; @@ -40,161 +39,162 @@ Gosu::Sample::Sample() { } -Gosu::Sample::Sample(const string& filename) +Gosu::Sample::Sample(const std::string& filename) +: m_impl{new Impl(AudioFile(filename))} { - pimpl.reset(new Impl(AudioFile(filename))); } Gosu::Sample::Sample(Gosu::Reader reader) +: m_impl{new Impl(AudioFile(reader))} { - pimpl.reset(new Impl(AudioFile(reader))); } Gosu::Channel Gosu::Sample::play(double volume, double speed, bool looping) const { - return play_pan(0, volume, speed, looping); + return play_pan(0.0, volume, speed, looping); } Gosu::Channel Gosu::Sample::play_pan(double pan, double volume, double speed, bool looping) const { - if (!pimpl) return Channel(); + if (!m_impl) return Channel{}; Channel channel = allocate_channel(); - + // Couldn't allocate a free channel. if (channel.current_channel() == NO_CHANNEL) return channel; - + ALuint source = al_source_for_channel(channel.current_channel()); - alSourcei(source, AL_BUFFER, pimpl->buffer); - alSource3f(source, AL_POSITION, pan * 10, 0, 0); - alSourcef(source, AL_GAIN, max(volume, 0.0)); - alSourcef(source, AL_PITCH, speed); + alSourcei(source, AL_BUFFER, static_cast<ALint>(m_impl->buffer)); + alSource3f(source, AL_POSITION, static_cast<ALfloat>(pan * 10), 0, 0); + alSourcef(source, AL_GAIN, static_cast<ALfloat>(std::max(volume, 0.0))); + alSourcef(source, AL_PITCH, static_cast<ALfloat>(speed)); alSourcei(source, AL_LOOPING, looping ? AL_TRUE : AL_FALSE); alSourcePlay(source); return channel; } // AudioFile impl -struct Gosu::Song::Impl +struct Gosu::Song::Impl : Gosu::Noncopyable { - double volume_ = 1.0; - unique_ptr<AudioFile> file; - ALuint buffers[2]; - +private: + double m_volume = 1.0; + std::unique_ptr<AudioFile> m_file; + ALuint m_buffers[2]; + void apply_volume() { - alSourcef(al_source_for_songs(), AL_GAIN, max(volume(), 0.0)); + alSourcef(al_source_for_songs(), AL_GAIN, static_cast<ALfloat>(std::max(volume(), 0.0))); } - + bool stream_to_buffer(ALuint buffer) { char audio_data[4096 * 8]; - size_t read_bytes = file->read_data(audio_data, sizeof audio_data); + size_t read_bytes = m_file->read_data(audio_data, sizeof audio_data); if (read_bytes > 0) { - alBufferData(buffer, file->format(), audio_data, - static_cast<ALsizei>(read_bytes), file->sample_rate()); + alBufferData(buffer, m_file->format(), audio_data, static_cast<ALsizei>(read_bytes), + static_cast<ALsizei>(m_file->sample_rate())); } return read_bytes > 0; } - + public: - explicit Impl(const string& filename) + explicit Impl(const std::string& filename) + : m_buffers{}, + m_file{new AudioFile{filename}} { - file.reset(new AudioFile(filename)); - al_initialize(); - alGenBuffers(2, buffers); + alGenBuffers(2, m_buffers); } explicit Impl(Reader reader) + : m_buffers{}, + m_file{new AudioFile{reader}} { - file.reset(new AudioFile(reader)); - al_initialize(); - alGenBuffers(2, buffers); + alGenBuffers(2, m_buffers); } - + ~Impl() { // It's hard to free things in the right order in Ruby/Gosu. // Make sure buffers aren't deleted after the context/device are shut down. if (!al_initialized()) return; - - alDeleteBuffers(2, buffers); + + alDeleteBuffers(2, m_buffers); } - - void play(bool looping) + + void play() { ALuint source = al_source_for_songs(); alSource3f(source, AL_POSITION, 0, 0, 0); - alSourcef(source, AL_GAIN, max(volume(), 0.0)); + alSourcef(source, AL_GAIN, static_cast<ALfloat>(std::max(volume(), 0.0))); alSourcef(source, AL_PITCH, 1); alSourcei(source, AL_LOOPING, AL_FALSE); // need to implement this manually... - stream_to_buffer(buffers[0]); - stream_to_buffer(buffers[1]); - + stream_to_buffer(m_buffers[0]); + stream_to_buffer(m_buffers[1]); + // TODO: Not good for songs with less than two buffers full of data. - alSourceQueueBuffers(source, 2, buffers); + alSourceQueueBuffers(source, 2, m_buffers); alSourcePlay(source); } void stop() { ALuint source = al_source_for_songs(); alSourceStop(source); - // Unqueue all buffers for this source. + // Dequeue all buffers for this source. // The number of QUEUED buffers apparently includes the number of PROCESSED ones, // so getting rid of the QUEUED ones is enough. ALuint buffer; int queued; alGetSourcei(source, AL_BUFFERS_QUEUED, &queued); while (queued--) { alSourceUnqueueBuffers(source, 1, &buffer); } - - file->rewind(); + + m_file->rewind(); } - - void pause() + + static void pause() // { alSourcePause(al_source_for_songs()); } - - void resume() + + static void resume() // { alSourcePlay(al_source_for_songs()); } - - bool paused() const + + static bool paused() { ALint state; alGetSourcei(al_source_for_songs(), AL_SOURCE_STATE, &state); return state == AL_PAUSED; } - + void update() { ALuint source = al_source_for_songs(); ALuint buffer; int processed; bool active = true; - + alGetSourcei(source, AL_BUFFERS_PROCESSED, &processed); for (int i = 0; i < processed; ++i) { alSourceUnqueueBuffers(source, 1, &buffer); active = stream_to_buffer(buffer); if (active) alSourceQueueBuffers(source, 1, &buffer); } - + ALint state; alGetSourcei(source, AL_SOURCE_STATE, &state); if (active && state != AL_PLAYING && state != AL_PAUSED) { // We seemingly got starved. alSourcePlay(source); @@ -203,39 +203,39 @@ // We got starved and there is nothing left to play. stop(); if (cur_song_looping) { // Start anew. - play(true); + play(); } else { // Let the world know we're finished. cur_song = nullptr; } } } - + double volume() const { - return volume_; + return m_volume; } - + void set_volume(double volume) { - volume_ = clamp(volume, 0.0, 1.0); + m_volume = std::clamp(volume, 0.0, 1.0); apply_volume(); } }; -Gosu::Song::Song(const string& filename) +Gosu::Song::Song(const std::string& filename) +: m_impl{new Impl(filename)} { - pimpl.reset(new Impl(filename)); } Gosu::Song::Song(Reader reader) +: m_impl{new Impl(reader)} { - pimpl.reset(new Impl(reader)); } Gosu::Song::~Song() { stop(); @@ -247,62 +247,62 @@ } void Gosu::Song::play(bool looping) { if (paused()) { - pimpl->resume(); + m_impl->resume(); } - + if (cur_song && cur_song != this) { cur_song->stop(); - assert (cur_song == nullptr); + assert(cur_song == nullptr); } - + if (cur_song == nullptr) { - pimpl->play(looping); + m_impl->play(); } - + cur_song = this; cur_song_looping = looping; } void Gosu::Song::pause() { if (cur_song == this) { - pimpl->pause(); + m_impl->pause(); } } bool Gosu::Song::paused() const { - return cur_song == this && pimpl->paused(); + return cur_song == this && m_impl->paused(); } void Gosu::Song::stop() { if (cur_song == this) { - pimpl->stop(); + m_impl->stop(); cur_song = nullptr; } } bool Gosu::Song::playing() const { - return cur_song == this && !pimpl->paused(); + return cur_song == this && !m_impl->paused(); } double Gosu::Song::volume() const { - return pimpl->volume(); + return m_impl->volume(); } void Gosu::Song::set_volume(double volume) { - pimpl->set_volume(volume); + m_impl->set_volume(volume); } void Gosu::Song::update() { if (current_song()) { - current_song()->pimpl->update(); + current_song()->m_impl->update(); } }