FIFE  2008.0
 All Classes Namespaces Functions Variables Enumerations Enumerator Pages
soundemitter.cpp
1 /***************************************************************************
2  * Copyright (C) 2005-2008 by the FIFE team *
3  * http://www.fifengine.de *
4  * This file is part of FIFE. *
5  * *
6  * FIFE is free software; you can redistribute it and/or *
7  * modify it under the terms of the GNU Lesser General Public *
8  * License as published by the Free Software Foundation; either *
9  * version 2.1 of the License, or (at your option) any later version. *
10  * *
11  * This library is distributed in the hope that it will be useful, *
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
14  * Lesser General Public License for more details. *
15  * *
16  * You should have received a copy of the GNU Lesser General Public *
17  * License along with this library; if not, write to the *
18  * Free Software Foundation, Inc., *
19  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
20  ***************************************************************************/
21 
22 // Standard C++ library includes
23 
24 // Platform specific includes
25 
26 // 3rd party library includes
27 
28 // FIFE includes
29 // These includes are split up in two parts, separated by one empty line
30 // First block: files included from the FIFE root src directory
31 // Second block: files included from the same folder
32 #include "util/log/logger.h"
33 #include "util/time/timemanager.h"
34 #include "util/base/exception.h"
35 #include "soundemitter.h"
36 #include "soundmanager.h"
37 #include "soundclipmanager.h"
38 
39 namespace FIFE {
40  static Logger _log(LM_AUDIO);
41 
42  SoundEmitter::SoundEmitter(SoundManager* manager, uint32_t uid) : m_manager(manager), m_source(0), m_soundclip(), m_soundclipid(0), m_streamid(0),
43  m_emitterid(uid), m_loop(false) {
44  if (!m_manager->isActive()) {
45  return;
46  }
47 
48  TimeManager::instance()->registerEvent(this);
49  setPeriod(-1);
50  alGenSources(1, &m_source);
51  CHECK_OPENAL_LOG(_log, LogManager::LEVEL_ERROR, "error creating source")
52  }
53 
54  SoundEmitter::~SoundEmitter() {
55  if (!m_manager->isActive()) {
56  return;
57  }
58 
59  setPeriod(-1);
60  TimeManager::instance()->unregisterEvent(this);
61  reset();
62  alDeleteSources(1, &m_source);
63  }
64 
65  void SoundEmitter::reset(bool defaultall) {
66  if (m_soundclip) {
67 
68  setPeriod(-1);
69  alSourceStop(m_source);
70 
71  // Release all buffers
72  alSourcei(m_source, AL_BUFFER, AL_NONE);
73  alGetError();
74 
75  if (m_soundclip->isStream()) {
76  m_soundclip->quitStreaming(m_streamid);
77  }
78 
79  // release the soundclip
80  //SoundClipManager::instance()->free(m_soundclipid);
81  m_soundclip.reset();
82 
83  // default source properties
84  if (defaultall) {
85  setPosition(0.0f, 0.0f, 0.0f);
86  setVelocity(0.0f, 0.0f, 0.0f);
87  setGain(1.0f);
88  setPositioning(false);
89  alSourcei(m_source, AL_LOOPING, AL_FALSE);
90  }
91  }
92  }
93 
95  m_manager->releaseEmitter(m_emitterid);
96  }
97 
99  m_soundclipid = soundclip->getHandle();
100  m_soundclip = soundclip;
101 
102  attachSoundClip();
103  }
104 
105  void SoundEmitter::setCallback(const type_callback& cb) {
106  m_callback = cb;
107  }
108 
109  void SoundEmitter::attachSoundClip() {
110  if (!m_soundclip->isStream()) {
111  // non-streaming
112  alSourceQueueBuffers(m_source, m_soundclip->countBuffers(), m_soundclip->getBuffers());
113  alSourcei(m_source, AL_LOOPING, m_loop ? AL_TRUE : AL_FALSE);
114 
115  } else {
116  // streaming
117  m_streamid = m_soundclip->beginStreaming();
118  m_soundclip->acquireStream(m_streamid);
119 
120  // queue initial buffers
121  alSourceQueueBuffers(m_source, BUFFER_NUM, m_soundclip->getBuffers(m_streamid));
122  alSourcei(m_source, AL_LOOPING, AL_FALSE);
123  }
124 
125  CHECK_OPENAL_LOG(_log, LogManager::LEVEL_ERROR, "error attaching sound clip")
126  }
127 
128  void SoundEmitter::updateEvent(uint32_t time) {
129  ALint procs;
130  ALint bufs;
131  ALuint buffer;
132 
133  alGetSourcei(m_source, AL_BUFFERS_PROCESSED, &procs);
134 
135  while (procs--) {
136  alSourceUnqueueBuffers(m_source, 1, &buffer);
137 
138  if (m_soundclip->getStream(m_streamid, buffer)) {
139  // EOF!
140  if (m_loop) {
141  // play again from the beginning
142  m_soundclip->setStreamPos(m_streamid, SD_BYTE_POS, 0);
143  m_soundclip->getStream(m_streamid, buffer);
144  } else {
145 
146  // check if the playback has been finished
147  alGetSourcei(m_source, AL_BUFFERS_QUEUED, &bufs);
148  if (bufs == 0) {
149  setPeriod(-1);
150  alSourceStop(m_source);
151  if(m_callback) {
152  m_callback();
153  }
154  }
155  continue;
156  }
157  }
158  alSourceQueueBuffers(m_source, 1, &buffer);
159  }
160 
161  CHECK_OPENAL_LOG(_log, LogManager::LEVEL_ERROR, "error while streaming")
162  }
163 
164  void SoundEmitter::setLooping(bool loop) {
165  if (m_soundclip) {
166  if (!m_soundclip->isStream()) {
167  alSourcei(m_source, AL_LOOPING, loop ? AL_TRUE : AL_FALSE);
168  } else {
169  alSourcei(m_source, AL_LOOPING, AL_FALSE);
170  }
171  }
172  m_loop = loop;
173  }
174 
176  if (m_soundclip) {
177  alSourcePlay(m_source);
178  if (m_soundclip->isStream()) {
179  setPeriod(5000);
180  }
181  }
182  }
183 
185  if (m_soundclip) {
186  alSourceStop(m_source);
187 
188  if (m_soundclip->isStream()) {
189  setPeriod(-1);
190  setCursor(SD_BYTE_POS, 0);
191  } else {
192  alSourceRewind(m_source);
193  }
194  }
195  }
196 
197  void SoundEmitter::setCursor(SoundPositionType type, float value) {
198  if (!m_soundclip) {
199  return;
200  }
201 
202  ALint state = 0;
203 
204  if (!m_soundclip->isStream()) {
205  switch(type) {
206  case SD_BYTE_POS:
207  alSourcef(m_source, AL_BYTE_OFFSET, value);
208  break;
209  case SD_SAMPLE_POS:
210  alSourcef(m_source, AL_SAMPLE_OFFSET, value);
211  break;
212  case SD_TIME_POS:
213  alSourcef(m_source, AL_SEC_OFFSET, value);
214  break;
215  }
216 
217  CHECK_OPENAL_LOG(_log, LogManager::LEVEL_ERROR, "error setting cursor position")
218  }
219  else {
220  alGetSourcei(m_source, AL_SOURCE_STATE, &state);
221 
222  if (state == AL_PLAYING || AL_PAUSED) {
223  setPeriod(-1);
224  alSourceStop(m_source);
225  }
226 
227  m_soundclip->setStreamPos(m_streamid, type, value);
228 
229  // detach all buffers
230  alSourcei(m_source, AL_BUFFER, 0);
231 
232  // queue the buffers with new data
233  m_soundclip->acquireStream(m_streamid);
234  alSourceQueueBuffers(m_source, BUFFER_NUM, m_soundclip->getBuffers(m_streamid));
235 
236  if (state == AL_PLAYING) {
237  setPeriod(5000);
238  alSourcePlay(m_source);
239  }
240 
241  CHECK_OPENAL_LOG(_log, LogManager::LEVEL_ERROR, "error setting stream cursor position")
242  }
243  }
244 
246  if (!m_soundclip) {
247  return 0.0f;
248  }
249 
250  ALfloat pos = 0.0f;
251 
252  switch(type) {
253  case SD_BYTE_POS:
254  alGetSourcef(m_source, AL_BYTE_OFFSET, &pos);
255  break;
256  case SD_SAMPLE_POS:
257  alGetSourcef(m_source, AL_SAMPLE_OFFSET, &pos);
258  break;
259  case SD_TIME_POS:
260  alGetSourcef(m_source, AL_SEC_OFFSET, &pos);
261  break;
262  }
263 
264  if (m_soundclip->isStream()) {
265  pos += m_soundclip->getStreamPos(m_streamid, type);
266  }
267 
268  CHECK_OPENAL_LOG(_log, LogManager::LEVEL_ERROR, "error getting cursor")
269 
270  return pos;
271  }
272 }