Torque3D Documentation / _generateds / sfxFMODBuffer.cpp

sfxFMODBuffer.cpp

Engine/source/sfx/fmod/sfxFMODBuffer.cpp

More...

Public Variables

const char *

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