Merge branch 'master' of https://git.magicalgirl.moe/STJr/SRB2Internal into 144-scrolltweaks

This commit is contained in:
Nev3r 2019-03-16 08:14:29 +01:00
commit aa43f8b3bf
27 changed files with 1510 additions and 112 deletions

View File

@ -36,7 +36,7 @@ jobs:
- v1-SRB2-APT
- run:
name: Install SDK
command: apt-get -qq -y --no-install-recommends install git build-essential nasm libpng12-dev:i386 libsdl2-mixer-dev:i386 libgme-dev:i386 gettext ccache wget gcc-multilib upx
command: apt-get -qq -y --no-install-recommends install git build-essential nasm libpng12-dev:i386 libsdl2-mixer-dev:i386 libgme-dev:i386 gettext ccache wget gcc-multilib upx openssh-client
- save_cache:
key: v1-SRB2-APT
paths:

View File

@ -15,6 +15,7 @@ matrix:
- p7zip-full
- gcc-4.4
compiler: gcc-4.4
env: GCC44=1
#gcc-4.4 (Ubuntu/Linaro 4.4.7-8ubuntu1) 4.4.7
- os: linux
addons:
@ -27,6 +28,7 @@ matrix:
- p7zip-full
- gcc-4.6
compiler: gcc-4.6
env: GCC46=1
#gcc-4.6 (Ubuntu/Linaro 4.6.4-6ubuntu2) 4.6.4
- os: linux
addons:
@ -39,9 +41,11 @@ matrix:
- p7zip-full
- gcc-4.7
compiler: gcc-4.7
env: GCC47=1
#gcc-4.7
- os: linux
compiler: gcc
env: GCC48=1
#gcc (Ubuntu 4.8.4-2ubuntu1~14.04) 4.8.4
- os: linux
addons:
@ -56,6 +60,7 @@ matrix:
- p7zip-full
- gcc-4.8
compiler: gcc-4.8
env: GCC48=1
#gcc-4.8 (Ubuntu 4.8.5-2ubuntu1~14.04.1) 4.8.5
- os: linux
addons:
@ -70,7 +75,7 @@ matrix:
- p7zip-full
- gcc-7
compiler: gcc-7
env: WFLAGS="-Wno-tautological-compare -Wno-error=implicit-fallthrough -Wno-implicit-fallthrough"
env: WFLAGS="-Wno-tautological-compare -Wno-error=implicit-fallthrough -Wno-implicit-fallthrough" GCC72=1
#gcc-7 (Ubuntu 7.2.0-1ubuntu1~14.04) 7.2.0 20170802
- os: linux
addons:
@ -85,7 +90,7 @@ matrix:
- p7zip-full
- gcc-8
compiler: gcc-8
env: WFLAGS="-Wno-tautological-compare -Wno-error=implicit-fallthrough -Wno-implicit-fallthrough -Wno-error=format-overflow"
env: WFLAGS="-Wno-tautological-compare -Wno-error=implicit-fallthrough -Wno-implicit-fallthrough -Wno-error=format-overflow" GCC81=1
#gcc-8 (Ubuntu 7.2.0-1ubuntu1~14.04) 8.1.0
- os: linux
compiler: clang

View File

@ -7,6 +7,10 @@
# and other things
#
ifdef GCC81
GCC80=1
endif
ifdef GCC80
GCC72=1
endif
@ -112,6 +116,7 @@ WFLAGS+=-Wfloat-equal
#WFLAGS+=-Wtraditional
ifdef VCHELP
WFLAGS+=-Wdeclaration-after-statement
WFLAGS+=-Wno-error=declaration-after-statement
endif
WFLAGS+=-Wundef
ifndef GCC295
@ -181,12 +186,6 @@ ifdef GCC46
WFLAGS+=-Wno-suggest-attribute=noreturn
endif
ifndef MINGW
ifdef GCC45
WFLAGS+=-Wunsuffixed-float-constants
endif
endif
ifdef NOLDWARNING
LDFLAGS+=-Wl,--as-needed
endif
@ -200,6 +199,9 @@ WFLAGS+=$(OLDWFLAGS)
ifdef GCC43
#WFLAGS+=-Wno-error=clobbered
endif
ifdef GCC44
WFLAGS+=-Wno-error=array-bounds
endif
ifdef GCC46
WFLAGS+=-Wno-error=suggest-attribute=noreturn
endif

View File

@ -96,6 +96,37 @@ boolean I_SetSongSpeed(float speed)
return false;
}
/// ------------------------
// MUSIC SEEKING
/// ------------------------
UINT32 I_GetSongLength(void)
{
return 0;
}
boolean I_SetSongLoopPoint(UINT32 looppoint)
{
(void)looppoint;
return false;
}
UINT32 I_GetSongLoopPoint(void)
{
return 0;
}
boolean I_SetSongPosition(UINT32 position)
{
(void)position;
return false;
}
UINT32 I_GetSongPosition(void)
{
return 0;
}
/// ------------------------
// MUSIC PLAYBACK
/// ------------------------
@ -140,3 +171,44 @@ void I_SetMusicVolume(INT32 volume)
{
(void)volume;
}
/// ------------------------
// MUSIC FADING
/// ------------------------
void I_SetInternalMusicVolume(UINT8 volume)
{
(void)volume;
}
void I_StopFadingSong(void)
{
}
boolean I_FadeSongFromVolume(UINT8 target_volume, UINT8 source_volume, UINT32 ms, void (*callback)(void));
{
(void)target_volume;
(void)source_volume;
(void)ms;
return false;
}
boolean I_FadeSong(UINT8 target_volume, UINT32 ms, void (*callback)(void));
{
(void)target_volume;
(void)ms;
return false;
}
boolean I_FadeOutStopSong(UINT32 ms)
{
(void)ms;
return false;
}
boolean I_FadeInPlaySong(UINT32 ms, boolean looping)
{
(void)ms;
(void)looping;
return false;
}

View File

@ -1160,6 +1160,13 @@ static void readlevelheader(MYFILE *f, INT32 num)
#endif
else if (fastcmp(word, "MUSICTRACK"))
mapheaderinfo[num-1]->mustrack = ((UINT16)i - 1);
else if (fastcmp(word, "MUSICPOS"))
mapheaderinfo[num-1]->muspos = (UINT32)get_number(word2);
else if (fastcmp(word, "MUSICINTERFADEOUT"))
mapheaderinfo[num-1]->musinterfadeout = (UINT32)get_number(word2);
else if (fastcmp(word, "MUSICINTER"))
deh_strlcpy(mapheaderinfo[num-1]->musintername, word2,
sizeof(mapheaderinfo[num-1]->musintername), va("Level header %d: intermission music", num));
else if (fastcmp(word, "FORCECHARACTER"))
{
strlcpy(mapheaderinfo[num-1]->forcecharacter, word2, SKINNAMESIZE+1);
@ -1264,6 +1271,13 @@ static void readlevelheader(MYFILE *f, INT32 num)
else
mapheaderinfo[num-1]->levelflags &= ~LF_SAVEGAME;
}
else if (fastcmp(word, "MIXNIGHTSCOUNTDOWN"))
{
if (i || word2[0] == 'T' || word2[0] == 'Y')
mapheaderinfo[num-1]->levelflags |= LF_MIXNIGHTSCOUNTDOWN;
else
mapheaderinfo[num-1]->levelflags &= ~LF_MIXNIGHTSCOUNTDOWN;
}
// Individual triggers for menu flags
else if (fastcmp(word, "HIDDEN"))
@ -1460,6 +1474,10 @@ static void readcutscenescene(MYFILE *f, INT32 num, INT32 scenenum)
{
cutscenes[num]->scene[scenenum].musswitchflags = ((UINT16)i) & MUSIC_TRACKMASK;
}
else if (fastcmp(word, "MUSICPOS"))
{
cutscenes[num]->scene[scenenum].musswitchposition = (UINT32)get_number(word2);
}
else if (fastcmp(word, "MUSICLOOP"))
{
cutscenes[num]->scene[scenenum].musicloop = (UINT8)(i || word2[0] == 'T' || word2[0] == 'Y');
@ -7793,6 +7811,7 @@ struct {
// doomdef.h constants
{"TICRATE",TICRATE},
{"MUSICRATE",MUSICRATE},
{"RING_DIST",RING_DIST},
{"PUSHACCEL",PUSHACCEL},
{"MODID",MODID}, // I don't know, I just thought it would be cool for a wad to potentially know what mod it was loaded into.
@ -7879,6 +7898,7 @@ struct {
{"LF_NORELOAD",LF_NORELOAD},
{"LF_NOZONE",LF_NOZONE},
{"LF_SAVEGAME",LF_SAVEGAME},
{"LF_MIXNIGHTSCOUNTDOWN",LF_MIXNIGHTSCOUNTDOWN},
// And map flags
{"LF2_HIDEINMENU",LF2_HIDEINMENU},
{"LF2_HIDEINSTATS",LF2_HIDEINSTATS},
@ -9249,6 +9269,9 @@ static inline int lib_getenum(lua_State *L)
} else if (fastcmp(word,"mapmusflags")) {
lua_pushinteger(L, mapmusflags);
return 1;
} else if (fastcmp(word,"mapmusposition")) {
lua_pushinteger(L, mapmusposition);
return 1;
} else if (fastcmp(word,"server")) {
if ((!multiplayer || !netgame) && !playeringame[serverplayer])
return 0;

View File

@ -438,6 +438,37 @@ boolean I_SetSongSpeed(float speed)
return false;
}
/// ------------------------
// MUSIC SEEKING
/// ------------------------
UINT32 I_GetSongLength(void)
{
return 0;
}
boolean I_SetSongLoopPoint(UINT32 looppoint)
{
(void)looppoint;
return false;
}
UINT32 I_GetSongLoopPoint(void)
{
return 0;
}
boolean I_SetSongPosition(UINT32 position)
{
(void)position;
return false;
}
UINT32 I_GetSongPosition(void)
{
return 0;
}
/// ------------------------
// MUSIC PLAYBACK
/// ------------------------
@ -545,3 +576,44 @@ int I_QrySongPlaying(int handle)
return (midi_pos==-1);
}
#endif
/// ------------------------
// MUSIC FADING
/// ------------------------
void I_SetInternalMusicVolume(UINT8 volume)
{
(void)volume;
}
void I_StopFadingSong(void)
{
}
boolean I_FadeSongFromVolume(UINT8 target_volume, UINT8 source_volume, UINT32 ms, void (*callback)(void));
{
(void)target_volume;
(void)source_volume;
(void)ms;
return false;
}
boolean I_FadeSong(UINT8 target_volume, UINT32 ms, void (*callback)(void));
{
(void)target_volume;
(void)ms;
return false;
}
boolean I_FadeOutStopSong(UINT32 ms)
{
(void)ms;
return false;
}
boolean I_FadeInPlaySong(UINT32 ms, boolean looping)
{
(void)ms;
(void)looping;
return false;
}

View File

@ -373,6 +373,8 @@ typedef enum
#define NEWTICRATERATIO 1 // try 4 for 140 fps :)
#define NEWTICRATE (TICRATE*NEWTICRATERATIO)
#define MUSICRATE 1000 // sound timing is calculated by milliseconds
#define RING_DIST 512*FRACUNIT // how close you need to be to a ring to attract it
#define PUSHACCEL (2*FRACUNIT) // Acceleration for MF2_SLIDEPUSH items.

View File

@ -33,8 +33,10 @@
extern INT16 gamemap;
extern char mapmusname[7];
extern UINT16 mapmusflags;
extern UINT32 mapmusposition;
#define MUSIC_TRACKMASK 0x0FFF // ----************
#define MUSIC_RELOADRESET 0x8000 // *---------------
#define MUSIC_FORCERESET 0x4000 // -*--------------
// Use other bits if necessary.
extern INT16 maptol;
@ -160,6 +162,7 @@ typedef struct
char musswitch[7];
UINT16 musswitchflags;
UINT32 musswitchposition;
UINT8 fadecolor; // Color number for fade, 0 means don't do the first fade
UINT8 fadeinid; // ID of the first fade, to a color -- ignored if fadecolor is 0
@ -284,6 +287,7 @@ typedef struct
INT16 nextlevel; ///< Map number of next level, or 1100-1102 to end.
char musname[7]; ///< Music track to play. "" for no music.
UINT16 mustrack; ///< Subsong to play. Only really relevant for music modules and specific formats supported by GME. 0 to ignore.
UINT32 muspos; ///< Music position to jump to.
char forcecharacter[17]; ///< (SKINNAMESIZE+1) Skin to switch to or "" to disable.
UINT8 weather; ///< 0 = sunny day, 1 = storm, 2 = snow, 3 = rain, 4 = blank, 5 = thunder w/o rain, 6 = rain w/o lightning, 7 = heat wave.
INT16 skynum; ///< Sky number to use.
@ -305,7 +309,7 @@ typedef struct
SINT8 bonustype; ///< What type of bonus does this level have? (-1 for null.)
SINT8 maxbonuslives; ///< How many bonus lives to award at Intermission? (-1 for unlimited.)
UINT8 levelflags; ///< LF_flags: merged eight booleans into one UINT8 for space, see below
UINT8 levelflags; ///< LF_flags: merged booleans into one UINT8 for space, see below
UINT8 menuflags; ///< LF2_flags: options that affect record attack / nights mode menus
char selectheading[22]; ///< Level select heading. Allows for controllable grouping.
@ -318,6 +322,10 @@ typedef struct
UINT8 numGradedMares; ///< Internal. For grade support.
nightsgrades_t *grades; ///< NiGHTS grades. Allocated dynamically for space reasons. Be careful.
// Music stuff.
UINT32 musinterfadeout; ///< Fade out level music on intermission screen in milliseconds
char musintername[7]; ///< Intermission screen music.
// Lua stuff.
// (This is not ifdeffed so the map header structure can stay identical, just in case.)
UINT8 numCustomOptions; ///< Internal. For Lua custom value support.
@ -331,6 +339,7 @@ typedef struct
#define LF_NORELOAD 8 ///< Don't reload level on death
#define LF_NOZONE 16 ///< Don't include "ZONE" on level title
#define LF_SAVEGAME 32 ///< Save the game upon loading this level
#define LF_MIXNIGHTSCOUNTDOWN 64 ///< Play sfx_timeup instead of music change for NiGHTS countdown
#define LF2_HIDEINMENU 1 ///< Hide in the multiplayer menu
#define LF2_HIDEINSTATS 2 ///< Hide in the statistics screen

View File

@ -95,6 +95,37 @@ boolean I_SetSongSpeed(float speed)
return false;
}
/// ------------------------
// MUSIC SEEKING
/// ------------------------
UINT32 I_GetSongLength(void)
{
return 0;
}
boolean I_SetSongLoopPoint(UINT32 looppoint)
{
(void)looppoint;
return false;
}
UINT32 I_GetSongLoopPoint(void)
{
return 0;
}
boolean I_SetSongPosition(UINT32 position)
{
(void)position;
return false;
}
UINT32 I_GetSongPosition(void)
{
return 0;
}
/// ------------------------
// MUSIC PLAYBACK
/// ------------------------
@ -142,4 +173,45 @@ boolean I_SetSongTrack(int track)
{
(void)track;
return false;
}
}
/// ------------------------
// MUSIC FADING
/// ------------------------
void I_SetInternalMusicVolume(UINT8 volume)
{
(void)volume;
}
void I_StopFadingSong(void)
{
}
boolean I_FadeSongFromVolume(UINT8 target_volume, UINT8 source_volume, UINT32 ms, void (*callback)(void));
{
(void)target_volume;
(void)source_volume;
(void)ms;
return false;
}
boolean I_FadeSong(UINT8 target_volume, UINT32 ms, void (*callback)(void));
{
(void)target_volume;
(void)ms;
return false;
}
boolean I_FadeOutStopSong(UINT32 ms)
{
(void)ms;
return false;
}
boolean I_FadeInPlaySong(UINT32 ms, boolean looping)
{
(void)ms;
(void)looping;
return false;
}

View File

@ -1875,9 +1875,10 @@ static void F_AdvanceToNextScene(void)
picypos = cutscenes[cutnum]->scene[scenenum].ycoord[picnum];
if (cutscenes[cutnum]->scene[scenenum].musswitch[0])
S_ChangeMusic(cutscenes[cutnum]->scene[scenenum].musswitch,
S_ChangeMusicEx(cutscenes[cutnum]->scene[scenenum].musswitch,
cutscenes[cutnum]->scene[scenenum].musswitchflags,
cutscenes[cutnum]->scene[scenenum].musicloop);
cutscenes[cutnum]->scene[scenenum].musicloop,
cutscenes[cutnum]->scene[scenenum].musswitchposition, 0, 0);
// Fade to the next
dofadenow = true;
@ -1951,9 +1952,10 @@ void F_StartCustomCutscene(INT32 cutscenenum, boolean precutscene, boolean reset
stoptimer = 0;
if (cutscenes[cutnum]->scene[0].musswitch[0])
S_ChangeMusic(cutscenes[cutnum]->scene[0].musswitch,
S_ChangeMusicEx(cutscenes[cutnum]->scene[0].musswitch,
cutscenes[cutnum]->scene[0].musswitchflags,
cutscenes[cutnum]->scene[0].musicloop);
cutscenes[cutnum]->scene[0].musicloop,
cutscenes[cutnum]->scene[scenenum].musswitchposition, 0, 0);
else
S_StopMusic();
}

View File

@ -71,6 +71,7 @@ static void G_DoWorldDone(void);
char mapmusname[7]; // Music name
UINT16 mapmusflags; // Track and reset bit
UINT32 mapmusposition; // Position to jump to
INT16 gamemap = 1;
INT16 maptol;
@ -2292,9 +2293,14 @@ void G_PlayerReborn(INT32 player)
{
strncpy(mapmusname, mapheaderinfo[gamemap-1]->musname, 7);
mapmusname[6] = 0;
mapmusflags = mapheaderinfo[gamemap-1]->mustrack & MUSIC_TRACKMASK;
mapmusflags = (mapheaderinfo[gamemap-1]->mustrack & MUSIC_TRACKMASK);
mapmusposition = mapheaderinfo[gamemap-1]->muspos;
}
S_ChangeMusic(mapmusname, mapmusflags, true);
// This is in S_Start, but this was not here previously.
// if (cv_resetmusic.value)
// S_StopMusic();
S_ChangeMusicEx(mapmusname, mapmusflags, true, mapmusposition, 0, 0);
}
if (gametype == GT_COOP)

View File

@ -146,6 +146,18 @@ boolean I_SongPaused(void);
boolean I_SetSongSpeed(float speed);
/// ------------------------
// MUSIC SEEKING
/// ------------------------
UINT32 I_GetSongLength(void);
boolean I_SetSongLoopPoint(UINT32 looppoint);
UINT32 I_GetSongLoopPoint(void);
boolean I_SetSongPosition(UINT32 position);
UINT32 I_GetSongPosition(void);
/// ------------------------
// MUSIC PLAYBACK
/// ------------------------
@ -216,6 +228,17 @@ void I_SetMusicVolume(UINT8 volume);
boolean I_SetSongTrack(INT32 track);
/// ------------------------
/// MUSIC FADING
/// ------------------------
void I_SetInternalMusicVolume(UINT8 volume);
void I_StopFadingSong(void);
boolean I_FadeSongFromVolume(UINT8 target_volume, UINT8 source_volume, UINT32 ms, void (*callback)(void));
boolean I_FadeSong(UINT8 target_volume, UINT32 ms, void (*callback)(void));
boolean I_FadeOutStopSong(UINT32 ms);
boolean I_FadeInPlaySong(UINT32 ms, boolean looping);
/// ------------------------
// CD MUSIC I/O
/// ------------------------

View File

@ -1015,7 +1015,8 @@ static int lib_pRestoreMusic(lua_State *L)
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
P_RestoreMusic(player);
if (P_IsLocalPlayer(player))
P_RestoreMusic(player);
return 0;
}
@ -2283,7 +2284,7 @@ static int lib_sChangeMusic(lua_State *L)
{
#ifdef MUSICSLOT_COMPATIBILITY
const char *music_name;
UINT32 music_num;
UINT32 music_num, position, prefadems, fadeinms;
char music_compat_name[7];
boolean looping;
@ -2311,7 +2312,6 @@ static int lib_sChangeMusic(lua_State *L)
music_name = luaL_checkstring(L, 1);
}
looping = (boolean)lua_opttrueboolean(L, 2);
#else
@ -2336,8 +2336,12 @@ static int lib_sChangeMusic(lua_State *L)
#endif
music_flags = (UINT16)luaL_optinteger(L, 4, 0);
position = (UINT32)luaL_optinteger(L, 5, 0);
prefadems = (UINT32)luaL_optinteger(L, 6, 0);
fadeinms = (UINT32)luaL_optinteger(L, 7, 0);
if (!player || P_IsLocalPlayer(player))
S_ChangeMusic(music_name, music_flags, looping);
S_ChangeMusicEx(music_name, music_flags, looping, position, prefadems, fadeinms);
return 0;
}
@ -2354,10 +2358,8 @@ static int lib_sSpeedMusic(lua_State *L)
return LUA_ErrInvalid(L, "player_t");
}
if (!player || P_IsLocalPlayer(player))
lua_pushboolean(L, S_SpeedMusic(speed));
else
lua_pushboolean(L, false);
return 1;
S_SpeedMusic(speed);
return 0;
}
static int lib_sStopMusic(lua_State *L)
@ -2375,6 +2377,110 @@ static int lib_sStopMusic(lua_State *L)
return 0;
}
static int lib_sSetInternalMusicVolume(lua_State *L)
{
UINT32 volume = (UINT32)luaL_checkinteger(L, 1);
player_t *player = NULL;
NOHUD
if (!lua_isnone(L, 2) && lua_isuserdata(L, 2))
{
player = *((player_t **)luaL_checkudata(L, 2, META_PLAYER));
if (!player)
return LUA_ErrInvalid(L, "player_t");
}
if (!player || P_IsLocalPlayer(player))
{
S_SetInternalMusicVolume(volume);
lua_pushboolean(L, true);
}
else
lua_pushnil(L);
return 1;
}
static int lib_sStopFadingMusic(lua_State *L)
{
player_t *player = NULL;
NOHUD
if (!lua_isnone(L, 1) && lua_isuserdata(L, 1))
{
player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
if (!player)
return LUA_ErrInvalid(L, "player_t");
}
if (!player || P_IsLocalPlayer(player))
{
S_StopFadingMusic();
lua_pushboolean(L, true);
}
else
lua_pushnil(L);
return 1;
}
static int lib_sFadeMusic(lua_State *L)
{
UINT32 target_volume = (UINT32)luaL_checkinteger(L, 1);
UINT32 ms;
INT32 source_volume;
player_t *player = NULL;
NOHUD
if (!lua_isnone(L, 3) && lua_isuserdata(L, 3))
{
player = *((player_t **)luaL_checkudata(L, 3, META_PLAYER));
if (!player)
return LUA_ErrInvalid(L, "player_t");
ms = (UINT32)luaL_checkinteger(L, 2);
source_volume = -1;
}
else if (!lua_isnone(L, 4) && lua_isuserdata(L, 4))
{
player = *((player_t **)luaL_checkudata(L, 4, META_PLAYER));
if (!player)
return LUA_ErrInvalid(L, "player_t");
source_volume = (INT32)luaL_checkinteger(L, 2);
ms = (UINT32)luaL_checkinteger(L, 3);
}
else if (luaL_optinteger(L, 3, INT32_MAX) == INT32_MAX)
{
ms = (UINT32)luaL_checkinteger(L, 2);
source_volume = -1;
}
else
{
source_volume = (INT32)luaL_checkinteger(L, 2);
ms = (UINT32)luaL_checkinteger(L, 3);
}
NOHUD
if (!player || P_IsLocalPlayer(player))
lua_pushboolean(L, S_FadeMusicFromVolume(target_volume, source_volume, ms));
else
lua_pushnil(L);
return 1;
}
static int lib_sFadeOutStopMusic(lua_State *L)
{
UINT32 ms = (UINT32)luaL_checkinteger(L, 1);
player_t *player = NULL;
NOHUD
if (!lua_isnone(L, 2) && lua_isuserdata(L, 2))
{
player = *((player_t **)luaL_checkudata(L, 2, META_PLAYER));
if (!player)
return LUA_ErrInvalid(L, "player_t");
}
if (!player || P_IsLocalPlayer(player))
{
lua_pushboolean(L, S_FadeOutStopMusic(ms));
}
else
lua_pushnil(L);
return 1;
}
static int lib_sOriginPlaying(lua_State *L)
{
void *origin = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
@ -2782,6 +2888,10 @@ static luaL_Reg lib[] = {
{"S_ChangeMusic",lib_sChangeMusic},
{"S_SpeedMusic",lib_sSpeedMusic},
{"S_StopMusic",lib_sStopMusic},
{"S_SetInternalMusicVolume", lib_sSetInternalMusicVolume},
{"S_StopFadingMusic",lib_sStopFadingMusic},
{"S_FadeMusic",lib_sFadeMusic},
{"S_FadeOutStopMusic",lib_sFadeOutStopMusic},
{"S_OriginPlaying",lib_sOriginPlaying},
{"S_IdPlaying",lib_sIdPlaying},
{"S_SoundPlaying",lib_sSoundPlaying},

View File

@ -2031,6 +2031,12 @@ static int mapheaderinfo_get(lua_State *L)
lua_pushstring(L, header->musname);
else if (fastcmp(field,"mustrack"))
lua_pushinteger(L, header->mustrack);
else if (fastcmp(field,"muspos"))
lua_pushinteger(L, header->muspos);
else if (fastcmp(field,"musinterfadeout"))
lua_pushinteger(L, header->musinterfadeout);
else if (fastcmp(field,"musintername"))
lua_pushstring(L, header->musintername);
else if (fastcmp(field,"forcecharacter"))
lua_pushstring(L, header->forcecharacter);
else if (fastcmp(field,"weather"))

View File

@ -2756,8 +2756,18 @@ static inline void P_NiGHTSDamage(mobj_t *target, mobj_t *source)
if (oldnightstime > 10*TICRATE
&& player->nightstime < 10*TICRATE)
{
//S_StartSound(NULL, sfx_timeup); // that creepy "out of time" music from NiGHTS. Dummied out, as some on the dev team thought it wasn't Sonic-y enough (Mystic, notably). Uncomment to restore. -SH
S_ChangeMusicInternal((((maptol & TOL_NIGHTS) && !G_IsSpecialStage(gamemap)) ? "_ntime" : "_drown"), false);
if ((mapheaderinfo[gamemap-1]->levelflags & LF_MIXNIGHTSCOUNTDOWN)
#ifdef _WIN32
// win32 MIDI volume hack means we cannot fade down the music
&& S_MusicType() != MU_MID
#endif
)
{
S_FadeMusic(0, 10*MUSICRATE);
S_StartSound(NULL, sfx_timeup); // that creepy "out of time" music from NiGHTS.
}
else
S_ChangeMusicInternal((((maptol & TOL_NIGHTS) && !G_IsSpecialStage(gamemap)) ? "_ntime" : "_drown"), false);
}
}
}
@ -3137,8 +3147,13 @@ void P_SpecialStageDamage(player_t *player, mobj_t *inflictor, mobj_t *source)
if (oldnightstime > 10*TICRATE
&& player->nightstime < 10*TICRATE)
{
//S_StartSound(NULL, sfx_timeup); // that creepy "out of time" music from NiGHTS. Dummied out, as some on the dev team thought it wasn't Sonic-y enough (Mystic, notably). Uncomment to restore. -SH
S_ChangeMusicInternal((((maptol & TOL_NIGHTS) && !G_IsSpecialStage(gamemap)) ? "_ntime" : "_drown"), false);
if (mapheaderinfo[gamemap-1]->levelflags & LF_MIXNIGHTSCOUNTDOWN)
{
S_FadeMusic(0, 10*MUSICRATE);
S_StartSound(NULL, sfx_timeup); // that creepy "out of time" music from NiGHTS.
}
else
S_ChangeMusicInternal((((maptol & TOL_NIGHTS) && !G_IsSpecialStage(gamemap)) ? "_ntime" : "_drown"), false);
}
}

View File

@ -212,6 +212,9 @@ static void P_ClearSingleMapHeaderInfo(INT16 i)
snprintf(mapheaderinfo[num]->musname, 7, "%sM", G_BuildMapName(i));
mapheaderinfo[num]->musname[6] = 0;
mapheaderinfo[num]->mustrack = 0;
mapheaderinfo[num]->muspos = 0;
mapheaderinfo[num]->musinterfadeout = 0;
mapheaderinfo[num]->musintername[0] = '\0';
mapheaderinfo[num]->forcecharacter[0] = '\0';
mapheaderinfo[num]->weather = 0;
mapheaderinfo[num]->skynum = 1;
@ -1428,19 +1431,33 @@ static void P_LoadRawSideDefs2(void *data)
{
M_Memcpy(process,msd->bottomtexture,8);
process[8] = '\0';
sd->bottomtexture = get_number(process)-1;
sd->bottomtexture = get_number(process);
}
M_Memcpy(process,msd->toptexture,8);
process[8] = '\0';
sd->text = Z_Malloc(7, PU_LEVEL, NULL);
// If they type in O_ or D_ and their music name, just shrug,
// then copy the rest instead.
if ((process[0] == 'O' || process[0] == 'D') && process[7])
M_Memcpy(sd->text, process+2, 6);
else // Assume it's a proper music name.
M_Memcpy(sd->text, process, 6);
sd->text[6] = 0;
if (!(msd->midtexture[0] == '-' && msd->midtexture[1] == '\0') || msd->midtexture[1] != '\0')
{
M_Memcpy(process,msd->midtexture,8);
process[8] = '\0';
sd->midtexture = get_number(process);
}
// always process if back sidedef, because we need that - symbol
sd->text = Z_Malloc(7, PU_LEVEL, NULL);
if (i == 1 || msd->toptexture[0] != '-' || msd->toptexture[1] != '\0')
{
M_Memcpy(process,msd->toptexture,8);
process[8] = '\0';
// If they type in O_ or D_ and their music name, just shrug,
// then copy the rest instead.
if ((process[0] == 'O' || process[0] == 'D') && process[7])
M_Memcpy(sd->text, process+2, 6);
else // Assume it's a proper music name.
M_Memcpy(sd->text, process, 6);
sd->text[6] = 0;
}
else
sd->text[0] = 0;
break;
}

View File

@ -2593,16 +2593,68 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
// console player only unless NOCLIMB is set
if ((line->flags & ML_NOCLIMB) || (mo && mo->player && P_IsLocalPlayer(mo->player)))
{
UINT16 tracknum = (UINT16)sides[line->sidenum[0]].bottomtexture;
boolean musicsame = (!sides[line->sidenum[0]].text[0] || !strnicmp(sides[line->sidenum[0]].text, S_MusicName(), 7));
UINT16 tracknum = (UINT16)max(sides[line->sidenum[0]].bottomtexture, 0);
INT32 position = (INT32)max(sides[line->sidenum[0]].midtexture, 0);
UINT32 prefadems = (UINT32)max(sides[line->sidenum[0]].textureoffset >> FRACBITS, 0);
UINT32 postfadems = (UINT32)max(sides[line->sidenum[0]].rowoffset >> FRACBITS, 0);
UINT8 fadetarget = (UINT8)max((line->sidenum[1] != 0xffff) ? sides[line->sidenum[1]].textureoffset >> FRACBITS : 0, 0);
INT16 fadesource = (INT16)max((line->sidenum[1] != 0xffff) ? sides[line->sidenum[1]].rowoffset >> FRACBITS : -1, -1);
strncpy(mapmusname, sides[line->sidenum[0]].text, 7);
mapmusname[6] = 0;
// Seek offset from current song position
if (line->flags & ML_EFFECT1)
{
// adjust for loop point if subtracting
if (position < 0 && S_GetMusicLength() &&
S_GetMusicPosition() > S_GetMusicLoopPoint() &&
S_GetMusicPosition() + position < S_GetMusicLoopPoint())
position = max(S_GetMusicLength() - (S_GetMusicLoopPoint() - (S_GetMusicPosition() + position)), 0);
else
position = max(S_GetMusicPosition() + position, 0);
}
mapmusflags = tracknum & MUSIC_TRACKMASK;
if (!(line->flags & ML_BLOCKMONSTERS))
mapmusflags |= MUSIC_RELOADRESET;
// Fade current music to target volume (if music won't be changed)
if ((line->flags & ML_EFFECT2) && fadetarget && musicsame)
{
// 0 fadesource means fade from current volume.
// meaning that we can't specify volume 0 as the source volume -- this starts at 1.
if (!fadesource)
fadesource = -1;
S_ChangeMusic(mapmusname, mapmusflags, !(line->flags & ML_EFFECT4));
if (!postfadems)
S_SetInternalMusicVolume(fadetarget);
else
S_FadeMusicFromVolume(fadetarget, fadesource, postfadems);
if (position)
S_SetMusicPosition(position);
}
// Change the music and apply position/fade operations
else
{
strncpy(mapmusname, sides[line->sidenum[0]].text, 7);
mapmusname[6] = 0;
mapmusflags = tracknum & MUSIC_TRACKMASK;
if (!(line->flags & ML_BLOCKMONSTERS))
mapmusflags |= MUSIC_RELOADRESET;
if (line->flags & ML_BOUNCY)
mapmusflags |= MUSIC_FORCERESET;
mapmusposition = position;
S_ChangeMusicEx(mapmusname, mapmusflags, !(line->flags & ML_EFFECT4), position,
!(line->flags & ML_EFFECT2) ? prefadems : 0,
!(line->flags & ML_EFFECT2) ? postfadems : 0);
if ((line->flags & ML_EFFECT2) && fadetarget)
{
if (!postfadems)
S_SetInternalMusicVolume(fadetarget);
else
S_FadeMusicFromVolume(fadetarget, fadesource, postfadems);
}
}
// Except, you can use the ML_BLOCKMONSTERS flag to change this behavior.
// if (mapmusflags & MUSIC_RELOADRESET) then it will reset the music in G_PlayerReborn.

View File

@ -629,6 +629,14 @@ static void P_DeNightserizePlayer(player_t *player)
player->marescore = player->spheres =\
player->rings = 0;
P_DamageMobj(player->mo, NULL, NULL, 1, DMG_INSTAKILL);
// Reset music to beginning if MIXNIGHTSCOUNTDOWN
if ((mapheaderinfo[gamemap-1]->levelflags & LF_MIXNIGHTSCOUNTDOWN)
#ifdef _WIN32
&& S_MusicType() != MU_MID
#endif
)
S_SetMusicPosition(0);
}
break;
@ -639,7 +647,24 @@ static void P_DeNightserizePlayer(player_t *player)
player->oldscale = 0;
// Restore from drowning music
P_RestoreMusic(player);
if ((mapheaderinfo[gamemap-1]->levelflags & LF_MIXNIGHTSCOUNTDOWN)
#ifdef _WIN32
&& S_MusicType() != MU_MID
#endif
)
{
S_StopSoundByNum(sfx_timeup);
S_StopFadingMusic();
S_SetInternalMusicVolume(100);
// Reset the music if you did not destroy all the capsules, because you failed.
// Why make the all-capsules exception: because it's your reward for nearly finishing the level!
// (unless the player auto-loses upon denightserizing; for death case, see above.)
if (P_FindLowestMare() != UINT8_MAX || G_IsSpecialStage(gamemap))
S_SetMusicPosition(0);
}
else
P_RestoreMusic(player);
P_RunDeNightserizeExecutors(player->mo);
}
@ -687,7 +712,16 @@ void P_NightserizePlayer(player_t *player, INT32 nighttime)
player->nightstime = player->startedtime = player->lapstartedtime = nighttime*TICRATE;
player->bonustime = false;
P_RestoreMusic(player);
// Restore from drowning music
if (mapheaderinfo[gamemap-1]->levelflags & LF_MIXNIGHTSCOUNTDOWN)
{
S_StopSoundByNum(sfx_timeup);
S_StopFadingMusic();
S_SetInternalMusicVolume(100);
}
else
P_RestoreMusic(player);
P_SetPlayerMobjState(player->mo, S_PLAY_NIGHTS_TRANS1);
if (gametype == GT_RACE || gametype == GT_COMPETITION)
@ -1292,13 +1326,13 @@ void P_RestoreMusic(player_t *player)
if (mapheaderinfo[gamemap-1]->levelflags & LF_SPEEDMUSIC)
{
S_SpeedMusic(1.4f);
S_ChangeMusic(mapmusname, mapmusflags, true);
S_ChangeMusicEx(mapmusname, mapmusflags, true, mapmusposition, 0, 0);
}
else
S_ChangeMusicInternal("_shoes", true);
}
else
S_ChangeMusic(mapmusname, mapmusflags, true);
S_ChangeMusicEx(mapmusname, mapmusflags, true, mapmusposition, 0, 0);
}
//
@ -6344,14 +6378,18 @@ static void P_NiGHTSMovement(player_t *player)
{
P_DeNightserizePlayer(player);
S_StartScreamSound(player->mo, sfx_s3k66);
// S_StopSoundByNum(sfx_timeup); // Kill the "out of time" music, if it's playing. Dummied out, as some on the dev team thought it wasn't Sonic-y enough (Mystic, notably). Uncomment to restore. -SH
P_RestoreMusic(player); // I have my doubts that this is the right place for this...
return;
}
else if (P_IsLocalPlayer(player) && player->nightstime == 10*TICRATE)
// S_StartSound(NULL, sfx_timeup); // that creepy "out of time" music from NiGHTS. Dummied out, as some on the dev team thought it wasn't Sonic-y enough (Mystic, notably). Uncomment to restore. -SH
S_ChangeMusicInternal((((maptol & TOL_NIGHTS) && !G_IsSpecialStage(gamemap)) ? "_ntime" : "_drown"), false);
{
if (mapheaderinfo[gamemap-1]->levelflags & LF_MIXNIGHTSCOUNTDOWN)
{
S_FadeMusic(0, 10*MUSICRATE);
S_StartSound(NULL, sfx_timeup); // that creepy "out of time" music from NiGHTS.
}
else
S_ChangeMusicInternal((((maptol & TOL_NIGHTS) && !G_IsSpecialStage(gamemap)) ? "_ntime" : "_drown"), false);
}
if (player->mo->z < player->mo->floorz)
player->mo->z = player->mo->floorz;

View File

@ -2818,12 +2818,23 @@ void R_StoreWallRange(INT32 start, INT32 stop)
ffloor[i].f_pos >>= 4;
#ifdef ESLOPE
ffloor[i].f_pos_slope >>= 4;
ffloor[i].f_frac = (centeryfrac>>4) - FixedMul(ffloor[i].f_pos, rw_scale);
ffloor[i].f_step = ((centeryfrac>>4) - FixedMul(ffloor[i].f_pos_slope, ds_p->scale2) - ffloor[i].f_frac)/(range);
#else
ffloor[i].f_step = FixedMul(-rw_scalestep, ffloor[i].f_pos);
ffloor[i].f_frac = (centeryfrac>>4) - FixedMul(ffloor[i].f_pos, rw_scale);
#endif
if (linedef->special == 41) // Horizon lines extend FOFs in contact with them too.
{
ffloor[i].f_step = 0;
ffloor[i].f_frac = (centeryfrac>>4);
topfrac++; // Prevent 1px HOM
}
else
{
#ifdef ESLOPE
ffloor[i].f_frac = (centeryfrac>>4) - FixedMul(ffloor[i].f_pos, rw_scale);
ffloor[i].f_step = ((centeryfrac>>4) - FixedMul(ffloor[i].f_pos_slope, ds_p->scale2) - ffloor[i].f_frac)/(range);
#else
ffloor[i].f_step = FixedMul(-rw_scalestep, ffloor[i].f_pos);
ffloor[i].f_frac = (centeryfrac>>4) - FixedMul(ffloor[i].f_pos, rw_scale);
#endif
}
}
}

View File

@ -39,6 +39,10 @@ extern INT32 msg_id;
#include "fastcmp.h"
#include "m_misc.h" // for tunes command
#if defined(HAVE_BLUA) && defined(HAVE_LUA_MUSICPLUS)
#include "lua_hook.h" // MusicChange hook
#endif
#ifdef HW3SOUND
// 3D Sound Interface
#include "hardware/hw3sound.h"
@ -1373,6 +1377,12 @@ static void *music_data;
static UINT16 music_flags;
static boolean music_looping;
static char queue_name[7];
static UINT16 queue_flags;
static boolean queue_looping;
static UINT32 queue_position;
static UINT32 queue_fadeinms;
/// ------------------------
/// Music Status
/// ------------------------
@ -1407,6 +1417,11 @@ musictype_t S_MusicType(void)
return I_SongType();
}
const char *S_MusicName(void)
{
return music_name;
}
boolean S_MusicInfo(char *mname, UINT16 *mflags, boolean *looping)
{
if (!I_SongPlaying())
@ -1437,6 +1452,35 @@ boolean S_SpeedMusic(float speed)
return I_SetSongSpeed(speed);
}
/// ------------------------
/// Music Seeking
/// ------------------------
UINT32 S_GetMusicLength(void)
{
return I_GetSongLength();
}
boolean S_SetMusicLoopPoint(UINT32 looppoint)
{
return I_SetSongLoopPoint(looppoint);
}
UINT32 S_GetMusicLoopPoint(void)
{
return I_GetSongLoopPoint();
}
boolean S_SetMusicPosition(UINT32 position)
{
return I_SetSongPosition(position);
}
UINT32 S_GetMusicPosition(void)
{
return I_GetSongPosition();
}
/// ------------------------
/// Music Playback
/// ------------------------
@ -1509,12 +1553,13 @@ static void S_UnloadMusic(void)
music_looping = false;
}
static boolean S_PlayMusic(boolean looping)
static boolean S_PlayMusic(boolean looping, UINT32 fadeinms)
{
if (S_MusicDisabled())
return false;
if (!I_PlaySong(looping))
if ((!fadeinms && !I_PlaySong(looping)) ||
(fadeinms && !I_FadeInPlaySong(fadeinms, looping)))
{
S_UnloadMusic();
return false;
@ -1524,38 +1569,93 @@ static boolean S_PlayMusic(boolean looping)
return true;
}
void S_ChangeMusic(const char *mmusic, UINT16 mflags, boolean looping)
static void S_QueueMusic(const char *mmusic, UINT16 mflags, boolean looping, UINT32 position, UINT32 fadeinms)
{
strncpy(queue_name, mmusic, 7);
queue_flags = mflags;
queue_looping = looping;
queue_position = position;
queue_fadeinms = fadeinms;
}
static void S_ClearQueue(void)
{
queue_name[0] = queue_flags = queue_looping = queue_position = queue_fadeinms = 0;
}
static void S_ChangeMusicToQueue(void)
{
S_ChangeMusicEx(queue_name, queue_flags, queue_looping, queue_position, 0, queue_fadeinms);
S_ClearQueue();
}
void S_ChangeMusicEx(const char *mmusic, UINT16 mflags, boolean looping, UINT32 position, UINT32 prefadems, UINT32 fadeinms)
{
char newmusic[7];
if (S_MusicDisabled())
return;
// No Music (empty string)
if (mmusic[0] == 0)
{
S_StopMusic();
strncpy(newmusic, mmusic, 7);
#if defined(HAVE_BLUA) && defined(HAVE_LUA_MUSICPLUS)
if(LUAh_MusicChange(music_name, newmusic, &mflags, &looping, &position, &prefadems, &fadeinms))
return;
#endif
newmusic[6] = 0;
// No Music (empty string)
if (newmusic[0] == 0)
{
if (prefadems)
I_FadeSong(0, prefadems, &S_StopMusic);
else
S_StopMusic();
return;
}
if (strnicmp(music_name, mmusic, 6))
if (prefadems && S_MusicPlaying()) // queue music change for after fade // allow even if the music is the same
{
S_StopMusic(); // shutdown old music
CONS_Debug(DBG_DETAILED, "Now fading out song %s\n", music_name);
S_QueueMusic(newmusic, mflags, looping, position, fadeinms);
I_FadeSong(0, prefadems, S_ChangeMusicToQueue);
return;
}
else if (strnicmp(music_name, newmusic, 6) || (mflags & MUSIC_FORCERESET))
{
CONS_Debug(DBG_DETAILED, "Now playing song %s\n", newmusic);
if (!S_LoadMusic(mmusic))
S_StopMusic();
if (!S_LoadMusic(newmusic))
{
CONS_Alert(CONS_ERROR, "Music %.6s could not be loaded!\n", mmusic);
CONS_Alert(CONS_ERROR, "Music %.6s could not be loaded!\n", newmusic);
return;
}
music_flags = mflags;
music_looping = looping;
if (!S_PlayMusic(looping))
{
CONS_Alert(CONS_ERROR, "Music %.6s could not be played!\n", mmusic);
if (!S_PlayMusic(looping, fadeinms))
{
CONS_Alert(CONS_ERROR, "Music %.6s could not be played!\n", newmusic);
return;
}
if (position)
I_SetSongPosition(position);
I_SetSongTrack(mflags & MUSIC_TRACKMASK);
}
else if (fadeinms) // let fades happen with same music
{
I_SetSongPosition(position);
I_FadeSong(100, fadeinms, NULL);
}
else // reset volume to 100 with same music
{
I_StopFadingSong();
I_FadeSong(100, 500, NULL);
}
I_SetSongTrack(mflags & MUSIC_TRACKMASK);
}
void S_StopMusic(void)
@ -1636,6 +1736,32 @@ void S_SetMusicVolume(INT32 digvolume, INT32 seqvolume)
}
}
/// ------------------------
/// Music Fading
/// ------------------------
void S_SetInternalMusicVolume(INT32 volume)
{
I_SetInternalMusicVolume(min(max(volume, 0), 100));
}
void S_StopFadingMusic(void)
{
I_StopFadingSong();
}
boolean S_FadeMusicFromVolume(UINT8 target_volume, INT16 source_volume, UINT32 ms)
{
if (source_volume < 0)
return I_FadeSong(target_volume, ms, NULL);
else
return I_FadeSongFromVolume(target_volume, source_volume, ms, NULL);
}
boolean S_FadeOutStopMusic(UINT32 ms)
{
return I_FadeSong(0, ms, &S_StopMusic);
}
/// ------------------------
/// Init & Others
@ -1653,22 +1779,24 @@ void S_Start(void)
strncpy(mapmusname, mapheaderinfo[gamemap-1]->musname, 7);
mapmusname[6] = 0;
mapmusflags = (mapheaderinfo[gamemap-1]->mustrack & MUSIC_TRACKMASK);
mapmusposition = mapheaderinfo[gamemap-1]->muspos;
}
if (cv_resetmusic.value)
S_StopMusic();
S_ChangeMusic(mapmusname, mapmusflags, true);
S_ChangeMusicEx(mapmusname, mapmusflags, true, mapmusposition, 0, 0);
}
static void Command_Tunes_f(void)
{
const char *tunearg;
UINT16 tunenum, track = 0;
UINT32 position = 0;
const size_t argc = COM_Argc();
if (argc < 2) //tunes slot ...
{
CONS_Printf("tunes <name/num> [track] [speed] / <-show> / <-default> / <-none>:\n");
CONS_Printf("tunes <name/num> [track] [speed] [position] / <-show> / <-default> / <-none>:\n");
CONS_Printf(M_GetText("Play an arbitrary music lump. If a map number is used, 'MAP##M' is played.\n"));
CONS_Printf(M_GetText("If the format supports multiple songs, you can specify which one to play.\n\n"));
CONS_Printf(M_GetText("* With \"-show\", shows the currently playing tune and track.\n"));
@ -1715,10 +1843,15 @@ static void Command_Tunes_f(void)
snprintf(mapmusname, 7, "%sM", G_BuildMapName(tunenum));
else
strncpy(mapmusname, tunearg, 7);
if (argc > 4)
position = (UINT32)atoi(COM_Argv(4));
mapmusname[6] = 0;
mapmusflags = (track & MUSIC_TRACKMASK);
mapmusposition = position;
S_ChangeMusic(mapmusname, mapmusflags, true);
S_ChangeMusicEx(mapmusname, mapmusflags, true, mapmusposition, 0, 0);
if (argc > 3)
{

View File

@ -140,29 +140,49 @@ boolean S_MusicDisabled(void);
boolean S_MusicPlaying(void);
boolean S_MusicPaused(void);
musictype_t S_MusicType(void);
const char *S_MusicName(void);
boolean S_MusicInfo(char *mname, UINT16 *mflags, boolean *looping);
boolean S_MusicExists(const char *mname, boolean checkMIDI, boolean checkDigi);
#define S_DigExists(a) S_MusicExists(a, false, true)
#define S_MIDIExists(a) S_MusicExists(a, true, false)
//
// Music Properties
// Music Effects
//
// Set Speed of Music
boolean S_SpeedMusic(float speed);
//
// Music Routines
// Music Seeking
//
// Get Length of Music
UINT32 S_GetMusicLength(void);
// Set LoopPoint of Music
boolean S_SetMusicLoopPoint(UINT32 looppoint);
// Get LoopPoint of Music
UINT32 S_GetMusicLoopPoint(void);
// Set Position of Music
boolean S_SetMusicPosition(UINT32 position);
// Get Position of Music
UINT32 S_GetMusicPosition(void);
//
// Music Playback
//
// Start music track, arbitrary, given its name, and set whether looping
// note: music flags 12 bits for tracknum (gme, other formats with more than one track)
// 13-15 aren't used yet
// and the last bit we ignore (internal game flag for resetting music on reload)
#define S_ChangeMusicInternal(a,b) S_ChangeMusic(a,0,b)
void S_ChangeMusic(const char *mmusic, UINT16 mflags, boolean looping);
void S_ChangeMusicEx(const char *mmusic, UINT16 mflags, boolean looping, UINT32 position, UINT32 prefadems, UINT32 fadeinms);
#define S_ChangeMusicInternal(a,b) S_ChangeMusicEx(a,0,b,0,0,0)
#define S_ChangeMusic(a,b,c) S_ChangeMusicEx(a,b,c,0,0,0)
// Stops the music.
void S_StopMusic(void);
@ -171,6 +191,17 @@ void S_StopMusic(void);
void S_PauseAudio(void);
void S_ResumeAudio(void);
//
// Music Fading
//
void S_SetInternalMusicVolume(INT32 volume);
void S_StopFadingMusic(void);
boolean S_FadeMusicFromVolume(UINT8 target_volume, INT16 source_volume, UINT32 ms);
#define S_FadeMusic(a, b) S_FadeMusicFromVolume(a, -1, b)
#define S_FadeInChangeMusic(a,b,c,d) S_ChangeMusicEx(a,b,c,0,0,d)
boolean S_FadeOutStopMusic(UINT32 ms);
//
// Updates music & sounds
//

View File

@ -75,15 +75,41 @@
UINT8 sound_started = false;
static Mix_Music *music;
static UINT8 music_volume, sfx_volume;
static UINT8 music_volume, sfx_volume, internal_volume;
static float loop_point;
static float song_length; // length in seconds
static boolean songpaused;
static UINT32 music_bytes;
static boolean is_looping;
// fading
static boolean is_fading;
static UINT8 fading_source;
static UINT8 fading_target;
static UINT32 fading_timer;
static UINT32 fading_duration;
static INT32 fading_id;
static void (*fading_callback)(void);
#ifdef HAVE_LIBGME
static Music_Emu *gme;
static INT32 current_track;
#endif
static void var_cleanup(void)
{
loop_point = song_length =\
music_bytes = fading_source = fading_target =\
fading_timer = fading_duration = 0;
songpaused = is_looping =\
is_fading = false;
fading_callback = NULL;
internal_volume = 100;
}
/// ------------------------
/// Audio System
/// ------------------------
@ -111,6 +137,8 @@ void I_StartupSound(void)
return;
}
var_cleanup();
music = NULL;
music_volume = sfx_volume = 0;
@ -336,6 +364,7 @@ void *I_GetSfx(sfxinfo_t *sfx)
len = (info->play_length * 441 / 10) << 2;
mem = malloc(len);
gme_play(emu, len >> 1, mem);
gme_free_info(info);
gme_delete(emu);
return Mix_QuickLoad_RAW((Uint8 *)mem, len);
@ -408,6 +437,7 @@ void *I_GetSfx(sfxinfo_t *sfx)
len = (info->play_length * 441 / 10) << 2;
mem = malloc(len);
gme_play(emu, len >> 1, mem);
gme_free_info(info);
gme_delete(emu);
return Mix_QuickLoad_RAW((Uint8 *)mem, len);
@ -482,14 +512,102 @@ void I_SetSfxVolume(UINT8 volume)
sfx_volume = volume;
}
/// ------------------------
/// Music Utilities
/// ------------------------
static UINT32 get_real_volume(UINT8 volume)
{
#ifdef _WIN32
if (I_SongType() == MU_MID)
// HACK: Until we stop using native MIDI,
// disable volume changes
return ((UINT32)31*128/31); // volume = 31
else
#endif
// convert volume to mixer's 128 scale
// then apply internal_volume as a percentage
return ((UINT32)volume*128/31) * (UINT32)internal_volume / 100;
}
static UINT32 get_adjusted_position(UINT32 position)
{
// all in milliseconds
UINT32 length = I_GetSongLength();
UINT32 looppoint = I_GetSongLoopPoint();
if (length)
return position >= length ? (position % (length-looppoint)) : position;
else
return position;
}
static void do_fading_callback(void)
{
if (fading_callback)
(*fading_callback)();
fading_callback = NULL;
}
/// ------------------------
/// Music Hooks
/// ------------------------
static void count_music_bytes(int chan, void *stream, int len, void *udata)
{
(void)chan;
(void)stream;
(void)udata;
if (!music || I_SongType() == MU_GME || I_SongType() == MU_MOD || I_SongType() == MU_MID)
return;
music_bytes += len;
}
static void music_loop(void)
{
Mix_PlayMusic(music, 0);
Mix_SetMusicPosition(loop_point);
if (is_looping)
{
Mix_PlayMusic(music, 0);
Mix_SetMusicPosition(loop_point);
music_bytes = loop_point*44100.0L*4; //assume 44.1khz, 4-byte length (see I_GetSongPosition)
}
else
I_StopSong();
}
static UINT32 music_fade(UINT32 interval, void *param)
{
(void)param;
if (!is_fading ||
internal_volume == fading_target ||
fading_duration == 0)
{
I_StopFadingSong();
do_fading_callback();
return 0;
}
else if (songpaused) // don't decrement timer
return interval;
else if ((fading_timer -= 10) <= 0)
{
internal_volume = fading_target;
Mix_VolumeMusic(get_real_volume(music_volume));
I_StopFadingSong();
do_fading_callback();
return 0;
}
else
{
UINT8 delta = abs(fading_target - fading_source);
fixed_t factor = FixedDiv(fading_duration - fading_timer, fading_duration);
if (fading_target < fading_source)
internal_volume = max(min(internal_volume, fading_source - FixedMul(delta, factor)), fading_target);
else if (fading_target > fading_source)
internal_volume = min(max(internal_volume, fading_source + FixedMul(delta, factor)), fading_target);
Mix_VolumeMusic(get_real_volume(music_volume));
return interval;
}
}
#ifdef HAVE_LIBGME
@ -509,7 +627,7 @@ static void mix_gme(void *udata, Uint8 *stream, int len)
// apply volume to stream
for (i = 0, p = (short *)stream; i < len/2; i++, p++)
*p = ((INT32)*p) * music_volume*2 / 42;
*p = ((INT32)*p) * (music_volume*internal_volume/100)*2 / 42;
}
#endif
@ -587,6 +705,194 @@ boolean I_SetSongSpeed(float speed)
return false;
}
/// ------------------------
/// MUSIC SEEKING
/// ------------------------
UINT32 I_GetSongLength(void)
{
INT32 length;
#ifdef HAVE_LIBGME
if (gme)
{
gme_info_t *info;
gme_err_t gme_e = gme_track_info(gme, &info, current_track);
if (gme_e != NULL)
{
CONS_Alert(CONS_ERROR, "GME error: %s\n", gme_e);
length = 0;
}
else
{
// reconstruct info->play_length, from GME source
// we only want intro + 1 loop, not 2
length = info->length;
if (length <= 0)
{
length = info->intro_length + info->loop_length; // intro + 1 loop
if (length <= 0)
length = 150 * 1000; // 2.5 minutes
}
}
gme_free_info(info);
return max(length, 0);
}
else
#endif
if (!music || I_SongType() == MU_MOD || I_SongType() == MU_MID)
return 0;
else
{
// VERY IMPORTANT to set your LENGTHMS= in your song files, folks!
// SDL mixer can't read music length itself.
length = (UINT32)(song_length*1000);
if (!length)
CONS_Debug(DBG_DETAILED, "Getting music length: music is missing LENGTHMS= tag. Needed for seeking.\n");
return length;
}
}
boolean I_SetSongLoopPoint(UINT32 looppoint)
{
if (!music || I_SongType() == MU_GME || I_SongType() == MU_MOD || I_SongType() == MU_MID || !is_looping)
return false;
else
{
UINT32 length = I_GetSongLength();
if (length > 0)
looppoint %= length;
loop_point = max((float)(looppoint / 1000.0L), 0);
return true;
}
}
UINT32 I_GetSongLoopPoint(void)
{
#ifdef HAVE_LIBGME
if (gme)
{
INT32 looppoint;
gme_info_t *info;
gme_err_t gme_e = gme_track_info(gme, &info, current_track);
if (gme_e != NULL)
{
CONS_Alert(CONS_ERROR, "GME error: %s\n", gme_e);
looppoint = 0;
}
else
looppoint = info->intro_length > 0 ? info->intro_length : 0;
gme_free_info(info);
return max(looppoint, 0);
}
else
#endif
if (!music || I_SongType() == MU_MOD || I_SongType() == MU_MID)
return 0;
else
return (UINT32)(loop_point * 1000);
}
boolean I_SetSongPosition(UINT32 position)
{
UINT32 length;
#ifdef HAVE_LIBGME
if (gme)
{
// this is unstable, so fail silently
return true;
// this isn't required technically, but GME thread-locks for a second
// if you seek too high from the counter
// length = I_GetSongLength();
// if (length)
// position = get_adjusted_position(position);
// SDL_LockAudio();
// gme_err_t gme_e = gme_seek(gme, position);
// SDL_UnlockAudio();
// if (gme_e != NULL)
// {
// CONS_Alert(CONS_ERROR, "GME error: %s\n", gme_e);
// return false;
// }
// else
// return true;
}
else
#endif
if (!music || I_SongType() == MU_MID)
return false;
else if (I_SongType() == MU_MOD)
return Mix_SetMusicPosition(position); // Goes by channels
else
{
// Because SDL mixer can't identify song length, if you have
// a position input greater than the real length, then
// music_bytes becomes inaccurate.
length = I_GetSongLength(); // get it in MS
if (length)
position = get_adjusted_position(position);
Mix_RewindMusic(); // needed for mp3
if(Mix_SetMusicPosition((float)(position/1000.0L)) == 0)
music_bytes = position/1000.0L*44100.0L*4; //assume 44.1khz, 4-byte length (see I_GetSongPosition)
else
// NOTE: This block fires on incorrect song format,
// NOT if position input is greater than song length.
music_bytes = 0;
return true;
}
}
UINT32 I_GetSongPosition(void)
{
#ifdef HAVE_LIBGME
if (gme)
{
INT32 position = gme_tell(gme);
gme_info_t *info;
gme_err_t gme_e = gme_track_info(gme, &info, current_track);
if (gme_e != NULL)
{
CONS_Alert(CONS_ERROR, "GME error: %s\n", gme_e);
return position;
}
else
{
// adjust position, since GME's counter keeps going past loop
if (info->length > 0)
position %= info->length;
else if (info->intro_length + info->loop_length > 0)
position = position >= (info->intro_length + info->loop_length) ? (position % info->loop_length) : position;
else
position %= 150 * 1000; // 2.5 minutes
}
gme_free_info(info);
return max(position, 0);
}
else
#endif
if (!music || I_SongType() == MU_MID)
return 0;
else
return music_bytes/44100.0L*1000.0L/4; //assume 44.1khz
// 4 = byte length for 16-bit samples (AUDIO_S16SYS), stereo (2-channel)
// This is hardcoded in I_StartupSound. Other formats for factor:
// 8M: 1 | 8S: 2 | 16M: 2 | 16S: 4
}
/// ------------------------
/// Music Playback
/// ------------------------
@ -596,9 +902,21 @@ boolean I_LoadSong(char *data, size_t len)
const char *key1 = "LOOP";
const char *key2 = "POINT=";
const char *key3 = "MS=";
const char *key4 = "LENGTHMS=";
const size_t key1len = strlen(key1);
const size_t key2len = strlen(key2);
const size_t key3len = strlen(key3);
const size_t key4len = strlen(key4);
// for mp3 wide chars
const char *key1w = "L\0O\0O\0P\0";
const char *key2w = "P\0O\0I\0N\0T\0\0\0\xFF\xFE";
const char *key3w = "M\0S\0\0\0\xFF\xFE";
const char *key4w = "L\0E\0N\0G\0T\0H\0M\0S\0\0\0\xFF\xFE";
const char *wterm = "\0\0";
char wval[10];
size_t wstart, wp;
char *p = data;
SDL_RWops *rw;
@ -609,6 +927,9 @@ boolean I_LoadSong(char *data, size_t len)
)
I_UnloadSong();
// always do this whether or not a music already exists
var_cleanup();
#ifdef HAVE_LIBGME
if ((UINT8)data[0] == 0x1F
&& (UINT8)data[1] == 0x8B)
@ -718,30 +1039,88 @@ boolean I_LoadSong(char *data, size_t len)
// Find the OGG loop point.
loop_point = 0.0f;
song_length = 0.0f;
while ((UINT32)(p - data) < len)
{
if (strncmp(p++, key1, key1len))
continue;
p += key1len-1; // skip OOP (the L was skipped in strncmp)
if (!strncmp(p, key2, key2len)) // is it LOOPPOINT=?
if (fpclassify(loop_point) == FP_ZERO && !strncmp(p, key1, key1len))
{
p += key2len; // skip POINT=
loop_point = (float)((44.1L+atoi(p)) / 44100.0L); // LOOPPOINT works by sample count.
// because SDL_Mixer is USELESS and can't even tell us
// something simple like the frequency of the streaming music,
// we are unfortunately forced to assume that ALL MUSIC is 44100hz.
// This means a lot of tracks that are only 22050hz for a reasonable downloadable file size will loop VERY badly.
p += key1len; // skip LOOP
if (!strncmp(p, key2, key2len)) // is it LOOPPOINT=?
{
p += key2len; // skip POINT=
loop_point = (float)((44.1L+atoi(p)) / 44100.0L); // LOOPPOINT works by sample count.
// because SDL_Mixer is USELESS and can't even tell us
// something simple like the frequency of the streaming music,
// we are unfortunately forced to assume that ALL MUSIC is 44100hz.
// This means a lot of tracks that are only 22050hz for a reasonable downloadable file size will loop VERY badly.
}
else if (!strncmp(p, key3, key3len)) // is it LOOPMS=?
{
p += key3len; // skip MS=
loop_point = (float)(atoi(p) / 1000.0L); // LOOPMS works by real time, as miliseconds.
// Everything that uses LOOPMS will work perfectly with SDL_Mixer.
}
}
else if (!strncmp(p, key3, key3len)) // is it LOOPMS=?
else if (fpclassify(song_length) == FP_ZERO && !strncmp(p, key4, key4len)) // is it LENGTHMS=?
{
p += key3len; // skip MS=
loop_point = (float)(atoi(p) / 1000.0L); // LOOPMS works by real time, as miliseconds.
// Everything that uses LOOPMS will work perfectly with SDL_Mixer.
p += key4len; // skip LENGTHMS
song_length = (float)(atoi(p) / 1000.0L);
}
// below: search MP3 or other tags that use wide char encoding
else if (fpclassify(loop_point) == FP_ZERO && !memcmp(p, key1w, key1len*2)) // LOOP wide char
{
p += key1len*2;
if (!memcmp(p, key2w, (key2len+1)*2)) // POINT= wide char
{
p += (key2len+1)*2;
wstart = (size_t)p;
wp = 0;
while (wp < 9 && memcmp(p, wterm, 2))
{
wval[wp] = *p;
p += 2;
wp = ((size_t)(p-wstart))/2;
}
wval[min(wp, 9)] = 0;
loop_point = (float)((44.1L+atoi(wval) / 44100.0L));
}
else if (!memcmp(p, key3w, (key3len+1)*2)) // MS= wide char
{
p += (key3len+1)*2;
wstart = (size_t)p;
wp = 0;
while (wp < 9 && memcmp(p, wterm, 2))
{
wval[wp] = *p;
p += 2;
wp = ((size_t)(p-wstart))/2;
}
wval[min(wp, 9)] = 0;
loop_point = (float)(atoi(wval) / 1000.0L);
}
}
else if (fpclassify(song_length) == FP_ZERO && !memcmp(p, key4w, (key4len+1)*2)) // LENGTHMS= wide char
{
p += (key4len+1)*2;
wstart = (size_t)p;
wp = 0;
while (wp < 9 && memcmp(p, wterm, 2))
{
wval[wp] = *p;
p += 2;
wp = ((size_t)(p-wstart))/2;
}
wval[min(wp, 9)] = 0;
song_length = (float)(atoi(wval) / 1000.0L);
}
// Neither?! Continue searching.
}
if (fpclassify(loop_point) != FP_ZERO && fpclassify(song_length) != FP_ZERO && song_length > loop_point) // Got what we needed
// the last case is a sanity check, in case the wide char searches were false matches.
break;
else // continue searching
p++;
}
return true;
}
@ -765,7 +1144,6 @@ void I_UnloadSong(void)
boolean I_PlaySong(boolean looping)
{
boolean lpz = fpclassify(loop_point) == FP_ZERO;
#ifdef HAVE_LIBGME
if (gme)
{
@ -779,21 +1157,37 @@ boolean I_PlaySong(boolean looping)
if (!music)
return false;
if (fpclassify(song_length) == FP_ZERO && (I_SongType() == MU_OGG || I_SongType() == MU_MP3 || I_SongType() == MU_FLAC))
CONS_Debug(DBG_DETAILED, "This song is missing a LENGTHMS= tag! Required to make seeking work properly.\n");
if (Mix_PlayMusic(music, looping && lpz ? -1 : 0) == -1)
if (I_SongType() != MU_MOD && I_SongType() != MU_MID && Mix_PlayMusic(music, 0) == -1)
{
CONS_Alert(CONS_ERROR, "Mix_PlayMusic: %s\n", Mix_GetError());
return false;
}
else if ((I_SongType() == MU_MOD || I_SongType() == MU_MID) && Mix_PlayMusic(music, looping ? -1 : 0) == -1) // if MOD, loop forever
{
CONS_Alert(CONS_ERROR, "Mix_PlayMusic: %s\n", Mix_GetError());
return false;
}
Mix_VolumeMusic((UINT32)music_volume*128/31);
if (!lpz)
Mix_HookMusicFinished(music_loop);
is_looping = looping;
I_SetMusicVolume(music_volume);
if (I_SongType() != MU_MOD && I_SongType() != MU_MID)
Mix_HookMusicFinished(music_loop); // don't bother counting if MOD
if(I_SongType() != MU_MOD && I_SongType() != MU_MID && !Mix_RegisterEffect(MIX_CHANNEL_POST, count_music_bytes, NULL, NULL))
CONS_Alert(CONS_WARNING, "Error registering SDL music position counter: %s\n", Mix_GetError());
return true;
}
void I_StopSong(void)
{
I_StopFadingSong();
#ifdef HAVE_LIBGME
if (gme)
{
@ -803,19 +1197,40 @@ void I_StopSong(void)
#endif
if (music)
{
Mix_UnregisterEffect(MIX_CHANNEL_POST, count_music_bytes);
Mix_HookMusicFinished(NULL);
Mix_HaltMusic();
}
var_cleanup();
}
void I_PauseSong(void)
{
if(I_SongType() == MU_MID) // really, SDL Mixer? why can't you pause MIDI???
return;
if(I_SongType() != MU_GME && I_SongType() != MU_MOD && I_SongType() != MU_MID)
Mix_UnregisterEffect(MIX_CHANNEL_POST, count_music_bytes);
Mix_PauseMusic();
songpaused = true;
}
void I_ResumeSong(void)
{
if (I_SongType() == MU_MID)
return;
if (I_SongType() != MU_GME && I_SongType() != MU_MOD && I_SongType() != MU_MID)
{
while(Mix_UnregisterEffect(MIX_CHANNEL_POST, count_music_bytes) != 0) { }
// HACK: fixes issue of multiple effect callbacks being registered
if(music && I_SongType() != MU_MOD && I_SongType() != MU_MID && !Mix_RegisterEffect(MIX_CHANNEL_POST, count_music_bytes, NULL, NULL))
CONS_Alert(CONS_WARNING, "Error registering SDL music position counter: %s\n", Mix_GetError());
}
Mix_ResumeMusic();
songpaused = false;
}
@ -834,7 +1249,7 @@ void I_SetMusicVolume(UINT8 volume)
#endif
music_volume = volume;
Mix_VolumeMusic((UINT32)music_volume*128/31);
Mix_VolumeMusic(get_real_volume(music_volume));
}
boolean I_SetSongTrack(int track)
@ -863,9 +1278,100 @@ boolean I_SetSongTrack(int track)
SDL_UnlockAudio();
return false;
}
else
#endif
if (I_SongType() == MU_MOD)
return !Mix_SetMusicPosition(track);
(void)track;
return false;
}
/// ------------------------
/// MUSIC FADING
/// ------------------------
void I_SetInternalMusicVolume(UINT8 volume)
{
internal_volume = volume;
if (!I_SongPlaying())
return;
Mix_VolumeMusic(get_real_volume(music_volume));
}
void I_StopFadingSong(void)
{
if (fading_id)
SDL_RemoveTimer(fading_id);
is_fading = false;
fading_source = fading_target = fading_timer = fading_duration = fading_id = 0;
}
boolean I_FadeSongFromVolume(UINT8 target_volume, UINT8 source_volume, UINT32 ms, void (*callback)(void))
{
INT16 volume_delta;
source_volume = min(source_volume, 100);
volume_delta = (INT16)(target_volume - source_volume);
I_StopFadingSong();
if (!ms && volume_delta)
{
I_SetInternalMusicVolume(target_volume);
if (callback)
(*callback)();
return true;
}
else if (!volume_delta)
{
if (callback)
(*callback)();
return true;
}
// Round MS to nearest 10
// If n - lower > higher - n, then round up
ms = (ms - ((ms / 10) * 10) > (((ms / 10) * 10) + 10) - ms) ?
(((ms / 10) * 10) + 10) // higher
: ((ms / 10) * 10); // lower
if (!ms)
I_SetInternalMusicVolume(target_volume);
else if (source_volume != target_volume)
{
fading_id = SDL_AddTimer(10, music_fade, NULL);
if (fading_id)
{
is_fading = true;
fading_timer = fading_duration = ms;
fading_source = source_volume;
fading_target = target_volume;
fading_callback = callback;
if (internal_volume != source_volume)
I_SetInternalMusicVolume(source_volume);
}
}
return is_fading;
}
boolean I_FadeSong(UINT8 target_volume, UINT32 ms, void (*callback)(void))
{
return I_FadeSongFromVolume(target_volume, internal_volume, ms, callback);
}
boolean I_FadeOutStopSong(UINT32 ms)
{
return I_FadeSongFromVolume(0, internal_volume, ms, &I_StopSong);
}
boolean I_FadeInPlaySong(UINT32 ms, boolean looping)
{
if (I_PlaySong(looping))
return I_FadeSongFromVolume(100, 0, ms, NULL);
else
return false;
}
#endif

View File

@ -1375,6 +1375,37 @@ boolean I_SetSongSpeed(float speed)
return false;
}
/// ------------------------
// MUSIC SEEKING
/// ------------------------
UINT32 I_GetSongLength(void)
{
return 0;
}
boolean I_SetSongLoopPoint(UINT32 looppoint)
{
(void)looppoint;
return false;
}
UINT32 I_GetSongLoopPoint(void)
{
return 0;
}
boolean I_SetSongPosition(UINT32 position)
{
(void)position;
return false;
}
UINT32 I_GetSongPosition(void)
{
return 0;
}
/// ------------------------
// MUSIC PLAYBACK
/// ------------------------
@ -1443,6 +1474,47 @@ boolean I_SetSongTrack(int track)
return false;
}
/// ------------------------
/// MUSIC FADING
/// ------------------------
void I_SetInternalMusicVolume(UINT8 volume)
{
(void)volume;
}
void I_StopFadingSong(void)
{
}
boolean I_FadeSongFromVolume(UINT8 target_volume, UINT8 source_volume, UINT32 ms, void (*callback)(void))
{
(void)target_volume;
(void)source_volume;
(void)ms;
return false;
}
boolean I_FadeSong(UINT8 target_volume, UINT32 ms, void (*callback)(void))
{
(void)target_volume;
(void)ms;
return false;
}
boolean I_FadeOutStopSong(UINT32 ms)
{
(void)ms;
return false;
}
boolean I_FadeInPlaySong(UINT32 ms, boolean looping)
{
(void)ms;
(void)looping;
return false;
}
/// ------------------------
// MUSIC LOADING AND CLEANUP
// \todo Split logic between loading and playing,

View File

@ -229,6 +229,7 @@ sfxinfo_t S_sfx[NUMSFX] =
{"hoop3", false, 192, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Hoop++"},
{"hidden", false, 204, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Discovery"},
{"prloop", false, 104, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Gust of wind"},
{"timeup", true, 256, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Ominous Countdown"},
{"ngjump", false, 96, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Jump"},
{"peww", false, 96, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Pew"},

View File

@ -295,6 +295,7 @@ typedef enum
sfx_hoop3,
sfx_hidden,
sfx_prloop,
sfx_timeup,
sfx_ngjump,
sfx_peww,

View File

@ -815,6 +815,60 @@ void I_SetMusicVolume(UINT8 volume)
FMR_MUSIC(FMOD_Channel_SetVolume(music_channel, music_volume / 31.0));
}
UINT32 I_GetSongLength(void)
{
UINT32 length;
if (I_SongType() == MU_MID)
return 0;
FMR_MUSIC(FMOD_Sound_GetLength(music_stream, &length, FMOD_TIMEUNIT_MS));
return length;
}
boolean I_SetSongLoopPoint(UINT32 looppoint)
{
(void)looppoint;
return false;
}
UINT32 I_GetSongLoopPoint(void)
{
return 0;
}
boolean I_SetSongPosition(UINT32 position)
{
FMOD_RESULT e;
if(I_SongType() == MU_MID)
// Dummy out; this works for some MIDI, but not others.
// SDL does not support this for any MIDI.
return false;
e = FMOD_Channel_SetPosition(music_channel, position, FMOD_TIMEUNIT_MS);
if (e == FMOD_OK)
return true;
else if (e == FMOD_ERR_UNSUPPORTED // Only music modules, numbnuts!
|| e == FMOD_ERR_INVALID_POSITION) // Out-of-bounds!
return false;
else // Congrats, you horribly broke it somehow
{
FMR_MUSIC(e);
return false;
}
}
UINT32 I_GetSongPosition(void)
{
FMOD_RESULT e;
unsigned int fmposition = 0;
if(I_SongType() == MU_MID)
// Dummy out because unsupported, even though FMOD does this correctly.
return 0;
e = FMOD_Channel_GetPosition(music_channel, &fmposition, FMOD_TIMEUNIT_MS);
if (e == FMOD_OK)
return (UINT32)fmposition;
else
return 0;
}
boolean I_SetSongTrack(INT32 track)
{
if (track != current_track) // If the track's already playing, then why bother?
@ -859,3 +913,46 @@ boolean I_SetSongTrack(INT32 track)
}
return false;
}
/// ------------------------
/// MUSIC FADING
/// ------------------------
void I_SetInternalMusicVolume(UINT8 volume)
{
(void)volume;
}
void I_StopFadingSong(void)
{
}
boolean I_FadeSongFromVolume(UINT8 target_volume, UINT8 source_volume, UINT32 ms, void (*callback)(void))
{
(void)target_volume;
(void)source_volume;
(void)ms;
(void)callback;
return false;
}
boolean I_FadeSong(UINT8 target_volume, UINT32 ms, void (*callback)(void))
{
(void)target_volume;
(void)ms;
(void)callback;
return false;
}
boolean I_FadeOutStopSong(UINT32 ms)
{
(void)ms;
return false;
}
boolean I_FadeInPlaySong(UINT32 ms, boolean looping)
{
(void)ms;
(void)looping;
return false;
}

View File

@ -833,7 +833,17 @@ void Y_Ticker(void)
if (!intertic) // first time only
{
S_ChangeMusicInternal("_clear", false); // don't loop it
if (mapheaderinfo[gamemap-1]->musinterfadeout
#ifdef _WIN32
// can't fade midi due to win32 volume hack
&& S_MusicType() != MU_MID
#endif
)
S_FadeOutStopMusic(mapheaderinfo[gamemap-1]->musinterfadeout);
else if (mapheaderinfo[gamemap-1]->musintername[0] && S_MusicExists(mapheaderinfo[gamemap-1]->musintername, !midi_disabled, !digital_disabled))
S_ChangeMusicInternal(mapheaderinfo[gamemap-1]->musintername, false); // don't loop it
else
S_ChangeMusicInternal("_clear", false); // don't loop it
tallydonetic = -1;
}
@ -898,7 +908,17 @@ void Y_Ticker(void)
if (!intertic) // first time only
{
S_ChangeMusicInternal("_clear", false); // don't loop it
if (mapheaderinfo[gamemap-1]->musinterfadeout
#ifdef _WIN32
// can't fade midi due to win32 volume hack
&& S_MusicType() != MU_MID
#endif
)
S_FadeOutStopMusic(mapheaderinfo[gamemap-1]->musinterfadeout);
else if (mapheaderinfo[gamemap-1]->musintername[0] && S_MusicExists(mapheaderinfo[gamemap-1]->musintername, !midi_disabled, !digital_disabled))
S_ChangeMusicInternal(mapheaderinfo[gamemap-1]->musintername, false); // don't loop it
else
S_ChangeMusicInternal("_clear", false); // don't loop it
tallydonetic = -1;
}