Descent3/sndlib/soundload.cpp
Chris Sarbora 3da53e567f
Programmatically replace all __LINUX__ with POSIX
Steps:
```sh
srcs=$(mktemp)
find . -name "*.cpp" -or -name "*.c" -or -name "*.h" -or -name "*.hpp" -or -name "*.cc" -or -name "*.hh" > $srcs
xargs sed -i 's/ifndef __LINUX__/if !defined(POSIX)/' < $srcs
xargs sed -i 's/ifdef __LINUX__/if defined(POSIX)/' < $srcs
xargs sed -i 's/defined(__LINUX__)/defined(POSIX)/' < $srcs
```
2024-07-12 18:11:54 -05:00

710 lines
20 KiB
C++

/*
* Descent 3
* Copyright (C) 2024 Parallax Software
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* $Logfile: /DescentIII/Main/sndlib/soundload.cpp $
* $Revision: 59 $
* $Date: 10/21/99 3:23p $
* $Author: Kevin $
*
* Code to load sounds
*
* $Log: /DescentIII/Main/sndlib/soundload.cpp $
*
* 59 10/21/99 3:23p Kevin
* Mac merge w/memory savings
*
* 58 5/11/99 12:10a Ardussi
* changes to compile on Mac
*
* 57 5/08/99 3:30p Matt
* Added weapon-hit-water sound.
*
* 56 4/30/99 3:28p Matt
* Weapons now make a special sound when colliding with lava & volatile
* surfaces, instead of the standard hit-wall sound.
*
* 55 4/29/99 3:50p Matt
* Added hiss sound for volatile surface damage
*
* 54 4/29/99 1:10p Jeff
* added sounds for inventory and countermeasure switch
*
* 53 4/14/99 1:46a Jeff
* fixed case mismatched #includes
*
* 52 4/12/99 4:18p Jason
* remap textures during sound remapping
*
* 51 4/11/99 5:03p Matt
* Changed static sound remapping code to use simpler & more
* space-efficient scheme. Also deleted an unused entry in the static
* sound list.
*
* 50 3/04/99 10:57a Matt
* Added goal message notification sound
*
* 49 2/22/99 10:24p Matt
* Added a static sound for debris explosion
*
* 48 2/18/99 4:48p Matt
* Changed the default import volume for new sounds to 100%
*
* 47 2/18/99 2:49p Matt
* Added goal complete sound
*
* 46 2/10/99 4:38p Matt
* Misc. changes for table file parsing
*
* 45 1/29/99 12:48p Matt
* Rewrote the doorway system
*
* 44 1/13/99 6:55a Jeff
* fixed #includes to work for linux
*
* 43 11/23/98 1:50p Jason
* added thruster sounds
*
* 42 10/22/98 8:31p Chris
* Sounds use GlobalAlloc and GlobalFree
*
* 41 10/21/98 4:53p Jeff
* added some sounds to sounds array
*
* 40 10/20/98 2:09p Jeff
* added 2 more sounds to static sounds
*
* 39 10/20/98 12:49p Matt
* Removed obsolete sounds from static sound list.
*
* 38 10/19/98 7:19p Matt
* Added system to support different types of damage to the player and
* have these different types make different sounds.
*
* 37 10/19/98 11:57a Chris
* Update the sound system to use the import volume
*
* 36 10/14/98 1:02p Jason
* fixed FindSoundName issues
*
* 35 10/12/98 1:27p Jeff
* all mem_free's do set the value to NULL after they are complete
*
* 34 9/21/98 8:19p Chris
* Improved volatile and forcefield hits
*
* 33 9/18/98 1:27p Matt
* Added afterburner release sound
*
* 32 9/08/98 12:05p Jason
* moved doorway.h out of room.h
*
* 31 7/24/98 5:22p Samir
* took out WAV file stuff because low level sound libray needs this code.
*
* 30 6/19/98 3:03p Chris
* Made CheckAndForceSoundDataAlloc a SoundSystem function - useful for
* multiple mixers. Added IsSoundPlaying to the high level sound lib.
*
* 29 6/17/98 4:39p Chris
* Added the playing of 8bit samples with the 16 bit sound mixer
*
* 28 5/26/98 10:54p Chris
* Ooops again
*
* 27 5/26/98 10:42p Chris
* Fixed door sound paging
*
* 26 5/26/98 10:21p Chris
* Added door sound paging
*
* 25 5/22/98 11:59a Chris
* Fixed improper uses of FindSoundName and made the proper static sounds
*
* 24 5/17/98 4:08p Chris
* Fixed bugs with initial sound loading. :)
*
* 23 5/14/98 1:28p Chris
* Improved sound loading stuff
*
* 22 5/14/98 11:49a Chris
* Bettered the sound paging system
*
* 21 5/03/98 10:22p Matt
* Added breaking glass sound
*
* 20 5/03/98 5:38p Chris
* Added sounds to anim page
*
* 19 4/24/98 3:02p Chris
* Removed GlobalAlloc and GlobalFree
*
* 18 4/22/98 5:38p Chris
* Fixed problems with adding new sounds
*
* 17 4/22/98 11:55a Jeff
* fixed stack overrun in ChangeSoundFileName
*
* 16 4/21/98 2:35p Chris
* Made soundload use the standard mem_malloc stuff
*
* 15 4/06/98 5:13p Chris
* Sounds page in at the beginning of a level
*
* 14 3/31/98 3:49p Jason
* added memory lib
*
* 13 3/02/98 4:16p Chris
* Added 14 new fields to the AI Settings Dialog/page.
*
* 12 2/23/98 5:03p Chris
* Added the global alloc calls (deifned them to malloc and free when not
* Win32)
*
* 11 2/16/98 4:55p Chris
* Added default sounds for explosions
*
* 10 2/12/98 4:23p Chris
* Fixed problem with sound dialog and allowing users to enter invalid
* values
*
* 9 1/02/98 5:32p Chris
* More radical changes to the sound system
*
* 8 12/31/97 2:58a Chris
* Another major revision to the SoundLib. This cleaned up the code after
* removing the direct sound secondary buffers.
*
* 7 12/30/97 2:15p Chris
* Adding further support for software 3d stuff
*
* 6 12/22/97 6:19p Chris
* Moved weapon battery firing sound off the projectile (weapon) and into
* the weapon battery.
*
* 5 12/19/97 4:09p Chris
* New dynamically loading sounds
*
* 4 12/10/97 4:47p Chris
* Revision 1.0 of new sound library (no hardware -- uses primary buffer
* streaming)
*
* 3 7/15/97 7:29p Chris
* Added a sound for helicopter blades.
*
* 13 5/29/97 3:26p Chris
*
* 12 5/29/97 3:11p Chris
* Fixed loadsound
*
* 11 5/22/97 3:29p Jason
* made sounds loading faster
*
* 10 5/14/97 11:31p Jason
* fixed annoying printf
*
* 9 5/14/97 12:31p Chris
*
* 8 5/13/97 10:31p Matt
* Added hook for refueling sound
*
* $NoKeywords: $
*/
#include <cstring>
#include "pserror.h"
#include "ssl_lib.h"
#include "object.h"
#include "ddio.h"
#include "mem.h"
#include "soundload.h"
#include "weapon.h"
#include "ship.h"
#include "door.h"
#include "room.h"
#include "doorway.h"
#if defined(WIN32) || defined(POSIX)
#include "../manage/soundpage.h"
#include "../Descent3/sounds.h"
#endif
int Num_sounds = 0;
int Num_sound_files = 0;
const char *Static_sound_names[NUM_STATIC_SOUNDS] = {
TBL_SOUND("Default"), // 0 SOUND_NONE_INDEX
TBL_SOUND("Refuel"), // 1 SOUND_REFUELING
TBL_SOUND("DefaultRobotExplode1"), // 2 SOUND_ROBOT_EXPLODE_1
TBL_SOUND("DefaultRobotExplode2"), // 3 SOUND_ROBOT_EXPLODE_2
TBL_SOUND("DefaultBuildingExplode"), // 4 SOUND_BUILDING_EXPLODE
TBL_SOUND("BreakingGlass"), // 5 SOUND_BREAKING_GLASS
TBL_SOUND("Tear01"), // 6 SOUND_MELEE_HIT_0
TBL_SOUND("Tear02"), // 7 SOUND_MELEE_HIT_1
TBL_SOUND("Afterburner"), // 8 SOUND_AFTERBURNER
TBL_SOUND("Drop unknown "), // 9 SOUND_ENERGY_DRAIN
TBL_SOUND("Missle lock"), // 10 SOUND_MISSLE_LOCK
TBL_SOUND("Powerup pickup"), // 11 SOUND_POWERUP_PICKUP
TBL_SOUND("You don't have it BEEP"), // 12 SOUND_DO_NOT_HAVE_IT
TBL_SOUND("Change primary weapon"), // 13 SOUND_CHANGE_PRIMARY
TBL_SOUND("Change secondary weapon"), // 14 SOUND_CHANGE_SECONDARY
TBL_SOUND("HitWall"), // 15 SOUND_PLAYER_HIT_WALL
TBL_SOUND("AftrBrnrTail"), // 16 SOUND_AFTERBURNER_TAIL
TBL_SOUND("Forcefield bounce"), // 17 SOUND_FORCEFIELD_BOUNCE
TBL_SOUND("Headlight1"), // 18 SOUND_HEADLIGHT
TBL_SOUND("Cheater!"), // 19 SOUND_CHEATER
TBL_SOUND("Energy Converter"), // 20 SOUND_ENERGY_CONVERTER
TBL_SOUND("CockpitSequenceTest1"), // 21 SOUND_COCKPIT
TBL_SOUND("Metallic Door Hit"), // 22 SOUND_METALLIC_DOOR_HIT
TBL_SOUND("Wall Fade ???"), // 23 SOUND_WALL_FADE
TBL_SOUND("Raindrop"), // 24 SOUND_RAINDROP
TBL_SOUND("Lightning"), // 25 SOUND_LIGHTNING
TBL_SOUND("HitEnergy"), // 26 SOUND_HIT_BY_ENERGY_WEAPON
TBL_SOUND("HitMatter"), // 27 SOUND_HIT_BY_MATTER_WEAPON
TBL_SOUND("HitConcussion"), // 28 SOUND_HIT_BY_CONCUSSIVE_FORCE
TBL_SOUND("HitFire"), // 29 SOUND_PLAYER_BURNING
TBL_SOUND("Menu Slider Click"), // 30 SOUND_MENU_SOUND_CLICK
TBL_SOUND("Hostage pickup"), // 31 SOUND_HOSTAGE_PICKUP
TBL_SOUND("Briefstartup1"), // 32 SOUND_BRIEF_STARTUP
TBL_SOUND("BriefStatic"), // 33 SOUND_BRIEF_STATIC
TBL_SOUND("Briefmonitoroff1"), // 34 SOUND_BRIEF_MONITOROFF
TBL_SOUND("Briefingrunning"), // 35 SOUND_BRIEF_RUNNING
TBL_SOUND("Briefbulb1"), // 36 SOUND_BRIEF_BULLB
TBL_SOUND("Briefingtype"), // 37 SOUND_BRIEF_TYPE
TBL_SOUND("ShpIdle"), // 38 SHIP_IDLE
TBL_SOUND("ShpForwardThrust"), // 39 SHIP_FORWARD_THRUST
TBL_SOUND("ShpForwardThrRelease"), // 40 SHIP_FORWARD_THRUST_RELEASE
TBL_SOUND("GoalComplete"), // 41 SOUND_GOAL_COMPLETE
TBL_SOUND("DebrisExplosion"), // 42 SOUND_DEBRIS_EXPLODE
TBL_SOUND("GameMessageNotify"), // 43 SOUND_GAME_MESSAGE
TBL_SOUND("Change countermeasure weapon"), // 44 SOUND_CHANGE_COUNTERMEASURE
TBL_SOUND("Change inventory item"), // 45 SOUND_CHANGE_INVENTORY
TBL_SOUND("VolatileHiss"), // 46 SOUND_VOLATILE_HISS
TBL_SOUND("WeaponHitLava"), // 47 SOUND_WEAPON_HIT_LAVA
TBL_SOUND("WeaponHitWater"), // 48 SOUND_WEAPON_HIT_WATER
};
// Allocs a sound file for use, returns -1 if error, else index on success
int AllocSoundFile() {
for (int i = 0; i < MAX_SOUND_FILES; i++) {
if (SoundFiles[i].used == 0) {
memset(&SoundFiles[i], 0, sizeof(sound_file_info));
SoundFiles[i].used = 1;
Num_sound_files++;
return i;
}
}
Int3(); // No sound files free!
return -1;
}
// Frees sound index n
void FreeSoundFile(int n) {
ASSERT(SoundFiles[n].used > 0);
SoundFiles[n].used = 0;
SoundFiles[n].name[0] = 0;
if (SoundFiles[n].sample_8bit) {
mem_free(SoundFiles[n].sample_8bit);
SoundFiles[n].sample_8bit = NULL;
}
if (SoundFiles[n].sample_16bit) {
mem_free(SoundFiles[n].sample_16bit);
SoundFiles[n].sample_16bit = NULL;
}
Num_sound_files--;
}
// Gets next sound file from n that has actually been alloced
int GetNextSoundFile(int n) {
int i;
ASSERT(n >= 0 && n < MAX_SOUND_FILES);
if (Num_sound_files == 0)
return -1;
for (i = n + 1; i < MAX_SOUND_FILES; i++)
if (SoundFiles[i].used)
return i;
for (i = 0; i < n; i++)
if (SoundFiles[i].used)
return i;
// this is the only one
return n;
}
// Gets previous sound file from n that has actually been alloced
int GetPrevSoundFile(int n) {
int i;
ASSERT(n >= 0 && n < MAX_SOUND_FILES);
if (Num_sound_files == 0)
return -1;
for (i = n - 1; i >= 0; i--) {
if (SoundFiles[i].used)
return i;
}
for (i = MAX_SOUND_FILES - 1; i > n; i--) {
if (SoundFiles[i].used)
return i;
}
// this is the only one
return n;
}
// Searches thru all sounds for a specific name, returns -1 if not found
// or index of sound with name
int FindSoundFileName(char *name) {
int i;
ASSERT(name != NULL);
for (i = 0; i < MAX_SOUND_FILES; i++)
if (SoundFiles[i].used && !stricmp(name, SoundFiles[i].name))
return i;
return -1;
}
// gets the filename from a path, plus appends our .wav extension
void ChangeSoundFileName(const char *src, char *dest) {
int limit;
char path[256], ext[256], filename[256];
limit = PAGENAME_LEN - 5;
ddio_SplitPath(src, path, filename, ext);
// Make sure we don't go over our name length limit
strncpy(dest, filename, limit);
strcat(dest, ".wav");
}
// Given a filename, loads the sound file.
int LoadSoundFile(const char *filename, float import_volume, bool f_get_data) {
int sound_file_index;
char extension[10];
char name[90];
int len;
ChangeSoundFileName(filename, name);
// See if the file was already loaded
sound_file_index = FindSoundFileName(name);
if (sound_file_index != -1)
return sound_file_index;
// Make room for the new sound
sound_file_index = AllocSoundFile();
if (sound_file_index == -1) {
mprintf(0, "SOUND LOADER: No free sound file slots are available.\n", filename);
Int3();
return -1;
}
// Validate the extension length
len = strlen(filename);
if (len < 4) {
mprintf(0, "SOUND LOADER: %s does not have a 3 charactor extension.\n", filename);
Int3(); // Get chris
goto error_state;
}
strcpy(SoundFiles[sound_file_index].name, name);
// Load the file by its type (as defined by the extension)
strncpy(extension, &filename[len - 3], 5);
if (strnicmp("wav", extension, 3) == 0) {
if (!SoundLoadWaveFile(filename, import_volume, sound_file_index, false, f_get_data)) {
mprintf(0, "SOUND LOADER: Error loading %s.\n", filename);
goto error_state;
}
} else {
mprintf(0, "SOUND LOADER: %s in not a supported file type.\n", extension);
goto error_state;
}
return sound_file_index;
error_state:
if (SoundFiles[sound_file_index].used)
FreeSoundFile(sound_file_index);
return -1;
}
// Sets all sounds to unused
void InitSounds() {
int i;
for (i = 0; i < MAX_SOUNDS; i++) {
Sounds[i].used = 0;
Sounds[i].name[0] = 0;
Sounds[i].flags = 0;
}
Num_sounds = 0;
for (i = 0; i < MAX_SOUND_FILES; i++) {
SoundFiles[i].name[0] = 0;
SoundFiles[i].used = 0;
}
Num_sound_files = 0;
}
// Allocs a sound for use, returns -1 if error, else index on success
int AllocSound() {
// Don't alloc sound 0, because 0 means something special (default/none)
for (int i = 1; i < MAX_SOUNDS; i++) {
if (Sounds[i].used == 0) {
memset(&Sounds[i], 0, sizeof(sound_info));
Sounds[i].min_distance = 10.0;
Sounds[i].max_distance = 256.0;
Sounds[i].outer_cone_volume = 1.0;
Sounds[i].inner_cone_angle = 360;
Sounds[i].outer_cone_angle = 360;
Sounds[i].import_volume = 1.0;
Sounds[i].flags = SPF_LISTENER_UPDATE;
Sounds[i].used = 1;
Num_sounds++;
return i;
}
}
Int3(); // No sounds free!
return -1;
}
// Frees sound index n
void FreeSound(int n) {
ASSERT(Sounds[n].used > 0);
Sounds[n].used = 0;
Sounds[n].name[0] = 0;
Sounds[n].flags = 0;
Num_sounds--;
}
// Gets next sound from n that has actually been alloced
int GetNextSound(int n) {
int i;
ASSERT(n >= 0 && n < MAX_SOUNDS);
if (Num_sounds == 0)
return -1;
for (i = n + 1; i < MAX_SOUNDS; i++)
if (Sounds[i].used)
return i;
for (i = 0; i < n; i++)
if (Sounds[i].used)
return i;
// this is the only one
return n;
}
// Gets previous sound from n that has actually been alloced
int GetPrevSound(int n) {
int i;
ASSERT(n >= 0 && n < MAX_SOUNDS);
if (Num_sounds == 0)
return -1;
for (i = n - 1; i >= 0; i--) {
if (Sounds[i].used)
return i;
}
for (i = MAX_SOUNDS - 1; i > n; i--) {
if (Sounds[i].used)
return i;
}
// this is the only one
return n;
}
// Searches thru all sounds for a specific name, returns -1 if not found
// or index of sound with name
int FindSoundName(const char *name) {
int i;
ASSERT(name != NULL);
for (i = 0; i < MAX_SOUNDS; i++)
if (Sounds[i].used && !stricmp(name, Sounds[i].name))
return i;
return -1;
}
// Given a filename, loads the sound.
int LoadSound(char *filename) {
int sound_handle;
sound_handle = mng_GetGuaranteedSoundPage(filename);
return sound_handle;
}
void RemapSounds() {
// Loop through the static sounds and move them to the correct slots
for (int i = 0; i < NUM_STATIC_SOUNDS; i++) {
int cur_index = FindSoundName(Static_sound_names[i]);
if (cur_index == -1) {
Int3(); // couldn't find statically-mapped sound
continue;
}
if (cur_index != i) { // not in right slot
if (Sounds[i].used) { // someone else in this slot, so swap
sound_info tsound = Sounds[i];
Sounds[i] = Sounds[cur_index];
Sounds[cur_index] = tsound;
RemapAllSoundObjects(i, MAX_SOUNDS);
RemapAllSoundObjects(cur_index, i);
RemapAllSoundObjects(MAX_SOUNDS, cur_index);
} else { // slot is unused, so just take it
Sounds[i] = Sounds[cur_index];
Sounds[cur_index].used = 0;
RemapAllSoundObjects(cur_index, i);
}
}
}
}
// goes thru every entity that could possible have a sound index (ie objects, robots, etc)
// and changes the old index to the new index
void RemapAllSoundObjects(int old_index, int new_index) {
int i, j, k;
// Remaps weapon sounds
for (i = 0; i < MAX_WEAPONS; i++) {
if (Weapons[i].used) {
for (j = 0; j < MAX_WEAPON_SOUNDS; j++) {
if (Weapons[i].sounds[j] == old_index) {
Weapons[i].sounds[j] = new_index;
}
}
}
}
// Remaps all non-wb object sounds
for (i = 0; i < MAX_OBJECT_IDS; i++) {
for (j = 0; j < MAX_OBJ_SOUNDS; j++) {
if (Object_info[i].sounds[j] == old_index) {
Object_info[i].sounds[j] = new_index;
}
}
if (Object_info[i].ai_info) {
for (j = 0; j < MAX_AI_SOUNDS; j++) {
if (Object_info[i].ai_info->sound[j] == old_index) {
Object_info[i].ai_info->sound[j] = new_index;
}
}
}
}
// Remaps weapon battery sounds contained by generic objects
for (i = 0; i < MAX_OBJECT_IDS; i++) {
if (Object_info[i].static_wb) {
for (j = 0; j < MAX_WBS_PER_OBJ; j++) {
for (k = 0; k < MAX_WB_FIRING_MASKS; k++) {
if (Object_info[i].static_wb[j].fm_fire_sound_index[k] == old_index) {
Object_info[i].static_wb[j].fm_fire_sound_index[k] = new_index;
}
}
}
}
}
// Remaps anim sounds contained by generic objects
for (i = 0; i < MAX_OBJECT_IDS; i++) {
if (Object_info[i].anim) {
for (j = 0; j < NUM_MOVEMENT_CLASSES; j++) {
for (k = 0; k < NUM_ANIMS_PER_CLASS; k++) {
if (Object_info[i].anim[j].elem[k].anim_sound_index == old_index) {
Object_info[i].anim[j].elem[k].anim_sound_index = new_index;
}
}
}
}
}
// Remaps weapons contained by Ships
for (i = 0; i < MAX_SHIPS; i++) {
for (j = 0; j < MAX_WBS_PER_OBJ; j++) {
if (Ships[i].firing_sound[j] == old_index) {
Ships[i].firing_sound[j] = new_index;
}
if (Ships[i].firing_release_sound[j] == old_index) {
Ships[i].firing_release_sound[j] = new_index;
}
for (k = 0; k < MAX_WB_FIRING_MASKS; k++) {
if (Ships[i].static_wb[j].fm_fire_sound_index[k] == old_index) {
Ships[i].static_wb[j].fm_fire_sound_index[k] = new_index;
}
}
}
}
for (i = 0; i <= Highest_room_index; i++) {
if (Rooms[i].used) {
if (Rooms[i].flags & RF_DOOR) {
door *door = &Doors[Rooms[i].doorway_data->doornum];
if (door->open_sound == old_index)
door->open_sound = new_index;
if (door->close_sound == old_index)
door->close_sound = new_index;
}
}
}
// Remaps textures
for (i = 0; i < MAX_TEXTURES; i++) {
if (GameTextures[i].used) {
if (GameTextures[i].sound == old_index) {
GameTextures[i].sound = new_index;
}
}
}
}