1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-07-08 09:16:00 +02:00

Initial checkin

This commit is contained in:
Brian Fiete 2019-08-23 11:56:54 -07:00
parent c74712dad9
commit 078564ac9e
3242 changed files with 1616395 additions and 0 deletions

View file

@ -0,0 +1,151 @@
#include "BFPlatform.h"
#ifdef BF_WWISE_ENABLED
//////////////////////////////////////////////////////////////////////
//
// AkDefaultLowLevelIODispatcher.cpp
//
// Canvas for implementation of the AK::StreamMgr::IAkFileLocationResolver,
// meant to be used in a multiple streaming devices system. It is this
// object that should be registered as the one and only
// AK::StreamMgr::IAkFileLocationResolver of the Stream Manager
// (by calling AK::StreamMgr::SetFileLocationResolver()).
//
// It forwards the calls to Open() to one of the low level I/O devices
// that were added to it using AddDevice(). These devices must thus also
// implement AK::StreamMgr::IAkFileLocationResolver.
//
// The strategy for device dispatching is that of a chain of responsibility:
// the dispatcher asks the first file resolver hook to open the file. If it
// fails, then it tries with the second, and so on, until a hook succeeds.
// This is inefficient. In your game, you should implement a strategy of
// your own (see CAkDefaultLowLevelIODispatcher::Open()).
//
// Copyright (c) 2006 Audiokinetic Inc. / All Rights Reserved
//
//////////////////////////////////////////////////////////////////////
#include "Common.h"
#include "AkDefaultLowLevelIODispatcher.h"
#include <AK/Tools/Common/AkAssert.h>
CAkDefaultLowLevelIODispatcher::CAkDefaultLowLevelIODispatcher()
:m_uNumDevices( 0 )
{
RemoveAllDevices();
}
CAkDefaultLowLevelIODispatcher::~CAkDefaultLowLevelIODispatcher()
{
}
// Returns a file descriptor for a given file name (string).
AKRESULT CAkDefaultLowLevelIODispatcher::Open(
const AkOSChar* in_pszFileName, // File name.
AkOpenMode in_eOpenMode, // Open mode.
AkFileSystemFlags * in_pFlags, // Special flags. Can pass NULL.
bool & io_bSyncOpen, // If true, the file must be opened synchronously. Otherwise it is left at the File Location Resolver's discretion. Return false if Open needs to be deferred.
AkFileDesc & out_fileDesc // Returned file descriptor.
)
{
// Here, you need to define a strategy to determine which device is going to handle this file's I/O.
// You could use some naming convention, or use the AkFileSystemFlags or file name extension if it depends
// on file type, or define a map, or read the mapping from an XML file... it is up to the game's organization.
// Since this default implementation doesn't know anything about that, it forwards the calls to each
// device until one of them succeeds.
// Disable deferred opening because devices may usually return AK_Success if io_bSyncOpen=false,
// and we count on the fact that they will return AK_Fail to select the proper device.
io_bSyncOpen = true;
AKRESULT eResult = AK_FileNotFound;
AkUInt32 uDevice = 0;
while ( uDevice < AK_MAX_IO_DEVICES
&& eResult != AK_Success )
{
if ( m_arDevices[uDevice] )
{
eResult = m_arDevices[uDevice]->Open(
in_pszFileName, // File name.
in_eOpenMode, // Open mode.
in_pFlags, // Special flags. Can pass NULL.
io_bSyncOpen, // If true, the file must be opened synchronously. Otherwise it is left at the File Location Resolver's discretion. Return false if Open needs to be deferred.
out_fileDesc // Returned file descriptor.
);
AKASSERT( io_bSyncOpen || !"It is illegal to reset io_bSyncOpen" );
}
++uDevice;
}
return eResult;
}
// Returns a file descriptor for a given file ID.
AKRESULT CAkDefaultLowLevelIODispatcher::Open(
AkFileID in_fileID, // File ID.
AkOpenMode in_eOpenMode, // Open mode.
AkFileSystemFlags * in_pFlags, // Special flags. Can pass NULL.
bool & io_bSyncOpen, // If true, the file must be opened synchronously. Otherwise it is left at the File Location Resolver's discretion. Return false if Open needs to be deferred.
AkFileDesc & out_fileDesc // Returned file descriptor.
)
{
// Here, you need to define a strategy to determine which device is going to handle this file's I/O.
// You could use the AkFileSystemFlags if it depends on file type, or define a map, or read the mapping
// from an XML file... it is up to the game's organization.
// Since this default implementation doesn't know anything about that, it forwards the calls to each
// device until one of them succeeds.
// Disable deferred opening because devices may usually return AK_Success if io_bSyncOpen=false,
// and we count on the fact that they will return AK_Fail to select the proper device.
io_bSyncOpen = true;
AKRESULT eResult = AK_FileNotFound;
AkUInt32 uDevice = 0;
while ( uDevice < AK_MAX_IO_DEVICES
&& eResult != AK_Success )
{
if ( m_arDevices[uDevice] )
{
eResult = m_arDevices[uDevice]->Open(
in_fileID, // File ID.
in_eOpenMode, // Open mode.
in_pFlags, // Special flags. Can pass NULL.
io_bSyncOpen, // If true, the file must be opened synchronously. Otherwise it is left at the File Location Resolver's discretion. Return false if Open needs to be deferred.
out_fileDesc // Returned file descriptor.
);
AKASSERT( io_bSyncOpen || !"It is illegal to reset io_bSyncOpen" );
}
++uDevice;
}
return eResult;
}
AKRESULT CAkDefaultLowLevelIODispatcher::AddDevice(
AK::StreamMgr::IAkFileLocationResolver * in_pHook
)
{
// Add the device in a free slot.
for ( AkUInt32 uRecord = 0; uRecord < AK_MAX_IO_DEVICES; uRecord++ )
{
if ( !m_arDevices[uRecord] )
{
m_arDevices[uRecord] = in_pHook;
++m_uNumDevices;
return AK_Success;
}
}
AKASSERT( !"Cannot hold any more I/O devices" );
return AK_Fail;
}
void CAkDefaultLowLevelIODispatcher::RemoveAllDevices()
{
for ( AkUInt32 uRecord = 0; uRecord < AK_MAX_IO_DEVICES; uRecord++ )
m_arDevices[uRecord] = NULL;
m_uNumDevices = 0;
}
#endif

View file

@ -0,0 +1,84 @@
//////////////////////////////////////////////////////////////////////
//
// AkDefaultLowLevelIODispatcher.h
//
// Canvas for implementation of the AK::StreamMgr::IAkFileLocationResolver,
// meant to be used in a multiple streaming devices system. It is this
// object that should be registered as the one and only
// AK::StreamMgr::IAkFileLocationResolver of the Stream Manager
// (by calling AK::StreamMgr::SetFileLocationResolver()).
//
// It forwards the calls to Open() to one of the low level I/O devices
// that were added to it using AddDevice(). These devices must thus also
// implement AK::StreamMgr::IAkFileLocationResolver.
//
// The strategy for device dispatching is that of a chain of responsibility:
// the dispatcher asks the first file resolver hook to open the file. If it
// fails, then it tries with the second, and so on, until a hook succeeds.
// This is inefficient. In your game, you should implement a strategy of
// your own (see CAkDefaultLowLevelIODispatcher::Open()).
//
// Copyright (c) 2006 Audiokinetic Inc. / All Rights Reserved
//
//////////////////////////////////////////////////////////////////////
#ifndef _AK_DEFAULT_LOW_LEVEL_IO_DISPATCHER_H_
#define _AK_DEFAULT_LOW_LEVEL_IO_DISPATCHER_H_
#include <AK/SoundEngine/Common/AkStreamMgrModule.h>
#define AK_MAX_IO_DEVICES (3)
//-----------------------------------------------------------------------------
// Name: class CAkDefaultLowLevelIODispatcher.
// Desc: Register this object to the Stream Manager as the File Location Resolver.
// You need to implement dispatching calls to Open() to separate devices,
// according to your specific requirements.
//-----------------------------------------------------------------------------
class CAkDefaultLowLevelIODispatcher : public AK::StreamMgr::IAkFileLocationResolver
{
public:
CAkDefaultLowLevelIODispatcher( );
virtual ~CAkDefaultLowLevelIODispatcher( );
// Returns a file descriptor for a given file name (string).
virtual AKRESULT Open(
const AkOSChar* in_pszFileName, // File name.
AkOpenMode in_eOpenMode, // Open mode.
AkFileSystemFlags * in_pFlags, // Special flags. Can pass NULL.
bool & io_bSyncOpen, // If true, the file must be opened synchronously. Otherwise it is left at the File Location Resolver's discretion. Return false if Open needs to be deferred.
AkFileDesc & out_fileDesc // Returned file descriptor.
);
// Returns a file descriptor for a given file ID.
virtual AKRESULT Open(
AkFileID in_fileID, // File ID.
AkOpenMode in_eOpenMode, // Open mode.
AkFileSystemFlags * in_pFlags, // Special flags. Can pass NULL.
bool & io_bSyncOpen, // If true, the file must be opened synchronously. Otherwise it is left at the File Location Resolver's discretion. Return false if Open needs to be deferred.
AkFileDesc & out_fileDesc // Returned file descriptor.
);
//
// Default dispatcher services.
//-----------------------------------------------------------------------------
// Add a "device" (actually, a File Location Resolver) to the dispatcher's list.
// The first device added will be the first device queried.
virtual AKRESULT AddDevice(
AK::StreamMgr::IAkFileLocationResolver * in_pHook
);
// Remove all devices from the dispatcher's array.
virtual void RemoveAllDevices();
protected:
// List of devices.
AK::StreamMgr::IAkFileLocationResolver * m_arDevices[AK_MAX_IO_DEVICES];
AkUInt32 m_uNumDevices;
};
#endif //_AK_DEFAULT_LOW_LEVEL_IO_DISPATCHER_H_

View file

@ -0,0 +1,290 @@
#include "BFPlatform.h"
#ifdef BF_WWISE_ENABLED
//////////////////////////////////////////////////////////////////////
//
// AkFileLocationBase.cpp
//
// Basic file location resolving: Uses simple path concatenation logic.
// Exposes basic path functions for convenience.
// For more details on resolving file location, refer to section "File Location" inside
// "Going Further > Overriding Managers > Streaming / Stream Manager > Low-Level I/O"
// of the SDK documentation.
//
// Copyright (c) 2006 Audiokinetic Inc. / All Rights Reserved
//
//////////////////////////////////////////////////////////////////////
#include "Common.h"
#include "AkFileLocationBase.h"
#include <AK/SoundEngine/Common/AkStreamMgrModule.h>
#ifdef AK_WIN
#include <AK/Plugin/AkMP3SourceFactory.h> // For MP3 Codec ID.
#endif
#include <AK/Tools/Common/AkPlatformFuncs.h>
#ifdef AK_SUPPORT_WCHAR
#include <wchar.h>
#endif //AK_SUPPORT_WCHAR
#include <stdio.h>
#include <AK/Tools/Common/AkAssert.h>
#define MAX_NUMBER_STRING_SIZE (10) // 4G
#define ID_TO_STRING_FORMAT_BANK AKTEXT("%u.bnk")
#define ID_TO_STRING_FORMAT_WEM AKTEXT("%u.wem")
#define MAX_EXTENSION_SIZE (4) // .xxx
#define MAX_FILETITLE_SIZE (MAX_NUMBER_STRING_SIZE+MAX_EXTENSION_SIZE+1) // null-terminated
template< class TYPE > inline
const TYPE& AkTemplMax( const TYPE& in_left, const TYPE& in_right )
{
return ( in_left < in_right ) ? in_right : in_left;
}
CAkFileLocationBase::CAkFileLocationBase()
{
m_szBasePath[0] = NULL;
m_szBankPath[0] = NULL;
m_szAudioSrcPath[0] = NULL;
}
CAkFileLocationBase::~CAkFileLocationBase()
{
}
// String overload.
// Returns AK_Success if input flags are supported and the resulting path is not too long.
// Returns AK_Fail otherwise.
AKRESULT CAkFileLocationBase::GetFullFilePath(
const AkOSChar* in_pszFileName, // File name.
AkFileSystemFlags * in_pFlags, // Special flags. Can be NULL.
AkOpenMode in_eOpenMode, // File open mode (read, write, ...).
AkOSChar* out_pszFullFilePath // Full file path.
)
{
if ( !in_pszFileName )
{
AKASSERT( !"Invalid file name" );
return AK_InvalidParameter;
}
// Prepend string path (basic file system logic).
// Compute file name with file system paths.
size_t uiPathSize = AKPLATFORM::OsStrLen( in_pszFileName );
if ( uiPathSize >= AK_MAX_PATH )
{
AKASSERT( !"Input string too large" );
return AK_InvalidParameter;
}
#ifdef AK_WIN
// MP3 files using the MP3 sample code, usually being provided by the gamer will
// not be located in the game path, for these sounds, we are using the Full path
// to access them.
if ( in_pFlags != NULL &&
in_pFlags->uCodecID == AKSOURCEID_MP3 &&
in_pFlags->uCompanyID == AKCOMPANYID_AUDIOKINETIC )
{
out_pszFullFilePath[0] = 0;
}
else
#endif
{
AKPLATFORM::SafeStrCpy( out_pszFullFilePath, m_szBasePath, AK_MAX_PATH );
}
if ( in_pFlags
&& in_eOpenMode == AK_OpenModeRead )
{
// Add bank path if file is an AK sound bank.
if ( in_pFlags->uCompanyID == AKCOMPANYID_AUDIOKINETIC &&
in_pFlags->uCodecID == AKCODECID_BANK )
{
uiPathSize += AKPLATFORM::OsStrLen( m_szBankPath );
if ( uiPathSize >= AK_MAX_PATH )
{
AKASSERT( !"Path is too large" );
return AK_Fail;
}
AKPLATFORM::SafeStrCat( out_pszFullFilePath, m_szBankPath, AK_MAX_PATH );
}
// Note: Standard streaming files do not use this overload. On the other hand, streaming external
// sources use it if you use AkExternalSourceInfo::szFile instead of AkExternalSourceInfo::idFile.
// Externally supplied source (see External Sources in SDK doc)
// In this sample, we will assume that the external source file name in_pszFileName
// must be used as is (e.g. "myExternalSourceFile.wem"). If you use the External Source feature
// you should modify this section to handle your FileIDs properly.
/*if (in_pFlags->uCompanyID == AKCOMPANYID_AUDIOKINETIC_EXTERNAL)
{
}*/
// Add language directory name if needed.
if ( in_pFlags->bIsLanguageSpecific )
{
size_t uLanguageStrLen = AKPLATFORM::OsStrLen( AK::StreamMgr::GetCurrentLanguage() );
if ( uLanguageStrLen > 0 )
{
uiPathSize += ( uLanguageStrLen + 1 );
if ( uiPathSize >= AK_MAX_PATH )
{
AKASSERT( !"Path is too large" );
return AK_Fail;
}
AKPLATFORM::SafeStrCat( out_pszFullFilePath, AK::StreamMgr::GetCurrentLanguage(), AK_MAX_PATH );
AKPLATFORM::SafeStrCat( out_pszFullFilePath, AK_PATH_SEPARATOR, AK_MAX_PATH );
}
}
}
// Append file title.
uiPathSize += AKPLATFORM::OsStrLen( out_pszFullFilePath );
if ( uiPathSize >= AK_MAX_PATH )
{
AKASSERT( !"File name string too large" );
return AK_Fail;
}
AKPLATFORM::SafeStrCat( out_pszFullFilePath, in_pszFileName, AK_MAX_PATH );
return AK_Success;
}
// ID overload.
// The name of the file will be formatted as ID.ext. This is meant to be used with options
// "Use SoundBank Names" unchecked, and/or "Copy Streamed Files" in the SoundBank Settings.
// For more details, refer to the SoundBank Settings in Wwise Help, and to section "Identifying Banks" inside
// "Sound Engine Integration Walkthrough > Integrate Wwise Elements into Your Game > Integrating Banks >
// Integration Details - Banks > General Information" of the SDK documentation.
// Returns AK_Success if input flags are supported and the resulting path is not too long.
// Returns AK_Fail otherwise.
AKRESULT CAkFileLocationBase::GetFullFilePath(
AkFileID in_fileID, // File ID.
AkFileSystemFlags * in_pFlags, // Special flags.
AkOpenMode /* in_eOpenMode*/, // File open mode (read, write, ...).
AkOSChar * out_pszFullFilePath // Full file path.
)
{
// If the file descriptor could not be found, or if the script-based FS does not exist,
// map file ID to file descriptor (string based) for Audiokinetic IDs.
if ( !in_pFlags ||
!(in_pFlags->uCompanyID == AKCOMPANYID_AUDIOKINETIC || in_pFlags->uCompanyID == AKCOMPANYID_AUDIOKINETIC_EXTERNAL))
{
AKASSERT( !"Unhandled file type" );
return AK_Fail;
}
// Compute file name with file system paths.
size_t uiPathSize = AKPLATFORM::OsStrLen( m_szBasePath );
// Copy base path.
AKPLATFORM::SafeStrCpy( out_pszFullFilePath, m_szBasePath, AK_MAX_PATH );
// Concatenate path for AK banks or streamed audio files (everything except banks).
if ( in_pFlags->uCodecID == AKCODECID_BANK )
{
uiPathSize += AKPLATFORM::OsStrLen( m_szBankPath );
if ( uiPathSize >= AK_MAX_PATH )
{
AKASSERT( !"Path is too large" );
return AK_Fail;
}
AKPLATFORM::SafeStrCat( out_pszFullFilePath, m_szBankPath, AK_MAX_PATH );
}
else
{
uiPathSize += AKPLATFORM::OsStrLen( m_szAudioSrcPath );
if ( uiPathSize >= AK_MAX_PATH )
{
AKASSERT( !"Path is too large" );
return AK_Fail;
}
AKPLATFORM::SafeStrCat( out_pszFullFilePath, m_szAudioSrcPath, AK_MAX_PATH );
}
// Externally supplied source (see External Sources in SDK doc)
// In this sample, we will assume that the file to load when receiving an external FileID is
// simply the FileID.wem (e.g. "12345.wem"). If you use the External Source feature
// you should modify this section to handle your FileIDs properly.
/*if (in_pFlags->uCompanyID == AKCOMPANYID_AUDIOKINETIC_EXTERNAL)
{
}*/
// Add language directory name if needed.
if ( in_pFlags->bIsLanguageSpecific )
{
size_t uLanguageStrLen = AKPLATFORM::OsStrLen( AK::StreamMgr::GetCurrentLanguage() );
if ( uLanguageStrLen > 0 )
{
uiPathSize += ( uLanguageStrLen + 1 );
if ( uiPathSize >= AK_MAX_PATH )
{
AKASSERT( !"Path is too large" );
return AK_Fail;
}
AKPLATFORM::SafeStrCat( out_pszFullFilePath, AK::StreamMgr::GetCurrentLanguage(), AK_MAX_PATH );
AKPLATFORM::SafeStrCat( out_pszFullFilePath, AK_PATH_SEPARATOR, AK_MAX_PATH );
}
}
// Append file title.
if ( ( uiPathSize + MAX_FILETITLE_SIZE ) <= AK_MAX_PATH )
{
AkOSChar * pszTitle = out_pszFullFilePath + uiPathSize;
if ( in_pFlags->uCodecID == AKCODECID_BANK )
AK_OSPRINTF( pszTitle, MAX_FILETITLE_SIZE, ID_TO_STRING_FORMAT_BANK, (unsigned int)in_fileID );
else
AK_OSPRINTF( pszTitle, MAX_FILETITLE_SIZE, ID_TO_STRING_FORMAT_WEM, (unsigned int)in_fileID );
}
else
{
AKASSERT( !"String buffer too small" );
return AK_Fail;
}
return AK_Success;
}
AKRESULT CAkFileLocationBase::SetBasePath(
const AkOSChar* in_pszBasePath
)
{
if ( AKPLATFORM::OsStrLen( in_pszBasePath ) + AkTemplMax( AKPLATFORM::OsStrLen( m_szBankPath ), AKPLATFORM::OsStrLen( m_szAudioSrcPath ) ) + AKPLATFORM::OsStrLen( AK::StreamMgr::GetCurrentLanguage() ) + 1 >= AK_MAX_PATH )
{
return AK_InvalidParameter;
}
AKPLATFORM::SafeStrCpy( m_szBasePath, in_pszBasePath, AK_MAX_PATH );
return AK_Success;
}
AKRESULT CAkFileLocationBase::SetBankPath(
const AkOSChar* in_pszBankPath
)
{
if ( AKPLATFORM::OsStrLen( m_szBasePath ) + AkTemplMax( AKPLATFORM::OsStrLen( in_pszBankPath ), AKPLATFORM::OsStrLen( m_szAudioSrcPath ) ) + AKPLATFORM::OsStrLen( AK::StreamMgr::GetCurrentLanguage() ) + 1 >= AK_MAX_PATH )
{
return AK_InvalidParameter;
}
AKPLATFORM::SafeStrCpy( m_szBankPath, in_pszBankPath, AK_MAX_PATH );
return AK_Success;
}
AKRESULT CAkFileLocationBase::SetAudioSrcPath(
const AkOSChar* in_pszAudioSrcPath
)
{
if ( AKPLATFORM::OsStrLen( m_szBasePath ) + AkTemplMax( AKPLATFORM::OsStrLen( m_szBankPath ), AKPLATFORM::OsStrLen( in_pszAudioSrcPath ) ) + AKPLATFORM::OsStrLen( AK::StreamMgr::GetCurrentLanguage() ) + 1 >= AK_MAX_PATH )
{
return AK_InvalidParameter;
}
AKPLATFORM::SafeStrCpy( m_szAudioSrcPath, in_pszAudioSrcPath, AK_MAX_PATH );
return AK_Success;
}
#endif

