Allolib  1.0
C++ Components For Interactive Multimedia
al_DynamicScene.hpp
1 
2 #ifndef AL_DYNAMICSCENE_HPP
3 #define AL_DYNAMICSCENE_HPP
4 
5 /* Allocore --
6  Multimedia / virtual environment application class library
7 
8  Copyright (C) 2009. AlloSphere Research Group, Media Arts & Technology,
9  UCSB. Copyright (C) 2012-2018. The Regents of the University of California.
10  All rights reserved.
11 
12  Redistribution and use in source and binary forms, with or without
13  modification, are permitted provided that the following conditions are
14  met:
15 
16  Redistributions of source code must retain the above copyright
17  notice, this list of conditions and the following disclaimer.
18 
19  Redistributions in binary form must reproduce the above
20  copyright notice, this list of conditions and the following disclaimer in the
21  documentation and/or other materials provided with the
22  distribution.
23 
24  Neither the name of the University of California nor the names
25  of its contributors may be used to endorse or promote products derived from
26  this software without specific prior written permission.
27 
28  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
29  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
31  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
32  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
33  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
34  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
35  OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
36  WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
37  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
38  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 
40  File description:
41  Dynamic Scene Manager
42 
43  File author(s):
44  AndrĂ©s Cabrera mantaraya36@gmail.com
45 */
46 
47 #include <condition_variable>
48 #include <memory>
49 #include <queue>
50 #include <thread>
51 
52 #include "al/math/al_Vec.hpp"
53 #include "al/scene/al_SynthSequencer.hpp"
54 #include "al/sound/al_Speaker.hpp"
55 #include "al/sound/al_StereoPanner.hpp"
56 #include "al/spatial/al_DistAtten.hpp"
57 #include "al/spatial/al_Pose.hpp"
58 
59 namespace al {
70 class PositionedVoice : public SynthVoice {
71 public:
72  const Pose pose() { return mPose.get(); }
73 
74  float size() { return mSize.get(); }
75 
76  void setPose(Pose pose) { mPose.set(pose); }
77 
78  void setSize(float size) { mSize.set(size); }
79 
80  ParameterPose &parameterPose() { return mPose; }
81 
82  Parameter &parameterSize() { return mSize; }
83 
84  bool useDistanceAttenuation() { return mUseDistAtten; }
85  void useDistanceAttenuation(bool atten) { mUseDistAtten = atten; }
86 
87  std::vector<Vec3f> &audioOutOffsets() { return mAudioOutPositionOffsets; }
88 
93  void audioOutOffsets(const std::vector<Vec3f> &offsets) {
94  mAudioOutPositionOffsets = offsets;
95  }
96 
101  virtual void preProcess(Graphics & /*g*/) {}
102 
107  virtual bool setTriggerParams(float *pFields, int numFields = -1) override;
108 
114  virtual bool setTriggerParams(std::vector<float> &pFields,
115  bool noCalls = false) override;
116 
122  virtual bool setTriggerParams(std::vector<ParameterField> pFields,
123  bool noCalls = false) override;
124 
129  virtual std::vector<ParameterField> getTriggerParams() override {
130  std::vector<ParameterField> pFields = SynthVoice::getTriggerParams();
131  pFields.reserve(pFields.size() + 8);
132  Pose currentPose = pose();
133  pFields.insert(pFields.end(), currentPose.vec().begin(),
134  currentPose.vec().end());
135 
136  auto *comps = currentPose.quat().components;
137 
138  pFields.push_back(*comps++);
139  pFields.push_back(*comps++);
140  pFields.push_back(*comps++);
141  pFields.push_back(*comps);
142 
143  pFields.push_back(mSize.get());
144  return pFields;
145  }
146 
147 protected:
151  void markAsReplica() { mIsReplica = true; }
152 
153  ParameterPose mPose{"_pose"};
154  Parameter mSize{"_size", "", 1.0};
155  // ParameterPose mPose {"_pose"};
156  // Parameter mSize {"_size", "", 1.0};
157  std::vector<Vec3f>
158  mAudioOutPositionOffsets; // This vector is added to the voice's position
159  // to determine the specific position of the
160  // audio out
161 
162  bool mUseDistAtten{true};
163  bool mIsReplica{false}; // If voice is replica, it should not send its
164  // internal state but listen for changes.
165 };
166 
168  SynthVoice *voice;
169  double dt;
170 };
171 
172 // thread pool from
173 // https://stackoverflow.com/questions/23896421/efficiently-waiting-for-all-tasks-in-a-threadpool-to-finish
174 class ThreadPool {
175 public:
176  ThreadPool(unsigned int n = std::thread::hardware_concurrency());
177 
178  template <class F> void enqueue(F &&f, UpdateThreadFuncData &data);
179  void waitForProcessingDone();
180  ~ThreadPool();
181 
182  size_t size() { return workers.size(); }
183 
184  void stopThreads();
185 
186 private:
187  std::vector<std::thread> workers;
188  std::deque<std::pair<std::function<void(UpdateThreadFuncData)>,
190  tasks;
191  std::mutex queue_mutex;
192  std::condition_variable cv_task;
193  std::condition_variable cv_finished;
194  unsigned int busy;
195  bool stop{false};
196 
197  void thread_proc();
198 };
199 
200 template <class F> void ThreadPool::enqueue(F &&f, UpdateThreadFuncData &data) {
201  std::unique_lock<std::mutex> lock(queue_mutex);
202  tasks.emplace_back(std::pair<std::function<void(UpdateThreadFuncData)>,
203  UpdateThreadFuncData>(std::forward<F>(f), data));
204  cv_task.notify_one();
205 }
206 
211 class DynamicScene : public PolySynth {
212 public:
213  DynamicScene(int threadPoolSize = 0,
214  TimeMasterMode masterMode = TimeMasterMode::TIME_MASTER_AUDIO);
215 
216  virtual ~DynamicScene();
217 
225  template <class TSpatializer>
226  std::shared_ptr<TSpatializer> setSpatializer(Speakers &sl) {
227  mSpatializer = std::make_shared<TSpatializer>(sl);
228  mSpatializer->compile();
229  return std::static_pointer_cast<TSpatializer>(mSpatializer);
230  }
231 
242  void prepare(AudioIOData &io);
243 
244  virtual void cleanup() {}
245 
251  Pose &listenerPose() { return mListenerPose; }
252  void listenerPose(Pose &pose) { mListenerPose = pose; }
253 
254  virtual void render(Graphics &g) final;
255  virtual void render(AudioIOData &io) final;
256 
263  virtual void update(double dt = 0) final;
264 
265  void setUpdateThreaded(bool threaded) { mThreadedUpdate = threaded; }
266  void setAudioThreaded(bool threaded) { mThreadedAudio = threaded; }
267 
268  DistAtten<> &distanceAttenuation() { return mDistAtten; }
269 
270  void print(std::ostream &stream = std::cout);
271 
272  void showWorldMarker(bool show = true) { mDrawWorldMarker = show; }
273 
277  void sortDrawingByDistance(bool sort = true);
278 
287  mSynthRunning = false;
288  mThreadTrigger.notify_all();
289  for (auto &thr : mAudioThreads) {
290  thr.join();
291  }
292  mAudioThreads.clear();
293  }
294 
295 protected:
296 private:
297  // A speaker layout and spatializer
298  std::shared_ptr<Spatializer> mSpatializer;
299 
300  Pose mListenerPose;
301  DistAtten<> mDistAtten;
302 
303  bool mSortDrawingByDistance{false};
304  // For threaded simulation
305  std::unique_ptr<ThreadPool> mWorkerThreads; // Update worker threads
306  bool mThreadedUpdate{true};
307 
308  // For threaded audio
309  bool mThreadedAudio{false};
310  std::vector<std::thread> mAudioThreads;
311  std::vector<AudioIOData> mThreadedAudioData;
312  std::map<int, std::vector<int>>
313  mThreadMap; // Defines which threads run which voices. Key is thread id,
314  // value is voice ids.
315  std::condition_variable mThreadTrigger;
316  std::condition_variable mAudioThreadDone;
317  std::mutex mSpatializerLock;
318  AudioIOData
319  *externalAudioIO; // This is captured by the audio callback and passed to
320  // the audio threads. Protected by mSpatializerLock
321  std::mutex mThreadTriggerLock;
322  bool mSynthRunning{true};
323  unsigned int mAudioBusy = 0;
324 
325  static void updateThreadFunc(UpdateThreadFuncData data);
326 
327  static void audioThreadFunc(DynamicScene *scene, int id);
328 
329  // World marker
330  bool mDrawWorldMarker{false};
331  Mesh mWorldMarker;
332 };
333 
334 } // namespace al
335 
336 #endif // AL_DYNAMICSCENE_HPP
The DynamicScene class.
std::shared_ptr< TSpatializer > setSpatializer(Speakers &sl)
Set a Spatializar to use.
Pose & listenerPose()
The listener pose is used to determine both the graphic view and the audio spatialization.
virtual void render(AudioIOData &io) final
render all the active voices into the audio buffers
virtual void update(double dt=0) final
This function runs the simulation/update of internal states for each voice.
void stopAudioThreads()
Stop all audio threads. No processing is possible after calling this function.
void prepare(AudioIOData &io)
Prepares internals for run.
void sortDrawingByDistance(bool sort=true)
Enables/disables sorting by distance to listener on graphics render.
virtual void render(Graphics &g) final
render graphics for all active voices
Interface for loading fonts and rendering text.
Definition: al_Graphics.hpp:63
The Parameter class.
virtual float get() override
get the parameter's value
virtual void set(float value, ValueSource *src=nullptr) override
set the parameter's value
virtual ParameterType get()
get the parameter's value
virtual void set(ParameterType value, ValueSource *src=nullptr)
set the parameter's value
A PolySynth manages polyphony and rendering of SynthVoice instances.
A local coordinate frame.
Definition: al_Pose.hpp:63
Vec3d & vec()
Get vector component.
Definition: al_Pose.hpp:104
Quatd & quat()
Get quaternion component (represents orientation)
Definition: al_Pose.hpp:108
A PositionedVoice is a rendering class that can have a position and size.
void markAsReplica()
Set voice as part of a replica distributed scene.
virtual bool setTriggerParams(float *pFields, int numFields=-1) override
For PositionedVoice, the pose (7 floats) and the size are appended to the pfields.
void audioOutOffsets(const std::vector< Vec3f > &offsets)
Set the position offset for each of the audio outputs for this voice.
virtual bool setTriggerParams(std::vector< float > &pFields, bool noCalls=false) override
Set parameter values.
virtual void preProcess(Graphics &)
Override this function to apply transformations after the internal transformations of the voice has b...
virtual std::vector< ParameterField > getTriggerParams() override
For PositionedVoice, the pose (7 floats) and the size are appended to the pfields.
virtual bool setTriggerParams(std::vector< ParameterField > pFields, bool noCalls=false) override
Set parameter values.
T components[4]
component vector
Definition: al_Quat.hpp:72
The SynthVoice class.
virtual std::vector< ParameterField > getTriggerParams()
Get this instance's parameter fields.
void sort(T &value1, T &value2)
Definition: al_App.hpp:23
std::vector< Speaker > Speakers
A set of speakers.
Definition: al_Speaker.hpp:101