music_ogg.c
author Ozkan Sezer <sezeroz@gmail.com>
Sun, 07 Oct 2018 00:08:00 +0300
branchSDL-1.2
changeset 871 284d10d87cc9
parent 869 318285c30cff
child 920 6d8ba24cbbd6
permissions -rw-r--r--
backport fix for bug #1833. (from 2.0 branch commit 7ead8213dfb0).
slouken@63
     1
/*
slouken@518
     2
  SDL_mixer:  An audio mixer library based on the SDL library
slouken@518
     3
  Copyright (C) 1997-2012 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@63
    44
	mixer = *mixerfmt;
slouken@63
    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@63
    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@246
    61
    return 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@246
    66
    return 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@246
    72
	OGG_music *music;
slouken@246
    73
	ov_callbacks callbacks;
slouken@246
    74
slouken@545
    75
	if ( !Mix_Init(MIX_INIT_OGG) ) {
slouken@545
    76
		if ( freerw ) {
slouken@545
    77
			SDL_RWclose(rw);
slouken@545
    78
		}
slouken@545
    79
		return(NULL);
slouken@545
    80
	}
slouken@545
    81
slouken@521
    82
	SDL_memset(&callbacks, 0, sizeof(callbacks));
slouken@246
    83
	callbacks.read_func = sdl_read_func;
slouken@246
    84
	callbacks.seek_func = sdl_seek_func;
slouken@246
    85
	callbacks.tell_func = sdl_tell_func;
slouken@246
    86
slouken@561
    87
	music = (OGG_music *)SDL_malloc(sizeof *music);
slouken@246
    88
	if ( music ) {
slouken@246
    89
		/* Initialize the music structure */
slouken@246
    90
		memset(music, 0, (sizeof *music));
slouken@521
    91
		music->rw = rw;
slouken@521
    92
		music->freerw = freerw;
slouken@246
    93
		OGG_stop(music);
slouken@246
    94
		OGG_setvolume(music, MIX_MAX_VOLUME);
slouken@246
    95
		music->section = -1;
slouken@246
    96
slouken@312
    97
		if ( vorbis.ov_open_callbacks(rw, &music->vf, NULL, 0, callbacks) < 0 ) {
slouken@561
    98
			SDL_free(music);
slouken@521
    99
			if ( freerw ) {
slouken@521
   100
				SDL_RWclose(rw);
slouken@521
   101
			}
slouken@312
   102
			SDL_SetError("Not an Ogg Vorbis audio stream");
slouken@246
   103
			return(NULL);
slouken@246
   104
		}
slouken@246
   105
	} else {
slouken@521
   106
		if ( freerw ) {
slouken@521
   107
			SDL_RWclose(rw);
slouken@521
   108
		}
slouken@312
   109
		SDL_OutOfMemory();
slouken@521
   110
		return(NULL);
slouken@246
   111
	}
slouken@246
   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@63
   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@63
   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@63
   130
	int section;
slouken@63
   131
	int len;
slouken@63
   132
	char data[4096];
slouken@63
   133
	SDL_AudioCVT *cvt;
slouken@63
   134
slouken@353
   135
#ifdef OGG_USE_TREMOR
slouken@353
   136
	len = vorbis.ov_read(&music->vf, data, sizeof(data), &section);
slouken@353
   137
#else
slouken@312
   138
	len = vorbis.ov_read(&music->vf, data, sizeof(data), 0, 2, 1, &section);
slouken@353
   139
#endif
slouken@63
   140
	if ( len <= 0 ) {
slouken@63
   141
		if ( len == 0 ) {
slouken@63
   142
			music->playing = 0;
slouken@63
   143
		}
slouken@63
   144
		return;
slouken@63
   145
	}
slouken@63
   146
	cvt = &music->cvt;
slouken@63
   147
	if ( section != music->section ) {
slouken@63
   148
		vorbis_info *vi;
slouken@63
   149
slouken@312
   150
		vi = vorbis.ov_info(&music->vf, -1);
slouken@63
   151
		SDL_BuildAudioCVT(cvt, AUDIO_S16, vi->channels, vi->rate,
slouken@63
   152
		                       mixer.format,mixer.channels,mixer.freq);
slouken@63
   153
		if ( cvt->buf ) {
slouken@561
   154
			SDL_free(cvt->buf);
slouken@63
   155
		}
slouken@561
   156
		cvt->buf = (Uint8 *)SDL_malloc(sizeof(data)*cvt->len_mult);
slouken@63
   157
		music->section = section;
slouken@63
   158
	}
slouken@63
   159
	if ( cvt->buf ) {
slouken@63
   160
		memcpy(cvt->buf, data, len);
slouken@63
   161
		if ( cvt->needed ) {
slouken@63
   162
			cvt->len = len;
slouken@63
   163
			SDL_ConvertAudio(cvt);
slouken@63
   164
		} else {
slouken@63
   165
			cvt->len_cvt = len;
slouken@63
   166
		}
slouken@63
   167
		music->len_available = music->cvt.len_cvt;
slouken@63
   168
		music->snd_available = music->cvt.buf;
slouken@63
   169
	} else {
slouken@93
   170
		SDL_SetError("Out of memory");
slouken@63
   171
		music->playing = 0;
slouken@63
   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@63
   178
	int mixable;
slouken@63
   179
slouken@63
   180
	while ( (len > 0) && music->playing ) {
slouken@63
   181
		if ( ! music->len_available ) {
slouken@63
   182
			OGG_getsome(music);
slouken@63
   183
		}
slouken@63
   184
		mixable = len;
slouken@63
   185
		if ( mixable > music->len_available ) {
slouken@63
   186
			mixable = music->len_available;
slouken@63
   187
		}
slouken@63
   188
		if ( music->volume == MIX_MAX_VOLUME ) {
slouken@63
   189
			memcpy(snd, music->snd_available, mixable);
slouken@63
   190
		} else {
slouken@63
   191
			SDL_MixAudio(snd, music->snd_available, mixable,
slouken@63
   192
			                              music->volume);
slouken@63
   193
		}
slouken@63
   194
		music->len_available -= mixable;
slouken@63
   195
		music->snd_available += mixable;
slouken@63
   196
		len -= mixable;
slouken@63
   197
		snd += mixable;
slouken@63
   198
	}
icculus@281
   199
	
icculus@281
   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@63
   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@63
   212
	if ( music ) {
slouken@63
   213
		if ( music->cvt.buf ) {
slouken@561
   214
			SDL_free(music->cvt.buf);
slouken@63
   215
		}
slouken@521
   216
		if ( music->freerw ) {
slouken@521
   217
			SDL_RWclose(music->rw);
slouken@521
   218
		}
slouken@312
   219
		vorbis.ov_clear(&music->vf);
slouken@561
   220
		SDL_free(music);
slouken@63
   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
sezeroz@869
   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 */