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