1 /*
2  * Copyright (C) 2010 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1.  Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer.
10  * 2.  Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution.
13  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14  *     its contributors may be used to endorse or promote products derived
15  *     from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include "third_party/blink/renderer/platform/audio/hrtf_database.h"
30 
31 #include <memory>
32 #include <utility>
33 
34 #include "base/memory/ptr_util.h"
35 #include "third_party/blink/public/resources/grit/blink_resources.h"
36 #include "third_party/blink/renderer/platform/wtf/math_extras.h"
37 
38 namespace blink {
39 
40 const int HRTFDatabase::kMinElevation = -45;
41 const int HRTFDatabase::kMaxElevation = 90;
42 const unsigned HRTFDatabase::kRawElevationAngleSpacing = 15;
43 const unsigned HRTFDatabase::kNumberOfRawElevations =
44     10;  // -45 -> +90 (each 15 degrees)
45 const unsigned HRTFDatabase::kInterpolationFactor = 1;
46 const unsigned HRTFDatabase::kNumberOfTotalElevations =
47     kNumberOfRawElevations * kInterpolationFactor;
48 
HRTFDatabase(float sample_rate)49 HRTFDatabase::HRTFDatabase(float sample_rate)
50     : elevations_(kNumberOfTotalElevations), sample_rate_(sample_rate) {
51   unsigned elevation_index = 0;
52   for (int elevation = kMinElevation; elevation <= kMaxElevation;
53        elevation += kRawElevationAngleSpacing) {
54     std::unique_ptr<HRTFElevation> hrtf_elevation =
55         HRTFElevation::CreateForSubject(IDR_AUDIO_SPATIALIZATION_COMPOSITE,
56                                         elevation, sample_rate);
57     DCHECK(hrtf_elevation.get());
58 
59     elevations_[elevation_index] = std::move(hrtf_elevation);
60     elevation_index += kInterpolationFactor;
61   }
62 
63   // Now, go back and interpolate elevations.
64   if (kInterpolationFactor > 1) {
65     for (unsigned i = 0; i < kNumberOfTotalElevations;
66          i += kInterpolationFactor) {
67       unsigned j = (i + kInterpolationFactor);
68       if (j >= kNumberOfTotalElevations)
69         j = i;  // for last elevation interpolate with itself
70 
71       // Create the interpolated convolution kernels and delays.
72       for (unsigned jj = 1; jj < kInterpolationFactor; ++jj) {
73         float x =
74             static_cast<float>(jj) / static_cast<float>(kInterpolationFactor);
75         elevations_[i + jj] = HRTFElevation::CreateByInterpolatingSlices(
76             elevations_[i].get(), elevations_[j].get(), x, sample_rate);
77         DCHECK(elevations_[i + jj].get());
78       }
79     }
80   }
81 }
82 
GetKernelsFromAzimuthElevation(double azimuth_blend,unsigned azimuth_index,double elevation_angle,HRTFKernel * & kernel_l,HRTFKernel * & kernel_r,double & frame_delay_l,double & frame_delay_r)83 void HRTFDatabase::GetKernelsFromAzimuthElevation(double azimuth_blend,
84                                                   unsigned azimuth_index,
85                                                   double elevation_angle,
86                                                   HRTFKernel*& kernel_l,
87                                                   HRTFKernel*& kernel_r,
88                                                   double& frame_delay_l,
89                                                   double& frame_delay_r) {
90   unsigned elevation_index = IndexFromElevationAngle(elevation_angle);
91   SECURITY_DCHECK(elevation_index < elevations_.size());
92   SECURITY_DCHECK(elevations_.size() > 0);
93 
94   if (elevation_index > elevations_.size() - 1)
95     elevation_index = elevations_.size() - 1;
96 
97   HRTFElevation* hrtf_elevation = elevations_[elevation_index].get();
98   DCHECK(hrtf_elevation);
99 
100   hrtf_elevation->GetKernelsFromAzimuth(azimuth_blend, azimuth_index, kernel_l,
101                                         kernel_r, frame_delay_l, frame_delay_r);
102 }
103 
IndexFromElevationAngle(double elevation_angle)104 unsigned HRTFDatabase::IndexFromElevationAngle(double elevation_angle) {
105   // Clamp to allowed range.
106   elevation_angle =
107       clampTo<double, double>(elevation_angle, kMinElevation, kMaxElevation);
108 
109   unsigned elevation_index = static_cast<int>(
110       kInterpolationFactor * (elevation_angle - kMinElevation) /
111       kRawElevationAngleSpacing);
112   return elevation_index;
113 }
114 
115 }  // namespace blink
116