diff --git a/src/xrSound/Sound.h b/src/xrSound/Sound.h index e1aa7a4192b..064d7282552 100644 --- a/src/xrSound/Sound.h +++ b/src/xrSound/Sound.h @@ -166,6 +166,7 @@ class XRSOUND_API XR_NOVTABLE CSound_emitter virtual void set_range(float min, float max) = 0; virtual void set_volume(float vol) = 0; virtual void set_priority(float vol) = 0; + virtual void set_time(float t) = 0; //--#SM+#-- virtual void stop(bool isDeffered) = 0; virtual const CSound_params* get_params() = 0; virtual u32 play_time() = 0; @@ -352,6 +353,7 @@ class ref_sound void set_range(float min, float max) { VerSndUnlocked(); if (_feedback()) _feedback()->set_range(min, max); } void set_volume(float vol) { VerSndUnlocked(); if (_feedback()) _feedback()->set_volume(vol); } void set_priority(float p) { VerSndUnlocked(); if (_feedback()) _feedback()->set_priority(p); } + void set_time(float t) { VerSndUnlocked(); if (_feedback()) _feedback()->set_time(t); }; //--#SM+#-- const CSound_params* get_params() { diff --git a/src/xrSound/SoundRender_Core_Processor.cpp b/src/xrSound/SoundRender_Core_Processor.cpp index e1ed17a4c35..2ff7fa341af 100644 --- a/src/xrSound/SoundRender_Core_Processor.cpp +++ b/src/xrSound/SoundRender_Core_Processor.cpp @@ -26,6 +26,7 @@ void CSoundRender_Core::update(const Fvector& P, const Fvector& D, const Fvector return; Stats.Update.Begin(); isLocked = true; + Timer.time_factor(psSoundTimeFactor); //--#SM+#-- float new_tm = Timer.GetElapsed_sec(); fTimer_Delta = new_tm - fTimer_Value; //float dt = float(Timer_Delta)/1000.f; diff --git a/src/xrSound/SoundRender_Emitter.cpp b/src/xrSound/SoundRender_Emitter.cpp index 2463e500d15..c451457b835 100644 --- a/src/xrSound/SoundRender_Emitter.cpp +++ b/src/xrSound/SoundRender_Emitter.cpp @@ -27,6 +27,14 @@ void CSoundRender_Emitter::set_frequency(float scale) fTimeToStop = SoundRender->fTimer_Value + ((get_length_sec() - (SoundRender->fTimer_Value - fTimeStarted)) / (scale * sndTimeFactorKoeff)); } +// Перемотка звука на заданную секунду [rewind snd to target time] --#SM+#-- +void CSoundRender_Emitter::set_time(float t) +{ + VERIFY2(get_length_sec() >= t, "set_time: time is bigger than length of sound"); + clamp(t, 0.0f, get_length_sec()); + fTimeToRewind = t; +} + CSoundRender_Emitter::CSoundRender_Emitter() { #ifdef DEBUG @@ -53,6 +61,7 @@ CSoundRender_Emitter::CSoundRender_Emitter() fTimeStarted = 0.0f; fTimeToStop = 0.0f; fTimeToPropagade = 0.0f; + fTimeToRewind = 0.0f; //--#SM+#-- marker = 0xabababab; starting_delay = 0.f; priority_scale = 1.f; diff --git a/src/xrSound/SoundRender_Emitter.h b/src/xrSound/SoundRender_Emitter.h index a67a83ffc5f..f4400048a9f 100644 --- a/src/xrSound/SoundRender_Emitter.h +++ b/src/xrSound/SoundRender_Emitter.h @@ -65,6 +65,7 @@ class CSoundRender_Emitter final : public CSound_emitter float fTimeStarted; // time of "Start" float fTimeToStop; // time to "Stop" float fTimeToPropagade; + float fTimeToRewind; // --#SM+#-- u32 marker; void i_stop(); @@ -100,6 +101,7 @@ class CSoundRender_Emitter final : public CSound_emitter } void set_priority(float p) override { priority_scale = p; } + void set_time(float t) override; //--#SM+#-- const CSound_params* get_params() override { return &p_source; } void fill_block(void* ptr, u32 size); void fill_data(u8* ptr, u32 offset, u32 size); diff --git a/src/xrSound/SoundRender_Emitter_FSM.cpp b/src/xrSound/SoundRender_Emitter_FSM.cpp index 9a12b282d28..0e627545582 100644 --- a/src/xrSound/SoundRender_Emitter_FSM.cpp +++ b/src/xrSound/SoundRender_Emitter_FSM.cpp @@ -7,16 +7,16 @@ XRSOUND_API extern float psSoundCull; -inline u32 calc_cursor(const float& fTimeStarted, float& fTime, const float& fTimeTotal, const WAVEFORMATEX& wfx) +inline u32 calc_cursor(const float& fTimeStarted, float& fTime, const float& fTimeTotal, const float& fFreq, const WAVEFORMATEX& wfx) //--#SM+#-- { if (fTime < fTimeStarted) fTime = fTimeStarted; // Андрюха посоветовал, ассерт что ниже вылетел из за паузы как то хитро R_ASSERT((fTime - fTimeStarted) >= 0.0f); - while ((fTime - fTimeStarted) > fTimeTotal) // looped + while ((fTime - fTimeStarted) > fTimeTotal / fFreq) // looped { - fTime -= fTimeTotal; + fTime -= fTimeTotal / fFreq; } - u32 curr_sample_num = iFloor((fTime - fTimeStarted) * wfx.nSamplesPerSec); + u32 curr_sample_num = iFloor((fTime - fTimeStarted) * fFreq * wfx.nSamplesPerSec); return curr_sample_num * (wfx.wBitsPerSample / 8) * wfx.nChannels; } @@ -49,7 +49,7 @@ void CSoundRender_Emitter::update(float dt) if (iPaused) break; fTimeStarted = fTime; - fTimeToStop = fTime + (get_length_sec() / psSoundTimeFactor); + fTimeToStop = fTime + (get_length_sec() / p_source.freq); //--#SM+#-- fTimeToPropagade = fTime; fade_volume = 1.f; occluder_volume = SoundRender->get_occlusion(p_source.position, .2f, occluder); @@ -143,7 +143,7 @@ void CSoundRender_Emitter::update(float dt) } else { - u32 ptr = calc_cursor(fTimeStarted, fTime, get_length_sec(), source()->m_wformat); + u32 ptr = calc_cursor(fTimeStarted, fTime, get_length_sec(), p_source.freq, source()->m_wformat); //--#SM+#-- set_cursor(ptr); if (update_culling(dt)) @@ -196,7 +196,7 @@ void CSoundRender_Emitter::update(float dt) { // switch to: PLAY m_current_state = stPlayingLooped; // switch state - u32 ptr = calc_cursor(fTimeStarted, fTime, get_length_sec(), source()->m_wformat); + u32 ptr = calc_cursor(fTimeStarted, fTime, get_length_sec(), p_source.freq, source()->m_wformat); //--#SM+#-- set_cursor(ptr); SoundRender->i_start(this); @@ -204,6 +204,56 @@ void CSoundRender_Emitter::update(float dt) break; } + //--#SM+# Begin-- + // hard rewind + switch (m_current_state) + { + case stStarting: + case stStartingLooped: + case stPlaying: + case stSimulating: + case stPlayingLooped: + case stSimulatingLooped: + if (fTimeToRewind > 0.0f) + { + float fLength = get_length_sec(); + bool bLooped = (fTimeToStop == 0xffffffff); + + R_ASSERT2(fLength >= fTimeToRewind, "set_time: target time is bigger than length of sound"); + + float fRemainingTime = (fLength - fTimeToRewind) / p_source.freq; + float fPastTime = fTimeToRewind / p_source.freq; + + fTimeStarted = SoundRender->fTimer_Value - fPastTime; + fTimeToPropagade = fTimeStarted; //--> For AI events + + if (fTimeStarted < 0.0f) + { + Log("fTimer_Value = ", SoundRender->fTimer_Value); + Log("fTimeStarted = ", fTimeStarted); + Log("fRemainingTime = ", fRemainingTime); + Log("fPastTime = ", fPastTime); + R_ASSERT2(fTimeStarted >= 0.0f, "Possible error in sound rewind logic! See log."); + + fTimeStarted = SoundRender->fTimer_Value; + fTimeToPropagade = fTimeStarted; + } + + if (!bLooped) + { + //--> Пересчитываем время, когда звук должен остановиться [recalculate stop time] + fTimeToStop = SoundRender->fTimer_Value + fRemainingTime; + } + + u32 ptr = calc_cursor(fTimeStarted, fTime, fLength, p_source.freq, source()->m_wformat); + set_cursor(ptr); + + fTimeToRewind = 0.0f; + } + default: break; + } + //--#SM+# End-- + // if deffered stop active and volume==0 -> physically stop sound if (bStopping && fis_zero(fade_volume)) i_stop(); diff --git a/src/xrSound/SoundRender_TargetA.cpp b/src/xrSound/SoundRender_TargetA.cpp index b12db7080c7..20570b01bdf 100644 --- a/src/xrSound/SoundRender_TargetA.cpp +++ b/src/xrSound/SoundRender_TargetA.cpp @@ -191,17 +191,19 @@ void CSoundRender_TargetA::fill_parameters() } VERIFY2(m_pEmitter, SE->source()->file_name()); + float _pitch = m_pEmitter->p_source.freq; - clamp(_pitch, EPS_L, 2.f); + clamp(_pitch, EPS_L, 100.f); //--#SM+#-- Increase sound frequency (speed) limit if (m_pEmitter->bIsIgnoreTimeFactor && !fsimilar(cache_pitch, _pitch)) { - cache_pitch = 1.f; + cache_pitch = _pitch; A_CHK(alSourcef(pSource, AL_PITCH, cache_pitch)); } else if (!m_pEmitter->bIsIgnoreTimeFactor && !fsimilar(cache_pitch, _pitch * psSoundTimeFactor)) { time_played = time_played + (SoundRender->fTimer_Value - last_pitch_change_time) * cache_pitch; cache_pitch = _pitch * psSoundTimeFactor; + // Only update time to stop for non-looped sounds if (!m_pEmitter->iPaused && (m_pEmitter->m_current_state == CSoundRender_Emitter::stStarting || m_pEmitter->m_current_state == CSoundRender_Emitter::stPlaying || m_pEmitter->m_current_state == CSoundRender_Emitter::stSimulating)) m_pEmitter->fTimeToStop = SoundRender->fTimer_Value + ((m_pEmitter->get_length_sec() - time_played) / cache_pitch); @@ -209,7 +211,6 @@ void CSoundRender_TargetA::fill_parameters() last_pitch_change_time = SoundRender->fTimer_Value; } - VERIFY2(m_pEmitter, SE->source()->file_name()); }