mirror of
https://github.com/vgmstream/vgmstream.git
synced 2025-01-18 07:44:43 +01:00
154 lines
6.6 KiB
Markdown
154 lines
6.6 KiB
Markdown
# TXTH FORMAT
|
|
|
|
TXTH is a simple text file that uses text commands to simulate a header for files unsupported by vgmstream, mainly headerless audio.
|
|
|
|
When an unsupported file is loaded, vgmstream tries to find a TXTH header in the same dir, in this order:
|
|
- (filename.ext).txth
|
|
- .(ext).txth
|
|
- .txth
|
|
|
|
If found and parsed correctly (the TXTH may be rejected if incorrect commands are found) vgmstream will try to play the file as described. Extension must be accepted/added to vgmstream (plugins like foobar2000 only load extensions from a whitelist in formats.c), or one could rename to any supported extension (like .vgmstream), or leave the file extensionless.
|
|
|
|
|
|
## Example of a TXTH file
|
|
For an unsupported bgm01.vag this would be a simple TXTH for it:
|
|
```
|
|
id_value = 0x534E4420 #test that file starts with "SND "
|
|
id_offset = @0x00:BE #test is done at offset 0, big endian value
|
|
codec = PSX
|
|
sample_rate = @0x10$2 #get sample rate at offset 0x10, 16 bit value
|
|
channels = @0x14 #get number of channels at offset 14
|
|
interleave = 0x1000 #fixed value
|
|
start_offset = 0x100
|
|
num_samples = data_size #find automatically number of samples in the file
|
|
loop_flag = auto
|
|
```
|
|
A text file with the above commands must be saved as ".vag.txth" or ".txth", notice it starts with a "." (dot). On Windows files starting with a dot can be created by appending a dot at the end: ".txth."
|
|
|
|
|
|
## Available commands
|
|
|
|
```
|
|
######################################################
|
|
|
|
# comments start with #, can be inline
|
|
# The file is made lines of "key = value" describing a header.
|
|
# Spaces are optional: key=value, key= value, and so on are all ok.
|
|
# The parser is fairly simple and may be buggy or unexpected in some cases.
|
|
# The order of keys is variable but some things won't work if others aren't defined
|
|
# (ex. bytes-to-samples may not work without channels or interleave).
|
|
|
|
# Common values:
|
|
# - (number): constant number in dec/hex.
|
|
# Examples: 44100, 40, 0x40 (dec=64)
|
|
# - (offset): format is @(number)[:LE|BE][$1|2|3|4]
|
|
# * @(number): value at offset (required)
|
|
# * :LE|BE: value is little/big endian (optional, defaults to LE)
|
|
# * $1|2|3|4: value has size of 8/16/24/32 bit (optional, defaults to 4)
|
|
# Examples: @0x10:BE$2 (get big endian 16b value at 0x10)
|
|
# - {string}: special values for certain keys, described below
|
|
|
|
# Codec used to encode the data [REQUIRED]
|
|
# Accepted codec strings:
|
|
# - PSX PlayStation ADPCM
|
|
# - XBOX Xbox IMA ADPCM
|
|
# - NGC_DTK Nintendo ADP/DTK ADPCM
|
|
# - PCM16BE PCM RAW 16bit big endian
|
|
# - PCM16LE PCM RAW 16bit little endian
|
|
# - PCM8 PCM RAW 8bit
|
|
# - SDX2 Squareroot-delta-exact 8-bit DPCM (3DO games)
|
|
# - DVI_IMA DVI IMA ADPCM
|
|
# - MPEG MPEG Audio Layer File (MP1/2/3)
|
|
# - IMA IMA ADPCM
|
|
# - AICA Yamaha AICA ADPCM (Dreamcast)
|
|
# - MSADPCM Microsoft ADPCM (Windows)
|
|
# - NGC_DSP Nintengo GameCube ADPCM
|
|
# - PCM8_U_int PCM RAW 8bit unsigned (interleaved)
|
|
# - PSX_bf PlayStation ADPCM with bad flags
|
|
# - MS_IMA Microsoft IMA ADPCM
|
|
# - PCM8_U PCM RAW 8bit unsigned
|
|
# - APPLE_IMA4 Apple Quicktime IMA ADPCM
|
|
# - ATRAC3 raw ATRAC3
|
|
# - ATRAC3PLUS raw ATRAC3PLUS
|
|
# - XMA1 raw XMA1
|
|
# - XMA2 raw XMA2
|
|
# - FFMPEG any headered FFmpeg format
|
|
codec = (codec string)
|
|
|
|
# Varies with codec:
|
|
# - NGC_DSP: 0=normal interleave, 1=byte interleave, 2=no interleave
|
|
# - ATRAC3: 0=autodetect joint stereo, 1=force joint stereo, 2=force normal stereo
|
|
# - XMA1|XMA2: 0=dual multichannel (2ch xN), 1=single multichannel (1ch xN)
|
|
# - XBOX: 0=standard, 1=force mono/interleave mode
|
|
# - others: ignored
|
|
codec_mode = (number)
|
|
|
|
# Interleave or block size [REQUIRED/OPTIONAL, depends on codec]
|
|
# Interleave 0 means "stereo mode" for some codecs (IMA, AICA, etc)
|
|
interleave = (number)|(offset)
|
|
|
|
# Validate that id_value matches value at id_offset [OPTIONAL]
|
|
# Can be redefined several times, it's checked whenever a new id_offset is found.
|
|
id_value = (number)|(offset)
|
|
id_offset = (number)|(offset)
|
|
|
|
# Number of channels [REQUIRED]
|
|
channels = (number)|(offset)
|
|
|
|
# Music frequency in hz [REQUIRED]
|
|
sample_rate = (number)|(offset)
|
|
|
|
# Data start [OPTIONAL, default to 0]
|
|
start_offset = (number)|(offset)
|
|
|
|
# Variable that can be used in sample values [OPTIONAL]
|
|
# Defaults to (file_size - start_offset), re-calculated when start_offset is set.
|
|
data_size = (number)|(offset)
|
|
|
|
|
|
# Modifies the meaning of sample fields when set *before* them [OPTIONAL, defaults to samples]
|
|
# - samples: exact sample
|
|
# - bytes: automatically converts bytes/offset to samples
|
|
# - blocks: same as bytes, but value is given in blocks/frames
|
|
# Value is internally converted from blocks to bytes first: bytes = (value * interleave*channels)
|
|
# It's possible to re-define values multiple times:
|
|
# * samples_type=bytes ... num_samples=@0x10
|
|
# * samples_type=sample ... loop_end_sample=@0x14
|
|
# Sometimes "bytes" values are given for a single channel only. In that case you can temporally set 1 channel
|
|
# * channels=1 ... sample_type=bytes ... num_samples=@0x10 ... channels=2
|
|
# Some codecs can't convert bytes-to-samples at the moment: MPEG/FFMPEG
|
|
# For XMA1/2 bytes does special parsing, with loop values being bit offsets within data.
|
|
sample_type = samples|bytes|blocks
|
|
|
|
# Various sample values [REQUIRED (num_samples) / OPTIONAL (rest)]
|
|
num_samples = (number)|(offset)|data_size
|
|
loop_start_sample = (number)|(offset)
|
|
loop_end_sample = (number)|(offset)|data_size
|
|
|
|
# For XMA1/2 + sample_type=bytes it means loop subregion, if read after loop values.
|
|
# For other codecs its added to loop start/end, if read before loop values
|
|
# (rarely a format may have rough loop offset/bytes, then a loop adjust in samples).
|
|
loop_adjust = (number)|(offset)
|
|
|
|
# Force loop, on (>0) or off (0), as loop start/end may be defined but not used [OPTIONAL]
|
|
# By default it loops when loop_end_sample is defined
|
|
# auto tries to autodetect loop points for PS-ADPCM data, which may include loop flags.
|
|
loop_flag = (number)|(offset)|auto
|
|
|
|
# beginning samples to skip (encoder delay), for codecs that need them (ATRAC3/XMA/etc)
|
|
skip_samples = (number)|(offset)
|
|
|
|
|
|
# DSP coefficients [REQUIRED for NGC_DSP]
|
|
# Coefs start
|
|
coef_offset = (number)|(offset)
|
|
# offset separation per channel, usually 0x20
|
|
# - Example: channel N coefs are read at coef_offset + coef_spacing * N
|
|
coef_spacing = (number)|(offset)
|
|
# Format, usually BE; with (offset): 0=LE, >0=BE
|
|
coef_endianness = BE|LE|(offset)
|
|
# Split/normal coefs [NOT IMPLEMENTED YET]
|
|
#coef_mode = (number)|(offset)
|
|
|
|
```
|