mirror of
https://github.com/vgmstream/vgmstream.git
synced 2024-11-15 02:57:38 +01:00
commit
709b897754
1068
cli/txtp_maker.py
1068
cli/txtp_maker.py
File diff suppressed because it is too large
Load Diff
23
doc/TXTP.md
23
doc/TXTP.md
@ -462,13 +462,22 @@ Wrong loop values (for example loop end being much larger than file's samples) w
|
||||
|
||||
**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
|
||||
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).
|
||||
|
@ -598,7 +598,7 @@ static STREAMFILE *open_mapfile_pair(STREAMFILE* sf, int track, int num_tracks)
|
||||
|
||||
/* EA MPF/MUS combo - used in older 7th gen games for storing interactive music */
|
||||
VGMSTREAM * init_vgmstream_ea_mpf_mus_eaac(STREAMFILE* sf) {
|
||||
uint32_t num_tracks, track_start, track_hash, mus_sounds, mus_stream = 0;
|
||||
uint32_t num_tracks, track_start, track_hash = 0, mus_sounds, mus_stream = 0;
|
||||
uint8_t version, sub_version;
|
||||
off_t tracks_table, samples_table, eof_offset, table_offset, entry_offset, snr_offset, sns_offset;
|
||||
int32_t(*read_32bit)(off_t, STREAMFILE*);
|
||||
|
@ -78,9 +78,6 @@ 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
|
||||
@ -144,7 +141,6 @@ 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]);
|
||||
|
424
src/meta/ivaud.c
424
src/meta/ivaud.c
@ -1,192 +1,232 @@
|
||||
#include "meta.h"
|
||||
#include "../layout/layout.h"
|
||||
#include "../util.h"
|
||||
|
||||
typedef struct {
|
||||
int is_music;
|
||||
|
||||
int total_subsongs;
|
||||
|
||||
int channel_count;
|
||||
int sample_rate;
|
||||
int codec;
|
||||
int num_samples;
|
||||
|
||||
size_t block_count;
|
||||
size_t block_size;
|
||||
|
||||
off_t stream_offset;
|
||||
size_t stream_size;
|
||||
|
||||
} ivaud_header;
|
||||
|
||||
static int parse_ivaud_header(STREAMFILE* streamFile, ivaud_header* ivaud);
|
||||
|
||||
|
||||
/* .ivaud - from GTA IV (PC) */
|
||||
VGMSTREAM * init_vgmstream_ivaud(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
ivaud_header ivaud = {0};
|
||||
int loop_flag;
|
||||
|
||||
/* checks */
|
||||
/* (hashed filenames are likely extensionless and .ivaud is added by tools) */
|
||||
if (!check_extensions(streamFile, "ivaud,"))
|
||||
goto fail;
|
||||
|
||||
/* check header */
|
||||
if (!parse_ivaud_header(streamFile, &ivaud))
|
||||
goto fail;
|
||||
|
||||
|
||||
loop_flag = 0;
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(ivaud.channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->sample_rate = ivaud.sample_rate;
|
||||
vgmstream->num_samples = ivaud.num_samples;
|
||||
vgmstream->num_streams = ivaud.total_subsongs;
|
||||
vgmstream->stream_size = ivaud.stream_size;
|
||||
vgmstream->meta_type = meta_IVAUD;
|
||||
|
||||
switch(ivaud.codec) {
|
||||
case 0x0001: /* common in sfx, uncommon in music (ex. EP2_SFX/MENU_MUSIC) */
|
||||
vgmstream->coding_type = coding_PCM16LE;
|
||||
vgmstream->layout_type = ivaud.is_music ? layout_blocked_ivaud : layout_none;
|
||||
vgmstream->full_block_size = ivaud.block_size;
|
||||
break;
|
||||
|
||||
case 0x0400:
|
||||
vgmstream->coding_type = coding_IMA_int;
|
||||
vgmstream->layout_type = ivaud.is_music ? layout_blocked_ivaud : layout_none;
|
||||
vgmstream->full_block_size = ivaud.block_size;
|
||||
break;
|
||||
|
||||
default:
|
||||
VGM_LOG("IVAUD: unknown codec 0x%x\n", ivaud.codec);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream,streamFile,ivaud.stream_offset))
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Parse Rockstar's .ivaud header (much info from SparkIV). */
|
||||
static int parse_ivaud_header(STREAMFILE* streamFile, ivaud_header* ivaud) {
|
||||
int target_subsong = streamFile->stream_index;
|
||||
|
||||
|
||||
/* use bank's stream count to detect */
|
||||
ivaud->is_music = (read_32bitLE(0x10,streamFile) == 0);
|
||||
|
||||
if (ivaud->is_music) {
|
||||
off_t block_table_offset, channel_table_offset, channel_info_offset;
|
||||
|
||||
/* music header */
|
||||
block_table_offset = read_32bitLE(0x00,streamFile); /* 64b */
|
||||
ivaud->block_count = read_32bitLE(0x08,streamFile);
|
||||
ivaud->block_size = read_32bitLE(0x0c,streamFile); /* 64b, uses padded blocks */
|
||||
channel_table_offset = read_32bitLE(0x14,streamFile); /* 64b */
|
||||
/* 0x1c(8): block_table_offset again? */
|
||||
ivaud->channel_count = read_32bitLE(0x24,streamFile);
|
||||
/* 0x28(4): unknown entries? */
|
||||
ivaud->stream_offset = read_32bitLE(0x2c,streamFile);
|
||||
channel_info_offset = channel_table_offset + ivaud->channel_count*0x10;
|
||||
|
||||
if ((ivaud->block_count * ivaud->block_size) + ivaud->stream_offset != get_streamfile_size(streamFile)) {
|
||||
VGM_LOG("IVAUD: bad file size\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* channel table (one entry per channel, points to channel info) */
|
||||
/* 0x00(8): offset within channel_info_offset */
|
||||
/* 0x08(4): hash */
|
||||
/* 0x0c(4): size */
|
||||
|
||||
/* channel info (one entry per channel) */
|
||||
/* 0x00(8): offset within data (should be 0) */
|
||||
/* 0x08(4): hash */
|
||||
/* 0x0c(4): half num_samples? */
|
||||
ivaud->num_samples = read_32bitLE(channel_info_offset+0x10,streamFile);
|
||||
/* 0x14(4): unknown (-1) */
|
||||
/* 0x18(2): sample rate */
|
||||
/* 0x1a(2): unknown */
|
||||
ivaud->codec = read_32bitLE(channel_info_offset+0x1c,streamFile);
|
||||
/* (when codec is IMA) */
|
||||
/* 0x20(8): adpcm states offset, 0x38: num states? (reference for seeks?) */
|
||||
/* rest: unknown data */
|
||||
|
||||
/* block table (one entry per block) */
|
||||
/* 0x00: data size processed up to this block (doesn't count block padding) */
|
||||
ivaud->sample_rate = read_32bitLE(block_table_offset + 0x04,streamFile);
|
||||
/* sample_rate should agree with each channel in the channel table */
|
||||
|
||||
|
||||
ivaud->total_subsongs = 1;
|
||||
ivaud->stream_size = get_streamfile_size(streamFile);
|
||||
}
|
||||
else {
|
||||
off_t stream_table_offset, stream_info_offset, stream_entry_offset;
|
||||
|
||||
/* bank header */
|
||||
stream_table_offset = read_32bitLE(0x00,streamFile); /* 64b */
|
||||
/* 0x08(8): header size? start offset? */
|
||||
ivaud->total_subsongs = read_32bitLE(0x10,streamFile);
|
||||
/* 0x14(4): unknown */
|
||||
ivaud->stream_offset = read_32bitLE(0x18,streamFile); /* base start_offset */
|
||||
|
||||
if (target_subsong == 0) target_subsong = 1;
|
||||
if (target_subsong < 0 || target_subsong > ivaud->total_subsongs || ivaud->total_subsongs < 1) goto fail;
|
||||
|
||||
if (stream_table_offset != 0x1c)
|
||||
goto fail;
|
||||
stream_info_offset = stream_table_offset + 0x10*ivaud->total_subsongs;
|
||||
|
||||
/* stream table (one entry per stream, points to stream info) */
|
||||
stream_entry_offset = read_32bitLE(stream_table_offset + 0x10*(target_subsong-1) + 0x00,streamFile); /* within stream info */
|
||||
/* 0x00(8): offset within stream_info_offset */
|
||||
/* 0x08(4): hash */
|
||||
/* 0x0c(4): size */
|
||||
|
||||
/* stream info (one entry per stream) */
|
||||
ivaud->stream_offset += read_32bitLE(stream_info_offset+stream_entry_offset+0x00,streamFile); /* 64b, within data */
|
||||
/* 0x08(4): hash */
|
||||
/* 0x0c(4): half num_samples? */
|
||||
ivaud->num_samples = read_32bitLE(stream_info_offset+stream_entry_offset+0x10,streamFile);
|
||||
/* 0x14(4): unknown (-1) */
|
||||
ivaud->sample_rate = (uint16_t)read_16bitLE(stream_info_offset+stream_entry_offset+0x18,streamFile);
|
||||
/* 0x1a(2): unknown */
|
||||
ivaud->codec = read_32bitLE(stream_info_offset+stream_entry_offset+0x1c,streamFile);
|
||||
/* (when codec is IMA) */
|
||||
/* 0x20(8): adpcm states offset, 0x38: num states? (reference for seeks?) */
|
||||
/* rest: unknown data */
|
||||
|
||||
ivaud->channel_count = 1;
|
||||
|
||||
/* ghetto size calculator (could substract offsets but streams are not ordered) */
|
||||
switch(ivaud->codec) {
|
||||
case 0x0001:
|
||||
ivaud->stream_size = ivaud->num_samples * 2; /* double 16b PCM */
|
||||
break;
|
||||
case 0x0400:
|
||||
ivaud->stream_size = ivaud->num_samples / 2; /* half nibbles */
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return 1;
|
||||
fail:
|
||||
return 0;
|
||||
}
|
||||
#include "meta.h"
|
||||
#include "../layout/layout.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
typedef struct {
|
||||
int is_music;
|
||||
|
||||
int total_subsongs;
|
||||
|
||||
int channel_count;
|
||||
int sample_rate;
|
||||
int codec;
|
||||
int num_samples;
|
||||
|
||||
size_t block_count;
|
||||
size_t block_size;
|
||||
|
||||
off_t stream_offset;
|
||||
size_t stream_size;
|
||||
|
||||
int big_endian;
|
||||
} ivaud_header;
|
||||
|
||||
static int parse_ivaud_header(STREAMFILE* sf, ivaud_header* ivaud);
|
||||
|
||||
|
||||
/* .ivaud - from GTA IV (PC/PS3/X360) */
|
||||
VGMSTREAM* init_vgmstream_ivaud(STREAMFILE* sf) {
|
||||
VGMSTREAM* vgmstream = NULL;
|
||||
ivaud_header ivaud = {0};
|
||||
int loop_flag;
|
||||
|
||||
/* checks */
|
||||
/* (hashed filenames are likely extensionless and .ivaud is added by tools) */
|
||||
if (!check_extensions(sf, "ivaud,"))
|
||||
goto fail;
|
||||
|
||||
/* check header */
|
||||
if (!parse_ivaud_header(sf, &ivaud))
|
||||
goto fail;
|
||||
|
||||
|
||||
loop_flag = 0;
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(ivaud.channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->sample_rate = ivaud.sample_rate;
|
||||
vgmstream->num_samples = ivaud.num_samples;
|
||||
vgmstream->num_streams = ivaud.total_subsongs;
|
||||
vgmstream->stream_size = ivaud.stream_size;
|
||||
vgmstream->meta_type = meta_IVAUD;
|
||||
|
||||
switch(ivaud.codec) {
|
||||
case 0x0001: /* common in sfx, uncommon in music (ex. EP2_SFX/MENU_MUSIC) */
|
||||
vgmstream->coding_type = coding_PCM16LE;
|
||||
vgmstream->layout_type = ivaud.is_music ? layout_blocked_ivaud : layout_none;
|
||||
vgmstream->full_block_size = ivaud.block_size;
|
||||
break;
|
||||
|
||||
#ifdef VGM_USE_FFMPEG
|
||||
case 0x0000: { /* XMA2 (X360) */
|
||||
uint8_t buf[0x100];
|
||||
size_t bytes;
|
||||
|
||||
if (ivaud.is_music) {
|
||||
goto fail;
|
||||
}
|
||||
else {
|
||||
/* regular XMA for sfx */
|
||||
bytes = ffmpeg_make_riff_xma1(buf, 0x100, ivaud.num_samples, ivaud.stream_size, ivaud.channel_count, ivaud.sample_rate, 0);
|
||||
vgmstream->codec_data = init_ffmpeg_header_offset(sf, buf,bytes, ivaud.stream_offset, ivaud.stream_size);
|
||||
if (!vgmstream->codec_data) goto fail;
|
||||
vgmstream->coding_type = coding_FFmpeg;
|
||||
vgmstream->layout_type = layout_none;
|
||||
|
||||
xma_fix_raw_samples(vgmstream, sf, ivaud.stream_offset, ivaud.stream_size, 0, 0,0); /* samples are ok? */
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef VGM_USE_MPEG
|
||||
case 0x0100: { /* MPEG (PS3) */
|
||||
mpeg_custom_config cfg = {0};
|
||||
|
||||
if (ivaud.is_music) {
|
||||
goto fail;
|
||||
}
|
||||
else {
|
||||
cfg.chunk_size = ivaud.block_size;
|
||||
cfg.big_endian = ivaud.big_endian;
|
||||
|
||||
vgmstream->codec_data = init_mpeg_custom(sf, ivaud.stream_offset, &vgmstream->coding_type, vgmstream->channels, MPEG_STANDARD, &cfg);
|
||||
if (!vgmstream->codec_data) goto fail;
|
||||
vgmstream->layout_type = layout_none;
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
case 0x0400: /* PC */
|
||||
vgmstream->coding_type = coding_IMA_int;
|
||||
vgmstream->layout_type = ivaud.is_music ? layout_blocked_ivaud : layout_none;
|
||||
vgmstream->full_block_size = ivaud.block_size;
|
||||
break;
|
||||
|
||||
default:
|
||||
VGM_LOG("IVAUD: unknown codec 0x%x\n", ivaud.codec);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream,sf,ivaud.stream_offset))
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Parse Rockstar's .ivaud header (much info from SparkIV). */
|
||||
static int parse_ivaud_header(STREAMFILE* sf, ivaud_header* ivaud) {
|
||||
int target_subsong = sf->stream_index;
|
||||
uint64_t (*read_u64)(off_t,STREAMFILE*);
|
||||
uint32_t (*read_u32)(off_t,STREAMFILE*);
|
||||
uint16_t (*read_u16)(off_t,STREAMFILE*);
|
||||
|
||||
|
||||
ivaud->big_endian = read_u32be(0x00, sf) == 0; /* table offset at 0x04 > BE (64b) */
|
||||
read_u64 = ivaud->big_endian ? read_u64be : read_u64le;
|
||||
read_u32 = ivaud->big_endian ? read_u32be : read_u32le;
|
||||
read_u16 = ivaud->big_endian ? read_u16be : read_u16le;
|
||||
|
||||
/* use bank's stream count to detect */
|
||||
ivaud->is_music = (read_u32(0x10,sf) == 0);
|
||||
|
||||
if (ivaud->is_music) {
|
||||
off_t block_table_offset, channel_table_offset, channel_info_offset;
|
||||
|
||||
/* music header */
|
||||
block_table_offset = read_u64(0x00,sf);
|
||||
ivaud->block_count = read_u32(0x08,sf);
|
||||
ivaud->block_size = read_u32(0x0c,sf); /* uses padded blocks */
|
||||
/* 0x10(4): stream count */
|
||||
channel_table_offset = read_u64(0x14,sf);
|
||||
/* 0x1c(8): block_table_offset again? */
|
||||
ivaud->channel_count = read_u32(0x24,sf);
|
||||
/* 0x28(4): unknown entries? */
|
||||
ivaud->stream_offset = read_u32(0x2c,sf);
|
||||
channel_info_offset = channel_table_offset + ivaud->channel_count * 0x10;
|
||||
|
||||
if ((ivaud->block_count * ivaud->block_size) + ivaud->stream_offset != get_streamfile_size(sf)) {
|
||||
VGM_LOG("IVAUD: bad file size\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* channel table (one entry per channel, points to channel info) */
|
||||
/* 0x00(8): offset within channel_info_offset */
|
||||
/* 0x08(4): hash */
|
||||
/* 0x0c(4): size */
|
||||
|
||||
/* channel info (one entry per channel) */
|
||||
/* 0x00(8): offset within data (should be 0) */
|
||||
/* 0x08(4): hash */
|
||||
/* 0x0c(4): half num_samples? */
|
||||
ivaud->num_samples = read_u32(channel_info_offset+0x10,sf);
|
||||
/* 0x14(4): unknown (-1) */
|
||||
/* 0x18(2): sample rate */
|
||||
/* 0x1a(2): unknown */
|
||||
ivaud->codec = read_u32(channel_info_offset+0x1c,sf);
|
||||
/* (when codec is IMA) */
|
||||
/* 0x20(8): adpcm states offset, 0x38: num states? (reference for seeks?) */
|
||||
/* rest: unknown data */
|
||||
|
||||
/* block table (one entry per block) */
|
||||
/* 0x00: data size processed up to this block (doesn't count block padding) */
|
||||
ivaud->sample_rate = read_u32(block_table_offset + 0x04,sf);
|
||||
/* sample_rate should agree with each channel in the channel table */
|
||||
|
||||
|
||||
ivaud->total_subsongs = 1;
|
||||
ivaud->stream_size = get_streamfile_size(sf);
|
||||
}
|
||||
else {
|
||||
off_t stream_table_offset, stream_info_offset, stream_entry_offset, offset;
|
||||
|
||||
/* bank header */
|
||||
stream_table_offset = read_u64(0x00,sf);
|
||||
/* 0x08(8): header size? start offset? */
|
||||
ivaud->total_subsongs = read_u32(0x10,sf);
|
||||
/* 0x14(4): unknown */
|
||||
ivaud->stream_offset = read_u32(0x18,sf); /* base start_offset */
|
||||
|
||||
if (target_subsong == 0) target_subsong = 1;
|
||||
if (target_subsong < 0 || target_subsong > ivaud->total_subsongs || ivaud->total_subsongs < 1) goto fail;
|
||||
|
||||
if (stream_table_offset != 0x1c)
|
||||
goto fail;
|
||||
stream_info_offset = stream_table_offset + 0x10*ivaud->total_subsongs;
|
||||
|
||||
/* stream table (one entry per stream, points to stream info) */
|
||||
stream_entry_offset = read_u64(stream_table_offset + 0x10*(target_subsong-1) + 0x00,sf); /* within stream info */
|
||||
/* 0x00(8): offset within stream_info_offset */
|
||||
/* 0x08(4): hash */
|
||||
/* 0x0c(4): some offset/size */
|
||||
|
||||
/* stream info (one entry per stream) */
|
||||
offset = stream_info_offset + stream_entry_offset;
|
||||
ivaud->stream_offset += read_u64(offset+0x00,sf); /* within data */
|
||||
/* 0x08(4): hash */
|
||||
ivaud->stream_size = read_u32(offset+0x0c,sf);
|
||||
ivaud->num_samples = read_u32(offset+0x10,sf);
|
||||
/* 0x14(4): unknown (-1) */
|
||||
ivaud->sample_rate = read_u16(offset+0x18,sf);
|
||||
/* 0x1a(2): unknown */
|
||||
ivaud->codec = read_u32(offset+0x1c,sf);
|
||||
/* (when codec is IMA) */
|
||||
/* 0x20(8): adpcm states offset, 0x38: num states? (reference for seeks?) */
|
||||
/* rest: unknown data */
|
||||
|
||||
ivaud->channel_count = 1;
|
||||
}
|
||||
|
||||
|
||||
return 1;
|
||||
fail:
|
||||
return 0;
|
||||
}
|
||||
|
@ -57,6 +57,7 @@ void vgmstream_set_play_forever(VGMSTREAM* vgmstream, int enabled) {
|
||||
* (play config is left untouched, should mix ok as this flag is only used during
|
||||
* render, while config is always prepared as if play forever wasn't enabled) */
|
||||
vgmstream->config.play_forever = enabled;
|
||||
setup_vgmstream(vgmstream); /* update config */
|
||||
}
|
||||
|
||||
int32_t vgmstream_get_samples(VGMSTREAM* vgmstream) {
|
||||
|
Loading…
Reference in New Issue
Block a user