Merge pull request #687 from bnnm/fsb-sil

fsb sil
This commit is contained in:
bnnm 2020-08-15 20:44:03 +02:00 committed by GitHub
commit 5682f3b9cc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 179 additions and 29 deletions

View File

@ -235,6 +235,30 @@ loop_mode = keep
```
### Silent files
You can put `?.` in an entry to make a silent (non-existing) file. By default takes channels and sample rate of nearby files, can be combined with regular commands to configure.
```
intro.adx
?.silence #b 3.0 # 3 seconds of silence
loop.adx
```
It also doubles as a quick "silence this file" while keeping the same structure, for complex cases. The `.` can actually be anywhere after `?`, but must appear before commands to function correctly.
```
layer1a.adx
?layer1b.adx
group = -L2
?layer2a.adx
layer2b.adx
group = -L2
group = -S2
```
Most of the time you can do the same with `#p`/`#P` padding commands or `#@volume 0.0`. This is mainly for complex engines that combine silent entries in twisted ways. You can't silence `group` with `?group` though since they aren't considered "entries".
## TXTP COMMANDS
You can set file commands by adding multiple `#(command)` after the name. `#(space)(anything)` is considered a comment and ignored, as well as any command not understood.

View File

@ -293,6 +293,9 @@ int get_vgmstream_samples_per_frame(VGMSTREAM* vgmstream) {
* (or some internal sample buffer max too). */
switch (vgmstream->coding_type) {
case coding_SILENCE:
return 0;
case coding_CRI_ADX:
case coding_CRI_ADX_fixed:
case coding_CRI_ADX_exp:
@ -495,6 +498,9 @@ int get_vgmstream_samples_per_frame(VGMSTREAM* vgmstream) {
/* Get the number of bytes of a single frame (smallest self-contained byte group, 1/N channels) */
int get_vgmstream_frame_size(VGMSTREAM* vgmstream) {
switch (vgmstream->coding_type) {
case coding_SILENCE:
return 0;
case coding_CRI_ADX:
case coding_CRI_ADX_fixed:
case coding_CRI_ADX_exp:
@ -695,7 +701,7 @@ int get_vgmstream_shortframe_size(VGMSTREAM* vgmstream) {
/* Decode samples into the buffer. Assume that we have written samples_written into the
* buffer already, and we have samples_to_do consecutive samples ahead of us (won't call
* more than one frame it configured above to do so).
* more than one frame if configured above to do so).
* Called by layouts since they handle samples written/to_do */
void decode_vgmstream(VGMSTREAM* vgmstream, int samples_written, int samples_to_do, sample_t* buffer) {
int ch;
@ -703,6 +709,10 @@ void decode_vgmstream(VGMSTREAM* vgmstream, int samples_written, int samples_to_
buffer += samples_written * vgmstream->channels; /* passed externally to simplify I guess */
switch (vgmstream->coding_type) {
case coding_SILENCE:
memset(buffer, 0, samples_to_do * vgmstream->channels * sizeof(sample_t));
break;
case coding_CRI_ADX:
case coding_CRI_ADX_exp:
case coding_CRI_ADX_fixed:

View File

@ -670,6 +670,8 @@ typedef struct {
static const coding_info coding_info_list[] = {
{coding_SILENCE, "Silence"},
{coding_PCM16LE, "Little Endian 16-bit PCM"},
{coding_PCM16BE, "Big Endian 16-bit PCM"},
{coding_PCM16_int, "16-bit PCM with 2 byte interleave (block)"},
@ -868,6 +870,7 @@ static const layout_info layout_info_list[] = {
};
static const meta_info meta_info_list[] = {
{meta_SILENCE, "Silence"},
{meta_RSTM, "Nintendo RSTM header"},
{meta_STRM, "Nintendo STRM header"},
{meta_ADX_03, "CRI ADX header type 03"},

View File

@ -5,7 +5,7 @@
/* Decodes samples for flat streams.
* Data forms a single stream, and the decoder may internally skip chunks and move offsets as needed. */
void render_vgmstream_flat(sample_t* buffer, int32_t sample_count, VGMSTREAM* vgmstream) {
void render_vgmstream_flat(sample_t* outbuf, int32_t sample_count, VGMSTREAM* vgmstream) {
int samples_written = 0;
int samples_per_frame, samples_this_block;
@ -25,17 +25,19 @@ void render_vgmstream_flat(sample_t* buffer, int32_t sample_count, VGMSTREAM* vg
if (samples_to_do > sample_count - samples_written)
samples_to_do = sample_count - samples_written;
if (samples_to_do == 0) {
VGM_LOG("layout_flat: wrong samples_to_do 0 found\n"); /* could happen when calling render at EOF? */
//VGM_LOG("layout_flat: tb=%i sib=%i, spf=%i\n", samples_this_block, vgmstream->samples_into_block, samples_per_frame);
memset(buffer + samples_written*vgmstream->channels, 0, (sample_count - samples_written) * vgmstream->channels * sizeof(sample_t));
break;
if (samples_to_do == 0) { /* when decoding more than num_samples */
VGM_LOG("FLAT: samples_to_do 0\n");
goto decode_fail;
}
decode_vgmstream(vgmstream, samples_written, samples_to_do, buffer);
decode_vgmstream(vgmstream, samples_written, samples_to_do, outbuf);
samples_written += samples_to_do;
vgmstream->current_sample += samples_to_do;
vgmstream->samples_into_block += samples_to_do;
}
return;
decode_fail:
memset(outbuf + samples_written * vgmstream->channels, 0, (sample_count - samples_written) * vgmstream->channels * sizeof(sample_t));
}

View File

@ -34,6 +34,10 @@ void render_vgmstream_layered(sample_t* outbuf, int32_t sample_count, VGMSTREAM*
if (samples_to_do > sample_count - samples_written)
samples_to_do = sample_count - samples_written;
if (samples_to_do <= 0) { /* when decoding more than num_samples */
VGM_LOG("LAYERED: samples_to_do 0\n");
goto decode_fail;
}
/* decode all layers */
ch = 0;
@ -65,6 +69,10 @@ void render_vgmstream_layered(sample_t* outbuf, int32_t sample_count, VGMSTREAM*
vgmstream->current_sample += samples_to_do;
vgmstream->samples_into_block += samples_to_do;
}
return;
decode_fail:
memset(outbuf + samples_written * data->output_channels, 0, (sample_count - samples_written) * data->output_channels * sizeof(sample_t));
}

View File

@ -23,7 +23,7 @@ void render_vgmstream_segmented(sample_t* outbuf, int32_t sample_count, VGMSTREA
if (data->current_segment >= data->segment_count) {
VGM_LOG("SEGMENT: wrong current segment\n");
return;
goto decode_fail;
}
samples_this_block = vgmstream_get_samples(data->segments[data->current_segment]);
@ -41,10 +41,9 @@ void render_vgmstream_segmented(sample_t* outbuf, int32_t sample_count, VGMSTREA
if (vgmstream->samples_into_block >= samples_this_block) {
data->current_segment++;
/* could happen on last segment trying to decode more samples */
if (data->current_segment >= data->segment_count) {
VGM_LOG("SEGMENTED: wrong next segment\n");
break;
if (data->current_segment >= data->segment_count) { /* when decoding more than num_samples */
VGM_LOG("SEGMENTED: reached last segment\n");
goto decode_fail;
}
/* in case of looping spanning multiple segments */
@ -62,9 +61,9 @@ void render_vgmstream_segmented(sample_t* outbuf, int32_t sample_count, VGMSTREA
if (samples_to_do > VGMSTREAM_SEGMENT_SAMPLE_BUFFER /*&& use_internal_buffer*/) /* always for fade/etc mixes */
samples_to_do = VGMSTREAM_SEGMENT_SAMPLE_BUFFER;
if (samples_to_do < 0) { /* ? */
if (samples_to_do < 0) { /* 0 is ok? */
VGM_LOG("SEGMENTED: wrong samples_to_do %i found\n", samples_to_do);
break;
goto decode_fail;
}
render_vgmstream(
@ -84,6 +83,10 @@ void render_vgmstream_segmented(sample_t* outbuf, int32_t sample_count, VGMSTREA
vgmstream->current_sample += samples_to_do;
vgmstream->samples_into_block += samples_to_do;
}
return;
decode_fail:
memset(outbuf + samples_written * data->output_channels, 0, (sample_count - samples_written) * data->output_channels * sizeof(sample_t));
}
void loop_layout_segmented(VGMSTREAM* vgmstream, int32_t loop_sample) {

View File

@ -1514,10 +1514,14 @@
RelativePath=".\meta\psf.c"
>
</File>
<File
RelativePath=".\meta\sgxd.c"
>
</File>
<File
RelativePath=".\meta\sgxd.c"
>
</File>
<File
RelativePath=".\meta\silence.c"
>
</File>
<File
RelativePath=".\meta\vawx.c"
>

View File

@ -232,6 +232,7 @@
<ClCompile Include="meta\ps3_past.c" />
<ClCompile Include="meta\psf.c" />
<ClCompile Include="meta\sgxd.c" />
<ClCompile Include="meta\silence.c" />
<ClCompile Include="meta\sk_aud.c" />
<ClCompile Include="meta\vawx.c" />
<ClCompile Include="meta\seg.c" />

View File

@ -1516,6 +1516,9 @@
<ClCompile Include="meta\sgxd.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
<ClCompile Include="meta\silence.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
<ClCompile Include="meta\ngca.c">
<Filter>meta\Source Files</Filter>
</ClCompile>

View File

@ -115,11 +115,7 @@ VGMSTREAM* init_vgmstream_bkhd(STREAMFILE* sf) {
if (is_dummy || is_wmid) {
/* for now leave a dummy song for easier .bnk index-to-subsong mapping */
temp_sf = setup_subfile_streamfile(sf, 0x00, 1000 * 0x02 * 2, "raw");
if (!temp_sf) goto fail;
//todo make some better silent entry
vgmstream = init_vgmstream_raw_pcm(temp_sf);
vgmstream = init_vgmstream_silence(0, 0, 0);
if (!vgmstream) goto fail;
}
else {

View File

@ -66,8 +66,7 @@ VGMSTREAM* init_vgmstream_fsb_encrypted(STREAMFILE* sf) {
vgmstream = init_vgmstream_fsb(temp_sf);
}
if (vgmstream)
dump_streamfile(temp_sf, 0);
//;if (vgmstream) dump_streamfile(temp_sf, 0);
close_streamfile(temp_sf);
if (vgmstream) break;

View File

@ -78,6 +78,9 @@ static const uint8_t key_gh5[] = { 0xFC,0xF9,0xE4,0xB3,0xF5,0x57,0x5C,0xA5,0xAC,
/* Sekiro: Shadows Die Twice (PC) */ //"G0KTrWjS9syqF7vVD6RaVXlFD91gMgkC"
static const uint8_t key_sek[] = { 0x47,0x30,0x4B,0x54,0x72,0x57,0x6A,0x53,0x39,0x73,0x79,0x71,0x46,0x37,0x76,0x56,0x44,0x36,0x52,0x61,0x56,0x58,0x6C,0x46,0x44,0x39,0x31,0x67,0x4D,0x67,0x6B,0x43 };
/* Stacking (X360) */ //"DFm3t4lFTW"
static const uint8_t key_sta[] = { 0x44,0x46,0x6d,0x33,0x74,0x34,0x6c,0x46,0x54,0x57 };
// Unknown:
// - Battle: Los Angeles
// - Guitar Hero: Warriors of Rock, DJ hero FSB
@ -141,6 +144,7 @@ static const fsbkey_info fsbkey_list[] = {
{ 0,1, sizeof(key_mtj),key_mtj },// FSB3
{ 0,1, sizeof(key_gh5),key_gh5 },// FSB4
{ 1,0, sizeof(key_sek),key_sek },// FSB5
{ 0,1, sizeof(key_sta),key_sta },// FSB4
};
static const int fsbkey_list_count = sizeof(fsbkey_list) / sizeof(fsbkey_list[0]);

View File

@ -3,6 +3,9 @@
#include "../vgmstream.h"
VGMSTREAM* init_vgmstream_silence(int channels, int sample_rate, int32_t num_samples);
VGMSTREAM * init_vgmstream_adx(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_afc(STREAMFILE *streamFile);

29
src/meta/silence.c Normal file
View File

@ -0,0 +1,29 @@
#include "meta.h"
/* silent stream - mainly for engines that need them or dummy subsongs */
VGMSTREAM* init_vgmstream_silence(int channels, int sample_rate, int32_t num_samples) {
VGMSTREAM* vgmstream = NULL;
if (channels <= 0)
channels = 2;
if (sample_rate <= 0)
sample_rate = 48000;
if (num_samples <= 0)
num_samples = 1.0 * sample_rate;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channels, 0);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_SILENCE;
vgmstream->sample_rate = sample_rate;
vgmstream->num_samples = num_samples;
vgmstream->coding_type = coding_SILENCE;
vgmstream->layout_type = layout_none;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -66,6 +66,7 @@ typedef struct {
typedef struct {
/* main entry */
char filename[TXTP_LINE_MAX];
int silent;
/* TXTP settings (applied at the end) */
int range_start;
@ -206,9 +207,46 @@ static void clean_txtp(txtp_header* txtp, int fail) {
/* ENTRIES */
/*******************************************************************************/
static int parse_silents(txtp_header* txtp) {
int i;
int channels = 0;
int sample_rate = 0;
int32_t num_samples = 0;
/* silents use same channels as close files */
for (i = 0; i < txtp->vgmstream_count; i++) {
if (!txtp->entry[i].silent) {
channels = txtp->vgmstream[i]->channels;
sample_rate = txtp->vgmstream[i]->sample_rate;
break;
}
}
/* actually open silents */
for (i = 0; i < txtp->vgmstream_count; i++) {
if (!txtp->entry[i].silent)
continue;
txtp->vgmstream[i] = init_vgmstream_silence(channels, sample_rate, num_samples);
if (!txtp->vgmstream[i]) goto fail;
apply_settings(txtp->vgmstream[i], &txtp->entry[i]);
}
return 1;
fail:
return 0;
}
static int is_silent(txtp_entry* entry) {
/* should also contain "." in the filename for commands with seconds ("1.0") to work */
return entry->filename[0] == '?';
}
/* open all entries and apply settings to resulting VGMSTREAMs */
static int parse_entries(txtp_header* txtp, STREAMFILE* sf) {
int i;
int has_silents = 0;
if (txtp->entry_count == 0)
@ -222,7 +260,16 @@ static int parse_entries(txtp_header* txtp, STREAMFILE* sf) {
/* open all entry files first as they'll be modified by modes */
for (i = 0; i < txtp->vgmstream_count; i++) {
STREAMFILE* temp_sf = open_streamfile_by_filename(sf, txtp->entry[i].filename);
STREAMFILE* temp_sf = NULL;
/* silent entry ignore */
if (is_silent(&txtp->entry[i])) {
txtp->entry[i].silent = 1;
has_silents = 1;
continue;
}
temp_sf = open_streamfile_by_filename(sf, txtp->entry[i].filename);
if (!temp_sf) {
VGM_LOG("TXTP: cannot open streamfile for %s\n", txtp->entry[i].filename);
goto fail;
@ -239,6 +286,11 @@ static int parse_entries(txtp_header* txtp, STREAMFILE* sf) {
apply_settings(txtp->vgmstream[i], &txtp->entry[i]);
}
if (has_silents) {
if (!parse_silents(txtp))
goto fail;
}
return 1;
fail:
return 0;

View File

@ -225,8 +225,9 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE* sf) {
goto fail;
}
if (ww.codec == PCM || ww.codec == IMA || ww.codec == DSP || ww.codec == VORBIS || ww.codec == XMA2 || ww.codec == OPUSNX || ww.codec == OPUS) {
ww.truncated = 1; /* only seen those, probably all exist */
if (ww.codec == PCM || ww.codec == IMA || ww.codec == VORBIS || ww.codec == DSP || ww.codec == XMA2 ||
ww.codec == OPUSNX || ww.codec == OPUS || ww.codec == PTADPCM) {
ww.truncated = 1; /* only seen those, probably all exist (XWMA, AAC, HEVAG, ATRAC9?) */
} else {
VGM_LOG("WWISE: wrong size, maybe truncated\n");
goto fail;
@ -679,6 +680,10 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE* sf) {
vgmstream->interleave_block_size = ww.block_align / ww.channels;
//vgmstream->codec_endian = ww.big_endian; //?
if (ww.truncated) {
ww.data_size = ww.file_size - ww.data_offset;
}
vgmstream->num_samples = ptadpcm_bytes_to_samples(ww.data_size, ww.channels, vgmstream->interleave_block_size);
break;

View File

@ -248,6 +248,7 @@ static int render_layout(sample_t* buf, int32_t sample_count, VGMSTREAM* vgmstre
/* current_sample goes between loop points (if looped) or up to max samples,
* must detect beyond that decoders would encounter garbage data */
/* not ">=" to allow layouts to loop in some cases when == happens */
if (vgmstream->current_sample > vgmstream->num_samples) {
int channels = vgmstream->channels;

View File

@ -65,6 +65,8 @@ enum { VGMSTREAM_MAX_NUM_SAMPLES = 1000000000 }; /* no ~5h vgm hopefully */
/* The encoding type specifies the format the sound data itself takes */
typedef enum {
coding_SILENCE, /* generates silence */
/* PCM */
coding_PCM16LE, /* little endian 16-bit PCM */
coding_PCM16BE, /* big endian 16-bit PCM */
@ -289,6 +291,7 @@ typedef enum {
/* The meta type specifies how we know what we know about the file.
* We may know because of a header we read, some of it may have been guessed from filenames, etc. */
typedef enum {
meta_SILENCE,
meta_DSP_STD, /* Nintendo standard GC ADPCM (DSP) header */
meta_DSP_CSTR, /* Star Fox Assault "Cstr" */