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();
|
2019-12-15 09:00:25 +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-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
|
|
|
}
|
|
|
|
|
2019-12-15 09:00:25 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
2015-02-11 05:22:00 +00:00
|
|
|
|
2019-12-15 09:00:25 +00:00
|
|
|
float S_ConvertPitch(int lpitch)
|
|
|
|
{
|
|
|
|
return pow(2, lpitch / 1200.); // I hope I got this right that ASS uses a linear scale where 1200 is a full octave.
|
|
|
|
}
|
2018-10-25 23:32:29 +00:00
|
|
|
|
2019-12-15 09:00:25 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
2012-08-13 18:25:48 +00:00
|
|
|
|
2019-12-15 09:00:25 +00:00
|
|
|
static int S_CalcDistAndAng(int spriteNum, int soundNum, int sectNum, int angle,
|
|
|
|
const vec3_t *cam, const vec3_t *pos, int *distPtr, FVector3 *sndPos)
|
|
|
|
{
|
|
|
|
// Todo: Some of this hackery really should be done using rolloff and attenuation instead of messing around with the sound origin.
|
|
|
|
int orgsndist = 0, sndang = 0, sndist = 0, explosion = 0;
|
|
|
|
int userflags = soundEngine->GetUserFlags(soundNum);
|
|
|
|
int dist_adjust = soundEngine->GetUserData(soundNum);
|
2018-10-25 23:32:29 +00:00
|
|
|
|
2019-12-15 09:00:25 +00:00
|
|
|
if (PN(spriteNum) == APLAYER && P_Get(spriteNum) == screenpeek)
|
|
|
|
goto sound_further_processing;
|
2018-10-25 23:32:29 +00:00
|
|
|
|
2019-12-15 09:00:25 +00:00
|
|
|
orgsndist = sndist = FindDistance3D(cam->x-pos->x, cam->y-pos->y, (cam->z-pos->z));
|
2018-10-25 23:32:29 +00:00
|
|
|
|
2019-12-15 09:00:25 +00:00
|
|
|
if ((userflags & (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-10-08 07:07:59 +00:00
|
|
|
|
2019-12-15 09:00:25 +00:00
|
|
|
sound_further_processing:
|
|
|
|
sndist += dist_adjust;
|
|
|
|
if (sndist < 0)
|
|
|
|
sndist = 0;
|
2012-08-13 18:25:48 +00:00
|
|
|
|
2019-12-15 09:00:25 +00:00
|
|
|
if (!FURY && sectNum > -1 && sndist && PN(spriteNum) != MUSICANDSFX
|
|
|
|
&& !cansee(cam->x, cam->y, cam->z - (24 << 8), sectNum, SX(spriteNum), SY(spriteNum), SZ(spriteNum) - (24 << 8), SECT(spriteNum)))
|
|
|
|
sndist += sndist>>5;
|
2012-10-08 07:07:17 +00:00
|
|
|
|
2019-12-15 09:00:25 +00:00
|
|
|
if ((userflags & (SF_GLOBAL|SF_DTAG)) == (SF_GLOBAL|SF_DTAG))
|
|
|
|
{
|
|
|
|
boost:
|
|
|
|
int const sdist = dist_adjust ? dist_adjust : 6144;
|
2012-10-08 07:07:17 +00:00
|
|
|
|
2019-12-15 09:00:25 +00:00
|
|
|
explosion = true;
|
2019-08-09 09:28:42 +00:00
|
|
|
|
2019-12-15 09:00:25 +00:00
|
|
|
if (sndist > sdist)
|
|
|
|
sndist = sdist;
|
|
|
|
}
|
|
|
|
else if (!FURY)
|
|
|
|
{
|
|
|
|
switch (DYNAMICSOUNDMAP(soundNum))
|
|
|
|
{
|
|
|
|
case PIPEBOMB_EXPLODE__STATIC:
|
|
|
|
case LASERTRIP_EXPLODE__STATIC:
|
|
|
|
case RPG_EXPLODE__STATIC:
|
|
|
|
goto boost;
|
|
|
|
}
|
|
|
|
}
|
2012-10-08 07:07:17 +00:00
|
|
|
|
2019-12-15 09:00:25 +00:00
|
|
|
if ((userflags & (SF_GLOBAL|SF_DTAG)) == SF_GLOBAL || sndist < ((255-LOUDESTVOLUME) << 6))
|
|
|
|
sndist = ((255-LOUDESTVOLUME) << 6);
|
2012-10-08 07:07:17 +00:00
|
|
|
|
2019-12-15 09:00:25 +00:00
|
|
|
if (distPtr)
|
|
|
|
{
|
|
|
|
*distPtr = sndist;
|
|
|
|
}
|
2012-10-08 07:07:17 +00:00
|
|
|
|
2019-12-15 09:00:25 +00:00
|
|
|
if (sndPos)
|
|
|
|
{
|
|
|
|
// Now calculate the position in sound system coordinates.
|
|
|
|
FVector3 sndvec = { float(pos->x - cam->x), (pos->z - cam->z) / 16.f, float(pos->y - cam->y) }; // distance vector
|
|
|
|
FVector3 campos = { float(pos->x), (cam->z) / 16.f, float(cam->y) }; // camera position
|
|
|
|
sndvec *= float(sndist) / orgsndist; // adjust by what was calculated above;
|
|
|
|
*sndPos = campos + sndvec; // final sound pos - still in Build fixed point coordinates.
|
|
|
|
*sndPos *= (1.f / 16); sndPos->Z = -sndPos->Z; // The sound engine works with Doom's coordinate system so do the necessary conversions
|
|
|
|
}
|
2012-10-08 07:07:17 +00:00
|
|
|
|
2019-12-15 09:00:25 +00:00
|
|
|
return explosion;
|
2012-08-13 18:25:48 +00:00
|
|
|
}
|
|
|
|
|
2019-12-15 09:00:25 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
2012-08-13 18:25:53 +00:00
|
|
|
|
2019-12-12 20:42:58 +00:00
|
|
|
void S_Update(void)
|
|
|
|
{
|
2019-12-15 09:00:25 +00:00
|
|
|
if ((g_player[myconnectindex].ps->gm & (MODE_GAME | MODE_DEMO)) == 0)
|
2019-12-12 20:42:58 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
g_numEnvSoundsPlaying = 0;
|
|
|
|
|
2019-12-15 09:00:25 +00:00
|
|
|
const vec3_t* c;
|
|
|
|
int32_t ca, cs;
|
2019-12-12 20:42:58 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2019-12-15 09:00:25 +00:00
|
|
|
int sndnum = 0;
|
2019-12-12 20:42:58 +00:00
|
|
|
int const highest = g_highestSoundIdx;
|
|
|
|
|
|
|
|
do
|
|
|
|
{
|
|
|
|
if (g_sounds[sndnum].num == 0)
|
|
|
|
continue;
|
|
|
|
|
2019-12-15 09:00:25 +00:00
|
|
|
for (auto& voice : g_sounds[sndnum].voices)
|
2019-12-12 20:42:58 +00:00
|
|
|
{
|
|
|
|
int const spriteNum = voice.owner;
|
|
|
|
|
|
|
|
if ((unsigned)spriteNum >= MAXSPRITES || voice.id <= FX_Ok || !FX_SoundActive(voice.id))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
int sndist, sndang;
|
|
|
|
|
2019-12-15 09:00:25 +00:00
|
|
|
S_CalcDistAndAng(spriteNum, sndnum, cs, ca, c, (const vec3_t*)&sprite[spriteNum], &sndist, nullptr);
|
2019-12-12 20:42:58 +00:00
|
|
|
|
|
|
|
if (S_IsAmbientSFX(spriteNum))
|
|
|
|
g_numEnvSoundsPlaying++;
|
|
|
|
|
|
|
|
// AMBIENT_SOUND
|
2019-12-15 09:00:25 +00:00
|
|
|
//FX_Pan3D(voice.id, sndang >> 4, sndist >> 6);
|
2019-12-12 20:42:58 +00:00
|
|
|
voice.dist = sndist >> 6;
|
|
|
|
voice.clock++;
|
|
|
|
}
|
|
|
|
} while (++sndnum <= highest);
|
|
|
|
}
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2019-12-15 09:00:25 +00:00
|
|
|
int32_t sndist;
|
|
|
|
FVector3 sndpos; // this is in sound engine space.
|
|
|
|
int const explosionp = S_CalcDistAndAng(spriteNum, sndnum, CAMERA(sect), fix16_to_int(CAMERA(q16ang)), &CAMERA(pos), pos, &sndist, &sndpos);
|
2019-12-12 20:42:58 +00:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2019-12-15 09:00:25 +00:00
|
|
|
bool is_playing = soundEngine->GetSoundPlayingInfo(SOURCE_Any, nullptr, sndnum);
|
|
|
|
if (is_playing && PN(spriteNum) != MUSICANDSFX)
|
|
|
|
S_StopEnvSound(sndnum, spriteNum);
|
2006-04-13 20:47:06 +00:00
|
|
|
|
2019-12-15 09:00:25 +00:00
|
|
|
int const repeatp = (userflags & SF_LOOP);
|
2006-04-13 20:47:06 +00:00
|
|
|
|
2019-12-15 09:00:25 +00:00
|
|
|
if (repeatp && (userflags & SF_ONEINST_INTERNAL) && is_playing)
|
2010-03-01 09:09:26 +00:00
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
}
|
2010-01-05 21:53:14 +00:00
|
|
|
|
2019-12-15 09:00:25 +00:00
|
|
|
// Now
|
|
|
|
auto chan = soundEngine->StartSound(SOURCE_Actor, &sprite[spriteNum], &sndpos, CHAN_AUTO, sndnum, 1.f, 1.f, nullptr, S_ConvertPitch(pitch));
|
|
|
|
if (!chan) return -1;
|
|
|
|
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 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);
|
2006-04-13 20:47:06 +00:00
|
|
|
|
2019-12-15 09:00:25 +00:00
|
|
|
soundEngine->StartSound(SOURCE_None, nullptr, nullptr, (userflags & SF_LOOP)? CHAN_AUTO|CHAN_LOOP : CHAN_AUTO, sndnum, 1.f, ATTN_NONE, nullptr, S_ConvertPitch(pitch));
|
2019-12-12 20:42:58 +00:00
|
|
|
/* 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
|