diff --git a/docs/rh-log.txt b/docs/rh-log.txt index 5a8c18b90..74ec05723 100644 --- a/docs/rh-log.txt +++ b/docs/rh-log.txt @@ -1,4 +1,14 @@ +July 4, 2008 +- Fixed: Screenwipes now pause sounds, since there can be sounds playing + during it. +- UI sounds are now omitted from savegames. +- Fixed: Menu sounds had been restricted to one at a time again. +- Moved the P_SerializeSounds() call to the end of G_SerializeLevel() so that + it will occur after the players are loaded. + July 2, 2008 +- Added fixes from FreeBSD for 0-length and very large string buffers + passed to myvsnprintf. - Rewrote myvsnprintf to use the StringFormat routines directly so that no additional memory needs to be allocated from the heap. diff --git a/src/d_main.cpp b/src/d_main.cpp index 9a8d54995..14771372a 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -688,6 +688,7 @@ void D_Display () int wipestart, nowtime, tics; bool done; + GSnd->SetSfxPaused(true, 1); screen->WipeEndScreen (); wipestart = I_GetTime (false); @@ -707,6 +708,7 @@ void D_Display () NetUpdate (); } while (!done); screen->WipeCleanup(); + GSnd->SetSfxPaused(false, 1); Net_WriteByte (DEM_WIPEOFF); } diff --git a/src/g_level.cpp b/src/g_level.cpp index 366b54aea..657faff5c 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -2819,7 +2819,6 @@ void G_SerializeLevel (FArchive &arc, bool hubLoad) P_SerializeThinkers (arc, hubLoad); P_SerializeWorld (arc); P_SerializePolyobjs (arc); - P_SerializeSounds (arc); StatusBar->Serialize (arc); //SerializeInterpolations (arc); @@ -2865,6 +2864,7 @@ void G_SerializeLevel (FArchive &arc, bool hubLoad) { P_SerializePlayers (arc); } + P_SerializeSounds (arc); } // Archives the current level diff --git a/src/m_menu.cpp b/src/m_menu.cpp index adf21135c..736fe671e 100644 --- a/src/m_menu.cpp +++ b/src/m_menu.cpp @@ -602,28 +602,28 @@ CCMD (menu_help) CCMD (quicksave) { // F6 //M_StartControlPanel (true); - S_Sound (CHAN_VOICE, "menu/activate", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/activate", 1, ATTN_NONE); M_QuickSave(); } CCMD (quickload) { // F9 //M_StartControlPanel (true); - S_Sound (CHAN_VOICE, "menu/activate", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/activate", 1, ATTN_NONE); M_QuickLoad(); } CCMD (menu_endgame) { // F7 //M_StartControlPanel (true); - S_Sound (CHAN_VOICE, "menu/activate", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/activate", 1, ATTN_NONE); M_EndGame(0); } CCMD (menu_quit) { // F10 //M_StartControlPanel (true); - S_Sound (CHAN_VOICE, "menu/activate", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/activate", 1, ATTN_NONE); M_QuitGame(0); } @@ -1380,7 +1380,7 @@ void M_QuickSaveResponse (int ch) if (ch == 'y') { M_DoSave (quickSaveSlot); - S_Sound (CHAN_VOICE, "menu/dismiss", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/dismiss", 1, ATTN_NONE); } } @@ -1388,7 +1388,7 @@ void M_QuickSave () { if (!usergame || (players[consoleplayer].health <= 0 && !multiplayer)) { - S_Sound (CHAN_VOICE, "menu/invalid", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/invalid", 1, ATTN_NONE); return; } @@ -1416,7 +1416,7 @@ void M_QuickLoadResponse (int ch) if (ch == 'y') { M_LoadSelect (quickSaveSlot); - S_Sound (CHAN_VOICE, "menu/dismiss", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/dismiss", 1, ATTN_NONE); } } @@ -1893,7 +1893,7 @@ void M_EndGame(int choice) choice = 0; if (!usergame) { - S_Sound (CHAN_VOICE, "menu/invalid", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/invalid", 1, ATTN_NONE); return; } @@ -1955,7 +1955,7 @@ void M_QuitResponse(int ch) { if (gameinfo.quitSound) { - S_Sound (CHAN_VOICE, gameinfo.quitSound, 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, gameinfo.quitSound, 1, ATTN_NONE); I_WaitVBL (105); } } @@ -2688,7 +2688,7 @@ void M_StartMessage (const char *string, void (*routine)(int), bool input) if (input) { S_StopSound (CHAN_VOICE); - S_Sound (CHAN_VOICE, "menu/prompt", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/prompt", 1, ATTN_NONE); } return; } @@ -2844,7 +2844,7 @@ bool M_Responder (event_t *ev) } SB_state = screen->GetPageCount (); // refresh the statbar BorderNeedRefresh = screen->GetPageCount (); - S_Sound (CHAN_VOICE, "menu/dismiss", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/dismiss", 1, ATTN_NONE); return true; } @@ -2871,7 +2871,7 @@ bool M_Responder (event_t *ev) if (itemOn+1 > currentMenu->numitems-1) itemOn = 0; else itemOn++; - S_Sound (CHAN_VOICE, "menu/cursor", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", 1, ATTN_NONE); } while(currentMenu->menuitems[itemOn].status==-1); return true; @@ -2881,7 +2881,7 @@ bool M_Responder (event_t *ev) if (!itemOn) itemOn = currentMenu->numitems-1; else itemOn--; - S_Sound (CHAN_VOICE, "menu/cursor", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", 1, ATTN_NONE); } while(currentMenu->menuitems[itemOn].status==-1); return true; @@ -2889,7 +2889,7 @@ bool M_Responder (event_t *ev) if (currentMenu->menuitems[itemOn].routine && currentMenu->menuitems[itemOn].status == 2) { - S_Sound (CHAN_VOICE, "menu/change", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", 1, ATTN_NONE); currentMenu->menuitems[itemOn].routine(0); } return true; @@ -2898,7 +2898,7 @@ bool M_Responder (event_t *ev) if (currentMenu->menuitems[itemOn].routine && currentMenu->menuitems[itemOn].status == 2) { - S_Sound (CHAN_VOICE, "menu/change", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", 1, ATTN_NONE); currentMenu->menuitems[itemOn].routine(1); } return true; @@ -2911,12 +2911,12 @@ bool M_Responder (event_t *ev) if (currentMenu->menuitems[itemOn].status == 2) { currentMenu->menuitems[itemOn].routine(1); // right arrow - S_Sound (CHAN_VOICE, "menu/change", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", 1, ATTN_NONE); } else { currentMenu->menuitems[itemOn].routine(itemOn); - S_Sound (CHAN_VOICE, "menu/choose", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/choose", 1, ATTN_NONE); } } return true; @@ -2945,7 +2945,7 @@ bool M_Responder (event_t *ev) if (currentMenu->menuitems[i].alphaKey == ch) { itemOn = i; - S_Sound (CHAN_VOICE, "menu/cursor", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", 1, ATTN_NONE); return true; } } @@ -3120,7 +3120,7 @@ void M_StartControlPanel (bool makeSound) if (makeSound) { - S_Sound (CHAN_VOICE, "menu/activate", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/activate", 1, ATTN_NONE); } } @@ -3354,12 +3354,12 @@ void M_PopMenuStack (void) } drawSkull = MenuStack[MenuStackDepth].drawSkull; ++MenuStackDepth; - S_Sound (CHAN_VOICE, "menu/backup", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/backup", 1, ATTN_NONE); } else { M_ClearMenus (); - S_Sound (CHAN_VOICE, "menu/clear", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/clear", 1, ATTN_NONE); } } diff --git a/src/m_options.cpp b/src/m_options.cpp index a914eb233..537988ab5 100644 --- a/src/m_options.cpp +++ b/src/m_options.cpp @@ -1472,13 +1472,13 @@ void M_SizeDisplay (int diff) CCMD (sizedown) { M_SizeDisplay (-1); - S_Sound (CHAN_VOICE, "menu/change", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", 1, ATTN_NONE); } CCMD (sizeup) { M_SizeDisplay (1); - S_Sound (CHAN_VOICE, "menu/change", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", 1, ATTN_NONE); } // Draws a string in the console font, scaled to the 8x8 cells @@ -2153,7 +2153,7 @@ void M_OptResponder (event_t *ev) CurrentMenu->items[CurrentItem].a.selmode = modecol; } - S_Sound (CHAN_VOICE, "menu/cursor", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", 1, ATTN_NONE); } break; @@ -2217,7 +2217,7 @@ void M_OptResponder (event_t *ev) if (CurrentMenu->items[CurrentItem].type == screenres) CurrentMenu->items[CurrentItem].a.selmode = modecol; - S_Sound (CHAN_VOICE, "menu/cursor", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", 1, ATTN_NONE); } break; @@ -2239,7 +2239,7 @@ void M_OptResponder (event_t *ev) { ++CurrentItem; } - S_Sound (CHAN_VOICE, "menu/cursor", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", 1, ATTN_NONE); } break; @@ -2262,7 +2262,7 @@ void M_OptResponder (event_t *ev) { ++CurrentItem; } - S_Sound (CHAN_VOICE, "menu/cursor", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", 1, ATTN_NONE); } break; @@ -2300,12 +2300,12 @@ void M_OptResponder (event_t *ev) else item->a.cvar->SetGenericRep (newval, CVAR_Float); } - S_Sound (CHAN_VOICE, "menu/change", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", 1, ATTN_NONE); break; case palettegrid: SelColorIndex = (SelColorIndex - 1) & 15; - S_Sound (CHAN_VOICE, "menu/cursor", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", 1, ATTN_NONE); break; case discretes: @@ -2335,14 +2335,14 @@ void M_OptResponder (event_t *ev) if (item->e.values == Depths) BuildModesList (SCREENWIDTH, SCREENHEIGHT, DisplayBits); } - S_Sound (CHAN_VOICE, "menu/change", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", 1, ATTN_NONE); break; case ediscrete: value = item->a.cvar->GetGenericRep(CVAR_String); value.String = const_cast(M_FindPrevVal(value.String, item->e.enumvalues, (int)item->b.numvalues)); item->a.cvar->SetGenericRep(value, CVAR_String); - S_Sound (CHAN_VOICE, "menu/change", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", 1, ATTN_NONE); break; case bitmask: @@ -2361,7 +2361,7 @@ void M_OptResponder (event_t *ev) value.Int = (value.Int & ~bmask) | int(item->e.values[cur].value); item->a.cvar->SetGenericRep (value, CVAR_Int); } - S_Sound (CHAN_VOICE, "menu/change", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", 1, ATTN_NONE); break; case discrete_guid: @@ -2376,14 +2376,14 @@ void M_OptResponder (event_t *ev) *(item->a.guidcvar) = item->e.guidvalues[cur].ID; } - S_Sound (CHAN_VOICE, "menu/change", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", 1, ATTN_NONE); break; case inverter: value = item->a.cvar->GetGenericRep (CVAR_Float); value.Float = -value.Float; item->a.cvar->SetGenericRep (value, CVAR_Float); - S_Sound (CHAN_VOICE, "menu/change", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", 1, ATTN_NONE); break; case screenres: @@ -2407,7 +2407,7 @@ void M_OptResponder (event_t *ev) item->a.selmode = col; } } - S_Sound (CHAN_VOICE, "menu/cursor", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", 1, ATTN_NONE); break; default: @@ -2449,12 +2449,12 @@ void M_OptResponder (event_t *ev) else item->a.cvar->SetGenericRep (newval, CVAR_Float); } - S_Sound (CHAN_VOICE, "menu/change", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", 1, ATTN_NONE); break; case palettegrid: SelColorIndex = (SelColorIndex + 1) & 15; - S_Sound (CHAN_VOICE, "menu/cursor", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", 1, ATTN_NONE); break; case discretes: @@ -2484,14 +2484,14 @@ void M_OptResponder (event_t *ev) if (item->e.values == Depths) BuildModesList (SCREENWIDTH, SCREENHEIGHT, DisplayBits); } - S_Sound (CHAN_VOICE, "menu/change", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", 1, ATTN_NONE); break; case ediscrete: value = item->a.cvar->GetGenericRep(CVAR_String); value.String = const_cast(M_FindNextVal(value.String, item->e.enumvalues, (int)item->b.numvalues)); item->a.cvar->SetGenericRep(value, CVAR_String); - S_Sound (CHAN_VOICE, "menu/change", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", 1, ATTN_NONE); break; case bitmask: @@ -2510,7 +2510,7 @@ void M_OptResponder (event_t *ev) value.Int = (value.Int & ~bmask) | int(item->e.values[cur].value); item->a.cvar->SetGenericRep (value, CVAR_Int); } - S_Sound (CHAN_VOICE, "menu/change", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", 1, ATTN_NONE); break; case discrete_guid: @@ -2525,14 +2525,14 @@ void M_OptResponder (event_t *ev) *(item->a.guidcvar) = item->e.guidvalues[cur].ID; } - S_Sound (CHAN_VOICE, "menu/change", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", 1, ATTN_NONE); break; case inverter: value = item->a.cvar->GetGenericRep (CVAR_Float); value.Float = -value.Float; item->a.cvar->SetGenericRep (value, CVAR_Float); - S_Sound (CHAN_VOICE, "menu/change", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", 1, ATTN_NONE); break; case screenres: @@ -2559,7 +2559,7 @@ void M_OptResponder (event_t *ev) item->a.selmode = col; } } - S_Sound (CHAN_VOICE, "menu/cursor", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", 1, ATTN_NONE); break; default: @@ -2617,7 +2617,7 @@ void M_OptResponder (event_t *ev) setmodeneeded = true; NewBits = BitTranslate[DummyDepthCvar]; } - S_Sound (CHAN_VOICE, "menu/choose", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/choose", 1, ATTN_NONE); SetModesMenu (NewWidth, NewHeight, NewBits); } else if ((item->type == more || @@ -2628,7 +2628,7 @@ void M_OptResponder (event_t *ev) && item->e.mfunc) { CurrentMenu->lastOn = CurrentItem; - S_Sound (CHAN_VOICE, "menu/choose", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/choose", 1, ATTN_NONE); if (item->type == safemore || item->type == rsafemore) { ActivateConfirm (item->label, item->e.mfunc); @@ -2663,7 +2663,7 @@ void M_OptResponder (event_t *ev) if (item->e.values == Depths) BuildModesList (SCREENWIDTH, SCREENHEIGHT, DisplayBits); - S_Sound (CHAN_VOICE, "menu/change", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", 1, ATTN_NONE); } else if (item->type == control) { @@ -2676,7 +2676,7 @@ void M_OptResponder (event_t *ev) else if (item->type == listelement) { CurrentMenu->lastOn = CurrentItem; - S_Sound (CHAN_VOICE, "menu/choose", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/choose", 1, ATTN_NONE); item->e.lfunc (CurrentItem); } else if (item->type == inverter) @@ -2684,7 +2684,7 @@ void M_OptResponder (event_t *ev) value = item->a.cvar->GetGenericRep (CVAR_Float); value.Float = -value.Float; item->a.cvar->SetGenericRep (value, CVAR_Float); - S_Sound (CHAN_VOICE, "menu/change", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", 1, ATTN_NONE); } else if (item->type == screenres) { @@ -2692,7 +2692,7 @@ void M_OptResponder (event_t *ev) else if (item->type == colorpicker) { CurrentMenu->lastOn = CurrentItem; - S_Sound (CHAN_VOICE, "menu/choose", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/choose", 1, ATTN_NONE); StartColorPickerMenu (item->label, item->a.colorcvar); } else if (item->type == palettegrid) @@ -2728,7 +2728,7 @@ void M_OptResponder (event_t *ev) NewBits = BitTranslate[DummyDepthCvar]; setmodeneeded = true; testingmode = I_GetTime(false) + 5 * TICRATE; - S_Sound (CHAN_VOICE, "menu/choose", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/choose", 1, ATTN_NONE); SetModesMenu (NewWidth, NewHeight, NewBits); } } diff --git a/src/p_tick.cpp b/src/p_tick.cpp index 05460ce94..5f1552965 100644 --- a/src/p_tick.cpp +++ b/src/p_tick.cpp @@ -31,6 +31,7 @@ #include "doomstat.h" #include "sbar.h" #include "r_interpolate.h" +#include "i_sound.h" extern gamestate_t wipegamestate; @@ -72,6 +73,13 @@ void P_Ticker (void) interpolator.UpdateInterpolations (); r_NoInterpolate = true; + if (!demoplayback) + { + // This is a separate slot from the wipe in D_Display(), because this + // is delayed slightly due to latency. (Even on a singleplayer game!) + GSnd->SetSfxPaused(!!playerswiping, 2); + } + // run the tic if (paused || (playerswiping && !demoplayback) || P_CheckTickerPaused()) return; diff --git a/src/s_sound.cpp b/src/s_sound.cpp index d990342a5..66c7e4bbc 100644 --- a/src/s_sound.cpp +++ b/src/s_sound.cpp @@ -117,6 +117,7 @@ static bool MusicPaused; // whether music is paused static MusPlayingInfo mus_playing; // music currently being played static FString LastSong; // last music that was played static FPlayList *PlayList; +static int RestartEvictionsAt; // do not restart evicted channels before this level.time // PUBLIC DATA DEFINITIONS ------------------------------------------------- @@ -670,13 +671,13 @@ static void CalcPosVel(int type, const AActor *actor, const sector_t *sector, case SOURCE_Unattached: pos->X = pt[0]; - pos->Y = !(chanflags & CHAN_LISTENERZ) ? pt[1] : FIXED2FLOAT(players[consoleplayer].camera->z); + pos->Y = !(chanflags & CHAN_LISTENERZ) ? pt[1] : FIXED2FLOAT(y); pos->Z = pt[2]; break; } if (type != SOURCE_Unattached) { - if (chanflags & CHAN_LISTENERZ) + if ((chanflags & CHAN_LISTENERZ) && players[consoleplayer].camera != NULL) { y = players[consoleplayer].camera != NULL ? players[consoleplayer].camera->z : 0; } @@ -932,7 +933,7 @@ static FSoundChan *S_StartSound(AActor *actor, const sector_t *sec, const FPolyO } // If this actor is already playing something on the selected channel, stop it. - if ((actor == NULL && channel != CHAN_AUTO) || (actor != NULL && actor->SoundChans & (1 << channel))) + if (type != SOURCE_None && (actor == NULL && channel != CHAN_AUTO) || (actor != NULL && actor->SoundChans & (1 << channel))) { for (chan = Channels; chan != NULL; chan = chan->NextChan) { @@ -942,7 +943,6 @@ static FSoundChan *S_StartSound(AActor *actor, const sector_t *sec, const FPolyO switch (type) { - case SOURCE_None: foundit = true; break; case SOURCE_Actor: foundit = (chan->Actor == actor); break; case SOURCE_Sector: foundit = (chan->Sector == sec); break; case SOURCE_Polyobj: foundit = (chan->Poly == poly); break; @@ -1453,7 +1453,7 @@ void S_PauseSound (bool notmusic) I_PauseSong (mus_playing.handle); MusicPaused = true; } - GSnd->SetSfxPaused (true); + GSnd->SetSfxPaused (true, 0); } //========================================================================== @@ -1470,7 +1470,7 @@ void S_ResumeSound () I_ResumeSong (mus_playing.handle); MusicPaused = false; } - GSnd->SetSfxPaused (false); + GSnd->SetSfxPaused (false, 0); } //========================================================================== @@ -1588,7 +1588,11 @@ void S_UpdateSounds (void *listener_p) GSnd->UpdateListener(); GSnd->UpdateSounds(); - S_RestoreEvictedChannels(); + if (level.time >= RestartEvictionsAt) + { + RestartEvictionsAt = 0; + S_RestoreEvictedChannels(); + } } //========================================================================== @@ -1668,8 +1672,9 @@ void S_SerializeSounds(FArchive &arc) for (chan = Channels; chan != NULL; chan = chan->NextChan) { // If the sound is forgettable, this is as good a time as - // any to forget about it. - if (!(chan->ChanFlags & CHAN_FORGETTABLE)) + // any to forget about it. And if it's a UI sound, it shouldn't + // be stored in the savegame. + if (!(chan->ChanFlags & (CHAN_FORGETTABLE | CHAN_UI))) { chans.Push(chan); } @@ -1697,9 +1702,16 @@ void S_SerializeSounds(FArchive &arc) chan = S_GetChannel(NULL); arc << *chan; // Sounds always start out evicted when restored from a save. - chan->ChanFlags |= CHAN_EVICTED; + chan->ChanFlags |= CHAN_EVICTED | CHAN_ABSTIME; } - S_RestoreEvictedChannels(); + // The two tic delay is to make sure any screenwipes have finished. + // This needs to be two because the game is run for one tic before + // the wipe so that it can produce a screen to wipe to. So if we + // only waited one tic to restart the sounds, they would start + // playing before the wipe, and depending on the synchronization + // between the main thread and the mixer thread at the time, the + // sounds might be heard briefly before pausing for the wipe. + RestartEvictionsAt = level.time + 2; } DSeqNode::SerializeSequences(arc); GSnd->Sync(false); diff --git a/src/s_sound.h b/src/s_sound.h index 3760aba74..4c5f5ec1f 100644 --- a/src/s_sound.h +++ b/src/s_sound.h @@ -263,9 +263,10 @@ void S_Sound (fixed_t x, fixed_t y, fixed_t z, int channel, FSoundID sfxid, floa #define CHAN_PICKUP (CHAN_ITEM|CHAN_MAYBE_LOCAL) #define CHAN_IS3D 1 // internal: Sound is 3D. -#define CHAN_EVICTED 2 // internal: Looping sound was evicted. -#define CHAN_FORGETTABLE 4 // internal: Forget sound data when sound stops. +#define CHAN_EVICTED 2 // internal: Sound was evicted. +#define CHAN_FORGETTABLE 4 // internal: Forget channel data when sound stops. #define CHAN_JUSTSTARTED 512 // internal: Sound has not been updated yet. +#define CHAN_ABSTIME 1024// internal: Start time is absolute and does not depend on current time. // sound attenuation values #define ATTN_NONE 0.f // full volume the entire level diff --git a/src/sound/fmodsound.cpp b/src/sound/fmodsound.cpp index cf231b5f2..89db82eaf 100644 --- a/src/sound/fmodsound.cpp +++ b/src/sound/fmodsound.cpp @@ -605,7 +605,7 @@ bool FMODSoundRenderer::Init() int eval; - SFXPaused = false; + SFXPaused = 0; DSPLocked = false; MusicGroup = NULL; SfxGroup = NULL; @@ -1382,7 +1382,7 @@ FSoundChan *FMODSoundRenderer::StartSound(sfxinfo_t *sfx, float vol, int pitch, mode = (mode & ~FMOD_LOOP_OFF) | FMOD_LOOP_NORMAL; } chan->setMode(mode); - chan->setChannelGroup((!(chanflags & CHAN_NOPAUSE) && !SFXPaused) ? PausableSfx : SfxGroup); + chan->setChannelGroup((chanflags & (CHAN_UI | CHAN_NOPAUSE)) ? SfxGroup : PausableSfx); if (freq != 0) { chan->setFrequency(freq); @@ -1470,7 +1470,8 @@ FSoundChan *FMODSoundRenderer::StartSound3D(sfxinfo_t *sfx, float vol, float dis } mode = SetChanHeadSettings(chan, sfx, pos, channum, chanflags, sector, mode); chan->setMode(mode); - chan->setChannelGroup((!(chanflags & CHAN_NOPAUSE) && !SFXPaused) ? PausableSfx : SfxGroup); + chan->setChannelGroup((chanflags & (CHAN_UI | CHAN_NOPAUSE)) ? SfxGroup : PausableSfx); + if (freq != 0) { chan->setFrequency(freq); @@ -1508,9 +1509,9 @@ void FMODSoundRenderer::HandleChannelDelay(FMOD::Channel *chan, FSoundChan *reus QWORD_UNION nowtime; chan->getDelay(FMOD_DELAYTYPE_DSPCLOCK_START, &nowtime.Hi, &nowtime.Lo); - // If the DSP is locked, the sounds are being restored, and + // If CHAN_ABSTIME is set, the sound is being restored, and // the channel's start time is actually its seek position. - if (DSPLocked) + if (reuse_chan->ChanFlags & CHAN_ABSTIME) { unsigned int seekpos = reuse_chan->StartTime.Lo; if (seekpos > 0) @@ -1518,6 +1519,7 @@ void FMODSoundRenderer::HandleChannelDelay(FMOD::Channel *chan, FSoundChan *reus chan->setPosition(seekpos, FMOD_TIMEUNIT_PCM); } reuse_chan->StartTime.AsOne = QWORD(nowtime.AsOne - seekpos * OutputRate / freq); + reuse_chan->ChanFlags &= ~CHAN_ABSTIME; } else { @@ -1679,12 +1681,26 @@ unsigned int FMODSoundRenderer::GetPosition(FSoundChan *chan) // //========================================================================== -void FMODSoundRenderer::SetSfxPaused(bool paused) +void FMODSoundRenderer::SetSfxPaused(bool paused, int slot) { - if (SFXPaused != paused) + int oldslots = SFXPaused; + + if (paused) { - PausableSfx->setPaused(paused); - SFXPaused = paused; + SFXPaused |= 1 << slot; + } + else + { + SFXPaused &= ~(1 << slot); + } + Printf("%d\n", SFXPaused); + if (oldslots != 0 && SFXPaused == 0) + { + PausableSfx->setPaused(false); + } + else if (oldslots == 0 && SFXPaused != 0) + { + PausableSfx->setPaused(true); } } diff --git a/src/sound/fmodsound.h b/src/sound/fmodsound.h index c9647eb25..73c7d5e2a 100644 --- a/src/sound/fmodsound.h +++ b/src/sound/fmodsound.h @@ -38,7 +38,7 @@ public: void Sync (bool sync); // Pauses or resumes all sound effect channels. - void SetSfxPaused (bool paused); + void SetSfxPaused (bool paused, int slot); // Pauses or resumes *every* channel, including environmental reverb. void SetInactive (bool inactive); @@ -57,7 +57,7 @@ public: void DrawWaveDebug(int mode); private: - bool SFXPaused; + int SFXPaused; bool InitSuccess; bool DSPLocked; QWORD_UNION DSPClock; diff --git a/src/sound/i_sound.cpp b/src/sound/i_sound.cpp index ba4609274..1d6931970 100644 --- a/src/sound/i_sound.cpp +++ b/src/sound/i_sound.cpp @@ -174,7 +174,7 @@ public: } // Pauses or resumes all sound effect channels. - void SetSfxPaused (bool paused) + void SetSfxPaused (bool paused, int slot) { } diff --git a/src/sound/i_sound.h b/src/sound/i_sound.h index 1ce2573d7..8be689bd0 100644 --- a/src/sound/i_sound.h +++ b/src/sound/i_sound.h @@ -102,7 +102,7 @@ public: virtual void Sync (bool sync) = 0; // Pauses or resumes all sound effect channels. - virtual void SetSfxPaused (bool paused) = 0; + virtual void SetSfxPaused (bool paused, int slot) = 0; // Pauses or resumes *every* channel, including environmental reverb. virtual void SetInactive(bool inactive) = 0; diff --git a/src/win32/i_system.cpp b/src/win32/i_system.cpp index 8739d182d..48d219669 100644 --- a/src/win32/i_system.cpp +++ b/src/win32/i_system.cpp @@ -523,17 +523,24 @@ struct snprintf_state char *buffer; size_t maxlen; size_t curlen; - bool overflow; + int ideallen; }; static int myvsnprintf_helper(void *data, const char *cstr, int cstr_len) { snprintf_state *state = (snprintf_state *)data; + if (INT_MAX - state->ideallen > cstr_len) + { + state->ideallen = INT_MAX; + } + else + { + state->ideallen += cstr_len; + } if (state->curlen + cstr_len > state->maxlen) { cstr_len = (int)(state->maxlen - state->curlen); - state->overflow = true; } if (cstr_len > 0) { @@ -543,14 +550,28 @@ static int myvsnprintf_helper(void *data, const char *cstr, int cstr_len) return cstr_len; } -// Unlike the standard C library function snprintf, this one always writes -// a terminating null character to the buffer. +// Unlike the MS CRT function snprintf, this one always writes a terminating +// null character to the buffer. It also returns the full length of the string +// that would have been output if the buffer had been large enough. In other +// words, it follows BSD/Linux rules and not MS rules. int myvsnprintf(char *buffer, size_t count, const char *format, va_list argptr) { - snprintf_state state = { buffer, count - 1, 0, false }; + size_t originalcount = count; + if (count != 0) + { + count--; + } + if (count > INT_MAX) + { + count = INT_MAX; + } + snprintf_state state = { buffer, count, 0, 0 }; StringFormat::VWorker(myvsnprintf_helper, &state, format, argptr); - buffer[state.curlen] = '\0'; - return state.overflow ? -1 : (int)state.curlen; + if (originalcount > 0) + { + buffer[state.curlen] = '\0'; + } + return state.ideallen; } int mysnprintf(char *buffer, size_t count, const char *format, ...) diff --git a/zdoom.sln b/zdoom.sln index d0b69f77f..28d9e565b 100644 --- a/zdoom.sln +++ b/zdoom.sln @@ -2,15 +2,15 @@ Microsoft Visual Studio Solution File, Format Version 9.00 # Visual Studio 2005 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zdoom", "zdoom.vcproj", "{8049475B-5C87-46F9-9358-635218A4EF18}" ProjectSection(ProjectDependencies) = postProject - {AC3F5340-40CB-4C3A-8AA7-CB7158DB4466} = {AC3F5340-40CB-4C3A-8AA7-CB7158DB4466} - {8997289F-10BF-4678-8BAA-3BB509C84953} = {8997289F-10BF-4678-8BAA-3BB509C84953} - {E83FD370-2E72-4D4C-9427-FF9D9DED1E88} = {E83FD370-2E72-4D4C-9427-FF9D9DED1E88} - {F9D9E7D4-E1A2-4866-9E85-B1B14137EE63} = {F9D9E7D4-E1A2-4866-9E85-B1B14137EE63} - {6077B7D6-349F-4077-B552-3BC302EF5859} = {6077B7D6-349F-4077-B552-3BC302EF5859} - {667D2EE7-C357-49E2-9BAB-0A4A45F0F76E} = {667D2EE7-C357-49E2-9BAB-0A4A45F0F76E} - {0F80ACBF-460E-44F0-B28E-B3272D1774A7} = {0F80ACBF-460E-44F0-B28E-B3272D1774A7} - {DA47396F-60C1-4BDE-A977-7F7DE461CF77} = {DA47396F-60C1-4BDE-A977-7F7DE461CF77} {1D179D4B-F008-431B-8C72-111F8372584F} = {1D179D4B-F008-431B-8C72-111F8372584F} + {DA47396F-60C1-4BDE-A977-7F7DE461CF77} = {DA47396F-60C1-4BDE-A977-7F7DE461CF77} + {0F80ACBF-460E-44F0-B28E-B3272D1774A7} = {0F80ACBF-460E-44F0-B28E-B3272D1774A7} + {667D2EE7-C357-49E2-9BAB-0A4A45F0F76E} = {667D2EE7-C357-49E2-9BAB-0A4A45F0F76E} + {6077B7D6-349F-4077-B552-3BC302EF5859} = {6077B7D6-349F-4077-B552-3BC302EF5859} + {F9D9E7D4-E1A2-4866-9E85-B1B14137EE63} = {F9D9E7D4-E1A2-4866-9E85-B1B14137EE63} + {E83FD370-2E72-4D4C-9427-FF9D9DED1E88} = {E83FD370-2E72-4D4C-9427-FF9D9DED1E88} + {8997289F-10BF-4678-8BAA-3BB509C84953} = {8997289F-10BF-4678-8BAA-3BB509C84953} + {AC3F5340-40CB-4C3A-8AA7-CB7158DB4466} = {AC3F5340-40CB-4C3A-8AA7-CB7158DB4466} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlib", "zlib\zlib.vcproj", "{F9D9E7D4-E1A2-4866-9E85-B1B14137EE63}" @@ -21,8 +21,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "re2c", "tools\re2c\re2c.vcp EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wadsrc", "wadsrc\wadsrc.vcproj", "{1D179D4B-F008-431B-8C72-111F8372584F}" ProjectSection(ProjectDependencies) = postProject - {24A19C02-F041-4AB0-A1A1-02E1E88EDBD3} = {24A19C02-F041-4AB0-A1A1-02E1E88EDBD3} {AC64EE8F-F019-4A3E-BCAF-BD1FD072B9C8} = {AC64EE8F-F019-4A3E-BCAF-BD1FD072B9C8} + {24A19C02-F041-4AB0-A1A1-02E1E88EDBD3} = {24A19C02-F041-4AB0-A1A1-02E1E88EDBD3} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "makewad", "tools\makewad\makewad.vcproj", "{24A19C02-F041-4AB0-A1A1-02E1E88EDBD3}" @@ -32,8 +32,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "makewad", "tools\makewad\ma EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dehsupp", "tools\dehsupp\dehsupp.vcproj", "{AC64EE8F-F019-4A3E-BCAF-BD1FD072B9C8}" ProjectSection(ProjectDependencies) = postProject - {0F80ACBF-460E-44F0-B28E-B3272D1774A7} = {0F80ACBF-460E-44F0-B28E-B3272D1774A7} {667D2EE7-C357-49E2-9BAB-0A4A45F0F76E} = {667D2EE7-C357-49E2-9BAB-0A4A45F0F76E} + {0F80ACBF-460E-44F0-B28E-B3272D1774A7} = {0F80ACBF-460E-44F0-B28E-B3272D1774A7} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "updaterevision", "tools\updaterevision\updaterevision.vcproj", "{6077B7D6-349F-4077-B552-3BC302EF5859}" @@ -46,6 +46,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "snes_spc", "snes_spc\snes_s EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dumb_static", "dumb\vc6\dumb_static\dumb_static.vcproj", "{8997289F-10BF-4678-8BAA-3BB509C84953}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gdtoa", "gdtoa\gdtoa.vcproj", "{B7B527BB-DC3A-41EF-96E5-7B057DE8BF9D}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -150,6 +152,12 @@ Global {8997289F-10BF-4678-8BAA-3BB509C84953}.Release|Win32.Build.0 = Release|Win32 {8997289F-10BF-4678-8BAA-3BB509C84953}.Release|x64.ActiveCfg = Release|x64 {8997289F-10BF-4678-8BAA-3BB509C84953}.Release|x64.Build.0 = Release|x64 + {B7B527BB-DC3A-41EF-96E5-7B057DE8BF9D}.Debug|Win32.ActiveCfg = Debug|Win32 + {B7B527BB-DC3A-41EF-96E5-7B057DE8BF9D}.Debug|Win32.Build.0 = Debug|Win32 + {B7B527BB-DC3A-41EF-96E5-7B057DE8BF9D}.Debug|x64.ActiveCfg = Debug|Win32 + {B7B527BB-DC3A-41EF-96E5-7B057DE8BF9D}.Release|Win32.ActiveCfg = Release|Win32 + {B7B527BB-DC3A-41EF-96E5-7B057DE8BF9D}.Release|Win32.Build.0 = Release|Win32 + {B7B527BB-DC3A-41EF-96E5-7B057DE8BF9D}.Release|x64.ActiveCfg = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE