music_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@63
     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@63
     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@63
     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@63
    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@63
    20
*/
slouken@63
    21
slouken@140
    22
/* $Id$ */
slouken@138
    23
slouken@63
    24
#ifdef OGG_MUSIC
slouken@63
    25
slouken@63
    26
/* This file supports Ogg Vorbis music streams */
slouken@63
    27
slouken@63
    28
#include <stdio.h>
slouken@152
    29
#include <stdlib.h>
slouken@63
    30
#include <string.h>
slouken@63
    31
slouken@63
    32
#include "SDL_mixer.h"
slouken@312
    33
#include "dynamic_ogg.h"
slouken@63
    34
#include "music_ogg.h"
slouken@63
    35
slouken@63
    36
/* This is the format of the audio mixer data */
slouken@63
    37
static SDL_AudioSpec mixer;
slouken@63
    38
slouken@63
    39
/* Initialize the Ogg Vorbis player, with the given mixer settings
slouken@63
    40
   This function returns 0, or -1 if there was an error.
slouken@63
    41
 */
slouken@63
    42
int OGG_init(SDL_AudioSpec *mixerfmt)
slouken@63
    43
{
slouken@617
    44
    mixer = *mixerfmt;
slouken@617
    45
    return(0);
slouken@63
    46
}
slouken@63
    47
slouken@63
    48
/* Set the volume for an OGG stream */
slouken@63
    49
void OGG_setvolume(OGG_music *music, int volume)
slouken@63
    50
{
slouken@617
    51
    music->volume = volume;
slouken@63
    52
}
slouken@63
    53
slouken@246
    54
static size_t sdl_read_func(void *ptr, size_t size, size_t nmemb, void *datasource)
slouken@246
    55
{
slouken@246
    56
    return SDL_RWread((SDL_RWops*)datasource, ptr, size, nmemb);
slouken@246
    57
}
slouken@246
    58
slouken@246
    59
static int sdl_seek_func(void *datasource, ogg_int64_t offset, int whence)
slouken@246
    60
{
slouken@621
    61
    return (int)SDL_RWseek((SDL_RWops*)datasource, (int)offset, whence);
slouken@246
    62
}
slouken@246
    63
slouken@246
    64
static long sdl_tell_func(void *datasource)
slouken@246
    65
{
slouken@621
    66
    return (long)SDL_RWtell((SDL_RWops*)datasource);
slouken@246
    67
}
slouken@246
    68
slouken@246
    69
/* Load an OGG stream from an SDL_RWops object */
slouken@521
    70
OGG_music *OGG_new_RW(SDL_RWops *rw, int freerw)
slouken@246
    71
{
slouken@617
    72
    OGG_music *music;
slouken@617
    73
    ov_callbacks callbacks;
slouken@246
    74
slouken@617
    75
    if ( !Mix_Init(MIX_INIT_OGG) ) {
slouken@617
    76
        if ( freerw ) {
slouken@617
    77
            SDL_RWclose(rw);
slouken@617
    78
        }
slouken@617
    79
        return(NULL);
slouken@617
    80
    }
slouken@545
    81
slouken@617
    82
    SDL_memset(&callbacks, 0, sizeof(callbacks));
slouken@617
    83
    callbacks.read_func = sdl_read_func;
slouken@617
    84
    callbacks.seek_func = sdl_seek_func;
slouken@617
    85
    callbacks.tell_func = sdl_tell_func;
slouken@246
    86
slouken@617
    87
    music = (OGG_music *)SDL_malloc(sizeof *music);
slouken@617
    88
    if ( music ) {
slouken@617
    89
        /* Initialize the music structure */
slouken@621
    90
        SDL_memset(music, 0, (sizeof *music));
slouken@617
    91
        music->rw = rw;
slouken@617
    92
        music->freerw = freerw;
slouken@617
    93
        OGG_stop(music);
slouken@617
    94
        OGG_setvolume(music, MIX_MAX_VOLUME);
slouken@617
    95
        music->section = -1;
slouken@246
    96
slouken@617
    97
        if ( vorbis.ov_open_callbacks(rw, &music->vf, NULL, 0, callbacks) < 0 ) {
slouken@617
    98
            SDL_free(music);
slouken@617
    99
            if ( freerw ) {
slouken@617
   100
                SDL_RWclose(rw);
slouken@617
   101
            }
slouken@617
   102
            SDL_SetError("Not an Ogg Vorbis audio stream");
slouken@617
   103
            return(NULL);
slouken@617
   104
        }
slouken@617
   105
    } else {
slouken@617
   106
        if ( freerw ) {
slouken@617
   107
            SDL_RWclose(rw);
slouken@617
   108
        }
slouken@617
   109
        SDL_OutOfMemory();
slouken@617
   110
        return(NULL);
slouken@617
   111
    }
slouken@617
   112
    return(music);
slouken@246
   113
}
slouken@246
   114
slouken@63
   115
/* Start playback of a given OGG stream */
slouken@63
   116
void OGG_play(OGG_music *music)
slouken@63
   117
{
slouken@617
   118
    music->playing = 1;
slouken@63
   119
}
slouken@63
   120
slouken@63
   121
/* Return non-zero if a stream is currently playing */
slouken@63
   122
int OGG_playing(OGG_music *music)
slouken@63
   123
{
slouken@617
   124
    return(music->playing);
slouken@63
   125
}
slouken@63
   126
slouken@63
   127
/* Read some Ogg stream data and convert it for output */
slouken@63
   128
