2022-05-19 01:51:26 -07:00
|
|
|
#include "audio.h"
|
|
|
|
|
2022-09-15 02:38:23 -07:00
|
|
|
#include <assert.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
2022-05-19 01:51:26 -07:00
|
|
|
#include "db.h"
|
|
|
|
#include "debug.h"
|
|
|
|
#include "memory_manager.h"
|
|
|
|
#include "sound.h"
|
2022-12-26 00:48:47 -08:00
|
|
|
#include "sound_decoder.h"
|
2022-05-19 01:51:26 -07:00
|
|
|
|
2022-09-23 05:43:44 -07:00
|
|
|
namespace fallout {
|
|
|
|
|
2022-12-26 00:48:47 -08:00
|
|
|
typedef enum AudioFlags {
|
|
|
|
AUDIO_IN_USE = 0x01,
|
|
|
|
AUDIO_COMPRESSED = 0x02,
|
|
|
|
} AudioFileFlags;
|
|
|
|
|
|
|
|
typedef struct Audio {
|
|
|
|
int flags;
|
2023-02-13 00:02:17 -08:00
|
|
|
File* stream;
|
2022-12-26 00:48:47 -08:00
|
|
|
SoundDecoder* soundDecoder;
|
|
|
|
int fileSize;
|
|
|
|
int sampleRate;
|
|
|
|
int channels;
|
|
|
|
int position;
|
|
|
|
} Audio;
|
|
|
|
|
|
|
|
static bool defaultCompressionFunc(char* filePath);
|
2023-02-13 00:02:17 -08:00
|
|
|
static int audioSoundDecoderReadHandler(void* data, void* buf, unsigned int size);
|
2022-06-18 05:36:13 -07:00
|
|
|
|
2022-05-19 01:51:26 -07:00
|
|
|
// 0x5108BC
|
2022-12-26 00:48:47 -08:00
|
|
|
static AudioQueryCompressedFunc* queryCompressedFunc = defaultCompressionFunc;
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
// 0x56CB00
|
2022-06-18 05:36:13 -07:00
|
|
|
static int gAudioListLength;
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
// 0x56CB04
|
2022-12-26 00:48:47 -08:00
|
|
|
static Audio* gAudioList;
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
// 0x41A2B0
|
2022-12-26 00:48:47 -08:00
|
|
|
static bool defaultCompressionFunc(char* filePath)
|
2022-05-19 01:51:26 -07:00
|
|
|
{
|
|
|
|
char* pch = strrchr(filePath, '.');
|
|
|
|
if (pch != NULL) {
|
2022-12-26 00:48:47 -08:00
|
|
|
strcpy(pch + 1, "raw");
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x41A2D0
|
2023-02-13 00:02:17 -08:00
|
|
|
static int audioSoundDecoderReadHandler(void* data, void* buffer, unsigned int size)
|
2022-05-19 01:51:26 -07:00
|
|
|
{
|
2023-02-13 00:02:17 -08:00
|
|
|
return fileRead(buffer, 1, size, reinterpret_cast<File*>(data));
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// AudioOpen
|
|
|
|
// 0x41A2EC
|
2023-02-13 00:51:09 -08:00
|
|
|
int audioOpen(const char* fname, int flags)
|
2022-05-19 01:51:26 -07:00
|
|
|
{
|
|
|
|
char path[80];
|
2022-12-08 12:05:50 -08:00
|
|
|
snprintf(path, sizeof(path), "%s", fname);
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
int compression;
|
2022-12-26 00:48:47 -08:00
|
|
|
if (queryCompressedFunc(path)) {
|
2022-05-19 01:51:26 -07:00
|
|
|
compression = 2;
|
|
|
|
} else {
|
|
|
|
compression = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
char mode[4];
|
|
|
|
memset(mode, 0, 4);
|
|
|
|
|
|
|
|
// NOTE: Original implementation is slightly different, it uses separate
|
|
|
|
// variable to track index where to set 't' and 'b'.
|
|
|
|
char* pm = mode;
|
|
|
|
if (flags & 1) {
|
|
|
|
*pm++ = 'w';
|
|
|
|
} else if (flags & 2) {
|
|
|
|
*pm++ = 'w';
|
|
|
|
*pm++ = '+';
|
|
|
|
} else {
|
|
|
|
*pm++ = 'r';
|
|
|
|
}
|
|
|
|
|
|
|
|
if (flags & 0x100) {
|
|
|
|
*pm++ = 't';
|
|
|
|
} else if (flags & 0x200) {
|
|
|
|
*pm++ = 'b';
|
|
|
|
}
|
|
|
|
|
|
|
|
File* stream = fileOpen(path, mode);
|
|
|
|
if (stream == NULL) {
|
|
|
|
debugPrint("AudioOpen: Couldn't open %s for read\n", path);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int index;
|
|
|
|
for (index = 0; index < gAudioListLength; index++) {
|
2022-12-26 00:48:47 -08:00
|
|
|
if ((gAudioList[index].flags & AUDIO_IN_USE) == 0) {
|
2022-05-19 01:51:26 -07:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (index == gAudioListLength) {
|
|
|
|
if (gAudioList != NULL) {
|
2022-12-26 00:48:47 -08:00
|
|
|
gAudioList = (Audio*)internal_realloc_safe(gAudioList, sizeof(*gAudioList) * (gAudioListLength + 1), __FILE__, __LINE__); // "..\int\audio.c", 216
|
2022-05-19 01:51:26 -07:00
|
|
|
} else {
|
2022-12-26 00:48:47 -08:00
|
|
|
gAudioList = (Audio*)internal_malloc_safe(sizeof(*gAudioList), __FILE__, __LINE__); // "..\int\audio.c", 218
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
gAudioListLength++;
|
|
|
|
}
|
|
|
|
|
2022-12-26 00:48:47 -08:00
|
|
|
Audio* audioFile = &(gAudioList[index]);
|
|
|
|
audioFile->flags = AUDIO_IN_USE;
|
2023-02-13 00:02:17 -08:00
|
|
|
audioFile->stream = stream;
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
if (compression == 2) {
|
2022-12-26 00:48:47 -08:00
|
|
|
audioFile->flags |= AUDIO_COMPRESSED;
|
|
|
|
audioFile->soundDecoder = soundDecoderInit(audioSoundDecoderReadHandler, audioFile->stream, &(audioFile->channels), &(audioFile->sampleRate), &(audioFile->fileSize));
|
2022-05-19 01:51:26 -07:00
|
|
|
audioFile->fileSize *= 2;
|
|
|
|
} else {
|
|
|
|
audioFile->fileSize = fileGetSize(stream);
|
|
|
|
}
|
|
|
|
|
|
|
|
audioFile->position = 0;
|
|
|
|
|
|
|
|
return index + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x41A50C
|
2022-12-26 00:48:47 -08:00
|
|
|
int audioClose(int handle)
|
2022-05-19 01:51:26 -07:00
|
|
|
{
|
2022-12-26 00:48:47 -08:00
|
|
|
Audio* audioFile = &(gAudioList[handle - 1]);
|
2023-02-13 00:02:17 -08:00
|
|
|
fileClose(audioFile->stream);
|
2022-05-19 01:51:26 -07:00
|
|
|
|
2022-12-26 00:48:47 -08:00
|
|
|
if ((audioFile->flags & AUDIO_COMPRESSED) != 0) {
|
2022-05-19 01:51:26 -07:00
|
|
|
soundDecoderFree(audioFile->soundDecoder);
|
|
|
|
}
|
|
|
|
|
2022-12-26 00:48:47 -08:00
|
|
|
memset(audioFile, 0, sizeof(Audio));
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x41A574
|
2022-12-26 00:48:47 -08:00
|
|
|
int audioRead(int handle, void* buffer, unsigned int size)
|
2022-05-19 01:51:26 -07:00
|
|
|
{
|
2022-12-26 00:48:47 -08:00
|
|
|
Audio* audioFile = &(gAudioList[handle - 1]);
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
int bytesRead;
|
2022-12-26 00:48:47 -08:00
|
|
|
if ((audioFile->flags & AUDIO_COMPRESSED) != 0) {
|
2022-05-19 01:51:26 -07:00
|
|
|
bytesRead = soundDecoderDecode(audioFile->soundDecoder, buffer, size);
|
|
|
|
} else {
|
2023-02-13 00:02:17 -08:00
|
|
|
bytesRead = fileRead(buffer, 1, size, audioFile->stream);
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
audioFile->position += bytesRead;
|
|
|
|
|
|
|
|
return bytesRead;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x41A5E0
|
2022-12-26 00:48:47 -08:00
|
|
|
long audioSeek(int handle, long offset, int origin)
|
2022-05-19 01:51:26 -07:00
|
|
|
{
|
|
|
|
int pos;
|
|
|
|
unsigned char* buf;
|
|
|
|
int v10;
|
|
|
|
|
2022-12-26 00:48:47 -08:00
|
|
|
Audio* audioFile = &(gAudioList[handle - 1]);
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
switch (origin) {
|
|
|
|
case SEEK_SET:
|
|
|
|
pos = offset;
|
|
|
|
break;
|
|
|
|
case SEEK_CUR:
|
|
|
|
pos = offset + audioFile->position;
|
|
|
|
break;
|
|
|
|
case SEEK_END:
|
|
|
|
pos = offset + audioFile->fileSize;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
assert(false && "Should be unreachable");
|
|
|
|
}
|
|
|
|
|
2022-12-26 00:48:47 -08:00
|
|
|
if ((audioFile->flags & AUDIO_COMPRESSED) != 0) {
|
2022-05-19 01:51:26 -07:00
|
|
|
if (pos < audioFile->position) {
|
|
|
|
soundDecoderFree(audioFile->soundDecoder);
|
2023-02-13 00:02:17 -08:00
|
|
|
fileSeek(audioFile->stream, 0, SEEK_SET);
|
2022-12-26 00:48:47 -08:00
|
|
|
audioFile->soundDecoder = soundDecoderInit(audioSoundDecoderReadHandler, audioFile->stream, &(audioFile->channels), &(audioFile->sampleRate), &(audioFile->fileSize));
|
2022-05-19 01:51:26 -07:00
|
|
|
audioFile->position = 0;
|
|
|
|
audioFile->fileSize *= 2;
|
|
|
|
|
|
|
|
if (pos != 0) {
|
2022-05-21 08:22:03 -07:00
|
|
|
buf = (unsigned char*)internal_malloc_safe(4096, __FILE__, __LINE__); // "..\int\audio.c", 361
|
2022-05-19 01:51:26 -07:00
|
|
|
while (pos > 4096) {
|
|
|
|
pos -= 4096;
|
2022-12-26 00:48:47 -08:00
|
|
|
audioRead(handle, buf, 4096);
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (pos != 0) {
|
2022-12-26 00:48:47 -08:00
|
|
|
audioRead(handle, buf, pos);
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
internal_free_safe(buf, __FILE__, __LINE__); // // "..\int\audio.c", 367
|
|
|
|
}
|
|
|
|
} else {
|
2022-05-21 08:22:03 -07:00
|
|
|
buf = (unsigned char*)internal_malloc_safe(1024, __FILE__, __LINE__); // "..\int\audio.c", 321
|
2022-05-19 01:51:26 -07:00
|
|
|
v10 = audioFile->position - pos;
|
|
|
|
while (v10 > 1024) {
|
|
|
|
v10 -= 1024;
|
2022-12-26 00:48:47 -08:00
|
|
|
audioRead(handle, buf, 1024);
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (v10 != 0) {
|
2022-12-26 00:48:47 -08:00
|
|
|
audioRead(handle, buf, v10);
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: Probably leaks memory.
|
|
|
|
}
|
|
|
|
|
|
|
|
return audioFile->position;
|
|
|
|
} else {
|
2023-02-13 00:02:17 -08:00
|
|
|
return fileSeek(audioFile->stream, offset, origin);
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x41A78C
|
2022-12-26 00:48:47 -08:00
|
|
|
long audioGetSize(int handle)
|
2022-05-19 01:51:26 -07:00
|
|
|
{
|
2022-12-26 00:48:47 -08:00
|
|
|
Audio* audioFile = &(gAudioList[handle - 1]);
|
2022-05-19 01:51:26 -07:00
|
|
|
return audioFile->fileSize;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x41A7A8
|
2022-12-26 00:48:47 -08:00
|
|
|
long audioTell(int handle)
|
2022-05-19 01:51:26 -07:00
|
|
|
{
|
2022-12-26 00:48:47 -08:00
|
|
|
Audio* audioFile = &(gAudioList[handle - 1]);
|
2022-05-19 01:51:26 -07:00
|
|
|
return audioFile->position;
|
|
|
|
}
|
|
|
|
|
|
|
|
// AudioWrite
|
|
|
|
// 0x41A7C4
|
|
|
|
int audioWrite(int handle, const void* buf, unsigned int size)
|
|
|
|
{
|
|
|
|
debugPrint("AudioWrite shouldn't be ever called\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x41A7D4
|
2022-12-26 00:48:47 -08:00
|
|
|
int audioInit(AudioQueryCompressedFunc* func)
|
2022-05-19 01:51:26 -07:00
|
|
|
{
|
2022-12-26 00:48:47 -08:00
|
|
|
queryCompressedFunc = func;
|
2022-05-19 01:51:26 -07:00
|
|
|
gAudioList = NULL;
|
|
|
|
gAudioListLength = 0;
|
|
|
|
|
|
|
|
return soundSetDefaultFileIO(audioOpen, audioClose, audioRead, audioWrite, audioSeek, audioTell, audioGetSize);
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x41A818
|
|
|
|
void audioExit()
|
|
|
|
{
|
|
|
|
if (gAudioList != NULL) {
|
|
|
|
internal_free_safe(gAudioList, __FILE__, __LINE__); // "..\int\audio.c", 406
|
|
|
|
}
|
|
|
|
|
|
|
|
gAudioListLength = 0;
|
|
|
|
gAudioList = NULL;
|
|
|
|
}
|
2022-09-23 05:43:44 -07:00
|
|
|
|
|
|
|
} // namespace fallout
|