music_ogg.c
author Sam Lantinga <slouken@libsdl.org>
Mon, 07 Jul 2014 11:01:41 -0700
changeset 690 3d18eb009c89
parent 642 dae7bb0a66b1
child 711 f40c5ac95b12
permissions -rw-r--r--
Fixed compiler warnings
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@690
    59
static int sdl_seek_func(void *datasource, ogg_int64_t offset, int whence)
slouken@246
    60
{
slouken@690
    61
    return (int)SDL_RWseek((SDL_RWops*)datasource, offset, whence);
slouken@246
    62
}
slouken@246
    63
slouken@690
    64
static long sdl_tell_func(void *datasource)
slouken@246
    65
{
slouken@690
    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@625
    70
OGG_music *OGG_new_RW(SDL_RWops *src, int freesrc)
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
        return(NULL);
slouken@617
    77
    }
slouken@545
    78
slouken@617
    79
    SDL_memset(&callbacks, 0, sizeof(callbacks));
slouken@617
    80
    callbacks.read_func = sdl_read_func;
slouken@617
    81
    callbacks.seek_func = sdl_seek_func;
slouken@617
    82
    callbacks.tell_func = sdl_tell_func;
slouken@246
    83
slouken@617
    84
    music = (OGG_music *)SDL_malloc(sizeof *music);
slouken@617
    85
    if ( music ) {
slouken@617
    86
        /* Initialize the music structure */
slouken@621
    87
        SDL_memset(music, 0, (sizeof *music));
slouken@625
    88
        music->src = src;
slouken@625
    89
        music->freesrc = freesrc;
slouken@617
    90
        OGG_stop(music);
slouken@617
    91
        OGG_setvolume(music, MIX_MAX_VOLUME);
slouken@617
    92
        music->section = -1;
slouken@246
    93
slouken@625
    94
        if ( vorbis.ov_open_callbacks(src, &music->vf, NULL, 0, callbacks) < 0 ) {
slouken@625
    95
            SDL_SetError("Not an Ogg Vorbis audio stream");
slouken@617
    96
            SDL_free(music);
slouken@617
    97
            return(NULL);
slouken@617
    98
        }
slouken@617
    99
    } else {
slouken@617
   100
        SDL_OutOfMemory();
slouken@617
   101
        return(NULL);
slouken@617
   102
    }
slouken@617
   103
    return(music);
slouken@246
   104
}
slouken@246
   105
slouken@63
   106
/* Start playback of a given OGG stream */
slouken@63
   107
void OGG_play(OGG_music *music)
slouken@63
   108
{
slouken@617
   109
    music->playing = 1;
slouken@63
   110
}
slouken@63
   111
slouken@63
   112
/* Return non-zero if a stream is currently playing */
slouken@63
   113
int OGG_playing(OGG_music *music)
slouken@63
   114
{
slouken@617
   115
    return(music->playing);
slouken@63
   116
}
slouken@63
   117
slouken@63
   118
/* Read some Ogg stream data and convert it for output */
slouken@63
   119
