Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/trunk/src/lib/sound/ogg_player.cc @ 7297

Last change on this file since 7297 was 7297, checked in by bensch, 18 years ago

orxonox/trunk: now the sound gets correcty detached from the source, when a SoundSource releses its alSource

File size: 9.0 KB
Line 
1/*
2   orxonox - the future of 3D-vertical-scrollers
3
4   Copyright (C) 2004 orx
5
6   This program is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 2, or (at your option)
9   any later version.
10
11### File Specific:
12   main-programmer: Benjamin Grauer
13   co-programmer: ...
14
15
16   -------------------------------------------------------------------
17   The source of this file comes stright from http://www.devmaster.net
18   Thanks a lot for the nice work, and the easy portability to our Project.
19*/
20
21#include <iostream>
22
23#include "ogg_player.h"
24
25#include "sound_engine.h"
26
27#include "debug.h"
28
29/**
30 * initializes an Ogg-player from a file
31 * @param fileName the file to load
32 */
33OggPlayer::OggPlayer(const std::string& fileName)
34{
35  this->setClassID(CL_SOUND_OGG_PLAYER, "OggPlayer");
36
37  this->state = None;
38
39  this->source = 0;
40  this->buffers[0] = 0;
41  this->buffers[1] = 0;
42
43  if (!fileName.empty())
44  {
45    if (this->open(fileName))
46      this->setName(fileName);
47  }
48}
49
50OggPlayer::~OggPlayer()
51{
52  this->release();
53}
54
55/**
56 * opens a file for playback
57 * @param fileName the file to open
58 */
59bool OggPlayer::open(const std::string& fileName)
60{
61  // release old Ogg-File
62  if (this->state & FileOpened)
63    this->release();
64
65  // allocating Buffers
66  if (this->buffers[0] == 0)
67    alGenBuffers(2, this->buffers);
68  SoundEngine::checkError("Allocating Buffers", __LINE__);
69  if (this->buffers[0] != 0 && this->buffers[1] != 0)
70    state |= BuffersAllocated;
71  else  {
72    PRINTF(2)("Unable to allocate al-Buffers\n");
73    this->release();
74    return false;
75  }
76  // allocating source
77  if (this->source == 0)
78    SoundEngine::getInstance()->popALSource(this->source);
79  if (this->source != 0)
80    state |= SourceAllocated;
81  else
82  {
83    PRINTF(2)("No more Sources Availiable (maybe you should consider raising the source-count.)\n");
84    this->release();
85    return false;
86  }
87
88  // opening the FILE;
89  int result;
90  if(!(oggFile = fopen(fileName.c_str(), "rb")))
91  {
92    PRINTF(2)("Could not open Ogg file.");
93    this->release();
94    return false;
95  }
96  // reading the Stream.
97  if((result = ov_open(oggFile, &oggStream, NULL, 0)) < 0)
98  {
99    PRINTF(2)("Could not open Ogg stream. %s", errorString(result));
100    fclose(oggFile);
101    this->release();
102    return false;
103  }
104
105  // acquiring the vorbis-properties.
106  vorbisInfo = ov_info(&oggStream, -1);
107  vorbisComment = ov_comment(&oggStream, -1);
108  this->state |= FileOpened;
109  if(vorbisInfo->channels == 1)
110    format = AL_FORMAT_MONO16;
111  else
112    format = AL_FORMAT_STEREO16;
113
114  // setting the Source Properties.
115  alSource3f(source, AL_POSITION,        0.0, 0.0, 0.0);
116  alSource3f(source, AL_VELOCITY,        0.0, 0.0, 0.0);
117  alSource3f(source, AL_DIRECTION,       0.0, 0.0, 0.0);
118  alSourcef (source, AL_ROLLOFF_FACTOR,  0.0          );
119  alSourcei (source, AL_SOURCE_RELATIVE, AL_TRUE      );
120  alSourcef (source, AL_GAIN,            SoundEngine::getInstance()->getMusicVolume());
121  SoundEngine::checkError("OggPlayer::open()::SetSourceProperties", __LINE__);
122
123  return true;
124}
125
126/**
127 * @brief releases a stream
128 */
129void OggPlayer::release()
130{
131  this->printState();
132  if (this->state & SourceAllocated)
133  {
134    assert(alIsSource(this->source));
135    if (this->state & Playing);
136    {
137      alSourceStop(source);
138      SoundEngine::checkError("OggPlayer::release()::alSourceStop", __LINE__);
139      this->state & !Playing;
140    }
141    empty();
142    alSourcei(this->source, AL_BUFFER, 0);
143    SoundEngine::getInstance()->pushALSource(this->source);
144    this->source = 0;
145    this->state &= !SourceAllocated;
146  }
147  if (this->state & BuffersAllocated)
148  {
149    assert (this->buffers[0] != 0 && this->buffers[1] != 0);
150    alDeleteBuffers(2, buffers);
151    SoundEngine::checkError("OggPlayer::release()::alDeleteBuffers", __LINE__);
152    this->buffers[0] = 0;
153    this->buffers[1] = 0;
154    this->state &= !BuffersAllocated;
155  }
156
157  if (this->state & FileOpened)
158  {
159    ov_clear(&oggStream);
160    this->state &= ! FileOpened;
161  }
162}
163
164
165/**
166 * plays back the sound
167 * @return true if running, false otherwise
168 */
169bool OggPlayer::playback()
170{
171  if (!(this->state & FileOpened))
172    return false;
173
174  if(playing())
175    return true;
176  this->state |= Playing;
177
178  if(!this->stream(this->buffers[0]) || !this->stream(this->buffers[1]))
179    return false;
180
181  alSourceQueueBuffers(this->source, 2, this->buffers);
182  if (DEBUG >= 3)
183    SoundEngine::checkError("OggPlayer::playback()::alSourceQueueBuffers", __LINE__);
184  if (!alIsBuffer(this->buffers[0])) printf("AHA0\n");
185  if (!alIsBuffer(this->buffers[1])) printf("AHA1\n");
186
187  if (!alIsSource(this->source)) printf("AHA2\n");
188  SoundEngine::checkError("SKJFLKSDJF",__LINE__);
189
190  alSourcePlay(this->source);
191  if (DEBUG >= 3)
192    SoundEngine::checkError("OggPlayer::playback()::alSourcePlay", __LINE__);
193  return true;
194}
195
196/**
197 *
198 * @returns true if the file is playing
199 */
200bool OggPlayer::playing()
201{
202  if (!(this->state & FileOpened))
203    return false;
204  ALenum state;
205
206  alGetSourcei(this->source, AL_SOURCE_STATE, &state);
207
208  return (state == AL_PLAYING);
209}
210
211/**
212 * updates the stream, this has to be done every few parts of a second, for sound-consistency
213 * @returns true, if the Sound is playing flawlessly
214 */
215bool OggPlayer::update()
216{
217  if (unlikely(!(this->state & Playing)))
218    return false;
219
220  int processed;
221  bool active = true;
222
223  alGetSourcei(source, AL_BUFFERS_PROCESSED, &processed);
224  if (DEBUG >= 3)
225    SoundEngine::checkError("OggPlayer::update()::alGetSourceI", __LINE__);
226
227  while(processed--)
228  {
229    ALuint buffer;
230
231    alSourceUnqueueBuffers(source, 1, &buffer);
232    if (DEBUG >= 3)
233      SoundEngine::checkError("OggPlayer::update()::unqueue", __LINE__);
234
235    active = stream(buffer);
236
237    alSourceQueueBuffers(source, 1, &buffer);
238    if (DEBUG >= 3)
239      SoundEngine::checkError("OggPlayer::update()::queue", __LINE__);
240  }
241
242  return active;
243}
244
245/**
246 * gets a new Stream from buffer
247 * @param buffer the buffer to get the stream from
248 * @return true, if everything worked as planed
249 */
250bool OggPlayer::stream(ALuint buffer)
251{
252  if (unlikely(!(this->state & Playing)))
253    return false;
254  char pcm[BUFFER_SIZE];
255  int  size = 0;
256  int  section;
257  int  result;
258
259  while(size < BUFFER_SIZE)
260  {
261    result = ov_read(&oggStream, pcm + size, BUFFER_SIZE - size, 0, 2, 1, &section);
262
263    if(result > 0)
264      size += result;
265    else
266      if(result < 0)
267        throw errorString(result);
268      else
269        break;
270  }
271
272  if(size == 0)
273    return false;
274
275  alBufferData(buffer, format, pcm, size, vorbisInfo->rate);
276  if (DEBUG >= 3)
277    SoundEngine::checkError("OggPlayer::stream()::BUFFER", __LINE__);
278
279  return true;
280}
281
282
283/**
284 * empties the buffers
285 */
286void OggPlayer::empty()
287{
288  int queued;
289
290  alGetSourcei(source, AL_BUFFERS_QUEUED, &queued);
291
292  while(queued--)
293  {
294    ALuint buffer;
295
296    alSourceUnqueueBuffers(source, 1, &buffer);
297    SoundEngine::checkError("OggPlayer::empty()::unqueue Buffers", __LINE__);
298  }
299}
300
301
302/**
303 * displays some info about the ogg-file
304 */
305void OggPlayer::debug()
306{
307  cout
308  << "version         " << vorbisInfo->version         << "\n"
309  << "channels        " << vorbisInfo->channels        << "\n"
310  << "rate (hz)       " << vorbisInfo->rate            << "\n"
311  << "bitrate upper   " << vorbisInfo->bitrate_upper   << "\n"
312  << "bitrate nominal " << vorbisInfo->bitrate_nominal << "\n"
313  << "bitrate lower   " << vorbisInfo->bitrate_lower   << "\n"
314  << "bitrate window  " << vorbisInfo->bitrate_window  << "\n"
315  << "\n"
316  << "vendor " << vorbisComment->vendor << "\n";
317
318  for(int i = 0; i < vorbisComment->comments; i++)
319    cout << "   " << vorbisComment->user_comments[i] << "\n";
320
321  cout << endl;
322}
323
324
325void OggPlayer::printState()
326{
327  PRINTF(0)("OggPlayer is in the following States: ");
328  if (this->state & FileOpened)
329      PRINT(0)("FileOpened ");
330  if (this->state & SourceAllocated)
331    PRINT(0)("SourceAllocated ");
332  if (this->state & BuffersAllocated)
333    PRINT(0)("BuffersAllocated ");
334  if (this->state & Stopped)
335    PRINT(0)("Stopped ");
336  if (this->state & Playing)
337    PRINT(0)("Playing ");
338  if (this->state & Paused)
339    PRINT(0)("Paused ");
340  if (this->state & Error)
341    PRINT(0)("Error ");
342  PRINT(0)("\n");
343}
344
345/**
346 * returns errors
347 * @param code the error-code
348 * @return the error as a String
349 */
350const char* OggPlayer::errorString(int code)
351{
352  switch(code)
353  {
354    case OV_EREAD:
355      return ("Read from media.");
356    case OV_ENOTVORBIS:
357      return ("Not Vorbis data.");
358    case OV_EVERSION:
359      return ("Vorbis version mismatch.");
360    case OV_EBADHEADER:
361      return ("Invalid Vorbis header.");
362    case OV_EFAULT:
363      return ("Internal logic fault (bug or heap/stack corruption.");
364    default:
365      return ("Unknown Ogg error.");
366  }
367}
368
Note: See TracBrowser for help on using the repository browser.