Merge branch 'master' into scripting

Conflicts:
	src/p_effect.cpp
	src/p_effect.h
	src/p_local.h
	src/p_map.cpp
	src/thingdef/thingdef_codeptr.cpp
	wadsrc/static/actors/actor.txt
	wadsrc/static/actors/shared/inventory.txt
	zdoom.vcproj
This commit is contained in:
Christoph Oelckers 2015-04-28 14:45:13 +02:00
commit 2e0f999fea
108 changed files with 5421 additions and 1028 deletions

View file

@ -106,6 +106,9 @@ endif( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE )
set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}")
option( NO_FMOD "Disable FMODEx sound support" OFF )
option( NO_OPENAL "Disable OpenAL sound support" OFF )
find_package( BZip2 )
find_package( JPEG )
find_package( ZLIB )

28
FindMPG123.cmake Normal file
View file

@ -0,0 +1,28 @@
# - Find mpg123
# Find the native mpg123 includes and library
#
# MPG123_INCLUDE_DIR - where to find mpg123.h
# MPG123_LIBRARIES - List of libraries when using mpg123.
# MPG123_FOUND - True if mpg123 found.
IF(MPG123_INCLUDE_DIR AND MPG123_LIBRARIES)
# Already in cache, be silent
SET(MPG123_FIND_QUIETLY TRUE)
ENDIF(MPG123_INCLUDE_DIR AND MPG123_LIBRARIES)
FIND_PATH(MPG123_INCLUDE_DIR mpg123.h
PATHS "${MPG123_DIR}"
PATH_SUFFIXES include
)
FIND_LIBRARY(MPG123_LIBRARIES NAMES mpg123 mpg123-0
PATHS "${MPG123_DIR}"
PATH_SUFFIXES lib
)
# MARK_AS_ADVANCED(MPG123_LIBRARIES MPG123_INCLUDE_DIR)
# handle the QUIETLY and REQUIRED arguments and set MPG123_FOUND to TRUE if
# all listed variables are TRUE
INCLUDE(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(MPG123 DEFAULT_MSG MPG123_LIBRARIES MPG123_INCLUDE_DIR)

29
FindSndFile.cmake Normal file
View file

@ -0,0 +1,29 @@
# - Try to find SndFile
# Once done this will define
#
# SNDFILE_FOUND - system has SndFile
# SNDFILE_INCLUDE_DIRS - the SndFile include directory
# SNDFILE_LIBRARIES - Link these to use SndFile
#
# Copyright © 2006 Wengo
# Copyright © 2009 Guillaume Martres
#
# Redistribution and use is allowed according to the terms of the New
# BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
#
find_path(SNDFILE_INCLUDE_DIR NAMES sndfile.h)
find_library(SNDFILE_LIBRARY NAMES sndfile sndfile-1)
set(SNDFILE_INCLUDE_DIRS ${SNDFILE_INCLUDE_DIR})
set(SNDFILE_LIBRARIES ${SNDFILE_LIBRARY})
INCLUDE(FindPackageHandleStandardArgs)
# handle the QUIETLY and REQUIRED arguments and set SNDFILE_FOUND to TRUE if
# all listed variables are TRUE
FIND_PACKAGE_HANDLE_STANDARD_ARGS(SndFile DEFAULT_MSG SNDFILE_LIBRARY SNDFILE_INCLUDE_DIR)
# show the SNDFILE_INCLUDE_DIRS and SNDFILE_LIBRARIES variables only in the advanced view
mark_as_advanced(SNDFILE_INCLUDE_DIRS SNDFILE_LIBRARIES)

View file

@ -1,4 +1,5 @@
cmake_minimum_required( VERSION 2.4 )
if( NOT NO_FMOD AND FMOD_INCLUDE_DIR )
add_library( output_sdl MODULE output_sdl.c )
include_directories( ${FMOD_INCLUDE_DIR} ${SDL2_INCLUDE_DIR} )
target_link_libraries( output_sdl ${SDL2_LIBRARY} )
@ -7,3 +8,4 @@ FILE( WRITE ${CMAKE_CURRENT_BINARY_DIR}/link-make "if [ ! -e ${ZDOOM_OUTPUT_DIR}
add_custom_command( TARGET output_sdl POST_BUILD
COMMAND chmod +x ${CMAKE_CURRENT_BINARY_DIR}/link-make
COMMAND /bin/sh -c ${CMAKE_CURRENT_BINARY_DIR}/link-make )
endif( NOT NO_FMOD AND FMOD_INCLUDE_DIR )

View file

@ -119,6 +119,7 @@ Note: All <bool> fields default to false unless mentioned otherwise.
blockhitscan = <bool>; // Line blocks hitscan attacks
locknumber = <int>; // Line special is locked
arg0str = <string>; // Alternate string-based version of arg0
moreids = <string>; // Additional line IDs, specified as a space separated list of numbers (e.g. "2 666 1003 4505")
transparent = <bool>; // true = line is a Strife transparent line (alpha 0.25)
@ -201,6 +202,7 @@ Note: All <bool> fields default to false unless mentioned otherwise.
// sound sequence thing in the sector will override this property.
hidden = <bool>; // if true this sector will not be drawn on the textured automap.
waterzone = <bool>; // Sector is under water and swimmable
moreids = <string>; // Additional sector IDs/tags, specified as a space separated list of numbers (e.g. "2 666 1003 4505")
* Note about dropactors
@ -370,6 +372,9 @@ Added transparent line property (to be folded back to core UDMF standard), and h
Added plane equations for sector slopes. (Please read carefully to ensure proper use!)
Changed language describing the DIALOGUE lump to mention USDF as an option.
1.25 19.04.2015
Added 'moreids' for linedefs and sectors.
===============================================================================
EOF
===============================================================================

View file

@ -212,23 +212,20 @@ else( WIN32 )
endif( FPU_CONTROL_DIR )
endif( WIN32 )
# Decide on the name of the FMOD library we want to use.
if( NOT FMOD_LIB_NAME AND MSVC )
set( FMOD_LIB_NAME fmodex${X64}_vc )
endif( NOT FMOD_LIB_NAME AND MSVC )
if( NOT FMOD_LIB_NAME AND BORLAND )
set( FMOD_LIB_NAME fmodex${X64}_bc )
endif( NOT FMOD_LIB_NAME AND BORLAND )
if( NOT FMOD_LIB_NAME )
set( FMOD_LIB_NAME fmodex${X64} )
endif( NOT FMOD_LIB_NAME )
if( NOT NO_OPENAL )
find_package( OpenAL )
mark_as_advanced(CLEAR OPENAL_LIBRARY OPENAL_INCLUDE_DIR)
if( OPENAL_FOUND )
include_directories( ${OPENAL_INCLUDE_DIR} )
set( ZDOOM_LIBS ${OPENAL_LIBRARY} ${ZDOOM_LIBS} )
else( OPENAL_FOUND )
set( NO_OPENAL ON )
endif( OPENAL_FOUND )
endif( NOT NO_OPENAL )
if( NOT NO_FMOD )
# Search for FMOD include files
if( NOT WIN32 )
find_path( FMOD_INCLUDE_DIR fmod.hpp
PATHS ${FMOD_LOCAL_INC_DIRS} )
@ -242,13 +239,28 @@ endif( NOT FMOD_INCLUDE_DIR )
if( FMOD_INCLUDE_DIR )
message( STATUS "FMOD include files found at ${FMOD_INCLUDE_DIR}" )
include_directories( "${FMOD_INCLUDE_DIR}" )
else( FMOD_INCLUDE_DIR )
message( SEND_ERROR "Could not find FMOD include files" )
message( STATUS "Could not find FMOD include files" )
set( NO_FMOD ON )
endif( FMOD_INCLUDE_DIR )
endif( NOT NO_FMOD )
if( NOT NO_FMOD )
# Decide on the name of the FMOD library we want to use.
if( NOT FMOD_LIB_NAME AND MSVC )
set( FMOD_LIB_NAME fmodex${X64}_vc )
endif( NOT FMOD_LIB_NAME AND MSVC )
if( NOT FMOD_LIB_NAME AND BORLAND )
set( FMOD_LIB_NAME fmodex${X64}_bc )
endif( NOT FMOD_LIB_NAME AND BORLAND )
if( NOT FMOD_LIB_NAME )
set( FMOD_LIB_NAME fmodex${X64} )
endif( NOT FMOD_LIB_NAME )
# Search for FMOD library
if( WIN32 OR APPLE )
find_library( FMOD_LIBRARY ${FMOD_LIB_NAME}
PATHS ${FMOD_SEARCH_PATHS}
@ -261,10 +273,27 @@ endif( WIN32 OR APPLE )
if( FMOD_LIBRARY )
message( STATUS "FMOD library found at ${FMOD_LIBRARY}" )
set( ZDOOM_LIBS ${ZDOOM_LIBS} "${FMOD_LIBRARY}" )
else( FMOD_LIBRARY )
message( SEND_ERROR "Could not find FMOD library" )
message( STATUS "Could not find FMOD library" )
set( NO_FMOD ON )
endif( FMOD_LIBRARY )
endif( NOT NO_FMOD )
if( NO_FMOD )
add_definitions( -DNO_FMOD=1 )
endif( NO_FMOD )
if( NO_OPENAL )
add_definitions( -DNO_OPENAL=1 )
endif( NO_OPENAL )
# Search for libSndFile
find_package( SndFile )
# Search for libmpg123
find_package( MPG123 )
# Search for FluidSynth
@ -512,9 +541,17 @@ add_custom_target( revision_check ALL
# Libraries ZDoom needs
message( STATUS "Fluid synth libs: ${FLUIDSYNTH_LIBRARIES}" )
set( ZDOOM_LIBS ${ZDOOM_LIBS} "${ZLIB_LIBRARIES}" "${JPEG_LIBRARIES}" "${BZIP2_LIBRARIES}" "${GME_LIBRARIES}" "${FMOD_LIBRARY}" )
include_directories( "${ZLIB_INCLUDE_DIR}" "${FMOD_INCLUDE_DIR}" "${BZIP2_INCLUDE_DIR}" "${LZMA_INCLUDE_DIR}" "${JPEG_INCLUDE_DIR}" "${GME_INCLUDE_DIR}" )
set( ZDOOM_LIBS ${ZDOOM_LIBS} "${ZLIB_LIBRARIES}" "${JPEG_LIBRARIES}" "${BZIP2_LIBRARIES}" "${GME_LIBRARIES}" )
include_directories( "${ZLIB_INCLUDE_DIR}" "${BZIP2_INCLUDE_DIR}" "${LZMA_INCLUDE_DIR}" "${JPEG_INCLUDE_DIR}" "${GME_INCLUDE_DIR}" )
if( SNDFILE_FOUND )
set( ZDOOM_LIBS ${ZDOOM_LIBS} "${SNDFILE_LIBRARIES}" )
include_directories( "${SNDFILE_INCLUDE_DIRS}" )
endif( SNDFILE_FOUND )
if( MPG123_FOUND )
set( ZDOOM_LIBS ${ZDOOM_LIBS} "${MPG123_LIBRARIES}" )
include_directories( "${MPG123_INCLUDE_DIR}" )
endif( MPG123_FOUND )
if( NOT DYN_FLUIDSYNTH)
if( FLUIDSYNTH_FOUND )
set( ZDOOM_LIBS ${ZDOOM_LIBS} "${FLUIDSYNTH_LIBRARIES}" )
@ -655,6 +692,12 @@ else( SSE_MATTERS )
set( X86_SOURCES )
endif( SSE_MATTERS )
if( SNDFILE_FOUND )
add_definitions( -DHAVE_SNDFILE )
endif( SNDFILE_FOUND )
if( MPG123_FOUND )
add_definitions( -DHAVE_MPG123 )
endif( MPG123_FOUND )
if( DYN_FLUIDSYNTH )
add_definitions( -DHAVE_FLUIDSYNTH -DDYN_FLUIDSYNTH )
elseif( FLUIDSYNTH_FOUND )
@ -905,6 +948,7 @@ add_executable( zdoom WIN32 MACOSX_BUNDLE
p_spec.cpp
p_states.cpp
p_switch.cpp
p_tags.cpp
p_teleport.cpp
p_terrain.cpp
p_things.cpp
@ -1035,6 +1079,7 @@ add_executable( zdoom WIN32 MACOSX_BUNDLE
sound/fmodsound.cpp
sound/i_music.cpp
sound/i_sound.cpp
sound/mpg123_decoder.cpp
sound/music_cd.cpp
sound/music_dumb.cpp
sound/music_gme.cpp
@ -1051,6 +1096,8 @@ add_executable( zdoom WIN32 MACOSX_BUNDLE
sound/music_softsynth_mididevice.cpp
sound/music_timidity_mididevice.cpp
sound/music_win_mididevice.cpp
sound/oalsound.cpp
sound/sndfile_decoder.cpp
sound/music_pseudo_mididevice.cpp
textures/animations.cpp
textures/anim_switches.cpp
@ -1171,9 +1218,9 @@ endif( NOT ZDOOM_OUTPUT_OLDSTYLE OR NO_GENERATOR_EXPRESSIONS )
if( MSVC )
option( ZDOOM_GENERATE_MAPFILE "Generate .map file for debugging." OFF )
if( ZDOOM_GENERATE_MAPFILE )
set_target_properties(zdoom PROPERTIES LINK_FLAGS "/MANIFEST:NO /DELAYLOAD:\"fmodex${X64}.dll\" /MAP")
set_target_properties(zdoom PROPERTIES LINK_FLAGS "/MANIFEST:NO /DELAYLOAD:\"fmodex${X64}.dll\" /DELAYLOAD:\"openal32.dll\" /DELAYLOAD:\"libmpg123-0.dll\" /DELAYLOAD:\"libsndfile-1.dll\" /MAP")
else( ZDOOM_GENERATE_MAPFILE )
set_target_properties(zdoom PROPERTIES LINK_FLAGS "/MANIFEST:NO /DELAYLOAD:\"fmodex${X64}.dll\"")
set_target_properties(zdoom PROPERTIES LINK_FLAGS "/MANIFEST:NO /DELAYLOAD:\"fmodex${X64}.dll\" /DELAYLOAD:\"openal32.dll\" /DELAYLOAD:\"libmpg123-0.dll\" /DELAYLOAD:\"libsndfile-1.dll\"")
endif( ZDOOM_GENERATE_MAPFILE )
add_custom_command(TARGET zdoom POST_BUILD

View file

@ -49,6 +49,7 @@
#include "gi.h"
#include "g_level.h"
#include "p_lnspec.h"
#include "p_tags.h"
#include "r_state.h"
#include "w_wad.h"
@ -551,8 +552,8 @@ void SetCompatibilityParams()
{
if ((unsigned)CompatParams[i + 1] < (unsigned)numsectors)
{
sectors[CompatParams[i + 1]].ClearTags();
sectors[CompatParams[i + 1]].SetMainTag(CompatParams[i + 2]);
// this assumes that the sector does not have any tags yet!
tagManager.AddSectorTag(CompatParams[i + 1], CompatParams[i + 2]);
}
i += 3;
break;

View file

@ -905,6 +905,7 @@ void D_Display ()
} while (diff < 1);
wipestart = nowtime;
done = screen->WipeDo (1);
S_UpdateMusic(); // OpenAL needs this to keep the music running, thanks to a complete lack of a sane streaming implementation using callbacks. :(
C_DrawConsole (hw2d); // console and
M_Drawer (); // menu are drawn even on top of wipes
screen->Update (); // page flip or blit buffer
@ -1003,6 +1004,7 @@ void D_DoomLoop ()
// Update display, next frame, with current state.
I_StartTic ();
D_Display ();
S_UpdateMusic(); // OpenAL needs this to keep the music running, thanks to a complete lack of a sane streaming implementation using callbacks. :(
}
catch (CRecoverableError &error)
{
@ -1999,6 +2001,9 @@ static void D_DoomInit()
}
FRandom::StaticClearRandom ();
Printf ("M_LoadDefaults: Load system defaults.\n");
M_LoadDefaults (); // load before initing other systems
}
//==========================================================================
@ -2249,8 +2254,8 @@ void D_DoomMain (void)
iwad_man = new FIWadManager;
iwad_man->ParseIWadInfos(basewad);
Printf ("M_LoadDefaults: Load system defaults.\n");
M_LoadDefaults (iwad_man); // load before initing other systems
// Now that we have the IWADINFO, initialize the autoload ini sections.
GameConfig->DoAutoloadSetup(iwad_man);
// reinit from here

View file

@ -544,3 +544,59 @@ char *MemoryReader::Gets(char *strbuf, int len)
{
return GetsFromBuffer(bufptr, strbuf, len);
}
//==========================================================================
//
// MemoryArrayReader
//
// reads data from an array of memory
//
//==========================================================================
MemoryArrayReader::MemoryArrayReader (const char *buffer, long length)
{
buf.Resize(length);
memcpy(&buf[0], buffer, length);
Length=length;
FilePos=0;
}
MemoryArrayReader::~MemoryArrayReader ()
{
}
long MemoryArrayReader::Tell () const
{
return FilePos;
}
long MemoryArrayReader::Seek (long offset, int origin)
{
switch (origin)
{
case SEEK_CUR:
offset+=FilePos;
break;
case SEEK_END:
offset+=Length;
break;
}
FilePos=clamp<long>(offset,0,Length-1);
return 0;
}
long MemoryArrayReader::Read (void *buffer, long len)
{
if (len>Length-FilePos) len=Length-FilePos;
if (len<0) len=0;
memcpy(buffer,&buf[FilePos],len);
FilePos+=len;
return len;
}
char *MemoryArrayReader::Gets(char *strbuf, int len)
{
return GetsFromBuffer((char*)&buf[0], strbuf, len);
}

View file

@ -336,6 +336,24 @@ protected:
const char * bufptr;
};
class MemoryArrayReader : public FileReader
{
public:
MemoryArrayReader (const char *buffer, long length);
~MemoryArrayReader ();
virtual long Tell () const;
virtual long Seek (long offset, int origin);
virtual long Read (void *buffer, long len);
virtual char *Gets(char *strbuf, int len);
virtual const char *GetBuffer() const { return (char*)&buf[0]; }
TArray<BYTE> &GetArray() { return buf; }
void UpdateLength() { Length = buf.Size(); }
protected:
TArray<BYTE> buf;
};
#endif

View file

@ -169,6 +169,7 @@ void FS_EmulateCmd(char * string)
{
// No, this is not correct. But this is the way Legacy WADs expect it to be handled!
if (players[i].mo != NULL) players[i].mo->ViewHeight = playerviewheight;
players[i].viewheight = playerviewheight;
players[i].Uncrouch();
}
while (sc.GetString())

View file

@ -1165,7 +1165,7 @@ void FParser::SF_ObjSector(void)
}
t_return.type = svt_int;
t_return.value.i = mo ? mo->Sector->GetMainTag() : 0; // nullptr check
t_return.value.i = mo ? tagManager.GetFirstSectorTag(mo->Sector) : 0; // nullptr check
}
//==========================================================================
@ -2235,7 +2235,7 @@ void FParser::SF_LineTrigger()
maplinedef_t mld;
mld.special=intvalue(t_argv[0]);
mld.tag=t_argc > 1 ? intvalue(t_argv[1]) : 0;
P_TranslateLineDef(&line, &mld, false);
P_TranslateLineDef(&line, &mld);
P_ExecuteSpecial(line.special, NULL, Script->trigger, false,
line.args[0],line.args[1],line.args[2],line.args[3],line.args[4]);
}
@ -4312,7 +4312,7 @@ void FParser::SF_KillInSector()
while ((mo=it.Next()))
{
if (mo->flags3&MF3_ISMONSTER && mo->Sector->HasTag(tag)) P_DamageMobj(mo, NULL, NULL, 1000000, NAME_Massacre);
if (mo->flags3&MF3_ISMONSTER && tagManager.SectorHasTag(mo->Sector, tag)) P_DamageMobj(mo, NULL, NULL, 1000000, NAME_Massacre);
}
}
}
@ -4385,7 +4385,7 @@ void FParser::SF_SetLineTrigger()
mld.tag = tag;
mld.flags = 0;
int f = lines[i].flags;
P_TranslateLineDef(&lines[i], &mld, false);
P_TranslateLineDef(&lines[i], &mld);
lines[i].flags = (lines[i].flags & (ML_MONSTERSCANACTIVATE | ML_REPEAT_SPECIAL | ML_SPAC_MASK | ML_FIRSTSIDEONLY)) |
(f & ~(ML_MONSTERSCANACTIVATE | ML_REPEAT_SPECIAL | ML_SPAC_MASK | ML_FIRSTSIDEONLY));

View file

