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"
Revision 2:f28cf0afd021, committed 2010-11-27
- Comitter:
- Gruenfrosch
- Date:
- Sat Nov 27 17:27:33 2010 +0000
- Parent:
- 1:7c923cbe9f1d
- Commit message:
- 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
Changed in this revision
diff -r 7c923cbe9f1d -r f28cf0afd021 config.h --- a/config.h Fri Nov 26 13:05:34 2010 +0000 +++ b/config.h Sat Nov 27 17:27:33 2010 +0000 @@ -42,7 +42,12 @@ # ifndef LIBMAD_CONFIG_H # define LIBMAD_CONFIG_H + +#if defined(TARGET_LPC1768) #include "mbed.h" +void *mad_malloc(unsigned int sz); +void reset_ahb_mem(void); +#endif /* config.h. Generated by configure. */ /* config.h.in. Generated from configure.ac by autoheader. */ @@ -53,6 +58,7 @@ /* used by ethernet */ #define AHBMEM ((void *)0x20080000) +#define AHBMEMSIZE 16300 #define FPM_DEFAULT /* Define to enable diagnostic debugging support. */ @@ -131,10 +137,10 @@ /* #undef OPT_ACCURACY */ /* Define to optimize for speed over accuracy. */ -/* #undef OPT_SPEED */ +/* #define OPT_SPEED */ /* Define to enable a fast subband synthesis approximation optimization. */ -/* #undef OPT_SSO */ +/* #define OPT_SSO */ /* Define to influence a strict interpretation of the ISO/IEC standards, even if this is in opposition with best accepted practices. */ @@ -182,4 +188,8 @@ /* Define to `int' if <sys/types.h> does not define. */ /* #undef pid_t */ + + +/* Define mad_malloc to malloc if no special mem handling required */ + #endif
diff -r 7c923cbe9f1d -r f28cf0afd021 decoder.cpp --- a/decoder.cpp Fri Nov 26 13:05:34 2010 +0000 +++ b/decoder.cpp Sat Nov 27 17:27:33 2010 +0000 @@ -76,9 +76,6 @@ decoder->options = 0; - decoder->async.pid = 0; - decoder->async.in = -1; - decoder->async.out = -1; decoder->sync = 0; @@ -94,202 +91,9 @@ int mad_decoder_finish(struct mad_decoder *decoder) { -# if defined(USE_ASYNC) - if (decoder->mode == MAD_DECODER_MODE_ASYNC && decoder->async.pid) { - pid_t pid; - int status; - - close(decoder->async.in); - - do - pid = waitpid(decoder->async.pid, &status, 0); - while (pid == -1 && errno == EINTR); - - decoder->mode = -1; - - close(decoder->async.out); - - decoder->async.pid = 0; - decoder->async.in = -1; - decoder->async.out = -1; - - if (pid == -1) - return -1; - - return (!WIFEXITED(status) || WEXITSTATUS(status)) ? -1 : 0; - } -# endif - return 0; } -# if defined(USE_ASYNC) -static -enum mad_flow send_io(int fd, void const *data, size_t len) -{ - char const *ptr = data; - ssize_t count; - - while (len) { - do - count = write(fd, ptr, len); - while (count == -1 && errno == EINTR); - - if (count == -1) - return MAD_FLOW_BREAK; - - len -= count; - ptr += count; - } - - return MAD_FLOW_CONTINUE; -} - -static -enum mad_flow receive_io(int fd, void *buffer, size_t len) -{ - char *ptr = buffer; - ssize_t count; - - while (len) { - do - count = read(fd, ptr, len); - while (count == -1 && errno == EINTR); - - if (count == -1) - return (errno == EAGAIN) ? MAD_FLOW_IGNORE : MAD_FLOW_BREAK; - else if (count == 0) - return MAD_FLOW_STOP; - - len -= count; - ptr += count; - } - - return MAD_FLOW_CONTINUE; -} - -static -enum mad_flow receive_io_blocking(int fd, void *buffer, size_t len) -{ - int flags, blocking; - enum mad_flow result; - - flags = fcntl(fd, F_GETFL); - if (flags == -1) - return MAD_FLOW_BREAK; - - blocking = flags & ~O_NONBLOCK; - - if (blocking != flags && - fcntl(fd, F_SETFL, blocking) == -1) - return MAD_FLOW_BREAK; - - result = receive_io(fd, buffer, len); - - if (flags != blocking && - fcntl(fd, F_SETFL, flags) == -1) - return MAD_FLOW_BREAK; - - return result; -} - -static -enum mad_flow send(int fd, void const *message, unsigned int size) -{ - enum mad_flow result; - - /* send size */ - - result = send_io(fd, &size, sizeof(size)); - - /* send message */ - - if (result == MAD_FLOW_CONTINUE) - result = send_io(fd, message, size); - - return result; -} - -static -enum mad_flow receive(int fd, void **message, unsigned int *size) -{ - enum mad_flow result; - unsigned int actual; - - if (*message == 0) - *size = 0; - - /* receive size */ - - result = receive_io(fd, &actual, sizeof(actual)); - - /* receive message */ - - if (result == MAD_FLOW_CONTINUE) { - if (actual > *size) - actual -= *size; - else { - *size = actual; - actual = 0; - } - - if (*size > 0) { - if (*message == 0) { - *message = malloc(*size); - if (*message == 0) - return MAD_FLOW_BREAK; - } - - result = receive_io_blocking(fd, *message, *size); - } - - /* throw away remainder of message */ - - while (actual && result == MAD_FLOW_CONTINUE) { - char sink[256]; - unsigned int len; - - len = actual > sizeof(sink) ? sizeof(sink) : actual; - - result = receive_io_blocking(fd, sink, len); - - actual -= len; - } - } - - return result; -} - -static -enum mad_flow check_message(struct mad_decoder *decoder) -{ - enum mad_flow result; - void *message = 0; - unsigned int size; - - result = receive(decoder->async.in, &message, &size); - - if (result == MAD_FLOW_CONTINUE) { - if (decoder->message_func == 0) - size = 0; - else { - result = decoder->message_func(decoder->cb_data, message, &size); - - if (result == MAD_FLOW_IGNORE || - result == MAD_FLOW_BREAK) - size = 0; - } - - if (send(decoder->async.out, message, size) != MAD_FLOW_CONTINUE) - result = MAD_FLOW_BREAK; - } - - if (message) - free(message); - - return result; -} -# endif static enum mad_flow error_default(void *data, struct mad_stream *stream, @@ -357,20 +161,6 @@ } while (1) { -# if defined(USE_ASYNC) - if (decoder->mode == MAD_DECODER_MODE_ASYNC) { - switch (check_message(decoder)) { - case MAD_FLOW_IGNORE: - case MAD_FLOW_CONTINUE: - break; - case MAD_FLOW_BREAK: - goto fail; - case MAD_FLOW_STOP: - goto done; - } - } -# endif - if (decoder->header_func) { if (mad_header_decode(&frame->header, stream) == -1) { if (!MAD_RECOVERABLE(stream->error)) @@ -461,69 +251,6 @@ return result; } -# if defined(USE_ASYNC) -static -int run_async(struct mad_decoder *decoder) -{ - pid_t pid; - int ptoc[2], ctop[2], flags; - - if (pipe(ptoc) == -1) - return -1; - - if (pipe(ctop) == -1) { - close(ptoc[0]); - close(ptoc[1]); - return -1; - } - - flags = fcntl(ptoc[0], F_GETFL); - if (flags == -1 || - fcntl(ptoc[0], F_SETFL, flags | O_NONBLOCK) == -1) { - close(ctop[0]); - close(ctop[1]); - close(ptoc[0]); - close(ptoc[1]); - return -1; - } - - pid = fork(); - if (pid == -1) { - close(ctop[0]); - close(ctop[1]); - close(ptoc[0]); - close(ptoc[1]); - return -1; - } - - decoder->async.pid = pid; - - if (pid) { - /* parent */ - - close(ptoc[0]); - close(ctop[1]); - - decoder->async.in = ctop[0]; - decoder->async.out = ptoc[1]; - - return 0; - } - - /* child */ - - close(ptoc[1]); - close(ctop[0]); - - decoder->async.in = ptoc[0]; - decoder->async.out = ctop[1]; - - _exit(run_sync(decoder)); - - /* not reached */ - return -1; -} -# endif /* * NAME: decoder->run() @@ -540,25 +267,28 @@ break; case MAD_DECODER_MODE_ASYNC: -# if defined(USE_ASYNC) - run = run_async; -# endif break; } if (run == 0) return -1; - + // static struct mad_sync_s sync_mem; decoder->sync = (struct mad_sync_s *)malloc(sizeof(*decoder->sync)); - decoder->sync->synth = (struct mad_synth *)AHBMEM; // 12kb in upper memory +#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; } @@ -569,14 +299,5 @@ int mad_decoder_message(struct mad_decoder *decoder, void *message, unsigned int *len) { -# if defined(USE_ASYNC) - if (decoder->mode != MAD_DECODER_MODE_ASYNC || - send(decoder->async.out, message, *len) != MAD_FLOW_CONTINUE || - receive(decoder->async.in, &message, len) != MAD_FLOW_CONTINUE) - return -1; - - return 0; -# else return -1; -# endif }
diff -r 7c923cbe9f1d -r f28cf0afd021 decoder.h --- a/decoder.h Fri Nov 26 13:05:34 2010 +0000 +++ b/decoder.h Sat Nov 27 17:27:33 2010 +0000 @@ -49,12 +49,6 @@ int options; - struct { - long pid; - int in; - int out; - } async; - struct mad_sync_s *sync; void *cb_data;
diff -r 7c923cbe9f1d -r f28cf0afd021 frame.cpp --- a/frame.cpp Fri Nov 26 13:05:34 2010 +0000 +++ b/frame.cpp Sat Nov 27 17:27:33 2010 +0000 @@ -92,7 +92,7 @@ frame->options = 0; - frame->overlap = 0; +//### frame->overlap = 0; mad_frame_mute(frame); } @@ -103,11 +103,12 @@ void mad_frame_finish(struct mad_frame *frame) { mad_header_finish(&frame->header); - +/* ### if (frame->overlap) { free(frame->overlap); frame->overlap = 0; } + */ } /* @@ -493,8 +494,8 @@ if (frame->overlap) { for (s = 0; s < 18; ++s) { for (sb = 0; sb < 32; ++sb) { - (*frame->overlap)[0][sb][s] = - (*frame->overlap)[1][sb][s] = 0; + (frame->overlap)[0][sb][s] = + (frame->overlap)[1][sb][s] = 0; } } }
diff -r 7c923cbe9f1d -r f28cf0afd021 frame.h --- a/frame.h Fri Nov 26 13:05:34 2010 +0000 +++ b/frame.h Sat Nov 27 17:27:33 2010 +0000 @@ -70,7 +70,7 @@ int options; /* decoding options (from stream) */ mad_fixed_t sbsample[2][36][32]; /* synthesis subband filter samples */ - mad_fixed_t (*overlap)[2][32][18]; /* Layer III block overlap data */ + mad_fixed_t overlap[2][32][18]; /* Layer III block overlap data */ }; # define MAD_NCHANNELS(header) ((header)->mode ? 2 : 1)
diff -r 7c923cbe9f1d -r f28cf0afd021 global.h --- a/global.h Fri Nov 26 13:05:34 2010 +0000 +++ b/global.h Sat Nov 27 17:27:33 2010 +0000 @@ -42,17 +42,4 @@ # define OPT_SSO # endif -# if defined(HAVE_UNISTD_H) && defined(HAVE_WAITPID) && \ - defined(HAVE_FCNTL) && defined(HAVE_PIPE) && defined(HAVE_FORK) -# define USE_ASYNC # endif - -# if !defined(HAVE_ASSERT_H) -# if defined(NDEBUG) -# define assert(x) /* nothing */ -# else -# define assert(x) do { if (!(x)) abort(); } while (0) -# endif -# endif - -# endif
diff -r 7c923cbe9f1d -r f28cf0afd021 layer3.cpp --- a/layer3.cpp Fri Nov 26 13:05:34 2010 +0000 +++ b/layer3.cpp Sat Nov 27 17:27:33 2010 +0000 @@ -26,10 +26,6 @@ # include <stdlib.h> # include <string.h> -# ifdef HAVE_ASSERT_H -# include <assert.h> -# endif - # ifdef HAVE_LIMITS_H # include <limits.h> # else @@ -1253,7 +1249,7 @@ } } - assert(-bits_left <= MAD_BUFFER_GUARD * CHAR_BIT); + /* assert(-bits_left <= MAD_BUFFER_GUARD * CHAR_BIT);*/ # if 0 && defined(DEBUG) if (bits_left < 0) @@ -2456,14 +2452,14 @@ /* long blocks */ for (sb = 0; sb < 2; ++sb, l += 18) { III_imdct_l(&xr[ch][l], output, block_type); - III_overlap(output, (*frame->overlap)[ch][sb], sample, sb); + III_overlap(output, (frame->overlap)[ch][sb], sample, sb); } } else { /* short blocks */ for (sb = 0; sb < 2; ++sb, l += 18) { III_imdct_s(&xr[ch][l], output); - III_overlap(output, (*frame->overlap)[ch][sb], sample, sb); + III_overlap(output, (frame->overlap)[ch][sb], sample, sb); } } @@ -2481,7 +2477,7 @@ /* long blocks */ for (sb = 2; sb < sblimit; ++sb, l += 18) { III_imdct_l(&xr[ch][l], output, channel->block_type); - III_overlap(output, (*frame->overlap)[ch][sb], sample, sb); + III_overlap(output, (frame->overlap)[ch][sb], sample, sb); if (sb & 1) III_freqinver(sample, sb); @@ -2491,7 +2487,7 @@ /* short blocks */ for (sb = 2; sb < sblimit; ++sb, l += 18) { III_imdct_s(&xr[ch][l], output); - III_overlap(output, (*frame->overlap)[ch][sb], sample, sb); + III_overlap(output, (frame->overlap)[ch][sb], sample, sb); if (sb & 1) III_freqinver(sample, sb); @@ -2501,7 +2497,7 @@ /* remaining (zero) subbands */ for (sb = sblimit; sb < 32; ++sb) { - III_overlap_z((*frame->overlap)[ch][sb], sample, sb); + III_overlap_z((frame->overlap)[ch][sb], sample, sb); if (sb & 1) III_freqinver(sample, sb); @@ -2530,21 +2526,17 @@ /* allocate Layer III dynamic structures */ if (stream->main_data == 0) { +#if defined(TARGET_LPC1768) + stream->main_data = (unsigned char (*)[MAD_BUFFER_MDLEN])mad_malloc(MAD_BUFFER_MDLEN); +#else stream->main_data = (unsigned char (*)[MAD_BUFFER_MDLEN])malloc(MAD_BUFFER_MDLEN); +#endif if (stream->main_data == 0) { stream->error = MAD_ERROR_NOMEM; return -1; } } - if (frame->overlap == 0) { - frame->overlap = (mad_fixed_t (*)[2][32][18])calloc(2 * 32 * 18, sizeof(mad_fixed_t)); - if (frame->overlap == 0) { - stream->error = MAD_ERROR_NOMEM; - return -1; - } - } - nch = MAD_NCHANNELS(header); si_len = (header->flags & MAD_FLAG_LSF_EXT) ? (nch == 1 ? 9 : 17) : (nch == 1 ? 17 : 32); @@ -2632,8 +2624,7 @@ *stream->main_data + stream->md_len - si.main_data_begin); if (md_len > si.main_data_begin) { - assert(stream->md_len + md_len - - si.main_data_begin <= MAD_BUFFER_MDLEN); + /*assert(stream->md_len + md_len -si.main_data_begin <= MAD_BUFFER_MDLEN); */ memcpy(*stream->main_data + stream->md_len, mad_bit_nextbyte(&stream->ptr),
diff -r 7c923cbe9f1d -r f28cf0afd021 lpc1768_mem.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lpc1768_mem.cpp Sat Nov 27 17:27:33 2010 +0000 @@ -0,0 +1,25 @@ +#include "mbed.h" +#include "config.h" + +static char *free_ptr = (char *)AHBMEM; +static int free_sz = AHBMEMSIZE; +void reset_ahb_mem(void) + { + free_ptr = (char *)AHBMEM; + free_sz = AHBMEMSIZE; + } +void *mad_malloc(unsigned int sz) +{ + unsigned int nsz = ((sz >> 3) + 1) << 3; // align to 8 byte + if(nsz < free_sz) + { + char *p = free_ptr; + free_ptr += nsz; + free_sz -=nsz; + return(p); + } + else + { + return(malloc(sz)); + } +}
diff -r 7c923cbe9f1d -r f28cf0afd021 main.cpp --- a/main.cpp Fri Nov 26 13:05:34 2010 +0000 +++ b/main.cpp Sat Nov 27 17:27:33 2010 +0000 @@ -28,18 +28,33 @@ * 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" -static int decode(void); FILE *fp; #include "MSCFileSystem.h" MSCFileSystem fs("usb"); -volatile unsigned short dacbuf[1200]; -volatile unsigned short *dac_s, *dac_e; +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; @@ -48,26 +63,33 @@ { if(dac_s < dac_e) { - dac.write_u16(*dac_s++); + dac.write_u16((dac_s->l/2)+(dac_s->r/2)); + dac_s++; } } int main(int argc, char *argv[]) { - int ret; + int result; Timer t; + struct mad_decoder decoder; dac_s = dac_e = dacbuf; dacclk.attach_us(dacout,23); - - fp = fopen("/usb/test.mp3","rb"); - if(!fp) return(printf("no file\r\n")); - t.start(); - ret = decode(); - t.stop(); - printf("decode ret=%d in %d ms\r\n",ret,t.read_ms()); - fclose(fp); - + 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; } @@ -149,33 +171,27 @@ 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(10); - dac_e = dacbuf; // potential thread problem ?? - dac_s = dacbuf; + + while(dac_s < dac_e) wait_us(1); + dac_e = dacbuf; // potential thread problem ?? no... + dac_s = dacbuf; while (nsamples--) { - signed int sample; - - /* output sample(s) in 16-bit signed little-endian PCM */ - - sample = scale(*left_ch++); - *dac_e++ = sample +32700; - //putchar((sample >> 0) & 0xff); - //putchar((sample >> 8) & 0xff); - /* the second channel is not supported at the moment*/ - if (nchannels == 2) { - sample = scale(*right_ch++); - //putchar((sample >> 0) & 0xff); - //putchar((sample >> 8) & 0xff); - } + 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; } @@ -202,36 +218,4 @@ return MAD_FLOW_CONTINUE; } -/* - * This is the function called by main() above to perform all the decoding. - * It instantiates a decoder object and configures it with the input, - * output, and error callback functions above. A single call to - * mad_decoder_run() continues until a callback function returns - * MAD_FLOW_STOP (to stop decoding) or MAD_FLOW_BREAK (to stop decoding and - * signal an error). - */ -static -int decode() -{ - struct mad_decoder decoder; - int result; - - /* configure input, output, and error functions */ - - mad_decoder_init(&decoder, NULL, - input, 0 /* header */, 0 /* filter */, output, - error_fn, 0 /* message */); - - /* start decoding */ - - result = mad_decoder_run(&decoder, MAD_DECODER_MODE_SYNC); - - /* release the decoder */ - - mad_decoder_finish(&decoder); - - return result; -} - -
diff -r 7c923cbe9f1d -r f28cf0afd021 stream.cpp --- a/stream.cpp Fri Nov 26 13:05:34 2010 +0000 +++ b/stream.cpp Sat Nov 27 17:27:33 2010 +0000 @@ -62,7 +62,9 @@ void mad_stream_finish(struct mad_stream *stream) { if (stream->main_data) { +#if !defined(TARGET_LPC1768) free(stream->main_data); +#endif stream->main_data = 0; }
diff -r 7c923cbe9f1d -r f28cf0afd021 timer.cpp --- a/timer.cpp Fri Nov 26 13:05:34 2010 +0000 +++ b/timer.cpp Sat Nov 27 17:27:33 2010 +0000 @@ -25,10 +25,6 @@ # include <stdio.h> -# ifdef HAVE_ASSERT_H -# include <assert.h> -# endif - # include "timer.h" mad_timer_t const mad_timer_zero = { 0, 0 };