Panda3D
 All Classes Functions Variables Enumerations
vorbisAudioCursor.cxx
1 // Filename: vorbisAudioCursor.cxx
2 // Created by: rdb (23Aug13)
3 //
4 ////////////////////////////////////////////////////////////////////
5 //
6 // PANDA 3D SOFTWARE
7 // Copyright (c) Carnegie Mellon University. All rights reserved.
8 //
9 // All use of this software is subject to the terms of the revised BSD
10 // license. You should have received a copy of this license along
11 // with this source code in a file named "LICENSE."
12 //
13 ////////////////////////////////////////////////////////////////////
14 
15 #include "vorbisAudioCursor.h"
16 #include "virtualFileSystem.h"
17 
18 #ifdef HAVE_VORBIS
19 
20 TypeHandle VorbisAudioCursor::_type_handle;
21 
22 ////////////////////////////////////////////////////////////////////
23 // Function: VorbisAudioCursor::Constructor
24 // Access: Protected
25 // Description: Reads the .wav header from the indicated stream.
26 // This leaves the read pointer positioned at the
27 // start of the data.
28 ////////////////////////////////////////////////////////////////////
29 VorbisAudioCursor::
30 VorbisAudioCursor(VorbisAudio *src, istream *stream) :
31  MovieAudioCursor(src),
32  _is_valid(false),
33  _bitstream(0)
34 {
35  nassertv(stream != NULL);
36  nassertv(stream->good());
37 
38  // Set up the callbacks to read via the VFS.
39  ov_callbacks callbacks;
40  callbacks.read_func = &cb_read_func;
41  callbacks.close_func = &cb_close_func;
42  callbacks.tell_func = &cb_tell_func;
43 
44  if (vorbis_enable_seek) {
45  callbacks.seek_func = &cb_seek_func;
46  } else {
47  callbacks.seek_func = NULL;
48  }
49 
50  if (ov_open_callbacks((void*) stream, &_ov, NULL, 0, callbacks) != 0) {
51  movies_cat.error()
52  << "Failed to read Ogg Vorbis file.\n";
53  return;
54  }
55 
56  double time_total = ov_time_total(&_ov, -1);
57  if (time_total != OV_EINVAL) {
58  _length = time_total;
59  }
60 
61  vorbis_info *vi = ov_info(&_ov, -1);
62  _audio_channels = vi->channels;
63  _audio_rate = vi->rate;
64 
65  _can_seek = vorbis_enable_seek && (ov_seekable(&_ov) != 0);
66  _can_seek_fast = _can_seek;
67 
68  _is_valid = true;
69 }
70 
71 ////////////////////////////////////////////////////////////////////
72 // Function: VorbisAudioCursor::Destructor
73 // Access: Protected, Virtual
74 // Description: xxx
75 ////////////////////////////////////////////////////////////////////
76 VorbisAudioCursor::
77 ~VorbisAudioCursor() {
78  ov_clear(&_ov);
79 }
80 
81 ////////////////////////////////////////////////////////////////////
82 // Function: VorbisAudioCursor::seek
83 // Access: Protected
84 // Description: Seeks to a target location. Afterward, the
85 // packet_time is guaranteed to be less than or
86 // equal to the specified time.
87 ////////////////////////////////////////////////////////////////////
88 void VorbisAudioCursor::
89 seek(double t) {
90  if (!vorbis_enable_seek) {
91  return;
92  }
93 
94  t = max(t, 0.0);
95 
96  // Use ov_time_seek_lap if cross-lapping is enabled.
97  if (vorbis_seek_lap) {
98  if (ov_time_seek_lap(&_ov, t) != 0) {
99  movies_cat.error()
100  << "Seek failed. Ogg Vorbis stream may not be seekable.\n";
101  return;
102  }
103  } else {
104  if (ov_time_seek(&_ov, t) != 0) {
105  movies_cat.error()
106  << "Seek failed. Ogg Vorbis stream may not be seekable.\n";
107  return;
108  }
109  }
110 
111  _last_seek = ov_time_tell(&_ov);
112  _samples_read = 0;
113 }
114 
115 ////////////////////////////////////////////////////////////////////
116 // Function: VorbisAudioCursor::read_samples
117 // Access: Public, Virtual
118 // Description: Read audio samples from the stream. N is the
119 // number of samples you wish to read. Your buffer
120 // must be equal in size to N * channels.
121 // Multiple-channel audio will be interleaved.
122 ////////////////////////////////////////////////////////////////////
123 void VorbisAudioCursor::
124 read_samples(int n, PN_int16 *data) {
125  int desired = n * _audio_channels;
126 
127  char *buffer = (char*) data;
128  int length = desired * 2;
129 
130  // Call ov_read repeatedly until the buffer is full.
131  while (length > 0) {
132  int bitstream;
133 
134  // ov_read can give it to us in the exact format we need. Nifty!
135  long read_bytes = ov_read(&_ov, buffer, length, 0, 2, 1, &bitstream);
136  if (read_bytes > 0) {
137  buffer += read_bytes;
138  length -= read_bytes;
139  } else {
140  break;
141  }
142 
143  if (_bitstream != bitstream) {
144  // It is technically possible for it to change parameters from one
145  // bitstream to the next. However, we don't offer this flexibility.
146  vorbis_info *vi = ov_info(&_ov, -1);
147  if (vi->channels != _audio_channels || vi->rate != _audio_rate) {
148  movies_cat.error()
149  << "Ogg Vorbis file has non-matching bitstreams!\n";
150 
151  // We'll change it anyway. Not sure what happens next.
152  _audio_channels = vi->channels;
153  _audio_rate = vi->rate;
154  break;
155  }
156 
157  _bitstream = bitstream;
158  }
159  }
160 
161  // Fill the rest of the buffer with silence.
162  if (length > 0) {
163  memset(buffer, 0, length);
164  n -= length / 2 / _audio_channels;
165  }
166 
167  _samples_read += n;
168 }
169 
170 ////////////////////////////////////////////////////////////////////
171 // Function: VorbisAudioCursor::cb_read_func
172 // Access: Private, Static
173 // Description: Callback passed to libvorbisfile to implement
174 // file I/O via the VirtualFileSystem.
175 ////////////////////////////////////////////////////////////////////
176 size_t VorbisAudioCursor::
177 cb_read_func(void *ptr, size_t size, size_t nmemb, void *datasource) {
178  istream *stream = (istream*) datasource;
179  nassertr(stream != NULL, -1);
180 
181  stream->read((char *)ptr, size * nmemb);
182 
183  if (stream->eof()) {
184  // Gracefully handle EOF.
185  stream->clear();
186  }
187 
188  return stream->gcount();
189 }
190 
191 ////////////////////////////////////////////////////////////////////
192 // Function: VorbisAudioCursor::cb_seek_func
193 // Access: Private, Static
194 // Description: Callback passed to libvorbisfile to implement
195 // file I/O via the VirtualFileSystem.
196 ////////////////////////////////////////////////////////////////////
197 int VorbisAudioCursor::
198 cb_seek_func(void *datasource, ogg_int64_t offset, int whence) {
199  if (!vorbis_enable_seek) {
200  return -1;
201  }
202 
203  istream *stream = (istream*) datasource;
204  nassertr(stream != NULL, -1);
205 
206  switch (whence) {
207  case SEEK_SET:
208  stream->seekg(offset, ios::beg);
209  break;
210 
211  case SEEK_CUR:
212  stream->seekg(offset, ios::cur);
213  break;
214 
215  case SEEK_END:
216  stream->seekg(offset, ios::end);
217  break;
218 
219  default:
220  movies_cat.error()
221  << "Illegal parameter to seek in VorbisAudioCursor::cb_seek_func\n";
222  return -1;
223  }
224 
225  if (stream->fail()) {
226  // This is a fatal error and usually leads to
227  // a libvorbis crash.
228  movies_cat.error()
229  << "Failure to seek to byte " << offset;
230 
231  switch (whence) {
232  case SEEK_CUR:
233  movies_cat.error(false)
234  << " from current location!\n";
235  break;
236 
237  case SEEK_END:
238  movies_cat.error(false)
239  << " from end of file!\n";
240  break;
241 
242  default:
243  movies_cat.error(false) << "!\n";
244  }
245 
246  return -1;
247  }
248 
249  return 0;
250 }
251 
252 ////////////////////////////////////////////////////////////////////
253 // Function: VorbisAudioCursor::cb_close_func
254 // Access: Private, Static
255 // Description: Callback passed to libvorbisfile to implement
256 // file I/O via the VirtualFileSystem.
257 ////////////////////////////////////////////////////////////////////
258 int VorbisAudioCursor::
259 cb_close_func(void *datasource) {
260  istream *stream = (istream*) datasource;
261  nassertr(stream != NULL, -1);
262 
264  vfs->close_read_file(stream);
265 
266  // Return value isn't checked, but let's be predictable
267  return 0;
268 }
269 
270 ////////////////////////////////////////////////////////////////////
271 // Function: VorbisAudioCursor::cb_tell_func
272 // Access: Private, Static
273 // Description: Callback passed to libvorbisfile to implement
274 // file I/O via the VirtualFileSystem.
275 ////////////////////////////////////////////////////////////////////
276 long VorbisAudioCursor::
277 cb_tell_func(void *datasource) {
278  istream *stream = (istream*) datasource;
279  nassertr(stream != NULL, -1);
280 
281  return stream->tellg();
282 }
283 
284 #endif // HAVE_VORBIS
A hierarchy of directories and files that appears to be one continuous file system, even though the files may originate from several different sources that may not be related to the actual OS&#39;s file system.
static void close_read_file(istream *stream)
Closes a file opened by a previous call to open_read_file().
A MovieAudio is actually any source that provides a sequence of audio samples.
static VirtualFileSystem * get_global_ptr()
Returns the default global VirtualFileSystem.
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:85