load_ogg.c
author Sam Lantinga <slouken@libsdl.org>
Sat, 31 Dec 2011 23:28:23 -0500
changeset 528 bc0dfe8ae026
parent 518 8bc9b5fd2aae
child 561 87bdb4c81c0b
permissions -rw-r--r--
Backed out changeset 1eddea51f162
     1 /*
     2   SDL_mixer:  An audio mixer library based on the SDL library
     3   Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
     4 
     5   This software is provided 'as-is', without any express or implied
     6   warranty.  In no event will the authors be held liable for any damages
     7   arising from the use of this software.
     8 
     9   Permission is granted to anyone to use this software for any purpose,
    10   including commercial applications, and to alter it and redistribute it
    11   freely, subject to the following restrictions:
    12 
    13   1. The origin of this software must not be misrepresented; you must not
    14      claim that you wrote the original software. If you use this software
    15      in a product, an acknowledgment in the product documentation would be
    16      appreciated but is not required.
    17   2. Altered source versions must be plainly marked as such, and must not be
    18      misrepresented as being the original software.
    19   3. This notice may not be removed or altered from any source distribution.
    20 
    21   This is the source needed to decode an Ogg Vorbis into a waveform.
    22   This file by Vaclav Slavik (vaclav.slavik@matfyz.cz).
    23 */
    24 
    25 /* $Id$ */
    26 
    27 #ifdef OGG_MUSIC
    28 
    29 #include <stdio.h>
    30 #include <stdlib.h>
    31 #include <string.h>
    32 
    33 #include "SDL_mutex.h"
    34 #include "SDL_endian.h"
    35 #include "SDL_timer.h"
    36 
    37 #include "SDL_mixer.h"
    38 #include "dynamic_ogg.h"
    39 #include "load_ogg.h"
    40 
    41 static size_t sdl_read_func(void *ptr, size_t size, size_t nmemb, void *datasource)
    42 {
    43     return SDL_RWread((SDL_RWops*)datasource, ptr, size, nmemb);
    44 }
    45 
    46 static int sdl_seek_func(void *datasource, ogg_int64_t offset, int whence)
    47 {
    48     return SDL_RWseek((SDL_RWops*)datasource, (int)offset, whence);
    49 }
    50 
    51 static int sdl_close_func_freesrc(void *datasource)
    52 {
    53     return SDL_RWclose((SDL_RWops*)datasource);
    54 }
    55 
    56 static int sdl_close_func_nofreesrc(void *datasource)
    57 {
    58     return SDL_RWseek((SDL_RWops*)datasource, 0, RW_SEEK_SET);
    59 }
    60 
    61 static long sdl_tell_func(void *datasource)
    62 {
    63     return SDL_RWtell((SDL_RWops*)datasource);
    64 }
    65 
    66 
    67 /* don't call this directly; use Mix_LoadWAV_RW() for now. */
    68 SDL_AudioSpec *Mix_LoadOGG_RW (SDL_RWops *src, int freesrc,
    69         SDL_AudioSpec *spec, Uint8 **audio_buf, Uint32 *audio_len)
    70 {
    71     OggVorbis_File vf;
    72     ov_callbacks callbacks;
    73     vorbis_info *info;
    74     Uint8 *buf;
    75     int bitstream = -1;
    76     long samplesize;
    77     long samples;
    78     int read, to_read;
    79     int must_close = 1;
    80     int was_error = 1;
    81     
    82     if ( (!src) || (!audio_buf) || (!audio_len) )   /* sanity checks. */
    83         goto done;
    84 
    85     if ( !Mix_Init(MIX_INIT_OGG) )
    86         goto done;
    87 
    88     callbacks.read_func = sdl_read_func;
    89     callbacks.seek_func = sdl_seek_func;
    90     callbacks.tell_func = sdl_tell_func;
    91     callbacks.close_func = freesrc ? 
    92                            sdl_close_func_freesrc : sdl_close_func_nofreesrc;
    93 
    94     if (vorbis.ov_open_callbacks(src, &vf, NULL, 0, callbacks) != 0)
    95     {
    96         SDL_SetError("OGG bitstream is not valid Vorbis stream!");
    97         goto done;
    98     }
    99 
   100     must_close = 0;
   101     
   102     info = vorbis.ov_info(&vf, -1);
   103     
   104     *audio_buf = NULL;
   105     *audio_len = 0;
   106     memset(spec, '\0', sizeof (SDL_AudioSpec));
   107 
   108     spec->format = AUDIO_S16;
   109     spec->channels = info->channels;
   110     spec->freq = info->rate;
   111     spec->samples = 4096; /* buffer size */
   112     
   113     samples = (long)vorbis.ov_pcm_total(&vf, -1);
   114 
   115     *audio_len = spec->size = samples * spec->channels * 2;
   116     *audio_buf = malloc(*audio_len);
   117     if (*audio_buf == NULL)
   118         goto done;
   119 
   120     buf = *audio_buf;
   121     to_read = *audio_len;
   122 #ifdef OGG_USE_TREMOR
   123     for (read = vorbis.ov_read(&vf, (char *)buf, to_read, &bitstream);
   124 	 read > 0;
   125 	 read = vorbis.ov_read(&vf, (char *)buf, to_read, &bitstream))
   126 #else
   127     for (read = vorbis.ov_read(&vf, (char *)buf, to_read, 0/*LE*/, 2/*16bit*/, 1/*signed*/, &bitstream);
   128          read > 0;
   129          read = vorbis.ov_read(&vf, (char *)buf, to_read, 0, 2, 1, &bitstream))
   130 #endif	 
   131     {
   132         if (read == OV_HOLE || read == OV_EBADLINK)
   133             break; /* error */
   134         
   135         to_read -= read;
   136         buf += read;
   137     }
   138 
   139     vorbis.ov_clear(&vf);
   140     was_error = 0;
   141 
   142     /* Don't return a buffer that isn't a multiple of samplesize */
   143     samplesize = ((spec->format & 0xFF)/8)*spec->channels;
   144     *audio_len &= ~(samplesize-1);
   145 
   146 done:
   147     if (src && must_close)
   148     {
   149         if (freesrc)
   150             SDL_RWclose(src);
   151         else
   152             SDL_RWseek(src, 0, RW_SEEK_SET);
   153     }
   154 
   155     if ( was_error )
   156         spec = NULL;
   157 
   158     return(spec);
   159 } /* Mix_LoadOGG_RW */
   160 
   161 /* end of load_ogg.c ... */
   162 
   163 #endif