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