diff options
Diffstat (limited to 'src/libjin/audio/sdl/source.cpp')
-rw-r--r-- | src/libjin/audio/sdl/source.cpp | 216 |
1 files changed, 119 insertions, 97 deletions
diff --git a/src/libjin/audio/sdl/source.cpp b/src/libjin/audio/sdl/source.cpp index 1a5c5d1..51b67e4 100644 --- a/src/libjin/audio/sdl/source.cpp +++ b/src/libjin/audio/sdl/source.cpp @@ -8,11 +8,15 @@ #define STB_VORBIS_HEADER_ONLY #include "3rdparty/stb/stb_vorbis.c" +#include "audio.h" + namespace jin { namespace audio { +#define BITS 8 + typedef struct SDLSourceCommand { typedef enum Action @@ -75,6 +79,7 @@ namespace audio char* buffer = (char*)malloc(size); memset(buffer, 0, size); fs.read(buffer, size); + fs.close(); SDLSource* source = createSource(buffer, size); free(buffer); return source; @@ -85,17 +90,15 @@ namespace audio if (mem == nullptr) return nullptr; SDLSource* source = new SDLSource(); -#define parse(FMT) case FMT : source->load##FMT(mem, size); break try { SourceType format = getType(mem, size); switch (format) { - parse(OGG); - parse(WAV); + case OGG: source->decode_ogg(mem, size); break; + case WAV: source->decode_wav(mem, size); break; } } -#undef parse catch (SourceException& exp) { delete source; @@ -117,37 +120,44 @@ namespace audio raw.data = 0; } - void SDLSource::loadWAV(void* mem, int size) + void SDLSource::decode_wav(void* mem, int size) { wav_t wav; if (wav_read(&wav, mem, size) == 0) { - raw.data = wav.data; - raw.size = wav.length * wav.bitdepth / 8; - raw.end = (char*)raw.data + raw.size; - raw.rate = wav.samplerate; - raw.bitdepth = wav.bitdepth; - raw.samples = raw.size / (wav.bitdepth / 8.f); - raw.channel = clamp(wav.channels, CHANNEL::MONO, CHANNEL::STEREO); - raw.silence = 0; + raw.data = wav.data; + raw.length = wav.length * wav.bitdepth / 8; + raw.end = (char*)raw.data + raw.length; + raw.samplerate = wav.samplerate; + raw.bitdepth = wav.bitdepth; + raw.samples = raw.length / (wav.bitdepth / 8.f) / wav.channels; + raw.channels = clamp(wav.channels, CHANNEL::MONO, CHANNEL::STEREO); } else throw SourceException(); } - void SDLSource::loadOGG(void* mem, int size) + void SDLSource::decode_ogg(void* _mem, int size) { - raw.samples = stb_vorbis_decode_memory((unsigned char*)mem, size, (int*)&raw.channel, &raw.rate, (short**)&raw.data) << 1; - raw.channel = clamp(raw.channel, CHANNEL::MONO, CHANNEL::STEREO); - raw.size = raw.samples << 1; // 2 bytes each sample - raw.bitdepth = 16; - raw.end = (char*)raw.data + raw.size; - raw.silence = 0; - - if (raw.samples < 0) - { - throw SourceException(); - } + unsigned char* mem = (unsigned char*)_mem; + int channels; + int samplerate; + short* data = (short*)raw.data; + int samples = stb_vorbis_decode_memory( + mem, + size, + &channels, + &samplerate, + &data + ); + const int bitdepth = sizeof(short) * BITS; + raw.channels = channels; + raw.samplerate = samplerate; + raw.data = data; + raw.samples = samples; + raw.length = samples * channels * sizeof(short); + raw.bitdepth = bitdepth; + raw.end = (char*)data + raw.length; } #define ActionNone(T)\ @@ -227,6 +237,85 @@ Manager::get()->pushCommand(cmd); \ ActionFloat(SetRate, rate); } + inline void SDLSource::handle( + SDLSourceManager* manager, + SDLSourceCommand* cmd + ) + { + switch (cmd->action) + { + case Command::Action::Play: + manager->removeSource(this); + manager->pushSource(this); + status.state = PLAYING; + status.pos = 0; // rewind + break; + case Command::Action::Stop: + manager->removeSource(this); + status.state = STOPPED; + status.pos = 0; // rewind + break; + case Command::Action::Pause: + manager->removeSource(this); + status.state = PAUSED; + break; + case Command::Action::Resume: + manager->removeSource(this); + manager->pushSource(this); + status.state = PLAYING; + break; + case Command::Action::Rewind: + status.state = PLAYING; + status.pos = 0; + break; + case Command::Action::SetVolume: + //float cmd->parameter._float; + break; + case Command::Action::SetLoop: + status.loop = cmd->parameter._boolean; + break; + } + } + + inline void SDLSource::process(void* buf, size_t size) + { + short* buffer = (short*)buf; // AUDIO_S16SYS + unsigned int samples = size / SDLAUDIO_BYTEDEPTH; + short* sample; + short origin; + + const char bitdepth = raw.bitdepth; + const char channles = raw.channels; + + int pos = status.pos; + int pitch = status.pitch; + int state = status.state; + bool loop = status.loop; + int volume = status.volume; + short* clip16 = nullptr; + char* clip8 = nullptr; + int clip = 0; + + if (bitdepth == 8) + clip8 = (char*)raw.data; + else if (bitdepth == 16) + clip16 = (short*)raw.data; + + for (int i = 0; i < samples; i+=2 /*˫*/) + { + /* Ƶļsampleᱻ */ + sample = buffer + i * SDLAUDIO_BYTEDEPTH; + origin = *sample; + if (bitdepth == 8) + { + clip = *clip8; + } + else if (bitdepth == 16) + clip = *clip16; + + } + } + Manager* Manager::get() { return (manager == nullptr ? manager = new Manager() : manager); @@ -243,43 +332,7 @@ Manager::get()->pushCommand(cmd); \ { source = cmd->source; if (source != nullptr) - { - switch (cmd->action) - { - case Command::Action::Play: - removeSource(source); - pushSource(source); - source->status.state = PLAYING; - source->status.pos = 0; // rewind - break; - case Command::Action::Stop: - manager->removeSource(source); - source->status.state = STOPPED; - source->status.pos = 0; // rewind - break; - case Command::Action::Pause: - manager->removeSource(source); - source->status.state = PAUSED; - break; - case Command::Action::Resume: - manager->removeSource(source); - manager->pushSource(source); - source->status.state = PLAYING; - break; - case Command::Action::Rewind: - source->status.state = PLAYING; - source->status.pos = 0; - break; - case Command::Action::SetVolume: - //float cmd->parameter._float; - break; - case Command::Action::SetLoop: - source->status.loop = cmd->parameter._boolean; - break; - /*case Command::Action::SetRate: - */ - } - } + source->handle(manager, cmd); } commands.pop(); } @@ -288,38 +341,15 @@ Manager::get()->pushCommand(cmd); \ /* AUDIO_S16SYS[size>>1] buffer */ shared void Manager::processSources(void* buf, size_t size) { - Sint16* buffer = (Sint16*)buf; - unsigned int samples = size >> 1; - memset(buffer, 0, size); + /* clear render buffer */ + memset(buf, 0, size); SDLSource* src = nullptr; std::vector<SDLSource*>::iterator it = sources.begin(); for (; it != sources.end();) { src = *it; - if (src == nullptr) - goto next; - src->status.pos; - Sint16* source = (Sint16*)((char*)src->raw.data + src->status.pos); - unsigned int remain = src->raw.samples - (src->status.pos >> 1); - for (int i = 0; i < min(remain, samples); ++i) - { - buffer[i] += (src->raw.channel == CHANNEL::STEREO ? source[i] : source[(i % 2) * 2]); - } - if (remain < samples) - { - if (!src->status.loop) - { - it = sources.erase(it); - continue; - } - int j = 0; - for (int i = samples - remain; i < samples; ++i, ++j) - buffer[i] += (src->raw.channel == CHANNEL::STEREO ? source[j] : source[j % 2 * 2]); - src->status.pos = (j << 1); - continue; - } - src->status.pos += (samples << 1); - next: + if (src != nullptr) + src->process(buf, size); ++it; } } @@ -360,13 +390,5 @@ Manager::get()->pushCommand(cmd); \ return new Command(); } - shared void Manager::collectCommand(Command* cmd) - { - if (cmd != nullptr) - { - commandsPool.push(cmd); - } - } - } }
\ No newline at end of file |