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