vadpcm_dec.c 8.08 KB
#include "vadpcm.h"
#include <signal.h>

static void
int_handler(int sig)
{
    /*
     * Exit nicely on ^C signal
     */
    int flags = fcntl(0, F_GETFL, 0);
    flags &= ~O_NDELAY;
    fcntl(0, F_SETFL, flags);
    exit(0);
    
}

static char usage[] = "bitfile";
static const struct sigaction int_act = {SA_RESTART, int_handler, 0};

main(int argc, char *argv[])
{
    extern char *optarg;
    extern int	optind;	
    int 	c;

    char
        cc,
        doloop = 0;
    
    short
        order,
        version,
        nloops,
        npredictors;
    
    int
        flags,
        ***coefTable = NULL,
        i,
        j,
        *outp,
        *state,
        done = 0,
        num,
        ts,
        soundPointer,
        cType,
        offset,
        currPos = 0,
        nSamples,
        framePos,
        loopBegin,
        left;

    ALADPCMloop
        *aloops;
    
    Chunk
        FormChunk;
    
    ChunkHeader
        Header;
    
    CommonChunk
        CommChunk;
    
    SoundDataChunk
        SndDChunk;

    char
        *ChunkName;

    FILE
        *ifile;
    
    char *progname = argv[0];
    
    if (argc<2){
        fprintf(stderr,"%s %s\n",progname,usage);
        exit(1);
    }
    
    while ((c=getopt(argc,argv,"l"))!=-1){
        switch (c) {
            case 'l':
                doloop = 1;
                break;
        }
    }
    argv += optind-1;
    
    if ((ifile = fopen(argv[1], "r")) == NULL){
        fprintf(stderr,"%s: bitstream file [%s] could not be opened\n",
                progname, argv[1]);
        exit(1);
    }
    
    state = (int *) malloc(FRAMESIZE*sizeof(int));
    for (i=0; i<FRAMESIZE; i++)
        state[i] = 0;

    /*
     * Read the FORM chunk and check for AIFC file
     */
    fread(&FormChunk, sizeof(Chunk), 1, ifile);
    if ((FormChunk.ckID != IFF_ID_FORM) ||
        (FormChunk.formType != IFF_ID_AIFC)) {
        fprintf(stderr,"%s: [%s] is not an AIFF-C File\n",progname,argv[1]);
        exit(1);
    }

    /*
     * Scan the aifc file for a COMMON chunk, SSND chunk
     * and application specific chunks defining a codebook
     * and loop points
     */

    while (!done) {

        num = fread(&Header, sizeof(ChunkHeader), 1, ifile);
        if (num < 1) {
            done = 1;
            break;
        }
        Header.ckSize  = ++Header.ckSize & ~1;
        
        switch (Header.ckID) {
            case (IFF_ID_COMM):

                offset = ftell(ifile);
                num = fread (&CommChunk, sizeof(CommonChunk), 1, ifile);
                if (num < 1) {
                    fprintf(stderr,"%s: error parsing file [%s]\n", progname, argv[1]);
                    done = 1;
                }                
                
                /*
                 * Check for a valid file format
                 */
                cType = (CommChunk.compressionTypeH<<16) + CommChunk.compressionTypeL;
                if (cType != 'VAPC'){
                    fprintf(stderr,"%s: file [%s] is of the wrong compression type.\n",
                            progname, argv[1]);
                    exit(1);
                }
                if (CommChunk.numChannels != 1){
                    fprintf(stderr,"%s: file [%s] contains %ld channels, only 1 channel supported.\n",
                            progname, argv[1], CommChunk.numChannels);
                    exit(1);
                }
                if (CommChunk.sampleSize != 16){
                    fprintf(stderr,"%s: file [%s] contains %ld bit samples, only 16 bit samples supported.\n",
                            progname, argv[1], CommChunk.sampleSize);
                    exit(1);
                }
                nSamples = (CommChunk.numFramesH<<16) + CommChunk.numFramesL;
                fseek(ifile, offset + Header.ckSize, SEEK_SET);
                
                break;
            
            case (IFF_ID_SSND):
                offset = ftell(ifile);
                
                fread(&SndDChunk, sizeof(SndDChunk), 1, ifile);
                assert(SndDChunk.offset == 0);
                assert(SndDChunk.blockSize == 0);
                
                soundPointer = ftell(ifile);

                fseek(ifile, offset + Header.ckSize, SEEK_SET);
                break;

            case (IFF_ID_APPL):
                offset = ftell(ifile);
                fread(&ts, sizeof(long), 1, ifile);
                if (ts == 'stoc'){
                    ChunkName = ReadPString(ifile);
                    if (!strcmp(CODE_NAME, ChunkName)){
                        fread(&version, sizeof(short), 1, ifile);
                        if (version != VERSION)
                            fprintf(stderr,"Non-identical codebook chunk versions\n");
                        readaifccodebook(ifile, &coefTable, &order, &npredictors);
                    } else
                        if (!strcmp(LOOP_NAME, ChunkName)){
                            fread(&version, sizeof(short), 1, ifile);
                            if (version != VERSION)
                                fprintf(stderr,"Non-identical loop chunk versions\n");
                            aloops = readlooppoints(ifile, &nloops);
                        }
                }
                fseek(ifile, offset + Header.ckSize, SEEK_SET);
                break;
            default:                
                /* skip chunks we don't know about */
                fseek(ifile, Header.ckSize, SEEK_CUR);                
                break;
        }        
    }
    if (coefTable==NULL){
        fprintf(stderr,"%s: Codebook missing from bitstream [%s]\n",argv[0], argv[1]);
        exit(1);
    }

    outp = (int *) malloc(FRAMESIZE*sizeof(int));
    for (i=0; i<order; i++)
        outp[FRAMESIZE-1-i] = 0;

    /*
     * Move to the start of sound data
     */
    fseek(ifile, soundPointer, SEEK_SET);

    if (doloop && (nloops > 0)){

        /*
         * Set up non-blocking i/o
         */
        sigaction(SIGINT,    &int_act, NULL);

        flags = fcntl(0, F_GETFL, 0);
        flags |= O_NDELAY;
        fcntl(0, F_SETFL, flags);
        
        for (i=0; i<nloops; i++){
        
            while(currPos<aloops[i].end){
                left = aloops[i].end - currPos;
                vdecodeframe(ifile, outp, order, coefTable);
                writeout(stdout, (left<FRAMESIZE) ? left : FRAMESIZE, outp, outp, 1);
                currPos += FRAMESIZE;
            }
            while (!read(0, &cc, 1)){
                /*
                 * Go the the start point
                 */
                framePos = aloops[i].start/FRAMESIZE + 1;
                fseek(ifile, soundPointer + framePos * FRAMEBYTES, SEEK_SET);
                /*
                 * Restore state
                 */
                for (j=0; j<FRAMESIZE; j++)
                    outp[j] = aloops[i].state[j];
                loopBegin = aloops[i].start % FRAMESIZE;
                writeout(stdout, FRAMESIZE - loopBegin, outp+loopBegin, outp+loopBegin, 1);
                currPos = framePos*FRAMESIZE;
                while(currPos<aloops[i].end){
                    left = aloops[i].end - currPos;
                    vdecodeframe(ifile, outp, order, coefTable);
                    writeout(stdout, (left<FRAMESIZE) ? left : FRAMESIZE, outp, outp, 1);
                    currPos += FRAMESIZE;
                }
            }
            left = FRAMESIZE - left;
            if (left)
                writeout(stdout, left, outp + left, outp + left, 1);

            while(currPos<nSamples){
                vdecodeframe(ifile, outp, order, coefTable);
                left = nSamples - currPos;
                writeout(stdout, (left<FRAMESIZE) ? left : FRAMESIZE, outp, outp, 1);
                currPos += FRAMESIZE;
            }

            /*
             * Switch back to blocking i/o
             */
            flags = fcntl(0, F_GETFL, 0);
            flags &= ~O_NDELAY;
            fcntl(0, F_SETFL, flags);
        }
    }
    else {
            while(currPos<nSamples){
                vdecodeframe(ifile, outp, order, coefTable);
                writeout(stdout, FRAMESIZE, outp, outp, 1);
                currPos += FRAMESIZE;
            }
    }
    
    fclose(ifile);
}