mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-03 10:22:45 -04:00
More improvements and bugfixes
This commit is contained in:
parent
11ee08072f
commit
a89589033b
@ -341,7 +341,7 @@ make_dsp(const FilterProperties::FilterConfig &conf) {
|
|||||||
void FmodAudioManager::
|
void FmodAudioManager::
|
||||||
update_dsp_chain(FMOD::DSP *head, FilterProperties *config) {
|
update_dsp_chain(FMOD::DSP *head, FilterProperties *config) {
|
||||||
const FilterProperties::ConfigVector &conf = config->get_config();
|
const FilterProperties::ConfigVector &conf = config->get_config();
|
||||||
FMOD_RESULT res1,res2,res3,res4,res5,res6;
|
FMOD_RESULT res1,res2,res3,res4,res5;
|
||||||
while (1) {
|
while (1) {
|
||||||
int numinputs;
|
int numinputs;
|
||||||
res1 = head->getNumInputs(&numinputs);
|
res1 = head->getNumInputs(&numinputs);
|
||||||
|
@ -282,14 +282,19 @@ get_loop_count() const {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: FmodAudioSound::set_time
|
// Function: FmodAudioSound::set_time
|
||||||
// Access: public
|
// Access: public
|
||||||
// Description: Sets the play position within the sound
|
// Description: Starts playing from the specified location.
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void FmodAudioSound::
|
void FmodAudioSound::
|
||||||
set_time(float start_time) {
|
set_time(float start_time) {
|
||||||
FMOD_RESULT result;
|
FMOD_RESULT result;
|
||||||
|
|
||||||
|
if (!_active) {
|
||||||
|
_paused = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
int startTime = (int)(start_time * 1000);
|
int startTime = (int)(start_time * 1000);
|
||||||
|
|
||||||
if (_channel != 0) {
|
if (_channel != 0) {
|
||||||
// try backing up current sound.
|
// try backing up current sound.
|
||||||
result = _channel->setPosition( startTime , FMOD_TIMEUNIT_MS );
|
result = _channel->setPosition( startTime , FMOD_TIMEUNIT_MS );
|
||||||
@ -324,10 +329,8 @@ set_time(float start_time) {
|
|||||||
// add_dsp_on_channel();
|
// add_dsp_on_channel();
|
||||||
set_3d_attributes_on_channel();
|
set_3d_attributes_on_channel();
|
||||||
|
|
||||||
if (_active) {
|
result = _channel->setPaused(false);
|
||||||
result = _channel->setPaused(false);
|
fmod_audio_errcheck("_channel->setPaused()", result);
|
||||||
fmod_audio_errcheck("_channel->setPaused()", result);
|
|
||||||
}
|
|
||||||
|
|
||||||
_self_ref = this;
|
_self_ref = this;
|
||||||
}
|
}
|
||||||
@ -785,13 +788,26 @@ status() const {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void FmodAudioSound::
|
void FmodAudioSound::
|
||||||
set_active(bool active) {
|
set_active(bool active) {
|
||||||
_active = active;
|
if (_active != active) {
|
||||||
|
_active = active;
|
||||||
|
if (_active) {
|
||||||
|
// ...activate the sound.
|
||||||
|
if (_paused && get_loop_count()==0) {
|
||||||
|
// ...this sound was looping when it was paused.
|
||||||
|
_paused = false;
|
||||||
|
play();
|
||||||
|
}
|
||||||
|
|
||||||
if (status() == PLAYING) {
|
} else {
|
||||||
// If the sound is (or should be) playing, then pause or unpause
|
// ...deactivate the sound.
|
||||||
// it in the system.
|
if (status() == PLAYING) {
|
||||||
FMOD_RESULT result = _channel->setPaused(!_active);
|
if (get_loop_count() == 0) {
|
||||||
fmod_audio_errcheck("_channel->setPaused()", result);
|
// ...we're pausing a looping sound.
|
||||||
|
_paused = true;
|
||||||
|
}
|
||||||
|
stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -809,14 +825,11 @@ get_active() const {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: FmodAudioSound::finished
|
// Function: FmodAudioSound::finished
|
||||||
// Access: public
|
// Access: public
|
||||||
// Description: NOT USED ANYMORE!!!
|
// Description: Not implemented.
|
||||||
// Called by finishedCallback function when a sound
|
|
||||||
// terminates (but doesn't loop).
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void FmodAudioSound::
|
void FmodAudioSound::
|
||||||
finished() {
|
finished() {
|
||||||
audio_debug("FmodAudioSound::finished()");
|
audio_error("finished: not implemented under FMOD-EX");
|
||||||
audio_debug("NOT USED ANYMORE in FMOD-EX version of PANDA.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -829,8 +842,7 @@ finished() {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void FmodAudioSound::
|
void FmodAudioSound::
|
||||||
set_finished_event(const string& event) {
|
set_finished_event(const string& event) {
|
||||||
audio_debug("FmodAudioSound::set_finished_event(event="<<event<<")");
|
audio_error("set_finished_event: not implemented under FMOD-EX");
|
||||||
audio_debug("NOT USED ANYMORE in FMOD-EX version of PANDA.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -843,8 +855,7 @@ set_finished_event(const string& event) {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
const string& FmodAudioSound::
|
const string& FmodAudioSound::
|
||||||
get_finished_event() const {
|
get_finished_event() const {
|
||||||
audio_debug("FmodAudioSound::get_finished_event() returning " << _finished_event );
|
audio_error("get_finished_event: not implemented under FMOD-EX");
|
||||||
audio_debug("NOT USED ANYMORE in FMOD-EX version of PANDA.");
|
|
||||||
return _finished_event;
|
return _finished_event;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -154,14 +154,9 @@ class EXPCL_FMOD_AUDIO FmodAudioSound : public AudioSound {
|
|||||||
void set_active(bool active=true);
|
void set_active(bool active=true);
|
||||||
bool get_active() const;
|
bool get_active() const;
|
||||||
|
|
||||||
//THESE ARE NOT USED ANYMORE.
|
|
||||||
//THEY ARE ONLY HERE BECAUSE THEY are still needed by Miles.
|
|
||||||
//THESE are stubs in FMOD-EX version
|
|
||||||
////////////////////////////////////////////////////////////////////
|
|
||||||
void finished();
|
void finished();
|
||||||
void set_finished_event(const string& event);
|
void set_finished_event(const string& event);
|
||||||
const string& get_finished_event() const;
|
const string& get_finished_event() const;
|
||||||
////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
PT(FmodAudioManager) _manager;
|
PT(FmodAudioManager) _manager;
|
||||||
@ -199,7 +194,10 @@ class EXPCL_FMOD_AUDIO FmodAudioSound : public AudioSound {
|
|||||||
virtual void set_priority(int priority);
|
virtual void set_priority(int priority);
|
||||||
|
|
||||||
bool _active;
|
bool _active;
|
||||||
|
bool _paused;
|
||||||
|
|
||||||
|
string _finished_event;
|
||||||
|
|
||||||
// This reference-counting pointer is set to this while the sound is
|
// This reference-counting pointer is set to this while the sound is
|
||||||
// playing, and cleared when we get an indication that the sound has
|
// playing, and cleared when we get an indication that the sound has
|
||||||
// stopped. This prevents a sound from destructing while it is
|
// stopped. This prevents a sound from destructing while it is
|
||||||
@ -208,11 +206,6 @@ class EXPCL_FMOD_AUDIO FmodAudioSound : public AudioSound {
|
|||||||
// other mismanagement.
|
// other mismanagement.
|
||||||
PT(FmodAudioSound) _self_ref;
|
PT(FmodAudioSound) _self_ref;
|
||||||
|
|
||||||
//THESE AREN'T USED ANYMORE.
|
|
||||||
//THEY ARE ONLY HERE BECAUSE THEY are still need by Miles.
|
|
||||||
//THESE are stubs in FMOD-EX version
|
|
||||||
string _finished_event;
|
|
||||||
|
|
||||||
friend FMOD_RESULT F_CALLBACK sound_end_callback(FMOD_CHANNEL * channel,
|
friend FMOD_RESULT F_CALLBACK sound_end_callback(FMOD_CHANNEL * channel,
|
||||||
FMOD_CHANNEL_CALLBACKTYPE type,
|
FMOD_CHANNEL_CALLBACKTYPE type,
|
||||||
int command,
|
int command,
|
||||||
|
@ -74,7 +74,6 @@ void alc_audio_errcheck(const char *context,ALCdevice* device) {
|
|||||||
// Description: Factory Function
|
// Description: Factory Function
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
PT(AudioManager) Create_AudioManager() {
|
PT(AudioManager) Create_AudioManager() {
|
||||||
audio_debug("Create_AudioManager() OpenAL.");
|
|
||||||
return new OpenALAudioManager;
|
return new OpenALAudioManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,8 +85,6 @@ PT(AudioManager) Create_AudioManager() {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
OpenALAudioManager::
|
OpenALAudioManager::
|
||||||
OpenALAudioManager() {
|
OpenALAudioManager() {
|
||||||
audio_debug("OpenALAudioManager::OpenALAudioManager(), this = "
|
|
||||||
<< (void *)this);
|
|
||||||
if (_managers == (Managers *)NULL) {
|
if (_managers == (Managers *)NULL) {
|
||||||
_managers = new Managers;
|
_managers = new Managers;
|
||||||
_al_sources = new SourceCache;
|
_al_sources = new SourceCache;
|
||||||
@ -95,9 +92,6 @@ OpenALAudioManager() {
|
|||||||
|
|
||||||
_managers->insert(this);
|
_managers->insert(this);
|
||||||
|
|
||||||
audio_debug(" audio_active="<<audio_active);
|
|
||||||
audio_debug(" audio_volume="<<audio_volume);
|
|
||||||
|
|
||||||
_cleanup_required = true;
|
_cleanup_required = true;
|
||||||
_active = audio_active;
|
_active = audio_active;
|
||||||
_volume = audio_volume;
|
_volume = audio_volume;
|
||||||
@ -146,7 +140,6 @@ OpenALAudioManager() {
|
|||||||
// The shutdown call will do the right thing when it's called,
|
// The shutdown call will do the right thing when it's called,
|
||||||
// either way.
|
// either way.
|
||||||
++_active_managers;
|
++_active_managers;
|
||||||
audio_debug(" _active_managers="<<_active_managers);
|
|
||||||
nassertv(_active_managers>0);
|
nassertv(_active_managers>0);
|
||||||
|
|
||||||
if (!_device || !_context) {
|
if (!_device || !_context) {
|
||||||
@ -170,15 +163,11 @@ OpenALAudioManager() {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
OpenALAudioManager::
|
OpenALAudioManager::
|
||||||
~OpenALAudioManager() {
|
~OpenALAudioManager() {
|
||||||
audio_debug("OpenALAudioManager::~OpenALAudioManager(), this = "
|
|
||||||
<< (void *)this);
|
|
||||||
nassertv(_managers != (Managers *)NULL);
|
nassertv(_managers != (Managers *)NULL);
|
||||||
Managers::iterator mi = _managers->find(this);
|
Managers::iterator mi = _managers->find(this);
|
||||||
nassertv(mi != _managers->end());
|
nassertv(mi != _managers->end());
|
||||||
_managers->erase(mi);
|
_managers->erase(mi);
|
||||||
|
|
||||||
cleanup();
|
cleanup();
|
||||||
audio_debug("OpenALAudioManager::~OpenALAudioManager() finished");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -192,7 +181,6 @@ OpenALAudioManager::
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void OpenALAudioManager::
|
void OpenALAudioManager::
|
||||||
shutdown() {
|
shutdown() {
|
||||||
audio_debug("shutdown(), _openal_active = " << _openal_active);
|
|
||||||
if (_managers != (Managers *)NULL) {
|
if (_managers != (Managers *)NULL) {
|
||||||
Managers::iterator mi;
|
Managers::iterator mi;
|
||||||
for (mi = _managers->begin(); mi != _managers->end(); ++mi) {
|
for (mi = _managers->begin(); mi != _managers->end(); ++mi) {
|
||||||
@ -201,7 +189,6 @@ shutdown() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
nassertv(_active_managers == 0);
|
nassertv(_active_managers == 0);
|
||||||
audio_debug("shutdown() finished");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -267,77 +254,97 @@ can_load_audio(MovieAudioCursor *source) {
|
|||||||
int channels = source->audio_channels();
|
int channels = source->audio_channels();
|
||||||
int samples = (int)(source->length() * source->audio_rate());
|
int samples = (int)(source->length() * source->audio_rate());
|
||||||
int bytes = samples * channels * 2;
|
int bytes = samples * channels * 2;
|
||||||
if (bytes > 200000000) {
|
if (bytes > 200000) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: OpenALAudioManager::load_sound_data
|
// Function: OpenALAudioManager::get_sound_data
|
||||||
// Access: Private
|
// Access: Private
|
||||||
// Description: Reads a sound file and creates a SoundData.
|
// Description: Obtains a SoundData for the specified sound.
|
||||||
// When you are done with the SoundData, you need
|
|
||||||
// to decrement the client count.
|
|
||||||
////////////////////////////////////////////////////////////////////
|
|
||||||
OpenALAudioManager::SoundData *OpenALAudioManager::
|
|
||||||
load_sound_data(MovieAudioCursor *source) {
|
|
||||||
|
|
||||||
nassertr(can_use_audio(source), NULL);
|
|
||||||
nassertr(can_load_audio(source), NULL);
|
|
||||||
|
|
||||||
make_current();
|
|
||||||
Filename path = source->get_source()->get_filename();
|
|
||||||
SoundData *sd = new SoundData(this, path);
|
|
||||||
|
|
||||||
alGetError(); // clear errors
|
|
||||||
sd->_buffer = 0;
|
|
||||||
alGenBuffers(1, &sd->_buffer);
|
|
||||||
al_audio_errcheck("alGenBuffers");
|
|
||||||
if (sd->_buffer == 0) {
|
|
||||||
audio_error("Could not create an OpenAL buffer object");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
int channels = source->audio_channels();
|
|
||||||
int samples = (int)(source->length() * source->audio_rate());
|
|
||||||
|
|
||||||
PN_int16 *data = new PN_int16[samples * channels];
|
|
||||||
source->read_samples(samples, data);
|
|
||||||
alBufferData(sd->_buffer,
|
|
||||||
(channels>1) ? AL_FORMAT_STEREO16 : AL_FORMAT_MONO16,
|
|
||||||
data, samples * channels * 2, source->audio_rate());
|
|
||||||
int err = alGetError();
|
|
||||||
if (err != AL_NO_ERROR) {
|
|
||||||
audio_error("alBufferData: " << alGetString(err));
|
|
||||||
alDeleteBuffers(1, &sd->_buffer);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
sd->_rate = source->audio_rate();
|
|
||||||
sd->_channels = source->audio_channels();
|
|
||||||
sd->_length = source->length();
|
|
||||||
_all_sound_data.insert(SoundDataSet::value_type(path, sd));
|
|
||||||
return sd;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
|
||||||
// Function: OpenALAudioManager::cached_sound_data
|
|
||||||
// Access: Private
|
|
||||||
// Description: Looks in the cache for the specified sound data,
|
|
||||||
// and returns it if present.
|
|
||||||
//
|
//
|
||||||
// When you are done with the SoundData, you need
|
// When you are done with the SoundData, you need
|
||||||
// to decrement the client count.
|
// to decrement the client count.
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
OpenALAudioManager::SoundData *OpenALAudioManager::
|
OpenALAudioManager::SoundData *OpenALAudioManager::
|
||||||
cached_sound_data(const Filename &path) {
|
get_sound_data(MovieAudio *movie) {
|
||||||
SoundDataSet::const_iterator si=_all_sound_data.find(path);
|
const Filename &path = movie->get_filename();
|
||||||
if (si != _all_sound_data.end()) {
|
|
||||||
SoundData *sd = (*si).second;
|
// Search for an already-cached sample or an already-opened stream.
|
||||||
increment_client_count(sd);
|
if (!path.empty()) {
|
||||||
return sd;
|
|
||||||
|
SampleCache::iterator lsmi=_sample_cache.find(path);
|
||||||
|
if (lsmi != _sample_cache.end()) {
|
||||||
|
SoundData *sd = (*lsmi).second;
|
||||||
|
increment_client_count(sd);
|
||||||
|
return sd;
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpirationQueue::iterator exqi;
|
||||||
|
for (exqi=_expiring_streams.begin(); exqi!=_expiring_streams.end(); exqi++) {
|
||||||
|
SoundData *sd = (SoundData*)(*exqi);
|
||||||
|
if (sd->_movie->get_filename() == path) {
|
||||||
|
increment_client_count(sd);
|
||||||
|
return sd;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return NULL;
|
|
||||||
|
PT(MovieAudioCursor) stream = movie->open();
|
||||||
|
if (stream == 0) {
|
||||||
|
audio_error("Cannot open file: "<<path);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!can_use_audio(stream)) {
|
||||||
|
audio_error("File is not in usable format: "<<path);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
SoundData *sd = new SoundData();
|
||||||
|
sd->_client_count = 1;
|
||||||
|
sd->_manager = this;
|
||||||
|
sd->_movie = movie;
|
||||||
|
sd->_rate = stream->audio_rate();
|
||||||
|
sd->_channels = stream->audio_channels();
|
||||||
|
sd->_length = stream->length();
|
||||||
|
|
||||||
|
audio_debug("Creating: " << sd->_movie->get_filename().get_basename());
|
||||||
|
|
||||||
|
if (can_load_audio(stream)) {
|
||||||
|
audio_debug(path.get_basename() << ": loading as sample");
|
||||||
|
make_current();
|
||||||
|
alGetError(); // clear errors
|
||||||
|
sd->_sample = 0;
|
||||||
|
alGenBuffers(1, &sd->_sample);
|
||||||
|
al_audio_errcheck("alGenBuffers");
|
||||||
|
if (sd->_sample == 0) {
|
||||||
|
audio_error("Could not create an OpenAL buffer object");
|
||||||
|
delete sd;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
int channels = stream->audio_channels();
|
||||||
|
int samples = (int)(stream->length() * stream->audio_rate());
|
||||||
|
PN_int16 *data = new PN_int16[samples * channels];
|
||||||
|
stream->read_samples(samples, data);
|
||||||
|
alBufferData(sd->_sample,
|
||||||
|
(channels>1) ? AL_FORMAT_STEREO16 : AL_FORMAT_MONO16,
|
||||||
|
data, samples * channels * 2, stream->audio_rate());
|
||||||
|
int err = alGetError();
|
||||||
|
if (err != AL_NO_ERROR) {
|
||||||
|
audio_error("could not fill OpenAL buffer object with data");
|
||||||
|
delete sd;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
_sample_cache.insert(SampleCache::value_type(path, sd));
|
||||||
|
} else {
|
||||||
|
audio_debug(path.get_basename() << ": loading as stream");
|
||||||
|
sd->_stream = stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sd;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -361,39 +368,20 @@ get_sound(const string &file_name, bool positional) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
PT(MovieAudioCursor) cursor;
|
PT(MovieAudio) mva = MovieAudio::get(path);
|
||||||
SoundData *sd = cached_sound_data(path);
|
|
||||||
if (sd == 0) {
|
|
||||||
cursor = MovieAudio::get(path)->open();
|
|
||||||
if (cursor == 0) {
|
|
||||||
audio_error("Cannot open file: "<<path);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
if (!can_use_audio(cursor)) {
|
|
||||||
audio_error("Audio data not supported format: "<<path);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
if (can_load_audio(cursor)) {
|
|
||||||
sd = load_sound_data(cursor);
|
|
||||||
cursor = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PT(OpenALAudioSound) oas =
|
PT(OpenALAudioSound) oas =
|
||||||
new OpenALAudioSound(this, path, cursor, sd, positional);
|
new OpenALAudioSound(this, mva, positional);
|
||||||
|
|
||||||
if (oas->get_active()) {
|
_all_sounds.insert(oas);
|
||||||
_all_audio_sounds.insert(oas);
|
PT(AudioSound) res = (AudioSound*)(OpenALAudioSound*)oas;
|
||||||
PT(AudioSound) res = (AudioSound*)(OpenALAudioSound*)oas;
|
return res;
|
||||||
return res;
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: OpenALAudioManager::uncache_sound
|
// Function: OpenALAudioManager::uncache_sound
|
||||||
// Access: Public
|
// Access: Public
|
||||||
// Description: Deletes a sound from the expiration queue.
|
// Description: Deletes a sample from the expiration queues.
|
||||||
// If the sound is actively in use, then the sound
|
// If the sound is actively in use, then the sound
|
||||||
// cannot be deleted, and this function has no effect.
|
// cannot be deleted, and this function has no effect.
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -405,15 +393,13 @@ uncache_sound(const string& file_name) {
|
|||||||
VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
|
VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
|
||||||
vfs->resolve_filename(path, get_sound_path()) ||
|
vfs->resolve_filename(path, get_sound_path()) ||
|
||||||
vfs->resolve_filename(path, get_model_path());
|
vfs->resolve_filename(path, get_model_path());
|
||||||
|
|
||||||
SoundDataSet::iterator sdi=_all_sound_data.find(path);
|
SampleCache::iterator sci = _sample_cache.find(path);
|
||||||
if (sdi != _all_sound_data.end()) {
|
if (sci != _sample_cache.end()) {
|
||||||
SoundData *sd = (*sdi).second;
|
SoundData *sd = (*sci).second;
|
||||||
ExpirationQueue::iterator exi =
|
if (sd->_client_count == 0) {
|
||||||
find(_expiration_queue.begin(), _expiration_queue.end(), sd);
|
_expiring_samples.erase(sd->_expire);
|
||||||
if (exi != _expiration_queue.end()) {
|
_sample_cache.erase(sci);
|
||||||
_expiration_queue.erase(exi);
|
|
||||||
_all_sound_data.erase(sdi);
|
|
||||||
delete sd;
|
delete sd;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -457,9 +443,9 @@ get_cache_limit() const {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void OpenALAudioManager::
|
void OpenALAudioManager::
|
||||||
release_sound(OpenALAudioSound* audioSound) {
|
release_sound(OpenALAudioSound* audioSound) {
|
||||||
AudioSoundSet::iterator ai = _all_audio_sounds.find(audioSound);
|
AllSounds::iterator ai = _all_sounds.find(audioSound);
|
||||||
if (ai != _all_audio_sounds.end()) {
|
if (ai != _all_sounds.end()) {
|
||||||
_all_audio_sounds.erase(ai);
|
_all_sounds.erase(ai);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -470,13 +456,12 @@ release_sound(OpenALAudioSound* audioSound) {
|
|||||||
// Sets listener gain
|
// Sets listener gain
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void OpenALAudioManager::set_volume(float volume) {
|
void OpenALAudioManager::set_volume(float volume) {
|
||||||
audio_debug("OpenALAudioManager::set_volume(volume="<<volume<<")");
|
|
||||||
if (_volume!=volume) {
|
if (_volume!=volume) {
|
||||||
_volume = volume;
|
_volume = volume;
|
||||||
|
|
||||||
// Tell our AudioSounds to adjust:
|
// Tell our AudioSounds to adjust:
|
||||||
AudioSoundSet::iterator i=_all_audio_sounds.begin();
|
AllSounds::iterator i=_all_sounds.begin();
|
||||||
for (; i!=_all_audio_sounds.end(); ++i) {
|
for (; i!=_all_sounds.end(); ++i) {
|
||||||
(**i).set_volume((**i).get_volume());
|
(**i).set_volume((**i).get_volume());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -499,7 +484,6 @@ void OpenALAudioManager::set_volume(float volume) {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
float OpenALAudioManager::
|
float OpenALAudioManager::
|
||||||
get_volume() const {
|
get_volume() const {
|
||||||
audio_debug("OpenALAudioManager::get_volume() returning "<<_volume);
|
|
||||||
return _volume;
|
return _volume;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -510,12 +494,11 @@ get_volume() const {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void OpenALAudioManager::
|
void OpenALAudioManager::
|
||||||
set_play_rate(float play_rate) {
|
set_play_rate(float play_rate) {
|
||||||
audio_debug("OpenALAudioManager::set_play_rate(play_rate="<<play_rate<<")");
|
|
||||||
if (_play_rate!=play_rate) {
|
if (_play_rate!=play_rate) {
|
||||||
_play_rate = play_rate;
|
_play_rate = play_rate;
|
||||||
// Tell our AudioSounds to adjust:
|
// Tell our AudioSounds to adjust:
|
||||||
AudioSoundSet::iterator i=_all_audio_sounds.begin();
|
AllSounds::iterator i=_all_sounds.begin();
|
||||||
for (; i!=_all_audio_sounds.end(); ++i) {
|
for (; i!=_all_sounds.end(); ++i) {
|
||||||
(**i).set_play_rate((**i).get_play_rate());
|
(**i).set_play_rate((**i).get_play_rate());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -528,7 +511,6 @@ set_play_rate(float play_rate) {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
float OpenALAudioManager::
|
float OpenALAudioManager::
|
||||||
get_play_rate() const {
|
get_play_rate() const {
|
||||||
audio_debug("OpenALAudioManager::get_play_rate() returning "<<_play_rate);
|
|
||||||
return _play_rate;
|
return _play_rate;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -540,12 +522,11 @@ get_play_rate() const {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void OpenALAudioManager::
|
void OpenALAudioManager::
|
||||||
set_active(bool active) {
|
set_active(bool active) {
|
||||||
audio_debug("OpenALAudioManager::set_active(flag="<<active<<")");
|
|
||||||
if (_active!=active) {
|
if (_active!=active) {
|
||||||
_active=active;
|
_active=active;
|
||||||
// Tell our AudioSounds to adjust:
|
// Tell our AudioSounds to adjust:
|
||||||
AudioSoundSet::iterator i=_all_audio_sounds.begin();
|
AllSounds::iterator i=_all_sounds.begin();
|
||||||
for (; i!=_all_audio_sounds.end(); ++i) {
|
for (; i!=_all_sounds.end(); ++i) {
|
||||||
(**i).set_active(_active);
|
(**i).set_active(_active);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -558,7 +539,6 @@ set_active(bool active) {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
bool OpenALAudioManager::
|
bool OpenALAudioManager::
|
||||||
get_active() const {
|
get_active() const {
|
||||||
audio_debug("OpenALAudioManager::get_active() returning "<<_active);
|
|
||||||
return _active;
|
return _active;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -661,8 +641,8 @@ audio_3d_set_distance_factor(float factor) {
|
|||||||
al_audio_errcheck("alDopplerFactor()");
|
al_audio_errcheck("alDopplerFactor()");
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioSoundSet::iterator i=_all_audio_sounds.begin();
|
AllSounds::iterator i=_all_sounds.begin();
|
||||||
for (; i!=_all_audio_sounds.end(); ++i) {
|
for (; i!=_all_sounds.end(); ++i) {
|
||||||
(**i).set_3d_min_distance((**i).get_3d_min_distance());
|
(**i).set_3d_min_distance((**i).get_3d_min_distance());
|
||||||
(**i).set_3d_max_distance((**i).get_3d_max_distance());
|
(**i).set_3d_max_distance((**i).get_3d_max_distance());
|
||||||
}
|
}
|
||||||
@ -715,8 +695,8 @@ void OpenALAudioManager::
|
|||||||
audio_3d_set_drop_off_factor(float factor) {
|
audio_3d_set_drop_off_factor(float factor) {
|
||||||
_drop_off_factor = factor;
|
_drop_off_factor = factor;
|
||||||
|
|
||||||
AudioSoundSet::iterator i=_all_audio_sounds.begin();
|
AllSounds::iterator i=_all_sounds.begin();
|
||||||
for (; i!=_all_audio_sounds.end(); ++i) {
|
for (; i!=_all_sounds.end(); ++i) {
|
||||||
(**i).set_3d_drop_off_factor((**i).get_3d_drop_off_factor());
|
(**i).set_3d_drop_off_factor((**i).get_3d_drop_off_factor());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -842,7 +822,6 @@ reduce_sounds_playing_to(unsigned int count) {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void OpenALAudioManager::
|
void OpenALAudioManager::
|
||||||
stop_all_sounds() {
|
stop_all_sounds() {
|
||||||
audio_debug("OpenALAudioManager::stop_all_sounds()");
|
|
||||||
reduce_sounds_playing_to(0);
|
reduce_sounds_playing_to(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -853,7 +832,6 @@ stop_all_sounds() {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void OpenALAudioManager::
|
void OpenALAudioManager::
|
||||||
update() {
|
update() {
|
||||||
//audio_debug("OpenALAudioManager::update()");
|
|
||||||
|
|
||||||
// See if any of our playing sounds have ended
|
// See if any of our playing sounds have ended
|
||||||
// we must first collect a seperate list of finished sounds and then
|
// we must first collect a seperate list of finished sounds and then
|
||||||
@ -862,13 +840,19 @@ update() {
|
|||||||
// since finished() modifies _sounds_playing
|
// since finished() modifies _sounds_playing
|
||||||
SoundsPlaying sounds_finished;
|
SoundsPlaying sounds_finished;
|
||||||
|
|
||||||
|
double rtc = TrueClock::get_global_ptr()->get_short_time();
|
||||||
SoundsPlaying::iterator i=_sounds_playing.begin();
|
SoundsPlaying::iterator i=_sounds_playing.begin();
|
||||||
for (; i!=_sounds_playing.end(); ++i) {
|
for (; i!=_sounds_playing.end(); ++i) {
|
||||||
if ((**i).status()!=AudioSound::PLAYING) {
|
OpenALAudioSound *sound = (*i);
|
||||||
|
sound->pull_used_buffers();
|
||||||
|
sound->push_fresh_buffers();
|
||||||
|
sound->restart_stalled_audio();
|
||||||
|
sound->cache_time(rtc);
|
||||||
|
if (sound->status()!=AudioSound::PLAYING) {
|
||||||
sounds_finished.insert(*i);
|
sounds_finished.insert(*i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
i=sounds_finished.begin();
|
i=sounds_finished.begin();
|
||||||
for (; i!=sounds_finished.end(); ++i) {
|
for (; i!=sounds_finished.end(); ++i) {
|
||||||
(**i).finished();
|
(**i).finished();
|
||||||
@ -885,19 +869,16 @@ update() {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void OpenALAudioManager::
|
void OpenALAudioManager::
|
||||||
cleanup() {
|
cleanup() {
|
||||||
audio_debug("OpenALAudioManager::cleanup(), this = " << (void *)this
|
|
||||||
<< ", _cleanup_required = " << _cleanup_required);
|
|
||||||
if (!_cleanup_required) {
|
if (!_cleanup_required) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioSoundSet sounds(_all_audio_sounds);
|
AllSounds sounds(_all_sounds);
|
||||||
AudioSoundSet::iterator ai;
|
AllSounds::iterator ai;
|
||||||
for (ai = sounds.begin(); ai != sounds.end(); ++ai) {
|
for (ai = sounds.begin(); ai != sounds.end(); ++ai) {
|
||||||
(*ai)->cleanup();
|
(*ai)->cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(_all_sound_data.size() == _expiration_queue.size());
|
|
||||||
clear_cache();
|
clear_cache();
|
||||||
|
|
||||||
nassertv(_active_managers > 0);
|
nassertv(_active_managers > 0);
|
||||||
@ -938,7 +919,6 @@ cleanup() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
_cleanup_required = false;
|
_cleanup_required = false;
|
||||||
audio_debug("OpenALAudioManager::cleanup() finished");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -947,12 +927,15 @@ cleanup() {
|
|||||||
// Description:
|
// Description:
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
OpenALAudioManager::SoundData::
|
OpenALAudioManager::SoundData::
|
||||||
SoundData(OpenALAudioManager* manager, const Filename &path) :
|
SoundData() :
|
||||||
_manager(manager),
|
_manager(0),
|
||||||
_path(path),
|
_movie(0),
|
||||||
_buffer(0),
|
_sample(0),
|
||||||
_client_count(1),
|
_stream(NULL),
|
||||||
_length(0.0)
|
_length(0.0),
|
||||||
|
_rate(0),
|
||||||
|
_channels(0),
|
||||||
|
_client_count(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -963,12 +946,12 @@ SoundData(OpenALAudioManager* manager, const Filename &path) :
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
OpenALAudioManager::SoundData::
|
OpenALAudioManager::SoundData::
|
||||||
~SoundData() {
|
~SoundData() {
|
||||||
if (_buffer != 0) {
|
if (_sample != 0) {
|
||||||
if (_manager->_is_valid) {
|
if (_manager->_is_valid) {
|
||||||
_manager->make_current();
|
_manager->make_current();
|
||||||
alDeleteBuffers(1,&_buffer);
|
alDeleteBuffers(1,&_sample);
|
||||||
}
|
}
|
||||||
_buffer = 0;
|
_sample = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -981,13 +964,14 @@ OpenALAudioManager::SoundData::
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void OpenALAudioManager::
|
void OpenALAudioManager::
|
||||||
increment_client_count(SoundData *sd) {
|
increment_client_count(SoundData *sd) {
|
||||||
audio_debug("Incrementing client count: " << sd->_path);
|
|
||||||
sd->_client_count += 1;
|
sd->_client_count += 1;
|
||||||
|
audio_debug("Incrementing: " << sd->_movie->get_filename().get_basename() << " " << sd->_client_count);
|
||||||
if (sd->_client_count == 1) {
|
if (sd->_client_count == 1) {
|
||||||
audio_debug("Removing from expiration queue: " << sd->_path);
|
if (sd->_sample) {
|
||||||
ExpirationQueue::iterator p=find(_expiration_queue.begin(), _expiration_queue.end(), sd);
|
_expiring_samples.erase(sd->_expire);
|
||||||
assert(p != _expiration_queue.end());
|
} else {
|
||||||
_expiration_queue.erase(p);
|
_expiring_streams.erase(sd->_expire);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1002,11 +986,18 @@ increment_client_count(SoundData *sd) {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void OpenALAudioManager::
|
void OpenALAudioManager::
|
||||||
decrement_client_count(SoundData *sd) {
|
decrement_client_count(SoundData *sd) {
|
||||||
audio_debug("Decrementing client count: " << sd->_path);
|
|
||||||
sd->_client_count -= 1;
|
sd->_client_count -= 1;
|
||||||
|
audio_debug("Decrementing: " << sd->_movie->get_filename().get_basename() << " " << sd->_client_count);
|
||||||
if (sd->_client_count == 0) {
|
if (sd->_client_count == 0) {
|
||||||
audio_debug("Adding to expiration queue: " << sd->_path);
|
if (sd->_sample) {
|
||||||
_expiration_queue.push_back(sd);
|
_expiring_samples.push_back(sd);
|
||||||
|
sd->_expire = _expiring_samples.end();
|
||||||
|
sd->_expire--;
|
||||||
|
} else {
|
||||||
|
_expiring_streams.push_back(sd);
|
||||||
|
sd->_expire = _expiring_streams.end();
|
||||||
|
sd->_expire--;
|
||||||
|
}
|
||||||
discard_excess_cache(_cache_limit);
|
discard_excess_cache(_cache_limit);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1018,13 +1009,25 @@ decrement_client_count(SoundData *sd) {
|
|||||||
// number of sounds remaining is under the limit.
|
// number of sounds remaining is under the limit.
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void OpenALAudioManager::
|
void OpenALAudioManager::
|
||||||
discard_excess_cache(int limit) {
|
discard_excess_cache(int sample_limit) {
|
||||||
while (((int)_expiration_queue.size()) > limit) {
|
int stream_limit = 5;
|
||||||
SoundData *sd = _expiration_queue.front();
|
|
||||||
audio_debug("Deleting head of sound cache: " << sd->_path);
|
while (((int)_expiring_samples.size()) > sample_limit) {
|
||||||
|
SoundData *sd = (SoundData*)(_expiring_samples.front());
|
||||||
assert(sd->_client_count == 0);
|
assert(sd->_client_count == 0);
|
||||||
_expiration_queue.pop_front();
|
assert(sd->_expire == _expiring_samples.begin());
|
||||||
_all_sound_data.erase(sd->_path);
|
_expiring_samples.pop_front();
|
||||||
|
_sample_cache.erase(_sample_cache.find(sd->_movie->get_filename()));
|
||||||
|
audio_debug("Expiring: " << sd->_movie->get_filename().get_basename());
|
||||||
|
delete sd;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (((int)_expiring_streams.size()) > stream_limit) {
|
||||||
|
SoundData *sd = (SoundData*)(_expiring_streams.front());
|
||||||
|
assert(sd->_client_count == 0);
|
||||||
|
assert(sd->_expire == _expiring_streams.begin());
|
||||||
|
_expiring_streams.pop_front();
|
||||||
|
audio_debug("Expiring: " << sd->_movie->get_filename().get_basename());
|
||||||
delete sd;
|
delete sd;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,9 +25,9 @@
|
|||||||
#ifdef HAVE_OPENAL //[
|
#ifdef HAVE_OPENAL //[
|
||||||
|
|
||||||
#include "audioManager.h"
|
#include "audioManager.h"
|
||||||
#include "pset.h"
|
#include "plist.h"
|
||||||
#include "pmap.h"
|
#include "pmap.h"
|
||||||
#include "pdeque.h"
|
#include "pset.h"
|
||||||
#include "movieAudioCursor.h"
|
#include "movieAudioCursor.h"
|
||||||
|
|
||||||
//The Includes needed for OpenAL
|
//The Includes needed for OpenAL
|
||||||
@ -115,12 +115,11 @@ class EXPCL_OPENAL_AUDIO OpenALAudioManager : public AudioManager {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
void make_current() const;
|
void make_current() const;
|
||||||
|
|
||||||
bool can_use_audio(MovieAudioCursor *source);
|
bool can_use_audio(MovieAudioCursor *source);
|
||||||
bool can_load_audio(MovieAudioCursor *source);
|
bool can_load_audio(MovieAudioCursor *source);
|
||||||
|
|
||||||
SoundData *cached_sound_data(const Filename &file_name);
|
SoundData *get_sound_data(MovieAudio *source);
|
||||||
SoundData *load_sound_data(MovieAudioCursor *source);
|
|
||||||
|
|
||||||
// Tell the manager that the sound dtor was called.
|
// Tell the manager that the sound dtor was called.
|
||||||
void release_sound(OpenALAudioSound* audioSound);
|
void release_sound(OpenALAudioSound* audioSound);
|
||||||
@ -135,6 +134,16 @@ private:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
// An expiration queue is a list of SoundData
|
||||||
|
// that are no longer being used. They are kept
|
||||||
|
// around for a little while, since it is common to
|
||||||
|
// stop using a sound for a brief moment and then
|
||||||
|
// quickly resume.
|
||||||
|
|
||||||
|
typedef plist<void *> ExpirationQueue;
|
||||||
|
ExpirationQueue _expiring_samples;
|
||||||
|
ExpirationQueue _expiring_streams;
|
||||||
|
|
||||||
// An AudioSound that uses a SoundData is called a "client"
|
// An AudioSound that uses a SoundData is called a "client"
|
||||||
// of the SoundData. The SoundData keeps track of how
|
// of the SoundData. The SoundData keeps track of how
|
||||||
// many clients are using it. When the number of clients
|
// many clients are using it. When the number of clients
|
||||||
@ -148,27 +157,28 @@ private:
|
|||||||
|
|
||||||
class SoundData {
|
class SoundData {
|
||||||
public:
|
public:
|
||||||
SoundData(OpenALAudioManager* manager, const Filename &path);
|
SoundData();
|
||||||
~SoundData();
|
~SoundData();
|
||||||
OpenALAudioManager* _manager;
|
OpenALAudioManager* _manager;
|
||||||
Filename _path;
|
PT(MovieAudio) _movie;
|
||||||
ALuint _buffer;
|
ALuint _sample;
|
||||||
double _length;
|
PT(MovieAudioCursor) _stream;
|
||||||
int _rate;
|
double _length;
|
||||||
int _channels;
|
int _rate;
|
||||||
int _client_count;
|
int _channels;
|
||||||
|
int _client_count;
|
||||||
|
ExpirationQueue::iterator _expire;
|
||||||
};
|
};
|
||||||
typedef pmap<string, SoundData *> SoundDataSet;
|
|
||||||
SoundDataSet _all_sound_data;
|
|
||||||
|
|
||||||
typedef pset<OpenALAudioSound *> AudioSoundSet;
|
typedef phash_map<string, SoundData *> SampleCache;
|
||||||
AudioSoundSet _all_audio_sounds;
|
SampleCache _sample_cache;
|
||||||
|
|
||||||
typedef pdeque<SoundData *> ExpirationQueue;
|
typedef phash_set<OpenALAudioSound *> SoundsPlaying;
|
||||||
ExpirationQueue _expiration_queue;
|
|
||||||
|
|
||||||
typedef pset<OpenALAudioSound *> SoundsPlaying;
|
|
||||||
SoundsPlaying _sounds_playing;
|
SoundsPlaying _sounds_playing;
|
||||||
|
|
||||||
|
typedef phash_set<OpenALAudioSound *> AllSounds;
|
||||||
|
AllSounds _all_sounds;
|
||||||
|
|
||||||
// State:
|
// State:
|
||||||
int _cache_limit;
|
int _cache_limit;
|
||||||
|
@ -16,8 +16,65 @@
|
|||||||
//
|
//
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: OpenALAudioSound::set_calibrated_clock
|
||||||
|
// Access: public
|
||||||
|
// Description: Sets the sound's calibrated clock.
|
||||||
|
//
|
||||||
|
// OpenAL is not very accurate at reporting how much
|
||||||
|
// time has elapsed within a buffer. However, it does
|
||||||
|
// accurately report when it has finished playing a
|
||||||
|
// buffer. So we use a hybrid clock algorithm.
|
||||||
|
// When OpenAL is in the middle of a buffer,
|
||||||
|
// we use a real-time-clock to estimate how far the
|
||||||
|
// sound has gotten. Each time OpenAL reaches the end
|
||||||
|
// of a buffer (which it does every 1/4 second or so),
|
||||||
|
// we calibrate our real-time-clock by speeding it up
|
||||||
|
// or slowing it down.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
INLINE void OpenALAudioSound::
|
||||||
|
set_calibrated_clock(double rtc, double t, double accel) {
|
||||||
|
_calibrated_clock_scale = _playing_rate * accel;
|
||||||
|
_calibrated_clock_base = rtc - (t / _calibrated_clock_scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: OpenALAudioSound::get_calibrated_clock
|
||||||
|
// Access: public
|
||||||
|
// Description: Returns the value of the calibrated clock.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
INLINE double OpenALAudioSound::
|
||||||
|
get_calibrated_clock(double rtc) const {
|
||||||
|
return (rtc - _calibrated_clock_base) * _calibrated_clock_scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: OpenALAudioSound::require_sound_data
|
||||||
|
// Access: Private
|
||||||
|
// Description: Makes sure the sound data record is present,
|
||||||
|
// and if not, obtains it.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void OpenALAudioSound::
|
||||||
|
require_sound_data() {
|
||||||
|
if (_sd==0) {
|
||||||
|
_sd = _manager->get_sound_data(_movie);
|
||||||
|
if (_sd==0) {
|
||||||
|
audio_error("Could not open audio " << _movie->get_filename());
|
||||||
|
cleanup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: OpenALAudioSound::release_sound_data
|
||||||
|
// Access: Private
|
||||||
|
// Description: Checks if the sound data record is present and
|
||||||
|
// releasable, and if so, releases it.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void OpenALAudioSound::
|
||||||
|
release_sound_data() {
|
||||||
|
if ((_sd!=0) && (!_movie->get_filename().empty())) {
|
||||||
|
_manager->decrement_client_count(_sd);
|
||||||
|
_sd = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -45,42 +45,48 @@ TypeHandle OpenALAudioSound::_type_handle;
|
|||||||
|
|
||||||
OpenALAudioSound::
|
OpenALAudioSound::
|
||||||
OpenALAudioSound(OpenALAudioManager* manager,
|
OpenALAudioSound(OpenALAudioManager* manager,
|
||||||
const Filename &path,
|
MovieAudio *movie,
|
||||||
PT(MovieAudioCursor) stream,
|
|
||||||
OpenALAudioManager::SoundData *sample,
|
|
||||||
bool positional) :
|
bool positional) :
|
||||||
_sample(sample),
|
_movie(movie),
|
||||||
_stream(stream),
|
_sd(NULL),
|
||||||
|
_loops_completed(0),
|
||||||
|
_playing_rate(0.0),
|
||||||
|
_playing_loops(0),
|
||||||
_source(0),
|
_source(0),
|
||||||
_manager(manager),
|
_manager(manager),
|
||||||
_path(path),
|
_basename(movie->get_filename().get_basename()),
|
||||||
_volume(1.0f),
|
_volume(1.0f),
|
||||||
_balance(0),
|
_balance(0),
|
||||||
_play_rate(1.0),
|
|
||||||
_loop_count(1),
|
_loop_count(1),
|
||||||
|
_length(0.0),
|
||||||
|
_start_time(0.0),
|
||||||
|
_play_rate(1.0),
|
||||||
|
_current_time(0.0),
|
||||||
_active(true),
|
_active(true),
|
||||||
_paused(false)
|
_paused(false)
|
||||||
{
|
{
|
||||||
//Inits 3D Attributes
|
|
||||||
|
|
||||||
_location[0] = 0;
|
_location[0] = 0;
|
||||||
_location[1] = 0;
|
_location[1] = 0;
|
||||||
_location[2] = 0;
|
_location[2] = 0;
|
||||||
|
|
||||||
_velocity[0] = 0;
|
_velocity[0] = 0;
|
||||||
_velocity[1] = 0;
|
_velocity[1] = 0;
|
||||||
_velocity[2] = 0;
|
_velocity[2] = 0;
|
||||||
|
|
||||||
_min_dist = 3.28f; _max_dist = 1000000000.0f;
|
_min_dist = 3.28f; _max_dist = 1000000000.0f;
|
||||||
_drop_off_factor = 1.0f;
|
_drop_off_factor = 1.0f;
|
||||||
|
|
||||||
_positional = positional;
|
_positional = positional;
|
||||||
if (_positional) {
|
|
||||||
if ((_sample && (_sample->_channels != 1)) ||
|
require_sound_data();
|
||||||
(_stream && (_stream->audio_channels() != 1))) {
|
if (_manager == 0) return;
|
||||||
audio_warning("Stereo sounds won't be spacialized: "<<path);
|
_length = _sd->_length;
|
||||||
|
if (positional) {
|
||||||
|
if (_sd->_channels != 1) {
|
||||||
|
audio_warning("stereo sound " << movie->get_filename() << " will not be spatialized");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
release_sound_data();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -108,13 +114,12 @@ cleanup() {
|
|||||||
if (_source) {
|
if (_source) {
|
||||||
stop();
|
stop();
|
||||||
}
|
}
|
||||||
if (_sample) {
|
if (_sd) {
|
||||||
_manager->decrement_client_count(_sample);
|
_manager->decrement_client_count(_sd);
|
||||||
_sample = 0;
|
_sd = 0;
|
||||||
}
|
}
|
||||||
_manager->release_sound(this);
|
_manager->release_sound(this);
|
||||||
_manager = 0;
|
_manager = 0;
|
||||||
_active = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -124,9 +129,72 @@ cleanup() {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void OpenALAudioSound::
|
void OpenALAudioSound::
|
||||||
play() {
|
play() {
|
||||||
set_time(0.0);
|
if (_manager == 0) return;
|
||||||
}
|
|
||||||
|
|
||||||
|
float px,py,pz,vx,vy,vz;
|
||||||
|
|
||||||
|
if (!_active) {
|
||||||
|
_paused = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
stop();
|
||||||
|
|
||||||
|
require_sound_data();
|
||||||
|
if (_manager == 0) return;
|
||||||
|
_manager->starting_sound(this);
|
||||||
|
|
||||||
|
if (!_source) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_manager->make_current();
|
||||||
|
|
||||||
|
alGetError(); // clear errors
|
||||||
|
|
||||||
|
// nonpositional sources are made relative to the listener so they don't move
|
||||||
|
alSourcei(_source,AL_SOURCE_RELATIVE,_positional?AL_FALSE:AL_TRUE);
|
||||||
|
al_audio_errcheck("alSourcei(_source,AL_SOURCE_RELATIVE)");
|
||||||
|
|
||||||
|
// set source properties that we have stored
|
||||||
|
set_volume(_volume);
|
||||||
|
//set_balance(_balance);
|
||||||
|
|
||||||
|
set_3d_min_distance(_min_dist);
|
||||||
|
set_3d_max_distance(_max_dist);
|
||||||
|
set_3d_drop_off_factor(_drop_off_factor);
|
||||||
|
get_3d_attributes(&px,&py,&pz,&vx,&vy,&vz);
|
||||||
|
set_3d_attributes(px, py, pz, vx, vy, vz);
|
||||||
|
|
||||||
|
_playing_loops = _loop_count;
|
||||||
|
if (_playing_loops == 0) {
|
||||||
|
_playing_loops = 1000000000;
|
||||||
|
}
|
||||||
|
_loops_completed = 0;
|
||||||
|
|
||||||
|
double play_rate = _play_rate * _manager->get_play_rate();
|
||||||
|
audio_debug("playing. Rate=" << play_rate);
|
||||||
|
alSourcef(_source, AL_PITCH, play_rate);
|
||||||
|
_playing_rate = play_rate;
|
||||||
|
|
||||||
|
if (_sd->_sample) {
|
||||||
|
push_fresh_buffers();
|
||||||
|
alSourcef(_source, AL_SEC_OFFSET, _start_time);
|
||||||
|
_stream_queued[0]._time_offset = _start_time;
|
||||||
|
restart_stalled_audio();
|
||||||
|
} else {
|
||||||
|
audio_debug("Play: stream tell = " << _sd->_stream->tell() << " seeking " << _start_time);
|
||||||
|
if (_sd->_stream->tell() != _start_time) {
|
||||||
|
_sd->_stream->seek(_start_time);
|
||||||
|
}
|
||||||
|
push_fresh_buffers();
|
||||||
|
restart_stalled_audio();
|
||||||
|
}
|
||||||
|
double rtc = TrueClock::get_global_ptr()->get_short_time();
|
||||||
|
set_calibrated_clock(rtc, _start_time, 1.0);
|
||||||
|
_current_time = _start_time;
|
||||||
|
_start_time = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: OpenALAudioSound::stop
|
// Function: OpenALAudioSound::stop
|
||||||
@ -135,24 +203,28 @@ play() {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void OpenALAudioSound::
|
void OpenALAudioSound::
|
||||||
stop() {
|
stop() {
|
||||||
openal_audio_debug("stop()");
|
if (_manager==0) return;
|
||||||
//nassertv(_source);
|
|
||||||
|
|
||||||
if (_source) {
|
if (_source) {
|
||||||
_manager->make_current();
|
_manager->make_current();
|
||||||
|
|
||||||
alGetError(); // clear errors
|
alGetError(); // clear errors
|
||||||
alSourceStop(_source);
|
alSourceStop(_source);
|
||||||
al_audio_errcheck("alSourceStop(_source)");
|
al_audio_errcheck("stopping a source");
|
||||||
|
alSourcei(_source, AL_BUFFER, 0);
|
||||||
|
al_audio_errcheck("clear source buffers");
|
||||||
|
for (int i=0; i<((int)(_stream_queued.size())); i++) {
|
||||||
|
ALuint buffer = _stream_queued[i]._buffer;
|
||||||
|
if (buffer != _sd->_sample) {
|
||||||
|
alDeleteBuffers(1, &buffer);
|
||||||
|
al_audio_errcheck("deleting a buffer");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_stream_queued.resize(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
_manager->stopping_sound(this);
|
_manager->stopping_sound(this);
|
||||||
// The _paused flag should not be cleared here. _paused is not like
|
release_sound_data();
|
||||||
// the Pause button on a cd/dvd player. It is used as a flag to say
|
|
||||||
// that it was looping when it was set inactive. There is no need to
|
|
||||||
// make this symmetrical with play(). set_active() is the 'owner' of
|
|
||||||
// _paused. play() accesses _paused to help in the situation where
|
|
||||||
// someone calls play on an inactive sound().
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -162,8 +234,8 @@ stop() {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void OpenALAudioSound::
|
void OpenALAudioSound::
|
||||||
finished() {
|
finished() {
|
||||||
openal_audio_debug("finished()");
|
stop();
|
||||||
_manager->stopping_sound(this);
|
_current_time = _length;
|
||||||
if (!_finished_event.empty()) {
|
if (!_finished_event.empty()) {
|
||||||
throw_event(_finished_event);
|
throw_event(_finished_event);
|
||||||
}
|
}
|
||||||
@ -186,7 +258,7 @@ set_loop(bool loop) {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
bool OpenALAudioSound::
|
bool OpenALAudioSound::
|
||||||
get_loop() const {
|
get_loop() const {
|
||||||
return (_loop_count != 1);
|
return (_loop_count == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -196,27 +268,12 @@ get_loop() const {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void OpenALAudioSound::
|
void OpenALAudioSound::
|
||||||
set_loop_count(unsigned long loop_count) {
|
set_loop_count(unsigned long loop_count) {
|
||||||
openal_audio_debug("set_loop_count(loop_count="<<loop_count<<")");
|
if (_manager==0) return;
|
||||||
|
|
||||||
if (loop_count>1) {
|
|
||||||
audio_error("OpenALAudioSound::set_loop_count() doesn't support looping a finite number of times, 0 (infinite) or 1 only");
|
|
||||||
loop_count = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_loop_count==loop_count) {
|
if (loop_count >= 1000000000) {
|
||||||
return;
|
loop_count = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
_loop_count=loop_count;
|
_loop_count=loop_count;
|
||||||
|
|
||||||
if (_source) {
|
|
||||||
// I believe there is a race condition here.
|
|
||||||
_manager->make_current();
|
|
||||||
|
|
||||||
alGetError(); // clear errors
|
|
||||||
alSourcei(_source,AL_LOOPING,_loop_count==0?AL_TRUE:AL_FALSE);
|
|
||||||
al_audio_errcheck("alSourcei(_source,AL_LOOPING)");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -229,70 +286,250 @@ get_loop_count() const {
|
|||||||
return _loop_count;
|
return _loop_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: OpenALAudioSound::restart_stalled_audio
|
||||||
|
// Access: public
|
||||||
|
// Description: When streaming audio, the computer is supposed to
|
||||||
|
// keep OpenAL's queue full. However, there are times
|
||||||
|
// when the computer is running slow and the queue
|
||||||
|
// empties prematurely. In that case, OpenAL will stop.
|
||||||
|
// When the computer finally gets around to refilling
|
||||||
|
// the queue, it is necessary to tell OpenAL to resume
|
||||||
|
// playing.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void OpenALAudioSound::
|
||||||
|
restart_stalled_audio() {
|
||||||
|
ALenum status;
|
||||||
|
if (_stream_queued.size() == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
alGetError();
|
||||||
|
alGetSourcei(_source, AL_SOURCE_STATE, &status);
|
||||||
|
if (status != AL_PLAYING) {
|
||||||
|
alSourcePlay(_source);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: OpenALAudioSound::queue_buffer
|
||||||
|
// Access: public
|
||||||
|
// Description: Pushes a buffer into the source queue.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void OpenALAudioSound::
|
||||||
|
queue_buffer(ALuint buffer, int loop_index, double time_offset) {
|
||||||
|
// Now push the buffer into the stream queue.
|
||||||
|
alGetError();
|
||||||
|
alSourceQueueBuffers(_source,1,&buffer);
|
||||||
|
ALenum err = alGetError();
|
||||||
|
if (err != AL_NO_ERROR) {
|
||||||
|
audio_error("could not load sample buffer into the queue");
|
||||||
|
cleanup();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
QueuedBuffer buf;
|
||||||
|
buf._buffer = buffer;
|
||||||
|
buf._loop_index = loop_index;
|
||||||
|
buf._time_offset = time_offset;
|
||||||
|
_stream_queued.push_back(buf);
|
||||||
|
// audio_debug("Buffer queued " << loop_index << " " << time_offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: OpenALAudioSound::make_buffer
|
||||||
|
// Access: public
|
||||||
|
// Description: Creates an OpenAL buffer object.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
ALuint OpenALAudioSound::
|
||||||
|
make_buffer(int samples, int channels, int rate, unsigned char *data) {
|
||||||
|
|
||||||
|
// Allocate a buffer to hold the data.
|
||||||
|
alGetError();
|
||||||
|
ALuint buffer;
|
||||||
|
alGenBuffers(1, &buffer);
|
||||||
|
if (alGetError() != AL_NO_ERROR) {
|
||||||
|
audio_error("could not allocate an OpenAL buffer object");
|
||||||
|
cleanup();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now fill the buffer with the data provided.
|
||||||
|
alBufferData(buffer,
|
||||||
|
(channels>1) ? AL_FORMAT_STEREO16 : AL_FORMAT_MONO16,
|
||||||
|
data, samples * channels * 2, rate);
|
||||||
|
int err = alGetError();
|
||||||
|
if (err != AL_NO_ERROR) {
|
||||||
|
audio_error("could not fill OpenAL buffer object with data");
|
||||||
|
cleanup();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: OpenALAudioSound::read_stream_data
|
||||||
|
// Access: public
|
||||||
|
// Description: Fills a buffer with data from the stream.
|
||||||
|
// Returns the number of samples stored in the buffer.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
int OpenALAudioSound::
|
||||||
|
read_stream_data(int bytelen, unsigned char *buffer) {
|
||||||
|
|
||||||
|
MovieAudioCursor *cursor = _sd->_stream;
|
||||||
|
double length = cursor->length();
|
||||||
|
int channels = cursor->audio_channels();
|
||||||
|
int rate = cursor->audio_rate();
|
||||||
|
int space = bytelen / (channels * 2);
|
||||||
|
int fill = 0;
|
||||||
|
|
||||||
|
while (space && (_loops_completed < _playing_loops)) {
|
||||||
|
double t = cursor->tell();
|
||||||
|
double remain = length - t;
|
||||||
|
if (remain > 60.0) {
|
||||||
|
remain = 60.0;
|
||||||
|
}
|
||||||
|
int samples = (int)(remain * rate);
|
||||||
|
if (samples <= 0) {
|
||||||
|
_loops_completed += 1;
|
||||||
|
cursor->seek(0.0);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (samples > space) {
|
||||||
|
samples = space;
|
||||||
|
}
|
||||||
|
cursor->read_samples(samples, (PN_int16 *)buffer);
|
||||||
|
size_t hval = AddHash::add_hash(0, (PN_uint8*)buffer, samples*channels*2);
|
||||||
|
audio_debug("Streaming " << cursor->get_source()->get_filename().get_basename() << " at " << t << " hash " << hval);
|
||||||
|
fill += samples;
|
||||||
|
space -= samples;
|
||||||
|
buffer += (samples * channels * 2);
|
||||||
|
}
|
||||||
|
return fill;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: OpenALAudioSound::correct_calibrated_clock
|
||||||
|
// Access: public
|
||||||
|
// Description: Compares the specified time to the value of the
|
||||||
|
// calibrated clock, and adjusts the calibrated
|
||||||
|
// clock speed to make it closer to the target value.
|
||||||
|
// This routine is quite careful to make sure that
|
||||||
|
// the calibrated clock moves in a smooth, monotonic
|
||||||
|
// way.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void OpenALAudioSound::
|
||||||
|
correct_calibrated_clock(double rtc, double t) {
|
||||||
|
double cc = (rtc - _calibrated_clock_base) * _calibrated_clock_scale;
|
||||||
|
double diff = cc-t;
|
||||||
|
_calibrated_clock_decavg = (_calibrated_clock_decavg * 0.95) + (diff * 0.05);
|
||||||
|
if (diff > 0.5) {
|
||||||
|
set_calibrated_clock(rtc, t, 1.0);
|
||||||
|
_calibrated_clock_decavg = 0.0;
|
||||||
|
} else {
|
||||||
|
double scale = 1.0;
|
||||||
|
if ((_calibrated_clock_decavg > 0.01) && (diff > 0.01)) {
|
||||||
|
scale = 0.98;
|
||||||
|
}
|
||||||
|
if ((_calibrated_clock_decavg < -0.01) && (diff < -0.01)) {
|
||||||
|
scale = 1.03;
|
||||||
|
}
|
||||||
|
if ((_calibrated_clock_decavg < -0.05) && (diff < -0.05)) {
|
||||||
|
scale = 1.2;
|
||||||
|
}
|
||||||
|
if ((_calibrated_clock_decavg < -0.15) && (diff < -0.15)) {
|
||||||
|
scale = 1.5;
|
||||||
|
}
|
||||||
|
set_calibrated_clock(rtc, cc, scale);
|
||||||
|
}
|
||||||
|
cc = (rtc - _calibrated_clock_base) * _calibrated_clock_scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: OpenALAudioSound::pull_used_buffers
|
||||||
|
// Access: public
|
||||||
|
// Description: Pulls any used buffers out of OpenAL's queue.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void OpenALAudioSound::
|
||||||
|
pull_used_buffers() {
|
||||||
|
while (_stream_queued.size()) {
|
||||||
|
ALuint buffer = 0;
|
||||||
|
alGetError();
|
||||||
|
alSourceUnqueueBuffers(_source, 1, &buffer);
|
||||||
|
int err = alGetError();
|
||||||
|
if (err == AL_NO_ERROR) {
|
||||||
|
if (_stream_queued[0]._buffer != buffer) {
|
||||||
|
audio_error("corruption in stream queue");
|
||||||
|
cleanup();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_stream_queued.pop_front();
|
||||||
|
if (_stream_queued.size()) {
|
||||||
|
double al = _stream_queued[0]._time_offset + _stream_queued[0]._loop_index * _length;
|
||||||
|
double rtc = TrueClock::get_global_ptr()->get_short_time();
|
||||||
|
correct_calibrated_clock(rtc, al);
|
||||||
|
}
|
||||||
|
if (buffer != _sd->_sample) {
|
||||||
|
alDeleteBuffers(1,&buffer);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: OpenALAudioSound::push_fresh_buffers
|
||||||
|
// Access: public
|
||||||
|
// Description: Pushes fresh buffers into OpenAL's queue until
|
||||||
|
// the queue is "full" (ie, has plenty of data).
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void OpenALAudioSound::
|
||||||
|
push_fresh_buffers() {
|
||||||
|
static unsigned char data[65536];
|
||||||
|
|
||||||
|
if (_sd->_sample) {
|
||||||
|
while ((_loops_completed < _playing_loops) &&
|
||||||
|
(_stream_queued.size() < 100)) {
|
||||||
|
queue_buffer(_sd->_sample, _loops_completed, 0.0);
|
||||||
|
_loops_completed += 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
MovieAudioCursor *cursor = _sd->_stream;
|
||||||
|
int channels = cursor->audio_channels();
|
||||||
|
int rate = cursor->audio_rate();
|
||||||
|
double space = 65536 / (channels * 2);
|
||||||
|
|
||||||
|
// Calculate how many buffers to keep in the queue.
|
||||||
|
int fill_to = (int)((audio_buffering_seconds * rate) / space) + 1;
|
||||||
|
if (fill_to < 3) {
|
||||||
|
fill_to = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((_loops_completed < _playing_loops) &&
|
||||||
|
(((int)(_stream_queued.size())) < fill_to)) {
|
||||||
|
int loop_index = _loops_completed;
|
||||||
|
double time_offset = cursor->tell();
|
||||||
|
int samples = read_stream_data(65536, data);
|
||||||
|
if (samples == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ALuint buffer = make_buffer(samples, channels, rate, data);
|
||||||
|
if (_manager == 0) return;
|
||||||
|
queue_buffer(buffer, loop_index, time_offset);
|
||||||
|
if (_manager == 0) return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: OpenALAudioSound::set_time
|
// Function: OpenALAudioSound::set_time
|
||||||
// Access: public
|
// Access: public
|
||||||
// Description: Sets the play position within the sound
|
// Description: The next time you call play, the sound will
|
||||||
|
// start from the specified offset.
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void OpenALAudioSound::
|
void OpenALAudioSound::
|
||||||
set_time(float time) {
|
set_time(float time) {
|
||||||
float px,py,pz,vx,vy,vz;
|
_start_time = time;
|
||||||
|
|
||||||
openal_audio_debug("play()");
|
|
||||||
if (!_active) {
|
|
||||||
_paused=true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (status() == AudioSound::PLAYING) {
|
|
||||||
stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
_manager->starting_sound(this);
|
|
||||||
|
|
||||||
if (!_source) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Setup source
|
|
||||||
_manager->make_current();
|
|
||||||
|
|
||||||
alGetError(); // clear errors
|
|
||||||
|
|
||||||
// Assign the buffer to the source
|
|
||||||
alSourcei(_source,AL_BUFFER,_sample->_buffer);
|
|
||||||
ALenum result = alGetError();
|
|
||||||
if (result!=AL_NO_ERROR) {
|
|
||||||
audio_error("alSourcei(_source,AL_BUFFER,_sample->_buffer): " << alGetString(result) );
|
|
||||||
stop();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// nonpositional sources are made relative to the listener so they don't move
|
|
||||||
alSourcei(_source,AL_SOURCE_RELATIVE,_positional?AL_FALSE:AL_TRUE);
|
|
||||||
al_audio_errcheck("alSourcei(_source,AL_SOURCE_RELATIVE)");
|
|
||||||
|
|
||||||
// set source properties that we have stored
|
|
||||||
set_volume(_volume);
|
|
||||||
//set_balance(_balance);
|
|
||||||
set_play_rate(_play_rate);
|
|
||||||
set_3d_min_distance(_min_dist);
|
|
||||||
set_3d_max_distance(_max_dist);
|
|
||||||
set_3d_drop_off_factor(_drop_off_factor);
|
|
||||||
get_3d_attributes(&px,&py,&pz,&vx,&vy,&vz);
|
|
||||||
set_3d_attributes(px, py, pz, vx, vy, vz);
|
|
||||||
|
|
||||||
set_loop_count(_loop_count);
|
|
||||||
|
|
||||||
openal_audio_debug("set_time(time="<<time<<")");
|
|
||||||
|
|
||||||
alSourcef(_source,AL_SEC_OFFSET,time);
|
|
||||||
al_audio_errcheck("alSourcef(_source,AL_SEC_OFFSET)");
|
|
||||||
|
|
||||||
alSourcePlay(_source);
|
|
||||||
al_audio_errcheck("alSourcePlay(_source)");
|
|
||||||
|
|
||||||
audio_debug(" started sound " << _path );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -302,18 +539,27 @@ set_time(float time) {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
float OpenALAudioSound::
|
float OpenALAudioSound::
|
||||||
get_time() const {
|
get_time() const {
|
||||||
float time;
|
if (_manager == 0) {
|
||||||
|
|
||||||
if (_source) {
|
|
||||||
_manager->make_current();
|
|
||||||
alGetError(); // clear errors
|
|
||||||
alGetSourcef(_source,AL_SEC_OFFSET,&time);
|
|
||||||
al_audio_errcheck("alGetSourcef(_source,AL_SEC_OFFSET)");
|
|
||||||
} else {
|
|
||||||
return 0.0;
|
return 0.0;
|
||||||
}
|
}
|
||||||
|
return _current_time;
|
||||||
return time;
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: OpenALAudioSound::cache_time
|
||||||
|
// Access: Private
|
||||||
|
// Description: Updates the current_time field of a playing sound.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void OpenALAudioSound::
|
||||||
|
cache_time(double rtc) {
|
||||||
|
assert(_source != 0);
|
||||||
|
double t=get_calibrated_clock(rtc);
|
||||||
|
double max = _length * _playing_loops;
|
||||||
|
if (t >= max) {
|
||||||
|
_current_time = _length;
|
||||||
|
} else {
|
||||||
|
_current_time = fmod(t, _length);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -324,17 +570,11 @@ get_time() const {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void OpenALAudioSound::
|
void OpenALAudioSound::
|
||||||
set_volume(float volume) {
|
set_volume(float volume) {
|
||||||
openal_audio_debug("set_volume(volume="<<volume<<")");
|
|
||||||
|
|
||||||
//nassertv(_source);
|
|
||||||
|
|
||||||
_volume=volume;
|
_volume=volume;
|
||||||
|
|
||||||
if (_source) {
|
if (_source) {
|
||||||
volume*=_manager->get_volume();
|
volume*=_manager->get_volume();
|
||||||
|
|
||||||
_manager->make_current();
|
_manager->make_current();
|
||||||
|
|
||||||
alGetError(); // clear errors
|
alGetError(); // clear errors
|
||||||
alSourcef(_source,AL_GAIN,volume);
|
alSourcef(_source,AL_GAIN,volume);
|
||||||
al_audio_errcheck("alSourcef(_source,AL_GAIN)");
|
al_audio_errcheck("alSourcef(_source,AL_GAIN)");
|
||||||
@ -348,7 +588,6 @@ set_volume(float volume) {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
float OpenALAudioSound::
|
float OpenALAudioSound::
|
||||||
get_volume() const {
|
get_volume() const {
|
||||||
openal_audio_debug("get_volume() returning "<<_volume);
|
|
||||||
return _volume;
|
return _volume;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -384,21 +623,7 @@ get_balance() const {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void OpenALAudioSound::
|
void OpenALAudioSound::
|
||||||
set_play_rate(float play_rate) {
|
set_play_rate(float play_rate) {
|
||||||
openal_audio_debug("set_play_rate(play_rate="<<play_rate<<")");
|
_play_rate = play_rate;
|
||||||
|
|
||||||
//nassertv(_source);
|
|
||||||
|
|
||||||
_play_rate=play_rate;
|
|
||||||
|
|
||||||
if (_source) {
|
|
||||||
play_rate*=_manager->get_play_rate();
|
|
||||||
|
|
||||||
_manager->make_current();
|
|
||||||
|
|
||||||
alGetError(); // clear errors
|
|
||||||
alSourcef(_source,AL_PITCH,play_rate);
|
|
||||||
al_audio_errcheck("alSourcef(_source,AL_PITCH)");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -408,7 +633,6 @@ set_play_rate(float play_rate) {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
float OpenALAudioSound::
|
float OpenALAudioSound::
|
||||||
get_play_rate() const {
|
get_play_rate() const {
|
||||||
openal_audio_debug("get_play_rate() returning "<<_play_rate);
|
|
||||||
return _play_rate;
|
return _play_rate;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -419,23 +643,24 @@ get_play_rate() const {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
float OpenALAudioSound::
|
float OpenALAudioSound::
|
||||||
length() const {
|
length() const {
|
||||||
return _sample->_length;
|
return _length;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: OpenALAudioSound::set_3d_attributes
|
// Function: OpenALAudioSound::set_3d_attributes
|
||||||
// Access: public
|
// Access: public
|
||||||
// Description: Set position and velocity of this sound
|
// Description: Set position and velocity of this sound
|
||||||
// NOW LISTEN UP!!! THIS IS IMPORTANT!
|
//
|
||||||
// Both Panda3D and OpenAL use a right handed coordinate system.
|
// Both Panda3D and OpenAL use a right handed
|
||||||
// But there is a major difference!
|
// coordinate system. However, in Panda3D the
|
||||||
// In Panda3D the Y-Axis is going into the Screen and the Z-Axis is going up.
|
// Y-Axis is going into the Screen and the
|
||||||
// In OpenAL the Y-Axis is going up and the Z-Axis is coming out of the screen.
|
// Z-Axis is going up. In OpenAL the Y-Axis is
|
||||||
// The solution is simple, we just flip the Y and Z axis and negate the Z, as we move coordinates
|
// going up and the Z-Axis is coming out of
|
||||||
// from Panda to OpenAL and back.
|
// the screen.
|
||||||
// What does did mean to average Panda user? Nothing, they shouldn't notice anyway.
|
//
|
||||||
// But if you decide to do any 3D audio work in here you have to keep it in mind.
|
// The solution is simple, we just flip the Y
|
||||||
// I told you, so you can't say I didn't.
|
// and Z axis and negate the Z, as we move
|
||||||
|
// coordinates from Panda to OpenAL and back.
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void OpenALAudioSound::
|
void OpenALAudioSound::
|
||||||
set_3d_attributes(float px, float py, float pz, float vx, float vy, float vz) {
|
set_3d_attributes(float px, float py, float pz, float vx, float vy, float vz) {
|
||||||
@ -572,14 +797,11 @@ get_3d_drop_off_factor() const {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void OpenALAudioSound::
|
void OpenALAudioSound::
|
||||||
set_active(bool active) {
|
set_active(bool active) {
|
||||||
openal_audio_debug("set_active(active="<<active<<")");
|
|
||||||
if (_active!=active) {
|
if (_active!=active) {
|
||||||
_active=active;
|
_active=active;
|
||||||
if (_active) {
|
if (_active) {
|
||||||
// ...activate the sound.
|
// ...activate the sound.
|
||||||
if (_paused
|
if (_paused && _loop_count==0) {
|
||||||
&&
|
|
||||||
_loop_count==0) {
|
|
||||||
// ...this sound was looping when it was paused.
|
// ...this sound was looping when it was paused.
|
||||||
_paused=false;
|
_paused=false;
|
||||||
play();
|
play();
|
||||||
@ -605,7 +827,6 @@ set_active(bool active) {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
bool OpenALAudioSound::
|
bool OpenALAudioSound::
|
||||||
get_active() const {
|
get_active() const {
|
||||||
openal_audio_debug("get_active() returning "<<_active);
|
|
||||||
return _active;
|
return _active;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -616,7 +837,6 @@ get_active() const {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void OpenALAudioSound::
|
void OpenALAudioSound::
|
||||||
set_finished_event(const string& event) {
|
set_finished_event(const string& event) {
|
||||||
openal_audio_debug("set_finished_event(event="<<event<<")");
|
|
||||||
_finished_event = event;
|
_finished_event = event;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -627,7 +847,6 @@ set_finished_event(const string& event) {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
const string& OpenALAudioSound::
|
const string& OpenALAudioSound::
|
||||||
get_finished_event() const {
|
get_finished_event() const {
|
||||||
openal_audio_debug("get_finished_event() returning "<<_finished_event);
|
|
||||||
return _finished_event;
|
return _finished_event;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -638,33 +857,29 @@ get_finished_event() const {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
const string& OpenALAudioSound::
|
const string& OpenALAudioSound::
|
||||||
get_name() const {
|
get_name() const {
|
||||||
return _path;
|
return _basename;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: OpenALAudioSound::status
|
// Function: OpenALAudioSound::status
|
||||||
// Access: public
|
// Access: public
|
||||||
// Description: Get status of the sound.
|
// Description: Get status of the sound.
|
||||||
|
//
|
||||||
|
// This returns the status as of the
|
||||||
|
// last AudioManager::update.
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
AudioSound::SoundStatus OpenALAudioSound::
|
AudioSound::SoundStatus OpenALAudioSound::
|
||||||
status() const {
|
status() const {
|
||||||
ALenum status;
|
|
||||||
|
|
||||||
if (_source==0) {
|
if (_source==0) {
|
||||||
//return AudioSound::BAD;
|
|
||||||
return AudioSound::READY;
|
return AudioSound::READY;
|
||||||
}
|
}
|
||||||
|
|
||||||
_manager->make_current();
|
_manager->make_current();
|
||||||
|
|
||||||
alGetError(); // clear errors
|
if (_stream_queued.size() == 0) {
|
||||||
alGetSourcei(_source,AL_SOURCE_STATE,&status);
|
|
||||||
al_audio_errcheck("alGetSourcei(_source,AL_SOURCE_STATE)");
|
|
||||||
|
|
||||||
if (status == AL_PLAYING/* || status == AL_PAUSED*/) {
|
|
||||||
return AudioSound::PLAYING;
|
|
||||||
} else {
|
|
||||||
return AudioSound::READY;
|
return AudioSound::READY;
|
||||||
|
} else {
|
||||||
|
return AudioSound::PLAYING;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
|
|
||||||
#include "audioSound.h"
|
#include "audioSound.h"
|
||||||
#include "movieAudioCursor.h"
|
#include "movieAudioCursor.h"
|
||||||
|
#include "trueClock.h"
|
||||||
|
|
||||||
#include <al.h>
|
#include <al.h>
|
||||||
#include <alc.h>
|
#include <alc.h>
|
||||||
@ -89,7 +90,7 @@ public:
|
|||||||
const string& get_finished_event() const;
|
const string& get_finished_event() const;
|
||||||
|
|
||||||
const string &get_name() const;
|
const string &get_name() const;
|
||||||
|
|
||||||
// return: playing time in seconds.
|
// return: playing time in seconds.
|
||||||
float length() const;
|
float length() const;
|
||||||
|
|
||||||
@ -114,18 +115,39 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
OpenALAudioSound(OpenALAudioManager* manager,
|
OpenALAudioSound(OpenALAudioManager* manager,
|
||||||
const Filename &path,
|
MovieAudio *movie,
|
||||||
PT(MovieAudioCursor) cursor,
|
|
||||||
OpenALAudioManager::SoundData *sd,
|
|
||||||
bool positional);
|
bool positional);
|
||||||
|
INLINE void set_calibrated_clock(double rtc, double t, double playrate);
|
||||||
|
INLINE double get_calibrated_clock(double rtc) const;
|
||||||
|
void correct_calibrated_clock(double rtc, double t);
|
||||||
|
void cache_time(double rtc);
|
||||||
void cleanup();
|
void cleanup();
|
||||||
|
void restart_stalled_audio();
|
||||||
|
void delete_queued_buffers();
|
||||||
|
ALuint make_buffer(int samples, int channels, int rate, unsigned char *data);
|
||||||
|
void queue_buffer(ALuint buffer, int loop_index, double time_offset);
|
||||||
|
int read_stream_data(int bytelen, unsigned char *data);
|
||||||
|
void pull_used_buffers();
|
||||||
|
void push_fresh_buffers();
|
||||||
|
INLINE void require_sound_data();
|
||||||
|
INLINE void release_sound_data();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
PT(MovieAudio) _movie;
|
||||||
|
OpenALAudioManager::SoundData *_sd;
|
||||||
|
|
||||||
// A Sound can have a sample or a stream, but not both.
|
struct QueuedBuffer {
|
||||||
OpenALAudioManager::SoundData *_sample;
|
ALuint _buffer;
|
||||||
PT(MovieAudioCursor) _stream;
|
int _loop_index;
|
||||||
ALuint _stream_buffers[3];
|
double _time_offset;
|
||||||
|
};
|
||||||
|
|
||||||
|
int _playing_loops;
|
||||||
|
float _playing_rate;
|
||||||
|
|
||||||
|
pdeque<QueuedBuffer> _stream_queued;
|
||||||
|
int _loops_completed;
|
||||||
|
|
||||||
ALuint _source;
|
ALuint _source;
|
||||||
PT(OpenALAudioManager) _manager;
|
PT(OpenALAudioManager) _manager;
|
||||||
@ -133,7 +155,7 @@ private:
|
|||||||
float _volume; // 0..1.0
|
float _volume; // 0..1.0
|
||||||
float _balance; // -1..1
|
float _balance; // -1..1
|
||||||
float _play_rate; // 0..1.0
|
float _play_rate; // 0..1.0
|
||||||
|
|
||||||
bool _positional;
|
bool _positional;
|
||||||
ALfloat _location[3];
|
ALfloat _location[3];
|
||||||
ALfloat _velocity[3];
|
ALfloat _velocity[3];
|
||||||
@ -141,28 +163,40 @@ private:
|
|||||||
float _min_dist;
|
float _min_dist;
|
||||||
float _max_dist;
|
float _max_dist;
|
||||||
float _drop_off_factor;
|
float _drop_off_factor;
|
||||||
|
|
||||||
|
double _length;
|
||||||
|
int _loop_count;
|
||||||
|
|
||||||
mutable float _length; // in seconds.
|
// The calibrated clock is initialized when the
|
||||||
unsigned long _loop_count;
|
// sound starts playing, and is periodically corrected
|
||||||
|
// thereafter.
|
||||||
|
double _calibrated_clock_base;
|
||||||
|
double _calibrated_clock_scale;
|
||||||
|
double _calibrated_clock_decavg;
|
||||||
|
|
||||||
|
// The start_time field affects the next call to play.
|
||||||
|
double _start_time;
|
||||||
|
|
||||||
|
// The current_time field is updated every frame
|
||||||
|
// during the AudioManager update. Updates need
|
||||||
|
// to be atomic, because get_time can be called
|
||||||
|
// in the cull thread.
|
||||||
|
float _current_time;
|
||||||
|
|
||||||
// This is the string that throw_event() will throw
|
// This is the string that throw_event() will throw
|
||||||
// when the sound finishes playing. It is not triggered
|
// when the sound finishes playing. It is not triggered
|
||||||
// when the sound is stopped with stop().
|
// when the sound is stopped with stop().
|
||||||
string _finished_event;
|
string _finished_event;
|
||||||
|
|
||||||
Filename _path;
|
Filename _basename;
|
||||||
|
|
||||||
// _active is for things like a 'turn off sound effects' in
|
// _active is for things like a 'turn off sound effects' in
|
||||||
// a preferences pannel.
|
// a preferences pannel.
|
||||||
// _active is not about whether a sound is currently playing.
|
// _active is not about whether a sound is currently playing.
|
||||||
// Use status() for info on whether the sound is playing.
|
// Use status() for info on whether the sound is playing.
|
||||||
bool _active;
|
bool _active;
|
||||||
|
|
||||||
// _paused is not like the Pause button on a cd/dvd player.
|
|
||||||
// It is used as a flag to say that the sound was looping when
|
|
||||||
// itwas set inactive.
|
|
||||||
bool _paused;
|
bool _paused;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static TypeHandle get_class_type() {
|
static TypeHandle get_class_type() {
|
||||||
return _type_handle;
|
return _type_handle;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user