static AudioDeviceID outputDeviceID;
static AudioStreamBasicDescription outputStreamBasicDescription;
-extern mempool_t *snd_mempool;
-
/*
===============
sfx = Mem_Alloc (snd_mempool, sizeof (*sfx));
memset (sfx, 0, sizeof(*sfx));
strlcpy (sfx->name, name, sizeof (sfx->name));
+ sfx->memsize = sizeof(*sfx);
sfx->next = known_sfx;
known_sfx = sfx;
*/
void S_FreeSfx (sfx_t *sfx, qboolean force)
{
+ unsigned int i;
+
// Never free a locked sfx unless forced
if (!force && (sfx->locks > 0 || (sfx->flags & SFXFLAG_PERMANENTLOCK)))
return;
}
}
+ // Stop all channels using this sfx
+ for (i = 0; i < total_channels; i++)
+ if (channels[i].sfx == sfx)
+ S_StopChannel (i);
+
// Free it
- Mem_FreePool (&sfx->mempool);
+ if (sfx->fetcher != NULL && sfx->fetcher->free != NULL)
+ sfx->fetcher->free (sfx);
Mem_Free (sfx);
}
if (sfx->fetcher != NULL)
{
- snd_fetcher_end_t fetcher_end = sfx->fetcher->end;
- if (fetcher_end != NULL)
- fetcher_end (ch);
+ snd_fetcher_endsb_t fetcher_endsb = sfx->fetcher->endsb;
+ if (fetcher_endsb != NULL)
+ fetcher_endsb (ch);
}
// Remove the lock it holds
{
if (sfx->fetcher != NULL)
{
- size = (int)sfx->mempool->totalsize;
+ size = (int)sfx->memsize;
total += size;
Con_Printf ("%c%c%c%c(%2db, %6s) %8i : %s\n",
(sfx->loopstart >= 0) ? 'L' : ' ',
{
char name[MAX_QPATH];
sfx_t *next;
- mempool_t *mempool;
+ size_t memsize; // total memory used (including sfx_t and fetcher data)
int locks; // One lock is automatically granted while the sfx is
// playing (and removed when stopped). Locks can also be
// added by S_PrecacheSound and S_ServerSounds.
} channel_t;
typedef const sfxbuffer_t* (*snd_fetcher_getsb_t) (channel_t* ch, unsigned int start, unsigned int nbsamples);
-typedef void (*snd_fetcher_end_t) (channel_t* ch);
+typedef void (*snd_fetcher_endsb_t) (channel_t* ch);
+typedef void (*snd_fetcher_free_t) (sfx_t* sfx);
struct snd_fetcher_s
{
snd_fetcher_getsb_t getsb;
- snd_fetcher_end_t end;
+ snd_fetcher_endsb_t endsb;
+ snd_fetcher_free_t free;
};
void S_PaintChannels(int endtime);
void SNDDMA_Shutdown(void);
qboolean S_LoadSound (sfx_t *s, qboolean complain);
-void S_UnloadSound(sfx_t *s);
void S_LockSfx (sfx_t *sfx);
void S_UnlockSfx (sfx_t *sfx);
extern size_t ResampleSfx (const qbyte *in_data, size_t in_length, const snd_format_t* in_format, qbyte *out_data, const char* sfxname);
-// ====================================================================
-// User-setable variables
// ====================================================================
// 0 to NUM_AMBIENTS - 1 = water, etc
extern int snd_blocked;
+extern mempool_t *snd_mempool;
+
#endif
Con_Printf("S_LoadSound: Couldn't load \"%s\"\n", s->name);
return false;
}
-
-void S_UnloadSound (sfx_t *s)
-{
- if (s->fetcher != NULL)
- {
- unsigned int i;
-
- // Stop all channels that use this sound
- for (i = 0; i < total_channels ; i++)
- if (channels[i].sfx == s)
- S_StopChannel (i);
-
- s->fetcher = NULL;
- s->fetcher_data = NULL;
- Mem_FreePool(&s->mempool);
- }
-}
/*
- Copyright (C) 2003-2004 Mathieu Olivier
+ Copyright (C) 2003-2005 Mathieu Olivier
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
*/
#define STREAM_BUFFER_DURATION 1.5f // 1.5 sec
+#define STREAM_BUFFER_SIZE(format_ptr) (ceil (STREAM_BUFFER_DURATION * ((format_ptr)->speed * (format_ptr)->width * (format_ptr)->channels)))
// We work with 1 sec sequences, so this buffer must be able to contain
// 1 sec of sound of the highest quality (48 KHz, 16 bit samples, stereo)
ogg_stream_perchannel_t* per_ch;
sfxbuffer_t* sb;
sfx_t* sfx;
+ snd_format_t* format;
ogg_stream_persfx_t* per_sfx;
int newlength, done, ret, bigendian;
unsigned int factor;
per_ch = ch->fetcher_data;
sfx = ch->sfx;
per_sfx = sfx->fetcher_data;
- buff_len = ceil (STREAM_BUFFER_DURATION * (sfx->format.speed * sfx->format.width * sfx->format.channels));
+ format = &sfx->format;
+ buff_len = STREAM_BUFFER_SIZE(format);
// If there's no fetcher structure attached to the channel yet
if (per_ch == NULL)
{
+ size_t memsize;
ogg_stream_persfx_t* per_sfx;
- per_ch = Mem_Alloc (sfx->mempool, sizeof (*per_ch) - sizeof (per_ch->sb.data) + buff_len);
+ memsize = sizeof (*per_ch) - sizeof (per_ch->sb.data) + buff_len;
+ per_ch = Mem_Alloc (snd_mempool, memsize);
+ sfx->memsize += memsize;
per_sfx = sfx->fetcher_data;
// Open it with the VorbisFile API
newlength = per_sfx->format.speed * factor; // -> 1 sec of sound before resampling
// Decompress in the resampling_buffer
-#if BYTE_ORDER == LITTLE_ENDIAN
- bigendian = 0;
-#else
+#if BYTE_ORDER == BIG_ENDIAN
bigendian = 1;
+#else
+ bigendian = 0;
#endif
done = 0;
while ((ret = qov_read (&per_ch->vf, &resampling_buffer[done], (int)(newlength - done), bigendian, 2, 1, &per_ch->bs)) > 0)
per_ch = ch->fetcher_data;
if (per_ch != NULL)
{
+ size_t buff_len;
+ snd_format_t* format;
+
// Free the ogg vorbis decoder
qov_clear (&per_ch->vf);
Mem_Free (per_ch);
ch->fetcher_data = NULL;
+
+ format = &ch->sfx->format;
+ buff_len = STREAM_BUFFER_SIZE(format);
+ ch->sfx->memsize -= sizeof (*per_ch) - sizeof (per_ch->sb.data) + buff_len;
}
}
-static const snd_fetcher_t ogg_fetcher = { OGG_FetchSound, OGG_FetchEnd };
+
+/*
+====================
+OGG_FreeSfx
+====================
+*/
+static void OGG_FreeSfx (sfx_t* sfx)
+{
+ ogg_stream_persfx_t* per_sfx = sfx->fetcher_data;
+
+ // Free the Ogg Vorbis file
+ Mem_Free(per_sfx->file);
+ sfx->memsize -= per_sfx->filesize;
+
+ // Free the stream structure
+ Mem_Free(per_sfx);
+ sfx->memsize -= sizeof (*per_sfx);
+
+ sfx->fetcher_data = NULL;
+ sfx->fetcher = NULL;
+}
+
+static const snd_fetcher_t ogg_fetcher = { OGG_FetchSound, OGG_FetchEnd, OGG_FreeSfx };
/*
if (!vf_dll)
return false;
- Mem_FreePool (&s->mempool);
- s->mempool = Mem_AllocPool (s->name, 0, NULL);
+ // Already loaded?
+ if (s->fetcher != NULL)
+ return true;
// Load the file
- data = FS_LoadFile (filename, s->mempool, false);
+ data = FS_LoadFile (filename, snd_mempool, false);
if (data == NULL)
- {
- Mem_FreePool (&s->mempool);
return false;
- }
Con_DPrintf ("Loading Ogg Vorbis file \"%s\"\n", filename);
if (qov_open_callbacks (&ov_decode, &vf, NULL, 0, callbacks) < 0)
{
Con_Printf ("error while opening Ogg Vorbis file \"%s\"\n", filename);
- Mem_FreePool (&s->mempool);
+ Mem_Free(data);
return false;
}
Con_Printf("%s has an unsupported number of channels (%i)\n",
s->name, vi->channels);
qov_clear (&vf);
- Mem_FreePool (&s->mempool);
+ Mem_Free(data);
return false;
}
ogg_stream_persfx_t* per_sfx;
Con_DPrintf ("\"%s\" will be streamed\n", filename);
- per_sfx = Mem_Alloc (s->mempool, sizeof (*per_sfx));
+ per_sfx = Mem_Alloc (snd_mempool, sizeof (*per_sfx));
+ s->memsize += sizeof (*per_sfx);
per_sfx->file = data;
per_sfx->filesize = fs_filesize;
+ s->memsize += fs_filesize;
per_sfx->format.speed = vi->rate;
per_sfx->format.width = 2; // We always work with 16 bits samples
int bs, bigendian;
long ret;
sfxbuffer_t *sb;
+ size_t memsize;
Con_DPrintf ("\"%s\" will be cached\n", filename);
// Decode it
- buff = Mem_Alloc (s->mempool, (int)len);
+ buff = Mem_Alloc (snd_mempool, (int)len);
done = 0;
bs = 0;
#if BYTE_ORDER == LITTLE_ENDIAN
len = (double)done * (double)shm->format.speed / (double)vi->rate;
// Resample it
- sb = Mem_Alloc (s->mempool, (size_t)len + sizeof (*sb) - sizeof (sb->data));
+ memsize = (size_t)len + sizeof (*sb) - sizeof (sb->data);
+ sb = Mem_Alloc (snd_mempool, memsize);
+ s->memsize += memsize;
s->fetcher_data = sb;
s->fetcher = &wav_fetcher;
s->format.speed = vi->rate;
} AudioState;
-extern mempool_t *snd_mempool;
static AudioState as;
static void Buffer_Callback(void *userdata, Uint8 *stream, int len);
return ch->sfx->fetcher_data;
}
+/*
+====================
+WAV_FreeSfx
+====================
+*/
+static void WAV_FreeSfx (sfx_t* sfx)
+{
+ sfxbuffer_t* sb = sfx->fetcher_data;
-snd_fetcher_t wav_fetcher = { WAV_FetchSound, NULL };
+ // Free the sound buffer
+ sfx->memsize -= (sb->length * sfx->format.channels * sfx->format.width) + sizeof (*sb) - sizeof (sb->data);
+ Mem_Free(sb);
+
+ sfx->fetcher_data = NULL;
+ sfx->fetcher = NULL;
+}
+
+const snd_fetcher_t wav_fetcher = { WAV_FetchSound, NULL, WAV_FreeSfx };
/*
qbyte *data;
wavinfo_t info;
int len;
+ size_t memsize;
sfxbuffer_t* sb;
- Mem_FreePool (&s->mempool);
- s->mempool = Mem_AllocPool(s->name, 0, NULL);
+ // Already loaded?
+ if (s->fetcher != NULL)
+ return true;
// Load the file
- data = FS_LoadFile(filename, s->mempool, false);
+ data = FS_LoadFile(filename, snd_mempool, false);
if (!data)
- {
- Mem_FreePool (&s->mempool);
return false;
- }
// Don't try to load it if it's not a WAV file
if (memcmp (data, "RIFF", 4) || memcmp (data + 8, "WAVE", 4))
{
- Mem_FreePool (&s->mempool);
+ Mem_Free(data);
return false;
}
if (info.channels < 1 || info.channels > 2)
{
Con_Printf("%s has an unsupported number of channels (%i)\n",s->name, info.channels);
- Mem_FreePool (&s->mempool);
+ Mem_Free(data);
return false;
}
//if (info.channels == 2)
len = (int) ((double) info.samples * (double) shm->format.speed / (double) info.rate);
len = len * info.width * info.channels;
- sb = Mem_Alloc (s->mempool, len + sizeof (*sb) - sizeof (sb->data));
+ memsize = len + sizeof (*sb) - sizeof (sb->data);
+ sb = Mem_Alloc (snd_mempool, memsize);
if (sb == NULL)
{
Con_Printf("failed to allocate memory for sound \"%s\"\n", s->name);
- Mem_FreePool(&s->mempool);
+ Mem_Free(data);
return false;
}
+ s->memsize += memsize;
s->fetcher = &wav_fetcher;
s->fetcher_data = sb;
#define SND_WAV_H
-extern snd_fetcher_t wav_fetcher;
+extern const snd_fetcher_t wav_fetcher;
qboolean S_LoadWavFile (const char *filename, sfx_t *s);