View file

@ -0,0 +1,85 @@
//////////////////////////////////////////////////////////////////////
//
// AkFileLocationBase.h
//
// Basic file location resolving: Uses simple path concatenation logic.
// Exposes basic path functions for convenience.
// For more details on resolving file location, refer to section "File Location" inside
// "Going Further > Overriding Managers > Streaming / Stream Manager > Low-Level I/O"
// of the SDK documentation.
//
// Copyright (c) 2006 Audiokinetic Inc. / All Rights Reserved
//
//////////////////////////////////////////////////////////////////////
#ifndef _AK_FILE_LOCATION_BASE_H_
#define _AK_FILE_LOCATION_BASE_H_
struct AkFileSystemFlags;
#include <AK/SoundEngine/Common/IAkStreamMgr.h>
class CAkFileLocationBase
{
public:
CAkFileLocationBase();
virtual ~CAkFileLocationBase();
//
// Global path functions.
// ------------------------------------------------------
// Base path is prepended to all file names.
// Audio source path is appended to base path whenever uCompanyID is AK and uCodecID specifies an audio source.
// Bank path is appended to base path whenever uCompanyID is AK and uCodecID specifies a sound bank.
// Language specific dir name is appended to path whenever "bIsLanguageSpecific" is true.
AKRESULT SetBasePath(
const AkOSChar* in_pszBasePath
);
AKRESULT SetBankPath(
const AkOSChar* in_pszBankPath
);
AKRESULT SetAudioSrcPath(
const AkOSChar* in_pszAudioSrcPath
);
// Note: SetLangSpecificDirName() does not exist anymore. See release note WG-19397 (Wwise 2011.2).
//
// Path resolving services.
// ------------------------------------------------------
// String overload.
// Returns AK_Success if input flags are supported and the resulting path is not too long.
// Returns AK_Fail otherwise.
AKRESULT GetFullFilePath(
const AkOSChar * in_pszFileName, // File name.
AkFileSystemFlags * in_pFlags, // Special flags. Can be NULL.
AkOpenMode in_eOpenMode, // File open mode (read, write, ...).
AkOSChar * out_pszFullFilePath // Full file path.
);
// ID overload.
// The name of the file will be formatted as ID.ext. This is meant to be used with options
// "Use SoundBank Names" unchecked, and/or "Copy Streamed Files" in the SoundBank Settings.
// For more details, refer to the SoundBank Settings in Wwise Help, and to section "Identifying Banks" inside
// "Sound Engine Integration Walkthrough > Integrate Wwise Elements into Your Game > Integrating Banks >
// Integration Details - Banks > General Information" of the SDK documentation.
// Returns AK_Success if input flags are supported and the resulting path is not too long.
// Returns AK_Fail otherwise.
AKRESULT GetFullFilePath(
AkFileID in_fileID, // File ID.
AkFileSystemFlags * in_pFlags, // Special flags.
AkOpenMode in_eOpenMode, // File open mode (read, write, ...).
AkOSChar * out_pszFullFilePath // Full file path.
);
protected:
// Internal user paths.
AkOSChar m_szBasePath[AK_MAX_PATH];
AkOSChar m_szBankPath[AK_MAX_PATH];
AkOSChar m_szAudioSrcPath[AK_MAX_PATH];
};
#endif //_AK_FILE_LOCATION_BASE_H_

View file

@ -0,0 +1,67 @@
#include "BFPlatform.h"
#ifdef BF_WWISE_ENABLED
//////////////////////////////////////////////////////////////////////
//
// AkFilePackage.h
//
// This class represents a file package that was created with the
// AkFilePackager utility app (located in ($WWISESDK)/samples/FilePackager/).
// It holds a system file handle and a look-up table (CAkFilePackageLUT).
//
// CAkFilePackage objects can be chained together using the ListFilePackages
// typedef defined below.
//
// Copyright (c) 2007-2009 Audiokinetic Inc. / All Rights Reserved
//
//////////////////////////////////////////////////////////////////////
#include "Common.h"
#include "AkFilePackage.h"
// Destroy file package and free memory / destroy pool.
void CAkFilePackage::Destroy()
{
// Cache memory pointer and pool ID because memory pool is destroyed _after_ deleting this.
AkMemPoolId poolID = m_poolID;
void * pToRelease = m_pToRelease;
bool bIsInternalPool = m_bIsInternalPool;
// Call destructor.
this->~CAkFilePackage();
// Free memory.
ClearMemory( poolID, pToRelease, bIsInternalPool );
}
void CAkFilePackage::ClearMemory(
AkMemPoolId in_poolID, // Pool to destroy.
void * in_pMemToRelease, // Memory block to free before destroying pool.
bool in_bIsInternalPool // Pool was created internally (and needs to be destroyed).
)
{
if ( in_poolID != AK_INVALID_POOL_ID )
{
if ( in_pMemToRelease )
{
if ( in_bIsInternalPool )
{
AK::MemoryMgr::ReleaseBlock( in_poolID, in_pMemToRelease );
// Destroy pool
AKVERIFY( AK::MemoryMgr::DestroyPool( in_poolID ) == AK_Success );
}
else
{
if ( AK::MemoryMgr::GetPoolAttributes( in_poolID ) & AkBlockMgmtMask )
AK::MemoryMgr::ReleaseBlock( in_poolID, in_pMemToRelease );
else
AkFree( in_poolID, in_pMemToRelease );
}
}
else
AKASSERT( !in_bIsInternalPool ); // Internal pools allocation is guaranteed.
}
}
#endif

View file

@ -0,0 +1,171 @@
//////////////////////////////////////////////////////////////////////
//
// AkFilePackage.h
//
// This class represents a file package that was created with the
// AkFilePackager utility app (located in ($WWISESDK)/samples/FilePackager/).
// It holds a system file handle and a look-up table (CAkFilePackageLUT).
//
// CAkFilePackage objects can be chained together using the ListFilePackages
// typedef defined below.
//
// Copyright (c) 2007-2009 Audiokinetic Inc. / All Rights Reserved
//
//////////////////////////////////////////////////////////////////////
#ifndef _AK_FILE_PACKAGE_H_
#define _AK_FILE_PACKAGE_H_
#include "AkFilePackageLUT.h"
#include <AK/SoundEngine/Common/AkSoundEngine.h>
#include <AK/Tools/Common/AkObject.h>
#include <AK/Tools/Common/AkListBare.h>
//-----------------------------------------------------------------------------
// Name: Base class for items that can be chained in AkListBareLight lists.
//-----------------------------------------------------------------------------
template<class T>
class CAkListAware
{
public:
CAkListAware()
: pNextItem( NULL ) {}
struct AkListNextItem
{
static AkForceInline T *& Get( T * in_pItem )
{
return in_pItem->pNextItem;
}
};
T * pNextItem;
};
//-----------------------------------------------------------------------------
// Name: CAkFilePackage
// Desc: Base class representing a file package (incomplete implementation).
// It holds a look-up table (CAkFilePackageLUT) and manages memory for the LUT and
// for itself.
//-----------------------------------------------------------------------------
class CAkFilePackage : public CAkListAware<CAkFilePackage>
{
public:
// Package factory.
// Creates a memory pool to contain the header of the file package and this object.
// Returns its address.
template<class T_PACKAGE>
static T_PACKAGE * Create(
const AkOSChar* in_pszPackageName, // Name of the file package (for memory monitoring and ID generation).
AkMemPoolId in_memPoolID, // Memory pool in which the package is created with its lookup table.
AkUInt32 in_uHeaderSize, // File package header size, including the size of the header chunk AKPK_HEADER_CHUNK_DEF_SIZE.
AkUInt32 in_uBlockAlign, // Alignment of memory block.
AkUInt32 & out_uReservedHeaderSize, // Size reserved for header, taking mem align into account.
AkUInt8 *& out_pHeaderBuffer // Returned address of memory for header.
)
{
AKASSERT( in_uHeaderSize > 0 );
out_pHeaderBuffer = NULL;
// Create memory pool and copy header.
// The pool must be big enough to hold both the buffer for the LUT's header
// and a CAkFilePackage object.
bool bIsInternalPool;
AkUInt8 * pToRelease = NULL;
out_uReservedHeaderSize = ( ( in_uHeaderSize + in_uBlockAlign - 1 ) / in_uBlockAlign ) * in_uBlockAlign;
AkUInt32 uMemSize = out_uReservedHeaderSize + sizeof( T_PACKAGE );
if ( in_memPoolID == AK_DEFAULT_POOL_ID )
{
in_memPoolID = AK::MemoryMgr::CreatePool( NULL, uMemSize, uMemSize, AkMalloc | AkFixedSizeBlocksMode, in_uBlockAlign );
if ( in_memPoolID == AK_INVALID_POOL_ID )
return NULL;
AK_SETPOOLNAME( in_memPoolID, in_pszPackageName );
bIsInternalPool = true;
pToRelease = (AkUInt8*)AK::MemoryMgr::GetBlock( in_memPoolID );
AKASSERT( pToRelease );
}
else
{
// Shared pool.
bIsInternalPool = false;
AKRESULT eResult = AK::MemoryMgr::CheckPoolId( in_memPoolID );
if ( eResult == AK_Success )
{
if ( AK::MemoryMgr::GetPoolAttributes( in_memPoolID ) & AkBlockMgmtMask )
{
if ( AK::MemoryMgr::GetBlockSize( in_memPoolID ) >= uMemSize )
pToRelease = (AkUInt8*)AK::MemoryMgr::GetBlock( in_memPoolID );
}
else
pToRelease = (AkUInt8*)AkAlloc( in_memPoolID, uMemSize );
}
}
if ( !pToRelease )
return NULL;
// Generate an ID.
AkUInt32 uPackageID = AK::SoundEngine::GetIDFromString( in_pszPackageName );
// Construct a CAkFilePackage at the end of this memory region.
T_PACKAGE * pFilePackage = AkPlacementNew( pToRelease + out_uReservedHeaderSize ) T_PACKAGE( uPackageID, in_uHeaderSize, in_memPoolID, pToRelease, bIsInternalPool );
AKASSERT( pFilePackage ); // Must succeed.
out_pHeaderBuffer = pToRelease;
return pFilePackage;
}
// Destroy file package and free memory / destroy pool.
virtual void Destroy();
// Getters.
inline AkUInt32 ID() { return m_uPackageID; }
inline AkUInt32 HeaderSize() { return m_uHeaderSize; }
inline AkUInt32 ExternalPool() { return ( !m_bIsInternalPool ) ? m_poolID : AK_DEFAULT_POOL_ID; }
// Members.
// ------------------------------
CAkFilePackageLUT lut; // Package look-up table.
protected:
AkUInt32 m_uPackageID;
AkUInt32 m_uHeaderSize;
// ------------------------------
protected:
// Private constructors: users should use Create().
CAkFilePackage();
CAkFilePackage(CAkFilePackage&);
CAkFilePackage( AkUInt32 in_uPackageID, AkUInt32 in_uHeaderSize, AkMemPoolId in_poolID, void * in_pToRelease, bool in_bIsInternalPool )
: m_uPackageID( in_uPackageID )
, m_uHeaderSize( in_uHeaderSize )
, m_poolID( in_poolID )
, m_pToRelease( in_pToRelease )
, m_bIsInternalPool( in_bIsInternalPool )
{
}
virtual ~CAkFilePackage() {}
// Helper.
static void ClearMemory(
AkMemPoolId in_poolID, // Pool to destroy.
void * in_pMemToRelease, // Memory block to free before destroying pool.
bool in_bIsInternalPool // Pool was created internally (and needs to be destroyed).
);
protected:
// Memory management.
AkMemPoolId m_poolID; // Memory pool for LUT.
void * m_pToRelease; // LUT storage (only keep this pointer to release memory).
bool m_bIsInternalPool; // True if pool was created by package, false if shared.
};
//-----------------------------------------------------------------------------
// Name: ListFilePackages
// Desc: AkListBare of CAkFilePackage items.
//-----------------------------------------------------------------------------
typedef AkListBare<CAkFilePackage,CAkListAware<CAkFilePackage>::AkListNextItem,AkCountPolicyWithCount> ListFilePackages;
#endif //_AK_FILE_PACKAGE_H_

View file

