123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322 |
- //-----------------------------------------------------------------------------
- // Copyright (c) 2012 GarageGames, LLC
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files (the "Software"), to
- // deal in the Software without restriction, including without limitation the
- // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- // sell copies of the Software, and to permit persons to whom the Software is
- // furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- // IN THE SOFTWARE.
- //-----------------------------------------------------------------------------
- #include "sfx/fmod/sfxFMODBuffer.h"
- #include "sfx/fmod/sfxFMODDevice.h"
- #include "sfx/sfxDescription.h"
- #include "core/util/safeDelete.h"
- #include "core/volume.h"
- //-----------------------------------------------------------------------------
- static const char* sExtensions[] =
- {
- "", // First try without doing anything with the given path.
- "", // Then try it without an extension but by expanding it through Torque::FS.
- "aiff",
- "asf",
- "asx",
- "dls",
- "flac",
- "fsb",
- "it",
- "m3u",
- "mid",
- "mod",
- "mp2",
- "mp3",
- "ogg",
- "pls",
- "s3m",
- "vag",
- "wav",
- "wax",
- "wma",
- "xm",
-
- #ifdef TORQUE_OS_XENON
- ".xma",
- #endif
- NULL
- };
- //-----------------------------------------------------------------------------
- SFXFMODBuffer* SFXFMODBuffer::create( const ThreadSafeRef< SFXStream >& stream, SFXDescription* description )
- {
- SFXFMODBuffer *buffer = new SFXFMODBuffer( stream, description );
- if( !buffer->mSound )
- SAFE_DELETE( buffer );
- return buffer;
- }
- //-----------------------------------------------------------------------------
- SFXFMODBuffer* SFXFMODBuffer::create( const String& filename, SFXDescription* description )
- {
- if( Con::getBoolVariable( "$pref::SFX::FMOD::noCustomFileLoading", false ) )
- return NULL;
-
- SFXFMODBuffer *buffer = new SFXFMODBuffer( filename, description );
- if( !buffer->mSound )
- SAFE_DELETE( buffer );
- return buffer;
- }
- //-----------------------------------------------------------------------------
- SFXFMODBuffer::SFXFMODBuffer( const String& filename, SFXDescription* description )
- : Parent( description ),
- mSound( NULL )
- {
- FMOD_MODE fMode = ( description->mUseHardware ? FMOD_HARDWARE : FMOD_SOFTWARE )
- | ( description->mIs3D ? FMOD_3D : FMOD_2D );
- if( description->mIsStreaming )
- {
- fMode |= FMOD_CREATESTREAM;
- mIsUnique = true;
- }
-
- // Go through the extensions and try each with the given path. The
- // first two are special. First we try without touching the filename at all
- // so FMOD gets a chance to handle URLs and whatever, and then second we
- // try by expanding the path but without adding an extension.
-
- Torque::Path path = filename;
- for( U32 i = 0; sExtensions[ i ]; ++ i )
- {
- path.setExtension( sExtensions[ i ] );
- if( !i || Torque::FS::IsFile( path ) )
- {
- // Translate to full path.
- //TODO: Remove this when hooking up the file system functions in sfxFMODDevice.cpp
- String fullPath;
- if( !i )
- fullPath = filename;
- else
- {
- Torque::Path realPath;
- if( !Torque::FS::GetFSPath( path, realPath ) )
- continue;
-
- fullPath = realPath.getFullPath().c_str();
- }
-
- mSound = NULL;
- FMOD_RESULT result = SFXFMODDevice::smFunc->FMOD_System_CreateSound(
- SFXFMODDevice::smSystem,
- fullPath.c_str(),
- fMode,
- ( FMOD_CREATESOUNDEXINFO* ) NULL,
- &mSound );
-
- if( result == FMOD_OK )
- {
- SFXFMODDevice::smFunc->FMOD_Sound_GetMode( mSound, &mMode );
-
- // Read out format.
-
- int numChannels;
- int bitsPerSample;
- unsigned int length;
- float frequency;
-
- SFXFMODDevice::smFunc->FMOD_Sound_GetFormat( mSound, ( FMOD_SOUND_TYPE* ) NULL, ( FMOD_SOUND_FORMAT* ) NULL, &numChannels, &bitsPerSample );
- SFXFMODDevice::smFunc->FMOD_Sound_GetLength( mSound, &length, FMOD_TIMEUNIT_MS );
- SFXFMODDevice::smFunc->FMOD_Sound_GetDefaults( mSound, &frequency, ( float* ) NULL, ( float* ) NULL, ( int* ) NULL );
- mDuration = length;
- mFormat = SFXFormat( numChannels, numChannels * bitsPerSample, frequency );
-
- break;
- }
- }
- }
- if( !mSound )
- Con::errorf( "SFXFMODBuffer::SFXFMODBuffer - failed to load '%s' through FMOD", filename.c_str() );
- }
- //-----------------------------------------------------------------------------
- SFXFMODBuffer::SFXFMODBuffer( const ThreadSafeRef< SFXStream >& stream, SFXDescription* description )
- : Parent( stream, description ),
- mSound( NULL )
- {
- FMOD_MODE fMode = ( description->mUseHardware ? FMOD_HARDWARE : FMOD_SOFTWARE )
- | ( description->mIs3D ? FMOD_3D : FMOD_2D );
- FMOD_CREATESOUNDEXINFO* pCreatesoundexinfo = NULL;
- FMOD_CREATESOUNDEXINFO createsoundexinfo;
- fMode |= FMOD_OPENUSER; // this tells fmod we are supplying the data directly
- if( isStreaming() )
- fMode |= FMOD_LOOP_NORMAL | FMOD_UNIQUE;
- const SFXFormat& format = getFormat();
- U32 channels = format.getChannels();
- U32 frequency = format.getSamplesPerSecond();
- U32 bitsPerChannel = format.getBitsPerSample() / channels;
- U32 dataSize = mBufferSize;
- FMOD_SOUND_FORMAT sfxFmt = FMOD_SOUND_FORMAT_NONE;
- switch(bitsPerChannel)
- {
- case 8:
- sfxFmt = FMOD_SOUND_FORMAT_PCM8;
- break;
- case 16:
- sfxFmt = FMOD_SOUND_FORMAT_PCM16;
- break;
- case 24:
- sfxFmt = FMOD_SOUND_FORMAT_PCM24;
- break;
- case 32:
- sfxFmt = FMOD_SOUND_FORMAT_PCM32;
- break;
- default:
- AssertISV(false, "SFXFMODBuffer::SFXFMODBuffer() - unsupported bits-per-sample (what format is it in, 15bit PCM?)");
- break;
- }
- dMemset(&createsoundexinfo, 0, sizeof(FMOD_CREATESOUNDEXINFO));
- createsoundexinfo.cbsize = sizeof(FMOD_CREATESOUNDEXINFO); /* required. */
- createsoundexinfo.decodebuffersize = frequency; /* Chunk size of stream update in samples. This will be the amount of data passed to the user callback. */
- createsoundexinfo.length = dataSize; /* Length of PCM data in bytes of whole sound (for Sound::getLength) */
- createsoundexinfo.numchannels = channels; /* Number of channels in the sound. */
- createsoundexinfo.defaultfrequency = frequency; /* Default playback rate of sound. */
- createsoundexinfo.format = sfxFmt; /* Data format of sound. */
- createsoundexinfo.pcmreadcallback = NULL; /* User callback for reading. */
- createsoundexinfo.pcmsetposcallback = NULL; /* User callback for seeking. */
- pCreatesoundexinfo = &createsoundexinfo;
- FMOD_RESULT result = SFXFMODDevice::smFunc->FMOD_System_CreateSound(
- SFXFMODDevice::smSystem,
- ( const char* ) NULL,
- fMode,
- pCreatesoundexinfo,
- &mSound );
-
- if( result != FMOD_OK )
- {
- mSound = NULL;
- Con::errorf( "SFXFMODBuffer::SFXFMODBuffer - failed to create buffer (%i)", result );
- }
- else
- SFXFMODDevice::smFunc->FMOD_Sound_GetMode( mSound, &mMode );
- }
- //-----------------------------------------------------------------------------
- SFXFMODBuffer::~SFXFMODBuffer()
- {
- if( mSound )
- FModAssert( SFXFMODDevice::smFunc->FMOD_Sound_Release( mSound ),
- "SFXFMODBuffer::~SFXFMODBuffer - Failed to release a sound!" );
- mSound = NULL;
- }
- //-----------------------------------------------------------------------------
- void SFXFMODBuffer::_flush()
- {
- AssertFatal( isStreaming(), "SFXFMODBuffer::_flush() - not a streaming buffer" );
- AssertFatal( SFXInternal::isSFXThread(), "SFXFMODBuffer::_flush() - not on SFX thread" );
- Parent::_flush();
- SFXFMODDevice::smFunc->FMOD_Channel_SetPosition
- ( ( ( SFXFMODVoice* ) mUniqueVoice.getPointer() )->mChannel, 0, FMOD_TIMEUNIT_PCM );
- }
- //-----------------------------------------------------------------------------
- bool SFXFMODBuffer::_copyData( U32 offset, const U8* data, U32 length )
- {
- AssertFatal( data != NULL && length > 0, "Must have data!" );
- // Fill the buffer with the resource data.
- void* lpvWrite;
- U32 dwLength;
- void* lpvWrite2;
- U32 dwLength2;
- int res = SFXFMODDevice::smFunc->FMOD_Sound_Lock(
- mSound,
- offset, // Offset at which to start lock.
- length, // Size of lock.
- &lpvWrite, // Gets address of first part of lock.
- &lpvWrite2, // Address of wraparound not needed.
- &dwLength, // Gets size of first part of lock.
- &dwLength2 // Size of wraparound not needed.
- );
- if ( res != FMOD_OK )
- {
- // You can remove this if it gets spammy. However since we can
- // safely fail in this case it doesn't seem right to assert...
- // at the same time it can be very annoying not to know why
- // an upload fails!
- Con::errorf("SFXFMODBuffer::_copyData - failed to lock a sound buffer! (%d)", this);
- return false;
- }
- // Copy the first part.
- dMemcpy( lpvWrite, data, dwLength );
- // Do we have a wrap?
- if ( lpvWrite2 )
- dMemcpy( lpvWrite2, data + dwLength, dwLength2 );
- // And finally, unlock.
- FModAssert( SFXFMODDevice::smFunc->FMOD_Sound_Unlock(
- mSound,
- lpvWrite, // Address of lock start.
- lpvWrite2, // No wraparound portion.
- dwLength, // Size of lock.
- dwLength2 ), // No wraparound size.
- "Failed to unlock sound buffer!" );
- return true;
- }
- //-----------------------------------------------------------------------------
- U32 SFXFMODBuffer::getMemoryUsed() const
- {
- unsigned int memoryUsed;
-
- SFXFMODDevice::smFunc->FMOD_Sound_GetMemoryInfo(
- mSound,
- FMOD_MEMBITS_ALL,
- FMOD_EVENT_MEMBITS_ALL,
- &memoryUsed,
- ( unsigned int* ) NULL );
-
- return memoryUsed;
- }
|