mnsound: merge to sound

This commit is contained in:
rr- 2021-11-05 20:39:24 +01:00 committed by Marcin Kurczewski
parent af767b58d1
commit aefcc47c96
9 changed files with 446 additions and 463 deletions

View file

@ -9,7 +9,6 @@
#include "game/items.h"
#include "game/lara.h"
#include "game/lot.h"
#include "game/mnsound.h"
#include "game/objects/keyhole.h"
#include "game/objects/puzzle_hole.h"
#include "game/objects/switch.h"

View file

@ -5,7 +5,6 @@
#include "config.h"
#include "game/game.h"
#include "game/lara.h"
#include "game/mnsound.h"
#include "game/option.h"
#include "game/overlay.h"
#include "game/savegame.h"

View file

@ -1,440 +0,0 @@
#include "game/mnsound.h"
#include "3dsystem/phd_math.h"
#include "game/game.h"
#include "global/vars.h"
#include "specific/init.h"
#include "specific/sndpc.h"
#include "util.h"
#include <stdio.h>
#define SOUND_RANGE 8
#define SOUND_RADIUS (SOUND_RANGE << 10)
#define SOUND_RANGE_MULT_CONSTANT ((int32_t)(32768 / SOUND_RADIUS))
#define MAX_VOLUME_CHANGE 0x2000
#define MAX_PITCH_CHANGE 10
#define MN_NOT_AUDIBLE -1
typedef enum SOUND_MODE {
SOUND_WAIT = 0,
SOUND_RESTART = 1,
SOUND_AMBIENT = 2,
} SOUND_MODE;
typedef enum SOUND_FLAG {
MN_FX_UNUSED = 0,
MN_FX_USED = 1 << 0,
MN_FX_AMBIENT = 1 << 1,
MN_FX_RESTARTED = 1 << 2,
MN_FX_NO_REVERB = 1 << 3,
} SOUND_FLAG;
typedef enum SAMPLE_FLAG {
NO_PAN = 1 << 12,
PITCH_WIBBLE = 1 << 13,
VOLUME_WIBBLE = 1 << 14,
} SAMPLE_FLAG;
static MN_SFX_PLAY_INFO SFXPlaying[MAX_PLAYING_FX] = { 0 };
static int32_t MnSoundMasterVolumeDefault = 32;
static int16_t MnAmbientLookup[MAX_AMBIENT_FX] = { -1 };
static int32_t MnAmbientLookupIdx = 0;
static MN_SFX_PLAY_INFO *mn_get_fx_slot(
int32_t sfx_num, uint32_t loudness, PHD_3DPOS *pos, int16_t mode);
static void mn_get_sound_params(MN_SFX_PLAY_INFO *slot);
static void mn_clear_fx_slot(MN_SFX_PLAY_INFO *slot);
static void mn_clear_handles(MN_SFX_PLAY_INFO *slot);
void mn_reset_sound_effects()
{
if (!SoundIsActive) {
return;
}
MnSoundMasterVolume = MnSoundMasterVolumeDefault;
for (int i = 0; i < MAX_PLAYING_FX; i++) {
mn_clear_fx_slot(&SFXPlaying[i]);
}
S_SoundStopAllSamples();
MnAmbientLookupIdx = 0;
for (int i = 0; i < MAX_SAMPLES; i++) {
if (SampleLUT[i] < 0) {
continue;
}
SAMPLE_INFO *s = &SampleInfos[SampleLUT[i]];
if (s->volume < 0) {
S_ExitSystemFmt(
"sample info for effect %d has incorrect volume(%d)", i,
s->volume);
}
if ((s->flags & 3) == SOUND_AMBIENT) {
if (MnAmbientLookupIdx >= MAX_AMBIENT_FX) {
S_ExitSystem("Ran out of ambient fx slots in "
"mn_reset_sound_effects()");
}
MnAmbientLookup[MnAmbientLookupIdx] = i;
MnAmbientLookupIdx++;
}
}
}
bool mn_sound_effect(int32_t sfx_num, PHD_3DPOS *pos, uint32_t flags)
{
if (!SoundIsActive) {
return false;
}
if (flags != SPM_ALWAYS
&& (flags & SPM_UNDERWATER)
!= (RoomInfo[Camera.pos.room_number].flags & RF_UNDERWATER)) {
return false;
}
if (SampleLUT[sfx_num] < 0) {
return false;
}
SAMPLE_INFO *s = &SampleInfos[SampleLUT[sfx_num]];
if (s->randomness && GetRandomDraw() > (int32_t)s->randomness) {
return false;
}
flags = 0;
int32_t pan = 0x7FFF;
int32_t mode = s->flags & 3;
uint32_t distance;
if (pos) {
int32_t x = pos->x - Camera.target.x;
int32_t y = pos->y - Camera.target.y;
int32_t z = pos->z - Camera.target.z;
if (ABS(x) > SOUND_RADIUS || ABS(y) > SOUND_RADIUS
|| ABS(z) > SOUND_RADIUS) {
return false;
}
distance = SQUARE(x) + SQUARE(y) + SQUARE(z);
if (!distance) {
pan = 0;
}
} else {
distance = 0;
pan = 0;
flags = MN_FX_NO_REVERB;
}
distance = phd_sqrt(distance);
int32_t volume = s->volume - distance * SOUND_RANGE_MULT_CONSTANT;
if (s->flags & VOLUME_WIBBLE) {
volume -= GetRandomDraw() * MAX_VOLUME_CHANGE >> 15;
}
if (s->flags & NO_PAN) {
pan = 0;
}
if (volume <= 0 && mode != SOUND_AMBIENT) {
return false;
}
if (pan) {
int16_t angle =
phd_atan(pos->z - LaraItem->pos.z, pos->x - LaraItem->pos.x);
angle -= LaraItem->pos.y_rot + Lara.torso_y_rot + Lara.head_y_rot;
pan = angle;
}
int32_t pitch = 100;
if (s->flags & PITCH_WIBBLE) {
pitch +=
((GetRandomDraw() * MAX_PITCH_CHANGE) / 16384) - MAX_PITCH_CHANGE;
}
int32_t vars = (s->flags >> 2) & 15;
int32_t sfx_id = s->number;
if (vars != 1) {
sfx_id += (GetRandomDraw() * vars) / 0x8000;
}
if (volume > 0x7FFF) {
volume = 0x7FFF;
}
switch (mode) {
case SOUND_WAIT: {
MN_SFX_PLAY_INFO *fxslot = mn_get_fx_slot(sfx_num, 0, pos, mode);
if (!fxslot) {
return false;
}
if (fxslot->mn_flags & MN_FX_RESTARTED) {
fxslot->mn_flags &= 0xFFFF - MN_FX_RESTARTED;
return true;
}
fxslot->handle = S_SoundPlaySample(sfx_id, volume, pitch, pan);
if (fxslot->handle == SOUND_INVALID_HANDLE) {
return false;
}
mn_clear_handles(fxslot);
fxslot->mn_flags = flags | MN_FX_USED;
fxslot->fxnum = sfx_num;
fxslot->pos = pos;
return true;
}
case SOUND_RESTART: {
MN_SFX_PLAY_INFO *fxslot = mn_get_fx_slot(sfx_num, 0, pos, mode);
if (!fxslot) {
return false;
}
if (fxslot->mn_flags & MN_FX_RESTARTED) {
S_SoundStopSample(fxslot->handle);
fxslot->handle = S_SoundPlaySample(sfx_id, volume, pitch, pan);
return true;
}
fxslot->handle = S_SoundPlaySample(sfx_id, volume, pitch, pan);
if (fxslot->handle == SOUND_INVALID_HANDLE) {
return false;
}
mn_clear_handles(fxslot);
fxslot->mn_flags = flags | MN_FX_USED;
fxslot->fxnum = sfx_num;
fxslot->pos = pos;
return true;
}
case SOUND_AMBIENT: {
uint32_t loudness = distance;
MN_SFX_PLAY_INFO *fxslot = mn_get_fx_slot(sfx_num, loudness, pos, mode);
if (!fxslot) {
return false;
}
fxslot->pos = pos;
if (fxslot->mn_flags & MN_FX_AMBIENT) {
if (volume > 0) {
fxslot->loudness = loudness;
fxslot->pan = pan;
fxslot->volume = volume;
} else {
fxslot->loudness = MN_NOT_AUDIBLE;
fxslot->volume = 0;
}
return true;
}
if (volume > 0) {
fxslot->handle =
S_SoundPlaySampleLooped(sfx_id, volume, pitch, pan);
if (fxslot->handle == SOUND_INVALID_HANDLE) {
mn_clear_fx_slot(fxslot);
return false;
}
mn_clear_handles(fxslot);
fxslot->loudness = loudness;
fxslot->fxnum = sfx_num;
fxslot->pan = pan;
fxslot->volume = volume;
fxslot->mn_flags |= MN_FX_AMBIENT | MN_FX_USED;
fxslot->pos = pos;
return true;
}
fxslot->loudness = MN_NOT_AUDIBLE;
return true;
}
}
return false;
}
static MN_SFX_PLAY_INFO *mn_get_fx_slot(
int32_t sfx_num, uint32_t loudness, PHD_3DPOS *pos, int16_t mode)
{
switch (mode) {
case SOUND_WAIT:
case SOUND_RESTART: {
MN_SFX_PLAY_INFO *last_free_slot = NULL;
for (int i = MnAmbientLookupIdx; i < MAX_PLAYING_FX; i++) {
MN_SFX_PLAY_INFO *result = &SFXPlaying[i];
if ((result->mn_flags & MN_FX_USED) && result->fxnum == sfx_num
&& result->pos == pos) {
result->mn_flags |= MN_FX_RESTARTED;
return result;
} else if (result->mn_flags == MN_FX_UNUSED) {
last_free_slot = result;
}
}
return last_free_slot;
}
case SOUND_AMBIENT:
for (int i = 0; i < MAX_AMBIENT_FX; i++) {
if (MnAmbientLookup[i] == sfx_num) {
MN_SFX_PLAY_INFO *result = &SFXPlaying[i];
if (result->mn_flags != MN_FX_UNUSED
&& result->loudness <= loudness) {
return NULL;
}
return result;
}
}
break;
}
return NULL;
}
void mn_reset_ambient_loudness()
{
if (!SoundIsActive) {
return;
}
for (int i = 0; i < MnAmbientLookupIdx; i++) {
MN_SFX_PLAY_INFO *slot = &SFXPlaying[i];
slot->loudness = MN_NOT_AUDIBLE;
}
}
void mn_stop_ambient_samples()
{
if (!SoundIsActive) {
return;
}
for (int i = 0; i < MnAmbientLookupIdx; i++) {
MN_SFX_PLAY_INFO *slot = &SFXPlaying[i];
if (S_SoundSampleIsPlaying(slot->handle)) {
S_SoundStopSample(slot->handle);
mn_clear_fx_slot(slot);
}
}
}
void mn_update_sound_effects()
{
if (!SoundIsActive) {
return;
}
for (int i = 0; i < MAX_PLAYING_FX; i++) {
MN_SFX_PLAY_INFO *slot = &SFXPlaying[i];
if (slot->mn_flags & MN_FX_USED) {
if (slot->mn_flags & MN_FX_AMBIENT) {
if (slot->loudness != MN_NOT_AUDIBLE
&& slot->handle != SOUND_INVALID_HANDLE) {
S_SoundSetPanAndVolume(
slot->handle, slot->pan, slot->volume);
} else {
if (slot->handle != SOUND_INVALID_HANDLE) {
S_SoundStopSample(slot->handle);
}
mn_clear_fx_slot(slot);
}
} else if (S_SoundSampleIsPlaying(slot->handle)) {
if (slot->pos != NULL) {
mn_get_sound_params(slot);
if (slot->volume > 0
&& slot->handle != SOUND_INVALID_HANDLE) {
S_SoundSetPanAndVolume(
slot->handle, slot->pan, slot->volume);
} else {
if (slot->handle != SOUND_INVALID_HANDLE) {
S_SoundStopSample(slot->handle);
}
mn_clear_fx_slot(slot);
}
}
} else {
mn_clear_fx_slot(slot);
}
}
}
}
static void mn_get_sound_params(MN_SFX_PLAY_INFO *slot)
{
SAMPLE_INFO *s = &SampleInfos[SampleLUT[slot->fxnum]];
int32_t x = slot->pos->x - Camera.target.x;
int32_t y = slot->pos->y - Camera.target.y;
int32_t z = slot->pos->z - Camera.target.z;
if (ABS(x) > SOUND_RADIUS || ABS(y) > SOUND_RADIUS
|| ABS(z) > SOUND_RADIUS) {
slot->volume = 0;
return;
}
uint32_t distance = SQUARE(x) + SQUARE(y) + SQUARE(z);
int32_t volume = s->volume - phd_sqrt(distance) * SOUND_RANGE_MULT_CONSTANT;
if (volume < 0) {
slot->volume = 0;
return;
}
if (volume > 0x7FFF) {
volume = 0x7FFF;
}
slot->volume = volume;
if (!distance || (s->flags & NO_PAN)) {
slot->pan = 0;
return;
}
int16_t angle = phd_atan(
slot->pos->z - LaraItem->pos.z, slot->pos->x - LaraItem->pos.x);
angle -= LaraItem->pos.y_rot + Lara.torso_y_rot + Lara.head_y_rot;
slot->pan = angle;
}
void mn_stop_sound_effect(int sfx_num, PHD_3DPOS *pos)
{
if (!SoundIsActive) {
return;
}
for (int i = 0; i < MAX_PLAYING_FX; i++) {
MN_SFX_PLAY_INFO *slot = &SFXPlaying[i];
if ((slot->mn_flags & MN_FX_USED)
&& S_SoundSampleIsPlaying(slot->handle)) {
if ((!pos && slot->fxnum == sfx_num)
|| (pos && sfx_num >= 0 && slot->fxnum == sfx_num)
|| (pos && sfx_num < 0)) {
S_SoundStopSample(slot->handle);
mn_clear_fx_slot(slot);
}
}
}
}
void mn_adjust_master_volume(int8_t volume)
{
MnSoundMasterVolumeDefault = volume & 0x3F;
MnSoundMasterVolume = volume & 0x3F;
}
static void mn_clear_fx_slot(MN_SFX_PLAY_INFO *slot)
{
slot->handle = SOUND_INVALID_HANDLE;
slot->pos = NULL;
slot->mn_flags = 0;
slot->volume = 0;
slot->pan = 0;
slot->loudness = MN_NOT_AUDIBLE;
slot->fxnum = -1;
}
static void mn_clear_handles(MN_SFX_PLAY_INFO *slot)
{
for (int i = 0; i < MAX_PLAYING_FX; i++) {
MN_SFX_PLAY_INFO *rslot = &SFXPlaying[i];
if (rslot != slot && rslot->handle == slot->handle) {
rslot->handle = SOUND_INVALID_HANDLE;
}
}
}

View file

@ -1,17 +0,0 @@
#ifndef T1M_GAME_MNSOUND_H
#define T1M_GAME_MNSOUND_H
#include "global/types.h"
#include <stdbool.h>
#include <stdint.h>
void mn_reset_sound_effects();
bool mn_sound_effect(int32_t sfx_num, PHD_3DPOS *pos, uint32_t flags);
void mn_reset_ambient_loudness();
void mn_stop_ambient_samples();
void mn_update_sound_effects();
void mn_stop_sound_effect(int sfx_num, PHD_3DPOS *pos);
void mn_adjust_master_volume(int8_t volume);
#endif

View file

@ -3,7 +3,6 @@
#include "config.h"
#include "game/game.h"
#include "game/inv.h"
#include "game/mnsound.h"
#include "game/requester.h"
#include "game/settings.h"
#include "game/sound.h"

View file

@ -2,8 +2,8 @@
#include "config.h"
#include "filesystem.h"
#include "game/mnsound.h"
#include "game/option.h"
#include "game/sound.h"
#include "global/const.h"
#include "global/types.h"
#include "global/vars.h"

View file

@ -43,7 +43,6 @@
#include "game/items.h"
#include "game/lara.h"
#include "game/lot.h"
#include "game/mnsound.h"
#include "game/objects/boat.h"
#include "game/objects/bridge.h"
#include "game/objects/cabin.h"
@ -60,6 +59,7 @@
#include "game/objects/trapdoor.h"
#include "game/overlay.h"
#include "game/savegame.h"
#include "game/sound.h"
#include "game/text.h"
#include "game/traps/damocles_sword.h"
#include "game/traps/dart.h"

View file

@ -1,12 +1,54 @@
#include "game/sound.h"
#include "game/mnsound.h"
#include "3dsystem/phd_math.h"
#include "game/game.h"
#include "global/vars.h"
#include "specific/init.h"
#include "specific/sndpc.h"
#include "util.h"
#include <stddef.h>
#include <stdio.h>
#define FLIPFLAG 0x40
#define UNFLIPFLAG 0x80
#define SOUND_RANGE 8
#define SOUND_RADIUS (SOUND_RANGE << 10)
#define SOUND_RANGE_MULT_CONSTANT ((int32_t)(32768 / SOUND_RADIUS))
#define MAX_VOLUME_CHANGE 0x2000
#define MAX_PITCH_CHANGE 10
#define MN_NOT_AUDIBLE -1
typedef enum SOUND_MODE {
SOUND_WAIT = 0,
SOUND_RESTART = 1,
SOUND_AMBIENT = 2,
} SOUND_MODE;
typedef enum SOUND_FLAG {
MN_FX_UNUSED = 0,
MN_FX_USED = 1 << 0,
MN_FX_AMBIENT = 1 << 1,
MN_FX_RESTARTED = 1 << 2,
MN_FX_NO_REVERB = 1 << 3,
} SOUND_FLAG;
typedef enum SAMPLE_FLAG {
NO_PAN = 1 << 12,
PITCH_WIBBLE = 1 << 13,
VOLUME_WIBBLE = 1 << 14,
} SAMPLE_FLAG;
static MN_SFX_PLAY_INFO SFXPlaying[MAX_PLAYING_FX] = { 0 };
static int32_t MnSoundMasterVolumeDefault = 32;
static int16_t MnAmbientLookup[MAX_AMBIENT_FX] = { -1 };
static int32_t MnAmbientLookupIdx = 0;
static MN_SFX_PLAY_INFO *mn_get_fx_slot(
int32_t sfx_num, uint32_t loudness, PHD_3DPOS *pos, int16_t mode);
static void mn_get_sound_params(MN_SFX_PLAY_INFO *slot);
static void mn_clear_fx_slot(MN_SFX_PLAY_INFO *slot);
static void mn_clear_handles(MN_SFX_PLAY_INFO *slot);
void Sound_UpdateEffects()
{
@ -39,3 +81,395 @@ void Sound_StopEffect(int32_t sfx_num, PHD_3DPOS *pos)
{
mn_stop_sound_effect(sfx_num, pos);
}
void mn_reset_sound_effects()
{
if (!SoundIsActive) {
return;
}
MnSoundMasterVolume = MnSoundMasterVolumeDefault;
for (int i = 0; i < MAX_PLAYING_FX; i++) {
mn_clear_fx_slot(&SFXPlaying[i]);
}
S_SoundStopAllSamples();
MnAmbientLookupIdx = 0;
for (int i = 0; i < MAX_SAMPLES; i++) {
if (SampleLUT[i] < 0) {
continue;
}
SAMPLE_INFO *s = &SampleInfos[SampleLUT[i]];
if (s->volume < 0) {
S_ExitSystemFmt(
"sample info for effect %d has incorrect volume(%d)", i,
s->volume);
}
if ((s->flags & 3) == SOUND_AMBIENT) {
if (MnAmbientLookupIdx >= MAX_AMBIENT_FX) {
S_ExitSystem("Ran out of ambient fx slots in "
"mn_reset_sound_effects()");
}
MnAmbientLookup[MnAmbientLookupIdx] = i;
MnAmbientLookupIdx++;
}
}
}
bool mn_sound_effect(int32_t sfx_num, PHD_3DPOS *pos, uint32_t flags)
{
if (!SoundIsActive) {
return false;
}
if (flags != SPM_ALWAYS
&& (flags & SPM_UNDERWATER)
!= (RoomInfo[Camera.pos.room_number].flags & RF_UNDERWATER)) {
return false;
}
if (SampleLUT[sfx_num] < 0) {
return false;
}
SAMPLE_INFO *s = &SampleInfos[SampleLUT[sfx_num]];
if (s->randomness && GetRandomDraw() > (int32_t)s->randomness) {
return false;
}
flags = 0;
int32_t pan = 0x7FFF;
int32_t mode = s->flags & 3;
uint32_t distance;
if (pos) {
int32_t x = pos->x - Camera.target.x;
int32_t y = pos->y - Camera.target.y;
int32_t z = pos->z - Camera.target.z;
if (ABS(x) > SOUND_RADIUS || ABS(y) > SOUND_RADIUS
|| ABS(z) > SOUND_RADIUS) {
return false;
}
distance = SQUARE(x) + SQUARE(y) + SQUARE(z);
if (!distance) {
pan = 0;
}
} else {
distance = 0;
pan = 0;
flags = MN_FX_NO_REVERB;
}
distance = phd_sqrt(distance);
int32_t volume = s->volume - distance * SOUND_RANGE_MULT_CONSTANT;
if (s->flags & VOLUME_WIBBLE) {
volume -= GetRandomDraw() * MAX_VOLUME_CHANGE >> 15;
}
if (s->flags & NO_PAN) {
pan = 0;
}
if (volume <= 0 && mode != SOUND_AMBIENT) {
return false;
}
if (pan) {
int16_t angle =
phd_atan(pos->z - LaraItem->pos.z, pos->x - LaraItem->pos.x);
angle -= LaraItem->pos.y_rot + Lara.torso_y_rot + Lara.head_y_rot;
pan = angle;
}
int32_t pitch = 100;
if (s->flags & PITCH_WIBBLE) {
pitch +=
((GetRandomDraw() * MAX_PITCH_CHANGE) / 16384) - MAX_PITCH_CHANGE;
}
int32_t vars = (s->flags >> 2) & 15;
int32_t sfx_id = s->number;
if (vars != 1) {
sfx_id += (GetRandomDraw() * vars) / 0x8000;
}
if (volume > 0x7FFF) {
volume = 0x7FFF;
}
switch (mode) {
case SOUND_WAIT: {
MN_SFX_PLAY_INFO *fxslot = mn_get_fx_slot(sfx_num, 0, pos, mode);
if (!fxslot) {
return false;
}
if (fxslot->mn_flags & MN_FX_RESTARTED) {
fxslot->mn_flags &= 0xFFFF - MN_FX_RESTARTED;
return true;
}
fxslot->handle = S_SoundPlaySample(sfx_id, volume, pitch, pan);
if (fxslot->handle == SOUND_INVALID_HANDLE) {
return false;
}
mn_clear_handles(fxslot);
fxslot->mn_flags = flags | MN_FX_USED;
fxslot->fxnum = sfx_num;
fxslot->pos = pos;
return true;
}
case SOUND_RESTART: {
MN_SFX_PLAY_INFO *fxslot = mn_get_fx_slot(sfx_num, 0, pos, mode);
if (!fxslot) {
return false;
}
if (fxslot->mn_flags & MN_FX_RESTARTED) {
S_SoundStopSample(fxslot->handle);
fxslot->handle = S_SoundPlaySample(sfx_id, volume, pitch, pan);
return true;
}
fxslot->handle = S_SoundPlaySample(sfx_id, volume, pitch, pan);
if (fxslot->handle == SOUND_INVALID_HANDLE) {
return false;
}
mn_clear_handles(fxslot);
fxslot->mn_flags = flags | MN_FX_USED;
fxslot->fxnum = sfx_num;
fxslot->pos = pos;
return true;
}
case SOUND_AMBIENT: {
uint32_t loudness = distance;
MN_SFX_PLAY_INFO *fxslot = mn_get_fx_slot(sfx_num, loudness, pos, mode);
if (!fxslot) {
return false;
}
fxslot->pos = pos;
if (fxslot->mn_flags & MN_FX_AMBIENT) {
if (volume > 0) {
fxslot->loudness = loudness;
fxslot->pan = pan;
fxslot->volume = volume;
} else {
fxslot->loudness = MN_NOT_AUDIBLE;
fxslot->volume = 0;
}
return true;
}
if (volume > 0) {
fxslot->handle =
S_SoundPlaySampleLooped(sfx_id, volume, pitch, pan);
if (fxslot->handle == SOUND_INVALID_HANDLE) {
mn_clear_fx_slot(fxslot);
return false;
}
mn_clear_handles(fxslot);
fxslot->loudness = loudness;
fxslot->fxnum = sfx_num;
fxslot->pan = pan;
fxslot->volume = volume;
fxslot->mn_flags |= MN_FX_AMBIENT | MN_FX_USED;
fxslot->pos = pos;
return true;
}
fxslot->loudness = MN_NOT_AUDIBLE;
return true;
}
}
return false;
}
static MN_SFX_PLAY_INFO *mn_get_fx_slot(
int32_t sfx_num, uint32_t loudness, PHD_3DPOS *pos, int16_t mode)
{
switch (mode) {
case SOUND_WAIT:
case SOUND_RESTART: {
MN_SFX_PLAY_INFO *last_free_slot = NULL;
for (int i = MnAmbientLookupIdx; i < MAX_PLAYING_FX; i++) {
MN_SFX_PLAY_INFO *result = &SFXPlaying[i];
if ((result->mn_flags & MN_FX_USED) && result->fxnum == sfx_num
&& result->pos == pos) {
result->mn_flags |= MN_FX_RESTARTED;
return result;
} else if (result->mn_flags == MN_FX_UNUSED) {
last_free_slot = result;
}
}
return last_free_slot;
}
case SOUND_AMBIENT:
for (int i = 0; i < MAX_AMBIENT_FX; i++) {
if (MnAmbientLookup[i] == sfx_num) {
MN_SFX_PLAY_INFO *result = &SFXPlaying[i];
if (result->mn_flags != MN_FX_UNUSED
&& result->loudness <= loudness) {
return NULL;
}
return result;
}
}
break;
}
return NULL;
}
void mn_reset_ambient_loudness()
{
if (!SoundIsActive) {
return;
}
for (int i = 0; i < MnAmbientLookupIdx; i++) {
MN_SFX_PLAY_INFO *slot = &SFXPlaying[i];
slot->loudness = MN_NOT_AUDIBLE;
}
}
void mn_stop_ambient_samples()
{
if (!SoundIsActive) {
return;
}
for (int i = 0; i < MnAmbientLookupIdx; i++) {
MN_SFX_PLAY_INFO *slot = &SFXPlaying[i];
if (S_SoundSampleIsPlaying(slot->handle)) {
S_SoundStopSample(slot->handle);
mn_clear_fx_slot(slot);
}
}
}
void mn_update_sound_effects()
{
if (!SoundIsActive) {
return;
}
for (int i = 0; i < MAX_PLAYING_FX; i++) {
MN_SFX_PLAY_INFO *slot = &SFXPlaying[i];
if (slot->mn_flags & MN_FX_USED) {
if (slot->mn_flags & MN_FX_AMBIENT) {
if (slot->loudness != MN_NOT_AUDIBLE
&& slot->handle != SOUND_INVALID_HANDLE) {
S_SoundSetPanAndVolume(
slot->handle, slot->pan, slot->volume);
} else {
if (slot->handle != SOUND_INVALID_HANDLE) {
S_SoundStopSample(slot->handle);
}
mn_clear_fx_slot(slot);
}
} else if (S_SoundSampleIsPlaying(slot->handle)) {
if (slot->pos != NULL) {
mn_get_sound_params(slot);
if (slot->volume > 0
&& slot->handle != SOUND_INVALID_HANDLE) {
S_SoundSetPanAndVolume(
slot->handle, slot->pan, slot->volume);
} else {
if (slot->handle != SOUND_INVALID_HANDLE) {
S_SoundStopSample(slot->handle);
}
mn_clear_fx_slot(slot);
}
}
} else {
mn_clear_fx_slot(slot);
}
}
}
}
static void mn_get_sound_params(MN_SFX_PLAY_INFO *slot)
{
SAMPLE_INFO *s = &SampleInfos[SampleLUT[slot->fxnum]];
int32_t x = slot->pos->x - Camera.target.x;
int32_t y = slot->pos->y - Camera.target.y;
int32_t z = slot->pos->z - Camera.target.z;
if (ABS(x) > SOUND_RADIUS || ABS(y) > SOUND_RADIUS
|| ABS(z) > SOUND_RADIUS) {
slot->volume = 0;
return;
}
uint32_t distance = SQUARE(x) + SQUARE(y) + SQUARE(z);
int32_t volume = s->volume - phd_sqrt(distance) * SOUND_RANGE_MULT_CONSTANT;
if (volume < 0) {
slot->volume = 0;
return;
}
if (volume > 0x7FFF) {
volume = 0x7FFF;
}
slot->volume = volume;
if (!distance || (s->flags & NO_PAN)) {
slot->pan = 0;
return;
}
int16_t angle = phd_atan(
slot->pos->z - LaraItem->pos.z, slot->pos->x - LaraItem->pos.x);
angle -= LaraItem->pos.y_rot + Lara.torso_y_rot + Lara.head_y_rot;
slot->pan = angle;
}
void mn_stop_sound_effect(int sfx_num, PHD_3DPOS *pos)
{
if (!SoundIsActive) {
return;
}
for (int i = 0; i < MAX_PLAYING_FX; i++) {
MN_SFX_PLAY_INFO *slot = &SFXPlaying[i];
if ((slot->mn_flags & MN_FX_USED)
&& S_SoundSampleIsPlaying(slot->handle)) {
if ((!pos && slot->fxnum == sfx_num)
|| (pos && sfx_num >= 0 && slot->fxnum == sfx_num)
|| (pos && sfx_num < 0)) {
S_SoundStopSample(slot->handle);
mn_clear_fx_slot(slot);
}
}
}
}
void mn_adjust_master_volume(int8_t volume)
{
MnSoundMasterVolumeDefault = volume & 0x3F;
MnSoundMasterVolume = volume & 0x3F;
}
static void mn_clear_fx_slot(MN_SFX_PLAY_INFO *slot)
{
slot->handle = SOUND_INVALID_HANDLE;
slot->pos = NULL;
slot->mn_flags = 0;
slot->volume = 0;
slot->pan = 0;
slot->loudness = MN_NOT_AUDIBLE;
slot->fxnum = -1;
}
static void mn_clear_handles(MN_SFX_PLAY_INFO *slot)
{
for (int i = 0; i < MAX_PLAYING_FX; i++) {
MN_SFX_PLAY_INFO *rslot = &SFXPlaying[i];
if (rslot != slot && rslot->handle == slot->handle) {
rslot->handle = SOUND_INVALID_HANDLE;
}
}
}

View file

@ -3,10 +3,19 @@
#include "global/types.h"
#include <stdbool.h>
#include <stdint.h>
void Sound_UpdateEffects();
void Sound_Effect(int32_t sfx_num, PHD_3DPOS *pos, uint32_t flags);
void Sound_StopEffect(int32_t sfx_num, PHD_3DPOS *pos);
void mn_reset_sound_effects();
bool mn_sound_effect(int32_t sfx_num, PHD_3DPOS *pos, uint32_t flags);
void mn_reset_ambient_loudness();
void mn_stop_ambient_samples();
void mn_update_sound_effects();
void mn_stop_sound_effect(int sfx_num, PHD_3DPOS *pos);
void mn_adjust_master_volume(int8_t volume);
#endif