Added a small spreadsheet with performance information
Changed the 3d tutorial to use the move convenience function in order to have proper doppler effects. Added relative seek ability to cAudio source. Updated decoders to have a flag if the data they are working with is valid for their decoder (isValid). Added reference counting to IAudio, IAudioDecoder, and IDataSource Added better error checking in cAudio sources and they will do a better job of detecting if they are invalid. Fixed the spelling on cWavAudioDecoderFactory.h Ogg decoder support for the isValid check. Time seek ability added to cRawDecoder Rewrote cWavDecoder. It will now read slightly malformed wav files (and conforms to the wav spec), no longer has a bug where 8 bit mono audio samples will play twice as fast as 16 bit mono samples, proper bounds checking to make sure only the audio data is sent to the audio source, and time seeking abilities. The decoder does not support channels over 2, compressed wavs, wavs with more than 1 data or fmt block, or any other blocks that may be present in a wav file. All unsupported blocks will be ignored.
This commit is contained in:
parent
4c76942a7f
commit
2132eea8bf
|
@ -56,7 +56,7 @@ int main(int argc, char* argv[])
|
|||
cAudio::IListener* listener = manager->getListener();
|
||||
|
||||
//Create a IAudio object and load a sound from a file
|
||||
cAudio::IAudio* mysound = manager->createFromFile("bling", "../../media/bling.ogg", true);
|
||||
cAudio::IAudio* mysound = manager->createFromFile("bling", "../../media/bling.ogg", false);
|
||||
|
||||
//Set the IAudio Sound to play3d and loop
|
||||
//play3d takes 4 arguments play3d(toloop,x,y,z,strength)
|
||||
|
|
|
@ -40,7 +40,7 @@ namespace cAudio
|
|||
/** Note: May not be supported by all codecs
|
||||
\param seconds: Number of seconds from the start of the audio stream to seek to
|
||||
\return True on success, False if the codec does not support seeking. */
|
||||
virtual bool seek(const float& seconds);
|
||||
virtual bool seek(const float& seconds, bool relative = false);
|
||||
|
||||
//! Normally called every frame by the audio manager to update the internal buffers
|
||||
//! Note: For internal use only.
|
||||
|
@ -160,7 +160,7 @@ namespace cAudio
|
|||
//Empties the current working buffer queue
|
||||
void empty();
|
||||
//Checks for OpenAL errors and reports them
|
||||
void checkError();
|
||||
bool checkError();
|
||||
//Steams audio data from the decoder into a buffer
|
||||
bool stream(ALuint buffer);
|
||||
|
||||
|
@ -173,6 +173,8 @@ namespace cAudio
|
|||
|
||||
//Stores whether the source is to loop the audio stream
|
||||
bool Loop;
|
||||
//Stores whether the source is ready to be used
|
||||
bool Valid;
|
||||
};
|
||||
}
|
||||
#endif //! CAUDIO_H_INCLUDED
|
||||
|
|
|
@ -21,7 +21,7 @@ namespace cAudio
|
|||
class cAudioManager : public IAudioManager
|
||||
{
|
||||
public:
|
||||
cAudioManager() { }
|
||||
cAudioManager() : Device(NULL), Context(NULL), EFXSupported(false), Initialized(false) { }
|
||||
virtual ~cAudioManager() { }
|
||||
|
||||
//!Inits the audio manager calling the alut/etc start ups
|
||||
|
@ -75,13 +75,19 @@ namespace cAudio
|
|||
//Make a openal device pointer
|
||||
ALCdevice* Device;
|
||||
|
||||
//Holds whether EFX is supported
|
||||
bool EFXSupported;
|
||||
|
||||
//Whether the manager is currently initialized and ready to go.
|
||||
bool Initialized;
|
||||
|
||||
//! Holds an index for fast searching of audio sources by name
|
||||
std::map<std::string, IAudio*> audioIndex;
|
||||
//! Holds all managed audio sources
|
||||
std::vector<IAudio*> audioSources;
|
||||
//!Decoder map that holds all decoders by file extension
|
||||
//! Decoder map that holds all decoders by file extension
|
||||
std::map<std::string, IAudioDecoderFactory*> decodermap;
|
||||
//!The listener object
|
||||
//! The listener object
|
||||
cListener initlistener;
|
||||
//! Check for OpenAL errors
|
||||
void checkError();
|
||||
|
|
|
@ -47,6 +47,23 @@ namespace cAudio
|
|||
bool Initialized;
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef CAUDIO_MAKE_THREAD_SAFE
|
||||
class cAudioMutexBasicLock
|
||||
{
|
||||
public:
|
||||
cAudioMutexBasicLock(cAudioMutex& mutex) : Mutex(&mutex)
|
||||
{
|
||||
Mutex->lock();
|
||||
}
|
||||
~cAudioMutexBasicLock()
|
||||
{
|
||||
Mutex->unlock();
|
||||
}
|
||||
protected:
|
||||
cAudioMutex* Mutex;
|
||||
};
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif //! CAUDIOMUTEX_H
|
|
@ -26,6 +26,9 @@ namespace cAudio
|
|||
//!Returns whether seeking is supported
|
||||
virtual bool isSeekingSupported();
|
||||
|
||||
//!Returns whether the stream is valid for this codec
|
||||
virtual bool isValid();
|
||||
|
||||
//!Reads a section of data out of the audio stream
|
||||
virtual int readAudioData(void* output, int amount);
|
||||
|
||||
|
@ -44,7 +47,7 @@ namespace cAudio
|
|||
vorbis_comment* vorbisComment;
|
||||
//!Stream handle
|
||||
OggVorbis_File oggStream;
|
||||
bool seekable;
|
||||
bool Valid;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -22,6 +22,9 @@ namespace cAudio
|
|||
//!Returns whether seeking is supported
|
||||
virtual bool isSeekingSupported();
|
||||
|
||||
//!Returns whether the stream is valid for this codec
|
||||
virtual bool isValid();
|
||||
|
||||
//!Reads a section of data out of the audio stream
|
||||
virtual int readAudioData(void* output, int amount);
|
||||
|
||||
|
|
|
@ -22,6 +22,9 @@ namespace cAudio
|
|||
//!Returns whether seeking is supported
|
||||
virtual bool isSeekingSupported();
|
||||
|
||||
//!Returns whether the stream is valid for this codec
|
||||
virtual bool isValid();
|
||||
|
||||
//!Reads a section of data out of the audio stream
|
||||
virtual int readAudioData(void* output, int amount);
|
||||
|
||||
|
@ -32,15 +35,15 @@ namespace cAudio
|
|||
virtual bool seek(float seconds,bool relative);
|
||||
|
||||
private:
|
||||
int mChunkSize;
|
||||
int mSubChunk1Size;
|
||||
short mFormat;
|
||||
short mChannels;
|
||||
int mSampleRate;
|
||||
int mByteRate;
|
||||
short mBlockAlign;
|
||||
short mBitsPerSample;
|
||||
int mDataSize;
|
||||
short Channels;
|
||||
int SampleRate;
|
||||
int ByteRate;
|
||||
short BlockAlign;
|
||||
short BitsPerSample;
|
||||
int DataSize;
|
||||
int DataOffset;
|
||||
|
||||
bool Valid;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -3,23 +3,27 @@
|
|||
|
||||
namespace cAudio
|
||||
{
|
||||
cAudio::cAudio(IAudioDecoder* decoder) : Decoder(decoder)
|
||||
cAudio::cAudio(IAudioDecoder* decoder) : Decoder(decoder), Loop(false), Valid(false)
|
||||
{
|
||||
Mutex.lock();
|
||||
Loop = false;
|
||||
|
||||
if(Decoder)
|
||||
Decoder->grab();
|
||||
|
||||
//Generates 3 buffers for the ogg file
|
||||
alGenBuffers(NUM_BUFFERS, Buffers);
|
||||
//Creates one source to be stored.
|
||||
alGenSources(1, &Source);
|
||||
checkError();
|
||||
bool state = !checkError();
|
||||
Valid = state && (Decoder != NULL);
|
||||
Mutex.unlock();
|
||||
}
|
||||
|
||||
cAudio::~cAudio()
|
||||
{
|
||||
Mutex.lock();
|
||||
delete Decoder;
|
||||
if(Decoder)
|
||||
Decoder->drop();
|
||||
Mutex.unlock();
|
||||
}
|
||||
|
||||
|
@ -100,13 +104,13 @@ namespace cAudio
|
|||
Mutex.unlock();
|
||||
}
|
||||
|
||||
bool cAudio::seek(const float& seconds)
|
||||
bool cAudio::seek(const float& seconds, bool relative)
|
||||
{
|
||||
bool state = false;
|
||||
Mutex.lock();
|
||||
if(Decoder->isSeekingSupported())
|
||||
{
|
||||
state = Decoder->seek(seconds, false);
|
||||
state = Decoder->seek(seconds, relative);
|
||||
}
|
||||
Mutex.unlock();
|
||||
return state;
|
||||
|
@ -158,8 +162,7 @@ namespace cAudio
|
|||
|
||||
const bool cAudio::isValid() const
|
||||
{
|
||||
bool state = (Decoder != 0);
|
||||
return state;
|
||||
return Valid;
|
||||
}
|
||||
|
||||
const bool cAudio::isPlaying() const
|
||||
|
@ -462,7 +465,7 @@ namespace cAudio
|
|||
}
|
||||
}
|
||||
|
||||
void cAudio::checkError()
|
||||
bool cAudio::checkError()
|
||||
{
|
||||
int error = alGetError();
|
||||
const char* errorString;
|
||||
|
@ -474,7 +477,9 @@ namespace cAudio
|
|||
getLogger()->logCritical("Audio Source", "OpenAL Error: %s.", errorString);
|
||||
else
|
||||
getLogger()->logError("Audio Source", "OpenAL Error: %s.", errorString);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cAudio::stream(ALuint buffer)
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
#include "../Headers/cMemorySource.h"
|
||||
#include "../Headers/cUtils.h"
|
||||
#include "../Headers/cOggAudioDecoderFactory.h"
|
||||
#include "../Headers/cWavAudioDecoderFacotry.h"
|
||||
#include "../Headers/cWavAudioDecoderFactory.h"
|
||||
#include "../Headers/cRawAudioDecoderFactory.h"
|
||||
#include "../Headers/cThread.h"
|
||||
#include "../include/cAudioSleep.h"
|
||||
|
@ -56,7 +56,10 @@ namespace cAudio
|
|||
//!Initialize the listener,openal,and mikmod
|
||||
bool cAudioManager::initialize(const char* deviceName, int outputFrequency, int eaxEffectSlots)
|
||||
{
|
||||
Mutex.lock();
|
||||
cAudioMutexBasicLock lock(Mutex);
|
||||
|
||||
if(Initialized)
|
||||
shutDown();
|
||||
|
||||
//Stores the context attributes (MAX of 4, with 2 zeros to terminate)
|
||||
ALint attribs[6] = { 0 };
|
||||
|
@ -80,17 +83,11 @@ namespace cAudio
|
|||
{
|
||||
getLogger()->logError("AudioManager", "Failed to Create OpenAL Device.");
|
||||
checkError();
|
||||
Mutex.unlock();
|
||||
return false;
|
||||
}
|
||||
|
||||
//Create context with eax effects for windows
|
||||
#ifdef CAUDIO_EAX_ENABLED
|
||||
if(alcIsExtensionPresent(Device, "ALC_EXT_EFX") == AL_FALSE)
|
||||
{
|
||||
getLogger()->logWarning("AudioManager", "EFX not supported.");
|
||||
}
|
||||
getLogger()->logInfo("AudioManager", "EFX supported and enabled.");
|
||||
EFXSupported = (alcIsExtensionPresent(Device, "ALC_EXT_EFX") == AL_TRUE);
|
||||
#endif
|
||||
|
||||
Context = alcCreateContext(Device, attribs);
|
||||
|
@ -98,7 +95,8 @@ namespace cAudio
|
|||
{
|
||||
getLogger()->logError("AudioManager", "Failed to Create OpenAL Context.");
|
||||
checkError();
|
||||
Mutex.unlock();
|
||||
alcCloseDevice(Device);
|
||||
Device = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -106,13 +104,31 @@ namespace cAudio
|
|||
{
|
||||
getLogger()->logError("AudioManager", "Failed to make OpenAL Context current.");
|
||||
checkError();
|
||||
Mutex.unlock();
|
||||
alcDestroyContext(Context);
|
||||
alcCloseDevice(Device);
|
||||
Context = NULL;
|
||||
Device = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
getLogger()->logInfo("AudioManager", "OpenAL Version: %s", alGetString(AL_VERSION));
|
||||
getLogger()->logInfo("AudioManager", "Vendor: %s", alGetString(AL_VENDOR));
|
||||
getLogger()->logInfo("AudioManager", "Renderer: %s", alGetString(AL_RENDERER));
|
||||
#ifdef CAUDIO_EAX_ENABLED
|
||||
if(EFXSupported)
|
||||
{
|
||||
int EFXMajorVersion = 0;
|
||||
int EFXMinorVersion = 0;
|
||||
alcGetIntegerv(Device, ALC_EFX_MAJOR_VERSION, 1, &EFXMajorVersion);
|
||||
alcGetIntegerv(Device, ALC_EFX_MINOR_VERSION, 1, &EFXMinorVersion);
|
||||
getLogger()->logInfo("AudioManager", "EFX Version: %i.%i", EFXMajorVersion, EFXMinorVersion);
|
||||
getLogger()->logInfo("AudioManager", "EFX supported and enabled.");
|
||||
}
|
||||
else
|
||||
{
|
||||
getLogger()->logWarning("AudioManager", "EFX is not supported, EFX disabled.");
|
||||
}
|
||||
#endif
|
||||
getLogger()->logInfo("AudioManager", "Supported Extensions: %s", alGetString(AL_EXTENSIONS));
|
||||
|
||||
#ifdef CAUDIO_COMPILE_WITH_OGG_DECODER
|
||||
|
@ -125,154 +141,240 @@ namespace cAudio
|
|||
registerAudioDecoder(&RawDecoderFactory, "raw");
|
||||
#endif
|
||||
|
||||
Mutex.unlock();
|
||||
Initialized = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
//!create a sound source
|
||||
IAudio* cAudioManager::createFromFile(const char* name, const char* pathToFile, bool stream)
|
||||
{
|
||||
Mutex.lock();
|
||||
cAudioMutexBasicLock lock(Mutex);
|
||||
|
||||
std::string audioName = safeCStr(name);
|
||||
std::string path = safeCStr(pathToFile);
|
||||
|
||||
if(stream)
|
||||
std::string ext = getExt(path);
|
||||
IAudioDecoderFactory* factory = getAudioDecoderFactory(ext.c_str());
|
||||
if(factory)
|
||||
{
|
||||
cFileSource* source = new cFileSource(path);
|
||||
if(source->isValid())
|
||||
{
|
||||
std::string ext = getExt(path);
|
||||
IAudioDecoderFactory* factory = getAudioDecoderFactory(ext.c_str());
|
||||
if(!factory)
|
||||
if(stream)
|
||||
{
|
||||
cFileSource* source = new cFileSource(path);
|
||||
if(source)
|
||||
{
|
||||
delete source;
|
||||
Mutex.unlock();
|
||||
return NULL;
|
||||
}
|
||||
IAudioDecoder* decoder = factory->CreateAudioDecoder(source);
|
||||
IAudio* audio = new cAudio(decoder);
|
||||
if(source->isValid())
|
||||
{
|
||||
IAudioDecoder* decoder = factory->CreateAudioDecoder(source);
|
||||
source->drop();
|
||||
if(decoder)
|
||||
{
|
||||
if(decoder->isValid())
|
||||
{
|
||||
IAudio* audio = new cAudio(decoder);
|
||||
decoder->drop();
|
||||
|
||||
if(!audioName.empty())
|
||||
audioIndex[audioName] = audio;
|
||||
if(audio)
|
||||
{
|
||||
if(audio->isValid())
|
||||
{
|
||||
if(!audioName.empty())
|
||||
audioIndex[audioName] = audio;
|
||||
|
||||
audioSources.push_back(audio);
|
||||
audioSources.push_back(audio);
|
||||
|
||||
getLogger()->logInfo("AudioManager", "Streaming Audio Source (%s) created from file %s.", audioName.c_str(), path.c_str());
|
||||
Mutex.unlock();
|
||||
return audio;
|
||||
}
|
||||
else
|
||||
{
|
||||
delete source;
|
||||
getLogger()->logError("AudioManager", "Failed to create Audio Source (%s) from file %s.", audioName.c_str(), path.c_str());
|
||||
Mutex.unlock();
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
cFileSource* tempsource = new cFileSource(path);
|
||||
int length = tempsource->getSize();
|
||||
char *tempbuf = new char[length];
|
||||
tempsource->read(tempbuf,length);
|
||||
getLogger()->logInfo("AudioManager", "Streaming Audio Source (%s) created from file %s.", audioName.c_str(), path.c_str());
|
||||
|
||||
return audio;
|
||||
}
|
||||
getLogger()->logError("AudioManager", "Failed to create Audio Source (%s): Error creating audio source.", audioName.c_str());
|
||||
audio->drop();
|
||||
return NULL;
|
||||
}
|
||||
getLogger()->logError("AudioManager", "Failed to create Audio Source (%s): Could not allocate enough memory.", audioName.c_str());
|
||||
return NULL;
|
||||
}
|
||||
getLogger()->logError("AudioManager", "Failed to create Audio Source (%s): Audio data could not be decoded by (.%s) decoder.", audioName.c_str(), ext.c_str());
|
||||
decoder->drop();
|
||||
return NULL;
|
||||
}
|
||||
getLogger()->logError("AudioManager", "Failed to create Audio Source (%s): Could not allocate enough memory.", audioName.c_str());
|
||||
return NULL;
|
||||
}
|
||||
source->drop();
|
||||
getLogger()->logError("AudioManager", "Failed to create Audio Source (%s): Could not load file %s.", audioName.c_str(), path.c_str());
|
||||
return NULL;
|
||||
}
|
||||
getLogger()->logError("AudioManager", "Failed to create Audio Source (%s): Could not allocate enough memory.", audioName.c_str());
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
cFileSource* tempsource = new cFileSource(path);
|
||||
if(tempsource)
|
||||
{
|
||||
if(tempsource->isValid())
|
||||
{
|
||||
int length = tempsource->getSize();
|
||||
char *tempbuf = new char[length];
|
||||
if(tempbuf)
|
||||
{
|
||||
tempsource->read(tempbuf,length);
|
||||
|
||||
IAudio* guy = createFromMemory(name, tempbuf, length, getExt(path).c_str());
|
||||
delete[]tempbuf;
|
||||
delete tempsource;
|
||||
Mutex.unlock();
|
||||
return guy;
|
||||
}
|
||||
IAudio* guy = createFromMemory(name, tempbuf, length, getExt(path).c_str());
|
||||
delete[]tempbuf;
|
||||
tempsource->drop();
|
||||
return guy;
|
||||
}
|
||||
getLogger()->logError("AudioManager", "Failed to create Audio Source (%s): Could not allocate enough memory.", audioName.c_str());
|
||||
tempsource->drop();
|
||||
return NULL;
|
||||
}
|
||||
getLogger()->logError("AudioManager", "Failed to create Audio Source (%s): Audio data is corrupt.", audioName.c_str());
|
||||
tempsource->drop();
|
||||
return NULL;
|
||||
}
|
||||
getLogger()->logError("AudioManager", "Failed to create Audio Source (%s): Could not allocate enough memory.", audioName.c_str());
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
getLogger()->logError("AudioManager", "Failed to create Audio Source (%s): Codec (.%s) is not supported.", audioName.c_str(), ext.c_str());
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//!Loads the ogg file from memory *virtual file systems*
|
||||
IAudio* cAudioManager::createFromMemory(const char* name, const char* data, size_t length, const char* extension)
|
||||
{
|
||||
Mutex.lock();
|
||||
cAudioMutexBasicLock lock(Mutex);
|
||||
|
||||
std::string audioName = safeCStr(name);
|
||||
std::string ext = safeCStr(extension);
|
||||
IAudioDecoderFactory* factory = getAudioDecoderFactory(ext.c_str());
|
||||
if(factory)
|
||||
{
|
||||
cMemorySource* source = new cMemorySource(data, length, true);
|
||||
if(source)
|
||||
{
|
||||
if(source->isValid())
|
||||
{
|
||||
IAudioDecoder* decoder = factory->CreateAudioDecoder(source);
|
||||
source->drop();
|
||||
if(decoder)
|
||||
{
|
||||
if(decoder->isValid())
|
||||
{
|
||||
IAudio* audio = new cAudio(decoder);
|
||||
decoder->drop();
|
||||
|
||||
cMemorySource* source = new cMemorySource(data, length, true);
|
||||
if(source->isValid())
|
||||
{
|
||||
IAudioDecoderFactory* factory = getAudioDecoderFactory(ext.c_str());
|
||||
if(!factory)
|
||||
{
|
||||
delete source;
|
||||
Mutex.unlock();
|
||||
return NULL;
|
||||
}
|
||||
IAudioDecoder* decoder = factory->CreateAudioDecoder(source);
|
||||
IAudio* audio = new cAudio(decoder);
|
||||
|
||||
if(!audioName.empty())
|
||||
audioIndex[audioName] = audio;
|
||||
if(audio)
|
||||
{
|
||||
if(audio->isValid())
|
||||
{
|
||||
if(!audioName.empty())
|
||||
audioIndex[audioName] = audio;
|
||||
|
||||
audioSources.push_back(audio);
|
||||
audioSources.push_back(audio);
|
||||
|
||||
getLogger()->logInfo("AudioManager", "Audio Source (%s) created from memory buffer.", audioName.c_str());
|
||||
Mutex.unlock();
|
||||
return audio;
|
||||
}
|
||||
else
|
||||
{
|
||||
delete source;
|
||||
getLogger()->logError("AudioManager", "Failed to create Audio Source (%s) from memory buffer.", audioName.c_str());
|
||||
Mutex.unlock();
|
||||
return NULL;
|
||||
}
|
||||
getLogger()->logInfo("AudioManager", "Audio Source (%s) successfully created from memory.", audioName.c_str());
|
||||
|
||||
return audio;
|
||||
}
|
||||
audio->drop();
|
||||
getLogger()->logError("AudioManager", "Failed to create Audio Source (%s): Error creating audio source.", audioName.c_str());
|
||||
return NULL;
|
||||
}
|
||||
getLogger()->logError("AudioManager", "Failed to create Audio Source (%s): Could not allocate enough memory.", audioName.c_str());
|
||||
return NULL;
|
||||
}
|
||||
decoder->drop();
|
||||
getLogger()->logError("AudioManager", "Failed to create Audio Source (%s): Audio data could not be decoded by (.%s) decoder.", audioName.c_str(), ext.c_str());
|
||||
return NULL;
|
||||
}
|
||||
getLogger()->logError("AudioManager", "Failed to create Audio Source (%s): Could not allocate enough memory for decoder.", audioName.c_str());
|
||||
return NULL;
|
||||
}
|
||||
source->drop();
|
||||
getLogger()->logError("AudioManager", "Failed to create Audio Source (%s): Audio data is corrupt.", audioName.c_str());
|
||||
return NULL;
|
||||
}
|
||||
getLogger()->logError("AudioManager", "Failed to create Audio Source (%s): Could not allocate enough memory.", audioName.c_str());
|
||||
return NULL;
|
||||
}
|
||||
getLogger()->logError("AudioManager", "Failed to create Audio Source (%s): Codec (.%s) is not supported.", audioName.c_str(), ext.c_str());
|
||||
return NULL;
|
||||
}
|
||||
|
||||
IAudio* cAudioManager::createFromRaw(const char* name, const char* data, size_t length, unsigned int frequency, AudioFormats format)
|
||||
{
|
||||
Mutex.lock();
|
||||
cAudioMutexBasicLock lock(Mutex);
|
||||
|
||||
std::string audioName = safeCStr(name);
|
||||
IAudioDecoderFactory* factory = getAudioDecoderFactory("raw");
|
||||
if(factory)
|
||||
{
|
||||
cMemorySource* source = new cMemorySource(data, length, true);
|
||||
if(source)
|
||||
{
|
||||
if(source->isValid())
|
||||
{
|
||||
IAudioDecoder* decoder = ((cRawAudioDecoderFactory*)factory)->CreateAudioDecoder(source, frequency, format);
|
||||
source->drop();
|
||||
if(decoder)
|
||||
{
|
||||
if(decoder->isValid())
|
||||
{
|
||||
IAudio* audio = new cAudio(decoder);
|
||||
decoder->drop();
|
||||
|
||||
cMemorySource* source = new cMemorySource(data, length, true);
|
||||
if(source->isValid())
|
||||
{
|
||||
IAudioDecoderFactory* factory = getAudioDecoderFactory("raw");
|
||||
if(!factory)
|
||||
{
|
||||
delete source;
|
||||
Mutex.unlock();
|
||||
return NULL;
|
||||
}
|
||||
IAudioDecoder* decoder = ((cRawAudioDecoderFactory*)factory)->CreateAudioDecoder(source, frequency, format);
|
||||
IAudio* audio = new cAudio(decoder);
|
||||
|
||||
if(!audioName.empty())
|
||||
audioIndex[audioName] = audio;
|
||||
if(audio)
|
||||
{
|
||||
if(audio->isValid())
|
||||
{
|
||||
if(!audioName.empty())
|
||||
audioIndex[audioName] = audio;
|
||||
|
||||
audioSources.push_back(audio);
|
||||
audioSources.push_back(audio);
|
||||
|
||||
getLogger()->logInfo("AudioManager", "Raw Audio Source (%s) created from memory buffer.", audioName.c_str());
|
||||
Mutex.unlock();
|
||||
return audio;
|
||||
}
|
||||
else
|
||||
{
|
||||
delete source;
|
||||
getLogger()->logError("AudioManager", "Failed to create Raw Audio Source (%s) from memory buffer.", audioName.c_str());
|
||||
Mutex.unlock();
|
||||
return NULL;
|
||||
}
|
||||
getLogger()->logInfo("AudioManager", "Audio Source (%s) successfully created from raw data.", audioName.c_str());
|
||||
|
||||
return audio;
|
||||
}
|
||||
audio->drop();
|
||||
getLogger()->logError("AudioManager", "Failed to create Audio Source (%s): Error creating audio source.", audioName.c_str());
|
||||
return NULL;
|
||||
}
|
||||
getLogger()->logError("AudioManager", "Failed to create Audio Source (%s): Could not allocate enough memory.", audioName.c_str());
|
||||
return NULL;
|
||||
}
|
||||
decoder->drop();
|
||||
getLogger()->logError("AudioManager", "Failed to create Audio Source (%s): Audio data could not be decoded by (.%s) decoder.", audioName.c_str(), "raw");
|
||||
return NULL;
|
||||
}
|
||||
getLogger()->logError("AudioManager", "Failed to create Audio Source (%s): Could not allocate enough memory for decoder.", audioName.c_str());
|
||||
return NULL;
|
||||
}
|
||||
source->drop();
|
||||
getLogger()->logError("AudioManager", "Failed to create Audio Source (%s): Audio data is corrupt.", audioName.c_str());
|
||||
return NULL;
|
||||
}
|
||||
getLogger()->logError("AudioManager", "Failed to create Audio Source (%s): Could not allocate enough memory.", audioName.c_str());
|
||||
return NULL;
|
||||
}
|
||||
getLogger()->logError("AudioManager", "Failed to create Audio Source (%s): Codec (.%s) is not supported.", audioName.c_str(), "raw");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool cAudioManager::registerAudioDecoder(IAudioDecoderFactory* factory, const char* extension)
|
||||
{
|
||||
Mutex.lock();
|
||||
cAudioMutexBasicLock lock(Mutex);
|
||||
std::string ext = safeCStr(extension);
|
||||
decodermap[ext] = factory;
|
||||
getLogger()->logInfo("AudioManager", "Audio Decoder for extension .%s registered.", ext.c_str());
|
||||
Mutex.unlock();
|
||||
return true;
|
||||
}
|
||||
|
||||
void cAudioManager::unRegisterAudioDecoder(const char* extension)
|
||||
{
|
||||
Mutex.lock();
|
||||
cAudioMutexBasicLock lock(Mutex);
|
||||
std::string ext = safeCStr(extension);
|
||||
std::map<std::string, IAudioDecoderFactory*>::iterator it = decodermap.find(ext);
|
||||
if(it != decodermap.end())
|
||||
|
@ -280,68 +382,59 @@ namespace cAudio
|
|||
decodermap.erase(it);
|
||||
getLogger()->logInfo("AudioManager", "Audio Decoder for extension .%s unregistered.", ext.c_str());
|
||||
}
|
||||
Mutex.unlock();
|
||||
}
|
||||
|
||||
bool cAudioManager::isAudioDecoderRegistered(const char* extension)
|
||||
{
|
||||
Mutex.lock();
|
||||
cAudioMutexBasicLock lock(Mutex);
|
||||
std::string ext = safeCStr(extension);
|
||||
std::map<std::string, IAudioDecoderFactory*>::iterator it = decodermap.find(ext);
|
||||
bool result = (it != decodermap.end());
|
||||
Mutex.unlock();
|
||||
return result;
|
||||
return (it != decodermap.end());
|
||||
}
|
||||
|
||||
IAudioDecoderFactory* cAudioManager::getAudioDecoderFactory(const char* extension)
|
||||
{
|
||||
Mutex.lock();
|
||||
cAudioMutexBasicLock lock(Mutex);
|
||||
std::string ext = safeCStr(extension);
|
||||
std::map<std::string, IAudioDecoderFactory*>::iterator it = decodermap.find(ext);
|
||||
if(it != decodermap.end())
|
||||
{
|
||||
Mutex.unlock();
|
||||
return it->second;
|
||||
}
|
||||
Mutex.unlock();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//!grabs the selected audio file via the identifier
|
||||
IAudio* cAudioManager::getSoundByName(const char* name)
|
||||
{
|
||||
Mutex.lock();
|
||||
cAudioMutexBasicLock lock(Mutex);
|
||||
std::string audioName = safeCStr(name);
|
||||
std::map<std::string,IAudio*>::iterator i = audioIndex.find(audioName);
|
||||
if (i == audioIndex.end())
|
||||
{
|
||||
Mutex.unlock();
|
||||
return NULL;
|
||||
}
|
||||
Mutex.unlock();
|
||||
return i->second;
|
||||
}
|
||||
|
||||
//!Releases the selected audio source
|
||||
void cAudioManager::release()
|
||||
{
|
||||
Mutex.lock();
|
||||
cAudioMutexBasicLock lock(Mutex);
|
||||
for(unsigned int i=0; i<audioSources.size(); ++i)
|
||||
{
|
||||
IAudio* source = audioSources[i];
|
||||
if(source)
|
||||
delete source;
|
||||
source->drop();
|
||||
}
|
||||
audioSources.clear();
|
||||
audioIndex.clear();
|
||||
decodermap.clear();
|
||||
Mutex.unlock();
|
||||
}
|
||||
|
||||
//!Updates all audiosources created
|
||||
void cAudioManager::update()
|
||||
{
|
||||
Mutex.lock();
|
||||
cAudioMutexBasicLock lock(Mutex);
|
||||
for(unsigned int i=0; i<audioSources.size(); ++i)
|
||||
{
|
||||
IAudio* source = audioSources[i];
|
||||
|
@ -353,21 +446,27 @@ namespace cAudio
|
|||
}
|
||||
}
|
||||
}
|
||||
Mutex.unlock();
|
||||
}
|
||||
|
||||
//!Shuts down cAudio. Deletes all audio sources in process
|
||||
void cAudioManager::shutDown()
|
||||
{
|
||||
Mutex.lock();
|
||||
//Reset context to null
|
||||
alcMakeContextCurrent(NULL);
|
||||
//Delete the context
|
||||
alcDestroyContext(Context);
|
||||
//Close the device
|
||||
alcCloseDevice(Device);
|
||||
getLogger()->logInfo("AudioManager", "Manager successfully shutdown.");
|
||||
Mutex.unlock();
|
||||
if(Initialized)
|
||||
{
|
||||
cAudioMutexBasicLock lock(Mutex);
|
||||
release();
|
||||
decodermap.clear();
|
||||
//Reset context to null
|
||||
alcMakeContextCurrent(NULL);
|
||||
//Delete the context
|
||||
alcDestroyContext(Context);
|
||||
Context = NULL;
|
||||
//Close the device
|
||||
alcCloseDevice(Device);
|
||||
Device = NULL;
|
||||
Initialized = false;
|
||||
getLogger()->logInfo("AudioManager", "Manager successfully shutdown.");
|
||||
}
|
||||
}
|
||||
|
||||
void cAudioManager::checkError()
|
||||
|
@ -395,7 +494,7 @@ namespace cAudio
|
|||
void cAudioManager::getAvailableDevices()
|
||||
{
|
||||
// Get list of available Playback Devices
|
||||
Mutex.lock();
|
||||
cAudioMutexBasicLock lock(Mutex);
|
||||
if( alcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT") == AL_TRUE )
|
||||
{
|
||||
const char* deviceList = alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER);
|
||||
|
@ -428,38 +527,31 @@ namespace cAudio
|
|||
// Get the name of the 'default' capture device
|
||||
DefaultDevice = alcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER);
|
||||
}
|
||||
Mutex.unlock();
|
||||
}
|
||||
|
||||
const char* cAudioManager::getAvailableDeviceName(unsigned int index)
|
||||
{
|
||||
Mutex.lock();
|
||||
cAudioMutexBasicLock lock(Mutex);
|
||||
if(!AvailableDevices.empty())
|
||||
{
|
||||
//Bounds check
|
||||
if( index > (AvailableDevices.size()-1) ) index = (AvailableDevices.size()-1);
|
||||
const char* deviceName = AvailableDevices[index].c_str();
|
||||
Mutex.unlock();
|
||||
return deviceName;
|
||||
}
|
||||
Mutex.unlock();
|
||||
return "";
|
||||
}
|
||||
|
||||
unsigned int cAudioManager::getAvailableDeviceCount()
|
||||
{
|
||||
Mutex.lock();
|
||||
unsigned int size = AvailableDevices.size();
|
||||
Mutex.unlock();
|
||||
return size;
|
||||
cAudioMutexBasicLock lock(Mutex);
|
||||
return AvailableDevices.size();
|
||||
}
|
||||
|
||||
const char* cAudioManager::getDefaultDeviceName()
|
||||
{
|
||||
Mutex.lock();
|
||||
const char* deviceName = DefaultDevice.empty() ? "" : DefaultDevice.c_str();
|
||||
Mutex.unlock();
|
||||
return deviceName;
|
||||
cAudioMutexBasicLock lock(Mutex);
|
||||
return DefaultDevice.empty() ? "" : DefaultDevice.c_str();
|
||||
}
|
||||
|
||||
CAUDIO_API IAudioManager* createAudioManager(bool initializeDefault)
|
||||
|
@ -498,6 +590,7 @@ namespace cAudio
|
|||
RunAudioManagerThread = false;
|
||||
AudioManagerObjectsMutex.unlock();
|
||||
#endif
|
||||
manager->shutDown();
|
||||
delete manager;
|
||||
manager = NULL;
|
||||
}
|
||||
|
|
|
@ -41,10 +41,13 @@ namespace cAudio
|
|||
vorbisCallbacks.close_func = NULL;
|
||||
vorbisCallbacks.seek_func = VorbisSeek;
|
||||
vorbisCallbacks.tell_func = VorbisTell;
|
||||
ov_open_callbacks(Stream,&oggStream,NULL,0,vorbisCallbacks);
|
||||
Valid = (ov_open_callbacks(Stream,&oggStream,NULL,0,vorbisCallbacks) == 0);
|
||||
|
||||
vorbisInfo = ov_info(&oggStream, -1);
|
||||
vorbisComment = ov_comment(&oggStream,-1);
|
||||
if(Valid)
|
||||
{
|
||||
vorbisInfo = ov_info(&oggStream, -1);
|
||||
vorbisComment = ov_comment(&oggStream,-1);
|
||||
}
|
||||
}
|
||||
|
||||
cOggDecoder::~cOggDecoder()
|
||||
|
@ -54,61 +57,86 @@ namespace cAudio
|
|||
//!Returns given vorbis channel format
|
||||
AudioFormats cOggDecoder::getFormat()
|
||||
{
|
||||
if(vorbisInfo->channels == 1)
|
||||
{
|
||||
return EAF_16BIT_MONO;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
return EAF_16BIT_STEREO;
|
||||
}
|
||||
if(Valid)
|
||||
{
|
||||
if(vorbisInfo->channels == 1)
|
||||
{
|
||||
return EAF_16BIT_MONO;
|
||||
}
|
||||
else
|
||||
{
|
||||
return EAF_16BIT_STEREO;
|
||||
}
|
||||
}
|
||||
return EAF_8BIT_MONO;
|
||||
}
|
||||
//!Returns vorbis file frequency
|
||||
int cOggDecoder::getFrequency()
|
||||
{
|
||||
return vorbisInfo->rate;
|
||||
if(Valid)
|
||||
{
|
||||
return vorbisInfo->rate;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//!Returns if vorbis file is seekable
|
||||
bool cOggDecoder::isSeekingSupported()
|
||||
{
|
||||
return (ov_seekable(&oggStream)!=0);
|
||||
if(Valid)
|
||||
{
|
||||
return (ov_seekable(&oggStream)!=0);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cOggDecoder::isValid()
|
||||
{
|
||||
return Valid;
|
||||
}
|
||||
|
||||
//!Reads the vorbis data
|
||||
int cOggDecoder::readAudioData(void* output, int amount)
|
||||
{
|
||||
int temp = 0;
|
||||
int result = ov_read(&oggStream,(char*)output,amount,0,2,1,&temp);
|
||||
//return (result < 0) ? 0 : result;
|
||||
return result;
|
||||
if(Valid)
|
||||
{
|
||||
int temp = 0;
|
||||
int result = ov_read(&oggStream,(char*)output,amount,0,2,1,&temp);
|
||||
//return (result < 0) ? 0 : result;
|
||||
return result;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//!Sets the postion for vorbis data reader
|
||||
bool cOggDecoder::setPosition(int position, bool relative)
|
||||
{
|
||||
if(ov_seekable(&oggStream))
|
||||
{
|
||||
return (ov_raw_seek(&oggStream,position)==0);
|
||||
}
|
||||
else
|
||||
return false;
|
||||
if(Valid)
|
||||
{
|
||||
if(ov_seekable(&oggStream))
|
||||
{
|
||||
return (ov_raw_seek(&oggStream,position)==0);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//!Seeks the vorbis data
|
||||
bool cOggDecoder::seek(float seconds, bool relative)
|
||||
{
|
||||
if(ov_seekable(&oggStream))
|
||||
{
|
||||
if(relative)
|
||||
if(Valid)
|
||||
{
|
||||
if(ov_seekable(&oggStream))
|
||||
{
|
||||
float curtime = ov_time_tell(&oggStream);
|
||||
return (ov_time_seek(&oggStream,curtime+seconds)==0);
|
||||
if(relative)
|
||||
{
|
||||
float curtime = ov_time_tell(&oggStream);
|
||||
return (ov_time_seek(&oggStream,curtime+seconds)==0);
|
||||
}
|
||||
else
|
||||
return (ov_time_seek(&oggStream,seconds)==0);
|
||||
}
|
||||
else
|
||||
return (ov_time_seek(&oggStream,seconds)==0);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,9 +27,14 @@ namespace cAudio{
|
|||
//!Returns if seeking is supported
|
||||
bool cRawDecoder::isSeekingSupported()
|
||||
{
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cRawDecoder::isValid()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
//!Reads wav data
|
||||
int cRawDecoder::readAudioData(void* output, int amount)
|
||||
{
|
||||
|
@ -46,8 +51,17 @@ namespace cAudio{
|
|||
//!Seeks wav data
|
||||
bool cRawDecoder::seek(float seconds,bool relative)
|
||||
{
|
||||
return false;
|
||||
int SampleSize = 1;
|
||||
if(Format == EAF_8BIT_MONO)
|
||||
SampleSize = 1;
|
||||
else if(Format == EAF_8BIT_STEREO)
|
||||
SampleSize = 2;
|
||||
else if(Format == EAF_16BIT_MONO)
|
||||
SampleSize = 2;
|
||||
else
|
||||
SampleSize = 4;
|
||||
|
||||
int amountToSeek = seconds * (float)Frequency * (float)SampleSize;
|
||||
return setPosition(amountToSeek, relative);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -1 +1 @@
|
|||
#include "../Headers/cWavAudioDecoderFacotry.h"
|
||||
#include "../Headers/cWavAudioDecoderFactory.h"
|
||||
|
|
|
@ -1,75 +1,189 @@
|
|||
#include "../Headers/cWavDecoder.h"
|
||||
#include <string.h>
|
||||
|
||||
namespace cAudio{
|
||||
|
||||
cWavDecoder::cWavDecoder(IDataSource* stream) : IAudioDecoder(stream)
|
||||
namespace cAudio
|
||||
{
|
||||
cWavDecoder::cWavDecoder(IDataSource* stream) : IAudioDecoder(stream), Valid(false)
|
||||
{
|
||||
Stream->seek(4,false);
|
||||
Stream->read(&mChunkSize,4);
|
||||
Stream->seek(16,false);
|
||||
Stream->read(&mSubChunk1Size,4);
|
||||
Stream->read(&mFormat,sizeof(short));
|
||||
Stream->read(&mChannels,sizeof(short));
|
||||
Stream->read(&mSampleRate,sizeof(int));
|
||||
Stream->read(&mByteRate,sizeof(int));
|
||||
Stream->read(&mBlockAlign,sizeof(short));
|
||||
Stream->read(&mBitsPerSample,sizeof(short));
|
||||
Stream->seek(40,false);
|
||||
Stream->read(&mDataSize,sizeof(int));
|
||||
Stream->seek(44,false);
|
||||
const char* RIFFTAG = "RIFF";
|
||||
const char* WAVETAG = "WAVE";
|
||||
const char* FORMATTAG = "fmt ";
|
||||
const char* DATATAG = "data";
|
||||
|
||||
//Double the sampleRate to fix a bug with half-time speed
|
||||
mSampleRate += mSampleRate;
|
||||
char ident[4];
|
||||
int tempint32 = 0;
|
||||
short tempint16 = 0;
|
||||
char tempint8 = 0;
|
||||
|
||||
unsigned int startOffset = 0;
|
||||
|
||||
//Read the first 4 bytes
|
||||
Stream->seek(0, false);
|
||||
Stream->read(ident, 4);
|
||||
//Check to see if it is a valid RIFF file
|
||||
if(strncmp(ident, RIFFTAG, 4) == 0)
|
||||
{
|
||||
Stream->read(&tempint32, 4);
|
||||
//Check to see if the file is big enough to be valid (not completely accurate)
|
||||
if(tempint32 >= 44)
|
||||
{
|
||||
Stream->read(ident, 4);
|
||||
//Check that it is a wave file
|
||||
if(strncmp(ident, WAVETAG, 4) == 0)
|
||||
{
|
||||
//Save our position
|
||||
startOffset = Stream->getCurrentPos();
|
||||
|
||||
//Scan for the first fmt chuck (not necessarily right after)
|
||||
do
|
||||
{
|
||||
Stream->read(ident, 4);
|
||||
}
|
||||
while((strncmp(ident, FORMATTAG, 4) != 0) && (Stream->getCurrentPos() < Stream->getSize()));
|
||||
|
||||
//Did we find it?
|
||||
if(Stream->getCurrentPos() < (Stream->getSize() - 16))
|
||||
{
|
||||
//Yes, read it in
|
||||
Stream->read(&tempint32, 4);
|
||||
if(tempint32 >= 16)
|
||||
{
|
||||
//Check that it is in PCM format, we don't support compressed wavs
|
||||
Stream->read(&tempint16, 2);
|
||||
if(tempint16 == 1)
|
||||
{
|
||||
Stream->read(&tempint16, 2);
|
||||
Channels = tempint16;
|
||||
//We only support mono or stereo wavs
|
||||
if(Channels == 1 || Channels == 2)
|
||||
{
|
||||
Stream->read(&tempint32, 4);
|
||||
SampleRate = tempint32;
|
||||
Stream->read(&tempint32, 4);
|
||||
ByteRate = tempint32;
|
||||
Stream->read(&tempint16, 2);
|
||||
BlockAlign = tempint16;
|
||||
Stream->read(&tempint16, 2);
|
||||
BitsPerSample = tempint16;
|
||||
|
||||
//We only support 8 bit or 16 bit wavs
|
||||
if(BitsPerSample == 8 || BitsPerSample == 16)
|
||||
{
|
||||
//Reset our pointer to start scanning for the data block
|
||||
Stream->seek(startOffset, false);
|
||||
//Scan for the first data chuck (not necessarily right after)
|
||||
do
|
||||
{
|
||||
Stream->read(ident, 4);
|
||||
}
|
||||
while((strncmp(ident, DATATAG, 4) != 0) && (Stream->getCurrentPos() < Stream->getSize()));
|
||||
|
||||
//Did we find it?
|
||||
if(Stream->getCurrentPos() < Stream->getSize())
|
||||
{
|
||||
//Get size of data block
|
||||
Stream->read(&tempint32, 4);
|
||||
DataSize = tempint32;
|
||||
DataOffset = Stream->getCurrentPos();
|
||||
|
||||
Valid = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cWavDecoder::~cWavDecoder()
|
||||
{
|
||||
mChunkSize = 0;
|
||||
mSubChunk1Size = 0;
|
||||
mFormat = 0;
|
||||
mChannels = 0;
|
||||
mSampleRate = 0;
|
||||
mByteRate = 0;
|
||||
mBlockAlign = 0;
|
||||
mBitsPerSample = 0;
|
||||
mDataSize = 0;
|
||||
{
|
||||
Channels = 0;
|
||||
SampleRate = 0;
|
||||
ByteRate = 0;
|
||||
BlockAlign = 0;
|
||||
BitsPerSample = 0;
|
||||
DataSize = 0;
|
||||
DataOffset = 0;
|
||||
Valid = false;
|
||||
}
|
||||
|
||||
//!Returns wav channel format
|
||||
AudioFormats cWavDecoder::getFormat()
|
||||
{
|
||||
if(mChannels = 1)
|
||||
if(Channels == 1 && BitsPerSample == 8)
|
||||
return EAF_8BIT_MONO;
|
||||
else if(Channels == 1 && BitsPerSample == 16)
|
||||
return EAF_16BIT_MONO;
|
||||
else if(Channels == 2 && BitsPerSample == 8)
|
||||
return EAF_8BIT_STEREO;
|
||||
else
|
||||
return EAF_16BIT_STEREO;
|
||||
|
||||
}
|
||||
|
||||
//!Returns wav data frequency
|
||||
int cWavDecoder::getFrequency()
|
||||
{
|
||||
return mSampleRate;
|
||||
return SampleRate;
|
||||
}
|
||||
|
||||
//!Returns if seeking is supported
|
||||
bool cWavDecoder::isSeekingSupported()
|
||||
{
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cWavDecoder::isValid()
|
||||
{
|
||||
return Valid;
|
||||
}
|
||||
|
||||
//!Reads wav data
|
||||
int cWavDecoder::readAudioData(void* output, int amount)
|
||||
{
|
||||
return Stream->read(output,amount);
|
||||
int currentPos = Stream->getCurrentPos();
|
||||
int startPos = DataOffset;
|
||||
int endPos = DataOffset + DataSize;
|
||||
int amountToRead = amount;
|
||||
|
||||
//Bounds checks (and adjustments if possible)
|
||||
if(currentPos > endPos)
|
||||
return 0;
|
||||
|
||||
if(currentPos < startPos)
|
||||
{
|
||||
Stream->seek(startPos, false);
|
||||
currentPos = Stream->getCurrentPos();
|
||||
}
|
||||
|
||||
if((currentPos + amountToRead) > endPos)
|
||||
amountToRead = endPos - currentPos;
|
||||
|
||||
if(amountToRead < 0)
|
||||
amountToRead = 0;
|
||||
|
||||
return Stream->read(output,amountToRead);
|
||||
|
||||
}
|
||||
|
||||
//!Sets data reader position
|
||||
bool cWavDecoder::setPosition(int position, bool relative)
|
||||
{
|
||||
//Safety to avoid reading the header as audio data
|
||||
if(!relative && position < 44)
|
||||
position = 44;
|
||||
int currentPos = Stream->getCurrentPos();
|
||||
int startPos = DataOffset;
|
||||
int endPos = DataOffset + DataSize;
|
||||
|
||||
//Bounds checks (and adjustments if possible)
|
||||
if(!relative && position < startPos)
|
||||
position = startPos;
|
||||
if(!relative && position > endPos)
|
||||
position = endPos;
|
||||
if(relative && currentPos + position < startPos)
|
||||
position = startPos - currentPos;
|
||||
if(relative && currentPos + position > startPos)
|
||||
position = endPos - currentPos;
|
||||
|
||||
Stream->seek(position,relative);
|
||||
return true;
|
||||
|
@ -78,7 +192,8 @@ namespace cAudio{
|
|||
//!Seeks wav data
|
||||
bool cWavDecoder::seek(float seconds,bool relative)
|
||||
{
|
||||
return false;
|
||||
int amountToSeek = seconds * (float)SampleRate * (float)Channels * (float)(BitsPerSample/8);
|
||||
return setPosition(amountToSeek, relative);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -25,6 +25,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Tutorial4_AudioCapture", "E
|
|||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Stress_Test", "tests\Stress_Test\Stress_Test.vcproj", "{0E491D8E-6B9E-4107-B50B-EC48CBA3203D}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mp3Decoder", "plugins\mp3Decoder\mp3Decoder.vcproj", "{F1741962-FBBB-4BA2-AC74-A97E2DDF6B2E}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Win32 = Debug|Win32
|
||||
|
@ -55,6 +57,10 @@ Global
|
|||
{0E491D8E-6B9E-4107-B50B-EC48CBA3203D}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{0E491D8E-6B9E-4107-B50B-EC48CBA3203D}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{0E491D8E-6B9E-4107-B50B-EC48CBA3203D}.Release|Win32.Build.0 = Release|Win32
|
||||
{F1741962-FBBB-4BA2-AC74-A97E2DDF6B2E}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{F1741962-FBBB-4BA2-AC74-A97E2DDF6B2E}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{F1741962-FBBB-4BA2-AC74-A97E2DDF6B2E}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{F1741962-FBBB-4BA2-AC74-A97E2DDF6B2E}.Release|Win32.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
|
@ -221,6 +221,10 @@
|
|||
RelativePath=".\Headers\cOggDecoder.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Headers\cPluginManager.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Headers\cRawAudioDecoderFactory.h"
|
||||
>
|
||||
|
@ -234,7 +238,7 @@
|
|||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Headers\cWavAudioDecoderFacotry.h"
|
||||
RelativePath=".\Headers\cWavAudioDecoderFactory.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
|
@ -301,6 +305,10 @@
|
|||
RelativePath=".\Source\cOggDecoder.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Source\cPluginManager.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Source\cRawDecoder.cpp"
|
||||
>
|
||||
|
@ -369,6 +377,10 @@
|
|||
RelativePath=".\include\ILogReceiver.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\include\IRefCounted.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Util"
|
||||
|
|
Binary file not shown.
|
@ -1,12 +1,13 @@
|
|||
#ifndef IAUDIO_H
|
||||
#define IAUDIO_H
|
||||
|
||||
#include "IRefCounted.h"
|
||||
#include "IAudioDecoder.h"
|
||||
#include "cVector3.h"
|
||||
|
||||
namespace cAudio
|
||||
{
|
||||
class IAudio
|
||||
class IAudio : public IRefCounted
|
||||
{
|
||||
public:
|
||||
IAudio() {}
|
||||
|
@ -29,7 +30,7 @@ namespace cAudio
|
|||
/** Note: May not be supported by all codecs
|
||||
\param seconds: Number of seconds from the start of the audio stream to seek to
|
||||
\return True on success, False if the codec does not support seeking. */
|
||||
virtual bool seek(const float& seconds) = 0;
|
||||
virtual bool seek(const float& seconds, bool relative = false) = 0;
|
||||
|
||||
//! Normally called every frame by the audio manager to update the internal buffers
|
||||
//! Note: For internal use only.
|
||||
|
|
|
@ -1,39 +1,41 @@
|
|||
#ifndef IAUDIODECODER_H
|
||||
#define IAUDIODECODER_H
|
||||
|
||||
#include "IRefCounted.h"
|
||||
#include "IDataSource.h"
|
||||
#include "eAudioFormats.h"
|
||||
|
||||
namespace cAudio
|
||||
{
|
||||
class IAudioDecoder : public IRefCounted
|
||||
{
|
||||
public:
|
||||
IAudioDecoder(IDataSource* stream) : Stream(stream) { if(Stream) Stream->grab(); }
|
||||
virtual ~IAudioDecoder() { if(Stream) Stream->drop(); }
|
||||
|
||||
class IAudioDecoder
|
||||
{
|
||||
public:
|
||||
IAudioDecoder(IDataSource* stream) : Stream(stream) {}
|
||||
virtual ~IAudioDecoder() { delete Stream; }
|
||||
//!Returns the format of the audio data
|
||||
virtual AudioFormats getFormat() = 0;
|
||||
|
||||
//!Returns the format of the audio data
|
||||
virtual AudioFormats getFormat() = 0;
|
||||
//!Returns the frequency of the audio data
|
||||
virtual int getFrequency() = 0;
|
||||
|
||||
//!Returns the frequency of the audio data
|
||||
virtual int getFrequency() = 0;
|
||||
//!Returns whether seeking is supported
|
||||
virtual bool isSeekingSupported() = 0;
|
||||
|
||||
//!Returns whether seeking is supported
|
||||
virtual bool isSeekingSupported() = 0;
|
||||
//!Returns whether the stream is valid for this codec
|
||||
virtual bool isValid() = 0;
|
||||
|
||||
//!Reads a section of data out of the audio stream
|
||||
virtual int readAudioData(void* output, int amount) = 0;
|
||||
//!Reads a section of data out of the audio stream
|
||||
virtual int readAudioData(void* output, int amount) = 0;
|
||||
|
||||
//!Sets the position to read data out of
|
||||
virtual bool setPosition(int position, bool relative) = 0;
|
||||
|
||||
//!If seeking is supported, will seek the stream to seconds
|
||||
virtual bool seek(float seconds, bool relative) = 0;
|
||||
protected:
|
||||
IDataSource* Stream;
|
||||
};
|
||||
//!Sets the position to read data out of
|
||||
virtual bool setPosition(int position, bool relative) = 0;
|
||||
|
||||
//!If seeking is supported, will seek the stream to seconds
|
||||
virtual bool seek(float seconds, bool relative) = 0;
|
||||
protected:
|
||||
IDataSource* Stream;
|
||||
};
|
||||
};
|
||||
|
||||
#endif //! IAUDIODECODER_H
|
||||
|
|
|
@ -1,31 +1,31 @@
|
|||
#ifndef IDATASOURCE_H
|
||||
#define IDATASOURCE_H
|
||||
|
||||
#include "IRefCounted.h"
|
||||
|
||||
namespace cAudio
|
||||
{
|
||||
class IDataSource : public IRefCounted
|
||||
{
|
||||
public:
|
||||
IDataSource() { }
|
||||
virtual ~IDataSource() { }
|
||||
|
||||
class IDataSource
|
||||
{
|
||||
public:
|
||||
IDataSource() { }
|
||||
virtual ~IDataSource() { }
|
||||
//!Returns whether the source is valid (in case of an error, like the file couldn't be found)
|
||||
virtual bool isValid() = 0;
|
||||
|
||||
//!Returns whether the source is valid (in case of an error, like the file couldn't be found)
|
||||
virtual bool isValid() = 0;
|
||||
//!Get the current location in the data stream
|
||||
virtual int getCurrentPos() = 0;
|
||||
|
||||
//!Get the current location in the data stream
|
||||
virtual int getCurrentPos() = 0;
|
||||
//!Get the total size of the data stream
|
||||
virtual int getSize() = 0;
|
||||
|
||||
//!Get the total size of the data stream
|
||||
virtual int getSize() = 0;
|
||||
|
||||
//!Read out a section of the data stream
|
||||
virtual int read(void* output, int size) = 0;
|
||||
|
||||
//!Seek to a position in the data stream
|
||||
virtual bool seek(int amount, bool relative) = 0;
|
||||
};
|
||||
//!Read out a section of the data stream
|
||||
virtual int read(void* output, int size) = 0;
|
||||
|
||||
//!Seek to a position in the data stream
|
||||
virtual bool seek(int amount, bool relative) = 0;
|
||||
};
|
||||
};
|
||||
|
||||
#endif //! IDATASOURCE_H
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
#ifndef IREFCOUNTED_H
|
||||
#define IREFCOUNTED_H
|
||||
|
||||
namespace cAudio
|
||||
{
|
||||
class IRefCounted
|
||||
{
|
||||
public:
|
||||
IRefCounted() : RefCount(1) { }
|
||||
virtual ~IRefCounted() { }
|
||||
|
||||
void grab()
|
||||
{
|
||||
++RefCount;
|
||||
}
|
||||
|
||||
bool drop()
|
||||
{
|
||||
--RefCount;
|
||||
if (RefCount < 1)
|
||||
{
|
||||
delete this;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int getReferenceCount() const
|
||||
{
|
||||
return RefCount;
|
||||
}
|
||||
|
||||
private:
|
||||
int RefCount;
|
||||
};
|
||||
}
|
||||
#endif //! IREFCOUNTED_H
|
|
@ -22,8 +22,8 @@
|
|||
|
||||
using namespace std;
|
||||
|
||||
#define MAXAUDIOSOURCES 128
|
||||
#define TESTDURATION 30
|
||||
#define MAXAUDIOSOURCES 64
|
||||
#define TESTDURATION 10
|
||||
|
||||
cAudio::IAudio* AudioSources[MAXAUDIOSOURCES];
|
||||
|
||||
|
@ -52,7 +52,7 @@ int main(int argc, char* argv[])
|
|||
if(manager)
|
||||
{
|
||||
//Allow the user to choose a playback device
|
||||
cout << "Available Playback Devices: \n";
|
||||
/*cout << "Available Playback Devices: \n";
|
||||
unsigned int deviceCount = manager->getAvailableDeviceCount();
|
||||
std::string defaultDeviceName = manager->getDefaultDeviceName();
|
||||
for(unsigned int i=0; i<deviceCount; ++i)
|
||||
|
@ -67,10 +67,11 @@ int main(int argc, char* argv[])
|
|||
cout << "Choose a device by number: ";
|
||||
unsigned int deviceSelection = 0;
|
||||
cin >> deviceSelection;
|
||||
cout << std::endl;
|
||||
cout << std::endl;*/
|
||||
|
||||
//Initialize the manager with the user settings
|
||||
manager->initialize(manager->getAvailableDeviceName(deviceSelection));
|
||||
//manager->initialize(manager->getAvailableDeviceName(deviceSelection));
|
||||
manager->initialize(NULL);
|
||||
|
||||
//Grab the listener object, which allows us to manipulate where "we" are in the world
|
||||
//It's useful to bind this to a camera if you are using a 3d graphics engine
|
||||
|
@ -117,7 +118,8 @@ int main(int argc, char* argv[])
|
|||
currentTick = clock();
|
||||
}
|
||||
cout << "Did " << currentCycle << " source moves in " << TESTDURATION << " seconds. \n";
|
||||
cout << "Each move took an average of " << ((float)TESTDURATION/(float)currentCycle)*1000.f << " milliseconds. \n \n";
|
||||
cout << "Average Moves Per Second: " << (((float)currentCycle)/(float)TESTDURATION) << " \n";
|
||||
cout << "Average Frames (All audio sources moved) Per Second: " << (((float)currentCycle/(float)MAXAUDIOSOURCES)/(float)TESTDURATION) << " \n \n";
|
||||
|
||||
std::cout << std::endl;
|
||||
|
||||
|
@ -141,7 +143,7 @@ int main(int argc, char* argv[])
|
|||
|
||||
std::cout << "Press any key to quit \n";
|
||||
std::cin.get();
|
||||
std::cin.get();
|
||||
//std::cin.get();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue