music_ogg.c
author Sam Lantinga <slouken@libsdl.org>
Fri, 14 Dec 2001 13:02:16 +0000
changeset 140 efa15d2a5403
parent 138 4d0dc6b4985d
child 152 c97650d4f432
permissions -rw-r--r--
*** empty log message ***
slouken@63
     1
/*
slouken@138
     2
    SDL_mixer:  An audio mixer library based on the SDL library
slouken@138
     3
    Copyright (C) 1997, 1998, 1999, 2000, 2001  Sam Lantinga
slouken@63
     4
slouken@63
     5
    This library is free software; you can redistribute it and/or
slouken@63
     6
    modify it under the terms of the GNU Library General Public
slouken@63
     7
    License as published by the Free Software Foundation; either
slouken@63
     8
    version 2 of the License, or (at your option) any later version.
slouken@63
     9
slouken@63
    10
    This library is distributed in the hope that it will be useful,
slouken@63
    11
    but WITHOUT ANY WARRANTY; without even the implied warranty of
slouken@63
    12
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
slouken@63
    13
    Library General Public License for more details.
slouken@63
    14
slouken@63
    15
    You should have received a copy of the GNU Library General Public
slouken@63
    16
    License along with this library; if not, write to the Free
slouken@63
    17
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
slouken@63
    18
slouken@63
    19
    Sam Lantinga
slouken@138
    20
    slouken@libsdl.org
slouken@63
    21
*/
slouken@63
    22
slouken@140
    23
/* $Id$ */
slouken@138
    24
slouken@63
    25
#ifdef OGG_MUSIC
slouken@63
    26
slouken@63
    27
/* This file supports Ogg Vorbis music streams */
slouken@63
    28
slouken@63
    29
#include <stdio.h>
slouken@63
    30
#include <string.h>
slouken@63
    31
slouken@63
    32
#include "SDL_mixer.h"
slouken@63
    33
#include "music_ogg.h"
slouken@63
    34
slouken@63
    35
/* This is the format of the audio mixer data */
slouken@63
    36
static SDL_AudioSpec mixer;
slouken@63
    37
slouken@63
    38
/* Initialize the Ogg Vorbis player, with the given mixer settings
slouken@63
    39
   This function returns 0, or -1 if there was an error.
slouken@63
    40
 */
slouken@63
    41
int OGG_init(SDL_AudioSpec *mixerfmt)
slouken@63
    42
{
slouken@63
    43
	mixer = *mixerfmt;
slouken@63
    44
	return(0);
slouken@63
    45
}
slouken@63
    46
slouken@63
    47
/* Set the volume for an OGG stream */
slouken@63
    48
void OGG_setvolume(OGG_music *music, int volume)
slouken@63
    49
{
slouken@63
    50
	music->volume = volume;
slouken@63
    51
}
slouken@63
    52
slouken@63
    53
/* Load an OGG stream from the given file */
slouken@63
    54
OGG_music *OGG_new(const char *file)
slouken@63
    55
{
slouken@63
    56
	OGG_music *music;
slouken@63
    57
	FILE *fp;
slouken@63
    58
slouken@63
    59
	music = (OGG_music *)malloc(sizeof *music);
slouken@63
    60
	if ( music ) {
slouken@63
    61
		/* Initialize the music structure */
slouken@63
    62
		memset(music, 0, (sizeof *music));
slouken@63
    63
		OGG_stop(music);
slouken@63
    64
		OGG_setvolume(music, MIX_MAX_VOLUME);
slouken@63
    65
		music->section = -1;
slouken@63
    66
slouken@63
    67
		fp = fopen(file, "rb");
slouken@63
    68
		if ( fp == NULL ) {
slouken@63
    69
			SDL_SetError("Couldn't open %s", file);
slouken@63
    70
			free(music);
slouken@63
    71
			return(NULL);
slouken@63
    72
		}
slouken@63
    73
		if ( ov_open(fp, &music->vf, NULL, 0) < 0 ) {
slouken@63
    74
			SDL_SetError("Not an Ogg Vorbis audio stream");
slouken@63
    75
			free(music);
slouken@63
    76
			fclose(fp);
slouken@63
    77
			return(NULL);
slouken@63
    78
		}
slouken@63
    79
	} else {
slouken@93
    80
		SDL_SetError("Out of memory");
slouken@63
    81
	}
slouken@63
    82
	return(music);
slouken@63
    83
}
slouken@63
    84
slouken@63
    85
/* Start playback of a given OGG stream */
slouken@63
    86
void OGG_play(OGG_music *music)
slouken@63
    87
{
slouken@63
    88
	music->playing = 1;
slouken@63
    89
}
slouken@63
    90
slouken@63
    91
