diff options
author | chai <chaifix@163.com> | 2018-05-27 17:39:09 +0800 |
---|---|---|
committer | chai <chaifix@163.com> | 2018-05-27 17:39:09 +0800 |
commit | 4f3ea475b0c72cf83175cc69bdd128b7a306523b (patch) | |
tree | 9cfab06aabccc112f1f0217810048cbd30666ed0 /src/libjin/audio/sdl/source.cpp | |
parent | 6cc59854d349a02263a5d27810fb824a9f4d1fde (diff) |
更新音频模块
Diffstat (limited to 'src/libjin/audio/sdl/source.cpp')
-rw-r--r-- | src/libjin/audio/sdl/source.cpp | 264 |
1 files changed, 227 insertions, 37 deletions
diff --git a/src/libjin/audio/sdl/source.cpp b/src/libjin/audio/sdl/source.cpp index ecdf5b5..7d71ce7 100644 --- a/src/libjin/audio/sdl/source.cpp +++ b/src/libjin/audio/sdl/source.cpp @@ -1,34 +1,132 @@ +#include <exception> + +#include "../../math/math.h" #include "../../utils/macros.h" #include "source.h" +#include "3rdparty/wav/wav.h" +#define STB_VORBIS_HEADER_ONLY +#include "3rdparty/stb/stb_vorbis.c" namespace jin { namespace audio { - shared std::queue<SDLSource::Command*> SDLSource::commands; - shared std::stack<SDLSource::Command*> SDLSource::commandsPool; + struct SDLSourceCommand + { + typedef enum Action + { + Nothing = 0, // + Play, // ͷʼ + Stop, // ֹͣ + Pause, // + Resume, // + Rewind, // + SetVolume, // + SetLoop, // + SetRate, // + }; + + Action action; + union { + int _integer; + float _float; + bool _boolean; + const char* _string; + } parameter; + + SDLSource* source; + }; + + typedef enum STATUS + { + PLAYING = 2, + PAUSED = 4, + STOPPED = 8 + }; + +#define Command SDLSourceCommand +#define Action Command::Action +#define Manager SDLSourceManager + + shared std::queue<Command*> Manager::commands; + shared std::stack<Command*> Manager::commandsPool; + shared std::vector<SDLSource*> Manager::sources; + shared Manager* Manager::manager = nullptr; + + SDLSource::SDLSource(Type format, void* mem, int size) + : pos(0) + , pitch(0) + , status(0) + , loop(false) + { + memset(&raw, 0, sizeof(raw)); + try + { + switch (format) + { + case WAV: + loadWAV(mem, size); + break; + case OGG: + loadOGG(mem, size); + break; + } + } + catch(SourceException& exp) + { + + }; + } + + void SDLSource::loadWAV(void* mem, int size) + { + wav_t wav; + if (wav_read(&wav, mem, size) == 0) + { + raw.data = wav.data; + raw.length = wav.length; + raw.end = (char*)raw.data + raw.length; + raw.rate = wav.samplerate; + raw.bitdepth = wav.bitdepth; + raw.samples = wav.length / (wav.bitdepth / 8.f); + raw.channel = wav.channels; + raw.silence = 0; + } + else + throw SourceException(); + } + + void SDLSource::loadOGG(void* mem, int size) + { + raw.samples = stb_vorbis_decode_memory((unsigned char*)mem, size, (int*)&raw.channel, &raw.rate, (short**)&raw.data); + if (raw.samples < 0) + { + throw SourceException(); + } + } - void SDLSource::generateSamples(Uint8* streamIn, int len) + SDLSource::~SDLSource() { } + #define ActionNone(T)\ do{\ -Command* cmd = getCommand(); \ -cmd->action = Command::Action::T; \ -cmd->source = this; \ -commands.push(cmd); \ +Command* cmd = Manager::get()->getCommand();\ +cmd->action = Action::T; \ +cmd->source = this; \ +Manager::get()->pushCommand(cmd); \ } while (0) #define ActionArg(T, ARGT, ARG)\ do{\ -Command* cmd = getCommand(); \ -cmd->action = Command::Action::T; \ -cmd->ARGT = ARG; \ -cmd->source = this; \ -commands.push(cmd); \ +Command* cmd = Manager::get()->getCommand();\ +cmd->action = Action::T; \ +cmd->parameter.ARGT = ARG; \ +cmd->source = this; \ +Manager::get()->pushCommand(cmd); \ }while(0) #define ActionInt(T, INT) ActionArg(T, _integer, INT) @@ -63,7 +161,7 @@ commands.push(cmd); \ void SDLSource::isStopped() const { - + } void SDLSource::isPaused() const {} @@ -81,7 +179,7 @@ commands.push(cmd); \ bool SDLSource::setLoop(bool loop) { - ActionFloat(SetLoop, loop); + ActionBool(SetLoop, loop); return false; } @@ -90,43 +188,106 @@ commands.push(cmd); \ ActionFloat(SetRate, rate); } - shared SDLSource::Command* SDLSource::getCommand() + Manager* Manager::get() { - if (!commandsPool.empty()) - { - Command* cmd = commandsPool.top(); - commandsPool.pop(); - } - return new Command(); + return (manager == nullptr ? manager = new Manager() : manager); } - shared void SDLSource::collectCommand(SDLSource::Command* cmd) + shared void Manager::processCommands() { - if (cmd != nullptr && cmd != NULL) - { - commandsPool.push(cmd); - } - } - - shared void SDLSource::processCommand() - { - Command* cmd = NULL; - Source* source = NULL; + Command* cmd = nullptr; + SDLSource* source = nullptr; while (!commands.empty()) { cmd = commands.front(); - source = cmd->source; - + source = cmd->source; + if (source != nullptr && cmd != nullptr) + { + switch (cmd->action) + { + case Command::Action::Play: + removeSource(source); + pushSource(source); + source->status = PLAYING; + source->pos = 0; // rewind + break; + case Command::Action::Stop: + manager->removeSource(source); + source->status = STOPPED; + source->pos = 0; // rewind + break; + case Command::Action::Pause: + source->status = PAUSED; + break; + case Command::Action::Resume: + source->status = PLAYING; + break; + case Command::Action::Rewind: + source->status = PLAYING; + source->pos = 0; + break; + case Command::Action::SetVolume: + break; + case Command::Action::SetLoop: + source->loop = cmd->parameter._boolean; + break; + /*case Command::Action::SetRate: + */ + } + } commands.pop(); } } - shared void SDLSource::processSource() + shared void Manager::processSources(Uint8* buffer, int len) { + memset(buffer, 0, len); + int16_t* buf16 = (int16_t*)buffer; + int samples = len >> 1; + std::vector<SDLSource*>::iterator it = sources.begin(); + SDLSource* source = nullptr; + for (; it != sources.end(); ++it) + { + source = *it; + int16_t* data16 = (int16_t*)source->raw.data; + if (source->is(STOPPED)) + removeSource(source); + else if (source->is(PAUSED)) + continue; + else if (source->is(PLAYING)) + { + int16_t* src16 = (int16_t*)((char*)source->raw.data + source->pos); + int remainsample = (source->raw.length - source->pos) >> 1; + int bound = min(samples, remainsample); + for (int i = 0; i < bound; ++i) + { + buf16[i] += src16[i]; // mix sources + } + source->pos += (bound << 1); + if (source->pos == 0) + { + if (source->loop) + { + int j = 0; + for (int i = bound; i < samples; ++i, ++j) + { + int val = data16[j]; + buf16[i] += val; + } + source->pos = (j << 1); + continue; + } + else + { + sources.erase(it); + } + } + } + } } - shared void SDLSource::removeSource(SDLSource* source) + shared void Manager::removeSource(SDLSource* source) { std::vector<SDLSource*>::iterator it = sources.begin(); for (it = sources.begin(); it != sources.end(); ++it) @@ -139,5 +300,34 @@ commands.push(cmd); \ } } + shared void Manager::pushSource(SDLSource* source) + { + if(source != nullptr) + sources.push_back(source); + } + + shared void Manager::pushCommand(SDLSourceCommand* cmd) + { + commands.push(cmd); + } + + shared Command* Manager::getCommand() + { + if (!commandsPool.empty()) + { + Command* cmd = commandsPool.top(); + commandsPool.pop(); + } + return new Command(); + } + + shared void Manager::collectCommand(Command* cmd) + { + if (cmd != nullptr) + { + commandsPool.push(cmd); + } + } + } -} +}
\ No newline at end of file |