Moved OpenAL_Sound to cpp file, added delayed buffer creation (prelude for streaming)

This commit is contained in:
Nicolay Korslund 2010-08-17 11:25:26 +02:00
parent c982f701ca
commit 932465442b
6 changed files with 145 additions and 86 deletions

View file

@ -72,7 +72,7 @@ class Sound
/** Playback status is not cloned, only the sound data
itself. Back-ends can use this as a means of sharing data and
saving memory. */
virtual SoundPtr clone() const = 0;
virtual SoundPtr clone() = 0;
/// Virtual destructor
virtual ~Sound() {}

View file

@ -4,6 +4,9 @@
#include "../../stream/filters/buffer_stream.hpp"
#include "../../tools/str_exception.hpp"
#include <AL/al.h>
#include <AL/alc.h>
using namespace Mangle::Sound;
// ---- Helper functions and classes ----
@ -69,17 +72,91 @@ static void getALFormat(SampleSourcePtr inp, int &fmt, int &rate)
fail("Unsupported input format");
}
/// OpenAL sound output
class OpenAL_Sound : public Sound
{
ALuint inst;
ALuint bufferID;
// Poor mans reference counting. Might improve this later. When
// NULL, the buffer has not been set up yet.
int *refCnt;
bool streaming;
// Input stream
SampleSourcePtr input;
void setupBuffer();
public:
/// Read samples from the given input buffer
OpenAL_Sound(SampleSourcePtr input);
/// Play an existing buffer, with a given ref counter. Used
/// internally for cloning.
OpenAL_Sound(ALuint buf, int *ref);
~OpenAL_Sound();
void play();
void stop();
void pause();
bool isPlaying() const;
void setVolume(float);
void setPos(float x, float y, float z);
void setPitch(float);
void setRepeat(bool);
void setStreaming(bool s) { streaming = s; }
SoundPtr clone();
// a = AL_REFERENCE_DISTANCE
// b = AL_MAX_DISTANCE
// c = ignored
void setRange(float a, float b=0.0, float c=0.0);
/// Not implemented
void setPan(float) {}
};
// ---- OpenAL_Factory ----
OpenAL_Factory::OpenAL_Factory(bool doSetup)
: didSetup(doSetup)
SoundPtr OpenAL_Factory::loadRaw(SampleSourcePtr input)
{
needsUpdate = false;
return SoundPtr(new OpenAL_Sound(input));
}
void OpenAL_Factory::update()
{
}
void OpenAL_Factory::setListenerPos(float x, float y, float z,
float fx, float fy, float fz,
float ux, float uy, float uz)
{
ALfloat orient[6];
orient[0] = fx;
orient[1] = fy;
orient[2] = fz;
orient[3] = ux;
orient[4] = uy;
orient[5] = uz;
alListener3f(AL_POSITION, x, y, z);
alListenerfv(AL_ORIENTATION, orient);
}
OpenAL_Factory::OpenAL_Factory(bool doSetup)
: device(NULL), context(NULL), didSetup(doSetup)
{
needsUpdate = true;
has3D = true;
canLoadFile = false;
canLoadStream = false;
canLoadSource = true;
ALCdevice *Device;
ALCcontext *Context;
if(doSetup)
{
// Set up sound system
@ -90,6 +167,9 @@ OpenAL_Factory::OpenAL_Factory(bool doSetup)
fail("Failed to initialize context or device");
alcMakeContextCurrent(Context);
device = Device;
context = Context;
}
}
@ -99,8 +179,8 @@ OpenAL_Factory::~OpenAL_Factory()
if(didSetup)
{
alcMakeContextCurrent(NULL);
if(Context) alcDestroyContext(Context);
if(Device) alcCloseDevice(Device);
if(context) alcDestroyContext((ALCcontext*)context);
if(device) alcCloseDevice((ALCdevice*)device);
}
}
@ -108,6 +188,7 @@ OpenAL_Factory::~OpenAL_Factory()
void OpenAL_Sound::play()
{
setupBuffer();
alSourcePlay(inst);
checkALError("starting playback");
}
@ -164,14 +245,16 @@ void OpenAL_Sound::setRepeat(bool rep)
alSourcei(inst, AL_LOOPING, rep?AL_TRUE:AL_FALSE);
}
SoundPtr OpenAL_Sound::clone() const
SoundPtr OpenAL_Sound::clone()
{
setupBuffer();
assert(!streaming && "cloning streamed sounds not supported");
return SoundPtr(new OpenAL_Sound(bufferID, refCnt));
}
// Constructor used for cloned sounds
OpenAL_Sound::OpenAL_Sound(ALuint buf, int *ref)
: bufferID(buf), refCnt(ref)
: bufferID(buf), refCnt(ref), streaming(false)
{
// Increase the reference count
assert(ref != NULL);
@ -185,12 +268,35 @@ OpenAL_Sound::OpenAL_Sound(ALuint buf, int *ref)
}
// Constructor used for original (non-cloned) sounds
OpenAL_Sound::OpenAL_Sound(SampleSourcePtr input)
OpenAL_Sound::OpenAL_Sound(SampleSourcePtr _input)
: bufferID(0), refCnt(NULL), streaming(false), input(_input)
{
// Create a source
alGenSources(1, &inst);
checkALError("creating source");
// By default, the sound starts out in a buffer-less mode. We don't
// create a buffer until the sound is played. This gives the user
// the chance to call setStreaming(true) first.
}
void OpenAL_Sound::setupBuffer()
{
if(refCnt != NULL) return;
assert(input);
// Get the format
int fmt, rate;
getALFormat(input, fmt, rate);
if(streaming)
{
// To be done
}
// NON-STREAMING
// Set up the OpenAL buffer
alGenBuffers(1, &bufferID);
checkALError("generating buffer");
@ -205,17 +311,16 @@ OpenAL_Sound::OpenAL_Sound(SampleSourcePtr input)
else
{
// Read the entire stream into a temporary buffer first
Mangle::Stream::BufferStream buf(input);
Mangle::Stream::BufferStream buf(input, streaming?1024*1024:32*1024);
// Then copy that into OpenAL
alBufferData(bufferID, fmt, buf.getPtr(), buf.size(), rate);
}
checkALError("loading sound buffer");
// Create a source
alGenSources(1, &inst);
checkALError("creating source");
// We're done with the input stream, release the pointer
input.reset();
alSourcei(inst, AL_BUFFER, bufferID);
checkALError("assigning buffer");

View file

@ -3,57 +3,13 @@
#include "../output.hpp"
#include <AL/al.h>
#include <AL/alc.h>
#include <list>
namespace Mangle {
namespace Sound {
/// OpenAL sound output
class OpenAL_Sound : public Sound
{
protected:
ALuint inst;
ALuint bufferID;
// Poor mans reference counting. Might improve this later.
int *refCnt;
public:
/// Read samples from the given input buffer
OpenAL_Sound(SampleSourcePtr input);
/// Play an existing buffer, with a given ref counter. Used
/// internally for cloning.
OpenAL_Sound(ALuint buf, int *ref);
~OpenAL_Sound();
void play();
void stop();
void pause();
bool isPlaying() const;
void setVolume(float);
void setPos(float x, float y, float z);
void setPitch(float);
void setRepeat(bool);
void setStreaming(bool) {} // Not implemented yet
SoundPtr clone() const;
// a = AL_REFERENCE_DISTANCE
// b = AL_MAX_DISTANCE
// c = ignored
void setRange(float a, float b=0.0, float c=0.0);
/// Not implemented
void setPan(float) {}
};
class OpenAL_Factory : public SoundFactory
{
ALCdevice *Device;
ALCcontext *Context;
void *device;
void *context;
bool didSetup;
public:
@ -65,24 +21,12 @@ class OpenAL_Factory : public SoundFactory
SoundPtr load(const std::string &file) { assert(0); }
SoundPtr load(Stream::StreamPtr input) { assert(0); }
SoundPtr loadRaw(SampleSourcePtr input)
{ return SoundPtr(new OpenAL_Sound(input)); }
SoundPtr loadRaw(SampleSourcePtr input);
void update() {}
void update();
void setListenerPos(float x, float y, float z,
float fx, float fy, float fz,
float ux, float uy, float uz)
{
ALfloat orient[6];
orient[0] = fx;
orient[1] = fy;
orient[2] = fz;
orient[3] = ux;
orient[4] = uy;
orient[5] = uz;
alListener3f(AL_POSITION, x, y, z);
alListenerfv(AL_ORIENTATION, orient);
}
float ux, float uy, float uz);
};
}} // namespaces