static void OGG_getsome(OGG_music *music)
slouken@63
   120
{
slouken@617
   121
    int section;
slouken@617
   122
    int len;
slouken@617
   123
    char data[4096];
slouken@617
   124
    SDL_AudioCVT *cvt;
slouken@63
   125
slouken@353
   126
#ifdef OGG_USE_TREMOR
slouken@617
   127
    len = vorbis.ov_read(&music->vf, data, sizeof(data), &section);
slouken@353
   128
#else
slouken@617
   129
    len = vorbis.ov_read(&music->vf, data, sizeof(data), 0, 2, 1, &section);
slouken@353
   130
#endif
slouken@617
   131
    if ( len <= 0 ) {
slouken@617
   132
        if ( len == 0 ) {
slouken@617
   133
            music->playing = 0;
slouken@617
   134
        }
slouken@617
   135
        return;
slouken@617
   136
    }
slouken@617
   137
    cvt = &music->cvt;
slouken@617
   138
    if ( section != music->section ) {
slouken@617
   139
        vorbis_info *vi;
slouken@63
   140
slouken@617
   141
        vi = vorbis.ov_info(&music->vf, -1);
slouken@617
   142
        SDL_BuildAudioCVT(cvt, AUDIO_S16, vi->channels, vi->rate,
slouken@617
   143
                               mixer.format,mixer.channels,mixer.freq);
slouken@617
   144
        if ( cvt->buf ) {
slouken@617
   145
            SDL_free(cvt->buf);
slouken@617
   146
        }
slouken@617
   147
        cvt->buf = (Uint8 *)SDL_malloc(sizeof(data)*cvt->len_mult);
slouken@617
   148
        music->section = section;
slouken@617
   149
    }
slouken@617
   150
    if ( cvt->buf ) {
slouken@621
   151
        SDL_memcpy(cvt->buf, data, len);
slouken@617
   152
        if ( cvt->needed ) {
slouken@617
   153
            cvt->len = len;
slouken@617
   154
            SDL_ConvertAudio(cvt);
slouken@617
   155
        } else {
slouken@617
   156
            cvt->len_cvt = len;
slouken@617
   157
        }
slouken@617
   158
        music->len_available = music->cvt.len_cvt;
slouken@617
   159
        music->snd_available = music->cvt.buf;
slouken@617
   160
    } else {
slouken@617
   161
        SDL_SetError("Out of memory");
slouken@617
   162
        music->playing = 0;
slouken@617
   163
    }
slouken@63
   164
}
slouken@63
   165
slouken@63
   166
/* Play some of a stream previously started with OGG_play() */
icculus@281
   167
int OGG_playAudio(OGG_music *music, Uint8 *snd, int len)
slouken@63
   168
{
slouken@617
   169
    int mixable;
slouken@63
   170
slouken@617
   171
    while ( (len > 0) && music->playing ) {
slouken@617
   172
        if ( ! music->len_available ) {
slouken@617
   173
            OGG_getsome(music);
slouken@617
   174
        }
slouken@617
   175
        mixable = len;
slouken@617
   176
        if ( mixable > music->len_available ) {
slouken@617
   177
            mixable = music->len_available;
slouken@617
   178
        }
slouken@617
   179
        if ( music->volume == MIX_MAX_VOLUME ) {
slouken@621
   180
            SDL_memcpy(snd, music->snd_available, mixable);
slouken@617
   181
        } else {
slouken@617
   182
            SDL_MixAudio(snd, music->snd_available, mixable,
slouken@617
   183
                                          music->volume);
slouken@617
   184
        }
slouken@617
   185
        music->len_available -= mixable;
slouken@617
   186
        music->snd_available += mixable;
slouken@617
   187
        len -= mixable;
slouken@617
   188
        snd += mixable;
slouken@617
   189
    }
slouken@617
   190
slouken@617
   191
    return len;
slouken@63
   192
}
slouken@63
   193
slouken@63
   194
/* Stop playback of a stream previously started with OGG_play() */
slouken@63
   195
void OGG_stop(OGG_music *music)
slouken@63
   196
{
slouken@617
   197
    music->playing = 0;
slouken@63
   198
}
slouken@63
   199
slouken@63
   200
/* Close the given OGG stream */
slouken@63
   201
void OGG_delete(OGG_music *music)
slouken@63
   202
{
slouken@617
   203
    if ( music ) {
slouken@617
   204
        if ( music->cvt.buf ) {
slouken@617
   205
            SDL_free(music->cvt.buf);
slouken@617
   206
        }
slouken@625
   207
        if ( music->freesrc ) {
slouken@625
   208
            SDL_RWclose(music->src);
slouken@617
   209
        }
slouken@617
   210
        vorbis.ov_clear(&music->vf);
slouken@617
   211
        SDL_free(music);
slouken@617
   212
    }
slouken@63
   213
}
slouken@63
   214
slouken@155
   215
/* Jump (seek) to a given position (time is in seconds) */
slouken@155
   216
void OGG_jump_to_time(OGG_music *music, double time)
slouken@155
   217
{
slouken@505
   218
#ifdef OGG_USE_TREMOR
notasas@612
   219
       vorbis.ov_time_seek( &music->vf, (ogg_int64_t)(time * 1000.0) );
slouken@505
   220
#else
slouken@312
   221
       vorbis.ov_time_seek( &music->vf, time );
slouken@505
   222
#endif
slouken@155
   223
}
slouken@155
   224
slouken@63
   225
#endif /* OGG_MUSIC */