From fb88d9ef0e3ec4750cd2f8eca1c01a3db13f7377 Mon Sep 17 00:00:00 2001 From: Nicolay Korslund Date: Tue, 29 Dec 2009 13:12:48 +0100 Subject: [PATCH] Deleted a bunch of files, started on output --- sound/input.h | 83 -------- sound/{sound.h => output.h} | 107 +++------- sound/servers/.gitignore | 1 - sound/servers/audiere_imp.cpp | 95 --------- sound/servers/audiere_imp.h | 77 ------- sound/servers/input_audiere.cpp | 139 ------------- sound/servers/input_audiere.h | 59 ------ sound/servers/input_ffmpeg.cpp | 224 -------------------- sound/servers/input_ffmpeg.h | 75 ------- sound/servers/input_filter.h | 80 -------- sound/servers/openal_audiere.h | 29 --- sound/servers/openal_ffmpeg.h | 28 --- sound/servers/output_openal.cpp | 353 -------------------------------- sound/servers/output_openal.h | 125 ----------- 14 files changed, 34 insertions(+), 1441 deletions(-) delete mode 100644 sound/input.h rename sound/{sound.h => output.h} (52%) delete mode 100644 sound/servers/.gitignore delete mode 100644 sound/servers/audiere_imp.cpp delete mode 100644 sound/servers/audiere_imp.h delete mode 100644 sound/servers/input_audiere.cpp delete mode 100644 sound/servers/input_audiere.h delete mode 100644 sound/servers/input_ffmpeg.cpp delete mode 100644 sound/servers/input_ffmpeg.h delete mode 100644 sound/servers/input_filter.h delete mode 100644 sound/servers/openal_audiere.h delete mode 100644 sound/servers/openal_ffmpeg.h delete mode 100644 sound/servers/output_openal.cpp delete mode 100644 sound/servers/output_openal.h diff --git a/sound/input.h b/sound/input.h deleted file mode 100644 index f61a029ff..000000000 --- a/sound/input.h +++ /dev/null @@ -1,83 +0,0 @@ -#ifndef MANGLE_SOUND_INPUT_H -#define MANGLE_SOUND_INPUT_H - -#include -#include - -#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 diff --git a/sound/sound.h b/sound/output.h similarity index 52% rename from sound/sound.h rename to sound/output.h index 0a51e9f93..4cdac7bed 100644 --- a/sound/sound.h +++ b/sound/output.h @@ -1,21 +1,24 @@ -#ifndef MANGLE_SOUND_SOUND_H -#define MANGLE_SOUND_SOUND_H +#ifndef MANGLE_SOUND_OUTPUT_H +#define MANGLE_SOUND_OUTPUT_H #include -#include "input.h" +#include "source.h" #include "../stream/stream.h" namespace Mangle { namespace Sound { -/// Abstract interface for sound instances -/** This class represents one sound instance, which may be played, - stopped, paused and so on. Instances are created from the Sound - class. All instances must be terminated manually using the drop() - function when they are no longer in use. +/// Abstract interface for a single playable sound +/** This class represents one sound outlet, which may be played, + stopped, paused and so on. + + Sound instances are created from the SoundFactory class. Sounds + may be connected to a SampleSource or read directly from a file, + and they may support 3d sounds, looping and other features + depending on the capabilities of the backend system. */ -class Instance +class Sound { public: /// Play or resume the sound @@ -36,63 +39,26 @@ class Instance /// Set the position. May not have any effect on 2D sounds. virtual void setPos(float x, float y, float z) = 0; - /// Kill the current object - virtual void drop() = 0; - - /// Virtual destructor - virtual ~Instance() {} -}; - -/// Abstract interface for sound files or sources -/** This class acts as a factory for sound Instance objects. - Implementations may choose to store shared sound buffers or other - optimizations in subclasses of Sound. Objects of this class are - created through the Manager class. All objects of this class - should be terminated manually using the drop() function when they - are no longer in use. -*/ -class Sound -{ - public: - /** - @brief Create an instance of this sound - - See also the capability flags in the Manager class. - - @param is3d true if this the sound is to be 3d enabled - @param repeat true if the sound should loop - @return new Instance object - */ - virtual Instance *getInstance(bool is3d, bool repeat) = 0; - - // Some prefab functions - - /// Shortcut for creating 3D instances - Instance *get3D(bool loop=false) - { return getInstance(true, loop); } - /// Shortcut for creating 2D instances - Instance *get2D(bool loop=false) - { return getInstance(false, loop); } - - /// Kill the current object - virtual void drop() = 0; - /// Virtual destructor virtual ~Sound() {} }; -/// Abstract interface for the main sound manager class -/** The sound manager is used to load sound files and is a factory for - Sound objects. It is the main entry point to a given sound system - implementation. +/// Factory interface for creating Sound objects +/** The SoundFactory is the main entry point to a given sound output + system. It is used to create Sound objects, which may be connected + to a sound file or stream, and which may be individually played, + paused, and so on. The class also contains a set of public bools which describe the capabilities the particular system. These should be set by implementations (base classes) in their respective constructors. */ -class Manager +class SoundFactory { public: + /// Virtual destructor + virtual ~SoundFactory() {} + /** @brief If set to true, you should call update() regularly (every frame or so) on this sound manager. If false, update() should not be called. @@ -111,23 +77,21 @@ class Manager */ bool canRepeatStream; - /// true if we can load sounds directly from file + /// true if we can load sounds directly from file (containing encoded data) bool canLoadFile; - /// true if we can load sounds from an InputSource - bool canLoadSource; - - /// If true, we can lound sound files from a Stream + /// If true, we can lound sound files from a Stream (containing encoded data) bool canLoadStream; + /// true if we can load sounds from a SampleSource (containing raw data) + bool canLoadSource; + /** - @brief Load a sound from an input source. Only valid if + @brief Load a sound from a sample source. Only valid if canLoadSource is true. This function loads a sound from a given stream as defined by - InputSource and InputStream. The InputSource and all streams - created from it will be dropped when drop() is called on the - owning sound / instance. + SampleSource. @param input the input source @param stream true if the file should be streamed. @@ -135,10 +99,10 @@ class Manager large files, but they are not required to. @return a new Sound object */ - virtual Sound *load(InputSource *input, bool stream=false) = 0; + virtual Sound *load(SampleSource *input, bool stream=false) = 0; /** - @brief Load a sound directly from file. Only valid if canLoadStream + @brief Load a sound file from stream. Only valid if canLoadStream is true. @param input audio file stream @@ -159,10 +123,10 @@ class Manager /// Call this every frame if needsUpdate is true /** - Update function that should be called regularly (about every - frame in a normal game setting.) Implementions may use this to - fill streaming buffers and similar. Implementations that do not - need this should set needsUpdate to false. + This should be called regularly (about every frame in a normal + game setting.) Implementions may use this for filling streaming + buffers and similar tasks. Implementations that do not need this + should set needsUpdate to false. */ virtual void update() = 0; @@ -177,9 +141,6 @@ class Manager virtual void setListenerPos(float x, float y, float z, float fx, float fy, float fz, float ux, float uy, float uz) = 0; - - /// Virtual destructor - virtual ~Manager() {} }; }} // Namespaces diff --git a/sound/servers/.gitignore b/sound/servers/.gitignore deleted file mode 100644 index 8b1378917..000000000 --- a/sound/servers/.gitignore +++ /dev/null @@ -1 +0,0 @@ - diff --git a/sound/servers/audiere_imp.cpp b/sound/servers/audiere_imp.cpp deleted file mode 100644 index ecdb0580a..000000000 --- a/sound/servers/audiere_imp.cpp +++ /dev/null @@ -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); } diff --git a/sound/servers/audiere_imp.h b/sound/servers/audiere_imp.h deleted file mode 100644 index 5ebb812bd..000000000 --- a/sound/servers/audiere_imp.h +++ /dev/null @@ -1,77 +0,0 @@ -#ifndef MANGLE_SOUND_AUDIERE_H -#define MANGLE_SOUND_AUDIERE_H - -#include "../sound.h" - -#include -#include - -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 diff --git a/sound/servers/input_audiere.cpp b/sound/servers/input_audiere.cpp deleted file mode 100644 index c48f45013..000000000 --- a/sound/servers/input_audiere.cpp +++ /dev/null @@ -1,139 +0,0 @@ -#include "input_audiere.h" -#include - -#include "../../stream/clients/audiere_file.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; - -// --- InputManager --- - -AudiereInput::AudiereInput() -{ - canLoadStream = true; -} - -InputSource *AudiereInput::load(const std::string &file) -{ return new AudiereSource(file); } - -InputSource *AudiereInput::load(Stream::Stream *input) -{ return new AudiereSource(input); } - -// --- InputSource --- - -AudiereSource::AudiereSource(const std::string &file) -{ - SampleSourcePtr sample = OpenSampleSource(file.c_str()); - if(!sample) - fail("Couldn't load file " + file); - - buf = CreateSampleBuffer(sample); -} - -AudiereSource::AudiereSource(Stream::Stream *input) -{ - SampleSourcePtr sample = OpenSampleSource - (new Stream::AudiereFile(input)); - if(!sample) - fail("Couldn't load stream"); - - buf = CreateSampleBuffer(sample); -} - -InputStream *AudiereSource::getStream() -{ - return new AudiereStream(buf->openStream()); -} - -// --- InputStream --- - -AudiereStream::AudiereStream(SampleSourcePtr _sample) - : sample(_sample), pullSize(0) -{ - assert(sample); - - SampleFormat fmt; - int channels, rate; - sample->getFormat(channels, rate, fmt); - - // Calculate the size of one frame - frameSize = GetSampleSize(fmt) * channels; - - // Make sure that our pullover hack will work. Increase this size if - // this doesn't work in all cases. - assert(frameSize <= PSIZE); -} - -void AudiereStream::getInfo(int32_t *rate, int32_t *channels, int32_t *bits) -{ - SampleFormat fmt; - sample->getFormat(*channels, *rate, fmt); - if(fmt == SF_U8) - *bits = 8; - else if(fmt == SF_S16) - *bits = 16; - else assert(0); -} - -/* - Get data. Since Audiere operates with frames, not bytes, there's a - little conversion magic going on here. We need to make sure we're - reading a whole number of frames - if not, we need to store the - remainding part of the last frame and remember it for the next read - operation. - - */ -uint32_t AudiereStream::getData(void *_data, uint32_t length) -{ - char *data = (char*)_data; - - // Move the remains from the last operation first - if(pullSize) - { - // pullSize is how much was stored the last time, so skip that. - memcpy(data, pullOver+pullSize, PSIZE-pullSize); - length -= pullSize; - data += pullSize; - } - - // Determine the overshoot up front - pullSize = length % frameSize; - - // Number of whole frames - int frames = length / frameSize; - - // Read the data - int res = sample->read(frames, data); - - // Are we missing data? If resread(1, pullOver) != 0)) - { - // Now, move as much of it as we can fit into the output - // data - memcpy(data+length-pullSize, pullOver, pullSize); - } - else pullSize = 0; - - // Return the total number of bytes stored - return frameSize*res + pullSize; -} diff --git a/sound/servers/input_audiere.h b/sound/servers/input_audiere.h deleted file mode 100644 index e753b0174..000000000 --- a/sound/servers/input_audiere.h +++ /dev/null @@ -1,59 +0,0 @@ -#ifndef MANGLE_SOUND_AUDIERE_INPUT_H -#define MANGLE_SOUND_AUDIERE_INPUT_H - -#include "../input.h" - -#include - -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 diff --git a/sound/servers/input_ffmpeg.cpp b/sound/servers/input_ffmpeg.cpp deleted file mode 100644 index f29ddfdb6..000000000 --- a/sound/servers/input_ffmpeg.cpp +++ /dev/null @@ -1,224 +0,0 @@ -#include "input_ffmpeg.h" -#include - -using namespace Mangle::Sound; - -// Static output buffer. Not thread safe, but supports multiple -// streams operated from the same thread. -static uint8_t outBuf[AVCODEC_MAX_AUDIO_FRAME_SIZE]; -bool FFM_InputManager::init = false; - -FFM_Exception::FFM_Exception(const std::string &m) - : msg(m) {} - -const char* FFM_Exception::what() const throw() -{ return msg.c_str(); } - -FFM_Exception::~FFM_Exception() throw() {} - -static void fail(const std::string &msg) -{ - throw FFM_Exception("FFMpeg exception: " + msg); -} - - -// --- Manager --- - -FFM_InputManager::FFM_InputManager() -{ - if(!init) - { - av_register_all(); - av_log_set_level(AV_LOG_ERROR); - init = true; - } - - canLoadStream = false; -} - -InputSource *FFM_InputManager::load(const std::string &file) -{ return new FFM_InputSource(file); } - - -// --- Source --- - -FFM_InputSource::FFM_InputSource(const std::string &file) -{ - // FFmpeg doesn't handle several instances from one source. So we - // just store the filename. - name = file; -} - -InputStream *FFM_InputSource::getStream() -{ return new FFM_InputStream(name); } - -void FFM_InputSource::drop() -{ delete this; } - - -// --- Stream --- - -FFM_InputStream::FFM_InputStream(const std::string &file) -{ - std::string msg; - AVCodec *codec; - - empty = false; - - if(av_open_input_file(&FmtCtx, file.c_str(), NULL, 0, NULL) != 0) - fail("Error loading audio file " + file); - - if(av_find_stream_info(FmtCtx) < 0) - { - msg = "Error in file stream " + file; - goto err; - } - - // Pick the first audio stream, if any - for(StreamNum = 0; StreamNum < FmtCtx->nb_streams; StreamNum++) - { - // Pick the first audio stream - if(FmtCtx->streams[StreamNum]->codec->codec_type == CODEC_TYPE_AUDIO) - break; - } - - if(StreamNum == FmtCtx->nb_streams) - fail("File " + file + " didn't contain any audio streams"); - - // Open the decoder - CodecCtx = FmtCtx->streams[StreamNum]->codec; - codec = avcodec_find_decoder(CodecCtx->codec_id); - - if(!codec || avcodec_open(CodecCtx, codec) < 0) - { - msg = "Error loading " + file + ": "; - if(codec) - msg += "coded error"; - else - msg += "no codec found"; - goto err; - } - - // No errors, we're done - return; - - // Handle errors - err: - av_close_input_file(FmtCtx); - fail(msg); -} - -FFM_InputStream::~FFM_InputStream() -{ - avcodec_close(CodecCtx); - av_close_input_file(FmtCtx); -} - -void FFM_InputStream::getInfo(int32_t *rate, int32_t *channels, int32_t *bits) -{ - if(rate) *rate = CodecCtx->sample_rate; - if(channels) *channels = CodecCtx->channels; - if(bits) *bits = 16; -} - -uint32_t FFM_InputStream::getData(void *data, uint32_t length) -{ - if(empty) return 0; - - uint32_t left = length; - uint8_t *outPtr = (uint8_t*)data; - - // First, copy over any stored data we might be sitting on - { - int s = storage.size(); - int copy = s; - if(s) - { - // Make sure there's room - if(copy > left) - copy = left; - - // Copy - memcpy(outPtr, &storage[0], copy); - outPtr += copy; - left -= copy; - - // Is there anything left in the storage? - s -= copy; - if(s) - { - assert(left == 0); - - // Move it to the start and resize - memmove(&storage[0], &storage[copy], s); - storage.resize(s); - } - } - } - - // Next, get more input data from stream, and decode it - while(left) - { - AVPacket packet; - - // Get the next packet, if any - if(av_read_frame(FmtCtx, &packet) < 0) - break; - - // We only allow one stream per file at the moment - assert(StreamNum == packet.stream_index); - - // Decode the packet - int len = AVCODEC_MAX_AUDIO_FRAME_SIZE; - int tmp = avcodec_decode_audio2(CodecCtx, (int16_t*)outBuf, - &len, packet.data, packet.size); - assert(tmp < 0 || tmp == packet.size); - - // We don't need the input packet any longer - av_free_packet(&packet); - - if(tmp < 0) - fail("Error decoding audio stream"); - - // Copy whatever data we got, and advance the pointer - if(len > 0) - { - // copy = how many bytes do we copy now - int copy = len; - if(copy > left) - copy = left; - - // len = how many bytes are left uncopied - len -= copy; - - // copy data - memcpy(outPtr, outBuf, copy); - - // left = how much space is left in the caller output - // buffer - left -= copy; - outPtr += copy; - assert(left >= 0); - - if(len > 0) - { - // There were uncopied bytes. Store them for later. - assert(left == 0); - storage.resize(len); - memcpy(&storage[0], outBuf, len); - } - } - } - - // End of loop. Return the number of bytes copied. - assert(left <= length); - - // If we're returning less than asked for, then we're done - if(left > 0) - empty = true; - - return length - left; -} - -void FFM_InputStream::drop() -{ delete this; } diff --git a/sound/servers/input_ffmpeg.h b/sound/servers/input_ffmpeg.h deleted file mode 100644 index b744a7585..000000000 --- a/sound/servers/input_ffmpeg.h +++ /dev/null @@ -1,75 +0,0 @@ -#ifndef MANGLE_SOUND_FFMPEG_H -#define MANGLE_SOUND_FFMPEG_H - -#include "../input.h" -#include -#include -#include - -extern "C" -{ -#include -#include -} - -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 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 diff --git a/sound/servers/input_filter.h b/sound/servers/input_filter.h deleted file mode 100644 index 455a60e14..000000000 --- a/sound/servers/input_filter.h +++ /dev/null @@ -1,80 +0,0 @@ -#ifndef MANGLE_INPUT_FILTER_H -#define MANGLE_INPUT_FILTER_H - -#include "../sound.h" - -#include - -namespace Mangle { -namespace Sound { - -/** - @brief This filter class adds file loading capabilities to a - Sound::Manager class, by associating an InputManager with it. - - The class takes an existing Manager able to load streams, and - associates an InputManager with it. The combined class is 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 -{ - protected: - Manager *snd; - InputManager *inp; - - public: - /// Empty constructor - InputFilter() {} - - /// Assign an input manager and a sound manager to this object - InputFilter(Manager *_snd, InputManager *_inp) - { set(_snd, _inp); } - - /// Assign an input manager and a sound manager to this object - void set(Manager *_snd, InputManager *_inp) - { - inp = _inp; - snd = _snd; - - // Set capabilities - needsUpdate = snd->needsUpdate; - has3D = snd->has3D; - canRepeatStream = snd->canRepeatStream; - canLoadStream = inp->canLoadStream; - - // Both these should be true, or the use of this class is pretty - // pointless - canLoadSource = snd->canLoadSource; - canLoadFile = canLoadSource; - assert(canLoadSource && canLoadFile); - } - - virtual Sound *load(const std::string &file, bool stream=false) - { return load(inp->load(file), stream); } - - virtual Sound *load(Stream::Stream *input, bool stream=false) - { return load(inp->load(input), stream); } - - virtual Sound *load(InputSource *input, bool stream=false) - { return snd->load(input, stream); } - - virtual void update() { snd->update(); } - virtual void setListenerPos(float x, float y, float z, - float fx, float fy, float fz, - float ux, float uy, float uz) - { snd->setListenerPos(x,y,z,fx,fy,fz,ux,uy,uz); } -}; - -}} -#endif diff --git a/sound/servers/openal_audiere.h b/sound/servers/openal_audiere.h deleted file mode 100644 index 65947b22f..000000000 --- a/sound/servers/openal_audiere.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef MANGLE_FFMPEG_OPENAL_H -#define MANGLE_FFMPEG_OPENAL_H - -#include "input_filter.h" -#include "input_audiere.h" -#include "output_openal.h" - -namespace Mangle { -namespace Sound { - -/// A InputFilter that adds audiere decoding to OpenAL. Audiere has -/// it's own output, but OpenAL sports 3D and other advanced features. -class OpenAL_Audiere_Manager : public InputFilter -{ - public: - OpenAL_Audiere_Manager() - { - set(new OpenAL_Manager, - new AudiereInput); - } - ~OpenAL_Audiere_Manager() - { - delete snd; - delete inp; - } -}; - -}} -#endif diff --git a/sound/servers/openal_ffmpeg.h b/sound/servers/openal_ffmpeg.h deleted file mode 100644 index 179d3cb70..000000000 --- a/sound/servers/openal_ffmpeg.h +++ /dev/null @@ -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 diff --git a/sound/servers/output_openal.cpp b/sound/servers/output_openal.cpp deleted file mode 100644 index 06a8edca8..000000000 --- a/sound/servers/output_openal.cpp +++ /dev/null @@ -1,353 +0,0 @@ -#include "output_openal.h" -#include - -#include - -using namespace Mangle::Sound; - - -// ---- Helper functions and classes ---- - -class OpenAL_Exception : public std::exception -{ - std::string msg; - - public: - - OpenAL_Exception(const std::string &m) : msg(m) {} - ~OpenAL_Exception() throw() {} - virtual const char* what() const throw() { return msg.c_str(); } -}; - -static void fail(const std::string &msg) -{ - throw OpenAL_Exception("OpenAL exception: " + msg); -} - -static void checkALError(const std::string &msg) -{ - ALenum err = alGetError(); - if(err != AL_NO_ERROR) - fail("\"" + std::string(alGetString(err)) + "\" while " + msg); -} - -static void getALFormat(InputStream *inp, int &fmt, int &rate) -{ - int ch, bits; - inp->getInfo(&rate, &ch, &bits); - - fmt = 0; - - if(bits == 8) - { - if(ch == 1) fmt = AL_FORMAT_MONO8; - if(ch == 2) fmt = AL_FORMAT_STEREO8; - if(alIsExtensionPresent("AL_EXT_MCFORMATS")) - { - if(ch == 4) fmt = alGetEnumValue("AL_FORMAT_QUAD8"); - if(ch == 6) fmt = alGetEnumValue("AL_FORMAT_51CHN8"); - } - } - if(bits == 16) - { - if(ch == 1) fmt = AL_FORMAT_MONO16; - if(ch == 2) fmt = AL_FORMAT_STEREO16; - if(ch == 4) fmt = alGetEnumValue("AL_FORMAT_QUAD16"); - if(alIsExtensionPresent("AL_EXT_MCFORMATS")) - { - if(ch == 4) fmt = alGetEnumValue("AL_FORMAT_QUAD16"); - if(ch == 6) fmt = alGetEnumValue("AL_FORMAT_51CHN16"); - } - } - - if(fmt == 0) - fail("Unsupported input format"); -} - - -// ---- Manager ---- - -OpenAL_Manager::OpenAL_Manager() - : Context(NULL), Device(NULL) -{ - needsUpdate = true; - has3D = true; - canRepeatStream = false; - canLoadFile = false; - canLoadSource = true; - canLoadStream = false; - - // Set up sound system - Device = alcOpenDevice(NULL); - Context = alcCreateContext(Device, NULL); - - if(!Device || !Context) - fail("Failed to initialize context or device"); - - alcMakeContextCurrent(Context); -} - -OpenAL_Manager::~OpenAL_Manager() -{ - // Deinitialize sound system - alcMakeContextCurrent(NULL); - if(Context) alcDestroyContext(Context); - if(Device) alcCloseDevice(Device); -} - -Sound *OpenAL_Manager::load(const std::string &file, bool stream) -{ assert(0 && "OpenAL cannot decode files"); } - -Sound *OpenAL_Manager::load(Stream::Stream*,bool) -{ assert(0 && "OpenAL cannot decode streams"); } - -Sound *OpenAL_Manager::load(InputSource *source, bool stream) -{ return new OpenAL_Sound(source, this, stream); } - -void OpenAL_Manager::update() -{ - // Loop through all the streaming sounds and update them - LST::iterator it, next; - for(it = streaming.begin(); - it != streaming.end(); - it++) - { - (*it)->update(); - } -} - -void OpenAL_Manager::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); - checkALError("setting listener position"); -} - -OpenAL_Manager::LST::iterator OpenAL_Manager::add_stream(OpenAL_Stream_Instance* inst) -{ - streaming.push_front(inst); - return streaming.begin(); -} - -void OpenAL_Manager::remove_stream(LST::iterator it) -{ - streaming.erase(it); -} - - -// ---- Sound ---- - -OpenAL_Sound::~OpenAL_Sound() -{ - // Kill the input source - if(source) source->drop(); - - // And any allocated buffers - if(bufferID) - alDeleteBuffers(1, &bufferID); -} - -Instance *OpenAL_Sound::getInstance(bool is3d, bool repeat) -{ - assert((!repeat || !stream) && "OpenAL implementation does not support looping streams"); - - if(stream) - 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 buffer; - - // Add 32 kb at each increment - const int ADD = 32*1024; - - // Fill the buffer. We increase the buffer until it's large - // enough to fit all the data. - 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); - - return new OpenAL_Simple_Instance(bufferID); -} - - -// ---- OpenAL_Instance_Base ---- - -void OpenAL_Instance_Base::play() -{ - alSourcePlay(inst); - checkALError("starting playback"); -} - -void OpenAL_Instance_Base::stop() -{ - alSourceStop(inst); - checkALError("stopping"); -} - -void OpenAL_Instance_Base::pause() -{ - alSourcePause(inst); - checkALError("pausing"); -} - -bool OpenAL_Instance_Base::isPlaying() -{ - ALint state; - alGetSourcei(inst, AL_SOURCE_STATE, &state); - - return state == AL_PLAYING; -} - -void OpenAL_Instance_Base::setVolume(float volume) -{ - if(volume > 1.0) volume = 1.0; - if(volume < 0.0) volume = 0.0; - alSourcef(inst, AL_GAIN, volume); - checkALError("setting volume"); -} - -void OpenAL_Instance_Base::setPos(float x, float y, float z) -{ - alSource3f(inst, AL_POSITION, x, y, z); - checkALError("setting position"); -} - - -// ---- OpenAL_Simple_Instance ---- - -OpenAL_Simple_Instance::OpenAL_Simple_Instance(ALuint buf) -{ - // Create instance and associate buffer - alGenSources(1, &inst); - alSourcei(inst, AL_BUFFER, buf); -} - -OpenAL_Simple_Instance::~OpenAL_Simple_Instance() -{ - // Stop - alSourceStop(inst); - - // Return sound - 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; iadd_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 - alBufferData(bId, fmt, buf, len, rate); - 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); - } -} diff --git a/sound/servers/output_openal.h b/sound/servers/output_openal.h deleted file mode 100644 index 53226c32f..000000000 --- a/sound/servers/output_openal.h +++ /dev/null @@ -1,125 +0,0 @@ -#ifndef MANGLE_SOUND_OPENAL_H -#define MANGLE_SOUND_OPENAL_H - -#include "../sound.h" - -#include -#include -#include - -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 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