build 171202. audio subsystem: volume support, source reassignment, bug fixes

This commit is contained in:
tmj-fstate
2017-12-03 02:35:49 +01:00
parent 0f0cb4209b
commit 5645c13362
11 changed files with 122 additions and 58 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,5 +1,5 @@
#pragma once
#define VERSION_MAJOR 17
#define VERSION_MINOR 1130
#define VERSION_MINOR 1202
#define VERSION_REVISION 0