thug/Code/Gel/Music/Xbox/p_music.cpp

1325 lines
40 KiB
C++
Raw Normal View History

2016-02-13 21:39:12 +00:00
/*****************************************************************************
** **
** Neversoft Entertainment **
** **
** Copyright (C) 1999 - All Rights Reserved **
** **
******************************************************************************
** **
** Project: GFX (Graphics Library) **
** **
** Module: Game Engine (GEL) **
** **
** File name: p_music.cpp **
** **
** Created: 07/24/01 - dc **
** **
** Description: Xbox specific .wma streaming code **
** **
*****************************************************************************/
/*****************************************************************************
** Includes **
*****************************************************************************/
#include <xtl.h>
#include <core/macros.h>
#include <core/defines.h>
#include <core/math.h>
#include <core/crc.h>
#include <sys/config/config.h>
#include <gel/soundfx/soundfx.h>
#include "p_music.h"
#include "p_wmafilestream.h"
#include "p_adpcmfilestream.h"
#include "p_soundtrack.h"
/*****************************************************************************
** DBG Information **
*****************************************************************************/
/*****************************************************************************
** Externals **
*****************************************************************************/
namespace Pcm
{
/*****************************************************************************
** Defines **
*****************************************************************************/
#define STREAMS_ARE_PCM
/*****************************************************************************
** Private Types **
*****************************************************************************/
/******************************************************************/
/* */
/* */
/******************************************************************/
struct sFileStreamInfo
{
enum FileStreamType
{
FILESTREAM_TYPE_WMA = 0,
FILESTREAM_TYPE_ADPCM = 1
};
// These two could really be a union...
CWMAFileStream* p_wma_filestream;
CADPCMFileStream* p_adpcm_filestream;
int pitch;
float volume;
bool paused;
void CreateFileStream( FileStreamType type, bool use_3d = false );
void DestroyFileStream( void );
HRESULT Initialize( HANDLE h_file, void* fileBuffer );
HRESULT Initialize( HANDLE h_file, unsigned int offset, unsigned int length, void* fileBuffer );
HRESULT Process( void );
void Pause( uint32 pause );
void SetOkayToPlay( bool okay_to_play );
bool GetOkayToPlay( void );
bool HasFileStream( void ) { return (( p_wma_filestream != NULL ) || ( p_adpcm_filestream != NULL )); }
bool IsCompleted( void );
bool IsAwaitingDeletion( void );
void SetAwaitingDeletion( bool is_awaiting );
bool IsSafeToDelete( void );
void Flush( void );
bool IsPreLoadDone( void );
void SetVolume( float v0 );
void SetVolume( float v0, float v1 );
void SetVolume( float v0, float v1, float v2, float v3, float v4 );
};
/******************************************************************/
/* */
/* */
/******************************************************************/
void sFileStreamInfo::CreateFileStream( FileStreamType type, bool use_3d )
{
Dbg_Assert(( p_wma_filestream == NULL ) && ( p_adpcm_filestream == NULL ));
if( type == FILESTREAM_TYPE_WMA )
{
p_wma_filestream = new CWMAFileStream( use_3d );
}
else if( type == FILESTREAM_TYPE_ADPCM )
{
p_adpcm_filestream = new CADPCMFileStream( use_3d );
}
else
{
Dbg_Assert( 0 );
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void sFileStreamInfo::DestroyFileStream( void )
{
if( p_wma_filestream )
{
delete p_wma_filestream;
p_wma_filestream = NULL;
}
if( p_adpcm_filestream )
{
delete p_adpcm_filestream;
p_adpcm_filestream = NULL;
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
HRESULT sFileStreamInfo::Initialize( HANDLE h_file, void* fileBuffer )
{
if( p_wma_filestream )
{
return p_wma_filestream->Initialize( h_file, fileBuffer );
}
else if( p_adpcm_filestream )
{
Dbg_Assert( 0 );
}
return -1;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
HRESULT sFileStreamInfo::Initialize( HANDLE h_file, unsigned int offset, unsigned int length, void* fileBuffer )
{
if( p_wma_filestream )
{
return p_wma_filestream->Initialize( h_file, offset, length, fileBuffer );
}
else if( p_adpcm_filestream )
{
return p_adpcm_filestream->Initialize( h_file, offset, length, fileBuffer );
}
return -1;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
HRESULT sFileStreamInfo::Process( void )
{
if( p_wma_filestream )
{
return p_wma_filestream->Process();
}
else if( p_adpcm_filestream )
{
return p_adpcm_filestream->Process();
}
return -1;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void sFileStreamInfo::Pause( uint32 pause )
{
if( p_wma_filestream )
{
p_wma_filestream->Pause( pause );
}
else if( p_adpcm_filestream )
{
p_adpcm_filestream->Pause( pause );
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void sFileStreamInfo::SetOkayToPlay( bool okay_to_play )
{
if( p_wma_filestream )
{
p_wma_filestream->m_bOkayToPlay = okay_to_play;
}
else if( p_adpcm_filestream )
{
p_adpcm_filestream->m_bOkayToPlay = okay_to_play;
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool sFileStreamInfo::GetOkayToPlay( void )
{
if( p_wma_filestream )
{
return p_wma_filestream->m_bOkayToPlay;
}
else if( p_adpcm_filestream )
{
return p_adpcm_filestream->m_bOkayToPlay;
}
return false;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool sFileStreamInfo::IsCompleted( void )
{
if( p_wma_filestream )
{
return p_wma_filestream->IsCompleted();
}
else if( p_adpcm_filestream )
{
return p_adpcm_filestream->IsCompleted();
}
return false;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool sFileStreamInfo::IsAwaitingDeletion( void )
{
if( p_wma_filestream )
{
return p_wma_filestream->m_AwaitingDeletion;
}
else if( p_adpcm_filestream )
{
return p_adpcm_filestream->m_AwaitingDeletion;
}
return false;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void sFileStreamInfo::SetAwaitingDeletion( bool is_awaiting )
{
if( p_wma_filestream )
{
p_wma_filestream->m_AwaitingDeletion = is_awaiting;
}
else if( p_adpcm_filestream )
{
p_adpcm_filestream->m_AwaitingDeletion = is_awaiting;
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool sFileStreamInfo::IsSafeToDelete( void )
{
if( p_wma_filestream )
{
return p_wma_filestream->IsSafeToDelete();
}
else if( p_adpcm_filestream )
{
return p_adpcm_filestream->IsSafeToDelete();
}
return false;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool sFileStreamInfo::IsPreLoadDone( void )
{
if( p_wma_filestream )
{
return p_wma_filestream->PreLoadDone();
}
else if( p_adpcm_filestream )
{
return p_adpcm_filestream->PreLoadDone();
}
return false;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void sFileStreamInfo::Flush( void )
{
if( p_wma_filestream )
{
if( p_wma_filestream->m_pRenderFilter )
{
p_wma_filestream->m_pRenderFilter->FlushEx( 0, DSSTREAMFLUSHEX_ASYNC );
}
}
else if( p_adpcm_filestream )
{
if( p_adpcm_filestream->m_pRenderFilter )
{
p_adpcm_filestream->m_pRenderFilter->FlushEx( 0, DSSTREAMFLUSHEX_ASYNC );
}
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void sFileStreamInfo::SetVolume( float v0 )
{
if( p_wma_filestream )
{
p_wma_filestream->SetVolume( v0 );
}
else if( p_adpcm_filestream )
{
p_adpcm_filestream->SetVolume( v0 );
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void sFileStreamInfo::SetVolume( float v0, float v1 )
{
if( p_wma_filestream )
{
p_wma_filestream->SetVolume( v0, v1 );
}
else if( p_adpcm_filestream )
{
p_adpcm_filestream->SetVolume( v0, v1 );
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void sFileStreamInfo::SetVolume( float v0, float v1, float v2, float v3, float v4 )
{
if( p_wma_filestream )
{
p_wma_filestream->SetVolume( v0, v1, v2, v3, v4 );
}
else if( p_adpcm_filestream )
{
p_adpcm_filestream->SetVolume( v0, v1, v2, v3, v4 );
}
}
/*****************************************************************************
** Private Data **
*****************************************************************************/
sFileStreamInfo gMusicInfo;
sFileStreamInfo gStreamInfo[NUM_STREAMS];
const uint32 FILESTREAM_BUFFER_SIZE = 80 * 1024;
#pragma pack( 16 )
// Grab an 80k read buffer. Must be DWORD aligned.
// This is big enough for (9 * 8k packets) for WMA, where last packet mirrors the first packet,
// for cases when the decoder reads past the end of the ring buffer.
// Also big enough for ( 5 * 16k packets) for ADPCM, where no wraparound is required.
DWORD gMusicFileBuffer[FILESTREAM_BUFFER_SIZE / 4];
DWORD gStreamFileBuffer[NUM_STREAMS][FILESTREAM_BUFFER_SIZE / 4];
#pragma pack()
const int NUM_OVERLAPPED = 256;
OVERLAPPED gOverlapped[NUM_OVERLAPPED];
int gNextOverlap = 0;
/*****************************************************************************
** Public Data **
*****************************************************************************/
HANDLE ghWADFile = INVALID_HANDLE_VALUE;
uint32 *pWADData = NULL;
uint32 numWADFileEntries = 0;
HANDLE ghMusicWADFile = INVALID_HANDLE_VALUE;
uint32 *pMusicWADData = NULL;
uint32 numMusicWADFileEntries = 0;
/*****************************************************************************
** Private Prototypes **
*****************************************************************************/
/*****************************************************************************
** Private Functions **
*****************************************************************************/
/*****************************************************************************
** Public Functions **
*****************************************************************************/
/******************************************************************/
/* */
/* */
/******************************************************************/
OVERLAPPED *PCMAudio_GetNextOverlapped( void )
{
OVERLAPPED *p_return = &( gOverlapped[gNextOverlap] );
if( ++gNextOverlap >= NUM_OVERLAPPED )
{
gNextOverlap = 0;
}
ZeroMemory( p_return, sizeof( OVERLAPPED ));
return p_return;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
uint32 PCMAudio_GetFilestreamBufferSize( void )
{
return FILESTREAM_BUFFER_SIZE;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void PCMAudio_Init( void )
{
// Zero the music and filestream info arrays.
ZeroMemory( &gMusicInfo, sizeof( sFileStreamInfo ));
ZeroMemory( &gStreamInfo[0], sizeof( sFileStreamInfo ) * NUM_STREAMS );
// Enumerate user soundtracks.
GetNumSoundtracks();
// Figure out the language, and open appropriate file.
Config::ELanguage lang = Config::GetLanguage();
// Assume English.
# ifdef STREAMS_ARE_PCM
ghWADFile = CreateFile( "d:\\data\\streams\\pcm\\pcm.wad",
# else
ghWADFile = CreateFile( "d:\\data\\streams\\wma\\wma.wad",
# endif
GENERIC_READ,
FILE_SHARE_READ, // Share mode.
NULL, // Ignored (security attributes).
OPEN_EXISTING, // File has to exist already.
FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING, // Xbox has no asynchronous i/o buffering.
NULL ); // Ignored (template file).
# ifdef STREAMS_ARE_PCM
ghMusicWADFile = CreateFile( "d:\\data\\streams\\pcm\\music_pcm.wad",
# else
ghMusicWADFile = CreateFile( "d:\\data\\streams\\wma\\music_wma.wad",
# endif
GENERIC_READ,
FILE_SHARE_READ, // Share mode.
NULL, // Ignored (security attributes).
OPEN_EXISTING, // File has to exist already.
FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING, // Xbox has no asynchronous i/o buffering.
NULL ); // Ignored (template file).
// Now read in the data files used for indexing into the WAD files.
# ifdef STREAMS_ARE_PCM
HANDLE wad_data = CreateFile( "d:\\data\\streams\\pcm\\pcm.dat",
# else
HANDLE wad_data = CreateFile( "d:\\data\\streams\\wma\\wma.dat",
# endif
GENERIC_READ,
FILE_SHARE_READ, // Share mode.
NULL, // Ignored (security attributes).
OPEN_EXISTING, // File has to exist already.
FILE_FLAG_SEQUENTIAL_SCAN,
NULL ); // Ignored (template file).
if( wad_data != INVALID_HANDLE_VALUE )
{
uint32 bytes_read;
ReadFile( wad_data, &numWADFileEntries, sizeof( uint32 ), &bytes_read, NULL );
pWADData = new uint32[numWADFileEntries * 3];
ReadFile( wad_data, pWADData, sizeof( uint32 ) * numWADFileEntries * 3, &bytes_read, NULL );
CloseHandle( wad_data );
}
// Sort the wad file entries into increasing checksum order, so that we can use a binary search algorithm to
// find the checksum quickly.
for( uint32 i = 0; i < numWADFileEntries; ++i )
{
for( uint32 j = i + 1; j < numWADFileEntries; ++j )
{
if( pWADData[i * 3] > pWADData[j * 3] )
{
uint32 temp[3];
temp[0] = pWADData[i * 3];
temp[1] = pWADData[i * 3 + 1];
temp[2] = pWADData[i * 3 + 2];
pWADData[i * 3] = pWADData[j * 3];
pWADData[i * 3 + 1] = pWADData[j * 3 + 1];
pWADData[i * 3 + 2] = pWADData[j * 3 + 2];
pWADData[j * 3] = temp[0];
pWADData[j * 3 + 1] = temp[1];
pWADData[j * 3 + 2] = temp[2];
}
}
}
# ifdef STREAMS_ARE_PCM
wad_data = CreateFile( "d:\\data\\streams\\pcm\\music_pcm.dat",
# else
wad_data = CreateFile( "d:\\data\\streams\\wma\\music_wma.dat",
# endif
GENERIC_READ,
FILE_SHARE_READ, // Share mode.
NULL, // Ignored (security attributes).
OPEN_EXISTING, // File has to exist already.
FILE_FLAG_SEQUENTIAL_SCAN,
NULL ); // Ignored (template file).
if( wad_data != INVALID_HANDLE_VALUE )
{
uint32 bytes_read;
ReadFile( wad_data, &numMusicWADFileEntries, sizeof( uint32 ), &bytes_read, NULL );
pMusicWADData = new uint32[numMusicWADFileEntries * 3];
ReadFile( wad_data, pMusicWADData, sizeof( uint32 ) * numMusicWADFileEntries * 3, &bytes_read, NULL );
CloseHandle( wad_data );
}
}
/******************************************************************/
/* */
/* Call every frame to make sure music and stream buffers are */
/* loaded and current status is checked each frame... */
/* */
/******************************************************************/
int PCMAudio_Update( void )
{
if( gMusicInfo.HasFileStream())
{
HRESULT hr = gMusicInfo.Process();
if( gMusicInfo.IsCompleted())
{
gMusicInfo.DestroyFileStream();
}
else if( gMusicInfo.IsAwaitingDeletion() && gMusicInfo.IsSafeToDelete())
{
gMusicInfo.DestroyFileStream();
}
}
for( int i = 0; i < NUM_STREAMS; ++i )
{
if( gStreamInfo[i].HasFileStream())
{
HRESULT hr = gStreamInfo[i].Process();
if( gStreamInfo[i].IsCompleted())
{
gStreamInfo[i].DestroyFileStream();
}
else if( gStreamInfo[i].IsAwaitingDeletion() && gStreamInfo[i].IsSafeToDelete())
{
gStreamInfo[i].DestroyFileStream();
}
}
}
// A non-zero return value singnals an error condition.
return 0;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void PCMAudio_StopMusic( bool waitPlease )
{
if( gMusicInfo.HasFileStream())
{
if( gMusicInfo.IsSafeToDelete())
{
gMusicInfo.Flush();
gMusicInfo.DestroyFileStream();
}
else
{
gMusicInfo.SetAwaitingDeletion( true );
}
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void PCMAudio_StopStream( int whichStream, bool waitPlease )
{
if( gStreamInfo[whichStream].HasFileStream())
{
if( gStreamInfo[whichStream].IsSafeToDelete())
{
gStreamInfo[whichStream].Flush();
gStreamInfo[whichStream].DestroyFileStream();
}
else
{
gStreamInfo[whichStream].SetAwaitingDeletion( true );
}
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void PCMAudio_StopStreams( void )
{
for( int i = 0; i < NUM_STREAMS; ++i )
{
PCMAudio_StopStream( i, false );
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
// This is temp code for the preload streams. It just calls the normal one.
static uint32 sPreLoadChecksum[NUM_STREAMS];
static uint32 sPreLoadMusicChecksum;
/******************************************************************/
/* */
/* Get a stream loaded into a buffer, but don't play yet */
/* */
/******************************************************************/
bool PCMAudio_PreLoadStream( uint32 checksum, int whichStream )
{
Dbg_Assert(( whichStream >= 0 ) && ( whichStream < NUM_STREAMS ));
sPreLoadChecksum[whichStream] = checksum;
// Start the track as normal...
if( PCMAudio_PlayStream( checksum, whichStream, NULL, 0.0f, false ))
{
// ...but then flag it as not okay to play until we say so.
if( gStreamInfo[whichStream].HasFileStream())
{
gStreamInfo[whichStream].SetOkayToPlay( false );
}
return true;
}
return false;
}
/******************************************************************/
/* */
/* Returns true if preload done. Assumes that caller is calling */
/* this on a preloaded, but not yet played, stream. The results */
/* are meaningless otherwise. */
/* */
/******************************************************************/
bool PCMAudio_PreLoadStreamDone( int whichStream )
{
if( gStreamInfo[whichStream].HasFileStream())
{
return gStreamInfo[whichStream].IsPreLoadDone();
}
return true;
}
/******************************************************************/
/* */
/* Tells a preloaded stream to start playing. */
/* Must call PCMAudio_PreLoadStreamDone() first to guarantee that */
/* it starts immediately. */
/* */
/******************************************************************/
bool PCMAudio_StartPreLoadedStream( int whichStream, Sfx::sVolume *p_volume, float pitch )
{
// Maybe we should check here to make sure the checksum of the music info filestream matches that
// passed in when the music stream preload request came in.
if( gStreamInfo[whichStream].HasFileStream())
{
gStreamInfo[whichStream].SetOkayToPlay( true );
PCMAudio_SetStreamVolume( p_volume, whichStream );
return true;
}
return false;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool PCMAudio_PreLoadMusicStream( uint32 checksum )
{
sPreLoadMusicChecksum = checksum;
// Start the track as normal...
if( PCMAudio_PlayMusicTrack( sPreLoadMusicChecksum ))
{
// ...but then flag it as not okay to play until we say so.
if( gMusicInfo.HasFileStream())
{
gMusicInfo.SetOkayToPlay( false );
}
return true;
}
return false;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool PCMAudio_PreLoadMusicStreamDone( void )
{
if( gMusicInfo.HasFileStream())
{
return gMusicInfo.IsPreLoadDone();
}
return true;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool PCMAudio_StartPreLoadedMusicStream( void )
{
// Maybe we should check here to make sure the checksum of the music info filestream matches that
// passed in when the music stream preload request came in.
if( gMusicInfo.HasFileStream())
{
// Call update immediately to start playback ASAP.
gMusicInfo.SetOkayToPlay( true );
PCMAudio_Update();
return true;
}
return false;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
int PCMAudio_GetMusicStatus( void )
{
if( gMusicInfo.HasFileStream())
{
return PCM_STATUS_PLAYING;
}
else
{
return PCM_STATUS_FREE;
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
int PCMAudio_GetStreamStatus( int whichStream )
{
int start, end;
// Negative one is used to signal 'any stream'.
if( whichStream == -1 )
{
start = 0;
end = NUM_STREAMS;
}
else
{
start = whichStream;
end = start + 1;
}
for( int s = start; s < end; ++s )
{
if( !gStreamInfo[s].HasFileStream())
{
return PCM_STATUS_FREE;
}
}
return PCM_STATUS_PLAYING;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void PCMAudio_Pause( bool pause, int ch )
{
if( ch == MUSIC_CHANNEL )
{
gMusicInfo.paused = pause;
if( gMusicInfo.HasFileStream())
{
if( pause )
{
gMusicInfo.Pause( 1 );
}
else
{
gMusicInfo.Pause( 0 );
}
}
}
else
{
for( int s = 0; s < NUM_STREAMS; ++s )
{
if( gStreamInfo[s].HasFileStream())
{
if( pause )
{
gStreamInfo[s].Pause( 1 );
gStreamInfo[s].paused = true;
}
else
{
gStreamInfo[s].Pause( 0 );
gStreamInfo[s].paused = false;
}
}
}
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool PCMAudio_TrackExists( const char *pTrackName, int ch )
{
return true;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool PCMAudio_LoadMusicHeader( const char *nameOfFile )
{
// Legacy call left over from PS2 code.
return true;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool PCMAudio_LoadStreamHeader( const char *nameOfFile )
{
// Legacy call left over from PS2 code.
return true;
}
/******************************************************************/
/* */
/* Return (any) position if t in sorted x[0..n-1] or -1 if t is */
/* not present. */
/* */
/******************************************************************/
static int binarySearch( uint32 checksum )
{
int l = 0;
int u = numWADFileEntries - 1;
while( l <= u )
{
int m = ( l + u ) / 2;
if( pWADData[m * 3] < checksum )
l = m + 1;
else if ( pWADData[m * 3] == checksum )
return m;
else // x[m] > t
u = m - 1;
}
return -1;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
uint32 PCMAudio_FindNameFromChecksum( uint32 checksum, int ch )
{
if( ch != EXTRA_CHANNEL )
return 0;
int rv = binarySearch( checksum );
return ( rv == -1 ) ? 0 : checksum;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool PCMAudio_SetStreamVolume( Sfx::sVolume *p_volume, int whichStream )
{
if( gStreamInfo[whichStream].HasFileStream())
{
// Adjust volumes for overall sound volume.
Spt::SingletonPtr< Sfx::CSfxManager > sfx_manager;
switch( p_volume->GetVolumeType())
{
case Sfx::VOLUME_TYPE_5_CHANNEL_DOLBY5_1:
{
float v0 = PERCENT( sfx_manager->GetMainVolume(), p_volume->GetChannelVolume( 0 ));
float v1 = PERCENT( sfx_manager->GetMainVolume(), p_volume->GetChannelVolume( 1 ));
float v2 = PERCENT( sfx_manager->GetMainVolume(), p_volume->GetChannelVolume( 2 ));
float v3 = PERCENT( sfx_manager->GetMainVolume(), p_volume->GetChannelVolume( 3 ));
float v4 = PERCENT( sfx_manager->GetMainVolume(), p_volume->GetChannelVolume( 4 ));
gStreamInfo[whichStream].volume = ( v0 + v1 + v2 + v3 + v4 ) * ( 1.0f / 5.0f );
gStreamInfo[whichStream].SetVolume( v0, v1, v2, v3, v4 );
break;
}
case Sfx::VOLUME_TYPE_2_CHANNEL_DOLBYII:
{
float v0 = PERCENT( sfx_manager->GetMainVolume(), p_volume->GetChannelVolume( 0 ));
float v1 = PERCENT( sfx_manager->GetMainVolume(), p_volume->GetChannelVolume( 1 ));
gStreamInfo[whichStream].volume = v0;
gStreamInfo[whichStream].SetVolume( v0, v1 );
break;
}
case Sfx::VOLUME_TYPE_BASIC_2_CHANNEL:
{
float v0 = PERCENT( sfx_manager->GetMainVolume(), p_volume->GetChannelVolume( 0 ));
gStreamInfo[whichStream].volume = v0;
gStreamInfo[whichStream].SetVolume( v0 );
break;
}
default:
{
Dbg_Assert( 0 );
break;
}
}
}
return true;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
int PCMAudio_SetMusicVolume( float volume )
{
if( gMusicInfo.HasFileStream())
{
gMusicInfo.volume = volume;
gMusicInfo.SetVolume( volume );
}
return true;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool PCMAudio_SetStreamPitch( float fPitch, int whichStream )
{
return true;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool PCMAudio_PlayMusicTrack( uint32 checksum )
{
// Find the entry in the offset array.
bool found = false;
unsigned int samplelength, sampleoffset;
// English.
for( unsigned int entry = 0; entry < numMusicWADFileEntries; ++entry )
{
if( pMusicWADData[entry * 3] == checksum )
{
sampleoffset = pMusicWADData[entry * 3 + 1];
samplelength = pMusicWADData[entry * 3 + 2];
found = true;
break;
}
}
if( !found )
{
return false;
}
// Just a stream like everything else.
if( PCMAudio_GetMusicStatus() != PCM_STATUS_FREE )
{
return false;
}
// Don't want to use 3d processing for the music track.
# ifdef STREAMS_ARE_PCM
gMusicInfo.CreateFileStream( sFileStreamInfo::FILESTREAM_TYPE_ADPCM, false );
# else
gMusicInfo.CreateFileStream( sFileStreamInfo::FILESTREAM_TYPE_WMA, false );
# endif
HRESULT hr = gMusicInfo.Initialize( ghMusicWADFile, sampleoffset, samplelength, gMusicFileBuffer );
if( hr == S_OK )
{
// All started fine. Pause music if paused flag is set.
if( gMusicInfo.paused )
{
PCMAudio_Pause( true, MUSIC_CHANNEL );
}
return true;
}
else
{
// Failed to initialize the stream.
gMusicInfo.DestroyFileStream();
Dbg_MsgAssert( 0, ( "Failed to initialize music stream: %x", checksum ));
}
return false;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool PCMAudio_PlayMusicTrack( const char *filename )
{
const char *samplename = filename;
char *locate;
// Search for the last directory seperator, and cut off all of the path prior to it.
if( locate = strrchr( samplename, '\\' ))
{
samplename = locate + 1;
}
if( locate = strrchr( samplename, '/' ))
{
samplename = locate + 1;
}
// Now generate the checksum for this samplename.
uint32 checksum = Crc::GenerateCRCFromString( samplename );
bool rv = PCMAudio_PlayMusicTrack( checksum );
if( rv == false )
{
Dbg_Message( "Failed to find stream: %s", filename );
}
return rv;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool PCMAudio_PlaySoundtrackMusicTrack( int soundtrack, int track )
{
// Just a stream like everything else.
if( gMusicInfo.HasFileStream())
{
Dbg_MsgAssert( 0, ( "Playing new track without stopping the first track." ));
}
else
{
// Don't want to use 3d processing for the music track.
gMusicInfo.CreateFileStream( sFileStreamInfo::FILESTREAM_TYPE_WMA, false );
HANDLE h_song = GetSoundtrackWMAHandle( soundtrack, track );
if( h_song == INVALID_HANDLE_VALUE )
{
return false;
}
HRESULT hr = gMusicInfo.Initialize( h_song, gMusicFileBuffer );
if( hr == S_OK )
{
// All started fine. Pause music if paused flag is set.
if( gMusicInfo.paused )
{
PCMAudio_Pause( true, MUSIC_CHANNEL );
}
return true;
}
}
return false;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool PCMAudio_StartStream( int whichStream )
{
if( gStreamInfo[whichStream].HasFileStream())
{
if( gStreamInfo[whichStream].GetOkayToPlay() == false )
{
// Now okay to start playing.
gStreamInfo[whichStream].SetOkayToPlay( true );
}
return true;
}
return false;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool PCMAudio_PlayStream( uint32 checksum, int whichStream, Sfx::sVolume *p_volume, float fPitch, bool preload )
{
unsigned int samplelength, sampleoffset;
// Perform a binary search on the checksum table to find the correct entry.
int entry = binarySearch( checksum );
if( entry >= 0 )
{
sampleoffset = pWADData[entry * 3 + 1];
samplelength = pWADData[entry * 3 + 2];
}
else
{
return false;
}
Dbg_Assert(( whichStream >= 0 ) && ( whichStream < NUM_STREAMS ));
// Just a stream like everything else.
if( PCMAudio_GetStreamStatus( whichStream ) != PCM_STATUS_FREE )
{
return false;
}
# ifdef STREAMS_ARE_PCM
gStreamInfo[whichStream].CreateFileStream( sFileStreamInfo::FILESTREAM_TYPE_ADPCM, true );
# else
gStreamInfo[whichStream].CreateFileStream( sFileStreamInfo::FILESTREAM_TYPE_WMA, true );
# endif
// The preload parameter indicates that we want to get this stream in a position where it is ready to play
// immediately at some later point in time. The m_bOkayToPlay member is used to signal this.
if( preload )
{
// Not okay to start playing until told to do so.
gStreamInfo[whichStream].SetOkayToPlay( false );
}
HRESULT hr = gStreamInfo[whichStream].Initialize( ghWADFile, sampleoffset, samplelength, &gStreamFileBuffer[whichStream][0] );
if( hr == S_OK )
{
// All started fine.
if( p_volume )
{
PCMAudio_SetStreamVolume( p_volume, whichStream );
}
return true;
}
else
{
// Failed to initialize the stream.
gStreamInfo[whichStream].DestroyFileStream();
}
return false;
}
} // namespace PCM