mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-03-27 08:09:31 +00:00
Engine directory for ticket #1
This commit is contained in:
parent
352279af7a
commit
7dbfe6994d
3795 changed files with 1363358 additions and 0 deletions
322
Engine/source/sfx/fmod/sfxFMODBuffer.cpp
Normal file
322
Engine/source/sfx/fmod/sfxFMODBuffer.cpp
Normal file
|
|
@ -0,0 +1,322 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue