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.1  2008/10/05 16:56:15  haraldkipp
00039  * Added Helix audio device.
00040  *
00041  */
00042 
00043 #include <cfg/arch/avr.h>
00044 #include <cfg/audio.h>
00045 
00046 #include <sys/atom.h>
00047 #include <sys/event.h>
00048 #include <sys/timer.h>
00049 #include <sys/heap.h>
00050 
00051 #include <dev/irqreg.h>
00052 
00053 #include <contrib/hxmp3/mp3dec.h>
00054 #include <contrib/hxmp3/hermite.h>
00055 #include <dev/hxcodec.h>
00056 #include <dev/tlv320dac.h>
00057 
00058 #include <sys/bankmem.h>
00059 
00060 #include <stdlib.h>
00061 #include <stddef.h>
00062 #include <string.h>
00063 
00064 #if 0
00065 /* Use for local debugging. */
00066 #define NUTDEBUG
00067 #include <stdio.h>
00068 #endif
00069 
00070 #ifndef DAC_OUTPUT_RATE
00071 #if defined (AT91SAM9260_EK)
00072 #define DAC_OUTPUT_RATE     44100
00073 #else
00074 #define DAC_OUTPUT_RATE     8000
00075 #endif
00076 #endif
00077 
00078 #ifndef MP3_BUFSIZ
00079 #if defined (AT91SAM9260_EK)
00080 #define MP3_BUFSIZ          1048576
00081 #else
00082 #define MP3_BUFSIZ          (4 * MAINBUF_SIZE)
00083 #endif
00084 #endif
00085 
00086 #ifndef ENABLE_RESAMPLER
00087 #if defined (AT91SAM9260_EK)
00088 #define ENABLE_RESAMPLER
00089 #endif
00090 #endif
00091 
00092 #ifdef ENABLE_RESAMPLER
00093 static int rs_maxout;
00094 static short *rs_pcmbuf;
00095 #endif
00096 
00101 
00102 typedef struct _HXDCB {
00103     int dcb_pbstat;     
00104     uint32_t dcb_scmd;    
00105     int dcb_crvol;      
00106     int dcb_srvol;      
00107     int dcb_clvol;      
00108     int dcb_slvol;      
00109     uint32_t dcb_pbwlo;   
00110     uint32_t dcb_pbwhi;   
00111 } HXDCB;
00112 
00113 static HXDCB dcb;
00114 static void *hres;
00115 
00116 typedef struct _MP3PLAYERINFO {
00117     HMP3Decoder mpi_mp3dec;
00118     MP3FrameInfo mpi_frameinfo;
00119 } MP3PLAYERINFO;
00120 
00121 static MP3PLAYERINFO mpi;
00122 
00123 static short pi_pcmbuf[MAX_NCHAN * MAX_NGRAN * MAX_NSAMP];
00124 
00129 static u_char ri_buff[MP3_BUFSIZ + 2 * MAINBUF_SIZE];
00130 
00133 static u_int ri_avail;
00134 
00135 static int first_frame;
00136 static int samprate;
00137 
00138 static int HelixPlayerFlush(void)
00139 {
00140     int tmo = 1000; /* TODO: Configurable timeout. */
00141 
00142     /* Stupid polling for now. */
00143     while(dcb.dcb_pbstat == CODEC_STATUS_PLAYING) {
00144         NutSleep(1);
00145         if (tmo-- <= 0) {
00146             return -1;
00147         }
00148     }
00149     return 0;
00150 }
00151 
00160 static int HelixWrite(NUTFILE * fp, CONST void *data, int len)
00161 {
00162     int ec;
00163     int rbytes;
00164     int skip;
00165     u_char *bufptr;
00166 
00167     /* Flush buffer if data pointer is a NULL pointer. */
00168     if (data == NULL || len == 0) {
00169         return HelixPlayerFlush();
00170     }
00171     /* Add the data to the MP3 buffer. */
00172     if (len) {
00173         memcpy(&ri_buff[ri_avail], data, len);
00174         ri_avail += len;
00175     }
00176     /* If we have a full frame, play it. */
00177     if (ri_avail >= 4 * MAINBUF_SIZE) {
00178         rbytes = ri_avail;
00179         bufptr = ri_buff;
00180         while (rbytes > 2 * MAINBUF_SIZE) {
00181             if ((skip = MP3FindSyncWord(bufptr, rbytes)) < 0) {
00182                 break;
00183             } else if (skip) {
00184                 rbytes -= skip;
00185                 bufptr += skip;
00186             } else {
00187                 ec = MP3Decode(mpi.mpi_mp3dec, &bufptr, &rbytes, pi_pcmbuf, 0);
00188                 if (ec) {
00189                     break;
00190                 }
00191                 if (first_frame) {
00192                     MP3GetLastFrameInfo(mpi.mpi_mp3dec, &mpi.mpi_frameinfo);
00193                     if (mpi.mpi_frameinfo.nChans == 1) {
00194                         samprate = mpi.mpi_frameinfo.samprate / 2;
00195                     }
00196                     else if (mpi.mpi_frameinfo.nChans == 2) {
00197                         samprate = mpi.mpi_frameinfo.samprate;
00198                     }
00199                     else {
00200                         samprate = 0;
00201                         ec = -1;
00202                     }
00203                     if (mpi.mpi_frameinfo.samprate < 8000 || samprate > DAC_OUTPUT_RATE) {
00204                         ec = -1;
00205                     }
00206                     if (mpi.mpi_frameinfo.bitsPerSample != 16) {
00207                         ec = -1;
00208                     }
00209 #ifdef ENABLE_RESAMPLER
00210                     /* If needed, initialize resampler. */
00211                     if (ec == 0 && samprate != DAC_OUTPUT_RATE) {
00212                         if ((hres = RAInitResamplerHermite(samprate, DAC_OUTPUT_RATE, mpi.mpi_frameinfo.nChans)) == NULL) {
00213                             ec = -1;
00214                         }
00215                         rs_maxout = RAGetMaxOutputHermite(mpi.mpi_frameinfo.outputSamps, hres);
00216                         if ((rs_pcmbuf = malloc(rs_maxout * 2)) == NULL) {
00217                             ec = -1;
00218                         }
00219                     }
00220 #endif
00221                     if (ec == 0) {
00222                         first_frame = 0;
00223                     }
00224                 }
00225                 if (ec == 0) {
00226                     if (Tlv320DacWrite(pi_pcmbuf, mpi.mpi_frameinfo.outputSamps)) {
00227                         return -1;
00228                     }
00229                 }
00230             }
00231         }
00232         if (rbytes > 0) {
00233             memcpy(ri_buff, &ri_buff[ri_avail - rbytes], rbytes);
00234             ri_avail = rbytes;
00235         } else {
00236             ri_avail = 0;
00237         }
00238     }
00239     return len;
00240 }
00241 
00242 #ifdef __HARVARD_ARCH__
00243 
00265 static int HelixWrite_P(NUTFILE * nfp, PGM_P buffer, int len)
00266 {
00267     return -1;
00268 }
00269 #endif
00270 
00276 static NUTFILE *HelixOpen(NUTDEVICE * dev, CONST char *name, int mode, int acc)
00277 {
00278     NUTFILE *nfp;
00279 
00280     ri_avail = 0;
00281 
00282     if ((mpi.mpi_mp3dec = MP3InitDecoder()) == NULL) {
00283         return NUTFILE_EOF;
00284     }
00285 
00286     first_frame = 1;
00287 
00288     NutSleep(2);
00289 
00290     nfp = malloc(sizeof(NUTFILE));
00291     nfp->nf_next = NULL;
00292     nfp->nf_dev = dev;
00293     nfp->nf_fcb = NULL;
00294 
00295     return nfp;
00296 }
00297 
00301 static int HelixClose(NUTFILE * nfp)
00302 {
00303     int rc = HelixPlayerFlush();
00304 
00305     if (nfp) {
00306         if (mpi.mpi_mp3dec) {
00307             MP3FreeDecoder(mpi.mpi_mp3dec);
00308             mpi.mpi_mp3dec = NULL;
00309         }
00310         free(nfp);
00311     }
00312     return rc;
00313 }
00314 
00334 static int HelixIOCtl(NUTDEVICE * dev, int req, void *conf)
00335 {
00336     int rc = 0;
00337     int *ivp = (int *) conf;
00338     int iv = *ivp;
00339 
00340     switch (req) {
00341     case AUDIO_PLAY:
00342         /* Immediately start playing. */
00343         break;
00344     case AUDIO_CANCEL:
00345         /* Immediately stop playing and discard buffer. */
00346         break;
00347     case AUDIO_GET_STATUS:
00348         break;
00349     case AUDIO_GET_PLAYGAIN:
00350         break;
00351     case AUDIO_SET_PLAYGAIN:
00352         if (iv > AUDIO_DAC_MAX_GAIN) {
00353             iv = AUDIO_DAC_MAX_GAIN;
00354         }
00355         if (iv < AUDIO_DAC_MIN_GAIN) {
00356             iv = AUDIO_DAC_MIN_GAIN;
00357         }
00358         dcb.dcb_slvol = dcb.dcb_srvol = iv;
00359         Tlv320DacSetVolume(dcb.dcb_slvol, dcb.dcb_srvol);
00360         break;
00361     default:
00362         rc = -1;
00363         break;
00364     }
00365     return rc;
00366 }
00367 
00368 /*
00369  * Called via dev_init pointer when the device is registered.
00370  */
00371 static int HelixInit(NUTDEVICE * dev)
00372 {
00373     Tlv320DacInit(DAC_OUTPUT_RATE);
00374 
00375     dcb.dcb_srvol = -32;
00376     dcb.dcb_slvol = -32;
00377     Tlv320DacSetVolume(dcb.dcb_srvol, dcb.dcb_slvol);
00378 
00379     return 0;
00380 }
00381 
00392 NUTDEVICE devHelixCodec = {
00393     0,              /* Pointer to next device, dev_next. */
00394     {'a', 'u', 'd', 'i', 'o', '0', 0, 0, 0},    /* Unique device name, dev_name. */
00395     IFTYP_CHAR,     /* Type of device, dev_type. */
00396     0,              /* Base address, dev_base (not used). */
00397     0,              /* First interrupt number, dev_irq (not used). */
00398     0,              /* Interface control block, dev_icb (not used). */
00399     &dcb,           /* Driver control block, dev_dcb. */
00400     HelixInit,         /* Driver initialization routine, dev_init. */
00401     HelixIOCtl,        /* Driver specific control function, dev_ioctl. */
00402     NULL,           /* Read from device, dev_read. */
00403     HelixWrite,        /* Write to device, dev_write. */
00404 #ifdef __HARVARD_ARCH__
00405     HelixWrite_P,      /* Write data from program space to device, dev_write_P. */
00406 #endif
00407     HelixOpen,         /* Open a device or file, dev_open. */
00408     HelixClose,        /* Close a device or file, dev_close. */
00409     NULL            /* Request file size, dev_size. */
00410 };
00411 

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