Logo Search packages:      
Sourcecode: nas version File versions  Download package

wave.c

/*
 * Copyright 1993 Network Computing Devices, Inc.
 * 
 * Permission to use, copy, modify, distribute, and sell this software and its
 * documentation for any purpose is hereby granted without fee, provided that
 * the above copyright notice appear in all copies and that both that
 * copyright notice and this permission notice appear in supporting
 * documentation, and that the name Network Computing Devices, Inc. not be
 * used in advertising or publicity pertaining to distribution of this
 * software without specific, written prior permission.
 * 
 * THIS SOFTWARE IS PROVIDED 'AS-IS'.  NETWORK COMPUTING DEVICES, INC.,
 * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING WITHOUT
 * LIMITATION ALL IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
 * PARTICULAR PURPOSE, OR NONINFRINGEMENT.  IN NO EVENT SHALL NETWORK
 * COMPUTING DEVICES, INC., BE LIABLE FOR ANY DAMAGES WHATSOEVER, INCLUDING
 * SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES, INCLUDING LOSS OF USE, DATA,
 * OR PROFITS, EVEN IF ADVISED OF THE POSSIBILITY THEREOF, AND REGARDLESS OF
 * WHETHER IN AN ACTION IN CONTRACT, TORT OR NEGLIGENCE, ARISING OUT OF OR IN
 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 * 
 * $NCDId: @(#)wave.c,v 1.26 1996/04/29 21:48:08 greg Exp $
 */

/*
 * WAVE support library
 */

#include "config.h"

#include    <stdio.h>

#if defined(HAVE_STDLIB_H)
# include <stdlib.h> 
#endif

#if defined(HAVE_MALLOC_H)
# include <malloc.h>
#endif


#include    <audio/Aos.h>
#include    <audio/wave.h>
#include    <audio/fileutil.h>

#define Err()           { WaveCloseFile(wi); return NULL; }
#define readFourcc(_f)  fread(_f, sizeof(RIFF_FOURCC), 1, wi->fp)
#define cmpID(_x, _y)                                             \
    strncmp((char *) (_x), (char *) (_y), sizeof(RIFF_FOURCC))
#define PAD2(_x)  (((_x) + 1) & ~1)

static int
readChunk(
          RiffChunk      *c,
          FILE           *fp
          )
{
    int             status;
    char            n;

    if ((status = fread(c, sizeof(RiffChunk), 1, fp)))
      if (NAS_BIG_ENDIAN)
          swapl(&c->ckSize, n);

    return status;
}

WaveInfo       *
WaveOpenFileForReading(_WaveConst char *name)
{
    RiffChunk       ck;
    RIFF_FOURCC     fourcc;
    AuInt32            fileSize;
    WaveInfo       *wi;

    if (!(wi = (WaveInfo *) malloc(sizeof(WaveInfo))))
      return NULL;

    wi->comment = NULL;
    wi->dataOffset = wi->format = wi->writing = 0;

    if (!(wi->fp = fopen(name, AU_READ_BINARY)))
      Err();

    if (!readChunk(&ck, wi->fp) ||
      cmpID(&ck.ckID, RIFF_RiffID) ||
      !readFourcc(&fourcc) ||
      cmpID(&fourcc, RIFF_WaveID))
      Err();

    fileSize = PAD2(ck.ckSize) - sizeof(RIFF_FOURCC);

    while (fileSize >= (AuInt32)sizeof(RiffChunk))
    {
      if (!readChunk(&ck, wi->fp))
          Err();

      fileSize -= sizeof(RiffChunk) + PAD2(ck.ckSize);

      /* LIST chunk */
      if (!cmpID(&ck.ckID, RIFF_ListID))
      {
          if (!readFourcc(&fourcc))
            Err();

          /* INFO chunk */
          if (!cmpID(&fourcc, RIFF_ListInfoID))
          {
            ck.ckSize -= sizeof(RIFF_FOURCC);

            while (ck.ckSize)
            {
                RiffChunk       c;

                if (!readChunk(&c, wi->fp))
                  Err();

                /* ICMT chunk */
                if (!cmpID(&c.ckID, RIFF_InfoIcmtID))
                {
                  if (!(wi->comment = (char *) malloc(c.ckSize)) ||
                      !fread(wi->comment, c.ckSize, 1, wi->fp))
                      Err();

                  if (c.ckSize & 1)
                      fgetc(wi->fp);      /* eat the pad byte */
                }
                else
                  /* skip unknown chunk */
                  fseek(wi->fp, PAD2(c.ckSize), 1);

                ck.ckSize -= sizeof(RiffChunk) + PAD2(c.ckSize);
            }
          }
          else
            /* skip unknown chunk */
            fseek(wi->fp, PAD2(ck.ckSize) - sizeof(RIFF_FOURCC), 1);
      }
      /* wave format chunk */
      else if (!cmpID(&ck.ckID, RIFF_WaveFmtID) && !wi->format)
      {
          AuInt32            dummy;

          wi->format = FileReadS(wi->fp, NAS_BIG_ENDIAN);
          wi->channels = FileReadS(wi->fp, NAS_BIG_ENDIAN);
          wi->sampleRate = FileReadL(wi->fp, NAS_BIG_ENDIAN);

          /* we don't care about the next two fields */
          dummy = FileReadL(wi->fp, NAS_BIG_ENDIAN);
          dummy = FileReadS(wi->fp, NAS_BIG_ENDIAN);

          if (wi->format != RIFF_WAVE_FORMAT_PCM)
            Err();

          wi->bitsPerSample = FileReadS(wi->fp, NAS_BIG_ENDIAN);

          /* skip any other format specific fields */
          fseek(wi->fp, PAD2(ck.ckSize - 16), 1);
      }
      /* wave data chunk */
      else if (!cmpID(&ck.ckID, RIFF_WaveDataID) && !wi->dataOffset)
      {
          long endOfFile;

          wi->dataOffset = ftell(wi->fp);
          wi->dataSize = ck.ckSize;
          fseek(wi->fp, 0, 2);
          endOfFile = ftell(wi->fp);

          /* seek past the data */
          if (fseek(wi->fp, wi->dataOffset + PAD2(ck.ckSize), 0) ||
            ftell(wi->fp) > endOfFile)
          {
            /* the seek failed, assume the size is bogus */
            fseek(wi->fp, 0, 2);
            wi->dataSize = ftell(wi->fp) - wi->dataOffset;
          }

          wi->dataOffset -= sizeof(long);
      }
      else
          /* skip unknown chunk */
          fseek(wi->fp, PAD2(ck.ckSize), 1);
    }

    if (!wi->dataOffset)
      Err();

    wi->numSamples = wi->dataSize / wi->channels / (wi->bitsPerSample >> 3);

    if (!wi->comment)
      wi->comment = FileCommentFromFilename(name);

    WaveRewindFile(wi);
    return wi;
}

WaveInfo       *
WaveOpenFileForWriting(
                       _WaveConst char *name,
                       WaveInfo       *wi
                       )
{
    int             n;

    wi->writing = wi->dataSize = 0;

    if (!(wi->fp = fopen(name, AU_WRITE_BINARY)) ||
      !fwrite(RIFF_RiffID, sizeof(RIFF_FOURCC), 1, wi->fp))
      Err();

    wi->sizeOffset = ftell(wi->fp);

    if (!FileWriteL(0, wi->fp, NAS_BIG_ENDIAN) ||
      !fwrite(RIFF_WaveID, sizeof(RIFF_FOURCC), 1, wi->fp))
      Err();

    wi->fileSize = sizeof(RIFF_FOURCC);

    if ((n = strlen(wi->comment)))
    {
      int             size;

      n++;
      size = sizeof(RiffChunk) + sizeof(RIFF_FOURCC) + PAD2(n);

      if (!fwrite(RIFF_ListID, sizeof(RIFF_FOURCC), 1, wi->fp) ||
          !FileWriteL(size, wi->fp, NAS_BIG_ENDIAN) ||
          !fwrite(RIFF_ListInfoID, sizeof(RIFF_FOURCC), 1, wi->fp) ||
          !fwrite(RIFF_InfoIcmtID, sizeof(RIFF_FOURCC), 1, wi->fp) ||
          !FileWriteL(n, wi->fp, NAS_BIG_ENDIAN) ||
          !fwrite(wi->comment, n, 1, wi->fp))
          Err();

      if (n & 1)
          fputc(0, wi->fp);   /* pad the comment */

      wi->fileSize += sizeof(RiffChunk) + size;
    }

    if (!fwrite(RIFF_WaveFmtID, sizeof(RIFF_FOURCC), 1, wi->fp) ||
      !FileWriteL(RIFF_WaveFmtSize, wi->fp, NAS_BIG_ENDIAN) ||
      !FileWriteS(RIFF_WAVE_FORMAT_PCM, wi->fp, NAS_BIG_ENDIAN) ||
      !FileWriteS(wi->channels, wi->fp, NAS_BIG_ENDIAN) ||
      !FileWriteL(wi->sampleRate, wi->fp, NAS_BIG_ENDIAN) ||
      !FileWriteL(wi->channels * wi->sampleRate * (wi->bitsPerSample >> 3),
                wi->fp, NAS_BIG_ENDIAN) ||
      !FileWriteS(wi->channels * (wi->bitsPerSample >> 3), wi->fp,
                NAS_BIG_ENDIAN) ||
      !FileWriteS(wi->bitsPerSample, wi->fp, NAS_BIG_ENDIAN))
      Err();

    wi->fileSize += sizeof(RiffChunk) + RIFF_WaveFmtSize;

    if (!fwrite(RIFF_WaveDataID, sizeof(RIFF_FOURCC), 1, wi->fp))
      Err();

    wi->dataOffset = ftell(wi->fp);

    if (!FileWriteL(0, wi->fp, NAS_BIG_ENDIAN))
      Err();

    wi->fileSize += sizeof(RiffChunk);

    wi->writing = 1;
    return wi;
}

int
WaveCloseFile(WaveInfo *wi)
{
    int             status = 0;

    if (wi->fp)
    {
      if (wi->writing)
      {
          if (wi->dataSize & 1)
            fputc(0, wi->fp); /* pad the data */

          fseek(wi->fp, wi->sizeOffset, 0);
          FileWriteL(wi->fileSize + PAD2(wi->dataSize), wi->fp, NAS_BIG_ENDIAN);
          fseek(wi->fp, wi->dataOffset, 0);
          FileWriteL(wi->dataSize, wi->fp, NAS_BIG_ENDIAN);
      }

      status = fclose(wi->fp);
    }

    if (wi->comment)
      free(wi->comment);

    free(wi);
    return status;
}

int
WaveReadFile(
             char           *p,
             int             n,
             WaveInfo       *wi
             )
{
    return fread(p, 1, n, wi->fp);
}

int
WaveWriteFile(
              char           *p,
              int             n,
              WaveInfo       *wi
              )
{
    int             num;

    num = fwrite(p, 1, n, wi->fp);
    wi->dataSize += num;
    return num;
}

int
WaveRewindFile(WaveInfo *wi)
{
    return wi->writing ? -1 : fseek(wi->fp, wi->dataOffset + sizeof(long), 0);
}

int
WaveSeekFile(
             int              n,
             WaveInfo       *wi
             )
{
    return wi->writing ? -1 :
      fseek(wi->fp, wi->dataOffset + sizeof(long) + n, 0);
}

int
WaveTellFile(WaveInfo *wi)
{
    return wi->writing ? -1 :
      ftell(wi->fp) - wi->dataOffset - sizeof(long);
}

int
WaveFlushFile(WaveInfo *wi)
{
    return fflush(wi->fp);
}

Generated by  Doxygen 1.6.0   Back to index