You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
256 lines
6.4 KiB
C++
256 lines
6.4 KiB
C++
// Copyright 1998-2014 Epic Games, Inc. All Rights Reserved.
|
|
|
|
/*------------------------------------------------------------------------------------
|
|
FALSoundSource.
|
|
------------------------------------------------------------------------------------*/
|
|
|
|
#include "HTML5AudioDevice.h"
|
|
#include "Engine.h"
|
|
/**
|
|
* Initializes a source with a given wave instance and prepares it for playback.
|
|
*
|
|
* @param WaveInstance wave instace being primed for playback
|
|
* @return TRUE if initialization was successful, FALSE otherwise
|
|
*/
|
|
bool FALSoundSource::Init( FWaveInstance* InWaveInstance )
|
|
{
|
|
if (InWaveInstance->OutputTarget != EAudioOutputTarget::Controller)
|
|
{
|
|
// Find matching buffer.
|
|
Buffer = FALSoundBuffer::Init( (FALAudioDevice*)AudioDevice, InWaveInstance->WaveData );
|
|
if( Buffer )
|
|
{
|
|
SCOPE_CYCLE_COUNTER( STAT_AudioSourceInitTime );
|
|
|
|
WaveInstance = InWaveInstance;
|
|
|
|
// Enable/disable spatialization of sounds
|
|
alSourcei( SourceId, AL_SOURCE_RELATIVE, WaveInstance->bUseSpatialization ? AL_FALSE : AL_TRUE );
|
|
|
|
// Setting looping on a real time decompressed source suppresses the buffers processed message
|
|
alSourcei( SourceId, AL_LOOPING, ( WaveInstance->LoopingMode == LOOP_Forever ) ? AL_TRUE : AL_FALSE );
|
|
|
|
// Always queue up the first buffer
|
|
alSourceQueueBuffers( SourceId, 1, Buffer->BufferIds );
|
|
if( WaveInstance->LoopingMode == LOOP_WithNotification )
|
|
{
|
|
// We queue the sound twice for wave instances that use seamless looping so we can have smooth
|
|
// loop transitions. The downside is that we might play at most one frame worth of audio from the
|
|
// beginning of the wave after the wave stops looping.
|
|
alSourceQueueBuffers( SourceId, 1, Buffer->BufferIds );
|
|
}
|
|
|
|
Update();
|
|
|
|
// Initialization was successful.
|
|
return true ;
|
|
}
|
|
}
|
|
|
|
// Failed to initialize source.
|
|
return false ;
|
|
}
|
|
|
|
/**
|
|
* Clean up any hardware referenced by the sound source
|
|
*/
|
|
FALSoundSource::~FALSoundSource( void )
|
|
{
|
|
// @todo openal: What do we do here
|
|
/// AudioDevice->DestroyEffect( this );
|
|
|
|
alDeleteSources( 1, &SourceId );
|
|
}
|
|
|
|
/**
|
|
* Updates the source specific parameter like e.g. volume and pitch based on the associated
|
|
* wave instance.
|
|
*/
|
|
void FALSoundSource::Update( void )
|
|
{
|
|
SCOPE_CYCLE_COUNTER( STAT_AudioUpdateSources );
|
|
|
|
if( !WaveInstance || Paused )
|
|
{
|
|
return;
|
|
}
|
|
|
|
float Volume = WaveInstance->Volume * WaveInstance->VolumeMultiplier;
|
|
if( SetStereoBleed() )
|
|
{
|
|
// Emulate the bleed to rear speakers followed by stereo fold down
|
|
Volume *= 1.25f;
|
|
}
|
|
Volume *= GVolumeMultiplier;
|
|
|
|
Volume = FMath::Clamp(Volume, 0.0f, MAX_VOLUME );
|
|
float Pitch = FMath::Clamp(WaveInstance->Pitch, MIN_PITCH, MAX_PITCH );
|
|
|
|
|
|
// Set whether to apply reverb
|
|
SetReverbApplied( true );
|
|
|
|
// Set the HighFrequencyGain value
|
|
SetHighFrequencyGain();
|
|
|
|
FVector Location;
|
|
FVector Velocity;
|
|
|
|
// See file header for coordinate system explanation.
|
|
Location.X = WaveInstance->Location.X;
|
|
Location.Y = WaveInstance->Location.Z; // Z/Y swapped on purpose, see file header
|
|
Location.Z = WaveInstance->Location.Y; // Z/Y swapped on purpose, see file header
|
|
|
|
Velocity.X = WaveInstance->Velocity.X;
|
|
Velocity.Y = WaveInstance->Velocity.Z; // Z/Y swapped on purpose, see file header
|
|
Velocity.Z = WaveInstance->Velocity.Y; // Z/Y swapped on purpose, see file header
|
|
|
|
// Convert to meters.
|
|
Location *= AUDIO_DISTANCE_FACTOR;
|
|
Velocity *= AUDIO_DISTANCE_FACTOR;
|
|
|
|
// We're using a relative coordinate system for un- spatialized sounds.
|
|
if( !WaveInstance->bUseSpatialization )
|
|
{
|
|
Location = FVector( 0.f, 0.f, 0.f );
|
|
}
|
|
|
|
alSourcef( SourceId, AL_GAIN, Volume );
|
|
alSourcef( SourceId, AL_PITCH, Pitch );
|
|
|
|
alSourcefv( SourceId, AL_POSITION, ( ALfloat * )&Location );
|
|
alSourcefv( SourceId, AL_VELOCITY, ( ALfloat * )&Velocity );
|
|
|
|
// Platform dependent call to update the sound output with new parameters
|
|
// @todo openal: Is this no longer needed?
|
|
/// AudioDevice->UpdateEffect( this );
|
|
}
|
|
|
|
/**
|
|
* Plays the current wave instance.
|
|
*/
|
|
void FALSoundSource::Play( void )
|
|
{
|
|
if( WaveInstance )
|
|
{
|
|
alSourcePlay( SourceId );
|
|
Paused = false;
|
|
Playing = true;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Stops the current wave instance and detaches it from the source.
|
|
*/
|
|
void FALSoundSource::Stop( void )
|
|
{
|
|
if( WaveInstance )
|
|
{
|
|
alSourceStop( SourceId );
|
|
// This clears out any pending buffers that may or may not be queued or played
|
|
alSourcei( SourceId, AL_BUFFER, 0 );
|
|
Paused = false;
|
|
Playing = false;
|
|
Buffer = NULL;
|
|
}
|
|
|
|
FSoundSource::Stop();
|
|
}
|
|
|
|
/**
|
|
* Pauses playback of current wave instance.
|
|
*/
|
|
void FALSoundSource::Pause( void )
|
|
{
|
|
if( WaveInstance )
|
|
{
|
|
alSourcePause( SourceId );
|
|
Paused = true;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns TRUE if an OpenAL source has finished playing
|
|
*/
|
|
bool FALSoundSource::IsSourceFinished( void )
|
|
{
|
|
ALint State = AL_STOPPED;
|
|
|
|
// Check the source for data to continue playing
|
|
alGetSourcei( SourceId, AL_SOURCE_STATE, &State );
|
|
if( State == AL_PLAYING || State == AL_PAUSED )
|
|
{
|
|
return( false );
|
|
}
|
|
|
|
return( true );
|
|
}
|
|
|
|
/**
|
|
* Handle dequeuing and requeuing of a single buffer
|
|
*/
|
|
void FALSoundSource::HandleQueuedBuffer( void )
|
|
{
|
|
ALuint DequeuedBuffer;
|
|
|
|
// Unqueue the processed buffers
|
|
alSourceUnqueueBuffers( SourceId, 1, &DequeuedBuffer );
|
|
|
|
// Notify the wave instance that the current (native) buffer has finished playing.
|
|
WaveInstance->NotifyFinished();
|
|
|
|
// Queue the same packet again for looping
|
|
alSourceQueueBuffers( SourceId, 1, Buffer->BufferIds );
|
|
}
|
|
|
|
/**
|
|
* Queries the status of the currently associated wave instance.
|
|
*
|
|
* @return TRUE if the wave instance/ source has finished playback and FALSE if it is
|
|
* currently playing or paused.
|
|
*/
|
|
bool FALSoundSource::IsFinished( void )
|
|
{
|
|
if( WaveInstance )
|
|
{
|
|
// Check for a non starved, stopped source
|
|
if( IsSourceFinished() )
|
|
{
|
|
// Notify the wave instance that it has finished playing.
|
|
WaveInstance->NotifyFinished();
|
|
return( true );
|
|
}
|
|
else
|
|
{
|
|
// Check to see if any complete buffers have been processed
|
|
ALint BuffersProcessed;
|
|
alGetSourcei( SourceId, AL_BUFFERS_PROCESSED, &BuffersProcessed );
|
|
|
|
switch( BuffersProcessed )
|
|
{
|
|
case 0:
|
|
// No buffers need updating
|
|
break;
|
|
|
|
case 1:
|
|
// Standard case of 1 buffer expired which needs repopulating
|
|
HandleQueuedBuffer();
|
|
break;
|
|
|
|
case 2:
|
|
// Starvation case when the source has stopped
|
|
HandleQueuedBuffer();
|
|
HandleQueuedBuffer();
|
|
|
|
// Restart the source
|
|
alSourcePlay( SourceId );
|
|
break;
|
|
}
|
|
}
|
|
|
|
return( false );
|
|
}
|
|
|
|
return( true );
|
|
}
|