mirror of
https://github.com/openmoh/openmohaa.git
synced 2025-04-28 13:47:58 +03:00
New sound system
This commit is contained in:
parent
41fc217a06
commit
ba0ed7504d
17 changed files with 5594 additions and 1596 deletions
292
code/client/new/snd_main_new.cpp
Normal file
292
code/client/new/snd_main_new.cpp
Normal 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
|
||||
}
|
40
code/client/new/snd_public_new.h
Normal file
40
code/client/new/snd_public_new.h
Normal 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
|
|
@ -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
229
code/client/snd_altivec.c
Normal 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
237
code/client/snd_codec.c
Normal 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
107
code/client/snd_codec.h
Normal 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
475
code/client/snd_codec_ogg.c
Normal 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
|
449
code/client/snd_codec_opus.c
Normal file
449
code/client/snd_codec_opus.c
Normal 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
291
code/client/snd_codec_wav.c
Normal 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
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
2734
code/client/snd_openal.c
Normal file
File diff suppressed because it is too large
Load diff
|
@ -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"
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue