diff options
Diffstat (limited to 'src/libjin/audio')
-rw-r--r-- | src/libjin/audio/sdl/audio.cpp | 30 | ||||
-rw-r--r-- | src/libjin/audio/sdl/audio.h | 14 | ||||
-rw-r--r-- | src/libjin/audio/sdl/source.cpp | 264 | ||||
-rw-r--r-- | src/libjin/audio/sdl/source.h | 118 | ||||
-rw-r--r-- | src/libjin/audio/source.h | 6 |
5 files changed, 322 insertions, 110 deletions
diff --git a/src/libjin/audio/sdl/audio.cpp b/src/libjin/audio/sdl/audio.cpp index 7870329..d753587 100644 --- a/src/libjin/audio/sdl/audio.cpp +++ b/src/libjin/audio/sdl/audio.cpp @@ -1,22 +1,29 @@ #include "audio.h" +#include "source.h" namespace jin { namespace audio { + static void defaultCallback(void *userdata, Uint8 *stream, int size) + { + SDLAudio* audio = (SDLAudio*)userdata; + audio->processCommands(); + audio->processSources(stream, size); + } + onlyonce bool SDLAudio::_init(const SettingBase* s) { if (SDL_Init(SDL_INIT_AUDIO) < 0) return false; - - const SDLAudioSetting* setting = (SDLAudioSetting*)s; + SDLAudioSetting* setting = (SDLAudioSetting*)s; SDL_AudioSpec spec; zero(spec); - spec.freq = setting->rate; - spec.format = setting->resolution; - spec.channels = setting->channels; - spec.samples = setting->samples; + spec.freq = 44100; + spec.format = AUDIO_S16SYS; + spec.channels = 1; + spec.samples = 2048; spec.userdata = this; spec.callback = defaultCallback; @@ -36,17 +43,14 @@ namespace audio delete audio; } - shared void SDLAudio::defaultCallback(void *userdata, Uint8 *stream, int size) + void SDLAudio::processCommands() { - SDLAudio* audio = (SDLAudio*)userdata; - int16_t* buffer = (int16_t*)stream; - int len = size >> 1; - audio->processSources(len); + SDLSourceManager::get()->processCommands(); } - void SDLAudio::processSources(int len) + void SDLAudio::processSources(Uint8* buffer, int len) { - + SDLSourceManager::get()->processSources(buffer, len); } void SDLAudio::play() {} diff --git a/src/libjin/audio/sdl/audio.h b/src/libjin/audio/sdl/audio.h index 969fbd9..53d0d76 100644 --- a/src/libjin/audio/sdl/audio.h +++ b/src/libjin/audio/sdl/audio.h @@ -16,6 +16,7 @@ namespace audio public: + /* struct Setting : SettingBase { int rate; // @@ -23,6 +24,7 @@ namespace audio char channels; // int samples; // ȡ }; + */ static inline Audio* get() { @@ -40,6 +42,10 @@ namespace audio void setVolume(float volume) override; float getVolume() override; + /* process functions*/ + void processCommands(); + void processSources(Uint8* buffer, int len); + private: SDLAudio() {} @@ -50,14 +56,6 @@ namespace audio unsigned int audioDevice; - std::vector<SDLSource*> sources; - - static void defaultCallback(void *udata, Uint8 *stream, int len); - - /* process functions*/ - void processCommands(); - void processSources(int len); - }; typedef SDLAudio::Setting SDLAudioSetting; 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 diff --git a/src/libjin/audio/sdl/source.h b/src/libjin/audio/sdl/source.h index 682ff50..d97590e 100644 --- a/src/libjin/audio/sdl/source.h +++ b/src/libjin/audio/sdl/source.h @@ -4,11 +4,7 @@ #include <vector> #include <queue> #include <stack> - -#include "3rdparty/wav/wav.h" -#define STB_VORBIS_HEADER_ONLY -#include "3rdparty/stb/stb_vorbis.c" -#undef STB_VORBIS_HEADER_ONLY +#include <exception> #include "../source.h" @@ -17,15 +13,21 @@ namespace jin namespace audio { + struct SDLSourceCommand; + class SDLSource : public Source { public: - SDLSource() {} - ~SDLSource() {} + enum Type + { + WAV = 1, + OGG = 2, + }; - void generateSamples(Uint8* streamIn, int len); + SDLSource(Type format, void* mem, int size) ; + ~SDLSource(); /* ISource interface */ void play() override; @@ -41,52 +43,70 @@ namespace audio bool setLoop(bool loop) override; void setRate(float rate) override; - /* process function */ - static void processCommand(); - static void processSource(); - static void removeSource(SDLSource* source); - private: - struct Command + friend class SDLSourceManager; + + void loadWAV(void* mem, int size); + void loadOGG(void* mem, int size); + + inline bool is(int state) { return (status & state) == state; } + + struct { - 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; - }; - SDLSource* source; - }; + const void* data; // Ƶ + int length; // dataֽڳ + void* end; // dataβ = (unsigned char*)data + length + int rate; // Ƶ + unsigned char bitdepth; // ÿsampleıس + int samples; // sample = length / (bitdepth / 8) + unsigned char channel; // channel12 + char silence; // 0 + } raw; + + /* Procedure controller variable */ + int pos; // ǰŵλ + int pitch; // pitch + int status; // ǰ״̬ + bool loop; // loop or not + + }; + + class SDLSourceManager + { + + public: + + static SDLSourceManager* get(); - static std::queue<Command*> commands; - static std::stack<Command*> commandsPool; - static Command* getCommand(); - static void collectCommand(Command* cmd); - - static std::vector<SDLSource*> sources; - - void* data; - void* pos; - int length; - int pitch; - bool paused; - bool playing; - bool stopped; + /* Process function */ + static void processCommands(); + static void processSources(Uint8* buffer, int len); + + private: + + friend class SDLSource; + + static void removeSource(SDLSource* source); + static void pushSource(SDLSource* source); + static SDLSourceCommand* getCommand(); + static void pushCommand(SDLSourceCommand* cmd); + static void collectCommand(SDLSourceCommand* cmd); + static SDLSourceManager* manager; + + static std::queue<SDLSourceCommand*> commands; + static std::stack<SDLSourceCommand*> commandsPool; + static std::vector<SDLSource*> sources; // processing sources + + }; + + class SourceException : public std::exception + { + const char * what() const throw () + { + return "Load Source Exception"; + } }; } diff --git a/src/libjin/audio/source.h b/src/libjin/audio/source.h index 4ed8752..b625758 100644 --- a/src/libjin/audio/source.h +++ b/src/libjin/audio/source.h @@ -33,13 +33,13 @@ namespace audio public: + Source() {}; + virtual ~Source() {}; + /* ISource interface */ protected: - Source(); - virtual ~Source(); - }; } |