load_ogg.c
author Sam Lantinga <slouken@libsdl.org>
Sun, 08 Nov 2009 18:40:07 +0000
changeset 474 a2c238c0c4b2
parent 473 60b7e1c4f6b2
child 518 8bc9b5fd2aae
permissions -rw-r--r--
Don't break binary compatibility!
     1 /*
     2     SDL_mixer:  An audio mixer library based on the SDL library
     3     Copyright (C) 1997-2009 Sam Lantinga
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Library General Public
     7     License as published by the Free Software Foundation; either
     8     version 2 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     Library General Public License for more details.
    14 
    15     You should have received a copy of the GNU Library General Public
    16     License along with this library; if not, write to the Free
    17     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    18 
    19     This is the source needed to decode an Ogg Vorbis into a waveform.
    20     This file by Vaclav Slavik (vaclav.slavik@matfyz.cz).
    21 */
    22 
    23 /* $Id$ */
    24 
    25 #ifdef OGG_MUSIC
    26 
    27 #include <stdio.h>
    28 #include <stdlib.h>
    29 #include <string.h>
    30 
    31 #include "SDL_mutex.h"
    32 #include "SDL_endian.h"
    33 #include "SDL_timer.h"
    34 
    35 #include "SDL_mixer.h"
    36 #include "dynamic_ogg.h"
    37 #include "load_ogg.h"
    38 
    39 static size_t sdl_read_func(void *ptr, size_t size, size_t nmemb, void *datasource)
    40 {
    41     return SDL_RWread((SDL_RWops*)datasource, ptr, size, nmemb);
    42 }
    43 
    44 static int sdl_seek_func(void *datasource, ogg_int64_t offset, int whence)
    45 {
    46     return SDL_RWseek((SDL_RWops*)datasource, (int)offset, whence);
    47 }
    48 
    49 static int sdl_close_func_freesrc(void *datasource)
    50 {
    51     return SDL_RWclose((SDL_RWops*)datasource);
    52 }
    53 
    54 static int sdl_close_func_nofreesrc(void *datasource)
    55 {
    56     return SDL_RWseek((SDL_RWops*)datasource, 0, RW_SEEK_SET);
    57 }
    58 
    59 static long sdl_tell_func(void *datasource)
    60 {
    61     return SDL_RWtell((SDL_RWops*)datasource);
    62 }
    63 
    64 
    65 /* don't call this directly; use Mix_LoadWAV_RW() for now. */
    66 SDL_AudioSpec *Mix_LoadOGG_RW (SDL_RWops *src, int freesrc,
    67         SDL_AudioSpec *spec, Uint8 **audio_buf, Uint32 *audio_len)
    68 {
    69     OggVorbis_File vf;
    70     ov_callbacks callbacks;
    71     vorbis_info *info;
    72     Uint8 *buf;
    73     int bitstream = -1;
    74     long samplesize;
    75     long samples;
    76     int read, to_read;
    77     int must_close = 1;
    78     int was_error = 1;
    79     
    80     if ( (!src) || (!audio_buf) || (!audio_len) )   /* sanity checks. */
    81         goto done;
    82 
    83     if ( !Mix_Init(MIX_INIT_OGG) )
    84         goto done;
    85 
    86     callbacks.read_func = sdl_read_func;
    87     callbacks.seek_func = sdl_seek_func;
    88     callbacks.tell_func = sdl_tell_func;
    89     callbacks.close_func = freesrc ? 
    90                            sdl_close_func_freesrc : sdl_close_func_nofreesrc;
    91 
    92     if (vorbis.ov_open_callbacks(src, &vf, NULL, 0, callbacks) != 0)
    93     {
    94         SDL_SetError("OGG bitstream is not valid Vorbis stream!");
    95         goto done;
    96     }
    97 
    98     must_close = 0;
    99     
   100     info = vorbis.ov_info(&vf, -1);
   101     
   102     *audio_buf = NULL;
   103     *audio_len = 0;
   104     memset(spec, '\0', sizeof (SDL_AudioSpec));
   105 
   106     spec->format = AUDIO_S16;
   107     spec->channels = info->channels;
   108     spec->freq = info->rate;
   109     spec->samples = 4096; /* buffer size */
   110     
   111     samples = (long)vorbis.ov_pcm_total(&vf, -1);
   112 
   113     *audio_len = spec->size = samples * spec->channels * 2;
   114     *audio_buf = malloc(*audio_len);
   115     if (*audio_buf == NULL)
   116         goto done;
   117 
   118     buf = *audio_buf;
   119     to_read = *audio_len;
   120 #ifdef OGG_USE_TREMOR
   121     for (read = vorbis.ov_read(&vf, (char *)buf, to_read, &bitstream);
   122 	 read > 0;
   123 	 read = vorbis.ov_read(&vf, (char *)buf, to_read, &bitstream))
   124 #else
   125     for (read = vorbis.ov_read(&vf, (char *)buf, to_read, 0/*LE*/, 2/*16bit*/, 1/*signed*/, &bitstream);
   126          read > 0;
   127          read = vorbis.ov_read(&vf, (char *)buf, to_read, 0, 2, 1, &bitstream))
   128 #endif	 
   129     {
   130         if (read == OV_HOLE || read == OV_EBADLINK)
   131             break; /* error */
   132         
   133         to_read -= read;
   134         buf += read;
   135     }
   136 
   137     vorbis.ov_clear(&vf);
   138     was_error = 0;
   139 
   140     /* Don't return a buffer that isn't a multiple of samplesize */
   141     samplesize = ((spec->format & 0xFF)/8)*spec->channels;
   142     *audio_len &= ~(samplesize-1);
   143 
   144 done:
   145     if (src && must_close)
   146     {
   147         if (freesrc)
   148             SDL_RWclose(src);
   149         else
   150             SDL_RWseek(src, 0, RW_SEEK_SET);
   151     }
   152 
   153     if ( was_error )
   154         spec = NULL;
   155 
   156     return(spec);
   157 } /* Mix_LoadOGG_RW */
   158 
   159 /* end of load_ogg.c ... */
   160 
   161 #endif