zenilib  0.5.3.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
Sound_Source_Pool.cpp
Go to the documentation of this file.
1 /* This file is part of the Zenipex Library (zenilib).
2  * Copyright (C) 2011 Mitchell Keith Bloch (bazald).
3  *
4  * zenilib is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU Lesser General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * zenilib is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public License
15  * along with zenilib. If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #include <zeni_audio.h>
19 
20 #include <algorithm>
21 #include <iostream>
22 
23 #include <Zeni/Define.h>
24 
25 #if defined(_DEBUG) && defined(_WINDOWS)
26 #define DEBUG_NEW new(_NORMAL_BLOCK, __FILE__, __LINE__)
27 #define new DEBUG_NEW
28 #endif
29 
30 #include <Zeni/Singleton.hxx>
31 
32 namespace Zeni {
33 
34  template class Singleton<Sound_Source_Pool>;
35 
36  Sound_Source_Pool * Sound_Source_Pool::create() {
37  return new Sound_Source_Pool;
38  }
39 
40  Singleton<Sound_Source_Pool>::Uninit Sound_Source_Pool::g_uninit;
41  Singleton<Sound_Source_Pool>::Reinit Sound_Source_Pool::g_reinit;
42 
43  Sound_Source_Pool::Sound_Source_Pool()
44  : m_replacement_policy(new Replacement_Policy()),
45  delete_m_replacement_policy(true),
46  m_muted(false)
47  {
48  Sound::remove_post_reinit(&g_reinit);
49 
50  // Ensure Sound is initialized
51  Sound &sr = get_Sound();
52 
53  sr.lend_pre_uninit(&g_uninit);
54  sr.lend_post_reinit(&g_reinit);
55  }
56 
57  Sound_Source_Pool::~Sound_Source_Pool() {
58  Sound::remove_pre_uninit(&g_uninit);
59 
60  purge();
61 
62  for(std::vector<Sound_Source *>::iterator it = m_handles.begin();
63  it != m_handles.end();
64  ++it)
65  {
66  (*it)->m_remove_from_Pool_on_destruction = false;
67  }
68 
69  if(delete_m_replacement_policy)
70  delete m_replacement_policy;
71  }
72 
74  if(&lhs == &rhs)
75  return false;
76 
77  if(!rhs.is_playing())
78  return false;
79  if(!lhs.is_playing())
80  return true;
81 
82  if(rhs.get_priority() < lhs.get_priority())
83  return false;
84  if(lhs.get_priority() < rhs.get_priority())
85  return true;
86 
87  if(rhs.get_gain() < lhs.get_gain())
88  return false;
89  if(lhs.get_gain() < rhs.get_gain())
90  return true;
91 
92  return lhs.get_unstop_time() < rhs.get_unstop_time();
93  }
94 
95  bool Sound_Source_Pool::Replacement_Policy::operator()(const Sound_Source * const &lhs, const Sound_Source * const &rhs) const {
96  return (*this)(*lhs, *rhs);
97  }
98 
100  : listener_position(listener_position_)
101  {
102  }
103 
105  if(&lhs == &rhs)
106  return false;
107 
108  if(!rhs.is_playing())
109  return false;
110  if(!lhs.is_playing())
111  return true;
112 
113  if(rhs.get_priority() < lhs.get_priority())
114  return false;
115  if(lhs.get_priority() < rhs.get_priority())
116  return true;
117 
118  if(rhs.get_priority() < lhs.get_priority())
119  return false;
120  if(lhs.get_priority() < rhs.get_priority())
121  return true;
122 
123  const float lhs_gain = lhs.calculate_gain(listener_position);
124  const float rhs_gain = rhs.calculate_gain(listener_position);
125 
126  if(rhs_gain < lhs_gain)
127  return false;
128  if(lhs_gain < rhs_gain)
129  return true;
130 
131  return lhs.get_unstop_time() < rhs.get_unstop_time();
132  }
133 
135  return *m_replacement_policy;
136  }
137 
139  set_Replacement_Policy(replacement_policy);
140  delete_m_replacement_policy = true;
141  }
142 
144  set_Replacement_Policy(replacement_policy);
145  delete_m_replacement_policy = false;
146  }
147 
149  for(std::vector<Sound_Source *>::iterator it = m_handles.begin();
150  it != m_handles.end();
151  ++it)
152  {
153  if((*it)->is_playing())
154  (*it)->pause();
155  }
156  }
157 
159  for(std::vector<Sound_Source *>::iterator it = m_handles.begin();
160  it != m_handles.end();
161  ++it)
162  {
163  if((*it)->is_paused())
164  (*it)->play();
165  }
166  }
167 
169  for(std::vector<Sound_Source *>::iterator it = m_playing_and_destroying.begin();
170  it != m_playing_and_destroying.end();
171  ++it)
172  {
173  delete *it;
174  }
175  m_playing_and_destroying.clear();
176 
177  destroy_all_hw();
178  }
179 
180  static void sound_quicksort(
181  const std::vector<Sound_Source *>::iterator &begin,
182  const std::vector<Sound_Source *>::iterator &end,
184  {
185  typedef std::vector<Sound_Source *>::difference_type diff_t;
186  const diff_t size = end - begin;
187 
188  if(size < 2)
189  return;
190 
191  std::vector<Sound_Source *> less, greater;
192  std::vector<Sound_Source *>::iterator pivot = begin + size / 2;
193  Sound_Source * const pivotValue = *pivot;
194 
195  for(std::vector<Sound_Source *>::iterator x = begin; x != end; ++x)
196  if(x != pivot) {
197  if(policy(*x, pivotValue))
198  less.push_back(*x);
199  else
200  greater.push_back(*x);
201  }
202 
203  const std::vector<Sound_Source *>::iterator less_end = std::copy(less.begin(), less.end(), begin);
204  *less_end = pivotValue;
205  const std::vector<Sound_Source *>::iterator greater_begin = less_end + 1;
206  std::copy(greater.begin(), greater.end(), greater_begin);
207 
208  less.clear();
209  greater.clear();
210 
211  sound_quicksort(begin, less_end, policy);
212  sound_quicksort(greater_begin, end, policy);
213  }
214 
216  /*** Handle the playing and destroying ***/
217 
218  std::vector<Sound_Source *> keepers;
219  keepers.reserve(m_playing_and_destroying.size());
220  for(std::vector<Sound_Source *>::iterator it = m_playing_and_destroying.begin();
221  it != m_playing_and_destroying.end();
222  ++it)
223  {
224  if((*it)->is_stopped()) {
225  ZENI_LOGD("Removing Sound_Source from Sound_Source_Pool");
226  delete *it;
227  }
228  else
229  keepers.push_back(*it);
230  }
231  m_playing_and_destroying.swap(keepers);
232 
233  /*** If muted, skip the rest of the update ***/
234 
235  if(m_muted)
236  return;
237 
238  /*** Do the regular update ***/
239 
240  std::vector<Sound_Source_HW *> unassigned_hw;
241  const size_t needed_hw = m_handles.size();
242  size_t given_hw = 0;
243 
244  /*** Find out how much Sound_Source_HW is needed ***/
245 
246  for(std::vector<Sound_Source *>::iterator it = m_handles.begin();
247  it != m_handles.end();
248  ++it)
249  {
250  if((*it)->is_assigned())
251  ++given_hw;
252  }
253 
254  /*** Acquire more Sound_Source_HW if needed (and if possible) ***/
255 
256 // ZENI_LOGD("Sound_Source_Pool has " + ulltoa(given_hw) + "/" + ulltoa(needed_hw));
257  while(needed_hw > given_hw
258 #ifdef TEST_NASTY_CONDITIONS
259  && given_hw < NASTY_SOUND_SOURCE_CAP
260 #endif
261  )
262  {
263  Sound_Source_HW * const sshw = Sound_Source_HW::Try_Construct();
264 
265  if(sshw) {
266  ZENI_LOGD("Sound_Source_HW added to Sound_Source_Pool");
267  unassigned_hw.push_back(sshw);
268  ++given_hw;
269  }
270  else {
271  ZENI_LOGD("Failed to add Sound_Source_HW to Sound_Source_Pool");
272  break;
273  }
274  }
275 
276  /*** Strip Sound_Source_HW from low priority 'Sound_Source's, as needed ***/
277 
278  const size_t cut = needed_hw - given_hw;
279 
280  if(cut) {
281  sound_quicksort(m_handles.begin(), m_handles.end(), *m_replacement_policy);
282 
283  for(size_t i = 0; i != cut; ++i) {
284  Sound_Source &source = *m_handles[i];
285 
286  if(source.is_assigned())
287  unassigned_hw.push_back(source.unassign());
288  }
289  }
290 
291  /*** Assign Sound_Source_HW to high priority 'Sound_Source's ***/
292 
293  std::vector<Sound_Source_HW *>::iterator jt = unassigned_hw.begin();
294 
295  for(size_t i = cut; i != needed_hw; ++i) {
296  Sound_Source &source = *m_handles[i];
297 
298  if(!source.is_assigned()) {
299  source.assign(**jt);
300  ++jt;
301  }
302  }
303  }
304 
305  void Sound_Source_Pool::play_and_destroy(Sound_Source * const &sound_source) {
306  m_playing_and_destroying.push_back(sound_source);
307  sound_source->play();
308  }
309 
310  void Sound_Source_Pool::set_Replacement_Policy(Sound_Source_Pool::Replacement_Policy * const &replacement_policy) {
311  assert(replacement_policy);
312 
313  if(delete_m_replacement_policy)
314  delete m_replacement_policy;
315 
316  m_replacement_policy = replacement_policy;
317  }
318 
319  void Sound_Source_Pool::insert_Sound_Source(Sound_Source &sound_source) {
320  m_handles.push_back(&sound_source);
321  }
322 
323  void Sound_Source_Pool::remove_Sound_Source(Sound_Source &sound_source) {
324  sound_source.stop();
325 
326  if(sound_source.m_hw) {
327  delete sound_source.m_hw;
328  sound_source.m_hw = 0;
329  }
330 
331  m_handles.erase(std::find(m_handles.begin(), m_handles.end(), &sound_source));
332  }
333 
334  void Sound_Source_Pool::destroy_all_hw() {
335  for(std::vector<Sound_Source *>::iterator it = m_handles.begin();
336  it != m_handles.end();
337  ++it)
338  {
339  if((*it)->is_assigned()) {
340  Sound_Source_HW * hw = (*it)->unassign();
341  hw->stop();
342  delete hw;
343  }
344  }
345  }
346 
348  return Sound_Source_Pool::get();
349  }
350 
352  const String &sound_name,
353  const float &pitch,
354  const float &gain,
355  const Point3f &position,
356  const Vector3f &velocity)
357  {
358  get_Sound_Source_Pool().play_and_destroy(new Sound_Source(get_Sounds()[sound_name], pitch, gain, position, velocity));
359  }
360 
361 }
362 
363 #include <Zeni/Undefine.h>
void pause_all()
Pause all Sound_Sources.
Sounds & get_Sounds()
Get access to the singleton.
Definition: Sounds.cpp:62
#define NASTY_SOUND_SOURCE_CAP
Definition: Define.h:130
float get_gain() const
Get the gain.
Sound_Source_Pool & get_Sound_Source_Pool()
Get access to the singleton.
virtual bool operator()(const Sound_Source &lhs, const Sound_Source &rhs) const
(Default) Priority Sort: Playing/Not-Playing, Priority, Gain, Recency
int get_priority() const
Get the Sound_Source&#39;s priority.
EGLSurface EGLint x
Definition: eglext.h:293
Time_HQ get_unstop_time() const
Get the Time_HQ at which the Sound_Source was most recently played or unpaused.
void purge()
Purge all Sound_Source_HW and all playing_and_destroying (created by play_sound(...))
Positional_Replacement_Policy(const Point3f &listener_position_)
#define assert(x)
Definition: SDL_malloc.c:1234
static void remove_post_reinit(Event::Handler *const &handler)
void play()
Begin playing or unpause the Sound_Source.
void unpause_all()
Unpause all paused Sound_Sources.
A 3D Point represented with floats.
Definition: Coordinate.h:133
Plays Sound Data.
Definition: Sound_Source.h:69
void update()
Redistribute hardware Sound_Sources according to the Replacement_Policy. Newer Sound_Sources are impl...
Plays Sound Data.
Definition: Sound_Source.h:147
Sound & get_Sound()
Get access to the singleton.
Definition: Sound.cpp:220
friend void play_sound(const String &sound_name, const float &pitch, const float &gain, const Point3f &position, const Vector3f &velocity)
A Featureful 3-Space Vector Class.
Definition: Vector3f.h:58
static void remove_pre_uninit(Event::Handler *const &handler)
void give_Replacement_Policy(Replacement_Policy *const &replacement_policy)
Give the Sound_Source_Pool a new Replacement_Policy (which it will delete later)
#define true
Definition: ftrandom.c:49
static Sound_Source_Pool & get()
void ZENI_LOGD(const Zeni::String &str)
Definition: Android.h:50
virtual bool operator()(const Sound_Source &lhs, const Sound_Source &rhs) const
Positional Priority Sort: Playing/Not-Playing, Priority, Computed Gain, Recency.
float calculate_gain(const Point3f &listener_position) const
Get the actual volume gain, given gain+position+near_clamp+far_clamp+rolloff.
This class manages Sound_Sources.
bool is_playing() const
Check to see if the Sound_Source is playing.
GLuint GLuint end
Definition: glew.h:1239
const Replacement_Policy & get_Replacement_Policy() const
Get the Replacement_Policy.
static void sound_quicksort(const std::vector< Sound_Source * >::iterator &begin, const std::vector< Sound_Source * >::iterator &end, const Sound_Source_Pool::Replacement_Policy &policy)
int i
Definition: pngrutil.c:1377
GLsizei GLsizei GLchar * source
Definition: gl2ext.h:994
bool is_assigned() const
Check to see if the Sound_Source is assigned to actual hardware.
#define false
Definition: ftrandom.c:50
void lend_Replacement_Policy(Replacement_Policy *const &replacement_policy)
Give the Sound_Source_Pool a new Replacement_Policy (which it will NEVER delete)
GLsizei size
Definition: gl2ext.h:1467