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