mirror of
https://github.com/vgmstream/vgmstream.git
synced 2024-11-28 16:30:54 +01:00
commit
bc15b99fce
@ -144,6 +144,7 @@ Should be buildable with Autotools, much like the Audacious plugin, though requi
|
||||
|
||||
Windows builds are possible with libao.dll and includes, but some features are disabled.
|
||||
|
||||
libao is licensed under the GPL v2 or later.
|
||||
|
||||
## External libraries
|
||||
Support for some codecs is done with external libs, instead of copying their code in vgmstream. There are various reasons for this:
|
||||
@ -164,6 +165,7 @@ Below is a quick explanation of each library and how to compile binaries from th
|
||||
Adds support for Vorbis (inside Ogg and custom containers).
|
||||
- Source: http://downloads.xiph.org/releases/vorbis/libvorbis-1.3.6.zip
|
||||
- DLL: `libvorbis.dll`
|
||||
- licensed under the 3-clause BSD license.
|
||||
|
||||
Should be buildable with MSVC (in /win32 dir are .sln files) or autotools (use `autogen.sh`).
|
||||
|
||||
@ -173,6 +175,7 @@ Adds support for MPEG (MP1/MP2/MP3).
|
||||
- Source: https://sourceforge.net/projects/mpg123/files/mpg123/1.25.10/
|
||||
- Builds: http://www.mpg123.de/download/win32/1.25.10/
|
||||
- DLL: `libmpg123-0.dll`
|
||||
- licensed under the LGPL v2.1
|
||||
|
||||
Must use autotools (sh configure, make, make install), though some scripts simplify the process: `makedll.sh`, `windows-builds.sh`.
|
||||
|
||||
@ -181,7 +184,9 @@ Must use autotools (sh configure, make, make install), though some scripts simpl
|
||||
Adds support for ITU-T G.722.1 annex C (standardization of Polycom Siren 14).
|
||||
- Source: https://github.com/bnnm/vgmstream-g7221
|
||||
- Alt lib (has volume problems): https://github.com/kode54/libg7221_decode
|
||||
- licensed under the LGPL v3 (possibly invalid and Polycom's)
|
||||
- DLL: `libg7221_decode.dll`
|
||||
- unknown license (possibly invalid and Polycom's)
|
||||
|
||||
Use make `libg7221_decode.dll`.
|
||||
|
||||
@ -189,6 +194,7 @@ Use make `libg7221_decode.dll`.
|
||||
Adds support for ITU-T G.719 (standardization of Polycom Siren 22).
|
||||
- Source: https://github.com/kode54/libg719_decode
|
||||
- DLL: `libg719_decode.dll`
|
||||
- unknown license (possibly invalid and Polycom's)
|
||||
|
||||
Requires MSVC (use `g719.sln`).
|
||||
|
||||
@ -197,6 +203,7 @@ Requires MSVC (use `g719.sln`).
|
||||
Adds support for multiple codecs: ATRAC3, ATRAC3plus, XMA1/2, WMA v1, WMA v2, WMAPro, AAC, Bink, AC3/SPDIF, Opus, Musepack, FLAC, etc (also Vorbis and MPEG for certain cases).
|
||||
- Source: https://github.com/FFmpeg/FFmpeg/
|
||||
- DLLs: `avcodec-vgmstream-58.dll`, `avformat-vgmstream-58.dll`, `avutil-vgmstream-56.dll`, `swresample-vgmstream-3.dll`
|
||||
- primarily licensed under the LGPL v2.1 or later, with portions licensed under the GPL v2
|
||||
|
||||
vgmstream's FFmpeg builds remove many unnecessary parts of FFmpeg to trim down its gigantic size, and are also built with the "vgmstream-" preffix (to avoid clashing with other plugins). Current options can be seen in `ffmpeg_options.txt`.
|
||||
|
||||
@ -211,6 +218,7 @@ Both may need yasm somewhere in PATH to properly compile: https://yasm.tortall.n
|
||||
Adds support for ATRAC9.
|
||||
- Source: https://github.com/Thealexbarney/LibAtrac9
|
||||
- DLL: `libatrac9.dll`
|
||||
- licensed under the MIT license
|
||||
|
||||
Use MSCV and `libatrac9.sln`, or GCC and the Makefile included.
|
||||
|
||||
@ -220,6 +228,7 @@ Adds support for FSB CELT versions 0.6.1 and 0.11.0.
|
||||
- Source (0.6.1): http://downloads.us.xiph.org/releases/celt/celt-0.6.1.tar.gz
|
||||
- Source (0.11.0): http://downloads.xiph.org/releases/celt/celt-0.11.0.tar.gz
|
||||
- DLL: `libcelt-0061.dll`, `libcelt-0110.dll`
|
||||
- licensed under the MIT license
|
||||
|
||||
FSB uses two incompatible, older libcelt versions. Both libraries export the same symbols so normally can't coexist together. To get them working we need to make sure symbols are renamed first. This may be solved in various ways:
|
||||
- using dynamic loading (LoadLibrary) but for portability it isn't an option
|
||||
|
175
src/coding/mpeg_custom_utils_eamp3.c
Normal file
175
src/coding/mpeg_custom_utils_eamp3.c
Normal file
@ -0,0 +1,175 @@
|
||||
#include "mpeg_decoder.h"
|
||||
|
||||
#ifdef VGM_USE_MPEG
|
||||
|
||||
/* parsed info from a single EAMP3 frame */
|
||||
typedef struct {
|
||||
uint32_t extended_flag;
|
||||
uint32_t stereo_flag; /* assumed */
|
||||
uint32_t unknown_flag; /* unused? */
|
||||
uint32_t frame_size; /* full size including headers and pcm block */
|
||||
uint32_t pcm_number; /* samples in the PCM block (typically 1 MPEG frame, 1152) */
|
||||
|
||||
uint32_t pre_size; /* size of the header part */
|
||||
uint32_t mpeg_size; /* size of the MPEG part */
|
||||
uint32_t pcm_size; /* size of the PCM block */
|
||||
} eamp3_frame_info;
|
||||
|
||||
static int eamp3_parse_frame(VGMSTREAMCHANNEL *stream, mpeg_codec_data *data, eamp3_frame_info * eaf);
|
||||
static int eamp3_write_pcm_block(VGMSTREAMCHANNEL *stream, mpeg_codec_data *data, int num_stream, eamp3_frame_info * eaf);
|
||||
static int eamp3_skip_data(VGMSTREAMCHANNEL *stream, mpeg_codec_data *data, int num_stream, int at_start);
|
||||
|
||||
/* init config and validate */
|
||||
int mpeg_custom_setup_init_eamp3(STREAMFILE *streamFile, off_t start_offset, mpeg_codec_data *data, coding_t *coding_type) {
|
||||
mpeg_frame_info info;
|
||||
uint16_t frame_header;
|
||||
size_t header_size;
|
||||
|
||||
|
||||
/* test unknown stuff */
|
||||
frame_header = (uint16_t)read_16bitLE(start_offset+0x00, streamFile);
|
||||
if (frame_header & 0x2000) {
|
||||
VGM_LOG("EAMP3: found unknown bit 13\n");
|
||||
goto fail;
|
||||
}
|
||||
if ((frame_header & 0x8000) && (uint32_t)read_32bitLE(start_offset+0x02, streamFile) > 0xFFFF) {
|
||||
VGM_LOG("EAMP3: found big PCM block\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* get frame info at offset */
|
||||
header_size = (frame_header & 0x8000) ? 0x06 : 0x02;
|
||||
if (!mpeg_get_frame_info(streamFile, start_offset+header_size, &info))
|
||||
goto fail;
|
||||
switch(info.layer) {
|
||||
case 1: *coding_type = coding_MPEG_layer1; break;
|
||||
case 2: *coding_type = coding_MPEG_layer2; break;
|
||||
case 3: *coding_type = coding_MPEG_layer3; break;
|
||||
default: goto fail;
|
||||
}
|
||||
data->channels_per_frame = info.channels;
|
||||
data->samples_per_frame = info.frame_samples;
|
||||
data->bitrate_per_frame = info.bit_rate;
|
||||
data->sample_rate_per_frame = info.sample_rate;
|
||||
|
||||
|
||||
return 1;
|
||||
fail:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* reads custom frame header + MPEG data + (optional) PCM block */
|
||||
int mpeg_custom_parse_frame_eamp3(VGMSTREAMCHANNEL *stream, mpeg_codec_data *data, int num_stream) {
|
||||
mpeg_custom_stream *ms = data->streams[num_stream];
|
||||
eamp3_frame_info eaf;
|
||||
int ok;
|
||||
|
||||
|
||||
if (!eamp3_skip_data(stream, data, num_stream, 1))
|
||||
goto fail;
|
||||
|
||||
ok = eamp3_parse_frame(stream, data, &eaf);
|
||||
if (!ok) goto fail;
|
||||
|
||||
ok = eamp3_write_pcm_block(stream, data, num_stream, &eaf);
|
||||
if (!ok) goto fail;
|
||||
|
||||
ms->bytes_in_buffer = read_streamfile(ms->buffer,stream->offset + eaf.pre_size, eaf.mpeg_size, stream->streamfile);
|
||||
stream->offset += eaf.frame_size;
|
||||
|
||||
if (!eamp3_skip_data(stream, data, num_stream, 0))
|
||||
goto fail;
|
||||
|
||||
return 1;
|
||||
fail:
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int eamp3_parse_frame(VGMSTREAMCHANNEL *stream, mpeg_codec_data *data, eamp3_frame_info * eaf) {
|
||||
uint16_t current_header = (uint16_t)read_16bitLE(stream->offset+0x00, stream->streamfile);
|
||||
|
||||
eaf->extended_flag = (current_header & 0x8000);
|
||||
eaf->stereo_flag = (current_header & 0x4000);
|
||||
eaf->unknown_flag = (current_header & 0x2000);
|
||||
eaf->frame_size = (current_header & 0x1FFF); /* full size including PCM block */
|
||||
eaf->pcm_number = 0;
|
||||
if (eaf->extended_flag > 0) {
|
||||
eaf->pcm_number = (uint32_t)read_32bitLE(stream->offset+0x02, stream->streamfile);
|
||||
eaf->pcm_size = sizeof(sample) * eaf->pcm_number * data->channels_per_frame;
|
||||
eaf->pre_size = 0x06;
|
||||
eaf->mpeg_size = eaf->frame_size - eaf->pre_size - eaf->pcm_size;
|
||||
if (eaf->frame_size < eaf->pre_size + eaf->pcm_size) {
|
||||
VGM_LOG("EAMP3: bad pcm size at %x\n", (uint32_t)stream->offset);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
else {
|
||||
eaf->pcm_size = 0;
|
||||
eaf->pre_size = 0x02;
|
||||
eaf->mpeg_size = eaf->frame_size - eaf->pre_size;
|
||||
}
|
||||
|
||||
return 1;
|
||||
fail:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* write PCM block directly to sample buffer and setup decode discard (see EALayer3). */
|
||||
static int eamp3_write_pcm_block(VGMSTREAMCHANNEL *stream, mpeg_codec_data *data, int num_stream, eamp3_frame_info * eaf) {
|
||||
mpeg_custom_stream *ms = data->streams[num_stream];
|
||||
size_t bytes_filled;
|
||||
int i;
|
||||
|
||||
|
||||
bytes_filled = sizeof(sample) * ms->samples_filled * data->channels_per_frame;
|
||||
if (bytes_filled + eaf->pcm_size > ms->output_buffer_size) {
|
||||
VGM_LOG("EAMP3: can't fill the sample buffer with 0x%x\n", eaf->pcm_size);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
||||
if (eaf->pcm_number) {
|
||||
|
||||
/* read + write PCM block samples (always LE) */
|
||||
for (i = 0; i < eaf->pcm_number * data->channels_per_frame; i++) {
|
||||
off_t pcm_offset = stream->offset + eaf->pre_size + eaf->mpeg_size + sizeof(sample)*i;
|
||||
int16_t pcm_sample = read_16bitLE(pcm_offset,stream->streamfile);
|
||||
put_16bitLE(ms->output_buffer + bytes_filled + sizeof(sample)*i, pcm_sample);
|
||||
}
|
||||
ms->samples_filled += eaf->pcm_number;
|
||||
|
||||
/* modify decoded samples */
|
||||
{
|
||||
size_t decode_to_discard = eaf->pcm_number; //todo guessed
|
||||
ms->decode_to_discard += decode_to_discard;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
fail:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Skip EA-frames from other streams for .sns/sps multichannel (see EALayer3). */
|
||||
static int eamp3_skip_data(VGMSTREAMCHANNEL *stream, mpeg_codec_data *data, int num_stream, int at_start) {
|
||||
int ok, i;
|
||||
eamp3_frame_info eaf;
|
||||
int skips = at_start ? num_stream : data->streams_size - 1 - num_stream;
|
||||
|
||||
|
||||
for (i = 0; i < skips; i++) {
|
||||
ok = eamp3_parse_frame(stream, data, &eaf);
|
||||
if (!ok) goto fail;
|
||||
|
||||
//;VGM_LOG("s%i: skipping %x, now at %lx\n", num_stream,eaf.frame_size,stream->offset);
|
||||
stream->offset += eaf.frame_size;
|
||||
}
|
||||
//;VGM_LOG("s%i: skipped %i frames, now at %lx\n", num_stream,skips,stream->offset);
|
||||
|
||||
return 1;
|
||||
fail:
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
@ -140,6 +140,7 @@ mpeg_codec_data *init_mpeg_custom(STREAMFILE *streamFile, off_t start_offset, co
|
||||
case MPEG_EAL32P:
|
||||
case MPEG_EAL32S: ok = mpeg_custom_setup_init_ealayer3(streamFile, start_offset, data, coding_type); break;
|
||||
case MPEG_AWC: ok = mpeg_custom_setup_init_awc(streamFile, start_offset, data, coding_type); break;
|
||||
case MPEG_EAMP3: ok = mpeg_custom_setup_init_eamp3(streamFile, start_offset, data, coding_type); break;
|
||||
default: ok = mpeg_custom_setup_init_default(streamFile, start_offset, data, coding_type); break;
|
||||
}
|
||||
if (!ok)
|
||||
@ -399,6 +400,7 @@ static void decode_mpeg_custom_stream(VGMSTREAMCHANNEL *stream, mpeg_codec_data
|
||||
case MPEG_EAL32S: ok = mpeg_custom_parse_frame_ealayer3(stream, data, num_stream); break;
|
||||
case MPEG_AHX: ok = mpeg_custom_parse_frame_ahx(stream, data, num_stream); break;
|
||||
case MPEG_AWC: ok = mpeg_custom_parse_frame_awc(stream, data, num_stream); break;
|
||||
case MPEG_EAMP3: ok = mpeg_custom_parse_frame_eamp3(stream, data, num_stream); break;
|
||||
default: ok = mpeg_custom_parse_frame_default(stream, data, num_stream); break;
|
||||
}
|
||||
if (!ok) {
|
||||
|
@ -21,11 +21,13 @@ int mpeg_get_frame_info(STREAMFILE *streamfile, off_t offset, mpeg_frame_info *
|
||||
int mpeg_custom_setup_init_default(STREAMFILE *streamFile, off_t start_offset, mpeg_codec_data *data, coding_t *coding_type);
|
||||
int mpeg_custom_setup_init_ealayer3(STREAMFILE *streamFile, off_t start_offset, mpeg_codec_data *data, coding_t *coding_type);
|
||||
int mpeg_custom_setup_init_awc(STREAMFILE *streamFile, off_t start_offset, mpeg_codec_data *data, coding_t *coding_type);
|
||||
int mpeg_custom_setup_init_eamp3(STREAMFILE *streamFile, off_t start_offset, mpeg_codec_data *data, coding_t *coding_type);
|
||||
|
||||
int mpeg_custom_parse_frame_default(VGMSTREAMCHANNEL *stream, mpeg_codec_data *data, int num_stream);
|
||||
int mpeg_custom_parse_frame_ahx(VGMSTREAMCHANNEL *stream, mpeg_codec_data *data, int num_stream);
|
||||
int mpeg_custom_parse_frame_ealayer3(VGMSTREAMCHANNEL *stream, mpeg_codec_data *data, int num_stream);
|
||||
int mpeg_custom_parse_frame_awc(VGMSTREAMCHANNEL *stream, mpeg_codec_data *data, int num_stream);
|
||||
int mpeg_custom_parse_frame_eamp3(VGMSTREAMCHANNEL *stream, mpeg_codec_data *data, int num_stream);
|
||||
|
||||
#endif/* VGM_USE_MPEG */
|
||||
|
||||
|
@ -263,6 +263,7 @@ static const char* extension_list[] = {
|
||||
"nop",
|
||||
"nps",
|
||||
"npsf", //fake extension/header id for .nps (in bigfiles)
|
||||
"nus3audio",
|
||||
"nus3bank",
|
||||
"nwa",
|
||||
"nwav",
|
||||
|
@ -846,6 +846,10 @@
|
||||
RelativePath=".\meta\nub_xma.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\meta\nus3audio.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\meta\nus3bank.c"
|
||||
>
|
||||
@ -1837,6 +1841,10 @@
|
||||
<File
|
||||
RelativePath=".\coding\mpeg_custom_utils_ealayer3.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\coding\mpeg_custom_utils_eamp3.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\coding\mpeg_decoder.c"
|
||||
|
@ -319,6 +319,7 @@
|
||||
<ClCompile Include="meta\ngc_ulw.c" />
|
||||
<ClCompile Include="meta\ngc_vid1.c" />
|
||||
<ClCompile Include="meta\nub_xma.c" />
|
||||
<ClCompile Include="meta\nus3audio.c" />
|
||||
<ClCompile Include="meta\nus3bank.c" />
|
||||
<ClCompile Include="meta\nwa.c" />
|
||||
<ClCompile Include="meta\nwav.c" />
|
||||
@ -515,6 +516,7 @@
|
||||
<ClCompile Include="coding\mpeg_custom_utils_ahx.c" />
|
||||
<ClCompile Include="coding\mpeg_custom_utils_awc.c" />
|
||||
<ClCompile Include="coding\mpeg_custom_utils_ealayer3.c" />
|
||||
<ClCompile Include="coding\mpeg_custom_utils_eamp3.c" />
|
||||
<ClCompile Include="coding\mpeg_decoder.c" />
|
||||
<ClCompile Include="coding\msadpcm_decoder.c" />
|
||||
<ClCompile Include="coding\nds_procyon_decoder.c" />
|
||||
|
@ -520,6 +520,9 @@
|
||||
<ClCompile Include="meta\nub_xma.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="meta\nus3audio.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="meta\nus3bank.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
@ -1090,6 +1093,9 @@
|
||||
<ClCompile Include="coding\mpeg_custom_utils_ealayer3.c">
|
||||
<Filter>coding\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="coding\mpeg_custom_utils_eamp3.c">
|
||||
<Filter>coding\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="coding\mpeg_decoder.c">
|
||||
<Filter>coding\Source Files</Filter>
|
||||
</ClCompile>
|
||||
|
@ -19,6 +19,7 @@
|
||||
#define EAAC_CODEC_DSP 0x08
|
||||
#define EAAC_CODEC_EASPEEX 0x09
|
||||
#define EAAC_CODEC_EATRAX 0x0a
|
||||
#define EAAC_CODEC_EAMP3 0x0b
|
||||
#define EAAC_CODEC_EAOPUS 0x0c
|
||||
|
||||
#define EAAC_FLAG_NONE 0x00
|
||||
@ -680,6 +681,25 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef VGM_USE_MPEG
|
||||
case EAAC_CODEC_EAMP3: { /* "EM30"?: EAMP3 [Need for Speed 2015 (PS4)] */
|
||||
mpeg_custom_config cfg = {0};
|
||||
|
||||
start_offset = 0x00; /* must point to the custom streamfile's beginning */
|
||||
|
||||
temp_streamFile = setup_eaac_streamfile(streamData, eaac.version, eaac.codec, eaac.streamed,0,0, eaac.stream_offset);
|
||||
if (!temp_streamFile) goto fail;
|
||||
|
||||
vgmstream->codec_data = init_mpeg_custom(temp_streamFile, start_offset, &vgmstream->coding_type, vgmstream->channels, MPEG_EAMP3, &cfg);
|
||||
if (!vgmstream->codec_data) goto fail;
|
||||
vgmstream->layout_type = layout_none;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef VGM_USE_FFMPEG
|
||||
case EAAC_CODEC_EAOPUS: { /* EAOpus (unknown FourCC) [FIFA 17 (PC), FIFA 19 (Switch)]*/
|
||||
int skip = 0;
|
||||
@ -701,7 +721,7 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST
|
||||
}
|
||||
#endif
|
||||
|
||||
case EAAC_CODEC_EASPEEX: /* EASpeex (libspeex variant, base versions vary: 1.0.5, 1.2beta3) */ //todo
|
||||
case EAAC_CODEC_EASPEEX: /* "Esp0"?: EASpeex (libspeex variant, base versions vary: 1.0.5, 1.2beta3) */ //todo
|
||||
default:
|
||||
VGM_LOG("EA EAAC: unknown codec 0x%02x\n", eaac.codec);
|
||||
goto fail;
|
||||
|
@ -85,6 +85,7 @@ static size_t eaac_io_read(STREAMFILE *streamfile, uint8_t *dest, off_t offset,
|
||||
case 0x05: /* EALayer3 v1 */
|
||||
case 0x06: /* EALayer3 v2 "PCM" */
|
||||
case 0x07: /* EALayer3 v2 "Spike" */
|
||||
case 0x0b: /* EAMP3 */
|
||||
case 0x0c: /* EAOpus */
|
||||
data->skip_size = 0x08;
|
||||
data->data_size = data->block_size - data->skip_size;
|
||||
@ -205,6 +206,7 @@ static size_t eaac_io_size(STREAMFILE *streamfile, eaac_io_data* data) {
|
||||
case 0x05: /* EALayer3 v1 */
|
||||
case 0x06: /* EALayer3 v2 "PCM" */
|
||||
case 0x07: /* EALayer3 v2 "Spike" */
|
||||
case 0x0b: /* EAMP3 */
|
||||
case 0x0c: /* EAOpus */
|
||||
data_size = block_size - 0x08;
|
||||
break;
|
||||
|
@ -819,4 +819,6 @@ VGMSTREAM * init_vgmstream_zsnd(STREAMFILE * streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_ogg_opus(STREAMFILE * streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_nus3audio(STREAMFILE * streamFile);
|
||||
|
||||
#endif /*_META_H*/
|
||||
|
119
src/meta/nus3audio.c
Normal file
119
src/meta/nus3audio.c
Normal file
@ -0,0 +1,119 @@
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
typedef enum { IDSP, OPUS, } nus3audio_codec;
|
||||
|
||||
/* .nus3audio - Namco's newest newest audio container [Super Smash Bros. Ultimate (Switch)] */
|
||||
VGMSTREAM * init_vgmstream_nus3audio(STREAMFILE *streamFile) {
|
||||
VGMSTREAM *vgmstream = NULL;
|
||||
STREAMFILE *temp_streamFile = NULL;
|
||||
off_t subfile_offset = 0, name_offset = 0;
|
||||
size_t subfile_size = 0;
|
||||
nus3audio_codec codec;
|
||||
const char* fake_ext = NULL;
|
||||
int total_subsongs, target_subsong = streamFile->stream_index;
|
||||
|
||||
|
||||
/* checks */
|
||||
if (!check_extensions(streamFile, "nus3audio"))
|
||||
goto fail;
|
||||
if (read_32bitBE(0x00,streamFile) != 0x4E555333) /* "NUS3" */
|
||||
goto fail;
|
||||
if (read_32bitLE(0x04,streamFile) + 0x08 != get_streamfile_size(streamFile))
|
||||
goto fail;
|
||||
if (read_32bitBE(0x08,streamFile) != 0x41554449) /* "AUDI" */
|
||||
goto fail;
|
||||
|
||||
|
||||
/* parse existing chunks */
|
||||
{
|
||||
off_t offset = 0x0c;
|
||||
size_t file_size = get_streamfile_size(streamFile);
|
||||
uint32_t codec_id = 0;
|
||||
|
||||
total_subsongs = 0;
|
||||
|
||||
while (offset < file_size) {
|
||||
uint32_t chunk_id = (uint32_t)read_32bitBE(offset+0x00, streamFile);
|
||||
size_t chunk_size = (size_t)read_32bitLE(offset+0x04, streamFile);
|
||||
|
||||
switch(chunk_id) {
|
||||
case 0x494E4458: /* "INDX": audio index */
|
||||
total_subsongs = read_32bitLE(offset+0x08 + 0x00,streamFile);
|
||||
if (target_subsong == 0) target_subsong = 1;
|
||||
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;
|
||||
break;
|
||||
|
||||
case 0x4E4D4F46: /* "NMOF": name offsets (absolute, inside TNNM) */
|
||||
name_offset = read_32bitLE(offset+0x08 + 0x04*(target_subsong-1),streamFile);
|
||||
break;
|
||||
|
||||
case 0x41444F46: /* "ADOF": audio offsets (absolute, inside PACK) */
|
||||
subfile_offset = read_32bitLE(offset+0x08 + 0x08*(target_subsong-1) + 0x00,streamFile);
|
||||
subfile_size = read_32bitLE(offset+0x08 + 0x08*(target_subsong-1) + 0x04,streamFile);
|
||||
break;
|
||||
|
||||
case 0x544E4944: /* "TNID": tone ids? */
|
||||
case 0x544E4E4D: /* "TNNM": tone names */
|
||||
case 0x4A554E4B: /* "JUNK": padding */
|
||||
case 0x5041434B: /* "PACK": main data */
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
offset += 0x08 + chunk_size;
|
||||
}
|
||||
|
||||
if (total_subsongs == 0 || subfile_offset == 0 || subfile_size == 0) {
|
||||
VGM_LOG("NUS3AUDIO: subfile not found\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
codec_id = read_32bitBE(subfile_offset, streamFile);
|
||||
switch(codec_id) {
|
||||
case 0x49445350: /* "IDSP" */
|
||||
codec = IDSP;
|
||||
fake_ext = "idsp";
|
||||
break;
|
||||
case 0x4F505553: /* "OPUS" */
|
||||
codec = OPUS;
|
||||
fake_ext = "opus";
|
||||
break;
|
||||
default:
|
||||
VGM_LOG("NUS3AUDIO: unknown codec %x\n", codec_id);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
temp_streamFile = setup_subfile_streamfile(streamFile, subfile_offset,subfile_size, fake_ext);
|
||||
if (!temp_streamFile) goto fail;
|
||||
|
||||
/* init the VGMSTREAM */
|
||||
switch(codec) {
|
||||
case IDSP:
|
||||
vgmstream = init_vgmstream_idsp_nus3(temp_streamFile);
|
||||
if (!vgmstream) goto fail;
|
||||
break;
|
||||
case OPUS:
|
||||
vgmstream = init_vgmstream_opus_nus3(temp_streamFile);
|
||||
if (!vgmstream) goto fail;
|
||||
break;
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
|
||||
vgmstream->num_streams = total_subsongs;
|
||||
if (name_offset) /* null-terminated */
|
||||
read_string(vgmstream->stream_name,STREAM_NAME_SIZE, name_offset,streamFile);
|
||||
|
||||
close_streamfile(temp_streamFile);
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_streamfile(temp_streamFile);
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -456,6 +456,7 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = {
|
||||
init_vgmstream_opus_opusx,
|
||||
init_vgmstream_dsp_adpcmx,
|
||||
init_vgmstream_ogg_opus,
|
||||
init_vgmstream_nus3audio,
|
||||
|
||||
/* lowest priority metas (should go after all metas, and TXTH should go before raw formats) */
|
||||
init_vgmstream_txth, /* proper parsers should supersede TXTH, once added */
|
||||
|
@ -952,7 +952,8 @@ typedef enum {
|
||||
MPEG_EAL32P, /* EALayer3 v2 "PCM", custom frames with v2 header + bigger PCM blocks? */
|
||||
MPEG_EAL32S, /* EALayer3 v2 "Spike", custom frames with v2 header + smaller PCM blocks? */
|
||||
MPEG_LYN, /* N streams of fixed interleave */
|
||||
MPEG_AWC /* N streams in block layout (music) or absolute offsets (sfx) */
|
||||
MPEG_AWC, /* N streams in block layout (music) or absolute offsets (sfx) */
|
||||
MPEG_EAMP3 /* custom frame header + MPEG frame + PCM blocks */
|
||||
} mpeg_custom_t;
|
||||
|
||||
/* config for the above modes */
|
||||
|
Loading…
Reference in New Issue
Block a user