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

Dependencies:   FatFileSystemCpp I2SSlave TLV320 mbed

Fork of madplayer by Andreas Grün

Committer:
okini3939
Date:
Fri Jul 26 15:02:49 2013 +0000
Revision:
5:50015f4868e2
Parent:
4:30b2cf4a8ee2
fix

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Gruenfrosch 0:7627c79db971 1 /* This file demonstrates the use of the modified libmad library on LPC1768
Gruenfrosch 0:7627c79db971 2 * Changes to the library are documented in config.h.
Gruenfrosch 0:7627c79db971 3 *
Gruenfrosch 0:7627c79db971 4 * The main change is to use parts of the AHB RAM dedicated to the ethernet module,
Gruenfrosch 0:7627c79db971 5 * because standard RAM is not sufficient for decoding.
Gruenfrosch 0:7627c79db971 6 * This means the ethernet module cannot be used !!!
Gruenfrosch 0:7627c79db971 7 *
Gruenfrosch 0:7627c79db971 8 * It plays a file "test.mp3" from an external USB-drive/USB-stick.
Gruenfrosch 0:7627c79db971 9 * For wiring of the USB-connector, see mbed.org
Gruenfrosch 0:7627c79db971 10 * ID3 decoding is not present at the moment and will cause warnings
Gruenfrosch 0:7627c79db971 11 * on stderr, and some short noise at the beginning or end of playback.
Gruenfrosch 0:7627c79db971 12 *
Gruenfrosch 0:7627c79db971 13 * Output is only for one channel on the DAC (AnalogOut) pin.
Gruenfrosch 0:7627c79db971 14 * (For connections see datasheets/mbed.org)
Gruenfrosch 0:7627c79db971 15 * This pin should be decoupled with a capacitor (100u or so) to remove DC.
Gruenfrosch 0:7627c79db971 16 * The output current is high enough to drive small headphones or active
Gruenfrosch 0:7627c79db971 17 * speakers directly.
Gruenfrosch 0:7627c79db971 18 *
okini3939 3:6f07b5f52c38 19 * Schematic: :-)
Gruenfrosch 0:7627c79db971 20 * MBED Pin 18 (AOut) o--||--o Headphone Left
okini3939 3:6f07b5f52c38 21 * MBED Pin 1 (GND) o------o Headphone Common
Gruenfrosch 0:7627c79db971 22 *
Gruenfrosch 0:7627c79db971 23 * It has been tested with fixed bitrate MP3's up to 320kbps and VBR files.
Gruenfrosch 0:7627c79db971 24 *
Gruenfrosch 0:7627c79db971 25 * The remaining RAM is very limited, so don't overuse it !
Gruenfrosch 0:7627c79db971 26 * The MSCFileSystem library from mbed.org is needed !
Gruenfrosch 0:7627c79db971 27 * Last warning: the main include file "mad.h" maybe not up to date,
Gruenfrosch 0:7627c79db971 28 * use "decoder.h" for now
Gruenfrosch 0:7627c79db971 29 * Have fun,
Gruenfrosch 0:7627c79db971 30 * Andreas Gruen
Gruenfrosch 2:f28cf0afd021 31 * *** Version 3: ***
Gruenfrosch 2:f28cf0afd021 32 * moved another memory block into AHB RAM, giving more room for
Gruenfrosch 2:f28cf0afd021 33 * stereo buffer.
Gruenfrosch 2:f28cf0afd021 34 * moved content of decode() to main()
okini3939 3:6f07b5f52c38 35 * decoding is now safe to be called multiple times (bug in older versions)
Gruenfrosch 2:f28cf0afd021 36 * Output routine now fills stereo buffer, DAC output sums channels,
Gruenfrosch 2:f28cf0afd021 37 * just for demonstration that stereo output could go here
Gruenfrosch 0:7627c79db971 38 */
Gruenfrosch 0:7627c79db971 39
Gruenfrosch 0:7627c79db971 40 #include "mbed.h"
okini3939 3:6f07b5f52c38 41 #include "decoder.h"
okini3939 3:6f07b5f52c38 42 #include "TLV320.h"
Gruenfrosch 0:7627c79db971 43
okini3939 3:6f07b5f52c38 44 DigitalOut led1(LED1), led2(LED2), led3(LED3), led4(LED4);
okini3939 3:6f07b5f52c38 45 Serial pc(USBTX, USBRX);
Gruenfrosch 0:7627c79db971 46 FILE *fp;
okini3939 3:6f07b5f52c38 47 #include "SDHCFileSystem.h"
okini3939 3:6f07b5f52c38 48 SDFileSystem sd(p11, p12, p13, p14, "sd");
okini3939 3:6f07b5f52c38 49 TLV320 audio(p9, p10, 0x34, p5, p6, p7, p8, p16); // I2S Codec
Gruenfrosch 0:7627c79db971 50
Gruenfrosch 2:f28cf0afd021 51 static enum mad_flow input(void *data,struct mad_stream *stream);
Gruenfrosch 2:f28cf0afd021 52 static enum mad_flow output(void *data,struct mad_header const *header,struct mad_pcm *pcm);
Gruenfrosch 2:f28cf0afd021 53 static enum mad_flow error_fn(void *data,struct mad_stream *stream,struct mad_frame *frame);
Gruenfrosch 2:f28cf0afd021 54
Gruenfrosch 2:f28cf0afd021 55 struct dacout_s {
Gruenfrosch 2:f28cf0afd021 56 unsigned short l;
Gruenfrosch 2:f28cf0afd021 57 unsigned short r;
Gruenfrosch 2:f28cf0afd021 58 };
Gruenfrosch 2:f28cf0afd021 59
okini3939 5:50015f4868e2 60 dacout_s dacbuf[1152];
okini3939 5:50015f4868e2 61 dacout_s * volatile dac_s, * volatile dac_e;
Gruenfrosch 0:7627c79db971 62
okini3939 3:6f07b5f52c38 63 void isr_audio () {
okini3939 3:6f07b5f52c38 64 int i;
okini3939 3:6f07b5f52c38 65 static int buf[4] = {0,0,0,0};
okini3939 3:6f07b5f52c38 66
okini3939 3:6f07b5f52c38 67 for (i = 0; i < 4; i ++) {
okini3939 3:6f07b5f52c38 68 if (dac_s < dac_e) {
okini3939 4:30b2cf4a8ee2 69 buf[i] = (dac_s->l << 16) | dac_s->r;
okini3939 3:6f07b5f52c38 70 dac_s++;
okini3939 3:6f07b5f52c38 71 led3 = !led3;
okini3939 3:6f07b5f52c38 72 } else {
okini3939 5:50015f4868e2 73 // under flow
okini3939 3:6f07b5f52c38 74 if (i) {
okini3939 3:6f07b5f52c38 75 buf[i] = buf[i - 1];
okini3939 3:6f07b5f52c38 76 } else {
okini3939 3:6f07b5f52c38 77 buf[i] = buf[3];
okini3939 3:6f07b5f52c38 78 }
okini3939 3:6f07b5f52c38 79 led4 = !led4;
okini3939 3:6f07b5f52c38 80 }
okini3939 3:6f07b5f52c38 81 }
okini3939 3:6f07b5f52c38 82 audio.write(buf, 0, 4);
okini3939 3:6f07b5f52c38 83 }
okini3939 3:6f07b5f52c38 84
Gruenfrosch 0:7627c79db971 85 int main(int argc, char *argv[])
Gruenfrosch 0:7627c79db971 86 {
Gruenfrosch 2:f28cf0afd021 87 int result;
Gruenfrosch 0:7627c79db971 88 Timer t;
Gruenfrosch 2:f28cf0afd021 89 struct mad_decoder decoder;
Gruenfrosch 0:7627c79db971 90
okini3939 3:6f07b5f52c38 91 pc.baud(115200);
Gruenfrosch 0:7627c79db971 92 dac_s = dac_e = dacbuf;
okini3939 3:6f07b5f52c38 93
okini3939 3:6f07b5f52c38 94 audio.power(0x02); // mic off
okini3939 3:6f07b5f52c38 95 audio.inputVolume(0.7, 0.7);
okini3939 3:6f07b5f52c38 96 audio.frequency(44100);
okini3939 3:6f07b5f52c38 97 audio.attach(&isr_audio);
okini3939 3:6f07b5f52c38 98 audio.start(TRANSMIT);
okini3939 3:6f07b5f52c38 99
Gruenfrosch 2:f28cf0afd021 100 while(1) {
okini3939 5:50015f4868e2 101 fp = fopen("/sd/filename.mp3","rb");
okini3939 3:6f07b5f52c38 102
okini3939 3:6f07b5f52c38 103 if(!fp) return(printf("file error\r\n"));
okini3939 3:6f07b5f52c38 104 fprintf(stderr,"decode start\r\n");
okini3939 3:6f07b5f52c38 105 led1 = 1;
okini3939 3:6f07b5f52c38 106 mad_decoder_init(&decoder, NULL,input, 0, 0, output,error_fn, 0);
okini3939 3:6f07b5f52c38 107 t.reset();
okini3939 3:6f07b5f52c38 108 t.start();
okini3939 3:6f07b5f52c38 109 result = mad_decoder_run(&decoder, MAD_DECODER_MODE_SYNC);
okini3939 3:6f07b5f52c38 110 t.stop();
okini3939 3:6f07b5f52c38 111 fprintf(stderr,"decode ret=%d in %d ms\r\n",result,t.read_ms());
okini3939 5:50015f4868e2 112 led1 = 0;
okini3939 3:6f07b5f52c38 113 mad_decoder_finish(&decoder);
okini3939 3:6f07b5f52c38 114 fclose(fp);
okini3939 3:6f07b5f52c38 115 }
Gruenfrosch 0:7627c79db971 116 }
Gruenfrosch 0:7627c79db971 117
Gruenfrosch 0:7627c79db971 118 /*
Gruenfrosch 0:7627c79db971 119 * This is the input callback. The purpose of this callback is to (re)fill
Gruenfrosch 0:7627c79db971 120 * the stream buffer which is to be decoded.
Gruenfrosch 0:7627c79db971 121 */
Gruenfrosch 0:7627c79db971 122
Gruenfrosch 0:7627c79db971 123 static
Gruenfrosch 0:7627c79db971 124 enum mad_flow input(void *data,
Gruenfrosch 0:7627c79db971 125 struct mad_stream *stream)
Gruenfrosch 0:7627c79db971 126 {
Gruenfrosch 0:7627c79db971 127 static unsigned char strmbuff[2100];
Gruenfrosch 0:7627c79db971 128 int ret;
Gruenfrosch 0:7627c79db971 129 int rsz;
Gruenfrosch 0:7627c79db971 130 unsigned char *bp;
Gruenfrosch 0:7627c79db971 131
Gruenfrosch 0:7627c79db971 132 /* the remaining bytes from incomplete frames must be copied
Gruenfrosch 0:7627c79db971 133 to the beginning of the new buffer !
Gruenfrosch 0:7627c79db971 134 */
Gruenfrosch 0:7627c79db971 135 bp = strmbuff;
Gruenfrosch 0:7627c79db971 136 rsz = 0;
Gruenfrosch 0:7627c79db971 137 if(stream->error == MAD_ERROR_BUFLEN||stream->buffer==NULL)
Gruenfrosch 0:7627c79db971 138 {
Gruenfrosch 0:7627c79db971 139 if(stream->next_frame!=NULL)
Gruenfrosch 0:7627c79db971 140 {
Gruenfrosch 0:7627c79db971 141 rsz = stream->bufend-stream->next_frame;
Gruenfrosch 0:7627c79db971 142 memmove(strmbuff,stream->next_frame,rsz);
Gruenfrosch 0:7627c79db971 143 bp = strmbuff+rsz;
Gruenfrosch 0:7627c79db971 144 }
Gruenfrosch 0:7627c79db971 145 }
Gruenfrosch 0:7627c79db971 146
Gruenfrosch 0:7627c79db971 147 ret = fread(bp,1,sizeof(strmbuff) - rsz,fp);
Gruenfrosch 0:7627c79db971 148
Gruenfrosch 0:7627c79db971 149 if (!ret)
Gruenfrosch 0:7627c79db971 150 return MAD_FLOW_STOP;
Gruenfrosch 0:7627c79db971 151
Gruenfrosch 0:7627c79db971 152
Gruenfrosch 0:7627c79db971 153 mad_stream_buffer(stream, strmbuff, ret + rsz);
Gruenfrosch 0:7627c79db971 154
Gruenfrosch 0:7627c79db971 155 return MAD_FLOW_CONTINUE;}
Gruenfrosch 0:7627c79db971 156
Gruenfrosch 0:7627c79db971 157
Gruenfrosch 0:7627c79db971 158 /*
Gruenfrosch 0:7627c79db971 159 * The following utility routine performs simple rounding, clipping, and
Gruenfrosch 0:7627c79db971 160 * scaling of MAD's high-resolution samples down to 16 bits. It does not
Gruenfrosch 0:7627c79db971 161 * perform any dithering or noise shaping, which would be recommended to
Gruenfrosch 0:7627c79db971 162 * obtain any exceptional audio quality. It is therefore not recommended to
Gruenfrosch 0:7627c79db971 163 * use this routine if high-quality output is desired.
Gruenfrosch 0:7627c79db971 164 */
Gruenfrosch 0:7627c79db971 165
Gruenfrosch 0:7627c79db971 166 static /*inline*/
Gruenfrosch 0:7627c79db971 167 signed int scale(mad_fixed_t sample)
Gruenfrosch 0:7627c79db971 168 {
Gruenfrosch 0:7627c79db971 169 /* round */
Gruenfrosch 0:7627c79db971 170 sample += (1L << (MAD_F_FRACBITS - 16));
Gruenfrosch 0:7627c79db971 171
Gruenfrosch 0:7627c79db971 172 /* clip */
Gruenfrosch 0:7627c79db971 173 if (sample >= MAD_F_ONE)
Gruenfrosch 0:7627c79db971 174 sample = MAD_F_ONE - 1;
Gruenfrosch 0:7627c79db971 175 else if (sample < -MAD_F_ONE)
Gruenfrosch 0:7627c79db971 176 sample = -MAD_F_ONE;
Gruenfrosch 0:7627c79db971 177
Gruenfrosch 0:7627c79db971 178 /* quantize */
Gruenfrosch 0:7627c79db971 179 return sample >> (MAD_F_FRACBITS + 1 - 16);
Gruenfrosch 0:7627c79db971 180 }
Gruenfrosch 0:7627c79db971 181
Gruenfrosch 0:7627c79db971 182 /*
Gruenfrosch 0:7627c79db971 183 * This is the output callback function. It is called after each frame of
Gruenfrosch 0:7627c79db971 184 * MPEG audio data has been completely decoded. The purpose of this callback
Gruenfrosch 0:7627c79db971 185 * is to output (or play) the decoded PCM audio.
Gruenfrosch 0:7627c79db971 186 */
Gruenfrosch 0:7627c79db971 187
Gruenfrosch 0:7627c79db971 188 static
Gruenfrosch 0:7627c79db971 189 enum mad_flow output(void *data,
Gruenfrosch 0:7627c79db971 190 struct mad_header const *header,
Gruenfrosch 0:7627c79db971 191 struct mad_pcm *pcm)
Gruenfrosch 0:7627c79db971 192 {
Gruenfrosch 0:7627c79db971 193 unsigned int nchannels, nsamples;
Gruenfrosch 0:7627c79db971 194 mad_fixed_t const *left_ch, *right_ch;
Gruenfrosch 0:7627c79db971 195
Gruenfrosch 2:f28cf0afd021 196
Gruenfrosch 0:7627c79db971 197 /* pcm->samplerate contains the sampling frequency */
Gruenfrosch 0:7627c79db971 198 nchannels = pcm->channels;
Gruenfrosch 0:7627c79db971 199 nsamples = pcm->length;
Gruenfrosch 0:7627c79db971 200 left_ch = pcm->samples[0];
Gruenfrosch 0:7627c79db971 201 right_ch = pcm->samples[1];
Gruenfrosch 2:f28cf0afd021 202
okini3939 5:50015f4868e2 203 // while(dac_s < dac_e) wait_us(1);
okini3939 5:50015f4868e2 204 while(dac_s < dac_e) {
okini3939 5:50015f4868e2 205 led2 = !led2;
okini3939 5:50015f4868e2 206 }
Gruenfrosch 2:f28cf0afd021 207 dac_e = dacbuf; // potential thread problem ?? no...
Gruenfrosch 2:f28cf0afd021 208 dac_s = dacbuf;
Gruenfrosch 0:7627c79db971 209
Gruenfrosch 0:7627c79db971 210 while (nsamples--) {
Gruenfrosch 2:f28cf0afd021 211 signed int sample_l,sample_r;
Gruenfrosch 2:f28cf0afd021 212 sample_l = scale(*left_ch);
Gruenfrosch 2:f28cf0afd021 213 sample_r = scale(*right_ch);
okini3939 4:30b2cf4a8ee2 214 // dac_e->l = sample_l +32768;
okini3939 4:30b2cf4a8ee2 215 // dac_e->r = sample_r +32768;
okini3939 4:30b2cf4a8ee2 216 dac_e->l = sample_l;
okini3939 4:30b2cf4a8ee2 217 dac_e->r = sample_r;
Gruenfrosch 2:f28cf0afd021 218 dac_e++;
Gruenfrosch 2:f28cf0afd021 219 left_ch++;
Gruenfrosch 2:f28cf0afd021 220 right_ch++;
Gruenfrosch 0:7627c79db971 221 }
Gruenfrosch 0:7627c79db971 222 return MAD_FLOW_CONTINUE;
Gruenfrosch 0:7627c79db971 223 }
Gruenfrosch 0:7627c79db971 224
Gruenfrosch 0:7627c79db971 225 /*
Gruenfrosch 0:7627c79db971 226 * This is the error callback function. It is called whenever a decoding
Gruenfrosch 0:7627c79db971 227 * error occurs. The error is indicated by stream->error; the list of
Gruenfrosch 0:7627c79db971 228 * possible MAD_ERROR_* errors can be found in the mad.h (or stream.h)
Gruenfrosch 0:7627c79db971 229 * header file.
Gruenfrosch 0:7627c79db971 230 */
Gruenfrosch 0:7627c79db971 231
Gruenfrosch 0:7627c79db971 232 static
Gruenfrosch 0:7627c79db971 233 enum mad_flow error_fn(void *data,
Gruenfrosch 0:7627c79db971 234 struct mad_stream *stream,
Gruenfrosch 0:7627c79db971 235 struct mad_frame *frame)
Gruenfrosch 0:7627c79db971 236 {
Gruenfrosch 0:7627c79db971 237 /* ID3 tags will cause warnings and short noise, ignore it for the moment*/
okini3939 3:6f07b5f52c38 238 /*
Gruenfrosch 0:7627c79db971 239 fprintf(stderr, "decoding error 0x%04x (%s)\n",
Gruenfrosch 0:7627c79db971 240 stream->error, mad_stream_errorstr(stream));
okini3939 3:6f07b5f52c38 241 */
Gruenfrosch 0:7627c79db971 242
Gruenfrosch 0:7627c79db971 243 /* return MAD_FLOW_BREAK here to stop decoding (and propagate an error) */
Gruenfrosch 0:7627c79db971 244
Gruenfrosch 0:7627c79db971 245 return MAD_FLOW_CONTINUE;
Gruenfrosch 0:7627c79db971 246 }
Gruenfrosch 0:7627c79db971 247
Gruenfrosch 0:7627c79db971 248