sfxFMODBuffer.cpp
Engine/source/sfx/fmod/sfxFMODBuffer.cpp
Public Variables
const char *
sExtensions []
Detailed Description
Public Variables
const char * sExtensions []
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#include "sfx/fmod/sfxFMODBuffer.h" 25#include "sfx/fmod/sfxFMODDevice.h" 26#include "sfx/sfxDescription.h" 27#include "core/util/safeDelete.h" 28#include "core/volume.h" 29 30 31//----------------------------------------------------------------------------- 32 33static const char* sExtensions[] = 34{ 35 "", // First try without doing anything with the given path. 36 "", // Then try it without an extension but by expanding it through Torque::FS. 37 "aiff", 38 "asf", 39 "asx", 40 "dls", 41 "flac", 42 "fsb", 43 "it", 44 "m3u", 45 "mid", 46 "mod", 47 "mp2", 48 "mp3", 49 "ogg", 50 "pls", 51 "s3m", 52 "vag", 53 "wav", 54 "wax", 55 "wma", 56 "xm", 57 58#ifdef TORQUE_OS_XENON 59 ".xma", 60#endif 61 62 NULL 63}; 64 65//----------------------------------------------------------------------------- 66 67SFXFMODBuffer* SFXFMODBuffer::create( const ThreadSafeRef< SFXStream>& stream, SFXDescription* description ) 68{ 69 SFXFMODBuffer *buffer = new SFXFMODBuffer( stream, description ); 70 if( !buffer->mSound ) 71 SAFE_DELETE( buffer ); 72 73 return buffer; 74} 75 76//----------------------------------------------------------------------------- 77 78SFXFMODBuffer* SFXFMODBuffer::create( const String& filename, SFXDescription* description ) 79{ 80 if( Con::getBoolVariable( "$pref::SFX::FMOD::noCustomFileLoading", false ) ) 81 return NULL; 82 83 SFXFMODBuffer *buffer = new SFXFMODBuffer( filename, description ); 84 if( !buffer->mSound ) 85 SAFE_DELETE( buffer ); 86 87 return buffer; 88} 89 90//----------------------------------------------------------------------------- 91 92SFXFMODBuffer::SFXFMODBuffer( const String& filename, SFXDescription* description ) 93 : Parent( description ), 94 mSound( NULL ) 95{ 96 FMOD_MODE fMode = ( description->mUseHardware ? FMOD_HARDWARE : FMOD_SOFTWARE ) 97 | ( description->mIs3D ? FMOD_3D : FMOD_2D ); 98 99 if( description->mIsStreaming ) 100 { 101 fMode |= FMOD_CREATESTREAM; 102 mIsUnique = true; 103 } 104 105 // Go through the extensions and try each with the given path. The 106 // first two are special. First we try without touching the filename at all 107 // so FMOD gets a chance to handle URLs and whatever, and then second we 108 // try by expanding the path but without adding an extension. 109 110 Torque::Path path = filename; 111 for( U32 i = 0; sExtensions[ i ]; ++ i ) 112 { 113 path.setExtension( sExtensions[ i ] ); 114 115 if( !i || Torque::FS::IsFile( path ) ) 116 { 117 // Translate to full path. 118 //TODO: Remove this when hooking up the file system functions in sfxFMODDevice.cpp 119 120 String fullPath; 121 if( !i ) 122 fullPath = filename; 123 else 124 { 125 Torque::Path realPath; 126 if( !Torque::FS::GetFSPath( path, realPath ) ) 127 continue; 128 129 fullPath = realPath.getFullPath().c_str(); 130 } 131 132 mSound = NULL; 133 FMOD_RESULT result = SFXFMODDevice::smFunc->FMOD_System_CreateSound( 134 SFXFMODDevice::smSystem, 135 fullPath.c_str(), 136 fMode, 137 ( FMOD_CREATESOUNDEXINFO* ) NULL, 138 &mSound ); 139 140 if( result == FMOD_OK ) 141 { 142 SFXFMODDevice::smFunc->FMOD_Sound_GetMode( mSound, &mMode ); 143 144 // Read out format. 145 146 int numChannels; 147 int bitsPerSample; 148 unsigned int length; 149 float frequency; 150 151 SFXFMODDevice::smFunc->FMOD_Sound_GetFormat( mSound, ( FMOD_SOUND_TYPE* ) NULL, ( FMOD_SOUND_FORMAT* ) NULL, &numChannels, &bitsPerSample ); 152 SFXFMODDevice::smFunc->FMOD_Sound_GetLength( mSound, &length, FMOD_TIMEUNIT_MS ); 153 SFXFMODDevice::smFunc->FMOD_Sound_GetDefaults( mSound, &frequency, ( float* ) NULL, ( float* ) NULL, ( int* ) NULL ); 154 155 mDuration = length; 156 mFormat = SFXFormat( numChannels, numChannels * bitsPerSample, frequency ); 157 158 break; 159 } 160 } 161 } 162 163 if( !mSound ) 164 Con::errorf( "SFXFMODBuffer::SFXFMODBuffer - failed to load '%s' through FMOD", filename.c_str() ); 165} 166 167//----------------------------------------------------------------------------- 168 169SFXFMODBuffer::SFXFMODBuffer( const ThreadSafeRef< SFXStream>& stream, SFXDescription* description ) 170 : Parent( stream, description ), 171 mSound( NULL ) 172{ 173 FMOD_MODE fMode = ( description->mUseHardware ? FMOD_HARDWARE : FMOD_SOFTWARE ) 174 | ( description->mIs3D ? FMOD_3D : FMOD_2D ); 175 176 FMOD_CREATESOUNDEXINFO* pCreatesoundexinfo = NULL; 177 FMOD_CREATESOUNDEXINFO createsoundexinfo; 178 179 fMode |= FMOD_OPENUSER; // this tells fmod we are supplying the data directly 180 if( isStreaming() ) 181 fMode |= FMOD_LOOP_NORMAL | FMOD_UNIQUE; 182 183 const SFXFormat& format = getFormat(); 184 U32 channels = format.getChannels(); 185 U32 frequency = format.getSamplesPerSecond(); 186 U32 bitsPerChannel = format.getBitsPerSample() / channels; 187 U32 dataSize = mBufferSize; 188 189 FMOD_SOUND_FORMAT sfxFmt = FMOD_SOUND_FORMAT_NONE; 190 switch(bitsPerChannel) 191 { 192 case 8: 193 sfxFmt = FMOD_SOUND_FORMAT_PCM8; 194 break; 195 case 16: 196 sfxFmt = FMOD_SOUND_FORMAT_PCM16; 197 break; 198 case 24: 199 sfxFmt = FMOD_SOUND_FORMAT_PCM24; 200 break; 201 case 32: 202 sfxFmt = FMOD_SOUND_FORMAT_PCM32; 203 break; 204 default: 205 AssertISV(false, "SFXFMODBuffer::SFXFMODBuffer() - unsupported bits-per-sample (what format is it in, 15bit PCM?)"); 206 break; 207 } 208 209 dMemset(&createsoundexinfo, 0, sizeof(FMOD_CREATESOUNDEXINFO)); 210 createsoundexinfo.cbsize = sizeof(FMOD_CREATESOUNDEXINFO); /* required. */ 211 createsoundexinfo.decodebuffersize = frequency; /* Chunk size of stream update in samples. This will be the amount of data passed to the user callback. */ 212 createsoundexinfo.length = dataSize; /* Length of PCM data in bytes of whole sound (for Sound::getLength) */ 213 createsoundexinfo.numchannels = channels; /* Number of channels in the sound. */ 214 createsoundexinfo.defaultfrequency = frequency; /* Default playback rate of sound. */ 215 createsoundexinfo.format = sfxFmt; /* Data format of sound. */ 216 createsoundexinfo.pcmreadcallback = NULL; /* User callback for reading. */ 217 createsoundexinfo.pcmsetposcallback = NULL; /* User callback for seeking. */ 218 pCreatesoundexinfo = &createsoundexinfo; 219 220 FMOD_RESULT result = SFXFMODDevice::smFunc->FMOD_System_CreateSound( 221 SFXFMODDevice::smSystem, 222 ( const char* ) NULL, 223 fMode, 224 pCreatesoundexinfo, 225 &mSound ); 226 227 if( result != FMOD_OK ) 228 { 229 mSound = NULL; 230 Con::errorf( "SFXFMODBuffer::SFXFMODBuffer - failed to create buffer (%i)", result ); 231 } 232 else 233 SFXFMODDevice::smFunc->FMOD_Sound_GetMode( mSound, &mMode ); 234} 235 236//----------------------------------------------------------------------------- 237 238SFXFMODBuffer::~SFXFMODBuffer() 239{ 240 if( mSound ) 241 FModAssert( SFXFMODDevice::smFunc->FMOD_Sound_Release( mSound ), 242 "SFXFMODBuffer::~SFXFMODBuffer - Failed to release a sound!" ); 243 244 mSound = NULL; 245} 246 247//----------------------------------------------------------------------------- 248 249void SFXFMODBuffer::_flush() 250{ 251 AssertFatal( isStreaming(), "SFXFMODBuffer::_flush() - not a streaming buffer" ); 252 AssertFatal( SFXInternal::isSFXThread(), "SFXFMODBuffer::_flush() - not on SFX thread" ); 253 254 Parent::_flush(); 255 SFXFMODDevice::smFunc->FMOD_Channel_SetPosition 256 ( ( ( SFXFMODVoice* ) mUniqueVoice.getPointer() )->mChannel, 0, FMOD_TIMEUNIT_PCM ); 257} 258 259//----------------------------------------------------------------------------- 260 261bool SFXFMODBuffer::_copyData( U32 offset, const U8* data, U32 length ) 262{ 263 AssertFatal( data != NULL && length > 0, "Must have data!" ); 264 265 // Fill the buffer with the resource data. 266 void* lpvWrite; 267 U32 dwLength; 268 void* lpvWrite2; 269 U32 dwLength2; 270 int res = SFXFMODDevice::smFunc->FMOD_Sound_Lock( 271 mSound, 272 offset, // Offset at which to start lock. 273 length, // Size of lock. 274 &lpvWrite, // Gets address of first part of lock. 275 &lpvWrite2, // Address of wraparound not needed. 276 &dwLength, // Gets size of first part of lock. 277 &dwLength2 // Size of wraparound not needed. 278 ); 279 280 if ( res != FMOD_OK ) 281 { 282 // You can remove this if it gets spammy. However since we can 283 // safely fail in this case it doesn't seem right to assert... 284 // at the same time it can be very annoying not to know why 285 // an upload fails! 286 Con::errorf("SFXFMODBuffer::_copyData - failed to lock a sound buffer! (%d)", this); 287 return false; 288 } 289 290 // Copy the first part. 291 dMemcpy( lpvWrite, data, dwLength ); 292 293 // Do we have a wrap? 294 if ( lpvWrite2 ) 295 dMemcpy( lpvWrite2, data + dwLength, dwLength2 ); 296 297 // And finally, unlock. 298 FModAssert( SFXFMODDevice::smFunc->FMOD_Sound_Unlock( 299 mSound, 300 lpvWrite, // Address of lock start. 301 lpvWrite2, // No wraparound portion. 302 dwLength, // Size of lock. 303 dwLength2 ), // No wraparound size. 304 "Failed to unlock sound buffer!" ); 305 306 return true; 307} 308 309//----------------------------------------------------------------------------- 310 311U32 SFXFMODBuffer::getMemoryUsed() const 312{ 313 unsigned int memoryUsed; 314 315 SFXFMODDevice::smFunc->FMOD_Sound_GetMemoryInfo( 316 mSound, 317 FMOD_MEMBITS_ALL, 318 FMOD_EVENT_MEMBITS_ALL, 319 &memoryUsed, 320 ( unsigned int* ) NULL ); 321 322 return memoryUsed; 323} 324