Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

less debug, and music should rewind now

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  {
73    PRINTF(2)("Unable to allocate al-Buffers\n");
74    this->release();
75    return false;
76  }
77  // allocating source
78  if (this->source == 0)
79    SoundEngine::getInstance()->popALSource(this->source);
80  if (this->source != 0)
81    state |= SourceAllocated;
82  else
83  {
84    PRINTF(2)("No more Sources Availiable (maybe you should consider raising the source-count.)\n");
85    this->release();
86    return false;
87  }
88
89  // opening the FILE;
90  int result;
91  if(!(oggFile = fopen(fileName.c_str(), "rb")))
92  {
93    PRINTF(2)("Could not open Ogg file.");
94    this->release();
95    return false;
96  }
97  // reading the Stream.
98  if((result = ov_open(oggFile, &oggStream, NULL, 0)) < 0)
99  {
100    PRINTF(2)("Could not open Ogg stream. %s", errorString(result));
101    fclose(oggFile);
102    this->release();
103    return false;
104  }
105  this->state |= FileOpened;
106
107  // acquiring the vorbis-properties.
108  vorbisInfo = ov_info(&oggStream, -1);
109  vorbisComment = ov_comment(&oggStream, -1);
110
111  if(vorbisInfo->channels == 1)
112    format = AL_FORMAT_MONO16;
113  else
114    format = AL_FORMAT_STEREO16;
115
116  // setting the Source Properties.
117  alSource3f(source, AL_POSITION,        0.0, 0.0, 0.0);
118  alSource3f(source, AL_VELOCITY,        0.0, 0.0, 0.0);
119  alSource3f(source, AL_DIRECTION,       0.0, 0.0, 0.0);
120  alSourcef (source, AL_ROLLOFF_FACTOR,  0.0          );
121  alSourcei (source, AL_SOURCE_RELATIVE, AL_TRUE      );
122  alSourcef (source, AL_GAIN,            SoundEngine::getInstance()->getMusicVolume());
123  SoundEngine::checkError("OggPlayer::open()::SetSourceProperties", __LINE__);
124
125  return true;
126}
127
128/**
129 * @brief releases a stream
130 */
131void OggPlayer::release()
132{
133  if (this->state & SourceAllocated)
134  {
135    assert(alIsSource(this->source));
136    if (this->state & Playing);
137    {
138      alSourceStop(source);
139      SoundEngine::checkError("OggPlayer::release()::alSourceStop", __LINE__);
140      this->state & !Playing;
141    }
142    empty();
143    alSourcei(this->source, AL_BUFFER, 0);
144    SoundEngine::getInstance()->pushALSource(this->source);
145    this->source = 0;
146    this->state &= !SourceAllocated;
147  }
148  if (this->state & BuffersAllocated)
149  {
150    assert (this->buffers[0] != 0 && this->buffers[1] != 0);
151    alDeleteBuffers(2, buffers);
152    SoundEngine::checkError("OggPlayer::release()::alDeleteBuffers", __LINE__);
153    this->buffers[0] = 0;
154    this->buffers[1] = 0;
155    this->state &= !BuffersAllocated;
156  }
157
158  if (this->state & FileOpened)
159  {
160    ov_clear(&oggStream);
161    this->state &= ! FileOpened;
162  }
163}
164
165
166/**
167 * plays back the sound
168 * @return true if running, false otherwise
169 */
170bool OggPlayer::playback()
171{
172  if (!(this->state & FileOpened))
173    return false;
174
175  if(playing())
176    return true;
177  this->state |= Playing;
178
179  if(!this->stream(this->buffers[0]) || !this->stream(this->buffers[1]))
180    return false;
181
182  alSourceQueueBuffers(this->source, 2, this->buffers);
183  if (DEBUG >= 3)
184    SoundEngine::checkError("OggPlayer::playback()::alSourceQueueBuffers", __LINE__);
185  if (!alIsBuffer(this->buffers[0])) printf("AHA0\n");
186  if (!alIsBuffer(this->buffers[1])) printf("AHA1\n");
187
188  if (!alIsSource(this->source)) printf("AHA2\n");
189  SoundEngine::checkError("SKJFLKSDJF",__LINE__);
190
191  alSourcePlay(this->source);
192  if (DEBUG >= 3)
193    SoundEngine::checkError("OggPlayer::playback()::alSourcePlay", __LINE__);
194  return true;
195}
196
197/**
198 *
199 * @returns true if the file is playing
200 */
201bool OggPlayer::playing()
202{
203  if (!(this->state & FileOpened))
204    return false;
205  ALenum state;
206
207  alGetSourcei(this->source, AL_SOURCE_STATE, &state);
208
209  return (state == AL_PLAYING);
210}
211
212/**
213 * updates the stream, this has to be done every few parts of a second, for sound-consistency
214 * @returns true, if the Sound is playing flawlessly
215 */
216bool OggPlayer::update()
217{
218  if (unlikely(!(this->state & Playing)))
219    return false;
220
221  int processed;
222  bool active = true;
223
224  alGetSourcei(source, AL_BUFFERS_PROCESSED, &processed);
225  if (DEBUG >= 3)
226    SoundEngine::checkError("OggPlayer::update()::alGetSourceI", __LINE__);
227
228  while(processed--)
229  {
230    ALuint buffer;
231
232    alSourceUnqueueBuffers(source, 1, &buffer);
233    if (DEBUG >= 3)
234      SoundEngine::checkError("OggPlayer::update()::unqueue", __LINE__);
235
236    active = stream(buffer);
237
238    alSourceQueueBuffers(source, 1, &buffer);
239    if (DEBUG >= 3)
240      SoundEngine::checkError("OggPlayer::update()::queue", __LINE__);
241  }
242
243  return active;
244}
245
246/**
247 * gets a new Stream from buffer
248 * @param buffer the buffer to get the stream from
249 * @return true, if everything worked as planed
250 */
251bool OggPlayer::stream(ALuint buffer)
252{
253  if (unlikely(!(this->state & Playing)))
254    return false;
255  char pcm[OGG_PLAYER_BUFFER_SIZE];
256  int  size = 0;
257  int  section;
258  int  result;
259
260  while(size < OGG_PLAYER_BUFFER_SIZE)
261  {
262    result = ov_read(&this->oggStream, pcm + size, OGG_PLAYER_BUFFER_SIZE - size, 0, 2, 1, &section);
263
264    if(result > 0)
265      size += result;
266    else if(result < 0)
267      throw errorString(result);
268    else /* eof */
269      ov_time_seek(&this->oggStream, 0.0);
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.