fallout2-ce/src/sound_effects_list.c

452 lines
11 KiB
C
Raw Normal View History

2022-05-19 01:51:26 -07:00
#include "sound_effects_list.h"
#include "db.h"
#include "debug.h"
#include "memory.h"
#include "sound_decoder.h"
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// 0x51C8F8
bool gSoundEffectsListInitialized = false;
// 0x51C8FC
int gSoundEffectsListDebugLevel = INT_MAX;
// sfxl_effect_path
// 0x51C900
char* gSoundEffectsListPath = NULL;
// sfxl_effect_path_len
// 0x51C904
int gSoundEffectsListPathLength = 0;
// sndlist.lst
//
// sfxl_list
// 0x51C908
SoundEffectsListEntry* gSoundEffectsListEntries = NULL;
// The length of [gSoundEffectsListEntries] array.
//
// 0x51C90C
int gSoundEffectsListEntriesLength = 0;
// 0x667F94
int _sfxl_compression;
// sfxl_tag_is_legal
// 0x4A98E0
bool soundEffectsListIsValidTag(int a1)
{
return soundEffectsListTagToIndex(a1, NULL) == SFXL_OK;
}
// sfxl_init
// 0x4A98F4
int soundEffectsListInit(const char* soundEffectsPath, int a2, int debugLevel)
{
char path[FILENAME_MAX];
// TODO: What for?
// memcpy(path, byte_4A97E0, 0xFF);
gSoundEffectsListDebugLevel = debugLevel;
_sfxl_compression = a2;
gSoundEffectsListEntriesLength = 0;
gSoundEffectsListPath = internal_strdup(soundEffectsPath);
if (gSoundEffectsListPath == NULL) {
return SFXL_ERR;
}
gSoundEffectsListPathLength = strlen(gSoundEffectsListPath);
if (gSoundEffectsListPathLength == 0 || soundEffectsPath[gSoundEffectsListPathLength - 1] == '\\') {
sprintf(path, "%sSNDLIST.LST", soundEffectsPath);
} else {
sprintf(path, "%s\\SNDLIST.LST", soundEffectsPath);
}
File* stream = fileOpen(path, "rt");
if (stream != NULL) {
fileReadString(path, 255, stream);
gSoundEffectsListEntriesLength = atoi(path);
gSoundEffectsListEntries = internal_malloc(sizeof(*gSoundEffectsListEntries) * gSoundEffectsListEntriesLength);
for (int index = 0; index < gSoundEffectsListEntriesLength; index++) {
SoundEffectsListEntry* entry = &(gSoundEffectsListEntries[index]);
fileReadString(path, 255, stream);
// Remove trailing newline.
*(path + strlen(path) - 1) = '\0';
entry->name = internal_strdup(path);
fileReadString(path, 255, stream);
entry->dataSize = atoi(path);
fileReadString(path, 255, stream);
entry->fileSize = atoi(path);
fileReadString(path, 255, stream);
entry->tag = atoi(path);
}
fileClose(stream);
debugPrint("Reading SNDLIST.LST Sound FX Count: %d", gSoundEffectsListEntriesLength);
} else {
int err;
err = soundEffectsListPopulateFileNames();
if (err != SFXL_OK) {
internal_free(gSoundEffectsListPath);
return err;
}
err = soundEffectsListPopulateFileSizes();
if (err != SFXL_OK) {
soundEffectsListClear();
internal_free(gSoundEffectsListPath);
return err;
}
// NOTE: For unknown reason tag generation functionality is missing.
// You won't be able to produce the same SNDLIST.LST as the game have.
// All tags will be 0 (see [soundEffectsListPopulateFileNames]).
//
// On the other hand, tags read from the SNDLIST.LST are not used in
// the game. Instead tag is automatically determined from entry's
// index (see [soundEffectsListGetTag]).
// NOTE: Uninline.
soundEffectsListSort();
File* stream = fileOpen(path, "wt");
if (stream != NULL) {
filePrintFormatted(stream, "%d\n", gSoundEffectsListEntriesLength);
for (int index = 0; index < gSoundEffectsListEntriesLength; index++) {
SoundEffectsListEntry* entry = &(gSoundEffectsListEntries[index]);
filePrintFormatted(stream, "%s\n", entry->name);
filePrintFormatted(stream, "%d\n", entry->dataSize);
filePrintFormatted(stream, "%d\n", entry->fileSize);
filePrintFormatted(stream, "%d\n", entry->tag);
}
fileClose(stream);
} else {
debugPrint("SFXLIST: Can't open file for write %s\n", path);
}
}
gSoundEffectsListInitialized = true;
return SFXL_OK;
}
// 0x4A9C04
void soundEffectsListExit()
{
if (gSoundEffectsListInitialized) {
soundEffectsListClear();
internal_free(gSoundEffectsListPath);
gSoundEffectsListInitialized = false;
}
}
// sfxl_name_to_tag
// 0x4A9C28
int soundEffectsListGetTag(char* name, int* tagPtr)
{
if (strnicmp(gSoundEffectsListPath, name, gSoundEffectsListPathLength) != 0) {
return SFXL_ERR;
}
SoundEffectsListEntry dummy;
dummy.name = name + gSoundEffectsListPathLength;
SoundEffectsListEntry* entry = bsearch(&dummy, gSoundEffectsListEntries, gSoundEffectsListEntriesLength, sizeof(*gSoundEffectsListEntries), soundEffectsListCompareByName);
if (entry == NULL) {
return SFXL_ERR;
}
int index = entry - gSoundEffectsListEntries;
if (index < 0 || index >= gSoundEffectsListEntriesLength) {
return SFXL_ERR;
}
*tagPtr = 2 * index + 2;
return SFXL_OK;
}
// sfxl_name
// 0x4A9CD8
int soundEffectsListGetFilePath(int tag, char** pathPtr)
{
int index;
int err = soundEffectsListTagToIndex(tag, &index);
if (err != SFXL_OK) {
return err;
}
char* name = gSoundEffectsListEntries[index].name;
char* path = internal_malloc(strlen(gSoundEffectsListPath) + strlen(name) + 1);
if (path == NULL) {
return SFXL_ERR;
}
strcpy(path, gSoundEffectsListPath);
strcat(path, name);
*pathPtr = path;
return SFXL_OK;
}
// 0x4A9D90
int soundEffectsListGetDataSize(int tag, int* sizePtr)
{
int index;
int rc = soundEffectsListTagToIndex(tag, &index);
if (rc != SFXL_OK) {
return rc;
}
SoundEffectsListEntry* entry = &(gSoundEffectsListEntries[index]);
*sizePtr = entry->dataSize;
return SFXL_OK;
}
// 0x4A9DBC
int soundEffectsListGetFileSize(int tag, int* sizePtr)
{
int index;
int err = soundEffectsListTagToIndex(tag, &index);
if (err != SFXL_OK) {
return err;
}
SoundEffectsListEntry* entry = &(gSoundEffectsListEntries[index]);
*sizePtr = entry->fileSize;
return SFXL_OK;
}
// sfxl_tag_to_index
// 0x4A9DE8
int soundEffectsListTagToIndex(int tag, int* indexPtr)
{
if (tag <= 0) {
return SFXL_ERR_TAG_INVALID;
}
if ((tag & 1) != 0) {
return SFXL_ERR_TAG_INVALID;
}
int index = (tag / 2) - 1;
if (index >= gSoundEffectsListEntriesLength) {
return SFXL_ERR_TAG_INVALID;
}
if (indexPtr != NULL) {
*indexPtr = index;
}
return SFXL_OK;
}
// 0x4A9E44
void soundEffectsListClear()
{
if (gSoundEffectsListEntriesLength < 0) {
return;
}
if (gSoundEffectsListEntries == NULL) {
return;
}
for (int index = 0; index < gSoundEffectsListEntriesLength; index++) {
SoundEffectsListEntry* entry = &(gSoundEffectsListEntries[index]);
if (entry->name != NULL) {
internal_free(entry->name);
}
}
internal_free(gSoundEffectsListEntries);
gSoundEffectsListEntries = NULL;
gSoundEffectsListEntriesLength = 0;
}
// sfxl_get_names
// 0x4A9EA0
int soundEffectsListPopulateFileNames()
{
const char* extension;
switch (_sfxl_compression) {
case 0:
extension = "*.SND";
break;
case 1:
extension = "*.ACM";
break;
default:
return SFXL_ERR;
}
char* pattern = internal_malloc(strlen(gSoundEffectsListPath) + strlen(extension) + 1);
if (pattern == NULL) {
return SFXL_ERR;
}
strcpy(pattern, gSoundEffectsListPath);
strcat(pattern, extension);
char** fileNameList;
gSoundEffectsListEntriesLength = fileNameListInit(pattern, &fileNameList, 0, 0);
internal_free(pattern);
if (gSoundEffectsListEntriesLength > 10000) {
fileNameListFree(&fileNameList, 0);
return SFXL_ERR;
}
if (gSoundEffectsListEntriesLength <= 0) {
return SFXL_ERR;
}
gSoundEffectsListEntries = internal_malloc(sizeof(*gSoundEffectsListEntries) * gSoundEffectsListEntriesLength);
if (gSoundEffectsListEntries == NULL) {
fileNameListFree(&fileNameList, 0);
return SFXL_ERR;
}
memset(gSoundEffectsListEntries, 0, sizeof(*gSoundEffectsListEntries) * gSoundEffectsListEntriesLength);
int err = soundEffectsListCopyFileNames(fileNameList);
fileNameListFree(&fileNameList, 0);
if (err != SFXL_OK) {
soundEffectsListClear();
return err;
}
return SFXL_OK;
}
// sfxl_copy_names
// 0x4AA000
int soundEffectsListCopyFileNames(char** fileNameList)
{
for (int index = 0; index < gSoundEffectsListEntriesLength; index++) {
SoundEffectsListEntry* entry = &(gSoundEffectsListEntries[index]);
entry->name = internal_strdup(*fileNameList++);
if (entry->name == NULL) {
soundEffectsListClear();
return SFXL_ERR;
}
}
return SFXL_OK;
}
// 0x4AA050
int soundEffectsListPopulateFileSizes()
{
char* path = internal_malloc(gSoundEffectsListPathLength + 13);
if (path == NULL) {
return SFXL_ERR;
}
strcpy(path, gSoundEffectsListPath);
char* fileName = path + gSoundEffectsListPathLength;
for (int index = 0; index < gSoundEffectsListEntriesLength; index++) {
SoundEffectsListEntry* entry = &(gSoundEffectsListEntries[index]);
strcpy(fileName, entry->name);
int fileSize;
if (dbGetFileSize(path, &fileSize) != 0) {
internal_free(path);
return SFXL_ERR;
}
if (fileSize <= 0) {
internal_free(path);
return SFXL_ERR;
}
entry->fileSize = fileSize;
switch (_sfxl_compression) {
case 0:
entry->dataSize = fileSize;
break;
case 1:
if (1) {
File* stream = fileOpen(path, "rb");
if (stream == NULL) {
internal_free(path);
return 1;
}
int v1;
int v2;
int v3;
SoundDecoder* soundDecoder = soundDecoderInit(_sfxl_ad_reader, (int)stream, &v1, &v2, &v3);
entry->dataSize = 2 * v3;
soundDecoderFree(soundDecoder);
fileClose(stream);
}
break;
default:
internal_free(path);
return SFXL_ERR;
}
}
internal_free(path);
return SFXL_OK;
}
// NOTE: Inlined.
//
// 0x4AA200
int soundEffectsListSort()
{
if (gSoundEffectsListEntriesLength != 1) {
qsort(gSoundEffectsListEntries, gSoundEffectsListEntriesLength, sizeof(*gSoundEffectsListEntries), soundEffectsListCompareByName);
}
return 0;
}
// 0x4AA228
int soundEffectsListCompareByName(const void* a1, const void* a2)
{
SoundEffectsListEntry* v1 = (SoundEffectsListEntry*)a1;
SoundEffectsListEntry* v2 = (SoundEffectsListEntry*)a2;
return stricmp(v1->name, v2->name);
}
// read via xfile
int _sfxl_ad_reader(int fileHandle, void* buf, unsigned int size)
{
return fileRead(buf, 1, size, (File*)fileHandle);
}