JPL Spatial
Sound spatialization and propagation library
Loading...
Searching...
No Matches
ReverbUtilities.h
Go to the documentation of this file.
1//
2// ██╗██████╗ ██╗ ██╗██████╗ ███████╗
3// ██║██╔══██╗ ██║ ██║██╔══██╗██╔════╝ ** JPL Spatial **
4// ██║██████╔╝ ██║ ██║██████╔╝███████╗
5// ██ ██║██╔═══╝ ██║ ██║██╔══██╗╚════██║ https://github.com/Jaytheway/JPLSpatial
6// ╚█████╔╝██║ ███████╗██║██████╔╝███████║
7// ╚════╝ ╚═╝ ╚══════╝╚═╝╚═════╝ ╚══════╝
8//
9// Copyright 2026 Jaroslav Pevno, JPL Spatial is offered under the terms of the ISC license:
10//
11// Permission to use, copy, modify, and/or distribute this software for any purpose with or
12// without fee is hereby granted, provided that the above copyright notice and this permission
13// notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
14// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
15// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
16// CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
17// WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
18// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
20#pragma once
21#include "JPLSpatial/Core.h"
26
27#include <cmath>
28#include <numbers>
29#include <span>
30#include <vector>
31
32namespace JPL
33{
34
35 //======================================================================
39 [[nosiscard]] JPL_INLINE simd EstimateRT60_Sabine(float w, float l, float h, const simd& avgAbsorption);
40
42 [[nosiscard]] JPL_INLINE simd EstimateRT60_Sabine(float w, float l, float h, const simd& avgAbsorption, const simd& airAttenuation_dB);
43
44 // Note: we keep Sabine estimator for material workflows/measures,
45 // because absorption coefficients found online often assume Sabine measure.
46
50 [[nosiscard]] JPL_INLINE simd EstimateRT60_Eyring(float w, float l, float h, const simd& avgAbsorption);
51
53 [[nosiscard]] JPL_INLINE simd EstimateRT60_Eyring(float w, float l, float h, const simd& avgAbsorption, const simd& airAttenuation_dB);
54
56 // Note: air absortion factor requires knowing total surface area and cannot be derived just from mean free path
57 [[nodiscard]] JPL_INLINE simd EstimateRT60FromMFP(float mfpMeters, const simd& avgAbsorption)
58 {
59 static constexpr float eps = 1.0e-4f;
60 const simd absorption = clamp(avgAbsorption, eps, 1.0f - eps);
61 return simd(0.161f * mfpMeters) / (4.0f * -log(simd(1.0f) - absorption));
62 }
63
64} // namespace JPL
65
66//==============================================================================
67//
68// Code beyond this point is implementation detail...
69//
70//==============================================================================
71
72namespace JPL
73{
74
75 //======================================================================
76 namespace Impl
77 {
78 struct Sabine
79 {
80 [[nosidscard]] static JPL_INLINE simd Compute(float surface, const simd& avgAbsorption)
81 {
82 return surface * avgAbsorption;
83 }
84 };
85
86 struct Eyring
87 {
88 [[nosidscard]] static JPL_INLINE simd Compute(float surface, const simd& avgAbsorption)
89 {
90 return -surface * log(simd(1.0f) - avgAbsorption);
91 }
92 };
93
94 [[nosidscard]] JPL_INLINE simd ComputeAirAbsorptionFactor(float volume, const simd& airAttenuation_dB)
95 {
96 // Air attenuation as reciprocal meters (1/m).
97 // I.e. dB converted to Nepers
98 static const float napersCoeff = 1.0f / (10.0f * ::log10(std::numbers::e_v<float>));
99 const simd m = airAttenuation_dB * napersCoeff;
100 return 4.0f * m * volume;
101 }
102
103 template<class SurfaceFactor>
104 [[nodiscard]] JPL_INLINE simd EstimateRT60(float w, float l, float h, const simd& avgAbsorption)
105 {
106 static const simd K(0.161f); // room constant
107 const float surface = 2.0f * (l * w + l * h + w * h);
108 const float volume = w * l * h;
109 return simd(K * volume) / SurfaceFactor::Compute(surface, avgAbsorption);
110 }
111
112 template<class SurfaceFactor>
113 [[nodiscard]] JPL_INLINE simd EstimateRT60(float w, float l, float h, const simd& avgAbsorption, const simd& airAttenuation_dB)
114 {
115 static const simd K(0.161f); // room constant
116 const float surface = 2.0f * (l * w + l * h + w * h);
117 const float volume = w * l * h;
118 return simd(K * volume) /
119 (SurfaceFactor::Compute(surface, avgAbsorption) + Impl::ComputeAirAbsorptionFactor(volume, airAttenuation_dB));
120 }
121
122 } // namespace Impl
123
124
125 [[nodiscard]] JPL_INLINE simd EstimateRT60_Sabine(float w, float l, float h, const simd& avgAbsorption)
126 {
127 return Impl::EstimateRT60<Impl::Sabine>(w, l, h, avgAbsorption);
128 }
129
130 [[nodiscard]] JPL_INLINE simd EstimateRT60_Sabine(float w, float l, float h, const simd& avgAbsorption, const simd& airAttenuation_dB)
131 {
132 return Impl::EstimateRT60<Impl::Sabine>(w, l, h, avgAbsorption, airAttenuation_dB);
133
134 }
135
136 [[nodiscard]] JPL_INLINE simd EstimateRT60_Eyring(float w, float l, float h, const simd& avgAbsorption)
137 {
138 return Impl::EstimateRT60<Impl::Eyring>(w, l, h, avgAbsorption);
139 }
140
141 [[nodiscard]] JPL_INLINE simd EstimateRT60_Eyring(float w, float l, float h, const simd& avgAbsorption, const simd& airAttenuation_dB)
142 {
143 return Impl::EstimateRT60<Impl::Eyring>(w, l, h, avgAbsorption, airAttenuation_dB);
144 }
145
146} // namespace JPL
JPL_INLINE simd ComputeAirAbsorptionFactor(float volume, const simd &airAttenuation_dB)
Definition ReverbUtilities.h:94
JPL_INLINE simd EstimateRT60(float w, float l, float h, const simd &avgAbsorption)
Definition ReverbUtilities.h:104
Definition AcousticMaterial.h:36
JPL_INLINE simd clamp(const simd &value, const simd &minV, const simd &maxV) noexcept
Element-wise clamp.
Definition SIMD.h:1838
JPL_INLINE simd EstimateRT60_Sabine(float w, float l, float h, const simd &avgAbsorption)
Definition ReverbUtilities.h:125
JPL_INLINE simd EstimateRT60_Eyring(float w, float l, float h, const simd &avgAbsorption)
Definition ReverbUtilities.h:136
JPL_INLINE simd EstimateRT60FromMFP(float mfpMeters, const simd &avgAbsorption)
Estimate RT60 from Mean Free Path using Eyring-Norris equation.
Definition ReverbUtilities.h:57
simd log(simd x) noexcept
Definition SIMDMath.h:191
JPL_INLINE simd log10(const simd &vec) noexcept
log10 for 4-wide 32-bit float vector
Definition SIMDMath.h:241
Definition ReverbUtilities.h:87
static JPL_INLINE simd Compute(float surface, const simd &avgAbsorption)
Definition ReverbUtilities.h:88
Definition ReverbUtilities.h:79
static JPL_INLINE simd Compute(float surface, const simd &avgAbsorption)
Definition ReverbUtilities.h:80
Minimal 4-wide 32-bit float vector implementation for SIMD.
Definition SIMD.h:60