From c068f22329d5cc722622a2183bbb22eef2093df7 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 24 Aug 2026 11:16:07 +0200 Subject: initial import --- src/parsec/snd_wav.cpp | 449 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 449 insertions(+) create mode 100644 src/parsec/snd_wav.cpp (limited to 'src/parsec/snd_wav.cpp') diff --git a/src/parsec/snd_wav.cpp b/src/parsec/snd_wav.cpp new file mode 100644 index 0000000..7a2f06b --- /dev/null +++ b/src/parsec/snd_wav.cpp @@ -0,0 +1,449 @@ +/* + * PARSEC - WAV Format Functions + * + * $Author: uberlinuxguy $ - $Date: 2004/09/26 03:43:42 $ + * + * Orginally written by: + * Copyright (c) Andreas Varga 1998-1999 + * Copyright (c) Markus Hadwiger 1998-1999 + * Copyright (c) Clemens Beer 1998-1999 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +// C library +#include +#include +#include +#include + +// compilation flags/debug support +#include "config.h" +#include "debug.h" + +// general definitions +#include "general.h" +#include "objstruc.h" + +// global externals +#include "globals.h" + +// sound API header +#include "snd_api.h" + +// local module header +#include "snd_wav.h" + +// proprietary module headers +#include "sys_file.h" + + + +// string constants ----------------------------------------------------------- +// +static char wav_readerror[] = "wav \"%s\" readerror"; + + +// parse file header of already opened wav file ------------------------------- +// +void WAV_ParseHeader( FILE *fp, sampleinfo_s *pSampleInfo, sample_s *pSample ) +{ + ASSERT( fp != NULL ); + ASSERT( pSampleInfo != NULL ); + ASSERT( pSample != NULL ); + + // read header field by field + + char magicword[ 4 ]; + + if ( SYS_fread( &magicword, 1, 4, fp ) != 4 ) + FERROR( wav_readerror, pSampleInfo->file ); + + if ( magicword[0] != 'R' || + magicword[1] != 'I' || + magicword[2] != 'F' || + magicword[3] != 'F' ) + FERROR( wav_readerror, pSampleInfo->file ); + + if ( SYS_fread( &pSample->totalfilelength, 1, 4, fp ) != 4 ) + FERROR( wav_readerror, pSampleInfo->file ); + + pSample->totalfilelength = SWAP_32( pSample->totalfilelength ); + + if ( SYS_fread( &magicword, 1, 4, fp ) != 4 ) + FERROR( wav_readerror, pSampleInfo->file ); + + if ( magicword[0] != 'W' || + magicword[1] != 'A' || + magicword[2] != 'V' || + magicword[3] != 'E' ) + FERROR( wav_readerror, pSampleInfo->file ); + + if ( SYS_fread( &magicword, 1, 4, fp ) != 4 ) + FERROR( wav_readerror, pSampleInfo->file ); + + if ( magicword[0] != 'f' || + magicword[1] != 'm' || + magicword[2] != 't' || + magicword[3] != ' ' ) + FERROR( wav_readerror, pSampleInfo->file ); + + if ( SYS_fread( &pSample->headerlength, 1, 4, fp ) != 4 ) + FERROR( wav_readerror, pSampleInfo->file ); + + pSample->headerlength = SWAP_32( pSample->headerlength ); + if (pSample->headerlength != 16) + FERROR( wav_readerror, pSampleInfo->file ); + + + if ( SYS_fread( &pSample->datatype, 1, 2, fp ) != 2 ) + FERROR( wav_readerror, pSampleInfo->file ); + + pSample->datatype = SWAP_16( pSample->datatype ); + if (pSample->datatype != 1) + FERROR( wav_readerror, pSampleInfo->file ); + + + if ( SYS_fread( &pSample->numchannels, 1, 2, fp ) != 2 ) + FERROR( wav_readerror, pSampleInfo->file ); + + pSample->numchannels = SWAP_16( pSample->numchannels ); + if ( pSample->numchannels != 1 && pSample->numchannels != 2 ) + FERROR( wav_readerror, pSampleInfo->file ); + + + if ( SYS_fread( &pSample->samplerate, 1, 4, fp ) != 4 ) + FERROR( wav_readerror, pSampleInfo->file ); + + pSample->samplerate = SWAP_32( pSample->samplerate ); + + + dword ldummy; + if ( SYS_fread( &ldummy, 1, 4, fp ) != 4 ) + FERROR( wav_readerror, pSampleInfo->file ); + + + if ( SYS_fread( &pSample->alignment, 1, 2, fp ) != 2 ) + FERROR( wav_readerror, pSampleInfo->file ); + + pSample->alignment = SWAP_16( pSample->alignment ); + + + if ( SYS_fread( &pSample->samplesize, 1, 2, fp ) != 2 ) + FERROR( wav_readerror, pSampleInfo->file ); + + pSample->samplesize = SWAP_16( pSample->samplesize ); + + if ( SYS_fread( &magicword, 1, 4, fp ) != 4 ) + FERROR( wav_readerror, pSampleInfo->file ); + + if ( magicword[0] != 'd' || + magicword[1] != 'a' || + magicword[2] != 't' || + magicword[3] != 'a' ) { + if ( magicword[0] != 'f' || + magicword[1] != 'a' || + magicword[2] != 'c' || + magicword[3] != 't' ) { + FERROR( wav_readerror, pSampleInfo->file ); + } + else { + // skip 'fact' chunk + if ( SYS_fread( &ldummy, 1, 4, fp ) != 4 ) + FERROR( wav_readerror, pSampleInfo->file ); + if ( SYS_fread( &ldummy, 1, 4, fp ) != 4 ) + FERROR( wav_readerror, pSampleInfo->file ); + if ( SYS_fread( &ldummy, 1, 4, fp ) != 4 ) + FERROR( wav_readerror, pSampleInfo->file ); + } + } + + if ( SYS_fread( &pSample->samplebytes, 1, 4, fp ) != 4 ) + FERROR( wav_readerror, pSampleInfo->file ); + + pSample->samplebytes = SWAP_32( pSample->samplebytes ); +} + + +// open and read wav file ----------------------------------------------------- +// +void WAV_ReadSample( sampleinfo_s *pSampleInfo, sample_s *pSample ) +{ + ASSERT( pSampleInfo != NULL ); + ASSERT( pSample != NULL ); + + // open wav file + FILE *fp = SYS_fopen( pSampleInfo->file, "rb" ); + if ( fp == NULL ) + FERROR( wav_readerror, pSampleInfo->file ); + + // parse header of wav file and fill pSample structure + WAV_ParseHeader( fp, pSampleInfo, pSample ); + + // alloc sample data buffer + pSample->samplebuffer = (byte *) ALLOCMEM( pSample->samplebytes ); + for(unsigned int i = 0; isamplebytes; i++) + pSample->samplebuffer[i]=0; + if ( pSample->samplebuffer == NULL ) + OUTOFMEM( "not enough mem for sample." ); + + if ( SYS_fread( pSample->samplebuffer, 1, pSample->samplebytes, fp ) != pSample->samplebytes ) + FERROR( wav_readerror, pSampleInfo->file ); + + SYS_fclose( fp ); + + +#ifdef SYSTEM_BIG_ENDIAN + + // numframes are number of individual samples + dword numframes = pSample->samplebytes; + + if ( pSample->numchannels == 2 ) + numframes = numframes >> 1; + if ( pSample->samplesize == 16 ) + numframes = numframes >> 1; + + if ( pSample->samplesize == 16 ) { + if ( pSample->numchannels == 2 ) { + word *sweep = (word *) pSample->samplebuffer; + for ( int i = 0; i < numframes * 2; i++, sweep++ ) + *sweep = SWAP_16( *sweep ); + } else { + word *sweep = (word *) pSample->samplebuffer; + for ( int i = 0; i < numframes; i++, sweep++ ) + *sweep = SWAP_16( *sweep ); + } + + } +#endif + + //FIXME: SEAL ? + //ASSERT( pSample->numchannels == 1 ); +} + + +// free a sample previously read with WAV_ReadSample() ------------------------ +// +void WAV_FreeSample( sample_s *pSample ) +{ + ASSERT( pSample != NULL ); + + if ( pSample->samplebuffer != NULL ) { + FREEMEM( pSample->samplebuffer ); + pSample->samplebuffer = NULL; + } + + FREEMEM( pSample ); +} + + +// convert a stereo sample to mono -------------------------------------------- +// +void WAV_ConvertToMono( sample_s *pSample ) +{ + ASSERT( pSample != NULL ); + + if ( pSample->numchannels == 2 ) { + // numframes are number of individual samples + dword numframes = pSample->samplebytes >> 1; + + if ( pSample->samplesize == 16 ) { + + // handle 16 bit stereo samples + numframes = numframes >> 1; + + word* source = (word *) pSample->samplebuffer; + word* dest = (word *) ALLOCMEM( pSample->samplebytes >> 1 ); + word* new_samplebuffer = dest; +// signed long temp; +// signed short s1,s2; + + for ( dword i = 0; i < numframes; i++ ) { + +//#define AVERAGING +#ifdef AVERAGING + + //FIXME: this does not work yet + + //temp = ( (dword) *source ) + ( (dword) *( source+1 ) ); + s1 = *source; + s2 = *source+1; + + temp = (signed long)( s1 ) & 0x0000ffff ; + temp += (signed long)( s2 ) & 0x0000ffff ; + + *dest = (signed short)( ( temp / 2 ) & 0xffff ); + +#else + + *dest = ( *source + 1 ); + +#endif // AVERAGING + + //*dest = ( *source >> 1 ) + ( *( source+1 ) >> 1 ); + //*dest = ( *source ) >> 1; + //source++; + //*dest += ( *source ) >> 1; + + source++; + source++; + dest++; + } + + // free the stereo buffer + FREEMEM( pSample->samplebuffer ); + + // assign the mono buffer, and correct samplebytes, numchannels, alignment + pSample->samplebuffer = (byte*) new_samplebuffer; + pSample->samplebytes = pSample->samplebytes >> 1; + pSample->numchannels = 1; + pSample->alignment = pSample->alignment >> 1; + + } else { + + // handle 8 bit stereo samples + byte* source = (byte *) pSample->samplebuffer; + byte* dest = (byte *) ALLOCMEM( pSample->samplebytes >> 1 ); + byte* new_samplebuffer = dest; +// signed long temp; +// signed short s1,s2; + + for ( dword i = 0; i < numframes; i++ ) { + + *dest = ( *source + 1 ); + + //*dest = ( *source >> 1 ) + ( *( source+1 ) >> 1 ); + //*dest = ( *source ) >> 1; + //source++; + //*dest += ( *source ) >> 1; + + source++; + source++; + dest++; + } + + // free the stereo buffer + FREEMEM( pSample->samplebuffer ); + + // assign the mono buffer, and correct samplebytes, numchannels, alignment + pSample->samplebuffer = (byte*) new_samplebuffer; + pSample->samplebytes = pSample->samplebytes >> 1; + pSample->numchannels = 1; + pSample->alignment = pSample->alignment >> 1; + } + } +} + + +// convert a sample to a given samplerate ------------------------------------- +// +void WAV_ConvertRate( sample_s *pSample, int samplerate ) +{ + ASSERT( pSample != NULL ); + ASSERT( ( samplerate >= 11025 ) && ( samplerate <= 44100 ) ); + + int origrate = pSample->samplerate; + + // we don't upsample + if ( origrate <= samplerate ) + return; + + float resampleratio = ( (float) origrate ) / ( (float) samplerate ); + + // numframes are number of individual samples + dword numbytes = pSample->samplebytes; + dword numframes = numbytes; + + if ( pSample->numchannels == 2 ) + numframes = numframes >> 1; + if ( pSample->samplesize == 16 ) + numframes = numframes >> 1; + + dword destframes = FLOAT2INT( numframes / resampleratio ); + dword destbytes = FLOAT2INT( numbytes / resampleratio ); + + byte* newbuffer = NULL; + int destsample; + float srcpos = 0; + + if ( pSample->samplesize == 16 ) { + + word* source = (word *) pSample->samplebuffer; + word* dest = (word *) ALLOCMEM( destbytes ); + if ( dest == NULL ) + OUTOFMEM( 0 ); + + newbuffer = (byte *) dest; + + if ( pSample->numchannels == 2 ) { + + for ( dword sid = 0; sid < destframes*2; sid += 2 ) { + destsample = source[ FLOAT2INT( srcpos ) ]; + dest[ sid ] = destsample; + destsample = source[ FLOAT2INT( srcpos + 1 ) ]; + dest[ sid + 1 ] = destsample; + + srcpos += resampleratio * 2; + } + + } else if ( pSample->numchannels == 1 ) { + + for ( dword sid = 0; sid < destframes; sid++ ) { + destsample = source[ FLOAT2INT( srcpos ) ]; + dest[ sid ] = destsample; + + srcpos += resampleratio; + } + } + + } else if ( pSample->samplesize == 8 ) { + + byte* source = (byte *) pSample->samplebuffer; + byte* dest = (byte *) ALLOCMEM( destbytes ); + if ( dest == NULL ) + OUTOFMEM( 0 ); + + newbuffer = dest; + + if ( pSample->numchannels == 2 ) { + + for ( dword sid = 0; sid < destframes*2; sid += 2 ) { + destsample = source[ FLOAT2INT( srcpos ) ]; + dest[ sid ] = destsample; + destsample = source[ FLOAT2INT( srcpos + 1 ) ]; + dest[ sid + 1 ] = destsample; + + srcpos += resampleratio * 2; + } + + } else if ( pSample->numchannels == 1 ) { + + for ( dword sid = 0; sid < destframes; sid++ ) { + destsample = source[ FLOAT2INT( srcpos ) ]; + dest[ sid ] = destsample; + + srcpos += resampleratio; + } + } + } + + FREEMEM( pSample->samplebuffer ); + pSample->samplebuffer = newbuffer; + pSample->samplerate = samplerate; + pSample->samplebytes = destbytes; +} + + + -- cgit v1.2.3