mirror of
https://github.com/vgmstream/vgmstream.git
synced 2025-01-29 19:37:30 +01:00
commit
12ad42378a
123
README.md
123
README.md
@ -42,62 +42,62 @@ Put the following files somewhere Windows can find them:
|
||||
For Winamp/XMPlay/command line this means in the directory with the main .exe,
|
||||
or in a system directory, or any other directory in the PATH variable.
|
||||
|
||||
### test.exe/vgmstream-cli
|
||||
```
|
||||
Usage: test.exe [-o outfile.wav] [options] infile
|
||||
Options:
|
||||
-o outfile.wav: name of output .wav file, default infile.wav
|
||||
-l loop count: loop count, default 2.0
|
||||
-f fade time: fade time in seconds after N loops, default 10.0
|
||||
-d fade delay: fade delay in seconds, default 0.0
|
||||
-F: don't fade after N loops and play the rest of the stream
|
||||
-i: ignore looping information and play the whole stream once
|
||||
-e: force end-to-end looping
|
||||
-E: force end-to-end looping even if file has real loop points
|
||||
-s N: select subsong N, if the format supports multiple subsongs
|
||||
-m: print metadata only, don't decode
|
||||
-L: append a smpl chunk and create a looping wav
|
||||
-2 N: only output the Nth (first is 0) set of stereo channels
|
||||
-p: output to stdout (for piping into another program)
|
||||
-P: output to stdout even if stdout is a terminal
|
||||
-c: loop forever (continuously) to stdout
|
||||
-x: decode and print adxencd command line to encode as ADX
|
||||
-g: decode and print oggenc command line to encode as OGG
|
||||
-b: decode and print batch variable commands
|
||||
-r: output a second file after resetting (for testing)
|
||||
-t file: print if tags are found in file
|
||||
```
|
||||
Typical usage would be: ```test -o happy.wav happy.adx``` to decode ```happy.adx``` to ```happy.wav```.
|
||||
|
||||
Please follow the above instructions for installing the other files needed.
|
||||
## Components
|
||||
|
||||
### test.exe/vgmstream-cli
|
||||
*Installation*: unzip the file and follow the above instructions for installing
|
||||
the other files needed.
|
||||
|
||||
Converts playable files to wav. Typical usage would be:
|
||||
- `test.exe -o happy.wav happy.adx` to decode `happy.adx` to `happy.wav`.
|
||||
|
||||
If command-line isn't your thing you can also drag and drop files to the
|
||||
executable to decode them as (filename).wav
|
||||
|
||||
There are multiple options that alter how the file is converted, for example:
|
||||
- `test.exe -m -o file.wav file.adx`: print info but don't decode
|
||||
- `test.exe -i -o file.wav file.hca`: convert without looping
|
||||
- `test.exe -s 2 -F -o file.wav file.fsb`: play 2nd subsong + ending after 2.0 loops
|
||||
- `test.exe -l 3.0 -f 5.0 -d 3.0 -o file.wav file.wem`: 3 loops, 3s delay, 5s fade
|
||||
|
||||
Available commands are printed when run with no flags. Note that you can also
|
||||
achieve similar results for other plugins using TXTP, described later.
|
||||
|
||||
### in_vgmstream
|
||||
Drop the ```in_vgmstream.dll``` in your Winamp plugins directory. Please follow
|
||||
the above instructions for installing the other files needed.
|
||||
*Installation*: drop the ```in_vgmstream.dll``` in your Winamp plugins directory,
|
||||
and follow the above instructions for installing the other files needed.
|
||||
|
||||
Once installed supported files should be playable.
|
||||
|
||||
### xmp-vgmstream
|
||||
Drop the ```xmp-vgmstream.dll``` in your XMPlay plugins directory. Please follow
|
||||
the above instructions for installing the other files needed.
|
||||
*Installation*: drop the ```xmp-vgmstream.dll``` in your XMPlay plugins directory,
|
||||
and follow the above instructions for installing the other files needed.
|
||||
|
||||
Note that there are minor differences compared to in_vgmstream. Since XMPlay
|
||||
supports Winamp plugins you may also use ```in_vgmstream.dll``` instead.
|
||||
Note that this has less features compared to in_vgmstream and has no configuration.
|
||||
Since XMPlay supports Winamp plugins you may also use ```in_vgmstream.dll``` instead.
|
||||
|
||||
Because the XMPlay MP3 decoder incorrectly tries to play some vgmstream exts,
|
||||
you need to manually fix it by going to **options > plugins > input > vgmstream**
|
||||
and in the "priority filetypes" put: ```ahx,asf,awc,ckd,fsb,genh,msf,p3d,rak,scd,txth,xvag```
|
||||
and in the "priority filetypes" put: `ahx,asf,awc,ckd,fsb,genh,msf,p3d,rak,scd,txth,xvag`
|
||||
|
||||
### foo_input_vgmstream
|
||||
Every file should be installed automatically by the .fb2k-component bundle.
|
||||
*Installation*: every file should be installed automatically by the `.fb2k-component`
|
||||
bundle.
|
||||
|
||||
A known quirk is that when loop options or tags change, playlist won't refresh
|
||||
automatically. You need to manually refresh it by selecting songs and doing
|
||||
**shift + right click > Tagging > Reload info from file(s)**.
|
||||
|
||||
### Audacious plugin
|
||||
Needs to be manually built. Instructions can be found in the BUILD document.
|
||||
*Installation*: needs to be manually built. Instructions can be found in the BUILD
|
||||
document.
|
||||
|
||||
### vgmstream123
|
||||
Needs to be manually built. Instructions can be found in the BUILD document.
|
||||
*Installation*: seeds to be manually built. Instructions can be found in the
|
||||
BUILD document in vgmstream's source code.
|
||||
|
||||
```
|
||||
Usage: vgmstream123 [options] INFILE ...
|
||||
```
|
||||
Usage: `vgmstream123 [options] INFILE ...`
|
||||
|
||||
The program is meant to be a simple stand-alone player, supporting playback
|
||||
of vgmstream files through libao. Files compressed with gzip/bzip2/xz also
|
||||
@ -225,10 +225,10 @@ Programs like VGMToolbox can help to create GENH.
|
||||
single file). Contains dynamic text commands to read data from the original
|
||||
file, or static values.
|
||||
|
||||
**TXTP**: a text playlist that works as a single song. Can contain a list of
|
||||
filenames to play as one (ex. "intro.vag" "loop.vag"), separate channel files
|
||||
to join as a single multichannel file, subsong index (ex. bgm.sxd#10), or
|
||||
channel mask to allow only certain channels (ex. "song.adx#c1,2").
|
||||
**TXTP**: a text playing configurator. Can contain a list of filenames to
|
||||
play as one (ex. "intro.vag" "loop.vag"), list of separate channel files
|
||||
to join as a single multichannel file, subsong index (ex. bgm.sxd#10),
|
||||
per-file configurations like number of loops, and many other features.
|
||||
|
||||
Creation of those files is meant for advanced users, docs can be found in
|
||||
vgmstream source.
|
||||
@ -237,17 +237,20 @@ vgmstream source.
|
||||
Since vgmstream supports a huge amount of formats it's possibly that some of
|
||||
them are also supported in other plugins, and this sometimes causes conflicts.
|
||||
If a file that should isn't playing or looping, first make sure vgmstream is
|
||||
really opening it (should show "vgmstream" somewhere in the file info), and
|
||||
try to remove a few other plugins. foobar's ffmpeg plugin and foo_adpcm are
|
||||
known to cause issues.
|
||||
really opening it (should show "VGMSTREAM" somewhere in the file info), and
|
||||
try to remove a few other plugins.
|
||||
|
||||
foobar's ffmpeg plugin and foo_adpcm are known to cause issues, but in
|
||||
recent versions (1.4.x) you can configure plugin priority.
|
||||
|
||||
### Channel issues
|
||||
Some games layer a huge number of channels, that are disabled or downmixed
|
||||
during gameplay. The player may be unable to play those files (for example
|
||||
foobar can only play up to 8 channels, and Winamp depends the your sound
|
||||
card). For those files you can set the "downmix" option in vgmstream, that
|
||||
can reduce the number of channels to a playable amount. Note that downmixing
|
||||
is very simple and not meant to be used when converting to other formats.
|
||||
can reduce the number of channels to a playable amount. Note that this type
|
||||
of downmixing is very generic, not meant to be used when converting to other
|
||||
formats.
|
||||
|
||||
## Tagging
|
||||
Some of vgmstream's plugins support simple read-only tagging via external files.
|
||||
@ -278,6 +281,20 @@ Playlist formatting should follow player's config. ASCII or UTF-8 tags work.
|
||||
GLOBAL_COMMANDs currently can be:
|
||||
- AUTOTRACK: sets %TRACK% tag automatically (1..N as files are encountered
|
||||
in the tag file).
|
||||
- AUTOALBUM: sets %ALBUM% tag automatically using the containing dir as album.
|
||||
|
||||
foobar2000 can apply the following replaygain tags (if ReplayGain is enabled
|
||||
in foobar's preferences):
|
||||
```
|
||||
# %replaygain_track_gain N.NN dB
|
||||
# %replaygain_track_peak N.NNN
|
||||
# @replaygain_album_gain N.NN dB
|
||||
# @replaygain_album_peak N.NNN
|
||||
```
|
||||
|
||||
If your player isn't picking tags make sure vgmstream is detecting the song
|
||||
(as other plugins can steal its extensions, see above), .m3u is properly
|
||||
named and that filenames inside match the song filename.
|
||||
|
||||
|
||||
## Supported codec types
|
||||
@ -286,6 +303,7 @@ are used in few games.
|
||||
|
||||
- PCM 16-bit
|
||||
- PCM 8-bit (signed/unsigned)
|
||||
- PCM 4-bit (signed/unsigned)
|
||||
- PCM 32-bit float
|
||||
- u-Law/a-LAW
|
||||
- CRI ADX (standard, fixed, exponential, encrypted)
|
||||
@ -302,7 +320,7 @@ are used in few games.
|
||||
- Microsoft MS IMA ADPCM (standard, Xbox, NDS, Radical, Wwise, FSB, WV6, etc)
|
||||
- Microsoft MS ADPCM (standard, Cricket Audio)
|
||||
- Westwood VBR ADPCM
|
||||
- Yamaha AICA ADPCM
|
||||
- Yamaha ADPCM (standard, Aska)
|
||||
- Procyon Studio ADPCM
|
||||
- Level-5 0x555 ADPCM
|
||||
- lsf ADPCM
|
||||
@ -315,6 +333,7 @@ are used in few games.
|
||||
- Ocean DSA 4-bit ADPCM
|
||||
- Circus XPCM ADPCM
|
||||
- OKI 4-bit ADPCM (16-bit output, PC-FX)
|
||||
- Ocean DSA 4-bit ADPCM
|
||||
- SDX2 2:1 Squareroot-Delta-Exact compression DPCM
|
||||
- CBD2 2:1 Cuberoot-Delta-Exact compression DPCM
|
||||
- Activision EXAKT SASSC DPCM
|
||||
@ -578,6 +597,7 @@ This list is not complete and many other files are supported.
|
||||
- .xma (MS XMA/XMA2)
|
||||
- .sb0/sb1/sb2/sb3/sb4/sb5/sb6/sb7 (many)
|
||||
- .sm0/sm1/sm2/sm3/sm4/sm5/sm6/sm7 (many)
|
||||
- .bao/pk (many)
|
||||
- artificial/generic headers:
|
||||
- .genh (lots)
|
||||
- .txth (lots)
|
||||
@ -586,11 +606,12 @@ This list is not complete and many other files are supported.
|
||||
- .pos (loop info for .wav: 32 bit LE loop start sample + loop end sample)
|
||||
- .sli (loop info for .ogg)
|
||||
- .sfl (loop info for .ogg)
|
||||
- .vgmstream + .vgmstream.pos (FFmpeg formats + loop assist)
|
||||
- other:
|
||||
- .adxkey (decryption key for .adx, in start/mult/add format)
|
||||
- .ahxkey (decryption key for .ahx, in start/mult/add format)
|
||||
- .hcakey (decryption key for .hca, in HCA Decoder format)
|
||||
- .fsbkey (decryption key for .fsb, in hex)
|
||||
- .vgmstream + .vgmstream.pos (FFmpeg formats + loop assist)
|
||||
- .txtp (per song segment/layer handler and player configurator)
|
||||
|
||||
Enjoy! *hcs*
|
||||
|
@ -255,7 +255,7 @@ static void print_info(VGMSTREAM * vgmstream, cli_config *cfg) {
|
||||
char description[1024];
|
||||
description[0] = '\0';
|
||||
describe_vgmstream(vgmstream,description,1024);
|
||||
printf("%s\n",description);
|
||||
printf("%s",description);
|
||||
}
|
||||
}
|
||||
|
||||
@ -418,7 +418,8 @@ int main(int argc, char ** argv) {
|
||||
|
||||
/* print tags info */
|
||||
if (cfg.tag_filename) {
|
||||
VGMSTREAM_TAGS tag;
|
||||
VGMSTREAM_TAGS *tags;
|
||||
const char *tag_key, *tag_val;
|
||||
|
||||
STREAMFILE *tagFile = open_stdio_streamfile(cfg.tag_filename);
|
||||
if (!tagFile) {
|
||||
@ -427,11 +428,13 @@ int main(int argc, char ** argv) {
|
||||
}
|
||||
|
||||
printf("tags:\n");
|
||||
vgmstream_tags_reset(&tag, cfg.infilename);
|
||||
while ( vgmstream_tags_next_tag(&tag, tagFile)) {
|
||||
printf("- '%s'='%s'\n", tag.key, tag.val);
|
||||
}
|
||||
|
||||
tags = vgmstream_tags_init(&tag_key, &tag_val);
|
||||
vgmstream_tags_reset(tags, cfg.infilename);
|
||||
while ( vgmstream_tags_next_tag(tags, tagFile)) {
|
||||
printf("- '%s'='%s'\n", tag_key, tag_val);
|
||||
}
|
||||
vgmstream_tags_close(tags);
|
||||
close_streamfile(tagFile);
|
||||
}
|
||||
|
||||
@ -462,12 +465,7 @@ int main(int argc, char ** argv) {
|
||||
|
||||
#ifdef VGMSTREAM_MIXING
|
||||
/* enable after all config but before outbuf */
|
||||
{
|
||||
vgmstream_enable_mixing(vgmstream, BUFFER_SAMPLES);
|
||||
|
||||
channels = vgmstream->output_channels;
|
||||
input_channels = vgmstream->input_channels;
|
||||
}
|
||||
vgmstream_enable_mixing(vgmstream, BUFFER_SAMPLES, &input_channels, &channels);
|
||||
#endif
|
||||
|
||||
buf = malloc(BUFFER_SAMPLES * sizeof(sample_t) * input_channels);
|
||||
|
45
doc/TXTP.md
45
doc/TXTP.md
@ -20,7 +20,7 @@ You can set commands to alter how files play (described later). Having a single
|
||||
### Segments mode
|
||||
Some games clumsily loop audio by using multiple full file "segments", so you can play separate intro + loop files together as a single track. Channel number must be equal, mixing sample rates is ok (uses first).
|
||||
|
||||
__Ratchet & Clank (PS2)__: _bgm01.txtp_
|
||||
**Ratchet & Clank (PS2)**: *bgm01.txtp*
|
||||
```
|
||||
# define 2 or more segments to play as one
|
||||
BGM01_BEGIN.VAG
|
||||
@ -53,7 +53,7 @@ loop_mode = keep # loops in 2nd file's loop_start to 3rd file's loop_end
|
||||
### Layers mode
|
||||
Some games layer channels or dynamic parts that must play at the same time, for example main melody + vocal track.
|
||||
|
||||
__Nier Automata__: _BGM_0_012_song2.txtp_
|
||||
**Nier Automata**: *BGM_0_012_song2.txtp*
|
||||
```
|
||||
# mix dynamic sections (2ch * 2)
|
||||
BGM_0_012_04.wem
|
||||
@ -62,7 +62,7 @@ BGM_0_012_07.wem
|
||||
mode = layers
|
||||
```
|
||||
|
||||
__Life is Strange__: _BIK_E1_6A_DialEnd.txtp_
|
||||
**Life is Strange**: *BIK_E1_6A_DialEnd.txtp*
|
||||
```
|
||||
# bik multichannel isn't autodetectable so must mix manually (1ch * 3)
|
||||
BIK_E1_6A_DialEnd_00000000.audio.multi.bik#1
|
||||
@ -80,7 +80,7 @@ You can set file commands by adding multiple `#(command)` after the name. `# (an
|
||||
### Subsong selection for bank formats
|
||||
**`#(number)` or `#s(number)`**: set subsong (number)
|
||||
|
||||
__Super Robot Taisen OG Saga - Masou Kishin III - Pride of Justice (Vita)__: _bgm_12.txtp_
|
||||
**Super Robot Taisen OG Saga - Masou Kishin III - Pride of Justice (Vita)**: *bgm_12.txtp*
|
||||
```
|
||||
# select subsong 12
|
||||
bigfiles/bgm.sxd2#12 #relative paths are ok too for TXTP
|
||||
@ -95,7 +95,7 @@ bigfiles/bgm.sxd2#12 #relative paths are ok too for TXTP
|
||||
### Play segmented subsong ranges as one
|
||||
**`#m(number)~(number)` or `#ms(number)~(number)`**: set multiple subsong segments at a time, to avoid so much C&P
|
||||
|
||||
__Prince of Persia Sands of Time__: _song_01.txtp_
|
||||
**Prince of Persia Sands of Time**: *song_01.txtp*
|
||||
```
|
||||
amb_fx.sb0#254
|
||||
amb_fx.sb0#122~144
|
||||
@ -115,7 +115,7 @@ song#3#h22050
|
||||
### Channel mask for channel subsongs/layers
|
||||
**`#c(number)`** (single) or **`#c(number)~(number)`** (range): set number of channels to play. You can add multiple comma-separated numbers, or use ` ` space or `-` as separator and combine multiple ranges with single channels too.
|
||||
|
||||
__Final Fantasy XIII-2__: _music_Home_01.ps3.txtp_
|
||||
**Final Fantasy XIII-2**: *music_Home_01.ps3.txtp*
|
||||
```
|
||||
#plays channels 1 and 2 = 1st subsong
|
||||
music_Home.ps3.scd#c1,2
|
||||
@ -136,7 +136,7 @@ Doesn't change the final number of channels though, just mutes non-selected chan
|
||||
|
||||
Those setting should override player's defaults if set (except "loop forever"). 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* (each line is a separate TXTP)
|
||||
```
|
||||
# set number of loops
|
||||
boss2_3ningumi_ver6.adx#l3
|
||||
@ -169,16 +169,37 @@ boss2_3ningumi_ver6.adx#l1.5#d1#f5
|
||||
### Force sample rate
|
||||
**`#h(sample rate)`**: for a few games that set a sample rate value in the header but actually play with other (applying some of pitch or just forcing it).
|
||||
|
||||
__Super Paper Mario (Wii)__
|
||||
**Super Paper Mario (Wii)**
|
||||
```
|
||||
btl_koopa1_44k_lp.brstm#h22050 #in hz
|
||||
```
|
||||
__Patapon (PSP)__
|
||||
**Patapon (PSP)**
|
||||
```
|
||||
ptp_btl_bgm_voice.sgd#s1#h11050
|
||||
```
|
||||
|
||||
|
||||
### Install loops
|
||||
**`#I(loop start time) (loop end time)`**: force/override looping values, same as .pos but nicer. Loop end is optional and defaults to total samples.
|
||||
|
||||
Time values can be `M:S(.n)` (minutes and seconds), `S.n` (seconds with dot) or `N` (samples). Beware of the subtle difference between 10.0 (10 seconds) and 10 (10 samples). Wrong loop values (for example loop end being much larger than file's samples) will be ignored, but there is some leeway when using seconds for the loop end.
|
||||
|
||||
**Jewels Ocean (PC)**
|
||||
```
|
||||
bgm01.ogg#I32.231 # from ~1421387 samples to end
|
||||
|
||||
#bgm01.ogg#I 0:32.231 # equivalent
|
||||
#bgm01.ogg#I 1421387 4212984 # equivalent, end is 4212984
|
||||
#bgm01.ogg#I32.231 1_35.533 # equivalent, end over file samples (~4213005) but adjusted to 4212984
|
||||
#bgm01.ogg#I 1421387 4212985 # ignored, end over file samples
|
||||
#bgm01.ogg#I32.231 1_37 # ignored, end over file (~4277700) but clearly wrong
|
||||
```
|
||||
|
||||
Use this feature responsibly, though. If you find a format that should loop using internal values that vgmstream doesn't detect correctly, consider reporting the bug for the benefit of all users and other games using the same format, and don't throw out the original loop definitions (as sometimes they may not take into account "encoder delay" and must be carefully adjusted).
|
||||
|
||||
Note that a few codecs may not work with arbitrary loop values since they weren't tested with loops. Misaligned loops will cause audible "clicks" at loop point too.
|
||||
|
||||
|
||||
## OTHER FEATURES
|
||||
|
||||
### Default commands
|
||||
@ -297,7 +318,7 @@ The parser is fairly simplistic and lax, and may be erratic with edge cases or b
|
||||
|
||||
## MINI-TXTP
|
||||
To simplify TXTP creation, if the .txtp is empty (0 bytes) its filename is used directly as a command. Note that extension is also included (since vgmstream needs a full filename).
|
||||
- _bgm.sxd2#12.txtp_: plays subsong 12
|
||||
- _Ryoshima Coast 1 & 2.aix#c1,2.txtp_: channel mask
|
||||
- _boss2_3ningumi_ver6.adx#l2#F.txtp_: loop twice then play song end file normally
|
||||
- *bgm.sxd2#12.txtp*: plays subsong 12
|
||||
- *Ryoshima Coast 1 & 2.aix#c1,2.txtp*: channel mask
|
||||
- *boss2_3ningumi_ver6.adx#l2#F.txtp*: loop twice then play song end file normally
|
||||
- etc
|
||||
|
@ -170,12 +170,21 @@ void input_vgmstream::get_info(t_uint32 p_subsong, file_info & p_info, abort_cal
|
||||
|
||||
STREAMFILE *tagFile = open_foo_streamfile(tagfile_path, &p_abort, &stats);
|
||||
if (tagFile != NULL) {
|
||||
VGMSTREAM_TAGS tag;
|
||||
vgmstream_tags_reset(&tag, filename);
|
||||
while (vgmstream_tags_next_tag(&tag, tagFile)) {
|
||||
p_info.meta_set(tag.key,tag.val);
|
||||
}
|
||||
VGMSTREAM_TAGS *tags;
|
||||
const char *tag_key, *tag_val;
|
||||
|
||||
tags = vgmstream_tags_init(&tag_key, &tag_val);
|
||||
vgmstream_tags_reset(tags, filename);
|
||||
while (vgmstream_tags_next_tag(tags, tagFile)) {
|
||||
if (replaygain_info::g_is_meta_replaygain(tag_key)) {
|
||||
p_info.info_set_replaygain(tag_key,tag_val);
|
||||
/* there is info_set_replaygain_auto too but no doc */
|
||||
}
|
||||
else {
|
||||
p_info.meta_set(tag_key,tag_val);
|
||||
}
|
||||
}
|
||||
vgmstream_tags_close(tags);
|
||||
close_streamfile(tagFile);
|
||||
}
|
||||
}
|
||||
@ -194,7 +203,7 @@ void input_vgmstream::get_info(t_uint32 p_subsong, file_info & p_info, abort_cal
|
||||
if (total_samples > 0)
|
||||
p_info.info_set_int("stream_total_samples", total_samples);
|
||||
if (loop_start >= 0 && loop_end > loop_start) {
|
||||
p_info.info_set("looping", loop_flag > 0 ? "enabled" : "disabled");
|
||||
if (loop_flag <= 0) p_info.info_set("looping", "disabled");
|
||||
p_info.info_set_int("loop_start", loop_start);
|
||||
p_info.info_set_int("loop_end", loop_end);
|
||||
}
|
||||
@ -210,6 +219,8 @@ void input_vgmstream::get_info(t_uint32 p_subsong, file_info & p_info, abort_cal
|
||||
if (get_description_tag(temp,description,"stream count: ")) p_info.info_set("stream_count",temp);
|
||||
if (get_description_tag(temp,description,"stream index: ")) p_info.info_set("stream_index",temp);
|
||||
if (get_description_tag(temp,description,"stream name: ")) p_info.info_set("stream_name",temp);
|
||||
|
||||
if (get_description_tag(temp,description,"channel mask: ")) p_info.info_set("channel_mask",temp);
|
||||
}
|
||||
|
||||
t_filestats input_vgmstream::get_file_stats(abort_callback & p_abort) {
|
||||
@ -293,12 +304,16 @@ bool input_vgmstream::decode_run(audio_chunk & p_chunk,abort_callback & p_abort)
|
||||
/* copy back to global buffer... in case of multithreading stuff? */
|
||||
memcpy(sample_buffer,temp_buffer, samples_to_do*downmix_channels*sizeof(short));
|
||||
|
||||
unsigned channel_config = audio_chunk::g_guess_channel_config(downmix_channels);
|
||||
bytes = (samples_to_do*downmix_channels * sizeof(sample_buffer[0]));
|
||||
p_chunk.set_data_fixedpoint((char*)sample_buffer, bytes, vgmstream->sample_rate, downmix_channels, 16, audio_chunk::g_guess_channel_config(downmix_channels));
|
||||
p_chunk.set_data_fixedpoint((char*)sample_buffer, bytes, vgmstream->sample_rate, downmix_channels, 16, channel_config);
|
||||
}
|
||||
else {
|
||||
unsigned channel_config = vgmstream->channel_layout;
|
||||
if (!channel_config)
|
||||
channel_config = audio_chunk::g_guess_channel_config(vgmstream->channels);
|
||||
bytes = (samples_to_do*vgmstream->channels * sizeof(sample_buffer[0]));
|
||||
p_chunk.set_data_fixedpoint((char*)sample_buffer, bytes, vgmstream->sample_rate, vgmstream->channels, 16, audio_chunk::g_guess_channel_config(vgmstream->channels));
|
||||
p_chunk.set_data_fixedpoint((char*)sample_buffer, bytes, vgmstream->sample_rate, vgmstream->channels, 16, channel_config);
|
||||
}
|
||||
|
||||
|
||||
|
@ -15,30 +15,30 @@ void decode_g721(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing,
|
||||
void g72x_init_state(struct g72x_state *state_ptr);
|
||||
|
||||
/* ima_decoder */
|
||||
void decode_standard_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, int is_stereo, int is_high_first);
|
||||
void decode_3ds_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
void decode_snds_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
|
||||
void decode_otns_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
|
||||
void decode_wv6_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
void decode_alp_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
void decode_ffta2_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
void decode_blitz_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
void decode_standard_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, int is_stereo, int is_high_first);
|
||||
void decode_3ds_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
void decode_snds_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
|
||||
void decode_otns_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
|
||||
void decode_wv6_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
void decode_alp_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
void decode_ffta2_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
void decode_blitz_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
|
||||
void decode_ms_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel);
|
||||
void decode_ref_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel);
|
||||
void decode_ms_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel);
|
||||
void decode_ref_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel);
|
||||
|
||||
void decode_xbox_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, int is_stereo);
|
||||
void decode_xbox_ima_mch(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
|
||||
void decode_nds_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
void decode_dat4_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
void decode_rad_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel);
|
||||
void decode_rad_ima_mono(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
void decode_apple_ima4(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
void decode_fsb_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
|
||||
void decode_wwise_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
|
||||
void decode_awc_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
void decode_ubi_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
|
||||
void decode_h4m_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, uint16_t frame_format);
|
||||
void decode_xbox_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, int is_stereo);
|
||||
void decode_xbox_ima_mch(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
|
||||
void decode_nds_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
void decode_dat4_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
void decode_rad_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel);
|
||||
void decode_rad_ima_mono(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
void decode_apple_ima4(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
void decode_fsb_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
|
||||
void decode_wwise_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
|
||||
void decode_awc_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
void decode_ubi_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
|
||||
void decode_h4m_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, uint16_t frame_format);
|
||||
size_t ima_bytes_to_samples(size_t bytes, int channels);
|
||||
size_t ms_ima_bytes_to_samples(size_t bytes, int block_align, int channels);
|
||||
size_t xbox_ima_bytes_to_samples(size_t bytes, int channels);
|
||||
@ -63,20 +63,20 @@ void decode_ngc_dtk(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspaci
|
||||
void decode_ngc_afc(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
|
||||
/* pcm_decoder */
|
||||
void decode_pcm16le(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
void decode_pcm16be(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
void decode_pcm16_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int big_endian);
|
||||
void decode_pcm8(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
void decode_pcm8_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
void decode_pcm8_unsigned(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
void decode_pcm8_unsigned_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
void decode_pcm8_sb(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
void decode_pcm4(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
|
||||
void decode_pcm4_unsigned(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
|
||||
void decode_ulaw(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
void decode_ulaw_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
void decode_alaw(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
void decode_pcmfloat(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int big_endian);
|
||||
void decode_pcm16le(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
void decode_pcm16be(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
void decode_pcm16_int(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int big_endian);
|
||||
void decode_pcm8(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
void decode_pcm8_int(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
void decode_pcm8_unsigned(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
void decode_pcm8_unsigned_int(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
void decode_pcm8_sb(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
void decode_pcm4(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
|
||||
void decode_pcm4_unsigned(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
|
||||
void decode_ulaw(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
void decode_ulaw_int(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
void decode_alaw(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
void decode_pcmfloat(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int big_endian);
|
||||
size_t pcm_bytes_to_samples(size_t bytes, int channels, int bits_per_sample);
|
||||
|
||||
/* psx_decoder */
|
||||
@ -129,11 +129,11 @@ void decode_msadpcm_ck(VGMSTREAM * vgmstream, sample * outbuf, int channelspacin
|
||||
long msadpcm_bytes_to_samples(long bytes, int block_size, int channels);
|
||||
|
||||
/* yamaha_decoder */
|
||||
void decode_aica(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, int is_stereo);
|
||||
void decode_yamaha(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
|
||||
void decode_yamaha_nxap(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
size_t aica_bytes_to_samples(size_t bytes, int channels);
|
||||
void decode_yamaha(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, int is_stereo);
|
||||
void decode_aska(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
|
||||
void decode_nxap(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
size_t yamaha_bytes_to_samples(size_t bytes, int channels);
|
||||
size_t aska_bytes_to_samples(size_t bytes, int channels);
|
||||
|
||||
/* nds_procyon_decoder */
|
||||
void decode_nds_procyon(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
@ -163,7 +163,7 @@ void decode_fadpcm(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacin
|
||||
void decode_asf(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
|
||||
/* dsa_decoder */
|
||||
void decode_dsa(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
void decode_dsa(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
|
||||
/* xmd_decoder */
|
||||
void decode_xmd(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, size_t frame_size);
|
||||
@ -198,14 +198,14 @@ int test_hca_key(hca_codec_data * data, unsigned long long keycode);
|
||||
|
||||
#ifdef VGM_USE_VORBIS
|
||||
/* ogg_vorbis_decoder */
|
||||
void decode_ogg_vorbis(ogg_vorbis_codec_data * data, sample * outbuf, int32_t samples_to_do, int channels);
|
||||
void decode_ogg_vorbis(ogg_vorbis_codec_data * data, sample_t * outbuf, int32_t samples_to_do, int channels);
|
||||
void reset_ogg_vorbis(VGMSTREAM *vgmstream);
|
||||
void seek_ogg_vorbis(VGMSTREAM *vgmstream, int32_t num_sample);
|
||||
void free_ogg_vorbis(ogg_vorbis_codec_data *data);
|
||||
|
||||
/* vorbis_custom_decoder */
|
||||
vorbis_custom_codec_data *init_vorbis_custom(STREAMFILE *streamfile, off_t start_offset, vorbis_custom_t type, vorbis_custom_config * config);
|
||||
void decode_vorbis_custom(VGMSTREAM * vgmstream, sample * outbuf, int32_t samples_to_do, int channels);
|
||||
void decode_vorbis_custom(VGMSTREAM * vgmstream, sample_t * outbuf, int32_t samples_to_do, int channels);
|
||||
void reset_vorbis_custom(VGMSTREAM *vgmstream);
|
||||
void seek_vorbis_custom(VGMSTREAM *vgmstream, int32_t num_sample);
|
||||
void free_vorbis_custom(vorbis_custom_codec_data *data);
|
||||
@ -215,7 +215,7 @@ void free_vorbis_custom(vorbis_custom_codec_data *data);
|
||||
/* mpeg_decoder */
|
||||
mpeg_codec_data *init_mpeg(STREAMFILE *streamfile, off_t start_offset, coding_t *coding_type, int channels);
|
||||
mpeg_codec_data *init_mpeg_custom(STREAMFILE *streamFile, off_t start_offset, coding_t *coding_type, int channels, mpeg_custom_t custom_type, mpeg_custom_config *config);
|
||||
void decode_mpeg(VGMSTREAM * vgmstream, sample * outbuf, int32_t samples_to_do, int channels);
|
||||
void decode_mpeg(VGMSTREAM * vgmstream, sample_t * outbuf, int32_t samples_to_do, int channels);
|
||||
void reset_mpeg(VGMSTREAM *vgmstream);
|
||||
void seek_mpeg(VGMSTREAM *vgmstream, int32_t num_sample);
|
||||
void free_mpeg(mpeg_codec_data *data);
|
||||
@ -283,12 +283,13 @@ ffmpeg_codec_data *init_ffmpeg_offset(STREAMFILE *streamFile, uint64_t start, ui
|
||||
ffmpeg_codec_data *init_ffmpeg_header_offset(STREAMFILE *streamFile, uint8_t * header, uint64_t header_size, uint64_t start, uint64_t size);
|
||||
ffmpeg_codec_data *init_ffmpeg_header_offset_subsong(STREAMFILE *streamFile, uint8_t * header, uint64_t header_size, uint64_t start, uint64_t size, int target_subsong);
|
||||
|
||||
void decode_ffmpeg(VGMSTREAM *stream, sample * outbuf, int32_t samples_to_do, int channels);
|
||||
void decode_ffmpeg(VGMSTREAM *stream, sample_t * outbuf, int32_t samples_to_do, int channels);
|
||||
void reset_ffmpeg(VGMSTREAM *vgmstream);
|
||||
void seek_ffmpeg(VGMSTREAM *vgmstream, int32_t num_sample);
|
||||
void free_ffmpeg(ffmpeg_codec_data *data);
|
||||
|
||||
void ffmpeg_set_skip_samples(ffmpeg_codec_data * data, int skip_samples);
|
||||
uint32_t ffmpeg_get_channel_layout(ffmpeg_codec_data * data);
|
||||
|
||||
/* ffmpeg_decoder_custom_opus.c (helper-things) */
|
||||
ffmpeg_codec_data * init_ffmpeg_switch_opus(STREAMFILE *streamFile, off_t start_offset, size_t data_size, int channels, int skip, int sample_rate);
|
||||
|
@ -10,7 +10,7 @@ static const int dsa_coefs[16] = {
|
||||
|
||||
/* Decodes Ocean DSA ADPCM codec from Last Rites (PC).
|
||||
* Reverse engineered from daemon1's reverse engineering. */
|
||||
void decode_dsa(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
void decode_dsa(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
off_t frame_offset;
|
||||
int i, frames_in, sample_count = 0;
|
||||
size_t bytes_per_frame, samples_per_frame;
|
||||
@ -32,20 +32,20 @@ void decode_dsa(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing,
|
||||
|
||||
/* decode nibbles */
|
||||
for (i = first_sample; i < first_sample + samples_to_do; i++) {
|
||||
int32_t new_sample;
|
||||
int32_t sample;
|
||||
uint8_t nibbles = (uint8_t)read_8bit(frame_offset+0x01 + i/2,stream->streamfile);
|
||||
|
||||
new_sample = i&1 ? /* high nibble first */
|
||||
sample = i&1 ? /* high nibble first */
|
||||
(nibbles >> 0) & 0xf :
|
||||
(nibbles >> 4) & 0xf;
|
||||
|
||||
new_sample = ((int16_t)(new_sample << 0xC) >> shift); /* 16b sign extend + scale */
|
||||
new_sample = new_sample + ((hist1 * filter) >> 0x10);
|
||||
sample = ((int16_t)(sample << 0xC) >> shift); /* 16b sign extend + scale */
|
||||
sample = sample + ((hist1 * filter) >> 0x10);
|
||||
|
||||
outbuf[sample_count] = (int16_t)(new_sample << 2);
|
||||
outbuf[sample_count] = (sample_t)(sample << 2);
|
||||
sample_count += channelspacing;
|
||||
|
||||
hist1 = new_sample;
|
||||
hist1 = sample;
|
||||
}
|
||||
|
||||
stream->adpcm_history1_32 = hist1;
|
||||
|
@ -29,7 +29,7 @@ static void g_init_ffmpeg() {
|
||||
}
|
||||
|
||||
/* converts codec's samples (can be in any format, ex. Ogg's float32) to PCM16 */
|
||||
static void convert_audio_pcm16(sample *outbuf, const uint8_t *inbuf, int fullSampleCount, int bitsPerSample, int floatingPoint) {
|
||||
static void convert_audio_pcm16(sample_t *outbuf, const uint8_t *inbuf, int fullSampleCount, int bitsPerSample, int floatingPoint) {
|
||||
int s;
|
||||
switch (bitsPerSample) {
|
||||
case 8: {
|
||||
@ -495,7 +495,7 @@ fail:
|
||||
}
|
||||
|
||||
/* decode samples of any kind of FFmpeg format */
|
||||
void decode_ffmpeg(VGMSTREAM *vgmstream, sample * outbuf, int32_t samples_to_do, int channels) {
|
||||
void decode_ffmpeg(VGMSTREAM *vgmstream, sample_t * outbuf, int32_t samples_to_do, int channels) {
|
||||
ffmpeg_codec_data *data = vgmstream->codec_data;
|
||||
int samplesReadNow;
|
||||
//todo use either channels / data->channels / codecCtx->channels
|
||||
@ -808,4 +808,10 @@ void ffmpeg_set_skip_samples(ffmpeg_codec_data * data, int skip_samples) {
|
||||
data->skipSamples = skip_samples;
|
||||
}
|
||||
|
||||
/* returns channel layout if set */
|
||||
uint32_t ffmpeg_get_channel_layout(ffmpeg_codec_data * data) {
|
||||
if (!data || !data->codecCtx) return 0;
|
||||
return (uint32_t)data->codecCtx->channel_layout; /* uint64 but there ain't so many speaker mappings */
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -270,7 +270,7 @@ static void blitz_ima_expand_nibble(VGMSTREAMCHANNEL * stream, off_t byte_offset
|
||||
/* Standard DVI/IMA ADPCM (as in, ADPCM recommended by the IMA using Intel/DVI's implementation).
|
||||
* Configurable: stereo or mono/interleave nibbles, and high or low nibble first.
|
||||
* For vgmstream, low nibble is called "IMA ADPCM" and high nibble is "DVI IMA ADPCM" (same thing though). */
|
||||
void decode_standard_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, int is_stereo, int is_high_first) {
|
||||
void decode_standard_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, int is_stereo, int is_high_first) {
|
||||
int i, sample_count = 0;
|
||||
int32_t hist1 = stream->adpcm_history1_32;
|
||||
int step_index = stream->adpcm_step_index;
|
||||
@ -298,7 +298,7 @@ void decode_standard_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channel
|
||||
stream->adpcm_step_index = step_index;
|
||||
}
|
||||
|
||||
void decode_3ds_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
void decode_3ds_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
int i, sample_count;
|
||||
int32_t hist1 = stream->adpcm_history1_32;
|
||||
int step_index = stream->adpcm_step_index;
|
||||
@ -319,7 +319,7 @@ void decode_3ds_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspaci
|
||||
stream->adpcm_step_index = step_index;
|
||||
}
|
||||
|
||||
void decode_snds_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
|
||||
void decode_snds_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
|
||||
int i, sample_count;
|
||||
int32_t hist1 = stream->adpcm_history1_32;
|
||||
int step_index = stream->adpcm_step_index;
|
||||
@ -340,7 +340,7 @@ void decode_snds_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspac
|
||||
stream->adpcm_step_index = step_index;
|
||||
}
|
||||
|
||||
void decode_otns_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
|
||||
void decode_otns_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
|
||||
int i, sample_count;
|
||||
int32_t hist1 = stream->adpcm_history1_32;
|
||||
int step_index = stream->adpcm_step_index;
|
||||
@ -364,7 +364,7 @@ void decode_otns_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample *
|
||||
}
|
||||
|
||||
/* WV6 IMA, DVI IMA with custom nibble expand */
|
||||
void decode_wv6_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
void decode_wv6_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
int i, sample_count;
|
||||
int32_t hist1 = stream->adpcm_history1_32;
|
||||
int step_index = stream->adpcm_step_index;
|
||||
@ -386,7 +386,7 @@ void decode_wv6_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspaci
|
||||
}
|
||||
|
||||
/* ALT IMA, DVI IMA with custom nibble expand */
|
||||
void decode_alp_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
void decode_alp_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
int i, sample_count;
|
||||
int32_t hist1 = stream->adpcm_history1_32;
|
||||
int step_index = stream->adpcm_step_index;
|
||||
@ -408,7 +408,7 @@ void decode_alp_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspaci
|
||||
}
|
||||
|
||||
/* FFTA2 IMA, DVI IMA with custom nibble expand/rounding */
|
||||
void decode_ffta2_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
void decode_ffta2_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
int i, sample_count;
|
||||
int32_t hist1 = stream->adpcm_history1_32;
|
||||
int step_index = stream->adpcm_step_index;
|
||||
@ -431,7 +431,7 @@ void decode_ffta2_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspa
|
||||
}
|
||||
|
||||
/* Blitz IMA, IMA with custom nibble expand */
|
||||
void decode_blitz_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
void decode_blitz_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
int i, sample_count;
|
||||
int32_t hist1 = stream->adpcm_history1_32;
|
||||
int step_index = stream->adpcm_step_index;
|
||||
@ -459,7 +459,7 @@ void decode_blitz_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspa
|
||||
/* IMA with custom frame sizes, header and nibble layout. Outputs an odd number of samples per frame,
|
||||
* so to simplify calcs this decodes full frames, thus hist doesn't need to be mantained.
|
||||
* Officially defined in "Microsoft Multimedia Standards Update" doc (RIFFNEW.pdf). */
|
||||
void decode_ms_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
|
||||
void decode_ms_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
|
||||
int i, samples_read = 0, samples_done = 0, max_samples;
|
||||
int32_t hist1;// = stream->adpcm_history1_32;
|
||||
int step_index;// = stream->adpcm_step_index;
|
||||
@ -513,7 +513,7 @@ void decode_ms_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * ou
|
||||
}
|
||||
|
||||
/* Reflection's MS-IMA with custom nibble layout (some info from XA2WAV by Deniz Oezmen) */
|
||||
void decode_ref_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
|
||||
void decode_ref_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
|
||||
int i, samples_read = 0, samples_done = 0, max_samples;
|
||||
int32_t hist1;// = stream->adpcm_history1_32;
|
||||
int step_index;// = stream->adpcm_step_index;
|
||||
@ -573,7 +573,7 @@ void decode_ref_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * o
|
||||
|
||||
/* MS-IMA with fixed frame size, and outputs an even number of samples per frame (skips last nibble).
|
||||
* Defined in Xbox's SDK. Usable in mono or stereo modes (both suitable for interleaved multichannel). */
|
||||
void decode_xbox_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, int is_stereo) {
|
||||
void decode_xbox_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, int is_stereo) {
|
||||
int i, frames_in, sample_pos = 0, block_samples, frame_size;
|
||||
int32_t hist1 = stream->adpcm_history1_32;
|
||||
int step_index = stream->adpcm_step_index;
|
||||
@ -625,7 +625,7 @@ void decode_xbox_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspac
|
||||
}
|
||||
|
||||
/* Multichannel XBOX-IMA ADPCM, with all channels mixed in the same block (equivalent to multichannel MS-IMA; seen in .rsd XADP). */
|
||||
void decode_xbox_ima_mch(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
|
||||
void decode_xbox_ima_mch(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
|
||||
int i, sample_count = 0, num_frame;
|
||||
int32_t hist1 = stream->adpcm_history1_32;
|
||||
int step_index = stream->adpcm_step_index;
|
||||
@ -671,7 +671,7 @@ void decode_xbox_ima_mch(VGMSTREAMCHANNEL * stream, sample * outbuf, int channel
|
||||
/* Similar to MS-IMA with even number of samples, header sample is not written (setup only).
|
||||
* Apparently clamps to -32767 unlike standard's -32768 (probably not noticeable).
|
||||
* Info here: http://problemkaputt.de/gbatek.htm#dssoundnotes */
|
||||
void decode_nds_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
void decode_nds_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
int i, sample_count;
|
||||
int32_t hist1 = stream->adpcm_history1_32;
|
||||
int step_index = stream->adpcm_step_index;
|
||||
@ -702,7 +702,7 @@ void decode_nds_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspaci
|
||||
stream->adpcm_step_index = step_index;
|
||||
}
|
||||
|
||||
void decode_dat4_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
void decode_dat4_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
int i, sample_count;
|
||||
int32_t hist1 = stream->adpcm_history1_16;//todo unneeded 16?
|
||||
int step_index = stream->adpcm_step_index;
|
||||
@ -731,7 +731,7 @@ void decode_dat4_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspac
|
||||
stream->adpcm_step_index = step_index;
|
||||
}
|
||||
|
||||
void decode_rad_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel) {
|
||||
void decode_rad_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel) {
|
||||
int i, sample_count;
|
||||
int32_t hist1 = stream->adpcm_history1_32;
|
||||
int step_index = stream->adpcm_step_index;
|
||||
@ -765,7 +765,7 @@ void decode_rad_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample * ou
|
||||
stream->adpcm_step_index = step_index;
|
||||
}
|
||||
|
||||
void decode_rad_ima_mono(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
void decode_rad_ima_mono(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
int i, sample_count;
|
||||
int32_t hist1 = stream->adpcm_history1_32;
|
||||
int step_index = stream->adpcm_step_index;
|
||||
@ -797,7 +797,7 @@ void decode_rad_ima_mono(VGMSTREAMCHANNEL * stream, sample * outbuf, int channel
|
||||
}
|
||||
|
||||
/* Apple's IMA4, a.k.a QuickTime IMA. 2 byte header and header sample is not written (setup only). */
|
||||
void decode_apple_ima4(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
void decode_apple_ima4(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
int i, sample_count, num_frame;
|
||||
int16_t hist1 = stream->adpcm_history1_16;//todo unneeded 16?
|
||||
int step_index = stream->adpcm_step_index;
|
||||
@ -830,7 +830,7 @@ void decode_apple_ima4(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelsp
|
||||
}
|
||||
|
||||
/* XBOX-IMA with modified data layout */
|
||||
void decode_fsb_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel) {
|
||||
void decode_fsb_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel) {
|
||||
int i, sample_count = 0;
|
||||
int32_t hist1 = stream->adpcm_history1_32;
|
||||
int step_index = stream->adpcm_step_index;
|
||||
@ -879,7 +879,7 @@ void decode_fsb_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * o
|
||||
}
|
||||
|
||||
/* mono XBOX-IMA with header endianness and alt nibble expand (per hcs's decompilation) */
|
||||
void decode_wwise_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
|
||||
void decode_wwise_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
|
||||
int i, sample_count = 0, num_frame;
|
||||
int32_t hist1 = stream->adpcm_history1_32;
|
||||
int step_index = stream->adpcm_step_index;
|
||||
@ -935,7 +935,7 @@ void decode_wwise_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample *
|
||||
*/
|
||||
|
||||
/* MS-IMA with possibly the XBOX-IMA model of even number of samples per block (more tests are needed) */
|
||||
void decode_awc_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
void decode_awc_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
int i, sample_count;
|
||||
|
||||
int32_t hist1 = stream->adpcm_history1_32;
|
||||
@ -972,7 +972,7 @@ void decode_awc_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspaci
|
||||
|
||||
|
||||
/* DVI stereo/mono with some mini header and sample output */
|
||||
void decode_ubi_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
|
||||
void decode_ubi_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
|
||||
int i, sample_count = 0;
|
||||
|
||||
int32_t hist1 = stream->adpcm_history1_32;
|
||||
@ -1038,7 +1038,7 @@ void decode_ubi_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspaci
|
||||
/* IMA with variable frame formats controlled by the block layout. The original code uses
|
||||
* tables mapping all standard IMA combinations (to optimize calculations), but decodes the same.
|
||||
* Based on HCS's and Nisto's reverse engineering in h4m_audio_decode. */
|
||||
void decode_h4m_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, uint16_t frame_format) {
|
||||
void decode_h4m_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, uint16_t frame_format) {
|
||||
int i, samples_done = 0;
|
||||
int32_t hist1 = stream->adpcm_history1_32;
|
||||
int step_index = stream->adpcm_step_index;
|
||||
|
@ -78,12 +78,14 @@ int mpeg_custom_setup_init_default(STREAMFILE *streamFile, off_t start_offset, m
|
||||
|
||||
//todo: test more: this improves the output, but seems formats aren't usually prepared
|
||||
// (and/or the num_samples includes all possible samples in file, so by discarding some it'll reach EOF)
|
||||
// FSBs (with FMOD DLLs) don't seem to need it, even when files contain garbage at the beginning
|
||||
#if 0
|
||||
/* set encoder delay (samples to skip at the beginning of a stream) if needed, which varies with encoder used */
|
||||
switch(data->type) {
|
||||
case MPEG_AHX: data->skip_samples = 480; break; /* observed default */
|
||||
case MPEG_P3D: data->skip_samples = info.frame_samples; break; /* matches Radical ADPCM (PC) output */
|
||||
/* FSBs (with FMOD DLLs) don't seem to need it. Particularly a few games (all from Wayforward?)
|
||||
* contain audible garbage at the beginning, but it's actually there in-game too */
|
||||
case MPEG_FSB: data->skip_samples = 0;
|
||||
default: break;
|
||||
}
|
||||
data->samples_to_discard = data->skip_samples;
|
||||
|
@ -10,8 +10,8 @@
|
||||
#define MPEG_DATA_BUFFER_SIZE 0x1000 /* at least one MPEG frame (max ~0x5A1 plus some more in case of free bitrate) */
|
||||
|
||||
static mpg123_handle * init_mpg123_handle();
|
||||
static void decode_mpeg_standard(VGMSTREAMCHANNEL *stream, mpeg_codec_data * data, sample * outbuf, int32_t samples_to_do, int channels);
|
||||
static void decode_mpeg_custom(VGMSTREAM * vgmstream, mpeg_codec_data * data, sample * outbuf, int32_t samples_to_do, int channels);
|
||||
static void decode_mpeg_standard(VGMSTREAMCHANNEL *stream, mpeg_codec_data * data, sample_t * outbuf, int32_t samples_to_do, int channels);
|
||||
static void decode_mpeg_custom(VGMSTREAM * vgmstream, mpeg_codec_data * data, sample_t * outbuf, int32_t samples_to_do, int channels);
|
||||
static void decode_mpeg_custom_stream(VGMSTREAMCHANNEL *stream, mpeg_codec_data * data, int num_stream);
|
||||
|
||||
|
||||
@ -218,7 +218,7 @@ fail:
|
||||
/* DECODERS */
|
||||
/************/
|
||||
|
||||
void decode_mpeg(VGMSTREAM * vgmstream, sample * outbuf, int32_t samples_to_do, int channels) {
|
||||
void decode_mpeg(VGMSTREAM * vgmstream, sample_t * outbuf, int32_t samples_to_do, int channels) {
|
||||
mpeg_codec_data * data = (mpeg_codec_data *) vgmstream->codec_data;
|
||||
|
||||
if (!data->custom) {
|
||||
@ -232,7 +232,7 @@ void decode_mpeg(VGMSTREAM * vgmstream, sample * outbuf, int32_t samples_to_do,
|
||||
* Decode anything mpg123 can.
|
||||
* Feeds raw data and extracts decoded samples as needed.
|
||||
*/
|
||||
static void decode_mpeg_standard(VGMSTREAMCHANNEL *stream, mpeg_codec_data * data, sample * outbuf, int32_t samples_to_do, int channels) {
|
||||
static void decode_mpeg_standard(VGMSTREAMCHANNEL *stream, mpeg_codec_data * data, sample_t * outbuf, int32_t samples_to_do, int channels) {
|
||||
int samples_done = 0;
|
||||
mpg123_handle *m = data->m;
|
||||
|
||||
@ -290,7 +290,7 @@ static void decode_mpeg_standard(VGMSTREAMCHANNEL *stream, mpeg_codec_data * dat
|
||||
* Copies to outbuf when there are samples in all streams and calls decode_mpeg_custom_stream to decode.
|
||||
. Depletes the stream's sample buffers before decoding more, so it doesn't run out of buffer space.
|
||||
*/
|
||||
static void decode_mpeg_custom(VGMSTREAM * vgmstream, mpeg_codec_data * data, sample * outbuf, int32_t samples_to_do, int channels) {
|
||||
static void decode_mpeg_custom(VGMSTREAM * vgmstream, mpeg_codec_data * data, sample_t * outbuf, int32_t samples_to_do, int channels) {
|
||||
int i, samples_done = 0;
|
||||
|
||||
while (samples_done < samples_to_do) {
|
||||
@ -327,7 +327,7 @@ static void decode_mpeg_custom(VGMSTREAM * vgmstream, mpeg_codec_data * data, sa
|
||||
ch = 0;
|
||||
for (stream = 0; stream < data->streams_size; stream++) {
|
||||
mpeg_custom_stream *ms = data->streams[stream];
|
||||
sample* inbuf = (sample*)ms->output_buffer;
|
||||
sample_t *inbuf = (sample_t *)ms->output_buffer;
|
||||
int stream_channels = ms->channels_per_frame;
|
||||
int stream_ch, s;
|
||||
|
||||
|
@ -1,55 +1,119 @@
|
||||
#include <math.h>
|
||||
#include "coding.h"
|
||||
#include "../util.h"
|
||||
|
||||
#ifdef VGM_USE_VORBIS
|
||||
#include <vorbis/vorbisfile.h>
|
||||
|
||||
void decode_ogg_vorbis(ogg_vorbis_codec_data * data, sample * outbuf, int32_t samples_to_do, int channels) {
|
||||
|
||||
static void pcm_convert_float_to_16(int channels, sample_t * outbuf, int samples_to_do, float ** pcm);
|
||||
|
||||
|
||||
void decode_ogg_vorbis(ogg_vorbis_codec_data * data, sample_t * outbuf, int32_t samples_to_do, int channels) {
|
||||
int samples_done = 0;
|
||||
OggVorbis_File *ogg_vorbis_file = &data->ogg_vorbis_file;
|
||||
long rc;
|
||||
float **pcm_channels; /* pointer to Xiph's double array buffer */
|
||||
|
||||
do {
|
||||
long rc = ov_read(ogg_vorbis_file, (char *)(outbuf + samples_done*channels),
|
||||
(samples_to_do - samples_done)*sizeof(sample)*channels, 0,
|
||||
sizeof(sample), 1, &data->bitstream);
|
||||
while (samples_done < samples_to_do) {
|
||||
rc = ov_read_float(
|
||||
&data->ogg_vorbis_file, /* context */
|
||||
&pcm_channels, /* buffer pointer */
|
||||
(samples_to_do - samples_done), /* samples to produce */
|
||||
&data->bitstream); /* bitstream*/
|
||||
if (rc <= 0) goto fail; /* rc is samples done */
|
||||
|
||||
if (rc > 0) samples_done += rc/sizeof(sample)/channels;
|
||||
else return;
|
||||
} while (samples_done < samples_to_do);
|
||||
pcm_convert_float_to_16(channels, outbuf, rc, pcm_channels);
|
||||
|
||||
swap_samples_le(outbuf, samples_to_do*channels);
|
||||
outbuf += rc * channels;
|
||||
samples_done += rc;
|
||||
|
||||
|
||||
#if 0 // alt decoding
|
||||
/* we use ov_read_float as to reuse the xiph's buffer for easier remapping,
|
||||
* but seems ov_read is slightly faster due to optimized (asm) float-to-int. */
|
||||
rc = ov_read(
|
||||
&data->ogg_vorbis_file, /* context */
|
||||
(char *)(outbuf), /* buffer */
|
||||
(samples_to_do - samples_done) * sizeof(sample_t) * channels, /* length in bytes */
|
||||
0, /* pcm endianness */
|
||||
sizeof(sample), /* pcm size */
|
||||
1, /* pcm signedness */
|
||||
&data->bitstream); /* bitstream */
|
||||
if (rc <= 0) goto fail; /* rc is bytes done (for all channels) */
|
||||
|
||||
swap_samples_le(outbuf, rc / sizeof(sample_t)); /* endianness is a bit weird with ov_read though */
|
||||
|
||||
outbuf += rc / sizeof(sample_t);
|
||||
samples_done += rc / sizeof(sample_t) / channels;
|
||||
#endif
|
||||
}
|
||||
|
||||
return;
|
||||
fail:
|
||||
VGM_LOG("OGG: error %lx during decode\n", rc);
|
||||
memset(outbuf, 0, (samples_to_do - samples_done) * channels * sizeof(sample));
|
||||
}
|
||||
|
||||
/* vorbis encodes channels in non-standard order, so we remap during conversion to fix this oddity.
|
||||
* (feels a bit weird as one would think you could leave as-is and set the player's output
|
||||
* order, but that isn't possible and remapping is what FFmpeg and every other plugin do). */
|
||||
static const int xiph_channel_map[8][8] = {
|
||||
{ 0 }, /* 1ch: FC > same */
|
||||
{ 0, 1 }, /* 2ch: FL FR > same */
|
||||
{ 0, 2, 1 }, /* 3ch: FL FC FR > FL FR FC */
|
||||
{ 0, 1, 2, 3 }, /* 4ch: FL FR BL BR > same */
|
||||
{ 0, 2, 1, 3, 4 }, /* 5ch: FL FC FR BL BR > FL FR FC BL BR */
|
||||
{ 0, 2, 1, 5, 3, 4 }, /* 6ch: FL FC FR BL BR LFE > FL FR FC LFE BL BR */
|
||||
{ 0, 2, 1, 6, 5, 3, 4 }, /* 7ch: FL FC FR SL SR BC LFE > FL FR FC LFE BC SL SR */
|
||||
{ 0, 2, 1, 7, 5, 6, 3, 4 }, /* 8ch: FL FC FR SL SR BL BR LFE > FL FR FC LFE BL BR SL SR */
|
||||
};
|
||||
|
||||
void reset_ogg_vorbis(VGMSTREAM *vgmstream) {
|
||||
OggVorbis_File *ogg_vorbis_file;
|
||||
ogg_vorbis_codec_data *data = vgmstream->codec_data;
|
||||
if (!data) return;
|
||||
/* converts from internal Vorbis format to standard PCM and remaps (mostly from Xiph's decoder_example.c) */
|
||||
static void pcm_convert_float_to_16(int channels, sample_t * outbuf, int samples_to_do, float ** pcm) {
|
||||
int ch, s, ch_map;
|
||||
sample_t *ptr;
|
||||
float *channel;
|
||||
|
||||
ogg_vorbis_file = &(data->ogg_vorbis_file);
|
||||
/* convert float PCM (multichannel float array, with pcm[0]=ch0, pcm[1]=ch1, pcm[2]=ch0, etc)
|
||||
* to 16 bit signed PCM ints (host order) and interleave + fix clipping */
|
||||
for (ch = 0; ch < channels; ch++) {
|
||||
ch_map = (channels > 8) ? ch : xiph_channel_map[channels - 1][ch]; /* put Vorbis' ch to other outbuf's ch */
|
||||
ptr = outbuf + ch;
|
||||
channel = pcm[ch_map];
|
||||
for (s = 0; s < samples_to_do; s++) {
|
||||
int val = (int)floor(channel[s] * 32767.0f + 0.5f); /* use floorf? doesn't seem any faster */
|
||||
if (val > 32767) val = 32767;
|
||||
else if (val < -32768) val = -32768;
|
||||
|
||||
ov_pcm_seek(ogg_vorbis_file, 0);
|
||||
}
|
||||
|
||||
void seek_ogg_vorbis(VGMSTREAM *vgmstream, int32_t num_sample) {
|
||||
OggVorbis_File *ogg_vorbis_file;
|
||||
ogg_vorbis_codec_data *data = (ogg_vorbis_codec_data *)(vgmstream->codec_data);
|
||||
if (!data) return;
|
||||
|
||||
ogg_vorbis_file = &(data->ogg_vorbis_file);
|
||||
|
||||
ov_pcm_seek_lap(ogg_vorbis_file, num_sample);
|
||||
}
|
||||
|
||||
void free_ogg_vorbis(ogg_vorbis_codec_data *data) {
|
||||
if (data) {
|
||||
OggVorbis_File *ogg_vorbis_file = &(data->ogg_vorbis_file);
|
||||
|
||||
ov_clear(ogg_vorbis_file);
|
||||
|
||||
close_streamfile(data->ov_streamfile.streamfile);
|
||||
free(data);
|
||||
*ptr = val;
|
||||
ptr += channels;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ********************************************** */
|
||||
|
||||
void reset_ogg_vorbis(VGMSTREAM *vgmstream) {
|
||||
ogg_vorbis_codec_data *data = vgmstream->codec_data;
|
||||
if (!data) return;
|
||||
|
||||
ov_pcm_seek(&data->ogg_vorbis_file, 0);
|
||||
}
|
||||
|
||||
void seek_ogg_vorbis(VGMSTREAM *vgmstream, int32_t num_sample) {
|
||||
ogg_vorbis_codec_data *data = vgmstream->codec_data;
|
||||
if (!data) return;
|
||||
|
||||
ov_pcm_seek_lap(&data->ogg_vorbis_file, num_sample);
|
||||
}
|
||||
|
||||
void free_ogg_vorbis(ogg_vorbis_codec_data *data) {
|
||||
if (!data) return;
|
||||
|
||||
ov_clear(&data->ogg_vorbis_file);
|
||||
|
||||
close_streamfile(data->ov_streamfile.streamfile);
|
||||
free(data);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -2,7 +2,7 @@
|
||||
#include "../util.h"
|
||||
#include <math.h>
|
||||
|
||||
void decode_pcm16le(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
void decode_pcm16le(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
int i;
|
||||
int32_t sample_count;
|
||||
|
||||
@ -11,7 +11,7 @@ void decode_pcm16le(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspaci
|
||||
}
|
||||
}
|
||||
|
||||
void decode_pcm16be(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
void decode_pcm16be(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
int i;
|
||||
int32_t sample_count;
|
||||
|
||||
@ -20,7 +20,7 @@ void decode_pcm16be(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspaci
|
||||
}
|
||||
}
|
||||
|
||||
void decode_pcm16_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int big_endian) {
|
||||
void decode_pcm16_int(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int big_endian) {
|
||||
int i, sample_count;
|
||||
int16_t (*read_16bit)(off_t,STREAMFILE*) = big_endian ? read_16bitBE : read_16bitLE;
|
||||
|
||||
@ -29,7 +29,7 @@ void decode_pcm16_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspa
|
||||
}
|
||||
}
|
||||
|
||||
void decode_pcm8(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
void decode_pcm8(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
int i;
|
||||
int32_t sample_count;
|
||||
|
||||
@ -38,7 +38,7 @@ void decode_pcm8(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing,
|
||||
}
|
||||
}
|
||||
|
||||
void decode_pcm8_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
void decode_pcm8_int(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
int i;
|
||||
int32_t sample_count;
|
||||
|
||||
@ -47,7 +47,7 @@ void decode_pcm8_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspac
|
||||
}
|
||||
}
|
||||
|
||||
void decode_pcm8_unsigned(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
void decode_pcm8_unsigned(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
int i;
|
||||
int32_t sample_count;
|
||||
|
||||
@ -57,7 +57,7 @@ void decode_pcm8_unsigned(VGMSTREAMCHANNEL * stream, sample * outbuf, int channe
|
||||
}
|
||||
}
|
||||
|
||||
void decode_pcm8_unsigned_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
void decode_pcm8_unsigned_int(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
int i;
|
||||
int32_t sample_count;
|
||||
|
||||
@ -67,7 +67,7 @@ void decode_pcm8_unsigned_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int ch
|
||||
}
|
||||
}
|
||||
|
||||
void decode_pcm8_sb(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
void decode_pcm8_sb(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
int i;
|
||||
int32_t sample_count;
|
||||
|
||||
@ -78,7 +78,7 @@ void decode_pcm8_sb(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspaci
|
||||
}
|
||||
}
|
||||
|
||||
void decode_pcm4(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
|
||||
void decode_pcm4(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
|
||||
int i, nibble_shift, is_high_first, is_stereo;
|
||||
int32_t sample_count;
|
||||
int16_t v;
|
||||
@ -101,7 +101,7 @@ void decode_pcm4(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outb
|
||||
}
|
||||
}
|
||||
|
||||
void decode_pcm4_unsigned(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
|
||||
void decode_pcm4_unsigned(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
|
||||
int i, nibble_shift, is_high_first, is_stereo;
|
||||
int32_t sample_count;
|
||||
int16_t v;
|
||||
@ -125,7 +125,7 @@ void decode_pcm4_unsigned(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, samp
|
||||
}
|
||||
|
||||
static int expand_ulaw(uint8_t ulawbyte) {
|
||||
int sign, segment, quantization, new_sample;
|
||||
int sign, segment, quantization, sample;
|
||||
const int bias = 0x84;
|
||||
|
||||
ulawbyte = ~ulawbyte; /* stored in complement */
|
||||
@ -133,9 +133,9 @@ static int expand_ulaw(uint8_t ulawbyte) {
|
||||
segment = (ulawbyte & 0x70) >> 4; /* exponent */
|
||||
quantization = ulawbyte & 0x0F; /* mantissa */
|
||||
|
||||
new_sample = (quantization << 3) + bias; /* add bias */
|
||||
new_sample <<= segment;
|
||||
new_sample = (sign) ? (bias - new_sample) : (new_sample - bias); /* remove bias */
|
||||
sample = (quantization << 3) + bias; /* add bias */
|
||||
sample <<= segment;
|
||||
sample = (sign) ? (bias - sample) : (sample - bias); /* remove bias */
|
||||
|
||||
#if 0 // the above follows Sun's implementation, but this works too
|
||||
{
|
||||
@ -145,11 +145,11 @@ static int expand_ulaw(uint8_t ulawbyte) {
|
||||
}
|
||||
#endif
|
||||
|
||||
return new_sample;
|
||||
return sample;
|
||||
}
|
||||
|
||||
/* decodes u-law (ITU G.711 non-linear PCM), from g711.c */
|
||||
void decode_ulaw(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
void decode_ulaw(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
int i, sample_count;
|
||||
|
||||
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
|
||||
@ -159,7 +159,7 @@ void decode_ulaw(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing,
|
||||
}
|
||||
|
||||
|
||||
void decode_ulaw_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
void decode_ulaw_int(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
int i, sample_count;
|
||||
|
||||
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
|
||||
@ -169,33 +169,33 @@ void decode_ulaw_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspac
|
||||
}
|
||||
|
||||
static int expand_alaw(uint8_t alawbyte) {
|
||||
int sign, segment, quantization, new_sample;
|
||||
int sign, segment, quantization, sample;
|
||||
|
||||
alawbyte ^= 0x55;
|
||||
sign = (alawbyte & 0x80);
|
||||
segment = (alawbyte & 0x70) >> 4; /* exponent */
|
||||
quantization = alawbyte & 0x0F; /* mantissa */
|
||||
|
||||
new_sample = (quantization << 4);
|
||||
sample = (quantization << 4);
|
||||
switch (segment) {
|
||||
case 0:
|
||||
new_sample += 8;
|
||||
sample += 8;
|
||||
break;
|
||||
case 1:
|
||||
new_sample += 0x108;
|
||||
sample += 0x108;
|
||||
break;
|
||||
default:
|
||||
new_sample += 0x108;
|
||||
new_sample <<= segment - 1;
|
||||
sample += 0x108;
|
||||
sample <<= segment - 1;
|
||||
break;
|
||||
}
|
||||
new_sample = (sign) ? new_sample : -new_sample;
|
||||
sample = (sign) ? sample : -sample;
|
||||
|
||||
return new_sample;
|
||||
return sample;
|
||||
}
|
||||
|
||||
/* decodes a-law (ITU G.711 non-linear PCM), from g711.c */
|
||||
void decode_alaw(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
void decode_alaw(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
int i, sample_count;
|
||||
|
||||
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
|
||||
@ -204,7 +204,7 @@ void decode_alaw(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing,
|
||||
}
|
||||
}
|
||||
|
||||
void decode_pcmfloat(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int big_endian) {
|
||||
void decode_pcmfloat(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int big_endian) {
|
||||
int i, sample_count;
|
||||
int32_t (*read_32bit)(off_t,STREAMFILE*) = big_endian ? read_32bitBE : read_32bitLE;
|
||||
|
||||
|
@ -7,7 +7,7 @@
|
||||
|
||||
#define VORBIS_DEFAULT_BUFFER_SIZE 0x8000 /* should be at least the size of the setup header, ~0x2000 */
|
||||
|
||||
static void pcm_convert_float_to_16(vorbis_custom_codec_data * data, sample * outbuf, int samples_to_do, float ** pcm);
|
||||
static void pcm_convert_float_to_16(int channels, sample_t * outbuf, int samples_to_do, float ** pcm);
|
||||
|
||||
/**
|
||||
* Inits a vorbis stream of some custom variety.
|
||||
@ -75,7 +75,7 @@ fail:
|
||||
}
|
||||
|
||||
/* Decodes Vorbis packets into a libvorbis sample buffer, and copies them to outbuf */
|
||||
void decode_vorbis_custom(VGMSTREAM * vgmstream, sample * outbuf, int32_t samples_to_do, int channels) {
|
||||
void decode_vorbis_custom(VGMSTREAM * vgmstream, sample_t * outbuf, int32_t samples_to_do, int channels) {
|
||||
VGMSTREAMCHANNEL *stream = &vgmstream->ch[0];
|
||||
vorbis_custom_codec_data * data = vgmstream->codec_data;
|
||||
size_t stream_size = get_streamfile_size(stream->streamfile);
|
||||
@ -112,7 +112,7 @@ void decode_vorbis_custom(VGMSTREAM * vgmstream, sample * outbuf, int32_t sample
|
||||
/* get max samples and convert from Vorbis float pcm to 16bit pcm */
|
||||
if (samples_to_get > samples_to_do - samples_done)
|
||||
samples_to_get = samples_to_do - samples_done;
|
||||
pcm_convert_float_to_16(data, outbuf + samples_done * channels, samples_to_get, pcm);
|
||||
pcm_convert_float_to_16(data->vi.channels, outbuf + samples_done * channels, samples_to_get, pcm);
|
||||
samples_done += samples_to_get;
|
||||
}
|
||||
|
||||
@ -167,21 +167,24 @@ decode_fail:
|
||||
}
|
||||
|
||||
/* converts from internal Vorbis format to standard PCM (mostly from Xiph's decoder_example.c) */
|
||||
static void pcm_convert_float_to_16(vorbis_custom_codec_data * data, sample * outbuf, int samples_to_do, float ** pcm) {
|
||||
int i,j;
|
||||
static void pcm_convert_float_to_16(int channels, sample_t * outbuf, int samples_to_do, float ** pcm) {
|
||||
int ch, s;
|
||||
sample_t *ptr;
|
||||
float *channel;
|
||||
|
||||
/* convert float PCM (multichannel float array, with pcm[0]=ch0, pcm[1]=ch1, pcm[2]=ch0, etc)
|
||||
* to 16 bit signed PCM ints (host order) and interleave + fix clipping */
|
||||
for (i = 0; i < data->vi.channels; i++) {
|
||||
sample *ptr = outbuf + i;
|
||||
float *mono = pcm[i];
|
||||
for (j = 0; j < samples_to_do; j++) {
|
||||
int val = (int)floor(mono[j] * 32767.f + .5f);
|
||||
for (ch = 0; ch < channels; ch++) {
|
||||
/* channels should be in standard order unlike Ogg Vorbis (at least in FSB) */
|
||||
ptr = outbuf + ch;
|
||||
channel = pcm[ch];
|
||||
for (s = 0; s < samples_to_do; s++) {
|
||||
int val = (int)floor(channel[s] * 32767.0f + 0.5f);
|
||||
if (val > 32767) val = 32767;
|
||||
if (val < -32768) val = -32768;
|
||||
else if (val < -32768) val = -32768;
|
||||
|
||||
*ptr = val;
|
||||
ptr += data->vi.channels;
|
||||
ptr += channels;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,11 @@ static const unsigned int scale_step[16] = {
|
||||
230, 230, 230, 230, 307, 409, 512, 614
|
||||
};
|
||||
|
||||
/* actually implemented with if-else/switchs but that's too goofy */
|
||||
static const int scale_step_aska[8] = {
|
||||
57, 57, 57, 57, 77, 102, 128, 153,
|
||||
};
|
||||
|
||||
/* expand an unsigned four bit delta to a wider signed range */
|
||||
static const int scale_delta[16] = {
|
||||
1, 3, 5, 7, 9, 11, 13, 15,
|
||||
@ -15,8 +20,9 @@ static const int scale_delta[16] = {
|
||||
};
|
||||
|
||||
|
||||
/* raw Yamaha ADPCM a.k.a AICA as it's mainly used in Naomi/Dreamcast (also in RIFF and older arcade sound chips). */
|
||||
void decode_aica(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, int is_stereo) {
|
||||
/* raw Yamaha ADPCM a.k.a AICA as it's prominently used in Naomi/Dreamcast's Yamaha AICA sound chip,
|
||||
* also found in Windows RIFF and older Yamaha's arcade sound chips. */
|
||||
void decode_yamaha(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, int is_stereo) {
|
||||
int i, sample_count;
|
||||
|
||||
int32_t hist1 = stream->adpcm_history1_16;
|
||||
@ -52,9 +58,8 @@ void decode_aica(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing,
|
||||
stream->adpcm_step_index = step_size;
|
||||
}
|
||||
|
||||
/* Yamaha ADPCM, in headered frames like MS-IMA. Possibly originated from Yamaha's SMAF tools
|
||||
* (Windows ACM encoder/decoder was given in their site). Some info from Rockbox's yamaha_adpcm.c */
|
||||
void decode_yamaha(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
|
||||
/* tri-Ace Aska ADPCM, same-ish with modified step table (reversed from Android SO's .so) */
|
||||
void decode_aska(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
|
||||
int i, sample_count, num_frame;
|
||||
int32_t hist1 = stream->adpcm_history1_32;
|
||||
int step_size = stream->adpcm_step_index;
|
||||
@ -84,15 +89,15 @@ void decode_yamaha(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacin
|
||||
(!(channel&1) ? 0:4) :
|
||||
(!(i&1) ? 0:4); /* even = low, odd = high */
|
||||
|
||||
/* Yamaha/AICA expand, but same result as IMA's (((delta * 2 + 1) * step) >> 3) */
|
||||
sample_nibble = (read_8bit(byte_offset,stream->streamfile) >> nibble_shift)&0xf;
|
||||
sample_delta = (step_size * scale_delta[sample_nibble]) / 8;
|
||||
sample_nibble = (read_8bit(byte_offset,stream->streamfile) >> nibble_shift) & 0xf;
|
||||
sample_delta = ((((sample_nibble & 0x7) * 2) | 1) * step_size) >> 3; /* like 'mul' IMA with 'or' */
|
||||
if (sample_nibble & 8) sample_delta = -sample_delta;
|
||||
sample_decoded = hist1 + sample_delta;
|
||||
|
||||
outbuf[sample_count] = clamp16(sample_decoded);
|
||||
outbuf[sample_count] = sample_decoded; /* not clamped */
|
||||
hist1 = outbuf[sample_count];
|
||||
|
||||
step_size = (step_size * scale_step[sample_nibble]) >> 8;
|
||||
step_size = (step_size * scale_step_aska[sample_nibble & 0x07]) >> 6;
|
||||
if (step_size < 0x7f) step_size = 0x7f;
|
||||
if (step_size > 0x6000) step_size = 0x6000;
|
||||
}
|
||||
@ -102,7 +107,7 @@ void decode_yamaha(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacin
|
||||
}
|
||||
|
||||
/* Yamaha ADPCM with unknown expand variation (noisy), step size is double of normal Yamaha? */
|
||||
void decode_yamaha_nxap(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
void decode_nxap(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
int i, sample_count, num_frame;
|
||||
int32_t hist1 = stream->adpcm_history1_32;
|
||||
int step_size = stream->adpcm_step_index;
|
||||
@ -145,12 +150,12 @@ void decode_yamaha_nxap(VGMSTREAMCHANNEL * stream, sample * outbuf, int channels
|
||||
stream->adpcm_step_index = step_size;
|
||||
}
|
||||
|
||||
size_t aica_bytes_to_samples(size_t bytes, int channels) {
|
||||
size_t yamaha_bytes_to_samples(size_t bytes, int channels) {
|
||||
/* 2 samples per byte (2 nibbles) in stereo or mono config */
|
||||
return bytes * 2 / channels;
|
||||
}
|
||||
|
||||
size_t yamaha_bytes_to_samples(size_t bytes, int channels) {
|
||||
size_t aska_bytes_to_samples(size_t bytes, int channels) {
|
||||
int block_align = 0x40;
|
||||
|
||||
return (bytes / block_align) * (block_align - 0x04*channels) * 2 / channels
|
||||
|
@ -367,7 +367,6 @@ static const char* extension_list[] = {
|
||||
"sbin",
|
||||
"sc",
|
||||
"scd",
|
||||
"sck",
|
||||
"sd9",
|
||||
"sdf",
|
||||
"sdt",
|
||||
@ -632,10 +631,10 @@ static const coding_info coding_info_list[] = {
|
||||
{coding_MSADPCM_int, "Microsoft 4-bit ADPCM (mono/interleave)"},
|
||||
{coding_MSADPCM_ck, "Microsoft 4-bit ADPCM (Cricket Audio)"},
|
||||
{coding_WS, "Westwood Studios VBR ADPCM"},
|
||||
{coding_AICA, "Yamaha 4-bit ADPCM"},
|
||||
{coding_AICA_int, "Yamaha 4-bit ADPCM (mono/interleave)"},
|
||||
{coding_YAMAHA, "Yamaha 4-bit ADPCM (framed)"},
|
||||
{coding_YAMAHA_NXAP, "Yamaha NXAP 4-bit ADPCM"},
|
||||
{coding_YAMAHA, "Yamaha 4-bit ADPCM"},
|
||||
{coding_YAMAHA_int, "Yamaha 4-bit ADPCM (mono/interleave)"},
|
||||
{coding_ASKA, "tri-Ace Aska 4-bit ADPCM"},
|
||||
{coding_NXAP, "Nex NXAP 4-bit ADPCM"},
|
||||
{coding_NDS_PROCYON, "Procyon Studio Digital Sound Elements NDS 4-bit APDCM"},
|
||||
{coding_L5_555, "Level-5 0x555 4-bit ADPCM"},
|
||||
{coding_LSF, "lsf 4-bit ADPCM"},
|
||||
@ -922,7 +921,7 @@ static const meta_info meta_info_list[] = {
|
||||
{meta_NGC_SSM, "SSM DSP Header"},
|
||||
{meta_PS2_JOE, "Asobo Studio .JOE header"},
|
||||
{meta_VGS, "Guitar Hero VGS Header"},
|
||||
{meta_DC_DCSW_DCS, "Evil Twin DCS file with helper"},
|
||||
{meta_DCS_WAV, "In Utero DCS+WAV header"},
|
||||
{meta_SMP, "Infernal Engine .smp header"},
|
||||
{meta_MUL, "Crystal Dynamics .MUL header"},
|
||||
{meta_THP, "THP Movie File Format Header"},
|
||||
|
@ -176,9 +176,11 @@ void reset_layout_segmented(segmented_layout_data *data) {
|
||||
/* helper for easier creation of segments */
|
||||
VGMSTREAM *allocate_segmented_vgmstream(segmented_layout_data* data, int loop_flag, int loop_start_segment, int loop_end_segment) {
|
||||
VGMSTREAM *vgmstream;
|
||||
int channel_layout;
|
||||
int i, num_samples, loop_start, loop_end;
|
||||
|
||||
/* get data */
|
||||
/* save data */
|
||||
channel_layout = data->segments[0]->channel_layout;
|
||||
num_samples = 0;
|
||||
loop_start = 0;
|
||||
loop_end = 0;
|
||||
@ -190,6 +192,10 @@ VGMSTREAM *allocate_segmented_vgmstream(segmented_layout_data* data, int loop_fl
|
||||
|
||||
if (loop_flag && i == loop_end_segment)
|
||||
loop_end = num_samples;
|
||||
|
||||
/* inherit first segment's layout but only if all segments' layout match */
|
||||
if (channel_layout != 0 && channel_layout != data->segments[i]->channel_layout)
|
||||
channel_layout = 0;
|
||||
}
|
||||
|
||||
/* respect loop_flag even when no loop_end found as it's possible file loops are set outside */
|
||||
@ -204,6 +210,7 @@ VGMSTREAM *allocate_segmented_vgmstream(segmented_layout_data* data, int loop_fl
|
||||
vgmstream->loop_start_sample = loop_start;
|
||||
vgmstream->loop_end_sample = loop_end;
|
||||
vgmstream->coding_type = data->segments[0]->coding_type;
|
||||
vgmstream->channel_layout = channel_layout;
|
||||
|
||||
vgmstream->layout_type = layout_segmented;
|
||||
vgmstream->layout_data = data;
|
||||
|
@ -477,7 +477,7 @@
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\meta\dc_dcsw_dcs.c"
|
||||
RelativePath=".\meta\dcs_wav.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
|
@ -242,7 +242,7 @@
|
||||
<ClCompile Include="meta\csmp.c" />
|
||||
<ClCompile Include="meta\cstr.c" />
|
||||
<ClCompile Include="meta\dc_asd.c" />
|
||||
<ClCompile Include="meta\dc_dcsw_dcs.c" />
|
||||
<ClCompile Include="meta\dcs_wav.c" />
|
||||
<ClCompile Include="meta\dc_idvi.c" />
|
||||
<ClCompile Include="meta\dc_kcey.c" />
|
||||
<ClCompile Include="meta\dc_str.c" />
|
||||
|
@ -301,7 +301,7 @@
|
||||
<ClCompile Include="meta\dc_asd.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="meta\dc_dcsw_dcs.c">
|
||||
<ClCompile Include="meta\dcs_wav.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="meta\dc_idvi.c">
|
||||
|
@ -1,119 +0,0 @@
|
||||
#include "meta.h"
|
||||
#include "../util.h"
|
||||
|
||||
/* WAV+DCS (DCSW+DCS)
|
||||
2008-12-06 - manakoAT : Evil Twin - Cypriens Chronicles...
|
||||
2008-12-07 - manakoAT : Added a function to read the Header file and for
|
||||
retrieving the channels/frequency, Frequency starts
|
||||
always at a "data" chunk - 0x0C bytes, Channels
|
||||
always - 0x0E bytes...
|
||||
2010-01-13 - manakoAT : Changed the 'Helper' extension from .wav to .dcws, to prevent conflicts */
|
||||
|
||||
VGMSTREAM * init_vgmstream_dc_dcsw_dcs(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
STREAMFILE * streamFileDCSW = NULL;
|
||||
char filename[PATH_LIMIT];
|
||||
char filenameDCSW[PATH_LIMIT];
|
||||
int i;
|
||||
int channel_count;
|
||||
int loop_flag;
|
||||
int frequency;
|
||||
int dataBuffer = 0;
|
||||
int Founddata = 0;
|
||||
size_t file_size;
|
||||
off_t current_chunk;
|
||||
|
||||
/* check extension, case insensitive */
|
||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||
if (strcasecmp("dcs",filename_extension(filename))) goto fail;
|
||||
|
||||
/* Getting the Header file name... */
|
||||
strcpy(filenameDCSW,filename);
|
||||
strcpy(filenameDCSW+strlen(filenameDCSW)-3,"dcsw");
|
||||
|
||||
/* Look if the Header file is present, else cancel vgmstream */
|
||||
streamFileDCSW = streamFile->open(streamFile,filenameDCSW,STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
if (!streamFileDCSW) goto fail;
|
||||
|
||||
/* check header */
|
||||
if (read_32bitBE(0x00,streamFileDCSW) != 0x52494646 || /* "RIFF" */
|
||||
read_32bitBE(0x08,streamFileDCSW) != 0x57415645 || /* "WAVE" */
|
||||
read_32bitBE(0x0C,streamFileDCSW) != 0x34582E76 || /* 0x34582E76 */
|
||||
read_32bitBE(0x3C,streamFileDCSW) != 0x406E616D) /* "@nam" */
|
||||
goto fail;
|
||||
|
||||
/* scan file until we find a "data" string */
|
||||
file_size = get_streamfile_size(streamFileDCSW);
|
||||
{
|
||||
current_chunk = 0;
|
||||
/* Start at 0 and loop until we reached the
|
||||
file size, or until we found a "data string */
|
||||
while (!Founddata && current_chunk < file_size) {
|
||||
dataBuffer = (read_32bitBE(current_chunk,streamFileDCSW));
|
||||
if (dataBuffer == 0x64617461) { /* "data" */
|
||||
/* if "data" string found, retrieve the needed infos */
|
||||
Founddata = 1;
|
||||
/* We will cancel the search here if we have a match */
|
||||
break;
|
||||
}
|
||||
/* else we will increase the search offset by 1 */
|
||||
current_chunk = current_chunk + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (Founddata == 0) {
|
||||
goto fail;
|
||||
} else if (Founddata == 1) {
|
||||
channel_count = (uint16_t)read_16bitLE(current_chunk-0x0E,streamFileDCSW);
|
||||
frequency = read_32bitLE(current_chunk-0x0C,streamFileDCSW);
|
||||
}
|
||||
|
||||
loop_flag = 0;
|
||||
|
||||
/* Seems we're dealing with a vaild file+header,
|
||||
now we can finally build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
/* fill in the vital statistics */
|
||||
vgmstream->channels = channel_count;
|
||||
vgmstream->sample_rate = frequency;
|
||||
vgmstream->num_samples=(get_streamfile_size(streamFile))*2/channel_count;
|
||||
|
||||
if(loop_flag) {
|
||||
vgmstream->loop_start_sample = 0;
|
||||
vgmstream->loop_end_sample = (get_streamfile_size(streamFile))*2/channel_count;
|
||||
}
|
||||
|
||||
if (channel_count == 1) {
|
||||
vgmstream->layout_type = layout_none;
|
||||
} else if (channel_count > 1) {
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x4000;
|
||||
}
|
||||
|
||||
vgmstream->coding_type = coding_AICA_int;
|
||||
vgmstream->meta_type = meta_DC_DCSW_DCS;
|
||||
|
||||
/* open the file for reading by each channel */
|
||||
{
|
||||
for (i=0;i<channel_count;i++) {
|
||||
vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
|
||||
if (!vgmstream->ch[i].streamfile) goto fail;
|
||||
vgmstream->ch[i].channel_start_offset=
|
||||
vgmstream->ch[i].offset=i*vgmstream->interleave_block_size;
|
||||
vgmstream->ch[i].adpcm_step_index = 0x7f; /* AICA */
|
||||
}
|
||||
}
|
||||
|
||||
close_streamfile(streamFileDCSW); streamFileDCSW=NULL;
|
||||
|
||||
return vgmstream;
|
||||
|
||||
/* clean up anything we may have opened */
|
||||
fail:
|
||||
if (streamFileDCSW) close_streamfile(streamFileDCSW);
|
||||
if (vgmstream) close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
@ -39,7 +39,7 @@ VGMSTREAM * init_vgmstream_dc_str(STREAMFILE *streamFile) {
|
||||
/* fill in the vital statistics */
|
||||
switch (samples) {
|
||||
case 4:
|
||||
vgmstream->coding_type = coding_AICA_int;
|
||||
vgmstream->coding_type = coding_YAMAHA_int;
|
||||
vgmstream->num_samples = read_32bitLE(0x14,streamFile);
|
||||
if (loop_flag) {
|
||||
vgmstream->loop_start_sample = 0;
|
||||
|
58
src/meta/dcs_wav.c
Normal file
58
src/meta/dcs_wav.c
Normal file
@ -0,0 +1,58 @@
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
|
||||
/* DCS+WAV - from In Utero games [Evil Twin: Cyprien's Chronicles (DC)] */
|
||||
VGMSTREAM * init_vgmstream_dcs_wav(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
STREAMFILE * streamHeader = NULL;
|
||||
int loop_flag, channel_count, sample_rate;
|
||||
off_t start_offset, fmt_offset;
|
||||
|
||||
|
||||
/* checks */
|
||||
if (!check_extensions(streamFile,"dcs"))
|
||||
goto fail;
|
||||
|
||||
streamHeader = open_streamfile_by_ext(streamFile, "wav");
|
||||
if (!streamHeader) goto fail;
|
||||
|
||||
/* a slightly funny RIFF */
|
||||
if (read_u32be(0x00,streamHeader) != 0x52494646 || /* "RIFF" */
|
||||
read_u32be(0x08,streamHeader) != 0x57415645 || /* "WAVE" */
|
||||
read_u32be(0x0C,streamHeader) != 0x34582E76 || /* "4X.v" */
|
||||
read_u32be(0x3C,streamHeader) != 0x406E616D) /* "@nam" */
|
||||
goto fail;
|
||||
|
||||
fmt_offset = 0x44 + read_32bitLE(0x40,streamHeader); /* skip @nam */
|
||||
if (fmt_offset % 2) fmt_offset += 1;
|
||||
if (read_u32be(fmt_offset,streamHeader) != 0x666D7420) goto fail; /* "fmt " */
|
||||
fmt_offset += 0x04+0x04;
|
||||
|
||||
if (read_u16le(fmt_offset+0x00,streamHeader) != 0x0005) goto fail; /* unofficial format */
|
||||
channel_count = read_u16le(fmt_offset+0x02,streamHeader);
|
||||
sample_rate = read_u32le(fmt_offset+0x04,streamHeader);
|
||||
loop_flag = 0;
|
||||
start_offset = 0x00;
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->meta_type = meta_DCS_WAV;
|
||||
vgmstream->sample_rate = sample_rate;
|
||||
vgmstream->num_samples = yamaha_bytes_to_samples(get_streamfile_size(streamFile), channel_count);
|
||||
vgmstream->coding_type = coding_YAMAHA_int;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x4000;
|
||||
|
||||
if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) )
|
||||
goto fail;
|
||||
close_streamfile(streamHeader);
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_streamfile(streamHeader);
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
@ -857,7 +857,9 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST
|
||||
switch(eaac.channel_config) {
|
||||
case 0x00: eaac.channels = 1; break;
|
||||
case 0x01: eaac.channels = 2; break;
|
||||
case 0x02: eaac.channels = 3; break; /* rare [Battlefield 4 (X360)-EAXMA] */
|
||||
case 0x03: eaac.channels = 4; break;
|
||||
case 0x04: eaac.channels = 5; break; /* rare [Battlefield 4 (X360)-EAXMA] */
|
||||
case 0x05: eaac.channels = 6; break;
|
||||
case 0x07: eaac.channels = 8; break;
|
||||
case 0x0a: eaac.channels = 11; break; /* rare [Army of Two: The Devil's Cartel (PS3)-EALayer3v2P] */
|
||||
|
@ -66,6 +66,8 @@ VGMSTREAM * init_vgmstream_ffmpeg_offset(STREAMFILE *streamFile, uint64_t start,
|
||||
if (vgmstream->num_samples <= 0)
|
||||
goto fail;
|
||||
|
||||
vgmstream->channel_layout = ffmpeg_get_channel_layout(vgmstream->codec_data);
|
||||
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
|
@ -16,7 +16,7 @@ typedef enum {
|
||||
DVI_IMA = 7, /* DVI IMA ADPCM (high nibble first) */
|
||||
MPEG = 8, /* MPEG (MP3) */
|
||||
IMA = 9, /* IMA ADPCM (low nibble first) */
|
||||
AICA = 10, /* AICA ADPCM (Dreamcast games) */
|
||||
YAMAHA = 10, /* YAMAHA (AICA) ADPCM (Dreamcast games) */
|
||||
MSADPCM = 11, /* MS ADPCM (Windows games) */
|
||||
NGC_DSP = 12, /* NGC DSP (Nintendo games) */
|
||||
PCM8_U_int = 13, /* 8-bit unsigned PCM (interleaved) */
|
||||
@ -101,7 +101,7 @@ VGMSTREAM * init_vgmstream_genh(STREAMFILE *streamFile) {
|
||||
case MPEG: coding = coding_MPEG_layer3; break; /* we later find out exactly which */
|
||||
#endif
|
||||
case IMA: coding = coding_IMA; break;
|
||||
case AICA: coding = coding_AICA; break;
|
||||
case YAMAHA: coding = coding_YAMAHA; break;
|
||||
case MSADPCM: coding = coding_MSADPCM; break;
|
||||
case NGC_DSP: coding = coding_NGC_DSP; break;
|
||||
case PCM8_U_int: coding = coding_PCM8_U_int; break;
|
||||
@ -151,7 +151,7 @@ VGMSTREAM * init_vgmstream_genh(STREAMFILE *streamFile) {
|
||||
case coding_PSX_badflags:
|
||||
case coding_DVI_IMA:
|
||||
case coding_IMA:
|
||||
case coding_AICA:
|
||||
case coding_YAMAHA:
|
||||
case coding_APPLE_IMA4:
|
||||
vgmstream->interleave_block_size = genh.interleave;
|
||||
vgmstream->interleave_last_block_size = genh.interleave_last;
|
||||
@ -170,8 +170,8 @@ VGMSTREAM * init_vgmstream_genh(STREAMFILE *streamFile) {
|
||||
coding = coding_DVI_IMA_int;
|
||||
if (coding == coding_IMA)
|
||||
coding = coding_IMA_int;
|
||||
if (coding == coding_AICA)
|
||||
coding = coding_AICA_int;
|
||||
if (coding == coding_YAMAHA)
|
||||
coding = coding_YAMAHA_int;
|
||||
}
|
||||
|
||||
/* to avoid endless loops */
|
||||
@ -188,7 +188,7 @@ VGMSTREAM * init_vgmstream_genh(STREAMFILE *streamFile) {
|
||||
}
|
||||
|
||||
/* setup adpcm */
|
||||
if (coding == coding_AICA || coding == coding_AICA_int) {
|
||||
if (coding == coding_YAMAHA || coding == coding_YAMAHA_int) {
|
||||
int ch;
|
||||
for (ch = 0; ch < vgmstream->channels; ch++) {
|
||||
vgmstream->ch[ch].adpcm_step_index = 0x7f;
|
||||
|
@ -359,7 +359,7 @@ VGMSTREAM * init_vgmstream_ps2_joe(STREAMFILE * streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_vgs(STREAMFILE * streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_dc_dcsw_dcs(STREAMFILE * streamFile);
|
||||
VGMSTREAM * init_vgmstream_dcs_wav(STREAMFILE * streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_mul(STREAMFILE * streamFile);
|
||||
|
||||
|
@ -216,12 +216,13 @@ VGMSTREAM * init_vgmstream_mp4_aac_ffmpeg(STREAMFILE *streamFile) {
|
||||
vgmstream->layout_type = layout_none;
|
||||
vgmstream->meta_type = meta_MP4;
|
||||
|
||||
vgmstream->num_samples = ffmpeg_data->totalSamples;
|
||||
vgmstream->sample_rate = ffmpeg_data->sampleRate;
|
||||
vgmstream->channels = ffmpeg_data->channels;
|
||||
vgmstream->num_samples = ffmpeg_data->totalSamples;
|
||||
vgmstream->loop_start_sample = loop_start_sample;
|
||||
vgmstream->loop_end_sample = loop_end_sample;
|
||||
|
||||
vgmstream->channel_layout = ffmpeg_get_channel_layout(vgmstream->codec_data);
|
||||
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
@ -233,11 +234,7 @@ fail:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Almost the same as streamfile.c's find_chunk but for "atom" chunks, which have chunk_size first because Apple.
|
||||
*
|
||||
* returns 0 on failure
|
||||
*/
|
||||
/* Almost the same as streamfile.c's find_chunk but for "atom" chunks, which have chunk_size first because Apple, returns 0 on failure */
|
||||
static int find_atom_be(STREAMFILE *streamFile, uint32_t atom_id, off_t start_offset, off_t *out_atom_offset, size_t *out_atom_size) {
|
||||
size_t filesize;
|
||||
off_t current_atom = start_offset;
|
||||
|
@ -27,9 +27,9 @@ VGMSTREAM * init_vgmstream_naomi_adpcm(STREAMFILE *streamFile) {
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->sample_rate = 44100;
|
||||
vgmstream->num_samples = aica_bytes_to_samples(data_size, channel_count);
|
||||
vgmstream->num_samples = yamaha_bytes_to_samples(data_size, channel_count);
|
||||
|
||||
vgmstream->coding_type = coding_AICA_int;
|
||||
vgmstream->coding_type = coding_YAMAHA_int;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = data_size / channel_count;
|
||||
vgmstream->meta_type = meta_NAOMI_ADPCM;
|
||||
|
@ -59,9 +59,9 @@ VGMSTREAM * init_vgmstream_naomi_spsd(STREAMFILE *streamFile) {
|
||||
break;
|
||||
|
||||
case 0x03: /* standard */
|
||||
vgmstream->coding_type = coding_AICA_int;
|
||||
vgmstream->num_samples = aica_bytes_to_samples(data_size,channel_count);
|
||||
vgmstream->loop_start_sample = /*read_32bitLE(0x2c,streamFile) +*/ aica_bytes_to_samples(0x2000*channel_count,channel_count);
|
||||
vgmstream->coding_type = coding_YAMAHA_int;
|
||||
vgmstream->num_samples = yamaha_bytes_to_samples(data_size,channel_count);
|
||||
vgmstream->loop_start_sample = /*read_32bitLE(0x2c,streamFile) +*/ yamaha_bytes_to_samples(0x2000*channel_count,channel_count);
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
break;
|
||||
|
||||
|
@ -1,98 +1,55 @@
|
||||
#include "meta.h"
|
||||
#include "../util.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
/*
|
||||
SCK+DSP
|
||||
2009-08-25 - manakoAT : Scorpion King (NGC)...
|
||||
*/
|
||||
|
||||
//todo this was extracted from a .pak bigfile. Inside are headers then data (no extensions),
|
||||
// but headers are VAGp in the PS2 version, so it would make more sense to extract pasting
|
||||
// header+data together, or support as-is (.SCK is a fake extension).
|
||||
|
||||
/* SCK+DSP - Scorpion King (GC) */
|
||||
VGMSTREAM * init_vgmstream_ngc_sck_dsp(STREAMFILE *streamFile) {
|
||||
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
STREAMFILE * streamFileDSP = NULL;
|
||||
char filename[PATH_LIMIT];
|
||||
char filenameDSP[PATH_LIMIT];
|
||||
|
||||
int i;
|
||||
int channel_count;
|
||||
int loop_flag;
|
||||
STREAMFILE * streamHeader = NULL;
|
||||
int channel_count, loop_flag;
|
||||
size_t data_size;
|
||||
|
||||
/* check extension, case insensitive */
|
||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||
if (strcasecmp("sck",filename_extension(filename))) goto fail;
|
||||
|
||||
|
||||
strcpy(filenameDSP,filename);
|
||||
strcpy(filenameDSP+strlen(filenameDSP)-3,"dsp");
|
||||
|
||||
streamFileDSP = streamFile->open(streamFile,filenameDSP,STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
|
||||
if (read_32bitBE(0x5C,streamFile) != 0x60A94000)
|
||||
if (!check_extensions(streamFile, "dsp"))
|
||||
goto fail;
|
||||
|
||||
if (!streamFile) goto fail;
|
||||
streamHeader = open_streamfile_by_ext(streamFile, "sck");
|
||||
if (!streamHeader) goto fail;
|
||||
|
||||
if (read_32bitBE(0x5C,streamHeader) != 0x60A94000)
|
||||
goto fail;
|
||||
|
||||
channel_count = 2;
|
||||
loop_flag = 0;
|
||||
data_size = read_32bitBE(0x14,streamHeader);
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
/* fill in the vital statistics */
|
||||
vgmstream->channels = channel_count;
|
||||
vgmstream->sample_rate = read_32bitBE(0x18,streamFile);
|
||||
vgmstream->num_samples=read_32bitBE(0x14,streamFile)/8/channel_count*14;
|
||||
vgmstream->sample_rate = read_32bitBE(0x18,streamHeader);
|
||||
vgmstream->num_samples = dsp_bytes_to_samples(data_size, channel_count);
|
||||
vgmstream->coding_type = coding_NGC_DSP;
|
||||
|
||||
if(loop_flag) {
|
||||
vgmstream->loop_start_sample = 0;
|
||||
vgmstream->loop_end_sample = read_32bitBE(0x10,streamFile)/8/channel_count*14;
|
||||
}
|
||||
|
||||
if (channel_count == 1) {
|
||||
vgmstream->layout_type = layout_none;
|
||||
} else if (channel_count == 2) {
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size=read_32bitBE(0xC,streamFile);
|
||||
}
|
||||
|
||||
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = read_32bitBE(0xC,streamHeader);
|
||||
if (vgmstream->interleave_block_size > 0)
|
||||
vgmstream->interleave_last_block_size = (data_size % (vgmstream->interleave_block_size * channel_count)) / channel_count;
|
||||
|
||||
vgmstream->meta_type = meta_NGC_SCK_DSP;
|
||||
|
||||
/* open the file for reading */
|
||||
{
|
||||
for (i=0;i<channel_count;i++) {
|
||||
/* Not sure, i'll put a fake value here for now */
|
||||
vgmstream->ch[i].streamfile = streamFile->open(streamFileDSP,filenameDSP,STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
vgmstream->ch[i].offset = 0;
|
||||
dsp_read_coefs_be(vgmstream,streamHeader, 0x2c, 0x00);
|
||||
|
||||
if (!vgmstream->ch[i].streamfile) goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (vgmstream->coding_type == coding_NGC_DSP) {
|
||||
int i;
|
||||
for (i=0;i<16;i++) {
|
||||
vgmstream->ch[0].adpcm_coef[i] = read_16bitBE(0x2C+i*2,streamFile);
|
||||
}
|
||||
if (vgmstream->channels == 2) {
|
||||
for (i=0;i<16;i++) {
|
||||
vgmstream->ch[1].adpcm_coef[i] = read_16bitBE(0x2C+i*2,streamFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
close_streamfile(streamFileDSP); streamFileDSP=NULL;
|
||||
if (!vgmstream_open_stream(vgmstream,streamFile,0x00))
|
||||
goto fail;
|
||||
close_streamfile(streamHeader);
|
||||
return vgmstream;
|
||||
|
||||
/* clean up anything we may have opened */
|
||||
fail:
|
||||
if (streamFileDSP) close_streamfile(streamFileDSP);
|
||||
if (vgmstream) close_vgmstream(vgmstream);
|
||||
close_streamfile(streamHeader);
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ VGMSTREAM * init_vgmstream_nxap(STREAMFILE *streamFile) {
|
||||
//vgmstream->loop_end_sample = vgmstream->loop_start_sample + vgmstream->loop_end_sample;
|
||||
|
||||
vgmstream->meta_type = meta_NXAP;
|
||||
vgmstream->coding_type = coding_YAMAHA_NXAP;
|
||||
vgmstream->coding_type = coding_NXAP;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x40;
|
||||
|
||||
|
@ -111,6 +111,7 @@ VGMSTREAM * init_vgmstream_ogg_opus(STREAMFILE *streamFile) {
|
||||
if (!vgmstream->codec_data) goto fail;
|
||||
vgmstream->coding_type = coding_FFmpeg;
|
||||
vgmstream->layout_type = layout_none;
|
||||
vgmstream->channel_layout = ffmpeg_get_channel_layout(vgmstream->codec_data);
|
||||
/* FFmpeg+libopus handles skip samples ok, FFmpeg+opus doesn't */
|
||||
}
|
||||
#else
|
||||
|
@ -275,6 +275,18 @@ static void lse_ff_ogg_decryption_callback(void *ptr, size_t size, size_t nmemb,
|
||||
}
|
||||
}
|
||||
|
||||
static const uint32_t xiph_mappings[] = {
|
||||
0,
|
||||
mapping_MONO,
|
||||
mapping_STEREO,
|
||||
mapping_2POINT1_xiph,
|
||||
mapping_QUAD,
|
||||
mapping_5POINT0_xiph,
|
||||
mapping_5POINT1,
|
||||
mapping_7POINT0,
|
||||
mapping_7POINT1,
|
||||
};
|
||||
|
||||
|
||||
/* Ogg Vorbis, by way of libvorbisfile; may contain loop comments */
|
||||
VGMSTREAM * init_vgmstream_ogg_vorbis(STREAMFILE *streamFile) {
|
||||
@ -634,6 +646,10 @@ VGMSTREAM * init_vgmstream_ogg_vorbis_callbacks(STREAMFILE *streamFile, ov_callb
|
||||
vgmstream->layout_type = layout_none;
|
||||
vgmstream->meta_type = ovmi->meta_type;
|
||||
|
||||
if (vgmstream->channels <= 8) {
|
||||
vgmstream->channel_layout = xiph_mappings[vgmstream->channels];
|
||||
}
|
||||
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
|
120
src/meta/riff.c
120
src/meta/riff.c
@ -87,6 +87,8 @@ typedef struct {
|
||||
int channel_count;
|
||||
uint32_t block_size;
|
||||
int bps;
|
||||
off_t extra_size;
|
||||
uint32_t channel_layout;
|
||||
|
||||
int coding_type;
|
||||
int interleave;
|
||||
@ -99,18 +101,30 @@ static int read_fmt(int big_endian, STREAMFILE * streamFile, off_t current_chunk
|
||||
fmt->offset = current_chunk;
|
||||
fmt->size = read_32bit(current_chunk+0x04,streamFile);
|
||||
|
||||
fmt->codec = (uint16_t)read_16bit(current_chunk+0x08,streamFile);
|
||||
fmt->sample_rate = read_32bit(current_chunk+0x0c,streamFile);
|
||||
fmt->channel_count = read_16bit(current_chunk+0x0a,streamFile);
|
||||
fmt->block_size = read_16bit(current_chunk+0x14,streamFile);
|
||||
fmt->bps = read_16bit(current_chunk+0x16,streamFile);
|
||||
fmt->interleave = 0;
|
||||
/* WAVEFORMAT */
|
||||
fmt->codec = (uint16_t)read_16bit(current_chunk+0x08,streamFile);
|
||||
fmt->channel_count = read_16bit(current_chunk+0x0a,streamFile);
|
||||
fmt->sample_rate = read_32bit(current_chunk+0x0c,streamFile);
|
||||
//fmt->avg_bps = read_32bit(current_chunk+0x10,streamFile);
|
||||
fmt->block_size = read_16bit(current_chunk+0x14,streamFile);
|
||||
fmt->bps = read_16bit(current_chunk+0x16,streamFile);
|
||||
/* WAVEFORMATEX */
|
||||
if (fmt->size >= 0x10) {
|
||||
fmt->extra_size = read_16bit(current_chunk+0x18,streamFile);
|
||||
/* 0x1a+ depends on codec (ex. coef table for MSADPCM, samples_per_frame in MS-IMA, etc) */
|
||||
}
|
||||
/* WAVEFORMATEXTENSIBLE */
|
||||
if (fmt->codec == 0xFFFE && fmt->extra_size >= 0x16) {
|
||||
//fmt->extra_samples = read_16bit(current_chunk+0x1a,streamFile); /* valid_bits_per_sample or samples_per_block */
|
||||
fmt->channel_layout = read_32bit(current_chunk+0x1c,streamFile);
|
||||
/* 0x10 guid at 0x20 */
|
||||
}
|
||||
|
||||
switch (fmt->codec) {
|
||||
case 0x00: /* Yamaha ADPCM (raw) [Headhunter (DC), Bomber hehhe (DC)] (unofficial) */
|
||||
if (fmt->bps != 4) goto fail;
|
||||
if (fmt->block_size != 0x02*fmt->channel_count) goto fail;
|
||||
fmt->coding_type = coding_AICA_int;
|
||||
fmt->coding_type = coding_YAMAHA_int;
|
||||
fmt->interleave = 0x01;
|
||||
break;
|
||||
|
||||
@ -148,7 +162,7 @@ static int read_fmt(int big_endian, STREAMFILE * streamFile, off_t current_chunk
|
||||
|
||||
case 0x20: /* Yamaha ADPCM (raw) [Takuyo/Dynamix/etc DC games] */
|
||||
if (fmt->bps != 4) goto fail;
|
||||
fmt->coding_type = coding_AICA;
|
||||
fmt->coding_type = coding_YAMAHA;
|
||||
break;
|
||||
|
||||
case 0x69: /* XBOX IMA ADPCM [Dynasty Warriors 5 (Xbox)] */
|
||||
@ -191,19 +205,34 @@ static int read_fmt(int big_endian, STREAMFILE * streamFile, off_t current_chunk
|
||||
goto fail;
|
||||
#endif
|
||||
|
||||
case 0xFFFE: /* WAVEFORMATEXTENSIBLE */
|
||||
case 0xFFFE: { /* WAVEFORMATEXTENSIBLE (see ksmedia.h for known GUIDs)*/
|
||||
uint32_t guid1 = (uint32_t)read_32bit (current_chunk+0x20,streamFile);
|
||||
uint32_t guid2 = ((uint16_t)read_16bit (current_chunk+0x24,streamFile) << 16u) |
|
||||
((uint16_t)read_16bit(current_chunk+0x26,streamFile));
|
||||
uint32_t guid3 = (uint32_t)read_32bitBE(current_chunk+0x28,streamFile);
|
||||
uint32_t guid4 = (uint32_t)read_32bitBE(current_chunk+0x2c,streamFile);
|
||||
//;VGM_LOG("RIFF: guid %08x %08x %08x %08x\n", guid1, guid2, guid3, guid4);
|
||||
|
||||
/* ATRAC3plus GUID (0xBFAA23E9 58CB7144 A119FFFA 01E4CE62) */
|
||||
if (read_32bit(current_chunk+0x20,streamFile) == 0xE923AABF &&
|
||||
read_16bit(current_chunk+0x24,streamFile) == (int16_t)0xCB58 &&
|
||||
read_16bit(current_chunk+0x26,streamFile) == 0x4471 &&
|
||||
read_32bitLE(current_chunk+0x28,streamFile) == 0xFAFF19A1 &&
|
||||
read_32bitLE(current_chunk+0x2C,streamFile) == 0x62CEE401) {
|
||||
/* PCM GUID (0x00000001,0000,0010,80,00,00,AA,00,38,9B,71) */
|
||||
if (guid1 == 0x00000001 && guid2 == 0x00000010 && guid3 == 0x800000AA && guid4 == 0x00389B71) {
|
||||
switch (fmt->bps) {
|
||||
case 16:
|
||||
fmt->coding_type = big_endian ? coding_PCM16BE : coding_PCM16LE;
|
||||
fmt->interleave = 0x02;
|
||||
break;
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* ATRAC3plus GUID (0xE923AABF,CB58,4471,A1,19,FF,FA,01,E4,CE,62) */
|
||||
if (guid1 == 0xE923AABF && guid2 == 0xCB584471 && guid3 == 0xA119FFFA && guid4 == 0x01E4CE62) {
|
||||
#ifdef VGM_USE_MAIATRAC3PLUS
|
||||
uint16_t bztmp = read_16bit(current_chunk+0x32,streamFile);
|
||||
bztmp = (bztmp >> 8) | (bztmp << 8);
|
||||
fmt->coding_type = coding_AT3plus;
|
||||
fmt->block_size = (bztmp & 0x3FF) * 8 + 8; //should match fmt->block_size
|
||||
fmt->block_size = (bztmp & 0x3FF) * 8 + 8; /* should match fmt->block_size */
|
||||
#elif defined(VGM_USE_FFMPEG)
|
||||
fmt->coding_type = coding_FFmpeg;
|
||||
break;
|
||||
@ -212,11 +241,8 @@ static int read_fmt(int big_endian, STREAMFILE * streamFile, off_t current_chunk
|
||||
#endif
|
||||
}
|
||||
|
||||
/* ATRAC9 GUID 47E142D2-36BA-4d8d-88FC-61654F8C836C (D242E147 BA368D4D 88FC6165 4F8C836C) */
|
||||
if (read_32bitBE(current_chunk+0x20,streamFile) == 0xD242E147 &&
|
||||
read_32bitBE(current_chunk+0x24,streamFile) == 0xBA368D4D &&
|
||||
read_32bitBE(current_chunk+0x28,streamFile) == 0x88FC6165 &&
|
||||
read_32bitBE(current_chunk+0x2c,streamFile) == 0x4F8C836C) {
|
||||
/* ATRAC9 GUID (0x47E142D2,36BA,4D8D,88,FC,61,65,4F,8C,83,6C) */
|
||||
if (guid1 == 0x47E142D2 && guid2 == 0x36BA4D8D && guid3 == 0x88FC6165 && guid4 == 0x4F8C836C) {
|
||||
#ifdef VGM_USE_ATRAC9
|
||||
fmt->coding_type = coding_ATRAC9;
|
||||
break;
|
||||
@ -226,15 +252,16 @@ static int read_fmt(int big_endian, STREAMFILE * streamFile, off_t current_chunk
|
||||
}
|
||||
|
||||
goto fail; /* unknown GUID */
|
||||
}
|
||||
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 1;
|
||||
|
||||
fail:
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int is_ue4_msadpcm(VGMSTREAM* vgmstream, STREAMFILE* streamFile, riff_fmt_chunk* fmt, int fact_sample_count, off_t start_offset);
|
||||
@ -283,7 +310,7 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
|
||||
* (extensionless): Myst III (Xbox)
|
||||
* .sbv: Spongebob Squarepants - The Movie (PC)
|
||||
* .wvx: Godzilla - Destroy All Monsters Melee (Xbox) */
|
||||
if ( check_extensions(streamFile, "wav,lwav,xwav,da,dax,cd,med,snd,adx,adp,xss,xsew,adpcm,adw,wd,,sbv") ) {
|
||||
if ( check_extensions(streamFile, "wav,lwav,xwav,da,dax,cd,med,snd,adx,adp,xss,xsew,adpcm,adw,wd,,sbv,wvx") ) {
|
||||
;
|
||||
}
|
||||
else if ( check_extensions(streamFile, "mwv") ) {
|
||||
@ -330,27 +357,21 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
|
||||
|
||||
/* read through chunks to verify format and find metadata */
|
||||
{
|
||||
off_t current_chunk = 0xc; /* start with first chunk */
|
||||
off_t current_chunk = 0x0c; /* start with first chunk */
|
||||
|
||||
while (current_chunk < file_size && current_chunk < riff_size+8) {
|
||||
uint32_t chunk_type = read_32bitBE(current_chunk,streamFile);
|
||||
size_t chunk_size = read_32bitLE(current_chunk+4,streamFile);
|
||||
uint32_t chunk_id = read_32bitBE(current_chunk + 0x00,streamFile); /* FOURCC */
|
||||
size_t chunk_size = read_32bitLE(current_chunk + 0x04,streamFile);
|
||||
|
||||
if (fmt.codec == 0x6771 && chunk_type == 0x64617461) /* Liar-soft again */
|
||||
chunk_size += (chunk_size%2) ? 0x01 : 0x00;
|
||||
if (current_chunk + 0x08 + chunk_size > file_size)
|
||||
goto fail;
|
||||
|
||||
if (current_chunk+0x08+chunk_size > file_size) goto fail;
|
||||
|
||||
switch(chunk_type) {
|
||||
switch(chunk_id) {
|
||||
case 0x666d7420: /* "fmt " */
|
||||
if (FormatChunkFound) goto fail; /* only one per file */
|
||||
FormatChunkFound = 1;
|
||||
|
||||
if (-1 == read_fmt(0, /* big endian == false*/
|
||||
streamFile,
|
||||
current_chunk,
|
||||
&fmt,
|
||||
mwv))
|
||||
if (!read_fmt(0, streamFile, current_chunk, &fmt, mwv))
|
||||
goto fail;
|
||||
|
||||
/* some Dreamcast/Naomi games again [Headhunter (DC), Bomber hehhe (DC)] */
|
||||
@ -367,7 +388,6 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
|
||||
break;
|
||||
|
||||
case 0x4C495354: /* "LIST" */
|
||||
/* what lurks within?? */
|
||||
switch (read_32bitBE(current_chunk+0x08, streamFile)) {
|
||||
case 0x6164746C: /* "adtl" */
|
||||
/* yay, atdl is its own little world */
|
||||
@ -430,6 +450,7 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
|
||||
if (!mwv) break; /* ignore if not in an mwv */
|
||||
mwv_pflt_offset = current_chunk; /* predictor filters */
|
||||
break;
|
||||
|
||||
case 0x6374726c: /* "ctrl" (.mwv extension) */
|
||||
if (!mwv) break;
|
||||
loop_flag = read_32bitLE(current_chunk+0x08, streamFile);
|
||||
@ -457,7 +478,13 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
|
||||
break;
|
||||
}
|
||||
|
||||
current_chunk += 8+chunk_size;
|
||||
/* chunks are even-sized with padding byte (for 16b reads) as per spec (normally
|
||||
* pre-adjusted except for a few like Liar-soft's), at end may not have padding though
|
||||
* (done *after* chunk parsing since size without padding is needed) */
|
||||
if (chunk_size % 0x02 && current_chunk + 0x08 + chunk_size+0x01 <= file_size)
|
||||
chunk_size += 0x01;
|
||||
|
||||
current_chunk += 0x08 + chunk_size;
|
||||
}
|
||||
}
|
||||
|
||||
@ -495,6 +522,7 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->sample_rate = fmt.sample_rate;
|
||||
vgmstream->channel_layout = fmt.channel_layout;
|
||||
|
||||
/* init, samples */
|
||||
switch (fmt.coding_type) {
|
||||
@ -544,9 +572,9 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
|
||||
vgmstream->num_samples = fact_sample_count;
|
||||
break;
|
||||
|
||||
case coding_AICA:
|
||||
case coding_AICA_int:
|
||||
vgmstream->num_samples = aica_bytes_to_samples(data_size, fmt.channel_count);
|
||||
case coding_YAMAHA:
|
||||
case coding_YAMAHA_int:
|
||||
vgmstream->num_samples = yamaha_bytes_to_samples(data_size, fmt.channel_count);
|
||||
break;
|
||||
|
||||
case coding_XBOX_IMA:
|
||||
@ -624,7 +652,7 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
|
||||
switch (fmt.coding_type) {
|
||||
case coding_MSADPCM:
|
||||
case coding_MS_IMA:
|
||||
case coding_AICA:
|
||||
case coding_YAMAHA:
|
||||
case coding_XBOX_IMA:
|
||||
case coding_IMA:
|
||||
#ifdef VGM_USE_FFMPEG
|
||||
@ -803,11 +831,7 @@ VGMSTREAM * init_vgmstream_rifx(STREAMFILE *streamFile) {
|
||||
if (FormatChunkFound) goto fail;
|
||||
FormatChunkFound = 1;
|
||||
|
||||
if (-1 == read_fmt(1, /* big endian == true */
|
||||
streamFile,
|
||||
current_chunk,
|
||||
&fmt,
|
||||
0)) /* mwv == false */
|
||||
if (!read_fmt(1, streamFile, current_chunk, &fmt, 0))
|
||||
goto fail;
|
||||
|
||||
break;
|
||||
|
@ -1,7 +1,7 @@
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
/* AAC - Tri-Ace Audio Container */
|
||||
/* AAC - tri-Ace (Aska engine) Audio Container */
|
||||
|
||||
/* Xbox 360 Variants (Star Ocean 4, End of Eternity, Infinite Undiscovery) */
|
||||
VGMSTREAM * init_vgmstream_ta_aac_x360(STREAMFILE *streamFile) {
|
||||
@ -297,12 +297,12 @@ VGMSTREAM * init_vgmstream_ta_aac_mobile(STREAMFILE *streamFile) {
|
||||
if (read_32bitLE(0x148, streamFile) != (0x40-0x04*channel_count)*2 / channel_count) goto fail; /* frame samples */
|
||||
if (channel_count > 2) goto fail; /* unknown data layout */
|
||||
|
||||
vgmstream->coding_type = coding_YAMAHA;
|
||||
vgmstream->coding_type = coding_ASKA;
|
||||
vgmstream->layout_type = layout_none;
|
||||
|
||||
vgmstream->num_samples = yamaha_bytes_to_samples(data_size, channel_count);
|
||||
vgmstream->loop_start_sample = yamaha_bytes_to_samples(read_32bitLE(0x130, streamFile), channel_count);
|
||||
vgmstream->loop_end_sample = yamaha_bytes_to_samples(read_32bitLE(0x134, streamFile), channel_count);
|
||||
vgmstream->num_samples = aska_bytes_to_samples(data_size, channel_count);
|
||||
vgmstream->loop_start_sample = aska_bytes_to_samples(read_32bitLE(0x130, streamFile), channel_count);
|
||||
vgmstream->loop_end_sample = aska_bytes_to_samples(read_32bitLE(0x134, streamFile), channel_count);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -16,7 +16,7 @@ typedef enum {
|
||||
DVI_IMA = 7, /* DVI IMA ADPCM (high nibble first) */
|
||||
MPEG = 8, /* MPEG (MP3) */
|
||||
IMA = 9, /* IMA ADPCM (low nibble first) */
|
||||
AICA = 10, /* AICA ADPCM (Dreamcast games) */
|
||||
YAMAHA = 10, /* YAMAHA (AICA) ADPCM (Dreamcast games) */
|
||||
MSADPCM = 11, /* MS ADPCM (Windows games) */
|
||||
NGC_DSP = 12, /* NGC DSP (Nintendo games) */
|
||||
PCM8_U_int = 13, /* 8-bit unsigned PCM (interleaved) */
|
||||
@ -163,7 +163,7 @@ VGMSTREAM * init_vgmstream_txth(STREAMFILE *streamFile) {
|
||||
case MPEG: coding = coding_MPEG_layer3; break; /* we later find out exactly which */
|
||||
#endif
|
||||
case IMA: coding = coding_IMA; break;
|
||||
case AICA: coding = coding_AICA; break;
|
||||
case YAMAHA: coding = coding_YAMAHA; break;
|
||||
case MSADPCM: coding = coding_MSADPCM; break;
|
||||
case NGC_DSP: coding = coding_NGC_DSP; break;
|
||||
case PCM8_U_int: coding = coding_PCM8_U_int; break;
|
||||
@ -226,7 +226,7 @@ VGMSTREAM * init_vgmstream_txth(STREAMFILE *streamFile) {
|
||||
case coding_PSX_badflags:
|
||||
case coding_DVI_IMA:
|
||||
case coding_IMA:
|
||||
case coding_AICA:
|
||||
case coding_YAMAHA:
|
||||
case coding_APPLE_IMA4:
|
||||
vgmstream->interleave_block_size = txth.interleave;
|
||||
vgmstream->interleave_last_block_size = txth.interleave_last;
|
||||
@ -245,8 +245,8 @@ VGMSTREAM * init_vgmstream_txth(STREAMFILE *streamFile) {
|
||||
coding = coding_DVI_IMA_int;
|
||||
if (coding == coding_IMA)
|
||||
coding = coding_IMA_int;
|
||||
if (coding == coding_AICA)
|
||||
coding = coding_AICA_int;
|
||||
if (coding == coding_YAMAHA)
|
||||
coding = coding_YAMAHA_int;
|
||||
}
|
||||
|
||||
/* to avoid endless loops */
|
||||
@ -256,7 +256,7 @@ VGMSTREAM * init_vgmstream_txth(STREAMFILE *streamFile) {
|
||||
coding == coding_IMA_int ||
|
||||
coding == coding_DVI_IMA_int ||
|
||||
coding == coding_SDX2_int ||
|
||||
coding == coding_AICA_int) ) {
|
||||
coding == coding_YAMAHA_int) ) {
|
||||
goto fail;
|
||||
}
|
||||
} else {
|
||||
@ -264,7 +264,7 @@ VGMSTREAM * init_vgmstream_txth(STREAMFILE *streamFile) {
|
||||
}
|
||||
|
||||
/* setup adpcm */
|
||||
if (coding == coding_AICA || coding == coding_AICA_int) {
|
||||
if (coding == coding_YAMAHA || coding == coding_YAMAHA_int) {
|
||||
int ch;
|
||||
for (ch = 0; ch < vgmstream->channels; ch++) {
|
||||
vgmstream->ch[ch].adpcm_step_index = 0x7f;
|
||||
@ -611,8 +611,8 @@ static int parse_keyval(STREAMFILE * streamFile_, txth_header * txth, const char
|
||||
else if (0==strcmp(val,"DVI_IMA")) txth->codec = DVI_IMA;
|
||||
else if (0==strcmp(val,"MPEG")) txth->codec = MPEG;
|
||||
else if (0==strcmp(val,"IMA")) txth->codec = IMA;
|
||||
else if (0==strcmp(val,"YAMAHA")) txth->codec = AICA;
|
||||
else if (0==strcmp(val,"AICA")) txth->codec = AICA;
|
||||
else if (0==strcmp(val,"YAMAHA")) txth->codec = YAMAHA;
|
||||
else if (0==strcmp(val,"AICA")) txth->codec = YAMAHA;
|
||||
else if (0==strcmp(val,"MSADPCM")) txth->codec = MSADPCM;
|
||||
else if (0==strcmp(val,"NGC_DSP")) txth->codec = NGC_DSP;
|
||||
else if (0==strcmp(val,"DSP")) txth->codec = NGC_DSP;
|
||||
@ -1011,8 +1011,8 @@ static int get_bytes_to_samples(txth_header * txth, uint32_t bytes) {
|
||||
case IMA:
|
||||
case DVI_IMA:
|
||||
return ima_bytes_to_samples(bytes, txth->channels);
|
||||
case AICA:
|
||||
return aica_bytes_to_samples(bytes, txth->channels);
|
||||
case YAMAHA:
|
||||
return yamaha_bytes_to_samples(bytes, txth->channels);
|
||||
case PCFX:
|
||||
case OKI16:
|
||||
return oki_bytes_to_samples(bytes, txth->channels);
|
||||
|
185
src/meta/txtp.c
185
src/meta/txtp.c
@ -27,6 +27,12 @@ typedef struct {
|
||||
int config_ignore_fade;
|
||||
|
||||
int sample_rate;
|
||||
int loop_install;
|
||||
int loop_end_max;
|
||||
double loop_start_second;
|
||||
int32_t loop_start_sample;
|
||||
double loop_end_second;
|
||||
int32_t loop_end_sample;
|
||||
|
||||
} txtp_entry;
|
||||
|
||||
@ -88,14 +94,13 @@ VGMSTREAM * init_vgmstream_txtp(STREAMFILE *streamFile) {
|
||||
}
|
||||
else if (txtp->is_layered) {
|
||||
/* layered multi file */
|
||||
int channel_count = 0, loop_flag;
|
||||
|
||||
/* init layout */
|
||||
data_l = init_layout_layered(txtp->entry_count);
|
||||
if (!data_l) goto fail;
|
||||
|
||||
/* open each segment subfile */
|
||||
for (i = 0; i < txtp->entry_count; i++) {
|
||||
for (i = 0; i < data_l->layer_count; i++) {
|
||||
STREAMFILE* temp_streamFile = open_streamfile_by_filename(streamFile, txtp->entry[i].filename);
|
||||
if (!temp_streamFile) goto fail;
|
||||
temp_streamFile->stream_index = txtp->entry[i].subsong;
|
||||
@ -105,43 +110,34 @@ VGMSTREAM * init_vgmstream_txtp(STREAMFILE *streamFile) {
|
||||
if (!data_l->layers[i]) goto fail;
|
||||
|
||||
apply_config(data_l->layers[i], &txtp->entry[i]);
|
||||
|
||||
/* get actual channel count after config */
|
||||
channel_count += data_l->layers[i]->channels;
|
||||
}
|
||||
|
||||
/* setup layered VGMSTREAMs */
|
||||
if (!setup_layout_layered(data_l))
|
||||
goto fail;
|
||||
|
||||
loop_flag = data_l->layers[0]->loop_flag;
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
/* build the layered VGMSTREAM */
|
||||
vgmstream = allocate_layered_vgmstream(data_l);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->sample_rate = data_l->layers[0]->sample_rate;
|
||||
vgmstream->num_samples = data_l->layers[0]->num_samples;
|
||||
vgmstream->loop_start_sample = data_l->layers[0]->loop_start_sample;
|
||||
vgmstream->loop_end_sample = data_l->layers[0]->loop_end_sample;
|
||||
|
||||
vgmstream->meta_type = meta_TXTP;
|
||||
vgmstream->coding_type = data_l->layers[0]->coding_type;
|
||||
vgmstream->layout_type = layout_layered;
|
||||
|
||||
vgmstream->layout_data = data_l;
|
||||
/* custom meta name if all parts don't match */
|
||||
for (i = 0; i < data_l->layer_count; i++) {
|
||||
if (vgmstream->meta_type != data_l->layers[i]->meta_type) {
|
||||
vgmstream->meta_type = meta_TXTP;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* segmented multi file */
|
||||
int num_samples, loop_start_sample = 0, loop_end_sample = 0;
|
||||
int loop_flag, channel_count;
|
||||
int loop_flag;
|
||||
|
||||
/* init layout */
|
||||
data_s = init_layout_segmented(txtp->entry_count);
|
||||
if (!data_s) goto fail;
|
||||
|
||||
/* open each segment subfile */
|
||||
for (i = 0; i < txtp->entry_count; i++) {
|
||||
for (i = 0; i < data_s->segment_count; i++) {
|
||||
STREAMFILE* temp_streamFile = open_streamfile_by_filename(streamFile, txtp->entry[i].filename);
|
||||
if (!temp_streamFile) goto fail;
|
||||
temp_streamFile->stream_index = txtp->entry[i].subsong;
|
||||
@ -162,41 +158,34 @@ VGMSTREAM * init_vgmstream_txtp(STREAMFILE *streamFile) {
|
||||
txtp->loop_end_segment = txtp->entry_count;
|
||||
loop_flag = (txtp->loop_start_segment > 0 && txtp->loop_start_segment <= txtp->entry_count);
|
||||
|
||||
num_samples = 0;
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_segmented_vgmstream(data_s,loop_flag, txtp->loop_start_segment - 1, txtp->loop_end_segment - 1);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
/* custom meta name if all parts don't match */
|
||||
for (i = 0; i < data_s->segment_count; i++) {
|
||||
|
||||
if (loop_flag && txtp->loop_start_segment == i+1) {
|
||||
if (txtp->is_loop_keep /*&& data_s->segments[i]->loop_start_sample*/)
|
||||
loop_start_sample = num_samples + data_s->segments[i]->loop_start_sample;
|
||||
else
|
||||
loop_start_sample = num_samples;
|
||||
}
|
||||
|
||||
num_samples += data_s->segments[i]->num_samples;
|
||||
|
||||
if (loop_flag && txtp->loop_end_segment == i+1) {
|
||||
if (txtp->is_loop_keep && data_s->segments[i]->loop_end_sample)
|
||||
loop_end_sample = num_samples - data_s->segments[i]->num_samples + data_s->segments[i]->loop_end_sample;
|
||||
else
|
||||
loop_end_sample = num_samples;
|
||||
if (vgmstream->meta_type != data_s->segments[i]->meta_type) {
|
||||
vgmstream->meta_type = meta_TXTP;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
channel_count = data_s->segments[0]->channels;
|
||||
/* fix loop keep */
|
||||
if (loop_flag && txtp->is_loop_keep) {
|
||||
int32_t current_samples = 0;
|
||||
for (i = 0; i < data_s->segment_count; i++) {
|
||||
if (txtp->loop_start_segment == i+1 /*&& data_s->segments[i]->loop_start_sample*/) {
|
||||
vgmstream->loop_start_sample = current_samples + data_s->segments[i]->loop_start_sample;
|
||||
}
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
current_samples += data_s->segments[i]->num_samples;
|
||||
|
||||
vgmstream->sample_rate = data_s->segments[0]->sample_rate;
|
||||
vgmstream->num_samples = num_samples;
|
||||
vgmstream->loop_start_sample = loop_start_sample;
|
||||
vgmstream->loop_end_sample = loop_end_sample;
|
||||
|
||||
vgmstream->meta_type = meta_TXTP;
|
||||
vgmstream->coding_type = data_s->segments[0]->coding_type;
|
||||
vgmstream->layout_type = layout_segmented;
|
||||
vgmstream->layout_data = data_s;
|
||||
if (txtp->loop_end_segment == i+1 && data_s->segments[i]->loop_end_sample) {
|
||||
vgmstream->loop_end_sample = current_samples - data_s->segments[i]->num_samples + data_s->segments[i]->loop_end_sample;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -230,9 +219,6 @@ static void apply_config(VGMSTREAM *vgmstream, txtp_entry *current) {
|
||||
}
|
||||
#endif
|
||||
|
||||
if (current->sample_rate > 0)
|
||||
vgmstream->sample_rate = current->sample_rate;
|
||||
|
||||
vgmstream->config_loop_count = current->config_loop_count;
|
||||
vgmstream->config_fade_time = current->config_fade_time;
|
||||
vgmstream->config_fade_delay = current->config_fade_delay;
|
||||
@ -240,6 +226,26 @@ static void apply_config(VGMSTREAM *vgmstream, txtp_entry *current) {
|
||||
vgmstream->config_force_loop = current->config_force_loop;
|
||||
vgmstream->config_ignore_fade = current->config_ignore_fade;
|
||||
|
||||
if (current->sample_rate > 0) {
|
||||
vgmstream->sample_rate = current->sample_rate;
|
||||
}
|
||||
|
||||
if (current->loop_install) {
|
||||
if (current->loop_start_second > 0 || current->loop_end_second > 0) {
|
||||
current->loop_start_sample = current->loop_start_second * (double)vgmstream->sample_rate;
|
||||
current->loop_end_sample = current->loop_end_second * (double)vgmstream->sample_rate;
|
||||
if (current->loop_end_sample > vgmstream->num_samples &&
|
||||
current->loop_end_sample - vgmstream->num_samples <= 0.1 * (double)vgmstream->sample_rate)
|
||||
current->loop_end_sample = vgmstream->num_samples; /* allow some rounding leeway */
|
||||
}
|
||||
|
||||
if (current->loop_end_max) {
|
||||
current->loop_end_sample = vgmstream->num_samples;
|
||||
}
|
||||
|
||||
vgmstream_force_loop(vgmstream, current->loop_install, current->loop_start_sample, current->loop_end_sample);
|
||||
}
|
||||
|
||||
#ifdef VGMSTREAM_MIXING
|
||||
/* add macro to mixing list */
|
||||
if (current->channel_mask) {
|
||||
@ -324,6 +330,47 @@ static int get_int(const char * config, int *value) {
|
||||
return n;
|
||||
}
|
||||
|
||||
static int get_time(const char * config, double *value_f, int32_t *value_i) {
|
||||
int n,m;
|
||||
int temp_i1, temp_i2;
|
||||
double temp_f1, temp_f2;
|
||||
char temp_c;
|
||||
|
||||
/* test if format is hour: N:N(.n) or N_N(.n) */
|
||||
m = sscanf(config, " %i%c%i%n", &temp_i1,&temp_c,&temp_i2,&n);
|
||||
if (m == 3 && (temp_c == ':' || temp_c == '_')) {
|
||||
m = sscanf(config, " %lf%c%lf%n", &temp_f1,&temp_c,&temp_f2,&n);
|
||||
if (m != 3 || temp_f1 < 0.0 || temp_f1 >= 60.0 || temp_f2 < 0.0 || temp_f2 >= 60.0)
|
||||
return 0;
|
||||
|
||||
*value_f = temp_f1 * 60.0 + temp_f2;
|
||||
return n;
|
||||
}
|
||||
|
||||
/* test if format is seconds: N.n */
|
||||
m = sscanf(config, " %i.%i%n", &temp_i1,&temp_i2,&n);
|
||||
if (m == 2) {
|
||||
m = sscanf(config, " %lf%n", &temp_f1,&n);
|
||||
if (m != 1 || temp_f1 < 0.0)
|
||||
return 0;
|
||||
*value_f = temp_f1;
|
||||
return n;
|
||||
}
|
||||
|
||||
/* assume format is samples: N */
|
||||
m = sscanf(config, " %i%n", &temp_i1,&n);
|
||||
if (m == 1) {
|
||||
if (temp_i1 < 0)
|
||||
return 0;
|
||||
|
||||
//*is_time_i = 1;
|
||||
*value_i = temp_i1;
|
||||
return n;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_bool(const char * config, int *value) {
|
||||
int n,m;
|
||||
char temp;
|
||||
@ -441,7 +488,7 @@ static void add_config(txtp_entry* current, txtp_entry* cfg, const char* filenam
|
||||
}
|
||||
#endif
|
||||
#ifdef VGMSTREAM_MIXING
|
||||
//*current = *cfg; /* don't memcopy to allow list additions */
|
||||
//*current = *cfg; /* don't memcopy to allow list additions */ //todo save list first then memcpy
|
||||
|
||||
if (cfg->mixing_count > 0) {
|
||||
int i;
|
||||
@ -460,7 +507,12 @@ static void add_config(txtp_entry* current, txtp_entry* cfg, const char* filenam
|
||||
current->config_ignore_fade = cfg->config_ignore_fade;
|
||||
|
||||
current->sample_rate = cfg->sample_rate;
|
||||
|
||||
current->loop_install = cfg->loop_install;
|
||||
current->loop_end_max = cfg->loop_end_max;
|
||||
current->loop_start_sample = cfg->loop_start_sample;
|
||||
current->loop_start_second = cfg->loop_start_second;
|
||||
current->loop_end_sample = cfg->loop_end_sample;
|
||||
current->loop_end_second = cfg->loop_end_second;
|
||||
}
|
||||
|
||||
static int add_filename(txtp_header * txtp, char *filename, int is_default) {
|
||||
@ -613,8 +665,8 @@ static int add_filename(txtp_header * txtp, char *filename, int is_default) {
|
||||
|
||||
if (get_fade(config, &mix, &n) != 0) {
|
||||
//;VGM_LOG("TXTP: fade %d^%f~%f=%c@%f~%f+%f~%f\n",
|
||||
mix.ch_dst, mix.vol_start, mix.vol_end, mix.shape,
|
||||
mix.time_pre, mix.time_start, mix.time_end, mix.time_post);
|
||||
// mix.ch_dst, mix.vol_start, mix.vol_end, mix.shape,
|
||||
// mix.time_pre, mix.time_start, mix.time_end, mix.time_post);
|
||||
add_mixing(&cfg, &mix, MIX_FADE); /* N^V1~V2@T1~T2+T3~T4: fades volumes between positions */
|
||||
config += n;
|
||||
continue;
|
||||
@ -675,6 +727,23 @@ static int add_filename(txtp_header * txtp, char *filename, int is_default) {
|
||||
config += get_int(config, &cfg.sample_rate);
|
||||
//;VGM_LOG("TXTP: sample_rate %i\n", cfg.sample_rate);
|
||||
}
|
||||
else if (strcmp(command,"I") == 0) {
|
||||
n = get_time(config, &cfg.loop_start_second, &cfg.loop_start_sample);
|
||||
if (n > 0) { /* first value must exist */
|
||||
config += n;
|
||||
|
||||
n = get_time(config, &cfg.loop_end_second, &cfg.loop_end_sample);
|
||||
if (n == 0) { /* second value is optional */
|
||||
cfg.loop_end_max = 1;
|
||||
}
|
||||
|
||||
config += n;
|
||||
cfg.loop_install = 1;
|
||||
}
|
||||
|
||||
//;VGM_LOG("TXTP: loop_install %i (max=%i): %i %i / %f %f\n", cfg.loop_install, cfg.loop_end_max,
|
||||
// cfg.loop_start_sample, cfg.loop_end_sample, cfg.loop_start_second, cfg.loop_end_second);
|
||||
}
|
||||
else if (config[nc] == ' ') {
|
||||
//;VGM_LOG("TXTP: comment\n");
|
||||
break; /* comment, ignore rest */
|
||||
|
@ -1396,6 +1396,10 @@ static STREAMFILE * open_atomic_bao(ubi_bao_file file_type, uint32_t file_id, in
|
||||
streamBAO = open_streamfile_by_filename(streamFile, buf);
|
||||
if (streamBAO) return streamBAO;
|
||||
|
||||
snprintf(buf,buf_size, "Czech_BAO_0x%08x", file_id);
|
||||
streamBAO = open_streamfile_by_filename(streamFile, buf);
|
||||
if (streamBAO) return streamBAO;
|
||||
|
||||
/* there may be more per language */
|
||||
}
|
||||
else {
|
||||
|
@ -29,6 +29,7 @@ typedef struct {
|
||||
int block_align;
|
||||
int average_bps;
|
||||
int bits_per_sample;
|
||||
uint32_t channel_layout;
|
||||
size_t extra_size;
|
||||
|
||||
int32_t num_samples;
|
||||
@ -104,11 +105,12 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
|
||||
if (ww.fmt_size < 0x12) goto fail;
|
||||
ww.format = (uint16_t)read_16bit(ww.fmt_offset+0x00,streamFile);
|
||||
|
||||
if (ww.format == 0x0165) { /* XMA2WAVEFORMAT (always "fmt"+"XMA2", unlike .xma that may only have "XMA2") */
|
||||
if (ww.format == 0x0165) { /* pseudo-XMA2WAVEFORMAT (always "fmt"+"XMA2", unlike .xma that may only have "XMA2") */
|
||||
if (!find_chunk(streamFile, 0x584D4132,first_offset,0, &ww.chunk_offset,NULL, ww.big_endian, 0))
|
||||
goto fail;
|
||||
xma2_parse_xma2_chunk(streamFile, ww.chunk_offset,&ww.channels,&ww.sample_rate, &ww.loop_flag, &ww.num_samples, &ww.loop_start_sample, &ww.loop_end_sample);
|
||||
} else { /* WAVEFORMATEX */
|
||||
}
|
||||
else { /* pseudo-WAVEFORMATEX */
|
||||
ww.channels = read_16bit(ww.fmt_offset+0x02,streamFile);
|
||||
ww.sample_rate = read_32bit(ww.fmt_offset+0x04,streamFile);
|
||||
ww.average_bps = read_32bit(ww.fmt_offset+0x08,streamFile);/* bytes per sec */
|
||||
@ -116,9 +118,10 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
|
||||
ww.bits_per_sample = (uint16_t)read_16bit(ww.fmt_offset+0x0e,streamFile);
|
||||
if (ww.fmt_size > 0x10 && ww.format != 0x0165 && ww.format != 0x0166) /* ignore XMAWAVEFORMAT */
|
||||
ww.extra_size = (uint16_t)read_16bit(ww.fmt_offset+0x10,streamFile);
|
||||
/* channel bitmask, see AkSpeakerConfig.h (ex. 1ch uses FRONT_CENTER 0x4, 2ch FRONT_LEFT 0x1 | FRONT_RIGHT 0x2, etc) */
|
||||
//if (ww.extra_size >= 6)
|
||||
// ww.channel_config = read_32bit(ww.fmt_offset+0x14,streamFile);
|
||||
if (ww.extra_size >= 0x06) { /* mostly WAVEFORMATEXTENSIBLE's bitmask, see AkSpeakerConfig.h */
|
||||
/* always present (actual RIFFs only have it in WAVEFORMATEXTENSIBLE) */
|
||||
ww.channel_layout = read_32bit(ww.fmt_offset+0x14,streamFile);
|
||||
}
|
||||
}
|
||||
|
||||
/* find loop info */
|
||||
@ -192,6 +195,7 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
start_offset = ww.data_offset;
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(ww.channels,ww.loop_flag);
|
||||
@ -200,10 +204,9 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
|
||||
vgmstream->sample_rate = ww.sample_rate;
|
||||
vgmstream->loop_start_sample = ww.loop_start_sample;
|
||||
vgmstream->loop_end_sample = ww.loop_end_sample;
|
||||
vgmstream->channel_layout = ww.channel_layout;
|
||||
vgmstream->meta_type = meta_WWISE_RIFF;
|
||||
|
||||
start_offset = ww.data_offset;
|
||||
|
||||
switch(ww.codec) {
|
||||
case PCM: /* common */
|
||||
/* normally riff.c has priority but it's needed when .wem is used */
|
||||
|
170
src/plugins.c
170
src/plugins.c
@ -1,6 +1,34 @@
|
||||
#include "vgmstream.h"
|
||||
#include "plugins.h"
|
||||
|
||||
#define VGMSTREAM_TAGS_LINE_MAX 2048
|
||||
|
||||
/* opaque tag state */
|
||||
struct VGMSTREAM_TAGS {
|
||||
/* extracted output */
|
||||
char key[VGMSTREAM_TAGS_LINE_MAX];
|
||||
char val[VGMSTREAM_TAGS_LINE_MAX];
|
||||
|
||||
/* file to find tags for */
|
||||
char targetname[VGMSTREAM_TAGS_LINE_MAX];
|
||||
/* path of targetname */
|
||||
char targetpath[VGMSTREAM_TAGS_LINE_MAX];
|
||||
|
||||
/* tag section for filename (see comments below) */
|
||||
int section_found;
|
||||
off_t section_start;
|
||||
off_t section_end;
|
||||
off_t offset;
|
||||
|
||||
/* commands */
|
||||
int autotrack_on;
|
||||
int autotrack_written;
|
||||
int track_count;
|
||||
|
||||
int autoalbum_on;
|
||||
int autoalbum_written;
|
||||
};
|
||||
|
||||
|
||||
static void tags_clean(VGMSTREAM_TAGS* tag) {
|
||||
int i;
|
||||
@ -14,62 +42,97 @@ static void tags_clean(VGMSTREAM_TAGS* tag) {
|
||||
}
|
||||
}
|
||||
|
||||
VGMSTREAM_TAGS* vgmstream_tags_init(const char* *tag_key, const char* *tag_val) {
|
||||
VGMSTREAM_TAGS* tags = malloc(sizeof(VGMSTREAM_TAGS));
|
||||
if (!tags) goto fail;
|
||||
|
||||
*tag_key = tags->key;
|
||||
*tag_val = tags->val;
|
||||
|
||||
return tags;
|
||||
fail:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void vgmstream_tags_close(VGMSTREAM_TAGS *tags) {
|
||||
free(tags);
|
||||
}
|
||||
|
||||
/* Tags are divided in two: "global" @TAGS and "file" %TAGS for target filename. To extract both
|
||||
* we find the filename's tag "section": (other_filename) ..(#tag section).. (target_filename).
|
||||
* When a new "other_filename" is found that offset is marked as section_start, and when target_filename
|
||||
* is found it's marked as section_end. Then we can begin extracting tags within that section, until
|
||||
* all tags are exhausted. Global tags are extracted while searching, so they always go first, and
|
||||
* also meaning any tags after the section is found are ignored. */
|
||||
int vgmstream_tags_next_tag(VGMSTREAM_TAGS* tag, STREAMFILE* tagfile) {
|
||||
int vgmstream_tags_next_tag(VGMSTREAM_TAGS* tags, STREAMFILE* tagfile) {
|
||||
off_t file_size = get_streamfile_size(tagfile);
|
||||
char currentname[TAG_LINE_MAX] = {0};
|
||||
char line[TAG_LINE_MAX] = {0};
|
||||
char currentname[VGMSTREAM_TAGS_LINE_MAX] = {0};
|
||||
char line[VGMSTREAM_TAGS_LINE_MAX] = {0};
|
||||
int ok, bytes_read, line_done;
|
||||
|
||||
if (!tags)
|
||||
return 0;
|
||||
|
||||
/* prepare file start and skip BOM if needed */
|
||||
if (tag->offset == 0) {
|
||||
if (tags->offset == 0) {
|
||||
if ((uint16_t)read_16bitLE(0x00, tagfile) == 0xFFFE ||
|
||||
(uint16_t)read_16bitLE(0x00, tagfile) == 0xFEFF) {
|
||||
tag->offset = 0x02;
|
||||
if (tag->section_start == 0)
|
||||
tag->section_start = 0x02;
|
||||
tags->offset = 0x02;
|
||||
if (tags->section_start == 0)
|
||||
tags->section_start = 0x02;
|
||||
}
|
||||
else if (((uint32_t)read_32bitBE(0x00, tagfile) & 0xFFFFFF00) == 0xEFBBBF00) {
|
||||
tag->offset = 0x03;
|
||||
if (tag->section_start == 0)
|
||||
tag->section_start = 0x03;
|
||||
tags->offset = 0x03;
|
||||
if (tags->section_start == 0)
|
||||
tags->section_start = 0x03;
|
||||
}
|
||||
}
|
||||
|
||||
/* read lines */
|
||||
while (tag->offset <= file_size) {
|
||||
while (tags->offset <= file_size) {
|
||||
|
||||
/* no more tags to extract */
|
||||
if (tag->section_found && tag->offset >= tag->section_end) {
|
||||
if (tags->section_found && tags->offset >= tags->section_end) {
|
||||
|
||||
/* write extra tags after all regular tags */
|
||||
if (tag->autotrack_on && !tag->autotrack_written) {
|
||||
sprintf(tag->key, "%s", "TRACK");
|
||||
sprintf(tag->val, "%i", tag->track_count);
|
||||
tag->autotrack_written = 1;
|
||||
if (tags->autotrack_on && !tags->autotrack_written) {
|
||||
sprintf(tags->key, "%s", "TRACK");
|
||||
sprintf(tags->val, "%i", tags->track_count);
|
||||
tags->autotrack_written = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (tags->autoalbum_on && !tags->autoalbum_written && tags->targetpath[0] != '\0') {
|
||||
const char* path;
|
||||
|
||||
path = strrchr(tags->targetpath,'\\');
|
||||
if (!path) {
|
||||
path = strrchr(tags->targetpath,'/');
|
||||
}
|
||||
if (!path) {
|
||||
path = tags->targetpath;
|
||||
}
|
||||
|
||||
sprintf(tags->key, "%s", "ALBUM");
|
||||
sprintf(tags->val, "%s", path+1);
|
||||
tags->autoalbum_written = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
goto fail;
|
||||
}
|
||||
|
||||
bytes_read = get_streamfile_text_line(TAG_LINE_MAX,line, tag->offset,tagfile, &line_done);
|
||||
bytes_read = get_streamfile_text_line(VGMSTREAM_TAGS_LINE_MAX,line, tags->offset,tagfile, &line_done);
|
||||
if (!line_done || bytes_read == 0) goto fail;
|
||||
|
||||
tag->offset += bytes_read;
|
||||
tags->offset += bytes_read;
|
||||
|
||||
|
||||
if (tag->section_found) {
|
||||
if (tags->section_found) {
|
||||
/* find possible file tag */
|
||||
ok = sscanf(line, "# %%%[^ \t] %[^\r\n] ", tag->key,tag->val);
|
||||
ok = sscanf(line, "# %%%[^ \t] %[^\r\n] ", tags->key,tags->val);
|
||||
if (ok == 2) {
|
||||
tags_clean(tag);
|
||||
tags_clean(tags);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@ -77,19 +140,22 @@ int vgmstream_tags_next_tag(VGMSTREAM_TAGS* tag, STREAMFILE* tagfile) {
|
||||
|
||||
if (line[0] == '#') {
|
||||
/* find possible global command */
|
||||
ok = sscanf(line, "# $%[^ \t] %[^\r\n]", tag->key,tag->val);
|
||||
ok = sscanf(line, "# $%[^ \t] %[^\r\n]", tags->key,tags->val);
|
||||
if (ok == 1 || ok == 2) {
|
||||
if (strcasecmp(tag->key,"AUTOTRACK") == 0) {
|
||||
tag->autotrack_on = 1;
|
||||
if (strcasecmp(tags->key,"AUTOTRACK") == 0) {
|
||||
tags->autotrack_on = 1;
|
||||
}
|
||||
else if (strcasecmp(tags->key,"AUTOALBUM") == 0) {
|
||||
tags->autoalbum_on = 1;
|
||||
}
|
||||
|
||||
continue; /* not an actual tag */
|
||||
}
|
||||
|
||||
/* find possible global tag */
|
||||
ok = sscanf(line, "# @%[^ \t] %[^\r\n]", tag->key,tag->val);
|
||||
ok = sscanf(line, "# @%[^ \t] %[^\r\n]", tags->key,tags->val);
|
||||
if (ok == 2) {
|
||||
tags_clean(tag);
|
||||
tags_clean(tags);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -99,18 +165,18 @@ int vgmstream_tags_next_tag(VGMSTREAM_TAGS* tag, STREAMFILE* tagfile) {
|
||||
/* find possible filename and section start/end */
|
||||
ok = sscanf(line, " %[^\r\n] ", currentname);
|
||||
if (ok == 1) {
|
||||
if (strcasecmp(tag->targetname,currentname) == 0) { /* looks ok even for UTF-8 */
|
||||
if (strcasecmp(tags->targetname,currentname) == 0) { /* looks ok even for UTF-8 */
|
||||
/* section ok, start would be set before this (or be 0) */
|
||||
tag->section_end = tag->offset;
|
||||
tag->section_found = 1;
|
||||
tag->offset = tag->section_start;
|
||||
tags->section_end = tags->offset;
|
||||
tags->section_found = 1;
|
||||
tags->offset = tags->section_start;
|
||||
}
|
||||
else {
|
||||
/* mark new possible section */
|
||||
tag->section_start = tag->offset;
|
||||
tags->section_start = tags->offset;
|
||||
}
|
||||
|
||||
tag->track_count++; /* new track found (target filename or not) */
|
||||
tags->track_count++; /* new track found (target filename or not) */
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -121,31 +187,39 @@ int vgmstream_tags_next_tag(VGMSTREAM_TAGS* tag, STREAMFILE* tagfile) {
|
||||
/* may reach here if read up to file_size but no section was found */
|
||||
|
||||
fail:
|
||||
tag->key[0] = '\0';
|
||||
tag->val[0] = '\0';
|
||||
tags->key[0] = '\0';
|
||||
tags->val[0] = '\0';
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void vgmstream_tags_reset(VGMSTREAM_TAGS* tag, const char* target_filename) {
|
||||
const char *path;
|
||||
void vgmstream_tags_reset(VGMSTREAM_TAGS* tags, const char* target_filename) {
|
||||
char *path;
|
||||
|
||||
memset(tag, 0, sizeof(VGMSTREAM_TAGS));
|
||||
if (!tags)
|
||||
return;
|
||||
|
||||
|
||||
/* get base name */
|
||||
|
||||
//todo Windows CMD accepts both \\ and /, better way to handle this?
|
||||
path = strrchr(target_filename,'\\');
|
||||
if (!path)
|
||||
path = strrchr(target_filename,'/');
|
||||
if (path != NULL)
|
||||
path = path+1;
|
||||
memset(tags, 0, sizeof(VGMSTREAM_TAGS));
|
||||
|
||||
//todo validate sizes and copy sensible max
|
||||
|
||||
/* get base name */
|
||||
strcpy(tags->targetpath, target_filename);
|
||||
|
||||
/* Windows CMD accepts both \\ and /, and maybe plugin uses either */
|
||||
path = strrchr(tags->targetpath,'\\');
|
||||
if (!path) {
|
||||
path = strrchr(tags->targetpath,'/');
|
||||
}
|
||||
if (path != NULL) {
|
||||
path[0] = '\0'; /* leave targetpath with path only */
|
||||
path = path+1;
|
||||
}
|
||||
|
||||
if (path) {
|
||||
strcpy(tag->targetname, path);
|
||||
strcpy(tags->targetname, path);
|
||||
} else {
|
||||
strcpy(tag->targetname, target_filename);
|
||||
tags->targetpath[0] = '\0';
|
||||
strcpy(tags->targetname, target_filename);
|
||||
}
|
||||
}
|
||||
|
@ -5,37 +5,31 @@
|
||||
#define _PLUGINS_H_
|
||||
|
||||
#include "streamfile.h"
|
||||
#define TAG_LINE_MAX 2048
|
||||
|
||||
//todo improve API and make opaque
|
||||
//typedef struct VGMSTREAM_TAGS VGMSTREAM_TAGS;
|
||||
typedef struct {
|
||||
/* extracted output */
|
||||
char key[TAG_LINE_MAX];
|
||||
char val[TAG_LINE_MAX];
|
||||
/* opaque tag state */
|
||||
typedef struct VGMSTREAM_TAGS VGMSTREAM_TAGS;
|
||||
|
||||
/* file to find tags for */
|
||||
char targetname[TAG_LINE_MAX];
|
||||
|
||||
/* tag section for filename (see comments below) */
|
||||
int section_found;
|
||||
off_t section_start;
|
||||
off_t section_end;
|
||||
off_t offset;
|
||||
|
||||
/* commands */
|
||||
int autotrack_on;
|
||||
int autotrack_written;
|
||||
int track_count;
|
||||
} VGMSTREAM_TAGS;
|
||||
/* Initializes TAGS and returns pointers to extracted strings (always valid but change
|
||||
* on every vgmstream_tags_next_tag call). Next functions are safe to call even if this fails (validate NULL).
|
||||
* ex.: const char *tag_key, *tag_val; tags=vgmstream_tags_init(&tag_key, &tag_val); */
|
||||
VGMSTREAM_TAGS* vgmstream_tags_init(const char* *tag_key, const char* *tag_val);
|
||||
|
||||
/* Resets tagfile to restart reading from the beginning for a new filename.
|
||||
* Must be called first before extracting tags. */
|
||||
void vgmstream_tags_reset(VGMSTREAM_TAGS* tags, const char* target_filename);
|
||||
|
||||
|
||||
/* Extracts next valid tag in tagfile to *tag. Returns 0 if no more tags are found (meant to be
|
||||
* called repeatedly until 0). Key/values are trimmed and values can be in UTF-8. */
|
||||
int vgmstream_tags_next_tag(VGMSTREAM_TAGS* tag, STREAMFILE* tagfile);
|
||||
int vgmstream_tags_next_tag(VGMSTREAM_TAGS* tags, STREAMFILE* tagfile);
|
||||
|
||||
/* resets tagfile to restart reading from the beginning for a new filename */
|
||||
void vgmstream_tags_reset(VGMSTREAM_TAGS* tag, const char* target_filename);
|
||||
/* Closes tag file */
|
||||
void vgmstream_tags_close(VGMSTREAM_TAGS* tags);
|
||||
|
||||
#ifdef VGMSTREAM_MIXING
|
||||
/* Enables mixing effects, with max outbuf samples as a hint. Once active, plugin
|
||||
* must use returned input_channels to create outbuf and output_channels to output audio. */
|
||||
void vgmstream_enable_mixing(VGMSTREAM* vgmstream, int32_t max_sample_count, int *input_channels, int *output_channels);
|
||||
#endif
|
||||
|
||||
#endif /* _PLUGINS_H_ */
|
||||
|
@ -202,7 +202,38 @@ static inline int32_t read_s32le(off_t offset, STREAMFILE * streamfile) { retur
|
||||
static inline uint32_t read_u32le(off_t offset, STREAMFILE * streamfile) { return (uint32_t)read_32bitLE(offset, streamfile); }
|
||||
static inline int32_t read_s32be(off_t offset, STREAMFILE * streamfile) { return read_32bitBE(offset, streamfile); }
|
||||
static inline uint32_t read_u32be(off_t offset, STREAMFILE * streamfile) { return (uint32_t)read_32bitBE(offset, streamfile); }
|
||||
static inline int64_t read_s64be(off_t offset, STREAMFILE * streamfile) { return read_64bitBE(offset, streamfile); }
|
||||
static inline uint64_t read_u64be(off_t offset, STREAMFILE * streamfile) { return (uint64_t)read_64bitBE(offset, streamfile); }
|
||||
static inline int64_t read_s64le(off_t offset, STREAMFILE * streamfile) { return read_64bitLE(offset, streamfile); }
|
||||
static inline uint64_t read_u64le(off_t offset, STREAMFILE * streamfile) { return (uint64_t)read_64bitLE(offset, streamfile); }
|
||||
|
||||
#if 0 //todo improve + test + simplify code (maybe not inline?)
|
||||
static inline float read_f32be(off_t offset, STREAMFILE * streamfile) {
|
||||
uint32_t sample_int = read_s32be(offset,streamfile);
|
||||
float* sample_float = (float*)&sample_int;
|
||||
return *sample_float;
|
||||
}
|
||||
static inline float read_f32le(off_t offset, STREAMFILE * streamfile) {
|
||||
...
|
||||
}
|
||||
static inline int read_s4h(off_t offset, STREAMFILE * streamfile) {
|
||||
uint8_t byte = read_u8(offset, streamfile);
|
||||
return get_nibble_signed(byte, 1);
|
||||
}
|
||||
static inline int read_u4h(off_t offset, STREAMFILE * streamfile) {
|
||||
uint8_t byte = read_u8(offset, streamfile);
|
||||
return (byte >> 4) & 0x0f;
|
||||
}
|
||||
static inline int read_s4l(off_t offset, STREAMFILE * streamfile) {
|
||||
...
|
||||
}
|
||||
static inline int read_u4l(off_t offset, STREAMFILE * streamfile) {
|
||||
...
|
||||
}
|
||||
static inline int max_s32(int32_t a, int32_t b) { return a > b ? a : b; }
|
||||
static inline int min_s32(int32_t a, int32_t b) { return a < b ? a : b; }
|
||||
//align32, align16, clamp16, etc
|
||||
#endif
|
||||
|
||||
/* guess byte endianness from a given value, return true if big endian and false if little endian */
|
||||
static inline int guess_endianness16bit(off_t offset, STREAMFILE * streamfile) {
|
||||
|
14
src/util.c
14
src/util.c
@ -32,7 +32,7 @@ const char * filename_extension(const char * pathname) {
|
||||
|
||||
/* unused */
|
||||
/*
|
||||
void interleave_channel(sample * outbuffer, sample * inbuffer, int32_t sample_count, int channel_count, int channel_number) {
|
||||
void interleave_channel(sample_t * outbuffer, sample_t * inbuffer, int32_t sample_count, int channel_count, int channel_number) {
|
||||
int32_t insample,outsample;
|
||||
|
||||
if (channel_count==1) {
|
||||
@ -48,9 +48,9 @@ void interleave_channel(sample * outbuffer, sample * inbuffer, int32_t sample_co
|
||||
|
||||
/* failed attempt at interleave in place */
|
||||
/*
|
||||
void interleave_stereo(sample * buffer, int32_t sample_count) {
|
||||
void interleave_stereo(sample_t * buffer, int32_t sample_count) {
|
||||
int32_t tomove, belongs;
|
||||
sample moving,temp;
|
||||
sample_t moving,temp;
|
||||
|
||||
tomove = sample_count;
|
||||
moving = buffer[tomove];
|
||||
@ -100,11 +100,11 @@ void put_32bitBE(uint8_t * buf, int32_t i) {
|
||||
buf[3] = (uint8_t)(i & 0xFF);
|
||||
}
|
||||
|
||||
void swap_samples_le(sample *buf, int count) {
|
||||
void swap_samples_le(sample_t *buf, int count) {
|
||||
int i;
|
||||
for (i=0;i<count;i++) {
|
||||
uint8_t b0 = buf[i]&0xff;
|
||||
uint8_t b1 = buf[i]>>8;
|
||||
for (i = 0; i < count; i++) {
|
||||
uint8_t b0 = buf[i] & 0xff;
|
||||
uint8_t b1 = buf[i] >> 8;
|
||||
uint8_t *p = (uint8_t*)&(buf[i]);
|
||||
p[0] = b0;
|
||||
p[1] = b1;
|
||||
|
223
src/vgmstream.c
223
src/vgmstream.c
@ -191,7 +191,7 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = {
|
||||
init_vgmstream_ngc_ssm,
|
||||
init_vgmstream_ps2_joe,
|
||||
init_vgmstream_vgs,
|
||||
init_vgmstream_dc_dcsw_dcs,
|
||||
init_vgmstream_dcs_wav,
|
||||
init_vgmstream_mul,
|
||||
init_vgmstream_thp,
|
||||
init_vgmstream_wii_sts,
|
||||
@ -498,14 +498,14 @@ static VGMSTREAM * init_vgmstream_internal(STREAMFILE *streamFile) {
|
||||
|
||||
/* fail if there is nothing to play (without this check vgmstream can generate empty files) */
|
||||
if (vgmstream->num_samples <= 0) {
|
||||
VGM_LOG("VGMSTREAM: wrong num_samples (ns=%i / 0x%08x)\n", vgmstream->num_samples, vgmstream->num_samples);
|
||||
VGM_LOG("VGMSTREAM: wrong num_samples %i\n", vgmstream->num_samples);
|
||||
close_vgmstream(vgmstream);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* everything should have a reasonable sample rate (300 is Wwise min) */
|
||||
if (vgmstream->sample_rate < 300 || vgmstream->sample_rate > 96000) {
|
||||
VGM_LOG("VGMSTREAM: wrong sample rate (sr=%i)\n", vgmstream->sample_rate);
|
||||
/* everything should have a reasonable sample rate */
|
||||
if (vgmstream->sample_rate < VGMSTREAM_MIN_SAMPLE_RATE || vgmstream->sample_rate > VGMSTREAM_MAX_SAMPLE_RATE) {
|
||||
VGM_LOG("VGMSTREAM: wrong sample_rate %i\n", vgmstream->sample_rate);
|
||||
close_vgmstream(vgmstream);
|
||||
continue;
|
||||
}
|
||||
@ -1214,13 +1214,13 @@ int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream) {
|
||||
return (vgmstream->interleave_block_size - 0x07)*2 + 2;
|
||||
case coding_WS: /* only works if output sample size is 8 bit, which always is for WS ADPCM */
|
||||
return vgmstream->ws_output_size;
|
||||
case coding_AICA:
|
||||
return 1;
|
||||
case coding_AICA_int:
|
||||
return 2;
|
||||
case coding_YAMAHA:
|
||||
return 1;
|
||||
case coding_YAMAHA_int:
|
||||
return 2;
|
||||
case coding_ASKA:
|
||||
return (0x40-0x04*vgmstream->channels) * 2 / vgmstream->channels;
|
||||
case coding_YAMAHA_NXAP:
|
||||
case coding_NXAP:
|
||||
return (0x40-0x04) * 2;
|
||||
case coding_NDS_PROCYON:
|
||||
return 30;
|
||||
@ -1402,11 +1402,11 @@ int get_vgmstream_frame_size(VGMSTREAM * vgmstream) {
|
||||
return vgmstream->interleave_block_size;
|
||||
case coding_WS:
|
||||
return vgmstream->current_block_size;
|
||||
case coding_AICA:
|
||||
case coding_AICA_int:
|
||||
return 0x01;
|
||||
case coding_YAMAHA:
|
||||
case coding_YAMAHA_NXAP:
|
||||
case coding_YAMAHA_int:
|
||||
return 0x01;
|
||||
case coding_ASKA:
|
||||
case coding_NXAP:
|
||||
return 0x40;
|
||||
case coding_NDS_PROCYON:
|
||||
return 0x10;
|
||||
@ -1991,25 +1991,25 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to
|
||||
vgmstream->channels,vgmstream->samples_into_block, samples_to_do, ch);
|
||||
}
|
||||
break;
|
||||
case coding_AICA:
|
||||
case coding_AICA_int:
|
||||
case coding_YAMAHA:
|
||||
case coding_YAMAHA_int:
|
||||
for (ch = 0; ch < vgmstream->channels; ch++) {
|
||||
int is_stereo = (vgmstream->channels > 1 && vgmstream->coding_type == coding_AICA);
|
||||
int is_stereo = (vgmstream->channels > 1 && vgmstream->coding_type == coding_YAMAHA);
|
||||
|
||||
decode_aica(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch,
|
||||
decode_yamaha(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch,
|
||||
vgmstream->channels,vgmstream->samples_into_block,samples_to_do, ch,
|
||||
is_stereo);
|
||||
}
|
||||
break;
|
||||
case coding_YAMAHA:
|
||||
case coding_ASKA:
|
||||
for (ch = 0; ch < vgmstream->channels; ch++) {
|
||||
decode_yamaha(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch,
|
||||
decode_aska(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch,
|
||||
vgmstream->channels,vgmstream->samples_into_block,samples_to_do, ch);
|
||||
}
|
||||
break;
|
||||
case coding_YAMAHA_NXAP:
|
||||
case coding_NXAP:
|
||||
for (ch = 0; ch < vgmstream->channels; ch++) {
|
||||
decode_yamaha_nxap(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch,
|
||||
decode_nxap(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch,
|
||||
vgmstream->channels,vgmstream->samples_into_block,samples_to_do);
|
||||
}
|
||||
break;
|
||||
@ -2270,51 +2270,78 @@ void describe_vgmstream(VGMSTREAM * vgmstream, char * desc, int length) {
|
||||
#define TEMPSIZE (256+32)
|
||||
char temp[TEMPSIZE];
|
||||
const char* description;
|
||||
double time_mm, time_ss, seconds;
|
||||
|
||||
if (!vgmstream) {
|
||||
snprintf(temp,TEMPSIZE,
|
||||
"NULL VGMSTREAM");
|
||||
snprintf(temp,TEMPSIZE, "NULL VGMSTREAM");
|
||||
concatn(length,desc,temp);
|
||||
return;
|
||||
}
|
||||
|
||||
snprintf(temp,TEMPSIZE,
|
||||
"sample rate: %d Hz\n",
|
||||
vgmstream->sample_rate);
|
||||
snprintf(temp,TEMPSIZE, "sample rate: %d Hz\n", vgmstream->sample_rate);
|
||||
concatn(length,desc,temp);
|
||||
|
||||
snprintf(temp,TEMPSIZE,
|
||||
"channels: %d\n",
|
||||
vgmstream->channels);
|
||||
snprintf(temp,TEMPSIZE, "channels: %d\n", vgmstream->channels);
|
||||
concatn(length,desc,temp);
|
||||
|
||||
if (vgmstream->channel_layout) {
|
||||
int cl = vgmstream->channel_layout;
|
||||
|
||||
/* not "channel layout: " to avoid mixups with "layout: " */
|
||||
snprintf(temp,TEMPSIZE, "channel mask: 0x%x /", vgmstream->channel_layout);
|
||||
concatn(length,desc,temp);
|
||||
if (cl & speaker_FL) concatn(length,desc," FL");
|
||||
if (cl & speaker_FR) concatn(length,desc," FR");
|
||||
if (cl & speaker_FC) concatn(length,desc," FC");
|
||||
if (cl & speaker_LFE) concatn(length,desc," LFE");
|
||||
if (cl & speaker_BL) concatn(length,desc," BL");
|
||||
if (cl & speaker_BR) concatn(length,desc," BR");
|
||||
if (cl & speaker_FLC) concatn(length,desc," FLC");
|
||||
if (cl & speaker_FRC) concatn(length,desc," FRC");
|
||||
if (cl & speaker_BC) concatn(length,desc," BC");
|
||||
if (cl & speaker_SL) concatn(length,desc," SL");
|
||||
if (cl & speaker_SR) concatn(length,desc," SR");
|
||||
if (cl & speaker_TC) concatn(length,desc," TC");
|
||||
if (cl & speaker_TFL) concatn(length,desc," TFL");
|
||||
if (cl & speaker_TFC) concatn(length,desc," TFC");
|
||||
if (cl & speaker_TFR) concatn(length,desc," TFR");
|
||||
if (cl & speaker_TBL) concatn(length,desc," TBL");
|
||||
if (cl & speaker_TBC) concatn(length,desc," TBC");
|
||||
if (cl & speaker_TBR) concatn(length,desc," TBR");
|
||||
concatn(length,desc,"\n");
|
||||
}
|
||||
|
||||
if (vgmstream->loop_start_sample >= 0 && vgmstream->loop_end_sample > vgmstream->loop_start_sample) {
|
||||
snprintf(temp,TEMPSIZE,
|
||||
"looping: %s\n"
|
||||
"loop start: %d samples (%.4f seconds)\n"
|
||||
"loop end: %d samples (%.4f seconds)\n",
|
||||
vgmstream->loop_flag ? "enabled" : "disabled",
|
||||
vgmstream->loop_start_sample,
|
||||
(double)vgmstream->loop_start_sample/vgmstream->sample_rate,
|
||||
vgmstream->loop_end_sample,
|
||||
(double)vgmstream->loop_end_sample/vgmstream->sample_rate);
|
||||
if (!vgmstream->loop_flag) {
|
||||
concatn(length,desc,"looping: disabled\n");
|
||||
}
|
||||
|
||||
seconds = (double)vgmstream->loop_start_sample / vgmstream->sample_rate;
|
||||
time_mm = (int)(seconds / 60.0);
|
||||
time_ss = seconds - time_mm * 60.0f;
|
||||
snprintf(temp,TEMPSIZE, "loop start: %d samples (%1.0f:%2.3f seconds)\n", vgmstream->loop_start_sample, time_mm, time_ss);
|
||||
concatn(length,desc,temp);
|
||||
|
||||
seconds = (double)vgmstream->loop_end_sample / vgmstream->sample_rate;
|
||||
time_mm = (int)(seconds / 60.0);
|
||||
time_ss = seconds - time_mm * 60.0f;
|
||||
snprintf(temp,TEMPSIZE, "loop end: %d samples (%1.0f:%2.3f seconds)\n", vgmstream->loop_end_sample, time_mm, time_ss);
|
||||
concatn(length,desc,temp);
|
||||
}
|
||||
|
||||
snprintf(temp,TEMPSIZE,
|
||||
"stream total samples: %d (%.4f seconds)\n",
|
||||
vgmstream->num_samples,
|
||||
(double)vgmstream->num_samples/vgmstream->sample_rate);
|
||||
seconds = (double)vgmstream->num_samples / vgmstream->sample_rate;
|
||||
time_mm = (int)(seconds / 60.0);
|
||||
time_ss = seconds - time_mm * 60.0;
|
||||
snprintf(temp,TEMPSIZE, "stream total samples: %d (%1.0f:%2.3f seconds)\n", vgmstream->num_samples, time_mm, time_ss);
|
||||
concatn(length,desc,temp);
|
||||
|
||||
snprintf(temp,TEMPSIZE,
|
||||
"encoding: ");
|
||||
snprintf(temp,TEMPSIZE, "encoding: ");
|
||||
concatn(length,desc,temp);
|
||||
switch (vgmstream->coding_type) {
|
||||
|
||||
//todo codec bugs with layout inside layouts (ex. TXTP)
|
||||
#ifdef VGM_USE_FFMPEG
|
||||
|
||||
case coding_FFmpeg: {
|
||||
//todo codec bugs with layout inside layouts (ex. TXTP)
|
||||
ffmpeg_codec_data *data = NULL;
|
||||
|
||||
if (vgmstream->layout_type == layout_layered) {
|
||||
@ -2333,61 +2360,68 @@ void describe_vgmstream(VGMSTREAM * vgmstream, char * desc, int length) {
|
||||
|
||||
if (data) {
|
||||
if (data->codec && data->codec->long_name) {
|
||||
snprintf(temp,TEMPSIZE,"%s",data->codec->long_name);
|
||||
snprintf(temp,TEMPSIZE, "%s",data->codec->long_name);
|
||||
} else if (data->codec && data->codec->name) {
|
||||
snprintf(temp,TEMPSIZE,"%s",data->codec->name);
|
||||
snprintf(temp,TEMPSIZE, "%s",data->codec->name);
|
||||
} else {
|
||||
snprintf(temp,TEMPSIZE,"FFmpeg (unknown codec)");
|
||||
snprintf(temp,TEMPSIZE, "FFmpeg (unknown codec)");
|
||||
}
|
||||
} else {
|
||||
snprintf(temp,TEMPSIZE,"FFmpeg");
|
||||
snprintf(temp,TEMPSIZE, "FFmpeg");
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
description = get_vgmstream_coding_description(vgmstream->coding_type);
|
||||
if (!description)
|
||||
description = "CANNOT DECODE";
|
||||
snprintf(temp,TEMPSIZE,"%s",description);
|
||||
if (!description) description = "CANNOT DECODE";
|
||||
snprintf(temp,TEMPSIZE, "%s",description);
|
||||
break;
|
||||
}
|
||||
concatn(length,desc,temp);
|
||||
concatn(length,desc,"\n");
|
||||
|
||||
snprintf(temp,TEMPSIZE,
|
||||
"\nlayout: ");
|
||||
snprintf(temp,TEMPSIZE, "layout: ");
|
||||
concatn(length,desc,temp);
|
||||
{
|
||||
VGMSTREAM* vgmstreamsub = NULL;
|
||||
|
||||
description = get_vgmstream_layout_description(vgmstream->layout_type);
|
||||
if (!description)
|
||||
description = "INCONCEIVABLE";
|
||||
switch (vgmstream->layout_type) {
|
||||
case layout_layered:
|
||||
snprintf(temp,TEMPSIZE,"%s (%i layers)",description, ((layered_layout_data*)vgmstream->layout_data)->layer_count);
|
||||
break;
|
||||
case layout_segmented:
|
||||
snprintf(temp,TEMPSIZE,"%s (%i segments)",description, ((segmented_layout_data*)vgmstream->layout_data)->segment_count);
|
||||
break;
|
||||
default:
|
||||
snprintf(temp,TEMPSIZE,"%s",description);
|
||||
break;
|
||||
description = get_vgmstream_layout_description(vgmstream->layout_type);
|
||||
if (!description) description = "INCONCEIVABLE";
|
||||
|
||||
if (vgmstream->layout_type == layout_layered) {
|
||||
vgmstreamsub = ((layered_layout_data*)vgmstream->layout_data)->layers[0];
|
||||
snprintf(temp,TEMPSIZE, "%s (%i layers)", description, ((layered_layout_data*)vgmstream->layout_data)->layer_count);
|
||||
}
|
||||
else if (vgmstream->layout_type == layout_segmented) {
|
||||
snprintf(temp,TEMPSIZE, "%s (%i segments)", description, ((segmented_layout_data*)vgmstream->layout_data)->segment_count);
|
||||
vgmstreamsub = ((segmented_layout_data*)vgmstream->layout_data)->segments[0];
|
||||
}
|
||||
else {
|
||||
snprintf(temp,TEMPSIZE, "%s",description);
|
||||
}
|
||||
concatn(length,desc,temp);
|
||||
|
||||
/* layouts can contain layouts infinitely let's leave it at one level deep (most common) */
|
||||
if (vgmstreamsub && vgmstreamsub->layout_type == layout_layered) {
|
||||
description = get_vgmstream_layout_description(vgmstreamsub->layout_type);
|
||||
snprintf(temp,TEMPSIZE, " + %s (%i layers)",description, ((layered_layout_data*)vgmstreamsub->layout_data)->layer_count);
|
||||
concatn(length,desc,temp);
|
||||
}
|
||||
else if (vgmstreamsub && vgmstreamsub->layout_type == layout_segmented) {
|
||||
description = get_vgmstream_layout_description(vgmstreamsub->layout_type);
|
||||
snprintf(temp,TEMPSIZE, " + %s (%i segments)",description, ((segmented_layout_data*)vgmstream->layout_data)->segment_count);
|
||||
concatn(length,desc,temp);
|
||||
}
|
||||
}
|
||||
concatn(length,desc,temp);
|
||||
|
||||
snprintf(temp,TEMPSIZE,
|
||||
"\n");
|
||||
concatn(length,desc,temp);
|
||||
concatn(length,desc,"\n");
|
||||
|
||||
if (vgmstream->layout_type == layout_interleave && vgmstream->channels > 1) {
|
||||
snprintf(temp,TEMPSIZE,
|
||||
"interleave: %#x bytes\n",
|
||||
(int32_t)vgmstream->interleave_block_size);
|
||||
snprintf(temp,TEMPSIZE, "interleave: %#x bytes\n", (int32_t)vgmstream->interleave_block_size);
|
||||
concatn(length,desc,temp);
|
||||
|
||||
if (vgmstream->interleave_last_block_size) {
|
||||
snprintf(temp,TEMPSIZE,
|
||||
"interleave last block: %#x bytes\n",
|
||||
(int32_t)vgmstream->interleave_last_block_size);
|
||||
snprintf(temp,TEMPSIZE, "interleave last block: %#x bytes\n", (int32_t)vgmstream->interleave_last_block_size);
|
||||
concatn(length,desc,temp);
|
||||
}
|
||||
}
|
||||
@ -2403,9 +2437,7 @@ void describe_vgmstream(VGMSTREAM * vgmstream, char * desc, int length) {
|
||||
case coding_WWISE_IMA:
|
||||
case coding_REF_IMA:
|
||||
case coding_PSX_cfg:
|
||||
snprintf(temp,TEMPSIZE,
|
||||
"frame size: %#x bytes\n",
|
||||
(int32_t)vgmstream->interleave_block_size);
|
||||
snprintf(temp,TEMPSIZE, "frame size: %#x bytes\n", (int32_t)vgmstream->interleave_block_size);
|
||||
concatn(length,desc,temp);
|
||||
break;
|
||||
default:
|
||||
@ -2413,43 +2445,34 @@ void describe_vgmstream(VGMSTREAM * vgmstream, char * desc, int length) {
|
||||
}
|
||||
}
|
||||
|
||||
snprintf(temp,TEMPSIZE,
|
||||
"metadata from: ");
|
||||
snprintf(temp,TEMPSIZE, "metadata from: ");
|
||||
concatn(length,desc,temp);
|
||||
switch (vgmstream->meta_type) {
|
||||
default:
|
||||
description = get_vgmstream_meta_description(vgmstream->meta_type);
|
||||
if (!description)
|
||||
description = "THEY SHOULD HAVE SENT A POET";
|
||||
snprintf(temp,TEMPSIZE,"%s",description);
|
||||
if (!description) description = "THEY SHOULD HAVE SENT A POET";
|
||||
snprintf(temp,TEMPSIZE, "%s", description);
|
||||
break;
|
||||
}
|
||||
concatn(length,desc,temp);
|
||||
concatn(length,desc,"\n");
|
||||
|
||||
snprintf(temp,TEMPSIZE,
|
||||
"\nbitrate: %d kbps",
|
||||
get_vgmstream_average_bitrate(vgmstream) / 1000);
|
||||
snprintf(temp,TEMPSIZE, "bitrate: %d kbps\n", get_vgmstream_average_bitrate(vgmstream) / 1000); //todo \n?
|
||||
concatn(length,desc,temp);
|
||||
|
||||
/* only interesting if more than one */
|
||||
if (vgmstream->num_streams > 1) {
|
||||
snprintf(temp,TEMPSIZE,
|
||||
"\nstream count: %d",
|
||||
vgmstream->num_streams);
|
||||
snprintf(temp,TEMPSIZE, "stream count: %d\n", vgmstream->num_streams);
|
||||
concatn(length,desc,temp);
|
||||
}
|
||||
|
||||
if (vgmstream->num_streams > 1) {
|
||||
snprintf(temp,TEMPSIZE,
|
||||
"\nstream index: %d",
|
||||
vgmstream->stream_index == 0 ? 1 : vgmstream->stream_index);
|
||||
snprintf(temp,TEMPSIZE, "stream index: %d\n", vgmstream->stream_index == 0 ? 1 : vgmstream->stream_index);
|
||||
concatn(length,desc,temp);
|
||||
}
|
||||
|
||||
if (vgmstream->stream_name[0] != '\0') {
|
||||
snprintf(temp,TEMPSIZE,
|
||||
"\nstream name: %s",
|
||||
vgmstream->stream_name);
|
||||
snprintf(temp,TEMPSIZE, "stream name: %s\n", vgmstream->stream_name);
|
||||
concatn(length,desc,temp);
|
||||
}
|
||||
}
|
||||
|
@ -9,6 +9,8 @@
|
||||
enum { PATH_LIMIT = 32768 };
|
||||
enum { STREAM_NAME_SIZE = 255 };
|
||||
enum { VGMSTREAM_MAX_CHANNELS = 64 };
|
||||
enum { VGMSTREAM_MIN_SAMPLE_RATE = 300 }; /* 300 is Wwise min */
|
||||
enum { VGMSTREAM_MAX_SAMPLE_RATE = 96000 };
|
||||
#ifdef VGMSTREAM_MIXING
|
||||
enum { VGMSTREAM_MAX_MIXING = 64 };
|
||||
#endif
|
||||
@ -146,10 +148,12 @@ typedef enum {
|
||||
coding_MSADPCM_int, /* Microsoft ADPCM (mono) */
|
||||
coding_MSADPCM_ck, /* Microsoft ADPCM (Cricket Audio variation) */
|
||||
coding_WS, /* Westwood Studios VBR ADPCM */
|
||||
coding_AICA, /* Yamaha AICA ADPCM (stereo) */
|
||||
coding_AICA_int, /* Yamaha AICA ADPCM (mono/interleave) */
|
||||
coding_YAMAHA, /* Yamaha ADPCM */
|
||||
coding_YAMAHA_NXAP, /* Yamaha ADPCM (NXAP variation) */
|
||||
|
||||
coding_YAMAHA, /* Yamaha ADPCM (stereo) */
|
||||
coding_YAMAHA_int, /* Yamaha ADPCM (mono/interleave) */
|
||||
coding_ASKA, /* Aska ADPCM */
|
||||
coding_NXAP, /* NXAP ADPCM */
|
||||
|
||||
coding_NDS_PROCYON, /* Procyon Studio ADPCM */
|
||||
coding_L5_555, /* Level-5 0x555 ADPCM */
|
||||
coding_LSF, /* lsf ADPCM (Fastlane Street Racing iPhone)*/
|
||||
@ -449,7 +453,7 @@ typedef enum {
|
||||
meta_STR_ASR, /* Donkey Kong Jet Race */
|
||||
meta_ZWDSP, /* Zack and Wiki */
|
||||
meta_VGS, /* Guitar Hero Encore - Rocks the 80s */
|
||||
meta_DC_DCSW_DCS, /* Evil Twin - Cypriens Chronicles (DC) */
|
||||
meta_DCS_WAV,
|
||||
meta_SMP,
|
||||
meta_WII_SNG, /* Excite Trucks */
|
||||
meta_MUL,
|
||||
@ -727,6 +731,48 @@ typedef enum {
|
||||
|
||||
} meta_t;
|
||||
|
||||
/* standard WAVEFORMATEXTENSIBLE speaker positions */
|
||||
typedef enum {
|
||||
speaker_FL = (1 << 0), /* front left */
|
||||
speaker_FR = (1 << 1), /* front right */
|
||||
speaker_FC = (1 << 2), /* front center */
|
||||
speaker_LFE = (1 << 3), /* low frequency effects */
|
||||
speaker_BL = (1 << 4), /* back left */
|
||||
speaker_BR = (1 << 5), /* back right */
|
||||
speaker_FLC = (1 << 6), /* front left center */
|
||||
speaker_FRC = (1 << 7), /* front right center */
|
||||
speaker_BC = (1 << 8), /* back center */
|
||||
speaker_SL = (1 << 9), /* side left */
|
||||
speaker_SR = (1 << 10), /* side right */
|
||||
|
||||
speaker_TC = (1 << 11), /* top center*/
|
||||
speaker_TFL = (1 << 12), /* top front left */
|
||||
speaker_TFC = (1 << 13), /* top front center */
|
||||
speaker_TFR = (1 << 14), /* top front right */
|
||||
speaker_TBL = (1 << 15), /* top back left */
|
||||
speaker_TBC = (1 << 16), /* top back center */
|
||||
speaker_TBR = (1 << 17), /* top back left */
|
||||
|
||||
} speaker_t;
|
||||
|
||||
/* typical mappings that metas may use to set channel_layout (but plugin must actually use it)
|
||||
* (in order, so 3ch file could be mapped to FL FR FC or FL FR LFE but not LFE FL FR) */
|
||||
typedef enum {
|
||||
mapping_MONO = speaker_FC,
|
||||
mapping_STEREO = speaker_FL | speaker_FR,
|
||||
mapping_2POINT1 = speaker_FL | speaker_FR | speaker_LFE,
|
||||
mapping_2POINT1_xiph = speaker_FL | speaker_FR | speaker_FC,
|
||||
mapping_QUAD = speaker_FL | speaker_FR | speaker_BL | speaker_BR,
|
||||
mapping_QUAD_surround = speaker_FL | speaker_FR | speaker_FC | speaker_BC,
|
||||
mapping_5POINT0 = speaker_FL | speaker_FR | speaker_LFE | speaker_BL | speaker_BR,
|
||||
mapping_5POINT0_xiph = speaker_FL | speaker_FR | speaker_FC | speaker_BL | speaker_BR,
|
||||
mapping_5POINT1 = speaker_FL | speaker_FR | speaker_FC | speaker_LFE | speaker_BL | speaker_BR,
|
||||
mapping_5POINT1_surround = speaker_FL | speaker_FR | speaker_FC | speaker_LFE | speaker_SL | speaker_SR,
|
||||
mapping_7POINT0 = speaker_FL | speaker_FR | speaker_FC | speaker_LFE | speaker_BC | speaker_FLC | speaker_FRC,
|
||||
mapping_7POINT1 = speaker_FL | speaker_FR | speaker_FC | speaker_LFE | speaker_BL | speaker_BR | speaker_FLC | speaker_FRC,
|
||||
mapping_7POINT1_surround = speaker_FL | speaker_FR | speaker_FC | speaker_LFE | speaker_BL | speaker_BR | speaker_SL | speaker_SR,
|
||||
} mapping_t;
|
||||
|
||||
#ifdef VGMSTREAM_MIXING
|
||||
/* mixing info */
|
||||
typedef enum {
|
||||
@ -832,6 +878,9 @@ typedef struct {
|
||||
size_t stream_size; /* info to properly calculate bitrate in case of subsongs */
|
||||
char stream_name[STREAM_NAME_SIZE]; /* name of the current stream (info), if the file stores it and it's filled */
|
||||
|
||||
/* mapping config (info for plugins) */
|
||||
uint32_t channel_layout; /* order: FL FR FC LFE BL BR FLC FRC BC SL SR etc (WAVEFORMATEX flags where FL=lowest bit set) */
|
||||
|
||||
/* other config */
|
||||
int allow_dual_stereo; /* search for dual stereo (file_L.ext + file_R.ext = single stereo file) */
|
||||
#ifndef VGMSTREAM_MIXING
|
||||
|
@ -1509,11 +1509,13 @@ static void load_tagfile_info(in_char* filename) {
|
||||
/* load all tags from tagfile */
|
||||
tagFile = open_winamp_streamfile_by_ipath(tagfile_path_i);
|
||||
if (tagFile != NULL) {
|
||||
VGMSTREAM_TAGS tag;
|
||||
VGMSTREAM_TAGS *tags;
|
||||
const char *tag_key, *tag_val;
|
||||
int i;
|
||||
|
||||
vgmstream_tags_reset(&tag, filename_utf8);
|
||||
while (vgmstream_tags_next_tag(&tag, tagFile)) {
|
||||
tags = vgmstream_tags_init(&tag_key, &tag_val);
|
||||
vgmstream_tags_reset(tags, filename_utf8);
|
||||
while (vgmstream_tags_next_tag(tags, tagFile)) {
|
||||
int repeated_tag = 0;
|
||||
int current_tag = last_tags.tag_count;
|
||||
if (current_tag >= WINAMP_TAGS_ENTRY_MAX)
|
||||
@ -1521,7 +1523,7 @@ static void load_tagfile_info(in_char* filename) {
|
||||
|
||||
/* should overwrite repeated tags as global tags may appear multiple times */
|
||||
for (i = 0; i < current_tag; i++) {
|
||||
if (strcmp(last_tags.keys[i], tag.key) == 0) {
|
||||
if (strcmp(last_tags.keys[i], tag_key) == 0) {
|
||||
current_tag = i;
|
||||
repeated_tag = 1;
|
||||
break;
|
||||
@ -1529,13 +1531,14 @@ static void load_tagfile_info(in_char* filename) {
|
||||
}
|
||||
|
||||
last_tags.keys[current_tag][0] = '\0';
|
||||
strncat(last_tags.keys[current_tag], tag.key, WINAMP_TAGS_ENTRY_SIZE);
|
||||
strncat(last_tags.keys[current_tag], tag_key, WINAMP_TAGS_ENTRY_SIZE);
|
||||
last_tags.vals[current_tag][0] = '\0';
|
||||
strncat(last_tags.vals[current_tag], tag.val, WINAMP_TAGS_ENTRY_SIZE);
|
||||
strncat(last_tags.vals[current_tag], tag_val, WINAMP_TAGS_ENTRY_SIZE);
|
||||
if (!repeated_tag)
|
||||
last_tags.tag_count++;
|
||||
}
|
||||
|
||||
vgmstream_tags_close(tags);
|
||||
close_streamfile(tagFile);
|
||||
last_tags.loaded = 1;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user