hxcodec.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2008 by egnite GmbH.
00003  * Copyright (C) 2001-2007 by egnite Software GmbH.
00004  *
00005  * All rights reserved.
00006  *
00007  * Redistribution and use in source and binary forms, with or without
00008  * modification, are permitted provided that the following conditions
00009  * are met:
00010  *
00011  * 1. Redistributions of source code must retain the above copyright
00012  *    notice, this list of conditions and the following disclaimer.
00013  * 2. Redistributions in binary form must reproduce the above copyright
00014  *    notice, this list of conditions and the following disclaimer in the
00015  *    documentation and/or other materials provided with the distribution.
00016  * 3. Neither the name of the copyright holders nor the names of
00017  *    contributors may be used to endorse or promote products derived
00018  *    from this software without specific prior written permission.
00019  *
00020  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00021  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00022  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00023  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00024  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00025  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00026  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
00027  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
00028  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00029  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
00030  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00031  * SUCH DAMAGE.
00032  *
00033  * For additional information see http://www.ethernut.de/
00034  */
00035 
00036 /*
00037  * $Log: hxcodec.c,v $
00038  * Revision 1.2  2008/10/23 08:54:07  haraldkipp
00039  * Include the correct header file.
00040  *
00041  * Revision 1.1  2008/10/05 16:56:15  haraldkipp
00042  * Added Helix audio device.
00043  *
00044  */
00045 
00046 #include <sys/atom.h>
00047 #include <sys/event.h>
00048 #include <sys/timer.h>
00049 #include <sys/heap.h>
00050 
00051 #include <cfg/arch/gpio.h>
00052 #include <cfg/audio.h>
00053 #include <dev/irqreg.h>
00054 
00055 #include <contrib/hxmp3/mp3dec.h>
00056 #include <contrib/hxmp3/hermite.h>
00057 #include <dev/hxcodec.h>
00058 #include <dev/tlv320dac.h>
00059 
00060 #include <sys/bankmem.h>
00061 
00062 #include <stdlib.h>
00063 #include <stddef.h>
00064 #include <string.h>
00065 
00066 #if 0
00067 /* Use for local debugging. */
00068 #define NUTDEBUG
00069 #include <stdio.h>
00070 #endif
00071 
00072 #ifndef DAC_OUTPUT_RATE
00073 #if defined (AT91SAM9260_EK)
00074 #define DAC_OUTPUT_RATE     44100
00075 #else
00076 #define DAC_OUTPUT_RATE     8000
00077 #endif
00078 #endif
00079 
00080 #ifndef MP3_BUFSIZ
00081 #if defined (AT91SAM9260_EK)
00082 #define MP3_BUFSIZ          1048576
00083 #else
00084 #define MP3_BUFSIZ          (4 * MAINBUF_SIZE)
00085 #endif
00086 #endif
00087 
00088 #ifndef ENABLE_RESAMPLER
00089 #if defined (AT91SAM9260_EK)
00090 #define ENABLE_RESAMPLER
00091 #endif
00092 #endif
00093 
00094 #ifdef ENABLE_RESAMPLER
00095 static int rs_maxout;
00096 static short *rs_pcmbuf;
00097 #endif
00098 
00103 
00104 typedef struct _HXDCB {
00105     int dcb_pbstat;     
00106     uint32_t dcb_scmd;    
00107     int dcb_crvol;      
00108     int dcb_srvol;      
00109     int dcb_clvol;      
00110     int dcb_slvol;      
00111     uint32_t dcb_pbwlo;   
00112     uint32_t dcb_pbwhi;   
00113 } HXDCB;
00114 
00115 static HXDCB dcb;
00116 static void *hres;
00117 
00118 typedef struct _MP3PLAYERINFO {
00119     HMP3Decoder mpi_mp3dec;
00120     MP3FrameInfo mpi_frameinfo;
00121 } MP3PLAYERINFO;
00122 
00123 static MP3PLAYERINFO mpi;
00124 
00125 static short pi_pcmbuf[MAX_NCHAN * MAX_NGRAN * MAX_NSAMP];
00126 
00131 static u_char ri_buff[MP3_BUFSIZ + 2 * MAINBUF_SIZE];
00132 
00135 static u_int ri_avail;
00136 
00137 static int first_frame;
00138 static int samprate;
00139 
00140 static int HelixPlayerFlush(void)
00141 {
00142     int tmo = 1000; /* TODO: Configurable timeout. */
00143 
00144     /* Stupid polling for now. */
00145     while(dcb.dcb_pbstat == CODEC_STATUS_PLAYING) {
00146         NutSleep(1);
00147         if (tmo-- <= 0) {
00148             return -1;
00149         }
00150     }
00151     return 0;
00152 }
00153 
00162 static int HelixWrite(NUTFILE * fp, CONST void *data, int len)
00163 {
00164     int ec;
00165     int rbytes;
00166     int skip;
00167     u_char *bufptr;
00168 
00169     /* Flush buffer if data pointer is a NULL pointer. */
00170     if (data == NULL || len == 0) {
00171         return HelixPlayerFlush();
00172     }
00173     /* Add the data to the MP3 buffer. */
00174     if (len) {
00175         memcpy(&ri_buff[ri_avail], data, len);
00176         ri_avail += len;
00177     }
00178     /* If we have a full frame, play it. */
00179     if (ri_avail >= 4 * MAINBUF_SIZE) {
00180         rbytes = ri_avail;
00181         bufptr = ri_buff;
00182         while (rbytes > 2 * MAINBUF_SIZE) {
00183             if ((skip = MP3FindSyncWord(bufptr, rbytes)) < 0) {
00184                 break;
00185             } else if (skip) {
00186                 rbytes -= skip;
00187                 bufptr += skip;
00188             } else {
00189                 ec = MP3Decode(mpi.mpi_mp3dec, &bufptr, &rbytes, pi_pcmbuf, 0);
00190                 if (ec) {
00191                     break;
00192                 }
00193                 if (first_frame) {
00194                     MP3GetLastFrameInfo(mpi.mpi_mp3dec, &mpi.mpi_frameinfo);
00195                     if (mpi.mpi_frameinfo.nChans == 1) {
00196                         samprate = mpi.mpi_frameinfo.samprate / 2;
00197                     }
00198                     else if (mpi.mpi_frameinfo.nChans == 2) {
00199                         samprate = mpi.mpi_frameinfo.samprate;
00200                     }
00201                     else {
00202                         samprate = 0;
00203                         ec = -1;
00204                     }
00205                     if (mpi.mpi_frameinfo.samprate < 8000 || samprate > DAC_OUTPUT_RATE) {
00206                         ec = -1;
00207                     }
00208                     if (mpi.mpi_frameinfo.bitsPerSample != 16) {
00209                         ec = -1;
00210                     }
00211 #ifdef ENABLE_RESAMPLER
00212                     /* If needed, initialize resampler. */
00213                     if (ec == 0 && samprate != DAC_OUTPUT_RATE) {
00214                         if ((hres = RAInitResamplerHermite(samprate, DAC_OUTPUT_RATE, mpi.mpi_frameinfo.nChans)) == NULL) {
00215                             ec = -1;
00216                         }
00217                         rs_maxout = RAGetMaxOutputHermite(mpi.mpi_frameinfo.outputSamps, hres);
00218                         if ((rs_pcmbuf = malloc(rs_maxout * 2)) == NULL) {
00219                             ec = -1;
00220                         }
00221                     }
00222 #endif
00223                     if (ec == 0) {
00224                         first_frame = 0;
00225                     }
00226                 }
00227                 if (ec == 0) {
00228                     if (Tlv320DacWrite(pi_pcmbuf, mpi.mpi_frameinfo.outputSamps)) {
00229                         return -1;
00230                     }
00231                 }
00232             }
00233         }
00234         if (rbytes > 0) {
00235             memcpy(ri_buff, &ri_buff[ri_avail - rbytes], rbytes);
00236             ri_avail = rbytes;
00237         } else {
00238             ri_avail = 0;
00239         }
00240     }
00241     return len;
00242 }
00243 
00244 #ifdef __HARVARD_ARCH__
00245 
00267 static int HelixWrite_P(NUTFILE * nfp, PGM_P buffer, int len)
00268 {
00269     return -1;
00270 }
00271 #endif
00272 
00278 static NUTFILE *HelixOpen(NUTDEVICE * dev, CONST char *name, int mode, int acc)
00279 {
00280     NUTFILE *nfp;
00281 
00282     ri_avail = 0;
00283 
00284     if ((mpi.mpi_mp3dec = MP3InitDecoder()) == NULL) {
00285         return NUTFILE_EOF;
00286     }
00287 
00288     first_frame = 1;
00289 
00290     NutSleep(2);
00291 
00292     nfp = malloc(sizeof(NUTFILE));
00293     nfp->nf_next = NULL;
00294     nfp->nf_dev = dev;
00295     nfp->nf_fcb = NULL;
00296 
00297     return nfp;
00298 }
00299 
00303 static int HelixClose(NUTFILE * nfp)
00304 {
00305     int rc = HelixPlayerFlush();
00306 
00307     if (nfp) {
00308         if (mpi.mpi_mp3dec) {
00309             MP3FreeDecoder(mpi.mpi_mp3dec);
00310             mpi.mpi_mp3dec = NULL;
00311         }
00312         free(nfp);
00313     }
00314     return rc;
00315 }
00316 
00336 static int HelixIOCtl(NUTDEVICE * dev, int req, void *conf)
00337 {
00338     int rc = 0;
00339     int *ivp = (int *) conf;
00340     int iv = *ivp;
00341 
00342     switch (req) {
00343     case AUDIO_PLAY:
00344         /* Immediately start playing. */
00345         break;
00346     case AUDIO_CANCEL:
00347         /* Immediately stop playing and discard buffer. */
00348         break;
00349     case AUDIO_GET_STATUS:
00350         break;
00351     case AUDIO_GET_PLAYGAIN:
00352         break;
00353     case AUDIO_SET_PLAYGAIN:
00354         if (iv > AUDIO_DAC_MAX_GAIN) {
00355             iv = AUDIO_DAC_MAX_GAIN;
00356         }
00357         if (iv < AUDIO_DAC_MIN_GAIN) {
00358             iv = AUDIO_DAC_MIN_GAIN;
00359         }
00360         dcb.dcb_slvol = dcb.dcb_srvol = iv;
00361         Tlv320DacSetVolume(dcb.dcb_slvol, dcb.dcb_srvol);
00362         break;
00363     default:
00364         rc = -1;
00365         break;
00366     }
00367     return rc;
00368 }
00369 
00370 /*
00371  * Called via dev_init pointer when the device is registered.
00372  */
00373 static int HelixInit(NUTDEVICE * dev)
00374 {
00375     Tlv320DacInit(DAC_OUTPUT_RATE);
00376 
00377     dcb.dcb_srvol = -32;
00378     dcb.dcb_slvol = -32;
00379     Tlv320DacSetVolume(dcb.dcb_srvol, dcb.dcb_slvol);
00380 
00381     return 0;
00382 }
00383 
00394 NUTDEVICE devHelixCodec = {
00395     0,              /* Pointer to next device, dev_next. */
00396     {'a', 'u', 'd', 'i', 'o', '0', 0, 0, 0},    /* Unique device name, dev_name. */
00397     IFTYP_CHAR,     /* Type of device, dev_type. */
00398     0,              /* Base address, dev_base (not used). */
00399     0,              /* First interrupt number, dev_irq (not used). */
00400     0,              /* Interface control block, dev_icb (not used). */
00401     &dcb,           /* Driver control block, dev_dcb. */
00402     HelixInit,         /* Driver initialization routine, dev_init. */
00403     HelixIOCtl,        /* Driver specific control function, dev_ioctl. */
00404     NULL,           /* Read from device, dev_read. */
00405     HelixWrite,        /* Write to device, dev_write. */
00406 #ifdef __HARVARD_ARCH__
00407     HelixWrite_P,      /* Write data from program space to device, dev_write_P. */
00408 #endif
00409     HelixOpen,         /* Open a device or file, dev_open. */
00410     HelixClose,        /* Close a device or file, dev_close. */
00411     NULL            /* Request file size, dev_size. */
00412 };
00413 

© 2000-2007 by egnite Software GmbH - visit http://www.ethernut.de/