New sound system

This commit is contained in:
OM 2023-05-24 19:40:09 +02:00
parent 41fc217a06
commit ba0ed7504d
17 changed files with 5594 additions and 1596 deletions

View file

@ -0,0 +1,292 @@
#include "../snd_local.h"
/*
=================
S_IsSoundPlaying
=================
*/
int S_IsSoundPlaying(int channelNumber, const char* name)
{
// FIXME: stub
STUB();
}
/*
=================
MUSIC_Pause
=================
*/
void MUSIC_Pause()
{
// FIXME: stub
STUB();
}
/*
=================
MUSIC_Unpause
=================
*/
void MUSIC_Unpause()
{
// FIXME: stub
STUB();
}
/*
=================
MUSIC_LoadSoundtrackFile
=================
*/
qboolean MUSIC_LoadSoundtrackFile(const char* filename)
{
// FIXME: stub
STUB();
return qfalse;
}
/*
=================
MUSIC_SongValid
=================
*/
qboolean MUSIC_SongValid(const char* mood)
{
// FIXME: stub
STUB();
return qfalse;
}
/*
=================
MUSIC_Loaded
=================
*/
qboolean MUSIC_Loaded(void)
{
// FIXME: stub
STUB();
return qfalse;
}
/*
=================
Music_Update
=================
*/
void Music_Update(void)
{
// FIXME: stub
STUB();
}
/*
=================
MUSIC_SongEnded
=================
*/
void MUSIC_SongEnded(void)
{
// FIXME: stub
STUB();
}
/*
=================
S_StartSound
=================
*/
void MUSIC_NewSoundtrack(const char* name)
{
// FIXME: stub
STUB();
}
/*
=================
MUSIC_UpdateMood
=================
*/
void MUSIC_UpdateMood(int current, int fallback)
{
// FIXME: stub
//STUB();
}
/*
=================
MUSIC_UpdateVolume
=================
*/
void MUSIC_UpdateVolume(float volume, float fade_time)
{
// FIXME: stub
STUB();
}
/*
=================
MUSIC_StopAllSongs
=================
*/
void MUSIC_StopAllSongs(void)
{
// FIXME: stub
STUB();
}
/*
=================
MUSIC_FreeAllSongs
=================
*/
void MUSIC_FreeAllSongs(void)
{
// FIXME: stub
STUB();
}
/*
=================
MUSIC_Playing
=================
*/
qboolean MUSIC_Playing(void)
{
// FIXME: stub
STUB();
return qfalse;
}
/*
=================
MUSIC_FindSong
=================
*/
int MUSIC_FindSong(const char* name)
{
// FIXME: stub
STUB();
return 0;
}
/*
=================
MUSIC_CurrentSongChannel
=================
*/
int MUSIC_CurrentSongChannel(void)
{
// FIXME: stub
STUB();
return 0;
}
/*
=================
MUSIC_StopChannel
=================
*/
void MUSIC_StopChannel(int channel_number)
{
// FIXME: stub
STUB();
}
/*
=================
MUSIC_PlaySong
=================
*/
qboolean MUSIC_PlaySong(const char* alias)
{
// FIXME: stub
STUB();
return qfalse;
}
/*
=================
MUSIC_UpdateMusicVolumes
=================
*/
void MUSIC_UpdateMusicVolumes(void)
{
// FIXME: stub
STUB();
}
/*
=================
MUSIC_CheckForStoppedSongs
=================
*/
void MUSIC_CheckForStoppedSongs(void)
{
// FIXME: stub
STUB();
}
/*
=================
S_IsSoundRegistered
=================
*/
qboolean S_IsSoundRegistered(const char* name)
{
// FIXME: stub
return qfalse;
}
/*
=================
S_GetSoundTime
=================
*/
float S_GetSoundTime(sfxHandle_t handle)
{
// FIXME: stub
STUB();
return 0.0;
}
/*
=================
S_SetGlobalAmbientVolumeLevel
=================
*/
void S_SetGlobalAmbientVolumeLevel(float volume)
{
// FIXME: stub
STUB();
}
/*
=================
S_SetReverb
=================
*/
void S_SetReverb(int reverb_type, float reverb_level)
{
// FIXME: stub
STUB();
}
/*
=================
S_EndRegistration
=================
*/
void S_EndRegistration(void)
{
// FIXME: stub
}
void S_UpdateEntity(int entityNum, const vec3_t origin, const vec3_t velocity, qboolean use_listener)
{
// FIXME: stub
}
void S_FadeSound(float fTime)
{
// FIXME: stub
}

View file

@ -0,0 +1,40 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
// Music soundtrack
void MUSIC_Pause();
void MUSIC_Unpause();
qboolean MUSIC_LoadSoundtrackFile(const char* filename);
qboolean MUSIC_SongValid(const char* mood);
qboolean MUSIC_Loaded(void);
void Music_Update(void);
void MUSIC_SongEnded(void);
void MUSIC_NewSoundtrack(const char* name);
void MUSIC_UpdateMood(int current, int fallback);
void MUSIC_UpdateVolume(float volume, float fade_time);
void MUSIC_StopAllSongs(void);
void MUSIC_FreeAllSongs(void);
qboolean MUSIC_Playing(void);
int MUSIC_FindSong(const char* name);
int MUSIC_CurrentSongChannel(void);
void MUSIC_StopChannel(int channel_number);
qboolean MUSIC_PlaySong(const char* alias);
void MUSIC_UpdateMusicVolumes(void);
void MUSIC_CheckForStoppedSongs(void);
float S_GetSoundTime(sfxHandle_t handle);
void S_SetGlobalAmbientVolumeLevel(float volume);
void S_SetReverb(int reverb_type, float reverb_level);
int S_IsSoundPlaying(int channelNumber, const char* name);
void S_RespatializeOld(int entityNum, const vec3_t origin, vec3_t axis[3]);
void S_UpdateEntity(int entityNum, const vec3_t origin, const vec3_t velocity, qboolean use_listener);
void S_FadeSound(float fTime);
#ifdef __cplusplus
}
#endif

View file

@ -25,7 +25,7 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
/*
** Intel/DVI ADPCM coder/decoder.
**
** The algorithm for this coder was taken from the IMA Compatability Project
** The algorithm for this coder was taken from the IMA Compatibility Project
** proceedings, Vol 2, Number 2; May 1992.
**
** Version 1.2, 18-Dec-92.
@ -278,7 +278,7 @@ void S_AdpcmGetSamples(sndBuffer *chunk, short *to) {
out = (byte *)chunk->sndChunk;
// get samples
S_AdpcmDecode( out, to, SND_CHUNK_SIZE_BYTE*2, &state );
S_AdpcmDecode((char *) out, to, SND_CHUNK_SIZE_BYTE*2, &state );
}
@ -310,7 +310,7 @@ void S_AdpcmEncodeSound( sfx_t *sfx, short *samples ) {
newchunk = SND_malloc();
if (sfx->soundData == NULL) {
sfx->soundData = newchunk;
} else {
} else if (chunk != NULL) {
chunk->next = newchunk;
}
chunk = newchunk;
@ -322,7 +322,7 @@ void S_AdpcmEncodeSound( sfx_t *sfx, short *samples ) {
out = (byte *)chunk->sndChunk;
// encode the samples
S_AdpcmEncode( samples + inOffset, out, n, &state );
S_AdpcmEncode( samples + inOffset, (char *) out, n, &state );
inOffset += n;
count -= n;

229
code/client/snd_altivec.c Normal file
View file

@ -0,0 +1,229 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code 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.
Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
/* This file is only compiled for PowerPC builds with Altivec support.
Altivec intrinsics need to be in a separate file, so GCC's -maltivec
command line can enable them, but give us the option to _not_ use that
on other files, where the compiler might then generate Altivec
instructions for normal floating point, crashing on G3 (etc) processors. */
#include "client.h"
#include "snd_local.h"
#if idppc_altivec
#if !defined(__APPLE__)
#include <altivec.h>
#endif
void S_PaintChannelFrom16_altivec( portable_samplepair_t paintbuffer[PAINTBUFFER_SIZE], int snd_vol, channel_t *ch, const sfx_t *sc, int count, int sampleOffset, int bufferOffset ) {
int data, aoff, boff;
int leftvol, rightvol;
int i, j;
portable_samplepair_t *samp;
sndBuffer *chunk;
short *samples;
float ooff, fdata[2], fdiv, fleftvol, frightvol;
if (sc->soundChannels <= 0) {
return;
}
samp = &paintbuffer[ bufferOffset ];
if (ch->doppler) {
sampleOffset = sampleOffset*ch->oldDopplerScale;
}
if ( sc->soundChannels == 2 ) {
sampleOffset *= sc->soundChannels;
if ( sampleOffset & 1 ) {
sampleOffset &= ~1;
}
}
chunk = sc->soundData;
while (sampleOffset>=SND_CHUNK_SIZE) {
chunk = chunk->next;
sampleOffset -= SND_CHUNK_SIZE;
if (!chunk) {
chunk = sc->soundData;
}
}
if (!ch->doppler || ch->dopplerScale==1.0f) {
vector signed short volume_vec;
vector unsigned int volume_shift;
int vectorCount, samplesLeft, chunkSamplesLeft;
leftvol = ch->leftvol*snd_vol;
rightvol = ch->rightvol*snd_vol;
samples = chunk->sndChunk;
((short *)&volume_vec)[0] = leftvol;
((short *)&volume_vec)[1] = leftvol;
((short *)&volume_vec)[4] = leftvol;
((short *)&volume_vec)[5] = leftvol;
((short *)&volume_vec)[2] = rightvol;
((short *)&volume_vec)[3] = rightvol;
((short *)&volume_vec)[6] = rightvol;
((short *)&volume_vec)[7] = rightvol;
volume_shift = vec_splat_u32(8);
i = 0;
while(i < count) {
/* Try to align destination to 16-byte boundary */
while(i < count && (((unsigned long)&samp[i] & 0x1f) || ((count-i) < 8) || ((SND_CHUNK_SIZE - sampleOffset) < 8))) {
data = samples[sampleOffset++];
samp[i].left += (data * leftvol)>>8;
if ( sc->soundChannels == 2 ) {
data = samples[sampleOffset++];
}
samp[i].right += (data * rightvol)>>8;
if (sampleOffset == SND_CHUNK_SIZE) {
chunk = chunk->next;
samples = chunk->sndChunk;
sampleOffset = 0;
}
i++;
}
/* Destination is now aligned. Process as many 8-sample
chunks as we can before we run out of room from the current
sound chunk. We do 8 per loop to avoid extra source data reads. */
samplesLeft = count - i;
chunkSamplesLeft = SND_CHUNK_SIZE - sampleOffset;
if(samplesLeft > chunkSamplesLeft)
samplesLeft = chunkSamplesLeft;
vectorCount = samplesLeft / 8;
if(vectorCount)
{
vector unsigned char tmp;
vector short s0, s1, sampleData0, sampleData1;
vector signed int merge0, merge1;
vector signed int d0, d1, d2, d3;
vector unsigned char samplePermute0 =
VECCONST_UINT8(0, 1, 4, 5, 0, 1, 4, 5, 2, 3, 6, 7, 2, 3, 6, 7);
vector unsigned char samplePermute1 =
VECCONST_UINT8(8, 9, 12, 13, 8, 9, 12, 13, 10, 11, 14, 15, 10, 11, 14, 15);
vector unsigned char loadPermute0, loadPermute1;
// Rather than permute the vectors after we load them to do the sample
// replication and rearrangement, we permute the alignment vector so
// we do everything in one step below and avoid data shuffling.
tmp = vec_lvsl(0,&samples[sampleOffset]);
loadPermute0 = vec_perm(tmp,tmp,samplePermute0);
loadPermute1 = vec_perm(tmp,tmp,samplePermute1);
s0 = *(vector short *)&samples[sampleOffset];
while(vectorCount)
{
/* Load up source (16-bit) sample data */
s1 = *(vector short *)&samples[sampleOffset+7];
/* Load up destination sample data */
d0 = *(vector signed int *)&samp[i];
d1 = *(vector signed int *)&samp[i+2];
d2 = *(vector signed int *)&samp[i+4];
d3 = *(vector signed int *)&samp[i+6];
sampleData0 = vec_perm(s0,s1,loadPermute0);
sampleData1 = vec_perm(s0,s1,loadPermute1);
merge0 = vec_mule(sampleData0,volume_vec);
merge0 = vec_sra(merge0,volume_shift); /* Shift down to proper range */
merge1 = vec_mulo(sampleData0,volume_vec);
merge1 = vec_sra(merge1,volume_shift);
d0 = vec_add(merge0,d0);
d1 = vec_add(merge1,d1);
merge0 = vec_mule(sampleData1,volume_vec);
merge0 = vec_sra(merge0,volume_shift); /* Shift down to proper range */
merge1 = vec_mulo(sampleData1,volume_vec);
merge1 = vec_sra(merge1,volume_shift);
d2 = vec_add(merge0,d2);
d3 = vec_add(merge1,d3);
/* Store destination sample data */
*(vector signed int *)&samp[i] = d0;
*(vector signed int *)&samp[i+2] = d1;
*(vector signed int *)&samp[i+4] = d2;
*(vector signed int *)&samp[i+6] = d3;
i += 8;
vectorCount--;
s0 = s1;
sampleOffset += 8;
}
if (sampleOffset == SND_CHUNK_SIZE) {
chunk = chunk->next;
samples = chunk->sndChunk;
sampleOffset = 0;
}
}
}
} else {
fleftvol = ch->leftvol*snd_vol;
frightvol = ch->rightvol*snd_vol;
ooff = sampleOffset;
samples = chunk->sndChunk;
for ( i=0 ; i<count ; i++ ) {
aoff = ooff;
ooff = ooff + ch->dopplerScale * sc->soundChannels;
boff = ooff;
fdata[0] = fdata[1] = 0;
for (j=aoff; j<boff; j += sc->soundChannels) {
if (j == SND_CHUNK_SIZE) {
chunk = chunk->next;
if (!chunk) {
chunk = sc->soundData;
}
samples = chunk->sndChunk;
ooff -= SND_CHUNK_SIZE;
}
if ( sc->soundChannels == 2 ) {
fdata[0] += samples[j&(SND_CHUNK_SIZE-1)];
fdata[1] += samples[(j+1)&(SND_CHUNK_SIZE-1)];
} else {
fdata[0] += samples[j&(SND_CHUNK_SIZE-1)];
fdata[1] += samples[j&(SND_CHUNK_SIZE-1)];
}
}
fdiv = 256 * (boff-aoff) / sc->soundChannels;
samp[i].left += (fdata[0] * fleftvol)/fdiv;
samp[i].right += (fdata[1] * frightvol)/fdiv;
}
}
}
#endif

