sfxProfile.cpp
Engine/source/sfx/sfxProfile.cpp
Classes:
class
Public Functions
ConsoleDocClass(AudioProfile , "@brief Allows legacy <a href="/coding/class/classaudioprofile/">AudioProfile</a> datablocks <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> be treated as <a href="/coding/class/classsfxprofile/">SFXProfile</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">datablocks.\n\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">afxMisc\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">AFX\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Datablocks\n</a>" )
ConsoleDocClass(SFXProfile , "@brief Encapsulates <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> single sound <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a702945180aa732857b380a007a7e2a21">file</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> playback by the sound <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">system.\n\n</a>" "<a href="/coding/class/classsfxprofile/">SFXProfile</a> combines <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> sound description (<a href="/coding/class/classsfxdescription/">SFXDescription</a>) with <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> sound <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a702945180aa732857b380a007a7e2a21">file</a> such that it can be played " "by the sound system. To be able <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> play <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> sound file, the sound system will always require <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> profile " "<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> it <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> be created. However, several of the <a href="/coding/file/sfxsystem_8h/#sfxsystem_8h_1a52e87f85ae30be82ffefd31b5c03e03d">SFX</a> functions(sfxPlayOnce(), sfxCreateSource()) perform " "this creation internally <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> convenience using temporary profile <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">objects.\n\n</a>" "Sound files can be in either OGG or WAV format. However, extended format support is available when using FMOD. " "See @ref <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">SFX_formats.\n\n</a>" " @section SFXProfile_loading Profile <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Loading\n\n</a>" "By default, the sound data referenced by <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> profile will be loaded when the profile is first played and the " "data then kept until either the profile is deleted or until the sound device on which the sound data is held " "is <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">deleted.\n\n</a>" "This initial loading my incur <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> small delay when the sound is first played. To avoid this, <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> profile may be " "expicitly set <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> load its sound data immediately when the profile is added <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the system. This is done by " "setting the #preload property <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">true.\n\n</a>" " @note Sounds using streamed playback(SFXDescription::isStreaming) cannot be preloaded and will thus " "ignore the #preload <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">flag.\n\n</a>" " @<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tsexample\n</a>" "datablock <a href="/coding/class/classsfxprofile/">SFXProfile</a>(Shore01Snd)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "{\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " fileName=\"art/sound/Lakeshore_mono_01\";\n" " description = Shore01Looping3d;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " preload = true;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "};\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">endtsexample\n\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">SFX\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Datablocks\n</a>" )
DefineEngineMethod(SFXProfile , getSoundDuration , F32 , () , "Return the length of the sound data in <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">seconds.\n\n</a>" "@return The length of the sound data in seconds or 0 <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> the sound referenced by the profile could not be found." )
Detailed Description
Public Functions
ConsoleDocClass(AudioProfile , "@brief Allows legacy <a href="/coding/class/classaudioprofile/">AudioProfile</a> datablocks <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> be treated as <a href="/coding/class/classsfxprofile/">SFXProfile</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">datablocks.\n\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">afxMisc\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">AFX\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Datablocks\n</a>" )
ConsoleDocClass(SFXProfile , "@brief Encapsulates <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> single sound <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a702945180aa732857b380a007a7e2a21">file</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> playback by the sound <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">system.\n\n</a>" "<a href="/coding/class/classsfxprofile/">SFXProfile</a> combines <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> sound description (<a href="/coding/class/classsfxdescription/">SFXDescription</a>) with <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> sound <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a702945180aa732857b380a007a7e2a21">file</a> such that it can be played " "by the sound system. To be able <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> play <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> sound file, the sound system will always require <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> profile " "<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> it <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> be created. However, several of the <a href="/coding/file/sfxsystem_8h/#sfxsystem_8h_1a52e87f85ae30be82ffefd31b5c03e03d">SFX</a> functions(sfxPlayOnce(), sfxCreateSource()) perform " "this creation internally <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> convenience using temporary profile <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">objects.\n\n</a>" "Sound files can be in either OGG or WAV format. However, extended format support is available when using FMOD. " "See @ref <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">SFX_formats.\n\n</a>" " @section SFXProfile_loading Profile <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Loading\n\n</a>" "By default, the sound data referenced by <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> profile will be loaded when the profile is first played and the " "data then kept until either the profile is deleted or until the sound device on which the sound data is held " "is <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">deleted.\n\n</a>" "This initial loading my incur <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> small delay when the sound is first played. To avoid this, <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> profile may be " "expicitly set <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> load its sound data immediately when the profile is added <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the system. This is done by " "setting the #preload property <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">true.\n\n</a>" " @note Sounds using streamed playback(SFXDescription::isStreaming) cannot be preloaded and will thus " "ignore the #preload <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">flag.\n\n</a>" " @<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tsexample\n</a>" "datablock <a href="/coding/class/classsfxprofile/">SFXProfile</a>(Shore01Snd)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "{\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " fileName=\"art/sound/Lakeshore_mono_01\";\n" " description = Shore01Looping3d;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " preload = true;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "};\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">endtsexample\n\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">SFX\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Datablocks\n</a>" )
DefineEngineMethod(SFXProfile , getSoundDuration , F32 , () , "Return the length of the sound data in <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">seconds.\n\n</a>" "@return The length of the sound data in seconds or 0 <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> the sound referenced by the profile could not be found." )
IMPLEMENT_CO_DATABLOCK_V1(AudioProfile )
IMPLEMENT_CO_DATABLOCK_V1(SFXProfile )
1 2//----------------------------------------------------------------------------- 3// Copyright (c) 2012 GarageGames, LLC 4// 5// Permission is hereby granted, free of charge, to any person obtaining a copy 6// of this software and associated documentation files (the "Software"), to 7// deal in the Software without restriction, including without limitation the 8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 9// sell copies of the Software, and to permit persons to whom the Software is 10// furnished to do so, subject to the following conditions: 11// 12// The above copyright notice and this permission notice shall be included in 13// all copies or substantial portions of the Software. 14// 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21// IN THE SOFTWARE. 22//----------------------------------------------------------------------------- 23 24//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// 25// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames 26// Copyright (C) 2015 Faust Logic, Inc. 27//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// 28 29#include "platform/platform.h" 30 31#include "sfx/sfxProfile.h" 32#include "sfx/sfxDescription.h" 33#include "sfx/sfxSystem.h" 34#include "sfx/sfxStream.h" 35#include "sim/netConnection.h" 36#include "core/stream/bitStream.h" 37#include "core/resourceManager.h" 38#include "console/engineAPI.h" 39 40using namespace Torque; 41 42IMPLEMENT_CO_DATABLOCK_V1( SFXProfile ); 43 44 45ConsoleDocClass( SFXProfile, 46 "@brief Encapsulates a single sound file for playback by the sound system.\n\n" 47 48 "SFXProfile combines a sound description (SFXDescription) with a sound file such that it can be played " 49 "by the sound system. To be able to play a sound file, the sound system will always require a profile " 50 "for it to be created. However, several of the SFX functions (sfxPlayOnce(), sfxCreateSource()) perform " 51 "this creation internally for convenience using temporary profile objects.\n\n" 52 53 "Sound files can be in either OGG or WAV format. However, extended format support is available when using FMOD. " 54 "See @ref SFX_formats.\n\n" 55 56 "@section SFXProfile_loading Profile Loading\n\n" 57 58 "By default, the sound data referenced by a profile will be loaded when the profile is first played and the " 59 "data then kept until either the profile is deleted or until the sound device on which the sound data is held " 60 "is deleted.\n\n" 61 62 "This initial loading my incur a small delay when the sound is first played. To avoid this, a profile may be " 63 "expicitly set to load its sound data immediately when the profile is added to the system. This is done by " 64 "setting the #preload property to true.\n\n" 65 66 "@note Sounds using streamed playback (SFXDescription::isStreaming) cannot be preloaded and will thus " 67 "ignore the #preload flag.\n\n" 68 69 "@tsexample\n" 70 "datablock SFXProfile( Shore01Snd )\n" 71 "{\n" 72 " fileName = \"art/sound/Lakeshore_mono_01\";\n" 73 " description = Shore01Looping3d;\n" 74 " preload = true;\n" 75 "};\n" 76 "@endtsexample\n\n" 77 78 "@ingroup SFX\n" 79 "@ingroup Datablocks\n" 80); 81 82 83//----------------------------------------------------------------------------- 84 85SFXProfile::SFXProfile() 86 : mPreload( false ) 87{ 88} 89 90//----------------------------------------------------------------------------- 91 92SFXProfile::SFXProfile( SFXDescription* desc, const String& filename, bool preload ) 93 : Parent( desc ), 94 mFilename( filename ), 95 mPreload( preload ) 96{ 97} 98 99//----------------------------------------------------------------------------- 100 101 102//----------------------------------------------------------------------------- 103 104void SFXProfile::initPersistFields() 105{ 106 addGroup( "Sound" ); 107 108 addField( "filename", TypeStringFilename, Offset( mFilename, SFXProfile ), 109 "%Path to the sound file.\n" 110 "If the extension is left out, it will be inferred by the sound system. This allows to " 111 "easily switch the sound format without having to go through the profiles and change the " 112 "filenames there, too.\n" ); 113 addField( "preload", TypeBool, Offset( mPreload, SFXProfile ), 114 "Whether to preload sound data when the profile is added to system.\n" 115 "@note This flag is ignored by streamed sounds.\n\n" 116 "@ref SFXProfile_loading" ); 117 118 endGroup( "Sound" ); 119 120 // disallow some field substitutions 121 disableFieldSubstitutions("description"); 122 123 Parent::initPersistFields(); 124} 125 126//----------------------------------------------------------------------------- 127 128bool SFXProfile::onAdd() 129{ 130 if( !Parent::onAdd() ) 131 return false; 132 133 // If we're a streaming profile we don't preload 134 // or need device events. 135 if( SFX && !mDescription->mIsStreaming ) 136 { 137 // If preload is enabled we load the resource 138 // and device buffer now to avoid a delay on 139 // first playback. 140 if( mPreload && !_preloadBuffer() ) 141 Con::errorf( "SFXProfile(%s)::onAdd: The preload failed!", getName() ); 142 } 143 144 _registerSignals(); 145 146 return true; 147} 148 149//----------------------------------------------------------------------------- 150 151void SFXProfile::onRemove() 152{ 153 _unregisterSignals(); 154 155 Parent::onRemove(); 156} 157 158//----------------------------------------------------------------------------- 159 160bool SFXProfile::preload( bool server, String &errorStr ) 161{ 162 if ( !Parent::preload( server, errorStr ) ) 163 return false; 164 165 // TODO: Investigate how NetConnection::filesWereDownloaded() 166 // effects the system. 167 168 // Validate the datablock... has nothing to do with mPreload. 169 if( !server && 170 NetConnection::filesWereDownloaded() && 171 ( mFilename.isEmpty() || !SFXResource::exists( mFilename ) ) ) 172 return false; 173 174 return true; 175} 176 177//----------------------------------------------------------------------------- 178 179void SFXProfile::packData(BitStream* stream) 180{ 181 Parent::packData( stream ); 182 183 char buffer[256]; 184 if ( mFilename.isEmpty() ) 185 buffer[0] = 0; 186 else 187 dStrncpy( buffer, mFilename.c_str(), 256 ); 188 stream->writeString( buffer ); 189 190 stream->writeFlag( mPreload ); 191} 192 193//----------------------------------------------------------------------------- 194 195void SFXProfile::unpackData(BitStream* stream) 196{ 197 Parent::unpackData( stream ); 198 199 char buffer[256]; 200 stream->readString( buffer ); 201 mFilename = buffer; 202 203 mPreload = stream->readFlag(); 204} 205 206//----------------------------------------------------------------------------- 207 208bool SFXProfile::isLooping() const 209{ 210 return getDescription()->mIsLooping; 211} 212 213//----------------------------------------------------------------------------- 214 215void SFXProfile::_registerSignals() 216{ 217 SFX->getEventSignal().notify( this, &SFXProfile::_onDeviceEvent ); 218 ResourceManager::get().getChangedSignal().notify( this, &SFXProfile::_onResourceChanged ); 219} 220 221//----------------------------------------------------------------------------- 222 223void SFXProfile::_unregisterSignals() 224{ 225 ResourceManager::get().getChangedSignal().remove( this, &SFXProfile::_onResourceChanged ); 226 if( SFX ) 227 SFX->getEventSignal().remove( this, &SFXProfile::_onDeviceEvent ); 228} 229 230//----------------------------------------------------------------------------- 231 232void SFXProfile::_onDeviceEvent( SFXSystemEventType evt ) 233{ 234 switch( evt ) 235 { 236 case SFXSystemEvent_CreateDevice: 237 { 238 if( mPreload && !mDescription->mIsStreaming && !_preloadBuffer() ) 239 Con::errorf( "SFXProfile::_onDeviceEvent: The preload failed! %s", getName() ); 240 break; 241 } 242 243 default: 244 break; 245 } 246} 247 248//----------------------------------------------------------------------------- 249 250void SFXProfile::_onResourceChanged( const Torque::Path& path ) 251{ 252 if( path != Path( mFilename ) ) 253 return; 254 255 // Let go of the old resource and buffer. 256 257 mResource = NULL; 258 mBuffer = NULL; 259 260 // Load the new resource. 261 262 getResource(); 263 264 if( mPreload && !mDescription->mIsStreaming ) 265 { 266 if( !_preloadBuffer() ) 267 Con::errorf( "SFXProfile::_onResourceChanged() - failed to preload '%s'", mFilename.c_str() ); 268 } 269 270 mChangedSignal.trigger( this ); 271} 272 273//----------------------------------------------------------------------------- 274 275bool SFXProfile::_preloadBuffer() 276{ 277 AssertFatal( !mDescription->mIsStreaming, "SFXProfile::_preloadBuffer() - must not be called for streaming profiles" ); 278 279 mBuffer = _createBuffer(); 280 return ( !mBuffer.isNull() ); 281} 282 283//----------------------------------------------------------------------------- 284 285Resource<SFXResource>& SFXProfile::getResource() 286{ 287 if( !mResource && !mFilename.isEmpty() ) 288 mResource = SFXResource::load( mFilename ); 289 290 return mResource; 291} 292 293//----------------------------------------------------------------------------- 294 295SFXBuffer* SFXProfile::getBuffer() 296{ 297 if ( mDescription->mIsStreaming ) 298 { 299 // Streaming requires unique buffers per 300 // source, so this creates a new buffer. 301 if ( SFX ) 302 return _createBuffer(); 303 304 return NULL; 305 } 306 307 if ( mBuffer.isNull() ) 308 _preloadBuffer(); 309 310 return mBuffer; 311} 312 313//----------------------------------------------------------------------------- 314 315SFXBuffer* SFXProfile::_createBuffer() 316{ 317 SFXBuffer* buffer = 0; 318 319 // Try to create through SFXDevie. 320 321 if( !mFilename.isEmpty() && SFX ) 322 { 323 buffer = SFX->_createBuffer( mFilename, mDescription ); 324 if( buffer ) 325 { 326 #ifdef TORQUE_DEBUG 327 const SFXFormat& format = buffer->getFormat(); 328 Con::printf( "%s SFX: %s (%i channels, %i kHz, %.02f sec, %i kb)", 329 mDescription->mIsStreaming ? "Streaming" : "Loaded", mFilename.c_str(), 330 format.getChannels(), 331 format.getSamplesPerSecond() / 1000, 332 F32( buffer->getDuration() ) / 1000.0f, 333 format.getDataLength( buffer->getDuration() ) / 1024 ); 334 #endif 335 } 336 } 337 338 // If that failed, load through SFXResource. 339 340 if( !buffer ) 341 { 342 Resource< SFXResource>& resource = getResource(); 343 if( resource != NULL && SFX ) 344 { 345 #ifdef TORQUE_DEBUG 346 const SFXFormat& format = resource->getFormat(); 347 Con::printf( "%s SFX: %s (%i channels, %i kHz, %.02f sec, %i kb)", 348 mDescription->mIsStreaming ? "Streaming" : "Loading", resource->getFileName().c_str(), 349 format.getChannels(), 350 format.getSamplesPerSecond() / 1000, 351 F32( resource->getDuration() ) / 1000.0f, 352 format.getDataLength( resource->getDuration() ) / 1024 ); 353 #endif 354 355 ThreadSafeRef< SFXStream> sfxStream = resource->openStream(); 356 buffer = SFX->_createBuffer( sfxStream, mDescription ); 357 } 358 } 359 360 return buffer; 361} 362 363//----------------------------------------------------------------------------- 364 365U32 SFXProfile::getSoundDuration() 366{ 367 Resource< SFXResource>& resource = getResource(); 368 if( resource != NULL ) 369 return mResource->getDuration(); 370 else 371 return 0; 372} 373 374//----------------------------------------------------------------------------- 375 376DefineEngineMethod( SFXProfile, getSoundDuration, F32, (),, 377 "Return the length of the sound data in seconds.\n\n" 378 "@return The length of the sound data in seconds or 0 if the sound referenced by the profile could not be found." ) 379{ 380 return ( F32 ) object->getSoundDuration() * 0.001f; 381} 382 383// enable this to help verify that temp-clones of AudioProfile are being deleted 384//#define TRACK_AUDIO_PROFILE_CLONES 385 386#ifdef TRACK_AUDIO_PROFILE_CLONES 387static int audio_prof_clones = 0; 388#endif 389 390SFXProfile::SFXProfile(const SFXProfile& other, bool temp_clone) : SFXTrack(other, temp_clone) 391{ 392#ifdef TRACK_AUDIO_PROFILE_CLONES 393 audio_prof_clones++; 394 if (audio_prof_clones == 1) 395 Con::errorf("SFXProfile -- Clones are on the loose!"); 396#endif 397 mResource = other.mResource; 398 mFilename = other.mFilename; 399 mPreload = other.mPreload; 400 mBuffer = other.mBuffer; // -- AudioBuffer loaded using mFilename 401 mChangedSignal = other.mChangedSignal; 402} 403 404SFXProfile::~SFXProfile() 405{ 406 if (!isTempClone()) 407 return; 408 409 // cleanup after a temp-clone 410 411 if (mDescription && mDescription->isTempClone()) 412 { 413 delete mDescription; 414 mDescription = 0; 415 } 416 417#ifdef TRACK_AUDIO_PROFILE_CLONES 418 if (audio_prof_clones > 0) 419 { 420 audio_prof_clones--; 421 if (audio_prof_clones == 0) 422 Con::errorf("SFXProfile -- Clones eliminated!"); 423 } 424 else 425 Con::errorf("SFXProfile -- Too many clones deleted!"); 426#endif 427} 428 429// Clone and perform substitutions on the SFXProfile and on any SFXDescription 430// it references. 431SFXProfile* SFXProfile::cloneAndPerformSubstitutions(const SimObject* owner, S32 index) 432{ 433 if (!owner) 434 return this; 435 436 SFXProfile* sub_profile_db = this; 437 438 // look for mDescriptionObject subs 439 SFXDescription* desc_db; 440 if (mDescription && mDescription->getSubstitutionCount() > 0) 441 { 442 SFXDescription* orig_db = mDescription; 443 desc_db = new SFXDescription(*orig_db, true); 444 orig_db->performSubstitutions(desc_db, owner, index); 445 } 446 else 447 desc_db = 0; 448 449 if (this->getSubstitutionCount() > 0 || desc_db) 450 { 451 sub_profile_db = new SFXProfile(*this, true); 452 performSubstitutions(sub_profile_db, owner, index); 453 if (desc_db) 454 sub_profile_db->mDescription = desc_db; 455 } 456 457 return sub_profile_db; 458} 459 460void SFXProfile::onPerformSubstitutions() 461{ 462 if ( SFX ) 463 { 464 // If preload is enabled we load the resource 465 // and device buffer now to avoid a delay on 466 // first playback. 467 if ( mPreload && !_preloadBuffer() ) 468 Con::errorf( "SFXProfile(%s)::onPerformSubstitutions: The preload failed!", getName() ); 469 470 // We need to get device change notifications. 471 SFX->getEventSignal().notify( this, &SFXProfile::_onDeviceEvent ); 472 } 473} 474// This allows legacy AudioProfile datablocks to be recognized as an alias 475// for SFXProfile. It is intended to ease the transition from older scripts 476// especially those that still need to support pre-1.7 applications. 477// (This maybe removed in future releases so treat as deprecated.) 478class AudioProfile : public SFXProfile 479{ 480 typedef SFXProfile Parent; 481public: 482 DECLARE_CONOBJECT(AudioProfile); 483}; 484 485IMPLEMENT_CO_DATABLOCK_V1(AudioProfile); 486 487ConsoleDocClass( AudioProfile, 488 "@brief Allows legacy AudioProfile datablocks to be treated as SFXProfile datablocks.\n\n" 489 490 "@ingroup afxMisc\n" 491 "@ingroup AFX\n" 492 "@ingroup Datablocks\n" 493); 494 495