View file

@ -17,11 +17,10 @@ using namespace Mangle::Stream;
support), but that's more messy.
- the library also supports output, via various other sources,
including ALSO, OSS, PortAudio, PulseAudio and SDL. Using this
including ALSA, OSS, PortAudio, PulseAudio and SDL. Using this
library as a pure output library (if that is possible) would be a
nice shortcut over using those libraries - OTOH it's another
dependency. But it also means we could scavenge the mpg123 source
for these parts if we want them.
dependency.
- we could implement seek(), tell() and size(), but they aren't
really necessary. Furthermore, since the returned size is only a

View file

@ -25,15 +25,23 @@ int main()
cout << "Playing\n";
// This initializes OpenAL for us, and serves no other purpose.
OpenAL_Factory mg;
OpenAL_Sound snd(source);
SoundPtr snd = mg.loadRaw(source);
try
{
snd.play();
// Try setting all kinds of stuff before playing. OpenAL_Sound
// uses delayed buffer loading, but these should still work
// without a buffer.
snd->stop();
snd->pause();
snd->setVolume(0.8);
snd->setPitch(0.9);
while(snd.isPlaying())
snd->play();
while(snd->isPlaying())
{
usleep(10000);
}

View file

@ -16,7 +16,11 @@ class BufferStream : public MemoryStream
std::vector<char> buffer;
public:
BufferStream(StreamPtr input)
/*
input = stream to copy
ADD = each read increment (for streams without size())
*/
BufferStream(StreamPtr input, size_t ADD = 32*1024)
{
assert(input);
@ -37,7 +41,6 @@ class BufferStream : public MemoryStream
{
// We DON'T know how big the stream is. We'll have to read
// it in increments.
const unsigned int ADD = 32*1024;
size_t len=0, newlen;
while(!input->eof())
@ -52,7 +55,7 @@ class BufferStream : public MemoryStream
// If we read less than expected, we should be at the
// end of the stream
assert(read == ADD || input->eof());
assert(read == ADD || (read < ADD && input->eof()));
}
// Downsize to match the real length