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