1 //////////////////////////////////////////////////////////////////////////////// 2 // Copyright (C) 2004-2010 by The Allacrost Project 3 // All Rights Reserved 4 // 5 // This code is licensed under the GNU GPL version 2. It is free software 6 // and you may modify it and/or redistribute it under the terms of this license. 7 // See http://www.gnu.org/copyleft/gpl.html for details. 8 //////////////////////////////////////////////////////////////////////////////// 9 10 /** **************************************************************************** 11 *** \file audio_descriptor.h 12 *** \author Mois�s Ferrer Serra, byaku@allacrost.org 13 *** \author Tyler Olsen, roots@allacrost.org 14 *** \brief Header file for audio descriptors, sources and buffers 15 *** 16 *** This code provides the interface for the sound and music descriptors, that 17 *** are the units for load and manage sounds in the engine. 18 *** 19 *** \note This code uses the OpenAL audio library. See http://www.openal.com/ 20 *** ***************************************************************************/ 21 22 #ifndef __AUDIO_DESCRIPTOR_HEADER__ 23 #define __AUDIO_DESCRIPTOR_HEADER__ 24 25 #ifdef __MACH__ 26 #include <OpenAL/al.h> 27 #include <OpenAL/alc.h> 28 #else 29 #include "al.h" 30 #include "alc.h" 31 #endif 32 33 #include "defs.h" 34 #include "utils.h" 35 36 #include "audio_input.h" 37 #include "audio_stream.h" 38 39 namespace hoa_audio { 40 41 //! \brief The set of states that AudioDescriptor class objects may be in 42 enum AUDIO_STATE { 43 //! Audio data is not loaded 44 AUDIO_STATE_UNLOADED = 0, 45 //! Audio is loaded, but is stopped 46 AUDIO_STATE_STOPPED = 1, 47 //! Audio is loaded and is presently playing 48 AUDIO_STATE_PLAYING = 2, 49 //! Audio is loaded and was playing, but is now paused 50 AUDIO_STATE_PAUSED = 3 51 }; 52 53 //! \brief The possible ways for that a piece of audio data may be loaded 54 enum AUDIO_LOAD { 55 //! \brief Load audio statically by placing the entire contents of the audio into a single OpenAL buffer 56 AUDIO_LOAD_STATIC = 0, 57 //! \brief Stream the audio data from a file into a pair of OpenAL buffers 58 AUDIO_LOAD_STREAM_FILE = 1, 59 //! \brief Stream the audio data from memory into a pair of OpenAL buffers 60 AUDIO_LOAD_STREAM_MEMORY = 2 61 }; 62 63 namespace private_audio { 64 65 //! \brief The default buffer size (in bytes) for streaming buffers 66 const uint32 DEFAULT_BUFFER_SIZE = 8192; 67 68 //! \brief The number of buffers to use for streaming audio descriptors 69 const uint32 NUMBER_STREAMING_BUFFERS = 4; 70 71 /** **************************************************************************** 72 *** \brief Represents an OpenAL buffer 73 *** 74 *** A buffer in OpenAL is simply a structure which contains raw audio data. 75 *** Buffers must be attached to an OpenAL source in order to play. OpenAL 76 *** suppports an infinte number of buffers (as long as there is enough memory). 77 *** ***************************************************************************/ 78 class AudioBuffer { 79 friend class AudioEngine; 80 81 public: 82 AudioBuffer(); 83 84 ~AudioBuffer(); 85 86 /** \brief Fills an OpenAL buffer with raw audio data 87 *** \param data A pointer to the raw data to fill the buffer with 88 *** \param format The format of the buffer data (mono/stereo, 8/16 bits per sample) 89 *** \param size The size of the data in number of bytes 90 *** \param frequency The audio frequency of the data in samples per second 91 **/ FillBuffer(uint8 * data,ALenum format,uint32 size,uint32 frequency)92 void FillBuffer(uint8* data, ALenum format, uint32 size, uint32 frequency) 93 { alBufferData(buffer, format, data, size, frequency); } 94 95 //! \brief Returns true if this class object holds a reference to a valid OpenAL buffer IsValid()96 bool IsValid() const 97 { return (alIsBuffer(buffer) == AL_TRUE); } 98 99 //! \brief The ID of the OpenAL buffer 100 ALuint buffer; 101 }; // class AudioBuffer 102 103 104 /** **************************************************************************** 105 *** \brief Represents an OpenAL source 106 *** 107 *** OpenAL is designed to take care of the complexity of panning sound to 108 *** different speakers; it does this by storing the locations in 3d space of 109 *** both the physical sources that a sound might originate from (for example, 110 *** the point in space where two swords clang together), and also the 3d 111 *** location of the listener's "ears". A source in OpenAL is simply metadata 112 *** about the position of the sound; the actual sound itself comes from audio 113 *** data which is loaded into a buffer, and then played back through one of 114 *** these sources. 115 *** 116 *** This metadata includes properties like position, velocity, 117 *** etc. None of these are actually altered by OpenAL; OpenAL does not use 118 *** velocity to move the sound sources for us each game tick; rather, it simply 119 *** uses these to calculate sound itself (velocity is actually used for 120 *** calculating doppler effects). We are expected to fill these values with 121 *** appropriate position/velocity data to keep them in sync with the game 122 *** objects they represent. 123 *** 124 *** Those properties are not managed by this class, but rather by the 125 *** AudioDescriptor to which the source is attached. OpenAL (or rather, the 126 *** audio hardware) only allows a limited number of audio sources to exist at 127 *** one time, so we can't create a source for every piece of audio that is 128 *** loaded by the game. Therefore, we create as many sources as we can (up to 129 *** MAX_DEFAULT_AUDIO_SOURCES) and have the audio descriptors share between 130 *** sources as they need them. 131 *** 132 *** \note OpenAL sources are created and by the AudioEngine class, not within the 133 *** AudioSource constructor. The sources are, however, deleted by the destructor. 134 *** 135 *** \note You should never really need to call the IsValid() function when 136 *** retrieving a new AudioSource to use. This is because all AudioSource objects 137 *** created by AudioEngine are guaranteed to have a valid OpenAL source contained 138 *** by the object. 139 *** ***************************************************************************/ 140 class AudioSource { 141 public: 142 //! \param al_source A valid OpenAL source that has been generated AudioSource(ALuint al_source)143 AudioSource(ALuint al_source) : 144 source(al_source), owner(NULL) {} 145 146 ~AudioSource(); 147 148 //! \brief Returns true if this class object holds a reference to a valid OpenAL source IsValid()149 bool IsValid() const 150 { return (alIsSource(source) == AL_TRUE); } 151 152 //! \brief Resets the default properties of the OpenAL sources and removes the owner 153 void Reset(); 154 155 //! \brief The ID of the OpenAL source 156 ALuint source; 157 158 //! \brief Pointer to the descriptor associated to this source. 159 AudioDescriptor* owner; 160 }; // class AudioSource 161 162 } // namespace private_audio 163 164 /** **************************************************************************** 165 *** \brief An abstract class for representing a piece of audio 166 *** 167 *** This class takes the OpenAL buffer and source concepts and ties them 168 *** together. This class enables playback, streaming, 3D source positioning, 169 *** and many other features for manipulating a piece of audio. Sounds and 170 *** music are defined by classes which derive from this class. 171 *** 172 *** \note Some features of this class are only available if the audio is loaded 173 *** in a streaming manner. 174 *** 175 *** \note You should <b>never</b> trust the value of _state when it is set to 176 *** AUDIO_STATE_PLAYING. This is because the audio may stop playing on its own 177 *** after the play state has been set. Instead, you should call the GetState() 178 *** method, which guarantees that the correct state value is set. 179 *** 180 *** \todo This class either needs to have its copy assignment operator defined 181 *** or it should be made private. 182 *** ***************************************************************************/ 183 class AudioDescriptor { 184 friend class AudioEngine; 185 186 public: 187 AudioDescriptor(); 188 ~AudioDescriptor()189 virtual ~AudioDescriptor() 190 { FreeAudio(); } 191 192 AudioDescriptor(const AudioDescriptor& copy); 193 194 /** \brief Loads a new piece of audio data from a file 195 *** \param filename The name of the file that contains the new audio data (should have a .wav or .ogg file extension) 196 *** \param load_type The type of loading to perform (default == AUDIO_LOAD_STATIC) 197 *** \param stream_buffer_size If the loading type is streaming, the buffer size to use (default == DEFAULT_BUFFER_SIZE) 198 *** \return True if the audio was succesfully loaded, false if there was an error 199 *** 200 *** The action taken by this function depends on the load type selected. For static sounds, a single OpenAL buffer is 201 *** filled. For streaming, the file/memory is prepared. 202 **/ 203 virtual bool LoadAudio(const std::string& filename, AUDIO_LOAD load_type = AUDIO_LOAD_STATIC, uint32 stream_buffer_size = private_audio::DEFAULT_BUFFER_SIZE); 204 205 /** \brief Frees all data resources and resets class parameters 206 *** 207 *** It resets the _state and _offset class members, as well as deleting _data, _stream, _input, _buffer, and resets _source. 208 **/ 209 void FreeAudio(); 210 GetFilename()211 const std::string GetFilename() const 212 { if (_input == NULL) return ""; else return _input->GetFilename(); } 213 214 //! \brief Returns true if this audio represents a sound, false if the audio represents a music piece 215 virtual bool IsSound() const = 0; 216 217 /** \brief Returns the state of the audio, 218 *** \note This function does not simply return the _state member. If _state is set 219 *** to AUDIO_STATE_PLAYING, the source state is queried to assure that it is still 220 *** playing. 221 **/ 222 AUDIO_STATE GetState(); 223 224 /** \name Audio State Manipulation Functions 225 *** \brief Performs specified operation on the audio 226 *** 227 *** These functions will only take effect when the audio is in the state(s) specified below: 228 *** - PlayAudio() <==> all states but the playing state 229 *** - PauseAudio() <==> playing state 230 *** - ResumeAudio() <==> paused state 231 *** - StopAudio() <==> all states but the stopped state 232 *** - RewindAudio() <==> all states 233 **/ 234 //@{ 235 virtual void Play(); 236 virtual void Stop(); 237 virtual void Pause(); 238 virtual void Resume(); 239 void Rewind(); 240 //@} 241 IsLooping()242 bool IsLooping() const 243 { return _looping; } 244 245 /** \brief Enables/disables looping for this audio 246 *** \param loop True to enable looping, false to disable it. 247 **/ 248 void SetLooping(bool loop); 249 250 /** \brief Sets the starting loop point, used for customized looping 251 *** \param loop_start The sample position for the start loop point 252 *** \note This function is only valid if the audio has been loaded with streaming support 253 **/ 254 void SetLoopStart(uint32 loop_start); 255 256 /** \brief Sets the ending loop point, used for customized looping 257 *** \param loop_start The sample position for the end loop point 258 *** \note This function is only valid if the audio has been loaded with streaming support 259 **/ 260 void SetLoopEnd(uint32 loop_end); 261 262 /** \brief Seeks to the requested sample position 263 *** \param sample The sample position to seek to 264 **/ 265 void SeekSample(uint32 sample); 266 267 /** \brief Seeks to the requested playback time 268 *** \param second The time to seek to, in seconds (e.g. 4.5f == 4.5 second mark) 269 *** \note The position is aligned with a proper sample position, so the seek is not fully 270 *** accurate. 271 **/ 272 void SeekSecond(float second); 273 274 //! \brief Returns the volume level for this audio GetVolume()275 float GetVolume() const 276 { return _volume; } 277 278 /** \brief Sets the volume for this particular audio piece 279 *** \param volume The volume level to set, ranging from [0.0f, 1.0f] 280 **/ 281 virtual void SetVolume(float volume) = 0; 282 283 /** \name Functions for 3D Spatial Audio 284 *** These functions manipulate and retrieve the 3d properties of the audio. Note that only audio which 285 *** are mono channel will be affected by these methods. Stereo channel audio will see no difference. 286 **/ 287 //@{ 288 void SetPosition(const float position[3]); 289 void SetVelocity(const float velocity[3]); 290 void SetDirection(const float direction[3]); 291 GetPosition(float position[3])292 void GetPosition(float position[3]) const 293 { memcpy(&position, _position, sizeof(float) * 3); } 294 GetVelocity(float velocity[3])295 void GetVelocity(float velocity[3]) const 296 { memcpy(&velocity, _velocity, sizeof(float) * 3); } 297 GetDirection(float direction[3])298 void GetDirection(float direction[3]) const 299 { memcpy(&direction, _direction, sizeof(float) * 3); } 300 //@} 301 302 //! \brief Prints various properties about the audio data managed by this class 303 void DEBUG_PrintInfo(); 304 305 protected: 306 //! \brief The current state of the audio (playing, stopped, etc.) 307 AUDIO_STATE _state; 308 309 //! \brief A pointer to the buffer(s) being used by the audio (1 buffer for static sounds, 2 for streamed ones) 310 private_audio::AudioBuffer* _buffer; 311 312 //! \brief A pointer to the source object being used by the audio 313 private_audio::AudioSource* _source; 314 315 //! \brief A pointer to the input object that manages the data 316 private_audio::AudioInput* _input; 317 318 //! \brief A pointer to the stream object (set to NULL if the audio was loaded statically) 319 private_audio::AudioStream* _stream; 320 321 //! \brief A pointer to where the data is streamed to 322 uint8* _data; 323 324 //! \brief The format of the audio (mono/stereo, 8/16 bits per second). 325 ALenum _format; 326 327 //! \brief Flag for indicating if the audio should loop or not 328 bool _looping; 329 330 //! \brief The audio position that was last seeked, in samples. 331 uint32 _offset; 332 333 /** \brief The volume of the audio, ranging from 0.0f to 1.0f 334 *** This isn't actually the true volume of the audio, but rather the modulation 335 *** value of the global sound or music volume level. For example, if this object 336 *** represented a sound and the volume was set to 0.75f, and the global sound 337 *** volume in AudioEngine was 0.80f, the true volume would be (0.75 * 0.8 = 0.6). 338 *** By default this member is set to 1.0f. 339 **/ 340 float _volume; 341 342 //! \brief Size of the streaming buffer, if the audio was loaded for streaming 343 uint32 _stream_buffer_size; 344 345 //! \brief The 3D orientation properties of the audio 346 //@{ 347 float _position[3]; 348 float _velocity[3]; 349 float _direction[3]; 350 //@} 351 352 /** \brief Sets the local volume control for this particular audio piece 353 *** \param volume The volume level to set, ranging from [0.0f, 1.0f] 354 *** This should be thought of as a helper function to the SetVolume methods 355 *** for the derived classes, which modulate the volume level of the sound/music 356 *** by the global sound and music volume controls in the AudioEngine class. 357 **/ 358 void _SetVolumeControl(float volume); 359 360 private: 361 /** \brief Updates the audio during playback 362 *** This function is only useful for streaming audio that is currently in the play state. If either of these two 363 *** conditions are not met, the function will return since it has nothing to do. 364 **/ 365 void _Update(); 366 367 /** \brief Acquires an audio source for playback 368 *** This function is called whenever an audio piece is loaded and whenever the Play operation is specified on 369 *** the audio, but the audio currently does not have a source. It is not guaranteed that the source acquisition 370 *** will be successful, as all other sources may be occupied by other audio. 371 **/ 372 void _AcquireSource(); 373 374 /** \brief Sets all of the relevant properties for the OpenAL source 375 *** This function should be called whenever a new source is allocated for the audio to use. 376 *** It sets all of the necessary properties for the OpenAL source, such as the volume (gain), 377 *** enables looping if requested, etc. 378 **/ 379 void _SetSourceProperties(); 380 381 /** \brief Prepares streaming buffers when a new source is acquired or after a seeking operation. 382 *** This is a special case, since the already queued buffers must be unqueued, and the new 383 *** ones must be refilled. This function should only be called for streaming audio. 384 **/ 385 void _PrepareStreamingBuffers(); 386 }; // class AudioDescriptor 387 388 389 /** **************************************************************************** 390 *** \brief An class for representing a piece of sound audio 391 *** 392 *** Sounds are almost always in the .wav file format. 393 *** ***************************************************************************/ 394 class SoundDescriptor : public AudioDescriptor { 395 public: 396 SoundDescriptor(); 397 398 ~SoundDescriptor(); 399 400 SoundDescriptor(const SoundDescriptor& copy); 401 IsSound()402 bool IsSound() const 403 { return true; } 404 405 /** \brief Sets the volume of the sound 406 *** \param volume The volume to set the sound, value between [0.0, 1.0] 407 *** This value will be modulated by the global sound volume found in the 408 *** AudioEngine class. 409 **/ 410 void SetVolume(float volume); 411 }; // class SoundDescriptor : public AudioDescriptor 412 413 414 /** **************************************************************************** 415 *** \brief A class for representing a piece of music audio 416 *** 417 *** Music is almost always in the .ogg file format. 418 *** 419 *** \note Looping is enabled for music by default 420 *** ***************************************************************************/ 421 class MusicDescriptor : public AudioDescriptor { 422 public: 423 MusicDescriptor(); 424 425 ~MusicDescriptor(); 426 427 MusicDescriptor(const MusicDescriptor& copy); 428 429 bool LoadAudio(const std::string& filename, AUDIO_LOAD load_type = AUDIO_LOAD_STREAM_FILE, uint32 stream_buffer_size = private_audio::DEFAULT_BUFFER_SIZE); 430 IsSound()431 bool IsSound() const 432 { return false; } 433 434 /** \brief Sets the volume of the music 435 *** \param volume The volume to set the music, value between [0.0, 1.0] 436 *** This value will be modulated by the global music volume found in the 437 *** AudioEngine class. 438 **/ 439 void SetVolume(float volume); 440 441 /** \brief Plays the selected music, after stopping the previous playing music 442 *** No two pieces of music are allowed to play simultaneously, meaning that 443 *** calling this method on one music also effectively calls stop on another 444 *** piece of music that was playing when the call was made 445 **/ 446 void Play(); 447 }; // class MusicDescriptor : public AudioDescriptor 448 449 } // namespace hoa_audio 450 451 #endif 452