Index: README
===================================================================
RCS file: /cvs/SDL_mixer/README,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -u -r1.1.1.1 -r1.2
--- README	29 Jun 2006 06:06:41 -0000	1.1.1.1
+++ README	29 Jun 2006 06:09:05 -0000	1.2
@@ -7,7 +7,7 @@
 Due to popular demand, here is a simple multi-channel audio mixer.
 It supports 8 channels of 16 bit stereo audio, plus a single channel
 of music, mixed by the popular MikMod MOD, Timidity MIDI and SMPEG MP3
-libraries.
+(or libmad MP3) libraries.
 
 See the header file SDL_mixer.h and the examples playwave.c and playmus.c
 for documentation on this mixer library.
@@ -16,7 +16,8 @@
 files as audio samples, and can load MIDI files via Timidity and the
 following music formats via MikMod:  .MOD .S3M .IT .XM. It can load
 Ogg Vorbis streams as music if built with the Ogg Vorbis libraries,
-and finally it can load MP3 music using the SMPEG library.
+and finally it can load MP3 music using either the SMPEG or the libmad
+libraries.
 
 The process of mixing MIDI files to wave output is very CPU intensive,
 so if playing regular WAVE files sound great, but playing MIDI files
Index: SDL_mixer.h
===================================================================
RCS file: /cvs/SDL_mixer/SDL_mixer.h,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -u -r1.1.1.1 -r1.2
--- SDL_mixer.h	29 Jun 2006 06:06:41 -0000	1.1.1.1
+++ SDL_mixer.h	29 Jun 2006 06:09:05 -0000	1.2
@@ -20,7 +20,7 @@
     slouken@libsdl.org
 */
 
-/* $Id: SDL_mixer.h,v 1.1.1.1 2006/06/29 06:06:41 drose Exp $ */
+/* $Id: SDL_mixer.h,v 1.2 2006/06/29 06:09:05 drose Exp $ */
 
 #ifndef _SDL_MIXER_H
 #define _SDL_MIXER_H
@@ -103,7 +103,8 @@
 	MUS_MOD,
 	MUS_MID,
 	MUS_OGG,
-	MUS_MP3
+	MUS_MP3,
+	MUS_MP3_MAD
 } Mix_MusicType;
 
 /* The internal format for a music chunk interpreted via mikmod */
Index: SDL_mixer.spec
===================================================================
RCS file: /cvs/SDL_mixer/SDL_mixer.spec,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -u -r1.1.1.1 -r1.2
--- SDL_mixer.spec	29 Jun 2006 06:06:41 -0000	1.1.1.1
+++ SDL_mixer.spec	29 Jun 2006 06:09:05 -0000	1.2
@@ -16,7 +16,7 @@
 Due to popular demand, here is a simple multi-channel audio mixer.
 It supports 4 channels of 16 bit stereo audio, plus a single channel
 of music, mixed by the popular MikMod MOD, Timidity MIDI and SMPEG MP3
-libraries.
+(or libmad MP3) libraries.
 
 %package devel
 Summary: Libraries, includes and more to develop SDL applications.
@@ -27,7 +27,7 @@
 Due to popular demand, here is a simple multi-channel audio mixer.
 It supports 4 channels of 16 bit stereo audio, plus a single channel
 of music, mixed by the popular MikMod MOD, Timidity MIDI and SMPEG MP3
-libraries.
+(or libmad MP3) libraries.
 
 %prep
 %setup 
Index: SDL_mixer.spec.in
===================================================================
RCS file: /cvs/SDL_mixer/SDL_mixer.spec.in,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -u -r1.1.1.1 -r1.2
--- SDL_mixer.spec.in	29 Jun 2006 06:06:07 -0000	1.1.1.1
+++ SDL_mixer.spec.in	29 Jun 2006 06:09:05 -0000	1.2
@@ -16,7 +16,7 @@
 Due to popular demand, here is a simple multi-channel audio mixer.
 It supports 4 channels of 16 bit stereo audio, plus a single channel
 of music, mixed by the popular MikMod MOD, Timidity MIDI and SMPEG MP3
-libraries.
+(or libmad MP3) libraries.
 
 %package devel
 Summary: Libraries, includes and more to develop SDL applications.
@@ -27,7 +27,7 @@
 Due to popular demand, here is a simple multi-channel audio mixer.
 It supports 4 channels of 16 bit stereo audio, plus a single channel
 of music, mixed by the popular MikMod MOD, Timidity MIDI and SMPEG MP3
-libraries.
+(or libmad MP3) libraries.
 
 %prep
 %setup 
Index: configure
===================================================================
RCS file: /cvs/SDL_mixer/configure,v
retrieving revision 1.1.1.1
retrieving revision 1.3
diff -u -r1.1.1.1 -r1.3
--- configure	29 Jun 2006 06:06:41 -0000	1.1.1.1
+++ configure	1 Jul 2006 05:16:29 -0000	1.3
@@ -1047,6 +1047,7 @@
   --disable-smpegtest       Do not try to compile and run a test SMPEG program
   --enable-music-mp3-shared
                           dynamically load MP3 support [default=yes]
+  --enable-music-mp3-mad  enable MP3 music via libmad [default=no]
 
 Optional Packages:
   --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
@@ -3155,7 +3156,7 @@
   ;;
 *-*-irix6*)
   # Find out which ABI we are using.
-  echo '#line 3158 "configure"' > conftest.$ac_ext
+  echo '#line 3159 "configure"' > conftest.$ac_ext
   if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
   (eval $ac_compile) 2>&5
   ac_status=$?
@@ -4887,7 +4888,7 @@
 
 
 # Provide some information about the compiler.
-echo "$as_me:4890:" \
+echo "$as_me:4891:" \
      "checking for Fortran 77 compiler version" >&5
 ac_compiler=`set X $ac_compile; echo $2`
 { (eval echo "$as_me:$LINENO: \"$ac_compiler --version </dev/null >&5\"") >&5
@@ -5960,11 +5961,11 @@
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:5963: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:5964: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>conftest.err)
    ac_status=$?
    cat conftest.err >&5
-   echo "$as_me:5967: \$? = $ac_status" >&5
+   echo "$as_me:5968: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s "$ac_outfile"; then
      # The compiler can only warn and ignore the option if not recognized
      # So say no if there are warnings other than the usual output.
@@ -6228,11 +6229,11 @@
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:6231: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:6232: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>conftest.err)
    ac_status=$?
    cat conftest.err >&5
-   echo "$as_me:6235: \$? = $ac_status" >&5
+   echo "$as_me:6236: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s "$ac_outfile"; then
      # The compiler can only warn and ignore the option if not recognized
      # So say no if there are warnings other than the usual output.
@@ -6332,11 +6333,11 @@
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:6335: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:6336: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>out/conftest.err)
    ac_status=$?
    cat out/conftest.err >&5
-   echo "$as_me:6339: \$? = $ac_status" >&5
+   echo "$as_me:6340: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s out/conftest2.$ac_objext
    then
      # The compiler can only warn and ignore the option if not recognized
@@ -8679,7 +8680,7 @@
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<EOF
-#line 8682 "configure"
+#line 8683 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -8779,7 +8780,7 @@
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<EOF
-#line 8782 "configure"
+#line 8783 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -11123,11 +11124,11 @@
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:11126: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:11127: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>conftest.err)
    ac_status=$?
    cat conftest.err >&5
-   echo "$as_me:11130: \$? = $ac_status" >&5
+   echo "$as_me:11131: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s "$ac_outfile"; then
      # The compiler can only warn and ignore the option if not recognized
      # So say no if there are warnings other than the usual output.
@@ -11227,11 +11228,11 @@
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:11230: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:11231: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>out/conftest.err)
    ac_status=$?
    cat out/conftest.err >&5
-   echo "$as_me:11234: \$? = $ac_status" >&5
+   echo "$as_me:11235: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s out/conftest2.$ac_objext
    then
      # The compiler can only warn and ignore the option if not recognized
@@ -12799,11 +12800,11 @@
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:12802: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:12803: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>conftest.err)
    ac_status=$?
    cat conftest.err >&5
-   echo "$as_me:12806: \$? = $ac_status" >&5
+   echo "$as_me:12807: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s "$ac_outfile"; then
      # The compiler can only warn and ignore the option if not recognized
      # So say no if there are warnings other than the usual output.
@@ -12903,11 +12904,11 @@
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:12906: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:12907: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>out/conftest.err)
    ac_status=$?
    cat out/conftest.err >&5
-   echo "$as_me:12910: \$? = $ac_status" >&5
+   echo "$as_me:12911: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s out/conftest2.$ac_objext
    then
      # The compiler can only warn and ignore the option if not recognized
@@ -15112,11 +15113,11 @@
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:15115: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:15116: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>conftest.err)
    ac_status=$?
    cat conftest.err >&5
-   echo "$as_me:15119: \$? = $ac_status" >&5
+   echo "$as_me:15120: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s "$ac_outfile"; then
      # The compiler can only warn and ignore the option if not recognized
      # So say no if there are warnings other than the usual output.
@@ -15380,11 +15381,11 @@
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:15383: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:15384: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>conftest.err)
    ac_status=$?
    cat conftest.err >&5
-   echo "$as_me:15387: \$? = $ac_status" >&5
+   echo "$as_me:15388: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s "$ac_outfile"; then
      # The compiler can only warn and ignore the option if not recognized
      # So say no if there are warnings other than the usual output.
@@ -15484,11 +15485,11 @@
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:15487: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:15488: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>out/conftest.err)
    ac_status=$?
    cat out/conftest.err >&5
-   echo "$as_me:15491: \$? = $ac_status" >&5
+   echo "$as_me:15492: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s out/conftest2.$ac_objext
    then
      # The compiler can only warn and ignore the option if not recognized
@@ -20408,6 +20409,74 @@
         fi
     fi
 fi
