partial unification of sound definition and handling for different vehicle types

This commit is contained in:
tmj-fstate
2017-12-23 16:58:12 +01:00
parent bc13e5b0b5
commit 61a2511e1f
6 changed files with 462 additions and 420 deletions

View File

@@ -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<float>( (
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<float>( 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<sound_source *> 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<sound_source *> 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

View File

@@ -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<axle_sounds> m_axlesounds;
/*
double dRailPosition[MaxAxles]; // licznik pozycji osi w/m szyny
double dWheelsPosition[MaxAxles]; // pozycja osi w/m srodka pojazdu
std::vector<sound_source> 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

View File

@@ -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" ) {

View File

@@ -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 ) );

View File

@@ -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 )

View File

@@ -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 ) {