1/*
2Copyright 2018 Google Inc. All Rights Reserved.
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS-IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15*/
16
17#if defined(_WIN32)
18#define _SCL_SECURE_NO_WARNINGS
19#endif
20
21#include "ambisonics/foa_rotator.h"
22
23#include <algorithm>
24
25#include "base/constants_and_types.h"
26#include "base/misc_math.h"
27
28namespace vraudio {
29
30bool FoaRotator::Process(const WorldRotation& target_rotation,
31 const AudioBuffer& input, AudioBuffer* output) {
32
33 DCHECK(output);
34 DCHECK_EQ(input.num_channels(), kNumFirstOrderAmbisonicChannels);
35 DCHECK_EQ(input.num_channels(), output->num_channels());
36 DCHECK_EQ(input.num_frames(), output->num_frames());
37
38 static const WorldRotation kIdentityRotation;
39
40 if (current_rotation_.AngularDifferenceRad(other: kIdentityRotation) <
41 kRotationQuantizationRad &&
42 target_rotation.AngularDifferenceRad(other: kIdentityRotation) <
43 kRotationQuantizationRad) {
44 return false;
45 }
46
47 if (current_rotation_.AngularDifferenceRad(other: target_rotation) <
48 kRotationQuantizationRad) {
49 // Rotate the whole input buffer frame by frame.
50 Rotate(target_rotation: current_rotation_, start_location: 0, duration: input.num_frames(), input, output);
51 return true;
52 }
53
54 // In order to perform a smooth rotation, we divide the buffer into
55 // chunks of size |kSlerpFrameInterval|.
56 //
57
58 const size_t kSlerpFrameInterval = 32;
59
60 WorldRotation slerped_rotation;
61 // Rotate the input buffer at every slerp update interval. Truncate the
62 // final chunk if the input buffer is not an integer multiple of the
63 // chunk size.
64 for (size_t i = 0; i < input.num_frames(); i += kSlerpFrameInterval) {
65 const size_t duration =
66 std::min(a: input.num_frames() - i, b: kSlerpFrameInterval);
67 const float interpolation_factor = static_cast<float>(i + duration) /
68 static_cast<float>(input.num_frames());
69 slerped_rotation =
70 current_rotation_.slerp(t: interpolation_factor, other: target_rotation);
71 // Rotate the input buffer frame by frame within the current chunk.
72 Rotate(target_rotation: slerped_rotation, start_location: i, duration, input, output);
73 }
74
75 current_rotation_ = target_rotation;
76
77 return true;
78}
79
80void FoaRotator::Rotate(const WorldRotation& target_rotation,
81 size_t start_location, size_t duration,
82 const AudioBuffer& input, AudioBuffer* output) {
83
84 const AudioBuffer::Channel& input_channel_audio_space_w = input[0];
85 const AudioBuffer::Channel& input_channel_audio_space_y = input[1];
86 const AudioBuffer::Channel& input_channel_audio_space_z = input[2];
87 const AudioBuffer::Channel& input_channel_audio_space_x = input[3];
88 AudioBuffer::Channel* output_channel_audio_space_w = &(*output)[0];
89 AudioBuffer::Channel* output_channel_audio_space_y = &(*output)[1];
90 AudioBuffer::Channel* output_channel_audio_space_z = &(*output)[2];
91 AudioBuffer::Channel* output_channel_audio_space_x = &(*output)[3];
92
93 for (size_t frame = start_location; frame < start_location + duration;
94 ++frame) {
95 // Convert the current audio frame into world space position.
96 temp_audio_position_(0) = input_channel_audio_space_x[frame];
97 temp_audio_position_(1) = input_channel_audio_space_y[frame];
98 temp_audio_position_(2) = input_channel_audio_space_z[frame];
99 ConvertWorldFromAudioPosition(audio_position: temp_audio_position_, world_position: &temp_world_position_);
100 // Apply rotation to |world_position| and return to audio space.
101 temp_rotated_world_position_ = target_rotation * temp_world_position_;
102
103 ConvertAudioFromWorldPosition(world_position: temp_rotated_world_position_,
104 audio_position: &temp_rotated_audio_position_);
105 (*output_channel_audio_space_x)[frame] =
106 temp_rotated_audio_position_(0); // X
107 (*output_channel_audio_space_y)[frame] =
108 temp_rotated_audio_position_(1); // Y
109 (*output_channel_audio_space_z)[frame] =
110 temp_rotated_audio_position_(2); // Z
111 }
112 // Copy W channel.
113 std::copy_n(first: &input_channel_audio_space_w[start_location], n: duration,
114 result: &(*output_channel_audio_space_w)[start_location]);
115}
116
117} // namespace vraudio
118

source code of qtmultimedia/src/3rdparty/resonance-audio/resonance_audio/ambisonics/foa_rotator.cc