@ -213,13 +213,12 @@ void FMapInfoParser::ParseDoomEdNums()
DoomEdFromMapinfo.Insert(ednum, editem);
continue;
}
sc.MustGetStringName(",");
sc.MustGetNumber();
}
int i = 0;
while (i < 5)
{
editem.args[i++] = sc.Number;
editem.args[i] = sc.Number;
i++;
if (!sc.CheckString(",")) break;
sc.MustGetNumber();

View file

@ -1229,6 +1229,7 @@ void G_FinishTravel ()
pawn->lastenemy = NULL;
pawn->player->mo = pawn;
pawn->player->camera = pawn;
pawn->player->viewheight = pawn->ViewHeight;
pawn->flags2 &= ~MF2_BLASTED;
DObject::StaticPointerSubstitution (oldpawn, pawn);
oldpawn->Destroy();

View file

@ -639,7 +639,7 @@ bool AInventory::HandlePickup (AInventory *item)
{
if (item->GetClass() == GetClass())
{
if (Amount < MaxAmount || sv_unlimited_pickup)
if (Amount < MaxAmount || (sv_unlimited_pickup && !item->ShouldStay()))
{
if (Amount > 0 && Amount + item->Amount < 0)
{

View file

@ -665,7 +665,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CheckTerrain)
}
else if ((sec->special & 0xFF) == Scroll_StrifeCurrent)
{
int anglespeed = sec->GetMainTag() - 100;
int anglespeed = tagManager.GetFirstSectorTag(sec) - 100;
fixed_t speed = (anglespeed % 10) << (FRACBITS - 4);
angle_t finean = (anglespeed / 10) << (32-3);
finean >>= ANGLETOFINESHIFT;

View file

@ -76,7 +76,7 @@ EXTERN_CVAR (Color, am_cdwallcolor)
EXTERN_CVAR (Float, spc_amp)
EXTERN_CVAR (Bool, wi_percents)
FGameConfigFile::FGameConfigFile (FIWadManager *iwad_man)
FGameConfigFile::FGameConfigFile ()
{
#ifdef __APPLE__
FString user_docs, user_app_support, local_app_support;
@ -161,6 +161,27 @@ FGameConfigFile::FGameConfigFile (FIWadManager *iwad_man)
SetValueForKey ("Path", "$DOOMWADDIR", true);
}
// Add some self-documentation.
SetSectionNote("IWADSearch.Directories",
"# These are the directories to automatically search for IWADs.\n"
"# Each directory should be on a separate line, preceded by Path=\n");
SetSectionNote("FileSearch.Directories",
"# These are the directories to search for wads added with the -file\n"
"# command line parameter, if they cannot be found with the path\n"
"# as-is. Layout is the same as for IWADSearch.Directories\n");
}
FGameConfigFile::~FGameConfigFile ()
{
}
void FGameConfigFile::WriteCommentHeader (FILE *file) const
{
fprintf (file, "# This file was generated by " GAMENAME " %s on %s\n", GetVersionString(), myasctime());
}
void FGameConfigFile::DoAutoloadSetup (FIWadManager *iwad_man)
{
// Create auto-load sections, so users know what's available.
// Note that this totem pole is the reverse of the order that
// they will appear in the file.
@ -220,14 +241,6 @@ FGameConfigFile::FGameConfigFile (FIWadManager *iwad_man)
MoveSectionToStart("FileSearch.Directories");
MoveSectionToStart("IWADSearch.Directories");
// Add some self-documentation.
SetSectionNote("IWADSearch.Directories",
"# These are the directories to automatically search for IWADs.\n"
"# Each directory should be on a separate line, preceded by Path=\n");
SetSectionNote("FileSearch.Directories",
"# These are the directories to search for wads added with the -file\n"
"# command line parameter, if they cannot be found with the path\n"
"# as-is. Layout is the same as for IWADSearch.Directories\n");
SetSectionNote("Doom.AutoExec",
"# Files to automatically execute when running the corresponding game.\n"
"# Each file should be on its own line, preceded by Path=\n\n");
@ -245,15 +258,6 @@ FGameConfigFile::FGameConfigFile (FIWadManager *iwad_man)
"# 'doom.doom2.commercial.Autoload' only when playing doom2.wad.\n\n");
}
FGameConfigFile::~FGameConfigFile ()
{
}
void FGameConfigFile::WriteCommentHeader (FILE *file) const
{
fprintf (file, "# This file was generated by " GAMENAME " %s on %s\n", GetVersionString(), myasctime());
}
void FGameConfigFile::DoGlobalSetup ()
{
if (SetSection ("GlobalSettings.Unknown"))

View file

@ -43,9 +43,10 @@ class FIWadManager;
class FGameConfigFile : public FConfigFile
{
public:
FGameConfigFile (FIWadManager *iwad_man);
FGameConfigFile ();
~FGameConfigFile ();
void DoAutoloadSetup (FIWadManager *iwad_man);
void DoGlobalSetup ();
void DoGameSetup (const char *gamename);
void DoKeySetup (const char *gamename);

View file

@ -319,7 +319,11 @@ void PacketGet (void)
}
else if (c > 0)
{ //The packet is not from any in-game node, so we might as well discard it.
Printf("Dropped packet: Unknown host (%s:%d)\n", inet_ntoa(fromaddress.sin_addr), fromaddress.sin_port);
// Don't show the message for disconnect notifications.
if (c != 2 || TransmitBuffer[0] != PRE_FAKE || TransmitBuffer[1] != PRE_DISCONNECT)
{
DPrintf("Dropped packet: Unknown host (%s:%d)\n", inet_ntoa(fromaddress.sin_addr), fromaddress.sin_port);
}
doomcom.remotenode = -1;
return;
}

View file

@ -358,7 +358,7 @@ void PClassActor::RegisterIDs()
if (ConversationID > 0)
{
StrifeTypes[ConversationID] = cls;
if (cls != Class)
if (cls != this)
{
Printf(TEXTCOLOR_RED"Conversation ID %d refers to hidden class type '%s'\n", SpawnID, cls->TypeName.GetChars());
}

View file

@ -410,9 +410,9 @@ CCMD (writeini)
// M_LoadDefaults
//
void M_LoadDefaults (FIWadManager *iwad_man)
void M_LoadDefaults ()
{
GameConfig = new FGameConfigFile(iwad_man);
GameConfig = new FGameConfigFile;
GameConfig->DoGlobalSetup ();
atterm (M_SaveDefaultsFinal);
}

View file

@ -41,7 +41,7 @@ void M_FindResponseFile (void);
// Pass a NULL to get the original behavior.
void M_ScreenShot (const char *filename);
void M_LoadDefaults (FIWadManager *iwad_man);
void M_LoadDefaults ();
bool M_SaveDefaults (const char *filename);
void M_SaveCustomKeys (FConfigFile *config, char *section, char *subsection, size_t sublen);

View file

@ -22,6 +22,8 @@
#if defined(_WIN32)
#include "i_system.h"
typedef HRESULT (WINAPI *GKFP)(REFKNOWNFOLDERID, DWORD, HANDLE, PWSTR *);
//===========================================================================
@ -73,18 +75,7 @@ bool UseKnownFolders()
bool GetKnownFolder(int shell_folder, REFKNOWNFOLDERID known_folder, bool create, FString &path)
{
static GKFP SHGetKnownFolderPath = NULL;
static bool tested = false;
if (!tested)
{
tested = true;
HMODULE shell32 = GetModuleHandle("shell32.dll");
if (shell32 != NULL)
{
SHGetKnownFolderPath = (GKFP)GetProcAddress(shell32, "SHGetKnownFolderPath");
}
}
static TOptWin32Proc<GKFP> SHGetKnownFolderPath("shell32.dll", "SHGetKnownFolderPath");
char pathstr[MAX_PATH];
@ -92,6 +83,13 @@ bool GetKnownFolder(int shell_folder, REFKNOWNFOLDERID known_folder, bool create
// new to Vista, hence the reason we support both.
if (SHGetKnownFolderPath == NULL)
{
static TOptWin32Proc<HRESULT(*)(HWND, int, HANDLE, DWORD, LPTSTR)>
SHGetFolderPathA("shell32.dll", "SHGetFolderPathA");
// NT4 doesn't even have this function.
if (SHGetFolderPathA == NULL)
return false;
if (shell_folder < 0)
{ // Not supported by SHGetFolderPath
return false;
@ -100,7 +98,7 @@ bool GetKnownFolder(int shell_folder, REFKNOWNFOLDERID known_folder, bool create
{
shell_folder |= CSIDL_FLAG_CREATE;
}
if (FAILED(SHGetFolderPathA(NULL, shell_folder, NULL, 0, pathstr)))
if (FAILED(SHGetFolderPathA.Call(NULL, shell_folder, NULL, 0, pathstr)))
{
return false;
}
@ -110,7 +108,7 @@ bool GetKnownFolder(int shell_folder, REFKNOWNFOLDERID known_folder, bool create
else
{
PWSTR wpath;
if (FAILED(SHGetKnownFolderPath(known_folder, create ? KF_FLAG_CREATE : 0, NULL, &wpath)))
if (FAILED(SHGetKnownFolderPath.Call(known_folder, create ? KF_FLAG_CREATE : 0, NULL, &wpath)))
{
return false;
}

View file

@ -49,6 +49,7 @@
#include "i_music.h"
#include "m_joy.h"
#include "gi.h"
#include "i_sound.h"
#include "optionmenuitems.h"
@ -60,6 +61,8 @@ static FOptionMenuDescriptor DefaultOptionMenuSettings; // contains common setti
FOptionMenuSettings OptionSettings;
FOptionMap OptionValues;
void I_BuildALDeviceList(FOptionValues *opt);
static void DeinitMenus()
{
{
@ -168,6 +171,14 @@ static bool CheckSkipOptionBlock(FScanner &sc)
filter = true;
#endif
}
else if (sc.Compare("OpenAL"))
{
filter |= IsOpenALPresent();
}
else if (sc.Compare("FModEx"))
{
filter |= IsFModExPresent();
}
}
while (sc.CheckString(","));
sc.MustGetStringName(")");
@ -589,7 +600,11 @@ static void ParseOptionSettings(FScanner &sc)
while (!sc.CheckString("}"))
{
sc.MustGetString();
if (sc.Compare("ifgame"))
if (sc.Compare("else"))
{
SkipSubBlock(sc);
}
else if (sc.Compare("ifgame"))
{
if (!CheckSkipGameBlock(sc))
{
@ -626,7 +641,11 @@ static void ParseOptionMenuBody(FScanner &sc, FOptionMenuDescriptor *desc)
while (!sc.CheckString("}"))
{
sc.MustGetString();
if (sc.Compare("ifgame"))
if (sc.Compare("else"))
{
SkipSubBlock(sc);
}
else if (sc.Compare("ifgame"))
{
if (!CheckSkipGameBlock(sc))
{
@ -1262,6 +1281,11 @@ void M_CreateMenus()
{
I_BuildMIDIMenuList(*opt);
}
opt = OptionValues.CheckKey(NAME_Aldevices);
if (opt != NULL)
{
I_BuildALDeviceList(*opt);
}
}
//=============================================================================

View file

@ -489,7 +489,13 @@ bool FOptionMenuItem::MouseEvent(int type, int x, int y)
int FOptionMenuItem::GetIndent()
{
return mCentered? 0 : SmallFont->StringWidth(mLabel);
if (mCentered)
{
return 0;
}
const char *label = mLabel;
if (*label == '$') label = GStrings(label+1);
return SmallFont->StringWidth(label);
}
void FOptionMenuItem::drawLabel(int indent, int y, EColorRange color, bool grayed)

View file

@ -338,6 +338,7 @@ xx(Arg4)
xx(Arg0Str)
xx(Arg1Str)
xx(Id)
xx(MoreIds)
xx(V1)
xx(V2)
@ -565,6 +566,7 @@ xx(Controlmessage)
xx(Crosshairs)
xx(Colorpickermenu)
xx(Mididevices)
xx(Aldevices)
xx(CustomizeControls)
xx(MessageOptions)
xx(AutomapOptions)

View file

@ -113,7 +113,7 @@ public:
BYTE chipnum = reg >> 8;
if (chipnum != CurChip)
{
BYTE switcher[2] = { chipnum + 1, 2 };
BYTE switcher[2] = { (BYTE)(chipnum + 1), 2 };
fwrite(switcher, 1, 2, File);
}
reg &= 255;
@ -192,7 +192,7 @@ public:
"\0\0\0\0" // Total milliseconds
"\0\0\0", // Total data
1, 20, File);
char type[4] = { Dual * 2, 0, 0, 0 }; // Single or dual OPL-2
char type[4] = { (char)(Dual * 2), 0, 0, 0 }; // Single or dual OPL-2
fwrite(type, 1, 4, File);
}
virtual ~OPL_DOSBOXdump()

View file

@ -52,29 +52,22 @@ void OPLmusicBlock::Restart()
LastOffset = 0;
}
OPLmusicFile::OPLmusicFile (FILE *file, BYTE *musiccache, int len)
: ScoreLen (len)
OPLmusicFile::OPLmusicFile (FileReader *reader)
: ScoreLen (reader->GetLength())
{
if (io == NULL)
{
return;
}
scoredata = new BYTE[len];
scoredata = new BYTE[ScoreLen];
if (file)
{
if (fread (scoredata, 1, len, file) != (size_t)len)
if (reader->Read(scoredata, ScoreLen) != ScoreLen)
{
fail: delete[] scoredata;
scoredata = NULL;
return;
}
}
else
{
memcpy(scoredata, &musiccache[0], len);
}
if (0 == (NumChips = io->OPLinit(NumChips)))
{
@ -100,7 +93,7 @@ fail: delete[] scoredata;
{
RawPlayer = DosBox1;
SamplesPerTick = OPL_SAMPLE_RATE / 1000;
ScoreLen = MIN<int>(len - 24, LittleLong(((DWORD *)scoredata)[4])) + 24;
ScoreLen = MIN<int>(ScoreLen - 24, LittleLong(((DWORD *)scoredata)[4])) + 24;
}
else if (((DWORD *)scoredata)[2] == MAKE_ID(2,0,0,0))
{
@ -120,7 +113,7 @@ fail: delete[] scoredata;
RawPlayer = DosBox2;
SamplesPerTick = OPL_SAMPLE_RATE / 1000;
int headersize = 0x1A + scoredata[0x19];
ScoreLen = MIN<int>(len - headersize, LittleLong(((DWORD *)scoredata)[3]) * 2) + headersize;
ScoreLen = MIN<int>(ScoreLen - headersize, LittleLong(((DWORD *)scoredata)[3]) * 2) + headersize;
}
else
{

View file

@ -29,7 +29,7 @@ protected:
class OPLmusicFile : public OPLmusicBlock
{
public:
OPLmusicFile(FILE *file, BYTE *musiccache, int len);
OPLmusicFile(FileReader *reader);
OPLmusicFile(const OPLmusicFile *source, const char *filename);
virtual ~OPLmusicFile();

View file

@ -844,7 +844,7 @@ void P_Spawn3DFloors (void)
{
if (line->args[1]&8)
{
line->SetMainId(line->args[4]);
tagManager.AddLineID(i, line->args[4]);
}
else
{

View file

@ -167,7 +167,7 @@ void P_Attach3dMidtexLinesToSector(sector_t *sector, int lineid, int tag, bool c
{
line_t *ln = sectors[sec].lines[line];
if (lineid != 0 && !ln->HasId(lineid)) continue;
if (lineid != 0 && !tagManager.LineHasID(ln, lineid)) continue;
if (ln->frontsector == NULL || ln->backsector == NULL || !(ln->flags & ML_3DMIDTEX))
{

View file

@ -1562,7 +1562,7 @@ void FBehavior::StaticSerializeModuleStates (FArchive &arc)
if (modnum != StaticModules.Size())
{
I_Error ("Level was saved with a different number of ACS modules.");
I_Error("Level was saved with a different number of ACS modules. (Have %d, save has %d)", StaticModules.Size(), modnum);
}
for (modnum = 0; modnum < StaticModules.Size(); ++modnum)
@ -1583,7 +1583,7 @@ void FBehavior::StaticSerializeModuleStates (FArchive &arc)
if (stricmp (modname, module->ModuleName) != 0)
{
delete[] modname;
I_Error ("Level was saved with a different set of ACS modules.");
I_Error("Level was saved with a different set or order of ACS modules. (Have %s, save has %s)", module->ModuleName, modname);
}
else if (ModSize != module->GetDataSize())
{
@ -3210,7 +3210,7 @@ do_count:
if (actor->health > 0 &&
(kind == NULL || actor->IsA (kind)))
{
if (actor->Sector->HasTag(tag) || tag == -1)
if (tag == -1 || tagManager.SectorHasTag(actor->Sector, tag))
{
// Don't count items in somebody's inventory
if (!actor->IsKindOf (RUNTIME_CLASS(AInventory)) ||
@ -3230,7 +3230,7 @@ do_count:
if (actor->health > 0 &&
(kind == NULL || actor->IsA (kind)))
{
if (actor->Sector->HasTag(tag) || tag == -1)
if (tag == -1 || tagManager.SectorHasTag(actor->Sector, tag))
{
// Don't count items in somebody's inventory
if (!actor->IsKindOf (RUNTIME_CLASS(AInventory)) ||
@ -3898,7 +3898,13 @@ void DLevelScript::DoSetActorProperty (AActor *actor, int property, int value)
case APROP_ViewHeight:
if (actor->IsKindOf (RUNTIME_CLASS (APlayerPawn)))
{
static_cast<APlayerPawn *>(actor)->ViewHeight = value;
if (actor->player != NULL)
{
actor->player->viewheight = value;
}
}
break;
case APROP_AttackZOffset:

View file

@ -586,7 +586,7 @@ void P_DrawSplash2 (int count, fixed_t x, fixed_t y, fixed_t z, angle_t angle, i
}
}
void P_DrawRailTrail (AActor *source, const FVector3 &start, const FVector3 &end, int color1, int color2, double maxdiff_d, int flags, PClassActor *spawnclass, angle_t angle, int duration, double sparsity, double drift)
void P_DrawRailTrail (AActor *source, const FVector3 &start, const FVector3 &end, int color1, int color2, double maxdiff_d, int flags, PClassActor *spawnclass, angle_t angle, int duration, double sparsity, double drift, int SpiralOffset)
{
double length, lengthsquared;
int steps, i;
@ -679,7 +679,7 @@ void P_DrawRailTrail (AActor *source, const FVector3 &start, const FVector3 &end
color1 = color1 == 0 ? -1 : ParticleColor(color1);
pos = start;
deg = FAngle(270);
deg = FAngle(SpiralOffset);
for (i = spiral_steps; i; i--)
{
particle_t *p = NewParticle ();

View file

@ -88,7 +88,7 @@ void P_RunEffects (void);
void P_RunEffect (AActor *actor, int effects);
void P_DrawRailTrail (AActor *source, const FVector3 &start, const FVector3 &end, int color1, int color2, double maxdiff = 0, int flags = 0, PClassActor *spawnclass = NULL, angle_t angle = 0, int duration = 35, double sparsity = 1.0, double drift = 1.0);
void P_DrawRailTrail (AActor *source, const FVector3 &start, const FVector3 &end, int color1, int color2, double maxdiff = 0, int flags = 0, PClassActor *spawnclass = NULL, angle_t angle = 0, int duration = 35, double sparsity = 1.0, double drift = 1.0, int SpiralOffset = 270);
void P_DrawSplash (int count, fixed_t x, fixed_t y, fixed_t z, angle_t angle, int kind);
void P_DrawSplash2 (int count, fixed_t x, fixed_t y, fixed_t z, angle_t angle, int updown, int kind);
void P_DisconnectEffect (AActor *actor);

View file

@ -838,7 +838,7 @@ void EV_StopLightEffect (int tag)
while ((effect = iterator.Next()) != NULL)
{
if (effect->GetSector()->HasTag(tag))
if (tagManager.SectorHasTag(effect->GetSector(), tag))
{
effect->Destroy();
}

View file

@ -278,7 +278,7 @@ static void RemoveTaggedSectors(extsector_t::linked::plane &scrollplane, int tag
{
for(int i = scrollplane.Sectors.Size()-1; i>=0; i--)
{
if (scrollplane.Sectors[i].Sector->HasTag(tag))
if (tagManager.SectorHasTag(scrollplane.Sectors[i].Sector, tag))
{
scrollplane.Sectors.Delete(i);
}

View file

@ -1266,7 +1266,7 @@ FUNC(LS_Thing_Destroy)
while (actor)
{
AActor *temp = iterator.Next ();
if (actor->flags & MF_SHOOTABLE && actor->Sector->HasTag(arg2))
if (actor->flags & MF_SHOOTABLE && tagManager.SectorHasTag(actor->Sector, arg2))
P_DamageMobj (actor, NULL, it, arg1 ? TELEFRAG_DAMAGE : actor->health, NAME_None);
actor = temp;
}
@ -1279,7 +1279,7 @@ FUNC(LS_Thing_Destroy)
while (actor)
{
AActor *temp = iterator.Next ();
if (actor->flags & MF_SHOOTABLE && (arg2 == 0 || actor->Sector->HasTag(arg2)))
if (actor->flags & MF_SHOOTABLE && (arg2 == 0 || tagManager.SectorHasTag(actor->Sector, arg2)))
P_DamageMobj (actor, NULL, it, arg1 ? TELEFRAG_DAMAGE : actor->health, NAME_None);
actor = temp;
}
@ -2063,7 +2063,7 @@ static void SetWallScroller (int id, int sidechoice, fixed_t dx, fixed_t dy, int
{
int wallnum = scroller->GetWallNum ();
if (wallnum >= 0 && sides[wallnum].linedef->HasId(id) &&
if (wallnum >= 0 && tagManager.LineHasID(sides[wallnum].linedef, id) &&
int(sides[wallnum].linedef->sidedef[sidechoice] - sides) == wallnum &&
Where == scroller->GetScrollParts())
{
@ -2082,7 +2082,7 @@ static void SetWallScroller (int id, int sidechoice, fixed_t dx, fixed_t dy, int
while ( (collect.Obj = iterator.Next ()) )
{
if ((collect.RefNum = ((DScroller *)collect.Obj)->GetWallNum ()) != -1 &&
sides[collect.RefNum].linedef->HasId(id) &&
tagManager.LineHasID(sides[collect.RefNum].linedef, id) &&
int(sides[collect.RefNum].linedef->sidedef[sidechoice] - sides) == collect.RefNum &&
Where == ((DScroller *)collect.Obj)->GetScrollParts())
{
@ -2169,7 +2169,7 @@ static void SetScroller (int tag, DScroller::EScrollType type, fixed_t dx, fixed
{
if (scroller->IsType (type))
{
if (sectors[scroller->GetAffectee ()].HasTag(tag))
if (tagManager.SectorHasTag(scroller->GetAffectee (), tag))
{
i++;
scroller->SetRate (dx, dy);

View file

@ -478,7 +478,7 @@ void P_TraceBleed (int damage, AActor *target); // random direction version
bool P_HitFloor (AActor *thing);
bool P_HitWater (AActor *thing, sector_t *sec, fixed_t splashx = FIXED_MIN, fixed_t splashy = FIXED_MIN, fixed_t splashz=FIXED_MIN, bool checkabove = false, bool alert = true);
void P_CheckSplash(AActor *self, fixed_t distance);
void P_RailAttack (AActor *source, int damage, int offset_xy, fixed_t offset_z = 0, int color1 = 0, int color2 = 0, double maxdiff = 0, int flags = 0, PClassActor *puff = NULL, angle_t angleoffset = 0, angle_t pitchoffset = 0, fixed_t distance = 8192*FRACUNIT, int duration = 0, double sparsity = 1.0, double drift = 1.0, PClassActor *spawnclass = NULL); // [RH] Shoot a railgun
void P_RailAttack (AActor *source, int damage, int offset_xy, fixed_t offset_z = 0, int color1 = 0, int color2 = 0, double maxdiff = 0, int flags = 0, PClassActor *puff = NULL, angle_t angleoffset = 0, angle_t pitchoffset = 0, fixed_t distance = 8192*FRACUNIT, int duration = 0, double sparsity = 1.0, double drift = 1.0, PClassActor *spawnclass = NULL, int SpiralOffset = 270); // [RH] Shoot a railgun
enum // P_RailAttack / A_RailAttack / A_CustomRailgun / P_DrawRailTrail flags
{

View file

@ -1034,7 +1034,7 @@ bool PIT_CheckThing(AActor *thing, FCheckPosition &tm)
// Both things overlap in x or y direction
bool unblocking = false;
if (tm.FromPMove || tm.thing->player != NULL)
if ((tm.FromPMove || tm.thing->player != NULL) && thing->flags&MF_SOLID)
{
// Both actors already overlap. To prevent them from remaining stuck allow the move if it
// takes them further apart or the move does not change the position (when called from P_ChangeSector.)
@ -1042,7 +1042,9 @@ bool PIT_CheckThing(AActor *thing, FCheckPosition &tm)
{
unblocking = true;
}
else
else if (abs(thing->x - tm.thing->x) < (thing->radius+tm.thing->radius)/2 &&
abs(thing->y - tm.thing->y) < (thing->radius+tm.thing->radius)/2)
{
fixed_t newdist = P_AproxDistance(thing->x - tm.x, thing->y - tm.y);
fixed_t olddist = P_AproxDistance(thing->x - tm.thing->x, thing->y - tm.thing->y);
@ -4140,7 +4142,7 @@ static ETraceStatus ProcessRailHit(FTraceResults &res, void *userdata)
//
//
//==========================================================================
void P_RailAttack(AActor *source, int damage, int offset_xy, fixed_t offset_z, int color1, int color2, double maxdiff, int railflags, PClassActor *puffclass, angle_t angleoffset, angle_t pitchoffset, fixed_t distance, int duration, double sparsity, double drift, PClassActor *spawnclass)
void P_RailAttack(AActor *source, int damage, int offset_xy, fixed_t offset_z, int color1, int color2, double maxdiff, int railflags, PClassActor *puffclass, angle_t angleoffset, angle_t pitchoffset, fixed_t distance, int duration, double sparsity, double drift, PClassActor *spawnclass, int SpiralOffset)
{
fixed_t vx, vy, vz;
angle_t angle, pitch;
@ -4295,7 +4297,7 @@ void P_RailAttack(AActor *source, int damage, int offset_xy, fixed_t offset_z, i
end.X = FIXED2FLOAT(trace.X);
end.Y = FIXED2FLOAT(trace.Y);
end.Z = FIXED2FLOAT(trace.Z);
P_DrawRailTrail(source, start, end, color1, color2, maxdiff, railflags, spawnclass, source->angle + angleoffset, duration, sparsity, drift);
P_DrawRailTrail(source, start, end, color1, color2, maxdiff, railflags, spawnclass, source->angle + angleoffset, duration, sparsity, drift, SpiralOffset);
}
//==========================================================================

View file

@ -3545,7 +3545,7 @@ void AActor::Tick ()
}
else if (scrolltype == Scroll_StrifeCurrent)
{ // Strife scroll special
int anglespeed = sec->GetMainTag() - 100;
int anglespeed = tagManager.GetFirstSectorTag(sec) - 100;
fixed_t carryspeed = DivScale32 (anglespeed % 10, 16*CARRYFACTOR);
angle_t fineangle = (anglespeed / 10) << (32-3);
fineangle >>= ANGLETOFINESHIFT;
@ -4857,7 +4857,7 @@ AActor *P_SpawnMapThing (FMapThing *mthing, int position)
// [RH] sound sequence overriders
if (mentry->Type == NULL && mentry->Special == SMT_SSeqOverride)
{
int type = mentry->Args[0];
int type = mthing->args[0];
if (type == 255) type = -1;
if (type > 63)
{

View file

@ -348,9 +348,13 @@ void P_SerializeWorld (FArchive &arc)
{
arc << sec->lightlevel;
}
arc << sec->special
<< sec->tag
<< sec->soundtraversed
arc << sec->special;
if (SaveVersion < 4523)
{
short tag;
arc << tag;
}
arc << sec->soundtraversed
<< sec->seqType
<< sec->friction
<< sec->movefactor
@ -405,8 +409,13 @@ void P_SerializeWorld (FArchive &arc)
arc << li->flags
<< li->activation
<< li->special
<< li->Alpha
<< li->id;
<< li->Alpha;
if (SaveVersion < 4523)
{
int id;
arc << id;
}
if (P_IsACSSpecial(li->special))
{
P_SerializeACSScriptNumber(arc, li->args[0], false);

View file

@ -825,77 +825,6 @@ sector_t *sector_t::GetHeightSec() const
}
bool sector_t::HasTag(int checktag) const
{
return tag == checktag;
}
bool sector_t::HasTags() const
{
return tag != 0;
}
void sector_t::SetMainTag(int tagnum)
{
tag = tagnum;
}
int sector_t::GetMainTag() const
{
return tag;
}
void sector_t::ClearTags()
{
tag = 0;
}
void sector_t::HashTags()
{
int i;
for (i=numsectors; --i>=0; ) // Initially make all slots empty.
sectors[i].firsttag = -1;
for (i=numsectors; --i>=0; ) // Proceed from last to first sector
{ // so that lower sectors appear first
int j = (unsigned) sectors[i].tag % (unsigned) numsectors; // Hash func
sectors[i].nexttag = sectors[j].firsttag; // Prepend sector to chain
sectors[j].firsttag = i;
}
}
void line_t::SetMainId(int newid)
{
id = newid;
}
void line_t::ClearIds()
{
id = -1;
}
bool line_t::HasId(int checkid) const
{
return id == checkid;
}
void line_t::HashIds()
{
// killough 4/17/98: same thing, only for linedefs
int i;
for (i=numlines; --i>=0; ) // Initially make all slots empty.
lines[i].firstid = -1;
for (i=numlines; --i>=0; ) // Proceed from last to first linedef
{ // so that lower linedefs appear first
int j = (unsigned) lines[i].id % (unsigned) numlines; // Hash func
lines[i].nextid = lines[j].firstid; // Prepend linedef to chain
lines[j].firstid = i;
}
}
bool secplane_t::CopyPlaneIfValid (secplane_t *dest, const secplane_t *opp) const
{
bool copy = false;

View file

@ -1513,7 +1513,7 @@ void P_LoadSectors (MapData *map, FMissingTextureTracker &missingtex)
else // [RH] Translate to new sector special
ss->special = P_TranslateSectorSpecial (LittleShort(ms->special));
ss->secretsector = !!(ss->special&SECRET_MASK);
ss->SetMainTag(LittleShort(ms->tag));
tagManager.AddSectorTag(i, LittleShort(ms->tag));
ss->thinglist = NULL;
ss->touching_thinglist = NULL; // phares 3/14/98
ss->seqType = defSeqType;
@ -1904,54 +1904,59 @@ void P_AdjustLine (line_t *ld)
}
}
void P_SetLineID (line_t *ld)
void P_SetLineID (int i, line_t *ld)
{
// [RH] Set line id (as appropriate) here
// for Doom format maps this must be done in P_TranslateLineDef because
// the tag doesn't always go into the first arg.
if (level.maptype == MAPTYPE_HEXEN)
{
int setid = -1;
switch (ld->special)
{
case Line_SetIdentification:
if (!(level.flags2 & LEVEL2_HEXENHACK))
{
ld->SetMainId(ld->args[0] + 256 * ld->args[4]);
setid = ld->args[0] + 256 * ld->args[4];
ld->flags |= ld->args[1]<<16;
}
else
{
ld->SetMainId(ld->args[0]);
setid = ld->args[0];
}
ld->special = 0;
break;
case TranslucentLine:
ld->SetMainId(ld->args[0]);
setid = ld->args[0];
ld->flags |= ld->args[3]<<16;
break;
case Teleport_Line:
case Scroll_Texture_Model:
ld->SetMainId(ld->args[0]);
setid = ld->args[0];
break;
case Polyobj_StartLine:
ld->SetMainId(ld->args[3]);
setid = ld->args[3];
break;
case Polyobj_ExplicitLine:
ld->SetMainId(ld->args[4]);
setid = ld->args[4];
break;
case Plane_Align:
ld->SetMainId(ld->args[2]);
setid = ld->args[2];
break;
case Static_Init:
if (ld->args[1] == Init_SectorLink) ld->SetMainId(ld->args[0]);
if (ld->args[1] == Init_SectorLink) setid = ld->args[0];
break;
}
if (setid != -1)
{
tagManager.AddLineID(i, setid);
}
}
}
@ -2034,7 +2039,7 @@ void P_FinishLoadingLineDef(line_t *ld, int alpha)
{
for (j = 0; j < numlines; j++)
{
if (lines[j].HasId(ld->args[0]))
if (tagManager.LineHasID(j, ld->args[0]))
{
lines[j].Alpha = alpha;
if (additive)
@ -2136,13 +2141,13 @@ void P_LoadLineDefs (MapData * map)
mld = (maplinedef_t *)mldf;
ld = lines;
for (i = numlines; i > 0; i--, mld++, ld++)
for (i = 0; i < numlines; i++, mld++, ld++)
{
ld->Alpha = FRACUNIT; // [RH] Opaque by default
// [RH] Translate old linedef special and flags to be
// compatible with the new format.
P_TranslateLineDef (ld, mld, true);
P_TranslateLineDef (ld, mld, i);
ld->v1 = &vertexes[LittleShort(mld->v1)];
ld->v2 = &vertexes[LittleShort(mld->v2)];
@ -2215,7 +2220,7 @@ void P_LoadLineDefs2 (MapData * map)
mld = (maplinedef2_t *)mldf;
ld = lines;
for (i = numlines; i > 0; i--, mld++, ld++)
for (i = 0; i < numlines; i++, mld++, ld++)
{
int j;
@ -2228,13 +2233,12 @@ void P_LoadLineDefs2 (MapData * map)
ld->v1 = &vertexes[LittleShort(mld->v1)];
ld->v2 = &vertexes[LittleShort(mld->v2)];
ld->Alpha = FRACUNIT; // [RH] Opaque by default
ld->ClearIds();
P_SetSideNum (&ld->sidedef[0], LittleShort(mld->sidenum[0]));
P_SetSideNum (&ld->sidedef[1], LittleShort(mld->sidenum[1]));
P_AdjustLine (ld);
P_SetLineID(ld);
P_SetLineID(i, ld);
P_SaveLineSpecial (ld);
if (level.flags2 & LEVEL2_CLIPMIDTEX) ld->flags |= ML_CLIP_MIDTEX;
if (level.flags2 & LEVEL2_WRAPMIDTEX) ld->flags |= ML_WRAP_MIDTEX;
@ -2490,7 +2494,7 @@ void P_ProcessSideTextures(bool checktranmap, side_t *sd, sector_t *sec, intmaps
for (s = 0; s < numsectors; s++)
{
if (sectors[s].HasTag(tag))
if (tagManager.SectorHasTag(s, tag))
{
if (!colorgood) color = sectors[s].ColorMap->Color;
if (!foggood) fog = sectors[s].ColorMap->Fade;
@ -3126,9 +3130,9 @@ static void P_GroupLines (bool buildmap)
{
if (sector->linecount == 0)
{
Printf ("Sector %i (tag %i) has no lines\n", i, sector->GetMainTag());
Printf ("Sector %i (tag %i) has no lines\n", i, tagManager.GetFirstSectorTag(sector));
// 0 the sector's tag so that no specials can use it
sector->ClearTags();
tagManager.RemoveSectorTags(i);
}
else
{
@ -3205,8 +3209,7 @@ static void P_GroupLines (bool buildmap)
// [RH] Moved this here
times[4].Clock();
// killough 1/30/98: Create xref tables for tags
sector_t::HashTags();
line_t::HashIds();
tagManager.HashTags();
times[4].Unclock();
times[5].Clock();
@ -3337,6 +3340,7 @@ void P_FreeLevelData ()
FPolyObj::ClearAllSubsectorLinks(); // can't be done as part of the polyobj deletion process.
SN_StopAllSequences ();
DThinker::DestroyAllThinkers ();
tagManager.Clear();
level.total_monsters = level.total_items = level.total_secrets =
level.killed_monsters = level.found_items = level.found_secrets =
wminfo.maxfrags = 0;

View file

@ -115,7 +115,7 @@ struct line_t;
struct maplinedef_t;
void P_LoadTranslator(const char *lumpname);
void P_TranslateLineDef (line_t *ld, maplinedef_t *mld, bool setlineid);
void P_TranslateLineDef (line_t *ld, maplinedef_t *mld, int lineindexforid = -1);
int P_TranslateSectorSpecial (int);
int GetUDMFInt(int type, int index, const char *key);

View file

@ -186,57 +186,6 @@ bool CheckIfExitIsGood (AActor *self, level_info_t *info)
// UTILITIES
//
//
// RETURN NEXT SECTOR # THAT LINE TAG REFERS TO
//
// Find the next sector with a specified tag.
// Rewritten by Lee Killough to use chained hashing to improve speed
int FSectorTagIterator::Next()
{
int ret;
if (searchtag == INT_MIN)
{
ret = start;
start = -1;
}
else
{
while (start != -1 && sectors[start].tag != searchtag) start = sectors[start].nexttag;
if (start == -1) return -1;
ret = start;
start = sectors[start].nexttag;
}
return ret;
}
int FSectorTagIterator::NextCompat(bool compat, int start)
{
if (!compat) return Next();
for (int i = start + 1; i < numsectors; i++)
{
if (sectors[i].HasTag(searchtag)) return i;
}
return -1;
}
// killough 4/16/98: Same thing, only for linedefs
int FLineIdIterator::Next()
{
while (start != -1 && lines[start].id != searchtag) start = lines[start].nextid;
if (start == -1) return -1;
int ret = start;
start = lines[start].nextid;
return ret;
}
//============================================================================
//
// P_ActivateLine
@ -283,7 +232,7 @@ bool P_ActivateLine (line_t *line, AActor *mo, int side, int activationType)
!repeat && // only non-repeatable triggers
(special<Generic_Floor || special>Generic_Crusher) && // not for Boom's generalized linedefs
special && // not for lines without a special
line->HasId(line->args[0]) && // Safety check: exclude edited UDMF linedefs or ones that don't map the tag to args[0]
tagManager.LineHasID(line, line->args[0]) && // Safety check: exclude edited UDMF linedefs or ones that don't map the tag to args[0]
line->args[0] && // only if there's a tag (which is stored in the first arg)
P_FindFirstSectorFromTag (line->args[0]) == -1) // only if no sector is tagged to this linedef
{
@ -1792,7 +1741,7 @@ static void P_SpawnScrollers(void)
if (lines[i].special == Sector_CopyScroller)
{
// don't allow copying the scroller if the sector has the same tag as it would just duplicate it.
if (lines[i].frontsector->HasTag(lines[i].args[0]))
if (tagManager.SectorHasTag(lines[i].frontsector, lines[i].args[0]))
{
copyscrollers.Push(i);
}
@ -2200,7 +2149,7 @@ DPusher::DPusher (DPusher::EPusher type, line_t *l, int magnitude, int angle,
int DPusher::CheckForSectorMatch (EPusher type, int tag)
{
if (m_Type == type && sectors[m_Affectee].HasTag(tag))
if (m_Type == type && tagManager.SectorHasTag(m_Affectee, tag))
return m_Affectee;
else
return -1;

View file

@ -242,66 +242,8 @@ inline sector_t *getNextSector (line_t *line, const sector_t *sec)
line->frontsector;
}
class FSectorTagIterator
{
protected:
int searchtag;
int start;
public:
FSectorTagIterator(int tag)
{
searchtag = tag;
start = sectors[(unsigned)tag % (unsigned)numsectors].firsttag;
}
// Special constructor for actions that treat tag 0 as 'back of activation line'
FSectorTagIterator(int tag, line_t *line)
{
if (tag == 0)
{
searchtag = INT_MIN;
start = (line == NULL || line->backsector == NULL)? -1 : (int)(line->backsector - sectors);
}
else
{
searchtag = tag;
start = sectors[(unsigned)tag % (unsigned)numsectors].firsttag;
}
}
int Next();
int NextCompat(bool compat, int secnum);
};
class FLineIdIterator
{
protected:
int searchtag;
int start;
public:
FLineIdIterator(int id)
{
searchtag = id;
start = lines[(unsigned) id % (unsigned) numlines].firstid;
}
int Next();
};
inline int P_FindFirstSectorFromTag(int tag)
{
FSectorTagIterator it(tag);
return it.Next();
}
inline int P_FindFirstLineFromID(int tag)
{
FLineIdIterator it(tag);
return it.Next();
}
#include "p_tags.h"
//
// P_LIGHTS

353
src/p_tags.cpp Normal file
View file

@ -0,0 +1,353 @@
/*
** p_tags.cpp
** everything to do with tags and their management
**
**---------------------------------------------------------------------------
** Copyright 2015 Christoph Oelckers
** All rights reserved.
**
** 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 "p_tags.h"
#include "c_dispatch.h"
FTagManager tagManager;
//-----------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------
static inline int sectindex(const sector_t *sector)
{
return (int)(intptr_t)(sector - sectors);
}
static inline int lineindex(const line_t *line)
{
return (int)(intptr_t)(line - lines);
}
//-----------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------
void FTagManager::AddSectorTag(int sector, int tag)
{
if (tag == 0) return;
// This function assumes that all tags for a single sector get added sequentially.
// Should there ever be some need for compatibility.txt to add tags to sectors which already have a tag this function needs to be changed to adjust the startForSector indices.
while (startForSector.Size() <= (unsigned int)sector)
{
startForSector.Push(-1);
}
if (startForSector[sector] == -1)
{
startForSector[sector] = allTags.Size();
}
else
{
// check if the key was already defined
for (unsigned i = startForSector[sector]; i < allTags.Size(); i++)
{
if (allTags[i].tag == tag)
{
return;
}
}
}
FTagItem it = { sector, tag, -1 };
allTags.Push(it);
}
//-----------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------
void FTagManager::RemoveSectorTags(int sect)
{
int start = startForSector[sect];
if (start >= 0)
{
while (allTags[start].target == sect)
{
allTags[start].tag = allTags[start].target = -1;
start++;
}
}
}
//-----------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------
void FTagManager::AddLineID(int line, int tag)
{
if (tag == -1) return; // For line IDs -1 means 'not set', unlike sectors.
// This function assumes that all ids for a single line get added sequentially.
while (startForLine.Size() <= (unsigned int)line)
{
startForLine.Push(-1);
}
if (startForLine[line] == -1)
{
startForLine[line] = allIDs.Size();
}
else
{
// check if the key was already defined
for (unsigned i = startForLine[line]; i < allIDs.Size(); i++)
{
if (allIDs[i].tag == tag)
{
return;
}
}
}
FTagItem it = { line, tag, -1 };
allIDs.Push(it);
}
//-----------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------
void FTagManager::HashTags()
{
// add an end marker so we do not need to check for the array's size in the other functions.
static FTagItem it = { -1, -1, -1 };
allTags.Push(it);
allIDs.Push(it);
// Initially make all slots empty.
memset(TagHashFirst, -1, sizeof(TagHashFirst));
memset(IDHashFirst, -1, sizeof(IDHashFirst));
// Proceed from last to first so that lower targets appear first
for (int i = allTags.Size() - 1; i >= 0; i--)
{
if (allTags[i].target >= 0) // only link valid entries
{
int hash = ((unsigned int)allTags[i].tag) % FTagManager::TAG_HASH_SIZE;
allTags[i].nexttag = TagHashFirst[hash];
TagHashFirst[hash] = i;
}
}
for (int i = allIDs.Size() - 1; i >= 0; i--)
{
if (allIDs[i].target >= 0) // only link valid entries
{
int hash = ((unsigned int)allIDs[i].tag) % FTagManager::TAG_HASH_SIZE;
allIDs[i].nexttag = IDHashFirst[hash];
IDHashFirst[hash] = i;
}
}
}
//-----------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------
bool FTagManager::SectorHasTags(const sector_t *sector) const
{
int i = sectindex(sector);
return SectorHasTags(i);
}
//-----------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------
int FTagManager::GetFirstSectorTag(const sector_t *sect) const
{
int i = sectindex(sect);
return SectorHasTags(i) ? allTags[startForSector[i]].tag : 0;
}
//-----------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------
bool FTagManager::SectorHasTag(int i, int tag) const
{
if (SectorHasTags(i))
{
int ndx = startForSector[i];
while (allTags[ndx].target == i)
{
if (allTags[ndx].tag == tag) return true;
ndx++;
}
}
return false;
}
//-----------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------
bool FTagManager::SectorHasTag(const sector_t *sector, int tag) const
{
return SectorHasTag(sectindex(sector), tag);
}
//-----------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------
bool FTagManager::LineHasID(int i, int tag) const
{
if (LineHasIDs(i))
{
int ndx = startForLine[i];
while (allIDs[ndx].target == i)
{
if (allIDs[ndx].tag == tag) return true;
ndx++;
}
}
return false;
}
//-----------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------
bool FTagManager::LineHasID(const line_t *line, int tag) const
{
return LineHasID(lineindex(line), tag);
}
//-----------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------
void FTagManager::DumpTags()
{
for (unsigned i = 0; i < allTags.Size(); i++)
{
Printf("Sector %d, tag %d\n", allTags[i].target, allTags[i].tag);
}
for (unsigned i = 0; i < allIDs.Size(); i++)
{
Printf("Line %d, ID %d\n", allIDs[i].target, allIDs[i].tag);
}
}
CCMD(dumptags)
{
tagManager.DumpTags();
}
//-----------------------------------------------------------------------------
//
// RETURN NEXT SECTOR # THAT LINE TAG REFERS TO
//
// Find the next sector with a specified tag.
// Rewritten by Lee Killough to use chained hashing to improve speed
//
//-----------------------------------------------------------------------------
int FSectorTagIterator::Next()
{
int ret;
if (searchtag == INT_MIN)
{
ret = start;
start = -1;
}
else
{
while (start >= 0 && tagManager.allTags[start].tag != searchtag) start = tagManager.allTags[start].nexttag;
if (start == -1) return -1;
ret = tagManager.allTags[start].target;
start = start = tagManager.allTags[start].nexttag;
}
return ret;
}
//-----------------------------------------------------------------------------
//
// linear search for compatible stair building
//
//-----------------------------------------------------------------------------
int FSectorTagIterator::NextCompat(bool compat, int start)
{
if (!compat) return Next();
for (int i = start + 1; i < numsectors; i++)
{
if (tagManager.SectorHasTag(i, searchtag)) return i;
}
return -1;
}
//-----------------------------------------------------------------------------
//
// killough 4/16/98: Same thing, only for linedefs
//
//-----------------------------------------------------------------------------
int FLineIdIterator::Next()
{
while (start >= 0 && tagManager.allIDs[start].tag != searchtag) start = tagManager.allIDs[start].nexttag;
if (start == -1) return -1;
int ret = tagManager.allIDs[start].target;
start = start = tagManager.allIDs[start].nexttag;
return ret;
}

133
src/p_tags.h Normal file
View file

@ -0,0 +1,133 @@
#ifndef P_TAGS_H
#define P_TAGS_H 1
#include "r_defs.h"
#include "r_state.h"
struct FTagItem
{
int target; // either sector or line
int tag;
int nexttag; // for hashing
};
class FSectorTagIterator;
class FLineIdIterator;
class FTagManager
{
enum
{
TAG_HASH_SIZE = 256
};
friend class FSectorTagIterator;
friend class FLineIdIterator;
TArray<FTagItem> allTags;
TArray<FTagItem> allIDs;
TArray<int> startForSector;
TArray<int> startForLine;
int TagHashFirst[TAG_HASH_SIZE];
int IDHashFirst[TAG_HASH_SIZE];
bool SectorHasTags(int sect) const
{
return sect >= 0 && sect < (int)startForSector.Size() && startForSector[sect] >= 0;
}
bool LineHasIDs(int sect) const
{
return sect >= 0 && sect < (int)startForLine.Size() && startForLine[sect] >= 0;
}
public:
void Clear()
{
allTags.Clear();
allIDs.Clear();
startForSector.Clear();
startForLine.Clear();
memset(TagHashFirst, -1, sizeof(TagHashFirst));
}
bool SectorHasTags(const sector_t *sector) const;
int GetFirstSectorTag(const sector_t *sect) const;
bool SectorHasTag(int sector, int tag) const;
bool SectorHasTag(const sector_t *sector, int tag) const;
bool LineHasID(int line, int id) const;
bool LineHasID(const line_t *line, int id) const;
void HashTags();
void AddSectorTag(int sector, int tag);
void AddLineID(int line, int tag);
void RemoveSectorTags(int sect);
void DumpTags();
};
extern FTagManager tagManager;
class FSectorTagIterator
{
protected:
int searchtag;
int start;
public:
FSectorTagIterator(int tag)
{
searchtag = tag;
start = tagManager.TagHashFirst[((unsigned int)tag) % FTagManager::TAG_HASH_SIZE];
}
// Special constructor for actions that treat tag 0 as 'back of activation line'
FSectorTagIterator(int tag, line_t *line)
{
if (tag == 0)
{
searchtag = INT_MIN;
start = (line == NULL || line->backsector == NULL)? -1 : (int)(line->backsector - sectors);
}
else
{
searchtag = tag;
start = tagManager.TagHashFirst[((unsigned int)tag) % FTagManager::TAG_HASH_SIZE];
}
}
int Next();
int NextCompat(bool compat, int secnum);
};
class FLineIdIterator
{
protected:
int searchtag;
int start;
public:
FLineIdIterator(int id)
{
searchtag = id;
start = tagManager.IDHashFirst[((unsigned int)id) % FTagManager::TAG_HASH_SIZE];
}
int Next();
};
inline int P_FindFirstSectorFromTag(int tag)
{
FSectorTagIterator it(tag);
return it.Next();
}
inline int P_FindFirstLineFromID(int tag)
{
FLineIdIterator it(tag);
return it.Next();
}
#endif

View file

@ -249,7 +249,7 @@ static AActor *SelectTeleDest (int tid, int tag, bool norandom)
int count = 0;
while ( (searcher = iterator.Next ()) )
{
if (tag == 0 || searcher->Sector->HasTag(tag))
if (tag == 0 || tagManager.SectorHasTag(searcher->Sector, tag))
{
count++;
}
@ -288,7 +288,7 @@ static AActor *SelectTeleDest (int tid, int tag, bool norandom)
while (count > 0)
{
searcher = iterator.Next ();
if (tag == 0 || searcher->Sector->HasTag(tag))
if (tag == 0 || tagManager.SectorHasTag(searcher->Sector, tag))
{
count--;
}

View file

@ -659,9 +659,13 @@ void InitClassMap(FClassMap &themap, SpawnMap &thedata)
pair->Value.filename.GetChars(), pair->Value.linenum, pair->Value.classname.GetChars());
error++;
}
}
themap.Insert(pair->Key, cls);
}
else
{
themap.Remove(pair->Key);
}
}
if (error > 0)
{
I_Error("%d unknown actor classes found", error);

View file

@ -46,6 +46,7 @@
#include "r_state.h"
#include "r_data/colormaps.h"
#include "w_wad.h"
#include "p_tags.h"
//===========================================================================
//
@ -754,7 +755,7 @@ public:
mld.flags = 0;
mld.special = th->special;
mld.tag = th->args[0];
P_TranslateLineDef(&ld, &mld, true);
P_TranslateLineDef(&ld, &mld);
th->special = ld.special;
memcpy(th->args, ld.args, sizeof (ld.args));
}
@ -779,10 +780,10 @@ public:
bool strifetrans2 = false;
FString arg0str, arg1str;
int lineid; // forZDoomTranslated namespace
FString tagstring;
memset(ld, 0, sizeof(*ld));
ld->Alpha = FRACUNIT;
ld->ClearIds();
ld->sidedef[0] = ld->sidedef[1] = NULL;
if (level.flags2 & LEVEL2_CLIPMIDTEX) ld->flags |= ML_CLIP_MIDTEX;
if (level.flags2 & LEVEL2_WRAPMIDTEX) ld->flags |= ML_WRAP_MIDTEX;
@ -816,7 +817,7 @@ public:
case NAME_Id:
lineid = CheckInt(key);
ld->SetMainId(lineid);
tagManager.AddLineID(index, lineid);
continue;
case NAME_Sidefront:
@ -1039,22 +1040,17 @@ public:
Flag(ld->flags, ML_3DMIDTEX_IMPASS, key);
continue;
case NAME_MoreIds:
// delay parsing of the tag string until parsing of the sector is complete
// This ensures that the ID is always the first tag in the list.
tagstring = CheckString(key);
break;
default:
break;
}
#if 0 // for later
if (namespace_bits & (Zd)) && !strnicmp(key.GetChars(), "Id", 2))
{
char *endp;
int num = strtol(key.GetChars(), &endp, 10);
if (num > 0 && *endp == NULL)
{
// only allow ID## with ## as a proper number
ld->SetId((short)CheckInt(key), false);
}
}
#endif
if ((namespace_bits & (Zd | Zdt)) && !strnicmp("user_", key.GetChars(), 5))
{
@ -1062,6 +1058,17 @@ public:
}
}
if (tagstring.IsNotEmpty())
{
FScanner sc;
sc.OpenString("tagstring", tagstring);
// scan the string as long as valid numbers can be found
while (sc.CheckNumber())
{
if (sc.Number != 0) tagManager.AddLineID(index, sc.Number);
}
}
if (isTranslated)
{
int saved = ld->flags;
@ -1070,7 +1077,7 @@ public:
memset(&mld, 0, sizeof(mld));
mld.special = ld->special;
mld.tag = lineid;
P_TranslateLineDef(ld, &mld, false);
P_TranslateLineDef(ld, &mld);
ld->flags = saved | (ld->flags&(ML_MONSTERSCANACTIVATE|ML_REPEAT_SPECIAL|ML_FIRSTSIDEONLY));
}
if (passuse && (ld->activation & SPAC_Use))
@ -1269,6 +1276,7 @@ public:
int desaturation = -1;
int fplaneflags = 0, cplaneflags = 0;
double fp[4] = { 0 }, cp[4] = { 0 };
FString tagstring;
memset(sec, 0, sizeof(*sec));
sec->lightlevel = 160;
@ -1332,7 +1340,7 @@ public:
continue;
case NAME_Id:
sec->SetMainTag((short)CheckInt(key));
tagManager.AddSectorTag(index, CheckInt(key));
continue;
default:
@ -1510,28 +1518,32 @@ public:
cp[3] = CheckFloat(key);
break;
case NAME_MoreIds:
// delay parsing of the tag string until parsing of the sector is complete
// This ensures that the ID is always the first tag in the list.
tagstring = CheckString(key);
break;
default:
break;
}
#if 0 // for later
if (namespace_bits & (Zd)) && !strnicmp(key.GetChars(), "Id", 2))
{
char *endp;
int num = strtol(key.GetChars(), &endp, 10);
if (num > 0 && *endp == NULL)
{
// only allow ID## with ## as a proper number
sec->SetTag((short)CheckInt(key), false);
}
}
#endif
if ((namespace_bits & (Zd | Zdt)) && !strnicmp("user_", key.GetChars(), 5))
{
AddUserKey(key, UDMF_Sector, index);
}
}
if (tagstring.IsNotEmpty())
{
FScanner sc;
sc.OpenString("tagstring", tagstring);
// scan the string as long as valid numbers can be found
while (sc.CheckNumber())
{
if (sc.Number != 0) tagManager.AddSectorTag(index, sc.Number);
}
}
sec->secretsector = !!(sec->special&SECRET_MASK);
// Reset the planes to their defaults if not all of the plane equation's parameters were found.

View file

@ -262,7 +262,7 @@ static int WriteSECTORS (FILE *file)
uppercopy (ms.ceilingpic, GetTextureName (sectors[i].GetTexture(sector_t::ceiling)));
ms.lightlevel = LittleShort((short)sectors[i].lightlevel);
ms.special = LittleShort(sectors[i].special);
ms.tag = LittleShort(sectors[i].GetMainTag());
ms.tag = LittleShort(tagManager.GetFirstSectorTag(&sectors[i]));
fwrite (&ms, sizeof(ms), 1, file);
}
return numsectors * sizeof(ms);

View file

@ -60,7 +60,7 @@ typedef enum
PushMany,
} triggertype_e;
void P_TranslateLineDef (line_t *ld, maplinedef_t *mld, bool setid)
void P_TranslateLineDef (line_t *ld, maplinedef_t *mld, int lineindexforid)
{
unsigned short special = (unsigned short) LittleShort(mld->special);
short tag = LittleShort(mld->tag);
@ -100,13 +100,13 @@ void P_TranslateLineDef (line_t *ld, maplinedef_t *mld, bool setid)
}
flags = newflags;
if (setid)
if (lineindexforid >= 0)
{
// For purposes of maintaining BOOM compatibility, each
// line also needs to have its ID set to the same as its tag.
// An external conversion program would need to do this more
// intelligently.
ld->SetMainId(tag);
tagManager.AddLineID(lineindexforid, tag);
}
// 0 specials are never translated.
@ -307,7 +307,7 @@ void P_TranslateTeleportThings ()
while ( (dest = iterator.Next()) )
{
if (!dest->Sector->HasTags())
if (!tagManager.SectorHasTags(dest->Sector))
{
dest->tid = 1;
dest->AddToHash ();

View file

@ -633,12 +633,6 @@ struct sector_t
return pos == floor? floorplane:ceilingplane;
}
bool HasTag(int checktag) const;
bool HasTags() const;
void SetMainTag(int tagnum);
int GetMainTag() const;
void ClearTags();
static void HashTags();
bool PlaneMoving(int pos);
@ -657,12 +651,9 @@ struct sector_t
TObjPtr<AActor> SoundTarget;
short special;
short tag;
short lightlevel;
short seqType; // this sector's sound sequence
int nexttag,firsttag; // killough 1/30/98: improves searches for tags.
int sky;
FNameNoInit SeqName; // Sound sequence name. Setting seqType non-negative will override this.
@ -897,21 +888,12 @@ struct line_t
DWORD activation; // activation type
int special;
fixed_t Alpha; // <--- translucency (0=invisibile, FRACUNIT=opaque)
int id; // <--- same as tag or set with Line_SetIdentification
int args[5]; // <--- hexen-style arguments (expanded to ZDoom's full width)
int firstid, nextid;
side_t *sidedef[2];
//DWORD sidenum[2]; // sidenum[1] will be NO_SIDE if one sided
fixed_t bbox[4]; // bounding box, for the extent of the LineDef.
sector_t *frontsector, *backsector;
int validcount; // if == validcount, already checked
int locknumber; // [Dusk] lock number for special
void SetMainId(int newid);
void ClearIds();
bool HasId(int id) const;
static void HashIds();
};
// phares 3/14/98

View file

@ -1366,7 +1366,7 @@ static void S_AddSNDINFO (int lump)
FName nm = sc.String;
sc.MustGetString();
if (sc.Compare("timidity")) MidiDevices[nm] = MDEV_TIMIDITY;
else if (sc.Compare("fmod")) MidiDevices[nm] = MDEV_FMOD;
else if (sc.Compare("fmod") || sc.Compare("sndsys")) MidiDevices[nm] = MDEV_SNDSYS;
else if (sc.Compare("standard")) MidiDevices[nm] = MDEV_MMAPI;
else if (sc.Compare("opl")) MidiDevices[nm] = MDEV_OPL;
else if (sc.Compare("default")) MidiDevices[nm] = MDEV_DEFAULT;

View file

@ -487,6 +487,11 @@ void S_PrecacheLevel ()
{
level.info->PrecacheSounds[i].MarkUsed();
}
// Don't unload sounds that are playing right now.
for (FSoundChan *chan = Channels; chan != NULL; chan = chan->NextChan)
{
chan->SoundID.MarkUsed();
}
for (i = 1; i < S_sfx.Size(); ++i)
{
@ -1311,53 +1316,36 @@ sfxinfo_t *S_LoadSound(sfxinfo_t *sfx)
int size = Wads.LumpLength(sfx->lumpnum);
if (size > 0)
{
BYTE *sfxdata;
BYTE *sfxstart;
FWadLump wlump = Wads.OpenLumpNum(sfx->lumpnum);
sfxstart = sfxdata = new BYTE[size];
BYTE *sfxdata = new BYTE[size];
wlump.Read(sfxdata, size);
SDWORD len = LittleLong(((SDWORD *)sfxdata)[1]);
SDWORD dmxlen = LittleLong(((SDWORD *)sfxdata)[1]);
// If the sound is voc, use the custom loader.
if (strncmp ((const char *)sfxstart, "Creative Voice File", 19) == 0)
if (strncmp ((const char *)sfxdata, "Creative Voice File", 19) == 0)
{
sfx->data = GSnd->LoadSoundVoc(sfxstart, size);
sfx->data = GSnd->LoadSoundVoc(sfxdata, size);
}
// If the sound is raw, just load it as such.
else if (sfx->bLoadRAW)
{
sfx->data = GSnd->LoadSoundRaw(sfxdata, size, sfx->RawRate, 1, 8, sfx->LoopStart);
}
// Otherwise, try the sound as DMX format.
// If that fails, let FMOD try and figure it out.
else if (sfx->bLoadRAW ||
(((BYTE *)sfxdata)[0] == 3 && ((BYTE *)sfxdata)[1] == 0 && len <= size - 8))
else if (((BYTE *)sfxdata)[0] == 3 && ((BYTE *)sfxdata)[1] == 0 && dmxlen <= size - 8)
{
int frequency;
if (sfx->bLoadRAW)
{
len = Wads.LumpLength (sfx->lumpnum);
frequency = sfx->RawRate;
int frequency = LittleShort(((WORD *)sfxdata)[1]);
if (frequency == 0) frequency = 11025;
sfx->data = GSnd->LoadSoundRaw(sfxdata+8, dmxlen, frequency, 1, 8, sfx->LoopStart);
}
// If that fails, let the sound system try and figure it out.
else
{
frequency = LittleShort(((WORD *)sfxdata)[1]);
if (frequency == 0)
{
frequency = 11025;
}
sfxstart = sfxdata + 8;
}
sfx->data = GSnd->LoadSoundRaw(sfxstart, len, frequency, 1, 8, sfx->LoopStart);
}
else
{
len = Wads.LumpLength (sfx->lumpnum);
sfx->data = GSnd->LoadSound(sfxstart, len);
sfx->data = GSnd->LoadSound(sfxdata, size);
}
if (sfxdata != NULL)
{
delete[] sfxdata;
}
}
if (!sfx->data.isValid())
{
@ -1925,6 +1913,8 @@ void S_UpdateSounds (AActor *listenactor)
S_ActivatePlayList(false);
}
if (listenactor != NULL)
{
// should never happen
S_SetListener(listener, listenactor);
@ -1950,6 +1940,7 @@ void S_UpdateSounds (AActor *listenactor)
S_RestoreEvictedChannels();
}
}
}
//==========================================================================
//
@ -2083,12 +2074,6 @@ void S_ChannelEnded(FISoundChannel *ichan)
evicted = (pos < len);
}
}
/*
else
{
evicted = false;
}
*/
if (!evicted)
{
S_ReturnChannel(schan);
@ -2346,8 +2331,6 @@ bool S_StartMusic (const char *m_id)
// specified, it will only be played if the specified CD is in a drive.
//==========================================================================
TArray<BYTE> musiccache;
bool S_ChangeMusic (const char *musicname, int order, bool looping, bool force)
{
if (!force && PlayList)
@ -2427,7 +2410,7 @@ bool S_ChangeMusic (const char *musicname, int order, bool looping, bool force)
else
{
int lumpnum = -1;
int offset = 0, length = 0;
int length = 0;
int device = MDEV_DEFAULT;
MusInfo *handle = NULL;
FName musicasname = musicname;
@ -2448,6 +2431,7 @@ bool S_ChangeMusic (const char *musicname, int order, bool looping, bool force)
musicname += 7;
}
FileReader *reader = NULL;
if (!FileExists (musicname))
{
if ((lumpnum = Wads.CheckNumForFullName (musicname, true, ns_music)) == -1)
@ -2470,33 +2454,21 @@ bool S_ChangeMusic (const char *musicname, int order, bool looping, bool force)
}
if (handle == NULL)
{
if (!Wads.IsUncompressedFile(lumpnum))
{
// We must cache the music data and use it from memory.
// shut down old music before reallocating and overwriting the cache!
S_StopMusic (true);
offset = -1; // this tells the low level code that the music
// is being used from memory
length = Wads.LumpLength (lumpnum);
if (length == 0)
if (Wads.LumpLength (lumpnum) == 0)
{
return false;
}
musiccache.Resize(length);
Wads.ReadLump(lumpnum, &musiccache[0]);
reader = Wads.ReopenLumpNumNewFile(lumpnum);
if (reader == NULL)
{
return false;
}
}
}
else
{
offset = Wads.GetLumpOffset (lumpnum);
length = Wads.LumpLength (lumpnum);
if (length == 0)
{
return false;
}
}
}
// Load an external file.
reader = new FileReader(musicname);
}
// shutdown old music
@ -2509,6 +2481,7 @@ bool S_ChangeMusic (const char *musicname, int order, bool looping, bool force)
mus_playing.name = musicname;
mus_playing.baseorder = order;
LastSong = musicname;
delete reader;
return true;
}
@ -2516,16 +2489,11 @@ bool S_ChangeMusic (const char *musicname, int order, bool looping, bool force)
if (handle != NULL)
{
mus_playing.handle = handle;
}
else if (offset != -1)
{
mus_playing.handle = I_RegisterSong (lumpnum != -1 ?
Wads.GetWadFullName (Wads.GetLumpFile (lumpnum)) :
musicname, NULL, offset, length, device);
delete reader;
}
else
{
mus_playing.handle = I_RegisterSong (NULL, &musiccache[0], -1, length, device);
mus_playing.handle = I_RegisterSong (reader, device);
}
}
@ -2623,6 +2591,17 @@ void S_StopMusic (bool force)
}
}
//==========================================================================
//
//
//
//==========================================================================
void S_UpdateMusic()
{
GSnd->UpdateMusic();
}
//==========================================================================
//
// CCMD playsound

View file

@ -329,6 +329,7 @@ int S_GetMusic (char **name);
// Stops the music for sure.
void S_StopMusic (bool force);
void S_UpdateMusic();
// Stop and resume music, during game PAUSE.
void S_PauseSound (bool notmusic, bool notsfx);
@ -389,7 +390,7 @@ enum EMidiDevice
MDEV_DEFAULT = -1,
MDEV_MMAPI = 0,
MDEV_OPL = 1,
MDEV_FMOD = 2,
MDEV_SNDSYS = 2,
MDEV_TIMIDITY = 3,
MDEV_FLUIDSYNTH = 4,
MDEV_GUS = 5,

View file

@ -196,9 +196,22 @@ void FScanner::OpenFile (const char *name)
//==========================================================================
void FScanner::OpenMem (const char *name, const char *buffer, int size)
{
OpenString(name, FString(buffer, size));
}
//==========================================================================
//
// FScanner :: OpenString
//
// Like OpenMem, but takes a string directly.
//
//==========================================================================
void FScanner::OpenString (const char *name, FString buffer)
{
Close ();
ScriptBuffer = FString(buffer, size);
ScriptBuffer = buffer;
ScriptName = name;
LumpNum = -1;
PrepareScript ();

View file

@ -21,6 +21,7 @@ public:
void Open(const char *lumpname);
void OpenFile(const char *filename);
void OpenMem(const char *name, const char *buffer, int size);
void OpenString(const char *name, FString buffer);
void OpenLumpNum(int lump);
void Close();

758
src/sound/efx.h Normal file
View file

@ -0,0 +1,758 @@
#ifndef AL_EFX_H
#define AL_EFX_H
#ifdef __cplusplus
extern "C" {
#endif
#define ALC_EXT_EFX_NAME "ALC_EXT_EFX"
#define ALC_EFX_MAJOR_VERSION 0x20001
#define ALC_EFX_MINOR_VERSION 0x20002
#define ALC_MAX_AUXILIARY_SENDS 0x20003
/* Listener properties. */
#define AL_METERS_PER_UNIT 0x20004
/* Source properties. */
#define AL_DIRECT_FILTER 0x20005
#define AL_AUXILIARY_SEND_FILTER 0x20006
#define AL_AIR_ABSORPTION_FACTOR 0x20007
#define AL_ROOM_ROLLOFF_FACTOR 0x20008
#define AL_CONE_OUTER_GAINHF 0x20009
#define AL_DIRECT_FILTER_GAINHF_AUTO 0x2000A
#define AL_AUXILIARY_SEND_FILTER_GAIN_AUTO 0x2000B
#define AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO 0x2000C
/* Effect properties. */
/* Reverb effect parameters */
#define AL_REVERB_DENSITY 0x0001
#define AL_REVERB_DIFFUSION 0x0002
#define AL_REVERB_GAIN 0x0003
#define AL_REVERB_GAINHF 0x0004
#define AL_REVERB_DECAY_TIME 0x0005
#define AL_REVERB_DECAY_HFRATIO 0x0006
#define AL_REVERB_REFLECTIONS_GAIN 0x0007
#define AL_REVERB_REFLECTIONS_DELAY 0x0008
#define AL_REVERB_LATE_REVERB_GAIN 0x0009
#define AL_REVERB_LATE_REVERB_DELAY 0x000A
#define AL_REVERB_AIR_ABSORPTION_GAINHF 0x000B
#define AL_REVERB_ROOM_ROLLOFF_FACTOR 0x000C
#define AL_REVERB_DECAY_HFLIMIT 0x000D
/* EAX Reverb effect parameters */
#define AL_EAXREVERB_DENSITY 0x0001
#define AL_EAXREVERB_DIFFUSION 0x0002
#define AL_EAXREVERB_GAIN 0x0003
#define AL_EAXREVERB_GAINHF 0x0004
#define AL_EAXREVERB_GAINLF 0x0005
#define AL_EAXREVERB_DECAY_TIME 0x0006
#define AL_EAXREVERB_DECAY_HFRATIO 0x0007
#define AL_EAXREVERB_DECAY_LFRATIO 0x0008
#define AL_EAXREVERB_REFLECTIONS_GAIN 0x0009
#define AL_EAXREVERB_REFLECTIONS_DELAY 0x000A
#define AL_EAXREVERB_REFLECTIONS_PAN 0x000B
#define AL_EAXREVERB_LATE_REVERB_GAIN 0x000C
#define AL_EAXREVERB_LATE_REVERB_DELAY 0x000D
#define AL_EAXREVERB_LATE_REVERB_PAN 0x000E
#define AL_EAXREVERB_ECHO_TIME 0x000F
#define AL_EAXREVERB_ECHO_DEPTH 0x0010
#define AL_EAXREVERB_MODULATION_TIME 0x0011
#define AL_EAXREVERB_MODULATION_DEPTH 0x0012
#define AL_EAXREVERB_AIR_ABSORPTION_GAINHF 0x0013
#define AL_EAXREVERB_HFREFERENCE 0x0014
#define AL_EAXREVERB_LFREFERENCE 0x0015
#define AL_EAXREVERB_ROOM_ROLLOFF_FACTOR 0x0016
#define AL_EAXREVERB_DECAY_HFLIMIT 0x0017
/* Chorus effect parameters */
#define AL_CHORUS_WAVEFORM 0x0001
#define AL_CHORUS_PHASE 0x0002
#define AL_CHORUS_RATE 0x0003
#define AL_CHORUS_DEPTH 0x0004
#define AL_CHORUS_FEEDBACK 0x0005
#define AL_CHORUS_DELAY 0x0006
/* Distortion effect parameters */
#define AL_DISTORTION_EDGE 0x0001
#define AL_DISTORTION_GAIN 0x0002
#define AL_DISTORTION_LOWPASS_CUTOFF 0x0003
#define AL_DISTORTION_EQCENTER 0x0004
#define AL_DISTORTION_EQBANDWIDTH 0x0005
/* Echo effect parameters */
#define AL_ECHO_DELAY 0x0001
#define AL_ECHO_LRDELAY 0x0002
#define AL_ECHO_DAMPING 0x0003
#define AL_ECHO_FEEDBACK 0x0004
#define AL_ECHO_SPREAD 0x0005
/* Flanger effect parameters */
#define AL_FLANGER_WAVEFORM 0x0001
#define AL_FLANGER_PHASE 0x0002
#define AL_FLANGER_RATE 0x0003
#define AL_FLANGER_DEPTH 0x0004
#define AL_FLANGER_FEEDBACK 0x0005
#define AL_FLANGER_DELAY 0x0006
/* Frequency shifter effect parameters */
#define AL_FREQUENCY_SHIFTER_FREQUENCY 0x0001
#define AL_FREQUENCY_SHIFTER_LEFT_DIRECTION 0x0002
#define AL_FREQUENCY_SHIFTER_RIGHT_DIRECTION 0x0003
/* Vocal morpher effect parameters */
#define AL_VOCAL_MORPHER_PHONEMEA 0x0001
#define AL_VOCAL_MORPHER_PHONEMEA_COARSE_TUNING 0x0002
#define AL_VOCAL_MORPHER_PHONEMEB 0x0003
#define AL_VOCAL_MORPHER_PHONEMEB_COARSE_TUNING 0x0004
#define AL_VOCAL_MORPHER_WAVEFORM 0x0005
#define AL_VOCAL_MORPHER_RATE 0x0006
/* Pitchshifter effect parameters */
#define AL_PITCH_SHIFTER_COARSE_TUNE 0x0001
#define AL_PITCH_SHIFTER_FINE_TUNE 0x0002
/* Ringmodulator effect parameters */
#define AL_RING_MODULATOR_FREQUENCY 0x0001
#define AL_RING_MODULATOR_HIGHPASS_CUTOFF 0x0002
#define AL_RING_MODULATOR_WAVEFORM 0x0003
/* Autowah effect parameters */
#define AL_AUTOWAH_ATTACK_TIME 0x0001
#define AL_AUTOWAH_RELEASE_TIME 0x0002
#define AL_AUTOWAH_RESONANCE 0x0003
#define AL_AUTOWAH_PEAK_GAIN 0x0004
/* Compressor effect parameters */
#define AL_COMPRESSOR_ONOFF 0x0001
/* Equalizer effect parameters */
#define AL_EQUALIZER_LOW_GAIN 0x0001
#define AL_EQUALIZER_LOW_CUTOFF 0x0002
#define AL_EQUALIZER_MID1_GAIN 0x0003
#define AL_EQUALIZER_MID1_CENTER 0x0004
#define AL_EQUALIZER_MID1_WIDTH 0x0005
#define AL_EQUALIZER_MID2_GAIN 0x0006
#define AL_EQUALIZER_MID2_CENTER 0x0007
#define AL_EQUALIZER_MID2_WIDTH 0x0008
#define AL_EQUALIZER_HIGH_GAIN 0x0009
#define AL_EQUALIZER_HIGH_CUTOFF 0x000A
/* Effect type */
#define AL_EFFECT_FIRST_PARAMETER 0x0000
#define AL_EFFECT_LAST_PARAMETER 0x8000
#define AL_EFFECT_TYPE 0x8001
/* Effect types, used with the AL_EFFECT_TYPE property */
#define AL_EFFECT_NULL 0x0000
#define AL_EFFECT_REVERB 0x0001
#define AL_EFFECT_CHORUS 0x0002
#define AL_EFFECT_DISTORTION 0x0003
#define AL_EFFECT_ECHO 0x0004
#define AL_EFFECT_FLANGER 0x0005
#define AL_EFFECT_FREQUENCY_SHIFTER 0x0006
#define AL_EFFECT_VOCAL_MORPHER 0x0007
#define AL_EFFECT_PITCH_SHIFTER 0x0008
#define AL_EFFECT_RING_MODULATOR 0x0009
#define AL_EFFECT_AUTOWAH 0x000A
#define AL_EFFECT_COMPRESSOR 0x000B
#define AL_EFFECT_EQUALIZER 0x000C
#define AL_EFFECT_EAXREVERB 0x8000
/* Auxiliary Effect Slot properties. */
#define AL_EFFECTSLOT_EFFECT 0x0001
#define AL_EFFECTSLOT_GAIN 0x0002
#define AL_EFFECTSLOT_AUXILIARY_SEND_AUTO 0x0003
/* NULL Auxiliary Slot ID to disable a source send. */
#define AL_EFFECTSLOT_NULL 0x0000
/* Filter properties. */
/* Lowpass filter parameters */
#define AL_LOWPASS_GAIN 0x0001
#define AL_LOWPASS_GAINHF 0x0002
/* Highpass filter parameters */
#define AL_HIGHPASS_GAIN 0x0001
#define AL_HIGHPASS_GAINLF 0x0002
/* Bandpass filter parameters */
#define AL_BANDPASS_GAIN 0x0001
#define AL_BANDPASS_GAINLF 0x0002
#define AL_BANDPASS_GAINHF 0x0003
/* Filter type */
#define AL_FILTER_FIRST_PARAMETER 0x0000
#define AL_FILTER_LAST_PARAMETER 0x8000
#define AL_FILTER_TYPE 0x8001
/* Filter types, used with the AL_FILTER_TYPE property */
#define AL_FILTER_NULL 0x0000
#define AL_FILTER_LOWPASS 0x0001
#define AL_FILTER_HIGHPASS 0x0002
#define AL_FILTER_BANDPASS 0x0003
/* Effect object function types. */
typedef void (AL_APIENTRY *LPALGENEFFECTS)(ALsizei, ALuint*);
typedef void (AL_APIENTRY *LPALDELETEEFFECTS)(ALsizei, ALuint*);
typedef ALboolean (AL_APIENTRY *LPALISEFFECT)(ALuint);
typedef void (AL_APIENTRY *LPALEFFECTI)(ALuint, ALenum, ALint);
typedef void (AL_APIENTRY *LPALEFFECTIV)(ALuint, ALenum, ALint*);
typedef void (AL_APIENTRY *LPALEFFECTF)(ALuint, ALenum, ALfloat);
typedef void (AL_APIENTRY *LPALEFFECTFV)(ALuint, ALenum, ALfloat*);
typedef void (AL_APIENTRY *LPALGETEFFECTI)(ALuint, ALenum, ALint*);
typedef void (AL_APIENTRY *LPALGETEFFECTIV)(ALuint, ALenum, ALint*);
typedef void (AL_APIENTRY *LPALGETEFFECTF)(ALuint, ALenum, ALfloat*);
typedef void (AL_APIENTRY *LPALGETEFFECTFV)(ALuint, ALenum, ALfloat*);
/* Filter object function types. */
typedef void (AL_APIENTRY *LPALGENFILTERS)(ALsizei, ALuint*);
typedef void (AL_APIENTRY *LPALDELETEFILTERS)(ALsizei, ALuint*);
typedef ALboolean (AL_APIENTRY *LPALISFILTER)(ALuint);
typedef void (AL_APIENTRY *LPALFILTERI)(ALuint, ALenum, ALint);
typedef void (AL_APIENTRY *LPALFILTERIV)(ALuint, ALenum, ALint*);
typedef void (AL_APIENTRY *LPALFILTERF)(ALuint, ALenum, ALfloat);
typedef void (AL_APIENTRY *LPALFILTERFV)(ALuint, ALenum, ALfloat*);
typedef void (AL_APIENTRY *LPALGETFILTERI)(ALuint, ALenum, ALint*);
typedef void (AL_APIENTRY *LPALGETFILTERIV)(ALuint, ALenum, ALint*);
typedef void (AL_APIENTRY *LPALGETFILTERF)(ALuint, ALenum, ALfloat*);
typedef void (AL_APIENTRY *LPALGETFILTERFV)(ALuint, ALenum, ALfloat*);
/* Auxiliary Effect Slot object function types. */
typedef void (AL_APIENTRY *LPALGENAUXILIARYEFFECTSLOTS)(ALsizei, ALuint*);
typedef void (AL_APIENTRY *LPALDELETEAUXILIARYEFFECTSLOTS)(ALsizei, ALuint*);
typedef ALboolean (AL_APIENTRY *LPALISAUXILIARYEFFECTSLOT)(ALuint);
typedef void (AL_APIENTRY *LPALAUXILIARYEFFECTSLOTI)(ALuint, ALenum, ALint);
typedef void (AL_APIENTRY *LPALAUXILIARYEFFECTSLOTIV)(ALuint, ALenum, ALint*);
typedef void (AL_APIENTRY *LPALAUXILIARYEFFECTSLOTF)(ALuint, ALenum, ALfloat);
typedef void (AL_APIENTRY *LPALAUXILIARYEFFECTSLOTFV)(ALuint, ALenum, ALfloat*);
typedef void (AL_APIENTRY *LPALGETAUXILIARYEFFECTSLOTI)(ALuint, ALenum, ALint*);
typedef void (AL_APIENTRY *LPALGETAUXILIARYEFFECTSLOTIV)(ALuint, ALenum, ALint*);
typedef void (AL_APIENTRY *LPALGETAUXILIARYEFFECTSLOTF)(ALuint, ALenum, ALfloat*);
typedef void (AL_APIENTRY *LPALGETAUXILIARYEFFECTSLOTFV)(ALuint, ALenum, ALfloat*);
#ifdef AL_ALEXT_PROTOTYPES
AL_API ALvoid AL_APIENTRY alGenEffects(ALsizei n, ALuint *effects);
AL_API ALvoid AL_APIENTRY alDeleteEffects(ALsizei n, ALuint *effects);
AL_API ALboolean AL_APIENTRY alIsEffect(ALuint effect);
AL_API ALvoid AL_APIENTRY alEffecti(ALuint effect, ALenum param, ALint iValue);
AL_API ALvoid AL_APIENTRY alEffectiv(ALuint effect, ALenum param, ALint *piValues);
AL_API ALvoid AL_APIENTRY alEffectf(ALuint effect, ALenum param, ALfloat flValue);
AL_API ALvoid AL_APIENTRY alEffectfv(ALuint effect, ALenum param, ALfloat *pflValues);
AL_API ALvoid AL_APIENTRY alGetEffecti(ALuint effect, ALenum param, ALint *piValue);
AL_API ALvoid AL_APIENTRY alGetEffectiv(ALuint effect, ALenum param, ALint *piValues);
AL_API ALvoid AL_APIENTRY alGetEffectf(ALuint effect, ALenum param, ALfloat *pflValue);
AL_API ALvoid AL_APIENTRY alGetEffectfv(ALuint effect, ALenum param, ALfloat *pflValues);
AL_API ALvoid AL_APIENTRY alGenFilters(ALsizei n, ALuint *filters);
AL_API ALvoid AL_APIENTRY alDeleteFilters(ALsizei n, ALuint *filters);
AL_API ALboolean AL_APIENTRY alIsFilter(ALuint filter);
AL_API ALvoid AL_APIENTRY alFilteri(ALuint filter, ALenum param, ALint iValue);
AL_API ALvoid AL_APIENTRY alFilteriv(ALuint filter, ALenum param, ALint *piValues);
AL_API ALvoid AL_APIENTRY alFilterf(ALuint filter, ALenum param, ALfloat flValue);
AL_API ALvoid AL_APIENTRY alFilterfv(ALuint filter, ALenum param, ALfloat *pflValues);
AL_API ALvoid AL_APIENTRY alGetFilteri(ALuint filter, ALenum param, ALint *piValue);
AL_API ALvoid AL_APIENTRY alGetFilteriv(ALuint filter, ALenum param, ALint *piValues);
AL_API ALvoid AL_APIENTRY alGetFilterf(ALuint filter, ALenum param, ALfloat *pflValue);
AL_API ALvoid AL_APIENTRY alGetFilterfv(ALuint filter, ALenum param, ALfloat *pflValues);
AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots);
AL_API ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots);
AL_API ALboolean AL_APIENTRY alIsAuxiliaryEffectSlot(ALuint effectslot);
AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint iValue);
AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, ALint *piValues);
AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat flValue);
AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, ALfloat *pflValues);
AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint *piValue);
AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, ALint *piValues);
AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat *pflValue);
AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, ALfloat *pflValues);
#endif
/* Filter ranges and defaults. */
/* Lowpass filter */
#define LOWPASS_MIN_GAIN (0.0f)
#define LOWPASS_MAX_GAIN (1.0f)
#define LOWPASS_DEFAULT_GAIN (1.0f)
#define LOWPASS_MIN_GAINHF (0.0f)
#define LOWPASS_MAX_GAINHF (1.0f)
#define LOWPASS_DEFAULT_GAINHF (1.0f)
/* Highpass filter */
#define HIGHPASS_MIN_GAIN (0.0f)
#define HIGHPASS_MAX_GAIN (1.0f)
#define HIGHPASS_DEFAULT_GAIN (1.0f)
#define HIGHPASS_MIN_GAINLF (0.0f)
#define HIGHPASS_MAX_GAINLF (1.0f)
#define HIGHPASS_DEFAULT_GAINLF (1.0f)
/* Bandpass filter */
#define BANDPASS_MIN_GAIN (0.0f)
#define BANDPASS_MAX_GAIN (1.0f)
#define BANDPASS_DEFAULT_GAIN (1.0f)
#define BANDPASS_MIN_GAINHF (0.0f)
#define BANDPASS_MAX_GAINHF (1.0f)
#define BANDPASS_DEFAULT_GAINHF (1.0f)
#define BANDPASS_MIN_GAINLF (0.0f)
#define BANDPASS_MAX_GAINLF (1.0f)
#define BANDPASS_DEFAULT_GAINLF (1.0f)
/* Effect parameter ranges and defaults. */
/* Standard reverb effect */
#define AL_REVERB_MIN_DENSITY (0.0f)
#define AL_REVERB_MAX_DENSITY (1.0f)
#define AL_REVERB_DEFAULT_DENSITY (1.0f)
#define AL_REVERB_MIN_DIFFUSION (0.0f)
#define AL_REVERB_MAX_DIFFUSION (1.0f)
#define AL_REVERB_DEFAULT_DIFFUSION (1.0f)
#define AL_REVERB_MIN_GAIN (0.0f)
#define AL_REVERB_MAX_GAIN (1.0f)
#define AL_REVERB_DEFAULT_GAIN (0.32f)
#define AL_REVERB_MIN_GAINHF (0.0f)
#define AL_REVERB_MAX_GAINHF (1.0f)
#define AL_REVERB_DEFAULT_GAINHF (0.89f)
#define AL_REVERB_MIN_DECAY_TIME (0.1f)
#define AL_REVERB_MAX_DECAY_TIME (20.0f)
#define AL_REVERB_DEFAULT_DECAY_TIME (1.49f)
#define AL_REVERB_MIN_DECAY_HFRATIO (0.1f)
#define AL_REVERB_MAX_DECAY_HFRATIO (2.0f)
#define AL_REVERB_DEFAULT_DECAY_HFRATIO (0.83f)
#define AL_REVERB_MIN_REFLECTIONS_GAIN (0.0f)
#define AL_REVERB_MAX_REFLECTIONS_GAIN (3.16f)
#define AL_REVERB_DEFAULT_REFLECTIONS_GAIN (0.05f)
#define AL_REVERB_MIN_REFLECTIONS_DELAY (0.0f)
#define AL_REVERB_MAX_REFLECTIONS_DELAY (0.3f)
#define AL_REVERB_DEFAULT_REFLECTIONS_DELAY (0.007f)
#define AL_REVERB_MIN_LATE_REVERB_GAIN (0.0f)
#define AL_REVERB_MAX_LATE_REVERB_GAIN (10.0f)
#define AL_REVERB_DEFAULT_LATE_REVERB_GAIN (1.26f)
#define AL_REVERB_MIN_LATE_REVERB_DELAY (0.0f)
#define AL_REVERB_MAX_LATE_REVERB_DELAY (0.1f)
#define AL_REVERB_DEFAULT_LATE_REVERB_DELAY (0.011f)
#define AL_REVERB_MIN_AIR_ABSORPTION_GAINHF (0.892f)
#define AL_REVERB_MAX_AIR_ABSORPTION_GAINHF (1.0f)
#define AL_REVERB_DEFAULT_AIR_ABSORPTION_GAINHF (0.994f)
#define AL_REVERB_MIN_ROOM_ROLLOFF_FACTOR (0.0f)
#define AL_REVERB_MAX_ROOM_ROLLOFF_FACTOR (10.0f)
#define AL_REVERB_DEFAULT_ROOM_ROLLOFF_FACTOR (0.0f)
#define AL_REVERB_MIN_DECAY_HFLIMIT AL_FALSE
#define AL_REVERB_MAX_DECAY_HFLIMIT AL_TRUE
#define AL_REVERB_DEFAULT_DECAY_HFLIMIT AL_TRUE
/* EAX reverb effect */
#define AL_EAXREVERB_MIN_DENSITY (0.0f)
#define AL_EAXREVERB_MAX_DENSITY (1.0f)
#define AL_EAXREVERB_DEFAULT_DENSITY (1.0f)
#define AL_EAXREVERB_MIN_DIFFUSION (0.0f)
#define AL_EAXREVERB_MAX_DIFFUSION (1.0f)
#define AL_EAXREVERB_DEFAULT_DIFFUSION (1.0f)
#define AL_EAXREVERB_MIN_GAIN (0.0f)
#define AL_EAXREVERB_MAX_GAIN (1.0f)
#define AL_EAXREVERB_DEFAULT_GAIN (0.32f)
#define AL_EAXREVERB_MIN_GAINHF (0.0f)
#define AL_EAXREVERB_MAX_GAINHF (1.0f)
#define AL_EAXREVERB_DEFAULT_GAINHF (0.89f)
#define AL_EAXREVERB_MIN_GAINLF (0.0f)
#define AL_EAXREVERB_MAX_GAINLF (1.0f)
#define AL_EAXREVERB_DEFAULT_GAINLF (1.0f)
#define AL_EAXREVERB_MIN_DECAY_TIME (0.1f)
#define AL_EAXREVERB_MAX_DECAY_TIME (20.0f)
#define AL_EAXREVERB_DEFAULT_DECAY_TIME (1.49f)
#define AL_EAXREVERB_MIN_DECAY_HFRATIO (0.1f)
#define AL_EAXREVERB_MAX_DECAY_HFRATIO (2.0f)
#define AL_EAXREVERB_DEFAULT_DECAY_HFRATIO (0.83f)
#define AL_EAXREVERB_MIN_DECAY_LFRATIO (0.1f)
#define AL_EAXREVERB_MAX_DECAY_LFRATIO (2.0f)
#define AL_EAXREVERB_DEFAULT_DECAY_LFRATIO (1.0f)
#define AL_EAXREVERB_MIN_REFLECTIONS_GAIN (0.0f)
#define AL_EAXREVERB_MAX_REFLECTIONS_GAIN (3.16f)
#define AL_EAXREVERB_DEFAULT_REFLECTIONS_GAIN (0.05f)
#define AL_EAXREVERB_MIN_REFLECTIONS_DELAY (0.0f)
#define AL_EAXREVERB_MAX_REFLECTIONS_DELAY (0.3f)
#define AL_EAXREVERB_DEFAULT_REFLECTIONS_DELAY (0.007f)
#define AL_EAXREVERB_DEFAULT_REFLECTIONS_PAN_XYZ (0.0f)
#define AL_EAXREVERB_MIN_LATE_REVERB_GAIN (0.0f)
#define AL_EAXREVERB_MAX_LATE_REVERB_GAIN (10.0f)
#define AL_EAXREVERB_DEFAULT_LATE_REVERB_GAIN (1.26f)
#define AL_EAXREVERB_MIN_LATE_REVERB_DELAY (0.0f)
#define AL_EAXREVERB_MAX_LATE_REVERB_DELAY (0.1f)
#define AL_EAXREVERB_DEFAULT_LATE_REVERB_DELAY (0.011f)
#define AL_EAXREVERB_DEFAULT_LATE_REVERB_PAN_XYZ (0.0f)
#define AL_EAXREVERB_MIN_ECHO_TIME (0.075f)
#define AL_EAXREVERB_MAX_ECHO_TIME (0.25f)
#define AL_EAXREVERB_DEFAULT_ECHO_TIME (0.25f)
#define AL_EAXREVERB_MIN_ECHO_DEPTH (0.0f)
#define AL_EAXREVERB_MAX_ECHO_DEPTH (1.0f)
#define AL_EAXREVERB_DEFAULT_ECHO_DEPTH (0.0f)
#define AL_EAXREVERB_MIN_MODULATION_TIME (0.04f)
#define AL_EAXREVERB_MAX_MODULATION_TIME (4.0f)
#define AL_EAXREVERB_DEFAULT_MODULATION_TIME (0.25f)
#define AL_EAXREVERB_MIN_MODULATION_DEPTH (0.0f)
#define AL_EAXREVERB_MAX_MODULATION_DEPTH (1.0f)
#define AL_EAXREVERB_DEFAULT_MODULATION_DEPTH (0.0f)
#define AL_EAXREVERB_MIN_AIR_ABSORPTION_GAINHF (0.892f)
#define AL_EAXREVERB_MAX_AIR_ABSORPTION_GAINHF (1.0f)
#define AL_EAXREVERB_DEFAULT_AIR_ABSORPTION_GAINHF (0.994f)
#define AL_EAXREVERB_MIN_HFREFERENCE (1000.0f)
#define AL_EAXREVERB_MAX_HFREFERENCE (20000.0f)
#define AL_EAXREVERB_DEFAULT_HFREFERENCE (5000.0f)
#define AL_EAXREVERB_MIN_LFREFERENCE (20.0f)
#define AL_EAXREVERB_MAX_LFREFERENCE (1000.0f)
#define AL_EAXREVERB_DEFAULT_LFREFERENCE (250.0f)
#define AL_EAXREVERB_MIN_ROOM_ROLLOFF_FACTOR (0.0f)
#define AL_EAXREVERB_MAX_ROOM_ROLLOFF_FACTOR (10.0f)
#define AL_EAXREVERB_DEFAULT_ROOM_ROLLOFF_FACTOR (0.0f)
#define AL_EAXREVERB_MIN_DECAY_HFLIMIT AL_FALSE
#define AL_EAXREVERB_MAX_DECAY_HFLIMIT AL_TRUE
#define AL_EAXREVERB_DEFAULT_DECAY_HFLIMIT AL_TRUE
/* Chorus effect */
#define AL_CHORUS_WAVEFORM_SINUSOID (0)
#define AL_CHORUS_WAVEFORM_TRIANGLE (1)
#define AL_CHORUS_MIN_WAVEFORM (0)
#define AL_CHORUS_MAX_WAVEFORM (1)
#define AL_CHORUS_DEFAULT_WAVEFORM (1)
#define AL_CHORUS_MIN_PHASE (-180)
#define AL_CHORUS_MAX_PHASE (180)
#define AL_CHORUS_DEFAULT_PHASE (90)
#define AL_CHORUS_MIN_RATE (0.0f)
#define AL_CHORUS_MAX_RATE (10.0f)
#define AL_CHORUS_DEFAULT_RATE (1.1f)
#define AL_CHORUS_MIN_DEPTH (0.0f)
#define AL_CHORUS_MAX_DEPTH (1.0f)
#define AL_CHORUS_DEFAULT_DEPTH (0.1f)
#define AL_CHORUS_MIN_FEEDBACK (-1.0f)
#define AL_CHORUS_MAX_FEEDBACK (1.0f)
#define AL_CHORUS_DEFAULT_FEEDBACK (0.25f)
#define AL_CHORUS_MIN_DELAY (0.0f)
#define AL_CHORUS_MAX_DELAY (0.016f)
#define AL_CHORUS_DEFAULT_DELAY (0.016f)
/* Distortion effect */
#define AL_DISTORTION_MIN_EDGE (0.0f)
#define AL_DISTORTION_MAX_EDGE (1.0f)
#define AL_DISTORTION_DEFAULT_EDGE (0.2f)
#define AL_DISTORTION_MIN_GAIN (0.01f)
#define AL_DISTORTION_MAX_GAIN (1.0f)
#define AL_DISTORTION_DEFAULT_GAIN (0.05f)
#define AL_DISTORTION_MIN_LOWPASS_CUTOFF (80.0f)
#define AL_DISTORTION_MAX_LOWPASS_CUTOFF (24000.0f)
#define AL_DISTORTION_DEFAULT_LOWPASS_CUTOFF (8000.0f)
#define AL_DISTORTION_MIN_EQCENTER (80.0f)
#define AL_DISTORTION_MAX_EQCENTER (24000.0f)
#define AL_DISTORTION_DEFAULT_EQCENTER (3600.0f)
#define AL_DISTORTION_MIN_EQBANDWIDTH (80.0f)
#define AL_DISTORTION_MAX_EQBANDWIDTH (24000.0f)
#define AL_DISTORTION_DEFAULT_EQBANDWIDTH (3600.0f)
/* Echo effect */
#define AL_ECHO_MIN_DELAY (0.0f)
#define AL_ECHO_MAX_DELAY (0.207f)
#define AL_ECHO_DEFAULT_DELAY (0.1f)
#define AL_ECHO_MIN_LRDELAY (0.0f)
#define AL_ECHO_MAX_LRDELAY (0.404f)
#define AL_ECHO_DEFAULT_LRDELAY (0.1f)
#define AL_ECHO_MIN_DAMPING (0.0f)
#define AL_ECHO_MAX_DAMPING (0.99f)
#define AL_ECHO_DEFAULT_DAMPING (0.5f)
#define AL_ECHO_MIN_FEEDBACK (0.0f)
#define AL_ECHO_MAX_FEEDBACK (1.0f)
#define AL_ECHO_DEFAULT_FEEDBACK (0.5f)
#define AL_ECHO_MIN_SPREAD (-1.0f)
#define AL_ECHO_MAX_SPREAD (1.0f)
#define AL_ECHO_DEFAULT_SPREAD (-1.0f)
/* Flanger effect */
#define AL_FLANGER_WAVEFORM_SINUSOID (0)
#define AL_FLANGER_WAVEFORM_TRIANGLE (1)
#define AL_FLANGER_MIN_WAVEFORM (0)
#define AL_FLANGER_MAX_WAVEFORM (1)
#define AL_FLANGER_DEFAULT_WAVEFORM (1)
#define AL_FLANGER_MIN_PHASE (-180)
#define AL_FLANGER_MAX_PHASE (180)
#define AL_FLANGER_DEFAULT_PHASE (0)
#define AL_FLANGER_MIN_RATE (0.0f)
#define AL_FLANGER_MAX_RATE (10.0f)
#define AL_FLANGER_DEFAULT_RATE (0.27f)
#define AL_FLANGER_MIN_DEPTH (0.0f)
#define AL_FLANGER_MAX_DEPTH (1.0f)
#define AL_FLANGER_DEFAULT_DEPTH (1.0f)
#define AL_FLANGER_MIN_FEEDBACK (-1.0f)
#define AL_FLANGER_MAX_FEEDBACK (1.0f)
#define AL_FLANGER_DEFAULT_FEEDBACK (-0.5f)
#define AL_FLANGER_MIN_DELAY (0.0f)
#define AL_FLANGER_MAX_DELAY (0.004f)
#define AL_FLANGER_DEFAULT_DELAY (0.002f)
/* Frequency shifter effect */
#define AL_FREQUENCY_SHIFTER_MIN_FREQUENCY (0.0f)
#define AL_FREQUENCY_SHIFTER_MAX_FREQUENCY (24000.0f)
#define AL_FREQUENCY_SHIFTER_DEFAULT_FREQUENCY (0.0f)
#define AL_FREQUENCY_SHIFTER_MIN_LEFT_DIRECTION (0)
#define AL_FREQUENCY_SHIFTER_MAX_LEFT_DIRECTION (2)
#define AL_FREQUENCY_SHIFTER_DEFAULT_LEFT_DIRECTION (0)
#define AL_FREQUENCY_SHIFTER_DIRECTION_DOWN (0)
#define AL_FREQUENCY_SHIFTER_DIRECTION_UP (1)
#define AL_FREQUENCY_SHIFTER_DIRECTION_OFF (2)
#define AL_FREQUENCY_SHIFTER_MIN_RIGHT_DIRECTION (0)
#define AL_FREQUENCY_SHIFTER_MAX_RIGHT_DIRECTION (2)
#define AL_FREQUENCY_SHIFTER_DEFAULT_RIGHT_DIRECTION (0)
/* Vocal morpher effect */
#define AL_VOCAL_MORPHER_MIN_PHONEMEA (0)
#define AL_VOCAL_MORPHER_MAX_PHONEMEA (29)
#define AL_VOCAL_MORPHER_DEFAULT_PHONEMEA (0)
#define AL_VOCAL_MORPHER_MIN_PHONEMEA_COARSE_TUNING (-24)
#define AL_VOCAL_MORPHER_MAX_PHONEMEA_COARSE_TUNING (24)
#define AL_VOCAL_MORPHER_DEFAULT_PHONEMEA_COARSE_TUNING (0)
#define AL_VOCAL_MORPHER_MIN_PHONEMEB (0)
#define AL_VOCAL_MORPHER_MAX_PHONEMEB (29)
#define AL_VOCAL_MORPHER_DEFAULT_PHONEMEB (10)
#define AL_VOCAL_MORPHER_MIN_PHONEMEB_COARSE_TUNING (-24)
#define AL_VOCAL_MORPHER_MAX_PHONEMEB_COARSE_TUNING (24)
#define AL_VOCAL_MORPHER_DEFAULT_PHONEMEB_COARSE_TUNING (0)
#define AL_VOCAL_MORPHER_PHONEME_A (0)
#define AL_VOCAL_MORPHER_PHONEME_E (1)
#define AL_VOCAL_MORPHER_PHONEME_I (2)
#define AL_VOCAL_MORPHER_PHONEME_O (3)
#define AL_VOCAL_MORPHER_PHONEME_U (4)
#define AL_VOCAL_MORPHER_PHONEME_AA (5)
#define AL_VOCAL_MORPHER_PHONEME_AE (6)
#define AL_VOCAL_MORPHER_PHONEME_AH (7)
#define AL_VOCAL_MORPHER_PHONEME_AO (8)
#define AL_VOCAL_MORPHER_PHONEME_EH (9)
#define AL_VOCAL_MORPHER_PHONEME_ER (10)
#define AL_VOCAL_MORPHER_PHONEME_IH (11)
#define AL_VOCAL_MORPHER_PHONEME_IY (12)
#define AL_VOCAL_MORPHER_PHONEME_UH (13)
#define AL_VOCAL_MORPHER_PHONEME_UW (14)
#define AL_VOCAL_MORPHER_PHONEME_B (15)
#define AL_VOCAL_MORPHER_PHONEME_D (16)
#define AL_VOCAL_MORPHER_PHONEME_F (17)
#define AL_VOCAL_MORPHER_PHONEME_G (18)
#define AL_VOCAL_MORPHER_PHONEME_J (19)
#define AL_VOCAL_MORPHER_PHONEME_K (20)
#define AL_VOCAL_MORPHER_PHONEME_L (21)
#define AL_VOCAL_MORPHER_PHONEME_M (22)
#define AL_VOCAL_MORPHER_PHONEME_N (23)
#define AL_VOCAL_MORPHER_PHONEME_P (24)
#define AL_VOCAL_MORPHER_PHONEME_R (25)
#define AL_VOCAL_MORPHER_PHONEME_S (26)
#define AL_VOCAL_MORPHER_PHONEME_T (27)
#define AL_VOCAL_MORPHER_PHONEME_V (28)
#define AL_VOCAL_MORPHER_PHONEME_Z (29)
#define AL_VOCAL_MORPHER_WAVEFORM_SINUSOID (0)
#define AL_VOCAL_MORPHER_WAVEFORM_TRIANGLE (1)
#define AL_VOCAL_MORPHER_WAVEFORM_SAWTOOTH (2)
#define AL_VOCAL_MORPHER_MIN_WAVEFORM (0)
#define AL_VOCAL_MORPHER_MAX_WAVEFORM (2)
#define AL_VOCAL_MORPHER_DEFAULT_WAVEFORM (0)
#define AL_VOCAL_MORPHER_MIN_RATE (0.0f)
#define AL_VOCAL_MORPHER_MAX_RATE (10.0f)
#define AL_VOCAL_MORPHER_DEFAULT_RATE (1.41f)
/* Pitch shifter effect */
#define AL_PITCH_SHIFTER_MIN_COARSE_TUNE (-12)
#define AL_PITCH_SHIFTER_MAX_COARSE_TUNE (12)
#define AL_PITCH_SHIFTER_DEFAULT_COARSE_TUNE (12)
#define AL_PITCH_SHIFTER_MIN_FINE_TUNE (-50)
#define AL_PITCH_SHIFTER_MAX_FINE_TUNE (50)
#define AL_PITCH_SHIFTER_DEFAULT_FINE_TUNE (0)
/* Ring modulator effect */
#define AL_RING_MODULATOR_MIN_FREQUENCY (0.0f)
#define AL_RING_MODULATOR_MAX_FREQUENCY (8000.0f)
#define AL_RING_MODULATOR_DEFAULT_FREQUENCY (440.0f)
#define AL_RING_MODULATOR_MIN_HIGHPASS_CUTOFF (0.0f)
#define AL_RING_MODULATOR_MAX_HIGHPASS_CUTOFF (24000.0f)
#define AL_RING_MODULATOR_DEFAULT_HIGHPASS_CUTOFF (800.0f)
#define AL_RING_MODULATOR_SINUSOID (0)
#define AL_RING_MODULATOR_SAWTOOTH (1)
#define AL_RING_MODULATOR_SQUARE (2)
#define AL_RING_MODULATOR_MIN_WAVEFORM (0)
#define AL_RING_MODULATOR_MAX_WAVEFORM (2)
#define AL_RING_MODULATOR_DEFAULT_WAVEFORM (0)
/* Autowah effect */
#define AL_AUTOWAH_MIN_ATTACK_TIME (0.0001f)
#define AL_AUTOWAH_MAX_ATTACK_TIME (1.0f)
#define AL_AUTOWAH_DEFAULT_ATTACK_TIME (0.06f)
#define AL_AUTOWAH_MIN_RELEASE_TIME (0.0001f)
#define AL_AUTOWAH_MAX_RELEASE_TIME (1.0f)
#define AL_AUTOWAH_DEFAULT_RELEASE_TIME (0.06f)
#define AL_AUTOWAH_MIN_RESONANCE (2.0f)
#define AL_AUTOWAH_MAX_RESONANCE (1000.0f)
#define AL_AUTOWAH_DEFAULT_RESONANCE (1000.0f)
#define AL_AUTOWAH_MIN_PEAK_GAIN (0.00003f)
#define AL_AUTOWAH_MAX_PEAK_GAIN (31621.0f)
#define AL_AUTOWAH_DEFAULT_PEAK_GAIN (11.22f)
/* Compressor effect */
#define AL_COMPRESSOR_MIN_ONOFF (0)
#define AL_COMPRESSOR_MAX_ONOFF (1)
#define AL_COMPRESSOR_DEFAULT_ONOFF (1)
/* Equalizer effect */
#define AL_EQUALIZER_MIN_LOW_GAIN (0.126f)
#define AL_EQUALIZER_MAX_LOW_GAIN (7.943f)
#define AL_EQUALIZER_DEFAULT_LOW_GAIN (1.0f)
#define AL_EQUALIZER_MIN_LOW_CUTOFF (50.0f)
#define AL_EQUALIZER_MAX_LOW_CUTOFF (800.0f)
#define AL_EQUALIZER_DEFAULT_LOW_CUTOFF (200.0f)
#define AL_EQUALIZER_MIN_MID1_GAIN (0.126f)
#define AL_EQUALIZER_MAX_MID1_GAIN (7.943f)
#define AL_EQUALIZER_DEFAULT_MID1_GAIN (1.0f)
#define AL_EQUALIZER_MIN_MID1_CENTER (200.0f)
#define AL_EQUALIZER_MAX_MID1_CENTER (3000.0f)
#define AL_EQUALIZER_DEFAULT_MID1_CENTER (500.0f)
#define AL_EQUALIZER_MIN_MID1_WIDTH (0.01f)
#define AL_EQUALIZER_MAX_MID1_WIDTH (1.0f)
#define AL_EQUALIZER_DEFAULT_MID1_WIDTH (1.0f)
#define AL_EQUALIZER_MIN_MID2_GAIN (0.126f)
#define AL_EQUALIZER_MAX_MID2_GAIN (7.943f)
#define AL_EQUALIZER_DEFAULT_MID2_GAIN (1.0f)
#define AL_EQUALIZER_MIN_MID2_CENTER (1000.0f)
#define AL_EQUALIZER_MAX_MID2_CENTER (8000.0f)
#define AL_EQUALIZER_DEFAULT_MID2_CENTER (3000.0f)
#define AL_EQUALIZER_MIN_MID2_WIDTH (0.01f)
#define AL_EQUALIZER_MAX_MID2_WIDTH (1.0f)
#define AL_EQUALIZER_DEFAULT_MID2_WIDTH (1.0f)
#define AL_EQUALIZER_MIN_HIGH_GAIN (0.126f)
#define AL_EQUALIZER_MAX_HIGH_GAIN (7.943f)
#define AL_EQUALIZER_DEFAULT_HIGH_GAIN (1.0f)
#define AL_EQUALIZER_MIN_HIGH_CUTOFF (4000.0f)
#define AL_EQUALIZER_MAX_HIGH_CUTOFF (16000.0f)
#define AL_EQUALIZER_DEFAULT_HIGH_CUTOFF (6000.0f)
/* Source parameter value ranges and defaults. */
#define AL_MIN_AIR_ABSORPTION_FACTOR (0.0f)
#define AL_MAX_AIR_ABSORPTION_FACTOR (10.0f)
#define AL_DEFAULT_AIR_ABSORPTION_FACTOR (0.0f)
#define AL_MIN_ROOM_ROLLOFF_FACTOR (0.0f)
#define AL_MAX_ROOM_ROLLOFF_FACTOR (10.0f)
#define AL_DEFAULT_ROOM_ROLLOFF_FACTOR (0.0f)
#define AL_MIN_CONE_OUTER_GAINHF (0.0f)
#define AL_MAX_CONE_OUTER_GAINHF (1.0f)
#define AL_DEFAULT_CONE_OUTER_GAINHF (1.0f)
#define AL_MIN_DIRECT_FILTER_GAINHF_AUTO AL_FALSE
#define AL_MAX_DIRECT_FILTER_GAINHF_AUTO AL_TRUE
#define AL_DEFAULT_DIRECT_FILTER_GAINHF_AUTO AL_TRUE
#define AL_MIN_AUXILIARY_SEND_FILTER_GAIN_AUTO AL_FALSE
#define AL_MAX_AUXILIARY_SEND_FILTER_GAIN_AUTO AL_TRUE
#define AL_DEFAULT_AUXILIARY_SEND_FILTER_GAIN_AUTO AL_TRUE
#define AL_MIN_AUXILIARY_SEND_FILTER_GAINHF_AUTO AL_FALSE
#define AL_MAX_AUXILIARY_SEND_FILTER_GAINHF_AUTO AL_TRUE
#define AL_DEFAULT_AUXILIARY_SEND_FILTER_GAINHF_AUTO AL_TRUE
/* Listener parameter value ranges and defaults. */
#define AL_MIN_METERS_PER_UNIT FLT_MIN
#define AL_MAX_METERS_PER_UNIT FLT_MAX
#define AL_DEFAULT_METERS_PER_UNIT (1.0f)
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* AL_EFX_H */

41
src/sound/except.h Normal file
View file

@ -0,0 +1,41 @@
#ifndef __EXCEPT_H
#define __EXCEPT_H
#ifdef _MSC_VER
//==========================================================================
//
// CheckException
//
//==========================================================================
#ifndef FACILITY_VISUALCPP
#define FACILITY_VISUALCPP ((LONG)0x6d)
#endif
#define VcppException(sev,err) ((sev) | (FACILITY_VISUALCPP<<16) | err)
inline int CheckException(DWORD code)
{
if (code == VcppException(ERROR_SEVERITY_ERROR,ERROR_MOD_NOT_FOUND) ||
code == VcppException(ERROR_SEVERITY_ERROR,ERROR_PROC_NOT_FOUND))
{
return EXCEPTION_EXECUTE_HANDLER;
}
return EXCEPTION_CONTINUE_SEARCH;
}
#else
#ifdef __try
#undef __try
#endif
#define __try
#ifdef __except
#undef __except
#endif
#define __except(a) if (0)
#endif
#endif

View file

@ -2,6 +2,8 @@
#ifndef FMOD_WRAP_H
#define FMOD_WRAP_H
#ifndef NO_FMOD
#if !defined(_WIN32) || defined(_MSC_VER)
// Use the real C++ interface if it's supported on this platform.
#include "fmod.hpp"
@ -610,3 +612,4 @@ namespace FMOD
#endif
#endif
#endif

View file

@ -52,6 +52,7 @@ extern HWND Window;
#include <malloc.h>
#endif
#include "except.h"
#include "templates.h"
#include "fmodsound.h"
#include "c_cvars.h"
@ -62,6 +63,7 @@ extern HWND Window;
#include "v_palette.h"
#include "cmdlib.h"
#include "s_sound.h"
#include "files.h"
#if FMOD_VERSION > 0x42899 && FMOD_VERSION < 0x43400
#error You are trying to compile with an unsupported version of FMOD.
@ -79,6 +81,35 @@ extern HWND Window;
#define SPECTRUM_SIZE 256
// PUBLIC DATA DEFINITIONS -------------------------------------------------
ReverbContainer *ForcedEnvironment;
CVAR (Int, snd_driver, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CVAR (Int, snd_buffercount, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CVAR (Bool, snd_hrtf, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CVAR (Bool, snd_waterreverb, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CVAR (String, snd_resampler, "Linear", CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CVAR (String, snd_speakermode, "Auto", CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CVAR (String, snd_output_format, "PCM-16", CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CVAR (String, snd_midipatchset, "", CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CVAR (Bool, snd_profile, false, 0)
// Underwater low-pass filter cutoff frequency. Set to 0 to disable the filter.
CUSTOM_CVAR (Float, snd_waterlp, 250, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
{
// Clamp to the DSP unit's limits.
if (*self < 10 && *self != 0)
{
self = 10;
}
else if (*self > 22000)
{
self = 22000;
}
}
#ifndef NO_FMOD
#if FMOD_VERSION < 0x43400
#define FMOD_OPENSTATE_PLAYING FMOD_OPENSTATE_STREAMING
#endif
@ -112,34 +143,6 @@ EXTERN_CVAR (Int, snd_channels)
extern int sfx_empty;
// PUBLIC DATA DEFINITIONS -------------------------------------------------
ReverbContainer *ForcedEnvironment;
CVAR (Int, snd_driver, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CVAR (Int, snd_buffercount, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CVAR (Bool, snd_hrtf, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CVAR (Bool, snd_waterreverb, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CVAR (String, snd_resampler, "Linear", CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CVAR (String, snd_speakermode, "Auto", CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CVAR (String, snd_output_format, "PCM-16", CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CVAR (Bool, snd_profile, false, 0)
CVAR (String, snd_midipatchset, "", CVAR_ARCHIVE|CVAR_GLOBALCONFIG);
// Underwater low-pass filter cutoff frequency. Set to 0 to disable the filter.
CUSTOM_CVAR (Float, snd_waterlp, 250, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
{
// Clamp to the DSP unit's limits.
if (*self < 10 && *self != 0)
{
self = 10;
}
else if (*self > 22000)
{
self = 22000;
}
}
// PRIVATE DATA DEFINITIONS ------------------------------------------------
static const ReverbContainer *PrevEnvironment;
@ -165,9 +168,6 @@ static const FEnumList OutputNames[] =
{ "Windows Multimedia", FMOD_OUTPUTTYPE_WINMM },
{ "WinMM", FMOD_OUTPUTTYPE_WINMM },
{ "WaveOut", FMOD_OUTPUTTYPE_WINMM },
#if FMOD_VERSION < 0x43400
{ "OpenAL", FMOD_OUTPUTTYPE_OPENAL },
#endif
{ "WASAPI", FMOD_OUTPUTTYPE_WASAPI },
{ "ASIO", FMOD_OUTPUTTYPE_ASIO },
@ -182,9 +182,6 @@ static const FEnumList OutputNames[] =
{ "SDL", 666 },
// Mac
#if FMOD_VERSION < 0x43000
{ "Sound Manager", FMOD_OUTPUTTYPE_SOUNDMANAGER },
#endif
{ "Core Audio", FMOD_OUTPUTTYPE_COREAUDIO },
{ NULL, 0 }
@ -307,14 +304,21 @@ class FMODStreamCapsule : public SoundStream
public:
FMODStreamCapsule(FMOD::Sound *stream, FMODSoundRenderer *owner, const char *url)
: Owner(owner), Stream(NULL), Channel(NULL),
UserData(NULL), Callback(NULL), URL(url), Ended(false)
UserData(NULL), Callback(NULL), URL(url), Reader(NULL), Ended(false)
{
SetStream(stream);
}
FMODStreamCapsule(FMOD::Sound *stream, FMODSoundRenderer *owner, FileReader *reader)
: Owner(owner), Stream(NULL), Channel(NULL),
UserData(NULL), Callback(NULL), Reader(reader), Ended(false)
{
SetStream(stream);
}
FMODStreamCapsule(void *udata, SoundStreamCallback callback, FMODSoundRenderer *owner)
: Owner(owner), Stream(NULL), Channel(NULL),
UserData(udata), Callback(callback), Ended(false)
UserData(udata), Callback(callback), Reader(NULL), Ended(false)
{}
~FMODStreamCapsule()
@ -327,6 +331,10 @@ public:
{
Stream->release();
}
if (Reader != NULL)
{
delete Reader;
}
}
void SetStream(FMOD::Sound *stream)
@ -596,6 +604,7 @@ private:
FMOD::Channel *Channel;
void *UserData;
SoundStreamCallback Callback;
FileReader *Reader;
FString URL;
bool Ended;
bool JustStarted;
@ -625,30 +634,6 @@ bool FMODSoundRenderer::IsValid()
return InitSuccess;
}
#ifdef _MSC_VER
//==========================================================================
//
// CheckException
//
//==========================================================================
#ifndef FACILITY_VISUALCPP
#define FACILITY_VISUALCPP ((LONG)0x6d)
#endif
#define VcppException(sev,err) ((sev) | (FACILITY_VISUALCPP<<16) | err)
static int CheckException(DWORD code)
{
if (code == VcppException(ERROR_SEVERITY_ERROR,ERROR_MOD_NOT_FOUND) ||
code == VcppException(ERROR_SEVERITY_ERROR,ERROR_PROC_NOT_FOUND))
{
return EXCEPTION_EXECUTE_HANDLER;
}
return EXCEPTION_CONTINUE_SEARCH;
}
#endif
//==========================================================================
//
// FMODSoundRenderer :: Init
@ -686,14 +671,8 @@ bool FMODSoundRenderer::Init()
Printf("I_InitSound: Initializing FMOD\n");
// Create a System object and initialize.
#ifdef _MSC_VER
__try {
#endif
result = FMOD::System_Create(&Sys);
#ifdef _MSC_VER
}
__except(CheckException(GetExceptionCode()))
// This is just for safety. Normally this should never be called if FMod Ex cannot be found.
if (!IsFModExPresent())
{
Sys = NULL;
Printf(TEXTCOLOR_ORANGE"Failed to load fmodex"
@ -703,7 +682,9 @@ bool FMODSoundRenderer::Init()
".dll\n");
return false;
}
#endif
// Create a System object and initialize.
result = FMOD::System_Create(&Sys);
if (result != FMOD_OK)
{
Sys = NULL;
@ -895,6 +876,15 @@ bool FMODSoundRenderer::Init()
// Set software format
eval = Enum_NumForName(SoundFormatNames, snd_output_format);
format = eval >= 0 ? FMOD_SOUND_FORMAT(eval) : FMOD_SOUND_FORMAT_PCM16;
if (format == FMOD_SOUND_FORMAT_PCM8)
{
// PCM-8 sounds like garbage with anything but DirectSound.
FMOD_OUTPUTTYPE output;
if (FMOD_OK != Sys->getOutput(&output) || output != FMOD_OUTPUTTYPE_DSOUND)
{
format = FMOD_SOUND_FORMAT_PCM16;
}
}
eval = Enum_NumForName(ResamplerNames, snd_resampler);
resampler = eval >= 0 ? FMOD_DSP_RESAMPLER(eval) : FMOD_DSP_RESAMPLER_LINEAR;
// These represented the frequency limits for hardware channels, which we never used anyway.
@ -1601,34 +1591,79 @@ static void SetCustomLoopPts(FMOD::Sound *sound)
//==========================================================================
//
// FMODSoundRenderer :: OpenStream
// open_reader_callback
// close_reader_callback
// read_reader_callback
// seek_reader_callback
//
// Creates a streaming sound from a file on disk.
// FMOD_CREATESOUNDEXINFO callbacks to handle reading resource data from a
// FileReader.
//
//==========================================================================
SoundStream *FMODSoundRenderer::OpenStream(const char *filename_or_data, int flags, int offset, int length)
static FMOD_RESULT F_CALLBACK open_reader_callback(const char *name, int unicode, unsigned int *filesize, void **handle, void **userdata)
{
FileReader *reader = NULL;
if(sscanf(name, "_FileReader_%p", &reader) != 1)
{
Printf("Invalid name in callback: %s\n", name);
return FMOD_ERR_FILE_NOTFOUND;
}
*filesize = reader->GetLength();
*handle = reader;
*userdata = reader;
return FMOD_OK;
}
static FMOD_RESULT F_CALLBACK close_reader_callback(void *handle, void *userdata)
{
return FMOD_OK;
}
static FMOD_RESULT F_CALLBACK read_reader_callback(void *handle, void *buffer, unsigned int sizebytes, unsigned int *bytesread, void *userdata)
{
FileReader *reader = reinterpret_cast<FileReader*>(handle);
*bytesread = reader->Read(buffer, sizebytes);
if(*bytesread > 0) return FMOD_OK;
return FMOD_ERR_FILE_EOF;
}
static FMOD_RESULT F_CALLBACK seek_reader_callback(void *handle, unsigned int pos, void *userdata)
{
FileReader *reader = reinterpret_cast<FileReader*>(handle);
if(reader->Seek(pos, SEEK_SET) == 0)
return FMOD_OK;
return FMOD_ERR_FILE_COULDNOTSEEK;
}
//==========================================================================
//
// FMODSoundRenderer :: OpenStream
//
// Creates a streaming sound from a FileReader.
//
//==========================================================================
SoundStream *FMODSoundRenderer::OpenStream(FileReader *reader, int flags)
{
FMOD_MODE mode;
FMOD_CREATESOUNDEXINFO exinfo;
FMOD::Sound *stream;
FMOD_RESULT result;
bool url;
FString patches;
FString name;
InitCreateSoundExInfo(&exinfo);
exinfo.useropen = open_reader_callback;
exinfo.userclose = close_reader_callback;
exinfo.userread = read_reader_callback;
exinfo.userseek = seek_reader_callback;
mode = FMOD_SOFTWARE | FMOD_2D | FMOD_CREATESTREAM;
if(flags & SoundStream::Loop)
{
mode |= FMOD_LOOP_NORMAL;
}
if (offset == -1)
{
mode |= FMOD_OPENMEMORY;
offset = 0;
}
exinfo.length = length;
exinfo.fileoffset = offset;
if((*snd_midipatchset)[0] != '\0')
{
#ifdef _WIN32
@ -1647,37 +1682,80 @@ SoundStream *FMODSoundRenderer::OpenStream(const char *filename_or_data, int fla
exinfo.dlsname = patches;
}
url = (offset == 0 && length == 0 && strstr(filename_or_data, "://") > filename_or_data);
if (url)
{
// Use a larger buffer for URLs so that it's less likely to be effected
// by hiccups in the data rate from the remote server.
Sys->setStreamBufferSize(64*1024, FMOD_TIMEUNIT_RAWBYTES);
}
result = Sys->createSound(filename_or_data, mode, &exinfo, &stream);
if (url)
{
// Restore standard buffer size.
Sys->setStreamBufferSize(16*1024, FMOD_TIMEUNIT_RAWBYTES);
}
name.Format("_FileReader_%p", reader);
result = Sys->createSound(name, mode, &exinfo, &stream);
if(result == FMOD_ERR_FORMAT && exinfo.dlsname != NULL)
{
// FMOD_ERR_FORMAT could refer to either the main sound file or
// to the DLS instrument set. Try again without special DLS
// instruments to see if that lets it succeed.
exinfo.dlsname = NULL;
result = Sys->createSound(filename_or_data, mode, &exinfo, &stream);
result = Sys->createSound(name, mode, &exinfo, &stream);
if (result == FMOD_OK)
{
Printf("%s is an unsupported format.\n", *snd_midipatchset);
}
}
if(result != FMOD_OK)
return NULL;
SetCustomLoopPts(stream);
return new FMODStreamCapsule(stream, this, reader);
}
SoundStream *FMODSoundRenderer::OpenStream(const char *url, int flags)
{
FMOD_MODE mode;
FMOD_CREATESOUNDEXINFO exinfo;
FMOD::Sound *stream;
FMOD_RESULT result;
FString patches;
InitCreateSoundExInfo(&exinfo);
mode = FMOD_SOFTWARE | FMOD_2D | FMOD_CREATESTREAM;
if(flags & SoundStream::Loop)
mode |= FMOD_LOOP_NORMAL;
if((*snd_midipatchset)[0] != '\0')
{
#ifdef _WIN32
// If the path does not contain any path separators, automatically
// prepend $PROGDIR to the path.
if (strcspn(snd_midipatchset, ":/\\") == strlen(snd_midipatchset))
{
patches << "$PROGDIR/" << snd_midipatchset;
patches = NicePath(patches);
}
else
#endif
{
patches = NicePath(snd_midipatchset);
}
exinfo.dlsname = patches;
}
// Use a larger buffer for URLs so that it's less likely to be effected
// by hiccups in the data rate from the remote server.
Sys->setStreamBufferSize(64*1024, FMOD_TIMEUNIT_RAWBYTES);
result = Sys->createSound(url, mode, &exinfo, &stream);
if(result == FMOD_ERR_FORMAT && exinfo.dlsname != NULL)
{
exinfo.dlsname = NULL;
result = Sys->createSound(url, mode, &exinfo, &stream);
if(result == FMOD_OK)
{
SetCustomLoopPts(stream);
return new FMODStreamCapsule(stream, this, url ? filename_or_data : NULL);
Printf("%s is an unsupported format.\n", *snd_midipatchset);
}
}
// Restore standard buffer size.
Sys->setStreamBufferSize(16*1024, FMOD_TIMEUNIT_RAWBYTES);
if(result != FMOD_OK)
return NULL;
SetCustomLoopPts(stream);
return new FMODStreamCapsule(stream, this, url);
}
//==========================================================================
@ -2047,7 +2125,7 @@ FISoundChannel *FMODSoundRenderer::CommonChannelSetup(FMOD::Channel *chan, FISou
//==========================================================================
//
// FMODSoundRenderer :: StopSound
// FMODSoundRenderer :: StopChannel
//
//==========================================================================
@ -2055,7 +2133,10 @@ void FMODSoundRenderer::StopChannel(FISoundChannel *chan)
{
if (chan != NULL && chan->SysChannel != NULL)
{
((FMOD::Channel *)chan->SysChannel)->stop();
if (((FMOD::Channel *)chan->SysChannel)->stop() == FMOD_ERR_INVALID_HANDLE)
{ // The channel handle was invalid; pretend it ended.
S_ChannelEnded(chan);
}
}
}
@ -3092,3 +3173,45 @@ FMOD_RESULT FMODSoundRenderer::SetSystemReverbProperties(const REVERB_PROPERTIES
#endif
}
#endif // NO_FMOD
//==========================================================================
//
// IsFModExPresent
//
// Check if FMod can be used
//
//==========================================================================
bool IsFModExPresent()
{
#ifdef NO_FMOD
return false;
#elif !defined _WIN32
return true; // on non-Windows we cannot delay load the library so it has to be present.
#else
static bool cached_result;
static bool done = false;
if (!done)
{
done = true;
FMOD::System *Sys;
FMOD_RESULT result;
__try
{
result = FMOD::System_Create(&Sys);
}
__except (CheckException(GetExceptionCode()))
{
// FMod could not be delay loaded
return false;
}
if (result == FMOD_OK) Sys->release();
cached_result = true;
}
return cached_result;
#endif
}

View file

@ -2,6 +2,8 @@
#define FMODSOUND_H
#include "i_sound.h"
#ifndef NO_FMOD
#include "fmod_wrap.h"
class FMODSoundRenderer : public SoundRenderer
@ -22,9 +24,8 @@ public:
// Streaming sounds.
SoundStream *CreateStream (SoundStreamCallback callback, int buffsamples, int flags, int samplerate, void *userdata);
SoundStream *OpenStream (const char *filename, int flags, int offset, int length);
long PlayStream (SoundStream *stream, int volume);
void StopStream (SoundStream *stream);
SoundStream *OpenStream (FileReader *reader, int flags);
SoundStream *OpenStream (const char *url, int flags);
// Starts a sound.
FISoundChannel *StartSound (SoundHandle sfx, float vol, int pitch, int chanflags, FISoundChannel *reuse_chan);
@ -126,3 +127,4 @@ private:
};
#endif
#endif

View file

@ -99,7 +99,7 @@ EXTERN_CVAR (Int, snd_mididevice)
static bool MusicDown = true;
static BYTE *ungzip(BYTE *data, int *size);
static bool ungzip(BYTE *data, int size, TArray<BYTE> &newdata);
MusInfo *currSong;
int nomusic = 0;
@ -301,21 +301,21 @@ MusInfo *MusInfo::GetWaveDumper(const char *filename, int rate)
//
//==========================================================================
static MIDIStreamer *CreateMIDIStreamer(FILE *file, BYTE *musiccache, int len, EMidiDevice devtype, EMIDIType miditype)
static MIDIStreamer *CreateMIDIStreamer(FileReader &reader, EMidiDevice devtype, EMIDIType miditype)
{
switch (miditype)
{
case MIDI_MUS:
return new MUSSong2(file, musiccache, len, devtype);
return new MUSSong2(reader, devtype);
case MIDI_MIDI:
return new MIDISong2(file, musiccache, len, devtype);
return new MIDISong2(reader, devtype);
case MIDI_HMI:
return new HMISong(file, musiccache, len, devtype);
return new HMISong(reader, devtype);
case MIDI_XMI:
return new XMISong(file, musiccache, len, devtype);
return new XMISong(reader, devtype);
default:
return NULL;
@ -377,100 +377,61 @@ static EMIDIType IdentifyMIDIType(DWORD *id, int size)
//
//==========================================================================
MusInfo *I_RegisterSong (const char *filename, BYTE *musiccache, int offset, int len, int device)
MusInfo *I_RegisterSong (FileReader *reader, int device)
{
FILE *file;
MusInfo *info = NULL;
const char *fmt;
DWORD id[32/4];
BYTE *ungzipped;
int i;
if (nomusic)
{
delete reader;
return 0;
}
if (offset != -1)
{
file = fopen (filename, "rb");
if (file == NULL)
if(reader->Read(id, 32) != 32 || reader->Seek(-32, SEEK_CUR) != 0)
{
delete reader;
return 0;
}
if (len == 0 && offset == 0)
{
fseek (file, 0, SEEK_END);
len = ftell (file);
fseek (file, 0, SEEK_SET);
}
else
{
fseek (file, offset, SEEK_SET);
}
if (len < 32)
{
return 0;
}
if (fread (id, 4, 32/4, file) != 32/4)
{
fclose (file);
return 0;
}
fseek (file, -32, SEEK_CUR);
}
else
{
file = NULL;
if (len < 32)
{
return 0;
}
for (i = 0; i < 32/4; ++i)
{
id[i] = ((DWORD *)musiccache)[i];
}
}
#ifndef _WIN32
// non-Windows platforms don't support MDEV_MMAPI so map to MDEV_FMOD
// non-Windows platforms don't support MDEV_MMAPI so map to MDEV_SNDSYS
if (device == MDEV_MMAPI)
device = MDEV_FMOD;
device = MDEV_SNDSYS;
#endif
// Check for gzip compression. Some formats are expected to have players
// that can handle it, so it simplifies things if we make all songs
// gzippable.
ungzipped = NULL;
if ((id[0] & MAKE_ID(255, 255, 255, 0)) == GZIP_ID)
{
if (offset != -1)
{
int len = reader->GetLength();
BYTE *gzipped = new BYTE[len];
if (fread(gzipped, 1, len, file) != (size_t)len)
if (reader->Read(gzipped, len) != len)
{
delete[] gzipped;
fclose(file);
delete reader;
return NULL;
}
ungzipped = ungzip(gzipped, &len);
delete reader;
MemoryArrayReader *memreader = new MemoryArrayReader(NULL, 0);
if (!ungzip(gzipped, len, memreader->GetArray()))
{
delete[] gzipped;
delete memreader;
return 0;
}
else
delete[] gzipped;
memreader->UpdateLength();
if (memreader->Read(id, 32) != 32 || memreader->Seek(-32, SEEK_CUR) != 0)
{
ungzipped = ungzip(musiccache, &len);
}
if (ungzipped == NULL)
{
fclose(file);
return NULL;
}
musiccache = ungzipped;
for (i = 0; i < 32/4; ++i)
{
id[i] = ((DWORD *)musiccache)[i];
delete memreader;
return 0;
}
reader = memreader;
}
EMIDIType miditype = IdentifyMIDIType(id, sizeof(id));
@ -478,22 +439,22 @@ MusInfo *I_RegisterSong (const char *filename, BYTE *musiccache, int offset, int
{
EMidiDevice devtype = (EMidiDevice)device;
retry_as_fmod:
info = CreateMIDIStreamer(file, musiccache, len, devtype, miditype);
retry_as_sndsys:
info = CreateMIDIStreamer(*reader, devtype, miditype);
if (info != NULL && !info->IsValid())
{
delete info;
info = NULL;
}
if (info == NULL && devtype != MDEV_FMOD && snd_mididevice < 0)
if (info == NULL && devtype != MDEV_SNDSYS && snd_mididevice < 0)
{
devtype = MDEV_FMOD;
goto retry_as_fmod;
devtype = MDEV_SNDSYS;
goto retry_as_sndsys;
}
#ifdef _WIN32
if (info == NULL && devtype != MDEV_MMAPI && snd_mididevice >= 0)
{
info = CreateMIDIStreamer(file, musiccache, len, MDEV_MMAPI, miditype);
info = CreateMIDIStreamer(*reader, MDEV_MMAPI, miditype);
}
#endif
}
@ -504,74 +465,62 @@ retry_as_fmod:
(id[0] == MAKE_ID('D','B','R','A') && id[1] == MAKE_ID('W','O','P','L')) || // DosBox Raw OPL
(id[0] == MAKE_ID('A','D','L','I') && *((BYTE *)id + 4) == 'B')) // Martin Fernandez's modified IMF
{
info = new OPLMUSSong (file, musiccache, len);
info = new OPLMUSSong (*reader);
}
// Check for game music
else if ((fmt = GME_CheckFormat(id[0])) != NULL && fmt[0] != '\0')
{
info = GME_OpenSong(file, musiccache, len, fmt);
info = GME_OpenSong(*reader, fmt);
}
// Check for module formats
else
{
info = MOD_OpenSong(file, musiccache, len);
info = MOD_OpenSong(*reader);
}
if (info == NULL)
{
// Check for CDDA "format"
if (id[0] == (('R')|(('I')<<8)|(('F')<<16)|(('F')<<24)))
{
if (file != NULL)
{
DWORD subid;
fseek (file, 8, SEEK_CUR);
if (fread (&subid, 4, 1, file) != 1)
reader->Seek(8, SEEK_CUR);
if (reader->Read (&subid, 4) != 4)
{
fclose (file);
delete reader;
return 0;
}
fseek (file, -12, SEEK_CUR);
reader->Seek(-12, SEEK_CUR);
if (subid == (('C')|(('D')<<8)|(('D')<<16)|(('A')<<24)))
{
// This is a CDDA file
info = new CDDAFile (file, len);
}
info = new CDDAFile (*reader);
}
}
// no FMOD => no modules/streams
// no support in sound system => no modules/streams
// 1024 bytes is an arbitrary restriction. It's assumed that anything
// smaller than this can't possibly be a valid music file if it hasn't
// been identified already, so don't even bother trying to load it.
// Of course MIDIs shorter than 1024 bytes should pass.
if (info == NULL && (len >= 1024 || id[0] == MAKE_ID('M','T','h','d')))
if (info == NULL && (reader->GetLength() >= 1024 || id[0] == MAKE_ID('M','T','h','d')))
{
// Let FMOD figure out what it is.
if (file != NULL)
{
fclose (file);
file = NULL;
}
info = new StreamSong (offset >= 0 ? filename : (const char *)musiccache, offset, len);
// Let the sound system figure out what it is.
info = new StreamSong (reader);
// Assumed ownership
reader = NULL;
}
}
if (reader != NULL) delete reader;
if (info && !info->IsValid ())
{
delete info;
info = NULL;
}
if (file != NULL)
{
fclose (file);
}
if (ungzipped != NULL)
{
delete[] ungzipped;
}
return info;
}
@ -605,7 +554,7 @@ MusInfo *I_RegisterURLSong (const char *url)
{
StreamSong *song;
song = new StreamSong(url, 0, 0);
song = new StreamSong(url);
if (song->IsValid())
{
return song;
@ -623,13 +572,12 @@ MusInfo *I_RegisterURLSong (const char *url)
//
//==========================================================================
BYTE *ungzip(BYTE *data, int *complen)
static bool ungzip(BYTE *data, int complen, TArray<BYTE> &newdata)
{
const BYTE *max = data + *complen - 8;
const BYTE *max = data + complen - 8;
const BYTE *compstart = data + 10;
BYTE flags = data[3];
unsigned isize;
BYTE *newdata;
z_stream stream;
int err;
@ -658,16 +606,16 @@ BYTE *ungzip(BYTE *data, int *complen)
}
if (compstart >= max - 1)
{
return NULL;
return false;
}
// Decompress
isize = LittleLong(*(DWORD *)(data + *complen - 4));
newdata = new BYTE[isize];
isize = LittleLong(*(DWORD *)(data + complen - 4));
newdata.Resize(isize);
stream.next_in = (Bytef *)compstart;
stream.avail_in = (uInt)(max - compstart);
stream.next_out = newdata;
stream.next_out = &newdata[0];
stream.avail_out = isize;
stream.zalloc = (alloc_func)0;
stream.zfree = (free_func)0;
@ -675,25 +623,20 @@ BYTE *ungzip(BYTE *data, int *complen)
err = inflateInit2(&stream, -MAX_WBITS);
if (err != Z_OK)
{
delete[] newdata;
return NULL;
return false;
}
err = inflate(&stream, Z_FINISH);
if (err != Z_STREAM_END)
{
inflateEnd(&stream);
delete[] newdata;
return NULL;
return false;
}
err = inflateEnd(&stream);
if (err != Z_OK)
{
delete[] newdata;
return NULL;
return false;
}
*complen = isize;
return newdata;
return true;
}
//==========================================================================

View file

@ -52,7 +52,7 @@ void I_SetMusicVolume (float volume);
// Registers a song handle to song data.
class MusInfo;
MusInfo *I_RegisterSong (const char *file, BYTE *musiccache, int offset, int length, int device);
MusInfo *I_RegisterSong (FileReader *reader, int device);
MusInfo *I_RegisterCDSong (int track, int cdid = 0);
MusInfo *I_RegisterURLSong (const char *url);

View file

@ -23,6 +23,7 @@
#include "i_sound.h"
#include "i_music.h"
#include "s_sound.h"
#include "files.h"
void I_InitMusicWin32 ();
void I_ShutdownMusicWin32 ();
@ -168,16 +169,16 @@ protected:
bool bLooping;
};
// FMOD pseudo-MIDI device --------------------------------------------------
// Sound System pseudo-MIDI device ------------------------------------------
class FMODMIDIDevice : public PseudoMIDIDevice
class SndSysMIDIDevice : public PseudoMIDIDevice
{
public:
int Open(void (*callback)(unsigned int, void *, DWORD, DWORD), void *userdata);
bool Preprocess(MIDIStreamer *song, bool looping);
};
// MIDI file played with TiMidity++ and possibly streamed through FMOD ------
// MIDI file played with TiMidity++ and possibly streamed through the Sound System
class TimidityPPMIDIDevice : public PseudoMIDIDevice
{
@ -500,7 +501,7 @@ protected:
class MUSSong2 : public MIDIStreamer
{
public:
MUSSong2(FILE *file, BYTE *musiccache, int length, EMidiDevice type);
MUSSong2(FileReader &reader, EMidiDevice type);
~MUSSong2();
MusInfo *GetOPLDumper(const char *filename);
@ -526,7 +527,7 @@ protected:
class MIDISong2 : public MIDIStreamer
{
public:
MIDISong2(FILE *file, BYTE *musiccache, int length, EMidiDevice type);
MIDISong2(FileReader &reader, EMidiDevice type);
~MIDISong2();
MusInfo *GetOPLDumper(const char *filename);
@ -583,7 +584,7 @@ protected:
class HMISong : public MIDIStreamer
{
public:
HMISong(FILE *file, BYTE *musiccache, int length, EMidiDevice type);
HMISong(FileReader &reader, EMidiDevice type);
~HMISong();
MusInfo *GetOPLDumper(const char *filename);
@ -626,7 +627,7 @@ protected:
class XMISong : public MIDIStreamer
{
public:
XMISong(FILE *file, BYTE *musiccache, int length, EMidiDevice type);
XMISong(FileReader &reader, EMidiDevice type);
~XMISong();
MusInfo *GetOPLDumper(const char *filename);
@ -660,12 +661,13 @@ protected:
EventSource EventDue;
};
// Anything supported by FMOD out of the box --------------------------------
// Anything supported by the sound system out of the box --------------------
class StreamSong : public MusInfo
{
public:
StreamSong (const char *file, int offset, int length);
StreamSong (FileReader *reader);
StreamSong (const char *url);
~StreamSong ();
void Play (bool looping, int subsong);
void Pause ();
@ -683,12 +685,12 @@ protected:
SoundStream *m_Stream;
};
// MUS file played by a software OPL2 synth and streamed through FMOD -------
// MUS file played by a software OPL2 synth and streamed through the sound system
class OPLMUSSong : public StreamSong
{
public:
OPLMUSSong (FILE *file, BYTE *musiccache, int length);
OPLMUSSong (FileReader &reader);
~OPLMUSSong ();
void Play (bool looping, int subsong);
bool IsPlaying ();
@ -737,17 +739,17 @@ protected:
class CDDAFile : public CDSong
{
public:
CDDAFile (FILE *file, int length);
CDDAFile (FileReader &reader);
};
// Module played via foo_dumb -----------------------------------------------
MusInfo *MOD_OpenSong(FILE *file, BYTE *musiccache, int len);
MusInfo *MOD_OpenSong(FileReader &reader);
// Music played via Game Music Emu ------------------------------------------
const char *GME_CheckFormat(uint32 header);
MusInfo *GME_OpenSong(FILE *file, BYTE *musiccache, int len, const char *fmt);
MusInfo *GME_OpenSong(FileReader &reader, const char *fmt);
// --------------------------------------------------------------------------

View file

@ -52,7 +52,12 @@ extern HINSTANCE g_hInst;
#include "doomtype.h"
#include <math.h>
#include "except.h"
#include "fmodsound.h"
#include "oalsound.h"
#include "mpg123_decoder.h"
#include "sndfile_decoder.h"
#include "m_swap.h"
#include "stats.h"
@ -77,6 +82,16 @@ CVAR (Int, snd_samplerate, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CVAR (Int, snd_buffersize, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CVAR (String, snd_output, "default", CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
#ifndef NO_FMOD
#define DEF_BACKEND "fmod"
#elif !defined(NO_OPENAL)
#define DEF_BACKEND "openal"
#else
#define DEF_BACKEND "null"
#endif
CVAR(String, snd_backend, DEF_BACKEND, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
// killough 2/21/98: optionally use varying pitched sounds
CVAR (Bool, snd_pitched, false, CVAR_ARCHIVE)
@ -159,8 +174,9 @@ public:
{
return NULL;
}
SoundStream *OpenStream (const char *filename, int flags, int offset, int length)
SoundStream *OpenStream (FileReader *reader, int flags)
{
delete reader;
return NULL;
}
@ -242,6 +258,7 @@ void I_InitSound ()
nosound = !!Args->CheckParm ("-nosound");
nosfx = !!Args->CheckParm ("-nosfx");
GSnd = NULL;
if (nosound)
{
GSnd = new NullSoundRenderer;
@ -249,9 +266,51 @@ void I_InitSound ()
return;
}
// This has been extended to allow falling back from FMod to OpenAL and vice versa if the currently active sound system cannot be found.
if (stricmp(snd_backend, "null") == 0)
{
GSnd = new NullSoundRenderer;
}
else if(stricmp(snd_backend, "fmod") == 0)
{
#ifndef NO_FMOD
if (IsFModExPresent())
{
GSnd = new FMODSoundRenderer;
if (!GSnd->IsValid ())
}
#endif
#ifndef NO_OPENAL
if ((!GSnd || !GSnd->IsValid()) && IsOpenALPresent())
{
Printf (TEXTCOLOR_RED"FMod Ex Sound init failed. Trying OpenAL.\n");
GSnd = new OpenALSoundRenderer;
snd_backend = "openal";
}
#endif
}
else if(stricmp(snd_backend, "openal") == 0)
{
#ifndef NO_OPENAL
if (IsOpenALPresent())
{
GSnd = new OpenALSoundRenderer;
}
#endif
#ifndef NO_FMOD
if ((!GSnd || !GSnd->IsValid()) && IsFModExPresent())
{
Printf (TEXTCOLOR_RED"OpenAL Sound init failed. Trying FMod Ex.\n");
GSnd = new FMODSoundRenderer;
snd_backend = "fmod";
}
#endif
}
else
{
Printf (TEXTCOLOR_RED"%s: Unknown sound system specified\n", *snd_backend);
snd_backend = "null";
}
if (!GSnd || !GSnd->IsValid ())
{
I_CloseSound();
GSnd = new NullSoundRenderer;
@ -283,6 +342,27 @@ void I_ShutdownSound()
}
}
const char *GetSampleTypeName(enum SampleType type)
{
switch(type)
{
case SampleType_UInt8: return "Unsigned 8-bit";
case SampleType_Int16: return "Signed 16-bit";
}
return "(invalid sample type)";
}
const char *GetChannelConfigName(enum ChannelConfig chan)
{
switch(chan)
{
case ChannelConfig_Mono: return "Mono";
case ChannelConfig_Stereo: return "Stereo";
}
return "(invalid channel config)";
}
CCMD (snd_status)
{
GSnd->PrintStatus ();
@ -321,9 +401,28 @@ FString SoundRenderer::GatherStats ()
return "No stats for this sound renderer.";
}
short *SoundRenderer::DecodeSample(int outlen, const void *coded, int sizebytes, ECodecType type)
short *SoundRenderer::DecodeSample(int outlen, const void *coded, int sizebytes, ECodecType ctype)
{
return NULL;
MemoryReader reader((const char*)coded, sizebytes);
short *samples = (short*)calloc(1, outlen);
ChannelConfig chans;
SampleType type;
int srate;
SoundDecoder *decoder = CreateDecoder(&reader);
if(!decoder) return samples;
decoder->getInfo(&srate, &chans, &type);
if(chans != ChannelConfig_Mono || type != SampleType_Int16)
{
DPrintf("Sample is not 16-bit mono\n");
delete decoder;
return samples;
}
decoder->read((char*)samples, outlen);
delete decoder;
return samples;
}
void SoundRenderer::DrawWaveDebug(int mode)
@ -504,3 +603,51 @@ SoundHandle SoundRenderer::LoadSoundVoc(BYTE *sfxdata, int length)
return retval;
}
SoundStream *SoundRenderer::OpenStream(const char *url, int flags)
{
return 0;
}
SoundDecoder *SoundRenderer::CreateDecoder(FileReader *reader)
{
SoundDecoder *decoder = NULL;
int pos = reader->Tell();
#ifdef HAVE_MPG123
decoder = new MPG123Decoder;
if (decoder->open(reader))
return decoder;
reader->Seek(pos, SEEK_SET);
delete decoder;
decoder = NULL;
#endif
#ifdef HAVE_SNDFILE
decoder = new SndFileDecoder;
if (decoder->open(reader))
return decoder;
reader->Seek(pos, SEEK_SET);
delete decoder;
decoder = NULL;
#endif
return decoder;
}
// Default readAll implementation, for decoders that can't do anything better
TArray<char> SoundDecoder::readAll()
{
TArray<char> output;
unsigned total = 0;
unsigned got;
output.Resize(total+32768);
while((got=(unsigned)read(&output[total], output.Size()-total)) > 0)
{
total += got;
output.Resize(total*2);
}
output.Resize(total);
return output;
}

View file

@ -38,6 +38,8 @@
#include "doomtype.h"
#include "i_soundinternal.h"
class FileReader;
enum ECodecType
{
CODEC_Unknown,
@ -82,6 +84,8 @@ public:
typedef bool (*SoundStreamCallback)(SoundStream *stream, void *buff, int len, void *userdata);
struct SoundDecoder;
class SoundRenderer
{
public:
@ -101,7 +105,8 @@ public:
// Streaming sounds.
virtual SoundStream *CreateStream (SoundStreamCallback callback, int buffbytes, int flags, int samplerate, void *userdata) = 0;
virtual SoundStream *OpenStream (const char *filename, int flags, int offset, int length) = 0;
virtual SoundStream *OpenStream (FileReader *reader, int flags) = 0;
virtual SoundStream *OpenStream (const char *url, int flags);
// Starts a sound.
virtual FISoundChannel *StartSound (SoundHandle sfx, float vol, int pitch, int chanflags, FISoundChannel *reuse_chan) = 0;
@ -142,6 +147,7 @@ public:
virtual void UpdateListener (SoundListener *) = 0;
virtual void UpdateSounds () = 0;
virtual void UpdateMusic() {}
virtual bool IsValid () = 0;
virtual void PrintStatus () = 0;
@ -150,6 +156,9 @@ public:
virtual short *DecodeSample(int outlen, const void *coded, int sizebytes, ECodecType type);
virtual void DrawWaveDebug(int mode);
protected:
virtual SoundDecoder *CreateDecoder(FileReader *reader);
};
extern SoundRenderer *GSnd;
@ -166,4 +175,7 @@ FISoundChannel *S_GetChannel(void *syschan);
extern ReverbContainer *DefaultEnvironments[26];
bool IsFModExPresent();
bool IsOpenALPresent();
#endif

View file

@ -1,7 +1,13 @@
#ifndef __SNDINT_H
#define __SNDINT_H
#include <stdio.h>
#include "basictypes.h"
#include "vectors.h"
#include "tarray.h"
class FileReader;
// For convenience, this structure matches FMOD_REVERB_PROPERTIES.
// Since I can't very well #include system-specific stuff in the
@ -96,8 +102,46 @@ struct FISoundChannel
// callback that can't be passed a sound channel pointer
FRolloffInfo Rolloff;
float DistanceScale;
float DistanceSqr;
bool ManualRolloff;
};
enum SampleType
{
SampleType_UInt8,
SampleType_Int16
};
enum ChannelConfig
{
ChannelConfig_Mono,
ChannelConfig_Stereo
};
const char *GetSampleTypeName(enum SampleType type);
const char *GetChannelConfigName(enum ChannelConfig chan);
struct SoundDecoder
{
virtual void getInfo(int *samplerate, ChannelConfig *chans, SampleType *type) = 0;
virtual size_t read(char *buffer, size_t bytes) = 0;
virtual TArray<char> readAll();
virtual bool seek(size_t ms_offset) = 0;
virtual size_t getSampleOffset() = 0;
virtual size_t getSampleLength() { return 0; }
SoundDecoder() { }
virtual ~SoundDecoder() { }
protected:
virtual bool open(FileReader *reader) = 0;
friend class SoundRenderer;
private:
// Make non-copyable
SoundDecoder(const SoundDecoder &rhs);
SoundDecoder& operator=(const SoundDecoder &rhs);
};
#endif

View file

@ -0,0 +1,206 @@
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#define USE_WINDOWS_DWORD
#endif
#include "mpg123_decoder.h"
#include "files.h"
#include "except.h"
#ifdef HAVE_MPG123
static bool inited = false;
off_t MPG123Decoder::file_lseek(void *handle, off_t offset, int whence)
{
MPG123Decoder *self = reinterpret_cast<MPG123Decoder*>(handle);
FileReader *reader = self->Reader;
if(whence == SEEK_SET)
offset += self->StartOffset;
else if(whence == SEEK_CUR)
{
if(offset < 0 && reader->Tell()+offset < self->StartOffset)
return -1;
}
else if(whence == SEEK_END)
{
if(offset < 0 && reader->GetLength()+offset < self->StartOffset)
return -1;
}
if(reader->Seek(offset, whence) != 0)
return -1;
return reader->Tell() - self->StartOffset;
}
ssize_t MPG123Decoder::file_read(void *handle, void *buffer, size_t bytes)
{
FileReader *reader = reinterpret_cast<MPG123Decoder*>(handle)->Reader;
return reader->Read(buffer, bytes);
}
MPG123Decoder::~MPG123Decoder()
{
if(MPG123)
{
mpg123_close(MPG123);
mpg123_delete(MPG123);
MPG123 = 0;
}
}
bool MPG123Decoder::open(FileReader *reader)
{
if(!inited)
{
__try
{
if(mpg123_init() != MPG123_OK)
return false;
inited = true;
}
__except (CheckException(GetExceptionCode()))
{
// this means that the delay loaded decoder DLL was not found.
return false;
}
}
Reader = reader;
StartOffset = 0;
char data[10];
if(file_read(this, data, 10) != 10)
return false;
int start_offset = 0;
// Check for ID3 tags and skip them
if(memcmp(data, "ID3", 3) == 0 &&
(BYTE)data[3] <= 4 && (BYTE)data[4] != 0xff &&
(data[5]&0x0f) == 0 && (data[6]&0x80) == 0 &&
(data[7]&0x80) == 0 && (data[8]&0x80) == 0 &&
(data[9]&0x80) == 0)
{
// ID3v2
start_offset = (data[6]<<21) | (data[7]<<14) |
(data[8]<< 7) | (data[9] );
start_offset += ((data[5]&0x10) ? 20 : 10);
}
StartOffset = start_offset;
if(file_lseek(this, 0, SEEK_SET) != 0)
return false;
// Check for a frame header
bool frame_ok = false;
if(file_read(this, data, 3) == 3)
{
if((BYTE)data[0] == 0xff &&
((data[1]&0xfe) == 0xfa/*MPEG-1*/ || (data[1]&0xfe) == 0xf2/*MPEG-2*/))
{
int brate_idx = (data[2]>>4) & 0x0f;
int srate_idx = (data[2]>>2) & 0x03;
if(brate_idx != 0 && brate_idx != 15 && srate_idx != 3)
frame_ok = (file_lseek(this, 0, SEEK_SET) == 0);
}
}
if(frame_ok)
{
MPG123 = mpg123_new(NULL, NULL);
if(mpg123_replace_reader_handle(MPG123, file_read, file_lseek, NULL) == MPG123_OK &&
mpg123_open_handle(MPG123, this) == MPG123_OK)
{
int enc, channels;
long srate;
if(mpg123_getformat(MPG123, &srate, &channels, &enc) == MPG123_OK)
{
if((channels == 1 || channels == 2) && srate > 0 &&
mpg123_format_none(MPG123) == MPG123_OK &&
mpg123_format(MPG123, srate, channels, MPG123_ENC_SIGNED_16) == MPG123_OK)
{
// All OK
Done = false;
return true;
}
}
mpg123_close(MPG123);
}
mpg123_delete(MPG123);
MPG123 = 0;
}
return false;
}
void MPG123Decoder::getInfo(int *samplerate, ChannelConfig *chans, SampleType *type)
{
int enc = 0, channels = 0;
long srate = 0;
mpg123_getformat(MPG123, &srate, &channels, &enc);
*samplerate = srate;
if(channels == 2)
*chans = ChannelConfig_Stereo;
else
*chans = ChannelConfig_Mono;
*type = SampleType_Int16;
}
size_t MPG123Decoder::read(char *buffer, size_t bytes)
{
size_t amt = 0;
while(!Done && bytes > 0)
{
size_t got = 0;
int ret = mpg123_read(MPG123, (unsigned char*)buffer, bytes, &got);
bytes -= got;
buffer += got;
amt += got;
if(ret == MPG123_NEW_FORMAT || ret == MPG123_DONE || got == 0)
{
Done = true;
break;
}
}
return amt;
}
bool MPG123Decoder::seek(size_t ms_offset)
{
int enc, channels;
long srate;
if(mpg123_getformat(MPG123, &srate, &channels, &enc) == MPG123_OK)
{
size_t smp_offset = (size_t)((double)ms_offset / 1000. * srate);
if(mpg123_seek(MPG123, smp_offset, SEEK_SET) >= 0)
{
Done = false;
return true;
}
}
return false;
}
size_t MPG123Decoder::getSampleOffset()
{
return mpg123_tell(MPG123);
}
size_t MPG123Decoder::getSampleLength()
{
off_t len = mpg123_length(MPG123);
return (len > 0) ? len : 0;
}
#endif

View file

@ -0,0 +1,44 @@
#ifndef MPG123_DECODER_H
#define MPG123_DECODER_H
#include "i_soundinternal.h"
#ifdef HAVE_MPG123
#ifdef _MSC_VER
typedef int ssize_t;
#endif
#include "mpg123.h"
struct MPG123Decoder : public SoundDecoder
{
virtual void getInfo(int *samplerate, ChannelConfig *chans, SampleType *type);
virtual size_t read(char *buffer, size_t bytes);
virtual bool seek(size_t ms_offset);
virtual size_t getSampleOffset();
virtual size_t getSampleLength();
MPG123Decoder() : MPG123(0) { }
virtual ~MPG123Decoder();
protected:
virtual bool open(FileReader *reader);
private:
mpg123_handle *MPG123;
bool Done;
FileReader *Reader;
int StartOffset;
static off_t file_lseek(void *handle, off_t offset, int whence);
static ssize_t file_read(void *handle, void *buffer, size_t bytes);
// Make non-copyable
MPG123Decoder(const MPG123Decoder &rhs);
MPG123Decoder& operator=(const MPG123Decoder &rhs);
};
#endif
#endif /* MPG123_DECODER_H */

View file

@ -1,5 +1,6 @@
#include "i_musicinterns.h"
#include "i_cd.h"
#include "files.h"
void CDSong::Play (bool looping, int subsong)
{
@ -78,31 +79,31 @@ bool CDSong::IsPlaying ()
return m_Status != STATE_Stopped;
}
CDDAFile::CDDAFile (FILE *file, int length)
CDDAFile::CDDAFile (FileReader &reader)
: CDSong ()
{
DWORD chunk;
WORD track;
DWORD discid;
long endpos = ftell (file) + length - 8;
long endpos = reader.Tell() + reader.GetLength() - 8;
// I_RegisterSong already identified this as a CDDA file, so we
// just need to check the contents we're interested in.
fseek (file, 12, SEEK_CUR);
reader.Seek(12, SEEK_CUR);
while (ftell (file) < endpos)
while (reader.Tell() < endpos)
{
fread (&chunk, 4, 1, file);
reader.Read(&chunk, 4);
if (chunk != (('f')|(('m')<<8)|(('t')<<16)|((' ')<<24)))
{
fread (&chunk, 4, 1, file);
fseek (file, chunk, SEEK_CUR);
reader.Read(&chunk, 4);
reader.Seek(chunk, SEEK_CUR);
}
else
{
fseek (file, 6, SEEK_CUR);
fread (&track, 2, 1, file);
fread (&discid, 4, 1, file);
reader.Seek(6, SEEK_CUR);
reader.Read(&track, 2);
reader.Read(&discid, 4);
if (CD_InitID (discid) && CD_CheckTrack (track))
{

View file

@ -30,6 +30,7 @@
#include "c_cvars.h"
#include "i_sound.h"
#include "i_system.h"
#include "files.h"
#undef CDECL // w32api's windef.h defines this
#include "../dumb/include/dumb.h"
@ -531,24 +532,17 @@ static DUMBFILE_SYSTEM mem_dfs = {
//
//==========================================================================
DUMBFILE *dumb_read_allfile(dumbfile_mem_status *filestate, BYTE *start, FILE *file, BYTE *musiccache, int lenhave, int lenfull)
DUMBFILE *dumb_read_allfile(dumbfile_mem_status *filestate, BYTE *start, FileReader &reader, int lenhave, int lenfull)
{
filestate->size = lenfull;
filestate->offset = 0;
if (lenhave >= lenfull)
{
filestate->ptr = (BYTE *)start;
return dumbfile_open_ex(filestate, &mem_dfs);
}
if (musiccache != NULL)
{
filestate->ptr = (BYTE *)musiccache;
}
else
{
BYTE *mem = new BYTE[lenfull];
memcpy(mem, start, lenhave);
if (fread(mem + lenhave, 1, lenfull - lenhave, file) != (size_t)(lenfull - lenhave))
if (reader.Read(mem + lenhave, lenfull - lenhave) != (lenfull - lenhave))
{
delete[] mem;
return NULL;
@ -753,7 +747,7 @@ static void MOD_SetAutoChip(DUH *duh)
//
//==========================================================================
MusInfo *MOD_OpenSong(FILE *file, BYTE *musiccache, int size)
MusInfo *MOD_OpenSong(FileReader &reader)
{
DUH *duh = 0;
int headsize;
@ -777,40 +771,36 @@ MusInfo *MOD_OpenSong(FILE *file, BYTE *musiccache, int size)
atterm(dumb_exit);
int size = reader.GetLength();
fpos = reader.Tell();
filestate.ptr = start;
filestate.offset = 0;
headsize = MIN((int)sizeof(start), size);
if (musiccache != NULL)
{
memcpy(start, musiccache, headsize);
}
else
{
fpos = ftell(file);
if ((size_t)headsize != fread(start, 1, headsize, file))
if (headsize != reader.Read(start, headsize))
{
return NULL;
}
}
if (size >= 4 && dstart[0] == MAKE_ID('I','M','P','M'))
{
is_it = true;
if ((f = dumb_read_allfile(&filestate, start, file, musiccache, headsize, size)))
if ((f = dumb_read_allfile(&filestate, start, reader, headsize, size)))
{
duh = dumb_read_it_quick(f);
}
}
else if (size >= 17 && !memcmp(start, "Extended Module: ", 17))
{
if ((f = dumb_read_allfile(&filestate, start, file, musiccache, headsize, size)))
if ((f = dumb_read_allfile(&filestate, start, reader, headsize, size)))
{
duh = dumb_read_xm_quick(f);
}
}
else if (size >= 0x30 && dstart[11] == MAKE_ID('S','C','R','M'))
{
if ((f = dumb_read_allfile(&filestate, start, file, musiccache, headsize, size)))
if ((f = dumb_read_allfile(&filestate, start, reader, headsize, size)))
{
duh = dumb_read_s3m_quick(f);
}
@ -821,7 +811,7 @@ MusInfo *MOD_OpenSong(FILE *file, BYTE *musiccache, int size)
!memcmp( &start[20], "BMOD2STM", 8 ) ||
!memcmp( &start[20], "WUZAMOD!", 8 ) ) )
{
if ((f = dumb_read_allfile(&filestate, start, file, musiccache, headsize, size)))
if ((f = dumb_read_allfile(&filestate, start, reader, headsize, size)))
{
duh = dumb_read_stm_quick(f);
}
@ -830,21 +820,21 @@ MusInfo *MOD_OpenSong(FILE *file, BYTE *musiccache, int size)
((start[0] == 0x69 && start[1] == 0x66) ||
(start[0] == 0x4A && start[1] == 0x4E)))
{
if ((f = dumb_read_allfile(&filestate, start, file, musiccache, headsize, size)))
if ((f = dumb_read_allfile(&filestate, start, reader, headsize, size)))
{
duh = dumb_read_669_quick(f);
}
}
else if (size >= 0x30 && dstart[11] == MAKE_ID('P','T','M','F'))
{
if ((f = dumb_read_allfile(&filestate, start, file, musiccache, headsize, size)))
if ((f = dumb_read_allfile(&filestate, start, reader, headsize, size)))
{
duh = dumb_read_ptm_quick(f);
}
}
else if (size >= 4 && dstart[0] == MAKE_ID('P','S','M',' '))
{
if ((f = dumb_read_allfile(&filestate, start, file, musiccache, headsize, size)))
if ((f = dumb_read_allfile(&filestate, start, reader, headsize, size)))
{
duh = dumb_read_psm_quick(f, 0/*start_order*/);
/*start_order = 0;*/
@ -852,14 +842,14 @@ MusInfo *MOD_OpenSong(FILE *file, BYTE *musiccache, int size)
}
else if (size >= 4 && dstart[0] == (DWORD)MAKE_ID('P','S','M',254))
{
if ((f = dumb_read_allfile(&filestate, start, file, musiccache, headsize, size)))
if ((f = dumb_read_allfile(&filestate, start, reader, headsize, size)))
{
duh = dumb_read_old_psm_quick(f);
}
}
else if (size >= 3 && start[0] == 'M' && start[1] == 'T' && start[2] == 'M')
{
if ((f = dumb_read_allfile(&filestate, start, file, musiccache, headsize, size)))
if ((f = dumb_read_allfile(&filestate, start, reader, headsize, size)))
{
duh = dumb_read_mtm_quick(f);
}
@ -869,7 +859,7 @@ MusInfo *MOD_OpenSong(FILE *file, BYTE *musiccache, int size)
dstart[2] == MAKE_ID('A','M',' ',' ') ||
dstart[2] == MAKE_ID('A','M','F','F')))
{
if ((f = dumb_read_allfile(&filestate, start, file, musiccache, headsize, size)))
if ((f = dumb_read_allfile(&filestate, start, reader, headsize, size)))
{
duh = dumb_read_riff_quick(f);
}
@ -878,7 +868,7 @@ MusInfo *MOD_OpenSong(FILE *file, BYTE *musiccache, int size)
!memcmp( start, "ASYLUM Music Format", 19 ) &&
!memcmp( start + 19, " V1.0", 5 ) )
{
if ((f = dumb_read_allfile(&filestate, start, file, musiccache, headsize, size)))
if ((f = dumb_read_allfile(&filestate, start, reader, headsize, size)))
{
duh = dumb_read_asy_quick(f);
}
@ -887,7 +877,7 @@ MusInfo *MOD_OpenSong(FILE *file, BYTE *musiccache, int size)
dstart[0] == MAKE_ID('O','K','T','A') &&
dstart[1] == MAKE_ID('S','O','N','G'))
{
if ((f = dumb_read_allfile(&filestate, start, file, musiccache, headsize, size)))
if ((f = dumb_read_allfile(&filestate, start, reader, headsize, size)))
{
duh = dumb_read_okt_quick(f);
}
@ -898,12 +888,9 @@ MusInfo *MOD_OpenSong(FILE *file, BYTE *musiccache, int size)
is_dos = false;
if (filestate.ptr == (BYTE *)start)
{
if (!(f = dumb_read_allfile(&filestate, start, file, musiccache, headsize, size)))
if (!(f = dumb_read_allfile(&filestate, start, reader, headsize, size)))
{
if (file != NULL)
{
fseek(file, fpos, SEEK_SET);
}
reader.Seek(fpos, SEEK_SET);
return NULL;
}
}
@ -914,8 +901,8 @@ MusInfo *MOD_OpenSong(FILE *file, BYTE *musiccache, int size)
// No way to get the filename, so we can't check for a .mod extension, and
// therefore, trying to load an old 15-instrument SoundTracker module is not
// safe. We'll restrict MOD loading to 31-instrument modules with known
// signatures and let FMOD worry about 15-instrument ones. (Assuming it even
// supports them; I have not checked.)
// signatures and let the sound system worry about 15-instrument ones.
// (Assuming it even supports them)
duh = dumb_read_mod_quick(f, TRUE);
}
@ -944,12 +931,9 @@ MusInfo *MOD_OpenSong(FILE *file, BYTE *musiccache, int size)
else
{
// Reposition file pointer for other codecs to do their checks.
if (file != NULL)
{
fseek(file, fpos, SEEK_SET);
reader.Seek(fpos, SEEK_SET);
}
}
if (filestate.ptr != (BYTE *)start && filestate.ptr != musiccache)
if (filestate.ptr != (BYTE *)start)
{
delete[] const_cast<BYTE *>(filestate.ptr);
}

View file

@ -42,6 +42,7 @@
#include "critsec.h"
#include <gme/gme.h>
#include "v_text.h"
#include "files.h"
// MACROS ------------------------------------------------------------------
@ -104,7 +105,7 @@ const char *GME_CheckFormat(uint32 id)
//
//==========================================================================
MusInfo *GME_OpenSong(FILE *file, BYTE *musiccache, int len, const char *fmt)
MusInfo *GME_OpenSong(FileReader &reader, const char *fmt)
{
gme_type_t type;
gme_err_t err;
@ -123,29 +124,26 @@ MusInfo *GME_OpenSong(FILE *file, BYTE *musiccache, int len, const char *fmt)
{
return NULL;
}
if (musiccache != NULL)
{
song = musiccache;
}
else
{
int fpos = reader.Tell();
int len = reader.GetLength();
song = new BYTE[len];
if (fread(song, 1, len, file) != (size_t)len)
if (reader.Read(song, len) != len)
{
delete[] song;
gme_delete(emu);
reader.Seek(fpos, SEEK_SET);
return NULL;
}
}
err = gme_load_data(emu, song, len);
if (song != musiccache)
{
delete[] song;
}
if (err != NULL)
{
Printf("Failed loading song: %s\n", err);
gme_delete(emu);
reader.Seek(fpos, SEEK_SET);
return NULL;
}
return new GMESong(emu, sample_rate);

View file

@ -38,6 +38,7 @@
#include "templates.h"
#include "doomdef.h"
#include "m_swap.h"
#include "files.h"
// MACROS ------------------------------------------------------------------
@ -127,7 +128,7 @@ extern char MIDI_CommonLengths[15];
//
//==========================================================================
HMISong::HMISong (FILE *file, BYTE *musiccache, int len, EMidiDevice type)
HMISong::HMISong (FileReader &reader, EMidiDevice type)
: MIDIStreamer(type), MusHeader(0), Tracks(0)
{
#ifdef _WIN32
@ -136,6 +137,7 @@ HMISong::HMISong (FILE *file, BYTE *musiccache, int len, EMidiDevice type)
return;
}
#endif
int len = reader.GetLength();
if (len < 0x100)
{ // Way too small to be HMI.
return;
@ -143,15 +145,8 @@ HMISong::HMISong (FILE *file, BYTE *musiccache, int len, EMidiDevice type)
MusHeader = new BYTE[len];
SongLen = len;
NumTracks = 0;
if (file != NULL)
{
if (fread(MusHeader, 1, len, file) != (size_t)len)
if (reader.Read(MusHeader, len) != len)
return;
}
else
{
memcpy(MusHeader, musiccache, len);
}
// Do some validation of the MIDI file
if (memcmp(MusHeader, HMI_SONG_MAGIC, sizeof(HMI_SONG_MAGIC)) == 0)

View file

@ -33,7 +33,7 @@ static void AddDefaultMidiDevices(FOptionValues *opt)
pair[p+1].Value = -3.0;
pair[p+2].Text = "TiMidity++";
pair[p+2].Value = -2.0;
pair[p+3].Text = "FMOD";
pair[p+3].Text = "Sound System";
pair[p+3].Value = -1.0;
}
@ -172,7 +172,7 @@ CCMD (snd_listmididevices)
PrintMidiDevice (-4, "Gravis Ultrasound Emulation", MOD_SWSYNTH, 0);
PrintMidiDevice (-3, "Emulated OPL FM Synth", MOD_FMSYNTH, 0);
PrintMidiDevice (-2, "TiMidity++", MOD_SWSYNTH, 0);
PrintMidiDevice (-1, "FMOD", MOD_SWSYNTH, 0);
PrintMidiDevice (-1, "Sound System", 0, 0);
if (nummididevices != 0)
{
for (id = 0; id < nummididevices; ++id)
@ -217,6 +217,6 @@ CCMD (snd_listmididevices)
Printf("%s-4. Gravis Ultrasound Emulation\n", -4 == snd_mididevice ? TEXTCOLOR_BOLD : "");
Printf("%s-3. Emulated OPL FM Synth\n", -3 == snd_mididevice ? TEXTCOLOR_BOLD : "");
Printf("%s-2. TiMidity++\n", -2 == snd_mididevice ? TEXTCOLOR_BOLD : "");
Printf("%s-1. FMOD\n", -1 == snd_mididevice ? TEXTCOLOR_BOLD : "");
Printf("%s-1. Sound System\n", -1 == snd_mididevice ? TEXTCOLOR_BOLD : "");
}
#endif

View file

@ -611,7 +611,7 @@ int TimidityPPMIDIDevice::Resume()
{
if (LaunchTimidity())
{
// Assume success if not mixing with FMOD
// Assume success if not mixing with the sound system
if (Stream == NULL || Stream->Play(true, timidity_mastervolume))
{
Started = true;

View file

@ -215,13 +215,13 @@ EMidiDevice MIDIStreamer::SelectMIDIDevice(EMidiDevice device)
- if explicitly selected by $mididevice
- when snd_mididevice is -2 and no midi device is set for the song
- FMod:
- Sound System:
- if explicitly selected by $mididevice
- when snd_mididevice is -1 and no midi device is set for the song
- as fallback when both OPL and Timidity failed unless snd_mididevice is >= 0
- MMAPI (Win32 only):
- if explicitly selected by $mididevice (non-Win32 redirects this to FMOD)
- if explicitly selected by $mididevice (non-Win32 redirects this to Sound System)
- when snd_mididevice is >= 0 and no midi device is set for the song
- as fallback when both OPL and Timidity failed and snd_mididevice is >= 0
*/
@ -233,7 +233,7 @@ EMidiDevice MIDIStreamer::SelectMIDIDevice(EMidiDevice device)
}
switch (snd_mididevice)
{
case -1: return MDEV_FMOD;
case -1: return MDEV_SNDSYS;
case -2: return MDEV_TIMIDITY;
case -3: return MDEV_OPL;
case -4: return MDEV_GUS;
@ -244,7 +244,7 @@ EMidiDevice MIDIStreamer::SelectMIDIDevice(EMidiDevice device)
#ifdef _WIN32
return MDEV_MMAPI;
#else
return MDEV_FMOD;
return MDEV_SNDSYS;
#endif
}
}
@ -271,8 +271,8 @@ MIDIDevice *MIDIStreamer::CreateMIDIDevice(EMidiDevice devtype) const
return new FluidSynthMIDIDevice;
#endif
case MDEV_FMOD:
return new FMODMIDIDevice;
case MDEV_SNDSYS:
return new SndSysMIDIDevice;
case MDEV_GUS:
return new TimidityMIDIDevice;
@ -285,8 +285,8 @@ MIDIDevice *MIDIStreamer::CreateMIDIDevice(EMidiDevice devtype) const
catch (CRecoverableError &err)
{
// The creation of an OPL MIDI device can abort with an error if no GENMIDI lump can be found.
Printf("Unable to create OPL MIDI device: %s\nFalling back to FModEx playback", err.GetMessage());
return new FMODMIDIDevice;
Printf("Unable to create OPL MIDI device: %s\nFalling back to Sound System playback", err.GetMessage());
return new SndSysMIDIDevice;
}
case MDEV_TIMIDITY:

View file

@ -42,6 +42,7 @@
#include "templates.h"
#include "doomdef.h"
#include "m_swap.h"
#include "files.h"
// MACROS ------------------------------------------------------------------
@ -91,7 +92,7 @@ static const BYTE CtrlTranslate[15] =
//
//==========================================================================
MUSSong2::MUSSong2 (FILE *file, BYTE *musiccache, int len, EMidiDevice type)
MUSSong2::MUSSong2 (FileReader &reader, EMidiDevice type)
: MIDIStreamer(type), MusHeader(0), MusBuffer(0)
{
#ifdef _WIN32
@ -104,11 +105,7 @@ MUSSong2::MUSSong2 (FILE *file, BYTE *musiccache, int len, EMidiDevice type)
BYTE front[32];
int start;
if (file == NULL)
{
memcpy(front, musiccache, sizeof(front));
}
else if (fread(front, 1, sizeof(front), file) != sizeof(front))
if (reader.Read(front, sizeof(front)) != sizeof(front))
{
return;
}
@ -124,24 +121,17 @@ MUSSong2::MUSSong2 (FILE *file, BYTE *musiccache, int len, EMidiDevice type)
}
// Read the remainder of the song.
len = int(len - start);
int len = int(reader.GetLength() - start);
if (len < (int)sizeof(MusHeader))
{ // It's too short.
return;
}
MusHeader = (MUSHeader *)new BYTE[len];
if (file == NULL)
{
memcpy(MusHeader, musiccache + start, len);
}
else
{
memcpy(MusHeader, front + start, sizeof(front) - start);
if (fread((BYTE *)MusHeader + sizeof(front) - start, 1, len - (sizeof(front) - start), file) != (size_t)(len - (32 - start)))
if (reader.Read((BYTE *)MusHeader + sizeof(front) - start, len - (sizeof(front) - start)) != (len - (32 - start)))
{
return;
}
}
// Do some validation of the MUS file.
if (LittleShort(MusHeader->NumChans) > 15)

View file

@ -22,11 +22,11 @@ CUSTOM_CVAR (Int, opl_numchips, 2, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CVAR(Int, opl_core, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
OPLMUSSong::OPLMUSSong (FILE *file, BYTE *musiccache, int len)
OPLMUSSong::OPLMUSSong (FileReader &reader)
{
int samples = int(OPL_SAMPLE_RATE / 14);
Music = new OPLmusicFile (file, musiccache, len);
Music = new OPLmusicFile (&reader);
m_Stream = GSnd->CreateStream (FillStream, samples*4,
(opl_core == 0 ? SoundStream::Mono : 0) | SoundStream::Float, int(OPL_SAMPLE_RATE), this);

View file

@ -38,6 +38,7 @@
#include "templates.h"
#include "doomdef.h"
#include "m_swap.h"
#include "files.h"
// MACROS ------------------------------------------------------------------
@ -234,29 +235,30 @@ FString PseudoMIDIDevice::GetStats()
//==========================================================================
//
// FMODMIDIDevice :: Open
// SndSysMIDIDevice :: Open
//
//==========================================================================
int FMODMIDIDevice::Open(void (*callback)(unsigned int, void *, DWORD, DWORD), void *userdata)
int SndSysMIDIDevice::Open(void (*callback)(unsigned int, void *, DWORD, DWORD), void *userdata)
{
return 0;
}
//==========================================================================
//
// FMODMIDIDevice :: Preprocess
// SndSysMIDIDevice :: Preprocess
//
// Create a standard MIDI file and stream it.
//
//==========================================================================
bool FMODMIDIDevice::Preprocess(MIDIStreamer *song, bool looping)
bool SndSysMIDIDevice::Preprocess(MIDIStreamer *song, bool looping)
{
TArray<BYTE> midi;
MemoryArrayReader *reader = new MemoryArrayReader(NULL, 0);
song->CreateSMF(reader->GetArray(), looping ? 0 : 1);
reader->UpdateLength();
song->CreateSMF(midi, looping ? 0 : 1);
bLooping = looping;
Stream = GSnd->OpenStream((char *)&midi[0], looping ? SoundStream::Loop : 0, -1, midi.Size());
Stream = GSnd->OpenStream(reader, looping ? SoundStream::Loop : 0);
return false;
}

View file

@ -41,6 +41,7 @@
#include "templates.h"
#include "doomdef.h"
#include "m_swap.h"
#include "files.h"
// MACROS ------------------------------------------------------------------
@ -101,7 +102,7 @@ char MIDI_CommonLengths[15] = { 0, 1, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
//
//==========================================================================
MIDISong2::MIDISong2 (FILE *file, BYTE *musiccache, int len, EMidiDevice type)
MIDISong2::MIDISong2 (FileReader &reader, EMidiDevice type)
: MIDIStreamer(type), MusHeader(0), Tracks(0)
{
int p;
@ -113,17 +114,10 @@ MIDISong2::MIDISong2 (FILE *file, BYTE *musiccache, int len, EMidiDevice type)
return;
}
#endif
MusHeader = new BYTE[len];
SongLen = len;
if (file != NULL)
{
if (fread(MusHeader, 1, len, file) != (size_t)len)
SongLen = reader.GetLength();
MusHeader = new BYTE[SongLen];
if (reader.Read(MusHeader, SongLen) != SongLen)
return;
}
else
{
memcpy(MusHeader, musiccache, len);
}
// Do some validation of the MIDI file
if (MusHeader[4] != 0 || MusHeader[5] != 0 || MusHeader[6] != 0 || MusHeader[7] != 6)
@ -153,7 +147,7 @@ MIDISong2::MIDISong2 (FILE *file, BYTE *musiccache, int len, EMidiDevice type)
Tracks = new TrackInfo[NumTracks];
// Gather information about each track
for (i = 0, p = 14; i < NumTracks && p < len + 8; ++i)
for (i = 0, p = 14; i < NumTracks && p < SongLen + 8; ++i)
{
DWORD chunkLen =
(MusHeader[p+4]<<24) |
@ -161,9 +155,9 @@ MIDISong2::MIDISong2 (FILE *file, BYTE *musiccache, int len, EMidiDevice type)
(MusHeader[p+6]<<8) |
(MusHeader[p+7]);
if (chunkLen + p + 8 > (DWORD)len)
if (chunkLen + p + 8 > (DWORD)SongLen)
{ // Track too long, so truncate it
chunkLen = len - p - 8;
chunkLen = SongLen - p - 8;
}
if (MusHeader[p+0] == 'M' &&

View file

@ -52,9 +52,14 @@ StreamSong::~StreamSong ()
}
}
StreamSong::StreamSong (const char *filename_or_data, int offset, int len)
StreamSong::StreamSong (FileReader *reader)
{
m_Stream = GSnd->OpenStream (filename_or_data, SoundStream::Loop, offset, len);
m_Stream = GSnd->OpenStream (reader, SoundStream::Loop);
}
StreamSong::StreamSong (const char *url)
{
m_Stream = GSnd->OpenStream (url, SoundStream::Loop);
}
bool StreamSong::IsPlaying ()

View file

@ -38,6 +38,7 @@
#include "templates.h"
#include "doomdef.h"
#include "m_swap.h"
#include "files.h"
// MACROS ------------------------------------------------------------------
@ -107,7 +108,7 @@ extern char MIDI_CommonLengths[15];
//
//==========================================================================
XMISong::XMISong (FILE *file, BYTE *musiccache, int len, EMidiDevice type)
XMISong::XMISong (FileReader &reader, EMidiDevice type)
: MIDIStreamer(type), MusHeader(0), Songs(0)
{
#ifdef _WIN32
@ -116,20 +117,13 @@ XMISong::XMISong (FILE *file, BYTE *musiccache, int len, EMidiDevice type)
return;
}
#endif
MusHeader = new BYTE[len];
SongLen = len;
if (file != NULL)
{
if (fread(MusHeader, 1, len, file) != (size_t)len)
SongLen = reader.GetLength();
MusHeader = new BYTE[SongLen];
if (reader.Read(MusHeader, SongLen) != SongLen)
return;
}
else
{
memcpy(MusHeader, musiccache, len);
}
// Find all the songs in this file.
NumSongs = FindXMIDforms(MusHeader, len, NULL);
NumSongs = FindXMIDforms(MusHeader, SongLen, NULL);
if (NumSongs == 0)
{
return;
@ -147,7 +141,7 @@ XMISong::XMISong (FILE *file, BYTE *musiccache, int len, EMidiDevice type)
Songs = new TrackInfo[NumSongs];
memset(Songs, 0, sizeof(*Songs) * NumSongs);
FindXMIDforms(MusHeader, len, Songs);
FindXMIDforms(MusHeader, SongLen, Songs);
CurrSong = Songs;
DPrintf("XMI song count: %d\n", NumSongs);
}

1973
src/sound/oalsound.cpp Normal file

File diff suppressed because it is too large Load diff

211
src/sound/oalsound.h Normal file
View file

@ -0,0 +1,211 @@
#ifndef OALSOUND_H
#define OALSOUND_H
#include "i_sound.h"
#include "s_sound.h"
#include "menu/menu.h"
#ifndef NO_OPENAL
#include "al.h"
#include "alc.h"
#ifndef ALC_ENUMERATE_ALL_EXT
#define ALC_ENUMERATE_ALL_EXT 1
#define ALC_DEFAULT_ALL_DEVICES_SPECIFIER 0x1012
#define ALC_ALL_DEVICES_SPECIFIER 0x1013
#endif
#ifndef ALC_EXT_disconnect
#define ALC_EXT_disconnect 1
#define ALC_CONNECTED 0x313
#endif
#ifndef AL_EXT_source_distance_model
#define AL_EXT_source_distance_model 1
#define AL_SOURCE_DISTANCE_MODEL 0x200
#endif
#ifndef AL_SOFT_loop_points
#define AL_SOFT_loop_points 1
#define AL_LOOP_POINTS_SOFT 0x2015
#endif
#ifndef AL_EXT_float32
#define AL_EXT_float32 1
#define AL_FORMAT_MONO_FLOAT32 0x10010
#define AL_FORMAT_STEREO_FLOAT32 0x10011
#endif
#ifndef AL_EXT_MCFORMATS
#define AL_EXT_MCFORMATS 1
#define AL_FORMAT_QUAD8 0x1204
#define AL_FORMAT_QUAD16 0x1205
#define AL_FORMAT_QUAD32 0x1206
#define AL_FORMAT_REAR8 0x1207
#define AL_FORMAT_REAR16 0x1208
#define AL_FORMAT_REAR32 0x1209
#define AL_FORMAT_51CHN8 0x120A
#define AL_FORMAT_51CHN16 0x120B
#define AL_FORMAT_51CHN32 0x120C
#define AL_FORMAT_61CHN8 0x120D
#define AL_FORMAT_61CHN16 0x120E
#define AL_FORMAT_61CHN32 0x120F
#define AL_FORMAT_71CHN8 0x1210
#define AL_FORMAT_71CHN16 0x1211
#define AL_FORMAT_71CHN32 0x1212
#endif
#include "efx.h"
class OpenALSoundStream;
class OpenALSoundRenderer : public SoundRenderer
{
public:
OpenALSoundRenderer();
virtual ~OpenALSoundRenderer();
virtual void SetSfxVolume(float volume);
virtual void SetMusicVolume(float volume);
virtual SoundHandle LoadSound(BYTE *sfxdata, int length);
virtual SoundHandle LoadSoundRaw(BYTE *sfxdata, int length, int frequency, int channels, int bits, int loopstart, int loopend = -1);
virtual void UnloadSound(SoundHandle sfx);
virtual unsigned int GetMSLength(SoundHandle sfx);
virtual unsigned int GetSampleLength(SoundHandle sfx);
virtual float GetOutputRate();
// Streaming sounds.
virtual SoundStream *CreateStream(SoundStreamCallback callback, int buffbytes, int flags, int samplerate, void *userdata);
virtual SoundStream *OpenStream(FileReader *reader, int flags);
// Starts a sound.
virtual FISoundChannel *StartSound(SoundHandle sfx, float vol, int pitch, int chanflags, FISoundChannel *reuse_chan);
virtual FISoundChannel *StartSound3D(SoundHandle sfx, SoundListener *listener, float vol, FRolloffInfo *rolloff, float distscale, int pitch, int priority, const FVector3 &pos, const FVector3 &vel, int channum, int chanflags, FISoundChannel *reuse_chan);
// Changes a channel's volume.
virtual void ChannelVolume(FISoundChannel *chan, float volume);
// Stops a sound channel.
virtual void StopChannel(FISoundChannel *chan);
// Returns position of sound on this channel, in samples.
virtual unsigned int GetPosition(FISoundChannel *chan);
// Synchronizes following sound startups.
virtual void Sync(bool sync);
// Pauses or resumes all sound effect channels.
virtual void SetSfxPaused(bool paused, int slot);
// Pauses or resumes *every* channel, including environmental reverb.
virtual void SetInactive(SoundRenderer::EInactiveState inactive);
// Updates the volume, separation, and pitch of a sound channel.
virtual void UpdateSoundParams3D(SoundListener *listener, FISoundChannel *chan, bool areasound, const FVector3 &pos, const FVector3 &vel);
virtual void UpdateListener(SoundListener *);
virtual void UpdateSounds();
virtual void UpdateMusic();
virtual void MarkStartTime(FISoundChannel*);
virtual float GetAudibility(FISoundChannel*);
virtual bool IsValid();
virtual void PrintStatus();
virtual void PrintDriversList();
virtual FString GatherStats();
private:
struct {
bool EXT_EFX;
bool EXT_disconnect;
} ALC;
struct {
bool EXT_source_distance_model;
bool SOFT_deferred_updates;
bool SOFT_loop_points;
} AL;
// EFX Extension function pointer variables. Loaded after context creation
// if EFX is supported. These pointers may be context- or device-dependant,
// thus can't be static
// Effect objects
LPALGENEFFECTS alGenEffects;
LPALDELETEEFFECTS alDeleteEffects;
LPALISEFFECT alIsEffect;
LPALEFFECTI alEffecti;
LPALEFFECTIV alEffectiv;
LPALEFFECTF alEffectf;
LPALEFFECTFV alEffectfv;
LPALGETEFFECTI alGetEffecti;
LPALGETEFFECTIV alGetEffectiv;
LPALGETEFFECTF alGetEffectf;
LPALGETEFFECTFV alGetEffectfv;
// Filter objects
LPALGENFILTERS alGenFilters;
LPALDELETEFILTERS alDeleteFilters;
LPALISFILTER alIsFilter;
LPALFILTERI alFilteri;
LPALFILTERIV alFilteriv;
LPALFILTERF alFilterf;
LPALFILTERFV alFilterfv;
LPALGETFILTERI alGetFilteri;
LPALGETFILTERIV alGetFilteriv;
LPALGETFILTERF alGetFilterf;
LPALGETFILTERFV alGetFilterfv;
// Auxiliary slot objects
LPALGENAUXILIARYEFFECTSLOTS alGenAuxiliaryEffectSlots;
LPALDELETEAUXILIARYEFFECTSLOTS alDeleteAuxiliaryEffectSlots;
LPALISAUXILIARYEFFECTSLOT alIsAuxiliaryEffectSlot;
LPALAUXILIARYEFFECTSLOTI alAuxiliaryEffectSloti;
LPALAUXILIARYEFFECTSLOTIV alAuxiliaryEffectSlotiv;
LPALAUXILIARYEFFECTSLOTF alAuxiliaryEffectSlotf;
LPALAUXILIARYEFFECTSLOTFV alAuxiliaryEffectSlotfv;
LPALGETAUXILIARYEFFECTSLOTI alGetAuxiliaryEffectSloti;
LPALGETAUXILIARYEFFECTSLOTIV alGetAuxiliaryEffectSlotiv;
LPALGETAUXILIARYEFFECTSLOTF alGetAuxiliaryEffectSlotf;
LPALGETAUXILIARYEFFECTSLOTFV alGetAuxiliaryEffectSlotfv;
ALvoid (AL_APIENTRY*alDeferUpdatesSOFT)(void);
ALvoid (AL_APIENTRY*alProcessUpdatesSOFT)(void);
void LoadReverb(const ReverbContainer *env);
void PurgeStoppedSources();
static FSoundChan *FindLowestChannel();
ALCdevice *Device;
ALCcontext *Context;
TArray<ALuint> Sources;
ALfloat SfxVolume;
ALfloat MusicVolume;
int SFXPaused;
TArray<ALuint> FreeSfx;
TArray<ALuint> PausableSfx;
TArray<ALuint> ReverbSfx;
TArray<ALuint> SfxGroup;
const ReverbContainer *PrevEnvironment;
typedef TMap<WORD,ALuint> EffectMap;
typedef TMapIterator<WORD,ALuint> EffectMapIter;
ALuint EnvSlot;
ALuint EnvFilters[2];
EffectMap EnvEffects;
bool WasInWater;
TArray<OpenALSoundStream*> Streams;
friend class OpenALSoundStream;
ALCdevice *InitDevice();
};
#endif // NO_OPENAL
#endif

View file

@ -0,0 +1,152 @@
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#define USE_WINDOWS_DWORD
#endif
#include "sndfile_decoder.h"
#include "templates.h"
#include "files.h"
#include "xs_Float.h"
#include "except.h"
#ifdef HAVE_SNDFILE
sf_count_t SndFileDecoder::file_get_filelen(void *user_data)
{
FileReader *reader = reinterpret_cast<SndFileDecoder*>(user_data)->Reader;
return reader->GetLength();
}
sf_count_t SndFileDecoder::file_seek(sf_count_t offset, int whence, void *user_data)
{
FileReader *reader = reinterpret_cast<SndFileDecoder*>(user_data)->Reader;
if(reader->Seek((long)offset, whence) != 0)
return -1;
return reader->Tell();
}
sf_count_t SndFileDecoder::file_read(void *ptr, sf_count_t count, void *user_data)
{
FileReader *reader = reinterpret_cast<SndFileDecoder*>(user_data)->Reader;
return reader->Read(ptr, (long)count);
}
sf_count_t SndFileDecoder::file_write(const void *ptr, sf_count_t count, void *user_data)
{
return -1;
}
sf_count_t SndFileDecoder::file_tell(void *user_data)
{
FileReader *reader = reinterpret_cast<SndFileDecoder*>(user_data)->Reader;
return reader->Tell();
}
SndFileDecoder::~SndFileDecoder()
{
if(SndFile)
sf_close(SndFile);
SndFile = 0;
}
bool SndFileDecoder::open(FileReader *reader)
{
__try
{
SF_VIRTUAL_IO sfio = { file_get_filelen, file_seek, file_read, file_write, file_tell };
Reader = reader;
SndFile = sf_open_virtual(&sfio, SFM_READ, &SndInfo, this);
if (SndFile)
{
if (SndInfo.channels == 1 || SndInfo.channels == 2)
return true;
sf_close(SndFile);
SndFile = 0;
}
}
__except (CheckException(GetExceptionCode()))
{
// this means that the delay loaded decoder DLL was not found.
}
return false;
}
void SndFileDecoder::getInfo(int *samplerate, ChannelConfig *chans, SampleType *type)
{
*samplerate = SndInfo.samplerate;
if(SndInfo.channels == 2)
*chans = ChannelConfig_Stereo;
else
*chans = ChannelConfig_Mono;
*type = SampleType_Int16;
}
size_t SndFileDecoder::read(char *buffer, size_t bytes)
{
short *out = (short*)buffer;
size_t frames = bytes / SndInfo.channels / 2;
size_t total = 0;
// It seems libsndfile has a bug with converting float samples from Vorbis
// to the 16-bit shorts we use, which causes some PCM samples to overflow
// and wrap, creating static. So instead, read the samples as floats and
// convert to short ourselves.
// Use a loop to convert a handful of samples at a time, avoiding a heap
// allocation for temporary storage. 64 at a time works, though maybe it
// could be more.
while(total < frames)
{
size_t todo = MIN<size_t>(frames-total, 64/SndInfo.channels);
float tmp[64];
size_t got = (size_t)sf_readf_float(SndFile, tmp, todo);
if(got < todo) frames = total + got;
for(size_t i = 0;i < got*SndInfo.channels;i++)
*out++ = (short)xs_CRoundToInt(clamp(tmp[i] * 32767.f, -32768.f, 32767.f));
total += got;
}
return total * SndInfo.channels * 2;
}
TArray<char> SndFileDecoder::readAll()
{
if(SndInfo.frames <= 0)
return SoundDecoder::readAll();
int framesize = 2 * SndInfo.channels;
TArray<char> output;
output.Resize((unsigned)(SndInfo.frames * framesize));
size_t got = read(&output[0], output.Size());
output.Resize(got);
return output;
}
bool SndFileDecoder::seek(size_t ms_offset)
{
size_t smp_offset = (size_t)((double)ms_offset / 1000. * SndInfo.samplerate);
if(sf_seek(SndFile, smp_offset, SEEK_SET) < 0)
return false;
return true;
}
size_t SndFileDecoder::getSampleOffset()
{
return (size_t)sf_seek(SndFile, 0, SEEK_CUR);
}
size_t SndFileDecoder::getSampleLength()
{
return (size_t)((SndInfo.frames > 0) ? SndInfo.frames : 0);
}
#endif

View file

@ -0,0 +1,44 @@
#ifndef SNDFILE_DECODER_H
#define SNDFILE_DECODER_H
#include "i_soundinternal.h"
#ifdef HAVE_SNDFILE
#include "sndfile.h"
struct SndFileDecoder : public SoundDecoder
{
virtual void getInfo(int *samplerate, ChannelConfig *chans, SampleType *type);
virtual size_t read(char *buffer, size_t bytes);
virtual TArray<char> readAll();
virtual bool seek(size_t ms_offset);
virtual size_t getSampleOffset();
virtual size_t getSampleLength();
SndFileDecoder() : SndFile(0) { }
virtual ~SndFileDecoder();
protected:
virtual bool open(FileReader *reader);
private:
SNDFILE *SndFile;
SF_INFO SndInfo;
FileReader *Reader;
static sf_count_t file_get_filelen(void *user_data);
static sf_count_t file_seek(sf_count_t offset, int whence, void *user_data);
static sf_count_t file_read(void *ptr, sf_count_t count, void *user_data);
static sf_count_t file_write(const void *ptr, sf_count_t count, void *user_data);
static sf_count_t file_tell(void *user_data);
// Make non-copyable
SndFileDecoder(const SndFileDecoder &rhs);
SndFileDecoder& operator=(const SndFileDecoder &rhs);
};
#endif
#endif /* SNDFILE_DECODER_H */

View file

@ -160,6 +160,17 @@ public:
return Array[Count-1];
}
unsigned int Find(const T& item) const
{
unsigned int i;
for(i = 0;i < Count;++i)
{
if(Array[i] == item)
break;
}
return i;
}
unsigned int Push (const T &item)
{
Grow (1);

View file

@ -1679,6 +1679,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RailAttack)
PARAM_FLOAT_OPT (driftspeed) { driftspeed = 1; }
PARAM_CLASS_OPT (spawnclass, AActor){ spawnclass = NULL; }
PARAM_FIXED_OPT (spawnofs_z) { spawnofs_z = 0; }
PARAM_INT_OPT (SpiralOffset) { SpiralOffset = 270; }
if (range == 0) range = 8192*FRACUNIT;
if (sparsity == 0) sparsity=1.0;
@ -1709,7 +1710,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RailAttack)
slope = pr_crailgun.Random2() * (spread_z / 255);
}
P_RailAttack (self, damage, spawnofs_xy, spawnofs_z, color1, color2, maxdiff, flags, pufftype, angle, slope, range, duration, sparsity, driftspeed, spawnclass);
P_RailAttack (self, damage, spawnofs_xy, spawnofs_z, color1, color2, maxdiff, flags, pufftype, angle, slope, range, duration, sparsity, driftspeed, spawnclass, SpiralOffset);
return 0;
}
@ -1745,6 +1746,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomRailgun)
PARAM_FLOAT_OPT (driftspeed) { driftspeed = 1; }
PARAM_CLASS_OPT (spawnclass, AActor){ spawnclass = NULL; }
PARAM_FIXED_OPT (spawnofs_z) { spawnofs_z = 0; }
PARAM_INT_OPT (SpiralOffset) { SpiralOffset = 270; }
if (range == 0) range = 8192*FRACUNIT;
if (sparsity == 0) sparsity = 1;
@ -1828,7 +1830,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomRailgun)
slopeoffset = pr_crailgun.Random2() * (spread_z / 255);
}
P_RailAttack (self, damage, spawnofs_xy, spawnofs_z, color1, color2, maxdiff, flags, pufftype, angleoffset, slopeoffset, range, duration, sparsity, driftspeed, spawnclass);
P_RailAttack (self, damage, spawnofs_xy, spawnofs_z, color1, color2, maxdiff, flags, pufftype, angleoffset, slopeoffset, range, duration, sparsity, driftspeed, spawnclass,SpiralOffset);
self->x = saved_x;
self->y = saved_y;
@ -4871,7 +4873,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_LineEffect)
if ((oldjunk.special = special)) // Linedef type
{
oldjunk.tag = tag; // Sector tag for linedef
P_TranslateLineDef(&junk, &oldjunk, false); // Turn into native type
P_TranslateLineDef(&junk, &oldjunk); // Turn into native type
res = !!P_ExecuteSpecial(junk.special, NULL, self, false, junk.args[0],
junk.args[1], junk.args[2], junk.args[3], junk.args[4]);
if (res && !(junk.flags & ML_REPEAT_SPECIAL)) // If only once,

View file

@ -333,6 +333,7 @@ bool DCanvas::ParseDrawTextureTags (FTexture *img, double x, double y, DWORD tag
int intval;
bool translationset = false;
bool virtBottom;
bool fillcolorset = false;
if (img == NULL || img->UseType == FTexture::TEX_Null)
{
@ -539,6 +540,7 @@ bool DCanvas::ParseDrawTextureTags (FTexture *img, double x, double y, DWORD tag
case DTA_FillColor:
parms->fillcolor = va_arg(tags, uint32);
fillcolorset = true;
break;
case DTA_Translation:
@ -711,7 +713,7 @@ bool DCanvas::ParseDrawTextureTags (FTexture *img, double x, double y, DWORD tag
if (parms->style.BlendOp == 255)
{
if (parms->fillcolor != ~0u)
if (fillcolorset)
{
if (parms->alphaChannel)
{

View file

@ -74,7 +74,7 @@ enum
DTA_DestWidth, // width of area to draw to
DTA_DestHeight, // height of area to draw to
DTA_Alpha, // alpha value for translucency
DTA_FillColor, // color to stencil onto the destination
DTA_FillColor, // color to stencil onto the destination (RGB is the color for truecolor drawers, A is the palette index for paletted drawers)
DTA_Translation, // translation table to recolor the source
DTA_AlphaChannel, // bool: the source is an alpha channel; used with DTA_FillColor
DTA_Clean, // bool: scale texture size and position by CleanXfac and CleanYfac

View file

@ -76,7 +76,7 @@ const char *GetVersionString();
// Use 4500 as the base git save version, since it's higher than the
// SVN revision ever got.
#define SAVEVER 4522
#define SAVEVER 4523
#define SAVEVERSTRINGIFY2(x) #x
#define SAVEVERSTRINGIFY(x) SAVEVERSTRINGIFY2(x)

View file

@ -1228,6 +1228,17 @@ FWadLump *FWadCollection::ReopenLumpNum (int lump)
return new FWadLump(LumpInfo[lump].lump, true);
}
FWadLump *FWadCollection::ReopenLumpNumNewFile (int lump)
{
if ((unsigned)lump >= (unsigned)LumpInfo.Size())
{
return NULL;
}
return new FWadLump(lump, LumpInfo[lump].lump);
}
//==========================================================================
//
// GetFileReader
@ -1417,6 +1428,34 @@ FWadLump::FWadLump(FResourceLump *lump, bool alwayscache)
}
}
FWadLump::FWadLump(int lumpnum, FResourceLump *lump)
: FileReader()
{
FileReader *f = lump->GetReader();
if (f != NULL && f->GetFile() != NULL)
{
// Uncompressed lump in a file. For this we will have to open a new FILE, since we need it for streaming
int fileno = Wads.GetLumpFile(lumpnum);
const char *filename = Wads.GetWadFullName(fileno);
File = fopen(filename, "rb");
if (File != NULL)
{
Length = lump->LumpSize;
StartPos = FilePos = lump->GetFileOffset();
Lump = NULL;
CloseOnDestruct = true;
Seek(0, SEEK_SET);
return;
}
}
File = NULL;
Length = lump->LumpSize;
StartPos = FilePos = 0;
Lump = lump;
Lump->CacheLump();
}
FWadLump::~FWadLump()
{
if (Lump != NULL)

View file

@ -112,6 +112,7 @@ public:
private:
FWadLump (FResourceLump *Lump, bool alwayscache = false);
FWadLump(int lumpnum, FResourceLump *lump);
FResourceLump *Lump;
@ -185,6 +186,7 @@ public:
FWadLump OpenLumpNum (int lump);
FWadLump OpenLumpName (const char *name) { return OpenLumpNum (GetNumForName (name)); }
FWadLump *ReopenLumpNum (int lump); // Opens a new, independent FILE
FWadLump *ReopenLumpNumNewFile (int lump); // Opens a new, independent FILE
FileReader * GetFileReader(int wadnum); // Gets a FileReader object to the entire WAD

View file

@ -1600,13 +1600,20 @@ unsigned int I_MakeRNGSeed()
FString I_GetLongPathName(FString shortpath)
{
DWORD buffsize = GetLongPathName(shortpath.GetChars(), NULL, 0);
static TOptWin32Proc<DWORD (WINAPI*)(LPCTSTR, LPTSTR, DWORD)>
GetLongPathNameA("kernel32.dll", "GetLongPathNameA");
// Doesn't exist on NT4
if (GetLongPathName == NULL)
return shortpath;
DWORD buffsize = GetLongPathNameA.Call(shortpath.GetChars(), NULL, 0);
if (buffsize == 0)
{ // nothing to change (it doesn't exist, maybe?)
return shortpath;
}
TCHAR *buff = new TCHAR[buffsize];
DWORD buffsize2 = GetLongPathName(shortpath.GetChars(), buff, buffsize);
DWORD buffsize2 = GetLongPathNameA.Call(shortpath.GetChars(), buff, buffsize);
if (buffsize2 >= buffsize)
{ // Failure! Just return the short path
delete[] buff;

View file

@ -51,6 +51,30 @@ typedef enum {
extern os_t OSPlatform;
// Helper template so that we can access newer Win32 functions with a single static
// variable declaration. If this were C++11 it could be totally transparent.
template<typename Proto>
class TOptWin32Proc
{
static Proto GetOptionalWin32Proc(const char* module, const char* function)
{
HMODULE hmodule = GetModuleHandle(module);
if (hmodule == NULL)
return NULL;
return (Proto)GetProcAddress(hmodule, function);
}
public:
const Proto Call;
TOptWin32Proc(const char* module, const char* function)
: Call(GetOptionalWin32Proc(module, function)) {}
// Wrapper object can be tested against NULL, but not directly called.
operator const void*() const { return Call; }
};
// Called by DoomMain.
void I_Init (void);

View file

@ -414,7 +414,10 @@ void Win32Video::DumpAdapters()
HMONITOR hm = D3D->GetAdapterMonitor(i);
MONITORINFOEX mi;
mi.cbSize = sizeof(mi);
if (GetMonitorInfo(hm, &mi))
TOptWin32Proc<BOOL(WINAPI*)(HMONITOR, LPMONITORINFO)> GetMonitorInfo("user32.dll", "GetMonitorInfoW");
assert(GetMonitorInfo != NULL); // Missing in NT4, but so is D3D
if (GetMonitorInfo.Call(hm, &mi))
{
mysnprintf(moreinfo, countof(moreinfo), " [%ldx%ld @ (%ld,%ld)]%s",
mi.rcMonitor.right - mi.rcMonitor.left,

View file

@ -178,7 +178,7 @@ ACTOR Actor native //: Thinker
action native A_Jump(int chance = 256, state label, ...);
action native A_CustomMissile(class<Actor> missiletype, float spawnheight = 32, int spawnofs_xy = 0, float angle = 0, int flags = 0, float pitch = 0, int ptr = AAPTR_TARGET);
action native A_CustomBulletAttack(float/*angle*/ spread_xy, float/*angle*/ spread_z, int numbullets, int damageperbullet, class<Actor> pufftype = "BulletPuff", float range = 0, int flags = 0, int ptr = AAPTR_TARGET);
action native A_CustomRailgun(int damage, int spawnofs_xy = 0, color color1 = "", color color2 = "", int flags = 0, int aim = 0, float maxdiff = 0, class<Actor> pufftype = "BulletPuff", float/*angle*/ spread_xy = 0, float/*angle*/ spread_z = 0, float range = 0, int duration = 0, float sparsity = 1.0, float driftspeed = 1.0, class<Actor> spawnclass = "none", float spawnofs_z = 0);
action native A_CustomRailgun(int damage, int spawnofs_xy = 0, color color1 = "", color color2 = "", int flags = 0, int aim = 0, float maxdiff = 0, class<Actor> pufftype = "BulletPuff", float/*angle*/ spread_xy = 0, float/*angle*/ spread_z = 0, float range = 0, int duration = 0, float sparsity = 1.0, float driftspeed = 1.0, class<Actor> spawnclass = "none", float spawnofs_z = 0, int spiraloffset = 270);
action native A_JumpIfHealthLower(int health, state label, int ptr_selector = AAPTR_DEFAULT);
action native A_JumpIfCloser(float distance, state label);
action native A_JumpIfTracerCloser(float distance, state label);

Some files were not shown because too many files have changed in this diff Show more