From d3cbbce42a8a5f7e9a9a8988ad2636ef99e21c0f Mon Sep 17 00:00:00 2001 From: IceDragon200 Date: Thu, 14 Jul 2016 23:50:29 -0500 Subject: [PATCH] modules/{audio-libsound,system}: Butchered audio Eh em, butchered AUDIO. Went on a refactor spree and forgot to commit piece by piece. Attempted to setup Music looping and ran into an issue where the current position of the stream could not be obtained (I didn't look that hard either...) --- .../include/moon/audio/libsoundio/handle.hxx | 2 +- .../moon/audio/libsoundio/mrb/music.hxx | 18 +++++ .../include/moon/audio/libsoundio/music.hxx | 17 ++++- .../include/moon/audio/libsoundio/sound.hxx | 6 +- modules/audio-libsoundio/src/handle.cxx | 12 ++-- modules/audio-libsoundio/src/mrb_music.cxx | 65 ++++++++++++++++--- modules/audio-libsoundio/src/mrb_sound.cxx | 9 +++ modules/audio-libsoundio/src/music.cxx | 53 +++++++++++++-- modules/audio-libsoundio/src/sound.cxx | 18 ++--- modules/system/include/moon/intern.h | 2 + 10 files changed, 165 insertions(+), 37 deletions(-) diff --git a/modules/audio-libsoundio/include/moon/audio/libsoundio/handle.hxx b/modules/audio-libsoundio/include/moon/audio/libsoundio/handle.hxx index d448d39..6f935f8 100644 --- a/modules/audio-libsoundio/include/moon/audio/libsoundio/handle.hxx +++ b/modules/audio-libsoundio/include/moon/audio/libsoundio/handle.hxx @@ -20,7 +20,7 @@ namespace Moon { float pitch; float gain; private: - Moon::Source* source; // TODO:mrb_sound/music sources will need to be wrapped... if a source deallocates, the handle will be broken (shared_ptr) + Moon::Source* m_source; // TODO:mrb_sound/music sources will need to be wrapped... if a source deallocates, the handle will be broken (shared_ptr) }; }; diff --git a/modules/audio-libsoundio/include/moon/audio/libsoundio/mrb/music.hxx b/modules/audio-libsoundio/include/moon/audio/libsoundio/mrb/music.hxx index 4789e26..d23f2e1 100644 --- a/modules/audio-libsoundio/include/moon/audio/libsoundio/mrb/music.hxx +++ b/modules/audio-libsoundio/include/moon/audio/libsoundio/mrb/music.hxx @@ -5,8 +5,26 @@ #include #include #include "moon/api.h" +#include "moon/audio/libsoundio/music.hxx" MOON_C_API const struct mrb_data_type music_data_type; MOON_C_API void mmrb_music_init(mrb_state *mrb, struct RClass *mod); +struct mmrb_Music +{ + Moon::Music* music; + Moon::Handle* handle; + + mmrb_Music(Moon::Music* ptr) + { + music = ptr; + handle = new Moon::Handle(music); + } + + ~mmrb_Music() + { + delete handle; + } +}; + #endif diff --git a/modules/audio-libsoundio/include/moon/audio/libsoundio/music.hxx b/modules/audio-libsoundio/include/moon/audio/libsoundio/music.hxx index da1f98b..aeaa9a9 100644 --- a/modules/audio-libsoundio/include/moon/audio/libsoundio/music.hxx +++ b/modules/audio-libsoundio/include/moon/audio/libsoundio/music.hxx @@ -9,6 +9,17 @@ namespace Moon { + struct LoopSettings { + bool enabled; + unsigned int start; + unsigned int end; + + LoopSettings() : + enabled(false), + start(0), + end(0) {} + }; + class Music : public Source { public: Music(const std::string filename); @@ -16,10 +27,14 @@ namespace Moon int read(float* dst, int frames); + int length(); int channels(); int sampleRate(); + void setLoop(unsigned int loopStart, unsigned int loopEnd); + void clearLoop(); private: - SndfileHandle file; + SndfileHandle m_file; + LoopSettings m_loop; }; }; diff --git a/modules/audio-libsoundio/include/moon/audio/libsoundio/sound.hxx b/modules/audio-libsoundio/include/moon/audio/libsoundio/sound.hxx index 7068bb5..c79320d 100644 --- a/modules/audio-libsoundio/include/moon/audio/libsoundio/sound.hxx +++ b/modules/audio-libsoundio/include/moon/audio/libsoundio/sound.hxx @@ -19,12 +19,12 @@ namespace Moon int channels(); int sampleRate(); private: - float* source; // [] ? + float* m_source; // [] ? int m_channels; int m_sampleRate; - std::uint32_t totalFrames; - std::uint32_t currentFrame; + std::uint32_t m_totalFrames; + std::uint32_t m_currentFrame; }; }; diff --git a/modules/audio-libsoundio/src/handle.cxx b/modules/audio-libsoundio/src/handle.cxx index 30e5186..3d245f6 100644 --- a/modules/audio-libsoundio/src/handle.cxx +++ b/modules/audio-libsoundio/src/handle.cxx @@ -6,7 +6,7 @@ namespace Moon { Handle::Handle(Moon::Source* source) // this can take mixer as arg in the future if we have more than 1 { - this->source = source; + this->m_source = source; this->pan = 0.0f; this->pitch = 1.0f; this->gain = 1.0f; @@ -17,20 +17,20 @@ namespace Moon } - void Handle::mix(struct SoundIoChannelArea *areas, const struct SoundIoChannelLayout &layout, const float sampleRate, unsigned int frames) { + void Handle::mix(struct SoundIoChannelArea* areas, const struct SoundIoChannelLayout& layout, const float sampleRate, const unsigned int frames) { float pan = this->pan; pan = (pan + 1.0f) / 2.0f; pan = glm::clamp(pan, 0.0f, 1.0f); // resample and pitch - float sampleScale = source->sampleRate() / sampleRate * pitch; + float sampleScale = m_source->sampleRate() / sampleRate * pitch; // TODO: compare source.channels() with layout.channel_count - int channels = source->channels(); - int totalSamples = frames * channels * source->sampleRate(); + int channels = m_source->channels(); + int totalSamples = frames * channels * m_source->sampleRate(); float* chunk = new float[totalSamples]; - int actual = source->read(chunk, frames); + int actual = m_source->read(chunk, frames); //printf("Read n frames: %d\n", actual); // TODO: mixer should complain if we don't have stereo diff --git a/modules/audio-libsoundio/src/mrb_music.cxx b/modules/audio-libsoundio/src/mrb_music.cxx index 6ca0fe4..801d5dd 100644 --- a/modules/audio-libsoundio/src/mrb_music.cxx +++ b/modules/audio-libsoundio/src/mrb_music.cxx @@ -4,21 +4,48 @@ #include #include "moon/audio/libsoundio/mrb/music.hxx" #include "moon/audio/libsoundio/music.hxx" +#include "moon/audio/libsoundio/handle.hxx" #include "moon/api.h" #include "moon/intern.h" #include "moon/mrb/helpers.hxx" static void -music_free(mrb_state *mrb, void *p) +music_free(mrb_state* mrb, void* p) { - Moon::Music *music = static_cast(p); - if (music) { - delete(music); + mmrb_Music* handle = static_cast(p); + if (handle) { + Moon::Music* music = handle->music; + delete(handle); + if (music) { + delete(music); + handle->music = NULL; + } } } MOON_C_API const struct mrb_data_type music_data_type = { "Moon::Music", music_free }; +static inline mmrb_Music* +mmrb_music_container_ptr(mrb_state* mrb, mrb_value self) +{ + return static_cast(mrb_data_get_ptr(mrb, self, &music_data_type)); +} + +static inline Moon::Handle* +mmrb_music_handle_ptr(mrb_state* mrb, mrb_value self) +{ + return mmrb_music_container_ptr(mrb, self)->handle; +} + +static inline Moon::Music* +mmrb_music_ptr(mrb_state* mrb, mrb_value self) +{ + return mmrb_music_container_ptr(mrb, self)->music; +} + +/** + * @param [String] filename + */ static mrb_value music_initialize(mrb_state* mrb, mrb_value self) { @@ -27,22 +54,27 @@ music_initialize(mrb_state* mrb, mrb_value self) moon_data_cleanup(mrb, self); if (exists(filename)) { Moon::Music* music = new Moon::Music(std::string(filename)); - mrb_data_init(self, music, &music_data_type); + mmrb_Music* handle = new mmrb_Music(music); + mrb_data_init(self, handle, &music_data_type); } else { - mrb_raisef(mrb, E_SCRIPT_ERROR, + mrb_raisef(mrb, MOON_E_FILE_NOT_FOUND, "cannot load such file -- %S", mrb_str_new_cstr(mrb, filename)); } return self; } - +/** + * @param [Float] gain + * @param [Float] pitch + * @param [Float] pan + */ static mrb_value music_play(mrb_state* mrb, mrb_value self) { mrb_float gain = 1.0f; mrb_float pitch = 1.0f; - mrb_float pan = 1.0f; + mrb_float pan = 0.0f; mrb_get_args(mrb, "|fff", &gain, &pitch, &pan); // TODO return self; @@ -73,15 +105,28 @@ music_length(mrb_state* mrb, mrb_value self) return mrb_fixnum_value(0); } +/** + * @param [Integer] start_frame + * @param [Integer] end_frame + */ static mrb_value -music_loop(mrb_state* mrb, mrb_value self) +music_set_loop(mrb_state* mrb, mrb_value self) { + mrb_int start_frame = 0; + mrb_int end_frame = 0; + mrb_get_args(mrb, "ii", &start_frame, &end_frame); + if (end_frame < start_frame) { + mrb_raisef(mrb, E_ARGUMENT_ERROR, "expected end_frame to be greater than start frame"); + } + mmrb_music_ptr(mrb, self)->setLoop(start_frame, end_frame); return self; } static mrb_value music_clear_loop(mrb_state* mrb, mrb_value self) { + Moon::Music* music = mmrb_music_ptr(mrb, self); + music->clearLoop(); return self; } @@ -122,7 +167,7 @@ mmrb_music_init(mrb_state* mrb, struct RClass* mod) mrb_define_method(mrb, music_class, "seek", music_seek, MRB_ARGS_REQ(1)); mrb_define_method(mrb, music_class, "pos", music_pos, MRB_ARGS_NONE()); mrb_define_method(mrb, music_class, "length", music_length, MRB_ARGS_NONE()); - mrb_define_method(mrb, music_class, "loop", music_loop, MRB_ARGS_OPT(2)); + mrb_define_method(mrb, music_class, "set_loop", music_set_loop, MRB_ARGS_OPT(2)); mrb_define_method(mrb, music_class, "clear_loop", music_clear_loop, MRB_ARGS_NONE()); /* Query */ diff --git a/modules/audio-libsoundio/src/mrb_sound.cxx b/modules/audio-libsoundio/src/mrb_sound.cxx index bdee9a2..b26178e 100644 --- a/modules/audio-libsoundio/src/mrb_sound.cxx +++ b/modules/audio-libsoundio/src/mrb_sound.cxx @@ -19,6 +19,10 @@ sound_free(mrb_state* mrb, void *p) MOON_C_API const struct mrb_data_type sound_data_type = { "Moon::Sound", sound_free }; +/** + * @param [String] filename + * @return [self] + */ static mrb_value sound_initialize(mrb_state* mrb, mrb_value self) { @@ -30,6 +34,11 @@ sound_initialize(mrb_state* mrb, mrb_value self) return self; } +/** + * @param [Float] gain the velocity or gain of the sound (default 1.0) + * @param [Float] pitch the sound's pitch (default 1.0) + * @param [Float] pan the pan (default 0.0 (centered)) + */ static mrb_value sound_play(mrb_state* mrb, mrb_value self) { diff --git a/modules/audio-libsoundio/src/music.cxx b/modules/audio-libsoundio/src/music.cxx index c7ac070..01fd3fb 100644 --- a/modules/audio-libsoundio/src/music.cxx +++ b/modules/audio-libsoundio/src/music.cxx @@ -4,28 +4,67 @@ namespace Moon { Music::Music(const std::string filename) : - file(filename, SFM_READ) + m_file(filename, SFM_READ) { printf("Opened file '%s'\n", filename.c_str()); - printf(" Sample rate : %d\n", file.samplerate()); - printf(" Channels : %d\n", file.channels()); + printf(" Sample rate : %d\n", m_file.samplerate()); + printf(" Channels : %d\n", m_file.channels()); + m_loop.end = length(); }; - Music::~Music() { } + int Music::length() { + return m_file.frames(); + } + int Music::channels() { - return file.channels(); + return m_file.channels(); } int Music::sampleRate() { - return file.samplerate(); + return m_file.samplerate(); } // returns how many frames we actually read int Music::read(float* dst, int frames) { - return file.readf(dst, frames); + // If looping is enabled, AND the file has content + if (m_loop.enabled && length() > 0) { + // TODO: Figure out how to prevent file from being read OVER the loop.end + // If the m_file could somehow report it's current position that would be swell + int totalReadFrames = m_file.readf(dst, frames); + const int step = channels() * sizeof(float); + // While we still have frames left to fill out, keep looping + while (totalReadFrames < frames) { + // rewind to the start of the loop + m_file.seek(m_loop.start, SEEK_SET); + int diff = frames - totalReadFrames; + int readFrames = m_file.readf(dst + totalReadFrames * step, diff); + totalReadFrames += readFrames; + if (!readFrames) { + break; + } + } + return totalReadFrames; + } else { + return m_file.readf(dst, frames); + } + } + + void Music::setLoop(unsigned int loopStart, unsigned int loopEnd) + { + assert(loopStart < loopEnd); + m_loop.enabled = true; + m_loop.start = loopStart; + m_loop.end = loopEnd; + } + + void Music::clearLoop() + { + m_loop.enabled = false; + m_loop.start = 0; + m_loop.end = length(); } } diff --git a/modules/audio-libsoundio/src/sound.cxx b/modules/audio-libsoundio/src/sound.cxx index fb01bee..25ca261 100644 --- a/modules/audio-libsoundio/src/sound.cxx +++ b/modules/audio-libsoundio/src/sound.cxx @@ -14,19 +14,19 @@ namespace Moon m_channels = file.channels(); m_sampleRate = file.samplerate(); - currentFrame = 0; + m_currentFrame = 0; int totalSamples = file.frames() * m_channels * m_sampleRate; - source = new float[totalSamples]; + m_source = new float[totalSamples]; - totalFrames = file.readf(source, file.frames()); - printf("total frames: %d\n", totalFrames); + m_totalFrames = file.readf(m_source, file.frames()); + printf("total frames: %d\n", m_totalFrames); // TODO: shout if totalFrames didn't match file.frames() }; Sound::~Sound() { - delete[] source; + delete[] m_source; } int Sound::channels() { @@ -40,12 +40,12 @@ namespace Moon // returns how many frames we actually read int Sound::read(float* dst, int frames) { - if(currentFrame > totalFrames) { return 0; } + if (m_currentFrame > m_totalFrames) { return 0; } // handle buffer edges (don't point past edge) - int actual = (currentFrame + frames > totalFrames) ? totalFrames - currentFrame : frames; - memcpy(dst, &source[currentFrame * m_channels], sizeof(float) * actual * m_channels); + int actual = (m_currentFrame + frames > m_totalFrames) ? m_totalFrames - m_currentFrame : frames; + memcpy(dst, &m_source[m_currentFrame * m_channels], sizeof(float) * actual * m_channels); - currentFrame += actual; + m_currentFrame += actual; return actual; } } diff --git a/modules/system/include/moon/intern.h b/modules/system/include/moon/intern.h index 57e56b5..37bccb6 100644 --- a/modules/system/include/moon/intern.h +++ b/modules/system/include/moon/intern.h @@ -1,6 +1,8 @@ #ifndef MOON_INTERN_H #define MOON_INTERN_H +#include + #include #include