/* Patrick 5/6/97 -------------------------------------------------------------
  AvP platform specific sound management source
  ----------------------------------------------------------------------------*/

#ifdef DAVEW
	#define DB_LEVEL 4
#else
	#define DB_LEVEL 3
#endif

#include "3dc.h"
#include "inline.h"


#include "module.h"
#include "stratdef.h"
#include "gamedef.h"
#include "dynamics.h"

#include "psndplat.h"
#define UseLocalAssert Yes
#include "ourasert.h"
#include "db.h"
#include "dsound.h"
#include "eax.h"
#include "vmanpset.h"
#include <windows.h>
#include "ffstdio.h"
/* Davew 27/7/98 --------------------------------------------------------------
	Internal types.
	--------------------------------------------------------------------------*/
/* Defines for the flags. */
#define SOUND_DEFAULT		0x00000000
#define SOUND_VOICE_MGER	0x00000001
#define SOUND_EAX			0x00000002
#define SOUND_3DHW			0x00000004
#define SOUND_USE_3DHW		0x00000008

struct SoundConfigTag
{
	unsigned int flags;
	BOOL	reverb_changed;
	float	reverb_mix;
	unsigned int env_index;
};

#ifndef IUnknown_AddRef
	#define IUnknown_AddRef(This) (This)->lpVtbl -> AddRef(This)
#endif
#ifndef IUnknown_Release
	#define IUnknown_Release(This) (This)->lpVtbl -> Release(This)
#endif
#define GET_REF_COUNT(x) (x ? IUnknown_AddRef(x), IUnknown_Release(x) : -1)
#define LOG_RC() db_logf4(("DSO %i, DSPB %i, DS3DL %i, PS %i", GET_REF_COUNT(DSObject), GET_REF_COUNT(DSPrimaryBuffer), GET_REF_COUNT(DS3DListener), GET_REF_COUNT(PropSetP)));

#ifndef DSBCAPS_CTRLDEFAULT
	#define DSBCAPS_CTRLDEFAULT (DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLPAN | DSBCAPS_CTRLFREQUENCY)
#endif

/* Patrick 5/6/97 -------------------------------------------------------------
  Sound system globals
  ----------------------------------------------------------------------------*/
SOUNDSAMPLEDATA GameSounds[SID_MAXIMUM];		   
ACTIVESOUNDSAMPLE ActiveSounds[SOUND_MAXACTIVE];
SOUNDSAMPLEDATA BlankGameSound = {0,0,0,0,NULL,0,NULL};
ACTIVESOUNDSAMPLE BlankActiveSound = {SID_NOSOUND,ASP_Minimum,0,0,NULL,0,0,0,0,0,{{0,0,0},0,0},NULL, NULL, NULL};

/* Patrick 5/6/97 -------------------------------------------------------------
  Direct sound globals
  ----------------------------------------------------------------------------*/
LPDIRECTSOUND			DSObject = NULL; 
LPDIRECTSOUNDBUFFER		DSPrimaryBuffer = NULL;
LPDIRECTSOUND3DLISTENER	DS3DListener = NULL;
LPKSPROPERTYSET 		PropSetP = NULL;
int 					SoundMinBufferFree;

/* Patrick 5/6/97 -------------------------------------------------------------
  Internal global variables
  ----------------------------------------------------------------------------*/
struct SoundConfigTag SoundConfig;
static signed int vol_to_atten_table[] = 
{
	-10000, -9922, -8502, -7672, -7083, -6626, -6252, -5936,
	-5663, -5422, -5206, -5011, -4832, -4669, -4517, -4375,
	-4243, -4119, -4002, -3891, -3786, -3686, -3591, -3500,
	-3413, -3329, -3249, -3172, -3097, -3025, -2956, -2889,
	-2824, -2761, -2700, -2640, -2582, -2526, -2472, -2419,
	-2367, -2316, -2267, -2219, -2171, -2125, -2080, -2036,
	-1993, -1951, -1910, -1869, -1829, -1790, -1752, -1714,
	-1678, -1641, -1606, -1571, -1536, -1502, -1469, -1436,
	-1404, -1372, -1341, -1310, -1280, -1250, -1221, -1191,
	-1163, -1135, -1107, -1079, -1052, -1025, -999, -973,
	-947, -922, -896, -872, -847, -823, -799, -775,
	-752, -729, -706, -683, -661, -639, -617, -595,
	-574, -552, -531, -511, -490, -470, -449, -429,
	-410, -390, -371, -351, -332, -314, -295, -276,
	-258, -240, -222, -204, -186, -168, -151, -134,
	-117, -100, -83, -66, -49, -33, -17, 0,
};


// this table plots the frequency change for
// 128/ths of a semitone for one octave (0-1535),
// divide or multiply by 2 to subtract or add an octave

