mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-01-18 06:51:47 +00:00
half way though the sfx loader re-write. nothing works :)
This commit is contained in:
parent
e5a23c95dc
commit
ccb56eea39
8 changed files with 440 additions and 578 deletions
|
@ -31,11 +31,9 @@
|
||||||
#define _SOUND_H
|
#define _SOUND_H
|
||||||
|
|
||||||
#include "QF/mathlib.h"
|
#include "QF/mathlib.h"
|
||||||
#include "QF/quakeio.h"
|
|
||||||
#include "QF/zone.h"
|
|
||||||
|
|
||||||
#define AMBIENT_WATER 0
|
#define AMBIENT_WATER 0
|
||||||
#define AMBIENT_SKY 1
|
#define AMBIENT_SKY 1
|
||||||
#define AMBIENT_SLIME 2
|
#define AMBIENT_SLIME 2
|
||||||
#define AMBIENT_LAVA 3
|
#define AMBIENT_LAVA 3
|
||||||
#define NUM_AMBIENTS 4 // automatic ambient sounds
|
#define NUM_AMBIENTS 4 // automatic ambient sounds
|
||||||
|
@ -43,11 +41,23 @@
|
||||||
#define DEFAULT_SOUND_PACKET_VOLUME 255
|
#define DEFAULT_SOUND_PACKET_VOLUME 255
|
||||||
#define DEFAULT_SOUND_PACKET_ATTENUATION 1.0
|
#define DEFAULT_SOUND_PACKET_ATTENUATION 1.0
|
||||||
|
|
||||||
typedef struct sfx_s
|
typedef struct sfx_s sfx_t;
|
||||||
|
struct sfx_s
|
||||||
{
|
{
|
||||||
char name[MAX_QPATH];
|
const char *name;
|
||||||
cache_user_t cache;
|
|
||||||
} sfx_t;
|
int length;
|
||||||
|
int loopstart;
|
||||||
|
int speed;
|
||||||
|
int width;
|
||||||
|
int channels;
|
||||||
|
|
||||||
|
void *data;
|
||||||
|
|
||||||
|
struct sfxbuffer_s *(*touch) (sfx_t *sfx);
|
||||||
|
struct sfxbuffer_s *(*retain) (sfx_t *sfx);
|
||||||
|
void (*release) (sfx_t *sfx);
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
|
@ -117,6 +127,7 @@ extern struct cvar_s *snd_loadas8bit;
|
||||||
extern struct cvar_s *bgmvolume;
|
extern struct cvar_s *bgmvolume;
|
||||||
extern struct cvar_s *volume;
|
extern struct cvar_s *volume;
|
||||||
|
|
||||||
|
extern struct cvar_s *snd_mixahead;
|
||||||
extern struct cvar_s *snd_device;
|
extern struct cvar_s *snd_device;
|
||||||
extern struct cvar_s *snd_rate;
|
extern struct cvar_s *snd_rate;
|
||||||
extern struct cvar_s *snd_bits;
|
extern struct cvar_s *snd_bits;
|
||||||
|
|
|
@ -32,25 +32,41 @@
|
||||||
#ifndef __snd_render_h
|
#ifndef __snd_render_h
|
||||||
#define __snd_render_h
|
#define __snd_render_h
|
||||||
|
|
||||||
|
#include "QF/zone.h"
|
||||||
|
|
||||||
// !!! if this is changed, it must be changed in asm_i386.h too !!!
|
// !!! if this is changed, it must be changed in asm_i386.h too !!!
|
||||||
typedef struct portable_samplepair_s {
|
typedef struct portable_samplepair_s {
|
||||||
int left;
|
int left;
|
||||||
int right;
|
int right;
|
||||||
} portable_samplepair_t;
|
} portable_samplepair_t;
|
||||||
|
|
||||||
// !!! if this is changed, it much be changed in asm_i386.h too !!!
|
typedef struct channel_s channel_t;
|
||||||
typedef struct sfxcache_s {
|
typedef struct sfxbuffer_s sfxbuffer_t;
|
||||||
int length;
|
struct sfxbuffer_s {
|
||||||
int loopstart;
|
int head; // ring buffer head position in sampels
|
||||||
int speed;
|
int tail; // ring buffer tail position in sampels
|
||||||
int width;
|
int length; // length of buffer in samples
|
||||||
int stereo;
|
int pos; // position of tail within full stream
|
||||||
int bytes;
|
void (*paint) (channel_t *ch, sfxbuffer_t *buffer, int count);
|
||||||
byte data[4]; // variable sized
|
void (*advance) (sfxbuffer_t *buffer, int count);
|
||||||
} sfxcache_t;
|
byte data[4];
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct sfxstream_s {
|
||||||
|
sfx_t *sfx;
|
||||||
|
void *file;
|
||||||
|
sfxbuffer_t buffer;
|
||||||
|
} sfxstream_t;
|
||||||
|
|
||||||
|
typedef struct sfxblock_s {
|
||||||
|
sfx_t *sfx;
|
||||||
|
const char *file;
|
||||||
|
int bytes;
|
||||||
|
cache_user_t cache;
|
||||||
|
} sfxblock_t;
|
||||||
|
|
||||||
// !!! if this is changed, it much be changed in asm_i386.h too !!!
|
// !!! if this is changed, it much be changed in asm_i386.h too !!!
|
||||||
typedef struct channel_s {
|
struct channel_s {
|
||||||
sfx_t *sfx; // sfx number
|
sfx_t *sfx; // sfx number
|
||||||
int leftvol; // 0-255 volume
|
int leftvol; // 0-255 volume
|
||||||
int rightvol; // 0-255 volume
|
int rightvol; // 0-255 volume
|
||||||
|
@ -64,7 +80,7 @@ typedef struct channel_s {
|
||||||
int master_vol; // 0-255 master volume
|
int master_vol; // 0-255 master volume
|
||||||
int phase; // phase shift between l-r in samples
|
int phase; // phase shift between l-r in samples
|
||||||
int oldphase; // phase shift between l-r in samples
|
int oldphase; // phase shift between l-r in samples
|
||||||
} channel_t;
|
};
|
||||||
|
|
||||||
typedef struct wavinfo_s {
|
typedef struct wavinfo_s {
|
||||||
int rate;
|
int rate;
|
||||||
|
@ -99,9 +115,9 @@ void SND_LocalSound (const char *s);
|
||||||
void SND_BlockSound (void);
|
void SND_BlockSound (void);
|
||||||
void SND_UnblockSound (void);
|
void SND_UnblockSound (void);
|
||||||
|
|
||||||
void SND_ResampleSfx (sfxcache_t *sc, byte * data);
|
void SND_ResampleSfx (sfx_t *sfx, sfxbuffer_t *sc, byte *data);
|
||||||
sfxcache_t *SND_GetCache (long samples, int rate, int inwidth, int channels,
|
sfxbuffer_t *SND_GetCache (long samples, int rate, int inwidth, int channels,
|
||||||
sfx_t *sfx, cache_allocator_t allocator);
|
sfxblock_t *block, cache_allocator_t allocator);
|
||||||
|
|
||||||
void SND_InitScaletable (void);
|
void SND_InitScaletable (void);
|
||||||
// picks a channel based on priorities, empty slots, number of channels
|
// picks a channel based on priorities, empty slots, number of channels
|
||||||
|
@ -109,15 +125,21 @@ channel_t *SND_PickChannel(int entnum, int entchannel);
|
||||||
// spatializes a channel
|
// spatializes a channel
|
||||||
void SND_Spatialize(channel_t *ch);
|
void SND_Spatialize(channel_t *ch);
|
||||||
|
|
||||||
|
void SND_Load (sfx_t *sfx);
|
||||||
void SND_CallbackLoad (void *object, cache_allocator_t allocator);
|
void SND_CallbackLoad (void *object, cache_allocator_t allocator);
|
||||||
sfxcache_t *SND_LoadOgg (QFile *file, sfx_t *sfx, cache_allocator_t allocator);
|
void SND_LoadOgg (QFile *file, sfx_t *sfx, char *realname);
|
||||||
wavinfo_t SND_GetWavinfo (const char *name, byte * wav, int wavlength);
|
void SND_LoadWav (QFile *file, sfx_t *sfx, char *realname);
|
||||||
|
|
||||||
|
sfxbuffer_t *SND_CacheRetain (sfx_t *sfx);
|
||||||
|
void SND_CacheRelease (sfx_t *sfx);
|
||||||
|
sfxbuffer_t *SND_StreamRetain (sfx_t *sfx);
|
||||||
|
void SND_StreamRelease (sfx_t *sfx);
|
||||||
|
|
||||||
void SND_WriteLinearBlastStereo16 (void);
|
void SND_WriteLinearBlastStereo16 (void);
|
||||||
void SND_PaintChannelFrom8 (channel_t *ch, sfxcache_t *sc, int count);
|
void SND_PaintChannelFrom8 (channel_t *ch, sfxbuffer_t *sc, int count);
|
||||||
void SND_PaintChannelFrom16 (channel_t *ch, sfxcache_t *sc, int count);
|
void SND_PaintChannelFrom16 (channel_t *ch, sfxbuffer_t *sc, int count);
|
||||||
void SND_PaintChannelStereo8 (channel_t *ch, sfxcache_t *sc, int count);
|
void SND_PaintChannelStereo8 (channel_t *ch, sfxbuffer_t *sc, int count);
|
||||||
void SND_PaintChannelStereo16 (channel_t *ch, sfxcache_t *sc, int count);
|
void SND_PaintChannelStereo16 (channel_t *ch, sfxbuffer_t *sc, int count);
|
||||||
|
|
||||||
wavinfo_t GetWavinfo (const char *name, byte *wav, int wavlength);
|
wavinfo_t GetWavinfo (const char *name, byte *wav, int wavlength);
|
||||||
|
|
||||||
|
|
|
@ -10,25 +10,14 @@ EXEEXT=
|
||||||
plugin_PROGRAMS= @SND_REND_TARGETS@
|
plugin_PROGRAMS= @SND_REND_TARGETS@
|
||||||
EXTRA_PROGRAMS= snd_render_default.la
|
EXTRA_PROGRAMS= snd_render_default.la
|
||||||
|
|
||||||
if ASM_ARCH
|
|
||||||
asm= libasm.la
|
|
||||||
else
|
|
||||||
asm=
|
|
||||||
endif
|
|
||||||
|
|
||||||
noinst_LTLIBRARIES= $(asm)
|
|
||||||
noinst_PROGRAMS= @SND_REND_STATIC@
|
noinst_PROGRAMS= @SND_REND_STATIC@
|
||||||
|
|
||||||
libasm_la_SOURCES= snd_mixa.S
|
|
||||||
|
|
||||||
snd_render_default_la_LDFLAGS= $(plugin_ldflags)
|
snd_render_default_la_LDFLAGS= $(plugin_ldflags)
|
||||||
snd_render_default_la_SOURCES= snd_dma.c snd_mem.c snd_mix.c vorbis.c
|
snd_render_default_la_SOURCES= snd_dma.c snd_mem.c snd_mix.c vorbis.c wav.c
|
||||||
if ASM_ARCH
|
if ASM_ARCH
|
||||||
snd_render_default_la_LDADD= $(asm) $(VORBISFILE_LIBS) $(VORBIS_LIBS) $(OGG_LIBS)
|
snd_render_default_la_LDADD= $(VORBISFILE_LIBS) $(VORBIS_LIBS) $(OGG_LIBS)
|
||||||
snd_render_default_la_DEPENDENCIES= $(asm)
|
snd_render_default_la_DEPENDENCIES=
|
||||||
else
|
else
|
||||||
snd_render_default_la_LDADD= $(VORBISFILE_LIBS) $(VORBIS_LIBS) $(OGG_LIBS)
|
snd_render_default_la_LDADD= $(VORBISFILE_LIBS) $(VORBIS_LIBS) $(OGG_LIBS)
|
||||||
snd_render_default_la_DEPENDENCIES=
|
snd_render_default_la_DEPENDENCIES=
|
||||||
endif
|
endif
|
||||||
|
|
||||||
EXTRA_DIST= $(libasm_la_SOURCES)
|
|
||||||
|
|
|
@ -176,7 +176,7 @@ SND_FindName (const char *name)
|
||||||
|
|
||||||
// see if already loaded
|
// see if already loaded
|
||||||
for (i = 0; i < num_sfx; i++)
|
for (i = 0; i < num_sfx; i++)
|
||||||
if (!strcmp (known_sfx[i].name, name)) {
|
if (known_sfx[i].name && !strcmp (known_sfx[i].name, name)) {
|
||||||
return &known_sfx[i];
|
return &known_sfx[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,8 +184,10 @@ SND_FindName (const char *name)
|
||||||
Sys_Error ("S_FindName: out of sfx_t");
|
Sys_Error ("S_FindName: out of sfx_t");
|
||||||
|
|
||||||
sfx = &known_sfx[i];
|
sfx = &known_sfx[i];
|
||||||
strcpy (sfx->name, name);
|
if (sfx->name)
|
||||||
Cache_Add (&sfx->cache, sfx, SND_CallbackLoad);
|
free ((char *) sfx->name);
|
||||||
|
sfx->name = strdup (name);
|
||||||
|
SND_Load (sfx);
|
||||||
|
|
||||||
num_sfx++;
|
num_sfx++;
|
||||||
|
|
||||||
|
@ -201,7 +203,7 @@ SND_TouchSound (const char *name)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
sfx = SND_FindName (name);
|
sfx = SND_FindName (name);
|
||||||
Cache_Check (&sfx->cache);
|
sfx->touch (sfx);
|
||||||
}
|
}
|
||||||
|
|
||||||
sfx_t *
|
sfx_t *
|
||||||
|
@ -215,10 +217,10 @@ SND_PrecacheSound (const char *name)
|
||||||
sfx = SND_FindName (name);
|
sfx = SND_FindName (name);
|
||||||
|
|
||||||
// cache it in
|
// cache it in
|
||||||
if (precache->int_val)
|
if (precache->int_val) {
|
||||||
if (Cache_TryGet (&sfx->cache))
|
if (sfx->retain (sfx))
|
||||||
Cache_Release (&sfx->cache);
|
sfx->release (sfx);
|
||||||
|
}
|
||||||
return sfx;
|
return sfx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -316,7 +318,6 @@ SND_StartSound (int entnum, int entchannel, sfx_t *sfx, const vec3_t origin,
|
||||||
{
|
{
|
||||||
int ch_idx, skip, vol;
|
int ch_idx, skip, vol;
|
||||||
channel_t *target_chan, *check;
|
channel_t *target_chan, *check;
|
||||||
sfxcache_t *sc;
|
|
||||||
|
|
||||||
if (!sound_started)
|
if (!sound_started)
|
||||||
return;
|
return;
|
||||||
|
@ -347,16 +348,15 @@ SND_StartSound (int entnum, int entchannel, sfx_t *sfx, const vec3_t origin,
|
||||||
return; // not audible at all
|
return; // not audible at all
|
||||||
|
|
||||||
// new channel
|
// new channel
|
||||||
sc = Cache_TryGet (&sfx->cache);
|
if (!sfx->retain (sfx)) {
|
||||||
if (!sc) {
|
|
||||||
target_chan->sfx = NULL;
|
target_chan->sfx = NULL;
|
||||||
return; // couldn't load the sound's data
|
return; // couldn't load the sound's data
|
||||||
}
|
}
|
||||||
|
|
||||||
target_chan->sfx = sfx;
|
target_chan->sfx = sfx;
|
||||||
target_chan->pos = 0.0;
|
target_chan->pos = 0.0;
|
||||||
target_chan->end = paintedtime + sc->length;
|
target_chan->end = paintedtime + sfx->length;
|
||||||
Cache_Release (&sfx->cache);
|
sfx->release (sfx);
|
||||||
|
|
||||||
// if an identical sound has also been started this frame, offset the pos
|
// if an identical sound has also been started this frame, offset the pos
|
||||||
// a bit to keep it from just making the first one louder
|
// a bit to keep it from just making the first one louder
|
||||||
|
@ -444,7 +444,6 @@ SND_StaticSound (sfx_t *sfx, const vec3_t origin, float vol,
|
||||||
float attenuation)
|
float attenuation)
|
||||||
{
|
{
|
||||||
channel_t *ss;
|
channel_t *ss;
|
||||||
sfxcache_t *sc;
|
|
||||||
|
|
||||||
if (!sound_started || !sfx)
|
if (!sound_started || !sfx)
|
||||||
return;
|
return;
|
||||||
|
@ -457,13 +456,12 @@ SND_StaticSound (sfx_t *sfx, const vec3_t origin, float vol,
|
||||||
ss = &channels[total_channels];
|
ss = &channels[total_channels];
|
||||||
total_channels++;
|
total_channels++;
|
||||||
|
|
||||||
sc = Cache_TryGet (&sfx->cache);
|
if (!sfx->retain (sfx))
|
||||||
if (!sc)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (sc->loopstart == -1) {
|
if (sfx->loopstart == -1) {
|
||||||
Sys_Printf ("Sound %s not looped\n", sfx->name);
|
Sys_Printf ("Sound %s not looped\n", sfx->name);
|
||||||
Cache_Release (&sfx->cache);
|
sfx->release (sfx);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -471,8 +469,8 @@ SND_StaticSound (sfx_t *sfx, const vec3_t origin, float vol,
|
||||||
VectorCopy (origin, ss->origin);
|
VectorCopy (origin, ss->origin);
|
||||||
ss->master_vol = vol;
|
ss->master_vol = vol;
|
||||||
ss->dist_mult = (attenuation / 64) / sound_nominal_clip_dist;
|
ss->dist_mult = (attenuation / 64) / sound_nominal_clip_dist;
|
||||||
ss->end = paintedtime + sc->length;
|
ss->end = paintedtime + sfx->length;
|
||||||
Cache_Release (&sfx->cache);
|
sfx->release (sfx);
|
||||||
|
|
||||||
SND_Spatialize (ss);
|
SND_Spatialize (ss);
|
||||||
ss->oldphase = ss->phase;
|
ss->oldphase = ss->phase;
|
||||||
|
@ -736,9 +734,8 @@ SND_PlayVol (void)
|
||||||
static void
|
static void
|
||||||
SND_SoundList (void)
|
SND_SoundList (void)
|
||||||
{
|
{
|
||||||
int load, size, total, i;
|
int load, total, i;
|
||||||
sfx_t *sfx;
|
sfx_t *sfx;
|
||||||
sfxcache_t *sc;
|
|
||||||
|
|
||||||
if (Cmd_Argc() >= 2 && Cmd_Argv (1)[0])
|
if (Cmd_Argc() >= 2 && Cmd_Argv (1)[0])
|
||||||
load = 1;
|
load = 1;
|
||||||
|
@ -747,23 +744,17 @@ SND_SoundList (void)
|
||||||
|
|
||||||
total = 0;
|
total = 0;
|
||||||
for (sfx = known_sfx, i = 0; i < num_sfx; i++, sfx++) {
|
for (sfx = known_sfx, i = 0; i < num_sfx; i++, sfx++) {
|
||||||
if (load)
|
if (load) {
|
||||||
sc = Cache_TryGet (&sfx->cache);
|
if (!sfx->retain (sfx))
|
||||||
else
|
continue;
|
||||||
sc = Cache_Check (&sfx->cache);
|
} else {
|
||||||
|
if (!sfx->touch (sfx))
|
||||||
if (!sc)
|
continue;
|
||||||
continue;
|
}
|
||||||
size = sc->length * sc->width * (sc->stereo + 1);
|
total += sfx->length;
|
||||||
total += size;
|
|
||||||
if (sc->loopstart >= 0)
|
|
||||||
Sys_Printf ("L");
|
|
||||||
else
|
|
||||||
Sys_Printf (" ");
|
|
||||||
Sys_Printf ("(%2db) %6i : %s\n", sc->width * 8, size, sfx->name);
|
|
||||||
|
|
||||||
if (load)
|
if (load)
|
||||||
Cache_Release (&sfx->cache);
|
sfx->release (sfx);
|
||||||
}
|
}
|
||||||
Sys_Printf ("Total resident: %i\n", total);
|
Sys_Printf ("Total resident: %i\n", total);
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,44 +45,121 @@ static __attribute__ ((unused)) const char rcsid[] =
|
||||||
#include "QF/qendian.h"
|
#include "QF/qendian.h"
|
||||||
#include "QF/quakefs.h"
|
#include "QF/quakefs.h"
|
||||||
|
|
||||||
|
#include "compat.h"
|
||||||
#include "snd_render.h"
|
#include "snd_render.h"
|
||||||
|
|
||||||
int cache_full_cycle;
|
static sfxbuffer_t *
|
||||||
|
snd_fail (sfx_t *sfx)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
sfxcache_t *
|
static void
|
||||||
|
snd_noop (sfx_t *sfx)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
sfxbuffer_t *
|
||||||
|
SND_CacheRetain (sfx_t *sfx)
|
||||||
|
{
|
||||||
|
return Cache_TryGet (&((sfxblock_t *) sfx)->cache);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SND_CacheRelease (sfx_t *sfx)
|
||||||
|
{
|
||||||
|
Cache_Release (&((sfxblock_t *) sfx->data)->cache);
|
||||||
|
}
|
||||||
|
|
||||||
|
sfxbuffer_t *
|
||||||
|
SND_StreamRetain (sfx_t *sfx)
|
||||||
|
{
|
||||||
|
return &((sfxstream_t *) sfx->data)->buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SND_StreamRelease (sfx_t *sfx)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SND_Load (sfx_t *sfx)
|
||||||
|
{
|
||||||
|
dstring_t *name = dstring_new ();
|
||||||
|
dstring_t *foundname = dstring_new ();
|
||||||
|
char *realname;
|
||||||
|
char buf[4];
|
||||||
|
QFile *file;
|
||||||
|
|
||||||
|
sfx->touch = sfx->retain = snd_fail;
|
||||||
|
sfx->release = snd_noop;
|
||||||
|
|
||||||
|
dsprintf (name, "sound/%s", sfx->name);
|
||||||
|
_QFS_FOpenFile (name->str, &file, foundname, 1);
|
||||||
|
if (!file) {
|
||||||
|
Sys_Printf ("Couldn't load %s\n", name->str);
|
||||||
|
dstring_delete (name);
|
||||||
|
dstring_delete (foundname);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!strequal (foundname->str, name->str)) {
|
||||||
|
realname = foundname->str;
|
||||||
|
dstring_delete (name);
|
||||||
|
free (foundname);
|
||||||
|
} else {
|
||||||
|
realname = name->str;
|
||||||
|
free (name);
|
||||||
|
dstring_delete (foundname);
|
||||||
|
}
|
||||||
|
Qread (file, buf, 4);
|
||||||
|
Qseek (file, 0, SEEK_SET);
|
||||||
|
if (strnequal ("OggS", buf, 4)) {
|
||||||
|
free (name);
|
||||||
|
SND_LoadOgg (file, sfx, realname);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (strnequal ("RIFF", buf, 4)) {
|
||||||
|
free (name);
|
||||||
|
SND_LoadWav (file, sfx, realname);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
free (realname);
|
||||||
|
}
|
||||||
|
|
||||||
|
sfxbuffer_t *
|
||||||
SND_GetCache (long samples, int rate, int inwidth, int channels,
|
SND_GetCache (long samples, int rate, int inwidth, int channels,
|
||||||
sfx_t *sfx, cache_allocator_t allocator)
|
sfxblock_t *block, cache_allocator_t allocator)
|
||||||
{
|
{
|
||||||
int size;
|
int size;
|
||||||
int width;
|
int width;
|
||||||
float stepscale;
|
float stepscale;
|
||||||
sfxcache_t *sc;
|
sfxbuffer_t *sc;
|
||||||
|
sfx_t *sfx = block->sfx;
|
||||||
|
|
||||||
width = snd_loadas8bit->int_val ? 1 : 2;
|
width = snd_loadas8bit->int_val ? 1 : 2;
|
||||||
stepscale = (float) rate / shm->speed; // usually 0.5, 1, or 2
|
stepscale = (float) rate / shm->speed; // usually 0.5, 1, or 2
|
||||||
size = samples / stepscale;
|
size = samples / stepscale;
|
||||||
size *= width * channels;
|
size *= width * channels;
|
||||||
sc = allocator (&sfx->cache, size + sizeof (sfxcache_t), sfx->name);
|
sc = allocator (&block->cache, sizeof (sfxbuffer_t) + size, sfx->name);
|
||||||
if (!sc)
|
if (!sc)
|
||||||
return 0;
|
return 0;
|
||||||
sc->length = samples;
|
sfx->length = samples;
|
||||||
sc->speed = rate;
|
sfx->speed = rate;
|
||||||
sc->width = inwidth;
|
sfx->width = inwidth;
|
||||||
sc->stereo = channels;
|
sfx->channels = channels;
|
||||||
sc->bytes = size;
|
block->bytes = size;
|
||||||
memcpy (sc->data + size, "\xde\xad\xbe\xef", 4);
|
|
||||||
return sc;
|
return sc;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
SND_ResampleSfx (sfxcache_t *sc, byte * data)
|
SND_ResampleSfx (sfx_t *sfx, sfxbuffer_t *sc, byte *data)
|
||||||
{
|
{
|
||||||
unsigned char *ib, *ob;
|
unsigned char *ib, *ob;
|
||||||
int fracstep, outcount, sample, samplefrac, srcsample, i;
|
int fracstep, outcount, sample, samplefrac, srcsample, i;
|
||||||
float stepscale;
|
float stepscale;
|
||||||
short *is, *os;
|
short *is, *os;
|
||||||
int inwidth = sc->width;
|
int inwidth = sfx->width;
|
||||||
int inrate = sc->speed;
|
int inrate = sfx->speed;
|
||||||
|
|
||||||
is = (short *) data;
|
is = (short *) data;
|
||||||
os = (short *) sc->data;
|
os = (short *) sc->data;
|
||||||
|
@ -91,30 +168,30 @@ SND_ResampleSfx (sfxcache_t *sc, byte * data)
|
||||||
|
|
||||||
stepscale = (float) inrate / shm->speed; // usually 0.5, 1, or 2
|
stepscale = (float) inrate / shm->speed; // usually 0.5, 1, or 2
|
||||||
|
|
||||||
outcount = sc->length / stepscale;
|
outcount = sfx->length / stepscale;
|
||||||
|
|
||||||
sc->speed = shm->speed;
|
sfx->speed = shm->speed;
|
||||||
if (snd_loadas8bit->int_val)
|
if (snd_loadas8bit->int_val)
|
||||||
sc->width = 1;
|
sfx->width = 1;
|
||||||
else
|
else
|
||||||
sc->width = 2;
|
sfx->width = 2;
|
||||||
sc->stereo = 0;
|
sfx->channels = 1;
|
||||||
|
|
||||||
// resample / decimate to the current source rate
|
// resample / decimate to the current source rate
|
||||||
if (stepscale == 1) {
|
if (stepscale == 1) {
|
||||||
if (inwidth == 1 && sc->width == 1) {
|
if (inwidth == 1 && sfx->width == 1) {
|
||||||
for (i = 0; i < outcount; i++) {
|
for (i = 0; i < outcount; i++) {
|
||||||
*ob++ = *ib++ - 128;
|
*ob++ = *ib++ - 128;
|
||||||
}
|
}
|
||||||
} else if (inwidth == 1 && sc->width == 2) {
|
} else if (inwidth == 1 && sfx->width == 2) {
|
||||||
for (i = 0; i < outcount; i++) {
|
for (i = 0; i < outcount; i++) {
|
||||||
*os++ = (*ib++ - 128) << 8;
|
*os++ = (*ib++ - 128) << 8;
|
||||||
}
|
}
|
||||||
} else if (inwidth == 2 && sc->width == 1) {
|
} else if (inwidth == 2 && sfx->width == 1) {
|
||||||
for (i = 0; i < outcount; i++) {
|
for (i = 0; i < outcount; i++) {
|
||||||
*ob++ = LittleShort (*is++) >> 8;
|
*ob++ = LittleShort (*is++) >> 8;
|
||||||
}
|
}
|
||||||
} else if (inwidth == 2 && sc->width == 2) {
|
} else if (inwidth == 2 && sfx->width == 2) {
|
||||||
for (i = 0; i < outcount; i++) {
|
for (i = 0; i < outcount; i++) {
|
||||||
*os++ = LittleShort (*is++);
|
*os++ = LittleShort (*is++);
|
||||||
}
|
}
|
||||||
|
@ -125,29 +202,29 @@ SND_ResampleSfx (sfxcache_t *sc, byte * data)
|
||||||
int j;
|
int j;
|
||||||
int points = 1 / stepscale;
|
int points = 1 / stepscale;
|
||||||
|
|
||||||
for (i = 0; i < sc->length; i++) {
|
for (i = 0; i < sfx->length; i++) {
|
||||||
int s1, s2;
|
int s1, s2;
|
||||||
|
|
||||||
if (inwidth == 2) {
|
if (inwidth == 2) {
|
||||||
s2 = s1 = LittleShort (is[0]);
|
s2 = s1 = LittleShort (is[0]);
|
||||||
if (i < sc->length - 1)
|
if (i < sfx->length - 1)
|
||||||
s2 = LittleShort (is[1]);
|
s2 = LittleShort (is[1]);
|
||||||
is++;
|
is++;
|
||||||
} else {
|
} else {
|
||||||
s2 = s1 = (ib[0] - 128) << 8;
|
s2 = s1 = (ib[0] - 128) << 8;
|
||||||
if (i < sc->length - 1)
|
if (i < sfx->length - 1)
|
||||||
s2 = (ib[1] - 128) << 8;
|
s2 = (ib[1] - 128) << 8;
|
||||||
ib++;
|
ib++;
|
||||||
}
|
}
|
||||||
for (j = 0; j < points; j++) {
|
for (j = 0; j < points; j++) {
|
||||||
sample = s1 + (s2 - s1) * ((float) j) / points;
|
sample = s1 + (s2 - s1) * ((float) j) / points;
|
||||||
if (sc->width == 2) {
|
if (sfx->width == 2) {
|
||||||
os[j] = sample;
|
os[j] = sample;
|
||||||
} else {
|
} else {
|
||||||
ob[j] = sample >> 8;
|
ob[j] = sample >> 8;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (sc->width == 2) {
|
if (sfx->width == 2) {
|
||||||
os += points;
|
os += points;
|
||||||
} else {
|
} else {
|
||||||
ob += points;
|
ob += points;
|
||||||
|
@ -164,7 +241,7 @@ SND_ResampleSfx (sfxcache_t *sc, byte * data)
|
||||||
else
|
else
|
||||||
sample =
|
sample =
|
||||||
(int) ((unsigned char) (data[srcsample]) - 128) << 8;
|
(int) ((unsigned char) (data[srcsample]) - 128) << 8;
|
||||||
if (sc->width == 2)
|
if (sfx->width == 2)
|
||||||
((short *) sc->data)[i] = sample;
|
((short *) sc->data)[i] = sample;
|
||||||
else
|
else
|
||||||
((signed char *) sc->data)[i] = sample >> 8;
|
((signed char *) sc->data)[i] = sample >> 8;
|
||||||
|
@ -172,241 +249,7 @@ SND_ResampleSfx (sfxcache_t *sc, byte * data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sc->length = outcount;
|
sfx->length = outcount;
|
||||||
if (sc->loopstart != -1)
|
if (sfx->loopstart != -1)
|
||||||
sc->loopstart = sc->loopstart / stepscale;
|
sfx->loopstart = sfx->loopstart / stepscale;
|
||||||
if (memcmp (sc->data + sc->bytes, "\xde\xad\xbe\xef", 4))
|
|
||||||
Sys_Error ("SND_ResampleSfx screwed the pooch: %02x%02x%02x%02x",
|
|
||||||
sc->data[sc->bytes + 0], sc->data[sc->bytes + 1],
|
|
||||||
sc->data[sc->bytes + 2], sc->data[sc->bytes + 3]);
|
|
||||||
}
|
|
||||||
|
|
||||||
static sfxcache_t *
|
|
||||||
SND_LoadSound (sfx_t *sfx, cache_allocator_t allocator)
|
|
||||||
{
|
|
||||||
char namebuffer[256];
|
|
||||||
dstring_t *foundname = dstring_new ();
|
|
||||||
byte *data;
|
|
||||||
wavinfo_t info;
|
|
||||||
int len;
|
|
||||||
float stepscale;
|
|
||||||
sfxcache_t *sc;
|
|
||||||
byte stackbuf[1 * 1024]; // avoid dirtying the cache heap
|
|
||||||
QFile *file;
|
|
||||||
|
|
||||||
// load it in
|
|
||||||
strcpy (namebuffer, "sound/");
|
|
||||||
strncat (namebuffer, sfx->name, sizeof (namebuffer) - strlen (namebuffer));
|
|
||||||
_QFS_FOpenFile (namebuffer, &file, foundname, 1);
|
|
||||||
if (!file) {
|
|
||||||
dstring_delete (foundname);
|
|
||||||
Sys_Printf ("Couldn't load %s\n", namebuffer);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (strcmp (".ogg", QFS_FileExtension (foundname->str)) == 0) {
|
|
||||||
dstring_delete (foundname);
|
|
||||||
return SND_LoadOgg (file, sfx, allocator);
|
|
||||||
}
|
|
||||||
dstring_delete (foundname);
|
|
||||||
Qclose (file); //FIXME this is a dumb way to do this
|
|
||||||
data = QFS_LoadStackFile (namebuffer, stackbuf, sizeof (stackbuf));
|
|
||||||
|
|
||||||
if (!data) {
|
|
||||||
Sys_Printf ("Couldn't load %s\n", namebuffer);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
info = SND_GetWavinfo (sfx->name, data, qfs_filesize);
|
|
||||||
if (info.channels != 1) {
|
|
||||||
Sys_Printf ("%s is a stereo sample\n", sfx->name);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
stepscale = (float) info.rate / shm->speed;
|
|
||||||
len = info.samples / stepscale;
|
|
||||||
|
|
||||||
if (snd_loadas8bit->int_val) {
|
|
||||||
len = len * info.channels;
|
|
||||||
} else {
|
|
||||||
len = len * 2 * info.channels;
|
|
||||||
}
|
|
||||||
|
|
||||||
sc = SND_GetCache (info.samples, info.rate, info.width, info.channels,
|
|
||||||
sfx, allocator);
|
|
||||||
if (!sc)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
sc->loopstart = info.loopstart;
|
|
||||||
|
|
||||||
SND_ResampleSfx (sc, data + info.dataofs);
|
|
||||||
|
|
||||||
return sc;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
SND_CallbackLoad (void *object, cache_allocator_t allocator)
|
|
||||||
{
|
|
||||||
SND_LoadSound (object, allocator);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* WAV loading */
|
|
||||||
|
|
||||||
byte *data_p;
|
|
||||||
byte *iff_end;
|
|
||||||
byte *last_chunk;
|
|
||||||
byte *iff_data;
|
|
||||||
int iff_chunk_len;
|
|
||||||
|
|
||||||
static short
|
|
||||||
SND_GetLittleShort (void)
|
|
||||||
{
|
|
||||||
short val = 0;
|
|
||||||
|
|
||||||
val = *data_p;
|
|
||||||
val = val + (*(data_p + 1) << 8);
|
|
||||||
data_p += 2;
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
SND_GetLittleLong (void)
|
|
||||||
{
|
|
||||||
int val = 0;
|
|
||||||
|
|
||||||
val = *data_p;
|
|
||||||
val = val + (*(data_p + 1) << 8);
|
|
||||||
val = val + (*(data_p + 2) << 16);
|
|
||||||
val = val + (*(data_p + 3) << 24);
|
|
||||||
data_p += 4;
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
SND_FindNexctChunk (const char *name)
|
|
||||||
{
|
|
||||||
while (1) {
|
|
||||||
data_p = last_chunk;
|
|
||||||
|
|
||||||
if (data_p >= iff_end) { // didn't find the chunk
|
|
||||||
data_p = NULL;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
data_p += 4;
|
|
||||||
iff_chunk_len = SND_GetLittleLong ();
|
|
||||||
if (iff_chunk_len < 0) {
|
|
||||||
data_p = NULL;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
data_p -= 8;
|
|
||||||
last_chunk = data_p + 8 + ((iff_chunk_len + 1) & ~1);
|
|
||||||
if (!strncmp (data_p, name, 4))
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
SND_FindChunk (const char *name)
|
|
||||||
{
|
|
||||||
last_chunk = iff_data;
|
|
||||||
SND_FindNexctChunk (name);
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
static void
|
|
||||||
SND_DumpChunks (void)
|
|
||||||
{
|
|
||||||
char str[5];
|
|
||||||
|
|
||||||
str[4] = 0;
|
|
||||||
data_p = iff_data;
|
|
||||||
do {
|
|
||||||
memcpy (str, data_p, 4);
|
|
||||||
data_p += 4;
|
|
||||||
iff_chunk_len = SND_GetLittleLong ();
|
|
||||||
Sys_Printf ("0x%lx : %s (%d)\n", (long) (data_p - 4), str,
|
|
||||||
iff_chunk_len);
|
|
||||||
data_p += (iff_chunk_len + 1) & ~1;
|
|
||||||
} while (data_p < iff_end);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
wavinfo_t
|
|
||||||
SND_GetWavinfo (const char *name, byte * wav, int wavlength)
|
|
||||||
{
|
|
||||||
int format, samples, i;
|
|
||||||
wavinfo_t info;
|
|
||||||
|
|
||||||
memset (&info, 0, sizeof (info));
|
|
||||||
|
|
||||||
if (!wav)
|
|
||||||
return info;
|
|
||||||
|
|
||||||
iff_data = wav;
|
|
||||||
iff_end = wav + wavlength;
|
|
||||||
|
|
||||||
// find "RIFF" chunk
|
|
||||||
SND_FindChunk ("RIFF");
|
|
||||||
if (!(data_p && !strncmp (data_p + 8, "WAVE", 4))) {
|
|
||||||
Sys_Printf ("Missing RIFF/WAVE chunks\n");
|
|
||||||
return info;
|
|
||||||
}
|
|
||||||
// get "fmt " chunk
|
|
||||||
iff_data = data_p + 12;
|
|
||||||
// SND_DumpChunks ();
|
|
||||||
|
|
||||||
SND_FindChunk ("fmt ");
|
|
||||||
if (!data_p) {
|
|
||||||
Sys_Printf ("Missing fmt chunk\n");
|
|
||||||
return info;
|
|
||||||
}
|
|
||||||
data_p += 8;
|
|
||||||
format = SND_GetLittleShort ();
|
|
||||||
if (format != 1) {
|
|
||||||
Sys_Printf ("Microsoft PCM format only\n");
|
|
||||||
return info;
|
|
||||||
}
|
|
||||||
|
|
||||||
info.channels = SND_GetLittleShort ();
|
|
||||||
info.rate = SND_GetLittleLong ();
|
|
||||||
data_p += 4 + 2;
|
|
||||||
info.width = SND_GetLittleShort () / 8;
|
|
||||||
|
|
||||||
// get cue chunk
|
|
||||||
SND_FindChunk ("cue ");
|
|
||||||
if (data_p) {
|
|
||||||
data_p += 32;
|
|
||||||
info.loopstart = SND_GetLittleLong ();
|
|
||||||
|
|
||||||
// if the next chunk is a LIST chunk, look for a cue length marker
|
|
||||||
SND_FindNexctChunk ("LIST");
|
|
||||||
if (data_p) {
|
|
||||||
if (!strncmp (data_p + 28, "mark", 4)) {
|
|
||||||
// this is not a proper parse, but it works with cooledit...
|
|
||||||
data_p += 24;
|
|
||||||
i = SND_GetLittleLong (); // samples in loop
|
|
||||||
info.samples = info.loopstart + i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
info.loopstart = -1;
|
|
||||||
|
|
||||||
// find data chunk
|
|
||||||
SND_FindChunk ("data");
|
|
||||||
if (!data_p) {
|
|
||||||
Sys_Printf ("Missing data chunk\n");
|
|
||||||
return info;
|
|
||||||
}
|
|
||||||
|
|
||||||
data_p += 4;
|
|
||||||
samples = SND_GetLittleLong () / info.width;
|
|
||||||
|
|
||||||
if (info.samples) {
|
|
||||||
if (samples < info.samples)
|
|
||||||
Sys_Error ("Sound %s has a bad loop length", name);
|
|
||||||
} else
|
|
||||||
info.samples = samples;
|
|
||||||
|
|
||||||
info.dataofs = data_p - wav;
|
|
||||||
|
|
||||||
return info;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,7 +55,6 @@ int snd_scaletable[32][256];
|
||||||
int *snd_p, snd_linear_count, snd_vol;
|
int *snd_p, snd_linear_count, snd_vol;
|
||||||
short *snd_out;
|
short *snd_out;
|
||||||
|
|
||||||
#ifndef USE_INTEL_ASM
|
|
||||||
void
|
void
|
||||||
SND_WriteLinearBlastStereo16 (void)
|
SND_WriteLinearBlastStereo16 (void)
|
||||||
{
|
{
|
||||||
|
@ -79,7 +78,6 @@ SND_WriteLinearBlastStereo16 (void)
|
||||||
snd_out[i + 1] = val;
|
snd_out[i + 1] = val;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
SND_TransferStereo16 (int endtime)
|
SND_TransferStereo16 (int endtime)
|
||||||
|
@ -172,7 +170,7 @@ SND_PaintChannels (int endtime)
|
||||||
{
|
{
|
||||||
int end, ltime, count, i;
|
int end, ltime, count, i;
|
||||||
channel_t *ch;
|
channel_t *ch;
|
||||||
sfxcache_t *sc;
|
sfxbuffer_t *sc;
|
||||||
|
|
||||||
while (paintedtime < endtime) {
|
while (paintedtime < endtime) {
|
||||||
// if paintbuffer is smaller than DMA buffer
|
// if paintbuffer is smaller than DMA buffer
|
||||||
|
@ -192,7 +190,7 @@ SND_PaintChannels (int endtime)
|
||||||
continue;
|
continue;
|
||||||
if (!ch->leftvol && !ch->rightvol)
|
if (!ch->leftvol && !ch->rightvol)
|
||||||
continue;
|
continue;
|
||||||
sc = Cache_TryGet (&ch->sfx->cache);
|
sc = ch->sfx->retain (ch->sfx);
|
||||||
if (!sc)
|
if (!sc)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -205,20 +203,17 @@ SND_PaintChannels (int endtime)
|
||||||
count = end - ltime;
|
count = end - ltime;
|
||||||
|
|
||||||
if (count > 0) {
|
if (count > 0) {
|
||||||
if (sc->width == 1)
|
sc->paint (ch, sc, count);
|
||||||
SND_PaintChannelFrom8 (ch, sc, count);
|
|
||||||
else
|
|
||||||
SND_PaintChannelFrom16 (ch, sc, count);
|
|
||||||
|
|
||||||
ltime += count;
|
ltime += count;
|
||||||
}
|
}
|
||||||
// if at end of loop, restart
|
// if at end of loop, restart
|
||||||
if (ltime >= ch->end) {
|
if (ltime >= ch->end) {
|
||||||
if (sc->loopstart >= 0) {
|
if (ch->sfx->loopstart >= 0) {
|
||||||
ch->pos = sc->loopstart;
|
ch->pos = ch->sfx->loopstart;
|
||||||
ch->end = ltime + sc->length - ch->pos;
|
ch->end = ltime + ch->sfx->length - ch->pos;
|
||||||
} else { // channel just stopped
|
} else { // channel just stopped
|
||||||
Cache_Release (&ch->sfx->cache);
|
ch->sfx->release (ch->sfx);
|
||||||
ch->sfx = NULL;
|
ch->sfx = NULL;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -226,7 +221,7 @@ SND_PaintChannels (int endtime)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ch->sfx)
|
if (ch->sfx)
|
||||||
Cache_Release (&ch->sfx->cache);
|
ch->sfx->release (ch->sfx);
|
||||||
}
|
}
|
||||||
|
|
||||||
// transfer out according to DMA format
|
// transfer out according to DMA format
|
||||||
|
@ -251,9 +246,8 @@ SND_InitScaletable (void)
|
||||||
snd_scaletable[i][j] = ((signed char) j) * i * 8;
|
snd_scaletable[i][j] = ((signed char) j) * i * 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef USE_INTEL_ASM
|
|
||||||
void
|
void
|
||||||
SND_PaintChannelFrom8 (channel_t *ch, sfxcache_t *sc, int count)
|
SND_PaintChannelFrom8 (channel_t *ch, sfxbuffer_t *sc, int count)
|
||||||
{
|
{
|
||||||
unsigned char *sfx;
|
unsigned char *sfx;
|
||||||
int data, i;
|
int data, i;
|
||||||
|
@ -276,10 +270,9 @@ SND_PaintChannelFrom8 (channel_t *ch, sfxcache_t *sc, int count)
|
||||||
|
|
||||||
ch->pos += count;
|
ch->pos += count;
|
||||||
}
|
}
|
||||||
#endif // !USE_INTEL_ASM
|
|
||||||
|
|
||||||
void
|
void
|
||||||
SND_PaintChannelFrom16 (channel_t *ch, sfxcache_t *sc, int count)
|
SND_PaintChannelFrom16 (channel_t *ch, sfxbuffer_t *sc, int count)
|
||||||
{
|
{
|
||||||
int leftvol, rightvol;
|
int leftvol, rightvol;
|
||||||
unsigned int left_phase, right_phase; // Never allowed < 0 anyway
|
unsigned int left_phase, right_phase; // Never allowed < 0 anyway
|
||||||
|
@ -374,7 +367,7 @@ SND_PaintChannelFrom16 (channel_t *ch, sfxcache_t *sc, int count)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
SND_PaintChannelStereo8 (channel_t *ch, sfxcache_t *sc, int count)
|
SND_PaintChannelStereo8 (channel_t *ch, sfxbuffer_t *sc, int count)
|
||||||
{
|
{
|
||||||
byte *samp;
|
byte *samp;
|
||||||
portable_samplepair_t *pair;
|
portable_samplepair_t *pair;
|
||||||
|
@ -398,7 +391,7 @@ SND_PaintChannelStereo8 (channel_t *ch, sfxcache_t *sc, int count)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
SND_PaintChannelStereo16 (channel_t *ch, sfxcache_t *sc, int count)
|
SND_PaintChannelStereo16 (channel_t *ch, sfxbuffer_t *sc, int count)
|
||||||
{
|
{
|
||||||
short *samp;
|
short *samp;
|
||||||
portable_samplepair_t *pair;
|
portable_samplepair_t *pair;
|
||||||
|
|
|
@ -47,7 +47,7 @@ static __attribute__ ((unused)) const char rcsid[] =
|
||||||
#include <vorbis/vorbisfile.h>
|
#include <vorbis/vorbisfile.h>
|
||||||
|
|
||||||
#include "QF/cvar.h"
|
#include "QF/cvar.h"
|
||||||
#include "QF/quakeio.h"
|
#include "QF/quakefs.h"
|
||||||
#include "QF/sound.h"
|
#include "QF/sound.h"
|
||||||
#include "QF/sys.h"
|
#include "QF/sys.h"
|
||||||
|
|
||||||
|
@ -85,73 +85,185 @@ static ov_callbacks callbacks = {
|
||||||
tell_func,
|
tell_func,
|
||||||
};
|
};
|
||||||
|
|
||||||
sfxcache_t *
|
static void
|
||||||
SND_LoadOgg (QFile *file, sfx_t *sfx, cache_allocator_t allocator)
|
get_info (OggVorbis_File *vf, sfx_t *sfx)
|
||||||
{
|
{
|
||||||
OggVorbis_File vf;
|
|
||||||
vorbis_info *vi;
|
vorbis_info *vi;
|
||||||
long samples, size;
|
|
||||||
byte *data, *d;
|
|
||||||
int current_section;
|
|
||||||
int sample_start = -1, sample_count = 0;
|
int sample_start = -1, sample_count = 0;
|
||||||
sfxcache_t *sc = 0;
|
|
||||||
char **ptr;
|
char **ptr;
|
||||||
|
|
||||||
if (ov_open_callbacks (file, &vf, 0, 0, callbacks) < 0) {
|
vi = ov_info (vf, -1);
|
||||||
Sys_Printf ("Input does not appear to be an Ogg bitstream.\n");
|
sfx->length = ov_pcm_total (vf, -1);
|
||||||
Qclose (file);
|
sfx->channels = vi->channels;
|
||||||
return 0;
|
sfx->speed = vi->rate;
|
||||||
}
|
|
||||||
vi = ov_info (&vf, -1);
|
|
||||||
samples = ov_pcm_total (&vf, -1);
|
|
||||||
|
|
||||||
for (ptr = ov_comment (&vf, -1)->user_comments; *ptr; ptr++) {
|
for (ptr = ov_comment (vf, -1)->user_comments; *ptr; ptr++) {
|
||||||
Sys_DPrintf ("%s\n", *ptr);
|
Sys_DPrintf ("%s\n", *ptr);
|
||||||
if (strncmp ("CUEPOINT=", *ptr, 9) == 0) {
|
if (strncmp ("CUEPOINT=", *ptr, 9) == 0) {
|
||||||
sscanf (*ptr + 9, "%d %d", &sample_start, &sample_count);
|
sscanf (*ptr + 9, "%d %d", &sample_start, &sample_count);
|
||||||
} else {
|
break;
|
||||||
sample_count = samples;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (sample_start != -1)
|
|
||||||
samples = sample_start + sample_count;
|
|
||||||
size = samples * vi->channels * 2;
|
|
||||||
if (developer->int_val) {
|
if (developer->int_val) {
|
||||||
Sys_Printf ("\nBitstream is %d channel, %ldHz\n",
|
Sys_Printf ("\nBitstream is %d channel, %dHz\n",
|
||||||
vi->channels, vi->rate);
|
sfx->channels, sfx->speed);
|
||||||
Sys_Printf ("\nDecoded length: %ld samples (%ld bytes)\n",
|
Sys_Printf ("\nDecoded length: %d samples (%d bytes)\n",
|
||||||
samples, size);
|
sfx->length, sfx->length * sfx->channels * 2);
|
||||||
Sys_Printf ("Encoded by: %s\n\n", ov_comment (&vf, -1)->vendor);
|
Sys_Printf ("Encoded by: %s\n\n", ov_comment (vf, -1)->vendor);
|
||||||
}
|
}
|
||||||
data = malloc (size);
|
|
||||||
if (!data)
|
if (sample_start != -1)
|
||||||
goto bail;
|
sfx->length = sample_start + sample_count;
|
||||||
sc = SND_GetCache (samples, vi->rate, 2, vi->channels, sfx, allocator);
|
sfx->loopstart = sample_start;
|
||||||
if (!sc)
|
}
|
||||||
goto bail;
|
|
||||||
d = data;
|
static int
|
||||||
while (size) {
|
read_ogg (OggVorbis_File *vf, byte *buf, int len)
|
||||||
int res = ov_read (&vf, d, size, 0, 2, 1, ¤t_section);
|
{
|
||||||
|
int count = 0;
|
||||||
|
int current_section;
|
||||||
|
|
||||||
|
while (len) {
|
||||||
|
int res = ov_read (vf, buf, len, 0, 2, 1, ¤t_section);
|
||||||
if (res > 0) {
|
if (res > 0) {
|
||||||
size -= res;
|
count += res;
|
||||||
d += res;
|
len -= res;
|
||||||
|
buf += res;
|
||||||
} else if (res < 0) {
|
} else if (res < 0) {
|
||||||
Sys_Printf ("vorbis error %d\n", res);
|
Sys_Printf ("vorbis error %d\n", res);
|
||||||
goto bail;
|
return -1;
|
||||||
} else {
|
} else {
|
||||||
Sys_Printf ("unexpected eof\n");
|
Sys_Printf ("unexpected eof\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sc->loopstart = sample_start;
|
return count;
|
||||||
SND_ResampleSfx (sc, data);
|
}
|
||||||
|
|
||||||
|
static sfxbuffer_t *
|
||||||
|
load_ogg (OggVorbis_File *vf, sfxblock_t *block, cache_allocator_t allocator)
|
||||||
|
{
|
||||||
|
long size;
|
||||||
|
byte *data;
|
||||||
|
sfxbuffer_t *sc = 0;
|
||||||
|
sfx_t *sfx = block->sfx;
|
||||||
|
int channels;
|
||||||
|
|
||||||
|
|
||||||
|
get_info (vf, sfx);
|
||||||
|
|
||||||
|
channels = sfx->channels;
|
||||||
|
|
||||||
|
size = sfx->length * channels * 2;
|
||||||
|
|
||||||
|
data = malloc (size);
|
||||||
|
if (!data)
|
||||||
|
goto bail;
|
||||||
|
sc = SND_GetCache (sfx->length, sfx->speed, 2, channels, block, allocator);
|
||||||
|
if (!sc)
|
||||||
|
goto bail;
|
||||||
|
if (read_ogg (vf, data, size) < 0)
|
||||||
|
goto bail;
|
||||||
|
SND_ResampleSfx (sfx, sc, data);
|
||||||
bail:
|
bail:
|
||||||
if (data)
|
if (data)
|
||||||
free (data);
|
free (data);
|
||||||
ov_clear (&vf);
|
ov_clear (vf);
|
||||||
return sc;
|
return sc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ogg_callback_load (void *object, cache_allocator_t allocator)
|
||||||
|
{
|
||||||
|
QFile *file;
|
||||||
|
OggVorbis_File vf;
|
||||||
|
|
||||||
|
sfxblock_t *block = (sfxblock_t *) object;
|
||||||
|
|
||||||
|
QFS_FOpenFile (block->file, &file);
|
||||||
|
if (!file)
|
||||||
|
return; //FIXME Sys_Error?
|
||||||
|
|
||||||
|
if (ov_open_callbacks (file, &vf, 0, 0, callbacks) < 0) {
|
||||||
|
Sys_Printf ("Input does not appear to be an Ogg bitstream.\n");
|
||||||
|
Qclose (file);
|
||||||
|
return; //FIXME Sys_Error?
|
||||||
|
}
|
||||||
|
load_ogg (&vf, block, allocator);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
vorbis_advance (sfxbuffer_t *buffer, int count)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
stream_ogg (sfx_t *sfx, OggVorbis_File *vf)
|
||||||
|
{
|
||||||
|
sfxstream_t *stream;
|
||||||
|
int length, bytes;
|
||||||
|
void (*paint) (channel_t *ch, sfxbuffer_t *buffer, int count);
|
||||||
|
|
||||||
|
|
||||||
|
get_info (vf, sfx);
|
||||||
|
|
||||||
|
switch (sfx->channels) {
|
||||||
|
case 1:
|
||||||
|
paint = SND_PaintChannelFrom16;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
paint = SND_PaintChannelStereo16;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Sys_Printf ("%s: unsupported channel count: %d\n",
|
||||||
|
sfx->name, sfx->channels);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
length = shm->speed * snd_mixahead->value * 3;
|
||||||
|
bytes = sfx->channels * 2 * length;
|
||||||
|
|
||||||
|
stream = calloc (1, sizeof (sfxstream_t) + bytes);
|
||||||
|
|
||||||
|
stream->file = malloc (sizeof (OggVorbis_File));
|
||||||
|
memcpy (stream->file, vf, sizeof (OggVorbis_File));
|
||||||
|
|
||||||
|
stream->buffer.length = length;
|
||||||
|
stream->buffer.paint = paint;
|
||||||
|
stream->buffer.advance = vorbis_advance;
|
||||||
|
|
||||||
|
sfx->data = stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SND_LoadOgg (QFile *file, sfx_t *sfx, char *realname)
|
||||||
|
{
|
||||||
|
OggVorbis_File vf;
|
||||||
|
|
||||||
|
if (ov_open_callbacks (file, &vf, 0, 0, callbacks) < 0) {
|
||||||
|
Sys_Printf ("Input does not appear to be an Ogg bitstream.\n");
|
||||||
|
Qclose (file);
|
||||||
|
free (realname);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (ov_pcm_total (&vf, -1) < 3 * shm->speed) {
|
||||||
|
sfxblock_t *block = calloc (1, sizeof (sfxblock_t));
|
||||||
|
ov_clear (&vf);
|
||||||
|
sfx->data = block;
|
||||||
|
sfx->retain = SND_CacheRetain;
|
||||||
|
sfx->release = SND_CacheRelease;
|
||||||
|
block->sfx = sfx;
|
||||||
|
block->file = realname;
|
||||||
|
Cache_Add (&block->cache, block, ogg_callback_load);
|
||||||
|
} else {
|
||||||
|
sfx->retain = SND_StreamRetain;
|
||||||
|
sfx->release = SND_StreamRelease;
|
||||||
|
free (realname);
|
||||||
|
stream_ogg (sfx, &vf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#else//HAVE_VORBIS
|
#else//HAVE_VORBIS
|
||||||
|
|
||||||
#include "QF/sound.h"
|
#include "QF/sound.h"
|
||||||
|
@ -160,11 +272,12 @@ SND_LoadOgg (QFile *file, sfx_t *sfx, cache_allocator_t allocator)
|
||||||
|
|
||||||
#include "snd_render.h"
|
#include "snd_render.h"
|
||||||
|
|
||||||
sfxcache_t *
|
void
|
||||||
SND_LoadOgg (QFile *file, sfx_t *sfx, cache_allocator_t allocator)
|
SND_LoadOgg (QFile *file, sfx_t *sfx, char *realname)
|
||||||
{
|
{
|
||||||
Sys_Printf ("Ogg/Vorbis support not available, sorry.\n");
|
Sys_Printf ("Ogg/Vorbis support not available, sorry.\n");
|
||||||
Qclose (file);
|
Qclose (file);
|
||||||
return 0;
|
free (realname);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
#endif//HAVE_VORBIS
|
#endif//HAVE_VORBIS
|
||||||
|
|
|
@ -43,184 +43,84 @@ static __attribute__ ((unused)) const char rcsid[] =
|
||||||
#include "QF/sys.h"
|
#include "QF/sys.h"
|
||||||
#include "QF/qendian.h"
|
#include "QF/qendian.h"
|
||||||
#include "QF/quakefs.h"
|
#include "QF/quakefs.h"
|
||||||
|
#include "QF/riff.h"
|
||||||
|
|
||||||
#include "snd_render.h"
|
#include "snd_render.h"
|
||||||
|
|
||||||
static byte *data_p;
|
|
||||||
static byte *iff_end;
|
|
||||||
static byte *last_chunk;
|
|
||||||
static byte *iff_data;
|
|
||||||
static int iff_chunk_len;
|
|
||||||
|
|
||||||
static short
|
|
||||||
SND_GetLittleShort (void)
|
|
||||||
{
|
|
||||||
short val = 0;
|
|
||||||
|
|
||||||
val = *data_p;
|
|
||||||
val = val + (*(data_p + 1) << 8);
|
|
||||||
data_p += 2;
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
SND_GetLittleLong (void)
|
|
||||||
{
|
|
||||||
int val = 0;
|
|
||||||
|
|
||||||
val = *data_p;
|
|
||||||
val = val + (*(data_p + 1) << 8);
|
|
||||||
val = val + (*(data_p + 2) << 16);
|
|
||||||
val = val + (*(data_p + 3) << 24);
|
|
||||||
data_p += 4;
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
SND_FindNexctChunk (const char *name)
|
|
||||||
{
|
|
||||||
while (1) {
|
|
||||||
data_p = last_chunk;
|
|
||||||
|
|
||||||
if (data_p >= iff_end) { // didn't find the chunk
|
|
||||||
data_p = NULL;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
data_p += 4;
|
|
||||||
iff_chunk_len = SND_GetLittleLong ();
|
|
||||||
if (iff_chunk_len < 0) {
|
|
||||||
data_p = NULL;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
data_p -= 8;
|
|
||||||
last_chunk = data_p + 8 + ((iff_chunk_len + 1) & ~1);
|
|
||||||
if (!strncmp (data_p, name, 4))
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
SND_FindChunk (const char *name)
|
|
||||||
{
|
|
||||||
last_chunk = iff_data;
|
|
||||||
SND_FindNexctChunk (name);
|
|
||||||
}
|
|
||||||
|
|
||||||
static wavinfo_t
|
|
||||||
SND_GetWavinfo (const char *name, byte * wav, int wavlength)
|
|
||||||
{
|
|
||||||
int format, samples, i;
|
|
||||||
wavinfo_t info;
|
|
||||||
|
|
||||||
memset (&info, 0, sizeof (info));
|
|
||||||
|
|
||||||
if (!wav)
|
|
||||||
return info;
|
|
||||||
|
|
||||||
iff_data = wav;
|
|
||||||
iff_end = wav + wavlength;
|
|
||||||
|
|
||||||
// find "RIFF" chunk
|
|
||||||
SND_FindChunk ("RIFF");
|
|
||||||
if (!(data_p && !strncmp (data_p + 8, "WAVE", 4))) {
|
|
||||||
Sys_Printf ("Missing RIFF/WAVE chunks\n");
|
|
||||||
return info;
|
|
||||||
}
|
|
||||||
// get "fmt " chunk
|
|
||||||
iff_data = data_p + 12;
|
|
||||||
// SND_DumpChunks ();
|
|
||||||
|
|
||||||
SND_FindChunk ("fmt ");
|
|
||||||
if (!data_p) {
|
|
||||||
Sys_Printf ("Missing fmt chunk\n");
|
|
||||||
return info;
|
|
||||||
}
|
|
||||||
data_p += 8;
|
|
||||||
format = SND_GetLittleShort ();
|
|
||||||
if (format != 1) {
|
|
||||||
Sys_Printf ("Microsoft PCM format only\n");
|
|
||||||
return info;
|
|
||||||
}
|
|
||||||
|
|
||||||
info.channels = SND_GetLittleShort ();
|
|
||||||
info.rate = SND_GetLittleLong ();
|
|
||||||
data_p += 4 + 2;
|
|
||||||
info.width = SND_GetLittleShort () / 8;
|
|
||||||
|
|
||||||
// get cue chunk
|
|
||||||
SND_FindChunk ("cue ");
|
|
||||||
if (data_p) {
|
|
||||||
data_p += 32;
|
|
||||||
info.loopstart = SND_GetLittleLong ();
|
|
||||||
|
|
||||||
// if the next chunk is a LIST chunk, look for a cue length marker
|
|
||||||
SND_FindNexctChunk ("LIST");
|
|
||||||
if (data_p) {
|
|
||||||
if (!strncmp (data_p + 28, "mark", 4)) {
|
|
||||||
// this is not a proper parse, but it works with cooledit...
|
|
||||||
data_p += 24;
|
|
||||||
i = SND_GetLittleLong (); // samples in loop
|
|
||||||
info.samples = info.loopstart + i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
info.loopstart = -1;
|
|
||||||
|
|
||||||
// find data chunk
|
|
||||||
SND_FindChunk ("data");
|
|
||||||
if (!data_p) {
|
|
||||||
Sys_Printf ("Missing data chunk\n");
|
|
||||||
return info;
|
|
||||||
}
|
|
||||||
|
|
||||||
data_p += 4;
|
|
||||||
samples = SND_GetLittleLong () / info.width;
|
|
||||||
|
|
||||||
if (info.samples) {
|
|
||||||
if (samples < info.samples)
|
|
||||||
Sys_Error ("Sound %s has a bad loop length", name);
|
|
||||||
} else
|
|
||||||
info.samples = samples;
|
|
||||||
|
|
||||||
info.dataofs = data_p - wav;
|
|
||||||
|
|
||||||
return info;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
SND_LoadWav (QFile *file)
|
SND_LoadWav (QFile *file, sfx_t *sfx, char *realname)
|
||||||
{
|
{
|
||||||
int size;
|
riff_t *riff;
|
||||||
|
riff_d_chunk_t **ck;
|
||||||
|
|
||||||
size = Qfilelen (file);
|
riff_format_t *fmt;
|
||||||
data = Hunk_TempAlloc (size);
|
riff_d_format_t *dfmt = 0;
|
||||||
Qread (file, data, size);
|
|
||||||
|
|
||||||
info = SND_GetWavinfo (sfx->name, data, qfs_filesize);
|
riff_data_t *data = 0;
|
||||||
if (info.channels != 1) {
|
|
||||||
Sys_Printf ("%s is a stereo sample\n", sfx->name);
|
riff_cue_t *cue;
|
||||||
return NULL;
|
riff_d_cue_t *dcue;
|
||||||
|
riff_d_cue_point_t *cp = 0;
|
||||||
|
|
||||||
|
riff_list_t *list;
|
||||||
|
riff_d_chunk_t **lck;
|
||||||
|
|
||||||
|
riff_ltxt_t *ltxt;
|
||||||
|
riff_d_ltxt_t *dltxt = 0;
|
||||||
|
|
||||||
|
int loop_start = -1, sample_count = -1;
|
||||||
|
|
||||||
|
if (!(riff = riff_read (file))) {
|
||||||
|
Sys_Printf ("bad riff file\n");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
stepscale = (float) info.rate / shm->speed;
|
for (ck = riff->chunks; *ck; ck++) {
|
||||||
len = info.samples / stepscale;
|
RIFF_SWITCH ((*ck)->name) {
|
||||||
|
case RIFF_CASE ('f','m','t',' '):
|
||||||
if (snd_loadas8bit->int_val) {
|
fmt = (riff_format_t *) *ck;
|
||||||
len = len * info.channels;
|
dfmt = (riff_d_format_t *) fmt->fdata;
|
||||||
} else {
|
break;
|
||||||
len = len * 2 * info.channels;
|
case RIFF_CASE ('d','a','t','a'):
|
||||||
|
data = (riff_data_t *) *ck;
|
||||||
|
break;
|
||||||
|
case RIFF_CASE ('c','u','e',' '):
|
||||||
|
cue = (riff_cue_t *) *ck;
|
||||||
|
dcue = cue->cue;
|
||||||
|
if (dcue->count)
|
||||||
|
cp = &dcue->cue_points[dcue->count - 1];
|
||||||
|
break;
|
||||||
|
case RIFF_CASE ('L','I','S','T'):
|
||||||
|
list = (riff_list_t *) *ck;
|
||||||
|
RIFF_SWITCH (list->name) {
|
||||||
|
case RIFF_CASE ('a','d','t','l'):
|
||||||
|
for (lck = list->chunks; *lck; lck++) {
|
||||||
|
RIFF_SWITCH ((*lck)->name) {
|
||||||
|
case RIFF_CASE ('l','t','x','t'):
|
||||||
|
ltxt = (riff_ltxt_t *) *ck;
|
||||||
|
dltxt = <xt->ltxt;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
if (!dfmt) {
|
||||||
sc = SND_GetCache (info.samples, info.rate, info.width, info.channels,
|
Sys_Printf ("missing format chunk\n");
|
||||||
sfx, allocator);
|
goto bail;
|
||||||
if (!sc)
|
}
|
||||||
return NULL;
|
if (!data) {
|
||||||
|
Sys_Printf ("missing data chunk\n");
|
||||||
sfx->loopstart = info.loopstart;
|
goto bail;
|
||||||
|
}
|
||||||
SND_ResampleSfx (sc, data + info.dataofs);
|
if (dltxt)
|
||||||
|
sample_count = dltxt->len;
|
||||||
return sc;
|
if (cp)
|
||||||
|
loop_start = cp->sample_offset;
|
||||||
|
bail:
|
||||||
|
Qclose (file);
|
||||||
|
riff_free (riff);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue