aboutsummaryrefslogtreecommitdiff
path: root/src/libjin/audio/sdl/source.cpp
diff options
context:
space:
mode:
authorchai <chaifix@163.com>2018-05-27 17:39:09 +0800
committerchai <chaifix@163.com>2018-05-27 17:39:09 +0800
commit4f3ea475b0c72cf83175cc69bdd128b7a306523b (patch)
tree9cfab06aabccc112f1f0217810048cbd30666ed0 /src/libjin/audio/sdl/source.cpp
parent6cc59854d349a02263a5d27810fb824a9f4d1fde (diff)
更新音频模块
Diffstat (limited to 'src/libjin/audio/sdl/source.cpp')
-rw-r--r--src/libjin/audio/sdl/source.cpp264
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