static float pitch_to_frequency_mult_table [] = 
{
	1.0F,	1.00045137F,	1.000902943F,	1.00135472F,	1.001806701F,	1.002258886F,	1.002711275F,	1.003163868F,
	1.003616666F,	1.004069668F,	1.004522874F,	1.004976285F,	1.005429901F,	1.005883722F,	1.006337747F,	1.006791977F,
	1.007246412F,	1.007701053F,	1.008155898F,	1.008610949F,	1.009066205F,	1.009521667F,	1.009977334F,	1.010433207F,
	1.010889286F,	1.011345571F,	1.011802061F,	1.012258758F,	1.012715661F,	1.01317277F,	1.013630085F,	1.014087607F,
	1.014545335F,	1.01500327F,	1.015461411F,	1.01591976F,	1.016378315F,	1.016837077F,	1.017296046F,	1.017755223F,
	1.018214607F,	1.018674198F,	1.019133996F,	1.019594002F,	1.020054216F,	1.020514637F,	1.020975266F,	1.021436104F,
	1.021897149F,	1.022358402F,	1.022819863F,	1.023281533F,	1.023743411F,	1.024205498F,	1.024667793F,	1.025130297F,
	1.025593009F,	1.026055931F,	1.026519061F,	1.026982401F,	1.027445949F,	1.027909707F,	1.028373674F,	1.028837851F,
	1.029302237F,	1.029766832F,	1.030231638F,	1.030696653F,	1.031161878F,	1.031627313F,	1.032092958F,	1.032558813F,
	1.033024879F,	1.033491155F,	1.033957641F,	1.034424338F,	1.034891246F,	1.035358364F,	1.035825694F,	1.036293234F,
	1.036760985F,	1.037228947F,	1.037697121F,	1.038165506F,	1.038634102F,	1.03910291F,	1.039571929F,	1.04004116F,
	1.040510603F,	1.040980258F,	1.041450125F,	1.041920204F,	1.042390495F,	1.042860998F,	1.043331714F,	1.043802642F,
	1.044273782F,	1.044745136F,	1.045216702F,	1.045688481F,	1.046160473F,	1.046632678F,	1.047105096F,	1.047577727F,
	1.048050572F,	1.04852363F,	1.048996902F,	1.049470387F,	1.049944086F,	1.050417999F,	1.050892125F,	1.051366466F,
	1.051841021F,	1.05231579F,	1.052790773F,	1.053265971F,	1.053741383F,	1.05421701F,	1.054692851F,	1.055168907F,
	1.055645178F,	1.056121664F,	1.056598366F,	1.057075282F,	1.057552413F,	1.05802976F,	1.058507323F,	1.058985101F,
	1.059463094F,	1.059941304F,	1.060419729F,	1.06089837F,	1.061377227F,	1.061856301F,	1.06233559F,	1.062815096F,
	1.063294818F,	1.063774757F,	1.064254913F,	1.064735285F,	1.065215874F,	1.06569668F,	1.066177703F,	1.066658943F,
	1.067140401F,	1.067622075F,	1.068103967F,	1.068586077F,	1.069068404F,	1.069550949F,	1.070033712F,	1.070516692F,
	1.070999891F,	1.071483308F,	1.071966943F,	1.072450796F,	1.072934868F,	1.073419158F,	1.073903666F,	1.074388394F,
	1.07487334F,	1.075358505F,	1.075843889F,	1.076329492F,	1.076815315F,	1.077301356F,	1.077787617F,	1.078274098F,
	1.078760798F,	1.079247718F,	1.079734857F,	1.080222216F,	1.080709796F,	1.081197595F,	1.081685615F,	1.082173855F,
	1.082662315F,	1.083150996F,	1.083639897F,	1.084129019F,	1.084618362F,	1.085107926F,	1.085597711F,	1.086087716F,
	1.086577943F,	1.087068391F,	1.087559061F,	1.088049952F,	1.088541065F,	1.089032399F,	1.089523955F,	1.090015733F,
	1.090507733F,	1.090999955F,	1.091492399F,	1.091985065F,	1.092477954F,	1.092971065F,	1.093464399F,	1.093957956F,
	1.094451735F,	1.094945737F,	1.095439962F,	1.09593441F,	1.096429082F,	1.096923976F,	1.097419095F,	1.097914436F,
	1.098410001F,	1.09890579F,	1.099401803F,	1.099898039F,	1.1003945F,	1.100891184F,	1.101388093F,	1.101885226F,
	1.102382583F,	1.102880165F,	1.103377972F,	1.103876003F,	1.104374259F,	1.10487274F,	1.105371446F,	1.105870377F,
	1.106369533F,	1.106868914F,	1.107368521F,	1.107868354F,	1.108368412F,	1.108868695F,	1.109369205F,	1.10986994F,
	1.110370902F,	1.11087209F,	1.111373503F,	1.111875143F,	1.11237701F,	1.112879103F,	1.113381423F,	1.113883969F,
	1.114386743F,	1.114889743F,	1.11539297F,	1.115896424F,	1.116400106F,	1.116904015F,	1.117408152F,	1.117912516F,
	1.118417107F,	1.118921927F,	1.119426974F,	1.119932249F,	1.120437752F,	1.120943484F,	1.121449444F,	1.121955632F,
	1.122462048F,	1.122968693F,	1.123475567F,	1.12398267F,	1.124490002F,	1.124997562F,	1.125505352F,	1.12601337F,
	1.126521619F,	1.127030096F,	1.127538803F,	1.12804774F,	1.128556906F,	1.129066302F,	1.129575929F,	1.130085785F,
	1.130595871F,	1.131106188F,	1.131616734F,	1.132127512F,	1.13263852F,	1.133149758F,	1.133661227F,	1.134172928F,
	1.134684859F,	1.135197021F,	1.135709414F,	1.136222039F,	1.136734895F,	1.137247982F,	1.137761301F,	1.138274852F,
	1.138788635F,	1.139302649F,	1.139816896F,	1.140331374F,	1.140846085F,	1.141361028F,	1.141876204F,	1.142391612F,
	1.142907253F,	1.143423126F,	1.143939233F,	1.144455572F,	1.144972144F,	1.14548895F,	1.146005989F,	1.146523261F,
	1.147040767F,	1.147558506F,	1.148076479F,	1.148594686F,	1.149113126F,	1.149631801F,	1.15015071F,	1.150669853F,
	1.15118923F,	1.151708842F,	1.152228688F,	1.152748769F,	1.153269085F,	1.153789635F,	1.154310421F,	1.154831441F,
	1.155352697F,	1.155874188F,	1.156395914F,	1.156917876F,	1.157440074F,	1.157962507F,	1.158485176F,	1.159008081F,
	1.159531222F,	1.160054599F,	1.160578212F,	1.161102062F,	1.161626148F,	1.16215047F,	1.16267503F,	1.163199826F,
	1.163724859F,	1.164250129F,	1.164775636F,	1.16530138F,	1.165827362F,	1.16635358F,	1.166880037F,	1.167406731F,
	1.167933663F,	1.168460833F,	1.16898824F,	1.169515886F,	1.17004377F,	1.170571892F,	1.171100252F,	1.171628851F,
	1.172157689F,	1.172686765F,	1.17321608F,	1.173745634F,	1.174275427F,	1.174805459F,	1.175335731F,	1.175866241F,
	1.176396992F,	1.176927981F,	1.177459211F,	1.17799068F,	1.178522389F,	1.179054338F,	1.179586527F,	1.180118957F,
	1.180651627F,	1.181184537F,	1.181717688F,	1.182251079F,	1.182784711F,	1.183318584F,	1.183852698F,	1.184387053F,
	1.184921649F,	1.185456487F,	1.185991566F,	1.186526886F,	1.187062448F,	1.187598252F,	1.188134298F,	1.188670585F,
	1.189207115F,	1.189743887F,	1.190280901F,	1.190818158F,	1.191355657F,	1.191893398F,	1.192431383F,	1.19296961F,
	1.19350808F,	1.194046793F,	1.194585749F,	1.195124949F,	1.195664392F,	1.196204079F,	1.196744009F,	1.197284182F,
	1.1978246F,	1.198365262F,	1.198906167F,	1.199447317F,	1.199988711F,	1.200530349F,	1.201072232F,	1.201614359F,
	1.202156731F,	1.202699348F,	1.20324221F,	1.203785317F,	1.204328669F,	1.204872266F,	1.205416109F,	1.205960197F,
	1.206504531F,	1.20704911F,	1.207593935F,	1.208139006F,	1.208684324F,	1.209229887F,	1.209775696F,	1.210321752F,
	1.210868055F,	1.211414604F,	1.211961399F,	1.212508442F,	1.213055731F,	1.213603267F,	1.214151051F,	1.214699082F,
	1.21524736F,	1.215795886F,	1.216344659F,	1.21689368F,	1.217442948F,	1.217992465F,	1.21854223F,	1.219092243F,
	1.219642504F,	1.220193013F,	1.220743771F,	1.221294778F,	1.221846033F,	1.222397537F,	1.22294929F,	1.223501292F,
	1.224053543F,	1.224606044F,	1.225158794F,	1.225711793F,	1.226265042F,	1.226818541F,	1.227372289F,	1.227926288F,
	1.228480536F,	1.229035035F,	1.229589784F,	1.230144783F,	1.230700033F,	1.231255533F,	1.231811285F,	1.232367287F,
	1.23292354F,	1.233480044F,	1.234036799F,	1.234593806F,	1.235151064F,	1.235708573F,	1.236266335F,	1.236824348F,
	1.237382612F,	1.237941129F,	1.238499898F,	1.239058919F,	1.239618193F,	1.240177719F,	1.240737497F,	1.241297528F,
	1.241857812F,	1.242418349F,	1.242979139F,	1.243540182F,	1.244101478F,	1.244663027F,	1.24522483F,	1.245786887F,
	1.246349197F,	1.246911761F,	1.247474579F,	1.248037651F,	1.248600977F,	1.249164558F,	1.249728392F,	1.250292482F,
	1.250856826F,	1.251421424F,	1.251986278F,	1.252551386F,	1.25311675F,	1.253682369F,	1.254248243F,	1.254814372F,
	1.255380757F,	1.255947398F,	1.256514294F,	1.257081446F,	1.257648855F,	1.258216519F,	1.25878444F,	1.259352616F,
	1.25992105F,	1.26048974F,	1.261058687F,	1.26162789F,	1.26219735F,	1.262767068F,	1.263337042F,	1.263907274F,
	1.264477763F,	1.26504851F,	1.265619515F,	1.266190777F,	1.266762297F,	1.267334075F,	1.26790611F,	1.268478405F,
	1.269050957F,	1.269623768F,	1.270196838F,	1.270770166F,	1.271343753F,	1.271917599F,	1.272491703F,	1.273066067F,
	1.273640691F,	1.274215573F,	1.274790715F,	1.275366117F,	1.275941778F,	1.2765177F,	1.277093881F,	1.277670322F,
	1.278247024F,	1.278823985F,	1.279401208F,	1.27997869F,	1.280556434F,	1.281134438F,	1.281712703F,	1.282291229F,
	1.282870016F,	1.283449065F,	1.284028374F,	1.284607946F,	1.285187778F,	1.285767873F,	1.28634823F,	1.286928848F,
	1.287509728F,	1.288090871F,	1.288672276F,	1.289253943F,	1.289835873F,	1.290418066F,	1.291000521F,	1.29158324F,
	1.292166221F,	1.292749466F,	1.293332973F,	1.293916744F,	1.294500779F,	1.295085077F,	1.295669639F,	1.296254465F,
	1.296839555F,	1.297424909F,	1.298010527F,	1.298596409F,	1.299182556F,	1.299768967F,	1.300355643F,	1.300942584F,
	1.30152979F,	1.302117261F,	1.302704997F,	1.303292998F,	1.303881265F,	1.304469797F,	1.305058595F,	1.305647659F,
	1.306236989F,	1.306826584F,	1.307416446F,	1.308006574F,	1.308596968F,	1.309187629F,	1.309778556F,	1.310369751F,
	1.310961212F,	1.311552939F,	1.312144935F,	1.312737197F,	1.313329726F,	1.313922523F,	1.314515588F,	1.31510892F,
	1.31570252F,	1.316296388F,	1.316890524F,	1.317484929F,	1.318079601F,	1.318674542F,	1.319269752F,	1.31986523F,
	1.320460977F,	1.321056993F,	1.321653278F,	1.322249832F,	1.322846655F,	1.323443748F,	1.32404111F,	1.324638742F,
	1.325236643F,	1.325834815F,	1.326433256F,	1.327031968F,	1.327630949F,	1.328230202F,	1.328829724F,	1.329429517F,
	1.330029581F,	1.330629916F,	1.331230522F,	1.331831399F,	1.332432547F,	1.333033967F,	1.333635657F,	1.33423762F,
	1.334839854F,	1.33544236F,	1.336045138F,	1.336648188F,	1.337251511F,	1.337855105F,	1.338458972F,	1.339063112F,
	1.339667524F,	1.340272209F,	1.340877167F,	1.341482398F,	1.342087903F,	1.34269368F,	1.343299731F,	1.343906056F,
	1.344512654F,	1.345119526F,	1.345726672F,	1.346334092F,	1.346941786F,	1.347549755F,	1.348157998F,	1.348766515F,
	1.349375307F,	1.349984374F,	1.350593716F,	1.351203333F,	1.351813225F,	1.352423392F,	1.353033835F,	1.353644553F,
	1.354255547F,	1.354866817F,	1.355478362F,	1.356090184F,	1.356702282F,	1.357314656F,	1.357927306F,	1.358540233F,
	1.359153437F,	1.359766917F,	1.360380675F,	1.360994709F,	1.361609021F,	1.362223609F,	1.362838476F,	1.363453619F,
	1.364069041F,	1.36468474F,	1.365300717F,	1.365916972F,	1.366533506F,	1.367150317F,	1.367767407F,	1.368384776F,
	1.369002423F,	1.369620349F,	1.370238554F,	1.370857038F,	1.371475801F,	1.372094843F,	1.372714165F,	1.373333766F,
	1.373953647F,	1.374573808F,	1.375194249F,	1.37581497F,	1.376435971F,	1.377057252F,	1.377678814F,	1.378300656F,
	1.378922779F,	1.379545183F,	1.380167867F,	1.380790833F,	1.38141408F,	1.382037608F,	1.382661418F,	1.383285509F,
	1.383909882F,	1.384534537F,	1.385159473F,	1.385784692F,	1.386410193F,	1.387035977F,	1.387662042F,	1.388288391F,
	1.388915022F,	1.389541936F,	1.390169133F,	1.390796613F,	1.391424376F,	1.392052422F,	1.392680752F,	1.393309366F,
	1.393938263F,	1.394567445F,	1.39519691F,	1.395826659F,	1.396456693F,	1.397087011F,	1.397717613F,	1.398348501F,
	1.398979673F,	1.399611129F,	1.400242871F,	1.400874898F,	1.40150721F,	1.402139808F,	1.402772691F,	1.40340586F,
	1.404039315F,	1.404673055F,	1.405307082F,	1.405941395F,	1.406575994F,	1.407210879F,	1.407846051F,	1.40848151F,
	1.409117256F,	1.409753289F,	1.410389608F,	1.411026215F,	1.411663109F,	1.412300291F,	1.41293776F,	1.413575517F,
	1.414213562F,	1.414851895F,	1.415490516F,	1.416129426F,	1.416768623F,	1.417408109F,	1.418047884F,	1.418687948F,
	1.4193283F,	1.419968942F,	1.420609873F,	1.421251093F,	1.421892602F,	1.422534401F,	1.42317649F,	1.423818868F,
	1.424461537F,	1.425104495F,	1.425747744F,	1.426391283F,	1.427035113F,	1.427679233F,	1.428323644F,	1.428968346F,
	1.429613338F,	1.430258622F,	1.430904197F,	1.431550064F,	1.432196222F,	1.432842672F,	1.433489413F,	1.434136447F,
	1.434783772F,	1.43543139F,	1.4360793F,	1.436727502F,	1.437375997F,	1.438024785F,	1.438673866F,	1.439323239F,
	1.439972906F,	1.440622866F,	1.441273119F,	1.441923666F,	1.442574506F,	1.44322564F,	1.443877069F,	1.444528791F,
	1.445180807F,	1.445833118F,	1.446485723F,	1.447138622F,	1.447791816F,	1.448445306F,	1.44909909F,	1.449753169F,
	1.450407543F,	1.451062213F,	1.451717178F,	1.452372439F,	1.453027996F,	1.453683848F,	1.454339997F,	1.454996442F,
	1.455653183F,	1.45631022F,	1.456967554F,	1.457625185F,	1.458283113F,	1.458941337F,	1.459599859F,	1.460258678F,
	1.460917794F,	1.461577208F,	1.462236919F,	1.462896929F,	1.463557236F,	1.464217841F,	1.464878744F,	1.465539946F,
	1.466201446F,	1.466863245F,	1.467525342F,	1.468187738F,	1.468850433F,	1.469513428F,	1.470176721F,	1.470840314F,
	1.471504207F,	1.472168399F,	1.472832891F,	1.473497683F,	1.474162775F,	1.474828167F,	1.475493859F,	1.476159852F,
	1.476826146F,	1.47749274F,	1.478159635F,	1.478826832F,	1.479494329F,	1.480162128F,	1.480830228F,	1.481498629F,
	1.482167333F,	1.482836338F,	1.483505645F,	1.484175254F,	1.484845166F,	1.48551538F,	1.486185896F,	1.486856715F,
	1.487527837F,	1.488199262F,	1.48887099F,	1.489543021F,	1.490215355F,	1.490887993F,	1.491560934F,	1.492234179F,
	1.492907728F,	1.493581581F,	1.494255739F,	1.4949302F,	1.495604966F,	1.496280037F,	1.496955412F,	1.497631092F,
	1.498307077F,	1.498983367F,	1.499659962F,	1.500336863F,	1.50101407F,	1.501691582F,	1.502369399F,	1.503047523F,
	1.503725953F,	1.504404689F,	1.505083732F,	1.505763081F,	1.506442736F,	1.507122698F,	1.507802968F,	1.508483544F,
	1.509164428F,	1.509845618F,	1.510527117F,	1.511208923F,	1.511891036F,	1.512573458F,	1.513256187F,	1.513939225F,
	1.514622571F,	1.515306226F,	1.515990189F,	1.516674461F,	1.517359041F,	1.518043931F,	1.51872913F,	1.519414638F,
	1.520100455F,	1.520786582F,	1.521473019F,	1.522159765F,	1.522846822F,	1.523534189F,	1.524221866F,	1.524909853F,
	1.525598151F,	1.526286759F,	1.526975679F,	1.527664909F,	1.52835445F,	1.529044303F,	1.529734467F,	1.530424942F,
	1.53111573F,	1.531806829F,	1.53249824F,	1.533189963F,	1.533881998F,	1.534574345F,	1.535267006F,	1.535959978F,
	1.536653264F,	1.537346862F,	1.538040774F,	1.538734999F,	1.539429537F,	1.540124388F,	1.540819553F,	1.541515032F,
	1.542210825F,	1.542906932F,	1.543603354F,	1.544300089F,	1.544997139F,	1.545694504F,	1.546392183F,	1.547090177F,
	1.547788487F,	1.548487111F,	1.549186051F,	1.549885307F,	1.550584878F,	1.551284764F,	1.551984967F,	1.552685486F,
	1.553386321F,	1.554087472F,	1.55478894F,	1.555490724F,	1.556192825F,	1.556895243F,	1.557597978F,	1.558301031F,
	1.5590044F,	1.559708087F,	1.560412092F,	1.561116415F,	1.561821055F,	1.562526013F,	1.56323129F,	1.563936885F,
	1.564642798F,	1.56534903F,	1.566055581F,	1.566762451F,	1.56746964F,	1.568177148F,	1.568884975F,	1.569593122F,
	1.570301589F,	1.571010375F,	1.571719481F,	1.572428908F,	1.573138654F,	1.573848721F,	1.574559108F,	1.575269816F,
	1.575980845F,	1.576692195F,	1.577403866F,	1.578115858F,	1.578828171F,	1.579540806F,	1.580253763F,	1.580967041F,
	1.581680641F,	1.582394564F,	1.583108809F,	1.583823376F,	1.584538265F,	1.585253478F,	1.585969013F,	1.586684871F,
	1.587401052F,	1.588117556F,	1.588834384F,	1.589551536F,	1.590269011F,	1.59098681F,	1.591704933F,	1.59242338F,
	1.593142151F,	1.593861247F,	1.594580668F,	1.595300413F,	1.596020483F,	1.596740878F,	1.597461598F,	1.598182643F,
	1.598904014F,	1.599625711F,	1.600347733F,	1.601070081F,	1.601792756F,	1.602515756F,	1.603239083F,	1.603962736F,
	1.604686716F,	1.605411023F,	1.606135656F,	1.606860617F,	1.607585905F,	1.60831152F,	1.609037463F,	1.609763734F,
	1.610490332F,	1.611217258F,	1.611944513F,	1.612672095F,	1.613400006F,	1.614128246F,	1.614856814F,	1.615585711F,
	1.616314938F,	1.617044493F,	1.617774377F,	1.618504592F,	1.619235135F,	1.619966009F,	1.620697212F,	1.621428745F,
	1.622160609F,	1.622892803F,	1.623625327F,	1.624358182F,	1.625091368F,	1.625824885F,	1.626558732F,	1.627292911F,
	1.628027422F,	1.628762264F,	1.629497437F,	1.630232943F,	1.63096878F,	1.63170495F,	1.632441452F,	1.633178286F,
	1.633915453F,	1.634652953F,	1.635390785F,	1.636128951F,	1.63686745F,	1.637606282F,	1.638345447F,	1.639084947F,
	1.63982478F,	1.640564947F,	1.641305448F,	1.642046283F,	1.642787453F,	1.643528957F,	1.644270796F,	1.645012969F,
	1.645755478F,	1.646498322F,	1.647241501F,	1.647985016F,	1.648728866F,	1.649473052F,	1.650217574F,	1.650962432F,
	1.651707626F,	1.652453156F,	1.653199024F,	1.653945227F,	1.654691768F,	1.655438645F,	1.65618586F,	1.656933412F,
	1.657681301F,	1.658429528F,	1.659178092F,	1.659926995F,	1.660676235F,	1.661425814F,	1.662175731F,	1.662925986F,
	1.66367658F,	1.664427513F,	1.665178785F,	1.665930396F,	1.666682346F,	1.667434636F,	1.668187265F,	1.668940234F,
	1.669693543F,	1.670447192F,	1.671201181F,	1.67195551F,	1.67271018F,	1.67346519F,	1.674220541F,	1.674976233F,
	1.675732267F,	1.676488641F,	1.677245357F,	1.678002414F,	1.678759814F,	1.679517555F,	1.680275638F,	1.681034063F,
	1.681792831F,	1.682551941F,	1.683311393F,	1.684071189F,	1.684831327F,	1.685591809F,	1.686352633F,	1.687113802F,
	1.687875313F,	1.688637169F,	1.689399368F,	1.690161912F,	1.690924799F,	1.691688031F,	1.692451608F,	1.693215529F,
	1.693979795F,	1.694744405F,	1.695509361F,	1.696274663F,	1.697040309F,	1.697806302F,	1.69857264F,	1.699339324F,
	1.700106354F,	1.70087373F,	1.701641453F,	1.702409522F,	1.703177937F,	1.7039467F,	1.70471581F,	1.705485266F,
	1.706255071F,	1.707025222F,	1.707795721F,	1.708566568F,	1.709337763F,	1.710109306F,	1.710881197F,	1.711653437F,
	1.712426025F,	1.713198962F,	1.713972248F,	1.714745883F,	1.715519867F,	1.7162942F,	1.717068883F,	1.717843916F,
	1.718619298F,	1.719395031F,	1.720171113F,	1.720947546F,	1.721724329F,	1.722501463F,	1.723278948F,	1.724056783F,
	1.72483497F,	1.725613508F,	1.726392397F,	1.727171638F,	1.727951231F,	1.728731176F,	1.729511472F,	1.730292121F,
	1.731073122F,	1.731854476F,	1.732636182F,	1.733418241F,	1.734200653F,	1.734983419F,	1.735766537F,	1.73655001F,
	1.737333835F,	1.738118015F,	1.738902548F,	1.739687436F,	1.740472678F,	1.741258274F,	1.742044225F,	1.742830531F,
	1.743617191F,	1.744404207F,	1.745191578F,	1.745979304F,	1.746767386F,	1.747555824F,	1.748344617F,	1.749133767F,
	1.749923272F,	1.750713134F,	1.751503353F,	1.752293928F,	1.75308486F,	1.753876149F,	1.754667796F,	1.755459799F,
	1.75625216F,	1.757044879F,	1.757837956F,	1.75863139F,	1.759425183F,	1.760219334F,	1.761013843F,	1.761808711F,
	1.762603938F,	1.763399524F,	1.764195468F,	1.764991772F,	1.765788436F,	1.766585459F,	1.767382842F,	1.768180585F,
	1.768978687F,	1.769777151F,	1.770575974F,	1.771375158F,	1.772174703F,	1.772974609F,	1.773774875F,	1.774575503F,
	1.775376493F,	1.776177843F,	1.776979556F,	1.77778163F,	1.778584067F,	1.779386865F,	1.780190027F,	1.78099355F,
	1.781797436F,	1.782601685F,	1.783406297F,	1.784211273F,	1.785016611F,	1.785822313F,	1.786628379F,	1.787434809F,
	1.788241602F,	1.78904876F,	1.789856282F,	1.790664169F,	1.79147242F,	1.792281036F,	1.793090017F,	1.793899363F,
	1.794709075F,	1.795519152F,	1.796329595F,	1.797140403F,	1.797951578F,	1.798763118F,	1.799575025F,	1.800387298F,
	1.801199938F,	1.802012945F,	1.802826319F,	1.80364006F,	1.804454168F,	1.805268643F,	1.806083487F,	1.806898698F,
	1.807714277F,	1.808530224F,	1.809346539F,	1.810163223F,	1.810980276F,	1.811797697F,	1.812615487F,	1.813433647F,
	1.814252176F,	1.815071074F,	1.815890341F,	1.816709979F,	1.817529987F,	1.818350364F,	1.819171112F,	1.819992231F,
	1.82081372F,	1.821635579F,	1.82245781F,	1.823280412F,	1.824103385F,	1.82492673F,	1.825750446F,	1.826574535F,
	1.827398995F,	1.828223827F,	1.829049031F,	1.829874608F,	1.830700558F,	1.831526881F,	1.832353576F,	1.833180645F,
	1.834008086F,	1.834835902F,	1.835664091F,	1.836492654F,	1.83732159F,	1.838150901F,	1.838980587F,	1.839810647F,
	1.840641081F,	1.84147189F,	1.842303075F,	1.843134634F,	1.843966569F,	1.844798879F,	1.845631565F,	1.846464627F,
	1.847298065F,	1.848131879F,	1.84896607F,	1.849800636F,	1.85063558F,	1.851470901F,	1.852306598F,	1.853142673F,
	1.853979125F,	1.854815955F,	1.855653162F,	1.856490747F,	1.857328711F,	1.858167052F,	1.859005772F,	1.859844871F,
	1.860684348F,	1.861524205F,	1.86236444F,	1.863205054F,	1.864046048F,	1.864887422F,	1.865729175F,	1.866571309F,
	1.867413822F,	1.868256716F,	1.86909999F,	1.869943645F,	1.87078768F,	1.871632097F,	1.872476895F,	1.873322074F,
	1.874167634F,	1.875013576F,	1.8758599F,	1.876706606F,	1.877553694F,	1.878401165F,	1.879249018F,	1.880097254F,
	1.880945872F,	1.881794874F,	1.882644259F,	1.883494027F,	1.884344179F,	1.885194715F,	1.886045634F,	1.886896938F,
	1.887748625F,	1.888600698F,	1.889453154F,	1.890305996F,	1.891159223F,	1.892012834F,	1.892866831F,	1.893721214F,
	1.894575982F,	1.895431135F,	1.896286675F,	1.897142601F,	1.897998914F,	1.898855613F,	1.899712698F,	1.900570171F,
	1.90142803F,	1.902286277F,	1.903144911F,	1.904003932F,	1.904863342F,	1.905723139F,	1.906583324F,	1.907443898F,
	1.90830486F,	1.909166211F,	1.91002795F,	1.910890079F,	1.911752596F,	1.912615503F,	1.913478799F,	1.914342486F,
	1.915206561F,	1.916071027F,	1.916935883F,	1.91780113F,	1.918666767F,	1.919532795F,	1.920399213F,	1.921266023F,
	1.922133224F,	1.923000816F,	1.9238688F,	1.924737176F,	1.925605944F,	1.926475103F,	1.927344656F,	1.9282146F,
	1.929084938F,	1.929955668F,	1.930826791F,	1.931698307F,	1.932570217F,	1.93344252F,	1.934315217F,	1.935188308F,
	1.936061793F,	1.936935673F,	1.937809947F,	1.938684615F,	1.939559678F,	1.940435136F,	1.94131099F,	1.942187238F,
	1.943063882F,	1.943940922F,	1.944818358F,	1.94569619F,	1.946574418F,	1.947453042F,	1.948332063F,	1.949211481F,
	1.950091295F,	1.950971507F,	1.951852116F,	1.952733123F,	1.953614527F,	1.954496329F,	1.955378529F,	1.956261128F,
	1.957144124F,	1.958027519F,	1.958911313F,	1.959795506F,	1.960680098F,	1.961565089F,	1.96245048F,	1.963336271F,
	1.964222461F,	1.965109051F,	1.965996041F,	1.966883432F,	1.967771223F,	1.968659415F,	1.969548008F,	1.970437002F,
	1.971326397F,	1.972216194F,	1.973106392F,	1.973996992F,	1.974887994F,	1.975779399F,	1.976671205F,	1.977563415F,
	1.978456026F,	1.979349041F,	1.980242459F,	1.98113628F,	1.982030505F,	1.982925133F,	1.983820165F,	1.984715601F,
	1.985611441F,	1.986507685F,	1.987404335F,	1.988301388F,	1.989198847F,	1.990096711F,	1.99099498F,	1.991893654F,
	1.992792734F,	1.99369222F,	1.994592112F,	1.99549241F,	1.996393115F,	1.997294226F,	1.998195744F,	1.999097668F,

};

