This commit is contained in:
nephacks
2025-06-04 03:22:50 +02:00
parent f234f23848
commit f12416cffd
14243 changed files with 6446499 additions and 26 deletions
+149
View File
@@ -0,0 +1,149 @@
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "DevShotGenerator.h"
#include "cmd.h"
#include "fmtstr.h"
#include "host.h"
#include "tier0/icommandline.h"
#include <tier0/dbg.h>
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
#define PAUSE_FRAMES_BETWEEN_MAPS 300
#define PAUSE_TIME_BETWEEN_MAPS 2.0f
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void DevShotGenerator_Usage()
{
//
Msg( "-makedevshots usage:\n" );
Msg( " [ -usedevshotsfile filename ] -- get map list from specified file, default is to build for maps/*.bsp\n" );
Msg( " [ -startmap mapname ] -- restart generation at specified map (after crash, implies resume)\n" );
Msg( " [ -condebug ] -- prepend console.log entries with mapname or engine if not in a map\n" );
Msg( " [ +map mapname ] -- generate devshots for specified map and exit after that map\n" );
}
void DevShotGenerator_Init()
{
// check for devshot generation
if ( CommandLine()->FindParm("-makedevshots") )
{
bool usemaplistfile = false;
if ( CommandLine()->FindParm("-usedevshotsfile") )
{
usemaplistfile = true;
}
DevShotGenerator().EnableDevShotGeneration( usemaplistfile );
}
}
void DevShotGenerator_Shutdown()
{
DevShotGenerator().Shutdown();
}
void DevShotGenerator_BuildMapList()
{
DevShotGenerator().BuildMapList();
}
CDevShotGenerator g_DevShotGenerator;
CDevShotGenerator &DevShotGenerator()
{
return g_DevShotGenerator;
}
void CL_DevShots_NextMap()
{
DevShotGenerator().NextMap();
}
static ConCommand devshots_nextmap( "devshots_nextmap", CL_DevShots_NextMap, "Used by the devshots system to go to the next map in the devshots maplist." );
//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
CDevShotGenerator::CDevShotGenerator()
{
m_bUsingMapList = false;
m_bDevShotsEnabled = false;
m_iCurrentMap = 0;
}
void CDevShotGenerator::BuildMapList()
{
if ( !m_bDevShotsEnabled )
return;
DevShotGenerator_Usage();
// Get the maplist file, if any
const char *pMapFile = NULL;
CommandLine()->CheckParm( "-usedevshotsfile", &pMapFile );
// Build the map list
if ( !BuildGeneralMapList( &m_Maps, CommandLine()->FindParm("-usedevshotsfile") != 0, pMapFile, "devshots", &m_iCurrentMap ) )
{
m_bDevShotsEnabled = false;
}
}
void CDevShotGenerator::NextMap()
{
if ( !m_bDevShotsEnabled )
return;
//Msg("DEVSHOTS: Nextmap command received.\n");
if (m_Maps.IsValidIndex(m_iCurrentMap))
{
//Msg("DEVSHOTS: Switching to %s (%d).\n", m_Maps[m_iCurrentMap].name, m_iCurrentMap );
CFmtStr str("map %s\n", m_Maps[m_iCurrentMap].name);
Cbuf_AddText( Cbuf_GetCurrentPlayer(), str.Access() );
++m_iCurrentMap;
}
else
{
//Msg("DEVSHOTS: Finished on map %d.\n", m_iCurrentMap);
// no more levels, just quit
Cbuf_AddText( Cbuf_GetCurrentPlayer(), "quit\n" );
}
}
//-----------------------------------------------------------------------------
// Purpose: initializes the object to enable dev shot generation
//-----------------------------------------------------------------------------
void CDevShotGenerator::EnableDevShotGeneration( bool usemaplistfile )
{
m_bUsingMapList = usemaplistfile;
m_bDevShotsEnabled = true;
}
//-----------------------------------------------------------------------------
// Purpose: starts the first map
//-----------------------------------------------------------------------------
void CDevShotGenerator::StartDevShotGeneration()
{
BuildMapList();
CFmtStr str("map %s\n", m_Maps[m_iCurrentMap].name);
Cbuf_AddText( Cbuf_GetCurrentPlayer(), str.Access() );
++m_iCurrentMap;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CDevShotGenerator::Shutdown()
{
}
+58
View File
@@ -0,0 +1,58 @@
//====== Copyright © 1996-2003, Valve Corporation, All rights reserved. =======
//
// Purpose:
//
//=============================================================================
#ifndef DEVSHOTGENERATOR_H
#define DEVSHOTGENERATOR_H
#ifdef _WIN32
#pragma once
#endif
#include "filesystem.h"
#include "utlvector.h"
#include "utlsymbol.h"
#include "MapReslistGenerator.h"
// initialization
void DevShotGenerator_Init();
void DevShotGenerator_Shutdown();
void DevShotGenerator_BuildMapList();
//-----------------------------------------------------------------------------
// Purpose: Takes development screenshots at camera positions over a set of levels
//-----------------------------------------------------------------------------
class CDevShotGenerator
{
public:
CDevShotGenerator();
// initializes the object to enable devshot generation
void EnableDevShotGeneration( bool usemaplistfile );
// starts the dev shot generation (starts cycling maps)
void StartDevShotGeneration();
void BuildMapList();
void NextMap();
void Shutdown();
// returns true if reslist generation is enabled
bool IsEnabled() { return m_bDevShotsEnabled; }
private:
bool m_bDevShotsEnabled;
int m_iCurrentMap;
bool m_bUsingMapList;
// list of all maps to scan
CUtlVector<maplist_map_t> m_Maps;
};
// singleton accessor
CDevShotGenerator &DevShotGenerator();
#endif // DEVSHOTGENERATOR_H
+415
View File
@@ -0,0 +1,415 @@
//========= Copyright 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "mathlib/vector.h"
#include "DownloadListGenerator.h"
#include "filesystem.h"
#include "filesystem_engine.h"
#include "sys.h"
#include "cmd.h"
#include "common.h"
#include "quakedef.h"
#include "vengineserver_impl.h"
#include "tier1/strtools.h"
#include "tier0/icommandline.h"
#include "checksum_engine.h"
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <tier0/dbg.h>
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
CDownloadListGenerator g_DownloadListGenerator;
CDownloadListGenerator &DownloadListGenerator()
{
return g_DownloadListGenerator;
}
ConVar sv_logdownloadlist( "sv_logdownloadlist", "0" );
//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
CDownloadListGenerator::CDownloadListGenerator()
: m_AlreadyWrittenFileNames( 0, 0, true )
{
m_hReslistFile = FILESYSTEM_INVALID_HANDLE;
m_pStringTable = NULL;
m_mapName[0] = 0;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CDownloadListGenerator::SetStringTable( INetworkStringTable *pStringTable )
{
if ( IsX360() )
{
// not supporting
return;
}
m_pStringTable = pStringTable;
// reset the duplication list
m_AlreadyWrittenFileNames.RemoveAll();
// add in the bsp file to the list, and its node graph and nav mesh
char path[_MAX_PATH];
Q_snprintf(path, sizeof(path), "maps\\%s.bsp", m_mapName);
OnResourcePrecached(path);
bool useNodeGraph = true;
KeyValues *modinfo = new KeyValues("ModInfo");
if ( modinfo->LoadFromFile( g_pFileSystem, "gameinfo.txt" ) )
{
useNodeGraph = modinfo->GetInt( "nodegraph", 1 ) != 0;
}
modinfo->deleteThis();
if ( useNodeGraph )
{
Q_snprintf(path, sizeof(path), "maps\\graphs\\%s.ain", m_mapName);
OnResourcePrecached(path);
}
Q_snprintf(path, sizeof(path), "maps\\%s.nav", m_mapName);
OnResourcePrecached(path);
char resfilename[MAX_OSPATH];
Q_snprintf( resfilename, sizeof( resfilename), "maps/%s.res", m_mapName );
KeyValues::AutoDelete resfilekeys( "resourcefiles" );
if ( resfilekeys->LoadFromFile( g_pFileSystem, resfilename, "GAME" ) )
{
for ( KeyValues *pKey = resfilekeys->GetFirstSubKey(); pKey != NULL; pKey = pKey->GetNextKey() )
{
OnResourcePrecached( pKey->GetName() );
}
}
}
//-----------------------------------------------------------------------------
// Purpose: call to mark level load/end
//-----------------------------------------------------------------------------
void CDownloadListGenerator::OnLevelLoadStart(const char *levelName)
{
if ( IsX360() )
{
// not supporting
return;
}
// close the previous level reslist, if any
if (m_hReslistFile != FILESYSTEM_INVALID_HANDLE)
{
g_pFileSystem->Close(m_hReslistFile);
m_hReslistFile = FILESYSTEM_INVALID_HANDLE;
}
// reset the duplication list
m_AlreadyWrittenFileNames.RemoveAll();
if ( sv_logdownloadlist.GetBool() )
{
// open the new level reslist
char path[MAX_OSPATH];
g_pFileSystem->CreateDirHierarchy( "DownloadLists", "MOD" );
Q_snprintf(path, sizeof(path), "DownloadLists/%s.lst", levelName);
m_hReslistFile = g_pFileSystem->Open(path, "wt", "GAME");
}
// add a slash to the end of com_gamedir, so we can only deal with files for this mod
Q_snprintf( m_gameDir, sizeof(m_gameDir), "%s/", com_gamedir );
V_FixSlashes( m_gameDir, '/' );
// save off the map name
V_strcpy_safe( m_mapName, levelName );
}
//-----------------------------------------------------------------------------
// Purpose: call to mark level load/end
//-----------------------------------------------------------------------------
void CDownloadListGenerator::OnLevelLoadEnd()
{
if ( IsX360() )
{
// not supporting
return;
}
if ( m_hReslistFile != FILESYSTEM_INVALID_HANDLE )
{
g_pFileSystem->Close(m_hReslistFile);
m_hReslistFile = FILESYSTEM_INVALID_HANDLE;
}
m_pStringTable = NULL;
}
//-----------------------------------------------------------------------------
// Purpose: logs and handles mdl files being precaches
//-----------------------------------------------------------------------------
void CDownloadListGenerator::OnModelPrecached(const char *relativePathFileName)
{
if ( IsX360() )
{
// not supporting
return;
}
if (Q_strstr(relativePathFileName, ".vmt"))
{
// it's a materials file, make sure that it starts in the materials directory, and we get the .vtf
char file[_MAX_PATH];
if ( StringHasPrefix( relativePathFileName, "materials" ) )
{
Q_strncpy(file, relativePathFileName, sizeof(file));
}
else
{
// prepend the materials directory
Q_snprintf(file, sizeof(file), "materials\\%s", relativePathFileName);
}
OnResourcePrecached(file);
// get the matching vtf file
char *ext = Q_strstr(file, ".vmt");
if (ext)
{
Q_strncpy(ext, ".vtf", 5);
OnResourcePrecached(file);
}
}
else
{
OnResourcePrecached(relativePathFileName);
}
}
//-----------------------------------------------------------------------------
// Purpose: logs sound file access
//-----------------------------------------------------------------------------
void CDownloadListGenerator::OnSoundPrecached(const char *relativePathFileName)
{
if ( IsX360() )
{
// not supporting
return;
}
// skip any special characters
if (!V_isalnum(relativePathFileName[0]))
{
++relativePathFileName;
}
// prepend the sound/ directory if necessary
char file[_MAX_PATH];
if ( StringHasPrefix( relativePathFileName, "sound" ) )
{
Q_strncpy(file, relativePathFileName, sizeof(file));
}
else
{
// prepend the materials directory
Q_snprintf(file, sizeof(file), "sound\\%s", relativePathFileName);
}
OnResourcePrecached(file);
}
//-----------------------------------------------------------------------------
// Purpose: logs the precache as a file access
//-----------------------------------------------------------------------------
void CDownloadListGenerator::OnResourcePrecached( const char *pRelativePathFileName )
{
// not supporting
if ( IsX360() )
return;
// ignore empty string
if ( pRelativePathFileName[0] == 0 )
return;
// ignore files that start with '*' since they signify special models
if ( pRelativePathFileName[0] == '*' )
return;
if ( Q_IsAbsolutePath( pRelativePathFileName ) )
{
Warning( "*** CDownloadListGenerator::OnResourcePrecached: Encountered full path %s!\n", pRelativePathFileName );
return;
}
char pRelativePath[MAX_PATH];
Q_strncpy( pRelativePath, pRelativePathFileName, sizeof(pRelativePath) );
Q_FixSlashes( pRelativePath, '/' );
// make sure the filename hasn't already been written
UtlSymId_t filename = m_AlreadyWrittenFileNames.Find( pRelativePath );
if ( filename != UTL_INVAL_SYMBOL )
return;
// record in list, so we don't write it again
m_AlreadyWrittenFileNames.AddString( pRelativePath );
// don't allow files for download the server doesn't have
if ( !g_pFileSystem->FileExists( pRelativePath, "GAME" ) )
return;
// add extras for mdl's
char *pExt = const_cast< char* >( Q_GetFileExtension( pRelativePath ) );
if ( !Q_stricmp( pExt, "mdl" ) )
{
Q_strncpy(pExt, "vvd", 10);
OnResourcePrecached(pRelativePath);
Q_strncpy(pExt, "ani", 10);
OnResourcePrecached(pRelativePath);
Q_strncpy(pExt, "dx90.vtx", 10);
OnResourcePrecached(pRelativePath);
Q_strncpy(pExt, "phy", 10);
OnResourcePrecached(pRelativePath);
Q_strncpy(pExt, "jpg", 10);
OnResourcePrecached(pRelativePath);
}
FileHandle_t handle = m_hReslistFile;
if ( handle != FILESYSTEM_INVALID_HANDLE )
{
g_pFileSystem->Write("\"", 1, handle);
g_pFileSystem->Write( pRelativePath, Q_strlen(pRelativePath), handle );
g_pFileSystem->Write("\"\n", 2, handle);
}
if ( m_pStringTable )
{
m_pStringTable->AddString( true, pRelativePath );
}
}
//-----------------------------------------------------------------------------
// Purpose: marks a precached file as needing a specific CRC on the client
//-----------------------------------------------------------------------------
void CDownloadListGenerator::ForceExactFile( const char *relativePathFileName, ConsistencyType consistency )
{
if ( IsX360() )
{
// not supporting
return;
}
if ( !m_pStringTable )
return;
if ( consistency != CONSISTENCY_EXACT && consistency != CONSISTENCY_SIMPLE_MATERIAL )
{
consistency = CONSISTENCY_EXACT;
}
CRC32_t crc;
bool error = true;
char file[_MAX_PATH];
const char *filePtr = relativePathFileName;
if (Q_strstr(relativePathFileName, ".vmt") || Q_strstr(relativePathFileName, ".vtf"))
{
// it's a materials file, make sure that it starts in the materials directory, and we get the .vtf
if ( StringHasPrefix(relativePathFileName, "materials" ) )
{
Q_strncpy(file, relativePathFileName, sizeof(file));
}
else
{
// prepend the materials directory
Q_snprintf(file, sizeof(file), "materials\\%s", relativePathFileName);
}
error = !CRC_File( &crc, file );
filePtr = file;
}
else
{
error = !CRC_File( &crc, relativePathFileName );
}
if ( error )
{
DevWarning( "Failed to CRC %s\n", relativePathFileName );
}
else
{
char relativeFileName[_MAX_PATH];
Q_strncpy( relativeFileName, filePtr, sizeof( relativeFileName ) );
V_FixSlashes( relativeFileName, '/' );
ExactFileUserData userData;
userData.consistencyType = consistency;
userData.crc = crc;
int index = m_pStringTable->FindStringIndex( relativeFileName );
if ( index != INVALID_STRING_INDEX )
{
m_pStringTable->SetStringUserData( index, sizeof( ExactFileUserData ), &userData );
}
else
{
m_pStringTable->AddString( true, relativeFileName, sizeof( ExactFileUserData ), &userData );
}
}
}
//-----------------------------------------------------------------------------
// Purpose: marks a precached model as having a maximum size on the client
//-----------------------------------------------------------------------------
void CDownloadListGenerator::ForceModelBounds( const char *relativePathFileName, const Vector &mins, const Vector &maxs )
{
if ( IsX360() )
{
// not supporting
return;
}
if ( !m_pStringTable )
return;
if ( !relativePathFileName )
relativePathFileName = "";
if (!Q_stristr(relativePathFileName, ".mdl"))
{
DevWarning( "Warning - trying to enforce model bounds on %s\n", relativePathFileName );
return;
}
char relativeFileName[_MAX_PATH];
Q_strncpy( relativeFileName, relativePathFileName, sizeof( relativeFileName ) );
V_FixSlashes( relativeFileName, '/' );
ModelBoundsUserData userData;
userData.consistencyType = CONSISTENCY_BOUNDS;
userData.mins = mins;
userData.maxs = maxs;
int index = m_pStringTable->FindStringIndex( relativeFileName );
if ( index != INVALID_STRING_INDEX )
{
m_pStringTable->SetStringUserData( index, sizeof( ModelBoundsUserData ), &userData );
}
else
{
m_pStringTable->AddString( true, relativeFileName, sizeof( ModelBoundsUserData ), &userData );
}
}
+77
View File
@@ -0,0 +1,77 @@
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef DOWNLOADLISTGENERATOR_H
#define DOWNLOADLISTGENERATOR_H
#ifdef _WIN32
#pragma once
#endif
#include "filesystem.h"
#include "utlvector.h"
#include "utlsymbol.h"
#include "networkstringtable.h"
#define DOWNLOADABLE_FILE_TABLENAME "downloadables"
#define MAX_DOWNLOADABLE_FILES 8192
enum ConsistencyType
{
CONSISTENCY_NONE,
CONSISTENCY_EXACT,
CONSISTENCY_SIMPLE_MATERIAL, // uses ExactFileUserData
CONSISTENCY_BOUNDS,
};
struct ExactFileUserData
{
unsigned char consistencyType;
unsigned long crc;
};
struct ModelBoundsUserData
{
unsigned char consistencyType;
Vector mins;
Vector maxs;
};
//-----------------------------------------------------------------------------
// Purpose: Handles collating lists of resources on level load
// Used to generate reslists for in-game downloads
//-----------------------------------------------------------------------------
class CDownloadListGenerator
{
public:
CDownloadListGenerator();
void SetStringTable( INetworkStringTable *pStringTable );
// call to mark level load/end
void OnLevelLoadStart(const char *levelName);
void OnLevelLoadEnd();
// call to mark resources as being precached
void OnResourcePrecached(const char *relativePathFileName);
void OnModelPrecached(const char *relativePathFileName);
void OnSoundPrecached(const char *relativePathFileName);
void ForceExactFile( const char *relativePathFileName, ConsistencyType consistency );
void ForceModelBounds( const char *relativePathFileName, const Vector &mins, const Vector &maxs );
private:
char m_gameDir[256];
char m_mapName[MAX_PATH];
FileHandle_t m_hReslistFile;
CUtlSymbolTable m_AlreadyWrittenFileNames;
INetworkStringTable *m_pStringTable;
};
// singleton accessor
CDownloadListGenerator &DownloadListGenerator();
#endif // DOWNLOADLISTGENERATOR_H
+601
View File
@@ -0,0 +1,601 @@
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "engine/IEngineSound.h"
#include "tier0/dbg.h"
#include "sound.h"
#include "client.h"
#include "vox.h"
#include "icliententity.h"
#include "icliententitylist.h"
#include "enginesingleuserfilter.h"
#include "snd_audio_source.h"
#if defined(_X360)
#include "xmp.h"
#endif
#include "tier0/vprof.h"
#include "audio/private/snd_sfx.h"
#include "cl_splitscreen.h"
#include "cl_demo.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
// HACK: expose in sound.h maybe?
void DSP_FastReset(int dsp);
extern float g_flReplaySoundFade;
//-----------------------------------------------------------------------------
//
// Client-side implementation of the engine sound interface
//
//-----------------------------------------------------------------------------
class CEngineSoundClient : public IEngineSound
{
public:
// constructor, destructor
CEngineSoundClient();
virtual ~CEngineSoundClient();
virtual bool PrecacheSound( const char *pSample, bool bPreload, bool bIsUISound );
virtual bool IsSoundPrecached( const char *pSample );
virtual void PrefetchSound( const char *pSample );
virtual bool IsLoopingSound( const char *pSample );
virtual float GetSoundDuration( const char *pSample );
virtual int EmitSound( IRecipientFilter& filter, int iEntIndex, int iChannel, const char *pSoundEntry, HSOUNDSCRIPTHASH nSoundEntryHash, const char *pSample,
float flVolume, float flAttenuation, int nSeed, int iFlags, int iPitch,
const Vector *pOrigin, const Vector *pDirection, CUtlVector< Vector >* pUtlVecOrigins, bool bUpdatePositions, float soundtime = 0.0f, int speakerentity = -1 );
virtual int EmitSound( IRecipientFilter& filter, int iEntIndex, int iChannel, const char *pSoundEntry, HSOUNDSCRIPTHASH nSoundEntryHash, const char *pSample,
float flVolume, soundlevel_t iSoundLevel, int nSeed, int iFlags, int iPitch,
const Vector *pOrigin, const Vector *pDirection, CUtlVector< Vector >* pUtlVecOrigins, bool bUpdatePositions, float soundtime = 0.0f, int speakerentity = -1 );
virtual void EmitSentenceByIndex( IRecipientFilter& filter, int iEntIndex, int iChannel, int iSentenceIndex,
float flVolume, soundlevel_t iSoundLevel, int nSeed, int iFlags, int iPitch,
const Vector *pOrigin, const Vector *pDirection, CUtlVector< Vector >* pUtlVecOrigins, bool bUpdatePositions, float soundtime = 0.0f, int speakerentity = -1 );
virtual void StopSound( int iEntIndex, int iChannel, const char *pSample, HSOUNDSCRIPTHASH nSoundEntryHash = SOUNDEMITTER_INVALID_HASH );
virtual void StopAllSounds(bool bClearBuffers);
virtual void SetRoomType( IRecipientFilter& filter, int roomType );
virtual void SetPlayerDSP( IRecipientFilter& filter, int dspType, bool fastReset );
virtual int EmitAmbientSound( const char *pSample, float flVolume,
int iPitch, int flags, float soundtime = 0.0f );
virtual float GetDistGainFromSoundLevel( soundlevel_t soundlevel, float dist );
// Client .dll only functions
virtual int GetGuidForLastSoundEmitted();
virtual bool IsSoundStillPlaying( int guid );
virtual bool GetSoundChannelVolume( const char* sound, float &flVolumeLeft, float &flVolumeRight );
virtual void StopSoundByGuid( int guid, bool bForceSync );
// Set's master volume (0.0->1.0)
virtual void SetVolumeByGuid( int guid, float fvol );
virtual float GetElapsedTimeByGuid( int guid );
// Retrieves list of all active sounds
virtual void GetActiveSounds( CUtlVector< SndInfo_t >& sndlist );
virtual void PrecacheSentenceGroup( const char *pGroupName );
virtual void NotifyBeginMoviePlayback();
virtual void NotifyEndMoviePlayback();
virtual bool IsMoviePlaying();
virtual bool GetPreventSound( void );
virtual void SetReplaySoundFade( float flReplayVolume ) { g_flReplaySoundFade = flReplayVolume; }
virtual float GetReplaySoundFade()const { return g_flReplaySoundFade; }
#if defined( _GAMECONSOLE )
virtual void UnloadSound( const char *pSample );
#endif
private:
int EmitSoundInternal( IRecipientFilter& filter, int iEntIndex, int iChannel, const char *pSoundEntry, HSOUNDSCRIPTHASH nSoundEntryHash, const char *pSample,
float flVolume, soundlevel_t iSoundLevel, int nSeed, int iFlags, int iPitch,
const Vector *pOrigin, const Vector *pDirection, CUtlVector< Vector >* pUtlVecOrigins, bool bUpdatePositions, float soundtime = 0.0f, int speakerentity = -1 );
bool m_bMoviePlaying;
};
//-----------------------------------------------------------------------------
// Client-server neutral sound interface accessor
//-----------------------------------------------------------------------------
static CEngineSoundClient s_EngineSoundClient;
EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CEngineSoundClient, IEngineSound,
IENGINESOUND_CLIENT_INTERFACE_VERSION, s_EngineSoundClient );
IEngineSound *EngineSoundClient()
{
return &s_EngineSoundClient;
}
//-----------------------------------------------------------------------------
// constructor, destructor
//-----------------------------------------------------------------------------
CEngineSoundClient::CEngineSoundClient() :
m_bMoviePlaying( false )
{
}
CEngineSoundClient::~CEngineSoundClient()
{
}
//-----------------------------------------------------------------------------
// Precache a particular sample
//-----------------------------------------------------------------------------
bool CEngineSoundClient::PrecacheSound( const char *pSample, bool bPreload, bool bIsUISound )
{
CSfxTable *pTable = S_PrecacheSound( pSample );
if ( pTable )
{
if ( bIsUISound )
{
S_MarkUISound( pTable );
}
return true;
}
return false;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : *pSample -
//-----------------------------------------------------------------------------
void CEngineSoundClient::PrefetchSound( const char *pSample )
{
S_PrefetchSound( pSample, true );
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : *pSample -
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CEngineSoundClient::IsSoundPrecached( const char *pSample )
{
if ( pSample && TestSoundChar(pSample, CHAR_SENTENCE) )
{
return true;
}
int idx = GetBaseLocalClient().LookupSoundIndex( pSample );
if ( idx == -1 )
return false;
return true;
}
//-----------------------------------------------------------------------------
// Returns if the sound is looping
//-----------------------------------------------------------------------------
bool CEngineSoundClient::IsLoopingSound( const char *pSample )
{
CSfxTable *pTable = S_PrecacheSound( pSample );
if ( !pTable || !pTable->pSource )
return false;
return pTable->pSource->IsLooped();
}
extern IBaseClientDLL *g_ClientDLL;
//-----------------------------------------------------------------------------
// Actually does the work of emitting a sound
//-----------------------------------------------------------------------------
int CEngineSoundClient::EmitSoundInternal( IRecipientFilter& filter, int iEntIndex, int iChannel, const char *pSoundEntry, HSOUNDSCRIPTHASH nSoundEntryHash, const char *pSample,
float flVolume, soundlevel_t iSoundLevel, int nSeed, int iFlags, int iPitch,
const Vector *pOrigin, const Vector *pDirection, CUtlVector< Vector >* pUtlVecOrigins, bool bUpdatePositions, float soundtime /*= 0.0f*/, int speakerentity /*= -1*/ )
{
FORCE_DEFAULT_SPLITSCREEN_PLAYER_GUARD;
if (flVolume < 0 || flVolume > 1)
{
Warning ("EmitSound: %s volume out of bounds = %f\n", pSample, flVolume);
return 0;
}
if (iSoundLevel < MIN_SNDLVL_VALUE || iSoundLevel > MAX_SNDLVL_VALUE)
{
Warning ("EmitSound: %s soundlevel out of bounds = %d\n", pSample, iSoundLevel);
return 0;
}
if (iPitch < 0 || iPitch > 255)
{
Warning ("EmitSound: %s pitch out of bounds = %i\n", pSample, iPitch);
return 0;
}
bool bInEyeSound = false;
if (iEntIndex < 0)
{
bInEyeSound = true;
if (g_ClientDLL)
iEntIndex = g_ClientDLL->GetInEyeEntity();
if (iEntIndex < 0)
iEntIndex = GetLocalClient().GetViewEntity();
}
// See if local player is a recipient
int i = 0;
int c = filter.GetRecipientCount();
for ( ; i < c ; i++ )
{
int index = filter.GetRecipientIndex( i );
if ( index == GetLocalClient().m_nPlayerSlot + 1 )
break;
}
// Local player not receiving sound
if ( i >= c )
return 0;
// Point at origin if they didn't specify a sound source.
Vector vecDummyOrigin;
if (!pOrigin)
{
// Try to use the origin of the entity
IClientEntity *pEnt = entitylist->GetClientEntity( iEntIndex );
// don't update position if we stop this sound
if (pEnt && !(iFlags & SND_STOP) )
{
vecDummyOrigin = pEnt->GetRenderOrigin();
}
else
{
vecDummyOrigin.Init();
}
pOrigin = &vecDummyOrigin;
}
Vector vecDirection;
if (!pDirection)
{
IClientEntity *pEnt = entitylist->GetClientEntity( iEntIndex );
if (pEnt && !(iFlags & SND_STOP))
{
QAngle angles;
angles = pEnt->GetAbsAngles();
AngleVectors( angles, &vecDirection );
}
else
{
vecDirection.Init();
}
pDirection = &vecDirection;
}
if ( pUtlVecOrigins )
{
(*pUtlVecOrigins).AddToTail( *pOrigin );
}
// L4D
float delay = soundtime;
if ( soundtime > 0.0f )
{
// this sound was played directly on the client, use its clock sync
delay = S_ComputeDelayForSoundtime( soundtime, CLOCK_SYNC_CLIENT );
if ( delay < 0 && delay > -0.100f )
{
delay = 0;
}
}
StartSoundParams_t params;
params.staticsound = iChannel == CHAN_STATIC;
params.soundsource = iEntIndex;
params.entchannel = iChannel;
params.origin = *pOrigin;
params.direction = *pDirection;
params.bUpdatePositions = bUpdatePositions;
params.fvol = flVolume;
params.soundlevel = iSoundLevel;
params.flags = iFlags;
params.pitch = iPitch;
params.fromserver = false;
params.delay = delay;
params.speakerentity = speakerentity;
params.m_bIsScriptHandle = ( iFlags & SND_IS_SCRIPTHANDLE ) ? true : false ;
params.m_bInEyeSound = bInEyeSound;
if ( iFlags & SND_GENERATE_GUID )
{
params.m_nQueuedGUID = StartSoundParams_t::GENERATE_GUID;
}
// soundentry handling
if ( iFlags & SND_IS_SCRIPTHANDLE )
{
// Don't actually play sounds if playing a demo and skipping ahead
// but always stop sounds
if ( demoplayer->IsSkipping() && !(iFlags&SND_STOP) )
{
return 0;
}
params.m_nSoundScriptHash = nSoundEntryHash;
return S_StartSoundEntry( params, nSeed, false );
}
CSfxTable *pSound = S_PrecacheSound(pSample);
if (!pSound)
return 0;
params.pSfx = pSound;
// Don't actually play sounds if playing a demo and skipping ahead
// but always stop sounds
if ( demoplayer->IsSkipping() && !(iFlags&SND_STOP) )
{
return 0;
}
return S_StartSound( params );
}
//-----------------------------------------------------------------------------
// Plays a sentence
//-----------------------------------------------------------------------------
void CEngineSoundClient::EmitSentenceByIndex( IRecipientFilter& filter, int iEntIndex, int iChannel,
int iSentenceIndex, float flVolume, soundlevel_t iSoundLevel, int nSeed, int iFlags, int iPitch,
const Vector *pOrigin, const Vector *pDirection, CUtlVector< Vector >* pUtlVecOrigins, bool bUpdatePosition, float soundtime /*= 0.0f*/, int speakerentity /*= -1*/ )
{
if ( iSentenceIndex >= 0 )
{
char pName[8];
Q_snprintf( pName, sizeof(pName), "!%d", iSentenceIndex );
EmitSoundInternal( filter, iEntIndex, iChannel, NULL, SOUNDEMITTER_INVALID_HASH, pName, flVolume, iSoundLevel, nSeed,
iFlags, iPitch, pOrigin, pDirection, pUtlVecOrigins, bUpdatePosition, soundtime, speakerentity );
}
}
//-----------------------------------------------------------------------------
// Emits a sound
//-----------------------------------------------------------------------------
int CEngineSoundClient::EmitSound( IRecipientFilter& filter, int iEntIndex, int iChannel, const char *pSoundEntry, HSOUNDSCRIPTHASH nSoundEntryHash, const char *pSample,
float flVolume, float flAttenuation, int nSeed, int iFlags, int iPitch,
const Vector *pOrigin, const Vector *pDirection, CUtlVector< Vector >* pUtlVecOrigins, bool bUpdatePositions, float soundtime /*= 0.0f*/, int speakerentity /*= -1*/ )
{
VPROF( "CEngineSoundClient::EmitSound" );
return EmitSound( filter, iEntIndex, iChannel, pSoundEntry, nSoundEntryHash, pSample, flVolume, ATTN_TO_SNDLVL( flAttenuation ), nSeed, iFlags,
iPitch, pOrigin, pDirection, pUtlVecOrigins, bUpdatePositions, soundtime, speakerentity );
}
int CEngineSoundClient::EmitSound( IRecipientFilter& filter, int iEntIndex, int iChannel, const char *pSoundEntry, HSOUNDSCRIPTHASH nSoundEntryHash, const char *pSample,
float flVolume, soundlevel_t iSoundLevel, int nSeed, int iFlags, int iPitch,
const Vector *pOrigin, const Vector *pDirection, CUtlVector< Vector >* pUtlVecOrigins, bool bUpdatePositions, float soundtime /*= 0.0f*/, int speakerentity /*= -1*/ )
{
VPROF( "CEngineSoundClient::EmitSound" );
if ( pSample && TestSoundChar(pSample, CHAR_SENTENCE) )
{
int iSentenceIndex = -1;
VOX_LookupString( PSkipSoundChars(pSample), &iSentenceIndex );
if (iSentenceIndex >= 0)
{
EmitSentenceByIndex( filter, iEntIndex, iChannel, iSentenceIndex, flVolume,
iSoundLevel, nSeed, iFlags, iPitch, pOrigin, pDirection, pUtlVecOrigins, bUpdatePositions, soundtime, speakerentity );
}
else
{
DevWarning( 2, "Unable to find %s in sentences.txt\n", PSkipSoundChars(pSample));
}
return -1;
}
else
{
return EmitSoundInternal( filter, iEntIndex, iChannel, pSoundEntry, nSoundEntryHash, pSample, flVolume, iSoundLevel, nSeed,
iFlags, iPitch, pOrigin, pDirection, pUtlVecOrigins, bUpdatePositions, soundtime, speakerentity );
}
}
//-----------------------------------------------------------------------------
// Stops a sound
//-----------------------------------------------------------------------------
void CEngineSoundClient::StopSound( int iEntIndex, int iChannel, const char *pSample, HSOUNDSCRIPTHASH nSoundEntryHash )
{
FORCE_DEFAULT_SPLITSCREEN_PLAYER_GUARD;
CEngineSingleUserFilter filter( GetLocalClient().m_nPlayerSlot + 1 );
EmitSound( filter, iEntIndex, iChannel, pSample, nSoundEntryHash, pSample, 0, SNDLVL_NONE, 0, SND_STOP, PITCH_NORM,
NULL, NULL, NULL, true );
}
void CEngineSoundClient::SetRoomType( IRecipientFilter& filter, int roomType )
{
#ifndef LINUX
extern ConVar snd_dsp_spew_changes;
extern ConVar dsp_room;
if ( snd_dsp_spew_changes.GetBool() )
{
DevMsg( "Changing to room type %d.\n", roomType );
}
dsp_room.SetValue( roomType );
#endif
}
void CEngineSoundClient::SetPlayerDSP( IRecipientFilter& filter, int dspType, bool fastReset )
{
extern void dsp_player_set( int val );
dsp_player_set( dspType );
if ( fastReset )
{
DSP_FastReset( dspType );
}
}
int CEngineSoundClient::EmitAmbientSound( const char *pSample, float flVolume,
int iPitch, int flags, float soundtime /*= 0.0f*/ )
{
float delay = 0.0f;
if ( soundtime != 0.0f )
{
delay = soundtime - GetBaseLocalClient().m_flLastServerTickTime;
}
CSfxTable *pSound = S_PrecacheSound(pSample);
StartSoundParams_t params;
params.staticsound = true;
params.soundsource = SOUND_FROM_LOCAL_PLAYER;
params.entchannel = CHAN_STATIC;
params.pSfx = pSound;
params.origin = vec3_origin;
params.fvol = flVolume;
params.soundlevel = SNDLVL_NONE;
params.flags = flags;
params.pitch = iPitch;
params.fromserver = false;
params.delay = delay;
return S_StartSound( params );
}
void CEngineSoundClient::StopAllSounds(bool bClearBuffers)
{
S_StopAllSounds( bClearBuffers );
}
bool CEngineSoundClient::GetPreventSound( void )
{
return S_GetPreventSound( );
}
float CEngineSoundClient::GetDistGainFromSoundLevel( soundlevel_t soundlevel, float dist )
{
return S_GetGainFromSoundLevel( soundlevel, dist );
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : *pSample -
// Output : float
//-----------------------------------------------------------------------------
float CEngineSoundClient::GetSoundDuration( const char *pSample )
{
return AudioSource_GetSoundDuration( pSample );
}
// Client .dll only functions
//-----------------------------------------------------------------------------
// Purpose:
// Input : -
// Output : int
//-----------------------------------------------------------------------------
int CEngineSoundClient::GetGuidForLastSoundEmitted()
{
return S_GetGuidForLastSoundEmitted();
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : guid -
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CEngineSoundClient::IsSoundStillPlaying( int guid )
{
return S_IsSoundStillPlaying( guid );
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : guid -
//-----------------------------------------------------------------------------
void CEngineSoundClient::StopSoundByGuid( int guid, bool bForceSync )
{
S_StopSoundByGuid( guid, bForceSync );
}
//-----------------------------------------------------------------------------
// Purpose: Retrieves list of all active sounds
// Input : sndlist -
//-----------------------------------------------------------------------------
void CEngineSoundClient::GetActiveSounds( CUtlVector< SndInfo_t >& sndlist )
{
S_GetActiveSounds( sndlist );
}
//-----------------------------------------------------------------------------
// Purpose: Set's master volume (0.0->1.0)
// Input : guid -
// fvol -
//-----------------------------------------------------------------------------
void CEngineSoundClient::SetVolumeByGuid( int guid, float fvol )
{
S_SetVolumeByGuid( guid, fvol );
}
//-----------------------------------------------------------------------------
// Purpose: Returns sound's current elapsed time
// Input : guid -
//-----------------------------------------------------------------------------
float CEngineSoundClient::GetElapsedTimeByGuid( int guid )
{
return S_GetElapsedTimeByGuid( guid );
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CEngineSoundClient::PrecacheSentenceGroup( const char *pGroupName )
{
VOX_PrecacheSentenceGroup( this, pGroupName );
}
void CEngineSoundClient::NotifyBeginMoviePlayback()
{
StopAllSounds(true);
#if defined( _X360 )
XMPOverrideBackgroundMusic();
#endif
m_bMoviePlaying = true;
}
void CEngineSoundClient::NotifyEndMoviePlayback()
{
#if defined( _X360 )
XMPRestoreBackgroundMusic();
#endif
m_bMoviePlaying = false;
}
bool CEngineSoundClient::IsMoviePlaying()
{
return m_bMoviePlaying;
}
bool CEngineSoundClient::GetSoundChannelVolume( const char* sound, float &flVolumeLeft, float &flVolumeRight )
{
return S_GetSoundChannelVolume( sound, flVolumeLeft, flVolumeRight );
}
#if defined( _GAMECONSOLE )
void CEngineSoundClient::UnloadSound( const char *pSample )
{
S_UnloadSound( pSample );
}
#endif
+23
View File
@@ -0,0 +1,23 @@
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef ENGINESOUNDINTERNAL_H
#define ENGINESOUNDINTERNAL_H
#if defined( _WIN32 )
#pragma once
#endif
#include "engine/IEngineSound.h"
//-----------------------------------------------------------------------------
// Method to get at the singleton implementations of the engine sound interfaces
//-----------------------------------------------------------------------------
IEngineSound* EngineSoundClient();
IEngineSound* EngineSoundServer();
#endif // SOUNDENGINEINTERNAL_H
+517
View File
@@ -0,0 +1,517 @@
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "engine/IEngineSound.h"
#include "tier0/dbg.h"
#include "quakedef.h"
#include "vox.h"
#include "server.h"
#include "sv_main.h"
#include "edict.h"
#include "sound.h"
#include "host.h"
#include "vengineserver_impl.h"
#include "enginesingleuserfilter.h"
#include "snd_audio_source.h"
#include "soundchars.h"
#include "tier0/vprof.h"
#ifndef DEDICATED
#include "vgui_baseui_interface.h"
#endif
#include "SoundEmitterSystem/isoundemittersystembase.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//-----------------------------------------------------------------------------
//
// Server-side implementation of the engine sound interface
//
//-----------------------------------------------------------------------------
class CEngineSoundServer : public IEngineSound
{
public:
// constructor, destructor
CEngineSoundServer();
virtual ~CEngineSoundServer();
virtual bool PrecacheSound( const char *pSample, bool bPreload, bool bIsUISound );
virtual bool IsSoundPrecached( const char *pSample );
virtual void PrefetchSound( const char *pSample );
virtual bool IsLoopingSound( const char *pSample )
{
Warning( "Can't call IsLoopingSound from server\n" );
return false;
}
virtual float GetSoundDuration( const char *pSample );
virtual int EmitSound( IRecipientFilter& filter, int iEntIndex, int iChannel, const char *pSoundEntry, HSOUNDSCRIPTHASH iSoundEntryHash, const char *pSample,
float flVolume, float flAttenuation, int nSeed, int iFlags, int iPitch,
const Vector *pOrigin, const Vector *pDirection, CUtlVector< Vector >* pUtlVecOrigins, bool bUpdatePositions, float soundtime = 0.0f, int speakerentity = -1 );
virtual int EmitSound( IRecipientFilter& filter, int iEntIndex, int iChannel, const char *pSoundEntry, HSOUNDSCRIPTHASH iSoundEntryHash, const char *pSample,
float flVolume, soundlevel_t iSoundLevel, int nSeed, int iFlags, int iPitch,
const Vector *pOrigin, const Vector *pDirection, CUtlVector< Vector >* pUtlVecOrigins, bool bUpdatePositions, float soundtime = 0.0f, int speakerentity = -1 );
virtual void EmitSentenceByIndex( IRecipientFilter& filter, int iEntIndex, int iChannel, int iSentenceIndex,
float flVolume, soundlevel_t iSoundLevel, int nSeed, int iFlags, int iPitch,
const Vector *pOrigin, const Vector *pDirection, CUtlVector< Vector >* pUtlVecOrigins, bool bUpdatePositions, float soundtime = 0.0f, int speakerentity = -1 );
virtual void StopSound( int iEntIndex, int iChannel, const char *pSample, HSOUNDSCRIPTHASH nSoundEntryHash = SOUNDEMITTER_INVALID_HASH );
virtual void StopAllSounds( bool bClearBuffers );
// Set the room type for a player
virtual void SetRoomType( IRecipientFilter& filter, int roomType );
virtual void SetPlayerDSP( IRecipientFilter& filter, int dspType, bool fastReset );
// emit an "ambient" sound that isn't spatialized - specify left/right volume
// only available on the client, assert on server
virtual int EmitAmbientSound( const char *pSample, float flVolume, int iPitch, int flags, float soundtime = 0.0f );
virtual float GetDistGainFromSoundLevel( soundlevel_t soundlevel, float dist );
// Client .dll only functions
virtual int GetGuidForLastSoundEmitted()
{
Warning( "Can't call GetGuidForLastSoundEmitted from server\n" );
return 0;
}
virtual bool IsSoundStillPlaying( int guid )
{
Warning( "Can't call IsSoundStillPlaying from server\n" );
return false;
}
virtual void StopSoundByGuid( int guid, bool bForce )
{
Warning( "Can't call StopSoundByGuid from server\n" );
return;
}
// Retrieves list of all active sounds
virtual void GetActiveSounds( CUtlVector< SndInfo_t >& sndlist )
{
Warning( "Can't call GetActiveSounds from server\n" );
return;
}
// Set's master volume (0.0->1.0)
virtual void SetVolumeByGuid( int guid, float fvol )
{
Warning( "Can't call SetVolumeByGuid from server\n" );
return;
}
// return's sound's current elapsed time
virtual float GetElapsedTimeByGuid( int guid)
{
Warning( "Can't call GetElapsedTimeByGuid from server\n" );
return 0.0;
}
virtual void PrecacheSentenceGroup( const char *pGroupName )
{
VOX_PrecacheSentenceGroup( this, pGroupName );
}
virtual void NotifyBeginMoviePlayback()
{
AssertMsg( 0, "Not supported" );
}
virtual void NotifyEndMoviePlayback()
{
AssertMsg( 0, "Not supported" );
}
virtual bool IsMoviePlaying()
{
AssertMsg( 0, "Not supported" );
return false;
}
virtual bool GetSoundChannelVolume( const char* sound, float &flVolumeLeft, float &flVolumeRight )
{
Warning( "Can't call GetSoundChannelVolume from server\n" );
return false;
}
virtual bool GetPreventSound( )
{
AssertMsg( 0, "Not supported" );
return false;
}
virtual void SetReplaySoundFade( float flReplayVolume ) { Assert( !"Client-only service" ); }
virtual float GetReplaySoundFade()const { Assert( !"Client-only service" ); return 0.0f; }
virtual void SetReplayMusicGain( float flReplayMusicGain ) { Assert( !"Client-only service" ); }
virtual float GetReplayMusicGain()const { Assert( !"Client-only service" ); return 0.0f; }
#if defined( _GAMECONSOLE )
virtual void UnloadSound( const char *pSample )
{
AssertMsg( 0, "Not supported" );
}
#endif
private:
void EmitSoundInternal( IRecipientFilter& filter, int iEntIndex, int iChannel, const char *pSoundEntry, HSOUNDSCRIPTHASH iSoundEntryHash, const char *pSample,
float flVolume, soundlevel_t iSoundLevel, int nSeed, int iFlags, int iPitch,
const Vector *pOrigin, const Vector *pDirection, CUtlVector< Vector >* pUtlVecOrigins, bool bUpdatePositions, float soundtime = 0.0f, int speakerentity = -1 );
};
//-----------------------------------------------------------------------------
// Client-server neutral sound interface accessor
//-----------------------------------------------------------------------------
static CEngineSoundServer s_EngineSoundServer;
EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CEngineSoundServer, IEngineSound,
IENGINESOUND_SERVER_INTERFACE_VERSION, s_EngineSoundServer );
IEngineSound *EngineSoundServer()
{
return &s_EngineSoundServer;
}
//-----------------------------------------------------------------------------
// constructor, destructor
//-----------------------------------------------------------------------------
CEngineSoundServer::CEngineSoundServer()
{
}
CEngineSoundServer::~CEngineSoundServer()
{
}
//-----------------------------------------------------------------------------
// Precache a particular sample
//-----------------------------------------------------------------------------
bool CEngineSoundServer::PrecacheSound( const char *pSample, bool bPreload, bool bIsUISound )
{
#ifndef DEDICATED
EngineVGui()->UpdateProgressBar( PROGRESS_DEFAULT );
#endif
int i;
if ( pSample && TestSoundChar( pSample, CHAR_SENTENCE ) )
{
return true;
}
if ( pSample[0] <= ' ' )
{
Host_Error( "CEngineSoundServer::PrecacheSound: Bad string: %s", pSample );
}
// add the sound to the precache list
// Start at 1, since 0 is used to indicate an error in the sound precache
i = SV_FindOrAddSound( pSample, bPreload );
if ( i >= 0 )
return true;
Host_Error( "CEngineSoundServer::PrecacheSound: '%s' overflow", pSample );
return false;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : *pSample -
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CEngineSoundServer::IsSoundPrecached( const char *pSample )
{
if ( pSample && TestSoundChar(pSample, CHAR_SENTENCE) )
{
return true;
}
int idx = SV_SoundIndex( pSample );
if ( idx == -1 )
{
return false;
}
return true;
}
void CEngineSoundServer::PrefetchSound( const char *pSample )
{
if ( pSample && TestSoundChar(pSample, CHAR_SENTENCE) )
{
return;
}
int idx = SV_SoundIndex( pSample );
if ( idx == -1 )
{
return;
}
// Tell clients to prefetch the sound
CSVCMsg_Prefetch_t msg;
msg.set_sound_index( idx );
sv.BroadcastMessage( msg, true, false );
}
//-----------------------------------------------------------------------------
// Stops a sound
//-----------------------------------------------------------------------------
void CEngineSoundServer::EmitSoundInternal( IRecipientFilter& filter, int iEntIndex, int iChannel, const char *pSoundEntry, HSOUNDSCRIPTHASH iSoundEntryHash, const char *pSample,
float flVolume, soundlevel_t iSoundLevel, int nSeed, int iFlags, int iPitch,
const Vector *pOrigin, const Vector *pDirection, CUtlVector< Vector >* pUtlVecOrigins, bool bUpdatePositions, float soundtime /*= 0.0f*/, int speakerentity /*=-1*/ )
{
AssertMsg( pDirection == NULL, "Direction specification not currently supported on server sounds" );
AssertMsg( bUpdatePositions, "Non-updated positions not currently supported on server sounds" );
if (flVolume < 0 || flVolume > 1)
{
Warning ("EmitSound: %s volume out of bounds = %f\n", pSample, flVolume);
return;
}
if (iSoundLevel < MIN_SNDLVL_VALUE || iSoundLevel > MAX_SNDLVL_VALUE)
{
Warning ("EmitSound: %s soundlevel out of bounds = %d\n", pSample, iSoundLevel);
return;
}
if (iPitch < 0 || iPitch > 255)
{
Warning ("EmitSound: %s pitch out of bounds = %i\n", pSample, iPitch);
return;
}
edict_t *pEdict = (iEntIndex >= 0) ? &sv.edicts[iEntIndex] : NULL;
SV_StartSound( filter, pEdict, iChannel, pSoundEntry, iSoundEntryHash, pSample, flVolume, iSoundLevel,
iFlags, iPitch, pOrigin, soundtime, speakerentity, pUtlVecOrigins, nSeed );
}
//-----------------------------------------------------------------------------
// Plays a sentence
//-----------------------------------------------------------------------------
void CEngineSoundServer::EmitSentenceByIndex( IRecipientFilter& filter, int iEntIndex, int iChannel,
int iSentenceIndex, float flVolume, soundlevel_t iSoundLevel, int nSeed, int iFlags, int iPitch,
const Vector *pOrigin, const Vector *pDirection, CUtlVector< Vector >* pUtlVecOrigins, bool bUpdatePositions, float soundtime /*= 0.0f*/, int speakerentity /*= -1*/ )
{
if ( iSentenceIndex >= 0 )
{
char pName[8];
Q_snprintf( pName, sizeof(pName), "!%d", iSentenceIndex );
EmitSoundInternal( filter, iEntIndex, iChannel, NULL, SOUNDEMITTER_INVALID_HASH, pName, flVolume, iSoundLevel, nSeed,
iFlags, iPitch, pOrigin, pDirection, pUtlVecOrigins, bUpdatePositions, soundtime, speakerentity );
}
}
//-----------------------------------------------------------------------------
// Emits a sound
//-----------------------------------------------------------------------------
int CEngineSoundServer::EmitSound( IRecipientFilter& filter, int iEntIndex, int iChannel, const char *pSoundEntry, HSOUNDSCRIPTHASH iSoundEntryHash, const char *pSample,
float flVolume, float flAttenuation, int nSeed, int iFlags, int iPitch,
const Vector *pOrigin, const Vector *pDirection, CUtlVector< Vector >* pUtlVecOrigins, bool bUpdatePositions, float soundtime /*= 0.0f*/, int speakerentity /*= -1*/ )
{
VPROF( "CEngineSoundServer::EmitSound" );
EmitSound( filter, iEntIndex, iChannel, pSoundEntry, iSoundEntryHash, pSample, flVolume, ATTN_TO_SNDLVL( flAttenuation ), nSeed, iFlags,
iPitch, pOrigin, pDirection, pUtlVecOrigins, bUpdatePositions, soundtime, speakerentity );
return -1; // Negative for unsupported feature.
}
int CEngineSoundServer::EmitSound( IRecipientFilter& filter, int iEntIndex, int iChannel, const char *pSoundEntry, HSOUNDSCRIPTHASH iSoundEntryHash, const char *pSample,
float flVolume, soundlevel_t iSoundLevel, int nSeed, int iFlags, int iPitch,
const Vector *pOrigin, const Vector *pDirection, CUtlVector< Vector >* pUtlVecOrigins, bool bUpdatePositions, float soundtime /*= 0.0f*/, int speakerentity /*= -1*/ )
{
VPROF( "CEngineSoundServer::EmitSound" );
if ( pSample && TestSoundChar(pSample, CHAR_SENTENCE) )
{
int iSentenceIndex = -1;
VOX_LookupString( PSkipSoundChars(pSample), &iSentenceIndex );
if (iSentenceIndex >= 0)
{
EmitSentenceByIndex( filter, iEntIndex, iChannel, iSentenceIndex, flVolume,
iSoundLevel, nSeed, iFlags, iPitch, pOrigin, pDirection, pUtlVecOrigins, bUpdatePositions, soundtime, speakerentity );
}
else
{
DevWarning( 2, "Unable to find %s in sentences.txt\n", PSkipSoundChars(pSample) );
}
}
else
{
EmitSoundInternal( filter, iEntIndex, iChannel, pSoundEntry, iSoundEntryHash, pSample, flVolume, iSoundLevel, nSeed,
iFlags, iPitch, pOrigin, pDirection, pUtlVecOrigins, bUpdatePositions, soundtime, speakerentity );
}
return -1; // Negative for unsupported feature.
}
void BuildRecipientList( CUtlVector< edict_t * >& list, const IRecipientFilter& filter )
{
int c = filter.GetRecipientCount();
for ( int i = 0; i < c; i++ )
{
int playerindex = filter.GetRecipientIndex( i );
if ( playerindex < 1 || playerindex > sv.GetClientCount() )
continue;
CGameClient *cl = sv.Client( playerindex - 1 );
// Never output to bots
if ( cl->IsFakeClient() )
continue;
if ( !cl->IsSpawned() )
continue;
list.AddToTail( cl->edict );
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : filter -
// roomType -
//-----------------------------------------------------------------------------
void CEngineSoundServer::SetRoomType( IRecipientFilter& filter, int roomType )
{
CUtlVector< edict_t * > players;
BuildRecipientList( players, filter );
for ( int i = 0 ; i < players.Count(); i++ )
{
g_pVEngineServer->ClientCommand( players[ i ], "room_type %i\n", roomType );
}
}
// Set the dsp preset for a player (client only)
//-----------------------------------------------------------------------------
// Purpose:
// Input : filter -
// dspType -
//-----------------------------------------------------------------------------
void CEngineSoundServer::SetPlayerDSP( IRecipientFilter& filter, int dspType, bool fastReset )
{
Assert( !fastReset );
if ( fastReset )
{
Warning( "SetPlayerDSP: fastReset only valid from client\n" );
}
CUtlVector< edict_t * > players;
BuildRecipientList( players, filter );
for ( int i = 0 ; i < players.Count(); i++ )
{
g_pVEngineServer->ClientCommand( players[ i ], "dsp_player %i\n", dspType );
KeyValues *kvClientCmd = new KeyValues( "dsp_player" );
kvClientCmd->SetInt( NULL, dspType );
g_pVEngineServer->ClientCommandKeyValues( players[ i ], kvClientCmd );
}
}
void CEngineSoundServer::StopAllSounds(bool bClearBuffers)
{
AssertMsg( 0, "Not supported" );
}
// bool CEngineSoundServer::GetPreventSound( void )
// {
// AssertMsg( 0, "Not supported" );
// }
int CEngineSoundServer::EmitAmbientSound( const char *pSample, float flVolume, int iPitch, int flags, float soundtime /*= 0.0f*/ )
{
AssertMsg( 0, "Not supported" );
return 0;
}
//-----------------------------------------------------------------------------
// Stops a sound
//-----------------------------------------------------------------------------
void CEngineSoundServer::StopSound( int iEntIndex, int iChannel, const char *pSample, HSOUNDSCRIPTHASH nSoundEntryHash )
{
CEngineRecipientFilter filter;
filter.AddAllPlayers();
filter.MakeReliable();
int nFlags = SND_STOP | ( nSoundEntryHash != SOUNDEMITTER_INVALID_HASH ? SND_IS_SCRIPTHANDLE : 0 );
EmitSound( filter, iEntIndex, iChannel, pSample, nSoundEntryHash, pSample, 0, SNDLVL_NONE, 0, nFlags, PITCH_NORM,
NULL, NULL, NULL, true );
}
float SV_GetSoundDuration( const char *pSample )
{
#ifdef DEDICATED
return 0; // TODO: make this return a real value (i.e implement an OS independent version of the sound code)
#else
return AudioSource_GetSoundDuration( pSample );
#endif
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : *pSample -
// Output : float
//-----------------------------------------------------------------------------
float CEngineSoundServer::GetSoundDuration( const char *pSample )
{
return Host_GetSoundDuration( pSample );
}
float CEngineSoundServer::GetDistGainFromSoundLevel( soundlevel_t soundlevel, float dist )
{
return S_GetGainFromSoundLevel( soundlevel, dist );
}
/*
//-----------------------------------------------------------------------------
// FIXME: Move into the CEngineSoundServer class?
//-----------------------------------------------------------------------------
void Host_RestartAmbientSounds()
{
if (!sv.active)
{
return;
}
#ifndef DEDICATED
const int NUM_INFOS = 64;
SoundInfo_t soundInfo[NUM_INFOS];
int nSounds = S_GetCurrentStaticSounds( soundInfo, NUM_INFOS, CHAN_STATIC );
for ( int i = 0; i < nSounds; i++)
{
if (soundInfo[i].looping &&
soundInfo[i].entity != -1 )
{
Msg("Restarting sound %s...\n", soundInfo[i].name);
S_StopSound(soundInfo[i].entity, soundInfo[i].channel);
CEngineRecipientFilter filter;
filter.AddAllPlayers();
SV_StartSound( filter, EDICT_NUM(soundInfo[i].entity),
CHAN_STATIC,
soundInfo[i].name,
soundInfo[i].volume,
soundInfo[i].soundlevel,
0, // @Q (toml 05-09-02): Is this correct, or will I need to squirrel away the original flags?
soundInfo[i].pitch );
}
}
#endif
} */
File diff suppressed because it is too large Load Diff
+200
View File
@@ -0,0 +1,200 @@
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose: gameeventmanager.h: interface for the CGameEventManager class.
//
// $Workfile: $
// $NoKeywords: $
//=============================================================================//
#if !defined ( GAMEEVENTMANAGER_H )
#define GAMEEVENTMANAGER_H
#ifdef _WIN32
#pragma once
#endif
#include <igameevents.h>
#include <utlvector.h>
#include <keyvalues.h>
#include <networkstringtabledefs.h>
#include <utlsymbol.h>
#include <utldict.h>
#include "netmessages.h"
class CSVCMsg_GameEventList;
class CCLCMsg_ListenEvents;
class CGameEventCallback
{
public:
void *m_pCallback; // callback pointer
int m_nListenerType; // client or server side ?
};
class CGameEventDescriptor
{
public:
CGameEventDescriptor()
{
eventid = -1;
keys = NULL;
local = false;
reliable = true;
elementIndex = -1;
numSerialized = 0;
numUnSerialized = 0;
totalSerializedBits = 0;
totalUnserializedBits = 0;
}
public:
int eventid; // network index number, -1 = not networked
int elementIndex;
KeyValues *keys; // KeyValue describing data types, if NULL only name
CUtlVector<CGameEventCallback*> listeners; // registered listeners
bool local; // local event, never tell clients about that
bool reliable; // send this event as reliable message
// Extra data for network monitoring
int numSerialized;
int numUnSerialized;
int totalSerializedBits;
int totalUnserializedBits;
};
class CGameEvent : public IGameEvent
{
public:
CGameEvent( CGameEventDescriptor *descriptor, const char *name );
virtual ~CGameEvent();
virtual const char *GetName() const OVERRIDE;
virtual bool IsEmpty(const char *keyName = NULL) const OVERRIDE;
virtual bool IsLocal() const OVERRIDE;
virtual bool IsReliable() const OVERRIDE;
virtual bool GetBool( const char *keyName = NULL, bool defaultValue = false ) const OVERRIDE;
virtual int GetInt( const char *keyName = NULL, int defaultValue = 0 ) const OVERRIDE;
virtual uint64 GetUint64( const char *keyName = NULL, uint64 defaultValue = 0 ) const OVERRIDE;
virtual float GetFloat( const char *keyName = NULL, float defaultValue = 0.0f ) const OVERRIDE;
virtual const char *GetString( const char *keyName = NULL, const char *defaultValue = "" ) const OVERRIDE;
virtual const wchar_t *GetWString( const char *keyName = NULL, const wchar_t *defaultValue = L"" ) const OVERRIDE;
virtual const void *GetPtr( const char *keyName = NULL ) const OVERRIDE;
virtual void SetBool( const char *keyName, bool value ) OVERRIDE;
virtual void SetInt( const char *keyName, int value ) OVERRIDE;
virtual void SetUint64( const char *keyName, uint64 value ) OVERRIDE;
virtual void SetFloat( const char *keyName, float value ) OVERRIDE;
virtual void SetString( const char *keyName, const char *value ) OVERRIDE;
virtual void SetWString( const char *keyName, const wchar_t *value ) OVERRIDE;
virtual void SetPtr( const char *keyName, const void * value ) OVERRIDE;
virtual bool ForEventData( IGameEventVisitor2* visitor ) const OVERRIDE;
CGameEventDescriptor *m_pDescriptor;
KeyValues *m_pDataKeys;
};
// NOTE: Every non-threadsafe externally-callable function must lock m_mutex before modifying the event manager
// member variables. Client & server threads can call into this class simultaneously
class CGameEventManager : public IGameEventManager2
{
friend class CGameEventManagerOld;
public: // IGameEventManager functions
enum
{
SERVERSIDE = 0, // this is a server side listener, event logger etc
CLIENTSIDE, // this is a client side listenet, HUD element etc
CLIENTSTUB, // this is a serverside stub for a remote client listener (used by engine only)
SERVERSIDE_OLD, // legacy support for old server event listeners
CLIENTSIDE_OLD, // legecy support for old client event listeners
};
enum
{
TYPE_LOCAL = 0, // not networked
TYPE_STRING, // zero terminated ASCII string
TYPE_FLOAT, // float 32 bit
TYPE_LONG, // signed int 32 bit
TYPE_SHORT, // signed int 16 bit
TYPE_BYTE, // unsigned int 8 bit
TYPE_BOOL, // unsigned int 1 bit
TYPE_UINT64, // unsigned int 64 bit
TYPE_WSTRING, // zero terminated wide char string
TYPE_COUNT,
};
CGameEventManager();
virtual ~CGameEventManager();
int LoadEventsFromFile( const char * filename );
void Reset();
bool AddListener( IGameEventListener2 *listener, const char *name, bool bServerSide );
bool FindListener( IGameEventListener2 *listener, const char *name );
void RemoveListener( IGameEventListener2 *listener);
virtual bool AddListenerGlobal( IGameEventListener2 *listener, bool bServerSide );
IGameEvent *CreateEvent( const char *name, bool bForce = false, int *pCookie = NULL );
IGameEvent *DuplicateEvent( IGameEvent *event);
bool FireEvent( IGameEvent *event, bool bDontBroadcast = false );
bool FireEventClientSide( IGameEvent *event );
void FreeEvent( IGameEvent *event );
bool SerializeEvent( IGameEvent *event, CSVCMsg_GameEvent *eventMsg );
IGameEvent *UnserializeEvent( const CSVCMsg_GameEvent& eventMsg );
virtual KeyValues* GetEventDataTypes( IGameEvent* event );
void DumpEventNetworkStats();
public:
bool Init();
void Shutdown();
void ReloadEventDefinitions(); // called by server on new map
bool AddListener( void *listener, CGameEventDescriptor *descriptor, int nListenerType );
CGameEventDescriptor *GetEventDescriptor( const char *name, int *pCookie = NULL );
CGameEventDescriptor *GetEventDescriptor( IGameEvent *event );
CGameEventDescriptor *GetEventDescriptor( int eventid );
void WriteEventList(CSVCMsg_GameEventList *msg);
bool ParseEventList(const CSVCMsg_GameEventList& msg);
void WriteListenEventList(CCLCMsg_ListenEvents *msg);
bool HasClientListenersChanged( bool bReset = true );
void ConPrintEvent( IGameEvent *event);
// legacy support
bool AddListenerAll( void *listener, int nListenerType );
void RemoveListenerOld( void *listener);
// Debug!
void VerifyListenerList( void );
protected:
IGameEvent *CreateEvent( CGameEventDescriptor *descriptor, const char *name );
bool RegisterEvent( KeyValues * keys );
void UnregisterEvent(int index);
bool FireEventIntern( IGameEvent *event, bool bServerSide, bool bClientOnly );
CGameEventCallback* FindEventListener( void* listener );
CUtlVector<CGameEventDescriptor> m_GameEvents; // list of all known events
CUtlVector<CGameEventCallback*> m_Listeners; // list of all registered listeners
CUtlSymbolTable m_EventFiles; // list of all loaded event files
CUtlVector<CUtlSymbol> m_EventFileNames;
CUtlDict<int, int> m_EventMap;
CThreadFastMutex m_mutex; // lock this when modifying the event table
bool m_bClientListenersChanged; // true every time client changed listeners
};
extern CGameEventManager &g_GameEventManager;
#endif
+144
View File
@@ -0,0 +1,144 @@
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose: wrapper for GameEvent manager legacy support
//
// $NoKeywords: $
//
//=============================================================================//
// GameEventManager.cpp: implementation of the CGameEventManager class.
//
//////////////////////////////////////////////////////////////////////
#include "GameEventManager.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
class CGameEventManagerOld : public IGameEventManager
{
public: // IGameEventManager wrapper
int LoadEventsFromFile( const char * filename ) { return g_GameEventManager.LoadEventsFromFile( filename ); }
KeyValues *GetEvent(const char * name);
void Reset() { g_GameEventManager.Reset(); }
bool AddListener( IGameEventListener * listener, const char * event, bool bIsServerSide );
bool AddListener( IGameEventListener * listener, bool bIsServerSide );
void RemoveListener(IGameEventListener * listener);
bool FireEvent( KeyValues * event );
bool FireEventClientOnly( KeyValues * event );
bool FireEventServerOnly( KeyValues * event );
bool SerializeKeyValues( KeyValues *event, bf_write *buf, CGameEvent *eventtype = NULL );
KeyValues * UnserializeKeyValue( bf_read *msg ); // create new KeyValues, must be deleted
protected:
bool FireEventIntern( KeyValues * event, bool bServerSide, bool bClientSide );
};
static CGameEventManagerOld s_GameEventManagerOld;
// Expose CVEngineServer to the engine.
EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CGameEventManagerOld, IGameEventManager, INTERFACEVERSION_GAMEEVENTSMANAGER, s_GameEventManagerOld );
bool CGameEventManagerOld::AddListener( IGameEventListener * listener, const char * event, bool bIsServerSide )
{
CGameEventDescriptor *descriptor = g_GameEventManager.GetEventDescriptor( event );
if ( !descriptor )
return false;
if ( bIsServerSide )
{
return g_GameEventManager.AddListener( listener, descriptor, CGameEventManager::SERVERSIDE_OLD );
}
else
{
return g_GameEventManager.AddListener( listener, descriptor, CGameEventManager::CLIENTSIDE_OLD );
}
}
bool CGameEventManagerOld::AddListener( IGameEventListener * listener, bool bIsServerSide )
{
if ( bIsServerSide )
{
return g_GameEventManager.AddListenerAll( listener, CGameEventManager::SERVERSIDE_OLD );
}
else
{
return g_GameEventManager.AddListenerAll( listener, CGameEventManager::CLIENTSIDE_OLD );
}
}
void CGameEventManagerOld::RemoveListener(IGameEventListener * listener)
{
g_GameEventManager.RemoveListenerOld( listener );
}
KeyValues *CGameEventManagerOld::GetEvent(const char * name)
{
CGameEventDescriptor *event = g_GameEventManager.GetEventDescriptor( name );
if ( !event )
return NULL;
return event->keys;
}
bool CGameEventManagerOld::FireEvent( KeyValues * event )
{
return FireEventIntern( event, false, false );
}
bool CGameEventManagerOld::FireEventClientOnly( KeyValues * event )
{
return FireEventIntern( event, false, true );
}
bool CGameEventManagerOld::FireEventServerOnly( KeyValues * event )
{
return FireEventIntern( event, true, false );
}
bool CGameEventManagerOld::FireEventIntern( KeyValues *keys, bool bServerSideOnly, bool bClientSideOnly )
{
if ( !keys )
return false;
CGameEvent *event = (CGameEvent*) g_GameEventManager.CreateEvent( keys->GetName() );
if ( !event )
return false;
event->m_pDataKeys->deleteThis();
event->m_pDataKeys = keys;
if ( bClientSideOnly )
{
return g_GameEventManager.FireEventClientSide( event );
}
else
{
return g_GameEventManager.FireEvent( event, bServerSideOnly );
}
}
bool CGameEventManagerOld::SerializeKeyValues( KeyValues* event, bf_write* buf, CGameEvent* eventtype )
{
DevMsg("SerializeKeyValues:: not supported\n");
return false;
}
KeyValues *CGameEventManagerOld::UnserializeKeyValue( bf_read *buf)
{
DevMsg("UnserializeKeyValue:: not supported\n");
return NULL;
}
+56
View File
@@ -0,0 +1,56 @@
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
#ifndef IOCCLUSIONSYSTEM_H
#define IOCCLUSIONSYSTEM_H
#ifdef _WIN32
#pragma once
#endif
class Vector;
class VMatrix;
struct model_t;
class VPlane;
class CUtlBuffer;
//-----------------------------------------------------------------------------
// Occlusion system interface
//-----------------------------------------------------------------------------
class IOcclusionSystem
{
public:
// Activate/deactivate an occluder brush model
virtual void ActivateOccluder( int nOccluderIndex, bool bActive ) = 0;
// Sets the view transform
virtual void SetView( const Vector &vecCameraPos, float flFOV, const VMatrix &worldToCamera,
const VMatrix &cameraToProjection, const VPlane &nearClipPlane ) = 0;
virtual int GetViewId() const = 0;
// Test for occlusion (bounds specified in abs space)
virtual bool IsOccluded( int occlusionViewId, const Vector &vecAbsMins, const Vector &vecAbsMaxs ) = 0;
// Sets global occlusion parameters
virtual void SetOcclusionParameters( float flMaxOccludeeArea, float flMinOccluderArea ) = 0;
virtual float MinOccluderArea() const = 0;
// Render debugging overlay
virtual void DrawDebugOverlays() = 0;
};
//-----------------------------------------------------------------------------
// Singleton accessor
//-----------------------------------------------------------------------------
IOcclusionSystem *OcclusionSystem();
#endif // IOCCLUSIONSYSTEM_H
+284
View File
@@ -0,0 +1,284 @@
//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======//
//
// Purpose: To accomplish X360 TCR 22, we need to call present ever 66msec
// at least during loading screens. This amazing hack will do it
// by overriding the allocator to tick it every so often.
//
// $NoKeywords: $
//===========================================================================//
#include "LoadScreenUpdate.h"
#include "tier0/memalloc.h"
#include "tier1/delegates.h"
#include "tier0/threadtools.h"
#include "tier2/tier2.h"
#include "materialsystem/imaterialsystem.h"
#include "tier0/dbg.h"
// NOTE: This has to be the last file included!
#include "tier0/memdbgon.h"
//-----------------------------------------------------------------------------
// Used to tick the loading screen every so often
//-----------------------------------------------------------------------------
class CLoaderMemAlloc : public IMemAlloc
{
// Methods of IMemAlloc
public:
virtual void *Alloc( size_t nSize );
virtual void *Realloc( void *pMem, size_t nSize );
virtual void Free( void *pMem );
DELEGATE_TO_OBJECT_2( void *, Expand_NoLongerSupported, void *, size_t, m_pMemAlloc );
virtual void *Alloc( size_t nSize, const char *pFileName, int nLine );
virtual void *Realloc( void *pMem, size_t nSize, const char *pFileName, int nLine );
virtual void Free( void *pMem, const char *pFileName, int nLine );
#ifdef MEMALLOC_SUPPORTS_ALIGNED_ALLOCATIONS
DELEGATE_TO_OBJECT_2( void *, AllocAlign, size_t, size_t, m_pMemAlloc );
DELEGATE_TO_OBJECT_4( void *, AllocAlign, size_t, size_t, const char *, int, m_pMemAlloc );
DELEGATE_TO_OBJECT_3( void *, ReallocAlign, void *, size_t, size_t, m_pMemAlloc );
#endif
DELEGATE_TO_OBJECT_4( void*, Expand_NoLongerSupported, void *, size_t, const char *, int, m_pMemAlloc );
DELEGATE_TO_OBJECT_1( size_t, GetSize, void *, m_pMemAlloc );
DELEGATE_TO_OBJECT_2V( PushAllocDbgInfo, const char *, int, m_pMemAlloc );
DELEGATE_TO_OBJECT_0V( PopAllocDbgInfo, m_pMemAlloc );
DELEGATE_TO_OBJECT_1( int32, CrtSetBreakAlloc, int32, m_pMemAlloc );
DELEGATE_TO_OBJECT_2( int, CrtSetReportMode, int, int, m_pMemAlloc );
DELEGATE_TO_OBJECT_1( int, CrtIsValidHeapPointer, const void *, m_pMemAlloc );
DELEGATE_TO_OBJECT_3( int, CrtIsValidPointer, const void *, unsigned int, int, m_pMemAlloc );
DELEGATE_TO_OBJECT_0( int, CrtCheckMemory, m_pMemAlloc );
DELEGATE_TO_OBJECT_1( int, CrtSetDbgFlag, int, m_pMemAlloc );
DELEGATE_TO_OBJECT_1V( CrtMemCheckpoint, _CrtMemState *, m_pMemAlloc );
DELEGATE_TO_OBJECT_0V( DumpStats, m_pMemAlloc );
DELEGATE_TO_OBJECT_2V( DumpStatsFileBase, const char *, IMemAlloc::DumpStatsFormat_t, m_pMemAlloc );
DELEGATE_TO_OBJECT_1( size_t, ComputeMemoryUsedBy, const char *, m_pMemAlloc );
DELEGATE_TO_OBJECT_2( void*, CrtSetReportFile, int, void*, m_pMemAlloc );
DELEGATE_TO_OBJECT_1( void*, CrtSetReportHook, void*, m_pMemAlloc );
DELEGATE_TO_OBJECT_5( int, CrtDbgReport, int, const char *, int, const char *, const char *, m_pMemAlloc );
DELEGATE_TO_OBJECT_0( int, heapchk, m_pMemAlloc );
DELEGATE_TO_OBJECT_0( bool, IsDebugHeap, m_pMemAlloc );
DELEGATE_TO_OBJECT_2V( GetActualDbgInfo, const char *&, int &, m_pMemAlloc );
DELEGATE_TO_OBJECT_5V( RegisterAllocation, const char *, int, size_t, size_t, unsigned, m_pMemAlloc );
DELEGATE_TO_OBJECT_5V( RegisterDeallocation, const char *, int, size_t, size_t, unsigned, m_pMemAlloc );
DELEGATE_TO_OBJECT_0( int, GetVersion, m_pMemAlloc );
DELEGATE_TO_OBJECT_0V( CompactHeap, m_pMemAlloc );
DELEGATE_TO_OBJECT_1( MemAllocFailHandler_t, SetAllocFailHandler, MemAllocFailHandler_t, m_pMemAlloc );
DELEGATE_TO_OBJECT_1V( DumpBlockStats, void *, m_pMemAlloc );
DELEGATE_TO_OBJECT_2V( SetStatsExtraInfo, const char *, const char *, m_pMemAlloc );
DELEGATE_TO_OBJECT_0( size_t, MemoryAllocFailed, m_pMemAlloc );
DELEGATE_TO_OBJECT_0V( CompactIncremental, m_pMemAlloc );
DELEGATE_TO_OBJECT_1V( OutOfMemory, size_t, m_pMemAlloc );
DELEGATE_TO_OBJECT_2V( GlobalMemoryStatus, size_t *, size_t *, m_pMemAlloc );
DELEGATE_TO_OBJECT_1( IVirtualMemorySection *, AllocateVirtualMemorySection, size_t, m_pMemAlloc );
DELEGATE_TO_OBJECT_1( int, GetGenericMemoryStats, GenericMemoryStat_t **, m_pMemAlloc );
virtual uint32 GetDebugInfoSize() { return 0; }
virtual void SaveDebugInfo( void *pvDebugInfo ) { }
virtual void RestoreDebugInfo( const void *pvDebugInfo ) {}
virtual void InitDebugInfo( void *pvDebugInfo, const char *pchRootFileName, int nLine ) {}
virtual void *RegionAlloc( int region, size_t nSize );
virtual void *RegionAlloc( int region, size_t nSize, const char *pFileName, int nLine );
// Other public methods
public:
CLoaderMemAlloc();
void Start( MaterialNonInteractiveMode_t mode );
void Stop();
void AbortDueToShutdown();
void Pause( bool bPause );
// Check if we need to call swap. Do so if necessary.
void CheckSwap( );
private:
IMemAlloc *m_pMemAlloc;
bool m_bPaused;
};
//-----------------------------------------------------------------------------
// Activate, deactivate loadermemalloc
//-----------------------------------------------------------------------------
static bool s_bLoadingUpdatesEnabled = true;
static CLoaderMemAlloc s_LoaderMemAlloc;
void AbortLoadingUpdatesDueToShutdown()
{
if ( IsGameConsole() && s_bLoadingUpdatesEnabled )
{
s_LoaderMemAlloc.AbortDueToShutdown();
}
s_bLoadingUpdatesEnabled = false;
}
void BeginLoadingUpdates( MaterialNonInteractiveMode_t mode )
{
if ( IsGameConsole() && s_bLoadingUpdatesEnabled )
{
s_LoaderMemAlloc.Start( mode );
}
}
void RefreshScreenIfNecessary()
{
if ( IsGameConsole() && s_bLoadingUpdatesEnabled )
{
s_LoaderMemAlloc.CheckSwap();
}
}
void PauseLoadingUpdates( bool bPause )
{
if ( IsGameConsole() && s_bLoadingUpdatesEnabled )
{
s_LoaderMemAlloc.Pause( bPause );
}
}
void EndLoadingUpdates()
{
if ( IsGameConsole() && s_bLoadingUpdatesEnabled )
{
s_LoaderMemAlloc.Stop();
}
}
static int LoadLibraryThreadFunc()
{
RefreshScreenIfNecessary();
return 15;
}
//-----------------------------------------------------------------------------
// Used to tick the loading screen every so often
//-----------------------------------------------------------------------------
CLoaderMemAlloc::CLoaderMemAlloc()
{
m_pMemAlloc = 0;
m_bPaused = false;
}
void CLoaderMemAlloc::Start( MaterialNonInteractiveMode_t mode )
{
AssertFatal( ThreadInMainThread() );
if ( g_pMemAlloc == this || ( mode == MATERIAL_NON_INTERACTIVE_MODE_NONE ) )
return;
CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
pRenderContext->EnableNonInteractiveMode( mode );
if ( mode == MATERIAL_NON_INTERACTIVE_MODE_STARTUP )
{
SetThreadedLoadLibraryFunc( LoadLibraryThreadFunc );
}
// NOTE: This is necessary to avoid a one-frame black flash
// since Present is what copies the back buffer into the temp buffer
if ( mode == MATERIAL_NON_INTERACTIVE_MODE_LEVEL_LOAD )
{
extern void V_RenderVGuiOnly( void );
V_RenderVGuiOnly();
}
m_pMemAlloc = g_pMemAlloc;
g_pMemAlloc = this;
m_bPaused = false;
}
void CLoaderMemAlloc::Stop()
{
AssertFatal( ThreadInMainThread() );
if ( g_pMemAlloc != this )
return;
g_pMemAlloc = m_pMemAlloc;
m_bPaused = false;
CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
pRenderContext->EnableNonInteractiveMode( MATERIAL_NON_INTERACTIVE_MODE_NONE );
SetThreadedLoadLibraryFunc( NULL );
}
void CLoaderMemAlloc::AbortDueToShutdown()
{
AssertFatal( ThreadInMainThread() );
if ( g_pMemAlloc != this )
return;
g_pMemAlloc = m_pMemAlloc;
m_bPaused = false;
}
void CLoaderMemAlloc::Pause( bool bPause )
{
if ( g_pMemAlloc != this )
return;
m_bPaused = bPause;
}
//-----------------------------------------------------------------------------
// Check if we need to call swap. Do so if necessary.
//-----------------------------------------------------------------------------
void CLoaderMemAlloc::CheckSwap( )
{
if ( g_pMemAlloc != this || m_bPaused )
return;
g_pMaterialSystem->RefreshFrontBufferNonInteractive();
}
//-----------------------------------------------------------------------------
// Hook allocations, render when appropriate
//-----------------------------------------------------------------------------
void *CLoaderMemAlloc::Alloc( size_t nSize )
{
CheckSwap();
return m_pMemAlloc->IndirectAlloc( nSize );
}
void *CLoaderMemAlloc::Realloc( void *pMem, size_t nSize )
{
CheckSwap();
return m_pMemAlloc->Realloc( pMem, nSize );
}
void CLoaderMemAlloc::Free( void *pMem )
{
CheckSwap();
m_pMemAlloc->Free( pMem );
}
void *CLoaderMemAlloc::Alloc( size_t nSize, const char *pFileName, int nLine )
{
CheckSwap();
return m_pMemAlloc->IndirectAlloc( nSize, pFileName, nLine );
}
void *CLoaderMemAlloc::Realloc( void *pMem, size_t nSize, const char *pFileName, int nLine )
{
CheckSwap();
return m_pMemAlloc->Realloc( pMem, nSize, pFileName, nLine );
}
void CLoaderMemAlloc::Free( void *pMem, const char *pFileName, int nLine )
{
CheckSwap();
m_pMemAlloc->Free( pMem, pFileName, nLine );
}
void *CLoaderMemAlloc::RegionAlloc( int region, size_t nSize )
{
CheckSwap();
return m_pMemAlloc->RegionAlloc( region, nSize );
}
void *CLoaderMemAlloc::RegionAlloc( int region, size_t nSize, const char *pFileName, int nLine )
{
CheckSwap();
return m_pMemAlloc->RegionAlloc( region, nSize, pFileName, nLine );
}
+29
View File
@@ -0,0 +1,29 @@
//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======//
//
// Purpose: To accomplish X360 TCR 22, we need to call present ever 66msec
// at least during loading screens. This amazing hack will do it
// by overriding the allocator to tick it every so often.
//
// $NoKeywords: $
//===========================================================================//
#ifndef LOAD_SCREEN_UPDATE_H
#define LOAD_SCREEN_UPDATE_H
#ifdef _WIN32
#pragma once
#endif
#include "materialsystem/imaterialsystem.h"
//-----------------------------------------------------------------------------
// Activate, deactivate loader updates
//-----------------------------------------------------------------------------
void BeginLoadingUpdates( MaterialNonInteractiveMode_t mode );
void RefreshScreenIfNecessary();
void EndLoadingUpdates();
void PauseLoadingUpdates( bool bPause );
#endif /* LOAD_SCREEN_UPDATE_H */
+414
View File
@@ -0,0 +1,414 @@
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "LocalNetworkBackdoor.h"
#include "server_class.h"
#include "client_class.h"
#include "server.h"
#include "eiface.h"
#include "cdll_engine_int.h"
#include "dt_localtransfer.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
CLocalNetworkBackdoor *g_pLocalNetworkBackdoor = NULL;
#ifndef DEDICATED
// This is called
void CLocalNetworkBackdoor::InitFastCopy()
{
if ( !GetBaseLocalClient().m_NetChannel->IsLoopback() )
return;
const CStandardSendProxies *pSendProxies = serverGameDLL->GetStandardSendProxies();
const CStandardRecvProxies *pRecvProxies = g_ClientDLL->GetStandardRecvProxies();
int nFastCopyProps = 0;
int nSlowCopyProps = 0;
for ( int iClass=0; iClass < GetBaseLocalClient().m_nServerClasses; iClass++ )
{
ClientClass *pClientClass = GetBaseLocalClient().GetClientClass(iClass);
if ( !pClientClass )
Error( "InitFastCopy - missing client class %d (Should be equivelent of server class: %s)", iClass, GetBaseLocalClient().m_pServerClasses[iClass].m_ClassName );
ServerClass *pServerClass = SV_FindServerClass( pClientClass->GetName() );
if ( !pServerClass )
Error( "InitFastCopy - missing server class %s", pClientClass->GetName() );
LocalTransfer_InitFastCopy(
pServerClass->m_pTable,
pSendProxies,
pClientClass->m_pRecvTable,
pRecvProxies,
nSlowCopyProps,
nFastCopyProps
);
}
int percentFast = (nFastCopyProps * 100 ) / (nSlowCopyProps + nFastCopyProps + 1);
if ( percentFast <= 45 )
{
// This may not be a real problem, but at the time this code was added, 67% of the
// properties were able to be copied without proxies. If percentFast goes to 0 or some
// really low number suddenly, then something probably got screwed up.
Assert( false );
Warning( "InitFastCopy: only %d%% fast props. Bug?\n", percentFast );
}
}
#endif //DEDICATED
void CLocalNetworkBackdoor::StartEntityStateUpdate()
{
m_EntsAlive.ClearAll();
m_nEntsCreated = 0;
m_nEntsChanged = 0;
// signal client that we start updating entities
ClientDLL_FrameStageNotify( FRAME_NET_UPDATE_START );
}
void CLocalNetworkBackdoor::EndEntityStateUpdate()
{
MDLCACHE_CRITICAL_SECTION_( g_pMDLCache );
ClientDLL_FrameStageNotify( FRAME_NET_UPDATE_POSTDATAUPDATE_START );
// Handle entities created.
int i;
for ( i=0; i < m_nEntsCreated; i++ )
{
int iEdict = m_EntsCreatedIndices[i];
CCachedEntState *pCached = &m_CachedEntState[iEdict];
IClientNetworkable *pNet = pCached->m_pNetworkable;
pNet->PostDataUpdate( DATA_UPDATE_CREATED );
pNet->NotifyShouldTransmit( SHOULDTRANSMIT_START );
pCached->m_bDormant = false;
}
// Handle entities changed.
for ( i=0; i < m_nEntsChanged; i++ )
{
int iEdict = m_EntsChangedIndices[i];
m_CachedEntState[iEdict].m_pNetworkable->PostDataUpdate( DATA_UPDATE_DATATABLE_CHANGED );
}
ClientDLL_FrameStageNotify( FRAME_NET_UPDATE_POSTDATAUPDATE_END );
// Handle entities removed (= SV_WriteDeletions() in normal mode)
int nDWords = m_PrevEntsAlive.GetNumDWords();
// Handle entities removed.
for ( i=0; i < nDWords; i++ )
{
unsigned long prevEntsAlive = m_PrevEntsAlive.GetDWord( i );
unsigned long entsAlive = m_EntsAlive.GetDWord( i );
unsigned long toDelete = (prevEntsAlive ^ entsAlive) & prevEntsAlive;
if ( toDelete )
{
for ( int iBit=0; iBit < 32; iBit++ )
{
if ( toDelete & (1 << iBit) )
{
int iEdict = (i<<5) + iBit;
if ( iEdict < MAX_EDICTS )
{
if ( m_CachedEntState[iEdict].m_pNetworkable )
{
m_CachedEntState[iEdict].m_pNetworkable->Release();
m_CachedEntState[iEdict].m_pNetworkable = NULL;
}
else
{
AssertOnce( !"EndEntityStateUpdate: Would have crashed with NULL m_pNetworkable\n" );
}
}
else
{
AssertOnce( !"EndEntityStateUpdate: Would have crashed with entity out of range\n" );
}
}
}
}
}
// Remember the previous state of which entities were around.
m_PrevEntsAlive = m_EntsAlive;
// end of all entity update activity
ClientDLL_FrameStageNotify( FRAME_NET_UPDATE_END );
/*
#ifdef _DEBUG
for ( i=0; i <= highest_index; i++ )
{
if ( !( m_EntsAlive[i>>5] & (1 << (i & 31)) ) )
Assert( !m_CachedEntState[i].m_pNetworkable );
if ( ( m_EntsAlive[i>>5] & (1 << (i & 31)) ) &&
( m_EntsCreated[i>>5] & (1 << (i & 31)) ) )
{
Assert( FindInList( m_EntsCreatedIndices, m_nEntsCreated, i ) );
}
if ( (m_EntsAlive[i>>5] & (1 << (i & 31))) &&
!(m_EntsCreated[i>>5] & (1 << (i & 31))) &&
(m_EntsChanged[i>>5] & (1 << (i & 31)))
)
{
Assert( FindInList( m_EntsChangedIndices, m_nEntsChanged, i ) );
}
}
#endif
*/
}
void CLocalNetworkBackdoor::EntityDormant( int iEnt, int iSerialNum )
{
CCachedEntState *pCached = &m_CachedEntState[iEnt];
IClientNetworkable *pNet = pCached->m_pNetworkable;
Assert( pNet == entitylist->GetClientNetworkable( iEnt ) );
if ( pNet )
{
Assert( pCached->m_iSerialNumber == pNet->GetIClientUnknown()->GetRefEHandle().GetSerialNumber() );
if ( pCached->m_iSerialNumber == iSerialNum )
{
m_EntsAlive.Set( iEnt );
// Tell the game code that this guy is now dormant.
Assert( pCached->m_bDormant == pNet->IsDormant() );
if ( !pCached->m_bDormant )
{
pNet->NotifyShouldTransmit( SHOULDTRANSMIT_END );
pCached->m_bDormant = true;
}
}
else
{
pNet->Release();
pCached->m_pNetworkable = NULL;
m_PrevEntsAlive.Clear( iEnt );
}
}
}
void CLocalNetworkBackdoor::AddToPendingDormantEntityList( unsigned short iEdict )
{
edict_t *e = &sv.edicts[iEdict];
if ( !( e->m_fStateFlags & FL_EDICT_PENDING_DORMANT_CHECK ) )
{
e->m_fStateFlags |= FL_EDICT_PENDING_DORMANT_CHECK;
m_PendingDormantEntities.AddToTail( iEdict );
}
}
void CLocalNetworkBackdoor::ProcessDormantEntities()
{
FOR_EACH_LL( m_PendingDormantEntities, i )
{
int iEdict = m_PendingDormantEntities[i];
edict_t *e = &sv.edicts[iEdict];
// Make sure the entity still exists and stil has the dontsend flag set.
if ( e->IsFree() || !(e->m_fStateFlags & FL_EDICT_DONTSEND) )
{
e->m_fStateFlags &= ~FL_EDICT_PENDING_DORMANT_CHECK;
continue;
}
EntityDormant( iEdict, e->m_NetworkSerialNumber );
e->m_fStateFlags &= ~FL_EDICT_PENDING_DORMANT_CHECK;
}
m_PendingDormantEntities.Purge();
}
void CLocalNetworkBackdoor::EntState(
int iEnt,
int iSerialNum,
int iClass,
const SendTable *pSendTable,
const void *pSourceEnt,
bool bChanged,
bool bShouldTransmit )
{
#ifndef DEDICATED
CCachedEntState *pCached = &m_CachedEntState[iEnt];
// Remember that this ent is alive.
m_EntsAlive.Set(iEnt);
ClientClass *pClientClass = GetBaseLocalClient().GetClientClass(iClass);
if ( !pClientClass )
Error( "CLocalNetworkBackdoor::EntState - missing client class %d", iClass );
IClientNetworkable *pNet = pCached->m_pNetworkable;
Assert( pNet == entitylist->GetClientNetworkable( iEnt ) );
if ( !bShouldTransmit )
{
if ( pNet )
{
Assert( pCached->m_iSerialNumber == pNet->GetIClientUnknown()->GetRefEHandle().GetSerialNumber() );
if ( pCached->m_iSerialNumber == iSerialNum )
{
// Tell the game code that this guy is now dormant.
Assert( pCached->m_bDormant == pNet->IsDormant() );
if ( !pCached->m_bDormant )
{
pNet->NotifyShouldTransmit( SHOULDTRANSMIT_END );
pCached->m_bDormant = true;
}
}
else
{
pNet->Release();
pNet = NULL;
pCached->m_pNetworkable = NULL;
// Since we set this above, need to clear it now to avoid assertion in EndEntityStateUpdate()
m_EntsAlive.Clear(iEnt);
m_PrevEntsAlive.Clear( iEnt );
}
}
else
{
m_EntsAlive.Clear( iEnt );
}
return;
}
// Do we have an entity here already?
bool bExistedAndWasDormant = false;
if ( pNet )
{
// If the serial numbers are different, make it recreate the ent.
Assert( pCached->m_iSerialNumber == pNet->GetIClientUnknown()->GetRefEHandle().GetSerialNumber() );
if ( iSerialNum == pCached->m_iSerialNumber )
{
bExistedAndWasDormant = pCached->m_bDormant;
}
else
{
pNet->Release();
pNet = NULL;
m_PrevEntsAlive.Clear(iEnt);
}
}
// Create the entity?
bool bCreated = false;
DataUpdateType_t updateType;
if ( pNet )
{
updateType = DATA_UPDATE_DATATABLE_CHANGED;
}
else
{
updateType = DATA_UPDATE_CREATED;
pNet = pClientClass->m_pCreateFn( iEnt, iSerialNum );
bCreated = true;
m_EntsCreatedIndices[m_nEntsCreated++] = iEnt;
pCached->m_iSerialNumber = iSerialNum;
pCached->m_pDataPointer = pNet->GetDataTableBasePtr();
pCached->m_pNetworkable = pNet;
// Tracker 73192: ywb 8/1/07: We used to get an assertion that the pCached->m_bDormant was not equal to pNet->IsDormant() in ProcessDormantEntities.
// This appears to be the case if when we get here, the entity is set for Transmit still, but is a dormant entity on the server.
// Seems safe to go ahead an fill in the cache with the correct data. Probably was just an oversight.
pCached->m_bDormant = pNet->IsDormant();
}
if ( bChanged || bCreated || bExistedAndWasDormant )
{
pNet->PreDataUpdate( updateType );
Assert( pCached->m_pDataPointer == pNet->GetDataTableBasePtr() );
LocalTransfer_TransferEntity(
&sv.edicts[iEnt],
pSendTable,
pSourceEnt,
pClientClass->m_pRecvTable,
pCached->m_pDataPointer,
bCreated,
bExistedAndWasDormant,
iEnt );
if ( bExistedAndWasDormant )
{
// Set this so we use DATA_UPDATE_CREATED logic
m_EntsCreatedIndices[m_nEntsCreated++] = iEnt;
}
else
{
if ( !bCreated )
{
m_EntsChangedIndices[m_nEntsChanged++] = iEnt;
}
}
}
#endif
}
void CLocalNetworkBackdoor::ClearState()
{
// Clear the cache for all the entities.
for ( int i=0; i < MAX_EDICTS; i++ )
{
CCachedEntState &ces = m_CachedEntState[i];
ces.m_pNetworkable = NULL;
ces.m_iSerialNumber = -1;
ces.m_bDormant = false;
ces.m_pDataPointer = NULL;
}
m_PrevEntsAlive.ClearAll();
}
void CLocalNetworkBackdoor::StartBackdoorMode()
{
ClearState();
for ( int i=0; i < MAX_EDICTS; i++ )
{
IClientNetworkable *pNet = entitylist->GetClientNetworkable( i );
CCachedEntState &ces = m_CachedEntState[i];
if ( pNet )
{
ces.m_pNetworkable = pNet;
ces.m_iSerialNumber = pNet->GetIClientUnknown()->GetRefEHandle().GetSerialNumber();
ces.m_bDormant = pNet->IsDormant();
ces.m_pDataPointer = pNet->GetDataTableBasePtr();
m_PrevEntsAlive.Set( i );
}
}
}
void CLocalNetworkBackdoor::StopBackdoorMode()
{
ClearState();
}
void CLocalNetworkBackdoor::ForceFlushEntity( int iEntity )
{
CCachedEntState *pCached = &m_CachedEntState[iEntity];
if ( pCached->m_pNetworkable )
pCached->m_pNetworkable->Release();
pCached->m_pNetworkable = NULL;
pCached->m_iSerialNumber = -1;
pCached->m_bDormant = false;
pCached->m_pDataPointer = NULL;
}
+113
View File
@@ -0,0 +1,113 @@
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef LOCALNETWORKBACKDOOR_H
#define LOCALNETWORKBACKDOOR_H
#ifdef _WIN32
#pragma once
#endif
#include "quakedef.h"
#include "cl_localnetworkbackdoor.h"
#include "icliententitylist.h"
#include "LocalNetworkBackdoor.h"
#include "iclientnetworkable.h"
#include "basehandle.h"
#include "client_class.h"
#include "dt_localtransfer.h"
#include "client.h"
#include "cdll_engine_int.h"
#include "datacache/imdlcache.h"
#include "sys_dll.h"
#include "utllinkedlist.h"
#include "edict.h"
#include "server.h"
class SendTable;
class CLocalNetworkBackdoor
{
public:
void StartEntityStateUpdate();
void EndEntityStateUpdate();
void EntityDormant( int iEnt, int iSerialNum );
void AddToPendingDormantEntityList( unsigned short iEdict );
void ProcessDormantEntities();
void NotifyEdictFlagsChange( int iEdict )
{
// If they newly added the dontsend flag, then we need to run it through EntityDormant.
if ( sv.edicts[iEdict].m_fStateFlags & FL_EDICT_DONTSEND )
AddToPendingDormantEntityList( iEdict );
}
void EntState(
int iEnt,
int iSerialNum,
int iClass,
const SendTable *pSendTable,
const void *pSourceEnt,
bool bChanged,
bool bShouldTransmit );
void ClearState();
void StartBackdoorMode();
void StopBackdoorMode();
// Used by Foundry when it changes an entity (and possibly its class) but preserves its serial number.
void ForceFlushEntity( int iEntity );
// This is called when the client DLL is loaded to precalculate data to let it copy data faster.
static void InitFastCopy();
private:
// Temporarily built up while processing a frame.
CBitVec<MAX_EDICTS> m_EntsAlive;
// This should correspond to which m_CachedEntState entries have a non-null m_pNetworkable pointer.
CBitVec<MAX_EDICTS> m_PrevEntsAlive;
// Entities that get created during a frame are remembered here.
unsigned short m_EntsCreatedIndices[MAX_EDICTS];
int m_nEntsCreated;
// Entities that changed but weren't created go here.
unsigned short m_EntsChangedIndices[MAX_EDICTS];
int m_nEntsChanged;
// Tell the client DLL about entities that need to be notified about being dormant.
// Anything that EntityDormant() would care about needs to get added to this list.
CUtlLinkedList<unsigned short,unsigned short> m_PendingDormantEntities;
// This data is cached in here so we don't have to call a lot of virtuals to get it from the client DLL.
class CCachedEntState
{
public:
CCachedEntState()
{
m_iSerialNumber = -1;
}
bool m_bDormant;
int m_iSerialNumber;
void *m_pDataPointer;
IClientNetworkable *m_pNetworkable;
};
CCachedEntState m_CachedEntState[MAX_EDICTS];
};
// The client will set this if it decides to use the fast path.
extern CLocalNetworkBackdoor *g_pLocalNetworkBackdoor;
#endif // LOCALNETWORKBACKDOOR_H
File diff suppressed because it is too large Load Diff
+130
View File
@@ -0,0 +1,130 @@
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef MAPRESLISTGENERATOR_H
#define MAPRESLISTGENERATOR_H
#ifdef _WIN32
#pragma once
#endif
#include "filesystem.h"
#include "utlvector.h"
#include "utlsymbol.h"
#include "utlstring.h"
// Map list creation
// Map entry
struct maplist_map_t
{
char name[64];
};
// General purpose maplist generator.
// aMaps: Utlvector you'd like filled with the maps.
// bUseMapListFile: true if you want to use a maplist file, vs parsing the maps directory or using +map
// pMapFile: If you're using a maplist file, this should be the filename of it
// pSystemMsg: Used to preface and debug messages
// iCurrentMap: The map in the list to begin at. Handles the -startmap parameter for you.
bool BuildGeneralMapList( CUtlVector<maplist_map_t> *aMaps, bool bUseMapListFile, const char *pMapFile, char *pSystemMsg, int *iCurrentMap );
// initialization
void MapReslistGenerator_Init();
void MapReslistGenerator_Shutdown();
void MapReslistGenerator_BuildMapList();
//-----------------------------------------------------------------------------
// Purpose: Handles collating lists of resources on level load
// Used to generate reslists for steam
//-----------------------------------------------------------------------------
class CMapReslistGenerator
{
public:
CMapReslistGenerator();
// initializes the object to enable reslist generation
void EnableReslistGeneration( bool usemaplistfile );
// starts the reslist generation (starts cycling maps)
void StartReslistGeneration();
void BuildMapList();
void Shutdown();
// call every frame if we're enabled, just so that the next map can be triggered at the right time
void RunFrame();
// returns true if reslist generation is enabled
bool IsEnabled() { return m_bLoggingEnabled; }
bool IsLoggingToMap() { return m_bLoggingEnabled && !m_bLogToEngineList; }
bool IsCreatingForXbox();
// call to mark level load/end
void OnLevelLoadStart(const char *levelName);
void OnLevelLoadEnd();
void OnLevelShutdown();
void OnPlayerSpawn();
void OnFullyConnected();
// call to mark resources as being precached
void OnResourcePrecached(const char *relativePathFileName);
void OnModelPrecached(const char *relativePathFileName);
void OnSoundPrecached(const char *relativePathFileName);
char const *LogPrefix();
void EnableDeletionsTracking();
void TrackDeletions( const char *fullPathFileName );
bool ShouldRebuildCaches();
char const *GetResListDirectory() const;
void SetAutoQuit( bool bState );
private:
static void TrackDeletionsLoggingFunc(const char *fullPathFileName, const char *options);
static void FileSystemLoggingFunc(const char *fullPathFileName, const char *options);
void OnResourcePrecachedFullPath(const char *fullPathFileName);
void BuildEngineLogFromReslist();
void LogToEngineReslist( char const *pLine );
void WriteMapLog();
void SetPrefix( char const *mapname );
void SpewTrackedDeletionsLog();
void DoQuit();
bool m_bTrackingDeletions;
bool m_bLoggingEnabled;
bool m_bUsingMapList;
bool m_bRestartOnTransition;
bool m_bCreatingForXbox;
// true for engine, false for map
bool m_bLogToEngineList;
bool m_bAutoQuit;
// list of all maps to scan
CUtlVector<maplist_map_t> m_Maps;
int m_iCurrentMap;
float m_flNextMapRunTime;
CUtlSymbolTable m_AlreadyWrittenFileNames;
int m_iPauseTimeBetweenMaps;
char m_szPrefix[64];
char m_szLevelName[MAX_PATH];
CUtlSymbolTable m_DeletionList;
CUtlRBTree< CUtlSymbol > m_DeletionListWarnings;
CUtlSymbolTable m_DeletionListWarningsSymbols;
CUtlRBTree< CUtlString, int > m_MapLog;
CUtlRBTree< CUtlString, int > m_EngineLog;
CUtlString m_sResListDir;
};
// singleton accessor
CMapReslistGenerator &MapReslistGenerator();
#endif // MAPRESLISTGENERATOR_H
+153
View File
@@ -0,0 +1,153 @@
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose: This is a helper class for the situation where you want to build lists of
// things that fall into buckets, and effeciently keep up with which buckets have
// been used since flush.
//
//=============================================================================//
#ifndef MATERIALBUCKETS_H
#define MATERIALBUCKETS_H
#ifdef _WIN32
#pragma once
#endif
// FLASHLIGHTFIXME: Make all of the buckets share the same m_Elements (ie. make m_Elements static)
template <class Element_t>
class CMaterialsBuckets
{
public:
typedef unsigned short SortIDHandle_t;
typedef unsigned short ElementHandle_t;
CMaterialsBuckets()
{
m_FlushCount = -1;
}
// Set the number of buckets that are needed. This should get called every time
// a level is loaded.
void SetNumMaterialSortIDs( int n )
{
m_MaterialSortInfoArray.Purge();
m_MaterialSortInfoArray.SetCount( n );
m_Elements.Purge();
m_UsedSortIDs.Purge();
}
// Clear out all buckets. This should get called once a frame.
void Flush( void )
{
m_FlushCount++;
m_Elements.RemoveAll();
m_UsedSortIDs.RemoveAll();
}
//
// These functions are used to get at the list of used buckets.
//
SortIDHandle_t GetFirstUsedSortID()
{
return m_UsedSortIDs.Head();
}
SortIDHandle_t GetNextUsedSortID( SortIDHandle_t prevSortID )
{
return m_UsedSortIDs.Next( prevSortID );
}
int GetSortID( SortIDHandle_t handle )
{
return m_UsedSortIDs[handle];
}
SortIDHandle_t InvalidSortIDHandle()
{
return m_UsedSortIDs.InvalidIndex();
}
//
// These functions are used to get at the list of elements for each sortID.
//
ElementHandle_t GetElementListHead( int sortID )
{
return m_MaterialSortInfoArray[sortID].m_Head;
}
ElementHandle_t GetElementListNext( ElementHandle_t h )
{
return m_Elements.Next( h );
}
Element_t GetElement( ElementHandle_t h )
{
return m_Elements[h];
}
ElementHandle_t InvalidElementHandle()
{
return m_Elements.InvalidIndex();
}
// Add an element to the the bucket specified by sortID
void AddElement( int sortID, Element_t elem )
{
// Allocate an element to stick this in.
unsigned short elemID = m_Elements.Alloc( true );
m_Elements[elemID] = elem;
if( m_MaterialSortInfoArray[sortID].m_FlushCount != m_FlushCount )
{
// This is the first element that has used this sort id since flush.
// FLASHLIGHTFIXME: need to sort these by vertex format when shoving
// them into this list!
// Mark this sortID as having been used since the last flush.
m_MaterialSortInfoArray[sortID].m_FlushCount = m_FlushCount;
// Add this sortID to the list of sortIDs used since flush.
m_UsedSortIDs.AddToTail( sortID );
// Set the head pointer for this sort id to this element.
m_MaterialSortInfoArray[sortID].m_Head = elemID;
}
else
{
// We already have an element in this sort id since flush, so chain
// into thelist of elements for this sort id.
m_Elements.LinkBefore( m_MaterialSortInfoArray[sortID].m_Head, elemID );
m_MaterialSortInfoArray[sortID].m_Head = elemID;
}
}
private:
struct MaterialSortInfo_t
{
MaterialSortInfo_t() :
m_FlushCount( -1 ),
m_Head( (unsigned short)-1 ) // i.e., InvalidIndex()
{
}
int m_FlushCount;
unsigned short m_Head;
};
// This is a list of material sort info ids that have been used since flush.
CUtlLinkedList<unsigned short> m_UsedSortIDs;
// This is m_NumMaterialSortIDs big.
CUtlVector<MaterialSortInfo_t> m_MaterialSortInfoArray;
// This is used in multilist mode to make elements that belong in the multiple lists of
CUtlLinkedList<Element_t, unsigned short, true> m_Elements;
int m_FlushCount;
};
#endif // MATERIALBUCKETS_H
+1454
View File
File diff suppressed because it is too large Load Diff
+25
View File
@@ -0,0 +1,25 @@
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $Workfile: $
// $NoKeywords: $
//=============================================================================//
#ifndef MODELINFO_H
#define MODELINFO_H
#ifdef _WIN32
#pragma once
#endif
#include "engine/ivmodelinfo.h"
extern IVModelInfo *modelinfo; // server version
#ifndef DEDICATED
extern IVModelInfoClient *modelinfoclient; // client version
#endif
#endif // MODELINFO_H
+232
View File
@@ -0,0 +1,232 @@
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "quakedef.h"
#include "networkstringtableitem.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CNetworkStringTableItem::CNetworkStringTableItem( void )
{
m_pUserData = NULL;
m_nUserDataLength = 0;
m_nTickChanged = 0;
#ifndef SHARED_NET_STRING_TABLES
m_nTickCreated = 0;
m_pChangeList = NULL;
#endif
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CNetworkStringTableItem::~CNetworkStringTableItem( void )
{
#ifndef SHARED_NET_STRING_TABLES
if ( m_pChangeList )
{
// free changelist and elements
for ( int i=0; i < m_pChangeList->Count(); i++ )
{
itemchange_s item = m_pChangeList->Element( i );
if ( item.data )
delete[] item.data;
}
delete m_pChangeList; // destructor calls Purge()
m_pUserData = NULL;
}
#endif
if ( m_pUserData )
{
delete[] m_pUserData;
}
}
#ifndef SHARED_NET_STRING_TABLES
void CNetworkStringTableItem::EnableChangeHistory( void )
{
if ( m_pChangeList )
return; // already enabled
m_pChangeList = new CUtlVector<itemchange_s>;
Assert ( m_pChangeList );
}
void CNetworkStringTableItem::UpdateChangeList( int tick, int length, const void *userData )
{
int count = m_pChangeList->Count();
itemchange_s item;
if ( count > 0 )
{
// check if different from last change in list
item = m_pChangeList->Element( count-1 );
if ( !item.data && !userData )
return; // both NULL data
if ( item.length == length )
{
if ( item.data && userData )
{
if ( Q_memcmp( (void*)userData, (void*)item.data, length ) == 0 )
{
return; // no data or size change
}
}
}
if ( item.tick == tick )
{
// two changes within same tick frame, remove last change from list
if ( item.data )
{
delete[] item.data;
}
m_pChangeList->Remove( count-1 );
}
}
item.tick = tick;
// add new user data and time stamp
if ( userData && length )
{
item.data = new unsigned char[length];
item.length = length;
Q_memcpy( item.data, userData, length );
}
else
{
item.data = NULL;
item.length = 0;
}
m_pChangeList->AddToTail( item );
}
int CNetworkStringTableItem::RestoreTick( int tick )
{
Assert( m_pChangeList->Count()>0 );
int index = 1;
itemchange_s *item = &m_pChangeList->Element( 0 );
while ( index < m_pChangeList->Count() )
{
itemchange_s *nextitem = &m_pChangeList->Element( index );
if ( nextitem->tick > tick )
{
break;
}
item = nextitem;
index++;
}
if ( item->tick > tick )
{
// this string was created after tick, so ignore it right now
m_pUserData = NULL;
m_nUserDataLength = 0;
m_nTickChanged = 0;
}
else
{
// restore user data for this string
m_pUserData = item->data;
m_nUserDataLength = item->length;
m_nTickChanged = item->tick;
}
return m_nTickChanged;
}
#endif
//-----------------------------------------------------------------------------
// Purpose:
// Input : *string -
//-----------------------------------------------------------------------------
bool CNetworkStringTableItem::SetUserData( int tick, int length, const void *userData )
{
#ifndef SHARED_NET_STRING_TABLES
if ( m_pChangeList )
{
UpdateChangeList( tick, length, userData );
return false;
}
Assert ( m_nTickCreated > 0 && m_nTickCreated <= tick );
#endif
Assert ( m_nTickChanged > 0 && m_nTickChanged <= tick );
Assert ( length < CNetworkStringTableItem::MAX_USERDATA_SIZE );
// no old or new data
if ( !userData && !m_pUserData )
return false;
if ( m_pUserData &&
length == m_nUserDataLength &&
!Q_memcmp( m_pUserData, (void*)userData, length ) )
{
return false; // old & new data are equal
}
if ( m_pUserData )
delete[] m_pUserData;
m_nUserDataLength = length;
if ( length > 0 )
{
m_pUserData = new unsigned char[ length ];
Q_memcpy( m_pUserData, userData, length );
}
else
{
m_pUserData = NULL;
}
m_nTickChanged = tick;
return true;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : stringNumber -
// Output : const void
//-----------------------------------------------------------------------------
const void *CNetworkStringTableItem::GetUserData( int *length )
{
if ( length )
*length = m_nUserDataLength;
return ( const void * )m_pUserData;
}
File diff suppressed because it is too large Load Diff
+3107
View File
File diff suppressed because it is too large Load Diff
+68
View File
@@ -0,0 +1,68 @@
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose: Model loading / unloading interface
//
// $NoKeywords: $
//=============================================================================//
#ifndef OVERLAY_H
#define OVERLAY_H
#ifdef _WIN32
#pragma once
#endif
// This is a workaround for the fact that we get massive decal flicker
// when looking at a decal at a glancing angle while standing right next to it.
#define OVERLAY_AVOID_FLICKER_NORMAL_OFFSET 0.1f
//-----------------------------------------------------------------------------
// Overlay fragments
//-----------------------------------------------------------------------------
typedef unsigned short OverlayFragmentHandle_t;
enum
{
OVERLAY_FRAGMENT_INVALID = (OverlayFragmentHandle_t)~0
};
//=============================================================================
//
// Overlay Manager Interface
//
class IOverlayMgr
{
public:
// Memory allocation/de-allocation.
virtual bool LoadOverlays( ) = 0;
virtual void UnloadOverlays( ) = 0;
virtual void CreateFragments( void ) = 0;
virtual void ReSortMaterials( void ) = 0;
// Drawing
// clears all
virtual void ClearRenderLists() = 0;
// clears a particular sort group
virtual void ClearRenderLists( int nSortGroup ) = 0;
virtual void AddFragmentListToRenderList( int nSortGroup, OverlayFragmentHandle_t iFragment, bool bDisp ) = 0;
virtual void RenderOverlays( IMatRenderContext *pRenderContext, int nSortGroup ) = 0;
// Sets the client renderable for an overlay's material proxy to bind to
virtual void SetOverlayBindProxy( int iOverlayID, void *pBindProxy ) = 0;
virtual void UpdateOverlayRenderLevels( int nCPULevel, int nGPULevel ) = 0;
virtual void RenderAllUnlitOverlays( IMatRenderContext *pRenderContext, int nSortGroup ) = 0;
};
//-----------------------------------------------------------------------------
// Overlay manager singleton
//-----------------------------------------------------------------------------
IOverlayMgr *OverlayMgr();
#endif // OVERLAY_H
+38
View File
@@ -0,0 +1,38 @@
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef SVCONNECTIONLESSHANDLER_H
#define SVCONNECTIONLESSHANDLER_H
#ifdef _WIN32
#pragma once
#endif
#include "inetmsghandler.h"
class CServerConnectionlessHandler : public IConnectionlessPacketHandler
{
public:
CServerConnectionlessHandler();
virtual ~CServerConnectionlessHandler();
public:
bool ProcessConnectionlessPacket( netpacket_t * packet );
private :
bool ProcessLog(netpacket_t * packet);
bool ProcessGetChallenge(netpacket_t * packet);
bool ProcessConnect(netpacket_t * packet);
bool ProcessInfo(netpacket_t * packet);
bool ProcessDetails(netpacket_t * packet);
bool ProcessPlayers(netpacket_t * packet);
bool ProcessRules(netpacket_t * packet);
bool ProcessRcon(netpacket_t * packet);
};
extern CServerConnectionlessHandler g_SVConnectionlessHandler;
#endif // SVCONNECTIONLESSHANDLER_H
File diff suppressed because it is too large Load Diff
+10
View File
@@ -0,0 +1,10 @@
//========= Copyright © 1996-2007, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $Workfile: $
// $Date: $
// $NoKeywords: $
//=============================================================================//
#include "audio_pch.h"
+409
View File
@@ -0,0 +1,409 @@
//====== Copyright 1996-2005, Valve Corporation, All rights reserved. =======
//
// Purpose:
//
//=============================================================================
#include "winlite.h"
#include "MPAFile.h"
#include "soundchars.h"
#include "tier1/utlrbtree.h"
// NOTE: This has to be the last file included!
#include "tier0/memdbgon.h"
// exception class
CMPAException::CMPAException(ErrorIDs ErrorID, const char *szFile, const char *szFunction, bool bGetLastError ) :
m_ErrorID( ErrorID ), m_bGetLastError( bGetLastError )
{
m_szFile = strdup(szFile);
m_szFunction = strdup(szFunction);
}
// copy constructor (necessary for exception throwing without pointers)
CMPAException::CMPAException(const CMPAException& Source)
{
m_ErrorID = Source.m_ErrorID;
m_bGetLastError = Source.m_bGetLastError;
m_szFile = strdup(Source.m_szFile);
m_szFunction = strdup(Source.m_szFunction);
}
// destructor
CMPAException::~CMPAException()
{
if( m_szFile )
free( (void*)m_szFile );
if( m_szFunction )
free( (void*)m_szFunction );
}
// should be in resource file for multi language applications
const char *m_szErrors[] =
{
"Can't open the file.",
"Can't set file position.",
"Can't read from file.",
"Reached end of buffer.",
"No VBR Header found.",
"Incomplete VBR Header.",
"No subsequent frame found within tolerance range.",
"No frame found."
};
#define MAX_ERR_LENGTH 256
void CMPAException::ShowError()
{
char szErrorMsg[MAX_ERR_LENGTH] = {0};
char szHelp[MAX_ERR_LENGTH];
// this is not buffer-overflow-proof!
if( m_szFunction )
{
sprintf( szHelp, _T("%s: "), m_szFunction );
strcat( szErrorMsg, szHelp );
}
if( m_szFile )
{
sprintf( szHelp, _T("'%s'\n"), m_szFile );
strcat( szErrorMsg, szHelp );
}
strcat( szErrorMsg, m_szErrors[m_ErrorID] );
#if defined(WIN32) && !defined(_X360)
if( m_bGetLastError )
{
// get error message of last system error id
LPVOID pMsgBuf;
if ( FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPTSTR) &pMsgBuf,
0,
NULL ))
{
strcat( szErrorMsg, "\n" );
strcat( szErrorMsg, (const char *)pMsgBuf );
LocalFree( pMsgBuf );
}
}
#endif
// show error message
Warning( "%s\n", szErrorMsg );
}
// 1KB is inital buffersize, each time the buffer needs to be increased it is doubled
const uint32 CMPAFile::m_dwInitBufferSize = 1024;
CMPAFile::CMPAFile( const char * szFile, uint32 dwFileOffset, FileHandle_t hFile ) :
m_pBuffer(NULL), m_dwBufferSize(0), m_dwBegin( dwFileOffset ), m_dwEnd(0),
m_dwNumTimesRead(0), m_bVBRFile( false ), m_pVBRHeader(NULL), m_bMustReleaseFile( false ),
m_pMPAHeader(NULL), m_hFile( hFile ), m_szFile(NULL), m_dwFrameNo(1)
{
// open file, if not already done
if( m_hFile == FILESYSTEM_INVALID_HANDLE )
{
Open( szFile );
m_bMustReleaseFile = true;
}
// save filename
m_szFile = strdup( szFile );
// set end of MPEG data (assume file end)
if( m_dwEnd <= 0 )
{
// get file size
m_dwEnd = g_pFullFileSystem->Size( m_hFile );
}
// find first valid MPEG frame
m_pMPAHeader = new CMPAHeader( this );
// is VBR header available?
CVBRHeader::VBRHeaderType HeaderType = CVBRHeader::NoHeader;
uint32 dwOffset = m_pMPAHeader->m_dwSyncOffset;
if( CVBRHeader::IsVBRHeaderAvailable( this, HeaderType, dwOffset ) )
{
try
{
// read out VBR header
m_pVBRHeader = new CVBRHeader( this, HeaderType, dwOffset );
m_bVBRFile = true;
m_dwBytesPerSec = m_pVBRHeader->m_dwBytesPerSec;
if( m_pVBRHeader->m_dwBytes > 0 )
m_dwEnd = m_dwBegin + m_pVBRHeader->m_dwBytes;
}
catch(CMPAException& Exc)
{
Exc.ShowError();
}
}
if( !m_pVBRHeader )
{
// always skip empty (32kBit) frames
m_bVBRFile = m_pMPAHeader->SkipEmptyFrames();
m_dwBytesPerSec = m_pMPAHeader->GetBytesPerSecond();
}
}
bool CMPAFile::GetNextFrame()
{
uint32 dwOffset = m_pMPAHeader->m_dwSyncOffset + m_pMPAHeader->m_dwRealFrameSize;
try
{
CMPAHeader* pFrame = new CMPAHeader( this, dwOffset, false );
delete m_pMPAHeader;
m_pMPAHeader = pFrame;
if( m_dwFrameNo > 0 )
m_dwFrameNo++;
}
catch(...)
{
return false;
}
return true;
}
bool CMPAFile::GetPrevFrame()
{
uint32 dwOffset = m_pMPAHeader->m_dwSyncOffset-MPA_HEADER_SIZE;
try
{
// look backward from dwOffset on
CMPAHeader* pFrame = new CMPAHeader( this, dwOffset, false, true );
delete m_pMPAHeader;
m_pMPAHeader = pFrame;
if( m_dwFrameNo > 0 )
m_dwFrameNo --;
}
catch(...)
{
return false;
}
return true;
}
bool CMPAFile::GetFirstFrame()
{
uint32 dwOffset = 0;
try
{
CMPAHeader* pFrame = new CMPAHeader( this, dwOffset, false );
delete m_pMPAHeader;
m_pMPAHeader = pFrame;
m_dwFrameNo = 1;
}
catch(...)
{
return false;
}
return true;
}
bool CMPAFile::GetLastFrame()
{
uint32 dwOffset = m_dwEnd - m_dwBegin - MPA_HEADER_SIZE;
try
{
// look backward from dwOffset on
CMPAHeader* pFrame = new CMPAHeader( this, dwOffset, false, true );
delete m_pMPAHeader;
m_pMPAHeader = pFrame;
m_dwFrameNo = 0;
}
catch(...)
{
return false;
}
return true;
}
// destructor
CMPAFile::~CMPAFile(void)
{
delete m_pMPAHeader;
if( m_pVBRHeader )
delete m_pVBRHeader;
if( m_pBuffer )
delete[] m_pBuffer;
// close file
if( m_bMustReleaseFile )
g_pFullFileSystem->Close( m_hFile );
if( m_szFile )
free( (void*)m_szFile );
}
// open file
void CMPAFile::Open( const char * szFilename )
{
// open with CreateFile (no limitation of 128byte filename length, like in mmioOpen)
m_hFile = g_pFullFileSystem->Open( szFilename, "rb", "GAME" );//::CreateFile( szFilename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
if( m_hFile == FILESYSTEM_INVALID_HANDLE )
{
// throw error
throw CMPAException( CMPAException::ErrOpenFile, szFilename, _T("CreateFile"), true );
}
}
// set file position
void CMPAFile::SetPosition( int offset )
{
/*
LARGE_INTEGER liOff;
liOff.QuadPart = lOffset;
liOff.LowPart = ::SetFilePointer(m_hFile, liOff.LowPart, &liOff.HighPart, dwMoveMethod );
if (liOff.LowPart == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR )
{
// throw error
throw CMPAException( CMPAException::ErrSetPosition, m_szFile, _T("SetFilePointer"), true );
}
*/
g_pFullFileSystem->Seek( m_hFile, offset, FILESYSTEM_SEEK_HEAD );
}
// read from file, return number of bytes read
uint32 CMPAFile::Read( void *pData, uint32 dwSize, uint32 dwOffset )
{
uint32 dwBytesRead = 0;
// set position first
SetPosition( m_dwBegin+dwOffset );
//if( !::ReadFile( m_hFile, pData, dwSize, &dwBytesRead, NULL ) )
// throw CMPAException( CMPAException::ErrReadFile, m_szFile, _T("ReadFile"), true );
dwBytesRead = g_pFullFileSystem->Read( pData, dwSize, m_hFile );
return dwBytesRead;
}
// convert from big endian to native format (Intel=little endian) and return as uint32 (32bit)
uint32 CMPAFile::ExtractBytes( uint32& dwOffset, uint32 dwNumBytes, bool bMoveOffset )
{
Assert( dwNumBytes > 0 );
Assert( dwNumBytes <= 4 ); // max 4 byte
// enough bytes in buffer, otherwise read from file
if( !m_pBuffer || ( ((int)(m_dwBufferSize - dwOffset)) < (int)dwNumBytes) )
FillBuffer( dwOffset + dwNumBytes );
uint32 dwResult = 0;
// big endian extract (most significant byte first) (will work on little and big-endian computers)
uint32 dwNumByteShifts = dwNumBytes - 1;
for( uint32 n=dwOffset; n < dwOffset+dwNumBytes; n++ )
{
dwResult |= ( ( unsigned char ) m_pBuffer[n] ) << 8*dwNumByteShifts--; // the bit shift will do the correct byte order for you
}
if( bMoveOffset )
dwOffset += dwNumBytes;
return dwResult;
}
// throws exception if not possible
void CMPAFile::FillBuffer( uint32 dwOffsetToRead )
{
uint32 dwNewBufferSize;
// calc new buffer size
if( m_dwBufferSize == 0 )
dwNewBufferSize = m_dwInitBufferSize;
else
dwNewBufferSize = m_dwBufferSize*2;
// is it big enough?
if( dwNewBufferSize < dwOffsetToRead )
dwNewBufferSize = dwOffsetToRead;
// reserve new buffer
BYTE* pNewBuffer = new BYTE[dwNewBufferSize];
// take over data from old buffer
if( m_pBuffer )
{
memcpy( pNewBuffer, m_pBuffer, m_dwBufferSize );
// release old buffer
delete[] m_pBuffer;
}
m_pBuffer = (char*)pNewBuffer;
// read <dwNewBufferSize-m_dwBufferSize> bytes from offset <m_dwBufferSize>
uint32 dwBytesRead = Read( m_pBuffer+m_dwBufferSize, dwNewBufferSize-m_dwBufferSize, m_dwBufferSize );
// no more bytes in buffer than read out from file
m_dwBufferSize += dwBytesRead;
}
// Uses mp3 code from: http://www.codeproject.com/audio/MPEGAudioInfo.asp
struct MP3Duration_t
{
FileNameHandle_t h;
float duration;
static bool LessFunc( const MP3Duration_t& lhs, const MP3Duration_t& rhs )
{
return lhs.h < rhs.h;
}
};
CUtlRBTree< MP3Duration_t, int > g_MP3Durations( 0, 0, MP3Duration_t::LessFunc );
float GetMP3Duration_Helper( char const *filename )
{
float duration = 60.0f;
// See if it's in the RB tree already...
char fn[ 512 ];
Q_snprintf( fn, sizeof( fn ), "sound/%s", PSkipSoundChars( filename ) );
FileNameHandle_t h = g_pFullFileSystem->FindOrAddFileName( fn );
MP3Duration_t search;
search.h = h;
int idx = g_MP3Durations.Find( search );
if ( idx != g_MP3Durations.InvalidIndex() )
{
return g_MP3Durations[ idx ].duration;
}
try
{
CMPAFile MPAFile( fn, 0 );
if ( MPAFile.m_dwBytesPerSec != 0 )
{
duration = (float)(MPAFile.m_dwEnd - MPAFile.m_dwBegin) / (float)MPAFile.m_dwBytesPerSec;
}
}
catch ( ... )
{
}
search.duration = duration;
g_MP3Durations.Insert( search );
return duration;
}
+125
View File
@@ -0,0 +1,125 @@
//====== Copyright 1996-2005, Valve Corporation, All rights reserved. =======
//
// Purpose: Uses mp3 code from: http://www.codeproject.com/audio/MPEGAudioInfo.asp
//
// There don't appear to be any licensing restrictions for using this code:
//
/*
- Readme - MPEG Audio Info Tool V2.0 - 2004-11-01
Description:
This tool can display information about MPEG audio files. It supports
MPEG1, MPEG2, MPEG2.5 in all three layers. You can get all the fields
from the MPEG audio frame in each frame of the file. Additionally you
can check the whole file for inconsistencies.
This tool was written as an example on how to use the classes:
CMPAFile, CMPAHeader, CVBRHeader and CMPAException.
The article MPEG Audio Frame Header on Sourceproject
[http://www.codeproject.com/audio/MPEGAudioInfo.asp]
provides additional information about these classes and the frame header
in general.
This tool was written with MS Visual C++ 7.1. The MFC library is
statically linked.
*/
//=============================================================================
#ifndef MPAFILE_H
#define MPAFILE_H
#ifdef _WIN32
#pragma once
#endif
#pragma once
#include "VBRHeader.h"
#include "MPAHeader.h"
#include "filesystem.h"
// exception class
class CMPAException
{
public:
enum ErrorIDs
{
ErrOpenFile,
ErrSetPosition,
ErrReadFile,
EndOfBuffer,
NoVBRHeader,
IncompleteVBRHeader,
NoFrameInTolerance,
NoFrame
};
CMPAException( ErrorIDs ErrorID, const char *szFile, const char *szFunction = NULL, bool bGetLastError=false );
// copy constructor (necessary because of LPSTR members)
CMPAException(const CMPAException& Source);
~CMPAException(void);
ErrorIDs GetErrorID() { return m_ErrorID; }
void ShowError();
private:
ErrorIDs m_ErrorID;
bool m_bGetLastError;
const char *m_szFunction;
const char *m_szFile;
};
class CMPAFile
{
public:
CMPAFile( const char *szFile, uint32 dwFileOffset, FileHandle_t hFile = FILESYSTEM_INVALID_HANDLE );
~CMPAFile(void);
uint32 ExtractBytes( uint32 &dwOffset, uint32 dwNumBytes, bool bMoveOffset = true );
const char *GetFilename() const { return m_szFile; };
bool GetNextFrame();
bool GetPrevFrame();
bool GetFirstFrame();
bool GetLastFrame();
private:
static const uint32 m_dwInitBufferSize;
// methods for file access
void Open( const char *szFilename );
void SetPosition( int offset );
uint32 Read( void *pData, uint32 dwSize, uint32 dwOffset );
void FillBuffer( uint32 dwOffsetToRead );
static uint32 m_dwBufferSizes[MAXTIMESREAD];
// concerning file itself
FileHandle_t m_hFile;
const char *m_szFile;
bool m_bMustReleaseFile;
public:
uint32 m_dwBegin; // offset of first MPEG Audio frame
uint32 m_dwEnd; // offset of last MPEG Audio frame (estimated)
bool m_bVBRFile;
uint32 m_dwBytesPerSec;
CMPAHeader* m_pMPAHeader;
uint32 m_dwFrameNo;
CVBRHeader* m_pVBRHeader; // XING or VBRI
// concerning read-buffer
uint32 m_dwNumTimesRead;
char *m_pBuffer;
uint32 m_dwBufferSize;
};
#endif // MPAFILE_H
+336
View File
@@ -0,0 +1,336 @@
//====== Copyright 1996-2005, Valve Corporation, All rights reserved. =======
//
// Purpose:
//
//=============================================================================
#if defined( WIN32) && !defined( _X360 )
#include "winlite.h"
#endif
#include "tier0/platform.h"
#include "MPAFile.h"
// NOTE: This has to be the last file included!
#include "tier0/memdbgon.h"
// static variables
const char *CMPAHeader::m_szLayers[] = { "Layer I", "Layer II", "Layer III" };
const char *CMPAHeader::m_szMPEGVersions[] = {"MPEG 2.5", "", "MPEG 2", "MPEG 1" };
const char *CMPAHeader::m_szChannelModes[] = { "Stereo", "Joint Stereo", "Dual Channel", "Single Channel" };
const char *CMPAHeader::m_szEmphasis[] = { "None", "50/15ms", "", "CCIT J.17" };
// tolerance range, look at expected offset +/- m_dwTolerance for subsequent frames
const uint32 CMPAHeader::m_dwTolerance = 3; // 3 bytes
// max. range where to look for frame sync
const uint32 CMPAHeader::m_dwMaxRange = ( 256 * 1024 );
// sampling rates in hertz: 1. index = MPEG Version ID, 2. index = sampling rate index
const uint32 CMPAHeader::m_dwSamplingRates[4][3] =
{
{11025, 12000, 8000, }, // MPEG 2.5
{0, 0, 0, }, // reserved
{22050, 24000, 16000, }, // MPEG 2
{44100, 48000, 32000 } // MPEG 1
};
// padding sizes in bytes for different layers: 1. index = layer
const uint32 CMPAHeader::m_dwPaddingSizes[3] =
{
4, // Layer1
1, // Layer2
1 // Layer3
};
// bitrates: 1. index = LSF, 2. index = Layer, 3. index = bitrate index
const uint32 CMPAHeader::m_dwBitrates[2][3][15] =
{
{ // MPEG 1
{0,32,64,96,128,160,192,224,256,288,320,352,384,416,448,}, // Layer1
{0,32,48,56, 64, 80, 96,112,128,160,192,224,256,320,384,}, // Layer2
{0,32,40,48, 56, 64, 80, 96,112,128,160,192,224,256,320,} // Layer3
},
{ // MPEG 2, 2.5
{0,32,48,56,64,80,96,112,128,144,160,176,192,224,256,}, // Layer1
{0,8,16,24,32,40,48,56,64,80,96,112,128,144,160,}, // Layer2
{0,8,16,24,32,40,48,56,64,80,96,112,128,144,160,} // Layer3
}
};
// Samples per Frame: 1. index = LSF, 2. index = Layer
const uint32 CMPAHeader::m_dwSamplesPerFrames[2][3] =
{
{ // MPEG 1
384, // Layer1
1152, // Layer2
1152 // Layer3
},
{ // MPEG 2, 2.5
384, // Layer1
1152, // Layer2
576 // Layer3
}
};
// Samples per Frame / 8
const uint32 CMPAHeader::m_dwCoefficients[2][3] =
{
{ // MPEG 1
48, // Layer1
144, // Layer2
144 // Layer3
},
{ // MPEG 2, 2.5
48, // Layer1
144, // Layer2
72 // Layer3
}
};
// needed later for CRC check
// sideinformation size: 1.index = lsf, 2. index = layer, 3. index = mono
const uint32 CMPAHeader::m_dwSideinfoSizes[2][3][2] =
{
{ // MPEG 1 (not mono, mono
{0,0}, // Layer1
{0,0}, // Layer2
{9,17} // Layer3
},
{ // MPEG 2, 2.5
{0,0}, // Layer1
{0,0}, // Layer2
{17,32} // Layer3
}
};
// constructor (throws exception if no frame found)
CMPAHeader::CMPAHeader( CMPAFile* pMPAFile, uint32 dwExpectedOffset, bool bSubsequentFrame, bool bReverse ) :
m_pMPAFile( pMPAFile ), m_dwSyncOffset( dwExpectedOffset ), m_dwRealFrameSize( 0 )
{
// first check at expected offset (extended for not subsequent frames)
HeaderError error = IsSync( m_dwSyncOffset, !bSubsequentFrame );
int nStep=1;
int nSyncOffset;
while( error != noError )
{
// either look in tolerance range
if( bSubsequentFrame )
{
if( nStep > m_dwTolerance )
{
// out of tolerance range
throw CMPAException( CMPAException::NoFrameInTolerance, pMPAFile->GetFilename() );
}
// look around dwExpectedOffset with increasing steps (+1,-1,+2,-2,...)
if( m_dwSyncOffset <= dwExpectedOffset )
{
nSyncOffset = dwExpectedOffset + nStep;
}
else
{
nSyncOffset = dwExpectedOffset - nStep++;
}
}
// just go forward/backward to find sync
else
{
nSyncOffset = ((int)m_dwSyncOffset) + (bReverse?-1:+1);
}
// is new offset within valid range?
if( nSyncOffset < 0 || nSyncOffset > (int)((pMPAFile->m_dwEnd - pMPAFile->m_dwBegin) - MPA_HEADER_SIZE) || abs( (long)(nSyncOffset-dwExpectedOffset) ) > m_dwMaxRange )
{
// out of tolerance range
throw CMPAException( CMPAException::NoFrame, pMPAFile->GetFilename() );
}
m_dwSyncOffset = nSyncOffset;
// found sync?
error = IsSync( m_dwSyncOffset, !bSubsequentFrame );
}
}
// destructor
CMPAHeader::~CMPAHeader()
{
}
// skips first 32kbit/s or lower bitrate frames to estimate bitrate (returns true if bitrate is variable)
bool CMPAHeader::SkipEmptyFrames()
{
if( m_dwBitrate > 32 )
return false;
uint32 dwHeader;
try
{
while( m_dwBitrate <= 32 )
{
m_dwSyncOffset += m_dwComputedFrameSize + MPA_HEADER_SIZE;
dwHeader = m_pMPAFile->ExtractBytes( m_dwSyncOffset, MPA_HEADER_SIZE, false );
if( IsSync( dwHeader, false ) != noError )
return false;
}
}
catch(CMPAException& /*Exc*/) // just catch the exception and return false
{
return false;
}
return true;
}
// in dwHeader stands 32bit header in big-endian format: frame sync at the end!
// because shifts do only work for integral types!!!
CMPAHeader::HeaderError CMPAHeader::DecodeHeader( uint32 dwHeader, bool bSimpleDecode )
{
// Check SYNC bits (last eleven bits set)
if( (dwHeader >> 24 != 0xff) || ((((dwHeader >> 16))&0xe0) != 0xe0) )
return noSync;
// get MPEG version
m_Version = (MPAVersion)((dwHeader >> 19) & 0x03); // mask only the rightmost 2 bits
if( m_Version == MPEGReserved )
return headerCorrupt;
if( m_Version == MPEG1 )
m_bLSF = false;
else
m_bLSF = true;
// get layer (0 = layer1, 2 = layer2, ...)
m_Layer = (MPALayer)(3 - ((dwHeader >> 17) & 0x03));
if( m_Layer == LayerReserved )
return headerCorrupt;
// protection bit (inverted)
m_bCRC = !((dwHeader >> 16) & 0x01);
// bitrate
BYTE bIndex = (BYTE)((dwHeader >> 12) & 0x0F);
if( bIndex == 0x0F ) // all bits set is reserved
return headerCorrupt;
m_dwBitrate = m_dwBitrates[m_bLSF][m_Layer][bIndex] * 1000; // convert from kbit to bit
if( m_dwBitrate == 0 ) // means free bitrate (is unsupported yet)
return freeBitrate;
// sampling rate
bIndex = (BYTE)((dwHeader >> 10) & 0x03);
if( bIndex == 0x03 ) // all bits set is reserved
return headerCorrupt;
m_dwSamplesPerSec = m_dwSamplingRates[m_Version][bIndex];
// padding bit
m_dwPaddingSize = m_dwPaddingSizes[m_Layer] * ((dwHeader >> 9) & 0x01);
// calculate frame size
m_dwComputedFrameSize = (m_dwCoefficients[m_bLSF][m_Layer] * m_dwBitrate / m_dwSamplesPerSec) + m_dwPaddingSize;
m_dwSamplesPerFrame = m_dwSamplesPerFrames[m_bLSF][m_Layer];
if( !bSimpleDecode )
{
// private bit
m_bPrivate = (dwHeader >> 8) & 0x01;
// channel mode
m_ChannelMode = (ChannelMode)((dwHeader >> 6) & 0x03);
// mode extension (currently not used)
m_ModeExt = (BYTE)((dwHeader >> 4) & 0x03);
// copyright bit
m_bCopyright = (dwHeader >> 3) & 0x01;
// original bit
m_bCopyright = (dwHeader >> 2) & 0x01;
// emphasis
m_Emphasis = (Emphasis)(dwHeader & 0x03);
if( m_Emphasis == EmphReserved )
return headerCorrupt;
}
return noError;
}
CMPAHeader::HeaderError CMPAHeader::IsSync( uint32 dwOffset, bool bExtended )
{
HeaderError error = noSync;
uint32 dwHeader = m_pMPAFile->ExtractBytes( dwOffset, MPA_HEADER_SIZE, false );
// sync bytes found?
if( (dwHeader & 0xFFE00000) == 0xFFE00000 )
{
error = DecodeHeader( dwHeader );
if( error == noError )
{
// enough buffer to do extended check?
if( bExtended )
{
// recursive call (offset for next frame header)
uint32 dwOffset = m_dwSyncOffset+m_dwComputedFrameSize;
try
{
CMPAHeader m_SubsequentFrame( m_pMPAFile, dwOffset, true );
m_dwRealFrameSize = m_SubsequentFrame.m_dwSyncOffset - m_dwSyncOffset;
}
catch( CMPAException& Exc )
{
// could not find any subsequent frame, assume it is the last frame
if( Exc.GetErrorID() == CMPAException::NoFrame )
{
if( dwOffset + m_pMPAFile->m_dwBegin > m_pMPAFile->m_dwEnd )
m_dwRealFrameSize = m_pMPAFile->m_dwEnd - m_pMPAFile->m_dwBegin - m_dwSyncOffset;
else
m_dwRealFrameSize = m_dwComputedFrameSize;
error = noError;
}
else
error = noSync;
}
}
}
}
return error;
}
// CRC-16 lookup table
const uint16 CMPAHeader::wCRC16Table[256] =
{
0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
};
+116
View File
@@ -0,0 +1,116 @@
//====== Copyright 1996-2005, Valve Corporation, All rights reserved. =======
//
// Purpose:
//
//=============================================================================
#ifndef MPAHEADER_H
#define MPAHEADER_H
#ifdef _WIN32
#pragma once
#endif
#pragma once
#define MPA_HEADER_SIZE 4 // MPEG-Audio Header Size 32bit
#define MAXTIMESREAD 5
class CMPAFile;
class CMPAHeader
{
public:
CMPAHeader( CMPAFile* pMPAFile, uint32 dwExpectedOffset = 0, bool bSubsequentFrame = false, bool bReverse = false );
~CMPAHeader();
bool SkipEmptyFrames();
// bitrate is in bit per second, to calculate in bytes => (/ 8)
uint32 GetBytesPerSecond() const { return m_dwBitrate / 8; };
// calc number of seconds from number of frames
uint32 GetLengthSecond(uint32 dwNumFrames) const { return dwNumFrames * m_dwSamplesPerFrame / m_dwSamplesPerSec; };
uint32 GetBytesPerSecond( uint32 dwNumFrames, uint32 dwNumBytes ) const { return dwNumBytes / GetLengthSecond( dwNumFrames ); };
bool IsMono() const { return (m_ChannelMode == SingleChannel)?true:false; };
// true if MPEG2/2.5 otherwise false
bool IsLSF() const { return m_bLSF; };
private:
static const uint32 m_dwMaxRange;
static const uint32 m_dwTolerance;
static const uint32 m_dwSamplingRates[4][3];
static const uint32 m_dwPaddingSizes[3];
static const uint32 m_dwBitrates[2][3][15];
static const uint32 m_dwSamplesPerFrames[2][3];
static const uint32 m_dwCoefficients[2][3];
// necessary for CRC check (not yet implemented)
static const uint32 m_dwSideinfoSizes[2][3][2];
static const uint16 wCRC16Table[256];
bool m_bLSF; // true means lower sampling frequencies (=MPEG2/MPEG2.5)
CMPAFile* m_pMPAFile;
public:
static const char * m_szLayers[];
static const char * m_szMPEGVersions[];
static const char * m_szChannelModes[];
static const char * m_szEmphasis[];
enum MPAVersion
{
MPEG25 = 0,
MPEGReserved,
MPEG2,
MPEG1
}m_Version;
enum MPALayer
{
Layer1,
Layer2,
Layer3,
LayerReserved
}m_Layer;
enum Emphasis
{
EmphNone = 0,
Emph5015,
EmphReserved,
EmphCCITJ17
}m_Emphasis;
enum ChannelMode
{
Stereo,
JointStereo,
DualChannel,
SingleChannel
}m_ChannelMode;
uint32 m_dwSamplesPerSec;
uint32 m_dwSamplesPerFrame;
uint32 m_dwBitrate; // in bit per second (1 kb = 1000 bit, not 1024)
uint32 m_dwSyncOffset;
uint32 m_dwComputedFrameSize, m_dwRealFrameSize;
uint32 m_dwPaddingSize;
// flags
bool m_bCopyright, m_bPrivate, m_bOriginal;
bool m_bCRC;
uint8 m_ModeExt;
private:
enum HeaderError
{
noError,
noSync,
freeBitrate,
headerCorrupt
};
HeaderError DecodeHeader( uint32 dwHeader, bool bSimpleDecode = false );
inline HeaderError IsSync( uint32 dwOffset, bool bExtended );
};
#endif // MPAHEADER_H
+308
View File
@@ -0,0 +1,308 @@
//====== Copyright 1996-2005, Valve Corporation, All rights reserved. =======
//
// Purpose:
//
//=============================================================================
#include "audio_pch.h"
#include "tier0/platform.h"
#include "MPAFile.h" // also includes vbrheader.h
#include "tier0/dbg.h"
// NOTE: This has to be the last file included!
#include "tier0/memdbgon.h"
#ifndef MAKEFOURCC
#define MAKEFOURCC(ch0, ch1, ch2, ch3) \
((uint32)(BYTE)(ch0) | ((uint32)(BYTE)(ch1) << 8) | \
((uint32)(BYTE)(ch2) << 16) | ((uint32)(BYTE)(ch3) << 24 ))
#endif //defined(MAKEFOURCC)
// XING Header offset: 1. index = lsf, 2. index = mono
uint32 CVBRHeader::m_dwXINGOffsets[2][2] =
{
// MPEG 1 (not mono, mono)
{ 32 + MPA_HEADER_SIZE, 17 + MPA_HEADER_SIZE },
// MPEG 2/2.5
{ 17 + MPA_HEADER_SIZE, 9 + MPA_HEADER_SIZE }
};
// first test with this static method, if it does exist
bool CVBRHeader::IsVBRHeaderAvailable( CMPAFile* pMPAFile, VBRHeaderType& HeaderType, uint32& dwOffset )
{
Assert(pMPAFile);
// where does VBR header begin (XING)
uint32 dwNewOffset = dwOffset + m_dwXINGOffsets[pMPAFile->m_pMPAHeader->IsLSF()][pMPAFile->m_pMPAHeader->IsMono()];
// check for XING header first
if( CheckXING( pMPAFile, dwNewOffset ) )
{
HeaderType = XINGHeader;
// seek offset back to header begin
dwOffset = dwNewOffset - 4;
return true;
}
// VBRI header always at fixed offset
dwNewOffset = dwOffset + 32 + MPA_HEADER_SIZE;
if( CheckVBRI( pMPAFile, dwNewOffset ) )
{
HeaderType = VBRIHeader;
// seek offset back to header begin
dwOffset = dwNewOffset - 4;
return true;
}
HeaderType = NoHeader;
return false;
}
CVBRHeader::CVBRHeader( CMPAFile* pMPAFile, VBRHeaderType HeaderType, uint32 dwOffset ) :
m_pMPAFile( pMPAFile ), m_pnToc(NULL), m_HeaderType( HeaderType ), m_dwOffset(dwOffset), m_dwFrames(0), m_dwBytes(0)
{
switch( m_HeaderType )
{
case NoHeader:
// no Header found
throw CMPAException( CMPAException::NoVBRHeader, pMPAFile->GetFilename(), NULL, false );
break;
case XINGHeader:
if( !ExtractXINGHeader( m_dwOffset ) )
throw CMPAException( CMPAException::NoVBRHeader, pMPAFile->GetFilename(), NULL, false );
break;
case VBRIHeader:
if( !ExtractVBRIHeader( m_dwOffset ) )
throw CMPAException( CMPAException::NoVBRHeader, pMPAFile->GetFilename(), NULL, false );
break;
}
// calc bitrate
if( m_dwBytes > 0 && m_dwFrames > 0 )
{
// calc number of seconds
m_dwBytesPerSec = m_pMPAFile->m_pMPAHeader->GetBytesPerSecond( m_dwFrames, m_dwBytes );
}
else // incomplete header found
{
throw CMPAException( CMPAException::IncompleteVBRHeader, pMPAFile->GetFilename(), NULL, false );
}
}
bool CVBRHeader::CheckID( CMPAFile* pMPAFile, char ch0, char ch1, char ch2, char ch3, uint32& dwOffset )
{
return ( pMPAFile->ExtractBytes( dwOffset, 4 ) == MAKEFOURCC( ch3, ch2, ch1, ch0 ) );
}
bool CVBRHeader::CheckXING( CMPAFile* pMPAFile, uint32& dwOffset )
{
// XING ID found?
if( !CheckID( pMPAFile, 'X', 'i', 'n', 'g', dwOffset) && !CheckID( pMPAFile, 'I', 'n', 'f', 'o', dwOffset) )
return false;
return true;
}
bool CVBRHeader::CheckVBRI( CMPAFile* pMPAFile, uint32& dwOffset )
{
// VBRI ID found?
if( !CheckID( pMPAFile, 'V', 'B', 'R', 'I', dwOffset ) )
return false;
return true;
}
// currently not used
bool CVBRHeader::ExtractLAMETag( uint32 dwOffset )
{
// LAME ID found?
if( !CheckID( m_pMPAFile, 'L', 'A', 'M', 'E', dwOffset ) && !CheckID( m_pMPAFile, 'G', 'O', 'G', 'O', dwOffset ) )
return false;
return true;
}
bool CVBRHeader::ExtractXINGHeader( uint32 dwOffset )
{
/* XING VBR-Header
size description
4 'Xing' or 'Info'
4 flags (indicates which fields are used)
4 frames (optional)
4 bytes (optional)
100 toc (optional)
4 a VBR quality indicator: 0=best 100=worst (optional)
*/
if( !CheckXING( m_pMPAFile, dwOffset ) )
return false;
uint32 dwFlags;
// get flags (mandatory in XING header)
dwFlags = m_pMPAFile->ExtractBytes( dwOffset, 4 );
// extract total number of frames in file
if(dwFlags & FRAMES_FLAG)
m_dwFrames = m_pMPAFile->ExtractBytes(dwOffset,4);
// extract total number of bytes in file
if(dwFlags & BYTES_FLAG)
m_dwBytes = m_pMPAFile->ExtractBytes(dwOffset,4);
// extract TOC (for more accurate seeking)
if (dwFlags & TOC_FLAG)
{
m_dwTableSize = 100;
m_pnToc = new int[m_dwTableSize];
if( m_pnToc )
{
for(uint32 i=0;i<m_dwTableSize;i++)
m_pnToc[i] = m_pMPAFile->ExtractBytes( dwOffset, 1 );
}
}
m_dwQuality = (uint32)-1;
if(dwFlags & VBR_SCALE_FLAG )
m_dwQuality = m_pMPAFile->ExtractBytes(dwOffset, 4);
return true;
}
bool CVBRHeader::ExtractVBRIHeader( uint32 dwOffset )
{
/* FhG VBRI Header
size description
4 'VBRI' (ID)
2 version
2 delay
2 quality
4 # bytes
4 # frames
2 table size (for TOC)
2 table scale (for TOC)
2 size of table entry (max. size = 4 byte (must be stored in an integer))
2 frames per table entry
?? dynamic table consisting out of frames with size 1-4
whole length in table size! (for TOC)
*/
if( !CheckVBRI( m_pMPAFile, dwOffset ) )
return false;
// extract all fields from header (all mandatory)
m_dwVersion = m_pMPAFile->ExtractBytes(dwOffset, 2 );
m_fDelay = (float)m_pMPAFile->ExtractBytes(dwOffset, 2 );
m_dwQuality = m_pMPAFile->ExtractBytes(dwOffset, 2 );
m_dwBytes = m_pMPAFile->ExtractBytes(dwOffset, 4 );
m_dwFrames = m_pMPAFile->ExtractBytes(dwOffset, 4 );
m_dwTableSize = m_pMPAFile->ExtractBytes(dwOffset, 2 ) + 1; //!!!
m_dwTableScale = m_pMPAFile->ExtractBytes(dwOffset, 2 );
m_dwBytesPerEntry = m_pMPAFile->ExtractBytes(dwOffset, 2 );
m_dwFramesPerEntry = m_pMPAFile->ExtractBytes(dwOffset, 2 );
// extract TOC (for more accurate seeking)
m_pnToc = new int[m_dwTableSize];
if( m_pnToc )
{
for ( unsigned int i = 0 ; i < m_dwTableSize ; i++)
{
m_pnToc[i] = m_pMPAFile->ExtractBytes(dwOffset, m_dwBytesPerEntry );
}
}
return true;
}
CVBRHeader::~CVBRHeader(void)
{
if( m_pnToc )
delete[] m_pnToc;
}
// get byte position for percentage value (fPercent) of file
bool CVBRHeader::SeekPoint(float fPercent, uint32& dwSeekPoint)
{
if( !m_pnToc || m_dwBytes == 0 )
return false;
if( fPercent < 0.0f )
fPercent = 0.0f;
if( fPercent > 100.0f )
fPercent = 100.0f;
switch( m_HeaderType )
{
case XINGHeader:
dwSeekPoint = SeekPointXING( fPercent );
break;
case VBRIHeader:
dwSeekPoint = SeekPointVBRI( fPercent );
break;
}
return true;
}
uint32 CVBRHeader::SeekPointXING(float fPercent) const
{
// interpolate in TOC to get file seek point in bytes
int a;
float fa, fb, fx;
a = (int)fPercent;
if( a > 99 ) a = 99;
fa = (float)m_pnToc[a];
if( a < 99 )
{
fb = (float)m_pnToc[a+1];
}
else
{
fb = 256.0f;
}
fx = fa + (fb-fa)*(fPercent-a);
uint32 dwSeekpoint = (int)((1.0f/256.0f)*fx*m_dwBytes);
return dwSeekpoint;
}
uint32 CVBRHeader::SeekPointVBRI(float fPercent) const
{
return SeekPointByTimeVBRI( (fPercent/100.0f) * m_pMPAFile->m_pMPAHeader->GetLengthSecond( m_dwFrames ) * 1000.0f );
}
uint32 CVBRHeader::SeekPointByTimeVBRI(float fEntryTimeMS) const
{
unsigned int i=0, fraction = 0;
uint32 dwSeekPoint = 0;
float fLengthMS;
float fLengthMSPerTOCEntry;
float fAccumulatedTimeMS = 0.0f ;
fLengthMS = (float)m_pMPAFile->m_pMPAHeader->GetLengthSecond( m_dwFrames ) * 1000.0f ;
fLengthMSPerTOCEntry = fLengthMS / (float)m_dwTableSize;
if ( fEntryTimeMS > fLengthMS )
fEntryTimeMS = fLengthMS;
while ( fAccumulatedTimeMS <= fEntryTimeMS )
{
dwSeekPoint += m_pnToc[i++];
fAccumulatedTimeMS += fLengthMSPerTOCEntry;
}
// Searched too far; correct result
fraction = ( (int)(((( fAccumulatedTimeMS - fEntryTimeMS ) / fLengthMSPerTOCEntry )
+ (1.0f/(2.0f*(float)m_dwFramesPerEntry))) * (float)m_dwFramesPerEntry));
dwSeekPoint -= (uint32)((float)m_pnToc[i-1] * (float)(fraction)
/ (float)m_dwFramesPerEntry);
return dwSeekPoint;
}
+73
View File
@@ -0,0 +1,73 @@
//====== Copyright 1996-2005, Valve Corporation, All rights reserved. =======
//
// Purpose:
//
//=============================================================================
#ifndef VBRHEADER_H
#define VBRHEADER_H
#ifdef _WIN32
#pragma once
#endif
#include "tier0/platform.h"
// for XING VBR Header flags
#define FRAMES_FLAG 0x0001
#define BYTES_FLAG 0x0002
#define TOC_FLAG 0x0004
#define VBR_SCALE_FLAG 0x0008
class CMPAFile;
class CVBRHeader
{
public:
enum VBRHeaderType
{
NoHeader,
XINGHeader,
VBRIHeader
};
CVBRHeader( CMPAFile* pMPAFile, VBRHeaderType HeaderType, uint32 dwOffset );
~CVBRHeader(void);
static bool IsVBRHeaderAvailable( CMPAFile* pMPAFile, VBRHeaderType& HeaderType, uint32& dwOffset );
bool SeekPoint(float fPercent, uint32& dwSeekPoint);
uint32 m_dwBytesPerSec;
uint32 m_dwBytes; // total number of bytes
uint32 m_dwFrames; // total number of frames
private:
static uint32 m_dwXINGOffsets[2][2];
static bool CheckID( CMPAFile* pMPAFile, char ch0, char ch1, char ch2, char ch3, uint32& dwOffset );
static bool CheckXING( CMPAFile* pMPAFile, uint32& dwOffset );
static bool CheckVBRI( CMPAFile* pMPAFile, uint32& dwOffset );
bool ExtractLAMETag( uint32 dwOffset );
bool ExtractXINGHeader( uint32 dwOffset );
bool ExtractVBRIHeader( uint32 dwOffset );
uint32 SeekPointXING(float fPercent)const ;
uint32 SeekPointVBRI(float fPercent) const;
uint32 SeekPointByTimeVBRI(float fEntryTimeMS) const;
CMPAFile* m_pMPAFile;
public:
VBRHeaderType m_HeaderType;
uint32 m_dwOffset;
uint32 m_dwQuality; // quality (0..100)
int* m_pnToc; // TOC points for seeking (must be freed)
uint32 m_dwTableSize; // size of table (number of entries)
// only VBRI
float m_fDelay;
uint32 m_dwTableScale; // for seeking
uint32 m_dwBytesPerEntry;
uint32 m_dwFramesPerEntry;
uint32 m_dwVersion;
};
#endif // VBRHEADER_H
+10
View File
@@ -0,0 +1,10 @@
//========= Copyright © 1996-2007, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $Workfile: $
// $Date: $
// $NoKeywords: $
//=============================================================================//
#include "audio_pch.h"
+78
View File
@@ -0,0 +1,78 @@
//===== Copyright © 1996-2007, Valve Corporation, All rights reserved. ======//
//
// Purpose:
//
// $Workfile: $
// $Date: $
// $NoKeywords: $
//===========================================================================//
#include "platform.h"
#if !defined( _X360 ) && defined( WIN32 )
#define WIN32_LEAN_AND_MEAN
#pragma warning(push, 1)
#pragma warning(disable: 4005)
#include <windows.h>
#include <mmsystem.h>
#pragma warning(pop)
#include <mmreg.h>
#endif
#ifdef _PS3
#include "ps3/ps3_core.h"
#endif
#include "basetypes.h"
#include "commonmacros.h"
#include "mathlib/mathlib.h"
#include "tier0/dbg.h"
#include "tier0/vprof.h"
#include "tier0/icommandline.h"
#include "tier1/strtools.h"
#include "tier2/riff.h"
#include "sound.h"
#include "color.h"
#include "convar.h"
#include "soundservice.h"
#include "voice_sound_engine_interface.h"
#include "soundflags.h"
#include "filesystem.h"
#include "../filesystem_engine.h"
#include "snd_device.h"
#include "sound_private.h"
#include "snd_mix_buf.h"
#include "snd_env_fx.h"
#include "snd_channels.h"
#include "snd_audio_source.h"
#include "snd_convars.h"
#include "snd_dev_common.h"
#include "snd_dev_direct.h"
#ifdef _PS3
#include "snd_dev_ps3audio.h"
#else
#include "snd_dev_xaudio.h"
#endif
#include "snd_sfx.h"
#include "snd_stubs.h"
#include "snd_audio_source.h"
#include "snd_wave_source.h"
#include "snd_wave_temp.h"
#include "snd_wave_data.h"
#include "snd_wave_mixer_private.h"
#include "snd_wave_mixer_adpcm.h"
#include "snd_io.h"
#include "voice_mixer_controls.h"
#if IsX360()
# include "snd_wave_mixer_xma.h"
# include "xbox/xbox_win32stubs.h"
# include <xhv2.h>
#elif IsPS3()
# include "snd_wave_mixer_ps3_mp3.h"
# include "ps3/ps3_win32stubs.h"
#elif defined(POSIX)
# include "audio/private/posix_stubs.h"
#endif
+307
View File
@@ -0,0 +1,307 @@
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose: Circular Buffer
//
//=============================================================================//
#include "tier0/dbg.h"
#include "tier1/mempool.h"
#include "circularbuffer.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
CCircularBuffer::CCircularBuffer()
{
SetSize( 0 );
}
CCircularBuffer::CCircularBuffer(int size)
{
SetSize(size);
}
//------------------ Copyright (c) 1999 Valve, LLC. ----------------------------
//Purpose : Sets the maximum size for a circular buffer. This does not do any
// memory allocation, it simply informs the buffer of its size.
//Author : DSpeyrer
//------------------------------------------------------------------------------
void CCircularBuffer::SetSize(int size)
{
Assert( this );
m_nSize = size;
m_nRead = 0;
m_nWrite = 0;
m_nCount = 0;
}
//------------------ Copyright (c) 1999 Valve, LLC. ----------------------------
//Purpose : Empties a circular buffer.
//Author : DSpeyrer
//------------------------------------------------------------------------------
void CCircularBuffer::Flush()
{
AssertValid();
m_nRead = 0;
m_nWrite = 0;
m_nCount = 0;
}
//------------------ Copyright (c) 1999 Valve, LLC. ----------------------------
//Purpose : Returns the available space in a circular buffer.
//Author : DSpeyrer
//------------------------------------------------------------------------------
int CCircularBuffer::GetWriteAvailable()
{
AssertValid();
return(m_nSize - m_nCount);
}
//------------------ Copyright (c) 1999 Valve, LLC. ----------------------------
//Purpose : Returns the size of a circular buffer.
//Author : DSpeyrer
//------------------------------------------------------------------------------
int CCircularBuffer::GetSize()
{
AssertValid();
return(m_nSize);
}
//------------------ Copyright (c) 1999 Valve, LLC. ----------------------------
//Purpose : Returns the number of bytes in a circular buffer.
//Author : DSpeyrer
//------------------------------------------------------------------------------
int CCircularBuffer::GetReadAvailable()
{
AssertValid();
return(m_nCount);
}
//------------------ Copyright (c) 1999 Valve, LLC. ----------------------------
//Purpose : Reads a specified number of bytes from a circular buffer without
// consuming them. They will still be available for future calls to
// Read or Peek.
//Input : pchDest - destination buffer.
// m_nCount - number of bytes to place in destination buffer.
//Output : Returns the number of bytes placed in the destination buffer.
//Author : DSpeyrer
//------------------------------------------------------------------------------
int CCircularBuffer::Peek(char *pchDest, int nCount)
{
// If no data available, just return.
if(m_nCount == 0)
{
return(0);
}
//
// Requested amount should not exceed the available amount.
//
nCount = MIN(m_nCount, nCount);
//
// Copy as many of the requested bytes as possible.
// If buffer wrap occurs split the data into two chunks.
//
if (m_nRead + nCount > m_nSize)
{
int nCount1 = m_nSize - m_nRead;
memcpy(pchDest, &m_chData[m_nRead], nCount1);
pchDest += nCount1;
int nCount2 = nCount - nCount1;
memcpy(pchDest, m_chData, nCount2);
}
// Otherwise copy it in one go.
else
{
memcpy(pchDest, &m_chData[m_nRead], nCount);
}
AssertValid();
return nCount;
}
//------------------ Copyright (c) 1999 Valve, LLC. ----------------------------
//Purpose : Advances the read index, consuming a specified number of bytes from
// the circular buffer.
//Input : m_nCount - number of bytes to consume.
//Output : Returns the actual number of bytes consumed.
//Author : DSpeyrer
//------------------------------------------------------------------------------
int CCircularBuffer::Advance(int nCount)
{
// If no data available, just return.
if (m_nCount == 0)
{
return(0);
}
//
// Requested amount should not exceed the available amount.
//
nCount = MIN(m_nCount, nCount);
//
// Advance the read pointer, checking for buffer wrap.
//
m_nRead = (m_nRead + nCount) % m_nSize;
m_nCount -= nCount;
//
// If we have emptied the buffer, reset the read and write indices
// to minimize buffer wrap.
//
if (m_nCount == 0)
{
m_nRead = 0;
m_nWrite = 0;
}
AssertValid();
return nCount;
}
//------------------ Copyright (c) 1999 Valve, LLC. ----------------------------
//Purpose : Reads a specified number of bytes from a circular buffer. The bytes
// will be consumed by the read process.
//Input : pchDest - destination buffer.
// m_nCount - number of bytes to place in destination buffer.
//Output : Returns the number of bytes placed in the destination buffer.
//Author : DSpeyrer
//------------------------------------------------------------------------------
int CCircularBuffer::Read(void *pchDestIn, int m_nCount)
{
int nPeeked;
int m_nRead;
char *pchDest = (char*)pchDestIn;
nPeeked = Peek(pchDest, m_nCount);
if (nPeeked != 0)
{
m_nRead = Advance(nPeeked);
assert(m_nRead == nPeeked);
}
else
{
m_nRead = 0;
}
AssertValid();
return(m_nRead);
}
//------------------ Copyright (c) 1999 Valve, LLC. ----------------------------
//Purpose : Writes a specified number of bytes to the buffer.
//Input : pm_chData - buffer containing bytes to bw written.
// m_nCount - the number of bytes to write.
//Output : Returns the number of bytes written. If there wa insufficient space
// to write all requested bytes, the value returned will be less than
// the requested amount.
//Author : DSpeyrer
//------------------------------------------------------------------------------
int CCircularBuffer::Write(void *pData, int nBytesRequested)
{
// Write all the data.
int nBytesToWrite = nBytesRequested;
char *pDataToWrite = (char*)pData;
while(nBytesToWrite)
{
int from = m_nWrite;
int to = m_nWrite + nBytesToWrite;
if(to >= m_nSize)
{
to = m_nSize;
}
memcpy(&m_chData[from], pDataToWrite, to - from);
pDataToWrite += to - from;
m_nWrite = to % m_nSize;
nBytesToWrite -= to - from;
}
// Did it cross the read pointer? Then slide the read pointer up.
// This way, we will discard the old data.
if(nBytesRequested > (m_nSize - m_nCount))
{
m_nCount = m_nSize;
m_nRead = m_nWrite;
}
else
{
m_nCount += nBytesRequested;
}
AssertValid();
return nBytesRequested;
}
CFixedBudgetMemoryPool<ALIGN_VALUE(sizeof( CCircularBuffer ) + 8820 - 1, TSLIST_NODE_ALIGNMENT ), 24> g_SmallBuffers;
CFixedBudgetMemoryPool<ALIGN_VALUE(sizeof( CCircularBuffer ) + 17640 - 1, TSLIST_NODE_ALIGNMENT ), 44> g_MediumBuffers;
CFixedBudgetMemoryPool<ALIGN_VALUE(sizeof( CCircularBuffer ) + 35280 - 1, TSLIST_NODE_ALIGNMENT ), 16> g_LargeBuffers;
CCircularBuffer *AllocateCircularBuffer( int nSize )
{
CCircularBuffer *pCCircularBuffer;
if ( nSize <= 8820 )
{
pCCircularBuffer = (CCircularBuffer *)g_SmallBuffers.Alloc();
}
else if ( nSize <= 17640 )
{
pCCircularBuffer = (CCircularBuffer *)g_MediumBuffers.Alloc();
}
else if ( nSize <= 35280 )
{
pCCircularBuffer = (CCircularBuffer *)g_LargeBuffers.Alloc();
}
else
{
pCCircularBuffer = (CCircularBuffer *)malloc( sizeof( CCircularBuffer ) + nSize - 1 );
}
pCCircularBuffer->SetSize( nSize );
return pCCircularBuffer;
}
void FreeCircularBuffer( CCircularBuffer *pCircularBuffer )
{
int nSize = pCircularBuffer->GetSize();
if ( nSize <= 8820 )
{
g_SmallBuffers.Free( pCircularBuffer );
}
else if ( nSize <= 17640 )
{
g_MediumBuffers.Free( pCircularBuffer );
}
else if ( nSize <= 35280 )
{
g_LargeBuffers.Free( pCircularBuffer );
}
else
{
free( pCircularBuffer );
}
}
+99
View File
@@ -0,0 +1,99 @@
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose: Defines an interface for circular buffers. Data can be written to
// and read from these buffers as though from a file. When it is
// write-overflowed (you write more data in than the buffer can hold),
// the read pointer is advanced to allow the new data to be written.
// This means old data will be discarded if you write too much data
// into the buffer.
//
// MikeD: Moved all the functions into a class.
// Changed it so when the buffer overflows, the old data
// is discarded rather than the new.
//
//=====================================================================================//
#ifndef CIRCULARBUFFER_H
#define CIRCULARBUFFER_H
#pragma once
class CCircularBuffer
{
public:
CCircularBuffer();
CCircularBuffer( int size );
void SetSize( int nSize );
protected:
inline void AssertValid()
{
#ifdef _DEBUG
Assert( this );
Assert( m_nSize > 0 );
Assert( m_nCount >= 0 );
Assert( m_nCount <= m_nSize );
Assert( m_nWrite < m_nSize );
// Verify that m_nCount is correct.
if( m_nRead == m_nWrite )
{
Assert( m_nCount == 0 || m_nCount == m_nSize );
}
else
{
int testCount=0;
if ( m_nRead < m_nWrite )
testCount = m_nWrite - m_nRead;
else
testCount = (m_nSize - m_nRead) + m_nWrite;
Assert( testCount == m_nCount );
}
#endif
}
public:
void Flush();
int GetSize(); // Get the size of the buffer (how much can you write without reading
// before losing data.
int GetWriteAvailable(); // Get the amount available to write without overflowing.
// Note: you can write however much you want, but it may overflow,
// in which case the newest data is kept and the oldest is discarded.
int GetReadAvailable(); // Get the amount available to read.
int GetMaxUsed();
int Peek(char *pchDest, int nCount);
int Advance(int nCount);
int Read(void *pchDest, int nCount);
int Write(void *pchData, int nCount);
public:
int m_nCount; // Space between the read and write pointers (how much data we can read).
int m_nRead; // Read index into circular buffer
int m_nWrite; // Write index into circular buffer
int m_nSize; // Size of circular buffer in bytes (how much data it can hold).
char m_chData[1]; // Circular buffer holding data
};
// Use this to instantiate a CircularBuffer.
template< int size >
class CSizedCircularBuffer : public CCircularBuffer
{
public:
CSizedCircularBuffer() : CCircularBuffer(size) {}
private:
char myData[size-1];
};
CCircularBuffer *AllocateCircularBuffer( int nSize );
void FreeCircularBuffer( CCircularBuffer *pCircularBuffer );
#endif // CIRCULARBUFFER_H
+124
View File
@@ -0,0 +1,124 @@
// EAX.H -- DirectSound Environmental Audio Extensions
#ifndef EAX_H
#define EAX_H
#pragma once
// EAX (listener) reverb property set {4a4e6fc1-c341-11d1-b73a-444553540000}
DEFINE_GUID(DSPROPSETID_EAX_ReverbProperties,
0x4a4e6fc1,
0xc341,
0x11d1,
0xb7, 0x3a, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00);
typedef enum
{
DSPROPERTY_EAX_ALL, // all reverb properties
DSPROPERTY_EAX_ENVIRONMENT, // standard environment no.
DSPROPERTY_EAX_VOLUME, // loudness of the reverb
DSPROPERTY_EAX_DECAYTIME, // how long the reverb lasts
DSPROPERTY_EAX_DAMPING // the high frequencies decay faster
} DSPROPERTY_EAX_REVERBPROPERTY;
#define EAX_NUM_STANDARD_PROPERTIES (DSPROPERTY_EAX_DAMPING + 1)
// use this structure for get/set all properties...
typedef struct
{
unsigned long environment; // 0 to EAX_ENVIRONMENT_COUNT-1
float fVolume; // 0 to 1
float fDecayTime_sec; // seconds, 0.1 to 100
float fDamping; // 0 to 1
} EAX_REVERBPROPERTIES;
enum
{
EAX_ENVIRONMENT_GENERIC, // factory default
EAX_ENVIRONMENT_PADDEDCELL,
EAX_ENVIRONMENT_ROOM, // standard environments
EAX_ENVIRONMENT_BATHROOM,
EAX_ENVIRONMENT_LIVINGROOM,
EAX_ENVIRONMENT_STONEROOM,
EAX_ENVIRONMENT_AUDITORIUM,
EAX_ENVIRONMENT_CONCERTHALL,
EAX_ENVIRONMENT_CAVE,
EAX_ENVIRONMENT_ARENA,
EAX_ENVIRONMENT_HANGAR,
EAX_ENVIRONMENT_CARPETEDHALLWAY,
EAX_ENVIRONMENT_HALLWAY,
EAX_ENVIRONMENT_STONECORRIDOR,
EAX_ENVIRONMENT_ALLEY,
EAX_ENVIRONMENT_FOREST,
EAX_ENVIRONMENT_CITY,
EAX_ENVIRONMENT_MOUNTAINS,
EAX_ENVIRONMENT_QUARRY,
EAX_ENVIRONMENT_PLAIN,
EAX_ENVIRONMENT_PARKINGLOT,
EAX_ENVIRONMENT_SEWERPIPE,
EAX_ENVIRONMENT_UNDERWATER,
EAX_ENVIRONMENT_DRUGGED,
EAX_ENVIRONMENT_DIZZY,
EAX_ENVIRONMENT_PSYCHOTIC,
EAX_ENVIRONMENT_COUNT // total number of environments
};
#define EAX_MAX_ENVIRONMENT (EAX_ENVIRONMENT_COUNT - 1)
// presets
#define EAX_PRESET_GENERIC EAX_ENVIRONMENT_GENERIC,0.5F,1.493F,0.5F
#define EAX_PRESET_PADDEDCELL EAX_ENVIRONMENT_PADDEDCELL,0.25F,0.1F,0.0F
#define EAX_PRESET_ROOM EAX_ENVIRONMENT_ROOM,0.417F,0.4F,0.666F
#define EAX_PRESET_BATHROOM EAX_ENVIRONMENT_BATHROOM,0.653F,1.499F,0.166F
#define EAX_PRESET_LIVINGROOM EAX_ENVIRONMENT_LIVINGROOM,0.208F,0.478F,0.0F
#define EAX_PRESET_STONEROOM EAX_ENVIRONMENT_STONEROOM,0.5F,2.309F,0.888F
#define EAX_PRESET_AUDITORIUM EAX_ENVIRONMENT_AUDITORIUM,0.403F,4.279F,0.5F
#define EAX_PRESET_CONCERTHALL EAX_ENVIRONMENT_CONCERTHALL,0.5F,3.961F,0.5F
#define EAX_PRESET_CAVE EAX_ENVIRONMENT_CAVE,0.5F,2.886F,1.304F
#define EAX_PRESET_ARENA EAX_ENVIRONMENT_ARENA,0.361F,7.284F,0.332F
#define EAX_PRESET_HANGAR EAX_ENVIRONMENT_HANGAR,0.5F,10.0F,0.3F
#define EAX_PRESET_CARPETEDHALLWAY EAX_ENVIRONMENT_CARPETEDHALLWAY,0.153F,0.259F,2.0F
#define EAX_PRESET_HALLWAY EAX_ENVIRONMENT_HALLWAY,0.361F,1.493F,0.0F
#define EAX_PRESET_STONECORRIDOR EAX_ENVIRONMENT_STONECORRIDOR,0.444F,2.697F,0.638F
#define EAX_PRESET_ALLEY EAX_ENVIRONMENT_ALLEY,0.25F,1.752F,0.776F
#define EAX_PRESET_FOREST EAX_ENVIRONMENT_FOREST,0.111F,3.145F,0.472F
#define EAX_PRESET_CITY EAX_ENVIRONMENT_CITY,0.111F,2.767F,0.224F
#define EAX_PRESET_MOUNTAINS EAX_ENVIRONMENT_MOUNTAINS,0.194F,7.841F,0.472F
#define EAX_PRESET_QUARRY EAX_ENVIRONMENT_QUARRY,1.0F,1.499F,0.5F
#define EAX_PRESET_PLAIN EAX_ENVIRONMENT_PLAIN,0.097F,2.767F,0.224F
#define EAX_PRESET_PARKINGLOT EAX_ENVIRONMENT_PARKINGLOT,0.208F,1.652F,1.5F
#define EAX_PRESET_SEWERPIPE EAX_ENVIRONMENT_SEWERPIPE,0.652F,2.886F,0.25F
#define EAX_PRESET_UNDERWATER EAX_ENVIRONMENT_UNDERWATER,1.0F,1.499F,0.0F
#define EAX_PRESET_DRUGGED EAX_ENVIRONMENT_DRUGGED,0.875F,8.392F,1.388F
#define EAX_PRESET_DIZZY EAX_ENVIRONMENT_DIZZY,0.139F,17.234F,0.666F
#define EAX_PRESET_PSYCHOTIC EAX_ENVIRONMENT_PSYCHOTIC,0.486F,7.563F,0.806F
// EAX buffer reverb property set {4a4e6fc0-c341-11d1-b73a-444553540000}
DEFINE_GUID(DSPROPSETID_EAXBUFFER_ReverbProperties,
0x4a4e6fc0,
0xc341,
0x11d1,
0xb7, 0x3a, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00);
typedef enum
{
DSPROPERTY_EAXBUFFER_ALL, // all reverb buffer properties
DSPROPERTY_EAXBUFFER_REVERBMIX // the wet source amount
} DSPROPERTY_EAXBUFFER_REVERBPROPERTY;
// use this structure for get/set all properties...
typedef struct
{
float fMix; // linear factor, 0.0F to 1.0F
} EAXBUFFER_REVERBPROPERTIES;
#define EAX_REVERBMIX_USEDISTANCE -1.0F // out of normal range
// signifies the reverb engine should
// calculate it's own reverb mix value
// based on distance
#endif // EAX_H
+234
View File
@@ -0,0 +1,234 @@
//========= Copyright 1996-2004, Valve LLC, All rights reserved. ============
//
// Purpose: Posix win32 replacements - Mocks trivial windows flow
//
//=============================================================================
#if !defined( POSIX_AUDIO_STUBS_H ) && !defined( _PS3 )
#define POSIX_AUDIO_STUBS_H
#define DSBCAPS_LOCSOFTWARE 0
#define DSERR_BUFFERLOST 0
#define DSBSTATUS_BUFFERLOST 0x02
#define DSSPEAKER_GEOMETRY(x) (((x)>>16) & 0xFFFF)
#define DSSPEAKER_CONFIG(x) ((x) & 0xFFFF)
#define DSSPEAKER_HEADPHONE -1
#define DSSPEAKER_QUAD -2
#define DSSPEAKER_5POINT1 -3
#define DSSPEAKER_7POINT1 -4
#define DISP_CHANGE_SUCCESSFUL 0
#define HKEY_CURRENT_USER NULL
#define HKEY_LOCAL_MACHINE NULL
#define KEY_QUERY_VALUE 0
#define KEY_READ 0
#define KEY_WRITE 1
#define KEY_ALL_ACCESS ((ULONG)-1)
#define SMTO_ABORTIFHUNG 0
#define JOY_RETURNX 0x01
#define JOY_RETURNY 0x02
#define JOY_RETURNZ 0x04
#define JOY_RETURNR 0x08
#define JOY_RETURNU 0x10
#define JOY_RETURNV 0x20
#define JOYCAPS_HASPOV 0x01
#define JOYCAPS_HASU 0x01
#define JOYCAPS_HASV 0x01
#define JOYCAPS_HASR 0x01
#define JOYCAPS_HASZ 0x01
#define MMSYSERR_NODRIVER 1
#define JOYERR_NOERROR 0
#define JOY_RETURNCENTERED 0
#define JOY_RETURNBUTTONS 0
#define JOY_RETURNPOV 0
#define JOY_POVCENTERED 0
#define JOY_POVFORWARD 0
#define JOY_POVRIGHT 0
#define JOY_POVBACKWARD 0
#define JOY_POVLEFT 0
#define CCHDEVICENAME 32
#define CCHFORMNAME 32
typedef wchar_t BCHAR;
typedef uint MMRESULT;
//typedef uint32 *DWORD_PTR;
typedef const char *LPCSTR;
typedef uint POINTL;
#define IDLE_PRIORITY_CLASS 1
#define HIGH_PRIORITY_CLASS 2
typedef struct _devicemode {
BCHAR dmDeviceName[CCHDEVICENAME];
WORD dmSpecVersion;
WORD dmDriverVersion;
WORD dmSize;
WORD dmDriverExtra;
DWORD dmFields;
union u1 {
struct s {
short dmOrientation;
short dmPaperSize;
short dmPaperLength;
short dmPaperWidth;
short dmScale;
short dmCopies;
short dmDefaultSource;
short dmPrintQuality;
};
POINTL dmPosition;
DWORD dmDisplayOrientation;
DWORD dmDisplayFixedOutput;
};
short dmColor;
short dmDuplex;
short dmYResolution;
short dmTTOption;
short dmCollate;
BYTE dmFormName[CCHFORMNAME];
WORD dmLogPixels;
DWORD dmBitsPerPel;
DWORD dmPelsWidth;
DWORD dmPelsHeight;
union u2 {
DWORD dmDisplayFlags;
DWORD dmNup;
};
DWORD dmDisplayFrequency;
DWORD dmICMMethod;
DWORD dmICMIntent;
DWORD dmMediaType;
DWORD dmDitherType;
DWORD dmReserved1;
DWORD dmReserved2;
DWORD dmPanningWidth;
DWORD dmPanningHeight;
} DEVMODE, *LPDEVMODE;
typedef uint32 MCIERROR;
typedef uint MCIDEVICEID;
typedef struct {
DWORD_PTR dwCallback;
} MCI_GENERIC_PARMS;
typedef struct {
DWORD_PTR dwCallback;
DWORD dwReturn;
DWORD dwItem;
DWORD dwTrack;
} MCI_STATUS_PARMS;
typedef struct {
DWORD_PTR dwCallback;
DWORD dwFrom;
DWORD dwTo;
} MCI_PLAY_PARMS;
typedef struct {
DWORD_PTR dwCallback;
MCIDEVICEID wDeviceID;
LPCSTR lpstrDeviceType;
LPCSTR lpstrElementName;
LPCSTR lpstrAlias;
} MCI_OPEN_PARMS;
typedef struct {
DWORD_PTR dwCallback;
DWORD dwTimeFormat;
DWORD dwAudio;
} MCI_SET_PARMS;
#define MCI_MAKE_TMSF(t, m, s, f) ((DWORD)(((BYTE)(t) | ((WORD)(m) << 8)) | ((DWORD)(BYTE)(s) | ((WORD)(f)<<8)) << 16))
#define MCI_MSF_MINUTE(msf) ((BYTE)(msf))
#define MCI_MSF_SECOND(msf) ((BYTE)(((WORD)(msf)) >> 8))
#define MCI_OPEN 0
#define MCI_OPEN_TYPE 0
#define MCI_OPEN_SHAREABLE 0
#define MCI_FORMAT_TMSF 0
#define MCI_SET_TIME_FORMAT 0
#define MCI_CLOSE 0
#define MCI_STOP 0
#define MCI_PAUSE 0
#define MCI_PLAY 0
#define MCI_SET 0
#define MCI_SET_DOOR_OPEN 0
#define MCI_SET_DOOR_CLOSED 0
#define MCI_STATUS_READY 0
#define MCI_STATUS 0
#define MCI_STATUS_ITEM 0
#define MCI_STATUS_WAIT 0
#define MCI_STATUS_NUMBER_OF_TRACKS 0
#define MCI_CDA_STATUS_TYPE_TRACK 0
#define MCI_TRACK 0
#define MCI_WAIT 0
#define MCI_CDA_TRACK_AUDIO 0
#define MCI_STATUS_LENGTH 0
#define MCI_NOTIFY 0
#define MCI_FROM 0
#define MCI_TO 0
#define MCIERR_DRIVER -1
#define DSERR_ALLOCATED 0
#pragma pack(push, 1)
typedef struct tWAVEFORMATEX
{
WORD wFormatTag;
WORD nChannels;
DWORD nSamplesPerSec;
DWORD nAvgBytesPerSec;
WORD nBlockAlign;
WORD wBitsPerSample;
WORD cbSize;
} WAVEFORMATEX, *PWAVEFORMATEX, *NPWAVEFORMATEX, *LPWAVEFORMATEX;
typedef const WAVEFORMATEX *LPCWAVEFORMATEX;
typedef struct waveformat_tag
{
WORD wFormatTag;
WORD nChannels;
DWORD nSamplesPerSec;
DWORD nAvgBytesPerSec;
WORD nBlockAlign;
} WAVEFORMAT, *PWAVEFORMAT, *NPWAVEFORMAT, *LPWAVEFORMAT;
typedef const WAVEFORMAT *LPCWAVEFORMAT;
typedef struct pcmwaveformat_tag
{
WAVEFORMAT wf;
WORD wBitsPerSample;
} PCMWAVEFORMAT, *PPCMWAVEFORMAT, *NPPCMWAVEFORMAT, *LPPCMWAVEFORMAT;
typedef const PCMWAVEFORMAT *LPCPCMWAVEFORMAT;
typedef struct adpcmcoef_tag {
short iCoef1;
short iCoef2;
} ADPCMCOEFSET;
typedef struct adpcmwaveformat_tag {
WAVEFORMATEX wfx;
WORD wSamplesPerBlock;
WORD wNumCoef;
ADPCMCOEFSET aCoef[1];
} ADPCMWAVEFORMAT;
#pragma pack(pop)
#endif
+251
View File
@@ -0,0 +1,251 @@
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef SND_CHANNELS_H
#define SND_CHANNELS_H
#include "mathlib/vector.h"
#include "phonon/phonon_3d.h"
#if defined( _WIN32 )
#pragma once
#endif
class CSfxTable;
class CAudioMixer;
class CSosOperatorStackList;
typedef int SoundSource;
// DO NOT REORDER: indices to fvolume arrays in channel_t
#define IFRONT_LEFT 0 // NOTE: must correspond to order of fvolume array below!
#define IFRONT_RIGHT 1
#define IREAR_LEFT 2
#define IREAR_RIGHT 3
#define IFRONT_CENTER 4
#define IFRONT_CENTER0 5 // dummy slot - center channel is mono, but mixers reference volume[1] slot
#define IFRONT_LEFTD 6 // start of doppler right array
#define IFRONT_RIGHTD 7
#define IREAR_LEFTD 8
#define IREAR_RIGHTD 9
#define IFRONT_CENTERD 10
#define IFRONT_CENTERD0 11 // dummy slot - center channel is mono, but mixers reference volume[1] slot
#define CCHANVOLUMES 12
struct gain_t
{
float ob_gain; // gain drop if sound source obscured from listener
float ob_gain_target; // target gain while crossfading between ob_gain & ob_gain_target
float ob_gain_inc; // crossfade increment
};
struct hrtf_info_t
{
Vector vec; // Sound source relative to the listener, updated every frame for channels using HRTF.
float lerp; // 1.0 = use phonon fully, 0.0 = don't use phonon at all.
bool follow_entity; // If true, we update the position of the entity every frame, otherwise we use the position of the sound.
bool bilinear_filtering; // If true, we use more expensive bilinear filtering for this sound.
bool debug_lock_position; // If true, the vec will not be modified after the sound starts.
};
//-----------------------------------------------------------------------------
// Purpose: Each currently playing wave is stored in a channel
//-----------------------------------------------------------------------------
// NOTE: 128bytes. These are memset to zero at some points. Do not add virtuals without changing that pattern.
// UNDONE: now 300 bytes...
struct channel_t
{
int guid; // incremented each time a channel is allocated (to match with channel free in tools, etc.)
int userdata; // user specified data for syncing to tools
hrtf_info_t hrtf;
CSfxTable *sfx; // the actual sound
CAudioMixer *pMixer; // The sound's instance data for this channel
CSosOperatorStackList *m_pStackList; // The operator stack for this channel
HSOUNDSCRIPTHASH m_nSoundScriptHash;
// speaker channel volumes, indexed using IFRONT_LEFT to IFRONT_CENTER.
// NOTE: never access these fvolume[] elements directly! Use channel helpers in snd_dma.cpp.
float fvolume[CCHANVOLUMES]; // 0.0-255.0 current output volumes
float fvolume_target[CCHANVOLUMES]; // 0.0-255.0 target output volumes
float fvolume_inc[CCHANVOLUMES]; // volume increment, per frame, moves volume[i] to vol_target[i] (per spatialization)
SoundSource soundsource; // see iclientsound.h for description.
int entchannel; // sound channel (CHAN_STREAM, CHAN_VOICE, etc.)
int speakerentity; // if a sound is being played through a speaker entity (e.g., on a monitor,), this is the
// entity upon which to show the lips moving, if the sound has sentence data
short master_vol; // 0-255 master volume
short basePitch; // base pitch percent (100% is normal pitch playback)
float pitch; // real-time pitch after any modulation or shift by dynamic data
int mixgroups[8]; // sound belongs to these mixgroups: world, actor, player weapon, explosion etc.
int last_mixgroupid;// last mixgroupid selected
float last_vol; // last volume after spatialization
Vector origin; // origin of sound effect
Vector direction; // direction of the sound
float dist_mult; // distance multiplier (attenuation/clipK)
float m_flSoundLevel; // storing actual spl to avoid switching back and forth from dist_mult
float dspmix; // 0 - 1.0 proportion of dsp to mix with original sound, based on distance
// NOTE: this gets multiplied by g_dsp_volume in snd_mix.cpp, which is a culum of
// other dsp setttings!
float dspface; // -1.0 - 1.0 (1.0 = facing listener)
float distmix; // 0 - 1.0 proportion based on distance from listner (1.0 - 100% wav right - far)
float dsp_mix_min; // for dspmix calculation - set by current preset in SND_GetDspMix
float dsp_mix_max; // for dspmix calculation - set by current preset in SND_GetDspMix
float radius; // Radius of this sound effect (spatialization is different within the radius)
gain_t gain[ MAX_SPLITSCREEN_CLIENTS ];
short activeIndex;
char wavtype; // 0 default, CHAR_DOPPLER, CHAR_DIRECTIONAL, CHAR_DISTVARIANT
char pad;
char sample_prev[8]; // last sample(s) in previous input data buffer - space for 2, 16 bit, stereo samples
int initialStreamPosition;
int skipInitialSamples;
union
{
unsigned int flagsword;
struct
{
bool bUpdatePositions : 1; // if true, assume sound source can move and update according to entity
bool isSentence : 1; // true if playing linked sentence
bool bdry : 1; // if true, bypass all dsp processing for this sound (ie: music)
bool bSpeaker : 1; // true if sound is playing through in-game speaker entity.
bool bstereowav : 1; // if true, a stereo .wav file is the sample data source
bool delayed_start : 1; // If true, sound had a delay and so same sound on same channel won't channel steal from it
bool fromserver : 1; // for snd_show, networked sounds get colored differently than local sounds
bool bfirstpass : 1; // true if this is first time sound is spatialized
bool bTraced : 1; // true if channel was already checked this frame for obscuring
bool bfast_pitch : 1; // true if using low quality pitch (fast, but no interpolation)
bool m_bIsFreeingChannel : 1; // true when inside S_FreeChannel - prevents reentrance
bool m_bCompatibilityAttenuation : 1; // True when we want to use goldsrc compatibility mode for the attenuation
// In that case, dist_mul is set to a relatively meaningful value in StartDynamic/StartStaticSound,
// but we interpret it totally differently in SND_GetGain.
bool m_bShouldPause : 1; // if true, sound should pause when the game is paused
bool m_bIgnorePhonemes : 1; // if true, we don't want to drive animation w/ phoneme data
bool m_bHasMouth : 1; // needs to output mouth records
bool m_bMouthEnvelope : 1; // needs mouth wave envelope follower
bool m_bShouldSaveRestore : 1; // Should be saved and restored
bool m_bUpdateDelayForChoreo : 1; // Should update snd_delay_for_choreo with IO latency.
bool m_bInEyeSound : 1; // This sound is playing from the viewpoint of the camera.
} flags;
};
};
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
#define MAX_CHANNELS 128
#define MAX_DYNAMIC_CHANNELS 32
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
extern channel_t channels[MAX_CHANNELS];
// 0 to MAX_DYNAMIC_CHANNELS-1 = normal entity sounds
// MAX_DYNAMIC_CHANNELS to total_channels = static sounds
extern int total_channels;
class CChannelList
{
public:
int Count();
int GetChannelIndex( int listIndex );
channel_t *GetChannel( int listIndex );
void RemoveChannelFromList( int listIndex );
bool IsQuashed( int listIndex );
int m_count;
short m_list[MAX_CHANNELS];
bool m_quashed[MAX_CHANNELS]; // if true, the channel should be advanced, but not mixed, because it's been heuristically suppressed
bool m_hasSpeakerChannels : 1;
bool m_hasDryChannels : 1;
bool m_has11kChannels : 1;
bool m_has22kChannels : 1;
bool m_has44kChannels : 1;
};
inline int CChannelList::Count()
{
return m_count;
}
inline int CChannelList::GetChannelIndex( int listIndex )
{
return m_list[listIndex];
}
inline channel_t *CChannelList::GetChannel( int listIndex )
{
return &channels[GetChannelIndex(listIndex)];
}
inline bool CChannelList::IsQuashed( int listIndex )
{
return m_quashed[listIndex];
}
inline void CChannelList::RemoveChannelFromList( int listIndex )
{
// decrease the count by one, and swap the deleted channel with
// the last one.
m_count--;
if ( m_count > 0 && listIndex != m_count )
{
m_list[listIndex] = m_list[m_count];
m_quashed[listIndex] = m_quashed[m_count];
}
}
struct activethreadsound_t
{
int m_nGuid;
float m_flElapsedTime;
};
class CActiveChannels
{
public:
void Add( channel_t *pChannel );
void Remove( channel_t *pChannel );
void GetActiveChannels( CChannelList &list ) const;
void CopyActiveSounds( CUtlVector<activethreadsound_t> &list ) const;
channel_t * FindActiveChannelByGuid( int guid ) const;
void DumpChannelInfo( CUtlBuffer &buf );
void Init();
int GetActiveCount() { return m_count; }
private:
int m_count;
short m_list[MAX_CHANNELS];
};
extern CActiveChannels g_ActiveChannels;
//=============================================================================
#endif // SND_CHANNELS_H
+21
View File
@@ -0,0 +1,21 @@
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef SND_CONVARS_H
#define SND_CONVARS_H
#if defined( _WIN32 )
#pragma once
#endif
#include "convar.h"
extern ConVar snd_legacy_surround;
extern ConVar snd_surround;
extern ConVar snd_mix_async;
#endif // SND_CONVARS_H
File diff suppressed because it is too large Load Diff
+45
View File
@@ -0,0 +1,45 @@
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose: Device Common Routines
//
//=====================================================================================//
#ifndef SND_DEV_COMMON_H
#define SND_DEV_COMMON_H
#pragma once
void DEBUG_DrawPanCurves(void);
#if USE_AUDIO_DEVICE_V1
class CAudioDeviceBase : public IAudioDevice
{
public:
virtual bool IsActive( void ) { return false; }
virtual bool Init( void ) { return false; }
virtual void Shutdown( void ) {}
virtual void Pause( void ) {}
virtual void UnPause( void ) {}
virtual int64 PaintBegin( float, int64 soundtime, int64 paintedtime ) { return 0; }
virtual void PaintEnd( void ) {}
virtual int GetOutputPosition( void ) { return 0; }
virtual void ClearBuffer( void ) {}
// virtual void TransferSamples( int64 end ) {}
virtual int DeviceSampleCount( void ) { return 0; }
};
#endif
extern void Device_MixUpsample( int sampleCount, int filtertype );
extern void Device_ApplyDSPEffects( int idsp, portable_samplepair_t *pbuffront, portable_samplepair_t *pbufrear, portable_samplepair_t *pbufcenter, int samplecount );
extern void Device_SpatializeChannel( int nSlot, float volume[CCHANVOLUMES/2], int master_vol, const Vector& sourceDir, float gain, float mono, int nWavType );
extern void Device_SpatializeChannel( int nSlot, float volume[CCHANVOLUMES/2], const Vector& sourceDir, float mono, float flRearToStereoScale = 0.75 );
extern void Device_Mix8Mono( channel_t *pChannel, char *pData, int outputOffset, int inputOffset, fixedint rateScaleFix, int outCount, int timecompress );
extern void Device_Mix8Stereo( channel_t *pChannel, char *pData, int outputOffset, int inputOffset, fixedint rateScaleFix, int outCount, int timecompress );
extern void Device_Mix16Mono( channel_t *pChannel, short *pData, int outputOffset, int inputOffset, fixedint rateScaleFix, int outCount, int timecompress );
extern void Device_Mix16Stereo( channel_t *pChannel, short *pData, int outputOffset, int inputOffset, fixedint rateScaleFix, int outCount, int timecompress );
#endif // SND_DEV_COMMON_H
File diff suppressed because it is too large Load Diff
+14
View File
@@ -0,0 +1,14 @@
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=====================================================================================//
#ifndef SND_DEV_DIRECT_H
#define SND_DEV_DIRECT_H
#pragma once
class IAudioDevice;
IAudioDevice *Audio_CreateDirectSoundDevice( void );
#endif // SND_DEV_DIRECT_H
@@ -0,0 +1,481 @@
//===== Copyright (c) 1996-2010, Valve Corporation, All rights reserved. ======//
//
// Purpose:
//
//===========================================================================//
#include "audio_pch.h"
#include <AudioToolbox/AudioQueue.h>
#include <AudioToolbox/AudioFile.h>
#include <AudioToolbox/AudioFormat.h>
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
extern bool snd_firsttime;
extern bool MIX_ScaleChannelVolume( paintbuffer_t *ppaint, channel_t *pChannel, int volume[CCHANVOLUMES], int mixchans );
#define NUM_BUFFERS_SOURCES 128
#define BUFF_MASK (NUM_BUFFERS_SOURCES - 1 )
#define BUFFER_SIZE 0x0400
//-----------------------------------------------------------------------------
//
// NOTE: This only allows 16-bit, stereo wave out
//
//-----------------------------------------------------------------------------
class CAudioDeviceAudioQueue : public CAudioDeviceBase
{
public:
CAudioDeviceAudioQueue()
{
m_pName = "AudioQueue";
m_nChannels = 2;
m_nSampleBits = 16;
m_nSampleRate = 44100;
m_bIsActive = true;
}
bool IsActive( void );
bool Init( void );
void Shutdown( void );
int GetOutputPosition( void );
void Pause( void );
void UnPause( void );
int64 PaintBegin( float mixAheadTime, int64 soundtime, int64 paintedtime );
void PaintEnd( void );
void ClearBuffer( void );
void UpdateListener( const Vector& position, const Vector& forward, const Vector& right, const Vector& up );
void TransferSamples( int end );
int DeviceSampleCount( void ) { return m_deviceSampleCount; }
void BufferCompleted() { m_buffersCompleted++; }
void SetRunning( bool bState ) { m_bRunning = bState; }
private:
void OpenWaveOut( void );
void CloseWaveOut( void );
bool ValidWaveOut( void ) const;
bool BIsPlaying();
AudioStreamBasicDescription m_DataFormat;
AudioQueueRef m_Queue;
AudioQueueBufferRef m_Buffers[NUM_BUFFERS_SOURCES];
int m_SndBufSize;
void *m_sndBuffers;
CInterlockedInt m_deviceSampleCount;
int m_buffersSent;
int m_buffersCompleted;
int m_pauseCount;
bool m_bSoundsShutdown;
bool m_bFailed;
bool m_bRunning;
bool m_bSurround;
bool m_bSurroundCenter;
bool m_bHeadphone;
};
CAudioDeviceAudioQueue *wave = NULL;
static void AudioCallback(void *pContext, AudioQueueRef pQueue, AudioQueueBufferRef pBuffer)
{
if ( wave )
wave->BufferCompleted();
}
IAudioDevice *Audio_CreateMacAudioQueueDevice( void )
{
wave = new CAudioDeviceAudioQueue;
if ( wave->Init() )
return wave;
delete wave;
wave = NULL;
return NULL;
}
void OnSndSurroundCvarChanged2( IConVar *pVar, const char *pOldString, float flOldValue );
void OnSndSurroundLegacyChanged2( IConVar *pVar, const char *pOldString, float flOldValue );
//-----------------------------------------------------------------------------
// Init, shutdown
//-----------------------------------------------------------------------------
bool CAudioDeviceAudioQueue::Init( void )
{
m_SndBufSize = 0;
m_sndBuffers = NULL;
m_pauseCount = 0;
m_bIsHeadphone = false;
m_buffersSent = 0;
m_buffersCompleted = 0;
m_pauseCount = 0;
m_bSoundsShutdown = false;
m_bFailed = false;
m_bRunning = false;
m_Queue = NULL;
static bool first = true;
if ( first )
{
snd_surround.SetValue( 2 );
snd_surround.InstallChangeCallback( &OnSndSurroundCvarChanged2 );
snd_legacy_surround.InstallChangeCallback( &OnSndSurroundLegacyChanged2 );
first = false;
}
OpenWaveOut();
if ( snd_firsttime )
{
DevMsg( "Wave sound initialized\n" );
}
return ValidWaveOut() && !m_bFailed;
}
void CAudioDeviceAudioQueue::Shutdown( void )
{
CloseWaveOut();
}
//-----------------------------------------------------------------------------
// WAV out device
//-----------------------------------------------------------------------------
inline bool CAudioDeviceAudioQueue::ValidWaveOut( void ) const
{
return m_sndBuffers != 0 && m_Queue;
}
//-----------------------------------------------------------------------------
// called by the mac audioqueue code when we run out of playback buffers
//-----------------------------------------------------------------------------
void AudioQueueIsRunningCallback( void* inClientData, AudioQueueRef inAQ, AudioQueuePropertyID inID)
{
CAudioDeviceAudioQueue* audioqueue = (CAudioDeviceAudioQueue*)inClientData;
UInt32 running = 0;
UInt32 size;
OSStatus err = AudioQueueGetProperty(inAQ, kAudioQueueProperty_IsRunning, &running, &size);
audioqueue->SetRunning( running != 0 );
//DevWarning( "AudioQueueStart %d\n", running );
}
//-----------------------------------------------------------------------------
// Opens the windows wave out device
//-----------------------------------------------------------------------------
void CAudioDeviceAudioQueue::OpenWaveOut( void )
{
if ( m_Queue )
return;
m_buffersSent = 0;
m_buffersCompleted = 0;
m_DataFormat.mSampleRate = SOUND_DMA_SPEED;
m_DataFormat.mFormatID = kAudioFormatLinearPCM;
m_DataFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger|kAudioFormatFlagIsPacked;
m_DataFormat.mBytesPerPacket = 4; // 16-bit samples * 2 channels
m_DataFormat.mFramesPerPacket = 1;
m_DataFormat.mBytesPerFrame = 4; // 16-bit samples * 2 channels
m_DataFormat.mChannelsPerFrame = 2;
m_DataFormat.mBitsPerChannel = 16;
m_DataFormat.mReserved = 0;
// Create the audio queue that will be used to manage the array of audio
// buffers used to queue samples.
OSStatus err = AudioQueueNewOutput(&m_DataFormat, AudioCallback, this, NULL, NULL, 0, &m_Queue);
if ( err != noErr)
{
DevMsg( "Failed to create AudioQueue output %d\n", err );
m_bFailed = true;
return;
}
for ( int i = 0; i < NUM_BUFFERS_SOURCES; ++i)
{
err = AudioQueueAllocateBuffer( m_Queue, BUFFER_SIZE,&(m_Buffers[i]));
if ( err != noErr)
{
DevMsg( "Failed to AudioQueueAllocateBuffer output %d (%i)\n", err,i );
m_bFailed = true;
}
m_Buffers[i]->mAudioDataByteSize = BUFFER_SIZE;
Q_memset( m_Buffers[i]->mAudioData, 0, BUFFER_SIZE );
}
err = AudioQueuePrime( m_Queue, 0, NULL);
if ( err != noErr)
{
DevMsg( "Failed to create AudioQueue output %d\n", err );
m_bFailed = true;
return;
}
AudioQueueSetParameter( m_Queue, kAudioQueueParam_Volume, 1.0);
err = AudioQueueAddPropertyListener( m_Queue, kAudioQueueProperty_IsRunning, AudioQueueIsRunningCallback, this );
if ( err != noErr)
{
DevMsg( "Failed to create AudioQueue output %d\n", err );
m_bFailed = true;
return;
}
m_SndBufSize = NUM_BUFFERS_SOURCES*BUFFER_SIZE;
m_deviceSampleCount = m_SndBufSize / DeviceSampleBytes();
if ( !m_sndBuffers )
{
m_sndBuffers = malloc( m_SndBufSize );
memset( m_sndBuffers, 0x0, m_SndBufSize );
}
}
//-----------------------------------------------------------------------------
// Closes the windows wave out device
//-----------------------------------------------------------------------------
void CAudioDeviceAudioQueue::CloseWaveOut( void )
{
if ( ValidWaveOut() )
{
AudioQueueStop(m_Queue, true);
m_bRunning = false;
AudioQueueRemovePropertyListener( m_Queue, kAudioQueueProperty_IsRunning, AudioQueueIsRunningCallback, this );
for ( int i = 0; i < NUM_BUFFERS_SOURCES; i++ )
AudioQueueFreeBuffer( m_Queue, m_Buffers[i]);
AudioQueueDispose( m_Queue, true);
m_Queue = NULL;
}
if ( m_sndBuffers )
{
free( m_sndBuffers );
m_sndBuffers = NULL;
}
}
//-----------------------------------------------------------------------------
// Mixing setup
//-----------------------------------------------------------------------------
int64 CAudioDeviceAudioQueue::PaintBegin( float mixAheadTime, int64 soundtime, int64 paintedtime )
{
// soundtime - total samples that have been played out to hardware at dmaspeed
// paintedtime - total samples that have been mixed at speed
// endtime - target for samples in mixahead buffer at speed
int64 endtime = soundtime + mixAheadTime * SampleRate();
int samps = DeviceSampleCount() >> (ChannelCount()-1);
if ((int)(endtime - soundtime) > samps)
endtime = soundtime + samps;
if ((endtime - paintedtime) & 0x3)
{
// The difference between endtime and painted time should align on
// boundaries of 4 samples. This is important when upsampling from 11khz -> 44khz.
endtime -= (endtime - paintedtime) & 0x3;
}
return endtime;
}
//-----------------------------------------------------------------------------
// Actually performs the mixing
//-----------------------------------------------------------------------------
void CAudioDeviceAudioQueue::PaintEnd( void )
{
int cblocks = 8 << 1;
//
// submit a few new sound blocks
//
// 44K sound support
while (((m_buffersSent - m_buffersCompleted) >> SAMPLE_16BIT_SHIFT) < cblocks)
{
int iBuf = m_buffersSent&BUFF_MASK;
m_Buffers[iBuf]->mAudioDataByteSize = BUFFER_SIZE;
Q_memcpy( m_Buffers[iBuf]->mAudioData, (char *)m_sndBuffers + iBuf*BUFFER_SIZE, BUFFER_SIZE);
// Queue the buffer for playback.
OSStatus err = AudioQueueEnqueueBuffer( m_Queue, m_Buffers[iBuf], 0, NULL);
if ( err != noErr)
{
DevMsg( "Failed to AudioQueueEnqueueBuffer output %d\n", err );
}
m_buffersSent++;
}
if ( !m_bRunning )
{
DevMsg( "Restarting sound playback\n" );
m_bRunning = true;
AudioQueueStart( m_Queue, NULL);
}
}
int CAudioDeviceAudioQueue::GetOutputPosition( void )
{
int s = m_buffersSent * BUFFER_SIZE;
s >>= SAMPLE_16BIT_SHIFT;
s &= (DeviceSampleCount()-1);
return s / ChannelCount();
}
//-----------------------------------------------------------------------------
// Pausing
//-----------------------------------------------------------------------------
void CAudioDeviceAudioQueue::Pause( void )
{
m_pauseCount++;
if (m_pauseCount == 1)
{
m_bRunning = false;
AudioQueueStop(m_Queue, true);
}
}
void CAudioDeviceAudioQueue::UnPause( void )
{
if ( m_pauseCount > 0 )
{
m_pauseCount--;
}
if ( m_pauseCount == 0 )
{
m_bRunning = true;
AudioQueueStart( m_Queue, NULL);
}
}
bool CAudioDeviceAudioQueue::IsActive( void )
{
return ( m_pauseCount == 0 );
}
void CAudioDeviceAudioQueue::ClearBuffer( void )
{
if ( !m_sndBuffers )
return;
Q_memset( m_sndBuffers, 0x0, DeviceSampleCount() * DeviceSampleBytes() );
}
void CAudioDeviceAudioQueue::UpdateListener( const Vector& position, const Vector& forward, const Vector& right, const Vector& up )
{
}
bool CAudioDeviceAudioQueue::BIsPlaying()
{
UInt32 isRunning;
UInt32 propSize = sizeof(isRunning);
OSStatus result = AudioQueueGetProperty( m_Queue, kAudioQueueProperty_IsRunning, &isRunning, &propSize);
return isRunning != 0;
}
void CAudioDeviceAudioQueue::TransferSamples( int end )
{
int64 lpaintedtime = g_paintedtime;
int64 endtime = end;
// resumes playback...
if ( m_sndBuffers )
{
S_TransferStereo16( m_sndBuffers, PAINTBUFFER, lpaintedtime, endtime );
}
}
static uint32 GetOSXSpeakerConfig()
{
return 2;
}
static uint32 GetSpeakerConfigForSurroundMode( int surroundMode, const char **pConfigDesc )
{
uint32 newSpeakerConfig = 2;
*pConfigDesc = "stereo speaker";
return newSpeakerConfig;
}
void OnSndSurroundCvarChanged2( IConVar *pVar, const char *pOldString, float flOldValue )
{
// if the old value is -1, we're setting this from the detect routine for the first time
// no need to reset the device
if ( flOldValue == -1 )
return;
// get the user's previous speaker config
uint32 speaker_config = GetOSXSpeakerConfig();
// get the new config
uint32 newSpeakerConfig = 0;
const char *speakerConfigDesc = "";
ConVarRef var( pVar );
newSpeakerConfig = GetSpeakerConfigForSurroundMode( var.GetInt(), &speakerConfigDesc );
// make sure the config has changed
if (newSpeakerConfig == speaker_config)
return;
// set new configuration
//SetWindowsSpeakerConfig(newSpeakerConfig);
Msg("Speaker configuration has been changed to %s.\n", speakerConfigDesc);
// restart sound system so it takes effect
//g_pSoundServices->RestartSoundSystem();
}
void OnSndSurroundLegacyChanged2( IConVar *pVar, const char *pOldString, float flOldValue )
{
}
@@ -0,0 +1,14 @@
//========= Copyright (c) 1996-2010, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=====================================================================================//
#ifndef SND_DEV_MAC_AUDIOQUEUE_H
#define SND_DEV_MAC_AUDIOQUEUE_H
#pragma once
class IAudioDevice;
IAudioDevice *Audio_CreateMacAudioQueueDevice( void );
#endif // SND_DEV_MAC_AUDIOQUEUE_H
+403
View File
@@ -0,0 +1,403 @@
//===== Copyright (c) 1996-2005, Valve Corporation, All rights reserved. ======//
//
// Purpose:
//
//===========================================================================//
#include "audio_pch.h"
#include <OpenAL/al.h>
#include <OpenAL/alc.h>
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
extern bool snd_firsttime;
#define NUM_BUFFERS_SOURCES 128
#define BUFF_MASK (NUM_BUFFERS_SOURCES - 1 )
#define BUFFER_SIZE 0x0400
//-----------------------------------------------------------------------------
//
// NOTE: This only allows 16-bit, stereo wave out
//
//-----------------------------------------------------------------------------
class CAudioDeviceOpenAL : public CAudioDeviceBase
{
public:
CAudioDeviceOpenAL()
{
m_pName = "OpenAL Audio";
m_nChannels = 2;
m_nSampleBits = 16;
m_nSampleRate = 44100;
m_bIsActive = true;
}
bool IsActive( void );
bool Init( void );
void Shutdown( void );
int GetOutputPosition( void );
void Pause( void );
void UnPause( void );
int64 PaintBegin( float mixAheadTime, int64 soundtime, int64 paintedtime );
void PaintEnd( void );
void ClearBuffer( void );
void UpdateListener( const Vector& position, const Vector& forward, const Vector& right, const Vector& up );
void TransferSamples( int end );
int DeviceSampleCount( void ) { return m_deviceSampleCount; }
private:
void OpenWaveOut( void );
void CloseWaveOut( void );
bool ValidWaveOut( void ) const;
ALuint m_Buffer[NUM_BUFFERS_SOURCES];
ALuint m_Source[1];
int m_SndBufSize;
void *m_sndBuffers;
int m_deviceSampleCount;
int m_buffersSent;
int m_buffersCompleted;
int m_pauseCount;
bool m_bHeadphone;
bool m_bSurround;
bool m_bSurroundCenter;
};
IAudioDevice *Audio_CreateOpenALDevice( void )
{
static CAudioDeviceOpenAL *wave = NULL;
if ( !wave )
{
wave = new CAudioDeviceOpenAL;
}
if ( wave->Init() )
return wave;
delete wave;
wave = NULL;
return NULL;
}
//-----------------------------------------------------------------------------
// Init, shutdown
//-----------------------------------------------------------------------------
bool CAudioDeviceOpenAL::Init( void )
{
m_SndBufSize = 0;
m_sndBuffers = NULL;
m_pauseCount = 0;
m_bIsHeadphone = false;
m_buffersSent = 0;
m_buffersCompleted = 0;
m_pauseCount = 0;
OpenWaveOut();
if ( snd_firsttime )
{
DevMsg( "Wave sound initialized\n" );
}
return ValidWaveOut();
}
void CAudioDeviceOpenAL::Shutdown( void )
{
CloseWaveOut();
}
//-----------------------------------------------------------------------------
// WAV out device
//-----------------------------------------------------------------------------
inline bool CAudioDeviceOpenAL::ValidWaveOut( void ) const
{
return m_sndBuffers != 0;
}
//-----------------------------------------------------------------------------
// Opens the windows wave out device
//-----------------------------------------------------------------------------
void CAudioDeviceOpenAL::OpenWaveOut( void )
{
m_buffersSent = 0;
m_buffersCompleted = 0;
ALenum error;
ALCcontext *newContext = NULL;
ALCdevice *newDevice = NULL;
// Create a new OpenAL Device
// Pass NULL to specify the systemuse default output device
const ALCchar *initStr = (const ALCchar *)"\'( (sampling-rate 44100 ))";
newDevice = alcOpenDevice(initStr);
if (newDevice != NULL)
{
// Create a new OpenAL Context
// The new context will render to the OpenAL Device just created
ALCint attr[] = { ALC_FREQUENCY, SampleRate(), ALC_SYNC, AL_FALSE, 0 };
newContext = alcCreateContext(newDevice, attr );
if (newContext != NULL)
{
// Make the new context the Current OpenAL Context
alcMakeContextCurrent(newContext);
// Create some OpenAL Buffer Objects
alGenBuffers( NUM_BUFFERS_SOURCES, m_Buffer);
if((error = alGetError()) != AL_NO_ERROR)
{
DevMsg("Error Generating Buffers: ");
return;
}
// Create some OpenAL Source Objects
alGenSources(1, m_Source);
if(alGetError() != AL_NO_ERROR)
{
DevMsg("Error generating sources! \n");
return;
}
alListener3f( AL_POSITION,0.0f,0.0f,0.0f);
int i;
for ( i = 0; i < 1; i++ )
{
alSource3f( m_Source[i],AL_POSITION,0.0f,0.0f,0.0f );
alSourcef( m_Source[i], AL_PITCH, 1.0f );
alSourcef( m_Source[i], AL_GAIN, 1.0f );
}
}
}
m_SndBufSize = NUM_BUFFERS_SOURCES*BUFFER_SIZE;
m_deviceSampleCount = m_SndBufSize / DeviceSampleBytes();
if ( !m_sndBuffers )
{
m_sndBuffers = malloc( m_SndBufSize );
memset( m_sndBuffers, 0x0, m_SndBufSize );
}
}
//-----------------------------------------------------------------------------
// Closes the windows wave out device
//-----------------------------------------------------------------------------
void CAudioDeviceOpenAL::CloseWaveOut( void )
{
if ( ValidWaveOut() )
{
ALCcontext *context = NULL;
ALCdevice *device = NULL;
alSourceStop( m_Source[0] );
// Delete the Sources
alDeleteSources(1, m_Source);
// Delete the Buffers
alDeleteBuffers(NUM_BUFFERS_SOURCES, m_Buffer);
//Get active context
context = alcGetCurrentContext();
//Get device for active context
device = alcGetContextsDevice(context);
alcMakeContextCurrent( NULL );
alcSuspendContext(context);
//Release context
alcDestroyContext(context);
//Close device
alcCloseDevice(device);
}
if ( m_sndBuffers )
{
free( m_sndBuffers );
m_sndBuffers = NULL;
}
}
//-----------------------------------------------------------------------------
// Mixing setup
//-----------------------------------------------------------------------------
int64 CAudioDeviceOpenAL::PaintBegin( float mixAheadTime, int64 soundtime, int64 paintedtime )
{
// soundtime - total samples that have been played out to hardware at dmaspeed
// paintedtime - total samples that have been mixed at speed
// endtime - target for samples in mixahead buffer at speed
int64 endtime = soundtime + mixAheadTime * SampleRate();
int samps = DeviceSampleCount() >> (ChannelCount()-1);
if ((int)(endtime - soundtime) > samps)
endtime = soundtime + samps;
if ((endtime - paintedtime) & 0x3)
{
// The difference between endtime and painted time should align on
// boundaries of 4 samples. This is important when upsampling from 11khz -> 44khz.
endtime -= (endtime - paintedtime) & 0x3;
}
return endtime;
}
//-----------------------------------------------------------------------------
// Actually performs the mixing
//-----------------------------------------------------------------------------
void CAudioDeviceOpenAL::PaintEnd( void )
{
if ( !m_sndBuffers )
return;
ALint state;
ALenum error;
int iloop;
int cblocks = 4 << 1;
ALint processed = 1;
while ( processed > 0 )
{
alGetSourcei( m_Source[ 0 ], AL_BUFFERS_PROCESSED, &processed);
if ( processed > 0 )
{
ALuint tempVal = 0;
alSourceUnqueueBuffers( m_Source[ 0 ], 1, &tempVal );
error = alGetError();
if ( error != AL_NO_ERROR && error != AL_INVALID_NAME )
{
DevMsg( "Error alSourceUnqueueBuffers %d\n", error );
}
else
{
m_buffersCompleted++; // this buffer has been played
}
}
}
//
// submit a few new sound blocks
//
// 44K sound support
while (((m_buffersSent - m_buffersCompleted) >> SAMPLE_16BIT_SHIFT) < cblocks)
{
int iBuf = m_buffersSent&BUFF_MASK;
alBufferData( m_Buffer[iBuf], AL_FORMAT_STEREO16, (char *)m_sndBuffers + iBuf*BUFFER_SIZE, BUFFER_SIZE, SampleRate() );
if ( (error = alGetError()) != AL_NO_ERROR )
{
DevMsg( "Error alBufferData %d %d\n", iBuf, error );
}
alSourceQueueBuffers( m_Source[0], 1, &m_Buffer[iBuf] );
if ( (error = alGetError() ) != AL_NO_ERROR )
{
DevMsg( "Error alSourceQueueBuffers %d %d\n", iBuf, error );
}
m_buffersSent++;
}
// make sure the stream is playing
alGetSourcei( m_Source[ 0 ], AL_SOURCE_STATE, &state);
if ( state != AL_PLAYING )
{
Warning( "Restarting sound playback\n" );
alSourcePlay( m_Source[0] );
if((error = alGetError()) != AL_NO_ERROR)
{
DevMsg( "Error alSourcePlay %d\n", error );
}
}
}
int CAudioDeviceOpenAL::GetOutputPosition( void )
{
int s = m_buffersSent * BUFFER_SIZE;
s >>= SAMPLE_16BIT_SHIFT;
s &= (DeviceSampleCount()-1);
return s / ChannelCount();
}
//-----------------------------------------------------------------------------
// Pausing
//-----------------------------------------------------------------------------
void CAudioDeviceOpenAL::Pause( void )
{
m_pauseCount++;
if (m_pauseCount == 1)
{
alSourceStop( m_Source[0] );
}
}
void CAudioDeviceOpenAL::UnPause( void )
{
if ( m_pauseCount > 0 )
{
m_pauseCount--;
}
if ( m_pauseCount == 0 )
alSourcePlay( m_Source[0] );
}
bool CAudioDeviceOpenAL::IsActive( void )
{
return ( m_pauseCount == 0 );
}
void CAudioDeviceOpenAL::ClearBuffer( void )
{
if ( !m_sndBuffers )
return;
Q_memset( m_sndBuffers, 0x0, DeviceSampleCount() * DeviceSampleBytes() );
}
void CAudioDeviceOpenAL::UpdateListener( const Vector& position, const Vector& forward, const Vector& right, const Vector& up )
{
}
void CAudioDeviceOpenAL::TransferSamples( int end )
{
int64 lpaintedtime = g_paintedtime;
int64 endtime = end;
// resumes playback...
if ( m_sndBuffers )
{
S_TransferStereo16( m_sndBuffers, PAINTBUFFER, lpaintedtime, endtime );
}
}
+14
View File
@@ -0,0 +1,14 @@
//========= Copyright (c) 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=====================================================================================//
#ifndef SND_DEV_OPENAL_H
#define SND_DEV_OPENAL_H
#pragma once
class IAudioDevice;
IAudioDevice *Audio_CreateOpenALDevice( void );
#endif // SND_DEV_OPENAL_H
File diff suppressed because it is too large Load Diff
+90
View File
@@ -0,0 +1,90 @@
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=====================================================================================//
#ifndef SND_DEV_PS3AUDIO_H
#define SND_DEV_PS3AUDIO_H
#pragma once
#include "audio_pch.h"
#include "inetmessage.h"
#include "netmessages.h"
#include "engine/ienginevoice.h"
class IAudioDevice;
IAudioDevice *Audio_CreatePS3AudioDevice( bool bInitVoice );
#define PS3_SUPPORT_XVOICE
#ifdef PS3_SUPPORT_XVOICE
class CEngineVoicePs3 : public IEngineVoice
{
public:
CEngineVoicePs3();
static const float MAX_VOICE_BUFFER_TIME = 0.200f; // 200ms
void VoiceInit( void );
void VoiceShutdown( void );
void AddPlayerToVoiceList( XUID xPlayer, int iController, uint64 uiFlags );
void RemovePlayerFromVoiceList( XUID xPlayer, int iController );
bool VoiceUpdateData( int iCtrlr );
void GetVoiceData( int iCtrlr, CCLCMsg_VoiceData_t *pData );
void GetVoiceData( int iController, const byte **ppvVoiceDataBuffer, unsigned int *pnumVoiceDataBytes );
void VoiceSendData( int iCtrlr, INetChannel *pChannel );
void VoiceResetLocalData( int iCtrlr );
void PlayIncomingVoiceData( XUID xuid, const byte *pbData, unsigned int dwDataSize, const bool *bAudiblePlayers = NULL );
void UpdateHUDVoiceStatus( void );
void GetRemoteTalkers( int *pNumTalkers, XUID *pRemoteTalkers );
void SetPlaybackPriority( XUID remoteTalker, int iController, int iAllowPlayback );
bool IsLocalPlayerTalking( int controlerID );
bool IsPlayerTalking( XUID uid );
bool IsHeadsetPresent( int id );
void RemoveAllTalkers();
void PlayPortInterruptHandler();
private:
// Local chat data
static const uint8 m_numVoiceUsers = 1;
inline int GetVoiceUserIndex( int iController ) const { return 0; }
inline int GetVoiceDeviceNumber( int iController ) const { return 0; }
static const WORD m_ChatBufferSize = 16*1024;
BYTE m_ChatBuffer[ m_numVoiceUsers ][ m_ChatBufferSize ];
WORD m_wLocalDataSize[ m_numVoiceUsers ];
enum VoiceState_t
{
kVoiceNotInitialized,
kVoiceInit,
kVoiceOpen
};
VoiceState_t m_bUserRegistered[ m_numVoiceUsers ]; //This is to handle a bug in UnregisterLocalTalker where it crashes on
//unregistering a local talker who has not been registered if the
//controller id is non-0.
// Last voice data sent
float m_dwLastVoiceSend[ m_numVoiceUsers ];
//
// PS3 playback parameters
//
int CreateVoicePortsLocal( uint64 uiFlags );
uint32 m_memContainer;
uint32 m_portIMic, m_portOVoice, m_portIVoiceEcho, m_portOPcm, m_portOEarphone, m_portOSendForRemote;
struct RemoteTalker_t
{
XUID m_xuid;
uint32 m_portIRemoteVoice;
uint64 m_uiFlags;
float m_flLastTalkTimestamp;
};
int CreateVoicePortsRemote( RemoteTalker_t &rt );
CUtlVector< RemoteTalker_t > m_arrRemoteTalkers;
};
CEngineVoicePs3 *Audio_GetXVoice( void );
#endif
#endif // SND_DEV_PS3AUDIO_H
+751
View File
@@ -0,0 +1,751 @@
//===== Copyright 1996-2005, Valve Corporation, All rights reserved. ======//
//
// Purpose:
//
//===========================================================================//
#include "audio_pch.h"
#if !DEDICATED
#include "tier0/dynfunction.h"
#include "avi/ibik.h"
// prevent some conflicts in SDL headers...
#undef M_PI
#include <stdint.h>
#ifndef _STDINT_H_
#define _STDINT_H_ 1
#endif
#include "SDL.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
extern IVEngineClient* engineClient;
extern bool snd_firsttime;
extern bool MIX_ScaleChannelVolume( paintbuffer_t *ppaint, channel_t *pChannel, int volume[CCHANVOLUMES], int mixchans );
extern void S_SpatializeChannel( int nSlot, int volume[6], int master_vol, const Vector *psourceDir, float gain, float mono );
ConVar snd_mute_losefocus("snd_mute_losefocus", "1", FCVAR_ARCHIVE);
static ConVar sdl_speaker_channels( "sdl_speaker_channels", "-1", FCVAR_RELEASE|FCVAR_ARCHIVE );
static void OnSDLSpeakerChannelsChanged( IConVar *pVar, const char *pOldString, float flOldValue )
{
if ( atoi( pOldString ) != sdl_speaker_channels.GetInt() )
{
g_pSoundServices->RestartSoundSystem();
}
}
// 64K is about 1/3 second at 16-bit, stereo, 44100 Hz
// 44k: UNDONE - need to double buffers now that we're playing back at 44100?
#define WAV_BUFFERS 64
#define WAV_MASK (WAV_BUFFERS - 1)
#define WAV_BUFFER_SIZE 0x0400
#if 0
#define debugsdl printf
#else
static inline void debugsdl(const char *fmt, ...) {}
#endif
//-----------------------------------------------------------------------------
//
// NOTE: This only allows 16-bit, stereo wave out (!!! FIXME: but SDL supports 7.1, etc, too!)
//
//-----------------------------------------------------------------------------
class CAudioDeviceSDLAudio : public CAudioDeviceBase
{
public:
CAudioDeviceSDLAudio();
virtual ~CAudioDeviceSDLAudio();
bool IsActive( void );
bool Init( void );
void Shutdown( void );
void PaintEnd( void );
int GetOutputPosition( void );
void ChannelReset( int entnum, int channelIndex, float distanceMod );
void Pause( void );
void UnPause( void );
float MixDryVolume( void );
bool Should3DMix( void );
void StopAllSounds( void );
int64 PaintBegin( float mixAheadTime, int64 soundtime, int64 paintedtime );
void ClearBuffer( void );
void MixBegin( int sampleCount );
void MixUpsample( int sampleCount, int filtertype );
void Mix8Mono( channel_t *pChannel, char *pData, int outputOffset, int inputOffset, fixedint rateScaleFix, int outCount, int timecompress );
void Mix8Stereo( channel_t *pChannel, char *pData, int outputOffset, int inputOffset, fixedint rateScaleFix, int outCount, int timecompress );
void Mix16Mono( channel_t *pChannel, short *pData, int outputOffset, int inputOffset, fixedint rateScaleFix, int outCount, int timecompress );
void Mix16Stereo( channel_t *pChannel, short *pData, int outputOffset, int inputOffset, fixedint rateScaleFix, int outCount, int timecompress );
void TransferSamples( int end );
void SpatializeChannel( int nSlot, int volume[CCHANVOLUMES/2], int master_vol, const Vector& sourceDir, float gain, float mono);
void ApplyDSPEffects( int idsp, portable_samplepair_t *pbuffront, portable_samplepair_t *pbufrear, portable_samplepair_t *pbufcenter, int samplecount );
const char *DeviceName( void ) { return "SDL"; }
int DeviceChannels( void ) { return m_numChannels; }
int DeviceSampleBits( void ) { return 16; }
int DeviceSampleBytes( void ) { return 2; }
int DeviceDmaSpeed( void ) { return SOUND_DMA_SPEED; }
int DeviceSampleCount( void ) { return m_deviceSampleCount; }
private:
SDL_AudioDeviceID m_devId;
static void SDLCALL AudioCallbackEntry(void *userdata, Uint8 * stream, int len);
void AudioCallback(Uint8 *stream, int len);
void OpenWaveOut( void );
void CloseWaveOut( void );
void AllocateOutputBuffers();
void FreeOutputBuffers();
bool ValidWaveOut( void ) const;
void TransferSurround16( void *pOutput, const portable_samplepair_t *pfront, const portable_samplepair_t *prear, const portable_samplepair_t *pcenter, int64 lpaintedtime, int64 endtime, int nChannels);
int m_numChannels;
int m_deviceSampleCount;
int m_buffersSent;
int m_pauseCount;
int m_readPos;
int m_partialWrite;
// Memory for the wave data
uint8_t *m_pBuffer;
bool m_bSurround;
bool m_bSurroundCenter;
bool m_bHeadphone;
};
static CAudioDeviceSDLAudio *g_wave = NULL;
//-----------------------------------------------------------------------------
// Constructor (just lookup SDL entry points, real work happens in this->Init())
//-----------------------------------------------------------------------------
CAudioDeviceSDLAudio::CAudioDeviceSDLAudio()
{
m_devId = 0;
m_numChannels = 2;
}
//-----------------------------------------------------------------------------
// Destructor. Make sure our global pointer gets set to NULL.
//-----------------------------------------------------------------------------
CAudioDeviceSDLAudio::~CAudioDeviceSDLAudio()
{
g_wave = NULL;
}
//-----------------------------------------------------------------------------
// Class factory
//-----------------------------------------------------------------------------
IAudioDevice *Audio_CreateSDLAudioDevice( void )
{
if ( !g_wave )
{
g_wave = new CAudioDeviceSDLAudio;
Assert( g_wave );
}
if ( g_wave && !g_wave->Init() )
{
delete g_wave;
g_wave = NULL;
}
return g_wave;
}
//-----------------------------------------------------------------------------
// Init, shutdown
//-----------------------------------------------------------------------------
bool CAudioDeviceSDLAudio::Init( void )
{
// If we've already got a device open, then return. This allows folks to call
// Audio_CreateSDLAudioDevice() multiple times. CloseWaveOut() will free the
// device, and set m_devId to 0.
if( m_devId )
return true;
m_bSurround = false;
m_bSurroundCenter = false;
m_bHeadphone = false;
m_buffersSent = 0;
m_pauseCount = 0;
m_pBuffer = NULL;
m_readPos = 0;
m_partialWrite = 0;
m_devId = 0;
OpenWaveOut();
if ( snd_firsttime )
{
DevMsg( "Wave sound initialized\n" );
}
return ValidWaveOut();
}
void CAudioDeviceSDLAudio::Shutdown( void )
{
CloseWaveOut();
}
//-----------------------------------------------------------------------------
// WAV out device
//-----------------------------------------------------------------------------
inline bool CAudioDeviceSDLAudio::ValidWaveOut( void ) const
{
return m_devId != 0;
}
//-----------------------------------------------------------------------------
// Opens the windows wave out device
//-----------------------------------------------------------------------------
void CAudioDeviceSDLAudio::OpenWaveOut( void )
{
debugsdl("SDLAUDIO: OpenWaveOut...\n");
#ifndef WIN32
// Set these environment variables, in case we're using PulseAudio.
const char *appname = "Counter-Strike: Global Offensive"; // !!! FIXME: get this from elsewhere.
setenv("PULSE_PROP_application.name", appname, 1);
setenv("PULSE_PROP_media.role", "game", 1);
#endif
// !!! FIXME: specify channel map, etc
// !!! FIXME: set properties (role, icon, etc).
//#define SDLAUDIO_FAIL(fnstr) do { DevWarning(fnstr " failed"); CloseWaveOut(); return; } while (false)
//#define SDLAUDIO_FAIL(fnstr) do { printf("SDLAUDIO: " fnstr " failed: %s\n", SDL_GetError ? SDL_GetError() : "???"); CloseWaveOut(); return; } while (false)
#define SDLAUDIO_FAIL(fnstr) do { printf("SDLAUDIO: " fnstr " failed: %s\n", SDL_GetError() ); CloseWaveOut(); return; } while (false)
if (!SDL_WasInit(SDL_INIT_AUDIO))
{
if (SDL_InitSubSystem(SDL_INIT_AUDIO))
SDLAUDIO_FAIL("SDL_InitSubSystem(SDL_INIT_AUDIO)");
}
char target[128];
debugsdl("SDLAUDIO: Using SDL audio target '%s'\n", SDL_GetCurrentAudioDriver());
int nChannelsDesired = sdl_speaker_channels.GetInt();
if ( nChannelsDesired == 1 )
{
//This really means 'headphones' which we want 2 channels for
nChannelsDesired = 2;
m_bHeadphone = true;
}
else if ( nChannelsDesired <= 0 )
{
nChannelsDesired = 6;
}
// Open an audio device...
// !!! FIXME: let user specify a device?
// !!! FIXME: we can handle quad, 5.1, 7.1, etc here.
SDL_AudioSpec obtained;
m_devId = 0;
for ( m_devId = 0; m_devId == 0 && nChannelsDesired > 0; nChannelsDesired -= 2 )
{
SDL_AudioSpec desired;
memset(&desired, '\0', sizeof (desired));
desired.freq = SOUND_DMA_SPEED;
desired.format = AUDIO_S16SYS;
desired.samples = 2048;
desired.channels = nChannelsDesired;
desired.callback = &CAudioDeviceSDLAudio::AudioCallbackEntry;
desired.userdata = this;
m_devId = SDL_OpenAudioDevice(NULL, 0, &desired, &obtained, 0);
}
if (!m_devId)
SDLAUDIO_FAIL("SDL_OpenAudioDevice()");
m_bSurround = obtained.channels >= 4;
m_bSurroundCenter = obtained.channels >= 6;
m_numChannels = obtained.channels;
if ( sdl_speaker_channels.GetInt() == 1 && m_numChannels == 2 )
{
//'headphones' setting.
sdl_speaker_channels.SetValue( 1 );
}
else
{
sdl_speaker_channels.SetValue( m_numChannels );
}
#undef SDLAUDIO_FAIL
// We're now ready to feed audio data to SDL!
AllocateOutputBuffers();
SDL_PauseAudioDevice(m_devId, 0);
#if defined( BINK_VIDEO ) && defined( LINUX )
// Tells Bink to use SDL for its audio decoding
if ( g_pBIK && g_pBIK->SetSDLDevice( obtained.freq, obtained.format, obtained.channels ) == 0 )
{
Assert( 0 );
}
#endif
static bool first_time = true;
if ( first_time )
{
first_time = false;
sdl_speaker_channels.InstallChangeCallback( &OnSDLSpeakerChannelsChanged );
}
}
//-----------------------------------------------------------------------------
// Closes the windows wave out device
//-----------------------------------------------------------------------------
void CAudioDeviceSDLAudio::CloseWaveOut( void )
{
// none of these SDL_* functions are available to call if this is false.
if (m_devId)
{
SDL_CloseAudioDevice(m_devId);
m_devId = 0;
}
SDL_QuitSubSystem(SDL_INIT_AUDIO);
FreeOutputBuffers();
}
//-----------------------------------------------------------------------------
// Allocate output buffers
//-----------------------------------------------------------------------------
void CAudioDeviceSDLAudio::AllocateOutputBuffers()
{
// Allocate and lock memory for the waveform data.
const int nBufferSize = (WAV_BUFFER_SIZE * WAV_BUFFERS * DeviceChannels())/2;
m_pBuffer = new uint8_t[nBufferSize];
memset(m_pBuffer, '\0', nBufferSize);
m_readPos = 0;
m_partialWrite = 0;
m_deviceSampleCount = nBufferSize / DeviceSampleBytes();
}
//-----------------------------------------------------------------------------
// Free output buffers
//-----------------------------------------------------------------------------
void CAudioDeviceSDLAudio::FreeOutputBuffers()
{
delete[] m_pBuffer;
m_pBuffer = NULL;
}
//-----------------------------------------------------------------------------
// Mixing setup
//-----------------------------------------------------------------------------
int64 CAudioDeviceSDLAudio::PaintBegin( float mixAheadTime, int64 soundtime, int64 paintedtime )
{
// soundtime - total samples that have been played out to hardware at dmaspeed
// paintedtime - total samples that have been mixed at speed
// endtime - target for samples in mixahead buffer at speed
unsigned int endtime = soundtime + mixAheadTime * DeviceDmaSpeed();
int samps = DeviceSampleCount() / DeviceChannels();
if ((int)(endtime - soundtime) > samps)
endtime = soundtime + samps;
if ((endtime - paintedtime) & 0x3)
{
// The difference between endtime and painted time should align on
// boundaries of 4 samples. This is important when upsampling from 11khz -> 44khz.
endtime -= (endtime - paintedtime) & 0x3;
}
return endtime;
}
void CAudioDeviceSDLAudio::AudioCallbackEntry(void *userdata, Uint8 *stream, int len)
{
((CAudioDeviceSDLAudio *) userdata)->AudioCallback(stream, len);
}
void CAudioDeviceSDLAudio::AudioCallback(Uint8 *stream, int len)
{
if (!m_devId)
{
debugsdl("SDLAUDIO: uhoh, no audio device!\n");
return; // can this even happen?
}
const int totalWriteable = len;
Uint8 *stream_orig = stream;
debugsdl("SDLAUDIO: writable size is %d.\n", totalWriteable);
Assert(len <= (WAV_BUFFERS * WAV_BUFFER_SIZE));
while (len > 0)
{
// spaceAvailable == bytes before we overrun the end of the ring buffer.
const int spaceAvailable = ((WAV_BUFFERS * WAV_BUFFER_SIZE * DeviceChannels())/2 - m_readPos);
const int writeLen = (len < spaceAvailable) ? len : spaceAvailable;
if (writeLen > 0)
{
const uint8_t *buf = m_pBuffer + m_readPos;
debugsdl("SDLAUDIO: Writing %d bytes...\n", writeLen);
#if 0
static FILE *io = NULL;
if (io == NULL) io = fopen("dumpplayback.raw", "wb");
if (io != NULL) { fwrite(buf, writeLen, 1, io); fflush(io); }
#endif
if ( engineClient->IsActiveApp() == false && snd_mute_losefocus.GetBool() )
{
// The game is in the background and we are set to mute
// while in background so just play silence.
memset(stream, 0, writeLen);
}
else
{
memcpy(stream, buf, writeLen);
}
stream += writeLen;
len -= writeLen;
Assert(len >= 0);
}
m_readPos = (m_readPos + writeLen) % ((WAV_BUFFERS * WAV_BUFFER_SIZE * DeviceChannels())/2); // if still bytes to write to stream, we're rolling around the ring buffer.
}
#if defined( BINK_VIDEO ) && defined( LINUX )
// Mix in Bink movie audio if that stuff is playing.
g_pBIK->SDLMixerAudioCallback( stream_orig, totalWriteable );
#endif
// Translate between bytes written and buffers written.
m_partialWrite += totalWriteable;
m_buffersSent += m_partialWrite / WAV_BUFFER_SIZE;
m_partialWrite %= WAV_BUFFER_SIZE;
}
//-----------------------------------------------------------------------------
// Actually performs the mixing
//-----------------------------------------------------------------------------
void CAudioDeviceSDLAudio::PaintEnd( void )
{
debugsdl("SDLAUDIO: PaintEnd...\n");
#if 0 // !!! FIXME: this is the 1.3 headers, but not implemented yet in SDL.
if (SDL_AudioDeviceConnected(m_devId) != 1)
{
debugsdl("SDLAUDIO: Audio device was disconnected!\n");
Shutdown();
}
#endif
}
int CAudioDeviceSDLAudio::GetOutputPosition( void )
{
return (m_readPos >> SAMPLE_16BIT_SHIFT)/DeviceChannels();
}
//-----------------------------------------------------------------------------
// Pausing
//-----------------------------------------------------------------------------
void CAudioDeviceSDLAudio::Pause( void )
{
m_pauseCount++;
if (m_pauseCount == 1)
{
debugsdl("SDLAUDIO: PAUSE\n");
SDL_PauseAudioDevice(m_devId, 1);
}
}
void CAudioDeviceSDLAudio::UnPause( void )
{
if ( m_pauseCount > 0 )
{
m_pauseCount--;
if (m_pauseCount == 0)
{
debugsdl("SDLAUDIO: UNPAUSE\n");
SDL_PauseAudioDevice(m_devId, 0);
}
}
}
bool CAudioDeviceSDLAudio::IsActive( void )
{
return ( m_pauseCount == 0 );
}
float CAudioDeviceSDLAudio::MixDryVolume( void )
{
return 0;
}
bool CAudioDeviceSDLAudio::Should3DMix( void )
{
return false;
}
void CAudioDeviceSDLAudio::ClearBuffer( void )
{
int clear;
if ( !m_pBuffer )
return;
clear = 0;
Q_memset(m_pBuffer, clear, DeviceSampleCount() * DeviceSampleBytes() );
}
void CAudioDeviceSDLAudio::MixBegin( int sampleCount )
{
MIX_ClearAllPaintBuffers( sampleCount, false );
}
void CAudioDeviceSDLAudio::MixUpsample( int sampleCount, int filtertype )
{
paintbuffer_t *ppaint = MIX_GetCurrentPaintbufferPtr();
int ifilter = ppaint->ifilter;
Assert (ifilter < CPAINTFILTERS);
S_MixBufferUpsample2x( sampleCount, ppaint->pbuf, &(ppaint->fltmem[ifilter][0]), CPAINTFILTERMEM, filtertype );
if ( ppaint->fsurround )
{
Assert( ppaint->pbufrear );
S_MixBufferUpsample2x( sampleCount, ppaint->pbufrear, &(ppaint->fltmemrear[ifilter][0]), CPAINTFILTERMEM, filtertype );
if ( ppaint->fsurround_center )
{
Assert( ppaint->pbufcenter );
S_MixBufferUpsample2x( sampleCount, ppaint->pbufcenter, &(ppaint->fltmemcenter[ifilter][0]), CPAINTFILTERMEM, filtertype );
}
}
ppaint->ifilter++;
}
void CAudioDeviceSDLAudio::Mix8Mono( channel_t *pChannel, char *pData, int outputOffset, int inputOffset, fixedint rateScaleFix, int outCount, int timecompress )
{
int volume[CCHANVOLUMES];
paintbuffer_t *ppaint = MIX_GetCurrentPaintbufferPtr();
if (!MIX_ScaleChannelVolume( ppaint, pChannel, volume, 1))
return;
Mix8MonoWavtype( pChannel, ppaint->pbuf + outputOffset, volume, (byte *)pData, inputOffset, rateScaleFix, outCount );
if ( ppaint->fsurround )
{
Assert( ppaint->pbufrear );
Mix8MonoWavtype( pChannel, ppaint->pbufrear + outputOffset, &volume[IREAR_LEFT], (byte *)pData, inputOffset, rateScaleFix, outCount );
if ( ppaint->fsurround_center )
{
Assert( ppaint->pbufcenter );
Mix8MonoWavtype( pChannel, ppaint->pbufcenter + outputOffset, &volume[IFRONT_CENTER], (byte *)pData, inputOffset, rateScaleFix, outCount );
}
}
}
void CAudioDeviceSDLAudio::Mix8Stereo( channel_t *pChannel, char *pData, int outputOffset, int inputOffset, fixedint rateScaleFix, int outCount, int timecompress )
{
int volume[CCHANVOLUMES];
paintbuffer_t *ppaint = MIX_GetCurrentPaintbufferPtr();
if (!MIX_ScaleChannelVolume( ppaint, pChannel, volume, 2 ))
return;
Mix8StereoWavtype( pChannel, ppaint->pbuf + outputOffset, volume, (byte *)pData, inputOffset, rateScaleFix, outCount );
if ( ppaint->fsurround )
{
Assert( ppaint->pbufrear );
Mix8StereoWavtype( pChannel, ppaint->pbufrear + outputOffset, &volume[IREAR_LEFT], (byte *)pData, inputOffset, rateScaleFix, outCount );
if ( ppaint->fsurround_center )
{
Assert( ppaint->pbufcenter );
Mix8StereoWavtype( pChannel, ppaint->pbufcenter + outputOffset, &volume[IFRONT_CENTER], (byte *)pData, inputOffset, rateScaleFix, outCount );
}
}
}
void CAudioDeviceSDLAudio::Mix16Mono( channel_t *pChannel, short *pData, int outputOffset, int inputOffset, fixedint rateScaleFix, int outCount, int timecompress )
{
int volume[CCHANVOLUMES];
paintbuffer_t *ppaint = MIX_GetCurrentPaintbufferPtr();
if (!MIX_ScaleChannelVolume( ppaint, pChannel, volume, 1 ))
return;
Mix16MonoWavtype( pChannel, ppaint->pbuf + outputOffset, volume, pData, inputOffset, rateScaleFix, outCount );
if ( ppaint->fsurround )
{
Assert( ppaint->pbufrear );
Mix16MonoWavtype( pChannel, ppaint->pbufrear + outputOffset, &volume[IREAR_LEFT], pData, inputOffset, rateScaleFix, outCount );
if ( ppaint->fsurround_center )
{
Assert( ppaint->pbufcenter );
Mix16MonoWavtype( pChannel, ppaint->pbufcenter + outputOffset, &volume[IFRONT_CENTER], pData, inputOffset, rateScaleFix, outCount );
}
}
}
void CAudioDeviceSDLAudio::Mix16Stereo( channel_t *pChannel, short *pData, int outputOffset, int inputOffset, fixedint rateScaleFix, int outCount, int timecompress )
{
int volume[CCHANVOLUMES];
paintbuffer_t *ppaint = MIX_GetCurrentPaintbufferPtr();
if (!MIX_ScaleChannelVolume( ppaint, pChannel, volume, 2 ))
return;
Mix16StereoWavtype( pChannel, ppaint->pbuf + outputOffset, volume, pData, inputOffset, rateScaleFix, outCount );
if ( ppaint->fsurround )
{
Assert( ppaint->pbufrear );
Mix16StereoWavtype( pChannel, ppaint->pbufrear + outputOffset, &volume[IREAR_LEFT], pData, inputOffset, rateScaleFix, outCount );
if ( ppaint->fsurround_center )
{
Assert( ppaint->pbufcenter );
Mix16StereoWavtype( pChannel, ppaint->pbufcenter + outputOffset, &volume[IFRONT_CENTER], pData, inputOffset, rateScaleFix, outCount );
}
}
}
void CAudioDeviceSDLAudio::ChannelReset( int entnum, int channelIndex, float distanceMod )
{
}
void CAudioDeviceSDLAudio::TransferSamples( int end )
{
int lpaintedtime = g_paintedtime;
int endtime = end;
// resumes playback...
if ( m_pBuffer )
{
if ( m_bSurround )
{
TransferSurround16( m_pBuffer, PAINTBUFFER, REARPAINTBUFFER, CENTERPAINTBUFFER, lpaintedtime, endtime, DeviceChannels() );
}
else
{
S_TransferStereo16( m_pBuffer, PAINTBUFFER, lpaintedtime, endtime );
}
}
}
void CAudioDeviceSDLAudio::SpatializeChannel( int nSlot, int volume[CCHANVOLUMES/2], int master_vol, const Vector& sourceDir, float gain, float mono )
{
VPROF("CAudioDeviceSDLAudio::SpatializeChannel");
S_SpatializeChannel( nSlot, volume, master_vol, &sourceDir, gain, mono );
}
void CAudioDeviceSDLAudio::StopAllSounds( void )
{
}
void CAudioDeviceSDLAudio::ApplyDSPEffects( int idsp, portable_samplepair_t *pbuffront, portable_samplepair_t *pbufrear, portable_samplepair_t *pbufcenter, int samplecount )
{
//SX_RoomFX( endtime, filter, timefx );
DSP_Process( idsp, pbuffront, pbufrear, pbufcenter, samplecount );
}
void CAudioDeviceSDLAudio::TransferSurround16( void *pOutput, const portable_samplepair_t *pfront, const portable_samplepair_t *prear, const portable_samplepair_t *pcenter, int64 lpaintedtime, int64 endtime, int nChannels)
{
const int volume = S_GetMasterVolume()*256;
const int* snd_front = (const int*)pfront;
const int* snd_rear = (const int*)prear;
const int* snd_center = (const int*)pcenter;
const int numSamples = (WAV_BUFFER_SIZE * WAV_BUFFERS)/4;
while(lpaintedtime < endtime)
{
const int lpos = lpaintedtime % numSamples;
int64 snd_linear_count = numSamples - lpos;
if ( snd_linear_count > endtime - lpaintedtime )
{
snd_linear_count = endtime - lpaintedtime;
}
short *snd_out = (short *)pOutput + lpos*nChannels;
for ( int i = 0; i < snd_linear_count; ++i )
{
const short* base = snd_out;
*snd_out++ = (snd_front[i*2] * volume) >> 8;
*snd_out++ = (snd_front[i*2+1] * volume) >> 8;
if ( nChannels >= 6 )
{
*snd_out++ = (snd_center[i*2] * volume) >> 8;
*snd_out++ = 0;
}
if ( nChannels >= 4 )
{
*snd_out++ = (snd_rear[i*2] * volume) >> 8;
*snd_out++ = (snd_rear[i*2+1] * volume) >> 8;
}
while ( snd_out - base < nChannels )
{
*snd_out++ = 0;
}
}
lpaintedtime += snd_linear_count;
snd_front += snd_linear_count*2;
snd_rear += snd_linear_count*2;
snd_center += snd_linear_count*2;
}
}
#endif // !DEDICATED
+16
View File
@@ -0,0 +1,16 @@
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=====================================================================================//
#ifndef SND_DEV_SDL_H
#define SND_DEV_SDL_H
#pragma once
class IAudioDevice;
IAudioDevice *Audio_CreateSDLAudioDevice( void );
#endif // SND_DEV_SDL_H
+563
View File
@@ -0,0 +1,563 @@
//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======//
//
// Purpose:
//
//===========================================================================//
#include "audio_pch.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
extern bool snd_firsttime;
extern bool MIX_ScaleChannelVolume( paintbuffer_t *ppaint, channel_t *pChannel, float volume[CCHANVOLUMES], int mixchans );
//extern void S_SpatializeChannel( int nSlot, int volume[6], int master_vol, const Vector *psourceDir, float gain, float mono );
// 64K is > 1 second at 16-bit, 22050 Hz
// 44k: UNDONE - need to double buffers now that we're playing back at 44100?
#define WAV_BUFFERS 64
#define WAV_MASK 0x3F
#define WAV_BUFFER_SIZE 0x0400
//-----------------------------------------------------------------------------
//
// NOTE: This only allows 16-bit, stereo wave out
//
//-----------------------------------------------------------------------------
class CAudioDeviceWave : public CAudioDeviceBase
{
public:
bool IsActive( void );
bool Init( void );
void Shutdown( void );
void PaintEnd( void );
int GetOutputPosition( void );
void ChannelReset( int entnum, int channelIndex, float distanceMod );
void Pause( void );
void UnPause( void );
float MixDryVolume( void );
bool Should3DMix( void );
void StopAllSounds( void );
int64 PaintBegin( float mixAheadTime, int64 soundtime, int64 paintedtime );
void ClearBuffer( void );
void MixBegin( int sampleCount );
void MixUpsample( int sampleCount, int filtertype );
void Mix8Mono( channel_t *pChannel, char *pData, int outputOffset, int inputOffset, fixedint rateScaleFix, int outCount, int timecompress );
void Mix8Stereo( channel_t *pChannel, char *pData, int outputOffset, int inputOffset, fixedint rateScaleFix, int outCount, int timecompress );
void Mix16Mono( channel_t *pChannel, short *pData, int outputOffset, int inputOffset, fixedint rateScaleFix, int outCount, int timecompress );
void Mix16Stereo( channel_t *pChannel, short *pData, int outputOffset, int inputOffset, fixedint rateScaleFix, int outCount, int timecompress );
void TransferSamples( int end );
// void SpatializeChannel( int nSlot, int volume[CCHANVOLUMES/2], int master_vol, const Vector& sourceDir, float gain, float mono);
void ApplyDSPEffects( int idsp, portable_samplepair_t *pbuffront, portable_samplepair_t *pbufrear, portable_samplepair_t *pbufcenter, int samplecount );
const char *DeviceName( void ) { return "Windows WAVE"; }
int DeviceChannels( void ) { return 2; }
int DeviceSampleBits( void ) { return 16; }
int DeviceSampleBytes( void ) { return 2; }
int DeviceDmaSpeed( void ) { return SOUND_DMA_SPEED; }
int DeviceSampleCount( void ) { return m_deviceSampleCount; }
private:
void OpenWaveOut( void );
void CloseWaveOut( void );
void AllocateOutputBuffers();
void FreeOutputBuffers();
void* AllocOutputMemory( int nSize, HGLOBAL &hMemory );
void FreeOutputMemory( HGLOBAL &hMemory );
bool ValidWaveOut( void ) const;
int m_deviceSampleCount;
int m_buffersSent;
int m_buffersCompleted;
int m_pauseCount;
// This is a single allocation for all wave headers (there are OUTPUT_BUFFER_COUNT of them)
HGLOBAL m_hWaveHdr;
// This is a single allocation for all wave data (there are OUTPUT_BUFFER_COUNT of them)
HANDLE m_hWaveData;
HWAVEOUT m_waveOutHandle;
// Memory for the wave data + wave headers
void *m_pBuffer;
LPWAVEHDR m_pWaveHdr;
};
//-----------------------------------------------------------------------------
// Class factory
//-----------------------------------------------------------------------------
IAudioDevice *Audio_CreateWaveDevice( void )
{
static CAudioDeviceWave *wave = NULL;
if ( !wave )
{
wave = new CAudioDeviceWave;
}
if ( wave->Init() )
return wave;
delete wave;
wave = NULL;
return NULL;
}
//-----------------------------------------------------------------------------
// Init, shutdown
//-----------------------------------------------------------------------------
bool CAudioDeviceWave::Init( void )
{
m_buffersSent = 0;
m_buffersCompleted = 0;
m_pauseCount = 0;
m_waveOutHandle = 0;
m_pBuffer = NULL;
m_pWaveHdr = NULL;
m_hWaveHdr = NULL;
m_hWaveData = NULL;
OpenWaveOut();
if ( snd_firsttime )
{
DevMsg( "Wave sound initialized\n" );
}
return ValidWaveOut();
}
void CAudioDeviceWave::Shutdown( void )
{
CloseWaveOut();
}
//-----------------------------------------------------------------------------
// WAV out device
//-----------------------------------------------------------------------------
inline bool CAudioDeviceWave::ValidWaveOut( void ) const
{
return m_waveOutHandle != 0;
}
//-----------------------------------------------------------------------------
// Opens the windows wave out device
//-----------------------------------------------------------------------------
void CAudioDeviceWave::OpenWaveOut( void )
{
WAVEFORMATEX waveFormat;
memset( &waveFormat, 0, sizeof(waveFormat) );
// Select a PCM, 16-bit stereo playback device
waveFormat.cbSize = sizeof(waveFormat);
waveFormat.wFormatTag = WAVE_FORMAT_PCM;
waveFormat.nChannels = DeviceChannels();
waveFormat.wBitsPerSample = DeviceSampleBits();
waveFormat.nSamplesPerSec = DeviceDmaSpeed(); // DeviceSampleRate
waveFormat.nBlockAlign = waveFormat.nChannels * waveFormat.wBitsPerSample / 8;
waveFormat.nAvgBytesPerSec = waveFormat.nSamplesPerSec * waveFormat.nBlockAlign;
MMRESULT errorCode = waveOutOpen( &m_waveOutHandle, WAVE_MAPPER, &waveFormat, 0, 0L, CALLBACK_NULL );
while ( errorCode != MMSYSERR_NOERROR )
{
if ( errorCode != MMSYSERR_ALLOCATED )
{
DevWarning( "waveOutOpen failed\n" );
m_waveOutHandle = 0;
return;
}
int nRetVal = MessageBox( NULL,
"The sound hardware is in use by another app.\n\n"
"Select Retry to try to start sound again or Cancel to run with no sound.",
"Sound not available",
MB_RETRYCANCEL | MB_SETFOREGROUND | MB_ICONEXCLAMATION);
if ( nRetVal != IDRETRY )
{
DevWarning( "waveOutOpen failure--hardware already in use\n" );
m_waveOutHandle = 0;
return;
}
errorCode = waveOutOpen( &m_waveOutHandle, WAVE_MAPPER, &waveFormat, 0, 0L, CALLBACK_NULL );
}
AllocateOutputBuffers();
}
//-----------------------------------------------------------------------------
// Closes the windows wave out device
//-----------------------------------------------------------------------------
void CAudioDeviceWave::CloseWaveOut( void )
{
if ( ValidWaveOut() )
{
waveOutReset( m_waveOutHandle );
FreeOutputBuffers();
waveOutClose( m_waveOutHandle );
m_waveOutHandle = NULL;
}
}
//-----------------------------------------------------------------------------
// Alloc output memory
//-----------------------------------------------------------------------------
void* CAudioDeviceWave::AllocOutputMemory( int nSize, HGLOBAL &hMemory )
{
// Output memory for waveform data+hdrs must be
// globally allocated with GMEM_MOVEABLE and GMEM_SHARE flags.
hMemory = GlobalAlloc( GMEM_MOVEABLE | GMEM_SHARE, nSize );
if ( !hMemory )
{
DevWarning( "Sound: Out of memory.\n");
CloseWaveOut();
return NULL;
}
HPSTR lpData = (char *)GlobalLock( hMemory );
if ( !lpData )
{
DevWarning( "Sound: Failed to lock.\n");
GlobalFree( hMemory );
hMemory = NULL;
CloseWaveOut();
return NULL;
}
memset( lpData, 0, nSize );
return lpData;
}
//-----------------------------------------------------------------------------
// Free output memory
//-----------------------------------------------------------------------------
void CAudioDeviceWave::FreeOutputMemory( HGLOBAL &hMemory )
{
if ( hMemory )
{
GlobalUnlock( hMemory );
GlobalFree( hMemory );
hMemory = NULL;
}
}
//-----------------------------------------------------------------------------
// Allocate output buffers
//-----------------------------------------------------------------------------
void CAudioDeviceWave::AllocateOutputBuffers()
{
// Allocate and lock memory for the waveform data.
int nBufferSize = WAV_BUFFER_SIZE * WAV_BUFFERS;
HPSTR lpData = (char *)AllocOutputMemory( nBufferSize, m_hWaveData );
if ( !lpData )
return;
// Allocate and lock memory for the waveform header
int nHdrSize = sizeof( WAVEHDR ) * WAV_BUFFERS;
LPWAVEHDR lpWaveHdr = (LPWAVEHDR)AllocOutputMemory( nHdrSize, m_hWaveHdr );
if ( !lpWaveHdr )
return;
// After allocation, set up and prepare headers.
for ( int i=0 ; i < WAV_BUFFERS; i++ )
{
LPWAVEHDR lpHdr = lpWaveHdr + i;
lpHdr->dwBufferLength = WAV_BUFFER_SIZE;
lpHdr->lpData = lpData + (i * WAV_BUFFER_SIZE);
MMRESULT nResult = waveOutPrepareHeader( m_waveOutHandle, lpHdr, sizeof(WAVEHDR) );
if ( nResult != MMSYSERR_NOERROR )
{
DevWarning( "Sound: failed to prepare wave headers\n" );
CloseWaveOut();
return;
}
}
m_deviceSampleCount = nBufferSize / DeviceSampleBytes();
m_pBuffer = (void *)lpData;
m_pWaveHdr = lpWaveHdr;
}
//-----------------------------------------------------------------------------
// Free output buffers
//-----------------------------------------------------------------------------
void CAudioDeviceWave::FreeOutputBuffers()
{
// Unprepare headers.
if ( m_pWaveHdr )
{
for ( int i=0 ; i < WAV_BUFFERS; i++ )
{
waveOutUnprepareHeader( m_waveOutHandle, m_pWaveHdr+i, sizeof(WAVEHDR) );
}
}
m_pWaveHdr = NULL;
m_pBuffer = NULL;
FreeOutputMemory( m_hWaveData );
FreeOutputMemory( m_hWaveHdr );
}
//-----------------------------------------------------------------------------
// Mixing setup
//-----------------------------------------------------------------------------
int64 CAudioDeviceWave::PaintBegin( float mixAheadTime, int64 soundtime, int64 paintedtime )
{
// soundtime - total samples that have been played out to hardware at dmaspeed
// paintedtime - total samples that have been mixed at speed
// endtime - target for samples in mixahead buffer at speed
int64 endtime = soundtime + mixAheadTime * DeviceDmaSpeed();
int samps = DeviceSampleCount() >> (DeviceChannels()-1);
if ((int)(endtime - soundtime) > samps)
endtime = soundtime + samps;
if ((endtime - paintedtime) & 0x3)
{
// The difference between endtime and painted time should align on
// boundaries of 4 samples. This is important when upsampling from 11khz -> 44khz.
endtime -= (endtime - paintedtime) & 0x3;
}
return endtime;
}
//-----------------------------------------------------------------------------
// Actually performs the mixing
//-----------------------------------------------------------------------------
void CAudioDeviceWave::PaintEnd( void )
{
LPWAVEHDR h;
int wResult;
int cblocks;
//
// find which sound blocks have completed
//
while (1)
{
if ( m_buffersCompleted == m_buffersSent )
{
//DevMsg ("Sound overrun\n");
break;
}
if ( ! (m_pWaveHdr[ m_buffersCompleted & WAV_MASK].dwFlags & WHDR_DONE) )
{
break;
}
m_buffersCompleted++; // this buffer has been played
}
//
// submit a few new sound blocks
//
// 22K sound support
// 44k: UNDONE - double blocks out now that we're at 44k playback?
cblocks = 4 << 1;
while (((m_buffersSent - m_buffersCompleted) >> SAMPLE_16BIT_SHIFT) < cblocks)
{
h = m_pWaveHdr + ( m_buffersSent&WAV_MASK );
m_buffersSent++;
/*
* Now the data block can be sent to the output device. The
* waveOutWrite function returns immediately and waveform
* data is sent to the output device in the background.
*/
wResult = waveOutWrite( m_waveOutHandle, h, sizeof(WAVEHDR) );
if (wResult != MMSYSERR_NOERROR)
{
Warning( "Failed to write block to device\n");
Shutdown();
return;
}
}
}
int CAudioDeviceWave::GetOutputPosition( void )
{
int s = m_buffersSent * WAV_BUFFER_SIZE;
s >>= SAMPLE_16BIT_SHIFT;
s &= (DeviceSampleCount()-1);
return s / DeviceChannels();
}
//-----------------------------------------------------------------------------
// Pausing
//-----------------------------------------------------------------------------
void CAudioDeviceWave::Pause( void )
{
m_pauseCount++;
if (m_pauseCount == 1)
{
waveOutReset( m_waveOutHandle );
}
}
void CAudioDeviceWave::UnPause( void )
{
if ( m_pauseCount > 0 )
{
m_pauseCount--;
}
}
bool CAudioDeviceWave::IsActive( void )
{
return ( m_pauseCount == 0 );
}
float CAudioDeviceWave::MixDryVolume( void )
{
return 0;
}
bool CAudioDeviceWave::Should3DMix( void )
{
return false;
}
void CAudioDeviceWave::ClearBuffer( void )
{
int clear;
if ( !m_pBuffer )
return;
clear = 0;
Q_memset(m_pBuffer, clear, DeviceSampleCount() * DeviceSampleBytes() );
}
void CAudioDeviceWave::MixBegin( int sampleCount )
{
MIX_ClearAllPaintBuffers( sampleCount, false );
}
void CAudioDeviceWave::MixUpsample( int sampleCount, int filtertype )
{
paintbuffer_t *ppaint = MIX_GetCurrentPaintbufferPtr();
int ifilter = ppaint->ifilter;
Assert (ifilter < CPAINTFILTERS);
S_MixBufferUpsample2x( sampleCount, ppaint->pbuf, &(ppaint->fltmem[ifilter][0]), CPAINTFILTERMEM, filtertype );
ppaint->ifilter++;
}
void CAudioDeviceWave::Mix8Mono( channel_t *pChannel, char *pData, int outputOffset, int inputOffset, fixedint rateScaleFix, int outCount, int timecompress )
{
float volume[CCHANVOLUMES];
paintbuffer_t *ppaint = MIX_GetCurrentPaintbufferPtr();
if (!MIX_ScaleChannelVolume( ppaint, pChannel, volume, 1))
return;
Mix8MonoWavtype( pChannel, ppaint->pbuf + outputOffset, volume, (byte *)pData, inputOffset, rateScaleFix, outCount );
}
void CAudioDeviceWave::Mix8Stereo( channel_t *pChannel, char *pData, int outputOffset, int inputOffset, fixedint rateScaleFix, int outCount, int timecompress )
{
float volume[CCHANVOLUMES];
paintbuffer_t *ppaint = MIX_GetCurrentPaintbufferPtr();
if (!MIX_ScaleChannelVolume( ppaint, pChannel, volume, 2 ))
return;
Mix8StereoWavtype( pChannel, ppaint->pbuf + outputOffset, volume, (byte *)pData, inputOffset, rateScaleFix, outCount );
}
void CAudioDeviceWave::Mix16Mono( channel_t *pChannel, short *pData, int outputOffset, int inputOffset, fixedint rateScaleFix, int outCount, int timecompress )
{
float volume[CCHANVOLUMES];
paintbuffer_t *ppaint = MIX_GetCurrentPaintbufferPtr();
if (!MIX_ScaleChannelVolume( ppaint, pChannel, volume, 1 ))
return;
Mix16MonoWavtype( pChannel, ppaint->pbuf + outputOffset, volume, pData, inputOffset, rateScaleFix, outCount );
}
void CAudioDeviceWave::Mix16Stereo( channel_t *pChannel, short *pData, int outputOffset, int inputOffset, fixedint rateScaleFix, int outCount, int timecompress )
{
float volume[CCHANVOLUMES];
paintbuffer_t *ppaint = MIX_GetCurrentPaintbufferPtr();
if (!MIX_ScaleChannelVolume( ppaint, pChannel, volume, 2 ))
return;
Mix16StereoWavtype( pChannel, ppaint->pbuf + outputOffset, volume, pData, inputOffset, rateScaleFix, outCount );
}
void CAudioDeviceWave::ChannelReset( int entnum, int channelIndex, float distanceMod )
{
}
void CAudioDeviceWave::TransferSamples( int end )
{
int64 lpaintedtime = g_paintedtime;
int64 endtime = end;
// resumes playback...
if ( m_pBuffer )
{
S_TransferStereo16( m_pBuffer, PAINTBUFFER, lpaintedtime, endtime );
}
}
// temporarily deprecating to be sure which version of SpatializeChannel is used
/*void CAudioDeviceWave::SpatializeChannel( int nSlot, int volume[CCHANVOLUMES/2], int master_vol, const Vector& sourceDir, float gain, float mono )
{
VPROF("CAudioDeviceWave::SpatializeChannel");
S_SpatializeChannel( nSlot, volume, master_vol, &sourceDir, gain, mono );
}
*/
void CAudioDeviceWave::StopAllSounds( void )
{
}
void CAudioDeviceWave::ApplyDSPEffects( int idsp, portable_samplepair_t *pbuffront, portable_samplepair_t *pbufrear, portable_samplepair_t *pbufcenter, int samplecount )
{
//SX_RoomFX( endtime, filter, timefx );
DSP_Process( idsp, pbuffront, pbufrear, pbufcenter, samplecount );
}
+14
View File
@@ -0,0 +1,14 @@
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=====================================================================================//
#ifndef SND_DEV_WAVE_H
#define SND_DEV_WAVE_H
#pragma once
class IAudioDevice;
IAudioDevice *Audio_CreateWaveDevice( void );
#endif // SND_DEV_WAVE_H
File diff suppressed because it is too large Load Diff
+66
View File
@@ -0,0 +1,66 @@
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=====================================================================================//
#ifndef SND_DEV_XAUDIO_H
#define SND_DEV_XAUDIO_H
#pragma once
#include "audio_pch.h"
#include "inetmessage.h"
#include "netmessages.h"
#include "engine/ienginevoice.h"
class IAudioDevice;
IAudioDevice *Audio_CreateXAudioDevice( bool bInitVoice );
#if defined ( _X360 )
class CXboxVoice : public IEngineVoice
{
public:
CXboxVoice();
static const DWORD MAX_VOICE_BUFFER_TIME = 200; // 200ms
void VoiceInit( void );
void VoiceShutdown( void );
void AddPlayerToVoiceList( XUID xPlayer, int iController, uint64 uiFlags );
void RemovePlayerFromVoiceList( XUID xPlayer, int iController );
bool VoiceUpdateData( int iCtrlr );
void GetVoiceData( int iCtrlr, CCLCMsg_VoiceData_t *pData );
void GetVoiceData( int iController, const byte **ppvVoiceDataBuffer, unsigned int *pnumVoiceDataBytes );
void VoiceSendData( int iCtrlr, INetChannel *pChannel );
void VoiceResetLocalData( int iCtrlr );
void PlayIncomingVoiceData( XUID xuid, const byte *pbData, unsigned int dwDataSize, const bool *bAudiblePlayers = NULL );
void UpdateHUDVoiceStatus( void );
void GetRemoteTalkers( int *pNumTalkers, XUID *pRemoteTalkers );
void SetPlaybackPriority( XUID remoteTalker, int iController, int iAllowPlayback );
bool IsLocalPlayerTalking( int controlerID );
bool IsPlayerTalking( XUID uid );
bool IsHeadsetPresent( int id );
void RemoveAllTalkers();
private:
PIXHV2ENGINE m_pXHVEngine;
// Local chat data
static const WORD m_ChatBufferSize = XHV_VOICECHAT_MODE_PACKET_SIZE * XHV_MAX_VOICECHAT_PACKETS;
BYTE m_ChatBuffer[ XUSER_MAX_COUNT ][ m_ChatBufferSize ];
WORD m_wLocalDataSize[ XUSER_MAX_COUNT ];
bool m_bUserRegistered[ XUSER_MAX_COUNT ]; //This is to handle a bug in UnregisterLocalTalker where it crashes on
//unregistering a local talker who has not been registered if the
//controller id is non-0.
// Last voice data sent
DWORD m_dwLastVoiceSend[ XUSER_MAX_COUNT ];
};
CXboxVoice *Audio_GetXVoice( void );
IXAudio2 *Audio_GetXAudio2( void );
#endif
#endif // SND_DEV_XAUDIO_H
File diff suppressed because it is too large Load Diff
+68
View File
@@ -0,0 +1,68 @@
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef SND_DMA_H
#define SND_DMA_H
#ifdef _WIN32
#pragma once
#endif
extern ConVar snd_obscured_gain_db;
extern ConVar snd_showstart;
extern ConVar snd_refdb;
extern ConVar snd_refdist;
extern float snd_refdb_dist_mult;
extern bool snd_initialized;
extern int g_snd_trace_count;
// convert sound db level to approximate sound source radius,
// used only for determining how much of sound is obscured by world
#define SND_RADIUS_MAX (20.0 * 12.0) // max sound source radius
#define SND_RADIUS_MIN (2.0 * 12.0) // min sound source radius
#define SND_DB_MAX 140.0 // max db of any sound source
#define SND_DB_MED 90.0 // db at which compression curve changes
#define SND_DB_MIN 60.0 // min db of any sound source
inline float dB_To_Radius ( float db )
{
return SND_RADIUS_MIN + (SND_RADIUS_MAX - SND_RADIUS_MIN) * (db - SND_DB_MIN) / (SND_DB_MAX - SND_DB_MIN);
}
class CScratchPad;
const int MASK_BLOCK_AUDIO = CONTENTS_SOLID|CONTENTS_MOVEABLE|CONTENTS_WINDOW;
#define SNDLVL_TO_DIST_MULT( sndlvl ) ( sndlvl ? ((snd_refdb_dist_mult / FastPow10( (float)sndlvl / 20 )) / snd_refdist.GetFloat()) : 0 )
#define DIST_MULT_TO_SNDLVL( dist_mult ) (soundlevel_t)(int)( dist_mult ? ( 20 * log10( (float)(snd_refdb_dist_mult / (dist_mult * snd_refdist.GetFloat()) )) ) : 0 )
float SND_GetGainFromMult( float gain, float dist_mult, vec_t dist );
float SND_GetDspMix( channel_t *pchannel, int idist, float flSndlvl );
bool SND_ChannelOkToTrace( channel_t *ch );
float SND_GetGainObscured( int nSlot, gain_t *gs, const channel_t *ch, const Vector &vecListenerOrigin, bool fplayersound, bool flooping, bool bAttenuated, bool bOkayToTrace, Vector *pOrigin = NULL );
float S_GetDashboarMusicMixValue( );
float SND_GetFacingDirection( channel_t *pChannel, const Vector &vecListenerOrigin, const QAngle &source_angles );
void SND_MergeVolumes( const float build_volumes[ MAX_SPLITSCREEN_CLIENTS ][CCHANVOLUMES/2], float volumes[CCHANVOLUMES/2] );
void ConvertListenerVectorTo2D( Vector *pvforward, const Vector *pvright );
void ChannelSetVolTargets( channel_t *pch, float *pvolumes, int ivol_offset, int cvol );
void S_StartSoundEntryByHash( HSOUNDSCRIPTHASH nHandle );
channel_t *S_FindChannelByScriptHash( HSOUNDSCRIPTHASH nHandle );
void S_StopChannel( channel_t *pChannel );
channel_t *S_FindChannelByGuid( int guid );
bool SND_IsInGame();
float SND_FadeToNewGain( gain_t *gs, const channel_t *ch, float gain_new );
bool SND_IsLongWave( channel_t pChannel );
float dB_To_Gain( float );
#endif // SND_DMA_H
File diff suppressed because it is too large Load Diff
+61
View File
@@ -0,0 +1,61 @@
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef SND_ENV_FX_H
#define SND_ENV_FX_H
#if defined( _WIN32 )
#pragma once
#endif
//=====================================================================
// FX presets
//=====================================================================
#define SXROOM_OFF 0
#define SXROOM_GENERIC 1 // general, low reflective, diffuse room
#define SXROOM_METALIC_S 2 // highly reflective, parallel surfaces
#define SXROOM_METALIC_M 3
#define SXROOM_METALIC_L 4
#define SXROOM_TUNNEL_S 5 // resonant reflective, long surfaces
#define SXROOM_TUNNEL_M 6
#define SXROOM_TUNNEL_L 7
#define SXROOM_CHAMBER_S 8 // diffuse, moderately reflective surfaces
#define SXROOM_CHAMBER_M 9
#define SXROOM_CHAMBER_L 10
#define SXROOM_BRITE_S 11 // diffuse, highly reflective
#define SXROOM_BRITE_M 12
#define SXROOM_BRITE_L 13
#define SXROOM_WATER1 14 // underwater fx
#define SXROOM_WATER2 15
#define SXROOM_WATER3 16
#define SXROOM_CONCRETE_S 17 // bare, reflective, parallel surfaces
#define SXROOM_CONCRETE_M 18
#define SXROOM_CONCRETE_L 19
#define SXROOM_OUTSIDE1 20 // echoing, moderately reflective
#define SXROOM_OUTSIDE2 21 // echoing, dull
#define SXROOM_OUTSIDE3 22 // echoing, very dull
#define SXROOM_CAVERN_S 23 // large, echoing area
#define SXROOM_CAVERN_M 24
#define SXROOM_CAVERN_L 25
#define SXROOM_WEIRDO1 26
#define SXROOM_WEIRDO2 27
#define SXROOM_WEIRDO3 28
#define CSXROOM 29
#endif // SND_ENV_FX_H
+40
View File
@@ -0,0 +1,40 @@
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef SND_FIXEDINT_H
#define SND_FIXEDINT_H
#if defined( _WIN32 )
#pragma once
#endif
// fixed point stuff for real-time resampling
#define FIX_BITS 28
#define FIX_SCALE (1 << FIX_BITS)
#define FIX_MASK ((1 << FIX_BITS)-1)
#define FIX_FLOAT(a) ((int)((a) * FIX_SCALE))
#define FIX(a) (((int)(a)) << FIX_BITS)
#define FIX_INTPART(a) (((int)(a)) >> FIX_BITS)
#define FIX_FRACTION(a,b) (FIX(a)/(b))
#define FIX_FRACPART(a) ((a) & FIX_MASK)
#define FIX_TODOUBLE(a) ((double)(a) / (double)FIX_SCALE)
typedef unsigned int fixedint;
#define FIX_BITS14 14
#define FIX_SCALE14 (1 << FIX_BITS14)
#define FIX_MASK14 ((1 << FIX_BITS14)-1)
#define FIX_FLOAT14(a) ((int)((a) * FIX_SCALE14))
#define FIX14(a) (((int)(a)) << FIX_BITS14)
#define FIX_INTPART14(a) (((int)(a)) >> FIX_BITS14)
#define FIX_FRACTION14(a,b) (FIX14(a)/(b))
#define FIX_FRACPART14(a) ((a) & FIX_MASK14)
#define FIX_14TODOUBLE(a) ((double)(a) / (double)FIX_SCALE14)
#define FIX_28TO14(a) ( (int)( ((unsigned int)(a)) >> (FIX_BITS - 14) ) )
#endif // SND_FIXEDINT_H
File diff suppressed because it is too large Load Diff
+107
View File
@@ -0,0 +1,107 @@
//========= Copyright 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef SND_MIX_BUF_H
#define SND_MIX_BUF_H
#if defined( _WIN32 )
#pragma once
#endif
// OPTIMIZE: note that making this larger will not increase performance (12/27/03)
#define PAINTBUFFER_SIZE 1020 // 44k: was 512
#define PAINTBUFFER (g_curpaintbuffer)
#define REARPAINTBUFFER (g_currearpaintbuffer)
#define CENTERPAINTBUFFER (g_curcenterpaintbuffer)
#define CPAINTBUFFERS 6
// !!! if this is changed, it much be changed in native assembly too !!!
struct portable_samplepair_t
{
int left;
int right;
};
// This should match the struct portable_samplepair_t
enum Channels
{
CHANNEL_LEFT = 0,
CHANNEL_RIGHT = 1,
};
// sound mixing buffer
#define CPAINTFILTERMEM 3
#define CPAINTFILTERS 4 // maximum number of consecutive upsample passes per paintbuffer
struct paintbuffer_t
{
bool factive; // if true, mix to this paintbuffer using flags
bool fsurround; // if true, mix to front and rear paintbuffers using flags
bool fsurround_center; // if true, mix to front, rear and center paintbuffers using flags
int flags; // SOUND_BUSS_ROOM, SOUND_BUSS_FACING, SOUND_BUSS_FACINGAWAY, SOUND_BUSS_SPEAKER, SOUND_BUSS_DRY
portable_samplepair_t *pbuf; // front stereo mix buffer, for 2 or 4 channel mixing
portable_samplepair_t *pbufrear; // rear mix buffer, for 4 channel mixing
portable_samplepair_t *pbufcenter; // center mix buffer, for 5 channel mixing
int ifilter; // current filter memory buffer to use for upsampling pass
portable_samplepair_t fltmem[CPAINTFILTERS][CPAINTFILTERMEM]; // filter memory, for upsampling with linear or cubic interpolation
portable_samplepair_t fltmemrear[CPAINTFILTERS][CPAINTFILTERMEM]; // filter memory, for upsampling with linear or cubic interpolation
portable_samplepair_t fltmemcenter[CPAINTFILTERS][CPAINTFILTERMEM]; // filter memory, for upsampling with linear or cubic interpolation
};
extern "C"
{
extern portable_samplepair_t *g_paintbuffer;
// temp paintbuffer - not included in main list of paintbuffers
extern portable_samplepair_t *g_temppaintbuffer;
extern paintbuffer_t *g_paintBuffers;
extern void MIX_SetCurrentPaintbuffer( int ipaintbuffer );
extern int MIX_GetCurrentPaintbufferIndex( void );
extern paintbuffer_t *MIX_GetCurrentPaintbufferPtr( void );
extern void MIX_ClearAllPaintBuffers( int SampleCount, bool clearFilters );
extern bool MIX_InitAllPaintbuffers(void);
extern void MIX_FreeAllPaintbuffers(void);
extern portable_samplepair_t *g_curpaintbuffer;
extern portable_samplepair_t *g_currearpaintbuffer;
extern portable_samplepair_t *g_curcenterpaintbuffer;
};
// must be at least PAINTBUFFER_SIZE+1 for upsampling
#define PAINTBUFFER_MEM_SIZE (PAINTBUFFER_SIZE+4)
// size in samples of copy buffer used by pitch shifters in mixing
#if defined(_GAMECONSOLE)
#define TEMP_COPY_BUFFER_SIZE (PAINTBUFFER_MEM_SIZE * 2)
#else
// allow more memory for this on PC for developers to pitch-shift their way through dialog
#define TEMP_COPY_BUFFER_SIZE (PAINTBUFFER_MEM_SIZE * 4)
#endif
// hard clip input value to -32767 <= y <= 32767
#define CLIP(x) ((x) > 32767 ? 32767 : ((x) < -32767 ? -32767 : (x)))
// Branch-less version of CLIP on PPC - Much better.
FORCEINLINE
int iclip( int nInput )
{
int nResult = iclamp( nInput, -32767, +32767 ); // Interestingly it should actually be -32768 but the old code did not use the correct value. Keep the old value for the moment.
Assert( nResult == CLIP( nInput ) );
return nResult;
}
#endif // SND_MIX_BUF_H
File diff suppressed because it is too large Load Diff
+70
View File
@@ -0,0 +1,70 @@
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef SND_MIXGROUP_MANAGER_H
#define SND_MIXGROUP_MANAGER_H
#ifdef _WIN32
#pragma once
#endif
enum MXRMixGroupFields_t
{
MXR_MIXGROUP_NONE = 0,
MXR_MIXGROUP_VOL,
MXR_MIXGROUP_LEVEL,
MXR_MIXGROUP_DSP,
MXR_MIXGROUP_SOLO,
MXR_MIXGROUP_MUTE
};
struct mixervalues_t
{
//public:
float volume;
float level;
float dsp;
mixervalues_t(void)
{
volume = 1.0;
level = 1.0;
dsp = 1.0;
}
};
void MXR_SetSoloActive(void);
bool MXR_LoadAllSoundMixers( void );
void MXR_ReleaseMemory( void );
int MXR_GetMixGroupListFromDirName( const char *pDirname, byte *pList, int listMax );
bool MXR_IsMusicGroup( int ruleIndex );
void MXR_GetMixGroupFromSoundsource( channel_t *pchan );
void MXR_GetValuesFromMixGroupIndex( mixervalues_t *mixValues, int imixgroup );
void MXR_GetVolFromMixGroup( channel_t *ch, mixervalues_t *mixValues, int *plast_mixgroupid );
char *MXR_GetGroupnameFromId( int mixgroupid );
int MXR_GetMixgroupFromName( const char *pszgroupname );
int MXR_GetFirstValidMixGroup( channel_t *pChannel );
void MXR_DebugShowMixVolumes( void );
#ifdef _DEBUG
void MXR_DebugSetMixGroupVolume( const CCommand &args );
#endif //_DEBUG
static void MXR_SetSoundMixer( const CCommand &args );
static void MXR_ListMixGroups( const CCommand &args );
void MXR_UpdateAllDuckerVolumes( void );
// // sound mixers
// int g_csoundmixers = 0; // total number of soundmixers found
// extern int g_cgrouprules; // total number of group rules found
// int g_cgroupclass = 0;
int MXR_GetMixLayerIndexFromName( const char *szmixlayername );
void S_SetMixGroupOfMixLayer( int nMixGroupIndex, int nMixLayerIndex, MXRMixGroupFields_t nMixGroupField, float flValue );
#endif // SND_MIXGROUP_MANAGER_H
+392
View File
@@ -0,0 +1,392 @@
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
#include "audio_pch.h"
#include "snd_mp3_source.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
CAudioSourceMP3::CAudioSourceMP3( CSfxTable *pSfx )
{
m_sampleRate = 44100;
m_pSfx = pSfx;
m_refCount = 0;
m_dataStart = 0;
char nameBuf[MAX_PATH];
FileHandle_t file = g_pSndIO->open( pSfx->GetFileName( nameBuf, sizeof(nameBuf) ) );
if ( (intp)file != -1 )
{
m_dataSize = g_pSndIO->size( file );
g_pSndIO->close( file );
}
else
{
m_dataSize = 0;
}
m_nCachedDataSize = 0;
m_bIsPlayOnce = false;
m_bIsSentenceWord = false;
}
CAudioSourceMP3::CAudioSourceMP3( CSfxTable *pSfx, CAudioSourceCachedInfo *info )
{
m_sampleRate = 44100;
m_pSfx = pSfx;
m_refCount = 0;
m_dataSize = info->DataSize();
m_dataStart = info->DataStart();
m_nCachedDataSize = 0;
m_bIsPlayOnce = false;
}
CAudioSourceMP3::~CAudioSourceMP3()
{
}
// mixer's references
void CAudioSourceMP3::ReferenceAdd( CAudioMixer * )
{
m_refCount++;
}
void CAudioSourceMP3::ReferenceRemove( CAudioMixer * )
{
m_refCount--;
if ( m_refCount == 0 && IsPlayOnce() )
{
SetPlayOnce( false ); // in case it gets used again
CacheUnload();
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CAudioSourceMP3::IsAsyncLoad()
{
if ( !m_AudioCacheHandle.IsValid() )
{
m_AudioCacheHandle.Get( GetType(), m_pSfx->IsPrecachedSound(), m_pSfx, &m_nCachedDataSize );
}
// If there's a bit of "cached data" then we don't have to lazy/async load (we still async load the remaining data,
// but we run from the cache initially)
return ( m_nCachedDataSize > 0 ) ? false : true;
}
// check reference count, return true if nothing is referencing this
bool CAudioSourceMP3::CanDelete( void )
{
return m_refCount > 0 ? false : true;
}
bool CAudioSourceMP3::GetStartupData()
{
char nameBuf[MAX_PATH];
FileHandle_t file = g_pSndIO->open( m_pSfx->GetFileName( nameBuf, sizeof(nameBuf) ) );
if ( !file )
{
return false;
}
m_dataSize = (int)g_pSndIO->size( file );
g_pSndIO->close( file );
return true;
}
//-----------------------------------------------------------------------------
// Purpose:
// Output : int
//-----------------------------------------------------------------------------
int CAudioSourceMP3::GetType()
{
return AUDIO_SOURCE_MP3;
}
void CAudioSourceMP3::GetCacheData( CAudioSourceCachedInfo *info )
{
info->SetSampleRate( m_sampleRate );
info->SetDataStart( 0 );
GetStartupData();
// Data size gets computed in GetStartupData!!!
info->SetDataSize( m_dataSize );
}
//-----------------------------------------------------------------------------
// Purpose:
// Output : char const
//-----------------------------------------------------------------------------
char const *CAudioSourceMP3::GetFileName( char *pOutBuf, size_t bufLen )
{
return m_pSfx ? m_pSfx->GetFileName(pOutBuf, bufLen) : "NULL m_pSfx";
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CAudioSourceMP3::CheckAudioSourceCache()
{
Assert( m_pSfx );
if ( !m_pSfx->IsPrecachedSound() )
{
return;
}
// This will "re-cache" this if it's not in this level's cache already
m_AudioCacheHandle.Get( GetType(), true, m_pSfx, &m_nCachedDataSize );
}
//-----------------------------------------------------------------------------
// Purpose: NULL the wave data pointer (we haven't loaded yet)
//-----------------------------------------------------------------------------
CAudioSourceMP3Cache::CAudioSourceMP3Cache( CSfxTable *pSfx ) :
CAudioSourceMP3( pSfx )
{
m_hCache = 0;
}
CAudioSourceMP3Cache::CAudioSourceMP3Cache( CSfxTable *pSfx, CAudioSourceCachedInfo *info ) :
CAudioSourceMP3( pSfx, info )
{
m_hCache = 0;
m_dataSize = info->DataSize();
m_dataStart = info->DataStart();
}
//-----------------------------------------------------------------------------
// Purpose: Free any wave data we've allocated
//-----------------------------------------------------------------------------
CAudioSourceMP3Cache::~CAudioSourceMP3Cache( void )
{
CacheUnload();
}
int CAudioSourceMP3Cache::GetCacheStatus( void )
{
bool bCacheValid;
int loaded = wavedatacache->IsDataLoadCompleted( m_hCache, &bCacheValid ) ? AUDIO_IS_LOADED : AUDIO_NOT_LOADED;
if ( !bCacheValid )
{
char nameBuf[MAX_PATH];
wavedatacache->RestartDataLoad( &m_hCache, m_pSfx->GetFileName(nameBuf, sizeof(nameBuf)), m_dataSize, m_dataStart );
}
return loaded;
}
void CAudioSourceMP3Cache::CacheLoad( void )
{
// Commence lazy load?
if ( m_hCache != 0 )
{
GetCacheStatus();
return;
}
char nameBuf[MAX_PATH];
m_hCache = wavedatacache->AsyncLoadCache( m_pSfx->GetFileName(nameBuf, sizeof(nameBuf)), m_dataSize, m_dataStart );
}
void CAudioSourceMP3Cache::CacheUnload( void )
{
if ( m_hCache != 0 )
{
wavedatacache->Unload( m_hCache );
}
}
char *CAudioSourceMP3Cache::GetDataPointer( void )
{
char *pMP3Data = NULL;
bool dummy = false;
if ( m_hCache == 0 )
{
CacheLoad();
}
char nameBuf[MAX_PATH];
wavedatacache->GetDataPointer(
m_hCache,
m_pSfx->GetFileName(nameBuf, sizeof(nameBuf)),
m_dataSize,
m_dataStart,
(void **)&pMP3Data,
0,
&dummy );
return pMP3Data;
}
int CAudioSourceMP3Cache::GetOutputData( void **pData, int64 samplePosition, int sampleCount, char copyBuf[AUDIOSOURCE_COPYBUF_SIZE] )
{
// how many bytes are available ?
int totalSampleCount = m_dataSize - samplePosition;
// may be asking for a sample out of range, clip at zero
if ( totalSampleCount < 0 )
totalSampleCount = 0;
// clip max output samples to max available
if ( sampleCount > totalSampleCount )
sampleCount = totalSampleCount;
// if we are returning some samples, store the pointer
if ( sampleCount )
{
// Starting past end of "preloaded" data, just use regular cache
if ( samplePosition >= m_nCachedDataSize )
{
*pData = GetDataPointer();
}
else
{
// Start async loader if we haven't already done so
CacheLoad();
// Return less data if we are about to run out of uncached data
if ( samplePosition + sampleCount >= m_nCachedDataSize )
{
sampleCount = m_nCachedDataSize - samplePosition;
}
// Point at preloaded/cached data from .cache file for now
*pData = GetCachedDataPointer();
}
if ( *pData )
{
*pData = (char *)*pData + samplePosition;
}
else
{
// Out of data or file i/o problem
sampleCount = 0;
}
}
return sampleCount;
}
CAudioMixer *CAudioSourceMP3Cache::CreateMixer( int initialStreamPosition, int skipInitialSamples, bool bUpdateDelayForChoreo, SoundError &soundError, hrtf_info_t *pHRTFVector )
{
CAudioMixer *pMixer = CreateMP3Mixer( CreateWaveDataMemory(*this), &m_sampleRate );
if ( pMixer )
{
ReferenceAdd( pMixer );
soundError = SE_OK;
}
else
{
soundError = SE_CANT_CREATE_MIXER;
}
return pMixer;
}
CAudioSourceStreamMP3::CAudioSourceStreamMP3( CSfxTable *pSfx ) :
CAudioSourceMP3( pSfx )
{
}
CAudioSourceStreamMP3::CAudioSourceStreamMP3( CSfxTable *pSfx, CAudioSourceCachedInfo *info ) :
CAudioSourceMP3( pSfx, info )
{
m_dataSize = info->DataSize();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CAudioSourceStreamMP3::Prefetch()
{
char nameBuf[MAX_PATH];
PrefetchDataStream( m_pSfx->GetFileName(nameBuf, sizeof(nameBuf)), 0, m_dataSize );
}
CAudioMixer *CAudioSourceStreamMP3::CreateMixer(int intialStreamPosition, int initialSkipSamples, bool bUpdateDelayForChoreo, SoundError &soundError, hrtf_info_t *pHRTFVector )
{
char nameBuf[MAX_PATH];
// BUGBUG: Source constructs the IWaveData, mixer frees it, fix this?
IWaveData *pWaveData = CreateWaveDataStream(*this, static_cast<IWaveStreamSource *>(this), m_pSfx->GetFileName(nameBuf, sizeof(nameBuf)), 0, m_dataSize, m_pSfx, 0, 0, soundError );
if ( pWaveData )
{
CAudioMixer *pMixer = CreateMP3Mixer( pWaveData, &m_sampleRate );
if ( pMixer )
{
ReferenceAdd( pMixer );
soundError = SE_OK;
return pMixer;
}
// no mixer but pWaveData was deleted in mixer's destructor
// so no need to delete
}
soundError = SE_CANT_CREATE_MIXER;
return NULL;
}
int CAudioSourceStreamMP3::GetOutputData( void **pData, int64 samplePosition, int sampleCount, char copyBuf[AUDIOSOURCE_COPYBUF_SIZE] )
{
return 0;
}
bool Audio_IsMP3( const char *pName )
{
int len = strlen(pName);
if ( len > 4 )
{
if ( !Q_strnicmp( &pName[len - 4], ".mp3", 4 ) )
{
return true;
}
}
return false;
}
CAudioSource *Audio_CreateStreamedMP3( CSfxTable *pSfx )
{
CAudioSourceStreamMP3 *pMP3 = NULL;
CAudioSourceCachedInfo *info = audiosourcecache->GetInfo( CAudioSource::AUDIO_SOURCE_MP3, pSfx->IsPrecachedSound(), pSfx );
if ( info && info->DataSize() != 0 )
{
pMP3 = new CAudioSourceStreamMP3( pSfx, info );
}
else
{
pMP3 = new CAudioSourceStreamMP3( pSfx );
}
return pMP3;
}
CAudioSource *Audio_CreateMemoryMP3( CSfxTable *pSfx )
{
CAudioSourceMP3Cache *pMP3 = NULL;
CAudioSourceCachedInfo *info = audiosourcecache->GetInfo( CAudioSource::AUDIO_SOURCE_MP3, pSfx->IsPrecachedSound(), pSfx );
if ( info )
{
pMP3 = new CAudioSourceMP3Cache( pSfx, info );
}
else
{
pMP3 = new CAudioSourceMP3Cache( pSfx );
}
return pMP3;
}
+185
View File
@@ -0,0 +1,185 @@
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef SND_MP3_SOURCE_H
#define SND_MP3_SOURCE_H
#ifdef _WIN32
#pragma once
#endif
#include "snd_audio_source.h"
#include "snd_wave_data.h"
#include "snd_sfx.h"
class IWaveData;
class CAudioMixer;
abstract_class CAudioSourceMP3 : public CAudioSource
{
public:
CAudioSourceMP3( CSfxTable *pSfx );
CAudioSourceMP3( CSfxTable *pSfx, CAudioSourceCachedInfo *info );
virtual ~CAudioSourceMP3();
// Create an instance (mixer) of this audio source
virtual CAudioMixer *CreateMixer( int initialStreamPosition, int skipInitialSamples, bool bUpdateDelayForChoreo, SoundError &soundError, struct hrtf_info_t* pHRTFVec ) = 0;
virtual int GetType( void );
virtual void GetCacheData( CAudioSourceCachedInfo *info );
// Provide samples for the mixer. You can point pData at your own data, or if you prefer to copy the data,
// you can copy it into copyBuf and set pData to copyBuf.
virtual int GetOutputData( void **pData, int64 samplePosition, int sampleCount, char copyBuf[AUDIOSOURCE_COPYBUF_SIZE] ) = 0;
virtual int SampleRate( void ) { return m_sampleRate; }
// Returns true if the source is a voice source.
// This affects the voice_overdrive behavior (all sounds get quieter when
// someone is speaking).
virtual bool IsVoiceSource() { return false; }
virtual bool IsPlayerVoice() { return false; }
virtual int SampleSize( void ) { return 1; }
// Total number of samples in this source. NOTE: Some sources are infinite (mic input), they should return
// a count equal to one second of audio at their current rate.
virtual int SampleCount( void ) { return m_dataSize; }
virtual int Format() { return 0; }
virtual int DataSize( void ) { return 0; }
virtual bool IsLooped( void ) { return false; }
virtual bool IsStereoWav( void ) { return false; }
virtual bool IsStreaming( void ) { return false; }
virtual int GetCacheStatus( void ) { return AUDIO_IS_LOADED; }
virtual void CacheLoad( void ) {}
virtual void CacheUnload( void ) {}
virtual CSentence *GetSentence( void ) { return NULL; }
virtual int GetQuality( void ) { return 0; }
virtual int ZeroCrossingBefore( int sample ) { return sample; }
virtual int ZeroCrossingAfter( int sample ) { return sample; }
// mixer's references
virtual void ReferenceAdd( CAudioMixer *pMixer );
virtual void ReferenceRemove( CAudioMixer *pMixer );
// check reference count, return true if nothing is referencing this
virtual bool CanDelete( void );
virtual bool IsAsyncLoad();
virtual void CheckAudioSourceCache();
virtual char const *GetFileName( char *pOutBuf, size_t bufLen );
virtual void SetPlayOnce( bool isPlayOnce ) { m_bIsPlayOnce = isPlayOnce; }
virtual bool IsPlayOnce() { return m_bIsPlayOnce; }
virtual void SetSentenceWord( bool bIsWord ) { m_bIsSentenceWord = bIsWord; }
virtual bool IsSentenceWord() { return m_bIsSentenceWord; }
virtual int SampleToStreamPosition( int samplePosition ) { return 0; }
virtual int StreamToSamplePosition( int streamPosition ) { return 0; }
protected:
//-----------------------------------------------------------------------------
// Purpose:
// Output : byte
//-----------------------------------------------------------------------------
inline byte *GetCachedDataPointer()
{
VPROF("CAudioSourceMP3::GetCachedDataPointer");
CAudioSourceCachedInfo *info = m_AudioCacheHandle.Get( CAudioSource::AUDIO_SOURCE_MP3, m_pSfx->IsPrecachedSound(), m_pSfx, &m_nCachedDataSize );
if ( !info )
{
Assert( !"CAudioSourceMP3::GetCachedDataPointer info == NULL" );
return NULL;
}
return (byte *)info->CachedData();
}
CAudioSourceCachedInfoHandle_t m_AudioCacheHandle;
int m_nCachedDataSize;
protected:
bool GetStartupData();
CSfxTable *m_pSfx;
int m_sampleRate;
int m_dataSize;
int m_dataStart;
int m_refCount;
bool m_bIsPlayOnce : 1;
bool m_bIsSentenceWord : 1;
};
//-----------------------------------------------------------------------------
// Purpose: Streaming MP3 file
//-----------------------------------------------------------------------------
class CAudioSourceStreamMP3 : public CAudioSourceMP3, public IWaveStreamSource
{
public:
CAudioSourceStreamMP3( CSfxTable *pSfx );
CAudioSourceStreamMP3( CSfxTable *pSfx, CAudioSourceCachedInfo *info );
~CAudioSourceStreamMP3() {}
bool IsStreaming( void ) { return true; }
bool IsStereoWav(void) { return false; }
CAudioMixer *CreateMixer(int initialStreamPosition, int skipInitialSamples, bool bUpdateDelayForChoreo, SoundError &soundError, struct hrtf_info_t* pHRTFVec);
int GetOutputData( void **pData, int64 samplePosition, int sampleCount, char copyBuf[AUDIOSOURCE_COPYBUF_SIZE] );
// IWaveStreamSource
virtual int64 UpdateLoopingSamplePosition( int64 samplePosition )
{
return samplePosition;
}
virtual void UpdateSamples( char *pData, int sampleCount ) {}
virtual int GetLoopingInfo( int *pLoopBlock, int *pNumLeadingSamples, int *pNumTrailingSamples )
{
return 0;
}
virtual void Prefetch();
private:
CAudioSourceStreamMP3( const CAudioSourceStreamMP3 & ); // not implemented, not accessible
};
class CAudioSourceMP3Cache : public CAudioSourceMP3
{
public:
CAudioSourceMP3Cache( CSfxTable *pSfx );
CAudioSourceMP3Cache( CSfxTable *pSfx, CAudioSourceCachedInfo *info );
~CAudioSourceMP3Cache( void );
int GetCacheStatus( void );
void CacheLoad( void );
void CacheUnload( void );
// NOTE: "samples" are bytes for MP3
int GetOutputData( void **pData, int64 samplePosition, int sampleCount, char copyBuf[AUDIOSOURCE_COPYBUF_SIZE] );
CAudioMixer *CreateMixer( int initialStreamPosition, int skipInitialSamples, bool bUpdateDelayForChoreo, SoundError &soundError, struct hrtf_info_t* pHRTFVec );
virtual void Prefetch() {}
protected:
virtual char *GetDataPointer( void );
WaveCacheHandle_t m_hCache;
private:
CAudioSourceMP3Cache( const CAudioSourceMP3Cache & );
};
bool Audio_IsMP3( const char *pName );
CAudioSource *Audio_CreateStreamedMP3( CSfxTable *pSfx );
CAudioSource *Audio_CreateMemoryMP3( CSfxTable *pSfx );
CAudioMixer *CreateMP3Mixer( IWaveData *data, int *pSampleRate );
#endif // SND_MP3_SOURCE_H
@@ -0,0 +1,220 @@
//============ Copyright (c) Valve Corporation, All rights reserved. ============
//
//
//
//===============================================================================
#include "audio_pch.h"
#include "sos_system.h"
#include "sos_entry_match_system.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
extern ConVar snd_sos_show_block_debug;
ConVar snd_sos_show_entry_match_free( "snd_sos_show_entry_match_free", "0" );
//-----------------------------------------------------------------------------
// CSosEntryMatch
//-----------------------------------------------------------------------------
bool CSosEntryMatch::IsAMatch( CSosEntryMatch *pEntryMatch )
{
bool bMatchString1 = true;
bool bMatchString2 = true;
bool bMatchInt1 = true;
bool bMatchInt2 = true;
bool bMatchInt3 = true;
if ( m_bMatchString1 )
{
if( m_bMatchSubString )
{
if ( V_stristr( pEntryMatch->m_nMatchString1, m_nMatchString1 ) == NULL )
{
bMatchString1 = false;
}
}
else
{
// optimize to be scripthandle
if ( V_stricmp( pEntryMatch->m_nMatchString1, m_nMatchString1 ) )
{
bMatchString1 = false;
}
}
}
if ( m_bMatchString2 )
{
if ( m_bMatchSubString )
{
if ( V_stristr( pEntryMatch->m_nMatchString2, m_nMatchString2 ) == NULL )
{
bMatchString2 = false;
}
}
else
{
// optimize to be scripthandle
if ( V_stricmp( pEntryMatch->m_nMatchString2, m_nMatchString2 ) )
{
bMatchString2 = false;
}
}
}
if ( m_bMatchInt1 )
{
if ( pEntryMatch->m_nMatchInt1 != m_nMatchInt1 )
{
bMatchInt1 = false;
}
}
if ( m_bMatchInt2 )
{
if ( pEntryMatch->m_nMatchInt2 != m_nMatchInt2 )
{
bMatchInt2 = false;
}
}
if ( m_bMatchInt3 )
{
if ( pEntryMatch->m_nMatchInt3 != m_nMatchInt3 )
{
bMatchInt3 = false;
}
}
if ( ( ( bMatchString1 && m_bMatchString1 ) || !m_bMatchString1 ) &&
( ( bMatchString2 && m_bMatchString2 ) || !m_bMatchString2 )&&
( ( bMatchInt1 && m_bMatchInt1 ) || !m_bMatchInt1 ) &&
( ( bMatchInt2 && m_bMatchInt2 ) || !m_bMatchInt2 ) &&
( ( bMatchInt3 && m_bMatchInt3 ) || !m_bMatchInt3 ) )
{
return true;
}
return false;
}
//-----------------------------------------------------------------------------
// CSosEntryMatchList
//-----------------------------------------------------------------------------
void CSosEntryMatchList::Update()
{
uint32 bit = 1;
for ( int i = 0; i < SOS_BLOCKSYS_MAX_ENTRIES; i++, ( bit <<= 1 ) )
{
if ( !( m_Free & bit ) )
{
Assert( !m_vEntryMatchList[i]->m_bFree );
if( m_vEntryMatchList[i]->m_bTimed )
{
if ( m_vEntryMatchList[i]->m_flDuration > -1.0 && m_vEntryMatchList[i]->m_flStartTime > -1.0 )
{
float flCurTime = g_pSoundServices->GetClientTime();
if ( ( m_vEntryMatchList[i]->m_flDuration + m_vEntryMatchList[i]->m_flStartTime ) <= flCurTime )
{
if( snd_sos_show_entry_match_free.GetInt() )
{
Log_Msg( LOG_SOUND_OPERATOR_SYSTEM, StackColor, "\nFREEING MATCH ENTRY:\n");
m_vEntryMatchList[i]->Print();
}
m_vEntryMatchList[i]->Reset();
m_Free |= bit;
}
}
else
{
if( snd_sos_show_entry_match_free.GetInt() )
{
Log_Msg( LOG_SOUND_OPERATOR_SYSTEM, StackColor, "\nFREEING MATCH ENTRY:\n");
m_vEntryMatchList[i]->Print();
}
m_vEntryMatchList[i]->Reset();
m_Free |= bit;
}
}
if( snd_sos_show_block_debug.GetInt() )
{
m_vEntryMatchList[i]->Print();
}
}
}
}
int CSosEntryMatchList::GetFreeEntryIndex() const
{
uint32 bit = 1;
for( int i = 0; i < SOS_BLOCKSYS_MAX_ENTRIES; i++, ( bit <<= 1 ) )
{
if ( m_vEntryMatchList[i]->m_bFree )
{
Assert( m_Free & bit );
m_vEntryMatchList[i]->m_bFree = false;
m_Free &= ~bit;
return i;
}
}
return -1;
}
CSosManagedEntryMatch *CSosEntryMatchList::GetEntryFromIndex( int nIndex ) const
{
Assert( IsValidIndex( nIndex ) );
if ( IsValidIndex( nIndex ) )
{
return m_vEntryMatchList[ nIndex ];
}
else
{
return NULL;
}
}
CSosManagedEntryMatch *CSosEntryMatchList::GetFreeEntry( int &nIndex ) const
{
int nMatchEntryIndex = g_pSoundOperatorSystem->m_sosEntryBlockList.GetFreeEntryIndex();
CSosManagedEntryMatch *pSosEntryMatch = g_pSoundOperatorSystem->m_sosEntryBlockList.GetEntryFromIndex( nMatchEntryIndex );
if ( !pSosEntryMatch )
{
Log_Warning( LOG_SND_OPERATORS, "Error: EntryMatchList has no free slots!\n" );
nIndex = -1;
return NULL;
}
return pSosEntryMatch;
}
void CSosEntryMatchList::FreeEntry( int nIndex, bool bForce /* = false */ )
{
if ( !m_vEntryMatchList[ nIndex ]->m_bTimed || bForce )
{
m_vEntryMatchList[ nIndex ]->Reset();
m_Free |= GetBitForBitnum( nIndex );
}
}
bool CSosEntryMatchList::HasAMatch( CSosEntryMatch *pEntryMatch ) const
{
uint32 bit = 1;
for( int i = 0; i < SOS_BLOCKSYS_MAX_ENTRIES; i++, (bit <<= 1) )
{
if ( !( m_Free & bit ) && m_vEntryMatchList[i]->m_bActive )
{
Assert( !m_vEntryMatchList[i]->m_bFree );
if ( m_vEntryMatchList[i]->IsAMatch( pEntryMatch ) )
{
return true;
}
}
}
return false;
}
void CSosEntryMatchList::Print() const
{
Log_Msg( LOG_SOUND_OPERATOR_SYSTEM, StackColor, "\nCUE Operators:\n");
}
@@ -0,0 +1,169 @@
//============ Copyright (c) Valve Corporation, All rights reserved. ============
//
//
//
//===============================================================================
#ifndef SOS_ENTRY_MATCH_SYSTEM_H
#define SOS_ENTRY_MATCH_SYSTEM_H
#ifdef _WIN32
#pragma once
#endif
#include "bitvec.h"
//#include "snd_channels.h"
// Externs the logging channel
DECLARE_LOGGING_CHANNEL( LOG_SND_OPERATORS );
extern Color StackColor;
//-----------------------------------------------------------------------------
//
// Match Entry system
//
//-----------------------------------------------------------------------------
class CSosEntryMatch
{
public:
CSosEntryMatch()
{
Reset();
}
void Reset()
{
m_nMatchString1[0] = '\n';
m_bMatchString1 = false;
m_nMatchString2[0] = '\n';
m_bMatchString2 = false;
m_bMatchSubString = false;
m_nMatchInt1 = -1;
m_bMatchInt1 = false;
m_nMatchInt2 = -1;
m_bMatchInt2 = false;
m_nMatchInt3 = -1;
m_bMatchInt3 = false;
}
bool IsAMatch( CSosEntryMatch *pEntryMatch );
public:
char m_nMatchString1[64];
bool m_bMatchString1;
char m_nMatchString2[64];
bool m_bMatchString2;
bool m_bMatchSubString;
int m_nMatchInt1;
bool m_bMatchInt1;
int m_nMatchInt2;
bool m_bMatchInt2;
int m_nMatchInt3;
bool m_bMatchInt3;
};
class CSosEntryMatchList;
class CSosManagedEntryMatch : public CSosEntryMatch
{
friend class CSosEntryMatchList;
void Reset()
{
CSosEntryMatch::Reset();
m_bActive = false;
m_bTimed = false;
m_flStartTime = -1.0;
m_flDuration = -1.0;
m_bFree = true;
}
public:
void Start()
{
m_flStartTime = g_pSoundServices->GetClientTime();
}
private:
void Print()
{
Log_Msg( LOG_SOUND_OPERATOR_SYSTEM, StackColor, "Match String 1: %s\n", m_nMatchString1 );
Log_Msg( LOG_SOUND_OPERATOR_SYSTEM, StackColor, "Match String 1?: %s\n", m_bMatchString1 ? "true" : "false" );
Log_Msg( LOG_SOUND_OPERATOR_SYSTEM, StackColor, "Match String 2: %s\n", m_nMatchString2 );
Log_Msg( LOG_SOUND_OPERATOR_SYSTEM, StackColor, "Match String 2?: %s\n", m_bMatchString2 ? "true" : "false" );
Log_Msg( LOG_SOUND_OPERATOR_SYSTEM, StackColor, "Match SubString ?: %s\n", m_bMatchSubString ? "true" : "false" );
Log_Msg( LOG_SOUND_OPERATOR_SYSTEM, StackColor, "Match Int 1: %i\n", m_nMatchInt1 );
Log_Msg( LOG_SOUND_OPERATOR_SYSTEM, StackColor, "Match Int 1?: %s\n", m_bMatchInt1 ? "true" : "false" );
Log_Msg( LOG_SOUND_OPERATOR_SYSTEM, StackColor, "Match Int 2: %i\n", m_nMatchInt2 );
Log_Msg( LOG_SOUND_OPERATOR_SYSTEM, StackColor, "Match Int 2?: %s\n", m_bMatchInt2 ? "true" : "false" );
Log_Msg( LOG_SOUND_OPERATOR_SYSTEM, StackColor, "Match Int 3: %i\n", m_nMatchInt3 );
Log_Msg( LOG_SOUND_OPERATOR_SYSTEM, StackColor, "Match Int 3?: %s\n", m_bMatchInt3 ? "true" : "false" );
Log_Msg( LOG_SOUND_OPERATOR_SYSTEM, StackColor, "Timed ?: %s\n", m_bTimed ? "true" : "false" );
Log_Msg( LOG_SOUND_OPERATOR_SYSTEM, StackColor, "Duration: %f\n", m_flDuration );
Log_Msg( LOG_SOUND_OPERATOR_SYSTEM, StackColor, "StartTime: %f\n", m_flStartTime );
Log_Msg( LOG_SOUND_OPERATOR_SYSTEM, StackColor, "StopTime: %f\n", m_flStartTime + m_flDuration );
Log_Msg( LOG_SOUND_OPERATOR_SYSTEM, StackColor, "CurTime: %f\n", g_pSoundServices->GetClientTime() );
Log_Msg( LOG_SOUND_OPERATOR_SYSTEM, StackColor, "Active ?: %s\n", m_bActive ? "true" : "false" );
Log_Msg( LOG_SOUND_OPERATOR_SYSTEM, StackColor, "Free ?: %s\n", m_bFree ? "true" : "false" );
}
bool m_bFree;
public:
bool m_bActive;
bool m_bTimed;
float m_flStartTime;
float m_flDuration;
};
#define SOS_BLOCKSYS_MAX_ENTRIES 32
class CSosEntryMatchList
{
public:
~CSosEntryMatchList()
{
for( int i = 0; i < SOS_BLOCKSYS_MAX_ENTRIES; i++ )
{
delete m_vEntryMatchList[i];
m_vEntryMatchList[i] = NULL;
}
}
CSosEntryMatchList()
{
uint32 bit = 1;
for( int i = 0; i < SOS_BLOCKSYS_MAX_ENTRIES; i++, ( bit <<= 1 ) )
{
m_vEntryMatchList[i] = new CSosManagedEntryMatch;
m_vEntryMatchList[i]->Reset();
m_Free |= bit;
}
}
void Update();
inline void Start( int nIndex ) { m_vEntryMatchList[ nIndex ]->Start(); }
inline bool IsValidIndex( int nIndex ) const { return nIndex > -1 && nIndex < SOS_BLOCKSYS_MAX_ENTRIES; }
int GetFreeEntryIndex() const;
CSosManagedEntryMatch *GetEntryFromIndex( int nIndex ) const ;
CSosManagedEntryMatch *GetFreeEntry( int &nIndex ) const ;
void FreeEntry( int nIndex, bool bForce = false );
bool HasAMatch( CSosEntryMatch *pEntryMatch ) const;
void Print() const;
protected:
mutable uint32 m_Free;
CSosManagedEntryMatch *m_vEntryMatchList[ SOS_BLOCKSYS_MAX_ENTRIES ];
};
#endif // SOS_ENTRY_MATCH_SYSTEM_H
+441
View File
@@ -0,0 +1,441 @@
//============ Copyright (c) Valve Corporation, All rights reserved. ============
//
//
//===============================================================================
#include "audio_pch.h"
#include "tier2/interval.h"
#include "sos_op.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
extern ConVar snd_sos_show_operator_init;
extern ConVar snd_sos_show_operator_shutdown;
BEGIN_DEFINE_LOGGING_CHANNEL( LOG_SND_OPERATORS, "SndOperators", LCF_CONSOLE_ONLY, LS_MESSAGE );
ADD_LOGGING_CHANNEL_TAG( "SndOperators" );
ADD_LOGGING_CHANNEL_TAG( "SND" );
END_DEFINE_LOGGING_CHANNEL();
Color OpNameColor( 185, 215, 255, 255 );
Color OpColor( 185, 185, 255, 255 );
Color ConnectColor( 255, 185, 255, 255 );
Color NotExecuteColor( 255, 0, 0, 255 );
Color ResultColor( 255, 185, 185, 255 );
int foo;
void S_GetFloatFromString( float *pFlVector, const char *pString, int nSize = 3 )
{
char tempString[128];
Q_strncpy( tempString, pString, sizeof(tempString) );
int i = 0;
char *token = strtok( tempString, "," );
while( token )
{
*pFlVector = atof( token );
token = strtok( NULL, "," );
i++;
if ( i >= nSize )
{
break;
}
pFlVector++;
}
}
//-----------------------------------------------------------------------------
// CSosOperator
// Operator base class
//-----------------------------------------------------------------------------
CSosOperator::CSosOperator( )
{
SOS_REGISTER_INPUT_FLOAT( CSosOperator, m_flExecute, SO_SINGLE, "input_execute" )
}
void CSosOperator::SetBaseDefaults( void *pVoidMem ) const
{
CSosOperator_t *pStructMem = (CSosOperator_t *)pVoidMem;
SOS_INIT_INPUT_VAR( m_flExecute, SO_SINGLE, 1.0 )
pStructMem->m_bExecuteOnce = false;
pStructMem->m_bHasExecuted = false;
}
void CSosOperator::PrintIO( CSosOperator_t *pStructMem, CSosOperatorStack *pStack, int nLevel ) const
{
int nNumberOfInputs = m_vInputs.Count();
for(int i = 0; i < nNumberOfInputs; i++ )
{
const InputData_t & inputData = m_vInputs[i];
const char *pInputName = m_vInputMap.GetElementName( i );
Log_Msg( LOG_SND_OPERATORS, OpColor , "%*s%s: ", nLevel, " ", pInputName );
int nConnections[8];
int nNumConnections = 0;
char *pInputValue = (char *)pStructMem + inputData.m_nValueOffset;
char *pOffsetOffset = (char *)pStructMem + inputData.m_nOffsetOffset;
bool bAnyConnected = false;
for( int j = 0; j < inputData.m_nCount; j++ )
{
int nOffsetValue = *((int *)pOffsetOffset + j );
bool bIsConnected = nOffsetValue < 0 ? false : true ;
bAnyConnected |= bIsConnected;
if( bIsConnected )
{
nConnections[ nNumConnections ] = nOffsetValue;
nNumConnections++;
}
else
{
nConnections[ nNumConnections ] = -1;
nNumConnections++;
}
Color connectedColor = bIsConnected ? ConnectColor : OpColor;
switch( inputData.m_Type )
{
case SO_FLOAT:
Log_Msg( LOG_SND_OPERATORS, connectedColor, "%f ", *((float *)pInputValue+j) );
break;
default:
Log_Msg( LOG_SND_OPERATORS, connectedColor, " UNKNOWN DATA TYPE %i ", inputData.m_Type );
break;
}
}
if( bAnyConnected )
{
int nOpIndex = pStack->FindOperatorViaOffset( nConnections[0] );
Log_Msg( LOG_SND_OPERATORS, ConnectColor, "%%(connected: %s", pStack->GetOperatorName( nOpIndex ) );
if( nNumConnections > 0 )
{
for( int k = 0; k < nNumConnections; k++ )
{
Log_Msg( LOG_SND_OPERATORS, ConnectColor, " %i", nConnections[k] );
}
}
Log_Msg( LOG_SND_OPERATORS, ConnectColor, ")");
}
Log_Msg( LOG_SND_OPERATORS, ConnectColor, "\n");
}
int nNumberOfOutputs = m_vOutputs.Count();
for(int i = 0; i < nNumberOfOutputs; i++ )
{
const OutputData_t & outputData = m_vOutputs[i];
const char *pOutputName = m_vOutputMap.GetElementName( i );
Log_Msg( LOG_SND_OPERATORS, OpColor, "%*s%s: ", nLevel, " ", pOutputName );
char *pOutput = (char *)pStructMem + outputData.m_nValueOffset;
for( int j = 0; j < outputData.m_nCount; j++ )
{
switch( outputData.m_Type )
{
case SO_FLOAT:
Log_Msg( LOG_SND_OPERATORS, OpColor, "%f ", *((float *)pOutput+j) );
break;
default:
Log_Msg( LOG_SND_OPERATORS, OpColor, " UNKNOWN DATA TYPE %i ", outputData.m_Type );
break;
}
}
Log_Msg( LOG_SND_OPERATORS, OpColor, "\n" );
}
}
void CSosOperator::PrintBaseParams( void *pVoidMem, CSosOperatorStack *pStack, int nOpIndex, int nLevel ) const
{
CSosOperator_t *pStructMem = (CSosOperator_t *)pVoidMem;
const char *pName = pStack->GetOperatorName( nOpIndex );
Color executeColor = ( ( pStructMem->m_flExecute[0] > 0.0 ) && !( pStructMem->m_bExecuteOnce && pStructMem->m_bHasExecuted ) ) ? OpNameColor : NotExecuteColor;
Log_Msg( LOG_SND_OPERATORS, executeColor, "\n%*sName: %s\n", nLevel, " ", pName );
Log_Msg( LOG_SND_OPERATORS, OpColor, "\n%*sExecute Once: %s\n", nLevel, " ", pStructMem->m_bExecuteOnce ? "true" : "false" );
PrintIO( pStructMem, pStack, nLevel );
}
int CSosOperator::ParseValueRef( CSosOperatorStack *pStack, const char *pParamString, const char *pValueString ) const
{
if ( pValueString[0] == VALUE_REF_CHAR )
{
pValueString++;
char tempString[64];
Q_strncpy( tempString, pValueString, sizeof(tempString) );
char *pOpname = strtok( tempString, "." );
char *pOutputName = strtok( NULL, "");
int nOutOffset = pStack->GetOperatorOutputOffset( pOpname, pOutputName );
if ( nOutOffset < 0 )
{
return -1;
}
int nOutIndex = BaseParseHasArrayIndice( pOutputName );
if ( nOutIndex > -1 )
{
nOutOffset += nOutIndex;
}
return nOutOffset;
}
return -1;
}
int CSosOperator::BaseParseHasArrayIndice( const char *pParamString ) const
{
int nInputIndex = -1;
char tempString[64];
Q_strncpy( tempString, pParamString, sizeof(tempString) );
// char *pInputParamString = strtok( tempString, "[" );
char *pIndexString = strtok( NULL, "]");
if ( pIndexString && *pIndexString )
{
nInputIndex = Q_atoi( pIndexString );
}
return nInputIndex;
}
bool CSosOperator::BaseParseKV( CSosOperatorStack *pStack, CSosOperator_t *pStructMem, const char *pParamString, const char *pValueString ) const
{
// if we succeed in finding the specified parameter we return true otw false
if ( pParamString && *pParamString && pValueString && *pValueString )
{
// check for simple global params
if ( !V_strcasecmp( pParamString, "operator" ) )
{
return true;
}
else if ( !V_strcasecmp( pParamString, "execute_once" ) )
{
if ( !V_strcasecmp( pValueString, "true" ) )
{
pStructMem->m_bExecuteOnce = true;
}
else
{
pStructMem->m_bExecuteOnce = false;
}
return true;
}
// is this accessing into the array?
// "parse" it, UGLY, CLEAN IT... move it to "HasIndice"
// int nInputIndex = BaseParseHasArrayIndice( pParamString );
int nInputIndex = -1;
char tempString[64];
Q_strncpy( tempString, pParamString, sizeof(tempString) );
char *pInputParamString = strtok( tempString, "[" );
char *pIndexString = strtok( NULL, "]");
bool bFillInputArray = false;
if ( pIndexString && *pIndexString )
{
if ( pIndexString[0] == '*' )
{
bFillInputArray = true;
}
else
{
nInputIndex = Q_atoi( pIndexString );
}
}
// find the input
int nInputParamIndex = m_vInputMap.Find( pInputParamString );
if ( ! m_vInputs.IsValidIndex( nInputParamIndex ) )
{
// Log_Warning( LOG_SND_OPERATORS, "Error: Unable to find input parameter %s", pParamString );
return false;
}
const InputData_t & inputData = m_vInputs[ nInputParamIndex ];
short nCount = inputData.m_nCount;
// gotta put some kind of type matching test in here!
// SODataType_t nType = m_vInputType[ nInputParamIndex ];
int nOffsetOffset = inputData.m_nOffsetOffset;
int nOutputOffset = ParseValueRef( pStack, pParamString, pValueString );
if ( nOutputOffset > -1 )
{
if ( nInputIndex > -1 )
{
if ( nInputIndex < nCount )
{
*((int *)((char *)pStructMem + nOffsetOffset) + nInputIndex) = nOutputOffset;
}
else
{
Log_Warning( LOG_SND_OPERATORS, "Error: Operator %s, illegal array access: %s", pStack->m_pCurrentOperatorName, pParamString );
}
return true;
}
else
{
for ( int i = 0; i < nCount; i++ )
{
if ( bFillInputArray )
{
*((int *)((char *)pStructMem + nOffsetOffset) + i) = nOutputOffset;
}
else
{
*((int *)((char *)pStructMem + nOffsetOffset) + i) = ( nOutputOffset + (sizeof(float)*i) );
}
}
}
return true;
}
else
{
// if an input is explicit, fill array with single value
int nInputOffset = inputData.m_nValueOffset;
float flValue = RandomInterval( ReadInterval( pValueString ) );
//S_GetFloatFromString( &flValue, pValueString );
if ( nInputIndex > -1 )
{
if ( nInputIndex < nCount )
{
*((float *)( (char *)pStructMem + nInputOffset ) + nInputIndex ) = flValue;
// clear potential previous connections
*((int *)((char *)pStructMem + nOffsetOffset) + nInputIndex) = -1;
}
else
{
//error
return true;
}
}
else
{
for ( int i = 0; i < nCount; i++ )
{
*((float *)( (char *)pStructMem + nInputOffset ) + i )= flValue;
// clear potential previous connections
*((int *)((char *)pStructMem + nOffsetOffset) + i) = nOutputOffset;
}
}
return true;
}
}
return false;
}
int CSosOperator::GetOutputOffset( const char *pOutputName ) const
{
int nIndex = m_vOutputMap.Find( pOutputName );
if ( !m_vOutputs.IsValidIndex( nIndex ) )
{
Log_Warning( LOG_SND_OPERATORS, "Error: Unable to find referenced sound operator output: %s", pOutputName );
return -1;
}
return m_vOutputs[ nIndex ].m_nValueOffset;
}
void CSosOperator::ResolveInputValue( void *pInputDefault, int *pOffsetArray, short nDataCount, SODataType_t nDataType, void *pStackMem ) const
{
size_t nDataSize = 0;
switch( nDataType )
{
case SO_FLOAT:
nDataSize = sizeof( float );
break;
default:
break;
}
for ( int i = 0; i < nDataCount; i++ )
{
int nOffset = *( pOffsetArray + i );
void *pSrc = NULL;
if ( nOffset > -1 )
{
// pSrc = (float *)( (char *)pStackMem + nOffset );
pSrc = ( void *)( (char *)pStackMem + nOffset );
Q_memcpy( ( void *) ( (char *) pInputDefault + ( i * nDataSize ) ) , pSrc, nDataSize );
}
// else
// {
// // copying from itself to itself?
// pSrc = ( void *) ( (char *) pInputDefault + ( i * nDataSize ) );
// }
//
//
// Q_memcpy( pInputDefault[i] , pSrc, nDataSize );
// pInputDefault[i] = *pSrc;
}
}
void CSosOperator::ResolveInputValues( void *pStructMem, void *pStackMem ) const
{
for ( unsigned int i = 0; i < m_vInputMap.Count(); i++ )
{
int nInputIndex = m_vInputMap[ i ];
const InputData_t & inputData = m_vInputs[ nInputIndex ];
SODataType_t nDataType = inputData.m_Type;
short nDataCount = inputData.m_nCount;
size_t nOffset = inputData.m_nValueOffset;
int nOffsetOffset = inputData.m_nOffsetOffset;
void *pInput = (void *)( (char *)pStructMem + nOffset );
int *pOffset = (int *)( (char *)pStructMem + nOffsetOffset );
ResolveInputValue( pInput, pOffset, nDataCount, nDataType, pStackMem );
}
}
void CSosOperator::OffsetConnections( void *pVoidMem, size_t nOffset ) const
{
// point offsets to a different memory segment
for ( unsigned int i = 0; i < m_vInputMap.Count(); i++ )
{
int nInputIndex = m_vInputMap[ i ];
const InputData_t & inputData = m_vInputs[ nInputIndex ];
// SODataType_t nDataType = inputData.m_Type;
short nDataCount = inputData.m_nCount;
int nOffsetOffset = m_vInputs[ nInputIndex ].m_nOffsetOffset;
int *pOffset = (int *)( (char *)pVoidMem + nOffsetOffset );
for( int j = 0; j < nDataCount; j++ )
{
if ( *(pOffset + j) > -1 )
{
*(pOffset + j) += nOffset;
}
}
}
}
void CSosOperator::StackInit( void *pVoidMem, CSosOperatorStack *pStack, int nOpIndex )
{
}
void CSosOperator::StackShutdown( void *pVoidMem, CSosOperatorStack *pStack, int nOpIndex )
{
if ( snd_sos_show_operator_shutdown.GetInt() )
{
Log_Msg( LOG_SND_OPERATORS, OpColor, "Stack Shutdown: Stack: %s : Operator: %s\n", pStack->GetName(), pStack->GetOperatorName( nOpIndex ) );
}
}
+170
View File
@@ -0,0 +1,170 @@
//============ Copyright (c) Valve Corporation, All rights reserved. ============
//
//
//
//===============================================================================
#ifndef SOS_OP_H
#define SOS_OP_H
#ifdef _WIN32
#pragma once
#endif
#include "sos_system.h"
#include "snd_channels.h"
// Externs the logging channel
DECLARE_LOGGING_CHANNEL( LOG_SND_OPERATORS );
#define THREAD_LOCK_SOUND() AUTO_LOCK( g_SndMutex )
#define VALUE_REF_CHAR '@'
#define CLOSE_SQ_BRACKET ']'
#define SOS_INPUT_FLOAT( memberName, memberCount ) \
float memberName[memberCount]; \
int memberName##Offset[memberCount];
#define SOS_OUTPUT_FLOAT( memberName, memberCount ) \
float memberName[memberCount];
#define SOS_INIT_INPUT_VAR( memberName, memberCount, value ) \
for( int i = 0; i < memberCount; i++ ) \
{ pStructMem->memberName[i] = value; pStructMem->memberName##Offset[i] = -1; }
#define SOS_INIT_OUTPUT_VAR( memberName, memberType, value ) \
for( int i = 0; i < memberType; i++ ) \
{ pStructMem->memberName[i] = value; }
#define SOS_REGISTER_INPUT( className, memberName, memberCount, memberString, type ) \
{ \
InputData_t inputData; \
inputData.m_nValueOffset = offsetof( className##_t, memberName ); \
inputData.m_nOffsetOffset = offsetof( className##_t, memberName##Offset ); \
inputData.m_Type = type; \
inputData.m_nCount = memberCount; \
int nIndex = m_vInputs.AddToTail( inputData ); \
m_vInputMap.Insert( memberString, nIndex ); \
}
#define SOS_REGISTER_INPUT_FLOAT( className, memberName, memberCount, memberString ) \
SOS_REGISTER_INPUT( className, memberName, memberCount, memberString, SO_FLOAT )
#define SOS_REGISTER_OUTPUT( className, memberName, memberCount, memberString, type ) \
{ \
OutputData_t outputData; \
outputData.m_nValueOffset = offsetof( className##_t, memberName ); \
outputData.m_Type = type; \
outputData.m_nCount = memberCount; \
int nIndex = m_vOutputs.AddToTail( outputData ); \
m_vOutputMap.Insert( memberString, nIndex ); \
}
#define SOS_REGISTER_OUTPUT_FLOAT( className, memberName, memberCount, memberString ) \
SOS_REGISTER_OUTPUT( className, memberName, memberCount, memberString, SO_FLOAT )
#define SOS_BEGIN_OPERATOR_CONSTRUCTOR( classname, operatorstring ) \
classname::classname() \
{
#define SOS_END_OPERATOR_CONSTRUCTOR( classname, operatorstring ) \
g_pSoundOperatorSystem->m_vOperatorCollection.Insert(operatorstring, this ); \
} \
classname g_##classname;
#define SOS_HEADER_DESC( classname ) \
public: \
classname(); \
virtual void SetDefaults( void *pVoidMem ) const ; \
virtual size_t GetSize() const { return sizeof( classname##_t ); } \
virtual void Execute( void *pVoidMem, channel_t *pChannel, CScratchPad *pScratchPad, CSosOperatorStack *pStack, int nOpIndex ) const ; \
virtual void Print( void *pVoidMem, CSosOperatorStack *pStack, int nOpIndex, int nLevel ) const ; \
virtual void OpHelp( ) const ; \
virtual void ParseKV( CSosOperatorStack *pStack, void *pVoidMem, KeyValues *pParamKV ) const ; \
//-----------------------------------------------------------------------------
// The CSosOperator class:
//
// Base class for all sound operators, each operator must override "execute"
//
//-----------------------------------------------------------------------------
struct CSosOperator_t
{
SOS_INPUT_FLOAT( m_flExecute, SO_SINGLE )
bool m_bExecuteOnce;
bool m_bHasExecuted;
};
class CSosOperator
{
public:
CSosOperator();
virtual ~CSosOperator() { } ;
int GetOutputOffset( const char *pOutputName ) const;
// Proposal to optimize this:
// For each InputData_t, we store a function pointer to handle the resolution.
// We would create a different resolve function for the major cases (write a float, write 3 floats, generic case - same as current implementation).
// When filling the inputs initially, we would store the optimal function pointer.
// Cost: 4 bytes per InputData_t
// One dynamic call instead of one static call (currently ResolveInputValue).
// But then in most cases, the implementation would more efficient (estimated at 4 to 10 times faster).
void ResolveInputValue( void *pInputDefault, int *pOffsetArray, short nDataCount, SODataType_t nDataType, void *pStackMem ) const;
void ResolveInputValues( void *pStructMem, void *pStackMem ) const;
void OffsetConnections( void *pVoidMem, size_t nOffset ) const;
bool BaseParseKV( CSosOperatorStack *pStack, CSosOperator_t *pStructMem, const char *pParamString, const char *pValueString ) const;
int ParseValueRef( CSosOperatorStack *pStack, const char *pParamString, const char *pValueString ) const;
void PrintBaseParams( void *pVoidMem, CSosOperatorStack *pStack, int nOpIndex, int nLevel ) const;
void PrintIO( CSosOperator_t *pStructMem, CSosOperatorStack *pStack, int nLevel ) const;
int BaseParseHasArrayIndice( const char *pParamString ) const;
void SetBaseDefaults( void *pVoidMem ) const;
virtual void SetDefaults( void *pVoidMem ) const = 0;
virtual size_t GetSize() const = 0;
virtual void Execute( void *pVoidMem, channel_t *pChannel, CScratchPad *pScratchPad, CSosOperatorStack *pStack, int nOpIndex ) const = 0;
virtual void Print( void *pVoidMem, CSosOperatorStack *pStack, int nOpIndex, int nLevel ) const = 0;
virtual void OpHelp( ) const = 0;
virtual void ParseKV( CSosOperatorStack *pStack, void *pVoidMem, KeyValues *pParamKV ) const = 0;
virtual void StackInit( void *pVoidMem, CSosOperatorStack *pStack, int nOpIndex );
virtual void StackShutdown( void *pVoidMem, CSosOperatorStack *pStack, int nOpIndex );
protected:
public:
struct OutputData_t
{
size_t m_nValueOffset;
SODataType_t m_Type;
short m_nCount;
};
struct InputData_t
{
size_t m_nValueOffset;
size_t m_nOffsetOffset;
SODataType_t m_Type;
short m_nCount;
};
CUtlDict <int, int> m_vOutputMap;
CUtlVector < OutputData_t > m_vOutputs;
CUtlDict <int, int> m_vInputMap;
CUtlVector< InputData_t > m_vInputs;
};
#endif // SOS_OP_H
@@ -0,0 +1,215 @@
//============ Copyright (c) Valve Corporation, All rights reserved. ============
//
//
//===============================================================================
#include "audio_pch.h"
#include "tier2/interval.h"
#include "sos_op.h"
#include "sos_entry_match_system.h"
#include "sos_op_block_entry.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
extern Color OpColor;
extern Color ConnectColor;
extern Color ResultColor;
//-----------------------------------------------------------------------------
// CSosOperatorBlockEntry
//
//-----------------------------------------------------------------------------
SOS_BEGIN_OPERATOR_CONSTRUCTOR( CSosOperatorBlockEntry, "sys_block_entries" )
SOS_REGISTER_INPUT_FLOAT( CSosOperatorBlockEntry, m_flInputDuration, SO_SINGLE, "input_duration" )
SOS_REGISTER_INPUT_FLOAT( CSosOperatorBlockEntry, m_flInputActive, SO_SINGLE, "input_active" )
SOS_END_OPERATOR_CONSTRUCTOR( CSosOperatorBlockEntry, "sys_block_entries" )
void CSosOperatorBlockEntry::StackShutdown( void *pVoidMem, CSosOperatorStack *pStack, int nOpIndex )
{
CSosOperatorBlockEntry_t *pStructMem = (CSosOperatorBlockEntry_t *)pVoidMem;
if( pStructMem->m_nEntryIndex > -1 )
{
//g_pSoundOperatorSystem->m_sosEntryBlockList.FreeEntry( pStructMem->m_nEntryIndex );
}
}
void CSosOperatorBlockEntry::SetDefaults( void *pVoidMem ) const
{
CSosOperatorBlockEntry_t *pStructMem = (CSosOperatorBlockEntry_t *)pVoidMem;
V_strncpy( pStructMem->m_nMatchEntryName, "", sizeof(pStructMem->m_nMatchEntryName) );
V_strncpy( pStructMem->m_nMatchSoundName, "", sizeof(pStructMem->m_nMatchSoundName) );
pStructMem->m_bMatchEntry = false;
pStructMem->m_bMatchSound = false;
pStructMem->m_bMatchEntity = false;
pStructMem->m_bMatchChannel = false;
pStructMem->m_bMatchSubString = false;
pStructMem->m_nEntryIndex = -1;
SOS_INIT_INPUT_VAR( m_flInputDuration, SO_SINGLE, 0.0 )
SOS_INIT_INPUT_VAR( m_flInputActive, SO_SINGLE, 1.0 )
}
void CSosOperatorBlockEntry::Execute( void *pVoidMem, channel_t *pChannel, CScratchPad *pScratchPad, CSosOperatorStack *pStack, int nOpIndex ) const
{
// THREAD_LOCK_SOUND();
CSosOperatorBlockEntry_t *pStructMem = (CSosOperatorBlockEntry_t *)pVoidMem;
if( pStructMem->m_nEntryIndex < 0 )
{
int nMatchEntryIndex = g_pSoundOperatorSystem->m_sosEntryBlockList.GetFreeEntryIndex();
CSosManagedEntryMatch *pSosEntryMatch = g_pSoundOperatorSystem->m_sosEntryBlockList.GetEntryFromIndex( nMatchEntryIndex );
if( !pSosEntryMatch )
{
Log_Warning( LOG_SND_OPERATORS, "Error: Operator %s, EntryMatchList has no free slots!\n", pStack->GetOperatorName( nOpIndex ) );
return;
}
pStructMem->m_nEntryIndex = nMatchEntryIndex;
pSosEntryMatch->m_bMatchString1 = pStructMem->m_bMatchEntry;
V_strncpy( pSosEntryMatch->m_nMatchString1, pStructMem->m_nMatchEntryName, sizeof( pSosEntryMatch->m_nMatchString1 ) );
// pSosEntryMatch->m_bMatchString2 = pStructMem->m_bMatchSound;
// V_strncpy( pSosEntryMatch->m_nMatchString2, pStructMem->m_nMatchSoundName, sizeof( pSosEntryMatch->m_nMatchString2 ) );
pSosEntryMatch->m_bMatchSubString = pStructMem->m_bMatchSubString;
pSosEntryMatch->m_bMatchInt1 = pStructMem->m_bMatchChannel;
pSosEntryMatch->m_nMatchInt1 = pScratchPad->m_nChannel;
pSosEntryMatch->m_bMatchInt2 = pStructMem->m_bMatchEntity;
pSosEntryMatch->m_nMatchInt2 = pScratchPad->m_nSoundSource;
pSosEntryMatch->Start();
}
CSosManagedEntryMatch *pSosEntryMatch = g_pSoundOperatorSystem->m_sosEntryBlockList.GetEntryFromIndex( pStructMem->m_nEntryIndex );
if( pSosEntryMatch )
{
// defaults for now
pSosEntryMatch->m_bActive = pStructMem->m_flInputActive[0] > 0.0 ? true : false;
pSosEntryMatch->m_flDuration = pStructMem->m_flInputDuration[0] >= 0.0 ? pStructMem->m_flInputDuration[0] : 0.0;
//pSosEntryMatch->m_bTimed = pSosEntryMatch->m_flDuration > -1 ? true : false;
pSosEntryMatch->m_bTimed = true;
}
}
void CSosOperatorBlockEntry::Print( void *pVoidMem, CSosOperatorStack *pStack, int nOpIndex, int nLevel ) const
{
CSosOperatorBlockEntry_t *pStructMem = (CSosOperatorBlockEntry_t *)pVoidMem;
PrintBaseParams( pVoidMem, pStack, nOpIndex, nLevel );
// Log_Msg( LOG_SND_OPERATORS, OpColor, "%*sNumber Allowed: %i\n", nLevel, " ", pStructMem->m_nNumAllowed );
Log_Msg( LOG_SND_OPERATORS, OpColor, "%*smatch_entry: %s\n", nLevel, " ", pStructMem->m_bMatchEntry ? pStructMem->m_nMatchEntryName : "\"\"" );
Log_Msg( LOG_SND_OPERATORS, OpColor, "%*smatch_sound: %s\n", nLevel, " ", pStructMem->m_bMatchSound ? pStructMem->m_nMatchSoundName : "\"\"" );
Log_Msg( LOG_SND_OPERATORS, OpColor, "%*smatch_entity: %s\n", nLevel, " ", pStructMem->m_bMatchEntity ? "true" : "false" );
Log_Msg( LOG_SND_OPERATORS, OpColor, "%*smatch_channel: %s\n", nLevel, " ", pStructMem->m_bMatchEntity ? "true" : "false" );
Log_Msg( LOG_SND_OPERATORS, OpColor, "%*smatch_substring: %s\n", nLevel, " ", pStructMem->m_bMatchSubString ? "true" : "false" );
}
void CSosOperatorBlockEntry::OpHelp( ) const
{
}
void CSosOperatorBlockEntry::ParseKV( CSosOperatorStack *pStack, void *pVoidMem, KeyValues *pOpKeys ) const
{
CSosOperatorBlockEntry_t *pStructMem = (CSosOperatorBlockEntry_t *)pVoidMem;
KeyValues *pParams = pOpKeys->GetFirstSubKey();
while ( pParams )
{
const char *pParamString = pParams->GetName();
const char *pValueString = pParams->GetString();
if ( pParamString && *pParamString )
{
if ( pValueString && *pValueString )
{
if ( BaseParseKV( pStack, (CSosOperator_t *)pStructMem, pParamString, pValueString ) )
{
}
else if ( !V_strcasecmp( pParamString, "match_entry" ) )
{
pStructMem->m_bMatchEntry = true;
V_strncpy( pStructMem->m_nMatchEntryName, pValueString, sizeof(pStructMem->m_nMatchEntryName) );
}
// else if ( !V_strcasecmp( pParamString, "match_sound" ) )
// {
// pStructMem->m_bMatchSound = true;
// V_strncpy( pStructMem->m_nMatchSoundName, pValueString, sizeof(pStructMem->m_nMatchSoundName) );
// }
else if ( !V_strcasecmp( pParamString, "match_entity" ) )
{
if ( !V_strcasecmp( pValueString, "true" ) )
{
pStructMem->m_bMatchEntity = true;
}
else
{
pStructMem->m_bMatchEntity = false;
}
}
else if ( !V_strcasecmp( pParamString, "match_channel" ) )
{
if ( !V_strcasecmp( pValueString, "true" ) )
{
pStructMem->m_bMatchChannel = true;
}
else
{
pStructMem->m_bMatchChannel = false;
}
}
else if ( !V_strcasecmp( pParamString, "match_substring" ) )
{
if ( !V_strcasecmp( pValueString, "true" ) )
{
pStructMem->m_bMatchSubString = true;
}
else
{
pStructMem->m_bMatchSubString = false;
}
}
// else if ( !V_strcasecmp( pParamString, "stop_oldest" ) )
// {
// if ( !V_strcasecmp( pValueString, "true" ) )
// {
// pStructMem->m_bStopOldest = true;
// }
// else
// {
// pStructMem->m_bStopOldest = false;
// }
// }
// else if ( !V_strcasecmp( pParamString, "num_allowed" ) )
// {
// pStructMem->m_nNumAllowed = V_atoi( pValueString );
// }
else
{
Log_Warning( LOG_SND_OPERATORS, "Error: Operator %s, unknown sound operator attribute %s\n", pStack->m_pCurrentOperatorName, pParamString );
}
}
}
pParams = pParams->GetNextKey();
}
}
@@ -0,0 +1,43 @@
//============ Copyright (c) Valve Corporation, All rights reserved. ============
//
//
//
//===============================================================================
#ifndef SOS_OP_BLOCK_ENTRY_H
#define SOS_OP_BLOCK_ENTRY_H
#ifdef _WIN32
#pragma once
#endif
#include "sos_op.h"
//-----------------------------------------------------------------------------
// stop other sound entries
//-----------------------------------------------------------------------------
struct CSosOperatorBlockEntry_t : CSosOperator_t
{
SOS_INPUT_FLOAT( m_flInputActive, SO_SINGLE )
SOS_INPUT_FLOAT( m_flInputDuration, SO_SINGLE )
char m_nMatchEntryName[64];
bool m_bMatchEntry;
char m_nMatchSoundName[64];
bool m_bMatchSound;
bool m_bMatchSubString;
bool m_bMatchEntity;
bool m_bMatchChannel;
int m_nEntryIndex;
};
class CSosOperatorBlockEntry : public CSosOperator
{
virtual void StackShutdown( void *pVoidMem, CSosOperatorStack *pStack, int nOpIndex );
SOS_HEADER_DESC( CSosOperatorBlockEntry )
};
#endif // SOS_OP_BLOCK_ENTRY_H
@@ -0,0 +1,186 @@
//============ Copyright (c) Valve Corporation, All rights reserved. ============
//
//
//===============================================================================
#include "audio_pch.h"
#include "tier2/interval.h"
#include "sos_op.h"
#include "sos_op_convar.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
ConVar snd_op_test_convar("snd_op_test_convar", "1.0", FCVAR_CHEAT );
extern Color OpColor;
extern Color ConnectColor;
extern Color ResultColor;
//-----------------------------------------------------------------------------
// CSosOperatorSetConvar
//-----------------------------------------------------------------------------
SOS_BEGIN_OPERATOR_CONSTRUCTOR( CSosOperatorSetConvar, "set_convar" )
SOS_REGISTER_INPUT_FLOAT( CSosOperatorSetConvar, m_flInput, SO_SINGLE, "input" )
SOS_END_OPERATOR_CONSTRUCTOR( CSosOperatorSetConvar, "set_convar" )
void CSosOperatorSetConvar::SetDefaults( void *pVoidMem ) const
{
CSosOperatorSetConvar_t *pStructMem = (CSosOperatorSetConvar_t *)pVoidMem;
SOS_INIT_INPUT_VAR( m_flInput, SO_SINGLE, 0.0 )
}
void CSosOperatorSetConvar::Execute( void *pVoidMem, channel_t *pChannel, CScratchPad *pScratchPad, CSosOperatorStack *pStack, int nOpIndex ) const
{
CSosOperatorSetConvar_t *pStructMem = (CSosOperatorSetConvar_t *)pVoidMem;
if ( pStructMem->m_ConVarRef.IsValid() )
{
pStructMem->m_ConVarRef.SetValue( pStructMem->m_flInput[0] );
}
else
{
// The stored ref is not valid, maybe was not initialized at load time, let's try again
pStructMem->m_ConVarRef.Init( pStructMem->m_nConvar, true );
if ( pStructMem->m_ConVarRef.IsValid() )
{
pStructMem->m_ConVarRef.SetValue( pStructMem->m_flInput[0] ); // Great success! Will be cached for next time.
}
else
{
Log_Warning( LOG_SND_OPERATORS, "Warning: Unable to set convar value: %s\n", pStructMem->m_nConvar );
}
}
}
void CSosOperatorSetConvar::Print( void *pVoidMem, CSosOperatorStack *pStack, int nOpIndex, int nLevel ) const
{
CSosOperatorSetConvar_t *pStructMem = (CSosOperatorSetConvar_t *)pVoidMem;
PrintBaseParams( pVoidMem, pStack, nOpIndex, nLevel );
Log_Msg( LOG_SND_OPERATORS, OpColor, "%*sconvar: %s\n", nLevel, " ", pStructMem->m_nConvar );
}
void CSosOperatorSetConvar::OpHelp( ) const
{
}
void CSosOperatorSetConvar::ParseKV( CSosOperatorStack *pStack, void *pVoidMem, KeyValues *pOpKeys ) const
{
CSosOperatorSetConvar_t *pStructMem = (CSosOperatorSetConvar_t *)pVoidMem;
KeyValues *pParams = pOpKeys->GetFirstSubKey();
while ( pParams )
{
const char *pParamString = pParams->GetName();
const char *pValueString = pParams->GetString();
if ( pParamString && *pParamString )
{
if ( pValueString && *pValueString )
{
if ( BaseParseKV( pStack, (CSosOperator_t *)pStructMem, pParamString, pValueString ) )
{
}
else if ( !V_strcasecmp( pParamString, "convar" ) )
{
V_strcpy_safe( pStructMem->m_nConvar, pValueString );
pStructMem->m_ConVarRef.Init( pValueString, true );
}
else
{
Log_Warning( LOG_SND_OPERATORS, "Error: Operator %s, unknown sound operator attribute %s\n", pStack->m_pCurrentOperatorName, pParamString );
}
}
}
pParams = pParams->GetNextKey();
}
}
//-----------------------------------------------------------------------------
// CSosOperatorConvar
//-----------------------------------------------------------------------------
SOS_BEGIN_OPERATOR_CONSTRUCTOR( CSosOperatorConvar, "get_convar" )
SOS_REGISTER_OUTPUT_FLOAT( CSosOperatorConvar, m_flOutput, SO_SINGLE, "output" )
SOS_END_OPERATOR_CONSTRUCTOR( CSosOperatorConvar, "get_convar" )
void CSosOperatorConvar::SetDefaults( void *pVoidMem ) const
{
CSosOperatorConvar_t *pStructMem = (CSosOperatorConvar_t *)pVoidMem;
SOS_INIT_OUTPUT_VAR( m_flOutput, SO_SINGLE, 1.0 )
}
void CSosOperatorConvar::Execute( void *pVoidMem, channel_t *pChannel, CScratchPad *pScratchPad, CSosOperatorStack *pStack, int nOpIndex ) const
{
CSosOperatorConvar_t *pStructMem = (CSosOperatorConvar_t *)pVoidMem;
float flValue;
if ( pStructMem->m_ConVarRef.IsValid() )
{
flValue = pStructMem->m_ConVarRef.GetFloat();
}
else
{
// The stored ref is not valid, maybe was not initialized at load time, let's try again
pStructMem->m_ConVarRef.Init( pStructMem->m_nConvar, true );
if ( pStructMem->m_ConVarRef.IsValid() )
{
flValue = pStructMem->m_ConVarRef.GetFloat(); // Great success! Will be cached for next time.
}
else
{
Log_Warning( LOG_SND_OPERATORS, "Warning: Unable to acquire convar value: %s\n", pStructMem->m_nConvar );
flValue = 1.0;
}
}
pStructMem->m_flOutput[0] = flValue;
}
void CSosOperatorConvar::Print( void *pVoidMem, CSosOperatorStack *pStack, int nOpIndex, int nLevel ) const
{
CSosOperatorConvar_t *pStructMem = (CSosOperatorConvar_t *)pVoidMem;
PrintBaseParams( pVoidMem, pStack, nOpIndex, nLevel );
Log_Msg( LOG_SND_OPERATORS, OpColor, "%*sconvar: %s\n", nLevel, " ", pStructMem->m_nConvar );
}
void CSosOperatorConvar::OpHelp( ) const
{
}
void CSosOperatorConvar::ParseKV( CSosOperatorStack *pStack, void *pVoidMem, KeyValues *pOpKeys ) const
{
CSosOperatorConvar_t *pStructMem = (CSosOperatorConvar_t *)pVoidMem;
KeyValues *pParams = pOpKeys->GetFirstSubKey();
while ( pParams )
{
const char *pParamString = pParams->GetName();
const char *pValueString = pParams->GetString();
if ( pParamString && *pParamString )
{
if ( pValueString && *pValueString )
{
if ( BaseParseKV( pStack, (CSosOperator_t *)pStructMem, pParamString, pValueString ) )
{
}
else if ( !V_strcasecmp( pParamString, "convar" ) )
{
V_strcpy_safe( pStructMem->m_nConvar, pValueString );
pStructMem->m_ConVarRef.Init( pValueString, true );
}
else
{
Log_Warning( LOG_SND_OPERATORS, "Error: Operator %s, unknown sound operator attribute %s\n", pStack->m_pCurrentOperatorName, pParamString );
}
}
}
pParams = pParams->GetNextKey();
}
}
@@ -0,0 +1,64 @@
//============ Copyright (c) Valve Corporation, All rights reserved. ============
//
//
//
//===============================================================================
#ifndef SOS_OP_CONVAR_H
#define SOS_OP_CONVAR_H
#ifdef _WIN32
#pragma once
#endif
#include "sos_op.h"
#include "tier1/convar.h"
//-----------------------------------------------------------------------------
// simple operator for getting a convar value
//-----------------------------------------------------------------------------
struct CSosOperatorConvar_t : CSosOperator_t
{
CSosOperatorConvar_t()
:
m_ConVarRef( ( IConVar * )NULL )
{
// Do nothing...
}
char m_nConvar[64];
ConVarRef m_ConVarRef;
SOS_OUTPUT_FLOAT( m_flOutput, SO_SINGLE )
};
class CSosOperatorConvar : public CSosOperator
{
SOS_HEADER_DESC( CSosOperatorConvar )
};
//-----------------------------------------------------------------------------
// simple operator for setting a convar value
//-----------------------------------------------------------------------------
struct CSosOperatorSetConvar_t : CSosOperator_t
{
CSosOperatorSetConvar_t()
:
m_ConVarRef( ( IConVar * )NULL )
{
// Do nothing...
}
char m_nConvar[64];
ConVarRef m_ConVarRef;
SOS_INPUT_FLOAT( m_flInput, SO_SINGLE )
};
class CSosOperatorSetConvar : public CSosOperator
{
SOS_HEADER_DESC( CSosOperatorSetConvar )
};
#endif // SOS_OP_CONVAR_H
@@ -0,0 +1,97 @@
//============ Copyright (c) Valve Corporation, All rights reserved. ============
//
//
//===============================================================================
#include "audio_pch.h"
#include "tier2/interval.h"
#include "sos_op.h"
#include "sos_op_dashboard.h"
#include "snd_dma.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
extern Color OpColor;
extern Color ConnectColor;
extern Color ResultColor;
//-----------------------------------------------------------------------------
// CSosOperatorDashboard
//-----------------------------------------------------------------------------
SOS_BEGIN_OPERATOR_CONSTRUCTOR( CSosOperatorDashboard, "get_dashboard" )
SOS_REGISTER_OUTPUT_FLOAT( CSosOperatorDashboard, m_flOutput, SO_SINGLE, "output" )
SOS_END_OPERATOR_CONSTRUCTOR( CSosOperatorDashboard, "get_dashboard" )
void CSosOperatorDashboard::SetDefaults( void *pVoidMem ) const
{
CSosOperatorDashboard_t *pStructMem = (CSosOperatorDashboard_t *)pVoidMem;
SOS_INIT_OUTPUT_VAR( m_flOutput, SO_SINGLE, 1.0 )
pStructMem->m_bMusic = true;
}
void CSosOperatorDashboard::Execute( void *pVoidMem, channel_t *pChannel, CScratchPad *pScratchPad, CSosOperatorStack *pStack, int nOpIndex ) const
{
CSosOperatorDashboard_t *pStructMem = (CSosOperatorDashboard_t *)pVoidMem;
float flValue = 1.0;
if ( pStructMem->m_bMusic )
{
flValue = S_GetDashboarMusicMixValue();
}
pStructMem->m_flOutput[0] = flValue;
}
void CSosOperatorDashboard::Print( void *pVoidMem, CSosOperatorStack *pStack, int nOpIndex, int nLevel ) const
{
// CSosOperatorDashboard_t *pStructMem = (CSosOperatorDashboard_t *)pVoidMem;
PrintBaseParams( pVoidMem, pStack, nOpIndex, nLevel );
/// Log_Msg( LOG_SND_OPERATORS, OpColor, "%*sDashboard: %s\n", nLevel, " ", pStructMem->m_nConvar );
}
void CSosOperatorDashboard::OpHelp( ) const
{
}
void CSosOperatorDashboard::ParseKV( CSosOperatorStack *pStack, void *pVoidMem, KeyValues *pOpKeys ) const
{
CSosOperatorDashboard_t *pStructMem = (CSosOperatorDashboard_t *)pVoidMem;
KeyValues *pParams = pOpKeys->GetFirstSubKey();
while ( pParams )
{
const char *pParamString = pParams->GetName();
const char *pValueString = pParams->GetString();
if ( pParamString && *pParamString )
{
if ( pValueString && *pValueString )
{
if ( BaseParseKV( pStack, (CSosOperator_t *)pStructMem, pParamString, pValueString ) )
{
}
else if ( !V_strcasecmp( pParamString, "ds_type" ) )
{
if ( !V_strcasecmp( pValueString, "music" ) )
{
pStructMem->m_bMusic = true;
}
else
{
pStructMem->m_bMusic = false;
}
}
else
{
Log_Warning( LOG_SND_OPERATORS, "Error: Operator %s, unknown sound operator attribute %s\n", pStack->m_pCurrentOperatorName, pParamString );
}
}
}
pParams = pParams->GetNextKey();
}
}
@@ -0,0 +1,31 @@
//============ Copyright (c) Valve Corporation, All rights reserved. ============
//
//
//
//===============================================================================
#ifndef SOS_OP_DASHBOARD_H
#define SOS_OP_DASHBOARD_H
#ifdef _WIN32
#pragma once
#endif
#include "sos_op.h"
//-----------------------------------------------------------------------------
// simple operator for getting the dashboard value
//-----------------------------------------------------------------------------
struct CSosOperatorDashboard_t : CSosOperator_t
{
bool m_bMusic;
SOS_OUTPUT_FLOAT( m_flOutput, SO_SINGLE )
};
class CSosOperatorDashboard : public CSosOperator
{
SOS_HEADER_DESC( CSosOperatorDashboard )
};
#endif // SOS_OP_DASHBOARD
@@ -0,0 +1,90 @@
//============ Copyright (c) Valve Corporation, All rights reserved. ============
//
//
//===============================================================================
#include "audio_pch.h"
#include "tier2/interval.h"
#include "sos_op.h"
#include "sos_op_delta.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
extern Color OpColor;
extern Color ConnectColor;
extern Color ResultColor;
//-----------------------------------------------------------------------------
// CSosOperatorDelta
// Setting a single, simple scratch pad Expression
//-----------------------------------------------------------------------------
SOS_BEGIN_OPERATOR_CONSTRUCTOR( CSosOperatorDelta, "math_delta" )
SOS_REGISTER_INPUT_FLOAT( CSosOperatorDelta, m_flInput, SO_SINGLE, "input" );
SOS_REGISTER_OUTPUT_FLOAT( CSosOperatorDelta, m_flOutput, SO_SINGLE, "output" );
SOS_END_OPERATOR_CONSTRUCTOR( CSosOperatorDelta, "math_delta" )
void CSosOperatorDelta::SetDefaults( void *pVoidMem ) const
{
CSosOperatorDelta_t *pStructMem = (CSosOperatorDelta_t *)pVoidMem;
SOS_INIT_INPUT_VAR( m_flInput, SO_SINGLE, 0.0 )
SOS_INIT_OUTPUT_VAR( m_flOutput, SO_SINGLE, 0.0 )
pStructMem->m_flLastInput = 0.0;
pStructMem->m_flLastTime = g_pSoundServices->GetHostTime();
}
void CSosOperatorDelta::Execute( void *pVoidMem, channel_t *pChannel, CScratchPad *pScratchPad, CSosOperatorStack *pStack, int nOpIndex ) const
{
CSosOperatorDelta_t *pStructMem = (CSosOperatorDelta_t *)pVoidMem;
// need to normalize for frame time
pStructMem->m_flOutput[0] = pStructMem->m_flInput[0] - pStructMem->m_flLastInput;
pStructMem->m_flLastInput = pStructMem->m_flInput[0];
}
void CSosOperatorDelta::Print( void *pVoidMem, CSosOperatorStack *pStack, int nOpIndex, int nLevel ) const
{
// CSosOperatorDelta_t *pStructMem = (CSosOperatorDelta_t *)pVoidMem;
PrintBaseParams( pVoidMem, pStack, nOpIndex, nLevel );
}
void CSosOperatorDelta::OpHelp( ) const
{
}
void CSosOperatorDelta::ParseKV( CSosOperatorStack *pStack, void *pVoidMem, KeyValues *pOpKeys ) const
{
CSosOperatorDelta_t *pStructMem = (CSosOperatorDelta_t *)pVoidMem;
KeyValues *pParams = pOpKeys->GetFirstSubKey();
while ( pParams )
{
const char *pParamString = pParams->GetName();
const char *pValueString = pParams->GetString();
if ( pParamString && *pParamString )
{
if ( pValueString && *pValueString )
{
if ( BaseParseKV( pStack, (CSosOperator_t *)pStructMem, pParamString, pValueString ) )
{
}
else
{
Log_Warning( LOG_SND_OPERATORS, "Error: Operator %s, unknown sound operator attribute %s\n", pStack->m_pCurrentOperatorName, pParamString );
}
}
}
pParams = pParams->GetNextKey();
}
}
@@ -0,0 +1,36 @@
//============ Copyright (c) Valve Corporation, All rights reserved. ============
//
//
//
//===============================================================================
#ifndef SOS_OP_DELTA_H
#define SOS_OP_DELTA_H
#ifdef _WIN32
#pragma once
#endif
#include "sos_op.h"
//-----------------------------------------------------------------------------
// get elapsed time
//-----------------------------------------------------------------------------
struct CSosOperatorDelta_t : CSosOperator_t
{
SOS_INPUT_FLOAT( m_flInput, SO_SINGLE )
SOS_OUTPUT_FLOAT( m_flOutput, SO_SINGLE )
float m_flLastInput;
float m_flLastTime;
};
class CSosOperatorDelta : public CSosOperator
{
SOS_HEADER_DESC( CSosOperatorDelta )
};
#endif // SOS_OP_DELTA_VALUE_H
@@ -0,0 +1,95 @@
//============ Copyright (c) Valve Corporation, All rights reserved. ============
//
//
//===============================================================================
#include "audio_pch.h"
#include "tier2/interval.h"
#include "sos_op.h"
#include "sos_op_distant_dsp.h"
#include "snd_dma.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
extern Color OpColor;
extern Color ConnectColor;
extern Color ResultColor;
//-----------------------------------------------------------------------------
// CSosOperatorDistantDSP
//-----------------------------------------------------------------------------
SOS_BEGIN_OPERATOR_CONSTRUCTOR( CSosOperatorDistantDSP, "calc_distant_dsp" )
SOS_REGISTER_OUTPUT_FLOAT( CSosOperatorDistantDSP, m_flOutput, SO_SINGLE, "output" )
SOS_REGISTER_INPUT_FLOAT( CSosOperatorDistantDSP, m_flInputDist, SO_SINGLE, "input_distance" )
SOS_REGISTER_INPUT_FLOAT( CSosOperatorDistantDSP, m_flInputLevel, SO_SINGLE, "input_level" )
SOS_END_OPERATOR_CONSTRUCTOR( CSosOperatorDistantDSP, "calc_distant_dsp" )
void CSosOperatorDistantDSP::SetDefaults( void *pVoidMem ) const
{
CSosOperatorDistantDSP_t *pStructMem = (CSosOperatorDistantDSP_t *)pVoidMem;
SOS_INIT_OUTPUT_VAR( m_flOutput, SO_SINGLE, 1.0 )
SOS_INIT_INPUT_VAR( m_flInputDist, SO_SINGLE, 1.0 )
SOS_INIT_INPUT_VAR( m_flInputLevel, SO_SINGLE, 65.0 )
}
void CSosOperatorDistantDSP::Execute( void *pVoidMem, channel_t *pChannel, CScratchPad *pScratchPad, CSosOperatorStack *pStack, int nOpIndex ) const
{
CSosOperatorDistantDSP_t *pStructMem = (CSosOperatorDistantDSP_t *)pVoidMem;
if( !pChannel )
{
Log_Warning( LOG_SND_OPERATORS, "Error: Sound operator %s requires valid channel pointer, being called without one\n", pStack->GetOperatorName( nOpIndex ));
return;
}
pStructMem->m_flOutput[0] = SND_GetDspMix( pChannel, pStructMem->m_flInputDist[0], pStructMem->m_flInputLevel[0] );
}
void CSosOperatorDistantDSP::Print( void *pVoidMem, CSosOperatorStack *pStack, int nOpIndex, int nLevel ) const
{
//CSosOperatorDistantDSP_t *pStructMem = (CSosOperatorDistantDSP_t *)pVoidMem;
PrintBaseParams( pVoidMem, pStack, nOpIndex, nLevel );
}
void CSosOperatorDistantDSP::OpHelp( ) const
{
}
void CSosOperatorDistantDSP::ParseKV( CSosOperatorStack *pStack, void *pVoidMem, KeyValues *pOpKeys ) const
{
CSosOperatorDistantDSP_t *pStructMem = (CSosOperatorDistantDSP_t *)pVoidMem;
KeyValues *pParams = pOpKeys->GetFirstSubKey();
while ( pParams )
{
const char *pParamString = pParams->GetName();
const char *pValueString = pParams->GetString();
if ( pParamString && *pParamString )
{
if ( pValueString && *pValueString )
{
if ( BaseParseKV( pStack, (CSosOperator_t *)pStructMem, pParamString, pValueString ) )
{
}
else
{
Log_Warning( LOG_SND_OPERATORS, "Error: Operator %s, unknown sound operator attribute %s\n", pStack->m_pCurrentOperatorName, pParamString );
}
}
}
pParams = pParams->GetNextKey();
}
}
@@ -0,0 +1,30 @@
//============ Copyright (c) Valve Corporation, All rights reserved. ============
//
//
//
//===============================================================================
#ifndef SOS_OP_DISTANT_DSP_H
#define SOS_OP_DISTANT_DSP_H
#ifdef _WIN32
#pragma once
#endif
#include "sos_op.h"
//-----------------------------------------------------------------------------
// basic dsp by distance operator
//-----------------------------------------------------------------------------
struct CSosOperatorDistantDSP_t : CSosOperator_t
{
SOS_INPUT_FLOAT( m_flInputDist, SO_SINGLE )
SOS_INPUT_FLOAT( m_flInputLevel, SO_SINGLE )
SOS_OUTPUT_FLOAT( m_flOutput, SO_SINGLE )
};
class CSosOperatorDistantDSP : public CSosOperator
{
SOS_HEADER_DESC( CSosOperatorDistantDSP )
};
#endif // SOS_OP_DISTANT_DSP_H
@@ -0,0 +1,192 @@
//============ Copyright (c) Valve Corporation, All rights reserved. ============
//
//
//===============================================================================
#include "audio_pch.h"
#include "tier2/interval.h"
#include "client.h"
#include "sos_op.h"
#include "sos_op_entity_info.h"
#include "icliententitylist.h"
#include "icliententity.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
extern Color OpColor;
extern Color ConnectColor;
extern Color ResultColor;
// ConVar snd_sos_show_source_info("snd_sos_show_source_info", "0" );
//-----------------------------------------------------------------------------
// CSosOperatorEntityInfo
//-----------------------------------------------------------------------------
SOS_BEGIN_OPERATOR_CONSTRUCTOR( CSosOperatorEntityInfo, "game_entity_info" )
SOS_REGISTER_OUTPUT_FLOAT( CSosOperatorEntityInfo, m_flOutPosition, SO_VEC3, "output_position" );
SOS_REGISTER_OUTPUT_FLOAT( CSosOperatorEntityInfo, m_flOutPosition_x, SO_SINGLE, "output_position_x" );
SOS_REGISTER_OUTPUT_FLOAT( CSosOperatorEntityInfo, m_flOutPosition_y, SO_SINGLE, "output_position_y" );
SOS_REGISTER_OUTPUT_FLOAT( CSosOperatorEntityInfo, m_flOutPosition_z, SO_SINGLE, "output_position_z" );
SOS_REGISTER_OUTPUT_FLOAT( CSosOperatorEntityInfo, m_flOutAngles, SO_VEC3, "output_angles" );
SOS_REGISTER_OUTPUT_FLOAT( CSosOperatorEntityInfo, m_flOutVelocityVector, SO_VEC3, "output_velocity_vector" );
SOS_REGISTER_OUTPUT_FLOAT( CSosOperatorEntityInfo, m_flOutVelocityVector_x, SO_SINGLE, "output_velocity_vector_x" );
SOS_REGISTER_OUTPUT_FLOAT( CSosOperatorEntityInfo, m_flOutVelocityVector_y, SO_SINGLE, "output_velocity_vector_y" );
SOS_REGISTER_OUTPUT_FLOAT( CSosOperatorEntityInfo, m_flOutVelocityVector_z, SO_SINGLE, "output_velocity_vector_z" );
SOS_REGISTER_OUTPUT_FLOAT( CSosOperatorEntityInfo, m_flOutVelocity, SO_SINGLE, "output_velocity" );
SOS_REGISTER_OUTPUT_FLOAT( CSosOperatorEntityInfo, m_flOutVelocityXY, SO_SINGLE, "output_velocity_xy" );
SOS_REGISTER_INPUT_FLOAT( CSosOperatorEntityInfo, m_flInputEntityIndex, SO_SINGLE, "input_entity_index" );
SOS_END_OPERATOR_CONSTRUCTOR( CSosOperatorEntityInfo, "game_entity_info" )
void CSosOperatorEntityInfo::SetDefaults( void *pVoidMem ) const
{
CSosOperatorEntityInfo_t *pStructMem = (CSosOperatorEntityInfo_t *)pVoidMem;
SOS_INIT_OUTPUT_VAR( m_flOutPosition, SO_VEC3, 0.0 )
SOS_INIT_OUTPUT_VAR( m_flOutPosition_x, SO_SINGLE, 0.0 )
SOS_INIT_OUTPUT_VAR( m_flOutPosition_y, SO_SINGLE, 0.0 )
SOS_INIT_OUTPUT_VAR( m_flOutPosition_z, SO_SINGLE, 0.0 )
SOS_INIT_OUTPUT_VAR( m_flOutAngles, SO_VEC3, 0.0 )
SOS_INIT_OUTPUT_VAR( m_flOutVelocity, SO_SINGLE, 0.0 )
SOS_INIT_OUTPUT_VAR( m_flOutVelocityVector, SO_VEC3, 0.0 )
SOS_INIT_OUTPUT_VAR( m_flOutVelocityVector_x, SO_SINGLE, 0.0 )
SOS_INIT_OUTPUT_VAR( m_flOutVelocityVector_y, SO_SINGLE, 0.0 )
SOS_INIT_OUTPUT_VAR( m_flOutVelocityVector_z, SO_SINGLE, 0.0 )
SOS_INIT_OUTPUT_VAR( m_flOutVelocityXY, SO_SINGLE, 0.0 )
SOS_INIT_INPUT_VAR( m_flInputEntityIndex, SO_SINGLE, 0.0 )
pStructMem->m_vecPrevPosition.Init();
pStructMem->m_flPrevTime = g_pSoundServices->GetHostTime();
}
void CSosOperatorEntityInfo::Execute( void *pVoidMem, channel_t *pChannel, CScratchPad *pScratchPad, CSosOperatorStack *pStack, int nOpIndex ) const
{
#ifndef DEDICATED
CSosOperatorEntityInfo_t *pStructMem = (CSosOperatorEntityInfo_t *)pVoidMem;
// for future use with splitscreen
int nCurIndex = (int) pStructMem->m_flInputEntityIndex[0];
if( nCurIndex < 0 )
{
Log_Warning( LOG_SND_OPERATORS, "Error: %s, input_entity_index %i invalid\n", pStack->GetOperatorName( nOpIndex ), nCurIndex );
return;
}
Vector vEntityAbsPos;
vEntityAbsPos.Init( 0.0, 0.0, 0.0 );
IClientEntity *pClientEntity = entitylist->GetClientEntity(nCurIndex );
if ( pClientEntity )
{
vEntityAbsPos = pClientEntity->GetAbsOrigin();
}
// first frame init position to avoid, erroneous deltas, zero is best option
if( pStructMem->m_flPrevTime == 0.0 )
{
VectorCopy( ( pScratchPad->m_vPlayerOrigin[ nCurIndex ]), pStructMem->m_vecPrevPosition );
}
// calculate delta time for this operator updates
float flCurTime = g_ClientGlobalVariables.curtime;
float flDeltaTime = flCurTime - pStructMem->m_flPrevTime;
pStructMem->m_flPrevTime = flCurTime;
if( flDeltaTime > 0.0 )
{
// per/sec factor
float flPerSec = 1.0 / flDeltaTime;
pStructMem->m_flOutPosition[0] = vEntityAbsPos[0];
pStructMem->m_flOutPosition[1] = vEntityAbsPos[1];
pStructMem->m_flOutPosition[2] = vEntityAbsPos[2];
// this is temporary for accessing single elements in array, will be a [] "feature" later when there's time
pStructMem->m_flOutPosition_x[0] = pStructMem->m_flOutPosition[0];
pStructMem->m_flOutPosition_y[0] = pStructMem->m_flOutPosition[1];
pStructMem->m_flOutPosition_z[0] = pStructMem->m_flOutPosition[2];
// get raw velocity vector
Vector vPositionDelta;
vPositionDelta[0] = pStructMem->m_flOutPosition[0] - pStructMem->m_vecPrevPosition[0];
vPositionDelta[1] = pStructMem->m_flOutPosition[1] - pStructMem->m_vecPrevPosition[1];
vPositionDelta[2] = pStructMem->m_flOutPosition[2] - pStructMem->m_vecPrevPosition[2];
// scale vector to per/sec
Vector vVelocity = vPositionDelta * flPerSec;
pStructMem->m_flOutVelocityVector[0] = vVelocity[0];
pStructMem->m_flOutVelocityVector[1] = vVelocity[1];
pStructMem->m_flOutVelocityVector[2] = vVelocity[2];
// this is temporary for accessing single elements in array, will be a "feature" later when there's time
pStructMem->m_flOutVelocityVector_x[0] = pStructMem->m_flOutVelocityVector[0];
pStructMem->m_flOutVelocityVector_y[0] = pStructMem->m_flOutVelocityVector[1];
pStructMem->m_flOutVelocityVector_z[0] = pStructMem->m_flOutVelocityVector[2];
pStructMem->m_flOutVelocity[0] = vVelocity.Length();
pStructMem->m_flOutVelocityXY[0] = vVelocity.Length2D();
VectorCopy( vEntityAbsPos, pStructMem->m_vecPrevPosition );
}
#endif
}
void CSosOperatorEntityInfo::Print( void *pVoidMem, CSosOperatorStack *pStack, int nOpIndex, int nLevel ) const
{
// CSosOperatorEntityInfo_t *pStructMem = (CSosOperatorEntityInfo_t *)pVoidMem;
PrintBaseParams( pVoidMem, pStack, nOpIndex, nLevel );
}
void CSosOperatorEntityInfo::OpHelp( ) const
{
}
void CSosOperatorEntityInfo::ParseKV( CSosOperatorStack *pStack, void *pVoidMem, KeyValues *pOpKeys ) const
{
CSosOperatorEntityInfo_t *pStructMem = (CSosOperatorEntityInfo_t *)pVoidMem;
KeyValues *pParams = pOpKeys->GetFirstSubKey();
while ( pParams )
{
const char *pParamString = pParams->GetName();
const char *pValueString = pParams->GetString();
if ( pParamString && *pParamString )
{
if ( pValueString && *pValueString )
{
if ( BaseParseKV( pStack, (CSosOperator_t *)pStructMem, pParamString, pValueString ) )
{
}
else
{
Log_Warning( LOG_SND_OPERATORS, "Error: Operator %s, unknown sound operator attribute %s\n", pStack->m_pCurrentOperatorName, pParamString );
}
}
}
pParams = pParams->GetNextKey();
}
}
@@ -0,0 +1,48 @@
//============ Copyright (c) Valve Corporation, All rights reserved. ============
//
//
//
//===============================================================================
#ifndef SOS_OP_ENTITY_INFO_H
#define SOS_OP_ENTITY_INFO_H
#ifdef _WIN32
#pragma once
#endif
#include "sos_op.h"
//-----------------------------------------------------------------------------
// simple operator for setting a single position
//-----------------------------------------------------------------------------
struct CSosOperatorEntityInfo_t : CSosOperator_t
{
SOS_OUTPUT_FLOAT( m_flOutPosition, SO_VEC3 )
SOS_OUTPUT_FLOAT( m_flOutPosition_x, SO_SINGLE )
SOS_OUTPUT_FLOAT( m_flOutPosition_y, SO_SINGLE )
SOS_OUTPUT_FLOAT( m_flOutPosition_z, SO_SINGLE )
SOS_OUTPUT_FLOAT( m_flOutAngles, SO_VEC3 )
SOS_OUTPUT_FLOAT( m_flOutVelocity, SO_SINGLE )
SOS_OUTPUT_FLOAT( m_flOutVelocityVector, SO_VEC3 )
SOS_OUTPUT_FLOAT( m_flOutVelocityVector_x, SO_SINGLE )
SOS_OUTPUT_FLOAT( m_flOutVelocityVector_y, SO_SINGLE )
SOS_OUTPUT_FLOAT( m_flOutVelocityVector_z, SO_SINGLE )
SOS_OUTPUT_FLOAT( m_flOutVelocityXY, SO_SINGLE )
SOS_INPUT_FLOAT( m_flInputEntityIndex, SO_SINGLE )
float m_flPrevTime;
Vector m_vecPrevPosition;
};
class CSosOperatorEntityInfo : public CSosOperator
{
SOS_HEADER_DESC( CSosOperatorEntityInfo )
};
#endif // SOS_OP_ENTITY_INFO_H
@@ -0,0 +1,134 @@
//============ Copyright (c) Valve Corporation, All rights reserved. ============
//
//
//===============================================================================
#include "audio_pch.h"
#include "tier2/interval.h"
#include "snd_dma.h"
#include "sos_op.h"
#include "sos_op_entry_time.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
extern Color OpColor;
extern Color ConnectColor;
extern Color ResultColor;
//-----------------------------------------------------------------------------
// CSosOperatorEntryTime
// Setting a single, simple scratch pad Expression
//-----------------------------------------------------------------------------
SOS_BEGIN_OPERATOR_CONSTRUCTOR( CSosOperatorEntryTime, "get_entry_time" )
SOS_REGISTER_OUTPUT_FLOAT( CSosOperatorEntryTime, m_flOutputEntryElapsed, SO_SINGLE, "output_entry_elapsed" );
SOS_REGISTER_OUTPUT_FLOAT( CSosOperatorEntryTime, m_flOutputSoundElapsed, SO_SINGLE, "output_sound_elapsed" );
SOS_REGISTER_OUTPUT_FLOAT( CSosOperatorEntryTime, m_flOutputStopElapsed, SO_SINGLE, "output_stop_elapsed" );
SOS_REGISTER_OUTPUT_FLOAT( CSosOperatorEntryTime, m_flOutputSoundDuration, SO_SINGLE, "output_sound_duration" );
SOS_END_OPERATOR_CONSTRUCTOR( CSosOperatorEntryTime, "get_entry_time" )
void CSosOperatorEntryTime::SetDefaults( void *pVoidMem ) const
{
CSosOperatorEntryTime_t *pStructMem = (CSosOperatorEntryTime_t *)pVoidMem;
SOS_INIT_OUTPUT_VAR( m_flOutputSoundDuration, SO_SINGLE, 0.0 )
SOS_INIT_OUTPUT_VAR( m_flOutputSoundElapsed, SO_SINGLE, 0.0 )
SOS_INIT_OUTPUT_VAR( m_flOutputStopElapsed, SO_SINGLE, 0.0 )
SOS_INIT_OUTPUT_VAR( m_flOutputEntryElapsed, SO_SINGLE, 0.0 )
pStructMem->m_nScriptHash = SOUNDEMITTER_INVALID_HASH;
}
void CSosOperatorEntryTime::Execute( void *pVoidMem, channel_t *pChannel, CScratchPad *pScratchPad, CSosOperatorStack *pStack, int nOpIndex ) const
{
CSosOperatorEntryTime_t *pStructMem = (CSosOperatorEntryTime_t *)pVoidMem;
channel_t *pTimeChannel = NULL;
if( pStructMem->m_nScriptHash != SOUNDEMITTER_INVALID_HASH )
{
pTimeChannel = S_FindChannelByScriptHash( pStructMem->m_nScriptHash );
}
else
{
pTimeChannel = S_FindChannelByGuid( pStack->GetChannelGuid() );
}
if( !pTimeChannel )
{
Log_Warning( LOG_SND_OPERATORS, "Error: Sound operator %s requires valid channel pointer, being called without one\n", pStack->GetOperatorName( nOpIndex ));
return;
}
if( pTimeChannel->m_pStackList )
{
CSosOperatorStack *pTheStack = NULL;
pTheStack = pTimeChannel->m_pStackList->GetStack( CSosOperatorStack::SOS_UPDATE );
if( pTheStack )
{
pStructMem->m_flOutputEntryElapsed[0] = pTheStack->GetElapsedTime();
}
}
pStructMem->m_flOutputSoundElapsed[0] = S_GetElapsedTime( pTimeChannel ) * 0.01;
pStructMem->m_flOutputSoundDuration[0] = S_SoundDuration( pTimeChannel );
pStructMem->m_flOutputStopElapsed[0] = pStack->GetElapsedStopTime( );
}
void CSosOperatorEntryTime::Print( void *pVoidMem, CSosOperatorStack *pStack, int nOpIndex, int nLevel ) const
{
// CSosOperatorEntryTime_t *pStructMem = (CSosOperatorEntryTime_t *)pVoidMem;
PrintBaseParams( pVoidMem, pStack, nOpIndex, nLevel );
}
void CSosOperatorEntryTime::OpHelp( ) const
{
}
void CSosOperatorEntryTime::ParseKV( CSosOperatorStack *pStack, void *pVoidMem, KeyValues *pOpKeys ) const
{
CSosOperatorEntryTime_t *pStructMem = (CSosOperatorEntryTime_t *)pVoidMem;
KeyValues *pParams = pOpKeys->GetFirstSubKey();
while ( pParams )
{
const char *pParamString = pParams->GetName();
const char *pValueString = pParams->GetString();
if ( pParamString && *pParamString )
{
if ( pValueString && *pValueString )
{
if ( BaseParseKV( pStack, (CSosOperator_t *)pStructMem, pParamString, pValueString ) )
{
}
else if ( !V_strcasecmp( pParamString, "entry" ) )
{
if ( !g_pSoundEmitterSystem )
{
DevWarning("Error: SoundEmitterSystem not initialized in engine!");
return;
}
pStructMem->m_nScriptHash = g_pSoundEmitterSystem->HashSoundName( pValueString );
if( !g_pSoundEmitterSystem->GetSoundNameForHash( pStructMem->m_nScriptHash ))
{
DevMsg( "Error: Invalid SoundEntry hash %i from entry %s", pStructMem->m_nScriptHash, pValueString );
return;
}
}
else
{
Log_Warning( LOG_SND_OPERATORS, "Error: Operator %s, unknown sound operator attribute %s\n", pStack->m_pCurrentOperatorName, pParamString );
}
}
}
pParams = pParams->GetNextKey();
}
}
@@ -0,0 +1,37 @@
//============ Copyright (c) Valve Corporation, All rights reserved. ============
//
//
//
//===============================================================================
#ifndef SOS_OP_ENTRY_TIME_H
#define SOS_OP_ENTRY_TIME_H
#ifdef _WIN32
#pragma once
#endif
#include "sos_op.h"
//-----------------------------------------------------------------------------
// get elapsed time
//-----------------------------------------------------------------------------
struct CSosOperatorEntryTime_t : CSosOperator_t
{
SOS_OUTPUT_FLOAT( m_flOutputSoundDuration, SO_SINGLE )
SOS_OUTPUT_FLOAT( m_flOutputSoundElapsed, SO_SINGLE )
SOS_OUTPUT_FLOAT( m_flOutputEntryElapsed, SO_SINGLE )
SOS_OUTPUT_FLOAT( m_flOutputStopElapsed, SO_SINGLE )
SOS_OUTPUT_FLOAT( m_flOutputHostElapsed, SO_SINGLE )
HSOUNDSCRIPTHASH m_nScriptHash;
};
class CSosOperatorEntryTime : public CSosOperator
{
SOS_HEADER_DESC( CSosOperatorEntryTime )
};
#endif // SOS_OP_ENTRY_TIME_H
@@ -0,0 +1,195 @@
//============ Copyright (c) Valve Corporation, All rights reserved. ============
//
//
//===============================================================================
#include "audio_pch.h"
#include "tier2/interval.h"
#include "sos_op.h"
#include "sos_op_falloff.h"
#include "snd_dma.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
extern Color OpColor;
extern Color ConnectColor;
extern Color ResultColor;
//-----------------------------------------------------------------------------
// CSosOperatorFalloff
// Setting a single, simple scratch pad Expression
//-----------------------------------------------------------------------------
SOS_BEGIN_OPERATOR_CONSTRUCTOR( CSosOperatorFalloff, "calc_falloff" )
SOS_REGISTER_OUTPUT_FLOAT( CSosOperatorFalloff, m_flOutput, SO_SINGLE, "output" )
SOS_REGISTER_INPUT_FLOAT( CSosOperatorFalloff, m_flInputDist, SO_SINGLE, "input_distance" )
SOS_REGISTER_INPUT_FLOAT( CSosOperatorFalloff, m_flInputLevel, SO_SINGLE, "input_level" )
SOS_END_OPERATOR_CONSTRUCTOR( CSosOperatorFalloff, "calc_falloff" )
void CSosOperatorFalloff::SetDefaults( void *pVoidMem ) const
{
CSosOperatorFalloff_t *pStructMem = (CSosOperatorFalloff_t *)pVoidMem;
SOS_INIT_OUTPUT_VAR( m_flOutput, SO_SINGLE, 1.0 )
SOS_INIT_INPUT_VAR( m_flInputDist, SO_SINGLE, 1.0 )
SOS_INIT_INPUT_VAR( m_flInputLevel, SO_SINGLE, 1.0 )
}
void CSosOperatorFalloff::Execute( void *pVoidMem, channel_t *pChannel, CScratchPad *pScratchPad, CSosOperatorStack *pStack, int nOpIndex ) const
{
CSosOperatorFalloff_t *pStructMem = (CSosOperatorFalloff_t *)pVoidMem;
float flDistMult = SNDLVL_TO_DIST_MULT( pStructMem->m_flInputLevel[0] );
// the first arg used to be because there was a form of compression on the falloff
// based on overall volume level, we are not having volume effect our falloff
pStructMem->m_flOutput[0] = SND_GetGainFromMult( 1.0, flDistMult, pStructMem->m_flInputDist[0] );
}
void CSosOperatorFalloff::Print( void *pVoidMem, CSosOperatorStack *pStack, int nOpIndex, int nLevel ) const
{
// CSosOperatorFalloff_t *pStructMem = (CSosOperatorFalloff_t *)pVoidMem;
PrintBaseParams( pVoidMem, pStack, nOpIndex, nLevel );
}
void CSosOperatorFalloff::OpHelp( ) const
{
}
void CSosOperatorFalloff::ParseKV( CSosOperatorStack *pStack, void *pVoidMem, KeyValues *pOpKeys ) const
{
CSosOperatorFalloff_t *pStructMem = (CSosOperatorFalloff_t *)pVoidMem;
KeyValues *pParams = pOpKeys->GetFirstSubKey();
while ( pParams )
{
const char *pParamString = pParams->GetName();
const char *pValueString = pParams->GetString();
if ( pParamString && *pParamString )
{
if ( pValueString && *pValueString )
{
if( BaseParseKV( pStack, (CSosOperator_t *)pStructMem, pParamString, pValueString ))
{
}
else
{
Log_Warning( LOG_SND_OPERATORS, "Error: Operator %s, unknown sound operator attribute %s\n", pStack->m_pCurrentOperatorName, pParamString );
}
}
}
pParams = pParams->GetNextKey();
}
}
//-----------------------------------------------------------------------------
// CSosOperatorFalloffTail
// Setting a single, simple scratch pad Expression
//-----------------------------------------------------------------------------
SOS_BEGIN_OPERATOR_CONSTRUCTOR( CSosOperatorFalloffTail, "calc_falloff_curve" )
SOS_REGISTER_OUTPUT_FLOAT( CSosOperatorFalloffTail, m_flOutput, SO_SINGLE, "output" )
SOS_REGISTER_INPUT_FLOAT( CSosOperatorFalloffTail, m_flInputDist, SO_SINGLE, "input_distance" )
SOS_REGISTER_INPUT_FLOAT( CSosOperatorFalloffTail, m_flInputExp, SO_SINGLE, "input_curve_amount" )
SOS_REGISTER_INPUT_FLOAT( CSosOperatorFalloffTail, m_flInputDistantMin, SO_SINGLE, "input_min" )
SOS_REGISTER_INPUT_FLOAT( CSosOperatorFalloffTail, m_flInputDistantMax, SO_SINGLE, "input_max" )
SOS_REGISTER_INPUT_FLOAT( CSosOperatorFalloffTail, m_flInputAtten, SO_SINGLE, "input_atten" )
// SOS_REGISTER_INPUT_FLOAT( CSosOperatorFalloffTail, m_flInputTailMin, SO_SINGLE, "input_tail_min" )
// SOS_REGISTER_INPUT_FLOAT( CSosOperatorFalloffTail, m_flInputTailMax, SO_SINGLE, "input_tail_max" )
SOS_END_OPERATOR_CONSTRUCTOR( CSosOperatorFalloffTail, "calc_falloff_curve" )
void CSosOperatorFalloffTail::SetDefaults( void *pVoidMem ) const
{
CSosOperatorFalloffTail_t *pStructMem = (CSosOperatorFalloffTail_t *)pVoidMem;
SOS_INIT_OUTPUT_VAR( m_flOutput, SO_SINGLE, 1.0 )
SOS_INIT_INPUT_VAR( m_flInputDist, SO_SINGLE, 0.0 )
SOS_INIT_INPUT_VAR( m_flInputExp, SO_SINGLE, 0.0 )
SOS_INIT_INPUT_VAR( m_flInputDistantMin, SO_SINGLE, 36.0 )
SOS_INIT_INPUT_VAR( m_flInputDistantMax, SO_SINGLE, 360.0 )
SOS_INIT_INPUT_VAR( m_flInputAtten, SO_SINGLE, 360.0 )
// SOS_INIT_INPUT_VAR( m_flInputTailMin, SO_SINGLE, 240.0 )
// SOS_INIT_INPUT_VAR( m_flInputTailMax, SO_SINGLE, 540.0 )
}
#define SOP_FALLOFF_MIN_EXP 0.1f
void CSosOperatorFalloffTail::Execute( void *pVoidMem, channel_t *pChannel, CScratchPad *pScratchPad, CSosOperatorStack *pStack, int nOpIndex ) const
{
CSosOperatorFalloffTail_t *pStructMem = (CSosOperatorFalloffTail_t *)pVoidMem;
float flDistance = pStructMem->m_flInputDist[0];
float flDistantMin = pStructMem->m_flInputDistantMin[0];
float flDistantMax = pStructMem->m_flInputDistantMax[0];
// float flTailMin = pStructMem->m_flInputTailMin[0];
// float flTailMax = pStructMem->m_flInputTailMax[0];
flDistantMax = flDistantMax > flDistantMin ? flDistantMax : flDistantMin;
// flTailMin < flDistantMax ? flTailMin : flDistantMax;
// flTailMax > flDistantMax ? flTailMax : flDistantMax;
float flResult;
if ( flDistance <= flDistantMin )
{
flResult = pStructMem->m_flInputAtten[0];
}
// else if ( flDistance >= flTailMax ||
// ( flDistance > flDistantMax && flTailMin == flDistantMax ) )
else if ( flDistance > flDistantMax )
{
flResult = 0.0;
}
// else if ( flDistance > flTailMin && flDistance < flTailMax )
// {
// flResult = 1.0 - ( ( flDistance - flTailMin ) / ( flTailMax - flTailMin ) );
// flResult *= FastPow( 1.0 - ( flTailMin - flDistantMin ) / ( flDistantMax - flDistantMin ), pStructMem->m_flInputDistantExp[0] );
// }
// else if ( flDistance > flDistantMin && flDistance <= flTailMin )
else // flDistance is between flDistantMin and flDistantMax
{
flResult = ( flDistance - flDistantMin ) / ( flDistantMax - flDistantMin );
flResult = (1.0 - FastPow( flResult, ( 1.0 + SOP_FALLOFF_MIN_EXP) - pStructMem->m_flInputExp[0] )) * pStructMem->m_flInputAtten[0];
}
pStructMem->m_flOutput[0] = flResult;
}
void CSosOperatorFalloffTail::Print( void *pVoidMem, CSosOperatorStack *pStack, int nOpIndex, int nLevel ) const
{
// CSosOperatorFalloffTail_t *pStructMem = (CSosOperatorFalloffTail_t *)pVoidMem;
PrintBaseParams( pVoidMem, pStack, nOpIndex, nLevel );
}
void CSosOperatorFalloffTail::OpHelp() const
{
}
void CSosOperatorFalloffTail::ParseKV( CSosOperatorStack *pStack, void *pVoidMem, KeyValues *pOpKeys ) const
{
CSosOperatorFalloffTail_t *pStructMem = (CSosOperatorFalloffTail_t *)pVoidMem;
KeyValues *pParams = pOpKeys->GetFirstSubKey();
while ( pParams )
{
const char *pParamString = pParams->GetName();
const char *pValueString = pParams->GetString();
if ( pParamString && *pParamString )
{
if ( pValueString && *pValueString )
{
if ( BaseParseKV( pStack, (CSosOperator_t *)pStructMem, pParamString, pValueString ) )
{
}
else
{
Log_Warning( LOG_SND_OPERATORS, "Error: Operator %s, unknown sound operator attribute %s\n", pStack->m_pCurrentOperatorName, pParamString );
}
}
}
pParams = pParams->GetNextKey();
}
}
@@ -0,0 +1,53 @@
//============ Copyright (c) Valve Corporation, All rights reserved. ============
//
//
//
//===============================================================================
#ifndef SOS_OP_FALLOFF_H
#define SOS_OP_FALLOFF_H
#ifdef _WIN32
#pragma once
#endif
#include "sos_op.h"
//-----------------------------------------------------------------------------
// falloff
//-----------------------------------------------------------------------------
struct CSosOperatorFalloff_t : CSosOperator_t
{
SOS_INPUT_FLOAT( m_flInputDist, SO_SINGLE )
SOS_INPUT_FLOAT( m_flInputLevel, SO_SINGLE )
SOS_OUTPUT_FLOAT( m_flOutput, SO_SINGLE )
};
class CSosOperatorFalloff : public CSosOperator
{
SOS_HEADER_DESC( CSosOperatorFalloff )
};
//-----------------------------------------------------------------------------
// falloff
//-----------------------------------------------------------------------------
struct CSosOperatorFalloffTail_t : CSosOperator_t
{
SOS_INPUT_FLOAT( m_flInputDist, SO_SINGLE )
SOS_INPUT_FLOAT( m_flInputAtten, SO_SINGLE )
SOS_INPUT_FLOAT( m_flInputDistantMin, SO_SINGLE )
SOS_INPUT_FLOAT( m_flInputDistantMax, SO_SINGLE )
SOS_INPUT_FLOAT( m_flInputExp, SO_SINGLE )
// SOS_INPUT_FLOAT( m_flInputTailMin, SO_SINGLE )
// SOS_INPUT_FLOAT( m_flInputTailMax, SO_SINGLE )
SOS_OUTPUT_FLOAT( m_flOutput, SO_SINGLE )
};
class CSosOperatorFalloffTail : public CSosOperator
{
SOS_HEADER_DESC( CSosOperatorFalloffTail )
};
#endif // SOS_OP_FALLOFF
@@ -0,0 +1,134 @@
//============ Copyright (c) Valve Corporation, All rights reserved. ============
//
//
//===============================================================================
#include "audio_pch.h"
#include "tier2/interval.h"
#include "client.h"
#include "sos_op.h"
#include "sos_op_filters.h"
#include "icliententitylist.h"
#include "icliententity.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
extern Color OpColor;
extern Color ConnectColor;
extern Color ResultColor;
// ConVar snd_sos_show_source_info("snd_sos_show_source_info", "0" );
//-----------------------------------------------------------------------------
// CSosOperatorFloatFilter
//-----------------------------------------------------------------------------
SOS_BEGIN_OPERATOR_CONSTRUCTOR( CSosOperatorFloatFilter, "math_float_filter" )
SOS_REGISTER_OUTPUT_FLOAT( CSosOperatorFloatFilter, m_flOutput, SO_SINGLE, "output" );
SOS_REGISTER_INPUT_FLOAT( CSosOperatorFloatFilter, m_flInput, SO_SINGLE, "input" );
SOS_REGISTER_INPUT_FLOAT( CSosOperatorFloatFilter, m_flInputMaxVel, SO_SINGLE, "input_max_velocity" );
SOS_END_OPERATOR_CONSTRUCTOR( CSosOperatorFloatFilter, "math_float_filter" )
void CSosOperatorFloatFilter::SetDefaults( void *pVoidMem ) const
{
CSosOperatorFloatFilter_t *pStructMem = (CSosOperatorFloatFilter_t *)pVoidMem;
SOS_INIT_OUTPUT_VAR( m_flOutput, SO_SINGLE, 0.0 )
SOS_INIT_INPUT_VAR( m_flInput, SO_SINGLE, 0.0 )
//pStructMem->m_flPrevTime = g_pSoundServices->GetHostTime();
pStructMem->m_flPrevTime = -1.0;
}
void CSosOperatorFloatFilter::Execute( void *pVoidMem, channel_t *pChannel, CScratchPad *pScratchPad, CSosOperatorStack *pStack, int nOpIndex ) const
{
#ifndef DEDICATED
CSosOperatorFloatFilter_t *pStructMem = (CSosOperatorFloatFilter_t *)pVoidMem;
// first frame init position to avoid, erroneous deltas, zero is best option
if( pStructMem->m_flPrevTime < 0.0 )
{
pStructMem->m_flOutput[0] = pStructMem->m_flInput[0];
pStructMem->m_flPrevTime = g_ClientGlobalVariables.curtime;
}
else
{
// calculate delta time for this operator updates
float flCurTime = g_ClientGlobalVariables.curtime;
float flDeltaTime = flCurTime - pStructMem->m_flPrevTime;
pStructMem->m_flPrevTime = flCurTime;
float flDeltaValue = pStructMem->m_flInput[0] - pStructMem->m_flOutput[0];
if( flDeltaTime > 0.0 && flDeltaValue != 0.0 )
{
float flMaxVel = pStructMem->m_flInputMaxVel[0];
// per/sec factor
float flPerSec = 1.0 / flDeltaTime;
float flValueVel = flPerSec * flDeltaValue;
if( fabs(flValueVel) > flMaxVel )
{
float flVector = ( flDeltaTime * (flMaxVel * ( flDeltaValue < 0.0 ? -1.0 : 1.0 )));
pStructMem->m_flOutput[0] += flVector;
}
else
{
pStructMem->m_flOutput[0] = pStructMem->m_flInput[0];
}
}
}
#endif
}
void CSosOperatorFloatFilter::Print( void *pVoidMem, CSosOperatorStack *pStack, int nOpIndex, int nLevel ) const
{
// CSosOperatorFloatFilter_t *pStructMem = (CSosOperatorFloatFilter_t *)pVoidMem;
PrintBaseParams( pVoidMem, pStack, nOpIndex, nLevel );
}
void CSosOperatorFloatFilter::OpHelp( ) const
{
}
void CSosOperatorFloatFilter::ParseKV( CSosOperatorStack *pStack, void *pVoidMem, KeyValues *pOpKeys ) const
{
CSosOperatorFloatFilter_t *pStructMem = (CSosOperatorFloatFilter_t *)pVoidMem;
KeyValues *pParams = pOpKeys->GetFirstSubKey();
while ( pParams )
{
const char *pParamString = pParams->GetName();
const char *pValueString = pParams->GetString();
if ( pParamString && *pParamString )
{
if ( pValueString && *pValueString )
{
if ( BaseParseKV( pStack, (CSosOperator_t *)pStructMem, pParamString, pValueString ) )
{
}
else
{
Log_Warning( LOG_SND_OPERATORS, "Error: Operator %s, unknown sound operator attribute %s\n", pStack->m_pCurrentOperatorName, pParamString );
}
}
}
pParams = pParams->GetNextKey();
}
}
@@ -0,0 +1,35 @@
//============ Copyright (c) Valve Corporation, All rights reserved. ============
//
//
//
//===============================================================================
#ifndef SOS_OP_FILTERS_H
#define SOS_OP_FILTERS_H
#ifdef _WIN32
#pragma once
#endif
#include "sos_op.h"
//-----------------------------------------------------------------------------
// simple operator for setting a single position
//-----------------------------------------------------------------------------
struct CSosOperatorFloatFilter_t : CSosOperator_t
{
SOS_OUTPUT_FLOAT( m_flOutput, SO_SINGLE )
SOS_INPUT_FLOAT( m_flInput, SO_SINGLE )
SOS_INPUT_FLOAT( m_flInputMaxVel, SO_SINGLE )
float m_flPrevTime;
float m_flPrevValue;
};
class CSosOperatorFloatFilter : public CSosOperator
{
SOS_HEADER_DESC( CSosOperatorFloatFilter )
};
#endif // SOS_OP_FILTERS_H
@@ -0,0 +1,149 @@
//============ Copyright (c) Valve Corporation, All rights reserved. ============
//
//
//===============================================================================
#include "audio_pch.h"
#include "tier2/interval.h"
#include "sos_op.h"
#include "sos_op_iterate_merge_speakers.h"
// #include "../../debugoverlay.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
extern Color OpColor;
extern Color ConnectColor;
extern Color ResultColor;
//-----------------------------------------------------------------------------
// CSosOperatorIterateAndMergeSpeakers_t
// Setting a single, simple scratch pad Expression
//-----------------------------------------------------------------------------
SOS_BEGIN_OPERATOR_CONSTRUCTOR( CSosOperatorIterateAndMergeSpeakers, "iterate_merge_speakers" )
SOS_REGISTER_INPUT_FLOAT( CSosOperatorIterateAndMergeSpeakers, m_flInputMaxIterations, SO_SINGLE, "input_max_iterations" )
SOS_REGISTER_OUTPUT_FLOAT( CSosOperatorIterateAndMergeSpeakers, m_flOutputIndex, SO_SINGLE, "output_index" )
SOS_REGISTER_OUTPUT_FLOAT( CSosOperatorIterateAndMergeSpeakers, m_flOutputSpeakers, SO_SPEAKERS, "output" )
SOS_REGISTER_INPUT_FLOAT( CSosOperatorIterateAndMergeSpeakers, m_flInputSpeakers, SO_SPEAKERS, "input")
SOS_END_OPERATOR_CONSTRUCTOR( CSosOperatorIterateAndMergeSpeakers, "iterate_merge_speakers" )
void CSosOperatorIterateAndMergeSpeakers::SetDefaults( void *pVoidMem ) const
{
CSosOperatorIterateAndMergeSpeakers_t *pStructMem = ( CSosOperatorIterateAndMergeSpeakers_t *)pVoidMem;
SOS_INIT_INPUT_VAR( m_flInputMaxIterations, SO_SINGLE, 0.0 )
SOS_INIT_INPUT_VAR( m_flInputSpeakers, SO_SPEAKERS, 0.0 )
SOS_INIT_OUTPUT_VAR( m_flOutputSpeakers, SO_SPEAKERS, 0.0 )
SOS_INIT_OUTPUT_VAR( m_flOutputIndex, SO_SINGLE, 0.0 )
pStructMem->m_nMaxIterations = 8;
pStructMem->m_nOperatorIndex = -1;
}
void CSosOperatorIterateAndMergeSpeakers::Execute( void *pVoidMem, channel_t *pChannel, CScratchPad *pScratchPad, CSosOperatorStack *pStack, int nOpIndex ) const
{
CSosOperatorIterateAndMergeSpeakers_t *pStructMem = ( CSosOperatorIterateAndMergeSpeakers_t *)pVoidMem;
if( !pChannel )
{
Log_Warning( LOG_SND_OPERATORS, "Error: Sound operator %s requires valid channel pointer, being called without one\n", pStack->GetOperatorName( nOpIndex ));
return;
}
int nCurIndex = ( int )pStructMem->m_flOutputIndex[0];
int nLastIndex = MIN( ( int ) pStructMem->m_flInputMaxIterations[0], pStructMem->m_nMaxIterations );
if( nCurIndex == 0 )
{
for ( int i = 0; i < SO_MAX_SPEAKERS; i++ )
{
pStructMem->m_flOutputSpeakers[i] = 0.0;
}
}
// merge speaker volumes
for ( int v = 0; v < SO_MAX_SPEAKERS; ++v )
{
// switch ( g_SndMergeMethod )
// switch ( SND_MERGE_MAX )
// {
// default:
// case SND_MERGE_SUMANDCLIP:
// {
// pStructMem->m_flOutputSpeakers[v] = min( pStructMem->m_flInputSpeakers[v]+pStructMem->m_flOutputSpeakers[v], 1.0 );
// }
// break;
// case SND_MERGE_MAX:
// {
pStructMem->m_flOutputSpeakers[v] = MAX( pStructMem->m_flInputSpeakers[v], pStructMem->m_flOutputSpeakers[v] );
// }
// break;
// }
}
// are we done?
if ( nCurIndex < nLastIndex )
{
nCurIndex++;
pStructMem->m_flOutputIndex[0] = ( float )nCurIndex;
pStack->ExecuteIterator( pChannel, pScratchPad, pVoidMem, pStructMem->m_nStartOperatorName, &pStructMem->m_nOperatorIndex );
return;
}
else
{
// clear index for next time around
pStructMem->m_flOutputIndex[0] = 0.0;
return;
}
}
void CSosOperatorIterateAndMergeSpeakers::Print( void *pVoidMem, CSosOperatorStack *pStack, int nOpIndex, int nLevel ) const
{
CSosOperatorIterateAndMergeSpeakers_t *pStructMem = ( CSosOperatorIterateAndMergeSpeakers_t * )pVoidMem;
PrintBaseParams( pVoidMem, pStack, nOpIndex, nLevel );
Log_Msg( LOG_SND_OPERATORS, OpColor, "%*sIterate Op: %s\n", nLevel, " ", pStructMem->m_nStartOperatorName );
}
void CSosOperatorIterateAndMergeSpeakers::OpHelp( ) const
{
}
void CSosOperatorIterateAndMergeSpeakers::ParseKV( CSosOperatorStack *pStack, void *pVoidMem, KeyValues *pOpKeys ) const
{
CSosOperatorIterateAndMergeSpeakers_t *pStructMem = (CSosOperatorIterateAndMergeSpeakers_t *)pVoidMem;
KeyValues *pParams = pOpKeys->GetFirstSubKey();
while ( pParams )
{
const char *pParamString = pParams->GetName();
const char *pValueString = pParams->GetString();
if ( pParamString && *pParamString )
{
if ( pValueString && *pValueString )
{
if ( BaseParseKV( pStack, (CSosOperator_t *)pStructMem, pParamString, pValueString ) )
{
}
else if ( !V_strcasecmp( pParamString, "iterate_operator" ) )
{
Q_strncpy( pStructMem->m_nStartOperatorName, pValueString, sizeof(pStructMem->m_nStartOperatorName) );
}
else
{
Log_Warning( LOG_SND_OPERATORS, "Error: Operator %s, unknown sound operator attribute %s\n", pStack->m_pCurrentOperatorName, pParamString );
}
}
}
pParams = pParams->GetNextKey();
}
}
@@ -0,0 +1,37 @@
//============ Copyright (c) Valve Corporation, All rights reserved. ============
//
//
//
//===============================================================================
#ifndef SOS_OP_ITERATE_MERGE_H
#define SOS_OP_ITERATE_MERGE_H
#ifdef _WIN32
#pragma once
#endif
#include "sos_op.h"
//-----------------------------------------------------------------------------
// calculate and merge multiple pass speaker volumes
//-----------------------------------------------------------------------------
struct CSosOperatorIterateAndMergeSpeakers_t : CSosOperator_t
{
char m_nStartOperatorName[64];
int m_nMaxIterations;
int m_nOperatorIndex;
SOS_OUTPUT_FLOAT( m_flOutputIndex, SO_SINGLE )
SOS_INPUT_FLOAT( m_flInputMaxIterations, SO_SINGLE )
SOS_INPUT_FLOAT( m_flInputSpeakers, SO_SPEAKERS )
SOS_OUTPUT_FLOAT( m_flOutputSpeakers, SO_SPEAKERS )
};
class CSosOperatorIterateAndMergeSpeakers : public CSosOperator
{
SOS_HEADER_DESC( CSosOperatorIterateAndMergeSpeakers )
};
#endif // SOS_OP_ITERATE_MERGE_H
@@ -0,0 +1,89 @@
//============ Copyright (c) Valve Corporation, All rights reserved. ============
//
//
//===============================================================================
#include "audio_pch.h"
#include "tier2/interval.h"
#include "sos_op.h"
#include "sos_op_map_name.h"
#include "snd_dma.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
extern Color OpColor;
extern Color ConnectColor;
extern Color ResultColor;
//-----------------------------------------------------------------------------
// CSosOperatorMapName
// Setting a single, simple scratch pad Expression
//-----------------------------------------------------------------------------
SOS_BEGIN_OPERATOR_CONSTRUCTOR( CSosOperatorMapName, "get_map_name" )
SOS_REGISTER_OUTPUT_FLOAT( CSosOperatorMapName, m_flOutput, SO_SINGLE, "output" )
SOS_END_OPERATOR_CONSTRUCTOR( CSosOperatorMapName, "get_map_name" )
void CSosOperatorMapName::SetDefaults( void *pVoidMem ) const
{
CSosOperatorMapName_t *pStructMem = (CSosOperatorMapName_t *)pVoidMem;
SOS_INIT_OUTPUT_VAR( m_flOutput, SO_SINGLE, 0.0 )
}
void CSosOperatorMapName::Execute( void *pVoidMem, channel_t *pChannel, CScratchPad *pScratchPad, CSosOperatorStack *pStack, int nOpIndex ) const
{
// CSosOperatorMapName_t *pStructMem = (CSosOperatorMapName_t *)pVoidMem;
}
void CSosOperatorMapName::Print( void *pVoidMem, CSosOperatorStack *pStack, int nOpIndex, int nLevel ) const
{
// CSosOperatorMapName_t *pStructMem = (CSosOperatorMapName_t *)pVoidMem;
PrintBaseParams( pVoidMem, pStack, nOpIndex, nLevel );
}
void CSosOperatorMapName::OpHelp( ) const
{
}
void CSosOperatorMapName::ParseKV( CSosOperatorStack *pStack, void *pVoidMem, KeyValues *pOpKeys ) const
{
extern IVEngineClient *engineClient;
CSosOperatorMapName_t *pStructMem = (CSosOperatorMapName_t *)pVoidMem;
KeyValues *pParams = pOpKeys->GetFirstSubKey();
while ( pParams )
{
const char *pParamString = pParams->GetName();
const char *pValueString = pParams->GetString();
if ( pParamString && *pParamString )
{
if ( pValueString && *pValueString )
{
if( BaseParseKV( pStack, (CSosOperator_t *)pStructMem, pParamString, pValueString ))
{
}
else if ( !V_strcasecmp( pParamString, "map_name" ) )
{
pStructMem->m_flOutput[0] = 0.0;
if( ! V_strcmp( engineClient->GetLevelNameShort(), pValueString ) )
{
pStructMem->m_flOutput[0] = 1.0;
}
}
else
{
Log_Warning( LOG_SND_OPERATORS, "Error: Operator %s, unknown sound operator attribute %s\n", pStack->m_pCurrentOperatorName, pParamString );
}
}
}
pParams = pParams->GetNextKey();
}
}
@@ -0,0 +1,31 @@
//============ Copyright (c) Valve Corporation, All rights reserved. ============
//
//
//
//===============================================================================
#ifndef SOS_OP_MAPNAME_H
#define SOS_OP_MAPNAME_H
#ifdef _WIN32
#pragma once
#endif
#include "sos_op.h"
//-----------------------------------------------------------------------------
// mapname
//-----------------------------------------------------------------------------
struct CSosOperatorMapName_t : CSosOperator_t
{
SOS_OUTPUT_FLOAT( m_flOutput, SO_SINGLE )
};
class CSosOperatorMapName : public CSosOperator
{
SOS_HEADER_DESC( CSosOperatorMapName )
};
#endif // SOS_OP_MAPNAME
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,296 @@
//============ Copyright (c) Valve Corporation, All rights reserved. ============
//
//
//
//===============================================================================
#ifndef SOS_OP_MATH_H
#define SOS_OP_MATH_H
#ifdef _WIN32
#pragma once
#endif
#include "sos_op.h"
enum SOOpCurveType_t
{
SO_OP_CURVETYPE_NONE = 0,
SO_OP_CURVETYPE_STEP,
SO_OP_CURVETYPE_LINEAR,
};
enum SOOpType_t
{
SO_OP_NONE = 0,
SO_OP_SET,
SO_OP_ADD,
SO_OP_SUB,
SO_OP_MULT,
SO_OP_DIV,
SO_OP_MOD,
SO_OP_MAX,
SO_OP_MIN,
SO_OP_INV,
SO_OP_GT,
SO_OP_LT,
SO_OP_GTOE,
SO_OP_LTOE,
SO_OP_EQ,
SO_OP_NOT_EQ,
SO_OP_INV_SCALE,
SO_OP_POW
};
enum SOFunc1Type_t
{
SO_FUNC1_NONE = 0,
SO_FUNC1_SIN,
SO_FUNC1_ASIN,
SO_FUNC1_COS,
SO_FUNC1_ACOS,
SO_FUNC1_TAN,
SO_FUNC1_ATAN,
SO_FUNC1_SINH,
SO_FUNC1_ASINH,
SO_FUNC1_COSH,
SO_FUNC1_ACOSH,
SO_FUNC1_TANH,
SO_FUNC1_ATANH,
SO_FUNC1_EXP,
SO_FUNC1_EXPM1,
SO_FUNC1_EXP2,
SO_FUNC1_LOG,
SO_FUNC1_LOG2,
SO_FUNC1_LOG1P,
SO_FUNC1_LOG10,
SO_FUNC1_LOGB,
SO_FUNC1_FABS,
SO_FUNC1_SQRT,
SO_FUNC1_ERF,
SO_FUNC1_ERFC,
SO_FUNC1_GAMMA,
SO_FUNC1_LGAMMA,
SO_FUNC1_CEIL,
SO_FUNC1_FLOOR,
SO_FUNC1_RINT,
SO_FUNC1_NEARBYINT,
SO_FUNC1_RINTOL,
SO_FUNC1_ROUND,
SO_FUNC1_ROUNDTOL,
SO_FUNC1_TRUNC,
};
//-----------------------------------------------------------------------------
// simple operator for single argument functions
//-----------------------------------------------------------------------------
struct CSosOperatorFunc1_t : CSosOperator_t
{
SOS_INPUT_FLOAT( m_flInput1, SO_SINGLE )
SOS_OUTPUT_FLOAT( m_flOutput, SO_SINGLE )
SOFunc1Type_t m_funcType;
bool m_bNormTrig;
};
class CSosOperatorFunc1 : public CSosOperator
{
SOS_HEADER_DESC( CSosOperatorFunc1 )
};
//-----------------------------------------------------------------------------
// simple operator for setting a single scratchpad Expression
//-----------------------------------------------------------------------------
struct CSosOperatorFloat_t : CSosOperator_t
{
SOS_INPUT_FLOAT( m_flInput1, SO_SINGLE )
SOS_INPUT_FLOAT( m_flInput2, SO_SINGLE )
SOS_OUTPUT_FLOAT( m_flOutput, SO_SINGLE )
SOOpType_t m_opType;
};
class CSosOperatorFloat : public CSosOperator
{
SOS_HEADER_DESC( CSosOperatorFloat )
};
//-----------------------------------------------------------------------------
// simple operator for setting a single scratchpad Expression
//-----------------------------------------------------------------------------
struct CSosOperatorFloatAccumulate12_t : CSosOperator_t
{
SOS_INPUT_FLOAT( m_flInput1, SO_SINGLE )
SOS_INPUT_FLOAT( m_flInput2, SO_SINGLE )
SOS_INPUT_FLOAT( m_flInput3, SO_SINGLE )
SOS_INPUT_FLOAT( m_flInput4, SO_SINGLE )
SOS_INPUT_FLOAT( m_flInput5, SO_SINGLE )
SOS_INPUT_FLOAT( m_flInput6, SO_SINGLE )
SOS_INPUT_FLOAT( m_flInput7, SO_SINGLE )
SOS_INPUT_FLOAT( m_flInput8, SO_SINGLE )
SOS_INPUT_FLOAT( m_flInput9, SO_SINGLE )
SOS_INPUT_FLOAT( m_flInput10, SO_SINGLE )
SOS_INPUT_FLOAT( m_flInput11, SO_SINGLE )
SOS_INPUT_FLOAT( m_flInput12, SO_SINGLE )
SOS_OUTPUT_FLOAT( m_flOutput, SO_SINGLE )
SOOpType_t m_opType;
};
class CSosOperatorFloatAccumulate12 : public CSosOperator
{
SOS_HEADER_DESC( CSosOperatorFloatAccumulate12 )
};
//-----------------------------------------------------------------------------
// simple operator for setting a single position
//-----------------------------------------------------------------------------
struct CSosOperatorVec3_t : CSosOperator_t
{
SOS_INPUT_FLOAT( m_flInput1, SO_VEC3 )
SOS_INPUT_FLOAT( m_flInput2, SO_VEC3 )
SOS_OUTPUT_FLOAT( m_flOutput, SO_VEC3 )
SOOpType_t m_opType;
};
class CSosOperatorVec3 : public CSosOperator
{
SOS_HEADER_DESC( CSosOperatorVec3 )
};
//-----------------------------------------------------------------------------
// simple operator for settting a single speaker scratchpad expression
//-----------------------------------------------------------------------------
struct CSosOperatorSpeakers_t : CSosOperator_t
{
SOS_INPUT_FLOAT( m_flInput1, SO_SPEAKERS )
SOS_INPUT_FLOAT( m_flInput2, SO_SPEAKERS )
SOS_OUTPUT_FLOAT( m_flOutput, SO_SPEAKERS )
SOOpType_t m_opType;
};
class CSosOperatorSpeakers : public CSosOperator
{
SOS_HEADER_DESC( CSosOperatorSpeakers )
};
//-----------------------------------------------------------------------------
// distance between 2 positions
//-----------------------------------------------------------------------------
struct CSosOperatorSourceDistance_t : CSosOperator_t
{
SOS_INPUT_FLOAT( m_flInputPos, SO_VEC3 )
SOS_OUTPUT_FLOAT( m_flOutput, SO_SINGLE )
bool m_b2D;
bool m_bForceNotPlayerSound;
};
class CSosOperatorSourceDistance : public CSosOperator
{
SOS_HEADER_DESC( CSosOperatorSourceDistance )
};
//-----------------------------------------------------------------------------
// RemapValue
//-----------------------------------------------------------------------------
struct CSosOperatorRemapValue_t : CSosOperator_t
{
SOS_INPUT_FLOAT(m_flInputMin, SO_SINGLE )
SOS_INPUT_FLOAT(m_flInputMax, SO_SINGLE )
SOS_INPUT_FLOAT(m_flInputMapMin, SO_SINGLE )
SOS_INPUT_FLOAT(m_flInputMapMax, SO_SINGLE )
SOS_INPUT_FLOAT(m_flInput, SO_SINGLE )
SOS_OUTPUT_FLOAT( m_flOutput, SO_SINGLE )
bool m_bClampRange;
bool m_bDefaultMax;
};
class CSosOperatorRemapValue : public CSosOperator
{
SOS_HEADER_DESC( CSosOperatorRemapValue )
};
//-----------------------------------------------------------------------------
// Curve4
//-----------------------------------------------------------------------------
struct CSosOperatorCurve4_t : CSosOperator_t
{
SOS_INPUT_FLOAT(m_flInputX1, SO_SINGLE )
SOS_INPUT_FLOAT(m_flInputY1, SO_SINGLE )
SOS_INPUT_FLOAT(m_flInputX2, SO_SINGLE )
SOS_INPUT_FLOAT(m_flInputY2, SO_SINGLE )
SOS_INPUT_FLOAT(m_flInputX3, SO_SINGLE )
SOS_INPUT_FLOAT(m_flInputY3, SO_SINGLE )
SOS_INPUT_FLOAT(m_flInputX4, SO_SINGLE )
SOS_INPUT_FLOAT(m_flInputY4, SO_SINGLE )
SOS_INPUT_FLOAT(m_flInput, SO_SINGLE )
SOS_OUTPUT_FLOAT( m_flOutput, SO_SINGLE )
SOOpCurveType_t m_nCurveType;
};
class CSosOperatorCurve4 : public CSosOperator
{
SOS_HEADER_DESC( CSosOperatorCurve4 )
};
//-----------------------------------------------------------------------------
// Facing
//-----------------------------------------------------------------------------
struct CSosOperatorFacing_t : CSosOperator_t
{
SOS_INPUT_FLOAT(m_flInputAngles, SO_VEC3 )
SOS_OUTPUT_FLOAT( m_flOutput, SO_SINGLE )
};
class CSosOperatorFacing : public CSosOperator
{
SOS_HEADER_DESC( CSosOperatorFacing )
};
//-----------------------------------------------------------------------------
// Facing
//-----------------------------------------------------------------------------
struct CSosOperatorRandom_t : CSosOperator_t
{
SOS_INPUT_FLOAT(m_flInputMin, SO_SINGLE )
SOS_INPUT_FLOAT(m_flInputMax, SO_SINGLE )
SOS_INPUT_FLOAT(m_flInputSeed, SO_SINGLE )
SOS_OUTPUT_FLOAT( m_flOutput, SO_SINGLE )
bool m_bRoundToInt;
};
class CSosOperatorRandom : public CSosOperator
{
SOS_HEADER_DESC( CSosOperatorRandom )
};
//-----------------------------------------------------------------------------
// Logic Switch
//-----------------------------------------------------------------------------
struct CSosOperatorLogicSwitch_t : CSosOperator_t
{
SOS_INPUT_FLOAT(m_flInput1, SO_SINGLE )
SOS_INPUT_FLOAT(m_flInput2, SO_SINGLE )
SOS_INPUT_FLOAT(m_flInputSwitch, SO_SINGLE )
SOS_OUTPUT_FLOAT( m_flOutput, SO_SINGLE )
};
class CSosOperatorLogicSwitch : public CSosOperator
{
SOS_HEADER_DESC( CSosOperatorLogicSwitch )
};
#endif // SOS_OP_MATH_H
@@ -0,0 +1,149 @@
//============ Copyright (c) Valve Corporation, All rights reserved. ============
//
//
//===============================================================================
#include "audio_pch.h"
#include "tier2/interval.h"
#include "sos_op.h"
#include "sos_op_mixer.h"
#include "snd_mixgroups.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
extern Color OpColor;
extern Color ConnectColor;
extern Color ResultColor;
//-----------------------------------------------------------------------------
// CSosOperatorMixGroup
// Catchall operator
//-----------------------------------------------------------------------------
SOS_BEGIN_OPERATOR_CONSTRUCTOR( CSosOperatorMixGroup, "get_soundmixer" )
SOS_REGISTER_OUTPUT_FLOAT( CSosOperatorMixGroup, m_flOutputVolume, SO_SINGLE, "output_volume" );
SOS_REGISTER_OUTPUT_FLOAT( CSosOperatorMixGroup, m_flOutputLevel, SO_SINGLE, "output_level" );
SOS_REGISTER_OUTPUT_FLOAT( CSosOperatorMixGroup, m_flOutputDSP, SO_SINGLE, "output_dsp" );
SOS_END_OPERATOR_CONSTRUCTOR( CSosOperatorMixGroup, "get_soundmixer" )
void CSosOperatorMixGroup::SetDefaults( void *pVoidMem ) const
{
CSosOperatorMixGroup_t *pStructMem = (CSosOperatorMixGroup_t *)pVoidMem;
pStructMem->m_nMixGroupIndex = -1;
pStructMem->m_bSetMixGroupOnChannel = false;
SOS_INIT_OUTPUT_VAR( m_flOutputVolume, SO_SINGLE, 1.0 )
SOS_INIT_OUTPUT_VAR( m_flOutputLevel, SO_SINGLE, 1.0 )
SOS_INIT_OUTPUT_VAR( m_flOutputDSP, SO_SINGLE, 1.0 )
}
void CSosOperatorMixGroup::Execute( void *pVoidMem, channel_t *pChannel, CScratchPad *pScratchPad, CSosOperatorStack *pStack, int nOpIndex ) const
{
CSosOperatorMixGroup_t *pStructMem = (CSosOperatorMixGroup_t *)pVoidMem;
if( !pChannel )
{
Log_Warning( LOG_SND_OPERATORS, "Error: Sound operator %s requires valid channel pointer, being called without one\n", pStack->GetOperatorName( nOpIndex ));
return;
}
if ( pStructMem->m_nMixGroupIndex < 0 )
{
char sndname[MAX_PATH];
pChannel->sfx->getname(sndname, sizeof(sndname));
MXR_GetMixGroupFromSoundsource( pChannel );
pStructMem->m_nMixGroupIndex = MXR_GetFirstValidMixGroup( pChannel );
// DevMsg( "***FILE: %s: INDEX: %i: MIXGROUP: %s\n", sndname, pStructMem->m_nMixGroupIndex, MXR_GetGroupnameFromId( pStructMem->m_nMixGroupIndex ));
if ( pStructMem->m_nMixGroupIndex < 0 )
{
Log_Warning( LOG_SND_OPERATORS, "Error: MixGroup index error, %s, %s", sndname, MXR_GetGroupnameFromId( pStructMem->m_nMixGroupIndex ));
return;
}
}
if( pStructMem->m_bSetMixGroupOnChannel && pChannel )
{
pChannel->mixgroups[0] = pStructMem->m_nMixGroupIndex;
}
mixervalues_t mixValues;
MXR_GetValuesFromMixGroupIndex( &mixValues, pStructMem->m_nMixGroupIndex );
pStructMem->m_flOutputLevel[0] = mixValues.level;
pStructMem->m_flOutputVolume[0] = mixValues.volume;
pStructMem->m_flOutputDSP[0] = mixValues.dsp;
pChannel->last_mixgroupid = pStructMem->m_nMixGroupIndex;
}
void CSosOperatorMixGroup::Print( void *pVoidMem, CSosOperatorStack *pStack, int nOpIndex, int nLevel ) const
{
PrintBaseParams( pVoidMem, pStack, nOpIndex, nLevel );
CSosOperatorMixGroup_t *pStructMem = (CSosOperatorMixGroup_t *)pVoidMem;
Log_Msg( LOG_SND_OPERATORS, OpColor, "%*smixgroup: %s\n", nLevel, " ", MXR_GetGroupnameFromId( pStructMem->m_nMixGroupIndex ));
}
void CSosOperatorMixGroup::OpHelp( ) const
{
}
void CSosOperatorMixGroup::ParseKV( CSosOperatorStack *pStack, void *pVoidMem, KeyValues *pOpKeys ) const
{
CSosOperatorMixGroup_t *pStructMem = (CSosOperatorMixGroup_t *)pVoidMem;
bool bHasMixGroupIndex = false;
KeyValues *pParams = pOpKeys->GetFirstSubKey();
while ( pParams )
{
const char *pParamString = pParams->GetName();
const char *pValueString = pParams->GetString();
if ( pParamString && *pParamString )
{
if ( pValueString && *pValueString )
{
if ( BaseParseKV( pStack, (CSosOperator_t *)pStructMem, pParamString, pValueString ) )
{
}
else if ( !V_strcasecmp( pParamString, "set_mixgroup_to_channel" ) )
{
if ( !V_strcasecmp( pValueString, "false" ) )
{
pStructMem->m_bSetMixGroupOnChannel = false;
}
else if ( !V_strcasecmp( pValueString, "true" ) )
{
pStructMem->m_bSetMixGroupOnChannel = true;
}
}
else if ( !V_strcasecmp( pParamString, "mixgroup" ) )
{
pStructMem->m_nMixGroupIndex = MXR_GetMixgroupFromName( pValueString );
if ( pStructMem->m_nMixGroupIndex > -1 )
{
bHasMixGroupIndex = true;
}
}
else
{
Log_Warning( LOG_SND_OPERATORS, "Error: Operator %s, unknown sound operator attribute %s\n", pStack->m_pCurrentOperatorName, pParamString );
}
}
}
pParams = pParams->GetNextKey();
}
/* if ( !bHasMixGroupIndex )
{
MXR_GetMixGroupFromSoundsource( pStructMem->m_pChannel );
pStructMem->m_nMixGroupIndex = MXR_GetFirstValidMixGroup( pStructMem->m_pChannel );
}
*/
}
@@ -0,0 +1,34 @@
//============ Copyright (c) Valve Corporation, All rights reserved. ============
//
//
//
//===============================================================================
#ifndef SOS_OP_MIXER_H
#define SOS_OP_MIXER_H
#ifdef _WIN32
#pragma once
#endif
#include "sos_op.h"
//-----------------------------------------------------------------------------
// basic mixgroup operator
//-----------------------------------------------------------------------------
struct CSosOperatorMixGroup_t : CSosOperator_t
{
int m_nMixGroupIndex;
bool m_bSetMixGroupOnChannel;
SOS_OUTPUT_FLOAT( m_flOutputVolume, SO_SINGLE )
SOS_OUTPUT_FLOAT( m_flOutputLevel, SO_SINGLE )
SOS_OUTPUT_FLOAT( m_flOutputDSP, SO_SINGLE )
};
class CSosOperatorMixGroup : public CSosOperator
{
SOS_HEADER_DESC( CSosOperatorMixGroup )
};
#endif // SOS_OP_MIXER
@@ -0,0 +1,163 @@
//============ Copyright (c) Valve Corporation, All rights reserved. ============
//
//
//===============================================================================
#include "audio_pch.h"
#include "tier2/interval.h"
#include "sos_op_mixlayer.h"
// #include "cdll_engine_int.h"
#include "../../debugoverlay.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
extern Color OpColor;
extern Color ConnectColor;
extern Color ResultColor;
//-----------------------------------------------------------------------------
// CSosOperatorMixLayer
//-----------------------------------------------------------------------------
SOS_BEGIN_OPERATOR_CONSTRUCTOR( CSosOperatorMixLayer, "sys_mixlayer" )
SOS_REGISTER_INPUT_FLOAT( CSosOperatorMixLayer, m_flInput, SO_SINGLE, "input" )
SOS_END_OPERATOR_CONSTRUCTOR( CSosOperatorMixLayer, "sys_mixlayer" )
void CSosOperatorMixLayer::SetDefaults( void *pVoidMem ) const
{
CSosOperatorMixLayer_t *pStructMem = (CSosOperatorMixLayer_t *)pVoidMem;
SOS_INIT_INPUT_VAR( m_flInput, SO_SINGLE, 0.0 )
pStructMem->m_nFieldType = MXR_MIXGROUP_NONE;
pStructMem->m_nMixLayerIndex = -1;
pStructMem->m_nMixGroupIndex = -1;
}
void CSosOperatorMixLayer::Execute( void *pVoidMem, channel_t *pChannel, CScratchPad *pScratchPad, CSosOperatorStack *pStack, int nOpIndex ) const
{
CSosOperatorMixLayer_t *pStructMem = (CSosOperatorMixLayer_t *)pVoidMem;
if( pStructMem->m_nMixGroupIndex < 0 )
{
Log_Warning( LOG_SND_OPERATORS, "Error: MixLayer operator has invalid mix group index!\n" );
return;
}
if( pStructMem->m_nMixLayerIndex < 0 )
{
Log_Warning( LOG_SND_OPERATORS, "Error: MixLayer operator has invalid mix layer index!\n" );
return;
}
S_SetMixGroupOfMixLayer( pStructMem->m_nMixGroupIndex, pStructMem->m_nMixLayerIndex, pStructMem->m_nFieldType, pStructMem->m_flInput[0] );
}
void CSosOperatorMixLayer::Print( void *pVoidMem, CSosOperatorStack *pStack, int nOpIndex, int nLevel ) const
{
CSosOperatorMixLayer_t *pStructMem = (CSosOperatorMixLayer_t *)pVoidMem;
PrintBaseParams( pVoidMem, pStack, nOpIndex, nLevel );
const char *pFieldTypeString = "none";
switch( pStructMem->m_nFieldType )
{
case MXR_MIXGROUP_VOL:
pFieldTypeString = "volume";
break;
case MXR_MIXGROUP_LEVEL:
pFieldTypeString = "level";
break;
case MXR_MIXGROUP_DSP:
pFieldTypeString = "dsp";
break;
case MXR_MIXGROUP_SOLO:
pFieldTypeString = "solo";
break;
case MXR_MIXGROUP_MUTE:
pFieldTypeString = "mute";
break;
default:
break;
}
Log_Msg( LOG_SND_OPERATORS, OpColor, "%*sField: %s\n", nLevel, " ", pFieldTypeString );
}
void CSosOperatorMixLayer::OpHelp( ) const
{
}
void CSosOperatorMixLayer::ParseKV( CSosOperatorStack *pStack, void *pVoidMem, KeyValues *pOpKeys ) const
{
CSosOperatorMixLayer_t *pStructMem = (CSosOperatorMixLayer_t *)pVoidMem;
KeyValues *pParams = pOpKeys->GetFirstSubKey();
while ( pParams )
{
const char *pParamString = pParams->GetName();
const char *pValueString = pParams->GetString();
if ( pParamString && *pParamString )
{
if ( pValueString && *pValueString )
{
if ( BaseParseKV( pStack, (CSosOperator_t *)pStructMem, pParamString, pValueString ))
{
}
else if ( !V_strcasecmp( pParamString, "field" ) )
{
if ( !V_strcasecmp( pValueString, "volume" ) )
{
pStructMem->m_nFieldType = MXR_MIXGROUP_VOL;
}
else if ( !V_strcasecmp( pValueString, "level" ) )
{
pStructMem->m_nFieldType = MXR_MIXGROUP_LEVEL;
}
else if ( !V_strcasecmp( pValueString, "dsp" ) )
{
pStructMem->m_nFieldType = MXR_MIXGROUP_DSP;
}
else if ( !V_strcasecmp( pValueString, "solo" ) )
{
pStructMem->m_nFieldType = MXR_MIXGROUP_SOLO;
}
else if ( !V_strcasecmp( pValueString, "mute" ) )
{
pStructMem->m_nFieldType = MXR_MIXGROUP_MUTE;
}
}
else if ( !V_strcasecmp( pParamString, "mixlayer" ) )
{
int nMixLayerID = MXR_GetMixLayerIndexFromName( pValueString );
if ( nMixLayerID == -1 )
{
Log_Warning( LOG_SND_OPERATORS, "Error: Failed to get mix layer %s!\n", pValueString );
}
pStructMem->m_nMixLayerIndex = nMixLayerID;
}
else if ( !V_strcasecmp( pParamString, "mixgroup" ) )
{
int nMixGroupID = S_GetMixGroupIndex( pValueString );
if ( nMixGroupID == -1 )
{
Log_Warning( LOG_SND_OPERATORS, "Error: Failed to get mix group %s!\n", pValueString );
}
pStructMem->m_nMixGroupIndex = nMixGroupID;
}
else
{
Log_Warning( LOG_SND_OPERATORS, "Error: Operator %s, unknown sound operator attribute %s\n", pStack->m_pCurrentOperatorName, pParamString );
}
}
}
pParams = pParams->GetNextKey();
}
}
@@ -0,0 +1,34 @@
//============ Copyright (c) Valve Corporation, All rights reserved. ============
//
//
//
//===============================================================================
#ifndef SOS_OP_MIXLAYER_H
#define SOS_OP_MIXLAYER_H
#ifdef _WIN32
#pragma once
#endif
#include "sos_op.h"
#include "snd_mixgroups.h"
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
struct CSosOperatorMixLayer_t : CSosOperator_t
{
SOS_INPUT_FLOAT( m_flInput, SO_SINGLE )
MXRMixGroupFields_t m_nFieldType;
int m_nMixLayerIndex;
int m_nMixGroupIndex;
};
class CSosOperatorMixLayer : public CSosOperator
{
SOS_HEADER_DESC( CSosOperatorMixLayer )
};
#endif // SOS_OP_MIXLAYER_H

Some files were not shown because too many files have changed in this diff Show More