/*--------------------------------------------------------------------------* Project: Revolution SOUNDFILE dynamic link library File: Wavfile.c Copyright (C)2001-2009 Nintendo All Rights Reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo of America Inc. and/or Nintendo Company Ltd., and are protected by Federal copyright law. They may not be disclosed to third parties or copied or duplicated in any form, in whole or in part, without the prior written consent of Nintendo. $Log: Wavfile.c,v $ Revision 1.4 2009/03/31 00:16:45 aka Copied from SDK_3_2_DEV_BRANCH. Revision 1.2.40.2 2009/03/31 00:14:43 aka Revised CVS log. Revision 1.2.40.1 2009/03/30 04:39:30 aka Added supporting a wav file with loop information. Cleaned up. Revision 1.2 2006/02/09 06:51:39 aka Changed copyright. *--------------------------------------------------------------------------*/ #include #include #include "Wavfile.h" u32 * str_riff = (u32 *)"RIFF"; u32 * str_wave = (u32 *)"WAVE"; u32 * str_fmt = (u32 *)"fmt "; u32 * str_data = (u32 *)"data"; u32 * str_smpl = (u32 *)"smpl"; /*---------------------------------------------------------------------------* Name: wavCreateHeader Description: create a Wave file header. Arguments: wc pointer of a WAVECHUNK structure. channels num of channels. samples num of samples. bitPerSample bit width per a sample. sampleRate sampling frequency. loopEnd end samlpe number of a loop. Returns: none. *---------------------------------------------------------------------------*/ void wavCreateHeader ( WAVECHUNK *wc, int channels, int samples, int bitsPerSample, int sampleRate, int loopEnd ) { u32 datasize, riffchunksize; u16 blocksize; *((u32*)(wc->chunkId)) = *str_riff; *((u32*)(wc->formType)) = *str_wave; *((u32*)(wc->fmt.chunkId)) = *str_fmt; *((u32*)(wc->data.chunkId)) = *str_data; blocksize = channels * ( bitsPerSample / 8 ); datasize = blocksize * samples; riffchunksize = datasize + 36; if (loopEnd) { riffchunksize += sizeof(SMPLCHUNK) + sizeof(SMPLLOOP); } wc->chunkSize = riffchunksize; wc->fmt.chunkSize = 16; wc->fmt.waveFormatType = 1; wc->fmt.channel = channels; wc->fmt.samplesPerSec = sampleRate; wc->fmt.bytesPerSec = sampleRate * blocksize; wc->fmt.blockSize = blocksize; wc->fmt.bitsPerSample = bitsPerSample; wc->data.chunkSize = datasize; return; } /*---------------------------------------------------------------------------* Name: wavWriteHeader Description: output a Wave file header. Arguments: wc pointer of a WAVECHUNK structure. outfile pointer of a FILE object. Returns: none. *---------------------------------------------------------------------------*/ void wavWriteHeader ( WAVECHUNK *wc, FILE *outfile ) { fwrite(wc, 1, sizeof(WAVECHUNK), outfile); return; } /*---------------------------------------------------------------------------* Name: wavCreateSmplChunk Description: create a SMPL chunk. Arguments: wc pointer of a WAVECHUNK structure. sc pointer of a SMPLCHUNK structure. sl pointer of a SMPLLOOP structure. loopStart position of loop start loopEnd position of loop end Returns: none. *---------------------------------------------------------------------------*/ void wavCreateSmplChunk ( WAVECHUNK *wc, SMPLCHUNK *sc, SMPLLOOP *sl, u32 loopStart, u32 loopEnd ) { *((u32*)(sc->chunkId)) = *str_smpl; sc->chunkSize = sizeof(SMPLCHUNK) + sizeof(SMPLLOOP) - 8; sc->manufacturer = 0; // (ignore) sc->product = 0; // (ignore) sc->samplePeriod = 0; // (ignore) sc->midiUnityNote = 0; // (ignore) sc->midiPitchFraction = 0; // (ignore) sc->smpteFormat = 0; // (ignore) sc->smpteOffset = 0; // (ignore) sc->sampleLoops = 1; // only 1 loop sc->samplerData = 0; // (ignore) sl->id = 0; // (ignore) sl->type = 0; // forward loop sl->start = loopStart; // loop start sl->end = loopEnd - 1; // loop end sl->fraction = 0; // (ignore) sl->playCount = 0; // infinte loop } /*---------------------------------------------------------------------------* Name: wavWriteSmplChunk Description: output a SMPL chunk. Arguments: sc pointer of a SMPLCHUNK structure. sl pointer of a SMPLLOOP structure. outfile pointer of a FILE object. Returns: none. *---------------------------------------------------------------------------*/ void wavWriteSmplChunk(SMPLCHUNK *sc, SMPLLOOP *sl, FILE *outfile) { fwrite(sc, 1, sizeof(SMPLCHUNK), outfile); fwrite(sl, 1, sizeof(SMPLLOOP), outfile); } /*---------------------------------------------------------------------------* Name: wavReadHeader Description: get & parse a Wave file header. Arguments: wc pointer of a WAVECHUNK structure. li pointer of a LOOPINFO structure. infile pointer of a FILE object. Returns: TRUE OK. FALSE invalid file. *---------------------------------------------------------------------------*/ int wavReadHeader ( WAVECHUNK *wc, LOOPINFO *li, FILE *infile ) { u32 d, riffchunksize, size; int state; int remaining; int top; SMPLCHUNK smpl; SMPLLOOP loop; state = 0; if (0 != fseek(infile, 0, SEEK_SET)) { return FALSE; } // check chunk ID = "RIFF" fread(&d, 1, sizeof(u32), infile); if (d != *str_riff) { return FALSE; } *(u32*)(wc->chunkId) = d; // get chunk size fread(&riffchunksize, 1, sizeof(u32), infile); wc->chunkSize = riffchunksize; // check RIFF type = "WAVE" fread(&d, 1, sizeof(u32), infile); if (d != *str_wave) { return FALSE; } *(u32*)(wc->formType) = d; riffchunksize -= 4; // check chunks while (riffchunksize > 8) { // get chunk ID fread(&d, 1, sizeof(u32), infile); // get chunk size fread(&size, 1, sizeof(u32), infile); // check chunk ID if (d == *str_fmt) { // fmt chunk *(u32*)(wc->fmt.chunkId) = d; wc->fmt.chunkSize = size; state++; fread(&wc->fmt.waveFormatType, 1, sizeof(FMTCHUNK) - 8, infile); remaining = size - (sizeof(FMTCHUNK) - 8); if (remaining > 0) { fseek(infile, remaining, SEEK_CUR); } } else if (d == *str_data) { // data chunk *(u32*)(wc->data.chunkId) = d; wc->data.chunkSize = size; state++; top = ftell(infile); fseek(infile, size, SEEK_CUR); } else if (d == *str_smpl) { // smpl chunk fread(&smpl.manufacturer, 1, sizeof(SMPLCHUNK) - 8, infile); remaining = size - (sizeof(SMPLCHUNK) - 8); if (smpl.sampleLoops) { fread(&loop, 1, sizeof(SMPLLOOP), infile); remaining -= sizeof(SMPLLOOP); } if (remaining > 0) { fseek(infile, remaining, SEEK_CUR); } } else { // other chunks fseek(infile, size, SEEK_CUR); } riffchunksize -= (2 * sizeof(u32)) + size; } if (riffchunksize < 0) { return FALSE; } if (state != 2) { return FALSE; } // fill LOOPINFO li->start = 0; li->end = 0; if (smpl.sampleLoops && !loop.type) { li->start = loop.start; li->end = loop.end + 1; // adjust to AIFF } // return to the top of samples fseek(infile, top, SEEK_SET); return TRUE; } /*---------------------------------------------------------------------------* Name: wavGetSamples Description: return num of samples. Arguments: wc pointer of a WAVECHUNK structure. Returns: num of samples. *---------------------------------------------------------------------------*/ u32 wavGetSamples(WAVECHUNK *wc) { u32 a, bps; bps = wc->fmt.channel * wc->fmt.bitsPerSample / 8; a = wc->data.chunkSize / bps; return a; } /*---------------------------------------------------------------------------* Name: wavGetChannels Description: return num of channels. Arguments: wc pointer of a WAVECHUNK structure. Returns: num of channels. *---------------------------------------------------------------------------*/ u32 wavGetChannels(WAVECHUNK *wc) { return (u32)wc->fmt.channel; } /*---------------------------------------------------------------------------* Name: wavGetBitsPerSample Description: return bit width per a sample. Arguments: wc pointer of a WAVECHUNK structure. Returns: bit width per a sample. *---------------------------------------------------------------------------*/ u32 wavGetBitsPerSample(WAVECHUNK *wc) { return (u32)wc->fmt.bitsPerSample; } /*---------------------------------------------------------------------------* Name: wavGetSampleRate Description: return num of samples per 1 sec. Arguments: wc pointer of a WAVECHUNK structure. Returns: num of samples per sec. *---------------------------------------------------------------------------*/ u32 wavGetSampleRate(WAVECHUNK *wc) { return (u32)wc->fmt.samplesPerSec; }