2006-04-13 20:47:06 +00:00
|
|
|
//-------------------------------------------------------------------------
|
|
|
|
/*
|
2016-02-07 02:38:03 +00:00
|
|
|
Copyright (C) 2016 EDuke32 developers and contributors
|
2006-04-13 20:47:06 +00:00
|
|
|
|
2010-05-25 10:56:00 +00:00
|
|
|
This file is part of EDuke32.
|
2006-04-13 20:47:06 +00:00
|
|
|
|
|
|
|
EDuke32 is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU General Public License version 2
|
|
|
|
as published by the Free Software Foundation.
|
|
|
|
|
|
|
|
This program 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 this program; if not, write to the Free Software
|
2014-07-20 08:55:56 +00:00
|
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
2006-04-13 20:47:06 +00:00
|
|
|
*/
|
|
|
|
//-------------------------------------------------------------------------
|
|
|
|
|
2019-09-21 18:59:54 +00:00
|
|
|
#include "ns.h" // Must come before everything else!
|
|
|
|
|
2017-02-25 08:15:45 +00:00
|
|
|
#include "compat.h"
|
2012-11-05 02:49:08 +00:00
|
|
|
|
2006-04-13 20:47:06 +00:00
|
|
|
#include "duke3d.h"
|
2016-02-07 02:38:03 +00:00
|
|
|
#include "renderlayer.h" // for win_gethwnd()
|
2019-10-19 23:48:20 +00:00
|
|
|
#include "al_midi.h"
|
2019-11-01 21:17:15 +00:00
|
|
|
#include "openaudio.h"
|
2019-11-10 22:58:51 +00:00
|
|
|
#include "z_music.h"
|
2019-12-09 23:01:45 +00:00
|
|
|
#include "mapinfo.h"
|
2019-12-12 20:42:58 +00:00
|
|
|
#include "sound/s_soundinternal.h"
|
2018-04-21 06:04:56 +00:00
|
|
|
#include <atomic>
|
2010-07-19 15:14:00 +00:00
|
|
|
|
2019-09-21 20:53:00 +00:00
|
|
|
BEGIN_DUKE_NS
|
|
|
|
|
|
|
|
|
2019-01-12 00:21:58 +00:00
|
|
|
#define DQSIZE 256
|
2015-02-11 05:22:00 +00:00
|
|
|
|
2019-08-07 22:44:29 +00:00
|
|
|
int32_t g_numEnvSoundsPlaying, g_highestSoundIdx;
|
2006-04-13 20:47:06 +00:00
|
|
|
|
2019-08-07 22:44:29 +00:00
|
|
|
static char *MusicPtr;
|
|
|
|
|
|
|
|
static int32_t MusicIsWaveform;
|
2009-07-27 05:33:12 +00:00
|
|
|
static int32_t MusicVoice = -1;
|
|
|
|
|
2019-08-07 22:44:29 +00:00
|
|
|
static bool MusicPaused;
|
|
|
|
static bool SoundPaused;
|
|
|
|
|
2019-08-09 09:28:42 +00:00
|
|
|
static std::atomic<uint32_t> dnum, dq[DQSIZE];
|
|
|
|
static mutex_t m_callback;
|
2010-06-22 21:50:01 +00:00
|
|
|
|
2019-08-07 22:44:20 +00:00
|
|
|
static inline void S_SetProperties(assvoice_t *snd, int const owner, int const voice, int const dist, int const clock)
|
|
|
|
{
|
|
|
|
snd->owner = owner;
|
|
|
|
snd->id = voice;
|
|
|
|
snd->dist = dist;
|
|
|
|
snd->clock = clock;
|
|
|
|
}
|
|
|
|
|
2008-11-20 14:06:36 +00:00
|
|
|
void S_SoundStartup(void)
|
2006-04-16 03:42:36 +00:00
|
|
|
{
|
2019-10-19 23:47:54 +00:00
|
|
|
#ifdef _WIN32
|
2018-10-16 06:08:50 +00:00
|
|
|
void *initdata = (void *) win_gethwnd(); // used for DirectSound
|
|
|
|
#else
|
|
|
|
void *initdata = NULL;
|
2009-07-27 05:33:12 +00:00
|
|
|
#endif
|
2009-07-09 02:29:48 +00:00
|
|
|
|
Patch from Hendricks266 and whatever changes happened to be in my tree. I hope they work ;)
"The most noticeable change is the addition of the "includedefault" CON and DEF command, which will attempt to include eduke.con (or nam.con, or ww2gi.con), then game.con, or duke3d.def, or nam.def, or ww2gi.def. This is useful for TCs like my add-ons, where for my pseudo-mutators I currently say "include EDUKE.CON", but I also have to juggle this terrible order of paths, so that I can have an EDUKE.CON file in my HRP which says "include GAME.CON" to allow the mainline game to actually run, but also allow DukePlus to load its EDUKE.CON file (since it uses that and not an -x switch), and also allow any custom EDUKE.CON files in the root to be used."
git-svn-id: https://svn.eduke32.com/eduke32@1909 1a8010ca-5511-0410-912e-c29ae57300e0
2011-06-19 00:11:52 +00:00
|
|
|
initprintf("Initializing sound... ");
|
2009-08-06 10:12:13 +00:00
|
|
|
|
2019-10-24 18:28:46 +00:00
|
|
|
int status = FX_Init(snd_numvoices, snd_numchannels, snd_mixrate, initdata);
|
2019-10-24 05:47:24 +00:00
|
|
|
if (status != FX_Ok)
|
2006-11-15 01:16:55 +00:00
|
|
|
{
|
2019-10-24 05:47:24 +00:00
|
|
|
initprintf("failed! %s\n", FX_ErrorString(status));
|
2011-01-23 04:59:04 +00:00
|
|
|
return;
|
2006-04-16 03:42:36 +00:00
|
|
|
}
|
2009-07-27 05:33:12 +00:00
|
|
|
|
2019-10-22 15:47:24 +00:00
|
|
|
initprintf("%d voices, %d channels, 16-bit %d Hz\n", *snd_numvoices, *snd_numchannels, *snd_mixrate);
|
Patch from Hendricks266 and whatever changes happened to be in my tree. I hope they work ;)
"The most noticeable change is the addition of the "includedefault" CON and DEF command, which will attempt to include eduke.con (or nam.con, or ww2gi.con), then game.con, or duke3d.def, or nam.def, or ww2gi.def. This is useful for TCs like my add-ons, where for my pseudo-mutators I currently say "include EDUKE.CON", but I also have to juggle this terrible order of paths, so that I can have an EDUKE.CON file in my HRP which says "include GAME.CON" to allow the mainline game to actually run, but also allow DukePlus to load its EDUKE.CON file (since it uses that and not an -x switch), and also allow any custom EDUKE.CON files in the root to be used."
git-svn-id: https://svn.eduke32.com/eduke32@1909 1a8010ca-5511-0410-912e-c29ae57300e0
2011-06-19 00:11:52 +00:00
|
|
|
|
2018-10-25 23:32:29 +00:00
|
|
|
for (int i = 0; i <= g_highestSoundIdx; ++i)
|
2010-08-02 08:13:51 +00:00
|
|
|
{
|
2018-10-25 23:32:29 +00:00
|
|
|
for (auto & voice : g_sounds[i].voices)
|
2010-08-02 08:13:51 +00:00
|
|
|
{
|
2018-10-25 23:32:29 +00:00
|
|
|
g_sounds[i].num = 0;
|
2019-08-07 22:44:20 +00:00
|
|
|
S_SetProperties(&voice, -1, 0, UINT16_MAX, 0);
|
2010-08-02 08:13:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-22 00:01:05 +00:00
|
|
|
snd_fxvolume.Callback();
|
2014-02-01 16:19:58 +00:00
|
|
|
|
2019-10-22 00:01:05 +00:00
|
|
|
snd_reversestereo.Callback();
|
2010-03-01 09:09:26 +00:00
|
|
|
FX_SetCallBack(S_Callback);
|
2019-01-12 00:21:58 +00:00
|
|
|
FX_SetPrintf(OSD_Printf);
|
2006-04-16 03:42:36 +00:00
|
|
|
}
|
2006-04-13 20:47:06 +00:00
|
|
|
|
2008-11-20 14:06:36 +00:00
|
|
|
void S_SoundShutdown(void)
|
2006-04-16 03:42:36 +00:00
|
|
|
{
|
2019-10-24 05:47:24 +00:00
|
|
|
int status = FX_Shutdown();
|
|
|
|
if (status != FX_Ok)
|
2006-11-15 01:16:55 +00:00
|
|
|
{
|
2019-10-24 05:47:24 +00:00
|
|
|
Bsprintf(tempbuf, "S_SoundShutdown(): error: %s", FX_ErrorString(status));
|
2008-11-20 14:06:36 +00:00
|
|
|
G_GameExit(tempbuf);
|
2006-04-16 03:42:36 +00:00
|
|
|
}
|
|
|
|
}
|
2006-04-13 20:47:06 +00:00
|
|
|
|
2018-10-25 23:32:29 +00:00
|
|
|
void S_PauseSounds(bool paused)
|
2016-02-02 06:39:22 +00:00
|
|
|
{
|
2018-10-25 23:32:29 +00:00
|
|
|
if (SoundPaused == paused)
|
2016-02-02 06:39:22 +00:00
|
|
|
return;
|
|
|
|
|
2018-10-25 23:32:29 +00:00
|
|
|
SoundPaused = paused;
|
2016-02-02 06:39:22 +00:00
|
|
|
|
2018-10-25 23:32:29 +00:00
|
|
|
for (int i = 0; i <= g_highestSoundIdx; ++i)
|
2016-02-02 06:39:22 +00:00
|
|
|
{
|
2018-10-25 23:32:29 +00:00
|
|
|
for (auto & voice : g_sounds[i].voices)
|
|
|
|
if (voice.id > 0)
|
|
|
|
FX_PauseVoice(voice.id, paused);
|
2016-02-02 06:39:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-06-22 21:50:01 +00:00
|
|
|
void S_Cleanup(void)
|
|
|
|
{
|
2019-08-07 22:44:29 +00:00
|
|
|
static uint32_t ldnum = 0;
|
2010-06-22 21:50:01 +00:00
|
|
|
|
2019-01-12 00:21:58 +00:00
|
|
|
while (ldnum < dnum)
|
2010-06-22 21:50:01 +00:00
|
|
|
{
|
2018-04-21 06:04:56 +00:00
|
|
|
uint32_t num = dq[ldnum++ & (DQSIZE - 1)];
|
2010-06-22 21:50:01 +00:00
|
|
|
|
|
|
|
// negative index is RTS playback
|
|
|
|
if ((int32_t)num < 0)
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2011-10-30 19:48:46 +00:00
|
|
|
// num + (MAXSOUNDS*MAXSOUNDINSTANCES) is a sound played globally
|
|
|
|
// for which there was no open slot to keep track of the voice
|
|
|
|
if (num >= (MAXSOUNDS*MAXSOUNDINSTANCES))
|
2011-05-28 14:15:41 +00:00
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2019-08-07 22:44:29 +00:00
|
|
|
int const voiceindex = num & (MAXSOUNDINSTANCES - 1);
|
2010-07-03 08:53:57 +00:00
|
|
|
|
2019-08-07 22:44:29 +00:00
|
|
|
num = (num - voiceindex) / MAXSOUNDINSTANCES;
|
2010-06-22 21:50:01 +00:00
|
|
|
|
2018-10-25 23:32:29 +00:00
|
|
|
auto &snd = g_sounds[num];
|
2019-08-07 22:44:29 +00:00
|
|
|
auto &voice = snd.voices[voiceindex];
|
2010-07-03 08:53:57 +00:00
|
|
|
|
2018-10-25 23:32:29 +00:00
|
|
|
int const spriteNum = voice.owner;
|
2010-06-22 21:50:01 +00:00
|
|
|
|
2018-05-04 22:42:37 +00:00
|
|
|
if (EDUKE32_PREDICT_FALSE(snd.num > MAXSOUNDINSTANCES))
|
|
|
|
OSD_Printf(OSD_ERROR "S_Cleanup(): num exceeds MAXSOUNDINSTANCES! g_sounds[%d].num %d wtf?\n", num, snd.num);
|
2019-08-07 22:44:29 +00:00
|
|
|
else if (snd.num > 0)
|
2018-10-25 23:32:29 +00:00
|
|
|
--snd.num;
|
2010-06-22 21:50:01 +00:00
|
|
|
|
2015-02-11 05:22:00 +00:00
|
|
|
// MUSICANDSFX uses t_data[0] to control restarting the sound
|
|
|
|
// CLEAR_SOUND_T0
|
2018-05-04 22:42:37 +00:00
|
|
|
if (spriteNum != -1 && S_IsAmbientSFX(spriteNum) && sector[SECT(spriteNum)].lotag < 3) // ST_2_UNDERWATER
|
|
|
|
actor[spriteNum].t_data[0] = 0;
|
2015-02-11 05:22:00 +00:00
|
|
|
|
2019-08-07 22:44:20 +00:00
|
|
|
S_SetProperties(&voice, -1, 0, UINT16_MAX, 0);
|
2010-06-22 21:50:01 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-03-01 09:09:26 +00:00
|
|
|
// returns number of bytes read
|
2018-10-25 23:32:29 +00:00
|
|
|
int32_t S_LoadSound(int num)
|
2006-04-13 20:47:06 +00:00
|
|
|
{
|
2018-10-25 23:32:29 +00:00
|
|
|
if ((unsigned)num > (unsigned)g_highestSoundIdx || EDUKE32_PREDICT_FALSE(g_sounds[num].filename == NULL))
|
2008-01-26 03:59:34 +00:00
|
|
|
return 0;
|
|
|
|
|
2018-10-25 23:32:29 +00:00
|
|
|
auto &snd = g_sounds[num];
|
|
|
|
|
2019-11-01 21:17:15 +00:00
|
|
|
auto fp = S_OpenAudio(snd.filename, 0, 0);
|
2018-04-02 22:00:11 +00:00
|
|
|
|
2019-10-20 21:37:07 +00:00
|
|
|
if (!fp.isOpen())
|
2006-04-13 20:47:06 +00:00
|
|
|
{
|
2018-10-25 23:32:29 +00:00
|
|
|
OSD_Printf(OSDTEXT_RED "Sound %s(#%d) not found!\n", snd.filename, num);
|
2015-11-25 12:08:04 +00:00
|
|
|
return 0;
|
2006-04-13 20:47:06 +00:00
|
|
|
}
|
|
|
|
|
2019-10-20 21:37:07 +00:00
|
|
|
int32_t l = fp.GetLength();
|
2018-10-25 23:32:29 +00:00
|
|
|
snd.siz = l;
|
2019-11-28 01:36:34 +00:00
|
|
|
cacheAllocateBlock((intptr_t *)&snd.ptr, l, nullptr);
|
2019-10-20 21:37:07 +00:00
|
|
|
l = fp.Read(snd.ptr, l);
|
2010-01-05 21:53:14 +00:00
|
|
|
|
2010-03-01 09:09:26 +00:00
|
|
|
return l;
|
2006-04-13 20:47:06 +00:00
|
|
|
}
|
|
|
|
|
2018-11-18 18:08:14 +00:00
|
|
|
void cacheAllSounds(void)
|
2018-04-02 22:00:11 +00:00
|
|
|
{
|
2019-08-07 22:44:29 +00:00
|
|
|
for (int i=0, j=0; i <= g_highestSoundIdx; ++i)
|
|
|
|
{
|
2018-04-02 22:00:11 +00:00
|
|
|
if (g_sounds[i].ptr == 0)
|
|
|
|
{
|
|
|
|
j++;
|
|
|
|
if ((j&7) == 0)
|
2019-10-19 23:41:40 +00:00
|
|
|
gameHandleEvents();
|
2018-04-02 22:00:11 +00:00
|
|
|
|
|
|
|
S_LoadSound(i);
|
|
|
|
}
|
2019-08-07 22:44:29 +00:00
|
|
|
}
|
2018-04-02 22:00:11 +00:00
|
|
|
}
|
2012-08-13 18:25:48 +00:00
|
|
|
|
2018-10-25 23:32:29 +00:00
|
|
|
static inline int S_GetPitch(int num)
|
2012-08-13 18:25:48 +00:00
|
|
|
{
|
2018-10-25 23:32:29 +00:00
|
|
|
auto const &snd = g_sounds[num];
|
|
|
|
int const range = klabs(snd.pe - snd.ps);
|
|
|
|
|
|
|
|
return (range == 0) ? snd.ps : min(snd.ps, snd.pe) + rand() % range;
|
2012-08-13 18:25:48 +00:00
|
|
|
}
|
|
|
|
|
2018-10-25 23:32:29 +00:00
|
|
|
static int S_TakeSlot(int soundNum)
|
2012-08-13 18:25:48 +00:00
|
|
|
{
|
2015-02-11 05:22:00 +00:00
|
|
|
S_Cleanup();
|
|
|
|
|
2018-10-25 23:32:29 +00:00
|
|
|
uint16_t dist = 0;
|
|
|
|
uint16_t clock = 0;
|
|
|
|
|
|
|
|
int bestslot = 0;
|
|
|
|
int slot = 0;
|
2012-08-13 18:25:48 +00:00
|
|
|
|
2018-10-25 23:32:29 +00:00
|
|
|
auto &snd = g_sounds[soundNum];
|
|
|
|
|
|
|
|
while (slot < MAXSOUNDINSTANCES && snd.voices[slot].id > 0)
|
2012-10-08 07:07:59 +00:00
|
|
|
{
|
2018-10-25 23:32:29 +00:00
|
|
|
auto &voice = snd.voices[slot];
|
|
|
|
|
|
|
|
if (voice.dist > dist || (voice.dist == dist && voice.clock > clock))
|
2012-10-08 07:07:59 +00:00
|
|
|
{
|
2018-10-25 23:32:29 +00:00
|
|
|
clock = voice.clock;
|
|
|
|
dist = voice.dist;
|
|
|
|
|
|
|
|
bestslot = slot;
|
2012-10-08 07:07:59 +00:00
|
|
|
}
|
|
|
|
|
2018-10-25 23:32:29 +00:00
|
|
|
slot++;
|
2012-10-08 07:07:59 +00:00
|
|
|
}
|
2012-08-13 18:25:48 +00:00
|
|
|
|
2018-10-25 23:32:29 +00:00
|
|
|
if (slot != MAXSOUNDINSTANCES)
|
|
|
|
return slot;
|
2012-10-08 07:07:17 +00:00
|
|
|
|
2018-10-25 23:32:29 +00:00
|
|
|
if (FX_SoundActive(snd.voices[bestslot].id))
|
|
|
|
FX_StopSound(snd.voices[bestslot].id);
|
2012-10-08 07:07:17 +00:00
|
|
|
|
2019-08-09 09:28:42 +00:00
|
|
|
mutex_lock(&m_callback);
|
|
|
|
unative_t const ldnum = dnum;
|
|
|
|
dq[ldnum & (DQSIZE-1)] = (soundNum * MAXSOUNDINSTANCES) + bestslot;
|
|
|
|
dnum++;
|
|
|
|
mutex_unlock(&m_callback);
|
|
|
|
|
2012-10-08 07:07:59 +00:00
|
|
|
S_Cleanup();
|
2012-10-08 07:07:17 +00:00
|
|
|
|
2018-10-25 23:32:29 +00:00
|
|
|
return bestslot;
|
2012-10-08 07:07:59 +00:00
|
|
|
}
|
2012-10-08 07:07:17 +00:00
|
|
|
|
2018-10-25 23:32:29 +00:00
|
|
|
static int S_GetSlot(int soundNum)
|
2012-10-08 07:07:59 +00:00
|
|
|
{
|
2018-10-25 23:32:29 +00:00
|
|
|
int slot = 0;
|
2012-10-08 07:07:17 +00:00
|
|
|
|
2018-10-25 23:32:29 +00:00
|
|
|
while (slot < MAXSOUNDINSTANCES && g_sounds[soundNum].voices[slot].id > 0)
|
|
|
|
slot++;
|
2012-10-08 07:07:17 +00:00
|
|
|
|
2018-10-25 23:32:29 +00:00
|
|
|
return slot == MAXSOUNDINSTANCES ? S_TakeSlot(soundNum) : slot;
|
2012-08-13 18:25:48 +00:00
|
|
|
}
|
|
|
|
|
2018-10-25 23:32:29 +00:00
|
|
|
static inline int S_GetAngle(int ang, const vec3_t *cam, const vec3_t *pos)
|
2012-08-13 18:25:53 +00:00
|
|
|
{
|
2018-10-25 23:32:29 +00:00
|
|
|
return (2048 + ang - getangle(cam->x - pos->x, cam->y - pos->y)) & 2047;
|
2012-08-13 18:25:53 +00:00
|
|
|
}
|
|
|
|
|
2019-12-12 20:42:58 +00:00
|
|
|
void S_Update(void)
|
|
|
|
{
|
|
|
|
if ((g_player[myconnectindex].ps->gm & (MODE_GAME|MODE_DEMO)) == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
g_numEnvSoundsPlaying = 0;
|
|
|
|
|
|
|
|
const vec3_t *c;
|
|
|
|
int32_t ca,cs;
|
|
|
|
|
|
|
|
if (ud.camerasprite == -1)
|
|
|
|
{
|
|
|
|
if (ud.overhead_on != 2)
|
|
|
|
{
|
|
|
|
c = &CAMERA(pos);
|
|
|
|
cs = CAMERA(sect);
|
|
|
|
ca = fix16_to_int(CAMERA(q16ang));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
auto pPlayer = g_player[screenpeek].ps;
|
|
|
|
c = &pPlayer->pos;
|
|
|
|
cs = pPlayer->cursectnum;
|
|
|
|
ca = fix16_to_int(pPlayer->q16ang);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
c = &sprite[ud.camerasprite].pos;
|
|
|
|
cs = sprite[ud.camerasprite].sectnum;
|
|
|
|
ca = sprite[ud.camerasprite].ang;
|
|
|
|
}
|
|
|
|
|
|
|
|
int sndnum = 0;
|
|
|
|
int const highest = g_highestSoundIdx;
|
|
|
|
|
|
|
|
do
|
|
|
|
{
|
|
|
|
if (g_sounds[sndnum].num == 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
S_Cleanup();
|
|
|
|
|
|
|
|
for (auto &voice : g_sounds[sndnum].voices)
|
|
|
|
{
|
|
|
|
int const spriteNum = voice.owner;
|
|
|
|
|
|
|
|
if ((unsigned)spriteNum >= MAXSPRITES || voice.id <= FX_Ok || !FX_SoundActive(voice.id))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
int sndist, sndang;
|
|
|
|
|
|
|
|
S_CalcDistAndAng(spriteNum, sndnum, cs, ca, c, (const vec3_t *)&sprite[spriteNum], &sndist, &sndang);
|
|
|
|
|
|
|
|
if (S_IsAmbientSFX(spriteNum))
|
|
|
|
g_numEnvSoundsPlaying++;
|
|
|
|
|
|
|
|
// AMBIENT_SOUND
|
|
|
|
FX_Pan3D(voice.id, sndang >> 4, sndist >> 6);
|
|
|
|
voice.dist = sndist >> 6;
|
|
|
|
voice.clock++;
|
|
|
|
}
|
|
|
|
} while (++sndnum <= highest);
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// With OpenAL we are only interested in how this function alters
|
|
|
|
// the distance to calculate attenuation.
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
static int S_CalcDistAndAng(int spriteNum, int soundNum, int sectNum, int angle, int* distPtr)
|
2012-08-13 18:25:51 +00:00
|
|
|
{
|
2019-08-07 22:44:29 +00:00
|
|
|
int sndang = 0, sndist = 0, explosion = 0;
|
2012-08-13 18:25:51 +00:00
|
|
|
|
2018-10-25 23:32:29 +00:00
|
|
|
if (PN(spriteNum) == APLAYER && P_Get(spriteNum) == screenpeek)
|
2012-08-13 18:25:53 +00:00
|
|
|
goto sound_further_processing;
|
|
|
|
|
2018-10-25 23:32:29 +00:00
|
|
|
sndang = S_GetAngle(angle, cam, pos);
|
2019-12-12 20:42:58 +00:00
|
|
|
sndist = FindDistance3D(cam->x - pos->x, cam->y - pos->y, (cam->z - pos->z));
|
2012-08-13 18:25:53 +00:00
|
|
|
|
2019-12-12 20:42:58 +00:00
|
|
|
if ((g_sounds[soundNum].m & (SF_GLOBAL | SF_DTAG)) != SF_GLOBAL && S_IsAmbientSFX(spriteNum) && (sector[SECT(spriteNum)].lotag & 0xff) < 9) // ST_9_SLIDING_ST_DOOR
|
|
|
|
sndist = divscale14(sndist, SHT(spriteNum) + 1);
|
2012-08-13 18:25:53 +00:00
|
|
|
|
|
|
|
sound_further_processing:
|
2018-10-25 23:32:29 +00:00
|
|
|
sndist += g_sounds[soundNum].vo;
|
2012-08-13 18:25:51 +00:00
|
|
|
if (sndist < 0)
|
|
|
|
sndist = 0;
|
|
|
|
|
2019-08-07 22:44:29 +00:00
|
|
|
if (!FURY && sectNum > -1 && sndist && PN(spriteNum) != MUSICANDSFX
|
2018-10-25 23:32:29 +00:00
|
|
|
&& !cansee(cam->x, cam->y, cam->z - (24 << 8), sectNum, SX(spriteNum), SY(spriteNum), SZ(spriteNum) - (24 << 8), SECT(spriteNum)))
|
2019-12-12 20:42:58 +00:00
|
|
|
sndist += sndist >> 5;
|
2012-08-13 18:25:51 +00:00
|
|
|
|
2019-12-12 20:42:58 +00:00
|
|
|
if ((g_sounds[soundNum].m & (SF_GLOBAL | SF_DTAG)) == (SF_GLOBAL | SF_DTAG))
|
2019-08-07 22:44:25 +00:00
|
|
|
{
|
2019-12-12 20:42:58 +00:00
|
|
|
boost:
|
2019-08-29 19:00:42 +00:00
|
|
|
int const sdist = g_sounds[soundNum].vo > 0 ? g_sounds[soundNum].vo : 6144;
|
|
|
|
|
2019-08-07 22:44:25 +00:00
|
|
|
explosion = true;
|
2019-08-29 19:00:42 +00:00
|
|
|
|
|
|
|
if (sndist > sdist)
|
|
|
|
sndist = sdist;
|
2019-08-07 22:44:25 +00:00
|
|
|
}
|
2019-08-10 13:03:31 +00:00
|
|
|
else if (!FURY)
|
2018-10-25 23:32:29 +00:00
|
|
|
{
|
2019-08-07 22:44:12 +00:00
|
|
|
switch (DYNAMICSOUNDMAP(soundNum))
|
|
|
|
{
|
2019-12-12 20:42:58 +00:00
|
|
|
case PIPEBOMB_EXPLODE__STATIC:
|
|
|
|
case LASERTRIP_EXPLODE__STATIC:
|
|
|
|
case RPG_EXPLODE__STATIC:
|
|
|
|
goto boost;
|
2019-08-07 22:44:12 +00:00
|
|
|
}
|
2012-08-13 18:25:51 +00:00
|
|
|
}
|
|
|
|
|
2019-12-12 20:42:58 +00:00
|
|
|
if ((g_sounds[soundNum].m & (SF_GLOBAL | SF_DTAG)) == SF_GLOBAL || sndist < ((255 - LOUDESTVOLUME) << 6))
|
|
|
|
sndist = ((255 - LOUDESTVOLUME) << 6);
|
2012-08-13 18:25:51 +00:00
|
|
|
|
2018-10-25 23:32:29 +00:00
|
|
|
*distPtr = sndist;
|
2019-12-12 20:42:58 +00:00
|
|
|
*angPtr = sndang;
|
2012-08-13 18:25:51 +00:00
|
|
|
|
|
|
|
return explosion;
|
|
|
|
}
|
|
|
|
|
2014-06-23 02:24:10 +00:00
|
|
|
|
2019-12-12 20:42:58 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
2014-06-23 02:24:10 +00:00
|
|
|
|
2019-12-12 20:42:58 +00:00
|
|
|
int S_PlaySound3D(int num, int spriteNum, const vec3_t* pos)
|
|
|
|
{
|
|
|
|
int32_t j = VM_OnEventWithReturn(EVENT_SOUND, spriteNum, screenpeek, num);
|
2012-05-17 17:33:29 +00:00
|
|
|
|
2019-12-12 20:42:58 +00:00
|
|
|
int sndnum = VM_OnEventWithReturn(EVENT_SOUND, spriteNum, screenpeek, num);
|
2018-05-04 22:42:37 +00:00
|
|
|
|
2019-07-08 00:41:25 +00:00
|
|
|
auto const pPlayer = g_player[myconnectindex].ps;
|
2019-12-12 20:42:58 +00:00
|
|
|
if (!soundEngine->isValidSoundId(sndnum) || !SoundEnabled() || (unsigned)spriteNum >= MAXSPRITES || (pPlayer->gm & MODE_MENU) ||
|
|
|
|
(pPlayer->timebeforeexit > 0 && pPlayer->timebeforeexit <= GAMETICSPERSEC * 3)) return -1;
|
2015-02-11 05:22:00 +00:00
|
|
|
|
2019-12-12 20:42:58 +00:00
|
|
|
int userflags = soundEngine->GetUserFlags(sndnum);
|
|
|
|
if ((!(snd_speech & 1) && (userflags & SF_TALK)) || ((userflags & SF_ADULT) && adult_lockout))
|
2013-03-31 18:58:17 +00:00
|
|
|
return -1;
|
2006-04-13 20:47:06 +00:00
|
|
|
|
2018-05-04 22:42:37 +00:00
|
|
|
// Duke talk
|
2019-12-12 20:42:58 +00:00
|
|
|
if (userflags & SF_TALK)
|
2018-05-04 22:42:37 +00:00
|
|
|
{
|
2018-10-25 23:32:29 +00:00
|
|
|
if ((g_netServer || ud.multimode > 1) && PN(spriteNum) == APLAYER && P_Get(spriteNum) != screenpeek) // other player sound
|
2018-05-04 22:42:37 +00:00
|
|
|
{
|
2019-10-22 00:01:05 +00:00
|
|
|
if ((snd_speech & 4) != 4)
|
2018-05-04 22:42:37 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2019-10-22 00:01:05 +00:00
|
|
|
else if ((snd_speech & 1) != 1)
|
2018-05-04 22:42:37 +00:00
|
|
|
return -1;
|
2015-02-11 05:22:00 +00:00
|
|
|
|
2018-05-04 22:42:37 +00:00
|
|
|
// don't play if any Duke talk sounds are already playing
|
|
|
|
for (j = 0; j <= g_highestSoundIdx; ++j)
|
|
|
|
if ((g_sounds[j].m & SF_TALK) && g_sounds[j].num > 0)
|
|
|
|
return -1;
|
|
|
|
}
|
2019-12-12 20:42:58 +00:00
|
|
|
else if ((userflags & (SF_DTAG | SF_GLOBAL)) == SF_DTAG) // Duke-Tag sound
|
2006-04-13 20:47:06 +00:00
|
|
|
{
|
2019-12-12 20:42:58 +00:00
|
|
|
return S_PlaySound(sndnum);
|
2018-05-04 22:42:37 +00:00
|
|
|
|
2006-04-13 20:47:06 +00:00
|
|
|
}
|
|
|
|
|
2018-10-25 23:32:29 +00:00
|
|
|
int32_t sndist, sndang;
|
2019-12-12 20:42:58 +00:00
|
|
|
int const explosionp = S_CalcDistAndAng(spriteNum, sndnum, CAMERA(sect), fix16_to_int(CAMERA(q16ang)), &CAMERA(pos), pos, &sndist, &sndang);
|
|
|
|
int pitch = S_GetPitch(sndnum);
|
|
|
|
auto const pOther = g_player[screenpeek].ps;
|
2006-04-13 20:47:06 +00:00
|
|
|
|
2012-08-22 22:50:32 +00:00
|
|
|
|
2018-05-04 22:42:37 +00:00
|
|
|
if (pOther->sound_pitch)
|
|
|
|
pitch += pOther->sound_pitch;
|
2012-08-13 18:25:51 +00:00
|
|
|
|
|
|
|
if (explosionp)
|
2006-04-13 20:47:06 +00:00
|
|
|
{
|
2018-05-04 22:42:37 +00:00
|
|
|
if (pOther->cursectnum > -1 && sector[pOther->cursectnum].lotag == ST_2_UNDERWATER)
|
2006-11-16 03:02:42 +00:00
|
|
|
pitch -= 1024;
|
2012-08-13 18:25:51 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-12-12 20:42:58 +00:00
|
|
|
if (sndist > 32767 && PN(spriteNum) != MUSICANDSFX && (userflags & (SF_LOOP | SF_MSFX)) == 0)
|
2011-03-04 08:50:58 +00:00
|
|
|
return -1;
|
2012-08-13 18:25:51 +00:00
|
|
|
|
2018-05-04 22:42:37 +00:00
|
|
|
if (pOther->cursectnum > -1 && sector[pOther->cursectnum].lotag == ST_2_UNDERWATER
|
2019-12-12 20:42:58 +00:00
|
|
|
&& (userflags & SF_TALK) == 0)
|
2006-11-16 03:02:42 +00:00
|
|
|
pitch = -768;
|
2006-04-13 20:47:06 +00:00
|
|
|
}
|
|
|
|
|
2018-10-25 23:32:29 +00:00
|
|
|
if (snd.num > 0 && PN(spriteNum) != MUSICANDSFX)
|
|
|
|
S_StopEnvSound(sndNum, spriteNum);
|
2006-04-13 20:47:06 +00:00
|
|
|
|
2018-04-02 22:00:11 +00:00
|
|
|
int const sndSlot = S_GetSlot(sndNum);
|
|
|
|
|
|
|
|
if (sndSlot >= MAXSOUNDINSTANCES)
|
2010-05-02 23:27:30 +00:00
|
|
|
{
|
2018-04-02 22:00:11 +00:00
|
|
|
return -1;
|
2010-05-02 23:27:30 +00:00
|
|
|
}
|
2006-04-13 20:47:06 +00:00
|
|
|
|
2018-05-04 22:42:37 +00:00
|
|
|
int const repeatp = (snd.m & SF_LOOP);
|
2006-04-13 20:47:06 +00:00
|
|
|
|
2018-04-02 22:00:11 +00:00
|
|
|
if (repeatp && (snd.m & SF_ONEINST_INTERNAL) && snd.num > 0)
|
2010-03-01 09:09:26 +00:00
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
}
|
2010-01-05 21:53:14 +00:00
|
|
|
|
2019-07-24 01:37:32 +00:00
|
|
|
int const voice = FX_Play3D(snd.ptr, snd.siz, repeatp ? FX_LOOP : FX_ONESHOT, pitch, sndang >> 4, sndist >> 6,
|
2019-12-12 20:42:58 +00:00
|
|
|
snd.pr, snd.volume, (sndNum * MAXSOUNDINSTANCES) + sndSlot);
|
2010-03-01 09:09:26 +00:00
|
|
|
|
2010-07-03 08:53:57 +00:00
|
|
|
if (voice <= FX_Ok)
|
2010-03-01 09:09:26 +00:00
|
|
|
{
|
2010-07-03 08:53:57 +00:00
|
|
|
return -1;
|
2006-04-13 20:47:06 +00:00
|
|
|
}
|
2010-03-01 09:09:26 +00:00
|
|
|
|
2018-04-02 22:00:11 +00:00
|
|
|
snd.num++;
|
2019-08-07 22:44:20 +00:00
|
|
|
|
|
|
|
S_SetProperties(&snd.voices[sndSlot], spriteNum, voice, sndist >> 6, 0);
|
2013-03-31 18:58:17 +00:00
|
|
|
|
2010-07-03 08:53:57 +00:00
|
|
|
return voice;
|
2006-04-13 20:47:06 +00:00
|
|
|
}
|
|
|
|
|
2019-12-12 20:42:58 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
2018-10-25 23:32:29 +00:00
|
|
|
int S_PlaySound(int num)
|
2006-04-13 20:47:06 +00:00
|
|
|
{
|
2018-10-25 23:32:29 +00:00
|
|
|
int sndnum = VM_OnEventWithReturn(EVENT_SOUND, g_player[screenpeek].ps->i, screenpeek, num);
|
2014-06-23 02:24:10 +00:00
|
|
|
|
2019-12-12 20:42:58 +00:00
|
|
|
if (!soundEngine->isValidSoundId(sndnum) || !SoundEnabled()) return -1;
|
2007-08-15 03:05:14 +00:00
|
|
|
|
2019-12-12 20:42:58 +00:00
|
|
|
int userflags = soundEngine->GetUserFlags(sndnum);
|
|
|
|
if ((!(snd_speech & 1) && (userflags & SF_TALK)) || ((userflags & SF_ADULT) && adult_lockout))
|
2015-02-11 05:22:00 +00:00
|
|
|
return -1;
|
2012-01-10 23:44:49 +00:00
|
|
|
|
2018-10-25 23:32:29 +00:00
|
|
|
int const pitch = S_GetPitch(num);
|
2019-12-12 20:42:58 +00:00
|
|
|
double expitch = pow(2, pitch / 1200.); // I hope I got this right that ASS uses a linear scale where 1200 is a full octave.
|
2006-04-13 20:47:06 +00:00
|
|
|
|
2019-12-12 20:42:58 +00:00
|
|
|
soundEngine->StartSound(SOURCE_None, nullptr, nullptr, (userflags & SF_LOOP)? CHAN_AUTO|CHAN_LOOP : CHAN_AUTO, sndnum, 1.f, ATTN_NONE, nullptr, expitch);
|
|
|
|
/* for reference. May still be needed for balancing later.
|
|
|
|
: FX_Play3D(snd.ptr, snd.siz, FX_ONESHOT, pitch, 0, 255 - LOUDESTVOLUME, snd.pr, snd.volume,
|
|
|
|
(num * MAXSOUNDINSTANCES) + sndnum);
|
|
|
|
*/
|
|
|
|
return 0;
|
2006-04-13 20:47:06 +00:00
|
|
|
}
|
|
|
|
|
2019-12-12 20:42:58 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
2018-10-25 23:32:29 +00:00
|
|
|
int A_PlaySound(int soundNum, int spriteNum)
|
2006-04-13 20:47:06 +00:00
|
|
|
{
|
2018-10-25 23:32:29 +00:00
|
|
|
return (unsigned)spriteNum >= MAXSPRITES ? S_PlaySound(soundNum) :
|
2019-08-13 14:44:00 +00:00
|
|
|
S_PlaySound3D(soundNum, spriteNum, &sprite[spriteNum].pos);
|
2006-04-13 20:47:06 +00:00
|
|
|
}
|
|
|
|
|
2019-08-09 11:00:34 +00:00
|
|
|
void S_StopEnvSound(int sndNum, int sprNum)
|
2006-04-13 20:47:06 +00:00
|
|
|
{
|
2019-12-12 20:42:58 +00:00
|
|
|
if (sprNum < -1 || sprNum >= MAXSPRITES) return;
|
2010-03-01 09:09:26 +00:00
|
|
|
|
2019-12-12 20:42:58 +00:00
|
|
|
if (sprNum == -1) soundEngine->StopSoundID(sndNum);
|
|
|
|
else soundEngine->StopSound(SOURCE_Actor, &sprite[sprNum], -1, sndNum);
|
2017-01-05 05:29:25 +00:00
|
|
|
}
|
|
|
|
|
2018-10-25 23:32:29 +00:00
|
|
|
void S_ChangeSoundPitch(int soundNum, int spriteNum, int pitchoffset)
|
2011-11-03 23:08:54 +00:00
|
|
|
{
|
2019-12-12 20:42:58 +00:00
|
|
|
if (spriteNum < -1 || spriteNum >= MAXSPRITES) return;
|
|
|
|
double expitch = pow(2, pitchoffset / 1200.); // I hope I got this right that ASS uses a linear scale where 1200 is a full octave.
|
|
|
|
if (spriteNum == -1)
|
2011-11-03 23:08:54 +00:00
|
|
|
{
|
2019-12-12 20:42:58 +00:00
|
|
|
soundEngine->ChangeSoundPitch(SOURCE_Unattached, nullptr, CHAN_AUTO, expitch, soundNum);
|
2006-04-13 20:47:06 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-12-12 20:42:58 +00:00
|
|
|
soundEngine->ChangeSoundPitch(SOURCE_Actor, &sprite[spriteNum], CHAN_AUTO, expitch, soundNum);
|
2006-04-13 20:47:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-12 20:42:58 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
2006-04-13 20:47:06 +00:00
|
|
|
|
2019-08-07 22:44:29 +00:00
|
|
|
int A_CheckSoundPlaying(int spriteNum, int soundNum)
|
2006-04-16 03:42:36 +00:00
|
|
|
{
|
2019-12-12 20:42:58 +00:00
|
|
|
if (spriteNum == -1) return soundEngine->GetSoundPlayingInfo(SOURCE_Any, nullptr, soundNum);
|
|
|
|
if ((unsigned)spriteNum >= MAXSPRITES) return false;
|
|
|
|
return soundEngine->IsSourcePlayingSomething(SOURCE_Actor, &sprite[spriteNum], CHAN_AUTO, soundNum);
|
2006-04-16 03:42:36 +00:00
|
|
|
}
|
|
|
|
|
2013-01-02 22:33:32 +00:00
|
|
|
// Check if actor <i> is playing any sound.
|
2019-08-07 22:44:29 +00:00
|
|
|
int A_CheckAnySoundPlaying(int spriteNum)
|
2013-01-02 22:33:32 +00:00
|
|
|
{
|
2019-12-12 20:42:58 +00:00
|
|
|
if ((unsigned)spriteNum >= MAXSPRITES) return false;
|
|
|
|
return soundEngine->IsSourcePlayingSomething(SOURCE_Actor, &sprite[spriteNum], CHAN_AUTO, 0);
|
2013-01-02 22:33:32 +00:00
|
|
|
}
|
|
|
|
|
2019-08-07 22:44:29 +00:00
|
|
|
int S_CheckSoundPlaying(int soundNum)
|
2006-04-16 03:42:36 +00:00
|
|
|
{
|
2019-12-12 20:42:58 +00:00
|
|
|
return soundEngine->GetSoundPlayingInfo(SOURCE_Any, nullptr, soundNum);
|
2006-04-16 03:42:36 +00:00
|
|
|
}
|
2019-12-12 17:43:27 +00:00
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
void S_MenuSound(void)
|
|
|
|
{
|
|
|
|
static int SoundNum;
|
|
|
|
int const menusnds[] = {
|
|
|
|
LASERTRIP_EXPLODE, DUKE_GRUNT, DUKE_LAND_HURT, CHAINGUN_FIRE, SQUISHED, KICK_HIT,
|
|
|
|
PISTOL_RICOCHET, PISTOL_BODYHIT, PISTOL_FIRE, SHOTGUN_FIRE, BOS1_WALK, RPG_EXPLODE,
|
|
|
|
PIPEBOMB_BOUNCE, PIPEBOMB_EXPLODE, NITEVISION_ONOFF, RPG_SHOOT, SELECT_WEAPON,
|
|
|
|
};
|
|
|
|
int s = VM_OnEventWithReturn(EVENT_OPENMENUSOUND, g_player[screenpeek].ps->i, screenpeek, FURY ? -1 : menusnds[SoundNum++ % ARRAY_SIZE(menusnds)]);
|
|
|
|
if (s != -1)
|
|
|
|
S_PlaySound(s);
|
|
|
|
}
|
|
|
|
|
2019-12-12 20:42:58 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// Music
|
|
|
|
//
|
|
|
|
//==========================================================================
|
2019-12-12 17:43:27 +00:00
|
|
|
|
|
|
|
static void S_SetMusicIndex(unsigned int m)
|
|
|
|
{
|
|
|
|
ud.music_episode = m / MAXLEVELS;
|
|
|
|
ud.music_level = m % MAXLEVELS;
|
|
|
|
}
|
|
|
|
|
|
|
|
void S_PlayLevelMusicOrNothing(unsigned int m)
|
|
|
|
{
|
|
|
|
ud.returnvar[0] = m / MAXLEVELS;
|
|
|
|
ud.returnvar[1] = m % MAXLEVELS;
|
|
|
|
|
|
|
|
int retval = VM_OnEvent(EVENT_PLAYLEVELMUSICSLOT, g_player[myconnectindex].ps->i, myconnectindex);
|
|
|
|
|
|
|
|
if (retval >= 0)
|
|
|
|
{
|
|
|
|
// Thanks to scripting that stupid slot hijack cannot be refactored - but we'll store the real data elsewhere anyway!
|
|
|
|
auto& mr = m == USERMAPMUSICFAKESLOT ? userMapRecord : mapList[m];
|
|
|
|
Mus_Play(mr.labelName, mr.music, true);
|
|
|
|
S_SetMusicIndex(m);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int S_TryPlaySpecialMusic(unsigned int m)
|
|
|
|
{
|
|
|
|
auto& musicfn = mapList[m].music;
|
|
|
|
if (musicfn.IsNotEmpty())
|
|
|
|
{
|
|
|
|
if (!Mus_Play(nullptr, musicfn, true))
|
|
|
|
{
|
|
|
|
S_SetMusicIndex(m);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void S_PlaySpecialMusicOrNothing(unsigned int m)
|
|
|
|
{
|
|
|
|
if (S_TryPlaySpecialMusic(m))
|
|
|
|
{
|
|
|
|
S_SetMusicIndex(m);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void S_ContinueLevelMusic(void)
|
|
|
|
{
|
|
|
|
VM_OnEvent(EVENT_CONTINUELEVELMUSICSLOT, g_player[myconnectindex].ps->i, myconnectindex);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-09-21 20:53:00 +00:00
|
|
|
END_DUKE_NS
|