diff --git a/docs/rh-log.txt b/docs/rh-log.txt index eae05baaa..c85cceba8 100644 --- a/docs/rh-log.txt +++ b/docs/rh-log.txt @@ -8,7 +8,41 @@ June 28, 2008 (Changes by Graf Zahl) - Fixed: Heretic's ActivatedTimeBomb had the same spawn ID as the inventory item. - fixed: Heretic's mace did not have its spawn ID set. +June 28, 2008 +- The sound code now handles restarting looping sounds itself. As far as + the rest of the game is concerned, these sounds will never stop once they + have been started until they are explicitly stopped. If they are evicted + from their channels, the sound code will restart them as soon as possible. + This means that instead of this: + if (!S_IsActorPlayingSomething(actor, CHAN_WEAPON, -1)) + { + S_Sound(actor, CHAN_WEAPON|CHAN_LOOP, soundid, 1, ATTN_NORM); + } + The following is now just as effective: + S_Sound(actor, CHAN_WEAPON|CHAN_LOOP, soundid, 1, ATTN_NORM); + There are also a couple of other ramifications presented by this change: + * The full state of the sound system (sans music) is now stored in save + games. Any sounds that were playing when you saved will still be + playing when you load. (Try saving while Korax is making a speech in + Hexen to hear it.) + * Using snd_reset will also preserve any playing sounds. + * Movie playback is disabled, probably forever. I did not want to + update the MovieDisable/ResumeSound stuff for the new eviction + tracking code. A properly updated movie player will use the VMR, + which doesn't need these functions, since it would pipe the sound + straight through the sound system like everything else, so I decided + to dump them now, which leaves the movie player in a totally unworkable + state. + June 26, 2008 +- Changed S_Sound() to take the same floating point attenuation that the + internal S_StartSound() uses. Now ambient sounds can use the public + S_Sound() interface. +- Fixed: S_RelinkSound() compared the points of the channels against the + from actor's point, rather than checking the channels' mover. +- Changed Strife's animated doors so that their sounds originate from the + interior of the sector making them and not from the entire vertical height + of the map. - For controls that are not bound, the customize controls menu now displays a black --- instead of ???. - Applied Gez's BossBrainPatch3. diff --git a/src/doomtype.h b/src/doomtype.h index 6b9232261..f062b2781 100644 --- a/src/doomtype.h +++ b/src/doomtype.h @@ -126,6 +126,18 @@ typedef struct _GUID } GUID; #endif +union QWORD_UNION +{ + QWORD AsOne; + struct + { +#ifdef WORDS_BIG_ENDIAN + unsigned int Hi, Lo; +#else + unsigned int Lo, Hi; +#endif + }; +}; // Bounding box coordinate storage. enum diff --git a/src/farchive.h b/src/farchive.h index fdb60d41b..b9d6a2b19 100644 --- a/src/farchive.h +++ b/src/farchive.h @@ -177,6 +177,7 @@ virtual void Read (void *mem, unsigned int len); FArchive& operator<< (WORD &s); FArchive& operator<< (DWORD &i); FArchive& operator<< (QWORD &i); + FArchive& operator<< (QWORD_UNION &i) { return operator<< (i.AsOne); } FArchive& operator<< (float &f); FArchive& operator<< (double &d); FArchive& operator<< (char *&str); diff --git a/src/p_doors.cpp b/src/p_doors.cpp index f4b382904..cf02ac5b0 100644 --- a/src/p_doors.cpp +++ b/src/p_doors.cpp @@ -729,7 +729,7 @@ DAnimatedDoor::DAnimatedDoor (sector_t *sec, line_t *line, int speed, int delay) MoveCeiling (2048*FRACUNIT, topdist, 1); if (DoorAnimations[m_WhichDoorIndex].OpenSound != NAME_None) { - SN_StartSequence (m_Sector, CHAN_FULLHEIGHT, DoorAnimations[m_WhichDoorIndex].OpenSound, 1); + SN_StartSequence (m_Sector, CHAN_INTERIOR, DoorAnimations[m_WhichDoorIndex].OpenSound, 1); } } diff --git a/src/p_saveg.cpp b/src/p_saveg.cpp index 655c55376..49d7ea8ad 100644 --- a/src/p_saveg.cpp +++ b/src/p_saveg.cpp @@ -436,6 +436,7 @@ void P_SerializeThinkers (FArchive &arc, bool hubLoad) void P_SerializeSounds (FArchive &arc) { + S_SerializeSounds (arc); DSeqNode::SerializeSequences (arc); char *name = NULL; BYTE order; diff --git a/src/s_advsound.cpp b/src/s_advsound.cpp index abe0bf3ca..dde217ed5 100644 --- a/src/s_advsound.cpp +++ b/src/s_advsound.cpp @@ -186,8 +186,6 @@ MidiDeviceMap MidiDevices; // EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- -FSoundChan *S_StartSound (fixed_t *pt, AActor *mover, sector_t *sec, int channel, - FSoundID sound_id, float volume, float attenuation); extern bool IsFloat (const char *str); // PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- @@ -1873,35 +1871,28 @@ void AAmbientSound::Tick () return; AmbientSound *ambient = Ambients[args[0]]; + int loop = 0; if ((ambient->type & CONTINUOUS) == CONTINUOUS) { - if (S_IsActorPlayingSomething (this, CHAN_BODY, -1)) - return; + loop = CHAN_LOOP; + } - if (ambient->sound[0]) + if (ambient->sound[0]) + { + S_Sound(this, CHAN_BODY | loop, ambient->sound, ambient->volume, ambient->attenuation); + if (!loop) { - S_StartSound (&this->x, this, NULL, CHAN_BODY|CHAN_LOOP, ambient->sound, - ambient->volume, ambient->attenuation); SetTicker (ambient); } else { - Destroy (); + NextCheck = INT_MAX; } } else { - if (ambient->sound[0]) - { - S_StartSound (NULL, this, NULL, CHAN_BODY, ambient->sound, - ambient->volume, ambient->attenuation); - SetTicker (ambient); - } - else - { - Destroy (); - } + Destroy (); } } diff --git a/src/s_sndseq.cpp b/src/s_sndseq.cpp index 58e7bcffe..18cb07dcf 100644 --- a/src/s_sndseq.cpp +++ b/src/s_sndseq.cpp @@ -269,10 +269,6 @@ static FRandom pr_sndseq ("SndSeq"); void DSeqNode::SerializeSequences (FArchive &arc) { - if (arc.IsLoading ()) - { - SN_StopAllSequences (); - } arc << SequenceListHead; } diff --git a/src/s_sound.cpp b/src/s_sound.cpp index 4a1e3442b..9e332e313 100644 --- a/src/s_sound.cpp +++ b/src/s_sound.cpp @@ -63,7 +63,6 @@ #define O_BINARY 0 #endif -#define SELECT_ATTEN(a) ((a)==ATTN_NONE ? 0 : (a)==ATTN_STATIC ? 3 : 1) #ifndef FIXED2FLOAT #define FIXED2FLOAT(f) (((float)(f))/(float)65536) #endif @@ -91,16 +90,15 @@ extern float S_GetMusicVolume (const char *music); // PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- -FSoundChan *S_StartSound(fixed_t *pt, AActor *mover, sector_t *sec, int channel, - FSoundID sound_id, float volume, float attenuation); - // PRIVATE FUNCTION PROTOTYPES --------------------------------------------- -static fixed_t P_AproxDistance2(fixed_t *listener, fixed_t x, fixed_t y); -static bool S_CheckSoundLimit(sfxinfo_t *sfx, float pos[3], int NearLimit); +static bool S_CheckSoundLimit(sfxinfo_t *sfx, float pos[3], int near_limit); static void S_ActivatePlayList(bool goBack); static void CalcPosVel(fixed_t *pt, AActor *mover, int constz, float pos[3], float vel[3]); +static FSoundChan *S_StartSound(fixed_t *pt, AActor *mover, sector_t *sec, + int channel, FSoundID sound_id, float volume, float attenuation); +static sfxinfo_t *S_LoadSound(sfxinfo_t *sfx); // PRIVATE DATA DEFINITIONS ------------------------------------------------ @@ -129,32 +127,6 @@ CVAR (Bool, snd_flipstereo, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) // CODE -------------------------------------------------------------------- -//========================================================================== -// -// P_AproxDistance2 -// -//========================================================================== - -static fixed_t P_AproxDistance2 (fixed_t *listener, fixed_t x, fixed_t y) -{ - // calculate the distance to sound origin - // and clip it if necessary - if (listener) - { - fixed_t adx = abs (listener[0] - x); - fixed_t ady = abs (listener[1] - y); - // From _GG1_ p.428. Appox. eucledian distance fast. - return adx + ady - ((adx < ady ? adx : ady)>>1); - } - else - return 0; -} - -static fixed_t P_AproxDistance2 (AActor *listener, fixed_t x, fixed_t y) -{ - return listener ? P_AproxDistance2 (&listener->x, x, y) : 0; -} - //========================================================================== // // S_NoiseDebug @@ -165,6 +137,7 @@ static fixed_t P_AproxDistance2 (AActor *listener, fixed_t x, fixed_t y) void S_NoiseDebug (void) { FSoundChan *chan; + FVector3 listener; fixed_t ox, oy, oz; int y, color; @@ -179,6 +152,7 @@ void S_NoiseDebug (void) screen->DrawText (CR_GOLD, 220, y, "vol", TAG_DONE); screen->DrawText (CR_GOLD, 250, y, "dist", TAG_DONE); screen->DrawText (CR_GOLD, 290, y, "chan", TAG_DONE); + screen->DrawText (CR_GOLD, 330, y, "flags", TAG_DONE); y += 8; if (Channels == NULL) @@ -186,48 +160,83 @@ void S_NoiseDebug (void) return; } - // Display the last channel first. + listener.X = FIXED2FLOAT(players[consoleplayer].camera->x); + listener.Y = FIXED2FLOAT(players[consoleplayer].camera->y); + listener.Z = FIXED2FLOAT(players[consoleplayer].camera->z); + + // Display the oldest channel first. for (chan = Channels; chan->NextChan != NULL; chan = chan->NextChan) { } while (y < SCREENHEIGHT - 16) { - char temp[16]; - fixed_t *origin = chan->Pt; + char temp[32]; - if (!(chan->ChanFlags & CHAN_IS3D)) - { - ox = players[consoleplayer].camera->x; - oy = players[consoleplayer].camera->y; - oz = players[consoleplayer].camera->z; - } - else if (origin) - { - ox = origin[0]; - oy = origin[1]; - oz = origin[2]; - } - else - { - ox = chan->X; - oy = chan->Y; - oz = chan->Z; - } + assert(chan->Pt != NULL); + ox = chan->Pt[0]; + oy = chan->Pt[1]; + oz = chan->Pt[2]; color = (chan->ChanFlags & CHAN_LOOP) ? CR_BROWN : CR_GREY; + + // Name Wads.GetLumpName (temp, chan->SfxInfo->lumpnum); temp[8] = 0; screen->DrawText (color, 0, y, temp, TAG_DONE); - sprintf (temp, "%d", ox >> FRACBITS); - screen->DrawText (color, 70, y, temp, TAG_DONE); - sprintf (temp, "%d", oy >> FRACBITS); - screen->DrawText (color, 120, y, temp, TAG_DONE); - sprintf (temp, "%d", oz >> FRACBITS); - screen->DrawText (color, 170, y, temp, TAG_DONE); + + if (!(chan->ChanFlags & CHAN_IS3D)) + { + screen->DrawText(color, 70, y, "---", TAG_DONE); // X + screen->DrawText(color, 120, y, "---", TAG_DONE); // Y + screen->DrawText(color, 170, y, "---", TAG_DONE); // Z + screen->DrawText(color, 250, y, "---", TAG_DONE); // Distance + } + else + { + // X coordinate + sprintf (temp, "%d", ox >> FRACBITS); + screen->DrawText (color, 70, y, temp, TAG_DONE); + + // Y coordinate + sprintf (temp, "%d", oy >> FRACBITS); + screen->DrawText (color, 120, y, temp, TAG_DONE); + + // Z coordinate + sprintf (temp, "%d", oz >> FRACBITS); + screen->DrawText (color, 170, y, temp, TAG_DONE); + + // Distance + if (chan->DistanceScale > 0) + { + FVector3 sound(ox, oy, oz); + sound /= FRACUNIT; + sprintf (temp, "%.0f", (sound - listener).Length()); + screen->DrawText (color, 250, y, temp, TAG_DONE); + } + else + { + screen->DrawText (color, 250, y, "---", TAG_DONE); + } + } + + // Volume sprintf (temp, "%g", chan->Volume); screen->DrawText (color, 220, y, temp, TAG_DONE); - sprintf (temp, "%d", P_AproxDistance2 (players[consoleplayer].camera, ox, oy) / FRACUNIT); - screen->DrawText (color, 250, y, temp, TAG_DONE); + + // Channel sprintf (temp, "%d", chan->EntChannel); screen->DrawText (color, 290, y, temp, TAG_DONE); + + // Flags + sprintf (temp, "%s3%sZ%sI%sM%sN%sA%sL%sE", + (chan->ChanFlags & CHAN_IS3D) ? TEXTCOLOR_GREEN : TEXTCOLOR_BLACK, + (chan->ChanFlags & CHAN_LISTENERZ) ? TEXTCOLOR_GREEN : TEXTCOLOR_BLACK, + (chan->ChanFlags & CHAN_IMMOBILE) ? TEXTCOLOR_GREEN : TEXTCOLOR_BLACK, + (chan->ChanFlags & CHAN_MAYBE_LOCAL) ? TEXTCOLOR_GREEN : TEXTCOLOR_BLACK, + (chan->ChanFlags & CHAN_NOPAUSE) ? TEXTCOLOR_GREEN : TEXTCOLOR_BLACK, + (chan->ChanFlags & CHAN_AREA) ? TEXTCOLOR_GREEN : TEXTCOLOR_BLACK, + (chan->ChanFlags & CHAN_LOOP) ? TEXTCOLOR_GREEN : TEXTCOLOR_BLACK, + (chan->ChanFlags & CHAN_EVICTED) ? TEXTCOLOR_GREEN : TEXTCOLOR_BLACK); + screen->DrawText (color, 330, y, temp, TAG_DONE); + y += 8; if (chan->PrevChan == &Channels) { @@ -638,8 +647,8 @@ void CalcPosVel (fixed_t *pt, AActor *mover, int constz, // calculating volume //========================================================================== -FSoundChan *S_StartSound (fixed_t *pt, AActor *mover, sector_t *sec, int channel, - FSoundID sound_id, float volume, float attenuation) +static FSoundChan *S_StartSound (fixed_t *pt, AActor *mover, sector_t *sec, + int channel, FSoundID sound_id, float volume, float attenuation) { sfxinfo_t *sfx; int chanflags; @@ -702,7 +711,7 @@ FSoundChan *S_StartSound (fixed_t *pt, AActor *mover, sector_t *sec, int channel // When resolving a link we do not want to get the NearLimit of // the referenced sound so some additional checks are required - int NearLimit = sfx->NearLimit; + int near_limit = sfx->NearLimit; // Resolve player sounds, random sounds, and aliases while (sfx->link != sfxinfo_t::NO_LINK) @@ -710,17 +719,17 @@ FSoundChan *S_StartSound (fixed_t *pt, AActor *mover, sector_t *sec, int channel if (sfx->bPlayerReserve) { sound_id = FSoundID(S_FindSkinnedSound (mover, sound_id)); - NearLimit = S_sfx[sound_id].NearLimit; + near_limit = S_sfx[sound_id].NearLimit; } else if (sfx->bRandomHeader) { sound_id = FSoundID(S_PickReplacement (sound_id)); - if (NearLimit < 0) NearLimit = S_sfx[sound_id].NearLimit; + if (near_limit < 0) near_limit = S_sfx[sound_id].NearLimit; } else { sound_id = FSoundID(sfx->link); - if (NearLimit < 0) NearLimit = S_sfx[sound_id].NearLimit; + if (near_limit < 0) near_limit = S_sfx[sound_id].NearLimit; } sfx = &S_sfx[sound_id]; } @@ -729,21 +738,20 @@ FSoundChan *S_StartSound (fixed_t *pt, AActor *mover, sector_t *sec, int channel if (sfx->bSingular && S_CheckSingular(sound_id)) return NULL; + // If the sound is unpositioned or comes from the listener, it is + // never limited. + if (pt == NULL || mover == players[consoleplayer].camera) + { + near_limit = 0; + } + // If this sound doesn't like playing near itself, don't play it if // that's what would happen. - if (NearLimit > 0 && pt != NULL && mover != players[consoleplayer].camera && - S_CheckSoundLimit(sfx, pos, NearLimit)) + if (near_limit > 0 && S_CheckSoundLimit(sfx, pos, near_limit)) return NULL; // Make sure the sound is loaded. - if (sfx->data == NULL) - { - GSnd->LoadSound (sfx); - if (sfx->link != sfxinfo_t::NO_LINK) - { - sfx = &S_sfx[sfx->link]; - } - } + sfx = S_LoadSound(sfx); // The empty sound never plays. if (sfx->lumpnum == sfx_empty) @@ -811,18 +819,18 @@ FSoundChan *S_StartSound (fixed_t *pt, AActor *mover, sector_t *sec, int channel if (attenuation > 0) { - chan = GSnd->StartSound3D (sfx, volume, attenuation, pitch, basepriority, pos, vel, sec, channel, chanflags); - chanflags |= CHAN_IS3D; + chan = GSnd->StartSound3D (sfx, volume, attenuation, pitch, basepriority, pos, vel, sec, channel, chanflags, NULL); + chanflags |= CHAN_IS3D | CHAN_JUSTSTARTED; } else { - chan = GSnd->StartSound (sfx, volume, pitch, chanflags); - chanflags |= CHAN_LISTENERZ; + chan = GSnd->StartSound (sfx, volume, pitch, chanflags, NULL); + chanflags |= CHAN_LISTENERZ | CHAN_JUSTSTARTED; } if (chan != NULL) { chan->SoundID = sound_id; - chan->OrgID = org_id; + chan->OrgID = FSoundID(org_id); chan->Mover = mover; chan->Pt = pt != NULL ? pt : &chan->X; chan->Sector = sec; @@ -833,6 +841,9 @@ FSoundChan *S_StartSound (fixed_t *pt, AActor *mover, sector_t *sec, int channel chan->Y = y; chan->Z = z; chan->ChanFlags |= chanflags; + chan->NearLimit = near_limit; + chan->Pitch = pitch; + chan->Priority = basepriority; if (mover != NULL) { mover->SoundChans |= 1 << channel; @@ -841,15 +852,72 @@ FSoundChan *S_StartSound (fixed_t *pt, AActor *mover, sector_t *sec, int channel return chan; } +//========================================================================== +// +// S_RestartSound +// +// Attempts to restart looping sounds that were evicted from their channels. +// +//========================================================================== + +void S_RestartSound(FSoundChan *chan) +{ + assert(chan->ChanFlags & CHAN_EVICTED); + assert(chan->SfxInfo != NULL); + + FSoundChan *ochan; + sfxinfo_t *sfx = chan->SfxInfo; + + // If this is a singular sound, don't play it if it's already playing. + if (sfx->bSingular && S_CheckSingular(chan->SoundID)) + return; + + sfx = S_LoadSound(sfx); + + // The empty sound never plays. + if (sfx->lumpnum == sfx_empty) + { + return; + } + + if (chan->ChanFlags & CHAN_IS3D) + { + float pos[3], vel[3]; + + CalcPosVel(chan->Pt, chan->Mover, chan->ChanFlags & CHAN_LISTENERZ, pos, vel); + + // If this sound doesn't like playing near itself, don't play it if + // that's what would happen. + ochan = GSnd->StartSound3D(sfx, chan->Volume, chan->DistanceScale, chan->Pitch, + chan->Priority, pos, vel, chan->Sector, chan->EntChannel, chan->ChanFlags, chan); + } + else + { + ochan = GSnd->StartSound(chan->SfxInfo, chan->Volume, chan->Pitch, chan->ChanFlags, chan); + } + assert(ochan == NULL || ochan == chan); + if (ochan != NULL) + { + ochan->ChanFlags &= ~CHAN_EVICTED; + // When called from the savegame loader, the actor's SoundChans + // flags will be cleared. During normal gameplay, they should still + // be set. + if (ochan->Mover != NULL) + { + ochan->Mover->SoundChans |= 1 << ochan->EntChannel; + } + } +} + //========================================================================== // // S_Sound - Unpositioned version // //========================================================================== -void S_Sound (int channel, FSoundID sound_id, float volume, int attenuation) +void S_Sound (int channel, FSoundID sound_id, float volume, float attenuation) { - S_StartSound ((fixed_t *)NULL, NULL, NULL, channel, sound_id, volume, SELECT_ATTEN(attenuation)); + S_StartSound ((fixed_t *)NULL, NULL, NULL, channel, sound_id, volume, attenuation); } //========================================================================== @@ -858,11 +926,11 @@ void S_Sound (int channel, FSoundID sound_id, float volume, int attenuation) // //========================================================================== -void S_Sound (AActor *ent, int channel, FSoundID sound_id, float volume, int attenuation) +void S_Sound (AActor *ent, int channel, FSoundID sound_id, float volume, float attenuation) { if (ent->Sector->Flags & SECF_SILENT) return; - S_StartSound (&ent->x, ent, NULL, channel, sound_id, volume, SELECT_ATTEN(attenuation)); + S_StartSound (&ent->x, ent, NULL, channel, sound_id, volume, attenuation); } //========================================================================== @@ -871,9 +939,9 @@ void S_Sound (AActor *ent, int channel, FSoundID sound_id, float volume, int att // //========================================================================== -void S_Sound (fixed_t *pt, int channel, FSoundID sound_id, float volume, int attenuation) +void S_Sound (fixed_t *pt, int channel, FSoundID sound_id, float volume, float attenuation) { - S_StartSound (pt, NULL, NULL, channel, sound_id, volume, SELECT_ATTEN(attenuation)); + S_StartSound (pt, NULL, NULL, channel, sound_id, volume, attenuation); } //========================================================================== @@ -882,13 +950,13 @@ void S_Sound (fixed_t *pt, int channel, FSoundID sound_id, float volume, int att // //========================================================================== -void S_Sound (fixed_t x, fixed_t y, fixed_t z, int channel, FSoundID sound_id, float volume, int attenuation) +void S_Sound (fixed_t x, fixed_t y, fixed_t z, int channel, FSoundID sound_id, float volume, float attenuation) { fixed_t pt[3]; pt[0] = x; pt[1] = y; pt[2] = z; - S_StartSound (pt, NULL, NULL, channel|CHAN_IMMOBILE, sound_id, volume, SELECT_ATTEN(attenuation)); + S_StartSound (pt, NULL, NULL, channel|CHAN_IMMOBILE, sound_id, volume, attenuation); } //========================================================================== @@ -897,11 +965,32 @@ void S_Sound (fixed_t x, fixed_t y, fixed_t z, int channel, FSoundID sound_id, f // //========================================================================== -void S_Sound (sector_t *sec, int channel, FSoundID sfxid, float volume, int attenuation) +void S_Sound (sector_t *sec, int channel, FSoundID sfxid, float volume, float attenuation) { S_StartSound (sec->soundorg, NULL, sec, channel, sfxid, volume, attenuation); } +//========================================================================== +// +// S_LoadSound +// +// Returns a pointer to the sfxinfo with the actual sound data. +// +//========================================================================== + +sfxinfo_t *S_LoadSound(sfxinfo_t *sfx) +{ + if (sfx->data == NULL) + { + GSnd->LoadSound (sfx); + if (sfx->link != sfxinfo_t::NO_LINK) + { + sfx = &S_sfx[sfx->link]; + } + } + return sfx; +} + //========================================================================== // // S_CheckSingular @@ -933,14 +1022,14 @@ bool S_CheckSingular(int sound_id) // //========================================================================== -bool S_CheckSoundLimit(sfxinfo_t *sfx, float pos[3], int NearLimit) +bool S_CheckSoundLimit(sfxinfo_t *sfx, float pos[3], int near_limit) { FSoundChan *chan; int count; - for (chan = Channels, count = 0; chan != NULL && count < NearLimit; chan = chan->NextChan) + for (chan = Channels, count = 0; chan != NULL && count < near_limit; chan = chan->NextChan) { - if (chan->SfxInfo == sfx) + if (!(chan->ChanFlags & CHAN_EVICTED) && chan->SfxInfo == sfx) { double dx = FIXED2FLOAT(chan->Pt[0]) - pos[0]; double dy = FIXED2FLOAT(chan->Pt[1]) - pos[2]; @@ -951,7 +1040,7 @@ bool S_CheckSoundLimit(sfxinfo_t *sfx, float pos[3], int NearLimit) } } } - return count >= NearLimit; + return count >= near_limit; } //========================================================================== @@ -1015,19 +1104,19 @@ void S_RelinkSound (AActor *from, AActor *to) if (from == NULL || GSnd == NULL) return; - fixed_t *frompt = &from->x; - fixed_t *topt = to ? &to->x : NULL; - for (FSoundChan *chan = Channels; chan != NULL; chan = chan->NextChan) { - if (chan->Pt == frompt) + if (chan->Mover == from) { if (to != NULL || !(chan->ChanFlags & CHAN_LOOP)) { - chan->Pt = topt ? topt : &chan->X; - chan->X = frompt[0]; - chan->Y = frompt[1]; - chan->Z = frompt[2]; + if (chan->Pt == &from->x) + { + chan->Pt = to ? &to->x : &chan->X; + chan->X = from->x; + chan->Y = from->y; + chan->Z = from->z; + } chan->Mover = to; } else @@ -1134,6 +1223,87 @@ void S_ResumeSound () } } +//========================================================================== +// +// S_EvictAllChannels +// +// Forcibly evicts all channels so that there are none playing, but all +// information needed to restart them is retained. +// +//========================================================================== + +void S_EvictAllChannels() +{ + FSoundChan *chan, *next; + + for (chan = Channels; chan != NULL; chan = next) + { + next = chan->NextChan; + + if (!(chan->ChanFlags & CHAN_EVICTED)) + { + chan->ChanFlags |= CHAN_EVICTED; + if (GSnd != NULL && chan->SysChannel != NULL) + { + GSnd->StopSound(chan); + } + assert(chan->NextChan == next); + } + } +} + +//========================================================================== +// +// S_RestoreEvictedChannel +// +// Recursive helper for S_RestoreEvictedChannels(). +// +//========================================================================== + +void S_RestoreEvictedChannel(FSoundChan *chan) +{ + if (chan == NULL) + { + return; + } + S_RestoreEvictedChannel(chan->NextChan); + if (chan->ChanFlags & CHAN_EVICTED) + { + S_RestartSound(chan); + if (!(chan->ChanFlags & CHAN_LOOP)) + { + if (chan->ChanFlags & CHAN_EVICTED) + { // Still evicted and not looping? Forget about it. + S_ReturnChannel(chan); + } + else if (!(chan->ChanFlags & CHAN_JUSTSTARTED)) + { // Should this sound become evicted again, it's okay to forget about it. + chan->ChanFlags |= CHAN_FORGETTABLE; + } + } + } +} + +//========================================================================== +// +// S_RestoreEvictedChannels +// +// Restarts as many evicted channels as possible. Any channels that could +// not be started and are not looping are moved to the free pool. +// +//========================================================================== + +void S_RestoreEvictedChannels() +{ + if (GSnd == NULL) + { + return; + } + + // Restart channels in the same order they were originally played. + S_RestoreEvictedChannel(Channels); +} + //========================================================================== // // S_UpdateSounds @@ -1163,22 +1333,25 @@ void S_UpdateSounds (void *listener_p) for (FSoundChan *chan = Channels; chan != NULL; chan = chan->NextChan) { - if (chan->ChanFlags & CHAN_IS3D) + if ((chan->ChanFlags & (CHAN_EVICTED | CHAN_IS3D)) == CHAN_IS3D) { CalcPosVel(chan->Pt, chan->Mover, chan->ChanFlags & CHAN_LISTENERZ, pos, vel); GSnd->UpdateSoundParams3D(chan, pos, vel); } + chan->ChanFlags &= ~CHAN_JUSTSTARTED; } SN_UpdateActiveSequences(); GSnd->UpdateListener(); GSnd->UpdateSounds(); + + S_RestoreEvictedChannels(); } //========================================================================== // -// FArchive & << FSoundID & +// (FArchive &) << (FSoundID &) // //========================================================================== @@ -1195,6 +1368,134 @@ FArchive &operator<<(FArchive &arc, FSoundID &sid) return arc; } +//========================================================================== +// +// (FArchive &) << (FSoundChan &) +// +//========================================================================== + +static FArchive &operator<<(FArchive &arc, FSoundChan &chan) +{ + BYTE pt_type; + + if (arc.IsStoring()) + { + if (chan.Pt == &chan.X) + { + pt_type = 2; + } + else if (chan.Pt == &chan.Mover->x) + { + pt_type = 1; + } + else + { // WTF? + assert(0); + pt_type = 0; + } + } + + arc << pt_type; + arc << chan.Mover; + arc << chan.Sector; + arc << chan.X; + arc << chan.Y; + arc << chan.Z; + arc << chan.SoundID; + arc << chan.OrgID; + arc << chan.Volume; + arc << chan.DistanceScale; + arc << chan.Pitch; + arc << chan.ChanFlags; + arc << chan.EntChannel; + arc << chan.Priority; + arc << chan.NearLimit; + arc << chan.StartTime; + + if (arc.IsLoading()) + { + chan.SfxInfo = &S_sfx[chan.SoundID]; + if (pt_type == 1) + { + chan.Pt = &chan.Mover->x; + } + else if (pt_type == 2) + { + chan.Pt = &chan.X; + } + else + { + chan.Pt = &chan.Mover->x; + } + } + return arc; +} + +//========================================================================== +// +// S_SerializeSounds +// +//========================================================================== + +void S_SerializeSounds(FArchive &arc) +{ + FSoundChan *chan; + + if (GSnd != NULL) + { + GSnd->Sync(true); + } + + if (arc.IsStoring()) + { + TArray chans; + + // Count channels and accumulate them so we can store them in + // reverse order. That way, they will be in the same order when + // reloaded later as they are now. + 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)) + { + chans.Push(chan); + } + } + + arc.WriteCount(chans.Size()); + + for (unsigned int i = chans.Size(); i-- != 0; ) + { + // Replace start time with sample position. + QWORD start = chans[i]->StartTime.AsOne; + chans[i]->StartTime.AsOne = GSnd ? GSnd->GetPosition(chans[i]) : 0; + arc << *chans[i]; + chans[i]->StartTime.AsOne = start; + } + } + else + { + unsigned int count; + + S_StopAllChannels(); + count = arc.ReadCount(); + for (unsigned int i = 0; i < count; ++i) + { + chan = S_GetChannel(NULL); + arc << *chan; + // Sounds always start out evicted when restored from a save. + chan->ChanFlags |= CHAN_EVICTED; + } + S_RestoreEvictedChannels(); + } + DSeqNode::SerializeSequences(arc); + if (GSnd != NULL) + { + GSnd->Sync(false); + GSnd->UpdateSounds(); + } +} //========================================================================== // diff --git a/src/s_sound.h b/src/s_sound.h index 7a6ed3e81..a754eae7d 100644 --- a/src/s_sound.h +++ b/src/s_sound.h @@ -177,17 +177,22 @@ struct FSoundChan fixed_t *Pt; // Origin of sound. sfxinfo_t *SfxInfo; // Sound information. fixed_t X,Y,Z; // Origin if Mover is NULL. - int SoundID; // Sound ID of playing sound - int OrgID; // Sound ID of sound used to start this channel + FSoundID SoundID; // Sound ID of playing sound. + FSoundID OrgID; // Sound ID of sound used to start this channel. float Volume; float DistanceScale; - BYTE EntChannel; // Actor's sound channel. + int Pitch; // Pitch variation. int ChanFlags; + BYTE EntChannel; // Actor's sound channel. + SBYTE Priority; + SWORD NearLimit; + QWORD_UNION StartTime; // Sound start time in DSP clocks. }; extern FSoundChan *Channels; FSoundChan *S_GetChannel(void *syschan); void S_ReturnChannel(FSoundChan *chan); +void S_EvictAllChannels(); void S_LinkChannel(FSoundChan *chan, FSoundChan **head); void S_UnlinkChannel(FSoundChan *chan); @@ -212,11 +217,11 @@ void S_PrecacheLevel (); void S_CacheSound (sfxinfo_t *sfx); // Start sound for thing at -void S_Sound (int channel, FSoundID sfxid, float volume, int attenuation); -void S_Sound (AActor *ent, int channel, FSoundID sfxid, float volume, int attenuation); -void S_Sound (fixed_t *pt, int channel, FSoundID sfxid, float volume, int attenuation); -void S_Sound (fixed_t x, fixed_t y, fixed_t z, int channel, FSoundID sfxid, float volume, int attenuation); -void S_Sound (sector_t *sec, int channel, FSoundID sfxid, float volume, int attenuation); +void S_Sound (int channel, FSoundID sfxid, float volume, float attenuation); +void S_Sound (AActor *ent, int channel, FSoundID sfxid, float volume, float attenuation); +void S_Sound (fixed_t *pt, int channel, FSoundID sfxid, float volume, float attenuation); +void S_Sound (fixed_t x, fixed_t y, fixed_t z, int channel, FSoundID sfxid, float volume, float attenuation); +void S_Sound (sector_t *sec, int channel, FSoundID sfxid, float volume, float attenuation); // sound channels // channel 0 never willingly overrides @@ -234,29 +239,34 @@ void S_Sound (sector_t *sec, int channel, FSoundID sfxid, float volume, int atte #define CHAN_VOICE 2 #define CHAN_ITEM 3 #define CHAN_BODY 4 -// modifier flags -#define CHAN_LISTENERZ 8 -#define CHAN_IMMOBILE 16 -#define CHAN_MAYBE_LOCAL 32 -#define CHAN_NOPAUSE 64 // do not pause this sound in menus -#define CHAN_AREA 128 // Sound plays from all around. Only valid with sector sounds. -#define CHAN_LOOP 256 // Channel alias for sector sounds. These define how listener height is // used when calculating 3D sound volume. #define CHAN_FLOOR 1 // Sound comes from the floor. #define CHAN_CEILING 2 // Sound comes from the ceiling. #define CHAN_FULLHEIGHT 3 // Sound comes entire height of the sector. +#define CHAN_INTERIOR 4 // Sound comes height between floor and ceiling. -#define CHAN_IS3D (1<<24) // internal flag +// modifier flags +#define CHAN_LISTENERZ 8 +#define CHAN_IMMOBILE 16 +#define CHAN_MAYBE_LOCAL 32 +#define CHAN_NOPAUSE 64 // Do not pause this sound in menus. +#define CHAN_AREA 128 // Sound plays from all around. Only valid with sector sounds. +#define CHAN_LOOP 256 #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_JUSTSTARTED 512 // internal: Sound has not been updated yet. + // sound attenuation values -#define ATTN_NONE 0 // full volume the entire level -#define ATTN_NORM 1 -#define ATTN_IDLE 2 -#define ATTN_STATIC 3 // diminish very rapidly with distance +#define ATTN_NONE 0.f // full volume the entire level +#define ATTN_NORM 1.f +#define ATTN_IDLE 1.001f +#define ATTN_STATIC 3.f // diminish very rapidly with distance int S_PickReplacement (int refid); void S_CacheRandomSound (sfxinfo_t *sfx); @@ -279,6 +289,9 @@ bool S_IsActorPlayingSomething (AActor *actor, int channel, int sound_id); // Moves all sounds from one mobj to another void S_RelinkSound (AActor *from, AActor *to); +// Stores/retrieves playing channel information in an archive. +void S_SerializeSounds(FArchive &arc); + // Start music using bool S_StartMusic (const char *music_name); @@ -304,6 +317,8 @@ void S_ResumeSound (); // void S_UpdateSounds (void *listener); +void S_RestoreEvictedChannels(); + // [RH] S_sfx "maintenance" routines void S_ParseSndInfo (); void S_ParseReverbDef (); diff --git a/src/sound/fmodsound.cpp b/src/sound/fmodsound.cpp index 5022d6749..48a25ac67 100644 --- a/src/sound/fmodsound.cpp +++ b/src/sound/fmodsound.cpp @@ -92,11 +92,6 @@ FMOD_RESULT SPC_CreateCodec(FMOD::System *sys); static int Enum_NumForName(const FEnumList *list, const char *name); static const char *Enum_NameForNum(const FEnumList *list, int num); -static FMOD_RESULT F_CALLBACK Memory_Open(const char *name, int unicode, unsigned int *filesize, void **handle, void **userdata); -static FMOD_RESULT F_CALLBACK Memory_Close(void *handle, void *userdata); -static FMOD_RESULT F_CALLBACK Memory_Read(void *handle, void *buffer, unsigned int sizebytes, unsigned int *bytesread, void *userdata); -static FMOD_RESULT F_CALLBACK Memory_Seek(void *handle, unsigned int pos, void *userdata); - // EXTERNAL DATA DECLARATIONS ---------------------------------------------- EXTERN_CVAR (String, snd_output) @@ -613,6 +608,7 @@ bool FMODSoundRenderer::Init() int eval; SFXPaused = false; + DSPLocked = false; MusicGroup = NULL; SfxGroup = NULL; PausableSfx = NULL; @@ -620,8 +616,7 @@ bool FMODSoundRenderer::Init() WaterLP = NULL; WaterReverb = NULL; PrevEnvironment = DefaultEnvironments[0]; - DSPClockLo = 0; - DSPClockHi = 0; + DSPClock.AsOne = 0; ChannelGroupTargetUnit = NULL; Printf("I_InitSound: Initializing FMOD\n"); @@ -991,7 +986,7 @@ void FMODSoundRenderer::Shutdown() { unsigned int i; - S_StopAllChannels(); + //S_StopAllChannels(); if (MusicGroup != NULL) { @@ -1179,36 +1174,14 @@ FString FMODSoundRenderer::GatherStats() Sys->getChannelsPlaying(&channels); Sys->getCPUUsage(&dsp, &stream, &update, &total); - out.Format ("%d channels,%5.2f%% CPU (DSP:%2.2f%% Stream:%2.2f%% Update:%2.2f%%)", + out.Format ("%d channels,"TEXTCOLOR_YELLOW"%5.2f"TEXTCOLOR_NORMAL"%% CPU " + "(DSP:"TEXTCOLOR_YELLOW"%2.2f"TEXTCOLOR_NORMAL"%% " + "Stream:"TEXTCOLOR_YELLOW"%2.2f"TEXTCOLOR_NORMAL"%% " + "Update:"TEXTCOLOR_YELLOW"%2.2f"TEXTCOLOR_NORMAL"%%)", channels, total, dsp, stream, update); return out; } -//========================================================================== -// -// FMODSoundRenderer :: MovieDisableSound -// -//========================================================================== - -void FMODSoundRenderer::MovieDisableSound() -{ - I_ShutdownMusic(); - Shutdown(); -} - -//========================================================================== -// -// FMODSoundRenderer :: MovieResumeSound -// -//========================================================================== - -void FMODSoundRenderer::MovieResumeSound() -{ - Init(); - S_Init(); - S_RestartMusic(); -} - //========================================================================== // // FMODSoundRenderer :: SetSfxVolume @@ -1377,7 +1350,7 @@ SoundStream *FMODSoundRenderer::OpenStream(const char *filename_or_data, int fla // //========================================================================== -FSoundChan *FMODSoundRenderer::StartSound(sfxinfo_t *sfx, float vol, int pitch, int chanflags) +FSoundChan *FMODSoundRenderer::StartSound(sfxinfo_t *sfx, float vol, int pitch, int chanflags, FSoundChan *reuse_chan) { int id = int(sfx - &S_sfx[0]); FMOD_RESULT result; @@ -1417,8 +1390,9 @@ FSoundChan *FMODSoundRenderer::StartSound(sfxinfo_t *sfx, float vol, int pitch, chan->setFrequency(freq); } chan->setVolume(vol); + HandleChannelDelay(chan, reuse_chan, freq); chan->setPaused(false); - return CommonChannelSetup(chan); + return CommonChannelSetup(chan, reuse_chan); } DPrintf ("Sound %s failed to play: %d\n", sfx->name.GetChars(), result); @@ -1434,7 +1408,8 @@ FSoundChan *FMODSoundRenderer::StartSound(sfxinfo_t *sfx, float vol, int pitch, CVAR(Float, snd_3dspread, 180, 0) FSoundChan *FMODSoundRenderer::StartSound3D(sfxinfo_t *sfx, float vol, float distscale, - int pitch, int priority, float pos[3], float vel[3], sector_t *sector, int channum, int chanflags) + int pitch, int priority, float pos[3], float vel[3], sector_t *sector, int channum, int chanflags, + FSoundChan *reuse_chan) { int id = int(sfx - &S_sfx[0]); FMOD_RESULT result; @@ -1460,6 +1435,11 @@ FSoundChan *FMODSoundRenderer::StartSound3D(sfxinfo_t *sfx, float vol, float dis // Play it. GSfxInfo = sfx; GDistScale = distscale; + + // Experiments indicate that playSound will ignore priorities and always succeed + // as long as the paremeters are set properly. It will first try to kick out sounds + // with the same priority level but has no problem with kicking out sounds at + // higher priority levels if it needs to. result = Sys->playSound(FMOD_CHANNEL_FREE, (FMOD::Sound *)sfx->data, true, &chan); // Then set the priority back. @@ -1503,9 +1483,9 @@ FSoundChan *FMODSoundRenderer::StartSound3D(sfxinfo_t *sfx, float vol, float dis chan->set3DAttributes((FMOD_VECTOR *)pos, (FMOD_VECTOR *)vel); chan->set3DSpread(snd_3dspread); } - chan->setDelay(FMOD_DELAYTYPE_DSPCLOCK_START, DSPClockHi, DSPClockLo); + HandleChannelDelay(chan, reuse_chan, freq); chan->setPaused(false); - FSoundChan *schan = CommonChannelSetup(chan); + FSoundChan *schan = CommonChannelSetup(chan, reuse_chan); schan->DistanceScale = distscale; return schan; } @@ -1516,7 +1496,50 @@ FSoundChan *FMODSoundRenderer::StartSound3D(sfxinfo_t *sfx, float vol, float dis //========================================================================== // -// FMODSound :: SetChanHeadSettings +// FMODSoundRenderer :: HandleChannelDelay +// +// If the sound is restarting, seek it to its proper place. +// Otherwise, record its starting time. +// +//========================================================================== + +void FMODSoundRenderer::HandleChannelDelay(FMOD::Channel *chan, FSoundChan *reuse_chan, float freq) const +{ + if (reuse_chan != NULL) + { // Sound is being restarted, so seek it to the position + // it would be in now if it had never been evicted. + QWORD_UNION nowtime; + chan->getDelay(FMOD_DELAYTYPE_DSPCLOCK_START, &nowtime.Hi, &nowtime.Lo); + + // If the DSP is locked, the sounds are being restored, and + // the channel's start time is actually its seek position. + if (DSPLocked) + { + unsigned int seekpos = reuse_chan->StartTime.Lo; + if (seekpos > 0) + { + chan->setPosition(seekpos, FMOD_TIMEUNIT_PCM); + } + reuse_chan->StartTime.AsOne = QWORD(nowtime.AsOne - seekpos * OutputRate / freq); + } + else + { + QWORD difftime = nowtime.AsOne - reuse_chan->StartTime.AsOne; + if (difftime > 0) + { + chan->setPosition((unsigned int)(difftime / OutputRate), FMOD_TIMEUNIT_MS); + } + } + } + else + { + chan->setDelay(FMOD_DELAYTYPE_DSPCLOCK_START, DSPClock.Hi, DSPClock.Lo); + } +} + +//========================================================================== +// +// FMODSoundRenderer :: SetChanHeadSettings // // If this sound is played at the same coordinates as the listener, make // it head relative. Also, area sounds should use no 3D panning if close @@ -1567,6 +1590,11 @@ FMOD_MODE FMODSoundRenderer::SetChanHeadSettings(FMOD::Channel *chan, sfxinfo_t { cz = MAX(sec->ceilingplane.ZatPoint(cx, cy), players[consoleplayer].camera->z); } + else if (channum == CHAN_INTERIOR) + { + cz = clamp(players[consoleplayer].camera->z, sec->floorplane.ZatPoint(cx, cy), + sec->ceilingplane.ZatPoint(cx, cy)); + } else { cz = players[consoleplayer].camera->z; @@ -1620,9 +1648,21 @@ FMOD_MODE FMODSoundRenderer::SetChanHeadSettings(FMOD::Channel *chan, sfxinfo_t // //========================================================================== -FSoundChan *FMODSoundRenderer::CommonChannelSetup(FMOD::Channel *chan) const +FSoundChan *FMODSoundRenderer::CommonChannelSetup(FMOD::Channel *chan, FSoundChan *reuse_chan) const { - FSoundChan *schan = S_GetChannel(chan); + FSoundChan *schan; + + if (reuse_chan != NULL) + { + schan = reuse_chan; + schan->ChanFlags &= ~CHAN_EVICTED; + schan->SysChannel = chan; + } + else + { + schan = S_GetChannel(chan); + chan->getDelay(FMOD_DELAYTYPE_DSPCLOCK_START, &schan->StartTime.Hi, &schan->StartTime.Lo); + } chan->setUserData(schan); chan->setCallback(FMOD_CHANNEL_CALLBACKTYPE_END, ChannelEndCallback, 0); GSfxInfo = NULL; @@ -1642,8 +1682,38 @@ void FMODSoundRenderer::StopSound(FSoundChan *chan) if (chan->SysChannel != NULL) { + // S_EvictAllChannels() will set the CHAN_EVICTED flag to indicate + // that it wants to keep all the channel information around. + if (!(chan->ChanFlags & CHAN_EVICTED)) + { + chan->ChanFlags |= CHAN_FORGETTABLE; + } ((FMOD::Channel *)chan->SysChannel)->stop(); } + else + { + S_ReturnChannel(chan); + } +} + +//========================================================================== +// +// FMODSoundRenderer :: GetPosition +// +// Returns position of sound on this channel, in samples. +// +//========================================================================== + +unsigned int FMODSoundRenderer::GetPosition(FSoundChan *chan) +{ + unsigned int pos; + + if (chan == NULL || chan->SysChannel == NULL) + { + return 0; + } + ((FMOD::Channel *)chan->SysChannel)->getPosition(&pos, FMOD_TIMEUNIT_PCM); + return pos; } //========================================================================== @@ -1816,6 +1886,29 @@ void FMODSoundRenderer::UpdateListener() } } +//========================================================================== +// +// FMODSoundRenderer :: Sync +// +// Used by the save/load code to restart sounds at the same position they +// were in at the time of saving. Must not be nested. +// +//========================================================================== + +void FMODSoundRenderer::Sync(bool sync) +{ + DSPLocked = sync; + if (sync) + { + Sys->lockDSP(); + Sys->getDSPClock(&DSPClock.Hi, &DSPClock.Lo); + } + else + { + Sys->unlockDSP(); + } +} + //========================================================================== // // FMODSoundRenderer :: UpdateSounds @@ -1826,9 +1919,8 @@ void FMODSoundRenderer::UpdateSounds() { // Any sounds played between now and the next call to this function // will start exactly one tic from now. - Sys->getDSPClock(&DSPClockHi, &DSPClockLo); - FMOD_64BIT_ADD(DSPClockHi, DSPClockLo, 0, OutputRate / TICRATE); - + Sys->getDSPClock(&DSPClock.Hi, &DSPClock.Lo); + DSPClock.AsOne += OutputRate / TICRATE; Sys->update(); } @@ -2064,7 +2156,58 @@ FMOD_RESULT F_CALLBACK FMODSoundRenderer::ChannelEndCallback if (chan->getUserData((void **)&schan) == FMOD_OK && schan != NULL) { - S_ReturnChannel(schan); + bool evicted; + + // If the sound was stopped with GSnd->StopSound(), then we know + // it wasn't evicted. Otherwise, if it's looping, it must have + // been evicted. If it's not looping, then it was evicted if it + // didn't reach the end of its playback. + if (schan->ChanFlags & CHAN_FORGETTABLE) + { + evicted = false; + } + else if (schan->ChanFlags & (CHAN_LOOP | CHAN_EVICTED)) + { + evicted = true; + } + else + { + FMOD::Sound *sound; + unsigned int len, pos; + + evicted = false; // Assume not evicted + if (FMOD_OK == chan->getPosition(&pos, FMOD_TIMEUNIT_PCM)) + { + // If position is 0, then this sound either didn't have + // a chance to play at all, or it stopped normally. + if (pos == 0) + { + if (schan->ChanFlags & CHAN_JUSTSTARTED) + { + evicted = true; + } + } + else if (FMOD_OK == chan->getCurrentSound(&sound)) + { + if (FMOD_OK == sound->getLength(&len, FMOD_TIMEUNIT_PCM)) + { + if (pos < len) + { + evicted = true; + } + } + } + } + } + if (!evicted) + { + S_ReturnChannel(schan); + } + else + { + schan->ChanFlags |= CHAN_EVICTED; + schan->SysChannel = NULL; + } } return FMOD_OK; } diff --git a/src/sound/fmodsound.h b/src/sound/fmodsound.h index 1039ac9ff..ad0dc6049 100644 --- a/src/sound/fmodsound.h +++ b/src/sound/fmodsound.h @@ -25,24 +25,27 @@ public: void StopStream (SoundStream *stream); // Starts a sound. - FSoundChan *StartSound (sfxinfo_t *sfx, float vol, int pitch, int chanflags); - FSoundChan *StartSound3D (sfxinfo_t *sfx, float vol, float distscale, int pitch, int priority, float pos[3], float vel[3], sector_t *sector, int channum, int chanflags); + FSoundChan *StartSound (sfxinfo_t *sfx, float vol, int pitch, int chanflags, FSoundChan *reuse_chan); + FSoundChan *StartSound3D (sfxinfo_t *sfx, float vol, float distscale, int pitch, int priority, float pos[3], float vel[3], sector_t *sector, int channum, int chanflags, FSoundChan *reuse_chan); // Stops a sound channel. void StopSound (FSoundChan *chan); + // Returns position of sound on this channel, in samples. + unsigned int GetPosition(FSoundChan *chan); + + // Synchronizes following sound startups. + void Sync (bool sync); + // Pauses or resumes all sound effect channels. void SetSfxPaused (bool paused); + // Pauses or resumes *every* channel, including environmental reverb. void SetInactive (bool inactive); // Updates the position of a sound channel. void UpdateSoundParams3D (FSoundChan *chan, float pos[3], float vel[3]); - // For use by I_PlayMovie - void MovieDisableSound (); - void MovieResumeSound (); - void UpdateListener (); void UpdateSounds (); @@ -56,15 +59,16 @@ public: private: bool SFXPaused; bool InitSuccess; - unsigned int DSPClockLo; - unsigned int DSPClockHi; + bool DSPLocked; + QWORD_UNION DSPClock; int OutputRate; static FMOD_RESULT F_CALLBACK ChannelEndCallback (FMOD_CHANNEL *channel, FMOD_CHANNEL_CALLBACKTYPE type, int cmd, unsigned int data1, unsigned int data2); static float F_CALLBACK RolloffCallback(FMOD_CHANNEL *channel, float distance); - FSoundChan *CommonChannelSetup(FMOD::Channel *chan) const; + void HandleChannelDelay(FMOD::Channel *chan, FSoundChan *reuse_chan, float freq) const; + FSoundChan *CommonChannelSetup(FMOD::Channel *chan, FSoundChan *reuse_chan) const; FMOD_MODE SetChanHeadSettings(FMOD::Channel *chan, sfxinfo_t *sfx, float pos[3], int channum, int chanflags, sector_t *sec, FMOD_MODE oldmode) const; void DoLoad (void **slot, sfxinfo_t *sfx); void getsfx (sfxinfo_t *sfx); diff --git a/src/sound/i_sound.cpp b/src/sound/i_sound.cpp index 1a2681906..381338c7a 100644 --- a/src/sound/i_sound.cpp +++ b/src/sound/i_sound.cpp @@ -155,16 +155,16 @@ CCMD (snd_status) CCMD (snd_reset) { - SoundRenderer *snd = GSnd; - if (snd != NULL) + I_ShutdownMusic(); + S_EvictAllChannels(); + if (GSnd != NULL) { - snd->MovieDisableSound (); + delete GSnd; GSnd = NULL; } - I_InitSound (); - S_Init (); - S_RestartMusic (); - if (snd != NULL) delete snd; + I_InitSound(); + S_RestartMusic(); + S_RestoreEvictedChannels(); } CCMD (snd_listdrivers) diff --git a/src/sound/i_sound.h b/src/sound/i_sound.h index c9f23f9b8..3dff09436 100644 --- a/src/sound/i_sound.h +++ b/src/sound/i_sound.h @@ -89,12 +89,18 @@ public: virtual SoundStream *OpenStream (const char *filename, int flags, int offset, int length) = 0; // Starts a sound. - virtual FSoundChan *StartSound (sfxinfo_t *sfx, float vol, int pitch, int chanflags) = 0; - virtual FSoundChan *StartSound3D (sfxinfo_t *sfx, float vol, float distscale, int pitch, int priority, float pos[3], float vel[3], sector_t *sector, int channum, int chanflags) = 0; + virtual FSoundChan *StartSound (sfxinfo_t *sfx, float vol, int pitch, int chanflags, FSoundChan *reuse_chan) = 0; + virtual FSoundChan *StartSound3D (sfxinfo_t *sfx, float vol, float distscale, int pitch, int priority, float pos[3], float vel[3], sector_t *sector, int channum, int chanflags, FSoundChan *reuse_chan) = 0; // Stops a sound channel. virtual void StopSound (FSoundChan *chan) = 0; + // Returns position of sound on this channel, in samples. + virtual unsigned int GetPosition(FSoundChan *chan) = 0; + + // Synchronizes following sound startups. + virtual void Sync (bool sync) = 0; + // Pauses or resumes all sound effect channels. virtual void SetSfxPaused (bool paused) = 0; @@ -104,10 +110,6 @@ public: // Updates the volume, separation, and pitch of a sound channel. virtual void UpdateSoundParams3D (FSoundChan *chan, float pos[3], float vel[3]) = 0; - // For use by I_PlayMovie - virtual void MovieDisableSound () = 0; - virtual void MovieResumeSound () = 0; - virtual void UpdateListener () = 0; virtual void UpdateSounds () = 0; diff --git a/src/version.h b/src/version.h index 200f8c812..9f50d8f77 100644 --- a/src/version.h +++ b/src/version.h @@ -75,7 +75,7 @@ // SAVESIG should match SAVEVER. // MINSAVEVER is the minimum level snapshot version that can be loaded. -#define MINSAVEVER 1044 +#define MINSAVEVER 1055 #if SVN_REVISION_NUMBER < MINSAVEVER // Never write a savegame with a version lower than what we need diff --git a/src/win32/i_input.cpp b/src/win32/i_input.cpp index 4b7736c9f..0314fffc0 100644 --- a/src/win32/i_input.cpp +++ b/src/win32/i_input.cpp @@ -811,16 +811,19 @@ LRESULT CALLBACK WndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) } } - if(GSnd != NULL) + if (GSnd != NULL) { +#if 0 + // Do we actually need this here? if (!oldstate && SessionState) { - GSnd->MovieDisableSound (); + GSnd->SuspendSound (); } else if (oldstate && !SessionState) { GSnd->MovieResumeSound (); } +#endif } #ifdef _DEBUG char foo[256]; diff --git a/src/win32/i_movie.cpp b/src/win32/i_movie.cpp index 171c8bc88..74440654e 100644 --- a/src/win32/i_movie.cpp +++ b/src/win32/i_movie.cpp @@ -37,6 +37,10 @@ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ +#ifndef I_DO_NOT_LIKE_BIG_DOWNLOADS +#define I_DO_NOT_LIKE_BIG_DOWNLOADS +#endif + #define WIN32_LEAN_AND_MEAN #include #define USE_WINDOWS_DWORD