openmohaa/code/client/snd_dma_new.cpp

831 lines
17 KiB
C++
Raw Normal View History

/*
===========================================================================
Copyright (C) 2024 the OpenMoHAA team
This file is part of OpenMoHAA source code.
OpenMoHAA source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
OpenMoHAA source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OpenMoHAA source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#include "snd_local.h"
#include "snd_openal_new.h"
#include "client.h"
#include "cl_ui.h"
typedef struct {
vec3_t origin;
vec3_t velocity;
sfx_t *sfx;
int mergeFrame;
} loopSound_t;
qboolean s_bLastInitSound = qfalse;
qboolean s_bSoundStarted = qfalse;
qboolean s_bSoundPaused = qfalse;
qboolean s_bTryUnpause = qfalse;
int s_iListenerNumber = 0;
float s_fAmbientVolume = 1.f;
int number_of_sfx_infos = 0;
cvar_t *s_volume;
cvar_t *s_loadas8bit;
cvar_t *s_khz;
cvar_t *s_show;
cvar_t *s_testsound;
cvar_t *s_separation;
cvar_t *s_musicVolume;
cvar_t *s_ambientVolume;
sfx_info_t sfx_infos[MAX_SFX_INFOS];
sfx_t s_knownSfx[MAX_SFX];
int s_numSfx;
s_entity_t s_entity[MAX_GENTITIES];
static int s_registrationSequence;
static qboolean s_inRegistration;
cvar_t *s_mixPreStep;
cvar_t *s_dialogscale;
int numLoopSounds;
loopSound_t loopSounds[MAX_LOOP_SOUNDS];
2024-01-08 20:07:26 +01:00
/*
==============
S_SoundInfo_f
==============
*/
void S_SoundInfo_f()
{
2024-01-08 20:07:26 +01:00
S_PrintInfo();
}
2024-01-08 20:07:26 +01:00
/*
==============
S_SoundDump_f
==============
*/
void S_SoundDump_f()
{
2024-01-08 20:07:26 +01:00
S_DumpInfo();
}
2024-01-08 20:07:26 +01:00
/*
==============
S_Init
==============
*/
void S_Init(qboolean full_startup)
{
2024-01-08 20:07:26 +01:00
int iStart, iEnd;
cvar_t *cv;
Com_Printf("------- Sound Initialization (%s) -------\n", full_startup ? "full" : "partial");
iStart = Sys_Milliseconds();
s_volume = Cvar_Get("s_volume", "0.9", CVAR_ARCHIVE);
s_musicVolume = Cvar_Get("s_musicvolume", "0.9", CVAR_ARCHIVE);
s_ambientVolume = Cvar_Get("s_ambientvolume", "1.00", CVAR_ARCHIVE);
s_separation = Cvar_Get("s_separation", "0.5", CVAR_ARCHIVE);
s_khz = Cvar_Get("s_khz", "11", CVAR_ARCHIVE | CVAR_SOUND_LATCH);
s_loadas8bit = Cvar_Get("s_loadas8bit", "0", CVAR_ARCHIVE | CVAR_LATCH);
s_mixPreStep = Cvar_Get("s_mixPreStep", "0.05", CVAR_ARCHIVE);
s_show = Cvar_Get("s_show", "0", CVAR_CHEAT);
s_testsound = Cvar_Get("s_testsound", "0", CVAR_CHEAT);
s_dialogscale = Cvar_Get("s_dialogscale", "1", CVAR_ARCHIVE);
s_bLastInitSound = false;
cv = Cvar_Get("s_initsound", "1", 0);
if (cv->integer) {
Cmd_AddCommand("play", S_Play);
Cmd_AddCommand("soundlist", S_SoundList);
Cmd_AddCommand("soundinfo", S_SoundInfo_f);
Cmd_AddCommand("sounddump", S_SoundDump_f);
if (S_Driver_Init()) {
s_bLastInitSound = true;
s_bSoundStarted = true;
if (full_startup) {
s_numSfx = 0;
S_StopAllSounds(true);
}
S_FindName("***DEFAULT***", -1);
S_SoundInfo_f();
}
} else {
Com_Printf("Sound Not Initializing.\n");
s_bSoundStarted = 0;
}
iEnd = Sys_Milliseconds();
Com_Printf("------- Sound Initialization Complete ------- %i ms\n", iEnd - iStart);
}
2024-01-08 20:07:26 +01:00
/*
==============
S_Shutdown
==============
*/
void S_Shutdown(qboolean full_shutdown)
{
2024-01-08 20:07:26 +01:00
int i;
sfx_t *sfx;
if (!s_bSoundStarted) {
return;
}
Com_Printf("------- Sound Shutdown (%s) -------\n", full_shutdown ? "full" : "partial");
S_Driver_Shutdown();
s_bSoundStarted = false;
Cmd_RemoveCommand("play");
Cmd_RemoveCommand("music");
Cmd_RemoveCommand("stopsound");
Cmd_RemoveCommand("soundlist");
Cmd_RemoveCommand("soundinfo");
if (full_shutdown) {
for (i = 0; i < s_numSfx; i++) {
sfx = &s_knownSfx[i];
if (sfx->name[0]) {
if (sfx->data) {
Z_Free(sfx->data);
}
*sfx = {};
}
}
s_numSfx = 0;
}
Com_Printf("------- Sound Shutdown Complete -------\n");
}
2024-01-08 20:07:26 +01:00
/*
==============
S_NameExists
==============
*/
qboolean S_NameExists(const char *name)
{
2024-01-08 20:07:26 +01:00
int i;
if (strlen(name) >= MAX_RES_NAME) {
Com_DPrintf("Sound name too long: %s", name);
return qfalse;
}
for (i = 0; i < s_numSfx; i++) {
if (!strcmp(s_knownSfx[i].name, name)) {
return qtrue;
}
}
return qfalse;
}
2024-01-08 20:07:26 +01:00
/*
==============
S_FindName
==============
*/
sfx_t *S_FindName(const char *name, int sequenceNumber)
{
2024-01-08 20:07:26 +01:00
int i;
sfx_t *sfx;
if (!name) {
Com_DPrintf("S_FindName: NULL\n");
return NULL;
}
if (!name[0]) {
Com_DPrintf("S_FindName: empty name\n");
return NULL;
}
if (strlen(name) >= MAX_RES_NAME) {
Com_DPrintf("Sound name too long: %s", name);
return NULL;
}
for (i = 0; i < s_numSfx; i++) {
sfx = &s_knownSfx[i];
if (!strcmp(sfx->name, name)) {
if (sfx->registration_sequence != -1) {
sfx->registration_sequence = sequenceNumber;
}
return sfx;
}
}
sfx = &s_knownSfx[0];
for (i = 0; i < s_numSfx; i++) {
sfx = &s_knownSfx[i];
if (!sfx->name[0]) {
break;
}
}
if (i == s_numSfx) {
if (i == MAX_SFX) {
Com_Error(ERR_FATAL, "S_FindName: out of sfx_t");
}
sfx = &s_knownSfx[s_numSfx];
2024-01-08 20:07:26 +01:00
s_numSfx++;
}
*sfx = {};
// Fixed in OPM
// strcpy was used before
//strcpy(sfx->name, name);
Q_strncpyz(sfx->name, name, sizeof(sfx->name));
sfx->registration_sequence = sequenceNumber;
return sfx;
}
2024-01-08 20:07:26 +01:00
/*
==============
S_BeginRegistration
==============
*/
void S_BeginRegistration()
{
2024-09-29 13:30:56 +02:00
int i;
2024-01-08 20:07:26 +01:00
Com_Printf("------- Sound Begin Registration -------\n");
S_StopAllSounds(true);
2024-09-29 13:30:56 +02:00
s_registrationSequence++;
2024-01-08 20:07:26 +01:00
s_inRegistration = true;
s_knownSfx[0].registration_sequence = s_registrationSequence;
Com_Printf("------- Sound Begin Registration Complete -------\n");
2024-09-29 13:30:56 +02:00
// Added in OPM
// Reset all sound entities
// OG doesn't do this but this makes sure
// entities don't leak info from previous sessions
for (i = 0; i < ARRAY_LEN(s_entity); i++) {
s_entity[i] = s_entity_t{};
}
}
2024-01-08 20:07:26 +01:00
/*
==============
S_DefaultSound
==============
*/
void S_DefaultSound(sfx_t *sfx)
{
2024-01-08 20:07:26 +01:00
sfx->data = NULL;
sfx->iFlags |= SFX_FLAG_DEFAULT_SOUND;
}
2024-01-08 20:07:26 +01:00
/*
==============
S_IsSoundRegistered
==============
*/
qboolean S_IsSoundRegistered(const char *name)
{
2024-01-08 20:07:26 +01:00
char szCacheName[MAX_QPATH];
int i;
if (!s_bSoundStarted) {
return qfalse;
}
for (i = 0; name[i] && i < MAX_QPATH; i++) {
szCacheName[i] = tolower(name[i]);
}
szCacheName[i] = 0;
if (i >= MAX_QPATH) {
Com_Printf("Sound name exceeds MAX_QPATH\n");
return qfalse;
}
return S_NameExists(szCacheName);
}
2024-01-08 20:07:26 +01:00
/*
==============
S_RegisterSound
==============
*/
sfxHandle_t S_RegisterSound(const char *name, int streamed, qboolean force_load)
{
2024-01-08 20:07:26 +01:00
char szCacheName[MAX_QPATH];
sfx_t *sfx;
int i;
if (!s_bSoundStarted) {
Com_Printf("ERROR: Trying to register sound %s when soundsystem hasn't started.\n", name);
return 0;
}
if (!name) {
return 0;
}
for (i = 0; name[i] && i < MAX_QPATH; i++) {
szCacheName[i] = tolower(name[i]);
}
szCacheName[i] = 0;
if (i >= MAX_QPATH) {
Com_Printf("Sound name exceeds MAX_QPATH\n");
return 0;
}
sfx = S_FindName(szCacheName, s_registrationSequence);
if (!sfx) {
return 0;
}
if (!sfx->data) {
if (!S_LoadSound(sfx->name, sfx, streamed, force_load)) {
Com_DPrintf("Couldn't load sound: %s\n", sfx->name);
if (!S_LoadSound("sound/default.wav", sfx, streamed, 0)) {
Com_DPrintf("Couldn't load sound: sound/default.wav\n");
sfx->iFlags |= SFX_FLAG_DEFAULT_SOUND;
return 0;
}
}
sfx->iFlags &= ~SFX_FLAG_DEFAULT_SOUND;
sfx->sfx_info_index = 0;
for (i = 0; i < number_of_sfx_infos; i++) {
if (!Q_stricmp(sfx->name, sfx_infos[i].name)) {
sfx->sfx_info_index = i;
break;
}
}
}
return sfx - s_knownSfx;
}
2024-01-08 20:07:26 +01:00
/*
==============
S_GetSoundTime
==============
*/
float S_GetSoundTime(sfxHandle_t handle)
{
2024-01-08 20:07:26 +01:00
return s_knownSfx[handle].time_length;
}
2024-01-08 20:07:26 +01:00
/*
==============
S_EndRegistration
==============
*/
void S_EndRegistration()
{
2024-01-08 20:07:26 +01:00
int i;
sfx_t *sfx;
Com_Printf("------- Sound End Registration -------\n");
s_inRegistration = qfalse;
for (i = 0; i < s_numSfx; i++) {
sfx = &s_knownSfx[i];
if (!sfx->name[0]) {
continue;
}
if (sfx->registration_sequence && sfx->registration_sequence != s_registrationSequence) {
if (sfx->data) {
Z_Free(sfx->data);
}
*sfx = {};
}
}
Com_Printf("------- Sound End Registration Complete -------\n");
}
2024-01-08 20:07:26 +01:00
/*
==============
S_UpdateEntity
==============
*/
void S_UpdateEntity(int entityNum, const vec3_t origin, const vec3_t vel, qboolean use_listener)
{
2024-01-08 20:07:26 +01:00
if (entityNum > MAX_GENTITIES) {
Com_Error(ERR_DROP, "S_UpdateEntityPosition: bad entitynum %i", entityNum);
}
VectorCopy(origin, s_entity[entityNum].position);
VectorCopy(vel, s_entity[entityNum].velocity);
s_entity[entityNum].use_listener = use_listener;
s_entity[entityNum].time = cl.serverTime;
}
2024-01-08 20:07:26 +01:00
/*
==============
S_SetGlobalAmbientVolumeLevel
==============
*/
void S_SetGlobalAmbientVolumeLevel(float volume)
{
2024-01-08 20:07:26 +01:00
s_fAmbientVolume = volume;
}
2024-01-08 20:07:26 +01:00
/*
==============
S_StartSound
==============
*/
void S_StartSound(
const vec3_t origin,
int entnum,
int entchannel,
sfxHandle_t sfxHandle,
float volume,
float min_dist,
float pitch,
float maxDist,
int streamed
)
{
2024-01-08 20:07:26 +01:00
if (s_show_sounds->integer > 0 && sfxHandle > 0 && sfxHandle < s_numSfx) {
Com_DPrintf("S_StartSound: %s\n", s_knownSfx[sfxHandle].name);
}
if (!s_bSoundStarted) {
if (s_show_sounds->integer > 0) {
Com_DPrintf("^~^~^ sound system not yet started\n");
}
return;
}
if (server_loading) {
if (s_show_sounds->integer > 0) {
Com_DPrintf("^~^~^ cannot start sounds while loading a server\n");
}
return;
}
if (sfxHandle < 0 || sfxHandle >= s_numSfx) {
Com_Error(ERR_DROP, "S_StartSound: handle %i out of range", sfxHandle);
}
if (!sfxHandle) {
if (s_show_sounds->integer > 0) {
Com_DPrintf("^~^~^ null handle\n");
}
return;
}
if (entnum && (entchannel == CHAN_DIALOG || entchannel == CHAN_DIALOG_SECONDARY) && s_dialogscale->value > 0) {
volume *= s_dialogscale->value;
}
S_Driver_StartSound(origin, entnum, entchannel, sfxHandle, volume, min_dist, pitch, maxDist, streamed);
}
2024-01-08 20:07:26 +01:00
/*
==============
S_StartLocalSound
==============
*/
void S_StartLocalSound(const char *sound_name, qboolean force_load)
{
2024-01-08 20:07:26 +01:00
sfxHandle_t sfxHandle;
const char *name;
2024-01-16 20:27:56 +01:00
AliasListNode_t *pSoundAlias = NULL;
2024-01-08 20:07:26 +01:00
if (!s_bSoundStarted) {
return;
}
if (!sound_name) {
return;
}
name = Alias_FindRandom(sound_name, &pSoundAlias);
if (!name) {
name = sound_name;
}
sfxHandle = S_RegisterSound(name, pSoundAlias ? pSoundAlias->streamed : qfalse, force_load);
if (!pSoundAlias) {
S_StartSound(NULL, s_iListenerNumber, CHAN_MENU, sfxHandle, -1.0, -1.0, 1.0, -1.0, qfalse);
return;
}
S_StartSound(
NULL,
2024-01-08 20:07:26 +01:00
s_iListenerNumber,
CHAN_MENU,
sfxHandle,
pSoundAlias->volume + random() * pSoundAlias->volumeMod,
-1.0,
pSoundAlias->pitch + random() * pSoundAlias->pitchMod,
pSoundAlias->maxDist,
pSoundAlias->streamed
);
}
2024-01-08 20:07:26 +01:00
/*
==============
S_StartLocalSoundChannel
Added in 2.0
Starts a local sound, with the specified channel
==============
*/
void S_StartLocalSoundChannel(const char *sound_name, qboolean force_load, soundChannel_t channel)
{
2024-01-08 20:07:26 +01:00
sfxHandle_t sfxHandle;
const char *name;
2024-03-03 18:53:22 +01:00
AliasListNode_t *pSoundAlias = NULL;
2024-01-08 20:07:26 +01:00
if (!s_bSoundStarted) {
return;
}
if (!sound_name) {
return;
}
name = Alias_FindRandom(sound_name, &pSoundAlias);
if (!name) {
name = sound_name;
}
sfxHandle = S_RegisterSound(name, pSoundAlias ? pSoundAlias->streamed : qfalse, force_load);
if (!pSoundAlias) {
S_StartSound(NULL, s_iListenerNumber, channel, sfxHandle, -1.0, -1.0, 1.0, -1.0, qfalse);
return;
}
S_StartSound(
0,
s_iListenerNumber,
channel,
sfxHandle,
pSoundAlias->volume + random() * pSoundAlias->volumeMod,
-1.0,
pSoundAlias->pitch + random() * pSoundAlias->pitchMod,
pSoundAlias->maxDist,
pSoundAlias->streamed
);
}
2024-01-08 20:07:26 +01:00
/*
==============
S_StopAllSounds
==============
*/
void S_StopAllSounds(qboolean stop_music)
{
2024-01-08 20:07:26 +01:00
if (!s_bSoundStarted) {
return;
}
Com_Printf("------- S_StopAllSounds (%s) -------\n", stop_music ? "stop music" : "don't stop music");
// Tell the driver to stop all sounds
S_Driver_StopAllSounds(stop_music);
Com_Printf("------- S_StopAllSounds Complete-------\n");
}
2024-01-08 20:07:26 +01:00
/*
==============
S_ClearLoopingSounds
==============
*/
void S_ClearLoopingSounds()
{
2024-01-08 20:07:26 +01:00
if (!s_bSoundStarted) {
return;
}
S_Driver_ClearLoopingSounds();
}
2024-01-08 20:07:26 +01:00
/*
==============
S_AddLoopingSound
==============
*/
void S_AddLoopingSound(
const vec3_t origin,
const vec3_t velocity,
sfxHandle_t sfxHandle,
float volume,
float min_dist,
float max_dist,
float pitch,
int flags
)
{
2024-01-08 20:07:26 +01:00
if (!s_bSoundStarted) {
return;
}
if (sfxHandle < 0 || sfxHandle >= s_numSfx) {
Com_Error(ERR_DROP, "S_AddLoopingSound: handle %i out of range", sfxHandle);
}
if (!sfxHandle) {
return;
}
S_Driver_AddLoopingSound(origin, velocity, sfxHandle, volume, min_dist, max_dist, pitch, flags);
}
2024-01-08 20:07:26 +01:00
/*
==============
S_Respatialize
==============
*/
void S_Respatialize(int entityNum, const vec3_t head, vec3_t axis[3])
{
2024-01-08 20:07:26 +01:00
if (!s_bSoundStarted) {
return;
}
S_Driver_Respatialize(entityNum, head, axis);
}
2024-01-08 20:07:26 +01:00
/*
==============
S_Update
==============
*/
void S_Update()
{
2024-01-08 20:07:26 +01:00
if (!s_bSoundStarted) {
return;
}
if (server_loading) {
return;
}
S_Driver_Update();
}
2024-01-08 20:07:26 +01:00
/*
==============
S_StopSound
==============
*/
void S_StopSound(int entnum, int channel)
{
2024-01-08 20:07:26 +01:00
if (!s_bSoundStarted) {
return;
}
if (channel == CHAN_AUTO) {
return;
}
S_Driver_StopSound(entnum, channel);
}
2024-01-08 20:07:26 +01:00
/*
==============
S_SetReverb
==============
*/
void S_SetReverb(int reverb_type, float reverb_level)
{
2024-01-08 20:07:26 +01:00
if (!s_bSoundStarted) {
return;
}
S_Driver_SetReverb(reverb_type, reverb_level);
}
2024-01-08 20:07:26 +01:00
/*
==============
S_Play
==============
*/
void S_Play()
{
2024-01-08 20:07:26 +01:00
int i;
char name[MAX_QPATH];
if (Cmd_Argc() < 2) {
return;
}
2024-01-08 20:07:26 +01:00
for (i = 1; i < Cmd_Argc(); i++) {
if (strrchr(Cmd_Argv(i), '.')) {
Q_strncpyz(name, Cmd_Argv(i), sizeof(name));
} else {
Com_sprintf(name, sizeof(name), "%s.wav", Cmd_Argv(1));
}
}
S_StartLocalSound(name, qfalse);
}
2024-01-08 20:07:26 +01:00
/*
==============
S_SoundList
==============
*/
void S_SoundList()
{
2024-01-08 20:07:26 +01:00
int i;
sfx_t *sfx;
int size;
int total = 0;
for (i = 0; i < s_numSfx; i++) {
sfx = &s_knownSfx[i];
if (sfx->registration_sequence) {
size = sfx->length * sfx->width;
total += size;
Com_Printf("(%2db) %6i : %s\n", sfx->width * 8, size, sfx->name);
}
}
Com_Printf("Total resident: %i\n", total);
}
2024-01-08 20:07:26 +01:00
/*
==============
S_ClearSoundBuffer
==============
*/
void S_ClearSoundBuffer()
{
// TODO: Remove once AL is fully implemented
}
/*
==============
S_GetMusicFilename
==============
*/
const char* S_GetMusicFilename()
{
return S_Driver_GetMusicFilename();
}
/*
==============
S_GetMusicLoopCount
==============
*/
int S_GetMusicLoopCount()
{
return S_Driver_GetMusicLoopCount();
}
/*
==============
S_GetMusicOffset
==============
*/
unsigned int S_GetMusicOffset()
{
return S_Driver_GetMusicOffset();
}