diff --git a/Libraries/FileHandler/Audio.cpp b/Libraries/FileHandler/Audio.cpp index 234a164..811551f 100644 --- a/Libraries/FileHandler/Audio.cpp +++ b/Libraries/FileHandler/Audio.cpp @@ -139,13 +139,7 @@ static uint8_t * ReadUTK(Sound_t * Sound, const uint8_t * InData, size_t FileSiz return NULL; } - static bool generated = false; - if(!generated){ - UTKGenerateTables(); - generated = true; - } - - if(!utk_decode(InData+32, OutData, UTKHeader.Frames)){ + if(!utk_decode(InData+32, OutData, FileSize-32, UTKHeader.Frames)){ free(OutData); return NULL; } diff --git a/Libraries/FileHandler/far/farextract.c b/Libraries/FileHandler/far/farextract.c index 64bcd0c..1824a3e 100644 --- a/Libraries/FileHandler/far/farextract.c +++ b/Libraries/FileHandler/far/farextract.c @@ -20,9 +20,31 @@ #include #include #include +#include #include +#include +#include #include "far.h" +#ifndef read_uint32 + #define read_uint32(x) (unsigned)(((x)[0]<<(8*0)) | ((x)[1]<<(8*1)) | ((x)[2]<<(8*2)) | ((x)[3]<<(8*3))) +#endif + +#ifdef _WIN32 +#define mkdir(path, x) mkdir(path) +#endif +static int mkpath(char * path){ + char * p; + for(p = strpbrk(path+1, "/\\"); p; p = strpbrk(p+1, "/\\")){ + char c = *p; + int value; + *p = '\0'; value = mkdir(path, 0644); *p = c; + if(value != 0 && errno != EEXIST) + return -1; + } + return 0; +} + enum { profile_ts1 = 1, profile_tso, @@ -32,6 +54,122 @@ enum { profile_ts3 }; +typedef struct { + uint32_t GroupID; + const char * Directory; +} GroupMap_t; + +typedef struct { + uint32_t TypeID; + const char * Extension; +} TypeMap_t; + +typedef struct { + uint8_t Size; + const char * Header; + const char * Extension; +} HeaderMap_t; + +static const GroupMap_t GroupMap[] = { + {0x0A3C55C7, "Music/Stations/Horror/"}, + {0x0A3C55CE, "Music/Stations/OldWorld/"}, + {0x0A3C55D3, "Music/Stations/SciFi/"}, + {0x1D6962CF, "SoundData/HitLabUI/"}, + {0x1D8A8B4F, "SoundData/HitLabTestSamples/"}, + {0x29D9359D, "SoundData/CustomTrks/"}, + {0x29DAA4A6, "SoundData/Custom/"}, + {0x29DD0888, "SoundData/Multiplayer/"}, + {0x69C6C943, "SoundData/tsov2/"}, + {0x8A6FCC30, "SoundData/EP5Samps/"}, + {0x9DBDBF74, "SoundData/HitLists/"}, + {0x9DBDBF89, "SoundData/Samples/"}, + {0x9DF26DAD, "Music/Stations/Country/"}, + {0x9DF26DAE, "Music/Stations/CountryD/"}, + {0x9DF26DB1, "Music/Stations/Latin/"}, + {0x9DF26DB3, "Music/Stations/Rap/"}, + {0x9DF26DB6, "Music/Stations/Rock/"}, + {0xA9C6C89A, "SoundData/Tracks/"}, + {0xBD6E5937, "SoundData/HitLabTest/"}, + {0xBDF26DB0, "Music/Stations/Disco/"}, + {0xC9C6C9B3, "SoundData/HitListsTemp/"}, + {0xDDBDBF8C, "SoundData/Stings/"}, + {0xDDE8F5C6, "SoundData/EP2/"}, + {0xDDF26DA9, "Music/Stations/Beach/"}, + {0xDDF26DB4, "Music/Stations/Rave/"}, + {0xFDBDBF87, "SoundData/TrackDefs/"}, + {0xFDF26DAB, "Music/Stations/Classica/"} +}; + +static const TypeMap_t TypeMap[] = { + {0, ".dat"}, + {1, ".bmp"}, + {2, ".tga"}, + {5, ".skel"}, + {7, ".anim"}, + {9, ".mesh"}, + {11, ".bnd"}, + {12, ".apr"}, + {13, ".oft"}, + {14, ".png"}, + {15, ".po"}, + {16, ".col"}, + {18, ".hag"}, + {20, ".jpg"}, + {24, ".png"}, + {0x0A8B0E70, ".mad"}, + {0x1B6B9806, ".utk"}, + {0x1D07EB4B, ".xa"}, + {0x1D968538, ".xa"}, + {0x2026960B, ".dat"}, + {0x3CEC2B47, ".mp3"}, + {0x3D968536, ".mp3"}, + {0x5D73A611, ".trk"}, + {0x7B1ACFCD, ".hls"}, + {0x856DDBAC, ".bmp"}, + {0x9D796DB4, ".tlo"}, + {0x9D96853A, ".wav"}, + {0xA3CD96CF, ".tkd"}, + {0xBB7051F5, ".wav"} +}; + +static const HeaderMap_t AudioHeaders[] = { + {2, "XA", ".xa"}, + {4, "RIFF", ".wav"}, + {4, "UTM0", ".utk"}, + {4, "\xFF\xFB\x90\x40", ".mp3"}, + {24, "# Generated by UI editor", ".scr"} +}; + +static const char * groupid_to_dir(uint32_t GroupID){ + size_t i; + for(i=0; i= AudioHeaders[i].Size && !memcmp(Buffer, AudioHeaders[i].Header, AudioHeaders[i].Size)) + return AudioHeaders[i].Extension; + } + + return ".str"; +} + int main(int argc, char *argv[]){ int profile = 0, overwrite = 0; const char * InFile = "", * OutDirectory; @@ -62,7 +200,7 @@ int main(int argc, char *argv[]){ "\n" "Report bugs to .\n" "farextract and libfar are maintained by the Niotso project.\n" - "Home page: "); + "Home page: \n"); return 0; } @@ -141,6 +279,11 @@ int main(int argc, char *argv[]){ return -1; } + if(chdir(OutDirectory) != 0){ + fprintf(stderr, "%sOutput directory '%s' does not exist.", "farextract: error: ", OutDirectory); + return -1; + } + if(ArchiveType != FAR_TYPE_PERSIST){ FAREntryNode * EntryNode; unsigned file = 0, filescount; @@ -177,28 +320,35 @@ int main(int argc, char *argv[]){ ** Extract each entry */ for(EntryNode = FARFileInfo->FirstEntry; EntryNode; EntryNode = EntryNode->NextEntry){ - char destination[256]; + char destbuffer[256], * destination = destbuffer; file++; if(EntryNode->Entry.Filename) - sprintf(destination, "%s/%s", OutDirectory, EntryNode->Entry.Filename); + destination = EntryNode->Entry.Filename; else - sprintf(destination, "%s/%08x-%08x-%08x.dat", OutDirectory, - EntryNode->Entry.TypeID, EntryNode->Entry.GroupID, EntryNode->Entry.FileID); + sprintf(destbuffer, "%s%08x%s", groupid_to_dir(EntryNode->Entry.GroupID), + EntryNode->Entry.FileID, typeid_to_ext(EntryNode->Entry.TypeID)); - if(!far_read_entry_data(FARFileInfo, &(EntryNode->Entry), ArchiveData)){ - printf(" (%u/%u) Skipped (%s): %s\n", file, filescount, - "entry data is corrupt", EntryNode->Entry.Filename); + if(far_read_entry_data(FARFileInfo, &(EntryNode->Entry), ArchiveData)){ + /* Decompression, if any, was successful */ + if(!EntryNode->Entry.Filename && EntryNode->Entry.TypeID == 0x2026960B) + sprintf(destbuffer, "%s%08x%s", groupid_to_dir(EntryNode->Entry.GroupID), EntryNode->Entry.FileID, + header_to_ext(EntryNode->Entry.DecompressedData, EntryNode->Entry.DecompressedSize)); + }else{ + printf(" (%u/%u) Skipped (%s): %s\n", file, filescount, "entry data is corrupt", destination); continue; } - /* Decompression, if any, was successful */ + if(mkpath(destination) != 0){ + fprintf(stderr, "%sCould not create path '%s'.", "farextract: error: ", destination); + return -1; + } if(!overwrite){ hFile = fopen(destination, "rb"); if(hFile != NULL){ /* File exists */ fclose(hFile); - printf(" (%u/%u) Skipped (%s): %s\n", file, filescount, "could not open", EntryNode->Entry.Filename); + printf(" (%u/%u) Skipped (%s): %s\n", file, filescount, "file exists", destination); if(EntryNode->Entry.DecompressedData != EntryNode->Entry.CompressedData) libfar_free(EntryNode->Entry.DecompressedData); continue; @@ -206,19 +356,15 @@ int main(int argc, char *argv[]){ } hFile = fopen(destination, "wb"); if(hFile == NULL){ - printf(" (%u/%u) Skipped (%s): %s\n", file, filescount, "could not open", EntryNode->Entry.Filename); + printf(" (%u/%u) Skipped (%s): %s\n", file, filescount, "could not open", destination); if(EntryNode->Entry.DecompressedData != EntryNode->Entry.CompressedData) libfar_free(EntryNode->Entry.DecompressedData); continue; } - if(EntryNode->Entry.Filename) - printf(" (%u/%u) %s (%u bytes)\n", file, filescount, - EntryNode->Entry.Filename, EntryNode->Entry.DecompressedSize); - else - printf(" (%u/%u) %08x-%08x-%08x (%u bytes)\n", file, filescount, - EntryNode->Entry.TypeID, EntryNode->Entry.GroupID, EntryNode->Entry.FileID, - EntryNode->Entry.DecompressedSize); + printf(" (%u/%u) %s (Group ID: 0x%08X, File ID: 0x%08X, Type ID: 0x%08X) (%u bytes)\n", file, filescount, + destination, EntryNode->Entry.GroupID, EntryNode->Entry.FileID, EntryNode->Entry.TypeID, + EntryNode->Entry.DecompressedSize); fwrite(EntryNode->Entry.DecompressedData, 1, EntryNode->Entry.DecompressedSize, hFile); fclose(hFile); @@ -232,8 +378,6 @@ int main(int argc, char *argv[]){ }else{ /* Persist file */ PersistFile * PersistInfo; - char destination[256]; - sprintf(destination, "%s/%s.out", OutDirectory, InFile); /**** ** Load header information @@ -261,7 +405,7 @@ int main(int argc, char *argv[]){ EndingTime = clock(); if(!overwrite){ - hFile = fopen(destination, "rb"); + hFile = fopen(InFile, "rb"); if(hFile != NULL){ /* File exists */ fclose(hFile); @@ -270,7 +414,7 @@ int main(int argc, char *argv[]){ return -1; } } - hFile = fopen(destination, "wb"); + hFile = fopen(InFile, "wb"); if(hFile == NULL){ fprintf(stderr, "%sCould not open.", "farextract: error: "); libfar_free(PersistInfo->DecompressedData); diff --git a/Libraries/FileHandler/utk/read_utk.c b/Libraries/FileHandler/utk/read_utk.c index cd0dba9..45ea103 100644 --- a/Libraries/FileHandler/utk/read_utk.c +++ b/Libraries/FileHandler/utk/read_utk.c @@ -35,21 +35,75 @@ #ifndef round #define round(x) ((x) >= 0 ? (x)+0.5 : (x)-0.5) #endif +#ifndef clamp + #define clamp(x, low, high) ((x) < low ? low : (x) > high ? high : (x)) +#endif #ifndef min #define min(x, y) ((x) < (y) ? (x) : (y)) #endif -static uint8_t ReadBits(utkparams_t *p, uint8_t bits); -static void SetUTKParameters(utkparams_t *p); -static void DecompressBlock(utkparams_t *p); -static void LatticeFilter(utkparams_t *p, int Voiced, float * Window, int Interval); -static void Synthesize(utkparams_t *p, unsigned Sample, unsigned Blocks); -static void PredictionFilter(const float *__restrict ImpulseTrain, float *__restrict Residual); +static uint8_t ReadBits(utkcontext_t *ctx, uint8_t bits); +static void InitUTKParameters(utkcontext_t *ctx); +static void DecodeFrame(utkcontext_t *ctx); +static void GenerateExcitation(utkcontext_t *ctx, int Voiced, float * Window, int Interval); +static void Synthesize(utkcontext_t *ctx, unsigned Sample, unsigned Blocks); +static void RCtoLPC(const float *__restrict RC, float *__restrict LPC); -float UTKTable1[64]; -uint8_t UTKTable2[512]; -const uint8_t UTKTable3[29] = {8,7,8,7,2,2,2,3,3,4,4,3,3,5,5,4,4,6,6,5,5,7,7,6,6,8,8,7,7}; -float UTKTable4[29]; +static const float UTKCosine[64] = { + 0, + -.99677598476409912109375, -.99032700061798095703125, -.983879029750823974609375, -.977430999279022216796875, + -.970982015132904052734375, -.964533984661102294921875, -.958085000514984130859375, -.9516370296478271484375, + -.930754005908966064453125, -.904959976673126220703125, -.879167020320892333984375, -.853372991085052490234375, + -.827579021453857421875, -.801786005496978759765625, -.775991976261138916015625, -.75019800662994384765625, + -.724404990673065185546875, -.6986110210418701171875, -.6706349849700927734375, -.61904799938201904296875, + -.567460000514984130859375, -.515873014926910400390625, -.4642859995365142822265625, -.4126980006694793701171875, + -.361110985279083251953125, -.309523999691009521484375, -.257937014102935791015625, -.20634900033473968505859375, + -.1547619998455047607421875, -.10317499935626983642578125, -.05158700048923492431640625, + 0, + +.05158700048923492431640625, +.10317499935626983642578125, +.1547619998455047607421875, +.20634900033473968505859375, + +.257937014102935791015625, +.309523999691009521484375, +.361110985279083251953125, +.4126980006694793701171875, + +.4642859995365142822265625, +.515873014926910400390625, +.567460000514984130859375, +.61904799938201904296875, + +.6706349849700927734375, +.6986110210418701171875, +.724404990673065185546875, +.75019800662994384765625, + +.775991976261138916015625, +.801786005496978759765625, +.827579021453857421875, +.853372991085052490234375, + +.879167020320892333984375, +.904959976673126220703125, +.930754005908966064453125, +.9516370296478271484375, + +.958085000514984130859375, +.964533984661102294921875, +.970982015132904052734375, +.977430999279022216796875, + +.983879029750823974609375, +.99032700061798095703125, +.99677598476409912109375 +}; +static const uint8_t UTKCodebook[512] = { + 4, 6, 5, 9, 4, 6, 5, 13, 4, 6, 5, 10, 4, 6, 5, 17, + 4, 6, 5, 9, 4, 6, 5, 14, 4, 6, 5, 10, 4, 6, 5, 21, + 4, 6, 5, 9, 4, 6, 5, 13, 4, 6, 5, 10, 4, 6, 5, 18, + 4, 6, 5, 9, 4, 6, 5, 14, 4, 6, 5, 10, 4, 6, 5, 25, + 4, 6, 5, 9, 4, 6, 5, 13, 4, 6, 5, 10, 4, 6, 5, 17, + 4, 6, 5, 9, 4, 6, 5, 14, 4, 6, 5, 10, 4, 6, 5, 22, + 4, 6, 5, 9, 4, 6, 5, 13, 4, 6, 5, 10, 4, 6, 5, 18, + 4, 6, 5, 9, 4, 6, 5, 14, 4, 6, 5, 10, 4, 6, 5, 0, + 4, 6, 5, 9, 4, 6, 5, 13, 4, 6, 5, 10, 4, 6, 5, 17, + 4, 6, 5, 9, 4, 6, 5, 14, 4, 6, 5, 10, 4, 6, 5, 21, + 4, 6, 5, 9, 4, 6, 5, 13, 4, 6, 5, 10, 4, 6, 5, 18, + 4, 6, 5, 9, 4, 6, 5, 14, 4, 6, 5, 10, 4, 6, 5, 26, + 4, 6, 5, 9, 4, 6, 5, 13, 4, 6, 5, 10, 4, 6, 5, 17, + 4, 6, 5, 9, 4, 6, 5, 14, 4, 6, 5, 10, 4, 6, 5, 22, + 4, 6, 5, 9, 4, 6, 5, 13, 4, 6, 5, 10, 4, 6, 5, 18, + 4, 6, 5, 9, 4, 6, 5, 14, 4, 6, 5, 10, 4, 6, 5, 2, + 4, 11, 7, 15, 4, 12, 8, 19, 4, 11, 7, 16, 4, 12, 8, 23, + 4, 11, 7, 15, 4, 12, 8, 20, 4, 11, 7, 16, 4, 12, 8, 27, + 4, 11, 7, 15, 4, 12, 8, 19, 4, 11, 7, 16, 4, 12, 8, 24, + 4, 11, 7, 15, 4, 12, 8, 20, 4, 11, 7, 16, 4, 12, 8, 1, + 4, 11, 7, 15, 4, 12, 8, 19, 4, 11, 7, 16, 4, 12, 8, 23, + 4, 11, 7, 15, 4, 12, 8, 20, 4, 11, 7, 16, 4, 12, 8, 28, + 4, 11, 7, 15, 4, 12, 8, 19, 4, 11, 7, 16, 4, 12, 8, 24, + 4, 11, 7, 15, 4, 12, 8, 20, 4, 11, 7, 16, 4, 12, 8, 3, + 4, 11, 7, 15, 4, 12, 8, 19, 4, 11, 7, 16, 4, 12, 8, 23, + 4, 11, 7, 15, 4, 12, 8, 20, 4, 11, 7, 16, 4, 12, 8, 27, + 4, 11, 7, 15, 4, 12, 8, 19, 4, 11, 7, 16, 4, 12, 8, 24, + 4, 11, 7, 15, 4, 12, 8, 20, 4, 11, 7, 16, 4, 12, 8, 1, + 4, 11, 7, 15, 4, 12, 8, 19, 4, 11, 7, 16, 4, 12, 8, 23, + 4, 11, 7, 15, 4, 12, 8, 20, 4, 11, 7, 16, 4, 12, 8, 28, + 4, 11, 7, 15, 4, 12, 8, 19, 4, 11, 7, 16, 4, 12, 8, 24, + 4, 11, 7, 15, 4, 12, 8, 20, 4, 11, 7, 16, 4, 12, 8, 3 +}; +static const uint8_t UTKCodeSkips[29] = {8,7,8,7,2,2,2,3,3,4,4,3,3,5,5,4,4,6,6,5,5,7,7,6,6,8,8,7,7}; int utk_read_header(utkheader_t * UTKHeader, const uint8_t * Buffer, size_t FileSize) { @@ -83,258 +137,199 @@ int utk_read_header(utkheader_t * UTKHeader, const uint8_t * Buffer, size_t File return 1; } -int utk_decode(const uint8_t *__restrict InBuffer, uint8_t *__restrict OutBuffer, size_t Frames){ - utkparams_t p; +int utk_decode(const uint8_t *__restrict InBuffer, uint8_t *__restrict OutBuffer, size_t InSize, size_t Samples){ + utkcontext_t p; p.InData = InBuffer; - SetUTKParameters(&p); + p.InDataEnd = InBuffer + InSize; + InitUTKParameters(&p); - while(Frames){ - int i, BlockSize = min(Frames, 432); - DecompressBlock(&p); + while(Samples){ + int i, BlockSize = min(Samples, 432); + DecodeFrame(&p); for(i=0; i 32767) - value = 32767; - + int value = round(p.DecompressedFrame[i]); + value = clamp(value, -32768, 32767); write_uint16(OutBuffer, value); OutBuffer += 2; } - Frames -= BlockSize; + Samples -= BlockSize; } return 1; } -void UTKGenerateTables(void){ - /* Call once per runtime */ - int i; +static uint8_t ReadBits(utkcontext_t *ctx, uint8_t bits){ + unsigned value = ctx->UnreadBitsValue & (255>>(8-bits)); + ctx->UnreadBitsValue >>= bits; + ctx->UnreadBitsCount -= bits; - /* UTKTable1 */ - UTKTable1[0] = 0; - for(i=-31; i<32; i++){ - int s = (i>=0) ? 1 : -1; - if (s*i<14) UTKTable1[i+32] = i*.051587f; - else if(s*i<25) UTKTable1[i+32] = i*.051587f/2 + s*.337503f; - else UTKTable1[i+32] = i*.051587f/8 + s*.796876f; - } - - /* UTKTable2 */ - for(i=0; i<512; i++){ - switch(i%4){ - case 0: UTKTable2[i] = 4; break; - case 1: UTKTable2[i] = (i<256) ? 6 : (11 + (i%8 > 4)); break; - case 2: UTKTable2[i] = (i<256) ? 5 : (7 + (i%8 > 4)); break; - case 3: { - const uint8_t l1[] = {9,15,13,19,10,16}, - l2[] = {17,21,18,25,17,22,18,00,17,21,18,26,17,22,18,02, - 23,27,24,01,23,28,24,03,23,27,24,01,23,28,24,03}; - if(i%16 < 4) UTKTable2[i] = l1[0 + (i>256)]; - else if(i%16 < 8) UTKTable2[i] = l1[2 + (i>256)] + (i%32 > 16); - else if(i%16 < 12) UTKTable2[i] = l1[4 + (i>256)]; - else UTKTable2[i] = l2[i/16]; - } break; - } - } - - /* UTKTable4 */ - UTKTable4[0] = 0; - for(i=0; i<7; i++){ - UTKTable4[4*i+1] = -i; - UTKTable4[4*i+2] = +i; - UTKTable4[4*i+3] = -i; - UTKTable4[4*i+4] = +i; - } -} - -static uint8_t ReadBits(utkparams_t *p, uint8_t bits){ - unsigned value = p->UnreadBitsValue & (255>>(8-bits)); - p->UnreadBitsValue >>= bits; - p->UnreadBitsCount -= bits; - - if(p->UnreadBitsCount < 8){ - p->UnreadBitsValue |= *(p->InData++) << p->UnreadBitsCount; - p->UnreadBitsCount += 8; + if(ctx->UnreadBitsCount < 8 && ctx->InData != ctx->InDataEnd){ + ctx->UnreadBitsValue |= *(ctx->InData++) << ctx->UnreadBitsCount; + ctx->UnreadBitsCount += 8; } return value; } -static void SetUTKParameters(utkparams_t *p){ - /* Call once per file */ +static void InitUTKParameters(utkcontext_t *ctx){ int i; - float s; - p->UnreadBitsValue = *(p->InData++); - p->UnreadBitsCount = 8; - p->UseLattice = (int)ReadBits(p, 1); - p->NoiseFloor = 32 - ReadBits(p, 4); - p->FixedCodebook[0] = (ReadBits(p, 4)+1)*8; + float base; + ctx->UnreadBitsValue = *(ctx->InData++); + ctx->UnreadBitsCount = 8; + ctx->HalvedExcitation = ReadBits(ctx, 1); + ctx->VoicedThreshold = 32 - ReadBits(ctx, 4); + ctx->InnovationPower[0] = (ReadBits(ctx, 4)+1) * 8; /* significand */ - s = (float)ReadBits(p, 6)/1000 + 1.04; + base = 1.04f + (float)ReadBits(ctx, 6)/1000; for(i=1; i<64; i++) - p->FixedCodebook[i] = p->FixedCodebook[i-1]*s; + ctx->InnovationPower[i] = ctx->InnovationPower[i-1]*base; - memset(p->ImpulseTrain, 0, 12*sizeof(float)); - memset(p->R, 0, 12*sizeof(float)); - memset(p->Delay, 0, 324*sizeof(float)); + memset(ctx->RC, 0, 12*sizeof(float)); + memset(ctx->History, 0, 12*sizeof(float)); + memset(ctx->Delay, 0, 324*sizeof(float)); } -static void DecompressBlock(utkparams_t *p){ +static void DecodeFrame(utkcontext_t *ctx){ int i,j; - float Window[118]; - float Matrix[12]; + float Excitation[118]; /* includes 5 0-valued samples to both the left and the right */ + float RCDelta[12]; int Voiced = 0; - memset(&Window[0], 0, 5*sizeof(float)); - memset(&Window[113], 0, 5*sizeof(float)); + memset(&Excitation[0], 0, 5*sizeof(float)); + memset(&Excitation[113], 0, 5*sizeof(float)); for(i=0; i<12; i++){ - unsigned result = ReadBits(p, (i<4) ? 6 : 5); - if(i==0 && p->NoiseFloor > result) Voiced++; - Matrix[i] = (UTKTable1[result + ((i<4)?0:16)] - p->ImpulseTrain[i])/4; + unsigned result = ReadBits(ctx, (i<4) ? 6 : 5); + if(i==0 && result < ctx->VoicedThreshold) Voiced++; + RCDelta[i] = (UTKCosine[result + ((i<4)?0:16)] - ctx->RC[i])/4; } for(i=0; i<4; i++){ float PitchGain, InnovationGain; - int Phase = (int)ReadBits(p, 8); - PitchGain = (float)ReadBits(p, 4)/15; - InnovationGain = p->FixedCodebook[ReadBits(p, 6)]; + int Phase = ReadBits(ctx, 8); + PitchGain = (float)ReadBits(ctx, 4)/15; + InnovationGain = ctx->InnovationPower[ReadBits(ctx, 6)]; - if(!p->UseLattice){ - LatticeFilter(p, Voiced, &Window[5], 1); + if(!ctx->HalvedExcitation){ + GenerateExcitation(ctx, Voiced, &Excitation[5], 1); }else{ - int o = ReadBits(p, 1); /* Order */ - int y = ReadBits(p, 1); - LatticeFilter(p, Voiced, &Window[5+o], 2); + /* Fill the excitation window with half as many samples and interpolate the rest */ + int Alignment = ReadBits(ctx, 1); /* whether to fill the even or odd samples */ + int FillWithZero = ReadBits(ctx, 1); + GenerateExcitation(ctx, Voiced, &Excitation[5+Alignment], 2); - if(y){ + if(FillWithZero){ for(j=0; j<108; j+=2) - Window[6-o + j] = 0; + Excitation[5 + (1-Alignment) + j] = 0.0; }else{ - /* Vector quantization */ - float *z = &Window[6-o]; - for(j=0; j<54; j++, z+=2) - *z = - (z[-5]+z[+5]) * .0180326793f - - (z[-3]+z[+3]) * .1145915613f - + (z[-1]+z[+1]) * .5973859429f; + /* Use sinc interpolation with 6 neighboring samples */ + float *x = &Excitation[5 + (1-Alignment)]; + for(j=0; j<54; j++, x+=2) + *x = (x[-1]+x[+1]) * .5973859429f + - (x[-3]+x[+3]) * .1145915613f + + (x[-5]+x[+5]) * .0180326793f; InnovationGain /= 2; } } - /* Excitation */ + /* If 216-Phase is negative on the first subframe, it will read into RC and History + as the reference decoder does, which have been initialized to 0 in InitUTKParameters(). */ for(j=0; j<108; j++) - p->DecompressedBlock[108*i + j] = InnovationGain*Window[5+j] + PitchGain*p->Delay[216 - Phase + 108*i + j]; + ctx->DecompressedFrame[108*i + j] = InnovationGain*Excitation[5+j] + PitchGain*ctx->Delay[108*i + j + (216-Phase)]; + for(j=0; j<108; j++) + ctx->WhatIsThis[108*i + j] = PitchGain*ctx->Delay[108*i + j + (216-Phase)]; } - memcpy(p->Delay, &p->DecompressedBlock[108], 324*sizeof(float)); + memcpy(ctx->Delay, &ctx->DecompressedFrame[108], 324*sizeof(float)); for(i=0; i<4; i++){ + /* Linearly interpolate the reflection coefficients for the current subframe */ for(j=0; j<12; j++) - p->ImpulseTrain[j] += Matrix[j]; + ctx->RC[j] += RCDelta[j]; - Synthesize(p, i*12, (i!=3) ? 1 : 33); + Synthesize(ctx, i*12, (i!=3) ? 12 : 396); } } -static void LatticeFilter(utkparams_t *p, int Voiced, float * Window, int Interval){ +static void GenerateExcitation(utkcontext_t *ctx, int Voiced, float * Window, int Interval){ if(Voiced){ - int t = 0; + int Table = 0; int i = 0; while(i<108){ - unsigned code = UTKTable2[(t<<8) | (p->UnreadBitsValue&0xFF)]; - t = (code<2 || code>8); - ReadBits(p, UTKTable3[code]); + unsigned code = UTKCodebook[(Table<<8) | (ctx->UnreadBitsValue&0xFF)]; + Table = (code<2 || code>8); + ReadBits(ctx, UTKCodeSkips[code]); if(code >= 4){ - Window[i] = UTKTable4[code]; + /* Fill a sample with a value specified by the code; magnitude is limited to 6.0 */ + Window[i] = (code-1)/4; + if(code&1) + Window[i] *= -1.0; + i += Interval; - }else{ - if(code > 1){ - int x = (int)ReadBits(p, 6)+7; - if(x > (108 - i)/Interval) - x = (108 - i)/Interval; - - while(x--){ - Window[i] = 0; - i += Interval; - } - }else{ - Window[i] = 7; - while(ReadBits(p, 1)) - Window[i]++; - - if(!ReadBits(p, 1)) - Window[i] *= -1; + }else if(code >= 2){ + /* Fill between 7 and 70 samples with 0s */ + int x = ReadBits(ctx, 6) + 7; + x = min(x, (108 - i)/Interval); + while(x--){ + Window[i] = 0.0; i += Interval; } + }else{ + /* Fill a sample with a custom value with magnitude >= 7.0 */ + Window[i] = 7.0; + while(ReadBits(ctx, 1)) + Window[i]++; + + if(!ReadBits(ctx, 1)) + Window[i] *= -1; + + i += Interval; } } }else{ - /* Unvoiced signal; load noise */ + /* Unvoiced: restrict all samples to 0.0, -2.0, or +2.0 without using the codebook */ int i; for(i=0; i<108; i+=Interval){ - uint8_t b; - switch(p->UnreadBitsValue & 3){ - case 3: - Window[i] = 2.0; - b = 2; - break; - case 1: - Window[i] = -2.0; - b = 2; - break; - default: - Window[i] = 0.0; - b = 1; - } - - ReadBits(p, b); + if(!ReadBits(ctx, 1)) Window[i] = 0.0; + else if(!ReadBits(ctx, 1)) Window[i] = -2.0; + else Window[i] = 2.0; } } } -static void Synthesize(utkparams_t *p, unsigned Sample, unsigned Blocks){ - float Residual[12]; - unsigned Samples = Blocks*12; +static void Synthesize(utkcontext_t *ctx, size_t Sample, size_t Samples){ + float LPC[12]; int offset = -1; - PredictionFilter(p->ImpulseTrain, Residual); + RCtoLPC(ctx->RC, LPC); while(Samples--){ int i; - float x = p->DecompressedBlock[Sample]; for(i=0; i<12; i++){ if(++offset == 12) offset = 0; - x += p->R[offset] * Residual[i]; + ctx->DecompressedFrame[Sample] += LPC[i] * ctx->History[offset]; } - p->R[offset--] = x; - p->DecompressedBlock[Sample++] = x; + ctx->History[offset--] = ctx->DecompressedFrame[Sample++]; } } -static void PredictionFilter(const float *__restrict ImpulseTrain, float *__restrict Residual){ +static void RCtoLPC(const float *__restrict RC, float *__restrict LPC){ int i,j; - float ResidualGain[12]; - float ImpulseGain[12]; - ImpulseGain[0] = 1; - memcpy(&ImpulseGain[1], ImpulseTrain, 11*sizeof(float)); + float RCTemp[12], LPCTemp[12]; + RCTemp[0] = 1.0; + memcpy(&RCTemp[1], RC, 11*sizeof(float)); for(i=0; i<12; i++){ - float x = 0; + LPC[i] = 0.0; for(j=11; j>=0; j--){ - x -= ImpulseTrain[j] * ImpulseGain[j]; + LPC[i] -= RC[j] * RCTemp[j]; if(j != 11) - ImpulseGain[j+1] = x*ImpulseTrain[j] + ImpulseGain[j]; + RCTemp[j+1] = RCTemp[j] + RC[j] * LPC[i]; } - ImpulseGain[0] = x; - ResidualGain[i] = x; + RCTemp[0] = LPCTemp[i] = LPC[i]; for(j=0; j #include #include +#define HITASM_HEADERS #include "hitutils.h" static uint8_t ObjectHeader[] = { 0x7F, 0x45, 0x4C, 0x46, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x40, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, + 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -103,29 +104,35 @@ enum { CN_LABELONLY = 1 }; +enum Sections { + Text, SymbolTable, StringTable, RelocationTable, SectionCount +}; + static FILE *hFile = NULL; static char *path[filecount] = {NULL}; static uint8_t *data[filecount] = {NULL}; -static ByteWriterContext TextSection = {0,0,1024,"text"}; -static ByteWriterContext SymbolTable = {0,0,1024,"symtab"}; -static ByteWriterContext StringTable = {0,0,1024,"strtab"}; -static ByteWriterContext RelocationTable = {0,0,1024,".rel.text"}; +static ByteWriterContext Section[] = { + {0,0,1024,"text"}, + {0,0,1024,"symtab"}, + {0,0,1024,"strtab"}, + {0,0,1024,".rel.text"} +}; static uint8_t * add_symbol(const char * Name){ - bw_write32(&SymbolTable, StringTable.Position); - bw_write32(&SymbolTable, 0); - bw_write32(&SymbolTable, 0); - bw_write32(&SymbolTable, 18); - bw_write_string(&StringTable, Name); - return SymbolTable.Data + SymbolTable.Position - 16; + bw_write32(&Section[SymbolTable], Section[StringTable].Position); + bw_write32(&Section[SymbolTable], 0); + bw_write32(&Section[SymbolTable], 0); + bw_write32(&Section[SymbolTable], 18); + bw_write_string(&Section[StringTable], Name); + return Section[SymbolTable].Data + Section[SymbolTable].Position - 16; } static uint8_t * find_symbol_by_name(const char * Name, uint32_t * SymbolIndex){ uint32_t p; - for(p=48; p>4; - return SymbolTable.Data + p; + return Section[SymbolTable].Data + p; } } @@ -233,7 +240,7 @@ static __inline void parser_add_symbol(const ParserContext *pc){ path[txt], pc->Line, pc->Col, pc->Token, path[txt], read_uint32(Symbol+8)); }else Symbol = add_symbol(pc->Token); - write_uint32(Symbol+4, TextSection.Position); + write_uint32(Symbol+4, Section[Text].Position); write_uint32(Symbol+8, pc->Line); } @@ -244,8 +251,8 @@ static __inline void parser_add_reference(const ParserContext *pc){ if(!find_symbol_by_name(pc->Token, &SymbolIndex)) add_symbol(pc->Token); - bw_write32(&RelocationTable, TextSection.Position); - bw_write32(&RelocationTable, (SymbolIndex<<8)|0x02); + bw_write32(&Section[RelocationTable], Section[Text].Position); + bw_write32(&Section[RelocationTable], (SymbolIndex<<8)|0x02); } static uint32_t read_integer(const ParserContext *pc, uint32_t maxval){ @@ -339,10 +346,8 @@ static void Shutdown(){ free(path[i]); free(data[i]); } - free(TextSection.Data); - free(SymbolTable.Data); - free(StringTable.Data); - free(RelocationTable.Data); + for(i=0; i>= 4) != 0; i++){ int type = operands & 15; @@ -564,19 +543,17 @@ int main(int argc, char *argv[]){ path[txt], pc.Line, pc.Col, pc.Token, InstructionName, position[j], position[i]); } - printf("Operand: %s\n", pc.Token); - if(type == o_byte) - bw_write8(&TextSection, read_constant(&pc, 0, 0x000000FF)); + bw_write8(&Section[Text], read_constant(&pc, 0, 0x000000FF)); else if(type == o_dword) - bw_write32(&TextSection, read_constant(&pc, 0, 0xFFFFFFFF)); + bw_write32(&Section[Text], read_constant(&pc, 0, 0xFFFFFFFF)); else if(type == o_address) - bw_write32(&TextSection, read_constant(&pc, CN_LABELONLY, 0xFFFFFFFF)); + bw_write32(&Section[Text], read_constant(&pc, CN_LABELONLY, 0xFFFFFFFF)); else if(type == o_variable) - bw_write8(&TextSection, read_variable(&pc, Variables, VariableCount)); + bw_write8(&Section[Text], read_variable(&pc, Variables, VariableCount)); else if(type == o_jump){ /* TODO: Change this */ - bw_write32(&TextSection, read_constant(&pc, CN_LABELONLY, 0xFFFFFFFF)); + bw_write32(&Section[Text], read_constant(&pc, CN_LABELONLY, 0xFFFFFFFF)); } } } @@ -589,31 +566,35 @@ int main(int argc, char *argv[]){ Shutdown_M("%s:%u:%u: error: expected ']' for end of BINARY section before end of file\n", path[txt], pc.Line, pc.Col); - for(i=48+8; iCount*sizeof(address_t) == List->SizeAllocated){ void * ptr; - if(List->SizeAllocated > SIZE_MAX/2 || !(ptr = realloc(List->Entries, (List->SizeAllocated <<= 1)))) + if(List->SizeAllocated > SIZE_MAX/2 || !(ptr = realloc(List->Entries, List->SizeAllocated<<=1))) Shutdown_M("%sCould not allocate memory for address list.\n", "hitdump: Error: "); List->Entries = ptr; } diff --git a/Tools/hitutils/hitld.c b/Tools/hitutils/hitld.c index f899cad..37ac5b5 100644 --- a/Tools/hitutils/hitld.c +++ b/Tools/hitutils/hitld.c @@ -16,17 +16,159 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include +#include #include +#include +#include +#include "hitutils.h" + +static const uint8_t ObjectHeader[] = {0x7F, 0x45, 0x4C, 0x46, 0x01, 0x01, 0x01}; +static const uint8_t ArchiveHeader[] = {'!', '<', 'a', 'r', 'c', 'h', '>', '\n'}; + +enum { + hsm, hot, out, filecount +}; + +typedef struct { + char *path; + uint8_t *data; +} object_t; + +typedef struct { + size_t SizeAllocated; + size_t Count; + object_t * Entries; +} objectlist_t; + +static object_t * add_object(objectlist_t * List){ + if(List->Count*sizeof(object_t) == List->SizeAllocated){ + void * ptr; + if(List->SizeAllocated > SIZE_MAX/2 || !(ptr = realloc(List->Entries, List->SizeAllocated<<=1))) + Shutdown_M("%sCould not allocate memory for object list.\n", "hitld: Error: "); + List->Entries = ptr; + } + return memset(List->Entries + List->Count++, 0, sizeof(object_t)); +} + +static FILE *hFile = NULL; +static char *path[filecount] = {NULL}; +static uint8_t *data[filecount] = {NULL}; +static objectlist_t ObjectList = {0}; + +static void Shutdown(){ + unsigned i; + for(i=0; i.\n" + "hitutils is maintained by the Niotso project.\n" + "Home page: \n"); + return 0; + } + + for(i=1; i<(unsigned)argc-1; i++){ + if(!strcmp(argv[i], "-ts1")) SimsVersion = VERSION_TS1; + else if(!strcmp(argv[i], "-tso")) SimsVersion = VERSION_TSO; + else if(!strcmp(argv[i], "-f")) overwrite = 1; + else if(i != (unsigned)argc-2){ + if(!strcmp(argv[i], "-o")) path[out] = argv[++i]; + else if(!strcmp(argv[i], "-hsm")) path[hsm] = argv[++i]; + else if(!strcmp(argv[i], "-hot")) path[hot] = argv[++i]; + else break; + } + else break; + } + ObjectArg = i; + for(i=0; i.\n" - "hitutils is maintained by the Niotso project.\n" - "Home page: \n"); return 0; } \ No newline at end of file