music_mad.c
author Sam Lantinga <slouken@libsdl.org>
Sun, 08 Nov 2009 17:11:09 +0000
changeset 473 60b7e1c4f6b2
parent 407 73a92ea2c061
child 518 8bc9b5fd2aae
permissions -rw-r--r--
Use RW_SEEK constants for RWseek()
     1 /*
     2     SDL_mixer:  An audio mixer library based on the SDL library
     3     Copyright (C) 1997-2009 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     slouken@libsdl.org
    21 */
    22 
    23 #ifdef MP3_MAD_MUSIC
    24 
    25 #include <string.h>
    26 
    27 #include "music_mad.h"
    28 
    29 mad_data *
    30 mad_openFile(const char *filename, SDL_AudioSpec *mixer) {
    31   SDL_RWops *rw;
    32   mad_data *mp3_mad;
    33 
    34   rw = SDL_RWFromFile(filename, "rb");
    35   if (rw == NULL) {
    36 	return NULL;
    37   }
    38 
    39   mp3_mad = mad_openFileRW(rw, mixer);
    40   if (mp3_mad == NULL) {
    41 	SDL_FreeRW(rw);
    42 	return NULL;
    43   }
    44   mp3_mad->freerw = SDL_TRUE;
    45   return mp3_mad;
    46 }
    47 
    48 mad_data *
    49 mad_openFileRW(SDL_RWops *rw, SDL_AudioSpec *mixer) {
    50   mad_data *mp3_mad;
    51 
    52   mp3_mad = (mad_data *)malloc(sizeof(mad_data));
    53   if (mp3_mad) {
    54 	mp3_mad->rw = rw;
    55 	mp3_mad->freerw = SDL_FALSE;
    56 	mad_stream_init(&mp3_mad->stream);
    57 	mad_frame_init(&mp3_mad->frame);
    58 	mad_synth_init(&mp3_mad->synth);
    59 	mp3_mad->frames_read = 0;
    60 	mad_timer_reset(&mp3_mad->next_frame_start);
    61 	mp3_mad->volume = MIX_MAX_VOLUME;
    62 	mp3_mad->status = 0;
    63 	mp3_mad->output_begin = 0;
    64 	mp3_mad->output_end = 0;
    65 	mp3_mad->mixer = *mixer;
    66   }
    67   return mp3_mad;
    68 }
    69 
    70 void
    71 mad_closeFile(mad_data *mp3_mad) {
    72   mad_stream_finish(&mp3_mad->stream);
    73   mad_frame_finish(&mp3_mad->frame);
    74   mad_synth_finish(&mp3_mad->synth);
    75 
    76   if (mp3_mad->freerw) {
    77 	SDL_FreeRW(mp3_mad->rw);
    78   }
    79   free(mp3_mad);
    80 }
    81 
    82 /* Starts the playback. */
    83 void
    84 mad_start(mad_data *mp3_mad) {
    85   mp3_mad->status |= MS_playing;
    86 }
    87 
    88 /* Stops the playback. */
    89 void 
    90 mad_stop(mad_data *mp3_mad) {
    91   mp3_mad->status &= ~MS_playing;
    92 }
    93 
    94 /* Returns true if the playing is engaged, false otherwise. */
    95 int
    96 mad_isPlaying(mad_data *mp3_mad) {
    97   return ((mp3_mad->status & MS_playing) != 0);
    98 }
    99 
   100 /* Reads the next frame from the file.  Returns true on success or
   101    false on failure. */
   102 static int
   103 read_next_frame(mad_data *mp3_mad) {
   104   if (mp3_mad->stream.buffer == NULL || 
   105 	  mp3_mad->stream.error == MAD_ERROR_BUFLEN) {
   106 	size_t read_size;
   107 	size_t remaining;
   108 	unsigned char *read_start;
   109 	
   110 	/* There might be some bytes in the buffer left over from last
   111 	   time.  If so, move them down and read more bytes following
   112 	   them. */
   113 	if (mp3_mad->stream.next_frame != NULL) {
   114 	  remaining = mp3_mad->stream.bufend - mp3_mad->stream.next_frame;
   115 	  memmove(mp3_mad->input_buffer, mp3_mad->stream.next_frame, remaining);
   116 	  read_start = mp3_mad->input_buffer + remaining;
   117 	  read_size = MAD_INPUT_BUFFER_SIZE - remaining;
   118 	  
   119 	} else {
   120 	  read_size = MAD_INPUT_BUFFER_SIZE;
   121 	  read_start = mp3_mad->input_buffer;
   122 	  remaining = 0;
   123 	}
   124 
   125 	/* Now read additional bytes from the input file. */
   126 	read_size = SDL_RWread(mp3_mad->rw, read_start, 1, read_size);
   127 	
   128 	if (read_size <= 0) {
   129 	  if ((mp3_mad->status & (MS_input_eof | MS_input_error)) == 0) {
   130 		if (read_size == 0) {
   131 		  mp3_mad->status |= MS_input_eof;
   132 		} else {
   133 		  mp3_mad->status |= MS_input_error;
   134 		}
   135 		
   136 		/* At the end of the file, we must stuff MAD_BUFFER_GUARD
   137 		   number of 0 bytes. */
   138 		memset(read_start + read_size, 0, MAD_BUFFER_GUARD);
   139 		read_size += MAD_BUFFER_GUARD;
   140 	  }
   141 	}
   142 	
   143 	/* Now feed those bytes into the libmad stream. */
   144 	mad_stream_buffer(&mp3_mad->stream, mp3_mad->input_buffer,
   145 					  read_size + remaining);
   146 	mp3_mad->stream.error = MAD_ERROR_NONE;
   147   }
   148   
   149   /* Now ask libmad to extract a frame from the data we just put in
   150 	 its buffer. */
   151   if (mad_frame_decode(&mp3_mad->frame, &mp3_mad->stream)) {
   152 	if (MAD_RECOVERABLE(mp3_mad->stream.error)) {
   153 	  return 0;
   154 	  
   155 	} else if (mp3_mad->stream.error == MAD_ERROR_BUFLEN) {
   156 	  return 0;
   157 	  
   158 	} else {
   159 	  mp3_mad->status |= MS_decode_error;
   160 	  return 0;
   161 	}
   162   }
   163   
   164   mp3_mad->frames_read++;
   165   mad_timer_add(&mp3_mad->next_frame_start, mp3_mad->frame.header.duration);
   166 
   167   return 1;
   168 }
   169 
   170 /* Scale a MAD sample to 16 bits for output. */
   171 static signed int
   172 scale(mad_fixed_t sample) {
   173   /* round */
   174   sample += (1L << (MAD_F_FRACBITS - 16));
   175 
   176   /* clip */
   177   if (sample >= MAD_F_ONE)
   178     sample = MAD_F_ONE - 1;
   179   else if (sample < -MAD_F_ONE)
   180     sample = -MAD_F_ONE;
   181 
   182   /* quantize */
   183   return sample >> (MAD_F_FRACBITS + 1 - 16);
   184 }
   185 
   186 /* Once the frame has been read, copies its samples into the output
   187    buffer. */
   188 static void
   189 decode_frame(mad_data *mp3_mad) {
   190   struct mad_pcm *pcm;
   191   unsigned int nchannels, nsamples;
   192   mad_fixed_t const *left_ch, *right_ch;
   193   unsigned char *out;
   194   int ret;
   195 
   196   mad_synth_frame(&mp3_mad->synth, &mp3_mad->frame);
   197   pcm = &mp3_mad->synth.pcm;
   198   out = mp3_mad->output_buffer + mp3_mad->output_end;
   199 
   200   if ((mp3_mad->status & MS_cvt_decoded) == 0) {
   201 	mp3_mad->status |= MS_cvt_decoded;
   202 
   203 	/* The first frame determines some key properties of the stream.
   204 	   In particular, it tells us enough to set up the convert
   205 	   structure now. */
   206 	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);
   207   }
   208 
   209   /* pcm->samplerate contains the sampling frequency */
   210 
   211   nchannels = pcm->channels;
   212   nsamples  = pcm->length;
   213   left_ch   = pcm->samples[0];
   214   right_ch  = pcm->samples[1];
   215 
   216   while (nsamples--) {
   217     signed int sample;
   218 
   219     /* output sample(s) in 16-bit signed little-endian PCM */
   220 
   221     sample = scale(*left_ch++);
   222     *out++ = ((sample >> 0) & 0xff);
   223     *out++ = ((sample >> 8) & 0xff);
   224 
   225     if (nchannels == 2) {
   226       sample = scale(*right_ch++);
   227       *out++ = ((sample >> 0) & 0xff);
   228       *out++ = ((sample >> 8) & 0xff);
   229     }
   230   }
   231 
   232   mp3_mad->output_end = out - mp3_mad->output_buffer;
   233   /*assert(mp3_mad->output_end <= MAD_OUTPUT_BUFFER_SIZE);*/
   234 }
   235 
   236 int
   237 mad_getSamples(mad_data *mp3_mad, Uint8 *stream, int len) {
   238   int bytes_remaining;
   239   int num_bytes;
   240   Uint8 *out;
   241 
   242   if ((mp3_mad->status & MS_playing) == 0) {
   243 	/* We're not supposed to be playing, so send silence instead. */
   244 	memset(stream, 0, len);
   245 	return;
   246   }
   247 
   248   out = stream;
   249   bytes_remaining = len;
   250   while (bytes_remaining > 0) {
   251 	if (mp3_mad->output_end == mp3_mad->output_begin) {
   252 	  /* We need to get a new frame. */
   253 	  mp3_mad->output_begin = 0;
   254 	  mp3_mad->output_end = 0;
   255 	  if (!read_next_frame(mp3_mad)) {
   256 		if ((mp3_mad->status & MS_error_flags) != 0) {
   257 		  /* Couldn't read a frame; either an error condition or
   258 			 end-of-file.  Stop. */
   259 		  memset(out, 0, bytes_remaining);
   260 		  mp3_mad->status &= ~MS_playing;
   261 		  return bytes_remaining;
   262 		}
   263 	  } else {
   264 		decode_frame(mp3_mad);
   265 
   266 		/* Now convert the frame data to the appropriate format for
   267 		   output. */
   268 		mp3_mad->cvt.buf = mp3_mad->output_buffer;
   269 		mp3_mad->cvt.len = mp3_mad->output_end;
   270 		
   271 		mp3_mad->output_end = (int)(mp3_mad->output_end * mp3_mad->cvt.len_ratio);
   272 		/*assert(mp3_mad->output_end <= MAD_OUTPUT_BUFFER_SIZE);*/
   273 		SDL_ConvertAudio(&mp3_mad->cvt);
   274 	  }
   275 	}
   276 
   277 	num_bytes = mp3_mad->output_end - mp3_mad->output_begin;
   278 	if (bytes_remaining < num_bytes) {
   279 	  num_bytes = bytes_remaining;
   280 	}
   281 
   282 	if (mp3_mad->volume == MIX_MAX_VOLUME) {
   283 	  memcpy(out, mp3_mad->output_buffer + mp3_mad->output_begin, num_bytes);
   284 	} else {
   285 	  SDL_MixAudio(out, mp3_mad->output_buffer + mp3_mad->output_begin,
   286 				   num_bytes, mp3_mad->volume);
   287 	}
   288 	out += num_bytes;
   289 	mp3_mad->output_begin += num_bytes;
   290 	bytes_remaining -= num_bytes;
   291   }
   292   return 0;
   293 }
   294 
   295 void
   296 mad_seek(mad_data *mp3_mad, double position) {
   297   mad_timer_t target;
   298   int int_part;
   299 
   300   int_part = (int)position;
   301   mad_timer_set(&target, int_part, 
   302 				(int)((position - int_part) * 1000000), 1000000);
   303 
   304   if (mad_timer_compare(mp3_mad->next_frame_start, target) > 0) {
   305 	/* In order to seek backwards in a VBR file, we have to rewind and
   306 	   start again from the beginning.  This isn't necessary if the
   307 	   file happens to be CBR, of course; in that case we could seek
   308 	   directly to the frame we want.  But I leave that little
   309 	   optimization for the future developer who discovers she really
   310 	   needs it. */
   311 	mp3_mad->frames_read = 0;
   312 	mad_timer_reset(&mp3_mad->next_frame_start);
   313 	mp3_mad->status &= ~MS_error_flags;
   314 	mp3_mad->output_begin = 0;
   315 	mp3_mad->output_end = 0;
   316 
   317 	SDL_RWseek(mp3_mad->rw, 0, RW_SEEK_SET);
   318   }
   319 
   320   /* Now we have to skip frames until we come to the right one.
   321 	 Again, only truly necessary if the file is VBR. */
   322   while (mad_timer_compare(mp3_mad->next_frame_start, target) < 0) {
   323 	if (!read_next_frame(mp3_mad)) {
   324 	  if ((mp3_mad->status & MS_error_flags) != 0) {
   325 		/* Couldn't read a frame; either an error condition or
   326 		   end-of-file.  Stop. */
   327 		mp3_mad->status &= ~MS_playing;
   328 		return;
   329 	  }
   330 	}
   331   }
   332 
   333   /* Here we are, at the beginning of the frame that contains the
   334 	 target time.  Ehh, I say that's close enough.  If we wanted to,
   335 	 we could get more precise by decoding the frame now and counting
   336 	 the appropriate number of samples out of it. */
   337 }
   338 
   339 void
   340 mad_setVolume(mad_data *mp3_mad, int volume) {
   341   mp3_mad->volume = volume;
   342 }
   343 
   344 
   345 #endif  /* MP3_MAD_MUSIC */