19 #include "pandabase.h"
23 #include "config_audio.h"
24 #include "config_fmodAudio.h"
25 #include "fmodAudioSound.h"
26 #include "string_utils.h"
27 #include "subfileInfo.h"
28 #include "reMutexHolder.h"
29 #include "virtualFileSystem.h"
44 audio_debug(
"FmodAudioSound::FmodAudioSound() Creating new sound, filename: " << file_name );
46 _active = manager->get_active();
66 for (
int i=0; i<AudioManager::SPK_COUNT; i++) {
72 DCAST_INTO_V(fmanager, manager);
76 _file_name = file_name;
80 result = _manager->_system->getSpeakerMode( &_speakermode );
81 fmod_audio_errcheck(
"_system->getSpeakerMode()", result);
88 result = FMOD_ERR_FILE_NOTFOUND;
91 bool preload = (fmod_audio_preload_threshold < 0) || (file->get_file_size() < fmod_audio_preload_threshold);
92 int flags = FMOD_SOFTWARE;
93 flags |= positional ? FMOD_3D : FMOD_2D;
95 FMOD_CREATESOUNDEXINFO sound_info;
96 memset(&sound_info, 0,
sizeof(sound_info));
97 sound_info.cbsize =
sizeof(sound_info);
102 memcpy(&sound_info, &_manager->_midi_info,
sizeof(sound_info));
103 if (sound_info.dlsname != NULL) {
104 audio_debug(
"Using DLS file " << sound_info.dlsname);
108 const char *name_or_data = _file_name.c_str();
117 file->read_file(mem_buffer,
true);
118 sound_info.length = mem_buffer.size();
119 if (mem_buffer.size() != 0) {
120 name_or_data = (
const char *)&mem_buffer[0];
122 flags |= FMOD_OPENMEMORY;
123 if (fmodAudio_cat.is_debug()) {
124 fmodAudio_cat.debug()
125 <<
"Reading " << _file_name <<
" into memory (" << sound_info.length
129 }
else if (file->get_system_info(info)) {
136 name_or_data = os_filename.c_str();
137 sound_info.fileoffset = (
unsigned int)info.
get_start();
138 sound_info.length = (
unsigned int)info.
get_size();
139 flags |= FMOD_CREATESTREAM;
140 if (fmodAudio_cat.is_debug()) {
141 fmodAudio_cat.debug()
142 <<
"Streaming " << _file_name <<
" from disk (" << name_or_data
143 <<
", " << sound_info.fileoffset <<
", " << sound_info.length <<
")\n";
147 #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
150 name_or_data = (
const char *)file.p();
151 sound_info.length = (
unsigned int)info.
get_size();
152 sound_info.useropen = open_callback;
153 sound_info.userclose = close_callback;
154 sound_info.userread = read_callback;
155 sound_info.userseek = seek_callback;
156 flags |= FMOD_CREATESTREAM;
157 if (fmodAudio_cat.is_debug()) {
158 fmodAudio_cat.debug()
159 <<
"Streaming " << _file_name <<
" from disk using callbacks\n";
162 #else // HAVE_THREADS && !SIMPLE_THREADS
166 fmodAudio_cat.warning()
167 <<
"Cannot stream " << _file_name <<
"; file is not literally on disk.\n";
172 _manager->_system->createSound(name_or_data, flags, &sound_info, &_sound);
175 if (result != FMOD_OK) {
176 audio_error(
"createSound(" << _file_name <<
"): " << FMOD_ErrorString(result));
180 FMOD_CREATESOUNDEXINFO sound_info;
181 memset(&sound_info, 0,
sizeof(sound_info));
182 char blank_data[100];
183 memset(blank_data, 0,
sizeof(blank_data));
184 sound_info.cbsize =
sizeof(sound_info);
185 sound_info.length =
sizeof(blank_data);
186 sound_info.numchannels = 1;
187 sound_info.defaultfrequency = 8000;
188 sound_info.format = FMOD_SOUND_FORMAT_PCM16;
189 int flags = FMOD_SOFTWARE | FMOD_OPENMEMORY | FMOD_OPENRAW;
191 result = _manager->_system->createSound( blank_data, flags, &sound_info, &_sound);
192 fmod_audio_errcheck(
"createSound (blank)", result);
197 _sound->setLoopCount(1);
198 _sound->setMode(FMOD_LOOP_OFF);
205 result = _sound->getDefaults( &_sampleFrequency, &_volume , &_balance, &_priority);
206 fmod_audio_errcheck(
"_sound->getDefaults()", result);
221 _manager->_all_sounds.erase(
this);
224 result = _sound->release();
225 fmod_audio_errcheck(
"_sound->release()", result);
250 result =_channel->stop();
251 if (result == FMOD_ERR_INVALID_HANDLE || result == FMOD_ERR_CHANNEL_STOLEN) {
253 }
else if (result == FMOD_OK) {
256 fmod_audio_errcheck(
"_channel->stop()", result);
303 audio_debug(
"FmodAudioSound::set_loop_count() Setting the sound's loop count to: " << loop_count);
308 if (loop_count == 0) {
309 result = _sound->setLoopCount( -1 );
310 fmod_audio_errcheck(
"_sound->setLoopCount()", result);
311 result =_sound->setMode(FMOD_LOOP_NORMAL);
312 fmod_audio_errcheck(
"_sound->setMode()", result);
313 }
else if (loop_count == 1) {
314 result = _sound->setLoopCount( 1 );
315 fmod_audio_errcheck(
"_sound->setLoopCount()", result);
316 result =_sound->setMode(FMOD_LOOP_OFF);
317 fmod_audio_errcheck(
"_sound->setMode()", result);
319 result = _sound->setLoopCount( loop_count );
320 fmod_audio_errcheck(
"_sound->setLoopCount()", result);
321 result =_sound->setMode(FMOD_LOOP_NORMAL);
322 fmod_audio_errcheck(
"_sound->setMode()", result);
325 audio_debug(
"FmodAudioSound::set_loop_count() Sound's loop count should be set to: " << loop_count);
339 result = _sound->getLoopCount( &loop_count );
340 fmod_audio_errcheck(
"_sound->getLoopCount()", result);
342 if (loop_count <= 0) {
345 return (
unsigned long)loop_count;
359 _start_time = start_time;
361 if (
status() == PLAYING) {
376 unsigned int current_time;
382 result = _channel->getPosition( ¤t_time , FMOD_TIMEUNIT_MS );
383 if (result == FMOD_ERR_INVALID_HANDLE || result == FMOD_ERR_CHANNEL_STOLEN) {
386 fmod_audio_errcheck(
"_channel->getPosition()", result);
388 return ((
double)current_time) / 1000.0;
401 set_volume_on_channel();
419 void FmodAudioSound::
429 int startTime = (int)(_start_time * 1000);
433 result = _channel->setPosition( startTime , FMOD_TIMEUNIT_MS );
434 if (result == FMOD_ERR_INVALID_HANDLE || result == FMOD_ERR_CHANNEL_STOLEN) {
438 fmod_audio_errcheck(
"_channel->setPosition()", result);
441 result = _channel->isPlaying(&playing);
442 fmod_audio_errcheck(
"_channel->isPlaying()", result);
443 if (result != FMOD_OK || !playing) {
450 result = _manager->_system->playSound(FMOD_CHANNEL_FREE, _sound,
true, &_channel);
451 fmod_audio_errcheck(
"_system->playSound()", result);
452 result = _channel->setChannelGroup(_manager->_channelgroup);
453 fmod_audio_errcheck(
"_channel->setChannelGroup()", result);
454 result = _channel->setUserData(
this);
455 fmod_audio_errcheck(
"_channel->setUserData()", result);
456 result = _channel->setCallback(sound_end_callback);
457 fmod_audio_errcheck(
"_channel->setCallback()", result);
458 result = _channel->setPosition( startTime , FMOD_TIMEUNIT_MS );
459 fmod_audio_errcheck(
"_channel->setPosition()", result);
461 set_volume_on_channel();
462 set_play_rate_on_channel();
463 set_speaker_mix_or_balance_on_channel();
465 set_3d_attributes_on_channel();
467 result = _channel->setPaused(
false);
468 fmod_audio_errcheck(
"_channel->setPaused()", result);
479 void FmodAudioSound::
480 set_volume_on_channel() {
485 result = _channel->setVolume( _volume );
486 if (result == FMOD_ERR_INVALID_HANDLE || result == FMOD_ERR_CHANNEL_STOLEN) {
489 fmod_audio_errcheck(
"_channel->setVolume()", result);
503 set_speaker_mix_or_balance_on_channel();
532 set_play_rate_on_channel();
540 PN_stdfloat FmodAudioSound::
541 get_play_rate()
const {
550 void FmodAudioSound::
551 set_play_rate_on_channel() {
554 PN_stdfloat frequency = _sampleFrequency * _playrate;
557 result = _channel->setFrequency( frequency );
558 if (result == FMOD_ERR_INVALID_HANDLE || result == FMOD_ERR_CHANNEL_STOLEN) {
561 fmod_audio_errcheck(
"_channel->setFrequency()", result);
588 result = _sound->getLength( &length, FMOD_TIMEUNIT_MS );
589 fmod_audio_errcheck(
"_sound->getLength()", result);
591 return ((
double)length) / 1000.0;
610 set_3d_attributes(PN_stdfloat px, PN_stdfloat py, PN_stdfloat pz, PN_stdfloat vx, PN_stdfloat vy, PN_stdfloat vz) {
620 set_3d_attributes_on_channel();
628 void FmodAudioSound::
629 set_3d_attributes_on_channel() {
634 result = _sound->getMode(&soundMode);
635 fmod_audio_errcheck(
"_sound->getMode()", result);
637 if ((_channel != 0) && (soundMode & FMOD_3D)) {
638 result = _channel->set3DAttributes( &_location, &_velocity );
639 if (result == FMOD_ERR_INVALID_HANDLE || result == FMOD_ERR_CHANNEL_STOLEN) {
642 fmod_audio_errcheck(
"_channel->set3DAttributes()", result);
654 get_3d_attributes(PN_stdfloat *px, PN_stdfloat *py, PN_stdfloat *pz, PN_stdfloat *vx, PN_stdfloat *vy, PN_stdfloat *vz) {
655 audio_error(
"get3dAttributes: Currently unimplemented. Get the attributes of the attached object.");
671 result = _sound->set3DMinMaxDistance( dist, _max_dist );
672 fmod_audio_errcheck(
"_sound->set3DMinMaxDistance()", result);
697 result = _sound->set3DMinMaxDistance( _min_dist, dist );
698 fmod_audio_errcheck(
"_sound->set3DMinMaxDistance()", result);
739 result = _channel->getSpeakerMix( &frontleft, &frontright, ¢er, &sub, &backleft, &backright, &sideleft, &sideright );
740 fmod_audio_errcheck(
"_channel->getSpeakerMix()", result);
743 case AudioManager::SPK_frontleft:
return frontleft;
744 case AudioManager::SPK_frontright:
return frontright;
745 case AudioManager::SPK_center:
return center;
746 case AudioManager::SPK_sub:
return sub;
747 case AudioManager::SPK_backleft:
return backleft;
748 case AudioManager::SPK_backright:
return backright;
749 case AudioManager::SPK_sideleft:
return sideleft;
750 case AudioManager::SPK_sideright:
return sideright;
772 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) {
774 _mix[AudioManager::SPK_frontleft] = frontleft;
775 _mix[AudioManager::SPK_frontright] = frontright;
776 _mix[AudioManager::SPK_center] = center;
777 _mix[AudioManager::SPK_sub] = sub;
778 _mix[AudioManager::SPK_backleft] = backleft;
779 _mix[AudioManager::SPK_backright] = backright;
780 _mix[AudioManager::SPK_sideleft] = sideleft;
781 _mix[AudioManager::SPK_sideright] = sideright;
783 set_speaker_mix_or_balance_on_channel();
797 void FmodAudioSound::
798 set_speaker_mix_or_balance_on_channel() {
803 result = _sound->getMode(&soundMode);
804 fmod_audio_errcheck(
"_sound->getMode()", result);
806 if ((_channel != 0) && (( soundMode & FMOD_3D ) == 0)) {
807 if ( _speakermode == FMOD_SPEAKERMODE_STEREO ) {
808 result = _channel->setPan( _balance );
810 result = _channel->setSpeakerMix( _mix[AudioManager::SPK_frontleft],
811 _mix[AudioManager::SPK_frontright],
812 _mix[AudioManager::SPK_center],
813 _mix[AudioManager::SPK_sub],
814 _mix[AudioManager::SPK_backleft],
815 _mix[AudioManager::SPK_backright],
816 _mix[AudioManager::SPK_sideleft],
817 _mix[AudioManager::SPK_sideright]
820 if (result == FMOD_ERR_INVALID_HANDLE || result == FMOD_ERR_CHANNEL_STOLEN) {
823 fmod_audio_errcheck(
"_channel->setSpeakerMix()/setPan()", result);
837 audio_debug(
"FmodAudioSound::get_priority()");
847 void FmodAudioSound::
848 set_priority(
int priority) {
851 audio_debug(
"FmodAudioSound::set_priority()");
855 _priority = priority;
857 result = _sound->setDefaults( _sampleFrequency, _volume , _balance, _priority);
858 fmod_audio_errcheck(
"_sound->setDefaults()", result);
872 if ( _channel == 0 ) {
876 result = _channel->isPlaying( &playingState );
877 if ((result == FMOD_OK) && (playingState ==
true)) {
895 if (_active != active) {
907 if (
status() == PLAYING) {
937 audio_error(
"finished: not implemented under FMOD-EX");
950 audio_error(
"set_finished_event: not implemented under FMOD-EX");
963 audio_error(
"get_finished_event: not implemented under FMOD-EX");
964 return _finished_event;
973 FMOD_RESULT F_CALLBACK FmodAudioSound::
974 sound_end_callback(FMOD_CHANNEL * channel,
975 FMOD_CHANNEL_CALLBACKTYPE type,
977 void *commanddata2) {
981 if (type == FMOD_CHANNEL_CALLBACKTYPE_END) {
982 FMOD::Channel *fc = (FMOD::Channel *)channel;
983 void *userdata = NULL;
984 FMOD_RESULT result = fc->getUserData(&userdata);
985 fmod_audio_errcheck(
"channel->getUserData()", result);
987 fsound->_self_ref = fsound;
997 FMOD_RESULT F_CALLBACK FmodAudioSound::
998 open_callback(
const char *name,
int,
unsigned int *file_size,
999 void **handle,
void **user_data) {
1003 return FMOD_ERR_FILE_NOTFOUND;
1005 if (fmodAudio_cat.is_spam()) {
1006 fmodAudio_cat.spam()
1007 <<
"open_callback(" << *file <<
")\n";
1013 (*handle) = (
void *)str;
1014 (*user_data) = (
void *)file;
1028 FMOD_RESULT F_CALLBACK FmodAudioSound::
1029 close_callback(
void *handle,
void *user_data) {
1031 if (fmodAudio_cat.is_spam()) {
1032 fmodAudio_cat.spam()
1033 <<
"close_callback(" << *file <<
")\n";
1038 istream *str = (istream *)handle;
1052 FMOD_RESULT F_CALLBACK FmodAudioSound::
1053 read_callback(
void *handle,
void *buffer,
unsigned int size_bytes,
1054 unsigned int *bytes_read,
void *user_data) {
1056 if (fmodAudio_cat.is_spam()) {
1057 fmodAudio_cat.spam()
1058 <<
"read_callback(" << *file <<
", " << size_bytes <<
")\n";
1061 istream *str = (istream *)handle;
1062 str->read((
char *)buffer, size_bytes);
1063 (*bytes_read) = str->gcount();
1072 if ((*bytes_read) == 0) {
1073 return FMOD_ERR_FILE_EOF;
1078 }
if (str->fail()) {
1079 return FMOD_ERR_FILE_BAD;
1090 FMOD_RESULT F_CALLBACK FmodAudioSound::
1091 seek_callback(
void *handle,
unsigned int pos,
void *user_data) {
1093 if (fmodAudio_cat.is_spam()) {
1094 fmodAudio_cat.spam()
1095 <<
"seek_callback(" << *file <<
", " << pos <<
")\n";
1098 istream *str = (istream *)handle;
1102 if (str->fail() && !str->eof()) {
1103 return FMOD_ERR_FILE_COULDNOTSEEK;
const string & get_finished_event() const
NOT USED ANYMORE!!! Return the string the finished event is referenced by.
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)
This sets the speaker mix for Surround Sound sytems.
streamsize get_size() const
Returns the number of consecutive bytes, beginning at get_start(), that correspond to this file data...
void play()
Plays a sound.
virtual istream * open_read_file(bool auto_unwrap) const
Opens the file for reading.
PN_stdfloat length() const
Get length FMOD returns the time in MS so we have to convert to seconds.
AudioSound::SoundStatus status() const
Get status of the sound.
void finished()
Not implemented.
A hierarchy of directories and files that appears to be one continuous file system, even though the files may originate from several different sources that may not be related to the actual OS's file system.
void set_3d_max_distance(PN_stdfloat dist)
Set the distance that this sound stops falling off.
FmodAudioSound(AudioManager *manager, Filename fn, bool positional)
Constructor All sound will DEFAULT load as a 2D sound unless otherwise specified. ...
void set_binary()
Indicates that the filename represents a binary file.
void set_volume(PN_stdfloat volume=1.0)
0.0 to 1.0 scale of volume converted to Fmod's internal 0.0 to 255.0 scale.
PN_stdfloat get_3d_min_distance() const
Get the distance that this sound begins to fall off.
void set_balance(PN_stdfloat balance_right=0.0)
-1.0 to 1.0 scale
void set_loop_count(unsigned long loop_count=1)
Panda uses 0 to mean loop forever.
void set_time(PN_stdfloat start_time=0.0)
Sets the time at which the next play() operation will begin.
streampos get_start() const
Returns the offset within the file at which this file data begins.
The abstract base class for a file or directory within the VirtualFileSystem.
static void close_read_file(istream *stream)
Closes a file opened by a previous call to open_read_file().
PN_stdfloat get_time() const
Gets the play position within the sound.
bool get_active() const
Returns whether the sound has been marked "active".
The name of a file, such as a texture file or an Egg file.
void set_loop(bool loop=true)
Turns looping on and off.
void set_3d_min_distance(PN_stdfloat dist)
Set the distance that this sound begins to fall off.
void set_play_rate(PN_stdfloat play_rate=1.0f)
Sets the speed at which a sound plays back.
static VirtualFileSystem * get_global_ptr()
Returns the default global VirtualFileSystem.
virtual PN_stdfloat get_speaker_mix(AudioManager::SpeakerId speaker)
In Multichannel Speaker systems [like Surround].
Similar to MutexHolder, but for a reentrant mutex.
void set_active(bool active=true)
Sets whether the sound is marked "active".
string to_os_specific() const
Converts the filename from our generic Unix-like convention (forward slashes starting with the root a...
virtual streamsize get_file_size(istream *stream) const
Returns the current size on disk (or wherever it is) of the already-open file.
PointerTo< VirtualFile > get_file(const Filename &filename, bool status_only=false) const
Looks up the file by the indicated name in the file system.
PN_stdfloat get_3d_max_distance() const
Get the distance that this sound stops falling off.
const Filename & get_filename() const
A shortcut to the filename.
This class records a particular byte sub-range within an existing file on disk.
PN_stdfloat get_volume() const
Gets the current volume of a sound.
void ref() const
Explicitly increments the reference count.
void set_finished_event(const string &event)
NOT USED ANYMORE!!! Assign a string for the finished event to be referenced by in python by an accept...
void set_3d_attributes(PN_stdfloat px, PN_stdfloat py, PN_stdfloat pz, PN_stdfloat vx, PN_stdfloat vy, PN_stdfloat vz)
Set position and velocity of this sound NOW LISTEN UP!!! THIS IS IMPORTANT! Both Panda3D and FMOD use...
void get_3d_attributes(PN_stdfloat *px, PN_stdfloat *py, PN_stdfloat *pz, PN_stdfloat *vx, PN_stdfloat *vy, PN_stdfloat *vz)
Get position and velocity of this sound Currently unimplemented.
~FmodAudioSound()
DESTRUCTOR!!!
PN_stdfloat get_balance() const
-1.0 to 1.0 scale -1 should be all the way left.
TypeHandle is the identifier used to differentiate C++ class types.
const string & get_name() const
Get name of sound file.
string get_extension() const
Returns the file extension.
bool get_loop() const
Returns whether looping is on or off.
unsigned long get_loop_count() const
Return how many times a sound will loop.