From 0c3df1d43057c174e13da738ab7ebb5e36923589 Mon Sep 17 00:00:00 2001 From: Joshua Jones Date: Tue, 11 Aug 2009 17:57:20 +0000 Subject: [PATCH] Added audio capture capabilities. The user can now get an interface for audio capture from cAudioManager and record audio from the default recording device. Added a raw audio decoder, allowing raw audio to be played if the format and frequency is known. Will also load from .raw files on disk, but will assume the format is 16 bit mono and the frequency is 22050 hz Added a tutorial to show how recording and playback can be done. Added the ability for the user to unregister audio codecs that they will not be using. Also added methods to test for the existance of a decoder and get the decoder factory back. Moved cVector3.h to include instead of Headers to make using it in user projects easier (one less include path) Moved the audio format enum to its own header file. Small fix in the wav decoder to prevent the file header from being played as audio data. --- .../Tutorial4_AudioCapture.vcproj | 186 ++++++++++++++++++ Examples/Tutorial4_AudioCapture/main.cpp | 103 ++++++++++ Headers/cAudio.h | 4 +- Headers/cAudioCapture.h | 93 +++++++++ Headers/cAudioManager.h | 36 +++- Headers/cRawAudioDecoderFactory.h | 32 +++ Headers/cRawDecoder.h | 41 ++++ Source/cAudio.cpp | 125 ++++++------ Source/cAudioCapture.cpp | 177 +++++++++++++++++ Source/cAudioManager.cpp | 79 +++++++- Source/cRawDecoder.cpp | 53 +++++ Source/cwavdecoder.cpp | 4 + cAudio.sln | 6 + cAudio.vcproj | 30 ++- include/IAudio.h | 2 +- include/IAudioCapture.h | 62 ++++++ include/IAudioDecoder.h | 10 +- include/IAudioManager.h | 40 ++-- include/IListener.h | 2 +- {Headers => include}/cVector3.h | 0 include/eAudioFormats.h | 17 ++ 21 files changed, 989 insertions(+), 113 deletions(-) create mode 100644 Examples/Tutorial4_AudioCapture/Tutorial4_AudioCapture.vcproj create mode 100644 Examples/Tutorial4_AudioCapture/main.cpp create mode 100644 Headers/cAudioCapture.h create mode 100644 Headers/cRawAudioDecoderFactory.h create mode 100644 Headers/cRawDecoder.h create mode 100644 Source/cAudioCapture.cpp create mode 100644 Source/cRawDecoder.cpp create mode 100644 include/IAudioCapture.h rename {Headers => include}/cVector3.h (100%) create mode 100644 include/eAudioFormats.h 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