2001-04-10 09:40:09 +00:00
|
|
|
/*
|
|
|
|
snd_mem.c
|
|
|
|
|
|
|
|
sound caching
|
|
|
|
|
|
|
|
Copyright (C) 1996-1997 Id Software, Inc.
|
|
|
|
|
|
|
|
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:
|
|
|
|
|
|
|
|
Free Software Foundation, Inc.
|
|
|
|
59 Temple Place - Suite 330
|
|
|
|
Boston, MA 02111-1307, USA
|
|
|
|
|
|
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
# include "config.h"
|
|
|
|
#endif
|
2003-01-15 15:31:36 +00:00
|
|
|
|
2001-04-10 09:40:09 +00:00
|
|
|
#ifdef HAVE_STRING_H
|
|
|
|
# include <string.h>
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE_STRINGS_H
|
|
|
|
# include <strings.h>
|
|
|
|
#endif
|
|
|
|
|
2011-08-25 13:35:20 +00:00
|
|
|
#if defined(_WIN32) && defined(HAVE_MALLOC_H)
|
2007-03-22 23:20:57 +00:00
|
|
|
#include <malloc.h>
|
|
|
|
#endif
|
|
|
|
|
2001-05-31 03:41:35 +00:00
|
|
|
#include "QF/cvar.h"
|
2003-04-09 05:55:41 +00:00
|
|
|
#include "QF/dstring.h"
|
2001-04-10 21:45:42 +00:00
|
|
|
#include "QF/sound.h"
|
2001-04-10 09:40:09 +00:00
|
|
|
#include "QF/sys.h"
|
2002-08-27 07:16:28 +00:00
|
|
|
#include "QF/qendian.h"
|
|
|
|
#include "QF/quakefs.h"
|
2001-04-10 09:40:09 +00:00
|
|
|
|
2003-04-11 01:17:48 +00:00
|
|
|
#include "compat.h"
|
2011-07-23 06:56:22 +00:00
|
|
|
#include "snd_internal.h"
|
2003-01-31 20:51:04 +00:00
|
|
|
|
2003-04-17 17:43:21 +00:00
|
|
|
#define SAMPLE_GAP 4
|
|
|
|
|
2007-03-17 06:20:52 +00:00
|
|
|
volatile dma_t *snd_shm;
|
|
|
|
snd_render_data_t snd_render_data = {
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
&snd_paintedtime,
|
|
|
|
0,
|
|
|
|
};
|
|
|
|
|
2003-04-11 01:17:48 +00:00
|
|
|
static sfxbuffer_t *
|
|
|
|
snd_fail (sfx_t *sfx)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
snd_noop (sfx_t *sfx)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2003-04-20 07:19:51 +00:00
|
|
|
static sfx_t *
|
|
|
|
snd_open (sfx_t *sfx)
|
|
|
|
{
|
|
|
|
return sfx;
|
|
|
|
}
|
|
|
|
|
2007-05-21 21:40:59 +00:00
|
|
|
static sfx_t *
|
|
|
|
snd_open_fail (sfx_t *sfx)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2003-04-11 18:59:14 +00:00
|
|
|
sfxbuffer_t *
|
|
|
|
SND_CacheTouch (sfx_t *sfx)
|
|
|
|
{
|
2007-05-07 05:20:24 +00:00
|
|
|
return Cache_Check (&sfx->data.block->cache);
|
2003-04-11 18:59:14 +00:00
|
|
|
}
|
|
|
|
|
2007-03-18 10:32:01 +00:00
|
|
|
sfxbuffer_t *
|
|
|
|
SND_CacheGetBuffer (sfx_t *sfx)
|
|
|
|
{
|
2007-05-07 05:20:24 +00:00
|
|
|
return sfx->data.block->buffer;
|
2007-03-18 10:32:01 +00:00
|
|
|
}
|
|
|
|
|
2003-04-11 01:17:48 +00:00
|
|
|
sfxbuffer_t *
|
|
|
|
SND_CacheRetain (sfx_t *sfx)
|
|
|
|
{
|
2007-05-07 05:20:24 +00:00
|
|
|
sfxblock_t *block = sfx->data.block;
|
2007-03-18 10:32:01 +00:00
|
|
|
block->buffer = Cache_TryGet (&block->cache);
|
2007-05-06 08:35:28 +00:00
|
|
|
if (!block->buffer)
|
|
|
|
Sys_Printf ("failed to cache sound!\n");
|
2007-03-18 10:32:01 +00:00
|
|
|
return block->buffer;
|
2003-04-11 01:17:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
SND_CacheRelease (sfx_t *sfx)
|
|
|
|
{
|
2007-05-07 05:20:24 +00:00
|
|
|
sfxblock_t *block = sfx->data.block;
|
2007-03-24 08:37:04 +00:00
|
|
|
// due to the possibly asynchronous nature of the mixer, the cache
|
|
|
|
// may have been flushed behind our backs
|
2007-03-27 03:42:11 +00:00
|
|
|
if (block->cache.data) {
|
2007-03-27 03:43:52 +00:00
|
|
|
if (!Cache_ReadLock (&block->cache)) {
|
2007-03-27 03:42:11 +00:00
|
|
|
Sys_Printf ("WARNING: taniwha screwed up in the sound engine: %s\n",
|
|
|
|
sfx->name);
|
|
|
|
return;
|
|
|
|
}
|
2007-03-24 08:37:04 +00:00
|
|
|
Cache_Release (&block->cache);
|
2007-05-06 08:35:28 +00:00
|
|
|
if (!Cache_ReadLock (&block->cache))
|
|
|
|
block->buffer = 0;
|
2007-03-27 03:42:11 +00:00
|
|
|
}
|
2007-03-18 10:32:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
sfxbuffer_t *
|
|
|
|
SND_StreamGetBuffer (sfx_t *sfx)
|
|
|
|
{
|
2007-05-07 05:20:24 +00:00
|
|
|
return &sfx->data.stream->buffer;
|
2003-04-11 01:17:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
sfxbuffer_t *
|
|
|
|
SND_StreamRetain (sfx_t *sfx)
|
|
|
|
{
|
2007-05-07 05:20:24 +00:00
|
|
|
return &sfx->data.stream->buffer;
|
2003-04-11 01:17:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
SND_StreamRelease (sfx_t *sfx)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2003-04-11 21:14:38 +00:00
|
|
|
wavinfo_t *
|
|
|
|
SND_CacheWavinfo (sfx_t *sfx)
|
|
|
|
{
|
2007-05-07 05:20:24 +00:00
|
|
|
return &sfx->data.stream->wavinfo;
|
2003-04-11 21:14:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
wavinfo_t *
|
|
|
|
SND_StreamWavinfo (sfx_t *sfx)
|
|
|
|
{
|
2007-05-07 05:20:24 +00:00
|
|
|
return &sfx->data.stream->wavinfo;
|
2003-04-11 21:14:38 +00:00
|
|
|
}
|
|
|
|
|
2003-04-14 06:11:53 +00:00
|
|
|
static void
|
2009-01-08 07:48:08 +00:00
|
|
|
read_samples (sfxbuffer_t *buffer, int count)
|
2003-04-14 06:11:53 +00:00
|
|
|
{
|
2003-04-17 17:43:21 +00:00
|
|
|
|
2003-04-14 06:11:53 +00:00
|
|
|
if (buffer->head + count > buffer->length) {
|
|
|
|
count -= buffer->length - buffer->head;
|
2009-01-08 07:48:08 +00:00
|
|
|
read_samples (buffer, buffer->length - buffer->head);
|
|
|
|
read_samples (buffer, count);
|
2003-04-14 06:11:53 +00:00
|
|
|
} else {
|
|
|
|
sfx_t *sfx = buffer->sfx;
|
2007-05-07 05:20:24 +00:00
|
|
|
sfxstream_t *stream = sfx->data.stream;
|
2003-04-14 06:11:53 +00:00
|
|
|
wavinfo_t *info = &stream->wavinfo;
|
2010-08-11 23:47:03 +00:00
|
|
|
float *data = buffer->data + buffer->head * info->channels;
|
|
|
|
int c;
|
2003-04-14 06:11:53 +00:00
|
|
|
|
2010-08-11 23:47:03 +00:00
|
|
|
if ((c = stream->read (stream, data, count)) != count)
|
|
|
|
Sys_Printf ("%s nr %d %d\n", sfx->name, count, c);
|
2003-04-14 06:11:53 +00:00
|
|
|
|
|
|
|
buffer->head += count;
|
|
|
|
if (buffer->head >= buffer->length)
|
|
|
|
buffer->head -= buffer->length;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-04-26 04:30:07 +00:00
|
|
|
static void
|
|
|
|
fill_buffer (sfx_t *sfx, sfxstream_t *stream, sfxbuffer_t *buffer,
|
|
|
|
wavinfo_t *info, unsigned int headpos)
|
|
|
|
{
|
|
|
|
unsigned int samples;
|
|
|
|
unsigned int loop_samples = 0;
|
|
|
|
|
|
|
|
// find out how many samples can be read into the buffer
|
|
|
|
samples = buffer->tail - buffer->head - SAMPLE_GAP;
|
|
|
|
if (buffer->tail <= buffer->head)
|
|
|
|
samples += buffer->length;
|
|
|
|
|
|
|
|
if (headpos + samples > sfx->length) {
|
|
|
|
if (sfx->loopstart == (unsigned int)-1) {
|
|
|
|
samples = sfx->length - headpos;
|
|
|
|
} else {
|
|
|
|
loop_samples = headpos + samples - sfx->length;
|
|
|
|
samples -= loop_samples;
|
|
|
|
}
|
|
|
|
}
|
2010-08-11 23:44:34 +00:00
|
|
|
if (samples)
|
2009-01-08 07:48:08 +00:00
|
|
|
read_samples (buffer, samples);
|
2003-04-26 04:30:07 +00:00
|
|
|
if (loop_samples) {
|
2010-08-11 23:47:03 +00:00
|
|
|
stream->seek (stream, info->loopstart);
|
2009-01-08 07:48:08 +00:00
|
|
|
read_samples (buffer, loop_samples);
|
2003-04-26 04:30:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
SND_StreamSetPos (sfxbuffer_t *buffer, unsigned int pos)
|
|
|
|
{
|
|
|
|
float stepscale;
|
|
|
|
sfx_t *sfx = buffer->sfx;
|
2007-05-07 05:20:24 +00:00
|
|
|
sfxstream_t *stream = sfx->data.stream;
|
2003-04-26 04:30:07 +00:00
|
|
|
wavinfo_t *info = &stream->wavinfo;
|
|
|
|
|
2007-03-10 04:21:32 +00:00
|
|
|
stepscale = (float) info->rate / snd_shm->speed;
|
2003-04-26 04:30:07 +00:00
|
|
|
|
|
|
|
buffer->head = buffer->tail = 0;
|
|
|
|
buffer->pos = pos;
|
|
|
|
stream->pos = pos;
|
2010-08-11 23:47:03 +00:00
|
|
|
stream->seek (stream, buffer->pos * stepscale);
|
2003-04-26 04:30:07 +00:00
|
|
|
fill_buffer (sfx, stream, buffer, info, pos);
|
|
|
|
}
|
|
|
|
|
2010-08-13 01:48:20 +00:00
|
|
|
int
|
2003-04-17 00:01:48 +00:00
|
|
|
SND_StreamAdvance (sfxbuffer_t *buffer, unsigned int count)
|
2003-04-14 06:11:53 +00:00
|
|
|
{
|
|
|
|
float stepscale;
|
2003-04-17 00:01:48 +00:00
|
|
|
unsigned int headpos, samples;
|
2003-04-14 06:11:53 +00:00
|
|
|
sfx_t *sfx = buffer->sfx;
|
2007-05-07 05:20:24 +00:00
|
|
|
sfxstream_t *stream = sfx->data.stream;
|
2003-04-14 06:11:53 +00:00
|
|
|
wavinfo_t *info = &stream->wavinfo;
|
|
|
|
|
2003-04-20 03:42:19 +00:00
|
|
|
stream->pos += count;
|
|
|
|
count = (stream->pos - buffer->pos) & ~255;
|
|
|
|
if (!count)
|
2010-08-13 01:48:20 +00:00
|
|
|
return 1;
|
2003-04-20 03:42:19 +00:00
|
|
|
|
2007-03-10 04:21:32 +00:00
|
|
|
stepscale = (float) info->rate / snd_shm->speed;
|
2003-04-14 06:11:53 +00:00
|
|
|
|
|
|
|
// find out how many samples the buffer currently holds
|
2003-04-17 02:40:17 +00:00
|
|
|
samples = buffer->head - buffer->tail;
|
|
|
|
if (buffer->head < buffer->tail)
|
|
|
|
samples += buffer->length;
|
2003-04-14 06:11:53 +00:00
|
|
|
|
|
|
|
// find out where head points to in the stream
|
|
|
|
headpos = buffer->pos + samples;
|
|
|
|
if (headpos >= sfx->length) {
|
2003-04-17 00:01:48 +00:00
|
|
|
if (sfx->loopstart == (unsigned int)-1)
|
2003-04-14 06:11:53 +00:00
|
|
|
headpos = sfx->length;
|
|
|
|
else
|
|
|
|
headpos -= sfx->length - sfx->loopstart;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (samples < count) {
|
|
|
|
buffer->head = buffer->tail = 0;
|
|
|
|
buffer->pos += count;
|
|
|
|
if (buffer->pos > sfx->length) {
|
2003-04-17 00:01:48 +00:00
|
|
|
if (sfx->loopstart == (unsigned int)-1) {
|
2003-04-14 06:11:53 +00:00
|
|
|
// reset the buffer and fill it incase it's needed again
|
2003-04-17 03:58:16 +00:00
|
|
|
buffer->pos = 0;
|
2003-04-14 06:11:53 +00:00
|
|
|
} else {
|
|
|
|
buffer->pos -= sfx->loopstart;
|
|
|
|
buffer->pos %= sfx->length - sfx->loopstart;
|
|
|
|
buffer->pos += sfx->loopstart;
|
|
|
|
}
|
2003-04-20 03:42:19 +00:00
|
|
|
stream->pos = buffer->pos;
|
2003-04-14 06:11:53 +00:00
|
|
|
}
|
2003-04-17 03:58:16 +00:00
|
|
|
headpos = buffer->pos;
|
2010-08-11 23:47:03 +00:00
|
|
|
stream->seek (stream, buffer->pos * stepscale);
|
2003-04-14 06:11:53 +00:00
|
|
|
} else {
|
|
|
|
buffer->pos += count;
|
|
|
|
if (buffer->pos >= sfx->length) {
|
2003-04-17 00:01:48 +00:00
|
|
|
if (sfx->loopstart == (unsigned int)-1) {
|
2004-03-01 11:51:01 +00:00
|
|
|
// reset the buffer and fill it in case it's needed again
|
2003-04-17 03:53:54 +00:00
|
|
|
headpos = buffer->pos = 0;
|
2003-04-14 06:11:53 +00:00
|
|
|
buffer->head = buffer->tail = 0;
|
|
|
|
count = 0;
|
2010-08-11 23:47:03 +00:00
|
|
|
stream->seek (stream, buffer->pos * stepscale);
|
2003-04-14 06:11:53 +00:00
|
|
|
} else {
|
|
|
|
buffer->pos -= sfx->length - sfx->loopstart;
|
|
|
|
}
|
2003-04-20 03:42:19 +00:00
|
|
|
stream->pos = buffer->pos;
|
2003-04-14 06:11:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
buffer->tail += count;
|
|
|
|
if (buffer->tail >= buffer->length)
|
|
|
|
buffer->tail -= buffer->length;
|
|
|
|
}
|
2003-04-26 04:30:07 +00:00
|
|
|
fill_buffer (sfx, stream, buffer, info, headpos);
|
2010-08-13 01:48:20 +00:00
|
|
|
return !stream->error;
|
2003-04-14 06:11:53 +00:00
|
|
|
}
|
|
|
|
|
2010-08-08 03:02:55 +00:00
|
|
|
int
|
2003-04-11 01:17:48 +00:00
|
|
|
SND_Load (sfx_t *sfx)
|
|
|
|
{
|
|
|
|
char *realname;
|
|
|
|
char buf[4];
|
|
|
|
QFile *file;
|
|
|
|
|
|
|
|
sfx->touch = sfx->retain = snd_fail;
|
|
|
|
sfx->release = snd_noop;
|
2003-04-20 07:19:51 +00:00
|
|
|
sfx->close = snd_noop;
|
2007-05-21 21:40:59 +00:00
|
|
|
sfx->open = snd_open_fail;
|
2003-04-11 01:17:48 +00:00
|
|
|
|
2014-01-23 02:57:57 +00:00
|
|
|
file = QFS_FOpenFile (sfx->name);
|
2003-04-11 01:17:48 +00:00
|
|
|
if (!file) {
|
2004-01-21 02:52:12 +00:00
|
|
|
Sys_Printf ("Couldn't load %s\n", sfx->name);
|
2010-08-08 03:02:55 +00:00
|
|
|
return -1;
|
2003-04-11 01:17:48 +00:00
|
|
|
}
|
2007-05-21 21:40:59 +00:00
|
|
|
sfx->open = snd_open;
|
2013-11-24 13:45:42 +00:00
|
|
|
if (!strequal (qfs_foundfile.realname, sfx->name)) {
|
|
|
|
realname = strdup (qfs_foundfile.realname);
|
2003-04-11 01:17:48 +00:00
|
|
|
} else {
|
2004-01-21 02:52:12 +00:00
|
|
|
realname = (char *) sfx->name; // won't free if realname == sfx->name
|
2003-04-11 01:17:48 +00:00
|
|
|
}
|
|
|
|
Qread (file, buf, 4);
|
|
|
|
Qseek (file, 0, SEEK_SET);
|
2003-04-11 14:38:31 +00:00
|
|
|
#ifdef HAVE_VORBIS
|
2003-04-11 01:17:48 +00:00
|
|
|
if (strnequal ("OggS", buf, 4)) {
|
2010-11-23 05:09:30 +00:00
|
|
|
Sys_MaskPrintf (SYS_DEV, "SND_Load: ogg file\n");
|
2010-08-08 03:02:55 +00:00
|
|
|
if (SND_LoadOgg (file, sfx, realname) == -1)
|
|
|
|
goto bail;
|
|
|
|
return 0;
|
2003-04-11 01:17:48 +00:00
|
|
|
}
|
2003-09-10 05:20:51 +00:00
|
|
|
#endif
|
2005-06-19 05:24:19 +00:00
|
|
|
#ifdef HAVE_FLAC
|
2005-06-15 10:02:50 +00:00
|
|
|
if (strnequal ("fLaC", buf, 4)) {
|
2010-11-23 05:09:30 +00:00
|
|
|
Sys_MaskPrintf (SYS_DEV, "SND_Load: flac file\n");
|
2010-08-08 03:02:55 +00:00
|
|
|
if (SND_LoadFLAC (file, sfx, realname) == -1)
|
|
|
|
goto bail;
|
|
|
|
return 0;
|
2005-06-15 10:02:50 +00:00
|
|
|
}
|
|
|
|
#endif
|
2003-09-10 05:20:51 +00:00
|
|
|
#ifdef HAVE_WILDMIDI
|
|
|
|
if (strnequal ("MThd", buf, 4)) {
|
2010-11-23 05:09:30 +00:00
|
|
|
Sys_MaskPrintf (SYS_DEV, "SND_Load: midi file\n");
|
2010-08-08 03:02:55 +00:00
|
|
|
if (SND_LoadMidi (file, sfx, realname) == -1)
|
|
|
|
goto bail;
|
|
|
|
return 0;
|
2003-09-10 05:20:51 +00:00
|
|
|
}
|
2003-04-11 14:38:31 +00:00
|
|
|
#endif
|
2003-04-11 01:17:48 +00:00
|
|
|
if (strnequal ("RIFF", buf, 4)) {
|
2010-11-23 05:09:30 +00:00
|
|
|
Sys_MaskPrintf (SYS_DEV, "SND_Load: wav file\n");
|
2010-08-08 03:02:55 +00:00
|
|
|
if (SND_LoadWav (file, sfx, realname) == -1)
|
|
|
|
goto bail;
|
|
|
|
return 0;
|
2003-04-11 01:17:48 +00:00
|
|
|
}
|
2010-08-08 03:02:55 +00:00
|
|
|
bail:
|
2003-04-15 02:34:17 +00:00
|
|
|
Qclose (file);
|
2004-01-21 02:52:12 +00:00
|
|
|
if (realname != sfx->name)
|
|
|
|
free (realname);
|
2010-08-08 03:02:55 +00:00
|
|
|
return -1;
|
2003-04-11 01:17:48 +00:00
|
|
|
}
|
2001-04-10 09:40:09 +00:00
|
|
|
|
2003-04-11 01:17:48 +00:00
|
|
|
sfxbuffer_t *
|
2010-08-11 23:44:34 +00:00
|
|
|
SND_GetCache (long frames, int rate, int channels,
|
2003-04-11 01:17:48 +00:00
|
|
|
sfxblock_t *block, cache_allocator_t allocator)
|
2002-06-15 05:43:56 +00:00
|
|
|
{
|
2010-08-11 23:44:34 +00:00
|
|
|
int len, size;
|
2002-06-17 00:26:13 +00:00
|
|
|
float stepscale;
|
2003-04-11 01:17:48 +00:00
|
|
|
sfxbuffer_t *sc;
|
|
|
|
sfx_t *sfx = block->sfx;
|
2002-06-15 05:43:56 +00:00
|
|
|
|
2007-03-10 04:21:32 +00:00
|
|
|
stepscale = (float) rate / snd_shm->speed;
|
2010-08-11 23:44:34 +00:00
|
|
|
len = size = frames / stepscale;
|
|
|
|
size *= sizeof (float) * channels;
|
2003-04-11 01:17:48 +00:00
|
|
|
sc = allocator (&block->cache, sizeof (sfxbuffer_t) + size, sfx->name);
|
2002-06-15 05:43:56 +00:00
|
|
|
if (!sc)
|
|
|
|
return 0;
|
2003-04-14 06:11:53 +00:00
|
|
|
memset (sc, 0, sizeof (sfxbuffer_t) + size);
|
2003-04-14 01:40:40 +00:00
|
|
|
sc->length = len;
|
2010-08-11 23:44:34 +00:00
|
|
|
memcpy (sc->data + len * channels, "\xde\xad\xbe\xef", 4);
|
2002-06-15 05:43:56 +00:00
|
|
|
return sc;
|
|
|
|
}
|