mirror of
https://github.com/simtactics/niotso.git
synced 2025-07-04 13:47:05 -04:00
Client: Separated the LoginScreen scene away from Scene.hpp, so it's compiled once as its own translation unit.
FileHandler: Added read support for XA, UTK, and MP3 to File::ReadSoundFile.
This commit is contained in:
parent
06f13d50ac
commit
5c7a36592e
11 changed files with 480 additions and 264 deletions
|
@ -17,7 +17,10 @@
|
|||
#include <stdint.h>
|
||||
#include <memory.h>
|
||||
#include <stdio.h>
|
||||
#include "libmpg123/mpg123.h"
|
||||
#include "utk/read_utk.h"
|
||||
#include "wav/read_wav.h"
|
||||
#include "xa/read_xa.h"
|
||||
#include "FileHandler.hpp"
|
||||
|
||||
namespace File {
|
||||
|
@ -103,8 +106,105 @@ static uint8_t * ReadWAV(Sound_t * Sound, const uint8_t * InData, size_t FileSiz
|
|||
}
|
||||
|
||||
|
||||
static uint8_t * ReadXA(Sound_t * Sound, const uint8_t * InData, size_t FileSize){};
|
||||
static uint8_t * ReadUTK(Sound_t * Sound, const uint8_t * InData, size_t FileSize){};
|
||||
static uint8_t * ReadMP3(Sound_t * Sound, const uint8_t * InData, size_t FileSize){};
|
||||
static uint8_t * ReadXA(Sound_t * Sound, const uint8_t * InData, size_t FileSize){
|
||||
xaheader_t XAHeader;
|
||||
if(!xa_read_header(&XAHeader, InData, FileSize)){
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint8_t * OutData = (uint8_t*) malloc(XAHeader.dwOutSize);
|
||||
if(OutData == NULL){
|
||||
return NULL;
|
||||
}
|
||||
if(!xa_decode(InData+24, OutData, XAHeader.Frames, XAHeader.nChannels)){
|
||||
free(OutData);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Sound->Channels = XAHeader.nChannels;
|
||||
Sound->SamplingRate = XAHeader.nSamplesPerSec;
|
||||
Sound->BitDepth = XAHeader.wBitsPerSample;
|
||||
Sound->Duration = XAHeader.dwOutSize / XAHeader.nBlockAlign;
|
||||
Sound->Data = OutData;
|
||||
return OutData;
|
||||
}
|
||||
|
||||
static uint8_t * ReadUTK(Sound_t * Sound, const uint8_t * InData, size_t FileSize){
|
||||
utkheader_t UTKHeader;
|
||||
if(!utk_read_header(&UTKHeader, InData, FileSize)){
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint8_t * OutData = (uint8_t*) malloc(UTKHeader.dwOutSize);
|
||||
if(OutData == NULL){
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bool generated = false;
|
||||
if(!generated){
|
||||
UTKGenerateTables();
|
||||
generated = true;
|
||||
}
|
||||
|
||||
if(!utk_decode(InData+32, OutData, UTKHeader.Frames)){
|
||||
free(OutData);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Sound->Channels = 1;
|
||||
Sound->SamplingRate = UTKHeader.nSamplesPerSec;
|
||||
Sound->BitDepth = UTKHeader.wBitsPerSample;
|
||||
Sound->Duration = UTKHeader.dwOutSize / UTKHeader.nBlockAlign;
|
||||
Sound->Data = OutData;
|
||||
return OutData;
|
||||
}
|
||||
|
||||
static uint8_t * ReadMP3(Sound_t * Sound, const uint8_t * InData, size_t FileSize){
|
||||
if(mpg123_init() != MPG123_OK){
|
||||
mpg123_exit();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
long rate;
|
||||
int channels, encoding;
|
||||
unsigned samples;
|
||||
size_t OutSize;
|
||||
uint8_t * OutData;
|
||||
|
||||
mpg123_handle *mh = mpg123_new(NULL, NULL);
|
||||
if(mh == NULL ||
|
||||
mpg123_format_none(mh) != MPG123_OK ||
|
||||
mpg123_format(mh, 44100, MPG123_MONO | MPG123_STEREO, MPG123_ENC_SIGNED_16) != MPG123_OK ||
|
||||
mpg123_open_feed(mh) != MPG123_OK ||
|
||||
mpg123_feed(mh, InData, FileSize) != MPG123_OK ||
|
||||
mpg123_set_filesize(mh, FileSize) != MPG123_OK ||
|
||||
mpg123_getformat(mh, &rate, &channels, &encoding) != MPG123_OK ||
|
||||
(samples = mpg123_length(mh)) == 0 ||
|
||||
(OutData = (uint8_t*) malloc(OutSize = samples * channels * 2)) == NULL
|
||||
){
|
||||
mpg123_close(mh);
|
||||
mpg123_delete(mh);
|
||||
mpg123_exit();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t decoded;
|
||||
mpg123_read(mh, OutData, OutSize, &decoded);
|
||||
mpg123_close(mh);
|
||||
mpg123_delete(mh);
|
||||
mpg123_exit();
|
||||
|
||||
if(decoded != OutSize){
|
||||
free(OutData);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Sound->Channels = channels;
|
||||
Sound->SamplingRate = rate;
|
||||
Sound->BitDepth = 16;
|
||||
Sound->Duration = samples;
|
||||
Sound->Data = OutData;
|
||||
return OutData;
|
||||
}
|
||||
|
||||
}
|
|
@ -23,7 +23,9 @@ set(FILEHANDLER_SOURCES
|
|||
cst/cst.c
|
||||
iff/chunks.c
|
||||
iff/iff.c
|
||||
utk/read_utk.c
|
||||
wav/read_wav.c
|
||||
xa/read_xa.c
|
||||
)
|
||||
|
||||
include_directories(${CMAKE_SOURCE_DIR}/Libraries/FileHandler)
|
||||
|
@ -42,4 +44,4 @@ set_target_properties(FileHandler_shared PROPERTIES
|
|||
PREFIX ""
|
||||
IMPORT_PREFIX ""
|
||||
CLEAN_DIRECT_OUTPUT 1)
|
||||
target_link_libraries(FileHandler_shared kernel32 jpegturbo_static libpng_static zlib_static)
|
||||
target_link_libraries(FileHandler_shared kernel32 jpegturbo_static libmpg123_static libpng_static zlib_static)
|
|
@ -19,23 +19,37 @@
|
|||
#include <stdint.h>
|
||||
#include "iff.h"
|
||||
|
||||
int iff_parse_chunk(IFFChunk * ChunkInfo, const uint8_t * Buffer){
|
||||
if( !strcmp(ChunkInfo->Type, "STR#") ||
|
||||
!strcmp(ChunkInfo->Type, "CTSS") ||
|
||||
!strcmp(ChunkInfo->Type, "FAMs") ||
|
||||
!strcmp(ChunkInfo->Type, "TTAs") )
|
||||
return iff_parse_str(ChunkInfo, Buffer);
|
||||
if( !strcmp(ChunkInfo->Type, "BCON") )
|
||||
return iff_parse_bcon(ChunkInfo, Buffer);
|
||||
/* All chunk-parsing functions */
|
||||
static int iff_parse_rsmp(IFFChunk * ChunkInfo, const uint8_t * Buffer, unsigned IFFSize);
|
||||
static int iff_parse_bcon(IFFChunk * ChunkInfo, const uint8_t * Buffer);
|
||||
static int iff_parse_str(IFFChunk * ChunkInfo, const uint8_t * Buffer);
|
||||
static int iff_parse_trcn(IFFChunk * ChunkInfo, const uint8_t * Buffer);
|
||||
|
||||
int iff_parse_chunk(IFFChunk * ChunkInfo, const uint8_t * Buffer){
|
||||
unsigned i;
|
||||
const char chunktypes[] =
|
||||
"STR#" "CTSS" "FAMs" "TTAs"
|
||||
"BCON"
|
||||
"TRCN"
|
||||
;
|
||||
int (* const iff_parse_function[])(IFFChunk*, const uint8_t*) = {
|
||||
iff_parse_str, iff_parse_str, iff_parse_str, iff_parse_str,
|
||||
iff_parse_bcon,
|
||||
iff_parse_trcn
|
||||
};
|
||||
|
||||
for(i=0; chunktypes[i*4] != '\0'; i++){
|
||||
if(!memcmp(ChunkInfo->Type, chunktypes+i*4, 4))
|
||||
return iff_parse_function[i](ChunkInfo, Buffer);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int iff_parse_rsmp(IFFChunk * ChunkInfo, const uint8_t * Buffer, unsigned IFFSize){
|
||||
static int iff_parse_rsmp(IFFChunk * ChunkInfo, const uint8_t * Buffer, unsigned IFFSize){
|
||||
return 1;
|
||||
}
|
||||
|
||||
int iff_parse_bcon(IFFChunk * ChunkInfo, const uint8_t * Buffer){
|
||||
static int iff_parse_bcon(IFFChunk * ChunkInfo, const uint8_t * Buffer){
|
||||
IFF_BCON *BCONData;
|
||||
unsigned Size = ChunkInfo->Size - 76;
|
||||
unsigned i;
|
||||
|
@ -51,14 +65,14 @@ int iff_parse_bcon(IFFChunk * ChunkInfo, const uint8_t * Buffer){
|
|||
BCONData->Flags = read_uint8le(Buffer + 1);
|
||||
if(BCONData->ConstantCount == 0)
|
||||
return 1;
|
||||
if(BCONData->ConstantCount * 2 > 255*2){
|
||||
free(ChunkInfo->FormattedData);
|
||||
if(BCONData->ConstantCount * 2 > Size - 2){
|
||||
free(BCONData);
|
||||
return 0;
|
||||
}
|
||||
|
||||
BCONData->Constants = malloc(BCONData->ConstantCount * sizeof(uint16_t));
|
||||
if(BCONData->Constants == NULL){
|
||||
free(ChunkInfo->FormattedData);
|
||||
free(BCONData);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -68,7 +82,7 @@ int iff_parse_bcon(IFFChunk * ChunkInfo, const uint8_t * Buffer){
|
|||
return 1;
|
||||
}
|
||||
|
||||
int iff_parse_str(IFFChunk * ChunkInfo, const uint8_t * Buffer){
|
||||
static int iff_parse_str(IFFChunk * ChunkInfo, const uint8_t * Buffer){
|
||||
/* No bounds checking yet */
|
||||
IFF_STR * StringData;
|
||||
unsigned Size = ChunkInfo->Size - 76;
|
||||
|
@ -78,8 +92,9 @@ int iff_parse_str(IFFChunk * ChunkInfo, const uint8_t * Buffer){
|
|||
ChunkInfo->FormattedData = malloc(sizeof(IFF_STR));
|
||||
if(ChunkInfo->FormattedData == NULL)
|
||||
return 0;
|
||||
memset(ChunkInfo->FormattedData, 0, sizeof(IFF_STR));
|
||||
|
||||
StringData = (IFF_STR*) ChunkInfo->FormattedData;
|
||||
memset(StringData, 0, sizeof(IFF_STR));
|
||||
StringData->Format = read_int16le(Buffer);
|
||||
Buffer += 2;
|
||||
if(Size-2 < 2) /* TSO allows this; as seen in the animations chunk in personglobals.iff */
|
||||
|
@ -298,4 +313,39 @@ int iff_parse_str(IFFChunk * ChunkInfo, const uint8_t * Buffer){
|
|||
|
||||
free(ChunkInfo->FormattedData);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int iff_parse_trcn(IFFChunk * ChunkInfo, const uint8_t * Buffer){
|
||||
IFF_TRCN * TRCNData;
|
||||
unsigned Size = ChunkInfo->Size - 76;
|
||||
unsigned i;
|
||||
|
||||
if(Size < 16)
|
||||
return 0;
|
||||
ChunkInfo->FormattedData = malloc(sizeof(IFF_TRCN));
|
||||
if(ChunkInfo->FormattedData == NULL)
|
||||
return 0;
|
||||
|
||||
TRCNData = (IFF_TRCN*) ChunkInfo->FormattedData;
|
||||
TRCNData->Reserved = read_uint32le(Buffer+0);
|
||||
TRCNData->Version = read_uint32le(Buffer+4);
|
||||
memcpy(TRCNData->MagicNumber, Buffer+8, 4);
|
||||
TRCNData->MagicNumber[4] = 0x00;
|
||||
TRCNData->EntryCount = read_uint32le(Buffer+12);
|
||||
|
||||
if(TRCNData->Reserved != 0 || TRCNData->Version > 2 || strcmp(TRCNData->MagicNumber, "NCRT")){
|
||||
free(TRCNData);
|
||||
return 0;
|
||||
}
|
||||
ChunkInfo->FormattedData = malloc(TRCNData->EntryCount * sizeof(IFFRangePair));
|
||||
if(ChunkInfo->FormattedData == NULL){
|
||||
free(TRCNData);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Buffer += 16;
|
||||
for(i=0; i<TRCNData->EntryCount; i++){/*
|
||||
IsUnused = read_uint32le(Buffer+0);
|
||||
Unknown = read_uint32le(Buffer+4);*/
|
||||
}
|
||||
}
|
|
@ -133,6 +133,28 @@ typedef struct IFF_STR_struct
|
|||
IFFLanguageSet LanguageSets[20];
|
||||
} IFF_STR;
|
||||
|
||||
/* TRCN chunk */
|
||||
|
||||
typedef struct IFFRangePair_struct
|
||||
{
|
||||
uint32_t IsUnused;
|
||||
uint32_t Unknown;
|
||||
char * Key;
|
||||
char * Value;
|
||||
uint8_t Enforced;
|
||||
uint16_t RangeMin;
|
||||
uint16_t RangeMax;
|
||||
} IFFRangePair;
|
||||
|
||||
typedef struct IFF_TRCN_struct
|
||||
{
|
||||
uint32_t Reserved;
|
||||
uint32_t Version;
|
||||
char MagicNumber[5];
|
||||
uint32_t EntryCount;
|
||||
IFFRangePair * Entries;
|
||||
} IFF_TRCN;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
@ -157,9 +179,6 @@ void iff_delete(IFFFile * IFFFileInfo);
|
|||
*/
|
||||
|
||||
int iff_parse_chunk(IFFChunk * ChunkInfo, const uint8_t * Buffer);
|
||||
int iff_parse_rsmp(IFFChunk * ChunkInfo, const uint8_t * Buffer, unsigned IFFSize);
|
||||
int iff_parse_bcon(IFFChunk * ChunkInfo, const uint8_t * Buffer);
|
||||
int iff_parse_str(IFFChunk * ChunkInfo, const uint8_t * Buffer);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
#define round(x) ((x) >= 0 ? (x)+0.5 : (x)-0.5)
|
||||
#endif
|
||||
#ifndef min
|
||||
#define min(x, y) ((x) > (y) ? (x) : (y))
|
||||
#define min(x, y) ((x) < (y) ? (x) : (y))
|
||||
#endif
|
||||
|
||||
#ifndef __inline
|
||||
|
@ -57,7 +57,7 @@ float UTKTable4[29];
|
|||
|
||||
int utk_read_header(utkheader_t * UTKHeader, const uint8_t * Buffer, size_t FileSize)
|
||||
{
|
||||
if(FileSize < 28) return 0;
|
||||
if(FileSize < 32) return 0;
|
||||
memcpy(&UTKHeader->sID, Buffer, 4);
|
||||
UTKHeader->dwOutSize = read_uint32(Buffer+4);
|
||||
UTKHeader->dwWfxSize = read_uint32(Buffer+8);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue