mirror of
https://github.com/beefytech/Beef.git
synced 2025-07-08 09:16:00 +02:00
Initial checkin
This commit is contained in:
parent
c74712dad9
commit
078564ac9e
3242 changed files with 1616395 additions and 0 deletions
151
BeefySysLib/sound/Common/AkDefaultLowLevelIODispatcher.cpp
Normal file
151
BeefySysLib/sound/Common/AkDefaultLowLevelIODispatcher.cpp
Normal 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
|
84
BeefySysLib/sound/Common/AkDefaultLowLevelIODispatcher.h
Normal file
84
BeefySysLib/sound/Common/AkDefaultLowLevelIODispatcher.h
Normal 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_
|
290
BeefySysLib/sound/Common/AkFileLocationBase.cpp
Normal file
290
BeefySysLib/sound/Common/AkFileLocationBase.cpp
Normal 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
|
85
BeefySysLib/sound/Common/AkFileLocationBase.h
Normal file
85
BeefySysLib/sound/Common/AkFileLocationBase.h
Normal 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_
|
67
BeefySysLib/sound/Common/AkFilePackage.cpp
Normal file
67
BeefySysLib/sound/Common/AkFilePackage.cpp
Normal 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
|
171
BeefySysLib/sound/Common/AkFilePackage.h
Normal file
171
BeefySysLib/sound/Common/AkFilePackage.h
Normal 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_
|
274
BeefySysLib/sound/Common/AkFilePackageLUT.cpp
Normal file
274
BeefySysLib/sound/Common/AkFilePackageLUT.cpp
Normal 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
|
207
BeefySysLib/sound/Common/AkFilePackageLUT.h
Normal file
207
BeefySysLib/sound/Common/AkFilePackageLUT.h
Normal 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_
|
399
BeefySysLib/sound/Common/AkFilePackageLowLevelIO.h
Normal file
399
BeefySysLib/sound/Common/AkFilePackageLowLevelIO.h
Normal 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_
|
468
BeefySysLib/sound/Common/AkFilePackageLowLevelIO.inl
Normal file
468
BeefySysLib/sound/Common/AkFilePackageLowLevelIO.inl
Normal 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;
|
||||
}
|
||||
|
||||
|
324
BeefySysLib/sound/Win32/AkDefaultIOHookBlocking.cpp
Normal file
324
BeefySysLib/sound/Win32/AkDefaultIOHookBlocking.cpp
Normal 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
|
177
BeefySysLib/sound/Win32/AkDefaultIOHookBlocking.h
Normal file
177
BeefySysLib/sound/Win32/AkDefaultIOHookBlocking.h
Normal 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_
|
404
BeefySysLib/sound/Win32/AkDefaultIOHookDeferred.cpp
Normal file
404
BeefySysLib/sound/Win32/AkDefaultIOHookDeferred.cpp
Normal 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
|
221
BeefySysLib/sound/Win32/AkDefaultIOHookDeferred.h
Normal file
221
BeefySysLib/sound/Win32/AkDefaultIOHookDeferred.h
Normal 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_
|
168
BeefySysLib/sound/Win32/AkFileHelpers.h
Normal file
168
BeefySysLib/sound/Win32/AkFileHelpers.h
Normal 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_
|
31
BeefySysLib/sound/Win32/AkFilePackageLowLevelIOBlocking.h
Normal file
31
BeefySysLib/sound/Win32/AkFilePackageLowLevelIOBlocking.h
Normal 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_
|
49
BeefySysLib/sound/Win32/AkFilePackageLowLevelIODeferred.h
Normal file
49
BeefySysLib/sound/Win32/AkFilePackageLowLevelIODeferred.h
Normal 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_
|
368
BeefySysLib/sound/WwiseSound.cpp
Normal file
368
BeefySysLib/sound/WwiseSound.cpp
Normal 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
|
9
BeefySysLib/sound/WwiseSound.h
Normal file
9
BeefySysLib/sound/WwiseSound.h
Normal file
|
@ -0,0 +1,9 @@
|
|||
#pragma once
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
NS_BF_BEGIN;
|
||||
|
||||
void WWiseUpdate();
|
||||
|
||||
NS_BF_END;
|
Loading…
Add table
Add a link
Reference in a new issue