SAL
A C++ library for spatial audio.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
microphonearray.h
Go to the documentation of this file.
1 /*
2  microphonearray.h
3  Spatial Audio Library (SAL)
4  Copyright (c) 2011, Enzo De Sena
5  All rights reserved.
6 
7  Authors: Enzo De Sena, enzodesena@gmail.com
8 
9  */
10 
11 #ifndef SAL_MICROPHONEARRAY_H
12 #define SAL_MICROPHONEARRAY_H
13 
14 
15 #include "microphone.h"
16 #include "point.h"
17 #include "source.h"
18 #include "microphone.h"
19 #include "saltypes.h"
20 #include "salconstants.h"
21 #include "monomics.h"
22 #include "salconstants.h"
23 
24 namespace sal {
25 
32 class MicrophoneArray : public Microphone {
33 public:
34  MicrophoneArray(const mcl::Point& position,
35  const mcl::Quaternion& orientation,
36  const std::vector<Microphone*>& microphones) :
37  Microphone(position, orientation), microphones_(microphones) {}
38 
39 
44  virtual void SetPosition(const mcl::Point& position) noexcept {
45  mcl::Point position_delta(position.x()-this->position().x(),
46  position.y()-this->position().y(),
47  position.z()-this->position().z());
48  for (Int i=0; i<(Int)microphones_.size(); ++i) {
49  mcl::Point old_mic_position = microphones_[i]->position();
50  mcl::Point new_mic_position(old_mic_position.x()+position_delta.x(),
51  old_mic_position.y()+position_delta.y(),
52  old_mic_position.z()+position_delta.z());
53  microphones_[i]->SetPosition(new_mic_position);
54  }
55 
57  }
58 
59 
60 
61  void SetOrientation(const mcl::Quaternion& orientation) noexcept {
62  for (Int i=0; i<(Int)microphones_.size(); ++i) {
63  microphones_[i]->SetOrientation(orientation);
64  }
65  orientation_ = orientation;
66  }
67 
72  bool IsCoincident() const noexcept {
73  const Int num_microphones = (Int)microphones_.size();
74 
75  if (num_microphones == 0 || num_microphones == 1) { return true; }
76 
77  mcl::Point position(microphones_[0]->position());
78  for (Int i=1; i<num_microphones; ++i) {
79  if (! IsEqual(microphones_[i]->position(), position)) {
80  return false;
81  }
82  }
83  return true;
84  }
85 
86  Int num_channels() const noexcept {
87  return microphones_.size();
88  }
89 
90  const Microphone* GetConstMicrophonePointer(const Int microphone_id) const noexcept {
91  return microphones_.at(microphone_id);
92  }
93 
94  Microphone* GetMicrophonePointer(const Int microphone_id) noexcept {
95  return microphones_.at(microphone_id);
96  }
97 
98  std::vector<Microphone*> GetMicrophonePointers() const noexcept {
99  return microphones_;
100  }
101 
102  std::vector<const Microphone*> GetConstMicrophonePointers() const noexcept {
103  std::vector<const Microphone*> microphones(num_microphones());
104  for (Int i=0; i<num_microphones(); ++i) {
105  microphones[i] = (const Microphone*) microphones_[i];
106  }
107  return microphones;
108  }
109 
110  Int num_microphones() const noexcept {
111  return microphones_.size();
112  }
113 
114  static bool Test();
115 
116  virtual ~MicrophoneArray() {}
117 
118 
128  virtual void AddPlaneWave(const Sample* input_data,
129  const Int num_samples,
130  const mcl::Point& point,
131  const Int wave_id,
132  Buffer& output_buffer) noexcept {
134  for (Int mic_i=0; mic_i<num_microphones; ++mic_i) {
135  MonoBuffer referencing_buffer(output_buffer, mic_i);
136  // Each microphone will push in his own mono stream. The multichannel
137  // stream is merely a vector of pointers to the individual mono streams
138  microphones_[mic_i]->AddPlaneWave(input_data, num_samples, point,
139  wave_id, referencing_buffer);
140  }
141  }
142 
143  virtual void AddPlaneWaveRelative(const Sample* input_data,
144  const Int num_samples,
145  const mcl::Point& point,
146  const Int wave_id,
147  Buffer& output_buffer) noexcept {
148  // This method can't be called directly (should call AddPlaneWave instead.
149  // That's because the relative point needs to be calculated with respect
150  // to each microphone individually. If you could call
151  // AddPlaneWaveRelative directly, on the other hand, it would carry out
152  // the same rotation for all of them.
153  ASSERT(false);
154  }
155 protected:
156  std::vector<Microphone*> microphones_;
157 };
158 
159 
165 template<class T>
167 public:
168  UniformArray(const mcl::Point& position,
169  const mcl::Quaternion& orientation,
170  const T& mic_prototype,
171  const mcl::Int num_microphones) :
172  MicrophoneArray(position, orientation,
173  MicrophoneFactory(mic_prototype, num_microphones)) {}
174 
175  virtual ~UniformArray() {
176  for (Int i=0; i<(Int) microphones_.size(); ++i) { delete microphones_[i]; }
177  }
178 
179 private:
180  std::vector<Microphone*>
181  MicrophoneFactory(const T& mic_prototype, const Int num_microphones) {
182  std::vector<Microphone*> output(num_microphones);
183  for (Int i=0; i<num_microphones; ++i) {
184  output[i] = new T(mic_prototype);
185  }
186  return output;
187  }
188 };
189 
197 template<class T>
198 class CircularArray : public UniformArray<T> {
199 public:
200  CircularArray(const mcl::Point& position,
201  const mcl::Quaternion& orientation,
202  const T& mic_prototype,
203  const Length radius,
204  const std::vector<Angle>& angles) :
205  UniformArray<T>(position, orientation, mic_prototype, angles.size()),
206  radius_(radius), angles_(angles) {
207  SetOrientation(orientation);
208  }
209 
210  virtual void SetOrientation(const mcl::Quaternion& orientation) noexcept {
211  mcl::Point position(this->position());
212  std::vector<mcl::Point> positions = GetPositions(position, radius_, angles_);
213 
214  for (mcl::Int i=0; i<(Int)angles_.size(); ++i) {
215  Angle mic_angle = (this->handedness_ == mcl::Handedness::kRightHanded) ? angles_[i] : -angles_[i];
216  mcl::Point relative_position = mcl::QuatRotate(orientation,
217  mcl::Subtract(positions[i],
218  position),
219  this->handedness_);
220  this->microphones_[i]->SetPosition(mcl::Sum(relative_position, position));
221 
222  mcl::Quaternion q = mcl::QuatMultiply(orientation, mcl::AxAng2Quat(0.0, 0.0, 1.0, mic_angle));
223  this->microphones_[i]->SetOrientation(q);
224  }
225  }
226 
227 private:
228  Length radius_;
229  std::vector<Angle> angles_;
230 
231  static std::vector<mcl::Point> GetPositions(const mcl::Point& position,
232  const Length radius,
233  const std::vector<Angle>& angles) {
234  std::vector<mcl::Point> positions(angles.size());
235  for (Int i=0; i<(Int)angles.size(); ++i) {
236  positions[i] = mcl::Point(radius*cos(angles[i])+position.x(),
237  radius*sin(angles[i])+position.y(),
238  position.z());
239  }
240  return positions;
241  }
242 };
243 
244 
245 
252 template<class T>
253 class StereoMic : public CircularArray<T> {
254 public:
255  StereoMic(const mcl::Point& position,
256  const mcl::Quaternion& orientation,
257  const T& mic_prototype,
258  const Length radius,
259  const Angle base_angle,
260  const Angle center_angle) :
261  CircularArray<T>(position, orientation,
262  mic_prototype, radius,
263  StereoAngles(base_angle, center_angle)) {}
264 
265 private:
266  static std::vector<Angle> StereoAngles(const Angle base_angle,
267  const Angle center_angle) {
268  std::vector<Angle> angles(2);
269  angles[0] = center_angle-base_angle/2.0;
270  angles[1] = center_angle+base_angle/2.0;
271  return angles;
272  }
273 };
274 
275 
276 bool MicrophoneArrayTest();
277 
278 } // namespace sal
279 
280 #endif