fallout2-ce/src/audio.cc

256 lines
6.2 KiB
C++
Raw Normal View History

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-04-11 06:37:01 -07:00
int audioOpen(const char* fname, int* channels, int* sampleRate)
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;
}
2023-04-11 06:37:01 -07:00
File* stream = fileOpen(path, "rb");
2022-05-19 01:51:26 -07:00
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;
2023-04-11 06:37:01 -07:00
*channels = audioFile->channels;
*sampleRate = audioFile->sampleRate;
2022-05-19 01:51:26 -07:00
} 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