@ -0,0 +1,274 @@
#include "BFPlatform.h"
#ifdef BF_WWISE_ENABLED
//////////////////////////////////////////////////////////////////////
//
// AkFilePackageLUT.cpp
//
// This class parses the header of file packages that were created with the
// AkFilePackager utility app (located in ($WWISESDK)/samples/FilePackager/),
// and looks-up files at run-time.
//
// The header of these file packages contains look-up tables that describe the
// internal offset of each file it references, their block size (required alignment),
// and their language. Each combination of AkFileID and Language ID is unique.
//
// The language was created dynamically when the package was created. The header
// also contains a map of language names (strings) to their ID, so that the proper
// language-specific version of files can be resolved. The language name that is stored
// matches the name of the directory that is created by the Wwise Bank Manager,
// except for the trailing slash.
//
// Copyright (c) 2007-2009 Audiokinetic Inc. / All Rights Reserved
//
//////////////////////////////////////////////////////////////////////
#include "Common.h"
#include "AkFilePackageLUT.h"
#include <AK/SoundEngine/Common/AkMemoryMgr.h>
#include <AK/SoundEngine/Common/AkSoundEngine.h> // For string hash.
#include <AK/Tools/Common/AkPlatformFuncs.h>
#include <AK/Tools/Common/AkFNVHash.h>
#ifdef _DEBUG
template<bool> struct AkCompileTimeAssert;
template<> struct AkCompileTimeAssert<true> { };
#define AK_STATIC_ASSERT(e) (AkCompileTimeAssert<(e) != 0>())
#else
#define AK_STATIC_ASSERT(e)
#endif
#define AK_MAX_EXTERNAL_NAME_SIZE 260
CAkFilePackageLUT::CAkFilePackageLUT()
:m_curLangID( AK_INVALID_LANGUAGE_ID )
,m_pLangMap( NULL )
,m_pSoundBanks( NULL )
,m_pStmFiles( NULL )
,m_pExternals( NULL )
{
AK_STATIC_ASSERT(sizeof(AkFileEntry<AkFileID>) == 20);
AK_STATIC_ASSERT(sizeof(AkFileEntry<AkUInt64>) == 24);
}
CAkFilePackageLUT::~CAkFilePackageLUT()
{
}
// Create a new LUT from a packaged file header.
// The LUT sets pointers to appropriate location inside header data (in_pData).
AKRESULT CAkFilePackageLUT::Setup(
AkUInt8 * in_pData, // Header data.
AkUInt32 in_uHeaderSize // Size of file package header.
)
{
struct FileHeaderFormat
{
char headerDefinition[AKPK_HEADER_CHUNK_DEF_SIZE];
AkUInt32 uVersion;
AkUInt32 uLanguageMapSize;
AkUInt32 uSoundBanksLUTSize;
AkUInt32 uStmFilesLUTSize;
AkUInt32 uExternalsLUTSize;
};
FileHeaderFormat * pHeader = (FileHeaderFormat*)in_pData;
// Check header size,
if ( in_uHeaderSize < sizeof(FileHeaderFormat)
+ pHeader->uLanguageMapSize
+ pHeader->uSoundBanksLUTSize
+ pHeader->uStmFilesLUTSize
+ pHeader->uExternalsLUTSize)
{
return AK_Fail;
}
// Check version.
if ( pHeader->uVersion < AKPK_CURRENT_VERSION )
return AK_Fail;
// Get address of maps and LUTs.
in_pData += sizeof(FileHeaderFormat);
m_pLangMap = (StringMap*)in_pData;
in_pData += pHeader->uLanguageMapSize;
m_pSoundBanks = (FileLUT<AkFileID>*)in_pData;
in_pData += pHeader->uSoundBanksLUTSize;
m_pStmFiles = (FileLUT<AkFileID>*)in_pData;
in_pData += pHeader->uStmFilesLUTSize;
m_pExternals = (FileLUT<AkUInt64>*)in_pData;
return AK_Success;
}
// Find a file entry by ID.
const CAkFilePackageLUT::AkFileEntry<AkFileID> * CAkFilePackageLUT::LookupFile(
AkFileID in_uID, // File ID.
AkFileSystemFlags * in_pFlags // Special flags. Do not pass NULL.
)
{
AKASSERT( in_pFlags && in_pFlags->uCompanyID == AKCOMPANYID_AUDIOKINETIC );
if ( in_pFlags->uCodecID == AKCODECID_BANK
&& m_pSoundBanks
&& m_pSoundBanks->HasFiles() )
{
return LookupFile<AkFileID>( in_uID, m_pSoundBanks, in_pFlags->bIsLanguageSpecific );
}
else if ( m_pStmFiles && m_pStmFiles->HasFiles() )
{
// We assume that the file is a streamed audio file.
return LookupFile<AkFileID>( in_uID, m_pStmFiles, in_pFlags->bIsLanguageSpecific );
}
// No table loaded.
return NULL;
}
// Find a file entry by ID.
const CAkFilePackageLUT::AkFileEntry<AkUInt64> * CAkFilePackageLUT::LookupFile(
AkUInt64 in_uID, // File ID.
AkFileSystemFlags * in_pFlags // Special flags. Do not pass NULL.
)
{
AKASSERT( in_pFlags );
if ( in_pFlags->uCompanyID == AKCOMPANYID_AUDIOKINETIC_EXTERNAL
&& m_pExternals
&& m_pExternals->HasFiles() )
{
return LookupFile<AkUInt64>( in_uID, m_pExternals, in_pFlags->bIsLanguageSpecific );
}
// No table loaded.
return NULL;
}
// Set current language.
// Returns AK_InvalidLanguage if a package is loaded but the language string cannot be found.
// Returns AK_Success otherwise.
AKRESULT CAkFilePackageLUT::SetCurLanguage(
const AkOSChar* in_pszLanguage // Language string.
)
{
m_curLangID = AK_INVALID_LANGUAGE_ID;
if ( m_pLangMap && in_pszLanguage )
{
AkUInt16 uLangID = (AkUInt16)m_pLangMap->GetID( in_pszLanguage );
if ( uLangID == AK_INVALID_UNIQUE_ID
&& m_pLangMap->GetNumStrings() > 1 ) // Do not return AK_InvalidLanguage if package contains only SFX data.
{
return AK_InvalidLanguage;
}
m_curLangID = uLangID;
}
return AK_Success;
}
void CAkFilePackageLUT::RemoveFileExtension( AkOSChar* in_pstring )
{
while( *in_pstring != 0 )
{
if( *in_pstring == AKTEXT('.') )
{
*in_pstring = 0;
return;
}
++in_pstring;
}
}
// Find a soundbank ID by its name.
// Returns AK_INVALID_FILE_ID if no soundbank LUT is loaded.
AkFileID CAkFilePackageLUT::GetSoundBankID(
const AkOSChar* in_pszBankName // Soundbank name.
)
{
// Remove the file extension if it was used.
AkUInt32 stringSize = (AkUInt32)AKPLATFORM::OsStrLen( in_pszBankName ) + 1;
AkOSChar* pStringWithoutExtension = (AkOSChar *)AkAlloca( (stringSize) * sizeof( AkOSChar ) );
AKPLATFORM::SafeStrCpy( pStringWithoutExtension, in_pszBankName, stringSize );
RemoveFileExtension( pStringWithoutExtension );
// Hash
return AK::SoundEngine::GetIDFromString( pStringWithoutExtension );
}
AkUInt64 CAkFilePackageLUT::GetExternalID(
const AkOSChar* in_pszExternalName // External Source name.
)
{
char* szString;
CONVERT_OSCHAR_TO_CHAR(in_pszExternalName, szString);
size_t stringSize = strlen( szString );
// 1- Make lower case.
_MakeLowerA( szString, stringSize );
AK::FNVHash64 MainHash;
return MainHash.Compute( (const unsigned char *) szString, (unsigned int)stringSize );
}
void CAkFilePackageLUT::_MakeLowerA( char* in_pString, size_t in_strlen )
{
for( size_t i = 0; i < in_strlen; ++i )
{
if( in_pString[i] >= 'A' && in_pString[i] <= 'Z' )
{
in_pString[i] += 0x20;
}
}
}
void CAkFilePackageLUT::_MakeLower( AkOSChar* in_pString )
{
size_t uStrlen = AKPLATFORM::OsStrLen( in_pString );
const AkOSChar CaseDiff = AKTEXT('a') - AKTEXT('A');
for( size_t i = 0; i < uStrlen; ++i )
{
if( in_pString[i] >= AKTEXT('A') && in_pString[i] <= AKTEXT('Z') )
{
in_pString[i] += CaseDiff;
}
}
}
AkUInt32 CAkFilePackageLUT::StringMap::GetID( const AkOSChar* in_pszString )
{
// Make string lower case.
size_t uStrLen = AKPLATFORM::OsStrLen(in_pszString)+1;
AkOSChar * pszLowerCaseString = (AkOSChar*)AkAlloca(uStrLen*sizeof(AkOSChar));
AKASSERT( pszLowerCaseString );
AKPLATFORM::SafeStrCpy(pszLowerCaseString, in_pszString, uStrLen );
_MakeLower( pszLowerCaseString );
// 'this' is m_uNumStrings. +1 points to the beginning of the StringEntry array.
StringEntry * pTable = (StringEntry*)((AkUInt32*)this + 1);
// Binary search: strings are sorted (case sensitive).
AkInt32 uTop = 0, uBottom = m_uNumStrings-1;
do
{
AkInt32 uThis = ( uBottom - uTop ) / 2 + uTop;
AkOSChar * pString = (AkOSChar*)((AkUInt8*)this + pTable[ uThis ].uOffset);
int iCmp = AKPLATFORM::OsStrCmp( pString, pszLowerCaseString );
if ( 0 == iCmp )
return pTable[uThis].uID;
else if ( iCmp > 0 ) //in_pTable[ uThis ].pString > pszLowerCaseString
uBottom = uThis - 1;
else //in_pTable[ uThis ].pString < pszLowerCaseString
uTop = uThis + 1;
}
while ( uTop <= uBottom );
// ID not found.
return AK_INVALID_UNIQUE_ID;
}
#endif

View file

@ -0,0 +1,207 @@
//////////////////////////////////////////////////////////////////////
//
// AkFilePackageLUT.h
//
// This class parses the header of file packages that were created with the
// AkFilePackager utility app (located in ($WWISESDK)/samples/FilePackager/),
// and looks-up files at run-time.
//
// The header of these file packages contains look-up tables that describe the
// internal offset of each file it references, their block size (required alignment),
// and their language. Each combination of AkFileID and Language ID is unique.
//
// The language was created dynamically when the package was created. The header
// also contains a map of language names (strings) to their ID, so that the proper
// language-specific version of files can be resolved. The language name that is stored
// matches the name of the directory that is created by the Wwise Bank Manager,
// except for the trailing slash.
//
// Copyright (c) 2007-2009 Audiokinetic Inc. / All Rights Reserved
//
//////////////////////////////////////////////////////////////////////
#ifndef _AK_FILE_PACKAGE_LUT_H_
#define _AK_FILE_PACKAGE_LUT_H_
#include <AK/SoundEngine/Common/IAkStreamMgr.h>
#include <AK/Tools/Common/AkAssert.h>
// AK file packager definitions.
#define AKPK_CURRENT_VERSION (1)
#define AKPK_HEADER_CHUNK_DEF_SIZE (8) // The header chunk definition is 8 bytes wide.
#define AKPK_FILE_FORMAT_TAG \
AkmmioFOURCC('A','K','P','K')
//-----------------------------------------------------------------------------
// Name: class CAkFilePackageLUT.
// Desc: Keeps pointers to various parts of the header. Offers look-up services
// for file look-up and soundbank ID retrieval.
//-----------------------------------------------------------------------------
class CAkFilePackageLUT
{
public:
static const AkUInt16 AK_INVALID_LANGUAGE_ID = 0;
// Ensure no padding is done because this structure is mapped to file content
#pragma pack(push, 4)
template <class T_FILEID>
struct AkFileEntry
{
T_FILEID fileID; // File identifier.
AkUInt32 uBlockSize; // Size of one block, required alignment (in bytes).
AkUInt32 uFileSize; // File size in bytes.
AkUInt32 uStartBlock;// Start block, expressed in terms of uBlockSize.
AkUInt32 uLanguageID;// Language ID. AK_INVALID_LANGUAGE_ID if not language-specific.
};
#pragma pack(pop)
CAkFilePackageLUT();
virtual ~CAkFilePackageLUT();
// Create a new LUT from a packaged file header.
// The LUT sets pointers to appropriate location inside header data (in_pData).
AKRESULT Setup(
AkUInt8 * in_pData, // Header data.
AkUInt32 in_uHeaderSize // Size of file package header.
);
// Find a file entry by ID.
const AkFileEntry<AkFileID> * LookupFile(
AkFileID in_uID, // File ID.
AkFileSystemFlags * in_pFlags // Special flags. Do not pass NULL.
);
// Find a file entry by ID with 64 bit ID.
const AkFileEntry<AkUInt64> * LookupFile(
AkUInt64 in_uID, // File ID.
AkFileSystemFlags * in_pFlags // Special flags. Do not pass NULL.
);
// Set current language.
// Returns AK_InvalidLanguage if a package is loaded but the language string cannot be found.
// Returns AK_Success otherwise.
AKRESULT SetCurLanguage(
const AkOSChar* in_pszLanguage // Language string.
);
// Find a soundbank ID by its name (by hashing its name)
AkFileID GetSoundBankID(
const AkOSChar* in_pszBankName // Soundbank name.
);
// Return the id of an external file (by hashing its name in 64 bits)
AkUInt64 GetExternalID(
const AkOSChar* in_pszExternalName // External Source name.
);
protected:
static void RemoveFileExtension( AkOSChar* in_pstring );
static void _MakeLower( AkOSChar* in_pString );
static void _MakeLowerA( char* in_pString, size_t in_strlen );
static AkUInt64 _MakeLowerAndHash64( char* in_pszString );
static AkUInt64 GetID64FromString( const char* in_pszString );
static AkUInt64 GetID64FromString( const wchar_t* in_pszString );
//
// File LUTs.
//
template <class T_FILEID>
class FileLUT
{
public:
const AkFileEntry<T_FILEID> * FileEntries() const { return (AkFileEntry<T_FILEID>*)((AkUInt32*)this + 1); }
bool HasFiles() const { return ( m_uNumFiles > 0 ); }
AkUInt32 NumFiles() const { return m_uNumFiles; }
private:
FileLUT(); // Do not create this object, just cast raw data.
AkUInt32 m_uNumFiles;
};
// Helper: Find a file entry by ID.
template <class T_FILEID>
const AkFileEntry<T_FILEID> * LookupFile(
T_FILEID in_uID, // File ID.
const FileLUT<T_FILEID> * in_pLut, // LUT to search.
bool in_bIsLanguageSpecific // True: match language ID.
);
private:
AkUInt16 m_curLangID; // Current language.
//
// Maps format.
//
class StringMap
{
public:
// Returns AK_INVALID_UNIQUE_ID if ID is not found.
AkUInt32 GetID( const AkOSChar* in_pszString );
inline AkUInt32 GetNumStrings() { return m_uNumStrings; }
private:
struct StringEntry
{
AkUInt32 uOffset; // Byte offset of the string in the packaged strings section,
// from beginning of the string map.
AkUInt32 uID; // ID.
};
StringMap(); // Do not create this object, just cast raw data to use GetID().
AkUInt32 m_uNumStrings;
};
// Languages map.
StringMap * m_pLangMap;
// SoundBanks LUT.
FileLUT<AkFileID> * m_pSoundBanks;
// StreamedFiles LUT.
FileLUT<AkFileID> * m_pStmFiles;
// External Sources LUT.
FileLUT<AkUInt64> * m_pExternals;
};
// Helper: Find a file entry by ID.
template <class T_FILEID>
const CAkFilePackageLUT::AkFileEntry<T_FILEID> * CAkFilePackageLUT::LookupFile(
T_FILEID in_uID, // File ID.
const FileLUT<T_FILEID> * in_pLut, // LUT to search.
bool in_bIsLanguageSpecific // True: match language ID.
)
{
const AkFileEntry<T_FILEID> * pTable = in_pLut->FileEntries();
AKASSERT( pTable && in_pLut->HasFiles() );
AkUInt16 uLangID = in_bIsLanguageSpecific ? m_curLangID : AK_INVALID_LANGUAGE_ID;
// Binary search. LUT items should be sorted by fileID, then by language ID.
AkInt32 uTop = 0, uBottom = in_pLut->NumFiles()-1;
do
{
AkInt32 uThis = ( uBottom - uTop ) / 2 + uTop;
if ( pTable[ uThis ].fileID > in_uID )
uBottom = uThis - 1;
else if ( pTable[ uThis ].fileID < in_uID )
uTop = uThis + 1;
else
{
// Correct ID. Check language.
if ( pTable[ uThis ].uLanguageID > uLangID )
uBottom = uThis - 1;
else if ( pTable[ uThis ].uLanguageID < uLangID )
uTop = uThis + 1;
else
return pTable + uThis;
}
}
while ( uTop <= uBottom );
return NULL;
}
#endif //_AK_FILE_PACKAGE_LUT_H_

View file

