423 lines
11 KiB
C
423 lines
11 KiB
C
/*----------------------------------------------------------------------------
|
|
*
|
|
* File:
|
|
* eas_wave.c
|
|
*
|
|
* Contents and purpose:
|
|
* This module contains .WAV file functions for the EAS synthesizer
|
|
* test harness.
|
|
*
|
|
* Copyright Sonic Network Inc. 2005
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*----------------------------------------------------------------------------
|
|
* Revision Control:
|
|
* $Revision: 658 $
|
|
* $Date: 2007-04-24 13:35:49 -0700 (Tue, 24 Apr 2007) $
|
|
*----------------------------------------------------------------------------
|
|
*/
|
|
|
|
/* lint complaints about most C library headers, so we use our own during lint step */
|
|
#ifdef _lint
|
|
#include "lint_stdlib.h"
|
|
#else
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#endif
|
|
|
|
#include "eas_wave.h"
|
|
|
|
/* .WAV file format tags */
|
|
const EAS_U32 riffTag = 0x46464952;
|
|
const EAS_U32 waveTag = 0x45564157;
|
|
const EAS_U32 fmtTag = 0x20746d66;
|
|
const EAS_U32 dataTag = 0x61746164;
|
|
|
|
#ifdef _BIG_ENDIAN
|
|
/*----------------------------------------------------------------------------
|
|
* FlipDWord()
|
|
*----------------------------------------------------------------------------
|
|
* Purpose: Endian flip a DWORD for big-endian processors
|
|
*
|
|
* Inputs:
|
|
*
|
|
* Outputs:
|
|
*
|
|
*----------------------------------------------------------------------------
|
|
*/
|
|
static void FlipDWord (EAS_U32 *pValue)
|
|
{
|
|
EAS_U8 *p;
|
|
EAS_U32 temp;
|
|
|
|
p = (EAS_U8*) pValue;
|
|
temp = (((((p[3] << 8) | p[2]) << 8) | p[1]) << 8) | p[0];
|
|
*pValue = temp;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------
|
|
* FlipWord()
|
|
*----------------------------------------------------------------------------
|
|
* Purpose: Endian flip a WORD for big-endian processors
|
|
*
|
|
* Inputs:
|
|
*
|
|
* Outputs:
|
|
*
|
|
*----------------------------------------------------------------------------
|
|
*/
|
|
static void FlipWord (EAS_U16 *pValue)
|
|
{
|
|
EAS_U8 *p;
|
|
EAS_U16 temp;
|
|
|
|
p = (EAS_U8*) pValue;
|
|
temp = (p[1] << 8) | p[0];
|
|
*pValue = temp;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------
|
|
* FlipWaveHeader()
|
|
*----------------------------------------------------------------------------
|
|
* Purpose: Endian flip the wave header for big-endian processors
|
|
*
|
|
* Inputs:
|
|
*
|
|
* Outputs:
|
|
*
|
|
*----------------------------------------------------------------------------
|
|
*/
|
|
static void FlipWaveHeader (WAVE_HEADER *p)
|
|
{
|
|
|
|
FlipDWord(&p->nRiffTag);
|
|
FlipDWord(&p->nRiffSize);
|
|
FlipDWord(&p->nWaveTag);
|
|
FlipDWord(&p->nFmtTag);
|
|
FlipDWord(&p->nFmtSize);
|
|
FlipDWord(&p->nDataTag);
|
|
FlipDWord(&p->nDataSize);
|
|
FlipWord(&p->fc.wFormatTag);
|
|
FlipWord(&p->fc.nChannels);
|
|
FlipDWord(&p->fc.nSamplesPerSec);
|
|
FlipDWord(&p->fc.nAvgBytesPerSec);
|
|
FlipWord(&p->fc.nBlockAlign);
|
|
FlipWord(&p->fc.wBitsPerSample);
|
|
|
|
}
|
|
#endif
|
|
|
|
/*----------------------------------------------------------------------------
|
|
* WaveFileCreate()
|
|
*----------------------------------------------------------------------------
|
|
* Purpose: Opens a wave file for writing and writes the header
|
|
*
|
|
* Inputs:
|
|
*
|
|
* Outputs:
|
|
*
|
|
*----------------------------------------------------------------------------
|
|
*/
|
|
|
|
WAVE_FILE *WaveFileCreate (const char *filename, EAS_I32 nChannels, EAS_I32 nSamplesPerSec, EAS_I32 wBitsPerSample)
|
|
{
|
|
WAVE_FILE *wFile;
|
|
|
|
/* allocate memory */
|
|
wFile = malloc(sizeof(WAVE_FILE));
|
|
if (!wFile)
|
|
return NULL;
|
|
wFile->write = EAS_TRUE;
|
|
|
|
/* create the file */
|
|
wFile->file = fopen(filename,"wb");
|
|
if (!wFile->file)
|
|
{
|
|
free(wFile);
|
|
return NULL;
|
|
}
|
|
|
|
/* initialize PCM format .WAV file header */
|
|
wFile->wh.nRiffTag = riffTag;
|
|
wFile->wh.nRiffSize = sizeof(WAVE_HEADER) - 8;
|
|
wFile->wh.nWaveTag = waveTag;
|
|
wFile->wh.nFmtTag = fmtTag;
|
|
wFile->wh.nFmtSize = sizeof(FMT_CHUNK);
|
|
|
|
/* initalize 'fmt' chunk */
|
|
wFile->wh.fc.wFormatTag = 1;
|
|
wFile->wh.fc.nChannels = (EAS_U16) nChannels;
|
|
wFile->wh.fc.nSamplesPerSec = (EAS_U32) nSamplesPerSec;
|
|
wFile->wh.fc.wBitsPerSample = (EAS_U16) wBitsPerSample;
|
|
wFile->wh.fc.nBlockAlign = (EAS_U16) (nChannels * (EAS_U16) (wBitsPerSample / 8));
|
|
wFile->wh.fc.nAvgBytesPerSec = wFile->wh.fc.nBlockAlign * (EAS_U32) nSamplesPerSec;
|
|
|
|
/* initialize 'data' chunk */
|
|
wFile->wh.nDataTag = dataTag;
|
|
wFile->wh.nDataSize = 0;
|
|
|
|
#ifdef _BIG_ENDIAN
|
|
FlipWaveHeader(&wFile->wh);
|
|
#endif
|
|
|
|
/* write the header */
|
|
if (fwrite(&wFile->wh, sizeof(WAVE_HEADER), 1, wFile->file) != 1)
|
|
{
|
|
fclose(wFile->file);
|
|
free(wFile);
|
|
return NULL;
|
|
}
|
|
|
|
#ifdef _BIG_ENDIAN
|
|
FlipWaveHeader(&wFile->wh);
|
|
#endif
|
|
|
|
/* return the file handle */
|
|
return wFile;
|
|
} /* end WaveFileCreate */
|
|
|
|
/*----------------------------------------------------------------------------
|
|
* WaveFileWrite()
|
|
*----------------------------------------------------------------------------
|
|
* Purpose: Writes data to the wave file
|
|
*
|
|
* Inputs:
|
|
*
|
|
* Outputs:
|
|
*
|
|
*----------------------------------------------------------------------------
|
|
*/
|
|
EAS_I32 WaveFileWrite (WAVE_FILE *wFile, void *buffer, EAS_I32 n)
|
|
{
|
|
EAS_I32 count;
|
|
|
|
/* make sure we have an open file */
|
|
if (wFile == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
#ifdef _BIG_ENDIAN
|
|
{
|
|
EAS_I32 i;
|
|
EAS_U16 *p;
|
|
p = buffer;
|
|
i = n >> 1;
|
|
while (i--)
|
|
FlipWord(p++);
|
|
}
|
|
#endif
|
|
|
|
/* write the data */
|
|
count = (EAS_I32) fwrite(buffer, 1, (size_t) n, wFile->file);
|
|
|
|
/* add the number of bytes written */
|
|
wFile->wh.nRiffSize += (EAS_U32) count;
|
|
wFile->wh.nDataSize += (EAS_U32) count;
|
|
|
|
/* return the count of bytes written */
|
|
return count;
|
|
} /* end WriteWaveHeader */
|
|
|
|
/*----------------------------------------------------------------------------
|
|
* WaveFileClose()
|
|
*----------------------------------------------------------------------------
|
|
* Purpose: Opens a wave file for writing and writes the header
|
|
*
|
|
* Inputs:
|
|
*
|
|
* Outputs:
|
|
*
|
|
*----------------------------------------------------------------------------
|
|
*/
|
|
|
|
EAS_BOOL WaveFileClose (WAVE_FILE *wFile)
|
|
{
|
|
EAS_I32 count = 1;
|
|
|
|
/* return to beginning of file and write the header */
|
|
if (wFile->write)
|
|
{
|
|
if (fseek(wFile->file, 0L, SEEK_SET) == 0)
|
|
{
|
|
|
|
#ifdef _BIG_ENDIAN
|
|
FlipWaveHeader(&wFile->wh);
|
|
#endif
|
|
count = (EAS_I32) fwrite(&wFile->wh, sizeof(WAVE_HEADER), 1, wFile->file);
|
|
#ifdef _BIG_ENDIAN
|
|
FlipWaveHeader(&wFile->wh);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
/* close the file */
|
|
if (fclose(wFile->file) != 0)
|
|
count = 0;
|
|
|
|
/* free the memory */
|
|
free(wFile);
|
|
|
|
/* return the file handle */
|
|
return (count == 1 ? EAS_TRUE : EAS_FALSE);
|
|
} /* end WaveFileClose */
|
|
|
|
#ifdef _WAVE_FILE_READ
|
|
#ifdef _BIG_ENDIAN
|
|
#error "WaveFileOpen not currently supported on big-endian processors"
|
|
#endif
|
|
/*----------------------------------------------------------------------------
|
|
* WaveFileOpen()
|
|
*----------------------------------------------------------------------------
|
|
* Purpose: Opens a wave file for reading and reads the header
|
|
*
|
|
* Inputs:
|
|
*
|
|
* Outputs:
|
|
*
|
|
*----------------------------------------------------------------------------
|
|
*/
|
|
|
|
WAVE_FILE *WaveFileOpen (const char *filename)
|
|
{
|
|
WAVE_FILE *wFile;
|
|
struct
|
|
{
|
|
EAS_U32 tag;
|
|
EAS_U32 size;
|
|
} chunk;
|
|
EAS_U32 tag;
|
|
EAS_I32 startChunkPos;
|
|
EAS_INT state;
|
|
EAS_BOOL done;
|
|
|
|
/* allocate memory */
|
|
wFile = malloc(sizeof(WAVE_FILE));
|
|
if (!wFile)
|
|
return NULL;
|
|
|
|
/* open the file */
|
|
wFile->write = EAS_FALSE;
|
|
wFile->file = fopen(filename,"rb");
|
|
if (!wFile->file)
|
|
{
|
|
free(wFile);
|
|
return NULL;
|
|
}
|
|
|
|
/* make lint happy */
|
|
chunk.tag = chunk.size = 0;
|
|
startChunkPos = 0;
|
|
|
|
/* read the RIFF tag and file size */
|
|
state = 0;
|
|
done = EAS_FALSE;
|
|
while (!done)
|
|
{
|
|
|
|
switch(state)
|
|
{
|
|
/* read the RIFF tag */
|
|
case 0:
|
|
if (fread(&chunk, sizeof(chunk), 1, wFile->file) != 1)
|
|
done = EAS_TRUE;
|
|
else
|
|
{
|
|
if (chunk.tag != riffTag)
|
|
done = EAS_TRUE;
|
|
else
|
|
state++;
|
|
}
|
|
break;
|
|
|
|
/* read the WAVE tag */
|
|
case 1:
|
|
if (fread(&tag, sizeof(tag), 1, wFile->file) != 1)
|
|
done = EAS_TRUE;
|
|
else
|
|
{
|
|
if (tag != waveTag)
|
|
done = EAS_TRUE;
|
|
else
|
|
state++;
|
|
}
|
|
break;
|
|
|
|
/* looking for fmt chunk */
|
|
case 2:
|
|
if (fread(&chunk, sizeof(chunk), 1, wFile->file) != 1)
|
|
done = EAS_TRUE;
|
|
else
|
|
{
|
|
startChunkPos = ftell(wFile->file);
|
|
|
|
/* not fmt tag, skip it */
|
|
if (chunk.tag != fmtTag)
|
|
fseek(wFile->file, startChunkPos + (EAS_I32) chunk.size, SEEK_SET);
|
|
else
|
|
state++;
|
|
}
|
|
break;
|
|
|
|
/* read fmt chunk */
|
|
case 3:
|
|
if (fread(&wFile->wh.fc, sizeof(FMT_CHUNK), 1, wFile->file) != 1)
|
|
done = EAS_TRUE;
|
|
else
|
|
{
|
|
fseek(wFile->file, startChunkPos + (EAS_I32) chunk.size, SEEK_SET);
|
|
state++;
|
|
}
|
|
break;
|
|
|
|
/* looking for data chunk */
|
|
case 4:
|
|
if (fread(&chunk, sizeof(chunk), 1, wFile->file) != 1)
|
|
done = EAS_TRUE;
|
|
else
|
|
{
|
|
startChunkPos = ftell(wFile->file);
|
|
|
|
/* not data tag, skip it */
|
|
if (chunk.tag != dataTag)
|
|
fseek(wFile->file, startChunkPos + (EAS_I32) chunk.size, SEEK_SET);
|
|
else
|
|
{
|
|
wFile->dataSize = chunk.size;
|
|
state++;
|
|
done = EAS_TRUE;
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
done = EAS_TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* if not final state, an error occurred */
|
|
if (state != 5)
|
|
{
|
|
fclose(wFile->file);
|
|
free(wFile);
|
|
return NULL;
|
|
}
|
|
|
|
/* return the file handle */
|
|
return wFile;
|
|
} /* end WaveFileOpen */
|
|
#endif
|
|
|
|
|
|
|