diff --git a/DynObj.cpp b/DynObj.cpp index 61d69e0b..1fd73538 100644 --- a/DynObj.cpp +++ b/DynObj.cpp @@ -1666,14 +1666,12 @@ TDynamicObject::TDynamicObject() { //smMechanik0 = smMechanik1 = NULL; smBuforLewy[0] = smBuforLewy[1] = NULL; smBuforPrawy[0] = smBuforPrawy[1] = NULL; - enginevolume = 0; smBogie[0] = smBogie[1] = NULL; bogieRot[0] = bogieRot[1] = vector3(0, 0, 0); modelRot = vector3(0, 0, 0); eng_vol_act = 0.8; eng_dfrq = 0; eng_frq_act = 1; - eng_turbo = 0; cp1 = cp2 = sp1 = sp2 = 0; iDirection = 1; // stoi w kierunku tradycyjnym (0, gdy jest odwrócony) iAxleFirst = 0; // numer pierwszej osi w kierunku ruchu (przełączenie @@ -3604,350 +3602,30 @@ void TDynamicObject::TurnOff() // przeliczanie dźwięków, bo będzie słychać bez wyświetlania sektora z pojazdem void TDynamicObject::RenderSounds() { - // McZapkie-010302: ulepszony dzwiek silnika - double frequency { 1.0 }; - double volume { 0.0 }; - double const dt { Timer::GetDeltaRenderTime() }; - if( Global::iPause != 0 ) { return; } - // engine sounds - if( MoverParameters->Power > 0 ) { + double const dt { Timer::GetDeltaRenderTime() }; + double volume { 0.0 }; + double frequency { 1.0 }; - if( ( true == MoverParameters->Mains ) - || ( MoverParameters->EngineType == DieselEngine ) ) { - - if( ( std::fabs( MoverParameters->enrot ) > 0.01 ) - // McZapkie-280503: zeby dla dumb dzialal silnik na jalowych obrotach - || ( MoverParameters->EngineType == Dumb ) ) { - - // frequency calculation - auto normalizer { 1.f }; - // for combined sound engine we calculate sound point in rpm, to make .mmd files setup easier - switch( MoverParameters->EngineType ) { - case DieselElectric: { - if( true == sConverter.is_combined() ) { - normalizer = 60.f * 0.01f; - } - break; - } - default: { - if( true == rsSilnik.is_combined() ) { - normalizer = 60.f * 0.01f; - } - break; - } - } - frequency = rsSilnik.m_frequencyfactor * std::abs( MoverParameters->enrot ) * normalizer + rsSilnik.m_frequencyoffset; - if( MoverParameters->EngineType == Dumb ) { - frequency -= 0.2 * MoverParameters->EnginePower / ( 1 + MoverParameters->Power * 1000 ); - } - - // base volume calculation - switch( MoverParameters->EngineType ) { - case DieselEngine: { - if( MoverParameters->enrot > 0.0 ) { - if( MoverParameters->EnginePower > 0 ) { - volume = rsSilnik.m_amplitudefactor * MoverParameters->dizel_fill + rsSilnik.m_amplitudeoffset; - } - else { - volume = rsSilnik.m_amplitudefactor * std::fabs( MoverParameters->enrot / MoverParameters->dizel_nmax ) + rsSilnik.m_amplitudeoffset * 0.9f; - } - } - else { - volume = 0.f; - } - break; - } - case DieselElectric: { - volume = - rsSilnik.m_amplitudefactor * ( MoverParameters->EnginePower / 1000 / MoverParameters->Power ) - + 0.2 * ( MoverParameters->enrot * 60 ) / ( MoverParameters->DElist[ MoverParameters->MainCtrlPosNo ].RPM ) - + rsSilnik.m_amplitudeoffset; - break; - } - case ElectricInductionMotor: { - volume = - rsSilnik.m_amplitudefactor * ( MoverParameters->EnginePower + std::fabs( MoverParameters->enrot * 2 ) ) - + rsSilnik.m_amplitudeoffset; - break; - } - // NOTE: default case also covers electric motors - default: { - volume = - rsSilnik.m_amplitudefactor * ( MoverParameters->EnginePower / 1000 + std::fabs( MoverParameters->enrot ) * 60.0 ) - + rsSilnik.m_amplitudeoffset; - break; - } - } - - if( MoverParameters->EngineType == ElectricSeriesMotor ) { - - // volume variation - if( ( volume < 1.0 ) - && ( MoverParameters->EnginePower < 100 ) ) { - - auto const volumevariation{ Random( 100 ) * MoverParameters->enrot / ( 1 + MoverParameters->nmax ) }; - if( volumevariation < 2 ) { - volume += volumevariation / 200; - } - } - - if( ( MoverParameters->DynamicBrakeFlag ) - && ( MoverParameters->EnginePower > 0.1 ) ) { - // Szociu - 29012012 - jeżeli uruchomiony jest hamulec elektrodynamiczny, odtwarzany jest dźwięk silnika - volume += 0.8; - } - } - - // volume environmental factor - switch( MyTrack->eEnvironment ) { - case e_tunnel: { - volume += 0.1; - break; - } - case e_canyon: { - volume += 0.05; - break; - } - default: { - break; - } - } - - if( enginevolume >= 0.05 ) { - - if( MoverParameters->EngineType != DieselElectric ) { - - rsSilnik - .pitch( frequency ) - .gain( enginevolume ) - .play( sound_flags::exclusive | sound_flags::looping ); - } - else { - - if( MoverParameters->ConverterFlag ) { - - sConverter - .pitch( frequency ) - .gain( volume ) - .play( sound_flags::exclusive | sound_flags::looping ); - - float fincvol { 0 }; - if( MoverParameters->enrot * 60 > MoverParameters->DElist[ 0 ].RPM ) { - - fincvol = ( MoverParameters->DElist[ MoverParameters->MainCtrlPos ].RPM - ( MoverParameters->enrot * 60 ) ); - fincvol /= ( 0.05 * MoverParameters->DElist[ 0 ].RPM ); - } - - if( fincvol > 0.02 ) { - rsDieselInc - .gain( fincvol ) - .play( sound_flags::exclusive | sound_flags::looping ); - } - else { - rsDieselInc.stop(); - } - } - } - } - } - else { - rsSilnik.stop(); - } - } - enginevolume = ( enginevolume + volume ) * 0.5; - if( enginevolume < 0.05 ) { - rsSilnik.stop(); - } -/* -// 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 - - // 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; - - 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; - } -*/ - if( ( MoverParameters->EngineType == ElectricSeriesMotor ) - || ( MoverParameters->EngineType == ElectricInductionMotor ) ) { - - if( MoverParameters->RventRot > 0.1 ) { - // play ventilator sound if the ventilators are rotating fast enough... - volume = ( - MoverParameters->EngineType == ElectricInductionMotor ? - rsWentylator.m_amplitudefactor * std::sqrt( std::fabs( MoverParameters->dizel_fill ) ) + rsWentylator.m_amplitudeoffset : - rsWentylator.m_amplitudefactor * MoverParameters->RventRot + rsWentylator.m_amplitudeoffset ); - - rsWentylator - .pitch( rsWentylator.m_frequencyfactor * MoverParameters->RventRot + rsWentylator.m_frequencyoffset ) - .gain( volume ) - .play( sound_flags::exclusive | sound_flags::looping ); - } - else { - // ...otherwise shut down the sound - rsWentylator.stop(); - } - } - - - if( MoverParameters->TrainType == dt_ET40 ) { - if( MoverParameters->Vel > 0.1 ) { - rsPrzekladnia - .pitch( rsPrzekladnia.m_frequencyfactor * ( MoverParameters->Vel ) + rsPrzekladnia.m_frequencyoffset ) - .gain( rsPrzekladnia.m_amplitudefactor * ( MoverParameters->Vel ) + rsPrzekladnia.m_amplitudeoffset ) - .play( sound_flags::exclusive | sound_flags::looping ); - } - else { - rsPrzekladnia.stop(); - } - } - - - if( MoverParameters->dizel_engage > 0.1 ) { - if( std::abs( MoverParameters->dizel_engagedeltaomega ) > 0.2 ) { - - frequency = rsEngageSlippery.m_frequencyfactor * std::fabs( MoverParameters->dizel_engagedeltaomega ) + rsEngageSlippery.m_frequencyoffset; - volume = rsEngageSlippery.m_amplitudefactor * ( MoverParameters->dizel_engage ) + rsEngageSlippery.m_amplitudeoffset; - } - else { - frequency = 1.f; // rsEngageSlippery.FA+0.7*rsEngageSlippery.FM*(fabs(mvControlled->enrot)+mvControlled->nmax); - volume = ( - MoverParameters->dizel_engage > 0.2 ? - 0.2 * rsEngageSlippery.m_amplitudefactor * ( MoverParameters->enrot / MoverParameters->nmax ) + rsEngageSlippery.m_amplitudeoffset : - 0.f ); - } - rsEngageSlippery - .pitch( frequency ) - .gain( volume ) - .play( sound_flags::exclusive | sound_flags::looping ); - } - else { - rsEngageSlippery.stop(); - } - - - // youBy - przenioslem, bo diesel tez moze miec turbo - if( MoverParameters->TurboTest > 0 ) { - // udawanie turbo: - auto const goalpitch { 6.66 * ( enginevolume - 0.8 ) }; - auto const goalvolume{ 3 * eng_turbo - 1 }; - auto const currentvolume { sTurbo.gain() }; - auto const changerate{ 0.4 * dt }; - - if( ( MoverParameters->MainCtrlPos >= MoverParameters->TurboTest ) - && ( MoverParameters->enrot > 0.1 ) ) { - - eng_turbo = ( - eng_turbo > goalpitch ? - std::max( goalpitch, eng_turbo - changerate * 0.5 ) : - std::min( goalpitch, eng_turbo + changerate ) ); - - volume = ( - currentvolume > goalvolume ? - std::max( goalvolume, currentvolume - changerate ) : - std::min( goalvolume, currentvolume + changerate ) ); - - sTurbo - .pitch( eng_turbo * 0.4 + 0.4 ) - .gain( volume ) - .play( sound_flags::exclusive | sound_flags::looping ); - } - else { - eng_turbo = std::max( goalpitch, eng_turbo - changerate * 0.5 ); - volume = std::max( 0.0, sTurbo.gain() - 2.0 * dt ); - if( volume > 0.05 ) { - sTurbo - .pitch( 0.4 + eng_turbo * 0.4 ) - .gain( volume ); - } - else { - sTurbo.stop(); - } - } - } - - - // diesel startup - if( MoverParameters->EngineType == DieselEngine ) { - if( true == MoverParameters->dizel_enginestart ) { - dsbDieselIgnition.play( sound_flags::exclusive | sound_flags::looping ); - } - else { - dsbDieselIgnition.stop(); - } - } - - } // if enginepower + m_powertrainsounds.render( *MoverParameters, dt ); // NBMX dzwiek przetwornicy if( MoverParameters->ConverterFlag ) { - sConverter.play( sound_flags::exclusive | sound_flags::looping ); + frequency = ( + MoverParameters->EngineType == ElectricSeriesMotor ? + MoverParameters->Voltage / ( MoverParameters->NominalVoltage * MoverParameters->RList[ MoverParameters->RlistSize ].Mn ) : + 1.0 ); + frequency = sConverter.m_frequencyoffset + sConverter.m_frequencyfactor * frequency; + sConverter + .pitch( clamp( frequency, 0.5, 1.25 ) ) // arbitrary limits ) + .play( sound_flags::exclusive | sound_flags::looping ); } else { sConverter.stop(); } - if( MoverParameters->VeselVolume != 0 ) { + if( MoverParameters->VeselVolume > 0 ) { // McZapkie! - dzwiek compressor.wav tylko gdy dziala sprezarka if( MoverParameters->CompressorFlag ) { sCompressor.play( sound_flags::exclusive | sound_flags::looping ); @@ -4009,7 +3687,7 @@ void TDynamicObject::RenderSounds() { auto const velocitydifference { GetVelocity() / MoverParameters->Vmax }; rsSlippery - .gain( rsSlippery.m_amplitudefactor * velocitydifference + rsSlippery.m_amplitudeoffset ) + .gain( rsSlippery.m_amplitudeoffset + rsSlippery.m_amplitudefactor * velocitydifference ) .play( sound_flags::exclusive | sound_flags::looping ); } } @@ -4242,12 +3920,12 @@ void TDynamicObject::RenderSounds() { // przekaznik - gdy bezpiecznik, automatyczny rozruch itp if( true == TestFlag( MoverParameters->SoundFlag, sound::parallel ) ) { if( TestFlag( MoverParameters->SoundFlag, sound::loud ) ) - dsbWejscie_na_bezoporow.play(); + m_powertrainsounds.dsbWejscie_na_bezoporow.play(); else - dsbWejscie_na_drugi_uklad.play(); + m_powertrainsounds.motor_parallel.play(); } else { - dsbRelay + m_powertrainsounds.motor_relay .gain( true == TestFlag( MoverParameters->SoundFlag, sound::loud ) ? 1.0f : @@ -5055,25 +4733,35 @@ void TDynamicObject::LoadMMediaFile( std::string BaseDir, std::string TypeName, else if( ( token == "engine:" ) && ( MoverParameters->Power > 0 ) ) { // plik z dzwiekiem silnika, mnozniki i ofsety amp. i czest. - rsSilnik.deserialize( parser, sound_type::single, sound_parameters::range | sound_parameters::amplitude | sound_parameters::frequency ); - rsSilnik.owner( this ); + m_powertrainsounds.engine.deserialize( parser, sound_type::single, sound_parameters::range | sound_parameters::amplitude | sound_parameters::frequency ); + m_powertrainsounds.engine.owner( this ); auto const amplitudedivisor = static_cast( ( - MoverParameters->EngineType == DieselEngine ? MoverParameters->Power + MoverParameters->nmax * 60 : + MoverParameters->EngineType == DieselEngine ? MoverParameters->nmax * 60 + MoverParameters->Power : MoverParameters->EngineType == DieselElectric ? MoverParameters->Power * 3 : - MoverParameters->Power + MoverParameters->nmax * 60 + MoverParameters->Power + MoverParameters->Power ) ); - rsSilnik.m_amplitudefactor /= amplitudedivisor; + MoverParameters->nmax * 60 + MoverParameters->Power * 3 ) ); + m_powertrainsounds.engine.m_amplitudefactor /= amplitudedivisor; } + else if( ( token == "tractionmotor:" ) + && ( MoverParameters->Power > 0 ) ) { + // plik z dzwiekiem silnika, mnozniki i ofsety amp. i czest. + m_powertrainsounds.motor.deserialize( parser, sound_type::single, sound_parameters::range | sound_parameters::amplitude | sound_parameters::frequency ); + m_powertrainsounds.motor.owner( this ); + + auto const amplitudedivisor = static_cast( MoverParameters->nmax * 60 + MoverParameters->Power * 3 ); + m_powertrainsounds.motor.m_amplitudefactor /= amplitudedivisor; + } + else if( token == "ventilator:" ) { // plik z dzwiekiem wentylatora, mnozniki i ofsety amp. i czest. - rsWentylator.deserialize( parser, sound_type::single, sound_parameters::range | sound_parameters::amplitude | sound_parameters::frequency ); - rsWentylator.owner( this ); + m_powertrainsounds.rsWentylator.deserialize( parser, sound_type::single, sound_parameters::range | sound_parameters::amplitude | sound_parameters::frequency ); + m_powertrainsounds.rsWentylator.owner( this ); if( ( MoverParameters->EngineType == ElectricSeriesMotor ) || ( MoverParameters->EngineType == ElectricInductionMotor ) ) { - rsWentylator.m_amplitudefactor /= MoverParameters->RVentnmax; - rsWentylator.m_frequencyfactor /= MoverParameters->RVentnmax; + m_powertrainsounds.rsWentylator.m_amplitudefactor /= MoverParameters->RVentnmax; + m_powertrainsounds.rsWentylator.m_frequencyfactor /= MoverParameters->RVentnmax; } } @@ -5081,13 +4769,13 @@ void TDynamicObject::LoadMMediaFile( std::string BaseDir, std::string TypeName, && ( MoverParameters->EngineType == ElectricSeriesMotor ) ) { // plik z dzwiekiem, mnozniki i ofsety amp. i czest. // NOTE, fixed default parameters, legacy system leftover - rsPrzekladnia.m_amplitudefactor = 0.029; - rsPrzekladnia.m_amplitudeoffset = 0.1; - rsPrzekladnia.m_frequencyfactor = 0.005; - rsPrzekladnia.m_frequencyoffset = 1.0; + m_powertrainsounds.transmission.m_amplitudefactor = 0.029; + m_powertrainsounds.transmission.m_amplitudeoffset = 0.1; + m_powertrainsounds.transmission.m_frequencyfactor = 0.005; + m_powertrainsounds.transmission.m_frequencyoffset = 1.0; - rsPrzekladnia.deserialize( parser, sound_type::single, sound_parameters::range ); - rsPrzekladnia.owner( this ); + m_powertrainsounds.transmission.deserialize( parser, sound_type::single, sound_parameters::range ); + m_powertrainsounds.transmission.owner( this ); } else if( token == "brake:" ) { @@ -5120,8 +4808,8 @@ void TDynamicObject::LoadMMediaFile( std::string BaseDir, std::string TypeName, else if( token == "dieselinc:" ) { // dzwiek przy wlazeniu na obroty woodwarda - rsDieselInc.deserialize( parser, sound_type::single, sound_parameters::range ); - rsDieselInc.owner( this ); + m_powertrainsounds.engine_revving.deserialize( parser, sound_type::single, sound_parameters::range ); + m_powertrainsounds.engine_revving.owner( this ); } else if( token == "curve:" ) { @@ -5185,8 +4873,8 @@ void TDynamicObject::LoadMMediaFile( std::string BaseDir, std::string TypeName, else if( token == "turbo:" ) { // pliki z turbogeneratorem - sTurbo.deserialize( parser, sound_type::multipart, sound_parameters::range ); - sTurbo.owner( this ); + m_powertrainsounds.engine_turbo.deserialize( parser, sound_type::multipart, sound_parameters::range ); + m_powertrainsounds.engine_turbo.owner( this ); } else if( token == "small-compressor:" ) { @@ -5259,20 +4947,20 @@ void TDynamicObject::LoadMMediaFile( std::string BaseDir, std::string TypeName, // engine sounds else if( token == "ignition:" ) { // odpalanie silnika - dsbDieselIgnition.deserialize( parser, sound_type::single ); - dsbDieselIgnition.owner( this ); + m_powertrainsounds.engine_ignition.deserialize( parser, sound_type::single ); + m_powertrainsounds.engine_ignition.owner( this ); } else if( token == "engageslippery:" ) { // tarcie tarcz sprzegla: - rsEngageSlippery.deserialize( parser, sound_type::single, sound_parameters::amplitude | sound_parameters::frequency ); - rsEngageSlippery.owner( this ); + m_powertrainsounds.rsEngageSlippery.deserialize( parser, sound_type::single, sound_parameters::amplitude | sound_parameters::frequency ); + m_powertrainsounds.rsEngageSlippery.owner( this ); - rsEngageSlippery.m_frequencyfactor /= ( 1 + MoverParameters->nmax ); + m_powertrainsounds.rsEngageSlippery.m_frequencyfactor /= ( 1 + MoverParameters->nmax ); } else if( token == "relay:" ) { // styczniki itp: - dsbRelay.deserialize( parser, sound_type::single ); - dsbRelay.owner( this ); + m_powertrainsounds.motor_relay.deserialize( parser, sound_type::single ); + m_powertrainsounds.motor_relay.owner( this ); } else if( token == "pneumaticrelay:" ) { // wylaczniki pneumatyczne: @@ -5281,12 +4969,12 @@ void TDynamicObject::LoadMMediaFile( std::string BaseDir, std::string TypeName, } else if( token == "wejscie_na_bezoporow:" ) { // hunter-111211: wydzielenie wejscia na bezoporowa i na drugi uklad do pliku - dsbWejscie_na_bezoporow.deserialize( parser, sound_type::single ); - dsbWejscie_na_bezoporow.owner( this ); + m_powertrainsounds.dsbWejscie_na_bezoporow.deserialize( parser, sound_type::single ); + m_powertrainsounds.dsbWejscie_na_bezoporow.owner( this ); } else if( token == "wejscie_na_drugi_uklad:" ) { - dsbWejscie_na_drugi_uklad.deserialize( parser, sound_type::single ); - dsbWejscie_na_drugi_uklad.owner( this ); + m_powertrainsounds.motor_parallel.deserialize( parser, sound_type::single ); + m_powertrainsounds.motor_parallel.owner( this ); } // braking sounds else if( token == "brakesound:" ) { @@ -5356,14 +5044,14 @@ void TDynamicObject::LoadMMediaFile( std::string BaseDir, std::string TypeName, // assign default samples to sound emitters which weren't included in the config file // engine if( MoverParameters->Power > 0 ) { - if( true == dsbWejscie_na_bezoporow.empty() ) { + if( true == m_powertrainsounds.dsbWejscie_na_bezoporow.empty() ) { // hunter-111211: domyslne, gdy brak - dsbWejscie_na_bezoporow.deserialize( "wejscie_na_bezoporow.wav", sound_type::single ); - dsbWejscie_na_bezoporow.owner( this ); + m_powertrainsounds.dsbWejscie_na_bezoporow.deserialize( "wejscie_na_bezoporow.wav", sound_type::single ); + m_powertrainsounds.dsbWejscie_na_bezoporow.owner( this ); } - if( true == dsbWejscie_na_drugi_uklad.empty() ) { - dsbWejscie_na_drugi_uklad.deserialize( "wescie_na_drugi_uklad.wav", sound_type::single ); - dsbWejscie_na_drugi_uklad.owner( this ); + if( true == m_powertrainsounds.motor_parallel.empty() ) { + m_powertrainsounds.motor_parallel.deserialize( "wescie_na_drugi_uklad.wav", sound_type::single ); + m_powertrainsounds.motor_parallel.owner( this ); } } // braking sounds @@ -5409,22 +5097,20 @@ void TDynamicObject::LoadMMediaFile( std::string BaseDir, std::string TypeName, Global::asCurrentDynamicPath = ""; // position sound emitters which weren't defined in the config file - auto const nullvector { glm::vec3() }; - // engine sounds , centre of the vehicle + // engine sounds, centre of the vehicle auto const enginelocation { glm::vec3 {0.f, MoverParameters->Dim.H * 0.5f, 0.f } }; + m_powertrainsounds.position( enginelocation ); + // other engine compartment sounds + auto const nullvector { glm::vec3() }; std::vector enginesounds = { - &dsbDieselIgnition, - &rsSilnik, - &dsbRelay, &dsbWejscie_na_bezoporow, &dsbWejscie_na_drugi_uklad, - &rsPrzekladnia, &rsEngageSlippery, &rsDieselInc, &sTurbo, - &rsWentylator, &sConverter, &sCompressor, &sSmallCompressor + &sConverter, &sCompressor, &sSmallCompressor }; for( auto sound : enginesounds ) { if( sound->offset() == nullvector ) { sound->offset( enginelocation ); } } - // TODO: other sound types + // pantographs if( pants != nullptr ) { std::size_t pantographindex { 0 }; @@ -5945,6 +5631,320 @@ TDynamicObject::ConnectedEnginePowerSource( TDynamicObject const *Caller ) const } +void +TDynamicObject::powertrain_sounds::position( glm::vec3 const Location ) { + + auto const nullvector { glm::vec3() }; + std::vector enginesounds = { + &motor_relay, &dsbWejscie_na_bezoporow, &motor_parallel, &rsWentylator, + &engine, &engine_ignition, &engine_revving, &engine_turbo, + &transmission, &rsEngageSlippery + }; + for( auto sound : enginesounds ) { + if( sound->offset() == nullvector ) { + sound->offset( Location ); + } + } +} + +void +TDynamicObject::powertrain_sounds::render( TMoverParameters const &Vehicle, double const Deltatime ) { + + if( Vehicle.Power == 0 ) { return; } + + double frequency { 1.0 }; + double volume { 0.0 }; + + // engine sounds + if( ( true == Vehicle.Mains ) + && ( false == Vehicle.dizel_enginestart ) ) { + + if( ( std::fabs( Vehicle.enrot ) > 0.01 ) + // McZapkie-280503: zeby dla dumb dzialal silnik na jalowych obrotach + || ( Vehicle.EngineType == Dumb ) ) { + + // frequency calculation + auto normalizer { 1.f }; + if( true == engine.is_combined() ) { + // for combined engine sound we calculate sound point in rpm, to make .mmd files setup easier + // NOTE: we supply 1/100th of actual value, as the sound module converts does the opposite, converting received (typically) 0-1 values to 0-100 range + normalizer = 60.f * 0.01f; + } + frequency = + engine.m_frequencyoffset + + engine.m_frequencyfactor * std::abs( Vehicle.enrot ) * normalizer; + + if( Vehicle.EngineType == Dumb ) { + frequency -= 0.2 * Vehicle.EnginePower / ( 1 + Vehicle.Power * 1000 ); + } + + // base volume calculation + switch( Vehicle.EngineType ) { + // TODO: check calculated values + case DieselElectric: { + volume = + engine.m_amplitudeoffset + + engine.m_amplitudefactor * ( Vehicle.EnginePower / 1000 / Vehicle.Power ) + + 0.2 * ( Vehicle.enrot * 60 ) / ( Vehicle.DElist[ Vehicle.MainCtrlPosNo ].RPM ); + break; + } + case DieselEngine: { + if( Vehicle.enrot > 0.0 ) { + volume = ( + Vehicle.EnginePower > 0 ? + engine.m_amplitudeoffset + engine.m_amplitudefactor * Vehicle.dizel_fill : + engine.m_amplitudeoffset * 0.9f + engine.m_amplitudefactor * std::fabs( Vehicle.enrot / Vehicle.dizel_nmax ) ); + } + break; + } + default: { + volume = + engine.m_amplitudeoffset + + engine.m_amplitudefactor * ( Vehicle.EnginePower / 1000 + std::fabs( Vehicle.enrot ) * 60.0 ); + break; + } + } + + if( engine_volume >= 0.05 ) { + engine + .pitch( frequency ) + .gain( engine_volume ) + .play( sound_flags::exclusive | sound_flags::looping ); + + if( ( Vehicle.EngineType == DieselElectric ) + || ( Vehicle.EngineType == DieselEngine ) ) { + // diesel engine revolutions increase + float enginerevvolume { 0 }; + if( engine_revs_last != -1.f ) { + // calculate potential recent increase of engine revolutions + auto const revolutionsperminute { Vehicle.enrot * 60 }; + auto const revolutionsdifference { revolutionsperminute - engine_revs_last }; + auto const idlerevolutionsthreshold { 1.01 * ( + Vehicle.EngineType == DieselElectric ? + Vehicle.DElist[ 0 ].RPM : + Vehicle.dizel_nmin * 60 ) }; + + engine_revs_change = std::max( 0.0, engine_revs_change - 2.5 * Deltatime ); + if( ( revolutionsperminute > idlerevolutionsthreshold ) + && ( revolutionsdifference > 1.0 * Deltatime ) ) { + engine_revs_change = clamp( engine_revs_change + 5.0 * Deltatime, 0.0, 1.25 ); + } + enginerevvolume = engine_revs_change; + } + engine_revs_last = Vehicle.enrot * 60; + + if( enginerevvolume > 0.02 ) { + engine_revving + .gain( enginerevvolume ) + .play( sound_flags::exclusive | sound_flags::looping ); + } + else { + engine_revving.stop(); + } + } + } // enginevolume > 0.05 + } + else { + engine.stop(); + } + } + engine_volume = interpolate( engine_volume, volume, 0.25 ); + if( engine_volume < 0.05 ) { + engine.stop(); + } + + + // youBy - przenioslem, bo diesel tez moze miec turbo + if( Vehicle.TurboTest > 0 ) { + // udawanie turbo: + auto const goalpitch { std::max( 0.025, ( engine_volume + engine_turbo.m_frequencyoffset ) * engine_turbo.m_frequencyfactor ) }; + auto const goalvolume { std::max( 0.0, ( engine_turbo_pitch + engine_turbo.m_amplitudeoffset ) * engine_turbo.m_amplitudefactor ) }; + auto const currentvolume { engine_turbo.gain() }; + auto const changerate { 0.4 * Deltatime }; + + if( ( Vehicle.MainCtrlPos >= Vehicle.TurboTest ) + && ( Vehicle.enrot > 0.1 ) ) { + + engine_turbo_pitch = ( + engine_turbo_pitch > goalpitch ? + std::max( goalpitch, engine_turbo_pitch - changerate * 0.5 ) : + std::min( goalpitch, engine_turbo_pitch + changerate ) ); + + volume = ( + currentvolume > goalvolume ? + std::max( goalvolume, currentvolume - changerate ) : + std::min( goalvolume, currentvolume + changerate ) ); + + engine_turbo + .pitch( 0.4 + engine_turbo_pitch * 0.4 ) + .gain( volume ) + .play( sound_flags::exclusive | sound_flags::looping ); + } + else { + engine_turbo_pitch = std::max( goalpitch, engine_turbo_pitch - changerate * 0.5 ); + volume = std::max( 0.0, engine_turbo.gain() - 2.0 * Deltatime ); + if( volume > 0.05 ) { + engine_turbo + .pitch( 0.4 + engine_turbo_pitch * 0.4 ) + .gain( volume ); + } + else { + engine_turbo.stop(); + engine_turbo_pitch = goalpitch; + } + } + } + + // diesel startup + if( ( Vehicle.EngineType == DieselEngine ) + || ( Vehicle.EngineType == DieselElectric ) ) { + + if( true == Vehicle.dizel_enginestart ) { + engine_ignition.play( sound_flags::exclusive ); + } + } + + + if( Vehicle.dizel_engage > 0.1 ) { + if( std::abs( Vehicle.dizel_engagedeltaomega ) > 0.2 ) { + frequency = rsEngageSlippery.m_frequencyoffset + rsEngageSlippery.m_frequencyfactor * std::fabs( Vehicle.dizel_engagedeltaomega ); + volume = rsEngageSlippery.m_amplitudeoffset + rsEngageSlippery.m_amplitudefactor * ( Vehicle.dizel_engage ); + } + else { + frequency = 1.f; // rsEngageSlippery.FA+0.7*rsEngageSlippery.FM*(fabs(mvControlled->enrot)+mvControlled->nmax); + volume = ( + Vehicle.dizel_engage > 0.2 ? + rsEngageSlippery.m_amplitudeoffset + 0.2 * rsEngageSlippery.m_amplitudefactor * ( Vehicle.enrot / Vehicle.nmax ) : + 0.f ); + } + + rsEngageSlippery + .pitch( frequency ) + .gain( volume ) + .play( sound_flags::exclusive | sound_flags::looping ); + } + else { + rsEngageSlippery.stop(); + } + + // motor sounds + volume = 0.0; + if( ( true == Vehicle.Mains ) + && ( false == Vehicle.dizel_enginestart ) ) { + + if( std::fabs( Vehicle.enrot ) > 0.01 ) { + + // frequency calculation + auto normalizer { 1.f }; + if( true == motor.is_combined() ) { + // for combined motor sound we calculate sound point in rpm, to make .mmd files setup easier + // NOTE: we supply 1/100th of actual value, as the sound module converts does the opposite, converting received (typically) 0-1 values to 0-100 range + normalizer = 60.f * 0.01f; + } + auto const motorrevolutions { std::abs( Vehicle.nrot ) * Vehicle.Transmision.Ratio }; + frequency = + motor.m_frequencyoffset + + motor.m_frequencyfactor * motorrevolutions * normalizer; + + // base volume calculation + switch( Vehicle.EngineType ) { + case ElectricInductionMotor: { + volume = + motor.m_amplitudeoffset + + motor.m_amplitudefactor * ( Vehicle.EnginePower + motorrevolutions * 2 ); + break; + } + case ElectricSeriesMotor: { + volume = + motor.m_amplitudeoffset + + motor.m_amplitudefactor * ( Vehicle.EnginePower / 1000 + motorrevolutions * 60.0 ); + break; + } + default: { + volume = + motor.m_amplitudeoffset + + motor.m_amplitudefactor * motorrevolutions * 60.0; + break; + } + } + + if( Vehicle.EngineType == ElectricSeriesMotor ) { + // volume variation + if( ( volume < 1.0 ) + && ( Vehicle.EnginePower < 100 ) ) { + + auto const volumevariation { Random( 100 ) * Vehicle.enrot / ( 1 + Vehicle.nmax ) }; + if( volumevariation < 2 ) { + volume += volumevariation / 200; + } + } + + if( ( Vehicle.DynamicBrakeFlag ) + && ( Vehicle.EnginePower > 0.1 ) ) { + // Szociu - 29012012 - jeżeli uruchomiony jest hamulec elektrodynamiczny, odtwarzany jest dźwięk silnika + volume += 0.8; + } + } + // scale motor volume based on whether they're active + motor_momentum = + clamp( + motor_momentum + - 1.0 * Deltatime // smooth out decay + + std::abs( Vehicle.Mm ) / 60.0 * Deltatime, + 0.0, 1.25 ); + volume *= std::max( 0.25f, motor_momentum ); + + if( motor_volume >= 0.05 ) { + motor + .pitch( frequency ) + .gain( motor_volume ) + .play( sound_flags::exclusive | sound_flags::looping ); + } + } + else { + motor.stop(); + } + } + motor_volume = interpolate( motor_volume, volume, 0.25 ); + if( motor_volume < 0.05 ) { + motor.stop(); + } + + if( ( Vehicle.EngineType == ElectricSeriesMotor ) + || ( Vehicle.EngineType == ElectricInductionMotor ) ) { + + if( Vehicle.RventRot > 0.1 ) { + // play ventilator sound if the ventilators are rotating fast enough... + volume = ( + Vehicle.EngineType == ElectricInductionMotor ? + rsWentylator.m_amplitudefactor * std::sqrt( std::fabs( Vehicle.dizel_fill ) ) + rsWentylator.m_amplitudeoffset : + rsWentylator.m_amplitudefactor * Vehicle.RventRot + rsWentylator.m_amplitudeoffset ); + + rsWentylator + .pitch( rsWentylator.m_frequencyfactor * Vehicle.RventRot + rsWentylator.m_frequencyoffset ) + .gain( volume ) + .play( sound_flags::exclusive | sound_flags::looping ); + } + else { + // ...otherwise shut down the sound + rsWentylator.stop(); + } + } + + + if( Vehicle.TrainType == dt_ET40 ) { + if( Vehicle.Vel > 0.1 ) { + transmission + .pitch( transmission.m_frequencyfactor * ( Vehicle.Vel ) + transmission.m_frequencyoffset ) + .gain( transmission.m_amplitudefactor * ( Vehicle.Vel ) + transmission.m_amplitudeoffset ) + .play( sound_flags::exclusive | sound_flags::looping ); + } + else { + transmission.stop(); + } + } +} + // legacy method, calculates changes in simulation state over specified time void diff --git a/DynObj.h b/DynObj.h index 9c0ed484..d245e63e 100644 --- a/DynObj.h +++ b/DynObj.h @@ -273,8 +273,8 @@ private: }; struct door_sounds { - sound_source rsDoorOpen{ sound_placement::general, 25.f }; // Ra: przeniesione z kabiny - sound_source rsDoorClose{ sound_placement::general, 25.f }; + sound_source rsDoorOpen { sound_placement::general, 25.f }; // Ra: przeniesione z kabiny + sound_source rsDoorClose { sound_placement::general, 25.f }; }; struct axle_sounds { @@ -283,6 +283,29 @@ private: sound_source clatter; // clatter emitter }; + struct powertrain_sounds { + sound_source motor { sound_placement::external }; // generally traction motor + double motor_volume { 0.0 }; // MC: pomocnicze zeby gladziej silnik buczal + float motor_momentum { 0.f }; // recent change in motor revolutions + sound_source motor_relay { sound_placement::engine }; + sound_source dsbWejscie_na_bezoporow { sound_placement::engine }; // moved from cab + sound_source motor_parallel { sound_placement::engine }; // moved from cab + sound_source rsWentylator { sound_placement::engine }; // McZapkie-030302 + sound_source engine { sound_placement::engine }; // generally diesel engine + sound_source engine_ignition { sound_placement::engine }; // moved from cab + double engine_volume { 0.0 }; // MC: pomocnicze zeby gladziej silnik buczal + sound_source engine_revving { sound_placement::engine }; // youBy + float engine_revs_last { -1.f }; // helper, cached rpm of the engine + float engine_revs_change { 0.f }; // recent change in engine revolutions + sound_source engine_turbo { sound_placement::engine }; + double engine_turbo_pitch { 1.0 }; + sound_source transmission { sound_placement::engine }; + sound_source rsEngageSlippery { sound_placement::engine }; // moved from cab + + void position( glm::vec3 const Location ); + void render( TMoverParameters const &Vehicle, double const Deltatime ); + }; + // methods void ABuLittleUpdate(double ObjSqrDist); double ComputeRadius( Math3D::vector3 p1, Math3D::vector3 p2, Math3D::vector3 p3, Math3D::vector3 p4); @@ -328,29 +351,35 @@ private: // int iAxles; // McZapkie: to potem mozna skasowac i zastapic iNumAxles double dRailLength { 0.0 }; std::vector m_axlesounds; -/* - double dRailPosition[MaxAxles]; // licznik pozycji osi w/m szyny - double dWheelsPosition[MaxAxles]; // pozycja osi w/m srodka pojazdu - std::vector rsStukot; // dzwieki poszczegolnych osi //McZapkie-270202 -*/ + powertrain_sounds m_powertrainsounds; // engine sounds +/* sound_source dsbDieselIgnition { sound_placement::engine }; // moved from cab sound_source rsSilnik { sound_placement::engine }; double enginevolume { 0.0 }; // MC: pomocnicze zeby gladziej silnik buczal + sound_source m_tractionmotor { sound_placement::external }; sound_source dsbRelay { sound_placement::engine }; sound_source dsbWejscie_na_bezoporow { sound_placement::engine }; // moved from cab sound_source dsbWejscie_na_drugi_uklad { sound_placement::engine }; // moved from cab sound_source rsPrzekladnia { sound_placement::engine }; sound_source rsEngageSlippery { sound_placement::engine }; // moved from cab sound_source rsDieselInc { sound_placement::engine }; // youBy + float m_lastenginerevolutions { -1.f }; // helper, cached rpm of the engine + float m_enginerevolutionschange { 0.f }; // recent change of engine revolutions sound_source sTurbo { sound_placement::engine }; sound_source rsWentylator { sound_placement::engine }; // McZapkie-030302 sound_source sConverter { sound_placement::engine }; sound_source sCompressor { sound_placement::engine }; // NBMX wrzesien 2003 sound_source sSmallCompressor { sound_placement::engine }; +*/ + sound_source sConverter { sound_placement::engine }; + sound_source sCompressor { sound_placement::engine }; // NBMX wrzesien 2003 + sound_source sSmallCompressor { sound_placement::engine }; // braking sounds sound_source dsbPneumaticRelay { sound_placement::external }; sound_source rsUnbrake { sound_placement::external }; // yB - odglos luzowania + float m_lastbrakepressure { -1.f }; // helper, cached level of pressure in brake cylinder + float m_brakepressurechange { 0.f }; // recent change of pressure in brake cylinder sound_source sReleaser { sound_placement::external }; sound_source rsSlippery { sound_placement::external, EU07_SOUND_BRAKINGCUTOFFRANGE }; // moved from cab sound_source sSand { sound_placement::external }; @@ -372,7 +401,6 @@ private: double eng_vol_act; double eng_frq_act; double eng_dfrq; - double eng_turbo; Math3D::vector3 modelShake; bool renderme; // yB - czy renderowac @@ -380,8 +408,6 @@ private: int iInventory[ 2 ] { 0, 0 }; // flagi bitowe posiadanych submodeli (np. świateł) bool btnOn; // ABu: czy byly uzywane buttony, jesli tak, to po renderingu wylacz // bo ten sam model moze byc jeszcze wykorzystany przez inny obiekt! - float m_lastbrakepressure { -1.f }; // helper, cached level of pressure in brake cylinder - float m_brakepressurechange { 0.f }; // recent change of pressure in brake cylinder public: int iHornWarning; // numer syreny do użycia po otrzymaniu sygnału do jazdy diff --git a/McZapkie/Mover.cpp b/McZapkie/Mover.cpp index 72532ec2..b7570740 100644 --- a/McZapkie/Mover.cpp +++ b/McZapkie/Mover.cpp @@ -1371,9 +1371,12 @@ double TMoverParameters::ComputeMovement(double dt, double dt1, const TTrackShap if (AutoRelayCheck()) SetFlag(SoundFlag, sound::relay); - if (EngineType == DieselEngine) - if (dizel_Update(dt)) - SetFlag(SoundFlag, sound::relay); + if( ( EngineType == DieselEngine ) + || ( EngineType == DieselElectric ) ) { + if( dizel_Update( dt ) ) { + SetFlag( SoundFlag, sound::relay ); + } + } // uklady hamulcowe: if (VeselVolume > 0) Compressor = CompressedVolume / VeselVolume; @@ -2412,7 +2415,7 @@ bool TMoverParameters::MainSwitch( bool const State, int const Notify ) } } if( ( EngineType == DieselEngine ) - && ( true == Mains ) ) { + || ( EngineType == DieselElectric ) ) { dizel_enginestart = State; } @@ -5642,22 +5645,28 @@ bool TMoverParameters::dizel_AutoGearCheck(void) // ************************************************************************************************* bool TMoverParameters::dizel_Update(double dt) { - const double fillspeed = 2; - bool DU; + double const fillspeed { 2 }; + bool DU { false }; // dizel_Update:=false; - if (dizel_enginestart && (LastSwitchingTime >= InitialCtrlDelay)) - { + if( ( true == dizel_enginestart ) + && ( LastSwitchingTime >= InitialCtrlDelay ) ) { dizel_enginestart = false; LastSwitchingTime = 0; - enrot = dizel_nmin / 2.0; // TODO: dac zaleznie od temperatury i baterii + + enrot = std::max( + enrot, + 0.1 * ( // TODO: dac zaleznie od temperatury i baterii + EngineType == DieselEngine ? + dizel_nmin : + DElist[ 0 ].RPM / 60.0 ) ); + } + + if( EngineType == DieselEngine ) { + dizel_EngageChange( dt ); + DU = dizel_AutoGearCheck(); + dizel_fill = dizel_fill + fillspeed * dt * ( dizel_fillcheck( MainCtrlPos ) - dizel_fill ); } - /*OK=*/dizel_EngageChange(dt); - // if AutoRelayFlag then Poprawka na SM03 - DU = dizel_AutoGearCheck(); - // dizel_fill:=(dizel_fill+dizel_fillcheck(MainCtrlPos))/2; - dizel_fill = dizel_fill + fillspeed * dt * (dizel_fillcheck(MainCtrlPos) - dizel_fill); - // dizel_Update:=OK; return DU; } @@ -7551,6 +7560,8 @@ void TMoverParameters::LoadFIZ_Circuit( std::string const &Input ) { void TMoverParameters::LoadFIZ_RList( std::string const &Input ) { + extract_value( RlistSize, "Size", Input, "" ); + auto const venttype = extract_value( "RVent", Input ); if( venttype == "Automatic" ) { diff --git a/Train.cpp b/Train.cpp index 953f0d82..cf44f4c9 100644 --- a/Train.cpp +++ b/Train.cpp @@ -1538,7 +1538,8 @@ void TTrain::OnCommand_linebreakertoggle( TTrain *Train, command_data const &Com Train->m_linebreakerstate = 2; // for diesels, we complete the engine start here // TODO: consider arranging a better way to start the diesel engines - if( Train->mvControlled->EngineType == DieselEngine ) { + if( ( Train->mvControlled->EngineType == DieselEngine ) + || ( Train->mvControlled->EngineType == DieselElectric ) ) { if( Train->mvControlled->MainSwitch( true ) ) { // side-effects Train->mvControlled->ConverterSwitch( ( Train->ggConverterButton.GetValue() > 0.5 ) || ( Train->mvControlled->ConverterStart == start::automatic ) ); @@ -1619,7 +1620,8 @@ void TTrain::OnCommand_linebreakertoggle( TTrain *Train, command_data const &Com else { // ...after closing the circuit // we don't need to start the diesel twice, but the other types still need to be launched - if( Train->mvControlled->EngineType != DieselEngine ) { + if( ( Train->mvControlled->EngineType != DieselEngine ) + && ( Train->mvControlled->EngineType != DieselElectric ) ) { if( Train->mvControlled->MainSwitch( true ) ) { // side-effects Train->mvControlled->ConverterSwitch( ( Train->ggConverterButton.GetValue() > 0.5 ) || ( Train->mvControlled->ConverterStart == start::automatic ) ); diff --git a/World.cpp b/World.cpp index 71593315..d7901166 100644 --- a/World.cpp +++ b/World.cpp @@ -1630,15 +1630,17 @@ TWorld::Update_UI() { if( vehicle == nullptr ) { break; } - uitextline1 = - "vel: " + to_string(vehicle->GetVelocity(), 2) + "/" + to_string(vehicle->MoverParameters->nrot* M_PI * vehicle->MoverParameters->WheelDiameter * 3.6, 2) - + " km/h" + (vehicle->MoverParameters->SlippingWheels ? " (!)" : " ") - + "; dist: " + to_string(vehicle->MoverParameters->DistCounter, 2) + " km" - + "; pos: (" - + to_string(vehicle->GetPosition().x, 2) + ", " - + to_string(vehicle->GetPosition().y, 2) + ", " - + to_string(vehicle->GetPosition().z, 2) + "), PM=" - + to_string(vehicle->MoverParameters->WheelFlat, 1) + " mm"; + uitextline1 = + "vel: " + to_string( vehicle->GetVelocity(), 2 ) + "/" + to_string( vehicle->MoverParameters->nrot* M_PI * vehicle->MoverParameters->WheelDiameter * 3.6, 2 ) + + " km/h;" + ( vehicle->MoverParameters->SlippingWheels ? " (!)" : " " ) + + " dist: " + to_string( vehicle->MoverParameters->DistCounter, 2 ) + " km" + + "; pos: (" + + to_string( vehicle->GetPosition().x, 2 ) + ", " + + to_string( vehicle->GetPosition().y, 2 ) + ", " + + to_string( vehicle->GetPosition().z, 2 ) + "), PM=" + + to_string( vehicle->MoverParameters->WheelFlat, 1 ) + " mm; enrot=" + + to_string( vehicle->MoverParameters->enrot * 60, 0 ) + " tmrot=" + + to_string( std::abs( vehicle->MoverParameters->nrot ) * vehicle->MoverParameters->Transmision.Ratio * 60, 0 ); uitextline2 = "HamZ=" + to_string( vehicle->MoverParameters->fBrakeCtrlPos, 2 ) diff --git a/sound.cpp b/sound.cpp index a9aa7a09..bd3f4ae7 100644 --- a/sound.cpp +++ b/sound.cpp @@ -59,11 +59,12 @@ sound_source::deserialize( cParser &Input, sound_type const Legacytype, int cons m_soundchunks[ idx ].second.fadeout = m_soundchunks[ idx + 1 ].second.threshold; } // ...and on the other end from the threshold point back into the range of previous chunk + m_soundchunks.front().second.fadein = std::max( 0, m_soundchunks.front().second.threshold ); for( std::size_t idx = 1; idx < m_soundchunks.size(); ++idx ) { auto const previouschunkwidth { m_soundchunks[ idx ].second.threshold - m_soundchunks[ idx - 1 ].second.threshold }; m_soundchunks[ idx ].second.fadein = m_soundchunks[ idx ].second.threshold - 0.01f * m_crossfaderange * previouschunkwidth; } - m_soundchunks.back().second.fadeout = std::max( m_soundchunks.back().second.threshold, 100 ); + m_soundchunks.back().second.fadeout = std::max( 100, m_soundchunks.back().second.threshold ); // test if the chunk table contains any actual samples while at it for( auto &soundchunk : m_soundchunks ) { if( soundchunk.first.buffer != null_handle ) {