From e30f90cc6602d8c5ea159e2d0c34f211c8489983 Mon Sep 17 00:00:00 2001 From: Kearwood Gilbert Date: Thu, 28 Feb 2013 19:09:27 -0800 Subject: [PATCH] Ambient Zones and Reverb Zones implemented and now working with Siren. --- KREngine/Kraken.xcodeproj/project.pbxproj | 36 ++- KREngine/kraken/KRAmbientZone.cpp | 166 ++++++++++ .../{KRAmbientSphere.h => KRAmbientZone.h} | 19 +- KREngine/kraken/KRAudioManager.cpp | 299 ++++++++++++++---- KREngine/kraken/KRAudioManager.h | 52 ++- KREngine/kraken/KRAudioSample.cpp | 115 ++++--- KREngine/kraken/KRAudioSample.h | 2 +- KREngine/kraken/KRAudioSource.cpp | 26 +- KREngine/kraken/KRContext.cpp | 1 + KREngine/kraken/KREngine-common.h | 2 + KREngine/kraken/KRNode.cpp | 10 +- .../{KRAmbientSphere.cpp => KRReverbZone.cpp} | 101 +++--- KREngine/kraken/KRReverbZone.h | 52 +++ KREngine/kraken/KRScene.cpp | 28 ++ KREngine/kraken/KRScene.h | 7 + 15 files changed, 689 insertions(+), 227 deletions(-) create mode 100644 KREngine/kraken/KRAmbientZone.cpp rename KREngine/kraken/{KRAmbientSphere.h => KRAmbientZone.h} (75%) rename KREngine/kraken/{KRAmbientSphere.cpp => KRReverbZone.cpp} (59%) create mode 100644 KREngine/kraken/KRReverbZone.h diff --git a/KREngine/Kraken.xcodeproj/project.pbxproj b/KREngine/Kraken.xcodeproj/project.pbxproj index c987b18..e7d6117 100644 --- a/KREngine/Kraken.xcodeproj/project.pbxproj +++ b/KREngine/Kraken.xcodeproj/project.pbxproj @@ -78,6 +78,10 @@ E44F38251683B23000399B5D /* KRRenderSettings.h in Headers */ = {isa = PBXBuildFile; fileRef = E44F38231683B22C00399B5D /* KRRenderSettings.h */; settings = {ATTRIBUTES = (Public, ); }; }; E44F38281683B24800399B5D /* KRRenderSettings.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E44F38271683B24400399B5D /* KRRenderSettings.cpp */; }; E44F38291683B24800399B5D /* KRRenderSettings.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E44F38271683B24400399B5D /* KRRenderSettings.cpp */; }; + E450273916E0491D00FDEC5C /* KRReverbZone.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E450273716E0491D00FDEC5C /* KRReverbZone.cpp */; }; + E450273A16E0491D00FDEC5C /* KRReverbZone.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E450273716E0491D00FDEC5C /* KRReverbZone.cpp */; }; + E450273B16E0491D00FDEC5C /* KRReverbZone.h in Headers */ = {isa = PBXBuildFile; fileRef = E450273816E0491D00FDEC5C /* KRReverbZone.h */; settings = {ATTRIBUTES = (Public, ); }; }; + E450273C16E0491D00FDEC5C /* KRReverbZone.h in Headers */ = {isa = PBXBuildFile; fileRef = E450273816E0491D00FDEC5C /* KRReverbZone.h */; settings = {ATTRIBUTES = (Public, ); }; }; E459040416C30CC5002B00A0 /* AudioUnit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E459040316C30CC5002B00A0 /* AudioUnit.framework */; }; E459040616C30CD9002B00A0 /* AudioUnit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E459040516C30CD9002B00A0 /* AudioUnit.framework */; }; E460292616681CFF00261BB9 /* KRTextureAnimated.h in Headers */ = {isa = PBXBuildFile; fileRef = E460292516681CFE00261BB9 /* KRTextureAnimated.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -168,10 +172,10 @@ E4924C2715EE95E800B965C6 /* KROctree.h in Headers */ = {isa = PBXBuildFile; fileRef = E4924C2515EE95E800B965C6 /* KROctree.h */; settings = {ATTRIBUTES = (Public, ); }; }; E4924C2B15EE96AB00B965C6 /* KROctreeNode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E4924C2915EE96AA00B965C6 /* KROctreeNode.cpp */; }; E4924C2C15EE96AB00B965C6 /* KROctreeNode.h in Headers */ = {isa = PBXBuildFile; fileRef = E4924C2A15EE96AA00B965C6 /* KROctreeNode.h */; settings = {ATTRIBUTES = (Public, ); }; }; - E4943231169E08D200BCB891 /* KRAmbientSphere.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E494322F169E08D200BCB891 /* KRAmbientSphere.cpp */; }; - E4943232169E08D200BCB891 /* KRAmbientSphere.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E494322F169E08D200BCB891 /* KRAmbientSphere.cpp */; }; - E4943233169E08D200BCB891 /* KRAmbientSphere.h in Headers */ = {isa = PBXBuildFile; fileRef = E4943230169E08D200BCB891 /* KRAmbientSphere.h */; settings = {ATTRIBUTES = (Public, ); }; }; - E4943234169E08D200BCB891 /* KRAmbientSphere.h in Headers */ = {isa = PBXBuildFile; fileRef = E4943230169E08D200BCB891 /* KRAmbientSphere.h */; settings = {ATTRIBUTES = (Public, ); }; }; + E4943231169E08D200BCB891 /* KRAmbientZone.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E494322F169E08D200BCB891 /* KRAmbientZone.cpp */; }; + E4943232169E08D200BCB891 /* KRAmbientZone.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E494322F169E08D200BCB891 /* KRAmbientZone.cpp */; }; + E4943233169E08D200BCB891 /* KRAmbientZone.h in Headers */ = {isa = PBXBuildFile; fileRef = E4943230169E08D200BCB891 /* KRAmbientZone.h */; settings = {ATTRIBUTES = (Public, ); }; }; + E4943234169E08D200BCB891 /* KRAmbientZone.h in Headers */ = {isa = PBXBuildFile; fileRef = E4943230169E08D200BCB891 /* KRAmbientZone.h */; settings = {ATTRIBUTES = (Public, ); }; }; E497B946151BA99500D3DC67 /* KRVector2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E497B945151BA99400D3DC67 /* KRVector2.cpp */; }; E497B947151BA99500D3DC67 /* KRVector2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E497B945151BA99400D3DC67 /* KRVector2.cpp */; }; E497B948151BB89D00D3DC67 /* KRVector2.h in Headers */ = {isa = PBXBuildFile; fileRef = E497B943151BA93400D3DC67 /* KRVector2.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -401,6 +405,8 @@ E43B0AD515DDCA0D00A5CB9F /* KRContextObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KRContextObject.h; sourceTree = ""; }; E44F38231683B22C00399B5D /* KRRenderSettings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KRRenderSettings.h; sourceTree = ""; }; E44F38271683B24400399B5D /* KRRenderSettings.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = KRRenderSettings.cpp; sourceTree = ""; }; + E450273716E0491D00FDEC5C /* KRReverbZone.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = KRReverbZone.cpp; sourceTree = ""; }; + E450273816E0491D00FDEC5C /* KRReverbZone.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KRReverbZone.h; sourceTree = ""; }; E459040316C30CC5002B00A0 /* AudioUnit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioUnit.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.8.sdk/System/Library/Frameworks/AudioUnit.framework; sourceTree = DEVELOPER_DIR; }; E459040516C30CD9002B00A0 /* AudioUnit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioUnit.framework; path = System/Library/Frameworks/AudioUnit.framework; sourceTree = SDKROOT; }; E460292516681CFE00261BB9 /* KRTextureAnimated.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KRTextureAnimated.h; sourceTree = ""; }; @@ -467,8 +473,8 @@ E4924C2515EE95E800B965C6 /* KROctree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KROctree.h; sourceTree = ""; }; E4924C2915EE96AA00B965C6 /* KROctreeNode.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = KROctreeNode.cpp; sourceTree = ""; }; E4924C2A15EE96AA00B965C6 /* KROctreeNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KROctreeNode.h; sourceTree = ""; }; - E494322F169E08D200BCB891 /* KRAmbientSphere.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = KRAmbientSphere.cpp; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.cpp; }; - E4943230169E08D200BCB891 /* KRAmbientSphere.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = KRAmbientSphere.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; + E494322F169E08D200BCB891 /* KRAmbientZone.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = KRAmbientZone.cpp; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.cpp; }; + E4943230169E08D200BCB891 /* KRAmbientZone.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = KRAmbientZone.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; E497B943151BA93400D3DC67 /* KRVector2.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = KRVector2.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; E497B945151BA99400D3DC67 /* KRVector2.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = KRVector2.cpp; sourceTree = ""; }; E497B949151BCEE900D3DC67 /* KRResource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KRResource.h; sourceTree = ""; }; @@ -891,8 +897,10 @@ children = ( E48B68131697794F00D99917 /* KRAudioSource.cpp */, E48B68141697794F00D99917 /* KRAudioSource.h */, - E494322F169E08D200BCB891 /* KRAmbientSphere.cpp */, - E4943230169E08D200BCB891 /* KRAmbientSphere.h */, + E494322F169E08D200BCB891 /* KRAmbientZone.cpp */, + E4943230169E08D200BCB891 /* KRAmbientZone.h */, + E450273716E0491D00FDEC5C /* KRReverbZone.cpp */, + E450273816E0491D00FDEC5C /* KRReverbZone.h */, ); name = Audio; sourceTree = ""; @@ -1197,11 +1205,12 @@ E4F027C916979CCD00D4427D /* KRAudioManager.h in Headers */, E4F027D016979CE200D4427D /* KRAudioSample.h in Headers */, E4F027E01697BFFF00D4427D /* KRAudioBuffer.h in Headers */, - E4943233169E08D200BCB891 /* KRAmbientSphere.h in Headers */, + E4943233169E08D200BCB891 /* KRAmbientZone.h in Headers */, E499BF1B16AE747C007FCDBE /* KRVector2.h in Headers */, E499BF1E16AE751E007FCDBE /* KRSceneManager.h in Headers */, E499BF2016AE755B007FCDBE /* KRPointLight.h in Headers */, E499BF2116AE75A7007FCDBE /* KREngine-common.h in Headers */, + E450273B16E0491D00FDEC5C /* KRReverbZone.h in Headers */, E4FE6AA816B21D660058B8CE /* forsyth.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; @@ -1268,11 +1277,12 @@ E4F027CA16979CCD00D4427D /* KRAudioManager.h in Headers */, E4F027D116979CE200D4427D /* KRAudioSample.h in Headers */, E4F027E11697BFFF00D4427D /* KRAudioBuffer.h in Headers */, - E4943234169E08D200BCB891 /* KRAmbientSphere.h in Headers */, + E4943234169E08D200BCB891 /* KRAmbientZone.h in Headers */, E414F9AF1694DA37000B3D58 /* KRUnknown.h in Headers */, E499BF2216AE760F007FCDBE /* krengine_osx.h in Headers */, E4FE6AA916B21D660058B8CE /* forsyth.h in Headers */, E4C454B3167BC04C003586CD /* KRMeshSphere.h in Headers */, + E450273C16E0491D00FDEC5C /* KRReverbZone.h in Headers */, E44F38251683B23000399B5D /* KRRenderSettings.h in Headers */, E499BF1D16AE74FF007FCDBE /* KRTextureAnimated.h in Headers */, E499BF1F16AE753E007FCDBE /* KRCollider.h in Headers */, @@ -1535,8 +1545,9 @@ E4F027C716979CCD00D4427D /* KRAudioManager.cpp in Sources */, E4F027CE16979CE200D4427D /* KRAudioSample.cpp in Sources */, E4F027DE1697BFFF00D4427D /* KRAudioBuffer.cpp in Sources */, - E4943231169E08D200BCB891 /* KRAmbientSphere.cpp in Sources */, + E4943231169E08D200BCB891 /* KRAmbientZone.cpp in Sources */, E4FE6AAB16B21D7E0058B8CE /* forsyth.cpp in Sources */, + E450273916E0491D00FDEC5C /* KRReverbZone.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1606,7 +1617,8 @@ E4F027C816979CCD00D4427D /* KRAudioManager.cpp in Sources */, E4F027CF16979CE200D4427D /* KRAudioSample.cpp in Sources */, E4F027DF1697BFFF00D4427D /* KRAudioBuffer.cpp in Sources */, - E4943232169E08D200BCB891 /* KRAmbientSphere.cpp in Sources */, + E4943232169E08D200BCB891 /* KRAmbientZone.cpp in Sources */, + E450273A16E0491D00FDEC5C /* KRReverbZone.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/KREngine/kraken/KRAmbientZone.cpp b/KREngine/kraken/KRAmbientZone.cpp new file mode 100644 index 0000000..4909cc2 --- /dev/null +++ b/KREngine/kraken/KRAmbientZone.cpp @@ -0,0 +1,166 @@ +// +// KRAmbientZone.cpp +// KREngine +// +// Created by Kearwood Gilbert on 2012-12-06. +// Copyright (c) 2012 Kearwood Software. All rights reserved. +// + +#include "KRAmbientZone.h" +#include "KRContext.h" + +KRAmbientZone::KRAmbientZone(KRScene &scene, std::string name) : KRNode(scene, name) +{ + m_ambient = ""; + m_ambient_gain = 1.0f; + + m_gradient_distance = 0.25f; + +} + +KRAmbientZone::~KRAmbientZone() +{ +} + +std::string KRAmbientZone::getElementName() { + return "ambient_zone"; +} + +tinyxml2::XMLElement *KRAmbientZone::saveXML( tinyxml2::XMLNode *parent) +{ + tinyxml2::XMLElement *e = KRNode::saveXML(parent); + e->SetAttribute("zone", m_zone.c_str()); + e->SetAttribute("sample", m_ambient.c_str()); + e->SetAttribute("gain", m_ambient_gain); + e->SetAttribute("gradient", m_gradient_distance); + return e; +} + +void KRAmbientZone::loadXML(tinyxml2::XMLElement *e) +{ + KRNode::loadXML(e); + + m_zone = e->Attribute("zone"); + + m_gradient_distance = 0.25f; + if(e->QueryFloatAttribute("gradient", &m_gradient_distance) != tinyxml2::XML_SUCCESS) { + m_gradient_distance = 0.25f; + } + + m_ambient = e->Attribute("ambient"); + + m_ambient_gain = 1.0f; + if(e->QueryFloatAttribute("ambient_gain", &m_ambient_gain) != tinyxml2::XML_SUCCESS) { + m_ambient_gain = 1.0f; + } +} + +std::string KRAmbientZone::getAmbient() +{ + return m_ambient; +} + +void KRAmbientZone::setAmbient(const std::string &ambient) +{ + m_ambient = ambient; +} + +float KRAmbientZone::getAmbientGain() +{ + return m_ambient_gain; +} + +void KRAmbientZone::setAmbientGain(float ambient_gain) +{ + m_ambient_gain = ambient_gain; +} + +std::string KRAmbientZone::getZone() +{ + return m_zone; +} + +void KRAmbientZone::setZone(const std::string &zone) +{ + m_zone = zone; +} + +void KRAmbientZone::render(KRCamera *pCamera, std::vector &lights, const KRViewport &viewport, KRNode::RenderPass renderPass) +{ + + KRNode::render(pCamera, lights, viewport, renderPass); + + bool bVisualize = false; + + if(renderPass == KRNode::RENDER_PASS_FORWARD_TRANSPARENT && bVisualize) { + KRMat4 sphereModelMatrix = getModelMatrix(); + + KRShader *pShader = getContext().getShaderManager()->getShader("visualize_overlay", pCamera, lights, 0, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, renderPass); + + if(getContext().getShaderManager()->selectShader(*pCamera, pShader, viewport, sphereModelMatrix, lights, 0, renderPass)) { + + // Enable additive blending + GLDEBUG(glEnable(GL_BLEND)); + GLDEBUG(glBlendFunc(GL_ONE, GL_ONE)); + + + // Disable z-buffer write + GLDEBUG(glDepthMask(GL_FALSE)); + + // Enable z-buffer test + GLDEBUG(glEnable(GL_DEPTH_TEST)); + GLDEBUG(glDepthFunc(GL_LEQUAL)); + GLDEBUG(glDepthRangef(0.0, 1.0)); + std::vector sphereModels = getContext().getModelManager()->getModel("__sphere"); + if(sphereModels.size()) { + for(int i=0; i < sphereModels[0]->getSubmeshCount(); i++) { + sphereModels[0]->renderSubmesh(i); + } + } + + // Enable alpha blending + GLDEBUG(glEnable(GL_BLEND)); + GLDEBUG(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); + } + } +} + + +float KRAmbientZone::getGradientDistance() +{ + return m_gradient_distance; +} + +void KRAmbientZone::setGradientDistance(float gradient_distance) +{ + m_gradient_distance = gradient_distance; +} + +KRAABB KRAmbientZone::getBounds() { + // Ambient zones always have a -1, -1, -1 to 1, 1, 1 bounding box + return KRAABB(-KRVector3::One(), KRVector3::One(), getModelMatrix()); +} + +float KRAmbientZone::getContainment(const KRVector3 &pos) +{ + KRAABB bounds = getBounds(); + if(bounds.contains(pos)) { + KRVector3 size = bounds.size(); + KRVector3 diff = pos - bounds.center(); + diff = diff * 2.0f; + diff = KRVector3(diff.x / size.x, diff.y / size.y, diff.z / size.z); + float d = diff.magnitude(); + + if(m_gradient_distance <= 0.0f) { + // Avoid division by zero + d = d > 1.0f ? 0.0f : 1.0f; + } else { + d = (1.0f - d) / m_gradient_distance; + d = KRCLAMP(d, 0.0f, 1.0f); + } + return d; + + } else { + return 0.0f; + } +} \ No newline at end of file diff --git a/KREngine/kraken/KRAmbientSphere.h b/KREngine/kraken/KRAmbientZone.h similarity index 75% rename from KREngine/kraken/KRAmbientSphere.h rename to KREngine/kraken/KRAmbientZone.h index 1133cb2..528dd5c 100644 --- a/KREngine/kraken/KRAmbientSphere.h +++ b/KREngine/kraken/KRAmbientZone.h @@ -1,5 +1,5 @@ // -// KRAmbientSphere.h +// KRAmbientZone.h // KREngine // // Created by Kearwood Gilbert on 2012-12-06. @@ -13,10 +13,10 @@ #include "KRNode.h" #include "KRTexture.h" -class KRAmbientSphere : public KRNode { +class KRAmbientZone : public KRNode { public: - KRAmbientSphere(KRScene &scene, std::string name); - virtual ~KRAmbientSphere(); + KRAmbientZone(KRScene &scene, std::string name); + virtual ~KRAmbientZone(); virtual std::string getElementName(); virtual tinyxml2::XMLElement *saveXML( tinyxml2::XMLNode *parent); virtual void loadXML(tinyxml2::XMLElement *e); @@ -29,12 +29,6 @@ public: float getGradientDistance(); void setGradientDistance(float gradient_distance); - std::string getReverb(); - void setReverb(const std::string &reverb); - - float getReverbGain(); - void setReverbGain(float reverb_gain); - std::string getAmbient(); void setAmbient(const std::string &ambient); @@ -43,14 +37,13 @@ public: virtual KRAABB getBounds(); + float getContainment(const KRVector3 &pos); + private: std::string m_zone; float m_gradient_distance; - std::string m_reverb; - float m_reverb_gain; - std::string m_ambient; float m_ambient_gain; }; diff --git a/KREngine/kraken/KRAudioManager.cpp b/KREngine/kraken/KRAudioManager.cpp index 620cdb8..9405fed 100644 --- a/KREngine/kraken/KRAudioManager.cpp +++ b/KREngine/kraken/KRAudioManager.cpp @@ -46,8 +46,11 @@ KRAudioManager::KRAudioManager(KRContext &context) : KRContextObject(context) { m_audio_engine = KRAKEN_AUDIO_SIREN; + m_listener_scene = NULL; + m_global_gain = 0.20f; - m_global_reverb_send_level = 1.00f; + m_global_reverb_send_level = 1.0f; + m_global_ambient_gain = 1.0f; // OpenAL @@ -92,6 +95,16 @@ void KRAudioManager::initAudio() } } +KRScene *KRAudioManager::getListenerScene() +{ + return m_listener_scene; +} + +void KRAudioManager::setListenerScene(KRScene *scene) +{ + m_listener_scene = scene; +} + void KRAudioManager::renderAudio(UInt32 inNumberFrames, AudioBufferList *ioData) { AudioUnitSampleType *outA = (AudioUnitSampleType *)ioData->mBuffers[0].mData; @@ -147,8 +160,9 @@ float *KRAudioManager::getBlockAddress(int block_offset) return m_output_accumulation + (m_output_accumulation_block_start + block_offset * KRENGINE_AUDIO_BLOCK_LENGTH * KRENGINE_MAX_OUTPUT_CHANNELS) % (KRENGINE_REVERB_MAX_SAMPLES * KRENGINE_MAX_OUTPUT_CHANNELS); } -void KRAudioManager::renderReverbImpulseResponse(KRAudioSample *impulse_response, int impulse_response_offset, int frame_count_log2) +void KRAudioManager::renderReverbImpulseResponse(int impulse_response_offset, int frame_count_log2) { + int frame_count = 1 << frame_count_log2; int fft_size = frame_count * 2; int fft_size_log2 = frame_count_log2 + 1; @@ -183,8 +197,24 @@ void KRAudioManager::renderReverbImpulseResponse(KRAudioSample *impulse_response int impulse_response_channels = 2; for(int channel=0; channel < impulse_response_channels; channel++) { - - impulse_response->sample(impulse_response_offset, frame_count, channel, impulse_block_data_complex.realp, 1.0f); + bool first_sample = true; + for(std::map::iterator zone_itr=m_reverb_zone_weights.begin(); zone_itr != m_reverb_zone_weights.end(); zone_itr++) { + siren_reverb_zone_weight_info zi = (*zone_itr).second; + if(zi.reverb_sample) { + if(impulse_response_offset < zi.reverb_sample->getFrameCount()) { // Optimization - when mixing multiple impulse responses (i.e. fading between reverb zones), do not process blocks past the end of a shorter impulse response sample when they differ in length + if(first_sample) { + // If this is the first or only sample, write directly to the first half of the FFT input buffer + first_sample = false; + zi.reverb_sample->sample(impulse_response_offset, frame_count, channel, impulse_block_data_complex.realp, zi.weight, false); + } else { + // Subsequent samples write to the second half of the FFT input buffer, which is then added to the first half (the second half will be zero'ed out anyways and works as a convenient temporary buffer) + zi.reverb_sample->sample(impulse_response_offset, frame_count, channel, impulse_block_data_complex.realp + frame_count, zi.weight, false); + vDSP_vadd(impulse_block_data_complex.realp, 1, impulse_block_data_complex.realp + frame_count, 1, impulse_block_data_complex.realp, 1, frame_count); + } + } + + } + } memset(impulse_block_data_complex.realp + frame_count, 0, frame_count * sizeof(float)); memset(impulse_block_data_complex.imagp, 0, fft_size * sizeof(float)); @@ -217,18 +247,39 @@ void KRAudioManager::renderReverb() for(std::set::iterator itr=active_sources.begin(); itr != active_sources.end(); itr++) { KRAudioSource *source = *itr; - float reverb_send_level = m_global_reverb_send_level * m_global_gain * source->getReverb(); - if(reverb_send_level > 0.0f) { - source->sample(KRENGINE_AUDIO_BLOCK_LENGTH, 0, reverb_data, reverb_send_level); - vDSP_vadd(reverb_accum, 1, reverb_data, 1, reverb_accum, 1, KRENGINE_AUDIO_BLOCK_LENGTH); + if(&source->getScene() == m_listener_scene) { + float containment_factor = 0.0f; + + for(std::map::iterator zone_itr=m_reverb_zone_weights.begin(); zone_itr != m_reverb_zone_weights.end(); zone_itr++) { + siren_reverb_zone_weight_info zi = (*zone_itr).second; + float gain = zi.weight * zi.reverb_zone->getReverbGain() * zi.reverb_zone->getContainment(source->getWorldTranslation()); + if(gain > containment_factor) containment_factor = gain; + } + + + float reverb_send_level = m_global_reverb_send_level * m_global_gain * source->getReverb() * containment_factor; + if(reverb_send_level > 0.0f) { + source->sample(KRENGINE_AUDIO_BLOCK_LENGTH, 0, reverb_data, reverb_send_level); + vDSP_vadd(reverb_accum, 1, reverb_data, 1, reverb_accum, 1, KRENGINE_AUDIO_BLOCK_LENGTH); + } } } // Apply impulse response reverb // KRAudioSample *impulse_response = getContext().getAudioManager()->get("hrtf_kemar_H10e040a"); - KRAudioSample *impulse_response_sample = getContext().getAudioManager()->get("test_reverb"); - if(impulse_response_sample) { - int impulse_response_blocks = impulse_response_sample->getFrameCount() / KRENGINE_AUDIO_BLOCK_LENGTH + 1; + + int impulse_response_blocks = 0; + for(std::map::iterator zone_itr=m_reverb_zone_weights.begin(); zone_itr != m_reverb_zone_weights.end(); zone_itr++) { + siren_reverb_zone_weight_info zi = (*zone_itr).second; + if(zi.reverb_sample) { + int zone_sample_blocks = zi.reverb_sample->getFrameCount() / KRENGINE_AUDIO_BLOCK_LENGTH + 1; + impulse_response_blocks = KRMAX(impulse_response_blocks, zone_sample_blocks); + } + } + +// KRAudioSample *impulse_response_sample = getContext().getAudioManager()->get("test_reverb"); + if(impulse_response_blocks) { +// int impulse_response_blocks = impulse_response_sample->getFrameCount() / KRENGINE_AUDIO_BLOCK_LENGTH + 1; int period_log2 = 0; int impulse_response_block=0; int period_count = 0; @@ -237,7 +288,7 @@ void KRAudioManager::renderReverb() int period = 1 << period_log2; if((m_reverb_sequence + period - period_count) % period == 0) { - renderReverbImpulseResponse(impulse_response_sample, impulse_response_block * KRENGINE_AUDIO_BLOCK_LENGTH, KRENGINE_AUDIO_BLOCK_LOG2N + period_log2); + renderReverbImpulseResponse(impulse_response_block * KRENGINE_AUDIO_BLOCK_LENGTH, KRENGINE_AUDIO_BLOCK_LOG2N + period_log2); } impulse_response_block += period; @@ -260,6 +311,8 @@ void KRAudioManager::renderReverb() void KRAudioManager::renderBlock() { + m_mutex.lock(); + bool headphone_mode = true; // ----====---- Advance to next block in accumulation buffer ----====---- @@ -281,8 +334,13 @@ void KRAudioManager::renderBlock() // ----====---- Render Indirect / Reverb channel ----====---- renderReverb(); + // ----====---- Render Ambient Sound ----====---- + renderAmbient(); + // ----====---- Advance audio sources ----====---- m_audio_frame += KRENGINE_AUDIO_BLOCK_LENGTH; + + m_mutex.unlock(); } // audio render procedure, don't allocate memory, don't take any locks, don't waste time @@ -700,7 +758,7 @@ void KRAudioManager::initHRTF() DSPSplitComplex spectral; spectral.realp = m_hrtf_data + sample_index * 1024 + channel * 512; spectral.imagp = m_hrtf_data + sample_index * 1024 + channel * 512 + 256; - sample->sample(0, 128, channel, spectral.realp, 1.0f); + sample->sample(0, 128, channel, spectral.realp, 1.0f, false); memset(spectral.realp + 128, 0, sizeof(float) * 128); memset(spectral.imagp, 0, sizeof(float) * 256); vDSP_fft_zip(m_fft_setup, &spectral, 1, 8, kFFTDirection_Forward); @@ -1297,6 +1355,110 @@ void KRAudioManager::setGlobalReverbSendLevel(float send_level) m_global_reverb_send_level = send_level; } +float KRAudioManager::getGlobalGain() +{ + return m_global_gain; +} + +void KRAudioManager::setGlobalGain(float gain) +{ + m_global_gain = gain; +} + +float KRAudioManager::getGlobalAmbientGain() +{ + return m_global_ambient_gain; +} + +void KRAudioManager::setGlobalAmbientGain(float gain) +{ + m_global_ambient_gain = gain; +} + +void KRAudioManager::startFrame(float deltaTime) +{ + m_mutex.lock(); + + m_ambient_zone_weights.clear(); + m_ambient_zone_total_weight = 0.0f; // For normalizing zone weights + if(m_listener_scene) { + std::set ambient_zones = m_listener_scene->getAmbientZones(); + + for(std::set::iterator itr=ambient_zones.begin(); itr != ambient_zones.end(); itr++) { + KRAmbientZone *sphere = *itr; + siren_ambient_zone_weight_info zi; + + zi.weight = sphere->getContainment(m_listener_position); + if(zi.weight > 0.0f) { + if(m_ambient_zone_weights.find(sphere->getZone()) == m_ambient_zone_weights.end()) { + zi.ambient_zone = sphere; + zi.ambient_sample = get(sphere->getAmbient()); + m_ambient_zone_weights[sphere->getZone()] = zi; + m_ambient_zone_total_weight += zi.weight; + } else { + float prev_weight = m_ambient_zone_weights[sphere->getZone()].weight; + if(zi.weight > prev_weight) { + m_ambient_zone_total_weight -= prev_weight; + m_ambient_zone_weights[sphere->getZone()].weight = zi.weight; + m_ambient_zone_total_weight += zi.weight; + } + } + } + } + } + + + m_reverb_zone_weights.clear(); + m_reverb_zone_total_weight = 0.0f; // For normalizing zone weights + if(m_listener_scene) { + std::set reverb_zones = m_listener_scene->getReverbZones(); + + for(std::set::iterator itr=reverb_zones.begin(); itr != reverb_zones.end(); itr++) { + KRReverbZone *sphere = *itr; + siren_reverb_zone_weight_info zi; + + zi.weight = sphere->getContainment(m_listener_position); + if(zi.weight > 0.0f) { + if(m_reverb_zone_weights.find(sphere->getZone()) == m_reverb_zone_weights.end()) { + zi.reverb_zone = sphere; + zi.reverb_sample = get(sphere->getReverb()); + m_reverb_zone_weights[sphere->getZone()] = zi; + m_reverb_zone_total_weight += zi.weight; + } else { + float prev_weight = m_reverb_zone_weights[sphere->getZone()].weight; + if(zi.weight > prev_weight) { + m_reverb_zone_total_weight -= prev_weight; + m_reverb_zone_weights[sphere->getZone()].weight = zi.weight; + m_reverb_zone_total_weight += zi.weight; + } + } + } + } + } + m_mutex.unlock(); +} + +void KRAudioManager::renderAmbient() +{ + if(m_listener_scene) { + + int output_offset = (m_output_accumulation_block_start) % (KRENGINE_REVERB_MAX_SAMPLES * KRENGINE_MAX_OUTPUT_CHANNELS); + float *buffer = m_workspace[0].realp; + + for(std::map::iterator zone_itr=m_ambient_zone_weights.begin(); zone_itr != m_ambient_zone_weights.end(); zone_itr++) { + siren_ambient_zone_weight_info zi = (*zone_itr).second; + float gain = (*zone_itr).second.weight * zi.ambient_zone->getAmbientGain() * m_global_ambient_gain * m_global_gain; + + KRAudioSample *source_sample = zi.ambient_sample; + if(source_sample) { + for(int channel=0; channel < KRENGINE_MAX_OUTPUT_CHANNELS; channel++) { + source_sample->sample(getContext().getAudioManager()->getAudioFrame(), KRENGINE_AUDIO_BLOCK_LENGTH, channel, buffer, gain, true); + vDSP_vadd(m_output_accumulation + output_offset + channel, KRENGINE_MAX_OUTPUT_CHANNELS, buffer, 1, m_output_accumulation + output_offset + channel, KRENGINE_MAX_OUTPUT_CHANNELS, KRENGINE_AUDIO_BLOCK_LENGTH); + } + } + } + } +} void KRAudioManager::renderHRTF() { @@ -1320,67 +1482,74 @@ void KRAudioManager::renderHRTF() KRVector3 diff = source_world_position - m_listener_position; float distance = diff.magnitude(); float gain = source->getGain() * m_global_gain / pow(KRMAX(distance / source->getReferenceDistance(), 1.0f), source->getRolloffFactor()); - KRVector3 source_listener_space = KRVector3( - KRVector3::Dot(listener_right, diff), - KRVector3::Dot(m_listener_up, diff), - KRVector3::Dot(m_listener_forward, diff) - ); + + // apply minimum-cutoff so that we don't waste cycles processing very quiet / distant sound sources + gain = KRMAX(gain - KRENGINE_AUDIO_CUTOFF, 0.0f) / (1.0f - KRENGINE_AUDIO_CUTOFF); - - KRVector3 source_dir = KRVector3::Normalize(source_listener_space); - - - - if(source->getEnableOcclusion() && false) { - KRHitInfo hitinfo; - if(source->getScene().lineCast(m_listener_position, source_world_position, hitinfo, KRAKEN_COLLIDER_AUDIO)) { - gain = 0.0f; - } - } - - KRVector2 source_dir2 = KRVector2::Normalize(KRVector2(source_dir.x, source_dir.z)); - float azimuth = -atan2(source_dir2.x, -source_dir2.y); - float elevation = atan( source_dir.y / sqrt(source_dir.x * source_dir.x + source_dir.z * source_dir.z)); - - float mix[4]; - KRVector2 dir[4]; - - - getHRTFMix(KRVector2(elevation, azimuth), dir[0], dir[1], dir[2], dir[3], mix[0], mix[1], mix[2], mix[3]); - - for(int channel=0; channel 0.0f) { - memset(hrtf_accum->realp, 0, sizeof(float) * fft_size); - memset(hrtf_accum->imagp, 0, sizeof(float) * fft_size); + KRVector3 source_listener_space = KRVector3( + KRVector3::Dot(listener_right, diff), + KRVector3::Dot(m_listener_up, diff), + KRVector3::Dot(m_listener_forward, diff) + ); - for(int i=0; i < 4; i++) { - if(mix[i] > 0.0f) { - DSPSplitComplex hrtf_impulse_sample = getHRTFSpectral(dir[i], channel); - vDSP_vsmul(hrtf_impulse_sample.realp, 1, mix+i, hrtf_impulse->realp, 1, fft_size); - vDSP_vsmul(hrtf_impulse_sample.imagp, 1, mix+i, hrtf_impulse->imagp, 1, fft_size); - vDSP_zvadd(hrtf_impulse, 1, hrtf_accum, 1, hrtf_accum, 1, fft_size); + + KRVector3 source_dir = KRVector3::Normalize(source_listener_space); + + + + if(source->getEnableOcclusion() && false) { + KRHitInfo hitinfo; + if(source->getScene().lineCast(m_listener_position, source_world_position, hitinfo, KRAKEN_COLLIDER_AUDIO)) { + gain = 0.0f; } } - source->sample(KRENGINE_AUDIO_BLOCK_LENGTH, 0, hrtf_sample->realp, gain); - memset(hrtf_sample->realp + hrtf_frames, 0, sizeof(float) * hrtf_frames); - memset(hrtf_sample->imagp, 0, sizeof(float) * fft_size); + KRVector2 source_dir2 = KRVector2::Normalize(KRVector2(source_dir.x, source_dir.z)); + float azimuth = -atan2(source_dir2.x, -source_dir2.y); + float elevation = atan( source_dir.y / sqrt(source_dir.x * source_dir.x + source_dir.z * source_dir.z)); + + float mix[4]; + KRVector2 dir[4]; - float scale = 0.5f / fft_size; - vDSP_fft_zip(m_fft_setup, hrtf_sample, 1, fft_size_log2, kFFTDirection_Forward); - vDSP_zvmul(hrtf_sample, 1, hrtf_accum, 1, hrtf_convolved, 1, fft_size, 1); - vDSP_fft_zip(m_fft_setup, hrtf_convolved, 1, fft_size_log2, kFFTDirection_Inverse); - vDSP_vsmul(hrtf_convolved->realp, 1, &scale, hrtf_convolved->realp, 1, fft_size); + getHRTFMix(KRVector2(elevation, azimuth), dir[0], dir[1], dir[2], dir[3], mix[0], mix[1], mix[2], mix[3]); - int output_offset = (m_output_accumulation_block_start) % (KRENGINE_REVERB_MAX_SAMPLES * KRENGINE_MAX_OUTPUT_CHANNELS); - int frames_left = fft_size; - while(frames_left) { - int frames_to_process = (KRENGINE_REVERB_MAX_SAMPLES * KRENGINE_MAX_OUTPUT_CHANNELS - output_offset) / KRENGINE_MAX_OUTPUT_CHANNELS; - if(frames_to_process > frames_left) frames_to_process = frames_left; - vDSP_vadd(m_output_accumulation + output_offset + channel, KRENGINE_MAX_OUTPUT_CHANNELS, hrtf_convolved->realp + fft_size - frames_left, 1, m_output_accumulation + output_offset + channel, KRENGINE_MAX_OUTPUT_CHANNELS, frames_to_process); - frames_left -= frames_to_process; - output_offset = (output_offset + frames_to_process * KRENGINE_MAX_OUTPUT_CHANNELS) % (KRENGINE_REVERB_MAX_SAMPLES * KRENGINE_MAX_OUTPUT_CHANNELS); + for(int channel=0; channelrealp, 0, sizeof(float) * fft_size); + memset(hrtf_accum->imagp, 0, sizeof(float) * fft_size); + + for(int i=0; i < 4; i++) { + if(mix[i] > 0.0f) { + DSPSplitComplex hrtf_impulse_sample = getHRTFSpectral(dir[i], channel); + vDSP_vsmul(hrtf_impulse_sample.realp, 1, mix+i, hrtf_impulse->realp, 1, fft_size); + vDSP_vsmul(hrtf_impulse_sample.imagp, 1, mix+i, hrtf_impulse->imagp, 1, fft_size); + vDSP_zvadd(hrtf_impulse, 1, hrtf_accum, 1, hrtf_accum, 1, fft_size); + } + } + + source->sample(KRENGINE_AUDIO_BLOCK_LENGTH, 0, hrtf_sample->realp, gain); + memset(hrtf_sample->realp + hrtf_frames, 0, sizeof(float) * hrtf_frames); + memset(hrtf_sample->imagp, 0, sizeof(float) * fft_size); + + + float scale = 0.5f / fft_size; + vDSP_fft_zip(m_fft_setup, hrtf_sample, 1, fft_size_log2, kFFTDirection_Forward); + vDSP_zvmul(hrtf_sample, 1, hrtf_accum, 1, hrtf_convolved, 1, fft_size, 1); + vDSP_fft_zip(m_fft_setup, hrtf_convolved, 1, fft_size_log2, kFFTDirection_Inverse); + vDSP_vsmul(hrtf_convolved->realp, 1, &scale, hrtf_convolved->realp, 1, fft_size); + + int output_offset = (m_output_accumulation_block_start) % (KRENGINE_REVERB_MAX_SAMPLES * KRENGINE_MAX_OUTPUT_CHANNELS); + int frames_left = fft_size; + while(frames_left) { + int frames_to_process = (KRENGINE_REVERB_MAX_SAMPLES * KRENGINE_MAX_OUTPUT_CHANNELS - output_offset) / KRENGINE_MAX_OUTPUT_CHANNELS; + if(frames_to_process > frames_left) frames_to_process = frames_left; + vDSP_vadd(m_output_accumulation + output_offset + channel, KRENGINE_MAX_OUTPUT_CHANNELS, hrtf_convolved->realp + fft_size - frames_left, 1, m_output_accumulation + output_offset + channel, KRENGINE_MAX_OUTPUT_CHANNELS, frames_to_process); + frames_left -= frames_to_process; + output_offset = (output_offset + frames_to_process * KRENGINE_MAX_OUTPUT_CHANNELS) % (KRENGINE_REVERB_MAX_SAMPLES * KRENGINE_MAX_OUTPUT_CHANNELS); + } } } } diff --git a/KREngine/kraken/KRAudioManager.h b/KREngine/kraken/KRAudioManager.h index 7001128..67cfa2a 100644 --- a/KREngine/kraken/KRAudioManager.h +++ b/KREngine/kraken/KRAudioManager.h @@ -50,10 +50,28 @@ const int KRENGINE_AUDIO_BLOCK_LOG2N = 7; // 2 ^ KRENGINE_AUDIO_BLOCK_LOG2N = KR const int KRENGINE_REVERB_MAX_FFT_LOG2 = 15; const int KRENGINE_REVERB_WORKSPACE_SIZE = 1 << KRENGINE_REVERB_MAX_FFT_LOG2; +const float KRENGINE_AUDIO_CUTOFF = 0.02f; // Cutoff gain level, to cull out processing of very quiet sounds + const int KRENGINE_REVERB_MAX_SAMPLES = 435200; // At least 10s reverb impulse response length, divisible by KRENGINE_AUDIO_BLOCK_LENGTH const int KRENGINE_MAX_REVERB_IMPULSE_MIX = 16; // Maximum number of impulse response filters that can be mixed simultaneously const int KRENGINE_MAX_OUTPUT_CHANNELS = 2; + +class KRAmbientZone; +class KRReverbZone; + +typedef struct { + float weight; + KRAmbientZone *ambient_zone; + KRAudioSample *ambient_sample; +} siren_ambient_zone_weight_info; + +typedef struct { + float weight; + KRReverbZone *reverb_zone; + KRAudioSample *reverb_sample; +} siren_reverb_zone_weight_info; + class KRAudioManager : public KRContextObject { public: KRAudioManager(KRContext &context); @@ -64,12 +82,26 @@ public: KRAudioSample *load(const std::string &name, const std::string &extension, KRDataBlock *data); KRAudioSample *get(const std::string &name); + // Listener position and orientation + KRScene *getListenerScene(); + void setListenerScene(KRScene *scene); void setListenerOrientation(const KRVector3 &position, const KRVector3 &forward, const KRVector3 &up); void setListenerOrientationFromModelMatrix(const KRMat4 &modelMatrix); KRVector3 &getListenerForward(); KRVector3 &getListenerPosition(); KRVector3 &getListenerUp(); + + + // Global audio gain / attenuation + float getGlobalGain(); + void setGlobalGain(float gain); + float getGlobalReverbSendLevel(); + void setGlobalReverbSendLevel(float send_level); + float getGlobalAmbientGain(); + void setGlobalAmbientGain(float gain); + + void makeCurrentContext(); KRDataBlock *getBufferData(int size); @@ -90,12 +122,14 @@ public: KRAudioBuffer *getBuffer(KRAudioSample &audio_sample, int buffer_index); - float getGlobalReverbSendLevel(); - void setGlobalReverbSendLevel(float send_level); - + + void startFrame(float deltaTime); private: + KRScene *m_listener_scene; // For now, only one scene is allowed to have active audio at once + float m_global_reverb_send_level; + float m_global_ambient_gain; float m_global_gain; KRVector3 m_listener_position; @@ -155,9 +189,10 @@ private: float *getBlockAddress(int block_offset); void renderBlock(); void renderReverb(); + void renderAmbient(); void renderHRTF(); void renderITD(); - void renderReverbImpulseResponse(KRAudioSample *impulse_response, int impulse_response_offset, int frame_count_log2); + void renderReverbImpulseResponse(int impulse_response_offset, int frame_count_log2); std::vector m_hrtf_sample_locations; float *m_hrtf_data; @@ -166,6 +201,15 @@ private: void getHRTFMix(const KRVector2 &dir, KRVector2 &hrtf1, KRVector2 &hrtf2, KRVector2 &hrtf3, KRVector2 &hrtf4, float &mix1, float &mix2, float &mix3, float &mix4); KRAudioSample *getHRTFSample(const KRVector2 &hrtf_dir); DSPSplitComplex getHRTFSpectral(const KRVector2 &hrtf_dir, const int channel); + + + std::map m_ambient_zone_weights; + float m_ambient_zone_total_weight = 0.0f; // For normalizing zone weights + + std::map m_reverb_zone_weights; + float m_reverb_zone_total_weight = 0.0f; // For normalizing zone weights + + boost::signals2::mutex m_mutex; }; #endif /* defined(KRAUDIO_MANAGER_H) */ diff --git a/KREngine/kraken/KRAudioSample.cpp b/KREngine/kraken/KRAudioSample.cpp index c171f5a..793729f 100644 --- a/KREngine/kraken/KRAudioSample.cpp +++ b/KREngine/kraken/KRAudioSample.cpp @@ -88,6 +88,8 @@ int KRAudioSample::getFrameCount() float KRAudioSample::sample(int frame_offset, int frame_rate, int channel) { + int c = KRMIN(channel, m_channelsPerFrame - 1); + if(frame_offset < 0) { return 0.0f; // Past the beginning of the recording } else { @@ -113,68 +115,77 @@ float KRAudioSample::sample(int frame_offset, int frame_rate, int channel) return 0.0f; // past the end of the recording } else { short *frame = buffer->getFrameData() + (buffer_offset * m_channelsPerFrame); - return frame[channel] / 32767.0f; + return frame[c] / 32767.0f; } } } } -void KRAudioSample::sample(int frame_offset, int frame_count, int channel, float *buffer, float amplitude) +void KRAudioSample::sample(__int64_t frame_offset, int frame_count, int channel, float *buffer, float amplitude, bool loop) { - if(frame_offset + frame_count <= 0) { - // Range is entirely before the sample - memset(buffer, 0, frame_count * sizeof(float)); - } else if(frame_offset >= m_totalFrames) { - // Range is entirely after the sample - memset(buffer, 0, frame_count * sizeof(float)); - } else { - int start_frame = frame_offset < 0 ? 0 : frame_offset; - int prefix_frames = frame_offset < 0 ? -frame_offset : 0; - if(prefix_frames > 0) { - // Prefix with padding of 0's - memset(buffer, 0, prefix_frames * sizeof(float)); - } - - int frames_per_buffer = KRENGINE_AUDIO_MAX_BUFFER_SIZE / m_bytesPerFrame; - - int buffer_index = start_frame / frames_per_buffer; - int buffer_offset = start_frame % frames_per_buffer; - int processed_frames = prefix_frames; - while(processed_frames < frame_count) { - int frames_left = frame_count - processed_frames; - if(buffer_index >= m_bufferCount) { - // Suffix with padding of 0's - memset(buffer + processed_frames, 0, frames_left * sizeof(float)); - processed_frames += frames_left; + if(loop) { + int buffer_offset = 0; + int frames_left = frame_count; + int sample_length = getFrameCount(); + while(frames_left) { + int next_frame = (int)(((__int64_t)frame_offset + (__int64_t)buffer_offset) % sample_length); + if(next_frame + frames_left >= sample_length) { + int frames_processed = sample_length - next_frame; + sample(next_frame, frames_processed, channel, buffer + buffer_offset, amplitude, false); + frames_left -= frames_processed; + buffer_offset += frames_processed; } else { - KRAudioBuffer *source_buffer = getContext().getAudioManager()->getBuffer(*this, buffer_index); - int frames_to_copy = source_buffer->getFrameCount() - buffer_offset; - if(frames_to_copy > frames_left) frames_to_copy = frames_left; - if(frames_to_copy > 0) { - /* - - void vDSP_vflt16 ( - short *A, - vDSP_Stride __vDSP_I, - float *__vDSP_C, - vDSP_Stride __vDSP_K, - vDSP_Length __vDSP_N - ); - - */ - signed short *source_data = source_buffer->getFrameData() + buffer_offset * m_channelsPerFrame + channel; - vDSP_vflt16(source_data, m_channelsPerFrame, buffer + processed_frames, 1, frames_to_copy); - //memcpy(buffer + processed_frames, source_buffer->getFrameData() + buffer_offset, frames_to_copy * m_channelsPerFrame * sizeof(float)); - processed_frames += frames_to_copy; - } - buffer_index++; - buffer_offset = 0; + sample(next_frame, frames_left, channel, buffer + buffer_offset, amplitude, false); + frames_left = 0; } } + } else { + int c = KRMIN(channel, m_channelsPerFrame - 1); + + if(frame_offset + frame_count <= 0) { + // Range is entirely before the sample + memset(buffer, 0, frame_count * sizeof(float)); + } else if(frame_offset >= m_totalFrames) { + // Range is entirely after the sample + memset(buffer, 0, frame_count * sizeof(float)); + } else { + int start_frame = frame_offset < 0 ? 0 : frame_offset; + int prefix_frames = frame_offset < 0 ? -frame_offset : 0; + if(prefix_frames > 0) { + // Prefix with padding of 0's + memset(buffer, 0, prefix_frames * sizeof(float)); + } + + int frames_per_buffer = KRENGINE_AUDIO_MAX_BUFFER_SIZE / m_bytesPerFrame; + + int buffer_index = start_frame / frames_per_buffer; + int buffer_offset = start_frame % frames_per_buffer; + int processed_frames = prefix_frames; + while(processed_frames < frame_count) { + int frames_left = frame_count - processed_frames; + if(buffer_index >= m_bufferCount) { + // Suffix with padding of 0's + memset(buffer + processed_frames, 0, frames_left * sizeof(float)); + processed_frames += frames_left; + } else { + KRAudioBuffer *source_buffer = getContext().getAudioManager()->getBuffer(*this, buffer_index); + int frames_to_copy = source_buffer->getFrameCount() - buffer_offset; + if(frames_to_copy > frames_left) frames_to_copy = frames_left; + if(frames_to_copy > 0) { + signed short *source_data = source_buffer->getFrameData() + buffer_offset * m_channelsPerFrame + c; + vDSP_vflt16(source_data, m_channelsPerFrame, buffer + processed_frames, 1, frames_to_copy); + //memcpy(buffer + processed_frames, source_buffer->getFrameData() + buffer_offset, frames_to_copy * m_channelsPerFrame * sizeof(float)); + processed_frames += frames_to_copy; + } + buffer_index++; + buffer_offset = 0; + } + } + } + + float scale = amplitude / 32768.0f; + vDSP_vsmul(buffer, 1, &scale, buffer, 1, frame_count); } - - float scale = amplitude / 32768.0f; - vDSP_vsmul(buffer, 1, &scale, buffer, 1, frame_count); } OSStatus KRAudioSample::ReadProc( // AudioFile_ReadProc diff --git a/KREngine/kraken/KRAudioSample.h b/KREngine/kraken/KRAudioSample.h index 9183af6..ab7093b 100644 --- a/KREngine/kraken/KRAudioSample.h +++ b/KREngine/kraken/KRAudioSample.h @@ -58,7 +58,7 @@ public: int getChannelCount(); int getFrameCount(); float sample(int frame_offset, int frame_rate, int channel); - void sample(int frame_offset, int frame_count, int channel, float *buffer, float amplitude); + void sample(__int64_t frame_offset, int frame_count, int channel, float *buffer, float amplitude, bool loop); private: diff --git a/KREngine/kraken/KRAudioSource.cpp b/KREngine/kraken/KRAudioSource.cpp index 3504f00..d6ec91e 100644 --- a/KREngine/kraken/KRAudioSource.cpp +++ b/KREngine/kraken/KRAudioSource.cpp @@ -508,28 +508,10 @@ void KRAudioSource::sample(int frame_count, int channel, float *buffer, float ga { KRAudioSample *source_sample = getAudioSample(); if(source_sample && m_playing) { - if(m_looping) { - int buffer_offset = 0; - int frames_left = frame_count; - int sample_length = source_sample->getFrameCount(); - while(frames_left) { - int next_frame = (int)((getContext().getAudioManager()->getAudioFrame() - getStartAudioFrame() + buffer_offset) % sample_length); - if(next_frame + frames_left >= sample_length) { - int frames_processed = sample_length - next_frame; - source_sample->sample(next_frame, frames_processed, channel, buffer + buffer_offset, gain); - frames_left -= frames_processed; - buffer_offset += frames_processed; - } else { - source_sample->sample(next_frame, frames_left, channel, buffer + buffer_offset, gain); - frames_left = 0; - } - } - } else { - int next_frame = (int)(getContext().getAudioManager()->getAudioFrame() - getStartAudioFrame()); - source_sample->sample(next_frame, frame_count, channel, buffer, gain); - if(next_frame > source_sample->getFrameCount()) { - stop(); - } + __int64_t next_frame = getContext().getAudioManager()->getAudioFrame() - getStartAudioFrame(); + source_sample->sample(next_frame, frame_count, channel, buffer, gain, m_looping); + if(!m_looping && next_frame > source_sample->getFrameCount()) { + stop(); } } else { memset(buffer, 0, sizeof(float) * frame_count); diff --git a/KREngine/kraken/KRContext.cpp b/KREngine/kraken/KRContext.cpp index 233960a..3781537 100644 --- a/KREngine/kraken/KRContext.cpp +++ b/KREngine/kraken/KRContext.cpp @@ -190,6 +190,7 @@ void KRContext::startFrame(float deltaTime) { m_pTextureManager->startFrame(deltaTime); m_pAnimationManager->startFrame(deltaTime); + m_pSoundManager->startFrame(deltaTime); } void KRContext::endFrame(float deltaTime) diff --git a/KREngine/kraken/KREngine-common.h b/KREngine/kraken/KREngine-common.h index 688590e..571e116 100644 --- a/KREngine/kraken/KREngine-common.h +++ b/KREngine/kraken/KREngine-common.h @@ -42,6 +42,7 @@ float const D2R = PI * 2 / 360; #include #include +#include @@ -129,6 +130,7 @@ fprintf(stderr, "Error at line number %d, in file %s. Returned %d for call %s\n" #define KRMIN(x,y) ((x) < (y) ? (x) : (y)) #define KRMAX(x,y) ((x) > (y) ? (x) : (y)) +#define KRCLAMP(x, min, max) (KRMAX(KRMIN(x, max), min)) #define KRALIGN(x) ((x + 3) & ~0x03) #include "KRVector3.h" diff --git a/KREngine/kraken/KRNode.cpp b/KREngine/kraken/KRNode.cpp index 3382831..006f8f3 100644 --- a/KREngine/kraken/KRNode.cpp +++ b/KREngine/kraken/KRNode.cpp @@ -20,8 +20,8 @@ #include "KRQuaternion.h" #include "KRBone.h" #include "KRAudioSource.h" -#include "KRAmbientSphere.h" - +#include "KRAmbientZone.h" +#include "KRReverbZone.h" KRNode::KRNode(KRScene &scene, std::string name) : KRContextObject(scene.getContext()) { @@ -241,8 +241,10 @@ KRNode *KRNode::LoadXML(KRScene &scene, tinyxml2::XMLElement *e) { new_node = new KRBone(scene, szName); } else if(strcmp(szElementName, "audio_source") == 0) { new_node = new KRAudioSource(scene, szName); - } else if(strcmp(szElementName, "ambient_sphere") == 0) { - new_node = new KRAmbientSphere(scene, szName); + } else if(strcmp(szElementName, "ambient_zone") == 0) { + new_node = new KRAmbientZone(scene, szName); + } else if(strcmp(szElementName, "reverb_zone") == 0) { + new_node = new KRReverbZone(scene, szName); } if(new_node) { diff --git a/KREngine/kraken/KRAmbientSphere.cpp b/KREngine/kraken/KRReverbZone.cpp similarity index 59% rename from KREngine/kraken/KRAmbientSphere.cpp rename to KREngine/kraken/KRReverbZone.cpp index 9ba010c..35f3ecb 100644 --- a/KREngine/kraken/KRAmbientSphere.cpp +++ b/KREngine/kraken/KRReverbZone.cpp @@ -1,53 +1,49 @@ // -// KRAmbientSphere.cpp +// KRReverbZone.cpp // KREngine // // Created by Kearwood Gilbert on 2012-12-06. // Copyright (c) 2012 Kearwood Software. All rights reserved. // -#include "KRAmbientSphere.h" +#include "KRReverbZone.h" #include "KRContext.h" -KRAmbientSphere::KRAmbientSphere(KRScene &scene, std::string name) : KRNode(scene, name) +KRReverbZone::KRReverbZone(KRScene &scene, std::string name) : KRNode(scene, name) { - m_ambient = ""; m_reverb = ""; - m_ambient_gain = 1.0f; m_reverb_gain = 1.0f; - m_gradient_distance = 1.0f; + m_gradient_distance = 0.25f; } -KRAmbientSphere::~KRAmbientSphere() +KRReverbZone::~KRReverbZone() { } -std::string KRAmbientSphere::getElementName() { - return "ambient_sphere"; +std::string KRReverbZone::getElementName() { + return "reverb_zone"; } -tinyxml2::XMLElement *KRAmbientSphere::saveXML( tinyxml2::XMLNode *parent) +tinyxml2::XMLElement *KRReverbZone::saveXML( tinyxml2::XMLNode *parent) { tinyxml2::XMLElement *e = KRNode::saveXML(parent); e->SetAttribute("zone", m_zone.c_str()); - e->SetAttribute("ambient", m_ambient.c_str()); - e->SetAttribute("ambient_gain", m_ambient_gain); - e->SetAttribute("reverb", m_reverb.c_str()); - e->SetAttribute("reverb_gain", m_reverb_gain); + e->SetAttribute("sample", m_reverb.c_str()); + e->SetAttribute("gain", m_reverb_gain); e->SetAttribute("gradient", m_gradient_distance); return e; } -void KRAmbientSphere::loadXML(tinyxml2::XMLElement *e) +void KRReverbZone::loadXML(tinyxml2::XMLElement *e) { KRNode::loadXML(e); m_zone = e->Attribute("zone"); - m_gradient_distance = 1.0f; + m_gradient_distance = 0.25f; if(e->QueryFloatAttribute("gradient", &m_gradient_distance) != tinyxml2::XML_SUCCESS) { - m_gradient_distance = 1.0f; + m_gradient_distance = 0.25f; } m_reverb = e->Attribute("reverb"); @@ -56,66 +52,39 @@ void KRAmbientSphere::loadXML(tinyxml2::XMLElement *e) if(e->QueryFloatAttribute("reverb_gain", &m_reverb_gain) != tinyxml2::XML_SUCCESS) { m_reverb_gain = 1.0f; } - - m_ambient = e->Attribute("ambient"); - - m_ambient_gain = 1.0f; - if(e->QueryFloatAttribute("ambient_gain", &m_ambient_gain) != tinyxml2::XML_SUCCESS) { - m_ambient_gain = 1.0f; - } } -std::string KRAmbientSphere::getReverb() +std::string KRReverbZone::getReverb() { return m_reverb; } -void KRAmbientSphere::setReverb(const std::string &reverb) +void KRReverbZone::setReverb(const std::string &reverb) { m_reverb = reverb; } -float KRAmbientSphere::getReverbGain() +float KRReverbZone::getReverbGain() { return m_reverb_gain; } -void KRAmbientSphere::setReverbGain(float reverb_gain) +void KRReverbZone::setReverbGain(float reverb_gain) { m_reverb_gain = reverb_gain; } -std::string KRAmbientSphere::getAmbient() -{ - return m_ambient; -} - -void KRAmbientSphere::setAmbient(const std::string &ambient) -{ - m_ambient = ambient; -} - -float KRAmbientSphere::getAmbientGain() -{ - return m_ambient_gain; -} - -void KRAmbientSphere::setAmbientGain(float ambient_gain) -{ - m_ambient_gain = ambient_gain; -} - -std::string KRAmbientSphere::getZone() +std::string KRReverbZone::getZone() { return m_zone; } -void KRAmbientSphere::setZone(const std::string &zone) +void KRReverbZone::setZone(const std::string &zone) { m_zone = zone; } -void KRAmbientSphere::render(KRCamera *pCamera, std::vector &lights, const KRViewport &viewport, KRNode::RenderPass renderPass) +void KRReverbZone::render(KRCamera *pCamera, std::vector &lights, const KRViewport &viewport, KRNode::RenderPass renderPass) { KRNode::render(pCamera, lights, viewport, renderPass); @@ -156,17 +125,41 @@ void KRAmbientSphere::render(KRCamera *pCamera, std::vector &lights, } -float KRAmbientSphere::getGradientDistance() +float KRReverbZone::getGradientDistance() { return m_gradient_distance; } -void KRAmbientSphere::setGradientDistance(float gradient_distance) +void KRReverbZone::setGradientDistance(float gradient_distance) { m_gradient_distance = gradient_distance; } -KRAABB KRAmbientSphere::getBounds() { +KRAABB KRReverbZone::getBounds() { // Reverb zones always have a -1, -1, -1 to 1, 1, 1 bounding box return KRAABB(-KRVector3::One(), KRVector3::One(), getModelMatrix()); } + +float KRReverbZone::getContainment(const KRVector3 &pos) +{ + KRAABB bounds = getBounds(); + if(bounds.contains(pos)) { + KRVector3 size = bounds.size(); + KRVector3 diff = pos - bounds.center(); + diff = diff * 2.0f; + diff = KRVector3(diff.x / size.x, diff.y / size.y, diff.z / size.z); + float d = diff.magnitude(); + + if(m_gradient_distance <= 0.0f) { + // Avoid division by zero + d = d > 1.0f ? 0.0f : 1.0f; + } else { + d = (1.0f - d) / m_gradient_distance; + d = KRCLAMP(d, 0.0f, 1.0f); + } + return d; + + } else { + return 0.0f; + } +} \ No newline at end of file diff --git a/KREngine/kraken/KRReverbZone.h b/KREngine/kraken/KRReverbZone.h new file mode 100644 index 0000000..a803e4a --- /dev/null +++ b/KREngine/kraken/KRReverbZone.h @@ -0,0 +1,52 @@ +// +// KRReverbZone.h +// KREngine +// +// Created by Kearwood Gilbert on 2012-12-06. +// Copyright (c) 2012 Kearwood Software. All rights reserved. +// + +#ifndef KRREVERB_ZONE_H +#define KRREVERB_ZONE_H + +#include "KRResource.h" +#include "KRNode.h" +#include "KRTexture.h" + +class KRReverbZone : public KRNode { +public: + KRReverbZone(KRScene &scene, std::string name); + virtual ~KRReverbZone(); + virtual std::string getElementName(); + virtual tinyxml2::XMLElement *saveXML( tinyxml2::XMLNode *parent); + virtual void loadXML(tinyxml2::XMLElement *e); + + void render(KRCamera *pCamera, std::vector &lights, const KRViewport &viewport, KRNode::RenderPass renderPass); + + std::string getZone(); + void setZone(const std::string &zone); + + float getGradientDistance(); + void setGradientDistance(float gradient_distance); + + std::string getReverb(); + void setReverb(const std::string &reverb); + + float getReverbGain(); + void setReverbGain(float reverb_gain); + + virtual KRAABB getBounds(); + + float getContainment(const KRVector3 &pos); + +private: + std::string m_zone; + + float m_gradient_distance; + + std::string m_reverb; + float m_reverb_gain; +}; + + +#endif diff --git a/KREngine/kraken/KRScene.cpp b/KREngine/kraken/KRScene.cpp index acd8b51..2316f16 100644 --- a/KREngine/kraken/KRScene.cpp +++ b/KREngine/kraken/KRScene.cpp @@ -72,6 +72,18 @@ void KRScene::renderFrame(float deltaTime, int width, int height) { physicsUpdate(deltaTime); } +std::set &KRScene::getAmbientZones() +{ + // FINDME, TODO - To support large scenes with many reverb / ambient zones, this function should take a KRAABB and cull out any far away zones + return m_ambientZoneNodes; +} + +std::set &KRScene::getReverbZones() +{ + // FINDME, TODO - To support large scenes with many reverb / ambient zones, this function should take a KRAABB and cull out any far away zones + return m_reverbZoneNodes; +} + void KRScene::render(KRCamera *pCamera, std::map &visibleBounds, const KRViewport &viewport, KRNode::RenderPass renderPass, bool new_frame) { updateOctree(); @@ -399,6 +411,14 @@ void KRScene::notify_sceneGraphDelete(KRNode *pNode) { m_nodeTree.remove(pNode); m_physicsNodes.erase(pNode); + KRAmbientZone *AmbientZoneNode = dynamic_cast(pNode); + if(AmbientZoneNode) { + m_ambientZoneNodes.erase(AmbientZoneNode); + } + KRReverbZone *ReverbZoneNode = dynamic_cast(pNode); + if(ReverbZoneNode) { + m_reverbZoneNodes.erase(ReverbZoneNode); + } m_modifiedNodes.erase(pNode); if(!m_newNodes.erase(pNode)) { m_nodeTree.remove(pNode); @@ -418,6 +438,14 @@ void KRScene::updateOctree() if(node->hasPhysics()) { m_physicsNodes.insert(node); } + KRAmbientZone *AmbientZoneNode = dynamic_cast(node); + if(dynamic_cast(node)) { + m_ambientZoneNodes.insert(AmbientZoneNode); + } + KRReverbZone *ReverbZoneNode = dynamic_cast(node); + if(dynamic_cast(node)) { + m_reverbZoneNodes.insert(ReverbZoneNode); + } } for(std::set::iterator itr=modifiedNodes.begin(); itr != modifiedNodes.end(); itr++) { KRNode *node = *itr; diff --git a/KREngine/kraken/KRScene.h b/KREngine/kraken/KRScene.h index fd9638d..6684ff4 100644 --- a/KREngine/kraken/KRScene.h +++ b/KREngine/kraken/KRScene.h @@ -40,6 +40,8 @@ #include "KRCamera.h" #include "KRMeshManager.h" #include "KRNode.h" +#include "KRAmbientZone.h" +#include "KRReverbZone.h" #include "KROctree.h" class KRModel; class KRLight; @@ -79,6 +81,9 @@ public: KRAABB getRootOctreeBounds(); + std::set &getAmbientZones(); + std::set &getReverbZones(); + private: KRNode *m_pRootNode; @@ -90,6 +95,8 @@ private: std::set m_physicsNodes; + std::set m_ambientZoneNodes; + std::set m_reverbZoneNodes; KROctree m_nodeTree; void updateOctree();