@ -0,0 +1,399 @@
//////////////////////////////////////////////////////////////////////
//
// AkFilePackageLowLevelIO.h
//
// CAkFilePackageLowLevelIO extends a Low-Level I/O device by providing
// the ability to reference files that are part of a file package.
//
// It can extend either blocking or deferred I/O hooks (both inheriting from
// AK::StreamMgr::IAkLowLevelIOHook), since its base class is templated.
// In either case, the base class must also implement
// AK::StreamMgr::IAkFileLocationResolver. This interface defines both overloads
// for Open(), and this is where the package's look-up table is searched.
// If no match is found, then it falls back on the base implementation.
//
// Clients of devices that use this class' functionnality simply need to call
// LoadFilePackage(), which loads and parses file packages that were created with
// the AkFilePackager utility app (located in ($WWISESDK)/samples/FilePackager/).
// The header of these file packages contains look-up tables that describe the
// internal offset of each file it references, their block size (required alignment),
// and their language. Each combination of AkFileID and Language ID is unique.
//
// LoadFilePackage() returns a package ID that can be used to unload it. Any number
// of packages can be loaded simultaneously. When Open() is called, the last package
// loaded is searched first, then the previous one, and so on.
//
// The language ID was created dynamically when the package was created. The header
// also contains a map of language names (strings) to their ID, so that the proper
// language-specific version of files can be resolved. The language name that is stored
// matches the name of the directory that is created by the Wwise Bank Manager,
// except for the trailing slash.
//
// The type of package is also a template argument. By default, it is a disk package
// (see AkDiskPackage.h).
//
// Copyright (c) 2006 Audiokinetic Inc. / All Rights Reserved
//
//////////////////////////////////////////////////////////////////////
#ifndef _AK_FILE_PACKAGE_LOW_LEVEL_IO_H_
#define _AK_FILE_PACKAGE_LOW_LEVEL_IO_H_
#include <AK/SoundEngine/Common/AkStreamMgrModule.h>
#include "AkFilePackage.h"
//-----------------------------------------------------------------------------
// Name: AkFilePackageReader
// Desc: This class wraps an AK::IAkStdStream to read a file package.
//-----------------------------------------------------------------------------
class AkFilePackageReader
{
public:
AkFilePackageReader()
: m_pStream( NULL ), m_uBlockSize( 0 ) {}
~AkFilePackageReader()
{
// IMPORTANT: Do not close file. This object can be copied.
}
AKRESULT Open(
const AkOSChar* in_pszFilePackageName, // File package name. Location is resolved using base class' Open().
bool in_bReadFromSFXOnlyDir // If true, the file package is opened from the language agnostic directory only. Otherwise, it tries to open it
// from the current language-specific directory first, and then from the common directory if it fails, similarly to the soundbanks loader of the Sound Engine (Default).
)
{
AkFileSystemFlags flags;
flags.uCompanyID = AKCOMPANYID_AUDIOKINETIC;
flags.uCodecID = AKCODECID_FILE_PACKAGE;
flags.uCustomParamSize = 0;
flags.pCustomParam = NULL;
flags.bIsLanguageSpecific = !in_bReadFromSFXOnlyDir;
flags.bIsFromRSX = false;
AKRESULT eResult = AK::IAkStreamMgr::Get()->CreateStd(
in_pszFilePackageName,
&flags,
AK_OpenModeRead,
m_pStream,
true );
if ( eResult != AK_Success
&& !in_bReadFromSFXOnlyDir )
{
// Try again, in SFX-only directory.
flags.bIsLanguageSpecific = false;
eResult = AK::IAkStreamMgr::Get()->CreateStd(
in_pszFilePackageName,
&flags,
AK_OpenModeRead,
m_pStream,
true );
}
return eResult;
}
AKRESULT Read(
void * in_pBuffer, // Buffer. Must be aligned with value returned by GetBlockSize().
AkUInt32 in_uSizeToRead, // Size to read. Must be a multiple of value returned by GetBlockSize().
AkUInt32 & out_uSizeRead, // Returned size read.
AkPriority in_priority = AK_DEFAULT_PRIORITY, // Priority heuristic.
AkReal32 in_fThroughput = 0 // Throughput heuristic. 0 means "not set", and results in "immediate".
)
{
AKASSERT( m_pStream );
AkReal32 fDeadline = ( in_fThroughput > 0 ) ? in_uSizeToRead / in_fThroughput : 0;
return m_pStream->Read(
in_pBuffer,
in_uSizeToRead,
true,
in_priority,
fDeadline,
out_uSizeRead );
}
AKRESULT Seek(
AkUInt32 in_uPosition,
AkUInt32 & out_uRealOffset
)
{
AkInt64 iRealOffset;
AKRESULT eResult = m_pStream->SetPosition( in_uPosition, AK_MoveBegin, &iRealOffset );
AKASSERT( eResult == AK_Success || !"Failed changing stream position" );
out_uRealOffset = (AkUInt32)iRealOffset;
return eResult;
}
void Close()
{
if ( m_pStream )
m_pStream->Destroy();
m_pStream = NULL;
}
void SetName(
const AkOSChar*
#ifndef AK_OPTIMIZED
in_pszName
#endif
)
{
#ifndef AK_OPTIMIZED
AKASSERT( m_pStream );
m_pStream->SetStreamName( in_pszName );
#endif
}
AkUInt64 GetSize()
{
AKASSERT( m_pStream );
AkStreamInfo info;
m_pStream->GetInfo( info );
return info.uSize;
}
AkUInt32 GetBlockSize()
{
AKASSERT( m_pStream );
// AK::IAkStdStream::GetBlockSize() is costly. Cache block size.
if ( !m_uBlockSize )
m_uBlockSize = m_pStream->GetBlockSize();
return m_uBlockSize;
}
AkFileHandle GetHandle()
{
AKASSERT( m_pStream );
AkFileDesc * pFileDesc = (AkFileDesc*)m_pStream->GetFileDescriptor();
AKASSERT( pFileDesc );
return pFileDesc->hFile;
}
private:
AK::IAkStdStream * m_pStream;
AkUInt32 m_uBlockSize;
};
//-----------------------------------------------------------------------------
// Name: CAkDiskPackage
// Desc: This class extends the CAkFilePackage class by providing system handle
// management.
// It keeps a copy of the file package reader that was used to read the file package
// header from disk, and uses it to query and cache its low-level system handle
// (AkFileDesc::hFile). This handle is kept open and used directly to read portions
// of the package from disk, corresponding to read requests for the files it
// contains. The streaming object / package handle is closed when the package
// is destroyed.
//-----------------------------------------------------------------------------
class CAkDiskPackage : public CAkFilePackage
{
public:
// Factory for disk package.
// Instantiates a file package object, queries its file handle once and keep in package.
// Also keeps a copy of its reader object, which is used to close the file handle on destruction.
static CAkDiskPackage * Create(
AkFilePackageReader & in_reader, // File package reader.
const AkOSChar* in_pszPackageName, // Name of the file package (for memory monitoring).
AkMemPoolId in_memPoolID, // Memory pool in which the package is created with its lookup table.
AkUInt32 in_uHeaderSize, // File package header size, including the size of the header chunk AKPK_HEADER_CHUNK_DEF_SIZE.
AkUInt32 & out_uReservedHeaderSize, // Size reserved for header, taking mem align into account.
AkUInt8 *& out_pHeaderBuffer // Returned address of memory for header.
)
{
CAkDiskPackage * pPackage = CAkFilePackage::Create<CAkDiskPackage>(
in_pszPackageName,
in_memPoolID,
in_uHeaderSize,
in_reader.GetBlockSize(),
out_uReservedHeaderSize,
out_pHeaderBuffer );
if ( pPackage )
{
pPackage->m_reader = in_reader; // Copy reader.
pPackage->m_hFile = in_reader.GetHandle(); // Cache handle.
}
return pPackage;
}
CAkDiskPackage( AkUInt32 in_uPackageID, AkUInt32 in_uHeaderSize, AkMemPoolId in_poolID, void * in_pToRelease, bool in_bIsInternalPool )
: CAkFilePackage( in_uPackageID, in_uHeaderSize, in_poolID, in_pToRelease, in_bIsInternalPool )
{ }
// Override Destroy(): Close
virtual void Destroy()
{
m_reader.Close();
CAkFilePackage::Destroy();
}
// Fills an AkFileHandle with a value that will be useable by the low-level I/O hook.
// Disk packages return the package's system handle: the hook reads from the package file itself, with
// proper offset, to get the data it needs.
inline void GetHandleForFileDesc( AkFileHandle & out_hFile ) { out_hFile = m_hFile; }
protected:
AkFilePackageReader m_reader; // READER object. Holds the stream used to read the package. Closed only upon package destruction.
AkFileHandle m_hFile; // Platform-independent file handle (cached from READER).
};
//-----------------------------------------------------------------------------
// Name: class CAkFilePackageLowLevelIO.
// Desc: Extends default Low-level IO implementation with packaged file support.
// Base class must implement one of the low-level I/O hooks
// (AK::StreamMgr::IAkIOHookBlocking or AK::StreamMgr::IAkIOHookDeferred)
// _and_ the AK::StreamMgr::IAkFileLocationResolver interface.
// It must also define the following methods:
// - void Term()
// Note: This class uses AkFileDesc::uCustomParamSize to store the block size
// of files opened from a package, and relies on the fact that it is 0
// when they are not part of the package.
//-----------------------------------------------------------------------------
template <class T_LLIOHOOK_FILELOC, class T_PACKAGE = CAkDiskPackage>
class CAkFilePackageLowLevelIO : public T_LLIOHOOK_FILELOC
{
public:
CAkFilePackageLowLevelIO();
virtual ~CAkFilePackageLowLevelIO();
// File package loading:
// Opens a package file, parses its header, fills LUT.
// Overrides of Open() will search files in loaded LUTs first, then use default Low-Level I/O
// services if they cannot be found.
// Any number of packages can be loaded at a time. Each LUT is searched until a match is found.
// Returns AK_Success if successful, AK_InvalidLanguage if the current language
// does not exist in the LUT (not necessarily an error), AK_Fail for any other reason.
// Also returns a package ID which can be used to unload it (see UnloadFilePackage()).
// WARNING: This method is not thread safe. Ensure there are no I/O occurring on this device
// when loading a file package.
virtual AKRESULT LoadFilePackage(
const AkOSChar* in_pszFilePackageName, // File package name. Location is resolved using base class' Open().
AkUInt32 & out_uPackageID, // Returned package ID.
AkMemPoolId in_memPoolID = AK_DEFAULT_POOL_ID // Memory pool in which the LUT is written. Passing AK_DEFAULT_POOL_ID will create a new pool automatically.
// Note that the bulk of the package's data is stored in VRAM, which is allocated through the VRAM allocation hook.
);
// Unload a file package.
// Returns AK_Success if in_uPackageID exists, AK_Fail otherwise.
// WARNING: This method is not thread safe. Ensure there are no I/O occurring on this device
// when unloading a file package.
virtual AKRESULT UnloadFilePackage(
AkUInt32 in_uPackageID // Returned package ID.
);
// Unload all file packages.
// Returns AK_Success;
// WARNING: This method is not thread safe. Ensure there are no I/O occurring on this device
// when unloading a file package.
virtual AKRESULT UnloadAllFilePackages();
//
// Overriden base class policies.
// ---------------------------------------------------------------
// Clean up.
void Term();
protected:
//
// IAkFileLocationResolver interface overriden methods.
// ---------------------------------------------------------------
// Override Open (string): Search file in each LUT first. If it cannot be found, use base class services.
// If the file is found in the LUTs, open is always synchronous.
// Applies to AK soundbanks only.
virtual AKRESULT Open(
const AkOSChar* in_pszFileName, // File name.
AkOpenMode in_eOpenMode, // Open mode.
AkFileSystemFlags * in_pFlags, // Special flags. Can pass NULL.
bool & io_bSyncOpen, // If true, the file must be opened synchronously. Otherwise it is left at the File Location Resolver's discretion. Return false if Open needs to be deferred.
AkFileDesc & out_fileDesc // Returned file descriptor.
);
// Override Open (ID): Search file in each LUT first. If it cannot be found, use base class services.
// If the file is found in the LUTs, open is always synchronous.
virtual AKRESULT Open(
AkFileID in_fileID, // File ID.
AkOpenMode in_eOpenMode, // Open mode.
AkFileSystemFlags * in_pFlags, // Special flags. Can pass NULL.
bool & io_bSyncOpen, // If true, the file must be opened synchronously. Otherwise it is left at the File Location Resolver's discretion. Return false if Open needs to be deferred.
AkFileDesc & out_fileDesc // Returned file descriptor.
);
//
// IAkLowLevelIOHook interface overriden methods.
// ---------------------------------------------------------------
// Override Close: Do not close handle if file descriptor is part of the current packaged file.
virtual AKRESULT Close(
AkFileDesc & in_fileDesc // File descriptor.
);
// Override GetBlockSize: Get the block size of the LUT if a file package is loaded.
virtual AkUInt32 GetBlockSize(
AkFileDesc & in_fileDesc // File descriptor.
);
protected:
// Language change handling.
// ------------------------------------------
// Handler for global language change.
static AK_FUNC( void, LanguageChangeHandler )(
const AkOSChar * const in_pLanguageName,// New language name.
void * in_pCookie // Cookie that was passed to AddLanguageChangeObserver().
)
{
((CAkFilePackageLowLevelIO<T_LLIOHOOK_FILELOC, T_PACKAGE>*)in_pCookie)->OnLanguageChange( in_pLanguageName );
}
// Updates language of all loaded packages. Packages keep a language ID to help them find
// language-specific assets quickly.
void OnLanguageChange(
const AkOSChar * const in_pLanguageName // New language name.
);
// File package handling methods.
// ------------------------------------------
// Loads a file package, with a given file package reader.
AKRESULT _LoadFilePackage(
const AkOSChar* in_pszFilePackageName, // File package name. Location is resolved using base class' Open().
AkFilePackageReader & in_reader, // File package reader.
AkPriority in_readerPriority, // File package reader priority heuristic.
AkMemPoolId in_memPoolID, // Memory pool in which the LUT is written. Passing AK_DEFAULT_POOL_ID will create a new pool automatically.
T_PACKAGE *& out_pPackage // Returned package
);
// Searches the LUT to find the file data associated with the FileID.
// Returns AK_Success if the file is found.
template <class T_FILEID>
AKRESULT FindPackagedFile(
T_PACKAGE * in_pPackage, // Package to search into.
T_FILEID in_fileID, // File ID.
AkFileSystemFlags * in_pFlags, // Special flags. Can pass NULL.
AkFileDesc & out_fileDesc // Returned file descriptor.
);
// Returns true if file described by in_fileDesc is in a package.
inline bool IsInPackage(
const AkFileDesc & in_fileDesc // File descriptor.
)
{
return in_fileDesc.uCustomParamSize > 0;
}
protected:
// List of loaded packages.
ListFilePackages m_packages;
bool m_bRegisteredToLangChg; // True after registering to language change notifications.
};
#include "AkFilePackageLowLevelIO.inl"
#endif //_AK_FILE_PACKAGE_LOW_LEVEL_IO_H_

View file

@ -0,0 +1,468 @@
//////////////////////////////////////////////////////////////////////
//
// AkFilePackageLowLevelIO.h
//
// CAkFilePackageLowLevelIO extends a Low-Level I/O device by providing
// the ability to reference files that are part of a file package.
//
// It can extend either blocking or deferred I/O hooks (both inheriting from
// AK::StreamMgr::IAkLowLevelIOHook), since its base class is templated.
// In either case, the base class must also implement
// AK::StreamMgr::IAkFileLocationResolver. This interface defines both overloads
// for Open(), and this is where the package's look-up table is searched.
// If no match is found, then it falls back on the base implementation.
//
// Clients of devices that use this class' functionnality simply need to call
// LoadFilePackage(), which loads and parses file packages that were created with
// the AkFilePackager utility app (located in ($WWISESDK)/samples/FilePackager/).
// The header of these file packages contains look-up tables that describe the
// internal offset of each file it references, their block size (required alignment),
// and their language. Each combination of AkFileID and Language ID is unique.
//
// LoadFilePackage() returns a package ID that can be used to unload it. Any number
// of packages can be loaded simultaneously. When Open() is called, the last package
// loaded is searched first, then the previous one, and so on.
//
// The language ID was created dynamically when the package was created. The header
// also contains a map of language names (strings) to their ID, so that the proper
// language-specific version of files can be resolved. The language name that is stored
// matches the name of the directory that is created by the Wwise Bank Manager,
// except for the trailing slash.
//
// The type of package is also a template argument. By default, it is a disk package
// (see AkDiskPackage.h).
//
// Copyright (c) 2006 Audiokinetic Inc. / All Rights Reserved
//
//////////////////////////////////////////////////////////////////////
#include "AkFilePackageLowLevelIO.h"
#include "AkFileHelpers.h"
#include <AK/Tools/Common/AkPlatformFuncs.h>
template <class T_LLIOHOOK_FILELOC, class T_PACKAGE>
CAkFilePackageLowLevelIO<T_LLIOHOOK_FILELOC,T_PACKAGE>::CAkFilePackageLowLevelIO()
: m_bRegisteredToLangChg( false )
{
}
template <class T_LLIOHOOK_FILELOC, class T_PACKAGE>
CAkFilePackageLowLevelIO<T_LLIOHOOK_FILELOC,T_PACKAGE>::~CAkFilePackageLowLevelIO()
{
}
// Initialize/terminate.
template <class T_LLIOHOOK_FILELOC, class T_PACKAGE>
void CAkFilePackageLowLevelIO<T_LLIOHOOK_FILELOC,T_PACKAGE>::Term()
{
UnloadAllFilePackages();
m_packages.Term();
if ( m_bRegisteredToLangChg )
AK::StreamMgr::RemoveLanguageChangeObserver( this );
T_LLIOHOOK_FILELOC::Term();
}
// Override Open (string): Search file in each LUT first. If it cannot be found, use base class services.
// If the file is found in the LUTs, open is always synchronous.
template <class T_LLIOHOOK_FILELOC, class T_PACKAGE>
AKRESULT CAkFilePackageLowLevelIO<T_LLIOHOOK_FILELOC,T_PACKAGE>::Open(
const AkOSChar* in_pszFileName, // File name.
AkOpenMode in_eOpenMode, // Open mode.
AkFileSystemFlags * in_pFlags, // Special flags. Can pass NULL.
bool & io_bSyncOpen, // If true, the file must be opened synchronously. Otherwise it is left at the File Location Resolver's discretion. Return false if Open needs to be deferred.
AkFileDesc & out_fileDesc // Returned file descriptor.
)
{
// If the file is an AK sound bank, try to find the identifier in the lookup table first.
if ( in_eOpenMode == AK_OpenModeRead
&& in_pFlags )
{
if( in_pFlags->uCompanyID == AKCOMPANYID_AUDIOKINETIC
&& in_pFlags->uCodecID == AKCODECID_BANK )
{
// Search file in each package.
ListFilePackages::Iterator it = m_packages.Begin();
while ( it != m_packages.End() )
{
AkFileID fileID = (*it)->lut.GetSoundBankID( in_pszFileName );
if ( FindPackagedFile( (T_PACKAGE*)(*it), fileID, in_pFlags, out_fileDesc ) == AK_Success )
{
// Found the ID in the lut.
io_bSyncOpen = true; // File is opened, now.
return AK_Success;
}
++it;
}
}
else if ( in_pFlags->uCompanyID == AKCOMPANYID_AUDIOKINETIC_EXTERNAL )
{
// Search file in each package.
ListFilePackages::Iterator it = m_packages.Begin();
while ( it != m_packages.End() )
{
AkUInt64 fileID = (*it)->lut.GetExternalID( in_pszFileName );
if ( FindPackagedFile( (T_PACKAGE*)(*it), fileID, in_pFlags, out_fileDesc ) == AK_Success )
{
// Found the ID in the lut.
io_bSyncOpen = true; // File is opened, now.
return AK_Success;
}
++it;
}
}
}
// It is not a soundbank, or it is not in the file package LUT. Use default implementation.
return T_LLIOHOOK_FILELOC::Open(
in_pszFileName,
in_eOpenMode,
in_pFlags,
io_bSyncOpen,
out_fileDesc);
}
// Override Open (ID): Search file in each LUT first. If it cannot be found, use base class services.
// If the file is found in the LUTs, open is always synchronous.
template <class T_LLIOHOOK_FILELOC, class T_PACKAGE>
AKRESULT CAkFilePackageLowLevelIO<T_LLIOHOOK_FILELOC,T_PACKAGE>::Open(
AkFileID in_fileID, // File ID.
AkOpenMode in_eOpenMode, // Open mode.
AkFileSystemFlags * in_pFlags, // Special flags. Can pass NULL.
bool & io_bSyncOpen, // If true, the file must be opened synchronously. Otherwise it is left at the File Location Resolver's discretion. Return false if Open needs to be deferred.
AkFileDesc & out_fileDesc // Returned file descriptor.
)
{
// Try to find the identifier in the lookup table first.
if ( in_eOpenMode == AK_OpenModeRead
&& in_pFlags
&& in_pFlags->uCompanyID == AKCOMPANYID_AUDIOKINETIC)
{
// Search file in each package.
ListFilePackages::Iterator it = m_packages.Begin();
while ( it != m_packages.End() )
{
if ( FindPackagedFile( (T_PACKAGE*)(*it), in_fileID, in_pFlags, out_fileDesc ) == AK_Success )
{
// File found. Return now.
io_bSyncOpen = true; // File is opened, now.
return AK_Success;
}
++it;
}
}
else if ( in_pFlags->uCompanyID == AKCOMPANYID_AUDIOKINETIC_EXTERNAL )
{
// Search file in each package.
ListFilePackages::Iterator it = m_packages.Begin();
while ( it != m_packages.End() )
{
AkOSChar szFileName[20];
AK_OSPRINTF(szFileName, 20, AKTEXT("%u.wem"), (unsigned int)in_fileID);
AkUInt64 fileID = (*it)->lut.GetExternalID(szFileName);
if ( FindPackagedFile( (T_PACKAGE*)(*it), fileID, in_pFlags, out_fileDesc ) == AK_Success )
{
// Found the ID in the lut.
io_bSyncOpen = true; // File is opened, now.
return AK_Success;
}
++it;
}
}
// If it the fileID is not in the LUT, perform standard path concatenation logic.
return T_LLIOHOOK_FILELOC::Open(
in_fileID,
in_eOpenMode,
in_pFlags,
io_bSyncOpen,
out_fileDesc);
}
// Override Close: Do not close handle if file descriptor is part of the current packaged file.
template <class T_LLIOHOOK_FILELOC, class T_PACKAGE>
AKRESULT CAkFilePackageLowLevelIO<T_LLIOHOOK_FILELOC,T_PACKAGE>::Close(
AkFileDesc & in_fileDesc // File descriptor.
)
{
// Do not close handle if it is that of the file package (closed only in UnloadFilePackage()).
if ( !IsInPackage( in_fileDesc ) )
return T_LLIOHOOK_FILELOC::Close( in_fileDesc );
return AK_Success;
}
// Override GetBlockSize: Get the block size of the LUT if a file package is loaded.
template <class T_LLIOHOOK_FILELOC, class T_PACKAGE>
AkUInt32 CAkFilePackageLowLevelIO<T_LLIOHOOK_FILELOC,T_PACKAGE>::GetBlockSize(
AkFileDesc & in_fileDesc // File descriptor.
)
{
if ( IsInPackage( in_fileDesc ) )
{
// This file is part of a package. At Open(), we used the
// AkFileDesc.uCustomParamSize field to store the block size.
return in_fileDesc.uCustomParamSize;
}
return T_LLIOHOOK_FILELOC::GetBlockSize( in_fileDesc );
}
// Updates language of all loaded packages. Packages keep a language ID to help them find
// language-specific assets quickly.
template <class T_LLIOHOOK_FILELOC, class T_PACKAGE>
void CAkFilePackageLowLevelIO<T_LLIOHOOK_FILELOC,T_PACKAGE>::OnLanguageChange(
const AkOSChar * const in_pLanguageName // New language name.
)
{
// Set language on all loaded packages.
ListFilePackages::Iterator it = m_packages.Begin();
while ( it != m_packages.End() )
{
(*it)->lut.SetCurLanguage( in_pLanguageName );
++it;
}
}
// Searches the LUT to find the file data associated with the FileID.
// Returns AK_Success if the file is found.
template <class T_LLIOHOOK_FILELOC, class T_PACKAGE>
template <class T_FILEID>
AKRESULT CAkFilePackageLowLevelIO<T_LLIOHOOK_FILELOC,T_PACKAGE>::FindPackagedFile(
T_PACKAGE * in_pPackage, // Package to search into.
T_FILEID in_fileID, // File ID.
AkFileSystemFlags * in_pFlags, // Special flags. Can pass NULL.
AkFileDesc & out_fileDesc // Returned file descriptor.
)
{
AKASSERT( in_pPackage && in_pFlags );
const CAkFilePackageLUT::AkFileEntry<T_FILEID> * pEntry = in_pPackage->lut.LookupFile( in_fileID, in_pFlags );
if ( pEntry )
{
// Fill file descriptor.
out_fileDesc.deviceID = T_LLIOHOOK_FILELOC::m_deviceID;
in_pPackage->GetHandleForFileDesc( out_fileDesc.hFile );
out_fileDesc.iFileSize = pEntry->uFileSize;
out_fileDesc.uSector = pEntry->uStartBlock;
out_fileDesc.pCustomParam = NULL;
// NOTE: We use the uCustomParamSize to store the block size.
// We will determine whether this file was opened from a package by comparing
// uCustomParamSize with 0 (see IsInPackage()).
out_fileDesc.uCustomParamSize = pEntry->uBlockSize;
return AK_Success;
}
return AK_FileNotFound;
}
// File package loading:
// Opens a package file, parses its header, fills LUT.
// Overrides of Open() will search files in loaded LUTs first, then use default Low-Level I/O
// services if they cannot be found.
// Any number of packages can be loaded at a time. Each LUT is searched until a match is found.
// Returns AK_Success if successful, AK_InvalidLanguage if the current language
// does not exist in the LUT (not necessarily an error), AK_Fail for any other reason.
// Also returns a package ID which can be used to unload it (see UnloadFilePackage()).
template <class T_LLIOHOOK_FILELOC, class T_PACKAGE>
AKRESULT CAkFilePackageLowLevelIO<T_LLIOHOOK_FILELOC,T_PACKAGE>::LoadFilePackage(
const AkOSChar * in_pszFilePackageName, // File package name.
AkUInt32 & out_uPackageID, // Returned package ID.
AkMemPoolId in_memPoolID /*= AK_DEFAULT_POOL_ID */ // Memory pool in which the LUT is written. Passing AK_DEFAULT_POOL_ID will create a new pool automatically.
)
{
// Open package file.
AkFilePackageReader filePackageReader;
AKRESULT eRes = filePackageReader.Open( in_pszFilePackageName, true ); // Open from SFX-only directory.
if ( eRes != AK_Success )
return eRes;
filePackageReader.SetName( in_pszFilePackageName );
T_PACKAGE * pPackage;
eRes = _LoadFilePackage( in_pszFilePackageName, filePackageReader, AK_DEFAULT_PRIORITY, in_memPoolID, pPackage );
if ( eRes == AK_Success
|| eRes == AK_InvalidLanguage )
{
AKASSERT( pPackage );
// Add to packages list.
m_packages.AddFirst( pPackage );
out_uPackageID = pPackage->ID();
}
return eRes;
}
// Loads a file package, with a given file package reader.
template <class T_LLIOHOOK_FILELOC, class T_PACKAGE>
AKRESULT CAkFilePackageLowLevelIO<T_LLIOHOOK_FILELOC,T_PACKAGE>::_LoadFilePackage(
const AkOSChar* in_pszFilePackageName, // File package name.
AkFilePackageReader & in_reader, // File package reader.
AkPriority in_readerPriority, // File package reader priority heuristic.
AkMemPoolId in_memPoolID, // Memory pool in which the LUT is written. Passing AK_DEFAULT_POOL_ID will create a new pool automatically.
T_PACKAGE *& out_pPackage // Returned package
)
{
// Read header chunk definition.
struct AkFilePackageHeader
{
AkUInt32 uFileFormatTag;
AkUInt32 uHeaderSize;
};
AkUInt32 uReadBufferSize = AkMax( 2 * in_reader.GetBlockSize(), sizeof(AkFilePackageHeader) );
AkUInt8 * pBufferForHeader = (AkUInt8*)AkAlloca( uReadBufferSize );
AkUInt32 uSizeToRead;
bool bAligned = ( sizeof(AkFilePackageHeader) % in_reader.GetBlockSize() ) > 0;
if ( bAligned )
{
// Header size is not a multiple of the required block size. Allocate an aligned buffer on the stack.
pBufferForHeader += ( in_reader.GetBlockSize() - (AkUIntPtr)pBufferForHeader % in_reader.GetBlockSize() );
uSizeToRead = in_reader.GetBlockSize();
}
else
{
// Header size is a multiple of the required block size.
uSizeToRead = sizeof(AkFilePackageHeader);
}
AkUInt32 uSizeRead;
AKRESULT eRes = in_reader.Read( pBufferForHeader, uSizeToRead, uSizeRead, in_readerPriority );
if ( eRes != AK_Success
|| uSizeRead < sizeof(AkFilePackageHeader) )
{
AKASSERT( !"Could not read package, or package is invalid" );
in_reader.Close();
return AK_Fail;
}
const AkFilePackageHeader & uFileHeader = *(AkFilePackageHeader*)pBufferForHeader;
if ( uFileHeader.uFileFormatTag != AKPK_FILE_FORMAT_TAG
|| 0 == uFileHeader.uHeaderSize )
{
AKASSERT( !"Invalid file package header" );
in_reader.Close();
return AK_Fail;
}
// Create file package.
AkUInt32 uReservedHeaderSize;
AkUInt8 * pFilePackageHeader;
out_pPackage = T_PACKAGE::Create(
in_reader,
in_pszFilePackageName,
in_memPoolID,
uFileHeader.uHeaderSize + AKPK_HEADER_CHUNK_DEF_SIZE, // NOTE: The header size written in the file package excludes the AKPK_HEADER_CHUNK_DEF_SIZE.
uReservedHeaderSize,
pFilePackageHeader );
if ( !out_pPackage )
{
AKASSERT( !"Could not create file package" );
in_reader.Close();
return AK_Fail;
}
AkUInt32 uHeaderSize = uFileHeader.uHeaderSize;
AkUInt32 uHeaderReadOffset = AKPK_HEADER_CHUNK_DEF_SIZE;
// If we had already read more than sizeof(AkFilePackageHeader), copy the rest now.
if ( uSizeRead > sizeof(AkFilePackageHeader) )
{
pBufferForHeader += sizeof(AkFilePackageHeader);
AkUInt32 uSizeToCopy = uSizeRead - sizeof(AkFilePackageHeader);
AKPLATFORM::AkMemCpy( pFilePackageHeader+AKPK_HEADER_CHUNK_DEF_SIZE, pBufferForHeader, uSizeToCopy );
// Adjust header size and read offset.
if ( uSizeToCopy > uHeaderSize )
uSizeToCopy = uHeaderSize;
uHeaderSize -= uSizeToCopy;
uHeaderReadOffset += uSizeToCopy;
// Round it up to required block size. It should be equal to the size that was reserved (minus what was already read).
uHeaderSize = ( ( uHeaderSize + in_reader.GetBlockSize() - 1 ) / in_reader.GetBlockSize() ) * in_reader.GetBlockSize();
AKASSERT( uHeaderSize == uReservedHeaderSize - uSizeRead );
}
// Stream in remaining of the header.
if ( uHeaderSize > 0 )
{
AKASSERT( uHeaderReadOffset % in_reader.GetBlockSize() == 0 );
if ( in_reader.Read( pFilePackageHeader+uHeaderReadOffset, uHeaderSize, uSizeRead, in_readerPriority ) != AK_Success
|| uSizeRead < uHeaderSize )
{
AKASSERT( !"Could not read file package" );
out_pPackage->Destroy();
return AK_Fail;
}
}
// Parse LUT.
eRes = out_pPackage->lut.Setup( pFilePackageHeader, uFileHeader.uHeaderSize + AKPK_HEADER_CHUNK_DEF_SIZE );
if ( eRes != AK_Success )
{
out_pPackage->Destroy();
return eRes;
}
// Register to language change notifications if it wasn't already done
if ( !m_bRegisteredToLangChg )
{
if ( AK::StreamMgr::AddLanguageChangeObserver( LanguageChangeHandler, this ) != AK_Success )
{
out_pPackage->Destroy();
return AK_Fail;
}
m_bRegisteredToLangChg = true;
}
// Use the current language path (if defined) to set the language ID,
// for language specific file mapping.
return out_pPackage->lut.SetCurLanguage( AK::StreamMgr::GetCurrentLanguage() );
}
// Unload a file package.
template <class T_LLIOHOOK_FILELOC, class T_PACKAGE>
AKRESULT CAkFilePackageLowLevelIO<T_LLIOHOOK_FILELOC,T_PACKAGE>::UnloadFilePackage(
AkUInt32 in_uPackageID // Package ID.
)
{
ListFilePackages::IteratorEx it = m_packages.BeginEx();
while ( it != m_packages.End() )
{
if ( (*it)->ID() == in_uPackageID )
{
CAkFilePackage * pPackage = (*it);
it = m_packages.Erase( it );
// Destroy package.
pPackage->Destroy();
return AK_Success;
}
else
++it;
}
AKASSERT( !"Invalid package ID" );
return AK_Fail;
}
// Unload all file packages.
template <class T_LLIOHOOK_FILELOC, class T_PACKAGE>
AKRESULT CAkFilePackageLowLevelIO<T_LLIOHOOK_FILELOC,T_PACKAGE>::UnloadAllFilePackages()
{
ListFilePackages::IteratorEx it = m_packages.BeginEx();
while ( it != m_packages.End() )
{
CAkFilePackage * pPackage = (*it);
it = m_packages.Erase( it );
// Destroy package.
pPackage->Destroy();
}
return AK_Success;
}

