mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-03 18:31:55 -04:00
368 lines
11 KiB
C++
368 lines
11 KiB
C++
// Filename: milesAudioSequence.cxx
|
|
// Created by: drose (31Jul07)
|
|
//
|
|
////////////////////////////////////////////////////////////////////
|
|
//
|
|
// PANDA 3D SOFTWARE
|
|
// Copyright (c) Carnegie Mellon University. All rights reserved.
|
|
//
|
|
// All use of this software is subject to the terms of the revised BSD
|
|
// license. You should have received a copy of this license along
|
|
// with this source code in a file named "LICENSE."
|
|
//
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
#include "milesAudioSequence.h"
|
|
|
|
#ifdef HAVE_RAD_MSS //[
|
|
|
|
#include "milesAudioManager.h"
|
|
|
|
|
|
TypeHandle MilesAudioSequence::_type_handle;
|
|
|
|
#undef miles_audio_debug
|
|
|
|
#ifndef NDEBUG //[
|
|
#define miles_audio_debug(x) \
|
|
audio_debug("MilesAudioSequence \""<<get_name()<<"\" "<< x )
|
|
#else //][
|
|
#define miles_audio_debug(x) ((void)0)
|
|
#endif //]
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: MilesAudioSequence::Constructor
|
|
// Access: Private
|
|
// Description: This constructor is called only by the
|
|
// MilesAudioManager.
|
|
////////////////////////////////////////////////////////////////////
|
|
MilesAudioSequence::
|
|
MilesAudioSequence(MilesAudioManager *manager, MilesAudioManager::SoundData *sd,
|
|
const string &file_name) :
|
|
MilesAudioSound(manager, file_name),
|
|
_sd(sd)
|
|
{
|
|
nassertv(sd != NULL);
|
|
audio_debug("MilesAudioSequence(manager=0x"<<(void*)&manager
|
|
<<", sd=0x"<<(void*)sd<<", file_name="<<file_name<<")");
|
|
|
|
_sequence = 0;
|
|
_sequence_index = 0;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: MilesAudioSequence::Destructor
|
|
// Access: Public, Virtual
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
MilesAudioSequence::
|
|
~MilesAudioSequence() {
|
|
miles_audio_debug("~MilesAudioSequence()");
|
|
cleanup();
|
|
_manager->release_sound(this);
|
|
miles_audio_debug("~MilesAudioSequence() done");
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: MilesAudioSequence::play
|
|
// Access: Public, Virtual
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
void MilesAudioSequence::
|
|
play() {
|
|
miles_audio_debug("play()");
|
|
if (_active) {
|
|
stop();
|
|
|
|
if (_sd->_raw_data.empty()) {
|
|
milesAudio_cat.warning()
|
|
<< "Could not play " << _file_name << ": no data\n";
|
|
} else {
|
|
_manager->starting_sound(this);
|
|
nassertv(_sequence == 0);
|
|
|
|
GlobalMilesManager *mgr = GlobalMilesManager::get_global_ptr();
|
|
if (!mgr->get_sequence(_sequence, _sequence_index, this)){
|
|
milesAudio_cat.warning()
|
|
<< "Could not play " << _file_name << ": too many open sequences\n";
|
|
_sequence = 0;
|
|
} else {
|
|
AIL_init_sequence(_sequence, &_sd->_raw_data[0], 0);
|
|
AIL_set_sequence_user_data(_sequence, 0, (SINTa)this);
|
|
AIL_register_sequence_callback(_sequence, finish_callback);
|
|
|
|
set_volume(_volume);
|
|
set_play_rate(_play_rate);
|
|
AIL_set_sequence_loop_count(_sequence, _loop_count);
|
|
|
|
if (_got_start_time) {
|
|
do_set_time(_start_time);
|
|
AIL_resume_sequence(_sequence);
|
|
} else {
|
|
AIL_start_sequence(_sequence);
|
|
}
|
|
}
|
|
|
|
_got_start_time = false;
|
|
}
|
|
} else {
|
|
// In case _loop_count gets set to forever (zero):
|
|
audio_debug(" paused "<<_file_name );
|
|
_paused = true;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: MilesAudioSequence::stop
|
|
// Access: Public, Virtual
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
void MilesAudioSequence::
|
|
stop() {
|
|
miles_audio_debug("stop()");
|
|
_manager->stopping_sound(this);
|
|
// The _paused flag should not be cleared here. _paused is not like
|
|
// 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().
|
|
|
|
if (_sequence != 0) {
|
|
AIL_end_sequence(_sequence);
|
|
|
|
GlobalMilesManager *mgr = GlobalMilesManager::get_global_ptr();
|
|
mgr->release_sequence(_sequence_index, this);
|
|
|
|
_sequence = 0;
|
|
_sequence_index = 0;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: MilesAudioSequence::get_time
|
|
// Access: Public, Virtual
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
float MilesAudioSequence::
|
|
get_time() const {
|
|
if (_sequence == 0) {
|
|
if (_got_start_time) {
|
|
return _start_time;
|
|
}
|
|
return 0.0f;
|
|
}
|
|
|
|
S32 current_ms;
|
|
AIL_sequence_ms_position(_sequence, NULL, ¤t_ms);
|
|
float time = float(current_ms * 0.001f);
|
|
|
|
return time;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: MilesAudioSequence::set_volume
|
|
// Access: Public, Virtual
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
void MilesAudioSequence::
|
|
set_volume(float volume) {
|
|
miles_audio_debug("set_volume(volume="<<volume<<")");
|
|
|
|
// Set the volume even if our volume is not changing, because the
|
|
// MilesAudioManager will call set_volume() when *its* volume
|
|
// changes.
|
|
|
|
// Set the volume:
|
|
_volume = volume;
|
|
|
|
if (_sequence != 0) {
|
|
volume *= _manager->get_volume();
|
|
|
|
// Change to Miles volume, range 0 to 127:
|
|
S32 milesVolume = (S32)(volume * 127.0f);
|
|
milesVolume = min(milesVolume, 127);
|
|
milesVolume = max(milesVolume, 0);
|
|
|
|
AIL_set_sequence_volume(_sequence, milesVolume, 0);
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: MilesAudioSequence::set_balance
|
|
// Access: Public, Virtual
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
void MilesAudioSequence::
|
|
set_balance(float balance_right) {
|
|
miles_audio_debug("set_balance(balance_right="<<balance_right<<")");
|
|
_balance = balance_right;
|
|
|
|
// Balance has no effect on a MIDI file.
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: MilesAudioSequence::set_play_rate
|
|
// Access: Public, Virtual
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
void MilesAudioSequence::
|
|
set_play_rate(float play_rate) {
|
|
miles_audio_debug("set_play_rate(play_rate="<<play_rate<<")");
|
|
|
|
// Set the play_rate:
|
|
_play_rate = play_rate;
|
|
|
|
if (_sequence != 0) {
|
|
play_rate *= _manager->get_play_rate();
|
|
|
|
S32 percent = (S32)(play_rate * 100.0f);
|
|
AIL_set_sequence_tempo(_sequence, percent, 0);
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: MilesAudioSequence::length
|
|
// Access: Public, Virtual
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
float MilesAudioSequence::
|
|
length() const {
|
|
if (_sequence == 0) {
|
|
// The MIDI file hasn't been started yet. See if the length is
|
|
// cached in the SoundData.
|
|
if (!_sd->_has_length) {
|
|
// It isn't cached, so load the sequence temporarily to
|
|
// determine its length.
|
|
((MilesAudioSequence *)this)->determine_length();
|
|
}
|
|
|
|
return _sd->get_length();
|
|
}
|
|
|
|
// The MIDI file has already been started, so we can ask it
|
|
// directly.
|
|
S32 length_ms;
|
|
AIL_sequence_ms_position(_sequence, &length_ms, NULL);
|
|
float time = (float)length_ms * 0.001f;
|
|
return time;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: MilesAudioSequence::status
|
|
// Access: Public, Virtual
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
AudioSound::SoundStatus MilesAudioSequence::
|
|
status() const {
|
|
if (_sequence == 0) {
|
|
return AudioSound::READY;
|
|
}
|
|
switch (AIL_sequence_status(_sequence)) {
|
|
case SEQ_DONE:
|
|
case SEQ_STOPPED:
|
|
case SEQ_FREE:
|
|
return AudioSound::READY;
|
|
|
|
case SEQ_PLAYING:
|
|
case SEQ_PLAYINGBUTRELEASED:
|
|
return AudioSound::PLAYING;
|
|
|
|
default:
|
|
return AudioSound::BAD;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: MilesAudioSequence::cleanup
|
|
// Access: Public, Virtual
|
|
// Description: Stops the sound from playing and releases any
|
|
// associated resources, in preparation for releasing
|
|
// the sound or shutting down the sound system.
|
|
////////////////////////////////////////////////////////////////////
|
|
void MilesAudioSequence::
|
|
cleanup() {
|
|
stop();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: MilesAudioSequence::internal_stop
|
|
// Access: Private
|
|
// Description: Called by the GlobalMilesManager when it is detected
|
|
// that this particular sound has already stopped, and
|
|
// its sequence handle will be recycled.
|
|
////////////////////////////////////////////////////////////////////
|
|
void MilesAudioSequence::
|
|
internal_stop() {
|
|
_sequence = 0;
|
|
_sequence_index = 0;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: MilesAudioSequence::finish_callback
|
|
// Access: Private, Static
|
|
// Description: This callback is made by Miles (possibly in a
|
|
// sub-thread) when the sequence finishes.
|
|
////////////////////////////////////////////////////////////////////
|
|
void AILCALLBACK MilesAudioSequence::
|
|
finish_callback(HSEQUENCE sequence) {
|
|
MilesAudioSequence *self = (MilesAudioSequence *)AIL_sequence_user_data(sequence, 0);
|
|
if (milesAudio_cat.is_debug()) {
|
|
milesAudio_cat.debug()
|
|
<< "finished " << *self << "\n";
|
|
}
|
|
self->_manager->_sounds_finished = true;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: MilesAudioSequence::do_set_time
|
|
// Access: Private
|
|
// Description: Sets the start time of an already allocated stream.
|
|
////////////////////////////////////////////////////////////////////
|
|
void MilesAudioSequence::
|
|
do_set_time(float time) {
|
|
miles_audio_debug("do_set_time(time="<<time<<")");
|
|
|
|
nassertv(_sequence != 0);
|
|
|
|
S32 time_ms = (S32)(1000.0f * time);
|
|
|
|
// Ensure we don't inadvertently run off the end of the sound.
|
|
S32 length_ms;
|
|
AIL_sequence_ms_position(_sequence, &length_ms, NULL);
|
|
time_ms = min(time_ms, length_ms);
|
|
|
|
AIL_set_sequence_ms_position(_sequence, time_ms);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: MilesAudioSequence::determine_length
|
|
// Access: Private
|
|
// Description: Temporarily loads the sequence to determine its
|
|
// length. Stores the result on the _sd.
|
|
////////////////////////////////////////////////////////////////////
|
|
void MilesAudioSequence::
|
|
determine_length() {
|
|
nassertv(_sequence == 0);
|
|
|
|
GlobalMilesManager *mgr = GlobalMilesManager::get_global_ptr();
|
|
if (!mgr->get_sequence(_sequence, _sequence_index, this)){
|
|
milesAudio_cat.warning()
|
|
<< "Could not determine length of " << _file_name << ": too many open sequences\n";
|
|
_sequence = 0;
|
|
} else {
|
|
AIL_init_sequence(_sequence, &_sd->_raw_data[0], 0);
|
|
S32 length_ms;
|
|
AIL_sequence_ms_position(_sequence, &length_ms, NULL);
|
|
float time = (float)length_ms * 0.001f;
|
|
mgr->release_sequence(_sequence_index, this);
|
|
_sequence = 0;
|
|
_sequence_index = 0;
|
|
|
|
_sd->set_length(time);
|
|
}
|
|
}
|
|
|
|
#endif //]
|