diff --git a/Examples/Tutorial4_AudioCapture/Tutorial4_AudioCapture.vcproj b/Examples/Tutorial4_AudioCapture/Tutorial4_AudioCapture.vcproj new file mode 100644 index 0000000..6c10792 --- /dev/null +++ b/Examples/Tutorial4_AudioCapture/Tutorial4_AudioCapture.vcproj @@ -0,0 +1,186 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Examples/Tutorial4_AudioCapture/main.cpp b/Examples/Tutorial4_AudioCapture/main.cpp new file mode 100644 index 0000000..7d190fb --- /dev/null +++ b/Examples/Tutorial4_AudioCapture/main.cpp @@ -0,0 +1,103 @@ +#include +#include +//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" + +using namespace std; + +#define CAPTURE_FREQUENCY 22050 +#define CAPTURE_DURATION 10 +#define CAPTURE_FORMAT cAudio::EAF_16BIT_MONO + +int main(int argc, char* argv[]) +{ + //To make visual studio happy + cAudio::IAudio* mysound = NULL; + + //Some fancy text + cout << "cAudio 1.7.1 Tutorial 4: Capturing Audio \n \n"; + + std::string formatName; + + if(CAPTURE_FORMAT == cAudio::EAF_8BIT_MONO) + formatName = "8 Bit Mono"; + else if(CAPTURE_FORMAT == cAudio::EAF_8BIT_STEREO) + formatName = "8 Bit Stereo"; + else if(CAPTURE_FORMAT == cAudio::EAF_16BIT_MONO) + formatName = "16 Bit Mono"; + else + formatName = "16 Bit Stereo"; + + //Grap the cAudioManager + cAudio::IAudioManager* manager = cAudio::getAudioManager(); + //Init the cAudio Engine + manager->init(argc,argv); + + //! The capture interface should be grabbed after the manager has been initialized + cAudio::IAudioCapture* capture = manager->getAudioCapture(); + bool captureReady = false; + cout << "Capturing Supported: " << std::boolalpha << capture->isSupported() << "\n"; + if(capture->isSupported()) + { + captureReady = capture->initialize(CAPTURE_FREQUENCY, CAPTURE_FORMAT); + cout << "Ready to capture audio: " << std::boolalpha << captureReady << "\n \n"; + + //Quick math to figure out how large our data should be for the duration of the record time + const int targetRecordSize = CAPTURE_FREQUENCY * CAPTURE_DURATION * capture->getSampleSize(); + cout << "Capture Frequency: " << CAPTURE_FREQUENCY << "\n"; + cout << "Capture Duration: " << CAPTURE_DURATION << "\n"; + cout << "Capture Format: " << formatName << "\n"; + cout << "Sample Size: " << capture->getSampleSize() << "\n"; + cout << "Total size of audio: " << targetRecordSize << "\n"; + + cout << std::endl; + + int currentsize = 0; + cout << "Starting capture... \n"; + if(capture->beginCapture()) + { + while(currentsize < targetRecordSize) + { + currentsize = capture->getCurrentCapturedAudioSize(); + //Run the main update loop to keep audio data flowing in + manager->update(); + } + } + capture->stopCapture(); + cout << "Capture stopped... \n \n"; + + char* buffer = new char[currentsize]; + capture->getCapturedAudio(buffer, currentsize); + + //Create a IAudio object and load a sound from a file + mysound = manager->createFromRaw("sound1", buffer, currentsize, CAPTURE_FREQUENCY, CAPTURE_FORMAT); + + delete buffer; + + if(mysound) + { + cout << "Playing back captured audio... \n \n"; + mysound->setVolume(1.0); + //Set the IAudio Sound to play2d and loop + mysound->play2d(false); + + while(mysound->playing()) + { + //Playback sound + manager->update(); + } + } + } + + //Delete all IAudio sounds + manager->release(); + //Shutdown cAudio + manager->shutDown(); + + std::cout << "Press any key to quit \n"; + std::cin.get(); + + return 0; +} diff --git a/Headers/cAudio.h b/Headers/cAudio.h index 165f52f..9cfa62f 100644 --- a/Headers/cAudio.h +++ b/Headers/cAudio.h @@ -19,11 +19,12 @@ namespace cAudio void play2d(bool loop = false); //!plays the audio file and sets it to 3d void play3d(bool loop = false, float x = 0.0, float y = 0.0, float z = 0.0, float soundstr = 1.0); + //!allows us to set the position or reset the position void setPosition(float posx,float posy,float posz); //!allows you to set the audio objects velocity void setVelocity(float velx,float vely,float velz); - //!allows us to set the direction the audio should play in / move + //!allows us to set the direction the audio should play in void setDirection(float dirx,float diry,float dirz); //! Sets the audios pitch level void setPitch(float pitch); @@ -35,6 +36,7 @@ namespace cAudio void setDopplerStrength(float doop); //!Set doppler velocity void setDopplerVelocity(float doopx,float doopy,float doopz); + //!Seek the audio stream void seek(float secs); //!release the file handle diff --git a/Headers/cAudioCapture.h b/Headers/cAudioCapture.h new file mode 100644 index 0000000..d639024 --- /dev/null +++ b/Headers/cAudioCapture.h @@ -0,0 +1,93 @@ +#ifndef CAUDIOCAPTURE_H +#define CAUDIOCAPTURE_H + +#include "../include/IAudioCapture.h" +#include +#include +#include + +namespace cAudio +{ + class cAudioCapture : public IAudioCapture + { + public: + cAudioCapture(); + ~cAudioCapture(); + + //! Checks to see if capturing audio is supported by OpenAL + //! Normally run automatically by cAudioManager::init() + bool checkCaptureExtension(); + + //! Grabs samples from the OpenAL buffer into the capture buffer. Should be run once every audio frame. + //! Normally run automatically by cAudioManager::update() + void updateCaptureBuffer(bool force = false); + + //! Shuts down the capture device + //! Normally run automatically by cAudioManager::shutDown() + void shutdown(); + + //! Initializes the capture device to the selected settings + /** Note that calling this will cause the capture device to be reinitialized. Calling while in use may lead to a loss of audio data. + \param frequency: Frequency that the captured audio will be at + \param format: Format of the captured audio + \param internalBufferSize: Size of the internal OpenAL buffer used to store the captured audio until the next IAudioManager::update() in bytes + \return True on success, False if the capture device failed to initialize. + */ + virtual bool initialize(unsigned int frequency = 22050, AudioFormats format = EAF_16BIT_MONO, unsigned int internalBufferSize = 8192); + //! Returns true if the current OpenAL implementation supports capturing audio + virtual bool isSupported() { return Supported; } + //! Returns true if the capture device is ready to be used. False may indicate an error with the current settings. + virtual bool isReady() { return Ready; } + + //! Returns the frequency that the captured audio will be at + virtual unsigned int getFrequency() { return Frequency; } + //! Returns the format of the captured audio + virtual AudioFormats getFormat() { return Format; } + //! Returns the internal OpenAL buffer size in bytes + virtual unsigned int getInternalBufferSize() { return InternalBufferSize; } + //! Returns the size of a "sample" of audio data. Useful for making sure you grab audio data at sample boundaries + virtual unsigned int getSampleSize() { return SampleSize; } + + //! Sets the frequency that the captured audio will be at. Will cause the capture device to be reinitialized. Calling while in use may lead to a loss of audio data. + /** \return True on success, False if the capture device failed to initialize. */ + virtual bool setFrequency(unsigned int frequency); + //! Sets the format that the captured audio will be at. Will cause the capture device to be reinitialized. Calling while in use may lead to a loss of audio data. + /** \return True on success, False if the capture device failed to initialize. */ + virtual bool setFormat(AudioFormats format); + //! Sets the internal buffer size that OpenAL will use to store captured audio between calls to IAudioManager::update() in bytes. Will cause the capture device to be reinitialized. Calling while in use may lead to a loss of audio data. + /** \return True on success, False if the capture device failed to initialize. */ + virtual bool setInternalBufferSize(unsigned int internalBufferSize); + + //! Starts capturing audio data to an internal buffer. Will clear any old data in the buffer. + /** \return True if capture was successfully started. */ + virtual bool beginCapture(); + //! Stops capturing audio data to an internal buffer. Will copy any remaining audio data to the capture buffer. + virtual void stopCapture(); + //! Allows access to the audio data in the internal capture buffer + /** Can be called at any time to retrieve recorded audio. It is recommended that you call it every so often to prevent the internal buffer from growing too large. + Once successfully retrieved, the captured audio will be deleted from the internal buffer. + \param outputBuffer: Pointer to an output array to copy audio data to. + \param outputBufferSize: Size of the output array in bytes + */ + virtual void getCapturedAudio(void* outputBuffer, unsigned int outputBufferSize); + + //! Returns the current size of the internal audio buffer in bytes + virtual unsigned int getCurrentCapturedAudioSize(); + protected: + bool initOpenALDevice(); + void shutdownOpenALDevice(); + + unsigned int Frequency; + AudioFormats Format; + unsigned int InternalBufferSize; + std::vector CaptureBuffer; + bool Supported; + bool Ready; + bool Capturing; + int SampleSize; + + ALCdevice* CaptureDevice; + }; +}; + +#endif //! CAUDIOCAPTURE_H \ No newline at end of file diff --git a/Headers/cAudioManager.h b/Headers/cAudioManager.h index f0fdd8a..ad8b158 100644 --- a/Headers/cAudioManager.h +++ b/Headers/cAudioManager.h @@ -6,6 +6,7 @@ #include "cAudio.h" #include "../include/IAudioDecoderFactory.h" #include "cListener.h" +#include "cAudioCapture.h" #include "../include/IAudioManager.h" namespace cAudio @@ -16,27 +17,40 @@ namespace cAudio { public: //!Inits the audio manager calling the alut/etc start ups - void init(int argc,char* argv[]); + virtual void init(int argc,char* argv[]); //!Shuts everything down - void shutDown(); + virtual void shutDown(); //!Creates the cAudio object - IAudio* createFromFile(const std::string& identifier,const std::string& file,bool stream = false); + virtual IAudio* createFromFile(const std::string& identifier,const std::string& file,bool stream = false); //!Loads ogg from memory or virtual file system - IAudio* createFromMemory(const std::string& identifier, const char* data, size_t length, std::string ext); + virtual IAudio* createFromMemory(const std::string& identifier, const char* data, size_t length, std::string ext); + //!Loads raw audio from memory. + virtual IAudio* createFromRaw(const std::string& identifier,const char* data, size_t length, unsigned int frequency, AudioFormats format); + //!Register Audio Codec - void registerAudioDecoder(IAudioDecoderFactory* factory, std::string extension); + virtual bool registerAudioDecoder(IAudioDecoderFactory* factory, std::string 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 delete the factory instance + virtual void unRegisterAudioDecoder(std::string extension); + //!Returns whether an audio decoder is currently registered for this file type + virtual bool isAudioDecoderRegistered(std::string extension); + //!Returns a registered audio decoder factory + virtual IAudioDecoderFactory* getAudioDecoderFactory(std::string extension); + //!Allows you to set the listener position (DEPRECIATED! USE getListener() INSTEAD!) - void setListenerPos(float x,float y,float z); + virtual void setListenerPos(float x,float y,float z); //!Set Listener Orientation (DEPRECIATED! USE getListener() INSTEAD!) - void setListenerOrientation(float ux,float uy,float uz); + virtual void setListenerOrientation(float ux,float uy,float uz); //!Updates the cAudio playback - void update(); + virtual void update(); //!Gets you the cAudio object you want - IAudio *getSound(std::string identifier); + virtual IAudio *getSound(std::string identifier); //!Releases "ALL" cAudio objects - void release(); + virtual void release(); virtual IListener* getListener() { return &initlistener; } + virtual IAudioCapture* getAudioCapture() { return &initCapture; } static cAudioManager* Instance() { @@ -55,6 +69,8 @@ namespace cAudio std::map decodermap; //!The listener object cListener initlistener; + //!The audio capture instance + cAudioCapture initCapture; }; } diff --git a/Headers/cRawAudioDecoderFactory.h b/Headers/cRawAudioDecoderFactory.h new file mode 100644 index 0000000..4c156a3 --- /dev/null +++ b/Headers/cRawAudioDecoderFactory.h @@ -0,0 +1,32 @@ +#ifndef CRAWAUDIODECODERFACOTRY_H_INCLUDED +#define CRAWAUDIODECODERFACOTRY_H_INCLUDED + +#include "../include/IAudioDecoderFactory.h" +#include "cRawDecoder.h" + + +namespace cAudio +{ + +class cRawAudioDecoderFactory : public IAudioDecoderFactory +{ + public: + cRawAudioDecoderFactory() {} + ~cRawAudioDecoderFactory() {} + + IAudioDecoder* CreateAudioDecoder(IDataSource* stream) + { + return new cRawDecoder(stream, 22050, EAF_16BIT_MONO); + } + + IAudioDecoder* CreateAudioDecoder(IDataSource* stream, unsigned int frequency = 22050, AudioFormats format = EAF_16BIT_MONO) + { + return new cRawDecoder(stream, frequency, format); + } + protected: + private: +}; + +}; + +#endif //! CRAWAUDIODECODERFACOTRY_H_INCLUDED diff --git a/Headers/cRawDecoder.h b/Headers/cRawDecoder.h new file mode 100644 index 0000000..7624bf1 --- /dev/null +++ b/Headers/cRawDecoder.h @@ -0,0 +1,41 @@ +#ifndef CRAWDECODER_H_INCLUDED +#define CRAWDECODER_H_INCLUDED + +#include "../include/IAudioDecoder.h" + +namespace cAudio +{ + + class cRawDecoder : public IAudioDecoder + { + public: + + cRawDecoder(IDataSource* stream, unsigned int frequency, AudioFormats format); + ~cRawDecoder(); + + //!Retruns the format of the audio data + virtual AudioFormats getFormat(); + + //!Returns the frequency of the audio data + virtual int getFrequency(); + + //!Returns whether seeking is supported + virtual bool isSeekingSupported(); + + //!Reads a section of data out of the audio stream + virtual int readAudioData(void* output, int amount); + + //!Sets the position to read data out of + virtual bool setPosition(int position, bool relative); + + //!If seeking is supported, will seek the stream to seconds + virtual bool seek(float seconds,bool relative); + + private: + unsigned int Frequency; + AudioFormats Format; + }; + +} + +#endif //! CRAWDECODER_H_INCLUDED \ No newline at end of file diff --git a/Source/cAudio.cpp b/Source/cAudio.cpp index 3255325..d61d1e2 100644 --- a/Source/cAudio.cpp +++ b/Source/cAudio.cpp @@ -27,13 +27,13 @@ namespace cAudio //!Stops all playing sound sources and deletes the sources and buffers void cAudio::release() { - //Stops the audio source - alSourceStop(source); - empty(); - //Deletes the source - alDeleteSources(1, &source); - //deletes the last filled buffer - alDeleteBuffers(3, buffers); + //Stops the audio source + alSourceStop(source); + empty(); + //Deletes the source + alDeleteSources(1, &source); + //deletes the last filled buffer + alDeleteBuffers(3, buffers); } //!Plays back sound source @@ -69,10 +69,10 @@ namespace cAudio int processed = 0; bool active = true; - //gets the sound source processed buffers/ + //gets the sound source processed buffers/ alGetSourcei(source, AL_BUFFERS_PROCESSED, &processed); - //while there is more data refill buffers with audio data. - while (processed--) + //while there is more data refill buffers with audio data. + while (processed--) { ALuint buffer; @@ -80,13 +80,11 @@ namespace cAudio active = stream(buffer); - //if more in stream continue playing. + //if more in stream continue playing. if(active) alSourceQueueBuffers(source, 1, &buffer); - } - return active; - + return active; } //!The streaming function @@ -95,58 +93,56 @@ namespace cAudio if(Decoder) { //stores the caculated data into buffer that is passed to output. - size_t totalread = 0; + size_t totalread = 0; char tempbuffer[BUFFER_SIZE]; - while( totalread < BUFFER_SIZE ) - { - char tempbuffer2[BUFFER_SIZE]; - int actualread = Decoder->readAudioData(tempbuffer2, BUFFER_SIZE-totalread); - if(actualread > 0) + while( totalread < BUFFER_SIZE ) { - memcpy(tempbuffer+totalread,tempbuffer2,actualread); - totalread += actualread; - } - if(actualread < 0) - { - break; - } - if(actualread == 0) - { - if(toloop) + char tempbuffer2[BUFFER_SIZE]; + int actualread = Decoder->readAudioData(tempbuffer2, BUFFER_SIZE-totalread); + if(actualread > 0) { - //If we are to loop, set to the beginning and reload from the start - Decoder->setPosition(0,false); + memcpy(tempbuffer+totalread,tempbuffer2,actualread); + totalread += actualread; } - else + if(actualread < 0) + { break; - } + } + if(actualread == 0) + { + if(toloop) + { + //If we are to loop, set to the beginning and reload from the start + Decoder->setPosition(0,false); + } + else + break; + } } - //Second check, in case looping is not enabled, we will return false for end of stream - if(totalread == 0) - { - return false; - } + //Second check, in case looping is not enabled, we will return false for end of stream + if(totalread == 0) + { + return false; + } //std::cout << buffer << std::endl; - - alBufferData(buffer, Decoder->getFormat(), tempbuffer, totalread, Decoder->getFrequency()); - - return true; - } - return false; + alBufferData(buffer, Decoder->getFormat(), tempbuffer, totalread, Decoder->getFrequency()); + return true; + } + return false; } //!clears the sound sources buffers and makes them free to be used by other sound sources. void cAudio::empty() { int queued = 0; - //grabs allt he sources buffers. + //grabs allt he sources buffers. alGetSourcei(source, AL_BUFFERS_QUEUED, &queued); while (queued--) { ALuint buffer; - //unqueues sources buffers to be used for others. + //unqueues sources buffers to be used for others. alSourceUnqueueBuffers(source, 1, &buffer); } } @@ -158,16 +154,14 @@ namespace cAudio if (error != AL_NO_ERROR) { - std::cout<<"OpenAL error was Raised."; + std::cout<< "OpenAL error was Raised."; } } //!checks to see if the given ogg file is valid bool cAudio::isvalid() { - return (Decoder != 0); - } //!Sets the sound source relativity to follow the listener to give the illusion of stereo 2d sound @@ -176,14 +170,14 @@ namespace cAudio alSourcei (source, AL_SOURCE_RELATIVE, true); toloop = loop; play(); - alSourcePlay(source); + alSourcePlay(source); } //!Plays the given audio file with 3d position void cAudio::play3d(bool loop, float x, float y, float z,float soundstr) { alSourcei (source, AL_SOURCE_RELATIVE, false); - alSource3f(source, AL_POSITION,x, y, z); + alSource3f(source, AL_POSITION, x, y, z); alSourcef (source, AL_ROLLOFF_FACTOR, soundstr); toloop = loop; play(); @@ -199,49 +193,49 @@ namespace cAudio //!Used to move the audio sources position after the initial creation void cAudio::setPosition(float posx,float posy,float posz) { - alSource3f(source, AL_POSITION,posx, posy, posz); + alSource3f(source, AL_POSITION, posx, posy, posz); } //!Used to set the velocity of the audio source. void cAudio::setVelocity(float velx,float vely, float velz) { - alSource3f(source, AL_VELOCITY,velx, vely, velz); + alSource3f(source, AL_VELOCITY, velx, vely, velz); } //!Used to set the direction of the audio source void cAudio::setDirection(float dirx,float diry,float dirz) { - alSource3f(source, AL_DIRECTION,dirx, diry, dirz); + alSource3f(source, AL_DIRECTION, dirx, diry, dirz); } //!Used to set the sound strength or roll off factor void cAudio::setStrength(float soundstrength) { - alSourcef (source, AL_ROLLOFF_FACTOR, soundstrength); + alSourcef(source, AL_ROLLOFF_FACTOR, soundstrength); } //!Used to set the pitch of the audio file void cAudio::setPitch(float pitch) { - alSourcef (source, AL_PITCH,pitch); + alSourcef (source, AL_PITCH, pitch); } //!Used to set the volume of the audio source void cAudio::setVolume(float volume) { - alSourcef(source,AL_GAIN,volume); + alSourcef(source, AL_GAIN, volume); } //!Used to set the doppler strength of the audio sources doppler effect void cAudio::setDopplerStrength(float doop) { - alSourcef(source,AL_DOPPLER_FACTOR,doop); + alSourcef(source, AL_DOPPLER_FACTOR, doop); } //!Used to set the doppler velocity of the audio source void cAudio::setDopplerVelocity(float doopx,float doopy,float doopz) { - alSource3f(source,AL_DOPPLER_VELOCITY,doopx,doopy,doopz); + alSource3f(source, AL_DOPPLER_VELOCITY, doopx, doopy, doopz); } //!Allows us to seek through a stream @@ -257,13 +251,12 @@ namespace cAudio bool cAudio::play() { playaudio = true; - if (!this->paused()) + if (!paused()) { int queueSize = 0; - for(int u = 0; u < 3; u++) { - int val = this->stream(buffers[u]); + int val = stream(buffers[u]); if(val < 0) { @@ -272,17 +265,13 @@ namespace cAudio else if(val > 0) ++queueSize; } - //Stores the sources 3 buffers to be used in the queue alSourceQueueBuffers(source, queueSize, buffers); - } - + } alSourcePlay(source); - return true; } - //!Used to stop the audio source void cAudio::stop() { diff --git a/Source/cAudioCapture.cpp b/Source/cAudioCapture.cpp new file mode 100644 index 0000000..d6a948c --- /dev/null +++ b/Source/cAudioCapture.cpp @@ -0,0 +1,177 @@ +#include "../Headers/cAudioCapture.h" +#include + +namespace cAudio +{ + cAudioCapture::cAudioCapture() : Frequency(22050), Format(EAF_16BIT_MONO), InternalBufferSize(8192), + Supported(false), Ready(false), Capturing(false), SampleSize(2), CaptureDevice(NULL) + { + + } + cAudioCapture::~cAudioCapture() + { + + } + + bool cAudioCapture::checkCaptureExtension() + { + // Check for Capture Extension support + ALCdevice* pDevice; + ALCcontext* pContext; + pContext = alcGetCurrentContext(); + pDevice = alcGetContextsDevice(pContext); + Supported = ( alcIsExtensionPresent(pDevice, "ALC_EXT_CAPTURE") == AL_TRUE ); + return Supported; + } + + bool cAudioCapture::initOpenALDevice() + { + if(Supported) + { + if(CaptureDevice) + shutdownOpenALDevice(); + + CaptureDevice = alcCaptureOpenDevice(NULL, Frequency, Format, InternalBufferSize / SampleSize); + if(CaptureDevice) + { + Ready = true; + return true; + } + } + return false; + } + + void cAudioCapture::shutdownOpenALDevice() + { + if(Supported) + { + if(Capturing) + stopCapture(); + + if(CaptureDevice) + { + alcCaptureCloseDevice(CaptureDevice); + CaptureDevice = NULL; + Ready = false; + } + } + } + + void cAudioCapture::shutdown() + { + shutdownOpenALDevice(); + } + + void cAudioCapture::updateCaptureBuffer(bool force) + { + if(Capturing && CaptureDevice && Ready) + { + int AvailableSamples = 0; + alcGetIntegerv(CaptureDevice, ALC_CAPTURE_SAMPLES, 1, &AvailableSamples); + const unsigned int availbuffersize = AvailableSamples * SampleSize; + + //If the samples in the OpenAL buffer are more than half of its max size, grab them + if(availbuffersize > InternalBufferSize / 2 || force) + { + //Fixes a bug with the capture being forced, but no data being available + if(availbuffersize > 0) + { + const int oldBufferSize = CaptureBuffer.size(); + CaptureBuffer.resize(oldBufferSize + availbuffersize, 0); + alcCaptureSamples(CaptureDevice, &CaptureBuffer[oldBufferSize], AvailableSamples); + } + } + } + } + + bool cAudioCapture::beginCapture() + { + if(!Capturing) + { + CaptureBuffer.clear(); + if(CaptureDevice && Ready) + { + alcCaptureStart(CaptureDevice); + Capturing = true; + } + return Capturing; + } + else + return false; + } + + void cAudioCapture::stopCapture() + { + if(CaptureDevice && Ready) + { + alcCaptureStop(CaptureDevice); + updateCaptureBuffer(true); + } + Capturing = false; + } + + void cAudioCapture::getCapturedAudio(void* outputBuffer, unsigned int outputBufferSize) + { + if(outputBuffer && outputBufferSize > 0) + { + int sizeToCopy = (outputBufferSize >= CaptureBuffer.size()) ? CaptureBuffer.size() : outputBufferSize; + memcpy(outputBuffer, &CaptureBuffer[0], sizeToCopy); + CaptureBuffer.erase(CaptureBuffer.begin(), CaptureBuffer.begin()+sizeToCopy); + } + } + + unsigned int cAudioCapture::getCurrentCapturedAudioSize() + { + return CaptureBuffer.size(); + } + + bool cAudioCapture::setFrequency(unsigned int frequency) + { + Frequency = frequency; + shutdownOpenALDevice(); + return initOpenALDevice(); + } + + bool cAudioCapture::setFormat(AudioFormats format) + { + Format = format; + 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; + + shutdownOpenALDevice(); + return initOpenALDevice(); + } + + bool cAudioCapture::setInternalBufferSize(unsigned int internalBufferSize) + { + InternalBufferSize = internalBufferSize; + + shutdownOpenALDevice(); + return initOpenALDevice(); + } + + bool cAudioCapture::initialize(unsigned int frequency, AudioFormats format, unsigned int internalBufferSize) + { + Frequency = frequency; + InternalBufferSize = internalBufferSize; + + Format = format; + 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; + + shutdownOpenALDevice(); + return initOpenALDevice(); + } +}; diff --git a/Source/cAudioManager.cpp b/Source/cAudioManager.cpp index 7c5a53d..e3ad8ab 100644 --- a/Source/cAudioManager.cpp +++ b/Source/cAudioManager.cpp @@ -4,8 +4,10 @@ #include "../Headers/cUtils.h" #include "../Headers/cOggAudioDecoderFactory.h" #include "../Headers/cWavAudioDecoderFacotry.h" +#include "../Headers/cRawAudioDecoderFactory.h" #include +#include #include //!#include //!#include @@ -24,6 +26,7 @@ namespace cAudio void cAudioManager::init(int argc,char* argv[]) { alutInit(&argc,argv); + /* ALCcontext *Context; ALCdevice *Device; @@ -64,8 +67,12 @@ namespace cAudio LOAD_AL_FUNC(alIsEffect); */ + initCapture.checkCaptureExtension(); + initCapture.initialize(); + registerAudioDecoder(new cOggAudioDecoderFactory, "ogg"); registerAudioDecoder(new cWavAudioDecoderFactory, "wav"); + registerAudioDecoder(new cRawAudioDecoderFactory, "raw"); } //!create a sound source @@ -76,13 +83,13 @@ namespace cAudio if(source->isValid()) { std::string ext = getExt(file); - std::map::iterator it = decodermap.find(ext); - if(it == decodermap.end()) - { + IAudioDecoderFactory* factory = getAudioDecoderFactory(ext); + if(!factory) + { delete source; return NULL; } - IAudioDecoder* decoder = it->second->CreateAudioDecoder(source); + IAudioDecoder* decoder = factory->CreateAudioDecoder(source); IAudio* audio = new cAudio(decoder); audiomap[identifier] = audio; return audio; @@ -113,13 +120,13 @@ namespace cAudio cMemorySource* source = new cMemorySource(data,length,true); if(source->isValid()) { - std::map::iterator it = decodermap.find(ext); - if(it == decodermap.end()) + IAudioDecoderFactory* factory = getAudioDecoderFactory(ext); + if(!factory) { delete source; return NULL; } - IAudioDecoder* decoder = it->second->CreateAudioDecoder(source); + IAudioDecoder* decoder = factory->CreateAudioDecoder(source); IAudio* audio = new cAudio(decoder); audiomap[identifier] = audio; return audio; @@ -131,11 +138,61 @@ namespace cAudio } } - void cAudioManager::registerAudioDecoder(IAudioDecoderFactory* factory, std::string extension) + IAudio* cAudioManager::createFromRaw(const std::string& identifier,const char* data, size_t length, unsigned int frequency, AudioFormats format) + { + cMemorySource* source = new cMemorySource(data,length,true); + if(source->isValid()) + { + IAudioDecoderFactory* factory = getAudioDecoderFactory("raw"); + if(!factory) + { + delete source; + return NULL; + } + IAudioDecoder* decoder = ((cRawAudioDecoderFactory*)factory)->CreateAudioDecoder(source, frequency, format); + IAudio* audio = new cAudio(decoder); + audiomap[identifier] = audio; + return audio; + } + else + { + delete source; + return NULL; + } + } + + bool cAudioManager::registerAudioDecoder(IAudioDecoderFactory* factory, std::string extension) { decodermap[extension] = factory; + return true; } + void cAudioManager::unRegisterAudioDecoder(std::string extension) + { + std::map::iterator it = decodermap.find(extension); + if(it != decodermap.end()) + { + delete it->second; + decodermap.erase(it); + } + } + + bool cAudioManager::isAudioDecoderRegistered(std::string extension) + { + std::map::iterator it = decodermap.find(extension); + return (it != decodermap.end()); + } + + IAudioDecoderFactory* cAudioManager::getAudioDecoderFactory(std::string extension) + { + std::map::iterator it = decodermap.find(extension); + if(it != decodermap.end()) + { + return it->second; + } + return NULL; + } + //!grabs the selected audio file via the identifier IAudio *cAudioManager::getSound(std::string identifier) { @@ -177,17 +234,19 @@ namespace cAudio { } - if (i->second->playback()) + /*if (i->second->playback()) { - } + }*/ } } + initCapture.updateCaptureBuffer(); } //!Shuts down cAudio. Deletes all audio sources in process void cAudioManager::shutDown() { + initCapture.shutdown(); alutExit(); } diff --git a/Source/cRawDecoder.cpp b/Source/cRawDecoder.cpp new file mode 100644 index 0000000..0798c42 --- /dev/null +++ b/Source/cRawDecoder.cpp @@ -0,0 +1,53 @@ +#include "../Headers/cRawDecoder.h" + +namespace cAudio{ + + cRawDecoder::cRawDecoder(IDataSource* stream, unsigned int frequency, AudioFormats format) : IAudioDecoder(stream), Frequency(frequency), Format(format) + { + + } + + cRawDecoder::~cRawDecoder() + { + + } + + //!Returns wav channel format + AudioFormats cRawDecoder::getFormat() + { + return Format; + } + + //!Returns wav data frequency + int cRawDecoder::getFrequency() + { + return Frequency; + } + + //!Returns if seeking is supported + bool cRawDecoder::isSeekingSupported() + { + return false; + } + + //!Reads wav data + int cRawDecoder::readAudioData(void* output, int amount) + { + return Stream->read(output,amount); + } + + //!Sets data reader position + bool cRawDecoder::setPosition(int position, bool relative) + { + Stream->seek(position,relative); + return true; + } + + //!Seeks wav data + bool cRawDecoder::seek(float seconds,bool relative) + { + return false; + } + + +} diff --git a/Source/cwavdecoder.cpp b/Source/cwavdecoder.cpp index 3f387ad..c88f359 100644 --- a/Source/cwavdecoder.cpp +++ b/Source/cwavdecoder.cpp @@ -67,6 +67,10 @@ namespace cAudio{ //!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; + Stream->seek(position,relative); return true; } diff --git a/cAudio.sln b/cAudio.sln index 4c04313..aee351c 100644 --- a/cAudio.sln +++ b/cAudio.sln @@ -9,6 +9,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Tutorial2_3DSound", "Exampl EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Tutorial3_MemoryPlayback", "Examples\Tutorial3_MemoryPlayback\Tutorial3_MemoryPlayback.vcproj", "{FEA3B340-BBB2-4AFB-AF31-3962A0F3F2C6}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Tutorial4_AudioCapture", "Examples\Tutorial4_AudioCapture\Tutorial4_AudioCapture.vcproj", "{F04BE31E-E8CC-40C8-9C63-EEAE1BF84EB7}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -31,6 +33,10 @@ Global {FEA3B340-BBB2-4AFB-AF31-3962A0F3F2C6}.Debug|Win32.Build.0 = Debug|Win32 {FEA3B340-BBB2-4AFB-AF31-3962A0F3F2C6}.Release|Win32.ActiveCfg = Release|Win32 {FEA3B340-BBB2-4AFB-AF31-3962A0F3F2C6}.Release|Win32.Build.0 = Release|Win32 + {F04BE31E-E8CC-40C8-9C63-EEAE1BF84EB7}.Debug|Win32.ActiveCfg = Debug|Win32 + {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 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/cAudio.vcproj b/cAudio.vcproj index 5354212..0f4b50e 100644 --- a/cAudio.vcproj +++ b/cAudio.vcproj @@ -178,6 +178,10 @@ RelativePath=".\Headers\cAudio.h" > + + @@ -202,12 +206,20 @@ RelativePath=".\Headers\cOggDecoder.h" > + + + + + + + + @@ -258,6 +278,10 @@ RelativePath=".\Source\cAudio.cpp" > + + @@ -282,6 +306,10 @@ RelativePath=".\Source\cOggDecoder.cpp" > + + diff --git a/include/IAudio.h b/include/IAudio.h index 3f590da..6d6f792 100644 --- a/include/IAudio.h +++ b/include/IAudio.h @@ -21,7 +21,7 @@ namespace cAudio virtual void setPosition(float posx,float posy,float posz) = 0; //!allows you to set the audio objects velocity virtual void setVelocity(float velx,float vely,float velz) = 0; - //!allows us to set the direction the audio should play in / move + //!allows us to set the direction the audio should play in virtual void setDirection(float dirx,float diry,float dirz) = 0; //! Sets the audios pitch level virtual void setPitch(float pitch) = 0; diff --git a/include/IAudioCapture.h b/include/IAudioCapture.h new file mode 100644 index 0000000..d799813 --- /dev/null +++ b/include/IAudioCapture.h @@ -0,0 +1,62 @@ +#ifndef IAUDIOCAPTURE_H +#define IAUDIOCAPTURE_H + +#include "eAudioFormats.h" + +namespace cAudio +{ + class IAudioCapture + { + public: + //! Initializes the capture device to the selected settings + /** Note that calling this will cause the capture device to be reinitialized. Calling while in use may lead to a loss of audio data. + \param frequency: Frequency that the captured audio will be at + \param format: Format of the captured audio + \param internalBufferSize: Size of the internal OpenAL buffer used to store the captured audio until the next IAudioManager::update() in bytes + \return True on success, False if the capture device failed to initialize. + */ + virtual bool initialize(unsigned int frequency = 22050, AudioFormats format = EAF_16BIT_MONO, unsigned int internalBufferSize = 8192) = 0; + //! Returns true if the current OpenAL implementation supports capturing audio + virtual bool isSupported() = 0; + //! Returns true if the capture device is ready to be used. False may indicate an error with the current settings. + virtual bool isReady() = 0; + + //! Returns the frequency that the captured audio will be at + virtual unsigned int getFrequency() = 0; + //! Returns the format of the captured audio + virtual AudioFormats getFormat() = 0; + //! Returns the internal OpenAL buffer size in bytes + virtual unsigned int getInternalBufferSize() = 0; + //! Returns the size of a "sample" of audio data. Useful for making sure you grab audio data at sample boundaries + virtual unsigned int getSampleSize() = 0; + + //! Sets the frequency that the captured audio will be at. Will cause the capture device to be reinitialized. Calling while in use may lead to a loss of audio data. + /** \return True on success, False if the capture device failed to initialize. */ + virtual bool setFrequency(unsigned int frequency) = 0; + //! Sets the format that the captured audio will be at. Will cause the capture device to be reinitialized. Calling while in use may lead to a loss of audio data. + /** \return True on success, False if the capture device failed to initialize. */ + virtual bool setFormat(AudioFormats format) = 0; + //! Sets the internal buffer size that OpenAL will use to store captured audio between calls to IAudioManager::update() in bytes. Will cause the capture device to be reinitialized. Calling while in use may lead to a loss of audio data. + /** \return True on success, False if the capture device failed to initialize. */ + virtual bool setInternalBufferSize(unsigned int internalBufferSize) = 0; + + //! Starts capturing audio data to an internal buffer. Will clear any old data in the buffer. + /** \return True if capture was successfully started. */ + virtual bool beginCapture() = 0; + //! Stops capturing audio data to an internal buffer. + virtual void stopCapture() = 0; + //! Allows access to the audio data in the internal capture buffer + /** Can be called at any time to retrieve recorded audio. It is recommended that you call it every so often to prevent the internal buffer from growing too large. + Once successfully retrieved, the captured audio will be deleted from the internal buffer. + \param outputBuffer: Pointer to an output array to copy audio data to. + \param outputBufferSize: Size of the output array in bytes + */ + virtual void getCapturedAudio(void* outputBuffer, unsigned int outputBufferSize) = 0; + + //! Returns the current size of the internal audio buffer in bytes + virtual unsigned int getCurrentCapturedAudioSize() = 0; + protected: + }; +}; + +#endif //! IAUDIOCAPTURE_H \ No newline at end of file diff --git a/include/IAudioDecoder.h b/include/IAudioDecoder.h index 32a8c11..b7305ba 100644 --- a/include/IAudioDecoder.h +++ b/include/IAudioDecoder.h @@ -2,19 +2,11 @@ #define IAUDIODECODER_H #include "IDataSource.h" +#include "eAudioFormats.h" namespace cAudio { -enum AudioFormats -{ - EAF_8BIT_MONO = 0x1100, - EAF_8BIT_STEREO = 0x1102, - EAF_16BIT_MONO = 0x1101, - EAF_16BIT_STEREO = 0x1103, - EAF_COUNT -}; - class IAudioDecoder { public: diff --git a/include/IAudioManager.h b/include/IAudioManager.h index 8779701..64eb3d5 100644 --- a/include/IAudioManager.h +++ b/include/IAudioManager.h @@ -3,6 +3,7 @@ #define IAUDIOMANAGER_H #include #include "IListener.h" +#include "IAudioCapture.h" #ifndef CAUDIO_STATIC_LIB @@ -28,24 +29,39 @@ namespace cAudio virtual void init(int argc,char* argv[]) = 0; //!Shuts everything down virtual void shutDown() = 0; + //!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; + //!Releases "ALL" cAudio objects (but does not shutdown the manager) + virtual void release() = 0; + //!Creates the cAudio object virtual IAudio* createFromFile(const std::string& identifier,const std::string& file,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; - //!Register Audio Codec - virtual void registerAudioDecoder(IAudioDecoderFactory* factory, std::string extension) = 0; - //!Allows you to set the listener position - virtual void setListenerPos(float x,float y,float z) = 0; - //!set the listeners orientation - virtual void setListenerOrientation(float ux,float uy,float uz) = 0; - //!Updates the cAudio playback - virtual void update() = 0; - //!Gets you the cAudio object you want - virtual IAudio *getSound(std::string identifier) = 0; - //!Releases "ALL" cAudio objects - virtual void release() = 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; + //!Register Audio Codec + virtual bool registerAudioDecoder(IAudioDecoderFactory* factory, std::string 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. + virtual void unRegisterAudioDecoder(std::string extension) = 0; + //!Returns whether an audio decoder is currently registered for this file type + virtual bool isAudioDecoderRegistered(std::string extension) = 0; + //!Returns a registered audio decoder factory + virtual IAudioDecoderFactory* getAudioDecoderFactory(std::string extension) = 0; + + //!Allows you to set the listener position (DEPRECIATED! USE getListener() INSTEAD!) + virtual void setListenerPos(float x,float y,float z) = 0; + //!set the listeners orientation (DEPRECIATED! USE getListener() INSTEAD!) + virtual void setListenerOrientation(float ux,float uy,float uz) = 0; + + //!Returns an interface for the listener virtual IListener* getListener() = 0; + //!Returns an interface for audio capture + virtual IAudioCapture* getAudioCapture() = 0; virtual ~IAudioManager() {} protected: diff --git a/include/IListener.h b/include/IListener.h index 20e0da3..74b24b3 100644 --- a/include/IListener.h +++ b/include/IListener.h @@ -2,7 +2,7 @@ #ifndef ILISTENER_H #define ILISTENER_H -#include "../Headers/cVector3.h" +#include "cVector3.h" namespace cAudio { diff --git a/Headers/cVector3.h b/include/cVector3.h similarity index 100% rename from Headers/cVector3.h rename to include/cVector3.h diff --git a/include/eAudioFormats.h b/include/eAudioFormats.h new file mode 100644 index 0000000..5903472 --- /dev/null +++ b/include/eAudioFormats.h @@ -0,0 +1,17 @@ +#ifndef EAUDIOFORMATS_H +#define EAUDIOFORMATS_H + +namespace cAudio +{ + +enum AudioFormats +{ + EAF_8BIT_MONO = 0x1100, + EAF_8BIT_STEREO = 0x1102, + EAF_16BIT_MONO = 0x1101, + EAF_16BIT_STEREO = 0x1103 +}; + +}; + +#endif //! EAUDIOFORMATS_H \ No newline at end of file