Panda3D
 All Classes Functions Variables Enumerations
milesAudioSample.cxx
1 // Filename: milesAudioSample.cxx
2 // Created by: skyler (June 6, 2001)
3 //
4 ////////////////////////////////////////////////////////////////////
5 //
6 // PANDA 3D SOFTWARE
7 // Copyright (c) Carnegie Mellon University. All rights reserved.
8 //
9 // All use of this software is subject to the terms of the revised BSD
10 // license. You should have received a copy of this license along
11 // with this source code in a file named "LICENSE."
12 //
13 ////////////////////////////////////////////////////////////////////
14 
15 #include "milesAudioSample.h"
16 
17 #ifdef HAVE_RAD_MSS //[
18 
19 #include "milesAudioManager.h"
20 
21 
22 TypeHandle MilesAudioSample::_type_handle;
23 
24 #undef miles_audio_debug
25 
26 #ifndef NDEBUG //[
27 #define miles_audio_debug(x) \
28  audio_debug("MilesAudioSample \""<<get_name()<<"\" "<< x )
29 #else //][
30 #define miles_audio_debug(x) ((void)0)
31 #endif //]
32 
33 ////////////////////////////////////////////////////////////////////
34 // Function: MilesAudioSample::Constructor
35 // Access: Private
36 // Description: This constructor is called only by the
37 // MilesAudioManager.
38 ////////////////////////////////////////////////////////////////////
39 MilesAudioSample::
40 MilesAudioSample(MilesAudioManager *manager, MilesAudioManager::SoundData *sd,
41  const string &file_name) :
42  MilesAudioSound(manager, file_name),
43  _sd(sd)
44 {
45  nassertv(sd != NULL);
46  audio_debug("MilesAudioSample(manager=0x"<<(void*)&manager
47  <<", sd=0x"<<(void*)sd<<", file_name="<<file_name<<")");
48 
49  _sample = 0;
50  _sample_index = 0;
51  _original_playback_rate = 1.0f;
52 }
53 
54 ////////////////////////////////////////////////////////////////////
55 // Function: MilesAudioSample::Destructor
56 // Access: Public, Virtual
57 // Description:
58 ////////////////////////////////////////////////////////////////////
59 MilesAudioSample::
60 ~MilesAudioSample() {
61  miles_audio_debug("~MilesAudioSample()");
62  cleanup();
63  miles_audio_debug("~MilesAudioSample() done");
64 }
65 
66 ////////////////////////////////////////////////////////////////////
67 // Function: MilesAudioSample::play
68 // Access: Public, Virtual
69 // Description:
70 ////////////////////////////////////////////////////////////////////
71 void MilesAudioSample::
72 play() {
73  miles_audio_debug("play()");
74  if (_active) {
75  if (_sd->_raw_data.empty()) {
76  milesAudio_cat.warning()
77  << "Could not play " << _file_name << ": no data\n";
78  } else {
79  stop();
80  _manager->starting_sound(this);
81 
82  nassertv(_sample == 0);
83 
84  GlobalMilesManager *mgr = GlobalMilesManager::get_global_ptr();
85  if (!mgr->get_sample(_sample, _sample_index, this)){
86  milesAudio_cat.warning()
87  << "Could not play " << _file_name << ": too many open samples\n";
88  _sample = 0;
89  } else {
90  AIL_set_named_sample_file(_sample, _sd->_basename.c_str(),
91  &_sd->_raw_data[0], _sd->_raw_data.size(),
92  0);
93  _original_playback_rate = AIL_sample_playback_rate(_sample);
94  AIL_set_sample_user_data(_sample, 0, (SINTa)this);
95  AIL_register_EOS_callback(_sample, finish_callback);
96 
97  set_volume(_volume);
98  set_play_rate(_play_rate);
99  AIL_set_sample_loop_count(_sample, _loop_count);
100 
101  if (_got_start_time) {
102  do_set_time(_start_time);
103  AIL_resume_sample(_sample);
104  } else {
105  AIL_start_sample(_sample);
106  }
107  }
108 
109  _got_start_time = false;
110  }
111  } else {
112  // In case _loop_count gets set to forever (zero):
113  audio_debug(" paused "<<_file_name );
114  _paused = true;
115  }
116 }
117 
118 ////////////////////////////////////////////////////////////////////
119 // Function: MilesAudioSample::stop
120 // Access: Public, Virtual
121 // Description:
122 ////////////////////////////////////////////////////////////////////
123 void MilesAudioSample::
124 stop() {
125  if (_manager == (MilesAudioManager *)NULL) {
126  return;
127  }
128 
129  miles_audio_debug("stop()");
130  _manager->stopping_sound(this);
131  // The _paused flag should not be cleared here. _paused is not like
132  // the Pause button on a cd/dvd player. It is used as a flag to say
133  // that it was looping when it was set inactive. There is no need to
134  // make this symmetrical with play(). set_active() is the 'owner' of
135  // _paused. play() accesses _paused to help in the situation where
136  // someone calls play on an inactive sound().
137 
138  // it fixes audio bug, I don't understand the reasoning of the above comment
139  _paused = false;
140 
141  if (_sample != 0) {
142  AIL_end_sample(_sample);
143 
144  GlobalMilesManager *mgr = GlobalMilesManager::get_global_ptr();
145  mgr->release_sample(_sample_index, this);
146 
147  _sample = 0;
148  _sample_index = 0;
149  }
150 }
151 
152 ////////////////////////////////////////////////////////////////////
153 // Function: MilesAudioSample::get_time
154 // Access: Public, Virtual
155 // Description:
156 ////////////////////////////////////////////////////////////////////
157 PN_stdfloat MilesAudioSample::
158 get_time() const {
159  if (_sample == 0) {
160  if (_got_start_time) {
161  return _start_time;
162  }
163  return 0.0f;
164  }
165 
166  S32 current_ms;
167  AIL_sample_ms_position(_sample, NULL, &current_ms);
168  PN_stdfloat time = PN_stdfloat(current_ms * 0.001f);
169 
170  return time;
171 }
172 
173 ////////////////////////////////////////////////////////////////////
174 // Function: MilesAudioSample::set_volume
175 // Access: Public, Virtual
176 // Description:
177 ////////////////////////////////////////////////////////////////////
178 void MilesAudioSample::
179 set_volume(PN_stdfloat volume) {
180  miles_audio_debug("set_volume(volume="<<volume<<")");
181 
182  // Set the volume even if our volume is not changing, because the
183  // MilesAudioManager will call set_volume() when *its* volume
184  // changes.
185 
186  // Set the volume:
187  _volume = volume;
188 
189  if (_sample != 0) {
190  volume *= _manager->get_volume();
191 
192  // Change to Miles volume, range 0 to 1.0:
193  F32 milesVolume = volume;
194  milesVolume = min(milesVolume, 1.0f);
195  milesVolume = max(milesVolume, 0.0f);
196 
197  // Convert balance of -1.0..1.0 to 0-1.0:
198  F32 milesBalance = (F32)((_balance + 1.0f) * 0.5f);
199 
200  AIL_set_sample_volume_pan(_sample, milesVolume, milesBalance);
201  }
202 }
203 
204 ////////////////////////////////////////////////////////////////////
205 // Function: MilesAudioSample::set_balance
206 // Access: Public, Virtual
207 // Description:
208 ////////////////////////////////////////////////////////////////////
209 void MilesAudioSample::
210 set_balance(PN_stdfloat balance_right) {
211  miles_audio_debug("set_balance(balance_right="<<balance_right<<")");
212  _balance = balance_right;
213 
214  // Call set_volume to effect the change:
215  set_volume(_volume);
216 }
217 
218 ////////////////////////////////////////////////////////////////////
219 // Function: MilesAudioSample::set_play_rate
220 // Access: Public, Virtual
221 // Description:
222 ////////////////////////////////////////////////////////////////////
223 void MilesAudioSample::
224 set_play_rate(PN_stdfloat play_rate) {
225  miles_audio_debug("set_play_rate(play_rate="<<play_rate<<")");
226 
227  // Set the play_rate:
228  _play_rate = play_rate;
229 
230  if (_sample != 0) {
231  play_rate *= _manager->get_play_rate();
232 
233  // wave and mp3 use sample rate (e.g. 44100)
234  S32 speed = (S32)(play_rate * (PN_stdfloat)_original_playback_rate);
235  AIL_set_sample_playback_rate(_sample, speed);
236  audio_debug(" play_rate for this wav or mp3 is now " << speed);
237  }
238 }
239 
240 ////////////////////////////////////////////////////////////////////
241 // Function: MilesAudioSample::length
242 // Access: Public, Virtual
243 // Description:
244 ////////////////////////////////////////////////////////////////////
245 PN_stdfloat MilesAudioSample::
246 length() const {
247  return _sd->get_length();
248 }
249 
250 ////////////////////////////////////////////////////////////////////
251 // Function: MilesAudioSample::status
252 // Access: Public, Virtual
253 // Description:
254 ////////////////////////////////////////////////////////////////////
255 AudioSound::SoundStatus MilesAudioSample::
256 status() const {
257  if (_sample == 0) {
258  return AudioSound::READY;
259  }
260  switch (AIL_sample_status(_sample)) {
261  case SMP_DONE:
262  case SMP_STOPPED:
263  case SMP_FREE:
264  return AudioSound::READY;
265 
266  case SMP_PLAYING:
267  case SMP_PLAYINGBUTRELEASED:
268  return AudioSound::PLAYING;
269 
270  default:
271  return AudioSound::BAD;
272  }
273 }
274 
275 ////////////////////////////////////////////////////////////////////
276 // Function: MilesAudioSample::cleanup
277 // Access: Public, Virtual
278 // Description: Stops the sound from playing and releases any
279 // associated resources, in preparation for releasing
280 // the sound or shutting down the sound system.
281 ////////////////////////////////////////////////////////////////////
282 void MilesAudioSample::
283 cleanup() {
284  stop();
285  set_active(false);
286  nassertv(_sample == 0);
287 
288  if (_manager != (MilesAudioManager *)NULL) {
289  _manager->release_sound(this);
290  _manager = NULL;
291  }
292 }
293 
294 ////////////////////////////////////////////////////////////////////
295 // Function: MilesAudioSample::output
296 // Access: Published, Virtual
297 // Description:
298 ////////////////////////////////////////////////////////////////////
299 void MilesAudioSample::
300 output(ostream &out) const {
301  out << get_type() << " " << get_name() << " " << status();
302  if (!_sd.is_null()) {
303  out << " " << (_sd->_raw_data.size() + 1023) / 1024 << "K";
304  }
305 }
306 
307 ////////////////////////////////////////////////////////////////////
308 // Function: MilesAudioSample::set_3d_attributes
309 // Access: public
310 // Description: Set position and velocity of this sound. Note that
311 // Y and Z are switched to translate from Miles's
312 // coordinate system.
313 ////////////////////////////////////////////////////////////////////
314 void MilesAudioSample::set_3d_attributes(PN_stdfloat px, PN_stdfloat py, PN_stdfloat pz, PN_stdfloat vx, PN_stdfloat vy, PN_stdfloat vz) {
315  audio_debug("MilesAudioSample::set_3d_attributes() Setting a sound's 3D Coordinates.");
316 
317  if(_sample != 0) {
318  AIL_set_sample_3D_position(_sample, px, pz, py);
319  AIL_set_sample_3D_velocity_vector(_sample, vx, vz, vy);
320  } else {
321  audio_warning("_sample == 0 in MilesAudioSample::set_3d_attributes().");
322  }
323 }
324 
325 ////////////////////////////////////////////////////////////////////
326 // Function: MilesAudioSample::get_3d_attributes
327 // Access: public
328 // Description: Get position and velocity of this sound.
329 ////////////////////////////////////////////////////////////////////
330 void MilesAudioSample::get_3d_attributes(PN_stdfloat *px, PN_stdfloat *py, PN_stdfloat *pz, PN_stdfloat *vx, PN_stdfloat *vy, PN_stdfloat *vz) {
331  audio_debug("MilesAudioSample::get_3d_attributes().");
332 
333  if(_sample != 0) {
334  float lpx, lpy, lpz, lvx, lvy, lvz;
335  AIL_sample_3D_position(_sample, &lpx, &lpz, &lpy);
336  AIL_sample_3D_velocity(_sample, &lvx, &lvz, &lvy);
337  *px = lpx;
338  *py = lpy;
339  *pz = lpz;
340  *vx = lvx;
341  *vy = lvy;
342  *vz = lvz;
343  } else {
344  audio_warning("_sample == 0 in MilesAudioSample::get_3d_attributes().");
345  }
346 }
347 
348 ////////////////////////////////////////////////////////////////////
349 // Function: MilesAudioSample::set_3d_min_distance
350 // Access: public
351 // Description: Set the distance that this sound begins to fall
352 // off. With Miles's default falloff behavior, when
353 // the distance between the sound and the listener is
354 // doubled, the volume is halved, and vice versa.
355 ////////////////////////////////////////////////////////////////////
356 void MilesAudioSample::set_3d_min_distance(PN_stdfloat dist) {
357  audio_debug("MilesAudioSample::set_3d_min_distance() Setting the sound's 3D min distance ( min= " << dist << " ) ");
358 
359  if(_sample != 0) {
360  // Implementation is awkward, since Miles gets and sets min and max distances
361  // in a single operation.
362  float max_dist;
363  int auto_3D_wet_atten;
364  AIL_sample_3D_distances(_sample, &max_dist, NULL, &auto_3D_wet_atten);
365 
366  AIL_set_sample_3D_distances(_sample, max_dist, dist, auto_3D_wet_atten);
367  } else {
368  audio_warning("_sample == 0 in MilesAudioSample::set_3d_min_distance().");
369  }
370 }
371 
372 ////////////////////////////////////////////////////////////////////
373 // Function: MilesAudioSample::get_3d_min_distance
374 // Access: public
375 // Description: Get the distance that this sound begins to fall off.
376 ////////////////////////////////////////////////////////////////////
377 PN_stdfloat MilesAudioSample::get_3d_min_distance() const {
378  audio_debug("MilesAudioSample::get_3d_min_distance() ");
379 
380  if(_sample != 0) {
381  float min_dist;
382  AIL_sample_3D_distances(_sample, NULL, &min_dist, NULL);
383  return (PN_stdfloat)min_dist;
384  } else {
385  audio_warning("_sample == 0 in MilesAudioSample::get_3d_min_distance().");
386  return -1.0;
387  }
388 }
389 
390 ////////////////////////////////////////////////////////////////////
391 // Function: MilesAudioSample::set_3d_max_distance
392 // Access: public
393 // Description: Set the distance at which this sound is clipped to
394 // silence. Note that this value does not affect
395 // the rate at which the sound falls off, but only
396 // the distance at which it gets clipped.
397 ////////////////////////////////////////////////////////////////////
398 void MilesAudioSample::set_3d_max_distance(PN_stdfloat dist) {
399  audio_debug("MilesAudioSample::set_3d_max_distance() Setting the sound's 3D max distance ( max= " << dist << " ) ");
400 
401  if(_sample != 0) {
402  // Implementation is awkward, since Miles gets and sets min and max distances
403  // in a single operation.
404  float min_dist;
405  int auto_3D_wet_atten;
406  AIL_sample_3D_distances(_sample, NULL, &min_dist, &auto_3D_wet_atten);
407 
408  AIL_set_sample_3D_distances(_sample, dist, min_dist, auto_3D_wet_atten);
409  } else {
410  audio_warning("_sample == 0 in MilesAudioSample::set_3d_max_distance().");
411  }
412 }
413 
414 ////////////////////////////////////////////////////////////////////
415 // Function: MilesAudioSample::get_3d_max_distance
416 // Access: public
417 // Description: Get the distance at which this sound is clipped to
418 // silence.
419 ////////////////////////////////////////////////////////////////////
420 PN_stdfloat MilesAudioSample::get_3d_max_distance() const {
421  audio_debug("MilesAudioSample::get_3d_max_distance() ");
422 
423  if(_sample != 0) {
424  float max_dist;
425  AIL_sample_3D_distances(_sample, &max_dist, NULL, NULL);
426  return (PN_stdfloat)max_dist;
427  } else {
428  audio_warning("_sample == 0 in MilesAudioSample::get_3d_max_distance().");
429  return -1.0;
430  }
431 }
432 
433 ////////////////////////////////////////////////////////////////////
434 // Function: MilesAudioSample::get_speaker_level
435 // Access: Published
436 // Description: Get the level of a particular logical channel (speaker).
437 // "index" specifies which speaker in an array of all the
438 // logical channels currently in use to retrieve the level
439 // of.
440 //
441 // For instance, in a standard 4.0 channel setup, speakers
442 // are setup as [frontLeft, frontRight, backLeft, backRight].
443 // Thus, get_speaker_level(2) will retrieve the level of the
444 // backLeft speaker.
445 //
446 // The order in which speakers appear in the array for
447 // standard speaker setups is defined to be:
448 //
449 // FRONT_LEFT
450 // FRONT_RIGHT
451 // FRONT_CENTER
452 // LOW_FREQUENCY (sub woofer)
453 // BACK_LEFT
454 // BACK_RIGHT
455 // FRONT_LEFT_OF_CENTER
456 // FRONT_RIGHT_OF_CENTER
457 // BACK_CENTER
458 // SIDE_LEFT
459 // SIDE_RIGHT
460 // TOP_CENTER
461 // TOP_FRONT_LEFT
462 // TOP_FRONT_CENTER
463 // TOP_FRONT_RIGHT
464 // TOP_BACK_LEFT
465 // TOP_BACK_CENTER
466 // TOP_BACK_RIGHT
467 //
468 ////////////////////////////////////////////////////////////////////
469 PN_stdfloat MilesAudioSample::
470 get_speaker_level(int index) {
471  audio_debug("MilesAudioSample::get_speaker_level(" << index << ")");
472 
473  if(_sample != 0) {
474  int numLevels;
475  float *levels = AIL_sample_channel_levels(_sample, &numLevels);
476 
477  if(index < numLevels) {
478  return (PN_stdfloat)levels[index];
479  } else {
480  audio_error("index out of range in MilesAudioSample::get_speaker_level. numLevels: " << numLevels);
481  return -1.0;
482  }
483  } else {
484  audio_warning("Warning: MilesAudioSample::get_speaker_level only works for sounds that are currently playing");
485  return -1.0;
486  }
487 }
488 
489 ////////////////////////////////////////////////////////////////////
490 // Function: MilesAudioSample::set_speaker_levels
491 // Access: Published
492 // Description: Set the output levels on the logical channels (speakers)
493 // for this sound. Values should be in the range 0.0 to 1.0.
494 // Levels for up to nine channels may be specified. As soon
495 // as a level is reached that falls outside the range 0.0 to
496 // 1.0, the levels specified up to that point will be sent
497 // and all other levels will be ignored.
498 //
499 // The user must know what the current speaker setup is in order
500 // to know which level corresponds to which speaker.
501 //
502 // This method will have no effect if 3D attributes have been
503 // set for this sound.
504 //
505 // The order in which speakers appear in the array for
506 // standard speaker setups is defined to be:
507 //
508 // FRONT_LEFT
509 // FRONT_RIGHT
510 // FRONT_CENTER
511 // LOW_FREQUENCY (sub woofer)
512 // BACK_LEFT
513 // BACK_RIGHT
514 // FRONT_LEFT_OF_CENTER
515 // FRONT_RIGHT_OF_CENTER
516 // BACK_CENTER
517 // SIDE_LEFT
518 // SIDE_RIGHT
519 // TOP_CENTER
520 // TOP_FRONT_LEFT
521 // TOP_FRONT_CENTER
522 // TOP_FRONT_RIGHT
523 // TOP_BACK_LEFT
524 // TOP_BACK_CENTER
525 // TOP_BACK_RIGHT
526 //
527 ////////////////////////////////////////////////////////////////////
528 void MilesAudioSample::
529 set_speaker_levels(PN_stdfloat level1, PN_stdfloat level2, PN_stdfloat level3, PN_stdfloat level4, PN_stdfloat level5, PN_stdfloat level6, PN_stdfloat level7, PN_stdfloat level8, PN_stdfloat level9) {
530  audio_debug("MilesAudioSample::set_speaker_levels()");
531 
532  if(_sample != 0) {
533  float levels[9] = {level1, level2, level3, level4, level5, level6, level7, level8, level9};
534 
535  if((level1 < 0.0) || (level1 > 1.0)) {
536  audio_error("No valid levels specified in MilesAudioSample::set_speaker_levels().");
537  } else if((level2 < 0.0) || (level2 > 1.0)) {
538  AIL_set_sample_channel_levels(_sample, levels, 1);
539  } else if((level3 < 0.0) || (level3 > 1.0)) {
540  AIL_set_sample_channel_levels(_sample, levels, 2);
541  } else if((level4 < 0.0) || (level4 > 1.0)) {
542  AIL_set_sample_channel_levels(_sample, levels, 3);
543  } else if((level5 < 0.0) || (level5 > 1.0)) {
544  AIL_set_sample_channel_levels(_sample, levels, 4);
545  } else if((level6 < 0.0) || (level6 > 1.0)) {
546  AIL_set_sample_channel_levels(_sample, levels, 5);
547  } else if((level7 < 0.0) || (level7 > 1.0)) {
548  AIL_set_sample_channel_levels(_sample, levels, 6);
549  } else if((level8 < 0.0) || (level8 > 1.0)) {
550  AIL_set_sample_channel_levels(_sample, levels, 7);
551  } else if((level9 < 0.0) || (level9 > 1.0)) {
552  AIL_set_sample_channel_levels(_sample, levels, 8);
553  } else {
554  AIL_set_sample_channel_levels(_sample, levels, 9);
555  }
556  } else {
557  audio_warning("Warning: MilesAudioSample::set_speaker_levels only works for sounds that are currently playing");
558  }
559 }
560 
561 ////////////////////////////////////////////////////////////////////
562 // Function: MilesAudioSample::internal_stop
563 // Access: Private
564 // Description: Called by the GlobalMilesManager when it is detected
565 // that this particular sound has already stopped, and
566 // its sample handle will be recycled.
567 ////////////////////////////////////////////////////////////////////
568 void MilesAudioSample::
569 internal_stop() {
570  _sample = 0;
571  _sample_index = 0;
572 }
573 
574 ////////////////////////////////////////////////////////////////////
575 // Function: MilesAudioSample::finish_callback
576 // Access: Private, Static
577 // Description: This callback is made by Miles (possibly in a
578 // sub-thread) when the sample finishes.
579 ////////////////////////////////////////////////////////////////////
580 void AILCALLBACK MilesAudioSample::
581 finish_callback(HSAMPLE sample) {
582  MilesAudioSample *self = (MilesAudioSample *)AIL_sample_user_data(sample, 0);
583  if (milesAudio_cat.is_debug()) {
584  milesAudio_cat.debug()
585  << "finished " << *self << "\n";
586  }
587  if (self->_manager == (MilesAudioManager *)NULL) {
588  return;
589  }
590  self->_manager->_sounds_finished = true;
591 }
592 
593 ////////////////////////////////////////////////////////////////////
594 // Function: MilesAudioSample::do_set_time
595 // Access: Private
596 // Description: Sets the start time of an already allocated sample.
597 ////////////////////////////////////////////////////////////////////
598 void MilesAudioSample::
599 do_set_time(PN_stdfloat time) {
600  miles_audio_debug("do_set_time(time="<<time<<")");
601  nassertv(_sample != 0);
602 
603  // Ensure we don't inadvertently run off the end of the sound.
604  PN_stdfloat max_time = length();
605  if (time > max_time) {
606  milesAudio_cat.warning()
607  << "set_time(" << time << ") requested for sound of length "
608  << max_time << "\n";
609  time = max_time;
610  }
611 
612  S32 time_ms = (S32)(1000.0f * time);
613  AIL_set_sample_ms_position(_sample, time_ms);
614 }
615 
616 #endif //]
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:85