Panda3D
 All Classes Functions Variables Enumerations
milesAudioSequence.cxx
1 // Filename: milesAudioSequence.cxx
2 // Created by: drose (31Jul07)
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 "milesAudioSequence.h"
16 
17 #ifdef HAVE_RAD_MSS //[
18 
19 #include "milesAudioManager.h"
20 
21 
22 TypeHandle MilesAudioSequence::_type_handle;
23 
24 #undef miles_audio_debug
25 
26 #ifndef NDEBUG //[
27 #define miles_audio_debug(x) \
28  audio_debug("MilesAudioSequence \""<<get_name()<<"\" "<< x )
29 #else //][
30 #define miles_audio_debug(x) ((void)0)
31 #endif //]
32 
33 ////////////////////////////////////////////////////////////////////
34 // Function: MilesAudioSequence::Constructor
35 // Access: Private
36 // Description: This constructor is called only by the
37 // MilesAudioManager.
38 ////////////////////////////////////////////////////////////////////
39 MilesAudioSequence::
40 MilesAudioSequence(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("MilesAudioSequence(manager=0x"<<(void*)&manager
47  <<", sd=0x"<<(void*)sd<<", file_name="<<file_name<<")");
48 
49  _sequence = 0;
50  _sequence_index = 0;
51 }
52 
53 ////////////////////////////////////////////////////////////////////
54 // Function: MilesAudioSequence::Destructor
55 // Access: Public, Virtual
56 // Description:
57 ////////////////////////////////////////////////////////////////////
58 MilesAudioSequence::
59 ~MilesAudioSequence() {
60  miles_audio_debug("~MilesAudioSequence()");
61  cleanup();
62  _manager->release_sound(this);
63  miles_audio_debug("~MilesAudioSequence() done");
64 }
65 
66 ////////////////////////////////////////////////////////////////////
67 // Function: MilesAudioSequence::play
68 // Access: Public, Virtual
69 // Description:
70 ////////////////////////////////////////////////////////////////////
71 void MilesAudioSequence::
72 play() {
73  miles_audio_debug("play()");
74  if (_active) {
75  stop();
76 
77  if (_sd->_raw_data.empty()) {
78  milesAudio_cat.warning()
79  << "Could not play " << _file_name << ": no data\n";
80  } else {
81  _manager->starting_sound(this);
82  nassertv(_sequence == 0);
83 
84  GlobalMilesManager *mgr = GlobalMilesManager::get_global_ptr();
85  if (!mgr->get_sequence(_sequence, _sequence_index, this)){
86  milesAudio_cat.warning()
87  << "Could not play " << _file_name << ": too many open sequences\n";
88  _sequence = 0;
89  } else {
90  AIL_init_sequence(_sequence, &_sd->_raw_data[0], 0);
91  AIL_set_sequence_user_data(_sequence, 0, (SINTa)this);
92  AIL_register_sequence_callback(_sequence, finish_callback);
93 
94  set_volume(_volume);
95  set_play_rate(_play_rate);
96  AIL_set_sequence_loop_count(_sequence, _loop_count);
97 
98  if (_got_start_time) {
99  do_set_time(_start_time);
100  AIL_resume_sequence(_sequence);
101  } else {
102  AIL_start_sequence(_sequence);
103  }
104  }
105 
106  _got_start_time = false;
107  }
108  } else {
109  // In case _loop_count gets set to forever (zero):
110  audio_debug(" paused "<<_file_name );
111  _paused = true;
112  }
113 }
114 
115 ////////////////////////////////////////////////////////////////////
116 // Function: MilesAudioSequence::stop
117 // Access: Public, Virtual
118 // Description:
119 ////////////////////////////////////////////////////////////////////
120 void MilesAudioSequence::
121 stop() {
122  miles_audio_debug("stop()");
123  _manager->stopping_sound(this);
124  // The _paused flag should not be cleared here. _paused is not like
125  // the Pause button on a cd/dvd player. It is used as a flag to say
126  // that it was looping when it was set inactive. There is no need to
127  // make this symmetrical with play(). set_active() is the 'owner' of
128  // _paused. play() accesses _paused to help in the situation where
129  // someone calls play on an inactive sound().
130 
131  if (_sequence != 0) {
132  AIL_end_sequence(_sequence);
133 
134  GlobalMilesManager *mgr = GlobalMilesManager::get_global_ptr();
135  mgr->release_sequence(_sequence_index, this);
136 
137  _sequence = 0;
138  _sequence_index = 0;
139  }
140 }
141 
142 ////////////////////////////////////////////////////////////////////
143 // Function: MilesAudioSequence::get_time
144 // Access: Public, Virtual
145 // Description:
146 ////////////////////////////////////////////////////////////////////
147 PN_stdfloat MilesAudioSequence::
148 get_time() const {
149  if (_sequence == 0) {
150  if (_got_start_time) {
151  return _start_time;
152  }
153  return 0.0f;
154  }
155 
156  S32 current_ms;
157  AIL_sequence_ms_position(_sequence, NULL, &current_ms);
158  PN_stdfloat time = PN_stdfloat(current_ms * 0.001f);
159 
160  return time;
161 }
162 
163 ////////////////////////////////////////////////////////////////////
164 // Function: MilesAudioSequence::set_volume
165 // Access: Public, Virtual
166 // Description:
167 ////////////////////////////////////////////////////////////////////
168 void MilesAudioSequence::
169 set_volume(PN_stdfloat volume) {
170  miles_audio_debug("set_volume(volume="<<volume<<")");
171 
172  // Set the volume even if our volume is not changing, because the
173  // MilesAudioManager will call set_volume() when *its* volume
174  // changes.
175 
176  // Set the volume:
177  _volume = volume;
178 
179  if (_sequence != 0) {
180  volume *= _manager->get_volume();
181 
182  // Change to Miles volume, range 0 to 127:
183  S32 milesVolume = (S32)(volume * 127.0f);
184  milesVolume = min(milesVolume, 127);
185  milesVolume = max(milesVolume, 0);
186 
187  AIL_set_sequence_volume(_sequence, milesVolume, 0);
188  }
189 }
190 
191 ////////////////////////////////////////////////////////////////////
192 // Function: MilesAudioSequence::set_balance
193 // Access: Public, Virtual
194 // Description:
195 ////////////////////////////////////////////////////////////////////
196 void MilesAudioSequence::
197 set_balance(PN_stdfloat balance_right) {
198  miles_audio_debug("set_balance(balance_right="<<balance_right<<")");
199  _balance = balance_right;
200 
201  // Balance has no effect on a MIDI file.
202 }
203 
204 ////////////////////////////////////////////////////////////////////
205 // Function: MilesAudioSequence::set_play_rate
206 // Access: Public, Virtual
207 // Description:
208 ////////////////////////////////////////////////////////////////////
209 void MilesAudioSequence::
210 set_play_rate(PN_stdfloat play_rate) {
211  miles_audio_debug("set_play_rate(play_rate="<<play_rate<<")");
212 
213  // Set the play_rate:
214  _play_rate = play_rate;
215 
216  if (_sequence != 0) {
217  play_rate *= _manager->get_play_rate();
218 
219  S32 percent = (S32)(play_rate * 100.0f);
220  AIL_set_sequence_tempo(_sequence, percent, 0);
221  }
222 }
223 
224 ////////////////////////////////////////////////////////////////////
225 // Function: MilesAudioSequence::length
226 // Access: Public, Virtual
227 // Description:
228 ////////////////////////////////////////////////////////////////////
229 PN_stdfloat MilesAudioSequence::
230 length() const {
231  if (_sequence == 0) {
232  // The MIDI file hasn't been started yet. See if the length is
233  // cached in the SoundData.
234  if (!_sd->_has_length) {
235  // It isn't cached, so load the sequence temporarily to
236  // determine its length.
237  ((MilesAudioSequence *)this)->determine_length();
238  }
239 
240  return _sd->get_length();
241  }
242 
243  // The MIDI file has already been started, so we can ask it
244  // directly.
245  S32 length_ms;
246  AIL_sequence_ms_position(_sequence, &length_ms, NULL);
247  PN_stdfloat time = (PN_stdfloat)length_ms * 0.001f;
248  return time;
249 }
250 
251 ////////////////////////////////////////////////////////////////////
252 // Function: MilesAudioSequence::status
253 // Access: Public, Virtual
254 // Description:
255 ////////////////////////////////////////////////////////////////////
256 AudioSound::SoundStatus MilesAudioSequence::
257 status() const {
258  if (_sequence == 0) {
259  return AudioSound::READY;
260  }
261  switch (AIL_sequence_status(_sequence)) {
262  case SEQ_DONE:
263  case SEQ_STOPPED:
264  case SEQ_FREE:
265  return AudioSound::READY;
266 
267  case SEQ_PLAYING:
268  case SEQ_PLAYINGBUTRELEASED:
269  return AudioSound::PLAYING;
270 
271  default:
272  return AudioSound::BAD;
273  }
274 }
275 
276 ////////////////////////////////////////////////////////////////////
277 // Function: MilesAudioSequence::cleanup
278 // Access: Public, Virtual
279 // Description: Stops the sound from playing and releases any
280 // associated resources, in preparation for releasing
281 // the sound or shutting down the sound system.
282 ////////////////////////////////////////////////////////////////////
283 void MilesAudioSequence::
284 cleanup() {
285  stop();
286 }
287 
288 ////////////////////////////////////////////////////////////////////
289 // Function: MilesAudioSequence::internal_stop
290 // Access: Private
291 // Description: Called by the GlobalMilesManager when it is detected
292 // that this particular sound has already stopped, and
293 // its sequence handle will be recycled.
294 ////////////////////////////////////////////////////////////////////
295 void MilesAudioSequence::
296 internal_stop() {
297  _sequence = 0;
298  _sequence_index = 0;
299 }
300 
301 ////////////////////////////////////////////////////////////////////
302 // Function: MilesAudioSequence::finish_callback
303 // Access: Private, Static
304 // Description: This callback is made by Miles (possibly in a
305 // sub-thread) when the sequence finishes.
306 ////////////////////////////////////////////////////////////////////
307 void AILCALLBACK MilesAudioSequence::
308 finish_callback(HSEQUENCE sequence) {
309  MilesAudioSequence *self = (MilesAudioSequence *)AIL_sequence_user_data(sequence, 0);
310  if (milesAudio_cat.is_debug()) {
311  milesAudio_cat.debug()
312  << "finished " << *self << "\n";
313  }
314  self->_manager->_sounds_finished = true;
315 }
316 
317 ////////////////////////////////////////////////////////////////////
318 // Function: MilesAudioSequence::do_set_time
319 // Access: Private
320 // Description: Sets the start time of an already allocated stream.
321 ////////////////////////////////////////////////////////////////////
322 void MilesAudioSequence::
323 do_set_time(PN_stdfloat time) {
324  miles_audio_debug("do_set_time(time="<<time<<")");
325 
326  nassertv(_sequence != 0);
327 
328  S32 time_ms = (S32)(1000.0f * time);
329 
330  // Ensure we don't inadvertently run off the end of the sound.
331  S32 length_ms;
332  AIL_sequence_ms_position(_sequence, &length_ms, NULL);
333  time_ms = min(time_ms, length_ms);
334 
335  AIL_set_sequence_ms_position(_sequence, time_ms);
336 }
337 
338 
339 ////////////////////////////////////////////////////////////////////
340 // Function: MilesAudioSequence::determine_length
341 // Access: Private
342 // Description: Temporarily loads the sequence to determine its
343 // length. Stores the result on the _sd.
344 ////////////////////////////////////////////////////////////////////
345 void MilesAudioSequence::
346 determine_length() {
347  nassertv(_sequence == 0);
348 
349  GlobalMilesManager *mgr = GlobalMilesManager::get_global_ptr();
350  if (!mgr->get_sequence(_sequence, _sequence_index, this)){
351  milesAudio_cat.warning()
352  << "Could not determine length of " << _file_name << ": too many open sequences\n";
353  _sequence = 0;
354  } else {
355  AIL_init_sequence(_sequence, &_sd->_raw_data[0], 0);
356  S32 length_ms;
357  AIL_sequence_ms_position(_sequence, &length_ms, NULL);
358  PN_stdfloat time = (PN_stdfloat)length_ms * 0.001f;
359  mgr->release_sequence(_sequence_index, this);
360  _sequence = 0;
361  _sequence_index = 0;
362 
363  _sd->set_length(time);
364  }
365 }
366 
367 #endif //]
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:85