2024-01-07 19:47:58 +01:00
|
|
|
/*
|
|
|
|
===========================================================================
|
|
|
|
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
|
|
|
|
===========================================================================
|
|
|
|
*/
|
|
|
|
|
2024-08-09 20:30:35 +02:00
|
|
|
#include "snd_local.h"
|
|
|
|
#include "snd_openal_new.h"
|
|
|
|
#include "client.h"
|
|
|
|
#include "../server/server.h"
|
|
|
|
#include "snd_codec.h"
|
2024-01-07 19:47:58 +01:00
|
|
|
|
|
|
|
typedef struct {
|
2024-08-22 12:42:34 +02:00
|
|
|
const char *funcname;
|
|
|
|
void **funcptr;
|
|
|
|
bool required;
|
2024-01-07 19:47:58 +01:00
|
|
|
} extensions_table_t;
|
|
|
|
|
|
|
|
# define MAX_MUSIC_SONGS 16
|
|
|
|
|
|
|
|
static int s_iNextLoopingWarning = 0;
|
|
|
|
static int s_iReverbType = 0;
|
|
|
|
static float s_fReverbLevel = 0;
|
|
|
|
static bool s_bReverbChanged = false;
|
|
|
|
static bool s_bFading = false;
|
|
|
|
static float s_fFadeVolume = 1.f;
|
|
|
|
|
2024-07-01 16:46:47 +02:00
|
|
|
static constexpr float s_fVolumeGain = 1.f; // = 84.f;
|
|
|
|
|
2024-01-07 19:47:58 +01:00
|
|
|
cvar_t *s_milesdriver;
|
|
|
|
cvar_t *s_openaldevice;
|
|
|
|
cvar_t *s_reverb;
|
|
|
|
cvar_t *s_show_cpu;
|
|
|
|
cvar_t *s_show_num_active_sounds;
|
|
|
|
cvar_t *s_show_sounds;
|
|
|
|
cvar_t *s_speaker_type;
|
|
|
|
cvar_t *s_obstruction_cal_time;
|
|
|
|
cvar_t *s_lastSoundTime;
|
2024-01-16 20:54:41 +01:00
|
|
|
// Added in OPM
|
|
|
|
cvar_t *s_openaldriver;
|
2024-08-22 13:30:04 +02:00
|
|
|
cvar_t *s_alAvailableDevices;
|
2024-01-07 19:47:58 +01:00
|
|
|
|
|
|
|
static float reverb_table[] = {
|
|
|
|
0.5f, 0.25f, 0.417f, 0.653f, 0.208f, 0.5f, 0.403f, 0.5f, 0.5f,
|
|
|
|
0.361f, 0.5f, 0.153f, 0.361f, 0.44400001f, 0.25f, 0.111f, 0.111f, 0.19400001f,
|
|
|
|
1.0f, 0.097000003f, 0.208f, 0.65200001f, 1.0f, 0.875f, 0.139f, 0.486f,
|
|
|
|
};
|
|
|
|
|
|
|
|
static vec3_t vec_zero = {0, 0, 0};
|
|
|
|
int s_iNumMilesAudioProviders = 0;
|
|
|
|
bool s_bProvidersEmunerated = false;
|
|
|
|
static bool al_initialized = false;
|
|
|
|
static bool al_use_reverb = false;
|
|
|
|
static float al_current_volume = 0;
|
|
|
|
static unsigned int al_frequency = 22050;
|
2024-01-12 00:04:36 +01:00
|
|
|
static ALCcontext *al_context_id = NULL;
|
2024-01-07 19:47:58 +01:00
|
|
|
static ALCdevice *al_device = NULL;
|
|
|
|
|
|
|
|
static ALboolean (*_alutLoadMP3_LOKI)(unsigned int buffer, const byte *data, int length);
|
|
|
|
static void (*_alReverbScale_LOKI)();
|
|
|
|
static void (*_alReverbDelay_LOKI)();
|
|
|
|
|
|
|
|
static qboolean music_active = qfalse;
|
|
|
|
int music_current_mood = 0;
|
|
|
|
int music_fallback_mood = 0;
|
|
|
|
float old_music_volume = 1.f;
|
|
|
|
float music_volume = 1.f;
|
|
|
|
float new_music_volume = 1.f;
|
|
|
|
float music_volume_fade_time = 0;
|
|
|
|
long int music_volume_start_time = 0;
|
|
|
|
int music_volume_direction = 0;
|
|
|
|
int music_volume_changed = 0;
|
|
|
|
int music_loaded = 0;
|
|
|
|
int music_numsongs = 0;
|
|
|
|
int music_currentsong = 0;
|
|
|
|
|
2024-08-22 13:30:04 +02:00
|
|
|
static qboolean enumeration_ext = qfalse;
|
|
|
|
static qboolean enumeration_all_ext = qfalse;
|
|
|
|
|
2024-01-07 19:47:58 +01:00
|
|
|
song_t music_songs[MAX_MUSIC_SONGS];
|
|
|
|
openal_internal_t openal;
|
|
|
|
static float s_fFadeStartTime;
|
|
|
|
static float s_fFadeStopTime;
|
|
|
|
static char current_soundtrack[128];
|
|
|
|
|
2024-01-12 00:04:36 +01:00
|
|
|
static void S_OPENAL_PlayMP3();
|
|
|
|
static void S_OPENAL_StopMP3();
|
|
|
|
static void S_OPENAL_Pitch();
|
2024-01-15 23:04:25 +01:00
|
|
|
static int
|
|
|
|
S_OPENAL_SpatializeStereoSound(const vec3_t listener_origin, const vec3_t listener_left, const vec3_t origin);
|
2024-01-12 00:04:36 +01:00
|
|
|
static void S_OPENAL_reverb(int iChannel, int iReverbType, float fReverbLevel);
|
2024-07-01 18:00:15 +02:00
|
|
|
static bool S_OPENAL_LoadMP3_Codec(const char *_path, sfx_t* pSfx);
|
|
|
|
static ALuint S_OPENAL_Format(int width, int channels);
|
2024-01-12 00:04:36 +01:00
|
|
|
|
|
|
|
# define alDieIfError() __alDieIfError(__FILE__, __LINE__)
|
|
|
|
|
2024-01-17 20:44:32 +01:00
|
|
|
# if defined(_WIN64)
|
|
|
|
# define ALDRIVER_DEFAULT "OpenAL64.dll"
|
|
|
|
# elif defined(_WIN32)
|
|
|
|
# define ALDRIVER_DEFAULT "OpenAL32.dll"
|
|
|
|
# elif defined(__APPLE__)
|
|
|
|
# define ALDRIVER_DEFAULT "/System/Library/Frameworks/OpenAL.framework/OpenAL"
|
|
|
|
# elif defined(__OpenBSD__)
|
|
|
|
# define ALDRIVER_DEFAULT "libopenal.so"
|
|
|
|
# else
|
|
|
|
# define ALDRIVER_DEFAULT "libopenal.so.1"
|
|
|
|
# endif
|
2024-01-16 20:54:41 +01:00
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
__alDieIfError
|
|
|
|
==============
|
|
|
|
*/
|
2024-01-12 00:04:36 +01:00
|
|
|
static void __alDieIfError(const char *file, int line)
|
2024-01-07 19:47:58 +01:00
|
|
|
{
|
2024-01-12 00:04:36 +01:00
|
|
|
ALint alErr = qalGetError();
|
|
|
|
if (alErr) {
|
2024-01-21 23:48:49 +01:00
|
|
|
if (s_show_sounds->integer) {
|
|
|
|
Com_DPrintf("OpenAL error, %s, line %i: [%s].\n", file, line, qalGetString(alErr));
|
|
|
|
}
|
2024-01-12 00:04:36 +01:00
|
|
|
}
|
2024-01-07 19:47:58 +01:00
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
S_OPENAL_NukeSource
|
|
|
|
==============
|
|
|
|
*/
|
2024-01-07 19:47:58 +01:00
|
|
|
static void S_OPENAL_NukeSource(ALuint *srcptr)
|
|
|
|
{
|
2024-01-12 00:04:36 +01:00
|
|
|
ALuint source;
|
|
|
|
|
|
|
|
source = *srcptr;
|
|
|
|
if (!*srcptr) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!qalIsSource(*srcptr)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
alDieIfError();
|
|
|
|
qalSourceStop(source);
|
|
|
|
|
|
|
|
alDieIfError();
|
|
|
|
qalSourcei(source, AL_BUFFER, 0);
|
|
|
|
|
|
|
|
alDieIfError();
|
|
|
|
qalDeleteSources(1, srcptr);
|
|
|
|
|
|
|
|
alDieIfError();
|
|
|
|
*srcptr = 0;
|
2024-01-07 19:47:58 +01:00
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
S_OPENAL_NukeBuffer
|
|
|
|
==============
|
|
|
|
*/
|
2024-01-07 19:47:58 +01:00
|
|
|
static void S_OPENAL_NukeBuffer(ALuint *bufptr)
|
|
|
|
{
|
2024-01-12 00:04:36 +01:00
|
|
|
if (!*bufptr) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!qalIsBuffer(*bufptr)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
alDieIfError();
|
|
|
|
qalDeleteBuffers(1, bufptr);
|
|
|
|
|
|
|
|
alDieIfError();
|
|
|
|
*bufptr = 0;
|
2024-01-07 19:47:58 +01:00
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
S_OPENAL_NukeChannel
|
|
|
|
==============
|
|
|
|
*/
|
2024-01-07 19:47:58 +01:00
|
|
|
static void S_OPENAL_NukeChannel(openal_channel *channel)
|
|
|
|
{
|
2024-01-12 00:04:36 +01:00
|
|
|
if (!channel) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
S_OPENAL_NukeSource(&channel->source);
|
|
|
|
S_OPENAL_NukeBuffer(&channel->buffer);
|
|
|
|
|
|
|
|
if (channel->bufferdata) {
|
|
|
|
delete[] channel->bufferdata;
|
|
|
|
}
|
2024-01-07 19:47:58 +01:00
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
S_OPENAL_NukeContext
|
|
|
|
==============
|
|
|
|
*/
|
2024-01-07 19:47:58 +01:00
|
|
|
static void S_OPENAL_NukeContext()
|
|
|
|
{
|
2024-01-12 00:04:36 +01:00
|
|
|
int i;
|
|
|
|
|
|
|
|
Com_Printf("OpenAL: Destroying channels...\n");
|
|
|
|
|
|
|
|
for (i = 0; i < MAX_OPENAL_CHANNELS; ++i) {
|
|
|
|
S_OPENAL_NukeChannel(openal.channel[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
Com_Printf("OpenAL: Channels destroyed successfully.\n");
|
|
|
|
|
|
|
|
for (i = 0; i < s_numSfx; i++) {
|
|
|
|
S_OPENAL_NukeBuffer(&s_knownSfx[i].buffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
S_OPENAL_NukeBuffer(&openal.movieSFX.buffer);
|
|
|
|
|
|
|
|
if (al_context_id) {
|
|
|
|
Com_Printf("OpenAL: Destroying context...\n");
|
|
|
|
|
|
|
|
qalcSuspendContext(al_context_id);
|
|
|
|
qalcMakeContextCurrent(NULL);
|
|
|
|
qalcDestroyContext(al_context_id);
|
|
|
|
al_context_id = NULL;
|
|
|
|
|
|
|
|
Com_Printf("OpenAL: Context destroyed successfully.\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (al_device) {
|
|
|
|
Com_Printf("OpenAL: Closing device...\n");
|
|
|
|
|
|
|
|
qalcCloseDevice(al_device);
|
|
|
|
al_device = NULL;
|
|
|
|
|
|
|
|
Com_Printf("OpenAL: Device closed successfully.\n");
|
|
|
|
}
|
2024-01-07 19:47:58 +01:00
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
S_OPENAL_InitContext
|
|
|
|
==============
|
|
|
|
*/
|
2024-01-07 19:47:58 +01:00
|
|
|
static bool S_OPENAL_InitContext()
|
|
|
|
{
|
2024-01-12 00:04:36 +01:00
|
|
|
const char *dev;
|
|
|
|
int attrlist[6];
|
|
|
|
|
2024-01-16 20:54:41 +01:00
|
|
|
dev = NULL;
|
2024-01-12 00:04:36 +01:00
|
|
|
if (s_openaldevice) {
|
|
|
|
dev = s_openaldevice->string;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dev && !*dev) {
|
|
|
|
dev = NULL;
|
|
|
|
}
|
|
|
|
|
2024-08-22 15:38:45 +02:00
|
|
|
Com_DPrintf("OpenAL: Context initialization\n");
|
2024-08-22 13:30:04 +02:00
|
|
|
|
|
|
|
// Device enumeration support
|
|
|
|
enumeration_all_ext = qalcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT");
|
|
|
|
enumeration_ext = qalcIsExtensionPresent(NULL, "ALC_ENUMERATION_EXT");
|
|
|
|
|
|
|
|
if(enumeration_ext || enumeration_all_ext)
|
|
|
|
{
|
|
|
|
char devicenames[16384] = "";
|
|
|
|
const char *devicelist;
|
|
|
|
#ifdef _WIN32
|
|
|
|
const char *defaultdevice;
|
|
|
|
#endif
|
|
|
|
int curlen;
|
|
|
|
|
|
|
|
// get all available devices + the default device name.
|
|
|
|
if(enumeration_all_ext)
|
|
|
|
{
|
2024-08-22 15:38:45 +02:00
|
|
|
Com_DPrintf("OpenAL: Fetching all devices\n");
|
2024-08-22 13:30:04 +02:00
|
|
|
devicelist = qalcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER);
|
|
|
|
#ifdef _WIN32
|
|
|
|
defaultdevice = qalcGetString(NULL, ALC_DEFAULT_ALL_DEVICES_SPECIFIER);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2024-08-22 15:38:45 +02:00
|
|
|
Com_DPrintf("OpenAL: Fetching current device\n");
|
2024-08-22 13:30:04 +02:00
|
|
|
// We don't have ALC_ENUMERATE_ALL_EXT but normal enumeration.
|
|
|
|
devicelist = qalcGetString(NULL, ALC_DEVICE_SPECIFIER);
|
|
|
|
#ifdef _WIN32
|
|
|
|
defaultdevice = qalcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER);
|
|
|
|
#endif
|
|
|
|
enumeration_ext = qtrue;
|
|
|
|
}
|
|
|
|
|
2024-08-22 15:38:45 +02:00
|
|
|
Com_DPrintf("OpenAL: Default playback device: \"%s\"\n", defaultdevice);
|
|
|
|
|
2024-08-22 13:30:04 +02:00
|
|
|
#ifdef _WIN32
|
|
|
|
// check whether the default device is generic hardware. If it is, change to
|
|
|
|
// Generic Software as that one works more reliably with various sound systems.
|
|
|
|
// If it's not, use OpenAL's default selection as we don't want to ignore
|
|
|
|
// native hardware acceleration.
|
|
|
|
if(!dev && defaultdevice && !strcmp(defaultdevice, "Generic Hardware"))
|
|
|
|
dev = "Generic Software";
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// dump a list of available devices to a cvar for the user to see.
|
|
|
|
|
|
|
|
if(devicelist)
|
|
|
|
{
|
|
|
|
while((curlen = strlen(devicelist)))
|
|
|
|
{
|
|
|
|
Q_strcat(devicenames, sizeof(devicenames), devicelist);
|
|
|
|
Q_strcat(devicenames, sizeof(devicenames), "\n");
|
|
|
|
|
|
|
|
devicelist += curlen + 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Com_Printf("OpenAL: List of available devices:\n%s\n", devicenames);
|
2024-08-22 15:38:45 +02:00
|
|
|
|
|
|
|
s_alAvailableDevices = Cvar_Get("s_alAvailableDevices", devicenames, CVAR_ROM | CVAR_NORESTART);
|
2024-08-22 13:30:04 +02:00
|
|
|
}
|
2024-08-22 12:39:14 +02:00
|
|
|
|
|
|
|
Com_Printf("OpenAL: Opening device \"%s\"...\n", dev ? dev : "{default}");
|
2024-01-12 00:04:36 +01:00
|
|
|
|
|
|
|
al_device = qalcOpenDevice(dev);
|
2024-08-22 13:30:04 +02:00
|
|
|
if (!al_device && dev) {
|
|
|
|
Com_Printf("Failed to open OpenAL device '%s', trying default.\n", dev);
|
|
|
|
al_device = qalcOpenDevice(NULL);
|
|
|
|
}
|
|
|
|
|
2024-01-12 00:04:36 +01:00
|
|
|
if (!al_device) {
|
|
|
|
Com_Printf("OpenAL: Could not open device\n");
|
|
|
|
S_OPENAL_NukeContext();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
Com_Printf("OpenAL: Device opened successfully.\n");
|
2024-08-22 12:42:34 +02:00
|
|
|
switch (s_khz->integer) {
|
|
|
|
case 11:
|
2024-01-12 00:04:36 +01:00
|
|
|
al_frequency = 11025;
|
2024-08-22 12:42:34 +02:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
case 22:
|
|
|
|
al_frequency = 22050;
|
|
|
|
break;
|
|
|
|
case 44:
|
2024-01-12 00:04:36 +01:00
|
|
|
al_frequency = 44100;
|
2024-08-22 12:42:34 +02:00
|
|
|
break;
|
2024-01-12 00:04:36 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
attrlist[0] = 256;
|
|
|
|
attrlist[1] = al_frequency;
|
|
|
|
attrlist[2] = 258;
|
|
|
|
attrlist[3] = 0;
|
|
|
|
attrlist[4] = 0;
|
|
|
|
attrlist[5] = 0;
|
|
|
|
|
|
|
|
Com_Printf("OpenAL: Creating AL context...\n");
|
|
|
|
al_context_id = qalcCreateContext(al_device, attrlist);
|
|
|
|
if (!al_context_id) {
|
|
|
|
Com_Printf("OpenAL: Could not create context\n");
|
|
|
|
S_OPENAL_NukeContext();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
Com_Printf("OpenAL: Context created successfully.\n");
|
|
|
|
|
|
|
|
qalcMakeContextCurrent(al_context_id);
|
|
|
|
alDieIfError();
|
|
|
|
|
|
|
|
Com_Printf("AL_VENDOR: %s\n", qalGetString(AL_VENDOR));
|
|
|
|
alDieIfError();
|
|
|
|
|
|
|
|
Com_Printf("AL_VERSION: %s\n", qalGetString(AL_VERSION));
|
|
|
|
alDieIfError();
|
|
|
|
|
|
|
|
Com_Printf("AL_RENDERER: %s\n", qalGetString(AL_RENDERER));
|
|
|
|
alDieIfError();
|
|
|
|
|
|
|
|
Com_Printf("AL_EXTENSIONS: %s\n", qalGetString(AL_EXTENSIONS));
|
|
|
|
alDieIfError();
|
|
|
|
|
|
|
|
qalDistanceModel(AL_INVERSE_DISTANCE_CLAMPED);
|
|
|
|
alDieIfError();
|
|
|
|
|
|
|
|
qalcProcessContext(al_context_id);
|
|
|
|
alDieIfError();
|
|
|
|
|
|
|
|
return true;
|
2024-01-07 19:47:58 +01:00
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
S_OPENAL_InitExtensions
|
|
|
|
==============
|
|
|
|
*/
|
2024-01-07 19:47:58 +01:00
|
|
|
static bool S_OPENAL_InitExtensions()
|
|
|
|
{
|
2024-01-16 20:54:41 +01:00
|
|
|
Com_Printf("AL extensions ignored\n");
|
|
|
|
return true;
|
|
|
|
|
2024-01-12 00:04:36 +01:00
|
|
|
extensions_table_t extensions_table[4] = {
|
|
|
|
"alutLoadMP3_LOKI",
|
2024-01-16 20:54:41 +01:00
|
|
|
(void **)&_alutLoadMP3_LOKI,
|
2024-01-12 00:04:36 +01:00
|
|
|
true,
|
|
|
|
"alReverbScale_LOKI",
|
2024-01-16 20:54:41 +01:00
|
|
|
(void **)&_alReverbScale_LOKI,
|
2024-01-12 00:04:36 +01:00
|
|
|
true,
|
|
|
|
"alReverbDelay_LOKI",
|
2024-01-16 20:54:41 +01:00
|
|
|
(void **)&_alReverbDelay_LOKI,
|
2024-01-12 00:04:36 +01:00
|
|
|
true
|
|
|
|
};
|
|
|
|
extensions_table_t *i;
|
|
|
|
|
|
|
|
for (i = extensions_table; i->funcname; ++i) {
|
|
|
|
*i->funcptr = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = extensions_table; i->funcname; ++i) {
|
|
|
|
Com_Printf("AL extension: Looking up %ssymbol \"%s\"...", i->required ? "required " : "", i->funcname);
|
|
|
|
|
|
|
|
*i->funcptr = qalGetProcAddress(i->funcname);
|
|
|
|
if (!*i->funcptr) {
|
2024-08-22 12:42:34 +02:00
|
|
|
Com_Printf("...not found! %d [%s]\n", qalGetError(), qalGetString(qalGetError()));
|
2024-01-12 00:04:36 +01:00
|
|
|
if (i->required) {
|
|
|
|
S_OPENAL_NukeContext();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
Com_Printf("...found.\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
qalGetError();
|
|
|
|
return true;
|
2024-01-07 19:47:58 +01:00
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
S_OPENAL_InitChannel
|
|
|
|
==============
|
|
|
|
*/
|
2024-01-07 19:47:58 +01:00
|
|
|
static bool S_OPENAL_InitChannel(int idx, openal_channel *chan)
|
|
|
|
{
|
2024-01-12 00:04:36 +01:00
|
|
|
openal.channel[idx] = chan;
|
2024-07-01 16:46:47 +02:00
|
|
|
VectorClear(chan->vOrigin);
|
2024-01-12 00:04:36 +01:00
|
|
|
chan->fVolume = 1.0;
|
|
|
|
chan->fNewPitchMult = 0.0;
|
|
|
|
chan->fMinDist = 0.0;
|
|
|
|
chan->fMaxDist = 0.0;
|
|
|
|
chan->pSfx = 0;
|
|
|
|
chan->iEntNum = 0;
|
|
|
|
chan->iEntChannel = 0;
|
|
|
|
chan->iBaseRate = 0;
|
|
|
|
chan->iStartTime = 0;
|
|
|
|
chan->iTime = 0;
|
|
|
|
chan->iEndTime = 0;
|
|
|
|
chan->iFlags = 0;
|
|
|
|
chan->iPausedOffset = 0;
|
|
|
|
chan->source = 0;
|
|
|
|
chan->buffer = 0;
|
|
|
|
chan->bufferdata = 0;
|
|
|
|
chan->fading = FADE_NONE;
|
|
|
|
chan->fade_time = 0;
|
|
|
|
chan->fade_start_time = 0;
|
|
|
|
chan->song_number = 0;
|
|
|
|
|
|
|
|
qalGenSources(1, &chan->source);
|
|
|
|
alDieIfError();
|
2024-01-17 20:44:32 +01:00
|
|
|
qalSourcei(chan->source, AL_SOURCE_RELATIVE, true);
|
2024-01-12 00:04:36 +01:00
|
|
|
alDieIfError();
|
|
|
|
|
|
|
|
return true;
|
2024-01-07 19:47:58 +01:00
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
S_OPENAL_Init
|
|
|
|
==============
|
|
|
|
*/
|
2024-01-07 19:47:58 +01:00
|
|
|
qboolean S_OPENAL_Init()
|
|
|
|
{
|
2024-01-12 00:04:36 +01:00
|
|
|
int i;
|
|
|
|
|
|
|
|
if (al_initialized) {
|
|
|
|
Com_DPrintf("S_OPENAL_Init(): Called when sound is already initialized!\n");
|
|
|
|
return qtrue;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < MAX_OPENAL_CHANNELS; i++) {
|
|
|
|
openal.channel[i] = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < MAX_OPENAL_LOOP_SOUNDS; i++) {
|
|
|
|
openal.loop_sounds[i] = {};
|
|
|
|
}
|
|
|
|
|
|
|
|
s_milesdriver = Cvar_Get("s_milesdriver", "auto", CVAR_SOUND_LATCH | CVAR_ARCHIVE);
|
|
|
|
s_openaldevice = Cvar_Get("s_openaldevice", "", CVAR_SOUND_LATCH | CVAR_ARCHIVE);
|
|
|
|
s_reverb = Cvar_Get("s_reverb", "0", CVAR_SOUND_LATCH | CVAR_ARCHIVE);
|
|
|
|
s_show_cpu = Cvar_Get("s_show_cpu", "0", 0);
|
|
|
|
s_show_num_active_sounds = Cvar_Get("s_show_num_active_sounds", "0", 0);
|
|
|
|
s_show_sounds = Cvar_Get("s_show_sounds", "0", 0);
|
|
|
|
s_speaker_type = Cvar_Get("s_speaker_type", "0", CVAR_ARCHIVE);
|
|
|
|
s_obstruction_cal_time = Cvar_Get("s_obstruction_cal_time", "500", CVAR_ARCHIVE);
|
2024-01-16 20:54:41 +01:00
|
|
|
//
|
|
|
|
// Added in OPM
|
|
|
|
// Initialize the AL driver DLL
|
2024-01-17 20:44:32 +01:00
|
|
|
s_openaldriver = Cvar_Get("s_openaldriver", ALDRIVER_DEFAULT, CVAR_ARCHIVE | CVAR_LATCH | CVAR_PROTECTED);
|
2024-01-16 20:54:41 +01:00
|
|
|
|
|
|
|
if (!QAL_Init(s_openaldriver->string)) {
|
|
|
|
Com_Printf("Failed to load library: \"%s\".\n", s_openaldriver->string);
|
|
|
|
if (!Q_stricmp(s_openaldriver->string, ALDRIVER_DEFAULT) || !QAL_Init(ALDRIVER_DEFAULT)) {
|
|
|
|
return qfalse;
|
|
|
|
}
|
|
|
|
}
|
2024-01-12 00:04:36 +01:00
|
|
|
|
|
|
|
if (!Cvar_Get("s_initsound", "1", 0)->integer) {
|
|
|
|
Com_Printf("OpenAL: s_initsound set to zero...disabling audio.\n");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!S_OPENAL_InitContext()) {
|
|
|
|
Com_Printf("OpenAL: initialization failed. No audio will play.\n");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!S_OPENAL_InitExtensions()) {
|
|
|
|
Com_Printf("OpenAL: A required extension is missing. No audio will play.\n");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
al_use_reverb = false;
|
|
|
|
if (s_reverb->integer) {
|
|
|
|
STUB_DESC("reenable reverb support later.");
|
|
|
|
|
|
|
|
if (al_use_reverb) {
|
|
|
|
S_OPENAL_SetReverb(s_iReverbType, s_fReverbLevel);
|
|
|
|
} else {
|
|
|
|
Com_Printf("OpenAL: No reverb support. Reverb is disabled.\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-08-06 18:43:15 +02:00
|
|
|
al_current_volume = Square(s_volume->value);
|
2024-01-12 00:04:36 +01:00
|
|
|
qalListenerf(AL_GAIN, al_current_volume);
|
|
|
|
alDieIfError();
|
|
|
|
|
|
|
|
for (i = 0; i < MAX_OPENAL_CHANNELS_3D; i++) {
|
|
|
|
if (!S_OPENAL_InitChannel(i, &openal.chan_3D[i])) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < MAX_OPENAL_CHANNELS_2D; i++) {
|
2024-01-16 20:54:41 +01:00
|
|
|
if (!S_OPENAL_InitChannel(i + MAX_OPENAL_CHANNELS_3D, &openal.chan_2D[i])) {
|
2024-01-12 00:04:36 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < MAX_OPENAL_CHANNELS_2D_STREAM; i++) {
|
2024-01-16 20:54:41 +01:00
|
|
|
if (!S_OPENAL_InitChannel(i + MAX_OPENAL_CHANNELS_3D + MAX_OPENAL_CHANNELS_2D, &openal.chan_2D_stream[i])) {
|
2024-01-12 00:04:36 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < MAX_OPENAL_SONGS; i++) {
|
2024-01-17 20:44:32 +01:00
|
|
|
if (!S_OPENAL_InitChannel(
|
|
|
|
i + MAX_OPENAL_CHANNELS_3D + MAX_OPENAL_CHANNELS_2D + MAX_OPENAL_CHANNELS_2D_STREAM,
|
|
|
|
&openal.chan_song[i]
|
|
|
|
)) {
|
2024-01-12 00:04:36 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!S_OPENAL_InitChannel(OPENAL_CHANNEL_MP3_ID, &openal.chan_mp3)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2024-01-16 20:54:41 +01:00
|
|
|
if (!S_OPENAL_InitChannel(OPENAL_CHANNEL_TRIGGER_MUSIC_ID, &openal.chan_trig_music)) {
|
2024-01-12 00:04:36 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2024-01-16 20:54:41 +01:00
|
|
|
if (!S_OPENAL_InitChannel(OPENAL_CHANNEL_MOVIE_ID, &openal.chan_movie)) {
|
2024-01-12 00:04:36 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
Cmd_AddCommand("playmp3", S_OPENAL_PlayMP3);
|
|
|
|
Cmd_AddCommand("stopmp3", S_OPENAL_StopMP3);
|
|
|
|
Cmd_AddCommand("loadsoundtrack", S_loadsoundtrack);
|
|
|
|
Cmd_AddCommand("playsong", S_PlaySong);
|
|
|
|
Cmd_AddCommand("pitch", S_OPENAL_Pitch);
|
|
|
|
Cmd_AddCommand("tmstart", S_TriggeredMusic_Start);
|
|
|
|
Cmd_AddCommand("tmstartloop", S_TriggeredMusic_StartLoop);
|
|
|
|
Cmd_AddCommand("tmstop", S_TriggeredMusic_Stop);
|
|
|
|
|
|
|
|
S_OPENAL_ClearLoopingSounds();
|
|
|
|
load_sfx_info();
|
|
|
|
s_bProvidersEmunerated = true;
|
|
|
|
al_initialized = true;
|
|
|
|
|
2024-01-16 20:54:41 +01:00
|
|
|
// Added in OPM
|
|
|
|
S_CodecInit();
|
|
|
|
|
2024-01-12 00:04:36 +01:00
|
|
|
return true;
|
2024-01-07 19:47:58 +01:00
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
S_OPENAL_Shutdown
|
|
|
|
==============
|
|
|
|
*/
|
2024-01-07 19:47:58 +01:00
|
|
|
void S_OPENAL_Shutdown()
|
|
|
|
{
|
2024-01-12 00:04:36 +01:00
|
|
|
if (!al_initialized) {
|
|
|
|
Com_DPrintf("S_OPENAL_Shutdown(): Called when sound is NOT initialized!\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
S_OPENAL_StopAllSounds(true);
|
|
|
|
|
|
|
|
Cmd_RemoveCommand("playmp3");
|
|
|
|
Cmd_RemoveCommand("stopmp3");
|
|
|
|
Cmd_RemoveCommand("loadsoundtrack");
|
|
|
|
Cmd_RemoveCommand("playsong");
|
|
|
|
Cmd_RemoveCommand("pitch");
|
|
|
|
Cmd_RemoveCommand("tmstart");
|
|
|
|
Cmd_RemoveCommand("tmstartloop");
|
|
|
|
Cmd_RemoveCommand("tmstop");
|
|
|
|
|
|
|
|
S_OPENAL_NukeContext();
|
|
|
|
|
|
|
|
s_bProvidersEmunerated = false;
|
|
|
|
al_initialized = false;
|
2024-01-07 19:47:58 +01:00
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
S_FadeSound
|
|
|
|
==============
|
|
|
|
*/
|
2024-01-07 19:47:58 +01:00
|
|
|
void S_FadeSound(float fTime)
|
|
|
|
{
|
2024-01-12 00:04:36 +01:00
|
|
|
Com_Printf("Called FadeSound with: %f\n", fTime);
|
|
|
|
|
|
|
|
if (fTime > 0) {
|
|
|
|
s_bFading = true;
|
|
|
|
s_fFadeStartTime = cls.realtime;
|
|
|
|
s_fFadeVolume = 1;
|
|
|
|
s_fFadeStopTime = cls.realtime + fTime;
|
|
|
|
} else {
|
|
|
|
s_fFadeVolume = 1;
|
|
|
|
s_bFading = false;
|
|
|
|
}
|
2024-01-07 19:47:58 +01:00
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
S_GetBaseVolume
|
|
|
|
==============
|
|
|
|
*/
|
2024-01-07 19:47:58 +01:00
|
|
|
float S_GetBaseVolume()
|
|
|
|
{
|
2024-01-12 00:04:36 +01:00
|
|
|
return s_volume->value * s_fFadeVolume;
|
2024-01-07 19:47:58 +01:00
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
S_NeedFullRestart
|
|
|
|
==============
|
|
|
|
*/
|
2024-01-07 19:47:58 +01:00
|
|
|
qboolean S_NeedFullRestart()
|
|
|
|
{
|
2024-01-12 00:04:36 +01:00
|
|
|
return Cvar_Get("s_initsound", "1", 0)->integer != s_bLastInitSound;
|
2024-01-07 19:47:58 +01:00
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
S_PrintInfo
|
|
|
|
==============
|
|
|
|
*/
|
2024-01-07 19:47:58 +01:00
|
|
|
void S_PrintInfo()
|
|
|
|
{
|
2024-01-12 00:04:36 +01:00
|
|
|
const char *dev;
|
|
|
|
|
|
|
|
Com_Printf("----- Sound Info -----\n");
|
|
|
|
|
|
|
|
if (s_bSoundStarted) {
|
|
|
|
dev = NULL;
|
|
|
|
if (s_openaldevice) {
|
|
|
|
dev = s_openaldevice->string;
|
|
|
|
}
|
|
|
|
if (!dev || !*dev) {
|
|
|
|
dev = "{default}";
|
|
|
|
}
|
|
|
|
Com_Printf("device - %s\n", dev);
|
|
|
|
if (al_use_reverb) {
|
|
|
|
Com_Printf("reverb - ON\n");
|
|
|
|
} else {
|
|
|
|
Com_Printf("reverb - OFF\n");
|
|
|
|
}
|
|
|
|
Com_Printf("samplebits - 16\n");
|
|
|
|
Com_Printf("speed - %d\n", al_frequency);
|
|
|
|
if (s_loadas8bit->integer) {
|
|
|
|
Com_Printf("Can NOT force all sounds to 8 bit in OpenAL, I think.\n");
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
Com_Printf("sound system not started\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
Com_Printf("----------------------\n");
|
2024-01-07 19:47:58 +01:00
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
S_DumpStatus
|
|
|
|
==============
|
|
|
|
*/
|
2024-01-07 19:47:58 +01:00
|
|
|
static void S_DumpStatus(const char *pszChanName, int iChanNum, openal_channel *channel)
|
|
|
|
{
|
2024-01-12 00:04:36 +01:00
|
|
|
sfx_t *sfx;
|
|
|
|
ALint status;
|
|
|
|
|
|
|
|
sfx = channel->pSfx;
|
|
|
|
|
|
|
|
qalGetSourceiv(channel->source, AL_SOURCE_STATE, &status);
|
|
|
|
alDieIfError();
|
|
|
|
|
|
|
|
if (status == AL_PLAYING || status == AL_PAUSED) {
|
|
|
|
const char *pszMode = status == AL_PLAYING ? "playing" : "paused";
|
|
|
|
|
|
|
|
if (sfx) {
|
|
|
|
if (sfx != (sfx_t *)-16 && sfx->name[0]) {
|
|
|
|
Com_Printf("%s channel %i - %s sfx %s\n", pszChanName, iChanNum, pszMode, sfx->name);
|
|
|
|
} else {
|
|
|
|
Com_Printf("%s channel %i - %s with nameless sfx\n", pszChanName, iChanNum, pszMode);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
Com_Printf("%s channel %i - %s with NULL sfx\n", pszChanName, iChanNum, pszMode);
|
|
|
|
}
|
|
|
|
}
|
2024-01-07 19:47:58 +01:00
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
S_DumpInfo
|
|
|
|
==============
|
|
|
|
*/
|
2024-01-07 19:47:58 +01:00
|
|
|
void S_DumpInfo()
|
|
|
|
{
|
2024-01-12 00:04:36 +01:00
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < MAX_OPENAL_CHANNELS_3D; i++) {
|
|
|
|
S_DumpStatus("3D", i, openal.channel[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < MAX_OPENAL_CHANNELS_2D; i++) {
|
|
|
|
S_DumpStatus("2D", i, openal.channel[MAX_OPENAL_CHANNELS_3D + i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < MAX_OPENAL_CHANNELS_2D_STREAM; i++) {
|
|
|
|
S_DumpStatus("2D stream", i, openal.channel[MAX_OPENAL_CHANNELS_3D + MAX_OPENAL_CHANNELS_2D + i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < MAX_OPENAL_MISC_CHANNELS; i++) {
|
|
|
|
S_DumpStatus(
|
|
|
|
"Misc",
|
|
|
|
i,
|
|
|
|
openal.channel[MAX_OPENAL_CHANNELS_3D + MAX_OPENAL_CHANNELS_2D + MAX_OPENAL_CHANNELS_2D_STREAM + i]
|
|
|
|
);
|
|
|
|
}
|
2024-01-07 19:47:58 +01:00
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
S_OPENAL_Pitch
|
|
|
|
==============
|
|
|
|
*/
|
2024-01-07 19:47:58 +01:00
|
|
|
static void S_OPENAL_Pitch()
|
|
|
|
{
|
2024-01-12 00:04:36 +01:00
|
|
|
Com_Printf("S_OPENAL_Pitch() needs to be implemented!\n");
|
2024-01-07 19:47:58 +01:00
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
S_OPENAL_LoadMP3
|
|
|
|
==============
|
|
|
|
*/
|
2024-01-07 19:47:58 +01:00
|
|
|
static bool S_OPENAL_LoadMP3(const char *_path, openal_channel *chan)
|
|
|
|
{
|
2024-07-01 18:00:15 +02:00
|
|
|
char path[MAX_QPATH];
|
|
|
|
snd_info_t info;
|
|
|
|
ALuint format;
|
|
|
|
|
|
|
|
chan->stop();
|
2024-01-16 20:54:41 +01:00
|
|
|
|
2024-07-01 18:00:15 +02:00
|
|
|
qalSourcei(chan->source, AL_BUFFER, 0);
|
|
|
|
alDieIfError();
|
|
|
|
|
|
|
|
Q_strncpyz(path, _path, sizeof(path));
|
|
|
|
path[MAX_QPATH - 1] = 0;
|
|
|
|
|
|
|
|
FS_CorrectCase(path);
|
|
|
|
|
|
|
|
// Try to load
|
|
|
|
chan->bufferdata = (ALubyte*)S_CodecLoad(path, &info);
|
|
|
|
if (!chan->bufferdata) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
format = S_OPENAL_Format(info.width, info.channels);
|
|
|
|
|
|
|
|
// Create a buffer
|
|
|
|
qalGenBuffers(1, &chan->buffer);
|
|
|
|
alDieIfError();
|
|
|
|
|
|
|
|
// Fill the buffer
|
|
|
|
if (info.size == 0) {
|
|
|
|
// We have no data to buffer, so buffer silence
|
|
|
|
byte dummyData[2] = {0};
|
|
|
|
|
|
|
|
qalBufferData(chan->buffer, AL_FORMAT_MONO16, (void *)dummyData, 2, 22050);
|
|
|
|
} else {
|
|
|
|
qalBufferData(chan->buffer, format, chan->bufferdata, info.size, info.rate);
|
|
|
|
}
|
|
|
|
|
|
|
|
alDieIfError();
|
|
|
|
|
|
|
|
// Free the memory
|
|
|
|
Hunk_FreeTempMemory(chan->bufferdata);
|
2024-07-01 19:39:51 +02:00
|
|
|
chan->bufferdata = NULL;
|
2024-07-01 18:00:15 +02:00
|
|
|
|
|
|
|
qalSourcei(chan->source, AL_BUFFER, chan->buffer);
|
|
|
|
alDieIfError();
|
|
|
|
|
|
|
|
chan->set_no_3d();
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
#if 0
|
2024-01-12 00:04:36 +01:00
|
|
|
char path[MAX_QPATH];
|
|
|
|
FILE *in;
|
|
|
|
size_t len;
|
|
|
|
size_t rc;
|
|
|
|
bool failed;
|
|
|
|
|
|
|
|
chan->stop();
|
|
|
|
|
|
|
|
qalSourcei(chan->source, AL_BUFFER, 0);
|
|
|
|
alDieIfError();
|
|
|
|
|
|
|
|
S_OPENAL_NukeBuffer(&chan->buffer);
|
|
|
|
alDieIfError();
|
|
|
|
|
|
|
|
Q_strncpyz(path, _path, sizeof(path));
|
|
|
|
path[MAX_QPATH - 1] = 0;
|
|
|
|
|
|
|
|
FS_CorrectCase(path);
|
|
|
|
|
|
|
|
in = fopen(path, "rb");
|
|
|
|
if (!in) {
|
|
|
|
Com_DPrintf("Failed to open MP3 \"%s\" for playback\n", path);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
fseek(in, 0, SEEK_END);
|
|
|
|
len = ftell(in);
|
|
|
|
fseek(in, 0, SEEK_SET);
|
|
|
|
|
|
|
|
chan->bufferdata = new ALubyte[len];
|
|
|
|
rc = fread(chan->bufferdata, 1, len, in);
|
|
|
|
fclose(in);
|
|
|
|
|
|
|
|
if (rc != len) {
|
|
|
|
delete[] chan->bufferdata;
|
|
|
|
chan->bufferdata = NULL;
|
|
|
|
Com_DPrintf("Failed to read MP3 \"%s\" from disk\n", path);
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
qalGenBuffers(1, &chan->buffer);
|
|
|
|
alDieIfError();
|
|
|
|
|
|
|
|
failed = !_alutLoadMP3_LOKI(chan->buffer, chan->bufferdata, rc);
|
|
|
|
alDieIfError();
|
|
|
|
|
|
|
|
delete[] chan->bufferdata;
|
|
|
|
chan->bufferdata = NULL;
|
|
|
|
|
|
|
|
if (failed) {
|
|
|
|
Com_DPrintf("Failed to decode MP3 file \"%s\"\n", path);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
qalSourcei(chan->source, AL_BUFFER, chan->buffer);
|
|
|
|
alDieIfError();
|
|
|
|
|
|
|
|
chan->set_no_3d();
|
|
|
|
|
|
|
|
return true;
|
2024-07-01 18:00:15 +02:00
|
|
|
#endif
|
2024-01-07 19:47:58 +01:00
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
S_OPENAL_PlayMP3
|
|
|
|
==============
|
|
|
|
*/
|
2024-01-07 19:47:58 +01:00
|
|
|
static void S_OPENAL_PlayMP3()
|
|
|
|
{
|
2024-01-12 00:04:36 +01:00
|
|
|
const char *path;
|
|
|
|
|
|
|
|
if (Cmd_Argc() != 2) {
|
|
|
|
Com_Printf("playmp3 <mp3 file>\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
path = Cmd_Argv(1);
|
|
|
|
if (!S_OPENAL_LoadMP3(path, &openal.chan_mp3)) {
|
|
|
|
Com_Printf("Failed to play mp3 - %s\n", path);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
openal.chan_mp3.play();
|
|
|
|
Com_Printf("Playing mp3 - %s\n", path);
|
2024-01-07 19:47:58 +01:00
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
S_OPENAL_StopMP3
|
|
|
|
==============
|
|
|
|
*/
|
2024-01-07 19:47:58 +01:00
|
|
|
static void S_OPENAL_StopMP3()
|
|
|
|
{
|
2024-01-12 00:04:36 +01:00
|
|
|
S_OPENAL_NukeChannel(&openal.chan_mp3);
|
2024-01-07 19:47:58 +01:00
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
MUSIC_Pause
|
|
|
|
==============
|
|
|
|
*/
|
2024-01-07 19:47:58 +01:00
|
|
|
void MUSIC_Pause()
|
|
|
|
{
|
2024-01-12 00:04:36 +01:00
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < MAX_OPENAL_SONGS; i++) {
|
|
|
|
openal.chan_song[i].pause();
|
|
|
|
}
|
2024-01-07 19:47:58 +01:00
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
MUSIC_Unpause
|
|
|
|
==============
|
|
|
|
*/
|
2024-01-07 19:47:58 +01:00
|
|
|
void MUSIC_Unpause()
|
|
|
|
{
|
2024-01-12 00:04:36 +01:00
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < MAX_OPENAL_SONGS; i++) {
|
|
|
|
if (openal.chan_song[i].is_paused()) {
|
|
|
|
openal.chan_song[i].play();
|
|
|
|
}
|
|
|
|
}
|
2024-01-07 19:47:58 +01:00
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
S_PauseSound
|
|
|
|
==============
|
|
|
|
*/
|
2024-01-07 19:47:58 +01:00
|
|
|
void S_PauseSound()
|
|
|
|
{
|
2024-01-12 00:04:36 +01:00
|
|
|
int i;
|
|
|
|
|
|
|
|
if (!s_bSoundStarted) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
s_bSoundPaused = true;
|
|
|
|
|
|
|
|
for (i = 0; i < MAX_OPENAL_POSITION_CHANNELS; i++) {
|
|
|
|
openal_channel *pChannel = openal.channel[i];
|
|
|
|
if (!pChannel) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pChannel->iEntChannel == CHAN_MENU) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!pChannel->is_playing()) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
pChannel->pause();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (openal.chan_mp3.is_playing()) {
|
|
|
|
openal.chan_mp3.pause();
|
|
|
|
}
|
|
|
|
|
|
|
|
MUSIC_Pause();
|
|
|
|
S_TriggeredMusic_Pause();
|
2024-01-07 19:47:58 +01:00
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
S_UnpauseSound
|
|
|
|
==============
|
|
|
|
*/
|
2024-01-07 19:47:58 +01:00
|
|
|
void S_UnpauseSound()
|
|
|
|
{
|
2024-01-12 00:04:36 +01:00
|
|
|
int i;
|
|
|
|
|
|
|
|
if (!s_bSoundStarted) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < MAX_OPENAL_POSITION_CHANNELS; i++) {
|
|
|
|
openal_channel *pChannel = openal.channel[i];
|
|
|
|
if (!pChannel) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2024-08-05 18:49:41 +02:00
|
|
|
if (pChannel->is_paused() || (pChannel->iFlags & CHANNEL_FLAG_PLAY_DEFERRED)) {
|
|
|
|
pChannel->iFlags &= ~CHANNEL_FLAG_PLAY_DEFERRED;
|
2024-07-22 20:44:00 +02:00
|
|
|
pChannel->play();
|
2024-01-12 00:04:36 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (openal.chan_mp3.is_paused()) {
|
|
|
|
openal.chan_mp3.play();
|
|
|
|
}
|
|
|
|
|
|
|
|
MUSIC_Unpause();
|
|
|
|
S_TriggeredMusic_Unpause();
|
|
|
|
|
|
|
|
s_bSoundPaused = false;
|
2024-01-07 19:47:58 +01:00
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
S_OPENAL_ShouldPlay
|
|
|
|
==============
|
|
|
|
*/
|
2024-01-07 19:47:58 +01:00
|
|
|
static qboolean S_OPENAL_ShouldPlay(sfx_t *pSfx)
|
|
|
|
{
|
2024-01-12 00:04:36 +01:00
|
|
|
if (sfx_infos[pSfx->sfx_info_index].max_number_playing <= 0) {
|
|
|
|
return qtrue;
|
|
|
|
}
|
|
|
|
|
|
|
|
int iRemainingTimesToPlay;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
iRemainingTimesToPlay = sfx_infos[pSfx->sfx_info_index].max_number_playing;
|
|
|
|
|
|
|
|
for (i = 0; i < MAX_OPENAL_POSITION_CHANNELS; i++) {
|
|
|
|
openal_channel *pChannel = openal.channel[i];
|
|
|
|
if (!pChannel) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pChannel->pSfx == pSfx && pChannel->is_playing()) {
|
|
|
|
iRemainingTimesToPlay--;
|
|
|
|
if (!iRemainingTimesToPlay) {
|
|
|
|
return qfalse;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return qtrue;
|
2024-01-07 19:47:58 +01:00
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
S_OPENAL_ShouldStart
|
|
|
|
==============
|
|
|
|
*/
|
2024-01-07 23:36:32 +01:00
|
|
|
static qboolean S_OPENAL_ShouldStart(const vec3_t vOrigin, float fMinDist, float fMaxDist)
|
2024-01-07 19:47:58 +01:00
|
|
|
{
|
2024-01-12 00:04:36 +01:00
|
|
|
vec3_t vDir;
|
|
|
|
vec3_t vListenerOrigin;
|
|
|
|
vec3_t alvec;
|
|
|
|
|
|
|
|
if (!al_initialized) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
qalGetListenerfv(AL_POSITION, alvec);
|
|
|
|
|
2024-01-17 20:44:32 +01:00
|
|
|
VectorCopy(alvec, vListenerOrigin);
|
2024-01-12 00:04:36 +01:00
|
|
|
VectorSubtract(vOrigin, vListenerOrigin, vDir);
|
|
|
|
|
|
|
|
return Square(fMaxDist) > VectorLengthSquared(vDir);
|
2024-01-07 19:47:58 +01:00
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
S_OPENAL_PickChannelBase
|
|
|
|
==============
|
|
|
|
*/
|
2024-01-07 19:47:58 +01:00
|
|
|
static int S_OPENAL_PickChannelBase(int iEntNum, int iEntChannel, int iFirstChannel, int iLastChannel)
|
|
|
|
{
|
2024-01-12 00:04:36 +01:00
|
|
|
int i;
|
|
|
|
int iBestChannel;
|
|
|
|
openal_channel *pChannel;
|
|
|
|
|
|
|
|
iBestChannel = -1;
|
|
|
|
if (iEntNum != ENTITYNUM_NONE && iEntChannel) {
|
|
|
|
bool bStoppedChannel = false;
|
|
|
|
|
|
|
|
for (i = iFirstChannel; i <= iLastChannel; i++) {
|
|
|
|
pChannel = openal.channel[i];
|
|
|
|
if (!pChannel) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pChannel->is_free()) {
|
|
|
|
iBestChannel = i;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pChannel->iEntNum == iEntNum && pChannel->iEntChannel == iEntChannel) {
|
|
|
|
pChannel->end_sample();
|
|
|
|
bStoppedChannel = 1;
|
|
|
|
iBestChannel = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!bStoppedChannel) {
|
|
|
|
for (i = 0; i < iFirstChannel; ++i) {
|
|
|
|
pChannel = openal.channel[i];
|
|
|
|
if (!pChannel || pChannel->is_free()) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pChannel->iEntNum == iEntNum && pChannel->iEntChannel == iEntChannel) {
|
|
|
|
bStoppedChannel = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!bStoppedChannel) {
|
2024-07-01 17:39:32 +02:00
|
|
|
for(i = iLastChannel + 1; i < MAX_OPENAL_POSITION_CHANNELS; i++) {
|
2024-01-12 00:04:36 +01:00
|
|
|
pChannel = openal.channel[i];
|
|
|
|
if (!pChannel || pChannel->is_free()) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pChannel->iEntNum == iEntNum && pChannel->iEntChannel == iEntChannel) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (iBestChannel < 0) {
|
|
|
|
int iBestTime = 0x7FFFFFFF;
|
|
|
|
|
|
|
|
for (i = iFirstChannel; i <= iLastChannel; i++) {
|
|
|
|
pChannel = openal.channel[i];
|
|
|
|
if (!pChannel) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pChannel->is_free()) {
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pChannel->iEntNum == s_iListenerNumber && iEntNum != pChannel->iEntNum) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pChannel->iEntChannel < iEntChannel
|
|
|
|
|| (pChannel->iEntChannel == iEntChannel && pChannel->iStartTime < iBestTime)) {
|
|
|
|
iBestChannel = i;
|
|
|
|
iEntChannel = pChannel->iEntChannel;
|
|
|
|
iBestTime = pChannel->iStartTime;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return iBestChannel;
|
2024-01-07 19:47:58 +01:00
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
S_OPENAL_PickChannel3D
|
|
|
|
==============
|
|
|
|
*/
|
2024-01-07 19:47:58 +01:00
|
|
|
static int S_OPENAL_PickChannel3D(int iEntNum, int iEntChannel)
|
|
|
|
{
|
2024-01-12 00:04:36 +01:00
|
|
|
return S_OPENAL_PickChannelBase(iEntNum, iEntChannel, 0, MAX_OPENAL_CHANNELS_3D - 1);
|
2024-01-07 19:47:58 +01:00
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
S_OPENAL_PickChannel2D
|
|
|
|
==============
|
|
|
|
*/
|
2024-01-07 19:47:58 +01:00
|
|
|
static int S_OPENAL_PickChannel2D(int iEntNum, int iEntChannel)
|
|
|
|
{
|
2024-01-12 00:04:36 +01:00
|
|
|
return S_OPENAL_PickChannelBase(
|
|
|
|
iEntNum, iEntChannel, MAX_OPENAL_CHANNELS_3D, MAX_OPENAL_CHANNELS_3D + MAX_OPENAL_CHANNELS_2D - 1
|
|
|
|
);
|
2024-01-07 19:47:58 +01:00
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
S_OPENAL_PickChannel2DStreamed
|
|
|
|
==============
|
|
|
|
*/
|
2024-01-07 19:47:58 +01:00
|
|
|
static int S_OPENAL_PickChannel2DStreamed(int iEntNum, int iEntChannel)
|
|
|
|
{
|
2024-01-12 00:04:36 +01:00
|
|
|
return S_OPENAL_PickChannelBase(
|
|
|
|
iEntNum,
|
|
|
|
iEntChannel,
|
|
|
|
MAX_OPENAL_CHANNELS_3D + MAX_OPENAL_CHANNELS_2D,
|
|
|
|
MAX_OPENAL_CHANNELS_3D + MAX_OPENAL_CHANNELS_2D + MAX_OPENAL_CHANNELS_2D_STREAM - 1
|
|
|
|
);
|
2024-01-07 19:47:58 +01:00
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
callbackServer
|
|
|
|
==============
|
|
|
|
*/
|
2024-01-07 19:47:58 +01:00
|
|
|
void callbackServer(int entnum, int channel_number, const char *name)
|
|
|
|
{
|
2024-01-12 00:04:36 +01:00
|
|
|
if (!com_sv_running->integer) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
SV_SoundCallback(entnum, channel_number, name);
|
2024-01-07 19:47:58 +01:00
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
S_OPENAL_Start2DSound
|
|
|
|
==============
|
|
|
|
*/
|
2024-01-07 19:47:58 +01:00
|
|
|
static void S_OPENAL_Start2DSound(
|
2024-01-07 23:36:32 +01:00
|
|
|
const vec3_t vOrigin,
|
|
|
|
int iEntNum,
|
|
|
|
int iEntChannel,
|
|
|
|
sfx_t *pSfx,
|
|
|
|
float fVolume,
|
|
|
|
float fMinDistance,
|
|
|
|
float fPitch,
|
|
|
|
float fMaxDistance
|
2024-01-07 19:47:58 +01:00
|
|
|
)
|
|
|
|
{
|
2024-01-12 00:04:36 +01:00
|
|
|
int iRealEntNum;
|
|
|
|
int iFreeChannel;
|
|
|
|
openal_channel *pChannel;
|
|
|
|
float fRealVolume;
|
|
|
|
bool bSupportWaitTillSoundDone;
|
|
|
|
|
|
|
|
iRealEntNum = iEntNum & ~S_FLAG_DO_CALLBACK;
|
|
|
|
|
2024-07-01 18:05:24 +02:00
|
|
|
if (pSfx->iFlags & SFX_FLAG_STREAMED) {
|
2024-01-12 00:04:36 +01:00
|
|
|
iFreeChannel = S_OPENAL_PickChannel2DStreamed(iRealEntNum, iEntChannel);
|
|
|
|
} else {
|
|
|
|
iFreeChannel = S_OPENAL_PickChannel2D(iRealEntNum, iEntChannel);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (iFreeChannel < 0) {
|
|
|
|
Com_DPrintf(
|
|
|
|
"Couldn't play %s sound '%s' for entity %i on channel %s\n",
|
2024-07-01 18:05:24 +02:00
|
|
|
(pSfx->iFlags & SFX_FLAG_STREAMED) ? "2Dstreamed" : "2D",
|
2024-01-12 00:04:36 +01:00
|
|
|
pSfx->name,
|
2024-01-18 20:39:04 +01:00
|
|
|
iRealEntNum,
|
2024-01-12 00:04:36 +01:00
|
|
|
S_ChannelNumToName(iEntChannel)
|
|
|
|
);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (iEntNum & S_FLAG_DO_CALLBACK) {
|
2024-01-18 20:39:04 +01:00
|
|
|
callbackServer(iRealEntNum, iFreeChannel, pSfx->name);
|
2024-01-12 00:04:36 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
pChannel = openal.channel[iFreeChannel];
|
|
|
|
pChannel->force_free();
|
|
|
|
|
|
|
|
if (fVolume < 0) {
|
|
|
|
fVolume = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
fRealVolume = S_GetBaseVolume() * fVolume;
|
|
|
|
pChannel->fVolume = fVolume;
|
|
|
|
|
|
|
|
if (pChannel->iEntChannel == CHAN_LOCAL) {
|
|
|
|
pChannel->iFlags |= CHANNEL_FLAG_LOCAL_LISTENER;
|
|
|
|
} else {
|
|
|
|
pChannel->iFlags &= ~CHANNEL_FLAG_LOCAL_LISTENER;
|
|
|
|
}
|
|
|
|
pChannel->iFlags &= ~CHANNEL_FLAG_PAUSED;
|
|
|
|
|
|
|
|
if (fMinDistance < 0.0) {
|
|
|
|
fMinDistance = 200.0;
|
|
|
|
}
|
|
|
|
pChannel->fMinDist = fMinDistance;
|
|
|
|
|
|
|
|
if (fMaxDistance < 0.0) {
|
|
|
|
fMaxDistance = pChannel->fMinDist * 64;
|
|
|
|
}
|
|
|
|
pChannel->fMaxDist = fMaxDistance;
|
|
|
|
|
|
|
|
pChannel->fNewPitchMult = fPitch;
|
|
|
|
pChannel->pSfx = pSfx;
|
|
|
|
pChannel->iEntNum = iRealEntNum;
|
|
|
|
pChannel->iEntChannel = iEntChannel;
|
2024-01-18 20:39:04 +01:00
|
|
|
if (iRealEntNum == ENTITYNUM_NONE) {
|
2024-01-12 00:04:36 +01:00
|
|
|
VectorClear(pChannel->vOrigin);
|
|
|
|
pChannel->iFlags |= CHANNEL_FLAG_NO_ENTITY;
|
|
|
|
pChannel->iEntNum = 0;
|
|
|
|
|
|
|
|
if (vOrigin) {
|
2024-07-01 17:39:32 +02:00
|
|
|
VectorCopy(vOrigin, pChannel->vOrigin);
|
2024-01-12 00:04:36 +01:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
pChannel->iFlags &= ~CHANNEL_FLAG_NO_ENTITY;
|
|
|
|
pChannel->iEntNum = iRealEntNum;
|
|
|
|
if (vOrigin) {
|
2024-07-01 17:39:32 +02:00
|
|
|
VectorCopy(vOrigin, pChannel->vOrigin);
|
2024-01-12 00:04:36 +01:00
|
|
|
|
|
|
|
bSupportWaitTillSoundDone = cl.serverTime - 1 < 0;
|
2024-01-15 23:04:25 +01:00
|
|
|
pChannel->iTime = cl.serverTime - 1;
|
2024-01-12 00:04:36 +01:00
|
|
|
if (bSupportWaitTillSoundDone) {
|
|
|
|
pChannel->iTime = 0;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
VectorClear(pChannel->vOrigin);
|
|
|
|
pChannel->iTime = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pChannel->iStartTime = cl.serverTime;
|
|
|
|
pChannel->iEndTime = (int)(cl.serverTime + pSfx->time_length + 250.f);
|
|
|
|
|
|
|
|
if (iFreeChannel > MAX_OPENAL_CHANNELS_3D + MAX_OPENAL_CHANNELS_2D) {
|
|
|
|
// streamed
|
|
|
|
if (!pChannel->set_sfx(pSfx)) {
|
|
|
|
Com_DPrintf("Set stream error - %s\n", pSfx->name);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
pChannel->iBaseRate = pChannel->sample_playback_rate();
|
|
|
|
pChannel->set_no_3d();
|
2024-07-01 16:46:47 +02:00
|
|
|
fRealVolume = fRealVolume * s_fVolumeGain;
|
2024-01-12 00:04:36 +01:00
|
|
|
pChannel->set_gain(fRealVolume);
|
|
|
|
pChannel->play();
|
|
|
|
} else {
|
|
|
|
pChannel->stop();
|
|
|
|
pChannel->set_no_3d();
|
|
|
|
pChannel->set_sfx(pSfx);
|
|
|
|
pChannel->set_gain(fRealVolume);
|
|
|
|
pChannel->play();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (s_show_sounds->integer > 0) {
|
|
|
|
Com_DPrintf(
|
|
|
|
"2D - %d (#%i) - %s (vol %f, mindist %f, maxdist %f)\n",
|
|
|
|
cl.serverTime,
|
|
|
|
iFreeChannel,
|
|
|
|
pSfx->name,
|
|
|
|
fVolume,
|
|
|
|
fMinDistance,
|
|
|
|
fMaxDistance
|
|
|
|
);
|
|
|
|
}
|
2024-01-07 19:47:58 +01:00
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
S_OPENAL_StartSound
|
|
|
|
==============
|
|
|
|
*/
|
2024-01-07 19:47:58 +01:00
|
|
|
void S_OPENAL_StartSound(
|
2024-01-07 23:42:32 +01:00
|
|
|
const vec3_t vOrigin,
|
|
|
|
int iEntNum,
|
|
|
|
int iEntChannel,
|
|
|
|
sfxHandle_t sfxHandle,
|
|
|
|
float fVolume,
|
|
|
|
float fMinDist,
|
|
|
|
float fPitch,
|
|
|
|
float fMaxDist,
|
|
|
|
qboolean bStreamed
|
2024-01-07 19:47:58 +01:00
|
|
|
)
|
|
|
|
{
|
2024-01-15 23:04:25 +01:00
|
|
|
int iChannel;
|
|
|
|
openal_channel *pChannel;
|
|
|
|
sfx_info_t *pSfxInfo;
|
|
|
|
sfx_t *pSfx;
|
|
|
|
ALint state;
|
|
|
|
bool bOnlyUpdate;
|
|
|
|
bool bSupportWaitTillSoundDone;
|
2024-01-12 00:04:36 +01:00
|
|
|
|
|
|
|
bOnlyUpdate = false;
|
2024-01-15 23:04:25 +01:00
|
|
|
pSfx = &s_knownSfx[sfxHandle];
|
2024-01-12 00:04:36 +01:00
|
|
|
if (bStreamed) {
|
2024-07-01 18:05:24 +02:00
|
|
|
pSfx->iFlags |= SFX_FLAG_STREAMED;
|
2024-01-12 00:04:36 +01:00
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
if (!S_OPENAL_ShouldPlay(pSfx)) {
|
2024-01-12 00:04:36 +01:00
|
|
|
Com_DPrintf("^~^~^ Not playing sound '%s'\n", pSfx->name);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2024-08-06 18:43:15 +02:00
|
|
|
if ((pSfx->iFlags & (SFX_FLAG_NO_OFFSET) || pSfx->iFlags & (SFX_FLAG_STREAMED | SFX_FLAG_MP3))
|
2024-07-01 18:17:04 +02:00
|
|
|
|| iEntChannel == CHAN_MENU || iEntChannel == CHAN_LOCAL) {
|
2024-01-12 00:04:36 +01:00
|
|
|
S_OPENAL_Start2DSound(vOrigin, iEntNum, iEntChannel, pSfx, fVolume, fMinDist, fPitch, fMaxDist);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
bSupportWaitTillSoundDone = (iEntNum & S_FLAG_DO_CALLBACK) != 0;
|
|
|
|
iEntNum &= ~S_FLAG_DO_CALLBACK;
|
|
|
|
|
|
|
|
pSfxInfo = &sfx_infos[pSfx->sfx_info_index];
|
2024-08-06 18:43:15 +02:00
|
|
|
if (pSfx->iFlags & SFX_FLAG_STREAMED) {
|
|
|
|
Com_DPrintf("3D sounds not supported - couldn't play '%s'\n", pSfx->name);
|
|
|
|
return;
|
|
|
|
}
|
2024-01-12 00:04:36 +01:00
|
|
|
|
|
|
|
iChannel = S_OPENAL_PickChannel3D(iEntNum, iEntChannel);
|
2024-01-15 23:04:25 +01:00
|
|
|
if (iChannel < 0) {
|
|
|
|
Com_DPrintf(
|
|
|
|
"Couldn't play %s sound '%s' for entity %i on channel %s\n",
|
2024-07-01 18:05:24 +02:00
|
|
|
(pSfx->iFlags & SFX_FLAG_STREAMED) ? "3Dstreamed" : "3D",
|
2024-01-15 23:04:25 +01:00
|
|
|
pSfx->name,
|
|
|
|
iEntNum,
|
|
|
|
S_ChannelNumToName(iEntChannel)
|
|
|
|
);
|
2024-01-12 00:04:36 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bSupportWaitTillSoundDone) {
|
|
|
|
callbackServer(iEntNum, iChannel, pSfx->name);
|
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
pChannel = &openal.chan_3D[iChannel];
|
2024-01-12 00:04:36 +01:00
|
|
|
pChannel->fNewPitchMult = fPitch;
|
2024-01-15 23:04:25 +01:00
|
|
|
pChannel->iEntChannel = iEntChannel;
|
2024-01-12 00:04:36 +01:00
|
|
|
pChannel->iFlags &= ~(CHANNEL_FLAG_PAUSED | CHANNEL_FLAG_LOCAL_LISTENER);
|
|
|
|
state = pChannel->get_state();
|
2024-01-17 20:44:32 +01:00
|
|
|
// Fixed in OPM
|
|
|
|
// Setup the channel for 3D
|
|
|
|
pChannel->set_3d();
|
2024-01-12 00:04:36 +01:00
|
|
|
|
|
|
|
if (pChannel->iEntNum == iEntNum && (state == AL_PLAYING || state == AL_PAUSED) && pChannel->pSfx == pSfx) {
|
|
|
|
bOnlyUpdate = true;
|
|
|
|
} else {
|
|
|
|
pChannel->stop();
|
|
|
|
pChannel->iFlags &= ~(CHANNEL_FLAG_LOOPING | CHANNEL_FLAG_PAUSED | CHANNEL_FLAG_LOCAL_LISTENER);
|
|
|
|
if (!pChannel->set_sfx(pSfx)) {
|
|
|
|
Com_DPrintf("Set sample error - %s\n", pSfx->name);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
if (fMinDist < 0.0) {
|
2024-01-12 00:04:36 +01:00
|
|
|
fMinDist = 200.0;
|
|
|
|
fMaxDist = 12800.0;
|
|
|
|
}
|
|
|
|
pChannel->fMinDist = fMinDist;
|
|
|
|
pChannel->fMaxDist = fMaxDist;
|
|
|
|
|
|
|
|
if (fVolume < 0.0) {
|
|
|
|
fVolume = 1.0;
|
|
|
|
}
|
|
|
|
|
|
|
|
pChannel->fVolume = S_GetBaseVolume() * fVolume;
|
|
|
|
pChannel->set_gain(pChannel->fVolume);
|
|
|
|
|
|
|
|
if (s_show_sounds->integer > 0) {
|
|
|
|
Com_DPrintf(
|
|
|
|
"%d (#%i) - %s (vol %f, mindist %f, maxdist %f)\n",
|
|
|
|
cl.serverTime,
|
|
|
|
iChannel,
|
|
|
|
pSfx->name,
|
|
|
|
pChannel->fVolume,
|
|
|
|
fMinDist,
|
2024-01-15 23:04:25 +01:00
|
|
|
fMaxDist
|
|
|
|
);
|
2024-01-12 00:04:36 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
pChannel->set_velocity(0, 0, 0);
|
|
|
|
if (iEntNum == ENTITYNUM_NONE) {
|
|
|
|
if (vOrigin) {
|
2024-01-17 20:44:32 +01:00
|
|
|
VectorCopy(vOrigin, pChannel->vOrigin);
|
2024-01-12 00:04:36 +01:00
|
|
|
} else {
|
|
|
|
//VectorClear(vOrigin);
|
|
|
|
// Fixed in OPM
|
|
|
|
// Tiny mistake found in original where the vOrigin parameter is set to 0
|
|
|
|
VectorClear(pChannel->vOrigin);
|
|
|
|
}
|
|
|
|
|
2024-01-17 20:44:32 +01:00
|
|
|
pChannel->set_position(pChannel->vOrigin[0], pChannel->vOrigin[1], pChannel->vOrigin[2]);
|
2024-01-12 00:04:36 +01:00
|
|
|
pChannel->iFlags |= CHANNEL_FLAG_NO_ENTITY;
|
|
|
|
pChannel->iEntNum = 0;
|
|
|
|
} else {
|
|
|
|
pChannel->iEntNum = iEntNum;
|
|
|
|
if (vOrigin) {
|
2024-01-17 20:44:32 +01:00
|
|
|
VectorCopy(vOrigin, pChannel->vOrigin);
|
|
|
|
|
2024-01-12 00:04:36 +01:00
|
|
|
bSupportWaitTillSoundDone = cl.serverTime - 1 < 0;
|
2024-01-15 23:04:25 +01:00
|
|
|
pChannel->iTime = cl.serverTime - 1;
|
2024-01-12 00:04:36 +01:00
|
|
|
if (bSupportWaitTillSoundDone) {
|
|
|
|
pChannel->iTime = 0;
|
|
|
|
}
|
2024-08-17 17:24:17 +02:00
|
|
|
|
|
|
|
if (s_entity[iEntNum].time < pChannel->iTime) {
|
|
|
|
// Fixed in OPM
|
|
|
|
// Not sure if it's the real solution, but script_origin entities are usually
|
|
|
|
// never sent to client so the sound will immediately get stopped
|
|
|
|
pChannel->iFlags |= CHANNEL_FLAG_NO_ENTITY;
|
|
|
|
}
|
2024-01-12 00:04:36 +01:00
|
|
|
} else {
|
|
|
|
VectorClear(pChannel->vOrigin);
|
|
|
|
pChannel->iTime = 0;
|
|
|
|
}
|
2024-01-17 20:44:32 +01:00
|
|
|
pChannel->set_position(pChannel->vOrigin[0], pChannel->vOrigin[1], pChannel->vOrigin[2]);
|
2024-01-12 00:04:36 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (pSfxInfo->loop_start != -1) {
|
|
|
|
pChannel->set_sample_loop_block(pSfxInfo->loop_start, pSfxInfo->loop_end);
|
|
|
|
pChannel->set_sample_loop_count(0);
|
|
|
|
|
|
|
|
pChannel->iFlags |= CHANNEL_FLAG_LOOPING;
|
|
|
|
if (s_show_sounds->integer) {
|
|
|
|
Com_DPrintf("loopblock - %d to %d\n", pSfxInfo->loop_start, pSfxInfo->loop_end);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
pChannel->set_sample_loop_count(1);
|
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
if (!bOnlyUpdate && S_OPENAL_ShouldStart(pChannel->vOrigin, pChannel->fMinDist, pChannel->fMaxDist)) {
|
2024-01-12 00:04:36 +01:00
|
|
|
pChannel->play();
|
2024-01-15 23:04:25 +01:00
|
|
|
pChannel->iEndTime = cl.serverTime + (int)pChannel->pSfx->time_length + 250;
|
|
|
|
pChannel->iBaseRate = pChannel->sample_playback_rate();
|
2024-01-12 00:04:36 +01:00
|
|
|
pChannel->iStartTime = cl.serverTime;
|
|
|
|
}
|
2024-01-07 19:47:58 +01:00
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
S_OPENAL_AddLoopingSound
|
|
|
|
==============
|
|
|
|
*/
|
2024-01-07 19:47:58 +01:00
|
|
|
void S_OPENAL_AddLoopingSound(
|
2024-01-07 23:36:32 +01:00
|
|
|
const vec3_t vOrigin,
|
|
|
|
const vec3_t vVelocity,
|
|
|
|
sfxHandle_t sfxHandle,
|
|
|
|
float fVolume,
|
|
|
|
float fMinDist,
|
|
|
|
float fMaxDist,
|
|
|
|
float fPitch,
|
|
|
|
int iFlags
|
2024-01-07 19:47:58 +01:00
|
|
|
)
|
|
|
|
{
|
2024-01-15 23:04:25 +01:00
|
|
|
int i;
|
|
|
|
int iFreeLoopSound;
|
|
|
|
sfx_t *pSfx;
|
|
|
|
openal_loop_sound_t *pLoopSound;
|
2024-01-12 00:04:36 +01:00
|
|
|
|
|
|
|
iFreeLoopSound = -1;
|
2024-01-15 23:04:25 +01:00
|
|
|
pSfx = &s_knownSfx[sfxHandle];
|
2024-01-12 00:04:36 +01:00
|
|
|
if (!pSfx) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < (MAX_OPENAL_CHANNELS_3D + MAX_OPENAL_CHANNELS_2D); i++) {
|
|
|
|
pLoopSound = &openal.loop_sounds[i];
|
|
|
|
if (pLoopSound->pSfx == pSfx && !pLoopSound->bInUse) {
|
|
|
|
iFreeLoopSound = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (iFreeLoopSound < 0) {
|
|
|
|
for (i = 0; i < (MAX_OPENAL_CHANNELS_3D + MAX_OPENAL_CHANNELS_2D); i++) {
|
|
|
|
pLoopSound = &openal.loop_sounds[i];
|
|
|
|
if (!pLoopSound->pSfx && !pLoopSound->bInUse) {
|
2024-01-15 23:04:25 +01:00
|
|
|
iFreeLoopSound = i;
|
2024-01-12 00:04:36 +01:00
|
|
|
pLoopSound->bPlaying = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (iFreeLoopSound < 0) {
|
|
|
|
if (cls.realtime >= s_iNextLoopingWarning) {
|
|
|
|
Com_DPrintf("Too many looping sounds\n");
|
|
|
|
s_iNextLoopingWarning = cls.realtime + 1000;
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2024-01-17 20:44:32 +01:00
|
|
|
pLoopSound = &openal.loop_sounds[iFreeLoopSound];
|
2024-07-02 20:25:08 +02:00
|
|
|
VectorCopy(vOrigin, pLoopSound->vOrigin);
|
2024-01-17 20:44:32 +01:00
|
|
|
VectorCopy(vVelocity, pLoopSound->vVelocity);
|
|
|
|
pLoopSound->pSfx = pSfx;
|
|
|
|
pLoopSound->bInUse = true;
|
|
|
|
pLoopSound->iStartTime = cls.realtime;
|
|
|
|
pLoopSound->fBaseVolume = fVolume;
|
|
|
|
pLoopSound->fMinDist = fMinDist;
|
|
|
|
pLoopSound->fMaxDist = fMaxDist;
|
|
|
|
pLoopSound->fPitch = fPitch;
|
|
|
|
pLoopSound->iFlags = iFlags;
|
|
|
|
pLoopSound->bCombine = VectorCompare(vVelocity, vec_zero) == 0;
|
2024-01-12 00:04:36 +01:00
|
|
|
|
|
|
|
if (pLoopSound->bCombine) {
|
|
|
|
for (i = 0; i < (MAX_OPENAL_CHANNELS_3D + MAX_OPENAL_CHANNELS_2D); i++) {
|
|
|
|
if (openal.loop_sounds[i].pSfx == pSfx && openal.loop_sounds[i].bInUse) {
|
|
|
|
pLoopSound->iStartTime = openal.loop_sounds[i].iStartTime;
|
|
|
|
if (openal.loop_sounds[i].bPlaying) {
|
|
|
|
pLoopSound->bPlaying = true;
|
|
|
|
pLoopSound->iChannel = openal.loop_sounds[i].iChannel;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2024-01-07 19:47:58 +01:00
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
S_OPENAL_StopLoopingSound
|
|
|
|
==============
|
|
|
|
*/
|
2024-01-07 19:47:58 +01:00
|
|
|
void S_OPENAL_StopLoopingSound(openal_loop_sound_t *pLoopSound)
|
|
|
|
{
|
2024-01-15 23:04:25 +01:00
|
|
|
bool bMayStop;
|
|
|
|
int i;
|
|
|
|
openal_channel *pChannel;
|
2024-01-12 00:04:36 +01:00
|
|
|
|
|
|
|
if (!pLoopSound->bPlaying) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
bMayStop = true;
|
|
|
|
|
|
|
|
if (pLoopSound->bCombine) {
|
|
|
|
for (i = 0; i < (MAX_OPENAL_CHANNELS_3D + MAX_OPENAL_CHANNELS_2D); i++) {
|
|
|
|
if (openal.loop_sounds[i].pSfx == pLoopSound->pSfx && openal.loop_sounds[i].bInUse) {
|
|
|
|
bMayStop = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bMayStop) {
|
|
|
|
if (s_show_sounds->integer > 0) {
|
2024-01-15 23:04:25 +01:00
|
|
|
Com_DPrintf(
|
|
|
|
"%d (#%i) - stopped loop - %s\n",
|
|
|
|
cl.serverTime,
|
|
|
|
pLoopSound->iChannel,
|
|
|
|
openal.channel[pLoopSound->iChannel]->pSfx->name
|
|
|
|
);
|
2024-01-12 00:04:36 +01:00
|
|
|
}
|
|
|
|
openal.channel[pLoopSound->iChannel]->force_free();
|
|
|
|
}
|
2024-01-15 23:04:25 +01:00
|
|
|
pLoopSound->pSfx = NULL;
|
2024-01-12 00:04:36 +01:00
|
|
|
pLoopSound->bPlaying = false;
|
|
|
|
|
|
|
|
if (pLoopSound->bCombine) {
|
|
|
|
for (i = 0; i < (MAX_OPENAL_CHANNELS_3D + MAX_OPENAL_CHANNELS_2D); i++) {
|
2024-01-15 23:04:25 +01:00
|
|
|
if (openal.loop_sounds[i].pSfx == pLoopSound->pSfx) {
|
2024-01-12 00:04:36 +01:00
|
|
|
openal.loop_sounds[i].bPlaying = false;
|
2024-01-15 23:04:25 +01:00
|
|
|
openal.loop_sounds[i].pSfx = NULL;
|
2024-01-12 00:04:36 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2024-01-07 19:47:58 +01:00
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
S_OPENAL_ClearLoopingSounds
|
|
|
|
==============
|
|
|
|
*/
|
2024-01-07 19:47:58 +01:00
|
|
|
void S_OPENAL_ClearLoopingSounds()
|
|
|
|
{
|
2024-01-12 00:04:36 +01:00
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < (MAX_OPENAL_CHANNELS_3D + MAX_OPENAL_CHANNELS_2D); i++) {
|
|
|
|
openal.loop_sounds[i].bInUse = false;
|
|
|
|
}
|
2024-01-07 19:47:58 +01:00
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
S_OPENAL_StopLoopingSounds
|
|
|
|
==============
|
|
|
|
*/
|
2024-01-07 19:47:58 +01:00
|
|
|
void S_OPENAL_StopLoopingSounds()
|
|
|
|
{
|
2024-01-12 00:04:36 +01:00
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < (MAX_OPENAL_CHANNELS_3D + MAX_OPENAL_CHANNELS_2D); i++) {
|
|
|
|
openal.loop_sounds[i].bInUse = false;
|
|
|
|
S_OPENAL_StopLoopingSound(&openal.loop_sounds[i]);
|
|
|
|
}
|
2024-01-07 19:47:58 +01:00
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
S_OPENAL_StopSound
|
|
|
|
==============
|
|
|
|
*/
|
2024-01-08 19:44:04 +01:00
|
|
|
void S_OPENAL_StopSound(int iEntNum, int iEntChannel)
|
2024-01-07 19:47:58 +01:00
|
|
|
{
|
2024-01-12 00:04:36 +01:00
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < MAX_OPENAL_POSITION_CHANNELS; i++) {
|
2024-01-15 23:04:25 +01:00
|
|
|
openal_channel *pChannel = openal.channel[i];
|
2024-01-12 00:04:36 +01:00
|
|
|
if (!pChannel->is_free() && pChannel->iEntNum == iEntNum && pChannel->iEntChannel == iEntChannel) {
|
|
|
|
pChannel->end_sample();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2024-01-07 19:47:58 +01:00
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
S_OPENAL_StopAllSounds
|
|
|
|
==============
|
|
|
|
*/
|
2024-01-07 19:47:58 +01:00
|
|
|
void S_OPENAL_StopAllSounds(qboolean bStopMusic)
|
|
|
|
{
|
2024-01-12 00:04:36 +01:00
|
|
|
int i;
|
|
|
|
|
|
|
|
if (!s_bSoundStarted) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < MAX_OPENAL_POSITION_CHANNELS; i++) {
|
2024-01-15 23:04:25 +01:00
|
|
|
openal_channel *pChannel = openal.channel[i];
|
2024-01-12 00:04:36 +01:00
|
|
|
if (pChannel) {
|
|
|
|
pChannel->force_free();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bStopMusic) {
|
|
|
|
MUSIC_FreeAllSongs();
|
|
|
|
S_TriggeredMusic_Stop();
|
|
|
|
}
|
2024-01-07 19:47:58 +01:00
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
S_OPENAL_Start2DLoopSound
|
|
|
|
==============
|
|
|
|
*/
|
2024-01-07 19:47:58 +01:00
|
|
|
static int S_OPENAL_Start2DLoopSound(
|
2024-01-07 23:36:32 +01:00
|
|
|
openal_loop_sound_t *pLoopSound, float fVolume, float fVolumeToPlay, float fMinDistance, const vec3_t vLoopOrigin
|
2024-01-07 19:47:58 +01:00
|
|
|
)
|
|
|
|
{
|
2024-01-15 23:04:25 +01:00
|
|
|
int iChannel;
|
|
|
|
int iSoundOFfset;
|
|
|
|
openal_channel *pChannel;
|
2024-01-12 00:04:36 +01:00
|
|
|
|
2024-07-01 18:05:24 +02:00
|
|
|
if (pLoopSound->pSfx->iFlags & SFX_FLAG_STREAMED) {
|
2024-01-12 00:04:36 +01:00
|
|
|
iChannel = S_OPENAL_PickChannel2DStreamed(0, 0);
|
2024-01-15 23:04:25 +01:00
|
|
|
} else {
|
2024-01-12 00:04:36 +01:00
|
|
|
iChannel = S_OPENAL_PickChannel2D(0, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (iChannel < 0) {
|
|
|
|
Com_DPrintf("Could not find a free 2D sound channel\n");
|
|
|
|
return iChannel;
|
|
|
|
}
|
|
|
|
|
|
|
|
pChannel = openal.channel[iChannel];
|
|
|
|
pChannel->force_free();
|
|
|
|
pChannel->fVolume = fVolume;
|
|
|
|
|
|
|
|
if (pLoopSound->iFlags & LOOPSOUND_FLAG_NO_PAN) {
|
|
|
|
pChannel->iFlags |= CHANNEL_FLAG_LOCAL_LISTENER;
|
|
|
|
} else {
|
|
|
|
pChannel->iFlags &= ~CHANNEL_FLAG_LOCAL_LISTENER;
|
|
|
|
}
|
|
|
|
pChannel->fMinDist = fMinDistance;
|
|
|
|
|
|
|
|
if (!pChannel->set_sfx(pLoopSound->pSfx)) {
|
|
|
|
Com_DPrintf("Set sample error\n");
|
2024-08-05 18:49:41 +02:00
|
|
|
pChannel->iFlags &= ~CHANNEL_FLAG_PLAY_DEFERRED;
|
2024-01-12 00:04:36 +01:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
pChannel->iEntNum = 0;
|
2024-01-12 00:04:36 +01:00
|
|
|
pChannel->iEntChannel = 0;
|
2024-01-15 23:04:25 +01:00
|
|
|
pChannel->pSfx = pLoopSound->pSfx;
|
2024-01-12 00:04:36 +01:00
|
|
|
pChannel->iFlags |= CHANNEL_FLAG_PAUSED | CHANNEL_FLAG_NO_ENTITY;
|
|
|
|
pChannel->iBaseRate = pChannel->sample_playback_rate();
|
|
|
|
VectorCopy(vLoopOrigin, pChannel->vOrigin);
|
2024-01-15 23:04:25 +01:00
|
|
|
pChannel->set_sample_offset(
|
|
|
|
(int)(pLoopSound->pSfx->info.width * pLoopSound->pSfx->info.rate
|
|
|
|
* (float)(cls.realtime - pLoopSound->iStartTime) / 1000.0)
|
|
|
|
% pLoopSound->pSfx->length
|
|
|
|
);
|
2024-01-12 00:04:36 +01:00
|
|
|
|
|
|
|
pChannel->set_sample_loop_count(0);
|
|
|
|
pChannel->fVolume = fVolumeToPlay;
|
|
|
|
pChannel->set_gain(fVolumeToPlay);
|
|
|
|
pChannel->start_sample();
|
|
|
|
if (s_show_sounds->integer > 0) {
|
|
|
|
Com_DPrintf("%d (#%i) - %s (vol %f)\n", cl.serverTime, pLoopSound->iChannel, pLoopSound->pSfx->name, fVolume);
|
|
|
|
}
|
|
|
|
|
|
|
|
return iChannel;
|
2024-01-07 19:47:58 +01:00
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
S_OPENAL_Start3DLoopSound
|
|
|
|
==============
|
|
|
|
*/
|
2024-01-07 19:47:58 +01:00
|
|
|
static int S_OPENAL_Start3DLoopSound(
|
|
|
|
openal_loop_sound_t *pLoopSound,
|
|
|
|
float fVolumeToPlay,
|
|
|
|
float fMinDistance,
|
|
|
|
float fMaxDistance,
|
2024-01-07 23:42:32 +01:00
|
|
|
const vec3_t vLoopOrigin,
|
|
|
|
const vec3_t vListenerOrigin
|
2024-01-07 19:47:58 +01:00
|
|
|
)
|
|
|
|
{
|
2024-01-15 23:04:25 +01:00
|
|
|
int iChannel;
|
|
|
|
vec3_t vDir;
|
|
|
|
int iSoundOffset;
|
|
|
|
openal_channel *pChan3D;
|
2024-01-12 00:04:36 +01:00
|
|
|
|
2024-08-06 18:43:15 +02:00
|
|
|
if (pLoopSound->pSfx->iFlags & SFX_FLAG_STREAMED) {
|
|
|
|
return -1;
|
|
|
|
}
|
2024-01-12 00:04:36 +01:00
|
|
|
|
|
|
|
iChannel = S_OPENAL_PickChannel3D(0, 0);
|
2024-01-15 23:04:25 +01:00
|
|
|
if (iChannel < 0) {
|
2024-01-12 00:04:36 +01:00
|
|
|
Com_DPrintf("Could not find a free channel\n");
|
|
|
|
return iChannel;
|
|
|
|
}
|
|
|
|
|
|
|
|
pChan3D = &openal.chan_3D[iChannel];
|
|
|
|
pChan3D->force_free();
|
2024-01-15 23:04:25 +01:00
|
|
|
pChan3D->iEntNum = 0;
|
2024-01-12 00:04:36 +01:00
|
|
|
pChan3D->iEntChannel = 0;
|
|
|
|
pChan3D->set_3d();
|
|
|
|
|
|
|
|
if (!pChan3D->set_sfx(pLoopSound->pSfx)) {
|
|
|
|
Com_DPrintf("Set sample error - %s\n", pLoopSound->pSfx->name);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2024-07-02 20:25:08 +02:00
|
|
|
pChan3D->set_position(vLoopOrigin[0], vLoopOrigin[1], vLoopOrigin[2]);
|
|
|
|
pChan3D->set_velocity(pLoopSound->vVelocity[0], pLoopSound->vVelocity[1], pLoopSound->vVelocity[2]);
|
2024-01-12 00:04:36 +01:00
|
|
|
pChan3D->pSfx = pLoopSound->pSfx;
|
|
|
|
pChan3D->iFlags |= CHANNEL_FLAG_PAUSED | CHANNEL_FLAG_NO_ENTITY;
|
|
|
|
pChan3D->iBaseRate = pChan3D->sample_playback_rate();
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
iSoundOffset = (int)((int)pLoopSound->pSfx->info.width * pLoopSound->pSfx->info.rate
|
|
|
|
* (float)(cls.realtime - pLoopSound->iStartTime) / 1000.0)
|
|
|
|
% pLoopSound->pSfx->length;
|
2024-01-12 00:04:36 +01:00
|
|
|
pChan3D->set_sample_offset(iSoundOffset);
|
|
|
|
pChan3D->set_sample_loop_count(0);
|
|
|
|
pChan3D->fVolume = fVolumeToPlay;
|
|
|
|
pChan3D->set_gain(fVolumeToPlay);
|
|
|
|
pChan3D->play();
|
|
|
|
|
|
|
|
S_OPENAL_reverb(iChannel, s_iReverbType, s_fReverbLevel);
|
|
|
|
|
|
|
|
return iChannel;
|
2024-01-07 19:47:58 +01:00
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
S_OPENAL_UpdateLoopSound
|
|
|
|
==============
|
|
|
|
*/
|
2024-01-07 19:47:58 +01:00
|
|
|
static bool S_OPENAL_UpdateLoopSound(
|
|
|
|
openal_loop_sound_t *pLoopSound,
|
|
|
|
float fVolumeToPlay,
|
|
|
|
float fMinDistance,
|
|
|
|
float fMaxDistance,
|
2024-01-07 23:42:32 +01:00
|
|
|
const vec3_t vListenerOrigin,
|
|
|
|
const vec3_t vTempAxis,
|
|
|
|
const vec3_t vLoopOrigin
|
2024-01-07 19:47:58 +01:00
|
|
|
)
|
|
|
|
{
|
2024-01-15 23:04:25 +01:00
|
|
|
openal_channel *pChannel;
|
|
|
|
float fVolume;
|
|
|
|
float fMaxVolume;
|
|
|
|
vec3_t vDir;
|
|
|
|
float fDistance;
|
2024-01-07 19:47:58 +01:00
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
pChannel = openal.channel[pLoopSound->iChannel];
|
|
|
|
if (!pChannel) {
|
|
|
|
return false;
|
|
|
|
}
|
2024-01-07 19:47:58 +01:00
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
if (pChannel->pSfx != pLoopSound->pSfx) {
|
|
|
|
pLoopSound->bPlaying = 0;
|
|
|
|
return false;
|
|
|
|
}
|
2024-01-07 19:47:58 +01:00
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
pChannel->iStartTime = cl.serverTime;
|
2024-01-07 19:47:58 +01:00
|
|
|
|
2024-08-06 18:43:15 +02:00
|
|
|
if (pLoopSound->pSfx->iFlags & (SFX_FLAG_NO_OFFSET) || pLoopSound->pSfx->iFlags & (SFX_FLAG_STREAMED | SFX_FLAG_MP3)
|
2024-01-15 23:04:25 +01:00
|
|
|
|| (pLoopSound->iFlags & LOOPSOUND_FLAG_NO_PAN)) {
|
|
|
|
vec3_t vOrigin;
|
|
|
|
int iPan;
|
2024-01-07 19:47:58 +01:00
|
|
|
|
2024-07-01 16:46:47 +02:00
|
|
|
pChannel->fVolume = fVolumeToPlay / s_fVolumeGain;
|
2024-01-15 23:04:25 +01:00
|
|
|
fVolume = S_GetBaseVolume() * pChannel->fVolume;
|
|
|
|
fMaxVolume = fVolume;
|
2024-01-07 19:47:58 +01:00
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
if (pLoopSound->iFlags & LOOPSOUND_FLAG_NO_PAN) {
|
|
|
|
// Center the sound
|
|
|
|
iPan = 64;
|
|
|
|
} else {
|
|
|
|
VectorCopy(vLoopOrigin, vOrigin);
|
|
|
|
iPan = S_OPENAL_SpatializeStereoSound(vListenerOrigin, vTempAxis, vOrigin);
|
|
|
|
|
|
|
|
VectorSubtract(vListenerOrigin, vOrigin, vDir);
|
|
|
|
// Clamp the volume by distance
|
|
|
|
fDistance = VectorLength(vDir);
|
|
|
|
if (pChannel->fMinDist >= fDistance) {
|
|
|
|
fVolume = fMaxVolume;
|
|
|
|
} else {
|
|
|
|
fVolume = pChannel->fMinDist / fDistance * fMaxVolume;
|
|
|
|
}
|
|
|
|
}
|
2024-01-07 19:47:58 +01:00
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
pChannel->set_gain(fVolume);
|
|
|
|
pChannel->set_sample_pan(iPan);
|
|
|
|
} else {
|
2024-01-17 20:44:32 +01:00
|
|
|
pChannel->set_position(vLoopOrigin[0], vLoopOrigin[1], vLoopOrigin[2]);
|
2024-01-15 23:04:25 +01:00
|
|
|
pChannel->fVolume = fVolumeToPlay;
|
|
|
|
pChannel->set_gain(fVolumeToPlay);
|
|
|
|
}
|
2024-01-07 19:47:58 +01:00
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
if (s_bReverbChanged) {
|
|
|
|
// Make sure to update the reverb
|
|
|
|
S_OPENAL_reverb(pLoopSound->iChannel, s_iReverbType, s_fReverbLevel);
|
|
|
|
}
|
2024-01-07 19:47:58 +01:00
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
return true;
|
2024-01-07 19:47:58 +01:00
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
S_OPENAL_AddLoopSounds
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
void S_OPENAL_AddLoopSounds(const vec3_t vTempAxis)
|
2024-01-07 19:47:58 +01:00
|
|
|
{
|
2024-01-15 23:04:25 +01:00
|
|
|
int i, j;
|
|
|
|
static int iLoopFrame = 0;
|
|
|
|
float fDistance;
|
|
|
|
int iChannel;
|
|
|
|
vec3_t vListenerOrigin;
|
|
|
|
vec3_t vLoopOrigin;
|
|
|
|
openal_loop_sound_t *pLoopSound;
|
|
|
|
float fTotalVolume;
|
|
|
|
float fVolumeToPlay;
|
|
|
|
float fMinDistance, fMaxDistance;
|
|
|
|
float fVolume;
|
|
|
|
float fPitch;
|
|
|
|
float fMaxVolume, fMaxFactor;
|
|
|
|
openal_channel *pChannel;
|
|
|
|
bool bAlreadyAdded[MAX_OPENAL_LOOP_SOUNDS] = {false};
|
|
|
|
vec3_t alvec;
|
2024-01-07 19:47:58 +01:00
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
qalGetListenerfv(AL_POSITION, alvec);
|
2024-07-02 20:25:08 +02:00
|
|
|
VectorCopy(alvec, vListenerOrigin);
|
2024-01-07 19:47:58 +01:00
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
for (i = 0; i < MAX_OPENAL_LOOP_SOUNDS; i++) {
|
|
|
|
vec3_t vDir;
|
2024-01-07 19:47:58 +01:00
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
if (bAlreadyAdded[i]) {
|
|
|
|
continue;
|
|
|
|
}
|
2024-01-07 19:47:58 +01:00
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
pLoopSound = &openal.loop_sounds[i];
|
|
|
|
if (!pLoopSound->pSfx) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
pChannel = openal.channel[pLoopSound->iChannel];
|
2024-01-07 19:47:58 +01:00
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
fMinDistance = pLoopSound->fMinDist;
|
|
|
|
if (fMinDistance < 0) {
|
|
|
|
fMinDistance = 200;
|
|
|
|
}
|
2024-01-07 19:47:58 +01:00
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
fMaxDistance = pLoopSound->fMaxDist;
|
|
|
|
if (fMaxDistance < 0) {
|
|
|
|
fMaxDistance = fMinDistance * 64;
|
|
|
|
}
|
2024-01-07 19:47:58 +01:00
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
fVolume = pLoopSound->fBaseVolume;
|
|
|
|
if (fVolume < 0) {
|
|
|
|
fVolume = 1;
|
|
|
|
}
|
|
|
|
fVolume = fVolume * s_fAmbientVolume;
|
2024-01-07 19:47:58 +01:00
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
fTotalVolume = 0.0;
|
|
|
|
fMaxVolume = 0.0;
|
2024-01-07 19:47:58 +01:00
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
if (pLoopSound->bPlaying) {
|
|
|
|
pChannel->fNewPitchMult = pLoopSound->fPitch;
|
|
|
|
}
|
2024-01-07 19:47:58 +01:00
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
if (pLoopSound->bCombine) {
|
|
|
|
for (j = 0; j < MAX_LOOP_SOUNDS; j++) {
|
|
|
|
openal_loop_sound_t *pLoopSound2 = &openal.loop_sounds[j];
|
|
|
|
|
|
|
|
if (pLoopSound2->pSfx == pLoopSound->pSfx) {
|
|
|
|
VectorSubtract(pLoopSound2->vOrigin, vListenerOrigin, vDir);
|
|
|
|
VectorCopy(vDir, pLoopSound2->vRelativeOrigin);
|
|
|
|
fDistance = VectorLength(pLoopSound2->vRelativeOrigin);
|
|
|
|
|
|
|
|
if (fDistance <= fMinDistance) {
|
|
|
|
fVolumeToPlay = fVolume;
|
|
|
|
} else if (fDistance >= fMaxDistance) {
|
|
|
|
fVolumeToPlay = 0;
|
|
|
|
} else {
|
|
|
|
fVolumeToPlay = fMinDistance * fMinDistance * fVolume / (fDistance * fDistance);
|
|
|
|
}
|
2024-01-07 19:47:58 +01:00
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
if (fMaxVolume < fVolumeToPlay) {
|
|
|
|
fMaxVolume = fVolumeToPlay;
|
|
|
|
}
|
|
|
|
fTotalVolume += fVolumeToPlay;
|
|
|
|
bAlreadyAdded[j] = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
VectorSubtract(pLoopSound->vOrigin, vListenerOrigin, vDir);
|
|
|
|
VectorCopy(vDir, pLoopSound->vRelativeOrigin);
|
|
|
|
fDistance = VectorLength(pLoopSound->vRelativeOrigin);
|
|
|
|
|
|
|
|
if (fDistance <= fMinDistance) {
|
|
|
|
fTotalVolume = fVolume;
|
|
|
|
} else if (fDistance >= fMaxDistance) {
|
|
|
|
fTotalVolume = 0;
|
|
|
|
} else {
|
|
|
|
fTotalVolume = fMinDistance * fMinDistance * fVolume / (fDistance * fDistance);
|
|
|
|
}
|
|
|
|
pLoopSound->fVolume = fTotalVolume;
|
|
|
|
fMaxVolume = fTotalVolume;
|
|
|
|
}
|
2024-01-07 19:47:58 +01:00
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
fMaxFactor = sfx_infos[pLoopSound->pSfx->sfx_info_index].max_factor;
|
|
|
|
if (fMaxFactor >= 1 && fMaxVolume * fMaxFactor < fTotalVolume) {
|
|
|
|
fTotalVolume = fMaxVolume * fMaxFactor;
|
|
|
|
}
|
2024-01-07 19:47:58 +01:00
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
if (fTotalVolume <= 0 && !(pLoopSound->iFlags & LOOPSOUND_FLAG_NO_PAN)) {
|
|
|
|
if (pLoopSound->bPlaying) {
|
|
|
|
if (s_show_sounds->integer > 0) {
|
|
|
|
Com_DPrintf(
|
|
|
|
"%d (#%i) - stopped loop - %s\n",
|
|
|
|
cl.serverTime,
|
|
|
|
pLoopSound->iChannel,
|
|
|
|
openal.channel[pLoopSound->iChannel]->pSfx->name
|
|
|
|
);
|
|
|
|
}
|
2024-01-07 19:47:58 +01:00
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
pChannel->stop();
|
|
|
|
pLoopSound->bPlaying = false;
|
|
|
|
if (pLoopSound->bCombine) {
|
|
|
|
for (j = 0; j < MAX_LOOP_SOUNDS; j++) {
|
|
|
|
openal_loop_sound_t *pLoopSound2 = &openal.loop_sounds[j];
|
2024-01-07 19:47:58 +01:00
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
if (pLoopSound2->pSfx == pLoopSound->pSfx) {
|
|
|
|
pLoopSound2->bPlaying = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2024-01-07 19:47:58 +01:00
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
continue;
|
|
|
|
}
|
2024-01-07 19:47:58 +01:00
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
VectorClear(vLoopOrigin);
|
2024-01-07 19:47:58 +01:00
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
if (pLoopSound->bCombine) {
|
|
|
|
for (j = 0; j < MAX_LOOP_SOUNDS; j++) {
|
|
|
|
openal_loop_sound_t *pLoopSound2 = &openal.loop_sounds[j];
|
2024-01-07 19:47:58 +01:00
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
if (pLoopSound2->pSfx == pLoopSound->pSfx) {
|
|
|
|
VectorNormalize(pLoopSound2->vRelativeOrigin);
|
2024-01-07 19:47:58 +01:00
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
VectorScale(
|
|
|
|
pLoopSound2->vRelativeOrigin, pLoopSound2->fVolume / fTotalVolume, pLoopSound2->vRelativeOrigin
|
|
|
|
);
|
|
|
|
VectorAdd(pLoopSound2->vRelativeOrigin, vLoopOrigin, vLoopOrigin);
|
|
|
|
}
|
|
|
|
}
|
2024-01-07 19:47:58 +01:00
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
VectorNormalize(vLoopOrigin);
|
|
|
|
VectorMA(vListenerOrigin, fMinDistance * 0.5f, vLoopOrigin, vLoopOrigin);
|
|
|
|
} else {
|
|
|
|
VectorCopy(pLoopSound->vOrigin, vLoopOrigin);
|
|
|
|
}
|
2024-01-07 19:47:58 +01:00
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
if (pLoopSound->bPlaying) {
|
|
|
|
S_OPENAL_UpdateLoopSound(
|
|
|
|
pLoopSound,
|
2024-07-01 16:46:47 +02:00
|
|
|
S_GetBaseVolume() * s_fVolumeGain * fTotalVolume,
|
2024-01-15 23:04:25 +01:00
|
|
|
fMinDistance,
|
|
|
|
fMaxDistance,
|
|
|
|
vListenerOrigin,
|
|
|
|
vTempAxis,
|
|
|
|
vLoopOrigin
|
|
|
|
);
|
|
|
|
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (s_show_sounds->integer > 0) {
|
|
|
|
Com_DPrintf("%d (#%i) - started loop - %s\n", cl.serverTime, pLoopSound->iChannel, pLoopSound->pSfx->name);
|
|
|
|
}
|
|
|
|
|
2024-08-06 18:43:15 +02:00
|
|
|
if (pLoopSound->pSfx->iFlags & (SFX_FLAG_NO_OFFSET) || pLoopSound->pSfx->iFlags & (SFX_FLAG_STREAMED | SFX_FLAG_MP3)
|
2024-01-15 23:04:25 +01:00
|
|
|
|| (pLoopSound->iFlags & LOOPSOUND_FLAG_NO_PAN)) {
|
|
|
|
iChannel = S_OPENAL_Start2DLoopSound(
|
2024-07-01 16:46:47 +02:00
|
|
|
pLoopSound, fVolume, S_GetBaseVolume() * s_fVolumeGain * fTotalVolume, fMinDistance, vLoopOrigin
|
2024-01-15 23:04:25 +01:00
|
|
|
);
|
|
|
|
} else {
|
|
|
|
iChannel = S_OPENAL_Start3DLoopSound(
|
|
|
|
pLoopSound,
|
2024-07-01 16:46:47 +02:00
|
|
|
S_GetBaseVolume() * s_fVolumeGain * fTotalVolume,
|
2024-01-15 23:04:25 +01:00
|
|
|
fMinDistance,
|
|
|
|
fMaxDistance,
|
|
|
|
vLoopOrigin,
|
|
|
|
vListenerOrigin
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (iChannel < 0) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2024-07-01 18:17:04 +02:00
|
|
|
pLoopSound->bPlaying = true;
|
2024-01-15 23:04:25 +01:00
|
|
|
pLoopSound->iChannel = iChannel;
|
|
|
|
|
|
|
|
if (pLoopSound->bCombine) {
|
|
|
|
for (j = 0; j < MAX_LOOP_SOUNDS; j++) {
|
|
|
|
openal_loop_sound_t *pLoopSound2 = &openal.loop_sounds[j];
|
|
|
|
|
|
|
|
if (pLoopSound2->pSfx == pLoopSound->pSfx) {
|
|
|
|
pLoopSound2->bPlaying = true;
|
|
|
|
pLoopSound2->iChannel = iChannel;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
S_OPENAL_Respatialize
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
void S_OPENAL_Respatialize(int iEntNum, const vec3_t vHeadPos, const vec3_t vAxis[3])
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
vec3_t vOrigin;
|
|
|
|
vec3_t vVelocity;
|
|
|
|
vec3_t vEntOrigin;
|
|
|
|
vec3_t vEntVelocity;
|
|
|
|
vec3_t vDir;
|
|
|
|
vec3_t vUp;
|
|
|
|
vec3_t vListenerOrigin;
|
|
|
|
int iPan;
|
|
|
|
vec3_t vTempAxis;
|
|
|
|
float fMaxVolume;
|
|
|
|
float fVolume;
|
|
|
|
float fDist;
|
|
|
|
openal_channel *pChannel;
|
|
|
|
vec3_t alvec {0};
|
|
|
|
vec3_t alorientation[2];
|
|
|
|
|
|
|
|
if (cls.no_menus) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
s_iListenerNumber = iEntNum;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Velocity
|
|
|
|
//
|
|
|
|
qalListenerfv(AL_VELOCITY, alvec);
|
|
|
|
alDieIfError();
|
|
|
|
|
|
|
|
//
|
|
|
|
// Position
|
|
|
|
//
|
2024-01-17 20:44:32 +01:00
|
|
|
VectorCopy(vHeadPos, alvec);
|
2024-01-15 23:04:25 +01:00
|
|
|
VectorCopy(alvec, vListenerOrigin);
|
|
|
|
qalListenerfv(AL_POSITION, alvec);
|
|
|
|
alDieIfError();
|
|
|
|
|
|
|
|
//
|
|
|
|
// Orientation
|
|
|
|
//
|
2024-01-17 20:44:32 +01:00
|
|
|
alorientation[0][0] = vAxis[0][0];
|
|
|
|
alorientation[0][1] = vAxis[0][1];
|
|
|
|
alorientation[0][2] = vAxis[0][2];
|
|
|
|
alorientation[1][0] = vAxis[2][0];
|
|
|
|
alorientation[1][1] = vAxis[2][1];
|
|
|
|
alorientation[1][2] = vAxis[2][2];
|
2024-01-15 23:04:25 +01:00
|
|
|
qalListenerfv(AL_ORIENTATION, (const ALfloat *)alorientation);
|
|
|
|
alDieIfError();
|
|
|
|
|
2024-08-06 18:43:15 +02:00
|
|
|
VectorCopy(vAxis[1], vTempAxis);
|
2024-01-15 23:04:25 +01:00
|
|
|
|
|
|
|
fVolume = 1;
|
|
|
|
iPan = 64;
|
|
|
|
|
|
|
|
for (i = 0; i < MAX_OPENAL_POSITION_CHANNELS; i++) {
|
|
|
|
pChannel = openal.channel[i];
|
|
|
|
fMaxVolume = S_GetBaseVolume() * pChannel->fVolume;
|
|
|
|
|
|
|
|
if (!pChannel) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!pChannel->is_playing()) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pChannel->iFlags & CHANNEL_FLAG_PAUSED) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pChannel->iFlags & CHANNEL_FLAG_NO_ENTITY) {
|
|
|
|
VectorCopy(pChannel->vOrigin, vOrigin);
|
|
|
|
|
|
|
|
if (pChannel->iFlags & CHANNEL_FLAG_LOCAL_LISTENER) {
|
|
|
|
VectorCopy(vListenerOrigin, vOrigin);
|
|
|
|
if (i >= MAX_OPENAL_CHANNELS_3D) {
|
|
|
|
fVolume = fMaxVolume;
|
|
|
|
iPan = 64;
|
|
|
|
} else {
|
2024-01-17 20:44:32 +01:00
|
|
|
pChannel->set_position(vOrigin[0], vOrigin[1], vOrigin[2]);
|
2024-01-15 23:04:25 +01:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (i >= MAX_OPENAL_CHANNELS_3D) {
|
|
|
|
iPan = S_OPENAL_SpatializeStereoSound(vListenerOrigin, vTempAxis, vOrigin);
|
|
|
|
VectorSubtract(vListenerOrigin, vOrigin, vDir);
|
|
|
|
|
|
|
|
fDist = VectorLength(vDir);
|
|
|
|
if (fDist <= pChannel->fMinDist + 0.001f) {
|
|
|
|
fVolume = fMaxVolume;
|
|
|
|
} else if (fDist >= pChannel->fMaxDist - 0.001f) {
|
|
|
|
fVolume = 0;
|
|
|
|
} else {
|
|
|
|
fVolume = (1.0 - (fDist - pChannel->fMinDist) / (pChannel->fMaxDist - pChannel->fMinDist))
|
|
|
|
* fMaxVolume;
|
|
|
|
}
|
|
|
|
} else {
|
2024-01-17 20:44:32 +01:00
|
|
|
pChannel->set_position(vOrigin[0], vOrigin[1], vOrigin[2]);
|
2024-01-15 23:04:25 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (pChannel->iFlags & CHANNEL_FLAG_LOCAL_LISTENER) {
|
|
|
|
VectorCopy(vListenerOrigin, vOrigin);
|
|
|
|
if (i >= MAX_OPENAL_CHANNELS_3D) {
|
|
|
|
fVolume = fMaxVolume;
|
|
|
|
iPan = 64;
|
|
|
|
} else {
|
2024-01-17 20:44:32 +01:00
|
|
|
pChannel->set_position(vOrigin[0], vOrigin[1], vOrigin[2]);
|
2024-01-15 23:04:25 +01:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (s_entity[pChannel->iEntNum].time < pChannel->iTime) {
|
|
|
|
VectorCopy(pChannel->vOrigin, vOrigin);
|
|
|
|
if (!(pChannel->iFlags & CHANNEL_FLAG_LOOPING)) {
|
|
|
|
pChannel->end_sample();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
VectorCopy(s_entity[pChannel->iEntNum].position, vEntOrigin);
|
2024-01-17 20:44:32 +01:00
|
|
|
VectorCopy(vEntOrigin, vOrigin);
|
2024-01-15 23:04:25 +01:00
|
|
|
VectorCopy(vOrigin, pChannel->vOrigin);
|
|
|
|
pChannel->iTime = s_entity[pChannel->iEntNum].time;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (s_entity[pChannel->iEntNum].use_listener) {
|
|
|
|
VectorCopy(vListenerOrigin, vOrigin);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pChannel->iEntNum == s_iListenerNumber) {
|
|
|
|
if (vListenerOrigin[0] == vOrigin[0] && vListenerOrigin[2] == vOrigin[2]) {
|
|
|
|
float fDelta = vListenerOrigin[1] - vOrigin[1];
|
|
|
|
|
|
|
|
if (fDelta > 89.9f && fDelta < 90.09f) {
|
|
|
|
VectorCopy(vListenerOrigin, vOrigin);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (i >= MAX_OPENAL_CHANNELS_3D) {
|
|
|
|
iPan = S_OPENAL_SpatializeStereoSound(vListenerOrigin, vTempAxis, vOrigin);
|
|
|
|
VectorSubtract(vListenerOrigin, vOrigin, vDir);
|
|
|
|
fDist = VectorLength(vDir);
|
|
|
|
if (fDist <= pChannel->fMinDist + 0.001f) {
|
|
|
|
fVolume = fMaxVolume;
|
|
|
|
} else if (fDist >= pChannel->fMaxDist - 0.001f) {
|
|
|
|
fVolume = 0;
|
|
|
|
} else {
|
|
|
|
fVolume =
|
|
|
|
(1.0 - (fDist - pChannel->fMinDist) / (pChannel->fMaxDist - pChannel->fMinDist)) * fMaxVolume;
|
|
|
|
}
|
|
|
|
} else {
|
2024-01-17 20:44:32 +01:00
|
|
|
pChannel->set_position(vOrigin[0], vOrigin[1], vOrigin[2]);
|
2024-01-15 23:04:25 +01:00
|
|
|
VectorCopy(s_entity[pChannel->iEntNum].velocity, vEntVelocity);
|
2024-01-17 20:44:32 +01:00
|
|
|
VectorCopy(vEntVelocity, vVelocity);
|
|
|
|
pChannel->set_velocity(vVelocity[0], vVelocity[1], vVelocity[2]);
|
2024-01-15 23:04:25 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (i >= MAX_OPENAL_CHANNELS_3D) {
|
|
|
|
pChannel->set_gain(fVolume);
|
|
|
|
pChannel->set_sample_pan(iPan);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (s_bReverbChanged) {
|
|
|
|
S_OPENAL_reverb(i, s_iReverbType, s_fReverbLevel);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
S_OPENAL_AddLoopSounds(vTempAxis);
|
|
|
|
s_bReverbChanged = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
S_OPENAL_SpatializeStereoSound
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
static int S_OPENAL_SpatializeStereoSound(const vec3_t listener_origin, const vec3_t listener_left, const vec3_t origin)
|
|
|
|
{
|
|
|
|
float lscale, rscale;
|
|
|
|
vec3_t source_vec;
|
2024-07-01 19:03:21 +02:00
|
|
|
float pan;
|
2024-01-15 23:04:25 +01:00
|
|
|
|
|
|
|
VectorSubtract(origin, listener_origin, source_vec);
|
|
|
|
VectorNormalize(source_vec);
|
|
|
|
|
|
|
|
pan = s_separation->value + (1.f - s_separation->value) * -DotProduct(listener_left, source_vec);
|
|
|
|
|
|
|
|
if (pan < 0) {
|
|
|
|
pan = 0;
|
|
|
|
}
|
|
|
|
|
2024-08-06 18:43:15 +02:00
|
|
|
return ceilf(pan * 127);
|
2024-01-15 23:04:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
S_OPENAL_reverb
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
static void S_OPENAL_reverb(int iChannel, int iReverbType, float fReverbLevel)
|
|
|
|
{
|
|
|
|
// No reverb.
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
S_OPENAL_SetReverb
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
void S_OPENAL_SetReverb(int iType, float fLevel)
|
|
|
|
{
|
|
|
|
s_fReverbLevel = fLevel;
|
|
|
|
s_iReverbType = iType;
|
|
|
|
if (al_use_reverb) {
|
|
|
|
s_bReverbChanged = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
S_OPENAL_Update
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
void S_OPENAL_Update()
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
openal_channel *pChannel;
|
|
|
|
|
|
|
|
if (cl.snap.ps.stats[STAT_CINEMATIC]) {
|
|
|
|
S_SetGlobalAmbientVolumeLevel(0.5f);
|
|
|
|
} else {
|
|
|
|
S_SetGlobalAmbientVolumeLevel(1.f);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (paused->integer && !s_bSoundPaused) {
|
|
|
|
S_PauseSound();
|
|
|
|
} else if (!paused->integer && s_bSoundPaused) {
|
|
|
|
S_UnpauseSound();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (s_bFading) {
|
|
|
|
s_fFadeVolume = 1.f - (cls.realtime - s_fFadeStartTime) / (s_fFadeStopTime - s_fFadeStartTime);
|
|
|
|
if (s_fFadeVolume < 0) {
|
|
|
|
s_fFadeVolume = 0;
|
|
|
|
}
|
|
|
|
music_volume_changed = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (s_volume->modified) {
|
|
|
|
if (s_volume->value > 1) {
|
|
|
|
Cvar_Set("s_volume", "1.0");
|
|
|
|
} else if (s_volume->value < 0) {
|
|
|
|
Cvar_Set("s_volume", "0.0");
|
|
|
|
}
|
|
|
|
|
|
|
|
music_volume_changed = true;
|
|
|
|
s_volume->modified = 0;
|
2024-08-06 18:43:15 +02:00
|
|
|
al_current_volume = Square(s_volume->value);
|
2024-01-15 23:04:25 +01:00
|
|
|
qalListenerf(AL_GAIN, al_current_volume);
|
|
|
|
alDieIfError();
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < MAX_OPENAL_POSITION_CHANNELS; i++) {
|
|
|
|
pChannel = openal.channel[i];
|
|
|
|
if (!pChannel) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!pChannel->is_playing()) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pChannel->fNewPitchMult <= 0) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
pChannel->set_sample_playback_rate(pChannel->iBaseRate * pChannel->fNewPitchMult);
|
|
|
|
pChannel->fNewPitchMult = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (s_speaker_type->modified) {
|
|
|
|
if (s_speaker_type->integer) {
|
|
|
|
Com_Printf("FIXME: Allow different speaker types in OpenAL code.\n");
|
|
|
|
Cvar_Set("s_speaker_type", "0");
|
|
|
|
}
|
|
|
|
s_speaker_type->modified = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (s_reverb->modified) {
|
|
|
|
s_reverb->modified = false;
|
|
|
|
Com_Printf("FIXME: Allow reverb toggle at runtime in OpenAL code.\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (s_show_num_active_sounds->integer == 1) {
|
|
|
|
int num = 0;
|
|
|
|
|
|
|
|
for (i = 0; i < MAX_OPENAL_POSITION_CHANNELS; i++) {
|
|
|
|
pChannel = openal.channel[i];
|
|
|
|
if (pChannel && pChannel->is_playing()) {
|
|
|
|
++num;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Com_DPrintf("Number of active sounds = %d\n", num);
|
|
|
|
}
|
|
|
|
|
|
|
|
Music_Update();
|
|
|
|
|
|
|
|
for (i = 0; i < MAX_LOOP_SOUNDS; i++) {
|
|
|
|
if (!openal.loop_sounds[i].bInUse) {
|
|
|
|
S_OPENAL_StopLoopingSound(&openal.loop_sounds[i]);
|
|
|
|
}
|
|
|
|
}
|
2024-08-12 20:25:04 +02:00
|
|
|
|
|
|
|
for (i = 0; i < MAX_OPENAL_CHANNELS; i++) {
|
|
|
|
openal.channel[i]->update();
|
|
|
|
}
|
2024-01-15 23:04:25 +01:00
|
|
|
}
|
|
|
|
|
2024-07-22 20:07:32 +02:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
S_OPENAL_GetMusicFilename
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
const char* S_OPENAL_GetMusicFilename()
|
|
|
|
{
|
|
|
|
return openal.tm_filename;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
S_OPENAL_GetMusicLoopCount
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
int S_OPENAL_GetMusicLoopCount()
|
|
|
|
{
|
|
|
|
return openal.tm_loopcount;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
S_OPENAL_GetMusicOffset
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
unsigned int S_OPENAL_GetMusicOffset()
|
|
|
|
{
|
|
|
|
return openal.chan_trig_music.sample_offset();
|
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
S_IsSoundPlaying
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
qboolean S_IsSoundPlaying(int channel_number, const char *sfxName)
|
|
|
|
{
|
|
|
|
openal_channel *pChannel = openal.channel[channel_number];
|
|
|
|
if (!pChannel) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (s_bSoundPaused) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!pChannel->is_playing()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!pChannel->pSfx || pChannel->pSfx == (sfx_t *)-16) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return !strcmp(sfxName, pChannel->pSfx->name);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
S_StoreBase
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
static void S_StoreBase(channelbasesavegame_t *pBase, openal_channel *pChannel)
|
|
|
|
{
|
|
|
|
if (!pChannel) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pChannel->iEntChannel == CHAN_MENU || pChannel->is_free()) {
|
|
|
|
pBase->bPlaying = false;
|
|
|
|
pBase->iOffset = 0;
|
|
|
|
pBase->iLoopCount = 0;
|
|
|
|
pBase->sfx.szName[0] = 0;
|
|
|
|
pBase->sfx.iFlags = 0;
|
|
|
|
pBase->fNewPitchMult = 1.f;
|
|
|
|
pBase->iBaseRate = pChannel->iBaseRate;
|
|
|
|
pBase->iStatus = 0;
|
|
|
|
} else {
|
|
|
|
pBase->bPlaying = true;
|
|
|
|
pBase->iOffset = pChannel->sample_offset();
|
|
|
|
pBase->iLoopCount = pChannel->sample_loop_count();
|
|
|
|
memcpy(pBase->sfx.szName, pChannel->pSfx->name, sizeof(pBase->sfx.szName));
|
|
|
|
pBase->sfx.iFlags = pChannel->pSfx->iFlags;
|
|
|
|
pBase->iBaseRate = pChannel->iBaseRate;
|
|
|
|
pBase->iStatus = 0;
|
|
|
|
pBase->fNewPitchMult = (float)pBase->iBaseRate / (float)pChannel->sample_playback_rate();
|
|
|
|
}
|
|
|
|
|
|
|
|
pBase->iStartTime = pChannel->iStartTime - cl.serverTime;
|
|
|
|
pBase->iEndTime = pChannel->iEndTime - cl.serverTime;
|
|
|
|
pBase->iEntChannel = pChannel->iEntChannel;
|
|
|
|
pBase->iEntNum = pChannel->iEntNum;
|
|
|
|
pBase->iFlags = pChannel->iFlags;
|
|
|
|
pBase->fMaxDist = pChannel->fMaxDist;
|
|
|
|
pBase->fMinDist = pChannel->fMinDist;
|
|
|
|
pBase->iNextCheckObstructionTime = 0;
|
|
|
|
VectorCopy(pChannel->vOrigin, pBase->vOrigin);
|
|
|
|
pBase->iTime = pChannel->iTime - cl.serverTime;
|
|
|
|
pBase->fVolume = pChannel->fVolume;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
S_StartSoundFromBase
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
S_StartSoundFromBase(channelbasesavegame_t *pBase, openal_channel *pChannel, sfx_t *pSfx, bool bStartUnpaused)
|
|
|
|
{
|
|
|
|
if (!pChannel->set_sfx(pSfx)) {
|
|
|
|
Com_DPrintf("Set sample error - %s\n", pSfx->name);
|
2024-08-05 18:49:41 +02:00
|
|
|
pChannel->iFlags &= ~CHANNEL_FLAG_PLAY_DEFERRED;
|
2024-01-15 23:04:25 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
pChannel->iBaseRate = pChannel->sample_playback_rate();
|
|
|
|
|
|
|
|
if (sfx_infos[pSfx->sfx_info_index].loop_start != -1) {
|
|
|
|
pChannel->set_sample_loop_block(
|
|
|
|
sfx_infos[pSfx->sfx_info_index].loop_start, sfx_infos[pSfx->sfx_info_index].loop_end
|
|
|
|
);
|
|
|
|
pChannel->set_sample_loop_count(1);
|
|
|
|
pChannel->iFlags |= CHANNEL_FLAG_LOOPING;
|
|
|
|
if (s_show_sounds->integer > 0) {
|
|
|
|
Com_DPrintf(
|
|
|
|
"loopblock - %d to %d\n",
|
|
|
|
sfx_infos[pSfx->sfx_info_index].loop_start,
|
|
|
|
sfx_infos[pSfx->sfx_info_index].loop_end
|
|
|
|
);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
pChannel->set_sample_loop_count(1);
|
|
|
|
}
|
|
|
|
|
2024-07-22 20:44:00 +02:00
|
|
|
pChannel->set_gain(pChannel->fVolume);
|
|
|
|
pChannel->set_sample_offset(pBase->iOffset);
|
|
|
|
pChannel->set_sample_playback_rate(pChannel->iBaseRate * pBase->fNewPitchMult);
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
if (bStartUnpaused) {
|
|
|
|
pChannel->resume_sample();
|
|
|
|
} else {
|
2024-08-05 18:49:41 +02:00
|
|
|
pChannel->iFlags |= CHANNEL_FLAG_PLAY_DEFERRED;
|
2024-01-15 23:04:25 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
S_LoadBase
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
static void S_LoadBase(channelbasesavegame_t *pBase, openal_channel *pChannel, bool bStartUnpaused)
|
|
|
|
{
|
|
|
|
sfxHandle_t handle;
|
|
|
|
|
|
|
|
if (!pChannel) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!pBase->bPlaying) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (strstr(pBase->sfx.szName, "null.wav")) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
handle = S_RegisterSound(pBase->sfx.szName, (pBase->sfx.iFlags & SFX_FLAG_DEFAULT_SOUND), false);
|
|
|
|
|
|
|
|
pChannel->iBaseRate = pBase->iBaseRate;
|
|
|
|
pChannel->iStartTime = pBase->iStartTime;
|
|
|
|
pChannel->iEndTime = pBase->iEndTime;
|
|
|
|
pChannel->iEntChannel = pBase->iEntChannel;
|
|
|
|
pChannel->iEntNum = pBase->iEntNum;
|
|
|
|
pChannel->iFlags = pBase->iFlags;
|
|
|
|
pChannel->fMaxDist = pBase->fMaxDist;
|
|
|
|
pChannel->fMinDist = pBase->fMinDist;
|
|
|
|
pChannel->fNewPitchMult = pBase->fNewPitchMult;
|
|
|
|
VectorCopy(pBase->vOrigin, pChannel->vOrigin);
|
|
|
|
pChannel->iTime = pBase->iTime;
|
|
|
|
pChannel->fVolume = pBase->fVolume;
|
|
|
|
pChannel->pSfx = &s_knownSfx[handle];
|
|
|
|
|
|
|
|
S_StartSoundFromBase(pBase, pChannel, &s_knownSfx[handle], bStartUnpaused);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
S_SaveData
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
void S_SaveData(soundsystemsavegame_t *pSave)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
bool bSoundWasUnpaused;
|
|
|
|
|
|
|
|
bSoundWasUnpaused = !s_bSoundPaused;
|
|
|
|
if (!s_bSoundPaused) {
|
|
|
|
S_PauseSound();
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < MAX_OPENAL_POSITION_CHANNELS; i++) {
|
|
|
|
S_StoreBase(&pSave->Channels[i], openal.channel[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bSoundWasUnpaused) {
|
|
|
|
S_UnpauseSound();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
S_ReLoad
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
void S_ReLoad(soundsystemsavegame_t *pSave)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
bool bSoundWasUnpaused;
|
|
|
|
|
|
|
|
bSoundWasUnpaused = !s_bSoundPaused;
|
|
|
|
if (!s_bSoundPaused) {
|
|
|
|
S_PauseSound();
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < MAX_OPENAL_POSITION_CHANNELS; i++) {
|
|
|
|
S_LoadBase(&pSave->Channels[i], openal.channel[i], bSoundWasUnpaused);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bSoundWasUnpaused) {
|
|
|
|
S_UnpauseSound();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
S_InitBase
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
static void S_InitBase(channelbasesavegame_t *pBase)
|
|
|
|
{
|
|
|
|
if (!pBase->bPlaying) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (strstr(pBase->sfx.szName, "null.wav")) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
SV_AddSvsTimeFixup(&pBase->iStartTime);
|
|
|
|
SV_AddSvsTimeFixup(&pBase->iEndTime);
|
|
|
|
SV_AddSvsTimeFixup(&pBase->iTime);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
S_LoadData
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
void S_LoadData(soundsystemsavegame_t *pSave)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < MAX_OPENAL_POSITION_CHANNELS; i++) {
|
|
|
|
S_InitBase(&pSave->Channels[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
openal_channel::set_velocity
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
void openal_channel::set_velocity(float v0, float v1, float v2)
|
|
|
|
{
|
|
|
|
qalSource3f(source, AL_VELOCITY, v0, v1, v2);
|
|
|
|
alDieIfError();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
openal_channel::set_position
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
void openal_channel::set_position(float v0, float v1, float v2)
|
|
|
|
{
|
|
|
|
qalSource3f(source, AL_POSITION, v0, v1, v2);
|
|
|
|
alDieIfError();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
openal_channel::set_gain
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
void openal_channel::set_gain(float gain)
|
|
|
|
{
|
|
|
|
qalSourcef(source, AL_GAIN, gain);
|
|
|
|
alDieIfError();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
openal_channel::set_no_3d
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
void openal_channel::set_no_3d()
|
|
|
|
{
|
|
|
|
qalSource3f(source, AL_POSITION, 0, 0, 0);
|
|
|
|
alDieIfError();
|
|
|
|
qalSource3f(source, AL_VELOCITY, 0, 0, 0);
|
|
|
|
alDieIfError();
|
|
|
|
qalSourcei(source, AL_SOURCE_RELATIVE, true);
|
|
|
|
alDieIfError();
|
|
|
|
qalSourcei(source, AL_LOOPING, false);
|
|
|
|
alDieIfError();
|
|
|
|
qalSourcei(source, AL_ROLLOFF_FACTOR, 0);
|
|
|
|
alDieIfError();
|
|
|
|
qalSourcef(source, AL_GAIN, S_GetBaseVolume());
|
|
|
|
alDieIfError();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
openal_channel::set_3d
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
void openal_channel::set_3d()
|
|
|
|
{
|
2024-01-17 20:44:32 +01:00
|
|
|
qalSourcei(source, AL_SOURCE_RELATIVE, false);
|
2024-01-15 23:04:25 +01:00
|
|
|
alDieIfError();
|
|
|
|
qalSourcei(source, AL_LOOPING, false);
|
|
|
|
alDieIfError();
|
2024-07-01 18:52:04 +02:00
|
|
|
qalSourcef(source, AL_ROLLOFF_FACTOR, 0.5f);
|
2024-01-15 23:04:25 +01:00
|
|
|
alDieIfError();
|
|
|
|
qalSourcef(source, AL_GAIN, S_GetBaseVolume());
|
|
|
|
alDieIfError();
|
2024-07-02 19:30:29 +02:00
|
|
|
qalSourcef(source, AL_DISTANCE_MODEL, AL_LINEAR_DISTANCE);
|
|
|
|
alDieIfError();
|
2024-07-01 18:52:04 +02:00
|
|
|
//
|
|
|
|
// Added in OPM
|
|
|
|
//
|
2024-07-01 19:39:51 +02:00
|
|
|
if (fMinDist > 0) {
|
|
|
|
qalSourcef(source, AL_REFERENCE_DISTANCE, fMinDist);
|
|
|
|
alDieIfError();
|
|
|
|
}
|
|
|
|
if (fMaxDist > 0) {
|
|
|
|
qalSourcef(source, AL_MAX_DISTANCE, fMaxDist);
|
|
|
|
alDieIfError();
|
|
|
|
}
|
2024-01-15 23:04:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
openal_channel::play
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
void openal_channel::play()
|
|
|
|
{
|
|
|
|
qalSourcePlay(source);
|
|
|
|
alDieIfError();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
openal_channel::pause
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
void openal_channel::pause()
|
|
|
|
{
|
|
|
|
qalSourcePause(source);
|
|
|
|
alDieIfError();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
openal_channel::stop
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
void openal_channel::stop()
|
|
|
|
{
|
|
|
|
qalSourceStop(source);
|
|
|
|
alDieIfError();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
openal_channel::get_state
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
ALint openal_channel::get_state()
|
|
|
|
{
|
|
|
|
ALint retval;
|
|
|
|
|
|
|
|
qalGetSourcei(source, AL_SOURCE_STATE, &retval);
|
|
|
|
alDieIfError();
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
openal_channel::is_free
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
bool openal_channel::is_free()
|
|
|
|
{
|
|
|
|
ALint state = get_state();
|
|
|
|
|
|
|
|
return state == AL_INITIAL || state == AL_STOPPED;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
openal_channel::is_paused
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
bool openal_channel::is_paused()
|
|
|
|
{
|
|
|
|
ALint state = get_state();
|
|
|
|
|
|
|
|
return state == AL_PAUSED;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
openal_channel::is_playing
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
bool openal_channel::is_playing()
|
|
|
|
{
|
|
|
|
ALint state = get_state();
|
|
|
|
|
|
|
|
return state == AL_PLAYING;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
openal_channel::force_free
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
void openal_channel::force_free()
|
|
|
|
{
|
|
|
|
stop();
|
2024-07-22 20:44:00 +02:00
|
|
|
iFlags = 0;
|
2024-01-15 23:04:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
openal_channel::set_sfx
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
bool openal_channel::set_sfx(sfx_t *pSfx)
|
|
|
|
{
|
2024-07-01 17:39:47 +02:00
|
|
|
ALint freq = 0;
|
2024-01-15 23:04:25 +01:00
|
|
|
|
|
|
|
this->pSfx = pSfx;
|
|
|
|
if (!pSfx->buffer || !qalIsBuffer(pSfx->buffer)) {
|
|
|
|
if (pSfx->iFlags & SFX_FLAG_MP3) {
|
|
|
|
qalGenBuffers(1, &pSfx->buffer);
|
|
|
|
alDieIfError();
|
|
|
|
|
2024-07-01 18:00:15 +02:00
|
|
|
if (!S_OPENAL_LoadMP3_Codec(pSfx->name, pSfx)) {
|
2024-01-15 23:04:25 +01:00
|
|
|
qalDeleteBuffers(1, &pSfx->buffer);
|
|
|
|
alDieIfError();
|
|
|
|
|
|
|
|
Com_Printf("OpenAL: Failed to load MP3.\n");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
alDieIfError();
|
|
|
|
} else {
|
|
|
|
ALenum fmt = 0;
|
|
|
|
|
|
|
|
if (pSfx->info.channels == 1) {
|
|
|
|
if (pSfx->info.width == 1) {
|
|
|
|
fmt = AL_FORMAT_MONO8;
|
|
|
|
} else if (pSfx->info.width == 2) {
|
|
|
|
fmt = AL_FORMAT_MONO16;
|
|
|
|
}
|
|
|
|
} else if (pSfx->info.channels == 2) {
|
|
|
|
if (pSfx->info.width == 1) {
|
|
|
|
fmt = AL_FORMAT_STEREO8;
|
|
|
|
} else if (pSfx->info.width == 2) {
|
|
|
|
fmt = AL_FORMAT_STEREO16;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!fmt) {
|
|
|
|
Com_Printf(
|
|
|
|
"OpenAL: Bad Wave file (%d channels, %d bits) [%s].\n",
|
|
|
|
pSfx->info.channels,
|
|
|
|
(int)(pSfx->info.width * 8.f),
|
|
|
|
pSfx->name
|
|
|
|
);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
qalGenBuffers(1, &pSfx->buffer);
|
|
|
|
alDieIfError();
|
|
|
|
|
|
|
|
qalBufferData(
|
|
|
|
pSfx->buffer,
|
|
|
|
fmt,
|
|
|
|
&pSfx->data[pSfx->info.dataofs],
|
|
|
|
pSfx->info.samples * pSfx->info.width,
|
|
|
|
pSfx->info.rate
|
|
|
|
);
|
|
|
|
alDieIfError();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
qalSourceStop(source);
|
|
|
|
alDieIfError();
|
|
|
|
|
|
|
|
qalSourcei(source, AL_BUFFER, pSfx->buffer);
|
|
|
|
alDieIfError();
|
|
|
|
|
|
|
|
// Get the base frequency
|
2024-07-01 17:39:47 +02:00
|
|
|
qalGetBufferi(pSfx->buffer, AL_FREQUENCY, &freq);
|
2024-01-15 23:04:25 +01:00
|
|
|
alDieIfError();
|
|
|
|
|
|
|
|
iBaseRate = freq;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
openal_channel::start_sample
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
void openal_channel::start_sample()
|
|
|
|
{
|
|
|
|
play();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
openal_channel::stop_sample
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
void openal_channel::stop_sample()
|
2024-01-07 19:47:58 +01:00
|
|
|
{
|
2024-01-15 23:04:25 +01:00
|
|
|
pause();
|
2024-01-07 19:47:58 +01:00
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
openal_channel::resume_sample
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
void openal_channel::resume_sample()
|
2024-01-07 19:47:58 +01:00
|
|
|
{
|
2024-01-15 23:04:25 +01:00
|
|
|
play();
|
2024-01-07 19:47:58 +01:00
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
openal_channel::end_sample
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
void openal_channel::end_sample()
|
2024-01-07 19:47:58 +01:00
|
|
|
{
|
2024-01-15 23:04:25 +01:00
|
|
|
stop();
|
2024-01-07 19:47:58 +01:00
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
openal_channel::set_sample_pan
|
|
|
|
==============
|
|
|
|
*/
|
2024-08-06 18:43:15 +02:00
|
|
|
void openal_channel::set_sample_pan(S32 pan)
|
|
|
|
{
|
|
|
|
const float panning = (pan - 64) / 127.f;
|
|
|
|
const ALfloat sourcePosition[3] = {panning, 0, sqrtf(1.f - Square(panning))};
|
|
|
|
|
|
|
|
qalSourcef(source, AL_ROLLOFF_FACTOR, 0);
|
|
|
|
qalSourcei(source, AL_SOURCE_RELATIVE, AL_TRUE);
|
|
|
|
qalSourcefv(source, AL_POSITION, sourcePosition);
|
|
|
|
}
|
2024-01-15 23:04:25 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
openal_channel::set_sample_playback_rate
|
|
|
|
==============
|
|
|
|
*/
|
2024-07-02 20:10:54 +02:00
|
|
|
void openal_channel::set_sample_playback_rate(S32 rate) {
|
|
|
|
// Fixed in OPM
|
|
|
|
// Set the pitch in OpenAL
|
|
|
|
qalSourcef(source, AL_PITCH, rate / (float)iBaseRate);
|
|
|
|
alDieIfError();
|
|
|
|
}
|
2024-01-15 23:04:25 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
openal_channel::sample_playback_rate
|
|
|
|
==============
|
|
|
|
*/
|
2024-01-07 19:47:58 +01:00
|
|
|
S32 openal_channel::sample_playback_rate()
|
|
|
|
{
|
2024-07-02 20:10:54 +02:00
|
|
|
float pitch = 1;
|
|
|
|
ALint freq = 0;
|
|
|
|
|
|
|
|
// Fixed in OPM
|
|
|
|
// The sample rate varies according to the pitch
|
|
|
|
qalGetSourcef(source, AL_PITCH, &pitch);
|
|
|
|
alDieIfError();
|
|
|
|
|
|
|
|
if (buffer) {
|
|
|
|
qalGetBufferi(buffer, AL_FREQUENCY, &freq);
|
|
|
|
alDieIfError();
|
|
|
|
} else if (pSfx) {
|
|
|
|
qalGetBufferi(pSfx->buffer, AL_FREQUENCY, &freq);
|
|
|
|
alDieIfError();
|
|
|
|
} else {
|
|
|
|
freq = 22050;
|
|
|
|
}
|
|
|
|
|
|
|
|
return freq * pitch;
|
2024-01-07 19:47:58 +01:00
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
openal_channel::sample_volume
|
|
|
|
==============
|
|
|
|
*/
|
2024-01-07 19:47:58 +01:00
|
|
|
S32 openal_channel::sample_volume()
|
|
|
|
{
|
2024-01-15 23:04:25 +01:00
|
|
|
STUB_DESC("sample_volume");
|
|
|
|
return 127;
|
2024-01-07 19:47:58 +01:00
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
openal_channel::sample_offset
|
|
|
|
==============
|
|
|
|
*/
|
2024-01-07 19:47:58 +01:00
|
|
|
U32 openal_channel::sample_offset()
|
|
|
|
{
|
2024-07-22 20:07:32 +02:00
|
|
|
ALint offset = 0;
|
|
|
|
|
|
|
|
qalGetSourcei(source, AL_SAMPLE_OFFSET, &offset);
|
|
|
|
alDieIfError();
|
|
|
|
|
|
|
|
return offset;
|
2024-01-07 19:47:58 +01:00
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
openal_channel::sample_ms_offset
|
|
|
|
==============
|
|
|
|
*/
|
2024-01-07 19:47:58 +01:00
|
|
|
U32 openal_channel::sample_ms_offset()
|
|
|
|
{
|
2024-07-22 20:07:32 +02:00
|
|
|
float offset = 0;
|
|
|
|
|
|
|
|
qalGetSourcef(source, AL_SAMPLE_OFFSET, &offset);
|
|
|
|
alDieIfError();
|
|
|
|
|
|
|
|
return offset * 1000.f;
|
2024-01-07 19:47:58 +01:00
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
openal_channel::sample_loop_count
|
|
|
|
==============
|
|
|
|
*/
|
2024-01-07 19:47:58 +01:00
|
|
|
U32 openal_channel::sample_loop_count()
|
|
|
|
{
|
2024-01-15 23:04:25 +01:00
|
|
|
ALuint queued;
|
|
|
|
ALuint processed;
|
|
|
|
S32 left;
|
|
|
|
|
|
|
|
qalGetSourceiv(source, AL_BUFFERS_QUEUED, (ALint *)&queued);
|
|
|
|
alDieIfError();
|
|
|
|
qalGetSourcei(source, AL_BUFFERS_PROCESSED, (ALint *)&processed);
|
|
|
|
alDieIfError();
|
|
|
|
|
|
|
|
left = queued + ~processed;
|
|
|
|
if (left < 0) {
|
|
|
|
left = 0;
|
|
|
|
}
|
|
|
|
return left;
|
2024-01-07 19:47:58 +01:00
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
openal_channel::set_sample_offset
|
|
|
|
==============
|
|
|
|
*/
|
2024-01-07 19:47:58 +01:00
|
|
|
void openal_channel::set_sample_offset(U32 offset)
|
|
|
|
{
|
2024-07-22 20:07:32 +02:00
|
|
|
qalSourcei(source, AL_SAMPLE_OFFSET, offset);
|
|
|
|
alDieIfError();
|
2024-01-07 19:47:58 +01:00
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
openal_channel::set_sample_ms_offset
|
|
|
|
==============
|
|
|
|
*/
|
2024-01-07 19:47:58 +01:00
|
|
|
void openal_channel::set_sample_ms_offset(U32 offset)
|
|
|
|
{
|
2024-07-22 20:07:32 +02:00
|
|
|
qalSourcef(source, AL_SEC_OFFSET, offset / 1000.f);
|
|
|
|
alDieIfError();
|
2024-01-07 19:47:58 +01:00
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
openal_channel::set_sample_loop_count
|
|
|
|
==============
|
|
|
|
*/
|
2024-01-07 19:47:58 +01:00
|
|
|
void openal_channel::set_sample_loop_count(S32 count)
|
|
|
|
{
|
2024-01-16 20:54:41 +01:00
|
|
|
ALuint processed = 0;
|
2024-01-15 23:04:25 +01:00
|
|
|
|
|
|
|
stop();
|
|
|
|
|
|
|
|
qalGetSourceiv(source, AL_BUFFERS_PROCESSED, (ALint *)&processed);
|
|
|
|
alDieIfError();
|
|
|
|
|
|
|
|
for (ALuint i = 0; i < processed; i++) {
|
|
|
|
ALuint bufName;
|
|
|
|
|
|
|
|
qalSourceUnqueueBuffers(source, 1, &bufName);
|
|
|
|
alDieIfError();
|
|
|
|
}
|
|
|
|
|
2024-07-01 17:39:47 +02:00
|
|
|
if (buffer) {
|
|
|
|
for (S32 i = 0; i < count; i++) {
|
|
|
|
qalSourceQueueBuffers(source, 1, &buffer);
|
|
|
|
alDieIfError();
|
|
|
|
}
|
2024-01-15 23:04:25 +01:00
|
|
|
}
|
2024-07-02 20:01:01 +02:00
|
|
|
|
|
|
|
if (count == 0) {
|
|
|
|
qalSourcei(source, AL_LOOPING, true);
|
|
|
|
alDieIfError();
|
|
|
|
}
|
2024-01-07 19:47:58 +01:00
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
openal_channel::set_sample_loop_block
|
|
|
|
==============
|
|
|
|
*/
|
2024-01-07 19:47:58 +01:00
|
|
|
void openal_channel::set_sample_loop_block(S32 start_offset, S32 end_offset)
|
|
|
|
{
|
2024-01-15 23:04:25 +01:00
|
|
|
STUB_DESC("sample_loop_block");
|
2024-01-07 19:47:58 +01:00
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
openal_channel::sample_status
|
|
|
|
==============
|
|
|
|
*/
|
2024-01-07 19:47:58 +01:00
|
|
|
U32 openal_channel::sample_status()
|
|
|
|
{
|
2024-01-15 23:04:25 +01:00
|
|
|
STUB_DESC("sample_status");
|
|
|
|
return 127;
|
2024-01-07 19:47:58 +01:00
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
MUSIC_LoadSoundtrackFile
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
qboolean MUSIC_LoadSoundtrackFile(const char *filename)
|
|
|
|
{
|
|
|
|
song_t *psong = NULL;
|
|
|
|
char args[MAX_MUSIC_SONGS][MAX_RES_NAME];
|
|
|
|
int numargs;
|
|
|
|
char com_token[MAX_STRING_CHARS];
|
|
|
|
char alias[128];
|
|
|
|
char file[128];
|
|
|
|
char load_path[128];
|
|
|
|
char *buffer;
|
|
|
|
char path[MAX_RES_NAME];
|
|
|
|
int i;
|
|
|
|
byte *data;
|
|
|
|
|
|
|
|
if (strrchr(filename, '.')) {
|
|
|
|
Com_sprintf(path, sizeof(path), "%s", filename);
|
|
|
|
} else {
|
|
|
|
Com_sprintf(path, sizeof(path), "%s.mus", filename);
|
|
|
|
}
|
|
|
|
|
|
|
|
FS_ReadFile(path, (void **)&data);
|
|
|
|
if (!data) {
|
|
|
|
Com_DPrintf("Couldn't load %s\n", path);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
Com_DPrintf("SOUNDTRACK: Loading %s\n", path);
|
|
|
|
|
|
|
|
MUSIC_StopAllSongs();
|
|
|
|
music_numsongs = 0;
|
|
|
|
|
|
|
|
buffer = (char *)data;
|
|
|
|
load_path[0] = 0;
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
strcpy(com_token, COM_GetToken(&buffer, true));
|
|
|
|
if (!com_token[0]) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (strlen(com_token) >= MAX_RES_NAME) {
|
|
|
|
Com_Printf("MUSIC_LoadSoundtrackFile: argument too long, truncating in %s\n", path);
|
|
|
|
com_token[MAX_RES_NAME - 1] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
numargs = 1;
|
|
|
|
strcpy(args[0], com_token);
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
strcpy(com_token, COM_GetToken(&buffer, false));
|
|
|
|
if (!com_token[0]) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (strlen(com_token) >= MAX_RES_NAME) {
|
|
|
|
Com_Printf("MUSIC_LoadSoundtrackFile: argument too long, truncating in %s\n", path);
|
|
|
|
com_token[MAX_RES_NAME - 1] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
strcpy(args[numargs], com_token);
|
|
|
|
numargs++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!Q_stricmp(args[0], "path")) {
|
|
|
|
strcpy(load_path, args[1]);
|
|
|
|
if (load_path[strlen(load_path) - 1] != '/' && load_path[strlen(load_path) - 1] != '\\') {
|
|
|
|
strcat(load_path, "/");
|
|
|
|
}
|
|
|
|
} else if (args[0][0] == '!') {
|
|
|
|
for (i = 0; i < music_numsongs; i++) {
|
|
|
|
psong = &music_songs[i];
|
|
|
|
if (!Q_stricmp(psong->alias, &args[0][1])) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (i == music_numsongs) {
|
|
|
|
Com_Printf("MUSIC_LoadSoundtrackFile: song %s not found, command skipped in %s.\n", &args[0][1], path);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!Q_stricmp(args[1], "volume")) {
|
|
|
|
psong->volume = atoi(args[2]);
|
|
|
|
} else if (!Q_stricmp(args[1], "fadetime")) {
|
|
|
|
psong->fadetime = atoi(args[2]);
|
|
|
|
} else if (!Q_stricmp(args[1], "loop")) {
|
|
|
|
psong->flags |= 1;
|
|
|
|
} else if (!Q_stricmp(args[1], "restart")) {
|
|
|
|
psong->flags |= 2;
|
|
|
|
} else if (!Q_stricmp(args[1], "interrupt")) {
|
|
|
|
psong->fadetime = 0;
|
|
|
|
psong->flags |= 4 | 2;
|
|
|
|
} else {
|
|
|
|
Com_Printf(
|
|
|
|
"MUSIC_LoadSoundtrackFile: unknown command %s for song %s in %s.\n", args[1], &args[0][1], path
|
|
|
|
);
|
|
|
|
}
|
|
|
|
} else {
|
2024-01-16 20:54:41 +01:00
|
|
|
if (numargs > 1) {
|
|
|
|
strcpy(alias, args[0]);
|
|
|
|
strcpy(file, load_path);
|
|
|
|
strcat(file, args[1]);
|
|
|
|
} else {
|
|
|
|
strcpy(file, load_path);
|
|
|
|
strcat(file, args[1]);
|
2024-01-15 23:04:25 +01:00
|
|
|
|
2024-01-16 20:54:41 +01:00
|
|
|
strncpy(alias, args[0], strlen(args[0]) - 4);
|
|
|
|
file[strlen(args[0]) + MAX_RES_NAME * 2 - 4] = 0;
|
|
|
|
}
|
2024-01-15 23:04:25 +01:00
|
|
|
|
|
|
|
if (music_numsongs >= MAX_MUSIC_SONGS) {
|
|
|
|
Com_Printf("MUSIC_LoadSoundtrackFile: Too many songs in %s, skipping %s.\n", path, alias);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
psong = &music_songs[music_numsongs];
|
|
|
|
strcpy(psong->alias, alias);
|
|
|
|
strcpy(psong->path, file);
|
|
|
|
music_songs[music_numsongs].fadetime = 1.0;
|
|
|
|
music_songs[music_numsongs].volume = 1.0;
|
|
|
|
music_songs[music_numsongs].flags = 0;
|
|
|
|
music_songs[music_numsongs].current_pos = 0;
|
|
|
|
music_songs[music_numsongs].mood_num = MusicMood_NameToNum(alias);
|
|
|
|
music_numsongs++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!music_numsongs) {
|
|
|
|
Com_Printf("MUSIC_LoadSoundtrackFile: could not load %s, no songs defined.\n", path);
|
|
|
|
FS_FreeFile(data);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
music_currentsong = -1;
|
|
|
|
FS_FreeFile(data);
|
|
|
|
|
|
|
|
if (music_current_mood == mood_none) {
|
|
|
|
MUSIC_UpdateMood(mood_normal, mood_normal);
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
2024-01-07 19:47:58 +01:00
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
MUSIC_SongValid
|
|
|
|
==============
|
|
|
|
*/
|
2024-01-07 19:47:58 +01:00
|
|
|
qboolean MUSIC_SongValid(const char *mood)
|
|
|
|
{
|
2024-01-15 23:04:25 +01:00
|
|
|
return MUSIC_FindSong(mood) != -1;
|
2024-01-07 19:47:58 +01:00
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
MUSIC_Loaded
|
|
|
|
==============
|
|
|
|
*/
|
2024-01-07 19:47:58 +01:00
|
|
|
qboolean MUSIC_Loaded()
|
|
|
|
{
|
2024-01-15 23:04:25 +01:00
|
|
|
return music_loaded;
|
2024-01-07 19:47:58 +01:00
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
Music_Update
|
|
|
|
==============
|
|
|
|
*/
|
2024-01-07 19:47:58 +01:00
|
|
|
void Music_Update()
|
|
|
|
{
|
2024-01-15 23:04:25 +01:00
|
|
|
int currentsong;
|
|
|
|
|
|
|
|
if (!s_bSoundStarted) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!music_active) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (s_bSoundPaused) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
MUSIC_CheckForStoppedSongs();
|
|
|
|
|
|
|
|
if (!MUSIC_Loaded() && music_active && strlen(current_soundtrack)) {
|
|
|
|
MUSIC_LoadSoundtrackFile(current_soundtrack);
|
|
|
|
music_loaded = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (music_currentsong >= 0) {
|
|
|
|
currentsong = music_songs[music_currentsong].mood_num;
|
|
|
|
} else {
|
|
|
|
currentsong = -1;
|
|
|
|
}
|
|
|
|
|
2024-01-17 20:44:32 +01:00
|
|
|
if (music_current_mood == mood_none) {
|
2024-01-15 23:04:25 +01:00
|
|
|
if (MUSIC_Playing()) {
|
|
|
|
MUSIC_StopAllSongs();
|
|
|
|
}
|
|
|
|
} else if (music_current_mood != currentsong) {
|
|
|
|
const char *mood = MusicMood_NumToName(music_current_mood);
|
|
|
|
if (MUSIC_SongValid(mood) && MUSIC_Loaded() && strlen(current_soundtrack)) {
|
|
|
|
Com_DebugPrintf("Playing %s.\n", mood);
|
|
|
|
MUSIC_PlaySong(mood);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (new_music_volume != music_volume) {
|
|
|
|
if (music_volume_fade_time > 0) {
|
|
|
|
if (music_volume_direction == 0) {
|
|
|
|
music_volume = (cls.realtime - music_volume_start_time) * (new_music_volume - old_music_volume)
|
|
|
|
/ (music_volume_fade_time * 1000.f)
|
|
|
|
+ old_music_volume;
|
|
|
|
|
|
|
|
if (music_volume > new_music_volume) {
|
|
|
|
music_volume = new_music_volume;
|
|
|
|
music_volume_changed = 1;
|
|
|
|
} else {
|
|
|
|
music_volume_changed = 1;
|
|
|
|
}
|
|
|
|
} else if (music_volume_direction == 1) {
|
|
|
|
music_volume = 1.0
|
|
|
|
- (cls.realtime - music_volume_start_time) * (old_music_volume - new_music_volume)
|
|
|
|
/ (music_volume_fade_time * 1000.f);
|
|
|
|
|
|
|
|
if (music_volume >= new_music_volume) {
|
|
|
|
music_volume_changed = true;
|
|
|
|
} else {
|
|
|
|
music_volume = new_music_volume;
|
|
|
|
music_volume_changed = true;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
music_volume_changed = true;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
music_volume = new_music_volume;
|
|
|
|
music_volume_changed = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
MUSIC_UpdateMusicVolumes();
|
2024-01-07 19:47:58 +01:00
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
MUSIC_SongEnded
|
|
|
|
==============
|
|
|
|
*/
|
2024-01-07 19:47:58 +01:00
|
|
|
void MUSIC_SongEnded()
|
|
|
|
{
|
2024-01-15 23:04:25 +01:00
|
|
|
Com_DPrintf(
|
|
|
|
"MUSIC: Song ended, changing from [ %s ] to [ %s ]\n",
|
|
|
|
MusicMood_NumToName(music_current_mood),
|
|
|
|
MusicMood_NumToName(music_fallback_mood)
|
|
|
|
);
|
|
|
|
music_current_mood = music_fallback_mood;
|
2024-01-07 19:47:58 +01:00
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
MUSIC_NewSoundtrack
|
|
|
|
==============
|
|
|
|
*/
|
2024-01-07 19:47:58 +01:00
|
|
|
void MUSIC_NewSoundtrack(const char *name)
|
|
|
|
{
|
2024-01-15 23:04:25 +01:00
|
|
|
if (!s_bSoundStarted) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!Q_stricmp(name, current_soundtrack)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Fixed in OPM
|
|
|
|
// Make sure to not get past the end of the buffer
|
|
|
|
//strcpy(current_soundtrack, name);
|
|
|
|
Q_strncpyz(current_soundtrack, name, sizeof(current_soundtrack));
|
|
|
|
|
|
|
|
if (!Q_stricmp(current_soundtrack, "none") || !Q_stricmp(current_soundtrack, "")) {
|
|
|
|
music_active = qfalse;
|
|
|
|
if (MUSIC_Playing()) {
|
|
|
|
MUSIC_StopAllSongs();
|
|
|
|
}
|
2024-01-16 20:54:41 +01:00
|
|
|
} else {
|
|
|
|
music_active = qtrue;
|
|
|
|
MUSIC_LoadSoundtrackFile(name);
|
|
|
|
music_loaded = qtrue;
|
2024-01-15 23:04:25 +01:00
|
|
|
}
|
2024-01-07 19:47:58 +01:00
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
MUSIC_UpdateMood
|
|
|
|
==============
|
|
|
|
*/
|
2024-01-07 19:47:58 +01:00
|
|
|
void MUSIC_UpdateMood(int current, int fallback)
|
|
|
|
{
|
2024-01-15 23:04:25 +01:00
|
|
|
static int last_current_mood = -1;
|
|
|
|
static int last_fallback_mood = -1;
|
|
|
|
static int current_mood = -1;
|
|
|
|
static int fallback_mood = -1;
|
|
|
|
qboolean was_action;
|
|
|
|
|
|
|
|
if (current == current_mood && fallback == fallback_mood) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
was_action = current == last_current_mood && fallback == last_fallback_mood && current_mood == mood_action;
|
|
|
|
last_current_mood = current_mood;
|
|
|
|
last_fallback_mood = fallback_mood;
|
|
|
|
current_mood = current;
|
|
|
|
music_current_mood = current;
|
|
|
|
fallback_mood = fallback;
|
|
|
|
music_fallback_mood = fallback;
|
|
|
|
music_active = qtrue;
|
|
|
|
|
|
|
|
Com_DPrintf(
|
|
|
|
"MUSIC: changing from [ %s | %s ] to [ %s | %s ]\n",
|
|
|
|
MusicMood_NumToName(last_current_mood),
|
|
|
|
MusicMood_NumToName(last_fallback_mood),
|
|
|
|
MusicMood_NumToName(current_mood),
|
|
|
|
MusicMood_NumToName(fallback)
|
|
|
|
);
|
|
|
|
|
|
|
|
if (was_action) {
|
|
|
|
int songnum = MUSIC_FindSong(MusicMood_NumToName(current_mood));
|
|
|
|
|
|
|
|
if (songnum != -1 && (music_songs[songnum].flags & 4)) {
|
|
|
|
Com_DPrintf(
|
|
|
|
"MUSIC: restoring music from action state, skipping [ %s ] for [ %s ]\n",
|
|
|
|
MusicMood_NumToName(current_mood),
|
|
|
|
MusicMood_NumToName(fallback_mood)
|
|
|
|
);
|
|
|
|
music_current_mood = music_fallback_mood;
|
|
|
|
}
|
|
|
|
}
|
2024-01-07 19:47:58 +01:00
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
MUSIC_UpdateVolume
|
|
|
|
==============
|
|
|
|
*/
|
2024-01-07 19:47:58 +01:00
|
|
|
void MUSIC_UpdateVolume(float volume, float fade_time)
|
|
|
|
{
|
2024-01-15 23:04:25 +01:00
|
|
|
if (new_music_volume == volume && music_volume_fade_time == fade_time) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
old_music_volume = music_volume;
|
|
|
|
new_music_volume = volume;
|
|
|
|
music_volume_fade_time = fade_time;
|
|
|
|
music_volume_start_time = cls.realtime;
|
|
|
|
|
|
|
|
if (volume > music_volume) {
|
|
|
|
music_volume_direction = 0;
|
|
|
|
} else if (volume < music_volume) {
|
|
|
|
music_volume_direction = 1;
|
|
|
|
}
|
2024-01-07 19:47:58 +01:00
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
MUSIC_StopAllSongs
|
|
|
|
==============
|
|
|
|
*/
|
2024-01-07 19:47:58 +01:00
|
|
|
void MUSIC_StopAllSongs()
|
|
|
|
{
|
2024-01-15 23:04:25 +01:00
|
|
|
for (int i = 0; i < MAX_OPENAL_SONGS; i++) {
|
|
|
|
MUSIC_StopChannel(i);
|
|
|
|
}
|
|
|
|
|
|
|
|
music_currentsong = -1;
|
2024-01-07 19:47:58 +01:00
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
MUSIC_FreeAllSongs
|
|
|
|
==============
|
|
|
|
*/
|
2024-01-07 19:47:58 +01:00
|
|
|
void MUSIC_FreeAllSongs()
|
|
|
|
{
|
2024-01-15 23:04:25 +01:00
|
|
|
MUSIC_StopAllSongs();
|
|
|
|
MUSIC_UpdateMood(mood_none, mood_none);
|
|
|
|
current_soundtrack[0] = 0;
|
|
|
|
music_loaded = false;
|
2024-01-07 19:47:58 +01:00
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
MUSIC_Playing
|
|
|
|
==============
|
|
|
|
*/
|
2024-01-07 19:47:58 +01:00
|
|
|
qboolean MUSIC_Playing()
|
|
|
|
{
|
2024-01-15 23:04:25 +01:00
|
|
|
return MUSIC_CurrentSongChannel() != -1;
|
2024-01-07 19:47:58 +01:00
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
MUSIC_FindSong
|
|
|
|
==============
|
|
|
|
*/
|
2024-01-07 19:47:58 +01:00
|
|
|
int MUSIC_FindSong(const char *name)
|
|
|
|
{
|
2024-01-15 23:04:25 +01:00
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < music_numsongs; i++) {
|
|
|
|
if (!Q_stricmp(music_songs[i].alias, name)) {
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
2024-01-07 19:47:58 +01:00
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
S_loadsoundtrack
|
|
|
|
==============
|
|
|
|
*/
|
2024-01-07 19:47:58 +01:00
|
|
|
void S_loadsoundtrack()
|
|
|
|
{
|
2024-01-15 23:04:25 +01:00
|
|
|
if (Cmd_Argc() != 2) {
|
|
|
|
Com_Printf("loadsoundtrack <sound track file>\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
MUSIC_LoadSoundtrackFile(Cmd_Argv(1));
|
|
|
|
music_loaded = true;
|
|
|
|
Q_strncpyz(current_soundtrack, Cmd_Argv(1), sizeof(current_soundtrack));
|
2024-01-07 19:47:58 +01:00
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
S_CurrentSoundtrack
|
|
|
|
==============
|
|
|
|
*/
|
2024-01-07 19:47:58 +01:00
|
|
|
const char *S_CurrentSoundtrack()
|
|
|
|
{
|
2024-01-15 23:04:25 +01:00
|
|
|
return current_soundtrack;
|
2024-01-07 19:47:58 +01:00
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
S_PlaySong
|
|
|
|
==============
|
|
|
|
*/
|
2024-01-07 19:47:58 +01:00
|
|
|
void S_PlaySong()
|
|
|
|
{
|
2024-01-15 23:04:25 +01:00
|
|
|
if (Cmd_Argc() != 2) {
|
|
|
|
Com_Printf("playsong <song alias>\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
MUSIC_PlaySong(Cmd_Argv(1));
|
|
|
|
music_active = true;
|
2024-01-07 19:47:58 +01:00
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
MUSIC_CurrentSongChannel
|
|
|
|
==============
|
|
|
|
*/
|
2024-01-07 19:47:58 +01:00
|
|
|
int MUSIC_CurrentSongChannel()
|
|
|
|
{
|
2024-01-15 23:04:25 +01:00
|
|
|
int channel_number = -1;
|
|
|
|
int ch_idx = 0;
|
|
|
|
|
|
|
|
for (ch_idx = 0; ch_idx < MAX_OPENAL_SONGS; ch_idx++) {
|
|
|
|
if (openal.chan_song[ch_idx].is_playing() && openal.chan_song[ch_idx].song_number == music_currentsong) {
|
|
|
|
channel_number = ch_idx;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return channel_number;
|
2024-01-07 19:47:58 +01:00
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
MUSIC_StopChannel
|
|
|
|
==============
|
|
|
|
*/
|
2024-01-07 19:47:58 +01:00
|
|
|
void MUSIC_StopChannel(int channel_number)
|
|
|
|
{
|
2024-01-15 23:04:25 +01:00
|
|
|
openal_channel *channel = &openal.chan_song[channel_number];
|
|
|
|
|
|
|
|
channel->pause();
|
|
|
|
if (music_songs[channel->song_number].flags & 2) {
|
|
|
|
music_songs[channel->song_number].current_pos = 0;
|
|
|
|
} else {
|
|
|
|
music_songs[channel->song_number].current_pos = channel->sample_ms_offset();
|
|
|
|
}
|
|
|
|
|
|
|
|
channel->stop();
|
2024-01-07 19:47:58 +01:00
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
MUSIC_PlaySong
|
|
|
|
==============
|
|
|
|
*/
|
2024-01-07 19:47:58 +01:00
|
|
|
qboolean MUSIC_PlaySong(const char *alias)
|
|
|
|
{
|
2024-08-12 20:25:04 +02:00
|
|
|
int channel_number;
|
|
|
|
song_t *song;
|
|
|
|
int songnum;
|
|
|
|
int channel_to_play_on;
|
|
|
|
int fading_song;
|
|
|
|
openal_channel_two_d_stream *song_channel;
|
|
|
|
unsigned int loop_start;
|
|
|
|
int rate;
|
2024-01-15 23:04:25 +01:00
|
|
|
|
|
|
|
fading_song = 0;
|
|
|
|
songnum = MUSIC_FindSong(alias);
|
|
|
|
|
|
|
|
if (songnum == -1) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
song = &music_songs[songnum];
|
|
|
|
|
|
|
|
if (MUSIC_Playing() && songnum == music_currentsong) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
channel_number = MUSIC_CurrentSongChannel();
|
|
|
|
music_currentsong = songnum;
|
|
|
|
|
|
|
|
if (channel_number != -1) {
|
|
|
|
if (song->flags & 4) {
|
|
|
|
MUSIC_StopChannel(channel_number);
|
|
|
|
} else {
|
|
|
|
song_channel = &openal.chan_song[channel_number];
|
|
|
|
song_channel->fading = FADE_OUT;
|
|
|
|
song_channel->fade_time = (int)song->fadetime;
|
|
|
|
song_channel->fade_start_time = cls.realtime;
|
|
|
|
fading_song = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
channel_to_play_on = (fading_song != 0) && (channel_number == 0);
|
|
|
|
song_channel = &openal.chan_song[channel_to_play_on];
|
|
|
|
|
|
|
|
if (song_channel->is_playing() || song_channel->is_paused()) {
|
|
|
|
MUSIC_StopChannel(channel_to_play_on);
|
|
|
|
}
|
|
|
|
|
2024-08-12 20:25:04 +02:00
|
|
|
if (!song_channel->queue_stream(song->path)) {
|
2024-01-15 23:04:25 +01:00
|
|
|
Com_DPrintf("Could not start music file '%s'!", song->path);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
rate = song_channel->sample_playback_rate();
|
|
|
|
|
|
|
|
song_channel->song_number = songnum;
|
|
|
|
if (song->current_pos) {
|
|
|
|
song_channel->set_sample_ms_offset(song->current_pos);
|
|
|
|
} else {
|
|
|
|
song_channel->set_sample_offset(rate * 0.063f);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (song->flags & 1) {
|
|
|
|
song_channel->set_sample_loop_count(0);
|
|
|
|
song_channel->set_sample_loop_block(rate * 0.063f, -1);
|
|
|
|
} else {
|
|
|
|
song_channel->set_sample_loop_count(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fading_song) {
|
|
|
|
song_channel->fading = FADE_IN;
|
|
|
|
song_channel->fade_time = (int)song->fadetime;
|
|
|
|
song_channel->set_gain(0.0);
|
|
|
|
song_channel->fade_start_time = cls.realtime;
|
|
|
|
} else {
|
|
|
|
song_channel->fading = FADE_NONE;
|
2024-07-01 16:46:47 +02:00
|
|
|
song_channel->set_gain(S_GetBaseVolume() * (song->volume * s_ambientVolume->value) * s_fVolumeGain);
|
2024-01-15 23:04:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
song_channel->play();
|
|
|
|
|
|
|
|
return true;
|
2024-01-07 19:47:58 +01:00
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
MUSIC_UpdateMusicVolumes
|
|
|
|
==============
|
|
|
|
*/
|
2024-01-07 19:47:58 +01:00
|
|
|
void MUSIC_UpdateMusicVolumes()
|
|
|
|
{
|
2024-01-15 23:04:25 +01:00
|
|
|
int i;
|
|
|
|
unsigned int current_time;
|
|
|
|
float new_volume, max_volume;
|
|
|
|
|
|
|
|
if (s_ambientVolume->modified || music_volume_changed) {
|
|
|
|
s_ambientVolume->modified = false;
|
|
|
|
|
|
|
|
for (i = 0; i < MAX_OPENAL_SONGS; i++) {
|
|
|
|
if (!openal.chan_song[i].is_playing() && !openal.chan_song[i].is_paused()) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (openal.chan_song[i].fading != FADE_NONE) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
openal.chan_song[i].set_gain(
|
|
|
|
S_GetBaseVolume() * (music_songs[openal.chan_song[i].song_number].volume * s_ambientVolume->value)
|
2024-07-01 16:46:47 +02:00
|
|
|
* s_fVolumeGain * music_volume
|
2024-01-15 23:04:25 +01:00
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < MAX_OPENAL_SONGS; i++) {
|
|
|
|
if (!openal.chan_song[i].is_playing() && !openal.chan_song[i].is_paused()) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (openal.chan_song[i].fading) {
|
|
|
|
case fade_t::FADE_IN:
|
|
|
|
max_volume = music_songs[openal.chan_song[i].song_number].volume * s_ambientVolume->value;
|
|
|
|
new_volume = (unsigned int)(cls.realtime - openal.chan_song[i].fade_start_time)
|
|
|
|
/ (openal.chan_song[i].fade_time * 1000.f) * max_volume;
|
|
|
|
|
|
|
|
if (new_volume > max_volume) {
|
2024-07-01 16:46:47 +02:00
|
|
|
openal.chan_song[i].set_gain(S_GetBaseVolume() * (max_volume * s_fVolumeGain * music_volume));
|
2024-01-15 23:04:25 +01:00
|
|
|
openal.chan_song[i].fading = FADE_NONE;
|
|
|
|
} else {
|
2024-07-01 16:46:47 +02:00
|
|
|
openal.chan_song[i].set_gain(S_GetBaseVolume() * (new_volume * s_fVolumeGain * music_volume));
|
2024-01-15 23:04:25 +01:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case fade_t::FADE_OUT:
|
|
|
|
max_volume = music_songs[openal.chan_song[i].song_number].volume * s_ambientVolume->value;
|
|
|
|
new_volume = (unsigned int)(cls.realtime - openal.chan_song[i].fade_start_time)
|
|
|
|
/ (openal.chan_song[i].fade_time * 1000.f) * max_volume;
|
|
|
|
|
|
|
|
if (new_volume > 0) {
|
2024-07-01 16:46:47 +02:00
|
|
|
openal.chan_song[i].set_gain(S_GetBaseVolume() * (new_volume * s_fVolumeGain * music_volume));
|
2024-01-15 23:04:25 +01:00
|
|
|
} else {
|
|
|
|
MUSIC_StopChannel(i);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (s_musicVolume->modified || music_volume_changed) {
|
|
|
|
s_musicVolume->modified = false;
|
|
|
|
if (openal.chan_trig_music.is_playing() || openal.chan_trig_music.is_paused()) {
|
|
|
|
openal.chan_trig_music.set_gain(
|
2024-07-01 16:46:47 +02:00
|
|
|
S_GetBaseVolume() * (openal.chan_trig_music.fVolume * s_musicVolume->value) * s_fVolumeGain
|
2024-01-15 23:04:25 +01:00
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
music_volume_changed = false;
|
2024-01-07 19:47:58 +01:00
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
MUSIC_CheckForStoppedSongs
|
|
|
|
==============
|
|
|
|
*/
|
2024-01-07 19:47:58 +01:00
|
|
|
void MUSIC_CheckForStoppedSongs()
|
|
|
|
{
|
2024-01-15 23:04:25 +01:00
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < MAX_OPENAL_SONGS; i++) {
|
|
|
|
if (!openal.chan_song[i].is_playing()) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (openal.chan_song[i].sample_loop_count()) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
MUSIC_FindSong(MusicMood_NumToName(music_fallback_mood));
|
|
|
|
if (!openal.chan_song[i].is_playing() && !openal.chan_song[i].is_paused()) {
|
|
|
|
MUSIC_SongEnded();
|
|
|
|
}
|
|
|
|
}
|
2024-01-07 19:47:58 +01:00
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
S_TriggeredMusic_SetupHandle
|
|
|
|
==============
|
|
|
|
*/
|
2024-01-07 19:47:58 +01:00
|
|
|
void S_TriggeredMusic_SetupHandle(const char *pszName, int iLoopCount, int iOffset, qboolean autostart)
|
|
|
|
{
|
2024-01-15 23:04:25 +01:00
|
|
|
char *pszFilename;
|
|
|
|
const char *pszRealName;
|
|
|
|
float fVolume = 1.0;
|
|
|
|
AliasListNode_t *pSoundAlias = NULL;
|
2024-08-12 20:25:04 +02:00
|
|
|
void *stream = NULL;
|
2024-01-15 23:04:25 +01:00
|
|
|
|
|
|
|
if (!s_bSoundStarted) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (openal.chan_trig_music.is_playing() || openal.chan_trig_music.is_paused()) {
|
|
|
|
Com_DPrintf("Didn't start new triggered music because some was already playing\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
openal.chan_trig_music.stop();
|
|
|
|
// Fixed in OPM
|
|
|
|
// Use strncpy instead
|
|
|
|
//strcpy(openal.tm_filename, pszName);
|
|
|
|
Q_strncpyz(openal.tm_filename, pszName, sizeof(openal.tm_filename));
|
|
|
|
|
|
|
|
openal.tm_loopcount = iLoopCount;
|
|
|
|
openal.chan_trig_music.set_sample_loop_count(iLoopCount);
|
|
|
|
pszRealName = Alias_FindRandom(pszName, &pSoundAlias);
|
|
|
|
|
|
|
|
if (!pszRealName) {
|
|
|
|
pszRealName = pszName;
|
|
|
|
} else if (pSoundAlias) {
|
|
|
|
fVolume = random() * pSoundAlias->volumeMod + pSoundAlias->volume;
|
|
|
|
}
|
|
|
|
|
|
|
|
pszFilename = FS_BuildOSPath(Cvar_VariableString("fs_basepath"), FS_Gamedir(), pszRealName);
|
|
|
|
|
2024-08-12 20:25:04 +02:00
|
|
|
if (!openal.chan_trig_music.queue_stream(pszRealName)) {
|
2024-01-15 23:04:25 +01:00
|
|
|
S_OPENAL_InitChannel(OPENAL_CHANNEL_TRIGGER_MUSIC_ID, &openal.chan_trig_music);
|
|
|
|
Com_DPrintf("Could not start triggered music '%s'\n", pszName);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
openal.chan_trig_music.fVolume = fVolume;
|
2024-07-01 16:46:47 +02:00
|
|
|
openal.chan_trig_music.set_gain(S_GetBaseVolume() * (fVolume * s_musicVolume->value) * s_fVolumeGain);
|
2024-01-15 23:04:25 +01:00
|
|
|
openal.chan_trig_music.set_sample_loop_count(iLoopCount);
|
|
|
|
openal.chan_trig_music.set_sample_offset(iOffset);
|
|
|
|
|
2024-07-22 20:07:32 +02:00
|
|
|
// Fixed in OPM
|
|
|
|
// Play the sound then pause it immediately
|
|
|
|
// So it can be unpaused upon loading from save
|
|
|
|
openal.chan_trig_music.play();
|
|
|
|
|
|
|
|
if (!autostart) {
|
|
|
|
openal.chan_trig_music.pause();
|
2024-01-15 23:04:25 +01:00
|
|
|
}
|
2024-01-07 19:47:58 +01:00
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
S_TriggeredMusic_Start
|
|
|
|
==============
|
|
|
|
*/
|
2024-01-07 19:47:58 +01:00
|
|
|
void S_TriggeredMusic_Start()
|
|
|
|
{
|
2024-01-15 23:04:25 +01:00
|
|
|
if (Cmd_Argc() != 2) {
|
|
|
|
Com_Printf("tmstart <sound file>\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
S_TriggeredMusic_SetupHandle(Cmd_Argv(1), 1, 0, true);
|
2024-01-07 19:47:58 +01:00
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
S_TriggeredMusic_StartLoop
|
|
|
|
==============
|
|
|
|
*/
|
2024-01-07 19:47:58 +01:00
|
|
|
void S_TriggeredMusic_StartLoop()
|
|
|
|
{
|
2024-01-15 23:04:25 +01:00
|
|
|
if (Cmd_Argc() != 2) {
|
|
|
|
Com_Printf("tmstartloop <sound file>\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
S_TriggeredMusic_SetupHandle(Cmd_Argv(1), 0, 0, true);
|
2024-01-07 19:47:58 +01:00
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
S_TriggeredMusic_Stop
|
|
|
|
==============
|
|
|
|
*/
|
2024-01-07 19:47:58 +01:00
|
|
|
void S_TriggeredMusic_Stop()
|
|
|
|
{
|
2024-01-15 23:04:25 +01:00
|
|
|
if (!s_bSoundStarted) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
openal.chan_trig_music.stop();
|
2024-08-05 19:09:29 +02:00
|
|
|
// Fixed in OPM
|
|
|
|
// Make sure to clear the triggered music in case snd_restart is called
|
|
|
|
openal.tm_filename[0] = 0;
|
|
|
|
openal.tm_loopcount = 0;
|
2024-01-07 19:47:58 +01:00
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
S_TriggeredMusic_Pause
|
|
|
|
==============
|
|
|
|
*/
|
2024-01-07 19:47:58 +01:00
|
|
|
void S_TriggeredMusic_Pause()
|
|
|
|
{
|
2024-01-15 23:04:25 +01:00
|
|
|
if (!s_bSoundStarted) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (openal.chan_trig_music.is_playing()) {
|
|
|
|
openal.chan_trig_music.pause();
|
|
|
|
}
|
2024-01-07 19:47:58 +01:00
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
S_TriggeredMusic_Unpause
|
|
|
|
==============
|
|
|
|
*/
|
2024-01-07 19:47:58 +01:00
|
|
|
void S_TriggeredMusic_Unpause()
|
|
|
|
{
|
2024-01-15 23:04:25 +01:00
|
|
|
if (!s_bSoundStarted) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (openal.chan_trig_music.is_paused()) {
|
|
|
|
openal.chan_trig_music.play();
|
|
|
|
}
|
|
|
|
|
2024-07-01 16:46:47 +02:00
|
|
|
openal.chan_trig_music.set_gain(S_GetBaseVolume() * (openal.chan_trig_music.fVolume * s_musicVolume->value) * s_fVolumeGain);
|
2024-01-07 19:47:58 +01:00
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
S_TriggeredMusic_PlayIntroMusic
|
|
|
|
==============
|
|
|
|
*/
|
2024-01-07 19:47:58 +01:00
|
|
|
void S_TriggeredMusic_PlayIntroMusic()
|
|
|
|
{
|
2024-01-15 23:04:25 +01:00
|
|
|
S_TriggeredMusic_SetupHandle("sound/music/mus_MainTheme.mp3", 0, 0, true);
|
2024-01-07 19:47:58 +01:00
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
S_StopMovieAudio
|
|
|
|
==============
|
|
|
|
*/
|
2024-01-07 19:47:58 +01:00
|
|
|
void S_StopMovieAudio()
|
|
|
|
{
|
2024-01-15 23:04:25 +01:00
|
|
|
STUB_DESC("sound stuff.");
|
2024-01-07 19:47:58 +01:00
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
S_SetupMovieAudio
|
|
|
|
==============
|
|
|
|
*/
|
2024-01-07 19:47:58 +01:00
|
|
|
void S_SetupMovieAudio(const char *pszMovieName)
|
|
|
|
{
|
2024-01-15 23:04:25 +01:00
|
|
|
STUB_DESC("sound stuff");
|
2024-01-07 19:47:58 +01:00
|
|
|
}
|
|
|
|
|
2024-01-15 23:04:25 +01:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
S_CurrentMoviePosition
|
|
|
|
==============
|
|
|
|
*/
|
2024-01-07 19:47:58 +01:00
|
|
|
int S_CurrentMoviePosition()
|
|
|
|
{
|
2024-01-15 23:04:25 +01:00
|
|
|
STUB_DESC("sound stuff");
|
2024-01-07 19:47:58 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2024-01-16 20:54:41 +01:00
|
|
|
/*
|
|
|
|
=================
|
|
|
|
S_AL_Format
|
|
|
|
=================
|
|
|
|
*/
|
|
|
|
static ALuint S_OPENAL_Format(int width, int channels)
|
|
|
|
{
|
|
|
|
ALuint format = AL_FORMAT_MONO16;
|
|
|
|
|
|
|
|
// Work out format
|
2024-01-17 20:44:32 +01:00
|
|
|
if (width == 1) {
|
|
|
|
if (channels == 1) {
|
2024-01-16 20:54:41 +01:00
|
|
|
format = AL_FORMAT_MONO8;
|
2024-01-17 20:44:32 +01:00
|
|
|
} else if (channels == 2) {
|
2024-01-16 20:54:41 +01:00
|
|
|
format = AL_FORMAT_STEREO8;
|
2024-01-17 20:44:32 +01:00
|
|
|
}
|
|
|
|
} else if (width == 2) {
|
|
|
|
if (channels == 1) {
|
2024-01-16 20:54:41 +01:00
|
|
|
format = AL_FORMAT_MONO16;
|
2024-01-17 20:44:32 +01:00
|
|
|
} else if (channels == 2) {
|
2024-01-16 20:54:41 +01:00
|
|
|
format = AL_FORMAT_STEREO16;
|
2024-01-17 20:44:32 +01:00
|
|
|
}
|
2024-01-16 20:54:41 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return format;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
S_OPENAL_LoadMP3_Codec
|
|
|
|
==============
|
|
|
|
*/
|
2024-07-01 18:00:15 +02:00
|
|
|
static bool S_OPENAL_LoadMP3_Codec(const char *_path, sfx_t* pSfx)
|
2024-01-17 20:44:32 +01:00
|
|
|
{
|
|
|
|
void *data;
|
2024-01-16 20:54:41 +01:00
|
|
|
snd_info_t info;
|
2024-01-17 20:44:32 +01:00
|
|
|
ALuint format;
|
2024-01-16 20:54:41 +01:00
|
|
|
|
|
|
|
// Try to load
|
|
|
|
data = S_CodecLoad(_path, &info);
|
|
|
|
if (!data) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
format = S_OPENAL_Format(info.width, info.channels);
|
|
|
|
|
|
|
|
// Create a buffer
|
2024-07-01 18:00:15 +02:00
|
|
|
qalGenBuffers(1, &pSfx->buffer);
|
2024-01-16 20:54:41 +01:00
|
|
|
alDieIfError();
|
|
|
|
|
|
|
|
// Fill the buffer
|
2024-01-17 20:44:32 +01:00
|
|
|
if (info.size == 0) {
|
2024-01-16 20:54:41 +01:00
|
|
|
// We have no data to buffer, so buffer silence
|
2024-01-17 20:44:32 +01:00
|
|
|
byte dummyData[2] = {0};
|
2024-01-16 20:54:41 +01:00
|
|
|
|
2024-07-01 18:00:15 +02:00
|
|
|
qalBufferData(pSfx->buffer, AL_FORMAT_MONO16, (void *)dummyData, 2, 22050);
|
2024-01-17 20:44:32 +01:00
|
|
|
} else {
|
2024-07-01 18:00:15 +02:00
|
|
|
qalBufferData(pSfx->buffer, format, data, info.size, info.rate);
|
2024-01-16 20:54:41 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
alDieIfError();
|
|
|
|
|
|
|
|
// Free the memory
|
|
|
|
Hunk_FreeTempMemory(data);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
2024-08-12 20:25:04 +02:00
|
|
|
|
|
|
|
void openal_channel::update()
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void openal_channel_two_d_stream::stop()
|
|
|
|
{
|
|
|
|
openal_channel::stop();
|
|
|
|
|
|
|
|
clear_stream();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool openal_channel_two_d_stream::set_sfx(sfx_t* pSfx) {
|
|
|
|
ALint freq = 0;
|
|
|
|
snd_stream_t* stream;
|
|
|
|
int bytesToRead = 0;
|
|
|
|
int bytesRead;
|
|
|
|
char rawData[MAX_BUFFER_SAMPLES * 2 * 2];
|
|
|
|
|
|
|
|
assert(!pSfx->buffer);
|
|
|
|
|
|
|
|
stop();
|
|
|
|
|
|
|
|
sampleLoopCount = 1;
|
|
|
|
|
|
|
|
this->pSfx = pSfx;
|
|
|
|
Q_strncpyz(this->fileName, pSfx->name, sizeof(this->fileName));
|
|
|
|
|
|
|
|
streamHandle = S_CodecLoad(pSfx->name, NULL);
|
|
|
|
if (!streamHandle) {
|
|
|
|
qalDeleteBuffers(1, &pSfx->buffer);
|
|
|
|
alDieIfError();
|
|
|
|
|
|
|
|
Com_Printf("OpenAL: Failed to load MP3.\n");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
stream = (snd_stream_t*)streamHandle;
|
|
|
|
pSfx->info.channels = stream->info.channels;
|
|
|
|
pSfx->info.dataofs = stream->info.dataofs;
|
|
|
|
pSfx->info.datasize = stream->info.size;
|
|
|
|
pSfx->info.rate = stream->info.rate;
|
|
|
|
pSfx->info.samples = stream->info.samples;
|
|
|
|
pSfx->info.width = stream->info.width;
|
|
|
|
|
|
|
|
pSfx->info.format = S_OPENAL_Format(stream->info.width, stream->info.channels);
|
|
|
|
if (!pSfx->info.format) {
|
|
|
|
Com_Printf(
|
|
|
|
"OpenAL: Bad Wave file (%d channels, %d bits) [%s].\n",
|
|
|
|
pSfx->info.channels,
|
|
|
|
(int)(pSfx->info.width * 8.f),
|
|
|
|
pSfx->name
|
|
|
|
);
|
|
|
|
|
|
|
|
S_CodecCloseStream(stream);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
qalGenBuffers(MAX_STREAM_BUFFERS, buffers);
|
|
|
|
alDieIfError();
|
|
|
|
|
|
|
|
// Read a smaller sample
|
|
|
|
bytesToRead = Q_min(stream->info.width * stream->info.channels * (MAX_BUFFER_SAMPLES / 2), sizeof(rawData));
|
|
|
|
bytesRead = S_CodecReadStream(stream, bytesToRead, rawData);
|
|
|
|
if (!bytesRead) {
|
|
|
|
// Valid stream but no data?
|
|
|
|
S_CodecCloseStream(stream);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
qalBufferData(buffers[currentBuf], pSfx->info.format, rawData, bytesRead, stream->info.rate);
|
|
|
|
alDieIfError();
|
|
|
|
|
|
|
|
qalSourceQueueBuffers(source, 1, &buffers[currentBuf]);
|
|
|
|
alDieIfError();
|
|
|
|
|
|
|
|
qalSourceStop(source);
|
|
|
|
alDieIfError();
|
|
|
|
|
|
|
|
iBaseRate = stream->info.rate;
|
|
|
|
currentBuf = (currentBuf + 1) % MAX_STREAM_BUFFERS;
|
|
|
|
streaming = true;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void openal_channel_two_d_stream::set_sample_loop_count(S32 count)
|
|
|
|
{
|
|
|
|
sampleLoopCount = count;
|
|
|
|
sampleLooped = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
openal_channel_two_d_stream::openal_channel_two_d_stream() {
|
|
|
|
int i;
|
|
|
|
|
|
|
|
streamHandle = NULL;
|
|
|
|
for (i = 0; i < MAX_STREAM_BUFFERS; i++) {
|
|
|
|
buffers[i] = 0;
|
|
|
|
}
|
|
|
|
currentBuf = 0;
|
|
|
|
sampleLoopCount = 0;
|
|
|
|
sampleLooped = 0;
|
|
|
|
streaming = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void openal_channel_two_d_stream::update()
|
|
|
|
{
|
|
|
|
snd_stream_t* stream = (snd_stream_t*)streamHandle;
|
|
|
|
int bytesToRead, bytesRead;
|
|
|
|
ALuint format;
|
|
|
|
ALint numProcessedBuffers = 0;
|
|
|
|
ALint numQueuedBuffers = 0;
|
|
|
|
ALint state = get_state();
|
|
|
|
// 2 channels with a width of 2
|
|
|
|
char rawData[MAX_BUFFER_SAMPLES * 2 * 2];
|
|
|
|
|
|
|
|
if (!streaming) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
qalGetSourcei(source, AL_BUFFERS_PROCESSED, &numProcessedBuffers);
|
|
|
|
alDieIfError();
|
|
|
|
|
|
|
|
qalGetSourcei(source, AL_BUFFERS_QUEUED, &numQueuedBuffers);
|
|
|
|
alDieIfError();
|
|
|
|
|
|
|
|
// Unqueue processed buffers
|
|
|
|
while (numProcessedBuffers-- > 0) {
|
|
|
|
ALuint tmpBuffer;
|
|
|
|
qalSourceUnqueueBuffers(source, 1, &tmpBuffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (numQueuedBuffers >= MAX_STREAM_BUFFERS) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sampleLoopCount && sampleLooped >= sampleLoopCount) {
|
|
|
|
if (!is_playing()) {
|
|
|
|
// Can clear the stream
|
|
|
|
clear_stream();
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
bytesToRead = Q_min(stream->info.width * stream->info.channels * MAX_BUFFER_SAMPLES, sizeof(rawData));
|
|
|
|
|
|
|
|
format = S_OPENAL_Format(stream->info.width, stream->info.channels);
|
|
|
|
|
|
|
|
bytesRead = S_CodecReadStream(stream, bytesToRead, rawData);
|
|
|
|
if (!bytesRead) {
|
|
|
|
S_CodecCloseStream(stream);
|
|
|
|
|
|
|
|
sampleLooped++;
|
|
|
|
if (sampleLoopCount && sampleLooped >= sampleLoopCount) {
|
|
|
|
// Finished the last loop
|
|
|
|
streamHandle = NULL;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
streamHandle = S_CodecLoad(this->fileName, NULL);
|
|
|
|
if (!streamHandle) {
|
|
|
|
clear_stream();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
stream = (snd_stream_t*)streamHandle;
|
|
|
|
//
|
|
|
|
// Re-read the format, we never know...
|
|
|
|
//
|
|
|
|
format = S_OPENAL_Format(stream->info.width, stream->info.channels);
|
|
|
|
bytesRead = S_CodecReadStream(stream, bytesToRead, rawData);
|
|
|
|
if (!bytesRead) {
|
|
|
|
S_CodecCloseStream(stream);
|
|
|
|
streamHandle = NULL;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
qalBufferData(buffers[currentBuf], format, rawData, bytesRead, stream->info.rate);
|
|
|
|
alDieIfError();
|
|
|
|
|
|
|
|
qalSourceQueueBuffers(source, 1, &buffers[currentBuf]);
|
|
|
|
alDieIfError();
|
|
|
|
|
2024-08-17 11:09:35 +02:00
|
|
|
if (!is_playing()) {
|
|
|
|
// The sample has stopped during stream
|
|
|
|
// Could be because the storage is slow enough for the buffer
|
|
|
|
// or because the storage was powering on after standby
|
|
|
|
play();
|
|
|
|
}
|
|
|
|
|
2024-08-12 20:25:04 +02:00
|
|
|
currentBuf = (currentBuf + 1) % MAX_STREAM_BUFFERS;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool openal_channel_two_d_stream::queue_stream(const char* fileName) {
|
|
|
|
|
|
|
|
ALint freq = 0;
|
|
|
|
ALuint format = 0;
|
|
|
|
snd_stream_t* stream;
|
|
|
|
int bytesToRead = 0;
|
|
|
|
int bytesRead;
|
|
|
|
ALuint old = 0;
|
|
|
|
int i;
|
|
|
|
char rawData[MAX_BUFFER_SAMPLES * 2 * 2];
|
|
|
|
|
|
|
|
// Store the filename so it can be looped later
|
|
|
|
Q_strncpyz(this->fileName, fileName, sizeof(this->fileName));
|
|
|
|
clear_stream();
|
|
|
|
|
|
|
|
sampleLoopCount = 1;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Load the file
|
|
|
|
//
|
|
|
|
streamHandle = S_CodecLoad(this->fileName, NULL);
|
|
|
|
if (!streamHandle) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
stream = (snd_stream_t*)streamHandle;
|
|
|
|
|
|
|
|
iStartTime = cl.serverTime;
|
|
|
|
iEndTime = (int)(cl.serverTime + (stream->info.samples / stream->info.rate * 1000.f));
|
|
|
|
|
|
|
|
format = S_OPENAL_Format(stream->info.width, stream->info.channels);
|
|
|
|
if (!format) {
|
|
|
|
Com_Printf(
|
|
|
|
"OpenAL: Bad Wave file (%d channels, %d bits) [%s].\n",
|
|
|
|
pSfx->info.channels,
|
|
|
|
(int)(pSfx->info.width * 8.f),
|
|
|
|
pSfx->name
|
|
|
|
);
|
|
|
|
|
|
|
|
S_CodecCloseStream(stream);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
qalGenBuffers(MAX_STREAM_BUFFERS, buffers);
|
|
|
|
alDieIfError();
|
|
|
|
|
|
|
|
// Read a smaller sample
|
|
|
|
bytesToRead = Q_min(stream->info.width * stream->info.channels * (MAX_BUFFER_SAMPLES / 2), sizeof(rawData));
|
|
|
|
bytesRead = S_CodecReadStream(stream, bytesToRead, rawData);
|
|
|
|
if (!bytesRead) {
|
|
|
|
// Valid stream but no data?
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
qalBufferData(buffers[currentBuf], format, rawData, bytesRead, stream->info.rate);
|
|
|
|
alDieIfError();
|
|
|
|
|
|
|
|
qalSourceQueueBuffers(source, 1, &buffers[currentBuf]);
|
|
|
|
alDieIfError();
|
|
|
|
|
|
|
|
currentBuf = (currentBuf + 1) % MAX_STREAM_BUFFERS;
|
|
|
|
|
|
|
|
streaming = true;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void openal_channel_two_d_stream::clear_stream() {
|
|
|
|
if (!streaming) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
qalSourceStop(source);
|
|
|
|
qalSourcei(source, AL_BUFFER, 0);
|
|
|
|
qalSourceUnqueueBuffers(source, MAX_STREAM_BUFFERS, buffers);
|
|
|
|
qalDeleteBuffers(1, buffers);
|
|
|
|
|
|
|
|
if (streamHandle) {
|
|
|
|
S_CodecCloseStream((snd_stream_t*)streamHandle);
|
|
|
|
}
|
|
|
|
|
|
|
|
fileName[0] = 0;
|
|
|
|
streamHandle = NULL;
|
|
|
|
|
|
|
|
currentBuf = 0;
|
|
|
|
streaming = false;
|
|
|
|
sampleLooped = 0;
|
|
|
|
}
|