mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-03-22 15:05:03 +01:00
build 171202. audio subsystem: volume support, source reassignment, bug fixes
This commit is contained in:
@@ -999,7 +999,7 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN
|
||||
go = cm_Ready; // gotów do odjazdu z W4 (semafor może
|
||||
// zatrzymać)
|
||||
if( ( tsGuardSignal != nullptr )
|
||||
&& ( false == tsGuardSignal->empty() ) ); {
|
||||
&& ( false == tsGuardSignal->empty() ) ) {
|
||||
// jeśli mamy głos kierownika, to odegrać
|
||||
iDrivigFlags |= moveGuardSignal;
|
||||
}
|
||||
@@ -1447,7 +1447,7 @@ void TController::TableSort() {
|
||||
return;
|
||||
}
|
||||
TSpeedPos sp_temp = TSpeedPos(); // uzywany do przenoszenia
|
||||
for( std::size_t i = 0; i < ( iLast - 1 ); ++i ) {
|
||||
for( int i = 0; i < ( iLast - 1 ); ++i ) {
|
||||
// pętla tylko do dwóch pozycji od końca bo ostatniej nie modyfikujemy
|
||||
if (sSpeedTable[i].fDist > sSpeedTable[i + 1].fDist)
|
||||
{ // jesli pozycja wcześniejsza jest dalej to źle
|
||||
|
||||
44
DynObj.cpp
44
DynObj.cpp
@@ -3705,25 +3705,28 @@ void TDynamicObject::RenderSounds() {
|
||||
}
|
||||
else {
|
||||
|
||||
sConverter
|
||||
.pitch( frequency )
|
||||
.gain( volume )
|
||||
.play( sound_flags::exclusive | sound_flags::looping );
|
||||
if( MoverParameters->ConverterFlag ) {
|
||||
|
||||
float fincvol { 0 };
|
||||
if( ( MoverParameters->ConverterFlag )
|
||||
&& ( 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 )
|
||||
sConverter
|
||||
.pitch( frequency )
|
||||
.gain( volume )
|
||||
.play( sound_flags::exclusive | sound_flags::looping );
|
||||
}
|
||||
else {
|
||||
rsDieselInc.stop();
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4024,10 +4027,7 @@ void TDynamicObject::RenderSounds() {
|
||||
// McZapkie-280302 - pisk mocno zacisnietych hamulcow
|
||||
if( /*( false == MoverParameters->SlippingWheels )
|
||||
&&*/ ( MoverParameters->UnitBrakeForce > rsPisk.m_amplitudefactor )
|
||||
&& ( MoverParameters->Vel > (
|
||||
true == rsPisk.is_playing() ?
|
||||
0.05 :
|
||||
0.5 ) ) ) {
|
||||
&& ( MoverParameters->Vel > 2.5 ) ) {
|
||||
|
||||
rsPisk
|
||||
.gain( MoverParameters->UnitBrakeForce / ( rsPisk.m_amplitudefactor + 1 ) + rsPisk.m_amplitudeoffset )
|
||||
@@ -4035,7 +4035,7 @@ void TDynamicObject::RenderSounds() {
|
||||
}
|
||||
else {
|
||||
// don't stop the sound too abruptly
|
||||
volume = std::max( 0.0, rsPisk.gain() - ( rsPisk.gain() * 1.5 * dt ) );
|
||||
volume = std::max( 0.0, rsPisk.gain() - ( rsPisk.gain() * 2.5 * dt ) );
|
||||
rsPisk.gain( volume );
|
||||
if( volume < 0.05 ) {
|
||||
rsPisk.stop();
|
||||
|
||||
4
DynObj.h
4
DynObj.h
@@ -355,8 +355,8 @@ private:
|
||||
std::vector<pantograph_sounds> m_pantographsounds; // typically 2 but can be less (or more?)
|
||||
std::vector<door_sounds> m_doorsounds; // can expect symmetrical arrangement, but don't count on it
|
||||
sound_source sDepartureSignal { sound_placement::general };
|
||||
sound_source sHorn1 { sound_placement::external };
|
||||
sound_source sHorn2 { sound_placement::external };
|
||||
sound_source sHorn1 { sound_placement::external, 5 * EU07_SOUND_RUNNINGNOISECUTOFFRANGE };
|
||||
sound_source sHorn2 { sound_placement::external, 5 * EU07_SOUND_RUNNINGNOISECUTOFFRANGE };
|
||||
sound_source rsRunningNoise { sound_placement::external, EU07_SOUND_RUNNINGNOISECUTOFFRANGE };
|
||||
sound_source rscurve { sound_placement::external, EU07_SOUND_RUNNINGNOISECUTOFFRANGE }; // youBy
|
||||
|
||||
|
||||
@@ -134,7 +134,7 @@ bool Global::bWireFrame = false;
|
||||
|
||||
// sound renderer
|
||||
bool Global::bSoundEnabled = true;
|
||||
float Global::AudioVolume = 1.0f;
|
||||
float Global::AudioVolume = 2.0f;
|
||||
std::string Global::AudioRenderer;
|
||||
|
||||
int Global::iWriteLogEnabled = 3; // maska bitowa: 1-zapis do pliku, 2-okienko, 4-nazwy torów
|
||||
@@ -288,6 +288,12 @@ void Global::ConfigParse(cParser &Parser)
|
||||
// selected device for audio renderer
|
||||
Global::AudioRenderer = Parser.getToken<std::string>( false ); // case-sensitive
|
||||
}
|
||||
else if( token == "sound.volume" ) {
|
||||
// selected device for audio renderer
|
||||
Parser.getTokens();
|
||||
Parser >> Global::AudioVolume;
|
||||
Global::AudioVolume = clamp( Global::AudioVolume, 1.f, 4.f );
|
||||
}
|
||||
// else if (str==AnsiString("renderalpha")) //McZapkie-1312302 - dwuprzebiegowe renderowanie
|
||||
// bRenderAlpha=(GetNextSymbol().LowerCase()==AnsiString("yes"));
|
||||
else if (token == "physicslog")
|
||||
|
||||
30
Train.cpp
30
Train.cpp
@@ -2731,16 +2731,16 @@ void TTrain::OnCommand_departureannounce( TTrain *Train, command_data const &Com
|
||||
|
||||
if( Command.action == GLFW_PRESS ) {
|
||||
// only reacting to press, so the sound can loop uninterrupted
|
||||
if( false == Train->mvControlled->DepartureSignal ) {
|
||||
if( false == Train->mvOccupied->DepartureSignal ) {
|
||||
// turn on
|
||||
Train->mvControlled->signal_departure( true );
|
||||
Train->mvOccupied->signal_departure( true );
|
||||
// visual feedback
|
||||
Train->ggDepartureSignalButton.UpdateValue( 1.0, Train->dsbSwitch );
|
||||
}
|
||||
}
|
||||
else if( Command.action == GLFW_RELEASE ) {
|
||||
// turn off
|
||||
Train->mvControlled->signal_departure( false );
|
||||
Train->mvOccupied->signal_departure( false );
|
||||
// visual feedback
|
||||
Train->ggDepartureSignalButton.UpdateValue( 0.0, Train->dsbSwitch );
|
||||
}
|
||||
@@ -5494,6 +5494,20 @@ bool TTrain::LoadMMediaFile(std::string const &asFileName)
|
||||
bool TTrain::InitializeCab(int NewCabNo, std::string const &asFileName)
|
||||
{
|
||||
m_controlmapper.clear();
|
||||
// reset sound positions and owner
|
||||
auto const nullvector { glm::vec3() };
|
||||
std::vector<sound_source *> sounds = {
|
||||
&dsbReverserKey, &dsbNastawnikJazdy, &dsbNastawnikBocz,
|
||||
&dsbSwitch, &dsbPneumaticSwitch,
|
||||
&rsHiss, &rsHissU, &rsHissE, &rsHissX, &rsHissT, &rsSBHiss,
|
||||
&rsFadeSound,
|
||||
&dsbHasler, &dsbBuzzer, &dsbSlipAlarm
|
||||
};
|
||||
for( auto sound : sounds ) {
|
||||
sound->offset( nullvector );
|
||||
sound->owner( DynamicObject );
|
||||
}
|
||||
|
||||
pyScreens.reset(this);
|
||||
pyScreens.setLookupPath(DynamicObject->asBaseDir);
|
||||
bool parse = false;
|
||||
@@ -5658,7 +5672,6 @@ bool TTrain::InitializeCab(int NewCabNo, std::string const &asFileName)
|
||||
set_cab_controls();
|
||||
|
||||
// configure placement of sound emitters which aren't bound with any device model, and weren't placed manually
|
||||
auto const nullvector { glm::vec3() };
|
||||
// try first to bind sounds to location of possible devices
|
||||
if( dsbReverserKey.offset() == nullvector ) {
|
||||
dsbReverserKey.offset( ggDirKey.model_offset() );
|
||||
@@ -5682,14 +5695,7 @@ bool TTrain::InitializeCab(int NewCabNo, std::string const &asFileName)
|
||||
}
|
||||
}
|
||||
// for whatever is left fallback on generic location, centre of the cab
|
||||
auto const caboffset { glm::dvec3 { ( Cabine[ NewCabNo ].CabPos1 + Cabine[ NewCabNo ].CabPos2 ) * 0.5 } + glm::dvec3 { 0, 1, 0 } };
|
||||
std::vector<sound_source *> sounds = {
|
||||
&dsbReverserKey, &dsbNastawnikJazdy, &dsbNastawnikBocz,
|
||||
&dsbSwitch, &dsbPneumaticSwitch,
|
||||
&rsHiss, &rsHissU, &rsHissE, &rsHissX, &rsHissT, &rsSBHiss,
|
||||
&rsFadeSound,
|
||||
&dsbHasler, &dsbBuzzer, &dsbSlipAlarm
|
||||
};
|
||||
auto const caboffset { glm::dvec3 { ( Cabine[ cabindex ].CabPos1 + Cabine[ cabindex ].CabPos2 ) * 0.5 } + glm::dvec3 { 0, 1, 0 } };
|
||||
for( auto sound : sounds ) {
|
||||
if( sound->offset() == nullvector ) {
|
||||
sound->offset( caboffset );
|
||||
|
||||
@@ -103,7 +103,8 @@ bool TTrackFollower::Move(double fDistance, bool bPrimary)
|
||||
// TODO: refactor following block as track method
|
||||
if( pCurrentTrack->iEvents ) { // sumaryczna informacja o eventach
|
||||
// omijamy cały ten blok, gdy tor nie ma on żadnych eventów (większość nie ma)
|
||||
if( std::abs( fDistance ) < 0.01 ) {
|
||||
if( ( std::abs( fDistance ) < 0.01 )
|
||||
&& ( Owner->GetVelocity() < 0.01 ) ) {
|
||||
//McZapkie-140602: wyzwalanie zdarzenia gdy pojazd stoi
|
||||
if( ( Owner->Mechanik != nullptr )
|
||||
&& ( Owner->Mechanik->Primary() ) ) {
|
||||
|
||||
@@ -94,18 +94,21 @@ openal_source::sync_with( sound_properties const &State ) {
|
||||
*/
|
||||
// location
|
||||
properties.location = State.location;
|
||||
auto sourceoffset { glm::vec3 { properties.location - glm::dvec3 { Global::pCameraPosition } } };
|
||||
sound_distance = properties.location - glm::dvec3 { Global::pCameraPosition };
|
||||
if( sound_range > 0 ) {
|
||||
// range cutoff check
|
||||
auto const cutoffrange { sound_range * 7.5f };
|
||||
if( glm::length2( sourceoffset ) > std::min( ( cutoffrange * cutoffrange ), ( EU07_SOUND_CUTOFFRANGE * EU07_SOUND_CUTOFFRANGE ) ) ) {
|
||||
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 );
|
||||
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
|
||||
return;
|
||||
}
|
||||
}
|
||||
if( sound_range >= 0 ) {
|
||||
::alSourcefv( id, AL_POSITION, glm::value_ptr( sourceoffset ) );
|
||||
::alSourcefv( id, AL_POSITION, glm::value_ptr( sound_distance ) );
|
||||
}
|
||||
else {
|
||||
// sounds with 'unlimited' range are positioned on top of the listener
|
||||
@@ -233,6 +236,7 @@ openal_renderer::init() {
|
||||
//
|
||||
// ::alDistanceModel( AL_LINEAR_DISTANCE );
|
||||
::alDistanceModel( AL_INVERSE_DISTANCE_CLAMPED );
|
||||
::alListenerf( AL_GAIN, clamp( Global::AudioVolume, 1.f, 4.f ) );
|
||||
// all done
|
||||
m_ready = true;
|
||||
return true;
|
||||
@@ -315,13 +319,54 @@ openal_renderer::update( double const Deltatime ) {
|
||||
audio::openal_source
|
||||
openal_renderer::fetch_source() {
|
||||
|
||||
audio::openal_source soundsource;
|
||||
audio::openal_source newsource;
|
||||
if( false == m_sourcespares.empty() ) {
|
||||
// reuse (a copy of) already allocated source
|
||||
soundsource.id = m_sourcespares.top();
|
||||
newsource.id = m_sourcespares.top();
|
||||
m_sourcespares.pop();
|
||||
}
|
||||
return soundsource;
|
||||
if( newsource.id == audio::null_resource ) {
|
||||
// if there's no source to reuse, try to generate a new one
|
||||
::alGenSources( 1, &( newsource.id ) );
|
||||
}
|
||||
if( newsource.id == audio::null_resource ) {
|
||||
// if we still don't have a working source, see if we can sacrifice an already active one
|
||||
// under presumption it's more important to play new sounds than keep the old ones going
|
||||
// TBD, TODO: for better results we could use range and/or position for the new sound
|
||||
// to better weight whether the new sound is really more important
|
||||
auto leastimportantsource { std::end( m_sources ) };
|
||||
auto leastimportantweight { std::numeric_limits<float>::max() };
|
||||
|
||||
for( auto source { std::begin( m_sources ) }; source != std::cend( m_sources ); ++source ) {
|
||||
|
||||
if( ( source->id == audio::null_resource )
|
||||
|| ( true == source->is_multipart )
|
||||
|| ( false == source->is_playing ) ) {
|
||||
|
||||
continue;
|
||||
}
|
||||
auto const sourceweight { (
|
||||
source->sound_range > 0 ?
|
||||
( source->sound_range * source->sound_range ) / ( glm::length2( source->sound_distance ) + 1 ) :
|
||||
std::numeric_limits<float>::max() ) };
|
||||
if( sourceweight < leastimportantweight ) {
|
||||
leastimportantsource = source;
|
||||
leastimportantweight = sourceweight;
|
||||
}
|
||||
}
|
||||
if( ( leastimportantsource != std::end( m_sources ) )
|
||||
&& ( leastimportantweight < 1.f ) ) {
|
||||
// only accept the candidate if it's outside of its nominal hearing range
|
||||
leastimportantsource->stop();
|
||||
leastimportantsource->update( 0 ); // HACK: a roundabout way to notify the controller its emitter has stopped
|
||||
leastimportantsource->clear();
|
||||
// we should be now free to grab the id and get rid of the remains
|
||||
newsource.id = leastimportantsource->id;
|
||||
m_sources.erase( leastimportantsource );
|
||||
}
|
||||
}
|
||||
|
||||
return newsource;
|
||||
}
|
||||
|
||||
bool
|
||||
|
||||
@@ -29,6 +29,8 @@ namespace audio {
|
||||
// TODO: generic interface base, for implementations other than openAL
|
||||
struct openal_source {
|
||||
|
||||
friend class openal_renderer;
|
||||
|
||||
// types
|
||||
using buffer_sequence = std::vector<audio::buffer_handle>;
|
||||
|
||||
@@ -48,14 +50,14 @@ struct openal_source {
|
||||
bind( sound_source *Controller, Iterator_ First, Iterator_ Last ) {
|
||||
controller = Controller;
|
||||
buffers.insert( std::end( buffers ), First, Last );
|
||||
if( id == audio::null_resource ) {
|
||||
::alGenSources( 1, &id ); }
|
||||
is_multipart = ( buffers.size() > 1 );
|
||||
// look up and queue assigned buffers
|
||||
std::vector<ALuint> bufferids;
|
||||
for( auto const buffer : buffers ) {
|
||||
bufferids.emplace_back( audio::renderer.buffer( buffer ).id ); }
|
||||
::alSourceQueueBuffers( id, bufferids.size(), bufferids.data() );
|
||||
::alSourceRewind( id );
|
||||
if( id != audio::null_resource ) {
|
||||
::alSourceQueueBuffers( id, bufferids.size(), bufferids.data() );
|
||||
::alSourceRewind( id ); }
|
||||
return *this; }
|
||||
// starts playback of queued buffers
|
||||
void
|
||||
@@ -88,6 +90,8 @@ private:
|
||||
double update_deltatime; // time delta of most current update
|
||||
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_multipart { false }; // multi-part sounds are kept alive at longer ranges
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -307,8 +307,8 @@ state_manager::deserialize_node( cParser &Input, scene::scratch_data &Scratchpad
|
||||
}
|
||||
|
||||
if( ( vehicle->MoverParameters->CategoryFlag == 1 ) // trains only
|
||||
&& ( ( vehicle->LightList( side::front ) & ( light::headlight_left | light::headlight_right | light::headlight_upper ) != 0 )
|
||||
|| ( vehicle->LightList( side::rear ) & ( light::headlight_left | light::headlight_right | light::headlight_upper ) != 0 ) ) ) {
|
||||
&& ( ( ( vehicle->LightList( side::front ) & ( light::headlight_left | light::headlight_right | light::headlight_upper ) ) != 0 )
|
||||
|| ( ( vehicle->LightList( side::rear ) & ( light::headlight_left | light::headlight_right | light::headlight_upper ) ) != 0 ) ) ) {
|
||||
simulation::Lights.insert( vehicle );
|
||||
}
|
||||
}
|
||||
|
||||
10
sound.cpp
10
sound.cpp
@@ -95,7 +95,7 @@ sound_source::play( int const Flags ) {
|
||||
|
||||
// initialize emitter-specific pitch variation if it wasn't yet set
|
||||
if( m_pitchvariation == 0.f ) {
|
||||
m_pitchvariation = 0.01f * static_cast<float>( Random( 95, 105 ) );
|
||||
m_pitchvariation = 0.01f * static_cast<float>( Random( 97.5, 102.5 ) );
|
||||
}
|
||||
|
||||
m_flags = Flags;
|
||||
@@ -130,7 +130,8 @@ sound_source::stop() {
|
||||
m_stop = true;
|
||||
|
||||
if( ( m_soundend.buffer != null_handle )
|
||||
&& ( m_soundend.buffer != m_soundmain.buffer ) ) { // end == main can happen in malformed legacy cases
|
||||
&& ( m_soundend.buffer != m_soundmain.buffer ) // end == main can happen in malformed legacy cases
|
||||
&& ( m_soundend.playing == 0 ) ) {
|
||||
// spawn potentially defined sound end sample, if the emitter is currently active
|
||||
insert( m_soundend.buffer );
|
||||
}
|
||||
@@ -142,8 +143,9 @@ sound_source::update( audio::openal_source &Source ) {
|
||||
|
||||
if( true == Source.is_playing ) {
|
||||
|
||||
// kill the sound if requested
|
||||
if( true == m_stop ) {
|
||||
if( ( true == m_stop )
|
||||
&& ( Source.buffers[ Source.buffer_index ] != m_soundend.buffer ) ) {
|
||||
// kill the sound if stop was requested, unless it's sound bookend sample
|
||||
Source.stop();
|
||||
update_counter( Source.buffers[ Source.buffer_index ], -1 );
|
||||
if( false == is_playing() ) {
|
||||
|
||||
Reference in New Issue
Block a user