Skip to content

Commit

Permalink
modules/{audio-libsound,system}: Butchered audio
Browse files Browse the repository at this point in the history
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...)
  • Loading branch information
IceDragon200 committed Jul 15, 2016
1 parent eafea43 commit d3cbbce
Show file tree
Hide file tree
Showing 10 changed files with 165 additions and 37 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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)
};
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,26 @@
#include <mruby/class.h>
#include <mruby/data.h>
#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
17 changes: 16 additions & 1 deletion modules/audio-libsoundio/include/moon/audio/libsoundio/music.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,32 @@

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);
virtual ~Music();

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;
};
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};
};

Expand Down
12 changes: 6 additions & 6 deletions modules/audio-libsoundio/src/handle.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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
Expand Down
65 changes: 55 additions & 10 deletions modules/audio-libsoundio/src/mrb_music.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,48 @@
#include <mruby/numeric.h>
#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<Moon::Music*>(p);
if (music) {
delete(music);
mmrb_Music* handle = static_cast<mmrb_Music*>(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<mmrb_Music*>(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)
{
Expand All @@ -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;
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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 */
Expand Down
9 changes: 9 additions & 0 deletions modules/audio-libsoundio/src/mrb_sound.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand All @@ -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)
{
Expand Down
53 changes: 46 additions & 7 deletions modules/audio-libsoundio/src/music.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
}
18 changes: 9 additions & 9 deletions modules/audio-libsoundio/src/sound.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand All @@ -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;
}
}
2 changes: 2 additions & 0 deletions modules/system/include/moon/intern.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#ifndef MOON_INTERN_H
#define MOON_INTERN_H

#include <assert.h>

#include <string>
#include <cstring>

Expand Down

2 comments on commit d3cbbce

@archseer
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@IceDragon200 I think a better option is to create a Loop Source (like Sound/Music) that takes Sound/Music and then you only have to implement once. I'd add a seek(pos, type) where type can be set (absolute) or rel (relative), to the Source interface, and use that

@archseer
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have it planned out so maybe just leave it :P

Please sign in to comment.