implement workarounds for VBR mp3 problem
This commit is contained in:
parent
00990fb767
commit
4ffa6f2864
|
|
@ -34,6 +34,24 @@ ConfigureFn(config_milesAudio) {
|
|||
ConfigVariableBool miles_audio_force_midi_reset
|
||||
("audio-force-midi-reset", true);
|
||||
|
||||
ConfigVariableInt miles_audio_expand_mp3_threshold
|
||||
("miles-audio-expand-mp3-threshold", 16384,
|
||||
PRC_DESC("This enables a Miles workaround in which small MP3 files are "
|
||||
"expanded in-memory at load time into WAV format, which can "
|
||||
"work around problems with Miles being unable to correctly "
|
||||
"report the length of, or seek within, a variable bit-rate encoded "
|
||||
"MP3 file. Any MP3 file whose length in bytes is less than "
|
||||
"this value will be expanded."));
|
||||
|
||||
ConfigVariableInt miles_audio_calc_mp3_threshold
|
||||
("miles-audio-calc-mp3-threshold", 1048576,
|
||||
PRC_DESC("This is a second fallback for miles-audio-expand-mp3-threshold. "
|
||||
"Any MP3 file whose length in bytes is less than this value "
|
||||
"will have its length calculated on demand, by running through "
|
||||
"the entire file first. This works around a Miles bug in "
|
||||
"which variable bit-rate encoded MP3 files do not report an "
|
||||
"accurate length."));
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: init_libMilesAudio
|
||||
// Description: Initializes the library. This must be called at
|
||||
|
|
|
|||
|
|
@ -24,12 +24,15 @@
|
|||
#ifdef HAVE_RAD_MSS //[
|
||||
#include "notifyCategoryProxy.h"
|
||||
#include "configVariableBool.h"
|
||||
#include "configVariableInt.h"
|
||||
#include "dconfig.h"
|
||||
|
||||
ConfigureDecl(config_milesAudio, EXPCL_MILES_AUDIO, EXPTP_MILES_AUDIO);
|
||||
NotifyCategoryDecl(milesAudio, EXPCL_MILES_AUDIO, EXPTP_MILES_AUDIO);
|
||||
|
||||
extern ConfigVariableBool miles_audio_force_midi_reset;
|
||||
extern ConfigVariableInt miles_audio_expand_mp3_threshold;
|
||||
extern ConfigVariableInt miles_audio_calc_mp3_threshold;
|
||||
|
||||
extern EXPCL_MILES_AUDIO void init_libMilesAudio();
|
||||
|
||||
|
|
|
|||
|
|
@ -154,13 +154,6 @@ MilesAudioManager() {
|
|||
} else {
|
||||
audio_info(" using Miles hardware midi");
|
||||
}
|
||||
|
||||
if (use_vfs) {
|
||||
AIL_set_file_callbacks(vfs_open_callback,
|
||||
vfs_close_callback,
|
||||
vfs_seek_callback,
|
||||
vfs_read_callback);
|
||||
}
|
||||
} else {
|
||||
audio_debug(" AIL_quick_startup failed: "<<AIL_last_error());
|
||||
_is_valid = false;
|
||||
|
|
@ -246,24 +239,82 @@ is_valid() {
|
|||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: MilesAudioManager::load
|
||||
// Access:
|
||||
// Description:
|
||||
// Access: Private
|
||||
// Description: Reads a sound file and allocates a SoundData pointer
|
||||
// for it. Returns NULL if the sound file cannot be
|
||||
// loaded.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
HAUDIO MilesAudioManager::
|
||||
PT(MilesAudioManager::SoundData) MilesAudioManager::
|
||||
load(Filename file_name) {
|
||||
HAUDIO audio;
|
||||
if (use_vfs) {
|
||||
audio = AIL_quick_load(file_name.c_str());
|
||||
// We used to use callbacks to hook AIL_quick_load() into the vfs
|
||||
// system directly. The theory was that that would enable
|
||||
// AIL_quick_load() to stream the file from disk, avoiding the need
|
||||
// to keep the whole thing in memory at once. But it turns out that
|
||||
// AIL_quick_load() always reads the whole file anyway, so it's a
|
||||
// moot point.
|
||||
|
||||
// Nowadays we don't mess around with that callback nonsense, and
|
||||
// just read the whole file directly. Not only is it simpler, but
|
||||
// preloading the sound files allows us to optionally convert MP3 to
|
||||
// WAV format in-memory at load time.
|
||||
|
||||
PT(SoundData) sd = new SoundData;
|
||||
|
||||
VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
|
||||
if (!vfs->read_file(file_name, sd->_raw_data)) {
|
||||
milesAudio_cat.warning()
|
||||
<< "Unable to read " << file_name << "\n";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sd->_basename = file_name.get_basename();
|
||||
sd->_file_type =
|
||||
AIL_file_type(sd->_raw_data.data(), sd->_raw_data.size());
|
||||
|
||||
bool expand_to_wav = false;
|
||||
|
||||
if (sd->_file_type != AILFILETYPE_MPEG_L3_AUDIO) {
|
||||
audio_debug(sd->_basename << " is not an mp3 file.");
|
||||
} else if ((int)sd->_raw_data.size() >= miles_audio_expand_mp3_threshold) {
|
||||
audio_debug(sd->_basename << " is too large to expand in-memory.");
|
||||
} else {
|
||||
string stmp = file_name.to_os_specific();
|
||||
audio_debug(" \"" << stmp << "\"");
|
||||
audio = AIL_quick_load(stmp.c_str());
|
||||
expand_to_wav = true;
|
||||
}
|
||||
|
||||
if (expand_to_wav) {
|
||||
// Now convert the file to WAV format in-memory. This is useful
|
||||
// to work around seek and length problems associated with
|
||||
// variable bit-rate MP3 encoding.
|
||||
void *wav_data;
|
||||
U32 wav_data_size;
|
||||
if (AIL_decompress_ASI(sd->_raw_data.data(), sd->_raw_data.size(),
|
||||
sd->_basename.c_str(), &wav_data, &wav_data_size,
|
||||
NULL)) {
|
||||
audio_debug("expanded " << sd->_basename << " from " << sd->_raw_data.size()
|
||||
<< " bytes to " << wav_data_size << " bytes.");
|
||||
|
||||
// Now copy the memory into our own buffers, and free the
|
||||
// Miles-allocated memory.
|
||||
sd->_raw_data.assign((char *)wav_data, wav_data_size);
|
||||
AIL_mem_free_lock(wav_data);
|
||||
sd->_file_type = AILFILETYPE_PCM_WAV;
|
||||
|
||||
} else {
|
||||
audio_debug("unable to expand " << sd->_basename);
|
||||
}
|
||||
}
|
||||
|
||||
sd->_audio = AIL_quick_load_mem(sd->_raw_data.data(), sd->_raw_data.size());
|
||||
|
||||
if (!audio) {
|
||||
if (!sd->_audio) {
|
||||
audio_error(" MilesAudioManager::load failed "<< AIL_last_error());
|
||||
return NULL;
|
||||
}
|
||||
return audio;
|
||||
|
||||
// We still need to keep around the raw data value, since
|
||||
// AIL_quick_load_mem() doesn't make a copy.
|
||||
|
||||
return sd;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -283,34 +334,29 @@ get_sound(const string& file_name, bool) {
|
|||
assert(is_valid());
|
||||
Filename path = file_name;
|
||||
|
||||
if (use_vfs) {
|
||||
VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
|
||||
vfs->resolve_filename(path, get_sound_path());
|
||||
} else {
|
||||
path.resolve_filename(get_sound_path());
|
||||
}
|
||||
|
||||
VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
|
||||
vfs->resolve_filename(path, get_sound_path());
|
||||
audio_debug(" resolved file_name is '"<<path<<"'");
|
||||
|
||||
HAUDIO audio=0;
|
||||
PT(SoundData) sd;
|
||||
// Get the sound, either from the cache or from a loader:
|
||||
SoundMap::const_iterator si=_sounds.find(path);
|
||||
if (si != _sounds.end()) {
|
||||
// ...found the sound in the cache.
|
||||
audio = (*si).second;
|
||||
audio_debug(" sound found in pool 0x" << (void*)audio);
|
||||
sd = (*si).second;
|
||||
audio_debug(" sound found in pool 0x" << (void*)sd);
|
||||
} else {
|
||||
// ...the sound was not found in the cache/pool.
|
||||
audio=load(path);
|
||||
if (audio) {
|
||||
sd = load(path);
|
||||
if (sd != (SoundData *)NULL) {
|
||||
while (_sounds.size() >= (unsigned int)_cache_limit) {
|
||||
uncache_a_sound();
|
||||
}
|
||||
// Put it in the pool:
|
||||
// The following is roughly like: _sounds[path] = audio;
|
||||
// The following is roughly like: _sounds[path] = sd;
|
||||
// But, it gives us an iterator into the map.
|
||||
pair<SoundMap::const_iterator, bool> ib
|
||||
=_sounds.insert(pair<string, HAUDIO>(path, audio));
|
||||
=_sounds.insert(SoundMap::value_type(path, sd));
|
||||
if (!ib.second) {
|
||||
// The insert failed.
|
||||
audio_debug(" failed map insert of "<<path);
|
||||
|
|
@ -324,10 +370,10 @@ get_sound(const string& file_name, bool) {
|
|||
}
|
||||
// Create an AudioSound from the sound:
|
||||
PT(AudioSound) audioSound = 0;
|
||||
if (audio) {
|
||||
if (sd != (SoundData *)NULL) {
|
||||
most_recently_used((*si).first);
|
||||
PT(MilesAudioSound) milesAudioSound
|
||||
=new MilesAudioSound(this, audio, (*si).first);
|
||||
=new MilesAudioSound(this, sd, (*si).first);
|
||||
nassertr(milesAudioSound, 0);
|
||||
milesAudioSound->set_active(_active);
|
||||
_sounds_on_loan.insert(milesAudioSound);
|
||||
|
|
@ -352,12 +398,8 @@ uncache_sound(const string& file_name) {
|
|||
assert(is_valid());
|
||||
Filename path = file_name;
|
||||
|
||||
if (use_vfs) {
|
||||
VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
|
||||
vfs->resolve_filename(path, get_sound_path());
|
||||
} else {
|
||||
path.resolve_filename(get_sound_path());
|
||||
}
|
||||
VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
|
||||
vfs->resolve_filename(path, get_sound_path());
|
||||
|
||||
audio_debug(" path=\""<<path<<"\"");
|
||||
SoundMap::iterator i=_sounds.find(path);
|
||||
|
|
@ -366,7 +408,6 @@ uncache_sound(const string& file_name) {
|
|||
LRU::iterator lru_i=find(_lru.begin(), _lru.end(), &(i->first));
|
||||
assert(lru_i != _lru.end());
|
||||
_lru.erase(lru_i);
|
||||
AIL_quick_unload(i->second);
|
||||
_sounds.erase(i);
|
||||
}
|
||||
assert(is_valid());
|
||||
|
|
@ -390,7 +431,6 @@ uncache_a_sound() {
|
|||
|
||||
if (i != _sounds.end()) {
|
||||
audio_debug(" uncaching \""<<i->first<<"\"");
|
||||
AIL_quick_unload(i->second);
|
||||
_sounds.erase(i);
|
||||
}
|
||||
assert(is_valid());
|
||||
|
|
@ -424,10 +464,6 @@ void MilesAudioManager::
|
|||
clear_cache() {
|
||||
audio_debug("MilesAudioManager::clear_cache()");
|
||||
if (_is_valid) { assert(is_valid()); }
|
||||
SoundMap::iterator i=_sounds.begin();
|
||||
for (; i!=_sounds.end(); ++i) {
|
||||
AIL_quick_unload(i->second);
|
||||
}
|
||||
_sounds.clear();
|
||||
_lru.clear();
|
||||
if (_is_valid) { assert(is_valid()); }
|
||||
|
|
@ -697,99 +733,75 @@ get_gm_file_path(string& result) {
|
|||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: MilesAudioManager::vfs_open_callback
|
||||
// Access: Private, Static
|
||||
// Description: A Miles callback to open a file for reading from the
|
||||
// VFS system.
|
||||
// Function: MilesAudioManager::SoundData::Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
U32 MilesAudioManager::
|
||||
vfs_open_callback(const char *filename, U32 *file_handle) {
|
||||
VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
|
||||
istream *istr = vfs->open_read_file(filename);
|
||||
if (istr == (istream *)NULL) {
|
||||
// Unable to open.
|
||||
milesAudio_cat.warning()
|
||||
<< "Unable to open " << filename << "\n";
|
||||
*file_handle = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Successfully opened. Now we should return a U32 that we can
|
||||
// map back into this istream pointer later. Strictly speaking,
|
||||
// we should allocate a table of istream pointers and assign each
|
||||
// one a unique number, but for now we'll cheat because we know
|
||||
// that the Miles code (presently) only runs on Win32, which
|
||||
// always has 32-bit pointers.
|
||||
*file_handle = (U32)istr;
|
||||
return 1;
|
||||
MilesAudioManager::SoundData::
|
||||
SoundData() :
|
||||
_audio(0),
|
||||
_has_length(false)
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: MilesAudioManager::vfs_read_callback
|
||||
// Access: Private, Static
|
||||
// Description: A Miles callback to read data from a file opened via
|
||||
// vfs_open_callback().
|
||||
// Function: MilesAudioManager::SoundData::Destructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
U32 MilesAudioManager::
|
||||
vfs_read_callback(U32 file_handle, void *buffer, U32 bytes) {
|
||||
if (file_handle == 0) {
|
||||
// File was not opened.
|
||||
return 0;
|
||||
MilesAudioManager::SoundData::
|
||||
~SoundData() {
|
||||
if (_audio != 0) {
|
||||
AIL_quick_unload(_audio);
|
||||
}
|
||||
istream *istr = (istream *)file_handle;
|
||||
istr->read((char *)buffer, bytes);
|
||||
size_t bytes_read = istr->gcount();
|
||||
|
||||
return bytes_read;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: MilesAudioManager::vfs_seek_callback
|
||||
// Access: Private, Static
|
||||
// Description: A Miles callback to seek within a file opened via
|
||||
// vfs_open_callback().
|
||||
// Function: MilesAudioManager::SoundData::Destructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
S32 MilesAudioManager::
|
||||
vfs_seek_callback(U32 file_handle, S32 offset, U32 type) {
|
||||
if (file_handle == 0) {
|
||||
// File was not opened.
|
||||
return 0;
|
||||
}
|
||||
istream *istr = (istream *)file_handle;
|
||||
float MilesAudioManager::SoundData::
|
||||
get_length() {
|
||||
if (!_has_length) {
|
||||
// Time to determine the length of the file.
|
||||
|
||||
ios::seekdir dir = ios::beg;
|
||||
switch (type) {
|
||||
case AIL_FILE_SEEK_BEGIN:
|
||||
dir = ios::beg;
|
||||
break;
|
||||
case AIL_FILE_SEEK_CURRENT:
|
||||
dir = ios::cur;
|
||||
break;
|
||||
case AIL_FILE_SEEK_END:
|
||||
dir = ios::end;
|
||||
break;
|
||||
if (_file_type == AILFILETYPE_MPEG_L3_AUDIO &&
|
||||
(int)_raw_data.size() < miles_audio_calc_mp3_threshold) {
|
||||
// If it's an mp3 file, we may not trust Miles to compute its
|
||||
// length correctly (Miles doesn't correctly compute the length
|
||||
// of VBR MP3 files). So in that case, decompress the whole
|
||||
// file to determine its precise length.
|
||||
audio_debug("Computing length of " << _basename);
|
||||
|
||||
void *wav_data;
|
||||
U32 wav_data_size;
|
||||
if (AIL_decompress_ASI(_raw_data.data(), _raw_data.size(),
|
||||
_basename.c_str(), &wav_data, &wav_data_size,
|
||||
NULL)) {
|
||||
AILSOUNDINFO info;
|
||||
if (AIL_WAV_info(wav_data, &info)) {
|
||||
_length = (float)info.samples / (float)info.rate;
|
||||
audio_debug(info.samples << " samples at " << info.rate
|
||||
<< "; length is " << _length << " seconds.");
|
||||
_has_length = true;
|
||||
}
|
||||
|
||||
AIL_mem_free_lock(wav_data);
|
||||
}
|
||||
}
|
||||
|
||||
if (!_has_length) {
|
||||
// If it's not an mp3 file, or we don't care about precalcing
|
||||
// mp3 files, just ask Miles to do it.
|
||||
_length = ((float)AIL_quick_ms_length(_audio)) * 0.001f;
|
||||
|
||||
audio_debug("Miles reports length of " << _length
|
||||
<< " for " << _basename);
|
||||
}
|
||||
}
|
||||
|
||||
istr->seekg(offset, dir);
|
||||
return istr->tellg();
|
||||
return _length;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: MilesAudioManager::vfs_close_callback
|
||||
// Access: Private, Static
|
||||
// Description: A Miles callback to close a file opened via
|
||||
// vfs_open_callback().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void MilesAudioManager::
|
||||
vfs_close_callback(U32 file_handle) {
|
||||
if (file_handle == 0) {
|
||||
// File was not opened.
|
||||
return;
|
||||
}
|
||||
istream *istr = (istream *)file_handle;
|
||||
VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
|
||||
vfs->close_read_file(istr);
|
||||
}
|
||||
|
||||
|
||||
#endif //]
|
||||
|
|
|
|||
|
|
@ -65,7 +65,20 @@ public:
|
|||
|
||||
private:
|
||||
// The sound cache:
|
||||
typedef pmap<string, HAUDIO > SoundMap;
|
||||
class SoundData : public ReferenceCount {
|
||||
public:
|
||||
SoundData();
|
||||
~SoundData();
|
||||
float get_length();
|
||||
|
||||
string _basename;
|
||||
HAUDIO _audio;
|
||||
S32 _file_type;
|
||||
string _raw_data;
|
||||
bool _has_length;
|
||||
float _length; // in seconds.
|
||||
};
|
||||
typedef pmap<string, PT(SoundData) > SoundMap;
|
||||
SoundMap _sounds;
|
||||
|
||||
typedef pset<MilesAudioSound* > AudioSet;
|
||||
|
|
@ -90,7 +103,7 @@ private:
|
|||
bool _is_valid;
|
||||
bool _hasMidiSounds;
|
||||
|
||||
HAUDIO load(Filename file_name);
|
||||
PT(SoundData) load(Filename file_name);
|
||||
// Tell the manager that the sound dtor was called.
|
||||
void release_sound(MilesAudioSound* audioSound);
|
||||
|
||||
|
|
@ -110,13 +123,6 @@ private:
|
|||
|
||||
void force_midi_reset();
|
||||
|
||||
// These are "callback" functions that implement vfs-style I/O for
|
||||
// Miles.
|
||||
static U32 AILCALLBACK vfs_open_callback(const char *filename, U32 *file_handle);
|
||||
static U32 AILCALLBACK vfs_read_callback(U32 file_handle, void *buffer, U32 bytes);
|
||||
static S32 AILCALLBACK vfs_seek_callback(U32 file_handle, S32 offset, U32 type);
|
||||
static void AILCALLBACK vfs_close_callback(U32 file_handle);
|
||||
|
||||
friend class MilesAudioSound;
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -160,17 +160,17 @@ namespace {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
MilesAudioSound::
|
||||
MilesAudioSound(MilesAudioManager* manager,
|
||||
HAUDIO audio, string file_name, float length)
|
||||
: _manager(manager), _file_name(file_name),
|
||||
MilesAudioManager::SoundData *sd, string file_name, float length)
|
||||
: _sd(sd), _manager(manager), _file_name(file_name),
|
||||
_volume(1.0f), _balance(0),
|
||||
_loop_count(1), _length(length),
|
||||
_active(true), _paused(false) {
|
||||
nassertv(audio);
|
||||
nassertv(sd != NULL);
|
||||
nassertv(!file_name.empty());
|
||||
audio_debug("MilesAudioSound(manager=0x"<<(void*)&manager
|
||||
<<", audio=0x"<<(void*)audio<<", file_name="<<file_name<<")");
|
||||
<<", sd=0x"<<(void*)sd<<", file_name="<<file_name<<")");
|
||||
// Make our own copy of the sound header data:
|
||||
_audio=AIL_quick_copy(audio);
|
||||
_audio=AIL_quick_copy(sd->_audio);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -232,10 +232,9 @@ stop() {
|
|||
// 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 symetrical with play(). set_active() is the 'owner' of
|
||||
// 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().
|
||||
// removing --> _paused=false;
|
||||
AIL_quick_halt(_audio);
|
||||
}
|
||||
|
||||
|
|
@ -329,8 +328,8 @@ set_time(float time) {
|
|||
time = max_time;
|
||||
}
|
||||
|
||||
S32 milisecond_time=S32(1000*time);
|
||||
AIL_quick_set_ms_position(_audio, milisecond_time);
|
||||
S32 millisecond_time=S32(1000*time);
|
||||
AIL_quick_set_ms_position(_audio, millisecond_time);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -340,8 +339,8 @@ set_time(float time) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
float MilesAudioSound::
|
||||
get_time() const {
|
||||
S32 milisecond_time=AIL_quick_ms_position(_audio);
|
||||
float time=float(milisecond_time*.001);
|
||||
S32 millisecond_time=AIL_quick_ms_position(_audio);
|
||||
float time=float(millisecond_time*.001);
|
||||
miles_audio_debug("get_time() returning "<<time);
|
||||
return time;
|
||||
}
|
||||
|
|
@ -355,7 +354,7 @@ void MilesAudioSound::
|
|||
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.
|
||||
// MilesAudioManager will call set_volume when *its* volume changes.
|
||||
// Set the volume:
|
||||
_volume=volume;
|
||||
// Account for the category of sound:
|
||||
|
|
@ -440,44 +439,7 @@ get_balance() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
float MilesAudioSound::
|
||||
length() const {
|
||||
if (_length == 0.0f) {
|
||||
#ifndef NEED_MILES_LENGTH_WORKAROUND
|
||||
_length=((float)AIL_quick_ms_length(_audio))*0.001f;
|
||||
if (_length == 0.0f) {
|
||||
audio_error("ERROR: Miles returned length 0 for "<<_file_name << "!");
|
||||
}
|
||||
#else
|
||||
// hack:
|
||||
// For now, the sound needs to be playing, in order to
|
||||
// get the right length. I'm in contact with RAD about the problem. I've
|
||||
// sent them example code. They've told me they're looking into it.
|
||||
// Until then, we'll play the sound to get the length.
|
||||
|
||||
// Miles 6.5c note: seems to be fixed for .mid, .mp3 also seems mostly fixed,
|
||||
// but not 100% positive (need to look for errors with CATCH_ERROR on)
|
||||
|
||||
// #define CATCH_MILES_LENGTH_ERROR
|
||||
#ifdef CATCH_MILES_LENGTH_ERROR
|
||||
_length=((float)AIL_quick_ms_length(_audio))*0.001f;
|
||||
if (_length == 0.0f) {
|
||||
audio_error("ERROR: Miles returned length 0 for "<<_file_name << "!");
|
||||
exit(1);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (AIL_quick_status(_audio)==QSTAT_PLAYING) {
|
||||
_length=((float)AIL_quick_ms_length(_audio))*0.001f;
|
||||
} else {
|
||||
AIL_quick_play(_audio, 1);
|
||||
_length=((float)AIL_quick_ms_length(_audio))*0.001f;
|
||||
AIL_quick_halt(_audio);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//audio_cat->info() << "MilesAudioSound::length() returning " << _length << endl;
|
||||
audio_debug("MilesAudioSound::length() returning "<<_length);
|
||||
return _length;
|
||||
return _sd->get_length();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -116,6 +116,7 @@ public:
|
|||
void finished();
|
||||
|
||||
private:
|
||||
PT(MilesAudioManager::SoundData) _sd;
|
||||
HAUDIO _audio;
|
||||
PT(MilesAudioManager) _manager;
|
||||
float _volume; // 0..1.0
|
||||
|
|
@ -142,7 +143,7 @@ private:
|
|||
bool _paused;
|
||||
|
||||
MilesAudioSound(MilesAudioManager* manager,
|
||||
HAUDIO audio, string file_name, float length=0.0f);
|
||||
MilesAudioManager::SoundData *sd, string file_name, float length=0.0f);
|
||||
|
||||
friend class MilesAudioManager;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue