diff --git a/docs/progress.svg b/docs/progress.svg
index 209628c0..f23e1153 100644
--- a/docs/progress.svg
+++ b/docs/progress.svg
@@ -69,10 +69,10 @@
Tomb2.exe progress according to the physical function order:
-2.33% (28) · 95.25% (1143) · 0.67% (8) · 1.75% (21)
+5.42% (65) · 92.17% (1106) · 0.67% (8) · 1.75% (21)
-
-
+
+
@@ -319,7 +319,7 @@
void __cdecl BigEelControl(int16_t item_num);
void __cdecl EelControl(int16_t item_num);
int32_t __cdecl ItemNearLara(struct PHD_3DPOS *pos, int32_t distance);
-void __cdecl SoundEffects(void);
+void __cdecl Sound_Update(void);
int16_t __cdecl DoBloodSplat(int32_t x, int32_t y, int32_t z, int16_t speed, PHD_ANGLE direction, int16_t room_num);
void __cdecl DoLotsOfBlood(int32_t x, int32_t y, int32_t z, int16_t speed, PHD_ANGLE direction, int16_t room_num, int32_t num);
void __cdecl ControlBlood1(int16_t fx_num);
@@ -916,10 +916,10 @@
HRESULT __stdcall EnumDisplayModesCallback(LPDDSDESC lpDDSurfaceDesc, LPVOID lpContext);
bool __cdecl WinVidInit(void);
bool __cdecl WinVidGetDisplayAdapters(void);
-void __thiscall FlaggedStringDelete(struct STRING_FLAGGED *item);
+void __thiscall FlaggedStringDelete(struct STRING_FLAGGED *item);
bool __cdecl EnumerateDisplayAdapters(struct DISPLAY_ADAPTER_LIST *displayAdapterList);
BOOL __stdcall EnumDisplayAdaptersCallback(GUID *lpGUID, LPTSTR lpDriverDescription, LPTSTR lpDriverName, LPVOID lpContext);
-void __thiscall FlaggedStringsCreate(struct DISPLAY_ADAPTER *adapter);
+void __thiscall FlaggedStringsCreate(struct DISPLAY_ADAPTER *adapter);
bool __cdecl WinVidRegisterGameWindowClass(void);
LRESULT __stdcall WinVidGameWindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
void __cdecl WinVidResizeGameWindow(HWND hWnd, int32_t edge, LPRECT rect);
@@ -949,7 +949,7 @@
bool __cdecl WinInputInit(void);
bool __cdecl DInputEnumDevices(JOYSTICK_LIST *joystickList);
BOOL __stdcall DInputEnumDevicesCallback(LPCDIDEVICEINSTANCE lpddi, LPVOID pvRef);
-void __thiscall FlaggedStringCreate(struct STRING_FLAGGED *item, DWORD dwSize);
+void __thiscall FlaggedStringCreate(struct STRING_FLAGGED *item, DWORD dwSize);
JOYSTICK_NODE *__cdecl GetJoystick(GUID *lpGuid);
void __cdecl DInputKeyboardCreate(void);
void __cdecl DInputKeyboardRelease(void);
@@ -970,24 +970,24 @@
sub_447B30
sub_447B40
sub_447B90
-SOUND_ADAPTER_NODE *__cdecl GetSoundAdapter(GUID *lpGuid);
-void __cdecl WinSndFreeAllSamples(void);
-bool __cdecl WinSndMakeSample(DWORD sampleIdx, LPWAVEFORMATEX format, const LPVOID data, DWORD dataSize);
-bool __cdecl WinSndIsChannelPlaying(DWORD channel);
-int32_t __cdecl WinSndPlaySample(DWORD sampleIdx, int32_t volume, DWORD pitch, int32_t pan, DWORD flags);
-int32_t __cdecl WinSndGetFreeChannelIndex(void);
-void __cdecl WinSndAdjustVolumeAndPan(int32_t channel, int32_t volume, int32_t pan);
-void __cdecl WinSndAdjustPitch(int32_t channel, DWORD pitch);
-void __cdecl WinSndStopSample(int32_t channel);
+struct SOUND_ADAPTER_NODE *__cdecl S_Audio_Sample_GetAdapter(GUID *guid);
+void __cdecl S_Audio_Sample_CloseAllTracks(void);
+bool __cdecl S_Audio_Sample_Load(int32_t sample_id, LPWAVEFORMATEX format, const void *data, int32_t data_size);
+bool __cdecl S_Audio_Sample_IsTrackPlaying(int32_t track_id);
+int32_t __cdecl S_Audio_Sample_Play(int32_t sample_id, int32_t volume, int32_t pitch, int32_t pan, int32_t flags);
+int32_t __cdecl S_Audio_Sample_GetFreeTrackIndex(void);
+void __cdecl S_Audio_Sample_AdjustTrackVolumeAndPan(int32_t track_id, int32_t volume, int32_t pan);
+void __cdecl S_Audio_Sample_AdjustTrackPitch(int32_t track_id, int32_t pitch);
+void __cdecl S_Audio_Sample_CloseTrack(int32_t track_id);
sub_447FA0
-bool __cdecl WinSndInit(void);
-bool __cdecl DSoundEnumerate(SOUND_ADAPTER_LIST *adapterList);
-BOOL __stdcall DSoundEnumCallback(LPGUID lpGuid, LPCTSTR lpcstrDescription, LPCTSTR lpcstrModule, LPVOID lpContext);
-void __cdecl WinSndStart(HWND hWnd);
-bool __cdecl DSoundCreate(GUID *lpGuid);
-bool __cdecl DSoundBufferTest(void);
-void __cdecl WinSndFinish(void);
-bool __cdecl WinSndIsSoundEnabled(void);
+bool __cdecl S_Audio_Sample_Init(void);
+bool __cdecl S_Audio_Sample_DSoundEnumerate(struct SOUND_ADAPTER_LIST *adapter_list);
+BOOL __stdcall S_Audio_Sample_DSoundEnumCallback(LPGUID guid, LPCTSTR description, LPCTSTR module, LPVOID context);
+void __cdecl S_Audio_Sample_Init2(HWND hwnd);
+bool __cdecl S_Audio_Sample_DSoundCreate(GUID *guid);
+bool __cdecl S_Audio_Sample_DSoundBufferTest(void);
+void __cdecl S_Audio_Sample_Shutdown(void);
+bool __cdecl S_Audio_Sample_IsEnabled(void);
sub_448410
sub_448420
void __cdecl CreateScreenBuffers(void);
@@ -1187,23 +1187,23 @@
void __cdecl CheckCheatMode(void);
void __cdecl S_SaveSettings(void);
void __cdecl S_LoadSettings(void);
-int32_t __cdecl S_SoundPlaySample(int32_t channel, UINT16 volume, int32_t pitch, int32_t pan);
-int32_t __cdecl S_Sound_CalculateSampleVolume(DWORD volume);
-int32_t __cdecl S_Sound_CalculateSamplePan(int16_t pan);
-int32_t __cdecl S_SoundPlaySampleLooped(int32_t channel, UINT16 volume, DWORD pitch, int32_t pan);
-void __cdecl S_SoundSetPanAndVolume(int32_t channel, int32_t pan, UINT16 volume);
-void __cdecl S_SoundSetPitch(int32_t channel, DWORD pitch);
-void __cdecl S_SoundSetMasterVolume(DWORD volume);
-void __cdecl S_SoundStopSample(int32_t channel);
-void __cdecl S_SoundStopAllSamples(void);
-BOOL __cdecl S_SoundSampleIsPlaying(int32_t channel);
-bool __cdecl CD_Init(void);
-void __cdecl CD_Cleanup(void);
-void __cdecl S_CDPlay(int16_t trackID, BOOL isLooped);
-void __cdecl S_CDStop(void);
-BOOL __cdecl StartSyncedAudio(int32_t trackID);
-DWORD __cdecl S_CDGetLoc(void);
-void __cdecl Music_SetVolume(int32_t volume);
+int32_t __cdecl Sound_Play(int32_t sample_id, uint16_t volume, int32_t pitch, int32_t pan);
+int32_t __cdecl Sound_CalculateSampleVolume(int32_t volume);
+int32_t __cdecl Sound_CalculateSamplePan(int16_t pan);
+int32_t __cdecl Sound_PlayLooped(int32_t sample_id, uint16_t volume, int32_t pitch, int32_t pan);
+void __cdecl Sound_SetPanAndVolume(int32_t sample_id, int32_t pan, uint16_t volume);
+void __cdecl Sound_SetPitch(int32_t sample_id, int32_t pitch);
+void __cdecl Sound_SetMasterVolume(int32_t volume);
+void __cdecl Sound_StopSample(int32_t sample_id);
+void __cdecl Sound_StopAllSamples(void);
+BOOL __cdecl Sound_SampleIsPlaying(int32_t sample_id);
+bool __cdecl CD_Init(void);
+void __cdecl CD_Cleanup(void);
+void __cdecl S_CDPlay(int16_t trackID, BOOL isLooped);
+void __cdecl S_CDStop(void);
+BOOL __cdecl StartSyncedAudio(int32_t trackID);
+DWORD __cdecl S_CDGetLoc(void);
+void __cdecl Music_SetVolume(int32_t volume);
void __cdecl CopyBitmapPalette(RGB888 *srcPal, BYTE *srcBitmap, int32_t bitmapSize, RGB888 *destPal);
BYTE __cdecl FindNearestPaletteEntry(RGB888 *palette, int32_t red, int32_t green, int32_t blue, bool ignoreSysPalette);
void __cdecl SyncSurfacePalettes(void *srcData, int32_t width, int32_t height, int32_t srcPitch, RGB888 *srcPalette, void *dstData, int32_t dstPitch, RGB888 *dstPalette, bool preserveSysPalette);
@@ -1281,10 +1281,10 @@
Tomb2.exe progress according to the function sizes:
-2.91% · 96.76% · 0.02% · 0.31%
+3.86% · 95.81% · 0.02% · 0.31%
-
-
+
+
@@ -1531,7 +1531,7 @@
void __cdecl FireHarpoon(void);
void __cdecl Output_InsertFlatRect_Sorted(int32_t x0, int32_t y0, int32_t x1, int32_t y1, int32_t z, uint8_t color_idx);
void __cdecl ControlTwinkle(int16_t fx_num);
-void __cdecl WinSndStart(HWND hWnd);
+void __cdecl S_Audio_Sample_Init2(HWND hwnd);
void __cdecl SE_GraphicsDlgInit(HWND hwndDlg);
void __cdecl SpinningBlade(int16_t item_num);
void __cdecl LiftFloorCeiling(struct ITEM_INFO *item, int32_t x, int32_t y, int32_t z, int32_t *floor, int32_t *ceiling);
@@ -1625,7 +1625,7 @@
int16_t __cdecl TitleSequence(void);
void __cdecl Inv_RingInit(struct RING_INFO *ring, int16_t type, struct INVENTORY_ITEM **list, int16_t qty, int16_t current, struct IMOTION_INFO *imo);
void __cdecl ScreenShotPCX(void);
-bool __cdecl WinSndMakeSample(DWORD sampleIdx, LPWAVEFORMATEX format, const LPVOID data, DWORD dataSize);
+bool __cdecl S_Audio_Sample_Load(int32_t sample_id, LPWAVEFORMATEX format, const void *data, int32_t data_size);
void __cdecl lara_as_compress(struct ITEM_INFO *item, struct COLL_INFO *coll);
void __cdecl CopterControl(int16_t item_num);
void __cdecl ControlLavaBlob(int16_t fx_num);
@@ -1676,7 +1676,7 @@
void __cdecl CalculateWibbleTable(void);
void __cdecl Camera_RefreshFromTrigger(int16_t type, int16_t *data);
int32_t __cdecl LaraTestWaterStepOut(struct ITEM_INFO *item, struct COLL_INFO *coll);
-int32_t __cdecl WinSndPlaySample(DWORD sampleIdx, int32_t volume, DWORD pitch, int32_t pan, DWORD flags);
+int32_t __cdecl S_Audio_Sample_Play(int32_t sample_id, int32_t volume, int32_t pitch, int32_t pan, int32_t flags);
void __cdecl LavaBurn(struct ITEM_INFO *item);
void __cdecl RenderFinish(bool needToClearTextures);
bool __cdecl DInputJoystickCreate(void);
@@ -1685,7 +1685,7 @@
void __cdecl BigBowlControl(int16_t item_num);
void __cdecl lara_slide_slope(struct ITEM_INFO *item, struct COLL_INFO *coll);
bool __cdecl WinVidSpinMessageLoop(bool needWait);
-BOOL __stdcall DSoundEnumCallback(LPGUID lpGuid, LPCTSTR lpcstrDescription, LPCTSTR lpcstrModule, LPVOID lpContext);
+BOOL __stdcall S_Audio_Sample_DSoundEnumCallback(LPGUID guid, LPCTSTR description, LPCTSTR module, LPVOID context);
int32_t __cdecl TestWall(struct ITEM_INFO *item, int32_t front, int32_t right, int32_t down);
int32_t __cdecl SkidooCheckGeton(int16_t item_num, struct COLL_INFO *coll);
BOOL __cdecl SelectDrive(void);
@@ -1734,7 +1734,7 @@
void __cdecl Output_QuickSort(int32_t left, int32_t right);
void __cdecl LavaSpray(int16_t item_num);
void __cdecl SmashWindow(int16_t item_num);
-bool __cdecl DSoundBufferTest(void);
+bool __cdecl S_Audio_Sample_DSoundBufferTest(void);
BOOL __cdecl S_ReloadLevelGraphics(BOOL reloadPalettes, BOOL reloadTexPages);
void __thiscall SE_LoadBitmapResource(BITMAP_RESOURCE *bmpRsrc, LPCTSTR lpName);
void __cdecl Splash(struct ITEM_INFO *item);
@@ -1821,7 +1821,7 @@
void __cdecl InitialiseFinalLevel(void);
void __cdecl CreateClipper(void);
void __cdecl ItemNewRoom(int16_t item_num, int16_t room_num);
-bool __cdecl WinSndInit(void);
+bool __cdecl S_Audio_Sample_Init(void);
void __cdecl LaraCollideStop(struct ITEM_INFO *item, struct COLL_INFO *coll);
void __cdecl swap_meshes_with_meshswap3(struct ITEM_INFO *item);
void __cdecl LoadDemoExternal(LPCTSTR levelName);
@@ -1853,7 +1853,7 @@
void __cdecl EffectNewRoom(int16_t fx_num, int16_t room_num);
void __cdecl SE_AdvancedDlgUpdate(HWND hwndDlg);
int32_t __cdecl GetFrames(struct ITEM_INFO *item, int16_t *frmptr[], int32_t *rate);
-void __cdecl Music_SetVolume(int32_t volume);
+void __cdecl Music_SetVolume(int32_t volume);
int16_t *__cdecl Output_InsertObjectGT4_ZBuffered(int16_t *obj_ptr, int32_t num, enum SORT_TYPE sort_type);
void __cdecl extra_as_sharkkill(struct ITEM_INFO *item, struct COLL_INFO *coll);
bool __cdecl GetRegistryGuidValue(LPCTSTR lpValueName, GUID *value, GUID *defaultValue);
@@ -1893,7 +1893,7 @@
void __cdecl lara_as_tread(struct ITEM_INFO *item, struct COLL_INFO *coll);
int32_t __cdecl Targetable(struct ITEM_INFO *item, AI_INFO *info);
void __cdecl lara_as_back(struct ITEM_INFO *item, struct COLL_INFO *coll);
-BOOL __cdecl StartSyncedAudio(int32_t trackID);
+BOOL __cdecl StartSyncedAudio(int32_t trackID);
void __cdecl DrawSpriteItem(struct ITEM_INFO *item);
void __cdecl lara_col_fallback(struct ITEM_INFO *item, struct COLL_INFO *coll);
void __cdecl ControlBlood1(int16_t fx_num);
@@ -1936,7 +1936,7 @@
void __cdecl LaraBubbles(struct ITEM_INFO *item);
void __cdecl Door_Collision(int16_t item_num, struct ITEM_INFO *lara_item, struct COLL_INFO *coll);
int32_t __cdecl Inv_RequestItem(int32_t itemNum);
-bool __cdecl CD_Init(void);
+bool __cdecl CD_Init(void);
int16_t __cdecl Knife(int32_t x, int32_t y, int32_t z, int16_t speed, PHD_ANGLE yrot, int16_t room_num);
void __cdecl DrawHair(void);
void __cdecl lara_as_glide(struct ITEM_INFO *item, struct COLL_INFO *coll);
@@ -1958,7 +1958,7 @@
void __cdecl CreatePictureBuffer(void);
int32_t __cdecl Box_UpdateLOT(struct LOT_INFO *lot, int32_t expansion);
void __cdecl RemoveDrawnItem(int16_t item_num);
-void __cdecl S_CDPlay(int16_t trackID, BOOL isLooped);
+void __cdecl S_CDPlay(int16_t trackID, BOOL isLooped);
BOOL __cdecl UT_CenterWindow(HWND hWnd);
void __cdecl UT_MemBlt(BYTE *dstBuf, DWORD dstX, DWORD dstY, DWORD width, DWORD height, DWORD dstPitch, BYTE *srcBuf, DWORD srcX, DWORD srcY, DWORD srcPitch);
bool __cdecl Output_VisibleZClip(struct PHD_VBUF *vtx0, struct PHD_VBUF *vtx1, struct PHD_VBUF *vtx2);
@@ -1974,7 +1974,7 @@
bool __cdecl WinVidRegisterGameWindowClass(void);
int32_t __cdecl CreateTexturePage(int32_t width, int32_t height, bool alpha);
void __cdecl lara_col_swandive(struct ITEM_INFO *item, struct COLL_INFO *coll);
-void __cdecl SoundEffects(void);
+void __cdecl Sound_Update(void);
void __cdecl ControlClockChimes(int16_t item_num);
void __cdecl lara_col_death(struct ITEM_INFO *item, struct COLL_INFO *coll);
void __cdecl InitialiseObjects(void);
@@ -2000,7 +2000,7 @@
void __cdecl DecreaseScreenSize(void);
void __cdecl InitialiseGameFlags(void);
DWORD __cdecl CalculateCompatibleColor(COLOR_BIT_MASKS *mask, int32_t red, int32_t green, int32_t blue, int32_t alpha);
-DWORD __cdecl S_CDGetLoc(void);
+DWORD __cdecl S_CDGetLoc(void);
bool __cdecl SE_RegisterSetupWindowClass(void);
void __fastcall flatA(int32_t y0, int32_t y1, BYTE colorIdx);
void __cdecl Inv_RingGetView(struct RING_INFO *ring, struct PHD_3DPOS *viewer);
@@ -2063,7 +2063,7 @@
int32_t __cdecl LaraFallen(struct ITEM_INFO *item, struct COLL_INFO *coll);
void __cdecl SmashItem(int16_t item_num, int32_t weapon_type);
void __cdecl S_SetupBelowWater(BOOL underwater);
-void __cdecl CD_Cleanup(void);
+void __cdecl CD_Cleanup(void);
bool __cdecl TIME_Init(void);
LPCTSTR __cdecl GuidBinaryToString(GUID *guid);
void __cdecl Creature_Underwater(struct ITEM_INFO *item, int32_t depth);
@@ -2105,7 +2105,7 @@
int32_t __cdecl CalculateWindowWidth(int32_t width, int32_t height);
DISPLAY_ADAPTER_NODE *__cdecl WinVidGetDisplayAdapter(GUID *lpGuid);
DISPLAY_MODE *__thiscall InsertDisplayModeInListHead(DISPLAY_MODE_LIST *modeList);
-SOUND_ADAPTER_NODE *__cdecl GetSoundAdapter(GUID *lpGuid);
+struct SOUND_ADAPTER_NODE *__cdecl S_Audio_Sample_GetAdapter(GUID *guid);
void __cdecl WinStopFMV(bool isPlayback);
int32_t __fastcall Math_Atan(int32_t x, int32_t y);
int32_t __cdecl Creature_Activate(int16_t item_num);
@@ -2115,11 +2115,11 @@
HRESULT __cdecl DDrawSurfaceRestoreLost(LPDDS surface1, LPDDS surface2, bool blank);
DWORD __cdecl GetRenderBitDepth(DWORD dwRGBBitCount);
void __cdecl S_InsertBackPolygon(int32_t x0, int32_t y0, int32_t x1, int32_t y1);
-int32_t __cdecl S_SoundPlaySample(int32_t channel, UINT16 volume, int32_t pitch, int32_t pan);
-int32_t __cdecl S_SoundPlaySampleLooped(int32_t channel, UINT16 volume, DWORD pitch, int32_t pan);
+int32_t __cdecl Sound_Play(int32_t sample_id, uint16_t volume, int32_t pitch, int32_t pan);
+int32_t __cdecl Sound_PlayLooped(int32_t sample_id, uint16_t volume, int32_t pitch, int32_t pan);
void __cdecl DrawGameInfo(int32_t timed);
bool __thiscall CompareVideoModes(DISPLAY_MODE *mode1, DISPLAY_MODE *mode2);
-bool __cdecl WinSndIsChannelPlaying(DWORD channel);
+bool __cdecl S_Audio_Sample_IsTrackPlaying(int32_t track_id);
HRESULT __cdecl DDrawSurfaceCreate(LPDDSDESC dsp, LPDDS *surface);
void __cdecl BitMaskGetNumberOfBits(DWORD bitMask, DWORD *bitDepth, DWORD *bitOffset);
void __cdecl GetValidLevelsList(REQUEST_INFO *req);
@@ -2159,7 +2159,7 @@
void __cdecl InitialiseRollingBall(int16_t item_num);
int32_t __cdecl RenderErrorBox(int32_t errorCode);
void __cdecl Shell_ExitSystem(const char *message);
-void __cdecl S_SoundStopAllSamples(void);
+void __cdecl Sound_StopAllSamples(void);
int32_t __cdecl CheckForHoldingState(int32_t state);
int32_t __cdecl WeaponObject(int32_t weapon_type);
void __cdecl DrawBridgeCeiling(struct ITEM_INFO *item, int32_t x, int32_t y, int32_t z, int32_t *height);
@@ -2180,10 +2180,10 @@
sub_447170
void __cdecl TempVideoRemove(void);
sub_447B40
-int32_t __cdecl WinSndGetFreeChannelIndex(void);
+int32_t __cdecl S_Audio_Sample_GetFreeTrackIndex(void);
void __cdecl Shell_Shutdown(void);
-void __cdecl S_SoundSetPanAndVolume(int32_t channel, int32_t pan, UINT16 volume);
-void __cdecl S_CDStop(void);
+void __cdecl Sound_SetPanAndVolume(int32_t sample_id, int32_t pan, uint16_t volume);
+void __cdecl S_CDStop(void);
void __cdecl Output_DrawPolyGTMapPersp(int16_t *obj_ptr);
void __cdecl Output_DrawPolyWGTMapPersp(int16_t *obj_ptr);
void __cdecl Item_ShiftCol(struct ITEM_INFO *item, struct COLL_INFO *coll);
@@ -2216,7 +2216,7 @@
void __cdecl BridgeTilt1Ceiling(struct ITEM_INFO *item, int32_t x, int32_t y, int32_t z, int32_t *height);
void __cdecl ReadSG(void *pointer, int32_t size);
void __cdecl WinVidSetGameWindowSize(int32_t width, int32_t height);
-void __thiscall FlaggedStringsCreate(struct DISPLAY_ADAPTER *adapter);
+void __thiscall FlaggedStringsCreate(struct DISPLAY_ADAPTER *adapter);
void __cdecl S_FadeInInventory(BOOL isFade);
void __cdecl S_DrawScreenLine(int32_t x, int32_t y, int32_t z, int32_t xLen, int32_t yLen, BYTE colorIdx, D3DCOLOR *gour, uint16_t flags);
void __cdecl HWR_GetPageHandles(void);
@@ -2246,7 +2246,7 @@
void __cdecl phd_RotX_I(int16_t ang);
void __cdecl phd_RotZ_I(int16_t ang);
int32_t __cdecl GetRealTrack(int32_t track);
-void __cdecl WinSndAdjustPitch(int32_t channel, DWORD pitch);
+void __cdecl S_Audio_Sample_AdjustTrackPitch(int32_t track_id, int32_t pitch);
void __cdecl S_CalculateStaticLight(int16_t adder);
void __cdecl ControlRichochet1(int16_t fx_num);
void __cdecl InitialiseFXArray(void);
@@ -2265,8 +2265,8 @@
void __cdecl BridgeTilt2Floor(struct ITEM_INFO *item, int32_t x, int32_t y, int32_t z, int32_t *height);
sub_4471C0
sub_447B90
-void __cdecl WinSndStopSample(int32_t channel);
-void __cdecl WinSndFreeAllSamples(void);
+void __cdecl S_Audio_Sample_CloseTrack(int32_t track_id);
+void __cdecl S_Audio_Sample_CloseAllTracks(void);
void __cdecl S_DrawScreenFBox(int32_t sx, int32_t sy, int32_t z, int32_t width, int32_t height, BYTE colorIdx, GOURAUD_FILL *gour, uint16_t flags);
void __cdecl Demo_GetInput(void);
int32_t __cdecl FlashIt(void);
@@ -2279,7 +2279,7 @@
void __cdecl InitialiseMovingBlock(int16_t item_num);
void __cdecl DrawBridgeCollision(int16_t item_num, struct ITEM_INFO *laraitem, struct COLL_INFO *coll);
void __cdecl T_InitPrint(void);
-void __cdecl WinSndAdjustVolumeAndPan(int32_t channel, int32_t volume, int32_t pan);
+void __cdecl S_Audio_Sample_AdjustTrackVolumeAndPan(int32_t track_id, int32_t volume, int32_t pan);
LPTSTR __cdecl UT_FindArg(LPCTSTR str);
uint32_t __fastcall Math_Sqrt(uint32_t n);
void __cdecl lara_as_slide(struct ITEM_INFO *item, struct COLL_INFO *coll);
@@ -2289,9 +2289,9 @@
void __cdecl HWR_ResetColorKey(void);
void __cdecl phd_PutPolygons_I(int16_t *ptr, int32_t clip);
void __cdecl SOUND_Init(void);
-void __cdecl WinSndFinish(void);
+void __cdecl S_Audio_Sample_Shutdown(void);
void __cdecl S_UnloadLevelFile(void);
-int32_t __cdecl S_Sound_CalculateSampleVolume(DWORD volume);
+int32_t __cdecl Sound_CalculateSampleVolume(int32_t volume);
LONG __cdecl SetRegistryBoolValue(LPCTSTR lpValueName, bool value);
void __cdecl T_AddOutline(struct TEXTSTRING *textstring, int16_t enable, int16_t colour, uint16_t *gourptr, uint16_t flags);
void __cdecl DInputKeyboardRelease(void);
@@ -2306,7 +2306,7 @@
void __cdecl Inv_RingMotionRadius(struct RING_INFO *ring, int16_t target);
LPCTSTR __cdecl GetFullPath(LPCTSTR fileName);
void __cdecl ScreenClear(bool isPhdWinSize);
-int32_t __cdecl S_Sound_CalculateSamplePan(int16_t pan);
+int32_t __cdecl Sound_CalculateSamplePan(int16_t pan);
void __cdecl FreeTexturePages(void);
void __cdecl SE_PassMessageToImage(HWND hWnd, UINT uMsg, WPARAM wParam);
void __cdecl Inv_RingMotionCameraPos(struct RING_INFO *ring, int16_t target);
@@ -2347,8 +2347,8 @@
void __cdecl AssaultStop(struct ITEM_INFO *item);
int32_t __cdecl GF_DoFrontEndSequence(void);
bool __cdecl D3DCreate(void);
-void __thiscall FlaggedStringCreate(struct STRING_FLAGGED *item, DWORD dwSize);
-BOOL __cdecl S_SoundSampleIsPlaying(int32_t channel);
+void __thiscall FlaggedStringCreate(struct STRING_FLAGGED *item, DWORD dwSize);
+BOOL __cdecl Sound_SampleIsPlaying(int32_t sample_id);
bool __cdecl InitTextures(void);
void __cdecl lara_col_slide(struct ITEM_INFO *item, struct COLL_INFO *coll);
void __cdecl lara_as_climbend(struct ITEM_INFO *item, struct COLL_INFO *coll);
@@ -2369,9 +2369,9 @@
void __cdecl StatueFX(struct ITEM_INFO *item);
void __cdecl SetChangeFX(struct ITEM_INFO *item);
void __cdecl lara_as_reach(struct ITEM_INFO *item, struct COLL_INFO *coll);
-bool __cdecl DSoundCreate(GUID *lpGuid);
+bool __cdecl S_Audio_Sample_DSoundCreate(GUID *guid);
void __cdecl S_DontDisplayPicture(void);
-void __cdecl S_SoundSetPitch(int32_t channel, DWORD pitch);
+void __cdecl Sound_SetPitch(int32_t sample_id, int32_t pitch);
int32_t __cdecl GetFreePaletteIndex(void);
int32_t __cdecl GetFreeTexturePageIndex(void);
void __thiscall SE_UpdateBitmapPalette(BITMAP_RESOURCE *bmpRsrc, HWND hWnd, HWND hSender);
@@ -2382,7 +2382,7 @@
int32_t __fastcall Math_Sin(int16_t angle);
bool __cdecl EnumerateDisplayAdapters(struct DISPLAY_ADAPTER_LIST *displayAdapterList);
void __cdecl DInputRelease(void);
-bool __cdecl DSoundEnumerate(SOUND_ADAPTER_LIST *adapterList);
+bool __cdecl S_Audio_Sample_DSoundEnumerate(struct SOUND_ADAPTER_LIST *adapter_list);
int32_t __fastcall Math_SinImpl(int16_t angle);
int32_t __cdecl GetDebouncedInput(int32_t input);
bool __cdecl HWR_VertexBufferFull(void);
@@ -2402,7 +2402,7 @@
void __cdecl WinInRunControlPanel(HWND hWnd);
sub_44E860
void __cdecl SE_GraphicsAdapterSet(HWND hwndDlg, DISPLAY_ADAPTER_NODE *adapter);
-void __cdecl S_SoundStopSample(int32_t channel);
+void __cdecl Sound_StopSample(int32_t sample_id);
void __cdecl turn180_effect(struct ITEM_INFO *item);
void __cdecl invisibility_off(struct ITEM_INFO *item);
void __cdecl BridgeFlatFloor(struct ITEM_INFO *item, int32_t x, int32_t y, int32_t z, int32_t *height);
@@ -2424,7 +2424,7 @@
void __cdecl lara_col_stepleft(struct ITEM_INFO *item, struct COLL_INFO *coll);
void __cdecl lara_col_roll(struct ITEM_INFO *item, struct COLL_INFO *coll);
void __cdecl lara_col_swim(struct ITEM_INFO *item, struct COLL_INFO *coll);
-void __thiscall FlaggedStringDelete(struct STRING_FLAGGED *item);
+void __thiscall FlaggedStringDelete(struct STRING_FLAGGED *item);
void __cdecl WinVidFinish(void);
bool __cdecl S_IntroFMV(LPCTSTR fileName1, LPCTSTR fileName2);
LONG __cdecl DeleteRegistryValue(LPCTSTR lpValueName);
@@ -2461,13 +2461,13 @@
void __cdecl SeedRandomDraw(int32_t seed);
void __cdecl SE_SoundAdapterSet(HWND hwndDlg, SOUND_ADAPTER_NODE *adapter);
void __cdecl SE_ControlsJoystickSet(HWND hwndDlg, JOYSTICK_NODE *joystick);
-void __cdecl S_SoundSetMasterVolume(DWORD volume);
+void __cdecl Sound_SetMasterVolume(int32_t volume);
void __cdecl invisibility_on(struct ITEM_INFO *item);
void __cdecl dynamic_light_on(struct ITEM_INFO *item);
void __cdecl WinVidClearMinWindowSize(void);
void __cdecl WinVidClearMaxWindowSize(void);
bool __cdecl Direct3DInit(void);
-bool __cdecl WinSndIsSoundEnabled(void);
+bool __cdecl S_Audio_Sample_IsEnabled(void);
int32_t __cdecl LevelCompleteSequence(void);
int32_t __cdecl GetRenderHeight(void);
int32_t __cdecl GetRenderWidth(void);
diff --git a/docs/progress.txt b/docs/progress.txt
index 5357a4cc..10b441a0 100644
--- a/docs/progress.txt
+++ b/docs/progress.txt
@@ -1134,7 +1134,7 @@ typedef struct CINE_FRAME {
# game/effects.c
0041C4D0 0000008C -R int32_t __cdecl ItemNearLara(struct PHD_3DPOS *pos, int32_t distance);
-0041C560 00000068 -R void __cdecl SoundEffects(void);
+0041C560 00000068 -R void __cdecl Sound_Update(void);
0041C5D0 00000059 -R int16_t __cdecl DoBloodSplat(int32_t x, int32_t y, int32_t z, int16_t speed, PHD_ANGLE direction, int16_t room_num);
0041C630 000000A4 -R void __cdecl DoLotsOfBlood(int32_t x, int32_t y, int32_t z, int16_t speed, PHD_ANGLE direction, int16_t room_num, int32_t num);
0041C6E0 00000082 -R void __cdecl ControlBlood1(int16_t fx_num);
@@ -1662,11 +1662,11 @@ typedef struct CINE_FRAME {
# game/sound.c
0043F380 00000031 -R int32_t __cdecl GetRealTrack(int32_t track);
-0043F3C0 00000484 - void __cdecl Sound_Effect(uint32_t sfx_num, const struct PHD_3DPOS *pos, uint32_t flags);
-0043F860 0000005E - void __cdecl Sound_StopEffect(int32_t sfx_num);
-0043F8C0 00000086 -R void __cdecl SOUND_EndScene(void);
-0043F950 00000024 -R void __cdecl SOUND_Stop(void);
-0043F980 0000002A -R void __cdecl SOUND_Init(void);
+0043F3C0 00000484 - void __cdecl Sound_Effect(int32_t sample_id, const struct PHD_3DPOS *pos, uint32_t flags);
+0043F860 0000005E - void __cdecl Sound_StopEffect(int32_t sample_id);
+0043F8C0 00000086 -R void __cdecl Sound_UpdateContinued(void);
+0043F950 00000024 -R void __cdecl Sound_Shutdown(void);
+0043F980 0000002A -R void __cdecl Sound_Init(void);
# game/sphere.c
0043F9B0 00000128 -R int32_t __cdecl TestCollision(struct ITEM_INFO *item, struct ITEM_INFO *laraitem);
@@ -1800,10 +1800,10 @@ typedef struct CINE_FRAME {
00445A50 000003B1 -R HRESULT __stdcall EnumDisplayModesCallback(LPDDSDESC lpDDSurfaceDesc, LPVOID lpContext);
00445E10 00000040 -R bool __cdecl WinVidInit(void);
00445E50 000000AF -R bool __cdecl WinVidGetDisplayAdapters(void);
-00445F00 00000013 -R void __thiscall FlaggedStringDelete(struct STRING_FLAGGED *item);
+00445F00 00000013 +R void __thiscall FlaggedStringDelete(struct STRING_FLAGGED *item);
00445F20 0000001A -R bool __cdecl EnumerateDisplayAdapters(struct DISPLAY_ADAPTER_LIST *displayAdapterList);
00445F40 000001BE -R BOOL __stdcall EnumDisplayAdaptersCallback(GUID *lpGUID, LPTSTR lpDriverDescription, LPTSTR lpDriverName, LPVOID lpContext);
-00446100 00000035 -R void __thiscall FlaggedStringsCreate(struct DISPLAY_ADAPTER *adapter);
+00446100 00000035 +R void __thiscall FlaggedStringsCreate(struct DISPLAY_ADAPTER *adapter);
00446140 0000006A -R bool __cdecl WinVidRegisterGameWindowClass(void);
004461B0 0000049F -R LRESULT __stdcall WinVidGameWindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
004467C0 000001C0 -R void __cdecl WinVidResizeGameWindow(HWND hWnd, int32_t edge, LPRECT rect);
@@ -1833,7 +1833,7 @@ typedef struct CINE_FRAME {
004473B0 0000007F -R bool __cdecl WinInputInit(void);
00447430 00000024 -R bool __cdecl DInputEnumDevices(JOYSTICK_LIST *joystickList);
00447460 000000E8 -R BOOL __stdcall DInputEnumDevicesCallback(LPCDIDEVICEINSTANCE lpddi, LPVOID pvRef);
-00447550 0000001F -R void __thiscall FlaggedStringCreate(struct STRING_FLAGGED *item, DWORD dwSize);
+00447550 0000001F +R void __thiscall FlaggedStringCreate(struct STRING_FLAGGED *item, DWORD dwSize);
00447570 0000004E -R JOYSTICK_NODE *__cdecl GetJoystick(GUID *lpGuid);
004475C0 000000C9 -R void __cdecl DInputKeyboardCreate(void);
00447690 00000029 -R void __cdecl DInputKeyboardRelease(void);
@@ -1854,24 +1854,24 @@ typedef struct CINE_FRAME {
00447B30 00000018 x sub_447B30
00447B40 00000039 x sub_447B40
00447B90 0000002F x sub_447B90
-00447BC0 00000048 -R SOUND_ADAPTER_NODE *__cdecl GetSoundAdapter(GUID *lpGuid);
-00447C10 0000002E -R void __cdecl WinSndFreeAllSamples(void);
-00447C40 0000010E -R bool __cdecl WinSndMakeSample(DWORD sampleIdx, LPWAVEFORMATEX format, const LPVOID data, DWORD dataSize);
-00447D50 00000045 -R bool __cdecl WinSndIsChannelPlaying(DWORD channel);
-00447DA0 000000E7 -R int32_t __cdecl WinSndPlaySample(DWORD sampleIdx, int32_t volume, DWORD pitch, int32_t pan, DWORD flags);
-00447E90 00000039 -R int32_t __cdecl WinSndGetFreeChannelIndex(void);
-00447ED0 0000002C -R void __cdecl WinSndAdjustVolumeAndPan(int32_t channel, int32_t volume, int32_t pan);
-00447F00 00000031 -R void __cdecl WinSndAdjustPitch(int32_t channel, DWORD pitch);
-00447F40 0000002F -R void __cdecl WinSndStopSample(int32_t channel);
+00447BC0 00000048 + struct SOUND_ADAPTER_NODE *__cdecl S_Audio_Sample_GetAdapter(GUID *guid);
+00447C10 0000002E + void __cdecl S_Audio_Sample_CloseAllTracks(void);
+00447C40 0000010E + bool __cdecl S_Audio_Sample_Load(int32_t sample_id, LPWAVEFORMATEX format, const void *data, int32_t data_size);
+00447D50 00000045 + bool __cdecl S_Audio_Sample_IsTrackPlaying(int32_t track_id);
+00447DA0 000000E7 + int32_t __cdecl S_Audio_Sample_Play(int32_t sample_id, int32_t volume, int32_t pitch, int32_t pan, int32_t flags);
+00447E90 00000039 + int32_t __cdecl S_Audio_Sample_GetFreeTrackIndex(void);
+00447ED0 0000002C + void __cdecl S_Audio_Sample_AdjustTrackVolumeAndPan(int32_t track_id, int32_t volume, int32_t pan);
+00447F00 00000031 + void __cdecl S_Audio_Sample_AdjustTrackPitch(int32_t track_id, int32_t pitch);
+00447F40 0000002F + void __cdecl S_Audio_Sample_CloseTrack(int32_t track_id);
00447FA0 00000005 -R sub_447FA0
-00447FB0 0000009C -R bool __cdecl WinSndInit(void);
-00448050 0000001A -R bool __cdecl DSoundEnumerate(SOUND_ADAPTER_LIST *adapterList);
-00448070 000000E2 -R BOOL __stdcall DSoundEnumCallback(LPGUID lpGuid, LPCTSTR lpcstrDescription, LPCTSTR lpcstrModule, LPVOID lpContext);
-00448160 0000017C -R void __cdecl WinSndStart(HWND hWnd);
-004482E0 0000001C -R bool __cdecl DSoundCreate(GUID *lpGuid);
-00448300 000000C4 -R bool __cdecl DSoundBufferTest(void);
-004483D0 0000002A -R void __cdecl WinSndFinish(void);
-00448400 00000006 -R bool __cdecl WinSndIsSoundEnabled(void);
+00447FB0 0000009C +R bool __cdecl S_Audio_Sample_Init(void);
+00448050 0000001A +R bool __cdecl S_Audio_Sample_DSoundEnumerate(struct SOUND_ADAPTER_LIST *adapter_list);
+00448070 000000E2 +R BOOL __stdcall S_Audio_Sample_DSoundEnumCallback(LPGUID guid, LPCTSTR description, LPCTSTR module, LPVOID context);
+00448160 0000017C +R void __cdecl S_Audio_Sample_Init2(HWND hwnd);
+004482E0 0000001C +R bool __cdecl S_Audio_Sample_DSoundCreate(GUID *guid);
+00448300 000000C4 +R bool __cdecl S_Audio_Sample_DSoundBufferTest(void);
+004483D0 0000002A +R void __cdecl S_Audio_Sample_Shutdown(void);
+00448400 00000006 +R bool __cdecl S_Audio_Sample_IsEnabled(void);
00448410 00000005 -R sub_448410
00448420 00000001 -R sub_448420
00448430 0000013B -R void __cdecl CreateScreenBuffers(void);
@@ -2071,23 +2071,23 @@ typedef struct CINE_FRAME {
00454D60 0000032D -R void __cdecl CheckCheatMode(void);
004550C0 0000007D -R void __cdecl S_SaveSettings(void);
00455140 000000DB -R void __cdecl S_LoadSettings(void);
-00455220 00000046 -R int32_t __cdecl S_SoundPlaySample(int32_t channel, UINT16 volume, int32_t pitch, int32_t pan);
-00455270 0000002A -R int32_t __cdecl S_Sound_CalculateSampleVolume(DWORD volume);
-004552A0 00000026 -R int32_t __cdecl S_Sound_CalculateSamplePan(int16_t pan);
-004552D0 00000046 -R int32_t __cdecl S_SoundPlaySampleLooped(int32_t channel, UINT16 volume, DWORD pitch, int32_t pan);
-00455320 00000039 -R void __cdecl S_SoundSetPanAndVolume(int32_t channel, int32_t pan, UINT16 volume);
-00455360 0000001C -R void __cdecl S_SoundSetPitch(int32_t channel, DWORD pitch);
-00455380 0000000A -R void __cdecl S_SoundSetMasterVolume(DWORD volume);
-00455390 00000017 -R void __cdecl S_SoundStopSample(int32_t channel);
-004553B0 0000003C -R void __cdecl S_SoundStopAllSamples(void);
-004553C0 0000001F -R BOOL __cdecl S_SoundSampleIsPlaying(int32_t channel);
-004553E0 00000077 -R bool __cdecl CD_Init(void);
-00455460 00000051 -R void __cdecl CD_Cleanup(void);
-00455500 0000006F -R void __cdecl S_CDPlay(int16_t trackID, BOOL isLooped);
-00455570 00000039 -R void __cdecl S_CDStop(void);
-004555B0 00000084 -R BOOL __cdecl StartSyncedAudio(int32_t trackID);
-00455640 00000061 -R DWORD __cdecl S_CDGetLoc(void);
-004556B0 00000092 * void __cdecl Music_SetVolume(int32_t volume);
+00455220 00000046 +R int32_t __cdecl Sound_Play(int32_t sample_id, uint16_t volume, int32_t pitch, int32_t pan);
+00455270 0000002A +R int32_t __cdecl Sound_CalculateSampleVolume(int32_t volume);
+004552A0 00000026 +R int32_t __cdecl Sound_CalculateSamplePan(int16_t pan);
+004552D0 00000046 +R int32_t __cdecl Sound_PlayLooped(int32_t sample_id, uint16_t volume, int32_t pitch, int32_t pan);
+00455320 00000039 +R void __cdecl Sound_SetPanAndVolume(int32_t sample_id, int32_t pan, uint16_t volume);
+00455360 0000001C +R void __cdecl Sound_SetPitch(int32_t sample_id, int32_t pitch);
+00455380 0000000A +R void __cdecl Sound_SetMasterVolume(int32_t volume);
+00455390 00000017 +R void __cdecl Sound_StopSample(int32_t sample_id);
+004553B0 0000003C +R void __cdecl Sound_StopAllSamples(void);
+004553C0 0000001F +R BOOL __cdecl Sound_SampleIsPlaying(int32_t sample_id);
+004553E0 00000077 +R bool __cdecl CD_Init(void);
+00455460 00000051 +R void __cdecl CD_Cleanup(void);
+00455500 0000006F +R void __cdecl S_CDPlay(int16_t trackID, BOOL isLooped);
+00455570 00000039 +R void __cdecl S_CDStop(void);
+004555B0 00000084 +R BOOL __cdecl StartSyncedAudio(int32_t trackID);
+00455640 00000061 +R DWORD __cdecl S_CDGetLoc(void);
+004556B0 00000092 + void __cdecl Music_SetVolume(int32_t volume);
004557A0 00000137 -R void __cdecl CopyBitmapPalette(RGB888 *srcPal, BYTE *srcBitmap, int32_t bitmapSize, RGB888 *destPal);
004558E0 000000C8 -R BYTE __cdecl FindNearestPaletteEntry(RGB888 *palette, int32_t red, int32_t green, int32_t blue, bool ignoreSysPalette);
004559B0 000000AE -R void __cdecl SyncSurfacePalettes(void *srcData, int32_t width, int32_t height, int32_t srcPitch, RGB888 *srcPalette, void *dstData, int32_t dstPitch, RGB888 *dstPalette, bool preserveSysPalette);
@@ -2169,6 +2169,7 @@ typedef struct CINE_FRAME {
# Offset Flags Declaration
004640BC - int16_t g_CD_TrackID;
+004640C4 - int32_t g_FlipEffect;
00465A60 - int16_t g_OptionMusicVolume;
00467DD0 + const int32_t g_AtanBaseTable[8];
00467DF0 + const int16_t g_AtanAngleTable[0x800];
@@ -2218,7 +2219,9 @@ typedef struct CINE_FRAME {
0051E6C4 - int32_t g_SoundIsActive;
005206E0 - struct LARA_INFO g_Lara;
005207BC - struct ITEM_INFO *g_LaraItem;
+00521FDC - int32_t g_SoundFxCount;
0052618C - struct ROOM_INFO *g_Rooms;
+00526240 - int32_t g_FlipStatus;
005262F0 - struct ITEM_INFO g_Items[];
005262F6 - int16_t g_NumCineFrames;
005262F8 - CINE_FRAME *g_CineData = NULL;
@@ -2226,3 +2229,5 @@ typedef struct CINE_FRAME {
00526314 - int16_t g_CineFrame;
00526320 - struct CAMERA_INFO g_Camera;
005263CC - struct BOX_INFO *g_Boxes;
+004641F8 - void (__cdecl *g_EffectRoutines[32])(struct ITEM_INFO *item);
+004D7C80 - DWORD g_SoundTrackIds[128];
diff --git a/meson.build b/meson.build
index 4db536c8..9062f794 100644
--- a/meson.build
+++ b/meson.build
@@ -84,6 +84,11 @@ dll_sources = [
'src/main_dll.c',
'src/memory.c',
'src/specific/s_filesystem.c',
+ 'src/specific/s_pauld.c',
+ 'src/specific/s_sndpc.c',
+ 'src/specific/s_sound.c',
+ 'src/specific/s_winvid.c',
+ 'src/lib/winmm.c',
]
executable(
diff --git a/src/game/camera.c b/src/game/camera.c
index 24ea8e5d..b72a2d0a 100644
--- a/src/game/camera.c
+++ b/src/game/camera.c
@@ -5,6 +5,7 @@
#include "global/const.h"
#include "global/funcs.h"
#include "global/vars.h"
+#include "specific/s_sndpc.h"
#include "util.h"
#define CHASE_SPEED 10
diff --git a/src/global/const.h b/src/global/const.h
index 24daf7fa..98e92037 100644
--- a/src/global/const.h
+++ b/src/global/const.h
@@ -20,3 +20,6 @@
#define MIN_HEAD_ROTATION (-MAX_HEAD_ROTATION) // = -9100
#define MAX_HEAD_TILT_CAM (85 * PHD_DEGREE) // = 15470
#define MIN_HEAD_TILT_CAM (-MAX_HEAD_TILT_CAM) // = -15470
+
+#define MAX_AUDIO_SAMPLE_BUFFERS 256
+#define MAX_AUDIO_SAMPLE_TRACKS 32
diff --git a/src/global/funcs.h b/src/global/funcs.h
index 134a26ca..c5b23c50 100644
--- a/src/global/funcs.h
+++ b/src/global/funcs.h
@@ -225,7 +225,7 @@
#define BigEelControl ((void __cdecl (*)(int16_t item_num))0x0041C140)
#define EelControl ((void __cdecl (*)(int16_t item_num))0x0041C2E0)
#define ItemNearLara ((int32_t __cdecl (*)(struct PHD_3DPOS *pos, int32_t distance))0x0041C4D0)
-#define SoundEffects ((void __cdecl (*)(void))0x0041C560)
+#define Sound_Update ((void __cdecl (*)(void))0x0041C560)
#define DoBloodSplat ((int16_t __cdecl (*)(int32_t x, int32_t y, int32_t z, int16_t speed, PHD_ANGLE direction, int16_t room_num))0x0041C5D0)
#define DoLotsOfBlood ((void __cdecl (*)(int32_t x, int32_t y, int32_t z, int16_t speed, PHD_ANGLE direction, int16_t room_num, int32_t num))0x0041C630)
#define ControlBlood1 ((void __cdecl (*)(int16_t fx_num))0x0041C6E0)
@@ -814,10 +814,8 @@
#define EnumDisplayModesCallback ((HRESULT __stdcall (*)(LPDDSDESC lpDDSurfaceDesc, LPVOID lpContext))0x00445A50)
#define WinVidInit ((bool __cdecl (*)(void))0x00445E10)
#define WinVidGetDisplayAdapters ((bool __cdecl (*)(void))0x00445E50)
-#define FlaggedStringDelete ((void __thiscall (*)(struct STRING_FLAGGED *item))0x00445F00)
#define EnumerateDisplayAdapters ((bool __cdecl (*)(struct DISPLAY_ADAPTER_LIST *displayAdapterList))0x00445F20)
#define EnumDisplayAdaptersCallback ((BOOL __stdcall (*)(GUID *lpGUID, LPTSTR lpDriverDescription, LPTSTR lpDriverName, LPVOID lpContext))0x00445F40)
-#define FlaggedStringsCreate ((void __thiscall (*)(struct DISPLAY_ADAPTER *adapter))0x00446100)
#define WinVidRegisterGameWindowClass ((bool __cdecl (*)(void))0x00446140)
#define WinVidGameWindowProc ((LRESULT __stdcall (*)(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam))0x004461B0)
#define WinVidResizeGameWindow ((void __cdecl (*)(HWND hWnd, int32_t edge, LPRECT rect))0x004467C0)
@@ -840,7 +838,6 @@
#define WinInputInit ((bool __cdecl (*)(void))0x004473B0)
#define DInputEnumDevices ((bool __cdecl (*)(JOYSTICK_LIST *joystickList))0x00447430)
#define DInputEnumDevicesCallback ((BOOL __stdcall (*)(LPCDIDEVICEINSTANCE lpddi, LPVOID pvRef))0x00447460)
-#define FlaggedStringCreate ((void __thiscall (*)(struct STRING_FLAGGED *item, DWORD dwSize))0x00447550)
#define GetJoystick ((JOYSTICK_NODE *__cdecl (*)(GUID *lpGuid))0x00447570)
#define DInputKeyboardCreate ((void __cdecl (*)(void))0x004475C0)
#define DInputKeyboardRelease ((void __cdecl (*)(void))0x00447690)
@@ -855,23 +852,6 @@
#define TempVideoRemove ((void __cdecl (*)(void))0x004479D0)
#define S_FadeInInventory ((void __cdecl (*)(BOOL isFade))0x00447A10)
#define S_FadeOutInventory ((void __cdecl (*)(BOOL isFade))0x00447A50)
-#define GetSoundAdapter ((SOUND_ADAPTER_NODE *__cdecl (*)(GUID *lpGuid))0x00447BC0)
-#define WinSndFreeAllSamples ((void __cdecl (*)(void))0x00447C10)
-#define WinSndMakeSample ((bool __cdecl (*)(DWORD sampleIdx, LPWAVEFORMATEX format, const LPVOID data, DWORD dataSize))0x00447C40)
-#define WinSndIsChannelPlaying ((bool __cdecl (*)(DWORD channel))0x00447D50)
-#define WinSndPlaySample ((int32_t __cdecl (*)(DWORD sampleIdx, int32_t volume, DWORD pitch, int32_t pan, DWORD flags))0x00447DA0)
-#define WinSndGetFreeChannelIndex ((int32_t __cdecl (*)(void))0x00447E90)
-#define WinSndAdjustVolumeAndPan ((void __cdecl (*)(int32_t channel, int32_t volume, int32_t pan))0x00447ED0)
-#define WinSndAdjustPitch ((void __cdecl (*)(int32_t channel, DWORD pitch))0x00447F00)
-#define WinSndStopSample ((void __cdecl (*)(int32_t channel))0x00447F40)
-#define WinSndInit ((bool __cdecl (*)(void))0x00447FB0)
-#define DSoundEnumerate ((bool __cdecl (*)(SOUND_ADAPTER_LIST *adapterList))0x00448050)
-#define DSoundEnumCallback ((BOOL __stdcall (*)(LPGUID lpGuid, LPCTSTR lpcstrDescription, LPCTSTR lpcstrModule, LPVOID lpContext))0x00448070)
-#define WinSndStart ((void __cdecl (*)(HWND hWnd))0x00448160)
-#define DSoundCreate ((bool __cdecl (*)(GUID *lpGuid))0x004482E0)
-#define DSoundBufferTest ((bool __cdecl (*)(void))0x00448300)
-#define WinSndFinish ((void __cdecl (*)(void))0x004483D0)
-#define WinSndIsSoundEnabled ((bool __cdecl (*)(void))0x00448400)
#define CreateScreenBuffers ((void __cdecl (*)(void))0x00448430)
#define CreatePrimarySurface ((void __cdecl (*)(void))0x00448570)
#define CreateBackBuffer ((void __cdecl (*)(void))0x00448610)
@@ -1063,23 +1043,6 @@
#define CheckCheatMode ((void __cdecl (*)(void))0x00454D60)
#define S_SaveSettings ((void __cdecl (*)(void))0x004550C0)
#define S_LoadSettings ((void __cdecl (*)(void))0x00455140)
-#define S_SoundPlaySample ((int32_t __cdecl (*)(int32_t channel, UINT16 volume, int32_t pitch, int32_t pan))0x00455220)
-#define S_Sound_CalculateSampleVolume ((int32_t __cdecl (*)(DWORD volume))0x00455270)
-#define S_Sound_CalculateSamplePan ((int32_t __cdecl (*)(int16_t pan))0x004552A0)
-#define S_SoundPlaySampleLooped ((int32_t __cdecl (*)(int32_t channel, UINT16 volume, DWORD pitch, int32_t pan))0x004552D0)
-#define S_SoundSetPanAndVolume ((void __cdecl (*)(int32_t channel, int32_t pan, UINT16 volume))0x00455320)
-#define S_SoundSetPitch ((void __cdecl (*)(int32_t channel, DWORD pitch))0x00455360)
-#define S_SoundSetMasterVolume ((void __cdecl (*)(DWORD volume))0x00455380)
-#define S_SoundStopSample ((void __cdecl (*)(int32_t channel))0x00455390)
-#define S_SoundStopAllSamples ((void __cdecl (*)(void))0x004553B0)
-#define S_SoundSampleIsPlaying ((BOOL __cdecl (*)(int32_t channel))0x004553C0)
-#define CD_Init ((bool __cdecl (*)(void))0x004553E0)
-#define CD_Cleanup ((void __cdecl (*)(void))0x00455460)
-#define S_CDPlay ((void __cdecl (*)(int16_t trackID, BOOL isLooped))0x00455500)
-#define S_CDStop ((void __cdecl (*)(void))0x00455570)
-#define StartSyncedAudio ((BOOL __cdecl (*)(int32_t trackID))0x004555B0)
-#define S_CDGetLoc ((DWORD __cdecl (*)(void))0x00455640)
-#define Music_SetVolume ((void __cdecl (*)(int32_t volume))0x004556B0)
#define CopyBitmapPalette ((void __cdecl (*)(RGB888 *srcPal, BYTE *srcBitmap, int32_t bitmapSize, RGB888 *destPal))0x004557A0)
#define FindNearestPaletteEntry ((BYTE __cdecl (*)(RGB888 *palette, int32_t red, int32_t green, int32_t blue, bool ignoreSysPalette))0x004558E0)
#define SyncSurfacePalettes ((void __cdecl (*)(void *srcData, int32_t width, int32_t height, int32_t srcPitch, RGB888 *srcPalette, void *dstData, int32_t dstPitch, RGB888 *dstPalette, bool preserveSysPalette))0x004559B0)
diff --git a/src/global/types.h b/src/global/types.h
index 53927dec..2d7b587e 100644
--- a/src/global/types.h
+++ b/src/global/types.h
@@ -3,6 +3,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -129,14 +130,14 @@ typedef struct SOUND_ADAPTER {
} SOUND_ADAPTER;
typedef struct SOUND_ADAPTER_NODE {
- struct SoundAdapterNode_t *next;
- struct SoundAdapterNode_t *previous;
+ struct SOUND_ADAPTER_NODE *next;
+ struct SOUND_ADAPTER_NODE *previous;
SOUND_ADAPTER body;
} SOUND_ADAPTER_NODE;
typedef struct SOUND_ADAPTER_LIST {
- struct SoundAdapterNode_t *head;
- struct SoundAdapterNode_t *tail;
+ struct SOUND_ADAPTER_NODE *head;
+ struct SOUND_ADAPTER_NODE *tail;
DWORD dwCount;
} SOUND_ADAPTER_LIST;
diff --git a/src/global/vars.h b/src/global/vars.h
index 5108a621..5969da45 100644
--- a/src/global/vars.h
+++ b/src/global/vars.h
@@ -7,6 +7,7 @@
// clang-format off
#define g_CD_TrackID VAR_U_(0x004640BC, int16_t)
+#define g_FlipEffect VAR_U_(0x004640C4, int32_t)
#define g_OptionMusicVolume VAR_U_(0x00465A60, int16_t)
#define g_ViewportAspectRatio VAR_I_(0x0046C304, float, 0.0f)
#define g_PhdWinTop VAR_U_(0x0046E310, int32_t)
@@ -53,7 +54,9 @@
#define g_SoundIsActive VAR_U_(0x0051E6C4, int32_t)
#define g_Lara VAR_U_(0x005206E0, struct LARA_INFO)
#define g_LaraItem VAR_U_(0x005207BC, struct ITEM_INFO *)
+#define g_SoundFxCount VAR_U_(0x00521FDC, int32_t)
#define g_Rooms VAR_U_(0x0052618C, struct ROOM_INFO *)
+#define g_FlipStatus VAR_U_(0x00526240, int32_t)
#define g_Items ARRAY_(0x005262F0, struct ITEM_INFO, [])
#define g_NumCineFrames VAR_U_(0x005262F6, int16_t)
#define g_CineData VAR_I_(0x005262F8, CINE_FRAME *, NULL)
diff --git a/src/inject_exec.c b/src/inject_exec.c
index f58596f6..63bf4c07 100644
--- a/src/inject_exec.c
+++ b/src/inject_exec.c
@@ -5,11 +5,17 @@
#include "game/matrix.h"
#include "game/shell.h"
#include "inject_util.h"
+#include "specific/s_sndpc.h"
+#include "specific/s_sound.h"
+#include "specific/s_winvid.h"
static void Inject_Camera(void);
static void Inject_Math(void);
static void Inject_Matrix(void);
static void Inject_Shell(void);
+static void Inject_S_Audio_Sample(void);
+static void Inject_S_SndPC(void);
+static void Inject_S_WinVid(void);
static void Inject_Camera(void)
{
@@ -54,10 +60,63 @@ static void Inject_Shell(void)
INJECT(1, 0x0044E890, Shell_ExitSystem);
}
+static void Inject_S_Audio_Sample(void)
+{
+ INJECT(1, 0x00447BC0, S_Audio_Sample_GetAdapter);
+ INJECT(1, 0x00447C10, S_Audio_Sample_CloseAllTracks);
+ INJECT(1, 0x00447C40, S_Audio_Sample_Load);
+ INJECT(1, 0x00447D50, S_Audio_Sample_IsTrackPlaying);
+ INJECT(1, 0x00447DA0, S_Audio_Sample_Play);
+ INJECT(1, 0x00447E90, S_Audio_Sample_GetFreeTrackIndex);
+ INJECT(1, 0x00447ED0, S_Audio_Sample_AdjustTrackVolumeAndPan);
+ INJECT(1, 0x00447F00, S_Audio_Sample_AdjustTrackPitch);
+ INJECT(1, 0x00447F40, S_Audio_Sample_CloseTrack);
+ INJECT(1, 0x00447FB0, S_Audio_Sample_Init);
+ INJECT(1, 0x00448050, S_Audio_Sample_DSoundEnumerate);
+ INJECT(1, 0x00448070, S_Audio_Sample_DSoundEnumCallback);
+ INJECT(1, 0x00448160, S_Audio_Sample_Init2);
+ INJECT(1, 0x004482E0, S_Audio_Sample_DSoundCreate);
+ INJECT(1, 0x00448300, S_Audio_Sample_DSoundBufferTest);
+ INJECT(1, 0x004483D0, S_Audio_Sample_Shutdown);
+ INJECT(1, 0x00448400, S_Audio_Sample_IsEnabled);
+}
+
+static void Inject_S_SndPC(void)
+{
+ INJECT(1, 0x00455220, S_SoundPlaySample);
+ INJECT(1, 0x00455270, S_Sound_CalculateSampleVolume);
+ INJECT(1, 0x004552A0, S_Sound_CalculateSamplePan);
+ INJECT(1, 0x004552D0, S_SoundPlaySampleLooped);
+ INJECT(1, 0x00455320, S_SoundSetPanAndVolume);
+ INJECT(1, 0x00455360, S_SoundSetPitch);
+ INJECT(1, 0x00455380, S_SoundSetMasterVolume);
+ INJECT(1, 0x00455390, S_SoundStopSample);
+ INJECT(1, 0x004553B0, S_SoundStopAllSamples);
+ INJECT(1, 0x004553C0, S_SoundSampleIsPlaying);
+ INJECT(1, 0x004553E0, CD_Init);
+ INJECT(1, 0x00455460, CD_Cleanup);
+ INJECT(1, 0x00455500, S_CDPlay);
+ INJECT(1, 0x00455570, S_CDStop);
+ INJECT(1, 0x004555B0, StartSyncedAudio);
+ INJECT(1, 0x00455640, S_CDGetLoc);
+ INJECT(1, 0x004556B0, Music_SetVolume);
+}
+
+static void Inject_S_WinVid(void)
+{
+ INJECT(1, 0x00447550, FlaggedStringCreate);
+ INJECT(1, 0x00446100, FlaggedStringsCreate);
+ INJECT(1, 0x00445F00, FlaggedStringDelete);
+}
+
void Inject_Exec(void)
{
Inject_Camera();
- Inject_Matrix();
Inject_Math();
+ Inject_Matrix();
Inject_Shell();
+
+ Inject_S_Audio_Sample();
+ Inject_S_SndPC();
+ Inject_S_WinVid();
}
diff --git a/src/lib/dsound.h b/src/lib/dsound.h
new file mode 100644
index 00000000..875275c4
--- /dev/null
+++ b/src/lib/dsound.h
@@ -0,0 +1,11 @@
+#pragma once
+
+#include
+
+#define DirectSoundCreate \
+ ((HRESULT(__stdcall *)( \
+ LPCGUID pcGuidDevice, LPDIRECTSOUND * ppDS, \
+ LPUNKNOWN pUnkOuter))0x00458CEE)
+#define DirectSoundEnumerateA \
+ ((HRESULT(__stdcall *)( \
+ LPDSENUMCALLBACKA pDSEnumCallback, LPVOID pContext))0x00458CE8)
diff --git a/src/lib/winmm.c b/src/lib/winmm.c
new file mode 100644
index 00000000..e9b74adb
--- /dev/null
+++ b/src/lib/winmm.c
@@ -0,0 +1,11 @@
+#include "lib/winmm.h"
+
+MMRESULT(__stdcall *g_MM_auxGetDevCapsA)
+(UINT_PTR uDeviceID, LPAUXCAPSA pac, UINT cbac);
+UINT(__stdcall *g_MM_auxGetNumDevs)(void) = NULL;
+MMRESULT(__stdcall *g_MM_auxSetVolume)(UINT uDeviceID, DWORD dwVolume) = NULL;
+MCIERROR(__stdcall *g_MM_mciSendCommandA)
+(MCIDEVICEID mciId, UINT uMsg, DWORD_PTR dwParam1, DWORD_PTR dwParam2) = NULL;
+MCIERROR(__stdcall *g_MM_mciSendStringA)
+(LPCSTR lpszCommand, LPSTR lpszReturnString, UINT cchReturn,
+ HANDLE hwndCallback) = NULL;
diff --git a/src/lib/winmm.h b/src/lib/winmm.h
new file mode 100644
index 00000000..35fe835f
--- /dev/null
+++ b/src/lib/winmm.h
@@ -0,0 +1,19 @@
+#pragma once
+
+#include
+
+extern MMRESULT(__stdcall *g_MM_auxGetDevCapsA)(
+ UINT_PTR uDeviceID, LPAUXCAPSA pac, UINT cbac);
+extern UINT(__stdcall *g_MM_auxGetNumDevs)(void);
+extern MMRESULT(__stdcall *g_MM_auxSetVolume)(UINT uDeviceID, DWORD dwVolume);
+extern MCIERROR(__stdcall *g_MM_mciSendCommandA)(
+ MCIDEVICEID mciId, UINT uMsg, DWORD_PTR dwParam1, DWORD_PTR dwParam2);
+extern MCIERROR(__stdcall *g_MM_mciSendStringA)(
+ LPCSTR lpszCommand, LPSTR lpszReturnString, UINT cchReturn,
+ HANDLE hwndCallback);
+
+#define auxGetDevCapsA g_MM_auxGetDevCapsA
+#define auxGetNumDevs g_MM_auxGetNumDevs
+#define auxSetVolume g_MM_auxSetVolume
+#define mciSendCommandA g_MM_mciSendCommandA
+#define mciSendStringA g_MM_mciSendStringA
diff --git a/src/main_dll.c b/src/main_dll.c
index a2aee2a9..9966292e 100644
--- a/src/main_dll.c
+++ b/src/main_dll.c
@@ -1,9 +1,19 @@
#include "inject_exec.h"
+#include "lib/winmm.h"
#include "log.h"
#include
#include
+static void LoadWinMM(void)
+{
+ HANDLE g_WinMM = LoadLibrary("winmm.dll");
+ auxGetNumDevs = GetProcAddress(g_WinMM, "auxGetNumDevs");
+ auxSetVolume = GetProcAddress(g_WinMM, "auxSetVolume");
+ mciSendCommandA = GetProcAddress(g_WinMM, "mciSendCommandA");
+ mciSendStringA = GetProcAddress(g_WinMM, "mciSendStringA");
+}
+
BOOL APIENTRY
DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
@@ -12,6 +22,7 @@ DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
Log_Init();
LOG_DEBUG("Injected\n");
+ LoadWinMM();
Inject_Exec();
break;
diff --git a/src/main_exe.c b/src/main_exe.c
index c7b08cac..d98e7d23 100644
--- a/src/main_exe.c
+++ b/src/main_exe.c
@@ -5,73 +5,86 @@
// The path to the legitimate host process
const char *hostProcessPath = "Tomb2.exe";
-bool fileExists(const char *filePath)
+static bool FileExists(const char *path)
{
- DWORD fileAttributes = GetFileAttributes(filePath);
-
+ DWORD fileAttributes = GetFileAttributes(path);
if (fileAttributes != INVALID_FILE_ATTRIBUTES
&& !(fileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
return true;
}
-
return false;
}
-int main()
+static bool InjectDLL(HANDLE process_handle, const char *dll_path)
{
- char dll_path[MAX_PATH];
- GetModuleFileNameA(NULL, dll_path, MAX_PATH);
- strcpy(strstr(dll_path, ".exe"), ".dll");
- fprintf(stderr, "injecting %s\n", dll_path);
-
- STARTUPINFO si;
- ZeroMemory(&si, sizeof(si));
- si.cb = sizeof(si);
-
- PROCESS_INFORMATION pi;
- ZeroMemory(&pi, sizeof(pi));
-
- if (!CreateProcess(
- hostProcessPath, NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL,
- NULL, &si, &pi)) {
- fprintf(stderr, "Failed to create the process.\n");
- return 1;
- }
-
+ bool status = false;
LPVOID loadLibraryAddr =
(LPVOID)GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA");
- if (!fileExists(dll_path)) {
+ fprintf(stderr, "Injecting %s\n", dll_path);
+
+ if (!FileExists(dll_path)) {
fprintf(stderr, "DLL does not exist.\n");
- return 1;
+ goto finish;
}
- LPVOID dllPathAddr = VirtualAllocEx(
- pi.hProcess, NULL, strlen(dll_path) + 1, MEM_RESERVE | MEM_COMMIT,
+ LPVOID dll_path_adr = VirtualAllocEx(
+ process_handle, NULL, strlen(dll_path) + 1, MEM_RESERVE | MEM_COMMIT,
PAGE_READWRITE);
- if (!dllPathAddr) {
+ if (!dll_path_adr) {
fprintf(stderr, "Failed to allocate remote memory.\n");
- return 1;
+ goto finish;
}
if (!WriteProcessMemory(
- pi.hProcess, dllPathAddr, dll_path, strlen(dll_path) + 1, NULL)) {
+ process_handle, dll_path_adr, dll_path, strlen(dll_path) + 1,
+ NULL)) {
fprintf(stderr, "Failed to write remote memory.\n");
- return 1;
+ goto finish;
}
HANDLE hRemoteThread = CreateRemoteThread(
- pi.hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)loadLibraryAddr,
- dllPathAddr, 0, NULL);
+ process_handle, NULL, 0, (LPTHREAD_START_ROUTINE)loadLibraryAddr,
+ dll_path_adr, 0, NULL);
if (hRemoteThread == INVALID_HANDLE_VALUE) {
fprintf(stderr, "Failed to create remote thread.\n");
- return 1;
+ goto finish;
}
WaitForSingleObject(hRemoteThread, INFINITE);
- VirtualFreeEx(pi.hProcess, dllPathAddr, strlen(dll_path) + 1, MEM_RELEASE);
+ VirtualFreeEx(
+ process_handle, dll_path_adr, strlen(dll_path) + 1, MEM_RELEASE);
CloseHandle(hRemoteThread);
+ status = true;
+finish:
+ return status;
+}
+
+int main()
+{
+ char dll_path[MAX_PATH];
+ GetModuleFileNameA(NULL, dll_path, MAX_PATH);
+ strcpy(strstr(dll_path, ".exe"), ".dll");
+
+ STARTUPINFO si;
+ ZeroMemory(&si, sizeof(si));
+ si.cb = sizeof(si);
+
+ PROCESS_INFORMATION pi;
+ ZeroMemory(&pi, sizeof(pi));
+
+ if (!CreateProcess(
+ hostProcessPath, NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL,
+ NULL, &si, &pi)) {
+ fprintf(stderr, "Failed to create the process.\n");
+ return 1;
+ }
+
+ if (!InjectDLL(pi.hProcess, dll_path)) {
+ return 1;
+ }
+
if (ResumeThread(pi.hThread) == (DWORD)-1) {
fprintf(stderr, "Failed to resume the execution of the process.\n");
return 1;
diff --git a/src/specific/s_pauld.c b/src/specific/s_pauld.c
new file mode 100644
index 00000000..64fd61a7
--- /dev/null
+++ b/src/specific/s_pauld.c
@@ -0,0 +1,278 @@
+#include "specific/s_pauld.h"
+
+#include "global/funcs.h"
+#include "global/types.h"
+#include "global/vars.h"
+#include "lib/winmm.h"
+#include "log.h"
+
+#include
+
+#define CD_ALIAS "T2"
+#define MAX_TRACKS 60
+
+typedef struct TRACK_INFO {
+ DWORD from;
+ DWORD to;
+ bool active;
+} TRACK_INFO;
+
+static TRACK_INFO g_Tracks[60];
+static bool m_IsCDAudioEnabled = false;
+
+bool __cdecl PaulD_CD_Init(void)
+{
+ static LPCTSTR audio_files[2] = {
+ "audio\\cdaudio.wav",
+ "audio\\cdaudio.mp3",
+ };
+
+ static LPCTSTR audio_types[2] = {
+ "waveaudio",
+ "mpegvideo",
+ };
+
+ HANDLE file;
+ DWORD file_size;
+ DWORD bytes_read;
+ DWORD offset;
+ char cmd_string[256];
+ char *buf;
+ int32_t rc;
+ int32_t audio_type = -1;
+
+ if (m_IsCDAudioEnabled) {
+ return true;
+ }
+
+ for (int32_t i = 0; i < 2; ++i) {
+ file = CreateFile(
+ audio_files[i], GENERIC_READ, 0, NULL, OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL, NULL);
+ if (file != INVALID_HANDLE_VALUE) {
+ audio_type = i;
+ CloseHandle(file);
+ break;
+ }
+ }
+ if (audio_type < 0) {
+ return false;
+ }
+
+ file = CreateFile(
+ "audio\\cdaudio.dat", GENERIC_READ, 0, NULL, OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL, NULL);
+ if (file == INVALID_HANDLE_VALUE) {
+ return false;
+ }
+
+ file_size = GetFileSize(file, NULL);
+ buf = (char *)malloc(file_size);
+ if (buf == NULL) {
+ CloseHandle(file);
+ return false;
+ }
+ rc = ReadFile(file, buf, file_size, &bytes_read, NULL);
+ CloseHandle(file);
+ if (!rc || bytes_read == 0) {
+ return false;
+ }
+
+ memset(g_Tracks, 0, sizeof(g_Tracks));
+ offset = 0;
+
+ while (offset < bytes_read) {
+ DWORD index, from, to;
+
+ while (buf[offset] == 0x0A || buf[offset] == 0x0D) {
+ if (++offset >= bytes_read) {
+ goto PARSE_END;
+ }
+ }
+ rc = sscanf(&buf[offset], "%lu %lu %lu", &index, &from, &to);
+ if (rc == 3 && index > 0 && index <= 60) {
+ g_Tracks[index - 1].active = true;
+ g_Tracks[index - 1].from = from;
+ g_Tracks[index - 1].to = to;
+ }
+ while (buf[offset] != 0x0A && buf[offset] != 0x0D) {
+ if (++offset >= bytes_read) {
+ goto PARSE_END;
+ }
+ }
+ }
+
+PARSE_END:
+ free(buf);
+
+ for (DWORD i = 0; i < MAX_TRACKS; ++i) {
+ if (!g_Tracks[i].active) {
+ continue;
+ }
+ if (g_Tracks[i].from >= g_Tracks[i].to && i < MAX_TRACKS - 1) {
+ for (DWORD j = i + 1; j < MAX_TRACKS; ++j) {
+ if (g_Tracks[j].active) {
+ g_Tracks[i].to = g_Tracks[j].from;
+ break;
+ }
+ }
+ }
+ if (g_Tracks[i].from >= g_Tracks[i].to && i > 0) {
+ for (int32_t j = i - 1; j >= 0; --j) {
+ if (g_Tracks[j].active) {
+ g_Tracks[i].from = g_Tracks[j].to;
+ break;
+ }
+ }
+ }
+ }
+
+ wsprintf(
+ cmd_string, "open %s type %s alias " CD_ALIAS, audio_files[audio_type],
+ audio_types[audio_type]);
+ rc = mciSendStringA(cmd_string, NULL, 0, 0);
+ if (rc == 0) {
+ mciSendStringA("set " CD_ALIAS " time format ms", NULL, 0, 0);
+ m_IsCDAudioEnabled = true;
+ }
+ return true;
+}
+
+void __cdecl PaulD_CD_Cleanup(void)
+{
+ if (!m_IsCDAudioEnabled) {
+ return;
+ }
+
+ PaulD_CDStop();
+ mciSendStringA("close " CD_ALIAS, NULL, 0, 0);
+ m_IsCDAudioEnabled = false;
+}
+
+// void __cdecl PaulD_CDLoop(void)
+// {
+// int32_t rc;
+// char status_string[32];
+// char cmd_string[256];
+//
+// if (g_CD_LoopTrack == 0 || ++g_CD_LoopCounter < 150) {
+// return;
+// }
+//
+// g_CD_LoopCounter = 0;
+// rc = mciSendStringA(
+// "status " CD_ALIAS " mode", status_string, sizeof(status_string), 0);
+//
+// if ((rc == 0) && !strncmp(status_string, "stopped",
+// sizeof(status_string))) {
+// wsprintf(
+// cmd_string, "play " CD_ALIAS " from %lu to %lu",
+// g_Tracks[g_CD_LoopTrack - 1].from, g_Tracks[g_CD_LoopTrack -
+// 1].to);
+// mciSendStringA(cmd_string, NULL, 0, 0);
+// }
+// }
+
+void __cdecl PaulD_CDPlay(int16_t track_id, bool is_looped)
+{
+ int16_t track;
+ char cmd_string[256];
+
+ if (g_OptionMusicVolume == 0) {
+ return;
+ }
+
+ track = GetRealTrack(track_id);
+ if (track < 1 || !g_Tracks[track - 1].active) {
+ return;
+ }
+
+ g_CD_TrackID = track_id;
+
+ wsprintf(
+ cmd_string, "play " CD_ALIAS " from %lu to %lu",
+ g_Tracks[track - 1].from, g_Tracks[track - 1].to);
+ MMRESULT result = mciSendStringA(cmd_string, NULL, 0, 0);
+
+ if (is_looped) {
+ g_CD_LoopTrack = track;
+ // g_CD_LoopCounter = 120;
+ }
+}
+
+void __cdecl PaulD_CDStop(void)
+{
+ if (g_CD_TrackID <= 0) {
+ return;
+ }
+
+ mciSendStringA("stop " CD_ALIAS, NULL, 0, 0);
+ g_CD_TrackID = 0;
+ g_CD_LoopTrack = 0;
+}
+
+bool __cdecl PaulD_StartSyncedAudio(int16_t track_id)
+{
+ int16_t track;
+ char cmd_string[256];
+
+ track = GetRealTrack(track_id);
+ if (track < 1 || !g_Tracks[track - 1].active) {
+ return false;
+ }
+
+ g_CD_TrackID = track_id;
+ if (mciSendStringA("set " CD_ALIAS " time format ms", NULL, 0, 0) != 0) {
+ return false;
+ }
+
+ wsprintf(
+ cmd_string, "play " CD_ALIAS " from %lu to %lu",
+ g_Tracks[track - 1].from, g_Tracks[track - 1].to);
+ return mciSendStringA(cmd_string, NULL, 0, 0) == 0;
+}
+
+uint32_t __cdecl PaulD_CDGetLoc(void)
+{
+ int16_t track;
+ char status_string[32];
+
+ if (mciSendStringA(
+ "status " CD_ALIAS " position", status_string,
+ sizeof(status_string), 0)
+ != 0) {
+ return 0;
+ }
+
+ track = GetRealTrack(g_CD_TrackID);
+ return (atol(status_string) - g_Tracks[track - 1].from) * 75 / 1000;
+}
+
+void __cdecl PaulD_CDVolume(int32_t volume)
+{
+ char cmd_string[256];
+
+ if (volume > 0) {
+ volume = (volume - 5) * 4;
+ }
+
+ wsprintf(cmd_string, "setaudio " CD_ALIAS " volume to %lu", volume);
+ mciSendStringA(cmd_string, NULL, 0, 0);
+
+ char status_string[32];
+ if (mciSendStringA(
+ "status " CD_ALIAS " mode", status_string, sizeof(status_string), 0)
+ != 0) {
+ return;
+ }
+
+ if (volume > 0) {
+ if (!strncmp(status_string, "paused", sizeof(status_string))) {
+ mciSendStringA("resume " CD_ALIAS, NULL, 0, 0);
+ }
+ } else {
+ if (!strncmp(status_string, "playing", sizeof(status_string))) {
+ mciSendStringA("pause " CD_ALIAS, NULL, 0, 0);
+ }
+ }
+}
diff --git a/src/specific/s_pauld.h b/src/specific/s_pauld.h
new file mode 100644
index 00000000..467b47db
--- /dev/null
+++ b/src/specific/s_pauld.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2017-2018 Michael Chaban. All rights reserved.
+ * CD Audio solution in this file was designed by PaulD.
+ * Original game is created by Core Design Ltd. in 1997.
+ * Lara Croft and Tomb Raider are trademarks of Embracer Group AB.
+ *
+ * This file is part of TR2Main.
+ *
+ * TR2Main 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.
+ *
+ * TR2Main 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 TR2Main. If not, see .
+ */
+
+#pragma once
+
+#include "global/types.h"
+
+#include
+#include
+
+bool __cdecl PaulD_CD_Init(void);
+void __cdecl PaulD_CD_Cleanup(void);
+// void __cdecl PaulD_CDLoop(void);
+void __cdecl PaulD_CDPlay(int16_t track_id, bool is_looped);
+void __cdecl PaulD_CDStop(void);
+bool __cdecl PaulD_StartSyncedAudio(int16_t track_id);
+uint32_t __cdecl PaulD_CDGetLoc(void);
+void __cdecl PaulD_CDVolume(int32_t volume);
diff --git a/src/specific/s_sndpc.c b/src/specific/s_sndpc.c
new file mode 100644
index 00000000..b265bdb5
--- /dev/null
+++ b/src/specific/s_sndpc.c
@@ -0,0 +1,317 @@
+#include "specific/s_sndpc.h"
+
+#include "global/const.h"
+#include "global/funcs.h"
+#include "global/vars.h"
+#include "lib/winmm.h"
+#include "log.h"
+#include "specific/s_pauld.h"
+#include "specific/s_sound.h"
+
+static bool g_PaulDActive = false;
+
+static HMODULE g_WinMM = NULL;
+
+static bool isCDAudioEnabled = false;
+static int32_t m_CDVolume = 0;
+
+int32_t __cdecl S_SoundPlaySample(
+ int32_t sample_id, int32_t volume, int32_t pitch, int32_t pan)
+{
+ if (!g_SoundIsActive) {
+ return -3;
+ }
+
+ int32_t calc_pan = S_Sound_CalculateSamplePan(pan);
+ int32_t calc_volume = S_Sound_CalculateSampleVolume(volume);
+ return S_Audio_Sample_Play(sample_id, calc_volume, pitch, calc_pan, 0);
+}
+
+int32_t __cdecl S_Sound_CalculateSampleVolume(int32_t volume)
+{
+ return (int32_t)(((double)(g_MasterVolume * volume) / 0x200000.p0 - 1.0)
+ * 5000.0);
+}
+
+int32_t __cdecl S_Sound_CalculateSamplePan(int16_t pan)
+{
+ return pan / 16;
+}
+
+int32_t __cdecl S_SoundPlaySampleLooped(
+ int32_t sample_id, int32_t volume, int32_t pitch, int32_t pan)
+{
+ if (!g_SoundIsActive) {
+ return -3;
+ }
+
+ int32_t calc_pan = S_Sound_CalculateSamplePan(pan);
+ int32_t calc_volume = S_Sound_CalculateSampleVolume(volume);
+ return S_Audio_Sample_Play(
+ sample_id, calc_volume, pitch, calc_pan, DSBPLAY_LOOPING);
+}
+
+void __cdecl S_SoundSetPanAndVolume(
+ int32_t track_id, int32_t pan, int32_t volume)
+{
+ if (g_SoundIsActive) {
+ int32_t calc_pan = S_Sound_CalculateSamplePan(pan);
+ int32_t calc_volume = S_Sound_CalculateSampleVolume(volume);
+ S_Audio_Sample_AdjustTrackVolumeAndPan(track_id, calc_volume, calc_pan);
+ }
+}
+
+void __cdecl S_SoundSetPitch(int32_t track_id, int32_t pitch)
+{
+ if (g_SoundIsActive) {
+ S_Audio_Sample_AdjustTrackPitch(track_id, pitch);
+ }
+}
+
+void __cdecl S_SoundSetMasterVolume(int32_t volume)
+{
+ g_MasterVolume = volume;
+}
+
+void __cdecl S_SoundStopSample(int32_t track_id)
+{
+ if (g_SoundIsActive) {
+ S_Audio_Sample_CloseTrack(track_id);
+ }
+}
+
+void __cdecl S_SoundStopAllSamples(void)
+{
+ if (g_SoundIsActive) {
+ for (int32_t i = 0; i < MAX_AUDIO_SAMPLE_TRACKS; ++i) {
+ S_Audio_Sample_CloseTrack(i);
+ }
+ }
+}
+
+bool __cdecl S_SoundSampleIsPlaying(int32_t track_id)
+{
+ if (!g_SoundIsActive) {
+ return FALSE;
+ }
+
+ return S_Audio_Sample_IsTrackPlaying(track_id);
+}
+
+#include "log.h"
+bool __cdecl CD_Init(void)
+{
+ MCI_OPEN_PARMS openParams;
+ MCI_SET_PARMS setParams;
+
+ g_PaulDActive = PaulD_CD_Init();
+ if (g_PaulDActive) {
+ return true;
+ }
+
+ if (isCDAudioEnabled) {
+ return true;
+ }
+
+ openParams.lpstrDeviceType = "cdaudio";
+ if (mciSendCommand(0, MCI_OPEN, MCI_OPEN_TYPE, (DWORD_PTR)&openParams)
+ == 0) {
+ g_MciDeviceID = openParams.wDeviceID;
+ setParams.dwTimeFormat = MCI_FORMAT_TMSF;
+ mciSendCommand(
+ g_MciDeviceID, MCI_SET, MCI_SET_TIME_FORMAT, (DWORD_PTR)&setParams);
+ isCDAudioEnabled = true;
+ }
+ return true;
+}
+
+void __cdecl CD_Cleanup(void)
+{
+ MCI_GENERIC_PARMS params;
+
+ if (g_PaulDActive) {
+ PaulD_CD_Cleanup();
+ return;
+ }
+
+ if (!isCDAudioEnabled) {
+ return;
+ }
+
+ mciSendCommand(g_MciDeviceID, MCI_STOP, 0, (DWORD_PTR)¶ms);
+ mciSendCommand(g_MciDeviceID, MCI_CLOSE, 0, (DWORD_PTR)¶ms);
+ isCDAudioEnabled = false;
+}
+
+// void __cdecl S_CDLoop(void) {
+// int32_t rc;
+// MCI_PLAY_PARMS playParams;
+// MCI_STATUS_PARMS statusParams;
+//
+// if( g_PaulDActive ) {
+// PaulD_CDLoop();
+// return;
+// }
+//
+// if( g_CD_LoopTrack == 0 || ++g_CD_LoopCounter < 150 ) {
+// return;
+// }
+//
+// g_CD_LoopCounter = 0;
+// statusParams.dwItem = MCI_STATUS_MODE;
+// rc = mciSendCommand(g_MciDeviceID, MCI_STATUS, MCI_STATUS_ITEM,
+// (DWORD_PTR)&statusParams); if( (rc == 0) && (statusParams.dwReturn ==
+// MCI_MODE_STOP) ) {
+// playParams.dwFrom = g_CD_LoopTrack;
+// playParams.dwTo = g_CD_LoopTrack + 1;
+// mciSendCommand(g_MciDeviceID, MCI_PLAY,
+// MCI_NOTIFY_FAILURE|MCI_NOTIFY_ABORTED, (DWORD_PTR)&playParams);
+// }
+// }
+
+void __cdecl S_CDPlay(int16_t track_id, bool is_looped)
+{
+ CD_Init();
+ LOG_DEBUG("track_id=%d is_looped=%d", track_id, is_looped);
+ int16_t track;
+ MCI_PLAY_PARMS playParams;
+
+ if (g_PaulDActive) {
+ PaulD_CDPlay(track_id, is_looped);
+ return;
+ }
+
+ if (g_OptionMusicVolume == 0) {
+ return;
+ }
+
+ g_CD_TrackID = track_id;
+ track = GetRealTrack(track_id);
+ playParams.dwFrom = track;
+ playParams.dwTo = track + 1;
+ mciSendCommand(
+ g_MciDeviceID, MCI_PLAY, MCI_NOTIFY_FAILURE | MCI_NOTIFY_ABORTED,
+ (DWORD_PTR)&playParams);
+
+ if (is_looped) {
+ g_CD_LoopTrack = track;
+ // g_CD_LoopCounter = 120;
+ }
+}
+
+void __cdecl S_CDStop(void)
+{
+ LOG_DEBUG("");
+ MCI_GENERIC_PARMS params;
+
+ if (g_PaulDActive) {
+ PaulD_CDStop();
+ return;
+ }
+
+ if (g_CD_TrackID > 0) {
+ mciSendCommand(g_MciDeviceID, MCI_STOP, 0, (DWORD_PTR)¶ms);
+ g_CD_TrackID = 0;
+ g_CD_LoopTrack = 0;
+ }
+}
+
+bool __cdecl StartSyncedAudio(int32_t track_id)
+{
+ LOG_DEBUG("%d", track_id);
+ int16_t track;
+ MCI_PLAY_PARMS playParams;
+ MCI_SET_PARMS setParams;
+
+ if (g_PaulDActive) {
+ return PaulD_StartSyncedAudio(track_id);
+ }
+
+ g_CD_TrackID = track_id;
+ track = GetRealTrack(track_id);
+
+ setParams.dwTimeFormat = MCI_FORMAT_TMSF;
+ if (mciSendCommand(
+ g_MciDeviceID, MCI_SET, MCI_SET_TIME_FORMAT, (DWORD_PTR)&setParams)
+ != 0) {
+ return FALSE;
+ }
+
+ playParams.dwFrom = track;
+ playParams.dwTo = track + 1;
+ return (
+ mciSendCommand(
+ g_MciDeviceID, MCI_PLAY, MCI_NOTIFY_FAILURE | MCI_NOTIFY_ABORTED,
+ (DWORD_PTR)&playParams)
+ == 0);
+}
+
+uint32_t __cdecl S_CDGetLoc(void)
+{
+ uint32_t pos;
+ MCI_STATUS_PARMS statusParams;
+
+ if (g_PaulDActive) {
+ return PaulD_CDGetLoc();
+ }
+
+ statusParams.dwItem = MCI_STATUS_POSITION;
+ if (mciSendCommand(
+ g_MciDeviceID, MCI_STATUS, MCI_STATUS_ITEM,
+ (DWORD_PTR)&statusParams)
+ != 0) {
+ return 0;
+ }
+
+ pos = statusParams.dwReturn;
+ // calculate audio frames position (75 audio frames per second)
+ return (MCI_TMSF_MINUTE(pos) * 60 + MCI_TMSF_SECOND(pos)) * 75
+ + MCI_TMSF_FRAME(pos);
+}
+
+void __cdecl Music_SetVolume(int32_t volume)
+{
+ if (!g_WinMM) {
+ return;
+ }
+ AUXCAPS caps;
+ bool isVolumeSet = false;
+ int32_t device_id = -1;
+ int32_t aux_dev_count = auxGetNumDevs();
+ m_CDVolume = volume; // NOTE: store current CD Audio volume
+
+ if (g_PaulDActive) {
+ PaulD_CDVolume(volume);
+ return;
+ }
+
+ if (aux_dev_count == 0) {
+ return;
+ }
+
+ volume *= 0x100; // 0 .. 255 -> 0..65280
+
+ for (int32_t i = 0; i < aux_dev_count; ++i) {
+ auxGetDevCaps(i, &caps, sizeof(AUXCAPS));
+
+ switch (caps.wTechnology) {
+ case AUXCAPS_CDAUDIO:
+ auxSetVolume(i, MAKELONG(volume, volume));
+ isVolumeSet = true;
+ break;
+
+ case AUXCAPS_AUXIN:
+ device_id = i;
+ break;
+ }
+ }
+
+ if (!isVolumeSet && device_id != -1) {
+ auxSetVolume(device_id, MAKELONG(volume, volume));
+ }
+}
+
+int32_t __cdecl S_GetCDVolume(void)
+{
+ return m_CDVolume;
+}
diff --git a/src/specific/s_sndpc.h b/src/specific/s_sndpc.h
new file mode 100644
index 00000000..836bd593
--- /dev/null
+++ b/src/specific/s_sndpc.h
@@ -0,0 +1,26 @@
+#pragma once
+
+#include "global/types.h"
+
+int32_t __cdecl S_SoundPlaySample(
+ int32_t channel, int32_t volume, int32_t pitch, int32_t pan);
+int32_t __cdecl S_Sound_CalculateSampleVolume(int32_t volume);
+int32_t __cdecl S_Sound_CalculateSamplePan(int16_t pan);
+int32_t __cdecl S_SoundPlaySampleLooped(
+ int32_t channel, int32_t volume, int32_t pitch, int32_t pan);
+void __cdecl S_SoundSetPanAndVolume(
+ int32_t channel, int32_t pan, int32_t volume);
+void __cdecl S_SoundSetPitch(int32_t channel, int32_t pitch);
+void __cdecl S_SoundSetMasterVolume(int32_t volume);
+void __cdecl S_SoundStopSample(int32_t channel);
+void __cdecl S_SoundStopAllSamples(void);
+bool __cdecl S_SoundSampleIsPlaying(int32_t channel);
+bool __cdecl CD_Init(void);
+void __cdecl CD_Cleanup(void);
+// void __cdecl S_CDLoop(void);
+void __cdecl S_CDPlay(int16_t track_id, bool is_looped);
+void __cdecl S_CDStop(void);
+bool __cdecl StartSyncedAudio(int32_t track_id);
+uint32_t __cdecl S_CDGetLoc(void);
+void __cdecl Music_SetVolume(int32_t volume);
+int32_t __cdecl S_GetCDVolume(void);
diff --git a/src/specific/s_sound.c b/src/specific/s_sound.c
new file mode 100644
index 00000000..b207af3c
--- /dev/null
+++ b/src/specific/s_sound.c
@@ -0,0 +1,354 @@
+#include "specific/s_sound.h"
+
+#include "game/shell.h"
+#include "global/const.h"
+#include "global/funcs.h"
+#include "global/types.h"
+#include "global/vars.h"
+#include "lib/dsound.h"
+#include "lib/winmm.h"
+#include "log.h"
+
+extern bool FlaggedStringCopy(
+ struct STRING_FLAGGED *dst, struct STRING_FLAGGED *src);
+extern void __thiscall FlaggedStringDelete(struct STRING_FLAGGED *item);
+extern void __thiscall FlaggedStringCreate(
+ struct STRING_FLAGGED *item, int32_t size);
+
+struct SOUND_ADAPTER_NODE *__cdecl S_Audio_Sample_GetAdapter(GUID *guid)
+{
+ struct SOUND_ADAPTER_NODE *adapter;
+
+ if (guid != NULL) {
+ for (adapter = g_SoundAdapterList.head; adapter;
+ adapter = adapter->next) {
+ if (!memcmp(&adapter->body.adapterGuid, guid, sizeof(GUID))) {
+ return adapter;
+ }
+ }
+ }
+ return g_PrimarySoundAdapter;
+}
+
+void __cdecl S_Audio_Sample_CloseAllTracks(void)
+{
+ if (!g_IsSoundEnabled) {
+ return;
+ }
+
+ for (int32_t i = 0; i < MAX_AUDIO_SAMPLE_BUFFERS; ++i) {
+ if (g_SampleBuffers[i] != NULL) {
+ IDirectSound_Release(g_SampleBuffers[i]);
+ g_SampleBuffers[i] = NULL;
+ }
+ }
+}
+
+bool __cdecl S_Audio_Sample_Load(
+ int32_t sample_idx, LPWAVEFORMATEX format, const void *data,
+ uint32_t data_size)
+{
+ LPVOID audio_ptr;
+ DWORD audio_bytes;
+ DSBUFFERDESC desc;
+
+ if (!g_DSound || !g_IsSoundEnabled
+ || sample_idx >= MAX_AUDIO_SAMPLE_BUFFERS) {
+ return false;
+ }
+
+ if (g_SampleBuffers[sample_idx] != NULL) {
+ IDirectSound_Release(g_SampleBuffers[sample_idx]);
+ g_SampleBuffers[sample_idx] = NULL;
+ }
+
+ desc.dwSize = sizeof(DSBUFFERDESC);
+ desc.dwFlags = DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLPAN | DSBCAPS_CTRLFREQUENCY
+ | DSBCAPS_LOCSOFTWARE;
+ desc.dwBufferBytes = data_size;
+ desc.dwReserved = 0;
+ desc.lpwfxFormat = format;
+
+ if FAILED (IDirectSound_CreateSoundBuffer(
+ g_DSound, &desc, &g_SampleBuffers[sample_idx], NULL)) {
+ return false;
+ }
+
+ if FAILED (IDirectSoundBuffer_Lock(
+ g_SampleBuffers[sample_idx], 0, data_size, &audio_ptr,
+ &audio_bytes, NULL, NULL, 0)) {
+ return false;
+ }
+
+ memcpy(audio_ptr, data, audio_bytes);
+
+ if FAILED (IDirectSoundBuffer_Unlock(
+ g_SampleBuffers[sample_idx], audio_ptr, audio_bytes, NULL,
+ 0)) {
+ return false;
+ }
+
+ g_SampleFreqs[sample_idx] = format->nSamplesPerSec;
+ return true;
+}
+
+bool __cdecl S_Audio_Sample_IsTrackPlaying(int32_t track_id)
+{
+ DWORD status;
+
+ if (!g_ChannelBuffers[track_id]
+ || FAILED(IDirectSoundBuffer_GetStatus(
+ g_ChannelBuffers[track_id], &status))) {
+ return false;
+ }
+
+ if ((status & DSBSTATUS_PLAYING) == 0) {
+ IDirectSoundBuffer_Release(g_ChannelBuffers[track_id]);
+ g_ChannelBuffers[track_id] = NULL;
+ return false;
+ }
+
+ return true;
+}
+
+int32_t __cdecl S_Audio_Sample_Play(
+ int32_t sample_idx, int32_t volume, int32_t pitch, int32_t pan,
+ uint32_t flags)
+{
+ LPDIRECTSOUNDBUFFER dsBuffer = NULL;
+ int32_t track_id = S_Audio_Sample_GetFreeTrackIndex();
+
+ if (track_id < 0) {
+ return -1;
+ }
+
+ if (FAILED(IDirectSound_DuplicateSoundBuffer(
+ g_DSound, g_SampleBuffers[sample_idx], &dsBuffer))
+ || FAILED(IDirectSoundBuffer_SetVolume(dsBuffer, volume))
+ || FAILED(IDirectSoundBuffer_SetFrequency(
+ dsBuffer, g_SampleFreqs[sample_idx] * pitch / PHD_ONE))
+ || FAILED(IDirectSoundBuffer_SetPan(dsBuffer, pan))
+ || FAILED(IDirectSoundBuffer_SetCurrentPosition(dsBuffer, 0))
+ || FAILED(IDirectSoundBuffer_Play(dsBuffer, 0, 0, flags))) {
+ return -2;
+ }
+
+ g_ChannelSamples[track_id] = sample_idx;
+ g_ChannelBuffers[track_id] = dsBuffer;
+
+ return track_id;
+}
+
+int32_t __cdecl S_Audio_Sample_GetFreeTrackIndex(void)
+{
+ for (int32_t i = 0; i < MAX_AUDIO_SAMPLE_TRACKS; ++i) {
+ if (!g_ChannelBuffers[i]) {
+ return i;
+ }
+ }
+
+ for (int32_t i = 0; i < MAX_AUDIO_SAMPLE_TRACKS; ++i) {
+ if (!S_Audio_Sample_IsTrackPlaying(i)) {
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+void __cdecl S_Audio_Sample_AdjustTrackVolumeAndPan(
+ int32_t track_id, int32_t volume, int32_t pan)
+{
+ if (track_id >= 0 && g_ChannelBuffers[track_id] != NULL) {
+ IDirectSoundBuffer_SetVolume(g_ChannelBuffers[track_id], volume);
+ IDirectSoundBuffer_SetPan(g_ChannelBuffers[track_id], pan);
+ }
+}
+
+void __cdecl S_Audio_Sample_AdjustTrackPitch(int32_t track_id, int32_t pitch)
+{
+ if (track_id >= 0 && g_ChannelBuffers[track_id] != NULL) {
+ IDirectSoundBuffer_SetFrequency(
+ g_ChannelBuffers[track_id],
+ g_SampleFreqs[g_ChannelSamples[track_id]] * pitch / PHD_ONE);
+ }
+}
+
+void __cdecl S_Audio_Sample_CloseTrack(int32_t track_id)
+{
+ if (track_id >= 0 && g_ChannelBuffers[track_id] != NULL) {
+ IDirectSoundBuffer_Stop(g_ChannelBuffers[track_id]);
+ IDirectSoundBuffer_Release(g_ChannelBuffers[track_id]);
+ g_ChannelBuffers[track_id] = NULL;
+ }
+}
+
+bool __cdecl S_Audio_Sample_Init(void)
+{
+ struct SOUND_ADAPTER_NODE *node, *nextNode;
+
+ for (node = g_SoundAdapterList.head; node; node = nextNode) {
+ nextNode = node->next;
+ FlaggedStringDelete(&node->body.module);
+ FlaggedStringDelete(&node->body.description);
+ free(node);
+ }
+
+ g_SoundAdapterList.head = NULL;
+ g_SoundAdapterList.tail = NULL;
+ g_SoundAdapterList.dwCount = 0;
+
+ g_PrimarySoundAdapter = NULL;
+
+ if (!S_Audio_Sample_DSoundEnumerate(&g_SoundAdapterList)) {
+ LOG_ERROR("Failed to enumerate sound devices");
+ return false;
+ }
+
+ for (node = g_SoundAdapterList.head; node; node = node->next) {
+ if (!node->body.lpAdapterGuid) {
+ g_PrimarySoundAdapter = node;
+ break;
+ }
+ }
+
+ LOG_ERROR("Finished loading sound");
+ return true;
+}
+
+bool __cdecl S_Audio_Sample_DSoundEnumerate(
+ struct SOUND_ADAPTER_LIST *adapter_list)
+{
+ return SUCCEEDED(DirectSoundEnumerateA(
+ S_Audio_Sample_DSoundEnumCallback, (LPVOID)adapter_list));
+}
+
+BOOL CALLBACK S_Audio_Sample_DSoundEnumCallback(
+ LPGUID guid, LPCTSTR description, LPCTSTR module, LPVOID context)
+{
+ struct SOUND_ADAPTER_LIST *adapter_list =
+ (struct SOUND_ADAPTER_LIST *)context;
+ struct SOUND_ADAPTER_NODE *adapter_node =
+ malloc(sizeof(struct SOUND_ADAPTER_NODE));
+
+ if (!adapter_node) {
+ return TRUE;
+ }
+
+ adapter_node->next = NULL;
+ adapter_node->previous = adapter_list->tail;
+
+ if (!adapter_list->head) {
+ adapter_list->head = adapter_node;
+ }
+
+ if (adapter_list->tail) {
+ adapter_list->tail->next = adapter_node;
+ }
+
+ adapter_list->tail = adapter_node;
+ adapter_list->dwCount++;
+
+ if (!guid) {
+ memset(&adapter_node->body.adapterGuid, 0, sizeof(GUID));
+ adapter_node->body.lpAdapterGuid = NULL;
+ } else {
+ adapter_node->body.adapterGuid = *guid;
+ adapter_node->body.lpAdapterGuid = &adapter_node->body.adapterGuid;
+ }
+
+ FlaggedStringCreate(&adapter_node->body.description, 256);
+ FlaggedStringCreate(&adapter_node->body.module, 256);
+ lstrcpy(adapter_node->body.description.lpString, description);
+ lstrcpy(adapter_node->body.module.lpString, module);
+
+ return TRUE;
+}
+
+void __cdecl S_Audio_Sample_Init2(HWND hwnd)
+{
+ memset(g_SampleBuffers, 0, sizeof(g_SampleBuffers));
+ memset(g_ChannelBuffers, 0, sizeof(g_ChannelBuffers));
+
+ g_Camera.is_lara_mic = g_SavedAppSettings.LaraMic;
+ g_IsSoundEnabled = false;
+
+ if (!g_SavedAppSettings.SoundEnabled
+ || !g_SavedAppSettings.PreferredSoundAdapter) {
+ return;
+ }
+
+ struct SOUND_ADAPTER *preferred =
+ &g_SavedAppSettings.PreferredSoundAdapter->body;
+ g_CurrentSoundAdapter = *preferred;
+
+ FlaggedStringCopy(
+ &g_CurrentSoundAdapter.description, &preferred->description);
+ FlaggedStringCopy(&g_CurrentSoundAdapter.module, &preferred->module);
+
+ if (!S_Audio_Sample_DSoundCreate(g_CurrentSoundAdapter.lpAdapterGuid)) {
+ return;
+ }
+
+ if (!hwnd) {
+ hwnd = g_GameWindowHandle;
+ }
+
+ if FAILED (IDirectSound_SetCooperativeLevel(
+ g_DSound, hwnd, DSSCL_EXCLUSIVE)) {
+ Shell_ExitSystem("Error: Can't set DSound cooperative level");
+ }
+
+ if (S_Audio_Sample_DSoundBufferTest()) {
+ g_IsSoundEnabled = true;
+ }
+}
+
+bool __cdecl S_Audio_Sample_DSoundCreate(GUID *guid)
+{
+ return SUCCEEDED(DirectSoundCreate(guid, &g_DSound, NULL));
+}
+
+bool __cdecl S_Audio_Sample_DSoundBufferTest(void)
+{
+ WAVEFORMATEX format;
+ DSBUFFERDESC desc;
+ LPDIRECTSOUNDBUFFER dsBuffer;
+
+ desc.dwSize = sizeof(DSBUFFERDESC);
+ desc.dwFlags = DSBCAPS_PRIMARYBUFFER;
+ desc.dwBufferBytes = 0;
+ desc.dwReserved = 0;
+ desc.lpwfxFormat = NULL;
+
+ if FAILED (IDirectSound_CreateSoundBuffer(
+ g_DSound, &desc, &dsBuffer, NULL)) {
+ return false;
+ }
+
+ format.wFormatTag = WAVE_FORMAT_PCM;
+ format.nChannels = 2;
+ format.nSamplesPerSec = 11025;
+ format.nAvgBytesPerSec = 44100;
+ format.nBlockAlign = 4;
+ format.wBitsPerSample = 16;
+ format.cbSize = 0;
+
+ bool result = SUCCEEDED(IDirectSoundBuffer_SetFormat(dsBuffer, &format));
+ IDirectSoundBuffer_Release(dsBuffer);
+ return result;
+}
+
+void __cdecl S_Audio_Sample_Shutdown(void)
+{
+ S_Audio_Sample_CloseAllTracks();
+ if (g_DSound != NULL) {
+ IDirectSound_Release(g_DSound);
+ g_DSound = NULL;
+ }
+}
+
+bool __cdecl S_Audio_Sample_IsEnabled(void)
+{
+ return g_IsSoundEnabled;
+}
diff --git a/src/specific/s_sound.h b/src/specific/s_sound.h
new file mode 100644
index 00000000..ac6849bb
--- /dev/null
+++ b/src/specific/s_sound.h
@@ -0,0 +1,31 @@
+#pragma once
+
+#include "global/types.h"
+
+#define VOLUME_PCT(x) \
+ (DSBVOLUME_MIN + (DSBVOLUME_MAX - DSBVOLUME_MIN) * (x) / 100)
+
+struct SOUND_ADAPTER_NODE *__cdecl S_Audio_Sample_GetAdapter(GUID *guid);
+void __cdecl S_Audio_Sample_CloseAllTracks(void);
+bool __cdecl S_Audio_Sample_Load(
+ int32_t sample_id, LPWAVEFORMATEX format, const void *data,
+ uint32_t data_size);
+bool __cdecl S_Audio_Sample_IsTrackPlaying(int32_t track_id);
+int32_t __cdecl S_Audio_Sample_Play(
+ int32_t sample_idx, int32_t volume, int32_t pitch, int32_t pan,
+ uint32_t flags);
+int32_t __cdecl S_Audio_Sample_GetFreeTrackIndex(void);
+void __cdecl S_Audio_Sample_AdjustTrackVolumeAndPan(
+ int32_t track_id, int32_t volume, int32_t pan);
+void __cdecl S_Audio_Sample_AdjustTrackPitch(int32_t track_id, int32_t pitch);
+void __cdecl S_Audio_Sample_CloseTrack(int32_t track_id);
+bool __cdecl S_Audio_Sample_Init(void);
+bool __cdecl S_Audio_Sample_DSoundEnumerate(
+ struct SOUND_ADAPTER_LIST *adapter_list);
+BOOL CALLBACK S_Audio_Sample_DSoundEnumCallback(
+ LPGUID guid, LPCTSTR description, LPCTSTR module, LPVOID context);
+void __cdecl S_Audio_Sample_Init2(HWND hwnd);
+bool __cdecl S_Audio_Sample_DSoundCreate(GUID *guid);
+bool __cdecl S_Audio_Sample_DSoundBufferTest(void);
+void __cdecl S_Audio_Sample_Shutdown(void);
+bool __cdecl S_Audio_Sample_IsEnabled(void);
diff --git a/src/specific/s_winvid.c b/src/specific/s_winvid.c
new file mode 100644
index 00000000..e31f47bb
--- /dev/null
+++ b/src/specific/s_winvid.c
@@ -0,0 +1,64 @@
+#include "specific/s_winvid.h"
+
+#include "global/types.h"
+
+void __thiscall FlaggedStringCreate(struct STRING_FLAGGED *item, DWORD dwSize)
+{
+ item->lpString = malloc(dwSize);
+
+ if (item->lpString != NULL) {
+ *item->lpString = 0;
+ item->isPresented = true;
+ }
+}
+
+void __thiscall FlaggedStringsCreate(struct DISPLAY_ADAPTER *adapter)
+{
+ LPTSTR lpDriverDescription = malloc(256);
+ LPTSTR lpDriverName = malloc(256);
+
+ if (lpDriverDescription) {
+ *lpDriverDescription = 0;
+ adapter->driverDescription.lpString = lpDriverDescription;
+ adapter->driverDescription.isPresented = true;
+ }
+
+ if (lpDriverName) {
+ *lpDriverName = 0;
+ adapter->driverName.lpString = lpDriverName;
+ adapter->driverName.isPresented = true;
+ }
+}
+
+void __thiscall FlaggedStringDelete(struct STRING_FLAGGED *item)
+{
+ if (item->isPresented && item->lpString) {
+ free(item->lpString);
+ item->lpString = NULL;
+ item->isPresented = false;
+ }
+}
+
+bool FlaggedStringCopy(struct STRING_FLAGGED *dst, struct STRING_FLAGGED *src)
+{
+ if (dst == NULL || src == NULL || dst == src || !src->isPresented) {
+ return false;
+ }
+
+ size_t srcLen = lstrlen(src->lpString);
+
+ dst->isPresented = false;
+ dst->lpString = malloc(srcLen + 1);
+
+ if (dst->lpString == NULL) {
+ return false;
+ }
+
+ if (srcLen > 0) {
+ lstrcpy(dst->lpString, src->lpString);
+ } else {
+ *dst->lpString = 0;
+ }
+ dst->isPresented = true;
+ return true;
+}
diff --git a/src/specific/s_winvid.h b/src/specific/s_winvid.h
new file mode 100644
index 00000000..a2452e85
--- /dev/null
+++ b/src/specific/s_winvid.h
@@ -0,0 +1,10 @@
+#pragma once
+
+#include "global/types.h"
+
+#include
+
+bool FlaggedStringCopy(struct STRING_FLAGGED *dst, struct STRING_FLAGGED *src);
+void __thiscall FlaggedStringCreate(struct STRING_FLAGGED *item, DWORD dwSize);
+void __thiscall FlaggedStringDelete(struct STRING_FLAGGED *item);
+void __thiscall FlaggedStringsCreate(struct DISPLAY_ADAPTER *adapter);