From: <kla...@us...> - 2008-08-02 21:59:18
|
Revision: 12402 http://vegastrike.svn.sourceforge.net/vegastrike/?rev=12402&view=rev Author: klaussfreire Date: 2008-08-02 21:59:18 +0000 (Sat, 02 Aug 2008) Log Message: ----------- More work on audio stuff Modified Paths: -------------- branches/audio/vegastrike/src/audio/Exceptions.h branches/audio/vegastrike/src/audio/Format.h branches/audio/vegastrike/src/audio/Listener.h branches/audio/vegastrike/src/audio/RenderableSource.cpp branches/audio/vegastrike/src/audio/Renderer.h branches/audio/vegastrike/src/audio/SceneManager.cpp branches/audio/vegastrike/src/audio/SceneManager.h branches/audio/vegastrike/src/audio/Sound.cpp branches/audio/vegastrike/src/audio/Sound.h branches/audio/vegastrike/src/audio/utils.h Added Paths: ----------- branches/audio/vegastrike/src/audio/RenderableListener.cpp branches/audio/vegastrike/src/audio/RenderableListener.h branches/audio/vegastrike/src/audio/SimpleSound.cpp branches/audio/vegastrike/src/audio/SimpleSound.h branches/audio/vegastrike/src/audio/SoundBuffer.cpp branches/audio/vegastrike/src/audio/SoundBuffer.h branches/audio/vegastrike/src/audio/VirtualIterator.h branches/audio/vegastrike/src/audio/renderers/ branches/audio/vegastrike/src/audio/renderers/OpenAL/ branches/audio/vegastrike/src/audio/renderers/OpenAL/OpenALRenderer.cpp branches/audio/vegastrike/src/audio/renderers/OpenAL/OpenALRenderer.h branches/audio/vegastrike/src/audio/renderers/OpenAL/al.h Modified: branches/audio/vegastrike/src/audio/Exceptions.h =================================================================== --- branches/audio/vegastrike/src/audio/Exceptions.h 2008-08-02 01:23:00 UTC (rev 12401) +++ branches/audio/vegastrike/src/audio/Exceptions.h 2008-08-02 21:59:18 UTC (rev 12402) @@ -106,6 +106,19 @@ }; /** + * Resource already loaded exception + * @remarks thrown when an attempt to load a resource that has already been loaded is made, + * within a context where transparent failure is not desirable, or such decision left + * to the caller (such cases should be explicitly documented). + */ + class ResourceAlreadyLoadedException : public Exception { + public: + ResourceAlreadyLoadedException() {} + ResourceAlreadyLoadedException(const ResourceAlreadyLoadedException &other) : Exception(other) {} + explicit ResourceAlreadyLoadedException(const std::string &message) : Exception(message) {} + }; + + /** * Attempted to create an object that already existed */ class DuplicateObjectException : public Exception { @@ -123,6 +136,23 @@ Exception(std::string("Object with name \"") + name + "\" does not exist") {} }; + /** + * Request for unimplemented features + */ + class NotImplementedException : public Exception { + public: + explicit NotImplementedException(const std::string &name) : + Exception(name + " has not been implemented yet") {} + }; + + /** + * Ran out of memory while performing some operation + */ + class OutOfMemoryException : public Exception { + public: + OutOfMemoryException() {} + }; + }; #endif//__AUDIO_EXCEPTIONS_H__INCLUDED__ Modified: branches/audio/vegastrike/src/audio/Format.h =================================================================== --- branches/audio/vegastrike/src/audio/Format.h 2008-08-02 01:23:00 UTC (rev 12401) +++ branches/audio/vegastrike/src/audio/Format.h 2008-08-02 21:59:18 UTC (rev 12402) @@ -16,6 +16,30 @@ unsigned char channels; int signedSamples : 1; int nativeOrder : 1; + + unsigned int frameSize() const + { + return (bitsPerSample * channels + 7) / 8; + } + + unsigned int bytesPerSecond() const + { + return frameSize() * sampleFrequency; + } + + bool operator==(const Format &o) const + { + return (sampleFrequency == o.sampleFrequency) + && (bitesPerSample == o.bitsPerSample) + && (channels == o.channels) + && (signedSamples == o.signedSamples) + && (nativeOrder == o.nativeOrder); + } + + bool operator!=(const Format &o) const + { + return !(*this == o); + } }; }; Modified: branches/audio/vegastrike/src/audio/Listener.h =================================================================== --- branches/audio/vegastrike/src/audio/Listener.h 2008-08-02 01:23:00 UTC (rev 12401) +++ branches/audio/vegastrike/src/audio/Listener.h 2008-08-02 21:59:18 UTC (rev 12402) @@ -9,6 +9,9 @@ namespace Audio { + // Some forward declarations of referenced-yet-unused classes + class RenderableListener; + /** * Listener class * @@ -29,7 +32,7 @@ Range<Scalar> cosAngleRange; SharedPtr<UserData> userDataPtr; - SharedPtr<UserData> rendererDataPtr; + SharedPtr<RenderableListener> rendererDataPtr; protected: /** Notify implementations after position and/or attributes changes @@ -103,10 +106,10 @@ /** Get renderer-specific data associated (and destroyed) with this sound source */ - SharedPtr<UserData> getRendererData() const throw() { return rendererDataPtr; } + SharedPtr<RenderableListener> getRendererable() const throw() { return rendererDataPtr; } /** Set renderer-specific data to be associated (and destroyed) with this sound source */ - void setRendererData(SharedPtr<UserData> ptr) throw() { rendererDataPtr = ptr; } + void setRendererable(SharedPtr<RenderableListener> ptr) throw() { rendererDataPtr = ptr; } /** Get user-specific data associated (and destroyed) with this listener */ SharedPtr<UserData> getUserData() const throw() { return userDataPtr; } Added: branches/audio/vegastrike/src/audio/RenderableListener.cpp =================================================================== --- branches/audio/vegastrike/src/audio/RenderableListener.cpp (rev 0) +++ branches/audio/vegastrike/src/audio/RenderableListener.cpp 2008-08-02 21:59:18 UTC (rev 12402) @@ -0,0 +1,29 @@ +// +// C++ Implementation: Audio::RenderableListener +// + +#include "RenderableListener.h" +#include "config.h" + +namespace Audio { + + RenderableListener::RenderableListener(Listener *_listener) throw() : + listener(_listener) + { + } + + RenderableListener::~RenderableListener() + { + // Just in case. + listener = 0; + } + + void RenderableListener::update(UpdateFlags flags) + throw() + { + try { + updateImpl(flags); + } catch(Exception e) {} + } + +}; Added: branches/audio/vegastrike/src/audio/RenderableListener.h =================================================================== --- branches/audio/vegastrike/src/audio/RenderableListener.h (rev 0) +++ branches/audio/vegastrike/src/audio/RenderableListener.h 2008-08-02 21:59:18 UTC (rev 12402) @@ -0,0 +1,72 @@ +// +// C++ Interface: Audio::RenderableSource +// +#ifndef __AUDIO_RENDERABLELISTENER_H__INCLUDED__ +#define __AUDIO_RENDERABLELISTENER_H__INCLUDED__ + +#include "Exceptions.h" +#include "Types.h" + +namespace Audio { + + // Forward declarations + + class Listener; + + + /** + * Renderable Listener abstract class + * + * @remarks This is the interface to renderer-specific listeners. + * Listeners attached to a renderer receive one such instance + * that allows listener-specific commands to be given to the + * renderer, like requesting position updates and such. + * @note Since this mutual attachment would create circular references, + * it is implemented on this side with raw pointers. No problem should arise since + * the smart pointer used in abstract listener already handles everything correctly, + * but care must be had not to have detached renderable listeners around. + * + */ + class RenderableListener : public UserData + { + private: + Listener *listener; + + protected: + /** Internal constructor used by derived classes */ + RenderableListener(Listener *listener) throw(); + + public: + virtual ~RenderableListener(); + + enum UpdateFlags { + UPDATE_ALL, + UPDATE_LOCATION, + UPDATE_ATTRIBUTES, + UPDATE_EFFECTS + }; + + /** Get the attached listener */ + Listener* getListener() const throw() { return listener; } + + /** Update the underlying API with dirty attributes + * @param flags You may specify which attributes to update. Not all attributes are + * equally costly, so you'll want to ease up on some, pump up some others. + * @remarks Although the implementation may throw exceptions, the interface will + * ignore them (just log them or something like that). Updates are non-critical + * and may fail silently. + */ + void update(UpdateFlags flags) throw(); + + // The following section contains all the virtual functions that need be implemented + // by a concrete class. All are protected, so the interface is independent + // of implementations. + protected: + + /** @see update. */ + virtual void updateImpl(UpdateFlags flags) throw(Exception) = 0; + }; + +}; + +#endif//__AUDIO_RENDERABLELISTENER_H__INCLUDED__ Modified: branches/audio/vegastrike/src/audio/RenderableSource.cpp =================================================================== --- branches/audio/vegastrike/src/audio/RenderableSource.cpp 2008-08-02 01:23:00 UTC (rev 12401) +++ branches/audio/vegastrike/src/audio/RenderableSource.cpp 2008-08-02 21:59:18 UTC (rev 12402) @@ -53,11 +53,11 @@ return getPlayingTimeImpl(); } - void RenderableSource::update(UpdateFlags flags) + void RenderableSource::update(UpdateFlags flags, const Listener& sceneListener) throw() { try { - updateImpl(flags); + updateImpl(flags, sceneListener); } catch(Exception e) {} } Modified: branches/audio/vegastrike/src/audio/Renderer.h =================================================================== --- branches/audio/vegastrike/src/audio/Renderer.h 2008-08-02 01:23:00 UTC (rev 12401) +++ branches/audio/vegastrike/src/audio/Renderer.h 2008-08-02 21:59:18 UTC (rev 12402) @@ -90,7 +90,7 @@ /** Detach a listener from this renderer. * @remarks Immediately frees any allocated resources. */ - virtual void detach(SharedPtr<Listener> source) throw() = 0; + virtual void detach(SharedPtr<Listener> listener) throw() = 0; Modified: branches/audio/vegastrike/src/audio/SceneManager.cpp =================================================================== --- branches/audio/vegastrike/src/audio/SceneManager.cpp 2008-08-02 01:23:00 UTC (rev 12401) +++ branches/audio/vegastrike/src/audio/SceneManager.cpp 2008-08-02 21:59:18 UTC (rev 12402) @@ -68,6 +68,7 @@ Timestamp lastPositionUpdateTime; Timestamp lastAttributeUpdateTime; Timestamp lastListenerUpdateTime; + Timestamp lastListenerAttUpdateTime; Timestamp lastActivationTime; Duration positionUpdateFrequency; @@ -360,18 +361,34 @@ void SceneManager::commit() throw(Exception) { - Timestamp realTime = getRealTime(); - bool needActivation = ((realTime - getActivationFrequency()) >= data->lastActivationTime); - bool needPosUpdates = ((realTime - getPositionUpdateFrequency()) >= data->lastPositionUpdateTime); - bool needAttUpdates = ((realTime - getAttributeUpdateFrequency()) >= data->lastAttributeUpdateTime); - bool needListenerUpdate = ((realTime - getListenerUpdateFrequency()) >= data->lastListenerUpdateTime); + Timestamp realTime = getRealTime(); + bool needActivation = ((realTime - getActivationFrequency()) >= data->lastActivationTime); + bool needPosUpdates = ((realTime - getPositionUpdateFrequency()) >= data->lastPositionUpdateTime); + bool needAttUpdates = ((realTime - getAttributeUpdateFrequency()) >= data->lastAttributeUpdateTime); + bool needListenerUpdate = ((realTime - getListenerUpdateFrequency()) >= data->lastListenerUpdateTime); + bool needListenerAttUpdate = ((realTime - getAttributeUpdateFrequency()) >= data->lastListenerAttUpdateTime); - if (needActivation) + if (needActivation) { activationPhaseImpl(); - if (needPosUpdates || needAttUpdates) + + data->lastActivationTime = realTime; + } + + if (needPosUpdates || needAttUpdates) { updateSourcesImpl(needAttUpdates); - if (needListenerUpdate) - updateListenerImpl(); + + data->lastPositionUpdateTime = realTime; + if (needAttUpdates) + data->lastAttributeUpdateTime = realTime; + } + + if (needListenerUpdate) { + updateListenerImpl(needListenerAttUpdate); + + data->lastListenerUpdateTime = realTime; + if (needListenerAttUpdate) + data->lastListenerAttUpdateTime = realTime; + } } struct SourcePriorityRef { @@ -478,9 +495,15 @@ it->source->updateRenderable(updateFlags, it->scene->getListener()); } - void SceneManager::updateListenerImpl() + void SceneManager::updateListenerImpl(bool withAttributes) throw(Exception) { + RenderableListener::UpdateFlags updateFlags = + withAttributes ? + RenderableListener::UPDATE_ALL : + RenderableListener::UPDATE_LOCATION; + if (data->rootListener.get()) + data->rootListener->updateRenderable(updateFlags); } Duration SceneManager::getPositionUpdateFrequency() const Modified: branches/audio/vegastrike/src/audio/SceneManager.h =================================================================== --- branches/audio/vegastrike/src/audio/SceneManager.h 2008-08-02 01:23:00 UTC (rev 12401) +++ branches/audio/vegastrike/src/audio/SceneManager.h 2008-08-02 21:59:18 UTC (rev 12402) @@ -23,7 +23,7 @@ namespace __impl { - // Forward declaration of internal template manager data + // Forward declaration of internal scene manager data struct SceneManagerData; }; @@ -328,7 +328,7 @@ * @remarks Since renderer implementations require one listener, this only updates * the root listener. Scene listeners fall under the category of position updates. */ - virtual void updateListenerImpl() throw(Exception); + virtual void updateListenerImpl(bool withAttributes) throw(Exception); }; }; Added: branches/audio/vegastrike/src/audio/SimpleSound.cpp =================================================================== --- branches/audio/vegastrike/src/audio/SimpleSound.cpp (rev 0) +++ branches/audio/vegastrike/src/audio/SimpleSound.cpp 2008-08-02 21:59:18 UTC (rev 12402) @@ -0,0 +1,82 @@ +// +// C++ Implementation: Audio::SimpleSound +// + +#include "SimpleSound.h" +#include "config.h" + +#include "CodecRegistry.h" + +namespace Audio { + + SimpleSound::SimpleSound(const std::string& name, VSFileSystem::VSFileType _type) + throw() + : Sound(name), + type(_type) + { + } + + SimpleSound::~SimpleSound() + { + } + + void SimpleSound::loadStream() + throw(Exception) + { + if (isStreamLoaded) + throw(ResourceAlreadyLoadedException()); + + // Open stream and initialize shared pointer + stream.reset( + CodecRegistry::getSingleton()->open( + getName(), + getType() + ) + ); + + // Copy format + getFormat() = getStream()->getFormat(); + } + + void closeStream() + throw(ResourceNotLoadedException) + { + if (!isStreamLoaded()) + throw(ResourceNotLoadedException()); + stream.reset(0); + } + + SharedPtr<Stream> SimpleSound::getStream() const + throw(ResourceNotLoadedException) + { + if (!isStreamLoaded()) + throw(ResourceNotLoadedException()); + return stream; + } + + void SimpleSound::readBuffer(SoundBuffer &buffer) + throw(Exception) + { + if (buffer.getFormat() == getFormat()) { + // Same formats, so all we have to do is read bytes ;) + buffer.setUsedBytes( + getStream()->read( buffer.getBuffer(), buffer.getByteCapacity() ) + ); + } else { + // Save the buffer format, we'll have to reformat to this format + Format targetFormat = buffer.getFormat(); + + // Set buffer format to stream format + buffer.setFormat(getFormat()); + + // Now read bytes from the stream + buffer.setUsedBytes( + getStream()->read( buffer.getBuffer(), buffer.getByteCapacity() ) + ); + + // Finally we have to reformat the buffer back to the original format + buffer.reformat(targetFormat); + } + } + +}; Added: branches/audio/vegastrike/src/audio/SimpleSound.h =================================================================== --- branches/audio/vegastrike/src/audio/SimpleSound.h (rev 0) +++ branches/audio/vegastrike/src/audio/SimpleSound.h 2008-08-02 21:59:18 UTC (rev 12402) @@ -0,0 +1,87 @@ +// +// C++ Interface: Audio::SimpleSound +// +#ifndef __AUDIO_SIMPLESOUND_H__INCLUDED__ +#define __AUDIO_SIMPLESOUND_H__INCLUDED__ + +#include "Exceptions.h" +#include "Types.h" +#include "Format.h" +#include "Sound.h" +#include "SoundBuffer.h" + +#include "vsfilesystem.h" + +namespace Audio { + + // Forward definitions + class Stream; + + /** + * Simple Sound abstract class + * + * @remarks This partial implementation implements foreground loading of files + * using the codec registry. + * @par No background loading is implemented, meaning all requests for load, + * even with wait=false, are processed in the foreground. + * @par There's a possibility for streaming given the packetized pulling + * architecture. Renderers are not required to pull all packets from the stream, + * and access to the Stream object is also provided for seeking back and forth. + * @par Renderers still have to override (un)loadImpl() and abortLoad(). + * This refinement merely adds supporting methods for implementing them. + * @see Sound, BackgroundLoadingSound + * + */ + class SimpleSound + { + private: + SharedPtr<Stream> stream; + VSFileSystem::VSFileType type; + + protected: + /** Internal constructor used by derived classes */ + SimpleSound(const std::string& name, VSFileSystem::VSFileType type = VSFileSystem::UnknownFile) throw(); + + public: + virtual ~SimpleSound(); + + /** VSFileSystem File type */ + VSFileSystem::VSFileType getType() const { return type; } + + // The following section contains supporting methods for accessing the stream. + // Subclasses need not bother with actual stream management, they need only worry + // about sending the samples to where they're needed. + protected: + + /** Do we have an open stream? */ + bool isStreamLoaded() const { return stream.get() != 0; } + + /** Initialize the stream. + * @remarks Calling this when the stream has already been initialized will + * raise an ReasourceAlreadyLoadedException. + */ + void loadStream() throw(Exception); + + /** Uninitialize the stream + * @remarks Calling this when isStreamLoaded() returns false will raise an + * ResourceNotLoadedException. + */ + void closeStream() throw(ResourceNotLoadedException); + + /** Get a pointer to the stream + * @remarks Calling this when isStreamLoaded() returns false will raise an + * ResourceNotLoadedException. + */ + SharedPtr<Stream> getStream() const throw(ResourceNotLoadedException); + + /** Read from the stream into the buffer + * @remarks Will throw EndOfStreamException when the end of the stream + * is reached. Any other exception is probably fatal. + */ + void readBuffer(SoundBuffer &buffer) throw(Exception); + + }; + +}; + +#endif//__AUDIO_SIMPLESOUND_H__INCLUDED__ Modified: branches/audio/vegastrike/src/audio/Sound.cpp =================================================================== --- branches/audio/vegastrike/src/audio/Sound.cpp 2008-08-02 01:23:00 UTC (rev 12401) +++ branches/audio/vegastrike/src/audio/Sound.cpp 2008-08-02 21:59:18 UTC (rev 12402) @@ -5,6 +5,8 @@ #include "Sound.h" #include "config.h" +#include "utils.h" + namespace Audio { Sound::Sound(const std::string& _name) throw() : @@ -16,20 +18,42 @@ { } - void Sound::load() throw(Exception) + void Sound::load(bool wait) throw(Exception) { if (!isLoaded()) { - loadImpl(); - loaded = true; + if (!isLoading()) + loadImpl(wait); + if (wait && !isLoaded()) + waitLoad(); } } - void Sound::unload() throw() + void Sound::waitLoad() + throw(Exception) { + while (isLoading()) + Audio::sleep(0); + } + + void Sound::unload() + throw() + { + if (isLoading()) { + abortLoad(); + if (isLoading()) + waitLoad(); + } if (isLoaded()) { unloadImpl(); loaded = false; } } + void Sound::onLoaded(bool success) + throw() + { + loaded = success; + loading = false; + } + }; Modified: branches/audio/vegastrike/src/audio/Sound.h =================================================================== --- branches/audio/vegastrike/src/audio/Sound.h 2008-08-02 01:23:00 UTC (rev 12401) +++ branches/audio/vegastrike/src/audio/Sound.h 2008-08-02 21:59:18 UTC (rev 12402) @@ -32,6 +32,11 @@ */ bool loaded; + /** Background loading state of the resource. + * @note Accessible to derived classes to support easier and safer threading + */ + bool loading; + protected: /** Internal constructor used by derived classes */ Sound(const std::string& name) throw(); @@ -52,9 +57,24 @@ /** Return whether the resource has been loaded or not */ bool isLoaded() const throw() { return loaded; } - /** Load the resource if not loaded */ - void load() throw(Exception); + /** Return whether the resource is being loaded in the background */ + bool isLoading() const throw() { return loading; } + /** Load the resource if not loaded + * @param wait If true, the function will return only when the resource + * has been loaded (or failed to load). Exceptions will be risen on + * failure. If false, however, a request for background loading is + * issued which may or may not be performed asynchronously. In the + * event the implementation does provide background loading of resources, + * exceptions and error conditions will be masked because of the + * asynchronicity. Only subsequent calls to isLoading() / isLoaded + * will allow for such events to be recognized: if it ceases to be + * in loading state yet it isn't loaded, either it has been immediately + * unloaded (memory short), or an error ocurred during load and it never + * became loaded. + */ + void load(bool wait = true) throw(Exception); + /** Unload the resource if loaded */ void unload() throw(); @@ -62,16 +82,39 @@ // by a concrete Sound class. All are protected, so the stream interface is independent // of implementations. protected: + + /** loadImpl should call this upon process termination + * @remarks Either from the foreground thread or the background thread, + * whichever is performing the actual load). + * The method guaranteed to be threadsafe. + * @param success Whether or not the process succeeded in loading the resource + */ + virtual void onLoaded(bool success) throw(); + /** Wait for background loading to finish + * @remarks The base implementation checks for completion periodically. + * Implementations are likely to have better ways to do this, so they're + * welcome to override this method. + */ + virtual void waitLoad() throw(Exception); + /** Load the resource - * @note Assume it is unloaded + * @note Assume it is unloaded and not loading */ - virtual double loadImpl() const throw(Exception) = 0; + virtual void loadImpl(bool wait) throw(Exception) = 0; + /** Abort an in-progress background load procedure + * @note Although no exceptions should be risen, the abort request may + * not be carried out for various reasons. The caller should check + * that on return by calling isLoaded() / isLoading(). + */ + virtual void abortLoad() throw() = 0; + + /** Unload the resource. * @note Assume it is loaded */ - virtual double unloadImpl() const throw() = 0; + virtual void unloadImpl() throw() = 0; }; Added: branches/audio/vegastrike/src/audio/SoundBuffer.cpp =================================================================== --- branches/audio/vegastrike/src/audio/SoundBuffer.cpp (rev 0) +++ branches/audio/vegastrike/src/audio/SoundBuffer.cpp 2008-08-02 21:59:18 UTC (rev 12402) @@ -0,0 +1,56 @@ +// +// C++ Implementation: Audio::SoundBuffer +// + +#include "SoundBuffer.h" +#include "config.h" + +#include <memory.h> + +namespace Audio { + + SoundBuffer::SoundBuffer() + throw() + : buffer(0), + byteCapacity(0), + bytesUsed(0) + { + } + + SoundBuffer::SoundBuffer(unsigned int capacity, const Format &format) + throw(OutOfMemoryException) + : SoundBuffer() + { + reserve(capacity, format); + } + + SoundBuffer::SoundBuffer(const SoundBuffer &other) + throw(OutOfMemoryException) + { + bytesUsed = byteCapacity = other.bytesUsed; + buffer = malloc(byteCapacity); + if (buffer == 0) + throw OutOfMemoryException(); + memcpy(buffer, other.buffer, bytesUsed); + format = other.format; + } + + void SoundBuffer::reserve(unsigned int capacity, const Format &_format) + { + format = _format; + byteCapacity = capacity * _format.frameSize(); + bytesUsed = 0; + + buffer = realloc(buffer, byteCapacity); + if (buffer == 0) + throw OutOfMemoryException(); + } + + void SoundBuffer::reformat(const Format &newFormat) + throw(Exception) + { + if (newFormat != format) + throw(NotImplementedException("Format conversion")); + } + +}; Added: branches/audio/vegastrike/src/audio/SoundBuffer.h =================================================================== --- branches/audio/vegastrike/src/audio/SoundBuffer.h (rev 0) +++ branches/audio/vegastrike/src/audio/SoundBuffer.h 2008-08-02 21:59:18 UTC (rev 12402) @@ -0,0 +1,96 @@ +// +// C++ Interface: Audio::SoundBuffer +// + +#ifndef __AUDIO__SOUND_BUFFER__INCLUDED__ +#define __AUDIO__SOUND_BUFFER__INCLUDED__ + +#include "Exceptions.h" +#include "Format.h" + +namespace Audio { + + /** + * Sound Buffer class + * + * @remarks + * This class represents a buffer for sound data. + * Though codecs usually treat samples as raw bytes in some uninteresting + * (for the api) format, renderers don't have that luxury. + * @par This class encapsulates buffers and associates a format to them, + * allowing for the implementation of format conversion (should it be + * needed). + * @par At this point no conversion is supported, and requiring such + * a conversion would raise a NotImplementedException. + */ + class SoundBuffer + { + private: + void *buffer; + unsigned int byteCapacity; + unsigned int bytesUsed; + + Format format; + + public: + /** Create an empty buffer (zero capacity, default format) */ + SoundBuffer() throw(); + + /** Create a buffer of specified sample capacity and format */ + SoundBuffer(unsigned int capacity, const Format &format) throw(OutOfMemoryException); + + /** Create a copy of the other buffer + * @remarks Only used bytes will be copied. + */ + SoundBuffer(const SoundBuffer &other) throw(OutOfMemoryException); + + /** Set a buffer's capacity and format. + * @param capacity The buffer's capacity in samples (or frames) for 'format' + * @param format The new format associated to the buffer + * @remarks Destroys the current data in the buffer. + */ + void reserve(unsigned int capacity, const Format &format) throw(OutOfMemoryException); + + /** Get a buffer's byte capacity */ + unsigned int getByteCapacity() const throw() { return byteCapacity; } + + /** Get a buffer's sample capacity + * @remarks Frame capacity actually, which is not the same for multichannel formats. + */ + unsigned int getSampleCapacity() const throw() { return byteCapacity / format.frameSize(); } + + /** Get the portion of the buffer actually used for holding useful data */ + unsigned int getUsedBytes() const throw() { return bytesUsed; } + + /** Get write access to the buffer */ + void* getBuffer() throw() { return buffer; } + + /** Get read access to the buffer */ + const void* getBuffer() const throw() { return buffer; } + + /** Get the buffer's format */ + const Format& getFormat() const { return format; } + + /** Set the format of the stream mantaining the capacity yet destroying all current data */ + void setFormat(const Format &newFormat) throw() { format = newFormat; usedBytes = 0; } + + /** Set the portion of the buffer actually used for holding useful data */ + void setUsedBytes(unsigned int used) throw() { bytesUsed = used; } + + /** Get a buffer's sample capacity for a certain format */ + unsigned int getSampleCount() const throw() { return bytesUsed / format.frameSize(); } + + /** Reformat the samples in the buffer without reallocating if possible (inplace) + * @remarks If the new format requires more bytes than the buffer's byte capacity, + * reallocation will be unavoidable. However, if the same buffer is used + * for conversion of several packets, subsequent operations on same-sized + * packets will not require such a reallocation, since if the new format + * requires less bytes only the used bytes count will be modified leaving + * the same byte capacity. + */ + void reformat(const Format &newFormat) throw(Exception); + }; + +}; + +#endif//__AUDIO__SOUND_BUFFER__INCLUDED__ Added: branches/audio/vegastrike/src/audio/VirtualIterator.h =================================================================== --- branches/audio/vegastrike/src/audio/VirtualIterator.h (rev 0) +++ branches/audio/vegastrike/src/audio/VirtualIterator.h 2008-08-02 21:59:18 UTC (rev 12402) @@ -0,0 +1,129 @@ +#ifndef __AUDIO_VIRTUALITERATOR_H__INCLUDED__ +#define __AUDIO_VIRTUALITERATOR_H__INCLUDED__ + +#include "Types.h" +#include <iterator> + +namespace Audio { + + /** Used to derive virtual iterator types + @remarks + Since all operators are virtual, it is recommended not to use these iterators + for iterating through large collections... + @note + By necessity, due to design constraints, no postfix increment/decrement operators + are defined: those don't get along with virtuality. + */ + template<class _T, class _Rt, class _Pt> class VirtualIterator : public std::iterator< std::bidirectional_iterator_tag , _T > + { + public: + typedef _T value_type; + typedef _Rt reference_type; + typedef _Pt pointer_type; + typedef VirtualIterator<_T,_IDt,_Rt,_Pt> iterator_type; + + VirtualIterator() {} + virtual ~VirtualIterator() {} + + virtual reference_type operator*() const = 0; + virtual pointer_type operator->() const = 0; + + virtual iterator_type& operator++() = 0; + virtual iterator_type& operator--() = 0; + + virtual bool operator==(const iterator_type& other) const = 0; + bool operator!=(const iterator_type& other) const { return !(*this == other); } + + virtual SharedPtr<iterator_type> clone() const = 0; + + /// End-of-sequence + virtual bool eos() const = 0; + + /// Start-of-sequence + virtual bool sos() const = 0; + + /* Aliases + * + * since virtual iterators must be handled through pointers, the standard + * operator interface is highly inconvenient + */ + + reference_type get() const { return **this; } + pointer_type getPtr() const { return this->operator->(); } + + iterator_type& next() { return ++(*this); } + iterator_type& prev() { return --(*this); } + }; + + template <typename _It> class VirtualStandardIterator : + public VirtualIterator< + typename iterator_traits<_It>::value_type, + typename iterator_traits<_It>::reference_type, + typename iterator_traits<_It>::pointer_type + > + { + _It begin; + _It end; + _It cur; + + public: + VirtualStandardIterator(const _It &_begin, const _It &_end) : begin(_begin), end(_end), cur(_begin) {} + VirtualStandardIterator(const iterator_type &o) : begin(o.begin), end(o.end), cur(o.cur) {} + + virtual reference_type operator*() const { return *cur; }; + virtual pointer_type operator->() const { return cur.operator->(); }; + + virtual iterator_type& operator++() { ++cur; return *this; }; + virtual iterator_type& operator--() { --cur; return *this; }; + + virtual bool operator==(const iterator_type& other) const { return cur == other.cur; }; + + virtual SharedPtr<iterator_type> clone() const { return SharedPtr<iterator_type>(new iterator_type(*this)); }; + + virtual bool eos() const { return *this == end; } + virtual bool sos() const { return *this == begin; }; + }; + + template <typename _It, typename _T, typename _Rt=T&, typename _Pt=T*> class VirtualMappingIterator : + public VirtualIterator<_T,_Rt,_Pt> + { + VirtualStandardIterator<_It> it; + public: + VirtualValuesIterator(const _It &_begin, const _It &_end) : + it(_begin,_end) {} + VirtualValuesIterator(const iterator_type &o) : + it( o.it ) {} + VirtualValuesIterator(const VirtualStandardIterator<_It> &o) : + it( o ) {} + + virtual iterator_type& operator++() { ++it; return *this; }; + virtual iterator_type& operator--() { --it; return *this; }; + + virtual bool operator==(const iterator_type& other) const { return it == other.it; }; + + virtual SharedPtr<iterator_type> clone() const { return SharedPtr<iterator_type>(new iterator_type(*this)); }; + + virtual bool eos() const { return it.eos(); } + virtual bool sos() const { return it.sos(); }; + }; + + template <typename _It> class VirtualValuesIterator : + public VirtualMappingIterator<_It, typename _It::value_type::second_type> + { + public: + virtual reference_type operator*() const { return it->second; }; + virtual pointer_type operator->() const { return it->second; }; + }; + + template <typename _It> class VirtualValuesIterator : + public VirtualMappingIterator<_It, typename _It::value_type::first_type> + { + public: + virtual reference_type operator*() const { return it->first; }; + virtual pointer_type operator->() const { return it->first; }; + }; + +} + + +#endif//__AUDIO_VIRTUALITERATOR_H__INCLUDED__ Added: branches/audio/vegastrike/src/audio/renderers/OpenAL/OpenALRenderer.cpp =================================================================== --- branches/audio/vegastrike/src/audio/renderers/OpenAL/OpenALRenderer.cpp (rev 0) +++ branches/audio/vegastrike/src/audio/renderers/OpenAL/OpenALRenderer.cpp 2008-08-02 21:59:18 UTC (rev 12402) @@ -0,0 +1,75 @@ +// +// C++ Implementation: Audio::Renderer +// + +#include "OpenALRenderer.h" +#include "config.h" + +#include "al.h" + +namespace Audio { + + namespace __impl { + + namespace OpenAL { + struct RendererData + { + // The many required indexes + typedef std::map<std::string, SharedPtr<Sound> > SoundMap; + + SoundMap sounds; + }; + }; + }; + + using namespace __impl::OpenAL; + + OpenALRenderer::OpenALRenderer() + throw(Exception) : + data(new RendererData) + { + } + + OpenALRenderer::~OpenALRenderer() + { + } + + SharedPtr<Sound> OpenALRenderer::getSound( + const std::string &name, + VSFileSystem::VSFileType type = VSFileSystem::UnknownFile, + bool streaming = false) + throw(Exception) + { + } + + bool owns(SharedPtr<Sound> sound) + { + return (data->sounds.find(sound->getName()) != data->sounds.end()); + } + + void attach(SharedPtr<Source> source) + throw(Exception) + { + } + + void attach(SharedPtr<Listener> listener) + throw(Exception) + { + } + + void detach(SharedPtr<Source> source) + throw() + { + } + + void detach(SharedPtr<Listener> listener) + throw() + { + } + + void setMeterDistance(Scalar distance) + throw() + { + } + +}; Added: branches/audio/vegastrike/src/audio/renderers/OpenAL/OpenALRenderer.h =================================================================== --- branches/audio/vegastrike/src/audio/renderers/OpenAL/OpenALRenderer.h (rev 0) +++ branches/audio/vegastrike/src/audio/renderers/OpenAL/OpenALRenderer.h 2008-08-02 21:59:18 UTC (rev 12402) @@ -0,0 +1,67 @@ +// +// C++ Interface: Audio::SceneManager +// +#ifndef __AUDIO_OPENAL_RENDERER_H__INCLUDED__ +#define __AUDIO_OPENAL_RENDERER_H__INCLUDED__ + +#include "../../Exceptions.h" +#include "../../Singleton.h" +#include "../../Types.h" +#include "../../Renderer.h" + +namespace Audio { + + namespace __impl { + + namespace OpenAL { + // Forward declaration of internal renderer data + struct RendererData; + }; + + }; + + /** + * OpenAL Renderer implementation + * + * @remarks Audio renderer implementation based on OpenAL. + * + */ + class Renderer + { + AutoPtr<__impl::SceneManagerData> data; + + public: + /** Initialize the renderer with default or config-driven settings. */ + OpenALRenderer() throw(Exception); + + virtual ~OpenALRenderer(); + + /** @copydoc Renderer::getSound */ + virtual SharedPtr<Sound> getSound( + const std::string &name, + VSFileSystem::VSFileType type = VSFileSystem::UnknownFile, + bool streaming = false) throw(Exception); + + /** @copydoc Renderer::owns */ + virtual bool owns(SharedPtr<Sound> sound); + + /** @copydoc Renderer::attach(SharedPtr<Source>) */ + virtual void attach(SharedPtr<Source> source) throw(Exception); + + /** @copydoc Renderer::attach(SharedPtr<Listener>) */ + virtual void attach(SharedPtr<Listener> listener) throw(Exception); + + /** @copydoc Renderer::detach(SharedPtr<Source>) */ + virtual void detach(SharedPtr<Source> source) throw(); + + /** @copydoc Renderer::detach(SharedPtr<Listener>) */ + virtual void detach(SharedPtr<Listener> listener) throw(); + + /** @copydoc Renderer::setMeterDistance */ + virtual void setMeterDistance(Scalar distance) throw(); + + }; + +}; + +#endif//__AUDIO_OPENAL_RENDERER_H__INCLUDED__ Added: branches/audio/vegastrike/src/audio/renderers/OpenAL/al.h =================================================================== --- branches/audio/vegastrike/src/audio/renderers/OpenAL/al.h (rev 0) +++ branches/audio/vegastrike/src/audio/renderers/OpenAL/al.h 2008-08-02 21:59:18 UTC (rev 12402) @@ -0,0 +1,17 @@ +#ifndef __AL_INCLUDES__INCLUDED__ +#define __AL_INCLUDES__INCLUDED__ + +#include "config.h" + +#ifdef HAVE_AL +#ifdef __APPLE__ +#include <al.h> +#else +#include <AL/al.h> +#endif + +typedef ALuint ALSourceHandle; + + +#endif//__AL_INCLUDES__INCLUDED__ + Modified: branches/audio/vegastrike/src/audio/utils.h =================================================================== --- branches/audio/vegastrike/src/audio/utils.h 2008-08-02 01:23:00 UTC (rev 12401) +++ branches/audio/vegastrike/src/audio/utils.h 2008-08-02 21:59:18 UTC (rev 12402) @@ -5,10 +5,28 @@ namespace Audio { + /** Get the game time stamp - ie, the time as it elapses in the game's universe */ Timestamp getGameTime() throw(); + + /** Get the current real time stamp */ Timestamp getRealTime() throw(); + /** Estimate a distant source's gain + * @remarks Computes source attenuation relative to a listener. + * The computation is an estimated (a rather accurate estimate though). + * Advanced factors like atmospheric absorption and environment filtering + * may make the final attenuation differ significantly, so this should only + * be used for culling purposes. + */ Scalar estimateGain(const Source &src, const Listener &listener) throw(); + + /** Make the thread sleep for at least 'ms' milliseconds. + * @remarks sleep(0) is a very common way to implement a waiting loop: + * @code while (condition) sleep(0); + * @par Interval precision is highly dependant on the platform. Usually, + * it lays close to 15ms. + */ + void sleep(unsigned int ms); } #endif//__AUDIO_UTILS_H__INCLUDED__ |