From 807eecd4822cf340e02d1701135d14f94cf91127 Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Tue, 5 Dec 2017 19:51:36 +0100 Subject: [PATCH] build 171205. support for random sound sets, explicit range-driven sound attenuation --- DynObj.cpp | 143 ++++++++++++++++++++++++---------------------- Train.cpp | 7 ++- audiorenderer.cpp | 22 ++++++- audiorenderer.h | 3 +- sound.cpp | 34 +++++++++-- sound.h | 3 + version.h | 2 +- 7 files changed, 135 insertions(+), 79 deletions(-) diff --git a/DynObj.cpp b/DynObj.cpp index 7f629cb3..076dd4c2 100644 --- a/DynObj.cpp +++ b/DynObj.cpp @@ -16,6 +16,7 @@ http://mozilla.org/MPL/2.0/. #include "DynObj.h" #include "simulation.h" +#include "train.h" #include "Globals.h" #include "Timer.h" #include "logs.h" @@ -3745,73 +3746,72 @@ void TDynamicObject::RenderSounds() { } /* // NOTE: experimentally disabled to see if it's still used anywhere - if (MoverParameters->TrainType == dt_PseudoDiesel) - { - // ABu: udawanie woodwarda dla lok. spalinowych - // jesli silnik jest podpiety pod dzwiek przetwornicy + if (MoverParameters->TrainType == dt_PseudoDiesel) + { + // ABu: udawanie woodwarda dla lok. spalinowych + // jesli silnik jest podpiety pod dzwiek przetwornicy - // glosnosc zalezy od stosunku mocy silnika el. do mocy max - double eng_vol; - if (MoverParameters->Power > 1) - // 0.85+0.000015*(...) - eng_vol = 0.8 + 0.00002 * (MoverParameters->EnginePower / MoverParameters->Power); - else - eng_vol = 1; + // glosnosc zalezy od stosunku mocy silnika el. do mocy max + double eng_vol; + if (MoverParameters->Power > 1) + // 0.85+0.000015*(...) + eng_vol = 0.8 + 0.00002 * (MoverParameters->EnginePower / MoverParameters->Power); + else + eng_vol = 1; - eng_dfrq = eng_dfrq + (eng_vol_act - eng_vol); - if (eng_dfrq > 0) - { - eng_dfrq = eng_dfrq - 0.025 * dt; - if (eng_dfrq < 0.025 * dt) - eng_dfrq = 0; - } - else if (eng_dfrq < 0) - { - eng_dfrq = eng_dfrq + 0.025 * dt; - if (eng_dfrq > -0.025 * dt) - eng_dfrq = 0; - } - double defrot; - if (MoverParameters->MainCtrlPos != 0) - { - double CtrlPos = MoverParameters->MainCtrlPos; - double CtrlPosNo = MoverParameters->MainCtrlPosNo; - // defrot=1+0.4*(CtrlPos/CtrlPosNo); - defrot = 1 + 0.5 * (CtrlPos / CtrlPosNo); - } - else - defrot = 1; + eng_dfrq = eng_dfrq + (eng_vol_act - eng_vol); + if (eng_dfrq > 0) + { + eng_dfrq = eng_dfrq - 0.025 * dt; + if (eng_dfrq < 0.025 * dt) + eng_dfrq = 0; + } + else if (eng_dfrq < 0) + { + eng_dfrq = eng_dfrq + 0.025 * dt; + if (eng_dfrq > -0.025 * dt) + eng_dfrq = 0; + } + double defrot; + if (MoverParameters->MainCtrlPos != 0) + { + double CtrlPos = MoverParameters->MainCtrlPos; + double CtrlPosNo = MoverParameters->MainCtrlPosNo; + // defrot=1+0.4*(CtrlPos/CtrlPosNo); + defrot = 1 + 0.5 * (CtrlPos / CtrlPosNo); + } + else + defrot = 1; - if (eng_frq_act < defrot) - { - // if (MoverParameters->MainCtrlPos==1) eng_frq_act=eng_frq_act+0.1*dt; - eng_frq_act = eng_frq_act + 0.4 * dt; // 0.05 - if (eng_frq_act > defrot - 0.4 * dt) - eng_frq_act = defrot; - } - else if (eng_frq_act > defrot) - { - eng_frq_act = eng_frq_act - 0.1 * dt; // 0.05 - if (eng_frq_act < defrot + 0.1 * dt) - eng_frq_act = defrot; - } - sConverter.UpdateAF(eng_vol_act, eng_frq_act + eng_dfrq, MechInside, GetPosition()); - // udawanie turbo: (6.66*(eng_vol-0.85)) - if (eng_turbo > 6.66 * (eng_vol - 0.8) + 0.2 * dt) - eng_turbo = eng_turbo - 0.2 * dt; // 0.125 - else if (eng_turbo < 6.66 * (eng_vol - 0.8) - 0.4 * dt) - eng_turbo = eng_turbo + 0.4 * dt; // 0.333 - else - eng_turbo = 6.66 * (eng_vol - 0.8); + if (eng_frq_act < defrot) + { + // if (MoverParameters->MainCtrlPos==1) eng_frq_act=eng_frq_act+0.1*dt; + eng_frq_act = eng_frq_act + 0.4 * dt; // 0.05 + if (eng_frq_act > defrot - 0.4 * dt) + eng_frq_act = defrot; + } + else if (eng_frq_act > defrot) + { + eng_frq_act = eng_frq_act - 0.1 * dt; // 0.05 + if (eng_frq_act < defrot + 0.1 * dt) + eng_frq_act = defrot; + } + sConverter.UpdateAF(eng_vol_act, eng_frq_act + eng_dfrq, MechInside, GetPosition()); + // udawanie turbo: (6.66*(eng_vol-0.85)) + if (eng_turbo > 6.66 * (eng_vol - 0.8) + 0.2 * dt) + eng_turbo = eng_turbo - 0.2 * dt; // 0.125 + else if (eng_turbo < 6.66 * (eng_vol - 0.8) - 0.4 * dt) + eng_turbo = eng_turbo + 0.4 * dt; // 0.333 + else + eng_turbo = 6.66 * (eng_vol - 0.8); - sTurbo.TurnOn(MechInside, GetPosition()); - // sTurbo.UpdateAF(eng_turbo,0.7+(eng_turbo*0.6),MechInside,GetPosition()); - sTurbo.UpdateAF(3 * eng_turbo - 1, 0.4 + eng_turbo * 0.4, MechInside, GetPosition()); - eng_vol_act = eng_vol; - // eng_frq_act=eng_frq; - } + sTurbo.TurnOn(MechInside, GetPosition()); + // sTurbo.UpdateAF(eng_turbo,0.7+(eng_turbo*0.6),MechInside,GetPosition()); + sTurbo.UpdateAF(3 * eng_turbo - 1, 0.4 + eng_turbo * 0.4, MechInside, GetPosition()); + eng_vol_act = eng_vol; + // eng_frq_act=eng_frq; + } */ - if( ( MoverParameters->EngineType == ElectricSeriesMotor ) || ( MoverParameters->EngineType == ElectricInductionMotor ) ) { @@ -4009,8 +4009,8 @@ void TDynamicObject::RenderSounds() { sSand.stop(); } - if( /*( false == mvOccupied->SlippingWheels ) - &&*/ ( MoverParameters->UnitBrakeForce > 10.0 ) + if( //( false == mvOccupied->SlippingWheels ) && + ( MoverParameters->UnitBrakeForce > 10.0 ) && ( GetVelocity() > 0.05 ) ) { rsBrake @@ -4030,8 +4030,8 @@ void TDynamicObject::RenderSounds() { } // McZapkie-280302 - pisk mocno zacisnietych hamulcow - if( /*( false == MoverParameters->SlippingWheels ) - &&*/ ( MoverParameters->UnitBrakeForce > rsPisk.m_amplitudefactor ) + if( //( false == MoverParameters->SlippingWheels ) && + ( MoverParameters->UnitBrakeForce > rsPisk.m_amplitudefactor ) && ( MoverParameters->Vel > 2.5 ) ) { rsPisk @@ -4118,7 +4118,13 @@ void TDynamicObject::RenderSounds() { } // szum w czasie jazdy - if( GetVelocity() > 0.5 ) { + if( ( GetVelocity() > 0.5 ) + && ( // compound test whether the vehicle belongs to user-driven consist (as these don't emit outer noise in cab view) + true == FreeFlyModeFlag ? true : // in external view all vehicles emit outer noise + // Global::pWorld->train() == nullptr ? true : // (can skip this check, with no player train the external view is a given) + ctOwner == nullptr ? true : // standalone vehicle, can't be part of user-driven train + ctOwner != Global::pWorld->train()->Dynamic()->ctOwner ? true : // confirmed isn't a part of the user-driven train + false ) ) { volume = rsOuterNoise.m_amplitudefactor * MoverParameters->Vel + rsOuterNoise.m_amplitudeoffset; frequency = rsOuterNoise.m_frequencyfactor * MoverParameters->Vel + rsOuterNoise.m_frequencyoffset; @@ -4306,6 +4312,7 @@ void TDynamicObject::RenderSounds() { MoverParameters->EventFlag = false; } + } // McZapkie-250202 @@ -5018,7 +5025,7 @@ void TDynamicObject::LoadMMediaFile( std::string BaseDir, std::string TypeName, { sound_placement::external, static_cast( dSDist ) } }; axle.clatter.deserialize( parser, sound_type::single ); axle.clatter.owner( this ); - axle.clatter.offset( { 0, 0, -axle.offset } ); + axle.clatter.offset( { 0, 0, -axle.offset } ); // vehicle faces +Z in 'its' space, for axle locations negative value means ahead of centre m_axlesounds.emplace_back( axle ); } // arrange the axles in case they're listed out of order diff --git a/Train.cpp b/Train.cpp index fa9ccee0..dd43dbf1 100644 --- a/Train.cpp +++ b/Train.cpp @@ -5163,7 +5163,7 @@ TTrain::update_sounds( double const Deltatime ) { if( ( mvOccupied->BrakeHandle == FV4a ) || ( mvOccupied->BrakeHandle == FVel6 ) ) { // upuszczanie z PG - fPPress = interpolate( fPPress, mvOccupied->Handle->GetSound( s_fv4a_b ), 0.05 ); + fPPress = interpolate( fPPress, static_cast( mvOccupied->Handle->GetSound( s_fv4a_b ) ), 0.05f ); volume = ( fPPress > 0 ? rsHiss.m_amplitudefactor * fPPress * 0.25 : @@ -5177,7 +5177,7 @@ TTrain::update_sounds( double const Deltatime ) { rsHiss.stop(); } // napelnianie PG - fNPress = interpolate( fNPress, mvOccupied->Handle->GetSound( s_fv4a_u ), 0.25 ); + fNPress = interpolate( fNPress, static_cast( mvOccupied->Handle->GetSound( s_fv4a_u ) ), 0.25f ); volume = ( fNPress > 0 ? rsHissU.m_amplitudefactor * fNPress : @@ -5269,7 +5269,8 @@ TTrain::update_sounds( double const Deltatime ) { } // szum w czasie jazdy - if( DynamicObject->GetVelocity() > 0.5 ) { + if( ( false == FreeFlyModeFlag ) + && ( DynamicObject->GetVelocity() > 0.5 ) ) { volume = rsRunningNoise.m_amplitudefactor * mvOccupied->Vel + rsRunningNoise.m_amplitudeoffset; auto frequency { rsRunningNoise.m_frequencyfactor * mvOccupied->Vel + rsRunningNoise.m_frequencyoffset }; diff --git a/audiorenderer.cpp b/audiorenderer.cpp index f7df7d40..c25390cb 100644 --- a/audiorenderer.cpp +++ b/audiorenderer.cpp @@ -100,7 +100,7 @@ openal_source::sync_with( sound_properties const &State ) { auto const cutoffrange = ( is_multipart ? EU07_SOUND_CUTOFFRANGE : // we keep multi-part sounds around longer, to minimize restarts as the sounds get out and back in range - sound_range * 7.5f ); + sound_range * 5.0f ); if( glm::length2( sound_distance ) > std::min( ( cutoffrange * cutoffrange ), ( EU07_SOUND_CUTOFFRANGE * EU07_SOUND_CUTOFFRANGE ) ) ) { stop(); is_synced = false; // flag sync failure for the controller @@ -124,6 +124,24 @@ openal_source::sync_with( sound_properties const &State ) { ::alSourcef( id, AL_GAIN, properties.gain * properties.soundproofing * Global::AudioVolume ); } + if( sound_range > 0 ) { + auto const rangesquared { sound_range * sound_range }; + auto const distancesquared { glm::length2( sound_distance ) }; + if( ( distancesquared > rangesquared ) + || ( false == is_in_range ) ) { + // if the emitter is outside of its nominal hearing range or was outside of it during last check + // adjust the volume to a suitable fraction of nominal value + auto const fadedistance { sound_range * 0.75 }; + auto const rangefactor { + interpolate( + 1.f, 0.f, + clamp( + ( distancesquared - rangesquared ) / ( fadedistance * fadedistance ), + 0.f, 1.f ) ) }; + ::alSourcef( id, AL_GAIN, properties.gain * properties.soundproofing * rangefactor * Global::AudioVolume ); + } + is_in_range = ( distancesquared <= rangesquared ); + } // pitch if( State.pitch != properties.pitch ) { // pitch value has changed @@ -148,7 +166,7 @@ openal_source::range( float const Range ) { Range : 5 ) }; // range of -1 means sound of unlimited range, positioned at the listener ::alSourcef( id, AL_REFERENCE_DISTANCE, range * ( 1.f / 16.f ) ); - ::alSourcef( id, AL_ROLLOFF_FACTOR, 1.5f ); + ::alSourcef( id, AL_ROLLOFF_FACTOR, 1.75f ); } // sets modifier applied to the pitch of sounds emitted by the source diff --git a/audiorenderer.h b/audiorenderer.h index 7426014c..efed232f 100644 --- a/audiorenderer.h +++ b/audiorenderer.h @@ -56,7 +56,7 @@ struct openal_source { for( auto const buffer : buffers ) { bufferids.emplace_back( audio::renderer.buffer( buffer ).id ); } if( id != audio::null_resource ) { - ::alSourceQueueBuffers( id, bufferids.size(), bufferids.data() ); + ::alSourceQueueBuffers( id, static_cast( bufferids.size() ), bufferids.data() ); ::alSourceRewind( id ); } return *this; } // starts playback of queued buffers @@ -91,6 +91,7 @@ private: float pitch_variation { 1.f }; // emitter-specific variation of the base pitch float sound_range { 50.f }; // cached audible range of the emitted samples glm::vec3 sound_distance; // cached distance between sound and the listener + bool is_in_range { false }; // helper, indicates the source was recently within audible range bool is_multipart { false }; // multi-part sounds are kept alive at longer ranges }; diff --git a/sound.cpp b/sound.cpp index 5eeab001..fb8cfcfb 100644 --- a/sound.cpp +++ b/sound.cpp @@ -41,14 +41,14 @@ sound_source::deserialize( cParser &Input, sound_type const Legacytype, int cons switch( Legacytype ) { case sound_type::single: { // single sample only - m_soundmain.buffer = audio::renderer.fetch_buffer( Input.getToken( true, "\n\r\t ,;" ) ); + m_soundmain.buffer = audio::renderer.fetch_buffer( deserialize_filename( Input ) ); break; } case sound_type::multipart: { // three samples: start, middle, stop - m_soundbegin.buffer = audio::renderer.fetch_buffer( Input.getToken( true, "\n\r\t ,;" ) ); - m_soundmain.buffer = audio::renderer.fetch_buffer( Input.getToken( true, "\n\r\t ,;" ) ); - m_soundend.buffer = audio::renderer.fetch_buffer( Input.getToken( true, "\n\r\t ,;" ) ); + m_soundbegin.buffer = audio::renderer.fetch_buffer( deserialize_filename( Input ) ); + m_soundmain.buffer = audio::renderer.fetch_buffer( deserialize_filename( Input ) ); + m_soundend.buffer = audio::renderer.fetch_buffer( deserialize_filename( Input ) ); break; } default: { @@ -76,6 +76,32 @@ sound_source::deserialize( cParser &Input, sound_type const Legacytype, int cons return *this; } +// extracts name of the sound file from provided data stream +std::string +sound_source::deserialize_filename( cParser &Input ) { + + auto token { Input.getToken( true, "\n\r\t ,;" ) }; + if( token != "[" ) { + // simple case, single file + return token; + } + // if instead of filename we've encountered '[' this marks beginning of random sound set + // we retrieve all filenames from the set, then return a random one + std::vector filenames; + while( ( ( token = Input.getToken( true, "\n\r\t ,;" ) ) != "" ) + && ( token != "]" ) ) { + filenames.emplace_back( token ); + } + if( false == filenames.empty() ) { + std::shuffle( std::begin( filenames ), std::end( filenames ), Global::random_engine ); + return filenames.front(); + } + else { + // shouldn't ever get here but, eh + return ""; + } +} + // issues contextual play commands for the audio renderer void sound_source::play( int const Flags ) { diff --git a/sound.h b/sound.h index f79eef83..b19c3e7d 100644 --- a/sound.h +++ b/sound.h @@ -115,6 +115,9 @@ private: }; // methods + // extracts name of the sound file from provided data stream + std::string + deserialize_filename( cParser &Input ); void update_counter( audio::buffer_handle const Buffer, int const Value ); void diff --git a/version.h b/version.h index 9e45ba55..fa045cb1 100644 --- a/version.h +++ b/version.h @@ -1,5 +1,5 @@ #pragma once #define VERSION_MAJOR 17 -#define VERSION_MINOR 1204 +#define VERSION_MINOR 1205 #define VERSION_REVISION 0