Advertisement
Guest User

FSB5_to_ATRAC9(Bloodborne)

a guest
Dec 22nd, 2017
1,198
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 15.34 KB | None | 0 0
  1. // extracts ATRAC9 audio files from FMOD sound bank (FSB5) files for Bloodborne
  2. //by adlem/albeartron
  3. /*
  4.     This program is free software: you can redistribute it and/or modify
  5.     it under the terms of the GNU General Public License as published by
  6.     the Free Software Foundation, either version 3 of the License, or
  7.     (at your option) any later version.
  8.  
  9.     This program is distributed in the hope that it will be useful,
  10.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.     GNU General Public License for more details.
  13.  
  14.     You should have received a copy of the GNU General Public License
  15.     along with this program.  If not, see <http://www.gnu.org/licenses/>.
  16. */
  17.  
  18.  
  19. #include <iostream>
  20. #include <fstream>
  21. #include <inttypes.h>
  22. #include <string>
  23.  
  24. #define VERSION "Rev0-1"
  25.  
  26. #pragma pack(1) //bytewise
  27. struct ATRAC9_HEADER {
  28.     //used to assemble the header that goes on the output data
  29.     //ATRAC9 header info from PS4 SDK documentation
  30.     unsigned char   RIFF_Chunk_ID[4] = { 0x52, 0x49, 0x46, 0x46 };  //alwyas "RIFF"
  31.     std::uint32_t   RIFF_Chunk_Data_Size;       //should be 92 + datasize (0x5C + datasize)
  32.     unsigned char   RIFF_Type_ID[4] = { 0x57, 0x41, 0x56, 0x45 };   //always 'WAVE"
  33.     //fmt chunk
  34.     unsigned char   fmt_Chunk_ID[4] = { 0x66, 0x6d, 0x74, 0x20 };   //always "fmt "
  35.     std::uint32_t   fmt_Chunk_Data_Size = 52;   //size of the fmt chunk is always 52 (0x34)
  36.     std::uint16_t   wFormatTag = 0xFFFE;        //WAVE_FORMAT_EXTENSIBLE = 0xFFFE (a.k.a. AT9)
  37.     std::uint16_t   nChannels;                  //determined by FSB header
  38.     std::uint32_t   nSamplesPerSec;             //determined by FSB header
  39.     std::uint32_t   nAvgBytesPerSec;            //Average byte rate [Byte/s], Calculated by rounding off nBlockAlign * nSamplesPerSec / wSamplesPerBlock
  40.     std::uint16_t   nBlockAlign;                //Audio block size [Byte]
  41.     std::uint16_t   wBitsPerSample = 0;         //Quantifying bit number (0)
  42.     std::uint16_t   cbSize = 34;                //Extension size (34)
  43.     std::uint16_t   wSamplesPerBlock = 1024;    //Number of output samples of the audio block
  44.     std::uint32_t   dwChannelMask = 4;          //Channel map of speaker position
  45.     std::uint8_t    SubFormat[16] = { 0xD2, 0x42, 0xE1, 0x47, 0xBA, 0x36, 0x8D, 0x4D, 0x88, 0xFC, 0x61, 0x65, 0x4F, 0x8C, 0x83, 0x6C }; //GUID,  Codec identifier (KSDATAFORMAT_SUBTYPE_ATRAC9 = {47E142D2-36BA-4d8d-88FC-61654F8C836C})
  46.     std::uint32_t   dwVersionInfo = 1;          //Version information (1 or 2)
  47.     //ATRAC9 config data bitfield
  48.     unsigned char   atrac9_id : 8;
  49.     std::uint8_t    reserved1 : 1;
  50.     std::uint8_t    sampling_rate_index : 3;
  51.     std::uint8_t    channel_config_index : 3;
  52.     std::uint8_t    reserved2 : 1;
  53.     std::uint16_t   frame_length_index : 11;
  54.     std::uint8_t    super_frame_index : 2;
  55.     std::uint8_t    reserved3 : 3;
  56.     std::uint32_t   reserved4 = 0;  //padding
  57.     //fact chunk
  58.     unsigned char   fact_Chunk_ID[4] = { 0x66, 0x61 ,0x63, 0x74 };  //always "fact"
  59.     std::uint32_t   fact_Chunk_Data_Size = 12;  //size of the fact chunk is always 12
  60.     std::uint32_t   Total_Samples;              //found in FSB sample header
  61.     std::uint32_t   Input_And_Overlap_Delay_Samples = 256; 
  62.     std::uint32_t   Encoder_Delay_Samples = 256;           
  63.     //data chunk
  64.     unsigned char   data_Chunk_ID[4] = { 0x64, 0x61, 0x74, 0x61 };  //always "data"
  65.     std::uint32_t   data_Chunk_Data_Size;
  66. };
  67.  
  68. struct FSB5_HEADER {
  69.     //this info found in "FSB5.bt" template by Simon Pinfold for "010 Editor"
  70.     unsigned char   FSB5_ID[4];         //FSB5 identifier
  71.     std::uint32_t   FSB5_version;       //sub version number, e.g. 5.1
  72.     std::uint32_t   numSamples;         //number of file/sample entries in this FSB
  73.     std::uint32_t   sampleHeaderSize;   //size of the headers info section (following this main header)
  74.     std::uint32_t   nameTableSize;      //size of the names table section (following the headers section)
  75.     std::uint32_t   dataSize;           //size of the data section (following the names table section)
  76.     //settings
  77.     std::uint32_t   mode;               //at9 files are 0x0000000D = 13; not included in the original FSB5.bt template
  78.     std::uint8_t    unknown01[8];       //unknown
  79.     std::uint8_t    unknown02[16];      //unknown hash?
  80.     std::uint8_t    unknown03[8];       //unknown
  81.     //headers table follows this section
  82. };
  83.  
  84. struct FSB5_SAMPLE_HEADER {
  85.     //just the sample header:
  86.     std::uint32_t   extraParams : 1;    //whether or not there are exta chunks after this info
  87.     std::uint32_t   frequency : 4;
  88.     std::uint32_t   twoChannels : 1;
  89.     std::uint32_t   dataOffset : 28;
  90.     std::uint32_t   samples : 30;
  91.     //54 bits... 6 bytes
  92. };
  93.  
  94. struct FSB5_SAMPLE_CHUNK_DEF {
  95.     //fsb5 has different chunks in each sample header, each begins with this structure
  96.     std::uint32_t   next : 1;   //more chunks to follow?
  97.     std::uint32_t   size : 24;  //size of this chunk (just the data)
  98.     std::uint32_t   chunkType : 7;  //chunk type 3=loop, 9=ATRAC9, etc. only caring about ATRAC9 for this
  99. };
  100.  
  101. struct FSB5_SAMPLE_ATRAC9_CHUNK {
  102.     //chunk type 9
  103.     std::uint32_t   unknownByte;    //there's a byte at the beginning of this chunk that might be important but is currently unknown, probably a bitfield that has the info for blockAlign/other things
  104.     std::uint8_t    atrac9_id : 8;              //ATRAC9™ format data(0xFE)
  105.     std::uint8_t    reserved1 : 1;              //Reserved area
  106.     std::uint8_t    sampling_rate_index : 3;    //Sampling rate and number of samples per frame
  107.     std::uint8_t    channel_config_index : 3;   //Number of channels and audio blocks
  108.     std::uint8_t    reserved2 : 1;              //Reserved area
  109.     std::uint16_t   frame_length_index : 11;    //Frame length for bitstreaming, The actual frame length will be (frame_length_index + 1) bytes.
  110.     std::uint8_t    super_frame_index : 2;      //Number of frames in a superframe
  111.     std::uint8_t    reserved3 : 3;              //Reserved area
  112. };
  113. #pragma pack()
  114.  
  115. static void show_usage(std::string);
  116.  
  117. int main(int argc, char *argv[]) {
  118.     if (argc < 2) {
  119.         show_usage(argv[0]);
  120.         return 1;
  121.     }
  122.  
  123.     char* filenametemp = argv[1];
  124.     std::ifstream inputFile(argv[1], std::ios::binary);     //open file as binary
  125.  
  126.     ATRAC9_HEADER outputHeader; //the at9 output file's header, to be populated by this program
  127.  
  128.     //header/chunk structs:
  129.     FSB5_HEADER fsbHeader;
  130.     FSB5_SAMPLE_HEADER fsbSampleHeader, nextSampleHeader;   //each file's header info
  131.     FSB5_SAMPLE_CHUNK_DEF fsbSampleChunk;   //if extraParams != 0
  132.     FSB5_SAMPLE_ATRAC9_CHUNK fsbAt9Chunk;   //important chunk that will dictate ATRAC9 header info
  133.  
  134.     //variables
  135.     std::uint32_t   sampleTableStart;   //where the samples data starts
  136.     std::uint32_t   nameTableStart;     //where the name table starts (the nametable offset list)
  137.     std::uint32_t   dataTableStart;     //where the actual data table starts
  138.     std::uint32_t   dataTableEnd;       //where the end of the data table is (EOF)
  139.  
  140.     std::uint32_t   returnAddress;  //where to come back to after getting name + data
  141.     std::uint32_t   sampleTableCurrent; //the current working location in the sample table
  142.     std::uint32_t   nameTableCurrent;   //the current working location in the name table (offsets list)
  143.     std::uint32_t   nameTableTextOffset;    //start + offset = where the text is
  144.     std::uint32_t   dataTableCurrent;   //the current working location in the data table
  145.     std::uint32_t   nextDataOffset; //used to know where to stop reading
  146.     std::uint32_t   dataEntrySize;
  147.  
  148.     const int MAX_BUFFSIZE = 512;
  149.     char stringBuffer[MAX_BUFFSIZE];
  150.  
  151.     unsigned char tempChar = 0xFF;
  152.     std::uint8_t    tempByte;
  153.     std::uint8_t    tempChannels;   //number of channels in the output
  154.     std::string     tempString; //use for filename output
  155.  
  156.  
  157.     //read FSB5 main header (done once)
  158.     inputFile.read((char *)&fsbHeader, sizeof(fsbHeader));
  159.    
  160.     std::printf("FSB5 ID\t%.*s\n", sizeof(fsbHeader.FSB5_ID), fsbHeader.FSB5_ID);   //string of char [4] (print size/ptr because non null terminated)
  161.     std::printf("Sub Version\t0x%08X\t%d\n", fsbHeader.FSB5_version, fsbHeader.FSB5_version);
  162.     std::printf("numSamples\t0x%08X\t%d\n", fsbHeader.numSamples, fsbHeader.numSamples);
  163.     sampleTableStart = 0x3C;    //not actually important
  164.     std::printf("sampleHeaderSize\t0x%08X\t%d\n", fsbHeader.sampleHeaderSize, fsbHeader.sampleHeaderSize);
  165.     nameTableStart = sampleTableStart + fsbHeader.sampleHeaderSize; //name table starts after FSBheader + sampleHeader
  166.     nameTableCurrent = nameTableStart;  //initial position in name table
  167.     std::printf("nameTableSize\t0x%08X\t%d\n", fsbHeader.nameTableSize, fsbHeader.nameTableSize);
  168.     dataTableStart = nameTableStart + fsbHeader.nameTableSize;
  169.     dataTableCurrent = dataTableStart;  //initial position in the data table
  170.     std::printf("dataSize\t0x%08X\t%d\n", fsbHeader.dataSize, fsbHeader.dataSize);
  171.     dataTableEnd = dataTableStart + fsbHeader.dataSize; //should probably verify that this = EOF
  172.     std::printf("mode\t0x%08X\t%d\n", fsbHeader.mode, fsbHeader.mode);  //it's AT9 mode for the files we care about
  173.     std::printf("unknown01\t0x");
  174.     for (std::uint8_t i = 0; i < sizeof(fsbHeader.unknown01); i++) { std::printf("%02X", fsbHeader.unknown01[i]); } std::printf("\n");
  175.     std::printf("unknown02\t0x");
  176.     for (std::uint8_t i = 0; i < sizeof(fsbHeader.unknown02); i++) { std::printf("%02X", fsbHeader.unknown02[i]); } std::printf("\n");
  177.     std::printf("unknown03\t0x");
  178.     for (std::uint8_t i = 0; i < sizeof(fsbHeader.unknown03); i++) { std::printf("%02X", fsbHeader.unknown03[i]); } std::printf("\n");
  179.     std::printf("\n");
  180.  
  181.     std::printf(
  182.         "no." "\t"
  183.         "xtra" "\t"
  184.         "freq" "\t"
  185.         "2ch?" "\t"
  186.         "datoffset" "\t"
  187.         "#samples" "\t"
  188.         "filename" "\t"
  189.         "dataBegin" "\t"
  190.         "dataEnd" "\n"
  191.     );
  192.  
  193.  
  194.     for (size_t sampleNumber = 0; sampleNumber < fsbHeader.numSamples; sampleNumber++)
  195.     //for (size_t sampleNumber = 0; sampleNumber < 1; sampleNumber++)   //one once for debugging
  196.     {
  197.         std::printf("%d\t", sampleNumber);
  198.         //read SAMPLE header (done for each sample, numsamples times)
  199.         inputFile.read((char *)&fsbSampleHeader, sizeof(fsbSampleHeader));  //read sample header
  200.         //show it
  201.         std::printf("%d\t", fsbSampleHeader.extraParams);
  202.         std::printf("%d\t", fsbSampleHeader.frequency);
  203.         std::printf("%d\t", fsbSampleHeader.twoChannels);
  204.         tempChannels = fsbSampleHeader.twoChannels + 1; //0+1=1, 1+1=2; may be overwritten by CHANNELS chunk info later
  205.         std::printf("0x%08X\t", fsbSampleHeader.dataOffset);    //this is dataStart + this offset
  206.         dataTableCurrent = dataTableStart + (fsbSampleHeader.dataOffset * 16);
  207.         std::printf("%d\t", fsbSampleHeader.samples);
  208.  
  209.         //read SAMPLE header's extra params (if there are any)
  210.         if (fsbSampleHeader.extraParams) {
  211.             do
  212.             {
  213.                 //read the SAMPLE header's extra param chunk info
  214.                 inputFile.read((char *)&fsbSampleChunk, sizeof(fsbSampleChunk));
  215.                 switch (fsbSampleChunk.chunkType)   //do something based on the chunk type
  216.                 {
  217.                 case 1: //channels chunk
  218.                     inputFile.read((char *)&tempChannels, sizeof(tempChannels));    //if there's a channels chunk, read it and store the #
  219.                     //only used for files with >2 channels
  220.                     break;
  221.                 case 3: //loop chunk
  222.                     inputFile.seekg(fsbSampleChunk.size, std::ios::cur);    //skip for now
  223.                     //could add loop info to the ATRAC9 header
  224.                     break;
  225.                 case 9: //ATRAC9 chunk
  226.                     inputFile.read((char *)&fsbAt9Chunk, sizeof(fsbAt9Chunk));  //read the ATRAC9 config data
  227.                     break;
  228.                 default:
  229.                     inputFile.seekg(fsbSampleChunk.size, std::ios::cur);    //skip this unknown chunk
  230.                     //several other chunk types were encountered in the Bloodborne files but no time was spent to learn what they do as they don't seem important for decoding
  231.                     break;
  232.                 }
  233.             } while (fsbSampleChunk.next);  //if next = 1, repeat the above since there are more chunks for this sample
  234.         }
  235.         sampleTableCurrent = inputFile.tellg(); //remember where we were in the sampleHeaders, last step for this file will be returning here
  236.         //go to the name table (first time this is at nameTableStart)
  237.         inputFile.seekg(nameTableCurrent);
  238.         //determine the name location, save in fileNameOffset
  239.         inputFile.read((char *)&nameTableTextOffset, sizeof(nameTableTextOffset));  //read the offset from the nametable offset list
  240.         nameTableCurrent = inputFile.tellg();   //remember where the next name offset is for next time
  241.         inputFile.seekg(nameTableTextOffset + nameTableStart);  //go to the actual filename location, which is at nameTableStart + whatever offset
  242.         //read until null encountered. this is a dumb way to do this but it worked...
  243.         tempString.clear();
  244.         while (tempChar != 0x00)
  245.         {
  246.             inputFile.read((char *)&tempChar, sizeof(tempChar));
  247.             if (tempChar == 0x00)
  248.             {
  249.                 break;  //don't add the null
  250.             }
  251.             tempString += tempChar;
  252.         }
  253.         tempString += ".at9\0";
  254.         tempChar = 0xFF;
  255.  
  256.         std::printf("\t");
  257.         std::printf("%s\t", tempString.c_str());    //this should be the filename
  258.  
  259.         std::ofstream outputFile(tempString, std::ios::binary);     //create the output file and open file as binary
  260.    
  261.         //doesn't have data chunk size info so:
  262.         //check if this is the last entry
  263.         if (sampleNumber + 1 == fsbHeader.numSamples)
  264.         {
  265.             //this is the last sample, read until EOF
  266.             dataEntrySize = dataTableEnd - dataTableCurrent;    //size of entry is EOF - currentoffset
  267.         }
  268.         else
  269.         {
  270.             //not the last sample, so get next sampleheader to find where the next sample begins
  271.             inputFile.seekg(sampleTableCurrent);
  272.             inputFile.read((char *)&nextSampleHeader, sizeof(nextSampleHeader));
  273.             dataEntrySize = (dataTableStart + (nextSampleHeader.dataOffset * 16)) - dataTableCurrent;   //size of this entry is nextoffset - currentoffset
  274.         }
  275.  
  276.         //write the ATRAC9 config data to the at9 output's header here
  277.         //riff
  278.         outputHeader.RIFF_Chunk_Data_Size = 0x58 + dataEntrySize;   //ATRAC9 could have extra chunks but this program doesn't add them in
  279.         outputHeader.nChannels = tempChannels;
  280.         outputHeader.nSamplesPerSec = 48000;    //need to add code to interpret fsbSampleHeader.frequency, but '9' = 48000Hz and all the files appear the same for Bloodborne
  281.         outputHeader.nAvgBytesPerSec = 9000;    //should calculate this instead, but at9tool will still extract audio with incorrect value
  282.         outputHeader.nBlockAlign = 48;  //should calculate this instead, but at9tool will still extract audio with incorrect value (may be in FSB ATRAC9 chunk's first half)
  283.         //config
  284.         outputHeader.atrac9_id = fsbAt9Chunk.atrac9_id;
  285.         outputHeader.reserved1 = fsbAt9Chunk.reserved1;
  286.         outputHeader.sampling_rate_index = fsbAt9Chunk.sampling_rate_index;
  287.         outputHeader.channel_config_index = fsbAt9Chunk.channel_config_index;
  288.         outputHeader.reserved2 = fsbAt9Chunk.reserved2;
  289.         outputHeader.frame_length_index = fsbAt9Chunk.frame_length_index;
  290.         outputHeader.super_frame_index = fsbAt9Chunk.super_frame_index;
  291.         outputHeader.reserved3 = fsbAt9Chunk.reserved3;
  292.         //fact
  293.         outputHeader.Total_Samples = fsbSampleHeader.samples;
  294.         outputHeader.data_Chunk_Data_Size = dataEntrySize;
  295.  
  296.         outputFile.write((char *)&outputHeader, sizeof(outputHeader));  //write the ATRAC9 header
  297.  
  298.         inputFile.seekg(dataTableCurrent);  //go to where the data starts
  299.         //read data starting here, total size of dataEntrySize
  300.  
  301.         std::printf("0x%08X\t", dataTableCurrent);
  302.         std::printf("0x%08X\t", dataEntrySize);
  303.         std::printf("\n");
  304.  
  305.         //send the data from the FSB into the new file
  306.         //there's probably a better way to do this, but this seems to work OK
  307.         for (size_t i = 0; i < dataEntrySize; i++)
  308.         {
  309.             inputFile.read((char *)&tempByte, sizeof(tempByte));
  310.             outputFile.write((char *)&tempByte, sizeof(tempByte));
  311.         }
  312.  
  313.         outputFile.close();
  314.         //then move onto the next sample and repeat the process numSamples times total
  315.         inputFile.seekg(sampleTableCurrent);
  316.     }
  317.    
  318.    
  319.     return 0;
  320. }
  321.  
  322. static void show_usage(std::string execName) {
  323.     std::cerr
  324.         << "Revision: " << VERSION << '\n'
  325.         << "Usage: " << execName << " <FILE1>\n"
  326.         << "\t<FILE1>\tFSB5 input file (required)\n";
  327. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement