comparison decoders/oggtremor.c @ 590:1c8414cd5839

Introduced new Ogg Tremor decoder, based on the existing Ogg Vorbis decoder.
author Eric Wing <ewing@anscamobile.com>
date Wed, 27 Apr 2011 19:37:16 -0700
parents
children 8faf61a640f0
comparison
equal deleted inserted replaced
589:e3f029c68671 590:1c8414cd5839
1 /*
2 * SDL_sound -- An abstract sound format decoding API.
3 * Copyright (C) 2001 Ryan C. Gordon.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20 /*
21 * Ogg Vorbis decoder for SDL_sound.
22 *
23 * This driver handles .OGG audio files, and depends on libvorbisfile to
24 * do the actual decoding work. libvorbisfile is part of libvorbis, which
25 * is part of the Ogg Vorbis project.
26 *
27 * Ogg Vorbis: http://www.xiph.org/ogg/vorbis/
28 * vorbisfile documentation: http://www.xiph.org/ogg/vorbis/doc/vorbisfile/
29 *
30 * Please see the file LICENSE.txt in the source's root directory.
31 *
32 * This file written by Ryan C. Gordon. (icculus@icculus.org)
33 */
34
35 #if HAVE_CONFIG_H
36 # include <config.h>
37 #endif
38
39 #ifdef SOUND_SUPPORTS_OGG
40
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <math.h>
45
46 #include "SDL_sound.h"
47
48 #define __SDL_SOUND_INTERNAL__
49 #include "SDL_sound_internal.h"
50
51 //#include <vorbis/codec.h>
52 #include <ivorbisfile.h>
53 #define ERR_IO_ERROR "I/O error"
54
55
56 static int OGG_init(void);
57 static void OGG_quit(void);
58 static int OGG_open(Sound_Sample *sample, const char *ext);
59 static void OGG_close(Sound_Sample *sample);
60 static Uint32 OGG_read(Sound_Sample *sample);
61 static int OGG_rewind(Sound_Sample *sample);
62 static int OGG_seek(Sound_Sample *sample, Uint32 ms);
63
64 static const char *extensions_ogg[] = { "OGG", NULL };
65 const Sound_DecoderFunctions __Sound_DecoderFunctions_OGG =
66 {
67 {
68 extensions_ogg,
69 "Ogg Vorbis audio through VorbisFile",
70 "Ryan C. Gordon <icculus@icculus.org>",
71 "http://www.icculus.org/SDL_sound/"
72 },
73
74 OGG_init, /* init() method */
75 OGG_quit, /* quit() method */
76 OGG_open, /* open() method */
77 OGG_close, /* close() method */
78 OGG_read, /* read() method */
79 OGG_rewind, /* rewind() method */
80 OGG_seek /* seek() method */
81 };
82
83
84 static int OGG_init(void)
85 {
86 return(1); /* always succeeds. */
87 } /* OGG_init */
88
89
90 static void OGG_quit(void)
91 {
92 /* it's a no-op. */
93 } /* OGG_quit */
94
95
96
97 /*
98 * These are callbacks from vorbisfile that let them read data from
99 * a RWops...
100 */
101
102 static size_t RWops_ogg_read(void *ptr, size_t size, size_t nmemb, void *datasource)
103 {
104 return((size_t) SDL_RWread((SDL_RWops *) datasource, ptr, size, nmemb));
105 } /* RWops_ogg_read */
106
107 static int RWops_ogg_seek(void *datasource, ogg_int64_t offset, int whence)
108 {
109 return(SDL_RWseek((SDL_RWops *) datasource, offset, whence));
110 } /* RWops_ogg_seek */
111
112 static int RWops_ogg_close(void *datasource)
113 {
114 /* do nothing; SDL_sound will delete the RWops at a higher level. */
115 return(0); /* this is success in fclose(), so I guess that's okay. */
116 } /* RWops_ogg_close */
117
118 static long RWops_ogg_tell(void *datasource)
119 {
120 return((long) SDL_RWtell((SDL_RWops *) datasource));
121 } /* RWops_ogg_tell */
122
123 static const ov_callbacks RWops_ogg_callbacks =
124 {
125 RWops_ogg_read,
126 RWops_ogg_seek,
127 RWops_ogg_close,
128 RWops_ogg_tell
129 };
130
131
132 /* Return a human readable version of an VorbisFile error code... */
133 #if (defined DEBUG_CHATTER)
134 static const char *ogg_error(int errnum)
135 {
136 switch(errnum)
137 {
138 case OV_EREAD:
139 return("i/o error");
140 case OV_ENOTVORBIS:
141 return("not a vorbis file");
142 case OV_EVERSION:
143 return("Vorbis version mismatch");
144 case OV_EBADHEADER:
145 return("invalid Vorbis bitstream header");
146 case OV_EFAULT:
147 return("internal logic fault in Vorbis library");
148 } /* switch */
149
150 return("unknown error");
151 } /* ogg_error */
152 #endif
153
154 static __inline__ void output_ogg_comments(OggVorbis_File *vf)
155 {
156 #if (defined DEBUG_CHATTER)
157 int i;
158 vorbis_comment *vc = ov_comment(vf, -1);
159
160 if (vc == NULL)
161 return;
162
163 SNDDBG(("OGG: vendor == [%s].\n", vc->vendor));
164 for (i = 0; i < vc->comments; i++)
165 {
166 SNDDBG(("OGG: user comment [%s].\n", vc->user_comments[i]));
167 } /* for */
168 #endif
169 } /* output_ogg_comments */
170
171
172 static int OGG_open(Sound_Sample *sample, const char *ext)
173 {
174 int rc;
175 double total_time;
176 OggVorbis_File *vf;
177 vorbis_info *info;
178 Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
179
180 vf = (OggVorbis_File *) malloc(sizeof (OggVorbis_File));
181 BAIL_IF_MACRO(vf == NULL, ERR_OUT_OF_MEMORY, 0);
182
183 rc = ov_open_callbacks(internal->rw, vf, NULL, 0, RWops_ogg_callbacks);
184 if (rc != 0)
185 {
186 SNDDBG(("OGG: can't grok data. reason: [%s].\n", ogg_error(rc)));
187 free(vf);
188 BAIL_MACRO("OGG: Not valid Ogg Vorbis data.", 0);
189 } /* if */
190
191 info = ov_info(vf, -1);
192 if (info == NULL)
193 {
194 ov_clear(vf);
195 free(vf);
196 BAIL_MACRO("OGG: failed to retrieve bitstream info", 0);
197 } /* if */
198
199 SNDDBG(("OGG: Accepting data stream.\n"));
200
201 output_ogg_comments(vf);
202 SNDDBG(("OGG: bitstream version == (%d).\n", info->version));
203 SNDDBG(("OGG: bitstream channels == (%d).\n", info->channels));
204 SNDDBG(("OGG: bitstream sampling rate == (%ld).\n", info->rate));
205 SNDDBG(("OGG: seekable == {%s}.\n", ov_seekable(vf) ? "TRUE" : "FALSE"));
206 SNDDBG(("OGG: number of logical bitstreams == (%ld).\n", ov_streams(vf)));
207 SNDDBG(("OGG: serial number == (%ld).\n", ov_serialnumber(vf, -1)));
208 SNDDBG(("OGG: total seconds of sample == (%f).\n", ov_time_total(vf, -1)));
209
210 internal->decoder_private = vf;
211 sample->flags = SOUND_SAMPLEFLAG_CANSEEK;
212 sample->actual.rate = (Uint32) info->rate;
213 sample->actual.channels = (Uint8) info->channels;
214 total_time = ov_time_total(vf, -1);
215 if (OV_EINVAL == total_time)
216 internal->total_time = -1;
217 else
218 internal->total_time = (Sint32)(total_time * 1000.0 + 0.5);
219
220
221 /*
222 * Since we might have more than one logical bitstream in the OGG file,
223 * and these bitstreams may be in different formats, we might be
224 * converting two or three times: once in vorbisfile, once again in
225 * SDL_sound, and perhaps a third time to get it to the sound device's
226 * format. That's wickedly inefficient.
227 *
228 * To combat this a little, if the user specified a desired format, we
229 * claim that to be the "actual" format of the collection of logical
230 * bitstreams. This means that VorbisFile will do a conversion as
231 * necessary, and SDL_sound will not. If the user didn't specify a
232 * desired format, then we pretend the "actual" format is something that
233 * OGG files are apparently commonly encoded in.
234 */
235 sample->actual.format = (sample->desired.format == 0) ?
236 AUDIO_S16SYS : sample->desired.format;
237 return(1);
238 } /* OGG_open */
239
240
241 static void OGG_close(Sound_Sample *sample)
242 {
243 Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
244 OggVorbis_File *vf = (OggVorbis_File *) internal->decoder_private;
245 ov_clear(vf);
246 free(vf);
247 } /* OGG_close */
248
249 /* Note: According to the Vorbis documentation:
250 * "ov_read() will decode at most one vorbis packet per invocation,
251 * so the value returned will generally be less than length."
252 * Due to this, for buffer sizes like 16384, SDL_Sound was always getting
253 * an underfilled buffer and always setting the EAGAIN flag.
254 * Since the SDL_Sound API implies that the entire buffer
255 * should be filled unless EOF, additional code has been added
256 * to this function to call ov_read() until the buffer is filled.
257 * However, there may still be some corner cases where the buffer
258 * cannot be entirely filled. So be aware.
259 */
260 static Uint32 OGG_read(Sound_Sample *sample)
261 {
262 int rc;
263 int bitstream;
264 Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
265 OggVorbis_File *vf = (OggVorbis_File *) internal->decoder_private;
266
267 rc = ov_read(vf, internal->buffer, internal->buffer_size,
268 &bitstream);
269
270 /* Make sure the read went smoothly... */
271 if (rc == 0)
272 sample->flags |= SOUND_SAMPLEFLAG_EOF;
273
274 else if (rc < 0)
275 sample->flags |= SOUND_SAMPLEFLAG_ERROR;
276
277 /* If the buffer isn't filled, keep trying to fill it
278 * until no more data can be grabbed */
279 else if ((Uint32) rc < internal->buffer_size)
280 {
281 /* Creating a pointer to the buffer that denotes where to start
282 * writing new data. */
283 Uint8* buffer_start_point = NULL;
284 int total_bytes_read = rc;
285 int bytes_remaining = internal->buffer_size - rc;
286
287 /* Keep grabbing data until something prevents
288 * us from getting more. (Could be EOF,
289 * packets are too large to fit in remaining
290 * space, or an error.)
291 */
292 while( (rc > 0) && (bytes_remaining > 0) )
293 {
294 /* Set buffer pointer to end of last write */
295 /* All the messiness is to get rid of the warning for
296 * dereferencing a void*
297 */
298 buffer_start_point = &(((Uint8*)internal->buffer)[total_bytes_read]);
299 rc = ov_read(vf, buffer_start_point, bytes_remaining,
300 &bitstream);
301 /* Make sure rc > 0 because we don't accidently want
302 * to change the counters if there was an error
303 */
304 if(rc > 0)
305 {
306 total_bytes_read += rc;
307 bytes_remaining = bytes_remaining - rc;
308 }
309 }
310 /* I think the minimum read size is 2, though I'm
311 * not sure about this. (I've hit cases where I
312 * couldn't read less than 4.) What I don't want to do is
313 * accidently claim we hit EOF when the reason rc == 0
314 * is because the requested amount of data was smaller
315 * than the minimum packet size.
316 * For now, I will be conservative
317 * and not set the EOF flag, and let the next call to
318 * this function figure it out.
319 * I think the ERROR flag is safe to set because
320 * it looks like OGG simply returns 0 if the
321 * read size is too small.
322 * And in most cases for sensible buffer sizes,
323 * this fix will fill the buffer,
324 * so we can set the EAGAIN flag without worrying
325 * that it will always be set.
326 */
327 if(rc < 0)
328 {
329 sample->flags |= SOUND_SAMPLEFLAG_ERROR;
330 }
331 else if(rc == 0)
332 {
333 /* Do nothing for now until there is a better solution */
334 /* sample->flags |= SOUND_SAMPLEFLAG_EOF; */
335 }
336
337 /* Test for a buffer underrun. It should occur less frequently
338 * now, but it still may happen and not necessarily mean
339 * anything useful. */
340 if ((Uint32) total_bytes_read < internal->buffer_size)
341 {
342 sample->flags |= SOUND_SAMPLEFLAG_EAGAIN;
343 }
344 /* change rc to the total bytes read so function
345 * can return the correct value.
346 */
347 rc = total_bytes_read;
348 }
349
350 return((Uint32) rc);
351 } /* OGG_read */
352
353
354 static int OGG_rewind(Sound_Sample *sample)
355 {
356 Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
357 OggVorbis_File *vf = (OggVorbis_File *) internal->decoder_private;
358
359 BAIL_IF_MACRO(ov_raw_seek(vf, 0) < 0, ERR_IO_ERROR, 0);
360 return(1);
361 } /* OGG_rewind */
362
363
364 static int OGG_seek(Sound_Sample *sample, Uint32 ms)
365 {
366 Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
367 OggVorbis_File *vf = (OggVorbis_File *) internal->decoder_private;
368 double timepos = (((double) ms) / 1000.0);
369 BAIL_IF_MACRO(ov_time_seek(vf, timepos) < 0, ERR_IO_ERROR, 0);
370 return(1);
371 } /* OGG_seek */
372
373 #endif /* SOUND_SUPPORTS_OGG */
374
375
376 /* end of ogg.c ... */
377