FIFE  6e1afdbeda11afe9ac53e6023a4be96ef88f1dc6
soundclip.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * Copyright (C) 2005-2017 by the FIFE team *
3  * http://www.fifengine.net *
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 #include <sstream>
26 
27 // 3rd party library includes
28 
29 // FIFE includes
30 // These includes are split up in two parts, separated by one empty line
31 // First block: files included from the FIFE root src directory
32 // Second block: files included from the same folder
33 #include "util/base/exception.h"
34 #include "util/log/logger.h"
36 
37 #include "soundclip.h"
38 
39 namespace FIFE {
40  static Logger _log(LM_AUDIO);
41 
43  IResource(createUniqueClipName(), loader),
44  m_isStream(false),
45  m_decoder(NULL),
46  m_deleteDecoder(false) {
47 
48  }
49 
50  SoundClip::SoundClip(const std::string& name, IResourceLoader* loader) :
51  IResource(name, loader),
52  m_isStream(false),
53  m_decoder(NULL),
54  m_deleteDecoder(false) {
55 
56  }
57 
59  free();
60 
61  // delete decoder
62  if (m_deleteDecoder && m_decoder != NULL) {
63  delete m_decoder;
64  }
65  }
66 
68  if (m_loader){
69  m_loader->load(this);
70  }
71  else { //no loader specified so find one to use
72  if(m_name.find(".ogg", m_name.size() - 4) != std::string::npos) {
73  OggLoader loader;
74  loader.load(this);
75  } else {
76  FL_WARN(_log, LMsg() << "No audio-decoder available for file \"" << m_name << "\"!");
77  throw InvalidFormat("Error: Ogg loader can't load files without ogg extension");
78  }
79  }
80 
81  assert(m_decoder); //should be set by now
82 
84 
85  if (!m_isStream) {
86  // only for non-streaming buffers
88 
89  // iterate the bufs and fill them with data
90  for (int32_t i = 0; i < BUFFER_NUM; i++) {
91 
92  if (m_decoder->decode(BUFFER_LEN)) {
93  // EOF or error
94  break;
95  }
96 
97  // generate buffer and fill it with data
98  alGenBuffers(1, &ptr->buffers[i]);
99 
100  alBufferData(ptr->buffers[i], m_decoder->getALFormat(), m_decoder->getBuffer(),
102 
103  CHECK_OPENAL_LOG(_log, LogManager::LEVEL_ERROR, "error copying data to buffers")
104 
105  ptr->usedbufs++;
106  }
107 
109 
110  // push the buffer information to the vector
111  m_buffervec.push_back(ptr);
112 
113  }
114 
116  }
117 
120  if (m_isStream) {
121  // erase all elements from the list
122  std::vector<SoundBufferEntry*>::iterator it;
123  for (it = m_buffervec.begin(); it != m_buffervec.end(); ++it) {
124  if ((*it) && (*it)->buffers[0] != 0) {
125  alDeleteBuffers(BUFFER_NUM, (*it)->buffers);
126  }
127  delete (*it);
128  }
129  } else {
130  // for non-streaming soundclips
131  SoundBufferEntry* ptr = m_buffervec.at(0);
132  for(uint32_t i = 0; i < ptr->usedbufs; i++) {
133  alDeleteBuffers(1, &ptr->buffers[i]);
134  }
135  delete ptr;
136  }
137  m_buffervec.clear();
138  }
140  }
141 
142  bool SoundClip::isStream() const {
143  return m_isStream;
144  }
145 
147  return m_buffervec.at(0)->usedbufs;
148  }
149 
150  ALuint* SoundClip::getBuffers(uint32_t streamid) const {
151  return m_buffervec.at(streamid)->buffers;
152  }
153 
155  SoundBufferEntry* ptr = NULL;
156  uint32_t id = 0;
157  for (uint32_t i = 0; i < m_buffervec.size(); i++) {
158  if (m_buffervec.at(i) == NULL) {
159  ptr = new SoundBufferEntry();
160  m_buffervec.at(i) = ptr;
161  id = i;
162  break;
163  }
164  }
165  // create new sound buffer entry
166  if (!ptr) {
167  ptr = new SoundBufferEntry();
168  m_buffervec.push_back(ptr);
169  id = m_buffervec.size() -1 ;
170  }
171 
172  ptr->usedbufs=0;
173  ptr->deccursor = 0;
174  alGenBuffers(BUFFER_NUM, ptr->buffers);
175 
176  CHECK_OPENAL_LOG(_log, LogManager::LEVEL_ERROR, "error creating streaming-buffers")
177 
178  return id;
179  }
180 
181  bool SoundClip::setStreamPos(uint32_t streamid, SoundPositionType type, float value) {
182  uint64_t pos = 0;
183  // convert position to bytes
184  switch (type) {
185  case SD_BYTE_POS:
186  pos = static_cast<uint64_t>(value);
187  break;
188  case SD_TIME_POS:
189  value /= static_cast<float>(m_decoder->getSampleRate());
190  case SD_SAMPLE_POS:
191  pos = static_cast<uint64_t>((m_decoder->getBitResolution() / 8) * (m_decoder->isStereo() ? 2 : 1) * value);
192  break;
193  }
194 
195  if (pos > m_decoder->getDecodedLength()) {
196  // EOF!
197  m_buffervec.at(streamid)->deccursor = m_decoder->getDecodedLength();
198  return true;
199  }
200 
201  // set cursor position
202  m_buffervec.at(streamid)->deccursor = pos;
203  return false;
204  }
205 
207  uint64_t pos = m_buffervec.at(streamid)->deccursor;
208  switch(type) {
209  case SD_BYTE_POS:
210  return pos;
211  case SD_SAMPLE_POS:
212  return pos / (m_decoder->getBitResolution() / 8 * (m_decoder->isStereo() ? 2 : 1));
213  case SD_TIME_POS:
214  return pos / (m_decoder->getBitResolution() / 8 * (m_decoder->isStereo() ? 2 : 1) * m_decoder->getSampleRate());
215  }
216  return 0.0f;
217  }
218 
220  SoundBufferEntry* ptr = m_buffervec.at(streamid);
221  for (int32_t i = 0; i < BUFFER_NUM; i++) {
222  if (getStream(streamid, ptr->buffers[i])) {
223  break;
224  }
225  }
226  }
227 
228  bool SoundClip::getStream(uint32_t streamid, ALuint buffer) {
229  SoundBufferEntry* ptr = m_buffervec.at(streamid);
230 
231  if (ptr->deccursor >= m_decoder->getDecodedLength()) {
232  // EOF!
233  return true;
234  }
235 
236  // set cursor of decoder
237  if (!m_decoder->setCursor(ptr->deccursor)) {
238  return true;
239  }
240 
241  // Error while decoding file?
242  if (m_decoder->decode(BUFFER_LEN)) {
243  throw Exception("error while reading from audio file");
244  }
245 
246  // fill the buffer with data
247  alBufferData(buffer, m_decoder->getALFormat(),
249 
250  // update cursor
251  ptr->deccursor += m_decoder->getBufferSize();
252 
254 
255  CHECK_OPENAL_LOG(_log, LogManager::LEVEL_ERROR, "error catching stream")
256 
257  return false;
258  }
259 
261  // release the buffers
262  SoundBufferEntry* ptr = m_buffervec.at(streamid);
263  alDeleteBuffers(BUFFER_NUM, ptr->buffers);
264  ptr->buffers[0] = 0;
265  }
266 
268  SoundBufferEntry** ptr = &m_buffervec.at(streamid);
269  delete *ptr;
270  *ptr = NULL;
271  }
272 
274  m_decoder = decoder;
275  m_deleteDecoder = true;
276  }
277 
279  m_decoder = decoder;
280  m_deleteDecoder = false;
281  }
282 
284  return m_decoder;
285  }
286 
288  return 0;
289  }
290 
292  // automated counting for name generation, in case the user doesn't provide a name
293  static uint32_t uniqueNumber = 0;
294  static std::string baseName = "soundclip";
295 
296  std::ostringstream oss;
297  oss << uniqueNumber << "_" << baseName;
298 
299  const std::string name = oss.str();
300  ++uniqueNumber;
301 
302  return name;
303  }
304 }
#define FL_WARN(logger, msg)
Definition: logger.h:72
const uint32_t BUFFER_LEN
Definition: soundconfig.h:193
bool getStream(uint32_t streamid, ALuint buffer)
Refill a processed buffer with new data.
Definition: soundclip.cpp:228
void endStreaming(uint32_t streamid)
Ends streaming, invalidate also the stream id.
Definition: soundclip.cpp:267
bool m_deleteDecoder
Definition: soundclip.h:143
ALuint buffers[BUFFER_NUM]
Definition: soundclip.h:51
Helper class to create log strings out from separate parts Usage: LMsg("some text") << variable << "...
Definition: logger.h:82
virtual size_t getSize()
Definition: soundclip.cpp:287
virtual void releaseBuffer()=0
Releases the buffer returned by getBuffer()
bool isStereo() const
Tests if the audio data is stereo data or mono.
Definition: sounddecoder.h:92
IResourceLoader * m_loader
Definition: resource.h:80
static Logger _log(LM_AUDIO)
#define CHECK_OPENAL_LOG(logger, level, msg)
Definition: fife_openal.h:49
bool isStream() const
Does this SoundClip require a streaming mechanism?
Definition: soundclip.cpp:142
virtual uint64_t getBufferSize()=0
Returns the byte-size of the buffer returned by getBuffer().
virtual void load()
Definition: soundclip.cpp:67
Exception base class.
Definition: exception.h:43
virtual void * getBuffer() const =0
Returns the next decoded buffer.
void adobtDecoder(SoundDecoder *decoder)
Adopts a decoder to use so DONT delete it.
Definition: soundclip.cpp:273
virtual bool decode(uint64_t length)=0
Request the decoding of the next part of the stream.
virtual void free()
Definition: soundclip.cpp:118
bool needsStreaming() const
A stream or not?
Definition: sounddecoder.h:59
void acquireStream(uint32_t streamid)
Fills the streaming-buffers with initial data.
Definition: soundclip.cpp:219
ALuint * getBuffers(uint32_t streamid=0) const
Returns the array of buffers for queuing.
Definition: soundclip.cpp:150
SoundPositionType
Different types of audio-file positions.
Definition: soundclip.h:44
uint32_t usedbufs
Definition: soundclip.h:52
virtual uint64_t getDecodedLength() const =0
Returns the decoded length of the file in bytes.
std::string createUniqueClipName()
Definition: soundclip.cpp:291
int16_t getBitResolution() const
Returns the bit resolution.
Definition: sounddecoder.h:108
std::string m_name
Definition: resource.h:79
Definition: soundclip.h:50
float getStreamPos(uint32_t streamid, SoundPositionType type) const
Gets the stream position.
Definition: soundclip.cpp:206
ResourceState m_state
Definition: resource.h:81
virtual bool setCursor(uint64_t pos)=0
Sets the current position in the file (in bytes)
uint64_t getSampleRate() const
Returns the sample rate.
Definition: sounddecoder.h:114
std::vector< SoundBufferEntry * > m_buffervec
Definition: soundclip.h:144
void setDecoder(SoundDecoder *decoder)
Sets the decoder to use so DONT delete it before this SoundClip is done with it.
Definition: soundclip.cpp:278
void quitStreaming(uint32_t streamid)
Quits Streaming.
Definition: soundclip.cpp:260
uint64_t deccursor
Definition: soundclip.h:53
SoundDecoder * getDecoder() const
Returns the attached decoder.
Definition: soundclip.cpp:283
virtual void load(IResource *res)
Definition: ogg_loader.cpp:43
SoundClip(IResourceLoader *loader=0)
Definition: soundclip.cpp:42
uint32_t countBuffers() const
Returns the number of buffers used by the SoundClip (only for non-streaming sound clips) ...
Definition: soundclip.cpp:146
virtual void load(IResource *resource)=0
const int16_t BUFFER_NUM
Definition: soundconfig.h:190
unsigned int uint32_t
Definition: core.h:40
SoundDecoder * m_decoder
Definition: soundclip.h:141
bool setStreamPos(uint32_t streamid, SoundPositionType type, float value)
Sets the stream position.
Definition: soundclip.cpp:181
uint32_t beginStreaming()
Starts streaming the soundclip.
Definition: soundclip.cpp:154
ALenum getALFormat() const
Returns the openAL-Format of the audio file.
Definition: sounddecoder.h:98