+# Check whether --enable-music-mp3-mad or --disable-music-mp3-mad was given.
+if test "${enable_music_mp3_mad+set}" = set; then
+  enableval="$enable_music_mp3_mad"
+
+else
+  enable_music_mp3_mad=no
+fi;
+if test x$enable_music_mp3_mad = xyes; then
+    echo "$as_me:$LINENO: checking for libmad headers" >&5
+echo $ECHO_N "checking for libmad headers... $ECHO_C" >&6
+    have_libmad=no
+    cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+     #include "mad.h"
+
+int
+main ()
+{
+
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+
+    have_libmad=yes
+
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+    echo "$as_me:$LINENO: result: $have_libmad" >&5
+echo "${ECHO_T}$have_libmad" >&6
+    if test x$have_libmad = xyes; then
+        SOURCES="$SOURCES $srcdir/mp3_mad.c"
+        EXTRA_CFLAGS="$EXTRA_CFLAGS -DMP3_MAD_MUSIC"
+        EXTRA_LDFLAGS="$EXTRA_LDFLAGS -lmad"
+    fi
+fi
 
 OBJECTS=`echo $SOURCES | sed 's,[^ ]*/\([^ ]*\)\.c,$(objects)/\1.lo,g'`
 
Index: configure.in
===================================================================
RCS file: /cvs/SDL_mixer/configure.in,v
retrieving revision 1.1.1.1
retrieving revision 1.3
diff -u -r1.1.1.1 -r1.3
--- configure.in	29 Jun 2006 06:06:07 -0000	1.1.1.1
+++ configure.in	1 Jul 2006 05:14:21 -0000	1.3
@@ -292,6 +292,25 @@
         fi
     fi
 fi
+AC_ARG_ENABLE(music-mp3-mad,
+[  --enable-music-mp3-mad  enable MP3 music via libmad [[default=no]]],
+              , enable_music_mp3_mad=no)
+if test x$enable_music_mp3_mad = xyes; then
+    AC_MSG_CHECKING(for libmad headers)
+    have_libmad=no
+    AC_TRY_COMPILE([
+     #include "mad.h"
+    ],[
+    ],[
+    have_libmad=yes
+    ])
+    AC_MSG_RESULT($have_libmad)
+    if test x$have_libmad = xyes; then
+        SOURCES="$SOURCES $srcdir/mp3_mad.c"
+        EXTRA_CFLAGS="$EXTRA_CFLAGS -DMP3_MAD_MUSIC"
+        EXTRA_LDFLAGS="$EXTRA_LDFLAGS -lmad"
+    fi
+fi
 
 OBJECTS=`echo $SOURCES | sed 's,[[^ ]]*/\([[^ ]]*\)\.c,$(objects)/\1.lo,g'`
 
Index: mp3_mad.c
===================================================================
RCS file: mp3_mad.c
diff -N mp3_mad.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ mp3_mad.c	30 Jun 2006 23:55:43 -0000	1.3
@@ -0,0 +1,352 @@
+/*
+    SDL_mixer:  An audio mixer library based on the SDL library
+    Copyright (C) 1997-2004 Sam Lantinga
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public
+    License along with this library; if not, write to the Free
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+    Sam Lantinga
+    slouken@libsdl.org
+*/
+
+#ifdef MP3_MAD_MUSIC
+
+#include "mp3_mad.h"
+#include <stdio.h>
+#include <assert.h>
+#include <malloc.h>
+#include <string.h>
+
+
+mad_data *
+mad_openFile(const char *filename, SDL_AudioSpec *mixer) {
+  SDL_RWops *rw;
+
+  rw = SDL_RWFromFile(filename, "rb");
+  if (rw == NULL) {
+	return NULL;
+  }
+
+  return mad_openFileRW(rw, mixer);
+}
+
+mad_data *
+mad_openFileRW(SDL_RWops *rw, SDL_AudioSpec *mixer) {
+  mad_data *mp3_mad;
+
+  mp3_mad = (mad_data *)malloc(sizeof(mad_data));
+  mp3_mad->rw = rw;
+  mad_stream_init(&mp3_mad->stream);
+  mad_frame_init(&mp3_mad->frame);
+  mad_synth_init(&mp3_mad->synth);
+  mp3_mad->frames_read = 0;
+  mad_timer_reset(&mp3_mad->next_frame_start);
+  mp3_mad->volume = MIX_MAX_VOLUME;
+  mp3_mad->status = 0;
+  mp3_mad->output_begin = 0;
+  mp3_mad->output_end = 0;
+  mp3_mad->mixer = *mixer;
+
+  return mp3_mad;
+}
+
+void
+mad_closeFile(mad_data *mp3_mad) {
+  SDL_FreeRW(mp3_mad->rw);
+  mad_stream_finish(&mp3_mad->stream);
+  mad_frame_finish(&mp3_mad->frame);
+  mad_synth_finish(&mp3_mad->synth);
+
+  free(mp3_mad);
+}
+
+/* Starts the playback. */
+void
+mad_start(mad_data *mp3_mad) {
+  mp3_mad->status |= MS_playing;
+}
+
+/* Stops the playback. */
+void 
+mad_stop(mad_data *mp3_mad) {
+  mp3_mad->status &= ~MS_playing;
+}
+
+/* Returns true if the playing is engaged, false otherwise. */
+int
+mad_isPlaying(mad_data *mp3_mad) {
+  return ((mp3_mad->status & MS_playing) != 0);
+}
+
+/* Reads the next frame from the file.  Returns true on success or
+   false on failure. */
+static int
+read_next_frame(mad_data *mp3_mad) {
+  if (mp3_mad->stream.buffer == NULL || 
+	  mp3_mad->stream.error == MAD_ERROR_BUFLEN) {
+	size_t read_size;
+	size_t remaining;
+	unsigned char *read_start;
+	
+	/* There might be some bytes in the buffer left over from last
+	   time.  If so, move them down and read more bytes following
+	   them. */
+	if (mp3_mad->stream.next_frame != NULL) {
+	  remaining = mp3_mad->stream.bufend - mp3_mad->stream.next_frame;
+	  memmove(mp3_mad->input_buffer, mp3_mad->stream.next_frame, remaining);
+	  read_start = mp3_mad->input_buffer + remaining;
+	  read_size = MAD_INPUT_BUFFER_SIZE - remaining;
+	  
+	} else {
+	  read_size = MAD_INPUT_BUFFER_SIZE;
+	  read_start = mp3_mad->input_buffer;
+	  remaining = 0;
+	}
+
+	/* Now read additional bytes from the input file. */
+	read_size = SDL_RWread(mp3_mad->rw, read_start, 1, read_size);
+	
+	if (read_size <= 0) {
+	  if ((mp3_mad->status & (MS_input_eof | MS_input_error)) == 0) {
+		if (read_size == 0) {
+		  fprintf(stderr, "end of input stream\n");
+		  mp3_mad->status |= MS_input_eof;
+		} else {
+		  fprintf(stderr, "read error on input stream\n");
+		  mp3_mad->status |= MS_input_error;
+		}
+		
+		/* At the end of the file, we must stuff MAD_BUFFER_GUARD
+		   number of 0 bytes. */
+		memset(read_start + read_size, 0, MAD_BUFFER_GUARD);
+		read_size += MAD_BUFFER_GUARD;
+	  } else {
+		fprintf(stderr, "repeated eof\n");
+	  }
+	}
+	
+	/* Now feed those bytes into the libmad stream. */
+	mad_stream_buffer(&mp3_mad->stream, mp3_mad->input_buffer,
+					  read_size + remaining);
+	mp3_mad->stream.error = MAD_ERROR_NONE;
+  }
+  
+  /* Now ask libmad to extract a frame from the data we just put in
+	 its buffer. */
+  if (mad_frame_decode(&mp3_mad->frame, &mp3_mad->stream)) {
+	if (MAD_RECOVERABLE(mp3_mad->stream.error)) {
+	  return 0;
+	  
+	} else if (mp3_mad->stream.error == MAD_ERROR_BUFLEN) {
+	  return 0;
+	  
+	} else {
+	  fprintf(stderr,"unrecoverable frame level error (%s).\n",
+			  mad_stream_errorstr(&mp3_mad->stream));
+	  mp3_mad->status |= MS_decode_error;
+	  return 0;
+	}
+  }
+  
+  mp3_mad->frames_read++;
+  mad_timer_add(&mp3_mad->next_frame_start, mp3_mad->frame.header.duration);
+
+  return 1;
+}
+
+/* Scale a MAD sample to 16 bits for output. */
+static signed int
+scale(mad_fixed_t sample) {
+  /* round */
+  sample += (1L << (MAD_F_FRACBITS - 16));
+
+  /* clip */
+  if (sample >= MAD_F_ONE)
+    sample = MAD_F_ONE - 1;
+  else if (sample < -MAD_F_ONE)
+    sample = -MAD_F_ONE;
+
+  /* quantize */
+  return sample >> (MAD_F_FRACBITS + 1 - 16);
+}
+
+/* Once the frame has been read, copies its samples into the output
+   buffer. */
+static void
+decode_frame(mad_data *mp3_mad) {
+  struct mad_pcm *pcm;
+  unsigned int nchannels, nsamples;
+  mad_fixed_t const *left_ch, *right_ch;
+  unsigned char *out;
+  int ret;
+
+  mad_synth_frame(&mp3_mad->synth, &mp3_mad->frame);
+  pcm = &mp3_mad->synth.pcm;
+  out = mp3_mad->output_buffer + mp3_mad->output_end;
+
+  if ((mp3_mad->status & MS_cvt_decoded) == 0) {
+	mp3_mad->status |= MS_cvt_decoded;
+
+	/* The first frame determines some key properties of the stream.
+	   In particular, it tells us enough to set up the convert
+	   structure now. */
+	ret = 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);
+	if (ret == -1) {
+	  fprintf(stderr, "Couldn't convert audio!\n");
+	}
+  }
+
+  /* pcm->samplerate contains the sampling frequency */
+
+  nchannels = pcm->channels;
+  nsamples  = pcm->length;
+  left_ch   = pcm->samples[0];
+  right_ch  = pcm->samples[1];
+
+  while (nsamples--) {
+    signed int sample;
+
+    /* output sample(s) in 16-bit signed little-endian PCM */
+
+    sample = scale(*left_ch++);
+    *out++ = ((sample >> 0) & 0xff);
+    *out++ = ((sample >> 8) & 0xff);
+
+    if (nchannels == 2) {
+      sample = scale(*right_ch++);
+      *out++ = ((sample >> 0) & 0xff);
+      *out++ = ((sample >> 8) & 0xff);
+    }
+  }
+
+  mp3_mad->output_end = out - mp3_mad->output_buffer;
+  assert(mp3_mad->output_end <= MAD_OUTPUT_BUFFER_SIZE);
+}
+
+void
+mad_getSamples(mad_data *mp3_mad, Uint8 *stream, int len) {
+  int bytes_remaining;
+  int num_bytes;
+  Uint8 *out;
+
+  if ((mp3_mad->status & MS_playing) == 0) {
+	/* We're not supposed to be playing, so send silence instead. */
+	memset(stream, 0, len);
+	return;
+  }
+
+  out = stream;
+  bytes_remaining = len;
+  while (bytes_remaining > 0) {
+	if (mp3_mad->output_end == mp3_mad->output_begin) {
+	  /* We need to get a new frame. */
+	  mp3_mad->output_begin = 0;
+	  mp3_mad->output_end = 0;
+	  if (!read_next_frame(mp3_mad)) {
+		if ((mp3_mad->status & MS_error_flags) != 0) {
+		  /* Couldn't read a frame; either an error condition or
+			 end-of-file.  Stop. */
+		  memset(out, 0, bytes_remaining);
+		  mp3_mad->status &= ~MS_playing;
+		  return;
+		}
+	  } else {
+		decode_frame(mp3_mad);
+
+		/* Now convert the frame data to the appropriate format for
+		   output. */
+		mp3_mad->cvt.buf = mp3_mad->output_buffer;
+		mp3_mad->cvt.len = mp3_mad->output_end;
+		
+		mp3_mad->output_end = (int)(mp3_mad->output_end * mp3_mad->cvt.len_ratio);
+		assert(mp3_mad->output_end <= MAD_OUTPUT_BUFFER_SIZE);
+		if (SDL_ConvertAudio(&mp3_mad->cvt) < 0) {
+		  fprintf(stderr, "Unable to convert!\n");
+		}
+	  }
+	}
+
+	num_bytes = mp3_mad->output_end - mp3_mad->output_begin;
+	if (bytes_remaining < num_bytes) {
+	  num_bytes = bytes_remaining;
+	}
+
+	if (mp3_mad->volume == MIX_MAX_VOLUME) {
+	  memcpy(out, mp3_mad->output_buffer + mp3_mad->output_begin, num_bytes);
+	} else {
+	  SDL_MixAudio(out, mp3_mad->output_buffer + mp3_mad->output_begin,
+				   num_bytes, mp3_mad->volume);
+	}
+	out += num_bytes;
+	mp3_mad->output_begin += num_bytes;
+	bytes_remaining -= num_bytes;
+  }
+}
+
+void
+mad_seek(mad_data *mp3_mad, double position) {
+  mad_timer_t target;
+  int int_part;
+
+  int_part = (int)position;
+  mad_timer_set(&target, int_part, 
+				(int)((position - int_part) * 1000000), 1000000);
+
+  if (mad_timer_compare(mp3_mad->next_frame_start, target) > 0) {
+	/* In order to seek backwards in a VBR file, we have to rewind and
+	   start again from the beginning.  This isn't necessary if the
+	   file happens to be CBR, of course; in that case we could seek
+	   directly to the frame we want.  But I leave that little
+	   optimization for the future developer who discovers she really
+	   needs it. */
+	mp3_mad->frames_read = 0;
+	mad_timer_reset(&mp3_mad->next_frame_start);
+	mp3_mad->status &= ~MS_error_flags;
+	mp3_mad->output_begin = 0;
+	mp3_mad->output_end = 0;
+
+	SDL_RWseek(mp3_mad->rw, 0, SEEK_SET);
+  }
+
+  /* Now we have to skip frames until we come to the right one.
+	 Again, only truly necessary if the file is VBR. */
+  while (mad_timer_compare(mp3_mad->next_frame_start, target) < 0) {
+	if (!read_next_frame(mp3_mad)) {
+	  if ((mp3_mad->status & MS_error_flags) != 0) {
+		/* Couldn't read a frame; either an error condition or
+		   end-of-file.  Stop. */
+		mp3_mad->status &= ~MS_playing;
+		return;
+	  }
+	}
+  }
+
+  /* Here we are, at the beginning of the frame that contains the
+	 target time.  Ehh, I say that's close enough.  If we wanted to,
+	 we could get more precise by decoding the frame now and counting
+	 the appropriate number of samples out of it. */
+}
+
+void
+mad_setVolume(mad_data *mp3_mad, int volume) {
+  mp3_mad->volume = volume;
+}
+
+
+#endif  /* MP3_MAD_MUSIC */
+
+
Index: mp3_mad.h
===================================================================
RCS file: mp3_mad.h
diff -N mp3_mad.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ mp3_mad.h	29 Jun 2006 16:27:25 -0000	1.2
@@ -0,0 +1,74 @@
+/*
+    SDL_mixer:  An audio mixer library based on the SDL library
+    Copyright (C) 1997-2004 Sam Lantinga
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public
+    License along with this library; if not, write to the Free
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+    Sam Lantinga
+    slouken@libsdl.org
+*/
+
+
+#ifdef MP3_MAD_MUSIC
+
+#include "mad.h"
+#include "SDL_rwops.h"
+#include "SDL_audio.h"
+#include "SDL_mixer.h"
+
+#define MAD_INPUT_BUFFER_SIZE	(5*8192)
+#define MAD_OUTPUT_BUFFER_SIZE	8192
+
+enum {
+  MS_input_eof    = 0x0001,
+  MS_input_error  = 0x0001,
+  MS_decode_eof   = 0x0002,
+  MS_decode_error = 0x0004,
+  MS_error_flags  = 0x000f,
+
+  MS_playing      = 0x0100,
+  MS_cvt_decoded  = 0x0200,
+};
+
+typedef struct {
+  SDL_RWops *rw;
+  struct mad_stream stream;
+  struct mad_frame frame;
+  struct mad_synth synth;
+  int frames_read;
+  mad_timer_t next_frame_start;
+  int volume;
+  int status;
+  int output_begin, output_end;
+  SDL_AudioSpec mixer;
+  SDL_AudioCVT cvt;
+
+  unsigned char input_buffer[MAD_INPUT_BUFFER_SIZE + MAD_BUFFER_GUARD];
+  unsigned char output_buffer[MAD_OUTPUT_BUFFER_SIZE];
+} mad_data;
+
+mad_data *mad_openFile(const char *filename, SDL_AudioSpec *mixer);
+mad_data *mad_openFileRW(SDL_RWops *rw, SDL_AudioSpec *mixer);
+void mad_closeFile(mad_data *mp3_mad);
+
+void mad_start(mad_data *mp3_mad);
+void mad_stop(mad_data *mp3_mad);
+int mad_isPlaying(mad_data *mp3_mad);
+
+void mad_getSamples(mad_data *mp3_mad, Uint8 *stream, int len);
+void mad_seek(mad_data *mp3_mad, double position);
+void mad_setVolume(mad_data *mp3_mad, int volume);
+
+#endif
Index: music.c
===================================================================
RCS file: /cvs/SDL_mixer/music.c,v
retrieving revision 1.1.1.1
retrieving revision 1.3
diff -u -r1.1.1.1 -r1.3
--- music.c	29 Jun 2006 06:06:08 -0000	1.1.1.1
+++ music.c	29 Jun 2006 16:27:25 -0000	1.3
@@ -20,7 +20,7 @@
     slouken@libsdl.org
 */
 
-/* $Id: music.c,v 1.1.1.1 2006/06/29 06:06:08 drose Exp $ */
+/* $Id: music.c,v 1.3 2006/06/29 16:27:25 drose Exp $ */
 
 #include <stdlib.h>
 #include <string.h>
@@ -85,10 +85,16 @@
 #endif
 #ifdef MP3_MUSIC
 #include "dynamic_mp3.h"
+#endif
+#ifdef MP3_MAD_MUSIC
+#include "mp3_mad.h"
+#endif
 
+#if defined(MP3_MUSIC) || defined(MP3_MAD_MUSIC)
 static SDL_AudioSpec used_mixer;
 #endif
 
+
 int volatile music_active = 1;
 static int volatile music_stopped = 0;
 static int music_loops = 0;
@@ -124,6 +130,9 @@
 #ifdef MP3_MUSIC
 		SMPEG *mp3;
 #endif
+#ifdef MP3_MAD_MUSIC
+		mad_data *mp3_mad;
+#endif
 	} data;
 	Mix_Fading fading;
 	int fade_step;
@@ -341,6 +350,11 @@
 				smpeg.SMPEG_playAudio(music_playing->data.mp3, stream, len);
 				break;
 #endif
+#ifdef MP3_MAD_MUSIC
+			case MUS_MP3_MAD:
+			    mad_getSamples(music_playing->data.mp3_mad, stream, len);
+				break;
+#endif
 			default:
 				/* Unknown music type?? */
 				break;