static void OGG_getsome(OGG_music *music)
slouken@63
   129
{
slouken@617
   130
    int section;
slouken@617
   131
    int len;
slouken@617
   132
    char data[4096];
slouken@617
   133
    SDL_AudioCVT *cvt;
slouken@63
   134
slouken@353
   135
#ifdef OGG_USE_TREMOR
slouken@617
   136
    len = vorbis.ov_read(&music->vf, data, sizeof(data), &section);
slouken@353
   137
#else
slouken@617
   138
    len = vorbis.ov_read(&music->vf, data, sizeof(data), 0, 2, 1, &section);
slouken@353
   139
#endif
slouken@617
   140
    if ( len <= 0 ) {
slouken@617
   141
        if ( len == 0 ) {
slouken@617
   142
            music->playing = 0;
slouken@617
   143
        }
slouken@617
   144
        return;
slouken@617
   145
    }
slouken@617
   146
    cvt = &music->cvt;
slouken@617
   147
    if ( section != music->section ) {
slouken@617
   148
        vorbis_info *vi;
slouken@63
   149
slouken@617
   150
        vi = vorbis.ov_info(&music->vf, -1);
slouken@617
   151
        SDL_BuildAudioCVT(cvt, AUDIO_S16, vi->channels, vi->rate,
slouken@617
   152
                               mixer.format,mixer.channels,mixer.freq);
slouken@617
   153
        if ( cvt->buf ) {
slouken@617
   154
            SDL_free(cvt->buf);
slouken@617
   155
        }
slouken@617
   156
        cvt->buf = (Uint8 *)SDL_malloc(sizeof(data)*cvt->len_mult);
slouken@617
   157
        music->section = section;
slouken@617
   158
    }
slouken@617
   159
    if ( cvt->buf ) {
slouken@621
   160
        SDL_memcpy(cvt->buf, data, len);
slouken@617
   161
        if ( cvt->needed ) {
slouken@617
   162
            cvt->len = len;
slouken@617
   163
            SDL_ConvertAudio(cvt);
slouken@617
   164
        } else {
slouken@617
   165
            cvt->len_cvt = len;
slouken@617
   166
        }
slouken@617
   167
        music->len_available = music->cvt.len_cvt;
slouken@617
   168
        music->snd_available = music->cvt.buf;
slouken@617
   169
    } else {
slouken@617
   170
        SDL_SetError("Out of memory");
slouken@617
   171
        music->playing = 0;
slouken@617
   172
    }
slouken@63
   173
}
slouken@63
   174
slouken@63
   175
/* Play some of a stream previously started with OGG_play() */
icculus@281
   176
int OGG_playAudio(OGG_music *music, Uint8 *snd, int len)
slouken@63
   177
{
slouken@617
   178
    int mixable;
slouken@63
   179
slouken@617
   180
    while ( (len > 0) && music->playing ) {
slouken@617
   181
        if ( ! music->len_available ) {
slouken@617
   182
            OGG_getsome(music);
slouken@617
   183
        }
slouken@617
   184
        mixable = len;
slouken@617
   185
        if ( mixable > music->len_available ) {
slouken@617
   186
            mixable = music->len_available;
slouken@617
   187
        }
slouken@617
   188
        if ( music->volume == MIX_MAX_VOLUME ) {
slouken@621
   189
            SDL_memcpy(snd, music->snd_available, mixable);
slouken@617
   190
        } else {
slouken@617
   191
            SDL_MixAudio(snd, music->snd_available, mixable,
slouken@617
   192
                                          music->volume);
slouken@617
   193
        }
slouken@617
   194
        music->len_available -= mixable;
slouken@617
   195
        music->snd_available += mixable;
slouken@617
   196
        len -= mixable;
slouken@617
   197
        snd += mixable;
slouken@617
   198
    }
slouken@617
   199
slouken@617
   200
    return len;
slouken@63
   201
}
slouken@63
   202
slouken@63
   203
/* Stop playback of a stream previously started with OGG_play() */
slouken@63
   204
void OGG_stop(OGG_music *music)
slouken@63
   205
{
slouken@617
   206
    music->playing = 0;
slouken@63
   207
}
slouken@63
   208
slouken@63
   209
/* Close the given OGG stream */
slouken@63
   210
void OGG_delete(OGG_music *music)
slouken@63
   211
{
slouken@617
   212
    if ( music ) {
slouken@617
   213
        if ( music->cvt.buf ) {
slouken@617
   214
            SDL_free(music->cvt.buf);
slouken@617
   215
        }
slouken@617
   216
        if ( music->freerw ) {
slouken@617
   217
            SDL_RWclose(music->rw);
slouken@617
   218
        }
slouken@617
   219
        vorbis.ov_clear(&music->vf);
slouken@617
   220
        SDL_free(music);
slouken@617
   221
    }
slouken@63
   222
}
slouken@63
   223
slouken@155
   224
/* Jump (seek) to a given position (time is in seconds) */
slouken@155
   225
void OGG_jump_to_time(OGG_music *music, double time)
slouken@155
   226
{
slouken@505
   227
#ifdef OGG_USE_TREMOR
notasas@612
   228
       vorbis.ov_time_seek( &music->vf, (ogg_int64_t)(time * 1000.0) );
slouken@505
   229
#else
slouken@312
   230
       vorbis.ov_time_seek( &music->vf, time );
slouken@505
   231
#endif
slouken@155
   232
}
slouken@155
   233
slouken@63
   234
#endif /* OGG_MUSIC */