00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053 #include <sys/atom.h>
00054 #include <sys/event.h>
00055 #include <sys/timer.h>
00056 #include <sys/heap.h>
00057
00058 #include <cfg/arch/gpio.h>
00059 #include <cfg/audio.h>
00060 #include <dev/irqreg.h>
00061
00062 #include <contrib/hxmp3/mp3dec.h>
00063 #include <contrib/hxmp3/hermite.h>
00064 #include <dev/hxcodec.h>
00065 #include <dev/tlv320dac.h>
00066
00067 #include <sys/bankmem.h>
00068
00069 #include <stdlib.h>
00070 #include <stddef.h>
00071 #include <string.h>
00072 #include <memdebug.h>
00073
00074 #if 0
00075
00076 #define NUTDEBUG
00077 #include <stdio.h>
00078 #endif
00079
00080 #ifndef NUT_THREAD_HXCODEC0STACK
00081
00082 #define NUT_THREAD_HXCODEC0STACK 768
00083 #endif
00084
00085 #ifndef HXCODEC0_MAX_OUTPUT_BUFSIZ
00086
00087 #define HXCODEC0_MAX_OUTPUT_BUFSIZ 16384
00088 #endif
00089
00090 #ifndef DAC_OUTPUT_RATE
00091 #if defined (AT91SAM9260_EK)
00092 #define DAC_OUTPUT_RATE 44100
00093 #else
00094 #define DAC_OUTPUT_RATE 8000
00095 #endif
00096 #endif
00097
00098 #ifndef MP3_BUFSIZ
00099 #if defined (AT91SAM9260_EK)
00100 #define MP3_BUFSIZ 1048576
00101 #else
00102 #define MP3_BUFSIZ (4 * MAINBUF_SIZE)
00103 #endif
00104 #endif
00105
00106 #ifdef HXCODEC0_RESAMPLER
00107 static int rs_maxout;
00108 static short *rs_pcmbuf;
00109 #endif
00110
00114 #define HXREQ_PLAY 0x00000001
00115
00116 #define HXREQ_CANCEL 0x00000002
00117
00118 #define HXREQ_VOLUPD 0x00000004
00119
00120 #define HXREQ_BEEP 0x00000008
00121
00127
00128 typedef struct _HXDCB {
00129 int dcb_pbstat;
00130 uint32_t dcb_scmd;
00131 int dcb_rvol;
00132 int dcb_lvol;
00133 uint32_t dcb_pbwlo;
00134 uint32_t dcb_pbwhi;
00135 uint32_t dcb_wtmo;
00136 HANDLE dcb_bufque;
00137 HANDLE dcb_feedme;
00138 } HXDCB;
00139
00140 static HXDCB dcb;
00141
00142 typedef struct _MP3PLAYERINFO {
00143 HMP3Decoder mpi_mp3dec;
00144 MP3FrameInfo mpi_frameinfo;
00145 } MP3PLAYERINFO;
00146
00147 static MP3PLAYERINFO mpi;
00148
00149 static short pi_pcmbuf[MAX_NCHAN * MAX_NGRAN * MAX_NSAMP];
00150
00151 static int first_frame;
00152 static int samprate;
00153
00163 static int HelixPlayerSetVolume(NUTDEVICE *dev, int left, int right)
00164 {
00165 HXDCB *dcb = (HXDCB *)dev->dev_dcb;
00166
00167
00168 left = left > AUDIO_DAC_MAX_GAIN ? AUDIO_DAC_MAX_GAIN : left;
00169 left = left < AUDIO_DAC_MIN_GAIN ? AUDIO_DAC_MIN_GAIN : left;
00170 right = right > AUDIO_DAC_MAX_GAIN ? AUDIO_DAC_MAX_GAIN : right;
00171 right = right < AUDIO_DAC_MIN_GAIN ? AUDIO_DAC_MIN_GAIN : right;
00172
00173 Tlv320DacSetVolume(left, right);
00174
00175 dcb->dcb_lvol = left;
00176 dcb->dcb_rvol = right;
00177
00178 return 0;
00179 }
00180
00181 static int DecodeFrame(uint8_t *buf, int len)
00182 {
00183 int rc = len;
00184 int skip;
00185
00186 while (len > 2 * MAINBUF_SIZE) {
00187 if ((skip = MP3FindSyncWord(buf, len)) < 0) {
00188 return -1;
00189 }
00190 if (skip) {
00191 len -= skip;
00192 buf += skip;
00193 } else {
00194 if (MP3Decode(mpi.mpi_mp3dec, &buf, &len, pi_pcmbuf, 0)) {
00195 return -1;
00196 }
00197 if (first_frame) {
00198 MP3GetLastFrameInfo(mpi.mpi_mp3dec, &mpi.mpi_frameinfo);
00199 if (mpi.mpi_frameinfo.nChans == 1) {
00200 samprate = mpi.mpi_frameinfo.samprate / 2;
00201 }
00202 else if (mpi.mpi_frameinfo.nChans == 2) {
00203 samprate = mpi.mpi_frameinfo.samprate;
00204 }
00205 else {
00206 return -1;
00207 }
00208 if (mpi.mpi_frameinfo.samprate < 8000 || samprate > DAC_OUTPUT_RATE) {
00209 return -1;
00210 }
00211 if (mpi.mpi_frameinfo.bitsPerSample != 16) {
00212 return -1;
00213 }
00214 #ifdef HXCODEC0_RESAMPLER
00215
00216 if (samprate != DAC_OUTPUT_RATE) {
00217 void *hres;
00218
00219 if ((hres = RAInitResamplerHermite(samprate, DAC_OUTPUT_RATE, mpi.mpi_frameinfo.nChans)) == NULL) {
00220 return -1;
00221 }
00222 rs_maxout = RAGetMaxOutputHermite(mpi.mpi_frameinfo.outputSamps, hres);
00223 if ((rs_pcmbuf = malloc(rs_maxout * 2)) == NULL) {
00224 return -1;
00225 }
00226 }
00227 #endif
00228 first_frame = 0;
00229 }
00230 if (Tlv320DacWrite(pi_pcmbuf, mpi.mpi_frameinfo.outputSamps)) {
00231 return -1;
00232 }
00233 break;
00234 }
00235 }
00236 return rc - len;
00237 }
00238
00239
00240
00241
00242
00243
00244 static int HelixPlayerBufferInit(NUTDEVICE *dev, uint32_t size)
00245 {
00246 HXDCB *dcb = (HXDCB *)dev->dev_dcb;
00247
00248
00249 if (dcb->dcb_pbstat != CODEC_STATUS_IDLE) {
00250 return -1;
00251 }
00252
00253 if (NutSegBufInit((size_t)size) == NULL) {
00254 return -1;
00255 }
00256
00257 dcb->dcb_pbwlo = NutSegBufAvailable() / 3;
00258 dcb->dcb_pbwhi = dcb->dcb_pbwlo * 2;
00259
00260 return 0;
00261 }
00262
00263
00264
00265
00266 THREAD(FeederThread, arg)
00267 {
00268 uint8_t *bp;
00269 uint8_t *backbuf = NULL;
00270 int backcnt = 0;
00271 size_t avail;
00272 int filled;
00273 NUTDEVICE *dev = (NUTDEVICE *)arg;
00274 HXDCB *dcb = (HXDCB *)dev->dev_dcb;
00275
00276
00277 NutThreadSetPriority(7);
00278 for (;;) {
00279
00280
00281
00282 if (dcb->dcb_pbstat == CODEC_STATUS_IDLE) {
00283
00284 NutEventWait(&dcb->dcb_feedme, NUT_WAIT_INFINITE);
00285
00286
00287
00288 if ((dcb->dcb_scmd & HXREQ_PLAY) != 0 || NutSegBufUsed() >= dcb->dcb_pbwhi) {
00289 dcb->dcb_scmd &= ~(HXREQ_PLAY | HXREQ_CANCEL);
00290 dcb->dcb_pbstat = CODEC_STATUS_PLAYING;
00291 HelixPlayerSetVolume(dev, dcb->dcb_lvol, dcb->dcb_rvol);
00292 }
00293 }
00294
00295
00296
00297
00298 if (dcb->dcb_pbstat == CODEC_STATUS_PLAYING) {
00299
00300 if (dcb->dcb_scmd & HXREQ_CANCEL) {
00301 dcb->dcb_scmd &= ~HXREQ_CANCEL;
00302 NutSegBufReset();
00303 }
00304 if (dcb->dcb_scmd & HXREQ_VOLUPD) {
00305 HelixPlayerSetVolume(dev, dcb->dcb_lvol, dcb->dcb_rvol);
00306 dcb->dcb_scmd &= ~HXREQ_VOLUPD;
00307 }
00308
00309 bp = (uint8_t *) NutSegBufReadRequest(&avail);
00310 if (backcnt && backcnt + avail >= 4 * MAINBUF_SIZE) {
00311 memcpy(&backbuf[backcnt], bp, 4 * MAINBUF_SIZE - backcnt);
00312 filled = DecodeFrame(backbuf, 4 * MAINBUF_SIZE);
00313 if (filled < 0) {
00314 backcnt = 0;
00315 free(backbuf);
00316 } else if (filled < backcnt) {
00317 bp = backbuf;
00318 backcnt -= filled;
00319 backbuf = malloc(4 * MAINBUF_SIZE);
00320 memcpy(backbuf, &bp[filled], backcnt);
00321 free(bp);
00322 } else {
00323 if (filled > backcnt) {
00324 NutSegBufReadLast(filled - backcnt);
00325 }
00326 backcnt = 0;
00327 free(backbuf);
00328 }
00329 } else if (avail > 2 * MAINBUF_SIZE) {
00330 filled = DecodeFrame(bp, avail);
00331 if (filled < 0) {
00332 NutSegBufReadLast(1);
00333 } else if (filled) {
00334 NutSegBufReadLast(filled);
00335 }
00336 NutEventPost(&dcb->dcb_bufque);
00337 }
00338 else if (NutSegBufUsed() == 0) {
00339
00340 dcb->dcb_pbstat = CODEC_STATUS_IDLE;
00341 NutEventPost(&dcb->dcb_bufque);
00342 } else if (avail && backcnt == 0) {
00343 backcnt = avail;
00344 backbuf = malloc(4 * MAINBUF_SIZE);
00345 memcpy(backbuf, bp, backcnt);
00346 NutSegBufReadLast(backcnt);
00347 NutEventPost(&dcb->dcb_bufque);
00348 } else {
00349
00350 NutEventWait(&dcb->dcb_feedme, 1000);
00351 }
00352 }
00353 }
00354 }
00355
00375 static int HelixIOCtl(NUTDEVICE * dev, int req, void *conf)
00376 {
00377 int rc = 0;
00378 uint32_t *lvp = (uint32_t *) conf;
00379 int *ivp = (int *) conf;
00380 HXDCB *dcb = (HXDCB *)dev->dev_dcb;
00381
00382 switch (req) {
00383 case AUDIO_PLAY:
00384 if (dcb->dcb_pbstat == CODEC_STATUS_IDLE) {
00385
00386 dcb->dcb_scmd |= HXREQ_PLAY;
00387 }
00388 NutEventPost(&dcb->dcb_feedme);
00389 break;
00390 case AUDIO_CANCEL:
00391 if (dcb->dcb_pbstat == CODEC_STATUS_PLAYING) {
00392
00393 dcb->dcb_scmd |= HXREQ_CANCEL;
00394 }
00395 NutEventPost(&dcb->dcb_feedme);
00396 break;
00397 case AUDIO_GET_STATUS:
00398 *ivp = dcb->dcb_pbstat;
00399 break;
00400 case AUDIO_GET_PLAYGAIN:
00401 *ivp = dcb->dcb_rvol > dcb->dcb_lvol ? dcb->dcb_rvol : dcb->dcb_lvol;
00402 break;
00403 case AUDIO_SET_PLAYGAIN:
00404 dcb->dcb_lvol = *ivp;
00405 dcb->dcb_rvol = *ivp;
00406 dcb->dcb_scmd |= HXREQ_VOLUPD;
00407 break;
00408 case AUDIO_GET_PBSIZE:
00409 *lvp = NutSegBufAvailable() + NutSegBufUsed();
00410 break;
00411 case AUDIO_SET_PBSIZE:
00412 rc = HelixPlayerBufferInit(dev, *lvp);
00413 break;
00414 case AUDIO_GET_PBLEVEL:
00415 *lvp = NutSegBufUsed();
00416 break;
00417 case AUDIO_GET_PBWLOW:
00418 *lvp = dcb->dcb_pbwlo;
00419 break;
00420 case AUDIO_SET_PBWLOW:
00421 dcb->dcb_pbwlo = *lvp;
00422 break;
00423 case AUDIO_GET_PBWHIGH:
00424 *lvp = dcb->dcb_pbwhi;
00425 break;
00426 case AUDIO_SET_PBWHIGH:
00427 dcb->dcb_pbwhi = *lvp;
00428 break;
00429 case AUDIO_SETWRITETIMEOUT:
00430 dcb->dcb_wtmo = *lvp;
00431 break;
00432 case AUDIO_GETWRITETIMEOUT:
00433 *lvp = dcb->dcb_wtmo;
00434 break;
00435 default:
00436 rc = -1;
00437 break;
00438 }
00439 return rc;
00440 }
00441
00454 static int HelixPlayerFlush(NUTDEVICE *dev, uint32_t tmo)
00455 {
00456 int rc = 0;
00457 HXDCB *dcb = dev->dev_dcb;
00458
00459 for (;;) {
00460
00461 if (NutSegBufUsed()) {
00462 HelixIOCtl(dev, AUDIO_PLAY, NULL);
00463 }
00464
00465 else if (dcb->dcb_pbstat == CODEC_STATUS_IDLE) {
00466
00467 break;
00468 }
00469
00470 rc = NutEventWait(&dcb->dcb_bufque, tmo);
00471 if (rc) {
00472 break;
00473 }
00474 }
00475 return rc;
00476 }
00477
00486 static int HelixWrite(NUTFILE * nfp, CONST void *data, int len)
00487 {
00488 int rc = 0;
00489 uint8_t *bp;
00490 CONST uint8_t *dp;
00491 size_t rbytes;
00492 HXDCB *dcb = nfp->nf_dev->dev_dcb;
00493
00494 dcb->dcb_wtmo = 3000;
00495
00496 if (data == NULL || len == 0) {
00497 return HelixPlayerFlush(nfp->nf_dev, dcb->dcb_wtmo);
00498 }
00499 dp = data;
00500 while (len) {
00501 bp = (uint8_t *)NutSegBufWriteRequest(&rbytes);
00502 if (rbytes == 0) {
00503
00504 if (NutEventWait(&dcb->dcb_bufque, dcb->dcb_wtmo)) {
00505
00506 break;
00507 }
00508 } else {
00509 if (rbytes > len) {
00510 rbytes = len;
00511 }
00512 memcpy(bp, dp, rbytes);
00513 NutSegBufWriteLast(rbytes);
00514 NutEventPost(&dcb->dcb_feedme);
00515 len -= rbytes;
00516 rc += rbytes;
00517 dp += rbytes;
00518 }
00519 }
00520 return rc;
00521 }
00522
00523 #ifdef __HARVARD_ARCH__
00524
00546 static int HelixWrite_P(NUTFILE * nfp, PGM_P buffer, int len)
00547 {
00548 return -1;
00549 }
00550 #endif
00551
00557 static NUTFILE *HelixOpen(NUTDEVICE * dev, CONST char *name, int mode, int acc)
00558 {
00559 NUTFILE *nfp;
00560
00561 if ((mpi.mpi_mp3dec = MP3InitDecoder()) == NULL) {
00562 return NUTFILE_EOF;
00563 }
00564
00565 first_frame = 1;
00566
00567 NutSleep(2);
00568
00569 nfp = malloc(sizeof(NUTFILE));
00570 nfp->nf_next = NULL;
00571 nfp->nf_dev = dev;
00572 nfp->nf_fcb = NULL;
00573
00574 NutSegBufReset();
00575
00576 return nfp;
00577 }
00578
00582 static int HelixClose(NUTFILE * nfp)
00583 {
00584 HXDCB *dcb = nfp->nf_dev->dev_dcb;
00585 int rc = HelixPlayerFlush(nfp->nf_dev, dcb->dcb_wtmo);
00586
00587 if (nfp) {
00588 if (mpi.mpi_mp3dec) {
00589 MP3FreeDecoder(mpi.mpi_mp3dec);
00590 mpi.mpi_mp3dec = NULL;
00591 }
00592 free(nfp);
00593 }
00594 return rc;
00595 }
00596
00597
00598
00599
00600 static int HelixInit(NUTDEVICE * dev)
00601 {
00602 size_t avail;
00603
00604 Tlv320DacInit(DAC_OUTPUT_RATE);
00605
00606 dcb.dcb_rvol = -32;
00607 dcb.dcb_lvol = -32;
00608 Tlv320DacSetVolume(dcb.dcb_lvol, dcb.dcb_rvol);
00609
00610
00611
00612
00613 #ifdef HXCODEC0_OUTPUT_BUFSIZ
00614 avail = HXCODEC0_OUTPUT_BUFSIZ;
00615 #else
00616 avail = NutHeapAvailable() / 2;
00617 if (avail > HXCODEC0_MAX_OUTPUT_BUFSIZ) {
00618 avail = HXCODEC0_MAX_OUTPUT_BUFSIZ;
00619 }
00620 #endif
00621 if (HelixPlayerBufferInit(dev, avail)) {
00622 return -1;
00623 }
00624
00625
00626 if (NutThreadCreate(dev->dev_name, FeederThread, dev,
00627 (NUT_THREAD_HXCODEC0STACK * NUT_THREAD_STACK_MULT) + NUT_THREAD_STACK_ADD) == 0) {
00628 return -1;
00629 }
00630 return 0;
00631 }
00632
00643 NUTDEVICE devHelixCodec = {
00644 0,
00645 {'a', 'u', 'd', 'i', 'o', '0', 0, 0, 0},
00646 IFTYP_CHAR,
00647 0,
00648 0,
00649 0,
00650 &dcb,
00651 HelixInit,
00652 HelixIOCtl,
00653 NULL,
00654 HelixWrite,
00655 #ifdef __HARVARD_ARCH__
00656 HelixWrite_P,
00657 #endif
00658 HelixOpen,
00659 HelixClose,
00660 NULL
00661 };
00662