@@ -455,7 +469,7 @@
 		++music_error;
 	}
 #endif
-#ifdef MP3_MUSIC
+#if defined(MP3_MUSIC) || defined(MP3_MAD_MUSIC)
 	/* Keep a copy of the mixer */
 	used_mixer = *mixer;
 #endif
@@ -608,6 +622,20 @@
 		}
 	} else
 #endif
+#ifdef MP3_MAD_MUSIC
+	if ( (ext && MIX_string_equals(ext, "MPG")) ||
+	     (ext && MIX_string_equals(ext, "MP3")) ||
+	     (ext && MIX_string_equals(ext, "MPEG")) ||
+	     (ext && MIX_string_equals(ext, "MAD")) ||
+	     (magic[0] == 0xFF && (magic[1] & 0xF0) == 0xF0) ) {
+	    music->type = MUS_MP3_MAD;
+	    music->data.mp3_mad = mad_openFile(file, &used_mixer);
+		if (music->data.mp3_mad == 0) {
+		    Mix_SetError("Could not initialize MPEG stream.");
+			music->error = 1;
+		}
+	} else
+#endif
 #if defined(MOD_MUSIC) || defined(LIBMIKMOD_MUSIC)
 	if ( 1 ) {
 		music->type = MUS_MOD;
@@ -698,6 +726,11 @@
 				Mix_QuitMP3();
 				break;
 #endif
+#ifdef MP3_MAD_MUSIC
+			case MUS_MP3_MAD:
+			    mad_closeFile(music->data.mp3_mad);
+				break;
+#endif
 			default:
 				/* Unknown music type?? */
 				break;
@@ -787,6 +820,11 @@
 		smpeg.SMPEG_play(music_playing->data.mp3);
 		break;
 #endif
+#ifdef MP3_MAD_MUSIC
+	    case MUS_MP3_MAD:
+		mad_start(music->data.mp3_mad);
+		break;
+#endif
 	    default:
 		Mix_SetError("Can't play unknown music type");
 		retval = -1;
@@ -880,6 +918,11 @@
 		}
 		break;
 #endif
+#ifdef MP3_MAD_MUSIC
+	    case MUS_MP3_MAD:
+		mad_seek(music_playing->data.mp3_mad, position);
+		break;
+#endif
 	    default:
 		/* TODO: Implement this for other music backends */
 		retval = -1;
@@ -959,6 +1002,11 @@
 		smpeg.SMPEG_setvolume(music_playing->data.mp3,(int)(((float)volume/(float)MIX_MAX_VOLUME)*100.0));
 		break;
 #endif
+#ifdef MP3_MAD_MUSIC
+	    case MUS_MP3_MAD:
+		mad_setVolume(music_playing->data.mp3_mad, volume);
+		break;
+#endif
 	    default:
 		/* Unknown music type?? */
 		break;
@@ -1027,6 +1075,11 @@
 		smpeg.SMPEG_stop(music_playing->data.mp3);
 		break;
 #endif
+#ifdef MP3_MAD_MUSIC
+	    case MUS_MP3_MAD:
+		mad_stop(music_playing->data.mp3_mad);
+		break;
+#endif
 	    default:
 		/* Unknown music type?? */
 		return;
@@ -1170,6 +1223,13 @@
 			playing = 0;
 		break;
 #endif
+#ifdef MP3_MAD_MUSIC
+	    case MUS_MP3_MAD:
+		if (!mad_isPlaying(music_playing->data.mp3_mad)) {
+			playing = 0;
+		}
+		break;
+#endif
 	    default:
 		playing = 0;
 		break;
@@ -1408,6 +1468,16 @@
 		}
 	} else
 #endif
+#ifdef MP3_MAD_MUSIC
+	if ( magic[0] == 0xFF && (magic[1] & 0xF0) == 0xF0 ) {
+	    music->type = MUS_MP3_MAD;
+	    music->data.mp3_mad = mad_openFileRW(rw, &used_mixer);
+		if (music->data.mp3_mad == 0) {
+		    Mix_SetError("Could not initialize MPEG stream.");
+			music->error = 1;
+		}
+	} else
+#endif
 #ifdef MID_MUSIC
 	/* MIDI files have the magic four bytes "MThd" */
 	if ( strcmp((char *)magic, "MThd") == 0 ) {
