initial
This commit is contained in:
@@ -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()
|
||||
{
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
|
||||
@@ -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
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
@@ -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
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
@@ -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
@@ -0,0 +1,10 @@
|
||||
//========= Copyright © 1996-2007, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $Workfile: $
|
||||
// $Date: $
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#include "audio_pch.h"
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
};
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -0,0 +1,10 @@
|
||||
//========= Copyright © 1996-2007, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $Workfile: $
|
||||
// $Date: $
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#include "audio_pch.h"
|
||||
@@ -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
|
||||
@@ -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 );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
@@ -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
@@ -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
|
||||
@@ -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 system‚use 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 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
@@ -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
@@ -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
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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 ) );
|
||||
}
|
||||
}
|
||||
@@ -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
Reference in New Issue
Block a user