Merge pull request #651 from bnnm/ikm-txth

ikm txth
This commit is contained in:
bnnm 2020-06-14 16:02:04 +02:00 committed by GitHub
commit 75f7115e28
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 292 additions and 269 deletions

View File

@ -268,15 +268,16 @@ loop_end_sample = (value)|data_size
Force loop on or off, as loop start/end may be defined but not used. If not set, by default it loops when loop_end_sample is defined and less than num_samples.
Special values:
- auto: tries to autodetect loop points for PS-ADPCM data using data loop flags.
- `auto`: tries to autodetect loop points for PS-ADPCM data using data loop flags.
Sometimes games give loop flags different meaning, so behavior can be tweaked by defining `loop_behavior` before `loop_flag`:
- `default`: values 0 or 0xFFFF/0xFFFFFFFF (-1) disable looping, but not 0xFF (loop endlessly)
- `negative`: values 0xFF/0xFFFF/0xFFFFFFFF (-1) enable looping
- `positive`: values 0xFF/0xFFFF/0xFFFFFFFF (-1) disable looping
- `inverted`: values not 0 disable looping
```
loop_negative = default|negative|positive
loop_behavior = default|negative|positive|inverted
loop_flag = (value)|auto
```
@ -414,12 +415,12 @@ Inside the table you define lines mapping a filename to a bunch of values, in th
(filename1): (value)
...
# may put multiple comma-separated values, spaces are ok
(filenameN) : (value1), (...) , (valueN)
(filenameN) : (value1), (...) , (valueN) # inline comments too
# put no name before the : to set default values
: (value1), (...), (valueN)
```
Then I'll find your current file name, and you can then reference its numbers from the list as a `name_value` field, like `base_offset = name_value`, `start_offset = 0x1000 + name_value1`, `interleave = name_value5`, etc. `(filename)` can be with or without extension (like `bgm01.vag` or just `bgm01`), and if the file's name isn't found it'll use default values, and if those aren't defined you'll get 0 instead. Being "values" they can be use math or offsets too.
Then I'll find your current file name, and you can then reference its numbers from the list as a `name_value` field, like `base_offset = name_value`, `start_offset = 0x1000 + name_value1`, `interleave = name_value5`, etc. `(filename)` can be with or without extension (like `bgm01.vag` or just `bgm01`), and if the file's name isn't found it'll use default values, and if those aren't defined you'll get 0 instead. Being "values" they can use math or offsets too (`bgm05: 5*0x010`).
You can use wildcards to match multiple names too (it stops on first name that matches), and UTF-8 names should work, case insensitive even.
```
@ -428,11 +429,11 @@ bgm*_M: 1 # 1ch: some files end with _M for mono
bgm*: 2 # 2ch: all other files, notice order matters
```
While you can put anything in the values, this feature is meant to be used to store some number that points to the actual data inside a real multi-header, that could be set with `header_file`. If you need to store many constant values there is good chance it could be done in some better way.
While you can put anything in the values, this feature is meant to be used to store some number that points to the actual data inside a real multi-header, that could be set with `header_file`. If you feel the need to store many constant values per file, there is good chance it can be done in some better, simpler way.
#### BASE OFFSET MODIFIER
You can set a default offset that affects next `@(offset)` reads making them `@(offset + base_offset)`, for cleaner parsing (particularly interesting when combined with the `name_list`).
You can set a default offset that affects next `@(offset)` reads making them `@(offset + base_offset)`, for cleaner parsing (particularly interesting when combined with the `name_table`).
For example instead of `channels = @0x714` you could set `base_offset = 0x710, channels = @0x04`. Set to 0 when you want to disable it.
```
@ -633,7 +634,7 @@ chunk_count = 26
# after setting chunks (sizes vary when 'dechunking')
start_offset = 0x00
padding_size = auto-empty
padding_size = auto-empty
num_samples = data_size
```
@ -675,9 +676,9 @@ Some formats read an offset to another part of the file, then another offset, th
You can simulate this chaining multiple `base_offset`
```
base_offset = @0x10 #sets at 0x1000
channels = @0x04 #reads at 0x1004
base_offset = base_offset + @0x10 #sets at 0x1000 + 0x200 = 0x1200
base_offset = @0x10 #sets current at 0x1000
channels = @0x04 #reads at 0x1004 (base_offset + 0x04)
base_offset = base_offset + @0x10 #sets current at 0x1000 + 0x200 = 0x1200
sample_rate = @0x04 #reads at 0x1204
...
```

View File

@ -91,7 +91,7 @@ BIK_E1_6A_DialEnd_00000000.audio.multi.bik#3
mode = layers
```
Note that the number of channels is the sum of all layers, so three 2ch layers play as a 6ch file. If all layers share loop points they are automatically kept.
Note that the number of channels is the sum of all layers, so three 2ch layers play as a 6ch file (you can downmix to stereo using mixing commands, described later). If all layers share loop points they are automatically kept.
### Mixed groups
You can set "groups" to 'fold' various files into one, as layers or segments, to allow complex cases:
@ -166,7 +166,7 @@ mainB_2ch.at3
group = 2L2 #@layer-v 2
# finally resulting layers are played as segments (2ch, 2ch)
# (could set a group = S and ommit S here, too)
# (could set a group = S and ommit mode here, too)
mode = segments
# if the last group joins all as segments you can use loop_start
@ -239,34 +239,42 @@ music_Home.ps3.scd#C3 4
### Play settings
**`#l(loops)`**, **`#f(fade)`**, **`#d(fade-delay)`**, **`#i(ignore loop)`**, **`#F(ignore fade)`**, **`#E(end-to-end loop)`**
Those setting should override player's defaults if set (except "loop forever"). They are equivalent to some test.exe options.
Those setting should override player's defaults if set. They are equivalent to some test.exe options.
**God Hand (PS2)**: *boss2_3ningumi_ver6.txtp* (each line is a separate TXTP)
**God Hand (PS2)**: *boss2_3ningumi_ver6.txtp*
```
# set number of loops
boss2_3ningumi_ver6.adx#l3
```
```
# set fade time (in seconds)
boss2_3ningumi_ver6.adx#f10.5
```
```
# set fade delay (in seconds)
boss2_3ningumi_ver6.adx#d0.5
```
```
# ignore and disable loops
boss2_3ningumi_ver6.adx#i
```
```
# don't fade out and instead play the song ending after
boss2_3ningumi_ver6.adx#F # this song has a nice stop
```
```
# force full loops from end-to-end
boss2_3ningumi_ver6.adx#E
```
```
# settings can be combined
boss2_3ningumi_ver6.adx#l2#F # 2 loops + ending
```
```
# settings can be combined
boss2_3ningumi_ver6.adx#l1.5#d1#f5
```
```
# boss2_3ningumi_ver6.adx#l1.0#F # this is equivalent to #i
```
@ -284,7 +292,7 @@ main.fsb
Similarly other games don't use loop points, but rather repeat/loops the song internally many times:
```
intro.vag #t3:20 #i #l1.0 #trim + combine with forced loops for easy fades
bgm01.vag #t3:20 #i #l1.0 # trim + combine with forced loops for easy fades
```
Note that if you need to remove very few samples (like 1) to get smooth transitions it may be a bug in vgmstream, consider reporting.

View File

@ -155,7 +155,8 @@ int ffmpeg_make_riff_xma1(uint8_t * buf, size_t buf_size, size_t sample_count, s
put_16bitLE(buf+off+0x12, speakers);
}
/* xmaencode decoding rejects XMA1 without "seek" chunk, though it doesn't seem to use it */
/* xmaencode decoding rejects XMA1 without "seek" chunk, though it doesn't seem to use it
* (needs to be have entries but can be bogus, also generates seek for even small sounds) */
memcpy(buf+riff_size-4-4, "data", 4);
put_32bitLE(buf+riff_size-4, data_size); /* data size */

View File

@ -3,24 +3,24 @@
/* IKM - MiCROViSiON PS2 container [Zwei (PS2)] */
VGMSTREAM * init_vgmstream_ikm_ps2(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
VGMSTREAM* init_vgmstream_ikm_ps2(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
off_t start_offset;
int loop_flag, channel_count;
/* checks */
if ( !check_extensions(streamFile,"ikm") )
if ( !check_extensions(sf,"ikm") )
goto fail;
if (read_32bitBE(0x00,streamFile) != 0x494B4D00) /* "IKM\0" */
if (read_u32be(0x00,sf) != 0x494B4D00) /* "IKM\0" */
goto fail;
if (read_32bitBE(0x40,streamFile) != 0x41535400) /* "AST\0" */
if (read_u32be(0x40,sf) != 0x41535400) /* "AST\0" */
goto fail;
/* 0x20: type 03? */
loop_flag = (read_32bitLE(0x14, streamFile) > 0);
channel_count = read_32bitLE(0x50, streamFile);
loop_flag = (read_s32le(0x14, sf) > 0);
channel_count = read_s32le(0x50, sf);
start_offset = 0x800;
@ -29,15 +29,15 @@ VGMSTREAM * init_vgmstream_ikm_ps2(STREAMFILE *streamFile) {
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_IKM;
vgmstream->sample_rate = read_32bitLE(0x44, streamFile);
vgmstream->num_samples = ps_bytes_to_samples(read_32bitLE(0x4c, streamFile), channel_count);
vgmstream->loop_start_sample = read_32bitLE(0x14, streamFile);
vgmstream->loop_end_sample = read_32bitLE(0x18, streamFile);
vgmstream->sample_rate = read_s32le(0x44, sf);
vgmstream->num_samples = ps_bytes_to_samples(read_s32le(0x4c, sf), channel_count);
vgmstream->loop_start_sample = read_s32le(0x14, sf);
vgmstream->loop_end_sample = read_s32le(0x18, sf);
vgmstream->coding_type = coding_PSX;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x10; /* @0x40 / channels */
if (!vgmstream_open_stream(vgmstream, streamFile, start_offset))
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
goto fail;
return vgmstream;
@ -46,34 +46,41 @@ fail:
return NULL;
}
/* IKM - MiCROViSiON PC container [Chaos Legion (PC)] */
VGMSTREAM * init_vgmstream_ikm_pc(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
/* IKM - MiCROViSiON PC container [Chaos Legion (PC), Legend of Galactic Heroes (PC)] */
VGMSTREAM* init_vgmstream_ikm_pc(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
off_t start_offset;
/* checks */
if ( !check_extensions(streamFile,"ikm") )
if ( !check_extensions(sf,"ikm") )
goto fail;
if (read_32bitBE(0x00,streamFile) != 0x494B4D00) /* "IKM\0" */
goto fail;
if (read_32bitBE(0x30,streamFile) != 0x4F676753) /* "OggS" */
if (read_u32be(0x00,sf) != 0x494B4D00) /* "IKM\0" */
goto fail;
/* 0x20: type 01? */
start_offset = 0x30;
/* find "OggS" start */
if (read_u32be(0x30,sf) == 0x4F676753) {
start_offset = 0x30; /* Chaos Legion (PC) */
} else if (read_u32be(0x800,sf) == 0x4F676753) {
start_offset = 0x800; /* Legend of Galactic Heroes (PC) */
} else {
goto fail;
}
#ifdef VGM_USE_VORBIS
{
ogg_vorbis_meta_info_t ovmi = {0};
ovmi.meta_type = meta_IKM;
ovmi.loop_start = read_32bitLE(0x14, streamFile);
ovmi.loop_end = read_32bitLE(0x18, streamFile);
ovmi.loop_start = read_s32le(0x14, sf);
ovmi.loop_end = read_s32le(0x18, sf);
ovmi.loop_end_found = ovmi.loop_end;
ovmi.loop_flag = ovmi.loop_end > 0;
ovmi.stream_size = read_32bitLE(0x24, streamFile);
ovmi.stream_size = read_s32le(0x24, sf);
vgmstream = init_vgmstream_ogg_vorbis_callbacks(streamFile, NULL, start_offset, &ovmi);
vgmstream = init_vgmstream_ogg_vorbis_callbacks(sf, NULL, start_offset, &ovmi);
}
#else
goto fail;
@ -87,39 +94,39 @@ fail:
}
/* IKM - MiCROViSiON PSP container [The Legend of Heroes: A Tear of Vermillion (PSP)] */
VGMSTREAM * init_vgmstream_ikm_psp(STREAMFILE *streamFile) {
VGMSTREAM *vgmstream = NULL;
STREAMFILE *temp_streamFile = NULL;
VGMSTREAM* init_vgmstream_ikm_psp(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
STREAMFILE* temp_sf = NULL;
off_t start_offset;
size_t data_size;
/* checks */
if ( !check_extensions(streamFile,"ikm") )
if (!check_extensions(sf,"ikm"))
goto fail;
if (read_32bitBE(0x00,streamFile) != 0x494B4D00) /* "IKM\0" */
if (read_u32be(0x00,sf) != 0x494B4D00) /* "IKM\0" */
goto fail;
if (read_32bitBE(0x800,streamFile) != 0x52494646) /* "RIFF" */
if (read_u32be(0x800,sf) != 0x52494646) /* "RIFF" */
goto fail;
/* 0x20: type 00? */
/* loop values (pre-adjusted without encoder delay) at 0x14/18 are found in the RIFF too */
data_size = read_32bitLE(0x24, streamFile);
data_size = read_s32le(0x24, sf);
start_offset = 0x800;
temp_streamFile = setup_subfile_streamfile(streamFile, start_offset, data_size, "at3");
if (!temp_streamFile) goto fail;
temp_sf = setup_subfile_streamfile(sf, start_offset, data_size, "at3");
if (!temp_sf) goto fail;
vgmstream = init_vgmstream_riff(temp_streamFile);
vgmstream = init_vgmstream_riff(temp_sf);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_IKM;
close_streamfile(temp_streamFile);
close_streamfile(temp_sf);
return vgmstream;
fail:
close_streamfile(temp_streamFile);
close_streamfile(temp_sf);
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -936,7 +936,7 @@ static size_t get_ue4_msadpcm_interleave(STREAMFILE *sf, riff_fmt_chunk *fmt, of
return v2_interleave; /* favor newer games */
}
/* same but big endian, seen in the spec and in Kitchenette (PC) */
/* same but big endian, seen in the spec and in Kitchenette (PC) (possibly from Adobe Director) */
VGMSTREAM * init_vgmstream_rifx(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
riff_fmt_chunk fmt = {0};

File diff suppressed because it is too large Load Diff