Main Page   Data Structures   File List   Data Fields   Globals  

mp3.c

Go to the documentation of this file.
00001 /***************************************************************************
00002  *   Copyright (C) 2006 by André Lindhjem <belgarat@sdf.lonestar.org>,     *
00003  *                         Kjetil Holien <kjetil.holien@gmail.com>,        *
00004  *                         Terje Risa <terje.risa@gmail.com> &             *
00005  *                         Øyvind Nerbråten <oyvind@nerbraten.com>         *
00006  *                                                                         *
00007  *   This program is free software; you can redistribute it and/or modify  *
00008  *   it under the terms of the GNU General Public License as published by  *
00009  *   the Free Software Foundation; either version 2 of the License, or     *
00010  *   (at your option) any later version.                                   *
00011  *                                                                         *
00012  *   This program is distributed in the hope that it will be useful,       *
00013  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00014  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00015  *   GNU General Public License for more details.                          *
00016  *                                                                         *
00017  *   You should have received a copy of the GNU General Public License     *
00018  *   along with this program; if not, write to the                         *
00019  *   Free Software Foundation, Inc.,                                       *
00020  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
00021  ***************************************************************************
00022  *
00023  * \file mp3.c
00024  * \author André Lindhjem, Kjetil Holien, Terje Risa & Øyvind Nerbråten
00025  * \date 15.02.2006
00026  * 
00027  * This code uses libmad0 to do mp3 decoding, and libao to do the audio output.
00028  * It borrows code from / are inspired by mpg321 and minimad.c.
00029  */
00030  
00031 /* * * Resources:
00032  * * * A good description of how mad works (the closest thing to an API we'll get?).
00033  * * * * http://trac.videolan.org/vlc/file/tags/v0_3_0/plugins/mad/API?rev=6952
00034  * * * http://www.mars.org/mailman/public/mad-dev/2001-August/000338.html
00035  * * * http://www.mars.org/mailman/public/mad-dev/2001-May/000244.html
00036 */
00037 
00038 #include <stdio.h>
00039 #include <unistd.h>
00040 #include <sys/stat.h>
00041 #include <sys/mman.h>
00042 #include <sys/types.h>
00043 #include <fcntl.h>
00044 #include <mad.h>
00045 #include <stdbool.h>
00046 #include <pthread.h>
00047 #include <assert.h>
00048 
00049 #include "common.h"     /* common project settings */
00050 #include "mp3.h"        /* handles mp3 decoding */
00051 #include "daisylibao.h" /* libao wrapper for the daisyplayer */
00052 #include "audio.h"      /* audio interface */
00053 #include "report.h"     /* report method */
00054 #include "snprintf/snprintf.h"
00055 #include "parsetime.h"
00056 
00057 
00058 
00059 /* ************************************************** *
00060  *          Static function declarations              *
00061  * ************************************************** */
00062 
00063 static
00064 enum                mad_flow input      (audio_data_t _data, struct mad_stream *stream);
00065 
00066 static
00067 __inline__
00068 signed long audio_linear_dither (unsigned int bits, mad_fixed_t sample,
00069                                  struct audio_dither *dither);
00070 
00071 static
00072 int                 mp3_decode          (struct_audio_data_t *data);
00073 
00074 static
00075 __inline__
00076 unsigned long       prng                (unsigned long state);
00077 
00078 static
00079 enum                mad_flow output     (audio_data_t _data, struct mad_header const *header, struct mad_pcm *pcm);
00080 
00081 static
00082 enum                mad_flow error      (audio_data_t _data, struct mad_stream *stream, struct mad_frame *frame);
00083 
00084 static
00085 enum                mad_flow header     (audio_data_t _data, struct mad_header const *header);
00086 
00087 static
00088 struct audio_dither * init_dither (void);
00089 
00090 static
00091 void reset_dither (struct audio_dither *dither);
00092 
00093 static
00094 void free_dither (struct audio_dither *dither);
00095 
00096 
00097 
00098 /* ************************************************** *
00099  *          Static function definitions               *
00100  * ************************************************** */
00101 
00112 static
00113 enum mad_flow input (audio_data_t data,
00114                      struct mad_stream *stream)
00115 {
00116     struct_audio_data_t *_data = data;
00117     
00118     pthread_mutex_lock (&_data->mutex);
00119     if (DEBUG_THREADS) printf ("mp3_input has mutex\n");
00120 
00121     if (!_data->buffer.buffer_length) {
00122         pthread_mutex_unlock (&_data->mutex);   /* release mutex - we're done with "data" */
00123         if (DEBUG_THREADS) printf ("mp3_input released mutex - stopping\n");
00124         return MAD_FLOW_STOP;
00125     } else {
00126 
00127         pthread_mutex_unlock (&_data->mutex);   /* release mutex - we're done with "data" */
00128         if (DEBUG_THREADS) printf ("mp3_input released mutex before mad_stream_buffer\n");
00129         /*TODO: We'll probably need to copy out _data->buffer.buffer_start, _data->buffer.buffer_length while we actually have the mutex */
00130         mad_stream_buffer (stream, _data->buffer.buffer_start, _data->buffer.buffer_length);
00131 /*      while (pthread_mutex_trylock (&data->mutex) == EBUSY) { printf ("mp3 input: retrying mutex after mad_stream_buffer\n"); }*/ /* get mutex - we work on "data" */     
00132         pthread_mutex_lock (&_data->mutex);
00133         if (DEBUG_THREADS) printf ("mp3_input got mutex after mad_stream_buffer\n");
00134         _data->buffer.buffer_length = 0;
00135         pthread_mutex_unlock (&_data->mutex);   /* release mutex - we're done with "data" */
00136         if (DEBUG_THREADS) printf ("mp3_input released mutex - continuing\n");
00137         return MAD_FLOW_CONTINUE;
00138     }
00139 }
00140 
00148 static
00149 __inline__
00150 signed long audio_linear_dither (unsigned int bits, mad_fixed_t sample,
00151                                  struct audio_dither *dither)
00152 {
00153     unsigned int scalebits;
00154     mad_fixed_t output, mask, random;
00155 
00156     enum {
00157         MIN = -MAD_F_ONE,
00158         MAX =  MAD_F_ONE - 1
00159     };
00160 
00161     assert (dither->magic == DITHER_MAGIC);
00162 
00163     /* noise shape */
00164     sample += dither->error[0] - dither->error[1] + dither->error[2];
00165 
00166     dither->error[2] = dither->error[1];
00167     dither->error[1] = dither->error[0] / 2;
00168 
00169     /* bias */
00170     output = sample + (1L << (MAD_F_FRACBITS + 1 - bits - 1));
00171 
00172     scalebits = MAD_F_FRACBITS + 1 - bits;
00173     mask = (1L << scalebits) - 1;
00174 
00175     /* dither */
00176     random  = prng (dither->random);
00177     output += (random & mask) - (dither->random & mask);
00178 
00179     dither->random = random;
00180 
00181     /* clip */
00182     if (output > MAX) {
00183         output = MAX;
00184 
00185         if (sample > MAX)
00186             sample = MAX;
00187     }
00188     else if (output < MIN) {
00189         output = MIN;
00190 
00191         if (sample < MIN)
00192             sample = MIN;
00193     }
00194 
00195     /* quantize */
00196     output &= ~mask;
00197 
00198     /* error feedback */
00199     dither->error[0] = sample - output;
00200 
00201     /* scale */
00202     return output >> scalebits;
00203 }
00204 
00211 static
00212 __inline__
00213 unsigned long prng (unsigned long state)
00214 {
00215   return (state * 0x0019660dL + 0x3c6ef35fL) & 0xffffffffL;
00216 }
00217 
00229 static
00230 enum mad_flow output (audio_data_t _data,
00231                       struct mad_header const *header,
00232                       struct mad_pcm *pcm)
00233 {
00234     struct_audio_data_t *data = _data;
00235     
00236     /* The buffer that we will tell libao to audio_play. 1152 is the max
00237      * buffer we will get from mad. Stereo and a 16bit samplesize
00238      * means that we'll  have to multiply it by 4 (2 channels * 2 bytes).
00239      */
00240     static unsigned char stream[1152 * 4];
00241     
00242     /* A pointer within the stream-buffer. It uses register keyword because
00243      * we'll probably use it alot */
00244     register unsigned char *ptr = stream;
00245 
00246     /* This contains our current sample. This is what we let libao
00247      * play */
00248     register signed int sample;
00249     
00250     /* This contains our temporary sample.
00251      * We will run audio_linear_dither and normalize this */
00252     register mad_fixed_t tempsample;
00253     
00254 /*    static struct audio_dither dither;*/
00255     
00256     unsigned int nchannels, nsamples, samplerate;
00257     mad_fixed_t const *left_ch, *right_ch;
00258 
00259 
00260     /* resetting the dither struct */
00261     pthread_mutex_lock(&data->mutex);
00262     reset_dither(data->mp3_dither);
00263 
00264     nchannels = pcm->channels;
00265     nsamples  = pcm->length;
00266     left_ch   = pcm->samples[0];
00267     right_ch  = pcm->samples[1];
00268 
00269     samplerate = pcm->samplerate;
00270 
00271     /* We need to know information about the file before we can open the
00272      * playdevice in some cases. So, we do it here. */
00273     if (!data->device)  /* if ao haven't opened a playdevice yet */
00274     {
00275         if (DEBUG_MP3) report ("First time we play - initializing daisylibao", REP_DEBUG);
00276         data->device = libao_initiate((int) AO_FMT_LITTLE, (int) pcm->channels, (int) pcm->samplerate);
00277         assert (data->device != NULL);
00278     }
00279     /* if channels or samplerate changes. (this should never happen in
00280      * daisy-books) */
00281     else if ((nchannels != MAD_NCHANNELS(header) || samplerate != header->samplerate))
00282     {
00283         if (DEBUG_MP3) report ("channels or samplerate have changed!", REP_DEBUG);
00284         libao_terminate(data->device);
00285         data->device = libao_initiate(AO_FMT_LITTLE, pcm->channels, pcm->samplerate);
00286         assert (data->device != NULL);
00287     }
00288     
00289     pthread_mutex_unlock(&data->mutex);
00290     
00291     /*
00292      * Stereo.
00293      * Output sample(s) in 16-bit signed little-endian PCM.
00294      */
00295     if (pcm->channels == 2)
00296     {
00297         while (nsamples--) {
00298             tempsample = *left_ch++;
00299             sample = (signed int) audio_linear_dither(16, tempsample, data->mp3_dither);
00300             
00301             *ptr++ = (unsigned char) (sample >> 0); /* Assumes that words ar big-endian. If they're not, we'll need to switch the two following lines. */
00302             *ptr++ = (unsigned char) (sample >> 8);
00303             
00304             tempsample = *right_ch++;
00305             sample = (signed int) audio_linear_dither(16, tempsample, data->mp3_dither);
00306             
00307             *ptr++ = (unsigned char) (sample >> 0); /* Assumes that words ar big-endian. If they're not, we'll need to switch the two following lines. */
00308             *ptr++ = (unsigned char) (sample >> 8);
00309         }
00310         libao_play (data->device, stream, pcm->length * 4);
00311     }
00312 
00313     /*
00314      * Mono.
00315      * Output sample(s) in 16-bit signed little-endian PCM
00316      */
00317     else
00318     {
00319         while (nsamples--)
00320         {
00321             tempsample = *left_ch++;
00322             sample = (signed int) audio_linear_dither(16, tempsample, data->mp3_dither);
00323             
00324             *ptr++ = (unsigned char) (sample >> 0); /* Assumes that words ar big-endian. If they're not, we'll need to switch the two following lines. */
00325             *ptr++ = (unsigned char) (sample >> 8);
00326         }
00327         libao_play (data->device, stream, pcm->length * 2);
00328     }
00329     return MAD_FLOW_CONTINUE;   /* Continue decoding */
00330 }
00331 
00342 static
00343 enum mad_flow error (audio_data_t _data,
00344                      struct mad_stream *stream,
00345                      struct mad_frame *frame)
00346 {
00347     
00348     struct_audio_data_t *data = _data;
00349 
00350     frame = NULL;   /* we don't use this */
00351 
00352     if (DEBUG_MP3)  /* If debug is enabled, we report error messages. */
00353     {
00354         char error[STRLEN]; /* prepare an error-message */
00355         snprintf (error, sizeof (error), "decoding error 0x%04x (%s) at byte offset %u",
00356                  stream->error, mad_stream_errorstr(stream),
00357                  stream->this_frame - data->buffer.buffer_start);
00358         report (error, REP_DEBUG);  /* report the error-message */
00359     }
00360 
00361     /* return MAD_FLOW_BREAK here to stop decoding (and propagate an error) */
00362 
00363     return MAD_FLOW_CONTINUE;
00364 }
00365 
00372 static
00373 enum mad_flow header (audio_data_t data, struct mad_header const *header)
00374 {
00375     struct_audio_data_t *_data = data;
00376     long int progress_ms = 0;
00377 
00378     pthread_mutex_lock (&_data->mutex);
00379     /*if (DEBUG_THREADS) printf ("mp3_header got mutex\n");*/
00380 
00381     /* we increment our duration */
00382     _data->progress.fraction += header->duration.fraction;
00383     _data->progress.seconds  += header->duration.seconds;
00384     if (_data->progress.fraction > MAD_TIMER_RESOLUTION)
00385     {
00386         _data->progress.seconds  += _data->progress.fraction / MAD_TIMER_RESOLUTION;
00387         _data->progress.fraction %= MAD_TIMER_RESOLUTION;
00388     }
00389 
00390     /* compares progress agains start- and stop-points */
00391     if (_data->start.seconds > _data->progress.seconds) {
00392         pthread_mutex_unlock (&_data->mutex);   /* release mutex - we're done with "data" */
00393         /*if (DEBUG_THREADS) printf ("mp3_header released mutex\n");*/
00394         return MAD_FLOW_IGNORE;
00395     }
00396 
00397     if (_data->start.seconds == _data->progress.seconds && _data->start.fraction > _data->progress.fraction) {
00398         pthread_mutex_unlock (&_data->mutex);   /* release mutex - we're done with "data" */
00399         /*if (DEBUG_THREADS) printf ("mp3_header released mutex\n");*/
00400         return MAD_FLOW_IGNORE;
00401     }
00402 
00403     if ((_data->stop.seconds <= _data->progress.seconds) &&
00404         (_data->stop.fraction <= _data->progress.fraction))
00405     {
00406         if (DEBUG_MP3) report ("mp3.c Finished playing segment. return MAD_FLOW_STOP", REP_DEBUG);
00407         pthread_mutex_unlock (&_data->mutex);   /* release mutex - we're done with "data" */
00408         /*if (DEBUG_THREADS) printf ("mp3_header released mutex\n");*/
00409         return MAD_FLOW_STOP;
00410     }
00411 
00412     progress_ms = mad_timer_count(_data->progress, MAD_UNITS_MILLISECONDS); /* store our proress */
00413 
00414     pthread_mutex_unlock (&_data->mutex);   /* release mutex - we're done with "data" */
00415     /*if (DEBUG_THREADS) printf ("mp3_header released mutex before callback\n");*/
00416     if (callback (_data, progress_ms) == -1) {  /* STOP */
00417         /*if (DEBUG_MP3) report ("mp3.c: callback returned -1. stopping decoder", REP_DEBUG);*/
00418         return MAD_FLOW_STOP;
00419     }
00420 
00421     return MAD_FLOW_CONTINUE;
00422 }
00423 
00428 static
00429 struct audio_dither * init_dither (void)
00430 {
00431     struct audio_dither *dither = NULL;
00432     if ((dither = (struct audio_dither *) malloc (sizeof (struct audio_dither))) == NULL)
00433     {
00434         report("init_dither could not allocate memory", REP_CRITICAL);
00435     }
00436     dither->magic = DITHER_MAGIC;
00437     reset_dither (dither);
00438     return dither;
00439 }
00440 
00445 static
00446 void reset_dither (struct audio_dither *dither)
00447 {
00448     assert (dither->magic == DITHER_MAGIC);
00449     dither->error[0] = 0;
00450     dither->error[1] = 0;
00451     dither->error[2] = 0;
00452     dither->random = 0;
00453 }
00454 
00459 static
00460 void free_dither (struct audio_dither *dither)
00461 {
00462     if(dither->magic == DITHER_MAGIC)
00463     {
00464         dither->magic = 0x00000000;
00465         free (dither);
00466     }
00467 }
00468 
00469 
00480 static
00481 int mp3_decode (struct_audio_data_t *data)
00482 {
00483     struct mad_decoder decoder;
00484     int result;
00485 
00486     /* initialize the buffer-part of the audio_data struct */
00487     pthread_mutex_lock (&data->mutex);
00488     if (DEBUG_THREADS) printf ("mp3_decode has mutex\n");
00489     
00490     data->mp3_dither = init_dither ();  /* create a dither struct */    
00491     data->buffer.buffer_start = data->fdm;
00492     data->buffer.buffer_length = data->stat.st_size;
00493     pthread_mutex_unlock (&data->mutex);    /* release mutex - we're done with "data" */
00494 
00495     if (DEBUG_THREADS) printf ("mp3_decode released mutex\n");
00496     
00497     /* configure input, output, and error functions */
00498     mad_decoder_init (&decoder, /* mad decoder      */
00499                       data,     /* data structure   */
00500                       input,    /* input function   */
00501                       header,   /* header function  */
00502                       0,        /* filter function  */
00503                       output,   /* output function  */
00504                       error,    /* error function   */
00505                       0         /* message function */);
00506 
00507     result = mad_decoder_run (&decoder, MAD_DECODER_MODE_SYNC); /* start decoding */
00508 
00509     mad_decoder_finish (&decoder);  /* release the decoder */
00510 
00511     pthread_mutex_lock (&data->mutex);
00512     free_dither(data->mp3_dither);  /* free dither struct */
00513     pthread_mutex_unlock (&data->mutex);
00514     
00515     return result;
00516 }
00517 
00518 
00519 
00520 /* ************************************************** *
00521  *          Global function definitions               *
00522  * ************************************************** */
00523 
00530 void mp3_init (struct_audio_data_t *data)
00531 {
00532     pthread_mutex_lock (&data->mutex);
00533     if (DEBUG_THREADS) printf ("mp3_init has mutex\n");
00534 
00535     /* Initializing the mp3 data struct */
00536     if (data == NULL) {
00537         data->cb_error (data->daisy, DAISY_ERROR_AUDIO_DATA_IS_NULL, NULL);
00538         report ("data pointer is NULL.", REP_CRITICAL);
00539     }
00540     if (DEBUG_MP3) report("initializing audio_data", REP_DEBUG);
00541     data->progress.fraction = 0;
00542     data->progress.seconds  = 0;
00543     
00544     /* output device should be NULL if it's not initialized already */
00545     data->device = NULL;
00546     
00547     pthread_mutex_unlock (&data->mutex);    /* release mutex - we're done with "data" */
00548     if (DEBUG_THREADS) printf ("mp3_init released mutex\n");
00549 }
00550 
00558 bool mp3_play (struct_audio_data_t *data)
00559 {
00560     pthread_mutex_lock (&data->mutex);
00561     if (DEBUG_THREADS) printf ("mp3_play has mutex\n");
00562     data->progress.seconds = 0; /* initialize some data in the audio_data struct */
00563     data->progress.fraction = 0;
00564     pthread_mutex_unlock (&data->mutex);    /* release mutex - we're done with data */
00565     if (DEBUG_THREADS) printf ("mp3_play released mutex\n");
00566 
00567     if (DEBUG_MP3)
00568     {
00569         char msg[STRLEN];
00570         snprintf (msg, sizeof (msg), "mp3_play: Starting mp3 decoding.\nFile: %s\tMemory pos: %p", data->file_name, data->fdm);
00571         report(msg, REP_DEBUG);
00572     }
00573 
00574     mp3_decode (data);  /* start decoding the data */
00575     return false;
00576 }
00577 
00583 void mp3_close (struct_audio_data_t *data)
00584 {
00585     libao_terminate (data->device); /* freeing daisyLibao */
00586 }

Generated on Tue Sep 5 12:14:07 2006 for libdaisy by doxygen1.2.15