237
code/client/snd_codec.c Normal file
View file

@ -0,0 +1,237 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
Copyright (C) 2005 Stuart Dalton (badcdev@gmail.com)
This file is part of Quake III Arena source code.
Quake III Arena source code 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.
Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#include "client.h"
#include "snd_codec.h"
static snd_codec_t *codecs;
/*
=================
S_CodecGetSound
Opens/loads a sound, tries codec based on the sound's file extension
then tries all supported codecs.
=================
*/
static void *S_CodecGetSound(const char *filename, snd_info_t *info)
{
snd_codec_t *codec;
snd_codec_t *orgCodec = NULL;
qboolean orgNameFailed = qfalse;
char localName[ MAX_QPATH ];
const char *ext;
char altName[ MAX_QPATH ];
void *rtn = NULL;
Q_strncpyz(localName, filename, MAX_QPATH);
ext = COM_GetExtension(localName);
if( *ext )
{
// Look for the correct loader and use it
for( codec = codecs; codec; codec = codec->next )
{
if( !Q_stricmp( ext, codec->ext ) )
{
// Load
if( info )
rtn = codec->load(localName, info);
else
rtn = codec->open(localName);
break;
}
}
// A loader was found
if( codec )
{
if( !rtn )
{
// Loader failed, most likely because the file isn't there;
// try again without the extension
orgNameFailed = qtrue;
orgCodec = codec;
COM_StripExtension( filename, localName, MAX_QPATH );
}
else
{
// Something loaded
return rtn;
}
}
}
// Try and find a suitable match using all
// the sound codecs supported
for( codec = codecs; codec; codec = codec->next )
{
if( codec == orgCodec )
continue;
Com_sprintf( altName, sizeof (altName), "%s.%s", localName, codec->ext );
// Load
if( info )
rtn = codec->load(altName, info);
else
rtn = codec->open(altName);
if( rtn )
{
if( orgNameFailed )
{
Com_DPrintf(S_COLOR_YELLOW "WARNING: %s not present, using %s instead\n",
filename, altName );
}
return rtn;
}
}
Com_Printf(S_COLOR_YELLOW "WARNING: Failed to %s sound %s!\n", info ? "load" : "open", filename);
return NULL;
}
/*
=================
S_CodecInit
=================
*/
void S_CodecInit()
{
codecs = NULL;
#ifdef USE_CODEC_OPUS
S_CodecRegister(&opus_codec);
#endif
#ifdef USE_CODEC_VORBIS
S_CodecRegister(&ogg_codec);
#endif
// Register wav codec last so that it is always tried first when a file extension was not found
S_CodecRegister(&wav_codec);
}
/*
=================
S_CodecShutdown
=================
*/
void S_CodecShutdown()
{
codecs = NULL;
}
/*
=================
S_CodecRegister
=================
*/
void S_CodecRegister(snd_codec_t *codec)
{
codec->next = codecs;
codecs = codec;
}
/*
=================
S_CodecLoad
=================
*/
void *S_CodecLoad(const char *filename, snd_info_t *info)
{
return S_CodecGetSound(filename, info);
}
/*
=================
S_CodecOpenStream
=================
*/
snd_stream_t *S_CodecOpenStream(const char *filename)
{
return S_CodecGetSound(filename, NULL);
}
void S_CodecCloseStream(snd_stream_t *stream)
{
stream->codec->close(stream);
}
int S_CodecReadStream(snd_stream_t *stream, int bytes, void *buffer)
{
return stream->codec->read(stream, bytes, buffer);
}
//=======================================================================
// Util functions (used by codecs)
/*
=================
S_CodecUtilOpen
=================
*/
snd_stream_t *S_CodecUtilOpen(const char *filename, snd_codec_t *codec)
{
snd_stream_t *stream;
fileHandle_t hnd;
int length;
// Try to open the file
length = FS_FOpenFileRead(filename, &hnd, qtrue);
if(!hnd)
{
Com_DPrintf("Can't read sound file %s\n", filename);
return NULL;
}
// Allocate a stream
stream = Z_Malloc(sizeof(snd_stream_t));
if(!stream)
{
FS_FCloseFile(hnd);
return NULL;
}
// Copy over, return
stream->codec = codec;
stream->file = hnd;
stream->length = length;
return stream;
}
/*
=================
S_CodecUtilClose
=================
*/
void S_CodecUtilClose(snd_stream_t **stream)
{
FS_FCloseFile((*stream)->file);
Z_Free(*stream);
*stream = NULL;
}

107
code/client/snd_codec.h Normal file
View file

@ -0,0 +1,107 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
Copyright (C) 2005 Stuart Dalton (badcdev@gmail.com)
This file is part of Quake III Arena source code.
Quake III Arena source code 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.
Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#ifndef _SND_CODEC_H_
#define _SND_CODEC_H_
#include "../qcommon/q_shared.h"
#include "../qcommon/qcommon.h"
typedef struct snd_info_s
{
int rate;
int width;
int channels;
int samples;
int size;
int dataofs;
} snd_info_t;
typedef struct snd_codec_s snd_codec_t;
typedef struct snd_stream_s
{
snd_codec_t *codec;
fileHandle_t file;
snd_info_t info;
int length;
int pos;
void *ptr;
} snd_stream_t;
// Codec functions
typedef void *(*CODEC_LOAD)(const char *filename, snd_info_t *info);
typedef snd_stream_t *(*CODEC_OPEN)(const char *filename);
typedef int (*CODEC_READ)(snd_stream_t *stream, int bytes, void *buffer);
typedef void (*CODEC_CLOSE)(snd_stream_t *stream);
// Codec data structure
struct snd_codec_s
{
char *ext;
CODEC_LOAD load;
CODEC_OPEN open;
CODEC_READ read;
CODEC_CLOSE close;
snd_codec_t *next;
};
// Codec management
void S_CodecInit( void );
void S_CodecShutdown( void );
void S_CodecRegister(snd_codec_t *codec);
void *S_CodecLoad(const char *filename, snd_info_t *info);
snd_stream_t *S_CodecOpenStream(const char *filename);
void S_CodecCloseStream(snd_stream_t *stream);
int S_CodecReadStream(snd_stream_t *stream, int bytes, void *buffer);
// Util functions (used by codecs)
snd_stream_t *S_CodecUtilOpen(const char *filename, snd_codec_t *codec);
void S_CodecUtilClose(snd_stream_t **stream);
// WAV Codec
extern snd_codec_t wav_codec;
void *S_WAV_CodecLoad(const char *filename, snd_info_t *info);
snd_stream_t *S_WAV_CodecOpenStream(const char *filename);
void S_WAV_CodecCloseStream(snd_stream_t *stream);
int S_WAV_CodecReadStream(snd_stream_t *stream, int bytes, void *buffer);
// Ogg Vorbis codec
#ifdef USE_CODEC_VORBIS
extern snd_codec_t ogg_codec;
void *S_OGG_CodecLoad(const char *filename, snd_info_t *info);
snd_stream_t *S_OGG_CodecOpenStream(const char *filename);
void S_OGG_CodecCloseStream(snd_stream_t *stream);
int S_OGG_CodecReadStream(snd_stream_t *stream, int bytes, void *buffer);
#endif // USE_CODEC_VORBIS
// Ogg Opus codec
#ifdef USE_CODEC_OPUS
extern snd_codec_t opus_codec;
void *S_OggOpus_CodecLoad(const char *filename, snd_info_t *info);
snd_stream_t *S_OggOpus_CodecOpenStream(const char *filename);
void S_OggOpus_CodecCloseStream(snd_stream_t *stream);
int S_OggOpus_CodecReadStream(snd_stream_t *stream, int bytes, void *buffer);
#endif // USE_CODEC_OPUS
#endif // !_SND_CODEC_H_

475
code/client/snd_codec_ogg.c Normal file
View file

@ -0,0 +1,475 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
Copyright (C) 2005 Stuart Dalton (badcdev@gmail.com)
Copyright (C) 2005-2006 Joerg Dietrich <dietrich_joerg@gmx.de>
This file is part of Quake III Arena source code.
Quake III Arena source code 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.
Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// OGG support is enabled by this define
#ifdef USE_CODEC_VORBIS
// includes for the Q3 sound system
#include "client.h"
#include "snd_codec.h"
// includes for the OGG codec
#include <errno.h>
#define OV_EXCLUDE_STATIC_CALLBACKS
#include <vorbis/vorbisfile.h>
// The OGG codec can return the samples in a number of different formats,
// we use the standard signed short format.
#define OGG_SAMPLEWIDTH 2
// Q3 OGG codec
snd_codec_t ogg_codec =
{
"ogg",
S_OGG_CodecLoad,
S_OGG_CodecOpenStream,
S_OGG_CodecReadStream,
S_OGG_CodecCloseStream,
NULL
};
// callbacks for vobisfile
// fread() replacement
size_t S_OGG_Callback_read(void *ptr, size_t size, size_t nmemb, void *datasource)
{
snd_stream_t *stream;
int byteSize = 0;
int bytesRead = 0;
size_t nMembRead = 0;
// check if input is valid
if(!ptr)
{
errno = EFAULT;
return 0;
}
if(!(size && nmemb))
{
// It's not an error, caller just wants zero bytes!
errno = 0;
return 0;
}
if(!datasource)
{
errno = EBADF;
return 0;
}
// we use a snd_stream_t in the generic pointer to pass around
stream = (snd_stream_t *) datasource;
// FS_Read does not support multi-byte elements
byteSize = nmemb * size;
// read it with the Q3 function FS_Read()
bytesRead = FS_Read(ptr, byteSize, stream->file);
// update the file position
stream->pos += bytesRead;
// this function returns the number of elements read not the number of bytes
nMembRead = bytesRead / size;
// even if the last member is only read partially
// it is counted as a whole in the return value
if(bytesRead % size)
{
nMembRead++;
}
return nMembRead;
}
// fseek() replacement
int S_OGG_Callback_seek(void *datasource, ogg_int64_t offset, int whence)
{
snd_stream_t *stream;
int retVal = 0;
// check if input is valid
if(!datasource)
{
errno = EBADF;
return -1;
}
// snd_stream_t in the generic pointer
stream = (snd_stream_t *) datasource;
// we must map the whence to its Q3 counterpart
switch(whence)
{
case SEEK_SET :
{
// set the file position in the actual file with the Q3 function
retVal = FS_Seek(stream->file, (long) offset, FS_SEEK_SET);
// something has gone wrong, so we return here
if(retVal < 0)
{
return retVal;
}
// keep track of file position
stream->pos = (int) offset;
break;
}
case SEEK_CUR :
{
// set the file position in the actual file with the Q3 function
retVal = FS_Seek(stream->file, (long) offset, FS_SEEK_CUR);
// something has gone wrong, so we return here
if(retVal < 0)
{
return retVal;
}
// keep track of file position
stream->pos += (int) offset;
break;
}
case SEEK_END :
{
// set the file position in the actual file with the Q3 function
retVal = FS_Seek(stream->file, (long) offset, FS_SEEK_END);
// something has gone wrong, so we return here
if(retVal < 0)
{
return retVal;
}
// keep track of file position
stream->pos = stream->length + (int) offset;
break;
}
default :
{
// unknown whence, so we return an error
errno = EINVAL;
return -1;
}
}
// stream->pos shouldn't be smaller than zero or bigger than the filesize
stream->pos = (stream->pos < 0) ? 0 : stream->pos;
stream->pos = (stream->pos > stream->length) ? stream->length : stream->pos;
return 0;
}
// fclose() replacement
int S_OGG_Callback_close(void *datasource)
{
// we do nothing here and close all things manually in S_OGG_CodecCloseStream()
return 0;
}
// ftell() replacement
long S_OGG_Callback_tell(void *datasource)
{
snd_stream_t *stream;
// check if input is valid
if(!datasource)
{
errno = EBADF;
return -1;
}
// snd_stream_t in the generic pointer
stream = (snd_stream_t *) datasource;
return (long) FS_FTell(stream->file);
}
// the callback structure
const ov_callbacks S_OGG_Callbacks =
{
&S_OGG_Callback_read,
&S_OGG_Callback_seek,
&S_OGG_Callback_close,
&S_OGG_Callback_tell
};
/*
=================
S_OGG_CodecOpenStream
=================
*/
snd_stream_t *S_OGG_CodecOpenStream(const char *filename)
{
snd_stream_t *stream;
// OGG codec control structure
OggVorbis_File *vf;
// some variables used to get informations about the OGG
vorbis_info *OGGInfo;
ogg_int64_t numSamples;
// check if input is valid
if(!filename)
{
return NULL;
}
// Open the stream
stream = S_CodecUtilOpen(filename, &ogg_codec);
if(!stream)
{
return NULL;
}
// alloctate the OggVorbis_File
vf = Z_Malloc(sizeof(OggVorbis_File));
if(!vf)
{
S_CodecUtilClose(&stream);
return NULL;
}
// open the codec with our callbacks and stream as the generic pointer
if(ov_open_callbacks(stream, vf, NULL, 0, S_OGG_Callbacks) != 0)
{
Z_Free(vf);
S_CodecUtilClose(&stream);
return NULL;
}
// the stream must be seekable
if(!ov_seekable(vf))
{
ov_clear(vf);
Z_Free(vf);
S_CodecUtilClose(&stream);
return NULL;
}
// we only support OGGs with one substream
if(ov_streams(vf) != 1)
{
ov_clear(vf);
Z_Free(vf);
S_CodecUtilClose(&stream);
return NULL;
}
// get the info about channels and rate
OGGInfo = ov_info(vf, 0);
if(!OGGInfo)
{
ov_clear(vf);
Z_Free(vf);
S_CodecUtilClose(&stream);
return NULL;
}
// get the number of sample-frames in the OGG
numSamples = ov_pcm_total(vf, 0);
// fill in the info-structure in the stream
stream->info.rate = OGGInfo->rate;
stream->info.width = OGG_SAMPLEWIDTH;
stream->info.channels = OGGInfo->channels;
stream->info.samples = numSamples;
stream->info.size = stream->info.samples * stream->info.channels * stream->info.width;
stream->info.dataofs = 0;
// We use stream->pos for the file pointer in the compressed ogg file
stream->pos = 0;
// We use the generic pointer in stream for the OGG codec control structure
stream->ptr = vf;
return stream;
}
/*
=================
S_OGG_CodecCloseStream
=================
*/
void S_OGG_CodecCloseStream(snd_stream_t *stream)
{
// check if input is valid
if(!stream)
{
return;
}
// let the OGG codec cleanup its stuff
ov_clear((OggVorbis_File *) stream->ptr);
// free the OGG codec control struct
Z_Free(stream->ptr);
// close the stream
S_CodecUtilClose(&stream);
}
/*
=================
S_OGG_CodecReadStream
=================
*/
int S_OGG_CodecReadStream(snd_stream_t *stream, int bytes, void *buffer)
{
// buffer handling
int bytesRead, bytesLeft, c;
char *bufPtr;
// Bitstream for the decoder
int BS = 0;
// big endian machines want their samples in big endian order
int IsBigEndian = 0;
# ifdef Q3_BIG_ENDIAN
IsBigEndian = 1;
# endif // Q3_BIG_ENDIAN
// check if input is valid
if(!(stream && buffer))
{
return 0;
}
if(bytes <= 0)
{
return 0;
}
bytesRead = 0;
bytesLeft = bytes;
bufPtr = buffer;
// cycle until we have the requested or all available bytes read
while(-1)
{
// read some bytes from the OGG codec
c = ov_read((OggVorbis_File *) stream->ptr, bufPtr, bytesLeft, IsBigEndian, OGG_SAMPLEWIDTH, 1, &BS);
// no more bytes are left
if(c <= 0)
{
break;
}
bytesRead += c;
bytesLeft -= c;
bufPtr += c;
// we have enough bytes
if(bytesLeft <= 0)
{
break;
}
}
return bytesRead;
}
/*
=====================================================================
S_OGG_CodecLoad
We handle S_OGG_CodecLoad as a special case of the streaming functions
where we read the whole stream at once.
======================================================================
*/
void *S_OGG_CodecLoad(const char *filename, snd_info_t *info)
{
snd_stream_t *stream;
byte *buffer;
int bytesRead;
// check if input is valid
if(!(filename && info))
{
return NULL;
}
// open the file as a stream
stream = S_OGG_CodecOpenStream(filename);
if(!stream)
{
return NULL;
}
// copy over the info
info->rate = stream->info.rate;
info->width = stream->info.width;
info->channels = stream->info.channels;
info->samples = stream->info.samples;
info->size = stream->info.size;
info->dataofs = stream->info.dataofs;
// allocate a buffer
// this buffer must be free-ed by the caller of this function
buffer = Hunk_AllocateTempMemory(info->size);
if(!buffer)
{
S_OGG_CodecCloseStream(stream);
return NULL;
}
// fill the buffer
bytesRead = S_OGG_CodecReadStream(stream, info->size, buffer);
// we don't even have read a single byte
if(bytesRead <= 0)
{
Hunk_FreeTempMemory(buffer);
S_OGG_CodecCloseStream(stream);
return NULL;
}
S_OGG_CodecCloseStream(stream);
return buffer;
}
#endif // USE_CODEC_VORBIS

View file

@ -0,0 +1,449 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
Copyright (C) 2005 Stuart Dalton (badcdev@gmail.com)
Copyright (C) 2005-2006 Joerg Dietrich <dietrich_joerg@gmx.de>
This file is part of Quake III Arena source code.
Quake III Arena source code 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.
Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// Ogg Opus support is enabled by this define
#ifdef USE_CODEC_OPUS
// includes for the Q3 sound system
#include "client.h"
#include "snd_codec.h"
// includes for the Ogg Opus codec
#include <errno.h>
#include <opusfile.h>
// samples are 16 bit
#define OPUS_SAMPLEWIDTH 2
// Q3 Ogg Opus codec
snd_codec_t opus_codec =
{
"opus",
S_OggOpus_CodecLoad,
S_OggOpus_CodecOpenStream,
S_OggOpus_CodecReadStream,
S_OggOpus_CodecCloseStream,
NULL
};
// callbacks for opusfile
// fread() replacement
int S_OggOpus_Callback_read(void *datasource, unsigned char *ptr, int size )
{
snd_stream_t *stream;
int bytesRead = 0;
// check if input is valid
if(!ptr)
{
errno = EFAULT;
return -1;
}
if(!size)
{
// It's not an error, caller just wants zero bytes!
errno = 0;
return 0;
}
if (size < 0)
{
errno = EINVAL;
return -1;
}
if(!datasource)
{
errno = EBADF;
return -1;
}
// we use a snd_stream_t in the generic pointer to pass around
stream = (snd_stream_t *) datasource;
// read it with the Q3 function FS_Read()
bytesRead = FS_Read(ptr, size, stream->file);
// update the file position
stream->pos += bytesRead;
return bytesRead;
}
// fseek() replacement
int S_OggOpus_Callback_seek(void *datasource, opus_int64 offset, int whence)
{
snd_stream_t *stream;
int retVal = 0;
// check if input is valid
if(!datasource)
{
errno = EBADF;
return -1;
}
// snd_stream_t in the generic pointer
stream = (snd_stream_t *) datasource;
// we must map the whence to its Q3 counterpart
switch(whence)
{
case SEEK_SET :
{
// set the file position in the actual file with the Q3 function
retVal = FS_Seek(stream->file, (long) offset, FS_SEEK_SET);
// something has gone wrong, so we return here
if(retVal < 0)
{
return retVal;
}
// keep track of file position
stream->pos = (int) offset;
break;
}
case SEEK_CUR :
{
// set the file position in the actual file with the Q3 function
retVal = FS_Seek(stream->file, (long) offset, FS_SEEK_CUR);
// something has gone wrong, so we return here
if(retVal < 0)
{
return retVal;
}
// keep track of file position
stream->pos += (int) offset;
break;
}
case SEEK_END :
{
// set the file position in the actual file with the Q3 function
retVal = FS_Seek(stream->file, (long) offset, FS_SEEK_END);
// something has gone wrong, so we return here
if(retVal < 0)
{
return retVal;
}
// keep track of file position
stream->pos = stream->length + (int) offset;
break;
}
default :
{
// unknown whence, so we return an error
errno = EINVAL;
return -1;
}
}
// stream->pos shouldn't be smaller than zero or bigger than the filesize
stream->pos = (stream->pos < 0) ? 0 : stream->pos;
stream->pos = (stream->pos > stream->length) ? stream->length : stream->pos;
return 0;
}
// fclose() replacement
int S_OggOpus_Callback_close(void *datasource)
{
// we do nothing here and close all things manually in S_OggOpus_CodecCloseStream()
return 0;
}
// ftell() replacement
opus_int64 S_OggOpus_Callback_tell(void *datasource)
{
snd_stream_t *stream;
// check if input is valid
if(!datasource)
{
errno = EBADF;
return -1;
}
// snd_stream_t in the generic pointer
stream = (snd_stream_t *) datasource;
return (opus_int64) FS_FTell(stream->file);
}
// the callback structure
const OpusFileCallbacks S_OggOpus_Callbacks =
{
&S_OggOpus_Callback_read,
&S_OggOpus_Callback_seek,
&S_OggOpus_Callback_tell,
&S_OggOpus_Callback_close
};
/*
=================
S_OggOpus_CodecOpenStream
=================
*/
snd_stream_t *S_OggOpus_CodecOpenStream(const char *filename)
{
snd_stream_t *stream;
// Opus codec control structure
OggOpusFile *of;
// some variables used to get informations about the file
const OpusHead *opusInfo;
ogg_int64_t numSamples;
// check if input is valid
if(!filename)
{
return NULL;
}
// Open the stream
stream = S_CodecUtilOpen(filename, &opus_codec);
if(!stream)
{
return NULL;
}
// open the codec with our callbacks and stream as the generic pointer
of = op_open_callbacks(stream, &S_OggOpus_Callbacks, NULL, 0, NULL );
if (!of)
{
S_CodecUtilClose(&stream);
return NULL;
}
// the stream must be seekable
if(!op_seekable(of))
{
op_free(of);
S_CodecUtilClose(&stream);
return NULL;
}
// get the info about channels and rate
opusInfo = op_head(of, -1);
if(!opusInfo)
{
op_free(of);
S_CodecUtilClose(&stream);
return NULL;
}
if(opusInfo->stream_count != 1)
{
op_free(of);
S_CodecUtilClose(&stream);
Com_Printf("Only Ogg Opus files with one stream are support\n");
return NULL;
}
if(opusInfo->channel_count != 1 && opusInfo->channel_count != 2)
{
op_free(of);
S_CodecUtilClose(&stream);
Com_Printf("Only mono and stereo Ogg Opus files are supported\n");
return NULL;
}
// get the number of sample-frames in the file
numSamples = op_pcm_total(of, -1);
// fill in the info-structure in the stream
stream->info.rate = 48000;
stream->info.width = OPUS_SAMPLEWIDTH;
stream->info.channels = opusInfo->channel_count;
stream->info.samples = numSamples;
stream->info.size = stream->info.samples * stream->info.channels * stream->info.width;
stream->info.dataofs = 0;
// We use stream->pos for the file pointer in the compressed ogg file
stream->pos = 0;
// We use the generic pointer in stream for the opus codec control structure
stream->ptr = of;
return stream;
}
/*
=================
S_OggOpus_CodecCloseStream
=================
*/
void S_OggOpus_CodecCloseStream(snd_stream_t *stream)
{
// check if input is valid
if(!stream)
{
return;
}
// let the opus codec cleanup its stuff
op_free((OggOpusFile *) stream->ptr);
// close the stream
S_CodecUtilClose(&stream);
}
/*
=================
S_OggOpus_CodecReadStream
=================
*/
int S_OggOpus_CodecReadStream(snd_stream_t *stream, int bytes, void *buffer)
{
// buffer handling
int samplesRead, samplesLeft, c;
opus_int16 *bufPtr;
// check if input is valid
if(!(stream && buffer))
{
return 0;
}
if(bytes <= 0)
{
return 0;
}
samplesRead = 0;
samplesLeft = bytes / stream->info.channels / stream->info.width;
bufPtr = buffer;
if(samplesLeft <= 0)
{
return 0;
}
// cycle until we have the requested or all available bytes read
while(-1)
{
// read some samples from the opus codec
c = op_read((OggOpusFile *) stream->ptr, bufPtr + samplesRead * stream->info.channels, samplesLeft * stream->info.channels, NULL);
// no more samples are left
if(c <= 0)
{
break;
}
samplesRead += c;
samplesLeft -= c;
// we have enough samples
if(samplesLeft <= 0)
{
break;
}
}
return samplesRead * stream->info.channels * stream->info.width;
}
/*
=====================================================================
S_OggOpus_CodecLoad
We handle S_OggOpus_CodecLoad as a special case of the streaming functions
where we read the whole stream at once.
======================================================================
*/
void *S_OggOpus_CodecLoad(const char *filename, snd_info_t *info)
{
snd_stream_t *stream;
byte *buffer;
int bytesRead;
// check if input is valid
if(!(filename && info))
{
return NULL;
}
// open the file as a stream
stream = S_OggOpus_CodecOpenStream(filename);
if(!stream)
{
return NULL;
}
// copy over the info
info->rate = stream->info.rate;
info->width = stream->info.width;
info->channels = stream->info.channels;
info->samples = stream->info.samples;
info->size = stream->info.size;
info->dataofs = stream->info.dataofs;
// allocate a buffer
// this buffer must be free-ed by the caller of this function
buffer = Hunk_AllocateTempMemory(info->size);
if(!buffer)
{
S_OggOpus_CodecCloseStream(stream);
return NULL;
}
// fill the buffer
bytesRead = S_OggOpus_CodecReadStream(stream, info->size, buffer);
// we don't even have read a single byte
if(bytesRead <= 0)
{
Hunk_FreeTempMemory(buffer);
S_OggOpus_CodecCloseStream(stream);
return NULL;
}
S_OggOpus_CodecCloseStream(stream);
return buffer;
}
#endif // USE_CODEC_OPUS