View file

@ -0,0 +1,324 @@
#include "BFPlatform.h"
#ifdef BF_WWISE_ENABLED
//////////////////////////////////////////////////////////////////////
//
// AkDefaultIOHookBlocking.cpp
//
// Default blocking low level IO hook (AK::StreamMgr::IAkIOHookBlocking)
// and file system (AK::StreamMgr::IAkFileLocationResolver) implementation
// on Windows. It can be used as a standalone implementation of the
// Low-Level I/O system.
//
// AK::StreamMgr::IAkFileLocationResolver:
// Resolves file location using simple path concatenation logic
// (implemented in ../Common/CAkFileLocationBase). It can be used as a
// standalone Low-Level IO system, or as part of a multi device system.
// In the latter case, you should manage multiple devices by implementing
// AK::StreamMgr::IAkFileLocationResolver elsewhere (you may take a look
// at class CAkDefaultLowLevelIODispatcher).
//
// AK::StreamMgr::IAkIOHookBlocking:
// Uses platform API for I/O. Calls to ::ReadFile() and ::WriteFile()
// block because files are opened without the FILE_FLAG_OVERLAPPED flag.
// The AK::StreamMgr::IAkIOHookBlocking interface is meant to be used with
// AK_SCHEDULER_BLOCKING streaming devices.
//
// Init() creates a streaming device (by calling AK::StreamMgr::CreateDevice()).
// AkDeviceSettings::uSchedulerTypeFlags is set inside to AK_SCHEDULER_BLOCKING.
// If there was no AK::StreamMgr::IAkFileLocationResolver previously registered
// to the Stream Manager, this object registers itself as the File Location Resolver.
//
// Copyright (c) 2006 Audiokinetic Inc. / All Rights Reserved
//
//////////////////////////////////////////////////////////////////////
#include "Common.h"
#include "AkDefaultIOHookBlocking.h"
#include "AkFileHelpers.h"
#define WIN32_BLOCKING_DEVICE_NAME (AKTEXT("Win32 Blocking")) // Default blocking device name.
CAkDefaultIOHookBlocking::CAkDefaultIOHookBlocking()
: m_deviceID( AK_INVALID_DEVICE_ID )
, m_bAsyncOpen( false )
{
}
CAkDefaultIOHookBlocking::~CAkDefaultIOHookBlocking()
{
}
// Initialization/termination. Init() registers this object as the one and
// only File Location Resolver if none were registered before. Then
// it creates a streaming device with scheduler type AK_SCHEDULER_BLOCKING.
AKRESULT CAkDefaultIOHookBlocking::Init(
const AkDeviceSettings & in_deviceSettings, // Device settings.
bool in_bAsyncOpen/*=false*/ // If true, files are opened asynchronously when possible.
)
{
if ( in_deviceSettings.uSchedulerTypeFlags != AK_SCHEDULER_BLOCKING )
{
AKASSERT( !"CAkDefaultIOHookBlocking I/O hook only works with AK_SCHEDULER_BLOCKING devices" );
return AK_Fail;
}
m_bAsyncOpen = in_bAsyncOpen;
// If the Stream Manager's File Location Resolver was not set yet, set this object as the
// File Location Resolver (this I/O hook is also able to resolve file location).
if ( !AK::StreamMgr::GetFileLocationResolver() )
AK::StreamMgr::SetFileLocationResolver( this );
// Create a device in the Stream Manager, specifying this as the hook.
m_deviceID = AK::StreamMgr::CreateDevice( in_deviceSettings, this );
if ( m_deviceID != AK_INVALID_DEVICE_ID )
return AK_Success;
return AK_Fail;
}
void CAkDefaultIOHookBlocking::Term()
{
if ( AK::StreamMgr::GetFileLocationResolver() == this )
AK::StreamMgr::SetFileLocationResolver( NULL );
AK::StreamMgr::DestroyDevice( m_deviceID );
}
//
// IAkFileLocationAware interface.
//-----------------------------------------------------------------------------
// Returns a file descriptor for a given file name (string).
AKRESULT CAkDefaultIOHookBlocking::Open(
const AkOSChar* in_pszFileName, // File name.
AkOpenMode in_eOpenMode, // Open mode.
AkFileSystemFlags * in_pFlags, // Special flags. Can pass NULL.
bool & io_bSyncOpen, // If true, the file must be opened synchronously. Otherwise it is left at the File Location Resolver's discretion. Return false if Open needs to be deferred.
AkFileDesc & out_fileDesc // Returned file descriptor.
)
{
// We normally consider that calls to ::CreateFile() on a hard drive are fast enough to execute in the
// client thread. If you want files to be opened asynchronously when it is possible, this device should
// be initialized with the flag in_bAsyncOpen set to true.
if ( io_bSyncOpen || !m_bAsyncOpen )
{
io_bSyncOpen = true;
// Get the full file path, using path concatenation logic.
AkOSChar szFullFilePath[AK_MAX_PATH];
if ( GetFullFilePath( in_pszFileName, in_pFlags, in_eOpenMode, szFullFilePath ) == AK_Success )
{
// Open the file without FILE_FLAG_OVERLAPPED and FILE_FLAG_NO_BUFFERING flags.
AKRESULT eResult = CAkFileHelpers::OpenFile(
szFullFilePath,
in_eOpenMode,
false,
false,
out_fileDesc.hFile );
if ( eResult == AK_Success )
{
#ifdef AK_USE_METRO_API
FILE_STANDARD_INFO info;
::GetFileInformationByHandleEx( out_fileDesc.hFile, FileStandardInfo, &info, sizeof(info) );
out_fileDesc.iFileSize = info.EndOfFile.QuadPart;
#else
ULARGE_INTEGER Temp;
Temp.LowPart = ::GetFileSize( out_fileDesc.hFile,(LPDWORD)&Temp.HighPart );
out_fileDesc.iFileSize = Temp.QuadPart;
#endif
out_fileDesc.uSector = 0;
out_fileDesc.deviceID = m_deviceID;
out_fileDesc.pCustomParam = NULL;
out_fileDesc.uCustomParamSize = 0;
}
return eResult;
}
return AK_Fail;
}
else
{
// The client allows us to perform asynchronous opening.
// We only need to specify the deviceID, and leave the boolean to false.
out_fileDesc.iFileSize = 0;
out_fileDesc.uSector = 0;
out_fileDesc.deviceID = m_deviceID;
out_fileDesc.pCustomParam = NULL;
out_fileDesc.uCustomParamSize = 0;
return AK_Success;
}
}
// Returns a file descriptor for a given file ID.
AKRESULT CAkDefaultIOHookBlocking::Open(
AkFileID in_fileID, // File ID.
AkOpenMode in_eOpenMode, // Open mode.
AkFileSystemFlags * in_pFlags, // Special flags. Can pass NULL.
bool & io_bSyncOpen, // If true, the file must be opened synchronously. Otherwise it is left at the File Location Resolver's discretion. Return false if Open needs to be deferred.
AkFileDesc & out_fileDesc // Returned file descriptor.
)
{
// We normally consider that calls to ::CreateFile() on a hard drive are fast enough to execute in the
// client thread. If you want files to be opened asynchronously when it is possible, this device should
// be initialized with the flag in_bAsyncOpen set to true.
if ( io_bSyncOpen || !m_bAsyncOpen )
{
io_bSyncOpen = true;
// Get the full file path, using path concatenation logic.
AkOSChar szFullFilePath[AK_MAX_PATH];
if ( GetFullFilePath( in_fileID, in_pFlags, in_eOpenMode, szFullFilePath ) == AK_Success )
{
// Open the file without FILE_FLAG_OVERLAPPED and FILE_FLAG_NO_BUFFERING flags.
AKRESULT eResult = CAkFileHelpers::OpenFile(
szFullFilePath,
in_eOpenMode,
false,
false,
out_fileDesc.hFile );
if ( eResult == AK_Success )
{
#ifdef AK_USE_METRO_API
FILE_STANDARD_INFO info;
::GetFileInformationByHandleEx( out_fileDesc.hFile, FileStandardInfo, &info, sizeof(info) );
out_fileDesc.iFileSize = info.EndOfFile.QuadPart;
#else
ULARGE_INTEGER Temp;
Temp.LowPart = ::GetFileSize( out_fileDesc.hFile,(LPDWORD)&Temp.HighPart );
out_fileDesc.iFileSize = Temp.QuadPart;
#endif
out_fileDesc.uSector = 0;
out_fileDesc.deviceID = m_deviceID;
out_fileDesc.pCustomParam = NULL;
out_fileDesc.uCustomParamSize = 0;
}
return eResult;
}
return AK_Fail;
}
else
{
// The client allows us to perform asynchronous opening.
// We only need to specify the deviceID, and leave the boolean to false.
out_fileDesc.iFileSize = 0;
out_fileDesc.uSector = 0;
out_fileDesc.deviceID = m_deviceID;
out_fileDesc.pCustomParam = NULL;
out_fileDesc.uCustomParamSize = 0;
return AK_Success;
}
}
//
// IAkIOHookBlocking implementation.
//-----------------------------------------------------------------------------
// Reads data from a file (synchronous).
AKRESULT CAkDefaultIOHookBlocking::Read(
AkFileDesc & in_fileDesc, // File descriptor.
const AkIoHeuristics & /*in_heuristics*/, // Heuristics for this data transfer (not used in this implementation).
void * out_pBuffer, // Buffer to be filled with data.
AkIOTransferInfo & io_transferInfo // Synchronous data transfer info.
)
{
AKASSERT( out_pBuffer &&
in_fileDesc.hFile != INVALID_HANDLE_VALUE );
OVERLAPPED overlapped;
overlapped.Offset = (DWORD)( io_transferInfo.uFilePosition & 0xFFFFFFFF );
overlapped.OffsetHigh = (DWORD)( ( io_transferInfo.uFilePosition >> 32 ) & 0xFFFFFFFF );
overlapped.hEvent = NULL;
AkUInt32 uSizeTransferred;
if ( ::ReadFile(
in_fileDesc.hFile,
out_pBuffer,
io_transferInfo.uRequestedSize,
&uSizeTransferred,
&overlapped ) )
{
AKASSERT( uSizeTransferred == io_transferInfo.uRequestedSize );
return AK_Success;
}
return AK_Fail;
}
// Writes data to a file (synchronous).
AKRESULT CAkDefaultIOHookBlocking::Write(
AkFileDesc & in_fileDesc, // File descriptor.
const AkIoHeuristics & /*in_heuristics*/, // Heuristics for this data transfer (not used in this implementation).
void * in_pData, // Data to be written.
AkIOTransferInfo & io_transferInfo // Synchronous data transfer info.
)
{
AKASSERT( in_pData &&
in_fileDesc.hFile != INVALID_HANDLE_VALUE );
OVERLAPPED overlapped;
overlapped.Offset = (DWORD)( io_transferInfo.uFilePosition & 0xFFFFFFFF );
overlapped.OffsetHigh = (DWORD)( ( io_transferInfo.uFilePosition >> 32 ) & 0xFFFFFFFF );
overlapped.hEvent = NULL;
AkUInt32 uSizeTransferred;
if ( ::WriteFile(
in_fileDesc.hFile,
in_pData,
io_transferInfo.uRequestedSize,
&uSizeTransferred,
&overlapped ) )
{
AKASSERT( uSizeTransferred == io_transferInfo.uRequestedSize );
return AK_Success;
}
return AK_Fail;
}
// Cleans up a file.
AKRESULT CAkDefaultIOHookBlocking::Close(
AkFileDesc & in_fileDesc // File descriptor.
)
{
return CAkFileHelpers::CloseFile( in_fileDesc.hFile );
}
// Returns the block size for the file or its storage device.
AkUInt32 CAkDefaultIOHookBlocking::GetBlockSize(
AkFileDesc & /*in_fileDesc*/ // File descriptor.
)
{
// No constraint on block size (file seeking).
return 1;
}
// Returns a description for the streaming device above this low-level hook.
void CAkDefaultIOHookBlocking::GetDeviceDesc(
AkDeviceDesc &
#ifndef AK_OPTIMIZED
out_deviceDesc // Description of associated low-level I/O device.
#endif
)
{
#ifndef AK_OPTIMIZED
AKASSERT( m_deviceID != AK_INVALID_DEVICE_ID || !"Low-Level device was not initialized" );
out_deviceDesc.deviceID = m_deviceID;
out_deviceDesc.bCanRead = true;
out_deviceDesc.bCanWrite = true;
AKPLATFORM::SafeStrCpy( out_deviceDesc.szDeviceName, WIN32_BLOCKING_DEVICE_NAME, AK_MONITOR_DEVICENAME_MAXLENGTH );
out_deviceDesc.uStringSize = (AkUInt32)wcslen( out_deviceDesc.szDeviceName ) + 1;
#endif
}
// Returns custom profiling data: 1 if file opens are asynchronous, 0 otherwise.
AkUInt32 CAkDefaultIOHookBlocking::GetDeviceData()
{
return ( m_bAsyncOpen ) ? 1 : 0;
}
#endif

