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 ©) :
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 ©) :
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 ©) :
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