.wav Parser Making Popping Sounds

Started by
2 comments, last by blueshogun96 11 years, 1 month ago

I have this .wav parsing code that I've been using for quite some time, but there are some .wav files that will have a popping sound after it finishes playing. I assume that it has something to do with my code since this doesn't happen when other .wav playing programs play the sound. It shouldn't really matter, but I'm using OpenAL.

My code to load .wav files is in a single function.


ALuint wavstatic_open( char* filename )
{
	FILE* file = NULL;
	char* buffer = NULL;
	ALuint channels;
	ALuint frequency;
	ALuint format;
	ALuint bits;
	ALuint albuffer;
	long filesize = 0;
	int ret;

	/* Does the wav file exist? */
	file = fopen( filename, "rb" );
	if( !file )
		return 0;

	/* Get the file size */
	fseek( file, 0, SEEK_END );
	filesize = ftell(file);
	fseek( file, 0, SEEK_SET );

	/* Create buffers and sources */
	alGenBuffers( 1, &albuffer );
	if( alGetError() != AL_NO_ERROR )
	{
		fclose(file);
		free(buffer);
		alDeleteBuffers( 1, &albuffer );
		return 0;
	}

	/* Allocate this buffer to read bytes from as we go. */
	/* Should check for the strings "RIFF" and "WAVE" in the header, but I don't feel like
	   it at the moment, so... */
	buffer = malloc( filesize );
	fread( buffer, 1, 12, file );

	/* Check the wav file chunk header for the format information. If it's not there, forget it */
	fread( buffer, 1, 8, file );
	if( buffer[0] != 'f' || buffer[1] != 'm' || buffer[2] != 't' || buffer[3] != ' ' )
	{
		fclose(file);
		free(buffer);
		alDeleteBuffers( 1, &albuffer );
		return 0;
	}

	/* Read the wav format type. 1 == PCM.  If it's not, then we either
	   exit, or have to decode the format ourselves */
	fread( buffer, 1, 2, file );
	if( buffer[1] != 0 || buffer[0] != 1 )
	{
		fclose(file);
		free(buffer);
		alDeleteBuffers( 1, &albuffer );
		return 0;
	}

	/* Get the channel count */
	fread( buffer, 1, 2, file );
	channels = buffer[1]<<8;
	channels |= buffer[0];

	/* Get the sample frequency */
	fread( buffer, 1, 4, file );
	frequency  = buffer[3]<<24;
    frequency |= buffer[2]<<16;
    frequency |= buffer[1]<<8;
    frequency |= buffer[0];

	/* Ignore block size and bytes per second */
	fread( buffer, 1, 6, file );

	/* Get the bit depth */
	fread( buffer, 1, 2, file );
	bits = buffer[1]<<8;
	bits |= buffer[0];

	if( bits == 8 )
	{
		if( channels == 1 )
			format = AL_FORMAT_MONO8;
		else if( channels == 2 )
			format = AL_FORMAT_STEREO8;
	}
	else if( bits == 16 )
	{
		if( channels == 1 )
			format = AL_FORMAT_MONO16;
		else if( channels == 2 )
			format = AL_FORMAT_STEREO16;
	}

	/* Read the data chunk which will hold the decoded sample data */
	fread( buffer, 1, 8, file );
	if( buffer[0] != 'd' || buffer[1] != 'a' || buffer[2] != 't' || buffer[3] != 'a' )
	{
		fclose(file);
		free(buffer);
		alDeleteBuffers( 1, &albuffer );
		return 0;
	}

	/* Now read in the data section of this wav file */
	ret = fread( buffer, 1, filesize, file );
	alBufferData( albuffer, format, buffer, ret, frequency );
	if( alGetError() != AL_NO_ERROR )
	{
		fclose(file);
		free(buffer);
		alDeleteBuffers( 1, &albuffer );
		return 0;
	}

	/* That's all */
	fclose(file);
	free(buffer);

	return albuffer;
}

Not sure what it is. The pop sound at the end only happens with a few .wav files. The rest sound and work okay. Any ideas? Thanks.

Shogun.

Advertisement

Pop sounds usually happen when there's a bigger step in the sound curve. Look at the end of the .wav in an audio editor. Ideally the sound curve is zero at the end to avoid popping.

Some audio players default to fading out when playing (WinAMP)

Fruny: Ftagn! Ia! Ia! std::time_put_byname! Mglui naflftagn std::codecvt eY'ha-nthlei!,char,mbstate_t>

some audio programs put some data after the "data" lump (note: lump==chunk).
(a common example here are lumps that indicate the audio program used and/or contain data similar to that found in an ID3 tag).

the reader code appears as if it will just read all the way to the end of the file, so if anything follows the main data lump, it may result in noise and/or pops, due to this data being treated as audio.

better could be taking the lump-size into account (for the "data" lump), then use this to know how many audio samples are present (rather than how much data was read).


secondary notes:
not all WAV files will have exactly the same length for the "fmt " lump (mostly N/A for PCM WAV files);
theoretically, other lumps may appear between "fmt " and "data" lumps (not actually ran into this AFAICT);
thoeretically, audio files may contain a 'LIST'/'wavl' lump instead of a single big 'data' lump (not seen AFAICT);
RIFF does this odd thing of padding lumps up to even (multiple of 2) sizes (N/A in this case);
...

the most likely scenario is here being data following 'data', because most of the other scenarios would likely result in the decoder rejecting the file (by not seeing 'data' where it is expected).


ADD, maybe try something like (trivial edit):
/* decode the length for "data" (32 bit little-endian DWORD) */
len = buffer[4] | (buffer[5]<<8) | (buffer[6]<<16) | (buffer[7]<<24);

/* Now read in the data section of this wav file */
ret = fread( buffer, 1, len, file );

This makes sense. It would be best not to expect every chunk to come in a certain order. Also, I'm pretty sure that it's another chunk after the actual data chunk.

So far, I've only had one instance where the data chunk wasn't where I expected it to be.

This topic is closed to new replies.

Advertisement