Merged multiple WIPs into one big mess
Merge branch 'master' into stream_bufferactorid
commit
c7701ace82
@ -0,0 +1,57 @@
|
||||
#ifndef MANGLE_SOUND_BUFFER_H
|
||||
#define MANGLE_SOUND_BUFFER_H
|
||||
|
||||
#include "source.h"
|
||||
#include "sources/memsource.h"
|
||||
#include <vector>
|
||||
#include <assert.h>
|
||||
|
||||
namespace Mangle {
|
||||
namespace Sound {
|
||||
|
||||
/** A sample buffer is a factory that creates SampleSources from one
|
||||
single sound source. It is helpful when you have many instances of
|
||||
one sound and want to use one shared memory buffer.
|
||||
|
||||
This is just a helper class - you don't have to include it in your
|
||||
program if you don't need it.
|
||||
*/
|
||||
class SampleBuffer
|
||||
{
|
||||
std::vector<uint8_t> buffer;
|
||||
|
||||
public:
|
||||
/// Reads the source into a memory buffer. Not heavily optimized.
|
||||
SampleBuffer(SampleSource *source)
|
||||
{
|
||||
size_t final = 0;
|
||||
|
||||
while(!source->eof())
|
||||
{
|
||||
const int add = 16*1024;
|
||||
|
||||
// Allocate more memory
|
||||
size_t newSize = final + add;
|
||||
buffer.resize(newSize);
|
||||
|
||||
// Fill in data
|
||||
size_t read = source->read(&buffer[final], add);
|
||||
|
||||
// If we couldn't read enough data, we should be at the end
|
||||
// of the stream
|
||||
assert(read == add || source->eof());
|
||||
|
||||
final += read;
|
||||
}
|
||||
|
||||
// Downsize the buffer to the actual length
|
||||
buffer.resize(final);
|
||||
}
|
||||
|
||||
/// Get a new source
|
||||
SampleSource *get()
|
||||
{ return new MemorySource(&buffer[0], buffer.size()); }
|
||||
};
|
||||
|
||||
}}
|
||||
#endif
|
@ -1,83 +0,0 @@
|
||||
#ifndef MANGLE_SOUND_INPUT_H
|
||||
#define MANGLE_SOUND_INPUT_H
|
||||
|
||||
#include <string>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "../stream/stream.h"
|
||||
|
||||
namespace Mangle {
|
||||
namespace Sound {
|
||||
|
||||
/// An abstract interface for a read-once stream of audio data.
|
||||
/** All instances of this is created through InputSource. Objects
|
||||
should be manually deleted through a call to drop() when they are
|
||||
no longer needed.
|
||||
*/
|
||||
class InputStream
|
||||
{
|
||||
public:
|
||||
/// Get the sample rate, number of channels, and bits per
|
||||
/// sample. NULL parameters are ignored.
|
||||
virtual void getInfo(int32_t *rate, int32_t *channels, int32_t *bits) = 0;
|
||||
|
||||
/// Get decoded sound data from the stream.
|
||||
/** Stores 'length' bytes (or less) in the buffer pointed to by
|
||||
'output'. Returns the number of bytes written. The function will
|
||||
only return less than 'length' at the end of the stream. When
|
||||
the stream is empty, all subsequent calls will return zero.
|
||||
|
||||
@param output where to store data
|
||||
@param length number of bytes to get
|
||||
@return number of bytes actually written
|
||||
*/
|
||||
virtual uint32_t getData(void *output, uint32_t length) = 0;
|
||||
|
||||
/// Kill this object
|
||||
virtual void drop() = 0;
|
||||
|
||||
/// Virtual destructor
|
||||
virtual ~InputStream() {}
|
||||
};
|
||||
|
||||
/// Abstract interface representing one sound source.
|
||||
/** A sound source may represent one sound file or buffer, and is a
|
||||
factory for producing InputStream objects from that
|
||||
sound. Instances of this class are created by an InputManager. All
|
||||
instances should be deleted through drop() when they are no longer
|
||||
needed.
|
||||
*/
|
||||
class InputSource
|
||||
{
|
||||
public:
|
||||
/// Create a stream from this sound
|
||||
virtual InputStream *getStream() = 0;
|
||||
|
||||
/// Kill this object
|
||||
virtual void drop() = 0;
|
||||
|
||||
/// Virtual destructor
|
||||
virtual ~InputSource() {}
|
||||
};
|
||||
|
||||
/// Main interface to a sound decoder backend.
|
||||
/** An input manager is a factory of InputSource objects.
|
||||
*/
|
||||
class InputManager
|
||||
{
|
||||
public:
|
||||
/// If true, the stream version of load() works
|
||||
bool canLoadStream;
|
||||
|
||||
/// Load a sound input source from file
|
||||
virtual InputSource *load(const std::string &file) = 0;
|
||||
|
||||
/// Load a sound input source from stream (if canLoadStream is true)
|
||||
virtual InputSource *load(Stream::Stream *input) = 0;
|
||||
|
||||
/// Virtual destructor
|
||||
virtual ~InputManager() {}
|
||||
};
|
||||
|
||||
}} // namespaces
|
||||
#endif
|
@ -0,0 +1,109 @@
|
||||
#ifndef MANGLE_SOUND_OPENAL_OUT_H
|
||||
#define MANGLE_SOUND_OPENAL_OUT_H
|
||||
|
||||
#include "../output.h"
|
||||
|
||||
#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;
|
||||
|
||||
public:
|
||||
OpenAL_Sound(SampleSource *input);
|
||||
~OpenAL_Sound();
|
||||
|
||||
/// Play or resume the sound
|
||||
void play();
|
||||
|
||||
/// Stop the sound
|
||||
void stop();
|
||||
|
||||
/// Pause the sound, may be resumed later
|
||||
void pause();
|
||||
|
||||
/// Check if the sound is still playing
|
||||
bool isPlaying();
|
||||
|
||||
/// Set the volume. The parameter must be between 0.0 and 1.0.
|
||||
void setVolume(float);
|
||||
|
||||
/// Set the 3D position.
|
||||
void setPos(float x, float y, float z);
|
||||
};
|
||||
|
||||
class OpenALFactory : public SoundFactory
|
||||
{
|
||||
ALCdevice *Device;
|
||||
ALCcontext *Context;
|
||||
bool didSetup;
|
||||
|
||||
public:
|
||||
/// Initialize object. Pass true (default) if you want the
|
||||
/// constructor to set up the current ALCdevice and ALCcontext for
|
||||
/// you.
|
||||
OpenALFactory(bool doSetup = true)
|
||||
: didSetup(doSetup)
|
||||
{
|
||||
needsUpdate = false;
|
||||
has3D = true;
|
||||
canRepeatStream = false;
|
||||
canLoadFile = false;
|
||||
canLoadStream = false;
|
||||
canLoadSource = true;
|
||||
|
||||
if(doSetup)
|
||||
{
|
||||
// Set up sound system
|
||||
Device = alcOpenDevice(NULL);
|
||||
Context = alcCreateContext(Device, NULL);
|
||||
|
||||
if(!Device || !Context)
|
||||
fail("Failed to initialize context or device");
|
||||
|
||||
alcMakeContextCurrent(Context);
|
||||
}
|
||||
}
|
||||
|
||||
~OpenALFactory()
|
||||
{
|
||||
// Deinitialize sound system
|
||||
if(didSetup)
|
||||
{
|
||||
alcMakeContextCurrent(NULL);
|
||||
if(Context) alcDestroyContext(Context);
|
||||
if(Device) alcCloseDevice(Device);
|
||||
}
|
||||
}
|
||||
|
||||
Sound *load(const std::string &file, bool stream=false) { assert(0); }
|
||||
Sound *load(Stream::Stream *input, bool stream=false) { assert(0); }
|
||||
Sound *load(SampleSource* input, bool stream=false)
|
||||
{ return new OpenAL_Sound(input); }
|
||||
|
||||
void update() {}
|
||||
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);
|
||||
}
|
||||
};
|
||||
|
||||
}} // namespaces
|
||||
#endif
|
@ -1 +0,0 @@
|
||||
|
@ -1,95 +0,0 @@
|
||||
#include "audiere_imp.h"
|
||||
|
||||
// Exception handling
|
||||
class Audiere_Exception : public std::exception
|
||||
{
|
||||
std::string msg;
|
||||
|
||||
public:
|
||||
|
||||
Audiere_Exception(const std::string &m) : msg(m) {}
|
||||
~Audiere_Exception() throw() {}
|
||||
virtual const char* what() const throw() { return msg.c_str(); }
|
||||
};
|
||||
|
||||
static void fail(const std::string &msg)
|
||||
{
|
||||
throw Audiere_Exception("Audiere exception: " + msg);
|
||||
}
|
||||
|
||||
using namespace audiere;
|
||||
using namespace Mangle::Sound;
|
||||
|
||||
AudiereManager::AudiereManager()
|
||||
{
|
||||
needsUpdate = false;
|
||||
has3D = false;
|
||||
canRepeatStream = true;
|
||||
canLoadFile = true;
|
||||
canLoadSource = false;
|
||||
canLoadStream = false;
|
||||
|
||||
device = OpenDevice("");
|
||||
|
||||
if(device == NULL)
|
||||
fail("Failed to open device");
|
||||
}
|
||||
|
||||
// --- Manager ---
|
||||
|
||||
Sound *AudiereManager::load(const std::string &file, bool stream)
|
||||
{ return new AudiereSound(file, device, stream); }
|
||||
|
||||
|
||||
// --- Sound ---
|
||||
|
||||
AudiereSound::AudiereSound(const std::string &file,
|
||||
AudioDevicePtr _device,
|
||||
bool _stream)
|
||||
: device(_device), stream(_stream)
|
||||
{
|
||||
sample = OpenSampleSource(file.c_str());
|
||||
if(!sample)
|
||||
fail("Couldn't load file " + file);
|
||||
|
||||
buf = CreateSampleBuffer(sample);
|
||||
}
|
||||
|
||||
Instance *AudiereSound::getInstance(bool is3d, bool repeat)
|
||||
{
|
||||
// Ignore is3d. Audiere doesn't implement 3d sound. We could make a
|
||||
// hack software 3D implementation later, but it's not that
|
||||
// important.
|
||||
|
||||
SampleSourcePtr sample = buf->openStream();
|
||||
if(!sample)
|
||||
fail("Failed to open sample stream");
|
||||
|
||||
OutputStreamPtr sound = OpenSound(device, sample, stream);
|
||||
|
||||
if(repeat)
|
||||
sound->setRepeat(true);
|
||||
|
||||
return new AudiereInstance(sound);
|
||||
}
|
||||
|
||||
|
||||
// --- Instance ---
|
||||
|
||||
AudiereInstance::AudiereInstance(OutputStreamPtr _sound)
|
||||
: sound(_sound) {}
|
||||
|
||||
void AudiereInstance::play()
|
||||
{ sound->play(); }
|
||||
|
||||
void AudiereInstance::stop()
|
||||
{ sound->stop(); }
|
||||
|
||||
void AudiereInstance::pause()
|
||||
{ stop(); }
|
||||
|
||||
bool AudiereInstance::isPlaying()
|
||||
{ return sound->isPlaying(); }
|
||||
|
||||
void AudiereInstance::setVolume(float vol)
|
||||
{ sound->setVolume(vol); }
|
@ -1,77 +0,0 @@
|
||||
#ifndef MANGLE_SOUND_AUDIERE_H
|
||||
#define MANGLE_SOUND_AUDIERE_H
|
||||
|
||||
#include "../sound.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <audiere.h>
|
||||
|
||||
namespace Mangle {
|
||||
namespace Sound {
|
||||
|
||||
/// Implementation of Sound::Manager for Audiere
|
||||
class AudiereManager : public Manager
|
||||
{
|
||||
audiere::AudioDevicePtr device;
|
||||
|
||||
public:
|
||||
AudiereManager();
|
||||
|
||||
virtual Sound *load(const std::string &file, bool stream=false);
|
||||
|
||||
/// not implemented yet
|
||||
virtual Sound *load(Stream::Stream *input, bool stream=false)
|
||||
{ assert(0); }
|
||||
|
||||
/// disabled
|
||||
virtual Sound *load(InputSource *input, bool stream=false)
|
||||
{ assert(0); }
|
||||
/// disabled
|
||||
virtual void update() { assert(0); }
|
||||
/// disabled
|
||||
virtual void setListenerPos(float x, float y, float z,
|
||||
float fx, float fy, float fz,
|
||||
float ux, float uy, float uz)
|
||||
{ assert(0); };
|
||||
};
|
||||
|
||||
/// Audiere Sound implementation
|
||||
class AudiereSound : public Sound
|
||||
{
|
||||
audiere::AudioDevicePtr device;
|
||||
audiere::SampleSourcePtr sample;
|
||||
audiere::SampleBufferPtr buf;
|
||||
|
||||
bool stream;
|
||||
|
||||
public:
|
||||
virtual Instance *getInstance(bool is3d, bool repeat);
|
||||
virtual void drop()
|
||||
{ delete this; }
|
||||
|
||||
AudiereSound(const std::string &file, audiere::AudioDevicePtr device,
|
||||
bool stream);
|
||||
};
|
||||
|
||||
/// Audiere Instance implementation
|
||||
class AudiereInstance : public Instance
|
||||
{
|
||||
audiere::OutputStreamPtr sound;
|
||||
|
||||
public:
|
||||
virtual void play();
|
||||
virtual void stop();
|
||||
virtual void pause();
|
||||
virtual bool isPlaying();
|
||||
virtual void setVolume(float);
|
||||
/// disabled
|
||||
virtual void setPos(float x, float y, float z)
|
||||
{ assert(0); }
|
||||
virtual void drop()
|
||||
{ delete this; }
|
||||
|
||||
AudiereInstance(audiere::OutputStreamPtr);
|
||||
};
|
||||
|
||||
}} // Namespace
|
||||
#endif
|
@ -1,59 +0,0 @@
|
||||
#ifndef MANGLE_SOUND_AUDIERE_INPUT_H
|
||||
#define MANGLE_SOUND_AUDIERE_INPUT_H
|
||||
|
||||
#include "../input.h"
|
||||
|
||||
#include <audiere.h>
|
||||
|
||||
namespace Mangle {
|
||||
namespace Sound {
|
||||
|
||||
/// Implementation of Sound::InputManager for Audiere
|
||||
class AudiereInput : public InputManager
|
||||
{
|
||||
public:
|
||||
AudiereInput();
|
||||
|
||||
/// Load a source from a file
|
||||
InputSource *load(const std::string &file);
|
||||
|
||||
/// Load a source from a stream
|
||||
virtual InputSource *load(Stream::Stream *input);
|
||||
};
|
||||
|
||||
/// Audiere InputSource implementation
|
||||
class AudiereSource : public InputSource
|
||||
{
|
||||
audiere::SampleBufferPtr buf;
|
||||
|
||||
public:
|
||||
AudiereSource(const std::string &file);
|
||||
AudiereSource(Stream::Stream *input);
|
||||
InputStream *getStream();
|
||||
void drop() { delete this; }
|
||||
};
|
||||
|
||||
/// Audiere InputStream implementation
|
||||
class AudiereStream : public InputStream
|
||||
{
|
||||
audiere::SampleSourcePtr sample;
|
||||
int frameSize; // Size of one frame, in bytes
|
||||
|
||||
static const int PSIZE = 10;
|
||||
|
||||
// Temporary storage for unevenly read samples. See the comment for
|
||||
// getData() in the .cpp file.
|
||||
char pullOver[PSIZE];
|
||||
// How much of the above buffer is in use
|
||||
int pullSize;
|
||||
|
||||
public:
|
||||
AudiereStream(audiere::SampleSourcePtr _sample);
|
||||
|
||||
void getInfo(int32_t *rate, int32_t *channels, int32_t *bits);
|
||||
uint32_t getData(void *data, uint32_t length);
|
||||
void drop() { delete this; }
|
||||
};
|
||||
|
||||
}} // Namespace
|
||||
#endif
|
@ -1,75 +0,0 @@
|
||||
#ifndef MANGLE_SOUND_FFMPEG_H
|
||||
#define MANGLE_SOUND_FFMPEG_H
|
||||
|
||||
#include "../input.h"
|
||||
#include <exception>
|
||||
#include <vector>
|
||||
#include <assert.h>
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include <libavcodec/avcodec.h>
|
||||
#include <libavformat/avformat.h>
|
||||
}
|
||||
|
||||
namespace Mangle {
|
||||
namespace Sound {
|
||||
|
||||
/// FFmpeg exception
|
||||
class FFM_Exception : public std::exception
|
||||
{
|
||||
std::string msg;
|
||||
|
||||
public:
|
||||
|
||||
FFM_Exception(const std::string &m);
|
||||
~FFM_Exception() throw();
|
||||
virtual const char* what() const throw();
|
||||
};
|
||||
|
||||
/// FFMpeg implementation of InputManager
|
||||
class FFM_InputManager : public InputManager
|
||||
{
|
||||
static bool init;
|
||||
|
||||
public:
|
||||
FFM_InputManager();
|
||||
virtual InputSource *load(const std::string &file);
|
||||
|
||||
/// not supported
|
||||
virtual InputSource *load(Stream::Stream *input) { assert(0); }
|
||||
};
|
||||
|
||||
/// FFMpeg implementation of InputSource
|
||||
class FFM_InputSource : public InputSource
|
||||
{
|
||||
std::string name;
|
||||
|
||||
public:
|
||||
FFM_InputSource(const std::string &file);
|
||||
|
||||
virtual InputStream *getStream();
|
||||
virtual void drop();
|
||||
};
|
||||
|
||||
/// FFMpeg implementation of InputStream
|
||||
class FFM_InputStream : public InputStream
|
||||
{
|
||||
AVFormatContext *FmtCtx;
|
||||
AVCodecContext *CodecCtx;
|
||||
int StreamNum;
|
||||
bool empty;
|
||||
|
||||
std::vector<uint8_t> storage;
|
||||
|
||||
public:
|
||||
FFM_InputStream(const std::string &file);
|
||||
~FFM_InputStream();
|
||||
|
||||
virtual void getInfo(int32_t *rate, int32_t *channels, int32_t *bits);
|
||||
virtual uint32_t getData(void *data, uint32_t length);
|
||||
virtual void drop();
|
||||
};
|
||||
|
||||
}} // namespaces
|
||||
#endif
|
@ -1,28 +0,0 @@
|
||||
#ifndef MANGLE_FFMPEG_OPENAL_H
|
||||
#define MANGLE_FFMPEG_OPENAL_H
|
||||
|
||||
#include "input_filter.h"
|
||||
#include "input_ffmpeg.h"
|
||||
#include "output_openal.h"
|
||||
|
||||
namespace Mangle {
|
||||
namespace Sound {
|
||||
|
||||
/// An InputFilter that adds FFmpeg decoding to OpenAL
|
||||
class OpenAL_FFM_Manager : public InputFilter
|
||||
{
|
||||
public:
|
||||
OpenAL_FFM_Manager()
|
||||
{
|
||||
set(new OpenAL_Manager,
|
||||
new FFM_InputManager);
|
||||
}
|
||||
~OpenAL_FFM_Manager()
|
||||
{
|
||||
delete snd;
|
||||
delete inp;
|
||||
}
|
||||
};
|
||||
|
||||
}}
|
||||
#endif
|
@ -1,125 +0,0 @@
|
||||
#ifndef MANGLE_SOUND_OPENAL_H
|
||||
#define MANGLE_SOUND_OPENAL_H
|
||||
|
||||
#include "../sound.h"
|
||||
|
||||
#include <AL/al.h>
|
||||
#include <AL/alc.h>
|
||||
#include <list>
|
||||
|
||||
namespace Mangle {
|
||||
namespace Sound {
|
||||
|
||||
class OpenAL_Stream_Instance;
|
||||
|
||||
/// OpenAL implementation of Manager
|
||||
class OpenAL_Manager : public Manager
|
||||
{
|
||||
public:
|
||||
// List of all streaming sounds - these need to be updated regularly
|
||||
typedef std::list<OpenAL_Stream_Instance*> LST;
|
||||
|
||||
OpenAL_Manager();
|
||||
virtual ~OpenAL_Manager();
|
||||
|
||||
LST::iterator add_stream(OpenAL_Stream_Instance*);
|
||||
void remove_stream(LST::iterator);
|
||||
|
||||
virtual Sound *load(const std::string &file, bool stream=false);
|
||||
virtual Sound *load(Stream::Stream *input, bool stream=false);
|
||||
virtual Sound *load(InputSource* input, bool stream=false);
|
||||
virtual void update();
|
||||
virtual void setListenerPos(float x, float y, float z,
|
||||
float fx, float fy, float fz,
|
||||
float ux, float uy, float uz);
|
||||
|
||||
private:
|
||||
ALCdevice *Device;
|
||||
ALCcontext *Context;
|
||||
|
||||
LST streaming;
|
||||
};
|
||||
|
||||
/// OpenAL implementation of Sound
|
||||
class OpenAL_Sound : public Sound
|
||||
{
|
||||
InputSource *source;
|
||||
OpenAL_Manager *owner;
|
||||
bool stream;
|
||||
|
||||
// Used for non-streaming files, contains the entire sound buffer if
|
||||
// non-zero
|
||||
ALuint bufferID;
|
||||
|
||||
public:
|
||||
OpenAL_Sound(InputSource *src, OpenAL_Manager *own, bool str)
|
||||
: source(src), owner(own), stream(str), bufferID(0) {}
|
||||
~OpenAL_Sound();
|
||||
|
||||
virtual Instance *getInstance(bool is3d, bool repeat);
|
||||
void drop() { delete this; }
|
||||
};
|
||||
|
||||
/// Shared parent class that holds an OpenAL sound instance. Just used
|
||||
/// for shared functionality, has no setup or cleanup code.
|
||||
class OpenAL_Instance_Base : public Instance
|
||||
{
|
||||
protected:
|
||||
ALuint inst;
|
||||
|
||||
public:
|
||||
void drop() { delete this; }
|
||||
virtual void play();
|
||||
virtual void stop();
|
||||
virtual void pause();
|
||||
virtual bool isPlaying();
|
||||
virtual void setVolume(float);
|
||||
virtual void setPos(float x, float y, float z);
|
||||
};
|
||||
|
||||
/// Non-streaming OpenAL-implementation of Instance. Uses a shared
|
||||
/// sound buffer in OpenAL_Sound.
|
||||
class OpenAL_Simple_Instance : public OpenAL_Instance_Base
|
||||
{
|
||||
public:
|
||||
OpenAL_Simple_Instance(ALuint buf);
|
||||
~OpenAL_Simple_Instance();
|
||||
};
|
||||
|
||||
/// Streaming OpenAL-implementation of Instance.
|
||||
class OpenAL_Stream_Instance : public OpenAL_Instance_Base
|
||||
{
|
||||
// Since OpenAL streams have to be updated manually each frame, we
|
||||
// need to have a sufficiently large buffer so that we don't run out
|
||||
// of data in the mean time. Each instance will take around 512 Kb
|
||||
// of memory, independent of how large the file is.
|
||||
static const int BUFS = 4;
|
||||
static const int SIZE = 128*1024;
|
||||
|
||||
// Buffers
|
||||
ALuint bufs[BUFS];
|
||||
|
||||
// Sound format settings
|
||||
int rate, fmt;
|
||||
|
||||
// Source of data
|
||||
InputStream *stream;
|
||||
|
||||
OpenAL_Manager *owner;
|
||||
|
||||
// List iterator, used for removing ourselves from the streaming
|
||||
// list when we're deleted.
|
||||
OpenAL_Manager::LST::iterator lit;
|
||||
|
||||
// Load and queue a new buffer
|
||||
void queueBuffer(ALuint buffer);
|
||||
|
||||
public:
|
||||
OpenAL_Stream_Instance(InputStream*, OpenAL_Manager*);
|
||||
~OpenAL_Stream_Instance();
|
||||
|
||||
void update();
|
||||
};
|
||||
|
||||
}} // namespaces
|
||||
#endif
|
@ -0,0 +1,63 @@
|
||||
#ifndef MANGLE_SOUND_SOURCE_H
|
||||
#define MANGLE_SOUND_SOURCE_H
|
||||
|
||||
#include <string>
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "../stream/stream.h"
|
||||
|
||||
namespace Mangle {
|
||||
namespace Sound {
|
||||
|
||||
/// A stream containing raw sound data and information about the format
|
||||
class SampleSource : public Stream::Stream
|
||||
{
|
||||
protected:
|
||||
bool isEof;
|
||||
|
||||
public:
|
||||
SampleSource()
|
||||
{
|
||||
// These are usually not needed for sound data
|
||||
isSeekable = false;
|
||||
hasPosition = false;
|
||||
hasSize = false;
|
||||
|
||||
isEof = false;
|
||||
}
|
||||
|
||||
/// Get the sample rate, number of channels, and bits per
|
||||
/// sample. NULL parameters are ignored.
|
||||
virtual void getInfo(int32_t *rate, int32_t *channels, int32_t *bits) const = 0;
|
||||
|
||||
bool eof() const { return isEof; }
|
||||
|
||||
// Disabled functions
|
||||
void seek(size_t pos) const { assert(0); }
|
||||
size_t tell() const { assert(0); }
|
||||
size_t size() const { assert(0); }
|
||||
};
|
||||
|
||||
/// A factory interface for loading SampleSources from file or stream
|
||||
class SampleSourceLoader
|
||||
{
|
||||
public:
|
||||
/// If true, the stream version of load() works
|
||||
bool canLoadStream;
|
||||
|
||||
/// If true, the file version of load() works
|
||||
bool canLoadFile;
|
||||
|
||||
/// Load a sound input source from file (if canLoadFile is true)
|
||||
virtual SampleSource *load(const std::string &file) = 0;
|
||||
|
||||
/// Load a sound input source from stream (if canLoadStream is true)
|
||||
virtual SampleSource *load(Stream::Stream *input) = 0;
|
||||
|
||||
/// Virtual destructor
|
||||
virtual ~SampleSourceLoader() {}
|
||||
};
|
||||
|
||||
}} // namespaces
|
||||
#endif
|
@ -0,0 +1,51 @@
|
||||
#ifndef MANGLE_SOUND_AUDIERE_SOURCE_H
|
||||
#define MANGLE_SOUND_AUDIERE_SOURCE_H
|
||||
|
||||
#include "../source.h"
|
||||
|
||||
#include <audiere.h>
|
||||
|
||||
namespace Mangle {
|
||||
namespace Sound {
|
||||
|
||||
/// A sample source that decodes files using Audiere
|
||||
class AudiereSource : public SampleSource
|
||||
{
|
||||
audiere::SampleSourcePtr sample;
|
||||
|
||||
// Number of bytes we cache between reads. This should correspond to
|
||||
// the maximum possible value of frameSize.
|
||||
static const int PSIZE = 10;
|
||||
|
||||
// Size of one frame, in bytes
|
||||
int frameSize;
|
||||
|
||||
// Temporary storage for unevenly read samples. See the comment for
|
||||
// read() in the .cpp file.
|
||||
char pullOver[PSIZE];
|
||||
// How much of the above buffer is in use
|
||||
int pullSize;
|
||||
|
||||
void getFormat();
|
||||
|
||||
public:
|
||||
/// Decode the given sound file
|
||||
AudiereSource(const std::string &file);
|
||||
|
||||
/// Decode the given sound stream
|
||||
AudiereSource(Stream::Stream *src);
|
||||
|
||||
/// Read directly from an existing audiere::SampleSource
|
||||
AudiereSource(audiere::SampleSourcePtr src);
|
||||
|
||||
void getInfo(int32_t *rate, int32_t *channels, int32_t *bits);
|
||||
size_t read(void *data, size_t length);
|
||||
};
|
||||
|
||||
#include "loadertemplate.h"
|
||||
|
||||
/// A factory that loads AudiereSources from file and stream
|
||||
typedef SSL_Template<AudiereSource,true,true> AudiereLoader;
|
||||
|
||||
}} // Namespace
|
||||
#endif
|
@ -0,0 +1,53 @@
|
||||
#ifndef MANGLE_SOUND_FFMPEG_H
|
||||
#define MANGLE_SOUND_FFMPEG_H
|
||||
|
||||
#include "../input.h"
|
||||
#include <exception>
|
||||
#include <vector>
|
||||
#include <assert.h>
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include <libavcodec/avcodec.h>
|
||||
#include <libavformat/avformat.h>
|
||||
}
|
||||
|
||||
namespace Mangle {
|
||||
namespace Sound {
|
||||
|
||||
class FFMpegSource : public SampleSource
|
||||
{
|
||||
AVFormatContext *FmtCtx;
|
||||
AVCodecContext *CodecCtx;
|
||||
int StreamNum;
|
||||
|
||||
std::vector<uint8_t> storage;
|
||||
|
||||
public:
|
||||
/// Decode the given sound file
|
||||
FFMpegSource(const std::string &file);
|
||||
|
||||
/// Decode the given sound stream (not supported by FFmpeg)
|
||||
FFMpegSource(Stream::Stream *src) { assert(0); }
|
||||
|
||||
~FFMpegSource();
|
||||
|
||||
// Overrides
|
||||
void getInfo(int32_t *rate, int32_t *channels, int32_t *bits);
|
||||
size_t read(void *data, size_t length);
|
||||
};
|
||||
|
||||
#include "loadertemplate.h"
|
||||
|
||||
/// A factory that loads FFMpegSources from file
|
||||
class FFMpegLoader : public SSL_Template<AudiereSource,false,true>
|
||||
{
|
||||
public:
|
||||
|
||||
/// Sets up the libavcodec library. If you want to do your own
|
||||
/// setup, send a setup=false parameter.
|
||||
FFMpegLoader(bool setup=true);
|
||||
};
|
||||
|
||||
}} // namespaces
|
||||
#endif
|
@ -0,0 +1,26 @@
|
||||
#ifndef SSL_TEMPL_H
|
||||
#define SSL_TEMPL_H
|
||||
|
||||
template <class SourceT, bool stream, bool file>
|
||||
class SSL_Template : public SampleSourceLoader
|
||||
{
|
||||
SSL_Template()
|
||||
{
|
||||
canLoadStream = stream;
|
||||
canLoadFile = file;
|
||||
}
|
||||
|
||||
SampleSource *load(const std::string &file)
|
||||
{
|
||||
assert(canLoadFile);
|
||||
return new SourceT(file);
|
||||
}
|
||||
|
||||
SampleSource *load(Stream::Stream *input)
|
||||
{
|
||||
assert(canLoadStream);
|
||||
return new SourceT(input);
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
@ -0,0 +1,49 @@
|
||||
#ifndef MANGLE_SOUND_MEMSOURCE_H
|
||||
#define MANGLE_SOUND_MEMSOURCE_H
|
||||
|
||||
#include "../source.h"
|
||||
|
||||
namespace Mangle {
|
||||
namespace Sound {
|
||||
|
||||
/// A sample source reading directly from a memory buffer
|
||||
class MemorySource : public SampleSource
|
||||
{
|
||||
char *buf;
|
||||
size_t len;
|
||||
size_t pos;
|
||||
|
||||
int32_t rate, channels, bits;
|
||||
|
||||
public:
|
||||
MemorySource(void *_buf, size_t _len, int32_t _rate, int32_t _channels, int32_t _bits)
|
||||
: len(_len), pos(0), rate(_rate), channels(_channels), bits(_bits)
|
||||
{ buf = (char*)_buf; }
|
||||
|
||||
/// Get the sample rate, number of channels, and bits per
|
||||
/// sample. NULL parameters are ignored.
|
||||
void getInfo(int32_t *_rate, int32_t *_channels, int32_t *_bits) const
|
||||
{
|
||||
if(_rate) *_rate = rate;
|
||||
if(_channels) *_channels = channels;
|
||||
if(_bits) *_bits = bits;
|
||||
}
|
||||
|
||||
bool eof() const { return pos == len; }
|
||||
|
||||
size_t read(void *out, size_t count)
|
||||
{
|
||||
assert(len >= pos);
|
||||
|
||||
if(count > (len-pos))
|
||||
count = len-pos;
|
||||
|
||||
if(count) memcpy(out, buf+pos, count);
|
||||
pos += count;
|
||||
|
||||
return count;
|
||||
}
|
||||
};
|
||||
|
||||
}} // namespaces
|
||||
#endif
|
Loading…
Reference in New Issue