/* Enviromental Presets. */
EAX_REVERBPROPERTIES Sound_Enviroments[] = 
{
/*	Enviroment							Volume	Decay	Damping */
	{EAX_ENVIRONMENT_GENERIC,			0.5F,	1.493F,	0.5F},
	{EAX_ENVIRONMENT_PADDEDCELL,		0.25F,	0.1F,	0.0F},
	{EAX_ENVIRONMENT_ROOM,				0.417F,	0.4F,	0.666F},
	{EAX_ENVIRONMENT_BATHROOM,			0.653F,	1.499F,	0.166F},
	{EAX_ENVIRONMENT_LIVINGROOM,		0.208F,	0.478F,	0.0F},
 	{EAX_ENVIRONMENT_STONEROOM,			0.5F,	2.309F,	0.888F},
	{EAX_ENVIRONMENT_AUDITORIUM,		0.403F,	4.279F,	0.5F},
	{EAX_ENVIRONMENT_CONCERTHALL,		0.5F,	3.961F,	0.5F},
	{EAX_ENVIRONMENT_CAVE,				0.5F,	2.886F,	1.304F},
	{EAX_ENVIRONMENT_ARENA,				0.361F,	7.284F,	0.332F},
	{EAX_ENVIRONMENT_HANGAR,			0.5F,	10.0F,	0.3F},
	{EAX_ENVIRONMENT_CARPETEDHALLWAY,	0.153F,	0.259F,	2.0F},
	{EAX_ENVIRONMENT_HALLWAY,			0.361F,	1.493F,	0.0F},
	{EAX_ENVIRONMENT_STONECORRIDOR,		0.444F,	2.697F,	0.638F},
	{EAX_ENVIRONMENT_ALLEY,				0.25F,	1.752F,	0.776F},
	{EAX_ENVIRONMENT_FOREST,			0.111F,	3.145F,	0.472F},
	{EAX_ENVIRONMENT_CITY,				0.111F,	2.767F,	0.224F},
	{EAX_ENVIRONMENT_MOUNTAINS,			0.194F,	7.841F,	0.472F},
	{EAX_ENVIRONMENT_QUARRY,			1.0F,	1.499F,	0.5F},
	{EAX_ENVIRONMENT_PLAIN,				0.097F,	2.767F,	0.224F},
	{EAX_ENVIRONMENT_PARKINGLOT,		0.208F,	1.652F,	1.5F},
	{EAX_ENVIRONMENT_SEWERPIPE,			0.652F,	2.886F,	0.25F},
	{EAX_ENVIRONMENT_UNDERWATER,		1.0F,	1.499F,	0.0F},
	{EAX_ENVIRONMENT_DRUGGED,			0.875F,	8.392F,	1.388F},
	{EAX_ENVIRONMENT_DIZZY,				0.139F,	17.234F,0.666F},
	{EAX_ENVIRONMENT_PSYCHOTIC,			0.486F,	7.563F,	0.806F},
	{EAX_ENVIRONMENT_PLAIN,				0.0F,	0.1F,	0.5F}
};

// Extra enumeration we have made up.
enum
{
	EAX_ENVIRONMENT_DEFAULT = EAX_ENVIRONMENT_PSYCHOTIC + 1,
	EAX_MAX
};

static unsigned int SoundMaxHW;
extern int GlobalFrameCounter;

// Test.
LPDIRECTSOUNDBUFFER		NullDSBufferP = NULL;
LPDIRECTSOUND3DBUFFER	NullDS3DBufferP = NULL;
/* Patrick 5/6/97 -------------------------------------------------------------
  Internal functions
  ----------------------------------------------------------------------------*/
static int PlatChangeSoundPan(int activeIndex, int pan);
static int ToneToFrequency(int currentFrequency, int currentPitch, int newPitch);

/* Patrick 5/6/97 -------------------------------------------------------------
  External references
  ----------------------------------------------------------------------------*/
extern HWND hWndMain;
extern DISPLAYBLOCK *Player;
extern VIEWDESCRIPTORBLOCK *Global_VDB_Ptr;

/* Patrick 5/6/97 -------------------------------------------------------------
  Function definitions
  ----------------------------------------------------------------------------*/
int PlatStartSoundSys(void)
{
	HRESULT hres;
 	DSCAPS caps;

	db_log4("PlatStartSound called");
	LOG_RC();

	/* Set the globals. */
	SoundConfig.flags			= SOUND_DEFAULT;
	SoundConfig.reverb_changed	= TRUE;
	SoundConfig.reverb_mix		= 0.0F;
	SoundConfig.env_index		= 1000;

	/* Create the ds object */
	hres = DirectSoundCreate(NULL,&DSObject,NULL);
	if(hres!=DS_OK)
	{		
		PlatEndSoundSys();
		return 0;
	}

	db_log5("Made DSO");
	LOG_RC();

	/* Set cooperative level */
    hres = IDirectSound_SetCooperativeLevel(DSObject, hWndMain, DSSCL_PRIORITY);
	if(hres!=DS_OK)
	{		
		PlatEndSoundSys();
		return 0;
	}

	/* Create primary buffer & set format */
	{
		DSBUFFERDESC dsBuffDesc;
		WAVEFORMATEX wfex;		
    	
		/* set format description */
    	memset(&wfex, 0, sizeof(WAVEFORMATEX));
    	wfex.wFormatTag = WAVE_FORMAT_PCM;
    	wfex.nChannels = 2;
    	wfex.nSamplesPerSec = 22050;
    	wfex.nBlockAlign = 4;
    	wfex.nAvgBytesPerSec = 
        wfex.nSamplesPerSec * wfex.nBlockAlign;
    	wfex.wBitsPerSample = 16;
		wfex.cbSize = 0;

		/* set buffer description */
		memset(&dsBuffDesc,0,sizeof(DSBUFFERDESC));
		dsBuffDesc.dwSize = sizeof(DSBUFFERDESC);
		dsBuffDesc.dwFlags = (DSBCAPS_PRIMARYBUFFER | DSBCAPS_CTRL3D | DSBCAPS_LOCHARDWARE | DSBCAPS_CTRLVOLUME);
		dsBuffDesc.dwBufferBytes = 0;
		dsBuffDesc.lpwfxFormat = NULL;
	
		hres = IDirectSound_CreateSoundBuffer(DSObject, &dsBuffDesc, &DSPrimaryBuffer, NULL);	
		if(hres!=DS_OK)
		{		
			PlatEndSoundSys();
			return 0;
		}

		hres = IDirectSoundBuffer_SetFormat(DSPrimaryBuffer, &wfex);	
		/* If the format set failed just continue with the default format */ 
	}

	db_log5("Make DSPB");
	LOG_RC();

	/* Get and log some caps. */
	ZeroMemory(&caps, sizeof(DSCAPS));
	caps.dwSize = sizeof(DSCAPS);

	IDirectSound_GetCaps(DSObject, &caps);

	db_logf1(("Number of HW buffers %i", caps.dwMaxHwMixingStaticBuffers));
	db_logf1(("Number of HW 3D buffers %i", caps.dwFreeHw3DStaticBuffers));
	if(caps.dwFreeHw3DStaticBuffers)
	{
		SoundConfig.flags |= (SOUND_3DHW | SOUND_USE_3DHW);
	}
	if(caps.dwMaxHwMixingStaticBuffers)
	{
		SoundMaxHW = min(caps.dwMaxHwMixingStaticBuffers - 1,SOUND_MAXACTIVE); // Always leave one free. 
	}
	else
	{
		SoundMaxHW = 0;
	}
	SoundMinBufferFree = SoundMaxHW / 2;

	/* Create a Listener. */
	hres = IDirectSoundBuffer_QueryInterface(DSPrimaryBuffer, &IID_IDirectSound3DListener, (void **) &DS3DListener);
	if(hres!=DS_OK)
	{		
		PlatEndSoundSys();
		return 0;
	}

	db_log5("Made a DS3DL");
	LOG_RC();

	/* Set the Listener's data. */
	{
		DS3DLISTENER listener;
		memset(&listener, 0, sizeof(DS3DLISTENER));
		listener.dwSize				= sizeof(DS3DLISTENER);
		listener.vPosition.x		= 0.0F;
		listener.vPosition.y		= 0.0F;
		listener.vPosition.z		= 0.0F;
		listener.vVelocity.x		= 0.0F;
		listener.vVelocity.y		= 0.0F;
		listener.vVelocity.z		= 0.0F;
		listener.vOrientFront.x		= 0.0F;
		listener.vOrientFront.y		= 0.0F;
		listener.vOrientFront.z		= 1.0F;
		listener.vOrientTop.x		= 0.0F;
		listener.vOrientTop.y		= -1.0F;
		listener.vOrientTop.z		= 0.0F;
		listener.flDistanceFactor	= 0.001F;
		listener.flRolloffFactor	= 0.0F;
		listener.flDopplerFactor	= DS3D_DEFAULTDOPPLERFACTOR;
		hres = IDirectSound3DListener_SetAllParameters(DS3DListener, &listener, DS3D_IMMEDIATE);
		if(hres!=DS_OK)
		{		
			PlatEndSoundSys();
			return 0;
		}
	}

	/* Create a NULL secondary buffer. */
	{
		DSBUFFERDESC			dsBuffDesc;
		WAVEFORMATEX			wfex;		

		/* Set buffer desciption. */
		memset(&dsBuffDesc, 0, sizeof(DSBUFFERDESC));
		dsBuffDesc.dwSize			= sizeof(DSBUFFERDESC);
		dsBuffDesc.dwFlags			= (DSBCAPS_STATIC | DSBCAPS_CTRL3D | DSBCAPS_MUTE3DATMAXDISTANCE);
		dsBuffDesc.dwBufferBytes	= 8;
		dsBuffDesc.lpwfxFormat		= &wfex;

		/* Set the format. */
		wfex.wFormatTag				= WAVE_FORMAT_PCM;
		wfex.nChannels				= 1;
		wfex.nSamplesPerSec			= 11025;
		wfex.nBlockAlign			= 1;
	    wfex.nAvgBytesPerSec		= wfex.nSamplesPerSec * wfex.nBlockAlign;
	   	wfex.wBitsPerSample			= 8;
	  	wfex.cbSize					= 0;
	   								
		hres = IDirectSound_CreateSoundBuffer(DSObject, &dsBuffDesc, &NullDSBufferP, NULL);
		if(hres!=DS_OK)
		{		
			PlatEndSoundSys();
			return 0;
		}

		/* Get the 3D Buffer. */
		hres = IDirectSoundBuffer_QueryInterface(NullDSBufferP, &IID_IDirectSound3DBuffer, (void **) &NullDS3DBufferP);
		if(hres!=DS_OK)
		{		
			PlatEndSoundSys();
			return 0;
		}

		IDirectSound_GetCaps(DSObject, &caps);

		db_logf1(("Number of HW buffers %i", caps.dwMaxHwMixingStaticBuffers));
		db_logf1(("Number of HW 3D buffers %i", caps.dwFreeHw3DStaticBuffers));

		/* Get the Property set. */
		hres = IDirectSound3DBuffer_QueryInterface
			(
				NullDS3DBufferP,
				&IID_IKsPropertySet,
				(void**) &PropSetP
			);
	   	if(hres != DD_OK)
		{
			/* No property set. */
			db_log1("Error: Failed to get the property set.");
		}

		db_log5("Made a PropSet");
		LOG_RC();

		/* Test for the property set we want to use. */
		if(PropSetP)
		{
			unsigned long support;

  			/* Voice Management. */
			IKsPropertySet_QuerySupport
				(
					PropSetP,								   
					&DSPROPSETID_VoiceManager,
					DSPROPERTY_VMANAGER_MODE,
					&support
				);

			if(support == (KSPROPERTY_SUPPORT_GET | KSPROPERTY_SUPPORT_SET))
			{
				VmMode mode = DSPROPERTY_VMANAGER_MODE_AUTO;

				db_log1("Voice Management active.");
				SoundConfig.flags |= SOUND_VOICE_MGER;

				// Set the mode we want.
				hres = IKsPropertySet_Set
				(
					PropSetP,
					&DSPROPSETID_VoiceManager,
		        	DSPROPERTY_VMANAGER_MODE,
			        NULL,
		    	    0,
		        	&mode,
			        sizeof(VmMode)
				);
			}
			else
			{
				db_logf1(("No voice management. Support %x", support));
			}

			/* EAX support. */
			IKsPropertySet_QuerySupport
				(
					PropSetP,
					&DSPROPSETID_EAX_ReverbProperties,
					DSPROPERTY_EAX_ALL,
					&support
				);

			if(support == (KSPROPERTY_SUPPORT_GET | KSPROPERTY_SUPPORT_SET))
			{
				db_log1("EAX suppport.");
				SoundConfig.flags |= SOUND_EAX;

				// Set a default value.
				PlatSetEnviroment(EAX_ENVIRONMENT_DEFAULT, EAX_REVERBMIX_USEDISTANCE);
			}
			else
			{
				db_logf1(("No EAX support. Support %x", support));
			}
		}

		/* If we have Voice Management release everything and reaquire to free up one buffer. */
		if(SoundConfig.flags & SOUND_VOICE_MGER)
		{
			IDirectSound_GetCaps(DSObject, &caps);

			db_logf1(("Number of HW buffers %i", caps.dwMaxHwMixingStaticBuffers));
			db_logf1(("Number of HW 3D buffers %i", caps.dwFreeHw3DStaticBuffers));

			/* Release the Property Set. */
			IKsPropertySet_Release(PropSetP);
			PropSetP = NULL;

			/* Release the Null buffers. */
			if(NullDS3DBufferP)
			{
				IDirectSoundBuffer_Release(NullDS3DBufferP);
				NullDS3DBufferP = NULL;
			}

			if(NullDSBufferP)
			{
				IDirectSoundBuffer_Release(NullDSBufferP);
				NullDSBufferP = NULL;
			}

			/* Remake the buffers. */
			hres = IDirectSound_CreateSoundBuffer(DSObject, &dsBuffDesc, &NullDSBufferP, NULL);
			if(hres!=DS_OK)
			{		
				db_log1("Error: Remaking buffer.");
			}

			hres = IDirectSoundBuffer_QueryInterface(NullDSBufferP, &IID_IDirectSound3DBuffer, (void **) &NullDS3DBufferP);
			if(hres!=DS_OK)
			{		
				db_log1("Error: Remaking buffer.");
			}

			/* Get the Property set. */
			hres = IDirectSound3DBuffer_QueryInterface
				(
					NullDS3DBufferP,
					&IID_IKsPropertySet,
					(void**) &PropSetP
				);
		   	if(hres != DD_OK)
			{
				/* No property set. */
				db_log1("Error: Failed to get the property set again.");
			}

			/* Now recheck the number of free buffers. */
			IDirectSound_GetCaps(DSObject, &caps);

			db_logf1(("Number of HW buffers %i", caps.dwMaxHwMixingStaticBuffers));
			db_logf1(("Number of HW 3D buffers %i", caps.dwFreeHw3DStaticBuffers));
			if(caps.dwMaxHwMixingStaticBuffers)
			{
				SoundMaxHW = min(caps.dwMaxHwMixingStaticBuffers - 1,SOUND_MAXACTIVE); // Always leave one free. 
			}
			else
			{
				SoundMaxHW = 0;
			}
			SoundMinBufferFree = SoundMaxHW / 2;
		}

		/* Do we need the property set. */
		if(PropSetP && (~SoundConfig.flags & SOUND_EAX) && (~SoundConfig.flags & SOUND_VOICE_MGER))
		{
			IKsPropertySet_Release(PropSetP);
			PropSetP = NULL;
			db_log1("Releasing the property set.");
		}		

	}

	/* Play the primary buffer */
	hres = IDirectSoundBuffer_Play(DSPrimaryBuffer,0,0,DSBPLAY_LOOPING);
	if(hres!=DS_OK)
	{		
		PlatEndSoundSys();
		return 0;
	}

	db_log4("PlatStartSound finished");
	LOG_RC();

	return 1;
}
void ResetEaxEnvironment(void)
{
 	// Set a default value.
 	PlatSetEnviroment(EAX_ENVIRONMENT_DEFAULT, EAX_REVERBMIX_USEDISTANCE);
}

void PlatEndSoundSys(void)
{
	HRESULT hres;

	db_log3("PlatEndSoundSys called.");
	LOG_RC();
	
	if(PropSetP)
	{
		IKsPropertySet_Release(PropSetP);
		PropSetP = NULL;
	}

	db_log5("Released the PS");
	LOG_RC();

	if(DS3DListener)
	{
		IDirectSound3DListener_Release(DS3DListener);
		DS3DListener = NULL;
	}

	db_log5("Released the DSL");
	LOG_RC();

	if(NullDS3DBufferP)
	{
		IDirectSoundBuffer_Release(NullDS3DBufferP);
		NullDS3DBufferP = NULL;
	}

	if(NullDSBufferP)
	{
		IDirectSoundBuffer_Release(NullDSBufferP);
		NullDSBufferP = NULL;
	}

	db_log5("Released the last buffers");
	LOG_RC();

	if(DSPrimaryBuffer)
	{
		hres = IDirectSoundBuffer_Stop(DSPrimaryBuffer);
		hres = IDirectSoundBuffer_Release(DSPrimaryBuffer);
		DSPrimaryBuffer = NULL;
	}

	db_log5("Released the Primary Buffer.");
	LOG_RC();

	if(DSObject)
	{		
		hres = IDirectSound_Release(DSObject);
		DSObject = NULL;
	}	

	db_log5("Released the sodding lot.");
	LOG_RC();

	db_log3("PlatEndSoundSys finished.");
}

int PlatChangeGlobalVolume(volume)
{
	int attenuation;
	HRESULT hres;
	LOCALASSERT((volume>=VOLUME_MIN)&&(volume<=VOLUME_MAX));

	/* convert from intensity to attenuation: 
	see comment for PLATCHANGEVOLUME to see how this works  */
	if(volume == VOLUME_MIN) attenuation = VOLUME_MINPLAT;
	else if(volume == VOLUME_MAX) attenuation = VOLUME_MAXPLAT;	
	else if(volume <(VOLUME_MAX>>4)) attenuation = ((3000*volume)>>3)-7000;
	else if(volume <(VOLUME_MAX>>3)) attenuation = ((1000*(volume-(VOLUME_MAX>>4)))>>3)-4000;
	else if(volume <(VOLUME_MAX>>2)) attenuation = ((1000*(volume-(VOLUME_MAX>>3)))>>4)-3000;
	else if(volume <(VOLUME_MAX>>1)) attenuation = ((1000*(volume-(VOLUME_MAX>>2)))>>5)-2000;
	else if(volume <VOLUME_MAX) attenuation = ((1000*(volume-(VOLUME_MAX>>1)))>>6)-1000;

	if(attenuation>VOLUME_MAXPLAT) attenuation=VOLUME_MAXPLAT;
	if(attenuation<VOLUME_MINPLAT) attenuation=VOLUME_MINPLAT;

	hres = IDirectSoundBuffer_SetVolume(DSPrimaryBuffer,attenuation);
	if(hres==DS_OK)
	{
		return 1;	
	}
	
	return SOUND_PLATFORMERROR;
}
 
int PlatPlaySound(activeIndex)
{
	HRESULT hres;
	SOUNDINDEX gameIndex;

	/* check bounds of active sound index */
	LOCALASSERT((activeIndex>=0)||(activeIndex<SOUND_MAXACTIVE));
	gameIndex = ActiveSounds[activeIndex].soundIndex;
	LOCALASSERT((gameIndex>=0)&&(gameIndex<SID_MAXIMUM));	
	LOCALASSERT(GameSounds[gameIndex].loaded);
	 

	/* duplicate the game sound buffer */
	hres = IDirectSound_DuplicateSoundBuffer(DSObject,GameSounds[gameIndex].dsBufferP,
		&(ActiveSounds[activeIndex].dsBufferP));
	if(hres!=DS_OK) 
	{
		db_logf3(("Error: Failed to duplicate a sound buffer. Index %i", gameIndex));
		return SOUND_PLATFORMERROR;
	}

#if 1
	/* Do we need to get a DirectSound3D buffer. */
	if((ActiveSounds[activeIndex].threedee))/* &&
		(GameSounds[gameIndex].flags & SAMPLE_IN_HW) &&
		(SoundConfig.flags & SOUND_EAX) &&
		(SoundConfig.flags & SOUND_USE_3DHW)) */
	{
		db_log5("Going for a DirectSound3DBuffer.");
		hres = IDirectSoundBuffer_QueryInterface
			(
				ActiveSounds[activeIndex].dsBufferP,
				&IID_IDirectSound3DBuffer,
				&ActiveSounds[activeIndex].ds3DBufferP
			);

		if(hres != DD_OK)
		{
			db_logf5(("Error: Failed to get a DirectSound3DBuffer. res %x", hres));
		}
	}
#endif

#if 0
	if((SoundConfig.flags & SOUND_EAX) &&
		(GameSounds[gameIndex].flags & SAMPLE_IN_HW) &&
		(ActiveSounds[activeIndex].ds3DBufferP))
	{
		db_log5("Going for a EAX property set.");
		hres = IDirectSound3DBuffer_QueryInterface
			(
				ActiveSounds[activeIndex].ds3DBufferP,
				&IID_IKsPropertySet,
				(void**) &(ActiveSounds[activeIndex].PropSetP)
			);
		if(hres != DD_OK)
		{
			db_logf3(("Failed to get the property set for a DirectSoundBuffer. res %x", hres));
		}
	}
#endif

	/* may need to initialise pitch before playing */
	if(ActiveSounds[activeIndex].pitch != GameSounds[gameIndex].pitch)
	{
		int ok = PlatChangeSoundPitch(activeIndex,ActiveSounds[activeIndex].pitch);
		if(ok==SOUND_PLATFORMERROR)
		{
		   	PlatStopSound(activeIndex);
			return SOUND_PLATFORMERROR;
		}
	}

	/* Initialise volume before playing */
	if(ActiveSounds[activeIndex].threedee)
	{
		int ok;

		if(ActiveSounds[activeIndex].ds3DBufferP)
		{
			/*set 3d sound mode*/
			IDirectSound3DBuffer_SetMode(ActiveSounds[activeIndex].ds3DBufferP,DS3DMODE_NORMAL,DS3D_DEFERRED);

			/*set distance at which attenuation starts*/
			IDirectSound3DBuffer_SetMinDistance(ActiveSounds[activeIndex].ds3DBufferP,(D3DVALUE)ActiveSounds[activeIndex].threedeedata.inner_range,DS3D_DEFERRED);
			IDirectSound3DBuffer_SetMaxDistance(ActiveSounds[activeIndex].ds3DBufferP,DS3D_DEFAULTMAXDISTANCE,DS3D_DEFERRED);
		}

		/* 3d sounds always need initialising */
		ok = PlatDo3dSound(activeIndex);
		if(ok==SOUND_PLATFORMERROR)
		{
		   	PlatStopSound(activeIndex);
			return SOUND_PLATFORMERROR;
		}
	}
	else 
	{
		int newVolume,ok;
		/* 2d sound: ummm: cap all 2d sounds to SOUND_PLAT2DSCALE * their specified volume.
		This is really project&platform specific, so that 3d sounds aren't drowned out by
		2d ones...*/
		newVolume = ActiveSounds[activeIndex].volume;
		newVolume = (newVolume*VOLUME_PLAT2DSCALE)>>7;
		ActiveSounds[activeIndex].volume = newVolume;		
		
		ok = PlatChangeSoundVolume(activeIndex, ActiveSounds[activeIndex].volume);
		if(ok==SOUND_PLATFORMERROR)
		{
		   	PlatStopSound(activeIndex);
			return SOUND_PLATFORMERROR;
		}
	}

   	if(ActiveSounds[activeIndex].PropSetP)
  	{
		HRESULT res;
		if(!ActiveSounds[activeIndex].reverb_off)
		{
		   res = IKsPropertySet_Set
				(
					ActiveSounds[activeIndex].PropSetP,
					&DSPROPSETID_EAXBUFFER_ReverbProperties,
			        DSPROPERTY_EAXBUFFER_REVERBMIX,
			        NULL,
			        0,
			        &SoundConfig.reverb_mix,
		    	    sizeof(float)
				);
		}
		else
		{
			float temp =0;
		   res = IKsPropertySet_Set
				(
					ActiveSounds[activeIndex].PropSetP,
					&DSPROPSETID_EAXBUFFER_ReverbProperties,
			        DSPROPERTY_EAXBUFFER_REVERBMIX,
			        NULL,
			        0,
			        &temp,
		    	    sizeof(float)
				);
		}

		if(res != DD_OK)
		{
			db_logf3(("Error: Failed to set the buffer property set at play start. res %x", res));
		}
	}

	db_logf4(("RefCount after PlaySound %i, Active Inst %i, activeIndex %i", GET_REF_COUNT(ActiveSounds[activeIndex].PropSetP), GameSounds[gameIndex].activeInstances, activeIndex));

   //	IDirectSound3DListener_CommitDeferredSettings(DS3DListener);

	/* play the buffer then... */
	if (!ActiveSounds[activeIndex].paused)
	{
		DWORD flags = 0;
		if(ActiveSounds[activeIndex].loop)
		{
			flags|= DSBPLAY_LOOPING;
		}
		hres = IDirectSoundBuffer_Play(ActiveSounds[activeIndex].dsBufferP,0,0,flags);
		if(hres!=DS_OK)
		{
			if(GameSounds[gameIndex].flags & SAMPLE_IN_HW)
			{
				db_log3("Failed to play a sample in Hardware");
			}
			else
			{
				db_log3("Failed to play a sample from Software.");
			}
			return SOUND_PLATFORMERROR;	
		}

		/* success */
		if(ActiveSounds[activeIndex].loop)
		{
			db_logf5(("Playing Sound %i looping in slot %i on frame %i", ActiveSounds[activeIndex].soundIndex, activeIndex, GlobalFrameCounter));
		}
		else
		{
			db_logf5(("Playing Sound %i once in slot %i on frame %i", ActiveSounds[activeIndex].soundIndex, activeIndex, GlobalFrameCounter));
		}
	}

	return 1;	 	

}

void PlatStopSound(int activeIndex)
{
	HRESULT hres;

	db_logf5(("Stopping Sound %i in slot %i on frame %i", ActiveSounds[activeIndex].soundIndex, activeIndex, GlobalFrameCounter));

	if(!(ActiveSounds[activeIndex].dsBufferP)) return;
	
	if (!ActiveSounds[activeIndex].paused)
		hres = IDirectSoundBuffer_Stop(ActiveSounds[activeIndex].dsBufferP);
	
	db_logf4(("RefCount before StopSound %i, activeIndex %i", GET_REF_COUNT(ActiveSounds[activeIndex].PropSetP), activeIndex));
	if(ActiveSounds[activeIndex].PropSetP)
	{
		IKsPropertySet_Release(ActiveSounds[activeIndex].PropSetP);
		ActiveSounds[activeIndex].PropSetP = NULL;
	}

	if(ActiveSounds[activeIndex].ds3DBufferP)
	{
		IDirectSound3DBuffer_Release(ActiveSounds[activeIndex].ds3DBufferP);
		ActiveSounds[activeIndex].ds3DBufferP = NULL;
	}

	IDirectSoundBuffer_Release(ActiveSounds[activeIndex].dsBufferP);
	ActiveSounds[activeIndex].dsBufferP = NULL;
}

/* Patrick 15/6/97 -------------------------------------------------------------
  The standard volume interface in PSND is a linear intensity scale, matching the
  PSX's scale. However, ds uses a logarithmic scale: 
  Atenuation = 10 log(2) (I/I0).
  We should therefore convert from intensity to attenuation...
  I have cheated here, and used a sequence of linear approximations between 
  power-of-two intensity values....
  NB an attenuation of 70db is about 1% of full volume;
  ----------------------------------------------------------------------------*/
int PlatChangeSoundVolume(int activeIndex, int volume)
{
	signed int attenuation;
	HRESULT hres;
	LOCALASSERT(ActiveSounds[activeIndex].dsBufferP);
	if(volume<VOLUME_MIN) volume=VOLUME_MIN;
	if(volume>VOLUME_MAX) volume=VOLUME_MAX;

	/* convert from intensity to attenuation */
	attenuation = vol_to_atten_table[volume];

	if(attenuation>VOLUME_MAXPLAT) attenuation=VOLUME_MAXPLAT;
	if(attenuation<VOLUME_MINPLAT) attenuation=VOLUME_MINPLAT;

	/* and apply it */
	hres = IDirectSoundBuffer_SetVolume(ActiveSounds[activeIndex].dsBufferP,attenuation);
	if(hres==DS_OK) return 1;	
	else return SOUND_PLATFORMERROR;
}

int PlatChangeSoundPitch(int activeIndex, int pitch)
{
	HRESULT hres;
	int frequency;

	LOCALASSERT(ActiveSounds[activeIndex].dsBufferP);
	LOCALASSERT((pitch>=PITCH_MIN)&&(pitch<=PITCH_MAX));

	/* calculate new frequency from base pitch for game sound
	(NB don't need to scale pitch values...) */
	
	/* default pitch is a special case in ds */
	if(pitch==PITCH_DEFAULTPLAT) frequency=0;
	else
	{
		SOUNDINDEX gameSoundIndex = ActiveSounds[activeIndex].soundIndex;
		frequency = ToneToFrequency(GameSounds[gameSoundIndex].dsFrequency, 
			GameSounds[gameSoundIndex].pitch, pitch);	
	}

	ActiveSounds[activeIndex].pitch = pitch;
	hres = IDirectSoundBuffer_SetFrequency(ActiveSounds[activeIndex].dsBufferP,frequency);
	if(hres==DS_OK) return 1;	
	else return SOUND_PLATFORMERROR;
	return 1;
}

int PlatSoundHasStopped(int activeIndex)
{
	HRESULT hres;
	DWORD status = 0;

	LOCALASSERT(ActiveSounds[activeIndex].dsBufferP);
	hres = IDirectSoundBuffer_GetStatus(ActiveSounds[activeIndex].dsBufferP,&status);
	if(hres==DS_OK)
	{
		if(status&DSBSTATUS_BUFFERLOST)
		{
			return SOUND_PLATFORMERROR;
		}
		if(status&DSBSTATUS_PLAYING)
		{
			return 0;
		}
		else
		{
			return 1;
		}
	}

	return SOUND_PLATFORMERROR;
}

int PlatDo3dSound(int activeIndex)
{
	int distance;
	VECTORCH relativePosn;
	HRESULT hres;
	int newVolume;
	int newPan;
	
	/* find the distance of the sound */
	relativePosn.vx = ActiveSounds[activeIndex].threedeedata.position.vx - Global_VDB_Ptr->VDB_World.vx;
	relativePosn.vy = ActiveSounds[activeIndex].threedeedata.position.vy - Global_VDB_Ptr->VDB_World.vy;
	relativePosn.vz = ActiveSounds[activeIndex].threedeedata.position.vz - Global_VDB_Ptr->VDB_World.vz;
	distance = Magnitude(&relativePosn);

	db_logf5(("Sound Index %i", ActiveSounds[activeIndex].soundIndex));
	db_logf5(("Global Player Posn (%i, %i, %i)",  Global_VDB_Ptr->VDB_World.vx, Global_VDB_Ptr->VDB_World.vy, Global_VDB_Ptr->VDB_World.vz));
	db_logf5(("Sound Posn (%i, %i, %i)",  ActiveSounds[activeIndex].threedeedata.position.vx, ActiveSounds[activeIndex].threedeedata.position.vy, ActiveSounds[activeIndex].threedeedata.position.vz));
	db_logf5(("Relative Posn (%i, %i, %i)",  relativePosn.vx, relativePosn.vy, relativePosn.vz));
	db_logf5(("distance %i", distance));
	db_logf5(("range (%i, %i)", ActiveSounds[activeIndex].threedeedata.inner_range, ActiveSounds[activeIndex].threedeedata.outer_range));

	/* Deal with paused looping sounds. */
	if(ActiveSounds[activeIndex].paused)
	{
		if(distance < (ActiveSounds[activeIndex].threedeedata.outer_range + SOUND_DEACTIVATERANGE))
		{
			DWORD flags = 0;
			GLOBALASSERT (ActiveSounds[activeIndex].dsBufferP);
			if(ActiveSounds[activeIndex].loop)
			{
				flags|= DSBPLAY_LOOPING;
			}
			IDirectSoundBuffer_Play(ActiveSounds[activeIndex].dsBufferP,0,0,flags);
			newVolume = 0;
			ActiveSounds[activeIndex].paused = 0;
		}
		else
		{
			return 1;
		}
	}

	if(distance < ActiveSounds[activeIndex].threedeedata.inner_range)
	{
		newVolume = ActiveSounds[activeIndex].volume;
	}
	else
	{
		if(distance < ActiveSounds[activeIndex].threedeedata.outer_range)
		{
			/* Use proper 3D, but our own attenuation. */
			float in_to_dis_to_out = ActiveSounds[activeIndex].threedeedata.outer_range - distance;
			float in_to_out = ActiveSounds[activeIndex].threedeedata.outer_range - ActiveSounds[activeIndex].threedeedata.inner_range;

			if (in_to_out > 0.0)
			{
				newVolume = (int) 
					((float)ActiveSounds[activeIndex].volume * (in_to_dis_to_out / in_to_out));
			}
			else
			{
				newVolume = 0;
			}
		}
		else
		{
			newVolume = 0;

			/* Deal with looping sounds. */
			if((distance < (ActiveSounds[activeIndex].threedeedata.outer_range + SOUND_DEACTIVATERANGE)) &&
				ActiveSounds[activeIndex].loop)
			{
				hres = IDirectSoundBuffer_Stop(ActiveSounds[activeIndex].dsBufferP);
				if (hres == DS_OK)
				{
					ActiveSounds[activeIndex].paused = 1;
				}
				else
				{
					textprint ("Error stopping sound\n");
				}
			}
		}
	}

	if(newVolume>VOLUME_MAX) newVolume=VOLUME_MAX;
	if(newVolume<VOLUME_MIN) newVolume=VOLUME_MIN;
	
	if(PlatChangeSoundVolume(activeIndex, newVolume) == SOUND_PLATFORMERROR)
	{
		return SOUND_PLATFORMERROR;
	}

	/* Now deal with the panning issues. */
	if(distance < ActiveSounds[activeIndex].threedeedata.outer_range)
	{
		if(ActiveSounds[activeIndex].ds3DBufferP)
		{
			/* Use the Hardware. */
			IDirectSound3DBuffer_SetPosition
				(
					ActiveSounds[activeIndex].ds3DBufferP,
					(D3DVALUE) relativePosn.vx,
					(D3DVALUE) relativePosn.vy,
					(D3DVALUE) relativePosn.vz,
					DS3D_DEFERRED
				);
#if 0
// No doppler for now.
			IDirectSound3DBuffer_SetVelocity
				(
					ActiveSounds[activeIndex].ds3DBufferP,
					(D3DVALUE) ActiveSounds[activeIndex].threedeedata.velocity.vx,
					(D3DVALUE) ActiveSounds[activeIndex].threedeedata.velocity.vy,
					(D3DVALUE) ActiveSounds[activeIndex].threedeedata.velocity.vz,
					DS3D_DEFERRED
				);
#endif
		}
		else
		{
			int angle;
			Normalise(&relativePosn);
			angle = ArcTan(relativePosn.vx,relativePosn.vz);
			if(angle>=Player->ObEuler.EulerY) angle-=Player->ObEuler.EulerY;
			else angle += (4096-Player->ObEuler.EulerY);
			LOCALASSERT((angle>=0)&&(angle<=4095)); 
		
			/* map angle to range +- 1024 */
			if(angle>1024)
			{
				if(angle<=3072) angle = (2048-angle); /*quadrants 2 & 3*/
				else angle = (angle-4096);	  /* quadrant 4 */
			}
			LOCALASSERT((angle>=-1024)&&(angle<=1024));	
			/* now scale pan to angle */
			newPan = (PAN_MAXPLAT*angle)>>10;

			/* now damp pan for close objects, so we don't get such a sharp contrast moving
			through a 3d object. */
			if((distance<ActiveSounds[activeIndex].threedeedata.inner_range)&&(newPan!=0))
			{
				newPan = (newPan*distance)/ActiveSounds[activeIndex].threedeedata.inner_range;
	 		}
	
			if(PlatChangeSoundPan(activeIndex,newPan) == SOUND_PLATFORMERROR)
			{
				db_log3("PlatDo3dSound finished.");
				return SOUND_PLATFORMERROR;
			}
		}
	}

	return 1;
}

void PlatEndGameSound(SOUNDINDEX index)
{
	if((index<0)||(index>=SID_MAXIMUM)) return; /* no such sound */
	LOCALASSERT(GameSounds[index].loaded);
	LOCALASSERT(GameSounds[index].dsBufferP);	
	if(GameSounds[index].dsBufferP)
	{
		IDirectSoundBuffer_Release(GameSounds[index].dsBufferP);
		GameSounds[index].dsBufferP = NULL;	
	}
	GameSounds[index].dsFrequency = 0;	
	GameSounds[index].loaded = 0;	
	if (GameSounds[index].wavName)
	{
		DeallocateMem (GameSounds[index].wavName);
		GameSounds[index].wavName=0;
	}
}

/* Patrick 5/6/97 -------------------------------------------------------------
  Change pan function is internal to this file, since it is only needed for
  doing 3d effects. Consequently, the parameter is not scaled to external
  values, but to platform range. 
  ----------------------------------------------------------------------------*/
static int PlatChangeSoundPan(int activeIndex, int pan)
{
	HRESULT hres;
	LOCALASSERT(ActiveSounds[activeIndex].dsBufferP);

	if(pan>PAN_MAXPLAT) pan=PAN_MAXPLAT;
	if(pan<PAN_MINPLAT) pan=PAN_MINPLAT;

	hres = IDirectSoundBuffer_SetPan(ActiveSounds[activeIndex].dsBufferP,pan);
	if(hres==DS_OK) return 1;	
	else return SOUND_PLATFORMERROR;
	return 1;
}


unsigned int PlatMaxHWSounds()
{
	return SoundMaxHW;
}

/* Patrick 15/6/97 -------------------------------------------------------------
  Post processor for the sound loaders...
  Wavs are recorded at a particular frequency, which is taken as equivalent to
  a base pitch setting of PITCH_DEFAULTPLAT.  However, some wavs need to be
  shifted up or down a number of semi-tones in order to be played at the correct
  pitch... Hence, they are pitch shifted here, as neccessary....      
  ----------------------------------------------------------------------------*/
void InitialiseBaseFrequency(SOUNDINDEX soundNum)
{
	int frequency;
	HRESULT hres;

	/* validate the loaded pitch */
	if(GameSounds[soundNum].pitch>PITCH_MAXPLAT) GameSounds[soundNum].pitch=PITCH_MAXPLAT;
	if(GameSounds[soundNum].pitch<PITCH_MINPLAT) GameSounds[soundNum].pitch=PITCH_MINPLAT;

	/* get and set the loaded frequency */
	hres = IDirectSoundBuffer_GetFrequency(GameSounds[soundNum].dsBufferP,(LPDWORD)&frequency);
	if(hres!=DS_OK)
	{
		/* error */
		LOCALASSERT(1==0);
		PlatEndGameSound(soundNum);
		GameSounds[soundNum] = BlankGameSound;
		return;
	}
	GameSounds[soundNum].dsFrequency = frequency;
	
	/* if the pitch is default, just return at this point */
	if(GameSounds[soundNum].pitch==PITCH_DEFAULTPLAT) return;

	/* otherwise, we have to set a new frequency, for our non-default pitch,
	taking the current frequency as corresponding to the default pitch */
	frequency = ToneToFrequency(GameSounds[soundNum].dsFrequency,
		PITCH_DEFAULTPLAT, GameSounds[soundNum].pitch);
	
	hres = IDirectSoundBuffer_SetFrequency(GameSounds[soundNum].dsBufferP,(DWORD)frequency);
	if(hres!=DS_OK)
	{
		/* error */
		LOCALASSERT(1==0);
		PlatEndGameSound(soundNum);
		GameSounds[soundNum] = BlankGameSound;
		return;
	}
	GameSounds[soundNum].dsFrequency = frequency;
}


/* Patrick 5/6/97 -------------------------------------------------------------
  This function loads a WAV file, and inserts into the game sounds array, with
  any required platform initialistions
  NB should manage to load PCM and Extended WAV files 
  ----------------------------------------------------------------------------*/
int LoadWavFile(int soundNum, char * wavFileName)
{
	PWAVCHUNKHEADER myChunkHeader;
	PWAVRIFFHEADER myRiffHeader;
	FILE *myFile;
	WAVEFORMATEX myWaveFormat;
	size_t res;
	int lengthInSeconds;

	myFile = fopen(wavFileName,"rb");
	if(!myFile)
	{
		GLOBALASSERT (0);
		return(0);
	}

	/* Read the WAV RIFF header */
	res = fread(&myChunkHeader,sizeof(PWAVCHUNKHEADER),1,myFile);
	res = fread(&myRiffHeader,sizeof(PWAVRIFFHEADER),1,myFile);

	/* Read the WAV format chunk */
	res = fread(&myChunkHeader,sizeof(PWAVCHUNKHEADER),1,myFile);
	if(myChunkHeader.chunkLength==16)
	{
		/* a standard PCM wave format chunk */
		PCMWAVEFORMAT tmpWaveFormat;
		res = fread(&tmpWaveFormat,sizeof(PCMWAVEFORMAT),1,myFile);	
		myWaveFormat.wFormatTag = tmpWaveFormat.wf.wFormatTag;        
		myWaveFormat.nChannels = tmpWaveFormat.wf.nChannels;
		myWaveFormat.nSamplesPerSec = tmpWaveFormat.wf.nSamplesPerSec;;
		myWaveFormat.nAvgBytesPerSec = tmpWaveFormat.wf.nAvgBytesPerSec;   
		myWaveFormat.nBlockAlign = tmpWaveFormat.wf.nBlockAlign;
		myWaveFormat.wBitsPerSample = tmpWaveFormat.wBitsPerSample;
		myWaveFormat.cbSize = 0;
	}
	else if(myChunkHeader.chunkLength==18)
	{
		/* an extended PCM wave format chunk */
		res = fread(&myWaveFormat,sizeof(WAVEFORMATEX),1,myFile);	
		myWaveFormat.cbSize = 0;
	}
	else
	{
		/* uh oh: a different chunk type */
		LOCALASSERT(1==0);
		fclose(myFile);
		return 0;
	}

	
	/* Read	the data chunk header */
	//skip chunks until we reach the 'data' chunk
	do
	{
		/* Read	the data chunk header */
		res = fread(&myChunkHeader,sizeof(PWAVCHUNKHEADER),1,myFile);
		if((myChunkHeader.chunkName[0]=='d')&&(myChunkHeader.chunkName[1]=='a')&&
	   		(myChunkHeader.chunkName[2]=='t')&&(myChunkHeader.chunkName[3]=='a'))
		{
			break;
		}
	
		fseek(myFile,myChunkHeader.chunkLength,SEEK_CUR);
	}while(res);

	/* Now do a few checks */
	if((myChunkHeader.chunkName[0]!='d')||(myChunkHeader.chunkName[1]!='a')||
	   (myChunkHeader.chunkName[2]!='t')||(myChunkHeader.chunkName[3]!='a'))
	{
		/* chunk alignment disaster */
		LOCALASSERT(1==0);
		fclose(myFile);
		return 0;	
	}
	
	//calculate length of sample
	lengthInSeconds=DIV_FIXED(myChunkHeader.chunkLength,myWaveFormat.nAvgBytesPerSec);

	if((myChunkHeader.chunkLength<0)||(myChunkHeader.chunkLength > SOUND_MAXSIZE))
	{
		LOCALASSERT(1==0);
		fclose(myFile);
		return 0;	
	}	
	if(myWaveFormat.wFormatTag != WAVE_FORMAT_PCM)
	{
		LOCALASSERT(1==0);
		fclose(myFile);
		return 0;	
	}	
	if((myWaveFormat.nChannels != 1)&&(myWaveFormat.nChannels != 2))
	{
		LOCALASSERT(1==0);
		fclose(myFile);
		return 0;	
	}	
	if((myWaveFormat.wBitsPerSample != 8)&&(myWaveFormat.wBitsPerSample != 16))
	{
		LOCALASSERT(1==0);
		fclose(myFile);
		return 0;	
	}	
		
	{
		/* Now set the buffer description and make a sound object */
		DSBUFFERDESC dsBuffDesc;
		LPDIRECTSOUNDBUFFER sndBuffer;
		HRESULT hres;
		LPVOID audioPtr1;
		DWORD audioBytes1;
		LPVOID audioPtr2;   
		DWORD audioBytes2;

		memset(&dsBuffDesc,0,sizeof(DSBUFFERDESC));
		dsBuffDesc.dwSize = sizeof(DSBUFFERDESC);
		dsBuffDesc.dwFlags = (DSBCAPS_CTRLDEFAULT | DSBCAPS_STATIC);		
		dsBuffDesc.dwBufferBytes = myChunkHeader.chunkLength;
		dsBuffDesc.lpwfxFormat = &myWaveFormat;

		/* Do we need to specify 3D. */
		if(SoundConfig.flags & SOUND_3DHW)
		{
			dsBuffDesc.dwFlags |= DSBCAPS_CTRL3D;
		}

		/* If we have no Voice Manager support we must leave some hardware buffers free. */
		if(SoundConfig.flags & SOUND_VOICE_MGER)
		{
			// Do nothing for the moment.
		}
		else
		{
			/* No Voice Manager. */
			DSCAPS caps;
			ZeroMemory(&caps, sizeof(DSCAPS));
			caps.dwSize = sizeof(DSCAPS);

			IDirectSound_GetCaps(DSObject, &caps);
			db_logf5(("caps.dwFreeHwMixingStaticBuffers %i SoundMinBufferFree %i",caps.dwFreeHwMixingStaticBuffers, SoundMinBufferFree));
			if(caps.dwFreeHwMixingStaticBuffers < SoundMinBufferFree)
			{
				/* Force to software. */
				db_log3("Forcing buffer to software.");
				dsBuffDesc.dwFlags |= DSBCAPS_LOCSOFTWARE;
			}
		}

		/* Create the Direct Sound buffer for this sound */
		hres = IDirectSound_CreateSoundBuffer(DSObject,&dsBuffDesc,&sndBuffer,NULL); 
		if(hres != DS_OK)
		{
			LOCALASSERT(1==0);
			fclose(myFile);
			return 0;
		}

		/* Lock the buffer to allow the write */
		hres = IDirectSoundBuffer_Lock(sndBuffer,0,myChunkHeader.chunkLength,
			&audioPtr1,&audioBytes1,&audioPtr2,&audioBytes2,0); 
		if((hres!=DS_OK)||(audioPtr2 != NULL))
		{
			LOCALASSERT(1==0);
			IDirectSoundBuffer_Release(sndBuffer);		
			fclose(myFile);
			return 0;
		}
		
		/* Read data from file to buffer */
		res = fread(audioPtr1,1,myChunkHeader.chunkLength,myFile);
		if(res != (size_t)myChunkHeader.chunkLength)
		{
			LOCALASSERT(1==0);
			IDirectSoundBuffer_Release(sndBuffer);		
			fclose(myFile);
			return 0;
		}
		/* then unlock it and close the file */
		hres = IDirectSoundBuffer_Unlock(sndBuffer,audioPtr1,audioBytes1,audioPtr2,audioBytes2);
		if (hres!=DS_OK)
		{
			LOCALASSERT(1==0);
			IDirectSoundBuffer_Release(sndBuffer);		
			fclose(myFile);
			return 0;
		}
		/* Finally, put a pointer the the buffer into the sound data */
		GameSounds[soundNum].dsBufferP = sndBuffer;
		{
			char * wavname = strrchr (wavFileName, '\\');
			if (wavname)
			{
				wavname ++;
			}
			else
			{
				wavname = wavFileName;
			}
			
			GameSounds[soundNum].wavName = (char *)AllocateMem (strlen (wavname) + 1);
			strcpy (GameSounds[soundNum].wavName, wavname);
		}

		/* Log it's position. */
		{
			DSBCAPS caps;
			ZeroMemory(&caps, sizeof(DSBCAPS));
			caps.dwSize = sizeof(DSBCAPS);
			IDirectSoundBuffer_GetCaps(sndBuffer, &caps);
			
			if(caps.dwFlags & DSBCAPS_LOCHARDWARE)
			{
				GameSounds[soundNum].flags = SAMPLE_IN_HW;
				db_logf3(("Sound %s loaded into hardware slot %i by LoadWavFile.", GameSounds[soundNum].wavName, soundNum));
			}
			else
			{
				GameSounds[soundNum].flags = SAMPLE_IN_SW;
				db_logf3(("Sound %s loaded into software slot %i by LoadWavFile.", GameSounds[soundNum].wavName, soundNum));
			}
		}
		GameSounds[soundNum].length=lengthInSeconds;
	}

	fclose(myFile);
    return 1;
}
/*identical to above function except it loads from fast files*/
int LoadWavFromFastFile(int soundNum, char * wavFileName)
{
	PWAVCHUNKHEADER myChunkHeader;
	PWAVRIFFHEADER myRiffHeader;
	FFILE *myFile;
	WAVEFORMATEX myWaveFormat;
	size_t res;
	int lengthInSeconds;

	myFile = ffopen(wavFileName,"rb");
	if(!myFile)
	{
		GLOBALASSERT (0);
		return(0);
	}

	/* Read the WAV RIFF header */
	res = ffread(&myChunkHeader,sizeof(PWAVCHUNKHEADER),1,myFile);
	res = ffread(&myRiffHeader,sizeof(PWAVRIFFHEADER),1,myFile);

	/* Read the WAV format chunk */
	res = ffread(&myChunkHeader,sizeof(PWAVCHUNKHEADER),1,myFile);
	if(myChunkHeader.chunkLength==16)
	{
		/* a standard PCM wave format chunk */
		PCMWAVEFORMAT tmpWaveFormat;
		res = ffread(&tmpWaveFormat,sizeof(PCMWAVEFORMAT),1,myFile);	
		myWaveFormat.wFormatTag = tmpWaveFormat.wf.wFormatTag;        
		myWaveFormat.nChannels = tmpWaveFormat.wf.nChannels;
		myWaveFormat.nSamplesPerSec = tmpWaveFormat.wf.nSamplesPerSec;;
		myWaveFormat.nAvgBytesPerSec = tmpWaveFormat.wf.nAvgBytesPerSec;   
		myWaveFormat.nBlockAlign = tmpWaveFormat.wf.nBlockAlign;
		myWaveFormat.wBitsPerSample = tmpWaveFormat.wBitsPerSample;
		myWaveFormat.cbSize = 0;
	}
	else if(myChunkHeader.chunkLength==18)
	{
		/* an extended PCM wave format chunk */
		res = ffread(&myWaveFormat,sizeof(WAVEFORMATEX),1,myFile);	
		myWaveFormat.cbSize = 0;
	}
	else
	{
		/* uh oh: a different chunk type */
		LOCALASSERT(1==0);
		ffclose(myFile);
		return 0;
	}

	/* Read	the data chunk header */
	//skip chunks until we reach the 'data' chunk
	do
	{
		/* Read	the data chunk header */
		res = ffread(&myChunkHeader,sizeof(PWAVCHUNKHEADER),1,myFile);
		if((myChunkHeader.chunkName[0]=='d')&&(myChunkHeader.chunkName[1]=='a')&&
	   		(myChunkHeader.chunkName[2]=='t')&&(myChunkHeader.chunkName[3]=='a'))
		{
			break;
		}
	
		ffseek(myFile,myChunkHeader.chunkLength,SEEK_CUR);
	}while(res);

	/* Now do a few checks */
	if((myChunkHeader.chunkName[0]!='d')||(myChunkHeader.chunkName[1]!='a')||
	   (myChunkHeader.chunkName[2]!='t')||(myChunkHeader.chunkName[3]!='a'))
	{
		/* chunk alignment disaster */
		LOCALASSERT(1==0);
		ffclose(myFile);
		return 0;	
	}
	
	//calculate length of sample
	lengthInSeconds=DIV_FIXED(myChunkHeader.chunkLength,myWaveFormat.nAvgBytesPerSec);

	if((myChunkHeader.chunkLength<0)||(myChunkHeader.chunkLength > SOUND_MAXSIZE))
	{
		LOCALASSERT(1==0);
		ffclose(myFile);
		return 0;	
	}	
	if(myWaveFormat.wFormatTag != WAVE_FORMAT_PCM)
	{
		LOCALASSERT(1==0);
		ffclose(myFile);
		return 0;	
	}	
	if((myWaveFormat.nChannels != 1)&&(myWaveFormat.nChannels != 2))
	{
		LOCALASSERT(1==0);
		ffclose(myFile);
		return 0;	
	}	
	if((myWaveFormat.wBitsPerSample != 8)&&(myWaveFormat.wBitsPerSample != 16))
	{
		LOCALASSERT(1==0);
		ffclose(myFile);
		return 0;	
	}	
		
	{
		/* Now set the buffer description and make a sound object */
		DSBUFFERDESC dsBuffDesc;
		LPDIRECTSOUNDBUFFER sndBuffer;
		HRESULT hres;
		LPVOID audioPtr1;
		DWORD audioBytes1;
		LPVOID audioPtr2;   
		DWORD audioBytes2;

		memset(&dsBuffDesc,0,sizeof(DSBUFFERDESC));
		dsBuffDesc.dwSize = sizeof(DSBUFFERDESC);
		dsBuffDesc.dwFlags = (DSBCAPS_CTRLDEFAULT | DSBCAPS_STATIC);		
		dsBuffDesc.dwBufferBytes = myChunkHeader.chunkLength;
		dsBuffDesc.lpwfxFormat = &myWaveFormat;

		/* Do we need to specify 3D. */
		if(SoundConfig.flags & SOUND_3DHW)
		{
			dsBuffDesc.dwFlags |= DSBCAPS_CTRL3D;
		}

		/* If we have no Voice Manager support we must leave some hardware buffers free. */
		if(SoundConfig.flags & SOUND_VOICE_MGER)
		{
			// Do nothing for the moment.
		}
		else
		{
			/* No Voice Manager. */
			DSCAPS caps;
			ZeroMemory(&caps, sizeof(DSCAPS));
			caps.dwSize = sizeof(DSCAPS);

			IDirectSound_GetCaps(DSObject, &caps);
			db_logf5(("caps.dwFreeHwMixingStaticBuffers %i SoundMinBufferFree %i",caps.dwFreeHwMixingStaticBuffers, SoundMinBufferFree));
			if(caps.dwFreeHwMixingStaticBuffers < SoundMinBufferFree)
			{
				/* Force to software. */
				db_log3("Forcing buffer to software.");
				dsBuffDesc.dwFlags |= DSBCAPS_LOCSOFTWARE;
			}
		}

		/* Create the Direct Sound buffer for this sound */
		hres = IDirectSound_CreateSoundBuffer(DSObject,&dsBuffDesc,&sndBuffer,NULL); 
		if(hres != DS_OK)
		{
			LOCALASSERT(1==0);
			ffclose(myFile);
			return 0;
		}

		/* Lock the buffer to allow the write */
		hres = IDirectSoundBuffer_Lock(sndBuffer,0,myChunkHeader.chunkLength,
			&audioPtr1,&audioBytes1,&audioPtr2,&audioBytes2,0); 
		if((hres!=DS_OK)||(audioPtr2 != NULL))
		{
			LOCALASSERT(1==0);
			IDirectSoundBuffer_Release(sndBuffer);		
			ffclose(myFile);
			return 0;
		}
		
		/* Read data from file to buffer */
		res = ffread(audioPtr1,1,myChunkHeader.chunkLength,myFile);
		if(res != (size_t)myChunkHeader.chunkLength)
		{
			LOCALASSERT(1==0);
			IDirectSoundBuffer_Release(sndBuffer);		
			ffclose(myFile);
			return 0;
		}
		/* then unlock it and close the file */
		hres = IDirectSoundBuffer_Unlock(sndBuffer,audioPtr1,audioBytes1,audioPtr2,audioBytes2);
		if (hres!=DS_OK)
		{
			LOCALASSERT(1==0);
			IDirectSoundBuffer_Release(sndBuffer);		
			ffclose(myFile);
			return 0;
		}
		/* Finally, put a pointer the the buffer into the sound data */
		GameSounds[soundNum].dsBufferP = sndBuffer;
		{
			char * wavname = strrchr (wavFileName, '\\');
			if (wavname)
			{
				wavname ++;
			}
			else
			{
				wavname = wavFileName;
			}
			
			GameSounds[soundNum].wavName = (char *)AllocateMem (strlen (wavname) + 1);
			strcpy (GameSounds[soundNum].wavName, wavname);
		}

		/* Log it's position. */
		{
			DSBCAPS caps;
			ZeroMemory(&caps, sizeof(DSBCAPS));
			caps.dwSize = sizeof(DSBCAPS);
			IDirectSoundBuffer_GetCaps(sndBuffer, &caps);
			
			if(caps.dwFlags & DSBCAPS_LOCHARDWARE)
			{
				GameSounds[soundNum].flags = SAMPLE_IN_HW;
				db_logf3(("Sound %s loaded into hardware slot %i by LoadWavFromFastFile.", GameSounds[soundNum].wavName, soundNum));
			}
			else
			{
				GameSounds[soundNum].flags = SAMPLE_IN_SW;
				db_logf3(("Sound %s loaded into software slot %i by LoadWavFromFastFile.", GameSounds[soundNum].wavName, soundNum));
			}
		}
		GameSounds[soundNum].length=lengthInSeconds;
	}

	ffclose(myFile);
    return 1;
}

/* Patrick 13/6/97 -------------------------------------------------------------
  Stuff for converting pitch semi-tones into frequencies:
  The common sound interface in PSND uses 1/128ths of a semi-tone increments to 
  change sounds (like the PSX) however, DS uses frequency shifts. We must therefore 
  convert semi-tone shifts into frequency shifts. The conversion formula is:
  f = f0 * 2^(P-P0)
  ----------------------------------------------------------------------------*/
static int ToneToFrequency(int currentFrequency, int currentPitch, int newPitch)
{
	int newFrequency = currentFrequency;

	LOCALASSERT((currentPitch>=PITCH_MINPLAT)&&(currentPitch<=PITCH_MAXPLAT));
	LOCALASSERT((currentFrequency>=FREQUENCY_MINPLAT)&&(currentPitch<=FREQUENCY_MAXPLAT));

	/* limit pitch */
	if(newPitch>PITCH_MAXPLAT) newPitch=PITCH_MAXPLAT;
	if(newPitch<PITCH_MINPLAT) newPitch=PITCH_MINPLAT;

	if(newPitch>currentPitch)
	{
		/* scale up */		
		int numOctaves, numTones;
  	 	numOctaves = (newPitch-currentPitch)/1536;
		numTones = (newPitch-currentPitch)%1536;

		newFrequency<<=numOctaves;
		if(newFrequency>FREQUENCY_MAXPLAT) newFrequency=FREQUENCY_MAXPLAT;
		
		if(numTones>0) newFrequency = (int)((float)(newFrequency)*pitch_to_frequency_mult_table[numTones]);
		if(newFrequency>FREQUENCY_MAXPLAT) newFrequency=FREQUENCY_MAXPLAT;
	}
	else
	{
		/* scale down */
		int numOctaves, numTones;
  	 	numOctaves = (currentPitch-newPitch)/1536;
		numTones = (currentPitch-newPitch)%1536;

		newFrequency>>=numOctaves;
	 	if(newFrequency<FREQUENCY_MINPLAT) newFrequency=FREQUENCY_MINPLAT;
		
		if(numTones>0) newFrequency = (int)((float)(newFrequency)/pitch_to_frequency_mult_table[numTones]);
		if(newFrequency<FREQUENCY_MINPLAT) newFrequency=FREQUENCY_MINPLAT;
	}
	return newFrequency;
} 

void PlatUpdatePlayer()
{
#if 0
	IDirectSound3DListener_SetPosition
		(
			DS3DListener,
			(D3DVALUE) Global_VDB_Ptr->VDB_World.vx,
			(D3DVALUE) Global_VDB_Ptr->VDB_World.vy,
			(D3DVALUE) Global_VDB_Ptr->VDB_World.vz,
			DS3D_DEFERRED
		);
#endif
	if (Global_VDB_Ptr)
	{
		extern int NormalFrameTime;
		extern int DopplerShiftIsOn;

		if(AvP.PlayerType != I_Alien)
		{
			IDirectSound3DListener_SetOrientation
				(
					DS3DListener,
					(D3DVALUE) (float) ((Global_VDB_Ptr->VDB_Mat.mat13) / 65536.0F),
					(D3DVALUE) 0,
					(D3DVALUE) (float) ((Global_VDB_Ptr->VDB_Mat.mat33) / 65536.0F),
					(D3DVALUE) 0,
					(D3DVALUE) 1,
					(D3DVALUE) 0,
					DS3D_DEFERRED
				);
		}
		else
		{
			IDirectSound3DListener_SetOrientation
				(
					DS3DListener,
					(D3DVALUE) (float) ((Global_VDB_Ptr->VDB_Mat.mat13) / 65536.0F),
					(D3DVALUE) (float) ((Global_VDB_Ptr->VDB_Mat.mat23) / 65536.0F),
					(D3DVALUE) (float) ((Global_VDB_Ptr->VDB_Mat.mat33) / 65536.0F),
					(D3DVALUE) (float) ((Global_VDB_Ptr->VDB_Mat.mat12) / 65536.0F),
					(D3DVALUE) (float) ((Global_VDB_Ptr->VDB_Mat.mat22) / 65536.0F),
					(D3DVALUE) (float) ((Global_VDB_Ptr->VDB_Mat.mat32) / 65536.0F),
					DS3D_DEFERRED
				);
		}

		if (AvP.PlayerType == I_Alien && DopplerShiftIsOn && NormalFrameTime)
		{
			DYNAMICSBLOCK *dynPtr=Player->ObStrategyBlock->DynPtr;
			float vx,vy,vz;
			float invFrameTime = 100000.0f/(float)NormalFrameTime;

			vx = (float)(dynPtr->Position.vx - dynPtr->PrevPosition.vx)*invFrameTime;
			vy = (float)(dynPtr->Position.vy - dynPtr->PrevPosition.vy)*invFrameTime;
			vz = (float)(dynPtr->Position.vz - dynPtr->PrevPosition.vz)*invFrameTime;
			
		
			IDirectSound3DListener_SetVelocity
				(
					DS3DListener,
					vx,vy,vz,
					DS3D_DEFERRED
				);
		}
		else
		{
			IDirectSound3DListener_SetVelocity
				(
					DS3DListener,
					0.0f,0.0f,0.0f,
					DS3D_DEFERRED
				);

		}
	}

	if(SoundConfig.reverb_changed)
	{
		unsigned int count = SoundMaxHW;

		// Go through every sound setting the reverb
		while(count--)
		{
		   	if(ActiveSounds[count].PropSetP)
	 	  	{
				HRESULT res;
				if(!ActiveSounds[count].reverb_off)
				{
					res = IKsPropertySet_Set
					(
						ActiveSounds[count].PropSetP,
						&DSPROPSETID_EAXBUFFER_ReverbProperties,
				        DSPROPERTY_EAXBUFFER_REVERBMIX,
				        NULL,
				        0,
				        &SoundConfig.reverb_mix,
			    	    sizeof(float)
					);
				}
				else
				{
					float temp = 0;
					res = IKsPropertySet_Set
					(
						ActiveSounds[count].PropSetP,
						&DSPROPSETID_EAXBUFFER_ReverbProperties,
				        DSPROPERTY_EAXBUFFER_REVERBMIX,
				        NULL,
				        0,
				        &temp,
			    	    sizeof(float)
					);
				}

				if(res != DD_OK)
				{
					db_logf3(("Error: Failed to set the property set. %x", res));
				}
			}
		}
		SoundConfig.reverb_changed = FALSE;
	}

	IDirectSound3DListener_CommitDeferredSettings(DS3DListener);
}

void PlatSetEnviroment(unsigned int env_index, float reverb_mix)
{
	HRESULT res;

	if(~SoundConfig.flags & SOUND_EAX)
	{
		return;
	}

	db_assert3(env_index < EAX_MAX);
	db_assert3(PropSetP);

	/* Set up the enviroment. */
	if(SoundConfig.env_index != env_index)
	{
		res = IKsPropertySet_Set
		(
			PropSetP,
			&DSPROPSETID_EAX_ReverbProperties,
        	DSPROPERTY_EAX_ALL,
	        NULL,
    	    0,
        	&Sound_Enviroments[env_index],
	        sizeof(EAX_REVERBPROPERTIES)
		);

		SoundConfig.env_index = env_index;

		db_logf3(("Set the Enviroment to %i", env_index));

		if(res != DD_OK)
		{
			db_logf3(("Error: Failed to set the enviroment. %x", res));
		}
	}

	if(reverb_mix == SoundConfig.reverb_mix)
	{
		return;
	}

	if((reverb_mix < 0.0F) || (reverb_mix > 1.0F))
	{
		db_log3("Using EAX,");
		SoundConfig.reverb_mix = EAX_REVERBMIX_USEDISTANCE;	
	}
	else
	{
		db_log3("Using reverb_mix,");
		SoundConfig.reverb_mix = reverb_mix;
	}

	SoundConfig.reverb_changed = TRUE;
}




#define RebSndRead(dest,size,n,src)\
{\
	unsigned char *d = (unsigned char*)(dest);\
	int i = (n)*(size);\
	do\
	{\
		*d++ = *(src)++;\
	}\
	while(--i);\
}

/* KJL 17:06:46 01/09/98 - ExtractWavFile does basically the same job as LoadWavFile,
except that it takes data from a memory buffer, rather than through file access. */
extern unsigned char *ExtractWavFile(int soundIndex, unsigned char *bufferPtr)
{
	PWAVCHUNKHEADER myChunkHeader;
	PWAVRIFFHEADER myRiffHeader;
	WAVEFORMATEX myWaveFormat;
	unsigned char *endOfBufferPtr;   
	int lengthInSeconds;

	{
		int length = strlen (bufferPtr) + 1;
		GameSounds[soundIndex].wavName = (char *)AllocateMem (length);
		strcpy (GameSounds[soundIndex].wavName, bufferPtr);
		bufferPtr += length;
	}

	/* Read the WAV RIFF header */
	RebSndRead(&myChunkHeader,sizeof(PWAVCHUNKHEADER),1,bufferPtr);
	endOfBufferPtr = bufferPtr+myChunkHeader.chunkLength;

	RebSndRead(&myRiffHeader,sizeof(PWAVRIFFHEADER),1,bufferPtr);

	/* Read the WAV format chunk */
	RebSndRead(&myChunkHeader,sizeof(PWAVCHUNKHEADER),1,bufferPtr);
	if(myChunkHeader.chunkLength==16)
	{
		/* a standard PCM wave format chunk */
		PCMWAVEFORMAT tmpWaveFormat;
		RebSndRead(&tmpWaveFormat,sizeof(PCMWAVEFORMAT),1,bufferPtr);	
		myWaveFormat.wFormatTag = tmpWaveFormat.wf.wFormatTag;        
		myWaveFormat.nChannels = tmpWaveFormat.wf.nChannels;
		myWaveFormat.nSamplesPerSec = tmpWaveFormat.wf.nSamplesPerSec;;
		myWaveFormat.nAvgBytesPerSec = tmpWaveFormat.wf.nAvgBytesPerSec;   
		myWaveFormat.nBlockAlign = tmpWaveFormat.wf.nBlockAlign;
		myWaveFormat.wBitsPerSample = tmpWaveFormat.wBitsPerSample;
		myWaveFormat.cbSize = 0;
	}
	else if(myChunkHeader.chunkLength==18)
	{
		/* an extended PCM wave format chunk */
		RebSndRead(&myWaveFormat,sizeof(WAVEFORMATEX),1,bufferPtr);	
		myWaveFormat.cbSize = 0;
	}
	else
	{
		/* uh oh: a different chunk type */
		LOCALASSERT(1==0);
		return 0;
	}

	/* Read	the data chunk header */
	//skip chunks until we reach the 'data' chunk
	do
	{
		/* Read	the data chunk header */
		RebSndRead(&myChunkHeader,sizeof(PWAVCHUNKHEADER),1,bufferPtr);
		if((myChunkHeader.chunkName[0]=='d')&&(myChunkHeader.chunkName[1]=='a')&&
	   		(myChunkHeader.chunkName[2]=='t')&&(myChunkHeader.chunkName[3]=='a'))
		{
			break;
		}
		//skip to next chunk
		bufferPtr+=myChunkHeader.chunkLength;
	}while(TRUE);

	/* Now do a few checks */
	if((myChunkHeader.chunkName[0]!='d')||(myChunkHeader.chunkName[1]!='a')||
	   (myChunkHeader.chunkName[2]!='t')||(myChunkHeader.chunkName[3]!='a'))
	{
		/* chunk alignment disaster */
		LOCALASSERT(1==0);
		return 0;	
	}
	
	//calculate length of sample
	lengthInSeconds=DIV_FIXED(myChunkHeader.chunkLength,myWaveFormat.nAvgBytesPerSec);
	
	if((myChunkHeader.chunkLength<0)||(myChunkHeader.chunkLength > SOUND_MAXSIZE))
	{
		LOCALASSERT(1==0);
		return 0;	
	}	
	if(myWaveFormat.wFormatTag != WAVE_FORMAT_PCM)
	{
		LOCALASSERT(1==0);
		return 0;	
	}	
	if((myWaveFormat.nChannels != 1)&&(myWaveFormat.nChannels != 2))
	{
		LOCALASSERT(1==0);
		return 0;	
	}	
	if((myWaveFormat.wBitsPerSample != 8)&&(myWaveFormat.wBitsPerSample != 16))
	{
		LOCALASSERT(1==0);
		return 0;	
	}	
		
	{
		/* Now set the buffer description and make a sound object */
		DSBUFFERDESC dsBuffDesc;
		LPDIRECTSOUNDBUFFER sndBuffer;
		HRESULT hres;
		LPVOID audioPtr1;
		DWORD audioBytes1;
		LPVOID audioPtr2;   
		DWORD audioBytes2;

		memset(&dsBuffDesc,0,sizeof(DSBUFFERDESC));
		dsBuffDesc.dwSize = sizeof(DSBUFFERDESC);
		dsBuffDesc.dwFlags = (DSBCAPS_CTRLDEFAULT | DSBCAPS_STATIC);		
		dsBuffDesc.dwBufferBytes = myChunkHeader.chunkLength;
		dsBuffDesc.lpwfxFormat = &myWaveFormat;

		/* Do we need to specify 3D. */
		if(SoundConfig.flags & SOUND_3DHW)
		{
			dsBuffDesc.dwFlags |= DSBCAPS_CTRL3D;
		}

		/* If we have no Voice Manager support we must leave some hardware buffers free. */
		if(SoundConfig.flags & SOUND_VOICE_MGER)
		{
			// Do nothing for the moment.
		}
		else
		{
			/* No Voice Manager. */
			DSCAPS caps;
			ZeroMemory(&caps, sizeof(DSCAPS));
			caps.dwSize = sizeof(DSCAPS);

			IDirectSound_GetCaps(DSObject, &caps);
			db_logf5(("caps.dwFreeHwMixingStaticBuffers %i SoundMinBufferFree %i",caps.dwFreeHwMixingStaticBuffers, SoundMinBufferFree));
			if(caps.dwFreeHwMixingStaticBuffers < SoundMinBufferFree)
			{
				/* Force to software. */
				db_log3("Forcing buffer to software.");
				dsBuffDesc.dwFlags |= DSBCAPS_LOCSOFTWARE;
			}
		}

		/* Create the Direct Sound buffer for this sound */
		hres = IDirectSound_CreateSoundBuffer(DSObject,&dsBuffDesc,&sndBuffer,NULL); 
		if(hres != DS_OK)
		{
			LOCALASSERT(1==0);
			return 0;
		}

		/* Lock the buffer to allow the write */
		hres = IDirectSoundBuffer_Lock(sndBuffer,0,myChunkHeader.chunkLength,
			&audioPtr1,&audioBytes1,&audioPtr2,&audioBytes2,0); 
		if((hres!=DS_OK)||(audioPtr2 != NULL))
		{
			LOCALASSERT(1==0);
			IDirectSoundBuffer_Release(sndBuffer);		
			return 0;
		}
		
		/* Read data from file to buffer */
		RebSndRead(audioPtr1,1,myChunkHeader.chunkLength,bufferPtr);
		#if 0
		if(res != (size_t)myChunkHeader.chunkLength)
		{
			LOCALASSERT(1==0);
			IDirectSoundBuffer_Release(sndBuffer);		
			return 0;
		}
		#endif
		/* then unlock it and close the file */
		hres = IDirectSoundBuffer_Unlock(sndBuffer,audioPtr1,audioBytes1,audioPtr2,audioBytes2);
		if (hres!=DS_OK)
		{
			LOCALASSERT(1==0);
			IDirectSoundBuffer_Release(sndBuffer);		
			return 0;
		}
		/* Finally, put a pointer the the buffer into the sound data */
		GameSounds[soundIndex].dsBufferP = sndBuffer;

		/* Log it's position. */
		{
			DSBCAPS caps;
			ZeroMemory(&caps, sizeof(DSBCAPS));
			caps.dwSize = sizeof(DSBCAPS);
			IDirectSoundBuffer_GetCaps(sndBuffer, &caps);
			
			if(caps.dwFlags & DSBCAPS_LOCHARDWARE)
			{
				GameSounds[soundIndex].flags = SAMPLE_IN_HW;
				db_logf3(("Sound %s loaded into hardware slot %i by ExtractWavFile.", GameSounds[soundIndex].wavName, soundIndex));
			}
			else
			{
				GameSounds[soundIndex].flags = SAMPLE_IN_SW;
				db_logf3(("Sound %s loaded into software slot %i by ExtractWavFile.", GameSounds[soundIndex].wavName, soundIndex));
			}
		}
		GameSounds[soundIndex].length=lengthInSeconds;
	}

    return endOfBufferPtr;
}

int PlatUse3DSoundHW()
{
	unsigned int count = SoundMaxHW;

	if(SoundConfig.flags & SOUND_USE_3DHW)
	{
		db_log1("Sound system already using 3DHW.");
		return 2;
	}

	if(~SoundConfig.flags & SOUND_3DHW)
	{
		db_log1("Sound system does not have any 3DHW to use.");
		return -1;
	}

	SoundConfig.flags |= SOUND_USE_3DHW;

	// Go through and get 3DBuffers for all active sounds.
	while(count--)
	{
	   	if(ActiveSounds[count].dsBufferP)
 	  	{
			HRESULT hres = IDirectSoundBuffer_QueryInterface
				(
					ActiveSounds[count].dsBufferP,
					&IID_IDirectSound3DBuffer,
					&ActiveSounds[count].ds3DBufferP
				);

			if(hres != DD_OK)
			{
				db_logf3(("Error: Failed to get a DirectSound3DBuffer. res %x", hres));
			}
	   	}
	}

	return 1;
}

int PlatDontUse3DSoundHW()
{
	unsigned int count = SoundMaxHW;

	if(~SoundConfig.flags & SOUND_USE_3DHW)
	{
		db_log1("Sound system already not using 3DHW.");
		return 2;
	}

	SoundConfig.flags &= ~SOUND_USE_3DHW;

	// Go through and release 3DBuffers for all active sounds.
	while(count--)
	{
	   	if(ActiveSounds[count].ds3DBufferP)
 	  	{
			IDirectSound3DBuffer_Release(ActiveSounds[count].ds3DBufferP);
			ActiveSounds[count].ds3DBufferP = NULL;
	   	}
	}

	return 1;
}
#if 1
void UpdateSoundFrequencies(void)
{
	extern int SoundSwitchedOn;
	extern int TimeScale;
	int i;

	if(!SoundSwitchedOn) return;

	for(i=0;i<SOUND_MAXACTIVE;i++)
	{
		int gameIndex = ActiveSounds[i].soundIndex;

		if (gameIndex==SID_NOSOUND) continue;

		IDirectSoundBuffer_SetFrequency(ActiveSounds[i].dsBufferP,MUL_FIXED(GameSounds[gameIndex].dsFrequency,TimeScale));
		if(ActiveSounds[i].pitch != GameSounds[gameIndex].pitch)
		{
			PlatChangeSoundPitch(i,ActiveSounds[i].pitch);
		}
	}
}
#endif
