2013-01-04 23:03:40 +00:00
//
// KRAudioSource.cpp
2021-08-16 16:35:36 -07:00
// Kraken Engine
2013-01-04 23:03:40 +00:00
//
2024-01-20 19:01:29 -08:00
// Copyright 2024 Kearwood Gilbert. All rights reserved.
2013-01-04 23:03:40 +00:00
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other materials
// provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY KEARWOOD GILBERT ''AS IS'' AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KEARWOOD GILBERT OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// The views and conclusions contained in the software and documentation are those of the
// authors and should not be interpreted as representing official policies, either expressed
// or implied, of Kearwood Gilbert.
//
# include "KRAudioSource.h"
# include "KRContext.h"
2024-08-17 23:12:20 -07:00
# include "resources/audio/KRAudioManager.h"
# include "resources/audio/KRAudioSample.h"
2013-01-05 04:04:58 +00:00
# include "KRAudioBuffer.h"
2024-01-21 18:34:36 -08:00
# include "KRRenderPass.h"
2013-01-04 23:03:40 +00:00
2023-08-05 21:14:53 -07:00
using namespace hydra ;
2020-06-21 22:42:10 -07:00
/* static */
void KRAudioSource : : InitNodeInfo ( KrNodeInfo * nodeInfo )
{
KRNode : : InitNodeInfo ( nodeInfo ) ;
nodeInfo - > audio_source . enable_obstruction = true ;
nodeInfo - > audio_source . enable_occlusion = true ;
nodeInfo - > audio_source . gain = 1.0f ;
nodeInfo - > audio_source . is_3d = true ;
nodeInfo - > audio_source . looping = false ;
nodeInfo - > audio_source . pitch = 1.0f ;
nodeInfo - > audio_source . reference_distance = 1.0f ;
nodeInfo - > audio_source . reverb = 0.0f ;
nodeInfo - > audio_source . rolloff_factor = 2.0f ;
nodeInfo - > audio_source . sample = - 1 ;
}
2022-08-08 01:07:26 -07:00
KRAudioSource : : KRAudioSource ( KRScene & scene , std : : string name ) : KRNode ( scene , name )
2013-01-04 23:03:40 +00:00
{
2022-08-08 01:07:26 -07:00
m_currentBufferFrame = 0 ;
m_playing = false ;
m_is3d = true ;
m_isPrimed = false ;
m_audioFile = NULL ;
m_gain = 1.0f ;
m_pitch = 1.0f ;
m_looping = false ;
2013-01-04 23:03:40 +00:00
2022-08-08 01:07:26 -07:00
m_referenceDistance = 1.0f ;
m_reverb = 0.0f ;
m_rolloffFactor = 2.0f ;
m_enable_occlusion = true ;
m_enable_obstruction = true ;
2013-01-04 23:03:40 +00:00
2022-08-08 01:07:26 -07:00
m_start_audio_frame = - 1 ;
m_paused_audio_frame = 0 ;
2013-01-04 23:03:40 +00:00
}
2022-08-08 01:07:26 -07:00
KRAudioSource : : ~ KRAudioSource ( )
2013-01-04 23:03:40 +00:00
{
2022-08-08 01:07:26 -07:00
while ( m_audioBuffers . size ( ) ) {
delete m_audioBuffers . front ( ) ;
m_audioBuffers . pop ( ) ;
}
}
std : : string KRAudioSource : : getElementName ( )
{
return " audio_source " ;
}
tinyxml2 : : XMLElement * KRAudioSource : : saveXML ( tinyxml2 : : XMLNode * parent )
{
tinyxml2 : : XMLElement * e = KRNode : : saveXML ( parent ) ;
e - > SetAttribute ( " sample " , m_audio_sample_name . c_str ( ) ) ;
e - > SetAttribute ( " gain " , m_gain ) ;
e - > SetAttribute ( " pitch " , m_pitch ) ;
e - > SetAttribute ( " looping " , m_looping ? " true " : " false " ) ;
e - > SetAttribute ( " is3d " , m_is3d ? " true " : " false " ) ;
e - > SetAttribute ( " reference_distance " , m_referenceDistance ) ;
e - > SetAttribute ( " reverb " , m_reverb ) ;
e - > SetAttribute ( " rolloff_factor " , m_rolloffFactor ) ;
e - > SetAttribute ( " enable_occlusion " , m_enable_occlusion ? " true " : " false " ) ;
e - > SetAttribute ( " enable_obstruction " , m_enable_obstruction ? " true " : " false " ) ;
return e ;
}
void KRAudioSource : : loadXML ( tinyxml2 : : XMLElement * e )
{
m_audio_sample_name = e - > Attribute ( " sample " ) ;
float gain = 1.0f ;
if ( e - > QueryFloatAttribute ( " gain " , & gain ) ! = tinyxml2 : : XML_SUCCESS ) {
gain = 1.0f ;
}
setGain ( gain ) ;
float pitch = 1.0f ;
if ( e - > QueryFloatAttribute ( " pitch " , & pitch ) ! = tinyxml2 : : XML_SUCCESS ) {
pitch = 1.0f ;
}
setPitch ( m_pitch ) ;
bool looping = false ;
if ( e - > QueryBoolAttribute ( " looping " , & looping ) ! = tinyxml2 : : XML_SUCCESS ) {
looping = false ;
}
setLooping ( looping ) ;
bool is3d = true ;
if ( e - > QueryBoolAttribute ( " is3d " , & is3d ) ! = tinyxml2 : : XML_SUCCESS ) {
is3d = true ;
}
setIs3D ( is3d ) ;
float reference_distance = 1.0f ;
if ( e - > QueryFloatAttribute ( " reference_distance " , & reference_distance ) ! = tinyxml2 : : XML_SUCCESS ) {
reference_distance = 1.0f ;
}
setReferenceDistance ( reference_distance ) ;
float reverb = 0.0f ;
if ( e - > QueryFloatAttribute ( " reverb " , & reverb ) ! = tinyxml2 : : XML_SUCCESS ) {
reverb = 0.0f ;
}
setReverb ( reverb ) ;
float rolloff_factor = 2.0f ;
if ( e - > QueryFloatAttribute ( " rolloff_factor " , & rolloff_factor ) ! = tinyxml2 : : XML_SUCCESS ) {
rolloff_factor = 2.0f ;
}
setRolloffFactor ( rolloff_factor ) ;
m_enable_obstruction = true ;
if ( e - > QueryBoolAttribute ( " enable_obstruction " , & m_enable_obstruction ) ! = tinyxml2 : : XML_SUCCESS ) {
2013-01-05 07:27:39 +00:00
m_enable_obstruction = true ;
2022-08-08 01:07:26 -07:00
}
2013-01-05 07:27:39 +00:00
2022-08-08 01:07:26 -07:00
m_enable_occlusion = true ;
if ( e - > QueryBoolAttribute ( " enable_occlusion " , & m_enable_occlusion ) ! = tinyxml2 : : XML_SUCCESS ) {
2013-01-05 07:27:39 +00:00
m_enable_occlusion = true ;
2022-08-08 01:07:26 -07:00
}
KRNode : : loadXML ( e ) ;
2013-01-04 23:03:40 +00:00
}
2013-01-05 04:04:58 +00:00
void KRAudioSource : : prime ( )
{
2022-08-08 01:07:26 -07:00
if ( ! m_isPrimed ) {
if ( m_audioFile = = NULL & & m_audio_sample_name . size ( ) ! = 0 ) {
m_audioFile = getContext ( ) . getAudioManager ( ) - > get ( m_audio_sample_name ) ;
}
if ( m_audioFile ) {
// Prime the buffer queue
m_nextBufferIndex = 0 ;
for ( int i = 0 ; i < KRENGINE_AUDIO_BUFFERS_PER_SOURCE ; i + + ) {
queueBuffer ( ) ;
}
m_isPrimed = true ;
2013-01-05 04:04:58 +00:00
}
2022-08-08 01:07:26 -07:00
}
2013-01-05 04:04:58 +00:00
}
void KRAudioSource : : queueBuffer ( )
{
2022-08-08 01:07:26 -07:00
KRAudioBuffer * buffer = m_audioFile - > getBuffer ( m_nextBufferIndex ) ;
m_audioBuffers . push ( buffer ) ;
m_nextBufferIndex = ( m_nextBufferIndex + 1 ) % m_audioFile - > getBufferCount ( ) ;
2013-01-05 04:04:58 +00:00
}
2013-01-04 23:03:40 +00:00
2022-04-06 01:00:13 -07:00
void KRAudioSource : : render ( RenderInfo & ri )
2013-01-04 23:03:40 +00:00
{
2022-08-08 01:07:26 -07:00
if ( m_lod_visible < = LOD_VISIBILITY_PRESTREAM ) return ;
KRNode : : render ( ri ) ;
bool bVisualize = false ;
2024-01-21 18:34:36 -08:00
if ( ri . renderPass - > getType ( ) = = RenderPassType : : RENDER_PASS_FORWARD_TRANSPARENT & & bVisualize ) {
2022-08-08 01:07:26 -07:00
KRMesh * sphereModel = getContext ( ) . getMeshManager ( ) - > getMaxLODModel ( " __sphere " ) ;
if ( sphereModel ) {
Matrix4 sphereModelMatrix = getModelMatrix ( ) ;
PipelineInfo info { } ;
std : : string shader_name ( " visualize_overlay " ) ;
info . shader_name = & shader_name ;
info . pCamera = ri . camera ;
info . point_lights = & ri . point_lights ;
info . directional_lights = & ri . directional_lights ;
info . spot_lights = & ri . spot_lights ;
info . renderPass = ri . renderPass ;
info . rasterMode = RasterMode : : kAdditive ;
info . modelFormat = sphereModel - > getModelFormat ( ) ;
info . vertexAttributes = sphereModel - > getVertexAttributes ( ) ;
KRPipeline * pShader = getContext ( ) . getPipelineManager ( ) - > getPipeline ( * ri . surface , info ) ;
2024-09-21 16:46:04 -07:00
pShader - > bind ( ri . commandBuffer , * ri . camera , * ri . viewport , sphereModelMatrix , & ri . point_lights , & ri . directional_lights , & ri . spot_lights , ri . renderPass ) ;
2022-08-08 01:07:26 -07:00
sphereModel - > renderNoMaterials ( ri . commandBuffer , ri . renderPass , getName ( ) , " visualize_overlay " , 1.0f ) ;
} // sphereModels.size()
}
2013-01-04 23:03:40 +00:00
}
2013-01-05 04:04:58 +00:00
void KRAudioSource : : setGain ( float gain )
{
2022-08-08 01:07:26 -07:00
m_gain = gain ;
2013-01-05 04:04:58 +00:00
}
float KRAudioSource : : getGain ( )
{
2022-08-08 01:07:26 -07:00
return m_gain ;
2013-01-05 04:04:58 +00:00
}
void KRAudioSource : : setPitch ( float pitch )
{
2022-08-08 01:07:26 -07:00
m_pitch = pitch ;
2013-01-05 04:04:58 +00:00
}
2013-01-05 07:27:39 +00:00
float KRAudioSource : : getReferenceDistance ( )
{
2022-08-08 01:07:26 -07:00
return m_referenceDistance ;
2013-01-05 07:27:39 +00:00
}
void KRAudioSource : : setReferenceDistance ( float reference_distance )
{
2022-08-08 01:07:26 -07:00
m_referenceDistance = reference_distance ;
2013-01-05 07:27:39 +00:00
}
float KRAudioSource : : getReverb ( )
{
2022-08-08 01:07:26 -07:00
return m_reverb ;
2013-01-05 07:27:39 +00:00
}
void KRAudioSource : : setReverb ( float reverb )
{
2022-08-08 01:07:26 -07:00
m_reverb = reverb ;
2013-01-05 07:27:39 +00:00
}
float KRAudioSource : : getRolloffFactor ( )
{
2022-08-08 01:07:26 -07:00
return m_rolloffFactor ;
2013-01-05 07:27:39 +00:00
}
void KRAudioSource : : setRolloffFactor ( float rolloff_factor )
{
2022-08-08 01:07:26 -07:00
m_rolloffFactor = rolloff_factor ;
2013-01-05 07:27:39 +00:00
}
2013-01-05 04:04:58 +00:00
void KRAudioSource : : setLooping ( bool looping )
{
2022-08-08 01:07:26 -07:00
// Enable or disable looping playback; Audio source must be stopped and re-started for loop mode changes to take effect
m_looping = looping ;
2013-01-05 04:04:58 +00:00
}
bool KRAudioSource : : getLooping ( )
{
2022-08-08 01:07:26 -07:00
// Returns true if the playback will automatically loop
return m_looping ;
2013-01-05 04:04:58 +00:00
}
2013-01-05 07:27:39 +00:00
bool KRAudioSource : : getEnableOcclusion ( )
{
2022-08-08 01:07:26 -07:00
return m_enable_occlusion ;
2013-01-05 07:27:39 +00:00
}
void KRAudioSource : : setEnableOcclusion ( bool enable_occlusion )
{
2022-08-08 01:07:26 -07:00
m_enable_occlusion = enable_occlusion ;
2013-01-05 07:27:39 +00:00
}
bool KRAudioSource : : getEnableObstruction ( )
{
2022-08-08 01:07:26 -07:00
return m_enable_obstruction ;
2013-01-05 07:27:39 +00:00
}
void KRAudioSource : : setEnableObstruction ( bool enable_obstruction )
{
2022-08-08 01:07:26 -07:00
m_enable_obstruction = enable_obstruction ;
2013-01-05 07:27:39 +00:00
}
bool KRAudioSource : : getIs3D ( )
{
2022-08-08 01:07:26 -07:00
return m_is3d ;
2013-01-05 07:27:39 +00:00
}
void KRAudioSource : : setIs3D ( bool is3D )
{
2022-08-08 01:07:26 -07:00
// Audio source must be stopped and re-started for mode change to take effect
m_is3d = is3D ;
2013-01-05 07:27:39 +00:00
}
2013-02-07 13:00:51 -08:00
void KRAudioSource : : advanceBuffer ( )
{
2022-08-08 01:07:26 -07:00
if ( m_audioBuffers . size ( ) ) {
delete m_audioBuffers . front ( ) ;
m_audioBuffers . pop ( ) ;
}
queueBuffer ( ) ;
2013-01-05 04:04:58 +00:00
}
void KRAudioSource : : physicsUpdate ( float deltaTime )
{
2022-08-08 01:07:26 -07:00
KRNode : : physicsUpdate ( deltaTime ) ;
KRAudioManager * audioManager = getContext ( ) . getAudioManager ( ) ;
audioManager - > activateAudioSource ( this ) ;
2013-01-05 04:04:58 +00:00
}
2013-01-04 23:03:40 +00:00
void KRAudioSource : : play ( )
{
2022-08-08 01:07:26 -07:00
// Start playback of audio at the current audio sample position. If audio is already playing, this has no effect.
// play() does not automatically seek to the beginning of the sample. Call setAudioFrame( 0 ) first if you wish the playback to begin at the start of the audio sample.
// If not set to looping, audio playback ends automatically at the end of the sample
if ( ! m_playing ) {
KRAudioManager * audioManager = getContext ( ) . getAudioManager ( ) ;
assert ( m_start_audio_frame = = - 1 ) ;
m_start_audio_frame = audioManager - > getAudioFrame ( ) - m_paused_audio_frame ;
m_paused_audio_frame = - 1 ;
audioManager - > activateAudioSource ( this ) ;
}
m_playing = true ;
2013-01-04 23:03:40 +00:00
}
void KRAudioSource : : stop ( )
{
2022-08-08 01:07:26 -07:00
// Stop playback of audio. If audio is already stopped, this has no effect.
// If play() is called afterwards, playback will continue at the current audio sample position.
if ( m_playing ) {
m_paused_audio_frame = getAudioFrame ( ) ;
m_start_audio_frame = - 1 ;
m_playing = false ;
getContext ( ) . getAudioManager ( ) - > deactivateAudioSource ( this ) ;
}
2013-01-04 23:03:40 +00:00
}
bool KRAudioSource : : isPlaying ( )
{
2022-08-08 01:07:26 -07:00
// Returns true if audio is playing. Will return false if a non-looped playback has reached the end of the audio sample.
return m_playing ;
2013-01-04 23:03:40 +00:00
}
2022-08-08 01:07:26 -07:00
void KRAudioSource : : setSample ( const std : : string & sound_name )
2013-01-04 23:03:40 +00:00
{
2022-08-08 01:07:26 -07:00
m_audio_sample_name = sound_name ;
2013-01-04 23:03:40 +00:00
}
2013-01-05 04:04:58 +00:00
std : : string KRAudioSource : : getSample ( )
2013-01-04 23:03:40 +00:00
{
2022-08-08 01:07:26 -07:00
return m_audio_sample_name ;
2013-01-04 23:03:40 +00:00
}
2013-01-05 07:27:39 +00:00
2022-08-08 01:07:26 -07:00
KRAudioSample * KRAudioSource : : getAudioSample ( )
2013-02-08 17:28:17 -08:00
{
2022-08-08 01:07:26 -07:00
if ( m_audioFile = = NULL & & m_audio_sample_name . size ( ) ! = 0 ) {
m_audioFile = getContext ( ) . getAudioManager ( ) - > get ( m_audio_sample_name ) ;
}
return m_audioFile ;
2013-02-08 17:28:17 -08:00
}
2013-02-07 13:00:51 -08:00
void KRAudioSource : : advanceFrames ( int frame_count )
{
2022-08-08 01:07:26 -07:00
m_currentBufferFrame + = frame_count ;
KRAudioBuffer * buffer = getBuffer ( ) ;
while ( buffer ! = NULL & & m_currentBufferFrame > = buffer - > getFrameCount ( ) ) {
m_currentBufferFrame - = buffer - > getFrameCount ( ) ;
advanceBuffer ( ) ;
buffer = getBuffer ( ) ;
}
if ( buffer = = NULL ) {
m_currentBufferFrame = 0 ;
stop ( ) ;
}
2013-01-05 07:27:39 +00:00
}
2022-08-08 01:07:26 -07:00
KRAudioBuffer * KRAudioSource : : getBuffer ( )
2013-02-07 13:00:51 -08:00
{
2022-08-08 01:07:26 -07:00
if ( m_playing ) {
prime ( ) ;
return m_audioBuffers . front ( ) ;
} else {
return NULL ;
}
2013-02-07 13:00:51 -08:00
}
int KRAudioSource : : getBufferFrame ( )
{
2022-08-08 01:07:26 -07:00
return m_currentBufferFrame ;
2013-02-07 13:00:51 -08:00
}
2013-01-05 07:27:39 +00:00
2013-11-17 01:46:12 -08:00
__int64_t KRAudioSource : : getAudioFrame ( )
{
2022-08-08 01:07:26 -07:00
// Returns the audio playback position in units of integer audio frames.
if ( m_playing ) {
return getContext ( ) . getAudioManager ( ) - > getAudioFrame ( ) - m_start_audio_frame ;
} else {
return m_paused_audio_frame ;
}
2013-11-17 01:46:12 -08:00
}
void KRAudioSource : : setAudioFrame ( __int64_t next_frame )
{
2022-08-08 01:07:26 -07:00
// Sets the audio playback position with units of integer audio frames.
if ( m_playing ) {
m_start_audio_frame = getContext ( ) . getAudioManager ( ) - > getAudioFrame ( ) - next_frame ;
} else {
m_paused_audio_frame = next_frame ;
}
2013-11-17 01:46:12 -08:00
}
float KRAudioSource : : getAudioTime ( )
{
2022-08-08 01:07:26 -07:00
// Gets the audio playback position with units of floating point seconds.
return getAudioFrame ( ) / 44100.0f ;
2013-11-17 01:46:12 -08:00
}
void KRAudioSource : : setAudioTime ( float new_position )
2013-02-08 17:28:17 -08:00
{
2022-08-08 01:07:26 -07:00
// Sets the audio playback position with units of floating point seconds.
setAudioFrame ( ( __int64_t ) ( new_position * 44100.0f ) ) ;
2013-02-08 17:28:17 -08:00
}
2022-08-08 01:07:26 -07:00
void KRAudioSource : : sample ( int frame_count , int channel , float * buffer , float gain )
2013-02-27 13:11:24 -08:00
{
2022-08-08 01:07:26 -07:00
KRAudioSample * source_sample = getAudioSample ( ) ;
if ( source_sample & & m_playing ) {
__int64_t next_frame = getAudioFrame ( ) ;
source_sample - > sample ( next_frame , frame_count , channel , buffer , gain , m_looping ) ;
if ( ! m_looping & & next_frame > source_sample - > getFrameCount ( ) ) {
stop ( ) ;
2013-02-27 13:11:24 -08:00
}
2022-08-08 01:07:26 -07:00
} else {
memset ( buffer , 0 , sizeof ( float ) * frame_count ) ;
}
2013-02-27 13:11:24 -08:00
}