streo mp3 player see: http://mbed.org/users/okini3939/notebook/I2S_AUDIO

Dependencies:   FatFileSystemCpp I2SSlave TLV320 mbed

Fork of madplayer by Andreas Grün

main.cpp

Committer:
Gruenfrosch
Date:
2010-11-27
Revision:
2:f28cf0afd021
Parent:
0:7627c79db971
Child:
3:6f07b5f52c38

File content as of revision 2:f28cf0afd021:

/* This file demonstrates the use of the modified libmad library on LPC1768
 * Changes to the library are documented in config.h.
 *
 * The main change is to use parts of the AHB RAM dedicated to the ethernet module,
 * because standard RAM is not sufficient for decoding.
 * This means the ethernet module cannot be used !!!
 *
 * It plays a file "test.mp3" from an external USB-drive/USB-stick. 
 * For wiring of the USB-connector, see mbed.org
 * ID3 decoding is not present at the moment and will cause warnings 
 * on stderr, and some short noise at the beginning or end of playback.
 *
 * Output is only for one channel on the DAC (AnalogOut) pin.
 * (For connections see datasheets/mbed.org)
 * This pin should be decoupled with a capacitor (100u or so) to remove DC.
 * The output current is high enough to drive small headphones or active 
 * speakers directly.
 *
 * Schematic: :-)		   
 *  MBED Pin 18 (AOut)  o--||--o  Headphone Left
 *	MBED Pin 1 (GND)	o------o  Headphone Common
 *
 * It has been tested with fixed bitrate MP3's up to 320kbps and VBR files.
 * 
 * The remaining RAM is very limited, so don't overuse it !
 * The MSCFileSystem library from mbed.org is needed !
 * Last warning: the main include file "mad.h" maybe not up to date,
 * use "decoder.h" for now
 * Have fun, 
 *   Andreas Gruen 
 * *** Version 3:  ***
 * moved another memory block into AHB RAM, giving more room for
 * stereo buffer.
 * moved content of decode() to main()
 * decoding	is now safe to be called multiple times (bug in older versions)
 * Output routine now fills stereo buffer, DAC output sums channels,
 * just for demonstration that stereo output could go here
 */

#include "mbed.h"
# include "decoder.h"

FILE *fp;
#include "MSCFileSystem.h"
MSCFileSystem fs("usb");

static enum mad_flow input(void *data,struct mad_stream *stream);
static enum mad_flow output(void *data,struct mad_header const *header,struct mad_pcm *pcm);
static enum mad_flow error_fn(void *data,struct mad_stream *stream,struct mad_frame *frame);

struct dacout_s {
  unsigned short l;
  unsigned short r;
 };

volatile dacout_s dacbuf[1152];
volatile dacout_s *dac_s, *dac_e;

AnalogOut dac(p18);
Ticker dacclk;

void dacout(void)
{
  if(dac_s < dac_e)  
  {
    dac.write_u16((dac_s->l/2)+(dac_s->r/2));
	dac_s++;
  }
}

int main(int argc, char *argv[])
{
  int result;
  Timer t;
  struct mad_decoder decoder;

  dac_s = dac_e = dacbuf;
  dacclk.attach_us(dacout,23);
  while(1) {
	  fp = fopen("/usb/test.mp3","rb");
	
	  if(!fp)  return(printf("file error\r\n"));
	  fprintf(stderr,"decode start\r\n");
	  mad_decoder_init(&decoder, NULL,input, 0, 0, output,error_fn, 0);
	  t.reset();
	  t.start();
	  result = mad_decoder_run(&decoder, MAD_DECODER_MODE_SYNC);
	  t.stop();
	  fprintf(stderr,"decode ret=%d in %d ms\r\n",result,t.read_ms());
	  mad_decoder_finish(&decoder);
	  fclose(fp);
	}
  return 0;
}

/*
 * This is the input callback. The purpose of this callback is to (re)fill
 * the stream buffer which is to be decoded. 
 */

static
enum mad_flow input(void *data,
            struct mad_stream *stream)
{
  static unsigned char strmbuff[2100];
  int ret;
  int rsz;
  unsigned char *bp;

  /* the remaining bytes from incomplete frames must be copied
  to the beginning of the new buffer !
  */
  bp = strmbuff;
  rsz = 0;
  if(stream->error == MAD_ERROR_BUFLEN||stream->buffer==NULL)
    {
    if(stream->next_frame!=NULL)   
      {   
         rsz = stream->bufend-stream->next_frame;
         memmove(strmbuff,stream->next_frame,rsz);
         bp = strmbuff+rsz;
      } 
    }

  ret = fread(bp,1,sizeof(strmbuff) - rsz,fp);

  if (!ret)
    return MAD_FLOW_STOP;


  mad_stream_buffer(stream, strmbuff, ret + rsz);

  return MAD_FLOW_CONTINUE;}


/*
 * The following utility routine performs simple rounding, clipping, and
 * scaling of MAD's high-resolution samples down to 16 bits. It does not
 * perform any dithering or noise shaping, which would be recommended to
 * obtain any exceptional audio quality. It is therefore not recommended to
 * use this routine if high-quality output is desired.
 */

static /*inline*/
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);
}

/*
 * This is the output callback function. It is called after each frame of
 * MPEG audio data has been completely decoded. The purpose of this callback
 * is to output (or play) the decoded PCM audio.
 */

static
enum mad_flow output(void *data,
             struct mad_header const *header,
             struct mad_pcm *pcm)
{
  unsigned int nchannels, nsamples;
  mad_fixed_t const *left_ch, *right_ch;


  /* pcm->samplerate contains the sampling frequency */
  nchannels = pcm->channels;
  nsamples  = pcm->length;
  left_ch   = pcm->samples[0];
  right_ch  = pcm->samples[1];

  while(dac_s < dac_e) wait_us(1);
  dac_e = dacbuf;  // potential thread problem ??  no...
  dac_s = dacbuf;

  while (nsamples--) {
    signed int sample_l,sample_r;
    sample_l = scale(*left_ch);
    sample_r = scale(*right_ch);
    dac_e->l = sample_l  +32768;
    dac_e->r = sample_r  +32768;
    dac_e++;
    left_ch++;
    right_ch++;
  }
  return MAD_FLOW_CONTINUE;
}

/*
 * This is the error callback function. It is called whenever a decoding
 * error occurs. The error is indicated by stream->error; the list of
 * possible MAD_ERROR_* errors can be found in the mad.h (or stream.h)
 * header file.
 */

static
enum mad_flow error_fn(void *data,
            struct mad_stream *stream,
            struct mad_frame *frame)
{
  /* ID3 tags will cause warnings and short noise, ignore it for the moment*/

  fprintf(stderr, "decoding error 0x%04x (%s)\n",
      stream->error, mad_stream_errorstr(stream));
      

  /* return MAD_FLOW_BREAK here to stop decoding (and propagate an error) */

  return MAD_FLOW_CONTINUE;
}