load_ogg.c
author Sam Lantinga <slouken@libsdl.org>
Wed, 26 Feb 2003 17:05:59 +0000
changeset 221 b22f5567d398
parent 190 6c92264b847d
child 241 503416fca921
permissions -rw-r--r--
*** empty log message ***
     1 /*
     2     SDL_mixer:  An audio mixer library based on the SDL library
     3     Copyright (C) 1997, 1998, 1999, 2000, 2001  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 #include <vorbis/vorbisfile.h>
    31 
    32 #include "SDL_mutex.h"
    33 #include "SDL_endian.h"
    34 #include "SDL_timer.h"
    35 
    36 #include "SDL_mixer.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, 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     callbacks.read_func = sdl_read_func;
    84     callbacks.seek_func = sdl_seek_func;
    85     callbacks.tell_func = sdl_tell_func;
    86     callbacks.close_func = freesrc ? 
    87                            sdl_close_func_freesrc : sdl_close_func_nofreesrc;
    88 
    89     if (ov_open_callbacks(src, &vf, NULL, 0, callbacks) != 0)
    90     {
    91         SDL_SetError("OGG bitstream is not valid Vorbis stream!");
    92         goto done;
    93     }
    94 
    95     must_close = 0;
    96     
    97     info = ov_info(&vf, -1);
    98     
    99     *audio_buf = NULL;
   100     *audio_len = 0;
   101     memset(spec, '\0', sizeof (SDL_AudioSpec));
   102 
   103     spec->format = AUDIO_S16;
   104     spec->channels = info->channels;
   105     spec->freq = info->rate;
   106     spec->samples = 4096; /* buffer size */
   107     
   108     samples = (long)ov_pcm_total(&vf, -1);
   109 
   110     *audio_len = spec->size = samples * spec->channels * 2;
   111     *audio_buf = malloc(*audio_len);
   112     if (*audio_buf == NULL)
   113         goto done;
   114 
   115     buf = *audio_buf;
   116     to_read = *audio_len;
   117     for (read = ov_read(&vf, buf, to_read, 0/*LE*/, 2/*16bit*/, 1/*signed*/, &bitstream);
   118          read > 0;
   119          read = ov_read(&vf, buf, to_read, 0, 2, 1, &bitstream))
   120     {
   121         if (read == OV_HOLE || read == OV_EBADLINK)
   122             break; /* error */
   123         
   124         to_read -= read;
   125         buf += read;
   126     }
   127 
   128     ov_clear(&vf);
   129     was_error = 0;
   130 
   131     /* Don't return a buffer that isn't a multiple of samplesize */
   132     samplesize = ((spec->format & 0xFF)/8)*spec->channels;
   133     *audio_len &= ~(samplesize-1);
   134 
   135 done:
   136     if (src && must_close)
   137     {
   138         if (freesrc)
   139             SDL_RWclose(src);
   140         else
   141             SDL_RWseek(src, 0, SEEK_SET);
   142     }
   143 
   144     if ( was_error )
   145         spec = NULL;
   146 
   147     return(spec);
   148 } /* Mix_LoadOGG_RW */
   149 
   150 /* end of load_ogg.c ... */
   151 
   152 #endif