ref: c578df167489336da52f1d5703297dd2b1e281e1
parent: faa2a505ba7ee8c17679b208e4bfb6b30623a332
author: Simon Howard <fraggle@gmail.com>
date: Wed Sep 7 18:24:26 EDT 2005
Modify the sound effect caching behaviour: sounds which are not playing are now marked as PU_CACHE; it is otherwise possible to run out of memory. Subversion-branch: /trunk/chocolate-doom Subversion-revision: 87
--- a/src/i_sound.c
+++ b/src/i_sound.c
@@ -1,7 +1,7 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
-// $Id: i_sound.c 80 2005-09-06 22:39:43Z fraggle $
+// $Id: i_sound.c 87 2005-09-07 22:24:26Z fraggle $
//
// Copyright(C) 1993-1996 Id Software, Inc.
// Copyright(C) 2005 Simon Howard
@@ -22,6 +22,10 @@
// 02111-1307, USA.
//
// $Log$
+// Revision 1.17 2005/09/07 22:24:26 fraggle
+// Modify the sound effect caching behaviour: sounds which are not playing
+// are now marked as PU_CACHE; it is otherwise possible to run out of memory.
+//
// Revision 1.16 2005/09/06 22:39:43 fraggle
// Restore -nosound, -nosfx, -nomusic
//
@@ -83,7 +87,7 @@
//-----------------------------------------------------------------------------
static const char
-rcsid[] = "$Id: i_sound.c 80 2005-09-06 22:39:43Z fraggle $";
+rcsid[] = "$Id: i_sound.c 87 2005-09-07 22:24:26Z fraggle $";
#include <stdio.h>
#include <stdlib.h>
@@ -110,19 +114,49 @@
static boolean sound_initialised = false;
static Mix_Chunk sound_chunks[NUMSFX];
+static int channels_playing[NUM_CHANNELS];
-static byte *expand_sound_data(byte *data, int samplerate, int length)
+// When a sound stops, check if it is still playing. If it is not,
+// we can mark the sound data as CACHE to be freed back for other
+// means.
+
+void ReleaseSoundOnChannel(int channel)
{
- byte *result = data;
int i;
+ int id = channels_playing[channel];
+ if (!id)
+ return;
+
+ channels_playing[channel] = sfx_None;
+
+ for (i=0; i<NUM_CHANNELS; ++i)
+ {
+ // Playing on this channel? if so, don't release.
+
+ if (channels_playing[i] == id)
+ return;
+ }
+
+ // Not used on any channel, and can be safely released
+
+ Z_ChangeTag(sound_chunks[id].abuf, PU_CACHE);
+}
+
+// Expands the 11025Hz, 8bit, mono sound effects in Doom to
+// 22050Hz, 16bit stereo
+
+static void ExpandSoundData(byte *data, int samplerate, int length,
+ Mix_Chunk *destination)
+{
+ byte *expanded = (byte *) destination->abuf;
+ int i;
+
if (samplerate == 11025)
{
// need to expand to 2 channels, 11025->22050 and 8->16 bit
- result = Z_Malloc(length * 8, PU_STATIC, NULL);
-
for (i=0; i<length; ++i)
{
Uint16 sample;
@@ -130,18 +164,14 @@
sample = data[i] | (data[i] << 8);
sample -= 32768;
- result[i * 8] = result[i * 8 + 2]
- = result[i * 8 + 4] = result[i * 8 + 6] = sample & 0xff;
- result[i * 8 + 1] = result[i * 8 + 3]
- = result[i * 8 + 5] = result[i * 8 + 7] = (sample >> 8) & 0xff;
+ expanded[i * 8] = expanded[i * 8 + 2]
+ = expanded[i * 8 + 4] = expanded[i * 8 + 6] = sample & 0xff;
+ expanded[i * 8 + 1] = expanded[i * 8 + 3]
+ = expanded[i * 8 + 5] = expanded[i * 8 + 7] = (sample >> 8) & 0xff;
}
}
else if (samplerate == 22050)
{
- // need to expand to 2 channels (sample rate is already correct)
-
- result = Z_Malloc(length * 4, PU_STATIC, NULL);
-
for (i=0; i<length; ++i)
{
Uint16 sample;
@@ -149,8 +179,8 @@
sample = data[i] | (data[i] << 8);
sample -= 32768;
- result[i * 4] = result[i * 4 + 2] = sample & 0xff;
- result[i * 4 + 1] = result[i * 4 + 3] = (sample >> 8) & 0xff;
+ expanded[i * 4] = expanded[i * 4 + 2] = sample & 0xff;
+ expanded[i * 4 + 1] = expanded[i * 4 + 3] = (sample >> 8) & 0xff;
}
}
else
@@ -157,32 +187,52 @@
{
I_Error("Unsupported sample rate %i", samplerate);
}
-
- return result;
}
-static Mix_Chunk *getsfx(int sound)
+// Load and convert a sound effect
+
+static void CacheSFX(int sound)
{
- if (sound_chunks[sound].abuf == NULL)
- {
- int lumpnum;
- int samplerate;
- int length;
- byte *data;
+ int lumpnum;
+ int samplerate;
+ int length;
+ int expanded_length;
+ byte *data;
- // need to load the sound
+ // need to load the sound
- lumpnum = I_GetSfxLumpNum(&S_sfx[sound]);
- data = W_CacheLumpNum(lumpnum, PU_STATIC);
+ lumpnum = I_GetSfxLumpNum(&S_sfx[sound]);
+ data = W_CacheLumpNum(lumpnum, PU_STATIC);
- samplerate = (data[3] << 8) | data[2];
- length = (data[5] << 8) | data[4];
+ samplerate = (data[3] << 8) | data[2];
+ length = (data[5] << 8) | data[4];
+ expanded_length = (length * 4) * (22050 / samplerate);
- sound_chunks[sound].allocated = 1;
- sound_chunks[sound].abuf = expand_sound_data(data + 8, samplerate, length);
- sound_chunks[sound].alen = (length * 4) * (22050 / samplerate);
- sound_chunks[sound].volume = 64;
+ sound_chunks[sound].allocated = 1;
+ sound_chunks[sound].alen = expanded_length;
+ sound_chunks[sound].abuf
+ = Z_Malloc(expanded_length, PU_STATIC, &sound_chunks[sound].abuf);
+ sound_chunks[sound].volume = 64;
+
+ ExpandSoundData(data + 8, samplerate, length, &sound_chunks[sound]);
+
+ // don't need the original lump any more
+
+ Z_ChangeTag(data, PU_CACHE);
+}
+
+static Mix_Chunk *getsfx(int sound)
+{
+ if (sound_chunks[sound].abuf == NULL)
+ {
+ CacheSFX(sound);
}
+ else
+ {
+ // don't free the sound while it is playing!
+
+ Z_ChangeTag(sound_chunks[sound].abuf, PU_STATIC);
+ }
return &sound_chunks[sound];
}
@@ -231,7 +281,6 @@
sprintf(namebuf, "ds%s", sfx->name);
return W_GetNumForName(namebuf);
}
-
//
// Starting a sound means adding it
// to the current list of active sounds
@@ -258,6 +307,13 @@
if (!sound_initialised)
return 0;
+ // Release a sound effect if there is already one playing
+ // on this channel
+
+ ReleaseSoundOnChannel(channel);
+
+ // Get the sound data
+
chunk = getsfx(id);
// play sound
@@ -264,6 +320,8 @@
Mix_PlayChannelTimed(channel, chunk, 0, -1);
+ channels_playing[channel] = id;
+
// set separation, etc.
I_UpdateSoundParams(channel, vol, sep, pitch);
@@ -271,13 +329,17 @@
return channel;
}
-
-
void I_StopSound (int handle)
{
if (!sound_initialised)
return;
+
Mix_HaltChannel(handle);
+
+ // Sound data is no longer needed; release the
+ // sound data being used for this channel
+
+ ReleaseSoundOnChannel(handle);
}
@@ -292,21 +354,29 @@
+//
+// Periodically called to update the sound system
//
-// This function loops all active (internal) sound
-// channels, retrieves a given number of samples
-// from the raw sound data, modifies it according
-// to the current (internal) channel parameters,
-// mixes the per channel samples into the global
-// mixbuffer, clamping it to the allowed range,
-// and sets up everything for transferring the
-// contents of the mixbuffer to the (two)
-// hardware channels (left and right, that is).
-//
-// This function currently supports only 16bit.
-//
+
void I_UpdateSound( void )
{
+ int i;
+
+ if (!sound_initialised)
+ return;
+
+ // Check all channels to see if a sound has finished
+
+ for (i=0; i<NUM_CHANNELS; ++i)
+ {
+ if (channels_playing[i] && !I_SoundIsPlaying(i))
+ {
+ // Sound has finished playing on this channel,
+ // but sound data has not been released to cache
+
+ ReleaseSoundOnChannel(i);
+ }
+ }
}
@@ -360,6 +430,20 @@
void
I_InitSound()
{
+ int i;
+
+ // No sounds yet
+
+ for (i=0; i<NUMSFX; ++i)
+ {
+ sound_chunks[i].abuf = NULL;
+ }
+
+ for (i=0; i<NUM_CHANNELS; ++i)
+ {
+ channels_playing[i] = sfx_None;
+ }
+
// If music or sound is going to play, we need to at least
// initialise SDL
@@ -386,8 +470,6 @@
return;
sound_initialised = true;
-
-
}
@@ -395,8 +477,6 @@
//
// MUSIC API.
-// Still no music done.
-// Remains. Dummies.
//
static int music_initialised;