View file

@ -0,0 +1,177 @@
//////////////////////////////////////////////////////////////////////
//
// AkDefaultIOHookBlocking.h
//
// Default blocking low level IO hook (AK::StreamMgr::IAkIOHookBlocking)
// and file system (AK::StreamMgr::IAkFileLocationResolver) implementation
// on Windows. It can be used as a standalone implementation of the
// Low-Level I/O system.
//
// AK::StreamMgr::IAkFileLocationResolver:
// Resolves file location using simple path concatenation logic
// (implemented in ../Common/CAkFileLocationBase). It can be used as a
// standalone Low-Level IO system, or as part of a multi device system.
// In the latter case, you should manage multiple devices by implementing
// AK::StreamMgr::IAkFileLocationResolver elsewhere (you may take a look
// at class CAkDefaultLowLevelIODispatcher).
//
// AK::StreamMgr::IAkIOHookBlocking:
// Uses platform API for I/O. Calls to ::ReadFile() and ::WriteFile()
// block because files are opened without the FILE_FLAG_OVERLAPPED flag.
// The AK::StreamMgr::IAkIOHookBlocking interface is meant to be used with
// AK_SCHEDULER_BLOCKING streaming devices.
//
// Init() creates a streaming device (by calling AK::StreamMgr::CreateDevice()).
// AkDeviceSettings::uSchedulerTypeFlags is set inside to AK_SCHEDULER_BLOCKING.
// If there was no AK::StreamMgr::IAkFileLocationResolver previously registered
// to the Stream Manager, this object registers itself as the File Location Resolver.
//
// Examples of streaming initialization:
//
// Standalone (registered as the one and only File Location Resolver):
/*
// Create Stream Manager.
AkStreamMgrSettings stmSettings;
AK::StreamMgr::GetDefaultSettings( stmSettings );
AK:IAkStreamMgr * pStreamMgr = AK::StreamMgr::Create( stmSettings );
AKASSERT( pStreamMgr );
// Create blocking device.
AkDeviceSettings deviceSettings;
AK::StreamMgr::GetDefaultDeviceSettings( deviceSettings );
CAkDefaultIOHookBlocking hookIOBlocking;
AKRESULT eResult = hookIOBlocking.Init( deviceSettings );
AKASSERT( AK_Success == eResult );
*/
//
// As part of a system with multiple devices (the File Location Resolver is
// implemented by CAkDefaultLowLevelIODispatcher):
/*
// Create Stream Manager.
AkStreamMgrSettings stmSettings;
AK::StreamMgr::GetDefaultSettings( stmSettings );
AK:IAkStreamMgr * pStreamMgr = AK::StreamMgr::Create( stmSettings );
AKASSERT( pStreamMgr );
// Create and register the File Location Resolver.
CAkDefaultLowLevelIODispatcher lowLevelIODispatcher;
AK::StreamMgr::SetFileLocationResolver( &lowLevelIODispatcher );
// Create blocking device.
AkDeviceSettings deviceSettings;
AK::StreamMgr::GetDefaultDeviceSettings( deviceSettings );
CAkDefaultIOHookBlocking hookIOBlocking;
AKRESULT eResult = hookIOBlocking.Init( deviceSettings );
AKASSERT( AK_Success == eResult );
// Add it to the global File Location Resolver.
lowLevelIODispatcher.AddDevice( hookIOBlocking );
// Create more devices.
// ...
*/
//
// Copyright (c) 2006 Audiokinetic Inc. / All Rights Reserved
//
//////////////////////////////////////////////////////////////////////
#ifndef _AK_DEFAULT_IO_HOOK_BLOCKING_H_
#define _AK_DEFAULT_IO_HOOK_BLOCKING_H_
#include <AK/SoundEngine/Common/AkStreamMgrModule.h>
#include "../Common/AkFileLocationBase.h"
//-----------------------------------------------------------------------------
// Name: class CAkDefaultIOHookBlocking.
// Desc: Implements IAkIOHookBlocking low-level I/O hook, and
// IAkFileLocationResolver. Can be used as a standalone Low-Level I/O
// system, or as part of a system with multiple devices.
// File location is resolved using simple path concatenation logic
// (implemented in CAkFileLocationBase).
//-----------------------------------------------------------------------------
class CAkDefaultIOHookBlocking : public AK::StreamMgr::IAkFileLocationResolver
,public AK::StreamMgr::IAkIOHookBlocking
,public CAkFileLocationBase
{
public:
CAkDefaultIOHookBlocking();
virtual ~CAkDefaultIOHookBlocking();
// Initialization/termination. Init() registers this object as the one and
// only File Location Resolver if none were registered before. Then
// it creates a streaming device with scheduler type AK_SCHEDULER_BLOCKING.
AKRESULT Init(
const AkDeviceSettings & in_deviceSettings, // Device settings.
bool in_bAsyncOpen=false // If true, files are opened asynchronously when possible.
);
void Term();
//
// IAkFileLocationAware interface.
//-----------------------------------------------------------------------------
// Returns a file descriptor for a given file name (string).
virtual AKRESULT Open(
const AkOSChar* in_pszFileName, // File name.
AkOpenMode in_eOpenMode, // Open mode.
AkFileSystemFlags * in_pFlags, // Special flags. Can pass NULL.
bool & io_bSyncOpen, // If true, the file must be opened synchronously. Otherwise it is left at the File Location Resolver's discretion. Return false if Open needs to be deferred.
AkFileDesc & out_fileDesc // Returned file descriptor.
);
// Returns a file descriptor for a given file ID.
virtual AKRESULT Open(
AkFileID in_fileID, // File ID.
AkOpenMode in_eOpenMode, // Open mode.
AkFileSystemFlags * in_pFlags, // Special flags. Can pass NULL.
bool & io_bSyncOpen, // If true, the file must be opened synchronously. Otherwise it is left at the File Location Resolver's discretion. Return false if Open needs to be deferred.
AkFileDesc & out_fileDesc // Returned file descriptor.
);
//
// IAkIOHookBlocking interface.
//-----------------------------------------------------------------------------
// Reads data from a file (synchronous).
virtual AKRESULT Read(
AkFileDesc & in_fileDesc, // File descriptor.
const AkIoHeuristics & in_heuristics, // Heuristics for this data transfer.
void * out_pBuffer, // Buffer to be filled with data.
AkIOTransferInfo & io_transferInfo // Synchronous data transfer info.
);
// Writes data to a file (synchronous).
virtual AKRESULT Write(
AkFileDesc & in_fileDesc, // File descriptor.
const AkIoHeuristics & in_heuristics, // Heuristics for this data transfer.
void * in_pData, // Data to be written.
AkIOTransferInfo & io_transferInfo // Synchronous data transfer info.
);
// Cleans up a file.
virtual AKRESULT Close(
AkFileDesc & in_fileDesc // File descriptor.
);
// Returns the block size for the file or its storage device.
virtual AkUInt32 GetBlockSize(
AkFileDesc & in_fileDesc // File descriptor.
);
// Returns a description for the streaming device above this low-level hook.
virtual void GetDeviceDesc(
AkDeviceDesc & out_deviceDesc // Device description.
);
// Returns custom profiling data: 1 if file opens are asynchronous, 0 otherwise.
virtual AkUInt32 GetDeviceData();
protected:
AkDeviceID m_deviceID;
bool m_bAsyncOpen; // If true, opens files asynchronously when it can.
};
#endif //_AK_DEFAULT_IO_HOOK_BLOCKING_H_

View file

@ -0,0 +1,404 @@
#include "BFPlatform.h"
#ifdef BF_WWISE_ENABLED
//////////////////////////////////////////////////////////////////////
//
// AkDefaultIOHookDeferred.cpp
//
// Default deferred low level IO hook (AK::StreamMgr::IAkIOHookDeferred)
// and file system (AK::StreamMgr::IAkFileLocationResolver) implementation
// on Windows.
//
// AK::StreamMgr::IAkFileLocationResolver:
// Resolves file location using simple path concatenation logic
// (implemented in ../Common/CAkFileLocationBase). It can be used as a
// standalone Low-Level IO system, or as part of a multi device system.
// In the latter case, you should manage multiple devices by implementing
// AK::StreamMgr::IAkFileLocationResolver elsewhere (you may take a look
// at class CAkDefaultLowLevelIODispatcher).
//
// AK::StreamMgr::IAkIOHookDeferred:
// Uses platform API for I/O. Calls to ::ReadFile() and ::WriteFile()
// do not block because files are opened with the FILE_FLAG_OVERLAPPED flag.
// Transfer completion is handled by internal FileIOCompletionRoutine function,
// which then calls the AkAIOCallback.
// The AK::StreamMgr::IAkIOHookDeferred interface is meant to be used with
// AK_SCHEDULER_DEFERRED_LINED_UP streaming devices.
//
// Init() creates a streaming device (by calling AK::StreamMgr::CreateDevice()).
// AkDeviceSettings::uSchedulerTypeFlags is set inside to AK_SCHEDULER_DEFERRED_LINED_UP.
// If there was no AK::StreamMgr::IAkFileLocationResolver previously registered
// to the Stream Manager, this object registers itself as the File Location Resolver.
//
// Copyright (c) 2006 Audiokinetic Inc. / All Rights Reserved
//
//////////////////////////////////////////////////////////////////////
#include "Common.h"
#include "AkDefaultIOHookDeferred.h"
#include <AK/SoundEngine/Common/AkMemoryMgr.h>
#include "AkFileHelpers.h"
// Device info.
#define WIN32_DEFERRED_DEVICE_NAME (L"Win32 Deferred") // Default deferred device name.
// With files opened with FILE_FLAG_NO_BUFFERING flag, accesses should be made in multiple of the
// sector size. We don't know what it is, so we choose a safe value of 2 KB.
// On Windows, real sector size can be queried with ::GetDiskFreeSpace() (but you need to know the drive letter).
#define WIN32_NO_BUFFERING_BLOCK_SIZE (2048)
AkMemPoolId CAkDefaultIOHookDeferred::m_poolID = AK_INVALID_POOL_ID;
CAkDefaultIOHookDeferred::CAkDefaultIOHookDeferred()
: m_deviceID( AK_INVALID_DEVICE_ID )
, m_bAsyncOpen( false )
{
}
CAkDefaultIOHookDeferred::~CAkDefaultIOHookDeferred()
{
}
// Initialization/termination. Init() registers this object as the one and
// only File Location Resolver if none were registered before. Then
// it creates a streaming device with scheduler type AK_SCHEDULER_DEFERRED_LINED_UP.
AKRESULT CAkDefaultIOHookDeferred::Init(
const AkDeviceSettings & in_deviceSettings, // Device settings.
bool in_bAsyncOpen/*=false*/ // If true, files are opened asynchronously when possible.
)
{
if ( in_deviceSettings.uSchedulerTypeFlags != AK_SCHEDULER_DEFERRED_LINED_UP )
{
AKASSERT( !"CAkDefaultIOHookDeferred I/O hook only works with AK_SCHEDULER_DEFERRED_LINED_UP devices" );
return AK_Fail;
}
m_bAsyncOpen = in_bAsyncOpen;
// If the Stream Manager's File Location Resolver was not set yet, set this object as the
// File Location Resolver (this I/O hook is also able to resolve file location).
if ( !AK::StreamMgr::GetFileLocationResolver() )
AK::StreamMgr::SetFileLocationResolver( this );
// Create a device in the Stream Manager, specifying this as the hook.
m_deviceID = AK::StreamMgr::CreateDevice( in_deviceSettings, this );
if ( m_deviceID != AK_INVALID_DEVICE_ID )
{
// Initialize structures needed to perform deferred transfers.
AkUInt32 uPoolSize = (AkUInt32)( in_deviceSettings.uMaxConcurrentIO * sizeof( OVERLAPPED ) );
m_poolID = AK::MemoryMgr::CreatePool( NULL, uPoolSize, sizeof( OVERLAPPED ), AkMalloc | AkFixedSizeBlocksMode );
if ( m_poolID == AK_INVALID_POOL_ID )
{
AKASSERT( !"Failed creating pool for asynchronous device" );
return AK_Fail;
}
AK_SETPOOLNAME( m_poolID, L"Deferred I/O hook" );
return AK_Success;
}
return AK_Fail;
}
void CAkDefaultIOHookDeferred::Term()
{
if ( AK::StreamMgr::GetFileLocationResolver() == this )
AK::StreamMgr::SetFileLocationResolver( NULL );
AK::StreamMgr::DestroyDevice( m_deviceID );
if ( m_poolID != AK_INVALID_POOL_ID )
{
AK::MemoryMgr::DestroyPool( m_poolID );
m_poolID = AK_INVALID_POOL_ID;
}
}
//
// IAkFileLocationAware implementation.
//-----------------------------------------------------------------------------
// Returns a file descriptor for a given file name (string).
AKRESULT CAkDefaultIOHookDeferred::Open(
const AkOSChar* in_pszFileName, // File name.
AkOpenMode in_eOpenMode, // Open mode.
AkFileSystemFlags * in_pFlags, // Special flags. Can pass NULL.
bool & io_bSyncOpen, // If true, the file must be opened synchronously. Otherwise it is left at the File Location Resolver's discretion. Return false if Open needs to be deferred.
AkFileDesc & out_fileDesc // Returned file descriptor.
)
{
// We normally consider that calls to ::CreateFile() on a hard drive are fast enough to execute in the
// client thread. If you want files to be opened asynchronously when it is possible, this device should
// be initialized with the flag in_bAsyncOpen set to true.
if ( io_bSyncOpen || !m_bAsyncOpen )
{
io_bSyncOpen = true;
// Get the full file path, using path concatenation logic.
AkOSChar szFullFilePath[AK_MAX_PATH];
if ( GetFullFilePath( in_pszFileName, in_pFlags, in_eOpenMode, szFullFilePath ) == AK_Success )
{
// Open the file with FILE_FLAG_OVERLAPPED and FILE_FLAG_NO_BUFFERING flags.
AKRESULT eResult = CAkFileHelpers::OpenFile(
szFullFilePath,
in_eOpenMode,
true,
true,
out_fileDesc.hFile );
if ( eResult == AK_Success )
{
ULARGE_INTEGER Temp;
Temp.LowPart = ::GetFileSize( out_fileDesc.hFile,(LPDWORD)&Temp.HighPart );
out_fileDesc.iFileSize = Temp.QuadPart;
out_fileDesc.uSector = 0;
out_fileDesc.deviceID = m_deviceID;
out_fileDesc.pCustomParam = ( in_eOpenMode == AK_OpenModeRead ) ? NULL : (void*)1;
out_fileDesc.uCustomParamSize = 0;
}
return eResult;
}
return AK_Fail;
}
else
{
// The client allows us to perform asynchronous opening.
// We only need to specify the deviceID, and leave the boolean to false.
out_fileDesc.iFileSize = 0;
out_fileDesc.uSector = 0;
out_fileDesc.deviceID = m_deviceID;
out_fileDesc.pCustomParam = NULL;
out_fileDesc.uCustomParamSize = 0;
return AK_Success;
}
}
// Returns a file descriptor for a given file ID.
AKRESULT CAkDefaultIOHookDeferred::Open(
AkFileID in_fileID, // File ID.
AkOpenMode in_eOpenMode, // Open mode.
AkFileSystemFlags * in_pFlags, // Special flags. Can pass NULL.
bool & io_bSyncOpen, // If true, the file must be opened synchronously. Otherwise it is left at the File Location Resolver's discretion. Return false if Open needs to be deferred.
AkFileDesc & out_fileDesc // Returned file descriptor.
)
{
// We normally consider that calls to ::CreateFile() on a hard drive are fast enough to execute in the
// client thread. If you want files to be opened asynchronously when it is possible, this device should
// be initialized with the flag in_bAsyncOpen set to true.
if ( io_bSyncOpen || !m_bAsyncOpen )
{
io_bSyncOpen = true;
// Get the full file path, using path concatenation logic.
AkOSChar szFullFilePath[AK_MAX_PATH];
if ( GetFullFilePath( in_fileID, in_pFlags, in_eOpenMode, szFullFilePath ) == AK_Success )
{
// Open the file with FILE_FLAG_OVERLAPPED and FILE_FLAG_NO_BUFFERING flags.
AKRESULT eResult = CAkFileHelpers::OpenFile(
szFullFilePath,
in_eOpenMode,
true,
true,
out_fileDesc.hFile );
if ( eResult == AK_Success )
{
ULARGE_INTEGER Temp;
Temp.LowPart = ::GetFileSize( out_fileDesc.hFile,(LPDWORD)&Temp.HighPart );
out_fileDesc.iFileSize = Temp.QuadPart;
out_fileDesc.uSector = 0;
out_fileDesc.deviceID = m_deviceID;
out_fileDesc.pCustomParam = NULL;
out_fileDesc.uCustomParamSize = 0;
}
return eResult;
}
return AK_Fail;
}
else
{
// The client allows us to perform asynchronous opening.
// We only need to specify the deviceID, and leave the boolean to false.
out_fileDesc.iFileSize = 0;
out_fileDesc.uSector = 0;
out_fileDesc.deviceID = m_deviceID;
out_fileDesc.pCustomParam = NULL;
out_fileDesc.uCustomParamSize = 0;
return AK_Success;
}
}
//
// IAkIOHookDeferred implementation.
//-----------------------------------------------------------------------------
// Local callback for overlapped I/O.
VOID CALLBACK CAkDefaultIOHookDeferred::FileIOCompletionRoutine(
DWORD dwErrorCode,
DWORD
#ifdef _DEBUG
dwNumberOfBytesTransfered
#endif
,
LPOVERLAPPED lpOverlapped
)
{
AkAsyncIOTransferInfo * pXferInfo = (AkAsyncIOTransferInfo*)(lpOverlapped->hEvent);
ReleaseOverlapped( lpOverlapped );
AKRESULT eResult = AK_Fail;
if ( ERROR_SUCCESS == dwErrorCode )
{
eResult = AK_Success;
AKASSERT( dwNumberOfBytesTransfered >= pXferInfo->uRequestedSize && dwNumberOfBytesTransfered <= pXferInfo->uBufferSize );
}
pXferInfo->pCallback( pXferInfo, eResult );
}
// Reads data from a file (asynchronous overload).
AKRESULT CAkDefaultIOHookDeferred::Read(
AkFileDesc & in_fileDesc, // File descriptor.
const AkIoHeuristics & /*in_heuristics*/, // Heuristics for this data transfer (not used in this implementation).
AkAsyncIOTransferInfo & io_transferInfo // Asynchronous data transfer info.
)
{
AKASSERT( in_fileDesc.hFile != INVALID_HANDLE_VALUE
&& io_transferInfo.uRequestedSize > 0
&& io_transferInfo.uBufferSize >= io_transferInfo.uRequestedSize );
// If this assert comes up, it might be beacause this hook's GetBlockSize() return value is incompatible
// with the system's handling of file reading for this specific file handle.
// If you are using the File Package extension, did you create your package with a compatible
// block size? It should be a multiple of WIN32_NO_BUFFERING_BLOCK_SIZE. (check -blocksize argument in the File Packager command line)
AKASSERT( ( io_transferInfo.uFilePosition % WIN32_NO_BUFFERING_BLOCK_SIZE ) == 0
|| !"Requested file position for I/O transfer is inconsistent with block size" );
OVERLAPPED * pOverlapped = GetFreeOverlapped( &io_transferInfo );
// Set file offset in OVERLAPPED structure.
pOverlapped->Offset = (DWORD)( io_transferInfo.uFilePosition & 0xFFFFFFFF );
pOverlapped->OffsetHigh = (DWORD)( ( io_transferInfo.uFilePosition >> 32 ) & 0xFFFFFFFF );
// File was open with asynchronous flag.
// Read overlapped.
// Note: With a file handle opened with FILE_FLAG_NO_BUFFERING, ::ReadFileEx() supports read sizes that go beyond the end
// of file. However, it does not support read sizes that are not a multiple of the drive's sector size.
// Since the buffer size is always a multiple of the block size, let's use io_transferInfo.uBufferSize
// instead of io_transferInfo.uRequestedSize.
if ( ::ReadFileEx( in_fileDesc.hFile,
io_transferInfo.pBuffer,
io_transferInfo.uBufferSize,
pOverlapped,
CAkDefaultIOHookDeferred::FileIOCompletionRoutine ) )
{
return AK_Success;
}
ReleaseOverlapped( pOverlapped );
return AK_Fail;
}
// Writes data to a file (asynchronous overload).
AKRESULT CAkDefaultIOHookDeferred::Write(
AkFileDesc & in_fileDesc, // File descriptor.
const AkIoHeuristics & /*in_heuristics*/, // Heuristics for this data transfer (not used in this implementation).
AkAsyncIOTransferInfo & io_transferInfo // Platform-specific asynchronous IO operation info.
)
{
AKASSERT( in_fileDesc.hFile != INVALID_HANDLE_VALUE
&& io_transferInfo.uRequestedSize > 0 );
// If this assert comes up, it might be beacause this hook's GetBlockSize() return value is incompatible
// with the system's handling of file reading for this specific file handle.
// Are you using the File Package Low-Level I/O with incompatible block size? (check -blocksize argument in the File Packager command line)
AKASSERT( io_transferInfo.uFilePosition % GetBlockSize( in_fileDesc ) == 0
|| !"Requested file position for I/O transfer is inconsistent with block size" );
OVERLAPPED * pOverlapped = GetFreeOverlapped( &io_transferInfo );
// Set file offset in OVERLAPPED structure.
pOverlapped->Offset = (DWORD)( io_transferInfo.uFilePosition & 0xFFFFFFFF );
pOverlapped->OffsetHigh = (DWORD)( ( io_transferInfo.uFilePosition >> 32 ) & 0xFFFFFFFF );
// File was open with asynchronous flag.
// Read overlapped.
if ( ::WriteFileEx( in_fileDesc.hFile,
io_transferInfo.pBuffer,
io_transferInfo.uRequestedSize,
pOverlapped,
CAkDefaultIOHookDeferred::FileIOCompletionRoutine ) )
{
return AK_Success;
}
ReleaseOverlapped( pOverlapped );
return AK_Fail;
}
// Cancel transfer(s).
void CAkDefaultIOHookDeferred::Cancel(
AkFileDesc & in_fileDesc, // File descriptor.
AkAsyncIOTransferInfo & /*io_transferInfo*/,// Transfer info to cancel (this implementation only handles "cancel all").
bool & io_bCancelAllTransfersForThisFile // Flag indicating whether all transfers should be cancelled for this file (see notes in function description).
)
{
if ( io_bCancelAllTransfersForThisFile )
{
CancelIo( in_fileDesc.hFile );
// Leave io_bCancelAllTransfersForThisFile to true: all transfers were cancelled for this file,
// so we don't need to be called again.
}
}
// Close a file.
AKRESULT CAkDefaultIOHookDeferred::Close(
AkFileDesc & in_fileDesc // File descriptor.
)
{
return CAkFileHelpers::CloseFile( in_fileDesc.hFile );
}
// Returns the block size for the file or its storage device.
AkUInt32 CAkDefaultIOHookDeferred::GetBlockSize(
AkFileDesc & in_fileDesc // File descriptor.
)
{
if ( in_fileDesc.pCustomParam == 0 )
return WIN32_NO_BUFFERING_BLOCK_SIZE;
return 1;
}
// Returns a description for the streaming device above this low-level hook.
void CAkDefaultIOHookDeferred::GetDeviceDesc(
AkDeviceDesc &
#ifndef AK_OPTIMIZED
out_deviceDesc // Description of associated low-level I/O device.
#endif
)
{
#ifndef AK_OPTIMIZED
AKASSERT( m_deviceID != AK_INVALID_DEVICE_ID || !"Low-Level device was not initialized" );
// Deferred scheduler.
out_deviceDesc.deviceID = m_deviceID;
out_deviceDesc.bCanRead = true;
out_deviceDesc.bCanWrite = true;
AKPLATFORM::SafeStrCpy( out_deviceDesc.szDeviceName, WIN32_DEFERRED_DEVICE_NAME, AK_MONITOR_DEVICENAME_MAXLENGTH );
out_deviceDesc.uStringSize = (AkUInt32)wcslen( out_deviceDesc.szDeviceName ) + 1;
#endif
}
// Returns custom profiling data: 1 if file opens are asynchronous, 0 otherwise.
// Tip: An interesting application for custom profiling data in deferred devices is to display
// the number of requests currently pending in the low-level IO.
AkUInt32 CAkDefaultIOHookDeferred::GetDeviceData()
{
return ( m_bAsyncOpen ) ? 1 : 0;
}
#endif

