Cort Stratton's FMOD implementation
This commit is contained in:
parent
264e112fad
commit
92fca841bd
|
|
@ -210,6 +210,8 @@ class ShowBase(DirectObject.DirectObject):
|
|||
del self.win
|
||||
del self.winList
|
||||
del self.pipe
|
||||
del self.musicManager
|
||||
del self.sfxManagerList
|
||||
|
||||
try:
|
||||
direct.panel.destroy()
|
||||
|
|
|
|||
|
|
@ -365,6 +365,13 @@
|
|||
#define RAD_MSS_LIBS Mss32
|
||||
#defer HAVE_RAD_MSS $[libtest $[RAD_MSS_LPATH],$[RAD_MSS_LIBS]]
|
||||
|
||||
// Info for the Fmod audio engine
|
||||
// note this may be overwritten in wintools Config.pp
|
||||
#define FMOD_IPATH
|
||||
#define FMOD_LPATH
|
||||
#define FMOD_LIBS fmod
|
||||
#defer HAVE_FMOD $[libtest $[FMOD_LPATH],$[FMOD_LIBS]]
|
||||
|
||||
// Info for http://www.sourceforge.net/projects/chromium
|
||||
// note this may be overwritten in wintools Config.pp
|
||||
#define CHROMIUM_IPATH /usr/include/chromium/include
|
||||
|
|
|
|||
|
|
@ -19,6 +19,9 @@ $[cdefine HAVE_PYTHON]
|
|||
/* Define if we have RAD game tools, Miles Sound System installed. */
|
||||
$[cdefine HAVE_RAD_MSS]
|
||||
|
||||
/* Define if we have FMOD installed. */
|
||||
$[cdefine HAVE_FMOD]
|
||||
|
||||
/* Define if we have Freetype 2.0 or better available. */
|
||||
$[cdefine HAVE_FREETYPE]
|
||||
|
||||
|
|
|
|||
|
|
@ -184,6 +184,11 @@
|
|||
#set RAD_MSS_LIBS $[RAD_MSS_LIBS]
|
||||
#set HAVE_RAD_MSS $[HAVE_RAD_MSS]
|
||||
|
||||
#set FMOD_IPATH $[unixfilename $[FMOD_IPATH]]
|
||||
#set FMOD_LPATH $[unixfilename $[FMOD_LPATH]]
|
||||
#set FMOD_LIBS $[FMOD_LIBS]
|
||||
#set HAVE_FMOD $[HAVE_FMOD]
|
||||
|
||||
#set CHROMIUM_IPATH $[unixfilename $[CHROMIUM_IPATH]]
|
||||
#set CHROMIUM_LPATH $[unixfilename $[CHROMIUM_LPATH]]
|
||||
#set CHROMIUM_LIBS $[CHROMIUM_LIBS]
|
||||
|
|
|
|||
|
|
@ -236,6 +236,12 @@
|
|||
#define rad_mss_libs $[RAD_MSS_LIBS]
|
||||
#endif
|
||||
|
||||
#if $[HAVE_FMOD]
|
||||
#define fmod_ipath $[wildcard $[FMOD_IPATH]]
|
||||
#define fmod_lpath $[wildcard $[FMOD_LPATH]]
|
||||
#define fmod_libs $[FMOD_LIBS]
|
||||
#endif
|
||||
|
||||
#if $[HAVE_CHROMIUM]
|
||||
#define chromium_ipath $[wildcard $[CHROMIUM_IPATH]]
|
||||
#define chromium_lpath $[wildcard $[CHROMIUM_LPATH]]
|
||||
|
|
|
|||
|
|
@ -21,6 +21,26 @@
|
|||
|
||||
#end lib_target
|
||||
|
||||
#begin lib_target
|
||||
#define TARGET fmod_audio
|
||||
#define BUILD_TARGET $[HAVE_FMOD]
|
||||
#define USE_PACKAGES fmod
|
||||
#define BUILDING_DLL BUILDING_FMOD_AUDIO
|
||||
#define LOCAL_LIBS audio
|
||||
#define WIN_SYS_LIBS $[WIN_SYS_LIBS] user32.lib advapi32.lib winmm.lib
|
||||
|
||||
#define COMBINED_SOURCES $[TARGET]_composite1.cxx
|
||||
|
||||
#define SOURCES \
|
||||
config_fmodAudio.h \
|
||||
fmodAudioManager.h \
|
||||
fmodAudioSound.I fmodAudioSound.h
|
||||
|
||||
#define INCLUDED_SOURCES \
|
||||
config_fmodAudio.cxx fmodAudioManager.cxx fmodAudioSound.cxx
|
||||
|
||||
#end lib_target
|
||||
|
||||
//#begin lib_target
|
||||
// #define TARGET audio_linux
|
||||
// #define BUILDING_DLL BUILDING_MISC
|
||||
|
|
|
|||
|
|
@ -0,0 +1,54 @@
|
|||
// Filename: config_fmodAudio.cxx
|
||||
// Created by: cort
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
|
||||
//
|
||||
// All use of this software is subject to the terms of the Panda 3d
|
||||
// Software license. You should have received a copy of this license
|
||||
// along with this source code; you will also find a current copy of
|
||||
// the license at http://www.panda3d.org/license.txt .
|
||||
//
|
||||
// To contact the maintainers of this program write to
|
||||
// panda3d@yahoogroups.com .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "pandabase.h"
|
||||
#ifdef HAVE_FMOD //[
|
||||
|
||||
#include "config_fmodAudio.h"
|
||||
#include "fmodAudioManager.h"
|
||||
#include "fmodAudioSound.h"
|
||||
#include "dconfig.h"
|
||||
|
||||
ConfigureDef(config_fmodAudio);
|
||||
NotifyCategoryDef(fmodAudio, "");
|
||||
|
||||
ConfigureFn(config_fmodAudio) {
|
||||
init_libFmodAudio();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: init_libFmodAudio
|
||||
// Description: 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_libFmodAudio() {
|
||||
static bool initialized = false;
|
||||
if (initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
initialized = true;
|
||||
|
||||
AudioManager::register_AudioManager_creator(Create_AudioManager);
|
||||
}
|
||||
|
||||
#endif //]
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
// Filename: config_fmodAudio.h
|
||||
// Created by: cort
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
|
||||
//
|
||||
// All use of this software is subject to the terms of the Panda 3d
|
||||
// Software license. You should have received a copy of this license
|
||||
// along with this source code; you will also find a current copy of
|
||||
// the license at http://www.panda3d.org/license.txt .
|
||||
//
|
||||
// To contact the maintainers of this program write to
|
||||
// panda3d@yahoogroups.com .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef CONFIG_FMODAUDIO_H
|
||||
#define CONFIG_FMODAUDIO_H
|
||||
|
||||
#include "pandabase.h"
|
||||
|
||||
#ifdef HAVE_FMOD //[
|
||||
#include "notifyCategoryProxy.h"
|
||||
#include "dconfig.h"
|
||||
|
||||
ConfigureDecl(config_fmodAudio, EXPCL_FMOD_AUDIO, EXPTP_FMOD_AUDIO);
|
||||
NotifyCategoryDecl(fmodAudio, EXPCL_FMOD_AUDIO, EXPTP_FMOD_AUDIO);
|
||||
|
||||
extern EXPCL_FMOD_AUDIO void init_libFmodAudio();
|
||||
|
||||
#endif //]
|
||||
|
||||
#endif // CONFIG_FMODAUDIO_H
|
||||
|
|
@ -0,0 +1,482 @@
|
|||
// Filename: fmodAudioManager.cxx
|
||||
// Created by: cort (January 22, 2003)
|
||||
// Prior system by: cary
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
|
||||
//
|
||||
// All use of this software is subject to the terms of the Panda 3d
|
||||
// Software license. You should have received a copy of this license
|
||||
// along with this source code; you will also find a current copy of
|
||||
// the license at http://www.panda3d.org/license.txt .
|
||||
//
|
||||
// To contact the maintainers of this program write to
|
||||
// panda3d@yahoogroups.com .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "pandabase.h"
|
||||
#ifdef HAVE_FMOD //[
|
||||
|
||||
#include "config_audio.h"
|
||||
#include "config_util.h"
|
||||
#include "config_express.h"
|
||||
#include "filename.h"
|
||||
#include "fmodAudioManager.h"
|
||||
#include "fmodAudioSound.h"
|
||||
#include "nullAudioSound.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <fmod.h>
|
||||
#include <iostream>
|
||||
using std::cerr;
|
||||
|
||||
PT(AudioManager) Create_AudioManager() {
|
||||
audio_debug("Create_AudioManager() Fmod.");
|
||||
return new FmodAudioManager;
|
||||
}
|
||||
|
||||
int FmodAudioManager::_active_managers = 0;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: FmodAudioManager::FmodAudioManager
|
||||
// Access:
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
FmodAudioManager::
|
||||
FmodAudioManager() {
|
||||
audio_debug("FmodAudioManager::FmodAudioManager()");
|
||||
audio_debug(" audio_active="<<audio_active);
|
||||
audio_debug(" audio_volume="<<audio_volume);
|
||||
|
||||
_active = audio_active;
|
||||
|
||||
// Initialize FMOD, if this is the first manager created.
|
||||
if (_active_managers == 0) {
|
||||
do {
|
||||
audio_debug("Initializing FMOD for real.");
|
||||
float fmod_dll_version = FSOUND_GetVersion();
|
||||
if (fmod_dll_version < FMOD_VERSION) {
|
||||
audio_error("Wrong FMOD DLL version. You have "<<fmod_dll_version
|
||||
<<". You need "<<FMOD_VERSION);
|
||||
_is_valid = false;
|
||||
break;
|
||||
}
|
||||
if (FSOUND_Init(44100, 32, 0) == 0) {
|
||||
audio_error("Fmod initialization failure.");
|
||||
_is_valid = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
while(0);
|
||||
_is_valid = true;
|
||||
}
|
||||
|
||||
// increment regardless of whether an error has occured -- the
|
||||
// destructor will do the right thing.
|
||||
++_active_managers;
|
||||
audio_debug(" _active_managers="<<_active_managers);
|
||||
|
||||
if (_is_valid) {
|
||||
assert(is_valid());
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: FmodAudioManager::~FmodAudioManager
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
FmodAudioManager::
|
||||
~FmodAudioManager() {
|
||||
// Be sure to delete associated sounds before deleting the manager!
|
||||
nassertv(_soundsOnLoan.empty());
|
||||
clear_cache();
|
||||
--_active_managers;
|
||||
audio_debug("~FmodAudioManager(): "<<_active_managers<<" still active");
|
||||
if (_active_managers == 0) {
|
||||
audio_debug("Shutting down FMOD");
|
||||
FSOUND_Close();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: FmodAudioManager::is_valid
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool FmodAudioManager::
|
||||
is_valid() {
|
||||
// verify the cache and LRU list here.
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: FmodAudioManager::get_sound
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PT(AudioSound) FmodAudioManager::
|
||||
get_sound(const string &file_name) {
|
||||
audio_debug("FmodAudioManager::get_sound(file_name=\""<<file_name<<"\")");
|
||||
|
||||
if(!is_valid()) {
|
||||
audio_debug("invalid FmodAudioManager returning NullSound");
|
||||
return new NullAudioSound();
|
||||
}
|
||||
|
||||
assert(is_valid());
|
||||
Filename path = file_name;
|
||||
|
||||
audio_debug(" resolved file_name is '"<<path<<"'");
|
||||
|
||||
// Get the sound, either from the cache or from disk.
|
||||
SoundMap::iterator si = _sounds.find(path);
|
||||
SoundCacheEntry *entry = NULL;
|
||||
if (si != _sounds.end()) {
|
||||
// The sound was found in the cache.
|
||||
entry = &(*si).second;
|
||||
audio_debug("Sound file '"<<path<<"' found in cache.");
|
||||
} else {
|
||||
// The sound was not found in the cache. Load it from disk.
|
||||
SoundCacheEntry new_entry;
|
||||
new_entry.size = get_file_size(path);
|
||||
if (new_entry.size == 0) {
|
||||
audio_error("FmodAudioManager::get_file_size failed.");
|
||||
return 0;
|
||||
}
|
||||
new_entry.data = load(path, new_entry.size);
|
||||
if (!new_entry.data) {
|
||||
audio_error("FmodAudioManager::load failed.");
|
||||
return 0;
|
||||
}
|
||||
new_entry.refcount = 0;
|
||||
new_entry.stale = true;
|
||||
|
||||
// Add to the cache
|
||||
entry = &new_entry;
|
||||
_sounds[path] = new_entry;
|
||||
}
|
||||
assert(entry != NULL);
|
||||
|
||||
// Create an FMOD object from the memory-mapped file. Here remains
|
||||
// one last vestige of special-case MIDI code: apparently, FMOD
|
||||
// doesn't like creating streams from memory-mapped MIDI files.
|
||||
// They must therefore be streamed from disk every time. This
|
||||
// causes strange things to happen when the same MIDI file is loaded
|
||||
// twice, and played simultaneously...so, *don't do that then*. all
|
||||
// I can say is that MIDI support will be significantly improved in
|
||||
// FMOD v4.0!
|
||||
FSOUND_STREAM *stream = NULL;
|
||||
int flags = FSOUND_LOADMEMORY | FSOUND_MPEGACCURATE;
|
||||
string os_path = path.to_os_specific();
|
||||
string suffix = path.get_extension();
|
||||
std::transform(suffix.begin(), suffix.end(), suffix.begin(), tolower);
|
||||
if (suffix == "mid" || suffix == "rmi" || suffix == "midi") {
|
||||
stream = FSOUND_Stream_OpenFile(os_path.c_str(), 0, 0);
|
||||
} else {
|
||||
stream = FSOUND_Stream_OpenFile((const char*)(entry->data),
|
||||
flags, entry->size);
|
||||
}
|
||||
if (stream == NULL) {
|
||||
audio_error("FmodAudioManager::get_sound failed.");
|
||||
return 0;
|
||||
}
|
||||
inc_refcount(path);
|
||||
|
||||
// determine length of sound
|
||||
float length = (float)FSOUND_Stream_GetLengthMs(stream) * 0.001f;
|
||||
|
||||
// Build a new AudioSound from the audio data.
|
||||
PT(AudioSound) audioSound = 0;
|
||||
PT(FmodAudioSound) fmodAudioSound = new FmodAudioSound(this, stream, path,
|
||||
length);
|
||||
fmodAudioSound->set_active(_active);
|
||||
_soundsOnLoan.insert(fmodAudioSound);
|
||||
audioSound = fmodAudioSound;
|
||||
|
||||
audio_debug(" returning 0x" << (void*)audioSound);
|
||||
assert(is_valid());
|
||||
return audioSound;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: FmodAudioManager::uncache_sound
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void FmodAudioManager::
|
||||
uncache_sound(const string& file_name) {
|
||||
audio_debug("FmodAudioManager::uncache_sound(\""<<file_name<<"\")");
|
||||
Filename path = file_name;
|
||||
assert(is_valid());
|
||||
SoundMap::iterator itor = _sounds.find(path);
|
||||
if (itor == _sounds.end()) {
|
||||
audio_error("FmodAudioManager::uncache_sound: no such entry "<<file_name);
|
||||
return;
|
||||
}
|
||||
|
||||
// Mark the entry as stale -- when its refcount reaches zero, it will
|
||||
// be removed from the cache. If the refcount is already zero, it can be
|
||||
// purged right now!
|
||||
SoundCacheEntry *entry = &(*itor).second;
|
||||
if (entry->refcount == 0) {
|
||||
audio_debug("FmodAudioManager::dec_refcount: purging "<<path
|
||||
<< " from the cache.");
|
||||
delete [] entry->data;
|
||||
_sounds.erase(itor);
|
||||
} else {
|
||||
entry->stale = true;
|
||||
}
|
||||
|
||||
assert(is_valid());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: FmodAudioManager::clear_cache
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void FmodAudioManager::
|
||||
clear_cache() {
|
||||
// Mark all cache entries as stale. Delete those which already have
|
||||
// refcounts of zero.
|
||||
SoundMap::iterator itor = _sounds.begin();
|
||||
for( ; itor != _sounds.end(); ++itor) {
|
||||
SoundCacheEntry *entry = &(*itor).second;
|
||||
if (entry->refcount == 0) {
|
||||
audio_debug("FmodAudioManager: purging "<< (*itor).first
|
||||
<< " from the cache.");
|
||||
delete [] entry->data;
|
||||
_sounds.erase(itor);
|
||||
itor = _sounds.begin();
|
||||
} else {
|
||||
entry->stale = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: FmodAudioManager::set_cache_limit
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void FmodAudioManager::
|
||||
set_cache_limit(int) {
|
||||
// intentionally blank.
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: FmodAudioManager::get_cache_limit
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
int FmodAudioManager::
|
||||
get_cache_limit() {
|
||||
// intentionally blank.
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: FmodAudioManager::release_sound
|
||||
// Access: Private
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void FmodAudioManager::
|
||||
release_sound(FmodAudioSound* audioSound) {
|
||||
audio_debug("FmodAudioManager::release_sound(audioSound=\""
|
||||
<<audioSound->get_name()<<"\")");
|
||||
dec_refcount(audioSound->get_name());
|
||||
_soundsOnLoan.erase(audioSound);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: FmodAudioManager::set_volume
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void FmodAudioManager::
|
||||
set_volume(float) {
|
||||
// intentionally blank.
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: FmodAudioManager::get_volume
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
float FmodAudioManager::
|
||||
get_volume() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: FmodAudioManager::set_active
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void FmodAudioManager::
|
||||
set_active(bool active) {
|
||||
audio_debug("FmodAudioManager::set_active(flag="<<active<<")");
|
||||
if (_active!=active) {
|
||||
_active=active;
|
||||
// Tell our AudioSounds to adjust:
|
||||
AudioSet::iterator i=_soundsOnLoan.begin();
|
||||
for (; i!=_soundsOnLoan.end(); ++i) {
|
||||
(**i).set_active(_active);
|
||||
}
|
||||
}
|
||||
_active = active;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: FmodAudioManager::get_active
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool FmodAudioManager::
|
||||
get_active() {
|
||||
return _active;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: FmodAudioManager::stop_all_sounds
|
||||
// Access: Public
|
||||
// Description: Stop playback on all sounds managed by this manager.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void FmodAudioManager::
|
||||
stop_all_sounds(void) {
|
||||
audio_debug("FmodAudioManager::stop_all_sounds()");
|
||||
AudioSet::iterator i=_soundsOnLoan.begin();
|
||||
for (; i!=_soundsOnLoan.end(); ++i) {
|
||||
if((**i).status()==AudioSound::PLAYING)
|
||||
(**i).stop();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: FmodAudioManager::inc_refcount
|
||||
// Access: Protected
|
||||
// Description: Increments the refcount of a file's cache entry.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void FmodAudioManager::
|
||||
inc_refcount(const string& file_name) {
|
||||
Filename path = file_name;
|
||||
SoundMap::iterator itor = _sounds.find(path.to_os_specific());
|
||||
if (itor != _sounds.end()) {
|
||||
SoundCacheEntry *entry = &(*itor).second;
|
||||
entry->refcount++;
|
||||
entry->stale = false; // definitely not stale!
|
||||
audio_debug("FmodAudioManager: "<<path<<" has a refcount of "
|
||||
<< entry->refcount);
|
||||
} else {
|
||||
audio_debug("FmodAudioManager::inc_refcount: no such file "<<path);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: FmodAudioManager::dec_refcount
|
||||
// Access: Protected
|
||||
// Description: Decrements the refcount of a file's cache entry. If
|
||||
// the refcount reaches zero and the entry is stale, it
|
||||
// will be removed from the cache.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void FmodAudioManager::
|
||||
dec_refcount(const string& file_name) {
|
||||
Filename path = file_name;
|
||||
SoundMap::iterator itor = _sounds.find(path.to_os_specific());
|
||||
if (itor != _sounds.end()) {
|
||||
SoundCacheEntry *entry = &(*itor).second;
|
||||
entry->refcount--;
|
||||
audio_debug("FmodAudioManager: "<<path<<" has a refcount of "
|
||||
<< entry->refcount);
|
||||
if (entry->refcount == 0 && entry->stale) {
|
||||
audio_debug("FmodAudioManager: purging "<<path<< " from the cache.");
|
||||
delete [] entry->data;
|
||||
_sounds.erase(itor);
|
||||
}
|
||||
} else {
|
||||
audio_debug("FmodAudioManager::dec_refcount: no such file "<<path);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: FmodAudioManager::load
|
||||
// Access: Private
|
||||
// Description: Loads the specified file into memory.
|
||||
// Returns NULL if an error occurs.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void* FmodAudioManager::
|
||||
load(const Filename& filename, const size_t size) const {
|
||||
// Check file type (based on filename suffix
|
||||
string suffix = filename.get_extension();
|
||||
std::transform(suffix.begin(), suffix.end(), suffix.begin(), tolower);
|
||||
bool bSupported = false;
|
||||
if (suffix == "wav" || suffix == "mp3" || suffix == "mid"
|
||||
|| suffix == "rmi" || suffix == "midi") {
|
||||
bSupported = true;
|
||||
}
|
||||
if (!bSupported) {
|
||||
audio_error("FmodAudioManager::load: "<<filename
|
||||
<<" is not a supported file format.");
|
||||
audio_error("Supported formats are: WAV, MP3, MIDI");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// open the file.
|
||||
string os_filename = filename.to_os_specific();
|
||||
FILE *audioFile = fopen(os_filename.c_str(), "rb");
|
||||
if (!audioFile) {
|
||||
audio_error("File "<<filename<<" does not exist.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Read the entire file into memory.
|
||||
char *buffer = new char[size];
|
||||
if (buffer == NULL) {
|
||||
audio_error("out-of-memory error while loading "<<filename);
|
||||
fclose(audioFile);
|
||||
return NULL;
|
||||
}
|
||||
long bytes_read = fread(buffer, size, 1, audioFile);
|
||||
if (bytes_read != 1) {
|
||||
audio_error("Read error while loading "<<filename);
|
||||
fclose(audioFile);
|
||||
delete [] buffer;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fclose(audioFile);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: FmodAudioManager::get_file_size
|
||||
// Access: Private
|
||||
// Description: Calculates the size of the given file, in bytes.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
size_t FmodAudioManager::
|
||||
get_file_size(const Filename& filename) const {
|
||||
// open the file.
|
||||
string os_filename = filename.to_os_specific();
|
||||
FILE *audioFile = fopen(os_filename.c_str(), "rb");
|
||||
if (!audioFile) {
|
||||
audio_error("File "<<filename<<" does not exist.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Read the entire file into memory.
|
||||
if (fseek(audioFile, 0, SEEK_END) != 0) {
|
||||
audio_error("Seek error while loading "<<filename);
|
||||
fclose(audioFile);
|
||||
return 0;
|
||||
}
|
||||
size_t file_size = ftell(audioFile);
|
||||
fclose(audioFile);
|
||||
return file_size;
|
||||
}
|
||||
|
||||
#endif //]
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
// Filename: fmodAudioManager.h
|
||||
// Created by: cort (January 22, 2003)
|
||||
// Prior system by: cary
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
|
||||
//
|
||||
// All use of this software is subject to the terms of the Panda 3d
|
||||
// Software license. You should have received a copy of this license
|
||||
// along with this source code; you will also find a current copy of
|
||||
// the license at http://www.panda3d.org/license.txt .
|
||||
//
|
||||
// To contact the maintainers of this program write to
|
||||
// panda3d@yahoogroups.com .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef __FMOD_AUDIO_MANAGER_H__
|
||||
#define __FMOD_AUDIO_MANAGER_H__
|
||||
|
||||
#include <pandabase.h>
|
||||
#ifdef HAVE_FMOD //[
|
||||
|
||||
#include "audioManager.h"
|
||||
class FmodAudioSound;
|
||||
#include "filename.h"
|
||||
#include "pmap.h"
|
||||
#include "pset.h"
|
||||
|
||||
#include <fmod.h>
|
||||
|
||||
class EXPCL_FMOD_AUDIO FmodAudioManager : 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.
|
||||
|
||||
public:
|
||||
FmodAudioManager();
|
||||
virtual ~FmodAudioManager();
|
||||
|
||||
virtual bool is_valid();
|
||||
|
||||
virtual PT(AudioSound) get_sound(const string&);
|
||||
virtual void uncache_sound(const string&);
|
||||
virtual void clear_cache();
|
||||
virtual void set_cache_limit(int);
|
||||
virtual int get_cache_limit();
|
||||
|
||||
virtual void set_volume(float);
|
||||
virtual float get_volume();
|
||||
|
||||
virtual void set_active(bool);
|
||||
virtual bool get_active();
|
||||
void stop_all_sounds();
|
||||
|
||||
protected:
|
||||
// increment or decrement the refcount of the given file's cache entry.
|
||||
// sounds can only be uncached when their refcounts are zero.
|
||||
void inc_refcount(const string& file_name);
|
||||
void dec_refcount(const string& file_name);
|
||||
private:
|
||||
typedef struct {
|
||||
size_t size; // size of the data field, in bytes
|
||||
unsigned int refcount; // how many AudioSound objects are referencing me?
|
||||
bool stale; // can this entry be purged from the cache?
|
||||
void *data; // the memory-mapped audio file.
|
||||
} SoundCacheEntry;
|
||||
typedef pmap<string, SoundCacheEntry > SoundMap;
|
||||
SoundMap _sounds;
|
||||
|
||||
typedef pset<FmodAudioSound* > AudioSet;
|
||||
// The offspring of this manager:
|
||||
AudioSet _soundsOnLoan;
|
||||
|
||||
void release_sound(FmodAudioSound *audioSound);
|
||||
|
||||
static int _active_managers;
|
||||
bool _is_valid;
|
||||
bool _active;
|
||||
|
||||
void* load(const Filename& filename, const size_t size) const;
|
||||
size_t get_file_size(const Filename& filename) const;
|
||||
|
||||
friend FmodAudioSound;
|
||||
};
|
||||
|
||||
EXPCL_FMOD_AUDIO PT(AudioManager) Create_AudioManager();
|
||||
|
||||
#endif //]
|
||||
|
||||
#endif /* __FMOD_AUDIO_MANAGER_H__ */
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
// Filename: fmodAudioSound.I
|
||||
// Created by: cort (January 22, 2003)
|
||||
// Prior system by: cary
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
|
||||
//
|
||||
// All use of this software is subject to the terms of the Panda 3d
|
||||
// Software license. You should have received a copy of this license
|
||||
// along with this source code; you will also find a current copy of
|
||||
// the license at http://www.panda3d.org/license.txt .
|
||||
//
|
||||
// To contact the maintainers of this program write to
|
||||
// panda3d@yahoogroups.com .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,239 @@
|
|||
// Filename: fmodAudioSound.cxx
|
||||
// Created by: cort (January 22, 2003)
|
||||
// Prior system by: cary
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
|
||||
//
|
||||
// All use of this software is subject to the terms of the Panda 3d
|
||||
// Software license. You should have received a copy of this license
|
||||
// along with this source code; you will also find a current copy of
|
||||
// the license at http://www.panda3d.org/license.txt .
|
||||
//
|
||||
// To contact the maintainers of this program write to
|
||||
// panda3d@yahoogroups.com .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <pandabase.h>
|
||||
#ifdef HAVE_FMOD //[
|
||||
|
||||
#include "fmodAudioSound.h"
|
||||
#include "fmodAudioManager.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#ifndef NDEBUG //[
|
||||
#define fmod_audio_debug(x) \
|
||||
audio_debug("FmodAudioSound "<<" \""<<get_name()<<"\" "<< x )
|
||||
#else //][
|
||||
#define fmod_audio_debug(x) ((void)0)
|
||||
#endif //]
|
||||
|
||||
FmodAudioSound::
|
||||
FmodAudioSound(FmodAudioManager* manager, FSOUND_STREAM *audio_data,
|
||||
string file_name, float length)
|
||||
: _manager(manager), _audio(audio_data), _file_name(file_name),
|
||||
_volume(1.0f), _balance(0), _loop_count(1), _length(length),
|
||||
_active(true), _paused(false), _channel(-1) {
|
||||
nassertv(!file_name.empty());
|
||||
nassertv(audio_data != NULL);
|
||||
audio_debug("FmodAudioSound(manager=0x"<<(void*)&manager
|
||||
<<", file_name="<<file_name<<")");
|
||||
}
|
||||
|
||||
FmodAudioSound::
|
||||
~FmodAudioSound() {
|
||||
fmod_audio_debug("~FmodAudioSound()");
|
||||
this->stop();
|
||||
_manager->release_sound(this);
|
||||
}
|
||||
|
||||
void FmodAudioSound::
|
||||
play() {
|
||||
if (!_active) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(_manager->_bExclusive) {
|
||||
// stop any other sound that parent mgr is playing
|
||||
_manager->stop_all_sounds();
|
||||
}
|
||||
|
||||
// If the sound is already playing, stop it.
|
||||
if (this->status() == AudioSound::PLAYING) {
|
||||
this->stop();
|
||||
}
|
||||
|
||||
// Play the stream, but start it paused so we can set the volume and
|
||||
// panning first.
|
||||
bool bStatusOK = false;
|
||||
assert(_audio != NULL);
|
||||
_channel = FSOUND_Stream_PlayEx(FSOUND_FREE, _audio, NULL, 1);
|
||||
if (_channel == -1) {
|
||||
fmod_audio_debug("play() failed");
|
||||
return;
|
||||
}
|
||||
|
||||
// Set volume.
|
||||
unsigned char new_volume = (unsigned char)(_volume*255.0f);
|
||||
FSOUND_SetVolume(_channel, new_volume);
|
||||
|
||||
// Set panning.
|
||||
unsigned char new_balance = (unsigned char)( (_balance+1.0f)*0.5f*255.0f);
|
||||
FSOUND_SetPan(_channel, new_balance);
|
||||
|
||||
// Set looping -- unimplemented
|
||||
|
||||
// Unpause and set status to playing
|
||||
FSOUND_SetPaused(_channel, 0);
|
||||
|
||||
// Delay until the channel is actually playing. This shouldn't
|
||||
// result in a noticeable delay, and allows you to immediately test
|
||||
// the status of the sound after initiating playback.
|
||||
while (!FSOUND_IsPlaying(_channel));
|
||||
}
|
||||
|
||||
void FmodAudioSound::stop() {
|
||||
FSOUND_Stream_Stop(_audio);
|
||||
_channel = -1;
|
||||
}
|
||||
|
||||
void FmodAudioSound::set_loop(bool loop) {
|
||||
audio_error("FmodAudioSound::set_loop() -- not yet implemented");
|
||||
fmod_audio_debug("set_loop() set to "<<loop);
|
||||
_loop_count = loop ? 0 : 1;
|
||||
}
|
||||
|
||||
bool FmodAudioSound::get_loop() const {
|
||||
fmod_audio_debug("get_loop() returning "<<(_loop_count==0));
|
||||
return (_loop_count == 0);
|
||||
}
|
||||
|
||||
void FmodAudioSound::set_loop_count(unsigned long loop_count) {
|
||||
audio_error("FmodAudioSound::set_loop_count() -- not yet implemented");
|
||||
fmod_audio_debug("set_loop_count() set to "<<loop_count);
|
||||
_loop_count = loop_count;
|
||||
}
|
||||
|
||||
unsigned long FmodAudioSound::get_loop_count() const {
|
||||
fmod_audio_debug("get_loop_count() returning "<<_loop_count);
|
||||
return _loop_count;
|
||||
}
|
||||
|
||||
void FmodAudioSound::set_time(float start_time) {
|
||||
if (start_time < 0.0f) {
|
||||
fmod_audio_debug("set_time(): param "<<start_time<<" out of range.");
|
||||
fmod_audio_debug("set_time(): clamping to zero.");
|
||||
start_time = 0.0f;
|
||||
} else if (start_time > _length) {
|
||||
fmod_audio_debug("set_time(): param "<<start_time<<" out of range.");
|
||||
fmod_audio_debug("set_time(): clamping to length ("<<_length<<".");
|
||||
start_time = _length - 0.01;
|
||||
}
|
||||
// FMOD measures time in milliseconds, so scale up by 1000.
|
||||
FSOUND_Stream_SetTime(_audio, start_time * 1000.0f);
|
||||
}
|
||||
|
||||
float FmodAudioSound::get_time() const {
|
||||
// A bug in stream WAV files causes FSOUND_Stream_GetTime() to
|
||||
// divide-by-zero somewhere if the stream isn't currently playing.
|
||||
// In this case, we should just return zero.
|
||||
if (!FSOUND_IsPlaying(_channel)) {
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
// FMOD measures time in milliseconds, so scale down by 1000.
|
||||
float current_time = FSOUND_Stream_GetTime(_audio) * 0.001f;
|
||||
//fmod_audio_debug("get_time() returning "<<current_time);
|
||||
return current_time;
|
||||
}
|
||||
|
||||
void FmodAudioSound::set_volume(float vol) {
|
||||
if (vol < 0.0f) {
|
||||
fmod_audio_debug("set_volume(): param "<<vol<<" out of range.");
|
||||
fmod_audio_debug("set_volume(): clamping to zero.");
|
||||
vol = 0.0f;
|
||||
} else if (vol > 1.0f) {
|
||||
fmod_audio_debug("set_volume(): param "<<vol<<" out of range.");
|
||||
fmod_audio_debug("set_volume(): clamping to 1.0");
|
||||
vol = 1.0f;
|
||||
}
|
||||
_volume = vol;
|
||||
unsigned char new_volume = (unsigned char)(_volume*255.0f);
|
||||
FSOUND_SetVolume(_channel, new_volume);
|
||||
}
|
||||
|
||||
float FmodAudioSound::get_volume() const {
|
||||
fmod_audio_debug("get_volume() returning "<<_volume);
|
||||
return _volume;
|
||||
}
|
||||
|
||||
void FmodAudioSound::set_balance(float bal) {
|
||||
if (bal < -1.0f) {
|
||||
fmod_audio_debug("set_balance(): param "<<bal<<" out of range.");
|
||||
fmod_audio_debug("set_balance(): clamping to -1.0.");
|
||||
bal = -1.0f;
|
||||
} else if (bal > 1.0f) {
|
||||
fmod_audio_debug("set_balance(): param "<<bal<<" out of range.");
|
||||
fmod_audio_debug("set_balance(): clamping to 1.0");
|
||||
bal = 1.0f;
|
||||
}
|
||||
_balance = bal;
|
||||
unsigned char new_balance = (unsigned char)( (_balance+1.0f)*0.5f*255.0f);
|
||||
FSOUND_SetPan(_channel, new_balance);
|
||||
}
|
||||
|
||||
float FmodAudioSound::get_balance() const {
|
||||
fmod_audio_debug("get_balance() returning "<<_balance);
|
||||
return _balance;
|
||||
}
|
||||
|
||||
void FmodAudioSound::set_active(bool active) {
|
||||
fmod_audio_debug("set_active(active="<<active<<")");
|
||||
if (!active) {
|
||||
// Once looping works, a looping sound should be paused, not
|
||||
// stopped. When the sound is activated again, it is unpaused.
|
||||
this->stop();
|
||||
}
|
||||
_active = active;
|
||||
}
|
||||
|
||||
bool FmodAudioSound::get_active() const {
|
||||
fmod_audio_debug("get_active() returning "<<_active);
|
||||
return _active;
|
||||
}
|
||||
|
||||
const string& FmodAudioSound::get_name() const {
|
||||
//fmod_audio_debug("get_name() returning "<<_file_name);
|
||||
return _file_name;
|
||||
}
|
||||
|
||||
float FmodAudioSound::length() const {
|
||||
return _length;
|
||||
}
|
||||
|
||||
AudioSound::SoundStatus FmodAudioSound::status() const {
|
||||
// If the stream's channel isn't playing anything, then the stream
|
||||
// definitely isn't playing.
|
||||
if (!FSOUND_IsPlaying(_channel)) {
|
||||
return AudioSound::READY;
|
||||
}
|
||||
|
||||
// If the channel is playing, see whether the current time is at the
|
||||
// end of the file. If not, the stream is playing.
|
||||
float current_time = this->get_time();
|
||||
if (current_time >= _length - 0.01f) {
|
||||
// FMOD MIDI files don't stop automatically when they hit the end of the
|
||||
// file. Their channel isn't released unless the stream is stopped
|
||||
// explicitly.
|
||||
FSOUND_Stream_Stop(_audio);
|
||||
return AudioSound::READY;
|
||||
} else {
|
||||
return AudioSound::PLAYING;
|
||||
}
|
||||
}
|
||||
|
||||
#endif //]
|
||||
|
|
@ -0,0 +1,108 @@
|
|||
// Filename: fmodAudioSound.h
|
||||
// Created by: cort (January 22, 2003)
|
||||
// Prior system by: cary
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
|
||||
//
|
||||
// All use of this software is subject to the terms of the Panda 3d
|
||||
// Software license. You should have received a copy of this license
|
||||
// along with this source code; you will also find a current copy of
|
||||
// the license at http://www.panda3d.org/license.txt .
|
||||
//
|
||||
// To contact the maintainers of this program write to
|
||||
// panda3d@yahoogroups.com .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef __FMOD_AUDIO_SOUND_H__
|
||||
#define __FMOD_AUDIO_SOUND_H__
|
||||
|
||||
#include <pandabase.h>
|
||||
#ifdef HAVE_FMOD //[
|
||||
|
||||
#include "audioSound.h"
|
||||
class FmodAudioManager;
|
||||
#include <fmod.h>
|
||||
|
||||
|
||||
class EXPCL_FMOD_AUDIO FmodAudioSound : public AudioSound {
|
||||
public:
|
||||
~FmodAudioSound();
|
||||
|
||||
// For best compatability, set the loop_count, start_time,
|
||||
// volume, and balance, prior to calling play(). You may
|
||||
// set them while they're playing, but it's implementation
|
||||
// specific whether you get the results.
|
||||
void play();
|
||||
void stop();
|
||||
|
||||
// loop: false = play once; true = play forever.
|
||||
// inits to false.
|
||||
void set_loop(bool loop=true);
|
||||
bool get_loop() const;
|
||||
|
||||
// loop_count: 0 = forever; 1 = play once; n = play n times.
|
||||
// inits to 1.
|
||||
void set_loop_count(unsigned long loop_count=1);
|
||||
unsigned long get_loop_count() const;
|
||||
|
||||
// 0 = begining; length() = end.
|
||||
// inits to 0.0.
|
||||
void set_time(float start_time=0.0);
|
||||
float get_time() const;
|
||||
|
||||
// 0 = minimum; 1.0 = maximum.
|
||||
// inits to 1.0.
|
||||
void set_volume(float volume=1.0);
|
||||
float get_volume() const;
|
||||
|
||||
// -1.0 is hard left
|
||||
// 0.0 is centered
|
||||
// 1.0 is hard right
|
||||
// inits to 0.0.
|
||||
void set_balance(float balance_right=0.0);
|
||||
float get_balance() const;
|
||||
|
||||
// inits to manager's state.
|
||||
void set_active(bool active=true);
|
||||
bool get_active() const;
|
||||
|
||||
const string& get_name() const;
|
||||
|
||||
// return: playing time in seconds.
|
||||
float length() const;
|
||||
|
||||
AudioSound::SoundStatus status() const;
|
||||
|
||||
protected:
|
||||
|
||||
private:
|
||||
FSOUND_STREAM *_audio;
|
||||
PT(FmodAudioManager) _manager;
|
||||
float _volume; // 0..1.0
|
||||
float _balance; // -1..1
|
||||
mutable float _length; // in seconds.
|
||||
unsigned long _loop_count;
|
||||
string _file_name;
|
||||
bool _active;
|
||||
bool _paused;
|
||||
int _channel;
|
||||
|
||||
FmodAudioSound(FmodAudioManager* manager, FSOUND_STREAM *audio_data,
|
||||
string file_name, float length=0.0f);
|
||||
|
||||
// forbidden functions!
|
||||
FmodAudioSound(const FmodAudioSound& rhs) {}
|
||||
const FmodAudioSound& operator=(const FmodAudioSound& rhs) { return *this; }
|
||||
|
||||
friend class FmodAudioManager;
|
||||
};
|
||||
|
||||
#include "fmodAudioSound.I"
|
||||
|
||||
#endif //]
|
||||
|
||||
#endif /* __FMOD_AUDIO_SOUND_H__ */
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
/* Generated automatically by ppremake 1.11 from Sources.pp. */
|
||||
/* ################################# DO NOT EDIT ########################### */
|
||||
|
||||
#include "fmod_audio_composite1.cxx"
|
||||
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
|
||||
#include "config_fmodAudio.cxx"
|
||||
#include "fmodAudioManager.cxx"
|
||||
#include "fmodAudioSound.cxx"
|
||||
|
||||
|
|
@ -52,6 +52,14 @@
|
|||
#define EXPTP_MILES_AUDIO extern
|
||||
#endif
|
||||
|
||||
#ifdef BUILDING_FMOD_AUDIO
|
||||
#define EXPCL_FMOD_AUDIO __declspec(dllexport)
|
||||
#define EXPTP_FMOD_AUDIO
|
||||
#else
|
||||
#define EXPCL_FMOD_AUDIO __declspec(dllimport)
|
||||
#define EXPTP_FMOD_AUDIO extern
|
||||
#endif
|
||||
|
||||
#ifdef BUILDING_PANDA
|
||||
#define EXPCL_PANDA __declspec(dllexport)
|
||||
#define EXPTP_PANDA
|
||||
|
|
|
|||
Loading…
Reference in New Issue