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

decoder.cpp

Committer:
Gruenfrosch
Date:
2010-11-27
Revision:
2:f28cf0afd021
Parent:
0:7627c79db971

File content as of revision 2:f28cf0afd021:

/*
 * libmad - MPEG audio decoder library
 * Copyright (C) 2000-2004 Underbit Technologies, Inc.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * $Id: decoder.c,v 1.1 2010/11/23 20:12:57 andy Exp $
 */

#  include "config.h"

# include "global.h"


# ifdef HAVE_SYS_TYPES_H
#  include <sys/types.h>
# endif

# ifdef HAVE_SYS_WAIT_H
#  include <sys/wait.h>
# endif

# ifdef HAVE_UNISTD_H
#  include <unistd.h>
# endif

# ifdef HAVE_FCNTL_H
#  include <fcntl.h>
# endif

# include <stdlib.h>

# ifdef HAVE_ERRNO_H
#  include <errno.h>
# endif

# include "stream.h"
# include "frame.h"
# include "synth.h"
# include "decoder.h"

/*
 * NAME:        decoder->init()
 * DESCRIPTION: initialize a decoder object with callback routines
 */
void mad_decoder_init(struct mad_decoder *decoder, void *data,
                      enum mad_flow (*input_func)(void *,
                                                  struct mad_stream *),
                      enum mad_flow (*header_func)(void *,
                                                   struct mad_header const *),
                      enum mad_flow (*filter_func)(void *,
                                                   struct mad_stream const *,
                                                   struct mad_frame *),
                      enum mad_flow (*output_func)(void *,
                                                   struct mad_header const *,
                                                   struct mad_pcm *),
                      enum mad_flow (*error_func)(void *,
                                                  struct mad_stream *,
                                                  struct mad_frame *),
                      enum mad_flow (*message_func)(void *,
                                                    void *, unsigned int *))
{
  decoder->mode         = (enum mad_decoder_mode)-1;

  decoder->options      = 0;


  decoder->sync         = 0;

  decoder->cb_data      = data;

  decoder->input_func   = input_func;
  decoder->header_func  = header_func;
  decoder->filter_func  = filter_func;
  decoder->output_func  = output_func;
  decoder->error_func   = error_func;
  decoder->message_func = message_func;
}

int mad_decoder_finish(struct mad_decoder *decoder)
{
  return 0;
}


static
enum mad_flow error_default(void *data, struct mad_stream *stream,
                            struct mad_frame *frame)
{
  int *bad_last_frame = (int *)data;

  switch (stream->error) {
  case MAD_ERROR_BADCRC:
    if (*bad_last_frame)
      mad_frame_mute(frame);
    else
      *bad_last_frame = 1;

    return MAD_FLOW_IGNORE;

  default:
    return MAD_FLOW_CONTINUE;
  }
}

static
int run_sync(struct mad_decoder *decoder)
{
  enum mad_flow (*error_func)(void *, struct mad_stream *, struct mad_frame *);
  void *error_data;
  int bad_last_frame = 0;
  struct mad_stream *stream;
  struct mad_frame *frame;
  struct mad_synth *synth;
  int result = 0;

  if (decoder->input_func == 0)
    return 0;

  if (decoder->error_func) {
    error_func = decoder->error_func;
    error_data = decoder->cb_data;
  }
  else {
    error_func = error_default;
    error_data = &bad_last_frame;
  }

  stream = &decoder->sync->stream;
  frame  = &decoder->sync->frame;
  synth  = decoder->sync->synth;

  mad_stream_init(stream);
  mad_frame_init(frame);
  mad_synth_init(synth);

  mad_stream_options(stream, decoder->options);

  do {
    switch (decoder->input_func(decoder->cb_data, stream)) {
    case MAD_FLOW_STOP:
      goto done;
    case MAD_FLOW_BREAK:
      goto fail;
    case MAD_FLOW_IGNORE:
      continue;
    case MAD_FLOW_CONTINUE:
      break;
    }

    while (1) {
      if (decoder->header_func) {
        if (mad_header_decode(&frame->header, stream) == -1) {
          if (!MAD_RECOVERABLE(stream->error))
            break;

          switch (error_func(error_data, stream, frame)) {
          case MAD_FLOW_STOP:
            goto done;
          case MAD_FLOW_BREAK:
            goto fail;
          case MAD_FLOW_IGNORE:
          case MAD_FLOW_CONTINUE:
          default:
            continue;
          }
        }

        switch (decoder->header_func(decoder->cb_data, &frame->header)) {
        case MAD_FLOW_STOP:
          goto done;
        case MAD_FLOW_BREAK:
          goto fail;
        case MAD_FLOW_IGNORE:
          continue;
        case MAD_FLOW_CONTINUE:
          break;
        }
      }

      if (mad_frame_decode(frame, stream) == -1) {
        if (!MAD_RECOVERABLE(stream->error))
          break;

        switch (error_func(error_data, stream, frame)) {
        case MAD_FLOW_STOP:
          goto done;
        case MAD_FLOW_BREAK:
          goto fail;
        case MAD_FLOW_IGNORE:
          break;
        case MAD_FLOW_CONTINUE:
        default:
          continue;
        }
      }
      else
        bad_last_frame = 0;

      if (decoder->filter_func) {
        switch (decoder->filter_func(decoder->cb_data, stream, frame)) {
        case MAD_FLOW_STOP:
          goto done;
        case MAD_FLOW_BREAK:
          goto fail;
        case MAD_FLOW_IGNORE:
          continue;
        case MAD_FLOW_CONTINUE:
          break;
        }
      }

      mad_synth_frame(synth, frame);

      if (decoder->output_func) {
        switch (decoder->output_func(decoder->cb_data,
                                     &frame->header, &synth->pcm)) {
        case MAD_FLOW_STOP:
          goto done;
        case MAD_FLOW_BREAK:
          goto fail;
        case MAD_FLOW_IGNORE:
        case MAD_FLOW_CONTINUE:
          break;
        }
      }
    }
  }
  while (stream->error == MAD_ERROR_BUFLEN);

 fail:
  result = -1;

 done:
  mad_synth_finish(synth);
  mad_frame_finish(frame);
  mad_stream_finish(stream);

  return result;
}


/*
 * NAME:        decoder->run()
 * DESCRIPTION: run the decoder thread either synchronously or asynchronously
 */
int mad_decoder_run(struct mad_decoder *decoder, enum mad_decoder_mode mode)
{
  int result;
  int (*run)(struct mad_decoder *) = 0;

  switch (decoder->mode = mode) {
  case MAD_DECODER_MODE_SYNC:
    run = run_sync;
    break;

  case MAD_DECODER_MODE_ASYNC:
    break;
  }

  if (run == 0)
    return -1;
  // static struct mad_sync_s sync_mem;
  decoder->sync = (struct mad_sync_s *)malloc(sizeof(*decoder->sync));
#if defined(TARGET_LPC1768)  
  decoder->sync->synth = (struct mad_synth *)mad_malloc(sizeof(struct mad_synth));
#else
  decoder->sync->synth = (struct mad_synth *)malloc(sizeof(struct mad_synth));
#endif
  if (decoder->sync == 0)
    return -1;

  result = run(decoder);
#if !defined(TARGET_LPC1768)  
  free(decoder->sync->synth);
#endif  
  free(decoder->sync);
  decoder->sync = 0;
  reset_ahb_mem();
  return result;
}

/*
 * NAME:        decoder->message()
 * DESCRIPTION: send a message to and receive a reply from the decoder process
 */
int mad_decoder_message(struct mad_decoder *decoder,
                        void *message, unsigned int *len)
{
  return -1;
}