View file

@ -0,0 +1,221 @@
//////////////////////////////////////////////////////////////////////
//
// AkDefaultIOHookDeferred.h
//
// Default deferred low level IO hook (AK::StreamMgr::IAkIOHookDeferred)
// and file system (AK::StreamMgr::IAkFileLocationResolver) implementation
// on Windows.
//
// AK::StreamMgr::IAkFileLocationResolver:
// Resolves file location using simple path concatenation logic
// (implemented in ../Common/CAkFileLocationBase). It can be used as a
// standalone Low-Level IO system, or as part of a multi device system.
// In the latter case, you should manage multiple devices by implementing
// AK::StreamMgr::IAkFileLocationResolver elsewhere (you may take a look
// at class CAkDefaultLowLevelIODispatcher).
//
// AK::StreamMgr::IAkIOHookDeferred:
// Uses platform API for I/O. Calls to ::ReadFile() and ::WriteFile()
// do not block because files are opened with the FILE_FLAG_OVERLAPPED flag.
// Transfer completion is handled by internal FileIOCompletionRoutine function,
// which then calls the AkAIOCallback.
// The AK::StreamMgr::IAkIOHookDeferred interface is meant to be used with
// AK_SCHEDULER_DEFERRED_LINED_UP streaming devices.
//
// Init() creates a streaming device (by calling AK::StreamMgr::CreateDevice()).
// AkDeviceSettings::uSchedulerTypeFlags is set inside to AK_SCHEDULER_DEFERRED_LINED_UP.
// If there was no AK::StreamMgr::IAkFileLocationResolver previously registered
// to the Stream Manager, this object registers itself as the File Location Resolver.
//
// Examples of streaming initialization:
//
// Standalone (registered as the one and only File Location Resolver):
/*
// Create Stream Manager.
AkStreamMgrSettings stmSettings;
AK::StreamMgr::GetDefaultSettings( stmSettings );
AK:IAkStreamMgr * pStreamMgr = AK::StreamMgr::Create( stmSettings );
AKASSERT( pStreamMgr );
// Create deferred device.
AkDeviceSettings deviceSettings;
AK::StreamMgr::GetDefaultDeviceSettings( deviceSettings );
CAkDefaultIOHookDeferred hookIODeferred;
AKRESULT eResult = hookIODeferred.Init( deviceSettings );
AKASSERT( AK_SUCCESS == eResult );
*/
//
// As part of a system with multiple devices (the File Location Resolver is
// implemented by CAkDefaultLowLevelIODispatcher):
/*
// Create Stream Manager.
AkStreamMgrSettings stmSettings;
AK::StreamMgr::GetDefaultSettings( stmSettings );
AK:IAkStreamMgr * pStreamMgr = AK::StreamMgr::Create( stmSettings );
AKASSERT( pStreamMgr );
// Create and register the File Location Resolver.
CAkDefaultLowLevelIODispatcher lowLevelIODispatcher;
AK::StreamMgr::SetFileLocationResolver( &lowLevelIODispatcher );
// Create deferred device.
AkDeviceSettings deviceSettings;
AK::StreamMgr::GetDefaultDeviceSettings( deviceSettings );
CAkDefaultIOHookDeferred hookIODeferred;
AKRESULT eResult = hookIODeferred.Init( deviceSettings );
AKASSERT( AK_SUCCESS == eResult );
// Add it to the global File Location Resolver.
lowLevelIODispatcher.AddDevice( hookIODeferred );
// Create more devices.
// ...
*/
//
// Copyright (c) 2006 Audiokinetic Inc. / All Rights Reserved
//
//////////////////////////////////////////////////////////////////////
#ifndef _AK_DEFAULT_IO_HOOK_DEFERRED_H_
#define _AK_DEFAULT_IO_HOOK_DEFERRED_H_
#include <AK/SoundEngine/Common/AkStreamMgrModule.h>
#include "../Common/AkFileLocationBase.h"
#include <AK/Tools/Common/AkAssert.h>
//-----------------------------------------------------------------------------
// Name: class CAkDefaultIOHookDeferred.
// Desc: Implements IAkIOHookDeferred low-level I/O hook, and
// IAkFileLocationResolver. Can be used as a standalone Low-Level I/O
// system, or as part of a system with multiple devices.
// File location is resolved using simple path concatenation logic
// (implemented in CAkFileLocationBase).
//-----------------------------------------------------------------------------
class CAkDefaultIOHookDeferred : public AK::StreamMgr::IAkFileLocationResolver
,public AK::StreamMgr::IAkIOHookDeferred
,public CAkFileLocationBase
{
public:
CAkDefaultIOHookDeferred();
virtual ~CAkDefaultIOHookDeferred();
// Initialization/termination. Init() registers this object as the one and
// only File Location Resolver if none were registered before. Then
// it creates a streaming device with scheduler type AK_SCHEDULER_DEFERRED_LINED_UP.
AKRESULT Init(
const AkDeviceSettings & in_deviceSettings, // Device settings.
bool in_bAsyncOpen=false // If true, files are opened asynchronously when possible.
);
void Term();
//
// IAkFileLocationAware interface.
//-----------------------------------------------------------------------------
// Returns a file descriptor for a given file name (string).
virtual AKRESULT Open(
const AkOSChar* in_pszFileName, // File name.
AkOpenMode in_eOpenMode, // Open mode.
AkFileSystemFlags * in_pFlags, // Special flags. Can pass NULL.
bool & io_bSyncOpen, // If true, the file must be opened synchronously. Otherwise it is left at the File Location Resolver's discretion. Return false if Open needs to be deferred.
AkFileDesc & out_fileDesc // Returned file descriptor.
);
// Returns a file descriptor for a given file ID.
virtual AKRESULT Open(
AkFileID in_fileID, // File ID.
AkOpenMode in_eOpenMode, // Open mode.
AkFileSystemFlags * in_pFlags, // Special flags. Can pass NULL.
bool & io_bSyncOpen, // If true, the file must be opened synchronously. Otherwise it is left at the File Location Resolver's discretion. Return false if Open needs to be deferred.
AkFileDesc & out_fileDesc // Returned file descriptor.
);
//
// IAkIOHookDeferred interface.
//-----------------------------------------------------------------------------
/// Reads data from a file (asynchronous).
virtual AKRESULT Read(
AkFileDesc & in_fileDesc, // File descriptor.
const AkIoHeuristics & in_heuristics, // Heuristics for this data transfer.
AkAsyncIOTransferInfo & io_transferInfo // Asynchronous data transfer info.
);
// Writes data to a file (asynchronous).
virtual AKRESULT Write(
AkFileDesc & in_fileDesc, // File descriptor.
const AkIoHeuristics & in_heuristics, // Heuristics for this data transfer.
AkAsyncIOTransferInfo & io_transferInfo // Platform-specific asynchronous IO operation info.
);
// Notifies that a transfer request is cancelled. It will be flushed by the streaming device when completed.
virtual void Cancel(
AkFileDesc & in_fileDesc, // File descriptor.
AkAsyncIOTransferInfo & io_transferInfo, // Transfer info to cancel.
bool & io_bCancelAllTransfersForThisFile // Flag indicating whether all transfers should be cancelled for this file (see notes in function description).
);
// Cleans up a file.
virtual AKRESULT Close(
AkFileDesc & in_fileDesc // File descriptor.
);
// Returns the block size for the file or its storage device.
virtual AkUInt32 GetBlockSize(
AkFileDesc & in_fileDesc // File descriptor.
);
// Returns a description for the streaming device above this low-level hook.
virtual void GetDeviceDesc(
AkDeviceDesc & out_deviceDesc // Description of associated low-level I/O device.
);
// Returns custom profiling data: 1 if file opens are asynchronous, 0 otherwise.
virtual AkUInt32 GetDeviceData();
protected:
// Local callback for overlapped I/O.
static VOID CALLBACK FileIOCompletionRoutine(
DWORD dwErrorCode,
DWORD dwNumberOfBytesTransfered,
LPOVERLAPPED lpOverlapped
);
protected:
AkDeviceID m_deviceID;
bool m_bAsyncOpen; // If true, opens files asynchronously when it can.
// Structures for concurrent asynchronous transfers bookkeeping.
static AkMemPoolId m_poolID; // Memory pool for overlapped objects.
// Note 1: The pool is a fixed block size pool. It returns OVERLAPPED objects. Allocation is guaranteed
// because the pool size is MaxConcurrentIO * sizeof(OVERLAPPED).
// Note 2: accesses to memory pool are not locked, because we only use the platform SDK here,
// which is executed by the I/O thread when it is in an alertable state.
// If you release overlapped objects from your own thread, a lock is mandatory.
// Note 3: we use the hEvent field to store a pointer to the AkAsyncIOTransferInfo structure.
// Get a free slot for an OVERLAPPED I/O transfer.
OVERLAPPED * GetFreeOverlapped(
AkAsyncIOTransferInfo * in_pTransfer // Transfer that will use this OVERLAPPED. Its address is stored in OVERLAPPED::hEvent.
)
{
OVERLAPPED * pOverlapped = (OVERLAPPED*)AK::MemoryMgr::GetBlock( m_poolID );
AKASSERT( pOverlapped || !"Too many concurrent transfers in the Low-Level IO" );
pOverlapped->hEvent = in_pTransfer;
return pOverlapped;
}
// Release a slot after an OVERLAPPED I/O transfer.
static inline void ReleaseOverlapped(
OVERLAPPED * in_pOverlapped // OVERLAPPED structure to release.
)
{
AK::MemoryMgr::ReleaseBlock( m_poolID, in_pOverlapped );
}
};
#endif //_AK_DEFAULT_IO_HOOK_DEFERRED_H_

View file

@ -0,0 +1,168 @@
//////////////////////////////////////////////////////////////////////
//
// AkFileHelpers.h
//
// Platform-specific helpers for files.
//
// Copyright (c) 2006 Audiokinetic Inc. / All Rights Reserved
//
//////////////////////////////////////////////////////////////////////
#ifndef _AK_FILE_HELPERS_H_
#define _AK_FILE_HELPERS_H_
#include <AK/Tools/Common/AkAssert.h>
#include <windows.h>
#include <AK/SoundEngine/Common/IAkStreamMgr.h>
class CAkFileHelpers
{
public:
// Wrapper for Win32 CreateFile().
static AKRESULT OpenFile(
const AkOSChar* in_pszFilename, // File name.
AkOpenMode in_eOpenMode, // Open mode.
bool in_bOverlappedIO, // Use FILE_FLAG_OVERLAPPED flag.
bool in_bUnbufferedIO, // Use FILE_FLAG_NO_BUFFERING flag.
AkFileHandle & out_hFile // Returned file identifier/handle.
)
{
// Check parameters.
if ( !in_pszFilename )
{
AKASSERT( !"NULL file name" );
return AK_InvalidParameter;
}
// Open mode
DWORD dwShareMode;
DWORD dwAccessMode;
DWORD dwCreationDisposition;
switch ( in_eOpenMode )
{
case AK_OpenModeRead:
dwShareMode = FILE_SHARE_READ;
dwAccessMode = GENERIC_READ;
dwCreationDisposition = OPEN_EXISTING;
break;
case AK_OpenModeWrite:
dwShareMode = FILE_SHARE_WRITE;
dwAccessMode = GENERIC_WRITE;
dwCreationDisposition = OPEN_ALWAYS;
break;
case AK_OpenModeWriteOvrwr:
dwShareMode = FILE_SHARE_WRITE;
dwAccessMode = GENERIC_WRITE;
dwCreationDisposition = CREATE_ALWAYS;
break;
case AK_OpenModeReadWrite:
dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
dwAccessMode = GENERIC_READ | GENERIC_WRITE;
dwCreationDisposition = OPEN_ALWAYS;
break;
default:
AKASSERT( !"Invalid open mode" );
out_hFile = NULL;
return AK_InvalidParameter;
break;
}
// Flags
DWORD dwFlags = FILE_FLAG_SEQUENTIAL_SCAN;
if ( in_bUnbufferedIO && in_eOpenMode == AK_OpenModeRead )
dwFlags |= FILE_FLAG_NO_BUFFERING;
if ( in_bOverlappedIO )
dwFlags |= FILE_FLAG_OVERLAPPED;
// Create the file handle.
#ifdef AK_USE_METRO_API
out_hFile = ::CreateFile2(
in_pszFilename,
dwAccessMode,
dwShareMode,
dwCreationDisposition,
NULL );
#else
out_hFile = ::CreateFileW(
in_pszFilename,
dwAccessMode,
dwShareMode,
NULL,
dwCreationDisposition,
dwFlags,
NULL );
#endif
if( out_hFile == INVALID_HANDLE_VALUE )
{
DWORD dwAllocError = ::GetLastError();
if ( ERROR_FILE_NOT_FOUND == dwAllocError ||
ERROR_PATH_NOT_FOUND == dwAllocError )
return AK_FileNotFound;
return AK_Fail;
}
return AK_Success;
}
// Wrapper for system file handle closing.
static AKRESULT CloseFile( AkFileHandle in_hFile )
{
if ( ::CloseHandle( in_hFile ) )
return AK_Success;
AKASSERT( !"Failed to close file handle" );
return AK_Fail;
}
//
// Simple platform-independent API to open and read files using AkFileHandles,
// with blocking calls and minimal constraints.
// ---------------------------------------------------------------------------
// Open file to use with ReadBlocking().
static AKRESULT OpenBlocking(
const AkOSChar* in_pszFilename, // File name.
AkFileHandle & out_hFile // Returned file handle.
)
{
return OpenFile(
in_pszFilename,
AK_OpenModeRead,
false,
false,
out_hFile );
}
// Required block size for reads (used by ReadBlocking() below).
static const AkUInt32 s_uRequiredBlockSize = 1;
// Simple blocking read method.
static AKRESULT ReadBlocking(
AkFileHandle & in_hFile, // Returned file identifier/handle.
void * in_pBuffer, // Buffer. Must be aligned on CAkFileHelpers::s_uRequiredBlockSize boundary.
AkUInt32 in_uPosition, // Position from which to start reading.
AkUInt32 in_uSizeToRead, // Size to read. Must be a multiple of CAkFileHelpers::s_uRequiredBlockSize.
AkUInt32 & out_uSizeRead // Returned size read.
)
{
AKASSERT( in_uSizeToRead % s_uRequiredBlockSize == 0
&& in_uPosition % s_uRequiredBlockSize == 0 );
#ifdef AK_USE_METRO_API
LARGE_INTEGER uPosition;
uPosition.QuadPart = in_uPosition;
if ( SetFilePointerEx( in_hFile, uPosition, NULL, FILE_BEGIN ) == FALSE )
return AK_Fail;
#else
if ( SetFilePointer( in_hFile, in_uPosition, NULL, FILE_BEGIN ) != in_uPosition )
return AK_Fail;
#endif
if ( ::ReadFile( in_hFile, in_pBuffer, in_uSizeToRead, &out_uSizeRead, NULL ) )
return AK_Success;
return AK_Fail;
}
};
#endif //_AK_FILE_HELPERS_H_

View file

@ -0,0 +1,31 @@
//////////////////////////////////////////////////////////////////////
//
// AkFilePackageLowLevelIOBlocking.h
//
// Extends the CAkDefaultIOHookBlocking low level I/O hook with File
// Package handling functionality.
//
// See AkDefaultIOHookBlocking.h for details on using the blocking
// low level I/O hook.
//
// See AkFilePackageLowLevelIO.h for details on using file packages.
//
// Copyright (c) 2006 Audiokinetic Inc. / All Rights Reserved
//
//////////////////////////////////////////////////////////////////////
#ifndef _AK_FILE_PACKAGE_LOW_LEVEL_IO_BLOCKING_H_
#define _AK_FILE_PACKAGE_LOW_LEVEL_IO_BLOCKING_H_
#include "../Common/AkFilePackageLowLevelIO.h"
#include "AkDefaultIOHookBlocking.h"
class CAkFilePackageLowLevelIOBlocking
: public CAkFilePackageLowLevelIO<CAkDefaultIOHookBlocking>
{
public:
CAkFilePackageLowLevelIOBlocking() {}
virtual ~CAkFilePackageLowLevelIOBlocking() {}
};
#endif //_AK_FILE_PACKAGE_LOW_LEVEL_IO_BLOCKING_H_

View file

@ -0,0 +1,49 @@
//////////////////////////////////////////////////////////////////////
//
// AkFilePackageLowLevelIODeferred.h
//
// Extends the CAkDefaultIOHookDeferred low level I/O hook with File
// Package handling functionality.
//
// See AkDefaultIOHookBlocking.h for details on using the deferred
// low level I/O hook.
//
// See AkFilePackageLowLevelIO.h for details on using file packages.
//
// Copyright (c) 2006 Audiokinetic Inc. / All Rights Reserved
//
//////////////////////////////////////////////////////////////////////
#ifndef _AK_FILE_PACKAGE_LOW_LEVEL_IO_DEFERRED_H_
#define _AK_FILE_PACKAGE_LOW_LEVEL_IO_DEFERRED_H_
#include "../Common/AkFilePackageLowLevelIO.h"
#include "AkDefaultIOHookDeferred.h"
class CAkFilePackageLowLevelIODeferred
: public CAkFilePackageLowLevelIO<CAkDefaultIOHookDeferred>
{
public:
CAkFilePackageLowLevelIODeferred() {}
virtual ~CAkFilePackageLowLevelIODeferred() {}
// Override Cancel: The Windows platform SDK only permits cancellations of all transfers
// for a given file handle. Since the packaged files share the same handle, we cannot do this.
void Cancel(
AkFileDesc & in_fileDesc, // File descriptor.
AkAsyncIOTransferInfo & io_transferInfo, // Transfer info to cancel.
bool & io_bCancelAllTransfersForThisFile // Flag indicating whether all transfers should be cancelled for this file (see notes in function description).
)
{
if ( !IsInPackage( in_fileDesc ) )
{
CAkDefaultIOHookDeferred::Cancel(
in_fileDesc, // File descriptor.
io_transferInfo, // Transfer info to cancel.
io_bCancelAllTransfersForThisFile // Flag indicating whether all transfers should be cancelled for this file (see notes in function description).
);
}
}
};
#endif //_AK_FILE_PACKAGE_LOW_LEVEL_IO_DEFERRED_H_

View file

@ -0,0 +1,368 @@
#include "WwiseSound.h"
#include "BFApp.h"
#if (_MSC_VER != 1800)
#undef BF_WWISE_ENABLED
#endif
#ifdef BF_WWISE_ENABLED
#if _DEBUG
#define BF_IS_WWISE_COMM_ENABLED 1
#endif
#include "AK/SoundEngine/Common/AkTypes.h"
#include <AK/SoundEngine/Common/AkMemoryMgr.h> // Memory Manager
#include <AK/SoundEngine/Common/AkModule.h> // Default memory and stream managers
#include <AK/SoundEngine/Common/IAkStreamMgr.h> // Streaming Manager
#include <AK/SoundEngine/Common/AkSoundEngine.h> // Sound engine
#include <AK/MusicEngine/Common/AkMusicEngine.h> // Music Engine
#include <AK/SoundEngine/Common/AkStreamMgrModule.h> // AkStreamMgrModule
#include <AK/Plugin/AllPluginsFactories.h>
#include "Win32/AkDefaultIOHookBlocking.h"
#ifndef AK_OPTIMIZED
#include <AK/Comm/AkCommunication.h> // Communication between Wwise and the game (excluded in release build)
#endif
/*
AkMusicEngine.lib
AkHarmonizerFX.lib
AkPitchShifterFX.lib
AkStereoDelayFX.lib
AkTimeStretchFX.lib
AkMeterFX.lib
AkConvolutionReverbFX.lib
AkAudioInputSource.lib
AkSilenceSource.lib
AkPeakLimiterFX.lib
AkRoomVerbFX.lib
AkParametricEQFX.lib
AkGainFX.lib
AkDelayFX.lib
AkMatrixReverbFX.lib
AkExpanderFX.lib
AkCompressorFX.lib
AkSineSource.lib
AkGuitarDistortionFX.lib
AkTremoloFX.lib
AkFlangerFX.lib
AkToneSource.lib
AkSoundSeedImpactFX.lib
McDSPLimiterFX.lib McDSPFutzBoxFX.lib AkSoundSeedWoosh.lib AkSoundSeedWind.lib AkStreamMgr.lib AkVorbisDecoder.lib ;%(AdditionalDependencies)*/
//iZHybridReverbFX.lib iZTrashBoxModelerFX.lib iZTrashDelayFX.lib iZTrashDistortionFX.lib iZTrashDynamicsFX.lib iZTrashFiltersFX.lib iZTrashMultibandDistortionFX.lib McDSPLimiterFX.lib
#pragma comment(lib, "AkSoundEngine.lib")
#pragma comment(lib, "AkMemoryMgr.lib")
#pragma comment(lib, "AkStreamMgr.lib")
#pragma comment(lib, "AkMusicEngine.lib")
#pragma comment(lib, "AkVorbisDecoder.lib")
#pragma comment(lib, "AkAudioInputSource.lib")
#pragma comment(lib, "AkToneSource.lib")
#pragma comment(lib, "AkSilenceSource.lib")
#pragma comment(lib, "AkSineSource.lib")
//#pragma comment(lib, "AkMP3Source.lib")
#pragma comment(lib, "AkMatrixReverbFX.lib")
#pragma comment(lib, "AkMeterFX.lib")
#pragma comment(lib, "AkParametricEQFX.lib")
#pragma comment(lib, "AkGainFX.lib")
#pragma comment(lib, "AkDelayFX.lib")
#pragma comment(lib, "AkCompressorFX.lib")
#pragma comment(lib, "AkExpanderFX.lib")
#pragma comment(lib, "AkPeakLimiterFX.lib")
#pragma comment(lib, "AkRoomVerbFX.lib")
#pragma comment(lib, "AkGuitarDistortionFX.lib")
#pragma comment(lib, "AkFlangerFX.lib")
#pragma comment(lib, "AkStereoDelayFX.lib")
#pragma comment(lib, "AkTimeStretchFX.lib")
#pragma comment(lib, "AkHarmonizerFX.lib")
#pragma comment(lib, "AkPitchShifterFX.lib")
#pragma comment(lib, "AkConvolutionReverbFX.lib")
#pragma comment(lib, "AkTremoloFX.lib")
#pragma comment(lib, "AkRumble.lib")
#pragma comment(lib, "AkMotionGenerator.lib")
#pragma comment(lib, "AkSoundSeedWind.lib")
#pragma comment(lib, "AkSoundSeedWoosh.lib")
#pragma comment(lib, "AkSoundSeedImpactFX.lib")
#pragma comment(lib, "McDSPFutzBoxFX.lib")
#pragma comment(lib, "dxguid.lib")
#ifdef BF_IS_WWISE_COMM_ENABLED
#pragma comment(lib, "CommunicationCentral.lib")
#endif
#pragma comment(lib, "wsock32.lib")
static bool gWwiseInitialized = false;
USING_NS_BF;
#define DEMO_DEFAULT_POOL_SIZE 2*1024*1024
#define DEMO_LENGINE_DEFAULT_POOL_SIZE 1*1024*1024
CAkDefaultIOHookBlocking* m_pLowLevelIO = NULL;
namespace AK
{
void * AllocHook( size_t in_size )
{
return malloc( in_size );
}
void FreeHook( void * in_ptr )
{
free( in_ptr );
}
#ifdef _WINDOWS
// Note: VirtualAllocHook() may be used by I/O pools of the default implementation
// of the Stream Manager, to allow "true" unbuffered I/O (using FILE_FLAG_NO_BUFFERING
// - refer to the Windows SDK documentation for more details). This is NOT mandatory;
// you may implement it with a simple malloc().
void * VirtualAllocHook(
void * in_pMemAddress,
size_t in_size,
DWORD in_dwAllocationType,
DWORD in_dwProtect
)
{
return VirtualAlloc( in_pMemAddress, in_size, in_dwAllocationType, in_dwProtect );
}
void VirtualFreeHook(
void * in_pMemAddress,
size_t in_size,
DWORD in_dwFreeType
)
{
VirtualFree( in_pMemAddress, in_size, in_dwFreeType );
}
#endif
}
static bool WWise_Init()
{
m_pLowLevelIO = new CAkDefaultIOHookBlocking();
AkMemSettings memSettings;
AkStreamMgrSettings stmSettings;
AkDeviceSettings deviceSettings;
AkInitSettings initSettings;
AkPlatformInitSettings platformInitSettings;
AkMusicSettings musicInit;
// Get default settings
memSettings.uMaxNumPools = 20;
AK::StreamMgr::GetDefaultSettings( stmSettings );
AK::StreamMgr::GetDefaultDeviceSettings( deviceSettings );
AK::SoundEngine::GetDefaultInitSettings( initSettings );
initSettings.uDefaultPoolSize = DEMO_DEFAULT_POOL_SIZE;
#if defined( INTEGRATIONDEMO_ASSERT_HOOK )
initSettings.pfnAssertHook = INTEGRATIONDEMO_ASSERT_HOOK;
#endif // defined( INTEGRATIONDEMO_ASSERT_HOOK )
AK::SoundEngine::GetDefaultPlatformInitSettings( platformInitSettings );
platformInitSettings.uLEngineDefaultPoolSize = DEMO_LENGINE_DEFAULT_POOL_SIZE;
AK::MusicEngine::GetDefaultInitSettings( musicInit );
//
// Create and initialize an instance of the default memory manager. Note
// that you can override the default memory manager with your own. Refer
// to the SDK documentation for more information.
//
AKRESULT res = AK::MemoryMgr::Init( &memSettings );
if ( res != AK_Success )
{
return false;
}
//
// Create and initialize an instance of the default streaming manager. Note
// that you can override the default streaming manager with your own. Refer
// to the SDK documentation for more information.
//
// Customize the Stream Manager settings here.
if ( !AK::StreamMgr::Create( stmSettings ) )
{
return false;
}
//
// Create a streaming device with blocking low-level I/O handshaking.
// Init() creates a streaming device in the Stream Manager, and registers itself as the File Location Resolver.
deviceSettings.uSchedulerTypeFlags = AK_SCHEDULER_BLOCKING;
res = m_pLowLevelIO->Init( deviceSettings );
if ( res != AK_Success )
{
return false;
}
// Set the path to the SoundBank Files.
/*#ifdef HOST_WINDOWS
std::wstring wFullPath = StringToWString(m_filePath);
m_pLowLevelIO->SetBasePath( wFullPath.c_str() );
#else
m_pLowLevelIO->SetBasePath( m_filePath.c_str() );
#endif */
//
// Create the Sound Engine
// Using default initialization parameters
//
res = AK::SoundEngine::Init( &initSettings, &platformInitSettings );
if ( res != AK_Success )
{
return false;
}
//
// Initialize the music engine
// Using default initialization parameters
//
res = AK::MusicEngine::Init( &musicInit );
if ( res != AK_Success )
{
return false;
}
#if defined HOST_MACOSX || defined HOST_IPHONEOS
// Register the AAC codec for Mac/iOS.
AK::SoundEngine::RegisterCodec(
AKCOMPANYID_AUDIOKINETIC,
AKCODECID_AAC,
CreateAACFilePlugin,
CreateAACBankPlugin );
#endif
#if BF_IS_WWISE_COMM_ENABLED
//
// Initialize communications (not in release build!)
//
AkCommSettings commSettings;
AK::Comm::GetDefaultInitSettings( commSettings );
res = AK::Comm::Init( commSettings );
if ( res != AK_Success )
{
}
#endif // BF_IS_WWISE_COMM_ENABLED
gWwiseInitialized = true;
return true;
}
void Beefy::WWiseUpdate()
{
if (gWwiseInitialized)
AK::SoundEngine::RenderAudio();
}
BF_EXPORT void BF_CALLTYPE Wwise_Shutdown()
{
if (!gWwiseInitialized)
return;
#if BF_IS_WWISE_COMM_ENABLED
//
// Terminate Communication Services (not in release build!)
//
AK::Comm::Term();
#endif // BF_IS_WWISE_COMM_ENABLED
//
// Terminate the music engine
//
AK::MusicEngine::Term();
//
// Terminate the sound engine
//
AK::SoundEngine::Term();
// Terminate the streaming device and streaming manager
// SexyIOHookBlocking::Term() destroys its associated streaming device
// that lives in the Stream Manager, and unregisters itself as the File Location Resolver.
m_pLowLevelIO->Term();
delete m_pLowLevelIO;
if ( AK::IAkStreamMgr::Get() )
AK::IAkStreamMgr::Get()->Destroy();
// Terminate the Memory Manager
AK::MemoryMgr::Term();
gWwiseInitialized = false;
}
//
BF_EXPORT void* BF_CALLTYPE Wwise_LoadBankByName(const uint16* name)
{
if (!gWwiseInitialized)
WWise_Init();
std::wstring bankFileName = gBFApp->mInstallDir + UTF16Decode(name) + L".bnk";
AkBankID bankID;
AKRESULT result = AK::SoundEngine::LoadBank(bankFileName.c_str(), AK_DEFAULT_POOL_ID, bankID);
if (result != AK_Success)
return NULL;
return (void*) bankID;
}
BF_EXPORT uint32 BF_CALLTYPE Wwise_SendEvent(uint32 eventId, void* gameObject)
{
uint32 playingSound;
playingSound = AK::SoundEngine::PostEvent(eventId, (AkGameObjectID) gameObject);
return playingSound;
}
BF_EXPORT int BF_CALLTYPE Wwise_SetRTPCValue(uint32 paramId, float value, void* gameObject)
{
if (gameObject == 0)
{
if (AK::SoundEngine::SetRTPCValue(paramId, value, (AkGameObjectID) AK_INVALID_GAME_OBJECT) == AK_Success)
return true;
}
else
{
if (AK::SoundEngine::SetRTPCValue(paramId, value, (AkGameObjectID) gameObject) == AK_Success)
return true;
}
return false;
}
#else
void Beefy::WWiseUpdate()
{
}
BF_EXPORT void* BF_CALLTYPE Wwise_LoadBankByName(const uint16* name)
{
return NULL;
}
BF_EXPORT uint32 BF_CALLTYPE Wwise_SendEvent(uint32 eventId, void* gameObject)
{
return 0;
}
BF_EXPORT int BF_CALLTYPE Wwise_SetRTPCValue(uint32 paramId, float value, void* gameObject)
{
return false;
}
BF_EXPORT void BF_CALLTYPE Wwise_Shutdown()
{
}
#endif

View file

@ -0,0 +1,9 @@
#pragma once
#include "Common.h"
NS_BF_BEGIN;
void WWiseUpdate();
NS_BF_END;