MP3 Player. You can change fwd/rev speed and skip. see: http://mbed.org/users/okini3939/notebook/lpc4088_madplayer/

Dependencies:   I2SSlave SDFileSystem TLV320 mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers player.cpp Source File

player.cpp

00001 #include "mbed.h"
00002 #include "player.h"
00003 #include "SDFileSystem.h"
00004 #include "sdram.h"
00005 
00006 #define DACBUF_SIZE (1024 * 1024 * 8 - 1024)
00007 SDFileSystem sd(p5, p6, p7, p8, "sd");
00008 TLV320 audio(p32, p31, 0x34, p11, p12, p13, p14, p16); // I2S Codec / sda, scl, addr, tx_sda, tx_ws, clk, rx_sda, rx_ws
00009 
00010 static struct mad_decoder decoder;
00011 struct dacout_s *dacbuf;
00012 volatile int dac_r, dac_w, dac_l;
00013 FILE *fp;
00014 volatile int player_busy = 0, cmd_stop = 0;
00015 int dac_step = 1, dac_vol = 100;
00016 
00017 extern DigitalOut led1, led2, led3, led4;
00018 extern Serial pc;
00019 
00020 
00021 bool isFull() {
00022     return (((dac_w + 1) % DACBUF_SIZE) == dac_r);
00023 };
00024 bool isEmpty() {
00025     return (dac_r == dac_w);
00026 };
00027 bool isEmpty2() {
00028     return (dac_r == dac_l);
00029 };
00030 uint32_t available() {
00031     return (dac_w >= dac_r) ? dac_w - dac_r : DACBUF_SIZE - dac_r + dac_w;
00032 };
00033 uint32_t available2() {
00034     return (dac_r >= dac_l) ? dac_r - dac_l : DACBUF_SIZE - dac_l + dac_r;
00035 };
00036 
00037 
00038 void isr_audio ()
00039 {
00040     int i, j, a;
00041     static int buf[4] = {0,0,0,0};
00042     static int w = 0;
00043     static short l = 0, r = 0;
00044 
00045     for (i = 0; i < 4; i ++) {
00046         if (dac_step > 0 && !isEmpty()) {
00047             // fwd
00048             for (j = 0; j < dac_step; j ++) {
00049 //              buf[i] = (dacbuf[dac_r].l << 16) | dacbuf[dac_r].r;
00050               l = dacbuf[dac_r].l;
00051               r = dacbuf[dac_r].r;
00052               buf[i] = (l << 16) | (r & 0xffff);
00053               dac_r = (dac_r + 1) % DACBUF_SIZE;
00054               if (isEmpty()) break;
00055             }
00056         } else
00057         if (dac_step < 0 && !isEmpty2()) {
00058             // rev
00059             for (j = 0; j < -dac_step; j ++) {
00060 //              buf[i] = (dacbuf[dac_r].l << 16) | dacbuf[dac_r].r;
00061               l = dacbuf[dac_r].l;
00062               r = dacbuf[dac_r].r;
00063               buf[i] = (l << 16) | (r & 0xffff);
00064               dac_r = (dac_r - 1 + DACBUF_SIZE) % DACBUF_SIZE;
00065               if (isEmpty2()) break;
00066             }
00067         } else {
00068             // under flow
00069             if (l > 0) l --;
00070             if (l < 0) l ++;
00071             if (r > 0) r --;
00072             if (r < 0) r ++;
00073             buf[i] = (l << 16) | (r & 0xffff);
00074         }
00075     }
00076     audio.write(buf, 0, 4);
00077 }
00078 
00079 int init_audio () {
00080     if (sdram_init() == 1) {
00081         pc.printf("Failed to initialize SDRAM\n");
00082         return -1;
00083     }
00084     malloc(16); 
00085     dacbuf = (dacout_s*)malloc(sizeof(dacout_s) * DACBUF_SIZE);
00086     if (dacbuf == NULL) return -1;
00087     pc.printf("memory %08x\r\n", dacbuf);
00088 
00089     audio.power(0x02); // mic off
00090     audio.inputVolume(0, 0);
00091     audio.frequency(44100);
00092     audio.attach(&isr_audio);
00093     audio.start(TRANSMIT);
00094     NVIC_SetPriority(I2S_IRQn, 1);
00095     NVIC_SetPriority(TIMER3_IRQn, 10);
00096     return 0;
00097 }
00098 
00099 int play (char *filename) {
00100     int i;
00101 
00102     DBG("play: %s\r\n", filename);
00103     fp = fopen(filename, "rb");
00104     if(!fp) {
00105         pc.printf("file error\r\n");
00106         return -1;
00107     }
00108     player_busy = 1;
00109     dac_r = dac_w = dac_l = 0;
00110     dac_step = 1;
00111     cmd_stop = 0;
00112     led2 = 0;
00113     mad_decoder_init(&decoder, NULL, input, 0, 0, output, error_fn, 0);
00114     mad_decoder_run(&decoder, MAD_DECODER_MODE_SYNC);
00115     mad_decoder_finish(&decoder);
00116     fclose(fp);
00117     fp = 0;
00118     dac_r = dac_w = 0;
00119     led2 = 1;
00120     player_busy = 0;
00121     wait_ms(100);
00122     DBG("eof\r\n");
00123     return 0;
00124 }
00125 
00126 int command (char *cmd) {
00127     int i, r = -1;
00128 
00129     pc.printf("command %s\r\n", cmd);
00130     switch (cmd[0]) {
00131     case 'P':
00132         if (!player_busy) {
00133             char buf[40];
00134             strcpy(buf, "/sd/");
00135             strcat(buf, &cmd[1]);
00136             r = play(buf);
00137         }
00138         break;
00139     case 'S':
00140         cmd_stop = 1;
00141         r = 0;
00142         break;
00143     case 'T':
00144         i = atoi(&cmd[1]);
00145         if (i < -10 || i > 10) break;
00146         dac_step = i;
00147         DBG("dac_step %d\r\n", dac_step);
00148         r = 0;
00149         break;
00150     case 'Q':
00151         if (cmd[1] == '+' || cmd[1] == '-') {
00152             i = atof(&cmd[1]) * 44100;
00153             if (i < 0 && i < - available2()) break;
00154             if (i > 0 && i > available()) break;
00155             dac_r += i;
00156             DBG("skip %+d\r\n", i);
00157         } else {
00158             i = atof(&cmd[1]) * 44100;
00159             if (i < dac_l || i > dac_r + available()) break;
00160             dac_r = i;
00161             DBG("skip %d\r\n", i);
00162         }
00163         r = 0;
00164         break;
00165     case 'V':
00166         i = atoi(&cmd[1]);
00167         if (i < 0 || i > 200) break;
00168         dac_vol = i;
00169         DBG("volume %d\r\n", i);
00170         r = 0;
00171         break;
00172     }
00173 
00174     return r;
00175 }
00176 
00177 
00178 /*
00179  * This is the input callback. The purpose of this callback is to (re)fill
00180  * the stream buffer which is to be decoded.
00181  */
00182 
00183 enum mad_flow input(void *data,
00184                     struct mad_stream *stream)
00185 {
00186     static unsigned char strmbuff[2100];
00187     int ret;
00188     int rsz;
00189     unsigned char *bp;
00190 
00191     /* the remaining bytes from incomplete frames must be copied
00192     to the beginning of the new buffer !
00193     */
00194     bp = strmbuff;
00195     rsz = 0;
00196     if(stream->error == MAD_ERROR_BUFLEN||stream->buffer==NULL) {
00197         if(stream->next_frame!=NULL) {
00198             rsz = stream->bufend-stream->next_frame;
00199             memmove(strmbuff,stream->next_frame,rsz);
00200             bp = strmbuff+rsz;
00201         }
00202     }
00203 
00204     if (feof(fp)) {
00205         if (isEmpty()) {
00206             return MAD_FLOW_STOP;
00207         } else {
00208             return MAD_FLOW_CONTINUE;
00209         }
00210     }
00211 
00212     led4 = 1;
00213     ret = fread(bp,1,sizeof(strmbuff) - rsz,fp);
00214 
00215     if (!ret) {
00216         DBG("input stop\r\n");
00217         return MAD_FLOW_STOP;
00218     }
00219 
00220     mad_stream_buffer(stream, strmbuff, ret + rsz);
00221 
00222     return MAD_FLOW_CONTINUE;
00223 }
00224 
00225 
00226 /*
00227  * The following utility routine performs simple rounding, clipping, and
00228  * scaling of MAD's high-resolution samples down to 16 bits. It does not
00229  * perform any dithering or noise shaping, which would be recommended to
00230  * obtain any exceptional audio quality. It is therefore not recommended to
00231  * use this routine if high-quality output is desired.
00232  */
00233 
00234 static /*inline*/
00235 signed int scale(mad_fixed_t sample)
00236 {
00237     /* round */
00238     sample += (1L << (MAD_F_FRACBITS - 16));
00239 
00240     /* clip */
00241     if (sample >= MAD_F_ONE)
00242         sample = MAD_F_ONE - 1;
00243     else if (sample < -MAD_F_ONE)
00244         sample = -MAD_F_ONE;
00245 
00246     /* quantize */
00247     return sample >> (MAD_F_FRACBITS + 1 - 16);
00248 }
00249 
00250 /*
00251  * This is the output callback function. It is called after each frame of
00252  * MPEG audio data has been completely decoded. The purpose of this callback
00253  * is to output (or play) the decoded PCM audio.
00254  */
00255 
00256 enum mad_flow output(void *data,
00257                      struct mad_header const *header,
00258                      struct mad_pcm *pcm)
00259 {
00260     unsigned int nchannels, nsamples;
00261     mad_fixed_t const *left_ch, *right_ch;
00262 
00263     /* pcm->samplerate contains the sampling frequency */
00264     nchannels = pcm->channels;
00265     nsamples  = pcm->length;
00266     left_ch   = pcm->samples[0];
00267     right_ch  = pcm->samples[1];
00268 
00269     poll();
00270     while (nsamples--) {
00271         while (isFull() || available() >= (44100 * FWDBUF)) {
00272             poll();
00273             if (cmd_stop) break;
00274         }
00275         __disable_irq();
00276         dacbuf[dac_w].l = scale(*left_ch);
00277         dacbuf[dac_w].r = scale(*right_ch);
00278         dac_w = (dac_w + 1) % DACBUF_SIZE;
00279         if (dac_w == 0 || dac_l) dac_l ++;
00280         __enable_irq();
00281         left_ch++;
00282         right_ch++;
00283     }
00284 
00285     if (cmd_stop) {
00286         DBG("output stop o\r\n");
00287         cmd_stop = 0;
00288         return MAD_FLOW_STOP;
00289     }
00290     return MAD_FLOW_CONTINUE;
00291 }
00292 
00293 /*
00294  * This is the error callback function. It is called whenever a decoding
00295  * error occurs. The error is indicated by stream->error; the list of
00296  * possible MAD_ERROR_* errors can be found in the mad.h (or stream.h)
00297  * header file.
00298  */
00299 
00300 enum mad_flow error_fn(void *data,
00301                        struct mad_stream *stream,
00302                        struct mad_frame *frame)
00303 {
00304     /* ID3 tags will cause warnings and short noise, ignore it for the moment*/
00305     /*
00306       fprintf(stderr, "decoding error 0x%04x (%s)\n",
00307           stream->error, mad_stream_errorstr(stream));
00308     */
00309 
00310     /* return MAD_FLOW_BREAK here to stop decoding (and propagate an error) */
00311 
00312     return MAD_FLOW_CONTINUE;
00313 }
00314