/* Return non-zero if a stream is currently playing */
slouken@63
    92
int OGG_playing(OGG_music *music)
slouken@63
    93
{
slouken@63
    94
	return(music->playing);
slouken@63
    95
}
slouken@63
    96
slouken@63
    97
/* Read some Ogg stream data and convert it for output */
slouken@63
    98
static void OGG_getsome(OGG_music *music)
slouken@63
    99
{
slouken@63
   100
	int section;
slouken@63
   101
	int len;
slouken@63
   102
	char data[4096];
slouken@63
   103
	SDL_AudioCVT *cvt;
slouken@63
   104
slouken@63
   105
	len = ov_read(&music->vf, data, sizeof(data), 0, 2, 1, &section);
slouken@63
   106
	if ( len <= 0 ) {
slouken@63
   107
		if ( len == 0 ) {
slouken@63
   108
			music->playing = 0;
slouken@63
   109
		}
slouken@63
   110
		return;
slouken@63
   111
	}
slouken@63
   112
	cvt = &music->cvt;
slouken@63
   113
	if ( section != music->section ) {
slouken@63
   114
		vorbis_info *vi;
slouken@63
   115
slouken@63
   116
		vi = ov_info(&music->vf, -1);
slouken@63
   117
		SDL_BuildAudioCVT(cvt, AUDIO_S16, vi->channels, vi->rate,
slouken@63
   118
		                       mixer.format,mixer.channels,mixer.freq);
slouken@63
   119
		if ( cvt->buf ) {
slouken@63
   120
			free(cvt->buf);
slouken@63
   121
		}
slouken@63
   122
		cvt->buf = (Uint8 *)malloc(sizeof(data)*cvt->len_mult);
slouken@63
   123
		music->section = section;
slouken@63
   124
	}
slouken@63
   125
	if ( cvt->buf ) {
slouken@63
   126
		memcpy(cvt->buf, data, len);
slouken@63
   127
		if ( cvt->needed ) {
slouken@63
   128
			cvt->len = len;
slouken@63
   129
			SDL_ConvertAudio(cvt);
slouken@63
   130
		} else {
slouken@63
   131
			cvt->len_cvt = len;
slouken@63
   132
		}
slouken@63
   133
		music->len_available = music->cvt.len_cvt;
slouken@63
   134
		music->snd_available = music->cvt.buf;
slouken@63
   135
	} else {
slouken@93
   136
		SDL_SetError("Out of memory");
slouken@63
   137
		music->playing = 0;
slouken@63
   138
	}
slouken@63
   139
}
slouken@63
   140
slouken@63
   141
/* Play some of a stream previously started with OGG_play() */
slouken@63
   142
void OGG_playAudio(OGG_music *music, Uint8 *snd, int len)
slouken@63
   143
{
slouken@63
   144
	int mixable;
slouken@63
   145
slouken@63
   146
	while ( (len > 0) && music->playing ) {
slouken@63
   147
		if ( ! music->len_available ) {
slouken@63
   148
			OGG_getsome(music);
slouken@63
   149
		}
slouken@63
   150
		mixable = len;
slouken@63
   151
		if ( mixable > music->len_available ) {
slouken@63
   152
			mixable = music->len_available;
slouken@63
   153
		}
slouken@63
   154
		if ( music->volume == MIX_MAX_VOLUME ) {
slouken@63
   155
			memcpy(snd, music->snd_available, mixable);
slouken@63
   156
		} else {
slouken@63
   157
			SDL_MixAudio(snd, music->snd_available, mixable,
slouken@63
   158
			                              music->volume);
slouken@63
   159
		}
slouken@63
   160
		music->len_available -= mixable;
slouken@63
   161
		music->snd_available += mixable;
slouken@63
   162
		len -= mixable;
slouken@63
   163
		snd += mixable;
slouken@63
   164
	}
slouken@63
   165
}
slouken@63
   166
slouken@63
   167
/* Stop playback of a stream previously started with OGG_play() */
slouken@63
   168
void OGG_stop(OGG_music *music)
slouken@63
   169
{
slouken@63
   170
	music->playing = 0;
slouken@63
   171
}
slouken@63
   172
slouken@63
   173
/* Close the given OGG stream */
slouken@63
   174
void OGG_delete(OGG_music *music)
slouken@63
   175
{
slouken@63
   176
	if ( music ) {
slouken@63
   177
		if ( music->cvt.buf ) {
slouken@63
   178
			free(music->cvt.buf);
slouken@63
   179
		}
slouken@63
   180
		ov_clear(&music->vf);
slouken@63
   181
		free(music);
slouken@63
   182
	}
slouken@63
   183
}
slouken@63
   184
slouken@63
   185
#endif /* OGG_MUSIC */