FIFE  2008.0
 All Classes Namespaces Functions Variables Enumerations Enumerator Pages
sounddecoder_ogg.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/base/exception.h"
34 
35 #include "sounddecoder_ogg.h"
36 
37 namespace FIFE {
38  static Logger _log(LM_AUDIO);
39 
40  /* OggVorbis Callback functions
41  */
42  namespace OGG_cb {
43  static size_t read(void *ptr, size_t size, size_t nmemb, void *datasource) {
44  RawData* rdp = reinterpret_cast<RawData*>(datasource);
45  size_t restlen = rdp->getDataLength()-rdp->getCurrentIndex();
46  size_t len = (restlen<=size*nmemb)?restlen:size*nmemb;
47  if (len) {
48  rdp->readInto(reinterpret_cast<uint8_t *>(ptr), len);
49  }
50  return len;
51  }
52 
53  static int seek(void *datasource, ogg_int64_t offset, int whence) {
54  RawData* rdp = reinterpret_cast<RawData*>(datasource);
55  switch (whence) {
56  case SEEK_SET:
57  (*rdp).setIndex(offset);
58  return 0;
59  case SEEK_CUR:
60  (*rdp).moveIndex(offset);
61  return 0;
62  case SEEK_END:
63  (*rdp).setIndex( (*rdp).getDataLength() -1 + offset);
64  return 0;
65  }
66  return -1;
67  }
68 
69  static int close(void *datasource) { return 0; }
70 
71  static long tell(void *datasource) {
72  RawData* rdp = reinterpret_cast<RawData*>(datasource);
73  return (*rdp).getCurrentIndex();
74  }
75  }
76 
77  SoundDecoderOgg::SoundDecoderOgg(RawData* rdp) : m_file(rdp) {
78 
79  ov_callbacks ocb = {
80  OGG_cb::read, OGG_cb::seek, OGG_cb::close, OGG_cb::tell
81  };
82 
83  if (0 > ov_open_callbacks(m_file.get(), &m_ovf, 0, 0, ocb)) {
84  throw InvalidFormat("Error opening OggVorbis file");
85  }
86 
87 
88  vorbis_info *vi = ov_info(&m_ovf, -1);
89  if (!vi) {
90  throw InvalidFormat("Error fetching OggVorbis info");
91  }
92 
93  if (!ov_seekable(&m_ovf)) {
94  throw InvalidFormat("OggVorbis file has to be seekable");
95  }
96 
97  m_isstereo = vi->channels == 2;
98  m_samplerate = vi->rate;
99  m_is8bit = false;
100  m_declength = (m_isstereo ? 2 : 1) * 2 * ov_pcm_total(&m_ovf, -1);
101  m_datasize = 0;
102  m_data = NULL;
103  }
104 
105  bool SoundDecoderOgg::decode(unsigned long length) {
106  int stream = 0;
107  int ret = 0;
108 
109  // release buffer and allocate new memory
110  releaseBuffer();
111  m_data = new char[length];
112 
113  // decode the stream
114  m_datasize = 0;
115  do {
116  ret = ov_read(&m_ovf, m_data + m_datasize,
117  length-m_datasize, 0, 2, 1, &stream);
118  if (ret > 0) {
119  m_datasize += ret;
120  }
121 
122  } while (length-m_datasize > 0 && ret > 0);
123 
124  return m_datasize == 0;
125  }
126 
127  bool SoundDecoderOgg::setCursor(unsigned long pos) {
128 
129  if (ov_pcm_seek(&m_ovf, pos / ((m_isstereo ? 2 : 1) * 2)) == 0) {
130  return true;
131  }
132  return false;
133  }
134 }