mirror of
https://github.com/panda3d/panda3d.git
synced 2025-09-29 08:15:18 -04:00
Remove support for Miles audio system
See #440 for discussion on why this is being removed. Closes #660
This commit is contained in:
parent
0ce25d0e30
commit
1a03d997b2
@ -27,8 +27,7 @@ class SoundInterval(Interval.Interval):
|
||||
# than explicitly restarting the sound every time around. This
|
||||
# prevents a skip in the sound at every repetition (the gap in
|
||||
# the sound is caused by the delay between the end of the sound
|
||||
# and the next taskMgr cycle). There still seems to be a skip
|
||||
# in Miles when looping MP3s. =(
|
||||
# and the next taskMgr cycle).
|
||||
# RAU 03/01/07 add listenerNode in case we don't want to
|
||||
# use base.camera as the listener, node must not be None
|
||||
def __init__(self, sound, loop = 0, duration = 0.0, name = None,
|
||||
@ -62,23 +61,6 @@ class SoundInterval(Interval.Interval):
|
||||
#if (duration == 0):
|
||||
# self.notify.warning('zero length duration!')
|
||||
|
||||
# MPG - hack for Miles bug
|
||||
#duration += 1.5
|
||||
|
||||
# DCR - hack for Miles bug - adding 1.5 seconds caused
|
||||
# problems for MG_neg_buzzer.wav
|
||||
|
||||
# DCR - what this is all about: Miles is under-reporting the
|
||||
# length of MP3 files, and they're getting cut off too early.
|
||||
# This is a temporary hack. We could:
|
||||
# - hack Miles to fix its MP3 length calculation
|
||||
# - complain louder about this to RAD
|
||||
# - precompute MP3 durations and store them in a table
|
||||
|
||||
# drose - ok, I've put in a lower-level workaround in the
|
||||
# MilesAudioManager. This is no longer necessary up here,
|
||||
# where it pollutes SoundInterval for everyone.
|
||||
#duration += min(duration * 2.4, 1.5)
|
||||
|
||||
# Generate unique name if necessary
|
||||
if (name == None):
|
||||
|
@ -325,11 +325,3 @@ void AudioManager::
|
||||
write(std::ostream &out) const {
|
||||
out << (*this) << "\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* For use only with Miles.
|
||||
*/
|
||||
void AudioManager::
|
||||
set_speaker_configuration(LVecBase3 *speaker1, LVecBase3 *speaker2, LVecBase3 *speaker3, LVecBase3 *speaker4, LVecBase3 *speaker5, LVecBase3 *speaker6, LVecBase3 *speaker7, LVecBase3 *speaker8, LVecBase3 *speaker9) {
|
||||
// intentionally blank
|
||||
}
|
||||
|
@ -178,9 +178,6 @@ PUBLISHED:
|
||||
virtual void output(std::ostream &out) const;
|
||||
virtual void write(std::ostream &out) const;
|
||||
|
||||
// set_speaker_configuration is a Miles only method.
|
||||
virtual void set_speaker_configuration(LVecBase3 *speaker1, LVecBase3 *speaker2=nullptr, LVecBase3 *speaker3=nullptr, LVecBase3 *speaker4=nullptr, LVecBase3 *speaker5=nullptr, LVecBase3 *speaker6=nullptr, LVecBase3 *speaker7=nullptr, LVecBase3 *speaker8=nullptr, LVecBase3 *speaker9=nullptr);
|
||||
|
||||
public:
|
||||
static void register_AudioManager_creator(Create_AudioManager_proc* proc);
|
||||
|
||||
|
@ -83,23 +83,6 @@ set_speaker_mix(PN_stdfloat frontleft, PN_stdfloat frontright, PN_stdfloat cente
|
||||
// intentionally blank
|
||||
}
|
||||
|
||||
/**
|
||||
* For use only with Miles.
|
||||
*/
|
||||
PN_stdfloat AudioSound::
|
||||
get_speaker_level(int index) {
|
||||
// intentionally blank
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
/**
|
||||
* For use only with Miles.
|
||||
*/
|
||||
void AudioSound::
|
||||
set_speaker_levels(PN_stdfloat level1, PN_stdfloat level2, PN_stdfloat level3, PN_stdfloat level4, PN_stdfloat level5, PN_stdfloat level6, PN_stdfloat level7, PN_stdfloat level8, PN_stdfloat level9) {
|
||||
// intentionally blank
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the local DSP filter chain.
|
||||
*
|
||||
|
@ -104,17 +104,10 @@ PUBLISHED:
|
||||
virtual void set_3d_max_distance(PN_stdfloat dist);
|
||||
virtual PN_stdfloat get_3d_max_distance() const;
|
||||
|
||||
// *_speaker_mix and *_speaker_level(s) serve the same purpose.
|
||||
// *_speaker_mix is for use with FMOD. *_speaker_level(s) is for use with
|
||||
// Miles. Both interfaces exist because of a significant difference in the
|
||||
// two APIs. Hopefully the difference can be reconciled into a single
|
||||
// interface at some point.
|
||||
// *_speaker_mix is for use with FMOD.
|
||||
virtual PN_stdfloat get_speaker_mix(int speaker);
|
||||
virtual void set_speaker_mix(PN_stdfloat frontleft, PN_stdfloat frontright, PN_stdfloat center, PN_stdfloat sub, PN_stdfloat backleft, PN_stdfloat backright, PN_stdfloat sideleft, PN_stdfloat sideright);
|
||||
|
||||
virtual PN_stdfloat get_speaker_level(int index);
|
||||
virtual void set_speaker_levels(PN_stdfloat level1, PN_stdfloat level2=-1.0f, PN_stdfloat level3=-1.0f, PN_stdfloat level4=-1.0f, PN_stdfloat level5=-1.0f, PN_stdfloat level6=-1.0f, PN_stdfloat level7=-1.0f, PN_stdfloat level8=-1.0f, PN_stdfloat level9=-1.0f);
|
||||
|
||||
virtual int get_priority();
|
||||
virtual void set_priority(int priority);
|
||||
|
||||
|
@ -100,11 +100,6 @@ ConfigVariableEnum<FmodSpeakerMode> fmod_speaker_mode
|
||||
"Options: raw, mono, stereo, quad, surround, 5.1 and 7.1. "));
|
||||
|
||||
|
||||
// Config variables for Miles:
|
||||
|
||||
ConfigVariableBool audio_software_midi
|
||||
("audio-software-midi", true);
|
||||
|
||||
ConfigVariableFilename audio_dls_file
|
||||
("audio-dls-file", Filename(),
|
||||
PRC_DESC("Specifies a DLS file that defines an instrument set to load "
|
||||
@ -113,24 +108,6 @@ ConfigVariableFilename audio_dls_file
|
||||
"one is available; the likely success of this depends on the "
|
||||
"operating system."));
|
||||
|
||||
ConfigVariableBool audio_play_midi
|
||||
("audio-play-midi", true);
|
||||
|
||||
ConfigVariableBool audio_play_wave
|
||||
("audio-play-wave", true);
|
||||
|
||||
ConfigVariableBool audio_play_mp3
|
||||
("audio-play-mp3", true);
|
||||
|
||||
ConfigVariableInt audio_output_rate
|
||||
("audio-output-rate", 22050);
|
||||
|
||||
ConfigVariableInt audio_output_bits
|
||||
("audio-output-bits", 16);
|
||||
|
||||
ConfigVariableInt audio_output_channels
|
||||
("audio-output-channels", 2);
|
||||
|
||||
ConfigureFn(config_audio) {
|
||||
FilterProperties::init_type();
|
||||
AudioLoadRequest::init_type();
|
||||
|
@ -58,6 +58,7 @@ EXPCL_PANDA_AUDIO std::istream &operator >> (std::istream &in, FmodSpeakerMode &
|
||||
extern EXPCL_PANDA_AUDIO ConfigVariableInt fmod_number_of_sound_channels;
|
||||
extern EXPCL_PANDA_AUDIO ConfigVariableBool fmod_use_surround_sound;
|
||||
extern EXPCL_PANDA_AUDIO ConfigVariableEnum<FmodSpeakerMode> fmod_speaker_mode;
|
||||
extern EXPCL_PANDA_AUDIO ConfigVariableFilename audio_dls_file;
|
||||
|
||||
// Config vars for OpenAL:
|
||||
|
||||
@ -67,19 +68,6 @@ extern EXPCL_PANDA_AUDIO ConfigVariableDouble audio_drop_off_factor;
|
||||
extern EXPCL_PANDA_AUDIO ConfigVariableDouble audio_buffering_seconds;
|
||||
extern EXPCL_PANDA_AUDIO ConfigVariableInt audio_preload_threshold;
|
||||
|
||||
// Config vars for Miles:
|
||||
|
||||
extern EXPCL_PANDA_AUDIO ConfigVariableBool audio_software_midi;
|
||||
extern EXPCL_PANDA_AUDIO ConfigVariableFilename audio_dls_file;
|
||||
extern EXPCL_PANDA_AUDIO ConfigVariableBool audio_play_midi;
|
||||
extern EXPCL_PANDA_AUDIO ConfigVariableBool audio_play_wave;
|
||||
extern EXPCL_PANDA_AUDIO ConfigVariableBool audio_play_mp3;
|
||||
extern EXPCL_PANDA_AUDIO ConfigVariableInt audio_output_rate;
|
||||
extern EXPCL_PANDA_AUDIO ConfigVariableInt audio_output_bits;
|
||||
extern EXPCL_PANDA_AUDIO ConfigVariableInt audio_output_channels;
|
||||
|
||||
|
||||
|
||||
#ifdef NOTIFY_DEBUG //[
|
||||
// Non-release build:
|
||||
#define audio_debug(msg) \
|
||||
|
@ -21,7 +21,7 @@
|
||||
class EXPCL_PANDA_AUDIO NullAudioManager : public AudioManager {
|
||||
// All of these methods are stubbed out to some degree. If you're looking
|
||||
// for a starting place for a new AudioManager, please consider looking at
|
||||
// the milesAudioManager.
|
||||
// the openalAudioManager.
|
||||
|
||||
public:
|
||||
NullAudioManager();
|
||||
|
@ -23,7 +23,7 @@
|
||||
class EXPCL_PANDA_AUDIO NullAudioSound : public AudioSound {
|
||||
// All of these methods are stubbed out to some degree. If you're looking
|
||||
// for a starting place for a new AudioManager, please consider looking at
|
||||
// the milesAudioManager.
|
||||
// the openalAudioManager.
|
||||
|
||||
public:
|
||||
~NullAudioSound();
|
||||
|
@ -1,102 +0,0 @@
|
||||
/**
|
||||
* 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."
|
||||
*
|
||||
* @file config_milesAudio.cxx
|
||||
* @author skyler
|
||||
*/
|
||||
|
||||
#include "pandabase.h"
|
||||
#ifdef HAVE_RAD_MSS //[
|
||||
|
||||
#include "config_milesAudio.h"
|
||||
#include "milesAudioManager.h"
|
||||
#include "milesAudioSound.h"
|
||||
#include "milesAudioSample.h"
|
||||
#include "milesAudioSequence.h"
|
||||
#include "milesAudioStream.h"
|
||||
#include "pandaSystem.h"
|
||||
#include "dconfig.h"
|
||||
|
||||
#if !defined(CPPPARSER) && !defined(LINK_ALL_STATIC) && !defined(BUILDING_MILES_AUDIO)
|
||||
#error Buildsystem error: BUILDING_MILES_AUDIO not defined
|
||||
#endif
|
||||
|
||||
ConfigureDef(config_milesAudio);
|
||||
NotifyCategoryDef(milesAudio, ":audio");
|
||||
|
||||
ConfigureFn(config_milesAudio) {
|
||||
init_libMilesAudio();
|
||||
}
|
||||
|
||||
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. This only applies to files "
|
||||
"within the miles-audio-preload-threshold."));
|
||||
|
||||
ConfigVariableInt miles_audio_preload_threshold
|
||||
("miles-audio-preload-threshold", -1,
|
||||
PRC_DESC("This should be no smaller "
|
||||
"than miles-audio-expand-mp3-threshold. Files that are smaller "
|
||||
"than this number of bytes will be preloaded and kept "
|
||||
"resident in memory, while files that are this size or larger "
|
||||
"will be streamed from disk. Set this to -1 to preload "
|
||||
"every file."));
|
||||
|
||||
ConfigVariableBool miles_audio_panda_threads
|
||||
("miles-audio-panda-threads", true,
|
||||
PRC_DESC("Set this true to service Miles background audio via Panda's "
|
||||
"threading interface, instead of Miles' built-in threading "
|
||||
"interface. This gives Panda more control over the threading, "
|
||||
"and ensures better lock protection within Panda. This has "
|
||||
"no meaning unless Panda is compiled with thread support."));
|
||||
|
||||
/**
|
||||
* Initializes the library. This must be called at least once before any of
|
||||
* the functions or classes in this library can be used. Normally it will be
|
||||
* called by the static initializers and need not be called explicitly, but
|
||||
* special cases exist.
|
||||
*/
|
||||
void
|
||||
init_libMilesAudio() {
|
||||
static bool initialized = false;
|
||||
if (initialized) {
|
||||
return;
|
||||
}
|
||||
initialized = true;
|
||||
MilesAudioManager::init_type();
|
||||
MilesAudioSound::init_type();
|
||||
MilesAudioSample::init_type();
|
||||
MilesAudioSequence::init_type();
|
||||
MilesAudioStream::init_type();
|
||||
|
||||
PandaSystem *ps = PandaSystem::get_global_ptr();
|
||||
ps->add_system("Miles");
|
||||
ps->add_system("audio");
|
||||
ps->set_system_tag("audio", "implementation", "Miles");
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is called when the dynamic library is loaded; it should
|
||||
* return the Create_AudioManager function appropriate to create a
|
||||
* MilesAudioManager.
|
||||
*/
|
||||
Create_AudioManager_proc *
|
||||
get_audio_manager_func_miles_audio() {
|
||||
init_libMilesAudio();
|
||||
return &Create_MilesAudioManager;
|
||||
}
|
||||
|
||||
#endif //]
|
@ -1,37 +0,0 @@
|
||||
/**
|
||||
* 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."
|
||||
*
|
||||
* @file config_milesAudio.h
|
||||
* @author skyler
|
||||
*/
|
||||
|
||||
#ifndef CONFIG_MILESAUDIO_H
|
||||
#define CONFIG_MILESAUDIO_H
|
||||
|
||||
#include "pandabase.h"
|
||||
|
||||
#ifdef HAVE_RAD_MSS //[
|
||||
#include "notifyCategoryProxy.h"
|
||||
#include "configVariableBool.h"
|
||||
#include "configVariableInt.h"
|
||||
#include "dconfig.h"
|
||||
#include "audioManager.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_preload_threshold;
|
||||
extern ConfigVariableBool miles_audio_panda_threads;
|
||||
|
||||
extern EXPCL_MILES_AUDIO void init_libMilesAudio();
|
||||
extern "C" EXPCL_MILES_AUDIO Create_AudioManager_proc *get_audio_manager_func_miles_audio();
|
||||
#endif //]
|
||||
|
||||
#endif // CONFIG_MILESAUDIO_H
|
@ -1,39 +0,0 @@
|
||||
/**
|
||||
* 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."
|
||||
*
|
||||
* @file globalMilesManager.I
|
||||
* @author drose
|
||||
* @date 2007-07-30
|
||||
*/
|
||||
|
||||
/**
|
||||
* Returns true if the Miles Sound System is open (and active), false if it is
|
||||
* not.
|
||||
*/
|
||||
INLINE bool GlobalMilesManager::
|
||||
is_open() const {
|
||||
return _is_open;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of sample handles that have been allocated.
|
||||
*/
|
||||
INLINE int GlobalMilesManager::
|
||||
get_num_samples() const {
|
||||
LightMutexHolder holder(_samples_lock);
|
||||
return _samples.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of sequence handles that have been allocated.
|
||||
*/
|
||||
INLINE int GlobalMilesManager::
|
||||
get_num_sequences() const {
|
||||
LightMutexHolder holder(_sequences_lock);
|
||||
return _sequences.size();
|
||||
}
|
@ -1,446 +0,0 @@
|
||||
/**
|
||||
* 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."
|
||||
*
|
||||
* @file globalMilesManager.cxx
|
||||
* @author drose
|
||||
* @date 2007-07-26
|
||||
*/
|
||||
|
||||
#include "globalMilesManager.h"
|
||||
|
||||
#ifdef HAVE_RAD_MSS //[
|
||||
|
||||
#include "lightMutexHolder.h"
|
||||
#include "milesAudioManager.h"
|
||||
#include "milesAudioSample.h"
|
||||
#include "milesAudioSequence.h"
|
||||
|
||||
#ifdef WIN32
|
||||
// For midiOutReset()
|
||||
#include <windows.h>
|
||||
#include <mmsystem.h>
|
||||
#endif
|
||||
|
||||
using std::istream;
|
||||
using std::string;
|
||||
|
||||
GlobalMilesManager *GlobalMilesManager::_global_ptr;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
GlobalMilesManager::
|
||||
GlobalMilesManager() :
|
||||
_managers_lock("GlobalMilesManager::_managers_lock"),
|
||||
_samples_lock("GlobalMilesManager::_samples_lock"),
|
||||
_sequences_lock("GlobalMilesManager::_sequences_lock")
|
||||
{
|
||||
_digital_driver = 0;
|
||||
_midi_driver = 0;
|
||||
_dls_device = 0;
|
||||
_dls_file = 0;
|
||||
_is_open = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Records a new MilesAudioManager in the world. This will open the Miles API
|
||||
* when the first audio manager is added.
|
||||
*/
|
||||
void GlobalMilesManager::
|
||||
add_manager(MilesAudioManager *manager) {
|
||||
LightMutexHolder holder(_managers_lock);
|
||||
_managers.insert(manager);
|
||||
if (!_is_open) {
|
||||
open_api();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Records that a MilesAudioManager is destructing. This will clsoe the Miles
|
||||
* API when the last audio manager is removed.
|
||||
*/
|
||||
void GlobalMilesManager::
|
||||
remove_manager(MilesAudioManager *manager) {
|
||||
LightMutexHolder holder(_managers_lock);
|
||||
_managers.erase(manager);
|
||||
if (_managers.empty() && _is_open) {
|
||||
close_api();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls cleanup() on all MilesAudioManagers, to cause a clean shutdown.
|
||||
*/
|
||||
void GlobalMilesManager::
|
||||
cleanup() {
|
||||
LightMutexHolder holder(_managers_lock);
|
||||
Managers::iterator mi;
|
||||
for (mi = _managers.begin(); mi != _managers.end(); ++mi) {
|
||||
(*mi)->cleanup();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a sample handle from the global pool for the digital output device, to
|
||||
* be used with the indicated AudioSound.
|
||||
*
|
||||
* If successful, sets the sample handle and the index (which should later be
|
||||
* used to release the sample) and returns true. If unsuccessful (because
|
||||
* there are no more available handles), returns false.
|
||||
*
|
||||
* This is a very limited resource; you should only get a sample just before
|
||||
* playing a sound.
|
||||
*/
|
||||
bool GlobalMilesManager::
|
||||
get_sample(HSAMPLE &sample, size_t &index, MilesAudioSample *sound) {
|
||||
LightMutexHolder holder(_samples_lock);
|
||||
|
||||
for (size_t i = 0; i < _samples.size(); ++i) {
|
||||
SampleData &smp = _samples[i];
|
||||
if (AIL_sample_status(smp._sample) == SMP_DONE) {
|
||||
if (smp._sound != nullptr) {
|
||||
// Tell the last sound that was using this sample that it's done now.
|
||||
smp._sound->internal_stop();
|
||||
}
|
||||
smp._sound = sound;
|
||||
sample = smp._sample;
|
||||
index = i;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// No more already-allocated samples; get a new one from the system.
|
||||
sample = AIL_allocate_sample_handle(_digital_driver);
|
||||
if (sample == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
AIL_init_sample(sample, DIG_F_STEREO_16, 0);
|
||||
index = _samples.size();
|
||||
|
||||
SampleData smp;
|
||||
smp._sound = sound;
|
||||
smp._sample = sample;
|
||||
_samples.push_back(smp);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates that the indicated AudioSound no longer needs this sample.
|
||||
*/
|
||||
void GlobalMilesManager::
|
||||
release_sample(size_t index, MilesAudioSample *sound) {
|
||||
LightMutexHolder holder(_samples_lock);
|
||||
nassertv(index < _samples.size());
|
||||
|
||||
SampleData &smp = _samples[index];
|
||||
if (smp._sound == sound) {
|
||||
smp._sound = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a sequence handle from the global pool for the digital output device,
|
||||
* to be used with the indicated AudioSound.
|
||||
*
|
||||
* If successful, sets the sequence handle and the index (which should later
|
||||
* be used to release the sequence) and returns true. If unsuccessful
|
||||
* (because there are no more available handles), returns false.
|
||||
*
|
||||
* This is a very limited resource; you should only get a sequence just before
|
||||
* playing a sound.
|
||||
*/
|
||||
bool GlobalMilesManager::
|
||||
get_sequence(HSEQUENCE &sequence, size_t &index, MilesAudioSequence *sound) {
|
||||
LightMutexHolder holder(_sequences_lock);
|
||||
|
||||
for (size_t i = 0; i < _sequences.size(); ++i) {
|
||||
SequenceData &seq = _sequences[i];
|
||||
if (AIL_sequence_status(seq._sequence) == SEQ_DONE) {
|
||||
if (seq._sound != nullptr) {
|
||||
// Tell the last sound that was using this sequence that it's done
|
||||
// now.
|
||||
seq._sound->internal_stop();
|
||||
}
|
||||
seq._sound = sound;
|
||||
sequence = seq._sequence;
|
||||
index = i;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// No more already-allocated sequences; get a new one from the system.
|
||||
sequence = AIL_allocate_sequence_handle(_midi_driver);
|
||||
if (sequence == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
index = _sequences.size();
|
||||
|
||||
SequenceData seq;
|
||||
seq._sound = sound;
|
||||
seq._sequence = sequence;
|
||||
_sequences.push_back(seq);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates that the indicated AudioSound no longer needs this sequence.
|
||||
*/
|
||||
void GlobalMilesManager::
|
||||
release_sequence(size_t index, MilesAudioSequence *sound) {
|
||||
LightMutexHolder holder(_sequences_lock);
|
||||
nassertv(index < _sequences.size());
|
||||
|
||||
SequenceData &seq = _sequences[index];
|
||||
if (seq._sound == sound) {
|
||||
seq._sound = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sometimes Miles seems to leave midi notes hanging, even after stop is
|
||||
* called, so call this method to perform an explicit reset using winMM.dll
|
||||
* calls, just to ensure silence.
|
||||
*/
|
||||
void GlobalMilesManager::
|
||||
force_midi_reset() {
|
||||
if (!miles_audio_force_midi_reset) {
|
||||
audio_debug("MilesAudioManager::skipping force_midi_reset");
|
||||
return;
|
||||
}
|
||||
audio_debug("MilesAudioManager::force_midi_reset");
|
||||
|
||||
#ifdef WIN32
|
||||
if ((_midi_driver!=nullptr) && (_midi_driver->deviceid != MIDI_nullptr_DRIVER) && (_midi_driver->hMidiOut != nullptr)) {
|
||||
audio_debug("MilesAudioManager::calling midiOutReset");
|
||||
midiOutReset(_midi_driver->hMidiOut);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the pointer to the one GlobalMilesManager object.
|
||||
*/
|
||||
GlobalMilesManager *GlobalMilesManager::
|
||||
get_global_ptr() {
|
||||
if (_global_ptr == nullptr) {
|
||||
_global_ptr = new GlobalMilesManager;
|
||||
}
|
||||
return _global_ptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called internally to initialize the Miles API.
|
||||
*/
|
||||
void GlobalMilesManager::
|
||||
open_api() {
|
||||
audio_debug("GlobalMilesManager::open_api()")
|
||||
nassertv(!_is_open);
|
||||
|
||||
bool use_digital = (audio_play_wave || audio_play_mp3);
|
||||
if (audio_play_midi && audio_software_midi) {
|
||||
use_digital = true;
|
||||
}
|
||||
|
||||
#ifdef IS_OSX
|
||||
audio_software_midi = true;
|
||||
#endif
|
||||
|
||||
audio_debug(" use_digital="<<use_digital);
|
||||
audio_debug(" audio_play_midi="<<audio_play_midi);
|
||||
audio_debug(" audio_software_midi="<<audio_software_midi);
|
||||
audio_debug(" audio_output_rate="<<audio_output_rate);
|
||||
audio_debug(" audio_output_bits="<<audio_output_bits);
|
||||
audio_debug(" audio_output_channels="<<audio_output_channels);
|
||||
audio_debug(" audio_software_midi="<<audio_software_midi);
|
||||
|
||||
#if !defined(NDEBUG) && defined(AIL_MSS_version) //[
|
||||
char version[8];
|
||||
AIL_MSS_version(version, 8);
|
||||
audio_debug(" Mss32.dll Version: "<<version);
|
||||
#endif //]
|
||||
|
||||
if (!AIL_startup()) {
|
||||
milesAudio_cat.warning()
|
||||
<< "Miles Sound System already initialized!\n";
|
||||
}
|
||||
|
||||
AIL_set_file_callbacks(open_callback, close_callback,
|
||||
seek_callback, read_callback);
|
||||
|
||||
if (use_digital) {
|
||||
_digital_driver =
|
||||
AIL_open_digital_driver(audio_output_rate, audio_output_bits,
|
||||
audio_output_channels, 0);
|
||||
}
|
||||
|
||||
if (audio_play_midi) {
|
||||
if (audio_software_midi) {
|
||||
_midi_driver = AIL_open_XMIDI_driver(AIL_OPEN_XMIDI_NULL_DRIVER);
|
||||
|
||||
// Load the downloadable sounds file:
|
||||
_dls_device = AIL_DLS_open(_midi_driver, _digital_driver, nullptr, 0,
|
||||
audio_output_rate, audio_output_bits,
|
||||
audio_output_channels);
|
||||
|
||||
Filename dls_pathname = AudioManager::get_dls_pathname();
|
||||
|
||||
VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
|
||||
vfs->resolve_filename(dls_pathname, get_model_path());
|
||||
|
||||
_dls_data.clear();
|
||||
PT(VirtualFile) file = vfs->get_file(dls_pathname);
|
||||
if (file == nullptr) {
|
||||
milesAudio_cat.warning()
|
||||
<< "DLS file does not exist: " << dls_pathname << "\n";
|
||||
|
||||
} else if (!file->read_file(_dls_data, true)) {
|
||||
milesAudio_cat.warning()
|
||||
<< "Could not read DLS file: " << dls_pathname << "\n";
|
||||
|
||||
} else if (_dls_data.empty()) {
|
||||
milesAudio_cat.warning()
|
||||
<< "DLS file is empty: " << dls_pathname << "\n";
|
||||
|
||||
} else {
|
||||
_dls_file = AIL_DLS_load_memory(_dls_device, &_dls_data[0], 0);
|
||||
}
|
||||
|
||||
if (_dls_file == 0) {
|
||||
audio_error(" Could not get DLS file, switching to hardware MIDI.");
|
||||
AIL_DLS_close(_dls_device, 0);
|
||||
_dls_device = 0;
|
||||
AIL_close_XMIDI_driver(_midi_driver);
|
||||
_midi_driver = AIL_open_XMIDI_driver(0);
|
||||
|
||||
} else {
|
||||
audio_info(" using Miles software midi");
|
||||
}
|
||||
} else {
|
||||
_midi_driver = AIL_open_XMIDI_driver(0);
|
||||
audio_info(" using Miles hardware midi");
|
||||
}
|
||||
}
|
||||
|
||||
_is_open = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called internally to shut down the Miles API.
|
||||
*/
|
||||
void GlobalMilesManager::
|
||||
close_api() {
|
||||
audio_debug("GlobalMilesManager::close_api()")
|
||||
nassertv(_is_open);
|
||||
|
||||
Samples::iterator si;
|
||||
for (si = _samples.begin(); si != _samples.end(); ++si) {
|
||||
SampleData &smp = (*si);
|
||||
AIL_release_sample_handle(smp._sample);
|
||||
}
|
||||
_samples.clear();
|
||||
|
||||
Sequences::iterator qi;
|
||||
for (qi = _sequences.begin(); qi != _sequences.end(); ++qi) {
|
||||
SequenceData &smp = (*qi);
|
||||
AIL_release_sequence_handle(smp._sequence);
|
||||
}
|
||||
_sequences.clear();
|
||||
|
||||
if (_dls_file != 0) {
|
||||
AIL_DLS_unload(_dls_device, _dls_file);
|
||||
_dls_file = 0;
|
||||
}
|
||||
|
||||
if (_dls_device != 0) {
|
||||
AIL_DLS_close(_dls_device, 0);
|
||||
_dls_device = 0;
|
||||
}
|
||||
|
||||
if (_midi_driver != 0) {
|
||||
AIL_close_XMIDI_driver(_midi_driver);
|
||||
_midi_driver = 0;
|
||||
}
|
||||
|
||||
if (_digital_driver != 0) {
|
||||
AIL_close_digital_driver(_digital_driver);
|
||||
_digital_driver = 0;
|
||||
}
|
||||
|
||||
AIL_shutdown();
|
||||
|
||||
_is_open = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* This callback function is given to Miles to handle file I/O via the Panda
|
||||
* VFS. It's only used to implemented streaming audio files, since in all
|
||||
* other cases we open files directly.
|
||||
*/
|
||||
U32 AILCALLBACK GlobalMilesManager::
|
||||
open_callback(char const *filename, UINTa *file_handle) {
|
||||
VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
|
||||
istream *strm = vfs->open_read_file(Filename::binary_filename(string(filename)), true);
|
||||
if (strm == nullptr) {
|
||||
// Failure.
|
||||
return 0;
|
||||
}
|
||||
// Success.
|
||||
(*file_handle) = (UINTa)strm;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* This callback function is given to Miles to handle file I/O via the Panda
|
||||
* VFS.
|
||||
*/
|
||||
void AILCALLBACK GlobalMilesManager::
|
||||
close_callback(UINTa file_handle) {
|
||||
istream *strm = (istream *)file_handle;
|
||||
VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
|
||||
vfs->close_read_file(strm);
|
||||
}
|
||||
|
||||
/**
|
||||
* This callback function is given to Miles to handle file I/O via the Panda
|
||||
* VFS.
|
||||
*/
|
||||
S32 AILCALLBACK GlobalMilesManager::
|
||||
seek_callback(UINTa file_handle, S32 offset, U32 type) {
|
||||
istream *strm = (istream *)file_handle;
|
||||
strm->clear();
|
||||
switch (type) {
|
||||
case AIL_FILE_SEEK_BEGIN:
|
||||
strm->seekg(offset, std::ios::beg);
|
||||
break;
|
||||
|
||||
case AIL_FILE_SEEK_CURRENT:
|
||||
strm->seekg(offset, std::ios::cur);
|
||||
break;
|
||||
|
||||
case AIL_FILE_SEEK_END:
|
||||
strm->seekg(offset, std::ios::end);
|
||||
break;
|
||||
}
|
||||
|
||||
return strm->tellg();
|
||||
}
|
||||
|
||||
/**
|
||||
* This callback function is given to Miles to handle file I/O via the Panda
|
||||
* VFS.
|
||||
*/
|
||||
U32 AILCALLBACK GlobalMilesManager::
|
||||
read_callback(UINTa file_handle, void *buffer, U32 bytes) {
|
||||
istream *strm = (istream *)file_handle;
|
||||
strm->read((char *)buffer, bytes);
|
||||
return strm->gcount();
|
||||
}
|
||||
|
||||
#endif //]
|
@ -1,117 +0,0 @@
|
||||
/**
|
||||
* 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."
|
||||
*
|
||||
* @file globalMilesManager.h
|
||||
* @author drose
|
||||
* @date 2007-07-26
|
||||
*/
|
||||
|
||||
#ifndef GLOBALMILESMANAGER_H
|
||||
#define GLOBALMILESMANAGER_H
|
||||
|
||||
#include "pandabase.h"
|
||||
#ifdef HAVE_RAD_MSS //[
|
||||
|
||||
#include "pset.h"
|
||||
#include "lightMutex.h"
|
||||
#include "lightMutexHolder.h"
|
||||
|
||||
#include <mss.h>
|
||||
|
||||
#ifndef UINTa
|
||||
#define UINTa U32
|
||||
#endif
|
||||
|
||||
#ifndef SINTa
|
||||
#define SINTa S32
|
||||
#endif
|
||||
|
||||
class MilesAudioSample;
|
||||
class MilesAudioSequence;
|
||||
|
||||
/**
|
||||
* This is a wrapper around the parts of the Miles API that should only be
|
||||
* created once. This represents the global data common to all
|
||||
* MilesAudioManagers.
|
||||
*/
|
||||
class EXPCL_MILES_AUDIO GlobalMilesManager {
|
||||
private:
|
||||
GlobalMilesManager();
|
||||
|
||||
public:
|
||||
void add_manager(MilesAudioManager *manager);
|
||||
void remove_manager(MilesAudioManager *manager);
|
||||
void cleanup();
|
||||
INLINE bool is_open() const;
|
||||
|
||||
bool get_sample(HSAMPLE &sample, size_t &index, MilesAudioSample *sound);
|
||||
void release_sample(size_t index, MilesAudioSample *sound);
|
||||
INLINE int get_num_samples() const;
|
||||
|
||||
bool get_sequence(HSEQUENCE &sequence, size_t &index, MilesAudioSequence *sound);
|
||||
void release_sequence(size_t index, MilesAudioSequence *sound);
|
||||
INLINE int get_num_sequences() const;
|
||||
|
||||
void force_midi_reset();
|
||||
|
||||
static GlobalMilesManager *get_global_ptr();
|
||||
|
||||
public:
|
||||
HDIGDRIVER _digital_driver;
|
||||
HMDIDRIVER _midi_driver;
|
||||
|
||||
// For software MIDI:
|
||||
HDLSDEVICE _dls_device;
|
||||
HDLSFILEID _dls_file;
|
||||
vector_uchar _dls_data;
|
||||
|
||||
private:
|
||||
void open_api();
|
||||
void close_api();
|
||||
|
||||
static U32 AILCALLBACK open_callback(char const *filename, UINTa *file_handle);
|
||||
static void AILCALLBACK close_callback(UINTa file_handle);
|
||||
static S32 AILCALLBACK seek_callback(UINTa file_handle, S32 offset, U32 type);
|
||||
static U32 AILCALLBACK read_callback(UINTa file_handle, void *buffer, U32 bytes);
|
||||
|
||||
|
||||
private:
|
||||
bool _is_open;
|
||||
|
||||
typedef pset<MilesAudioManager *> Managers;
|
||||
Managers _managers;
|
||||
LightMutex _managers_lock;
|
||||
|
||||
class SampleData {
|
||||
public:
|
||||
HSAMPLE _sample;
|
||||
MilesAudioSample *_sound;
|
||||
};
|
||||
|
||||
typedef pvector<SampleData> Samples;
|
||||
Samples _samples;
|
||||
LightMutex _samples_lock;
|
||||
|
||||
class SequenceData {
|
||||
public:
|
||||
HSEQUENCE _sequence;
|
||||
MilesAudioSequence *_sound;
|
||||
};
|
||||
|
||||
typedef pvector<SequenceData> Sequences;
|
||||
Sequences _sequences;
|
||||
LightMutex _sequences_lock;
|
||||
|
||||
static GlobalMilesManager *_global_ptr;
|
||||
};
|
||||
|
||||
#include "globalMilesManager.I"
|
||||
|
||||
#endif //]
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
@ -1,198 +0,0 @@
|
||||
/**
|
||||
* 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."
|
||||
*
|
||||
* @file milesAudioManager.h
|
||||
* @author skyler
|
||||
* @date 2001-06-06
|
||||
* Prior system by: cary
|
||||
*/
|
||||
|
||||
#ifndef __MILES_AUDIO_MANAGER_H__ //[
|
||||
#define __MILES_AUDIO_MANAGER_H__
|
||||
|
||||
#include "pandabase.h"
|
||||
#ifdef HAVE_RAD_MSS //[
|
||||
|
||||
#include "audioManager.h"
|
||||
#include "pset.h"
|
||||
#include "pmap.h"
|
||||
#include "pdeque.h"
|
||||
#include "pvector.h"
|
||||
#include "thread.h"
|
||||
#include "pmutex.h"
|
||||
#include "lightReMutex.h"
|
||||
#include "conditionVar.h"
|
||||
#include "vector_uchar.h"
|
||||
|
||||
#include <mss.h>
|
||||
|
||||
class MilesAudioSound;
|
||||
|
||||
class EXPCL_MILES_AUDIO MilesAudioManager: public AudioManager {
|
||||
public:
|
||||
// See AudioManager.h for documentation.
|
||||
|
||||
MilesAudioManager();
|
||||
virtual ~MilesAudioManager();
|
||||
|
||||
virtual void shutdown();
|
||||
|
||||
virtual bool is_valid();
|
||||
|
||||
virtual PT(AudioSound) get_sound(const Filename &file_name, bool positional = false, int mode=SM_heuristic);
|
||||
virtual PT(AudioSound) get_sound(MovieAudio *sound, bool positional = false, int mode=SM_heuristic);
|
||||
virtual void uncache_sound(const Filename &file_name);
|
||||
virtual void clear_cache();
|
||||
virtual void set_cache_limit(unsigned int count);
|
||||
virtual unsigned int get_cache_limit() const;
|
||||
|
||||
virtual void set_volume(PN_stdfloat volume);
|
||||
virtual PN_stdfloat get_volume() const;
|
||||
|
||||
void set_play_rate(PN_stdfloat play_rate);
|
||||
PN_stdfloat get_play_rate() const;
|
||||
|
||||
virtual void set_active(bool active);
|
||||
virtual bool get_active() const;
|
||||
|
||||
virtual void set_concurrent_sound_limit(unsigned int limit = 0);
|
||||
virtual unsigned int get_concurrent_sound_limit() const;
|
||||
|
||||
virtual void reduce_sounds_playing_to(unsigned int count);
|
||||
virtual void stop_all_sounds();
|
||||
|
||||
virtual void update();
|
||||
|
||||
// Tell the manager that the sound dtor was called.
|
||||
void release_sound(MilesAudioSound *audioSound);
|
||||
void cleanup();
|
||||
|
||||
// 3D spatialized sound support. Spatialized sound was originally added for
|
||||
// FMOD, so there are parts of the interface in the Miles implementation
|
||||
// that are a little more awkward than they would be otherwise.
|
||||
virtual void audio_3d_set_listener_attributes(PN_stdfloat px, PN_stdfloat py, PN_stdfloat pz, PN_stdfloat vx, PN_stdfloat xy, PN_stdfloat xz, PN_stdfloat fx, PN_stdfloat fy, PN_stdfloat fz, PN_stdfloat ux, PN_stdfloat uy, PN_stdfloat uz);
|
||||
virtual void audio_3d_get_listener_attributes(PN_stdfloat *px, PN_stdfloat *py, PN_stdfloat *pz, PN_stdfloat *vx, PN_stdfloat *vy, PN_stdfloat *vz, PN_stdfloat *fx, PN_stdfloat *fy, PN_stdfloat *fz, PN_stdfloat *ux, PN_stdfloat *uy, PN_stdfloat *uz);
|
||||
virtual void audio_3d_set_distance_factor(PN_stdfloat factor);
|
||||
virtual PN_stdfloat audio_3d_get_distance_factor() const;
|
||||
virtual void audio_3d_set_doppler_factor(PN_stdfloat factor);
|
||||
virtual PN_stdfloat audio_3d_get_doppler_factor() const;
|
||||
virtual void audio_3d_set_drop_off_factor(PN_stdfloat factor);
|
||||
virtual PN_stdfloat audio_3d_get_drop_off_factor() const;
|
||||
virtual void set_speaker_configuration(LVecBase3 *speaker1, LVecBase3 *speaker2=nullptr, LVecBase3 *speaker3=nullptr, LVecBase3 *speaker4=nullptr, LVecBase3 *speaker5=nullptr, LVecBase3 *speaker6=nullptr, LVecBase3 *speaker7=nullptr, LVecBase3 *speaker8=nullptr, LVecBase3 *speaker9=nullptr);
|
||||
|
||||
virtual void output(std::ostream &out) const;
|
||||
virtual void write(std::ostream &out) const;
|
||||
|
||||
private:
|
||||
bool do_is_valid();
|
||||
void do_reduce_sounds_playing_to(unsigned int count);
|
||||
void do_clear_cache();
|
||||
|
||||
void start_service_stream(HSTREAM stream);
|
||||
void stop_service_stream(HSTREAM stream);
|
||||
|
||||
void most_recently_used(const std::string &path);
|
||||
void uncache_a_sound();
|
||||
|
||||
void starting_sound(MilesAudioSound *audio);
|
||||
void stopping_sound(MilesAudioSound *audio);
|
||||
|
||||
class SoundData;
|
||||
PT(SoundData) load(const Filename &file_name);
|
||||
|
||||
void thread_main(volatile bool &keep_running);
|
||||
void do_service_streams();
|
||||
|
||||
private:
|
||||
class StreamThread : public Thread {
|
||||
public:
|
||||
StreamThread(MilesAudioManager *mgr);
|
||||
virtual void thread_main();
|
||||
|
||||
MilesAudioManager *_mgr;
|
||||
volatile bool _keep_running;
|
||||
};
|
||||
|
||||
// The sound cache:
|
||||
class SoundData : public ReferenceCount {
|
||||
public:
|
||||
SoundData();
|
||||
~SoundData();
|
||||
PN_stdfloat get_length();
|
||||
void set_length(PN_stdfloat length);
|
||||
|
||||
Filename _basename;
|
||||
S32 _file_type;
|
||||
vector_uchar _raw_data;
|
||||
bool _has_length;
|
||||
PN_stdfloat _length; // in seconds.
|
||||
};
|
||||
typedef pmap<std::string, PT(SoundData) > SoundMap;
|
||||
SoundMap _sounds;
|
||||
|
||||
typedef pset<MilesAudioSound *> AudioSet;
|
||||
// The offspring of this manager:
|
||||
AudioSet _sounds_on_loan;
|
||||
|
||||
typedef pset<MilesAudioSound *> SoundsPlaying;
|
||||
// The sounds from this manager that are currently playing:
|
||||
SoundsPlaying _sounds_playing;
|
||||
|
||||
// The Least Recently Used mechanism:
|
||||
typedef pdeque<const std::string *> LRU;
|
||||
LRU _lru;
|
||||
// State:
|
||||
PN_stdfloat _volume;
|
||||
PN_stdfloat _play_rate;
|
||||
bool _active;
|
||||
int _cache_limit;
|
||||
bool _cleanup_required;
|
||||
unsigned int _concurrent_sound_limit;
|
||||
|
||||
bool _is_valid;
|
||||
bool _hasMidiSounds;
|
||||
|
||||
// This mutex protects everything above.
|
||||
LightReMutex _lock;
|
||||
bool _sounds_finished;
|
||||
|
||||
typedef pvector<HSTREAM> Streams;
|
||||
PT(StreamThread) _stream_thread;
|
||||
Streams _streams;
|
||||
Mutex _streams_lock;
|
||||
ConditionVar _streams_cvar;
|
||||
|
||||
public:
|
||||
static TypeHandle get_class_type() {
|
||||
return _type_handle;
|
||||
}
|
||||
static void init_type() {
|
||||
AudioManager::init_type();
|
||||
register_type(_type_handle, "MilesAudioManager",
|
||||
AudioManager::get_class_type());
|
||||
}
|
||||
virtual TypeHandle get_type() const {
|
||||
return get_class_type();
|
||||
}
|
||||
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
|
||||
|
||||
private:
|
||||
static TypeHandle _type_handle;
|
||||
|
||||
friend class MilesAudioSound;
|
||||
friend class MilesAudioSample;
|
||||
friend class MilesAudioSequence;
|
||||
friend class MilesAudioStream;
|
||||
};
|
||||
|
||||
EXPCL_MILES_AUDIO AudioManager *Create_MilesAudioManager();
|
||||
|
||||
|
||||
#endif //]
|
||||
|
||||
#endif //]
|
@ -1,13 +0,0 @@
|
||||
/**
|
||||
* 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."
|
||||
*
|
||||
* @file milesAudioSample.I
|
||||
* @author skyler
|
||||
* @date 2001-06-06
|
||||
* Prior system by: cary
|
||||
*/
|
@ -1,530 +0,0 @@
|
||||
/**
|
||||
* 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."
|
||||
*
|
||||
* @file milesAudioSample.cxx
|
||||
* @author skyler
|
||||
* @date 2001-06-06
|
||||
*/
|
||||
|
||||
#include "milesAudioSample.h"
|
||||
|
||||
#ifdef HAVE_RAD_MSS //[
|
||||
|
||||
#include "milesAudioManager.h"
|
||||
|
||||
|
||||
TypeHandle MilesAudioSample::_type_handle;
|
||||
|
||||
#undef miles_audio_debug
|
||||
|
||||
#ifndef NDEBUG //[
|
||||
#define miles_audio_debug(x) \
|
||||
audio_debug("MilesAudioSample \""<<get_name()<<"\" "<< x )
|
||||
#else //][
|
||||
#define miles_audio_debug(x) ((void)0)
|
||||
#endif //]
|
||||
|
||||
/**
|
||||
* This constructor is called only by the MilesAudioManager.
|
||||
*/
|
||||
MilesAudioSample::
|
||||
MilesAudioSample(MilesAudioManager *manager, MilesAudioManager::SoundData *sd,
|
||||
const std::string &file_name) :
|
||||
MilesAudioSound(manager, file_name),
|
||||
_sd(sd)
|
||||
{
|
||||
nassertv(sd != nullptr);
|
||||
audio_debug("MilesAudioSample(manager=0x"<<(void*)&manager
|
||||
<<", sd=0x"<<(void*)sd<<", file_name="<<file_name<<")");
|
||||
|
||||
_sample = 0;
|
||||
_sample_index = 0;
|
||||
_original_playback_rate = 1.0f;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
MilesAudioSample::
|
||||
~MilesAudioSample() {
|
||||
miles_audio_debug("~MilesAudioSample()");
|
||||
cleanup();
|
||||
miles_audio_debug("~MilesAudioSample() done");
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void MilesAudioSample::
|
||||
play() {
|
||||
miles_audio_debug("play()");
|
||||
if (_active) {
|
||||
if (_sd->_raw_data.empty()) {
|
||||
milesAudio_cat.warning()
|
||||
<< "Could not play " << _file_name << ": no data\n";
|
||||
} else {
|
||||
stop();
|
||||
_manager->starting_sound(this);
|
||||
|
||||
nassertv(_sample == 0);
|
||||
|
||||
GlobalMilesManager *mgr = GlobalMilesManager::get_global_ptr();
|
||||
if (!mgr->get_sample(_sample, _sample_index, this)){
|
||||
milesAudio_cat.warning()
|
||||
<< "Could not play " << _file_name << ": too many open samples\n";
|
||||
_sample = 0;
|
||||
} else {
|
||||
AIL_set_named_sample_file(_sample, _sd->_basename.c_str(),
|
||||
&_sd->_raw_data[0], _sd->_raw_data.size(),
|
||||
0);
|
||||
_original_playback_rate = AIL_sample_playback_rate(_sample);
|
||||
AIL_set_sample_user_data(_sample, 0, (SINTa)this);
|
||||
AIL_register_EOS_callback(_sample, finish_callback);
|
||||
|
||||
set_volume(_volume);
|
||||
set_play_rate(_play_rate);
|
||||
AIL_set_sample_loop_count(_sample, _loop_count);
|
||||
|
||||
if (_got_start_time) {
|
||||
do_set_time(_start_time);
|
||||
AIL_resume_sample(_sample);
|
||||
} else {
|
||||
AIL_start_sample(_sample);
|
||||
}
|
||||
}
|
||||
|
||||
_got_start_time = false;
|
||||
}
|
||||
} else {
|
||||
// In case _loop_count gets set to forever (zero):
|
||||
audio_debug(" paused "<<_file_name );
|
||||
_paused = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void MilesAudioSample::
|
||||
stop() {
|
||||
if (_manager == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
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 cddvd 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().
|
||||
|
||||
// it fixes audio bug, I don't understand the reasoning of the above comment
|
||||
_paused = false;
|
||||
|
||||
if (_sample != 0) {
|
||||
AIL_end_sample(_sample);
|
||||
|
||||
GlobalMilesManager *mgr = GlobalMilesManager::get_global_ptr();
|
||||
mgr->release_sample(_sample_index, this);
|
||||
|
||||
_sample = 0;
|
||||
_sample_index = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
PN_stdfloat MilesAudioSample::
|
||||
get_time() const {
|
||||
if (_sample == 0) {
|
||||
if (_got_start_time) {
|
||||
return _start_time;
|
||||
}
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
S32 current_ms;
|
||||
AIL_sample_ms_position(_sample, nullptr, ¤t_ms);
|
||||
PN_stdfloat time = PN_stdfloat(current_ms * 0.001f);
|
||||
|
||||
return time;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void MilesAudioSample::
|
||||
set_volume(PN_stdfloat 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 (_sample != 0) {
|
||||
volume *= _manager->get_volume();
|
||||
|
||||
// Change to Miles volume, range 0 to 1.0:
|
||||
F32 milesVolume = volume;
|
||||
milesVolume = std::min(milesVolume, 1.0f);
|
||||
milesVolume = std::max(milesVolume, 0.0f);
|
||||
|
||||
// Convert balance of -1.0..1.0 to 0-1.0:
|
||||
F32 milesBalance = (F32)((_balance + 1.0f) * 0.5f);
|
||||
|
||||
AIL_set_sample_volume_pan(_sample, milesVolume, milesBalance);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void MilesAudioSample::
|
||||
set_balance(PN_stdfloat balance_right) {
|
||||
miles_audio_debug("set_balance(balance_right="<<balance_right<<")");
|
||||
_balance = balance_right;
|
||||
|
||||
// Call set_volume to effect the change:
|
||||
set_volume(_volume);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void MilesAudioSample::
|
||||
set_play_rate(PN_stdfloat play_rate) {
|
||||
miles_audio_debug("set_play_rate(play_rate="<<play_rate<<")");
|
||||
|
||||
// Set the play_rate:
|
||||
_play_rate = play_rate;
|
||||
|
||||
if (_sample != 0) {
|
||||
play_rate *= _manager->get_play_rate();
|
||||
|
||||
// wave and mp3 use sample rate (e.g. 44100)
|
||||
S32 speed = (S32)(play_rate * (PN_stdfloat)_original_playback_rate);
|
||||
AIL_set_sample_playback_rate(_sample, speed);
|
||||
audio_debug(" play_rate for this wav or mp3 is now " << speed);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
PN_stdfloat MilesAudioSample::
|
||||
length() const {
|
||||
return _sd->get_length();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
AudioSound::SoundStatus MilesAudioSample::
|
||||
status() const {
|
||||
if (_sample == 0) {
|
||||
return AudioSound::READY;
|
||||
}
|
||||
switch (AIL_sample_status(_sample)) {
|
||||
case SMP_DONE:
|
||||
case SMP_STOPPED:
|
||||
case SMP_FREE:
|
||||
return AudioSound::READY;
|
||||
|
||||
case SMP_PLAYING:
|
||||
case SMP_PLAYINGBUTRELEASED:
|
||||
return AudioSound::PLAYING;
|
||||
|
||||
default:
|
||||
return AudioSound::BAD;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the sound from playing and releases any associated resources, in
|
||||
* preparation for releasing the sound or shutting down the sound system.
|
||||
*/
|
||||
void MilesAudioSample::
|
||||
cleanup() {
|
||||
stop();
|
||||
set_active(false);
|
||||
nassertv(_sample == 0);
|
||||
|
||||
if (_manager != nullptr) {
|
||||
_manager->release_sound(this);
|
||||
_manager = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void MilesAudioSample::
|
||||
output(std::ostream &out) const {
|
||||
out << get_type() << " " << get_name() << " " << status();
|
||||
if (!_sd.is_null()) {
|
||||
out << " " << (_sd->_raw_data.size() + 1023) / 1024 << "K";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set position and velocity of this sound. Note that Y and Z are switched to
|
||||
* translate from Miles's coordinate system.
|
||||
*/
|
||||
void MilesAudioSample::set_3d_attributes(PN_stdfloat px, PN_stdfloat py, PN_stdfloat pz, PN_stdfloat vx, PN_stdfloat vy, PN_stdfloat vz) {
|
||||
audio_debug("MilesAudioSample::set_3d_attributes() Setting a sound's 3D Coordinates.");
|
||||
|
||||
if(_sample != 0) {
|
||||
AIL_set_sample_3D_position(_sample, px, pz, py);
|
||||
AIL_set_sample_3D_velocity_vector(_sample, vx, vz, vy);
|
||||
} else {
|
||||
audio_warning("_sample == 0 in MilesAudioSample::set_3d_attributes().");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get position and velocity of this sound.
|
||||
*/
|
||||
void MilesAudioSample::get_3d_attributes(PN_stdfloat *px, PN_stdfloat *py, PN_stdfloat *pz, PN_stdfloat *vx, PN_stdfloat *vy, PN_stdfloat *vz) {
|
||||
audio_debug("MilesAudioSample::get_3d_attributes().");
|
||||
|
||||
if(_sample != 0) {
|
||||
float lpx, lpy, lpz, lvx, lvy, lvz;
|
||||
AIL_sample_3D_position(_sample, &lpx, &lpz, &lpy);
|
||||
AIL_sample_3D_velocity(_sample, &lvx, &lvz, &lvy);
|
||||
*px = lpx;
|
||||
*py = lpy;
|
||||
*pz = lpz;
|
||||
*vx = lvx;
|
||||
*vy = lvy;
|
||||
*vz = lvz;
|
||||
} else {
|
||||
audio_warning("_sample == 0 in MilesAudioSample::get_3d_attributes().");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the distance that this sound begins to fall off. With Miles's default
|
||||
* falloff behavior, when the distance between the sound and the listener is
|
||||
* doubled, the volume is halved, and vice versa.
|
||||
*/
|
||||
void MilesAudioSample::set_3d_min_distance(PN_stdfloat dist) {
|
||||
audio_debug("MilesAudioSample::set_3d_min_distance() Setting the sound's 3D min distance ( min= " << dist << " ) ");
|
||||
|
||||
if(_sample != 0) {
|
||||
// Implementation is awkward, since Miles gets and sets min and max
|
||||
// distances in a single operation.
|
||||
float max_dist;
|
||||
int auto_3D_wet_atten;
|
||||
AIL_sample_3D_distances(_sample, &max_dist, nullptr, &auto_3D_wet_atten);
|
||||
|
||||
AIL_set_sample_3D_distances(_sample, max_dist, dist, auto_3D_wet_atten);
|
||||
} else {
|
||||
audio_warning("_sample == 0 in MilesAudioSample::set_3d_min_distance().");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the distance that this sound begins to fall off.
|
||||
*/
|
||||
PN_stdfloat MilesAudioSample::get_3d_min_distance() const {
|
||||
audio_debug("MilesAudioSample::get_3d_min_distance() ");
|
||||
|
||||
if(_sample != 0) {
|
||||
float min_dist;
|
||||
AIL_sample_3D_distances(_sample, nullptr, &min_dist, nullptr);
|
||||
return (PN_stdfloat)min_dist;
|
||||
} else {
|
||||
audio_warning("_sample == 0 in MilesAudioSample::get_3d_min_distance().");
|
||||
return -1.0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the distance at which this sound is clipped to silence. Note that this
|
||||
* value does not affect the rate at which the sound falls off, but only the
|
||||
* distance at which it gets clipped.
|
||||
*/
|
||||
void MilesAudioSample::set_3d_max_distance(PN_stdfloat dist) {
|
||||
audio_debug("MilesAudioSample::set_3d_max_distance() Setting the sound's 3D max distance ( max= " << dist << " ) ");
|
||||
|
||||
if(_sample != 0) {
|
||||
// Implementation is awkward, since Miles gets and sets min and max
|
||||
// distances in a single operation.
|
||||
float min_dist;
|
||||
int auto_3D_wet_atten;
|
||||
AIL_sample_3D_distances(_sample, nullptr, &min_dist, &auto_3D_wet_atten);
|
||||
|
||||
AIL_set_sample_3D_distances(_sample, dist, min_dist, auto_3D_wet_atten);
|
||||
} else {
|
||||
audio_warning("_sample == 0 in MilesAudioSample::set_3d_max_distance().");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the distance at which this sound is clipped to silence.
|
||||
*/
|
||||
PN_stdfloat MilesAudioSample::get_3d_max_distance() const {
|
||||
audio_debug("MilesAudioSample::get_3d_max_distance() ");
|
||||
|
||||
if(_sample != 0) {
|
||||
float max_dist;
|
||||
AIL_sample_3D_distances(_sample, &max_dist, nullptr, nullptr);
|
||||
return (PN_stdfloat)max_dist;
|
||||
} else {
|
||||
audio_warning("_sample == 0 in MilesAudioSample::get_3d_max_distance().");
|
||||
return -1.0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the level of a particular logical channel (speaker). "index" specifies
|
||||
* which speaker in an array of all the logical channels currently in use to
|
||||
* retrieve the level of.
|
||||
*
|
||||
* For instance, in a standard 4.0 channel setup, speakers are setup as
|
||||
* [frontLeft, frontRight, backLeft, backRight]. Thus, get_speaker_level(2)
|
||||
* will retrieve the level of the backLeft speaker.
|
||||
*
|
||||
* The order in which speakers appear in the array for standard speaker setups
|
||||
* is defined to be:
|
||||
*
|
||||
* FRONT_LEFT FRONT_RIGHT FRONT_CENTER LOW_FREQUENCY (sub woofer) BACK_LEFT
|
||||
* BACK_RIGHT FRONT_LEFT_OF_CENTER FRONT_RIGHT_OF_CENTER BACK_CENTER SIDE_LEFT
|
||||
* SIDE_RIGHT TOP_CENTER TOP_FRONT_LEFT TOP_FRONT_CENTER TOP_FRONT_RIGHT
|
||||
* TOP_BACK_LEFT TOP_BACK_CENTER TOP_BACK_RIGHT
|
||||
*
|
||||
*/
|
||||
PN_stdfloat MilesAudioSample::
|
||||
get_speaker_level(int index) {
|
||||
audio_debug("MilesAudioSample::get_speaker_level(" << index << ")");
|
||||
|
||||
if(_sample != 0) {
|
||||
int numLevels;
|
||||
float *levels = AIL_sample_channel_levels(_sample, &numLevels);
|
||||
|
||||
if(index < numLevels) {
|
||||
return (PN_stdfloat)levels[index];
|
||||
} else {
|
||||
audio_error("index out of range in MilesAudioSample::get_speaker_level. numLevels: " << numLevels);
|
||||
return -1.0;
|
||||
}
|
||||
} else {
|
||||
audio_warning("Warning: MilesAudioSample::get_speaker_level only works for sounds that are currently playing");
|
||||
return -1.0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the output levels on the logical channels (speakers) for this sound.
|
||||
* Values should be in the range 0.0 to 1.0. Levels for up to nine channels
|
||||
* may be specified. As soon as a level is reached that falls outside the
|
||||
* range 0.0 to 1.0, the levels specified up to that point will be sent and
|
||||
* all other levels will be ignored.
|
||||
*
|
||||
* The user must know what the current speaker setup is in order to know which
|
||||
* level corresponds to which speaker.
|
||||
*
|
||||
* This method will have no effect if 3D attributes have been set for this
|
||||
* sound.
|
||||
*
|
||||
* The order in which speakers appear in the array for standard speaker setups
|
||||
* is defined to be:
|
||||
*
|
||||
* FRONT_LEFT FRONT_RIGHT FRONT_CENTER LOW_FREQUENCY (sub woofer) BACK_LEFT
|
||||
* BACK_RIGHT FRONT_LEFT_OF_CENTER FRONT_RIGHT_OF_CENTER BACK_CENTER SIDE_LEFT
|
||||
* SIDE_RIGHT TOP_CENTER TOP_FRONT_LEFT TOP_FRONT_CENTER TOP_FRONT_RIGHT
|
||||
* TOP_BACK_LEFT TOP_BACK_CENTER TOP_BACK_RIGHT
|
||||
*
|
||||
*/
|
||||
void MilesAudioSample::
|
||||
set_speaker_levels(PN_stdfloat level1, PN_stdfloat level2, PN_stdfloat level3, PN_stdfloat level4, PN_stdfloat level5, PN_stdfloat level6, PN_stdfloat level7, PN_stdfloat level8, PN_stdfloat level9) {
|
||||
audio_debug("MilesAudioSample::set_speaker_levels()");
|
||||
|
||||
if(_sample != 0) {
|
||||
float levels[9] = {level1, level2, level3, level4, level5, level6, level7, level8, level9};
|
||||
|
||||
if((level1 < 0.0) || (level1 > 1.0)) {
|
||||
audio_error("No valid levels specified in MilesAudioSample::set_speaker_levels().");
|
||||
} else if((level2 < 0.0) || (level2 > 1.0)) {
|
||||
AIL_set_sample_channel_levels(_sample, levels, 1);
|
||||
} else if((level3 < 0.0) || (level3 > 1.0)) {
|
||||
AIL_set_sample_channel_levels(_sample, levels, 2);
|
||||
} else if((level4 < 0.0) || (level4 > 1.0)) {
|
||||
AIL_set_sample_channel_levels(_sample, levels, 3);
|
||||
} else if((level5 < 0.0) || (level5 > 1.0)) {
|
||||
AIL_set_sample_channel_levels(_sample, levels, 4);
|
||||
} else if((level6 < 0.0) || (level6 > 1.0)) {
|
||||
AIL_set_sample_channel_levels(_sample, levels, 5);
|
||||
} else if((level7 < 0.0) || (level7 > 1.0)) {
|
||||
AIL_set_sample_channel_levels(_sample, levels, 6);
|
||||
} else if((level8 < 0.0) || (level8 > 1.0)) {
|
||||
AIL_set_sample_channel_levels(_sample, levels, 7);
|
||||
} else if((level9 < 0.0) || (level9 > 1.0)) {
|
||||
AIL_set_sample_channel_levels(_sample, levels, 8);
|
||||
} else {
|
||||
AIL_set_sample_channel_levels(_sample, levels, 9);
|
||||
}
|
||||
} else {
|
||||
audio_warning("Warning: MilesAudioSample::set_speaker_levels only works for sounds that are currently playing");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by the GlobalMilesManager when it is detected that this particular
|
||||
* sound has already stopped, and its sample handle will be recycled.
|
||||
*/
|
||||
void MilesAudioSample::
|
||||
internal_stop() {
|
||||
_sample = 0;
|
||||
_sample_index = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* This callback is made by Miles (possibly in a sub-thread) when the sample
|
||||
* finishes.
|
||||
*/
|
||||
void AILCALLBACK MilesAudioSample::
|
||||
finish_callback(HSAMPLE sample) {
|
||||
MilesAudioSample *self = (MilesAudioSample *)AIL_sample_user_data(sample, 0);
|
||||
if (milesAudio_cat.is_debug()) {
|
||||
milesAudio_cat.debug()
|
||||
<< "finished " << *self << "\n";
|
||||
}
|
||||
if (self->_manager == nullptr) {
|
||||
return;
|
||||
}
|
||||
self->_manager->_sounds_finished = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the start time of an already allocated sample.
|
||||
*/
|
||||
void MilesAudioSample::
|
||||
do_set_time(PN_stdfloat time) {
|
||||
miles_audio_debug("do_set_time(time="<<time<<")");
|
||||
nassertv(_sample != 0);
|
||||
|
||||
// Ensure we don't inadvertently run off the end of the sound.
|
||||
PN_stdfloat max_time = length();
|
||||
if (time > max_time) {
|
||||
milesAudio_cat.warning()
|
||||
<< "set_time(" << time << ") requested for sound of length "
|
||||
<< max_time << "\n";
|
||||
time = max_time;
|
||||
}
|
||||
|
||||
S32 time_ms = (S32)(1000.0f * time);
|
||||
AIL_set_sample_ms_position(_sample, time_ms);
|
||||
}
|
||||
|
||||
#endif //]
|
@ -1,103 +0,0 @@
|
||||
/**
|
||||
* 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."
|
||||
*
|
||||
* @file milesAudioSample.h
|
||||
* @author skyler
|
||||
* @date 2001-06-06
|
||||
* Prior system by: cary
|
||||
*/
|
||||
|
||||
#ifndef MILESAUDIOSAMPLE_H
|
||||
#define MILESAUDIOSAMPLE_H
|
||||
|
||||
#include "pandabase.h"
|
||||
#ifdef HAVE_RAD_MSS //[
|
||||
|
||||
#include "milesAudioSound.h"
|
||||
#include "milesAudioManager.h"
|
||||
|
||||
#include <mss.h>
|
||||
|
||||
/**
|
||||
* A sound file, such as a WAV or MP3 file, that is preloaded into memory and
|
||||
* played from memory.
|
||||
*/
|
||||
class EXPCL_MILES_AUDIO MilesAudioSample : public MilesAudioSound {
|
||||
private:
|
||||
MilesAudioSample(MilesAudioManager *manager,
|
||||
MilesAudioManager::SoundData *sd,
|
||||
const std::string &file_name);
|
||||
|
||||
public:
|
||||
virtual ~MilesAudioSample();
|
||||
|
||||
virtual void play();
|
||||
virtual void stop();
|
||||
|
||||
virtual PN_stdfloat get_time() const;
|
||||
|
||||
virtual void set_volume(PN_stdfloat volume=1.0f);
|
||||
virtual void set_balance(PN_stdfloat balance_right=0.0f);
|
||||
virtual void set_play_rate(PN_stdfloat play_rate=1.0f);
|
||||
|
||||
virtual PN_stdfloat length() const;
|
||||
|
||||
virtual AudioSound::SoundStatus status() const;
|
||||
|
||||
virtual void cleanup();
|
||||
virtual void output(std::ostream &out) const;
|
||||
|
||||
// 3D spatialized sound support. Spatialized sound was originally added for
|
||||
// FMOD, so there are parts of the interface in the Miles implementation
|
||||
// that are a little more awkward than they would be otherwise.
|
||||
void set_3d_attributes(PN_stdfloat px, PN_stdfloat py, PN_stdfloat pz, PN_stdfloat vx, PN_stdfloat vy, PN_stdfloat vz);
|
||||
void get_3d_attributes(PN_stdfloat *px, PN_stdfloat *py, PN_stdfloat *pz, PN_stdfloat *vx, PN_stdfloat *vy, PN_stdfloat *vz);
|
||||
void set_3d_min_distance(PN_stdfloat dist);
|
||||
PN_stdfloat get_3d_min_distance() const;
|
||||
void set_3d_max_distance(PN_stdfloat dist);
|
||||
PN_stdfloat get_3d_max_distance() const;
|
||||
|
||||
virtual PN_stdfloat get_speaker_level(int index);
|
||||
virtual void set_speaker_levels(PN_stdfloat level1, PN_stdfloat level2=-1.0f, PN_stdfloat level3=-1.0f, PN_stdfloat level4=-1.0f, PN_stdfloat level5=-1.0f, PN_stdfloat level6=-1.0f, PN_stdfloat level7=-1.0f, PN_stdfloat level8=-1.0f, PN_stdfloat level9=-1.0f);
|
||||
|
||||
private:
|
||||
void internal_stop();
|
||||
static void AILCALLBACK finish_callback(HSAMPLE sample);
|
||||
void do_set_time(PN_stdfloat time);
|
||||
|
||||
PT(MilesAudioManager::SoundData) _sd;
|
||||
HSAMPLE _sample;
|
||||
size_t _sample_index;
|
||||
S32 _original_playback_rate;
|
||||
|
||||
public:
|
||||
static TypeHandle get_class_type() {
|
||||
return _type_handle;
|
||||
}
|
||||
static void init_type() {
|
||||
MilesAudioSound::init_type();
|
||||
register_type(_type_handle, "MilesAudioSample",
|
||||
MilesAudioSound::get_class_type());
|
||||
}
|
||||
virtual TypeHandle get_type() const {
|
||||
return get_class_type();
|
||||
}
|
||||
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
|
||||
|
||||
private:
|
||||
static TypeHandle _type_handle;
|
||||
|
||||
friend class GlobalMilesManager;
|
||||
friend class MilesAudioManager;
|
||||
};
|
||||
|
||||
#include "milesAudioSample.I"
|
||||
|
||||
#endif //]
|
||||
|
||||
#endif /* MILESAUDIOSAMPLE_H */
|
@ -1,12 +0,0 @@
|
||||
/**
|
||||
* 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."
|
||||
*
|
||||
* @file milesAudioSequence.I
|
||||
* @author drose
|
||||
* @date 2007-07-31
|
||||
*/
|
@ -1,331 +0,0 @@
|
||||
/**
|
||||
* 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."
|
||||
*
|
||||
* @file milesAudioSequence.cxx
|
||||
* @author drose
|
||||
* @date 2007-07-31
|
||||
*/
|
||||
|
||||
#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 //]
|
||||
|
||||
/**
|
||||
* This constructor is called only by the MilesAudioManager.
|
||||
*/
|
||||
MilesAudioSequence::
|
||||
MilesAudioSequence(MilesAudioManager *manager, MilesAudioManager::SoundData *sd,
|
||||
const std::string &file_name) :
|
||||
MilesAudioSound(manager, file_name),
|
||||
_sd(sd)
|
||||
{
|
||||
nassertv(sd != nullptr);
|
||||
audio_debug("MilesAudioSequence(manager=0x"<<(void*)&manager
|
||||
<<", sd=0x"<<(void*)sd<<", file_name="<<file_name<<")");
|
||||
|
||||
_sequence = 0;
|
||||
_sequence_index = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
MilesAudioSequence::
|
||||
~MilesAudioSequence() {
|
||||
miles_audio_debug("~MilesAudioSequence()");
|
||||
cleanup();
|
||||
_manager->release_sound(this);
|
||||
miles_audio_debug("~MilesAudioSequence() done");
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
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 cddvd 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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
PN_stdfloat 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, nullptr, ¤t_ms);
|
||||
PN_stdfloat time = PN_stdfloat(current_ms * 0.001f);
|
||||
|
||||
return time;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void MilesAudioSequence::
|
||||
set_volume(PN_stdfloat 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 = std::min(milesVolume, 127);
|
||||
milesVolume = std::max(milesVolume, 0);
|
||||
|
||||
AIL_set_sequence_volume(_sequence, milesVolume, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void MilesAudioSequence::
|
||||
set_balance(PN_stdfloat balance_right) {
|
||||
miles_audio_debug("set_balance(balance_right="<<balance_right<<")");
|
||||
_balance = balance_right;
|
||||
|
||||
// Balance has no effect on a MIDI file.
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void MilesAudioSequence::
|
||||
set_play_rate(PN_stdfloat 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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
PN_stdfloat 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, nullptr);
|
||||
PN_stdfloat time = (PN_stdfloat)length_ms * 0.001f;
|
||||
return time;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the start time of an already allocated stream.
|
||||
*/
|
||||
void MilesAudioSequence::
|
||||
do_set_time(PN_stdfloat 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, nullptr);
|
||||
time_ms = std::min(time_ms, length_ms);
|
||||
|
||||
AIL_set_sequence_ms_position(_sequence, time_ms);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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, nullptr);
|
||||
PN_stdfloat time = (PN_stdfloat)length_ms * 0.001f;
|
||||
mgr->release_sequence(_sequence_index, this);
|
||||
_sequence = 0;
|
||||
_sequence_index = 0;
|
||||
|
||||
_sd->set_length(time);
|
||||
}
|
||||
}
|
||||
|
||||
#endif //]
|
@ -1,88 +0,0 @@
|
||||
/**
|
||||
* 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."
|
||||
*
|
||||
* @file milesAudioSequence.h
|
||||
* @author drose
|
||||
* @date 2007-07-31
|
||||
*/
|
||||
|
||||
#ifndef MILESAUDIOSEQUENCE_H
|
||||
#define MILESAUDIOSEQUENCE_H
|
||||
|
||||
#include "pandabase.h"
|
||||
#ifdef HAVE_RAD_MSS //[
|
||||
|
||||
#include "milesAudioSound.h"
|
||||
#include "milesAudioManager.h"
|
||||
|
||||
#include <mss.h>
|
||||
|
||||
/**
|
||||
* A MIDI file, preloaded and played from a memory buffer. MIDI files cannot
|
||||
* be streamed.
|
||||
*/
|
||||
class EXPCL_MILES_AUDIO MilesAudioSequence : public MilesAudioSound {
|
||||
private:
|
||||
MilesAudioSequence(MilesAudioManager *manager,
|
||||
MilesAudioManager::SoundData *sd,
|
||||
const std::string &file_name);
|
||||
|
||||
public:
|
||||
virtual ~MilesAudioSequence();
|
||||
|
||||
virtual void play();
|
||||
virtual void stop();
|
||||
|
||||
virtual PN_stdfloat get_time() const;
|
||||
|
||||
virtual void set_volume(PN_stdfloat volume=1.0f);
|
||||
virtual void set_balance(PN_stdfloat balance_right=0.0f);
|
||||
virtual void set_play_rate(PN_stdfloat play_rate=1.0f);
|
||||
|
||||
virtual PN_stdfloat length() const;
|
||||
|
||||
virtual AudioSound::SoundStatus status() const;
|
||||
|
||||
virtual void cleanup();
|
||||
|
||||
private:
|
||||
void internal_stop();
|
||||
static void AILCALLBACK finish_callback(HSEQUENCE sequence);
|
||||
void do_set_time(PN_stdfloat time);
|
||||
void determine_length();
|
||||
|
||||
PT(MilesAudioManager::SoundData) _sd;
|
||||
HSEQUENCE _sequence;
|
||||
size_t _sequence_index;
|
||||
|
||||
public:
|
||||
static TypeHandle get_class_type() {
|
||||
return _type_handle;
|
||||
}
|
||||
static void init_type() {
|
||||
MilesAudioSound::init_type();
|
||||
register_type(_type_handle, "MilesAudioSequence",
|
||||
MilesAudioSound::get_class_type());
|
||||
}
|
||||
virtual TypeHandle get_type() const {
|
||||
return get_class_type();
|
||||
}
|
||||
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
|
||||
|
||||
private:
|
||||
static TypeHandle _type_handle;
|
||||
|
||||
friend class GlobalMilesManager;
|
||||
friend class MilesAudioManager;
|
||||
};
|
||||
|
||||
#include "milesAudioSequence.I"
|
||||
|
||||
#endif //]
|
||||
|
||||
#endif /* MILESAUDIOSEQUENCE_H */
|
@ -1,12 +0,0 @@
|
||||
/**
|
||||
* 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."
|
||||
*
|
||||
* @file milesAudioSound.I
|
||||
* @author drose
|
||||
* @date 2007-07-30
|
||||
*/
|
@ -1,205 +0,0 @@
|
||||
/**
|
||||
* 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."
|
||||
*
|
||||
* @file milesAudioSound.cxx
|
||||
* @author drose
|
||||
* @date 2007-07-30
|
||||
*/
|
||||
|
||||
#include "milesAudioSound.h"
|
||||
#ifdef HAVE_RAD_MSS //[
|
||||
|
||||
#include "milesAudioManager.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
TypeHandle MilesAudioSound::_type_handle;
|
||||
|
||||
#undef miles_audio_debug
|
||||
|
||||
#ifndef NDEBUG //[
|
||||
#define miles_audio_debug(x) \
|
||||
audio_debug("MilesAudioSound \""<<get_name()<<"\" "<< x )
|
||||
#else //][
|
||||
#define miles_audio_debug(x) ((void)0)
|
||||
#endif //]
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
MilesAudioSound::
|
||||
MilesAudioSound(MilesAudioManager *manager,
|
||||
const string &file_name) :
|
||||
_manager(manager),
|
||||
_file_name(file_name),
|
||||
_volume(1.0f), _balance(0), _play_rate(1.0f),
|
||||
_loop_count(1),
|
||||
_active(true),
|
||||
_paused(false),
|
||||
_start_time(0.0f),
|
||||
_got_start_time(false)
|
||||
{
|
||||
nassertv(!file_name.empty());
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void MilesAudioSound::
|
||||
set_loop(bool loop) {
|
||||
// loop count of 0 means always loop
|
||||
set_loop_count((loop)?0:1);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
bool MilesAudioSound::
|
||||
get_loop() const {
|
||||
return (_loop_count == 0);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void MilesAudioSound::
|
||||
set_loop_count(unsigned long loop_count) {
|
||||
if (_loop_count != loop_count) {
|
||||
_loop_count = loop_count;
|
||||
if (status() == PLAYING) {
|
||||
// hack: For now, the loop count is picked up when the sound starts
|
||||
// playing. There may be a way to change the loop count of a playing
|
||||
// sound, but I'm going to focus on other things. If you would like to
|
||||
// change the need to stop and start the sound, feel free. Or, maybe
|
||||
// I'll spend time on it in the future. Please set the loop option
|
||||
// before starting the sound.
|
||||
play();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
unsigned long MilesAudioSound::
|
||||
get_loop_count() const {
|
||||
return _loop_count;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
PN_stdfloat MilesAudioSound::
|
||||
get_volume() const {
|
||||
return _volume;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
PN_stdfloat MilesAudioSound::
|
||||
get_balance() const {
|
||||
return _balance;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
PN_stdfloat MilesAudioSound::
|
||||
get_play_rate() const {
|
||||
return _play_rate;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void MilesAudioSound::
|
||||
set_time(PN_stdfloat time) {
|
||||
miles_audio_debug("set_time(time="<<time<<")");
|
||||
|
||||
// Mark this position for the next play().
|
||||
_start_time = time;
|
||||
_got_start_time = true;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void MilesAudioSound::
|
||||
set_active(bool active) {
|
||||
if (_manager == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
miles_audio_debug("set_active(active="<<active<<")");
|
||||
if (_active != active) {
|
||||
_active = active;
|
||||
if (_active) {
|
||||
// ...activate the sound.
|
||||
if (_paused && _loop_count==0) {
|
||||
// ...this sound was looping when it was paused.
|
||||
_paused = false;
|
||||
play();
|
||||
}
|
||||
|
||||
} else {
|
||||
// ...deactivate the sound.
|
||||
if (status() == PLAYING) {
|
||||
if (_loop_count == 0) {
|
||||
// ...we're pausing a looping sound.
|
||||
_paused = true;
|
||||
}
|
||||
_start_time = get_time();
|
||||
_got_start_time = true;
|
||||
stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
bool MilesAudioSound::
|
||||
get_active() const {
|
||||
return _active;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is no longer implemented.
|
||||
*/
|
||||
void MilesAudioSound::
|
||||
set_finished_event(const string &event) {
|
||||
_finished_event = event;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is no longer implemented.
|
||||
*/
|
||||
const string &MilesAudioSound::
|
||||
get_finished_event() const {
|
||||
return _finished_event;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
const string &MilesAudioSound::
|
||||
get_name() const {
|
||||
return _file_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the sound from playing and releases any associated resources, in
|
||||
* preparation for releasing the sound or shutting down the sound system.
|
||||
*/
|
||||
void MilesAudioSound::
|
||||
cleanup() {
|
||||
}
|
||||
|
||||
#endif //]
|
@ -1,107 +0,0 @@
|
||||
/**
|
||||
* 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."
|
||||
*
|
||||
* @file milesAudioSound.h
|
||||
* @author drose
|
||||
* @date 2007-07-30
|
||||
*/
|
||||
|
||||
#ifndef MILESAUDIOSOUND_H
|
||||
#define MILESAUDIOSOUND_H
|
||||
|
||||
#include "pandabase.h"
|
||||
#ifdef HAVE_RAD_MSS //[
|
||||
|
||||
#include "audioSound.h"
|
||||
#include "milesAudioManager.h"
|
||||
|
||||
#include <mss.h>
|
||||
|
||||
/**
|
||||
* The base class for both MilesAudioStream and MilesAudioSample.
|
||||
*/
|
||||
class EXPCL_MILES_AUDIO MilesAudioSound : public AudioSound {
|
||||
protected:
|
||||
MilesAudioSound(MilesAudioManager *manager, const std::string &file_name);
|
||||
|
||||
public:
|
||||
virtual void set_loop(bool loop=true);
|
||||
virtual bool get_loop() const;
|
||||
|
||||
virtual void set_loop_count(unsigned long loop_count=1);
|
||||
virtual unsigned long get_loop_count() const;
|
||||
|
||||
virtual PN_stdfloat get_volume() const;
|
||||
virtual PN_stdfloat get_balance() const;
|
||||
virtual PN_stdfloat get_play_rate() const;
|
||||
|
||||
virtual void set_time(PN_stdfloat start_time=0.0);
|
||||
|
||||
virtual void set_active(bool active=true);
|
||||
virtual bool get_active() const;
|
||||
|
||||
virtual void set_finished_event(const std::string &event);
|
||||
virtual const std::string &get_finished_event() const;
|
||||
|
||||
virtual const std::string &get_name() const;
|
||||
|
||||
virtual void cleanup();
|
||||
|
||||
protected:
|
||||
PT(MilesAudioManager) _manager;
|
||||
std::string _file_name;
|
||||
|
||||
PN_stdfloat _volume; // 0..1.0
|
||||
PN_stdfloat _balance; // -1..1
|
||||
PN_stdfloat _play_rate; // 0..1.0
|
||||
unsigned long _loop_count;
|
||||
|
||||
// _active is for things like a 'turn off sound effects' in a preferences
|
||||
// pannel. _active is not about whether a sound is currently playing. Use
|
||||
// status() for info on whether the sound is playing.
|
||||
bool _active;
|
||||
|
||||
// _paused is not like the Pause button on a cddvd player. It is used as a
|
||||
// flag to say that the sound was looping when it was set inactive.
|
||||
bool _paused;
|
||||
|
||||
// This is the string that throw_event() will throw when the sound finishes
|
||||
// playing. It is not triggered when the sound is stopped with stop().
|
||||
// Note: no longer implemented.
|
||||
std::string _finished_event;
|
||||
|
||||
// This is set whenever we call set_time(). Calling play() will respect
|
||||
// this if it is set, and then reset it.
|
||||
PN_stdfloat _start_time;
|
||||
bool _got_start_time;
|
||||
|
||||
public:
|
||||
static TypeHandle get_class_type() {
|
||||
return _type_handle;
|
||||
}
|
||||
static void init_type() {
|
||||
AudioSound::init_type();
|
||||
register_type(_type_handle, "MilesAudioSound",
|
||||
AudioSound::get_class_type());
|
||||
}
|
||||
virtual TypeHandle get_type() const {
|
||||
return get_class_type();
|
||||
}
|
||||
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
|
||||
|
||||
private:
|
||||
static TypeHandle _type_handle;
|
||||
|
||||
friend class MilesAudioManager;
|
||||
};
|
||||
|
||||
#include "milesAudioSound.I"
|
||||
|
||||
#endif //]
|
||||
|
||||
#endif
|
@ -1,12 +0,0 @@
|
||||
/**
|
||||
* 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."
|
||||
*
|
||||
* @file milesAudioStream.I
|
||||
* @author drose
|
||||
* @date 2007-07-26
|
||||
*/
|
@ -1,310 +0,0 @@
|
||||
/**
|
||||
* 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."
|
||||
*
|
||||
* @file milesAudioStream.cxx
|
||||
* @author drose
|
||||
* @date 2007-07-26
|
||||
*/
|
||||
|
||||
#include "milesAudioStream.h"
|
||||
#ifdef HAVE_RAD_MSS //[
|
||||
|
||||
#include "milesAudioManager.h"
|
||||
#include "pnotify.h"
|
||||
|
||||
TypeHandle MilesAudioStream::_type_handle;
|
||||
|
||||
#undef miles_audio_debug
|
||||
|
||||
#ifndef NDEBUG //[
|
||||
#define miles_audio_debug(x) \
|
||||
audio_debug("MilesAudioStream \""<<get_name()<<"\" "<< x )
|
||||
#else //][
|
||||
#define miles_audio_debug(x) ((void)0)
|
||||
#endif //]
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
MilesAudioStream::
|
||||
MilesAudioStream(MilesAudioManager *manager, const std::string &file_name,
|
||||
const Filename &path) :
|
||||
MilesAudioSound(manager, file_name),
|
||||
_path(path)
|
||||
{
|
||||
_stream = 0;
|
||||
_got_length = false;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
MilesAudioStream::
|
||||
~MilesAudioStream() {
|
||||
miles_audio_debug("~MilesAudioStream()");
|
||||
cleanup();
|
||||
|
||||
miles_audio_debug("~MilesAudioStream() done");
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void MilesAudioStream::
|
||||
play() {
|
||||
miles_audio_debug("play()");
|
||||
if (_active) {
|
||||
|
||||
_manager->starting_sound(this);
|
||||
|
||||
if (_stream == 0) {
|
||||
GlobalMilesManager *mgr = GlobalMilesManager::get_global_ptr();
|
||||
_stream = AIL_open_stream(mgr->_digital_driver, _path.c_str(), 0);
|
||||
if (_stream == 0) {
|
||||
milesAudio_cat.warning()
|
||||
<< "Could not play " << _file_name << ": too many open streams\n";
|
||||
return;
|
||||
}
|
||||
AIL_set_stream_user_data(_stream, 0, (SINTa)this);
|
||||
AIL_register_stream_callback(_stream, finish_callback);
|
||||
|
||||
} else {
|
||||
// We already had the stream open. Keep it open; just restart it.
|
||||
AIL_pause_stream(_stream, 1);
|
||||
_manager->stop_service_stream(_stream);
|
||||
}
|
||||
|
||||
// Start playing:
|
||||
nassertv(_stream != 0);
|
||||
HSAMPLE sample = AIL_stream_sample_handle(_stream);
|
||||
nassertv(sample != 0);
|
||||
|
||||
_original_playback_rate = AIL_sample_playback_rate(sample);
|
||||
set_volume(_volume);
|
||||
set_play_rate(_play_rate);
|
||||
|
||||
AIL_set_stream_loop_count(_stream, _loop_count);
|
||||
|
||||
AIL_start_stream(_stream);
|
||||
if (_got_start_time) {
|
||||
// There's no AIL_resume_stream(), so we start in the middle by starting
|
||||
// normally, then immediately skipping to the middle.
|
||||
do_set_time(_start_time);
|
||||
}
|
||||
|
||||
if (miles_audio_panda_threads) {
|
||||
AIL_auto_service_stream(_stream, 0);
|
||||
_manager->start_service_stream(_stream);
|
||||
} else {
|
||||
AIL_auto_service_stream(_stream, 1);
|
||||
}
|
||||
|
||||
_got_start_time = false;
|
||||
|
||||
} else {
|
||||
// In case _loop_count gets set to forever (zero):
|
||||
audio_debug(" paused "<<_file_name );
|
||||
_paused = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void MilesAudioStream::
|
||||
stop() {
|
||||
if (_manager == nullptr) {
|
||||
return;
|
||||
}
|
||||
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 cddvd 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 (_stream != 0) {
|
||||
_manager->stop_service_stream(_stream);
|
||||
|
||||
AIL_pause_stream(_stream, 1);
|
||||
AIL_close_stream(_stream);
|
||||
_stream = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
PN_stdfloat MilesAudioStream::
|
||||
get_time() const {
|
||||
if (_stream == 0) {
|
||||
if (_got_start_time) {
|
||||
return _start_time;
|
||||
}
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
S32 current_ms;
|
||||
AIL_stream_ms_position(_stream, nullptr, ¤t_ms);
|
||||
PN_stdfloat time = PN_stdfloat(current_ms * 0.001f);
|
||||
|
||||
return time;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void MilesAudioStream::
|
||||
set_volume(PN_stdfloat volume) {
|
||||
_volume = volume;
|
||||
|
||||
if (_stream != 0) {
|
||||
HSAMPLE sample = AIL_stream_sample_handle(_stream);
|
||||
nassertv(sample != 0);
|
||||
|
||||
volume *= _manager->get_volume();
|
||||
|
||||
// Change to Miles volume, range 0 to 1.0:
|
||||
F32 milesVolume = volume;
|
||||
milesVolume = std::min(milesVolume, 1.0f);
|
||||
milesVolume = std::max(milesVolume, 0.0f);
|
||||
|
||||
// Convert balance of -1.0..1.0 to 0-1.0:
|
||||
F32 milesBalance = (F32)((_balance + 1.0f) * 0.5f);
|
||||
|
||||
AIL_set_sample_volume_pan(sample, milesVolume, milesBalance);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void MilesAudioStream::
|
||||
set_balance(PN_stdfloat balance_right) {
|
||||
_balance = balance_right;
|
||||
|
||||
// Call set_volume to effect the change:
|
||||
set_volume(_volume);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void MilesAudioStream::
|
||||
set_play_rate(PN_stdfloat play_rate) {
|
||||
_play_rate = play_rate;
|
||||
|
||||
if (_stream != 0) {
|
||||
HSAMPLE sample = AIL_stream_sample_handle(_stream);
|
||||
nassertv(sample != 0);
|
||||
|
||||
play_rate *= _manager->get_play_rate();
|
||||
|
||||
// wave and mp3 use sample rate (e.g. 44100)
|
||||
S32 speed = (S32)(play_rate * (PN_stdfloat)_original_playback_rate);
|
||||
AIL_set_sample_playback_rate(sample, speed);
|
||||
audio_debug(" play_rate for this wav or mp3 is now " << speed);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
PN_stdfloat MilesAudioStream::
|
||||
length() const {
|
||||
if (!_got_length) {
|
||||
if (_stream == 0) {
|
||||
GlobalMilesManager *mgr = GlobalMilesManager::get_global_ptr();
|
||||
((MilesAudioStream *)this)->_stream = AIL_open_stream(mgr->_digital_driver, _path.c_str(), 0);
|
||||
}
|
||||
|
||||
S32 length_ms;
|
||||
AIL_stream_ms_position(_stream, &length_ms, nullptr);
|
||||
_length = (PN_stdfloat)length_ms * 0.001f;
|
||||
_got_length = true;
|
||||
}
|
||||
|
||||
return _length;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
AudioSound::SoundStatus MilesAudioStream::
|
||||
status() const {
|
||||
if (!_stream) {
|
||||
return AudioSound::READY;
|
||||
}
|
||||
|
||||
switch (AIL_stream_status(_stream)) {
|
||||
case SMP_STOPPED:
|
||||
case SMP_DONE:
|
||||
return AudioSound::READY;
|
||||
case SMP_PLAYING:
|
||||
case SMP_PLAYINGBUTRELEASED:
|
||||
return AudioSound::PLAYING;
|
||||
default:
|
||||
return AudioSound::BAD;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called to release any resources associated with the sound.
|
||||
*/
|
||||
void MilesAudioStream::
|
||||
cleanup() {
|
||||
if (_stream) {
|
||||
stop();
|
||||
}
|
||||
set_active(false);
|
||||
nassertv(_stream == 0);
|
||||
|
||||
if (_manager != nullptr) {
|
||||
_manager->release_sound(this);
|
||||
_manager = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This callback is made by Miles (possibly in a sub-thread) when the stream
|
||||
* finishes.
|
||||
*/
|
||||
void AILCALLBACK MilesAudioStream::
|
||||
finish_callback(HSTREAM stream) {
|
||||
MilesAudioStream *self = (MilesAudioStream *)AIL_stream_user_data(stream, 0);
|
||||
if (milesAudio_cat.is_debug()) {
|
||||
milesAudio_cat.debug()
|
||||
<< "finished " << *self << "\n";
|
||||
}
|
||||
if (self->_manager == nullptr) {
|
||||
return;
|
||||
}
|
||||
self->_manager->_sounds_finished = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the start time of an already allocated stream.
|
||||
*/
|
||||
void MilesAudioStream::
|
||||
do_set_time(PN_stdfloat time) {
|
||||
nassertv(_stream != 0);
|
||||
|
||||
S32 time_ms = (S32)(1000.0f * time);
|
||||
|
||||
// Ensure we don't inadvertently run off the end of the sound.
|
||||
S32 length_ms;
|
||||
AIL_stream_ms_position(_stream, &length_ms, nullptr);
|
||||
time_ms = std::min(time_ms, length_ms);
|
||||
|
||||
AIL_set_stream_ms_position(_stream, time_ms);
|
||||
}
|
||||
|
||||
|
||||
#endif //]
|
@ -1,87 +0,0 @@
|
||||
/**
|
||||
* 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."
|
||||
*
|
||||
* @file milesAudioStream.h
|
||||
* @author drose
|
||||
* @date 2007-07-26
|
||||
*/
|
||||
|
||||
#ifndef MILESAUDIOSTREAM_H
|
||||
#define MILESAUDIOSTREAM_H
|
||||
|
||||
#include "pandabase.h"
|
||||
#ifdef HAVE_RAD_MSS //[
|
||||
|
||||
#include "milesAudioSound.h"
|
||||
#include "milesAudioManager.h"
|
||||
|
||||
#include <mss.h>
|
||||
|
||||
/**
|
||||
* This represents a sound file played by the Miles Sound System, similar to
|
||||
* MilesAudioSample, except that it is streamed from disk instead of preloaded
|
||||
* into memory.
|
||||
*/
|
||||
class EXPCL_MILES_AUDIO MilesAudioStream : public MilesAudioSound {
|
||||
private:
|
||||
MilesAudioStream(MilesAudioManager *manager, const std::string &file_name,
|
||||
const Filename &path);
|
||||
|
||||
public:
|
||||
virtual ~MilesAudioStream();
|
||||
|
||||
virtual void play();
|
||||
virtual void stop();
|
||||
|
||||
virtual PN_stdfloat get_time() const;
|
||||
|
||||
virtual void set_volume(PN_stdfloat volume=1.0f);
|
||||
virtual void set_balance(PN_stdfloat balance_right=0.0f);
|
||||
virtual void set_play_rate(PN_stdfloat play_rate=1.0f);
|
||||
|
||||
virtual PN_stdfloat length() const;
|
||||
|
||||
virtual AudioSound::SoundStatus status() const;
|
||||
|
||||
virtual void cleanup();
|
||||
|
||||
private:
|
||||
static void AILCALLBACK finish_callback(HSTREAM stream);
|
||||
void do_set_time(PN_stdfloat time);
|
||||
|
||||
Filename _path;
|
||||
HSTREAM _stream;
|
||||
S32 _original_playback_rate;
|
||||
mutable PN_stdfloat _length;
|
||||
mutable bool _got_length;
|
||||
|
||||
public:
|
||||
static TypeHandle get_class_type() {
|
||||
return _type_handle;
|
||||
}
|
||||
static void init_type() {
|
||||
MilesAudioSound::init_type();
|
||||
register_type(_type_handle, "MilesAudioStream",
|
||||
MilesAudioSound::get_class_type());
|
||||
}
|
||||
virtual TypeHandle get_type() const {
|
||||
return get_class_type();
|
||||
}
|
||||
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
|
||||
|
||||
private:
|
||||
static TypeHandle _type_handle;
|
||||
|
||||
friend class MilesAudioManager;
|
||||
};
|
||||
|
||||
#include "milesAudioStream.I"
|
||||
|
||||
#endif //]
|
||||
|
||||
#endif
|
@ -1,9 +0,0 @@
|
||||
|
||||
#include "config_milesAudio.cxx"
|
||||
#include "milesAudioManager.cxx"
|
||||
#include "milesAudioSample.cxx"
|
||||
#include "milesAudioSequence.cxx"
|
||||
#include "milesAudioSound.cxx"
|
||||
#include "milesAudioStream.cxx"
|
||||
#include "globalMilesManager.cxx"
|
||||
|
@ -53,14 +53,6 @@
|
||||
#define EXPTP_FRAMEWORK IMPORT_TEMPL
|
||||
#endif
|
||||
|
||||
#ifdef BUILDING_MILES_AUDIO
|
||||
#define EXPCL_MILES_AUDIO EXPORT_CLASS
|
||||
#define EXPTP_MILES_AUDIO EXPORT_TEMPL
|
||||
#else
|
||||
#define EXPCL_MILES_AUDIO IMPORT_CLASS
|
||||
#define EXPTP_MILES_AUDIO IMPORT_TEMPL
|
||||
#endif
|
||||
|
||||
#ifdef BUILDING_OPENAL_AUDIO
|
||||
#define EXPCL_OPENAL_AUDIO EXPORT_CLASS
|
||||
#define EXPTP_OPENAL_AUDIO EXPORT_TEMPL
|
||||
|
Loading…
x
Reference in New Issue
Block a user