Finished first rewrite draft. Not done or tested, but good enough for now.

pull/21/head
Nicolay Korslund 15 years ago
parent aafe01dccc
commit d60f0fa900

@ -1,7 +1,7 @@
#ifndef MANGLE_INPUT_FILTER_H #ifndef MANGLE_INPUT_FILTER_H
#define MANGLE_INPUT_FILTER_H #define MANGLE_INPUT_FILTER_H
#include "../sound.h" #include "../output.h"
#include <assert.h> #include <assert.h>
@ -10,39 +10,29 @@ namespace Sound {
/** /**
@brief This filter class adds file loading capabilities to a @brief This filter class adds file loading capabilities to a
Sound::Manager class, by associating an InputManager with it. Sound::SoundFactory class, by associating an SampleSourceLoader
with it.
The class takes an existing Manager able to load streams, and The class takes an existing SoundFactory able to load streams, and
associates an InputManager with it. The combined class is able to associates an SampleSourceLoader with it. The combined class is
load files directly. able to load files directly.
Example:
\code
// Add FFmpeg input to an OpenAL soud output manager. OpenAL cannot
// decode sound files on its own.
InputFilter mg(new OpenAL_Manager, new FFM_InputManager);
// We can now load filenames directly.
mg.load("file1.mp3");
\endcode
*/ */
class InputFilter : public Manager class InputFilter : public SoundFactory
{ {
protected: protected:
Manager *snd; SoundFactory *snd;
InputManager *inp; SampleSourceLoader *inp;
public: public:
/// Empty constructor /// Empty constructor
InputFilter() {} InputFilter() {}
/// Assign an input manager and a sound manager to this object /// Assign an input manager and a sound manager to this object
InputFilter(Manager *_snd, InputManager *_inp) InputFilter(SoundFactory *_snd, SampleSourceLoader *_inp)
{ set(_snd, _inp); } { set(_snd, _inp); }
/// Assign an input manager and a sound manager to this object /// Assign an input manager and a sound manager to this object
void set(Manager *_snd, InputManager *_inp) void set(SoundFactory *_snd, SampleSourceLoader *_inp)
{ {
inp = _inp; inp = _inp;
snd = _snd; snd = _snd;

@ -2,23 +2,23 @@
#define MANGLE_FFMPEG_OPENAL_H #define MANGLE_FFMPEG_OPENAL_H
#include "input_filter.h" #include "input_filter.h"
#include "input_audiere.h" #include "../sources/audiere_source.h"
#include "output_openal.h" #include "../outputs/openal_out.h"
namespace Mangle { namespace Mangle {
namespace Sound { namespace Sound {
/// A InputFilter that adds audiere decoding to OpenAL. Audiere has /// A InputFilter that adds audiere decoding to OpenAL. Audiere has
/// it's own output, but OpenAL sports 3D and other advanced features. /// it's own output, but OpenAL sports 3D and other advanced features.
class OpenAL_Audiere_Manager : public InputFilter class OpenAL_Audiere_Factory : public InputFilter
{ {
public: public:
OpenAL_Audiere_Manager() OpenAL_Audiere_Factory()
{ {
set(new OpenAL_Manager, set(new OpenAL_Factory,
new AudiereInput); new AudiereLoader);
} }
~OpenAL_Audiere_Manager() ~OpenAL_Audiere_Factory()
{ {
delete snd; delete snd;
delete inp; delete inp;

@ -1,8 +1,6 @@
#include "openal_out.h" #include "openal_out.h"
#include <assert.h> #include <assert.h>
// ALuint bufferID;
using namespace Mangle::Sound; using namespace Mangle::Sound;
// ---- Helper functions and classes ---- // ---- Helper functions and classes ----
@ -65,11 +63,6 @@ static void getALFormat(InputStream *inp, int &fmt, int &rate)
// ---- OpenAL_Sound ---- // ---- OpenAL_Sound ----
OpenAL_Sound::OpenAL_Sound(SampleSource *input)
{
}
void OpenAL_Sound::play() void OpenAL_Sound::play()
{ {
alSourcePlay(inst); alSourcePlay(inst);
@ -110,174 +103,34 @@ void OpenAL_Sound::setPos(float x, float y, float z)
checkALError("setting position"); checkALError("setting position");
} }
OpenAL_Sound::OpenAL_Sound(SampleSource *input)
Instance *OpenAL_Sound::getInstance(bool is3d, bool repeat)
{ {
assert((!repeat || !stream) && "OpenAL implementation does not support looping streams"); // Get the format
int fmt, rate;
if(stream) getALFormat(inp, fmt, rate);
return new OpenAL_Stream_Instance(source->getStream(), owner);
// Load the buffer if it hasn't been done already
if(bufferID == 0)
{
// Get an input stream and load the file from it
InputStream *inp = source->getStream();
std::vector<unsigned char> buffer;
// Add 32 kb at each increment // Read the entire stream into a buffer
const int ADD = 32*1024; BufferStream buf(input);
// Fill the buffer. We increase the buffer until it's large // Move the data into OpenAL
// enough to fit all the data. alGenBuffers(1, &bufferID);
while(true)
{
// Increase the buffer
int oldlen = buffer.size();
buffer.resize(oldlen+ADD);
// Read the data
size_t len = inp->getData(&buffer[oldlen], ADD);
// If we read less than requested, we're done.
if(len < ADD)
{
// Downsize the buffer to the right size
buffer.resize(oldlen+len);
break;
}
}
// Get the format
int fmt, rate;
getALFormat(inp, fmt, rate);
// We don't need the file anymore
inp->drop();
source->drop();
source = NULL;
// Move the data into OpenAL
alGenBuffers(1, &bufferID);
alBufferData(bufferID, fmt, &buffer[0], buffer.size(), rate);
checkALError("loading sound buffer");
} // End of buffer loading
// At this point, the file data has been loaded into the buffer
// in 'bufferID', and we should be ready to go.
assert(bufferID != 0); assert(bufferID != 0);
alBufferData(bufferID, fmt, &buf.getPtr(), buf.size(), rate);
checkALError("loading sound buffer");
return new OpenAL_Simple_Instance(bufferID); // Create a source
}
// ---- OpenAL_Simple_Instance ----
OpenAL_Simple_Instance::OpenAL_Simple_Instance(ALuint buf)
{
// Create instance and associate buffer
alGenSources(1, &inst); alGenSources(1, &inst);
alSourcei(inst, AL_BUFFER, buf); alSourcei(inst, AL_BUFFER, buf);
} }
OpenAL_Simple_Instance::~OpenAL_Simple_Instance() OpenAL_Sound::~OpenAL_Sound()
{ {
// Stop // Stop
alSourceStop(inst); alSourceStop(inst);
// Return sound // Return sound
alDeleteSources(1, &inst); alDeleteSources(1, &inst);
}
// ---- OpenAL_Stream_Instance ----
OpenAL_Stream_Instance::OpenAL_Stream_Instance(InputStream *_stream,
OpenAL_Manager *_owner)
: stream(_stream), owner(_owner)
{
// Deduce the file format from the stream info
getALFormat(stream, fmt, rate);
// Create the buffers and the sound instance
alGenBuffers(BUFS, bufs);
alGenSources(1, &inst);
checkALError("initializing");
// Fill the buffers and que them
for(int i=0; i<BUFS; i++)
queueBuffer(bufs[i]);
checkALError("buffering initial data");
// Add ourselves to the stream list
lit = owner->add_stream(this);
}
void OpenAL_Stream_Instance::queueBuffer(ALuint bId)
{
char buf[SIZE];
// Get the data
int len = stream->getData(buf, SIZE);
if(len == 0)
return;
// .. and stash it // Delete buffer
alBufferData(bId, fmt, buf, len, rate); alDeleteBuffers(1, &bufferID);
alSourceQueueBuffers(inst, 1, &bId);
}
OpenAL_Stream_Instance::~OpenAL_Stream_Instance()
{
// Remove ourselves from streaming list
owner->remove_stream(lit);
// Stop
alSourceStop(inst);
// Kill the input stream
stream->drop();
// Return sound
alDeleteSources(1, &inst);
// Delete buffers
alDeleteBuffers(BUFS, bufs);
}
void OpenAL_Stream_Instance::update()
{
ALint count;
alGetSourcei(inst, AL_BUFFERS_PROCESSED, &count);
for(int i = 0;i < count;i++)
{
// Unque a finished buffer
ALuint bId;
alSourceUnqueueBuffers(inst, 1, &bId);
// Queue a new buffer
queueBuffer(bId);
}
} }

@ -2,6 +2,7 @@
#define MANGLE_SOUND_OPENAL_OUT_H #define MANGLE_SOUND_OPENAL_OUT_H
#include "../output.h" #include "../output.h"
#include "../../stream/filters/buffer_stream.h"
#include <AL/al.h> #include <AL/al.h>
#include <AL/alc.h> #include <AL/alc.h>
@ -15,6 +16,7 @@ class OpenAL_Sound : public Sound
{ {
protected: protected:
ALuint inst; ALuint inst;
ALuint bufferID;
public: public:
OpenAL_Sound(SampleSource *input); OpenAL_Sound(SampleSource *input);
@ -39,7 +41,7 @@ class OpenAL_Sound : public Sound
void setPos(float x, float y, float z); void setPos(float x, float y, float z);
}; };
class OpenALFactory : public SoundFactory class OpenAL_Factory : public SoundFactory
{ {
ALCdevice *Device; ALCdevice *Device;
ALCcontext *Context; ALCcontext *Context;
@ -49,7 +51,7 @@ class OpenALFactory : public SoundFactory
/// Initialize object. Pass true (default) if you want the /// Initialize object. Pass true (default) if you want the
/// constructor to set up the current ALCdevice and ALCcontext for /// constructor to set up the current ALCdevice and ALCcontext for
/// you. /// you.
OpenALFactory(bool doSetup = true) OpenAL_Factory(bool doSetup = true)
: didSetup(doSetup) : didSetup(doSetup)
{ {
needsUpdate = false; needsUpdate = false;
@ -72,7 +74,7 @@ class OpenALFactory : public SoundFactory
} }
} }
~OpenALFactory() ~OpenAL_Factory()
{ {
// Deinitialize sound system // Deinitialize sound system
if(didSetup) if(didSetup)

@ -1,7 +0,0 @@
#include "audiere_imp.h"
using namespace Mangle::Sound;
AudiereManager mg;
#include "common.cpp"

@ -1,7 +0,0 @@
#include "openal_ffmpeg.h"
using namespace Mangle::Sound;
OpenAL_FFM_Manager mg;
#include "common.cpp"

@ -1,7 +1,7 @@
#include "openal_audiere.h" #include "../filters/openal_audiere.h"
using namespace Mangle::Sound; using namespace Mangle::Sound;
OpenAL_Audiere_Manager mg; OpenAL_Audiere_Factory mg;
#include "common.cpp" #include "common.cpp"

Loading…
Cancel
Save