use SDL_ConvertAudio() to convert sound samples to target format (#863)

* properly cache sound lump numbers

* initialize original_S_sfx[] array using macros

* rename channelinfo[].id -> channelinfo[].sfx

* rename LINKED_SOUND -> SOUND_LINK

* use SDL_ConvertAudio() to convert sound samples to target format

Fixes #858

* precache_sounds is not an option anymore

* lowpass_filter is not an option anymore

* rename channel -> handle and other clean-up

* some more clean-up

* fix pitch-shifted sounds

* set SDL_HINT_AUDIO_RESAMPLING_MODE to "default"

* set SDL_HINT_AUDIO_RESAMPLING_MODE to "linear", with a comment

* clear out cvt target buffer

* de-obfuscate steptable[pitch] generation

* make snd_samplerate and snd_resampling_mode configurable

* simplify SOUND_LINK macro call

* set default sampling mode to "default"

* cosmetics

* comments

* correct snd_resampling_mode choice name

* replace some redundant variables by a single SDL_AudioSpec

* forgotten parenthesis

* minor polish
This commit is contained in:
Fabian Greffrath 2023-01-10 07:48:33 +01:00 committed by GitHub
parent e5872e9bda
commit 73dc94480c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 703 additions and 809 deletions

View File

@ -2721,10 +2721,6 @@ void D_DoomMain(void)
// Sound mixing for the buffer is snychronous.
I_UpdateSound();
// Synchronous sound output is explicitly called.
// Update sound output.
I_SubmitSound();
}
}

View File

@ -5,7 +5,7 @@
//
// Copyright (C) 1999 by
// id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
// Copyright(C) 2020-2021 Fabian Greffrath
// Copyright(C) 2020-2023 Fabian Greffrath
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
@ -35,18 +35,6 @@
#include "doomstat.h"
#include "i_sound.h"
#include "w_wad.h"
#include "d_main.h"
#ifndef M_PI
#define M_PI 3.14
#endif
// [FG] precache all sound effects
boolean precache_sounds;
// [FG] optional low-pass filter
boolean lowpass_filter;
// [FG] variable pitch bend range
int pitch_bend_range;
// Music modules
extern music_module_t music_win_module;
@ -78,15 +66,18 @@ static music_module_t *active_module = NULL;
// haleyjd: safety variables to keep changes to *_card from making
// these routines think that sound has been initialized when it hasn't
boolean snd_init = false;
static boolean snd_init = false;
// haleyjd 10/28/05: updated for Julian's music code, need full quality now
int snd_samplerate = 44100;
int snd_samplerate;
char *snd_resampling_mode;
static Uint16 mix_format;
static int mix_channels;
typedef struct {
// SFX id of the playing sound effect.
// Used to catch duplicates (like chainsaw).
sfxinfo_t *id;
sfxinfo_t *sfx;
// The channel data pointer.
unsigned char* data;
// [FG] let SDL_Mixer do the actual sound mixing
@ -98,313 +89,243 @@ typedef struct {
channel_info_t channelinfo[MAX_CHANNELS];
// Pitch to stepping lookup, unused.
int steptable[256];
float steptable[256];
//
// stopchan
// StopChannel
//
// cph
// Stops a sound, unlocks the data
//
static void stopchan(int handle)
static void StopChannel(int channel)
{
int cnum;
#ifdef RANGECHECK
// haleyjd 02/18/05: bounds checking
if(handle < 0 || handle >= MAX_CHANNELS)
if (channel < 0 || channel >= MAX_CHANNELS)
return;
#endif
if(channelinfo[handle].data)
if (channelinfo[channel].data)
{
Mix_HaltChannel(handle);
// [FG] immediately free samples not connected to a sound SFX
if (channelinfo[handle].id == NULL)
{
Z_Free(channelinfo[handle].data);
}
channelinfo[handle].data = NULL;
Mix_HaltChannel(channel);
if(channelinfo[handle].id)
// [FG] immediately free samples not connected to a sound SFX
if (channelinfo[channel].sfx == NULL)
{
free(channelinfo[channel].data);
}
channelinfo[channel].data = NULL;
if (channelinfo[channel].sfx)
{
// haleyjd 06/03/06: see if we can free the sound
for(cnum = 0; cnum < MAX_CHANNELS; ++cnum)
for (cnum = 0; cnum < MAX_CHANNELS; cnum++)
{
if(cnum == handle)
if (cnum == channel)
continue;
if(channelinfo[cnum].id &&
channelinfo[cnum].id->data == channelinfo[handle].id->data)
if (channelinfo[cnum].sfx &&
channelinfo[cnum].sfx->data == channelinfo[channel].sfx->data)
{
return; // still being used by some channel
}
// set sample to PU_CACHE level
if (!precache_sounds)
{
Z_ChangeTag(channelinfo[handle].id->data, PU_CACHE);
}
}
}
channelinfo[handle].id = NULL;
channelinfo[channel].sfx = NULL;
}
static int SOUNDHDRSIZE = 8;
#define SOUNDHDRSIZE 8
//
// addsfx
//
// This function adds a sound to the
// list of currently active sounds,
// which is maintained as a given number
// (eight, usually) of internal channels.
// Returns a handle.
// CacheSound
//
// haleyjd: needs to take a sfxinfo_t ptr, not a sound id num
// haleyjd 06/03/06: changed to return boolean for failure or success
//
static boolean addsfx(sfxinfo_t *sfx, int channel, int pitch)
static boolean CacheSound(sfxinfo_t *sfx, int channel, int pitch)
{
size_t lumplen;
int lump;
// [FG] do not connect pitch-shifted samples to a sound SFX
unsigned int sfx_alen;
unsigned int bits;
void *sfx_data;
int lumpnum, lumplen;
Uint8 *lumpdata = NULL, *wavdata = NULL;
Mix_Chunk *const chunk = &channelinfo[channel].chunk;
#ifdef RANGECHECK
if(channel < 0 || channel >= MAX_CHANNELS)
I_Error("addsfx: channel out of range!\n");
if (channel < 0 || channel >= MAX_CHANNELS)
{
I_Error("CacheSound: channel out of range!\n");
}
#endif
// haleyjd 02/18/05: null ptr check
if(!snd_init || !sfx)
if (!snd_init || !sfx)
{
return false;
}
stopchan(channel);
StopChannel(channel);
// We will handle the new SFX.
// Set pointer to raw data.
lumpnum = I_GetSfxLumpNum(sfx);
// haleyjd: Eternity sfxinfo_t does not have a lumpnum field
lump = I_GetSfxLumpNum(sfx);
if (lumpnum == -1)
{
return false;
}
// replace missing sounds with a reasonable default
if(lump == -1)
lump = W_GetNumForName("DSPISTOL");
lumplen = W_LumpLength(lump);
lumplen = W_LumpLength(lumpnum);
// haleyjd 10/08/04: do not play zero-length sound lumps
if(lumplen <= SOUNDHDRSIZE)
if (lumplen <= SOUNDHDRSIZE)
{
return false;
}
// haleyjd 06/03/06: rewrote again to make sound data properly freeable
if(sfx->data == NULL || pitch != NORM_PITCH)
while (sfx->data == NULL)
{
byte *data;
Uint32 samplerate, samplelen, samplecount;
Uint8 *wav_buffer = NULL;
SDL_AudioSpec sample;
SDL_AudioCVT cvt;
Uint8 *sampledata;
Uint32 samplelen;
// haleyjd: this should always be called (if lump is already loaded,
// W_CacheLumpNum handles that for us).
data = (byte *)W_CacheLumpNum(lump, PU_STATIC);
lumpdata = (Uint8 *)W_CacheLumpNum(lumpnum, PU_STATIC);
// [crispy] Check if this is a valid RIFF wav file
if (lumplen > 44 && memcmp(data, "RIFF", 4) == 0 && memcmp(data + 8, "WAVEfmt ", 8) == 0)
{
SDL_RWops *RWops;
SDL_AudioSpec wav_spec;
RWops = SDL_RWFromMem(data, lumplen);
Z_ChangeTag(data, PU_CACHE);
if (SDL_LoadWAV_RW(RWops, 1, &wav_spec, &wav_buffer, &samplelen) == NULL)
{
fprintf(stderr, "Could not open wav file: %s\n", SDL_GetError());
return false;
}
if (wav_spec.channels != 1)
{
fprintf(stderr, "Only mono WAV file is supported");
SDL_FreeWAV(wav_buffer);
return false;
}
if (!SDL_AUDIO_ISINT(wav_spec.format))
{
SDL_FreeWAV(wav_buffer);
return false;
}
bits = SDL_AUDIO_BITSIZE(wav_spec.format);
if (bits != 8 && bits != 16)
{
fprintf(stderr, "Only 8 or 16 bit WAV files are supported");
SDL_FreeWAV(wav_buffer);
return false;
}
samplerate = wav_spec.freq;
data = wav_buffer;
SOUNDHDRSIZE = 0;
}
// Check the header, and ensure this is a valid sound
else if(data[0] == 0x03 && data[1] == 0x00)
if (lumpdata[0] == 0x03 && lumpdata[1] == 0x00)
{
samplerate = (data[3] << 8) | data[2];
samplelen = (data[7] << 24) | (data[6] << 16) | (data[5] << 8) | data[4];
// All Doom sounds are 8-bit
bits = 8;
SOUNDHDRSIZE = 8;
}
else
{
Z_ChangeTag(data, PU_CACHE);
return false;
}
sample.freq = (lumpdata[3] << 8) | lumpdata[2];
samplelen = (lumpdata[7] << 24) | (lumpdata[6] << 16) |
(lumpdata[5] << 8) | lumpdata[4];
// don't play sounds that think they're longer than they really are
if(samplelen > lumplen - SOUNDHDRSIZE)
if (samplelen > lumplen - SOUNDHDRSIZE)
{
break;
}
sampledata = lumpdata + SOUNDHDRSIZE;
// All Doom sounds are 8-bit
sample.format = AUDIO_U8;
sample.channels = 1;
}
else
{
SDL_RWops *RWops;
if ((RWops = SDL_RWFromMem(lumpdata, lumplen)) == NULL)
{
fprintf(stderr, "SDL_RWFromMem: %s\n", SDL_GetError());
break;
}
if (SDL_LoadWAV_RW(RWops, 1, &sample, &wavdata, &samplelen) == NULL) // 1 = will call SDL_RWclose(RWops) for us
{
fprintf(stderr, "SDL_LoadWAV_RW: %s\n", SDL_GetError());
break;
}
if (sample.channels != 1)
{
fprintf(stderr, "Only mono WAV files are supported\n");
break;
}
sampledata = wavdata;
}
// Convert sound to target samplerate
if (SDL_BuildAudioCVT(&cvt,
sample.format, sample.channels, sample.freq,
mix_format, mix_channels, snd_samplerate) < 0)
{
fprintf(stderr, "SDL_BuildAudioCVT: %s\n", SDL_GetError());
break;
}
cvt.len = samplelen;
cvt.buf = (Uint8 *)malloc(cvt.len * cvt.len_mult);
// [FG] clear buffer (cvt.len * cvt.len_mult >= cvt.len_cvt)
memset(cvt.buf, 0, cvt.len * cvt.len_mult);
memcpy(cvt.buf, sampledata, cvt.len);
if (SDL_ConvertAudio(&cvt) < 0)
{
fprintf(stderr, "SDL_ConvertAudio: %s\n", SDL_GetError());
break;
}
sfx->data = cvt.buf;
sfx->alen = cvt.len_cvt;
}
// don't need original lump data any more
if (lumpdata)
{
Z_Free(lumpdata);
}
if (wavdata)
{
SDL_FreeWAV(wavdata);
}
if (sfx->data == NULL)
{
Z_ChangeTag(data, PU_CACHE);
return false;
}
samplecount = samplelen / (bits / 8);
// [FG] do not connect pitch-shifted samples to a sound SFX
if (pitch == NORM_PITCH)
{
sfx_alen = (Uint32)(((uint64_t)samplecount * snd_samplerate) / samplerate);
// [FG] double up twice: 8 -> 16 bit and mono -> stereo
sfx->alen = 4 * sfx_alen;
sfx->data = precache_sounds ? malloc(sfx->alen) : Z_Malloc(sfx->alen, PU_STATIC, &sfx->data);
sfx_data = sfx->data;
}
else
{
// [FG] spoof sound samplerate if using randomly pitched sounds
samplerate = (Uint32)(((uint64_t)samplerate * steptable[pitch]) >> 16);
sfx_alen = (Uint32)(((uint64_t)samplecount * snd_samplerate) / samplerate);
// [FG] double up twice: 8 -> 16 bit and mono -> stereo
channelinfo[channel].data = Z_Malloc(4 * sfx_alen, PU_STATIC, (void **)&channelinfo[channel].data);
sfx_data = channelinfo[channel].data;
}
// haleyjd 04/23/08: Convert sound to target samplerate
{
unsigned int i;
Sint16 sample = 0;
Sint16 *dest = (Sint16 *)sfx_data;
byte *src = data + SOUNDHDRSIZE;
unsigned int step = (samplerate << 16) / snd_samplerate;
unsigned int stepremainder = 0, j = 0;
// do linear filtering operation
for(i = 0; i < sfx_alen && j < samplelen - 1; ++i)
{
int d;
if (bits == 16)
{
d = ((Sint16)(src[j ] | (src[j+1] << 8)) * (0x10000 - stepremainder) +
(Sint16)(src[j+2] | (src[j+3] << 8)) * stepremainder) >> 16;
sample = d;
}
else
{
d = (((unsigned int)src[j ] * (0x10000 - stepremainder)) +
((unsigned int)src[j+1] * stepremainder)) >> 8;
// [FG] interpolate sfx in a 16-bit int domain, convert to signed
sample = d - (1<<15);
}
dest[2*i] = dest[2*i+1] = sample;
stepremainder += step;
if (bits == 16)
j += (stepremainder >> 16) * 2;
else
j += (stepremainder >> 16);
stepremainder &= 0xffff;
}
// fill remainder (if any) with final sample byte
for(; i < sfx_alen; ++i)
dest[2*i] = dest[2*i+1] = sample;
// Perform a low-pass filter on the upscaled sound to filter
// out high-frequency noise from the conversion process.
if (lowpass_filter)
{
float rc, dt, alpha;
// Low-pass filter for cutoff frequency f:
//
// For sampling rate r, dt = 1 / r
// rc = 1 / 2*pi*f
// alpha = dt / (rc + dt)
// Filter to the half sample rate of the original sound effect
// (maximum frequency, by nyquist)
dt = 1.0f / snd_samplerate;
rc = 1.0f / (M_PI * samplerate);
alpha = dt / (rc + dt);
// Both channels are processed in parallel, hence [i-2]:
for (i = 2; i < sfx_alen * 2; ++i)
{
dest[i] = (Sint16) (alpha * dest[i]
+ (1.0f - alpha) * dest[i-2]);
}
}
}
// [FG] double up twice: 8 -> 16 bit and mono -> stereo
sfx_alen *= 4;
if (wav_buffer)
SDL_FreeWAV(wav_buffer);
else
// haleyjd 06/03/06: don't need original lump data any more
Z_ChangeTag(data, PU_CACHE);
}
else
if (!precache_sounds)
Z_ChangeTag(sfx->data, PU_STATIC); // reset to static cache level
// [FG] let SDL_Mixer do the actual sound mixing
channelinfo[channel].chunk.allocated = 1;
channelinfo[channel].chunk.volume = MIX_MAX_VOLUME;
chunk->allocated = 1;
chunk->volume = MIX_MAX_VOLUME;
// Allocate a new sound chunk and pitch-shift an existing sound up-or-down
// into it, based on chocolate-doom/src/i_sdlsound.c:PitchShift().
if (pitch != NORM_PITCH)
{
Sint16 *inp, *outp;
Sint16 *srcbuf, *dstbuf;
Uint32 srclen, dstlen;
srcbuf = (Sint16 *)sfx->data;
srclen = sfx->alen;
dstlen = (int)(srclen * steptable[pitch]);
// ensure that the new buffer is an even length
if ((dstlen % 2) == 0)
{
dstlen++;
}
dstbuf = (Sint16 *)malloc(dstlen);
// loop over output buffer. find corresponding input cell, copy over
for (outp = dstbuf; outp < dstbuf + dstlen/2; outp++)
{
inp = srcbuf + (int)((float)(outp - dstbuf) * srclen / dstlen);
*outp = *inp;
}
chunk->abuf = (Uint8 *)dstbuf;
chunk->alen = dstlen;
// [FG] do not connect pitch-shifted samples to a sound SFX
if (pitch == NORM_PITCH)
channelinfo[channel].sfx = NULL;
}
else
{
channelinfo[channel].data = sfx->data;
channelinfo[channel].chunk.abuf = sfx->data;
channelinfo[channel].chunk.alen = sfx->alen;
chunk->abuf = sfx->data;
chunk->alen = sfx->alen;
// Preserve sound SFX id
channelinfo[channel].id = sfx;
channelinfo[channel].sfx = sfx;
}
else
{
channelinfo[channel].chunk.abuf = sfx_data;
channelinfo[channel].chunk.alen = sfx_alen;
channelinfo[channel].id = NULL;
}
channelinfo[channel].data = chunk->abuf;
return true;
}
@ -412,57 +333,46 @@ static boolean addsfx(sfxinfo_t *sfx, int channel, int pitch)
int forceFlipPan;
//
// updateSoundParams
// I_UpdateSoundParams
//
// Changes sound parameters in response to stereo panning and relative location
// change.
//
static void updateSoundParams(int handle, int volume, int separation, int pitch)
void I_UpdateSoundParams(int channel, int volume, int separation)
{
int rightvol;
int leftvol;
if(!snd_init)
if (!snd_init)
return;
#ifdef RANGECHECK
if(handle < 0 || handle >= MAX_CHANNELS)
I_Error("I_UpdateSoundParams: handle out of range");
if (channel < 0 || channel >= MAX_CHANNELS)
I_Error("I_UpdateSoundParams: channel out of range");
#endif
// SoM 7/1/02: forceFlipPan accounted for here
if(forceFlipPan)
if (forceFlipPan)
separation = 254 - separation;
// [FG] linear stereo volume separation
leftvol = ((254 - separation) * volume) / 127;
rightvol = ((separation) * volume) / 127;
if (leftvol < 0) leftvol = 0;
else if (leftvol > 255) leftvol = 255;
if (rightvol < 0) rightvol = 0;
else if (rightvol > 255) rightvol = 255;
if (leftvol < 0)
leftvol = 0;
else if (leftvol > 255)
leftvol = 255;
if (rightvol < 0)
rightvol = 0;
else if (rightvol > 255)
rightvol = 255;
Mix_SetPanning(handle, leftvol, rightvol);
Mix_SetPanning(channel, leftvol, rightvol);
}
//
// SFX API
//
//
// I_UpdateSoundParams
//
// Update the sound parameters. Used to control volume,
// pan, and pitch changes such as when a player turns.
//
void I_UpdateSoundParams(int handle, int vol, int sep, int pitch)
{
if(!snd_init)
return;
updateSoundParams(handle, vol, sep, pitch);
}
// [FG] variable pitch bend range
int pitch_bend_range;
//
// I_SetChannels
@ -474,20 +384,18 @@ void I_UpdateSoundParams(int handle, int vol, int sep, int pitch)
void I_SetChannels(void)
{
int i;
int *steptablemid = steptable + 128;
const double base = pitch_bend_range / 100.0;
// Okay, reset internal mixing channels to zero.
for(i = 0; i < MAX_CHANNELS; ++i)
for (i = 0; i < MAX_CHANNELS; i++)
{
memset(&channelinfo[i], 0, sizeof(channel_info_t));
}
// This table provides step widths for pitch parameters.
for(i=-128 ; i<128 ; i++)
for (i = 0; i < arrlen(steptable); i++)
{
steptablemid[i] = (int)(pow(base, (double)i / 64.0) * 65536.0); // [FG] variable pitch bend range
steptable[i] = pow(base, (double)(2 * (i - NORM_PITCH)) / NORM_PITCH); // [FG] variable pitch bend range
}
}
@ -515,6 +423,8 @@ void I_SetSfxVolume(int volume)
//
int I_GetSfxLumpNum(sfxinfo_t *sfx)
{
if (sfx->lumpnum == -1)
{
char namebuf[16];
memset(namebuf, 0, sizeof(namebuf));
@ -522,7 +432,10 @@ int I_GetSfxLumpNum(sfxinfo_t *sfx)
strcpy(namebuf, "DS");
strcpy(namebuf+2, sfx->name);
return W_CheckNumForName(namebuf);
sfx->lumpnum = W_CheckNumForName(namebuf);
}
return sfx->lumpnum;
}
// Almost all of the sound code from this point on was
@ -534,45 +447,38 @@ int I_GetSfxLumpNum(sfxinfo_t *sfx)
//
// This function adds a sound to the list of currently
// active sounds, which is maintained as a given number
// of internal channels. Returns a handle.
// of internal channels. Returns a free channel.
//
int I_StartSound(sfxinfo_t *sound, int cnum, int vol, int sep, int pitch, int pri, boolean loop)
int I_StartSound(sfxinfo_t *sound, int vol, int sep, int pitch, boolean loop)
{
static unsigned int id = 0;
int handle;
int channel;
if(!snd_init)
if (!snd_init)
return -1;
// haleyjd: turns out this is too simplistic. see below.
/*
// SoM: reimplement hardware channel wrap-around
if(++handle >= MAX_CHANNELS)
handle = 0;
*/
// haleyjd 06/03/06: look for an unused hardware channel
for(handle = 0; handle < MAX_CHANNELS; ++handle)
for (channel = 0; channel < MAX_CHANNELS; channel++)
{
if(channelinfo[handle].data == NULL)
if (channelinfo[channel].data == NULL)
break;
}
// all used? don't play the sound. It's preferable to miss a sound
// than it is to cut off one already playing, which sounds weird.
if(handle == MAX_CHANNELS)
if (channel == MAX_CHANNELS)
return -1;
if(addsfx(sound, handle, pitch))
if (CacheSound(sound, channel, pitch))
{
channelinfo[handle].idnum = id++; // give the sound a unique id
Mix_PlayChannelTimed(handle, &channelinfo[handle].chunk, loop ? -1 : 0, -1);
updateSoundParams(handle, vol, sep, pitch);
channelinfo[channel].idnum = id++; // give the sound a unique id
Mix_PlayChannelTimed(channel, &channelinfo[channel].chunk, loop ? -1 : 0, -1);
I_UpdateSoundParams(channel, vol, sep);
}
else
handle = -1;
channel = -1;
return handle;
return channel;
}
//
@ -581,17 +487,17 @@ int I_StartSound(sfxinfo_t *sound, int cnum, int vol, int sep, int pitch, int pr
// Stop the sound. Necessary to prevent runaway chainsaw,
// and to stop rocket launches when an explosion occurs.
//
void I_StopSound(int handle)
void I_StopSound(int channel)
{
if(!snd_init)
if (!snd_init)
return;
#ifdef RANGECHECK
if(handle < 0 || handle >= MAX_CHANNELS)
I_Error("I_StopSound: handle out of range");
if (channel < 0 || channel >= MAX_CHANNELS)
I_Error("I_StopSound: channel out of range");
#endif
stopchan(handle);
StopChannel(channel);
}
//
@ -599,17 +505,17 @@ void I_StopSound(int handle)
//
// haleyjd: wow, this can actually do something in the Windows version :P
//
int I_SoundIsPlaying(int handle)
int I_SoundIsPlaying(int channel)
{
if(!snd_init)
if (!snd_init)
return false;
#ifdef RANGECHECK
if(handle < 0 || handle >= MAX_CHANNELS)
I_Error("I_SoundIsPlaying: handle out of range");
if (channel < 0 || channel >= MAX_CHANNELS)
I_Error("I_SoundIsPlaying: channel out of range");
#endif
return Mix_Playing(handle);
return Mix_Playing(channel);
}
//
@ -620,17 +526,17 @@ int I_SoundIsPlaying(int handle)
// that the higher-level sound code doesn't start updating sounds that have
// been displaced without it noticing.
//
int I_SoundID(int handle)
int I_SoundID(int channel)
{
if(!snd_init)
if (!snd_init)
return 0;
#ifdef RANGECHECK
if(handle < 0 || handle >= MAX_CHANNELS)
I_Error("I_SoundID: handle out of range\n");
if (channel < 0 || channel >= MAX_CHANNELS)
I_Error("I_SoundID: channel out of range\n");
#endif
return channelinfo[handle].idnum;
return channelinfo[channel].idnum;
}
// This function loops all active (internal) sound
@ -651,30 +557,18 @@ void I_UpdateSound(void)
// Check all channels to see if a sound has finished
for (i=0; i<MAX_CHANNELS; ++i)
for (i = 0; i < MAX_CHANNELS; i++)
{
if (channelinfo[i].data && !I_SoundIsPlaying(i))
{
// Sound has finished playing on this channel,
// but sound data has not been released to cache
stopchan(i);
StopChannel(i);
}
}
}
// This would be used to write out the mixbuffer
// during each game loop update.
// Updates sound buffer and audio device at runtime.
// It is called during Timer interrupt with SNDINTR.
void I_SubmitSound(void)
{
//this should no longer be necessary because
//allegro is doing all the sound mixing now
}
//
// I_ShutdownSound
//
@ -682,7 +576,7 @@ void I_SubmitSound(void)
//
void I_ShutdownSound(void)
{
if(snd_init)
if (snd_init)
{
Mix_CloseAudio();
snd_init = 0;
@ -718,19 +612,15 @@ static int GetSliceSize(void)
//
// I_InitSound
//
// SoM 9/14/02: Rewrite. code taken from prboom to use SDL_Mixer
//
void I_InitSound(void)
{
if(!nosfxparm || !nomusicparm)
if (!nosfxparm || !nomusicparm)
{
Uint16 mix_format;
int mix_channels;
printf("I_InitSound: ");
// haleyjd: the docs say we should do this
// In SDL2, SDL_InitSubSystem() and SDL_Init() are interchangeable.
SDL_SetHint(SDL_HINT_AUDIO_RESAMPLING_MODE, snd_resampling_mode);
if (SDL_Init(SDL_INIT_AUDIO) < 0)
{
printf("Couldn't initialize SDL audio: %s\n", SDL_GetError());
@ -761,7 +651,7 @@ void I_InitSound(void)
snd_init = true;
// [FG] precache all sound effects
if (!nosfxparm && precache_sounds)
if (!nosfxparm)
{
int i;
@ -772,9 +662,9 @@ void I_InitSound(void)
if (!S_sfx[i].name)
continue;
addsfx(&S_sfx[i], 0, NORM_PITCH);
CacheSound(&S_sfx[i], 0, NORM_PITCH);
}
stopchan(0);
StopChannel(0);
printf("done.\n");
}
}

View File

@ -45,11 +45,8 @@
#define S_STEREO_SWING (96<<FRACBITS)
extern int snd_samplerate;
extern char *snd_resampling_mode;
// [FG] precache all sound SFX
extern boolean precache_sounds;
// [FG] optional low-pass filter
extern boolean lowpass_filter;
// [FG] variable pitch bend range
extern int pitch_bend_range;
@ -58,7 +55,6 @@ void I_InitSound(void);
// ... update sound buffer and audio device at runtime...
void I_UpdateSound(void);
void I_SubmitSound(void);
// ... shut down and relase at program termination.
void I_ShutdownSound(void);
@ -74,8 +70,7 @@ void I_SetChannels(void);
int I_GetSfxLumpNum(sfxinfo_t *sfxinfo);
// Starts a sound in a particular sound channel.
int I_StartSound(sfxinfo_t *sound, int cnum, int vol, int sep, int pitch,
int pri, boolean loop);
int I_StartSound(sfxinfo_t *sound, int vol, int sep, int pitch, boolean loop);
// Stops a sound channel.
void I_StopSound(int handle);
@ -87,7 +82,7 @@ int I_SoundIsPlaying(int handle);
// Updates the volume, separation,
// and pitch of a sound channel.
void I_UpdateSoundParams(int handle, int vol, int sep, int pitch);
void I_UpdateSoundParams(int handle, int vol, int sep);
// haleyjd
int I_SoundID(int handle);

View File

@ -3948,7 +3948,7 @@ setup_menu_t gen_settings1[] = { // General Settings screen1
{"Number of Sound Channels", S_NUM|S_PRGWARN, m_null, M_X,
M_Y + gen1_sndchan*M_SPC, {"snd_channels"}},
{"Enable v1.1 Pitch Effects", S_YESNO, m_null, M_X,
{"Pitch-Shifted Sounds", S_YESNO, m_null, M_X,
M_Y + gen1_pitch*M_SPC, {"pitched_sounds"}},
// [FG] play sounds in full length

View File

@ -229,8 +229,8 @@ default_t defaults[] = {
{
"pitch_bend_range",
(config_t *) &pitch_bend_range, NULL,
{200}, {100,300}, number, ss_none, wad_yes,
"variable pitch bend range (100 none, 120 original, 200 Woof default)"
{120}, {100,300}, number, ss_none, wad_yes,
"variable pitch bend range (100 none, 120 default)"
},
{ // phares
@ -2258,20 +2258,18 @@ default_t defaults[] = {
"1 to enable fullscreen mode"
},
// [FG] precache all sound effects
{
"precache_sounds",
(config_t *) &precache_sounds, NULL,
{1}, {0, 1}, number, ss_gen, wad_no,
"1 to precache all sound effects"
"snd_samplerate",
(config_t *) &snd_samplerate, NULL,
{44100}, {11025, 96000}, number, ss_none, wad_no,
"audio device frequency in Hz"
},
// [FG] optional low-pass filter
{
"lowpass_filter",
(config_t *) &lowpass_filter, NULL,
{0}, {0, 1}, number, ss_none, wad_no,
"1 to apply low-pass filtering to all sounds effects"
"snd_resampling_mode",
(config_t *) &snd_resampling_mode, NULL,
{.s = "default"}, {0}, string, ss_none, wad_no,
"audio resampling mode (\"default\", \"fast\", \"medium\", \"best\")"
},
// [FG] play sounds in full length

View File

@ -428,7 +428,7 @@ static void S_StartSoundEx(const mobj_t *origin, int sfx_id, int loop_timeout)
sfx = sfx->link; // sf: skip thru link(s)
// Assigns the handle to one of the channels in the mix/output buffer.
handle = I_StartSound(sfx, cnum, volume, sep, pitch, priority, loop);
handle = I_StartSound(sfx, volume, sep, pitch, loop);
// haleyjd: check to see if the sound was started
if(handle >= 0)
@ -585,7 +585,7 @@ void S_UpdateSounds(const mobj_t *listener)
S_StopChannel(cnum);
else
{
I_UpdateSoundParams(c->handle, volume, sep, pitch);
I_UpdateSoundParams(c->handle, volume, sep);
c->priority = pri; // haleyjd
}
}

View File

@ -125,328 +125,343 @@ musicinfo_t S_music[] = {
// killough 12/98:
// Reimplemented 'singularity' flag, adjusting many sounds below
sfxinfo_t original_S_sfx[NUMSFX] = {
{ 0 }, // S_sfx[0] needs to be a dummy for odd reasons.
#define SOUND_LINK(n, s, p, l, i) \
{.name = n, \
.singularity = s, \
.priority = p, \
.link = l ? &original_S_sfx[l] : NULL, \
.pitch = i, \
.volume = -1, \
.data = NULL, \
.usefulness = -1, \
.lumpnum = -1, \
.alen = 0}
{ "pistol", sg_none, 64, 0, -1, -1, 0 },
{ "shotgn", sg_none, 64, 0, -1, -1, 0 },
{ "sgcock", sg_none, 64, 0, -1, -1, 0 },
{ "dshtgn", sg_none, 64, 0, -1, -1, 0 },
{ "dbopn", sg_none, 64, 0, -1, -1, 0 },
{ "dbcls", sg_none, 64, 0, -1, -1, 0 },
{ "dbload", sg_none, 64, 0, -1, -1, 0 },
{ "plasma", sg_none, 64, 0, -1, -1, 0 },
{ "bfg", sg_none, 64, 0, -1, -1, 0 },
{ "sawup", sg_none, 64, 0, -1, -1, 0 },
{ "sawidl", sg_none, 118, 0, -1, -1, 0 },
{ "sawful", sg_none, 64, 0, -1, -1, 0 },
{ "sawhit", sg_none, 64, 0, -1, -1, 0 },
{ "rlaunc", sg_none, 64, 0, -1, -1, 0 },
{ "rxplod", sg_none, 70, 0, -1, -1, 0 },
{ "firsht", sg_none, 70, 0, -1, -1, 0 },
{ "firxpl", sg_none, 70, 0, -1, -1, 0 },
{ "pstart", sg_none, 100, 0, -1, -1, 0 },
{ "pstop", sg_none, 100, 0, -1, -1, 0 },
{ "doropn", sg_none, 100, 0, -1, -1, 0 },
{ "dorcls", sg_none, 100, 0, -1, -1, 0 },
{ "stnmov", sg_none, 119, 0, -1, -1, 0 },
{ "swtchn", sg_none, 78, 0, -1, -1, 0 },
{ "swtchx", sg_none, 78, 0, -1, -1, 0 },
{ "plpain", sg_none, 96, 0, -1, -1, 0 },
{ "dmpain", sg_none, 96, 0, -1, -1, 0 },
{ "popain", sg_none, 96, 0, -1, -1, 0 },
{ "vipain", sg_none, 96, 0, -1, -1, 0 },
{ "mnpain", sg_none, 96, 0, -1, -1, 0 },
{ "pepain", sg_none, 96, 0, -1, -1, 0 },
{ "slop", sg_none, 78, 0, -1, -1, 0 },
{ "itemup", sg_itemup, 78, 0, -1, -1, 0 },
{ "wpnup", sg_wpnup, 78, 0, -1, -1, 0 },
{ "oof", sg_oof, 96, 0, -1, -1, 0 },
{ "telept", sg_none, 32, 0, -1, -1, 0 },
{ "posit1", sg_none, 98, 0, -1, -1, 0 },
{ "posit2", sg_none, 98, 0, -1, -1, 0 },
{ "posit3", sg_none, 98, 0, -1, -1, 0 },
{ "bgsit1", sg_none, 98, 0, -1, -1, 0 },
{ "bgsit2", sg_none, 98, 0, -1, -1, 0 },
{ "sgtsit", sg_none, 98, 0, -1, -1, 0 },
{ "cacsit", sg_none, 98, 0, -1, -1, 0 },
{ "brssit", sg_none, 94, 0, -1, -1, 0 },
{ "cybsit", sg_none, 92, 0, -1, -1, 0 },
{ "spisit", sg_none, 90, 0, -1, -1, 0 },
{ "bspsit", sg_none, 90, 0, -1, -1, 0 },
{ "kntsit", sg_none, 90, 0, -1, -1, 0 },
{ "vilsit", sg_none, 90, 0, -1, -1, 0 },
{ "mansit", sg_none, 90, 0, -1, -1, 0 },
{ "pesit", sg_none, 90, 0, -1, -1, 0 },
{ "sklatk", sg_none, 70, 0, -1, -1, 0 },
{ "sgtatk", sg_none, 70, 0, -1, -1, 0 },
{ "skepch", sg_none, 70, 0, -1, -1, 0 },
{ "vilatk", sg_none, 70, 0, -1, -1, 0 },
{ "claw", sg_none, 70, 0, -1, -1, 0 },
{ "skeswg", sg_none, 70, 0, -1, -1, 0 },
{ "pldeth", sg_none, 32, 0, -1, -1, 0 },
{ "pdiehi", sg_none, 32, 0, -1, -1, 0 },
{ "podth1", sg_none, 70, 0, -1, -1, 0 },
{ "podth2", sg_none, 70, 0, -1, -1, 0 },
{ "podth3", sg_none, 70, 0, -1, -1, 0 },
{ "bgdth1", sg_none, 70, 0, -1, -1, 0 },
{ "bgdth2", sg_none, 70, 0, -1, -1, 0 },
{ "sgtdth", sg_none, 70, 0, -1, -1, 0 },
{ "cacdth", sg_none, 70, 0, -1, -1, 0 },
{ "skldth", sg_none, 70, 0, -1, -1, 0 },
{ "brsdth", sg_none, 32, 0, -1, -1, 0 },
{ "cybdth", sg_none, 32, 0, -1, -1, 0 },
{ "spidth", sg_none, 32, 0, -1, -1, 0 },
{ "bspdth", sg_none, 32, 0, -1, -1, 0 },
{ "vildth", sg_none, 32, 0, -1, -1, 0 },
{ "kntdth", sg_none, 32, 0, -1, -1, 0 },
{ "pedth", sg_none, 32, 0, -1, -1, 0 },
{ "skedth", sg_none, 32, 0, -1, -1, 0 },
{ "posact", sg_none, 120, 0, -1, -1, 0 },
{ "bgact", sg_none, 120, 0, -1, -1, 0 },
{ "dmact", sg_none, 120, 0, -1, -1, 0 },
{ "bspact", sg_none, 100, 0, -1, -1, 0 },
{ "bspwlk", sg_none, 100, 0, -1, -1, 0 },
{ "vilact", sg_none, 100, 0, -1, -1, 0 },
{ "noway", sg_oof, 78, 0, -1, -1, 0 },
{ "barexp", sg_none, 60, 0, -1, -1, 0 },
{ "punch", sg_none, 64, 0, -1, -1, 0 },
{ "hoof", sg_none, 70, 0, -1, -1, 0 },
{ "metal", sg_none, 70, 0, -1, -1, 0 },
{ "chgun", sg_none, 64, &original_S_sfx[sfx_pistol], 150, 0, 0 },
{ "tink", sg_none, 60, 0, -1, -1, 0 },
{ "bdopn", sg_none, 100, 0, -1, -1, 0 },
{ "bdcls", sg_none, 100, 0, -1, -1, 0 },
{ "itmbk", sg_none, 100, 0, -1, -1, 0 },
{ "flame", sg_none, 32, 0, -1, -1, 0 },
{ "flamst", sg_none, 32, 0, -1, -1, 0 },
{ "getpow", sg_getpow, 60, 0, -1, -1, 0 },
{ "bospit", sg_none, 70, 0, -1, -1, 0 },
{ "boscub", sg_none, 70, 0, -1, -1, 0 },
{ "bossit", sg_none, 70, 0, -1, -1, 0 },
{ "bospn", sg_none, 70, 0, -1, -1, 0 },
{ "bosdth", sg_none, 70, 0, -1, -1, 0 },
{ "manatk", sg_none, 70, 0, -1, -1, 0 },
{ "mandth", sg_none, 70, 0, -1, -1, 0 },
{ "sssit", sg_none, 70, 0, -1, -1, 0 },
{ "ssdth", sg_none, 70, 0, -1, -1, 0 },
{ "keenpn", sg_none, 70, 0, -1, -1, 0 },
{ "keendt", sg_none, 70, 0, -1, -1, 0 },
{ "skeact", sg_none, 70, 0, -1, -1, 0 },
{ "skesit", sg_none, 70, 0, -1, -1, 0 },
{ "skeatk", sg_none, 70, 0, -1, -1, 0 },
{ "radio", sg_none, 60, 0, -1, -1, 0 },
#define SOUND(n, s, p) \
SOUND_LINK(n, s, p, 0, -1)
sfxinfo_t original_S_sfx[NUMSFX] = {
SOUND("none", sg_none, 0), // S_sfx[0] needs to be a dummy for odd reasons.
SOUND("pistol", sg_none, 64),
SOUND("shotgn", sg_none, 64),
SOUND("sgcock", sg_none, 64),
SOUND("dshtgn", sg_none, 64),
SOUND("dbopn", sg_none, 64),
SOUND("dbcls", sg_none, 64),
SOUND("dbload", sg_none, 64),
SOUND("plasma", sg_none, 64),
SOUND("bfg", sg_none, 64),
SOUND("sawup", sg_none, 64),
SOUND("sawidl", sg_none, 118),
SOUND("sawful", sg_none, 64),
SOUND("sawhit", sg_none, 64),
SOUND("rlaunc", sg_none, 64),
SOUND("rxplod", sg_none, 70),
SOUND("firsht", sg_none, 70),
SOUND("firxpl", sg_none, 70),
SOUND("pstart", sg_none, 100),
SOUND("pstop", sg_none, 100),
SOUND("doropn", sg_none, 100),
SOUND("dorcls", sg_none, 100),
SOUND("stnmov", sg_none, 119),
SOUND("swtchn", sg_none, 78),
SOUND("swtchx", sg_none, 78),
SOUND("plpain", sg_none, 96),
SOUND("dmpain", sg_none, 96),
SOUND("popain", sg_none, 96),
SOUND("vipain", sg_none, 96),
SOUND("mnpain", sg_none, 96),
SOUND("pepain", sg_none, 96),
SOUND("slop", sg_none, 78),
SOUND("itemup", sg_itemup, 78),
SOUND("wpnup", sg_wpnup, 78),
SOUND("oof", sg_oof, 96),
SOUND("telept", sg_none, 32),
SOUND("posit1", sg_none, 98),
SOUND("posit2", sg_none, 98),
SOUND("posit3", sg_none, 98),
SOUND("bgsit1", sg_none, 98),
SOUND("bgsit2", sg_none, 98),
SOUND("sgtsit", sg_none, 98),
SOUND("cacsit", sg_none, 98),
SOUND("brssit", sg_none, 94),
SOUND("cybsit", sg_none, 92),
SOUND("spisit", sg_none, 90),
SOUND("bspsit", sg_none, 90),
SOUND("kntsit", sg_none, 90),
SOUND("vilsit", sg_none, 90),
SOUND("mansit", sg_none, 90),
SOUND("pesit", sg_none, 90),
SOUND("sklatk", sg_none, 70),
SOUND("sgtatk", sg_none, 70),
SOUND("skepch", sg_none, 70),
SOUND("vilatk", sg_none, 70),
SOUND("claw", sg_none, 70),
SOUND("skeswg", sg_none, 70),
SOUND("pldeth", sg_none, 32),
SOUND("pdiehi", sg_none, 32),
SOUND("podth1", sg_none, 70),
SOUND("podth2", sg_none, 70),
SOUND("podth3", sg_none, 70),
SOUND("bgdth1", sg_none, 70),
SOUND("bgdth2", sg_none, 70),
SOUND("sgtdth", sg_none, 70),
SOUND("cacdth", sg_none, 70),
SOUND("skldth", sg_none, 70),
SOUND("brsdth", sg_none, 32),
SOUND("cybdth", sg_none, 32),
SOUND("spidth", sg_none, 32),
SOUND("bspdth", sg_none, 32),
SOUND("vildth", sg_none, 32),
SOUND("kntdth", sg_none, 32),
SOUND("pedth", sg_none, 32),
SOUND("skedth", sg_none, 32),
SOUND("posact", sg_none, 120),
SOUND("bgact", sg_none, 120),
SOUND("dmact", sg_none, 120),
SOUND("bspact", sg_none, 100),
SOUND("bspwlk", sg_none, 100),
SOUND("vilact", sg_none, 100),
SOUND("noway", sg_oof, 78),
SOUND("barexp", sg_none, 60),
SOUND("punch", sg_none, 64),
SOUND("hoof", sg_none, 70),
SOUND("metal", sg_none, 70),
SOUND_LINK("chgun", sg_none, 64, sfx_pistol, 150),
SOUND("tink", sg_none, 60),
SOUND("bdopn", sg_none, 100),
SOUND("bdcls", sg_none, 100),
SOUND("itmbk", sg_none, 100),
SOUND("flame", sg_none, 32),
SOUND("flamst", sg_none, 32),
SOUND("getpow", sg_getpow, 60),
SOUND("bospit", sg_none, 70),
SOUND("boscub", sg_none, 70),
SOUND("bossit", sg_none, 70),
SOUND("bospn", sg_none, 70),
SOUND("bosdth", sg_none, 70),
SOUND("manatk", sg_none, 70),
SOUND("mandth", sg_none, 70),
SOUND("sssit", sg_none, 70),
SOUND("ssdth", sg_none, 70),
SOUND("keenpn", sg_none, 70),
SOUND("keendt", sg_none, 70),
SOUND("skeact", sg_none, 70),
SOUND("skesit", sg_none, 70),
SOUND("skeatk", sg_none, 70),
SOUND("radio", sg_none, 60),
// killough 11/98: dog sounds
{ "dgsit", sg_none, 98, 0, -1, -1, 0 },
{ "dgatk", sg_none, 70, 0, -1, -1, 0 },
{ "dgact", sg_none, 120, 0, -1, -1, 0 },
{ "dgdth", sg_none, 70, 0, -1, -1, 0 },
{ "dgpain", sg_none, 96, 0, -1, -1, 0 },
SOUND("dgsit", sg_none, 98),
SOUND("dgatk", sg_none, 70),
SOUND("dgact", sg_none, 120),
SOUND("dgdth", sg_none, 70),
SOUND("dgpain", sg_none, 96),
// [crispy] play DSSECRET if available
{ "secret", sg_none, 100, 0, -1, -1, 0 },
SOUND("secret", sg_none, 100),
[500] = { "fre000", sg_none, 127, 0, -1, -1, 0 },
[501] = { "fre001", sg_none, 127, 0, -1, -1, 0 },
[502] = { "fre002", sg_none, 127, 0, -1, -1, 0 },
[503] = { "fre003", sg_none, 127, 0, -1, -1, 0 },
[504] = { "fre004", sg_none, 127, 0, -1, -1, 0 },
[505] = { "fre005", sg_none, 127, 0, -1, -1, 0 },
[506] = { "fre006", sg_none, 127, 0, -1, -1, 0 },
[507] = { "fre007", sg_none, 127, 0, -1, -1, 0 },
[508] = { "fre008", sg_none, 127, 0, -1, -1, 0 },
[509] = { "fre009", sg_none, 127, 0, -1, -1, 0 },
[510] = { "fre010", sg_none, 127, 0, -1, -1, 0 },
[511] = { "fre011", sg_none, 127, 0, -1, -1, 0 },
[512] = { "fre012", sg_none, 127, 0, -1, -1, 0 },
[513] = { "fre013", sg_none, 127, 0, -1, -1, 0 },
[514] = { "fre014", sg_none, 127, 0, -1, -1, 0 },
[515] = { "fre015", sg_none, 127, 0, -1, -1, 0 },
[516] = { "fre016", sg_none, 127, 0, -1, -1, 0 },
[517] = { "fre017", sg_none, 127, 0, -1, -1, 0 },
[518] = { "fre018", sg_none, 127, 0, -1, -1, 0 },
[519] = { "fre019", sg_none, 127, 0, -1, -1, 0 },
[520] = { "fre020", sg_none, 127, 0, -1, -1, 0 },
[521] = { "fre021", sg_none, 127, 0, -1, -1, 0 },
[522] = { "fre022", sg_none, 127, 0, -1, -1, 0 },
[523] = { "fre023", sg_none, 127, 0, -1, -1, 0 },
[524] = { "fre024", sg_none, 127, 0, -1, -1, 0 },
[525] = { "fre025", sg_none, 127, 0, -1, -1, 0 },
[526] = { "fre026", sg_none, 127, 0, -1, -1, 0 },
[527] = { "fre027", sg_none, 127, 0, -1, -1, 0 },
[528] = { "fre028", sg_none, 127, 0, -1, -1, 0 },
[529] = { "fre029", sg_none, 127, 0, -1, -1, 0 },
[530] = { "fre030", sg_none, 127, 0, -1, -1, 0 },
[531] = { "fre031", sg_none, 127, 0, -1, -1, 0 },
[532] = { "fre032", sg_none, 127, 0, -1, -1, 0 },
[533] = { "fre033", sg_none, 127, 0, -1, -1, 0 },
[534] = { "fre034", sg_none, 127, 0, -1, -1, 0 },
[535] = { "fre035", sg_none, 127, 0, -1, -1, 0 },
[536] = { "fre036", sg_none, 127, 0, -1, -1, 0 },
[537] = { "fre037", sg_none, 127, 0, -1, -1, 0 },
[538] = { "fre038", sg_none, 127, 0, -1, -1, 0 },
[539] = { "fre039", sg_none, 127, 0, -1, -1, 0 },
[540] = { "fre040", sg_none, 127, 0, -1, -1, 0 },
[541] = { "fre041", sg_none, 127, 0, -1, -1, 0 },
[542] = { "fre042", sg_none, 127, 0, -1, -1, 0 },
[543] = { "fre043", sg_none, 127, 0, -1, -1, 0 },
[544] = { "fre044", sg_none, 127, 0, -1, -1, 0 },
[545] = { "fre045", sg_none, 127, 0, -1, -1, 0 },
[546] = { "fre046", sg_none, 127, 0, -1, -1, 0 },
[547] = { "fre047", sg_none, 127, 0, -1, -1, 0 },
[548] = { "fre048", sg_none, 127, 0, -1, -1, 0 },
[549] = { "fre049", sg_none, 127, 0, -1, -1, 0 },
[550] = { "fre050", sg_none, 127, 0, -1, -1, 0 },
[551] = { "fre051", sg_none, 127, 0, -1, -1, 0 },
[552] = { "fre052", sg_none, 127, 0, -1, -1, 0 },
[553] = { "fre053", sg_none, 127, 0, -1, -1, 0 },
[554] = { "fre054", sg_none, 127, 0, -1, -1, 0 },
[555] = { "fre055", sg_none, 127, 0, -1, -1, 0 },
[556] = { "fre056", sg_none, 127, 0, -1, -1, 0 },
[557] = { "fre057", sg_none, 127, 0, -1, -1, 0 },
[558] = { "fre058", sg_none, 127, 0, -1, -1, 0 },
[559] = { "fre059", sg_none, 127, 0, -1, -1, 0 },
[560] = { "fre060", sg_none, 127, 0, -1, -1, 0 },
[561] = { "fre061", sg_none, 127, 0, -1, -1, 0 },
[562] = { "fre062", sg_none, 127, 0, -1, -1, 0 },
[563] = { "fre063", sg_none, 127, 0, -1, -1, 0 },
[564] = { "fre064", sg_none, 127, 0, -1, -1, 0 },
[565] = { "fre065", sg_none, 127, 0, -1, -1, 0 },
[566] = { "fre066", sg_none, 127, 0, -1, -1, 0 },
[567] = { "fre067", sg_none, 127, 0, -1, -1, 0 },
[568] = { "fre068", sg_none, 127, 0, -1, -1, 0 },
[569] = { "fre069", sg_none, 127, 0, -1, -1, 0 },
[570] = { "fre070", sg_none, 127, 0, -1, -1, 0 },
[571] = { "fre071", sg_none, 127, 0, -1, -1, 0 },
[572] = { "fre072", sg_none, 127, 0, -1, -1, 0 },
[573] = { "fre073", sg_none, 127, 0, -1, -1, 0 },
[574] = { "fre074", sg_none, 127, 0, -1, -1, 0 },
[575] = { "fre075", sg_none, 127, 0, -1, -1, 0 },
[576] = { "fre076", sg_none, 127, 0, -1, -1, 0 },
[577] = { "fre077", sg_none, 127, 0, -1, -1, 0 },
[578] = { "fre078", sg_none, 127, 0, -1, -1, 0 },
[579] = { "fre079", sg_none, 127, 0, -1, -1, 0 },
[580] = { "fre080", sg_none, 127, 0, -1, -1, 0 },
[581] = { "fre081", sg_none, 127, 0, -1, -1, 0 },
[582] = { "fre082", sg_none, 127, 0, -1, -1, 0 },
[583] = { "fre083", sg_none, 127, 0, -1, -1, 0 },
[584] = { "fre084", sg_none, 127, 0, -1, -1, 0 },
[585] = { "fre085", sg_none, 127, 0, -1, -1, 0 },
[586] = { "fre086", sg_none, 127, 0, -1, -1, 0 },
[587] = { "fre087", sg_none, 127, 0, -1, -1, 0 },
[588] = { "fre088", sg_none, 127, 0, -1, -1, 0 },
[589] = { "fre089", sg_none, 127, 0, -1, -1, 0 },
[590] = { "fre090", sg_none, 127, 0, -1, -1, 0 },
[591] = { "fre091", sg_none, 127, 0, -1, -1, 0 },
[592] = { "fre092", sg_none, 127, 0, -1, -1, 0 },
[593] = { "fre093", sg_none, 127, 0, -1, -1, 0 },
[594] = { "fre094", sg_none, 127, 0, -1, -1, 0 },
[595] = { "fre095", sg_none, 127, 0, -1, -1, 0 },
[596] = { "fre096", sg_none, 127, 0, -1, -1, 0 },
[597] = { "fre097", sg_none, 127, 0, -1, -1, 0 },
[598] = { "fre098", sg_none, 127, 0, -1, -1, 0 },
[599] = { "fre099", sg_none, 127, 0, -1, -1, 0 },
[600] = { "fre100", sg_none, 127, 0, -1, -1, 0 },
[601] = { "fre101", sg_none, 127, 0, -1, -1, 0 },
[602] = { "fre102", sg_none, 127, 0, -1, -1, 0 },
[603] = { "fre103", sg_none, 127, 0, -1, -1, 0 },
[604] = { "fre104", sg_none, 127, 0, -1, -1, 0 },
[605] = { "fre105", sg_none, 127, 0, -1, -1, 0 },
[606] = { "fre106", sg_none, 127, 0, -1, -1, 0 },
[607] = { "fre107", sg_none, 127, 0, -1, -1, 0 },
[608] = { "fre108", sg_none, 127, 0, -1, -1, 0 },
[609] = { "fre109", sg_none, 127, 0, -1, -1, 0 },
[610] = { "fre110", sg_none, 127, 0, -1, -1, 0 },
[611] = { "fre111", sg_none, 127, 0, -1, -1, 0 },
[612] = { "fre112", sg_none, 127, 0, -1, -1, 0 },
[613] = { "fre113", sg_none, 127, 0, -1, -1, 0 },
[614] = { "fre114", sg_none, 127, 0, -1, -1, 0 },
[615] = { "fre115", sg_none, 127, 0, -1, -1, 0 },
[616] = { "fre116", sg_none, 127, 0, -1, -1, 0 },
[617] = { "fre117", sg_none, 127, 0, -1, -1, 0 },
[618] = { "fre118", sg_none, 127, 0, -1, -1, 0 },
[619] = { "fre119", sg_none, 127, 0, -1, -1, 0 },
[620] = { "fre120", sg_none, 127, 0, -1, -1, 0 },
[621] = { "fre121", sg_none, 127, 0, -1, -1, 0 },
[622] = { "fre122", sg_none, 127, 0, -1, -1, 0 },
[623] = { "fre123", sg_none, 127, 0, -1, -1, 0 },
[624] = { "fre124", sg_none, 127, 0, -1, -1, 0 },
[625] = { "fre125", sg_none, 127, 0, -1, -1, 0 },
[626] = { "fre126", sg_none, 127, 0, -1, -1, 0 },
[627] = { "fre127", sg_none, 127, 0, -1, -1, 0 },
[628] = { "fre128", sg_none, 127, 0, -1, -1, 0 },
[629] = { "fre129", sg_none, 127, 0, -1, -1, 0 },
[630] = { "fre130", sg_none, 127, 0, -1, -1, 0 },
[631] = { "fre131", sg_none, 127, 0, -1, -1, 0 },
[632] = { "fre132", sg_none, 127, 0, -1, -1, 0 },
[633] = { "fre133", sg_none, 127, 0, -1, -1, 0 },
[634] = { "fre134", sg_none, 127, 0, -1, -1, 0 },
[635] = { "fre135", sg_none, 127, 0, -1, -1, 0 },
[636] = { "fre136", sg_none, 127, 0, -1, -1, 0 },
[637] = { "fre137", sg_none, 127, 0, -1, -1, 0 },
[638] = { "fre138", sg_none, 127, 0, -1, -1, 0 },
[639] = { "fre139", sg_none, 127, 0, -1, -1, 0 },
[640] = { "fre140", sg_none, 127, 0, -1, -1, 0 },
[641] = { "fre141", sg_none, 127, 0, -1, -1, 0 },
[642] = { "fre142", sg_none, 127, 0, -1, -1, 0 },
[643] = { "fre143", sg_none, 127, 0, -1, -1, 0 },
[644] = { "fre144", sg_none, 127, 0, -1, -1, 0 },
[645] = { "fre145", sg_none, 127, 0, -1, -1, 0 },
[646] = { "fre146", sg_none, 127, 0, -1, -1, 0 },
[647] = { "fre147", sg_none, 127, 0, -1, -1, 0 },
[648] = { "fre148", sg_none, 127, 0, -1, -1, 0 },
[649] = { "fre149", sg_none, 127, 0, -1, -1, 0 },
[650] = { "fre150", sg_none, 127, 0, -1, -1, 0 },
[651] = { "fre151", sg_none, 127, 0, -1, -1, 0 },
[652] = { "fre152", sg_none, 127, 0, -1, -1, 0 },
[653] = { "fre153", sg_none, 127, 0, -1, -1, 0 },
[654] = { "fre154", sg_none, 127, 0, -1, -1, 0 },
[655] = { "fre155", sg_none, 127, 0, -1, -1, 0 },
[656] = { "fre156", sg_none, 127, 0, -1, -1, 0 },
[657] = { "fre157", sg_none, 127, 0, -1, -1, 0 },
[658] = { "fre158", sg_none, 127, 0, -1, -1, 0 },
[659] = { "fre159", sg_none, 127, 0, -1, -1, 0 },
[660] = { "fre160", sg_none, 127, 0, -1, -1, 0 },
[661] = { "fre161", sg_none, 127, 0, -1, -1, 0 },
[662] = { "fre162", sg_none, 127, 0, -1, -1, 0 },
[663] = { "fre163", sg_none, 127, 0, -1, -1, 0 },
[664] = { "fre164", sg_none, 127, 0, -1, -1, 0 },
[665] = { "fre165", sg_none, 127, 0, -1, -1, 0 },
[666] = { "fre166", sg_none, 127, 0, -1, -1, 0 },
[667] = { "fre167", sg_none, 127, 0, -1, -1, 0 },
[668] = { "fre168", sg_none, 127, 0, -1, -1, 0 },
[669] = { "fre169", sg_none, 127, 0, -1, -1, 0 },
[670] = { "fre170", sg_none, 127, 0, -1, -1, 0 },
[671] = { "fre171", sg_none, 127, 0, -1, -1, 0 },
[672] = { "fre172", sg_none, 127, 0, -1, -1, 0 },
[673] = { "fre173", sg_none, 127, 0, -1, -1, 0 },
[674] = { "fre174", sg_none, 127, 0, -1, -1, 0 },
[675] = { "fre175", sg_none, 127, 0, -1, -1, 0 },
[676] = { "fre176", sg_none, 127, 0, -1, -1, 0 },
[677] = { "fre177", sg_none, 127, 0, -1, -1, 0 },
[678] = { "fre178", sg_none, 127, 0, -1, -1, 0 },
[679] = { "fre179", sg_none, 127, 0, -1, -1, 0 },
[680] = { "fre180", sg_none, 127, 0, -1, -1, 0 },
[681] = { "fre181", sg_none, 127, 0, -1, -1, 0 },
[682] = { "fre182", sg_none, 127, 0, -1, -1, 0 },
[683] = { "fre183", sg_none, 127, 0, -1, -1, 0 },
[684] = { "fre184", sg_none, 127, 0, -1, -1, 0 },
[685] = { "fre185", sg_none, 127, 0, -1, -1, 0 },
[686] = { "fre186", sg_none, 127, 0, -1, -1, 0 },
[687] = { "fre187", sg_none, 127, 0, -1, -1, 0 },
[688] = { "fre188", sg_none, 127, 0, -1, -1, 0 },
[689] = { "fre189", sg_none, 127, 0, -1, -1, 0 },
[690] = { "fre190", sg_none, 127, 0, -1, -1, 0 },
[691] = { "fre191", sg_none, 127, 0, -1, -1, 0 },
[692] = { "fre192", sg_none, 127, 0, -1, -1, 0 },
[693] = { "fre193", sg_none, 127, 0, -1, -1, 0 },
[694] = { "fre194", sg_none, 127, 0, -1, -1, 0 },
[695] = { "fre195", sg_none, 127, 0, -1, -1, 0 },
[696] = { "fre196", sg_none, 127, 0, -1, -1, 0 },
[697] = { "fre197", sg_none, 127, 0, -1, -1, 0 },
[698] = { "fre198", sg_none, 127, 0, -1, -1, 0 },
[699] = { "fre199", sg_none, 127, 0, -1, -1, 0 },
[500] = SOUND("fre000", sg_none, 127),
[501] = SOUND("fre001", sg_none, 127),
[502] = SOUND("fre002", sg_none, 127),
[503] = SOUND("fre003", sg_none, 127),
[504] = SOUND("fre004", sg_none, 127),
[505] = SOUND("fre005", sg_none, 127),
[506] = SOUND("fre006", sg_none, 127),
[507] = SOUND("fre007", sg_none, 127),
[508] = SOUND("fre008", sg_none, 127),
[509] = SOUND("fre009", sg_none, 127),
[510] = SOUND("fre010", sg_none, 127),
[511] = SOUND("fre011", sg_none, 127),
[512] = SOUND("fre012", sg_none, 127),
[513] = SOUND("fre013", sg_none, 127),
[514] = SOUND("fre014", sg_none, 127),
[515] = SOUND("fre015", sg_none, 127),
[516] = SOUND("fre016", sg_none, 127),
[517] = SOUND("fre017", sg_none, 127),
[518] = SOUND("fre018", sg_none, 127),
[519] = SOUND("fre019", sg_none, 127),
[520] = SOUND("fre020", sg_none, 127),
[521] = SOUND("fre021", sg_none, 127),
[522] = SOUND("fre022", sg_none, 127),
[523] = SOUND("fre023", sg_none, 127),
[524] = SOUND("fre024", sg_none, 127),
[525] = SOUND("fre025", sg_none, 127),
[526] = SOUND("fre026", sg_none, 127),
[527] = SOUND("fre027", sg_none, 127),
[528] = SOUND("fre028", sg_none, 127),
[529] = SOUND("fre029", sg_none, 127),
[530] = SOUND("fre030", sg_none, 127),
[531] = SOUND("fre031", sg_none, 127),
[532] = SOUND("fre032", sg_none, 127),
[533] = SOUND("fre033", sg_none, 127),
[534] = SOUND("fre034", sg_none, 127),
[535] = SOUND("fre035", sg_none, 127),
[536] = SOUND("fre036", sg_none, 127),
[537] = SOUND("fre037", sg_none, 127),
[538] = SOUND("fre038", sg_none, 127),
[539] = SOUND("fre039", sg_none, 127),
[540] = SOUND("fre040", sg_none, 127),
[541] = SOUND("fre041", sg_none, 127),
[542] = SOUND("fre042", sg_none, 127),
[543] = SOUND("fre043", sg_none, 127),
[544] = SOUND("fre044", sg_none, 127),
[545] = SOUND("fre045", sg_none, 127),
[546] = SOUND("fre046", sg_none, 127),
[547] = SOUND("fre047", sg_none, 127),
[548] = SOUND("fre048", sg_none, 127),
[549] = SOUND("fre049", sg_none, 127),
[550] = SOUND("fre050", sg_none, 127),
[551] = SOUND("fre051", sg_none, 127),
[552] = SOUND("fre052", sg_none, 127),
[553] = SOUND("fre053", sg_none, 127),
[554] = SOUND("fre054", sg_none, 127),
[555] = SOUND("fre055", sg_none, 127),
[556] = SOUND("fre056", sg_none, 127),
[557] = SOUND("fre057", sg_none, 127),
[558] = SOUND("fre058", sg_none, 127),
[559] = SOUND("fre059", sg_none, 127),
[560] = SOUND("fre060", sg_none, 127),
[561] = SOUND("fre061", sg_none, 127),
[562] = SOUND("fre062", sg_none, 127),
[563] = SOUND("fre063", sg_none, 127),
[564] = SOUND("fre064", sg_none, 127),
[565] = SOUND("fre065", sg_none, 127),
[566] = SOUND("fre066", sg_none, 127),
[567] = SOUND("fre067", sg_none, 127),
[568] = SOUND("fre068", sg_none, 127),
[569] = SOUND("fre069", sg_none, 127),
[570] = SOUND("fre070", sg_none, 127),
[571] = SOUND("fre071", sg_none, 127),
[572] = SOUND("fre072", sg_none, 127),
[573] = SOUND("fre073", sg_none, 127),
[574] = SOUND("fre074", sg_none, 127),
[575] = SOUND("fre075", sg_none, 127),
[576] = SOUND("fre076", sg_none, 127),
[577] = SOUND("fre077", sg_none, 127),
[578] = SOUND("fre078", sg_none, 127),
[579] = SOUND("fre079", sg_none, 127),
[580] = SOUND("fre080", sg_none, 127),
[581] = SOUND("fre081", sg_none, 127),
[582] = SOUND("fre082", sg_none, 127),
[583] = SOUND("fre083", sg_none, 127),
[584] = SOUND("fre084", sg_none, 127),
[585] = SOUND("fre085", sg_none, 127),
[586] = SOUND("fre086", sg_none, 127),
[587] = SOUND("fre087", sg_none, 127),
[588] = SOUND("fre088", sg_none, 127),
[589] = SOUND("fre089", sg_none, 127),
[590] = SOUND("fre090", sg_none, 127),
[591] = SOUND("fre091", sg_none, 127),
[592] = SOUND("fre092", sg_none, 127),
[593] = SOUND("fre093", sg_none, 127),
[594] = SOUND("fre094", sg_none, 127),
[595] = SOUND("fre095", sg_none, 127),
[596] = SOUND("fre096", sg_none, 127),
[597] = SOUND("fre097", sg_none, 127),
[598] = SOUND("fre098", sg_none, 127),
[599] = SOUND("fre099", sg_none, 127),
[600] = SOUND("fre100", sg_none, 127),
[601] = SOUND("fre101", sg_none, 127),
[602] = SOUND("fre102", sg_none, 127),
[603] = SOUND("fre103", sg_none, 127),
[604] = SOUND("fre104", sg_none, 127),
[605] = SOUND("fre105", sg_none, 127),
[606] = SOUND("fre106", sg_none, 127),
[607] = SOUND("fre107", sg_none, 127),
[608] = SOUND("fre108", sg_none, 127),
[609] = SOUND("fre109", sg_none, 127),
[610] = SOUND("fre110", sg_none, 127),
[611] = SOUND("fre111", sg_none, 127),
[612] = SOUND("fre112", sg_none, 127),
[613] = SOUND("fre113", sg_none, 127),
[614] = SOUND("fre114", sg_none, 127),
[615] = SOUND("fre115", sg_none, 127),
[616] = SOUND("fre116", sg_none, 127),
[617] = SOUND("fre117", sg_none, 127),
[618] = SOUND("fre118", sg_none, 127),
[619] = SOUND("fre119", sg_none, 127),
[620] = SOUND("fre120", sg_none, 127),
[621] = SOUND("fre121", sg_none, 127),
[622] = SOUND("fre122", sg_none, 127),
[623] = SOUND("fre123", sg_none, 127),
[624] = SOUND("fre124", sg_none, 127),
[625] = SOUND("fre125", sg_none, 127),
[626] = SOUND("fre126", sg_none, 127),
[627] = SOUND("fre127", sg_none, 127),
[628] = SOUND("fre128", sg_none, 127),
[629] = SOUND("fre129", sg_none, 127),
[630] = SOUND("fre130", sg_none, 127),
[631] = SOUND("fre131", sg_none, 127),
[632] = SOUND("fre132", sg_none, 127),
[633] = SOUND("fre133", sg_none, 127),
[634] = SOUND("fre134", sg_none, 127),
[635] = SOUND("fre135", sg_none, 127),
[636] = SOUND("fre136", sg_none, 127),
[637] = SOUND("fre137", sg_none, 127),
[638] = SOUND("fre138", sg_none, 127),
[639] = SOUND("fre139", sg_none, 127),
[640] = SOUND("fre140", sg_none, 127),
[641] = SOUND("fre141", sg_none, 127),
[642] = SOUND("fre142", sg_none, 127),
[643] = SOUND("fre143", sg_none, 127),
[644] = SOUND("fre144", sg_none, 127),
[645] = SOUND("fre145", sg_none, 127),
[646] = SOUND("fre146", sg_none, 127),
[647] = SOUND("fre147", sg_none, 127),
[648] = SOUND("fre148", sg_none, 127),
[649] = SOUND("fre149", sg_none, 127),
[650] = SOUND("fre150", sg_none, 127),
[651] = SOUND("fre151", sg_none, 127),
[652] = SOUND("fre152", sg_none, 127),
[653] = SOUND("fre153", sg_none, 127),
[654] = SOUND("fre154", sg_none, 127),
[655] = SOUND("fre155", sg_none, 127),
[656] = SOUND("fre156", sg_none, 127),
[657] = SOUND("fre157", sg_none, 127),
[658] = SOUND("fre158", sg_none, 127),
[659] = SOUND("fre159", sg_none, 127),
[660] = SOUND("fre160", sg_none, 127),
[661] = SOUND("fre161", sg_none, 127),
[662] = SOUND("fre162", sg_none, 127),
[663] = SOUND("fre163", sg_none, 127),
[664] = SOUND("fre164", sg_none, 127),
[665] = SOUND("fre165", sg_none, 127),
[666] = SOUND("fre166", sg_none, 127),
[667] = SOUND("fre167", sg_none, 127),
[668] = SOUND("fre168", sg_none, 127),
[669] = SOUND("fre169", sg_none, 127),
[670] = SOUND("fre170", sg_none, 127),
[671] = SOUND("fre171", sg_none, 127),
[672] = SOUND("fre172", sg_none, 127),
[673] = SOUND("fre173", sg_none, 127),
[674] = SOUND("fre174", sg_none, 127),
[675] = SOUND("fre175", sg_none, 127),
[676] = SOUND("fre176", sg_none, 127),
[677] = SOUND("fre177", sg_none, 127),
[678] = SOUND("fre178", sg_none, 127),
[679] = SOUND("fre179", sg_none, 127),
[680] = SOUND("fre180", sg_none, 127),
[681] = SOUND("fre181", sg_none, 127),
[682] = SOUND("fre182", sg_none, 127),
[683] = SOUND("fre183", sg_none, 127),
[684] = SOUND("fre184", sg_none, 127),
[685] = SOUND("fre185", sg_none, 127),
[686] = SOUND("fre186", sg_none, 127),
[687] = SOUND("fre187", sg_none, 127),
[688] = SOUND("fre188", sg_none, 127),
[689] = SOUND("fre189", sg_none, 127),
[690] = SOUND("fre190", sg_none, 127),
[691] = SOUND("fre191", sg_none, 127),
[692] = SOUND("fre192", sg_none, 127),
[693] = SOUND("fre193", sg_none, 127),
[694] = SOUND("fre194", sg_none, 127),
[695] = SOUND("fre195", sg_none, 127),
[696] = SOUND("fre196", sg_none, 127),
[697] = SOUND("fre197", sg_none, 127),
[698] = SOUND("fre198", sg_none, 127),
[699] = SOUND("fre199", sg_none, 127),
};
//----------------------------------------------------------------------------