1 ////////////////////////////////////////////////////////////////////////////////
2 //            Copyright (C) 2004-2011 by The Allacrost Project
3 //            Copyright (C) 2012-2016 by Bertram (Valyria Tear)
4 //                         All Rights Reserved
5 //
6 // This code is licensed under the GNU GPL version 2. It is free software
7 // and you may modify it and/or redistribute it under the terms of this license.
8 // See http://www.gnu.org/copyleft/gpl.html for details.
9 ////////////////////////////////////////////////////////////////////////////////
10 
11 /** ****************************************************************************
12 *** \file   audio_descriptor.cpp
13 *** \author Mois�s Ferrer Serra, byaku@allacrost.org
14 *** \author Tyler Olsen, roots@allacrost.org
15 *** \author  Yohann Ferreira, yohann ferreira orange fr
16 *** \brief  Source for audio descriptors, sources and buffers
17 ***
18 *** This code provides the funcionality for load sounds and music in the engine.
19 *** it provides all the funtions available for them, as basic ones (play, stop,...)
20 *** seeking and more.
21 ***
22 *** \note This code uses the OpenAL audio library. See http://www.openal.com/
23 *** ***************************************************************************/
24 
25 #include "audio_descriptor.h"
26 
27 #include "audio.h"
28 #include "engine/system.h"
29 
30 #include "utils/utils_common.h"
31 #include "utils/utils_strings.h"
32 
33 #include <cstring>
34 
35 using namespace vt_audio::private_audio;
36 
37 namespace vt_audio
38 {
39 
40 namespace private_audio
41 {
42 
43 ////////////////////////////////////////////////////////////////////////////////
44 // AudioBuffer class methods
45 ////////////////////////////////////////////////////////////////////////////////
46 
AudioBuffer()47 AudioBuffer::AudioBuffer() :
48     buffer(0)
49 {
50     if(AudioManager->CheckALError()) {
51         IF_PRINT_WARNING(AUDIO_DEBUG) << "OpenAL error detected before buffer generation: " << AudioManager->CreateALErrorString() << std::endl;
52     }
53 
54     alGenBuffers(1, &buffer);
55 
56     if(AudioManager->CheckALError()) {
57         IF_PRINT_WARNING(AUDIO_DEBUG) << "OpenAL error detected after buffer generation: "
58                                       << AudioManager->CreateALErrorString() << std::endl;
59         buffer = 0;
60     }
61 }
62 
~AudioBuffer()63 AudioBuffer::~AudioBuffer()
64 {
65     if(IsValid()) {
66         alDeleteBuffers(1, &buffer);
67     }
68 }
69 
70 ////////////////////////////////////////////////////////////////////////////////
71 // AudioSource class methods
72 ////////////////////////////////////////////////////////////////////////////////
73 
~AudioSource()74 AudioSource::~AudioSource()
75 {
76     if(IsValid()) {
77         alSourceStop(source);
78         alDeleteSources(1, &source);
79     } else {
80         IF_PRINT_WARNING(AUDIO_DEBUG) << "OpenAL source was invalid upon destruction" << std::endl;
81     }
82 }
83 
Reset()84 void AudioSource::Reset()
85 {
86     owner = nullptr;
87 
88     if(IsValid() == false) {
89         return;
90     }
91 
92     alSourcei(source, AL_LOOPING, AL_FALSE);
93     alSourcef(source, AL_GAIN, 1.0f);
94     alSourcei(source, AL_SAMPLE_OFFSET, 0);		// This line will cause AL_INVALID_ENUM error in linux/Solaris. It is normal.
95     alSourcei(source, AL_BUFFER, 0);
96 
97     if(AudioManager->CheckALError()) {
98 #ifdef WIN32
99         IF_PRINT_WARNING(AUDIO_DEBUG) << "resetting source failed: " << AudioManager->CreateALErrorString() << std::endl;
100 #endif
101     }
102 }
103 
104 } // namespace private_audio
105 
106 ////////////////////////////////////////////////////////////////////////////////
107 // AudioDescriptor class methods
108 ////////////////////////////////////////////////////////////////////////////////
109 
AudioDescriptor()110 AudioDescriptor::AudioDescriptor() :
111     _state(AUDIO_STATE_UNLOADED),
112     _buffer(nullptr),
113     _source(nullptr),
114     _input(nullptr),
115     _stream(nullptr),
116     _data(nullptr),
117     _looping(false),
118     _offset(0),
119     _volume(1.0f),
120     _fade_effect_time(0.0f),
121     _original_volume(0.0f),
122     _stream_buffer_size(0)
123 {
124     _position[0] = 0.0f;
125     _position[1] = 0.0f;
126     _position[2] = 0.0f;
127     _velocity[0] = 0.0f;
128     _velocity[1] = 0.0f;
129     _velocity[2] = 0.0f;
130     _direction[0] = 0.0f;
131     _direction[1] = 0.0f;
132     _direction[2] = 0.0f;
133 }
134 
AudioDescriptor(const AudioDescriptor & copy)135 AudioDescriptor::AudioDescriptor(const AudioDescriptor &copy) :
136     _state(AUDIO_STATE_UNLOADED),
137     _buffer(nullptr),
138     _source(nullptr),
139     _input(nullptr),
140     _stream(nullptr),
141     _data(nullptr),
142     _looping(copy._looping),
143     _offset(0),
144     _volume(copy._volume),
145     _fade_effect_time(copy._fade_effect_time),
146     _original_volume(copy._original_volume),
147     _stream_buffer_size(0)
148 {
149     _position[0] = 0.0f;
150     _position[1] = 0.0f;
151     _position[2] = 0.0f;
152     _velocity[0] = 0.0f;
153     _velocity[1] = 0.0f;
154     _velocity[2] = 0.0f;
155     _direction[0] = 0.0f;
156     _direction[1] = 0.0f;
157     _direction[2] = 0.0f;
158 
159     // If the copy is not in the unloaded state, print a warning
160     if(copy._state != AUDIO_STATE_UNLOADED) {
161         IF_PRINT_WARNING(AUDIO_DEBUG) << "created a copy of an already initialized AudioDescriptor" << std::endl;
162     }
163 }
164 
LoadAudio(const std::string & filename,AUDIO_LOAD load_type,uint32_t stream_buffer_size)165 bool AudioDescriptor::LoadAudio(const std::string &filename, AUDIO_LOAD load_type, uint32_t stream_buffer_size)
166 {
167     if(!AUDIO_ENABLE)
168         return true;
169 
170     // Clean out any audio resources being used before trying to set new ones
171     FreeAudio();
172 
173     // Load the input file for the audio
174     if(filename.size() <= 3) {  // Name of file is at least 3 letters (so the extension is in there)
175         IF_PRINT_WARNING(AUDIO_DEBUG) << "file name argument is too short: " << filename << std::endl;
176         return false;
177     }
178     // Convert the file extension to uppercase and use it to create the proper input type
179     std::string file_extension = filename.substr(filename.size() - 3, 3);
180     file_extension = vt_utils::Upcase(file_extension);
181 
182     // Based on the extension of the file, load properly one
183     if(file_extension.compare("WAV") == 0) {
184         _input = new WavFile(filename);
185     } else if(file_extension.compare("OGG") == 0) {
186         _input = new OggFile(filename);
187     } else {
188         IF_PRINT_WARNING(AUDIO_DEBUG) << "failed due to unsupported input file extension: " << file_extension << std::endl;
189         return false;
190     }
191 
192     if(_input->Initialize() == false) {
193         IF_PRINT_WARNING(AUDIO_DEBUG) << "failed to load and initialize audio file: " << filename << std::endl;
194         return false;
195     }
196 
197     // Retreive audio data properties from the newly initialized input
198     if(_input->GetBitsPerSample() == 8) {
199         if(_input->GetNumberChannels() == 1) {
200             _format = AL_FORMAT_MONO8;
201         } else {
202             _format = AL_FORMAT_STEREO8;
203         }
204     } else { // 16 bits per sample
205         if(_input->GetNumberChannels() == 1) {
206             _format = AL_FORMAT_MONO16;
207         } else {
208             _format = AL_FORMAT_STEREO16;
209         }
210     }
211 
212     // Load the audio data depending upon the load type requested
213     if(load_type == AUDIO_LOAD_STATIC) {
214         // For static sounds just 1 buffer is needed. We create it as an array here, so that
215         // later we can delete it with a call of delete[], similar to the streaming cases
216         _buffer = new AudioBuffer[1];
217 
218         // Create space in memory for the audio data to be read and passed to the OpenAL buffer
219         _data = new uint8_t[_input->GetDataSize()];
220         bool all_data_read = false;
221         if(_input->Read(_data, _input->GetTotalNumberSamples(), all_data_read) != _input->GetTotalNumberSamples()) {
222             IF_PRINT_WARNING(AUDIO_DEBUG) << "failed to read entire audio data stream for file: " << filename << std::endl;
223             return false;
224         }
225 
226         // Pass the buffer data to the OpenAL buffer
227         _buffer->FillBuffer(_data, _format, _input->GetDataSize(), _input->GetSamplesPerSecond());
228         delete[] _data;
229         _data = nullptr;
230 
231         // Attempt to acquire a source for the new audio to use
232         _AcquireSource();
233         if(_source == nullptr) {
234             IF_PRINT_WARNING(AUDIO_DEBUG) << "could not acquire audio source for new audio file: " << filename << std::endl;
235         }
236     } // if (load_type == AUDIO_LOAD_STATIC)
237 
238     // Stream the audio from the file data
239     else if(load_type == AUDIO_LOAD_STREAM_FILE) {
240         _buffer = new AudioBuffer[NUMBER_STREAMING_BUFFERS]; // For streaming we need to use multiple buffers
241         _stream = new AudioStream(_input, _looping);
242         _stream_buffer_size = stream_buffer_size;
243 
244         _data = new uint8_t[_stream_buffer_size * _input->GetSampleSize()];
245 
246         // Attempt to acquire a source for the new audio to use
247         _AcquireSource();
248         if(_source == nullptr) {
249             IF_PRINT_WARNING(AUDIO_DEBUG) << "could not acquire audio source for new audio file: " << filename << std::endl;
250         }
251     } // else if (load_type == AUDIO_LOAD_STREAM_FILE)
252 
253     // Allocate memory for the audio data to remain in and stream it from that location
254     else if(load_type == AUDIO_LOAD_STREAM_MEMORY) {
255         _buffer = new AudioBuffer[NUMBER_STREAMING_BUFFERS]; // For streaming we need to use multiple buffers
256         _stream = new AudioStream(_input, _looping);
257         _stream_buffer_size = stream_buffer_size;
258 
259         _data = new uint8_t[_stream_buffer_size * _input->GetSampleSize()];
260 
261         // We need to replace the _input member with a AudioMemory class object
262         AudioInput *temp_input = _input;
263         _input = new AudioMemory(temp_input);
264         delete temp_input;
265 
266         // Attempt to acquire a source for the new audio to use
267         _AcquireSource();
268         if(_source == nullptr) {
269             IF_PRINT_WARNING(AUDIO_DEBUG) << "could not acquire audio source for new audio file: " << filename << std::endl;
270         }
271     } // else if (load_type == AUDIO_LOAD_STREAM_MEMORY) {
272 
273     else {
274         IF_PRINT_WARNING(AUDIO_DEBUG) << "unknown load_type argument passed: " << load_type << std::endl;
275         return false;
276     }
277 
278     if(AudioManager->CheckALError())
279         IF_PRINT_WARNING(AUDIO_DEBUG) << "OpenAL generated the following error: " << AudioManager->CreateALErrorString() << std::endl;
280 
281     _state = AUDIO_STATE_STOPPED;
282     return true;
283 } // bool AudioDescriptor::LoadAudio(const string& file_name, AUDIO_LOAD load_type, uint32_t stream_buffer_size)
284 
FreeAudio()285 void AudioDescriptor::FreeAudio()
286 {
287     // First, remove any effects.
288     RemoveEffects();
289 
290     if(_source != nullptr)
291         Stop();
292 
293     _state = AUDIO_STATE_UNLOADED;
294     _offset = 0;
295 
296     // If the source is still attached to a sound, reset to the default parameters the source
297     if(_source != nullptr) {
298         _source->Reset();
299         _source = nullptr;
300     }
301 
302     if(_buffer != nullptr) {
303         delete[] _buffer;
304         _buffer = nullptr;
305     }
306 
307     if(_input != nullptr) {
308         delete _input;
309         _input = nullptr;
310     }
311 
312     if(_stream != nullptr) {
313         delete _stream;
314         _stream = nullptr;
315     }
316 
317     if(_data != nullptr) {
318         delete[] _data;
319         _data = nullptr;
320     }
321 }
322 
Play()323 bool AudioDescriptor::Play()
324 {
325     if(!AUDIO_ENABLE)
326         return true;
327 
328     if(_state == AUDIO_STATE_PLAYING)
329         return true;
330 
331     if(!_source) {
332         _AcquireSource();
333         if(!_source) {
334             IF_PRINT_WARNING(AUDIO_DEBUG) << "did not have access to valid AudioSource" << std::endl;
335             return false;
336         }
337         _SetSourceProperties();
338     }
339 
340     if(_stream && _stream->GetEndOfStream()) {
341         _stream->Seek(_offset);
342         _PrepareStreamingBuffers();
343     }
344 
345     // Temp: Checks if there is already an AL error in the buffer. If it is, print error and clear buffer.
346     if(AudioManager->CheckALError()) {
347         IF_PRINT_WARNING(AUDIO_DEBUG) << "audio error occured some time before playing source: " << AudioManager->CreateALErrorString() << std::endl;
348     }
349 
350     alSourcePlay(_source->source);
351     if(AudioManager->CheckALError()) {
352         IF_PRINT_WARNING(AUDIO_DEBUG) << "playing the source failed: " << AudioManager->CreateALErrorString() << std::endl;
353     }
354     _state = AUDIO_STATE_PLAYING;
355     return true;
356 }
357 
Stop()358 void AudioDescriptor::Stop()
359 {
360     if(_state == AUDIO_STATE_STOPPED || _state == AUDIO_STATE_UNLOADED)
361         return;
362 
363     if(!_source) {
364         IF_PRINT_WARNING(AUDIO_DEBUG) << "did not have access to valid AudioSource" << std::endl;
365         return;
366     }
367 
368     // Temp: Checks if there is already an AL error in the buffer. If it is, print error and clear buffer.
369     if(AudioManager->CheckALError()) {
370         IF_PRINT_WARNING(AUDIO_DEBUG) << "audio error occured some time before stopping source: " << AudioManager->CreateALErrorString() << std::endl;
371     }
372 
373     alSourceStop(_source->source);
374     if(AudioManager->CheckALError()) {
375         IF_PRINT_WARNING(AUDIO_DEBUG) << "stopping the source failed: " << AudioManager->CreateALErrorString() << std::endl;
376     }
377     _state = AUDIO_STATE_STOPPED;
378 }
379 
Pause()380 void AudioDescriptor::Pause()
381 {
382     if(_state == AUDIO_STATE_PAUSED || _state == AUDIO_STATE_UNLOADED)
383         return;
384 
385     if(_source == nullptr) {
386         IF_PRINT_WARNING(AUDIO_DEBUG) << "did not have access to valid AudioSource" << std::endl;
387         return;
388     }
389 
390     alSourcePause(_source->source);
391     if(AudioManager->CheckALError()) {
392         IF_PRINT_WARNING(AUDIO_DEBUG) << "pausing the source failed: " << AudioManager->CreateALErrorString() << std::endl;
393     }
394     _state = AUDIO_STATE_PAUSED;
395 }
396 
Resume()397 void AudioDescriptor::Resume()
398 {
399     if(_state != AUDIO_STATE_PAUSED)
400         return;
401 
402     Play();
403 }
404 
Rewind()405 void AudioDescriptor::Rewind()
406 {
407     if(_source == nullptr) {
408         IF_PRINT_WARNING(AUDIO_DEBUG) << "did not have access to valid AudioSource" << std::endl;
409         return;
410     }
411 
412     alSourceRewind(_source->source);
413     if(AudioManager->CheckALError()) {
414         IF_PRINT_WARNING(AUDIO_DEBUG) << "rewinding the source failed: " << AudioManager->CreateALErrorString() << std::endl;
415     }
416 }
417 
SetLooping(bool loop)418 void AudioDescriptor::SetLooping(bool loop)
419 {
420     if(_looping == loop)
421         return;
422 
423     _looping = loop;
424     if(_stream != nullptr) {
425         _stream->SetLooping(_looping);
426     } else if(_source != nullptr) {
427         if(_looping)
428             alSourcei(_source->source, AL_LOOPING, AL_TRUE);
429         else
430             alSourcei(_source->source, AL_LOOPING, AL_FALSE);
431     }
432 }
433 
SetLoopStart(uint32_t loop_start)434 void AudioDescriptor::SetLoopStart(uint32_t loop_start)
435 {
436     if(_stream == nullptr) {
437         IF_PRINT_WARNING(AUDIO_DEBUG) << "the audio data was not loaded with streaming properties, this operation is not permitted" << std::endl;
438         return;
439     }
440     _stream->SetLoopStart(loop_start);
441 }
442 
SetLoopEnd(uint32_t loop_end)443 void AudioDescriptor::SetLoopEnd(uint32_t loop_end)
444 {
445     if(_stream == nullptr) {
446         IF_PRINT_WARNING(AUDIO_DEBUG) << "the audio data was not loaded with streaming properties, this operation is not permitted" << std::endl;
447         return;
448     }
449     _stream->SetLoopEnd(loop_end);
450 }
451 
SeekSample(uint32_t sample)452 void AudioDescriptor::SeekSample(uint32_t sample)
453 {
454     if(!_input)
455         return;
456     if(sample >= _input->GetTotalNumberSamples()) {
457         IF_PRINT_WARNING(AUDIO_DEBUG) << "failed because requested seek time fell outside the valid range of samples: " << sample << std::endl;
458         return;
459     }
460 
461     _offset = sample;
462 
463     if(_stream) {
464         _stream->Seek(_offset);
465         _PrepareStreamingBuffers();
466     } else if(_source != nullptr) {
467         alSourcei(_source->source, AL_SAMPLE_OFFSET, _offset);
468         if(AudioManager->CheckALError()) {
469             IF_PRINT_WARNING(AUDIO_DEBUG) << "setting a source's offset failed: " << AudioManager->CreateALErrorString() << std::endl;
470         }
471     }
472 }
473 
GetCurrentSampleNumber() const474 uint32_t AudioDescriptor::GetCurrentSampleNumber() const
475 {
476     if(_stream) {
477         return _stream->GetCurrentSamplePosition();
478     } else if(_source != nullptr) {
479         int32_t sample = 0;
480         alGetSourcei(_source->source, AL_SAMPLE_OFFSET, &sample);
481         if(AudioManager->CheckALError()) {
482             IF_PRINT_WARNING(AUDIO_DEBUG) << "Getting a source's offset failed: " << AudioManager->CreateALErrorString() << std::endl;
483         }
484         if (sample < 0)
485             return 0;
486         else
487             return static_cast<int32_t>(sample);
488     }
489 
490     // default behavior
491     return 0;
492 }
493 
SeekSecond(float second)494 void AudioDescriptor::SeekSecond(float second)
495 {
496     if(second < 0.0f) {
497         IF_PRINT_WARNING(AUDIO_DEBUG) << "function received invalid argument that was less than 0.0f: " << second << std::endl;
498         return;
499     }
500 
501     uint32_t pos = static_cast<uint32_t>(second * _input->GetSamplesPerSecond());
502     if(pos >= _input->GetTotalNumberSamples()) {
503         IF_PRINT_WARNING(AUDIO_DEBUG) << "failed because requested seek time fell outside the valid range of samples: " << pos << std::endl;
504         return;
505     }
506 
507     _offset = pos;
508     if(_stream) {
509         _stream->Seek(_offset);
510         _PrepareStreamingBuffers();
511     } else if(_source != nullptr) {
512         alSourcei(_source->source, AL_SEC_OFFSET, _offset);
513         if(AudioManager->CheckALError()) {
514             IF_PRINT_WARNING(AUDIO_DEBUG) << "setting a source's offset failed: " << AudioManager->CreateALErrorString() << std::endl;
515         }
516     }
517 }
518 
SetPosition(const ALfloat position[ALFLOAT3D])519 void AudioDescriptor::SetPosition(const ALfloat position[ALFLOAT3D])
520 {
521     if(_format != AL_FORMAT_MONO8 && _format != AL_FORMAT_MONO16) {
522         IF_PRINT_WARNING(AUDIO_DEBUG) << "audio is stereo channel and will not be effected by function call" << std::endl;
523         return;
524     }
525 
526     memcpy(_position, position, sizeof(ALfloat) * ALFLOAT3D);
527     if(_source != nullptr) {
528         alSourcefv(_source->source, AL_POSITION, _position);
529         if(AudioManager->CheckALError()) {
530             IF_PRINT_WARNING(AUDIO_DEBUG) << "setting a source's position failed: " << AudioManager->CreateALErrorString() << std::endl;
531         }
532     }
533 }
534 
SetVelocity(const ALfloat velocity[ALFLOAT3D])535 void AudioDescriptor::SetVelocity(const ALfloat velocity[ALFLOAT3D])
536 {
537     if(_format != AL_FORMAT_MONO8 && _format != AL_FORMAT_MONO16) {
538         IF_PRINT_WARNING(AUDIO_DEBUG) << "audio is stereo channel and will not be effected by function call" << std::endl;
539         return;
540     }
541 
542     memcpy(_velocity, velocity, sizeof(ALfloat) * ALFLOAT3D);
543     if(_source != nullptr) {
544         alSourcefv(_source->source, AL_VELOCITY, _position);
545         if(AudioManager->CheckALError()) {
546             IF_PRINT_WARNING(AUDIO_DEBUG) << "setting a source's velocity failed: " << AudioManager->CreateALErrorString() << std::endl;
547         }
548     }
549 }
550 
SetDirection(const ALfloat direction[ALFLOAT3D])551 void AudioDescriptor::SetDirection(const ALfloat direction[ALFLOAT3D])
552 {
553     if(_format != AL_FORMAT_MONO8 && _format != AL_FORMAT_MONO16) {
554         IF_PRINT_WARNING(AUDIO_DEBUG) << "audio is stereo channel and will not be effected by function call" << std::endl;
555         return;
556     }
557 
558     memcpy(_direction, direction, sizeof(ALfloat) * ALFLOAT3D);
559     if(_source != nullptr) {
560         alSourcefv(_source->source, AL_DIRECTION, _direction);
561         if(AudioManager->CheckALError()) {
562             IF_PRINT_WARNING(AUDIO_DEBUG) << "setting a source's direction failed: " << AudioManager->CreateALErrorString() << std::endl;
563         }
564     }
565 }
566 
AddGameModeOwner(vt_mode_manager::GameMode * gm)567 void AudioDescriptor::AddGameModeOwner(vt_mode_manager::GameMode *gm)
568 {
569     // Don't accept null references.
570     if(!gm)
571         return;
572 
573     // Check for duplicate entries
574     std::vector<vt_mode_manager::GameMode *>::const_iterator it = _game_mode_owners.begin();
575     for(; it != _game_mode_owners.end(); ++it) {
576         if(*it == gm)
577             return;
578     }
579     // Add the new owner in the list
580     _game_mode_owners.push_back(gm);
581 }
582 
AddGameModeOwners(std::vector<vt_mode_manager::GameMode * > & owners)583 void AudioDescriptor::AddGameModeOwners(std::vector<vt_mode_manager::GameMode *>& owners)
584 {
585     std::vector<vt_mode_manager::GameMode *>::const_iterator it = owners.begin();
586 
587     for(; it != owners.end(); ++it) {
588         AddGameModeOwner(*it);
589     }
590 }
591 
RemoveGameModeOwner(vt_mode_manager::GameMode * gm)592 bool AudioDescriptor::RemoveGameModeOwner(vt_mode_manager::GameMode* gm)
593 {
594     if(!gm)
595         return false;
596 
597     // Don't deal with never owned audio descriptors.
598     if(_game_mode_owners.empty())
599         return false;
600 
601     // Check for duplicate entries
602     std::vector<vt_mode_manager::GameMode *>::iterator it = _game_mode_owners.begin();
603     for(; it != _game_mode_owners.end();) {
604         if(*it != gm) {
605             ++it;
606             continue;
607         }
608 
609         // Remove the owner and check whether the sound can be freed
610         it = _game_mode_owners.erase(it);
611 
612         if(_game_mode_owners.empty()) {
613             FreeAudio();
614             return true;
615         }
616     }
617     return false;
618 }
619 
FadeIn(float time)620 void AudioDescriptor::FadeIn(float time)
621 {
622     // If the sound is not playing, then start it.
623     // Note: Only audio descriptors being played are updated.
624     if(_state != AUDIO_STATE_PLAYING)
625         Play();
626 
627     if (GetVolume() >= 1.0f)
628         return;
629 
630     _state = AUDIO_STATE_FADE_IN;
631     _fade_effect_time = time;
632 }
633 
FadeOut(float time)634 void AudioDescriptor::FadeOut(float time)
635 {
636     _original_volume = GetVolume();
637 
638     if (_original_volume <= 0.0f) {
639         Stop();
640         return;
641     }
642 
643     _fade_effect_time = time;
644     _state = AUDIO_STATE_FADE_OUT;
645 }
646 
RemoveEffects()647 void AudioDescriptor::RemoveEffects()
648 {
649     // Delete any active audio effects for the given audio descriptor
650     for(std::vector<AudioEffect *>::iterator it = _audio_effects.begin();
651             it != _audio_effects.end(); ++it) {
652         if(*it)
653             delete(*it);
654     }
655     _audio_effects.clear();
656 }
657 
DEBUG_PrintInfo()658 void AudioDescriptor::DEBUG_PrintInfo()
659 {
660     PRINT_WARNING << "*** Audio Descriptor Information ***" << std::endl;
661 
662     if(_input == nullptr) {
663         PRINT_WARNING << "no audio data loaded" << std::endl;
664         return;
665     }
666 
667     uint16_t num_channels = 0;
668     uint16_t bits_per_sample = 0;
669     switch(_format) {
670     case AL_FORMAT_MONO8:
671         num_channels = 1;
672         bits_per_sample = 8;
673         break;
674     case AL_FORMAT_MONO16:
675         num_channels = 1;
676         bits_per_sample = 16;
677         break;
678     case AL_FORMAT_STEREO8:
679         num_channels = 1;
680         bits_per_sample = 8;
681         break;
682     case AL_FORMAT_STEREO16:
683         num_channels = 2;
684         bits_per_sample = 16;
685         break;
686     default:
687         IF_PRINT_WARNING(AUDIO_DEBUG) << "unknown audio format: " << _format << std::endl;
688         break;
689     }
690 
691     PRINT_WARNING << "Filename:          " << _input->GetFilename() << std::endl;
692     PRINT_WARNING << "Channels:          " << num_channels << std::endl;
693     PRINT_WARNING << "Bits Per Sample:   " << bits_per_sample << std::endl;
694     PRINT_WARNING << "Frequency:         " << _input->GetSamplesPerSecond() << std::endl;
695     PRINT_WARNING << "Samples:           " << _input->GetTotalNumberSamples() << std::endl;
696     PRINT_WARNING << "Time:              " << _input->GetPlayTime() << std::endl;
697 
698     if(_stream != nullptr) {
699         PRINT_WARNING << "Audio load type:    streamed" << std::endl;
700         PRINT_WARNING << "Stream buffer size (samples): " << _stream_buffer_size << std::endl;
701     } else {
702         PRINT_WARNING << "Audio load type:    static" << std::endl;
703     }
704 } // void AudioDescriptor::DEBUG_PrintInfo()
705 
706 
707 
_SetVolumeControl(float volume)708 void AudioDescriptor::_SetVolumeControl(float volume)
709 {
710     if(volume < 0.0f) {
711         IF_PRINT_WARNING(AUDIO_DEBUG) << "tried to set volume less than 0.0f" << std::endl;
712         _volume = 0.0f;
713     } else if(volume > 1.0f) {
714         IF_PRINT_WARNING(AUDIO_DEBUG) << "tried to set volume greater than 1.0f" << std::endl;
715         _volume = 1.0f;
716     } else {
717         _volume = volume;
718     }
719 }
720 
721 
722 
_Update()723 void AudioDescriptor::_Update()
724 {
725     // Don't update stopped audio descriptors
726     if(_state != AUDIO_STATE_PLAYING && _state != AUDIO_STATE_FADE_IN && _state != AUDIO_STATE_FADE_OUT)
727         return;
728 
729     // If the last set state was the playing state, we have to double check
730     // with the OpenAL source to make sure that the audio is still playing.
731     // If the descriptor no longer has a source, we can stop
732     if(!_source) {
733         _state = AUDIO_STATE_STOPPED;
734     } else {
735         ALint source_state;
736         alGetSourcei(_source->source, AL_SOURCE_STATE, &source_state);
737         if(AudioManager->CheckALError()) {
738             IF_PRINT_WARNING(AUDIO_DEBUG) << "getting the source's state failed: " << AudioManager->CreateALErrorString() << std::endl;
739         }
740         if(source_state != AL_PLAYING) {
741             _state = AUDIO_STATE_STOPPED;
742         }
743     }
744 
745     // Handle the fade in/out states
746     _HandleFadeStates();
747 
748     // Update all registered audio effects
749     for(std::vector<AudioEffect *>::iterator it = _audio_effects.begin(); it != _audio_effects.end();) {
750         (*it)->Update();
751 
752         // If the effect is finished, delete it
753         if(!(*it)->active) {
754             delete(*it);
755             it = _audio_effects.erase(it);
756         } else {
757             ++it;
758         }
759     }
760 
761     // Only streaming audio that is being played requires periodic updates
762     if(!_stream)
763         return;
764 
765     ALint queued = 0;
766     alGetSourcei(_source->source, AL_BUFFERS_QUEUED, &queued);
767     if(AudioManager->CheckALError()) {
768         IF_PRINT_WARNING(AUDIO_DEBUG) << "getting queued sources failed: " << AudioManager->CreateALErrorString() << std::endl;
769     }
770 
771     // If there are no more buffers and the end of stream was reached, stop the sound
772     if(queued != 0 && _stream->GetEndOfStream()) {
773         _state = AUDIO_STATE_STOPPED;
774         return;
775     }
776 
777     ALint buffers_processed = 0;
778     alGetSourcei(_source->source, AL_BUFFERS_PROCESSED, &buffers_processed);
779     if(AudioManager->CheckALError()) {
780         IF_PRINT_WARNING(AUDIO_DEBUG) << "getting processed sources failed: " << AudioManager->CreateALErrorString() << std::endl;
781     }
782 
783     // If any buffers have finished playing, attempt to refill them
784     if(buffers_processed > 0) {
785         ALuint buffer_finished;
786         alSourceUnqueueBuffers(_source->source, 1, &buffer_finished);
787         if(AudioManager->CheckALError()) {
788             IF_PRINT_WARNING(AUDIO_DEBUG) << "unqueuing a source failed: " << AudioManager->CreateALErrorString() << std::endl;
789         }
790 
791         uint32_t size = _stream->FillBuffer(_data, _stream_buffer_size);
792         if(size > 0) {  // Make sure that there is data available to fill
793             alBufferData(buffer_finished, _format, _data, size * _input->GetSampleSize(), _input->GetSamplesPerSecond());
794             if(AudioManager->CheckALError()) {
795                 IF_PRINT_WARNING(AUDIO_DEBUG) << "buffering data failed: " << AudioManager->CreateALErrorString() << std::endl;
796             }
797             alSourceQueueBuffers(_source->source, 1, &buffer_finished);
798             if(AudioManager->CheckALError()) {
799                 IF_PRINT_WARNING(AUDIO_DEBUG) << "queueing a source failed: " << AudioManager->CreateALErrorString() << std::endl;
800             }
801         }
802 
803         // This ensures that if a streaming audio piece is stopped because the buffers ran out
804         // of audio data for the source to play, the audio will be automatically replayed again.
805         ALint state;
806         alGetSourcei(_source->source, AL_SOURCE_STATE, &state);
807         if(state != AL_PLAYING) {
808             alSourcePlay(_source->source);
809             if(AudioManager->CheckALError()) {
810                 IF_PRINT_WARNING(AUDIO_DEBUG) << "playing a source failed: " << AudioManager->CreateALErrorString() << std::endl;
811             }
812         }
813     }
814 } // void AudioDescriptor::_Update()
815 
816 
_HandleFadeStates()817 void AudioDescriptor::_HandleFadeStates()
818 {
819     if (_state == AUDIO_STATE_FADE_OUT) {
820         // Hande when the effect time is very quick
821         if( _fade_effect_time <= 10.0f) {
822             Stop();
823             SetVolume(0.0f);
824             return;
825         }
826 
827         float time_elapsed = (float)vt_system::SystemManager->GetUpdateTime();
828         float new_volume = GetVolume() - (_original_volume - (_original_volume - (time_elapsed / _fade_effect_time)));
829 
830         // Stop the audio, and terminate the effect if the volume drops to 0.0f or below
831         if(new_volume <= 0.0f) {
832             Stop();
833             SetVolume(0.0f);
834             return;
835         }
836         // Otherwise, update the volume for the audio
837         else {
838             SetVolume(new_volume);
839             return;
840         }
841     }
842     else if (_state == AUDIO_STATE_FADE_IN) {
843         // Stop right away when the effect is less than a usual cpu cycle
844         if(_fade_effect_time <= 10.0f) {
845             SetVolume(1.0f);
846             _state = AUDIO_STATE_PLAYING;
847             return;
848         }
849 
850         float time_elapsed = (float)vt_system::SystemManager->GetUpdateTime();
851         float new_volume = GetVolume() + (time_elapsed / _fade_effect_time);
852 
853 
854         // If the volume has reached the maximum, mark the effect as over
855         if(new_volume >= 1.0f) {
856             SetVolume(1.0f);
857             _state = AUDIO_STATE_PLAYING;
858             return;
859         }
860         // Otherwise, update the volume for the audio
861         else {
862             SetVolume(new_volume);
863         }
864     }
865 }
866 
_AcquireSource()867 void AudioDescriptor::_AcquireSource()
868 {
869     if(_source != nullptr) {
870         IF_PRINT_WARNING(AUDIO_DEBUG) << "function was invoked when object already had a source acquired" << std::endl;
871         return;
872     }
873 
874     if(_buffer == nullptr) {
875         IF_PRINT_WARNING(AUDIO_DEBUG) << "function was invoked when object did not have an audio buffer attached" << std::endl;
876         return;
877     }
878 
879     _source = AudioManager->_AcquireAudioSource();
880     if(_source == nullptr) {
881         IF_PRINT_WARNING(AUDIO_DEBUG) << "could not acquire audio source for new audio file: " << _input->GetFilename() << std::endl;
882         return;
883     }
884 
885     _source->owner = this;
886     _SetSourceProperties();
887     if(_stream == nullptr)
888         alSourcei(_source->source, AL_BUFFER, _buffer->buffer);
889     else
890         _PrepareStreamingBuffers();
891 }
892 
893 
894 
_SetSourceProperties()895 void AudioDescriptor::_SetSourceProperties()
896 {
897     if(_source == nullptr) {
898         IF_PRINT_WARNING(AUDIO_DEBUG) << "function was invoked when class did not have access to an audio source" << std::endl;
899         return;
900     }
901 
902     // Set volume (gain)
903     float volume_multiplier = 0.0f;
904     if(IsSound())
905         volume_multiplier = AudioManager->GetSoundVolume();
906     else
907         volume_multiplier = AudioManager->GetMusicVolume();
908 
909     alSourcef(_source->source, AL_GAIN, _volume * volume_multiplier);
910     if(AudioManager->CheckALError()) {
911         IF_PRINT_WARNING(AUDIO_DEBUG) << "changing volume on a source failed: " << AudioManager->CreateALErrorString() << std::endl;
912     }
913 
914     // Set looping (source has looping disabled by default, so only need to check the true case)
915     if(_stream != nullptr) {
916         _stream->SetLooping(_looping);
917     } else if(_source != nullptr) {
918         if(_looping) {
919             alSourcei(_source->source, AL_LOOPING, AL_TRUE);
920             if(AudioManager->CheckALError()) {
921                 IF_PRINT_WARNING(AUDIO_DEBUG) << "setting a source to loop failed: " << AudioManager->CreateALErrorString() << std::endl;
922             }
923         }
924     }
925 
926     //! \todo More properties need to be set here, such as source position, etc.
927 }
928 
929 
930 
_PrepareStreamingBuffers()931 void AudioDescriptor::_PrepareStreamingBuffers()
932 {
933     if(_stream == nullptr) {
934         IF_PRINT_WARNING(AUDIO_DEBUG) << "_stream pointer was nullptr, meaning this function should never have been called" << std::endl;
935         return;
936     }
937 
938     if(_source == nullptr) {
939         IF_PRINT_WARNING(AUDIO_DEBUG) << "failed because no source was available for this object to utilize" << std::endl;
940         return;
941     }
942 
943     bool was_playing = false;
944     if(AudioManager->CheckALError()) {
945         IF_PRINT_WARNING(AUDIO_DEBUG) << "OpenAL error detected: " << AudioManager->CreateALErrorString() << std::endl;
946     }
947 
948     // Stop the audio if it is playing and detatch the buffer from the source
949     if(_state == AUDIO_STATE_PLAYING) {
950         was_playing = true;
951         Stop();
952     }
953     alSourcei(_source->source, AL_BUFFER, 0);
954 
955     // Fill each buffer with audio data
956     for(uint32_t i = 0; i < NUMBER_STREAMING_BUFFERS; i++) {
957         uint32_t read = _stream->FillBuffer(_data, _stream_buffer_size);
958         if(read > 0) {
959             _buffer[i].FillBuffer(_data, _format, read * _input->GetSampleSize(), _input->GetSamplesPerSecond());
960             if(_source != nullptr)
961                 alSourceQueueBuffers(_source->source, 1, &_buffer[i].buffer);
962         }
963     }
964 
965     if(AudioManager->CheckALError()) {
966         IF_PRINT_WARNING(AUDIO_DEBUG) << "failed to fill all buffers: " << AudioManager->CreateALErrorString() << std::endl;
967     }
968 
969     if(was_playing) {
970         Play();
971     }
972 }
973 
974 ////////////////////////////////////////////////////////////////////////////////
975 // SoundDescriptor class methods
976 ////////////////////////////////////////////////////////////////////////////////
977 
SoundDescriptor()978 SoundDescriptor::SoundDescriptor() :
979     AudioDescriptor()
980 {
981     AudioManager->_registered_sounds.push_back(this);
982 }
983 
984 
985 
~SoundDescriptor()986 SoundDescriptor::~SoundDescriptor()
987 {
988     for(std::vector<SoundDescriptor *>::iterator i = AudioManager->_registered_sounds.begin();
989             i != AudioManager->_registered_sounds.end(); ++i) {
990         if(*i == this) {
991             AudioManager->_registered_sounds.erase(i);
992             return;
993         }
994     }
995 }
996 
997 
998 
SoundDescriptor(const SoundDescriptor & copy)999 SoundDescriptor::SoundDescriptor(const SoundDescriptor &copy) :
1000     AudioDescriptor(copy)
1001 {
1002     AudioManager->_registered_sounds.push_back(this);
1003 }
1004 
SetVolume(float volume)1005 void SoundDescriptor::SetVolume(float volume)
1006 {
1007     AudioDescriptor::_SetVolumeControl(volume);
1008 
1009     float sound_volume = _volume * AudioManager->GetSoundVolume();
1010 
1011     if(_source) {
1012         alSourcef(_source->source, AL_GAIN, sound_volume);
1013     }
1014 }
1015 
Play()1016 bool SoundDescriptor::Play()
1017 {
1018     if(!AUDIO_ENABLE)
1019         return true;
1020 
1021     if(_state == AUDIO_STATE_PLAYING)
1022         Stop();
1023 
1024     return AudioDescriptor::Play();
1025 }
1026 
1027 ////////////////////////////////////////////////////////////////////////////////
1028 // MusicDescriptor class methods
1029 ////////////////////////////////////////////////////////////////////////////////
1030 
MusicDescriptor()1031 MusicDescriptor::MusicDescriptor() :
1032     AudioDescriptor()
1033 {
1034     _looping = true;
1035     AudioManager->_registered_music.push_back(this);
1036 }
1037 
~MusicDescriptor()1038 MusicDescriptor::~MusicDescriptor()
1039 {
1040     if(AudioManager->_active_music == this) {
1041         AudioManager->_active_music = nullptr;
1042     }
1043 
1044     for(std::vector<MusicDescriptor *>::iterator i = AudioManager->_registered_music.begin();
1045             i != AudioManager->_registered_music.end(); ++i) {
1046         if(*i == this) {
1047             AudioManager->_registered_music.erase(i);
1048             return;
1049         }
1050     }
1051 }
1052 
MusicDescriptor(const MusicDescriptor & copy)1053 MusicDescriptor::MusicDescriptor(const MusicDescriptor &copy) :
1054     AudioDescriptor(copy)
1055 {
1056     AudioManager->_registered_music.push_back(this);
1057 }
1058 
LoadAudio(const std::string & filename,AUDIO_LOAD load_type,uint32_t stream_buffer_size)1059 bool MusicDescriptor::LoadAudio(const std::string &filename, AUDIO_LOAD load_type, uint32_t stream_buffer_size)
1060 {
1061     return AudioDescriptor::LoadAudio(filename, load_type, stream_buffer_size);
1062 }
1063 
Play()1064 bool MusicDescriptor::Play()
1065 {
1066     if(!AUDIO_ENABLE)
1067         return true;
1068 
1069     if(AudioManager->_active_music == this) {
1070         if(_state != AUDIO_STATE_PLAYING && _state != AUDIO_STATE_FADE_IN) {
1071             if (AudioDescriptor::Play())
1072                 FadeIn(500);
1073             else
1074                 return false;
1075         }
1076     } else {
1077         if(AudioManager->_active_music)
1078             AudioManager->_active_music->FadeOut(500);
1079         AudioManager->_active_music = this;
1080         if (AudioDescriptor::Play())
1081             FadeIn(500);
1082         else
1083             return false;
1084     }
1085     return true;
1086 }
1087 
SetVolume(float volume)1088 void MusicDescriptor::SetVolume(float volume)
1089 {
1090     AudioDescriptor::_SetVolumeControl(volume);
1091 
1092     float music_volume = _volume * AudioManager->GetMusicVolume();
1093 
1094     if(_source) {
1095         alSourcef(_source->source, AL_GAIN, (ALfloat)music_volume);
1096     }
1097 }
1098 
1099 } // namespace vt_audio
1100