mirror of
https://github.com/kevinbentley/Descent3.git
synced 2026-04-13 20:00:01 -04:00
This definition was used to control the accessibility of some class members, changing protected qualifiers to public. This introduced unnecessary coupling between components and headers. All conditional access specifiers have been set to public, which should not be a problem given the low number of classes that actually used affected members. Another albeit more complex solution could have been to use friend classes.
3566 lines
106 KiB
C++
3566 lines
106 KiB
C++
/*
|
|
* Descent 3
|
|
* Copyright (C) 2024 Parallax Software
|
|
*
|
|
* 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 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
--- HISTORICAL COMMENTS FOLLOW ---
|
|
|
|
* $Logfile: /DescentIII/Main/dd_sndlib/Ds3dlib.cpp $
|
|
* $Revision: 149 $
|
|
* $Date: 9/27/99 5:38p $
|
|
* $Author: Samir $
|
|
*
|
|
* DirectSound(2d and 3d) implementation of the Descent III low-level sound interface
|
|
*
|
|
* $Log: /DescentIII/Main/dd_sndlib/Ds3dlib.cpp $
|
|
*
|
|
* 149 9/27/99 5:38p Samir
|
|
* EAX 2.0->1.0 compatibility checkin.
|
|
*
|
|
* 148 8/23/99 5:29p Samir
|
|
* incremental EAX 2.0 checkin
|
|
*
|
|
* 147 8/13/99 2:00p Samir
|
|
* more aureal and geometry fixes.
|
|
*
|
|
* 146 5/23/99 12:48a Samir
|
|
* decreased rolloff factor of 3d sounds under 3d sound mixers from 0.75
|
|
* to 0.5
|
|
*
|
|
* 145 5/20/99 6:23p Kevin
|
|
* minor speed up of software mixer and fix for memory debugging
|
|
*
|
|
* 144 5/20/99 1:00a Samir
|
|
* changes in ordering of EAX and NONE mixers.
|
|
*
|
|
* 143 5/09/99 7:09p Samir
|
|
* fixed sound card selection (enumeration) problems.
|
|
*
|
|
* 142 5/07/99 5:39p Samir
|
|
* better error checking for CheckAndForceDataAlloc for PageInSound.
|
|
*
|
|
* 141 5/03/99 3:12a Samir
|
|
* fixed up aureal so it works (a little slow though...)
|
|
*
|
|
* 140 5/01/99 10:25p Jeff
|
|
* (samir) fixed crash bug when alt-tabbing,inserting cds,etc
|
|
*
|
|
* 139 4/29/99 4:36p Kevin
|
|
* fixed a problem with low quality sounds & the optimizd software mixer
|
|
*
|
|
* 138 4/29/99 3:01p Samir
|
|
* added code for direct sound mixers only (and function for Aureal
|
|
* really) that will use direct sound looping for simple loops.
|
|
*
|
|
* 137 4/27/99 7:08p Kevin
|
|
* optimized software mixer!
|
|
*
|
|
* 136 4/27/99 6:21p Samir
|
|
* if callback gets a NULL guid, just return, assume that the sound device
|
|
* is the default?
|
|
*
|
|
* 135 4/27/99 5:19p Samir
|
|
* mprintf change.
|
|
*
|
|
* 134 4/27/99 2:10p Samir
|
|
* added code to set the desired sound card given the descriptive name of
|
|
* a sound card.
|
|
*
|
|
* 133 4/25/99 9:52p Samir
|
|
* fixed looping sequencing bug with thread for direct sound mixers.
|
|
* SSF_PLAY_LOOPING must be set before any buffer filling occurs,
|
|
* otherwise bad things happen with very small loops....
|
|
*
|
|
* 132 4/23/99 7:51p Samir
|
|
* looping fixes for directsound
|
|
*
|
|
* 131 4/22/99 10:33p Samir
|
|
* modifications so that DirectSound mixers use one thread for all looping
|
|
* and streaming sounds. It worked without crashing for about twenty
|
|
* minutes of playing from level 1 to level 2 of D3. We'll see.
|
|
*
|
|
* 130 4/18/99 5:37p Kevin
|
|
* Very simple optimization for the software mixer
|
|
*
|
|
* 129 4/13/99 4:15p Jason
|
|
* took out register keyword because it was hurting performance
|
|
*
|
|
* 128 4/13/99 4:09p Samir
|
|
* more priority stuff.
|
|
*
|
|
*
|
|
* 126 4/12/99 7:14p Samir
|
|
* prioritization code added.
|
|
*
|
|
* 125 4/10/99 5:08p Samir
|
|
* took out obsolete data from play_information structure that should save
|
|
* around 70 bytes per instance.
|
|
*
|
|
* 124 4/09/99 5:00p Kevin
|
|
* put the memset in -- memset should be doing at least 32 bit copies,
|
|
* which is FAR better than a for loop.
|
|
*
|
|
* 123 4/09/99 12:03p Samir
|
|
* took out windows.h again, this time made HWND a void pointer, and
|
|
* checked under both editor and main projects.
|
|
*
|
|
* 122 4/06/99 8:29p Samir
|
|
* added error check system.
|
|
*
|
|
* 121 3/29/99 11:00a Samir
|
|
* added system to support different 3d sound options.
|
|
*
|
|
* 120 3/17/99 4:20p Samir
|
|
* added functions to pause and resume individual sounds.
|
|
*
|
|
* 119 3/04/99 1:23p Kevin
|
|
* Fixed Poping sound!!!
|
|
*
|
|
* 118 3/03/99 6:53p Matt
|
|
* Fixed compile warning
|
|
*
|
|
* 117 3/03/99 3:12p Chris
|
|
* Fixed volume problems
|
|
*
|
|
* 116 3/01/99 8:12p Samir
|
|
* pause sounds when switching sound quality!
|
|
*
|
|
* 115 2/25/99 4:50p Kevin
|
|
* Semi-hack to fix the problem with music looping and stuttering in DS
|
|
*
|
|
* 114 2/24/99 3:15p Kevin
|
|
* OEM menu changes, and bug fixes for the save/load system
|
|
*
|
|
* 113 2/22/99 6:28p Kevin
|
|
* Fixed a bug that was introduced (?) when the thread problem was fixed.
|
|
*
|
|
* 112 2/20/99 1:14a Kevin
|
|
* Fixed another bug
|
|
*
|
|
* 111 2/19/99 10:45p Kevin
|
|
* Fixed bug I just introduced...
|
|
*
|
|
* 110 2/19/99 5:21p Kevin
|
|
* Fixed some connection DLLs and a Direct Sound bug with threads.
|
|
*
|
|
* 109 2/11/99 3:30p Doug
|
|
* error checking in PlaySoundBuffer.
|
|
*
|
|
* 108 2/04/99 9:46a Kevin
|
|
* OEM version changes
|
|
*
|
|
* 107 1/14/99 6:10p Samir
|
|
* added DirectSound buffer duplication code.
|
|
*
|
|
* 106 1/11/99 5:51p Samir
|
|
* reverb on the buffer level.
|
|
*
|
|
* 105 1/08/99 6:31p Samir
|
|
* added reverb
|
|
*
|
|
* 104 1/08/99 11:36a Samir
|
|
* implemented basic Aureal 2.0 support.
|
|
*
|
|
* 103 1/08/99 10:32a Chris
|
|
*
|
|
* 102 12/23/98 11:49a Samir
|
|
* reorganized code so it works with different APIs.
|
|
*
|
|
* 101 12/11/98 5:21p Samir
|
|
* (chris) fixed problem with software streaming audio.
|
|
*
|
|
* 100 12/10/98 3:16p Chris
|
|
* added mprintfs for later use
|
|
*
|
|
* 99 12/10/98 2:18p Chris
|
|
* Added more asserts to the streaming code
|
|
*
|
|
* 98 11/13/98 4:55p Nate
|
|
* don't do dedicated server check in lowlevel.
|
|
*
|
|
* 97 11/13/98 12:17p Chris
|
|
*
|
|
* 96 11/12/98 12:15p Chris
|
|
* Fixed a bug with streaming mixers
|
|
*
|
|
* 95 10/30/98 1:20p Chris
|
|
* Fixed a m_unique_id bug where it was being used before it was being
|
|
* assigned
|
|
*
|
|
*
|
|
* $NoKeywords: $
|
|
*/
|
|
|
|
#include "ds3dlib_internal.h"
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <process.h>
|
|
#include "cfile.h"
|
|
#include "pserror.h"
|
|
#include "mono.h"
|
|
#include "soundload.h"
|
|
#include "mem.h"
|
|
#include "application.h"
|
|
#include "auddev.h"
|
|
#include "Macros.h"
|
|
#include "ddio.h"
|
|
|
|
// Hacked window handle -- chrishack
|
|
static oeWin32Application *SoundApp = NULL;
|
|
static void *GameWindowHandle;
|
|
#define MIN_SOUND_MIX_VOLUME 0.0
|
|
#define MAX_WRITE_AHEAD .04 // Seconds to write ahead of the play position (in seconds)
|
|
|
|
// write position
|
|
|
|
#define IS_3D_MIXER(_type) ((_type) >= SOUND_MIXER_DS3D_16 && (_type) != SOUND_MIXER_NONE)
|
|
|
|
win_llsSystem *ll_sound_ptr;
|
|
emulated_listener *g_emulated_listener = NULL; // silly hack (Samir)
|
|
short Global_DS_alloced_sounds = 0;
|
|
|
|
int *Fast_mixer = NULL;
|
|
int Fast_mixer_len = 0;
|
|
|
|
#define VOLUME_FIX_BITS 1024
|
|
|
|
// Streaming primary buffer information
|
|
DSSTREAM m_sb_info;
|
|
char m_sound_device_name[256] = ""; // set by set sound card
|
|
|
|
// Loads a sound buffer with data
|
|
long LoadSoundData(LPDIRECTSOUNDBUFFER lp_dsb, char *sound_data_ptr, ulong total_bytes);
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
static t3dEnvironmentValues Env3dValues;
|
|
static t3dEnvironmentToggles Env3dToggles;
|
|
|
|
#define ENV3DTOG_DOPPLER true
|
|
#define ENV3DTOG_GEOMETRY true
|
|
|
|
#define ENV3DVAL_DOPPLER_DEFAULT 0.5f
|
|
#define ENV3DVAL_ROLLOFF_DEFAULT 0.5f
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
win_llsSystem::win_llsSystem(void) : llsSystem() {
|
|
m_lp_ds = NULL;
|
|
m_f_sound_lib_init = 0;
|
|
m_hwnd_main = NULL;
|
|
m_mixer_type = -1;
|
|
m_sound_quality = SQT_NORMAL;
|
|
m_cache_stress_timer = 0.0f;
|
|
ll_sound_ptr = NULL;
|
|
m_timer_last_frametime = -1;
|
|
memset(&Env3dValues, 0, sizeof(Env3dValues));
|
|
memset(&Env3dToggles, 0, sizeof(Env3dToggles));
|
|
SetError(SSL_OK);
|
|
}
|
|
|
|
win_llsSystem::~win_llsSystem(void) {
|
|
DestroySoundLib();
|
|
SetSoundCard(NULL);
|
|
}
|
|
|
|
inline void opti_8m_mix(unsigned char *cur_sample_8bit, const int num_write, int &samples_played, int *mixer_buffer16,
|
|
const float l_volume, const float r_volume) {
|
|
int i;
|
|
int *mb = mixer_buffer16;
|
|
|
|
const int fix_rvol = r_volume * VOLUME_FIX_BITS;
|
|
const int fix_lvol = l_volume * VOLUME_FIX_BITS;
|
|
|
|
for (i = 0; i < (num_write << 1); i += 2) {
|
|
int sample;
|
|
int l_sample;
|
|
int r_sample;
|
|
|
|
sample = (((*cur_sample_8bit)) - 128) << 8;
|
|
cur_sample_8bit++;
|
|
|
|
l_sample = *mb + (sample * fix_lvol);
|
|
r_sample = *(mb + 1) + (sample * fix_rvol);
|
|
|
|
*mb = l_sample;
|
|
mb++;
|
|
*mb = r_sample;
|
|
mb++;
|
|
}
|
|
samples_played += (i / 2);
|
|
}
|
|
|
|
inline void opti_8s_mix(unsigned char *cur_sample_8bit, const int num_write, int &samples_played, int *mixer_buffer16,
|
|
const float l_volume, const float r_volume) {
|
|
int i;
|
|
int *mb = mixer_buffer16;
|
|
|
|
const int fix_rvol = r_volume * VOLUME_FIX_BITS;
|
|
const int fix_lvol = l_volume * VOLUME_FIX_BITS;
|
|
|
|
for (i = 0; i < (num_write << 1); i += 2) {
|
|
int lsample;
|
|
int rsample;
|
|
int l_sample;
|
|
int r_sample;
|
|
|
|
lsample = (((*cur_sample_8bit)) - 128) << 8;
|
|
cur_sample_8bit++;
|
|
rsample = (((*cur_sample_8bit)) - 128) << 8;
|
|
cur_sample_8bit++;
|
|
|
|
l_sample = *mb + (lsample * fix_lvol);
|
|
r_sample = *(mb + 1) + (rsample * fix_rvol);
|
|
|
|
*mb = l_sample;
|
|
mb++;
|
|
*mb = r_sample;
|
|
mb++;
|
|
}
|
|
samples_played += (i / 2);
|
|
}
|
|
|
|
inline void opti_16m_mix(short *cur_sample_16bit, const int num_write, int &samples_played, int *mixer_buffer16,
|
|
const float l_volume, const float r_volume) {
|
|
int i;
|
|
int *mb = mixer_buffer16;
|
|
|
|
const int fix_rvol = r_volume * VOLUME_FIX_BITS;
|
|
const int fix_lvol = l_volume * VOLUME_FIX_BITS;
|
|
|
|
for (i = 0; i < (num_write << 1); i += 2) {
|
|
int sample;
|
|
int l_sample;
|
|
int r_sample;
|
|
|
|
sample = *cur_sample_16bit;
|
|
cur_sample_16bit++;
|
|
|
|
l_sample = *mb + (sample * fix_lvol);
|
|
r_sample = *(mb + 1) + (sample * fix_rvol);
|
|
|
|
*mb = l_sample;
|
|
mb++;
|
|
*mb = r_sample;
|
|
mb++;
|
|
}
|
|
samples_played += (i / 2);
|
|
}
|
|
|
|
inline void opti_16s_mix(short *cur_sample_16bit, const int num_write, int &samples_played, int *mixer_buffer16,
|
|
const float l_volume, const float r_volume) {
|
|
int i;
|
|
int *mb = mixer_buffer16;
|
|
|
|
const int fix_rvol = r_volume * VOLUME_FIX_BITS;
|
|
const int fix_lvol = l_volume * VOLUME_FIX_BITS;
|
|
|
|
for (i = 0; i < (num_write << 1); i += 2) {
|
|
int lsample;
|
|
int rsample;
|
|
int l_sample;
|
|
int r_sample;
|
|
|
|
lsample = *cur_sample_16bit;
|
|
cur_sample_16bit++;
|
|
rsample = *cur_sample_16bit;
|
|
cur_sample_16bit++;
|
|
|
|
l_sample = *mb + (lsample * fix_lvol);
|
|
r_sample = *(mb + 1) + (rsample * fix_rvol);
|
|
|
|
*mb = l_sample;
|
|
mb++;
|
|
*mb = r_sample;
|
|
*mb++;
|
|
}
|
|
samples_played += (i / 2);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#define MAX_DS_PAN 1000.0f
|
|
|
|
int GamePanToDsPan(float pan) {
|
|
int ds_pan;
|
|
ds_pan = (int)(pan * MAX_DS_PAN);
|
|
|
|
if (ds_pan > MAX_DS_PAN)
|
|
ds_pan = MAX_DS_PAN;
|
|
if (ds_pan < -MAX_DS_PAN)
|
|
ds_pan = -MAX_DS_PAN;
|
|
|
|
// mprintf((0, "P %f %d\n", pan, ds_pan));
|
|
return ds_pan;
|
|
}
|
|
|
|
int GameVolumeToDsAttenuation(float volume) {
|
|
float fvol;
|
|
|
|
if (volume <= 0.0f) {
|
|
fvol = 2000.0f;
|
|
} else {
|
|
fvol = logf(volume) / logf(10.0f);
|
|
fvol *= 2000.0;
|
|
}
|
|
|
|
if (volume <= 0.01f) {
|
|
fvol = DSBVOLUME_MIN;
|
|
}
|
|
|
|
// mprintf((0, "V %f %f\n", volume, fvol));
|
|
return (int)fvol;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
inline char *get_sound_info(sound_buffer_info *sb, int *length, bool *f16bit) {
|
|
if (sb->m_sound_index < 0) {
|
|
if (sb->s) {
|
|
*f16bit = sb->s->f_sample_16bit;
|
|
}
|
|
return NULL;
|
|
}
|
|
if (SoundFiles[Sounds[sb->m_sound_index].sample_index].sample_8bit) {
|
|
*length = SoundFiles[Sounds[sb->m_sound_index].sample_index].np_sample_length;
|
|
*f16bit = false;
|
|
return (char *)SoundFiles[Sounds[sb->m_sound_index].sample_index].sample_8bit;
|
|
} else {
|
|
ASSERT(SoundFiles[Sounds[sb->m_sound_index].sample_index].sample_16bit);
|
|
*f16bit = true;
|
|
*length = SoundFiles[Sounds[sb->m_sound_index].sample_index].np_sample_length * 2;
|
|
return (char *)SoundFiles[Sounds[sb->m_sound_index].sample_index].sample_16bit;
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////
|
|
#define SB_STATUS_PLAYING 0x1
|
|
#define SB_STATUS_INVALID 0x2
|
|
|
|
inline int sb_get_status(sound_buffer_info *sb) {
|
|
int retflags = 0;
|
|
|
|
#ifdef SUPPORT_AUREAL
|
|
if (sb->m_mixer_type == SOUND_MIXER_AUREAL) {
|
|
int status;
|
|
|
|
if (sb->m_snd_obj) {
|
|
status = A3D_GetSourceStatus(sb->m_snd_obj);
|
|
if (status & A3D_STATUS_PLAYING)
|
|
retflags |= SB_STATUS_PLAYING;
|
|
} else {
|
|
retflags |= SB_STATUS_INVALID;
|
|
}
|
|
} else
|
|
#endif
|
|
if (sb->m_mixer_type != SOUND_MIXER_SOFTWARE_16) {
|
|
LPDIRECTSOUNDBUFFER sound_ptr = sb->m_sound_buffer;
|
|
unsigned long status;
|
|
|
|
if (sound_ptr) {
|
|
sound_ptr->GetStatus(&status);
|
|
if (status & DSBSTATUS_PLAYING)
|
|
retflags |= SB_STATUS_PLAYING;
|
|
} else {
|
|
retflags |= SB_STATUS_INVALID;
|
|
}
|
|
}
|
|
|
|
return retflags;
|
|
}
|
|
|
|
inline void sb_adjust_properties_3d(sound_buffer_info *sb, float f_volume, pos_state *pos, float reverb) {
|
|
if (!ll_sound_ptr->m_in_sound_frame)
|
|
ll_sound_ptr->m_pending_actions = true;
|
|
|
|
sb->m_volume = f_volume;
|
|
|
|
#ifdef SUPPORT_AUREAL
|
|
if (sb->m_mixer_type == SOUND_MIXER_AUREAL) {
|
|
// f_volume = f_volume * 1.2;
|
|
if (f_volume > 1.0f)
|
|
f_volume = 1.0f;
|
|
A3D_SetSourceVolume(sb->m_snd_obj, f_volume);
|
|
// A3D_SetMinMaxDistance(sb->m_snd_obj, Sounds[sb->m_sound_index].min_distance,
|
|
// Sounds[sb->m_sound_index].max_distance);
|
|
A3D_SetMinMaxDistance(sb->m_snd_obj, 30.0f, Sounds[sb->m_sound_index].max_distance);
|
|
// A3D_SetSourceCone(sb->m_snd_obj, x,y,z);
|
|
A3D_SetSourceOrientation(sb->m_snd_obj, &pos->orient->fvec, &pos->orient->uvec);
|
|
A3D_SetSourcePosition(sb->m_snd_obj, pos->position->x, pos->position->y, pos->position->z);
|
|
A3D_SetSourceVelocity(sb->m_snd_obj, pos->velocity->x, pos->velocity->y, pos->velocity->z);
|
|
} else
|
|
#endif
|
|
if (IS_3D_MIXER(sb->m_mixer_type)) {
|
|
LPDIRECTSOUNDBUFFER lp_dsb = sb->m_sound_buffer;
|
|
LPDIRECTSOUND3DBUFFER lpDSB3D = sb->m_sound_buffer_3d;
|
|
|
|
lp_dsb->SetVolume(GameVolumeToDsAttenuation(f_volume));
|
|
|
|
ASSERT(lpDSB3D != NULL);
|
|
|
|
if (sb->m_mixer_type == SOUND_MIXER_CREATIVE_EAX) {
|
|
lpDSB3D->SetMinDistance(30.0f, DS3D_IMMEDIATE);
|
|
} else {
|
|
lpDSB3D->SetMinDistance(Sounds[sb->m_sound_index].min_distance, DS3D_IMMEDIATE);
|
|
}
|
|
lpDSB3D->SetMaxDistance(Sounds[sb->m_sound_index].max_distance, DS3D_IMMEDIATE);
|
|
lpDSB3D->SetConeOrientation(pos->orient->fvec.x, pos->orient->fvec.y, pos->orient->fvec.z, DS3D_IMMEDIATE);
|
|
lpDSB3D->SetPosition(pos->position->x, pos->position->y, pos->position->z, DS3D_IMMEDIATE);
|
|
lpDSB3D->SetVelocity(pos->velocity->x, pos->velocity->y, pos->velocity->z, DS3D_IMMEDIATE);
|
|
|
|
// if (sb->m_mixer_type == SOUND_MIXER_CREATIVE_EAX) {
|
|
// EAX_SetBufferReverbMix(lpDSB3D, reverb);
|
|
// }
|
|
} else {
|
|
mprintf((0, "m_mixer_type = %d\n", sb->m_mixer_type));
|
|
Int3();
|
|
}
|
|
}
|
|
|
|
inline void sb_adjust_properties_2d(sound_buffer_info *sb, float f_volume, float f_pan, ushort frequency) {
|
|
if (!ll_sound_ptr->m_in_sound_frame)
|
|
ll_sound_ptr->m_pending_actions = true;
|
|
|
|
sb->m_volume = f_volume;
|
|
|
|
#ifdef SUPPORT_AUREAL
|
|
if (sb->m_mixer_type == SOUND_MIXER_AUREAL) {
|
|
if (sb->m_snd_obj) {
|
|
float l_pan = 1.0f, r_pan = 1.0f;
|
|
if (f_pan < 0.0f)
|
|
r_pan = r_pan + f_pan;
|
|
if (f_pan > 0.0f)
|
|
l_pan = l_pan - f_pan;
|
|
A3D_SetSourceVolume(sb->m_snd_obj, f_volume);
|
|
A3D_SetSourcePan(sb->m_snd_obj, l_pan, r_pan);
|
|
// mprintf((0, "2d vol:%.1f pan:%.1f,%.1f\n", f_volume, l_pan, r_pan));
|
|
}
|
|
} else
|
|
#endif
|
|
if (sb->m_mixer_type != SOUND_MIXER_SOFTWARE_16) {
|
|
LPDIRECTSOUNDBUFFER lpdsb;
|
|
|
|
ASSERT(f_pan >= -1.0f && f_pan <= 1.0f);
|
|
ASSERT(f_volume >= 0.0f && f_volume <= 1.0f);
|
|
|
|
lpdsb = sb->m_sound_buffer;
|
|
if (lpdsb == NULL)
|
|
return;
|
|
|
|
// mprintf((0, "Sound UID %d is now at %d volume,%d pan\n", sound_uid, volume, pan));
|
|
|
|
lpdsb->SetVolume(GameVolumeToDsAttenuation(f_volume));
|
|
lpdsb->SetPan(GamePanToDsPan(f_pan)); // chrishack pan is off
|
|
lpdsb->SetFrequency(frequency);
|
|
}
|
|
}
|
|
|
|
// functions for different APIs
|
|
int sb_get_current_position(sound_buffer_info *sb, uint *writep) {
|
|
DWORD playp, wp;
|
|
|
|
#ifdef SUPPORT_AUREAL
|
|
if (sb->m_mixer_type == SOUND_MIXER_AUREAL) {
|
|
if (!sb->m_snd_obj) {
|
|
*writep = (uint)(-1);
|
|
playp = (DWORD)(-1);
|
|
} else {
|
|
uint pp;
|
|
A3D_GetCurrentPosition(sb->m_snd_obj, &pp);
|
|
*writep = pp;
|
|
playp = (DWORD)pp;
|
|
}
|
|
} else
|
|
#endif
|
|
if (sb->m_mixer_type != SOUND_MIXER_SOFTWARE_16) {
|
|
if (sb->m_sound_buffer && sb->m_sound_buffer->GetCurrentPosition(&playp, &wp) == DS_OK) {
|
|
*writep = (uint)wp;
|
|
} else {
|
|
playp = (DWORD)(-1);
|
|
*writep = (uint)(-1);
|
|
}
|
|
}
|
|
|
|
return (uint)playp;
|
|
}
|
|
|
|
inline void sb_set_current_position(sound_buffer_info *sb, uint pos) {
|
|
if (!ll_sound_ptr->m_in_sound_frame)
|
|
ll_sound_ptr->m_pending_actions = true;
|
|
|
|
#ifdef SUPPORT_AUREAL
|
|
if (sb->m_mixer_type == SOUND_MIXER_AUREAL) {
|
|
A3D_SetCurrentPosition(sb->m_snd_obj, pos);
|
|
} else
|
|
#endif
|
|
if (sb->m_mixer_type != SOUND_MIXER_SOFTWARE_16) {
|
|
sb->m_sound_buffer->SetCurrentPosition((DWORD)pos);
|
|
}
|
|
}
|
|
|
|
void sb_free_buffer(sound_buffer_info *sb) {
|
|
if (!ll_sound_ptr->m_in_sound_frame)
|
|
ll_sound_ptr->m_pending_actions = true;
|
|
if (!sb->m_sound_buffer)
|
|
return;
|
|
|
|
#ifdef SUPPORT_AUREAL
|
|
if (sb->m_mixer_type == SOUND_MIXER_AUREAL) {
|
|
A3D_FreeSSource(sb->m_snd_obj);
|
|
sb->m_snd_obj = NULL;
|
|
} else
|
|
#endif
|
|
if (sb->m_mixer_type != SOUND_MIXER_SOFTWARE_16) {
|
|
if (sb->m_mixer_type == SOUND_MIXER_CREATIVE_EAX) {
|
|
EAX_FreeSource(sb->m_lpksps);
|
|
}
|
|
|
|
if (sb->m_sound_buffer) {
|
|
sb->m_sound_buffer->Release();
|
|
sb->m_sound_buffer = NULL;
|
|
}
|
|
if (sb->m_sound_buffer_3d) {
|
|
sb->m_sound_buffer_3d->Release();
|
|
sb->m_sound_buffer_3d = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
void sb_stop_buffer(sound_buffer_info *sb) {
|
|
if (!ll_sound_ptr->m_in_sound_frame)
|
|
ll_sound_ptr->m_pending_actions = true;
|
|
|
|
#ifdef SUPPORT_AUREAL
|
|
if (sb->m_mixer_type == SOUND_MIXER_AUREAL) {
|
|
A3D_Stop(sb->m_snd_obj);
|
|
} else
|
|
#endif
|
|
if (sb->m_mixer_type != SOUND_MIXER_SOFTWARE_16) {
|
|
sb->m_sound_buffer->Stop();
|
|
}
|
|
}
|
|
|
|
bool sb_lock_buffer(sound_buffer_info *sb, uint dwWriteCursor, uint dwWriteBytes, void **lplpvAudioPtr1,
|
|
uint *lpdwAudioBytes1, void **lplpvAudioPtr2, uint *lpdwAudioBytes2) {
|
|
DWORD len1, len2;
|
|
|
|
#ifdef SUPPORT_AUREAL
|
|
if (sb->m_mixer_type == SOUND_MIXER_AUREAL) {
|
|
if (A3D_Lock(sb->m_snd_obj, dwWriteCursor, dwWriteBytes, lplpvAudioPtr1, &len1, lplpvAudioPtr2, &len2)) {
|
|
*lpdwAudioBytes1 = len1;
|
|
*lpdwAudioBytes2 = len2;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
} else
|
|
#endif
|
|
if (sb->m_mixer_type != SOUND_MIXER_SOFTWARE_16) {
|
|
TryLockAgainLabel:
|
|
switch (sb->m_sound_buffer->Lock(dwWriteCursor, dwWriteBytes, lplpvAudioPtr1, &len1, lplpvAudioPtr2, &len2, 0)) {
|
|
case DS_OK:
|
|
*lpdwAudioBytes1 = len1;
|
|
*lpdwAudioBytes2 = len2;
|
|
return true;
|
|
|
|
case DSERR_BUFFERLOST:
|
|
if (sb->m_sound_buffer->Restore() == DS_OK)
|
|
goto TryLockAgainLabel;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool sb_unlock_buffer(sound_buffer_info *sb, void *ptr1, uint len1, void *ptr2, uint len2) {
|
|
#ifdef SUPPORT_AUREAL
|
|
if (sb->m_mixer_type == SOUND_MIXER_AUREAL) {
|
|
A3D_Unlock(sb->m_snd_obj, ptr1, len1, ptr2, len2);
|
|
} else
|
|
#endif
|
|
if (sb->m_mixer_type != SOUND_MIXER_SOFTWARE_16) {
|
|
sb->m_sound_buffer->Unlock(ptr1, len1, ptr2, len2);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool sb_load_buffer(sound_buffer_info *sb, void *sample_data, int length) {
|
|
if (!ll_sound_ptr->m_in_sound_frame)
|
|
ll_sound_ptr->m_pending_actions = true;
|
|
|
|
#ifdef SUPPORT_AUREAL
|
|
switch (sb->m_mixer_type) {
|
|
case SOUND_MIXER_AUREAL:
|
|
if (!A3D_LoadSample(sb->m_snd_obj, sample_data, length)) {
|
|
Int3();
|
|
sb->m_status = SSF_UNUSED;
|
|
return false;
|
|
}
|
|
break;
|
|
default:
|
|
#endif
|
|
if (LoadSoundData(sb->m_sound_buffer, (char *)sample_data, length) != DS_OK) {
|
|
Int3();
|
|
sb->m_status = SSF_UNUSED;
|
|
return false;
|
|
}
|
|
#ifdef SUPPORT_AUREAL
|
|
}
|
|
#endif
|
|
|
|
return true;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// The actual mixer code that sum's the sounds on each channel and does all the actual
|
|
// mixing and effects (writes data to the locked primary buffer)
|
|
void StreamMixer(char *ptr, int len) {
|
|
int i;
|
|
short *mixer_buffer16 = (short *)ptr;
|
|
int current_slot = 0;
|
|
bool f_loop;
|
|
bool f_mono;
|
|
|
|
const int buff_len = len / ll_sound_ptr->m_primary_alignment;
|
|
|
|
// this code will assure that this function will not be called when sound system is in error mode.
|
|
if (ll_sound_ptr->m_lib_error_code != SSL_OK) {
|
|
return;
|
|
}
|
|
|
|
ASSERT(len <= m_sb_info.BufferSize);
|
|
ASSERT(ptr && len >= 0);
|
|
|
|
ASSERT((len % ll_sound_ptr->m_primary_alignment) == 0);
|
|
|
|
// memset((char *)ptr, 0, len);
|
|
|
|
// This memset is hopefully temporary
|
|
memset(Fast_mixer, 0, Fast_mixer_len * sizeof(int));
|
|
int *fast_mix_ptr = Fast_mixer;
|
|
|
|
// Mix the sound slots
|
|
while (current_slot < ll_sound_ptr->m_sound_mixer.m_max_sounds_played) {
|
|
sound_buffer_info *cur_buf = &ll_sound_ptr->m_sound_mixer.m_sound_cache[current_slot];
|
|
int num_samples = buff_len;
|
|
// mixer_buffer16 = (short *) ptr;
|
|
fast_mix_ptr = Fast_mixer;
|
|
f_mono = true;
|
|
|
|
// Find slots with sounds in them
|
|
if ((cur_buf->m_status != SSF_UNUSED) && !(cur_buf->m_status & SSF_PAUSED)) {
|
|
float l_volume = cur_buf->play_info->left_volume;
|
|
float r_volume = cur_buf->play_info->right_volume;
|
|
int skip_interval = cur_buf->play_info->sample_skip_interval;
|
|
int samples_played = cur_buf->play_info->m_samples_played;
|
|
short *sample_16bit;
|
|
unsigned char *sample_8bit;
|
|
int np_sample_length;
|
|
int sample_length;
|
|
int loop_start;
|
|
int loop_end;
|
|
|
|
if (cur_buf->m_status & SSF_PLAY_STREAMING) {
|
|
switch (cur_buf->play_info->m_stream_format) {
|
|
case SIF_STREAMING_16_M:
|
|
sample_16bit = (short *)cur_buf->play_info->m_stream_data;
|
|
sample_8bit = NULL;
|
|
np_sample_length = sample_length = cur_buf->play_info->m_stream_size / 2;
|
|
break;
|
|
case SIF_STREAMING_8_M:
|
|
sample_16bit = NULL;
|
|
sample_8bit = (unsigned char *)cur_buf->play_info->m_stream_data;
|
|
np_sample_length = sample_length = cur_buf->play_info->m_stream_size;
|
|
break;
|
|
case SIF_STREAMING_16_S:
|
|
sample_16bit = (short *)cur_buf->play_info->m_stream_data;
|
|
sample_8bit = NULL;
|
|
np_sample_length = sample_length = cur_buf->play_info->m_stream_size / 4;
|
|
f_mono = false;
|
|
break;
|
|
case SIF_STREAMING_8_S:
|
|
sample_16bit = NULL;
|
|
sample_8bit = (unsigned char *)cur_buf->play_info->m_stream_data;
|
|
np_sample_length = sample_length = cur_buf->play_info->m_stream_size / 2;
|
|
f_mono = false;
|
|
break;
|
|
default:
|
|
Int3();
|
|
break;
|
|
}
|
|
loop_start = 0;
|
|
loop_end = np_sample_length - 1;
|
|
} else {
|
|
int sound_index = cur_buf->m_sound_index;
|
|
int sample_index = Sounds[sound_index].sample_index;
|
|
sound_file_info *snd_file = &SoundFiles[sample_index];
|
|
sample_16bit = snd_file->sample_16bit;
|
|
sample_8bit = snd_file->sample_8bit;
|
|
np_sample_length = snd_file->np_sample_length;
|
|
sample_length = snd_file->sample_length;
|
|
loop_start = Sounds[sound_index].loop_start;
|
|
loop_end = Sounds[sound_index].loop_end;
|
|
if (!sample_16bit && !sample_8bit) {
|
|
mprintf((0, "sound file %s didn't have data for samples.\n", snd_file->name));
|
|
}
|
|
}
|
|
|
|
// cleanly continue if this happens, and inform a logfile, if it does. error handling
|
|
// ASSERT(sample_16bit || sample_8bit);
|
|
if (!sample_16bit && !sample_8bit) {
|
|
sound_file_info *snd_file = &SoundFiles[Sounds[cur_buf->m_sound_index].sample_index];
|
|
ll_sound_ptr->SetError(SSL_ERROR_SAMPLE_NODATA);
|
|
ll_sound_ptr->ErrorText("ASSERT(sample_16bit || sample_8bit)\nNo data found for sound file: %s",
|
|
snd_file->name);
|
|
cur_buf->m_status = SSF_UNUSED;
|
|
goto error_bail;
|
|
}
|
|
|
|
ASSERT(np_sample_length <= sample_length);
|
|
ASSERT(samples_played >= 0 || samples_played <= sample_length);
|
|
|
|
int num_write;
|
|
|
|
error_trap:
|
|
|
|
// We have not looped -- yet
|
|
f_loop = false;
|
|
|
|
// Verify the volume levels are o.k.
|
|
ASSERT(l_volume >= 0.0 && l_volume <= 1.0);
|
|
ASSERT(r_volume >= 0.0 && r_volume <= 1.0);
|
|
|
|
looping: // Will go to this label to do the next iteration of a looping sample
|
|
|
|
if (cur_buf->m_status &
|
|
(SSF_PLAY_LOOPING | SSF_PLAY_STREAMING)) // Looping sample's process is broken up into linear pieces
|
|
{
|
|
if (f_loop) {
|
|
ASSERT(num_write >= 0);
|
|
|
|
num_samples -= num_write;
|
|
ASSERT(num_samples > 0);
|
|
|
|
fast_mix_ptr += (num_write * 2);
|
|
// mixer_buffer16 += num_write << 1; // update to the new start position
|
|
// (2x because of left and right channels)
|
|
|
|
samples_played = loop_start;
|
|
}
|
|
|
|
if (cur_buf->m_status & SSF_PLAY_LOOPING) // Looping sample's process is broken up into linear pieces
|
|
{
|
|
ASSERT(loop_end < sample_length);
|
|
if (loop_end < samples_played) {
|
|
// CHRISHACK -- Fuck milestone. Fix later. Code below is a major hack (but it works). :)
|
|
|
|
if (loop_end != loop_start) {
|
|
while (loop_end < samples_played) {
|
|
// Int3();
|
|
samples_played -= loop_end - loop_start;
|
|
}
|
|
|
|
ASSERT(samples_played >= 0);
|
|
} else {
|
|
cur_buf->m_status &= ~SSF_PLAY_LOOPING;
|
|
cur_buf->m_status |= SSF_PLAY_NORMAL;
|
|
}
|
|
|
|
goto error_trap;
|
|
}
|
|
}
|
|
// The number of samples to write to the primary buffer
|
|
num_write = ((num_samples) < (loop_end - samples_played + 1)) ? (num_samples) : (loop_end - samples_played + 1);
|
|
ASSERT(num_write >= 0 && num_write <= num_samples);
|
|
|
|
if (num_write < num_samples)
|
|
f_loop = true;
|
|
else
|
|
f_loop = false;
|
|
|
|
if (num_write <= 0) {
|
|
num_write = 0;
|
|
mprintf((0, "d"));
|
|
goto stream_done;
|
|
}
|
|
} else {
|
|
// The number of samples to write to the primary buffer
|
|
num_write =
|
|
((num_samples) < (np_sample_length - samples_played)) ? (num_samples) : (np_sample_length - samples_played);
|
|
if (!(num_write > 0 && num_write <= num_samples)) {
|
|
num_write = 0;
|
|
goto done;
|
|
}
|
|
|
|
// Optimization for silent sounds
|
|
if (l_volume <= MIN_SOUND_MIX_VOLUME && r_volume <= MIN_SOUND_MIX_VOLUME) {
|
|
cur_buf->play_info->m_samples_played += num_write;
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
if (!(num_write > 0 && num_write <= num_samples)) // this was an assert
|
|
{
|
|
num_write = 0;
|
|
mprintf((0, "D"));
|
|
goto done;
|
|
}
|
|
|
|
// Mix at 16 bits per sample
|
|
if (skip_interval == 0) {
|
|
short *cur_sample_16bit = sample_16bit;
|
|
unsigned char *cur_sample_8bit = sample_8bit;
|
|
|
|
if (f_mono) {
|
|
if (sample_8bit) {
|
|
cur_sample_8bit += samples_played;
|
|
opti_8m_mix(cur_sample_8bit, num_write, samples_played, fast_mix_ptr, l_volume, r_volume);
|
|
} else {
|
|
cur_sample_16bit += samples_played;
|
|
opti_16m_mix(cur_sample_16bit, num_write, samples_played, fast_mix_ptr, l_volume, r_volume);
|
|
}
|
|
} else {
|
|
if (sample_8bit) {
|
|
cur_sample_8bit += (samples_played << 1);
|
|
opti_8s_mix(cur_sample_8bit, num_write, samples_played, fast_mix_ptr, l_volume, r_volume);
|
|
} else {
|
|
cur_sample_16bit += (samples_played << 1);
|
|
opti_16s_mix(cur_sample_16bit, num_write, samples_played, fast_mix_ptr, l_volume, r_volume);
|
|
}
|
|
}
|
|
} else
|
|
// Account for lower-sampling rate
|
|
{
|
|
if (skip_interval == 1) {
|
|
const int fix_rvol = r_volume * VOLUME_FIX_BITS;
|
|
const int fix_lvol = l_volume * VOLUME_FIX_BITS;
|
|
|
|
for (i = 0; i < (num_write << 1); i += 2) {
|
|
int sample;
|
|
|
|
if (sample_16bit) {
|
|
if (samples_played & 0x0001) {
|
|
sample = ((int)sample_16bit[samples_played ^ 0x0001] + (int)sample_16bit[samples_played + 1]) >> 1;
|
|
} else
|
|
sample = sample_16bit[samples_played];
|
|
} else {
|
|
if (samples_played & 0x0001) {
|
|
// Notes: (<<7) is from a (<<8) - (>>1)
|
|
// Notes: (-256) is from (-128) + (-128)
|
|
sample = ((int)sample_8bit[samples_played ^ 0x0001] + (int)sample_8bit[samples_played + 1] - 256) << 7;
|
|
} else
|
|
sample = (((int)sample_8bit[samples_played]) - (int)128) << 8;
|
|
}
|
|
|
|
samples_played++;
|
|
|
|
ASSERT(i >= 0 && (i + 1 < num_samples * 2));
|
|
|
|
int l_sample = fast_mix_ptr[i] + (sample * fix_lvol);
|
|
int r_sample = fast_mix_ptr[i + 1] + (sample * fix_rvol);
|
|
|
|
fast_mix_ptr[i] = l_sample;
|
|
fast_mix_ptr[i + 1] = r_sample;
|
|
}
|
|
} else {
|
|
const int fix_rvol = r_volume * VOLUME_FIX_BITS;
|
|
const int fix_lvol = l_volume * VOLUME_FIX_BITS;
|
|
for (i = 0; i < (num_write << 1); i += 2) {
|
|
int sample;
|
|
const int mod_pos = samples_played % 4;
|
|
|
|
if (sample_16bit) {
|
|
switch (mod_pos) {
|
|
case 0:
|
|
sample = sample_16bit[samples_played];
|
|
break;
|
|
case 1:
|
|
sample = (sample_16bit[samples_played - 1] * 3 + sample_16bit[samples_played + 3]) >> 2;
|
|
break;
|
|
case 2:
|
|
sample = (sample_16bit[samples_played - 2] + sample_16bit[samples_played + 2]) >> 1;
|
|
break;
|
|
case 3:
|
|
sample = (sample_16bit[samples_played - 3] + sample_16bit[samples_played + 1] * 3) >> 2;
|
|
break;
|
|
}
|
|
} else {
|
|
switch (mod_pos) {
|
|
case 0:
|
|
sample = ((((int)sample_8bit[samples_played]) - 128) << 8);
|
|
break;
|
|
case 1:
|
|
sample = (((((int)sample_8bit[samples_played - 1]) - 128) << 8) * 3 +
|
|
((((int)sample_8bit[samples_played + 3]) - 128) << 8)) >>
|
|
2;
|
|
break;
|
|
case 2:
|
|
sample = (((((int)sample_8bit[samples_played - 2]) - 128) << 8) +
|
|
((((int)sample_8bit[samples_played + 2]) - 128) << 8)) >>
|
|
1;
|
|
break;
|
|
case 3:
|
|
sample = (((((int)sample_8bit[samples_played - 3]) - 128) << 8) +
|
|
((((int)sample_8bit[samples_played + 1]) - 128) << 8) * 3) >>
|
|
2;
|
|
break;
|
|
}
|
|
}
|
|
|
|
samples_played++;
|
|
|
|
ASSERT(i >= 0 && (i + 1 < num_samples * 2));
|
|
|
|
int l_sample = fast_mix_ptr[i] + (sample * fix_lvol);
|
|
int r_sample = fast_mix_ptr[i + 1] + (sample * fix_rvol);
|
|
|
|
fast_mix_ptr[i] = l_sample;
|
|
fast_mix_ptr[i + 1] = r_sample;
|
|
}
|
|
}
|
|
}
|
|
|
|
stream_done:
|
|
|
|
cur_buf->play_info->m_samples_played = samples_played;
|
|
|
|
if (cur_buf->m_status & SSF_PLAY_STREAMING) {
|
|
if (f_loop) {
|
|
if (cur_buf->play_info->m_stream_cback && cur_buf->play_info->m_stream_data) {
|
|
cur_buf->play_info->m_stream_data = (*cur_buf->play_info->m_stream_cback)(
|
|
cur_buf->play_info->user_data, cur_buf->play_info->m_stream_handle, &cur_buf->play_info->m_stream_size);
|
|
// cur_buf->s->current_position = (char
|
|
//*)cur_buf->play_info->m_stream_data; mprintf((0, "%x %d\n",
|
|
// cur_buf->play_info->m_stream_data, cur_buf->play_info->m_stream_size));
|
|
ASSERT(!(cur_buf->play_info->m_stream_data && cur_buf->play_info->m_stream_size <= 0));
|
|
// mprintf((0, "Data %X, length %d\n",
|
|
// cur_buf->play_info->m_stream_data, cur_buf->play_info->m_stream_size));
|
|
|
|
if (cur_buf->play_info->m_stream_data) {
|
|
switch (cur_buf->play_info->m_stream_format) {
|
|
case SIF_STREAMING_16_M:
|
|
sample_16bit = (short *)cur_buf->play_info->m_stream_data;
|
|
loop_end = sample_length = np_sample_length = cur_buf->play_info->m_stream_size / 2;
|
|
break;
|
|
case SIF_STREAMING_8_M:
|
|
sample_8bit = (unsigned char *)cur_buf->play_info->m_stream_data;
|
|
loop_end = sample_length = np_sample_length = cur_buf->play_info->m_stream_size;
|
|
break;
|
|
case SIF_STREAMING_16_S:
|
|
sample_16bit = (short *)cur_buf->play_info->m_stream_data;
|
|
loop_end = sample_length = np_sample_length = cur_buf->play_info->m_stream_size / 4;
|
|
break;
|
|
case SIF_STREAMING_8_S:
|
|
sample_8bit = (unsigned char *)cur_buf->play_info->m_stream_data;
|
|
loop_end = sample_length = np_sample_length = cur_buf->play_info->m_stream_size / 2;
|
|
break;
|
|
default:
|
|
Int3();
|
|
break;
|
|
}
|
|
loop_end -= 1;
|
|
} else {
|
|
mprintf((0, "SE: Data is NULL\n"));
|
|
cur_buf->m_status &= ~SSF_PLAY_STREAMING;
|
|
f_loop = false;
|
|
}
|
|
} else {
|
|
mprintf((0, "SE: Callback/data is NULL\n"));
|
|
cur_buf->m_status &= ~SSF_PLAY_STREAMING;
|
|
f_loop = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (f_loop)
|
|
goto looping;
|
|
|
|
done:
|
|
|
|
if (cur_buf->play_info->m_samples_played >= (np_sample_length) &&
|
|
!(cur_buf->m_status & (SSF_PLAY_LOOPING | SSF_PLAY_STREAMING))) {
|
|
ll_sound_ptr->StopSound(cur_buf->m_unique_id);
|
|
}
|
|
}
|
|
|
|
error_bail:
|
|
current_slot++;
|
|
}
|
|
|
|
for (int a = 0; a < (buff_len * 2); a++) {
|
|
Fast_mixer[a] = Fast_mixer[a] / VOLUME_FIX_BITS;
|
|
|
|
if (Fast_mixer[a] > 32767)
|
|
Fast_mixer[a] = 32767;
|
|
if (Fast_mixer[a] < -32767)
|
|
Fast_mixer[a] = -32767;
|
|
|
|
mixer_buffer16[a] = Fast_mixer[a];
|
|
|
|
Fast_mixer[a + 1] = Fast_mixer[a + 1] / VOLUME_FIX_BITS;
|
|
|
|
if (Fast_mixer[a + 1] > 32767)
|
|
Fast_mixer[a + 1] = 32767;
|
|
if (Fast_mixer[a + 1] < -32767)
|
|
Fast_mixer[a + 1] = -32767;
|
|
|
|
mixer_buffer16[a + 1] = Fast_mixer[a + 1];
|
|
|
|
a++;
|
|
}
|
|
// mprintf((0," -%d- ",a));
|
|
}
|
|
|
|
// Locks the primary buffer and fills in the new data
|
|
void StreamFill(int start_byte, int num_bytes) {
|
|
char *ptr1;
|
|
char *ptr2;
|
|
int len1, len2;
|
|
|
|
if ((num_bytes % ll_sound_ptr->m_primary_alignment) != 0) {
|
|
ll_sound_ptr->SetError(SSL_ERROR_STREAMMIXER);
|
|
ll_sound_ptr->ErrorText("ASSERT((len % ll_sound_ptr->m_primary_alignment) == 0)\nLen:%d PrA:%d", num_bytes,
|
|
ll_sound_ptr->m_primary_alignment);
|
|
return;
|
|
}
|
|
ASSERT((num_bytes % ll_sound_ptr->m_primary_alignment) == 0);
|
|
ASSERT((start_byte % ll_sound_ptr->m_primary_alignment) == 0);
|
|
|
|
start_byte = (start_byte % m_sb_info.BufferSize);
|
|
|
|
TryLockAgainLabel:
|
|
|
|
switch (m_sb_info.m_lp_looping_buffer->Lock(start_byte, num_bytes, (void **)&ptr1, (DWORD *)&len1, (void **)&ptr2,
|
|
(DWORD *)&len2, 0)) {
|
|
ASSERT((len1 % ll_sound_ptr->m_primary_alignment) == 0);
|
|
ASSERT((len2 % ll_sound_ptr->m_primary_alignment) == 0);
|
|
|
|
// The pointers are to the lock areas of the primary buffer. There are two because locked region
|
|
// might be a discontinuous chunk (wrapped around the end of the buffer i.e. 'LLLLBBBBBBLLLLL'
|
|
// L is for Locked and B is unlocked buffer.
|
|
case DS_OK:
|
|
StreamMixer(ptr1, len1);
|
|
if (ptr2)
|
|
StreamMixer(ptr2, len2);
|
|
|
|
m_sb_info.m_lp_looping_buffer->Unlock(ptr1, len1, ptr2, len2);
|
|
|
|
m_sb_info.NextWritePos = (start_byte + num_bytes) % m_sb_info.BufferSize;
|
|
break;
|
|
|
|
case DSERR_BUFFERLOST:
|
|
if (m_sb_info.m_lp_primary_buffer->Restore() == DS_OK && m_sb_info.m_lp_looping_buffer->Restore() == DS_OK)
|
|
goto TryLockAgainLabel;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// A peroidic mixer that uses the primary buffer as a stream buffer
|
|
void __cdecl StreamTimer(void *user_ptr) {
|
|
int playp, writep;
|
|
int try_count = 0;
|
|
DSSTREAM *sb_info = (DSSTREAM *)user_ptr;
|
|
DWORD result;
|
|
|
|
m_sb_info.m_lp_primary_buffer->Restore();
|
|
m_sb_info.m_lp_primary_buffer->Play(0, 0, DSBPLAY_LOOPING);
|
|
|
|
while (!sb_info->thread_request_kill) {
|
|
try_count = 0;
|
|
|
|
TryAgain:
|
|
try_count++;
|
|
|
|
// hresult = m_sb_info.m_lp_primary_buffer->GetStatus(&stat_result);
|
|
//
|
|
// if(hresult != DS_OK || !(stat_result & DSBSTATUS_LOOPING))
|
|
// {
|
|
// m_sb_info.m_lp_primary_buffer->Restore();
|
|
m_sb_info.m_lp_primary_buffer->Restore();
|
|
m_sb_info.m_lp_primary_buffer->Play(0, 0, DSBPLAY_LOOPING);
|
|
// }
|
|
|
|
result = sb_info->m_lp_looping_buffer->GetCurrentPosition((DWORD *)&playp, (DWORD *)&writep);
|
|
|
|
// mprintf((0, "(%d,%d)\n", playp, writep));
|
|
|
|
// If primary buffer was stopped from playing
|
|
if (writep == playp) {
|
|
sb_info->NextWritePos = -1;
|
|
|
|
if ((try_count == 1) &&
|
|
(m_sb_info.m_lp_primary_buffer->Restore() == DS_OK && m_sb_info.m_lp_looping_buffer->Restore() == DS_OK)) {
|
|
if ((try_count == 1) && (m_sb_info.m_lp_looping_buffer->Play(0, 0, DSBPLAY_LOOPING) == DS_OK)) {
|
|
goto TryAgain;
|
|
}
|
|
}
|
|
|
|
goto done;
|
|
}
|
|
|
|
// Insert mixer code
|
|
{
|
|
int num_write_bytes;
|
|
|
|
if (sb_info->NextWritePos < 0)
|
|
sb_info->NextWritePos = writep;
|
|
|
|
// Debugging code (not sure what would happen if we hit these without an Int3()) -- Skipping noise
|
|
if (sb_info->LastPlayPos < sb_info->NextWritePos) {
|
|
|
|
if (playp >= sb_info->NextWritePos || playp < sb_info->LastPlayPos) {
|
|
if (!sb_info->m_f_secondary_looping)
|
|
goto done;
|
|
playp = sb_info->NextWritePos - 4;
|
|
num_write_bytes = 4 * (int)(22050 * DSPB_TICK_INTERVAL);
|
|
} else {
|
|
// Determine how much we can write out.
|
|
num_write_bytes = (sb_info->MaxWriteBytes + playp) - sb_info->NextWritePos;
|
|
}
|
|
} else {
|
|
if (playp >= sb_info->NextWritePos && playp < sb_info->LastPlayPos) {
|
|
if (!sb_info->m_f_secondary_looping)
|
|
goto done;
|
|
|
|
playp = sb_info->NextWritePos - 4;
|
|
num_write_bytes = 4 * (int)(22050 * DSPB_TICK_INTERVAL);
|
|
} else {
|
|
// Determine how much we can write out.
|
|
if (playp < sb_info->NextWritePos)
|
|
num_write_bytes = (sb_info->MaxWriteBytes + playp) - sb_info->NextWritePos;
|
|
else
|
|
num_write_bytes = sb_info->MaxWriteBytes - (sb_info->NextWritePos + (sb_info->BufferSize - playp));
|
|
}
|
|
}
|
|
|
|
num_write_bytes &= (0xFFFFFFFF & (~(ll_sound_ptr->m_primary_alignment)));
|
|
|
|
if (num_write_bytes > 0) {
|
|
// ASSERT(num_write_bytes < sb_info->BufferSize);
|
|
if (num_write_bytes >= sb_info->BufferSize) {
|
|
num_write_bytes = sb_info->BufferSize / 2;
|
|
}
|
|
|
|
StreamFill(sb_info->NextWritePos, num_write_bytes);
|
|
}
|
|
}
|
|
|
|
sb_info->LastPlayPos = playp;
|
|
|
|
done:
|
|
Sleep(DSPB_TICK_MILLISECONDS);
|
|
}
|
|
|
|
sb_info->thread_alive = false;
|
|
}
|
|
|
|
// Begins the whole streaming process
|
|
bool win_llsSystem::StartStreaming(void) {
|
|
DSBCAPS dsbcaps;
|
|
|
|
dsbcaps.dwSize = sizeof(DSBCAPS);
|
|
m_sb_info.m_lp_looping_buffer->GetCaps(&dsbcaps);
|
|
|
|
m_sb_info.m_f_secondary_looping = (m_sb_info.m_lp_looping_buffer != m_sb_info.m_lp_primary_buffer);
|
|
|
|
m_sb_info.BufferSize = dsbcaps.dwBufferBytes;
|
|
|
|
m_sb_info.MaxWriteSamples = m_primary_frequency * MAX_WRITE_AHEAD;
|
|
m_sb_info.MaxWriteBytes = m_sb_info.MaxWriteSamples * m_primary_alignment;
|
|
|
|
m_sb_info.NextWritePos = -1;
|
|
m_sb_info.LastPlayPos = 0;
|
|
|
|
StreamFill(0, dsbcaps.dwBufferBytes);
|
|
|
|
m_sb_info.thread_request_kill = false;
|
|
m_sb_info.thread_alive = true;
|
|
|
|
// Start mixing thread.
|
|
m_sb_info.thread_handle = _beginthread(StreamTimer, 16384, (void *)&m_sb_info);
|
|
if (m_sb_info.thread_handle == -1) {
|
|
m_sb_info.thread_alive = false;
|
|
mprintf((0, "Thread failed\n"));
|
|
Int3();
|
|
return false;
|
|
}
|
|
|
|
if (m_sb_info.m_f_secondary_looping) {
|
|
if (!SetThreadPriority((HANDLE)m_sb_info.thread_handle, THREAD_PRIORITY_HIGHEST))
|
|
Int3();
|
|
} else {
|
|
if (!SetThreadPriority((HANDLE)m_sb_info.thread_handle, THREAD_PRIORITY_TIME_CRITICAL))
|
|
Int3();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// Creates a 2d, 3d, or Primary direct sound buffer
|
|
long win_llsSystem::CreateDSBuffer(int buffer_type, LPDIRECTSOUNDBUFFER *lp_lp_dsb, LPDIRECTSOUND3DBUFFER *lp_lp_dsb_3d,
|
|
ulong sound_bytes, ulong frequency, bool f_is_stereo, bool f_is_16_bit) {
|
|
DSBUFFERDESC dsbd;
|
|
tWAVEFORMATEX fmt;
|
|
HRESULT result = DS_OK;
|
|
|
|
ASSERT(m_lp_ds != NULL && sound_bytes >= 0);
|
|
ASSERT(frequency == 44100 || frequency == 22050 || frequency == 11025);
|
|
if (!m_f_sound_lib_init)
|
|
return 0;
|
|
|
|
if (lp_lp_dsb) {
|
|
*lp_lp_dsb = NULL;
|
|
}
|
|
if (lp_lp_dsb_3d) {
|
|
*lp_lp_dsb_3d = NULL;
|
|
}
|
|
|
|
// Setup the wave format
|
|
fmt.nChannels = (f_is_stereo) ? 2 : 1;
|
|
fmt.wBitsPerSample = (f_is_16_bit) ? 16 : 8;
|
|
fmt.nSamplesPerSec = ((DWORD)frequency);
|
|
fmt.nBlockAlign = fmt.nChannels * (fmt.wBitsPerSample >> 3);
|
|
fmt.nAvgBytesPerSec = ((DWORD)fmt.nSamplesPerSec) * ((DWORD)fmt.nBlockAlign);
|
|
fmt.wFormatTag = WAVE_FORMAT_PCM;
|
|
|
|
// Setup the secondary direct sound buffer
|
|
memset(&dsbd, 0, sizeof(dsbd));
|
|
dsbd.lpwfxFormat = (LPWAVEFORMATEX)&fmt;
|
|
dsbd.dwSize = sizeof(DSBUFFERDESC);
|
|
dsbd.dwBufferBytes = sound_bytes;
|
|
|
|
if (m_mixer_type == SOUND_MIXER_SOFTWARE_16) {
|
|
dsbd.dwFlags = DSBCAPS_GETCURRENTPOSITION2;
|
|
|
|
ASSERT(buffer_type == SBT_PRIMARY);
|
|
|
|
m_primary_frequency = m_current_frequency = frequency;
|
|
m_primary_bit_depth = fmt.wBitsPerSample;
|
|
m_primary_alignment = fmt.nBlockAlign;
|
|
|
|
dsbd.lpwfxFormat = NULL;
|
|
dsbd.dwBufferBytes = 0;
|
|
dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER | DSBCAPS_GETCURRENTPOSITION2;
|
|
} else if (m_mixer_type == SOUND_MIXER_DS_16 || m_mixer_type == SOUND_MIXER_DS_8) {
|
|
// There are three buffer types that we should consider.
|
|
switch (buffer_type) {
|
|
case SBT_2D:
|
|
dsbd.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLPAN;
|
|
break;
|
|
case SBT_PRIMARY:
|
|
dsbd.lpwfxFormat = NULL;
|
|
dsbd.dwBufferBytes = 0;
|
|
dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER;
|
|
break;
|
|
default:
|
|
ASSERT(0); // Invalid type of buffer
|
|
}
|
|
} else if (IS_3D_MIXER(m_mixer_type)) {
|
|
// There are three buffer types that we should consider.
|
|
switch (buffer_type) {
|
|
case SBT_2D:
|
|
dsbd.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLPAN;
|
|
break;
|
|
case SBT_3D:
|
|
dsbd.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRL3D | DSBCAPS_CTRLVOLUME;
|
|
break;
|
|
case SBT_PRIMARY:
|
|
dsbd.lpwfxFormat = NULL;
|
|
dsbd.dwBufferBytes = 0;
|
|
dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER | DSBCAPS_CTRL3D | DSBCAPS_CTRLVOLUME;
|
|
break;
|
|
default:
|
|
ASSERT(0); // Invalid type of buffer
|
|
}
|
|
} else {
|
|
mprintf(
|
|
(0, "DS3DLIB: Unsupported function for mixer specfied in CreateDSBuffer (%d,%d)\n", m_mixer_type, buffer_type));
|
|
Int3(); // Get Samir!!!
|
|
return DSERR_UNSUPPORTED;
|
|
}
|
|
|
|
// Create the buffer
|
|
result = m_lp_ds->CreateSoundBuffer(&dsbd, lp_lp_dsb, 0);
|
|
/// ASSERT(result == DS_OK);
|
|
|
|
if (result == DS_OK && buffer_type == SBT_PRIMARY) {
|
|
// Creative EAX Init
|
|
if (m_mixer_type == SOUND_MIXER_CREATIVE_EAX) {
|
|
if (!EAX_SetPrimaryBuffer()) {
|
|
mprintf((0, "CreateDSBuffer: EAX Init failed.\n"));
|
|
result = DSERR_UNSUPPORTED;
|
|
goto ds_error;
|
|
}
|
|
}
|
|
|
|
// Succeeded. Set primary buffer to desired format.
|
|
result = (*lp_lp_dsb)->SetFormat(&fmt);
|
|
}
|
|
|
|
if (result != DS_OK) {
|
|
mprintf((0, "DS3DLIB: Failed to init sound buffer of type %d for mixer %d.\n", buffer_type, m_mixer_type));
|
|
goto ds_error;
|
|
}
|
|
|
|
// call get format to make sure we're okay.
|
|
if (buffer_type == SBT_PRIMARY) {
|
|
}
|
|
|
|
// do 3d sound support stuff.
|
|
if (IS_3D_MIXER(m_mixer_type)) {
|
|
// a 3d buffer needs a 3d interface pointer
|
|
if (buffer_type == SBT_3D) {
|
|
ASSERT(lp_lp_dsb_3d != NULL);
|
|
result = (*lp_lp_dsb)->QueryInterface(IID_IDirectSound3DBuffer, (void **)lp_lp_dsb_3d);
|
|
if (result != DS_OK) {
|
|
goto ds_error;
|
|
}
|
|
|
|
// ASSERT(result == DS_OK);
|
|
} else if (buffer_type == SBT_PRIMARY) {
|
|
if ((result = (*lp_lp_dsb)->QueryInterface(IID_IDirectSound3DListener, (void **)&m_lp_listener)) == S_OK) {
|
|
m_lp_listener->SetRolloffFactor(ENV3DVAL_ROLLOFF_DEFAULT, DS3D_IMMEDIATE);
|
|
}
|
|
}
|
|
}
|
|
|
|
ds_error:
|
|
if (result != DS_OK) {
|
|
mprintf((0, "DS3DLIB:result=%x\n", result));
|
|
if (lp_lp_dsb_3d && (*lp_lp_dsb_3d)) {
|
|
(*lp_lp_dsb_3d)->Release();
|
|
*lp_lp_dsb_3d = NULL;
|
|
}
|
|
|
|
if (lp_lp_dsb && (*lp_lp_dsb)) {
|
|
(*lp_lp_dsb)->Release();
|
|
*lp_lp_dsb = NULL;
|
|
}
|
|
}
|
|
|
|
return (long)result;
|
|
}
|
|
|
|
// Internal function to enumerate sound devices
|
|
BOOL CALLBACK LLEnumCallback(LPGUID lp_guid, LPCSTR lpstr_description, LPCSTR lpstr_module, LPVOID lp_Context) {
|
|
GUID FAR *lp_ret_guid = (GUID FAR *)lp_Context;
|
|
|
|
if (m_sound_device_name[0]) {
|
|
if (strcmp(lpstr_description, m_sound_device_name) == 0) {
|
|
mprintf((0, "Using sound card:%s-%s\n", lpstr_description, lpstr_module));
|
|
if (lp_guid) {
|
|
memmove(lp_ret_guid, lp_guid, sizeof(GUID));
|
|
}
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void win_llsSystem::SetSoundCard(const char *name) {
|
|
if (name) {
|
|
strcpy(m_sound_device_name, name);
|
|
} else {
|
|
m_sound_device_name[0] = 0;
|
|
}
|
|
}
|
|
|
|
// Initializes the sound library
|
|
int win_llsSystem::InitSoundLib(char mixer_type, oeApplication *sos, unsigned char MaxSoundsPlayed) // add playlist info
|
|
{
|
|
GUID card_guid, zero_card_guid;
|
|
GUID *pguid = NULL;
|
|
DSCAPS dscaps;
|
|
HRESULT hresult;
|
|
bool f16bit;
|
|
bool retval = true;
|
|
|
|
// reset error system.
|
|
SetError(SSL_OK);
|
|
|
|
#ifdef OEM_AUREAL
|
|
mixer_type = SOUND_MIXER_AUREAL;
|
|
#endif
|
|
|
|
SoundApp = (oeWin32Application *)sos;
|
|
|
|
if (sos) {
|
|
oeWin32Application *obj = (oeWin32Application *)sos;
|
|
|
|
// If the the library if already init'ed, then return o.k.
|
|
if (m_f_sound_lib_init)
|
|
return 1;
|
|
|
|
GameWindowHandle = (void *)obj->m_hWnd;
|
|
} else {
|
|
ASSERT(GameWindowHandle);
|
|
}
|
|
|
|
ll_sound_ptr = this;
|
|
m_timer_last_frametime = -1;
|
|
m_cache_stress_timer = 0.0f;
|
|
m_in_sound_frame = false;
|
|
m_pending_actions = false;
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// chrishack -- Need to enumerate sound devices for now
|
|
// Attempt to enumerate the sound device
|
|
// if(DirectSoundEnumerate(&LLEnumCallback, NULL) != DS_OK) return 0;
|
|
|
|
// Setup the game handle
|
|
m_hwnd_main = GameWindowHandle;
|
|
|
|
// Check for invalid values and NULL pointers
|
|
ASSERT(m_hwnd_main != NULL);
|
|
ASSERT(Sounds != NULL);
|
|
ASSERT(SoundFiles != NULL);
|
|
ASSERT(MaxSoundsPlayed > 0);
|
|
|
|
memset(&m_sb_info, 0, sizeof(DSSTREAM));
|
|
|
|
// Currently restart total sounds played count (for unique ids and stats)
|
|
m_total_sounds_played = 0;
|
|
|
|
// Setup the sound mixer object
|
|
m_sound_mixer.m_cur_sounds_played = 0;
|
|
m_sound_mixer.m_max_sounds_played = MaxSoundsPlayed;
|
|
m_sound_mixer.m_sound_cache = new sound_buffer_info[MaxSoundsPlayed];
|
|
m_mixer_type = SOUND_MIXER_NONE;
|
|
|
|
if (m_sound_mixer.m_sound_cache == NULL) {
|
|
Int3();
|
|
goto error_sub;
|
|
}
|
|
|
|
// Create the Direct Sound Interface
|
|
// determine GUID for sound card which was chosen in the launcher...
|
|
ZeroMemory(&card_guid, sizeof(GUID));
|
|
ZeroMemory(&zero_card_guid, sizeof(GUID));
|
|
hresult = DirectSoundEnumerate(LLEnumCallback, &card_guid);
|
|
if (hresult == DS_OK) {
|
|
if (memcmp(&card_guid, &zero_card_guid, sizeof(GUID)) != 0) {
|
|
pguid = &card_guid;
|
|
}
|
|
}
|
|
|
|
#ifdef SUPPORT_AUREAL
|
|
if (mixer_type == SOUND_MIXER_AUREAL) {
|
|
if (!A3D_Init((HWND)GameWindowHandle)) {
|
|
retval = false;
|
|
goto error_sub;
|
|
}
|
|
m_lp_ds = NULL;
|
|
m_sound_mixer.m_loop_method = DSLOOP_BUFFER_METHOD;
|
|
} else
|
|
#endif
|
|
if (mixer_type != SOUND_MIXER_NONE) {
|
|
if (mixer_type == SOUND_MIXER_CREATIVE_EAX) {
|
|
if (!EAX_Create(pguid, &m_lp_ds)) {
|
|
mprintf((0, "Sound NT: Error EAX\n"));
|
|
retval = false;
|
|
goto error_sub;
|
|
}
|
|
} else {
|
|
hresult = DirectSoundCreate(pguid, &m_lp_ds, NULL);
|
|
if (hresult != DS_OK) {
|
|
retval = false;
|
|
goto error_sub;
|
|
}
|
|
}
|
|
|
|
ASSERT(m_lp_ds != NULL);
|
|
|
|
// determine if we're using a crappy card
|
|
dscaps.dwSize = sizeof(DSCAPS);
|
|
m_lp_ds->GetCaps(&dscaps);
|
|
if (dscaps.dwFlags & DSCAPS_EMULDRIVER) {
|
|
mixer_type = SOUND_MIXER_DS_8;
|
|
mprintf((0, "SOUND INIT(1): We are in NT or have a crappy sound card\n"));
|
|
}
|
|
|
|
m_sound_mixer.m_loop_method = DSLOOP_STREAM_METHOD;
|
|
}
|
|
|
|
if (mixer_type != SOUND_MIXER_NONE) {
|
|
m_f_sound_lib_init = 1;
|
|
}
|
|
|
|
// This section initializes the primary buffer
|
|
// software mixer try.
|
|
retry_mixer_init:
|
|
if (mixer_type == SOUND_MIXER_SOFTWARE_16) {
|
|
// test different conditions to see if we really can play sound in software
|
|
hresult = m_lp_ds->SetCooperativeLevel((HWND)m_hwnd_main, DSSCL_WRITEPRIMARY);
|
|
if (hresult != DS_OK) {
|
|
mprintf((0, "SOUND INIT(2): SCL: WritePrimary failed. Attempting DS 8 init.\n"));
|
|
mixer_type = SOUND_MIXER_DS_8;
|
|
goto retry_mixer_init;
|
|
}
|
|
|
|
// Creates a primary buffer and makes sure we are at the specified frequency, bit depth, and that we
|
|
// can to 3d stuff too :)
|
|
m_mixer_type = SOUND_MIXER_SOFTWARE_16;
|
|
f16bit = true;
|
|
hresult = CreateDSBuffer(SBT_PRIMARY, &m_sb_info.m_lp_primary_buffer, NULL, 0,
|
|
22050, // frequency
|
|
true, // stereo
|
|
f16bit); // 16-bit
|
|
if (hresult != DS_OK) {
|
|
if (m_sb_info.m_lp_primary_buffer) {
|
|
m_sb_info.m_lp_primary_buffer->Release();
|
|
m_sb_info.m_lp_primary_buffer = NULL;
|
|
}
|
|
mprintf((0, "SOUND INIT(3): Cannot create primary buffer.\n"));
|
|
mixer_type = SOUND_MIXER_DS_8;
|
|
goto retry_mixer_init;
|
|
} else {
|
|
// Determine if we are running NT or have a shitty Win95 sound card
|
|
DSBCAPS dsbcaps;
|
|
|
|
ASSERT(m_sb_info.m_lp_primary_buffer);
|
|
|
|
dsbcaps.dwSize = sizeof(DSBCAPS);
|
|
m_sb_info.m_lp_primary_buffer->GetCaps(&dsbcaps);
|
|
|
|
// Let's allocate our array of ints for our optimized software mixer!
|
|
if (!Fast_mixer) {
|
|
Fast_mixer = (int *)mem_malloc(dsbcaps.dwBufferBytes * sizeof(int));
|
|
Fast_mixer_len = dsbcaps.dwBufferBytes;
|
|
mprintf((0, "Using %d ints for fast software mixer\n", dsbcaps.dwBufferBytes));
|
|
}
|
|
|
|
// Is you want to see the caps, here is where -- mprintf all you want
|
|
if (!(dsbcaps.dwFlags & DSBCAPS_LOCHARDWARE)) {
|
|
mprintf((0, "SOUND INIT(4): Primary is not in hardware\n"));
|
|
m_sb_info.m_lp_primary_buffer->Release();
|
|
m_sb_info.m_lp_primary_buffer = NULL;
|
|
mixer_type = SOUND_MIXER_DS_8;
|
|
goto retry_mixer_init;
|
|
}
|
|
}
|
|
|
|
// looping buffer is the same as the primary buffer for software mixers.
|
|
m_sb_info.m_lp_looping_buffer = m_sb_info.m_lp_primary_buffer;
|
|
|
|
// Start the primary and have it always play.
|
|
m_f_sound_lib_init = StartStreaming();
|
|
if (!m_f_sound_lib_init) {
|
|
mprintf((0, "SOUND INIT(5): Something went wrong in StartStreaming\n"));
|
|
m_sb_info.m_lp_primary_buffer->Release();
|
|
m_sb_info.m_lp_primary_buffer = NULL;
|
|
mixer_type = SOUND_MIXER_DS_8;
|
|
goto retry_mixer_init;
|
|
}
|
|
|
|
}
|
|
#ifdef SUPPORT_AUREAL
|
|
else if (mixer_type == SOUND_MIXER_AUREAL) {
|
|
m_mixer_type = SOUND_MIXER_AUREAL;
|
|
if (!A3D_CreateListener()) {
|
|
retval = false;
|
|
goto error_sub;
|
|
}
|
|
A3D_SetRolloffFactor(ENV3DVAL_ROLLOFF_DEFAULT);
|
|
A3D_SetUnitsPerMeter(1.0f); // feet per meter.
|
|
}
|
|
#endif
|
|
else if (mixer_type == SOUND_MIXER_NONE) {
|
|
m_mixer_type = mixer_type;
|
|
m_f_sound_lib_init = 0;
|
|
} else {
|
|
// This is for DirectSound Internal Mixers. We let DirectSound do its magic.
|
|
m_mixer_type = mixer_type;
|
|
hresult = m_lp_ds->SetCooperativeLevel((HWND)m_hwnd_main, DSSCL_PRIORITY);
|
|
if (hresult != DS_OK) {
|
|
mprintf((0, "Sound NT: Error 1\n"));
|
|
retval = false;
|
|
goto error_sub;
|
|
}
|
|
|
|
// start primary buffer
|
|
f16bit = (mixer_type == SOUND_MIXER_DS_16 || mixer_type == SOUND_MIXER_DS3D_16 ||
|
|
mixer_type == SOUND_MIXER_CREATIVE_EAX);
|
|
hresult = CreateDSBuffer(SBT_PRIMARY, &m_sb_info.m_lp_primary_buffer, NULL, 0,
|
|
22050, // frequency
|
|
true, // stereo
|
|
f16bit); // 8 or 16 bit
|
|
if (hresult != DS_OK) {
|
|
mprintf((0, "Sound NT: Error 2\n"));
|
|
if (m_sb_info.m_lp_primary_buffer) {
|
|
m_sb_info.m_lp_primary_buffer->Release();
|
|
m_sb_info.m_lp_primary_buffer = NULL;
|
|
}
|
|
retval = false;
|
|
goto error_sub;
|
|
}
|
|
|
|
m_sb_info.m_lp_primary_buffer->Play(0, 0, DSBPLAY_LOOPING);
|
|
}
|
|
|
|
// buffered method doesn't use threads at all.
|
|
if (m_mixer_type != SOUND_MIXER_SOFTWARE_16 && m_mixer_type != SOUND_MIXER_NONE &&
|
|
m_sound_mixer.m_loop_method != DSLOOP_BUFFER_METHOD) {
|
|
// start looping thread, failure results in a 'clean exit'
|
|
if (!sb_loop_thread_init(this)) {
|
|
retval = false;
|
|
if (m_sb_info.m_lp_primary_buffer) {
|
|
m_sb_info.m_lp_primary_buffer->Release();
|
|
m_sb_info.m_lp_primary_buffer = NULL;
|
|
}
|
|
goto error_sub;
|
|
}
|
|
}
|
|
|
|
mprintf((0, "Sound mixer: "));
|
|
retval = true;
|
|
|
|
switch (m_mixer_type) {
|
|
case SOUND_MIXER_SOFTWARE_16:
|
|
mprintf((0, "Software 16\n"));
|
|
break;
|
|
case SOUND_MIXER_DS_8:
|
|
mprintf((0, "DS 8\n"));
|
|
break;
|
|
case SOUND_MIXER_DS_16:
|
|
mprintf((0, "DS 16\n"));
|
|
break;
|
|
case SOUND_MIXER_DS3D_16:
|
|
mprintf((0, "DS3D 16\n"));
|
|
break;
|
|
case SOUND_MIXER_AUREAL:
|
|
mprintf((0, "Aureal 3D\n"));
|
|
break;
|
|
case SOUND_MIXER_CREATIVE_EAX:
|
|
mprintf((0, "Creative EAX\n"));
|
|
break;
|
|
case SOUND_MIXER_NONE:
|
|
mprintf((0, "None\n"));
|
|
break;
|
|
default:
|
|
mprintf((0, "LLSound ERROR: Unsupported mixer"));
|
|
Int3();
|
|
retval = false;
|
|
break;
|
|
}
|
|
|
|
// set 3d environment settings
|
|
t3dEnvironmentToggles env_toggles;
|
|
t3dEnvironmentValues env_values;
|
|
|
|
memset(&Env3dValues, 0, sizeof(Env3dValues));
|
|
memset(&Env3dToggles, 0, sizeof(Env3dToggles));
|
|
|
|
env_toggles.flags = 0; // get supported features
|
|
GetEnvironmentToggles(&env_toggles);
|
|
|
|
env_values.flags = 0; // set up values and toggles to be set
|
|
env_toggles.flags = env_toggles.supported;
|
|
|
|
// we may want to check this with configured options later -- samir
|
|
if (CHECK_FLAG(env_toggles.supported, ENV3DVALF_DOPPLER) && ENV3DTOG_DOPPLER) {
|
|
env_values.flags |= ENV3DVALF_DOPPLER;
|
|
env_values.doppler_scalar = ENV3DVAL_DOPPLER_DEFAULT;
|
|
env_toggles.doppler = true;
|
|
}
|
|
if (CHECK_FLAG(env_toggles.supported, ENV3DVALF_GEOMETRY) && ENV3DTOG_GEOMETRY) {
|
|
env_toggles.geometry = true;
|
|
}
|
|
SetEnvironmentToggles(&env_toggles);
|
|
SetEnvironmentValues(&env_values);
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
g_emulated_listener = &m_emulated_listener;
|
|
|
|
error_sub:
|
|
if (retval == false) {
|
|
// Only gets here if there was an error
|
|
#ifdef SUPPORT_AUREAL
|
|
if (m_mixer_type == SOUND_MIXER_AUREAL) {
|
|
A3D_Destroy();
|
|
} else
|
|
#endif
|
|
if (m_mixer_type == SOUND_MIXER_CREATIVE_EAX) {
|
|
EAX_Destroy();
|
|
} else if (m_lp_ds) {
|
|
m_lp_ds->Release();
|
|
}
|
|
m_lp_ds = NULL;
|
|
mprintf((0, "Sound Warning: Didn't initialize sound library.\n"));
|
|
if (m_sound_mixer.m_sound_cache != NULL)
|
|
delete[] m_sound_mixer.m_sound_cache;
|
|
m_f_sound_lib_init = 0;
|
|
m_mixer_type = SOUND_MIXER_NONE;
|
|
}
|
|
|
|
Global_DS_alloced_sounds = 0;
|
|
|
|
return (m_f_sound_lib_init);
|
|
}
|
|
|
|
// Cleans up after the sound library is done being used
|
|
void win_llsSystem::DestroySoundLib(void) {
|
|
bool f_all_done = false;
|
|
|
|
if (!m_f_sound_lib_init)
|
|
return;
|
|
|
|
mprintf((0, "Start of sound system close\n"));
|
|
|
|
// kill sound geometry object if any.
|
|
if (m_geometry) {
|
|
m_geometry->Shutdown();
|
|
m_geometry = NULL;
|
|
}
|
|
|
|
StopAllSounds();
|
|
|
|
// Wait till they are all done
|
|
mprintf((0, "Waiting for sounds to stop\n"));
|
|
if (m_mixer_type != SOUND_MIXER_SOFTWARE_16) {
|
|
while (!f_all_done) {
|
|
f_all_done = true;
|
|
int i;
|
|
|
|
for (i = 0; i < m_sound_mixer.m_max_sounds_played; i++) {
|
|
sound_buffer_info *sb = &m_sound_mixer.m_sound_cache[i];
|
|
if (sb->s && sb->s->kill_me && !(sb->m_status & (SSF_BUFFERED_LOOP + SSF_BUFFERED_STRM))) {
|
|
cleanup_directsound_looping_sb(&m_sound_mixer.m_sound_cache[i]);
|
|
} else if (sb->m_status & (SSF_PLAY_LOOPING | SSF_PLAY_STREAMING)) {
|
|
// this should block until the sound is truly free, so we don't need to do a 'all done'
|
|
StopSound(m_sound_mixer.m_sound_cache[i].m_unique_id, SKT_HOLD_UNTIL_STOP);
|
|
// f_all_done = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
// buffered method doesn't use threads at all.
|
|
if (m_sound_mixer.m_loop_method != DSLOOP_BUFFER_METHOD) {
|
|
sb_loop_thread_kill();
|
|
}
|
|
#ifdef SUPPORT_AUREAL
|
|
if (m_mixer_type == SOUND_MIXER_AUREAL) {
|
|
A3D_Flush();
|
|
}
|
|
#endif
|
|
}
|
|
mprintf((0, "All sounds stopped\n"));
|
|
|
|
if (m_mixer_type == SOUND_MIXER_SOFTWARE_16) {
|
|
// Kill thread goes here
|
|
if (m_sb_info.thread_handle) {
|
|
m_sb_info.thread_request_kill = true;
|
|
while (m_sb_info.thread_alive) {
|
|
}
|
|
}
|
|
|
|
if (m_mixer_type == SOUND_MIXER_SOFTWARE_16) {
|
|
m_sb_info.m_lp_looping_buffer->Stop();
|
|
m_sb_info.m_lp_looping_buffer->Release();
|
|
}
|
|
}
|
|
|
|
// free audio device;
|
|
#ifdef SUPPORT_AUREAL
|
|
if (m_mixer_type == SOUND_MIXER_AUREAL) {
|
|
A3D_Destroy();
|
|
} else
|
|
#endif
|
|
if (m_mixer_type == SOUND_MIXER_CREATIVE_EAX) {
|
|
EAX_Destroy();
|
|
} else if (m_lp_ds) {
|
|
m_lp_ds->Release();
|
|
}
|
|
|
|
m_lp_ds = NULL;
|
|
m_sb_info.m_lp_looping_buffer = NULL;
|
|
|
|
mprintf((0, "End of sound system close\n"));
|
|
|
|
if (m_sound_mixer.m_sound_cache != NULL)
|
|
delete[] m_sound_mixer.m_sound_cache;
|
|
|
|
m_f_sound_lib_init = false;
|
|
g_emulated_listener = NULL;
|
|
m_mixer_type = -1;
|
|
ll_sound_ptr = NULL;
|
|
if (Fast_mixer) {
|
|
mem_free(Fast_mixer);
|
|
Fast_mixer = NULL;
|
|
Fast_mixer_len = 0;
|
|
}
|
|
}
|
|
|
|
// used to clean up direct sound buffer stuff
|
|
void win_llsSystem::cleanup_directsound_looping_sb(sound_buffer_info *sb) {
|
|
if (!sb->s)
|
|
return;
|
|
if (!sb->s->kill_me)
|
|
return;
|
|
|
|
// should occur when kill_me set, sb_stop_buffer(&ll_sound_ptr->m_sound_mixer.m_sound_cache[i]);
|
|
sb_free_buffer(sb);
|
|
|
|
sb->m_sound_buffer = NULL;
|
|
sb->s->playing = 0;
|
|
|
|
void *p = (void *)sb->s;
|
|
sb->s = NULL;
|
|
sb->m_status = SSF_UNUSED;
|
|
mem_free(p);
|
|
}
|
|
|
|
// cleans up a sound -replaces a lot of repeated code whenever we cleanup sounds.
|
|
void win_llsSystem::update_directsound_sb(sound_buffer_info *sb, bool update_looping) {
|
|
if (m_mixer_type == SOUND_MIXER_SOFTWARE_16 || m_mixer_type == SOUND_MIXER_NONE) {
|
|
return;
|
|
}
|
|
|
|
// take care of any streamed threaded method looping sounds that are done.
|
|
// orphan streaming structure, clean it up! (sound buffer is NULL yet sb->s is valid
|
|
if (sb->s && (((sb->m_status & (SSF_BUFFERED_LOOP + SSF_BUFFERED_STRM)) && !sb->m_sound_buffer) || sb->s->kill_me)) {
|
|
cleanup_directsound_looping_sb(sb);
|
|
} else if (sb->m_status && !(sb->m_status & SSF_PAUSED)) {
|
|
// non playing sounds should be stopped always
|
|
int status = sb_get_status(sb);
|
|
|
|
if (update_looping) {
|
|
// int status2 = A3D_GetSourceStatus(sb->m_snd_obj);
|
|
// mprintf((0, "(%x) status (%x)\n", sb->m_unique_id, status2));
|
|
|
|
if (status & SB_STATUS_PLAYING) {
|
|
if ((sb->m_status & (SSF_PLAY_STREAMING + SSF_BUFFERED_STRM)) == (SSF_PLAY_STREAMING + SSF_BUFFERED_STRM)) {
|
|
sb_stream_buffered_update(sb);
|
|
}
|
|
} else {
|
|
if ((sb->m_status & (SSF_PLAY_LOOPING + SSF_BUFFERED_LOOP)) == (SSF_PLAY_LOOPING + SSF_BUFFERED_LOOP)) {
|
|
sb_buffered_loop_step(this, sb);
|
|
status = sb_get_status(sb); // get new status for following checks.
|
|
}
|
|
}
|
|
}
|
|
if (!(status & SB_STATUS_PLAYING)) {
|
|
StopSound(sb->m_unique_id);
|
|
} else if (status & SB_STATUS_INVALID) {
|
|
StopSound(sb->m_unique_id);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Stops the sound from playing -- f_immediately is used for looping samples -- i.e. so we can
|
|
// play the end of loop snipit
|
|
void win_llsSystem::StopSound(int sound_uid, unsigned char f_immediately) {
|
|
int current_slot;
|
|
sound_buffer_info *sb;
|
|
|
|
if (!m_f_sound_lib_init)
|
|
return;
|
|
|
|
if ((current_slot = ValidateUniqueId(sound_uid)) == -1)
|
|
return;
|
|
|
|
sb = &m_sound_mixer.m_sound_cache[current_slot];
|
|
|
|
if (sb->m_status == SSF_UNUSED)
|
|
return;
|
|
|
|
// update sound count.
|
|
m_sound_mixer.m_cur_sounds_played--;
|
|
|
|
if (f_immediately == SKT_STOP_AFTER_LOOP) {
|
|
sb->m_status &= ~SSF_PLAY_LOOPING;
|
|
sb->m_status |= SSF_PLAY_NORMAL;
|
|
if (m_mixer_type != SOUND_MIXER_SOFTWARE_16 && (sb->m_status & SSF_BUFFERED_LOOP)) {
|
|
sb_buffered_loop_step(this, sb, DSBUFLOOP_FINISH_STEP);
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (m_mixer_type != SOUND_MIXER_SOFTWARE_16) {
|
|
if (sb->s && !(sb->m_status & (SSF_BUFFERED_LOOP + SSF_BUFFERED_STRM))) {
|
|
sb_loop_element_kill(sb);
|
|
if (f_immediately == SKT_HOLD_UNTIL_STOP) {
|
|
sb_loop_element_wait_until_dead(sb);
|
|
cleanup_directsound_looping_sb(sb);
|
|
}
|
|
return;
|
|
} else if (sb->m_sound_buffer) // this works for buffered loops too.
|
|
{
|
|
if (sb->m_status & (SSF_BUFFERED_LOOP + SSF_BUFFERED_STRM)) {
|
|
if (sb->m_status & SSF_PLAY_STREAMING) {
|
|
sb_stream_element_kill(sb);
|
|
}
|
|
|
|
void *p = (void *)sb->s;
|
|
if (p) {
|
|
mem_free(p);
|
|
sb->s = NULL;
|
|
}
|
|
}
|
|
GetSoundPos(sb->m_unique_id);
|
|
sb_stop_buffer(sb);
|
|
sb_free_buffer(sb);
|
|
|
|
if (SoundFiles[Sounds[sb->m_sound_index].sample_index].use_count > 0) {
|
|
SoundFiles[Sounds[sb->m_sound_index].sample_index].use_count--;
|
|
// DUPSND if (SoundFiles[Sounds[sb->m_sound_index].sample_index].use_count == 0) {
|
|
// DUPSND Global_DS_alloced_sounds--;
|
|
// DUPSND }
|
|
}
|
|
Global_DS_alloced_sounds--;
|
|
}
|
|
m_sound_mixer.m_sound_cache[current_slot].m_sound_buffer = NULL;
|
|
}
|
|
|
|
// mprintf((0, "SL cleaning slot %d\n", current_slot));
|
|
m_sound_mixer.m_sound_cache[current_slot].m_status = SSF_UNUSED;
|
|
}
|
|
|
|
// Copies sound data from the external sound data block to an individual sound buffer
|
|
long LoadSoundData(LPDIRECTSOUNDBUFFER lp_dsb, char *sound_data_ptr, ulong total_bytes) {
|
|
LPVOID ptr1, ptr2;
|
|
DWORD len1, len2;
|
|
HRESULT result;
|
|
|
|
ASSERT(lp_dsb != NULL && sound_data_ptr != NULL && total_bytes > 0);
|
|
|
|
TryLockAgainLabel:
|
|
result = lp_dsb->Lock(0, total_bytes, &ptr1, &len1, &ptr2, &len2, 0);
|
|
|
|
switch (result) {
|
|
case DS_OK:
|
|
memcpy(ptr1, sound_data_ptr, len1);
|
|
if (ptr2)
|
|
memcpy(ptr2, sound_data_ptr + len1, len2);
|
|
lp_dsb->Unlock(ptr1, len1, ptr2, len2);
|
|
break;
|
|
case DSERR_BUFFERLOST:
|
|
result = lp_dsb->Restore();
|
|
if (result == DS_OK)
|
|
goto TryLockAgainLabel;
|
|
break;
|
|
}
|
|
|
|
return (long)result;
|
|
}
|
|
|
|
// Determines if a sound will play. Takes into account maximum allowable
|
|
// sounds.
|
|
// Also put prioritization code in here
|
|
// ignore reserved slots
|
|
|
|
#ifdef _DEBUG
|
|
short win_llsSystem::FindFreeSoundSlot(int sound_index, float volume, int priority)
|
|
#else
|
|
short win_llsSystem::FindFreeSoundSlot(float volume, int priority)
|
|
#endif
|
|
{
|
|
int current_slot;
|
|
sound_buffer_info *sb;
|
|
|
|
// stop any left over sounds for Direct Sound.
|
|
if (m_mixer_type != SOUND_MIXER_SOFTWARE_16) {
|
|
for (current_slot = 0; current_slot < m_sound_mixer.m_max_sounds_played; current_slot++) {
|
|
sb = &m_sound_mixer.m_sound_cache[current_slot];
|
|
update_directsound_sb(sb);
|
|
}
|
|
}
|
|
|
|
for (current_slot = 0; current_slot < m_sound_mixer.m_max_sounds_played; current_slot++) {
|
|
sb = &m_sound_mixer.m_sound_cache[current_slot];
|
|
if (sb->m_status == SSF_UNUSED) {
|
|
if (!((m_mixer_type == SOUND_MIXER_DS_8 || m_mixer_type == SOUND_MIXER_DS_16 ||
|
|
m_mixer_type == SOUND_MIXER_DS3D_16 || m_mixer_type == SOUND_MIXER_AUREAL ||
|
|
m_mixer_type == SOUND_MIXER_CREATIVE_EAX) &&
|
|
sb->s))
|
|
return current_slot;
|
|
}
|
|
}
|
|
|
|
// no more slots? take priority into account.
|
|
// throw out lowest priority sound slot (must be lower than or equal to new sound priority)
|
|
float weighted_priority = (priority * 2.0f) * volume;
|
|
if (current_slot == m_sound_mixer.m_max_sounds_played) {
|
|
int throw_out_slot = -1, equiv_priority_slot = -1;
|
|
float weighted_priorityA, weighted_priorityB;
|
|
for (current_slot = 0; current_slot < m_sound_mixer.m_max_sounds_played; current_slot++) {
|
|
sb = &m_sound_mixer.m_sound_cache[current_slot];
|
|
if (!(sb->m_status & (SSF_PLAY_LOOPING + SSF_PLAY_STREAMING))) {
|
|
weighted_priorityA = sb->play_info->priority * 2.0f * sb->m_volume;
|
|
if (weighted_priorityA < weighted_priority) {
|
|
if (throw_out_slot == -1) {
|
|
throw_out_slot = current_slot;
|
|
} else {
|
|
play_information *play_info2 = m_sound_mixer.m_sound_cache[throw_out_slot].play_info;
|
|
weighted_priorityB = play_info2->priority * 2.0f * sb->m_volume;
|
|
if (weighted_priorityB > weighted_priorityA) {
|
|
throw_out_slot = current_slot;
|
|
}
|
|
}
|
|
}
|
|
|
|
else if (equiv_priority_slot == -1 && weighted_priorityA == weighted_priority) {
|
|
equiv_priority_slot = current_slot;
|
|
}
|
|
}
|
|
}
|
|
|
|
// if no slot found to stop, look for a slot with priority == new priority
|
|
if (throw_out_slot == -1) {
|
|
throw_out_slot = equiv_priority_slot;
|
|
}
|
|
if (throw_out_slot > -1) {
|
|
sb = &m_sound_mixer.m_sound_cache[throw_out_slot];
|
|
win_llsSystem::StopSound(sb->m_unique_id, SKT_HOLD_UNTIL_STOP);
|
|
// mprintf((0, "DDSNDLIB: Replace sound (p:%d) with sound (p:%d) in slot %d\n", sb->play_info->priority,
|
|
// priority, throw_out_slot));
|
|
return throw_out_slot;
|
|
}
|
|
}
|
|
|
|
#ifdef _DEBUG
|
|
if (sound_index > -1) {
|
|
mprintf((0, "DDSNDLIB: Sound %s with priority (%d) too low.\n", Sounds[sound_index].name, priority));
|
|
} else {
|
|
mprintf((0, "DDSNDLIB: Sound unknown with priority (%d) too low.\n", priority));
|
|
}
|
|
#endif
|
|
|
|
return -1;
|
|
}
|
|
|
|
int win_llsSystem::PlaySound2d(play_information *play_info, int sound_index, float f_volume, float f_pan,
|
|
bool f_looped) {
|
|
sound_buffer_info *sb = NULL;
|
|
short sound_slot;
|
|
|
|
if (!m_f_sound_lib_init) {
|
|
return -1;
|
|
}
|
|
|
|
// calculate volume and pan
|
|
f_volume = (f_volume < 0.0f) ? 0.0f : (f_volume > 1.0f) ? 1.0f : f_volume;
|
|
play_info->left_volume = play_info->right_volume = f_volume;
|
|
|
|
f_pan = (f_pan < -1.0f) ? -1.0f : (f_pan > 1.0f) ? 1.0f : f_pan;
|
|
if (f_pan < 0.0) {
|
|
play_info->right_volume += f_volume * f_pan;
|
|
} else {
|
|
play_info->left_volume -= f_volume * f_pan;
|
|
}
|
|
|
|
// do common processing.
|
|
if (SoundFiles[Sounds[sound_index].sample_index].used == 0) {
|
|
mprintf((0, "Tryed to play %d sound, it DNE.\n", sound_index));
|
|
return -1;
|
|
}
|
|
#ifdef _DEBUG
|
|
sound_slot = FindFreeSoundSlot(sound_index, f_volume, play_info->priority);
|
|
#else
|
|
sound_slot = FindFreeSoundSlot(f_volume, play_info->priority);
|
|
#endif
|
|
if (sound_slot < 0) {
|
|
// do prioritization code here.
|
|
return -1;
|
|
}
|
|
sb = &m_sound_mixer.m_sound_cache[sound_slot];
|
|
m_total_sounds_played++;
|
|
sb->play_info = play_info;
|
|
sb->m_unique_id = MakeUniqueId(sound_slot);
|
|
sb->m_buffer_type = SBT_2D;
|
|
sb->m_sound_index = sound_index;
|
|
sb->m_status = SSF_UNUSED;
|
|
|
|
ASSERT(sb->m_unique_id != -1);
|
|
|
|
// play 2d sound
|
|
if (m_mixer_type == SOUND_MIXER_SOFTWARE_16) {
|
|
sb->m_status = (f_looped) ? SSF_PLAY_LOOPING : SSF_PLAY_NORMAL;
|
|
return sb->m_unique_id;
|
|
}
|
|
|
|
if (f_looped) {
|
|
LoopStartStreaming(sb, SBT_2D, f_volume, f_pan, NULL);
|
|
if (sb->m_snd_obj == NULL) {
|
|
sb->m_status = SSF_UNUSED;
|
|
Int3();
|
|
return -1;
|
|
}
|
|
} else {
|
|
tPSBInfo psb;
|
|
|
|
if (SoundFiles[Sounds[sound_index].sample_index].use_count > 0) {
|
|
if (DuplicateSoundBuffer(sb)) {
|
|
goto play_sound;
|
|
}
|
|
}
|
|
if (!CreateSoundBuffer(sb, false)) {
|
|
return -1;
|
|
}
|
|
if (!LoadSoundBuffer(sb)) {
|
|
sb_free_buffer(sb);
|
|
return -1;
|
|
}
|
|
|
|
play_sound:
|
|
sb->m_status = SSF_PLAY_NORMAL;
|
|
|
|
psb.volume = f_volume;
|
|
psb.pan = f_pan;
|
|
psb.freq = 22050;
|
|
psb.looping = false;
|
|
if (!PlaySoundBuffer(sb, &psb)) {
|
|
sb_free_buffer(sb);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
m_sound_mixer.m_cur_sounds_played++;
|
|
|
|
return sb->m_unique_id;
|
|
}
|
|
|
|
void win_llsSystem::LoopStartStreaming(sound_buffer_info *sb, int buffer_type, float volume, float pan,
|
|
pos_state *cur_pos) {
|
|
// unsigned long thread_handle;
|
|
int sound_length, buffer_size;
|
|
int determined_method;
|
|
bool f_sample_16bit;
|
|
char *sample_ptr;
|
|
tPSBInfo psb;
|
|
DSLOOPSTREAM *s;
|
|
|
|
// setup looping buffer. must clear out before assigning to sound buffer for thread security.
|
|
s = (DSLOOPSTREAM *)mem_malloc(sizeof(DSLOOPSTREAM));
|
|
if (s == NULL) {
|
|
sb->s = NULL;
|
|
return;
|
|
}
|
|
memset((void *)s, 0, sizeof(DSLOOPSTREAM));
|
|
sb->s = s;
|
|
|
|
sample_ptr = get_sound_info(sb, &sound_length, &f_sample_16bit);
|
|
sb->s->f_sample_16bit = f_sample_16bit;
|
|
sb->m_buffer_type = buffer_type;
|
|
|
|
if (m_sound_mixer.m_loop_method == DSLOOP_SMART_METHOD) {
|
|
int loop_startb, loop_endb;
|
|
bool b;
|
|
if (sb_get_loop_info(sb, &loop_startb, &loop_endb, &b)) {
|
|
if (SoundFiles[Sounds[sb->m_sound_index].sample_index].np_sample_length == (loop_endb - loop_startb + 1)) {
|
|
determined_method = DSLOOP_BUFFER_METHOD;
|
|
} else {
|
|
determined_method = DSLOOP_STREAM_METHOD;
|
|
}
|
|
} else { // wtf?
|
|
return;
|
|
}
|
|
} else {
|
|
determined_method = m_sound_mixer.m_loop_method;
|
|
}
|
|
|
|
switch (determined_method) {
|
|
case DSLOOP_BUFFER_METHOD:
|
|
sound_length = 0;
|
|
sb->s->loop_step = -1;
|
|
while (!sound_length && sb->s->loop_step < 2) {
|
|
sample_ptr = sb_get_loop_step_info(sb, sb->s->loop_step, f_sample_16bit, &sound_length);
|
|
sb->s->loop_step++;
|
|
}
|
|
if (!sound_length && sb->s->loop_step == 2) {
|
|
// hmm, weird loop. no sample?
|
|
return;
|
|
}
|
|
sb->s->loop_step--; // return to proper step.
|
|
sb->s->loop_timer = 0.0f;
|
|
sb->s->bytes_left = sound_length;
|
|
buffer_size = sound_length;
|
|
sb->m_status = SSF_PLAY_LOOPING | SSF_BUFFERED_LOOP;
|
|
// mprintf((0, "DDSNDLIB: Starting buffered loop %d (step %d).\n", sb->m_unique_id, sb->s->loop_step));
|
|
break;
|
|
default:
|
|
buffer_size = STREAM_BUFFER_SIZE;
|
|
sb->m_status = SSF_PLAY_LOOPING; // must go before buffer is initialized!!!!!!
|
|
}
|
|
|
|
sb->sample_data = sample_ptr;
|
|
|
|
// allocate buffer for playback
|
|
if (!CreateSoundBuffer(sb, false, buffer_size, (sb->m_status & SSF_BUFFERED_LOOP) ? false : true)) {
|
|
return;
|
|
}
|
|
|
|
// remind sb system and play.
|
|
if (determined_method == DSLOOP_BUFFER_METHOD) {
|
|
psb.looping = (sb->s->loop_step == 0) ? true : false;
|
|
if (!sb_load_buffer(sb, sb->sample_data, sound_length))
|
|
return;
|
|
} else if (sb_loop_element_init(sb, sample_ptr, sound_length, STREAM_BUFFER_SIZE)) {
|
|
psb.looping = true;
|
|
} else {
|
|
sb->s->playing = 0;
|
|
return;
|
|
}
|
|
|
|
if (buffer_type == SBT_3D) {
|
|
psb.cur_pos = cur_pos;
|
|
} else {
|
|
ASSERT(buffer_type == SBT_2D);
|
|
psb.pan = pan;
|
|
}
|
|
psb.volume = volume;
|
|
psb.freq = 22050;
|
|
|
|
PlaySoundBuffer(sb, &psb);
|
|
|
|
// must be at end to initiate thread management.
|
|
sb->s->playing = 1;
|
|
}
|
|
|
|
void win_llsSystem::DSStartStreaming(sound_buffer_info *sb, float volume, float pan) {
|
|
tPSBInfo psb;
|
|
int sound_length;
|
|
int stream_buflength;
|
|
int determined_method;
|
|
char *sample_ptr;
|
|
bool f_stereo;
|
|
|
|
sb->s = (DSLOOPSTREAM *)mem_malloc(sizeof(DSLOOPSTREAM));
|
|
ASSERT(sb->s);
|
|
if (sb->s == NULL)
|
|
return;
|
|
|
|
memset((void *)sb->s, 0, sizeof(DSLOOPSTREAM));
|
|
|
|
sample_ptr = (char *)sb->play_info->m_stream_data;
|
|
sound_length = sb->play_info->m_stream_size;
|
|
stream_buflength = sb->play_info->m_stream_bufsize;
|
|
|
|
switch (sb->play_info->m_stream_format) {
|
|
case SIF_STREAMING_16_M:
|
|
sb->s->f_sample_16bit = true;
|
|
f_stereo = false;
|
|
break;
|
|
|
|
case SIF_STREAMING_8_M:
|
|
sb->s->f_sample_16bit = false;
|
|
f_stereo = false;
|
|
break;
|
|
|
|
case SIF_STREAMING_16_S:
|
|
sb->s->f_sample_16bit = true;
|
|
f_stereo = true;
|
|
break;
|
|
|
|
case SIF_STREAMING_8_S:
|
|
sb->s->f_sample_16bit = false;
|
|
f_stereo = true;
|
|
break;
|
|
|
|
default:
|
|
ASSERT(0);
|
|
break;
|
|
}
|
|
|
|
ASSERT(sb->m_buffer_type == SBT_2D);
|
|
sb->m_sound_index = -1;
|
|
|
|
// determine how we will stream this data
|
|
determined_method = m_sound_mixer.m_loop_method;
|
|
if (m_sound_mixer.m_loop_method == DSLOOP_SMART_METHOD) {
|
|
if (m_mixer_type == SOUND_MIXER_AUREAL) {
|
|
determined_method = DSLOOP_BUFFER_METHOD;
|
|
}
|
|
}
|
|
|
|
switch (determined_method) {
|
|
case DSLOOP_BUFFER_METHOD:
|
|
sb->m_status = SSF_PLAY_STREAMING | SSF_BUFFERED_STRM;
|
|
break;
|
|
default:
|
|
sb->m_status = SSF_PLAY_STREAMING; // must go before buffer is initialized!!!!!!
|
|
break;
|
|
}
|
|
|
|
if (!CreateSoundBuffer(sb, f_stereo, stream_buflength, true)) {
|
|
mem_free((void *)sb->s);
|
|
sb->s = NULL;
|
|
return;
|
|
}
|
|
|
|
// set wave event or do thread streamed method
|
|
if (sb_stream_element_init(sb, sample_ptr, sound_length, stream_buflength)) {
|
|
psb.pan = pan;
|
|
psb.volume = volume;
|
|
psb.freq = 22050;
|
|
psb.looping = true;
|
|
|
|
PlaySoundBuffer(sb, &psb);
|
|
|
|
// must be at end to initiate thread management.
|
|
sb->s->playing = 1;
|
|
}
|
|
}
|
|
|
|
int win_llsSystem::PlayStream(play_information *play_info) {
|
|
short sound_slot;
|
|
DWORD ds_flags = 0;
|
|
|
|
ASSERT(play_info != NULL);
|
|
|
|
float volume = (play_info->left_volume > play_info->right_volume) ? play_info->left_volume : play_info->right_volume;
|
|
|
|
if (!m_f_sound_lib_init)
|
|
return -1;
|
|
|
|
#ifdef _DEBUG
|
|
sound_slot = FindFreeSoundSlot(-1, volume, play_info->priority);
|
|
#else
|
|
sound_slot = FindFreeSoundSlot(volume, play_info->priority);
|
|
#endif
|
|
// Out of sound slots
|
|
if (sound_slot < 0) {
|
|
return -1;
|
|
}
|
|
|
|
// mprintf((0, "TS(%d)Playing sound index %d at %d volume,%d pan\n", TotalSoundsPlayed, sound_index, volume, pan));
|
|
|
|
m_total_sounds_played++;
|
|
m_sound_mixer.m_sound_cache[sound_slot].play_info = play_info;
|
|
|
|
m_sound_mixer.m_sound_cache[sound_slot].m_unique_id = MakeUniqueId(sound_slot);
|
|
ASSERT(m_sound_mixer.m_sound_cache[sound_slot].m_unique_id != -1);
|
|
|
|
m_sound_mixer.m_sound_cache[sound_slot].m_buffer_type = SBT_2D;
|
|
|
|
if (m_mixer_type != SOUND_MIXER_SOFTWARE_16) {
|
|
float volume;
|
|
float pan;
|
|
LPDIRECTSOUNDBUFFER sound_ptr;
|
|
|
|
if (play_info->left_volume > play_info->right_volume) {
|
|
volume = play_info->left_volume;
|
|
pan = -1.0f + (play_info->right_volume / play_info->left_volume);
|
|
} else {
|
|
volume = play_info->right_volume;
|
|
pan = 1.0f - (play_info->left_volume / play_info->right_volume);
|
|
}
|
|
|
|
DSStartStreaming(&m_sound_mixer.m_sound_cache[sound_slot], volume, pan);
|
|
sound_ptr = m_sound_mixer.m_sound_cache[sound_slot].m_sound_buffer;
|
|
if (sound_ptr == NULL) {
|
|
m_sound_mixer.m_sound_cache[sound_slot].m_sound_buffer = NULL;
|
|
return -1;
|
|
}
|
|
} else {
|
|
m_sound_mixer.m_sound_cache[sound_slot].m_status = SSF_PLAY_STREAMING;
|
|
}
|
|
|
|
m_sound_mixer.m_cur_sounds_played++;
|
|
|
|
return (m_sound_mixer.m_sound_cache[sound_slot].m_unique_id);
|
|
}
|
|
|
|
// Checks a Unique Sound ID and determines if that sound is still playing
|
|
bool win_llsSystem::IsSoundInstancePlaying(int sound_uid) {
|
|
int current_slot;
|
|
|
|
if (!m_f_sound_lib_init)
|
|
return false;
|
|
|
|
if ((current_slot = ValidateUniqueId(sound_uid)) == -1)
|
|
return false;
|
|
|
|
// mprintf((0, "Checking slot %d of UID %d\n", current_slot, sound_uid));
|
|
|
|
if (m_sound_mixer.m_sound_cache[current_slot].m_status != SSF_UNUSED) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// Is this sound placing on any "channel"
|
|
int win_llsSystem::IsSoundPlaying(int sound_index) {
|
|
int current_slot;
|
|
|
|
if (!m_f_sound_lib_init)
|
|
return -1;
|
|
|
|
for (current_slot = 0; current_slot < m_sound_mixer.m_max_sounds_played; current_slot++) {
|
|
if ((m_sound_mixer.m_sound_cache[current_slot].m_status != SSF_UNUSED) &&
|
|
(m_sound_mixer.m_sound_cache[current_slot].m_sound_index == sound_index)) {
|
|
return m_sound_mixer.m_sound_cache[current_slot].m_unique_id;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
// This function limits the number of sounds cached to 255(8bits) and 256 bit is for invalid channel
|
|
// The purpose is to create unique signatures for each sound played (and allow for
|
|
// the slot_number to be quickly determined)
|
|
inline int win_llsSystem::MakeUniqueId(int sound_slot) { return ((((int)m_total_sounds_played) << 8) + sound_slot); }
|
|
|
|
inline int win_llsSystem::ValidateUniqueId(int sound_uid) {
|
|
if (sound_uid == m_sound_mixer.m_sound_cache[sound_uid & 0x00FF].m_unique_id) {
|
|
return sound_uid & 0x00FF;
|
|
} else {
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
void win_llsSystem::PauseSounds() {
|
|
int current_slot;
|
|
|
|
if (m_mixer_type != SOUND_MIXER_SOFTWARE_16) {
|
|
|
|
for (current_slot = 0; current_slot < m_sound_mixer.m_max_sounds_played; current_slot++) {
|
|
sound_buffer_info *sb = &m_sound_mixer.m_sound_cache[current_slot];
|
|
update_directsound_sb(sb);
|
|
|
|
/* if((sb->m_status != SSF_UNUSED) &&
|
|
((sb->m_status & SSF_PAUSED) == 0))
|
|
{
|
|
int status = sb_get_status(sb);
|
|
|
|
if(!(status & SB_STATUS_PLAYING)) {
|
|
ll_sound_ptr->StopSound(sb->m_unique_id);
|
|
}
|
|
else if (status & SB_STATUS_INVALID) {
|
|
ll_sound_ptr->StopSound(sb->m_unique_id);
|
|
}
|
|
}
|
|
*/
|
|
}
|
|
}
|
|
|
|
for (current_slot = 0; current_slot < m_sound_mixer.m_max_sounds_played; current_slot++) {
|
|
sound_buffer_info *sb = &m_sound_mixer.m_sound_cache[current_slot];
|
|
if (sb->m_status != SSF_UNUSED && !(sb->m_status & SSF_PAUSED)) {
|
|
sb->m_status |= SSF_PAUSED;
|
|
if (m_mixer_type != SOUND_MIXER_SOFTWARE_16 && (sb->m_sound_buffer)) {
|
|
sb_stop_buffer(sb);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void win_llsSystem::ResumeSounds() {
|
|
int current_slot;
|
|
|
|
for (current_slot = 0; current_slot < m_sound_mixer.m_max_sounds_played; current_slot++) {
|
|
sound_buffer_info *sb = &m_sound_mixer.m_sound_cache[current_slot];
|
|
|
|
if (sb->m_status != SSF_UNUSED && (sb->m_status & SSF_PAUSED)) {
|
|
if (m_mixer_type != SOUND_MIXER_SOFTWARE_16) {
|
|
PlaySoundBuffer(sb, NULL);
|
|
}
|
|
|
|
m_sound_mixer.m_sound_cache[current_slot].m_status &= (~SSF_PAUSED);
|
|
}
|
|
}
|
|
}
|
|
|
|
void win_llsSystem::PauseSound(int sound_uid) {
|
|
int current_slot;
|
|
|
|
if (m_mixer_type != SOUND_MIXER_SOFTWARE_16) {
|
|
|
|
for (current_slot = 0; current_slot < m_sound_mixer.m_max_sounds_played; current_slot++) {
|
|
sound_buffer_info *sb = &m_sound_mixer.m_sound_cache[current_slot];
|
|
|
|
if (sb->m_unique_id == sound_uid) {
|
|
update_directsound_sb(sb);
|
|
|
|
/* if((sb->m_status != SSF_UNUSED) && ((sb->m_status & SSF_PAUSED) == 0))
|
|
{
|
|
int status = sb_get_status(sb);
|
|
|
|
if(!(status & SB_STATUS_PLAYING)) {
|
|
ll_sound_ptr->StopSound(sb->m_unique_id);
|
|
}
|
|
else if (status & SB_STATUS_INVALID) {
|
|
ll_sound_ptr->StopSound(sb->m_unique_id);
|
|
}
|
|
}
|
|
*/
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
for (current_slot = 0; current_slot < m_sound_mixer.m_max_sounds_played; current_slot++) {
|
|
sound_buffer_info *sb = &m_sound_mixer.m_sound_cache[current_slot];
|
|
if (sb->m_unique_id == sound_uid) {
|
|
if (sb->m_status != SSF_UNUSED && !(sb->m_status & SSF_PAUSED)) {
|
|
sb->m_status |= SSF_PAUSED;
|
|
if (m_mixer_type != SOUND_MIXER_SOFTWARE_16 && (sb->m_sound_buffer)) {
|
|
sb_stop_buffer(sb);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void win_llsSystem::ResumeSound(int sound_uid) {
|
|
int current_slot;
|
|
|
|
for (current_slot = 0; current_slot < m_sound_mixer.m_max_sounds_played; current_slot++) {
|
|
if (sound_uid == m_sound_mixer.m_sound_cache[current_slot].m_unique_id) {
|
|
if (m_sound_mixer.m_sound_cache[current_slot].m_status != SSF_UNUSED &&
|
|
(m_sound_mixer.m_sound_cache[current_slot].m_status & SSF_PAUSED)) {
|
|
if (m_mixer_type != SOUND_MIXER_SOFTWARE_16) {
|
|
PlaySoundBuffer(&m_sound_mixer.m_sound_cache[current_slot], NULL);
|
|
}
|
|
|
|
m_sound_mixer.m_sound_cache[current_slot].m_status &= (~SSF_PAUSED);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void win_llsSystem::StopAllSounds() {
|
|
int current_slot;
|
|
|
|
for (current_slot = 0; current_slot < m_sound_mixer.m_max_sounds_played; current_slot++) {
|
|
if (m_sound_mixer.m_sound_cache[current_slot].m_status != SSF_UNUSED) {
|
|
StopSound(m_sound_mixer.m_sound_cache[current_slot].m_unique_id);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Begin sound frame
|
|
void win_llsSystem::SoundStartFrame(void) {
|
|
float frame_time;
|
|
int current_slot;
|
|
int i;
|
|
|
|
if (m_timer_last_frametime == -1) {
|
|
frame_time = 0.0f;
|
|
} else {
|
|
frame_time = (timer_GetMSTime() - m_timer_last_frametime) / 1000.0f;
|
|
}
|
|
m_timer_last_frametime = timer_GetMSTime();
|
|
|
|
// perform necessary functions if sound events are pending for frame, this doesn't have to do anything
|
|
// if the mixer doesn't require such actions. Aureal does though.
|
|
if (m_pending_actions) {
|
|
mprintf((0, "pending actions\n"));
|
|
#ifdef SUPPORT_AUREAL
|
|
if (m_mixer_type == SOUND_MIXER_AUREAL) {
|
|
A3D_Flush();
|
|
}
|
|
#endif
|
|
}
|
|
|
|
// start mixer dependant frame
|
|
#ifdef SUPPORT_AUREAL
|
|
if (m_mixer_type == SOUND_MIXER_AUREAL) {
|
|
A3D_StartFrame();
|
|
}
|
|
#endif
|
|
|
|
m_in_sound_frame = true;
|
|
m_pending_actions = false;
|
|
|
|
// cleanup sound cache.
|
|
// mprintf((0, "StartCleanup\n"));
|
|
if (m_mixer_type != SOUND_MIXER_SOFTWARE_16) {
|
|
for (i = 0; i < m_sound_mixer.m_max_sounds_played; i++) {
|
|
sound_buffer_info *sb = &m_sound_mixer.m_sound_cache[i];
|
|
update_directsound_sb(sb, true);
|
|
}
|
|
}
|
|
// mprintf((0, "EndCleanup\n"));
|
|
|
|
int counter = 0, loop_counter = 0, stream_counter = 0, buf_loop_counter = 0;
|
|
|
|
#ifdef _DEBUG
|
|
int n_p5 = 0, n_p4 = 0, n_p3 = 0, n_p2 = 0, n_p1 = 0, n_p0 = 0;
|
|
#endif
|
|
|
|
for (current_slot = 0; current_slot < m_sound_mixer.m_max_sounds_played; current_slot++) {
|
|
sound_buffer_info *sb = &m_sound_mixer.m_sound_cache[current_slot];
|
|
if (sb->m_status != SSF_UNUSED) {
|
|
counter++;
|
|
if (sb->m_status & SSF_PLAY_LOOPING) {
|
|
if (sb->m_status & SSF_BUFFERED_LOOP)
|
|
buf_loop_counter++;
|
|
loop_counter++;
|
|
}
|
|
if (sb->m_status & SSF_PLAY_STREAMING)
|
|
stream_counter++;
|
|
|
|
#ifdef _DEBUG
|
|
if (sb->play_info->priority == SND_PRIORITY_CRITICAL)
|
|
n_p5++;
|
|
else if (sb->play_info->priority == SND_PRIORITY_HIGHEST)
|
|
n_p4++;
|
|
else if (sb->play_info->priority == SND_PRIORITY_HIGH)
|
|
n_p3++;
|
|
else if (sb->play_info->priority == SND_PRIORITY_NORMAL)
|
|
n_p2++;
|
|
else if (sb->play_info->priority == SND_PRIORITY_LOW)
|
|
n_p1++;
|
|
else if (sb->play_info->priority == SND_PRIORITY_LOWEST)
|
|
n_p0++;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
// update cache stress timer.
|
|
if (counter < (m_sound_mixer.m_max_sounds_played * 3 / 4)) {
|
|
m_cache_stress_timer += frame_time;
|
|
} else {
|
|
m_cache_stress_timer = 0.0f;
|
|
}
|
|
|
|
#ifdef _DEBUG
|
|
mprintf_at((3, 2, 0, "LNS: %02d/%02d", counter, m_sound_mixer.m_max_sounds_played));
|
|
mprintf_at((3, 3, 1, "Lp: %02d", loop_counter));
|
|
mprintf_at((3, 4, 1, "St: %02d", stream_counter));
|
|
mprintf_at((3, 5, 0, " Ot: %02d", counter - loop_counter - stream_counter));
|
|
|
|
if (m_sound_mixer.m_loop_method != DSLOOP_STREAM_METHOD && m_mixer_type != SOUND_MIXER_SOFTWARE_16) {
|
|
mprintf_at((3, 3, 10, "Bf: %02d", buf_loop_counter));
|
|
}
|
|
|
|
mprintf_at((3, 2, 20, "P5:%02d P4:%02d P3:%02d", n_p5, n_p4, n_p3));
|
|
mprintf_at((3, 3, 20, "P2:%02d P1:%02d P0:%02d", n_p2, n_p1, n_p0));
|
|
#endif
|
|
}
|
|
|
|
// End sound frame
|
|
void win_llsSystem::SoundEndFrame(void) {
|
|
#ifdef SUPPORT_AUREAL
|
|
if (m_mixer_type == SOUND_MIXER_AUREAL) {
|
|
A3D_EndFrame();
|
|
}
|
|
#endif
|
|
|
|
CheckForErrors(); // handles errors.
|
|
|
|
m_in_sound_frame = false;
|
|
}
|
|
|
|
bool win_llsSystem::LockSound(int sound_uid) { return false; }
|
|
|
|
bool win_llsSystem::UnlockSound(int sound_uid) { return false; }
|
|
|
|
// True means it was already loaded, false means that it was not
|
|
bool win_llsSystem::CheckAndForceSoundDataAlloc(int sound_index) {
|
|
int result;
|
|
int sound_file_index = Sounds[sound_index].sample_index;
|
|
|
|
ASSERT(sound_file_index >= 0 && sound_file_index < MAX_SOUND_FILES);
|
|
|
|
if (sound_file_index < 0 || sound_file_index >= MAX_SOUND_FILES) {
|
|
return false;
|
|
}
|
|
|
|
// Check if the sample data is already loaded
|
|
if (SoundFiles[sound_file_index].sample_16bit != NULL || SoundFiles[sound_file_index].sample_8bit != NULL)
|
|
return true;
|
|
|
|
// If not, get the sound data
|
|
result = SoundLoadWaveFile(SoundFiles[sound_file_index].name, Sounds[sound_index].import_volume, sound_file_index,
|
|
(m_sound_quality == SQT_HIGH), true);
|
|
|
|
// Why would it load once (table load time) and not now?
|
|
if (!result)
|
|
return false;
|
|
|
|
mprintf((0, "Sound %s loaded.\n", SoundFiles[sound_file_index].name));
|
|
|
|
return true;
|
|
}
|
|
|
|
bool win_llsSystem::SetSoundQuality(char quality) {
|
|
int i;
|
|
|
|
if (quality == m_sound_quality)
|
|
return true;
|
|
|
|
// pause any sounds that may be playing
|
|
win_llsSystem::PauseSounds();
|
|
|
|
if (quality == SQT_NORMAL) {
|
|
m_sound_quality = SQT_NORMAL;
|
|
} else {
|
|
m_sound_quality = SQT_HIGH;
|
|
}
|
|
|
|
for (i = 0; i < MAX_SOUNDS; i++) {
|
|
if (Sounds[i].used != 0) {
|
|
int j = Sounds[i].sample_index;
|
|
|
|
if (SoundFiles[j].sample_8bit && m_sound_quality == SQT_HIGH) {
|
|
GlobalFree(SoundFiles[j].sample_8bit);
|
|
SoundFiles[j].sample_8bit = NULL;
|
|
|
|
CheckAndForceSoundDataAlloc(i);
|
|
}
|
|
if (SoundFiles[j].sample_16bit && m_sound_quality == SQT_NORMAL) {
|
|
int count;
|
|
|
|
ASSERT(SoundFiles[j].sample_8bit == NULL);
|
|
SoundFiles[j].sample_8bit = (unsigned char *)GlobalAlloc(0, SoundFiles[j].sample_length);
|
|
|
|
// NOTE: Interesting note on sound conversion: 16 bit sounds are signed (0 biase). 8 bit sounds are unsigned
|
|
// (+128 biase).
|
|
for (count = 0; count < (int)SoundFiles[j].sample_length; count++) {
|
|
SoundFiles[j].sample_8bit[count] = (unsigned char)((((int)SoundFiles[j].sample_16bit[count]) + 32767) >> 8);
|
|
}
|
|
|
|
GlobalFree(SoundFiles[j].sample_16bit);
|
|
SoundFiles[j].sample_16bit = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
win_llsSystem::ResumeSounds();
|
|
|
|
return true;
|
|
}
|
|
|
|
char win_llsSystem::GetSoundQuality(void) { return m_sound_quality; }
|
|
|
|
bool win_llsSystem::SetSoundMixer(char mixer_type) {
|
|
if (mixer_type == m_mixer_type)
|
|
return true;
|
|
else {
|
|
// Chris note: This is not the best way to do this. All the currently playing
|
|
// sounds are lost. This shouldn't happen. A real solutions has to take in account
|
|
// for three things: Normal sounds, looping sounds, and streaming audio.
|
|
DestroySoundLib();
|
|
InitSoundLib(mixer_type, SoundApp, m_sound_mixer.m_max_sounds_played);
|
|
SetSoundQuality(m_sound_quality);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
char win_llsSystem::GetSoundMixer(void) { return m_mixer_type; }
|
|
|
|
void win_llsSystem::SetListener(pos_state *cur_pos) {
|
|
if (!m_f_sound_lib_init)
|
|
return;
|
|
|
|
m_emulated_listener.orient = *cur_pos->orient;
|
|
m_emulated_listener.position = *cur_pos->position;
|
|
m_emulated_listener.velocity = *cur_pos->velocity;
|
|
|
|
#ifdef SUPPORT_AUREAL
|
|
if (m_mixer_type == SOUND_MIXER_AUREAL) {
|
|
A3D_SetListenerOrient(&cur_pos->orient->fvec, &cur_pos->orient->uvec);
|
|
A3D_SetListenerPosition(cur_pos->position->x, cur_pos->position->y, cur_pos->position->z);
|
|
A3D_SetListenerVelocity(cur_pos->velocity->x, cur_pos->velocity->y, cur_pos->velocity->z);
|
|
} else
|
|
#endif
|
|
if (IS_3D_MIXER(m_mixer_type)) {
|
|
m_lp_listener->SetOrientation(cur_pos->orient->fvec.x, cur_pos->orient->fvec.y, cur_pos->orient->fvec.z,
|
|
cur_pos->orient->uvec.x, cur_pos->orient->uvec.y, cur_pos->orient->uvec.z,
|
|
DS3D_DEFERRED);
|
|
m_lp_listener->SetPosition(cur_pos->position->x, cur_pos->position->y, cur_pos->position->z, DS3D_DEFERRED);
|
|
m_lp_listener->SetVelocity(cur_pos->velocity->x, cur_pos->velocity->y, cur_pos->velocity->z, DS3D_DEFERRED);
|
|
m_lp_listener->CommitDeferredSettings();
|
|
}
|
|
}
|
|
|
|
// AdjustSound2d -- adjusts the volume, pan, and freq. of a sound
|
|
void win_llsSystem::AdjustSound(int sound_uid, float f_volume, float f_pan, unsigned short frequency) {
|
|
int current_slot;
|
|
|
|
if (!m_f_sound_lib_init)
|
|
return;
|
|
|
|
if ((current_slot = ValidateUniqueId(sound_uid)) == -1)
|
|
return;
|
|
if (m_sound_mixer.m_sound_cache[current_slot].m_status == SSF_UNUSED)
|
|
return;
|
|
|
|
sound_buffer_info *sb = &m_sound_mixer.m_sound_cache[current_slot];
|
|
play_information *play_info = sb->play_info;
|
|
|
|
play_info->left_volume = play_info->right_volume = f_volume;
|
|
if (f_pan < 0.0)
|
|
play_info->right_volume += f_volume * f_pan;
|
|
else
|
|
play_info->left_volume -= f_volume * f_pan;
|
|
|
|
sb_adjust_properties_2d(&m_sound_mixer.m_sound_cache[current_slot], f_volume, f_pan, frequency);
|
|
|
|
return;
|
|
}
|
|
|
|
void win_llsSystem::AdjustSound(int sound_uid, pos_state *cur_pos, float adjusted_volume, float reverb) {
|
|
if (!m_f_sound_lib_init)
|
|
return;
|
|
|
|
LPDIRECTSOUNDBUFFER lp_dsb;
|
|
// LPDIRECTSOUND3DBUFFER lpDSB3D;
|
|
int current_slot;
|
|
|
|
if (!m_f_sound_lib_init)
|
|
return;
|
|
|
|
if ((current_slot = ValidateUniqueId(sound_uid)) == -1)
|
|
return;
|
|
if (m_sound_mixer.m_sound_cache[current_slot].m_status == SSF_UNUSED)
|
|
return;
|
|
|
|
// sound_buffer_info *sb = &m_sound_mixer.m_sound_cache[current_slot];
|
|
|
|
if (IS_3D_MIXER(m_mixer_type)) {
|
|
int sound_index = m_sound_mixer.m_sound_cache[current_slot].m_sound_index;
|
|
lp_dsb = m_sound_mixer.m_sound_cache[current_slot].m_sound_buffer;
|
|
if (lp_dsb == NULL)
|
|
return;
|
|
|
|
sb_adjust_properties_3d(&m_sound_mixer.m_sound_cache[current_slot], adjusted_volume, cur_pos, reverb);
|
|
} else {
|
|
// We need to determine the pan and volume
|
|
float volume;
|
|
|
|
volume = adjusted_volume;
|
|
|
|
float dist;
|
|
vector dir_to_sound = *cur_pos->position - m_emulated_listener.position;
|
|
float pan;
|
|
|
|
dist = vm_NormalizeVector(&dir_to_sound);
|
|
if (dist < .1f) {
|
|
dir_to_sound = m_emulated_listener.orient.fvec;
|
|
}
|
|
|
|
if (dist >= Sounds[m_sound_mixer.m_sound_cache[current_slot].m_sound_index].max_distance) {
|
|
volume = 0.0f;
|
|
} else if (dist > Sounds[m_sound_mixer.m_sound_cache[current_slot].m_sound_index].min_distance) {
|
|
volume *= (1.0 - ((dist - Sounds[m_sound_mixer.m_sound_cache[current_slot].m_sound_index].min_distance) /
|
|
(Sounds[m_sound_mixer.m_sound_cache[current_slot].m_sound_index].max_distance -
|
|
Sounds[m_sound_mixer.m_sound_cache[current_slot].m_sound_index].min_distance)));
|
|
}
|
|
|
|
pan = (dir_to_sound * m_emulated_listener.orient.rvec);
|
|
|
|
if (volume < 0.0f)
|
|
volume = 0.0f;
|
|
else if (volume > 1.0f)
|
|
volume = 1.0f;
|
|
|
|
if (pan < -1.0f)
|
|
pan = -1.0f;
|
|
else if (pan > 1.0f)
|
|
pan = 1.0f;
|
|
|
|
AdjustSound(m_sound_mixer.m_sound_cache[current_slot].m_unique_id, volume, pan, 22050);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
int win_llsSystem::PlaySound3d(play_information *play_info, int sound_index, pos_state *cur_pos, float adjusted_volume,
|
|
bool f_looped, float reverb) {
|
|
short sound_slot;
|
|
DWORD ds_flags = 0;
|
|
float volume;
|
|
|
|
volume = adjusted_volume; // Adjust base volume by sent volume, let 3d stuff do the rest
|
|
|
|
if (!m_f_sound_lib_init)
|
|
return -1;
|
|
|
|
ASSERT(Sounds[sound_index].used != 0);
|
|
if (Sounds[sound_index].used == 0)
|
|
return -1;
|
|
|
|
if (!IS_3D_MIXER(m_mixer_type)) {
|
|
float dist;
|
|
vector dir_to_sound = *cur_pos->position - m_emulated_listener.position;
|
|
float pan;
|
|
|
|
dist = vm_NormalizeVector(&dir_to_sound);
|
|
if (dist < .1f) {
|
|
dir_to_sound = m_emulated_listener.orient.fvec;
|
|
}
|
|
|
|
if (dist >= Sounds[sound_index].max_distance) {
|
|
return -1;
|
|
} else if (dist > Sounds[sound_index].min_distance) {
|
|
volume *= (1.0 - ((dist - Sounds[sound_index].min_distance) /
|
|
(Sounds[sound_index].max_distance - Sounds[sound_index].min_distance)));
|
|
}
|
|
|
|
pan = (dir_to_sound * m_emulated_listener.orient.rvec);
|
|
|
|
if (volume < 0.0f)
|
|
volume = 0.0f;
|
|
else if (volume > 1.0f)
|
|
volume = 1.0f;
|
|
|
|
if (pan < -1.0f)
|
|
pan = -1.0f;
|
|
else if (pan > 1.0f)
|
|
pan = 1.0f;
|
|
|
|
return PlaySound2d(play_info, sound_index, volume, pan, f_looped);
|
|
}
|
|
|
|
// Out of sound slots
|
|
#ifdef _DEBUG
|
|
sound_slot = FindFreeSoundSlot(sound_index, volume, play_info->priority);
|
|
#else
|
|
sound_slot = FindFreeSoundSlot(volume, play_info->priority);
|
|
#endif
|
|
|
|
if (sound_slot < 0) {
|
|
return -1;
|
|
}
|
|
|
|
m_sound_mixer.m_sound_cache[sound_slot].play_info = play_info;
|
|
m_total_sounds_played++;
|
|
m_sound_mixer.m_sound_cache[sound_slot].m_unique_id = MakeUniqueId(sound_slot);
|
|
ASSERT(m_sound_mixer.m_sound_cache[sound_slot].m_unique_id != -1);
|
|
|
|
// 3-D!!
|
|
sound_buffer_info *sb = &m_sound_mixer.m_sound_cache[sound_slot];
|
|
|
|
sb->m_buffer_type = SBT_3D;
|
|
sb->m_sound_index = sound_index;
|
|
|
|
if (f_looped) {
|
|
LoopStartStreaming(sb, SBT_3D, adjusted_volume, 0.0, cur_pos);
|
|
if (sb->m_snd_obj == NULL) {
|
|
sb->m_sound_buffer = NULL;
|
|
Int3();
|
|
return -1;
|
|
}
|
|
} else {
|
|
tPSBInfo psb;
|
|
|
|
if (SoundFiles[Sounds[sound_index].sample_index].use_count > 0) {
|
|
if (DuplicateSoundBuffer(sb)) {
|
|
goto play_sound;
|
|
}
|
|
}
|
|
if (!CreateSoundBuffer(sb, false)) {
|
|
return -1;
|
|
}
|
|
if (!LoadSoundBuffer(sb)) {
|
|
sb_free_buffer(sb);
|
|
return -1;
|
|
}
|
|
|
|
play_sound:
|
|
sb->m_status = SSF_PLAY_NORMAL;
|
|
|
|
psb.cur_pos = cur_pos;
|
|
psb.volume = volume;
|
|
psb.freq = 22050;
|
|
psb.reverb = reverb;
|
|
psb.looping = false;
|
|
if (!PlaySoundBuffer(sb, &psb)) {
|
|
sb_free_buffer(sb);
|
|
return -1;
|
|
}
|
|
|
|
// mprintf((0, "SL Play sound on slot %d, TP = %d UI = %X\n", sound_slot, TotalSoundsPlayed,
|
|
// m_sound_mixer.m_sound_cache[sound_slot].m_unique_id));
|
|
}
|
|
|
|
m_sound_mixer.m_cur_sounds_played++;
|
|
|
|
return (sb->m_unique_id);
|
|
}
|
|
|
|
// These work in samples to make things easier in the long run
|
|
int win_llsSystem::SetSoundPos(int sound_uid, int pos) {
|
|
int current_slot;
|
|
|
|
if (pos <= 0)
|
|
return 1;
|
|
|
|
if (!m_f_sound_lib_init)
|
|
return -1;
|
|
if ((current_slot = ValidateUniqueId(sound_uid)) == -1)
|
|
return -1;
|
|
if (m_sound_mixer.m_sound_cache[current_slot].m_status == SSF_UNUSED)
|
|
return -1;
|
|
|
|
m_sound_mixer.m_sound_cache[current_slot].play_info->m_samples_played = pos;
|
|
|
|
if (m_mixer_type != SOUND_MIXER_SOFTWARE_16) {
|
|
sound_buffer_info *sb = &m_sound_mixer.m_sound_cache[current_slot];
|
|
|
|
if (sb->stereo) {
|
|
pos *= 2;
|
|
}
|
|
|
|
if (sb->bps == 16) {
|
|
pos *= 2;
|
|
}
|
|
|
|
sb_set_current_position(sb, pos);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
// These work in samples to make things easier in the long run
|
|
int win_llsSystem::GetSoundPos(int sound_uid) {
|
|
int current_slot;
|
|
uint temp, pos;
|
|
|
|
if (!m_f_sound_lib_init)
|
|
return -1;
|
|
if ((current_slot = ValidateUniqueId(sound_uid)) == -1)
|
|
return -1;
|
|
if (m_sound_mixer.m_sound_cache[current_slot].m_status == SSF_UNUSED)
|
|
return -1;
|
|
|
|
if (m_mixer_type != SOUND_MIXER_SOFTWARE_16) {
|
|
sound_buffer_info *sb = &m_sound_mixer.m_sound_cache[current_slot];
|
|
|
|
temp = sb_get_current_position(sb, &pos);
|
|
|
|
if (sb->stereo) {
|
|
pos /= 2;
|
|
}
|
|
if (sb->bps == 16) {
|
|
pos /= 2;
|
|
}
|
|
|
|
// Updates the readable data
|
|
m_sound_mixer.m_sound_cache[current_slot].play_info->m_samples_played = pos;
|
|
|
|
return pos;
|
|
} else {
|
|
return m_sound_mixer.m_sound_cache[current_slot].play_info->m_samples_played;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
bool win_llsSystem::CreateSoundBuffer(sound_buffer_info *sb, bool f_is_stereo, int size, bool dynamic) {
|
|
// do buffer creation
|
|
int buftype = sb->m_buffer_type;
|
|
bool f_sample_16bit;
|
|
int sound_length;
|
|
|
|
get_sound_info(sb, &sound_length, &f_sample_16bit);
|
|
|
|
if (size != -1) {
|
|
sound_length = size;
|
|
}
|
|
|
|
switch (m_mixer_type) {
|
|
case SOUND_MIXER_SOFTWARE_16:
|
|
Int3();
|
|
break;
|
|
|
|
#ifdef SUPPORT_AUREAL
|
|
case SOUND_MIXER_AUREAL:
|
|
sb->m_snd_obj = A3D_CreateSSource(sound_length, f_sample_16bit ? 16 : 8, f_is_stereo, (dynamic) ? true : false,
|
|
22050, (buftype == SBT_3D) ? true : false);
|
|
if (!sb->m_snd_obj) {
|
|
Int3();
|
|
sb->m_status = SSF_UNUSED;
|
|
return false;
|
|
}
|
|
break;
|
|
#endif
|
|
default:
|
|
CreateDSBuffer(buftype, &sb->m_sound_buffer, &sb->m_sound_buffer_3d, sound_length, 22050, f_is_stereo,
|
|
f_sample_16bit);
|
|
|
|
sb->m_lpksps = NULL;
|
|
if (m_mixer_type == SOUND_MIXER_CREATIVE_EAX) {
|
|
EAX_InitSource(sb->m_sound_buffer_3d, &sb->m_lpksps);
|
|
}
|
|
|
|
if (!sb->m_sound_buffer) {
|
|
Int3();
|
|
sb->m_status = SSF_UNUSED;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
sb->m_mixer_type = m_mixer_type;
|
|
sb->bps = f_sample_16bit ? 16 : 8;
|
|
sb->stereo = f_is_stereo;
|
|
|
|
if (sb->m_sound_index > -1) {
|
|
SoundFiles[Sounds[sb->m_sound_index].sample_index].use_count++;
|
|
// Global_DS_alloced_sounds++;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool win_llsSystem::LoadSoundBuffer(sound_buffer_info *sb) {
|
|
// play 2d sound
|
|
int buftype = sb->m_buffer_type;
|
|
bool f_sample_16bit;
|
|
char *sample_ptr;
|
|
int sound_length;
|
|
|
|
// get pointer
|
|
sample_ptr = get_sound_info(sb, &sound_length, &f_sample_16bit);
|
|
sb->sample_data = sample_ptr;
|
|
sb->sample_length = (int)sound_length;
|
|
|
|
// do buffer creation
|
|
switch (m_mixer_type) {
|
|
case SOUND_MIXER_SOFTWARE_16:
|
|
Int3();
|
|
break;
|
|
#ifdef SUPPORT_AUREAL
|
|
case SOUND_MIXER_AUREAL:
|
|
if (!A3D_LoadSample(sb->m_snd_obj, sample_ptr, sound_length)) {
|
|
Int3();
|
|
sb->m_status = SSF_UNUSED;
|
|
return false;
|
|
}
|
|
break;
|
|
#endif
|
|
default:
|
|
if (LoadSoundData(sb->m_sound_buffer, sample_ptr, sound_length) != DS_OK) {
|
|
Int3();
|
|
sb->m_status = SSF_UNUSED;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool win_llsSystem::PlaySoundBuffer(sound_buffer_info *sb, tPSBInfo *psb) {
|
|
bool f_looping;
|
|
|
|
if (!m_f_sound_lib_init)
|
|
return false;
|
|
if (!m_in_sound_frame)
|
|
m_pending_actions = true;
|
|
|
|
TryPlayAgainLabel:
|
|
if (psb) {
|
|
if (sb->m_buffer_type == SBT_2D) {
|
|
AdjustSound(sb->m_unique_id, psb->volume, psb->pan, psb->freq);
|
|
} else if (sb->m_buffer_type == SBT_3D) {
|
|
AdjustSound(sb->m_unique_id, psb->cur_pos, psb->volume, psb->reverb);
|
|
}
|
|
|
|
SetSoundPos(sb->m_unique_id, sb->play_info->m_samples_played);
|
|
|
|
f_looping = psb->looping;
|
|
} else {
|
|
f_looping = ((sb->m_status & SSF_PLAY_LOOPING) || sb->s) ? true : false;
|
|
if (f_looping && m_sound_mixer.m_loop_method == DSLOOP_BUFFER_METHOD && sb->s->loop_step != 0 &&
|
|
(sb->m_status & SSF_BUFFERED_LOOP)) {
|
|
f_looping = false;
|
|
}
|
|
}
|
|
|
|
switch (m_mixer_type) {
|
|
#ifdef SUPPORT_AUREAL
|
|
case SOUND_MIXER_AUREAL: {
|
|
float priority;
|
|
switch (sb->play_info->priority) {
|
|
case SND_PRIORITY_CRITICAL:
|
|
case SND_PRIORITY_HIGHEST:
|
|
priority = 1.0f;
|
|
break;
|
|
case SND_PRIORITY_HIGH:
|
|
priority = 0.85f;
|
|
break;
|
|
case SND_PRIORITY_NORMAL:
|
|
priority = 0.60f;
|
|
break;
|
|
case SND_PRIORITY_LOW:
|
|
priority = 0.30f;
|
|
break;
|
|
case SND_PRIORITY_LOWEST:
|
|
priority = 0.1f;
|
|
break;
|
|
default:
|
|
priority = 0.5f;
|
|
}
|
|
A3D_SetSourcePriority(sb->m_snd_obj, priority);
|
|
A3D_Play(sb->m_snd_obj, f_looping);
|
|
} break;
|
|
#endif
|
|
|
|
case SOUND_MIXER_SOFTWARE_16:
|
|
Int3();
|
|
break;
|
|
|
|
default: {
|
|
LPDIRECTSOUNDBUFFER sound_ptr = sb->m_sound_buffer;
|
|
DWORD ds_flags = f_looping ? DSBPLAY_LOOPING : 0;
|
|
|
|
ASSERT(sound_ptr);
|
|
|
|
if (sound_ptr->Play(0, 0, ds_flags) == DSERR_BUFFERLOST) {
|
|
if (LoadSoundData(sound_ptr, sb->sample_data, sb->sample_length) == DS_OK) {
|
|
goto TryPlayAgainLabel;
|
|
}
|
|
|
|
sb->m_status = SSF_UNUSED;
|
|
|
|
// Some type of error -- we cannot play the sound? -- get chris
|
|
Int3();
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool win_llsSystem::DuplicateSoundBuffer(sound_buffer_info *sb) {
|
|
return false; // for now, let's not do this.
|
|
|
|
/*
|
|
sound_buffer_info *source_sb = m_sound_mixer.FindSoundBuffer(sb->m_sound_index);
|
|
|
|
ASSERT(m_mixer_type != SOUND_MIXER_SOFTWARE_16);
|
|
|
|
if (!source_sb) {
|
|
Int3();
|
|
return false;
|
|
}
|
|
|
|
// we have a source sound buffer. let's use it.
|
|
if (m_mixer_type == SOUND_MIXER_AUREAL) {
|
|
sb->m_snd_obj = A3D_DuplicateSource(source_sb->m_snd_obj);
|
|
if (!sb->m_snd_obj) {
|
|
return false;
|
|
}
|
|
}
|
|
else {
|
|
HRESULT hr;
|
|
hr = m_lp_ds->DuplicateSoundBuffer(source_sb->m_sound_buffer, &sb->m_sound_buffer);
|
|
if (FAILED(hr)) {
|
|
mprintf((0, "DDSNDLIB: Failed to duplicate sound buffer (%x)\n", hr));
|
|
return false;
|
|
}
|
|
|
|
if(IS_3D_MIXER(m_mixer_type)) {
|
|
// a 3d buffer needs a 3d interface pointer
|
|
if(sb->m_buffer_type == SBT_3D)
|
|
{
|
|
hr = sb->m_sound_buffer->QueryInterface(IID_IDirectSound3DBuffer, (void
|
|
**)&sb->m_sound_buffer_3d); if (FAILED(hr)) { mprintf((0, "DDSNDLIB: Failed to acquire 3d interface from duplicate
|
|
buffer (%x)\n", hr)); return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
sb->m_mixer_type = source_sb->m_mixer_type;
|
|
sb->bps = source_sb->bps;
|
|
sb->stereo = source_sb->stereo;
|
|
sb->sample_data = source_sb->sample_data;
|
|
sb->sample_length = source_sb->sample_length;
|
|
|
|
// mprintf((0, "Duplicated!!\n"));
|
|
SoundFiles[Sounds[sb->m_sound_index].sample_index].use_count++;
|
|
|
|
return true;
|
|
*/
|
|
}
|
|
|
|
// environmental sound interface
|
|
// volume modifier (0-1), damping(0-1), 1 = complete, 0 = none
|
|
// decay 0.1 to 100 seconds, how long it takes for a sound to die.
|
|
bool win_llsSystem::SetGlobalReverbProperties(float volume, float damping, float decay) {
|
|
#ifdef SUPPORT_AUREAL
|
|
if (m_mixer_type == SOUND_MIXER_AUREAL) {
|
|
return A3D_SetEnvironmentalReverb(volume, damping, decay);
|
|
} else
|
|
#endif
|
|
if (m_mixer_type == SOUND_MIXER_CREATIVE_EAX) {
|
|
return EAX_SetEnvironmentalReverb(volume, damping, decay);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
sound_buffer_info *sound_buffer_cache::FindSoundBuffer(int sound_index) {
|
|
int i;
|
|
|
|
// is there's no use count for this soudn, then there should be no available buffer.
|
|
if (SoundFiles[Sounds[sound_index].sample_index].use_count == 0) {
|
|
return NULL;
|
|
}
|
|
|
|
// returns a sound buffer with the 'sound_index' if it is still active.
|
|
// we can use the sound buffer to create duplicates.
|
|
for (i = 0; i < m_max_sounds_played; i++) {
|
|
sound_buffer_info *sb = &m_sound_cache[i];
|
|
|
|
if (sb->m_status != SSF_UNUSED) {
|
|
if (sb->m_sound_index == sound_index) {
|
|
return sb;
|
|
}
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
// set special parameters for the 3d environment.
|
|
// of strcuture passed, you must set the appropriate 'flags' value for values you wish to modify
|
|
void win_llsSystem::SetEnvironmentValues(const t3dEnvironmentValues *env) {
|
|
if (CHECK_FLAG(env->flags, ENV3DVALF_DOPPLER)) {
|
|
Env3dValues.doppler_scalar = env->doppler_scalar;
|
|
|
|
#ifdef SUPPORT_AUREAL
|
|
switch (m_mixer_type) {
|
|
case SOUND_MIXER_AUREAL:
|
|
A3D_SetDopplerFactor(Env3dToggles.doppler ? Env3dValues.doppler_scalar : 0.0f);
|
|
break;
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
// get special parameters for the 3d environment.
|
|
// of strcuture passed, you must set the appropriate 'flags' value for values you wish to modify
|
|
void win_llsSystem::GetEnvironmentValues(t3dEnvironmentValues *env) {
|
|
if (CHECK_FLAG(env->flags, ENV3DVALF_DOPPLER)) {
|
|
env->doppler_scalar = Env3dValues.doppler_scalar;
|
|
}
|
|
}
|
|
|
|
// enable special parameters for the 3d environment.
|
|
// of strcuture passed, you must set the appropriate 'flags' value for values you wish to modify
|
|
void win_llsSystem::SetEnvironmentToggles(const t3dEnvironmentToggles *env) {
|
|
t3dEnvironmentValues values;
|
|
|
|
if (CHECK_FLAG(env->flags, ENV3DVALF_DOPPLER)) {
|
|
// set toggle then set doppler again.
|
|
Env3dToggles.doppler = env->doppler;
|
|
values.flags = ENV3DVALF_DOPPLER;
|
|
values.doppler_scalar = Env3dValues.doppler_scalar;
|
|
SetEnvironmentValues(&Env3dValues);
|
|
}
|
|
if (CHECK_FLAG(env->flags, ENV3DVALF_GEOMETRY)) {
|
|
// initialize geometry object if available and true.
|
|
if (m_geometry) {
|
|
delete m_geometry;
|
|
}
|
|
m_geometry = NULL;
|
|
if (env->geometry) {
|
|
if (m_mixer_type == SOUND_MIXER_AUREAL) {
|
|
m_geometry = new llsGeometry;
|
|
if (!m_geometry->Init(this)) {
|
|
delete m_geometry;
|
|
m_geometry = NULL;
|
|
}
|
|
}
|
|
}
|
|
Env3dToggles.geometry = m_geometry ? true : false;
|
|
}
|
|
}
|
|
|
|
// get states of special parameters for the 3d environment.
|
|
// of strcuture passed, you must set the appropriate 'flags' value for values you wish to modify
|
|
void win_llsSystem::GetEnvironmentToggles(t3dEnvironmentToggles *env) {
|
|
if (CHECK_FLAG(env->flags, ENV3DVALF_DOPPLER)) {
|
|
env->doppler = Env3dToggles.doppler;
|
|
}
|
|
|
|
env->supported = 0;
|
|
|
|
switch (m_mixer_type) {
|
|
case SOUND_MIXER_AUREAL:
|
|
env->supported |= ENV3DVALF_DOPPLER;
|
|
env->supported |= ENV3DVALF_GEOMETRY;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Sound System Error Handler.
|
|
void win_llsSystem::CheckForErrors() {
|
|
// if a fatal error occurred, quit and display an error
|
|
// non fatal errors should be put inside a logfile, or just mprinted out.
|
|
switch (m_lib_error_code) {
|
|
case SSL_ERROR_SAMPLE_NODATA:
|
|
Error("%s\nSample had no data.", m_error_text);
|
|
break;
|
|
|
|
case SSL_ERROR_STREAMMIXER:
|
|
Error("%s\nMixer alignment check failed.", m_error_text);
|
|
break;
|
|
|
|
case SSL_ERROR_GENERIC:
|
|
Error("%s\nGeneric error.", m_error_text);
|
|
break;
|
|
}
|
|
|
|
// must call!
|
|
llsSystem::CheckForErrors();
|
|
|
|
// add our default error string.
|
|
char buf[8];
|
|
sprintf(buf, "mix:%d\n", m_mixer_type);
|
|
strcat(m_error_text, buf);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
// set auxillary 3d sound properties
|
|
bool win_llsSystem::SoundPropertySupport() const {
|
|
switch (m_mixer_type) {
|
|
case SOUND_MIXER_CREATIVE_EAX:
|
|
if (EAX_Caps() & EAXF_SOURCE_OBSTRUCTION) {
|
|
return true;
|
|
}
|
|
break;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// sound obstruction from 0 to 1.0 (1.0 = fully obstructed)
|
|
void win_llsSystem::SetSoundProperties(int sound_uid, float obstruction) {
|
|
sound_buffer_info *sb;
|
|
int current_slot;
|
|
|
|
if (!m_f_sound_lib_init)
|
|
return;
|
|
|
|
if ((current_slot = ValidateUniqueId(sound_uid)) == -1)
|
|
return;
|
|
|
|
sb = &m_sound_mixer.m_sound_cache[current_slot];
|
|
|
|
switch (m_mixer_type) {
|
|
case SOUND_MIXER_CREATIVE_EAX:
|
|
EAX_SetSourceProperties(sb->m_lpksps, obstruction);
|
|
break;
|
|
}
|
|
}
|