MP3 Player without external hardware MP3 Player without external hardware. A software based MP3 player based on a modified version of libmad. Mono output (at the moment) via AnalogOut. Files are read from an USB drive. This is a demo program, it plays only one file at the moment. Documentation is in "main.cpp" and "config.h"

Dependencies:   mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 /* This file demonstrates the use of the modified libmad library on LPC1768
00002  * Changes to the library are documented in config.h.
00003  *
00004  * The main change is to use parts of the AHB RAM dedicated to the ethernet module,
00005  * because standard RAM is not sufficient for decoding.
00006  * This means the ethernet module cannot be used !!!
00007  *
00008  * It plays a file "test.mp3" from an external USB-drive/USB-stick. 
00009  * For wiring of the USB-connector, see mbed.org
00010  * ID3 decoding is not present at the moment and will cause warnings 
00011  * on stderr, and some short noise at the beginning or end of playback.
00012  *
00013  * Output is only for one channel on the DAC (AnalogOut) pin.
00014  * (For connections see datasheets/mbed.org)
00015  * This pin should be decoupled with a capacitor (100u or so) to remove DC.
00016  * The output current is high enough to drive small headphones or active 
00017  * speakers directly.
00018  *
00019  * Schematic: :-)          
00020  *  MBED Pin 18 (AOut)  o--||--o  Headphone Left
00021  *  MBED Pin 1 (GND)    o------o  Headphone Common
00022  *
00023  * It has been tested with fixed bitrate MP3's up to 320kbps and VBR files.
00024  * 
00025  * The remaining RAM is very limited, so don't overuse it !
00026  * The MSCFileSystem library from mbed.org is needed !
00027  * Last warning: the main include file "mad.h" maybe not up to date,
00028  * use "decoder.h" for now
00029  * Have fun, 
00030  *   Andreas Gruen 
00031  * *** Version 3:  ***
00032  * moved another memory block into AHB RAM, giving more room for
00033  * stereo buffer.
00034  * moved content of decode() to main()
00035  * decoding is now safe to be called multiple times (bug in older versions)
00036  * Output routine now fills stereo buffer, DAC output sums channels,
00037  * just for demonstration that stereo output could go here
00038  */
00039 
00040 #include "mbed.h"
00041 # include "decoder.h"
00042 
00043 FILE *fp;
00044 #include "MSCFileSystem.h"
00045 MSCFileSystem fs("usb");
00046 
00047 static enum mad_flow input(void *data,struct mad_stream *stream);
00048 static enum mad_flow output(void *data,struct mad_header const *header,struct mad_pcm *pcm);
00049 static enum mad_flow error_fn(void *data,struct mad_stream *stream,struct mad_frame *frame);
00050 
00051 struct dacout_s {
00052   unsigned short l;
00053   unsigned short r;
00054  };
00055 
00056 volatile dacout_s dacbuf[1152];
00057 volatile dacout_s *dac_s, *dac_e;
00058 
00059 AnalogOut dac(p18);
00060 Ticker dacclk;
00061 
00062 void dacout(void)
00063 {
00064   if(dac_s < dac_e)  
00065   {
00066     dac.write_u16((dac_s->l/2)+(dac_s->r/2));
00067     dac_s++;
00068   }
00069 }
00070 
00071 int main(int argc, char *argv[])
00072 {
00073   int result;
00074   Timer t;
00075   struct mad_decoder decoder;
00076 
00077   dac_s = dac_e = dacbuf;
00078   dacclk.attach_us(dacout,23);
00079   while(1) {
00080       fp = fopen("/usb/test.mp3","rb");
00081     
00082       if(!fp)  return(printf("file error\r\n"));
00083       fprintf(stderr,"decode start\r\n");
00084       mad_decoder_init(&decoder, NULL,input, 0, 0, output,error_fn, 0);
00085       t.reset();
00086       t.start();
00087       result = mad_decoder_run(&decoder, MAD_DECODER_MODE_SYNC);
00088       t.stop();
00089       fprintf(stderr,"decode ret=%d in %d ms\r\n",result,t.read_ms());
00090       mad_decoder_finish(&decoder);
00091       fclose(fp);
00092     }
00093   return 0;
00094 }
00095 
00096 /*
00097  * This is the input callback. The purpose of this callback is to (re)fill
00098  * the stream buffer which is to be decoded. 
00099  */
00100 
00101 static
00102 enum mad_flow input(void *data,
00103             struct mad_stream *stream)
00104 {
00105   static unsigned char strmbuff[2100];
00106   int ret;
00107   int rsz;
00108   unsigned char *bp;
00109 
00110   /* the remaining bytes from incomplete frames must be copied
00111   to the beginning of the new buffer !
00112   */
00113   bp = strmbuff;
00114   rsz = 0;
00115   if(stream->error == MAD_ERROR_BUFLEN||stream->buffer==NULL)
00116     {
00117     if(stream->next_frame!=NULL)   
00118       {   
00119          rsz = stream->bufend-stream->next_frame;
00120          memmove(strmbuff,stream->next_frame,rsz);
00121          bp = strmbuff+rsz;
00122       } 
00123     }
00124 
00125   ret = fread(bp,1,sizeof(strmbuff) - rsz,fp);
00126 
00127   if (!ret)
00128     return MAD_FLOW_STOP;
00129 
00130 
00131   mad_stream_buffer(stream, strmbuff, ret + rsz);
00132 
00133   return MAD_FLOW_CONTINUE;}
00134 
00135 
00136 /*
00137  * The following utility routine performs simple rounding, clipping, and
00138  * scaling of MAD's high-resolution samples down to 16 bits. It does not
00139  * perform any dithering or noise shaping, which would be recommended to
00140  * obtain any exceptional audio quality. It is therefore not recommended to
00141  * use this routine if high-quality output is desired.
00142  */
00143 
00144 static /*inline*/
00145 signed int scale(mad_fixed_t sample)
00146 {
00147   /* round */
00148   sample += (1L << (MAD_F_FRACBITS - 16));
00149 
00150   /* clip */
00151   if (sample >= MAD_F_ONE)
00152     sample = MAD_F_ONE - 1;
00153   else if (sample < -MAD_F_ONE)
00154     sample = -MAD_F_ONE;
00155 
00156   /* quantize */
00157   return sample >> (MAD_F_FRACBITS + 1 - 16);
00158 }
00159 
00160 /*
00161  * This is the output callback function. It is called after each frame of
00162  * MPEG audio data has been completely decoded. The purpose of this callback
00163  * is to output (or play) the decoded PCM audio.
00164  */
00165 
00166 static
00167 enum mad_flow output(void *data,
00168              struct mad_header const *header,
00169              struct mad_pcm *pcm)
00170 {
00171   unsigned int nchannels, nsamples;
00172   mad_fixed_t const *left_ch, *right_ch;
00173 
00174 
00175   /* pcm->samplerate contains the sampling frequency */
00176   nchannels = pcm->channels;
00177   nsamples  = pcm->length;
00178   left_ch   = pcm->samples[0];
00179   right_ch  = pcm->samples[1];
00180 
00181   while(dac_s < dac_e) wait_us(1);
00182   dac_e = dacbuf;  // potential thread problem ??  no...
00183   dac_s = dacbuf;
00184 
00185   while (nsamples--) {
00186     signed int sample_l,sample_r;
00187     sample_l = scale(*left_ch);
00188     sample_r = scale(*right_ch);
00189     dac_e->l = sample_l  +32768;
00190     dac_e->r = sample_r  +32768;
00191     dac_e++;
00192     left_ch++;
00193     right_ch++;
00194   }
00195   return MAD_FLOW_CONTINUE;
00196 }
00197 
00198 /*
00199  * This is the error callback function. It is called whenever a decoding
00200  * error occurs. The error is indicated by stream->error; the list of
00201  * possible MAD_ERROR_* errors can be found in the mad.h (or stream.h)
00202  * header file.
00203  */
00204 
00205 static
00206 enum mad_flow error_fn(void *data,
00207             struct mad_stream *stream,
00208             struct mad_frame *frame)
00209 {
00210   /* ID3 tags will cause warnings and short noise, ignore it for the moment*/
00211 
00212   fprintf(stderr, "decoding error 0x%04x (%s)\n",
00213       stream->error, mad_stream_errorstr(stream));
00214       
00215 
00216   /* return MAD_FLOW_BREAK here to stop decoding (and propagate an error) */
00217 
00218   return MAD_FLOW_CONTINUE;
00219 }
00220 
00221