Changed IAudioManager to no longer use std::strings in the main interface. It now uses const char* strings. The reason this change was made was to make porting to other languages, or even use with other string libraries easier. std::string is no longer required to interface with the library.
Added a convenience function (move()) to the cAudio source, making it easier to move a source and do velocity for doppler effects with a single call. Internally, audio sources are now stored in an std::vector for better performance. This change also makes it so that it is no longer required for the user to name a source. The user can pass NULL to name to avoid naming it. Some documentation fixes. Added a stress test app, allowing users and developers test how well cAudio performs under pressure.
This commit is contained in:
parent
e1bf4ecc9a
commit
4c76942a7f
|
@ -1,4 +1,6 @@
|
|||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
//Include IAudioManager so we can easily work with cAudio
|
||||
#include "../../include/IAudioManager.h"
|
||||
//Include IAudio so we can create cAudio objects
|
||||
|
|
|
@ -4,7 +4,9 @@
|
|||
//****************************************************************
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <math.h>
|
||||
|
||||
//Include IAudioManager so we can easily work with cAudio
|
||||
#include "../../include/IAudioManager.h"
|
||||
//Include IAudio so we can create cAudio objects
|
||||
|
@ -54,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", true);
|
||||
|
||||
//Set the IAudio Sound to play3d and loop
|
||||
//play3d takes 4 arguments play3d(toloop,x,y,z,strength)
|
||||
|
@ -79,7 +81,7 @@ int main(int argc, char* argv[])
|
|||
//Sound "starts" at x=5, y=0, z=0
|
||||
float x = 5.0f * cosf(rot) - 0.0f * sinf(rot);
|
||||
float z = 0.0f * cosf(rot) + 5.0f * sinf(rot);
|
||||
mysound->setPosition(cAudio::cVector3(x,0.0,z));
|
||||
mysound->move(cAudio::cVector3(x,0.0,z));
|
||||
|
||||
++currentTick;
|
||||
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
//****************************************************************
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
//Include IAudioManager so we can easily work with cAudio
|
||||
#include "../../include/IAudioManager.h"
|
||||
//Include IAudio so we can create cAudio objects
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
#ifndef CAUDIO_H_INCLUDED
|
||||
#define CAUDIO_H_INCLUDED
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <AL/al.h>
|
||||
#include <AL/alc.h>
|
||||
|
@ -113,6 +112,10 @@ namespace cAudio
|
|||
//! Overrides the doppler velocity vector
|
||||
virtual void setDopplerVelocity(const cVector3& dvelocity);
|
||||
|
||||
//! Convenience function to automatically set the velocity and position for you in a single call
|
||||
//! Velocity will be set to new position - last position
|
||||
virtual void move(const cVector3& position);
|
||||
|
||||
//!Returns the audio objects position
|
||||
virtual const cVector3 getPosition() const;
|
||||
//!Returns the audio objects velocity
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
#ifndef CAUDIOMANAGER_H_INCLUDED
|
||||
#define CAUDIOMANAGER_H_INCLUDED
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "cAudio.h"
|
||||
#include "../include/IAudioDecoderFactory.h"
|
||||
#include "cListener.h"
|
||||
|
@ -26,6 +28,12 @@ namespace cAudio
|
|||
virtual bool initialize(const char* deviceName = 0x0, int outputFrequency = -1, int eaxEffectSlots = 4);
|
||||
//!Shuts everything down
|
||||
virtual void shutDown();
|
||||
//!Updates the cAudio playback
|
||||
virtual void update();
|
||||
//!Gets you the cAudio object you want
|
||||
virtual IAudio* getSoundByName(const char* name);
|
||||
//!Releases "ALL" cAudio objects
|
||||
virtual void release();
|
||||
|
||||
//! Returns the name of an available playback device.
|
||||
/** \param index: Specify which name to retrieve ( Range: 0 to getAvailableDeviceCount()-1 ) */
|
||||
|
@ -36,29 +44,22 @@ namespace cAudio
|
|||
virtual const char* getDefaultDeviceName();
|
||||
|
||||
//!Creates the cAudio object
|
||||
virtual IAudio* createFromFile(const std::string& identifier,const std::string& file,bool stream = false);
|
||||
virtual IAudio* createFromFile(const char* name, const char* pathToFile, bool stream = false);
|
||||
//!Loads ogg from memory or virtual file system
|
||||
virtual IAudio* createFromMemory(const std::string& identifier, const char* data, size_t length, std::string ext);
|
||||
virtual IAudio* createFromMemory(const char* name, const char* data, size_t length, const char* extension);
|
||||
//!Loads raw audio from memory.
|
||||
virtual IAudio* createFromRaw(const std::string& identifier,const char* data, size_t length, unsigned int frequency, AudioFormats format);
|
||||
virtual IAudio* createFromRaw(const char* name, const char* data, size_t length, unsigned int frequency, AudioFormats format);
|
||||
|
||||
//!Register Audio Codec
|
||||
virtual bool registerAudioDecoder(IAudioDecoderFactory* factory, std::string extension);
|
||||
virtual bool registerAudioDecoder(IAudioDecoderFactory* factory, const char* extension);
|
||||
//!Unregister Audio Codec (allows you to prevent an file type from being playable with new sound sources)
|
||||
//!Note that all current sound sources will still continue to use any currently allocated decoders.
|
||||
//!Will NOT delete any user added factory instance, you must do that yourself
|
||||
virtual void unRegisterAudioDecoder(std::string extension);
|
||||
virtual void unRegisterAudioDecoder(const char* extension);
|
||||
//!Returns whether an audio decoder is currently registered for this file type
|
||||
virtual bool isAudioDecoderRegistered(std::string extension);
|
||||
virtual bool isAudioDecoderRegistered(const char* extension);
|
||||
//!Returns a registered audio decoder factory
|
||||
virtual IAudioDecoderFactory* getAudioDecoderFactory(std::string extension);
|
||||
|
||||
//!Updates the cAudio playback
|
||||
virtual void update();
|
||||
//!Gets you the cAudio object you want
|
||||
virtual IAudio *getSound(std::string identifier);
|
||||
//!Releases "ALL" cAudio objects
|
||||
virtual void release();
|
||||
virtual IAudioDecoderFactory* getAudioDecoderFactory(const char* extension);
|
||||
|
||||
//! Grabs a list of available devices, as well as the default system one
|
||||
void getAvailableDevices();
|
||||
|
@ -70,12 +71,14 @@ namespace cAudio
|
|||
cAudioMutex Mutex;
|
||||
|
||||
//Make a Openal context pointer
|
||||
ALCcontext *Context;
|
||||
ALCcontext* Context;
|
||||
//Make a openal device pointer
|
||||
ALCdevice *Device;
|
||||
ALCdevice* Device;
|
||||
|
||||
//!The map that holds the cAudio objects
|
||||
std::map<std::string, IAudio*> audiomap;
|
||||
//! 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
|
||||
std::map<std::string, IAudioDecoderFactory*> decodermap;
|
||||
//!The listener object
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
#ifndef CLOGGER_H_INCLUDED
|
||||
#define CLOGGER_H_INCLUDED
|
||||
|
||||
#include "../include/ILogger.h"
|
||||
#include "../Headers/cMutex.h"
|
||||
#include <map>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "../include/ILogger.h"
|
||||
#include "../Headers/cMutex.h"
|
||||
|
||||
namespace cAudio
|
||||
{
|
||||
class cLogger : public ILogger
|
||||
|
@ -26,14 +27,14 @@ namespace cAudio
|
|||
//! Register Log Receiver
|
||||
//! Note: Any class registered will become owned by the internal thread.
|
||||
//! If threading is enabled, you MUST make the receiver threadsafe if you plan to access it in your application while it is registered
|
||||
virtual bool registerLogReceiver(ILogReceiver* receiver, std::string name);
|
||||
virtual bool registerLogReceiver(ILogReceiver* receiver, const char* name);
|
||||
//!Unregister a Log Receiver
|
||||
//!Will NOT delete any user added receiver, you must do that yourself
|
||||
virtual void unRegisterLogReceiver(std::string name);
|
||||
virtual void unRegisterLogReceiver(const char* name);
|
||||
//!Returns whether an log receiver is currently registered
|
||||
virtual bool isLogReceiverRegistered(std::string name);
|
||||
virtual bool isLogReceiverRegistered(const char* name);
|
||||
//!Returns a registered log receiver
|
||||
virtual ILogReceiver* getLogReceiver(std::string name);
|
||||
virtual ILogReceiver* getLogReceiver(const char* name);
|
||||
|
||||
protected:
|
||||
void broadcastMessage( LogLevel level, const char* sender, const char* msg, va_list args );
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
#include <iostream>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "../Headers/cAudio.h"
|
||||
#include "../Headers/cLogger.h"
|
||||
|
||||
|
@ -323,6 +320,18 @@ namespace cAudio
|
|||
Mutex.unlock();
|
||||
}
|
||||
|
||||
void cAudio::move(const cVector3& position)
|
||||
{
|
||||
Mutex.lock();
|
||||
cVector3 oldPos = getPosition();
|
||||
cVector3 velocity = position - oldPos;
|
||||
|
||||
alSource3f(Source, AL_VELOCITY, velocity.x, velocity.y, velocity.z);
|
||||
alSource3f(Source, AL_POSITION, position.x, position.y, position.z);
|
||||
checkError();
|
||||
Mutex.unlock();
|
||||
}
|
||||
|
||||
const cVector3 cAudio::getPosition() const
|
||||
{
|
||||
cVector3 position;
|
||||
|
|
|
@ -130,15 +130,20 @@ namespace cAudio
|
|||
}
|
||||
|
||||
//!create a sound source
|
||||
IAudio* cAudioManager::createFromFile(const std::string& identifier,const std::string& file,bool stream)
|
||||
IAudio* cAudioManager::createFromFile(const char* name, const char* pathToFile, bool stream)
|
||||
{
|
||||
Mutex.lock();
|
||||
if(stream){
|
||||
cFileSource* source = new cFileSource(file);
|
||||
|
||||
std::string audioName = safeCStr(name);
|
||||
std::string path = safeCStr(pathToFile);
|
||||
|
||||
if(stream)
|
||||
{
|
||||
cFileSource* source = new cFileSource(path);
|
||||
if(source->isValid())
|
||||
{
|
||||
std::string ext = getExt(file);
|
||||
IAudioDecoderFactory* factory = getAudioDecoderFactory(ext);
|
||||
std::string ext = getExt(path);
|
||||
IAudioDecoderFactory* factory = getAudioDecoderFactory(ext.c_str());
|
||||
if(!factory)
|
||||
{
|
||||
delete source;
|
||||
|
@ -147,27 +152,32 @@ namespace cAudio
|
|||
}
|
||||
IAudioDecoder* decoder = factory->CreateAudioDecoder(source);
|
||||
IAudio* audio = new cAudio(decoder);
|
||||
audiomap[identifier] = audio;
|
||||
getLogger()->logInfo("AudioManager", "Streaming Audio Source (%s) created from file %s.", identifier.c_str(), file.c_str());
|
||||
|
||||
if(!audioName.empty())
|
||||
audioIndex[audioName] = 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.", identifier.c_str(), file.c_str());
|
||||
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(file);
|
||||
cFileSource* tempsource = new cFileSource(path);
|
||||
int length = tempsource->getSize();
|
||||
char *tempbuf = new char[length];
|
||||
tempsource->read(tempbuf,length);
|
||||
|
||||
IAudio* guy = createFromMemory(identifier,tempbuf,length,getExt(file));
|
||||
IAudio* guy = createFromMemory(name, tempbuf, length, getExt(path).c_str());
|
||||
delete[]tempbuf;
|
||||
delete tempsource;
|
||||
Mutex.unlock();
|
||||
|
@ -176,13 +186,17 @@ namespace cAudio
|
|||
}
|
||||
|
||||
//!Loads the ogg file from memory *virtual file systems*
|
||||
IAudio* cAudioManager::createFromMemory(const std::string& identifier, const char* data, size_t length, std::string ext)
|
||||
IAudio* cAudioManager::createFromMemory(const char* name, const char* data, size_t length, const char* extension)
|
||||
{
|
||||
Mutex.lock();
|
||||
cMemorySource* source = new cMemorySource(data,length,true);
|
||||
|
||||
std::string audioName = safeCStr(name);
|
||||
std::string ext = safeCStr(extension);
|
||||
|
||||
cMemorySource* source = new cMemorySource(data, length, true);
|
||||
if(source->isValid())
|
||||
{
|
||||
IAudioDecoderFactory* factory = getAudioDecoderFactory(ext);
|
||||
IAudioDecoderFactory* factory = getAudioDecoderFactory(ext.c_str());
|
||||
if(!factory)
|
||||
{
|
||||
delete source;
|
||||
|
@ -191,24 +205,31 @@ namespace cAudio
|
|||
}
|
||||
IAudioDecoder* decoder = factory->CreateAudioDecoder(source);
|
||||
IAudio* audio = new cAudio(decoder);
|
||||
audiomap[identifier] = audio;
|
||||
getLogger()->logInfo("AudioManager", "Audio Source (%s) created from memory buffer.", identifier.c_str());
|
||||
|
||||
if(!audioName.empty())
|
||||
audioIndex[audioName] = 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.", identifier.c_str());
|
||||
getLogger()->logError("AudioManager", "Failed to create Audio Source (%s) from memory buffer.", audioName.c_str());
|
||||
Mutex.unlock();
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
IAudio* cAudioManager::createFromRaw(const std::string& identifier,const char* data, size_t length, unsigned int frequency, AudioFormats format)
|
||||
IAudio* cAudioManager::createFromRaw(const char* name, const char* data, size_t length, unsigned int frequency, AudioFormats format)
|
||||
{
|
||||
Mutex.lock();
|
||||
cMemorySource* source = new cMemorySource(data,length,true);
|
||||
std::string audioName = safeCStr(name);
|
||||
|
||||
cMemorySource* source = new cMemorySource(data, length, true);
|
||||
if(source->isValid())
|
||||
{
|
||||
IAudioDecoderFactory* factory = getAudioDecoderFactory("raw");
|
||||
|
@ -220,54 +241,63 @@ namespace cAudio
|
|||
}
|
||||
IAudioDecoder* decoder = ((cRawAudioDecoderFactory*)factory)->CreateAudioDecoder(source, frequency, format);
|
||||
IAudio* audio = new cAudio(decoder);
|
||||
audiomap[identifier] = audio;
|
||||
getLogger()->logInfo("AudioManager", "Raw Audio Source (%s) created from memory buffer.", identifier.c_str());
|
||||
|
||||
if(!audioName.empty())
|
||||
audioIndex[audioName] = 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.", identifier.c_str());
|
||||
getLogger()->logError("AudioManager", "Failed to create Raw Audio Source (%s) from memory buffer.", audioName.c_str());
|
||||
Mutex.unlock();
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool cAudioManager::registerAudioDecoder(IAudioDecoderFactory* factory, std::string extension)
|
||||
bool cAudioManager::registerAudioDecoder(IAudioDecoderFactory* factory, const char* extension)
|
||||
{
|
||||
Mutex.lock();
|
||||
decodermap[extension] = factory;
|
||||
getLogger()->logInfo("AudioManager", "Audio Decoder for extension .%s registered.", extension.c_str());
|
||||
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(std::string extension)
|
||||
void cAudioManager::unRegisterAudioDecoder(const char* extension)
|
||||
{
|
||||
Mutex.lock();
|
||||
std::map<std::string, IAudioDecoderFactory*>::iterator it = decodermap.find(extension);
|
||||
std::string ext = safeCStr(extension);
|
||||
std::map<std::string, IAudioDecoderFactory*>::iterator it = decodermap.find(ext);
|
||||
if(it != decodermap.end())
|
||||
{
|
||||
decodermap.erase(it);
|
||||
getLogger()->logInfo("AudioManager", "Audio Decoder for extension .%s unregistered.", extension.c_str());
|
||||
getLogger()->logInfo("AudioManager", "Audio Decoder for extension .%s unregistered.", ext.c_str());
|
||||
}
|
||||
Mutex.unlock();
|
||||
}
|
||||
|
||||
bool cAudioManager::isAudioDecoderRegistered(std::string extension)
|
||||
bool cAudioManager::isAudioDecoderRegistered(const char* extension)
|
||||
{
|
||||
Mutex.lock();
|
||||
std::map<std::string, IAudioDecoderFactory*>::iterator it = decodermap.find(extension);
|
||||
std::string ext = safeCStr(extension);
|
||||
std::map<std::string, IAudioDecoderFactory*>::iterator it = decodermap.find(ext);
|
||||
bool result = (it != decodermap.end());
|
||||
Mutex.unlock();
|
||||
return result;
|
||||
}
|
||||
|
||||
IAudioDecoderFactory* cAudioManager::getAudioDecoderFactory(std::string extension)
|
||||
IAudioDecoderFactory* cAudioManager::getAudioDecoderFactory(const char* extension)
|
||||
{
|
||||
Mutex.lock();
|
||||
std::map<std::string, IAudioDecoderFactory*>::iterator it = decodermap.find(extension);
|
||||
std::string ext = safeCStr(extension);
|
||||
std::map<std::string, IAudioDecoderFactory*>::iterator it = decodermap.find(ext);
|
||||
if(it != decodermap.end())
|
||||
{
|
||||
Mutex.unlock();
|
||||
|
@ -278,11 +308,12 @@ namespace cAudio
|
|||
}
|
||||
|
||||
//!grabs the selected audio file via the identifier
|
||||
IAudio *cAudioManager::getSound(std::string identifier)
|
||||
IAudio* cAudioManager::getSoundByName(const char* name)
|
||||
{
|
||||
Mutex.lock();
|
||||
std::map<std::string,IAudio*>::iterator i = audiomap.find(identifier);
|
||||
if (i == audiomap.end())
|
||||
std::string audioName = safeCStr(name);
|
||||
std::map<std::string,IAudio*>::iterator i = audioIndex.find(audioName);
|
||||
if (i == audioIndex.end())
|
||||
{
|
||||
Mutex.unlock();
|
||||
return NULL;
|
||||
|
@ -295,14 +326,14 @@ namespace cAudio
|
|||
void cAudioManager::release()
|
||||
{
|
||||
Mutex.lock();
|
||||
std::map<std::string,IAudio*>::iterator i = audiomap.begin();
|
||||
while ( i != audiomap.end())
|
||||
{
|
||||
i->second->release();
|
||||
delete i->second;
|
||||
i++;
|
||||
}
|
||||
audiomap.clear();
|
||||
for(unsigned int i=0; i<audioSources.size(); ++i)
|
||||
{
|
||||
IAudio* source = audioSources[i];
|
||||
if(source)
|
||||
delete source;
|
||||
}
|
||||
audioSources.clear();
|
||||
audioIndex.clear();
|
||||
decodermap.clear();
|
||||
Mutex.unlock();
|
||||
}
|
||||
|
@ -311,12 +342,12 @@ namespace cAudio
|
|||
void cAudioManager::update()
|
||||
{
|
||||
Mutex.lock();
|
||||
std::map<std::string,IAudio*>::iterator i = audiomap.begin();
|
||||
for (i = audiomap.begin(); i != audiomap.end() ; i++)
|
||||
{
|
||||
if (i->second->isValid() == true)
|
||||
for(unsigned int i=0; i<audioSources.size(); ++i)
|
||||
{
|
||||
IAudio* source = audioSources[i];
|
||||
if (source->isValid())
|
||||
{
|
||||
if (i->second->update())
|
||||
if (source->update())
|
||||
{
|
||||
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "../Headers/cLogger.h"
|
||||
#include <time.h>
|
||||
#include "../Headers/cLogger.h"
|
||||
#include "../Headers/cConsoleLogReceiver.h"
|
||||
#include "../Headers/cUtils.h"
|
||||
|
||||
namespace cAudio
|
||||
{
|
||||
|
@ -90,18 +91,20 @@ namespace cAudio
|
|||
it->second->OnLogMessage(sender, TempTextBuf, level, messageTime);
|
||||
}
|
||||
}
|
||||
bool cLogger::registerLogReceiver(ILogReceiver* receiver, std::string name)
|
||||
bool cLogger::registerLogReceiver(ILogReceiver* receiver, const char* name)
|
||||
{
|
||||
Mutex.lock();
|
||||
Receivers[name] = receiver;
|
||||
std::string logName = safeCStr(name);
|
||||
Receivers[logName] = receiver;
|
||||
Mutex.unlock();
|
||||
return true;
|
||||
}
|
||||
|
||||
void cLogger::unRegisterLogReceiver(std::string name)
|
||||
void cLogger::unRegisterLogReceiver(const char* name)
|
||||
{
|
||||
Mutex.lock();
|
||||
std::map<std::string, ILogReceiver*>::iterator it = Receivers.find(name);
|
||||
std::string logName = safeCStr(name);
|
||||
std::map<std::string, ILogReceiver*>::iterator it = Receivers.find(logName);
|
||||
if(it != Receivers.end())
|
||||
{
|
||||
Receivers.erase(it);
|
||||
|
@ -109,19 +112,21 @@ namespace cAudio
|
|||
Mutex.unlock();
|
||||
}
|
||||
|
||||
bool cLogger::isLogReceiverRegistered(std::string name)
|
||||
bool cLogger::isLogReceiverRegistered(const char* name)
|
||||
{
|
||||
Mutex.lock();
|
||||
std::map<std::string, ILogReceiver*>::iterator it = Receivers.find(name);
|
||||
std::string logName = safeCStr(name);
|
||||
std::map<std::string, ILogReceiver*>::iterator it = Receivers.find(logName);
|
||||
bool result = (it != Receivers.end());
|
||||
Mutex.unlock();
|
||||
return result;
|
||||
}
|
||||
|
||||
ILogReceiver* cLogger::getLogReceiver(std::string name)
|
||||
ILogReceiver* cLogger::getLogReceiver(const char* name)
|
||||
{
|
||||
Mutex.lock();
|
||||
std::map<std::string, ILogReceiver*>::iterator it = Receivers.find(name);
|
||||
std::string logName = safeCStr(name);
|
||||
std::map<std::string, ILogReceiver*>::iterator it = Receivers.find(logName);
|
||||
if(it != Receivers.end())
|
||||
{
|
||||
Mutex.unlock();
|
||||
|
|
|
@ -23,6 +23,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Tutorial4_AudioCapture", "E
|
|||
{ACD6C202-85D4-44F5-83BF-6577A074F655} = {ACD6C202-85D4-44F5-83BF-6577A074F655}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Stress_Test", "tests\Stress_Test\Stress_Test.vcproj", "{0E491D8E-6B9E-4107-B50B-EC48CBA3203D}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Win32 = Debug|Win32
|
||||
|
@ -49,6 +51,10 @@ Global
|
|||
{F04BE31E-E8CC-40C8-9C63-EEAE1BF84EB7}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{F04BE31E-E8CC-40C8-9C63-EEAE1BF84EB7}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{F04BE31E-E8CC-40C8-9C63-EEAE1BF84EB7}.Release|Win32.Build.0 = Release|Win32
|
||||
{0E491D8E-6B9E-4107-B50B-EC48CBA3203D}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{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
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
|
@ -101,11 +101,15 @@ namespace cAudio
|
|||
//! Overrides the doppler velocity vector
|
||||
virtual void setDopplerVelocity(const cVector3& dvelocity) = 0;
|
||||
|
||||
//!Returns the audio objects position
|
||||
//! Convenience function to automatically set the velocity and position for you in a single call
|
||||
//! Velocity will be set to new position - last position
|
||||
virtual void move(const cVector3& position) = 0;
|
||||
|
||||
//! Returns the audio objects position
|
||||
virtual const cVector3 getPosition() const = 0;
|
||||
//!Returns the audio objects velocity
|
||||
//! Returns the audio objects velocity
|
||||
virtual const cVector3 getVelocity() const = 0;
|
||||
//!Returns the audio objects direction
|
||||
//! Returns the audio objects direction
|
||||
virtual const cVector3 getDirection() const = 0;
|
||||
|
||||
//! Returns the factor used in attenuating the source over distance
|
||||
|
@ -117,9 +121,9 @@ namespace cAudio
|
|||
//! Returns the distance from the source where attenuation will stop
|
||||
virtual const float getMaxDistance() const = 0;
|
||||
|
||||
//!Returns the pitch of the source
|
||||
//! Returns the pitch of the source
|
||||
virtual const float getPitch() const = 0;
|
||||
//!Returns the source volume before attenuation and other effects
|
||||
//! Returns the source volume before attenuation and other effects
|
||||
virtual const float getVolume() const = 0;
|
||||
//! Returns the minimum volume that the source can be attenuated to
|
||||
virtual const float getMinVolume() const = 0;
|
||||
|
@ -133,9 +137,9 @@ namespace cAudio
|
|||
//! Returns how much the volume of the source is scaled in the outer cone
|
||||
virtual const float getOuterConeVolume() const = 0;
|
||||
|
||||
//!Returns the doppler strength, which enhances or diminishes the doppler effect
|
||||
//! Returns the doppler strength, which enhances or diminishes the doppler effect
|
||||
virtual const float getDopplerStrength() const = 0;
|
||||
//!Returns the override for the doppler velocity vector
|
||||
//! Returns the override for the doppler velocity vector
|
||||
virtual const cVector3 getDopplerVelocity() const = 0;
|
||||
|
||||
protected:
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#ifndef IAUDIOMANAGER_H
|
||||
#define IAUDIOMANAGER_H
|
||||
#include <string>
|
||||
|
||||
#include "IListener.h"
|
||||
#include "cAudioDefines.h"
|
||||
#include "eAudioFormats.h"
|
||||
|
@ -23,7 +23,7 @@ namespace cAudio
|
|||
//!Updates the cAudio playback
|
||||
virtual void update() = 0;
|
||||
//!Returns an IAudio object by its "name" and 0 if the name is not found
|
||||
virtual IAudio* getSound(std::string identifier) = 0;
|
||||
virtual IAudio* getSoundByName(const char* name) = 0;
|
||||
//!Releases "ALL" cAudio objects (but does not shutdown the manager)
|
||||
virtual void release() = 0;
|
||||
|
||||
|
@ -36,22 +36,22 @@ namespace cAudio
|
|||
virtual const char* getDefaultDeviceName() = 0;
|
||||
|
||||
//!Creates the cAudio object
|
||||
virtual IAudio* createFromFile(const std::string& identifier,const std::string& file,bool stream = false) = 0;
|
||||
virtual IAudio* createFromFile(const char* name, const char* pathToFile, bool stream = false) = 0;
|
||||
//!Loads audio from memory or virtual file system
|
||||
virtual IAudio* createFromMemory(const std::string& identifier,const char* data, size_t length, std::string ext) = 0;
|
||||
virtual IAudio* createFromMemory(const char* name, const char* data, size_t length, const char* extension) = 0;
|
||||
//!Loads raw audio from memory.
|
||||
virtual IAudio* createFromRaw(const std::string& identifier,const char* data, size_t length, unsigned int frequency, AudioFormats format) = 0;
|
||||
virtual IAudio* createFromRaw(const char* name, const char* data, size_t length, unsigned int frequency, AudioFormats format) = 0;
|
||||
|
||||
//!Register Audio Codec
|
||||
virtual bool registerAudioDecoder(IAudioDecoderFactory* factory, std::string extension) = 0;
|
||||
virtual bool registerAudioDecoder(IAudioDecoderFactory* factory, const char* extension) = 0;
|
||||
//!Unregister Audio Codec (allows you to prevent an file type from being playable with new sound sources)
|
||||
//!Note that all current sound sources will still continue to use any currently allocated decoders.
|
||||
//!Will NOT delete any user added factory instance, you must do that yourself
|
||||
virtual void unRegisterAudioDecoder(std::string extension) = 0;
|
||||
virtual void unRegisterAudioDecoder(const char* extension) = 0;
|
||||
//!Returns whether an audio decoder is currently registered for this file type
|
||||
virtual bool isAudioDecoderRegistered(std::string extension) = 0;
|
||||
virtual bool isAudioDecoderRegistered(const char* extension) = 0;
|
||||
//!Returns a registered audio decoder factory
|
||||
virtual IAudioDecoderFactory* getAudioDecoderFactory(std::string extension) = 0;
|
||||
virtual IAudioDecoderFactory* getAudioDecoderFactory(const char* extension) = 0;
|
||||
|
||||
//!Returns an interface for the listener
|
||||
virtual IListener* getListener() = 0;
|
||||
|
|
|
@ -13,9 +13,8 @@ namespace cAudio
|
|||
virtual ~IListener() {}
|
||||
|
||||
//!Sets the position of the listener
|
||||
//!Note that this will automatically set velocity to 0
|
||||
//!Note that you will still have to set velocity after this call for proper doppler effects
|
||||
//!Use move() if you'd like to have cAudio automatically handle velocity for you
|
||||
//!or remember to set it yourself after setPosition
|
||||
virtual void setPosition(const cVector3 pos) = 0;
|
||||
//!Sets the direction the listener is facing
|
||||
virtual void setDirection(const cVector3 dir) = 0;
|
||||
|
@ -26,7 +25,7 @@ namespace cAudio
|
|||
//!Sets the global volume modifier (will effect all sources)
|
||||
virtual void setMasterVolume(const float volume) = 0;
|
||||
|
||||
//!Convenience function to automatically set the velocity for you on a move
|
||||
//!Convenience function to automatically set the velocity and position for you in a single call
|
||||
//!Velocity will be set to new position - last position
|
||||
virtual void move(const cVector3 pos) = 0;
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
|
||||
#include "ILogReceiver.h"
|
||||
#include "cAudioDefines.h"
|
||||
#include <string>
|
||||
|
||||
namespace cAudio
|
||||
{
|
||||
|
@ -25,14 +24,14 @@ namespace cAudio
|
|||
//! Register Log Receiver
|
||||
//! Note: Any class registered will become owned by the internal thread.
|
||||
//! If threading is enabled, you MUST make the receiver threadsafe if you plan to access it in your application while it is registered
|
||||
virtual bool registerLogReceiver(ILogReceiver* receiver, std::string name) = 0;
|
||||
virtual bool registerLogReceiver(ILogReceiver* receiver, const char* name) = 0;
|
||||
//!Unregister a Log Receiver
|
||||
//!Will NOT delete any user added receiver, you must do that yourself
|
||||
virtual void unRegisterLogReceiver(std::string name) = 0;
|
||||
virtual void unRegisterLogReceiver(const char* name) = 0;
|
||||
//!Returns whether an log receiver is currently registered
|
||||
virtual bool isLogReceiverRegistered(std::string name) = 0;
|
||||
virtual bool isLogReceiverRegistered(const char* name) = 0;
|
||||
//!Returns a registered log receiver
|
||||
virtual ILogReceiver* getLogReceiver(std::string name) = 0;
|
||||
virtual ILogReceiver* getLogReceiver(const char* name) = 0;
|
||||
protected:
|
||||
private:
|
||||
};
|
||||
|
|
|
@ -0,0 +1,188 @@
|
|||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="9.00"
|
||||
Name="Stress_Test"
|
||||
ProjectGUID="{0E491D8E-6B9E-4107-B50B-EC48CBA3203D}"
|
||||
RootNamespace="Stress_Test"
|
||||
TargetFrameworkVersion="196613"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="../../bin/win32-visual"
|
||||
IntermediateDirectory="obj/$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="2"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="3"
|
||||
WarningLevel="3"
|
||||
DebugInformationFormat="4"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="cAudio.lib"
|
||||
AdditionalLibraryDirectories=""..\..\bin\win32-visual""
|
||||
GenerateDebugInformation="true"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="../../bin/win32-visual"
|
||||
IntermediateDirectory="obj/$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="2"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="2"
|
||||
EnableIntrinsicFunctions="true"
|
||||
RuntimeLibrary="2"
|
||||
EnableFunctionLevelLinking="true"
|
||||
WarningLevel="3"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="cAudio.lib"
|
||||
AdditionalLibraryDirectories=""..\..\bin\win32-visual""
|
||||
GenerateDebugInformation="true"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<Filter
|
||||
Name="Source Files"
|
||||
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\main.cpp"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Header Files"
|
||||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
|
||||
>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Resource Files"
|
||||
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
|
||||
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
|
||||
>
|
||||
</Filter>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
|
@ -0,0 +1,147 @@
|
|||
//****************************************************************
|
||||
//cAudio 1.7.1 Stress Test
|
||||
//Used to push cAudio to its limits
|
||||
//****************************************************************
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <math.h>
|
||||
#include <time.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
//Include IAudioManager so we can easily work with cAudio
|
||||
#include "../../include/IAudioManager.h"
|
||||
//Include IAudio so we can create cAudio objects
|
||||
#include "../../include/IAudio.h"
|
||||
//Include The cAudio vector class
|
||||
#include "../../include/cVector3.h"
|
||||
//Include our version of Sleep to free CPU usage
|
||||
#include "../../include/cAudioSleep.h"
|
||||
//Include the logger interface
|
||||
#include "../../include/ILogger.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
#define MAXAUDIOSOURCES 128
|
||||
#define TESTDURATION 30
|
||||
|
||||
cAudio::IAudio* AudioSources[MAXAUDIOSOURCES];
|
||||
|
||||
inline float getRandomFloat(float fMin, float fMax)
|
||||
{
|
||||
float fUnit = float(rand( )) / RAND_MAX;
|
||||
float fDiff = fMax - fMin;
|
||||
|
||||
return fMin + fUnit * fDiff;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
//Some fancy text
|
||||
cout << "cAudio 1.7.1 Stress Test \n \n";
|
||||
srand(time(NULL));
|
||||
|
||||
unsigned int startTick = clock();
|
||||
|
||||
//Create an uninitialized Audio Manager
|
||||
cAudio::IAudioManager* manager = cAudio::createAudioManager(false);
|
||||
|
||||
//Limit the severity of log messages to just warnings, for best performance
|
||||
cAudio::getLogger()->setLogLevel(cAudio::ELL_WARNING);
|
||||
|
||||
if(manager)
|
||||
{
|
||||
//Allow the user to choose a playback device
|
||||
cout << "Available Playback Devices: \n";
|
||||
unsigned int deviceCount = manager->getAvailableDeviceCount();
|
||||
std::string defaultDeviceName = manager->getDefaultDeviceName();
|
||||
for(unsigned int i=0; i<deviceCount; ++i)
|
||||
{
|
||||
std::string deviceName = manager->getAvailableDeviceName(i);
|
||||
if(deviceName.compare(defaultDeviceName) == 0)
|
||||
cout << i << "): " << deviceName << " [DEFAULT] \n";
|
||||
else
|
||||
cout << i << "): " << deviceName << " \n";
|
||||
}
|
||||
cout << std::endl;
|
||||
cout << "Choose a device by number: ";
|
||||
unsigned int deviceSelection = 0;
|
||||
cin >> deviceSelection;
|
||||
cout << std::endl;
|
||||
|
||||
//Initialize the manager with the user settings
|
||||
manager->initialize(manager->getAvailableDeviceName(deviceSelection));
|
||||
|
||||
//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
|
||||
cAudio::IListener* listener = manager->getListener();
|
||||
|
||||
cout << "Creating " << MAXAUDIOSOURCES << " sources. \n";
|
||||
unsigned int startTick = clock();
|
||||
for(unsigned int i=0; i<MAXAUDIOSOURCES; ++i)
|
||||
{
|
||||
AudioSources[i] = manager->createFromFile("bling", "../../media/bling.ogg", false);
|
||||
}
|
||||
unsigned int endTick = clock();
|
||||
unsigned int elaspedTicks = endTick - startTick;
|
||||
cout << "Took " << (float)elaspedTicks/(float)CLOCKS_PER_SEC << " seconds. \n \n";
|
||||
|
||||
cout << "Telling " << MAXAUDIOSOURCES << " sources to play (in 3D). \n";
|
||||
startTick = clock();
|
||||
for(unsigned int i=0; i<MAXAUDIOSOURCES; ++i)
|
||||
{
|
||||
if(AudioSources[i])
|
||||
{
|
||||
AudioSources[i]->play3d(cAudio::cVector3(getRandomFloat(-100,100),getRandomFloat(-100,100),getRandomFloat(-100,100)),2.0f,true);
|
||||
AudioSources[i]->setMinDistance(10.0f);
|
||||
AudioSources[i]->setMaxDistance(200.0f);
|
||||
}
|
||||
}
|
||||
endTick = clock();
|
||||
elaspedTicks = endTick - startTick;
|
||||
cout << "Took " << (float)elaspedTicks/(float)CLOCKS_PER_SEC << " seconds. \n \n";
|
||||
|
||||
cout << "Playing and moving all sources (" << MAXAUDIOSOURCES << ") for " << TESTDURATION << " seconds. \n";
|
||||
unsigned int currentTick = clock();
|
||||
unsigned int currentCycle = 0;
|
||||
while(currentTick < (TESTDURATION*CLOCKS_PER_SEC))
|
||||
{
|
||||
for(unsigned int i=0; i<MAXAUDIOSOURCES; ++i)
|
||||
{
|
||||
if(AudioSources[i])
|
||||
{
|
||||
AudioSources[i]->move(AudioSources[i]->getPosition() + cAudio::cVector3(getRandomFloat(-10,10),getRandomFloat(-10,10),getRandomFloat(-10,10)));
|
||||
++currentCycle;
|
||||
}
|
||||
}
|
||||
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";
|
||||
|
||||
std::cout << std::endl;
|
||||
|
||||
cout << "Deleting " << MAXAUDIOSOURCES << " sources. \n";
|
||||
startTick = clock();
|
||||
//Delete all IAudio sounds
|
||||
manager->release();
|
||||
endTick = clock();
|
||||
elaspedTicks = endTick - startTick;
|
||||
cout << "Took " << (float)elaspedTicks/(float)CLOCKS_PER_SEC << " seconds. \n \n";
|
||||
|
||||
//Shutdown cAudio
|
||||
manager->shutDown();
|
||||
|
||||
cAudio::destroyAudioManager(manager);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "Failed to create audio playback manager. \n";
|
||||
}
|
||||
|
||||
std::cout << "Press any key to quit \n";
|
||||
std::cin.get();
|
||||
std::cin.get();
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue