From 1595bf30c6ab48f435ec80927023a06b498c80f1 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 23 Aug 2019 08:31:49 +0200 Subject: [PATCH 1/5] Revert "- removed a few redundant includes" This reverts commit 7cd5bd97737a5c40b89abc52f3149b177c03eaee. This commit was only meant for testing, not for publishing --- src/sound/mididevices/music_win_mididevice.cpp | 1 + src/sound/music/i_music.h | 1 + src/sound/music/i_musicinterns.h | 1 + src/sound/timidity/instrum_dls.cpp | 1 + src/sound/timidity/instrum_sf2.cpp | 1 + 5 files changed, 5 insertions(+) diff --git a/src/sound/mididevices/music_win_mididevice.cpp b/src/sound/mididevices/music_win_mididevice.cpp index 1bc42116e2..94c8a0b36a 100644 --- a/src/sound/mididevices/music_win_mididevice.cpp +++ b/src/sound/mididevices/music_win_mididevice.cpp @@ -42,6 +42,7 @@ #include "i_musicinterns.h" #include "templates.h" +#include "doomdef.h" #include "m_swap.h" #include "doomerrors.h" diff --git a/src/sound/music/i_music.h b/src/sound/music/i_music.h index 714cbd95fd..421bf1355a 100644 --- a/src/sound/music/i_music.h +++ b/src/sound/music/i_music.h @@ -34,6 +34,7 @@ #ifndef __I_MUSIC_H__ #define __I_MUSIC_H__ +#include "doomdef.h" #include "i_soundinternal.h" class FileReader; diff --git a/src/sound/music/i_musicinterns.h b/src/sound/music/i_musicinterns.h index 53d2b81a73..09bba62dca 100644 --- a/src/sound/music/i_musicinterns.h +++ b/src/sound/music/i_musicinterns.h @@ -5,6 +5,7 @@ #include "mus2midi.h" #include "i_sound.h" #include "i_music.h" +#include "s_sound.h" #include "files.h" #include "wildmidi/wildmidi_lib.h" #include "midisources/midisource.h" diff --git a/src/sound/timidity/instrum_dls.cpp b/src/sound/timidity/instrum_dls.cpp index 1ddf666074..bc6b5b5d27 100644 --- a/src/sound/timidity/instrum_dls.cpp +++ b/src/sound/timidity/instrum_dls.cpp @@ -26,6 +26,7 @@ #include #include "timidity.h" +#include "doomdef.h" #define __Sound_SetError(x) diff --git a/src/sound/timidity/instrum_sf2.cpp b/src/sound/timidity/instrum_sf2.cpp index 87b5ee4bea..3f50f15750 100644 --- a/src/sound/timidity/instrum_sf2.cpp +++ b/src/sound/timidity/instrum_sf2.cpp @@ -4,6 +4,7 @@ #include #include +#include "doomdef.h" #include "m_swap.h" #include "templates.h" #include "timidity.h" From 80ef9ca686fb91dff53f4c2e5a6f9cebc510f368 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Fri, 23 Aug 2019 12:11:25 +0300 Subject: [PATCH 2/5] - set locale to US English UTF-8 for POSIX targets Locale-dependent standard library functions didn't treat UTF-8 strings correctly, e.g. iswalpha() returns 0 for any non-latin letter The same function from MSVC runtime classifies such characters as alphabetic even with C locale https://forum.zdoom.org/viewtopic.php?t=65641&start=18#p1115930 --- src/posix/cocoa/i_main.mm | 4 ++-- src/posix/sdl/i_main.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/posix/cocoa/i_main.mm b/src/posix/cocoa/i_main.mm index 5b4ea31b7e..a5e7db2f4b 100644 --- a/src/posix/cocoa/i_main.mm +++ b/src/posix/cocoa/i_main.mm @@ -199,8 +199,8 @@ int OriginalMain(int argc, char** argv) // Set LC_NUMERIC environment variable in case some library decides to // clear the setlocale call at least this will be correct. // Note that the LANG environment variable is overridden by LC_* - setenv("LC_NUMERIC", "C", 1); - setlocale(LC_ALL, "C"); + setenv("LC_NUMERIC", "en_US.UTF-8", 1); + setlocale(LC_ALL, "en_US.UTF-8"); // Set reasonable default values for video settings diff --git a/src/posix/sdl/i_main.cpp b/src/posix/sdl/i_main.cpp index 5720942171..c17ed8be73 100644 --- a/src/posix/sdl/i_main.cpp +++ b/src/posix/sdl/i_main.cpp @@ -170,9 +170,9 @@ int main (int argc, char **argv) // Set LC_NUMERIC environment variable in case some library decides to // clear the setlocale call at least this will be correct. // Note that the LANG environment variable is overridden by LC_* - setenv ("LC_NUMERIC", "C", 1); + setenv ("LC_NUMERIC", "en_US.UTF-8", 1); - setlocale (LC_ALL, "C"); + setlocale (LC_ALL, "en_US.UTF-8"); if (SDL_Init (0) < 0) { From 179e526981e64fd1d2f2dddabaaf30e183aef649 Mon Sep 17 00:00:00 2001 From: PaulyB <43163391+3saster@users.noreply.github.com> Date: Fri, 23 Aug 2019 01:41:26 -0700 Subject: [PATCH 3/5] Let Hexen Cleric and Mage use unique health chains - (changed slightly by Rachelle) Hexen's characters incorrectly only used the Fighter's health chain previously. --- wadsrc/static/zscript/ui/statusbar/hexen_sbar.zs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/wadsrc/static/zscript/ui/statusbar/hexen_sbar.zs b/wadsrc/static/zscript/ui/statusbar/hexen_sbar.zs index 26794e9338..0e7723e21b 100644 --- a/wadsrc/static/zscript/ui/statusbar/hexen_sbar.zs +++ b/wadsrc/static/zscript/ui/statusbar/hexen_sbar.zs @@ -105,13 +105,13 @@ class HexenStatusBar : BaseStatusBar { DrawImage("H2BAR", (0, 134), DI_ITEM_OFFSETS); - String Gem; - if (CPlayer.mo is "ClericPlayer") Gem = "LIFEGMC2"; - else if (CPlayer.mo is "MagePlayer") Gem = "LIFEGMM2"; - else Gem = "LIFEGMF2"; + String Gem, Chain; + if (CPlayer.mo is "ClericPlayer") { Gem = "LIFEGMC2"; Chain = "CHAIN2"; } + else if (CPlayer.mo is "MagePlayer") { Gem = "LIFEGMM2"; Chain = "CHAIN3"; } + else { Gem = "LIFEGMF2"; Chain = "CHAIN"; } int inthealth = mHealthInterpolator2.GetValue(); - DrawGem("CHAIN", "LIFEGMF2", inthealth, CPlayer.mo.GetMaxHealth(true), (30, 193), -23, 49, 15, (multiplayer? DI_TRANSLATABLE : 0) | DI_ITEM_LEFT_TOP); + DrawGem(Chain, Gem, inthealth, CPlayer.mo.GetMaxHealth(true), (30, 193), -23, 49, 15, (multiplayer? DI_TRANSLATABLE : 0) | DI_ITEM_LEFT_TOP); DrawImage("LFEDGE", (0, 192), DI_ITEM_OFFSETS); DrawImage("RTEDGE", (277, 192), DI_ITEM_OFFSETS); From 9456eeb8ecf93717d9654c200fb6b5ca7162cca5 Mon Sep 17 00:00:00 2001 From: Rachael Alexanderson Date: Fri, 23 Aug 2019 05:56:10 -0400 Subject: [PATCH 4/5] - oops, this didn't get through --- .../static/zscript/ui/statusbar/hexen_sbar.zs | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/wadsrc/static/zscript/ui/statusbar/hexen_sbar.zs b/wadsrc/static/zscript/ui/statusbar/hexen_sbar.zs index 0e7723e21b..8286f419fe 100644 --- a/wadsrc/static/zscript/ui/statusbar/hexen_sbar.zs +++ b/wadsrc/static/zscript/ui/statusbar/hexen_sbar.zs @@ -106,9 +106,21 @@ class HexenStatusBar : BaseStatusBar DrawImage("H2BAR", (0, 134), DI_ITEM_OFFSETS); String Gem, Chain; - if (CPlayer.mo is "ClericPlayer") { Gem = "LIFEGMC2"; Chain = "CHAIN2"; } - else if (CPlayer.mo is "MagePlayer") { Gem = "LIFEGMM2"; Chain = "CHAIN3"; } - else { Gem = "LIFEGMF2"; Chain = "CHAIN"; } + if (CPlayer.mo is "ClericPlayer") + { + Gem = "LIFEGMC2"; + Chain = "CHAIN2"; + } + else if (CPlayer.mo is "MagePlayer") + { + Gem = "LIFEGMM2"; + Chain = "CHAIN3"; + } + else + { + Gem = "LIFEGMF2"; + Chain = "CHAIN"; + } int inthealth = mHealthInterpolator2.GetValue(); DrawGem(Chain, Gem, inthealth, CPlayer.mo.GetMaxHealth(true), (30, 193), -23, 49, 15, (multiplayer? DI_TRANSLATABLE : 0) | DI_ITEM_LEFT_TOP); From 66db8948665b6f79d27384df68933a6311e2e8e0 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 23 Aug 2019 17:15:19 +0200 Subject: [PATCH 5/5] - split off all music code from s_sound.cpp --- src/CMakeLists.txt | 1 + src/console/c_console.cpp | 2 + src/d_main.cpp | 4 + src/d_net.cpp | 1 + src/g_level.cpp | 8 + src/g_levellocals.h | 7 +- src/intermission/intermission.cpp | 3 +- src/p_saveg.cpp | 1 + src/p_setup.cpp | 2 + src/playsim/a_dynlight.cpp | 1 - src/playsim/fragglescript/t_func.cpp | 1 + src/playsim/fragglescript/t_load.cpp | 1 + src/playsim/p_acs.cpp | 1 + src/playsim/p_user.cpp | 1 + src/posix/cocoa/i_main.mm | 1 + src/sound/backend/i_sound.cpp | 1 + src/sound/music/i_music.cpp | 1 + src/sound/music/music_midi_base.cpp | 1 + src/sound/s_advsound.cpp | 1 + src/sound/s_music.cpp | 872 +++++++++++++++++++++++++++ src/sound/s_music.h | 88 +++ src/sound/s_sound.cpp | 850 +++----------------------- src/sound/s_sound.h | 38 +- src/win32/i_main.cpp | 1 + src/win32/st_start.cpp | 1 + 25 files changed, 1078 insertions(+), 811 deletions(-) create mode 100644 src/sound/s_music.cpp create mode 100644 src/sound/s_music.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b8531384bb..fda0c0007f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1001,6 +1001,7 @@ set (PCH_SOURCES sound/s_environment.cpp sound/s_sndseq.cpp sound/s_sound.cpp + sound/s_music.cpp serializer.cpp scriptutil.cpp st_stuff.cpp diff --git a/src/console/c_console.cpp b/src/console/c_console.cpp index 4a0b2ab0de..f15989a6ba 100644 --- a/src/console/c_console.cpp +++ b/src/console/c_console.cpp @@ -64,6 +64,7 @@ #include "g_levellocals.h" #include "vm.h" #include "utf8.h" +#include "s_music.h" #include "gi.h" @@ -1268,6 +1269,7 @@ void C_FullConsole () gamestate = GS_FULLCONSOLE; primaryLevel->Music = ""; S_Start (); + S_StartMusic(); P_FreeLevelData (); } else diff --git a/src/d_main.cpp b/src/d_main.cpp index 1aa67e9b48..44cb3d0060 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -102,6 +102,7 @@ #include "g_cvars.h" #include "r_data/r_vanillatrans.h" #include "atterm.h" +#include "s_music.h" EXTERN_CVAR(Bool, hud_althud) EXTERN_CVAR(Int, vr_mode) @@ -1034,6 +1035,7 @@ void D_DoomLoop () // Update display, next frame, with current state. I_StartTic (); D_Display (); + S_UpdateMusic(); if (wantToRestart) { wantToRestart = false; @@ -2459,6 +2461,7 @@ void D_DoomMain (void) if (!batchrun) Printf ("S_Init: Setting up sound.\n"); S_Init (); + S_InitMusic(); if (!batchrun) Printf ("ST_Init: Init startup screen.\n"); if (!restart) @@ -2752,6 +2755,7 @@ void D_DoomMain (void) R_DeinitTranslationTables(); // some tables are initialized from outside the translation code. gameinfo.~gameinfo_t(); new (&gameinfo) gameinfo_t; // Reset gameinfo + S_ShutdownMusic(); S_Shutdown(); // free all channels and delete playlist C_ClearAliases(); // CCMDs won't be reinitialized so these need to be deleted here DestroyCVarsFlagged(CVAR_MOD); // Delete any cvar left by mods diff --git a/src/d_net.cpp b/src/d_net.cpp index bcf3153006..95e1cd7562 100644 --- a/src/d_net.cpp +++ b/src/d_net.cpp @@ -67,6 +67,7 @@ #include "i_system.h" #include "vm.h" #include "gstrings.h" +#include "s_music.h" EXTERN_CVAR (Int, disableautosave) EXTERN_CVAR (Int, autosavecount) diff --git a/src/g_level.cpp b/src/g_level.cpp index 6cf4adad1a..909e73cdb8 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -89,6 +89,7 @@ #include "actorinlines.h" #include "i_time.h" #include "p_maputl.h" +#include "s_music.h" void STAT_StartNewGame(const char *lev); void STAT_ChangeLevel(const char *newl, FLevelLocals *Level); @@ -2221,3 +2222,10 @@ int IsPointInMap(FLevelLocals *Level, double x, double y, double z) return true; } + +void FLevelLocals::SetMusic() +{ + if (cdtrack == 0 || !S_ChangeCDMusic(cdtrack, cdid)) + S_ChangeMusic(Music, musicorder); +} + diff --git a/src/g_levellocals.h b/src/g_levellocals.h index ff7749b37d..ad29e78bd7 100644 --- a/src/g_levellocals.h +++ b/src/g_levellocals.h @@ -424,11 +424,8 @@ public: return thinker; } - void SetMusic() - { - if (cdtrack == 0 || !S_ChangeCDMusic(cdtrack, cdid)) - S_ChangeMusic(Music, musicorder); - } + void SetMusic(); + TArray vertexes; TArray sectors; diff --git a/src/intermission/intermission.cpp b/src/intermission/intermission.cpp index 290dae96e9..fa09541317 100644 --- a/src/intermission/intermission.cpp +++ b/src/intermission/intermission.cpp @@ -51,6 +51,7 @@ #include "g_levellocals.h" #include "utf8.h" #include "templates.h" +#include "s_music.h" FIntermissionDescriptorList IntermissionDescriptors; @@ -1100,4 +1101,4 @@ CCMD(measureintermissions) } } } -} \ No newline at end of file +} diff --git a/src/p_saveg.cpp b/src/p_saveg.cpp index b842e23b6f..025ca18a4b 100644 --- a/src/p_saveg.cpp +++ b/src/p_saveg.cpp @@ -59,6 +59,7 @@ #include "r_sky.h" #include "version.h" #include "fragglescript/t_script.h" +#include "s_music.h" EXTERN_CVAR(Bool, save_formatted) diff --git a/src/p_setup.cpp b/src/p_setup.cpp index 714cb4eba9..814052a306 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -76,6 +76,7 @@ #include "v_video.h" #include "fragglescript/t_script.h" #include "atterm.h" +#include "s_music.h" extern AActor *SpawnMapThing (int index, FMapThing *mthing, int position); @@ -407,6 +408,7 @@ void P_SetupLevel(FLevelLocals *Level, int position, bool newGame) // Make sure all sounds are stopped before Z_FreeTags. S_Start(); + S_StartMusic(); // [RH] clear out the mid-screen message C_MidPrint(nullptr, nullptr); diff --git a/src/playsim/a_dynlight.cpp b/src/playsim/a_dynlight.cpp index 9aea2689ae..686230e0b2 100644 --- a/src/playsim/a_dynlight.cpp +++ b/src/playsim/a_dynlight.cpp @@ -989,4 +989,3 @@ void FLevelLocals::RecreateAllAttachedLights() } } } - diff --git a/src/playsim/fragglescript/t_func.cpp b/src/playsim/fragglescript/t_func.cpp index c0804ffba0..ee41d0d9c6 100644 --- a/src/playsim/fragglescript/t_func.cpp +++ b/src/playsim/fragglescript/t_func.cpp @@ -51,6 +51,7 @@ #include "scriptutil.h" #include "vm.h" #include "a_lights.h" +#include "s_music.h" static FRandom pr_script("FScript"); diff --git a/src/playsim/fragglescript/t_load.cpp b/src/playsim/fragglescript/t_load.cpp index 7f5d8024f7..8d2b5d6d77 100644 --- a/src/playsim/fragglescript/t_load.cpp +++ b/src/playsim/fragglescript/t_load.cpp @@ -34,6 +34,7 @@ #include "g_levellocals.h" #include "xlat/xlat.h" #include "maploader/maploader.h" +#include "s_music.h" class FScriptLoader { diff --git a/src/playsim/p_acs.cpp b/src/playsim/p_acs.cpp index 23d7342bfa..0cb77f19e8 100644 --- a/src/playsim/p_acs.cpp +++ b/src/playsim/p_acs.cpp @@ -75,6 +75,7 @@ #include "actorinlines.h" #include "types.h" #include "scriptutil.h" +#include "s_music.h" // P-codes for ACS scripts enum diff --git a/src/playsim/p_user.cpp b/src/playsim/p_user.cpp index 6578c2c99a..1ad68b098d 100644 --- a/src/playsim/p_user.cpp +++ b/src/playsim/p_user.cpp @@ -91,6 +91,7 @@ #include "g_game.h" #include "v_video.h" #include "gstrings.h" +#include "s_music.h" static FRandom pr_skullpop ("SkullPop"); diff --git a/src/posix/cocoa/i_main.mm b/src/posix/cocoa/i_main.mm index 5b4ea31b7e..90e03267f9 100644 --- a/src/posix/cocoa/i_main.mm +++ b/src/posix/cocoa/i_main.mm @@ -46,6 +46,7 @@ #include "st_console.h" #include "version.h" #include "doomerrors.h" +#include "s_music.h" #define ZD_UNUSED(VARIABLE) ((void)(VARIABLE)) diff --git a/src/sound/backend/i_sound.cpp b/src/sound/backend/i_sound.cpp index c7aae60ec2..f2e5759706 100644 --- a/src/sound/backend/i_sound.cpp +++ b/src/sound/backend/i_sound.cpp @@ -48,6 +48,7 @@ #include "v_text.h" #include "c_cvars.h" #include "stats.h" +#include "s_music.h" EXTERN_CVAR (Float, snd_sfxvolume) EXTERN_CVAR (Float, snd_musicvolume) diff --git a/src/sound/music/i_music.cpp b/src/sound/music/i_music.cpp index f4b932695d..320495b75f 100644 --- a/src/sound/music/i_music.cpp +++ b/src/sound/music/i_music.cpp @@ -47,6 +47,7 @@ #include "stats.h" #include "timidity/timidity.h" #include "vm.h" +#include "s_music.h" diff --git a/src/sound/music/music_midi_base.cpp b/src/sound/music/music_midi_base.cpp index 7a3071fdfb..13e2d55843 100644 --- a/src/sound/music/music_midi_base.cpp +++ b/src/sound/music/music_midi_base.cpp @@ -36,6 +36,7 @@ #include "v_text.h" #include "menu/menu.h" +#include "s_music.h" static uint32_t nummididevices; static bool nummididevicesset; diff --git a/src/sound/s_advsound.cpp b/src/sound/s_advsound.cpp index b869473a2b..8a7d10947a 100644 --- a/src/sound/s_advsound.cpp +++ b/src/sound/s_advsound.cpp @@ -49,6 +49,7 @@ #include "vm.h" #include "i_system.h" #include "atterm.h" +#include "s_music.h" // MACROS ------------------------------------------------------------------ diff --git a/src/sound/s_music.cpp b/src/sound/s_music.cpp new file mode 100644 index 0000000000..f668b6afb5 --- /dev/null +++ b/src/sound/s_music.cpp @@ -0,0 +1,872 @@ +//----------------------------------------------------------------------------- +// +// Copyright 1993-1996 id Software +// Copyright 1999-2016 Randy Heit +// Copyright 2002-2016 Christoph Oelckers +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// 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, see http://www.gnu.org/licenses/ +// +//----------------------------------------------------------------------------- +// +// DESCRIPTION: none +// +//----------------------------------------------------------------------------- + +/* For code that originates from ZDoom the following applies: +** +**--------------------------------------------------------------------------- +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +*/ + +#include +#include +#ifdef _WIN32 +#include +#endif + +#include "i_system.h" +#include "i_sound.h" +#include "i_music.h" +#include "i_cd.h" +#include "s_sound.h" +#include "s_sndseq.h" +#include "s_playlist.h" +#include "c_dispatch.h" +#include "m_random.h" +#include "w_wad.h" +#include "p_local.h" +#include "doomstat.h" +#include "cmdlib.h" +#include "v_video.h" +#include "v_text.h" +#include "a_sharedglobal.h" +#include "gstrings.h" +#include "gi.h" +#include "po_man.h" +#include "serializer.h" +#include "d_player.h" +#include "g_levellocals.h" +#include "vm.h" +#include "g_game.h" +#include "atterm.h" +#include "s_music.h" + +// MACROS ------------------------------------------------------------------ + + +// EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- + +extern float S_GetMusicVolume (const char *music); + +static void S_ActivatePlayList(bool goBack); + +// PRIVATE DATA DEFINITIONS ------------------------------------------------ + +static bool MusicPaused; // whether music is paused +MusPlayingInfo mus_playing; // music currently being played +static FString LastSong; // last music that was played +static FPlayList *PlayList; + +DEFINE_GLOBAL_NAMED(mus_playing, musplaying); +DEFINE_FIELD_X(MusPlayingInfo, MusPlayingInfo, name); +DEFINE_FIELD_X(MusPlayingInfo, MusPlayingInfo, baseorder); +DEFINE_FIELD_X(MusPlayingInfo, MusPlayingInfo, loop); + +// PUBLIC DATA DEFINITIONS ------------------------------------------------- +void S_ShutdownMusic (); + +// CODE -------------------------------------------------------------------- + +//========================================================================== +// +// S_Init +// +// Initializes sound stuff, including volume. Sets channels, SFX and +// music volume, allocates channel buffer, and sets S_sfx lookup. +//========================================================================== + +void S_InitMusic () +{ + // no sounds are playing, and they are not paused + mus_playing.name = ""; + LastSong = ""; + mus_playing.handle = nullptr; + mus_playing.baseorder = 0; + MusicPaused = false; + atterm(S_ShutdownMusic); +} + +//========================================================================== +// +// S_Shutdown +// +//========================================================================== + +void S_ShutdownMusic () +{ + if (PlayList != nullptr) + { + delete PlayList; + PlayList = nullptr; + } + S_StopMusic (true); + mus_playing.name = ""; + LastSong = ""; +} + +//========================================================================== +// +// S_PauseSound +// +// Stop music and sound effects, during game PAUSE. +//========================================================================== + +void S_PauseMusic () +{ + if (mus_playing.handle && !MusicPaused) + { + mus_playing.handle->Pause(); + MusicPaused = true; + } +} + +//========================================================================== +// +// S_ResumeSound +// +// Resume music and sound effects, after game PAUSE. +//========================================================================== + +void S_ResumeMusic () +{ + if (mus_playing.handle && MusicPaused) + { + mus_playing.handle->Resume(); + MusicPaused = false; + } +} + +//========================================================================== +// +// S_UpdateSound +// +//========================================================================== + +void S_UpdateMusic () +{ + I_UpdateMusic(); + + // [RH] Update music and/or playlist. IsPlaying() must be called + // to attempt to reconnect to broken net streams and to advance the + // playlist when the current song finishes. + if (mus_playing.handle != nullptr && + !mus_playing.handle->IsPlaying() && + PlayList) + { + PlayList->Advance(); + S_ActivatePlayList(false); + } +} + +//========================================================================== +// +// S_Start +// +// Per level startup code. Kills playing sounds at start of level +// and starts new music. +//========================================================================== + +void S_StartMusic () +{ + // stop the old music if it has been paused. + // This ensures that the new music is started from the beginning + // if it's the same as the last one and it has been paused. + if (MusicPaused) S_StopMusic(true); + + // start new music for the level + MusicPaused = false; + + // Don't start the music if loading a savegame, because the music is stored there. + // Don't start the music if revisiting a level in a hub for the same reason. + if (!primaryLevel->IsReentering()) + { + primaryLevel->SetMusic(); + } +} + + +//========================================================================== +// +// S_ActivatePlayList +// +// Plays the next song in the playlist. If no songs in the playlist can be +// played, then it is deleted. +//========================================================================== + +void S_ActivatePlayList (bool goBack) +{ + int startpos, pos; + + startpos = pos = PlayList->GetPosition (); + S_StopMusic (true); + while (!S_ChangeMusic (PlayList->GetSong (pos), 0, false, true)) + { + pos = goBack ? PlayList->Backup () : PlayList->Advance (); + if (pos == startpos) + { + delete PlayList; + PlayList = nullptr; + Printf ("Cannot play anything in the playlist.\n"); + return; + } + } +} + +//========================================================================== +// +// S_ChangeCDMusic +// +// Starts a CD track as music. +//========================================================================== + +bool S_ChangeCDMusic (int track, unsigned int id, bool looping) +{ + char temp[32]; + + if (id != 0) + { + mysnprintf (temp, countof(temp), ",CD,%d,%x", track, id); + } + else + { + mysnprintf (temp, countof(temp), ",CD,%d", track); + } + return S_ChangeMusic (temp, 0, looping); +} + +//========================================================================== +// +// S_StartMusic +// +// Starts some music with the given name. +//========================================================================== + +bool S_StartMusic (const char *m_id) +{ + return S_ChangeMusic (m_id, 0, false); +} + +//========================================================================== +// +// S_ChangeMusic +// +// Starts playing a music, possibly looping. +// +// [RH] If music is a MOD, starts it at position order. If name is of the +// format ",CD,,[cd id]" song is a CD track, and if [cd id] is +// specified, it will only be played if the specified CD is in a drive. +//========================================================================== + +bool S_ChangeMusic (const char *musicname, int order, bool looping, bool force) +{ + if (!force && PlayList) + { // Don't change if a playlist is active + return false; + } + + // allow specifying "*" as a placeholder to play the level's default music. + if (musicname != nullptr && !strcmp(musicname, "*")) + { + if (gamestate == GS_LEVEL || gamestate == GS_TITLELEVEL) + { + musicname = primaryLevel->Music; + order = primaryLevel->musicorder; + } + else + { + musicname = nullptr; + } + } + + if (musicname == nullptr || musicname[0] == 0) + { + // Don't choke if the map doesn't have a song attached + S_StopMusic (true); + mus_playing.name = ""; + LastSong = ""; + return true; + } + + FString DEH_Music; + if (musicname[0] == '$') + { + // handle dehacked replacement. + // Any music name defined this way needs to be prefixed with 'D_' because + // Doom.exe does not contain the prefix so these strings don't either. + const char * mus_string = GStrings[musicname+1]; + if (mus_string != nullptr) + { + DEH_Music << "D_" << mus_string; + musicname = DEH_Music; + } + } + + FName *aliasp = MusicAliases.CheckKey(musicname); + if (aliasp != nullptr) + { + if (*aliasp == NAME_None) + { + return true; // flagged to be ignored + } + musicname = aliasp->GetChars(); + } + + if (!mus_playing.name.IsEmpty() && + mus_playing.handle != nullptr && + stricmp (mus_playing.name, musicname) == 0 && + mus_playing.handle->m_Looping == looping) + { + if (order != mus_playing.baseorder) + { + if (mus_playing.handle->SetSubsong(order)) + { + mus_playing.baseorder = order; + } + } + else if (!mus_playing.handle->IsPlaying()) + { + mus_playing.handle->Play(looping, order); + } + return true; + } + + if (strnicmp (musicname, ",CD,", 4) == 0) + { + int track = strtoul (musicname+4, nullptr, 0); + const char *more = strchr (musicname+4, ','); + unsigned int id = 0; + + if (more != nullptr) + { + id = strtoul (more+1, nullptr, 16); + } + S_StopMusic (true); + mus_playing.handle = I_RegisterCDSong (track, id); + } + else + { + int lumpnum = -1; + int length = 0; + MusInfo *handle = nullptr; + MidiDeviceSetting *devp = MidiDevices.CheckKey(musicname); + + // Strip off any leading file:// component. + if (strncmp(musicname, "file://", 7) == 0) + { + musicname += 7; + } + + FileReader reader; + if (!FileExists (musicname)) + { + if ((lumpnum = Wads.CheckNumForFullName (musicname, true, ns_music)) == -1) + { + Printf ("Music \"%s\" not found\n", musicname); + return false; + } + if (handle == nullptr) + { + if (Wads.LumpLength (lumpnum) == 0) + { + return false; + } + reader = Wads.ReopenLumpReader(lumpnum); + } + } + else + { + // Load an external file. + if (!reader.OpenFile(musicname)) + { + return false; + } + } + + // shutdown old music + S_StopMusic (true); + + // Just record it if volume is 0 + if (snd_musicvolume <= 0) + { + mus_playing.loop = looping; + mus_playing.name = musicname; + mus_playing.baseorder = order; + LastSong = musicname; + return true; + } + + // load & register it + if (handle != nullptr) + { + mus_playing.handle = handle; + } + else + { + mus_playing.handle = I_RegisterSong (reader, devp); + } + } + + mus_playing.loop = looping; + mus_playing.name = musicname; + mus_playing.baseorder = 0; + LastSong = ""; + + if (mus_playing.handle != 0) + { // play it + mus_playing.handle->Start(looping, S_GetMusicVolume (musicname), order); + mus_playing.baseorder = order; + return true; + } + return false; +} + +DEFINE_ACTION_FUNCTION(DObject, S_ChangeMusic) +{ + PARAM_PROLOGUE; + PARAM_STRING(music); + PARAM_INT(order); + PARAM_BOOL(looping); + PARAM_BOOL(force); + ACTION_RETURN_BOOL(S_ChangeMusic(music, order, looping, force)); +} + + +//========================================================================== +// +// S_RestartMusic +// +// Must only be called from snd_reset in i_sound.cpp! +//========================================================================== + +void S_RestartMusic () +{ + if (!LastSong.IsEmpty()) + { + FString song = LastSong; + LastSong = ""; + S_ChangeMusic (song, mus_playing.baseorder, mus_playing.loop, true); + } +} + +//========================================================================== +// +// S_MIDIDeviceChanged +// +//========================================================================== + +void S_MIDIDeviceChanged() +{ + if (mus_playing.handle != nullptr && mus_playing.handle->IsMIDI()) + { + mus_playing.handle->Stop(); + mus_playing.handle->Start(mus_playing.loop, -1, mus_playing.baseorder); + } +} + +//========================================================================== +// +// S_GetMusic +// +//========================================================================== + +int S_GetMusic (const char **name) +{ + int order; + + if (mus_playing.name.IsNotEmpty()) + { + *name = mus_playing.name; + order = mus_playing.baseorder; + } + else + { + *name = nullptr; + order = 0; + } + return order; +} + +//========================================================================== +// +// S_StopMusic +// +//========================================================================== + +void S_StopMusic (bool force) +{ + // [RH] Don't stop if a playlist is active. + if ((force || PlayList == nullptr) && !mus_playing.name.IsEmpty()) + { + if (mus_playing.handle != nullptr) + { + if (MusicPaused) + mus_playing.handle->Resume(); + + mus_playing.handle->Stop(); + delete mus_playing.handle; + mus_playing.handle = nullptr; + } + LastSong = mus_playing.name; + mus_playing.name = ""; + } +} + +//========================================================================== +// +// CCMD idmus +// +//========================================================================== + +CCMD (idmus) +{ + level_info_t *info; + FString map; + int l; + + if (!nomusic) + { + if (argv.argc() > 1) + { + if (gameinfo.flags & GI_MAPxx) + { + l = atoi (argv[1]); + if (l <= 99) + { + map = CalcMapName (0, l); + } + else + { + Printf ("%s\n", GStrings("STSTR_NOMUS")); + return; + } + } + else + { + map = CalcMapName (argv[1][0] - '0', argv[1][1] - '0'); + } + + if ( (info = FindLevelInfo (map)) ) + { + if (info->Music.IsNotEmpty()) + { + S_ChangeMusic (info->Music, info->musicorder); + Printf ("%s\n", GStrings("STSTR_MUS")); + } + } + else + { + Printf ("%s\n", GStrings("STSTR_NOMUS")); + } + } + } +} + +//========================================================================== +// +// CCMD changemus +// +//========================================================================== + +CCMD (changemus) +{ + if (!nomusic) + { + if (argv.argc() > 1) + { + if (PlayList) + { + delete PlayList; + PlayList = nullptr; + } + S_ChangeMusic (argv[1], argv.argc() > 2 ? atoi (argv[2]) : 0); + } + else + { + const char *currentmus = mus_playing.name.GetChars(); + if(currentmus != nullptr && *currentmus != 0) + { + Printf ("currently playing %s\n", currentmus); + } + else + { + Printf ("no music playing\n"); + } + } + } +} + +//========================================================================== +// +// CCMD stopmus +// +//========================================================================== + +CCMD (stopmus) +{ + if (PlayList) + { + delete PlayList; + PlayList = nullptr; + } + S_StopMusic (false); + LastSong = ""; // forget the last played song so that it won't get restarted if some volume changes occur +} + +//========================================================================== +// +// CCMD cd_play +// +// Plays a specified track, or the entire CD if no track is specified. +//========================================================================== + +CCMD (cd_play) +{ + char musname[16]; + + if (argv.argc() == 1) + { + strcpy (musname, ",CD,"); + } + else + { + mysnprintf (musname, countof(musname), ",CD,%d", atoi(argv[1])); + } + S_ChangeMusic (musname, 0, true); +} + +//========================================================================== +// +// CCMD cd_stop +// +//========================================================================== + +CCMD (cd_stop) +{ + CD_Stop (); +} + +//========================================================================== +// +// CCMD cd_eject +// +//========================================================================== + +CCMD (cd_eject) +{ + CD_Eject (); +} + +//========================================================================== +// +// CCMD cd_close +// +//========================================================================== + +CCMD (cd_close) +{ + CD_UnEject (); +} + +//========================================================================== +// +// CCMD cd_pause +// +//========================================================================== + +CCMD (cd_pause) +{ + CD_Pause (); +} + +//========================================================================== +// +// CCMD cd_resume +// +//========================================================================== + +CCMD (cd_resume) +{ + CD_Resume (); +} + +//========================================================================== +// +// CCMD playlist +// +//========================================================================== + +UNSAFE_CCMD (playlist) +{ + int argc = argv.argc(); + + if (argc < 2 || argc > 3) + { + Printf ("playlist [|shuffle]\n"); + } + else + { + if (PlayList != nullptr) + { + PlayList->ChangeList (argv[1]); + } + else + { + PlayList = new FPlayList (argv[1]); + } + if (PlayList->GetNumSongs () == 0) + { + delete PlayList; + PlayList = nullptr; + } + else + { + if (argc == 3) + { + if (stricmp (argv[2], "shuffle") == 0) + { + PlayList->Shuffle (); + } + else + { + PlayList->SetPosition (atoi (argv[2])); + } + } + S_ActivatePlayList (false); + } + } +} + +//========================================================================== +// +// CCMD playlistpos +// +//========================================================================== + +static bool CheckForPlaylist () +{ + if (PlayList == nullptr) + { + Printf ("No playlist is playing.\n"); + return false; + } + return true; +} + +CCMD (playlistpos) +{ + if (CheckForPlaylist() && argv.argc() > 1) + { + PlayList->SetPosition (atoi (argv[1]) - 1); + S_ActivatePlayList (false); + } +} + +//========================================================================== +// +// CCMD playlistnext +// +//========================================================================== + +CCMD (playlistnext) +{ + if (CheckForPlaylist()) + { + PlayList->Advance (); + S_ActivatePlayList (false); + } +} + +//========================================================================== +// +// CCMD playlistprev +// +//========================================================================== + +CCMD (playlistprev) +{ + if (CheckForPlaylist()) + { + PlayList->Backup (); + S_ActivatePlayList (true); + } +} + +//========================================================================== +// +// CCMD playliststatus +// +//========================================================================== + +CCMD (playliststatus) +{ + if (CheckForPlaylist ()) + { + Printf ("Song %d of %d:\n%s\n", + PlayList->GetPosition () + 1, + PlayList->GetNumSongs (), + PlayList->GetSong (PlayList->GetPosition ())); + } +} + +//========================================================================== +// +// +// +//========================================================================== + +CCMD(currentmusic) +{ + if (mus_playing.name.IsNotEmpty()) + { + Printf("Currently playing music '%s'\n", mus_playing.name.GetChars()); + } + else + { + Printf("Currently no music playing\n"); + } +} diff --git a/src/sound/s_music.h b/src/sound/s_music.h new file mode 100644 index 0000000000..3f10eb2b89 --- /dev/null +++ b/src/sound/s_music.h @@ -0,0 +1,88 @@ +//----------------------------------------------------------------------------- +// +// Copyright 1993-1996 id Software +// Copyright 1999-2016 Randy Heit +// Copyright 2002-2016 Christoph Oelckers +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// 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, see http://www.gnu.org/licenses/ +// +//----------------------------------------------------------------------------- +// +// DESCRIPTION: +// The not so system specific sound interface. +// +//----------------------------------------------------------------------------- + + +#ifndef __S_MUSIC__ +#define __S_MUSIC__ + +#include "doomtype.h" +#include "i_soundinternal.h" + + +void S_ParseMusInfo(); + + +// +void S_InitMusic (); +void S_ShutdownMusic (); +void S_StartMusic (); + + +// Start music using +bool S_StartMusic (const char *music_name); + +// Start music using , and set whether looping +bool S_ChangeMusic (const char *music_name, int order=0, bool looping=true, bool force=false); + +// Start playing a cd track as music +bool S_ChangeCDMusic (int track, unsigned int id=0, bool looping=true); + +void S_RestartMusic (); + +void S_MIDIDeviceChanged(); + +int S_GetMusic (const char **name); + +// Stops the music for sure. +void S_StopMusic (bool force); + +// Stop and resume music, during game PAUSE. +void S_PauseMusic (); +void S_ResumeMusic (); + +// +// Updates music & sounds +// +void S_UpdateMusic (); + +struct MidiDeviceSetting +{ + int device; + FString args; + + MidiDeviceSetting() + { + device = MDEV_DEFAULT; + } +}; + +typedef TMap MusicAliasMap; +typedef TMap MidiDeviceMap; + +extern MusicAliasMap MusicAliases; +extern MidiDeviceMap MidiDevices; + +#endif diff --git a/src/sound/s_sound.cpp b/src/sound/s_sound.cpp index 16a47bd8f6..c368a97584 100644 --- a/src/sound/s_sound.cpp +++ b/src/sound/s_sound.cpp @@ -138,17 +138,8 @@ static void S_SetListener(SoundListener &listener, AActor *listenactor); // PRIVATE DATA DEFINITIONS ------------------------------------------------ static bool SoundPaused; // whether sound is paused -static bool MusicPaused; // whether music is paused -MusPlayingInfo mus_playing; // music currently being played -static FString LastSong; // last music that was played -static FPlayList *PlayList; static int RestartEvictionsAt; // do not restart evicted channels before this time -DEFINE_GLOBAL_NAMED(mus_playing, musplaying); -DEFINE_FIELD_X(MusPlayingInfo, MusPlayingInfo, name); -DEFINE_FIELD_X(MusPlayingInfo, MusPlayingInfo, baseorder); -DEFINE_FIELD_X(MusPlayingInfo, MusPlayingInfo, loop); - // PUBLIC DATA DEFINITIONS ------------------------------------------------- int sfx_empty; @@ -333,9 +324,6 @@ void S_Init () { S_ReturnChannel(Channels); } - - // no sounds are playing, and they are not paused - MusicPaused = false; } //========================================================================== @@ -376,15 +364,6 @@ void S_Shutdown () delete chan; } FreeChannels = NULL; - - if (PlayList != NULL) - { - delete PlayList; - PlayList = NULL; - } - S_StopMusic (true); - mus_playing.name = ""; - LastSong = ""; } //========================================================================== @@ -413,58 +392,43 @@ void S_Start () LocalSndInfo = primaryLevel->info->SoundInfo; LocalSndSeq = primaryLevel->info->SndSeq; } - - bool parse_ss = false; - - // This level uses a different local SNDINFO + + bool parse_ss = false; + + // This level uses a different local SNDINFO if (LastLocalSndInfo.CompareNoCase(LocalSndInfo) != 0 || !primaryLevel->info) + { + // First delete the old sound list + for(unsigned i = 1; i < S_sfx.Size(); i++) { - // First delete the old sound list - for(unsigned i = 1; i < S_sfx.Size(); i++) - { - S_UnloadSound(&S_sfx[i]); - } - - // Parse the global SNDINFO - S_ParseSndInfo(true); - - if (LocalSndInfo.IsNotEmpty()) - { - // Now parse the local SNDINFO - int j = Wads.CheckNumForFullName(LocalSndInfo, true); - if (j>=0) S_AddLocalSndInfo(j); - } - - // Also reload the SNDSEQ if the SNDINFO was replaced! - parse_ss = true; - } - else if (LastLocalSndSeq.CompareNoCase(LocalSndSeq) != 0) - { - parse_ss = true; - } - - if (parse_ss) - { - S_ParseSndSeq(LocalSndSeq.IsNotEmpty()? Wads.CheckNumForFullName(LocalSndSeq, true) : -1); + S_UnloadSound(&S_sfx[i]); } - LastLocalSndInfo = LocalSndInfo; - LastLocalSndSeq = LocalSndSeq; + // Parse the global SNDINFO + S_ParseSndInfo(true); + + if (LocalSndInfo.IsNotEmpty()) + { + // Now parse the local SNDINFO + int j = Wads.CheckNumForFullName(LocalSndInfo, true); + if (j>=0) S_AddLocalSndInfo(j); + } + + // Also reload the SNDSEQ if the SNDINFO was replaced! + parse_ss = true; } - - // stop the old music if it has been paused. - // This ensures that the new music is started from the beginning - // if it's the same as the last one and it has been paused. - if (MusicPaused) S_StopMusic(true); - - // start new music for the level - MusicPaused = false; - - // Don't start the music if loading a savegame, because the music is stored there. - // Don't start the music if revisiting a level in a hub for the same reason. - if (!primaryLevel->IsReentering()) - { - primaryLevel->SetMusic(); + else if (LastLocalSndSeq.CompareNoCase(LocalSndSeq) != 0) + { + parse_ss = true; + } + + if (parse_ss) + { + S_ParseSndSeq(LocalSndSeq.IsNotEmpty()? Wads.CheckNumForFullName(LocalSndSeq, true) : -1); + } + + LastLocalSndInfo = LocalSndInfo; + LastLocalSndSeq = LocalSndSeq; } } @@ -2002,65 +1966,6 @@ bool S_IsActorPlayingSomething (AActor *actor, int channel, int sound_id) return false; } -//========================================================================== -// -// S_PauseSound -// -// Stop music and sound effects, during game PAUSE. -//========================================================================== - -void S_PauseSound (bool notmusic, bool notsfx) -{ - if (!notmusic && mus_playing.handle && !MusicPaused) - { - mus_playing.handle->Pause(); - MusicPaused = true; - } - if (!notsfx) - { - SoundPaused = true; - GSnd->SetSfxPaused (true, 0); - } -} - -DEFINE_ACTION_FUNCTION(DObject, S_PauseSound) -{ - PARAM_PROLOGUE; - PARAM_BOOL(notmusic); - PARAM_BOOL(notsfx); - S_PauseSound(notmusic, notsfx); - return 0; -} - -//========================================================================== -// -// S_ResumeSound -// -// Resume music and sound effects, after game PAUSE. -//========================================================================== - -void S_ResumeSound (bool notsfx) -{ - if (mus_playing.handle && MusicPaused) - { - mus_playing.handle->Resume(); - MusicPaused = false; - } - if (!notsfx) - { - SoundPaused = false; - GSnd->SetSfxPaused (false, 0); - } -} - -DEFINE_ACTION_FUNCTION(DObject, S_ResumeSound) -{ - PARAM_PROLOGUE; - PARAM_BOOL(notsfx); - S_ResumeSound(notsfx); - return 0; -} - //========================================================================== // // S_SetSoundPaused @@ -2202,19 +2107,6 @@ void S_UpdateSounds (AActor *listenactor) FVector3 pos, vel; SoundListener listener; - I_UpdateMusic(); - - // [RH] Update music and/or playlist. IsPlaying() must be called - // to attempt to reconnect to broken net streams and to advance the - // playlist when the current song finishes. - if (mus_playing.handle != NULL && - !mus_playing.handle->IsPlaying() && - PlayList) - { - PlayList->Advance(); - S_ActivatePlayList(false); - } - // should never happen S_SetListener(listener, listenactor); @@ -2551,331 +2443,6 @@ void S_SerializeSounds(FSerializer &arc) GSnd->UpdateSounds(); } -//========================================================================== -// -// S_ActivatePlayList -// -// Plays the next song in the playlist. If no songs in the playlist can be -// played, then it is deleted. -//========================================================================== - -void S_ActivatePlayList (bool goBack) -{ - int startpos, pos; - - startpos = pos = PlayList->GetPosition (); - S_StopMusic (true); - while (!S_ChangeMusic (PlayList->GetSong (pos), 0, false, true)) - { - pos = goBack ? PlayList->Backup () : PlayList->Advance (); - if (pos == startpos) - { - delete PlayList; - PlayList = NULL; - Printf ("Cannot play anything in the playlist.\n"); - return; - } - } -} - -//========================================================================== -// -// S_ChangeCDMusic -// -// Starts a CD track as music. -//========================================================================== - -bool S_ChangeCDMusic (int track, unsigned int id, bool looping) -{ - char temp[32]; - - if (id != 0) - { - mysnprintf (temp, countof(temp), ",CD,%d,%x", track, id); - } - else - { - mysnprintf (temp, countof(temp), ",CD,%d", track); - } - return S_ChangeMusic (temp, 0, looping); -} - -//========================================================================== -// -// S_StartMusic -// -// Starts some music with the given name. -//========================================================================== - -bool S_StartMusic (const char *m_id) -{ - return S_ChangeMusic (m_id, 0, false); -} - -//========================================================================== -// -// S_ChangeMusic -// -// Starts playing a music, possibly looping. -// -// [RH] If music is a MOD, starts it at position order. If name is of the -// format ",CD,,[cd id]" song is a CD track, and if [cd id] is -// specified, it will only be played if the specified CD is in a drive. -//========================================================================== - -bool S_ChangeMusic (const char *musicname, int order, bool looping, bool force) -{ - if (!force && PlayList) - { // Don't change if a playlist is active - return false; - } - - // allow specifying "*" as a placeholder to play the level's default music. - if (musicname != NULL && !strcmp(musicname, "*")) - { - if (gamestate == GS_LEVEL || gamestate == GS_TITLELEVEL) - { - musicname = primaryLevel->Music; - order = primaryLevel->musicorder; - } - else - { - musicname = NULL; - } - } - - if (musicname == NULL || musicname[0] == 0) - { - // Don't choke if the map doesn't have a song attached - S_StopMusic (true); - mus_playing.name = ""; - LastSong = ""; - return true; - } - - FString DEH_Music; - if (musicname[0] == '$') - { - // handle dehacked replacement. - // Any music name defined this way needs to be prefixed with 'D_' because - // Doom.exe does not contain the prefix so these strings don't either. - const char * mus_string = GStrings[musicname+1]; - if (mus_string != NULL) - { - DEH_Music << "D_" << mus_string; - musicname = DEH_Music; - } - } - - FName *aliasp = MusicAliases.CheckKey(musicname); - if (aliasp != NULL) - { - if (*aliasp == NAME_None) - { - return true; // flagged to be ignored - } - musicname = aliasp->GetChars(); - } - - if (!mus_playing.name.IsEmpty() && - mus_playing.handle != NULL && - stricmp (mus_playing.name, musicname) == 0 && - mus_playing.handle->m_Looping == looping) - { - if (order != mus_playing.baseorder) - { - if (mus_playing.handle->SetSubsong(order)) - { - mus_playing.baseorder = order; - } - } - else if (!mus_playing.handle->IsPlaying()) - { - mus_playing.handle->Play(looping, order); - } - return true; - } - - if (strnicmp (musicname, ",CD,", 4) == 0) - { - int track = strtoul (musicname+4, NULL, 0); - const char *more = strchr (musicname+4, ','); - unsigned int id = 0; - - if (more != NULL) - { - id = strtoul (more+1, NULL, 16); - } - S_StopMusic (true); - mus_playing.handle = I_RegisterCDSong (track, id); - } - else - { - int lumpnum = -1; - int length = 0; - MusInfo *handle = NULL; - MidiDeviceSetting *devp = MidiDevices.CheckKey(musicname); - - // Strip off any leading file:// component. - if (strncmp(musicname, "file://", 7) == 0) - { - musicname += 7; - } - - FileReader reader; - if (!FileExists (musicname)) - { - if ((lumpnum = Wads.CheckNumForFullName (musicname, true, ns_music)) == -1) - { - Printf ("Music \"%s\" not found\n", musicname); - return false; - } - if (handle == NULL) - { - if (Wads.LumpLength (lumpnum) == 0) - { - return false; - } - reader = Wads.ReopenLumpReader(lumpnum); - } - } - else - { - // Load an external file. - if (!reader.OpenFile(musicname)) - { - return false; - } - } - - // shutdown old music - S_StopMusic (true); - - // Just record it if volume is 0 - if (snd_musicvolume <= 0) - { - mus_playing.loop = looping; - mus_playing.name = musicname; - mus_playing.baseorder = order; - LastSong = musicname; - return true; - } - - // load & register it - if (handle != NULL) - { - mus_playing.handle = handle; - } - else - { - mus_playing.handle = I_RegisterSong (reader, devp); - } - } - - mus_playing.loop = looping; - mus_playing.name = musicname; - mus_playing.baseorder = 0; - LastSong = ""; - - if (mus_playing.handle != 0) - { // play it - mus_playing.handle->Start(looping, S_GetMusicVolume (musicname), order); - mus_playing.baseorder = order; - return true; - } - return false; -} - -DEFINE_ACTION_FUNCTION(DObject, S_ChangeMusic) -{ - PARAM_PROLOGUE; - PARAM_STRING(music); - PARAM_INT(order); - PARAM_BOOL(looping); - PARAM_BOOL(force); - ACTION_RETURN_BOOL(S_ChangeMusic(music, order, looping, force)); -} - - -//========================================================================== -// -// S_RestartMusic -// -// Must only be called from snd_reset in i_sound.cpp! -//========================================================================== - -void S_RestartMusic () -{ - if (!LastSong.IsEmpty()) - { - FString song = LastSong; - LastSong = ""; - S_ChangeMusic (song, mus_playing.baseorder, mus_playing.loop, true); - } -} - -//========================================================================== -// -// S_MIDIDeviceChanged -// -//========================================================================== - -void S_MIDIDeviceChanged() -{ - if (mus_playing.handle != NULL && mus_playing.handle->IsMIDI()) - { - mus_playing.handle->Stop(); - mus_playing.handle->Start(mus_playing.loop, -1, mus_playing.baseorder); - } -} - -//========================================================================== -// -// S_GetMusic -// -//========================================================================== - -int S_GetMusic (const char **name) -{ - int order; - - if (mus_playing.name.IsNotEmpty()) - { - *name = mus_playing.name; - order = mus_playing.baseorder; - } - else - { - *name = NULL; - order = 0; - } - return order; -} - -//========================================================================== -// -// S_StopMusic -// -//========================================================================== - -void S_StopMusic (bool force) -{ - // [RH] Don't stop if a playlist is active. - if ((force || PlayList == NULL) && !mus_playing.name.IsEmpty()) - { - if (mus_playing.handle != NULL) - { - if (MusicPaused) - mus_playing.handle->Resume(); - - mus_playing.handle->Stop(); - delete mus_playing.handle; - mus_playing.handle = NULL; - } - LastSong = mus_playing.name; - mus_playing.name = ""; - } -} //========================================================================== // @@ -2925,303 +2492,6 @@ CCMD (loopsound) } } -//========================================================================== -// -// CCMD idmus -// -//========================================================================== - -CCMD (idmus) -{ - level_info_t *info; - FString map; - int l; - - if (!nomusic) - { - if (argv.argc() > 1) - { - if (gameinfo.flags & GI_MAPxx) - { - l = atoi (argv[1]); - if (l <= 99) - { - map = CalcMapName (0, l); - } - else - { - Printf ("%s\n", GStrings("STSTR_NOMUS")); - return; - } - } - else - { - map = CalcMapName (argv[1][0] - '0', argv[1][1] - '0'); - } - - if ( (info = FindLevelInfo (map)) ) - { - if (info->Music.IsNotEmpty()) - { - S_ChangeMusic (info->Music, info->musicorder); - Printf ("%s\n", GStrings("STSTR_MUS")); - } - } - else - { - Printf ("%s\n", GStrings("STSTR_NOMUS")); - } - } - } -} - -//========================================================================== -// -// CCMD changemus -// -//========================================================================== - -CCMD (changemus) -{ - if (!nomusic) - { - if (argv.argc() > 1) - { - if (PlayList) - { - delete PlayList; - PlayList = NULL; - } - S_ChangeMusic (argv[1], argv.argc() > 2 ? atoi (argv[2]) : 0); - } - else - { - const char *currentmus = mus_playing.name.GetChars(); - if(currentmus != NULL && *currentmus != 0) - { - Printf ("currently playing %s\n", currentmus); - } - else - { - Printf ("no music playing\n"); - } - } - } -} - -//========================================================================== -// -// CCMD stopmus -// -//========================================================================== - -CCMD (stopmus) -{ - if (PlayList) - { - delete PlayList; - PlayList = NULL; - } - S_StopMusic (false); - LastSong = ""; // forget the last played song so that it won't get restarted if some volume changes occur -} - -//========================================================================== -// -// CCMD cd_play -// -// Plays a specified track, or the entire CD if no track is specified. -//========================================================================== - -CCMD (cd_play) -{ - char musname[16]; - - if (argv.argc() == 1) - { - strcpy (musname, ",CD,"); - } - else - { - mysnprintf (musname, countof(musname), ",CD,%d", atoi(argv[1])); - } - S_ChangeMusic (musname, 0, true); -} - -//========================================================================== -// -// CCMD cd_stop -// -//========================================================================== - -CCMD (cd_stop) -{ - CD_Stop (); -} - -//========================================================================== -// -// CCMD cd_eject -// -//========================================================================== - -CCMD (cd_eject) -{ - CD_Eject (); -} - -//========================================================================== -// -// CCMD cd_close -// -//========================================================================== - -CCMD (cd_close) -{ - CD_UnEject (); -} - -//========================================================================== -// -// CCMD cd_pause -// -//========================================================================== - -CCMD (cd_pause) -{ - CD_Pause (); -} - -//========================================================================== -// -// CCMD cd_resume -// -//========================================================================== - -CCMD (cd_resume) -{ - CD_Resume (); -} - -//========================================================================== -// -// CCMD playlist -// -//========================================================================== - -UNSAFE_CCMD (playlist) -{ - int argc = argv.argc(); - - if (argc < 2 || argc > 3) - { - Printf ("playlist [|shuffle]\n"); - } - else - { - if (PlayList != NULL) - { - PlayList->ChangeList (argv[1]); - } - else - { - PlayList = new FPlayList (argv[1]); - } - if (PlayList->GetNumSongs () == 0) - { - delete PlayList; - PlayList = NULL; - } - else - { - if (argc == 3) - { - if (stricmp (argv[2], "shuffle") == 0) - { - PlayList->Shuffle (); - } - else - { - PlayList->SetPosition (atoi (argv[2])); - } - } - S_ActivatePlayList (false); - } - } -} - -//========================================================================== -// -// CCMD playlistpos -// -//========================================================================== - -static bool CheckForPlaylist () -{ - if (PlayList == NULL) - { - Printf ("No playlist is playing.\n"); - return false; - } - return true; -} - -CCMD (playlistpos) -{ - if (CheckForPlaylist() && argv.argc() > 1) - { - PlayList->SetPosition (atoi (argv[1]) - 1); - S_ActivatePlayList (false); - } -} - -//========================================================================== -// -// CCMD playlistnext -// -//========================================================================== - -CCMD (playlistnext) -{ - if (CheckForPlaylist()) - { - PlayList->Advance (); - S_ActivatePlayList (false); - } -} - -//========================================================================== -// -// CCMD playlistprev -// -//========================================================================== - -CCMD (playlistprev) -{ - if (CheckForPlaylist()) - { - PlayList->Backup (); - S_ActivatePlayList (true); - } -} - -//========================================================================== -// -// CCMD playliststatus -// -//========================================================================== - -CCMD (playliststatus) -{ - if (CheckForPlaylist ()) - { - Printf ("Song %d of %d:\n%s\n", - PlayList->GetPosition () + 1, - PlayList->GetNumSongs (), - PlayList->GetSong (PlayList->GetPosition ())); - } -} - //========================================================================== // // CCMD cachesound @@ -3265,14 +2535,60 @@ CCMD(listsoundchannels) Printf("%d sounds playing\n", count); } -CCMD(currentmusic) +// intentionally moved here to keep the s_music include out of the rest of the file. + +//========================================================================== +// +// S_PauseSound +// +// Stop music and sound effects, during game PAUSE. +//========================================================================== +#include "s_music.h" + +void S_PauseSound (bool notmusic, bool notsfx) { - if (mus_playing.name.IsNotEmpty()) + if (!notmusic) { - Printf("Currently playing music '%s'\n", mus_playing.name.GetChars()); + S_PauseMusic(); } - else + if (!notsfx) { - Printf("Currently no music playing\n"); + SoundPaused = true; + GSnd->SetSfxPaused (true, 0); } } + +DEFINE_ACTION_FUNCTION(DObject, S_PauseSound) +{ + PARAM_PROLOGUE; + PARAM_BOOL(notmusic); + PARAM_BOOL(notsfx); + S_PauseSound(notmusic, notsfx); + return 0; +} + +//========================================================================== +// +// S_ResumeSound +// +// Resume music and sound effects, after game PAUSE. +//========================================================================== + +void S_ResumeSound (bool notsfx) +{ + S_ResumeMusic(); + if (!notsfx) + { + SoundPaused = false; + GSnd->SetSfxPaused (false, 0); + } +} + +DEFINE_ACTION_FUNCTION(DObject, S_ResumeSound) +{ + PARAM_PROLOGUE; + PARAM_BOOL(notsfx); + S_ResumeSound(notsfx); + return 0; +} + diff --git a/src/sound/s_sound.h b/src/sound/s_sound.h index 795a8b338f..b86c4573ee 100644 --- a/src/sound/s_sound.h +++ b/src/sound/s_sound.h @@ -323,24 +323,6 @@ void S_RelinkSound (AActor *from, AActor *to); // Stores/retrieves playing channel information in an archive. void S_SerializeSounds(FSerializer &arc); -// Start music using -bool S_StartMusic (const char *music_name); - -// Start music using , and set whether looping -bool S_ChangeMusic (const char *music_name, int order=0, bool looping=true, bool force=false); - -// Start playing a cd track as music -bool S_ChangeCDMusic (int track, unsigned int id=0, bool looping=true); - -void S_RestartMusic (); - -void S_MIDIDeviceChanged(); - -int S_GetMusic (const char **name); - -// Stops the music for sure. -void S_StopMusic (bool force); - // Stop and resume music, during game PAUSE. void S_PauseSound (bool notmusic, bool notsfx); void S_ResumeSound (bool notsfx); @@ -377,7 +359,6 @@ void S_ShrinkPlayerSoundLists (); void S_UnloadSound (sfxinfo_t *sfx); sfxinfo_t *S_LoadSound(sfxinfo_t *sfx, FSoundLoadBuffer *pBuffer = nullptr); unsigned int S_GetMSLength(FSoundID sound); -void S_ParseMusInfo(); bool S_ParseTimeTag(const char *tag, bool *as_samples, unsigned int *time); void A_PlaySound(AActor *self, int soundid, int channel, double volume, int looping, double attenuation, int local, double pitch); @@ -392,22 +373,5 @@ void S_SetEnvironment (const ReverbContainer *settings); ReverbContainer *S_FindEnvironment (const char *name); ReverbContainer *S_FindEnvironment (int id); void S_AddEnvironment (ReverbContainer *settings); - -struct MidiDeviceSetting -{ - int device; - FString args; - - MidiDeviceSetting() - { - device = MDEV_DEFAULT; - } -}; - -typedef TMap MusicAliasMap; -typedef TMap MidiDeviceMap; - -extern MusicAliasMap MusicAliases; -extern MidiDeviceMap MidiDevices; - + #endif diff --git a/src/win32/i_main.cpp b/src/win32/i_main.cpp index 6d9c9f7713..482ff170fe 100644 --- a/src/win32/i_main.cpp +++ b/src/win32/i_main.cpp @@ -74,6 +74,7 @@ #include "i_system.h" #include "gstrings.h" #include "atterm.h" +#include "s_music.h" #include "stats.h" #include "st_start.h" diff --git a/src/win32/st_start.cpp b/src/win32/st_start.cpp index 036a7e142b..9777601b77 100644 --- a/src/win32/st_start.cpp +++ b/src/win32/st_start.cpp @@ -50,6 +50,7 @@ #include "m_argv.h" #include "d_main.h" #include "doomerrors.h" +#include "s_music.h" // MACROS ------------------------------------------------------------------