16
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-07-22 19:49:19 +02:00

openalsoft compatibility fixes, basic measures for exceeding audio source limit

This commit is contained in:
tmj-fstate
2017-12-01 04:12:26 +01:00
parent 76e58200d2
commit 0f0cb4209b
6 changed files with 88 additions and 45 deletions

View File

@@ -4162,7 +4162,7 @@ void TDynamicObject::RenderSounds() {
} }
if( std::abs( MoverParameters->nrot ) > 0.01 ) { if( std::abs( MoverParameters->nrot ) > 0.01 ) {
// hamulce wzmagaja halas // hamulce wzmagaja halas
volume *= 1 + MoverParameters->UnitBrakeForce / ( 1 + MoverParameters->MaxBrakeForce ); volume *= 1 + 0.25 * ( MoverParameters->UnitBrakeForce / ( 1 + MoverParameters->MaxBrakeForce ) );
} }
// scale volume by track quality // scale volume by track quality
volume *= ( 20.0 + MyTrack->iDamageFlag ) / 21; volume *= ( 20.0 + MyTrack->iDamageFlag ) / 21;

View File

@@ -131,8 +131,11 @@ bool Global::FullPhysics { true }; // full calculations performed for each simul
// parametry testowe (do testowania scenerii i obiektów) // parametry testowe (do testowania scenerii i obiektów)
bool Global::bWireFrame = false; bool Global::bWireFrame = false;
// sound renderer
bool Global::bSoundEnabled = true; bool Global::bSoundEnabled = true;
float Global::AudioVolume = 1.0f; float Global::AudioVolume = 1.0f;
std::string Global::AudioRenderer;
int Global::iWriteLogEnabled = 3; // maska bitowa: 1-zapis do pliku, 2-okienko, 4-nazwy torów int Global::iWriteLogEnabled = 3; // maska bitowa: 1-zapis do pliku, 2-okienko, 4-nazwy torów
bool Global::MultipleLogs{ false }; bool Global::MultipleLogs{ false };
@@ -281,6 +284,10 @@ void Global::ConfigParse(cParser &Parser)
Parser.getTokens(); Parser.getTokens();
Parser >> Global::bSoundEnabled; Parser >> Global::bSoundEnabled;
} }
else if( token == "sound.openal.renderer" ) {
// selected device for audio renderer
Global::AudioRenderer = Parser.getToken<std::string>( false ); // case-sensitive
}
// else if (str==AnsiString("renderalpha")) //McZapkie-1312302 - dwuprzebiegowe renderowanie // else if (str==AnsiString("renderalpha")) //McZapkie-1312302 - dwuprzebiegowe renderowanie
// bRenderAlpha=(GetNextSymbol().LowerCase()==AnsiString("yes")); // bRenderAlpha=(GetNextSymbol().LowerCase()==AnsiString("yes"));
else if (token == "physicslog") else if (token == "physicslog")

View File

@@ -165,8 +165,6 @@ public:
static bool VSync; static bool VSync;
static bool bFreeFly; static bool bFreeFly;
static bool bWireFrame; static bool bWireFrame;
static bool bSoundEnabled;
static float AudioVolume;
// McZapkie-131202 // McZapkie-131202
static bool bAdjustScreenFreq; static bool bAdjustScreenFreq;
static bool bEnableTraction; static bool bEnableTraction;
@@ -215,6 +213,10 @@ public:
static bool bSmoothTraction; // wygładzanie drutów static bool bSmoothTraction; // wygładzanie drutów
static float SplineFidelity; // determines segment size during conversion of splines to geometry static float SplineFidelity; // determines segment size during conversion of splines to geometry
static GLfloat FogColor[]; static GLfloat FogColor[];
// sound renderer variables
static bool bSoundEnabled;
static float AudioVolume;
static std::string AudioRenderer;
static bool FullPhysics; // full calculations performed for each simulation step static bool FullPhysics; // full calculations performed for each simulation step
static int iSlowMotion; static int iSlowMotion;

View File

@@ -24,14 +24,22 @@ float const EU07_SOUND_CUTOFFRANGE { 3000.f }; // 2750 m = max expected emitter
void void
openal_source::play() { openal_source::play() {
if( id == audio::null_resource ) { return; } // no implementation-side source to match, no point
::alGetError(); // pop the error stack
::alSourcePlay( id ); ::alSourcePlay( id );
is_playing = true; is_playing = (
::alGetError() == AL_NO_ERROR ?
true :
false );
} }
// stops the playback // stops the playback
void void
openal_source::stop() { openal_source::stop() {
if( id == audio::null_resource ) { return; } // no implementation-side source to match, no point
loop( false ); loop( false );
// NOTE: workaround for potential edge cases where ::alSourceStop() doesn't set source which wasn't yet started to AL_STOPPED // NOTE: workaround for potential edge cases where ::alSourceStop() doesn't set source which wasn't yet started to AL_STOPPED
int state; int state;
@@ -49,6 +57,8 @@ openal_source::update( double const Deltatime ) {
update_deltatime = Deltatime; // cached for time-based processing of data from the controller update_deltatime = Deltatime; // cached for time-based processing of data from the controller
if( id != audio::null_resource ) {
::alGetSourcei( id, AL_BUFFERS_PROCESSED, &buffer_index ); ::alGetSourcei( id, AL_BUFFERS_PROCESSED, &buffer_index );
// for multipart sounds trim away processed sources until only one remains, the last one may be set to looping by the controller // for multipart sounds trim away processed sources until only one remains, the last one may be set to looping by the controller
ALuint bufferid; ALuint bufferid;
@@ -62,6 +72,7 @@ openal_source::update( double const Deltatime ) {
int state; int state;
::alGetSourcei( id, AL_SOURCE_STATE, &state ); ::alGetSourcei( id, AL_SOURCE_STATE, &state );
is_playing = ( state == AL_PLAYING ); is_playing = ( state == AL_PLAYING );
}
// request instructions from the controller // request instructions from the controller
controller->update( *this ); controller->update( *this );
@@ -71,6 +82,11 @@ openal_source::update( double const Deltatime ) {
void void
openal_source::sync_with( sound_properties const &State ) { openal_source::sync_with( sound_properties const &State ) {
if( id == audio::null_resource ) {
// no implementation-side source to match, return sync error so the controller can clean up on its end
is_synced = false;
return;
}
/* /*
// velocity // velocity
// not used yet // not used yet
@@ -79,12 +95,15 @@ openal_source::sync_with( sound_properties const &State ) {
// location // location
properties.location = State.location; properties.location = State.location;
auto sourceoffset { glm::vec3 { properties.location - glm::dvec3 { Global::pCameraPosition } } }; auto sourceoffset { glm::vec3 { properties.location - glm::dvec3 { Global::pCameraPosition } } };
if( glm::length2( sourceoffset ) > std::max( ( sound_range * sound_range ), ( EU07_SOUND_CUTOFFRANGE * EU07_SOUND_CUTOFFRANGE ) ) ) { if( sound_range > 0 ) {
// range cutoff check // range cutoff check
auto const cutoffrange { sound_range * 7.5f };
if( glm::length2( sourceoffset ) > std::min( ( cutoffrange * cutoffrange ), ( EU07_SOUND_CUTOFFRANGE * EU07_SOUND_CUTOFFRANGE ) ) ) {
stop(); stop();
is_synced = false; // flag sync failure for the controller is_synced = false; // flag sync failure for the controller
return; return;
} }
}
if( sound_range >= 0 ) { if( sound_range >= 0 ) {
::alSourcefv( id, AL_POSITION, glm::value_ptr( sourceoffset ) ); ::alSourcefv( id, AL_POSITION, glm::value_ptr( sourceoffset ) );
} }
@@ -116,14 +135,17 @@ openal_source::sync_with( sound_properties const &State ) {
void void
openal_source::range( float const Range ) { openal_source::range( float const Range ) {
auto const range(
Range >= 0 ?
Range :
5 ); // range of -1 means sound of unlimited range, positioned at the listener
::alSourcef( id, AL_REFERENCE_DISTANCE, range * ( 1.f / 16.f ) );
::alSourcef( id, AL_ROLLOFF_FACTOR, 1.5f );
// NOTE: we cache actual specified range, as we'll be giving 'unlimited' range special treatment // NOTE: we cache actual specified range, as we'll be giving 'unlimited' range special treatment
sound_range = Range; sound_range = Range;
if( id == audio::null_resource ) { return; } // no implementation-side source to match, no point
auto const range { (
Range >= 0 ?
Range :
5 ) }; // range of -1 means sound of unlimited range, positioned at the listener
::alSourcef( id, AL_REFERENCE_DISTANCE, range * ( 1.f / 16.f ) );
::alSourcef( id, AL_ROLLOFF_FACTOR, 1.5f );
} }
// sets modifier applied to the pitch of sounds emitted by the source // sets modifier applied to the pitch of sounds emitted by the source
@@ -139,6 +161,7 @@ openal_source::pitch( float const Pitch ) {
void void
openal_source::loop( bool const State ) { openal_source::loop( bool const State ) {
if( id == audio::null_resource ) { return; } // no implementation-side source to match, no point
if( is_looping == State ) { return; } if( is_looping == State ) { return; }
is_looping = State; is_looping = State;
@@ -154,6 +177,8 @@ openal_source::loop( bool const State ) {
// NOTE: doesn't release allocated implementation-side source // NOTE: doesn't release allocated implementation-side source
void void
openal_source::clear() { openal_source::clear() {
if( id != audio::null_resource ) {
// unqueue bound buffers: // unqueue bound buffers:
// ensure no buffer is in use... // ensure no buffer is in use...
stop(); stop();
@@ -162,7 +187,9 @@ openal_source::clear() {
bufferids.resize( buffers.size() ); bufferids.resize( buffers.size() );
// ...release the buffers... // ...release the buffers...
::alSourceUnqueueBuffers( id, bufferids.size(), bufferids.data() ); ::alSourceUnqueueBuffers( id, bufferids.size(), bufferids.data() );
}
// ...and reset reset the properties, except for the id of the allocated source // ...and reset reset the properties, except for the id of the allocated source
// NOTE: not strictly necessary since except for the id the source data typically get discarded in next step
auto const sourceid { id }; auto const sourceid { id };
*this = openal_source(); *this = openal_source();
id = sourceid; id = sourceid;
@@ -231,7 +258,10 @@ openal_renderer::erase( sound_source const *Controller ) {
if( source->controller == Controller ) { if( source->controller == Controller ) {
// if the controller is the one specified, kill it // if the controller is the one specified, kill it
source->clear(); source->clear();
m_sourcespares.push( *source ); if( source->id != audio::null_resource ) {
// keep around functional sources, but no point in doing it with the above-the-limit ones
m_sourcespares.push( source->id );
}
source = m_sources.erase( source ); source = m_sources.erase( source );
} }
else { else {
@@ -268,7 +298,10 @@ openal_renderer::update( double const Deltatime ) {
// if after the update the source isn't playing, put it away on the spare stack, it's done // if after the update the source isn't playing, put it away on the spare stack, it's done
if( false == source->is_playing ) { if( false == source->is_playing ) {
source->clear(); source->clear();
m_sourcespares.push( *source ); if( source->id != audio::null_resource ) {
// keep around functional sources, but no point in doing it with the above-the-limit ones
m_sourcespares.push( source->id );
}
source = m_sources.erase( source ); source = m_sources.erase( source );
} }
else { else {
@@ -285,7 +318,7 @@ openal_renderer::fetch_source() {
audio::openal_source soundsource; audio::openal_source soundsource;
if( false == m_sourcespares.empty() ) { if( false == m_sourcespares.empty() ) {
// reuse (a copy of) already allocated source // reuse (a copy of) already allocated source
soundsource = m_sourcespares.top(); soundsource.id = m_sourcespares.top();
m_sourcespares.pop(); m_sourcespares.pop();
} }
return soundsource; return soundsource;
@@ -294,9 +327,8 @@ openal_renderer::fetch_source() {
bool bool
openal_renderer::init_caps() { openal_renderer::init_caps() {
// select the "preferred device" // NOTE: default value of audio renderer variable is empty string, meaning argument of NULL i.e. 'preferred' device
// TODO: support for opening config-specified device m_device = ::alcOpenDevice( Global::AudioRenderer.c_str() );
m_device = ::alcOpenDevice( nullptr );
if( m_device == nullptr ) { if( m_device == nullptr ) {
ErrorLog( "Failed to obtain audio device" ); ErrorLog( "Failed to obtain audio device" );
return false; return false;

View File

@@ -55,6 +55,7 @@ struct openal_source {
for( auto const buffer : buffers ) { for( auto const buffer : buffers ) {
bufferids.emplace_back( audio::renderer.buffer( buffer ).id ); } bufferids.emplace_back( audio::renderer.buffer( buffer ).id ); }
::alSourceQueueBuffers( id, bufferids.size(), bufferids.data() ); ::alSourceQueueBuffers( id, bufferids.size(), bufferids.data() );
::alSourceRewind( id );
return *this; } return *this; }
// starts playback of queued buffers // starts playback of queued buffers
void void
@@ -128,7 +129,7 @@ public:
private: private:
// types // types
using source_list = std::list<audio::openal_source>; using source_list = std::list<audio::openal_source>;
using source_sequence = std::stack<audio::openal_source>; using source_sequence = std::stack<ALuint>;
// methods // methods
bool bool
init_caps(); init_caps();

View File

@@ -86,10 +86,7 @@ sound_source::play( int const Flags ) {
return; return;
} }
if( m_range > 0 ) { if( m_range > 0 ) {
auto const cutoffrange{ ( auto const cutoffrange{ m_range * 5 };
( m_soundbegin.buffer != null_handle ) && ( Flags & sound_flags::looping ) ?
m_range * 10 : // larger margin to let the startup sample finish playing at safe distance
m_range * 5 ) };
if( glm::length2( location() - glm::dvec3{ Global::pCameraPosition } ) > std::min( 2750.f * 2750.f, cutoffrange * cutoffrange ) ) { if( glm::length2( location() - glm::dvec3{ Global::pCameraPosition } ) > std::min( 2750.f * 2750.f, cutoffrange * cutoffrange ) ) {
// drop sounds from beyond sensible and/or audible range // drop sounds from beyond sensible and/or audible range
return; return;
@@ -196,6 +193,10 @@ sound_source::update( audio::openal_source &Source ) {
if( true == Source.is_synced ) { if( true == Source.is_synced ) {
// all set, start playback // all set, start playback
Source.play(); Source.play();
if( false == Source.is_playing ) {
// if the playback didn't start update the state counter
update_counter( buffer, -1 );
}
} }
else { else {
// if the initial sync went wrong we skip the activation so the renderer can clean the emitter on its end // if the initial sync went wrong we skip the activation so the renderer can clean the emitter on its end