music_ogg.c
author Sam Lantinga <slouken@libsdl.org>
Tue, 18 Dec 2001 21:43:19 +0000
changeset 152 c97650d4f432
parent 140 efa15d2a5403
child 155 53f259dae79d
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@152
    30
#include <stdlib.h>
slouken@63
    31
#include <string.h>
slouken@63
    32
slouken@63
    33
#include "SDL_mixer.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@63
    54
/* Load an OGG stream from the given file */
slouken@63
    55
OGG_music *OGG_new(const char *file)
slouken@63
    56
{
slouken@63
    57
	OGG_music *music;
slouken@63
    58
	FILE *fp;
slouken@63
    59
slouken@63
    60
	music = (OGG_music *)malloc(sizeof *music);
slouken@63
    61
	if ( music ) {
slouken@63
    62
		/* Initialize the music structure */
slouken@63
    63
		memset(music, 0, (sizeof *music));
slouken@63
    64
		OGG_stop(music);
slouken@63
    65
		OGG_setvolume(music, MIX_MAX_VOLUME);
slouken@63
    66
		music->section = -1;
slouken@63
    67
slouken@63
    68
		fp = fopen(file, "rb");
slouken@63
    69
		if ( fp == NULL ) {
slouken@63
    70
			SDL_SetError("Couldn't open %s", file);
slouken@63
    71
			free(music);
slouken@63
    72
			return(NULL);
slouken@63
    73
		}
slouken@63
    74
		if ( ov_open(fp, &music->vf, NULL, 0) < 0 ) {
slouken@63
    75
			SDL_SetError("Not an Ogg Vorbis audio stream");
slouken@63
    76
			free(music);
slouken@63
    77
			fclose(fp);
slouken@63
    78
			return(NULL);
slouken@63
    79
		}
slouken@63
    80
	} else {
slouken@93
    81
		SDL_SetError("Out of memory");
slouken@63
    82
	}
slouken@63
    83
	return(music);
slouken@63
    84
}
slouken@63
    85
slouken@63
    86
/* Start playback of a given OGG stream */
slouken@63
    87
void OGG_play(OGG_music *music)
slouken@63
    88
{
slouken@63
    89
	music->playing = 1;
slouken@63
    90
}
slouken@63
    91
slouken@63
    92
/* Return non-zero if a stream is currently playing */
slouken@63
    93
int OGG_playing(OGG_music *music)
slouken@63
    94
{
slouken@63
    95
	return(music->playing);
slouken@63
    96
}
slouken@63
    97
slouken@63
    98
/* Read some Ogg stream data and convert it for output */
slouken@63
    99
static void OGG_getsome(OGG_music *music)
slouken@63
   100
{
slouken@63
   101
	int section;
slouken@63
   102
	int len;
slouken@63
   103
	char data[4096];
slouken@63
   104
	SDL_AudioCVT *cvt;
slouken@63
   105
slouken@63
   106
	len = ov_read(&music->vf, data, sizeof(data), 0, 2, 1, &section);
slouken@63
   107
	if ( len <= 0 ) {
slouken@63
   108
		if ( len == 0 ) {
slouken@63
   109
			music->playing = 0;
slouken@63
   110
		}
slouken@63
   111
		return;
slouken@63
   112
	}
slouken@63
   113
	cvt = &music->cvt;
slouken@63
   114
	if ( section != music->section ) {
slouken@63
   115
		vorbis_info *vi;
slouken@63
   116
slouken@63
   117
		vi = ov_info(&music->vf, -1);
slouken@63
   118
		SDL_BuildAudioCVT(cvt, AUDIO_S16, vi->channels, vi->rate,
slouken@63
   119
		                       mixer.format,mixer.channels,mixer.freq);
slouken@63
   120
		if ( cvt->buf ) {
slouken@63
   121
			free(cvt->buf);
slouken@63
   122
		}
slouken@63
   123
		cvt->buf = (Uint8 *)malloc(sizeof(data)*cvt->len_mult);
slouken@63
   124
		music->section = section;
slouken@63
   125
	}
slouken@63
   126
	if ( cvt->buf ) {
slouken@63
   127
		memcpy(cvt->buf, data, len);
slouken@63
   128
		if ( cvt->needed ) {
slouken@63
   129
			cvt->len = len;
slouken@63
   130
			SDL_ConvertAudio(cvt);
slouken@63
   131
		} else {
slouken@63
   132
			cvt->len_cvt = len;
slouken@63
   133
		}
slouken@63
   134
		music->len_available = music->cvt.len_cvt;
slouken@63
   135
		music->snd_available = music->cvt.buf;
slouken@63
   136
	} else {
slouken@93
   137
		SDL_SetError("Out of memory");
slouken@63
   138
		music->playing = 0;
slouken@63
   139
	}
slouken@63
   140
}
slouken@63
   141
slouken@63
   142
/* Play some of a stream previously started with OGG_play() */
slouken@63
   143
void OGG_playAudio(OGG_music *music, Uint8 *snd, int len)
slouken@63
   144
{
slouken@63
   145
	int mixable;
slouken@63
   146
slouken@63
   147
	while ( (len > 0) && music->playing ) {
slouken@63
   148
		if ( ! music->len_available ) {
slouken@63
   149
			OGG_getsome(music);
slouken@63
   150
		}
slouken@63
   151
		mixable = len;
slouken@63
   152
		if ( mixable > music->len_available ) {
slouken@63
   153
			mixable = music->len_available;
slouken@63
   154
		}
slouken@63
   155
		if ( music->volume == MIX_MAX_VOLUME ) {
slouken@63
   156
			memcpy(snd, music->snd_available, mixable);
slouken@63
   157
		} else {
slouken@63
   158
			SDL_MixAudio(snd, music->snd_available, mixable,
slouken@63
   159
			                              music->volume);
slouken@63
   160
		}
slouken@63
   161
		music->len_available -= mixable;
slouken@63
   162
		music->snd_available += mixable;
slouken@63
   163
		len -= mixable;
slouken@63
   164
		snd += mixable;
slouken@63
   165
	}
slouken@63
   166
}
slouken@63
   167
slouken@63
   168
/* Stop playback of a stream previously started with OGG_play() */
slouken@63
   169
void OGG_stop(OGG_music *music)
slouken@63
   170
{
slouken@63
   171
	music->playing = 0;
slouken@63
   172
}
slouken@63
   173
slouken@63
   174
/* Close the given OGG stream */
slouken@63
   175
void OGG_delete(OGG_music *music)
slouken@63
   176
{
slouken@63
   177
	if ( music ) {
slouken@63
   178
		if ( music->cvt.buf ) {
slouken@63
   179
			free(music->cvt.buf);
slouken@63
   180
		}
slouken@63
   181
		ov_clear(&music->vf);
slouken@63
   182
		free(music);
slouken@63
   183
	}
slouken@63
   184
}
slouken@63
   185
slouken@63
   186
#endif /* OGG_MUSIC */