Fixed bug #269
authorSam Lantinga <slouken@libsdl.org>
Sun, 15 Jul 2007 05:33:35 +0000
changeset 357d6d0cfdbea65
parent 356 dae4b083e3ef
child 358 5f35def7a29a
Fixed bug #269

David Rose - Sat Jul 14 22:16:09 PDT 2007
* Added support for MP3 playback with libmad (for GPL projects only!)
CHANGES
Makefile.in
README
SDL_mixer.h
SDL_mixer.spec.in
configure.in
music.c
music_mad.c
music_mad.h
     1.1 --- a/CHANGES	Sun Jul 15 04:41:22 2007 +0000
     1.2 +++ b/CHANGES	Sun Jul 15 05:33:35 2007 +0000
     1.3 @@ -1,4 +1,6 @@
     1.4  1.2.8:
     1.5 +David Rose - Sat Jul 14 22:16:09 PDT 2007
     1.6 + * Added support for MP3 playback with libmad (for GPL projects only!)
     1.7  Sam Lantinga - Sat Jul 14 21:39:30 PDT 2007
     1.8   * Fixed the final loop of audio samples of a certain size
     1.9  Sam Lantinga - Sat Jul 14 21:05:09 PDT 2007
     2.1 --- a/Makefile.in	Sun Jul 15 04:41:22 2007 +0000
     2.2 +++ b/Makefile.in	Sun Jul 15 05:33:35 2007 +0000
     2.3 @@ -35,7 +35,7 @@
     2.4  SOURCES = @SOURCES@
     2.5  OBJECTS = @OBJECTS@
     2.6  
     2.7 -DIST = CHANGES COPYING CWProjects.sea.bin MPWmake.sea.bin Makefile.in README SDL_mixer.h SDL_mixer.qpg.in SDL_mixer.spec SDL_mixer.spec.in VisualC.zip Watcom-OS2.zip Xcode.tar.gz acinclude autogen.sh build-scripts configure configure.in dynamic_mp3.c dynamic_mp3.h dynamic_ogg.c dynamic_ogg.h effect_position.c effect_stereoreverse.c effects_internal.c effects_internal.h gcc-fat.sh load_aiff.c load_aiff.h load_ogg.c load_ogg.h load_voc.c load_voc.h mikmod mixer.c music.c music_cmd.c music_cmd.h music_ogg.c music_ogg.h native_midi native_midi_gpl playmus.c playwave.c timidity wavestream.c wavestream.h
     2.8 +DIST = CHANGES COPYING CWProjects.sea.bin MPWmake.sea.bin Makefile.in README SDL_mixer.h SDL_mixer.qpg.in SDL_mixer.spec SDL_mixer.spec.in VisualC.zip Watcom-OS2.zip Xcode.tar.gz acinclude autogen.sh build-scripts configure configure.in dynamic_mp3.c dynamic_mp3.h dynamic_ogg.c dynamic_ogg.h effect_position.c effect_stereoreverse.c effects_internal.c effects_internal.h gcc-fat.sh load_aiff.c load_aiff.h load_ogg.c load_ogg.h load_voc.c load_voc.h mikmod mixer.c music.c music_cmd.c music_cmd.h music_mad.c music_mad.h music_ogg.c music_ogg.h native_midi native_midi_gpl playmus.c playwave.c timidity wavestream.c wavestream.h
     2.9  
    2.10  LT_AGE      = @LT_AGE@
    2.11  LT_CURRENT  = @LT_CURRENT@
     3.1 --- a/README	Sun Jul 15 04:41:22 2007 +0000
     3.2 +++ b/README	Sun Jul 15 05:33:35 2007 +0000
     3.3 @@ -16,12 +16,20 @@
     3.4  files as audio samples, and can load MIDI files via Timidity and the
     3.5  following music formats via MikMod:  .MOD .S3M .IT .XM. It can load
     3.6  Ogg Vorbis streams as music if built with Ogg Vorbis or Tremor libraries,
     3.7 -and finally it can load MP3 music using the SMPEG library.
     3.8 +and finally it can load MP3 music using the SMPEG or libmad libraries.
     3.9  
    3.10 -Tremor decoding is disabled by default, you can enable it by passing
    3.11 +Tremor decoding is disabled by default; you can enable it by passing
    3.12  	--enable-music-ogg-tremor
    3.13  to configure, or by defining OGG_MUSIC and OGG_USE_TREMOR.
    3.14  
    3.15 +libmad decoding is disabled by default; you can enable it by passing
    3.16 +	--enable-music-mp3-mad
    3.17 +to configure, or by defining MP3_MAD_MUSIC
    3.18 +vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
    3.19 +WARNING: The license for libmad is GPL, which means that in order to
    3.20 +         use it your application must also be GPL!
    3.21 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    3.22 +
    3.23  The process of mixing MIDI files to wave output is very CPU intensive,
    3.24  so if playing regular WAVE files sound great, but playing MIDI files
    3.25  sound choppy, try using 8-bit audio, mono audio, or lower frequencies.
     4.1 --- a/SDL_mixer.h	Sun Jul 15 04:41:22 2007 +0000
     4.2 +++ b/SDL_mixer.h	Sun Jul 15 05:33:35 2007 +0000
     4.3 @@ -103,7 +103,8 @@
     4.4  	MUS_MOD,
     4.5  	MUS_MID,
     4.6  	MUS_OGG,
     4.7 -	MUS_MP3
     4.8 +	MUS_MP3,
     4.9 +	MUS_MP3_MAD
    4.10  } Mix_MusicType;
    4.11  
    4.12  /* The internal format for a music chunk interpreted via mikmod */
     5.1 --- a/SDL_mixer.spec.in	Sun Jul 15 04:41:22 2007 +0000
     5.2 +++ b/SDL_mixer.spec.in	Sun Jul 15 05:33:35 2007 +0000
     5.3 @@ -15,8 +15,8 @@
     5.4  %description
     5.5  Due to popular demand, here is a simple multi-channel audio mixer.
     5.6  It supports 4 channels of 16 bit stereo audio, plus a single channel
     5.7 -of music, mixed by the popular MikMod MOD, Timidity MIDI and SMPEG MP3
     5.8 -libraries.
     5.9 +of music, mixed by the popular MikMod MOD, Timidity MIDI, Ogg Vorbis,
    5.10 +Tremor, SMPEG MP3, and libmad MP3 libraries.
    5.11  
    5.12  %package devel
    5.13  Summary: Libraries, includes and more to develop SDL applications.
    5.14 @@ -26,8 +26,8 @@
    5.15  %description devel
    5.16  Due to popular demand, here is a simple multi-channel audio mixer.
    5.17  It supports 4 channels of 16 bit stereo audio, plus a single channel
    5.18 -of music, mixed by the popular MikMod MOD, Timidity MIDI and SMPEG MP3
    5.19 -libraries.
    5.20 +of music, mixed by the popular MikMod MOD, Timidity MIDI, Ogg Vorbis,
    5.21 +Tremor, SMPEG MP3, and libmad MP3 libraries.
    5.22  
    5.23  %prep
    5.24  %setup 
     6.1 --- a/configure.in	Sun Jul 15 04:41:22 2007 +0000
     6.2 +++ b/configure.in	Sun Jul 15 05:33:35 2007 +0000
     6.3 @@ -320,6 +320,25 @@
     6.4          fi
     6.5      fi
     6.6  fi
     6.7 +AC_ARG_ENABLE(music-mp3-mad-gpl,
     6.8 +AC_HELP_STRING([--enable-music-mp3-mad-gpl], [enable MP3 music via libmad GPL code [[default=no]]]),
     6.9 +                  [], [enable_music_mp3_mad_gpl=no])
    6.10 +if test x$enable_music_mp3_mad_gpl = xyes; then
    6.11 +    AC_MSG_CHECKING(for libmad headers)
    6.12 +    have_libmad=no
    6.13 +    AC_TRY_COMPILE([
    6.14 +     #include "mad.h"
    6.15 +    ],[
    6.16 +    ],[
    6.17 +    have_libmad=yes
    6.18 +    ])
    6.19 +    AC_MSG_RESULT($have_libmad)
    6.20 +    if test x$have_libmad = xyes; then
    6.21 +        SOURCES="$SOURCES $srcdir/music_mad.c"
    6.22 +        EXTRA_CFLAGS="$EXTRA_CFLAGS -DMP3_MAD_MUSIC"
    6.23 +        EXTRA_LDFLAGS="$EXTRA_LDFLAGS -lmad"
    6.24 +    fi
    6.25 +fi
    6.26  
    6.27  OBJECTS=`echo $SOURCES | sed 's,[[^ ]]*/\([[^ ]]*\)\.c,$(objects)/\1.lo,g'`
    6.28  
     7.1 --- a/music.c	Sun Jul 15 04:41:22 2007 +0000
     7.2 +++ b/music.c	Sun Jul 15 05:33:35 2007 +0000
     7.3 @@ -85,10 +85,16 @@
     7.4  #endif
     7.5  #ifdef MP3_MUSIC
     7.6  #include "dynamic_mp3.h"
     7.7 +#endif
     7.8 +#ifdef MP3_MAD_MUSIC
     7.9 +#include "music_mad.h"
    7.10 +#endif
    7.11  
    7.12 +#if defined(MP3_MUSIC) || defined(MP3_MAD_MUSIC)
    7.13  static SDL_AudioSpec used_mixer;
    7.14  #endif
    7.15  
    7.16 +
    7.17  int volatile music_active = 1;
    7.18  static int volatile music_stopped = 0;
    7.19  static int music_loops = 0;
    7.20 @@ -124,6 +130,9 @@
    7.21  #ifdef MP3_MUSIC
    7.22  		SMPEG *mp3;
    7.23  #endif
    7.24 +#ifdef MP3_MAD_MUSIC
    7.25 +		mad_data *mp3_mad;
    7.26 +#endif
    7.27  	} data;
    7.28  	Mix_Fading fading;
    7.29  	int fade_step;
    7.30 @@ -341,6 +350,11 @@
    7.31  				smpeg.SMPEG_playAudio(music_playing->data.mp3, stream, len);
    7.32  				break;
    7.33  #endif
    7.34 +#ifdef MP3_MAD_MUSIC
    7.35 +			case MUS_MP3_MAD:
    7.36 +				mad_getSamples(music_playing->data.mp3_mad, stream, len);
    7.37 +				break;
    7.38 +#endif
    7.39  			default:
    7.40  				/* Unknown music type?? */
    7.41  				break;
    7.42 @@ -455,7 +469,7 @@
    7.43  		++music_error;
    7.44  	}
    7.45  #endif
    7.46 -#ifdef MP3_MUSIC
    7.47 +#if defined(MP3_MUSIC) || defined(MP3_MAD_MUSIC)
    7.48  	/* Keep a copy of the mixer */
    7.49  	used_mixer = *mixer;
    7.50  #endif
    7.51 @@ -608,6 +622,20 @@
    7.52  		}
    7.53  	} else
    7.54  #endif
    7.55 +#ifdef MP3_MAD_MUSIC
    7.56 +	if ( (ext && MIX_string_equals(ext, "MPG")) ||
    7.57 +	     (ext && MIX_string_equals(ext, "MP3")) ||
    7.58 +	     (ext && MIX_string_equals(ext, "MPEG")) ||
    7.59 +	     (ext && MIX_string_equals(ext, "MAD")) ||
    7.60 +	     (magic[0] == 0xFF && (magic[1] & 0xF0) == 0xF0) ) {
    7.61 +		music->type = MUS_MP3_MAD;
    7.62 +		music->data.mp3_mad = mad_openFile(file, &used_mixer);
    7.63 +		if (music->data.mp3_mad == 0) {
    7.64 +		    Mix_SetError("Could not initialize MPEG stream.");
    7.65 +			music->error = 1;
    7.66 +		}
    7.67 +	} else
    7.68 +#endif
    7.69  #if defined(MOD_MUSIC) || defined(LIBMIKMOD_MUSIC)
    7.70  	if ( 1 ) {
    7.71  		music->type = MUS_MOD;
    7.72 @@ -698,6 +726,11 @@
    7.73  				Mix_QuitMP3();
    7.74  				break;
    7.75  #endif
    7.76 +#ifdef MP3_MAD_MUSIC
    7.77 +			case MUS_MP3_MAD:
    7.78 +				mad_closeFile(music->data.mp3_mad);
    7.79 +				break;
    7.80 +#endif
    7.81  			default:
    7.82  				/* Unknown music type?? */
    7.83  				break;
    7.84 @@ -787,6 +820,11 @@
    7.85  		smpeg.SMPEG_play(music_playing->data.mp3);
    7.86  		break;
    7.87  #endif
    7.88 +#ifdef MP3_MAD_MUSIC
    7.89 +	    case MUS_MP3_MAD:
    7.90 +		mad_start(music->data.mp3_mad);
    7.91 +		break;
    7.92 +#endif
    7.93  	    default:
    7.94  		Mix_SetError("Can't play unknown music type");
    7.95  		retval = -1;
    7.96 @@ -880,6 +918,11 @@
    7.97  		}
    7.98  		break;
    7.99  #endif
   7.100 +#ifdef MP3_MAD_MUSIC
   7.101 +	    case MUS_MP3_MAD:
   7.102 +		mad_seek(music_playing->data.mp3_mad, position);
   7.103 +		break;
   7.104 +#endif
   7.105  	    default:
   7.106  		/* TODO: Implement this for other music backends */
   7.107  		retval = -1;
   7.108 @@ -959,6 +1002,11 @@
   7.109  		smpeg.SMPEG_setvolume(music_playing->data.mp3,(int)(((float)volume/(float)MIX_MAX_VOLUME)*100.0));
   7.110  		break;
   7.111  #endif
   7.112 +#ifdef MP3_MAD_MUSIC
   7.113 +	    case MUS_MP3_MAD:
   7.114 +		mad_setVolume(music_playing->data.mp3_mad, volume);
   7.115 +		break;
   7.116 +#endif
   7.117  	    default:
   7.118  		/* Unknown music type?? */
   7.119  		break;
   7.120 @@ -1027,6 +1075,11 @@
   7.121  		smpeg.SMPEG_stop(music_playing->data.mp3);
   7.122  		break;
   7.123  #endif
   7.124 +#ifdef MP3_MAD_MUSIC
   7.125 +	    case MUS_MP3_MAD:
   7.126 +		mad_stop(music_playing->data.mp3_mad);
   7.127 +		break;
   7.128 +#endif
   7.129  	    default:
   7.130  		/* Unknown music type?? */
   7.131  		return;
   7.132 @@ -1170,6 +1223,13 @@
   7.133  			playing = 0;
   7.134  		break;
   7.135  #endif
   7.136 +#ifdef MP3_MAD_MUSIC
   7.137 +	    case MUS_MP3_MAD:
   7.138 +		if (!mad_isPlaying(music_playing->data.mp3_mad)) {
   7.139 +			playing = 0;
   7.140 +		}
   7.141 +		break;
   7.142 +#endif
   7.143  	    default:
   7.144  		playing = 0;
   7.145  		break;
   7.146 @@ -1413,6 +1473,16 @@
   7.147  		}
   7.148  	} else
   7.149  #endif
   7.150 +#ifdef MP3_MAD_MUSIC
   7.151 +	if ( magic[0] == 0xFF && (magic[1] & 0xF0) == 0xF0 ) {
   7.152 +		music->type = MUS_MP3_MAD;
   7.153 +		music->data.mp3_mad = mad_openFileRW(rw, &used_mixer);
   7.154 +		if (music->data.mp3_mad == 0) {
   7.155 +			Mix_SetError("Could not initialize MPEG stream.");
   7.156 +			music->error = 1;
   7.157 +		}
   7.158 +	} else
   7.159 +#endif
   7.160  #ifdef MID_MUSIC
   7.161  	/* MIDI files have the magic four bytes "MThd" */
   7.162  	if ( strcmp((char *)magic, "MThd") == 0 ) {
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/music_mad.c	Sun Jul 15 05:33:35 2007 +0000
     8.3 @@ -0,0 +1,333 @@
     8.4 +/*
     8.5 +    SDL_mixer:  An audio mixer library based on the SDL library
     8.6 +    Copyright (C) 1997-2004 Sam Lantinga
     8.7 +
     8.8 +    This library is free software; you can redistribute it and/or
     8.9 +    modify it under the terms of the GNU Library General Public
    8.10 +    License as published by the Free Software Foundation; either
    8.11 +    version 2 of the License, or (at your option) any later version.
    8.12 +
    8.13 +    This library is distributed in the hope that it will be useful,
    8.14 +    but WITHOUT ANY WARRANTY; without even the implied warranty of
    8.15 +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    8.16 +    Library General Public License for more details.
    8.17 +
    8.18 +    You should have received a copy of the GNU Library General Public
    8.19 +    License along with this library; if not, write to the Free
    8.20 +    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    8.21 +
    8.22 +    Sam Lantinga
    8.23 +    slouken@libsdl.org
    8.24 +*/
    8.25 +
    8.26 +#ifdef MP3_MAD_MUSIC
    8.27 +
    8.28 +#include <string.h>
    8.29 +
    8.30 +#include "music_mad.h"
    8.31 +
    8.32 +mad_data *
    8.33 +mad_openFile(const char *filename, SDL_AudioSpec *mixer) {
    8.34 +  SDL_RWops *rw;
    8.35 +
    8.36 +  rw = SDL_RWFromFile(filename, "rb");
    8.37 +  if (rw == NULL) {
    8.38 +	return NULL;
    8.39 +  }
    8.40 +
    8.41 +  return mad_openFileRW(rw, mixer);
    8.42 +}
    8.43 +
    8.44 +mad_data *
    8.45 +mad_openFileRW(SDL_RWops *rw, SDL_AudioSpec *mixer) {
    8.46 +  mad_data *mp3_mad;
    8.47 +
    8.48 +  mp3_mad = (mad_data *)malloc(sizeof(mad_data));
    8.49 +  mp3_mad->rw = rw;
    8.50 +  mad_stream_init(&mp3_mad->stream);
    8.51 +  mad_frame_init(&mp3_mad->frame);
    8.52 +  mad_synth_init(&mp3_mad->synth);
    8.53 +  mp3_mad->frames_read = 0;
    8.54 +  mad_timer_reset(&mp3_mad->next_frame_start);
    8.55 +  mp3_mad->volume = MIX_MAX_VOLUME;
    8.56 +  mp3_mad->status = 0;
    8.57 +  mp3_mad->output_begin = 0;
    8.58 +  mp3_mad->output_end = 0;
    8.59 +  mp3_mad->mixer = *mixer;
    8.60 +
    8.61 +  return mp3_mad;
    8.62 +}
    8.63 +
    8.64 +void
    8.65 +mad_closeFile(mad_data *mp3_mad) {
    8.66 +  SDL_FreeRW(mp3_mad->rw);
    8.67 +  mad_stream_finish(&mp3_mad->stream);
    8.68 +  mad_frame_finish(&mp3_mad->frame);
    8.69 +  mad_synth_finish(&mp3_mad->synth);
    8.70 +
    8.71 +  free(mp3_mad);
    8.72 +}
    8.73 +
    8.74 +/* Starts the playback. */
    8.75 +void
    8.76 +mad_start(mad_data *mp3_mad) {
    8.77 +  mp3_mad->status |= MS_playing;
    8.78 +}
    8.79 +
    8.80 +/* Stops the playback. */
    8.81 +void 
    8.82 +mad_stop(mad_data *mp3_mad) {
    8.83 +  mp3_mad->status &= ~MS_playing;
    8.84 +}
    8.85 +
    8.86 +/* Returns true if the playing is engaged, false otherwise. */
    8.87 +int
    8.88 +mad_isPlaying(mad_data *mp3_mad) {
    8.89 +  return ((mp3_mad->status & MS_playing) != 0);
    8.90 +}
    8.91 +
    8.92 +/* Reads the next frame from the file.  Returns true on success or
    8.93 +   false on failure. */
    8.94 +static int
    8.95 +read_next_frame(mad_data *mp3_mad) {
    8.96 +  if (mp3_mad->stream.buffer == NULL || 
    8.97 +	  mp3_mad->stream.error == MAD_ERROR_BUFLEN) {
    8.98 +	size_t read_size;
    8.99 +	size_t remaining;
   8.100 +	unsigned char *read_start;
   8.101 +	
   8.102 +	/* There might be some bytes in the buffer left over from last
   8.103 +	   time.  If so, move them down and read more bytes following
   8.104 +	   them. */
   8.105 +	if (mp3_mad->stream.next_frame != NULL) {
   8.106 +	  remaining = mp3_mad->stream.bufend - mp3_mad->stream.next_frame;
   8.107 +	  memmove(mp3_mad->input_buffer, mp3_mad->stream.next_frame, remaining);
   8.108 +	  read_start = mp3_mad->input_buffer + remaining;
   8.109 +	  read_size = MAD_INPUT_BUFFER_SIZE - remaining;
   8.110 +	  
   8.111 +	} else {
   8.112 +	  read_size = MAD_INPUT_BUFFER_SIZE;
   8.113 +	  read_start = mp3_mad->input_buffer;
   8.114 +	  remaining = 0;
   8.115 +	}
   8.116 +
   8.117 +	/* Now read additional bytes from the input file. */
   8.118 +	read_size = SDL_RWread(mp3_mad->rw, read_start, 1, read_size);
   8.119 +	
   8.120 +	if (read_size <= 0) {
   8.121 +	  if ((mp3_mad->status & (MS_input_eof | MS_input_error)) == 0) {
   8.122 +		if (read_size == 0) {
   8.123 +		  mp3_mad->status |= MS_input_eof;
   8.124 +		} else {
   8.125 +		  mp3_mad->status |= MS_input_error;
   8.126 +		}
   8.127 +		
   8.128 +		/* At the end of the file, we must stuff MAD_BUFFER_GUARD
   8.129 +		   number of 0 bytes. */
   8.130 +		memset(read_start + read_size, 0, MAD_BUFFER_GUARD);
   8.131 +		read_size += MAD_BUFFER_GUARD;
   8.132 +	  }
   8.133 +	}
   8.134 +	
   8.135 +	/* Now feed those bytes into the libmad stream. */
   8.136 +	mad_stream_buffer(&mp3_mad->stream, mp3_mad->input_buffer,
   8.137 +					  read_size + remaining);
   8.138 +	mp3_mad->stream.error = MAD_ERROR_NONE;
   8.139 +  }
   8.140 +  
   8.141 +  /* Now ask libmad to extract a frame from the data we just put in
   8.142 +	 its buffer. */
   8.143 +  if (mad_frame_decode(&mp3_mad->frame, &mp3_mad->stream)) {
   8.144 +	if (MAD_RECOVERABLE(mp3_mad->stream.error)) {
   8.145 +	  return 0;
   8.146 +	  
   8.147 +	} else if (mp3_mad->stream.error == MAD_ERROR_BUFLEN) {
   8.148 +	  return 0;
   8.149 +	  
   8.150 +	} else {
   8.151 +	  mp3_mad->status |= MS_decode_error;
   8.152 +	  return 0;
   8.153 +	}
   8.154 +  }
   8.155 +  
   8.156 +  mp3_mad->frames_read++;
   8.157 +  mad_timer_add(&mp3_mad->next_frame_start, mp3_mad->frame.header.duration);
   8.158 +
   8.159 +  return 1;
   8.160 +}
   8.161 +
   8.162 +/* Scale a MAD sample to 16 bits for output. */
   8.163 +static signed int
   8.164 +scale(mad_fixed_t sample) {
   8.165 +  /* round */
   8.166 +  sample += (1L << (MAD_F_FRACBITS - 16));
   8.167 +
   8.168 +  /* clip */
   8.169 +  if (sample >= MAD_F_ONE)
   8.170 +    sample = MAD_F_ONE - 1;
   8.171 +  else if (sample < -MAD_F_ONE)
   8.172 +    sample = -MAD_F_ONE;
   8.173 +
   8.174 +  /* quantize */
   8.175 +  return sample >> (MAD_F_FRACBITS + 1 - 16);
   8.176 +}
   8.177 +
   8.178 +/* Once the frame has been read, copies its samples into the output
   8.179 +   buffer. */
   8.180 +static void
   8.181 +decode_frame(mad_data *mp3_mad) {
   8.182 +  struct mad_pcm *pcm;
   8.183 +  unsigned int nchannels, nsamples;
   8.184 +  mad_fixed_t const *left_ch, *right_ch;
   8.185 +  unsigned char *out;
   8.186 +  int ret;
   8.187 +
   8.188 +  mad_synth_frame(&mp3_mad->synth, &mp3_mad->frame);
   8.189 +  pcm = &mp3_mad->synth.pcm;
   8.190 +  out = mp3_mad->output_buffer + mp3_mad->output_end;
   8.191 +
   8.192 +  if ((mp3_mad->status & MS_cvt_decoded) == 0) {
   8.193 +	mp3_mad->status |= MS_cvt_decoded;
   8.194 +
   8.195 +	/* The first frame determines some key properties of the stream.
   8.196 +	   In particular, it tells us enough to set up the convert
   8.197 +	   structure now. */
   8.198 +	SDL_BuildAudioCVT(&mp3_mad->cvt, AUDIO_S16, pcm->channels, mp3_mad->frame.header.samplerate, mp3_mad->mixer.format, mp3_mad->mixer.channels, mp3_mad->mixer.freq);
   8.199 +  }
   8.200 +
   8.201 +  /* pcm->samplerate contains the sampling frequency */
   8.202 +
   8.203 +  nchannels = pcm->channels;
   8.204 +  nsamples  = pcm->length;
   8.205 +  left_ch   = pcm->samples[0];
   8.206 +  right_ch  = pcm->samples[1];
   8.207 +
   8.208 +  while (nsamples--) {
   8.209 +    signed int sample;
   8.210 +
   8.211 +    /* output sample(s) in 16-bit signed little-endian PCM */
   8.212 +
   8.213 +    sample = scale(*left_ch++);
   8.214 +    *out++ = ((sample >> 0) & 0xff);
   8.215 +    *out++ = ((sample >> 8) & 0xff);
   8.216 +
   8.217 +    if (nchannels == 2) {
   8.218 +      sample = scale(*right_ch++);
   8.219 +      *out++ = ((sample >> 0) & 0xff);
   8.220 +      *out++ = ((sample >> 8) & 0xff);
   8.221 +    }
   8.222 +  }
   8.223 +
   8.224 +  mp3_mad->output_end = out - mp3_mad->output_buffer;
   8.225 +  /*assert(mp3_mad->output_end <= MAD_OUTPUT_BUFFER_SIZE);*/
   8.226 +}
   8.227 +
   8.228 +void
   8.229 +mad_getSamples(mad_data *mp3_mad, Uint8 *stream, int len) {
   8.230 +  int bytes_remaining;
   8.231 +  int num_bytes;
   8.232 +  Uint8 *out;
   8.233 +
   8.234 +  if ((mp3_mad->status & MS_playing) == 0) {
   8.235 +	/* We're not supposed to be playing, so send silence instead. */
   8.236 +	memset(stream, 0, len);
   8.237 +	return;
   8.238 +  }
   8.239 +
   8.240 +  out = stream;
   8.241 +  bytes_remaining = len;
   8.242 +  while (bytes_remaining > 0) {
   8.243 +	if (mp3_mad->output_end == mp3_mad->output_begin) {
   8.244 +	  /* We need to get a new frame. */
   8.245 +	  mp3_mad->output_begin = 0;
   8.246 +	  mp3_mad->output_end = 0;
   8.247 +	  if (!read_next_frame(mp3_mad)) {
   8.248 +		if ((mp3_mad->status & MS_error_flags) != 0) {
   8.249 +		  /* Couldn't read a frame; either an error condition or
   8.250 +			 end-of-file.  Stop. */
   8.251 +		  memset(out, 0, bytes_remaining);
   8.252 +		  mp3_mad->status &= ~MS_playing;
   8.253 +		  return;
   8.254 +		}
   8.255 +	  } else {
   8.256 +		decode_frame(mp3_mad);
   8.257 +
   8.258 +		/* Now convert the frame data to the appropriate format for
   8.259 +		   output. */
   8.260 +		mp3_mad->cvt.buf = mp3_mad->output_buffer;
   8.261 +		mp3_mad->cvt.len = mp3_mad->output_end;
   8.262 +		
   8.263 +		mp3_mad->output_end = (int)(mp3_mad->output_end * mp3_mad->cvt.len_ratio);
   8.264 +		/*assert(mp3_mad->output_end <= MAD_OUTPUT_BUFFER_SIZE);*/
   8.265 +		SDL_ConvertAudio(&mp3_mad->cvt);
   8.266 +	  }
   8.267 +	}
   8.268 +
   8.269 +	num_bytes = mp3_mad->output_end - mp3_mad->output_begin;
   8.270 +	if (bytes_remaining < num_bytes) {
   8.271 +	  num_bytes = bytes_remaining;
   8.272 +	}
   8.273 +
   8.274 +	if (mp3_mad->volume == MIX_MAX_VOLUME) {
   8.275 +	  memcpy(out, mp3_mad->output_buffer + mp3_mad->output_begin, num_bytes);
   8.276 +	} else {
   8.277 +	  SDL_MixAudio(out, mp3_mad->output_buffer + mp3_mad->output_begin,
   8.278 +				   num_bytes, mp3_mad->volume);
   8.279 +	}
   8.280 +	out += num_bytes;
   8.281 +	mp3_mad->output_begin += num_bytes;
   8.282 +	bytes_remaining -= num_bytes;
   8.283 +  }
   8.284 +}
   8.285 +
   8.286 +void
   8.287 +mad_seek(mad_data *mp3_mad, double position) {
   8.288 +  mad_timer_t target;
   8.289 +  int int_part;
   8.290 +
   8.291 +  int_part = (int)position;
   8.292 +  mad_timer_set(&target, int_part, 
   8.293 +				(int)((position - int_part) * 1000000), 1000000);
   8.294 +
   8.295 +  if (mad_timer_compare(mp3_mad->next_frame_start, target) > 0) {
   8.296 +	/* In order to seek backwards in a VBR file, we have to rewind and
   8.297 +	   start again from the beginning.  This isn't necessary if the
   8.298 +	   file happens to be CBR, of course; in that case we could seek
   8.299 +	   directly to the frame we want.  But I leave that little
   8.300 +	   optimization for the future developer who discovers she really
   8.301 +	   needs it. */
   8.302 +	mp3_mad->frames_read = 0;
   8.303 +	mad_timer_reset(&mp3_mad->next_frame_start);
   8.304 +	mp3_mad->status &= ~MS_error_flags;
   8.305 +	mp3_mad->output_begin = 0;
   8.306 +	mp3_mad->output_end = 0;
   8.307 +
   8.308 +	SDL_RWseek(mp3_mad->rw, 0, SEEK_SET);
   8.309 +  }
   8.310 +
   8.311 +  /* Now we have to skip frames until we come to the right one.
   8.312 +	 Again, only truly necessary if the file is VBR. */
   8.313 +  while (mad_timer_compare(mp3_mad->next_frame_start, target) < 0) {
   8.314 +	if (!read_next_frame(mp3_mad)) {
   8.315 +	  if ((mp3_mad->status & MS_error_flags) != 0) {
   8.316 +		/* Couldn't read a frame; either an error condition or
   8.317 +		   end-of-file.  Stop. */
   8.318 +		mp3_mad->status &= ~MS_playing;
   8.319 +		return;
   8.320 +	  }
   8.321 +	}
   8.322 +  }
   8.323 +
   8.324 +  /* Here we are, at the beginning of the frame that contains the
   8.325 +	 target time.  Ehh, I say that's close enough.  If we wanted to,
   8.326 +	 we could get more precise by decoding the frame now and counting
   8.327 +	 the appropriate number of samples out of it. */
   8.328 +}
   8.329 +
   8.330 +void
   8.331 +mad_setVolume(mad_data *mp3_mad, int volume) {
   8.332 +  mp3_mad->volume = volume;
   8.333 +}
   8.334 +
   8.335 +
   8.336 +#endif  /* MP3_MAD_MUSIC */
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/music_mad.h	Sun Jul 15 05:33:35 2007 +0000
     9.3 @@ -0,0 +1,73 @@
     9.4 +/*
     9.5 +    SDL_mixer:  An audio mixer library based on the SDL library
     9.6 +    Copyright (C) 1997-2004 Sam Lantinga
     9.7 +
     9.8 +    This library is free software; you can redistribute it and/or
     9.9 +    modify it under the terms of the GNU Library General Public
    9.10 +    License as published by the Free Software Foundation; either
    9.11 +    version 2 of the License, or (at your option) any later version.
    9.12 +
    9.13 +    This library is distributed in the hope that it will be useful,
    9.14 +    but WITHOUT ANY WARRANTY; without even the implied warranty of
    9.15 +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    9.16 +    Library General Public License for more details.
    9.17 +
    9.18 +    You should have received a copy of the GNU Library General Public
    9.19 +    License along with this library; if not, write to the Free
    9.20 +    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    9.21 +
    9.22 +    Sam Lantinga
    9.23 +    slouken@libsdl.org
    9.24 +*/
    9.25 +
    9.26 +#ifdef MP3_MAD_MUSIC
    9.27 +
    9.28 +#include "mad.h"
    9.29 +#include "SDL_rwops.h"
    9.30 +#include "SDL_audio.h"
    9.31 +#include "SDL_mixer.h"
    9.32 +
    9.33 +#define MAD_INPUT_BUFFER_SIZE	(5*8192)
    9.34 +#define MAD_OUTPUT_BUFFER_SIZE	8192
    9.35 +
    9.36 +enum {
    9.37 +  MS_input_eof    = 0x0001,
    9.38 +  MS_input_error  = 0x0001,
    9.39 +  MS_decode_eof   = 0x0002,
    9.40 +  MS_decode_error = 0x0004,
    9.41 +  MS_error_flags  = 0x000f,
    9.42 +
    9.43 +  MS_playing      = 0x0100,
    9.44 +  MS_cvt_decoded  = 0x0200,
    9.45 +};
    9.46 +
    9.47 +typedef struct {
    9.48 +  SDL_RWops *rw;
    9.49 +  struct mad_stream stream;
    9.50 +  struct mad_frame frame;
    9.51 +  struct mad_synth synth;
    9.52 +  int frames_read;
    9.53 +  mad_timer_t next_frame_start;
    9.54 +  int volume;
    9.55 +  int status;
    9.56 +  int output_begin, output_end;
    9.57 +  SDL_AudioSpec mixer;
    9.58 +  SDL_AudioCVT cvt;
    9.59 +
    9.60 +  unsigned char input_buffer[MAD_INPUT_BUFFER_SIZE + MAD_BUFFER_GUARD];
    9.61 +  unsigned char output_buffer[MAD_OUTPUT_BUFFER_SIZE];
    9.62 +} mad_data;
    9.63 +
    9.64 +mad_data *mad_openFile(const char *filename, SDL_AudioSpec *mixer);
    9.65 +mad_data *mad_openFileRW(SDL_RWops *rw, SDL_AudioSpec *mixer);
    9.66 +void mad_closeFile(mad_data *mp3_mad);
    9.67 +
    9.68 +void mad_start(mad_data *mp3_mad);
    9.69 +void mad_stop(mad_data *mp3_mad);
    9.70 +int mad_isPlaying(mad_data *mp3_mad);
    9.71 +
    9.72 +void mad_getSamples(mad_data *mp3_mad, Uint8 *stream, int len);
    9.73 +void mad_seek(mad_data *mp3_mad, double position);
    9.74 +void mad_setVolume(mad_data *mp3_mad, int volume);
    9.75 +
    9.76 +#endif