291
code/client/snd_codec_wav.c Normal file
View file

@ -0,0 +1,291 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
Copyright (C) 2005 Stuart Dalton (badcdev@gmail.com)
This file is part of Quake III Arena source code.
Quake III Arena source code 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.
Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#include "client.h"
#include "snd_codec.h"
/*
=================
FGetLittleLong
=================
*/
static int FGetLittleLong( fileHandle_t f ) {
int v;
FS_Read( &v, sizeof(v), f );
return LittleLong( v);
}
/*
=================
FGetLittleShort
=================
*/
static short FGetLittleShort( fileHandle_t f ) {
short v;
FS_Read( &v, sizeof(v), f );
return LittleShort( v);
}
/*
=================
S_ReadChunkInfo
=================
*/
static int S_ReadChunkInfo(fileHandle_t f, char *name)
{
int len, r;
name[4] = 0;
r = FS_Read(name, 4, f);
if(r != 4)
return -1;
len = FGetLittleLong(f);
if( len < 0 ) {
Com_Printf( S_COLOR_YELLOW "WARNING: Negative chunk length\n" );
return -1;
}
return len;
}
/*
=================
S_FindRIFFChunk
Returns the length of the data in the chunk, or -1 if not found
=================
*/
static int S_FindRIFFChunk( fileHandle_t f, char *chunk ) {
char name[5];
int len;
while( ( len = S_ReadChunkInfo(f, name) ) >= 0 )
{
// If this is the right chunk, return
if( !Q_strncmp( name, chunk, 4 ) )
return len;
len = PAD( len, 2 );
// Not the right chunk - skip it
FS_Seek( f, len, FS_SEEK_CUR );
}
return -1;
}
/*
=================
S_ByteSwapRawSamples
=================
*/
static void S_ByteSwapRawSamples( int samples, int width, int s_channels, const byte *data ) {
int i;
if ( width != 2 ) {
return;
}
if ( LittleShort( 256 ) == 256 ) {
return;
}
if ( s_channels == 2 ) {
samples <<= 1;
}
for ( i = 0 ; i < samples ; i++ ) {
((short *)data)[i] = LittleShort( ((short *)data)[i] );
}
}
/*
=================
S_ReadRIFFHeader
=================
*/
static qboolean S_ReadRIFFHeader(fileHandle_t file, snd_info_t *info)
{
char dump[16];
int bits;
int fmtlen = 0;
// skip the riff wav header
FS_Read(dump, 12, file);
// Scan for the format chunk
if((fmtlen = S_FindRIFFChunk(file, "fmt ")) < 0)
{
Com_Printf( S_COLOR_RED "ERROR: Couldn't find \"fmt\" chunk\n");
return qfalse;
}
// Save the parameters
FGetLittleShort(file); // wav_format
info->channels = FGetLittleShort(file);
info->rate = FGetLittleLong(file);
FGetLittleLong(file);
FGetLittleShort(file);
bits = FGetLittleShort(file);
if( bits < 8 )
{
Com_Printf( S_COLOR_RED "ERROR: Less than 8 bit sound is not supported\n");
return qfalse;
}
info->width = bits / 8;
info->dataofs = 0;
// Skip the rest of the format chunk if required
if(fmtlen > 16)
{
fmtlen -= 16;
FS_Seek( file, fmtlen, FS_SEEK_CUR );
}
// Scan for the data chunk
if( (info->size = S_FindRIFFChunk(file, "data")) < 0)
{
Com_Printf( S_COLOR_RED "ERROR: Couldn't find \"data\" chunk\n");
return qfalse;
}
info->samples = (info->size / info->width) / info->channels;
return qtrue;
}
// WAV codec
snd_codec_t wav_codec =
{
"wav",
S_WAV_CodecLoad,
S_WAV_CodecOpenStream,
S_WAV_CodecReadStream,
S_WAV_CodecCloseStream,
NULL
};
/*
=================
S_WAV_CodecLoad
=================
*/
void *S_WAV_CodecLoad(const char *filename, snd_info_t *info)
{
fileHandle_t file;
void *buffer;
// Try to open the file
FS_FOpenFileRead(filename, &file, qtrue);
if(!file)
{
return NULL;
}
// Read the RIFF header
if(!S_ReadRIFFHeader(file, info))
{
FS_FCloseFile(file);
Com_Printf( S_COLOR_RED "ERROR: Incorrect/unsupported format in \"%s\"\n",
filename);
return NULL;
}
// Allocate some memory
buffer = Hunk_AllocateTempMemory(info->size);
if(!buffer)
{
FS_FCloseFile(file);
Com_Printf( S_COLOR_RED "ERROR: Out of memory reading \"%s\"\n",
filename);
return NULL;
}
// Read, byteswap
FS_Read(buffer, info->size, file);
S_ByteSwapRawSamples(info->samples, info->width, info->channels, (byte *)buffer);
// Close and return
FS_FCloseFile(file);
return buffer;
}
/*
=================
S_WAV_CodecOpenStream
=================
*/
snd_stream_t *S_WAV_CodecOpenStream(const char *filename)
{
snd_stream_t *rv;
// Open
rv = S_CodecUtilOpen(filename, &wav_codec);
if(!rv)
return NULL;
// Read the RIFF header
if(!S_ReadRIFFHeader(rv->file, &rv->info))
{
S_CodecUtilClose(&rv);
return NULL;
}
return rv;
}
/*
=================
S_WAV_CodecCloseStream
=================
*/
void S_WAV_CodecCloseStream(snd_stream_t *stream)
{
S_CodecUtilClose(&stream);
}
/*
=================
S_WAV_CodecReadStream
=================
*/
int S_WAV_CodecReadStream(snd_stream_t *stream, int bytes, void *buffer)
{
int remaining = stream->info.size - stream->pos;
int samples;
if(remaining <= 0)
return 0;
if(bytes > remaining)
bytes = remaining;
stream->pos += bytes;
samples = (bytes / stream->info.width) / stream->info.channels;
FS_Read(buffer, bytes, stream->file);
S_ByteSwapRawSamples(samples, stream->info.width, stream->info.channels, buffer);
return bytes;
}

File diff suppressed because it is too large Load diff

View file

@ -15,21 +15,17 @@ 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 Foobar; if not, write to the Free Software
along with Quake III Arena source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// snd_local.h -- private sound definations
#include "q_shared.h"
#include "../qcommon/q_shared.h"
#include "../qcommon/qcommon.h"
#include "snd_public.h"
#ifdef __cplusplus
extern "C" {
#endif
#define PAINTBUFFER_SIZE 4096 // this is in samples
#define SND_CHUNK_SIZE 1024 // samples
@ -60,6 +56,7 @@ typedef struct sfx_s {
qboolean soundCompressed; // not in Memory
int soundCompressionMethod;
int soundLength;
int soundChannels;
char soundName[MAX_QPATH];
int lastTimeUsed;
struct sfx_s *next;
@ -68,14 +65,20 @@ typedef struct sfx_s {
typedef struct {
int channels;
int samples; // mono samples in buffer
int fullsamples; // samples with all channels in buffer (samples divided by channels)
int submission_chunk; // don't mix less than this #
int samplebits;
int isfloat;
int speed;
byte *buffer;
} dma_t;
#define START_SAMPLE_IMMEDIATE 0x7fffffff
#define MAX_DOPPLER_SCALE 50.0f //arbitrary
#define THIRD_PERSON_THRESHOLD_SQ (48.0f*48.0f)
typedef struct loopSound_s {
vec3_t origin;
vec3_t velocity;
@ -104,6 +107,7 @@ typedef struct
qboolean fixed_origin; // use origin instead of fetching entnum's origin
sfx_t *thesfx; // sfx structure
qboolean doppler;
qboolean fullVolume;
} channel_t;
@ -119,6 +123,38 @@ typedef struct {
int dataofs; // chunk starts this many bytes from file start
} wavinfo_t;
// Interface between Q3 sound "api" and the sound backend
typedef struct
{
void (*Shutdown)(void);
void (*StartSound)( vec3_t origin, int entnum, int entchannel, sfxHandle_t sfx );
void (*StartLocalSound)( sfxHandle_t sfx, int channelNum );
void (*StartBackgroundTrack)( const char *intro, const char *loop );
void (*StopBackgroundTrack)( void );
void (*RawSamples)(int stream, int samples, int rate, int width, int channels, const byte *data, float volume, int entityNum);
void (*StopAllSounds)( void );
void (*ClearLoopingSounds)( qboolean killall );
void (*AddLoopingSound)( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx );
void (*AddRealLoopingSound)( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx );
void (*StopLoopingSound)(int entityNum );
void (*Respatialize)( int entityNum, const vec3_t origin, vec3_t axis[3], int inwater );
void (*UpdateEntityPosition)( int entityNum, const vec3_t origin );
void (*Update)( void );
void (*DisableSounds)( void );
void (*BeginRegistration)( void );
sfxHandle_t (*RegisterSound)( const char *sample, qboolean compressed );
void (*ClearSoundBuffer)( void );
void (*SoundInfo)( void );
void (*SoundList)( void );
#ifdef USE_VOIP
void (*StartCapture)( void );
int (*AvailableCaptureSamples)( void );
void (*Capture)( int samples, byte *data );
void (*StopCapture)( void );
void (*MasterGain)( float gain );
#endif
} soundInterface_t;
/*
====================================================================
@ -141,6 +177,15 @@ void SNDDMA_BeginPainting (void);
void SNDDMA_Submit(void);
#ifdef USE_VOIP
void SNDDMA_StartCapture(void);
int SNDDMA_AvailableCaptureSamples(void);
void SNDDMA_Capture(int samples, byte *data);
void SNDDMA_StopCapture(void);
void SNDDMA_MasterGain(float val);
#endif
//====================================================================
#define MAX_CHANNELS 96
@ -150,34 +195,33 @@ extern channel_t loop_channels[MAX_CHANNELS];
extern int numLoopChannels;
extern int s_paintedtime;
extern int s_rawend;
extern vec3_t listener_forward;
extern vec3_t listener_right;
extern vec3_t listener_up;
extern dma_t dma;
#define MAX_RAW_SAMPLES 16384
extern portable_samplepair_t s_rawsamples[MAX_RAW_SAMPLES];
#define MAX_RAW_STREAMS (MAX_CLIENTS * 2 + 1)
extern portable_samplepair_t s_rawsamples[MAX_RAW_STREAMS][MAX_RAW_SAMPLES];
extern int s_rawend[MAX_RAW_STREAMS];
extern cvar_t *s_volume;
extern cvar_t *s_nosound;
extern cvar_t *s_khz;
extern cvar_t *s_show;
extern cvar_t *s_mixahead;
extern cvar_t *s_volume;
extern cvar_t *s_musicVolume;
extern cvar_t *s_muted;
extern cvar_t *s_doppler;
extern cvar_t *s_testsound;
extern cvar_t *s_separation;
extern cvar_t *s_testsound;
qboolean S_LoadSound( sfx_t *sfx );
void SND_free(sndBuffer *v);
sndBuffer* SND_malloc();
void SND_setup();
sndBuffer* SND_malloc( void );
void SND_setup( void );
void SND_shutdown(void);
void S_PaintChannels(int endtime);
void S_memoryLoad(sfx_t *sfx);
portable_samplepair_t *S_GetRawSamplePointer();
// spatializes a channel
void S_Spatialize(channel_t *ch);
@ -192,7 +236,7 @@ void S_AdpcmGetSamples(sndBuffer *chunk, short *to);
#define SENTINEL_MULAW_ZERO_RUN 127
#define SENTINEL_MULAW_FOUR_BIT_RUN 126
void S_FreeOldestSound();
void S_FreeOldestSound( void );
#define NXStream byte
@ -206,14 +250,22 @@ extern short *sfxScratchBuffer;
extern sfx_t *sfxScratchPointer;
extern int sfxScratchIndex;
#ifdef __linux__
// https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=371
// custom Snd_Memset implementation for glibc memset bug workaround
void Snd_Memset(void* dest, const int val, const size_t count);
#else
#define Snd_Memset Com_Memset
#endif
qboolean S_Base_Init( soundInterface_t *si );
#ifdef __cplusplus
}
// OpenAL stuff
typedef enum
{
SRCPRI_AMBIENT = 0, // Ambient sound effects
SRCPRI_ENTITY, // Entity sound effects
SRCPRI_ONESHOT, // One-shot sounds
SRCPRI_LOCAL, // Local sounds
SRCPRI_STREAM // Streams (music, cutscenes)
} alSrcPriority_t;
typedef int srcHandle_t;
qboolean S_AL_Init( soundInterface_t *si );
#ifdef idppc_altivec
void S_PaintChannelFrom16_altivec( portable_samplepair_t paintbuffer[PAINTBUFFER_SIZE], int snd_vol, channel_t *ch, const sfx_t *sc, int count, int sampleOffset, int bufferOffset );
#endif

View file

@ -22,19 +22,18 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "client.h"
#include "snd_codec.h"
#include "snd_local.h"
#include "snd_public.h"
cvar_t *s_volume;
cvar_t *s_muted;
cvar_t *s_musicVolume;
cvar_t *s_doppler;
cvar_t *s_backend;
cvar_t *s_muteWhenMinimized;
cvar_t *s_muteWhenUnfocused;
#if 0
cvar_t* s_volume;
cvar_t* s_musicVolume;
cvar_t* s_doppler;
static soundInterface_t si;
/*
@ -81,23 +80,13 @@ static qboolean S_ValidSoundInterface( soundInterface_t *si )
S_StartSound
=================
*/
void S_StartSound(const vec3_t origin, int entNum, int entChannel, sfxHandle_t sfxHandle, float volume, float minDist, float pitch, float maxDist, int streamed)
void S_StartSound( vec3_t origin, int entnum, int entchannel, sfxHandle_t sfx )
{
if( si.StartSound ) {
si.StartSound( origin, entNum, entChannel, sfxHandle);
si.StartSound( origin, entnum, entchannel, sfx );
}
}
/*
=================
S_StopSound
=================
*/
void S_StopSound(int entnum, int channel)
{
// FIXME: unimplemented
}
/*
=================
S_StartLocalSound
@ -110,16 +99,6 @@ void S_StartLocalSound( sfxHandle_t sfx, int channelNum )
}
}
/*
=================
S_StartLocalSound
=================
*/
void S_StartLocalSoundByName(const char* sound_name, qboolean force_load)
{
// FIXME: unimplemented
}
/*
=================
S_StartBackgroundTrack
@ -161,23 +140,11 @@ void S_RawSamples (int stream, int samples, int rate, int width, int channels,
S_StopAllSounds
=================
*/
void S_StopAllSounds( qboolean stop_music )
void S_StopAllSounds( void )
{
if( si.StopAllSounds ) {
si.StopAllSounds( );
}
// FIXME: stop music
}
/*
=================
S_ClearLoopingSoundsNoParam
=================
*/
void S_ClearLoopingSoundsNoParam(void)
{
S_ClearLoopingSounds(qtrue);
}
/*
@ -197,15 +164,12 @@ void S_ClearLoopingSounds( qboolean killall )
S_AddLoopingSound
=================
*/
void S_AddLoopingSound(const vec3_t origin, const vec3_t velocity, sfxHandle_t sfxHandle, float volume, float minDist, float maxDist, float pitch, int flags)
void S_AddLoopingSound( int entityNum, const vec3_t origin,
const vec3_t velocity, sfxHandle_t sfx )
{
/*
if( si.AddLoopingSound ) {
si.AddLoopingSound( entityNum, origin, velocity, sfx );
}
*/
// FIXME: unimplemented
}
/*
@ -238,27 +202,14 @@ void S_StopLoopingSound( int entityNum )
S_Respatialize
=================
*/
void S_Respatialize(int entityNum, const vec3_t origin,
vec3_t axis[3], int inwater)
void S_Respatialize( int entityNum, const vec3_t origin,
vec3_t axis[3], int inwater )
{
if( si.Respatialize ) {
si.Respatialize( entityNum, origin, axis, inwater );
}
}
/*
=================
S_Respatialize
=================
*/
void S_RespatializeOld(int entityNum, const vec3_t origin,
vec3_t axis[3])
{
if (si.Respatialize) {
si.Respatialize(entityNum, origin, axis, 0);
}
}
/*
=================
S_UpdateEntityPosition
@ -331,14 +282,13 @@ void S_BeginRegistration( void )
S_RegisterSound
=================
*/
sfxHandle_t S_RegisterSound(const char *sample, qboolean compressed, qboolean streamed)
sfxHandle_t S_RegisterSound( const char *sample, qboolean compressed )
{
if( si.RegisterSound ) {
return si.RegisterSound( sample, compressed );
} else {
return 0;
}
// FIXME: infinite loop
}
/*
@ -598,294 +548,3 @@ void S_Shutdown( void )
S_CodecShutdown( );
}
/*
=================
S_IsSoundPlaying
=================
*/
int S_IsSoundPlaying(int channelNumber, const char* name)
{
// FIXME: stub
STUB();
}
/*
=================
MUSIC_Pause
=================
*/
void MUSIC_Pause()
{
// FIXME: stub
STUB();
}
/*
=================
MUSIC_Unpause
=================
*/
void MUSIC_Unpause()
{
// FIXME: stub
STUB();
}
/*
=================
MUSIC_LoadSoundtrackFile
=================
*/
qboolean MUSIC_LoadSoundtrackFile(const char* filename)
{
// FIXME: stub
STUB();
return qfalse;
}
/*
=================
MUSIC_SongValid
=================
*/
qboolean MUSIC_SongValid(const char* mood)
{
// FIXME: stub
STUB();
return qfalse;
}
/*
=================
MUSIC_Loaded
=================
*/
qboolean MUSIC_Loaded(void)
{
// FIXME: stub
STUB();
return qfalse;
}
/*
=================
Music_Update
=================
*/
void Music_Update(void)
{
// FIXME: stub
STUB();
}
/*
=================
MUSIC_SongEnded
=================
*/
void MUSIC_SongEnded(void)
{
// FIXME: stub
STUB();
}
/*
=================
S_StartSound
=================
*/
void MUSIC_NewSoundtrack(const char* name)
{
// FIXME: stub
STUB();
}
/*
=================
MUSIC_UpdateMood
=================
*/
void MUSIC_UpdateMood(int current, int fallback)
{
// FIXME: stub
//STUB();
}
/*
=================
MUSIC_UpdateVolume
=================
*/
void MUSIC_UpdateVolume(float volume, float fade_time)
{
// FIXME: stub
STUB();
}
/*
=================
MUSIC_StopAllSongs
=================
*/
void MUSIC_StopAllSongs(void)
{
// FIXME: stub
STUB();
}
/*
=================
MUSIC_FreeAllSongs
=================
*/
void MUSIC_FreeAllSongs(void)
{
// FIXME: stub
STUB();
}
/*
=================
MUSIC_Playing
=================
*/
qboolean MUSIC_Playing(void)
{
// FIXME: stub
STUB();
return qfalse;
}
/*
=================
MUSIC_FindSong
=================
*/
int MUSIC_FindSong(const char* name)
{
// FIXME: stub
STUB();
return 0;
}
/*
=================
MUSIC_CurrentSongChannel
=================
*/
int MUSIC_CurrentSongChannel(void)
{
// FIXME: stub
STUB();
return 0;
}
/*
=================
MUSIC_StopChannel
=================
*/
void MUSIC_StopChannel(int channel_number)
{
// FIXME: stub
STUB();
}
/*
=================
MUSIC_PlaySong
=================
*/
qboolean MUSIC_PlaySong(const char* alias)
{
// FIXME: stub
STUB();
return qfalse;
}
/*
=================
MUSIC_UpdateMusicVolumes
=================
*/
void MUSIC_UpdateMusicVolumes(void)
{
// FIXME: stub
STUB();
}
/*
=================
MUSIC_CheckForStoppedSongs
=================
*/
void MUSIC_CheckForStoppedSongs(void)
{
// FIXME: stub
STUB();
}
/*
=================
S_IsSoundRegistered
=================
*/
qboolean S_IsSoundRegistered(const char* name)
{
// FIXME: stub
return qfalse;
}
/*
=================
S_GetSoundTime
=================
*/
float S_GetSoundTime(sfxHandle_t handle)
{
// FIXME: stub
STUB();
return 0.0;
}
/*
=================
S_SetGlobalAmbientVolumeLevel
=================
*/
void S_SetGlobalAmbientVolumeLevel(float volume)
{
// FIXME: stub
STUB();
}
/*
=================
S_SetReverb
=================
*/
void S_SetReverb(int reverb_type, float reverb_level)
{
// FIXME: stub
STUB();
}
/*
=================
S_EndRegistration
=================
*/
void S_EndRegistration(void)
{
// FIXME: stub
}
void S_UpdateEntity(int entityNum, const vec3_t origin, const vec3_t velocity, qboolean use_listener)
{
// FIXME: stub
}
void S_FadeSound(float fTime)
{
// FIXME: stub
}
#endif

View file

@ -15,7 +15,7 @@ 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 Foobar; if not, write to the Free Software
along with Quake III Arena source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
@ -30,6 +30,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*****************************************************************************/
#include "snd_local.h"
#include "snd_codec.h"
#define DEF_COMSOUNDMEGS "8"
@ -56,7 +57,7 @@ void SND_free(sndBuffer *v) {
inUse += sizeof(sndBuffer);
}
sndBuffer* SND_malloc() {
sndBuffer* SND_malloc(void) {
sndBuffer *v;
redo:
if (freelist == NULL) {
@ -73,7 +74,7 @@ redo:
return v;
}
void SND_setup() {
void SND_setup(void) {
sndBuffer *p, *q;
cvar_t *cv;
int scs;
@ -99,137 +100,12 @@ void SND_setup() {
Com_Printf("Sound memory manager started\n");
}
/*
===============================================================================
WAV loading
===============================================================================
*/
static byte *data_p;
static byte *iff_end;
static byte *last_chunk;
static byte *iff_data;
static int iff_chunk_len;
static short GetLittleShort(void)
void SND_shutdown(void)
{
short val = 0;
val = *data_p;
val = val + (*(data_p+1)<<8);
data_p += 2;
return val;
free(sfxScratchBuffer);
free(buffer);
}
static int 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 FindNextChunk(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 = 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((char *)data_p, name, 4))
return;
}
}
static void FindChunk(char *name)
{
last_chunk = iff_data;
FindNextChunk (name);
}
/*
============
GetWavinfo
============
*/
static wavinfo_t GetWavinfo (char *name, byte *wav, int wavlength)
{
wavinfo_t info;
Com_Memset (&info, 0, sizeof(info));
if (!wav)
return info;
iff_data = wav;
iff_end = wav + wavlength;
// find "RIFF" chunk
FindChunk("RIFF");
if (!(data_p && !strncmp((char *)data_p+8, "WAVE", 4)))
{
Com_Printf("Missing RIFF/WAVE chunks\n");
return info;
}
// get "fmt " chunk
iff_data = data_p + 12;
// DumpChunks ();
FindChunk("fmt ");
if (!data_p)
{
Com_Printf("Missing fmt chunk\n");
return info;
}
data_p += 8;
info.format = GetLittleShort();
info.channels = GetLittleShort();
info.rate = GetLittleLong();
data_p += 4+2;
info.width = GetLittleShort() / 8;
if (info.format != 1)
{
Com_Printf("Microsoft PCM format only\n");
return info;
}
// find data chunk
FindChunk("data");
if (!data_p)
{
Com_Printf("Missing data chunk\n");
return info;
}
data_p += 4;
info.samples = GetLittleLong () / info.width;
info.dataofs = data_p - wav;
return info;
}
/*
================
ResampleSfx
@ -237,47 +113,53 @@ ResampleSfx
resample / decimate to the current source rate
================
*/
static void ResampleSfx( sfx_t *sfx, int inrate, int inwidth, byte *data, qboolean compressed ) {
static int ResampleSfx( sfx_t *sfx, int channels, int inrate, int inwidth, int samples, byte *data, qboolean compressed ) {
int outcount;
int srcsample;
float stepscale;
int i;
int i, j;
int sample, samplefrac, fracstep;
int part;
sndBuffer *chunk;
stepscale = (float)inrate / dma.speed; // this is usually 0.5, 1, or 2
outcount = sfx->soundLength / stepscale;
sfx->soundLength = outcount;
outcount = samples / stepscale;
srcsample = 0;
samplefrac = 0;
fracstep = stepscale * 256;
fracstep = stepscale * 256 * channels;
chunk = sfx->soundData;
for (i=0 ; i<outcount ; i++)
{
srcsample = samplefrac >> 8;
srcsample += samplefrac >> 8;
samplefrac &= 255;
samplefrac += fracstep;
if( inwidth == 2 ) {
sample = LittleShort ( ((short *)data)[srcsample] );
} else {
sample = (int)( (unsigned char)(data[srcsample]) - 128) << 8;
}
part = (i&(SND_CHUNK_SIZE-1));
if (part == 0) {
sndBuffer *newchunk;
newchunk = SND_malloc();
if (chunk == NULL) {
sfx->soundData = newchunk;
for (j=0 ; j<channels ; j++)
{
if( inwidth == 2 ) {
sample = ( ((short *)data)[srcsample+j] );
} else {
chunk->next = newchunk;
sample = (unsigned int)( (unsigned char)(data[srcsample+j]) - 128) << 8;
}
part = (i*channels+j)&(SND_CHUNK_SIZE-1);
if (part == 0) {
sndBuffer *newchunk;
newchunk = SND_malloc();
if (chunk == NULL) {
sfx->soundData = newchunk;
} else {
chunk->next = newchunk;
}
chunk = newchunk;
}
chunk = newchunk;
}
chunk->sndChunk[part] = sample;
chunk->sndChunk[part] = sample;
}
}
return outcount;
}
/*
@ -287,35 +169,39 @@ ResampleSfx
resample / decimate to the current source rate
================
*/
static int ResampleSfxRaw( short *sfx, int inrate, int inwidth, int samples, byte *data ) {
static int ResampleSfxRaw( short *sfx, int channels, int inrate, int inwidth, int samples, byte *data ) {
int outcount;
int srcsample;
float stepscale;
int i;
int i, j;
int sample, samplefrac, fracstep;
stepscale = (float)inrate / dma.speed; // this is usually 0.5, 1, or 2
outcount = samples / stepscale;
srcsample = 0;
samplefrac = 0;
fracstep = stepscale * 256;
fracstep = stepscale * 256 * channels;
for (i=0 ; i<outcount ; i++)
{
srcsample = samplefrac >> 8;
srcsample += samplefrac >> 8;
samplefrac &= 255;
samplefrac += fracstep;
if( inwidth == 2 ) {
sample = LittleShort ( ((short *)data)[srcsample] );
} else {
sample = (int)( (unsigned char)(data[srcsample]) - 128) << 8;
for (j=0 ; j<channels ; j++)
{
if( inwidth == 2 ) {
sample = LittleShort ( ((short *)data)[srcsample+j] );
} else {
sample = (int)( (unsigned char)(data[srcsample+j]) - 128) << 8;
}
sfx[i*channels+j] = sample;
}
sfx[i] = sample;
}
return outcount;
}
//=============================================================================
/*
@ -330,40 +216,23 @@ qboolean S_LoadSound( sfx_t *sfx )
{
byte *data;
short *samples;
wavinfo_t info;
int size;
// player specific sounds are never directly loaded
if ( sfx->soundName[0] == '*') {
return qfalse;
}
snd_info_t info;
// int size;
// load it in
size = FS_ReadFile( sfx->soundName, (void **)&data );
if ( !data ) {
data = S_CodecLoad(sfx->soundName, &info);
if(!data)
return qfalse;
}
info = GetWavinfo( sfx->soundName, data, size );
if ( info.channels != 1 ) {
Com_Printf ("%s is a stereo wav file\n", sfx->soundName);
FS_FreeFile (data);
return qfalse;
}
if ( info.width == 1 ) {
Com_DPrintf(S_COLOR_YELLOW "WARNING: %s is a 8 bit wav file\n", sfx->soundName);
Com_DPrintf(S_COLOR_YELLOW "WARNING: %s is a 8 bit audio file\n", sfx->soundName);
}
if ( info.rate != 22050 ) {
Com_DPrintf(S_COLOR_YELLOW "WARNING: %s is not a 22kHz wav file\n", sfx->soundName);
Com_DPrintf(S_COLOR_YELLOW "WARNING: %s is not a 22kHz audio file\n", sfx->soundName);
}
if (!info.samples) {
return qfalse;
}
samples = Hunk_AllocateTempMemory(info.samples * sizeof(short) * 2);
samples = Hunk_AllocateTempMemory(info.channels * info.samples * sizeof(short) * 2);
sfx->lastTimeUsed = Com_Milliseconds()+1;
@ -373,36 +242,37 @@ qboolean S_LoadSound( sfx_t *sfx )
// manager to do the right thing for us and page
// sound in as needed
if( sfx->soundCompressed == qtrue) {
if( info.channels == 1 && sfx->soundCompressed == qtrue) {
sfx->soundCompressionMethod = 1;
sfx->soundData = NULL;
sfx->soundLength = ResampleSfxRaw( samples, info.rate, info.width, info.samples, (data + info.dataofs) );
sfx->soundLength = ResampleSfxRaw( samples, info.channels, info.rate, info.width, info.samples, data + info.dataofs );
S_AdpcmEncodeSound(sfx, samples);
#if 0
} else if (info.samples>(SND_CHUNK_SIZE*16) && info.width >1) {
} else if (info.channels == 1 && info.samples>(SND_CHUNK_SIZE*16) && info.width >1) {
sfx->soundCompressionMethod = 3;
sfx->soundData = NULL;
sfx->soundLength = ResampleSfxRaw( samples, info.rate, info.width, info.samples, (data + info.dataofs) );
sfx->soundLength = ResampleSfxRaw( samples, info.channels, info.rate, info.width, info.samples, (data + info.dataofs) );
encodeMuLaw( sfx, samples);
} else if (info.samples>(SND_CHUNK_SIZE*6400) && info.width >1) {
} else if (info.channels == 1 && info.samples>(SND_CHUNK_SIZE*6400) && info.width >1) {
sfx->soundCompressionMethod = 2;
sfx->soundData = NULL;
sfx->soundLength = ResampleSfxRaw( samples, info.rate, info.width, info.samples, (data + info.dataofs) );
sfx->soundLength = ResampleSfxRaw( samples, info.channels, info.rate, info.width, info.samples, (data + info.dataofs) );
encodeWavelet( sfx, samples);
#endif
} else {
sfx->soundCompressionMethod = 0;
sfx->soundLength = info.samples;
sfx->soundData = NULL;
ResampleSfx( sfx, info.rate, info.width, data + info.dataofs, qfalse );
sfx->soundLength = ResampleSfx( sfx, info.channels, info.rate, info.width, info.samples, data + info.dataofs, qfalse );
}
sfx->soundChannels = info.channels;
Hunk_FreeTempMemory(samples);
FS_FreeFile( data );
Hunk_FreeTempMemory(data);
return qtrue;
}
void S_DisplayFreeMemory() {
void S_DisplayFreeMemory(void) {
Com_Printf("%d bytes free sound buffer memory, %d total used\n", inUse, totalInUse);
}

View file

@ -15,24 +15,23 @@ 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 Foobar; if not, write to the Free Software
along with Quake III Arena source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// snd_mix.c -- portable code to mix sounds for snd_dma.c
#include "client.h"
#include "snd_local.h"
static portable_samplepair_t paintbuffer[PAINTBUFFER_SIZE];
static int snd_vol;
// bk001119 - these not static, required by unix/snd_mixa.s
int* snd_p;
int snd_linear_count;
short* snd_out;
#if !( (defined __linux__ || defined __FreeBSD__ ) && (defined __i386__) ) // rb010123
#if !id386
#if !id386 // if configured not to use asm
void S_WriteLinearBlastStereo16 (void)
{
@ -58,6 +57,9 @@ void S_WriteLinearBlastStereo16 (void)
snd_out[i+1] = val;
}
}
#elif defined(__GNUC__)
// uses snd_mixa.s
void S_WriteLinearBlastStereo16 (void);
#else
__declspec( naked ) void S_WriteLinearBlastStereo16 (void)
@ -104,10 +106,6 @@ LClampDone2:
}
}
#endif
#else
// forward declare, implementation somewhere else
void S_WriteLinearBlastStereo16 (void);
#endif
void S_TransferStereo16 (unsigned long *pbuf, int endtime)
@ -121,21 +119,24 @@ void S_TransferStereo16 (unsigned long *pbuf, int endtime)
while (ls_paintedtime < endtime)
{
// handle recirculating buffer issues
lpos = ls_paintedtime & ((dma.samples>>1)-1);
lpos = ls_paintedtime % dma.fullsamples;
snd_out = (short *) pbuf + (lpos<<1);
snd_out = (short *) pbuf + (lpos<<1); // lpos * dma.channels
snd_linear_count = (dma.samples>>1) - lpos;
snd_linear_count = dma.fullsamples - lpos;
if (ls_paintedtime + snd_linear_count > endtime)
snd_linear_count = endtime - ls_paintedtime;
snd_linear_count <<= 1;
snd_linear_count <<= 1; // snd_linear_count *= dma.channels
// write a linear blast of samples
S_WriteLinearBlastStereo16 ();
snd_p += snd_linear_count;
ls_paintedtime += (snd_linear_count>>1);
ls_paintedtime += (snd_linear_count>>1); // snd_linear_count / dma.channels
if( CL_VideoRecording( ) )
CL_WriteAVIAudioFrame( (byte *)snd_out, snd_linear_count << 1 ); // snd_linear_count * (dma.samplebits/8)
}
}
@ -149,19 +150,16 @@ void S_TransferPaintBuffer(int endtime)
{
int out_idx;
int count;
int out_mask;
int *p;
int step;
int val;
int i;
unsigned long *pbuf;
pbuf = (unsigned long *)dma.buffer;
if ( s_testsound->integer ) {
int i;
int count;
// write a fixed sine wave
count = (endtime - s_paintedtime);
for (i=0 ; i<count ; i++)
@ -177,38 +175,73 @@ void S_TransferPaintBuffer(int endtime)
{ // general case
p = (int *) paintbuffer;
count = (endtime - s_paintedtime) * dma.channels;
out_mask = dma.samples - 1;
out_idx = s_paintedtime * dma.channels & out_mask;
step = 3 - dma.channels;
out_idx = ((unsigned int)s_paintedtime * dma.channels) % dma.samples;
step = 3 - MIN(dma.channels, 2);
if (dma.samplebits == 16)
if ((dma.isfloat) && (dma.samplebits == 32))
{
float *out = (float *) pbuf;
for (i=0 ; i<count ; i++)
{
if ((i % dma.channels) >= 2)
{
val = 0;
}
else
{
val = *p >> 8;
p+= step;
}
if (val > 0x7fff)
val = 0x7fff;
else if (val < -32767) /* clamp to one less than max to make division max out at -1.0f. */
val = -32767;
out[out_idx] = ((float) val) / 32767.0f;
out_idx = (out_idx + 1) % dma.samples;
}
}
else if (dma.samplebits == 16)
{
short *out = (short *) pbuf;
while (count--)
for (i=0 ; i<count ; i++)
{
val = *p >> 8;
p+= step;
if ((i % dma.channels) >= 2)
{
val = 0;
}
else
{
val = *p >> 8;
p+= step;
}
if (val > 0x7fff)
val = 0x7fff;
else if (val < -32768)
val = -32768;
out[out_idx] = val;
out_idx = (out_idx + 1) & out_mask;
out_idx = (out_idx + 1) % dma.samples;
}
}
else if (dma.samplebits == 8)
{
unsigned char *out = (unsigned char *) pbuf;
while (count--)
for (i=0 ; i<count ; i++)
{
val = *p >> 8;
p+= step;
if ((i % dma.channels) >= 2)
{
val = 0;
}
else
{
val = *p >> 8;
p+= step;
}
if (val > 0x7fff)
val = 0x7fff;
else if (val < -32768)
val = -32768;
out[out_idx] = (val>>8) + 128;
out_idx = (out_idx + 1) & out_mask;
out_idx = (out_idx + 1) % dma.samples;
}
}
}
@ -223,14 +256,18 @@ CHANNEL MIXING
===============================================================================
*/
static void S_PaintChannelFrom16( channel_t *ch, const sfx_t *sc, int count, int sampleOffset, int bufferOffset ) {
static void S_PaintChannelFrom16_scalar( channel_t *ch, const sfx_t *sc, int count, int sampleOffset, int bufferOffset ) {
int data, aoff, boff;
int leftvol, rightvol;
int i, j;
portable_samplepair_t *samp;
sndBuffer *chunk;
short *samples;
float ooff, fdata, fdiv, fleftvol, frightvol;
float ooff, fdata[2], fdiv, fleftvol, frightvol;
if (sc->soundChannels <= 0) {
return;
}
samp = &paintbuffer[ bufferOffset ];
@ -238,6 +275,14 @@ static void S_PaintChannelFrom16( channel_t *ch, const sfx_t *sc, int count, int
sampleOffset = sampleOffset*ch->oldDopplerScale;
}
if ( sc->soundChannels == 2 ) {
sampleOffset *= sc->soundChannels;
if ( sampleOffset & 1 ) {
sampleOffset &= ~1;
}
}
chunk = sc->soundData;
while (sampleOffset>=SND_CHUNK_SIZE) {
chunk = chunk->next;
@ -248,126 +293,16 @@ static void S_PaintChannelFrom16( channel_t *ch, const sfx_t *sc, int count, int
}
if (!ch->doppler || ch->dopplerScale==1.0f) {
#if idppc_altivec
vector signed short volume_vec;
vector unsigned int volume_shift;
int vectorCount, samplesLeft, chunkSamplesLeft;
#endif
leftvol = ch->leftvol*snd_vol;
rightvol = ch->rightvol*snd_vol;
samples = chunk->sndChunk;
#if idppc_altivec
((short *)&volume_vec)[0] = leftvol;
((short *)&volume_vec)[1] = leftvol;
((short *)&volume_vec)[4] = leftvol;
((short *)&volume_vec)[5] = leftvol;
((short *)&volume_vec)[2] = rightvol;
((short *)&volume_vec)[3] = rightvol;
((short *)&volume_vec)[6] = rightvol;
((short *)&volume_vec)[7] = rightvol;
volume_shift = vec_splat_u32(8);
i = 0;
while(i < count) {
/* Try to align destination to 16-byte boundary */
while(i < count && (((unsigned long)&samp[i] & 0x1f) || ((count-i) < 8) || ((SND_CHUNK_SIZE - sampleOffset) < 8))) {
data = samples[sampleOffset++];
samp[i].left += (data * leftvol)>>8;
samp[i].right += (data * rightvol)>>8;
if (sampleOffset == SND_CHUNK_SIZE) {
chunk = chunk->next;
samples = chunk->sndChunk;
sampleOffset = 0;
}
i++;
}
/* Destination is now aligned. Process as many 8-sample
chunks as we can before we run out of room from the current
sound chunk. We do 8 per loop to avoid extra source data reads. */
samplesLeft = count - i;
chunkSamplesLeft = SND_CHUNK_SIZE - sampleOffset;
if(samplesLeft > chunkSamplesLeft)
samplesLeft = chunkSamplesLeft;
vectorCount = samplesLeft / 8;
if(vectorCount)
{
vector unsigned char tmp;
vector short s0, s1, sampleData0, sampleData1;
vector short samples0, samples1;
vector signed int left0, right0;
vector signed int merge0, merge1;
vector signed int d0, d1, d2, d3;
vector unsigned char samplePermute0 =
(vector unsigned char)(0, 1, 4, 5, 0, 1, 4, 5, 2, 3, 6, 7, 2, 3, 6, 7);
vector unsigned char samplePermute1 =
(vector unsigned char)(8, 9, 12, 13, 8, 9, 12, 13, 10, 11, 14, 15, 10, 11, 14, 15);
vector unsigned char loadPermute0, loadPermute1;
// Rather than permute the vectors after we load them to do the sample
// replication and rearrangement, we permute the alignment vector so
// we do everything in one step below and avoid data shuffling.
tmp = vec_lvsl(0,&samples[sampleOffset]);
loadPermute0 = vec_perm(tmp,tmp,samplePermute0);
loadPermute1 = vec_perm(tmp,tmp,samplePermute1);
s0 = *(vector short *)&samples[sampleOffset];
while(vectorCount)
{
/* Load up source (16-bit) sample data */
s1 = *(vector short *)&samples[sampleOffset+7];
/* Load up destination sample data */
d0 = *(vector signed int *)&samp[i];
d1 = *(vector signed int *)&samp[i+2];
d2 = *(vector signed int *)&samp[i+4];
d3 = *(vector signed int *)&samp[i+6];
sampleData0 = vec_perm(s0,s1,loadPermute0);
sampleData1 = vec_perm(s0,s1,loadPermute1);
merge0 = vec_mule(sampleData0,volume_vec);
merge0 = vec_sra(merge0,volume_shift); /* Shift down to proper range */
merge1 = vec_mulo(sampleData0,volume_vec);
merge1 = vec_sra(merge1,volume_shift);
d0 = vec_add(merge0,d0);
d1 = vec_add(merge1,d1);
merge0 = vec_mule(sampleData1,volume_vec);
merge0 = vec_sra(merge0,volume_shift); /* Shift down to proper range */
merge1 = vec_mulo(sampleData1,volume_vec);
merge1 = vec_sra(merge1,volume_shift);
d2 = vec_add(merge0,d2);
d3 = vec_add(merge1,d3);
/* Store destination sample data */
*(vector signed int *)&samp[i] = d0;
*(vector signed int *)&samp[i+2] = d1;
*(vector signed int *)&samp[i+4] = d2;
*(vector signed int *)&samp[i+6] = d3;
i += 8;
vectorCount--;
s0 = s1;
sampleOffset += 8;
}
if (sampleOffset == SND_CHUNK_SIZE) {
chunk = chunk->next;
samples = chunk->sndChunk;
sampleOffset = 0;
}
}
}
#else
for ( i=0 ; i<count ; i++ ) {
data = samples[sampleOffset++];
samp[i].left += (data * leftvol)>>8;
if ( sc->soundChannels == 2 ) {
data = samples[sampleOffset++];
}
samp[i].right += (data * rightvol)>>8;
if (sampleOffset == SND_CHUNK_SIZE) {
@ -376,7 +311,6 @@ static void S_PaintChannelFrom16( channel_t *ch, const sfx_t *sc, int count, int
sampleOffset = 0;
}
}
#endif
} else {
fleftvol = ch->leftvol*snd_vol;
frightvol = ch->rightvol*snd_vol;
@ -390,10 +324,10 @@ static void S_PaintChannelFrom16( channel_t *ch, const sfx_t *sc, int count, int
for ( i=0 ; i<count ; i++ ) {
aoff = ooff;
ooff = ooff + ch->dopplerScale;
ooff = ooff + ch->dopplerScale * sc->soundChannels;
boff = ooff;
fdata = 0;
for (j=aoff; j<boff; j++) {
fdata[0] = fdata[1] = 0;
for (j=aoff; j<boff; j += sc->soundChannels) {
if (j == SND_CHUNK_SIZE) {
chunk = chunk->next;
if (!chunk) {
@ -402,15 +336,32 @@ static void S_PaintChannelFrom16( channel_t *ch, const sfx_t *sc, int count, int
samples = chunk->sndChunk;
ooff -= SND_CHUNK_SIZE;
}
fdata += samples[j&(SND_CHUNK_SIZE-1)];
if ( sc->soundChannels == 2 ) {
fdata[0] += samples[j&(SND_CHUNK_SIZE-1)];
fdata[1] += samples[(j+1)&(SND_CHUNK_SIZE-1)];
} else {
fdata[0] += samples[j&(SND_CHUNK_SIZE-1)];
fdata[1] += samples[j&(SND_CHUNK_SIZE-1)];
}
}
fdiv = 256 * (boff-aoff);
samp[i].left += (fdata * fleftvol)/fdiv;
samp[i].right += (fdata * frightvol)/fdiv;
fdiv = 256 * (boff-aoff) / sc->soundChannels;
samp[i].left += (fdata[0] * fleftvol)/fdiv;
samp[i].right += (fdata[1] * frightvol)/fdiv;
}
}
}
static void S_PaintChannelFrom16( channel_t *ch, const sfx_t *sc, int count, int sampleOffset, int bufferOffset ) {
#if idppc_altivec
if (com_altivec->integer) {
// must be in a separate translation unit or G3 systems will crash.
S_PaintChannelFrom16_altivec( paintbuffer, snd_vol, ch, sc, count, sampleOffset, bufferOffset );
return;
}
#endif
S_PaintChannelFrom16_scalar( ch, sc, count, sampleOffset, bufferOffset );
}
void S_PaintChannelFromWavelet( channel_t *ch, sfx_t *sc, int count, int sampleOffset, int bufferOffset ) {
int data;
int leftvol, rightvol;
@ -432,7 +383,7 @@ void S_PaintChannelFromWavelet( channel_t *ch, sfx_t *sc, int count, int sampleO
}
if (i!=sfxScratchIndex || sfxScratchPointer != sc) {
S_AdpcmGetSamples( chunk, sfxScratchBuffer );
decodeWavelet(chunk, sfxScratchBuffer);
sfxScratchIndex = i;
sfxScratchPointer = sc;
}
@ -529,7 +480,7 @@ void S_PaintChannelFromMuLaw( channel_t *ch, sfx_t *sc, int count, int sampleOff
samp[i].left += (data * leftvol)>>8;
samp[i].right += (data * rightvol)>>8;
samples++;
if (samples == (byte *)chunk->sndChunk+(SND_CHUNK_SIZE*2)) {
if (chunk != NULL && samples == (byte *)chunk->sndChunk+(SND_CHUNK_SIZE*2)) {
chunk = chunk->next;
samples = (byte *)chunk->sndChunk;
}
@ -562,13 +513,16 @@ S_PaintChannels
void S_PaintChannels( int endtime ) {
int i;
int end;
int stream;
channel_t *ch;
sfx_t *sc;
int ltime, count;
int sampleOffset;
snd_vol = s_volume->value*255;
if(s_muted->integer)
snd_vol = 0;
else
snd_vol = s_volume->value*255;
//Com_Printf ("%i to %i\n", s_paintedtime, endtime);
while ( s_paintedtime < endtime ) {
@ -579,30 +533,18 @@ void S_PaintChannels( int endtime ) {
end = s_paintedtime + PAINTBUFFER_SIZE;
}
// clear the paint buffer to either music or zeros
if ( s_rawend < s_paintedtime ) {
if ( s_rawend ) {
//Com_DPrintf ("background sound underrun\n");
}
Com_Memset(paintbuffer, 0, (end - s_paintedtime) * sizeof(portable_samplepair_t));
} else {
// copy from the streaming sound source
int s;
int stop;
stop = (end < s_rawend) ? end : s_rawend;
for ( i = s_paintedtime ; i < stop ; i++ ) {
s = i&(MAX_RAW_SAMPLES-1);
paintbuffer[i-s_paintedtime] = s_rawsamples[s];
}
// if (i != end)
// Com_Printf ("partial stream\n");
// else
// Com_Printf ("full stream\n");
for ( ; i < end ; i++ ) {
paintbuffer[i-s_paintedtime].left =
paintbuffer[i-s_paintedtime].right = 0;
// clear the paint buffer and mix any raw samples...
Com_Memset(paintbuffer, 0, sizeof (paintbuffer));
for (stream = 0; stream < MAX_RAW_STREAMS; stream++) {
if ( s_rawend[stream] >= s_paintedtime ) {
// copy from the streaming sound source
const portable_samplepair_t *rawsamples = s_rawsamples[stream];
const int stop = (end < s_rawend[stream]) ? end : s_rawend[stream];
for ( i = s_paintedtime ; i < stop ; i++ ) {
const int s = i&(MAX_RAW_SAMPLES-1);
paintbuffer[i-s_paintedtime].left += rawsamples[s].left;
paintbuffer[i-s_paintedtime].right += rawsamples[s].right;
}
}
}
@ -616,6 +558,10 @@ void S_PaintChannels( int endtime ) {
ltime = s_paintedtime;
sc = ch->thesfx;
if (sc->soundData==NULL || sc->soundLength==0) {
continue;
}
sampleOffset = ltime - ch->startSample;
count = end - ltime;
if ( sampleOffset + count > sc->soundLength ) {

2734
code/client/snd_openal.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -15,44 +15,38 @@ 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 Foobar; if not, write to the Free Software
along with Quake III Arena source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#ifdef __cplusplus
extern "C" {
#endif
void S_Init( void );
void S_Shutdown( void );
// if origin is NULL, the sound will be dynamically sourced from the entity
void S_StartSound(const vec3_t origin, int entNum, int entChannel, sfxHandle_t sfxHandle, float volume, float minDist, float pitch, float maxDist, int streamed);
void S_StopSound(int entnum, int channel);
void S_StartLocalSound(sfxHandle_t sfx, int channelNum);
void S_StartLocalSoundByName(const char* sound_name, qboolean force_load);
void S_StartSound( vec3_t origin, int entnum, int entchannel, sfxHandle_t sfx );
void S_StartLocalSound( sfxHandle_t sfx, int channelNum );
void S_StartBackgroundTrack( const char *intro, const char *loop );
void S_StopBackgroundTrack( void );
// cinematics and voice-over-network will send raw samples
// 1.0 volume will be direct output of source samples
void S_RawSamples (int samples, int rate, int width, int channels,
const byte *data, float volume);
void S_RawSamples(int stream, int samples, int rate, int width, int channels,
const byte *data, float volume, int entityNum);
// stop all sounds and the background track
void S_StopAllSounds(qboolean stop_music);
void S_StopAllSounds( void );
// all continuous looping sounds must be added before calling S_Update
void S_ClearLoopingSoundsNoParam(void);
void S_ClearLoopingSounds( qboolean killall );
void S_AddLoopingSound(const vec3_t origin, const vec3_t velocity, sfxHandle_t sfxHandle, float volume, float minDist, float maxDist, float pitch, int flags);
void S_AddLoopingSound( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx );
void S_AddRealLoopingSound( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx );
void S_StopLoopingSound(int entityNum );
// recompute the reletive volumes for all running sounds
// reletive to the given entityNum / orientation
// recompute the relative volumes for all running sounds
// relative to the given entityNum / orientation
void S_Respatialize( int entityNum, const vec3_t origin, vec3_t axis[3], int inwater );
// let the sound system know where an entity currently is
@ -63,12 +57,11 @@ void S_Update( void );
void S_DisableSounds( void );
void S_BeginRegistration( void );
void S_EndRegistration(void);
qboolean S_IsSoundRegistered(const char* name);
// RegisterSound will allways return a valid sample, even if it
// has to create a placeholder. This prevents continuous filesystem
// checks for missing files
sfxHandle_t S_RegisterSound(const char *sample, qboolean compressed, qboolean streamed);
sfxHandle_t S_RegisterSound( const char *sample, qboolean compressed );
void S_DisplayFreeMemory(void);
@ -78,37 +71,13 @@ void SNDDMA_Activate( void );
void S_UpdateBackgroundTrack( void );
// Music soundtrack
void MUSIC_Pause();
void MUSIC_Unpause();
qboolean MUSIC_LoadSoundtrackFile(const char* filename);
qboolean MUSIC_SongValid(const char* mood);
qboolean MUSIC_Loaded(void);
void Music_Update(void);
void MUSIC_SongEnded(void);
void MUSIC_NewSoundtrack(const char* name);
void MUSIC_UpdateMood(int current, int fallback);
void MUSIC_UpdateVolume(float volume, float fade_time);
void MUSIC_StopAllSongs(void);
void MUSIC_FreeAllSongs(void);
qboolean MUSIC_Playing(void);
int MUSIC_FindSong(const char* name);
int MUSIC_CurrentSongChannel(void);
void MUSIC_StopChannel(int channel_number);
qboolean MUSIC_PlaySong(const char* alias);
void MUSIC_UpdateMusicVolumes(void);
void MUSIC_CheckForStoppedSongs(void);
float S_GetSoundTime(sfxHandle_t handle);
void S_SetGlobalAmbientVolumeLevel(float volume);
void S_SetReverb(int reverb_type, float reverb_level);
int S_IsSoundPlaying(int channelNumber, const char* name);
void S_RespatializeOld(int entityNum, const vec3_t origin, vec3_t axis[3]);
void S_UpdateEntity(int entityNum, const vec3_t origin, const vec3_t velocity, qboolean use_listener);
void S_FadeSound(float fTime);
#ifdef __cplusplus
}
#ifdef USE_VOIP
void S_StartCapture(void);
int S_AvailableCaptureSamples(void);
void S_Capture(int samples, byte* data);
void S_StopCapture(void);
void S_MasterGain(float gain);
#endif
#include "new/snd_public_new.h"

View file

@ -15,15 +15,13 @@ 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 Foobar; if not, write to the Free Software
along with Quake III Arena source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#include "snd_local.h"
long myftol( float f );
#define C0 0.4829629131445341
#define C1 0.8365163037378079
#define C2 0.2241438680420134
@ -31,8 +29,8 @@ long myftol( float f );
void daub4(float b[], unsigned long n, int isign)
{
float wksp[4097];
float *a=b-1; // numerical recipies so a[1] = b[0]
float wksp[4097] = { 0.0f };
#define a(x) b[(x)-1] // numerical recipies so a[1] = b[0]
unsigned long nh,nh1,i,j;
@ -41,22 +39,23 @@ void daub4(float b[], unsigned long n, int isign)
nh1=(nh=n >> 1)+1;
if (isign >= 0) {
for (i=1,j=1;j<=n-3;j+=2,i++) {
wksp[i] = C0*a[j]+C1*a[j+1]+C2*a[j+2]+C3*a[j+3];
wksp[i+nh] = C3*a[j]-C2*a[j+1]+C1*a[j+2]-C0*a[j+3];
wksp[i] = C0*a(j)+C1*a(j+1)+C2*a(j+2)+C3*a(j+3);
wksp[i+nh] = C3*a(j)-C2*a(j+1)+C1*a(j+2)-C0*a(j+3);
}
wksp[i ] = C0*a[n-1]+C1*a[n]+C2*a[1]+C3*a[2];
wksp[i+nh] = C3*a[n-1]-C2*a[n]+C1*a[1]-C0*a[2];
wksp[i ] = C0*a(n-1)+C1*a(n)+C2*a(1)+C3*a(2);
wksp[i+nh] = C3*a(n-1)-C2*a(n)+C1*a(1)-C0*a(2);
} else {
wksp[1] = C2*a[nh]+C1*a[n]+C0*a[1]+C3*a[nh1];
wksp[2] = C3*a[nh]-C0*a[n]+C1*a[1]-C2*a[nh1];
wksp[1] = C2*a(nh)+C1*a(n)+C0*a(1)+C3*a(nh1);
wksp[2] = C3*a(nh)-C0*a(n)+C1*a(1)-C2*a(nh1);
for (i=1,j=3;i<nh;i++) {
wksp[j++] = C2*a[i]+C1*a[i+nh]+C0*a[i+1]+C3*a[i+nh1];
wksp[j++] = C3*a[i]-C0*a[i+nh]+C1*a[i+1]-C2*a[i+nh1];
wksp[j++] = C2*a(i)+C1*a(i+nh)+C0*a(i+1)+C3*a(i+nh1);
wksp[j++] = C3*a(i)-C0*a(i+nh)+C1*a(i+1)-C2*a(i+nh1);
}
}
for (i=1;i<=n;i++) {
a[i]=wksp[i];
a(i)=wksp[i];
}
#undef a
}
void wt1(float a[], unsigned long n, int isign)
@ -121,7 +120,7 @@ void NXPutc(NXStream *stream, char out) {
void encodeWavelet( sfx_t *sfx, short *packets) {
float wksp[4097], temp;
float wksp[4097] = {0}, temp;
int i, samples, size;
sndBuffer *newchunk, *chunk;
byte *out;
@ -148,7 +147,7 @@ void encodeWavelet( sfx_t *sfx, short *packets) {
newchunk = SND_malloc();
if (sfx->soundData == NULL) {
sfx->soundData = newchunk;
} else {
} else if (chunk != NULL) {
chunk->next = newchunk;
}
chunk = newchunk;
@ -171,7 +170,7 @@ void encodeWavelet( sfx_t *sfx, short *packets) {
}
void decodeWavelet(sndBuffer *chunk, short *to) {
float wksp[4097];
float wksp[4097] = {0};
int i;
byte *out;
@ -217,7 +216,7 @@ void encodeMuLaw( sfx_t *sfx, short *packets) {
newchunk = SND_malloc();
if (sfx->soundData == NULL) {
sfx->soundData = newchunk;
} else {
} else if (chunk != NULL) {
chunk->next = newchunk;
}
chunk = newchunk;