Initial commit
This commit is contained in:
104
devtools/create_bladerunner/subtitles/.gitignore
vendored
Normal file
104
devtools/create_bladerunner/subtitles/.gitignore
vendored
Normal file
@@ -0,0 +1,104 @@
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
MANIFEST
|
||||
|
||||
# PyInstaller
|
||||
# Usually these files are written by a python script from a template
|
||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||
*.manifest
|
||||
*.spec
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.coverage
|
||||
.coverage.*
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*.cover
|
||||
.hypothesis/
|
||||
.pytest_cache/
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
# Django stuff:
|
||||
*.log
|
||||
local_settings.py
|
||||
db.sqlite3
|
||||
|
||||
# Flask stuff:
|
||||
instance/
|
||||
.webassets-cache
|
||||
|
||||
# Scrapy stuff:
|
||||
.scrapy
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
|
||||
# PyBuilder
|
||||
target/
|
||||
|
||||
# Jupyter Notebook
|
||||
.ipynb_checkpoints
|
||||
|
||||
# pyenv
|
||||
.python-version
|
||||
|
||||
# celery beat schedule file
|
||||
celerybeat-schedule
|
||||
|
||||
# SageMath parsed files
|
||||
*.sage.py
|
||||
|
||||
# Environments
|
||||
.env
|
||||
.venv
|
||||
env/
|
||||
venv/
|
||||
ENV/
|
||||
env.bak/
|
||||
venv.bak/
|
||||
|
||||
# Spyder project settings
|
||||
.spyderproject
|
||||
.spyproject
|
||||
|
||||
# Rope project settings
|
||||
.ropeproject
|
||||
|
||||
# mkdocs documentation
|
||||
/site
|
||||
|
||||
# mypy
|
||||
.mypy_cache/
|
||||
316
devtools/create_bladerunner/subtitles/README.md
Normal file
316
devtools/create_bladerunner/subtitles/README.md
Normal file
@@ -0,0 +1,316 @@
|
||||
# Blade Runner (Westwood Studios, 1997) Subtitles Support
|
||||
Some tools written in __Python 3.x (tested with 3.10.11) and backwards compatible with Python 2.7 (tested with 2.7.18)__ to help add support for subtitles in Westwood's point and click adventure game Blade Runner (1997) for PC.
|
||||
The official English, German, French, Italian and Spanish versions of the game should be supported.
|
||||
|
||||
## Quick guide for volunteer transcribers
|
||||
1. Please make sure you have an audio player installed in your Operating System (such as VLC).
|
||||
|
||||
2. You will need Python 3.10 (recommended) installed for this guide, as well as the Python libraries:
|
||||
* Pillow (tested with 9.5.0)
|
||||
* pandas (tested with 1.5.3)
|
||||
* openpyxl (tested with 3.1.2)
|
||||
* xlwt (tested with 1.3.0)
|
||||
|
||||
You could also use Python 2.7, but that is no longer the recommended way, since Python 2.7 reached the end of its life on January 1st, 2020 and is no longer maintained.
|
||||
For legacy purposes, the libraries required for running the scripts with Python 2.7 are:
|
||||
* Pillow (tested with 6.2.2) or PIL (tested with 1.1.7)
|
||||
* pandas (tested with 0.24.2)
|
||||
* openpyxl (tested with 2.6.4)
|
||||
* xlwt (tested with 1.3.0)
|
||||
* xlutils (tested with 2.0.0)
|
||||
|
||||
3. Using git, checkout the latest revision of the ScummVM repository from GitHub.
|
||||
|
||||
4. Make sure you've created a Blade Runner game directory and added Blade Runner in ScummVM as per the instructions in the wiki (the actual required files are __1.TLK, 2.TLK, 3.TLK, A.TLK and SPCHSFX.TLK__: <https://wiki.scummvm.org/index.php?title=User_Manual/Installing_a_game_for_use_with_ScummVM#Blade_Runner>
|
||||
For this guide it is assumed that this folder is:
|
||||
```console
|
||||
C:\Westwood\Blade Runner\
|
||||
```
|
||||
|
||||
5. Create a folder on your HDD to export all speech audio from the game. Eg. create:
|
||||
```console
|
||||
C:\Westwood\Blade Runner\AUDIO_FRA\
|
||||
```
|
||||
|
||||
6. Export all speech audio from the game and create an Excel file (xls) with links to the audio files.
|
||||
* You will need to have some free HDD space for this step (around 650MB).
|
||||
|
||||
* Using a command line interface (eg. MSYS2) navigate to the ScummVM repository folder and issue a command like the one below, making sure you specify the correct target language code for your requirements; supported language codes are "EN\_ANY" for English, "FR\_FRA" for French, "DE\_DEU" for German, "IT\_ITA" for Italian, "ES\_ESP" for Spanish and "RU\_RUS" for Russian (version by Fargus Multimedia).
|
||||
|
||||
* In the following example we assume we need to export the audio from the French version of the game. This could take a few minutes to complete. Please refer to the [quotesSpreadsheetCreator](#quotesspreadsheetcreator-quotespreadsheetcreatorpy) section of this document for more command-line options for this tool.
|
||||
```bash
|
||||
python devtools/create_bladerunner/subtitles/quotesSpreadsheetCreator/quoteSpreadsheetCreator.py -op "/c/Westwood/Blade Runner/AUDIO_FRA" -ip "/c/Westwood/Blade Runner" -ian "devtools/create_bladerunner/subtitles/common/actornames.txt" -xwav -ld FR_FRA
|
||||
```
|
||||
|
||||
7. Once you've completed the above step, an Excel file should be created in your current folder, named "out-French.xls". Open this file with a spreadsheet editor app (tested with Microsoft Excel 2007 and LibreOffice Calc 6.2.4) and select the "INGQUO_#.TR#" sheet.
|
||||
* Please keep the column A ("Filename") as is. Do not modify the contents of this column.
|
||||
|
||||
* Edit column B ("Quote") to put in the text for your transcript of the corresponding audio file
|
||||
|
||||
* Use column G ("ShortHandFileName") to play the audio file for the quote to be transcribed in the same line. You should be able to double click in MS Excel or Ctrl+Click on the specific cell; an audio player will be launched automatically to play the audio file.
|
||||
|
||||
* Note that the columns used by the tool that will create the final subtitles file are only columns A and B.
|
||||
|
||||
8. The rest of the sheets in the Excel file, excluding the "SBTLVERS.TRE" which contains versioning info) are the sheets for the video cutscenes. We don't provide links to the audio cues for those subtitles, but we do provide the timings for the English version of these scenes which you can use as a guide, along with the English transcript available online here: <https://docs.google.com/spreadsheets/d/17ew0YyhSwqcqZg6bXrIgz0GkA62dhgViHN15lOu5Hj8/edit?usp=sharing>
|
||||
* Note that the important columns used by the tool that will create the final subtitles file are in this case only columns A ("Frame Start"), B ("Frame End") and C ("Subtitle").
|
||||
|
||||
* Fill in column C with the subtitle text, and set the values in columns A and B to adjust when the subtitle should start and when it should stop being displayed respectively.
|
||||
|
||||
9. You may edit the info in the "SBTLVERS.TRE" sheet to fill in the credits and a version number for your transcript.
|
||||
|
||||
10. If you're transcribing for a non-Latin language, you will need to create a special font for the subtitles in order for the game to display your transcript properly. Please, refer to the [fontCreator](#fontcreator-fontcreatorpy) section of this document for this process.
|
||||
|
||||
## Building and installing a SUBTITLES.MIX file with a "make" command
|
||||
You need to follow these instructions:
|
||||
|
||||
1. Download the online Excel transcript and save it as "englishTranscript.xlsx" into the "devtools\create_bladerunner\subtitles\sampleInput" folder.
|
||||
__The online Excel file is available here:__
|
||||
<https://docs.google.com/spreadsheets/d/17ew0YyhSwqcqZg6bXrIgz0GkA62dhgViHN15lOu5Hj8/edit?usp=sharing>
|
||||
|
||||
2. Edit your font glyphs PNG file (or use the provided one in the sampleInput folder). This file should be stored as "subtitlesFont.png" into the "devtools\create\_bladerunner\subtitles\sampleInput" folder.
|
||||
|
||||
3. Create an overrideEncodingSUBLTS.txt file in the sampleInput folder. This is a configuration file for the font file creation. A sample is provided in the sampleInput folder and documentation about this is below in this document (see "override encoding text file" in fontCreator).
|
||||
|
||||
4. Create a configureFontsTranslation.txt in the sampleInput folder. A configuration file for the MIX file creation. A sample is provided in the sampleInput folder and documentation about this is below in this document (see "text configuration file" in mixResourceCreator).
|
||||
|
||||
5. From the ScummVM root folder run:
|
||||
```bash
|
||||
make devtools/create_bladerunner/subtitles
|
||||
```
|
||||
|
||||
6. You may need to install some required Python 3 (or 2) libraries such as Pillow (or PIL), pandas, openpyxl, xlwt.
|
||||
|
||||
7. Copy the output file "SUBTITLES.MIX", created in the ScummVM root folder, into your Blade Runner game directory.
|
||||
|
||||
8. Launch the Blade Runner game using ScummVM.
|
||||
|
||||
## quotesSpreadsheetCreator (quoteSpreadsheetCreator.py)
|
||||
(requires Python libs *xlwt* (tested with version 1.3.0 for both Python 3 and Python 2.7))
|
||||
|
||||
A tool to gather all the speech audio filenames in an Excel file which will include a column with links to the audio file location on the PC. By Ctrl+MouseClick on that column's entries you should be able to listen to the corresponding WAV file.
|
||||
|
||||
The output Excel file *out.xls* should help with the transcription of all the spoken *in-game* quotes. It also provides extra quote information such as the corresponding actor ID and quote ID per quote.
|
||||
|
||||
Note 1: A lot of extra information has been added to the output Excel file maintained for the English transcription, such as whether a quote is unused or untriggered, the person a quote refers to (when applicable), as well as extra quotes that are not separate Audio files (AUD) in the game's archives but are part of a video file (VQA) or were text resources (TRx) for dialogue menus, UI etc. Therefore, this tool is provided here mostly for archiving purposes.
|
||||
|
||||
__The online Excel file is available here:__
|
||||
<https://docs.google.com/spreadsheets/d/17ew0YyhSwqcqZg6bXrIgz0GkA62dhgViHN15lOu5Hj8/edit?usp=sharing>
|
||||
|
||||
Syntax Notes:
|
||||
|
||||
1. The "-op" switch should be followed by the path to the folder where the WAV files should be exported; This folder path will also be used as input when the output Excel will be created (for the "INGQUO\_x.TRx" sheet with the in-game quotes).
|
||||
|
||||
2. The "-ip" switch should be followed by the path to the game's folder, where the TLK and MIX files reside.
|
||||
|
||||
3. The "-ian" optional switch is followed by the path to the actornames.txt file -- if this is omitted then the file is assumed to reside in the current working directory.
|
||||
|
||||
4. The "-ld" optional switch is followed by a language description for the language of the game you are exporting Text Resources from. This switch is meaningful when you also use the "-xtre" switch to export Text Resource files.
|
||||
* Valid language values are: EN\_ANY, DE\_DEU, FR\_FRA, IT\_ITA, ES\_ESP, RU\_RUS
|
||||
|
||||
* Default language value is: EN\_ANY (English)
|
||||
|
||||
5. The "-xwav" optional switch will export __ALL__ game's audio files (AUD) (that are either speech or speech-related) in a WAV format. This is expected to run for a few minutes and take up quite a lot of your HDD space (around 650MB).
|
||||
|
||||
6. The "-xtre" optional switch will add extra sheets to the output Excel with the contents of each of the game's Text Resource files (TRx) (on sheet per TRx file).
|
||||
|
||||
7. The "-xdevs" optional switch will add a sheet for Developer Commentary text and some additional voice-overs from SFX.MIX.
|
||||
|
||||
8. The "-xpogo" optional switch will add a sheet for the POGO text.
|
||||
|
||||
9. You may use all, a subset or none of the "-xwav", "-xtre", "-xpogo", "-xdevs" switches, depending on what you need to do.
|
||||
|
||||
10. The "--trace" optional switch enables extra debug messages to be printed.
|
||||
|
||||
Usage:
|
||||
```bash
|
||||
python quoteSpreadsheetCreator.py -op folderpath_for_exported_wav_Files [-ip folderpath_for_TLK_Files] [-ian pathToActorNamesTxt] [-m stringPathToReplaceFolderpathInExcelLinks] [-ld languageDescription] [-xwav] [-xtre] [--trace]
|
||||
```
|
||||
|
||||
The tool __requires__ a valid path to the actornames.txt file; this file is included in the samples folder.
|
||||
|
||||
## mixResourceCreator (mixResourceCreator.py)
|
||||
(requires Python libs *xlwt* (tested with version 1.3.0 for both Python 3 and Python 2.7) and, only for Python 2.7, *xlutils* (version 2.0.0))
|
||||
|
||||
A tool to process the aforementioned Excel file with the dialogue transcriptions and output text resource files (TRx) that will be packed along with the external font (see fontCreator tool) into a SUBTITLES.MIX file. Multiple TRx files will be created intermediately in order to fully support subtitles in the game. One TRx file includes all in-game spoken quotes and the rest of them correspond to any VQA video sequence that contain voice acting.
|
||||
|
||||
Usage:
|
||||
```bash
|
||||
python mixResourceCreator.py -x excelWithTranscriptSheets.xlsx [-ian pathToActorNamesTxt] [-cft pathToConfigureFontsTranslationTxt] [--trace]
|
||||
```
|
||||
|
||||
The tool __requires__ a valid path to the actornames.txt file, which is included in the samples folder.
|
||||
|
||||
Syntax Notes:
|
||||
|
||||
1. The "-x" switch is followed by the path to the input Excel file (xls or xlsx) which should contain the transcript sheet(s).
|
||||
|
||||
2. The "-ian" optional switch is followed by the path to the actornames.txt file -- if this is omitted then the file is assumed to reside in the current working directory.
|
||||
|
||||
3. The "-cft" optional switch is followed by the path to the text configuration file "configureFontsTranslation.txt" -- if this is omitted then the file is assumed to reside in the current working directory.
|
||||
|
||||
4. The "-ld" optional switch is followed by a language description for the language of the game you are exporting Text Resources from. This switch is meaningful when you also use the "-xtre" switch to export Text Resource files.
|
||||
* Valid language values are: EN\_ANY, DE\_DEU, FR\_FRA, IT\_ITA, ES\_ESP, RU\_RUS, EFIGS
|
||||
|
||||
* Default language value is: EN\_ANY (English)
|
||||
|
||||
5. The "--trace" optional switch enables extra debug messages to be printed.
|
||||
|
||||
The __text configuration file "configureFontsTranslation.txt"__ is a __text file that should be saved in a UTF-8 encoding (no BOM)__, that contains the following:
|
||||
|
||||
1. Multiple lines (practically one per imported Font type) with the key "fontNameAndOutOfOrderGlyphs" and a '\#'-separated value that contains:
|
||||
* the name of an in-game Font "type" that will be included in the SUBTITLES.MIX resource archive. You could also have lines for Font "types" not imported in the SUBTITLES.MIX, but are already Font types used by the game (eg. KIA6PT) especially when you intend to add translated/ updated TRx files in the SUBTITLES.MIX (however even in that case, there are default settings for those fonts that the script will use if you don't specify alternative settings in this file to override them). Valid values can be: SUBTLS\_E (for all subtitles), KIA6PT, TAHOMA (for both TAHOMA18 and TAHOMA24), SYSTEM (this is basically for the ERRORMSG.TRx).
|
||||
|
||||
* a '\#' character after the font type
|
||||
|
||||
* the name of the 8-bit string encoding (codepage) (eg. cp437 or windows-1252) that should be used to store the texts that uses this particular font "type" in the game's TRx text resource files. Valid values can be the standard encodings listed in python's page:
|
||||
|
||||
For Python 3.10: <https://docs.python.org/3.10/library/codecs.html#standard-encodings>
|
||||
|
||||
For Python 2.7: <https://docs.python.org/2.7/library/codecs.html#standard-encodings>
|
||||
|
||||
* a '\#' character after the target Encoding
|
||||
|
||||
* a list of comma separated tuples that specify the mapping of special (out of order) character to placeholder characters from the selected codepage. See fontCreator section for more details on this.
|
||||
|
||||
* For example:
|
||||
```text
|
||||
fontNameAndOutOfOrderGlyphs=SUBTLS_E#windows-1253#í:Ά,ñ:¥,â:¦,é:§,Ά:£
|
||||
fontNameAndOutOfOrderGlyphs=KIA6PT#cp437#
|
||||
fontNameAndOutOfOrderGlyphs=TAHOMA#cp437#
|
||||
fontNameAndOutOfOrderGlyphs=SYSTEM#latin-1#
|
||||
```
|
||||
|
||||
Note: for font files (FON) that you have created or edited with the fontCreator tool (e.g for the "SUBTLS\_E.FON" file for subtitles, or another in-game font file eg. KIA6PT, TAHOMA) you __should copy the 8-bit encoding and the comma separated out of order character tuples from the respective "override encoding" text file that you used with the fontCreator tool for each new/ edited font in the configureFontsTranslation.txt fields__.
|
||||
|
||||
Additionally, __all the new and edited fonts (FON files that were output by the fontCreator script) should be in your working directory__ in order to include them in the SUBTITLES.MIX.
|
||||
|
||||
It's important to keep the naming of those files unchanged. __Supported name values for imported FON files__ are: SUBTLS\_E.FON, KIA6PT.FON, TAHOMA18.FON, TAHOMA24.FON and SYSTEM.FON (practically you won't be using the last one).
|
||||
|
||||
## fontCreator (fontCreator.py)
|
||||
(requires Python Image library *Pillow* (tested with version 9.5.0 for Python 3, and version 6.2.2 for Python 2.7))
|
||||
|
||||
A tool to support __both__ the exporting of fonts from the game (to PNG images) __and__ the creation of a font file (FON) in order to resolve various issues with the available fonts (included in the game's own resource files). These issues include alignment, kerning, corrupted format, limited charset and unsupported characters -- especially for languages with too many non-Latin symbols in their alphabet.
|
||||
This font tool's code is based off the Monkey Island Special Edition's Translator (<https://github.com/ShadowNate/MISETranslator>).
|
||||
|
||||
Usage:
|
||||
|
||||
Syntax A - To export game fonts to PNG images:
|
||||
```bash
|
||||
python fontCreator.py -ip folderpathForMIXFiles
|
||||
```
|
||||
|
||||
Syntax B - To create the subtitle's font:
|
||||
```bash
|
||||
python fontCreator.py -im imageRowPNGFilename -om targetFONfilename [-oe pathToOverrideEncodingTxt] -pxLL minSpaceBetweenLettersInRowLeftToLeft -pxTT minSpaceBetweenLettersInColumnTopToTop -pxKn kerningForFirstDummyFontLetter -pxWS whiteSpaceWidthInPixels [-pxYo yOffsetInPixels] [--noAutoTabCalculation] [--noSpecialGlyphs] [--trace]
|
||||
```
|
||||
|
||||
This tool __requires an override encoding text file__ in its Syntax B mode (subtitle font creation). You can specify the path to this file after a "-oe" switch. If you don't provide this path, the script will search for an "overrideEncoding.txt" file in the current working directory.
|
||||
|
||||
The override encoding file is a __text file that should be saved in a UTF-8 encoding (no BOM)__, that contains the following:
|
||||
|
||||
1. A key "targetEncoding" with a value of the name of the ASCII codepage (8-bit encoding) that should be used for the character fonts (eg windows-1253). Valid values can be the standard encodings listed in Python's page:
|
||||
* For Python 3.10: <https://docs.python.org/3.10/library/codecs.html#standard-encodings>
|
||||
* For Python 2.7: <https://docs.python.org/2.7/library/codecs.html#standard-encodings>
|
||||
|
||||
2. A key "asciiCharList" with value the "all-characters" string with all the printable characters that will be used in-game, from the specified codepage. Keep in mind that:
|
||||
* The first such character (typically this is the '!' character) should be repeated twice!
|
||||
|
||||
* All characters must belong to the specified codepage.
|
||||
|
||||
* The order that the characters appear in the string should match their order in the ASCII table of the codepage.
|
||||
|
||||
* You don't need to use all the characters of the specified codepage in your "all-characters" string.
|
||||
|
||||
* For any special characters that don't appear in the target codepage (eg ñ, é, í, â don't appear in the Greek codepage), you'll have to decide on an ASCII value for them (one not used by another character appearing in-game).
|
||||
|
||||
* In the "all-characters" string you should put as placeholders the actual characters from the specified codepage that correspond to the ASCII values you have decided above; The placeholder characters should also be in the proper order (by their ASCII value) inside the string.
|
||||
|
||||
3. A key "explicitKerningList" with value a list of comma separated tuples where each tuple specifies a character and its manually set kerning (x-offset) in pixels. Kerning can have integer (positive or negative) values. This list is optional and may be skipped, if you put a '-' instead of a list.
|
||||
* Example: explicitKerningList=i:-1
|
||||
|
||||
* Don't use space(s) between the tuples!
|
||||
|
||||
4. A key "explicitWidthIncrement" with value a list of comma separated tuples where each tuple specifies a character and its manually set extended width in pixels. This should be a positive integer value. You can skip this list by not writing anything in the file after the previous (manual kerning) list.
|
||||
* Example: explicitWidthIncrement=i:0,j:1,l:1
|
||||
|
||||
* Don't use space(s) between the tuples!
|
||||
|
||||
5. A key "originalFontName" with the FON file's original name in the game (the one that it should replace). Use SUBLTS for the subtitles FON.
|
||||
* Example: originalFontName=SUBLTS
|
||||
|
||||
6. A key "specialOutOfOrderGlyphsUTF8ToAsciiTargetEncoding" with value a list of comma separated tuples that indicates which character glyphs should replace the placeholder glyphs in your all-character string above.
|
||||
* Example: specialOutOfOrderGlyphsUTF8ToAsciiTargetEncoding=í:Ά,ñ:¥,â:¦,é:§,Ά:£
|
||||
|
||||
* Don't use space(s) between the tuples!
|
||||
|
||||
There is a sample of such file in the source folder for the fontCreator tool.
|
||||
|
||||
__For the exporting of the game fonts (to PNG) mode__, the valid syntax expects only one (1) argument:
|
||||
|
||||
1. folderpathForMIXFiles: is the path where the game's MIX files are located (STARTUP.MIX is required). The exported font files will be: 10PT.FON.PNG, TAHOMA18.FON.PNG, TAHOMA24.FON.PNG and KIA6PT.FON.PNG.
|
||||
|
||||
__For the creation of subtitles' font mode__, there are six (6) mandatory launch arguments for the fontCreator tool:
|
||||
|
||||
1. imageRowPNGFilename: is the filename of the input PNG image file which should contain a row of (preferably) tab separated glyphs. Example: "Tahoma\_18ShdwTranspThreshZero003-G5.png". Keep in mind that:
|
||||
* The first glyph should be repeated here too, as in the override encoding text file.
|
||||
|
||||
* Background should be transparent.
|
||||
|
||||
* All colors used in the character glyphs should not have any transparency value (eg from Gimp 2, set Layer->Transparency->Threshold alpha to 0). There's no partial transparency supported by the game. A pixel will either by fully transparent or fully opaque.
|
||||
|
||||
* If you use special glyphs that are not in the specified ASCII codepage (eg ñ, é, í, â don't appear in the Greek codepage), then in this image file you should use the actual special glyphs - put them at the position of the placeholder characters in your "all-characters" string that you've specified in the override encoding text file.
|
||||
|
||||
2. targetFONfilename: Example: "SUBTLS\_E.FON" for the subtitles.
|
||||
|
||||
3. minSpaceBetweenLettersInRowLeftToLeft: This is a length (positive integer) in pixels that indicates the __minimum__ distance between the left-most side of a glyph and the left-most side of the immediate subsequent glyph in the input image PNG (row of glyphs) file.
|
||||
|
||||
This basically tells the tool how far (in the x axis) it can search for pixels that belong to the same glyph). You can input an approximate value here and adjust it based on the output of the tool (the tool should be able to detect ALL the glyphs in the PNG row image file and it will report how many it detected in its output)
|
||||
|
||||
4. minSpaceBetweenLettersInColumnTopToTop: This is a positive integer in pixels that indicates the __minimum__ distance between the top-most pixel of a glyph and the top-most pixel of a glyph on another row of the input image file.
|
||||
|
||||
It is highly recommended, though, that the input image file should contain only a single row of glyphs and this value should be higher than the maximum height among the glyphs, typically this should be set to approximately double the maximum height of glyph.
|
||||
|
||||
5. kerningForFirstDummyFontGlyph: This is an integer that explicitly indicates the kerning, ie. offset in pixels (on the x-axis) of the first glyph (the one that is repeated twice). This can be measured by observing the indent that your image processing app adds when you enter the first glyph (typically it should be only a few pixels)
|
||||
|
||||
6. whiteSpaceWidthInPixels: This is a positive integer value that sets the width in pixels for the single white space between words for the subtitles in-game.
|
||||
|
||||
The "-pxYo" optional switch takes a yOffsetInPixels value: This is an integer value which sets a y-axis offset in pixels adjusting the y-axis positioning of the glyphs in-game. Typically, this is will be a small positive number, eg. "1", which would lower the glyphs on the y-axis by that amount of pixels.
|
||||
|
||||
The "--noAutoTabCalculation" optional switch forces the tool to more accurately set the start of each glyph, which can eliminate a x-offset of all the glyphs caused by the automatic tab calculation method.
|
||||
|
||||
The "--noSpecialGlyphs" optional switch explicitly indicates to the tool that there are no special (out of order) glyph cases.
|
||||
|
||||
The "--trace" optional switch enables extra debug messages to be printed.
|
||||
|
||||
A suggested method of creating decent looking PNG with the row of glyphs for your subtitles' font is the following:
|
||||
|
||||
1. Create the font row in __GIMP__
|
||||
* Start with a __new__ empty image, with transparent background. Choose a large enough canvas width (you can adjust it later)
|
||||
|
||||
* Paste as a new layer a tab separated alphanumeric sequence with all your glyphs (as specified above). Choose white as the font's color.
|
||||
|
||||
* Adjust your canvas' width and height to make sure all the glyphs are within its borders.
|
||||
|
||||
2. Add layers for shadows if necessary (recommended) by duplicating the original layer with the (white colored) glyphs to create layers that would be used for the shadow effect. Those layers should be __colorified__ as black and placed behind the original layer, displaced by one (1) pixel from eg. the top, right, left, and bottom (it's recommended to do this for all of those four).
|
||||
|
||||
3. __Merge all visible__ layers (maintaining an alpha channel for the background)
|
||||
|
||||
4. __Select all__ and __float the selection__, which should create a floating selection with all the letter glyphs.
|
||||
* __Promote that selection to a layer__ and __duplicate__ it.
|
||||
|
||||
5. Choose one of the duplicated layers and __COLORIFY__ it to pitch black.
|
||||
* __Set the transparency threshold__ of this black layer to 0.
|
||||
|
||||
6. Finally, place this completely black colored layer underneath the other one and __merge the visible__ layers.
|
||||
|
||||
7. Export your image to a PNG file.
|
||||
|
||||
This should get rid of semi-transparent pixels while maintaining the "aliasing" effect.
|
||||
There could be a better way but this should work ok.
|
||||
|
||||
## Credits and Special Thanks
|
||||
* All the developer guys from the ScummVM (<https://github.com/scummvm/scummvm>) team, and especially the ones involved in the implementation of the BladeRunner engine for ScummVM (madmoose, peterkohaut, sev and everyone else).
|
||||
|
||||
* The information provided in this blog (<http://westwoodbladerunner.blogspot.ca>) by Michael Liebscher.
|
||||
|
||||
* The creator of br-mixer (<https://github.com/bdamer/br-mixer>), Ben Damer, who also has a blog entry about the game resource file formats (<http://afqa123.com/2015/03/07/deciphering-blade-runner/>)
|
||||
75
devtools/create_bladerunner/subtitles/common/actornames.txt
Normal file
75
devtools/create_bladerunner/subtitles/common/actornames.txt
Normal file
@@ -0,0 +1,75 @@
|
||||
Id Short ActorDesc #skip first row
|
||||
0 MCCOY McCoy
|
||||
1 STEEL Steele
|
||||
2 GORDO Gordo
|
||||
3 DEKTO Dektora
|
||||
4 GUZZA Guzza
|
||||
5 CLOVI Clovis
|
||||
6 LLUCY Lucy
|
||||
7 IIIZO Izo
|
||||
8 SADIK Sadik
|
||||
9 CRAZY Crazylegs
|
||||
10 LUTHE Luther
|
||||
11 GRIGO Grigorian
|
||||
12 TRANS Transient
|
||||
13 LANCE Lance
|
||||
14 BBBOB Bullet Bob
|
||||
15 RUNCI Runciter
|
||||
16 INSEC Insect Dealer
|
||||
17 TGUAR Tyrell Guard
|
||||
18 EARLQ Early Q
|
||||
19 ZUBEN Zuben
|
||||
20 HASAN Hasan
|
||||
21 MARCU Marcus
|
||||
22 MMMIA Mia
|
||||
23 OLEAR Officer Leary
|
||||
24 OGRAY Officer Grayford
|
||||
25 HANOI Hanoi
|
||||
26 BAKER Baker
|
||||
27 DCLER Desk Clerk
|
||||
28 HOWIE Howie Lee
|
||||
29 FISHD Fish Dealer
|
||||
30 KLEIN Klein
|
||||
31 MURRA Murray
|
||||
32 HBARK Hawker's Barkeep
|
||||
33 HOLLO Holloway
|
||||
34 SWALL Sergeant Walls
|
||||
35 MORAJ Moraji
|
||||
36 TBARD The Bard
|
||||
37 PHOTG Photographer
|
||||
38 DISPA Dispatcher
|
||||
39 ANSWM Answering Machine
|
||||
40 RAJIF Rajif
|
||||
41 GKOLV Governor Kolvig
|
||||
42 ERLQB Early Q Bartender
|
||||
43 HPARR Hawker's Parrot
|
||||
44 TAFPA Taffy Patron
|
||||
45 LOCGU Lockup Guard
|
||||
46 TEENA Teenager
|
||||
47 HPATA Hysteria Patron A
|
||||
48 HPATB Hysteria Patron B
|
||||
49 HPATC Hysteria Patron C
|
||||
50 SHOES Shoeshine Man
|
||||
51 TYREL Tyrell
|
||||
52 CCHEW Chew
|
||||
53 GGAFF Gaff
|
||||
54 BRYAN Bryant
|
||||
55 TAFFY Taffy
|
||||
56 SEBAS Sebastian
|
||||
57 RACHA Rachael
|
||||
58 GDOLL General Doll
|
||||
59 ISABE Isabella
|
||||
60 BLIMP Blimp Guy
|
||||
61 NEWSC Newscaster
|
||||
62 LLEON Leon
|
||||
63 MALAN Male Announcer
|
||||
64 FREEA Free Slot A
|
||||
65 FREEB Free Slot B
|
||||
66 MAGGI Maggie
|
||||
67 ACTGA Actor Genwalker A
|
||||
68 ACTGB Actor Genwalker B
|
||||
69 ACTGC Actor Genwalker C
|
||||
70 MUTAA Mutant A
|
||||
71 MUTAB Mutant B
|
||||
72 MUTAC Mutant C
|
||||
99 MAINF Mainframe
|
||||
@@ -0,0 +1,54 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
|
||||
MY_MODULE_VERSION = "1.70"
|
||||
MY_MODULE_NAME = "extracTextResource"
|
||||
|
||||
# Template for EXTRA.TRE sheet's values ((row 2 and below)
|
||||
EXTRAC_TEXT_RESOURCE_TUPLE_LIST = [
|
||||
(0, "Thomas Fach-Pedersen", ""),
|
||||
(1, "Peter Kohaut", ""),
|
||||
(2, "Eugene Sandulenko", ""),
|
||||
(3, "Thanasis Antoniou", ""),
|
||||
(4, "Xavier Mohedano", ""),
|
||||
(5, "Víctor González Fraile", ""),
|
||||
(6, "Sergio Carmona", ""),
|
||||
(7, "Mark Benninghofen", ""),
|
||||
(8, "Frank Klepacki", ""),
|
||||
(9, "ScummVM", ""),
|
||||
(10, "Westwood Studios", ""),
|
||||
(11, "ix", ""),
|
||||
(12, "Jarrod O'Rafferty", ""),
|
||||
(13, "Sean Leong (JakeSteven1980)", ""),
|
||||
(14, ":...:", "REQUIRED")
|
||||
]
|
||||
#
|
||||
#
|
||||
#
|
||||
class extracTextResource:
|
||||
m_traceModeEnabled = True
|
||||
# traceModeEnabled is bool to enable more printed debug messages
|
||||
def __init__(self, traceModeEnabled = True):
|
||||
self.m_traceModeEnabled = traceModeEnabled
|
||||
return
|
||||
|
||||
def printExtracTemplate(self):
|
||||
for (idTre, textTre) in EXTRAC_TEXT_RESOURCE_TUPLE_LIST:
|
||||
print ("%s\t%s" % (idTre, textTre))
|
||||
return
|
||||
|
||||
def getExtracEntriesList(self):
|
||||
return EXTRAC_TEXT_RESOURCE_TUPLE_LIST
|
||||
|
||||
if __name__ == '__main__':
|
||||
# main()
|
||||
print ("[Debug] Running %s (%s) as main module" % (MY_MODULE_NAME, MY_MODULE_VERSION))
|
||||
traceModeEnabled = False
|
||||
excrTRInstance = extracTextResource(traceModeEnabled)
|
||||
excrTRInstance.printExtracTemplate()
|
||||
|
||||
else:
|
||||
#debug
|
||||
#print ("[Debug] Running %s (%s) imported from another module" % (MY_MODULE_NAME, MY_MODULE_VERSION))
|
||||
pass
|
||||
45
devtools/create_bladerunner/subtitles/common/pythonCompat.py
Normal file
45
devtools/create_bladerunner/subtitles/common/pythonCompat.py
Normal file
@@ -0,0 +1,45 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import sys
|
||||
|
||||
def makeUnicode(inp, enc='utf-8'):
|
||||
if sys.version_info[0] <= 2:
|
||||
return unicode(inp, enc)
|
||||
else:
|
||||
return inp
|
||||
|
||||
def makeAscii(inp):
|
||||
if sys.version_info[0] <= 2:
|
||||
return inp
|
||||
else:
|
||||
return inp.encode('ascii')
|
||||
|
||||
def unicodeEncode(inp, enc):
|
||||
if sys.version_info[0] <= 2:
|
||||
return unicode.encode(inp, enc)
|
||||
else:
|
||||
return inp.encode(enc)
|
||||
|
||||
def encodedSplit(s, spl):
|
||||
if sys.version_info[0] <= 2:
|
||||
return s.split(spl)
|
||||
elif isinstance(spl, bytes):
|
||||
return s.split(spl)
|
||||
else:
|
||||
return s.split(spl.encode('ascii'))
|
||||
|
||||
def getUnicodeSym(s):
|
||||
if sys.version_info[0] <= 2:
|
||||
return unichr(ord(s))
|
||||
return s
|
||||
|
||||
def makeToBytes(s):
|
||||
if sys.version_info[0] <= 2:
|
||||
return [ord(i) for i in s]
|
||||
return bytes(i for i in s)
|
||||
|
||||
def openWithUTF8Encoding(filepath, mode):
|
||||
if sys.version_info[0] <= 2:
|
||||
return open(filepath, mode)
|
||||
return open(filepath, mode, encoding='utf-8')
|
||||
@@ -0,0 +1,48 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
|
||||
MY_MODULE_VERSION = "1.70"
|
||||
MY_MODULE_NAME = "subtlsVersTextResource"
|
||||
|
||||
# Template for SBTLVERS.TRE sheet's values ((row 2 and below)
|
||||
SBTLVERS_TEXT_RESOURCE_TUPLE_LIST = [
|
||||
(0, "ScummVM Team", "Credits"),
|
||||
(1, "10", "Version (an incremental number)"),
|
||||
(2, "##:##:## ##/##/####", "Placeholder – Date of compilation (HH:mm:ss dd/mm/yyyy)"),
|
||||
(3, "EFIGS", "Placeholder – Language mode"),
|
||||
(4, "Copyright (C) 2019-2026 ScummVM team", "Copyright"),
|
||||
(5, "", "Font type"),
|
||||
(6, "", "Font name"),
|
||||
(7, "", "License"),
|
||||
(8, "", "License link")
|
||||
]
|
||||
#
|
||||
#
|
||||
#
|
||||
class sbtlVersTextResource:
|
||||
m_traceModeEnabled = True
|
||||
# traceModeEnabled is bool to enable more printed debug messages
|
||||
def __init__(self, traceModeEnabled = True):
|
||||
self.m_traceModeEnabled = traceModeEnabled
|
||||
return
|
||||
|
||||
def printSbtlVersTemplate(self):
|
||||
for (idTre, textTre) in SBTLVERS_TEXT_RESOURCE_TUPLE_LIST:
|
||||
print ("%s\t%s" % (idTre, textTre))
|
||||
return
|
||||
|
||||
def getSbtlVersEntriesList(self):
|
||||
return SBTLVERS_TEXT_RESOURCE_TUPLE_LIST
|
||||
|
||||
if __name__ == '__main__':
|
||||
# main()
|
||||
print ("[Debug] Running %s (%s) as main module" % (MY_MODULE_NAME, MY_MODULE_VERSION))
|
||||
traceModeEnabled = False
|
||||
sbtlVersTRInstance = sbtlVersTextResource(traceModeEnabled)
|
||||
sbtlVersTRInstance.printSbtlVersTemplate()
|
||||
|
||||
else:
|
||||
#debug
|
||||
#print ("[Debug] Running %s (%s) imported from another module" % (MY_MODULE_NAME, MY_MODULE_VERSION))
|
||||
pass
|
||||
500
devtools/create_bladerunner/subtitles/common/vqasTextResource.py
Normal file
500
devtools/create_bladerunner/subtitles/common/vqasTextResource.py
Normal file
@@ -0,0 +1,500 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
|
||||
MY_MODULE_VERSION = "1.70"
|
||||
MY_MODULE_NAME = "vqasTextResource"
|
||||
|
||||
# Timestamps and placeholder cells for all supported VQAs ((row 2 and below)
|
||||
WSTLGO_VQA_TEXT_RESOURCE_TUPLE_LIST = [
|
||||
(204, 260, " ", "00:00:13.66", "00:00:17.34", "Text")
|
||||
]
|
||||
##
|
||||
BRLOGO_VQA_TEXT_RESOURCE_TUPLE_LIST = [
|
||||
(0, 72, " ", "00:00:00.06", "00:00:04.81", "Text")
|
||||
]
|
||||
##
|
||||
INTRO_VQA_TEXT_RESOURCE_TUPLE_LIST = [
|
||||
(16, 55, " ", "00:00:01.10", "00:00:03.68", "Text"),
|
||||
(55, 95, " ", "00:00:03.68", "00:00:06.34", "Text"),
|
||||
(95, 145, " ", "00:00:06.34", "00:00:09.68", "Text"),
|
||||
(145, 206, " ", "00:00:09.68", "00:00:13.76", "Text"),
|
||||
(206, 255, " ", "00:00:13.76", "00:00:17.06", "Text"),
|
||||
(255, 307, " ", "00:00:17.06", "00:00:20.48", "Text"),
|
||||
(307, 366, " ", "00:00:20.48", "00:00:24.40", "Text"),
|
||||
(366, 428, " ", "00:00:24.40", "00:00:28.54", "Text"),
|
||||
(428, 487, " ", "00:00:28.54", "00:00:32.48", "Text"),
|
||||
(487, 550, " ", "00:00:32.48", "00:00:36.72", "Text"),
|
||||
(550, 607, " ", "00:00:36.72", "00:00:40.48", "Text"),
|
||||
(607, 674, " ", "00:00:40.48", "00:00:44.96", "Text"),
|
||||
(674, 738, " ", "00:00:44.96", "00:00:49.22", "Text"),
|
||||
(752, 815, " ", "00:00:50.14", "00:00:54.34", "Text"),
|
||||
(1417, 1459, " ", "00:01:34.46", "00:01:37.28", "Lucy"),
|
||||
(1459, 1493, " ", "00:01:37.28", "00:01:39.56", "Runciter"),
|
||||
(1495, 1539, " ", "00:01:39.70", "00:01:42.64", "Lucy"),
|
||||
(1540, 1604, " ", "00:01:42.72", "00:01:46.96", "Lucy"),
|
||||
(1609, 1666, " ", "00:01:47.32", "00:01:51.06", "Runciter"),
|
||||
(1666, 1710, " ", "00:01:51.06", "00:01:54.02", "Runciter"),
|
||||
(1710, 1734, " ", "00:01:54.02", "00:01:55.64", "Lucy"),
|
||||
(1737, 1784, " ", "00:01:55.82", "00:01:58.94", "Runciter"),
|
||||
(1785, 1807, " ", "00:01:59.04", "00:02:00.46", "Lucy"),
|
||||
(1809, 1873, " ", "00:02:00.60", "00:02:04.88", "Runciter"),
|
||||
(1873, 1945, " ", "00:02:04.88", "00:02:09.66", "Runciter"),
|
||||
(1950, 1997, " ", "00:02:10.00", "00:02:13.14", "Runciter"),
|
||||
(2003, 2048, " ", "00:02:13.52", "00:02:16.56", "Runciter"),
|
||||
(2051, 2090, " ", "00:02:16.78", "00:02:19.34", "Runciter"),
|
||||
(2091, 2146, " ", "00:02:19.44", "00:02:23.10", "Clovis"),
|
||||
(2147, 2198, " ", "00:02:23.14", "00:02:26.52", "Runciter"),
|
||||
(2198, 2286, " ", "00:02:26.52", "00:02:32.44", "Runciter"),
|
||||
(2288, 2339, " ", "00:02:32.58", "00:02:35.98", "Clovis"),
|
||||
(2403, 2452, " ", "00:02:40.20", "00:02:43.48", "Clovis"),
|
||||
(2459, 2492, " ", "00:02:43.92", "00:02:46.14", "Runciter"),
|
||||
(2494, 2546, " ", "00:02:46.28", "00:02:49.72", "Clovis"),
|
||||
(2546, 2580, " ", "00:02:49.76", "00:02:52.04", "Clovis"),
|
||||
(2582, 2659, " ", "00:02:52.16", "00:02:57.30", "Runciter"),
|
||||
(2733, 2808, " ", "00:03:02.20", "00:03:07.24", "Clovis"),
|
||||
(2810, 2873, " ", "00:03:07.38", "00:03:11.54", "Runciter"),
|
||||
(2881, 2959, " ", "00:03:12.06", "00:03:17.26", "Clovis"),
|
||||
(2968, 3048, " ", "00:03:17.90", "00:03:23.18", "Dispatch"),
|
||||
(3049, 3106, " ", "00:03:23.30", "00:03:27.08", "McCoy (internal monologue)"),
|
||||
(3106, 3147, " ", "00:03:27.08", "00:03:29.84", "McCoy (internal monologue)"),
|
||||
(3147, 3184, " ", "00:03:29.84", "00:03:32.28", "McCoy (internal monologue)"),
|
||||
(3184, 3243, " ", "00:03:32.28", "00:03:36.24", "McCoy (internal monologue)"),
|
||||
(3480, 3554, " ", "00:03:52.02", "00:03:56.96", "Dispatch"),
|
||||
(3558, 3606, " ", "00:03:57.24", "00:04:00.38", "McCoy (internal monologue)"),
|
||||
(3606, 3676, " ", "00:04:00.38", "00:04:05.08", "McCoy (internal monologue)"),
|
||||
(3697, 3767, " ", "00:04:06.46", "00:04:11.12", "McCoy (internal monologue)"),
|
||||
(3767, 3812, " ", "00:04:11.12", "00:04:14.12", "McCoy, Guzza"),
|
||||
(3812, 3855, " ", "00:04:14.12", "00:04:16.98", "Guzza"),
|
||||
(3855, 3915, " ", "00:04:16.98", "00:04:21.04", "Guzza"),
|
||||
(3918, 3972, " ", "00:04:21.24", "00:04:24.84", "McCoy (internal monologue)"),
|
||||
(3974, 4001, " ", "00:04:24.92", "00:04:26.76", "McCoy (internal monologue)"),
|
||||
(4001, 4040, " ", "00:04:26.76", "00:04:29.34", "McCoy (internal monologue)"),
|
||||
(4042, 4078, " ", "00:04:29.44", "00:04:31.84", "Guzza"),
|
||||
(4078, 4123, " ", "00:04:31.84", "00:04:34.86", "Guzza"),
|
||||
(4127, 4161, " ", "00:04:35.14", "00:04:37.42", "McCoy, Guzza"),
|
||||
(4161, 4195, " ", "00:04:37.42", "00:04:39.70", "Guzza"),
|
||||
(4195, 4256, " ", "00:04:39.70", "00:04:43.76", "Guzza"),
|
||||
(4256, 4291, " ", "00:04:43.76", "00:04:46.08", "Guzza"),
|
||||
(4291, 4325, " ", "00:04:46.08", "00:04:48.34", "Guzza"),
|
||||
(4327, 4375, " ", "00:04:48.48", "00:04:51.70", "McCoy"),
|
||||
(4384, 4427, " ", "00:04:52.24", "00:04:55.14", "Guzza"),
|
||||
(4427, 4482, " ", "00:04:55.14", "00:04:58.82", "Guzza"),
|
||||
(4482, 4531, " ", "00:04:58.82", "00:05:02.04", "Guzza"),
|
||||
(4533, 4571, " ", "00:05:02.22", "00:05:04.74", "McCoy"),
|
||||
(4573, 4642, " ", "00:05:04.84", "00:05:09.50", "Guzza"),
|
||||
(4715, 4758, " ", "00:05:14.32", "00:05:17.22", "Steele"),
|
||||
(4762, 4799, " ", "00:05:17.50", "00:05:19.94", "McCoy"),
|
||||
(4801, 4846, " ", "00:05:20.08", "00:05:23.04", "Steele"),
|
||||
(4847, 4858, " ", "00:05:23.14", "00:05:23.84", "McCoy"),
|
||||
(4859, 4913, " ", "00:05:23.94", "00:05:27.54", "Steele"),
|
||||
(4913, 4950, " ", "00:05:27.54", "00:05:29.98", "Steele"),
|
||||
(4950, 4979, " ", "00:05:29.98", "00:05:31.96", "McCoy"),
|
||||
(4979, 5038, " ", "00:05:31.96", "00:05:35.88", "Steele"),
|
||||
(5038, 5068, " ", "00:05:35.88", "00:05:37.86", "Steele"),
|
||||
(5068, 5113, " ", "00:05:37.86", "00:05:40.84", "Steele"),
|
||||
(5114, 5135, " ", "00:05:40.94", "00:05:42.30", "McCoy"),
|
||||
(5135, 5181, " ", "00:05:42.34", "00:05:45.42", "Steele, McCoy"),
|
||||
(5183, 5224, " ", "00:05:45.50", "00:05:48.24", "Steele"),
|
||||
(5224, 5251, " ", "00:05:48.24", "00:05:50.04", "Steele"),
|
||||
(5251, 5281, " ", "00:05:50.04", "00:05:52.06", "Steele"),
|
||||
(5281, 5315, " ", "00:05:52.06", "00:05:54.34", "Steele"),
|
||||
(5315, 5357, " ", "00:05:54.34", "00:05:57.14", "Steele"),
|
||||
(5359, 5415, " ", "00:05:57.26", "00:06:01.00", "Steele, McCoy"),
|
||||
(5415, 5458, " ", "00:06:01.00", "00:06:03.84", "Steele"),
|
||||
(5465, 5494, " ", "00:06:04.30", "00:06:06.26", "Steele"),
|
||||
(5494, 5540, " ", "00:06:06.26", "00:06:09.36", "McCoy"),
|
||||
(5550, 5588, " ", "00:06:10.00", "00:06:12.56", "Steele")
|
||||
]
|
||||
##
|
||||
MW_A_VQA_TEXT_RESOURCE_TUPLE_LIST = [
|
||||
(42, 98, " ", "00:00:02.86", "00:00:06.56", "Sadik, Eisenduller"),
|
||||
(98, 180, " ", "00:00:06.56", "00:00:12.00", "Sadik, Eisenduller"),
|
||||
(249, 294, " ", "00:00:16.62", "00:00:19.66", "Sadik"),
|
||||
(294, 366, " ", "00:00:19.66", "00:00:24.42", "Eisenduller"),
|
||||
(366, 392, " ", "00:00:24.42", "00:00:26.14", "Eisenduller"),
|
||||
(401, 463, " ", "00:00:26.76", "00:00:30.90", "Eisenduller"),
|
||||
(514, 564, " ", "00:00:34.28", "00:00:37.62", "Sadik"),
|
||||
(564, 623, " ", "00:00:37.62", "00:00:41.56", "Eisenduller"),
|
||||
(623, 658, " ", "00:00:41.56", "00:00:43.92", "Eisenduller"),
|
||||
(665, 737, " ", "00:00:44.34", "00:00:49.18", "Sadik, Eisenduller"),
|
||||
(737, 804, " ", "00:00:49.18", "00:00:53.64", "Eisenduller"),
|
||||
(804, 861, " ", "00:00:53.64", "00:00:57.42", "Sadik, Eisenduller"),
|
||||
(861, 889, " ", "00:00:57.42", "00:00:59.30", "Eisenduller"),
|
||||
(889, 962, " ", "00:00:59.32", "00:01:04.18", "Sadik"),
|
||||
(962, 1003, " ", "00:01:04.18", "00:01:06.90", "Eisenduller"),
|
||||
(1008, 1064, " ", "00:01:07.20", "00:01:10.94", "Sadik"),
|
||||
(1065, 1115, " ", "00:01:11.02", "00:01:14.34", "Sadik"),
|
||||
(1115, 1160, " ", "00:01:14.34", "00:01:17.38", "Sadik"),
|
||||
(1163, 1192, " ", "00:01:17.58", "00:01:19.48", "Eisenduller"),
|
||||
(1196, 1252, " ", "00:01:19.74", "00:01:23.46", "Eisenduller"),
|
||||
(1311, 1372, " ", "00:01:27.42", "00:01:31.50", "Sadik"),
|
||||
(1372, 1447, " ", "00:01:31.50", "00:01:36.50", "Sadik"),
|
||||
(1447, 1513, " ", "00:01:36.50", "00:01:40.90", "Eisenduller"),
|
||||
(1513, 1561, " ", "00:01:40.90", "00:01:44.08", "Sadik"),
|
||||
(1561, 1624, " ", "00:01:44.08", "00:01:48.28", "Eisenduller, Sadik"),
|
||||
(1624, 1674, " ", "00:01:48.28", "00:01:51.60", "Eisenduller"),
|
||||
(1674, 1725, " ", "00:01:51.60", "00:01:55.00", "Eisenduller"),
|
||||
(1725, 1747, " ", "00:01:55.00", "00:01:56.52", "Sadik"),
|
||||
(1747, 1837, " ", "00:01:56.52", "00:02:02.46", "Eisenduller"),
|
||||
(1861, 1963, " ", "00:02:04.06", "00:02:10.92", "Sadik, Eisenduller")
|
||||
]
|
||||
##
|
||||
MW_B01_VQA_TEXT_RESOURCE_TUPLE_LIST = [
|
||||
(64, 110, " ", "00:00:04.00", "00:00:07.35", "Sadik, Clovis")
|
||||
]
|
||||
##
|
||||
MW_B02_VQA_TEXT_RESOURCE_TUPLE_LIST = [
|
||||
(13, 98, " ", "00:00:01", "00:00:06.55", "Sadik"),
|
||||
(100, 153, " ", "00:00:07", "00:00:10.25", "Clovis"),
|
||||
(155, 239, " ", "00:00:10", "00:00:15.95", "Sadik")
|
||||
]
|
||||
##
|
||||
MW_B03_VQA_TEXT_RESOURCE_TUPLE_LIST = [
|
||||
(1, 75, " ", "00:00:00", "00:00:05.00", "Sadik"),
|
||||
(76, 124, " ", "00:00:05", "00:00:08.30", "Clovis"),
|
||||
(127, 165, " ", "00:00:08", "00:00:11.04", "Sadik")
|
||||
]
|
||||
##
|
||||
MW_B04_VQA_TEXT_RESOURCE_TUPLE_LIST = [
|
||||
(1, 75, " ", "00:00:00", "00:00:05.05", "Sadik"),
|
||||
(78, 145, " ", "00:00:05", "00:00:09.67", "Clovis"),
|
||||
(145, 221, " ", "00:00:10", "00:00:14.75", "Clovis"),
|
||||
(223, 269, " ", "00:00:15", "00:00:17.99", "Sadik")
|
||||
]
|
||||
##
|
||||
MW_B05_VQA_TEXT_RESOURCE_TUPLE_LIST = [
|
||||
(8, 38, " ", "00:00:01", "00:00:02.54", "Clovis"),
|
||||
(39, 81, " ", "00:00:03", "00:00:05.44", "Sadik"),
|
||||
(83, 135, " ", "00:00:06", "00:00:09.02", "Clovis"),
|
||||
(135, 167, " ", "00:00:09", "00:00:11.14", "Sadik"),
|
||||
(168, 237, " ", "00:00:11", "00:00:15.84", "Clovis"),
|
||||
(241, 285, " ", "00:00:16", "00:00:19.04", "Sadik"),
|
||||
(287, 345, " ", "00:00:19", "00:00:23.02", "Clovis"),
|
||||
(345, 414, " ", "00:00:23", "00:00:27.60", "Clovis"),
|
||||
(610, 648, " ", "00:00:41", "00:00:43.22", "Lucy"),
|
||||
(802, 836, " ", "00:00:53", "00:00:55.74", "McCoy"),
|
||||
(838, 912, " ", "00:00:56", "00:01:00.80", "Lucy, McCoy"),
|
||||
(912, 954, " ", "00:01:01", "00:01:03.64", "McCoy"),
|
||||
(956, 1035, " ", "00:01:04", "00:01:09.00", "Lucy"),
|
||||
(1035, 1098, " ", "00:01:09", "00:01:13.24", "Lucy"),
|
||||
(1101, 1128, " ", "00:01:13", "00:01:15.24", "McCoy"),
|
||||
(1130, 1221, " ", "00:01:15", "00:01:21.44", "Lucy"),
|
||||
(1223, 1271, " ", "00:01:22", "00:01:24.74", "McCoy"),
|
||||
(1278, 1329, " ", "00:01:25", "00:01:28.64", "Lucy"),
|
||||
(1332, 1365, " ", "00:01:29", "00:01:31.04", "McCoy, Lucy"),
|
||||
(1365, 1392, " ", "00:01:31", "00:01:32.82", "Lucy"),
|
||||
(1392, 1428, " ", "00:01:33", "00:01:35.24", "McCoy"),
|
||||
(1431, 1475, " ", "00:01:35", "00:01:38.34", "Lucy"),
|
||||
(1476, 1528, " ", "00:01:38", "00:01:41.92", "McCoy"),
|
||||
(1566, 1604, " ", "00:01:44", "00:01:46.98", "Lucy")
|
||||
]
|
||||
##
|
||||
INTRGT_VQA_TEXT_RESOURCE_TUPLE_LIST = [
|
||||
(130, 192, " ", "00:00:09", "00:00:12.85", "Mainframe"),
|
||||
(192, 248, " ", "00:00:13", "00:00:16.55", "Mainframe"),
|
||||
(248, 272, " ", "00:00:17", "00:00:18.19", "Mainframe"),
|
||||
(272, 324, " ", "00:00:18", "00:00:21.65", "Mainframe"),
|
||||
(324, 357, " ", "00:00:22", "00:00:23.85", "Mainframe"),
|
||||
(359, 397, " ", "00:00:24", "00:00:26.49", "Baker"),
|
||||
(397, 468, " ", "00:00:26", "00:00:31.25", "Baker"),
|
||||
(470, 512, " ", "00:00:31", "00:00:34.15", "McCoy"),
|
||||
(514, 551, " ", "00:00:34", "00:00:36.75", "Baker"),
|
||||
(553, 603, " ", "00:00:37", "00:00:40.25", "McCoy"),
|
||||
(606, 631, " ", "00:00:40", "00:00:42.11", "Baker"),
|
||||
(631, 684, " ", "00:00:42", "00:00:45.65", "Baker"),
|
||||
(686, 704, " ", "00:00:46", "00:00:46.95", "Holloway"),
|
||||
(706, 743, " ", "00:00:47", "00:00:49.55", "McCoy"),
|
||||
(744, 819, " ", "00:00:50", "00:00:54.61", "Baker"),
|
||||
(835, 869, " ", "00:00:56", "00:00:57.95", "McCoy"),
|
||||
(871, 916, " ", "00:00:58", "00:01:01.11", "Baker"),
|
||||
(918, 957, " ", "00:01:01", "00:01:03.85", "McCoy"),
|
||||
(960, 1042, " ", "00:01:04", "00:01:09.49", "Baker"),
|
||||
(1042, 1081, " ", "00:01:09", "00:01:12.11", "Baker"),
|
||||
(1081, 1108, " ", "00:01:12", "00:01:13.89", "Baker"),
|
||||
(1108, 1148, " ", "00:01:14", "00:01:16.55", "Baker"),
|
||||
(1149, 1191, " ", "00:01:17", "00:01:19.43", "McCoy"),
|
||||
(1192, 1233, " ", "00:01:19", "00:01:22.23", "Holloway"),
|
||||
(1233, 1276, " ", "00:01:22", "00:01:25.09", "Baker"),
|
||||
(1276, 1343, " ", "00:01:25", "00:01:29.55", "Baker"),
|
||||
(1343, 1385, " ", "00:01:30", "00:01:32.35", "Baker"),
|
||||
(1385, 1432, " ", "00:01:32", "00:01:35.47", "Baker"),
|
||||
(1432, 1465, " ", "00:01:35", "00:01:37.71", "Baker"),
|
||||
(1465, 1500, " ", "00:01:38", "00:01:40.05", "Baker"),
|
||||
(1503, 1554, " ", "00:01:40", "00:01:43.65", "McCoy"),
|
||||
(1557, 1638, " ", "00:01:44", "00:01:49.23", "Baker"),
|
||||
(1638, 1680, " ", "00:01:49", "00:01:52.05", "Baker"),
|
||||
(1680, 1727, " ", "00:01:52", "00:01:55.13", "Baker"),
|
||||
(1739, 1807, " ", "00:01:56", "00:02:00.49", "Baker"),
|
||||
(1807, 1836, " ", "00:02:00", "00:02:02.43", "Baker"),
|
||||
(1836, 1914, " ", "00:02:02", "00:02:07.63", "Baker"),
|
||||
(2003, 2060, " ", "00:02:14", "00:02:17.33", "Steele"),
|
||||
(2189, 2223, " ", "00:02:26", "00:02:28.25", "McCoy"),
|
||||
(2226, 2244, " ", "00:02:28", "00:02:29.61", "Steele"),
|
||||
(2244, 2302, " ", "00:02:30", "00:02:33.49", "Steele")
|
||||
]
|
||||
##
|
||||
MW_C01_VQA_TEXT_RESOURCE_TUPLE_LIST = [
|
||||
(167, 201, " ", "00:00:11", "00:00:13.42", "Luther"),
|
||||
(201, 257, " ", "00:00:13", "00:00:17.18", "Lance"),
|
||||
(261, 316, " ", "00:00:17", "00:00:21.10", "Luther"),
|
||||
(338, 351, " ", "00:00:23", "00:00:23.40", "Lance"),
|
||||
(352, 364, " ", "00:00:24", "00:00:24.30", "Luther"),
|
||||
(366, 379, " ", "00:00:24", "00:00:25.30", "Lance"),
|
||||
(381, 402, " ", "00:00:25", "00:00:26.82", "Luther"),
|
||||
(427, 462, " ", "00:00:28", "00:00:30.84", "Answering Machine"),
|
||||
(478, 499, " ", "00:00:32", "00:00:33.30", "Lance"),
|
||||
(501, 547, " ", "00:00:33", "00:00:36.52", "Clovis"),
|
||||
(547, 582, " ", "00:00:37", "00:00:38.80", "Luther"),
|
||||
(583, 608, " ", "00:00:39", "00:00:40.56", "Clovis"),
|
||||
(617, 673, " ", "00:00:41", "00:00:44.90", "Lance"),
|
||||
(675, 709, " ", "00:00:45", "00:00:47.30", "Luther"),
|
||||
(709, 738, " ", "00:00:47", "00:00:49.26", "Luther"),
|
||||
(738, 762, " ", "00:00:49", "00:00:50.80", "Luther"),
|
||||
(764, 798, " ", "00:00:51", "00:00:53.22", "Lance"),
|
||||
(798, 846, " ", "00:00:53", "00:00:56.40", "Lance"),
|
||||
(903, 942, " ", "00:01:00", "00:01:02.86", "Sadik"),
|
||||
(942, 975, " ", "00:01:03", "00:01:05.04", "Lance, Luther"),
|
||||
(975, 1019, " ", "00:01:05", "00:01:07.98", "Lance, Luther"),
|
||||
(1074, 1098, " ", "00:01:12", "00:01:13.24", "Clovis"),
|
||||
(1098, 1132, " ", "00:01:13", "00:01:15.50", "Clovis"),
|
||||
(1134, 1178, " ", "00:01:16", "00:01:18.54", "Luther"),
|
||||
(1178, 1219, " ", "00:01:19", "00:01:21.30", "Luther"),
|
||||
(1222, 1256, " ", "00:01:22", "00:01:23.78", "Sadik"),
|
||||
(1258, 1277, " ", "00:01:24", "00:01:25.16", "Luther"),
|
||||
(1277, 1306, " ", "00:01:25", "00:01:27.08", "Lance"),
|
||||
(1397, 1462, " ", "00:01:33", "00:01:37.52", "Clovis"),
|
||||
(1496, 1523, " ", "00:01:40", "00:01:41.54", "Luther"),
|
||||
(1523, 1570, " ", "00:01:42", "00:01:44.72", "Luther"),
|
||||
(1570, 1583, " ", "00:01:45", "00:01:45.58", "Lance"),
|
||||
(1583, 1633, " ", "00:01:46", "00:01:48.90", "Luther"),
|
||||
(1635, 1677, " ", "00:01:49", "00:01:51.84", "Clovis"),
|
||||
(1677, 1693, " ", "00:01:52", "00:01:52.90", "Clovis"),
|
||||
(1695, 1743, " ", "00:01:53", "00:01:56.22", "Luther"),
|
||||
(1745, 1780, " ", "00:01:56", "00:01:58.70", "Clovis"),
|
||||
(1782, 1795, " ", "00:01:59", "00:01:59.68", "Lance"),
|
||||
(1795, 1822, " ", "00:02:00", "00:02:01.50", "Luther")
|
||||
]
|
||||
##
|
||||
MW_C02_VQA_TEXT_RESOURCE_TUPLE_LIST = [
|
||||
(1, 26, " ", "00:00:00", "00:00:01.80", "Clovis"),
|
||||
(26, 72, " ", "00:00:02", "00:00:04.84", "Clovis"),
|
||||
(81, 122, " ", "00:00:05", "00:00:08.14", "Clovis"),
|
||||
(122, 186, " ", "00:00:08", "00:00:12.44", "Clovis"),
|
||||
(210, 267, " ", "00:00:14", "00:00:17.84", "Luther, Lance"),
|
||||
(278, 330, " ", "00:00:19", "00:00:22.02", "Clovis")
|
||||
]
|
||||
##
|
||||
MW_C03_VQA_TEXT_RESOURCE_TUPLE_LIST = [
|
||||
(1, 26, " ", "00:00:00", "00:00:01.74", "Clovis"),
|
||||
(26, 72, " ", "00:00:02", "00:00:04.84", "Clovis"),
|
||||
(81, 122, " ", "00:00:05", "00:00:08.18", "Clovis"),
|
||||
(122, 186, " ", "00:00:08", "00:00:12.40", "Clovis"),
|
||||
(210, 267, " ", "00:00:14", "00:00:17.82", "Luther, Lance"),
|
||||
(278, 330, " ", "00:00:19", "00:00:22.01", "Clovis")
|
||||
]
|
||||
##
|
||||
MW_D_VQA_TEXT_RESOURCE_TUPLE_LIST = [
|
||||
(21, 91, " ", "00:00:01", "00:00:06.13", "Governor Kolvig"),
|
||||
(91, 149, " ", "00:00:06", "00:00:09.99", "Eldon Tyrell"),
|
||||
(149, 192, " ", "00:00:10", "00:00:12.83", "Eldon Tyrell"),
|
||||
(192, 254, " ", "00:00:13", "00:00:16.99", "Eldon Tyrell"),
|
||||
(254, 283, " ", "00:00:17", "00:00:18.91", "Eldon Tyrell"),
|
||||
(285, 329, " ", "00:00:19", "00:00:21.99", "Governor Kolvig"),
|
||||
(329, 401, " ", "00:00:22", "00:00:26.75", "Eldon Tyrell"),
|
||||
(401, 422, " ", "00:00:27", "00:00:28.15", "Eldon Tyrell"),
|
||||
(424, 469, " ", "00:00:28", "00:00:31.31", "Governor Kolvig"),
|
||||
(471, 512, " ", "00:00:31", "00:00:34.13", "Eldon Tyrell"),
|
||||
(512, 586, " ", "00:00:34", "00:00:39.11", "Eldon Tyrell"),
|
||||
(586, 669, " ", "00:00:39", "00:00:44.61", "Eldon Tyrell"),
|
||||
(669, 694, " ", "00:00:45", "00:00:46.31", "Eldon Tyrell"),
|
||||
(697, 763, " ", "00:00:46", "00:00:50.91", "Governor Kolvig"),
|
||||
(766, 817, " ", "00:00:51", "00:00:54.51", "Eldon Tyrell"),
|
||||
(817, 876, " ", "00:00:55", "00:00:58.41", "Eldon Tyrell"),
|
||||
(878, 918, " ", "00:00:59", "00:01:01.21", "Clovis"),
|
||||
(920, 945, " ", "00:01:01", "00:01:03.01", "Governor Kolvig"),
|
||||
(947, 1005, " ", "00:01:03", "00:01:07.01", "Eldon Tyrell"),
|
||||
(1005, 1041, " ", "00:01:07", "00:01:09.41", "Eldon Tyrell"),
|
||||
(1042, 1057, " ", "00:01:10", "00:01:10.51", "Clovis"),
|
||||
(1058, 1080, " ", "00:01:11", "00:01:12.03", "Governor Kolvig"),
|
||||
(1090, 1112, " ", "00:01:13", "00:01:14.19", "Clovis"),
|
||||
(1114, 1135, " ", "00:01:14", "00:01:15.71", "Governor Kolvig"),
|
||||
(1137, 1186, " ", "00:01:16", "00:01:19.11", "Clovis"),
|
||||
(1188, 1220, " ", "00:01:19", "00:01:21.39", "Governor Kolvig"),
|
||||
(1227, 1255, " ", "00:01:22", "00:01:23.71", "Eldon Tyrell"),
|
||||
(1257, 1300, " ", "00:01:24", "00:01:26.67", "Clovis"),
|
||||
(1300, 1327, " ", "00:01:27", "00:01:28.51", "Clovis"),
|
||||
(1330, 1378, " ", "00:01:29", "00:01:31.91", "Eldon Tyrell"),
|
||||
(1381, 1405, " ", "00:01:32", "00:01:33.71", "Clovis"),
|
||||
(1408, 1446, " ", "00:01:34", "00:01:36.41", "Eldon Tyrell"),
|
||||
(1446, 1525, " ", "00:01:36", "00:01:41.71", "Eldon Tyrell"),
|
||||
(1527, 1632, " ", "00:01:42", "00:01:48.79", "Clovis"),
|
||||
(1632, 1672, " ", "00:01:49", "00:01:51.51", "Clovis"),
|
||||
(1674, 1752, " ", "00:01:52", "00:01:56.81", "Eldon Tyrell"),
|
||||
(1758, 1807, " ", "00:01:57", "00:02:00.47", "Clovis"),
|
||||
(1807, 1870, " ", "00:02:00", "00:02:04.67", "Clovis"),
|
||||
(1984, 2052, " ", "00:02:12", "00:02:16.83", "Eldon Tyrell"),
|
||||
(2190, 2251, " ", "00:02:26", "00:02:30.11", "Eldon Tyrell"),
|
||||
(2254, 2301, " ", "00:02:30", "00:02:33.41", "Security Guard"),
|
||||
(2303, 2342, " ", "00:02:34", "00:02:36.17", "Eldon Tyrell"),
|
||||
(2342, 2387, " ", "00:02:36", "00:02:39.17", "Eldon Tyrell")
|
||||
]
|
||||
##
|
||||
END01A_VQA_TEXT_RESOURCE_TUPLE_LIST = [
|
||||
(30, 125, " ", "00:00:02", "00:00:08.37", "Mainframe"),
|
||||
(125, 223, " ", "00:00:08", "00:00:14.87", "Mainframe")
|
||||
]
|
||||
##
|
||||
END01B_VQA_TEXT_RESOURCE_TUPLE_LIST = [
|
||||
(22, 85, " ", "00:00:01", "00:00:05.72", "Mainframe"),
|
||||
(85, 172, " ", "00:00:06", "00:00:11.52", "Mainframe"),
|
||||
(172, 211, " ", "00:00:12", "00:00:14.08", "Mainframe"),
|
||||
(211, 253, " ", "00:00:14", "00:00:16.92", "Mainframe"),
|
||||
(253, 328, " ", "00:00:17", "00:00:21.90", "Mainframe"),
|
||||
(328, 394, " ", "00:00:22", "00:00:26.32", "Mainframe"),
|
||||
(394, 468, " ", "00:00:26", "00:00:31.26", "Mainframe")
|
||||
]
|
||||
##
|
||||
END01C_VQA_TEXT_RESOURCE_TUPLE_LIST = [
|
||||
(28, 89, " ", "00:00:02", "00:00:05.97", "Mainframe"),
|
||||
(89, 176, " ", "00:00:06", "00:00:11.79", "Mainframe"),
|
||||
(176, 232, " ", "00:00:12", "00:00:15.53", "Mainframe"),
|
||||
(232, 272, " ", "00:00:16", "00:00:18.19", "Mainframe"),
|
||||
(272, 332, " ", "00:00:18", "00:00:22.17", "Mainframe"),
|
||||
(332, 372, " ", "00:00:22", "00:00:24.85", "Mainframe"),
|
||||
(372, 456, " ", "00:00:25", "00:00:30.43", "Mainframe")
|
||||
]
|
||||
##
|
||||
END01D_VQA_TEXT_RESOURCE_TUPLE_LIST = [
|
||||
(30, 125, " ", "00:00:02", "00:00:08.35", "Mainframe"),
|
||||
(125, 222, " ", "00:00:08", "00:00:14.83", "Mainframe")
|
||||
]
|
||||
##
|
||||
END01E_VQA_TEXT_RESOURCE_TUPLE_LIST = [
|
||||
(21, 84, " ", "00:00:01", "00:00:05.64", "Mainframe"),
|
||||
(84, 171, " ", "00:00:06", "00:00:11.42", "Mainframe"),
|
||||
(171, 209, " ", "00:00:11", "00:00:13.94", "Mainframe"),
|
||||
(209, 252, " ", "00:00:14", "00:00:16.82", "Mainframe"),
|
||||
(252, 327, " ", "00:00:17", "00:00:21.84", "Mainframe"),
|
||||
(327, 394, " ", "00:00:22", "00:00:26.28", "Mainframe"),
|
||||
(394, 460, " ", "00:00:26", "00:00:30.70", "Mainframe")
|
||||
]
|
||||
##
|
||||
END01F_VQA_TEXT_RESOURCE_TUPLE_LIST = [
|
||||
(28, 92, " ", "00:00:02", "00:00:06.16", "Mainframe"),
|
||||
(92, 178, " ", "00:00:06", "00:00:11.90", "Mainframe"),
|
||||
(178, 233, " ", "00:00:12", "00:00:15.58", "Mainframe"),
|
||||
(233, 273, " ", "00:00:16", "00:00:18.22", "Mainframe"),
|
||||
(273, 333, " ", "00:00:18", "00:00:22.20", "Mainframe"),
|
||||
(333, 376, " ", "00:00:22", "00:00:25.08", "Mainframe"),
|
||||
(376, 465, " ", "00:00:25", "00:00:31.02", "Mainframe")
|
||||
]
|
||||
##
|
||||
END03_VQA_TEXT_RESOURCE_TUPLE_LIST = [
|
||||
(8, 53, " ", "00:00:01", "00:00:03.55", "Mainframe"),
|
||||
(53, 82, " ", "00:00:04", "00:00:05.51", "Mainframe"),
|
||||
(82, 124, " ", "00:00:06", "00:00:08.29", "Mainframe"),
|
||||
(124, 147, " ", "00:00:08", "00:00:09.85", "Mainframe"),
|
||||
(147, 176, " ", "00:00:10", "00:00:11.77", "Mainframe"),
|
||||
(176, 211, " ", "00:00:12", "00:00:14.11", "Mainframe"),
|
||||
(211, 242, " ", "00:00:14", "00:00:16.17", "Mainframe"),
|
||||
(242, 308, " ", "00:00:16", "00:00:20.55", "Mainframe"),
|
||||
(308, 396, " ", "00:00:21", "00:00:26.45", "Mainframe")
|
||||
]
|
||||
##
|
||||
END04A_VQA_TEXT_RESOURCE_TUPLE_LIST = [
|
||||
(6, 31, " ", "00:00:00", "00:00:02.13", "McCoy"),
|
||||
(40, 72, " ", "00:00:03", "00:00:04.81", "Clovis"),
|
||||
(72, 116, " ", "00:00:05", "00:00:07.79", "Clovis")
|
||||
]
|
||||
##
|
||||
END04B_VQA_TEXT_RESOURCE_TUPLE_LIST = [
|
||||
(28, 97, " ", "00:00:02", "00:00:06.48", "Lucy")
|
||||
]
|
||||
##
|
||||
END04C_VQA_TEXT_RESOURCE_TUPLE_LIST = [
|
||||
(27, 115, " ", "00:00:02", "00:00:07.68", "Dektora")
|
||||
]
|
||||
##
|
||||
END06_VQA_TEXT_RESOURCE_TUPLE_LIST = [
|
||||
(5, 30, " ", "00:00:00", "00:00:02.00", "Steele, McCoy"),
|
||||
(32, 75, " ", "00:00:02", "00:00:05.06", "Steele"),
|
||||
(76, 109, " ", "00:00:05", "00:00:07.30", "McCoy"),
|
||||
(111, 142, " ", "00:00:07", "00:00:09.50", "Steele"),
|
||||
(146, 174, " ", "00:00:10", "00:00:11.60", "McCoy"),
|
||||
(175, 226, " ", "00:00:12", "00:00:15.10", "Steele")
|
||||
]
|
||||
##
|
||||
TB_FLY_VQA_TEXT_RESOURCE_TUPLE_LIST = [
|
||||
(11, 50, " ", "00:00:01", "00:00:03.37", "Blimp Guy")
|
||||
]
|
||||
##
|
||||
##
|
||||
##
|
||||
ALL_VQA_TEXT_RESOURCES_LISTS = [
|
||||
("WSTLGO_", WSTLGO_VQA_TEXT_RESOURCE_TUPLE_LIST),
|
||||
("BRLOGO_", BRLOGO_VQA_TEXT_RESOURCE_TUPLE_LIST),
|
||||
("INTRO_", INTRO_VQA_TEXT_RESOURCE_TUPLE_LIST),
|
||||
("MW_A_", MW_A_VQA_TEXT_RESOURCE_TUPLE_LIST),
|
||||
("MW_B01_", MW_B01_VQA_TEXT_RESOURCE_TUPLE_LIST),
|
||||
("MW_B02_", MW_B02_VQA_TEXT_RESOURCE_TUPLE_LIST),
|
||||
("MW_B03_", MW_B03_VQA_TEXT_RESOURCE_TUPLE_LIST),
|
||||
("MW_B04_", MW_B04_VQA_TEXT_RESOURCE_TUPLE_LIST),
|
||||
("MW_B05_", MW_B05_VQA_TEXT_RESOURCE_TUPLE_LIST),
|
||||
("INTRGT_", INTRGT_VQA_TEXT_RESOURCE_TUPLE_LIST),
|
||||
("MW_C01_", MW_C01_VQA_TEXT_RESOURCE_TUPLE_LIST),
|
||||
("MW_C02_", MW_C02_VQA_TEXT_RESOURCE_TUPLE_LIST),
|
||||
("MW_C03_", MW_C03_VQA_TEXT_RESOURCE_TUPLE_LIST),
|
||||
("MW_D_", MW_D_VQA_TEXT_RESOURCE_TUPLE_LIST),
|
||||
("END01A_", END01A_VQA_TEXT_RESOURCE_TUPLE_LIST),
|
||||
("END01B_", END01B_VQA_TEXT_RESOURCE_TUPLE_LIST),
|
||||
("END01C_", END01C_VQA_TEXT_RESOURCE_TUPLE_LIST),
|
||||
("END01D_", END01D_VQA_TEXT_RESOURCE_TUPLE_LIST),
|
||||
("END01E_", END01E_VQA_TEXT_RESOURCE_TUPLE_LIST),
|
||||
("END01F_", END01F_VQA_TEXT_RESOURCE_TUPLE_LIST),
|
||||
("END03_", END03_VQA_TEXT_RESOURCE_TUPLE_LIST),
|
||||
("END04A_", END04A_VQA_TEXT_RESOURCE_TUPLE_LIST),
|
||||
("END04B_", END04B_VQA_TEXT_RESOURCE_TUPLE_LIST),
|
||||
("END04C_", END04C_VQA_TEXT_RESOURCE_TUPLE_LIST),
|
||||
("END06_", END06_VQA_TEXT_RESOURCE_TUPLE_LIST),
|
||||
("TB_FLY_", TB_FLY_VQA_TEXT_RESOURCE_TUPLE_LIST)
|
||||
]
|
||||
#
|
||||
#
|
||||
#
|
||||
class vqasTextResource(object):
|
||||
m_traceModeEnabled = True
|
||||
# traceModeEnabled is bool to enable more printed debug messages
|
||||
def __init__(self, traceModeEnabled = True):
|
||||
self.m_traceModeEnabled = traceModeEnabled
|
||||
return
|
||||
|
||||
def printAllVqasTextResource(self):
|
||||
if self.m_traceModeEnabled:
|
||||
print ("[Trace] printing all VQAs Text")
|
||||
for (vqaKeyStr, vqaTreList) in ALL_VQA_TEXT_RESOURCES_LISTS:
|
||||
print ("VQA prefix: %s" % (vqaKeyStr))
|
||||
for (startFrameTre, endFrameTre, textTre, timeStartTre, timeEndTre, byActorTre) in vqaTreList:
|
||||
print ("%s\t%s\t%s\t%s\t%s\t%s" % (startFrameTre, endFrameTre, textTre, timeStartTre, timeEndTre, byActorTre))
|
||||
return
|
||||
|
||||
def getVqaEntriesList(self, sVQASheetPrefix):
|
||||
if self.m_traceModeEnabled:
|
||||
print ("[Trace] getVqaEntriesList()")
|
||||
for (vqaKeyStr, vqaTreList) in ALL_VQA_TEXT_RESOURCES_LISTS:
|
||||
if (vqaKeyStr == sVQASheetPrefix.upper()):
|
||||
return vqaTreList
|
||||
return None
|
||||
#
|
||||
#
|
||||
#
|
||||
if __name__ == '__main__':
|
||||
# main()
|
||||
print ("[Debug] Running %s (%s) as main module" % (MY_MODULE_NAME, MY_MODULE_VERSION))
|
||||
traceModeEnabled = False
|
||||
vqaTRInstance = vqasTextResource(traceModeEnabled)
|
||||
vqaTRInstance.printAllVqasTextResource()
|
||||
else:
|
||||
#debug
|
||||
#print ("[Debug] Running %s (%s) imported from another module" % (MY_MODULE_NAME, MY_MODULE_VERSION))
|
||||
pass
|
||||
297
devtools/create_bladerunner/subtitles/fontCreator/fonFileLib.py
Normal file
297
devtools/create_bladerunner/subtitles/fontCreator/fonFileLib.py
Normal file
@@ -0,0 +1,297 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
osLibFound = False
|
||||
sysLibFound = False
|
||||
shutilLibFound = False
|
||||
structLibFound = False
|
||||
imagePilLibFound = 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 struct
|
||||
except ImportError:
|
||||
print ("[Error] struct python library is required to be installed!")
|
||||
else:
|
||||
structLibFound = True
|
||||
|
||||
try:
|
||||
from PIL import Image
|
||||
except ImportError:
|
||||
print ("[Error] Image python library (PIL) is required to be installed!")
|
||||
else:
|
||||
imagePilLibFound = True
|
||||
|
||||
if (not osLibFound) \
|
||||
or (not sysLibFound) \
|
||||
or (not structLibFound) \
|
||||
or (not imagePilLibFound):
|
||||
sys.stdout.write("[Error] Errors were found when trying to import required python libraries\n")
|
||||
sys.exit(1)
|
||||
|
||||
from struct import *
|
||||
|
||||
MY_MODULE_VERSION = "0.90"
|
||||
MY_MODULE_NAME = "fonFileLib"
|
||||
|
||||
class FonHeader(object):
|
||||
maxEntriesInTableOfDetails = -1 # this is probably always the number of entries in table of details, but it won't work for the corrupted TAHOMA18.FON file
|
||||
maxGlyphWidth = -1 # in pixels
|
||||
maxGlyphHeight = -1 # in pixels
|
||||
graphicSegmentByteSize = -1 # Graphic segment byte size
|
||||
|
||||
def __init__(self):
|
||||
return
|
||||
|
||||
|
||||
class fonFile(object):
|
||||
m_header = FonHeader()
|
||||
|
||||
simpleFontFileName = 'GENERIC.FON'
|
||||
realNumOfCharactersInImageSegment = 0 # this is used for the workaround for the corrupted TAHOME18.FON
|
||||
nonEmptyCharacters = 0
|
||||
|
||||
glyphDetailEntriesLst = [] # list of 5-value tuples. Tuple values are (X-offset, Y-offset, Width, Height, Offset in Graphics segment)
|
||||
glyphPixelData = None # buffer of pixel data for glyphs
|
||||
|
||||
m_traceModeEnabled = False
|
||||
|
||||
# traceModeEnabled is bool to enable more printed debug messages
|
||||
def __init__(self, traceModeEnabled = True):
|
||||
del self.glyphDetailEntriesLst[:]
|
||||
self.glyphPixelData = None # buffer of pixel data for glyphs
|
||||
self.simpleFontFileName = 'GENERIC.FON'
|
||||
self.realNumOfCharactersInImageSegment = 0 # this is used for the workaround for the corrupted TAHOME18.FON
|
||||
self.nonEmptyCharacters = 0
|
||||
self.m_traceModeEnabled = traceModeEnabled
|
||||
|
||||
return
|
||||
|
||||
def loadFonFile(self, fonBytesBuff, maxLength, fonFileName):
|
||||
self.simpleFontFileName = fonFileName
|
||||
|
||||
offsInFonFile = 0
|
||||
localLstOfDataOffsets = []
|
||||
del localLstOfDataOffsets[:]
|
||||
#
|
||||
# parse FON file fields for header
|
||||
#
|
||||
try:
|
||||
tmpTuple = struct.unpack_from('I', fonBytesBuff, offsInFonFile) # unsigned integer 4 bytes
|
||||
self.header().maxEntriesInTableOfDetails = tmpTuple[0]
|
||||
offsInFonFile += 4
|
||||
|
||||
if self.simpleFontFileName == 'TAHOMA18.FON': # deal with corrupted original 'TAHOMA18.FON' file
|
||||
self.realNumOfCharactersInImageSegment = 176
|
||||
if self.m_traceModeEnabled:
|
||||
print ("[Debug] SPECIAL CASE. WORKAROUND FOR CORRUPTED %s FILE. Only %d characters supported!" % (self.simpleFontFileName, self.realNumOfCharactersInImageSegment))
|
||||
else:
|
||||
self.realNumOfCharactersInImageSegment = self.header().maxEntriesInTableOfDetails
|
||||
|
||||
tmpTuple = struct.unpack_from('I', fonBytesBuff, offsInFonFile) # unsigned integer 4 bytes
|
||||
self.header().maxGlyphWidth = tmpTuple[0]
|
||||
offsInFonFile += 4
|
||||
|
||||
tmpTuple = struct.unpack_from('I', fonBytesBuff, offsInFonFile) # unsigned integer 4 bytes
|
||||
self.header().maxGlyphHeight = tmpTuple[0]
|
||||
offsInFonFile += 4
|
||||
|
||||
tmpTuple = struct.unpack_from('I', fonBytesBuff, offsInFonFile) # unsigned integer 4 bytes
|
||||
self.header().graphicSegmentByteSize = tmpTuple[0]
|
||||
offsInFonFile += 4
|
||||
|
||||
if self.m_traceModeEnabled:
|
||||
print ("[Debug] Font file (FON) Header Info: ")
|
||||
print ("[Debug] Number of entries: %d, Glyph max-Width: %d, Glyph max-Height: %d, Graphic Segment size: %d" % (self.header().maxEntriesInTableOfDetails, self.header().maxGlyphWidth, self.header().maxGlyphHeight, self.header().graphicSegmentByteSize))
|
||||
#
|
||||
# Glyph details table (each entry is 5 unsigned integers == 5*4 = 20 bytes)
|
||||
# For most characters, their ASCII value + 1 is the index of their glyph's entry in the details table. The 0 entry of this table is reserved
|
||||
#
|
||||
#tmpXOffset, tmpYOffset, tmpWidth, tmpHeight, tmpDataOffset
|
||||
if self.m_traceModeEnabled:
|
||||
print ("[Debug] Font file (FON) glyph details table: ")
|
||||
for idx in range(0, self.realNumOfCharactersInImageSegment):
|
||||
tmpTuple = struct.unpack_from('i', fonBytesBuff, offsInFonFile) # unsigned integer 4 bytes
|
||||
tmpXOffset = tmpTuple[0]
|
||||
offsInFonFile += 4
|
||||
|
||||
tmpTuple = struct.unpack_from('I', fonBytesBuff, offsInFonFile) # unsigned integer 4 bytes
|
||||
tmpYOffset = tmpTuple[0]
|
||||
offsInFonFile += 4
|
||||
|
||||
tmpTuple = struct.unpack_from('I', fonBytesBuff, offsInFonFile) # unsigned integer 4 bytes
|
||||
tmpWidth = tmpTuple[0]
|
||||
offsInFonFile += 4
|
||||
|
||||
tmpTuple = struct.unpack_from('I', fonBytesBuff, offsInFonFile) # unsigned integer 4 bytes
|
||||
tmpHeight = tmpTuple[0]
|
||||
offsInFonFile += 4
|
||||
|
||||
tmpTuple = struct.unpack_from('I', fonBytesBuff, offsInFonFile) # unsigned integer 4 bytes
|
||||
tmpDataOffset = tmpTuple[0]
|
||||
offsInFonFile += 4
|
||||
|
||||
if tmpWidth == 0 or tmpHeight == 0:
|
||||
if self.m_traceModeEnabled:
|
||||
print ("Index: %d\t UNUSED *****************************************************************" % (idx))
|
||||
else:
|
||||
self.nonEmptyCharacters += 1
|
||||
if self.m_traceModeEnabled:
|
||||
print ("Index: %d\txOffs: %d\tyOffs: %d\twidth: %d\theight: %d\tdataOffs: %d" % (idx, tmpXOffset, tmpYOffset, tmpWidth, tmpHeight, tmpDataOffset))
|
||||
if tmpDataOffset not in localLstOfDataOffsets:
|
||||
localLstOfDataOffsets.append(tmpDataOffset)
|
||||
else:
|
||||
# This never happens in the original files. Offsets are "re-used" but not really because it happens only for empty (height = 0) characters which all seem to point to the next non-empty character
|
||||
if self.m_traceModeEnabled:
|
||||
print ("Index: %d\t RE-USING ANOTHER GLYPH *****************************************************************" % (idx))
|
||||
|
||||
self.glyphDetailEntriesLst.append( ( tmpXOffset, tmpYOffset, tmpWidth, tmpHeight, tmpDataOffset) )
|
||||
|
||||
offsInFonFile = (4 * 4) + (self.header().maxEntriesInTableOfDetails * 5 * 4) # we need the total self.header().maxEntriesInTableOfDetails here and not self.realNumOfCharactersInImageSegment
|
||||
self.glyphPixelData = fonBytesBuff[offsInFonFile:]
|
||||
return True
|
||||
except:
|
||||
print ("[Error] Loading Font file (FON) %s failed!" % (self.simpleFontFileName))
|
||||
raise
|
||||
return False
|
||||
|
||||
def outputFonToPNG(self):
|
||||
print ("[Info] Exporting font file (FON) to PNG: %s" % (self.simpleFontFileName + ".PNG"))
|
||||
|
||||
targWidth = 0
|
||||
targHeight = 0
|
||||
paddingFromTopY = 2
|
||||
paddingBetweenGlyphsX = 10
|
||||
|
||||
if len(self.glyphDetailEntriesLst) == 0 or (len(self.glyphDetailEntriesLst) != self.realNumOfCharactersInImageSegment and len(self.glyphDetailEntriesLst) != self.header().maxEntriesInTableOfDetails) :
|
||||
print ("[Error] Font file (FON) loading process did not complete correctly. Missing important data in structures. Cannot output image!")
|
||||
return
|
||||
|
||||
# TODO asdf refine this code here. the dimensions calculation is very crude for now
|
||||
if self.header().maxGlyphWidth > 0 :
|
||||
targWidth = (self.header().maxGlyphWidth + paddingBetweenGlyphsX) * (self.realNumOfCharactersInImageSegment + 1)
|
||||
else:
|
||||
targWidth = 1080
|
||||
|
||||
# TODO asdf refine this code here. the dimensions calculation is very crude for now
|
||||
if self.header().maxGlyphHeight > 0 :
|
||||
targHeight = self.header().maxGlyphHeight * 2
|
||||
else:
|
||||
targHeight = 480
|
||||
|
||||
imTargetGameFont = Image.new("RGBA",(targWidth, targHeight), (0,0,0,0))
|
||||
#print (imTargetGameFont.getbands())
|
||||
#
|
||||
# Now fill in the image segment
|
||||
# Fonts in image segment are stored in pixel colors from TOP to Bottom, Left to Right per GLYPH.
|
||||
# Each pixel is 16 bit (2 bytes). Highest bit seems to determine transparency (on/off flag).
|
||||
# There seem to be 5 bits per RGB channel and the value is the corresponding 8bit value (from the 24 bit pixel color) shifting out (right) the 3 LSBs
|
||||
# First font image is the special character (border of top row and left column) - color of font pixels should be "0x7FFF" for filled and "0x8000" for transparent
|
||||
drawIdx = 0
|
||||
drawIdxDeductAmount = 0
|
||||
for idx in range(0, self.realNumOfCharactersInImageSegment):
|
||||
# TODO check for size > 0 for self.glyphPixelData
|
||||
# TODO mark glyph OUTLINES? (optional by switch)
|
||||
(glyphXoffs, glyphYoffs, glyphWidth, glyphHeight, glyphDataOffs) = self.glyphDetailEntriesLst[idx]
|
||||
glyphDataOffs = glyphDataOffs * 2
|
||||
#print (idx, glyphDataOffs)
|
||||
currX = 0
|
||||
currY = 0
|
||||
if (glyphWidth == 0 or glyphHeight == 0):
|
||||
drawIdxDeductAmount += 1
|
||||
drawIdx = idx - drawIdxDeductAmount
|
||||
|
||||
for colorIdx in range(0, glyphWidth*glyphHeight):
|
||||
tmpTuple = struct.unpack_from('H', self.glyphPixelData, glyphDataOffs) # unsigned short 2 bytes
|
||||
pixelColor = tmpTuple[0]
|
||||
glyphDataOffs += 2
|
||||
|
||||
# if pixelColor > 0x8000:
|
||||
# print ("[Debug] WEIRD CASE" # NEVER HAPPENS - TRANSPARENCY IS ON/OFF. There's no grades of transparency)
|
||||
rgbacolour = (0,0,0,0)
|
||||
if pixelColor == 0x8000:
|
||||
rgbacolour = (0,0,0,0) # alpha: 0.0 fully transparent
|
||||
else:
|
||||
tmp8bitR1 = ( (pixelColor >> 10) ) << 3
|
||||
tmp8bitG1 = ( (pixelColor & 0x3ff) >> 5 ) << 3
|
||||
tmp8bitB1 = ( (pixelColor & 0x1f) ) << 3
|
||||
rgbacolour = (tmp8bitR1,tmp8bitG1,tmp8bitB1, 255) # alpha: 1.0 fully opaque
|
||||
#rgbacolour = (255,255,255, 255) # alpha: 1.0 fully opaque
|
||||
|
||||
if currX == glyphWidth:
|
||||
currX = 0
|
||||
currY += 1
|
||||
|
||||
imTargetGameFont.putpixel(( (drawIdx + 1) * (self.header().maxGlyphWidth + paddingBetweenGlyphsX ) + currX, paddingFromTopY + glyphYoffs + currY), rgbacolour)
|
||||
currX += 1
|
||||
try:
|
||||
imTargetGameFont.save(os.path.join(u'.', self.simpleFontFileName + ".PNG"), "PNG")
|
||||
except Exception as e:
|
||||
print ("[Error] Unable to write to output PNG file. " + str(e))
|
||||
|
||||
def header(self):
|
||||
return self.m_header
|
||||
#
|
||||
#
|
||||
#
|
||||
if __name__ == '__main__':
|
||||
# main()
|
||||
errorFound = False
|
||||
# By default assumes a file of name SUBTLS_E.FON in same directory
|
||||
# otherwise tries to use the first command line argument as input file
|
||||
# 'TAHOMA24.FON' # USED IN CREDIT END-TITLES and SCORERS BOARD AT POLICE STATION
|
||||
# 'TAHOMA18.FON' # USED IN CREDIT END-TITLES
|
||||
# '10PT.FON' # BLADE RUNNER UNUSED FONT - Probably font for reporting system errors
|
||||
# 'KIA6PT.FON' # BLADE RUNNER MAIN FONT
|
||||
# 'SUBTLS_E.FON' # OUR EXTRA FONT USED FOR SUBTITLES
|
||||
inFONFile = None
|
||||
inFONFileName = 'SUBTLS_E.FON' # Subtitles font custom
|
||||
|
||||
if len(sys.argv[1:]) > 0 \
|
||||
and os.path.isfile(os.path.join(u'.', sys.argv[1])) \
|
||||
and len(sys.argv[1]) >= 5 \
|
||||
and sys.argv[1][-3:].upper() == 'FON':
|
||||
inFONFileName = sys.argv[1]
|
||||
print ("[Info] Attempting to use %s as input FON file..." % (inFONFileName))
|
||||
elif os.path.isfile(os.path.join(u'.', inFONFileName)):
|
||||
print ("[Info] Using default %s as input FON file..." % (inFONFileName))
|
||||
else:
|
||||
print ("[Error] No valid input file argument was specified and default input file %s is missing." % (inFONFileName))
|
||||
errorFound = True
|
||||
|
||||
if not errorFound:
|
||||
try:
|
||||
print ("[Info] Opening %s" % (inFONFileName))
|
||||
inFONFile = open(os.path.join(u'.', inFONFileName), 'rb')
|
||||
except:
|
||||
errorFound = True
|
||||
print ("[Error] Unexpected event:", sys.exc_info()[0])
|
||||
raise
|
||||
if not errorFound:
|
||||
allOfFonFileInBuffer = inFONFile.read()
|
||||
fonFileInstance = fonFile(True)
|
||||
if fonFileInstance.m_traceModeEnabled:
|
||||
print ("[Debug] Running %s (%s) as main module" % (MY_MODULE_NAME, MY_MODULE_VERSION))
|
||||
if (fonFileInstance.loadFonFile(allOfFonFileInBuffer, len(allOfFonFileInBuffer), inFONFileName)):
|
||||
print ("[Info] Font file (FON) was loaded successfully!")
|
||||
fonFileInstance.outputFonToPNG()
|
||||
else:
|
||||
print ("[Error] Error while loading Font file (FON)!")
|
||||
inFONFile.close()
|
||||
else:
|
||||
#debug
|
||||
#print ("[Debug] Running %s (%s) imported from another module" % (MY_MODULE_NAME, MY_MODULE_VERSION))
|
||||
pass
|
||||
@@ -0,0 +1,17 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
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)
|
||||
|
||||
import grabberFromPNG17BR
|
||||
if __name__ == "__main__":
|
||||
grabberFromPNG17BR.main(sys.argv[0:])
|
||||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
After Width: | Height: | Size: 1.5 KiB |
@@ -0,0 +1 @@
|
||||
python2.7 fontCreator.py -ip /d/Westwood/BladeRunnerENG
|
||||
@@ -0,0 +1 @@
|
||||
python2.7 fontCreator.py -im ./samples/KIA6PT.FON-Ext012TranspZeroThresh0002.png -oe ./samples/overrideEncodingKIA6PT.txt -om KIA6PT.FON -pxLL 14 -pxTT 15 -pxKn 1 -pxWS 4 -pxYo 1 --noAutoTabCalculation -ld EN_ANY --trace
|
||||
@@ -0,0 +1 @@
|
||||
python2.7 fontCreator.py -im ./samples/Tahoma_18Shdw-G3NewMrgd.png -oe ./samples/overrideEncodingSUBLTS.txt -om SUBTLS_E.FON -pxLL 42 -pxTT 30 -pxKn 1 -pxWS 7 -ld EN_ANY --trace
|
||||
@@ -0,0 +1 @@
|
||||
python2.7 fontCreator.py -im ./samples/Tahoma_18ShdwSimpleN4TransOnBlack.png -oe ./samples/overrideEncodingTahoma18.txt -om TAHOMA18.FON -pxLL 42 -pxTT 30 -pxKn 1 -pxWS 5 -pxYo 3 -ld EN_ANY --trace
|
||||
@@ -0,0 +1 @@
|
||||
python2.7 fontCreator.py -im ./samples/Tahoma_24ShdwSimpleN3BlackMrgd.png -oe ./samples/overrideEncodingTahoma24.txt -om TAHOMA24.FON -pxLL 45 -pxTT 40 -pxKn 1 -pxWS 8 -pxYo 2 -ld EN_ANY --trace
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 27 KiB |
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 23 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 33 KiB |
@@ -0,0 +1 @@
|
||||
! ! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _ ` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~ … í Ά ñ â é Έ Ή Ί Ό Ύ Ώ ΐ Α Β Γ Δ Ε Ζ Η Θ Ι Κ Λ Μ Ν Ξ Ο Π Ρ Σ Τ Υ Φ Χ Ψ Ω Ϊ Ϋ ά έ ή ί ΰ α β γ δ ε ζ η θ ι κ λ μ ν ξ ο π ρ ς σ τ υ φ χ ψ ω ϊ ϋ ό ύ ώ
|
||||
@@ -0,0 +1,7 @@
|
||||
targetEncoding=windows-1253
|
||||
asciiCharList=!!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~–ƒΆΈΉΊΌΎΏΐΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩΪΫάέήίΰαβγδεζηθικλμνξοπρςστυφχψωϊϋόύώ
|
||||
explicitKerningList=!:1,;:1,`:1,{:1,|:1,}:1
|
||||
explicitWidthIncrement=i:0,j:1,l:1
|
||||
originalFontName=KIA6PT
|
||||
specialOutOfOrderGlyphsUTF8ToAsciiTargetEncoding=é:ƒ,ü:–
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
targetEncoding=windows-1252
|
||||
asciiCharList=!!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—™š›œžŸ¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþ
|
||||
explicitKerningList=Ì:1,Í:2,Î:1,Ï:1,ì:1,í:2,î:1,ï:1
|
||||
explicitWidthIncrement=1:2,Ì:1,Í:1
|
||||
originalFontName=SUBLTS
|
||||
specialOutOfOrderGlyphsUTF8ToAsciiTargetEncoding=ÿ:€
|
||||
@@ -0,0 +1,7 @@
|
||||
targetEncoding=windows-1253
|
||||
asciiCharList=!!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~–ƒΆΈΉΊΌΎΏΐΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩΪΫάέήίΰαβγδεζηθικλμνξοπρςστυφχψωϊϋόύώ
|
||||
explicitKerningList=i:-1
|
||||
explicitWidthIncrement=i:0,j:1,l:1
|
||||
originalFontName=TAHOMA
|
||||
specialOutOfOrderGlyphsUTF8ToAsciiTargetEncoding=é:ƒ,ü:–
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 26 KiB |
Binary file not shown.
@@ -0,0 +1,17 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
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)
|
||||
|
||||
import packBladeRunnerMIXFromPCTLKXLS04
|
||||
if __name__ == "__main__":
|
||||
packBladeRunnerMIXFromPCTLKXLS04.main(sys.argv[0:])
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,75 @@
|
||||
Id Short ActorDesc #skip first row
|
||||
0 MCCOY McCoy
|
||||
1 STEEL Steele
|
||||
2 GORDO Gordo
|
||||
3 DEKTO Dektora
|
||||
4 GUZZA Guzza
|
||||
5 CLOVI Clovis
|
||||
6 LLUCY Lucy
|
||||
7 IIIZO Izo
|
||||
8 SADIK Sadik
|
||||
9 CRAZY Crazylegs
|
||||
10 LUTHE Luther
|
||||
11 GRIGO Grigorian
|
||||
12 TRANS Transient
|
||||
13 LANCE Lance
|
||||
14 BBBOB Bullet Bob
|
||||
15 RUNCI Runciter
|
||||
16 INSEC Insect Dealer
|
||||
17 TGUAR Tyrell Guard
|
||||
18 EARLQ Early Q
|
||||
19 ZUBEN Zuben
|
||||
20 HASAN Hasan
|
||||
21 MARCU Marcus
|
||||
22 MMMIA Mia
|
||||
23 OLEAR Officer Leary
|
||||
24 OGRAY Officer Grayford
|
||||
25 HANOI Hanoi
|
||||
26 BAKER Baker
|
||||
27 DCLER Desk Clerk
|
||||
28 HOWIE Howie Lee
|
||||
29 FISHD Fish Dealer
|
||||
30 KLEIN Klein
|
||||
31 MURRA Murray
|
||||
32 HBARK Hawker's Barkeep
|
||||
33 HOLLO Holloway
|
||||
34 SWALL Sergeant Walls
|
||||
35 MORAJ Moraji
|
||||
36 TBARD The Bard
|
||||
37 PHOTG Photographer
|
||||
38 DISPA Dispatcher
|
||||
39 ANSWM Answering Machine
|
||||
40 RAJIF Rajif
|
||||
41 GKOLV Governor Kolvig
|
||||
42 ERLQB Early Q Bartender
|
||||
43 HPARR Hawker's Parrot
|
||||
44 TAFPA Taffy Patron
|
||||
45 LOCGU Lockup Guard
|
||||
46 TEENA Teenager
|
||||
47 HPATA Hysteria Patron A
|
||||
48 HPATB Hysteria Patron B
|
||||
49 HPATC Hysteria Patron C
|
||||
50 SHOES Shoeshine Man
|
||||
51 TYREL Tyrell
|
||||
52 CCHEW Chew
|
||||
53 GGAFF Gaff
|
||||
54 BRYAN Bryant
|
||||
55 TAFFY Taffy
|
||||
56 SEBAS Sebastian
|
||||
57 RACHA Rachael
|
||||
58 GDOLL General Doll
|
||||
59 ISABE Isabella
|
||||
60 BLIMP Blimp Guy
|
||||
61 NEWSC Newscaster
|
||||
62 LLEON Leon
|
||||
63 MALAN Male Announcer
|
||||
64 FREEA Free Slot A
|
||||
65 FREEB Free Slot B
|
||||
66 MAGGI Maggie
|
||||
67 ACTGA Actor Genwalker A
|
||||
68 ACTGB Actor Genwalker B
|
||||
69 ACTGC Actor Genwalker C
|
||||
70 MUTAA Mutant A
|
||||
71 MUTAB Mutant B
|
||||
72 MUTAC Mutant C
|
||||
99 MAINF Mainframe
|
||||
@@ -0,0 +1,4 @@
|
||||
fontNameAndOutOfOrderGlyphs=SUBTLS_E#windows-1253#í:Ά,ñ:¥,â:¦,é:§,Ά:£
|
||||
fontNameAndOutOfOrderGlyphs=KIA6PT#cp437#
|
||||
fontNameAndOutOfOrderGlyphs=TAHOMA#cp437#
|
||||
fontNameAndOutOfOrderGlyphs=SYSTEM#latin-1#
|
||||
@@ -0,0 +1,9 @@
|
||||
python2.7 mixResourceCreator.py -x ../sampleInput/englishTranscript.xls -ian ../common/actornames.txt -cft ../sampleInput/configureFontsTranslation.txt -ld EN_ANY --trace
|
||||
|
||||
python2.7 mixResourceCreator.py -x ../sampleInput/out-GermanFull.xls -ian ../common/actornames.txt -cft ../sampleInput/configureFontsTranslation.txt -ld DE_DEU
|
||||
|
||||
python2.7 mixResourceCreator.py -x ../sampleInput/out-FrenchFull.xls -ian ../common/actornames.txt -cft ../sampleInput/configureFontsTranslation.txt -ld FR_FRA
|
||||
|
||||
python2.7 mixResourceCreator.py -x ../sampleInput/out-ItalianFull.xls -ian ../common/actornames.txt -cft ../sampleInput/configureFontsTranslation.txt -ld IT_ITA
|
||||
|
||||
python2.7 mixResourceCreator.py -x ../sampleInput/out-SpanishFull.xls -ian ../common/actornames.txt -cft ../sampleInput/configureFontsTranslation.txt -ld ES_ESP
|
||||
59
devtools/create_bladerunner/subtitles/module.mk
Normal file
59
devtools/create_bladerunner/subtitles/module.mk
Normal file
@@ -0,0 +1,59 @@
|
||||
|
||||
MODULE := devtools/create_bladerunner/subtitles
|
||||
|
||||
# Set the name of the final output
|
||||
TOOL_OUTPUT := SUBTITLES.MIX
|
||||
FONT_OUTPUT := SUBTLS_E.FON
|
||||
|
||||
BLADERUNNER_SUBTITLES_SCRIPTS_ROOT_FOLDER := $(srcdir)/devtools/create_bladerunner/subtitles
|
||||
BLADERUNNER_SUBTITLES_SAMPLE_INPUT_FOLDER := $(srcdir)/devtools/create_bladerunner/subtitles/sampleInput
|
||||
INTERMEDIATE_RESOURCE_FILES_UI := OPTIONS.TR* DLGMENU.TR* SCORERS.TR* VK.TR* CLUES.TR* CRIMES.TR* ACTORS.TR* HELP.TR* EXTRA.TR* AUTOSAVE.TR* ERRORMSG.TR* SPINDEST.TR* KIA.TR* KIACRED.TR* CLUETYPE.TR* ENDCRED.TR* POGO.TR* SBTLVERS.TR*
|
||||
INTERMEDIATE_RESOURCE_FILES_SUBS := INGQUO_*.TR* WSTLGO_E.TR* BRLOGO_E.TR* INTRO_*.TR* MW_A_*.TR* MW_B01_*.TR* MW_B02_*.TR* MW_B03_*.TR* MW_B04_*.TR* MW_B05_*.TR* INTRGT_*.TR* MW_D_*.TR* MW_C01_*.TR* MW_C02_*.TR* MW_C03_*.TR* END04A_*.TR* END04B_*.TR* END04C_*.TR* END06_*.TR* END01A_*.TR* END01B_*.TR* END01C_*.TR* END01D_*.TR* END01E_*.TR* END01F_*.TR* END03_*.TR* TB_FLY_*.TR*
|
||||
INPUT_TRANSCRIPT_FILENAME := englishTranscript.xls
|
||||
INPUT_TRANSCRIPT_FILEPATH := $(BLADERUNNER_SUBTITLES_SAMPLE_INPUT_FOLDER)/$(INPUT_TRANSCRIPT_FILENAME)
|
||||
|
||||
ifeq (,$(wildcard $(INPUT_TRANSCRIPT_FILEPATH)))
|
||||
INPUT_TRANSCRIPT_FILENAME := englishTranscript.xlsx
|
||||
INPUT_TRANSCRIPT_FILEPATH := $(BLADERUNNER_SUBTITLES_SAMPLE_INPUT_FOLDER)/$(INPUT_TRANSCRIPT_FILENAME)
|
||||
endif
|
||||
|
||||
INPUT_TRANSCRIPT_AUX_CONF_FILENAME := configureFontsTranslation.txt
|
||||
INPUT_FONT_GLYPHS_PNG_FILENAME := subtitlesFont.png
|
||||
INPUT_FONT_GLYPHS_PNG_AUX_CONF_FILENAME := overrideEncodingSUBLTS.txt
|
||||
|
||||
$(MODULE): $(TOOL_OUTPUT)
|
||||
#
|
||||
# Font file creation from an input PNG image named $(INPUT_FONT_GLYPHS_PNG_FILENAME)
|
||||
# The $(INPUT_FONT_GLYPHS_PNG_AUX_CONF_FILENAME) is used to configure the font creation
|
||||
# also the command line switches pxLL, pxTT, pxKn, pxWS configure additional aspects for the font creation
|
||||
$(FONT_OUTPUT): $(BLADERUNNER_SUBTITLES_SAMPLE_INPUT_FOLDER)/$(INPUT_FONT_GLYPHS_PNG_FILENAME) $(BLADERUNNER_SUBTITLES_SAMPLE_INPUT_FOLDER)/$(INPUT_FONT_GLYPHS_PNG_AUX_CONF_FILENAME)
|
||||
$(info ---------)
|
||||
$(info Creating Blade Runner subtitles font $(FONT_OUTPUT)...)
|
||||
$(info This process assumes that the folder: )
|
||||
$(info $(BLADERUNNER_SUBTITLES_SAMPLE_INPUT_FOLDER))
|
||||
$(info contains: )
|
||||
$(info *. $(INPUT_FONT_GLYPHS_PNG_FILENAME) - a PNG (image) input file with the Font glyphs)
|
||||
$(info *. $(INPUT_FONT_GLYPHS_PNG_AUX_CONF_FILENAME) - a TXT (text) input file with configuration settings for the glyph image processing)
|
||||
$(info If successful, a $(FONT_OUTPUT) file will be created in your working directory)
|
||||
$(info This is an intermediate file. You don't need to copy this in your Blade Runner game directory)
|
||||
$(info ---------)
|
||||
$(BLADERUNNER_SUBTITLES_SCRIPTS_ROOT_FOLDER)/fontCreator/fontCreator.py -im $(BLADERUNNER_SUBTITLES_SAMPLE_INPUT_FOLDER)/$(INPUT_FONT_GLYPHS_PNG_FILENAME) -oe $(BLADERUNNER_SUBTITLES_SAMPLE_INPUT_FOLDER)/$(INPUT_FONT_GLYPHS_PNG_AUX_CONF_FILENAME) -om $(FONT_OUTPUT) -pxLL 42 -pxTT 30 -pxKn 1 -pxWS 7
|
||||
|
||||
# Creation of final output mix file SUBTILES.MIX
|
||||
# The MIX file will pack the fonts file $(FONT_OUTPUT) as well as resources created from the transcript (EXCEL) file $(INPUT_TRANSCRIPT_FILENAME)
|
||||
# The $(INPUT_TRANSCRIPT_AUX_CONF_FILENAME) file is used to configure the creation of the mix file
|
||||
# This command sequence will erase any intermediate resource files (.TR*) at the end.
|
||||
# The $(FONT_OUTPUT) file will not be erased.
|
||||
$(TOOL_OUTPUT): $(FONT_OUTPUT) $(INPUT_TRANSCRIPT_FILEPATH) $(BLADERUNNER_SUBTITLES_SAMPLE_INPUT_FOLDER)/$(INPUT_TRANSCRIPT_AUX_CONF_FILENAME) $(BLADERUNNER_SUBTITLES_SCRIPTS_ROOT_FOLDER)/common/actornames.txt
|
||||
$(info ---------)
|
||||
$(info Creating Blade Runner subtitles MIX file: $(TOOL_OUTPUT)...)
|
||||
$(info This process assumes that the folder: )
|
||||
$(info $(BLADERUNNER_SUBTITLES_SAMPLE_INPUT_FOLDER))
|
||||
$(info contains: )
|
||||
$(info *. $(INPUT_TRANSCRIPT_FILENAME) - an XLS(X) (Excel) input file with the transcript)
|
||||
$(info *. $(INPUT_TRANSCRIPT_AUX_CONF_FILENAME) - a TXT (text) input file with configuration settings for the transcript processing)
|
||||
$(info If successful, a $(TOOL_OUTPUT) file will be created in your working directory)
|
||||
$(info Please, copy this $(TOOL_OUTPUT) into your Blade Runner game directory!)
|
||||
$(info ---------)
|
||||
$(BLADERUNNER_SUBTITLES_SCRIPTS_ROOT_FOLDER)/mixResourceCreator/mixResourceCreator.py -x $(INPUT_TRANSCRIPT_FILEPATH) -ian $(BLADERUNNER_SUBTITLES_SCRIPTS_ROOT_FOLDER)/common/actornames.txt -cft $(BLADERUNNER_SUBTITLES_SAMPLE_INPUT_FOLDER)/$(INPUT_TRANSCRIPT_AUX_CONF_FILENAME) -ld EFIGS
|
||||
-$(RM) $(INTERMEDIATE_RESOURCE_FILES_UI) $(INTERMEDIATE_RESOURCE_FILES_SUBS)
|
||||
@@ -0,0 +1,227 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
ctypesLibFound = False
|
||||
structLibFound = False
|
||||
|
||||
try:
|
||||
import ctypes
|
||||
except ImportError:
|
||||
print ("[Error] ctypes python library is required to be installed!")
|
||||
else:
|
||||
ctypesLibFound = True
|
||||
|
||||
if (not ctypesLibFound):
|
||||
sys.stdout.write("[Error] Errors were found when trying to import required python libraries\n")
|
||||
sys.exit(1)
|
||||
|
||||
from struct import *
|
||||
|
||||
MY_MODULE_VERSION = "0.70"
|
||||
MY_MODULE_NAME = "audFileDecode"
|
||||
|
||||
aud_ima_index_adjust_table = [-1, -1, -1, -1, 2, 4, 6, 8]
|
||||
|
||||
# aud_ima_step_table has 89 entries
|
||||
aud_ima_step_table = [
|
||||
7, 8, 9, 10, 11, 12, 13, 14, 16,
|
||||
17, 19, 21, 23, 25, 28, 31, 34, 37,
|
||||
41, 45, 50, 55, 60, 66, 73, 80, 88,
|
||||
97, 107, 118, 130, 143, 157, 173, 190, 209,
|
||||
230, 253, 279, 307, 337, 371, 408, 449, 494,
|
||||
544, 598, 658, 724, 796, 876, 963, 1060, 1166,
|
||||
1282, 1411, 1552, 1707, 1878, 2066, 2272, 2499, 2749,
|
||||
3024, 3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484,
|
||||
7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899, 15289,
|
||||
16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767 ]
|
||||
|
||||
aud_ws_step_table2 = [-2, -1, 0, 1]
|
||||
|
||||
aud_ws_step_table4 = [
|
||||
-9, -8, -6, -5, -4, -3, -2, -1,
|
||||
0, 1, 2, 3, 4, 5, 6, 8
|
||||
]
|
||||
|
||||
# (const xccTHA::byte* audio_in, short* audio_out, int& index, int& sample, int cs_chunk)
|
||||
# index and sample are passed by reference and changed here...
|
||||
# audio_out is definitely affected!
|
||||
def aud_decode_ima_chunk(audioBufferIn, index, sample, cs_chunk):
|
||||
code = -1
|
||||
delta = -1
|
||||
step = -1
|
||||
|
||||
audioBufferOut = []
|
||||
#for i in range(0, len(audioBufferIn)):
|
||||
#if self.m_traceModeEnabled:
|
||||
# print ("[Debug] %d: %d" % (i, int(audioBufferIn[i])))
|
||||
|
||||
for sample_index in range (0, cs_chunk):
|
||||
try:
|
||||
code = audioBufferIn[sample_index >> 1]
|
||||
except:
|
||||
code = 0xa9 # dummy workaround because the c code is accessing an out of bounds index sometimes due to this shift here
|
||||
#print ("[Debug] cs_chunk: %d, sample_index: %d, shifted: %d, code: %d" % (cs_chunk, sample_index, sample_index >> 1, int(audioBufferIn[sample_index >> 1])))
|
||||
#print ("[Debug] cs_chunk: %s, sample_index: %s, shifted: %s, code: %s" % \
|
||||
# (''.join('{:04X}'.format(cs_chunk)), ''.join('{:02X}'.format(sample_index)), ''.join('{:02X}'.format(sample_index >> 1)), ''.join('{:04X}'.format(int(code)))))
|
||||
code = code >> 4 if (sample_index & 1) else code & 0xf
|
||||
step = aud_ima_step_table[index]
|
||||
delta = step >> 3
|
||||
if (code & 1):
|
||||
delta += step >> 2
|
||||
if (code & 2):
|
||||
delta += step >> 1
|
||||
if (code & 4):
|
||||
delta += step
|
||||
if (code & 8):
|
||||
sample -= delta
|
||||
if (sample < -32768):
|
||||
sample = -32768
|
||||
else:
|
||||
sample += delta
|
||||
if (sample > 32767):
|
||||
sample = 32767
|
||||
audioBufferOut.append(ctypes.c_short( sample ).value )
|
||||
#audioBufferOut.append(sample) # it's not different from above... ctypes.c_short( sample ).value
|
||||
#if self.m_traceModeEnabled:
|
||||
# print ("[Debug] audio_out[%s]: %s" % (''.join('{:02X}'.format(sample_index)), ''.join('{:02X}'.format(audioBufferOut[sample_index]))))
|
||||
index += aud_ima_index_adjust_table[code & 7]
|
||||
if (index < 0):
|
||||
index = 0
|
||||
elif (index > 88):
|
||||
index = 88
|
||||
## output buffer of shorts
|
||||
#binDataOut = struct.pack('h'*len(audioBufferOut), *audioBufferOut)
|
||||
#return (binDataOut, index, sample)
|
||||
return (audioBufferOut, index, sample)
|
||||
#
|
||||
#
|
||||
#
|
||||
def aud_decode_clip8(v):
|
||||
if (v < 0):
|
||||
return 0
|
||||
return 0xff if (v > 0xff) else v
|
||||
#
|
||||
#
|
||||
#
|
||||
|
||||
# (const xccTHA::byte* r, char* w, int cb_s, int cb_d)
|
||||
def aud_decode_ws_chunk(inputChunkBuffer, cb_s, cb_d):
|
||||
outputChunkBuffer = []
|
||||
inpChBuffIter = 0
|
||||
outChBuffIter = 0
|
||||
|
||||
if (cb_s == cb_d):
|
||||
# outputChunkBuffer = inputChunkBuffer[:cb_s] # memcpy(w, r, cb_s) # FIX
|
||||
for mcp in range(0, cb_s):
|
||||
outputChunkBuffer.append(ctypes.c_char(inputChunkBuffer[inpChBuffIter + mcp]).value)
|
||||
#binDataOut = struct.pack('b'*len(outputChunkBuffer), *outputChunkBuffer)
|
||||
#return binDataOut
|
||||
return outputChunkBuffer
|
||||
|
||||
# const xccTHA::byte* s_end = inputChunkBuffer + cb_s; # FIX
|
||||
|
||||
s_end = inpChBuffIter + cb_s
|
||||
sample = ctypes.c_int(0x80).value #int sample
|
||||
while (inpChBuffIter < s_end):
|
||||
inpChBuffIter += 1
|
||||
count = ctypes.c_char(inputChunkBuffer[inpChBuffIter] & 0x3f).value # char count
|
||||
switchKey = inputChunkBuffer[inpChBuffIter - 1] >> 6 # inputChunkBuffer[-1] # b[-1] is *(b - 1)
|
||||
if switchKey == 0:
|
||||
count += 1
|
||||
for iter0 in range (count, 0, -1):
|
||||
inpChBuffIter += 1
|
||||
code = ctypes.c_int(inputChunkBuffer[inpChBuffIter]).value # int code
|
||||
# assignment in C was right to left so:
|
||||
# *(outputChunkBuffer++) = sample = clip8(sample + aud_ws_step_table2[code & 3])
|
||||
# is:
|
||||
# *(outputChunkBuffer++) = (sample = clip8(sample + aud_ws_step_table2[code & 3]))
|
||||
# which is equivalent to these two commands:
|
||||
# sample = clip8(sample + aud_ws_step_table2[code & 3])
|
||||
# *(outputChunkBuffer++) = sample
|
||||
# SO:
|
||||
sample = aud_decode_clip8(sample + aud_ws_step_table2[code & 3])
|
||||
outputChunkBuffer.append(ctypes.c_char(sample).value)
|
||||
outChBuffIter += 1
|
||||
sample = aud_decode_clip8(sample + aud_ws_step_table2[code >> 2 & 3])
|
||||
outputChunkBuffer.append(ctypes.c_char(sample).value)
|
||||
outChBuffIter += 1
|
||||
sample = aud_decode_clip8(sample + aud_ws_step_table2[code >> 4 & 3])
|
||||
outputChunkBuffer.append(ctypes.c_char(sample).value)
|
||||
outChBuffIter += 1
|
||||
sample = aud_decode_clip8(sample + aud_ws_step_table2[code >> 6])
|
||||
outputChunkBuffer.append(ctypes.c_char(sample).value)
|
||||
outChBuffIter += 1
|
||||
elif switchKey == 1:
|
||||
count += 1
|
||||
for iter0 in range (count, 0, -1):
|
||||
inpChBuffIter += 1
|
||||
code = inputChunkBuffer[inpChBuffIter] # int code
|
||||
sample += aud_ws_step_table4[code & 0xf]
|
||||
sample = aud_decode_clip8(sample)
|
||||
outputChunkBuffer.append(ctypes.c_char(sample).value)
|
||||
outChBuffIter += 1
|
||||
sample += aud_ws_step_table4[code >> 4]
|
||||
sample = aud_decode_clip8(sample)
|
||||
outputChunkBuffer.append(ctypes.c_char(sample).value)
|
||||
outChBuffIter += 1
|
||||
elif switchKey == 2:
|
||||
if (count & 0x20):
|
||||
#sample += static_cast<char>(count << 3) >> 3
|
||||
#*(outputChunkBuffer++) = sample
|
||||
sample += ((count & 0xFF) << 3 ) >> 3
|
||||
outputChunkBuffer.append(ctypes.c_char(sample).value)
|
||||
outChBuffIter += 1
|
||||
else:
|
||||
count += 1
|
||||
# memcpy(outputChunkBuffer, inputChunkBuffer, count) # FIX
|
||||
for mcp in range(0, count):
|
||||
outputChunkBuffer.append(ctypes.c_char(inputChunkBuffer[inpChBuffIter + mcp]).value)
|
||||
inpChBuffIter += count
|
||||
outChBuffIter += count
|
||||
sample = inputChunkBuffer[inpChBuffIter - 1]
|
||||
else:
|
||||
count += 1
|
||||
# memset(outputChunkBuffer, sample, ++count)
|
||||
for mst in range(0, count):
|
||||
outputChunkBuffer.append(ctypes.c_char(sample).value)
|
||||
outChBuffIter += count;
|
||||
# output buffer of chars
|
||||
#binDataOut = struct.pack('b'*len(outputChunkBuffer), *outputChunkBuffer)
|
||||
#return binDataOut
|
||||
return outputChunkBuffer
|
||||
|
||||
#
|
||||
#
|
||||
#
|
||||
class audFileDecode(object):
|
||||
m_index = -1
|
||||
m_sample = -1
|
||||
m_traceModeEnabled = False
|
||||
|
||||
# traceModeEnabled is bool to enable more printed debug messages
|
||||
def __init__(self, traceModeEnabled = True, index = 0, sample = 0):
|
||||
self.m_traceModeEnabled = traceModeEnabled
|
||||
self.m_index = index;
|
||||
self.m_sample = sample;
|
||||
return
|
||||
|
||||
def index(self):
|
||||
return self.m_index
|
||||
|
||||
# (const xccTHA::byte* audio_in, short* audio_out, int cs_chunk)
|
||||
def decode_chunk(self, audio_in, cs_chunk):
|
||||
(audio_Out, outIndex, outSample) = aud_decode_ima_chunk(audio_in, self.m_index, self.m_sample, cs_chunk)
|
||||
self.m_index = outIndex
|
||||
self.m_sample = outSample
|
||||
return audio_Out
|
||||
|
||||
if __name__ == '__main__':
|
||||
# main()
|
||||
decodeInstance = audFileDecode()
|
||||
if decodeInstance.m_traceModeEnabled:
|
||||
print ("[Debug] Running %s (%s) as main module" % (MY_MODULE_NAME, MY_MODULE_VERSION))
|
||||
|
||||
else:
|
||||
#debug
|
||||
#print ("[Debug] Running %s (%s) imported from another module" % (MY_MODULE_NAME, MY_MODULE_VERSION))
|
||||
pass
|
||||
@@ -0,0 +1,413 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
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 wave
|
||||
except ImportError:
|
||||
print ("[Error] Wave python library is required to be installed!")
|
||||
else:
|
||||
waveLibFound = True
|
||||
|
||||
try:
|
||||
import struct
|
||||
except ImportError:
|
||||
print ("[Error] struct python library is required to be installed!")
|
||||
else:
|
||||
structLibFound = True
|
||||
|
||||
if (not osLibFound) \
|
||||
or (not sysLibFound) \
|
||||
or (not waveLibFound) \
|
||||
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.90"
|
||||
MY_MODULE_NAME = "audFileLib"
|
||||
|
||||
#constants
|
||||
aud_chunk_id = 0x0000deaf
|
||||
SIZE_OF_AUD_HEADER_IN_BYTES = 12
|
||||
SIZE_OF_AUD_CHUNK_HEADER_IN_BYTES = 8
|
||||
|
||||
class AudHeader(object):
|
||||
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
|
||||
|
||||
|
||||
# The rest of the AUD files is divided in chunks.
|
||||
# These are usually 512 bytes long, except for the last one.
|
||||
class AudChunkHeader(object):
|
||||
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
|
||||
|
||||
#
|
||||
#
|
||||
#
|
||||
class audFile(object):
|
||||
m_header = AudHeader()
|
||||
m_traceModeEnabled = False
|
||||
m_simpleAudioFileName = 'GENERIC.AUD'
|
||||
|
||||
# traceModeEnabled is bool to enable more printed debug messages
|
||||
def __init__(self, traceModeEnabled = True):
|
||||
self.m_simpleAudioFileName = 'GENERIC.AUD'
|
||||
self.m_traceModeEnabled = traceModeEnabled
|
||||
return
|
||||
|
||||
# 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):
|
||||
if (self.m_traceModeEnabled):
|
||||
print ("[Trace] Reading bytes %d, %d" % (2*i, 2*i + 1))
|
||||
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)
|
||||
|
||||
if (not cvirtualBinaryD and (len(audBytesBuff) - SIZE_OF_AUD_HEADER_IN_BYTES) > 0):
|
||||
print ("[Error] audio file could not be exported properly (0 data read): %s" % (filename))
|
||||
return 1
|
||||
elif (len(audBytesBuff) - SIZE_OF_AUD_HEADER_IN_BYTES) == 0:
|
||||
print ("[Warning] Creating empty wav file: %s" % (filename))
|
||||
|
||||
cb_sample = self.get_cb_sample()
|
||||
cs_remaining = self.get_c_samples()
|
||||
|
||||
waveWritFile = wave.open(filename, 'wb')
|
||||
waveWritFile.setnchannels(self.get_c_channels())
|
||||
waveWritFile.setsampwidth(cb_sample)
|
||||
waveWritFile.setframerate(self.get_samplerate())
|
||||
waveWritFile.setnframes(cs_remaining)
|
||||
#waveWritFile.setcomptype(None, '')
|
||||
waveWritFile.writeframesraw(cvirtualBinaryD)
|
||||
waveWritFile.close()
|
||||
# t_wav_header header;
|
||||
# memset(&header, 0, sizeof(t_wav_header));
|
||||
# header.file_header.id = wav_file_id; // # "RIFF"
|
||||
# header.file_header.size = sizeof(header) - sizeof(header.file_header) + (cs_remaining << 1);
|
||||
# header.form_type = wav_form_id; // # "WAVE"
|
||||
# header.format_chunk.header.id = wav_format_id; // #"fmt "
|
||||
# header.format_chunk.header.size = sizeof(header.format_chunk) - sizeof(header.format_chunk.header);
|
||||
# header.format_chunk.formattag = 1;
|
||||
# header.format_chunk.c_channels = 1;
|
||||
# header.format_chunk.samplerate = get_samplerate();
|
||||
# header.format_chunk.byterate = cb_sample * get_samplerate();
|
||||
# header.format_chunk.blockalign = cb_sample;
|
||||
# header.format_chunk.cbits_sample = cb_sample << 3;
|
||||
# header.data_chunk_header.id = wav_data_id; # "data"
|
||||
# header.data_chunk_header.size = cb_sample * cs_remaining;
|
||||
# error = f.write(&header, sizeof(t_wav_header));
|
||||
# return error ? error : f.write(d);
|
||||
return 0 # TODO fix
|
||||
|
||||
|
||||
def loadAudFile(self, audBytesBuff, maxLength, audFileName):
|
||||
self.m_simpleAudioFileName = audFileName
|
||||
offsInAudFile = 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().m_size_in = tmpTuple[0]
|
||||
offsInAudFile += 4
|
||||
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().m_flags = tmpTuple[0]
|
||||
offsInAudFile += 1
|
||||
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().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().m_size_in > (maxLength - SIZE_OF_AUD_HEADER_IN_BYTES ):
|
||||
print ("[Warning] Bad AUD Header info in file %s, size_in: %d, maxLen: %d" % (self.m_simpleAudioFileName, self.header().m_size_in, (maxLength - SIZE_OF_AUD_HEADER_IN_BYTES)))
|
||||
if self.header().m_size_in == 0:
|
||||
# handle special case where only the header of the AUD file is present and the size_in is 0.
|
||||
# fill the header with "valid" info for an empty wav file
|
||||
self.header().m_size_out = 0
|
||||
self.header().m_samplerate = 22050
|
||||
self.header().m_compression = 0
|
||||
self.header().m_flags = 2
|
||||
self.header().m_populated = True
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
else:
|
||||
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().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)
|
||||
def get_chunk_header(self, chunkIdx, inAudFileBytesBuffer, inAudFileSize):
|
||||
#fs.seekg(int(startAudFilepos) + int(SIZE_OF_AUD_HEADER_IN_BYTES), fs.beg);
|
||||
#AudFileNS::pos_type rAudPos;
|
||||
#rAudPos = fs.tellg();
|
||||
outAudChunkHeader = AudChunkHeader()
|
||||
rAudPos = SIZE_OF_AUD_HEADER_IN_BYTES
|
||||
|
||||
if (self.m_traceModeEnabled):
|
||||
print ("[Trace] Getting chunk header at %d" % (rAudPos))
|
||||
#AudChunkHeader tmpInremediateChunkheader;
|
||||
tmpInremediateChunkheader = AudChunkHeader()
|
||||
#while (i--) # value of i is decreased after checked by while loop
|
||||
while(chunkIdx > 0):
|
||||
chunkIdx -= 1
|
||||
if (rAudPos + SIZE_OF_AUD_CHUNK_HEADER_IN_BYTES > inAudFileSize):
|
||||
return (-1, rAudPos, None)
|
||||
|
||||
tmpAudFileOffset = rAudPos
|
||||
tmpTuple = struct.unpack_from('H', inAudFileBytesBuffer, tmpAudFileOffset)
|
||||
tmpInremediateChunkheader.m_ch_size_in = tmpTuple[0]
|
||||
tmpAudFileOffset += 2
|
||||
tmpTuple = struct.unpack_from('H', inAudFileBytesBuffer, tmpAudFileOffset)
|
||||
tmpInremediateChunkheader.m_ch_size_out = tmpTuple[0]
|
||||
tmpAudFileOffset += 2
|
||||
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.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.m_ch_size_in = tmpTuple[0]
|
||||
tmpAudFileOffset += 2
|
||||
tmpTuple = struct.unpack_from('H', inAudFileBytesBuffer, tmpAudFileOffset)
|
||||
outAudChunkHeader.m_ch_size_out = tmpTuple[0]
|
||||
tmpAudFileOffset += 2
|
||||
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.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);
|
||||
|
||||
# int AudFile::get_chunk_data(int i, std::fstream& fs, int sizeToRead, AudFileNS::byte* byteChunkDataPtr)
|
||||
def get_chunk_data(self, inAudFileBytesBuffer, startOffs, sizeToRead):
|
||||
#fs.read((char*)byteChunkDataPtr, sizeToRead)
|
||||
outChunkDataLst = []
|
||||
if (self.m_traceModeEnabled):
|
||||
print ("[Trace] Getting chunk data")
|
||||
print ("[Trace] startOffs: %d, sizeToRead: %d" % (startOffs, sizeToRead))
|
||||
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)
|
||||
outChunkDataLst.append(tmpTuple[0])
|
||||
#byteChunkDataOut = struct.pack('b'*len(outChunkDataLst), *outChunkDataLst)
|
||||
#return (0, byteChunkDataOut)
|
||||
return (0, outChunkDataLst)
|
||||
|
||||
|
||||
# std::fstream& fs, AudFileNS::pos_type startAudFilepos, AudFileNS::pos_type endAudFilepos
|
||||
# returned Cvirtual_binary
|
||||
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:
|
||||
print ("[Debug] Decoding AUD file format...")
|
||||
# Cvirtual_binary d;
|
||||
binaryDataOutLst = []
|
||||
binaryDataOutBuff = None
|
||||
cb_audio = self.get_cb_sample() * self.get_c_samples() # int cb_audio - basically this should be the size_out
|
||||
if speccompression == 1:
|
||||
# write_start allocates space for virtualBinary
|
||||
# AudFileNS::byte* w = d.write_start(cb_audio);
|
||||
errGetChunk = 0 # int errGetChunk
|
||||
#for (int chunk_i = 0; w != d.data_end(); chunk_i++)
|
||||
chunk_i = 0
|
||||
wIndex = 0
|
||||
while (wIndex < cb_audio):
|
||||
#AudChunkHeader out_chunk_header;
|
||||
#out_chunk_header = AudChunkHeader()
|
||||
(errGetChunk, bufferDataPos, out_chunk_header) = self.get_chunk_header(chunk_i, audBytesBuff, len(audBytesBuff))
|
||||
if errGetChunk != 0:
|
||||
if self.m_traceModeEnabled:
|
||||
print ("[Trace] Error OR End file case while getting uncompressed chunk header!")
|
||||
break
|
||||
|
||||
if self.m_traceModeEnabled:
|
||||
print ("[Trace] 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.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.m_ch_size_in, out_chunk_header.m_ch_size_out)
|
||||
binaryDataOutLst.extend(decodedAudioChunkAsLst)
|
||||
wIndex += out_chunk_header.m_ch_size_out
|
||||
chunk_i += 1
|
||||
binaryDataOutBuff = struct.pack('b'*len(binaryDataOutLst), *binaryDataOutLst)
|
||||
elif speccompression == 0x63:
|
||||
decodeInstance = audFileDecode(self.m_traceModeEnabled);
|
||||
#decodeInstance.init();
|
||||
#AudFileNS::byte* w = d.write_start(cb_audio);
|
||||
errGetChunk = 0 # int errGetChunk
|
||||
# for (int chunk_i = 0; w != d.data_end(); chunk_i++)
|
||||
chunk_i = 0
|
||||
wIndex = 0
|
||||
while (wIndex < cb_audio):
|
||||
if self.m_traceModeEnabled:
|
||||
print ("[Trace] chunkI: %d\t Windex: %d\t cb_audio: %d" % (chunk_i,wIndex,cb_audio))
|
||||
#AudChunkHeader out_chunk_header;
|
||||
#out_chunk_header = AudChunkHeader()
|
||||
#errGetChunk = self.get_chunk_header(chunk_i, fs, startAudFilepos, endAudFilepos, out_chunk_header);
|
||||
(errGetChunk, bufferDataPos, out_chunk_header) = self.get_chunk_header(chunk_i, audBytesBuff, len(audBytesBuff))
|
||||
if errGetChunk != 0:
|
||||
print ("[Warning] Error OR End file case while getting COMPRESSED chunk header!")
|
||||
break
|
||||
if self.m_traceModeEnabled:
|
||||
print ("[Trace] 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.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)
|
||||
if self.m_traceModeEnabled:
|
||||
print ("[Trace] byteChunkDataLst len: %d, m_ch_size_in was: %d" % (len(byteChunkDataLst), out_chunk_header.m_ch_size_in))
|
||||
# Use "//" for floor int division in decode_chunk(), since in python 3 just using "/" would result in float and that leads to error
|
||||
decodedAudioChunkAsLst = decodeInstance.decode_chunk(byteChunkDataLst, (out_chunk_header.m_ch_size_out // self.get_cb_sample()));
|
||||
binaryDataOutLst.extend(decodedAudioChunkAsLst)
|
||||
wIndex += out_chunk_header.m_ch_size_out
|
||||
if self.m_traceModeEnabled:
|
||||
print ("[Trace] New Windex: %d\t cb_audio: %d" % (wIndex,cb_audio))
|
||||
chunk_i += 1
|
||||
binaryDataOutBuff = struct.pack('h'*len(binaryDataOutLst), *binaryDataOutLst)
|
||||
if self.m_traceModeEnabled:
|
||||
if binaryDataOutBuff is not None:
|
||||
if self.m_traceModeEnabled:
|
||||
print ("[Trace] Decoding Done.")
|
||||
else: #if binaryDataOutBuff is None:
|
||||
print ("[Error] Decoding yielded errors (data out buffer is null).")
|
||||
return binaryDataOutBuff
|
||||
|
||||
def header(self):
|
||||
return self.m_header
|
||||
|
||||
def get_c_samples(self):
|
||||
# Use "//" for floor int division in return value, since in python 3 just using "/" would result in float and that leads to error
|
||||
return (self.m_header.m_size_out // self.get_cb_sample())
|
||||
|
||||
def get_samplerate(self):
|
||||
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.m_flags & 0x01) else 1;
|
||||
|
||||
# flag bit 1 is 16bit(set) 8bit (clear)
|
||||
def get_cb_sample(self):
|
||||
return 2 if (self.m_header.m_flags & 0x02) else 1
|
||||
#
|
||||
#
|
||||
#
|
||||
if __name__ == '__main__':
|
||||
# main()
|
||||
errorFound = False
|
||||
# By default assumes a file of name 000000.AUD in same directory
|
||||
# otherwise tries to use the first command line argument as input file
|
||||
inAUDFile = None
|
||||
inAUDFileName = '00000000.AUD'
|
||||
|
||||
if len(sys.argv[1:]) > 0 \
|
||||
and os.path.isfile(os.path.join(u'.', sys.argv[1])) \
|
||||
and len(sys.argv[1]) >= 5 \
|
||||
and sys.argv[1][-3:].upper() == 'AUD':
|
||||
inAUDFileName = sys.argv[1]
|
||||
print ("[Info] Attempting to use %s as input AUD file..." % (inAUDFileName))
|
||||
elif os.path.isfile(os.path.join(u'.', inAUDFileName)):
|
||||
print ("[Info] Using default %s as input AUD file..." % (inAUDFileName))
|
||||
else:
|
||||
print ("[Error] No valid input file argument was specified and default input file %s is missing." % (inAUDFileName))
|
||||
errorFound = True
|
||||
|
||||
if not errorFound:
|
||||
try:
|
||||
print ("[Info] Opening %s" % (inAUDFileName))
|
||||
inAUDFile = open(os.path.join(u'.', inAUDFileName), 'rb')
|
||||
except:
|
||||
errorFound = True
|
||||
print ("[Error] Unexpected event:", sys.exc_info()[0])
|
||||
raise
|
||||
if not errorFound:
|
||||
allOfAudFileInBuffer = inAUDFile.read()
|
||||
audFileInstance = audFile(True)
|
||||
if audFileInstance.m_traceModeEnabled:
|
||||
print ("[Debug] Running %s (%s) as main module" % (MY_MODULE_NAME, MY_MODULE_VERSION))
|
||||
if audFileInstance.loadAudFile(allOfAudFileInBuffer, len(allOfAudFileInBuffer), inAUDFileName):
|
||||
print ("[Info] Audio file (AUD) loaded successfully!")
|
||||
audFileInstance.export_as_wav(allOfAudFileInBuffer, './tmp.wav')
|
||||
else:
|
||||
print ("[Error] Error while loading Audio file (AUD)!")
|
||||
inAUDFile.close()
|
||||
else:
|
||||
#debug
|
||||
#print ("[Debug] Running %s (%s) imported from another module" % (MY_MODULE_NAME, MY_MODULE_VERSION))
|
||||
pass
|
||||
@@ -0,0 +1,104 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
|
||||
MY_MODULE_VERSION = "1.10"
|
||||
MY_MODULE_NAME = "devCommentaryText"
|
||||
|
||||
# All game versions should have the English text pre-filled in the POGO sheet
|
||||
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 = [
|
||||
("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.")
|
||||
]
|
||||
#
|
||||
#
|
||||
#
|
||||
class devCommentaryText(object):
|
||||
m_traceModeEnabled = True
|
||||
# traceModeEnabled is bool to enable more printed debug messages
|
||||
def __init__(self, traceModeEnabled = True):
|
||||
self.m_traceModeEnabled = traceModeEnabled
|
||||
return
|
||||
|
||||
def printTexts(self):
|
||||
if self.m_traceModeEnabled:
|
||||
print ("[Trace] Printing all dev commentary text")
|
||||
print ("\nAUDIO COMMENTARY")
|
||||
print ("------------------")
|
||||
for (idTre, textTre) in DEV_AUDIO_COMMENTARY_TUPLE_LIST:
|
||||
print ("%s\t%s" % (idTre, textTre))
|
||||
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):
|
||||
if self.m_traceModeEnabled:
|
||||
print ("[Trace] getAudioCommentaryTextEntriesList")
|
||||
return DEV_AUDIO_COMMENTARY_TUPLE_LIST
|
||||
|
||||
def getISEZTextEntriesList(self):
|
||||
|
||||
if self.m_traceModeEnabled:
|
||||
print ("[Trace] getISEZTextEntriesList")
|
||||
return DEV_ISEZ_QUOTES_TUPLE_LIST
|
||||
|
||||
def getExtraSpeechAudioEntriesList(self):
|
||||
if self.m_traceModeEnabled:
|
||||
print ("[Trace] getExtraSpeechAudioEntriesList")
|
||||
return EXTRA_SPEECH_AUDIO_TUPLE_LIST
|
||||
#
|
||||
#
|
||||
#
|
||||
if __name__ == '__main__':
|
||||
# main()
|
||||
print ("[Debug] Running %s (%s) as main module" % (MY_MODULE_NAME, MY_MODULE_VERSION))
|
||||
traceModeEnabled = False
|
||||
devCommentaryTextInstance = devCommentaryText(traceModeEnabled)
|
||||
devCommentaryTextInstance.printTexts()
|
||||
else:
|
||||
#debug
|
||||
#print ("[Debug] Running %s (%s) imported from another module" % (MY_MODULE_NAME, MY_MODULE_VERSION))
|
||||
pass
|
||||
@@ -0,0 +1,203 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
|
||||
MY_MODULE_VERSION = "1.10"
|
||||
MY_MODULE_NAME = "pogoTextResource"
|
||||
|
||||
# All game versions should have the English text pre-filled in the POGO sheet
|
||||
POGO_TEXT_RESOURCE_TUPLE_LIST = [
|
||||
(0, "Air Conditioning"),
|
||||
(1, "Amy Shoopman"),
|
||||
(2, "Andy B. and the Milk Carton Kids"),
|
||||
(3, "Area 51"),
|
||||
(4, "Aspirin"),
|
||||
(5, "Babylon 5"),
|
||||
(6, "Bandit"),
|
||||
(7, "Bauer Inline Skates"),
|
||||
(8, "Bill Randolph"),
|
||||
(9, "Bill (Mr. Motorola) and Sarah"),
|
||||
(10, "Boo Berry and Frankenberry"),
|
||||
(11, "Brett W. Sperry"),
|
||||
(12, "Brianhead Ski Resort"),
|
||||
(13, "Bubba"),
|
||||
(14, "Bubbles"),
|
||||
(15, "Building 2 Parking"),
|
||||
(16, "The Buke"),
|
||||
(17, "Chan \"The Emporer\" Lee"),
|
||||
(18, "Cheezy Poofs"),
|
||||
(19, "Chuck \"Walter\" Karras"),
|
||||
(20, "Cinco De Mayo"),
|
||||
(21, "Club Med"),
|
||||
(22, "Code Complete"),
|
||||
(23, "Coffee Pub, Las Vegas"),
|
||||
(24, "Coke"),
|
||||
(25, "Coin Magic"),
|
||||
(26, "Count Chocula"),
|
||||
(27, "Dad"),
|
||||
(28, "David Arkenstone"),
|
||||
(29, "Digital Camera"),
|
||||
(30, "Direct X Team"),
|
||||
(31, "Denis and Joanne Dyack"),
|
||||
(32, "Blue Bayou, Disneyland"),
|
||||
(33, "Dongle-Boy"),
|
||||
(34, "Doves and Sparrows"),
|
||||
(35, "Dovey"),
|
||||
(36, "Draracles"),
|
||||
(37, "Dry Air"),
|
||||
(38, "Ed Del Castillo"),
|
||||
(39, "Eric \"Kick Ass\" Cartman"),
|
||||
(40, "FHM"),
|
||||
(41, "Fog City Diner"),
|
||||
(42, "Fog Studios"),
|
||||
(43, "Gatorade"),
|
||||
(44, "Gandhi Cuisine of India"),
|
||||
(45, "Giant Lava Lamp"),
|
||||
(46, "Eric and Nancy Gooch"),
|
||||
(47, "Grayford Family"),
|
||||
(48, "Comet Hale-Bopp"),
|
||||
(49, "Joseph B. Hewitt IV"),
|
||||
(50, "Hercules"),
|
||||
(51, "Hillbilly Jeopardy"),
|
||||
(52, "Home Cookin'"),
|
||||
(53, "Hooey Stick"),
|
||||
(54, "The Hypnotist"),
|
||||
(55, "Insects on the Move"),
|
||||
(56, "Intel"),
|
||||
(57, "James Hong"),
|
||||
(58, "Jasmine"),
|
||||
(59, "The Mysterious Cockatiel"),
|
||||
(60, "Joe's Frog"),
|
||||
(61, "Jed"),
|
||||
(62, "Jeeps"),
|
||||
(63, "Jeeter"),
|
||||
(64, "Jeff Brown"),
|
||||
(65, "JoeB"),
|
||||
(66, "Joe-Bob McClintock"),
|
||||
(67, "Joseph Turkel"),
|
||||
(68, "Jose Cuervo"),
|
||||
(69, "Juggling Balls"),
|
||||
(70, "Keith Parkinson"),
|
||||
(71, "Khan"),
|
||||
(72, "King of the Hill"),
|
||||
(73, "Kurt O. and the Toothbrush Squad"),
|
||||
(74, "Leonard and Shirley Legg"),
|
||||
(75, "Leroy"),
|
||||
(76, "Brion James"),
|
||||
(77, "Louis and his \"friend\""),
|
||||
(78, "M.C. Crammer and Janie"),
|
||||
(79, "Men's Room Magna-Doodle"),
|
||||
(80, "Mark and Deepti Rowland"),
|
||||
(81, "Metro Pizza, Las Vegas"),
|
||||
(82, "Matt Vella"),
|
||||
(83, "Maui"),
|
||||
(84, "1 Million Candlepower Spotlight"),
|
||||
(85, "Mom"),
|
||||
(86, "Movie-makers"),
|
||||
(87, "Mr. Nonsense"),
|
||||
(88, "Needles"),
|
||||
(89, "Nerf Weaponry"),
|
||||
(90, "Nimbus"),
|
||||
(91, "Norm Vordahl"),
|
||||
(92, "KNPR"),
|
||||
(93, "Olive Garden"),
|
||||
(94, "Onkyo"),
|
||||
(95, "Orangey"),
|
||||
(96, "Osbur, the Human Resource Manager"),
|
||||
(97, "Our Cheery Friend Leary"),
|
||||
(98, "Ousted Gnome King"),
|
||||
(99, "Pepsi"),
|
||||
(100, "Peta Wilson"),
|
||||
(101, "Pogo the Mockingbird"),
|
||||
(102, "Poker Nights"),
|
||||
(103, "Pirates"),
|
||||
(104, "Playmate Lingerie Calendar"),
|
||||
(105, "Pop-Ice"),
|
||||
(106, "Powerhouse Gym"),
|
||||
(107, "Rade McDowell"),
|
||||
(108, "Red Rock Canyon"),
|
||||
(109, "Refrigeration"),
|
||||
(110, "Rhoda"),
|
||||
(111, "Richard and Kimberly Weier"),
|
||||
(112, "Ridley Scott"),
|
||||
(113, "Ruud the Dude"),
|
||||
(114, "Our old pal Rick Parks"),
|
||||
(115, "Ruby's Diner"),
|
||||
(116, "Savatage"),
|
||||
(117, "Scully and Mulder"),
|
||||
(118, "Sean Young"),
|
||||
(119, "Seinfeld"),
|
||||
(120, "The Shadow"),
|
||||
(121, "Shakes"),
|
||||
(122, "Shorts"),
|
||||
(123, "Silly Putty"),
|
||||
(124, "The Simpsons"),
|
||||
(125, "Thomas Christensen"),
|
||||
(126, "We love you Steve Wetherill!!!"),
|
||||
(127, "Skank"),
|
||||
(128, "Slice"),
|
||||
(129, "SSG"),
|
||||
(130, "Steve and Anne Tall"),
|
||||
(131, "South Park"),
|
||||
(132, "Snap 'n Pops"),
|
||||
(133, "Sneaker"),
|
||||
(134, "Star Wars Trilogy"),
|
||||
(135, "Nonstop Summer Pool Parties"),
|
||||
(136, "Sunsets"),
|
||||
(137, "T-Bone and Angie"),
|
||||
(138, "T-shirts"),
|
||||
(139, "Julio Schembari, Tango Pools"),
|
||||
(140, "The Thermostat Key"),
|
||||
(141, "The Wizard"),
|
||||
(142, "Tomb Raider"),
|
||||
(143, "Tom Elmer II"),
|
||||
(144, "Tujia Linden"),
|
||||
(145, "Turbo"),
|
||||
(146, "Tweeter"),
|
||||
(147, "Twonky"),
|
||||
(148, "Ty and Judy Coon"),
|
||||
(149, "The Courtyard"),
|
||||
(150, "U.F.C."),
|
||||
(151, "Uli Boehnke"),
|
||||
(152, "Virgil"),
|
||||
(153, "Virtual Boy"),
|
||||
(154, "Westwood Offroad Excursion Team"),
|
||||
(155, "William Sanderson"),
|
||||
(156, "Xena"),
|
||||
(157, "Zion National Park"),
|
||||
(158, "We 3 coders give special thanks to:")
|
||||
]
|
||||
|
||||
|
||||
class pogoTextResource(object):
|
||||
m_traceModeEnabled = True
|
||||
# traceModeEnabled is bool to enable more printed debug messages
|
||||
def __init__(self, traceModeEnabled = True):
|
||||
self.m_traceModeEnabled = traceModeEnabled
|
||||
return
|
||||
|
||||
def printPogo(self):
|
||||
if self.m_traceModeEnabled:
|
||||
print ("[Trace] printing Pogo...")
|
||||
for (idTre, textTre) in POGO_TEXT_RESOURCE_TUPLE_LIST:
|
||||
print ("%s\t%s" % (idTre, textTre))
|
||||
return
|
||||
|
||||
def getPogoEntriesList(self):
|
||||
if self.m_traceModeEnabled:
|
||||
print ("[Trace] getPogoEntriesList()")
|
||||
return POGO_TEXT_RESOURCE_TUPLE_LIST
|
||||
|
||||
#
|
||||
#
|
||||
#
|
||||
if __name__ == '__main__':
|
||||
# main()
|
||||
print ("[Debug] Running %s (%s) as main module" % (MY_MODULE_NAME, MY_MODULE_VERSION))
|
||||
traceModeEnabled = False
|
||||
pogoTRInstance = pogoTextResource(traceModeEnabled)
|
||||
pogoTRInstance.printPogo()
|
||||
else:
|
||||
#debug
|
||||
#print ("[Debug] Running %s (%s) imported from another module" % (MY_MODULE_NAME, MY_MODULE_VERSION))
|
||||
pass
|
||||
@@ -0,0 +1,17 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
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)
|
||||
|
||||
import sortBladeRunnerWavs02
|
||||
if __name__ == "__main__":
|
||||
sortBladeRunnerWavs02.main(sys.argv[0:])
|
||||
@@ -0,0 +1,75 @@
|
||||
Id Short ActorDesc #skip first row
|
||||
0 MCCOY McCoy
|
||||
1 STEEL Steele
|
||||
2 GORDO Gordo
|
||||
3 DEKTO Dektora
|
||||
4 GUZZA Guzza
|
||||
5 CLOVI Clovis
|
||||
6 LLUCY Lucy
|
||||
7 IIIZO Izo
|
||||
8 SADIK Sadik
|
||||
9 CRAZY Crazylegs
|
||||
10 LUTHE Luther
|
||||
11 GRIGO Grigorian
|
||||
12 TRANS Transient
|
||||
13 LANCE Lance
|
||||
14 BBBOB Bullet Bob
|
||||
15 RUNCI Runciter
|
||||
16 INSEC Insect Dealer
|
||||
17 TGUAR Tyrell Guard
|
||||
18 EARLQ Early Q
|
||||
19 ZUBEN Zuben
|
||||
20 HASAN Hasan
|
||||
21 MARCU Marcus
|
||||
22 MMMIA Mia
|
||||
23 OLEAR Officer Leary
|
||||
24 OGRAY Officer Grayford
|
||||
25 HANOI Hanoi
|
||||
26 BAKER Baker
|
||||
27 DCLER Desk Clerk
|
||||
28 HOWIE Howie Lee
|
||||
29 FISHD Fish Dealer
|
||||
30 KLEIN Klein
|
||||
31 MURRA Murray
|
||||
32 HBARK Hawker's Barkeep
|
||||
33 HOLLO Holloway
|
||||
34 SWALL Sergeant Walls
|
||||
35 MORAJ Moraji
|
||||
36 TBARD The Bard
|
||||
37 PHOTG Photographer
|
||||
38 DISPA Dispatcher
|
||||
39 ANSWM Answering Machine
|
||||
40 RAJIF Rajif
|
||||
41 GKOLV Governor Kolvig
|
||||
42 ERLQB Early Q Bartender
|
||||
43 HPARR Hawker's Parrot
|
||||
44 TAFPA Taffy Patron
|
||||
45 LOCGU Lockup Guard
|
||||
46 TEENA Teenager
|
||||
47 HPATA Hysteria Patron A
|
||||
48 HPATB Hysteria Patron B
|
||||
49 HPATC Hysteria Patron C
|
||||
50 SHOES Shoeshine Man
|
||||
51 TYREL Tyrell
|
||||
52 CCHEW Chew
|
||||
53 GGAFF Gaff
|
||||
54 BRYAN Bryant
|
||||
55 TAFFY Taffy
|
||||
56 SEBAS Sebastian
|
||||
57 RACHA Rachael
|
||||
58 GDOLL General Doll
|
||||
59 ISABE Isabella
|
||||
60 BLIMP Blimp Guy
|
||||
61 NEWSC Newscaster
|
||||
62 LLEON Leon
|
||||
63 MALAN Male Announcer
|
||||
64 FREEA Free Slot A
|
||||
65 FREEB Free Slot B
|
||||
66 MAGGI Maggie
|
||||
67 ACTGA Actor Genwalker A
|
||||
68 ACTGB Actor Genwalker B
|
||||
69 ACTGC Actor Genwalker C
|
||||
70 MUTAA Mutant A
|
||||
71 MUTAB Mutant B
|
||||
72 MUTAC Mutant C
|
||||
99 MAINF Mainframe
|
||||
@@ -0,0 +1,9 @@
|
||||
python2.7 quoteSpreadsheetCreator.py -op /d/BladeRunnerLPBackup/ENG_data/WAV -ip "/d/Westwood/BladeRunnerENG" -ian ../common/actornames.txt -ld EN_ANY -xtre -xwav -xpogo -xdevs --trace
|
||||
|
||||
python2.7 quoteSpreadsheetCreator.py -op /D/BladeRunnerLPBackup/DEU_data/WAV -ip "/d/Westwood/BladeRunnerDEU" -ian ../common/actornames.txt -ld DE_DEU -xtre -xwav -xpogo -xdevs
|
||||
|
||||
python2.7 quoteSpreadsheetCreator.py -op /D/BladeRunnerLPBackup/FRA_data/WAV -ip "/d/Westwood/BladeRunnerFRA" -ian ../common/actornames.txt -ld FR_FRA -xtre -xwav -xpogo -xdevs
|
||||
|
||||
python2.7 quoteSpreadsheetCreator.py -op /D/BladeRunnerLPBackup/ITA_data/WAV -ip "/d/Westwood/BladeRunnerIT" -ian ../common/actornames.txt -ld IT_ITA -xtre -xwav -xpogo -xdevs
|
||||
|
||||
python2.7 quoteSpreadsheetCreator.py -op /D/BladeRunnerLPBackup/ESP_data/WAV -ip "/d/Westwood/BladeRunnerESP" -ian ../common/actornames.txt -ld ES_ESP -xtre -xwav -xpogo -xdevs
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,181 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
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 struct
|
||||
except ImportError:
|
||||
print ("[Error] struct python library is required to be installed!")
|
||||
else:
|
||||
structLibFound = True
|
||||
|
||||
if (not osLibFound) \
|
||||
or (not sysLibFound) \
|
||||
or (not structLibFound):
|
||||
sys.stdout.write("[Error] Errors were found when trying to import required python libraries\n")
|
||||
sys.exit(1)
|
||||
|
||||
pathToParent = os.path.join(os.path.dirname(os.path.abspath(__file__)), os.pardir)
|
||||
pathToCommon = os.path.join(pathToParent, "common")
|
||||
sys.path.append(pathToCommon)
|
||||
|
||||
from struct import *
|
||||
from pythonCompat import *
|
||||
|
||||
MY_MODULE_VERSION = "0.70"
|
||||
MY_MODULE_NAME = "treFileLib"
|
||||
|
||||
|
||||
class TreHeader(object):
|
||||
numOfTextResources = -1
|
||||
def __init__(self):
|
||||
return
|
||||
|
||||
|
||||
class treFile(object):
|
||||
m_header = TreHeader()
|
||||
simpleTextResourceFileName = 'GENERIC.TRE'
|
||||
stringEntriesLst = [] # list of two-value tuples. First value is ID, second value is String content
|
||||
stringOffsets = []
|
||||
m_traceModeEnabled = False
|
||||
|
||||
# traceModeEnabled is bool to enable more printed debug messages
|
||||
def __init__(self, traceModeEnabled = True):
|
||||
del self.stringEntriesLst[:]
|
||||
del self.stringOffsets[:]
|
||||
self.simpleTextResourceFileName = 'GENERIC.TRE'
|
||||
self.m_traceModeEnabled = traceModeEnabled
|
||||
return
|
||||
|
||||
def loadTreFile(self, treBytesBuff, maxLength, treFileName):
|
||||
self.simpleTextResourceFileName = treFileName
|
||||
offsInTreFile = 0
|
||||
#
|
||||
# parse TRE file fields for header
|
||||
#
|
||||
try:
|
||||
tmpTuple = struct.unpack_from('I', treBytesBuff, offsInTreFile) # unsigned integer 4 bytes
|
||||
self.header().numOfTextResources = tmpTuple[0]
|
||||
offsInTreFile += 4
|
||||
#
|
||||
# string IDs table (each entry is unsigned integer 4 bytes)
|
||||
#
|
||||
if self.m_traceModeEnabled:
|
||||
print ("[Info] Total texts in Text Resource file: %d" % (self.header().numOfTextResources))
|
||||
for idx in range(0, self.header().numOfTextResources):
|
||||
tmpTuple = struct.unpack_from('I', treBytesBuff, offsInTreFile) # unsigned integer 4 bytes
|
||||
self.stringEntriesLst.append( (tmpTuple[0], '') )
|
||||
offsInTreFile += 4
|
||||
|
||||
# string offsets table (each entry is unsigned integer 4 bytes)
|
||||
for idx in range(0, self.header().numOfTextResources):
|
||||
tmpTuple = struct.unpack_from('I', treBytesBuff, offsInTreFile) # unsigned integer 4 bytes
|
||||
self.stringOffsets.append( tmpTuple[0] )
|
||||
offsInTreFile += 4
|
||||
#
|
||||
# strings (all entries are null terminated)
|
||||
# TODO +++
|
||||
absStartOfIndexTable = 4
|
||||
#absStartOfOffsetTable = absStartOfIndexTable + (self.header().numOfTextResources * 4)
|
||||
#absStartOfStringTable = absStartOfOffsetTable + ((self.header().numOfTextResources+1) * 4)
|
||||
|
||||
#print ("[Debug] buffer type: ", type(treBytesBuff)) # it is str
|
||||
|
||||
for idx in range(0, self.header().numOfTextResources):
|
||||
currOffset = self.stringOffsets[idx] + absStartOfIndexTable
|
||||
# the buffer (treBytesBuff) where we read the TRE file into, is "str" type but contains multiple null terminated strings
|
||||
# the solution here (to not get out of index errors when reading the null terminator points) is
|
||||
# to split the substring starting at the indicated offset each time, at the null character, and get the first string token.
|
||||
# This works ok.
|
||||
#
|
||||
print (treBytesBuff[currOffset:])
|
||||
if sys.version_info[0] <= 2:
|
||||
allTextsFound = treBytesBuff[currOffset:].split('\x00')
|
||||
else:
|
||||
allTextsFound = treBytesBuff[currOffset:].split(b'\0')
|
||||
print (allTextsFound[0])
|
||||
### check "problematic" character cases:
|
||||
##if self.m_traceModeEnabled:
|
||||
## if currOffset == 5982 or currOffset == 6050 or currOffset == 2827 or currOffset == 2880:
|
||||
## print ("[Debug] Offs: %d\tFound String: %s" % (currOffset, ''.join(allTextsFound[0]) ))
|
||||
(theId, stringOfIdx) = self.stringEntriesLst[idx]
|
||||
if sys.version_info[0] <= 2:
|
||||
self.stringEntriesLst[idx] = (theId, ''.join(allTextsFound[0]))
|
||||
else:
|
||||
self.stringEntriesLst[idx] = (theId, allTextsFound[0])
|
||||
|
||||
if self.m_traceModeEnabled:
|
||||
if sys.version_info[0] <= 2:
|
||||
print ("[Trace] ID: %d\tFound String: %s" % (theId, ''.join(allTextsFound[0]) ))
|
||||
else:
|
||||
print ("[Trace] ID: %d\tFound String: %s" % (theId, allTextsFound[0] ))
|
||||
return True
|
||||
except Exception as e:
|
||||
print ("[Error] Loading Text Resource %s failed!" % (self.simpleTextResourceFileName) + " " + str(e))
|
||||
return False
|
||||
|
||||
def header(self):
|
||||
return self.m_header
|
||||
#
|
||||
#
|
||||
#
|
||||
if __name__ == '__main__':
|
||||
# main()
|
||||
errorFound = False
|
||||
# By default assumes a file of name ACTORS.TRE in same directory
|
||||
# otherwise tries to use the first command line argument as input file
|
||||
inTREFile = None
|
||||
inTREFileName = 'ACTORS.TRE'
|
||||
|
||||
if len(sys.argv[1:]) > 0 \
|
||||
and os.path.isfile(os.path.join(u'.', sys.argv[1])) \
|
||||
and len(sys.argv[1]) >= 5 \
|
||||
and sys.argv[1][-3:].upper() == 'TRE':
|
||||
inTREFileName = sys.argv[1]
|
||||
print ("[Info] Attempting to use %s as input TRE file..." % (inTREFileName))
|
||||
elif os.path.isfile(os.path.join(u'.', inTREFileName)):
|
||||
print ("[Info] Using default %s as input TRE file..." % (inTREFileName))
|
||||
else:
|
||||
print ("[Error] No valid input file argument was specified and default input file %s is missing." % (inTREFileName))
|
||||
errorFound = True
|
||||
|
||||
if not errorFound:
|
||||
try:
|
||||
print ("[Info] Opening %s" % (inTREFileName))
|
||||
inTREFile = open(os.path.join(u'.', inTREFileName), 'rb')
|
||||
except:
|
||||
errorFound = True
|
||||
print ("[Error] Unexpected event: ", sys.exc_info()[0])
|
||||
raise
|
||||
if not errorFound:
|
||||
allOfTreFileInBuffer = inTREFile.read()
|
||||
treFileInstance = treFile(True)
|
||||
if treFileInstance.m_traceModeEnabled:
|
||||
print ("[Debug] Running %s (%s) as main module" % (MY_MODULE_NAME, MY_MODULE_VERSION))
|
||||
if treFileInstance.loadTreFile(allOfTreFileInBuffer, len(allOfTreFileInBuffer), inTREFileName):
|
||||
print ("[Info] Text Resource file loaded successfully!")
|
||||
else:
|
||||
print ("[Error] Error while loading Text Resource file!")
|
||||
inTREFile.close()
|
||||
else:
|
||||
#debug
|
||||
#print ("[Debug] Running %s (%s) imported from another module" % (MY_MODULE_NAME, MY_MODULE_VERSION))
|
||||
pass
|
||||
@@ -0,0 +1,4 @@
|
||||
fontNameAndOutOfOrderGlyphs=SUBTLS_E#windows-1252#ÿ:€
|
||||
fontNameAndOutOfOrderGlyphs=KIA6PT#cp437#
|
||||
fontNameAndOutOfOrderGlyphs=TAHOMA#cp437#
|
||||
fontNameAndOutOfOrderGlyphs=SYSTEM#latin-1#
|
||||
@@ -0,0 +1,6 @@
|
||||
targetEncoding=windows-1252
|
||||
asciiCharList=!!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—™š›œžŸ¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþ
|
||||
explicitKerningList=Ì:1,Í:2,Î:1,Ï:1,ì:1,í:2,î:1,ï:1
|
||||
explicitWidthIncrement=1:2,Ì:1,Í:1
|
||||
originalFontName=SUBLTS
|
||||
specialOutOfOrderGlyphsUTF8ToAsciiTargetEncoding=ÿ:€
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 26 KiB |
Reference in New Issue
Block a user