mirror of
https://git.do.srb2.org/KartKrew/Kart-Public.git
synced 2024-12-28 05:11:34 +00:00
03fe3bdad2
SDL1.2 is dead, long live SDL
2031 lines
49 KiB
C
2031 lines
49 KiB
C
// Emacs style mode select -*- C++ -*-
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Copyright (C) 1993-1996 by id Software, Inc.
|
|
//
|
|
// This program is free software; you can redistribute it and/or
|
|
// modify it under the terms of the GNU General Public License
|
|
// as published by the Free Software Foundation; either version 2
|
|
// of the License, or (at your option) any later version.
|
|
//
|
|
// The source 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.
|
|
//-----------------------------------------------------------------------------
|
|
/// \file
|
|
/// \brief SDL interface for sound
|
|
|
|
#include <math.h>
|
|
#include "../doomdef.h"
|
|
|
|
#ifdef _MSC_VER
|
|
#pragma warning(disable : 4214 4244)
|
|
#endif
|
|
|
|
#if defined(HAVE_SDL) && SOUND==SOUND_SDL
|
|
|
|
#include "SDL.h"
|
|
|
|
#ifdef _MSC_VER
|
|
#pragma warning(default : 4214 4244)
|
|
#endif
|
|
|
|
#ifdef HAVE_MIXER
|
|
#include "SDL_mixer.h"
|
|
/* This is the version number macro for the current SDL_mixer version: */
|
|
#ifndef SDL_MIXER_COMPILEDVERSION
|
|
#define SDL_MIXER_COMPILEDVERSION \
|
|
SDL_VERSIONNUM(MIX_MAJOR_VERSION, MIX_MINOR_VERSION, MIX_PATCHLEVEL)
|
|
#endif
|
|
|
|
/* This macro will evaluate to true if compiled with SDL_mixer at least X.Y.Z */
|
|
#ifndef SDL_MIXER_VERSION_ATLEAST
|
|
#define SDL_MIXER_VERSION_ATLEAST(X, Y, Z) \
|
|
(SDL_MIXER_COMPILEDVERSION >= SDL_VERSIONNUM(X, Y, Z))
|
|
#endif
|
|
|
|
#else
|
|
#define MIX_CHANNELS 8
|
|
#endif
|
|
|
|
#if defined (_WIN32) && !defined (_WIN32_WCE) && !defined (_XBOX)
|
|
#include <direct.h>
|
|
#elif defined (__GNUC__)
|
|
#include <unistd.h>
|
|
#endif
|
|
#include "../z_zone.h"
|
|
|
|
#include "../m_swap.h"
|
|
#include "../i_system.h"
|
|
#include "../i_sound.h"
|
|
#include "../m_argv.h"
|
|
#include "../m_misc.h"
|
|
#include "../w_wad.h"
|
|
#include "../screen.h" //vid.WndParent
|
|
#include "../doomdef.h"
|
|
#include "../doomstat.h"
|
|
#include "../s_sound.h"
|
|
|
|
#include "../d_main.h"
|
|
|
|
#ifdef HW3SOUND
|
|
#include "../hardware/hw3dsdrv.h"
|
|
#include "../hardware/hw3sound.h"
|
|
#include "hwsym_sdl.h"
|
|
#endif
|
|
|
|
#ifdef HAVE_LIBGME
|
|
#include "gme/gme.h"
|
|
#endif
|
|
|
|
// The number of internal mixing channels,
|
|
// the samples calculated for each mixing step,
|
|
// the size of the 16bit, 2 hardware channel (stereo)
|
|
// mixing buffer, and the samplerate of the raw data.
|
|
|
|
// Needed for calling the actual sound output.
|
|
#if defined (_WIN32_WCE) || defined (DC) || defined (PSP) || defined(GP2X)
|
|
#define NUM_CHANNELS MIX_CHANNELS
|
|
#else
|
|
#define NUM_CHANNELS MIX_CHANNELS*4
|
|
#endif
|
|
|
|
#define INDEXOFSFX(x) ((sfxinfo_t *)x - S_sfx)
|
|
|
|
#if defined (_WIN32_WCE) || defined (DC) || defined (PSP)
|
|
static Uint16 samplecount = 512; //Alam: .5KB samplecount at 11025hz is 46.439909297052154195011337868481ms of buffer
|
|
#elif defined(GP2X)
|
|
static Uint16 samplecount = 128;
|
|
#else
|
|
static Uint16 samplecount = 1024; //Alam: 1KB samplecount at 22050hz is 46.439909297052154195011337868481ms of buffer
|
|
#endif
|
|
|
|
typedef struct chan_struct
|
|
{
|
|
// The channel data pointers, start and end.
|
|
Uint8 *data; //static unsigned char *channels[NUM_CHANNELS];
|
|
Uint8 *end; //static unsigned char *channelsend[NUM_CHANNELS];
|
|
|
|
// pitch
|
|
Uint32 realstep; // The channel step amount...
|
|
Uint32 step; //static UINT32 channelstep[NUM_CHANNELS];
|
|
Uint32 stepremainder; //static UINT32 channelstepremainder[NUM_CHANNELS];
|
|
Uint32 samplerate; // ... and a 0.16 bit remainder of last step.
|
|
|
|
// Time/gametic that the channel started playing,
|
|
// used to determine oldest, which automatically
|
|
// has lowest priority.
|
|
tic_t starttic; //static INT32 channelstart[NUM_CHANNELS];
|
|
|
|
// The sound handle, determined on registration,
|
|
// used to unregister/stop/modify,
|
|
INT32 handle; //static INT32 channelhandles[NUM_CHANNELS];
|
|
|
|
// SFX id of the playing sound effect.
|
|
void *id; // Used to catch duplicates (like chainsaw).
|
|
sfxenum_t sfxid; //static INT32 channelids[NUM_CHANNELS];
|
|
INT32 vol; //the channel volume
|
|
INT32 sep; //the channel pan
|
|
|
|
// Hardware left and right channel volume lookup.
|
|
Sint16* leftvol_lookup; //static INT32 *channelleftvol_lookup[NUM_CHANNELS];
|
|
Sint16* rightvol_lookup; //static INT32 *channelrightvol_lookup[NUM_CHANNELS];
|
|
} chan_t;
|
|
|
|
static chan_t channels[NUM_CHANNELS];
|
|
|
|
// Pitch to stepping lookup
|
|
static INT32 steptable[256];
|
|
|
|
// Volume lookups.
|
|
static Sint16 vol_lookup[128 * 256];
|
|
|
|
UINT8 sound_started = false;
|
|
static SDL_mutex *Snd_Mutex = NULL;
|
|
|
|
//SDL's Audio
|
|
static SDL_AudioSpec audio;
|
|
|
|
static SDL_bool musicStarted = SDL_FALSE;
|
|
#ifdef HAVE_MIXER
|
|
static SDL_mutex *Msc_Mutex = NULL;
|
|
/* FIXME: Make this file instance-specific */
|
|
#ifdef _arch_dreamcast
|
|
#define MIDI_PATH "/ram"
|
|
#elif defined(GP2X)
|
|
#define MIDI_PATH "/mnt/sd/srb2"
|
|
#define MIDI_PATH2 "/tmp/mnt/sd/srb2"
|
|
#else
|
|
#define MIDI_PATH srb2home
|
|
#if defined (__unix__) || defined(__APPLE__) || defined (UNIXCOMMON)
|
|
#define MIDI_PATH2 "/tmp"
|
|
#endif
|
|
#endif
|
|
#define MIDI_TMPFILE "srb2music"
|
|
#define MIDI_TMPFILE2 "srb2wav"
|
|
static INT32 musicvol = 62;
|
|
|
|
#if SDL_MIXER_VERSION_ATLEAST(1,2,2)
|
|
#define MIXER_POS //Mix_FadeInMusicPos in 1.2.2+
|
|
static void SDLCALL I_FinishMusic(void);
|
|
static double loopstartDig = 0.0l;
|
|
static SDL_bool loopingDig = SDL_FALSE;
|
|
static SDL_bool canlooping = SDL_TRUE;
|
|
#endif
|
|
|
|
#if SDL_MIXER_VERSION_ATLEAST(1,2,7)
|
|
#define USE_RWOPS // ok, USE_RWOPS is in here
|
|
#if defined (DC) || defined (_WIN32_WCE) || defined (_XBOX) //|| defined(_WIN32) || defined(GP2X)
|
|
#undef USE_RWOPS
|
|
#endif
|
|
#endif
|
|
|
|
#if SDL_MIXER_VERSION_ATLEAST(1,2,10)
|
|
//#define MIXER_INIT
|
|
#endif
|
|
|
|
#ifdef USE_RWOPS
|
|
static void * Smidi[2] = { NULL, NULL };
|
|
static SDL_bool canuseRW = SDL_TRUE;
|
|
#endif
|
|
static const char *fmidi[2] = { MIDI_TMPFILE, MIDI_TMPFILE2};
|
|
|
|
static const INT32 MIDIfade = 500;
|
|
static const INT32 Digfade = 0;
|
|
|
|
static Mix_Music *music[2] = { NULL, NULL };
|
|
#endif
|
|
|
|
typedef struct srb2audio_s {
|
|
void *userdata;
|
|
#ifdef HAVE_LIBGME
|
|
Music_Emu *gme_emu;
|
|
UINT8 gme_pause;
|
|
UINT8 gme_loop;
|
|
#endif
|
|
} srb2audio_t;
|
|
|
|
static srb2audio_t localdata;
|
|
|
|
static void Snd_LockAudio(void) //Alam: Lock audio data and uninstall audio callback
|
|
{
|
|
if (Snd_Mutex) SDL_LockMutex(Snd_Mutex);
|
|
else if (nosound) return;
|
|
else if (nomidimusic && nodigimusic
|
|
#ifdef HW3SOUND
|
|
&& hws_mode == HWS_DEFAULT_MODE
|
|
#endif
|
|
) SDL_LockAudio();
|
|
#ifdef HAVE_MIXER
|
|
else if (musicStarted) Mix_SetPostMix(NULL, NULL);
|
|
#endif
|
|
}
|
|
|
|
static void Snd_UnlockAudio(void) //Alam: Unlock audio data and reinstall audio callback
|
|
{
|
|
if (Snd_Mutex) SDL_UnlockMutex(Snd_Mutex);
|
|
else if (nosound) return;
|
|
else if (nomidimusic && nodigimusic
|
|
#ifdef HW3SOUND
|
|
&& hws_mode == HWS_DEFAULT_MODE
|
|
#endif
|
|
) SDL_UnlockAudio();
|
|
#ifdef HAVE_MIXER
|
|
else if (musicStarted) Mix_SetPostMix(audio.callback, audio.userdata);
|
|
#endif
|
|
}
|
|
|
|
FUNCMATH static inline Uint16 Snd_LowerRate(Uint16 sr)
|
|
{
|
|
if (sr <= audio.freq) // already lowered rate?
|
|
return sr; // good then
|
|
for (;sr > audio.freq;) // not good?
|
|
{ // then let see...
|
|
if (sr % 2) // can we div by half?
|
|
return sr; // no, just use the currect rate
|
|
sr /= 2; // we can? wonderful
|
|
} // let start over again
|
|
if (sr == audio.freq) // did we drop to the desired rate?
|
|
return sr; // perfect! but if not
|
|
return sr*2; // just keep it just above the output sample rate
|
|
}
|
|
|
|
#ifdef _MSC_VER
|
|
#pragma warning(disable : 4200)
|
|
#pragma pack(1)
|
|
#endif
|
|
|
|
typedef struct
|
|
{
|
|
Uint16 header; // 3?
|
|
Uint16 samplerate; // 11025+
|
|
Uint16 samples; // number of samples
|
|
Uint16 dummy; // 0
|
|
Uint8 data[0]; // data;
|
|
} ATTRPACK dssfx_t;
|
|
|
|
#ifdef _MSC_VER
|
|
#pragma pack()
|
|
#pragma warning(default : 4200)
|
|
#endif
|
|
|
|
//
|
|
// This function loads the sound data from the WAD lump,
|
|
// for single sound.
|
|
//
|
|
static void *getsfx(lumpnum_t sfxlump, size_t *len)
|
|
{
|
|
dssfx_t *sfx, *paddedsfx;
|
|
Uint16 sr , csr;
|
|
size_t size = *len;
|
|
SDL_AudioCVT sfxcvt;
|
|
|
|
sfx = (dssfx_t *)malloc(size);
|
|
if (sfx) W_ReadLump(sfxlump, (void *)sfx);
|
|
else return NULL;
|
|
sr = SHORT(sfx->samplerate);
|
|
csr = Snd_LowerRate(sr);
|
|
|
|
if (sr > csr && SDL_BuildAudioCVT(&sfxcvt, AUDIO_U8, 1, sr, AUDIO_U8, 1, csr))
|
|
{//Alam: Setup the AudioCVT for the SFX
|
|
|
|
sfxcvt.len = (INT32)size-8; //Alam: Chop off the header
|
|
sfxcvt.buf = malloc(sfxcvt.len * sfxcvt.len_mult); //Alam: make room
|
|
if (sfxcvt.buf) M_Memcpy(sfxcvt.buf, &(sfx->data), sfxcvt.len); //Alam: copy the sfx sample
|
|
|
|
if (sfxcvt.buf && SDL_ConvertAudio(&sfxcvt) == 0) //Alam: let convert it!
|
|
{
|
|
size = sfxcvt.len_cvt + 8;
|
|
*len = sfxcvt.len_cvt;
|
|
|
|
// Allocate from zone memory.
|
|
paddedsfx = (dssfx_t *) Z_Malloc(size, PU_SOUND, NULL);
|
|
|
|
// Now copy and pad.
|
|
M_Memcpy(paddedsfx->data, sfxcvt.buf, sfxcvt.len_cvt);
|
|
free(sfxcvt.buf);
|
|
M_Memcpy(paddedsfx,sfx,8);
|
|
paddedsfx->samplerate = SHORT(csr); // new freq
|
|
}
|
|
else //Alam: the convert failed, not needed or I couldn't malloc the buf
|
|
{
|
|
if (sfxcvt.buf) free(sfxcvt.buf);
|
|
*len = size - 8;
|
|
|
|
// Allocate from zone memory then copy and pad
|
|
paddedsfx = (dssfx_t *)M_Memcpy(Z_Malloc(size, PU_SOUND, NULL), sfx, size);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Pads the sound effect out to the mixing buffer size.
|
|
// The original realloc would interfere with zone memory.
|
|
*len = size - 8;
|
|
|
|
// Allocate from zone memory then copy and pad
|
|
paddedsfx = (dssfx_t *)M_Memcpy(Z_Malloc(size, PU_SOUND, NULL), sfx, size);
|
|
}
|
|
|
|
// Remove the cached lump.
|
|
free(sfx);
|
|
|
|
// Return allocated padded data.
|
|
return paddedsfx;
|
|
}
|
|
|
|
// used to (re)calculate channel params based on vol, sep, pitch
|
|
static void I_SetChannelParams(chan_t *c, INT32 vol, INT32 sep, INT32 step)
|
|
{
|
|
INT32 leftvol;
|
|
INT32 rightvol;
|
|
c->vol = vol;
|
|
c->sep = sep;
|
|
c->step = c->realstep = step;
|
|
|
|
if (step != steptable[128])
|
|
c->step += (((c->samplerate<<16)/audio.freq)-65536);
|
|
else if (c->samplerate != (unsigned)audio.freq)
|
|
c->step = ((c->samplerate<<16)/audio.freq);
|
|
// x^2 separation, that is, orientation/stereo.
|
|
// range is: 0 (left) - 255 (right)
|
|
|
|
// Volume arrives in range 0..255 and it must be in 0..cv_soundvolume...
|
|
vol = (vol * cv_soundvolume.value) >> 7;
|
|
// note: >> 6 would use almost the entire dynamical range, but
|
|
// then there would be no "dynamical room" for other sounds :-/
|
|
|
|
leftvol = vol - ((vol*sep*sep) >> 16); ///(256*256);
|
|
sep = 255 - sep;
|
|
rightvol = vol - ((vol*sep*sep) >> 16);
|
|
|
|
// Sanity check, clamp volume.
|
|
if (rightvol < 0)
|
|
rightvol = 0;
|
|
else if (rightvol > 127)
|
|
rightvol = 127;
|
|
if (leftvol < 0)
|
|
leftvol = 0;
|
|
else if (leftvol > 127)
|
|
leftvol = 127;
|
|
|
|
// Get the proper lookup table piece
|
|
// for this volume level
|
|
c->leftvol_lookup = &vol_lookup[leftvol*256];
|
|
c->rightvol_lookup = &vol_lookup[rightvol*256];
|
|
}
|
|
|
|
static INT32 FindChannel(INT32 handle)
|
|
{
|
|
INT32 i;
|
|
|
|
for (i = 0; i < NUM_CHANNELS; i++)
|
|
if (channels[i].handle == handle)
|
|
return i;
|
|
|
|
// not found
|
|
return -1;
|
|
}
|
|
|
|
//
|
|
// 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.
|
|
//
|
|
static INT32 addsfx(sfxenum_t sfxid, INT32 volume, INT32 step, INT32 seperation)
|
|
{
|
|
static UINT16 handlenums = 0;
|
|
INT32 i, slot, oldestnum = 0;
|
|
tic_t oldest = gametic;
|
|
|
|
// Play these sound effects only one at a time.
|
|
#if 1
|
|
if (
|
|
#if 0
|
|
sfxid == sfx_stnmov || sfxid == sfx_sawup || sfxid == sfx_sawidl || sfxid == sfx_sawful || sfxid == sfx_sawhit || sfxid == sfx_pistol
|
|
#else
|
|
( sfx_litng1 <= sfxid && sfxid >= sfx_litng4 )
|
|
|| sfxid == sfx_trfire || sfxid == sfx_alarm || sfxid == sfx_spin
|
|
|| sfxid == sfx_athun1 || sfxid == sfx_athun2 || sfxid == sfx_rainin
|
|
#endif
|
|
)
|
|
{
|
|
// Loop all channels, check.
|
|
for (i = 0; i < NUM_CHANNELS; i++)
|
|
{
|
|
// Active, and using the same SFX?
|
|
if ((channels[i].end) && (channels[i].sfxid == sfxid))
|
|
{
|
|
// Reset.
|
|
channels[i].end = NULL;
|
|
// We are sure that iff,
|
|
// there will only be one.
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// Loop all channels to find oldest SFX.
|
|
for (i = 0; (i < NUM_CHANNELS) && (channels[i].end); i++)
|
|
{
|
|
if (channels[i].starttic < oldest)
|
|
{
|
|
oldestnum = i;
|
|
oldest = channels[i].starttic;
|
|
}
|
|
}
|
|
|
|
// Tales from the cryptic.
|
|
// If we found a channel, fine.
|
|
// If not, we simply overwrite the first one, 0.
|
|
// Probably only happens at startup.
|
|
if (i == NUM_CHANNELS)
|
|
slot = oldestnum;
|
|
else
|
|
slot = i;
|
|
|
|
channels[slot].end = NULL;
|
|
// Okay, in the less recent channel,
|
|
// we will handle the new SFX.
|
|
// Set pointer to raw data.
|
|
channels[slot].data = (Uint8 *)S_sfx[sfxid].data;
|
|
channels[slot].samplerate = (channels[slot].data[3]<<8)+channels[slot].data[2];
|
|
channels[slot].data += 8; //Alam: offset of the sound header
|
|
|
|
while (FindChannel(handlenums)!=-1)
|
|
{
|
|
handlenums++;
|
|
// Reset current handle number, limited to 0..65535.
|
|
if (handlenums == UINT16_MAX)
|
|
handlenums = 0;
|
|
}
|
|
|
|
// Assign current handle number.
|
|
// Preserved so sounds could be stopped.
|
|
channels[slot].handle = handlenums;
|
|
|
|
// Restart steper
|
|
channels[slot].stepremainder = 0;
|
|
// Should be gametic, I presume.
|
|
channels[slot].starttic = gametic;
|
|
|
|
I_SetChannelParams(&channels[slot], volume, seperation, step);
|
|
|
|
// Preserve sound SFX id,
|
|
// e.g. for avoiding duplicates of chainsaw.
|
|
channels[slot].id = S_sfx[sfxid].data;
|
|
|
|
channels[slot].sfxid = sfxid;
|
|
|
|
// Set pointer to end of raw data.
|
|
channels[slot].end = channels[slot].data + S_sfx[sfxid].length;
|
|
|
|
|
|
// You tell me.
|
|
return handlenums;
|
|
}
|
|
|
|
//
|
|
// SFX API
|
|
// Note: this was called by S_Init.
|
|
// However, whatever they did in the
|
|
// old DPMS based DOS version, this
|
|
// were simply dummies in the Linux
|
|
// version.
|
|
// See soundserver initdata().
|
|
//
|
|
// Well... To keep compatibility with legacy doom, I have to call this in
|
|
// I_InitSound since it is not called in S_Init... (emanne@absysteme.fr)
|
|
|
|
static inline void I_SetChannels(void)
|
|
{
|
|
// Init internal lookups (raw data, mixing buffer, channels).
|
|
// This function sets up internal lookups used during
|
|
// the mixing process.
|
|
INT32 i;
|
|
INT32 j;
|
|
|
|
INT32 *steptablemid = steptable + 128;
|
|
|
|
if (nosound)
|
|
return;
|
|
|
|
// This table provides step widths for pitch parameters.
|
|
for (i = -128; i < 128; i++)
|
|
{
|
|
const double po = pow((double)(2.0l), (double)(i / 64.0l));
|
|
steptablemid[i] = (INT32)(po * 65536.0l);
|
|
}
|
|
|
|
// Generates volume lookup tables
|
|
// which also turn the unsigned samples
|
|
// into signed samples.
|
|
for (i = 0; i < 128; i++)
|
|
for (j = 0; j < 256; j++)
|
|
{
|
|
//From PrDoom
|
|
// proff - made this a little bit softer, because with
|
|
// full volume the sound clipped badly
|
|
vol_lookup[i * 256 + j] = (Sint16)((i * (j - 128) * 256) / 127);
|
|
}
|
|
}
|
|
|
|
void I_SetSfxVolume(UINT8 volume)
|
|
{
|
|
INT32 i;
|
|
|
|
(void)volume;
|
|
//Snd_LockAudio();
|
|
|
|
for (i = 0; i < NUM_CHANNELS; i++)
|
|
if (channels[i].end) I_SetChannelParams(&channels[i], channels[i].vol, channels[i].sep, channels[i].realstep);
|
|
|
|
//Snd_UnlockAudio();
|
|
}
|
|
|
|
void *I_GetSfx(sfxinfo_t *sfx)
|
|
{
|
|
if (sfx->lumpnum == LUMPERROR)
|
|
sfx->lumpnum = S_GetSfxLumpNum(sfx);
|
|
// else if (sfx->lumpnum != S_GetSfxLumpNum(sfx))
|
|
// I_FreeSfx(sfx);
|
|
|
|
#ifdef HW3SOUND
|
|
if (hws_mode != HWS_DEFAULT_MODE)
|
|
return HW3S_GetSfx(sfx);
|
|
#endif
|
|
|
|
if (sfx->data)
|
|
return sfx->data; //Alam: I have it done!
|
|
|
|
sfx->length = W_LumpLength(sfx->lumpnum);
|
|
|
|
return getsfx(sfx->lumpnum, &sfx->length);
|
|
|
|
}
|
|
|
|
void I_FreeSfx(sfxinfo_t * sfx)
|
|
{
|
|
// if (sfx->lumpnum<0)
|
|
// return;
|
|
|
|
#ifdef HW3SOUND
|
|
if (hws_mode != HWS_DEFAULT_MODE)
|
|
{
|
|
HW3S_FreeSfx(sfx);
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
size_t i;
|
|
|
|
for (i = 1; i < NUMSFX; i++)
|
|
{
|
|
// Alias? Example is the chaingun sound linked to pistol.
|
|
if (S_sfx[i].data == sfx->data)
|
|
{
|
|
if (S_sfx+i != sfx) S_sfx[i].data = NULL;
|
|
S_sfx[i].lumpnum = LUMPERROR;
|
|
S_sfx[i].length = 0;
|
|
}
|
|
}
|
|
//Snd_LockAudio(); //Alam: too much?
|
|
// Loop all channels, check.
|
|
for (i = 0; i < NUM_CHANNELS; i++)
|
|
{
|
|
// Active, and using the same SFX?
|
|
if (channels[i].end && channels[i].id == sfx->data)
|
|
{
|
|
channels[i].end = NULL; // Reset.
|
|
}
|
|
}
|
|
//Snd_UnlockAudio(); //Alam: too much?
|
|
Z_Free(sfx->data);
|
|
}
|
|
sfx->data = NULL;
|
|
sfx->lumpnum = LUMPERROR;
|
|
}
|
|
|
|
//
|
|
// Starting a sound means adding it
|
|
// to the current list of active sounds
|
|
// in the internal channels.
|
|
// As the SFX info struct contains
|
|
// e.g. a pointer to the raw data,
|
|
// it is ignored.
|
|
// As our sound handling does not handle
|
|
// priority, it is ignored.
|
|
// Pitching (that is, increased speed of playback)
|
|
// is set, but currently not used by mixing.
|
|
//
|
|
INT32 I_StartSound(sfxenum_t id, UINT8 vol, UINT8 sep, UINT8 pitch, UINT8 priority)
|
|
{
|
|
(void)priority;
|
|
(void)pitch;
|
|
|
|
if (nosound)
|
|
return 0;
|
|
|
|
if (S_sfx[id].data == NULL) return -1;
|
|
|
|
Snd_LockAudio();
|
|
id = addsfx(id, vol, steptable[pitch], sep);
|
|
Snd_UnlockAudio();
|
|
|
|
return id; // Returns a handle (not used).
|
|
}
|
|
|
|
void I_StopSound(INT32 handle)
|
|
{
|
|
// You need the handle returned by StartSound.
|
|
// Would be looping all channels,
|
|
// tracking down the handle,
|
|
// an setting the channel to zero.
|
|
INT32 i;
|
|
|
|
i = FindChannel(handle);
|
|
|
|
if (i != -1)
|
|
{
|
|
//Snd_LockAudio(); //Alam: too much?
|
|
channels[i].end = NULL;
|
|
//Snd_UnlockAudio(); //Alam: too much?
|
|
channels[i].handle = -1;
|
|
channels[i].starttic = 0;
|
|
}
|
|
|
|
}
|
|
|
|
boolean I_SoundIsPlaying(INT32 handle)
|
|
{
|
|
boolean isplaying = false;
|
|
int chan = FindChannel(handle);
|
|
if (chan != -1)
|
|
isplaying = (channels[chan].end != NULL);
|
|
return isplaying;
|
|
}
|
|
|
|
FUNCINLINE static ATTRINLINE void I_UpdateStream8S(Uint8 *stream, int len)
|
|
{
|
|
// Mix current sound data.
|
|
// Data, from raw sound
|
|
register Sint16 dr; // Right 8bit stream
|
|
register Uint8 sample; // Center 8bit sfx
|
|
register Sint16 dl; // Left 8bit stream
|
|
|
|
// Pointers in audio stream
|
|
Sint8 *rightout = (Sint8 *)stream; // currect right
|
|
Sint8 *leftout = rightout + 1;// currect left
|
|
const Uint8 step = 2; // Step in stream, left and right, thus two.
|
|
|
|
INT32 chan; // Mixing channel index.
|
|
|
|
// Determine end of the stream
|
|
len /= 2; // not 8bit mono samples, 8bit stereo ones
|
|
|
|
if (Snd_Mutex) SDL_LockMutex(Snd_Mutex);
|
|
|
|
// Mix sounds into the mixing buffer.
|
|
// Loop over len
|
|
while (len--)
|
|
{
|
|
// Reset left/right value.
|
|
dl = *leftout;
|
|
dr = *rightout;
|
|
|
|
// Love thy L2 cache - made this a loop.
|
|
// Now more channels could be set at compile time
|
|
// as well. Thus loop those channels.
|
|
for (chan = 0; chan < NUM_CHANNELS; chan++)
|
|
{
|
|
// Check channel, if active.
|
|
if (channels[chan].end)
|
|
{
|
|
#if 1
|
|
// Get the raw data from the channel.
|
|
sample = channels[chan].data[0];
|
|
#else
|
|
// linear filtering from PrDoom
|
|
sample = (((Uint32)channels[chan].data[0] *(0x10000 - channels[chan].stepremainder))
|
|
+ ((Uint32)channels[chan].data[1]) * (channels[chan].stepremainder))) >> 16;
|
|
#endif
|
|
// Add left and right part
|
|
// for this channel (sound)
|
|
// to the current data.
|
|
// Adjust volume accordingly.
|
|
dl = (Sint16)(dl+(channels[chan].leftvol_lookup[sample]>>8));
|
|
dr = (Sint16)(dr+(channels[chan].rightvol_lookup[sample]>>8));
|
|
// Increment stepage
|
|
channels[chan].stepremainder += channels[chan].step;
|
|
// Check whether we are done.
|
|
if (channels[chan].data + (channels[chan].stepremainder >> 16) >= channels[chan].end)
|
|
channels[chan].end = NULL;
|
|
else
|
|
{
|
|
// step to next sample
|
|
channels[chan].data += (channels[chan].stepremainder >> 16);
|
|
// Limit to LSB???
|
|
channels[chan].stepremainder &= 0xffff;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Clamp to range. Left hardware channel.
|
|
// Has been char instead of short.
|
|
|
|
if (dl > 0x7f)
|
|
*leftout = 0x7f;
|
|
else if (dl < -0x80)
|
|
*leftout = -0x80;
|
|
else
|
|
*leftout = (Sint8)dl;
|
|
|
|
// Same for right hardware channel.
|
|
if (dr > 0x7f)
|
|
*rightout = 0x7f;
|
|
else if (dr < -0x80)
|
|
*rightout = -0x80;
|
|
else
|
|
*rightout = (Sint8)dr;
|
|
|
|
// Increment current pointers in stream
|
|
leftout += step;
|
|
rightout += step;
|
|
|
|
}
|
|
if (Snd_Mutex) SDL_UnlockMutex(Snd_Mutex);
|
|
}
|
|
|
|
FUNCINLINE static ATTRINLINE void I_UpdateStream8M(Uint8 *stream, int len)
|
|
{
|
|
// Mix current sound data.
|
|
// Data, from raw sound
|
|
register Sint16 d; // Mono 8bit stream
|
|
register Uint8 sample; // Center 8bit sfx
|
|
|
|
// Pointers in audio stream
|
|
Sint8 *monoout = (Sint8 *)stream; // currect mono
|
|
const Uint8 step = 1; // Step in stream, left and right, thus two.
|
|
|
|
INT32 chan; // Mixing channel index.
|
|
|
|
// Determine end of the stream
|
|
//len /= 1; // not 8bit mono samples, 8bit mono ones?
|
|
|
|
if (Snd_Mutex) SDL_LockMutex(Snd_Mutex);
|
|
|
|
// Mix sounds into the mixing buffer.
|
|
// Loop over len
|
|
while (len--)
|
|
{
|
|
// Reset left/right value.
|
|
d = *monoout;
|
|
|
|
// Love thy L2 cache - made this a loop.
|
|
// Now more channels could be set at compile time
|
|
// as well. Thus loop those channels.
|
|
for (chan = 0; chan < NUM_CHANNELS; chan++)
|
|
{
|
|
// Check channel, if active.
|
|
if (channels[chan].end)
|
|
{
|
|
#if 1
|
|
// Get the raw data from the channel.
|
|
sample = channels[chan].data[0];
|
|
#else
|
|
// linear filtering from PrDoom
|
|
sample = (((Uint32)channels[chan].data[0] *(0x10000 - channels[chan].stepremainder))
|
|
+ ((Uint32)channels[chan].data[1]) * (channels[chan].stepremainder))) >> 16;
|
|
#endif
|
|
// Add left and right part
|
|
// for this channel (sound)
|
|
// to the current data.
|
|
// Adjust volume accordingly.
|
|
d = (Sint16)(d+((channels[chan].leftvol_lookup[sample] + channels[chan].rightvol_lookup[sample])>>9));
|
|
// Increment stepage
|
|
channels[chan].stepremainder += channels[chan].step;
|
|
// Check whether we are done.
|
|
if (channels[chan].data + (channels[chan].stepremainder >> 16) >= channels[chan].end)
|
|
channels[chan].end = NULL;
|
|
else
|
|
{
|
|
// step to next sample
|
|
channels[chan].data += (channels[chan].stepremainder >> 16);
|
|
// Limit to LSB???
|
|
channels[chan].stepremainder &= 0xffff;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Clamp to range. Left hardware channel.
|
|
// Has been char instead of short.
|
|
|
|
if (d > 0x7f)
|
|
*monoout = 0x7f;
|
|
else if (d < -0x80)
|
|
*monoout = -0x80;
|
|
else
|
|
*monoout = (Sint8)d;
|
|
|
|
// Increment current pointers in stream
|
|
monoout += step;
|
|
}
|
|
if (Snd_Mutex) SDL_UnlockMutex(Snd_Mutex);
|
|
}
|
|
|
|
FUNCINLINE static ATTRINLINE void I_UpdateStream16S(Uint8 *stream, int len)
|
|
{
|
|
// Mix current sound data.
|
|
// Data, from raw sound
|
|
register Sint32 dr; // Right 16bit stream
|
|
register Uint8 sample; // Center 8bit sfx
|
|
register Sint32 dl; // Left 16bit stream
|
|
|
|
// Pointers in audio stream
|
|
Sint16 *rightout = (Sint16 *)(void *)stream; // currect right
|
|
Sint16 *leftout = rightout + 1;// currect left
|
|
const Uint8 step = 2; // Step in stream, left and right, thus two.
|
|
|
|
INT32 chan; // Mixing channel index.
|
|
|
|
// Determine end of the stream
|
|
len /= 4; // not 8bit mono samples, 16bit stereo ones
|
|
|
|
if (Snd_Mutex) SDL_LockMutex(Snd_Mutex);
|
|
|
|
|
|
// Mix sounds into the mixing buffer.
|
|
// Loop over len
|
|
while (len--)
|
|
{
|
|
// Reset left/right value.
|
|
dl = *leftout;
|
|
dr = *rightout;
|
|
|
|
// Love thy L2 cache - made this a loop.
|
|
// Now more channels could be set at compile time
|
|
// as well. Thus loop those channels.
|
|
for (chan = 0; chan < NUM_CHANNELS; chan++)
|
|
{
|
|
// Check channel, if active.
|
|
if (channels[chan].end)
|
|
{
|
|
#if 1
|
|
// Get the raw data from the channel.
|
|
sample = channels[chan].data[0];
|
|
#else
|
|
// linear filtering from PrDoom
|
|
sample = (((Uint32)channels[chan].data[0] *(0x10000 - channels[chan].stepremainder))
|
|
+ ((Uint32)channels[chan].data[1]) * (channels[chan].stepremainder))) >> 16;
|
|
#endif
|
|
// Add left and right part
|
|
// for this channel (sound)
|
|
// to the current data.
|
|
// Adjust volume accordingly.
|
|
dl += channels[chan].leftvol_lookup[sample];
|
|
dr += channels[chan].rightvol_lookup[sample];
|
|
// Increment stepage
|
|
channels[chan].stepremainder += channels[chan].step;
|
|
// Check whether we are done.
|
|
if (channels[chan].data + (channels[chan].stepremainder >> 16) >= channels[chan].end)
|
|
channels[chan].end = NULL;
|
|
else
|
|
{
|
|
// step to next sample
|
|
channels[chan].data += (channels[chan].stepremainder >> 16);
|
|
// Limit to LSB???
|
|
channels[chan].stepremainder &= 0xffff;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Clamp to range. Left hardware channel.
|
|
// Has been char instead of short.
|
|
|
|
if (dl > 0x7fff)
|
|
*leftout = 0x7fff;
|
|
else if (dl < -0x8000)
|
|
*leftout = -0x8000;
|
|
else
|
|
*leftout = (Sint16)dl;
|
|
|
|
// Same for right hardware channel.
|
|
if (dr > 0x7fff)
|
|
*rightout = 0x7fff;
|
|
else if (dr < -0x8000)
|
|
*rightout = -0x8000;
|
|
else
|
|
*rightout = (Sint16)dr;
|
|
|
|
// Increment current pointers in stream
|
|
leftout += step;
|
|
rightout += step;
|
|
|
|
}
|
|
if (Snd_Mutex) SDL_UnlockMutex(Snd_Mutex);
|
|
}
|
|
|
|
FUNCINLINE static ATTRINLINE void I_UpdateStream16M(Uint8 *stream, int len)
|
|
{
|
|
// Mix current sound data.
|
|
// Data, from raw sound
|
|
register Sint32 d; // Mono 16bit stream
|
|
register Uint8 sample; // Center 8bit sfx
|
|
|
|
// Pointers in audio stream
|
|
Sint16 *monoout = (Sint16 *)(void *)stream; // currect mono
|
|
const Uint8 step = 1; // Step in stream, left and right, thus two.
|
|
|
|
INT32 chan; // Mixing channel index.
|
|
|
|
// Determine end of the stream
|
|
len /= 2; // not 8bit mono samples, 16bit mono ones
|
|
|
|
if (Snd_Mutex) SDL_LockMutex(Snd_Mutex);
|
|
|
|
|
|
// Mix sounds into the mixing buffer.
|
|
// Loop over len
|
|
while (len--)
|
|
{
|
|
// Reset left/right value.
|
|
d = *monoout;
|
|
|
|
// Love thy L2 cache - made this a loop.
|
|
// Now more channels could be set at compile time
|
|
// as well. Thus loop those channels.
|
|
for (chan = 0; chan < NUM_CHANNELS; chan++)
|
|
{
|
|
// Check channel, if active.
|
|
if (channels[chan].end)
|
|
{
|
|
#if 1
|
|
// Get the raw data from the channel.
|
|
sample = channels[chan].data[0];
|
|
#else
|
|
// linear filtering from PrDoom
|
|
sample = (((Uint32)channels[chan].data[0] *(0x10000 - channels[chan].stepremainder))
|
|
+ ((Uint32)channels[chan].data[1]) * (channels[chan].stepremainder))) >> 16;
|
|
#endif
|
|
// Add left and right part
|
|
// for this channel (sound)
|
|
// to the current data.
|
|
// Adjust volume accordingly.
|
|
d += (channels[chan].leftvol_lookup[sample] + channels[chan].rightvol_lookup[sample])>>1;
|
|
// Increment stepage
|
|
channels[chan].stepremainder += channels[chan].step;
|
|
// Check whether we are done.
|
|
if (channels[chan].data + (channels[chan].stepremainder >> 16) >= channels[chan].end)
|
|
channels[chan].end = NULL;
|
|
else
|
|
{
|
|
// step to next sample
|
|
channels[chan].data += (channels[chan].stepremainder >> 16);
|
|
// Limit to LSB???
|
|
channels[chan].stepremainder &= 0xffff;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Clamp to range. Left hardware channel.
|
|
// Has been char instead of short.
|
|
|
|
if (d > 0x7fff)
|
|
*monoout = 0x7fff;
|
|
else if (d < -0x8000)
|
|
*monoout = -0x8000;
|
|
else
|
|
*monoout = (Sint16)d;
|
|
|
|
// Increment current pointers in stream
|
|
monoout += step;
|
|
}
|
|
if (Snd_Mutex) SDL_UnlockMutex(Snd_Mutex);
|
|
}
|
|
|
|
#ifdef HAVE_LIBGME
|
|
static void I_UpdateSteamGME(Music_Emu *emu, INT16 *stream, int len, UINT8 looping)
|
|
{
|
|
#define GME_BUFFER_LEN 44100*2048
|
|
// Mix current sound data.
|
|
// Data, from raw sound
|
|
register Sint32 da;
|
|
|
|
static short gme_buffer[GME_BUFFER_LEN]; // a large buffer for gme
|
|
Sint16 *in = gme_buffer;
|
|
|
|
do
|
|
{
|
|
int out = min(GME_BUFFER_LEN, len);
|
|
if ( gme_play( emu, len, gme_buffer ) ) { } // ignore error
|
|
len -= out;
|
|
while (out--)
|
|
{
|
|
//Left
|
|
da = *in;
|
|
in++;
|
|
da += *stream;
|
|
stream++;
|
|
//Right
|
|
da = *in;
|
|
in++;
|
|
da += *stream;
|
|
stream++;
|
|
}
|
|
if (gme_track_ended( emu ))
|
|
{
|
|
if (looping)
|
|
gme_seek( emu, 0);
|
|
else
|
|
break;
|
|
}
|
|
} while ( len );
|
|
#undef GME_BUFFER_LEN
|
|
}
|
|
#endif
|
|
|
|
static void SDLCALL I_UpdateStream(void *userdata, Uint8 *stream, int len)
|
|
{
|
|
if (!sound_started || !userdata)
|
|
return;
|
|
|
|
memset(stream, 0x00, len); // only work in !AUDIO_U8, that needs 0x80
|
|
|
|
if ((audio.channels != 1 && audio.channels != 2) ||
|
|
(audio.format != AUDIO_S8 && audio.format != AUDIO_S16SYS))
|
|
; // no function to encode this type of stream
|
|
else if (audio.channels == 1 && audio.format == AUDIO_S8)
|
|
I_UpdateStream8M(stream, len);
|
|
else if (audio.channels == 2 && audio.format == AUDIO_S8)
|
|
I_UpdateStream8S(stream, len);
|
|
else if (audio.channels == 1 && audio.format == AUDIO_S16SYS)
|
|
I_UpdateStream16M(stream, len);
|
|
else if (audio.channels == 2 && audio.format == AUDIO_S16SYS)
|
|
{
|
|
I_UpdateStream16S(stream, len);
|
|
#ifdef HAVE_LIBGME
|
|
if (userdata)
|
|
{
|
|
srb2audio_t *sa_userdata = userdata;
|
|
if (!sa_userdata->gme_pause)
|
|
I_UpdateSteamGME(sa_userdata->gme_emu, (INT16 *)stream, len/4, sa_userdata->gme_loop);
|
|
}
|
|
#endif
|
|
|
|
}
|
|
}
|
|
|
|
void I_UpdateSoundParams(INT32 handle, UINT8 vol, UINT8 sep, UINT8 pitch)
|
|
{
|
|
// Would be using the handle to identify
|
|
// on which channel the sound might be active,
|
|
// and resetting the channel parameters.
|
|
|
|
INT32 i = FindChannel(handle);
|
|
|
|
if (i != -1 && channels[i].end)
|
|
{
|
|
//Snd_LockAudio(); //Alam: too much?
|
|
I_SetChannelParams(&channels[i], vol, sep, steptable[pitch]);
|
|
//Snd_UnlockAudio(); //Alam: too much?
|
|
}
|
|
|
|
}
|
|
|
|
#ifdef HW3SOUND
|
|
|
|
static void *soundso = NULL;
|
|
|
|
static INT32 Init3DSDriver(const char *soName)
|
|
{
|
|
if (soName) soundso = hwOpen(soName);
|
|
#if defined (_WIN32) && defined (_X86_) && !defined (STATIC3DS)
|
|
HW3DS.pfnStartup = hwSym("Startup@8",soundso);
|
|
HW3DS.pfnShutdown = hwSym("Shutdown@0",soundso);
|
|
HW3DS.pfnAddSfx = hwSym("AddSfx@4",soundso);
|
|
HW3DS.pfnAddSource = hwSym("AddSource@8",soundso);
|
|
HW3DS.pfnStartSource = hwSym("StartSource@4",soundso);
|
|
HW3DS.pfnStopSource = hwSym("StopSource@4",soundso);
|
|
HW3DS.pfnGetHW3DSVersion = hwSym("GetHW3DSVersion@0",soundso);
|
|
HW3DS.pfnBeginFrameUpdate = hwSym("BeginFrameUpdate@0",soundso);
|
|
HW3DS.pfnEndFrameUpdate = hwSym("EndFrameUpdate@0",soundso);
|
|
HW3DS.pfnIsPlaying = hwSym("IsPlaying@4",soundso);
|
|
HW3DS.pfnUpdateListener = hwSym("UpdateListener@8",soundso);
|
|
HW3DS.pfnUpdateSourceParms = hwSym("UpdateSourceParms@12",soundso);
|
|
HW3DS.pfnSetCone = hwSym("SetCone@8",soundso);
|
|
HW3DS.pfnSetGlobalSfxVolume = hwSym("SetGlobalSfxVolume@4",soundso);
|
|
HW3DS.pfnUpdate3DSource = hwSym("Update3DSource@8",soundso);
|
|
HW3DS.pfnReloadSource = hwSym("ReloadSource@8",soundso);
|
|
HW3DS.pfnKillSource = hwSym("KillSource@4",soundso);
|
|
HW3DS.pfnKillSfx = hwSym("KillSfx@4",soundso);
|
|
HW3DS.pfnGetHW3DSTitle = hwSym("GetHW3DSTitle@8",soundso);
|
|
#else
|
|
HW3DS.pfnStartup = hwSym("Startup",soundso);
|
|
HW3DS.pfnShutdown = hwSym("Shutdown",soundso);
|
|
HW3DS.pfnAddSfx = hwSym("AddSfx",soundso);
|
|
HW3DS.pfnAddSource = hwSym("AddSource",soundso);
|
|
HW3DS.pfnStartSource = hwSym("StartSource",soundso);
|
|
HW3DS.pfnStopSource = hwSym("StopSource",soundso);
|
|
HW3DS.pfnGetHW3DSVersion = hwSym("GetHW3DSVersion",soundso);
|
|
HW3DS.pfnBeginFrameUpdate = hwSym("BeginFrameUpdate",soundso);
|
|
HW3DS.pfnEndFrameUpdate = hwSym("EndFrameUpdate",soundso);
|
|
HW3DS.pfnIsPlaying = hwSym("IsPlaying",soundso);
|
|
HW3DS.pfnUpdateListener = hwSym("UpdateListener",soundso);
|
|
HW3DS.pfnUpdateSourceParms = hwSym("UpdateSourceParms",soundso);
|
|
HW3DS.pfnSetCone = hwSym("SetCone",soundso);
|
|
HW3DS.pfnSetGlobalSfxVolume = hwSym("SetGlobalSfxVolume",soundso);
|
|
HW3DS.pfnUpdate3DSource = hwSym("Update3DSource",soundso);
|
|
HW3DS.pfnReloadSource = hwSym("ReloadSource",soundso);
|
|
HW3DS.pfnKillSource = hwSym("KillSource",soundso);
|
|
HW3DS.pfnKillSfx = hwSym("KillSfx",soundso);
|
|
HW3DS.pfnGetHW3DSTitle = hwSym("GetHW3DSTitle",soundso);
|
|
#endif
|
|
|
|
// if (HW3DS.pfnUpdateListener2 && HW3DS.pfnUpdateListener2 != soundso)
|
|
return true;
|
|
// else
|
|
// return false;
|
|
}
|
|
#endif
|
|
|
|
void I_ShutdownSound(void)
|
|
{
|
|
if (nosound || !sound_started)
|
|
return;
|
|
|
|
CONS_Printf("I_ShutdownSound: ");
|
|
|
|
#ifdef HW3SOUND
|
|
if (hws_mode != HWS_DEFAULT_MODE)
|
|
{
|
|
HW3S_Shutdown();
|
|
hwClose(soundso);
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
if (nomidimusic && nodigimusic)
|
|
SDL_CloseAudio();
|
|
CONS_Printf("%s", M_GetText("shut down\n"));
|
|
sound_started = false;
|
|
SDL_QuitSubSystem(SDL_INIT_AUDIO);
|
|
if (Snd_Mutex)
|
|
SDL_DestroyMutex(Snd_Mutex);
|
|
Snd_Mutex = NULL;
|
|
}
|
|
|
|
void I_UpdateSound(void)
|
|
{
|
|
}
|
|
|
|
void I_StartupSound(void)
|
|
{
|
|
#ifdef HW3SOUND
|
|
const char *sdrv_name = NULL;
|
|
#endif
|
|
#ifndef HAVE_MIXER
|
|
nomidimusic = nodigimusic = true;
|
|
#endif
|
|
#ifdef DC
|
|
//nosound = true;
|
|
#ifdef HAVE_MIXER
|
|
nomidimusic = true;
|
|
nodigimusic = true;
|
|
#endif
|
|
#endif
|
|
|
|
memset(channels, 0, sizeof (channels)); //Alam: Clean it
|
|
|
|
audio.format = AUDIO_S16SYS;
|
|
audio.channels = 2;
|
|
audio.callback = I_UpdateStream;
|
|
audio.userdata = &localdata;
|
|
|
|
if (dedicated)
|
|
{
|
|
nosound = nomidimusic = nodigimusic = true;
|
|
return;
|
|
}
|
|
|
|
// Configure sound device
|
|
CONS_Printf("I_StartupSound:\n");
|
|
|
|
// Open the audio device
|
|
if (M_CheckParm ("-freq") && M_IsNextParm())
|
|
{
|
|
audio.freq = atoi(M_GetNextParm());
|
|
if (!audio.freq) audio.freq = cv_samplerate.value;
|
|
audio.samples = (Uint16)((samplecount/2)*(INT32)(audio.freq/11025)); //Alam: to keep it around the same XX ms
|
|
CONS_Printf (M_GetText(" requested frequency of %d hz\n"), audio.freq);
|
|
}
|
|
else
|
|
{
|
|
audio.samples = samplecount;
|
|
audio.freq = cv_samplerate.value;
|
|
}
|
|
|
|
if (M_CheckParm ("-mono"))
|
|
{
|
|
audio.channels = 1;
|
|
audio.samples /= 2;
|
|
}
|
|
|
|
#if defined (_PSP) && defined (HAVE_MIXER) // Bug in PSP's SDL_OpenAudio, can not open twice
|
|
I_SetChannels();
|
|
sound_started = true;
|
|
Snd_Mutex = SDL_CreateMutex();
|
|
#else
|
|
if (nosound)
|
|
#endif
|
|
return;
|
|
|
|
#ifdef HW3SOUND
|
|
#ifdef STATIC3DS
|
|
if (M_CheckParm("-3dsound") || M_CheckParm("-ds3d"))
|
|
{
|
|
hws_mode = HWS_OPENAL;
|
|
}
|
|
#elif defined (_WIN32)
|
|
if (M_CheckParm("-ds3d"))
|
|
{
|
|
hws_mode = HWS_DS3D;
|
|
sdrv_name = "s_ds3d.dll";
|
|
}
|
|
else if (M_CheckParm("-fmod3d"))
|
|
{
|
|
hws_mode = HWS_FMOD3D;
|
|
sdrv_name = "s_fmod.dll";
|
|
}
|
|
else if (M_CheckParm("-openal"))
|
|
{
|
|
hws_mode = HWS_OPENAL;
|
|
sdrv_name = "s_openal.dll";
|
|
}
|
|
#else
|
|
if (M_CheckParm("-fmod3d"))
|
|
{
|
|
hws_mode = HWS_FMOD3D;
|
|
sdrv_name = "./s_fmod.so";
|
|
}
|
|
else if (M_CheckParm("-openal"))
|
|
{
|
|
hws_mode = HWS_OPENAL;
|
|
sdrv_name = "./s_openal.so";
|
|
}
|
|
#endif
|
|
else if (M_CheckParm("-sounddriver") && M_IsNextParm())
|
|
{
|
|
hws_mode = HWS_OTHER;
|
|
sdrv_name = M_GetNextParm();
|
|
}
|
|
if (hws_mode != HWS_DEFAULT_MODE)
|
|
{
|
|
if (Init3DSDriver(sdrv_name))
|
|
{
|
|
snddev_t snddev;
|
|
|
|
//nosound = true;
|
|
//I_AddExitFunc(I_ShutdownSound);
|
|
snddev.bps = 16;
|
|
snddev.sample_rate = audio.freq;
|
|
snddev.numsfxs = NUMSFX;
|
|
#if defined (_WIN32) && !defined (_XBOX)
|
|
snddev.cooplevel = 0x00000002;
|
|
snddev.hWnd = vid.WndParent;
|
|
#endif
|
|
if (HW3S_Init(I_Error, &snddev))
|
|
{
|
|
audio.userdata = NULL;
|
|
CONS_Printf("%s", M_GetText(" Using 3D sound driver\n"));
|
|
return;
|
|
}
|
|
CONS_Printf("%s", M_GetText(" Failed loading 3D sound driver\n"));
|
|
// Falls back to default sound system
|
|
HW3S_Shutdown();
|
|
hwClose(soundso);
|
|
}
|
|
CONS_Printf("%s", M_GetText(" Failed loading 3D sound driver\n"));
|
|
hws_mode = HWS_DEFAULT_MODE;
|
|
}
|
|
#endif
|
|
if (!musicStarted && SDL_OpenAudio(&audio, &audio) < 0)
|
|
{
|
|
CONS_Printf("%s", M_GetText(" couldn't open audio with desired format\n"));
|
|
nosound = true;
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
//char ad[100];
|
|
//CONS_Printf(M_GetText(" Starting up with audio driver : %s\n"), SDL_AudioDriverName(ad, (int)sizeof ad));
|
|
}
|
|
samplecount = audio.samples;
|
|
CV_SetValue(&cv_samplerate, audio.freq);
|
|
CONS_Printf(M_GetText(" configured audio device with %d samples/slice at %ikhz(%dms buffer)\n"), samplecount, audio.freq/1000, (INT32) (((float)audio.samples * 1000.0f) / audio.freq));
|
|
// Finished initialization.
|
|
CONS_Printf("%s", M_GetText(" Sound module ready\n"));
|
|
//[segabor]
|
|
if (!musicStarted) SDL_PauseAudio(0);
|
|
//Mix_Pause(0);
|
|
I_SetChannels();
|
|
sound_started = true;
|
|
Snd_Mutex = SDL_CreateMutex();
|
|
}
|
|
|
|
//
|
|
// MUSIC API.
|
|
//
|
|
|
|
void I_ShutdownMIDIMusic(void)
|
|
{
|
|
nomidimusic = false;
|
|
if (nodigimusic) I_ShutdownMusic();
|
|
}
|
|
|
|
#ifdef HAVE_LIBGME
|
|
static void I_ShutdownGMEMusic(void)
|
|
{
|
|
Snd_LockAudio();
|
|
if (localdata.gme_emu)
|
|
gme_delete(localdata.gme_emu);
|
|
localdata.gme_emu = NULL;
|
|
Snd_UnlockAudio();
|
|
}
|
|
#endif
|
|
|
|
void I_ShutdownDigMusic(void)
|
|
{
|
|
nodigimusic = false;
|
|
if (nomidimusic) I_ShutdownMusic();
|
|
}
|
|
|
|
#ifdef HAVE_MIXER
|
|
static boolean LoadSong(void *data, size_t lumplength, size_t selectpos)
|
|
{
|
|
FILE *midfile;
|
|
const char *tempname;
|
|
#ifdef USE_RWOPS
|
|
if (canuseRW)
|
|
{
|
|
SDL_RWops *SDLRW;
|
|
void *olddata = Smidi[selectpos]; //quick shortcut to set
|
|
|
|
Z_Free(olddata); //free old memory
|
|
Smidi[selectpos] = NULL;
|
|
|
|
if (!data)
|
|
return olddata != NULL; //was there old data?
|
|
|
|
SDLRW = SDL_RWFromConstMem(data, (int)lumplength); //new RWops from Z_zone
|
|
if (!SDLRW) //ERROR while making RWops!
|
|
{
|
|
CONS_Printf(M_GetText("Couldn't load music lump: %s\n"), SDL_GetError());
|
|
Z_Free(data);
|
|
return false;
|
|
}
|
|
|
|
music[selectpos] = Mix_LoadMUS_RW(SDLRW); // new Mix_Chuck from RWops
|
|
if (music[selectpos])
|
|
Smidi[selectpos] = data; //all done
|
|
else //ERROR while making Mix_Chuck
|
|
{
|
|
CONS_Printf(M_GetText("Couldn't load music data: %s\n"), Mix_GetError());
|
|
Z_Free(data);
|
|
SDL_RWclose(SDLRW);
|
|
Smidi[selectpos] = NULL;
|
|
}
|
|
return true;
|
|
}
|
|
#endif
|
|
tempname = va("%s/%s", MIDI_PATH, fmidi[selectpos]);
|
|
|
|
if (!data)
|
|
{
|
|
if (FIL_FileExists(tempname))
|
|
return unlink(tempname)+1;
|
|
#ifdef MIDI_PATH2
|
|
else if (FIL_FileExists(tempname = va("%s/%s", MIDI_PATH2, fmidi[selectpos])))
|
|
return unlink(tempname)+1;
|
|
#endif
|
|
else
|
|
return false;
|
|
}
|
|
|
|
midfile = fopen(tempname, "wb");
|
|
|
|
#ifdef MIDI_PATH2
|
|
if (!midfile)
|
|
{
|
|
tempname = va("%s/%s", MIDI_PATH2, fmidi[selectpos]);
|
|
midfile = fopen(tempname, "wb");
|
|
}
|
|
#endif
|
|
|
|
if (!midfile)
|
|
{
|
|
CONS_Printf(M_GetText("Couldn't open file %s to write music in\n"), tempname);
|
|
Z_Free(data);
|
|
return false;
|
|
}
|
|
|
|
if (fwrite(data, lumplength, 1, midfile) == 0)
|
|
{
|
|
CONS_Printf(M_GetText("Couldn't write music into file %s because %s\n"), tempname, strerror(ferror(midfile)));
|
|
Z_Free(data);
|
|
fclose(midfile);
|
|
return false;
|
|
}
|
|
|
|
fclose(midfile);
|
|
|
|
Z_Free(data);
|
|
|
|
music[selectpos] = Mix_LoadMUS(tempname);
|
|
if (!music[selectpos]) //ERROR while making Mix_Chuck
|
|
{
|
|
CONS_Printf(M_GetText("Couldn't load music file %s: %s\n"), tempname, Mix_GetError());
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
#endif
|
|
|
|
|
|
void I_ShutdownMusic(void)
|
|
{
|
|
#ifdef HAVE_MIXER
|
|
if ((nomidimusic && nodigimusic) || !musicStarted)
|
|
return;
|
|
|
|
CONS_Printf("%s", M_GetText("I_ShutdownMusic: "));
|
|
|
|
I_UnRegisterSong(0);
|
|
I_StopDigSong();
|
|
Mix_CloseAudio();
|
|
#ifdef MIX_INIT
|
|
Mix_Quit();
|
|
#endif
|
|
CONS_Printf("%s", M_GetText("shut down\n"));
|
|
musicStarted = SDL_FALSE;
|
|
if (Msc_Mutex)
|
|
SDL_DestroyMutex(Msc_Mutex);
|
|
Msc_Mutex = NULL;
|
|
#endif
|
|
}
|
|
|
|
void I_InitMIDIMusic(void)
|
|
{
|
|
if (nodigimusic) I_InitMusic();
|
|
}
|
|
|
|
void I_InitDigMusic(void)
|
|
{
|
|
if (nomidimusic) I_InitMusic();
|
|
}
|
|
|
|
void I_InitMusic(void)
|
|
{
|
|
#ifdef HAVE_MIXER
|
|
char ad[100];
|
|
SDL_version MIXcompiled;
|
|
const SDL_version *MIXlinked;
|
|
#ifdef MIXER_INIT
|
|
const int mixstart = MIX_INIT_OGG;
|
|
int mixflags;
|
|
#endif
|
|
#endif
|
|
#ifdef HAVE_LIBGME
|
|
I_AddExitFunc(I_ShutdownGMEMusic);
|
|
#endif
|
|
|
|
if ((nomidimusic && nodigimusic) || dedicated)
|
|
return;
|
|
|
|
#ifdef HAVE_MIXER
|
|
MIX_VERSION(&MIXcompiled)
|
|
MIXlinked = Mix_Linked_Version();
|
|
I_OutputMsg("Compiled for SDL_mixer version: %d.%d.%d\n",
|
|
MIXcompiled.major, MIXcompiled.minor, MIXcompiled.patch);
|
|
#ifdef MIXER_POS
|
|
#ifndef _WII
|
|
if (MIXlinked->major == 1 && MIXlinked->minor == 2 && MIXlinked->patch < 7)
|
|
#endif
|
|
canlooping = SDL_FALSE;
|
|
#endif
|
|
#ifdef USE_RWOPS
|
|
if (M_CheckParm("-noRW"))
|
|
canuseRW = SDL_FALSE;
|
|
#endif
|
|
I_OutputMsg("Linked with SDL_mixer version: %d.%d.%d\n",
|
|
MIXlinked->major, MIXlinked->minor, MIXlinked->patch);
|
|
#if !(defined (DC) || defined (PSP) || defined(GP2X) || defined (WII))
|
|
if (audio.freq < 44100 && !M_CheckParm ("-freq")) //I want atleast 44Khz
|
|
{
|
|
audio.samples = (Uint16)(audio.samples*(INT32)(44100/audio.freq));
|
|
audio.freq = 44100; //Alam: to keep it around the same XX ms
|
|
}
|
|
#endif
|
|
|
|
if (sound_started
|
|
#ifdef HW3SOUND
|
|
&& hws_mode == HWS_DEFAULT_MODE
|
|
#endif
|
|
)
|
|
{
|
|
I_OutputMsg("Temp Shutdown of SDL Audio System");
|
|
SDL_CloseAudio();
|
|
I_OutputMsg(" Done\n");
|
|
}
|
|
|
|
CONS_Printf("%s", M_GetText("I_InitMusic:"));
|
|
|
|
#ifdef MIXER_INIT
|
|
mixflags = Mix_Init(mixstart);
|
|
if ((mixstart & MIX_INIT_FLAC) != (mixflags & MIX_INIT_FLAC))
|
|
{
|
|
CONS_Printf("%s", M_GetText(" Unable to load FLAC support\n"));
|
|
}
|
|
if ((mixstart & MIX_INIT_MOD ) != (mixflags & MIX_INIT_MOD ))
|
|
{
|
|
CONS_Printf("%s", M_GetText(" Unable to load MOD support\n"));
|
|
}
|
|
if ((mixstart & MIX_INIT_MP3 ) != (mixflags & MIX_INIT_MP3 ))
|
|
{
|
|
CONS_Printf("%s", M_GetText(" Unable to load MP3 support\n"));
|
|
}
|
|
if ((mixstart & MIX_INIT_OGG ) != (mixflags & MIX_INIT_OGG ))
|
|
{
|
|
CONS_Printf("%s", M_GetText(" Unable to load OGG support\n"));
|
|
}
|
|
#endif
|
|
|
|
if (Mix_OpenAudio(audio.freq, audio.format, audio.channels, audio.samples) < 0) //open_music(&audio)
|
|
{
|
|
CONS_Printf(M_GetText(" Unable to open music: %s\n"), Mix_GetError());
|
|
nomidimusic = nodigimusic = true;
|
|
if (sound_started
|
|
#ifdef HW3SOUND
|
|
&& hws_mode == HWS_DEFAULT_MODE
|
|
#endif
|
|
)
|
|
{
|
|
if (SDL_OpenAudio(&audio, NULL) < 0) //retry
|
|
{
|
|
CONS_Printf("%s", M_GetText(" couldn't open audio with desired format\n"));
|
|
nosound = true;
|
|
sound_started = false;
|
|
}
|
|
else
|
|
{
|
|
CONS_Printf(M_GetText(" Starting with audio driver : %s\n"), SDL_AudioDriverName(ad, (int)sizeof ad));
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
else
|
|
CONS_Printf(M_GetText(" Starting up with audio driver : %s with SDL_Mixer\n"), SDL_AudioDriverName(ad, (int)sizeof ad));
|
|
|
|
samplecount = audio.samples;
|
|
CV_SetValue(&cv_samplerate, audio.freq);
|
|
if (sound_started
|
|
#ifdef HW3SOUND
|
|
&& hws_mode == HWS_DEFAULT_MODE
|
|
#endif
|
|
)
|
|
I_OutputMsg(" Reconfigured SDL Audio System");
|
|
else I_OutputMsg(" Configured SDL_Mixer System");
|
|
I_OutputMsg(" with %d samples/slice at %ikhz(%dms buffer)\n", samplecount, audio.freq/1000, (INT32) ((audio.samples * 1000.0f) / audio.freq));
|
|
Mix_SetPostMix(audio.callback, audio.userdata); // after mixing music, add sound effects
|
|
Mix_Resume(-1);
|
|
CONS_Printf("%s", M_GetText("Music initialized\n"));
|
|
musicStarted = SDL_TRUE;
|
|
Msc_Mutex = SDL_CreateMutex();
|
|
#endif
|
|
}
|
|
|
|
boolean I_PlaySong(INT32 handle, boolean looping)
|
|
{
|
|
(void)handle;
|
|
#ifdef HAVE_MIXER
|
|
if (nomidimusic || !musicStarted || !music[handle])
|
|
return false;
|
|
|
|
#ifdef MIXER_POS
|
|
if (canlooping)
|
|
Mix_HookMusicFinished(NULL);
|
|
#endif
|
|
|
|
if (Mix_FadeInMusic(music[handle], looping ? -1 : 0, MIDIfade) == -1)
|
|
CONS_Printf(M_GetText("Couldn't play song because %s\n"), Mix_GetError());
|
|
else
|
|
{
|
|
Mix_VolumeMusic(musicvol);
|
|
return true;
|
|
}
|
|
#else
|
|
(void)looping;
|
|
#endif
|
|
return false;
|
|
}
|
|
|
|
static void I_PauseGME(void)
|
|
{
|
|
#ifdef HAVE_LIBGME
|
|
localdata.gme_pause = true;
|
|
#endif
|
|
}
|
|
|
|
void I_PauseSong(INT32 handle)
|
|
{
|
|
(void)handle;
|
|
I_PauseGME();
|
|
#ifdef HAVE_MIXER
|
|
if ((nomidimusic && nodigimusic) || !musicStarted)
|
|
return;
|
|
|
|
Mix_PauseMusic();
|
|
//I_StopSong(handle);
|
|
#endif
|
|
}
|
|
|
|
static void I_ResumeGME(void)
|
|
{
|
|
#ifdef HAVE_LIBGME
|
|
localdata.gme_pause = false;
|
|
#endif
|
|
}
|
|
|
|
void I_ResumeSong(INT32 handle)
|
|
{
|
|
(void)handle;
|
|
I_ResumeGME();
|
|
#ifdef HAVE_MIXER
|
|
if ((nomidimusic && nodigimusic) || !musicStarted)
|
|
return;
|
|
|
|
Mix_VolumeMusic(musicvol);
|
|
Mix_ResumeMusic();
|
|
//I_PlaySong(handle, true);
|
|
#endif
|
|
}
|
|
|
|
void I_StopSong(INT32 handle)
|
|
{
|
|
(void)handle;
|
|
#ifdef HAVE_MIXER
|
|
if (nomidimusic || !musicStarted)
|
|
return;
|
|
Mix_FadeOutMusic(MIDIfade);
|
|
#endif
|
|
}
|
|
|
|
void I_UnRegisterSong(INT32 handle)
|
|
{
|
|
#ifdef HAVE_MIXER
|
|
|
|
if (nomidimusic || !musicStarted)
|
|
return;
|
|
|
|
Mix_HaltMusic();
|
|
while (Mix_PlayingMusic())
|
|
;
|
|
|
|
if (music[handle])
|
|
Mix_FreeMusic(music[handle]);
|
|
music[handle] = NULL;
|
|
LoadSong(NULL, 0, handle);
|
|
#else
|
|
(void)handle;
|
|
#endif
|
|
}
|
|
|
|
INT32 I_RegisterSong(void *data, size_t len)
|
|
{
|
|
#ifdef HAVE_MIXER
|
|
if (nomidimusic || !musicStarted)
|
|
return false;
|
|
|
|
if (!LoadSong(data, len, 0))
|
|
return false;
|
|
|
|
if (music[0])
|
|
return true;
|
|
|
|
CONS_Printf(M_GetText("Couldn't load MIDI: %s\n"), Mix_GetError());
|
|
#else
|
|
(void)len;
|
|
(void)data;
|
|
#endif
|
|
return false;
|
|
}
|
|
|
|
void I_SetMIDIMusicVolume(UINT8 volume)
|
|
{
|
|
#ifdef HAVE_MIXER
|
|
if ((nomidimusic && nodigimusic) || !musicStarted)
|
|
return;
|
|
|
|
if (Msc_Mutex) SDL_LockMutex(Msc_Mutex);
|
|
musicvol = volume * 2;
|
|
if (Msc_Mutex) SDL_UnlockMutex(Msc_Mutex);
|
|
Mix_VolumeMusic(musicvol);
|
|
#else
|
|
(void)volume;
|
|
#endif
|
|
}
|
|
|
|
#ifdef HAVE_LIBGME
|
|
static void I_CleanupGME(void *userdata)
|
|
{
|
|
Z_Free(userdata);
|
|
}
|
|
#endif
|
|
|
|
static boolean I_StartGMESong(const char *musicname, boolean looping)
|
|
{
|
|
#ifdef HAVE_LIBGME
|
|
XBOXSTATIC char filename[9];
|
|
void *data;
|
|
lumpnum_t lumpnum;
|
|
size_t lumplength;
|
|
Music_Emu *emu;
|
|
const char* gme_err;
|
|
|
|
Snd_LockAudio();
|
|
if (localdata.gme_emu)
|
|
gme_delete(localdata.gme_emu);
|
|
localdata.gme_emu = NULL;
|
|
Snd_UnlockAudio();
|
|
|
|
snprintf(filename, sizeof filename, "o_%s", musicname);
|
|
|
|
lumpnum = W_CheckNumForName(filename);
|
|
|
|
if (lumpnum == LUMPERROR)
|
|
{
|
|
return false; // No music found. Oh well!
|
|
}
|
|
else
|
|
lumplength = W_LumpLength(lumpnum);
|
|
|
|
data = W_CacheLumpNum(lumpnum, PU_MUSIC);
|
|
|
|
gme_err = gme_open_data(data, (long)lumplength, &emu, audio.freq);
|
|
if (gme_err != NULL) {
|
|
//I_OutputMsg("I_StartGMESong: error %s\n",gme_err);
|
|
return false;
|
|
}
|
|
gme_set_user_data(emu, data);
|
|
gme_set_user_cleanup(emu, I_CleanupGME);
|
|
gme_start_track(emu, 0);
|
|
#ifdef HAVE_MIXER
|
|
gme_set_fade(emu, Digfade);
|
|
#endif
|
|
|
|
Snd_LockAudio();
|
|
localdata.gme_emu = emu;
|
|
localdata.gme_pause = false;
|
|
localdata.gme_loop = (UINT8)looping;
|
|
Snd_UnlockAudio();
|
|
|
|
return true;
|
|
#else
|
|
(void)musicname;
|
|
(void)looping;
|
|
#endif
|
|
return false;
|
|
}
|
|
|
|
boolean I_StartDigSong(const char *musicname, boolean looping)
|
|
{
|
|
#ifdef HAVE_MIXER
|
|
XBOXSTATIC char filename[9];
|
|
void *data;
|
|
lumpnum_t lumpnum;
|
|
size_t lumplength;
|
|
#endif
|
|
|
|
if(I_StartGMESong(musicname, looping))
|
|
return true;
|
|
|
|
#ifdef HAVE_MIXER
|
|
if (nodigimusic)
|
|
return false;
|
|
|
|
snprintf(filename, sizeof filename, "o_%s", musicname);
|
|
|
|
lumpnum = W_CheckNumForName(filename);
|
|
|
|
I_StopDigSong();
|
|
|
|
if (lumpnum == LUMPERROR)
|
|
{
|
|
// Alam_GBC: like in win32/win_snd.c: Graue 02-29-2004: don't worry about missing music, there might still be a MIDI
|
|
//I_OutputMsg("Music lump %s not found!\n", filename);
|
|
return false; // No music found. Oh well!
|
|
}
|
|
else
|
|
lumplength = W_LumpLength(lumpnum);
|
|
|
|
data = W_CacheLumpNum(lumpnum, PU_MUSIC);
|
|
|
|
if (Msc_Mutex) SDL_LockMutex(Msc_Mutex);
|
|
|
|
#ifdef MIXER_POS
|
|
if (canlooping && (loopingDig = looping) == SDL_TRUE && strcmp(data, "OggS") == 0)
|
|
looping = false; // Only on looping Ogg files, will we will do our own looping
|
|
|
|
// Scan the Ogg Vorbis file for the COMMENT= field for a custom
|
|
// loop point
|
|
if (!looping && loopingDig)
|
|
{
|
|
size_t scan;
|
|
const char *dataum = data;
|
|
XBOXSTATIC char looplength[64];
|
|
UINT32 loopstart = 0;
|
|
UINT8 newcount = 0;
|
|
|
|
Mix_HookMusicFinished(I_FinishMusic);
|
|
|
|
for (scan = 0; scan < lumplength; scan++)
|
|
{
|
|
if (*dataum++ == 'C'){
|
|
if (*dataum++ == 'O'){
|
|
if (*dataum++ == 'M'){
|
|
if (*dataum++ == 'M'){
|
|
if (*dataum++ == 'E'){
|
|
if (*dataum++ == 'N'){
|
|
if (*dataum++ == 'T'){
|
|
if (*dataum++ == '='){
|
|
if (*dataum++ == 'L'){
|
|
if (*dataum++ == 'O'){
|
|
if (*dataum++ == 'O'){
|
|
if (*dataum++ == 'P'){
|
|
if (*dataum++ == 'P'){
|
|
if (*dataum++ == 'O'){
|
|
if (*dataum++ == 'I'){
|
|
if (*dataum++ == 'N'){
|
|
if (*dataum++ == 'T'){
|
|
if (*dataum++ == '=')
|
|
{
|
|
|
|
while (*dataum != 1 && newcount != 63)
|
|
looplength[newcount++] = *dataum++;
|
|
|
|
looplength[newcount] = '\0';
|
|
|
|
loopstart = atoi(looplength);
|
|
|
|
}
|
|
else
|
|
dataum--;}
|
|
else
|
|
dataum--;}
|
|
else
|
|
dataum--;}
|
|
else
|
|
dataum--;}
|
|
else
|
|
dataum--;}
|
|
else
|
|
dataum--;}
|
|
else
|
|
dataum--;}
|
|
else
|
|
dataum--;}
|
|
else
|
|
dataum--;}
|
|
else
|
|
dataum--;}
|
|
else
|
|
dataum--;}
|
|
else
|
|
dataum--;}
|
|
else
|
|
dataum--;}
|
|
else
|
|
dataum--;}
|
|
else
|
|
dataum--;}
|
|
else
|
|
dataum--;}
|
|
else
|
|
dataum--;}
|
|
}
|
|
|
|
if (loopstart > 0)
|
|
{
|
|
loopstartDig = (double)((44.1l+loopstart) / 44100.0l); //8 PCM chucks off and PCM to secs
|
|
//#ifdef GP2X//#ifdef PARANOIA
|
|
//I_OutputMsg("I_StartDigSong: setting looping point to %ul PCMs(%f seconds)\n", loopstart, loopstartDig);
|
|
//#endif
|
|
}
|
|
else
|
|
{
|
|
looping = true; // loopingDig true, but couldn't find start loop point
|
|
}
|
|
}
|
|
else
|
|
loopstartDig = 0.0l;
|
|
#else
|
|
if (looping && strcmp(data, "OggS") == 0)
|
|
I_OutputMsg("I_StartDigSong: SRB2 was not compiled with looping music support(no Mix_FadeInMusicPos)\n");
|
|
#endif
|
|
|
|
if (!LoadSong(data, lumplength, 1))
|
|
{
|
|
if (Msc_Mutex) SDL_UnlockMutex(Msc_Mutex);
|
|
return false;
|
|
}
|
|
|
|
// Note: LoadSong() frees the data. Let's make sure
|
|
// we don't try to use the data again.
|
|
data = NULL;
|
|
|
|
if (Mix_FadeInMusic(music[1], looping ? -1 : 0, Digfade) == -1)
|
|
{
|
|
if (Msc_Mutex) SDL_UnlockMutex(Msc_Mutex);
|
|
I_OutputMsg("I_StartDigSong: Couldn't play song %s because %s\n", musicname, Mix_GetError());
|
|
return false;
|
|
}
|
|
Mix_VolumeMusic(musicvol);
|
|
|
|
if (Msc_Mutex) SDL_UnlockMutex(Msc_Mutex);
|
|
return true;
|
|
#else
|
|
(void)looping;
|
|
(void)musicname;
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
static void I_StopGME(void)
|
|
{
|
|
#ifdef HAVE_LIBGME
|
|
Snd_LockAudio();
|
|
gme_seek(localdata.gme_emu, 0);
|
|
Snd_UnlockAudio();
|
|
#endif
|
|
}
|
|
|
|
void I_StopDigSong(void)
|
|
{
|
|
I_StopGME();
|
|
#ifdef HAVE_MIXER
|
|
if (nodigimusic)
|
|
return;
|
|
|
|
#ifdef MIXER_POS
|
|
if (canlooping)
|
|
Mix_HookMusicFinished(NULL);
|
|
#endif
|
|
|
|
Mix_HaltMusic();
|
|
while (Mix_PlayingMusic())
|
|
;
|
|
|
|
if (music[1])
|
|
Mix_FreeMusic(music[1]);
|
|
music[1] = NULL;
|
|
LoadSong(NULL, 0, 1);
|
|
#endif
|
|
}
|
|
|
|
void I_SetDigMusicVolume(UINT8 volume)
|
|
{
|
|
I_SetMIDIMusicVolume(volume);
|
|
}
|
|
|
|
boolean I_SetSongSpeed(float speed)
|
|
{
|
|
|
|
(void)speed;
|
|
return false;
|
|
}
|
|
|
|
boolean I_SetSongTrack(int track)
|
|
{
|
|
(void)track;
|
|
return false;
|
|
}
|
|
|
|
#ifdef MIXER_POS
|
|
static void SDLCALL I_FinishMusic(void)
|
|
{
|
|
if (!music[1])
|
|
return;
|
|
else if (Msc_Mutex) SDL_LockMutex(Msc_Mutex);
|
|
// I_OutputMsg("I_FinishMusic: Loopping song to %g seconds\n", loopstartDig);
|
|
|
|
if (Mix_FadeInMusicPos(music[1], loopstartDig ? 0 : -1, Digfade, loopstartDig) == 0)
|
|
Mix_VolumeMusic(musicvol);
|
|
else
|
|
I_OutputMsg("I_FinishMusic: Couldn't loop song because %s\n", Mix_GetError());
|
|
|
|
if (Msc_Mutex) SDL_UnlockMutex(Msc_Mutex);
|
|
}
|
|
#endif
|
|
#endif //HAVE_SDL
|