diff options
author | antoniou79 | 2019-01-05 17:47:27 +0200 |
---|---|---|
committer | Eugene Sandulenko | 2019-01-06 17:12:02 +0100 |
commit | 9dfe8281fc5f490b6776ee2b3a85f73eac1765be (patch) | |
tree | a6d22d4770a5808f66c4ec889fa56256a765bafe /devtools/create_bladerunner/subtitles/quotesSpreadsheetCreator | |
parent | 49497bfb4aff36f20ccb31e951335dc11348e652 (diff) | |
download | scummvm-rg350-9dfe8281fc5f490b6776ee2b3a85f73eac1765be.tar.gz scummvm-rg350-9dfe8281fc5f490b6776ee2b3a85f73eac1765be.tar.bz2 scummvm-rg350-9dfe8281fc5f490b6776ee2b3a85f73eac1765be.zip |
DEVTOOLS: Quotes Excel creator exports extra audio
quoteSpreadsheetCreator exports dev commentary and some optional speech audio from SFX.MIX
Diffstat (limited to 'devtools/create_bladerunner/subtitles/quotesSpreadsheetCreator')
6 files changed, 660 insertions, 337 deletions
diff --git a/devtools/create_bladerunner/subtitles/quotesSpreadsheetCreator/audFileDecode.py b/devtools/create_bladerunner/subtitles/quotesSpreadsheetCreator/audFileDecode.py index 832cc7115d..5be678f3f2 100644 --- a/devtools/create_bladerunner/subtitles/quotesSpreadsheetCreator/audFileDecode.py +++ b/devtools/create_bladerunner/subtitles/quotesSpreadsheetCreator/audFileDecode.py @@ -18,7 +18,8 @@ except ImportError: else: structLibFound = True -if (not ctypesLibFound) or (not structLibFound): +if (not ctypesLibFound) \ + or (not structLibFound): sys.stdout.write("[Error] Errors were found when trying to import required python libraries\n") sys.exit(1) diff --git a/devtools/create_bladerunner/subtitles/quotesSpreadsheetCreator/audFileLib.py b/devtools/create_bladerunner/subtitles/quotesSpreadsheetCreator/audFileLib.py index ed42c5ef08..2912a93930 100644 --- a/devtools/create_bladerunner/subtitles/quotesSpreadsheetCreator/audFileLib.py +++ b/devtools/create_bladerunner/subtitles/quotesSpreadsheetCreator/audFileLib.py @@ -1,14 +1,28 @@ #!/usr/bin/env python # -*- coding: UTF-8 -*- # -import os, sys - +osLibFound = False +sysLibFound = False shutilLibFound = False waveLibFound = False ctypesLibFound = False structLibFound = False try: + import os +except ImportError: + print "[Error] os python library is required to be installed!" +else: + osLibFound = True + +try: + import sys +except ImportError: + print "[Error] sys python library is required to be installed!" +else: + sysLibFound = True + +try: import shutil except ImportError: print "[Error] Shutil python library is required to be installed!" @@ -36,14 +50,19 @@ except ImportError: else: structLibFound = True -if (not shutilLibFound) or (not waveLibFound) or (not ctypesLibFound) or (not structLibFound): +if (not osLibFound) \ + or (not sysLibFound) \ + or (not shutilLibFound) \ + or (not waveLibFound) \ + or (not ctypesLibFound) \ + or (not structLibFound): sys.stdout.write("[Error] Errors were found when trying to import required python libraries\n") sys.exit(1) from struct import * from audFileDecode import * -my_module_version = "0.60" +my_module_version = "0.80" my_module_name = "audFileLib" #constants @@ -52,12 +71,13 @@ SIZE_OF_AUD_HEADER_IN_BYTES = 12 SIZE_OF_AUD_CHUNK_HEADER_IN_BYTES = 8 class AudHeader: - samplerate = -1 #// Frequency // int16_t // TODO should be unsigned (?) - size_in = -1 #// Size of file (without header) // int32_t // TODO should be unsigned (?) - size_out = -1 #// Size of output data // int32_t // TODO should be unsigned (?) - flags = -1 #// bit 0=stereo, bit 1=16bit // int8_t - compression = -1 #// 1=WW compressed, 99=IMA ADPCM (0x63) // int8_t - + m_samplerate = 0 #// Frequency // int16_t // TODO should be unsigned (?) + m_size_in = 0 #// Size of file (without header) // int32_t // TODO should be unsigned (?) + m_size_out = 0 #// Size of output data // int32_t // TODO should be unsigned (?) + m_flags = 0 #// bit 0=stereo, bit 1=16bit // int8_t + m_compression = 0 #// 1=WW compressed, 99=IMA ADPCM (0x63) // int8_t + m_populated = False + def __init__(self): return @@ -65,9 +85,9 @@ class AudHeader: #//The rest of the AUD files is divided in chunks. These are usually 512 #//bytes long, except for the last one. class AudChunkHeader: - size_in = -1 #// Size of compressed data // int16_t // TODO should be unsigned (?) - size_out = -1 #// Size of output data // int16_t // TODO should be unsigned (?) - id = 0x0000FFFF #// Always 0x0000DEAF // int32_t + m_ch_size_in = 0 #// Size of compressed data // int16_t // TODO should be unsigned (?) + m_ch_size_out = 0 #// Size of output data // int16_t // TODO should be unsigned (?) + m_ch_id = 0x0000FFFF #// Always 0x0000DEAF // int32_t def __init__(self): return @@ -88,12 +108,30 @@ class audFile: # std::fstream& fs, AudFileNS::pos_type startAudFilepos, AudFileNS::pos_type endAudFilepos, const std::string& filename def export_as_wav(self, audBytesBuff, filename): + if (not self.header().m_populated): + print "[Error] file was not loaded properly (header info missing): " + filename + return 1 + print "[Info] Exporting to wav: " + filename + + cvirtualBinaryD = None + if self.header().m_compression > 0: + cvirtualBinaryD = self.decode(self.header().m_compression, audBytesBuff) + elif self.header().m_flags == 2: # compression 0, 16bit stereo + cbinaryDataOutLst = [] + offsInAudFile = SIZE_OF_AUD_HEADER_IN_BYTES + for i in range(0, (len(audBytesBuff) - SIZE_OF_AUD_HEADER_IN_BYTES) / 2): + tmpTupleL = struct.unpack_from('B', audBytesBuff, offsInAudFile) + offsInAudFile += 1 + tmpTupleH = struct.unpack_from('B', audBytesBuff, offsInAudFile) + offsInAudFile += 1 + cbinaryDataOutLst.append(tmpTupleL[0]) + cbinaryDataOutLst.append(tmpTupleH[0]) + cvirtualBinaryD = struct.pack('B'*len(cbinaryDataOutLst), *cbinaryDataOutLst) - cvirtualBinaryD = self.decode(audBytesBuff) -# TODO DEBUG REMOVED FOR NOW. TODO RESTORE THIS!!! -# if (not cvirtualBinaryD): -# return 1 + if (not cvirtualBinaryD): + print "[Error] audio file could not be exported properly (0 data read): " + filename + return 1 cb_sample = self.get_cb_sample() cs_remaining = self.get_c_samples() @@ -130,34 +168,39 @@ class audFile: def loadAudFile(self, audBytesBuff, maxLength, audFileName): self.m_simpleAudioFileName = audFileName offsInAudFile = 0 - tmpTuple = struct.unpack_from('h', audBytesBuff, offsInAudFile) - self.header().samplerate = tmpTuple[0] + tmpTuple = struct.unpack_from('H', audBytesBuff, offsInAudFile) + self.header().m_samplerate = tmpTuple[0] offsInAudFile += 2 - tmpTuple = struct.unpack_from('i', audBytesBuff, offsInAudFile) - self.header().size_in = tmpTuple[0] + tmpTuple = struct.unpack_from('I', audBytesBuff, offsInAudFile) + self.header().m_size_in = tmpTuple[0] offsInAudFile += 4 - tmpTuple = struct.unpack_from('i', audBytesBuff, offsInAudFile) - self.header().size_out = tmpTuple[0] + tmpTuple = struct.unpack_from('I', audBytesBuff, offsInAudFile) + self.header().m_size_out = tmpTuple[0] offsInAudFile += 4 - tmpTuple = struct.unpack_from('b', audBytesBuff, offsInAudFile) - self.header().flags = tmpTuple[0] + tmpTuple = struct.unpack_from('B', audBytesBuff, offsInAudFile) + self.header().m_flags = tmpTuple[0] offsInAudFile += 1 - tmpTuple = struct.unpack_from('b', audBytesBuff, offsInAudFile) - self.header().compression = tmpTuple[0] + tmpTuple = struct.unpack_from('B', audBytesBuff, offsInAudFile) + self.header().m_compression = tmpTuple[0] offsInAudFile += 1 + if self.m_traceModeEnabled: - print "[Debug] Sample rate: %d\tsizeIn: %d\tsizeOut: %d\tflags: %d\tcompression: %d" % (self.get_samplerate(), self.header().size_in, self.header().size_out, self.header().flags, self.header().compression) + print "[Debug] Sample rate: %d\tsizeIn: %d\tsizeOut: %d\tflags: %d\tcompression: %d" % (self.get_samplerate(), self.header().m_size_in, self.header().m_size_out, self.header().m_flags, self.header().m_compression) - if self.get_samplerate() < 8000 or self.get_samplerate() > 48000 or self.header().size_in > (maxLength - SIZE_OF_AUD_HEADER_IN_BYTES ): + if self.get_samplerate() < 8000 or self.get_samplerate() > 48000 or self.header().m_size_in > (maxLength - SIZE_OF_AUD_HEADER_IN_BYTES ): print "[Error] Bad AUD Header size in file %s" % (self.m_simpleAudioFileName) return False else: - if self.header().compression == 1: - if (self.header().flags != 0): + if self.header().m_compression == 1: + if (self.header().m_flags != 0): + return False + elif self.header().m_compression == 0x63: + if (self.header().m_flags != 2): return False - elif self.header().compression == 0x63: - if (self.header().flags != 2): + elif self.header().m_compression == 0: # no compression. At least some AUD files in SFX.MIX have this + if (self.header().m_flags != 2): return False + self.header().m_populated = True return True # int AudFile::get_chunk_header(int i, std::fstream& fs, AudFileNS::pos_type startAudFilepos, AudFileNS::pos_type endAudFilepos, AudChunkHeader& outAudChunkHeader) @@ -177,34 +220,34 @@ class audFile: return (-1, rAudPos, None) tmpAudFileOffset = rAudPos - tmpTuple = struct.unpack_from('h', inAudFileBytesBuffer, tmpAudFileOffset) - tmpInremediateChunkheader.size_in = tmpTuple[0] + tmpTuple = struct.unpack_from('H', inAudFileBytesBuffer, tmpAudFileOffset) + tmpInremediateChunkheader.m_ch_size_in = tmpTuple[0] tmpAudFileOffset += 2 - tmpTuple = struct.unpack_from('h', inAudFileBytesBuffer, tmpAudFileOffset) - tmpInremediateChunkheader.size_out = tmpTuple[0] + tmpTuple = struct.unpack_from('H', inAudFileBytesBuffer, tmpAudFileOffset) + tmpInremediateChunkheader.m_ch_size_out = tmpTuple[0] tmpAudFileOffset += 2 - tmpTuple = struct.unpack_from('i', inAudFileBytesBuffer, tmpAudFileOffset) - tmpInremediateChunkheader.id = tmpTuple[0] + tmpTuple = struct.unpack_from('I', inAudFileBytesBuffer, tmpAudFileOffset) + tmpInremediateChunkheader.m_ch_id = tmpTuple[0] tmpAudFileOffset += 4 #fs.read((char*)&tmpInremediateChunkheader, SIZE_OF_AUD_CHUNK_HEADER_IN_BYTES); - rAudPos += SIZE_OF_AUD_CHUNK_HEADER_IN_BYTES + tmpInremediateChunkheader.size_in + rAudPos += SIZE_OF_AUD_CHUNK_HEADER_IN_BYTES + tmpInremediateChunkheader.m_ch_size_in #fs.seekg(int(rAudPos), fs.beg); if (rAudPos + SIZE_OF_AUD_CHUNK_HEADER_IN_BYTES > inAudFileSize ): return (-1, rAudPos, None) # write to FINAL output chunk header tmpAudFileOffset = rAudPos - tmpTuple = struct.unpack_from('h', inAudFileBytesBuffer, tmpAudFileOffset) - outAudChunkHeader.size_in = tmpTuple[0] + tmpTuple = struct.unpack_from('H', inAudFileBytesBuffer, tmpAudFileOffset) + outAudChunkHeader.m_ch_size_in = tmpTuple[0] tmpAudFileOffset += 2 - tmpTuple = struct.unpack_from('h', inAudFileBytesBuffer, tmpAudFileOffset) - outAudChunkHeader.size_out = tmpTuple[0] + tmpTuple = struct.unpack_from('H', inAudFileBytesBuffer, tmpAudFileOffset) + outAudChunkHeader.m_ch_size_out = tmpTuple[0] tmpAudFileOffset += 2 - tmpTuple = struct.unpack_from('i', inAudFileBytesBuffer, tmpAudFileOffset) - outAudChunkHeader.id = tmpTuple[0] + tmpTuple = struct.unpack_from('I', inAudFileBytesBuffer, tmpAudFileOffset) + outAudChunkHeader.m_ch_id = tmpTuple[0] tmpAudFileOffset += 4 #fs.read((char*)&outAudChunkHeader, SIZE_OF_AUD_CHUNK_HEADER_IN_BYTES); - if (rAudPos + SIZE_OF_AUD_CHUNK_HEADER_IN_BYTES + outAudChunkHeader.size_in > inAudFileSize): + if (rAudPos + SIZE_OF_AUD_CHUNK_HEADER_IN_BYTES + outAudChunkHeader.m_ch_size_in > inAudFileSize): return (-1, rAudPos, None) rAudPos += SIZE_OF_AUD_CHUNK_HEADER_IN_BYTES return (0, rAudPos, outAudChunkHeader) # //reinterpret_cast<const AudChunkHeader*>(r); @@ -217,7 +260,7 @@ class audFile: for i in range(startOffs, startOffs + sizeToRead): #outChunkDataLst.append(ctypes.c_char(inAudFileBytesBuffer[i]).value) #outChunkDataLst.append(ctypes.c_byte(inAudFileBytesBuffer[i]).value) - tmpTuple = struct.unpack_from('b', inAudFileBytesBuffer, i) + tmpTuple = struct.unpack_from('B', inAudFileBytesBuffer, i) outChunkDataLst.append(tmpTuple[0]) #byteChunkDataOut = struct.pack('b'*len(outChunkDataLst), *outChunkDataLst) #return (0, byteChunkDataOut) @@ -226,7 +269,7 @@ class audFile: # std::fstream& fs, AudFileNS::pos_type startAudFilepos, AudFileNS::pos_type endAudFilepos # returned Cvirtual_binary - def decode(self, audBytesBuff): + def decode(self, speccompression, audBytesBuff): # The * operator unpacks an argument list. It allows you to call a function with the list items as individual arguments. # binDataOut = struct.pack('i'*len(data), *data) if self.m_traceModeEnabled: @@ -235,7 +278,7 @@ class audFile: binaryDataOutLst = [] binaryDataOutBuff = None cb_audio = self.get_cb_sample() * self.get_c_samples() # int cb_audio - basically this should be the size_out - if self.header().compression == 1: + if speccompression == 1: # write_start allocates space for virtualBinary # AudFileNS::byte* w = d.write_start(cb_audio); errGetChunk = 0 # int errGetChunk @@ -249,17 +292,17 @@ class audFile: if errGetChunk != 0: # print "[Warning] Error OR End file case while getting uncompressed chunk header!" break - #print "[Debug] Get uncompressed chunk header returned: %d " % (out_chunk_header.id) + #print "[Debug] Get uncompressed chunk header returned: %d " % (out_chunk_header.m_ch_id) #Cvirtual_binary out_chunk_data; - #AudFileNS::byte* byteChunkDataPtr = out_chunk_data.write_start(out_chunk_header.size_in); - (errorGCD, byteChunkDataLst) = self.get_chunk_data(audBytesBuff, bufferDataPos, out_chunk_header.size_in) + #AudFileNS::byte* byteChunkDataPtr = out_chunk_data.write_start(out_chunk_header.m_ch_size_in); + (errorGCD, byteChunkDataLst) = self.get_chunk_data(audBytesBuff, bufferDataPos, out_chunk_header.m_ch_size_in) # export decoded chunk to w (output) buffer (of CHARS) at the point where we're currently at (so append there) - decodedAudioChunkAsLst = aud_decode_ws_chunk(byteChunkDataLst, out_chunk_header.size_in, out_chunk_header.size_out) + decodedAudioChunkAsLst = aud_decode_ws_chunk(byteChunkDataLst, out_chunk_header.m_ch_size_in, out_chunk_header.m_ch_size_out) binaryDataOutLst.extend(decodedAudioChunkAsLst) - wIndex += out_chunk_header.size_out + wIndex += out_chunk_header.m_ch_size_out chunk_i += 1 binaryDataOutBuff = struct.pack('b'*len(binaryDataOutLst), *binaryDataOutLst) - elif self.header().compression == 0x63: + elif speccompression == 0x63: decodeInstance = audFileDecode(self.m_traceModeEnabled); #decodeInstance.init(); #AudFileNS::byte* w = d.write_start(cb_audio); @@ -276,15 +319,15 @@ class audFile: if errGetChunk != 0: print "[Warning] Error OR End file case while getting COMPRESSED chunk header!" break - #print "[Debug] Get COMPRESSED chunk header returned:: headerInSize: %d headerOutSize: %d id: %d" % (out_chunk_header.size_in, out_chunk_header.size_out, out_chunk_header.id) + #print "[Debug] Get COMPRESSED chunk header returned:: headerInSize: %d headerOutSize: %d id: %d" % (out_chunk_header.m_ch_size_in, out_chunk_header.m_ch_size_out, out_chunk_header.m_ch_id) #Cvirtual_binary out_chunk_data; - #AudFileNS::byte* byteChunkDataPtr = out_chunk_data.write_start(out_chunk_header.size_in); - (errorGCD, byteChunkDataLst) = self.get_chunk_data(audBytesBuff, bufferDataPos, out_chunk_header.size_in) + #AudFileNS::byte* byteChunkDataPtr = out_chunk_data.write_start(out_chunk_header.m_ch_size_in); + (errorGCD, byteChunkDataLst) = self.get_chunk_data(audBytesBuff, bufferDataPos, out_chunk_header.m_ch_size_in) # export decoded chunk to w (output) buffer (of SHORTS) at the point where we're currently at (so append there) - #print "[Debug] byteChunkDataLst len: %d, size_in was: %d" % (len(byteChunkDataLst), out_chunk_header.size_in) - decodedAudioChunkAsLst = decodeInstance.decode_chunk(byteChunkDataLst, out_chunk_header.size_out / self.get_cb_sample()); + #print "[Debug] byteChunkDataLst len: %d, m_ch_size_in was: %d" % (len(byteChunkDataLst), out_chunk_header.m_ch_size_in) + decodedAudioChunkAsLst = decodeInstance.decode_chunk(byteChunkDataLst, out_chunk_header.m_ch_size_out / self.get_cb_sample()); binaryDataOutLst.extend(decodedAudioChunkAsLst) - wIndex += out_chunk_header.size_out + wIndex += out_chunk_header.m_ch_size_out #print("[Debug] New Windex: %d\t cb_audio: %d") % (wIndex,cb_audio) chunk_i += 1 binaryDataOutBuff = struct.pack('h'*len(binaryDataOutLst), *binaryDataOutLst) @@ -300,18 +343,18 @@ class audFile: return self.m_header def get_c_samples(self): - return self.m_header.size_out / self.get_cb_sample() + return self.m_header.m_size_out / self.get_cb_sample() def get_samplerate(self): - return self.m_header.samplerate; + return self.m_header.m_samplerate; # flag bit 0 is stereo(set) mono(clear) def get_c_channels(self): - return 2 if (self.m_header.flags & 0x01) else 1; + return 2 if (self.m_header.m_flags & 0x01) else 1; # flag bit 1 is 16bit(set) 8bit (clear) def get_cb_sample(self): - return 2 if (self.m_header.flags & 0x02) else 1 + return 2 if (self.m_header.m_flags & 0x02) else 1 # # # @@ -321,6 +364,12 @@ if __name__ == '__main__': # assumes a file of name 000000.AUD in same directory inAUDFile = None inAUDFileName = '00000000.AUD' + if len(sys.argv[1:]) > 0 \ + and os.path.isfile(os.path.join('.', sys.argv[1])) \ + and len (sys.argv[1]) > 5 \ + and sys.argv[1][-3:] == 'AUD': + inAUDFileName = sys.argv[1] + print "[Debug] Using %s as input AUD file..." % (inAUDFileName) errorFound = False try: diff --git a/devtools/create_bladerunner/subtitles/quotesSpreadsheetCreator/devCommentaryText.py b/devtools/create_bladerunner/subtitles/quotesSpreadsheetCreator/devCommentaryText.py index a8806cafaa..9ec4e10cdf 100644 --- a/devtools/create_bladerunner/subtitles/quotesSpreadsheetCreator/devCommentaryText.py +++ b/devtools/create_bladerunner/subtitles/quotesSpreadsheetCreator/devCommentaryText.py @@ -6,27 +6,46 @@ my_module_version = "1.00" my_module_name = "devCommentaryText" # All game versions should have the English text pre-filled in the POGO sheet -DEV_AUDIO_COMMENTART_TUPLE_LIST = [ - ("MA04VO1A.AUD", "Yes, this is McCoy's apartment. Probably one of the more pivotal areas in the game. You'll notice that if you walk McCoy into the bathroom on the right hand side over there a really weird thing happens. One of the things the player might not pick up on but is rather important is McCoy doesn't wash his hands every time he uses the bathroom. This can possibly lead the player to believe that: a) Ray McCoy is a Replicant who doesn't care about germs and, you know, doesn't use to wash his hands or b) McCoy is just kind of a slob."), - ("CT01VO1A.AUD", "Oh, yeah, this is the Chinatown scene with Howie's restaurant. You'll notice that Howie is moving his arms in the air. The thing we were trying to pull off here was that he was making the sushi but we had a lot of problems with the sushi going bad under the lights and it just wasn't a good scene, so what you're seeing in the final version here is we had to get rid of the lot of the fish and sushi and we're a little disappointed in this area."), - ("HC01VO1A.AUD", "This is an area known as Hawker's Circle. It's sort of a swamp pit, so to speak where a lot of the scum of the earth hang out. Notice again the constant Asian reminder here showing you that Asians are often living in poor rather dingy areas of the city.") +DEV_AUDIO_COMMENTARY_TUPLE_LIST = [ + ("MA04VO1A.AUD", "*McCoy's apartment*"), + ("CT01VO1A.AUD", "*Chinatown*"), + ("HC01VO1A.AUD", "*Hawker's Circle*") +] + +EXTRA_SPEECH_AUDIO_TUPLE_LIST = [ + ('COLONY.AUD', "*Blimp Guy talk*"), + ('67_0470R.AUD', "*Crowd talk*"), + ('67_0480R.AUD', "*Crowd talk*"), + ('67_0500R.AUD', "*Crowd talk*"), + ('67_0540R.AUD', "*Crowd talk*"), + ('67_0560R.AUD', "*Crowd talk*"), + ('67_0870R.AUD', "*Crowd talk*"), + ('67_0880R.AUD', "*Crowd talk*"), + ('67_0900R.AUD', "*Crowd talk*"), + ('67_0940R.AUD', "*Crowd talk*"), + ('67_0960R.AUD', "*Crowd talk*"), + ('67_1070R.AUD', "*Crowd talk*"), + ('67_1080R.AUD', "*Crowd talk*"), + ('67_1100R.AUD', "*Crowd talk*"), + ('67_1140R.AUD', "*Crowd talk*"), + ('67_1160R.AUD', "*Crowd talk*") ] # we use the spoken quote id that triggers the comment as an ID for the DEV commentary quote # Ids 00-9990 and above correspond to clicks or other transitions (no corresponding spoken in-game quote) DEV_ISEZ_QUOTES_TUPLE_LIST = [ - ("00-9990", "Blade Runner\nFrom the dark recesses of David Leary's imagination comes a game unlike any\nother. Blade Runner immerses you in the underbelly of future Los Angeles. Right\nfrom the start, the story pulls you in with graphic descriptions of a\ngrandmother doing the shimmy in her underwear, child molestation, brutal\ncold-blooded slaying of innocent animals, vomiting on desks, staring at a\nwoman's ass, the list goes on. And when the game starts, the real fun begins -\nshoot down-on-their-luck homeless people and toss them into a dumpster. Watch\nwith sadistic glee as a dog gets blown into chunky, bloody, bits by an\nexplosive, and even murder a shy little girl who loves you. If you think David\nLeary is sick, and you like sick, this is THE game for you.\n\nJW: Don't forget the wasting of helpless mutated cripples in the underground.\nIt's such a beautiful thing!\n\nDL: Go ahead. Just keep beating that snarling pit bull...ignore the foam\naround his jaws. There's room on the top shelf of my fridge for at least one\nmore head... - Psychotic Dave\n"), - ("99-1860", "MG: Is David Leary a self-respecting human or is he powered by rechargeable\nBatteries?"), # voice-over - ("99-1890", "JM: That McCoy--he's one funny guy! Jet-black fire truck, hehehehe..."), # voice-over - ("23-0130", "JM: Did it have a huge, ugly piece of chrome on it?"), # Officer Leary - ("23-0090", "JM: This officer has a talent for vivid metaphors."), # Officer Leary - ("00-4540", "DL: What is that supposed to mean? I didn't write this line..."), - ("00-4515", "MG: Hey, leave that officer alone. Can't you see he's busy?\nJM: (...mmm, donuts...)"), # clicking on Leary after we get his statement - ("23-0060", "MG: It's all fun and games until someone loses a tiger cub."), # Officer Leary - ("00-9991", "JM: Chrome...is that what that is?"), # pick up chrome - ("00-4510", "JM: It's hard to imagine that thing on either a car or a horse.\nMG: McCoy! What a witty chap...\nJM: He keeps me chuckling non-stop!"), - ("00-9992", "MG: Leaving already? The fun is just beginning!"), # leaving Runciter's zoo with Spinner - ("00-4500", "MG: We don't want any of that abstract art oozing out onto the street.") + ("IS-00-9990.AUD", "Blade Runner\nFrom the dark recesses of David Leary's imagination comes a game unlike any\nother. Blade Runner immerses you in the underbelly of future Los Angeles. Right\nfrom the start, the story pulls you in with graphic descriptions of a\ngrandmother doing the shimmy in her underwear, child molestation, brutal\ncold-blooded slaying of innocent animals, vomiting on desks, staring at a\nwoman's ass, the list goes on. And when the game starts, the real fun begins -\nshoot down-on-their-luck homeless people and toss them into a dumpster. Watch\nwith sadistic glee as a dog gets blown into chunky, bloody, bits by an\nexplosive, and even murder a shy little girl who loves you. If you think David\nLeary is sick, and you like sick, this is THE game for you.\n\nJW: Don't forget the wasting of helpless mutated cripples in the underground.\nIt's such a beautiful thing!\n\nDL: Go ahead. Just keep beating that snarling pit bull...ignore the foam\naround his jaws. There's room on the top shelf of my fridge for at least one\nmore head... - Psychotic Dave\n"), + ("IS-99-1860.AUD", "MG: Is David Leary a self-respecting human or is he powered by rechargeable\nBatteries?"), # voice-over + ("IS-99-1890.AUD", "JM: That McCoy--he's one funny guy! Jet-black fire truck, hehehehe..."), # voice-over + ("IS-23-0130.AUD", "JM: Did it have a huge, ugly piece of chrome on it?"), # Officer Leary + ("IS-23-0090.AUD", "JM: This officer has a talent for vivid metaphors."), # Officer Leary + ("IS-00-4540.AUD", "DL: What is that supposed to mean? I didn't write this line..."), + ("IS-00-4515.AUD", "MG: Hey, leave that officer alone. Can't you see he's busy?\nJM: (...mmm, donuts...)"), # clicking on Leary after we get his statement + ("IS-23-0060.AUD", "MG: It's all fun and games until someone loses a tiger cub."), # Officer Leary + ("IS-00-9991.AUD", "JM: Chrome...is that what that is?"), # pick up chrome + ("IS-00-4510.AUD", "JM: It's hard to imagine that thing on either a car or a horse.\nMG: McCoy! What a witty chap...\nJM: He keeps me chuckling non-stop!"), + ("IS-00-9992.AUD", "MG: Leaving already? The fun is just beginning!"), # leaving Runciter's zoo with Spinner + ("IS-00-4500.AUD", "MG: We don't want any of that abstract art oozing out onto the street.") ] # # @@ -39,20 +58,29 @@ class devCommentaryText: return def printTexts(self): - print "AUDIO COMMENTARY" - for (idTre, textTre) in DEV_AUDIO_COMMENTART_TUPLE_LIST: + print "\nAUDIO COMMENTARY" + print "------------------" + for (idTre, textTre) in DEV_AUDIO_COMMENTARY_TUPLE_LIST: print "%s\t%s" % (idTre, textTre) - print "I_SEZ QUOTES" + print "\nEXTRA SPEECH AUDIO" + print "------------------" + for (idTre, textTre) in EXTRA_SPEECH_AUDIO_TUPLE_LIST: + print "%s\t%s" % (idTre, textTre) + print "\nI_SEZ QUOTES" + print "------------------" for (idTre, textTre) in DEV_ISEZ_QUOTES_TUPLE_LIST: print "%s\t%s" % (idTre, textTre) return def getAudioCommentaryTextEntriesList(self): - return DEV_AUDIO_COMMENTART_TUPLE_LIST + return DEV_AUDIO_COMMENTARY_TUPLE_LIST def getISEZTextEntriesList(self): return DEV_ISEZ_QUOTES_TUPLE_LIST + def getExtraSpeechAudioEntriesList(self): + return EXTRA_SPEECH_AUDIO_TUPLE_LIST + if __name__ == '__main__': # main() print "[Debug] Running %s as main module" % (my_module_name) diff --git a/devtools/create_bladerunner/subtitles/quotesSpreadsheetCreator/quoteSpreadsheetCreator.py b/devtools/create_bladerunner/subtitles/quotesSpreadsheetCreator/quoteSpreadsheetCreator.py index 83c6db7e5a..e65f9daf84 100644 --- a/devtools/create_bladerunner/subtitles/quotesSpreadsheetCreator/quoteSpreadsheetCreator.py +++ b/devtools/create_bladerunner/subtitles/quotesSpreadsheetCreator/quoteSpreadsheetCreator.py @@ -1,6 +1,17 @@ #!/usr/bin/env python # -*- coding: UTF-8 -*- -import sys +sysLibFound = False +try: + import sys +except ImportError: + print "[Error] sys python library is required to be installed!" +else: + sysLibFound = True + +if (not sysLibFound): + sys.stdout.write("[Error] Errors were found when trying to import required python libraries\n") + sys.exit(1) + if not (sys.version_info[0] == 2 and sys.version_info[1] == 7): sys.stdout.write("[Error] Blade Runner Quotes Spreadsheet Creator script requires Python 2.7\n") sys.exit(1) diff --git a/devtools/create_bladerunner/subtitles/quotesSpreadsheetCreator/sortBladeRunnerWavs02.py b/devtools/create_bladerunner/subtitles/quotesSpreadsheetCreator/sortBladeRunnerWavs02.py index 4ded0c868b..ce9f9437a5 100644 --- a/devtools/create_bladerunner/subtitles/quotesSpreadsheetCreator/sortBladeRunnerWavs02.py +++ b/devtools/create_bladerunner/subtitles/quotesSpreadsheetCreator/sortBladeRunnerWavs02.py @@ -7,13 +7,27 @@ # DONE Add code and switch option: to get the blade runner installation directory as input, then find the TLK files and export them with proper naming # DONE fix proper names for sheets as per latest code changes # -import os, sys - +osLibFound = False +sysLibFound = False shutilLibFound = False xlwtLibFound = False csvLibFound = False try: + import os +except ImportError: + print "[Error] os python library is required to be installed!" +else: + osLibFound = True + +try: + import sys +except ImportError: + print "[Error] sys python library is required to be installed!" +else: + sysLibFound = True + +try: import shutil except ImportError: print "[Error] Shutil python library is required to be installed!" @@ -34,7 +48,11 @@ except ImportError: else: csvLibFound = True -if (not shutilLibFound) or (not xlwtLibFound) or (not csvLibFound): +if (not osLibFound) \ + or (not sysLibFound) \ + or (not shutilLibFound) \ + or (not xlwtLibFound) \ + or (not csvLibFound): sys.stdout.write("[Error] Errors were found when trying to import required python libraries\n") sys.exit(1) @@ -61,7 +79,29 @@ OUTPUT_XLS_FILENAME_EXT = '.xls' OUTPUT_XLS_QUOTES_SHEET = 'INGQUO_' # needs suffix x.TRx where x is the language code SUPPORTED_TLK_INPUT_FILES = [('1.TLK', 'TLK01'), ('2.TLK', 'TLK02'), ('3.TLK', 'TLK03'), ('A.TLK', 'TLK0A'), ('SPCHSFX.TLK', 'TLKSPCHSFX')] -SUPPORTED_MIX_INPUT_FILES = ['STARTUP.MIX'] +SUPPORTED_MIX_INPUT_FOR_EXTRA_SPEECH_EXPORT_FILES = [('SFX.MIX', 'SFX')] +SUPPORTED_EXPORTED_AUD_FROM_MIX_FILES = [('COLONY.AUD', 'SFX.MIX'), \ + ('MA04VO1A.AUD', 'SFX.MIX'), \ + ('CT01VO1A.AUD', 'SFX.MIX'), \ + ('HC01VO1A.AUD', 'SFX.MIX'), \ + ('67_0470R.AUD', 'SFX.MIX'), \ + ('67_0480R.AUD', 'SFX.MIX'), \ + ('67_0500R.AUD', 'SFX.MIX'), \ + ('67_0540R.AUD', 'SFX.MIX'), \ + ('67_0560R.AUD', 'SFX.MIX'), \ + ('67_0870R.AUD', 'SFX.MIX'), \ + ('67_0880R.AUD', 'SFX.MIX'), \ + ('67_0900R.AUD', 'SFX.MIX'),\ + ('67_0940R.AUD', 'SFX.MIX'), \ + ('67_0960R.AUD', 'SFX.MIX'), \ + ('67_1070R.AUD', 'SFX.MIX'), \ + ('67_1080R.AUD', 'SFX.MIX'), \ + ('67_1100R.AUD', 'SFX.MIX'), \ + ('67_1140R.AUD', 'SFX.MIX'), \ + ('67_1160R.AUD', 'SFX.MIX') \ + ] + +SUPPORTED_MIX_INPUT_FOR_TRX_EXPORT_FILES = ['STARTUP.MIX'] # 15 TRx files SUPPORTED_EXPORTED_TRx_FILES = ['CLUES.TR','ACTORS.TR','CRIMES.TR','CLUETYPE.TR','KIA.TR','SPINDEST.TR','VK.TR','OPTIONS.TR','DLGMENU.TR','ENDCRED.TR','HELP.TR','SCORERS.TR','KIACRED.TR','ERRORMSG.TR','AUTOSAVE.TR'] SUPPORTED_PLACEHOLDER_VQA_ENGLISH_FILES = [ @@ -103,8 +143,11 @@ gActiveLanguageDescriptionCodeTuple = '' gStringReplacementForRootFolderWithExportedFiles = "" gNumReplaceStartingCharacters = 0 -gWavFiles = [] -gWavFilesNoDups = [] +gMIXWavFiles = [] +gMIXWavFilesNoDups = [] +gTLKWavFiles = [] +gTLKWavFilesNoDups = [] + gActorPropertyEntries = [] #[0]:id, [1]:ShortHand Name [2]:Full Name gActorPropertyEntriesWasInit = False @@ -137,7 +180,7 @@ def initActorPropertyEntries(thePathToActorNamesTxt): global gActorPropertyEntries firstLine = True gActorPropertyEntriesWasInit = False -# print "[Debug] opening actornames" + #print "[Debug] opening actornames" if thePathToActorNamesTxt is None or not thePathToActorNamesTxt: actorNamesTextFile = u'actornames.txt' @@ -220,9 +263,9 @@ def ensure_dir(directory): # # Reading in the INPUT TLK files and checking all the AUD file properties -# -def inputTLKsExport(inputTLKpath, outputWAVpath): - # try to open all TLK file entries from SUPPORTED_TLK_INPUT_FILES + +def inputTLKsExport(inputTLKpath, outputWAVpath, pExportWavFilesMode, pExtractDevCommAndExtraSFXMode): + # try to open all TLK, MIX file entries from SUPPORTED_TLK_INPUT_FILES + SUPPORTED_MIX_INPUT_FOR_EXTRA_SPEECH_EXPORT_FILES # then per TLK file # create an output folder in the OUTPUT PATH named TLK## for the 1, 2, 3 TLK and TLKSPCHSFX for the SPCHSFX.TLK # printout: @@ -232,54 +275,72 @@ def inputTLKsExport(inputTLKpath, outputWAVpath): # fileID # segment offset # file size - print "[Info] Checking in %s for TLK files to export to %s" % (inputTLKpath, outputWAVpath) - inputTLKFilesFound = [] - # breaking after first for loop yields only the top directory files, which is what we want + if not pExportWavFilesMode and not pExtractDevCommAndExtraSFXMode: + return # nothing to do + print "[Info] Checking in:\n\t%s\n\tfor TLK or MIX files containing supported speech audio (AUD) to export as WAV to:\n\t%s" % (inputTLKpath, outputWAVpath) + inputTLKFilesForSpeechFound = [] + inputMIXFilesForSpeechFound = [] # breaking after first for loop yields only the top directory files, which is what we want for (dirpath, dirnames, filenames) in walk(inputTLKpath): for filename in filenames: - for tlkTuple in SUPPORTED_TLK_INPUT_FILES: - if filename.upper() == tlkTuple[0]: - inputTLKFilesFound.append(tlkTuple) + if pExportWavFilesMode: + for tlkTuple in (SUPPORTED_TLK_INPUT_FILES): + if filename.upper() == tlkTuple[0]: + inputTLKFilesForSpeechFound.append(tlkTuple) + if pExtractDevCommAndExtraSFXMode: + for tlkTuple in SUPPORTED_MIX_INPUT_FOR_EXTRA_SPEECH_EXPORT_FILES: + if filename.upper() == tlkTuple[0]: + inputMIXFilesForSpeechFound.append(tlkTuple) break - if len(inputTLKFilesFound) == 0: - print "[Error] No valid speech audio files (TLK) were found in the specified input path (-ip switch)" - sys.exit(1) - - for tmpTLKfileTuple in inputTLKFilesFound: + if pExportWavFilesMode: + if len(inputTLKFilesForSpeechFound) == 0: + print "[Error] No valid speech audio files (TLK) were found in the specified input path (-ip switch)" + sys.exit(1) + if pExtractDevCommAndExtraSFXMode: + if len(inputMIXFilesForSpeechFound) == 0: + print "[Error] No valid extras speech audio files (MIX) were found in the specified input path (-ip switch)" + sys.exit(1) + + # get the supported AUD files from TLK or MIX archives + for tmpTLKorMIXFileTuple in (inputTLKFilesForSpeechFound + inputMIXFilesForSpeechFound): if gTraceModeEnabled: - print "[Info] Found TLK: %s" % ('"' + inputTLKpath + tmpTLKfileTuple[0] + '"') + print "[Info] Found supported audio file: %s" % ('"' + inputTLKpath + tmpTLKorMIXFileTuple[0] + '"') errorFound = False - inTLKFile = None + inTLKorMIXFile = None + fileIsMIX = False + #print "[Trace] Type of file is: %s" % (tmpTLKorMIXFileTuple[0][-3:]) + if tmpTLKorMIXFileTuple[0][-3:].upper() == 'MIX': + fileIsMIX = True + print "[Info] Checking MIX file %s for speech audio (-xdevs mode)... " % (tmpTLKorMIXFileTuple[0]) # # Create output folder if not exists at output path if gTraceModeEnabled: - print "Ensuring output directory %s" % (os.path.join(outputWAVpath, tmpTLKfileTuple[1] )) - ensure_dir(os.path.join(outputWAVpath, tmpTLKfileTuple[1] ) ) + print "[Debug] Ensuring output directory %s" % (os.path.join(outputWAVpath, tmpTLKorMIXFileTuple[1] )) + ensure_dir(os.path.join(outputWAVpath, tmpTLKorMIXFileTuple[1] ) ) try: - inTLKFile = open(os.path.join(inputTLKpath,tmpTLKfileTuple[0]), 'rb') + inTLKorMIXFile = open(os.path.join(inputTLKpath,tmpTLKorMIXFileTuple[0]), 'rb') except: errorFound = True print "[Error] Unexpected event:", sys.exc_info()[0] raise if not errorFound: - tmpBuff = inTLKFile.read(2) + tmpBuff = inTLKorMIXFile.read(2) # H: unsigned short (2 bytes) followed by I: unsigned int (4 bytes) tlkFileEntriesNumTuple = struct.unpack('H', tmpBuff) - numOfTREEntriesToExtract = tlkFileEntriesNumTuple[0] - tmpBuff = inTLKFile.read(4) + numOfAUDEntriesToExtract = tlkFileEntriesNumTuple[0] + tmpBuff = inTLKorMIXFile.read(4) tlkFileDataSegmentSizeTuple = struct.unpack('I', tmpBuff) allTlkFileSize = tlkFileDataSegmentSizeTuple[0] - inTLKFile.seek(0, 2) # go to file end - allActualBytesInMixFile = inTLKFile.tell() - inTLKFile.seek(6, 0) # go to start of table of TLK file entries (right after the 6 bytes header) + inTLKorMIXFile.seek(0, 2) # go to file end + allActualBytesInMixFile = inTLKorMIXFile.tell() + inTLKorMIXFile.seek(6, 0) # go to start of table of TLK file entries (right after the 6 bytes header) # 2 + 4 = 6 bytes short MIX header # 12 bytes per TLK entry in entries table # quick size validation if gTraceModeEnabled: - print "[Debug] Entries: %d, Data segment size: %d bytes" % (numOfTREEntriesToExtract, allTlkFileSize) - if allActualBytesInMixFile != 2 + 4 + 12 * numOfTREEntriesToExtract + allTlkFileSize: - print "[Error] TLK file size mismatch with reported size in header for %s!" % (tmpTLKfileTuple[0]) + print "[Debug] Entries: %d, Data segment size: %d bytes" % (numOfAUDEntriesToExtract, allTlkFileSize) + if allActualBytesInMixFile != 2 + 4 + 12 * numOfAUDEntriesToExtract + allTlkFileSize: + print "[Error] Audio Archive file size mismatch with reported size in header for %s!" % (tmpTLKorMIXFileTuple[0]) else: # # 12 bytes per entry @@ -287,19 +348,35 @@ def inputTLKsExport(inputTLKpath, outputWAVpath): # 4 bytes: Offset in data segment # 4 bytes: Size of data # - for i in range(0, numOfTREEntriesToExtract): - inTLKFile.seek(2 + 4 + 12*i) - tmpBuff = inTLKFile.read(4) + for i in range(0, numOfAUDEntriesToExtract): + inTLKorMIXFile.seek(2 + 4 + 12*i) + tmpBuff = inTLKorMIXFile.read(4) tmpRdTuple = struct.unpack('I', tmpBuff) idOfAUDEntry = tmpRdTuple[0] - tmpBuff = inTLKFile.read(4) + tmpBuff = inTLKorMIXFile.read(4) tmpRdTuple = struct.unpack('I', tmpBuff) offsetOfAUDEntry = tmpRdTuple[0] - tmpBuff = inTLKFile.read(4) + tmpBuff = inTLKorMIXFile.read(4) tmpRdTuple = struct.unpack('I', tmpBuff) sizeOfAUDEntry = tmpRdTuple[0] - if gTraceModeEnabled: - print "[Debug] Entry: %s, offset: %s, Data segment size: %s bytes" % (''.join('{:08X}'.format(idOfAUDEntry)), ''.join('{:08X}'.format(offsetOfAUDEntry)),''.join('{:08X}'.format(sizeOfAUDEntry))) + + targetSimpleAudFileName = ''.join('{:08X}'.format(idOfAUDEntry)).upper()+'.AUD' + foundSupportedAUDFromMIXFile = False + if fileIsMIX: # MIX file like SFX.MIX which has some spoken dialogue + #print 'idOfEntry: %d' % (idOfAUDEntry) + for suppAUDFromMIXFileName in zip(*SUPPORTED_EXPORTED_AUD_FROM_MIX_FILES)[0]: + #print 'checked with: %d' % (calculateFoldHash(suppAUDFromMIXFileName)) + if(idOfAUDEntry == calculateFoldHash(suppAUDFromMIXFileName)): + foundSupportedAUDFromMIXFile = True + targetSimpleAudFileName = suppAUDFromMIXFileName + break + if foundSupportedAUDFromMIXFile: + if gTraceModeEnabled: + print "[Debug] Entry: %s, offset: %s, Data segment size: %s bytes" % (''.join('{:08X}'.format(idOfAUDEntry)), ''.join('{:08X}'.format(offsetOfAUDEntry)),''.join('{:08X}'.format(sizeOfAUDEntry))) + #print "[Debug] Filename: " + targetSimpleAudFileName + else: # TLK file + if gTraceModeEnabled: + print "[Debug] Entry: %s, offset: %s, Data segment size: %s bytes" % (''.join('{:08X}'.format(idOfAUDEntry)), ''.join('{:08X}'.format(offsetOfAUDEntry)),''.join('{:08X}'.format(sizeOfAUDEntry))) # # put file in AUD object # do we need AUD decode? @@ -312,34 +389,37 @@ def inputTLKsExport(inputTLKpath, outputWAVpath): # aud.export_as_wav(fs, offset, offset + int(sizeof(AudHeader)) + aud.header().size_in, target); # # - inTLKFile.seek(2 + 4 + 12*numOfTREEntriesToExtract + offsetOfAUDEntry) - if(offsetOfAUDEntry + sizeOfAUDEntry > allTlkFileSize): - print "[Error] audio file (AUD) file size mismatch with reported size in entry header!" - else: - targetSimpleAudFileName = ''.join('{:08X}'.format(idOfAUDEntry)).upper()+'.AUD' - audFileBuffer = inTLKFile.read(sizeOfAUDEntry) - if (len(audFileBuffer) == sizeOfAUDEntry): - # load audio file (AUD) file - thisAudFile = audFile(gTraceModeEnabled) - if (thisAudFile.loadAudFile(audFileBuffer, allTlkFileSize, targetSimpleAudFileName)): - if gTraceModeEnabled: - print "[Debug] Audio file (AUD) file %s was loaded successfully!" % (targetSimpleAudFileName) - # find - # print "[Debug] Emulating Wav write to appropriate folder..." - (actorID, actorSName, localQuoteId) = getActorShortNameAndLocalQuoteIdByAUDHashID(idOfAUDEntry) - targetSimpleWavFileName = actorSName + '_' + str(localQuoteId).zfill(4) + '_' + ''.join('{:08X}'.format(idOfAUDEntry)).upper()+'.WAV' - #print os.path.join(outputWAVpath, tmpTLKfileTuple[1], targetSimpleWavFileName) - if not os.path.isfile(os.path.join(outputWAVpath, tmpTLKfileTuple[1], targetSimpleWavFileName) ): - thisAudFile.export_as_wav(audFileBuffer, os.path.join(outputWAVpath, tmpTLKfileTuple[1], targetSimpleWavFileName) ) - else: + if foundSupportedAUDFromMIXFile or not fileIsMIX: + inTLKorMIXFile.seek(2 + 4 + 12*numOfAUDEntriesToExtract + offsetOfAUDEntry) + if(offsetOfAUDEntry + sizeOfAUDEntry > allTlkFileSize): + print "[Error] audio file (AUD) file size mismatch with reported size in entry header!" + else: + audFileBuffer = inTLKorMIXFile.read(sizeOfAUDEntry) + if (len(audFileBuffer) == sizeOfAUDEntry): + # load audio file (AUD) file + thisAudFile = audFile(gTraceModeEnabled) + if (thisAudFile.loadAudFile(audFileBuffer, allTlkFileSize, targetSimpleAudFileName)): if gTraceModeEnabled: - print "[Info] Output file %s already exists. Skipping..." % (os.path.join(outputWAVpath, tmpTLKfileTuple[1], targetSimpleWavFileName)) + print "[Debug] Audio file (AUD) file %s was loaded successfully!" % (targetSimpleAudFileName) + # find + # print "[Debug] Emulating Wav write to appropriate folder..." + targetSimpleWavFileName = targetSimpleAudFileName[:-4] + '.WAV' # remove the .AUD before adding the .WAV + if not fileIsMIX: # TLK file + (actorID, actorSName, localQuoteId) = getActorShortNameAndLocalQuoteIdByAUDHashID(idOfAUDEntry) + targetSimpleWavFileName = actorSName + '_' + str(localQuoteId).zfill(4) + '_' + ''.join('{:08X}'.format(idOfAUDEntry)).upper()+'.WAV' + #print os.path.join(outputWAVpath, tmpTLKorMIXFileTuple[1], targetSimpleWavFileName) + # tmpTLKorMIXFileTuple[1] is the subfolder where the AUD -> WAV files for this archive are written + if not os.path.isfile(os.path.join(outputWAVpath, tmpTLKorMIXFileTuple[1], targetSimpleWavFileName) ): + thisAudFile.export_as_wav(audFileBuffer, os.path.join(outputWAVpath, tmpTLKorMIXFileTuple[1], targetSimpleWavFileName) ) + else: + if gTraceModeEnabled: + print "[Info] Output file %s already exists. Skipping..." % (os.path.join(outputWAVpath, tmpTLKorMIXFileTuple[1], targetSimpleWavFileName)) + else: + print "[Error] while loading audio file (AUD) %s!" % (targetSimpleAudFileName) else: - print "[Error] while loading audio file (AUD) %s!" % (targetSimpleAudFileName) - else: - print "[Error] while reading audio file (AUD) file %s into mem buffer" % (targetSimpleAudFileName) - #print "[Error] while reading audio file (AUD) file %s into mem buffer" % (''.join('{:08X}'.format(idOfMIXEntry))) - inTLKFile.close() + print "[Error] while reading audio file (AUD) file %s into mem buffer" % (targetSimpleAudFileName) + #print "[Error] while reading audio file (AUD) file %s into mem buffer" % (''.join('{:08X}'.format(idOfMIXEntry))) + inTLKorMIXFile.close() # SYS EXIT IS HERE ONLY FOR DEBUG PURPOSES OF PARSING TLK FILES - SHOULD BE COMMENTED OUT NORMALLY @@ -397,7 +477,8 @@ def appendPOGOTextSheet(excelOutBook = None): sh.write(n, 1, col2_name) n+=1 pogoTRInstance = pogoTextResource(gTraceModeEnabled) - + + objUTF8Unicode = None for m, e1 in enumerate(pogoTRInstance.getPogoEntriesList(), n): sh.write(m, 0, e1[0]) objStr = e1[1] @@ -409,59 +490,154 @@ def appendPOGOTextSheet(excelOutBook = None): objUTF8Unicode = unicode("???", 'utf-8') sh.write(m, 1, objUTF8Unicode) - -def appendDevCommentarySheet(excelOutBook = None): - if excelOutBook != None: +# aux: populate a row in extra audio sheets +def auxPopulateExtraSpeechAudioRow(sh = None, n = 0, pFilenameStr = '', pTextStr = '', pListOfExtraWavsForDevSheet = None): + if sh is None \ + or not pFilenameStr \ + or pListOfExtraWavsForDevSheet is None \ + or len(pListOfExtraWavsForDevSheet) == 0: + return False + + foundMatch = False + for dcAUDFilename, dcArchiveMIXFile in SUPPORTED_EXPORTED_AUD_FROM_MIX_FILES: + if dcAUDFilename == pFilenameStr: + sh.write(n, 0, pFilenameStr) # Filename + # We assume utf-8 charset for Audio Commentary and extra text entries (since we get the text from a python script) + try: + objUTF8Unicode = unicode(pTextStr, 'utf-8') + except Exception as e: + print '[Error] Failed to create unicode string: ' + str(e) + objUTF8Unicode = unicode("???", 'utf-8') + sh.write(n, 1, objUTF8Unicode) # Quote + sh.write(n, 2, 'N/A') # By Actor + sh.write(n, 3, '') # Notes + sh.write(n, 4, 'N/A') # To Actor + smArchiveMIXFile = '' + for smArchiveMIXFile, smArchiveMIXShort in SUPPORTED_MIX_INPUT_FOR_EXTRA_SPEECH_EXPORT_FILES: + if smArchiveMIXFile == dcArchiveMIXFile: + sh.write(n, 5, smArchiveMIXShort) # Resource - proper + break + + for extraWavFDS in pListOfExtraWavsForDevSheet: + twoTokensOfRelDirnameAndFilenameXLS = extraWavFDS.split('&', 2) + if len(twoTokensOfRelDirnameAndFilenameXLS) == 3: + tokensOfFilename = twoTokensOfRelDirnameAndFilenameXLS[0].split('#', 3) + #ShortHandFileName + if (tokensOfFilename[0][:-4]+'.AUD') in zip(*SUPPORTED_EXPORTED_AUD_FROM_MIX_FILES)[0] \ + and (tokensOfFilename[0][:-4]+'.AUD') == dcAUDFilename: + shortHandFileName = tokensOfFilename[0] + # real path of filename + realPathOfFileNameToLink = twoTokensOfRelDirnameAndFilenameXLS[2] + # checks if not empty + if gStringReplacementForRootFolderWithExportedFiles and gNumReplaceStartingCharacters > 0: + realPathOfFileNameToLink = realPathOfFileNameToLink.replace(realPathOfFileNameToLink[:gNumReplaceStartingCharacters], gStringReplacementForRootFolderWithExportedFiles) + + hyperlinkAudioFormula = 'HYPERLINK("file://%s","%s")' % (realPathOfFileNameToLink, shortHandFileName) + sh.write(n, 6, Formula(hyperlinkAudioFormula)) + break + foundMatch = True + break + return foundMatch + +def appendDevCommentarySheet(excelOutBook = None, listOfExtraWavsForDevSheet = None ): + + if excelOutBook != None \ + and listOfExtraWavsForDevSheet != None \ + and len(listOfExtraWavsForDevSheet) > 0: + + objUTF8Unicode = None print "[Info] Appending Developer Commentary sheet..." - if excelOutBook != None: - sh = excelOutBook.add_sheet("DEV COMMENTARY") - devCommentaryTextInstance = devCommentaryText(gTraceModeEnabled) - # First Segment - n = 0 # keeps track of rows - col_names = ['AUDIO COMMENTARY'] - colIdx = 0 - for colNameIt in col_names: - sh.write(n, colIdx, colNameIt) - colIdx+=1 - n+= 1 - - for idStr, textStr in devCommentaryTextInstance.getAudioCommentaryTextEntriesList(): - sh.write(n, 0, idStr) - # We assume utf-8 charset for Audio Commentary and extra text entries (since we get the text from a python script) - try: - objUTF8Unicode = unicode(textStr, 'utf-8') - except Exception as e: - print '[Error] Failed to create unicode string: ' + str(e) - objUTF8Unicode = unicode("???", 'utf-8') - sh.write(n, 1, objUTF8Unicode) - n+=1 - # Second Segment - col_names = ['I_SEZ QUOTES'] - colIdx = 0 - for colNameIt in col_names: - sh.write(n, colIdx, colNameIt) - colIdx+=1 - n+= 1 - - for idStr, textStr in devCommentaryTextInstance.getISEZTextEntriesList(): - sh.write(n, 0, idStr) - # We assume utf-8 charset for I_SEZ Commentary (since we get the text from a python script) - try: - objUTF8Unicode = unicode(textStr, 'utf-8') - except Exception as e: - print '[Error] Failed to create unicode string: ' + str(e) - objUTF8Unicode = unicode("???", 'utf-8') - sh.write(n, 1, objUTF8Unicode) - n+=1 + + sh = excelOutBook.add_sheet("DEV AUDIO") + devCommentaryTextInstance = devCommentaryText(gTraceModeEnabled) + # + # + # First Sheet + n = 0 # keeps track of rows + col_names = ["DEVELOPERS' AUDIO COMMENTARY"] + colIdx = 0 + for colNameIt in col_names: + sh.write(n, colIdx, colNameIt) + colIdx+=1 + n+= 1 + + col_names = ['Filename', 'Quote', 'By Actor', 'Notes', 'To Actor', 'Resource', 'ShortHandFileName'] + colIdx = 0 + for colNameIt in col_names: + sh.write(n, colIdx, colNameIt) + colIdx+=1 + n+= 1 + # populate audio commentary rows + for pFilenameStr, pTextStr in devCommentaryTextInstance.getAudioCommentaryTextEntriesList(): + if auxPopulateExtraSpeechAudioRow(sh, n, pFilenameStr, pTextStr, listOfExtraWavsForDevSheet) == True: + n+=1 # change row + # + # + # Second Sheet (EXTRA SPEECH) + sh = excelOutBook.add_sheet("SPEECH (SFX)") + n = 0 # keeps track of rows + col_names = ['EXTRA SPEECH (SFX)'] + colIdx = 0 + for colNameIt in col_names: + sh.write(n, colIdx, colNameIt) + colIdx+=1 + n+= 1 + + col_names = ['Filename', 'Quote', 'By Actor', 'Notes', 'To Actor', 'Resource', 'ShortHandFileName'] + colIdx = 0 + for colNameIt in col_names: + sh.write(n, colIdx, colNameIt) + colIdx+=1 + n+= 1 + + # populate extra speech audio rows + for pFilenameStr, pTextStr in devCommentaryTextInstance.getExtraSpeechAudioEntriesList(): + if auxPopulateExtraSpeechAudioRow(sh, n, pFilenameStr, pTextStr, listOfExtraWavsForDevSheet) == True: + n+=1 # change row + # + # + # Third Sheet + sh = excelOutBook.add_sheet("DEV I_SEZ") + n = 0 # keeps track of rows + col_names = ['I_SEZ QUOTES'] + colIdx = 0 + for colNameIt in col_names: + sh.write(n, colIdx, colNameIt) + colIdx+=1 + n+= 1 + + col_names = ['AssignedID', 'Quote', 'By Actor', 'Notes', 'To Actor', 'Resource', 'ShortHandFileName'] + colIdx = 0 + for colNameIt in col_names: + sh.write(n, colIdx, colNameIt) + colIdx+=1 + n+= 1 + + for idStr, textStr in devCommentaryTextInstance.getISEZTextEntriesList(): + sh.write(n, 0, idStr) + # We assume utf-8 charset for I_SEZ Commentary (since we get the text from a python script) + try: + objUTF8Unicode = unicode(textStr, 'utf-8') + except Exception as e: + print '[Error] Failed to create unicode string: ' + str(e) + objUTF8Unicode = unicode("???", 'utf-8') + sh.write(n, 1, objUTF8Unicode) + sh.write(n, 2, 'N/A') # by actor + sh.write(n, 3, '') # notes + sh.write(n, 4, 'N/A') # to actor + sh.write(n, 5, 'N/A') # Resources + sh.write(n, 6, 'N/A') # ShortHandFilename and URL + n+=1 return def inputMIXExtractTREs(inputMIXpath, excelOutBook = None): print "[Info] Checking in %s for MIX files to extract Text Resources (TR%ss) from..." % (inputMIXpath, gActiveLanguageDescriptionCodeTuple[1]) inputMIXFilesFound = [] + objUTF8Unicode = None # breaking after first for loop yields only the top directory files, which is what we want for (dirpath, dirnames, filenames) in walk(inputMIXpath): for filename in filenames: - for mixFileName in SUPPORTED_MIX_INPUT_FILES: + for mixFileName in SUPPORTED_MIX_INPUT_FOR_TRX_EXPORT_FILES: if filename.upper() == mixFileName: inputMIXFilesFound.append(mixFileName) break @@ -631,30 +807,33 @@ def inputMIXExtractTREs(inputMIXpath, excelOutBook = None): # -# Creating the OUTPUT XLS file with one sheet named as the @param sheet with entries based on the list1 (wav files, without duplicates) +# Creating the OUTPUT XLS file with one sheet named as the @param sheet with entries based on the +# listTlkWavs (wav files from TLK files, without duplicates) +# and /or +# listDevsWavs (extra (supported) wav files practicaclly from the SFX.MIX file), without duplicates) # -def outputXLS(filename, sheet, list1, parseTREResourcesAlso = False, addDevCommAndExtraSFXSheetEnabled = False, addPOGOTextSheetEnabled = False, mixInputFolderPath = ''): +def outputXLS(filename, sheet, listTlkWavs, listDevsWavs, parseTREResourcesAlso = False, addDevCommAndExtraSFXSheetEnabled = False, addPOGOTextSheetEnabled = False, mixInputFolderPath = ''): global gStringReplacementForRootFolderWithExportedFiles global gNumReplaceStartingCharacters + book = xlwt.Workbook() sh = book.add_sheet(sheet) -# First Row + # First Row n = 0 # keeps track of rows -# variables = [x, y, z] -# x_desc = 'Display' -# y_desc = 'Dominance' -# z_desc = 'Test' -# desc = [x_desc, y_desc, z_desc] -# -# -# #You may need to group the variables together -# #for n, (v_desc, v) in enumerate(zip(desc, variables)): -# for n, (v_desc, v) in enumerate(zip(desc, variables)): -# sh.write(n, 0, v_desc) -# sh.write(n, 1, v) + #variables = [x, y, z] + #x_desc = 'Display' + #y_desc = 'Dominance' + #z_desc = 'Test' + #desc = [x_desc, y_desc, z_desc] + # + # + # You may need to group the variables together + #for n, (v_desc, v) in enumerate(zip(desc, variables)): + #sh.write(n, 0, v_desc) + #sh.write(n, 1, v) col1_name = 'BladeRunnerTLK In-Game dialogue / voiceover quotes' sh.write(n, 0, col1_name) -# Second Row + # Second Row n = 1 col1_name = 'Filename' col2_name = 'Quote' @@ -674,7 +853,7 @@ def outputXLS(filename, sheet, list1, parseTREResourcesAlso = False, addDevCommA n+=1 - for m, e1 in enumerate(list1, n): + for m, e1 in enumerate(listTlkWavs, n): twoTokensOfRelDirnameAndFilenameXLS = e1.split('&', 2) if len(twoTokensOfRelDirnameAndFilenameXLS) == 3: fourTokensOfFilename = twoTokensOfRelDirnameAndFilenameXLS[0].split('#', 3) @@ -724,8 +903,8 @@ def outputXLS(filename, sheet, list1, parseTREResourcesAlso = False, addDevCommA # works for filenames where some rogue greek characters exist #sh.write(m, 0, str.decode("%s" % e1, 'utf-8')) -# for m, e2 in enumerate(list2, n+1): -# sh.write(m, 1, e2) + #for m, e2 in enumerate(list2, n+1): + # sh.write(m, 1, e2) appendVQAPlaceHolderSheets(book) if parseTREResourcesAlso == True and mixInputFolderPath != '': @@ -735,7 +914,7 @@ def outputXLS(filename, sheet, list1, parseTREResourcesAlso = False, addDevCommA appendPOGOTextSheet(book) if addDevCommAndExtraSFXSheetEnabled == True: - appendDevCommentarySheet(book) + appendDevCommentarySheet(book, listDevsWavs) try: book.save(filename) @@ -744,6 +923,52 @@ def outputXLS(filename, sheet, list1, parseTREResourcesAlso = False, addDevCommA print "[Error] Could not save the output Excel file:: " + str(e) # +# Aux function to weed out duplicates from wav file lists +# valid listTypes: 'TLKWAVS', 'EXTRAMIXWAVS' +def wavDupsRemove(listOfWavFiles, listType): + if listType != 'TLKWAVS' and listType != 'EXTRAMIXWAVS': + print '[Error] Invalid listtype %s specified to remove duplicate wav files' % (listType) + sys.exit(1) + + listOfWavFilesNoDups = [] + for filenameSrcTmp in listOfWavFiles: + duplicateFound = False + #print "[Debug]Converted %s" % (filenameSrcTmp) + # Weed out duplicates by copying to another table (quick and dirty) + twoTokensOfRelDirnameAndFilenameSrc = filenameSrcTmp.split('&', 2) + tmpRelDirNameSrc = twoTokensOfRelDirnameAndFilenameSrc[1] # eg. TLK1 + keyForDuplicateSearchSrc = None + keyForDuplicateSearchTarg = None + + if (listType == 'EXTRAMIXWAVS'): + keyForDuplicateSearchSrc = twoTokensOfRelDirnameAndFilenameSrc[0] + else: + threeTokensOfQuoteFilenameSrc = twoTokensOfRelDirnameAndFilenameSrc[0].split('#', 2) + #concatenate actorID and quoteID for search key + keyForDuplicateSearchSrc = threeTokensOfQuoteFilenameSrc[0] + threeTokensOfQuoteFilenameSrc[1] + + for fileTargIdx, filenameTargTmp in enumerate(listOfWavFilesNoDups): + twoTokensOfRelDirnameAndFilenameTarg = filenameTargTmp.split('&', 2) + tmpRelDirNameTarg = twoTokensOfRelDirnameAndFilenameTarg[1] + + if (listType == 'EXTRAMIXWAVS'): + keyForDuplicateSearchTarg = twoTokensOfRelDirnameAndFilenameTarg[0] + else: + threeTokensOfQuoteFilenameTarg = twoTokensOfRelDirnameAndFilenameTarg[0].split('#', 2) + #concatenate actorID and quoteID for search key + keyForDuplicateSearchTarg = threeTokensOfQuoteFilenameTarg[0] + threeTokensOfQuoteFilenameTarg[1] + if(keyForDuplicateSearchSrc == keyForDuplicateSearchTarg): + #print "[Debug] Found duplicate %s" % (filenameSrcTmp) + duplicateFound = True + listOfWavFilesNoDups[fileTargIdx] = twoTokensOfRelDirnameAndFilenameTarg[0] + '&' + tmpRelDirNameSrc + ',' + tmpRelDirNameTarg + '&' + twoTokensOfRelDirnameAndFilenameTarg[2] + break + if(duplicateFound == False): + listOfWavFilesNoDups.append(filenameSrcTmp) + #for filenameSrcTmp in listOfWavFilesNoDups: + # print "[Debug] Unique %s" % (filenameSrcTmp) + return listOfWavFilesNoDups + +# # Aux function to validate input language description # def getLanguageDescCodeTuple(candidateLangDescriptionStr): @@ -773,9 +998,11 @@ def main(argsCL): global gStringReplacementForRootFolderWithExportedFiles global gNumReplaceStartingCharacters global gActiveLanguageDescriptionCodeTuple - global gWavFiles - global gWavFilesNoDups - + global gMIXWavFiles + global gMIXWavFilesNoDups + global gTLKWavFiles + global gTLKWavFilesNoDups + gTraceModeEnabled = False gActiveLanguageDescriptionCodeTuple = DEFAULT_LANG_DESC_CODE @@ -793,7 +1020,7 @@ def main(argsCL): invalidSyntax = False print "Running %s (%s)..." % (APP_NAME_SPACED, APP_VERSION) -# print "Len of sysargv = %s" % (len(argsCL)) + #print "Len of sysargv = %s" % (len(argsCL)) if len(argsCL) == 2: if(argsCL[1] == '--help'or argsCL[1] == '-h'): print "%s %s supports Westwood's Blade Runner PC Game (1997)." % (APP_NAME_SPACED, APP_VERSION) @@ -873,12 +1100,16 @@ def main(argsCL): print "[Error] The output path for exported files (-op switch) argument is mandatory!" invalidSyntax = True - if (not invalidSyntax) and (exportWavFilesMode == True or extractTreFilesMode == True) and (TMProotFolderWithInputTLKFiles == ''): - print "[Error] No game input path (-ip switch) specified, while the export audio to WAV mode or the extract Text Resources mode is enabled." + if (not invalidSyntax) \ + and (exportWavFilesMode == True or extractDevCommAndExtraSFXMode == True or extractTreFilesMode == True) \ + and (TMProotFolderWithInputTLKFiles == ''): + print "[Error] No game input path (-ip switch) specified, while any of the export audio to WAV mode (-xwav), the export extras (-xdevs) or the extract Text Resources mode (-xtre) is enabled." invalidSyntax = True - if (not invalidSyntax) and (exportWavFilesMode == False and extractTreFilesMode == False) and (TMProotFolderWithInputTLKFiles != ''): - print "[Warning] Specified game input path (-ip switch) will be ignored, since the export audio to WAV mode and the extract Text Resources mode are disabled." + if (not invalidSyntax) \ + and (exportWavFilesMode == False and extractDevCommAndExtraSFXMode == False and extractTreFilesMode == False) \ + and (TMProotFolderWithInputTLKFiles != ''): + print "[Warning] Specified game input path (-ip switch) will be ignored, since the export audio to WAV mode (-xwav), the export extras (-xdevs) and the extract Text Resources mode (-xtre) are disabled." # not invalid syntax though gActiveLanguageDescriptionCodeTuple = getLanguageDescCodeTuple(candidateLangDescriptionTxt) @@ -891,8 +1122,8 @@ def main(argsCL): print "[Info] Game Language Selected: %s (%s)" % (gActiveLanguageDescriptionCodeTuple[0], gActiveLanguageDescriptionCodeTuple[2]) # parse Actors files: initActorPropertyEntries(pathToActorNamesTxt) -# for actorEntryTmp in gActorPropertyEntries: -# print "[Debug] Found actor: %s %s %s" % (actorEntryTmp[0], actorEntryTmp[1], actorEntryTmp[2]) + #for actorEntryTmp in gActorPropertyEntries: + # print "[Debug] Found actor: %s %s %s" % (actorEntryTmp[0], actorEntryTmp[1], actorEntryTmp[2]) # # Early checks for invalid cases # 1. if TMProotFolderWithInputTLKFiles is not valid and -xtre or -xwav -> error! @@ -900,55 +1131,67 @@ def main(argsCL): # # 2. if not -wav and -op path is invalid then empty INGQUOT sheet -> error # 3 [We check for this further bellow, before call for outputXLS]. if not -wav and -op path is empty (has no WAVs) then empty INGQUOT sheet -> Treat as an error case! - if ((exportWavFilesMode == True or extractTreFilesMode == True) and (not os.path.isdir(TMProotFolderWithInputTLKFiles))): - print "[Error] Invalid game input path (-ip switch) was specified, while the export audio to WAV mode or the extract Text Resources mode is enabled." + if ((exportWavFilesMode == True or extractDevCommAndExtraSFXMode == True or extractTreFilesMode == True) and (not os.path.isdir(TMProotFolderWithInputTLKFiles))): + print "[Error] Invalid game input path (-ip switch) was specified, while the export audio to WAV mode (-xwav), export extras (-xdevs) or the extract Text Resources mode (-xtre) is enabled." sys.exit(1) - if ((exportWavFilesMode == False) and (not os.path.isdir(TMProotFolderWithExportedFiles))): - print "[Error] Invalid output path for exported files (-op switch) was specified, while the export audio to WAV mode is disabled (if enabled, it would create the path)." + if ((exportWavFilesMode == False and extractDevCommAndExtraSFXMode == False) and (not os.path.isdir(TMProotFolderWithExportedFiles))): + print "[Error] Invalid output path for exported files (-op switch) was specified, while the export audio to WAV mode (-xwav) and export extras (-xdevs) are disabled (if enabled, it would create the path)." sys.exit(1) # # Checking for the optional case of parsing the input TLK files to export to WAV # if TMProotFolderWithInputTLKFiles != '': - if (exportWavFilesMode == True): - inputTLKsExport(TMProotFolderWithInputTLKFiles, TMProotFolderWithExportedFiles) + if (exportWavFilesMode == True or extractDevCommAndExtraSFXMode == True): + inputTLKsExport(TMProotFolderWithInputTLKFiles, TMProotFolderWithExportedFiles, exportWavFilesMode, extractDevCommAndExtraSFXMode) #if (extractTreFilesMode == True): # inputMIXExtractTREs(TMProotFolderWithInputTLKFiles) # # Parsing the exported WAV files - # - print "[Info] Parsing the exported WAV audio files. Please wait (this could take a while)..." + # NO: depending on the mode don't parse the irrellevant WAVs? + print "[Info] Parsing the (exported) WAV audio files in the -op path.\n\tPlease wait (this could take a while)..." + # The broad search here is intentional for (dirpath, dirnames, filenames) in walk(TMProotFolderWithExportedFiles): - for nameIdx, nameTmp in enumerate(filenames): - relDirName = '' -# os.path.split would Split the pathname path into a pair, (head, tail) where tail is the last pathname component and head is everything leading up to that. The tail part will never contain a slash - pathTokens = dirpath.split(os.path.sep) - for pTokenTmp in pathTokens: - if pTokenTmp.find("TLK") != -1: - relDirName = pTokenTmp -# print os.path.dirname(dirpath) -# print os.path.abspath(os.path.join(os.path.join(dirpath, nameTmp), os.pardir)) - filenames[nameIdx] = filenames[nameIdx] +'&' + relDirName + '&' + os.path.join(dirpath, nameTmp) - gWavFiles.extend(filenames) -# break - for fileIdx, filenameTmp in enumerate(gWavFiles): + for nameIdx, nameTmp in enumerate(filenames): + if (len(nameTmp) > 4) \ + and nameTmp.upper()[-4:] == '.WAV' \ + and len(nameTmp.split('.', 1)) == 2: # radical heal (but practical) - don't allow cases like .AUD.WAV or any intermediate dots in the filename! + relDirName = '' + # os.path.split would Split the pathname path into a pair, + # (head, tail) where tail is the last pathname component and head is everything leading up to that. The tail part will never contain a slash + pathTokens = dirpath.split(os.path.sep) + idxOfLastTLKToken = -1 + idxOfLastSFXToken = -1 + for tokenIdx, pTokenTmp in enumerate(pathTokens): + posOfTLKWithinRightmostToken = pTokenTmp.find("TLK") + posOfSFXWithinRightmostToken = pTokenTmp.find("SFX") + + if posOfTLKWithinRightmostToken != -1: + idxOfLastTLKToken = tokenIdx + if posOfSFXWithinRightmostToken != -1: + idxOfLastSFXToken = tokenIdx + + if (posOfTLKWithinRightmostToken != -1 \ + or posOfSFXWithinRightmostToken != -1): + relDirName = pTokenTmp # don't break, we are interested in right-most matching token in the path + #if (nameTmp.upper()[:-4] + '.AUD') in zip(*SUPPORTED_EXPORTED_AUD_FROM_MIX_FILES)[0]: + # print '[Trace] 1 file: %s' % (nameTmp.upper()) + # print 'TLKss %d vs SFXss:%d ' % (idxOfLastTLKToken, idxOfLastSFXToken) + + if (idxOfLastSFXToken > idxOfLastTLKToken \ + and (nameTmp.upper()[:-4] + '.AUD') in zip(*SUPPORTED_EXPORTED_AUD_FROM_MIX_FILES)[0]): + gMIXWavFiles.append(filenames[nameIdx] +'&' + relDirName + '&' + os.path.join(dirpath, nameTmp)) + else: + gTLKWavFiles.append(filenames[nameIdx] +'&' + relDirName + '&' + os.path.join(dirpath, nameTmp)) + #break + for fileIdx, filenameTmp in enumerate(gTLKWavFiles): twoTokensOfFilenameAndRelDirname = filenameTmp.split('&', 1) if len(twoTokensOfFilenameAndRelDirname) != 2: print "[Error] While attempting filename and relative dirname split: %s" % (filenameTmp) sys.exit(0) - twoTokensOfFilenameForExt = twoTokensOfFilenameAndRelDirname[0].split('.', 1) - if len(twoTokensOfFilenameForExt) == 2: - if twoTokensOfFilenameForExt[1] != 'WAV' and twoTokensOfFilenameForExt[1] != 'wav': - print "[Error] Found non supported file extension (not WAV): %s" % (twoTokensOfFilenameAndRelDirname[0]) - sys.exit(0) - else: - print "[Error] While attempting extension split: %s" % (twoTokensOfFilenameAndRelDirname[0]) - sys.exit(0) - #remove WAV extension here -# filenameTmp = twoTokensOfFilenameAndRelDirname[0] + '&' + twoTokensOfFilenameForExt[0] -# print "[Debug] Found %s" % (filenameTmp) - - threeTokensOfFilename = twoTokensOfFilenameForExt[0].split('_', 2) + # + # Remove WAV extension here + # AUD file from TLK archive + threeTokensOfFilename = twoTokensOfFilenameAndRelDirname[0][:-4].split('_', 2) if len(threeTokensOfFilename) == 3: # fix rogue _ chars in 3rd token of filename (split at '_') threeTokensOfFilename[2] = threeTokensOfFilename[2].replace("_", "-") @@ -963,91 +1206,65 @@ def main(argsCL): threeTokensOfFilename.append(tmpActorFullName) else: #fatal error if something cannot convert to spot it immediately - print "[Error] in actorIdMatch match: %s %s" % (tmpActorId, twoTokensOfFilenameForExt[0]) + print "[Error] in actorIdMatch match: %s %s" % (tmpActorId, twoTokensOfFilenameAndRelDirname[0][:-4]) sys.exit(0) else: #fatal error if something cannot convert to spot it immediately - print "[Error] in shorthand match: %s %s" % (threeTokensOfFilename[0], twoTokensOfFilenameForExt[0]) + print "[Error] in shorthand match: %s %s" % (threeTokensOfFilename[0], twoTokensOfFilenameAndRelDirname[0][:-4]) sys.exit(0) -# -# -# foundMatchForActorShortHand = False -# for actorEntryTmp in gActorPropertyEntries: -# if actorEntryTmp[1] == threeTokensOfFilename[0]: -# threeTokensOfFilename[0] = actorEntryTmp[0].zfill(2) -# threeTokensOfFilename.append(actorEntryTmp[2]) -# foundMatchForActorShortHand = True -# break - # end of replace actor name shorthand - twoTokensOfFilenameForExt[0] = '#'.join(threeTokensOfFilename) - filenameTmp = twoTokensOfFilenameForExt[0] + '&' + twoTokensOfFilenameAndRelDirname[1] - gWavFiles[fileIdx] = filenameTmp + # + # + #foundMatchForActorShortHand = False + #for actorEntryTmp in gActorPropertyEntries: + # if actorEntryTmp[1] == threeTokensOfFilename[0]: + # threeTokensOfFilename[0] = actorEntryTmp[0].zfill(2) + # threeTokensOfFilename.append(actorEntryTmp[2]) + # foundMatchForActorShortHand = True + # break + # end of replace actor name shorthand + tmpHealedSimpleFilename = '#'.join(threeTokensOfFilename) + filenameTmp = tmpHealedSimpleFilename + '&' + twoTokensOfFilenameAndRelDirname[1] + gTLKWavFiles[fileIdx] = filenameTmp else: print "[Error] in splitting tokens on _: %s" % (filenameTmp) sys.exit(0) + # + # Now handle the extra speech files (-xdevs mode) + for fileIdx, filenameTmp in enumerate(gMIXWavFiles): # + # if it's a AUD file from a MIX archive, we treat it differently here + # (we will put it in another sheet) + twoTokensOfFilenameAndRelDirname = filenameTmp.split('&', 1) + if len(twoTokensOfFilenameAndRelDirname) != 2: + print "[Error] While attempting filename and relative dirname split on extra speech file: %s" % (filenameTmp) + sys.exit(0) + + if (gTraceModeEnabled): + print "[Debug] No healing action needed on: %s" % (twoTokensOfFilenameAndRelDirname[0]) + #sort in-place # # - gWavFiles.sort() -# # -# # -# # Code for renaming non conforming filenames - just to be consistent in file naming -# # TO BE RUN ONCE FOR CONFORMANCE. No NEED TO Re-RUN -# # If its run though, comment this section and re-run the tool to get proper links in Excel file -# # -# for filenameSrcTmp in gWavFiles: -# # get real full path from last token when split at & -# # create target full path from the parentdir of last token and the current state of first 3 tokens when splitting at '#' -# # report mismatch -# # print (BUT DON'T PROCEED AT THIS POINT) what you would rename to what. -# threeTokensOfFilenameAndRelDirname = filenameSrcTmp.split('&', 2) -# currentSrcFullPath = threeTokensOfFilenameAndRelDirname[2] -# fourTokensOfTargetFileName = threeTokensOfFilenameAndRelDirname[0].split('#', 3) -# tmpActorShortHand = getActorShortNameById(fourTokensOfTargetFileName[0]) -# targetFileName = tmpActorShortHand + '_' + fourTokensOfTargetFileName[1] + '_' + fourTokensOfTargetFileName[2] + '.WAV' -# # os.path.split would Split the pathname path into a pair, (head, tail) where tail is the last pathname component and head is everything leading up to that. The tail part will never contain a slash -# (srcParentDir, srcTail) = os.path.split(currentSrcFullPath) -# targetFullPath = os.path.join(srcParentDir, targetFileName) -# # os.rename(src, dst) -# if(currentSrcFullPath != targetFullPath): -# print currentSrcFullPath -# print targetFullPath -# os.rename(currentSrcFullPath, targetFullPath) + gTLKWavFiles.sort() + gMIXWavFiles.sort() # - # END OF: Code for renaming non conforming filenames - just to be consistent in file naming # + # Remove duplicates from TLK AUD speech files (-xwav mode) # - for filenameSrcTmp in gWavFiles: - duplicateFound = False -# print "[Debug]Converted %s" % (filenameSrcTmp) - # Weed out duplicates by copying to another table (quick and dirty) - twoTokensOfRelDirnameAndFilenameSrc = filenameSrcTmp.split('&', 2) - tmpRelDirNameSrc = twoTokensOfRelDirnameAndFilenameSrc[1] - threeTokensOfQuoteFilenameSrc = twoTokensOfRelDirnameAndFilenameSrc[0].split('#', 2) - #concatenate actorID and quoteID for search key - keyForDuplicateSearchSrc = threeTokensOfQuoteFilenameSrc[0] + threeTokensOfQuoteFilenameSrc[1] - for fileTargIdx, filenameTargTmp in enumerate(gWavFilesNoDups): - twoTokensOfRelDirnameAndFilenameTarg = filenameTargTmp.split('&', 2) - tmpRelDirNameTarg = twoTokensOfRelDirnameAndFilenameTarg[1] - threeTokensOfQuoteFilenameTarg = twoTokensOfRelDirnameAndFilenameTarg[0].split('#', 2) - #concatenate actorID and quoteID for search key - keyForDuplicateSearchTarg = threeTokensOfQuoteFilenameTarg[0] + threeTokensOfQuoteFilenameTarg[1] - if(keyForDuplicateSearchSrc == keyForDuplicateSearchTarg): - #print "[Debug] Found duplicate %s" % (filenameSrcTmp) - duplicateFound = True - gWavFilesNoDups[fileTargIdx] = twoTokensOfRelDirnameAndFilenameTarg[0] + '&' + tmpRelDirNameSrc + ',' + tmpRelDirNameTarg + '&' + twoTokensOfRelDirnameAndFilenameTarg[2] - break - if(duplicateFound == False): - gWavFilesNoDups.append(filenameSrcTmp) -# for filenameSrcTmp in gWavFilesNoDups: -# print "[Debug] Unique %s" % (filenameSrcTmp) - if len(gWavFilesNoDups) == 0: - print "[Error] No supported audio files (WAV) were found in the output folder path (-op switch)." + gTLKWavFilesNoDups = wavDupsRemove(gTLKWavFiles, 'TLKWAVS') + if len(gTLKWavFilesNoDups) == 0: + print "[Error] No supported speech audio files (WAV) were found in the output folder path (-op switch)." sys.exit(1) - + # + # Remove duplicates from extra speech files (-xdevs mode) + # + gMIXWavFilesNoDups = wavDupsRemove(gMIXWavFiles, 'EXTRAMIXWAVS') + if extractDevCommAndExtraSFXMode and len(gMIXWavFilesNoDups) == 0: + print "[Error] No supported extra speech audio files (WAV) were found in the output folder path (-op switch)." + sys.exit(1) + constructedOutputFilename = "%s-%s%s" % (OUTPUT_XLS_FILENAME, gActiveLanguageDescriptionCodeTuple[2], OUTPUT_XLS_FILENAME_EXT) print "[Info] Creating output excel %s file..." % (constructedOutputFilename) - outputXLS(constructedOutputFilename, OUTPUT_XLS_QUOTES_SHEET + gActiveLanguageDescriptionCodeTuple[1] + '.TR' + gActiveLanguageDescriptionCodeTuple[1], gWavFilesNoDups, extractTreFilesMode, extractDevCommAndExtraSFXMode, extractPOGOTextMode, TMProotFolderWithInputTLKFiles) + outputXLS(constructedOutputFilename, OUTPUT_XLS_QUOTES_SHEET + gActiveLanguageDescriptionCodeTuple[1] + '.TR' + gActiveLanguageDescriptionCodeTuple[1], gTLKWavFilesNoDups, gMIXWavFilesNoDups, extractTreFilesMode, extractDevCommAndExtraSFXMode, extractPOGOTextMode, TMProotFolderWithInputTLKFiles) else: invalidSyntax = True diff --git a/devtools/create_bladerunner/subtitles/quotesSpreadsheetCreator/treFileLib.py b/devtools/create_bladerunner/subtitles/quotesSpreadsheetCreator/treFileLib.py index 34435eb0c5..d9ee538fb0 100644 --- a/devtools/create_bladerunner/subtitles/quotesSpreadsheetCreator/treFileLib.py +++ b/devtools/create_bladerunner/subtitles/quotesSpreadsheetCreator/treFileLib.py @@ -1,12 +1,26 @@ #!/usr/bin/env python # -*- coding: UTF-8 -*- # -import os, sys - +osLibFound = False +sysLibFound = False shutilLibFound = False structLibFound = False try: + import os +except ImportError: + print "[Error] os python library is required to be installed!" +else: + osLibFound = True + +try: + import sys +except ImportError: + print "[Error] sys python library is required to be installed!" +else: + sysLibFound = True + +try: import shutil except ImportError: print "[Error] Shutil python library is required to be installed!" @@ -20,7 +34,10 @@ except ImportError: else: structLibFound = True -if (not shutilLibFound) or (not structLibFound): +if (not osLibFound) \ + or (not sysLibFound) \ + or (not shutilLibFound) \ + or (not structLibFound): sys.stdout.write("[Error] Errors were found when trying to import required python libraries\n") sys.exit(1) |