diff --git a/src/coding/coding.h b/src/coding/coding.h index d3dc76bd..edbf6256 100644 --- a/src/coding/coding.h +++ b/src/coding/coding.h @@ -298,7 +298,7 @@ void free_imuse(imuse_codec_data* data); typedef struct ongakukan_adp_data ongakukan_adp_data; ongakukan_adp_data* init_ongakukan_adp(STREAMFILE* sf, int32_t data_offset, int32_t data_size, - char sound_is_adpcm, char sample_has_base_setup_from_the_start); + bool sound_is_adpcm); void decode_ongakukan_adp(VGMSTREAM* vgmstream, sample_t* outbuf, int32_t samples_to_do); void reset_ongakukan_adp(ongakukan_adp_data* data); void seek_ongakukan_adp(ongakukan_adp_data* data, int32_t current_sample); diff --git a/src/coding/libs/ongakukan_adp_lib.c b/src/coding/libs/ongakukan_adp_lib.c index 7222061f..87fd07ab 100644 --- a/src/coding/libs/ongakukan_adp_lib.c +++ b/src/coding/libs/ongakukan_adp_lib.c @@ -14,6 +14,7 @@ * -- However, much of that support is reliant on a flag that's set to either one of the two codecs depending on the opened file extension. * Basically, how it works is: if sound data is "PCM16" (available to "wav" and "ads" files), set flag to 0. * If sound data is "ADPCM" (available to "adp" files), set it to 1. + * Code handles this flag as a boolean var; 0 is "false" and 1 is "true". * -- As vgmstream has built-in support for the former codec (and the many metas that use it) however, despite being fairly easy to add here, * re-implementing one from scratch would be a wasted effort regardless; it is consequentially not included. */ @@ -36,15 +37,14 @@ struct ongakukan_adp_t long int samples_filled; /* how many samples were filled to vgmstream buffer. */ long int samples_consumed; /* how many samples vgmstream buffer had to consume. */ - char sound_is_adpcm; /* 0 = no (see "additional notes" above) , 1 = yes */ - char sample_startpoint_present; /* -1 = failed to make startpoint, 1 = startpoint present */ + bool sound_is_adpcm; /* false = no (see "additional notes" above) , true = yes */ + bool sample_startpoint_present; /* false = failed to make startpoint, true = startpoint present */ char sample_mode; /* 0 = creates decoding setup, 1 = continue decoding data with setup in place */ - char sample_has_base_setup_from_the_start; /* 0 = no, 1 = yes */ - char sample_pair_is_decoded; /* 0 = no, 1 = yes */ + bool sample_pair_is_decoded; /* false = no, true = yes */ unsigned char base_pair; /* represents a read byte from ADPCM data, consisting of two 4-bit nibbles each.*/ long int base_scale; /* how loud should this sample be. */ - void* sample_hist; /* two pairs of signed 16-bit data, representing samples. yes, it is void. */ + short int sample_hist[2]; /* two pairs of signed 16-bit data, representing samples. yes, it is void. */ }; /* filter table consisting of 16 numbers each. */ @@ -53,18 +53,18 @@ const short int ongakukan_adpcm_filter[16] = { 233, 549, 453, 375, 310, 233, 233 /* streamfile read function declararion, more may be added in the future. */ -uint8_t read_u8_wrapper(ongakukan_adp_t* handle); +static uint8_t read_u8_wrapper(ongakukan_adp_t* handle); /* function declarations for the inner workings of codec data. */ -char set_up_sample_startpoint(ongakukan_adp_t* handle); -void decode_ongakukan_adpcm_sample(ongakukan_adp_t* handle, short int* sample_hist); +static bool set_up_sample_startpoint(ongakukan_adp_t* handle); +static void decode_ongakukan_adpcm_samples(ongakukan_adp_t* handle); /* codec management functions, meant to oversee and supervise ADP data from the top-down. * in layman terms, they control how ADP data should be handled and when. */ -ongakukan_adp_t* boot_ongakukan_adpcm(STREAMFILE* sf, long int data_offset, long int data_size, - char sound_is_adpcm, char sample_has_base_setup_from_the_start) +ongakukan_adp_t* init_ongakukan_adpcm(STREAMFILE* sf, long int data_offset, long int data_size, + bool sound_is_adpcm) { ongakukan_adp_t* handle = NULL; @@ -77,50 +77,45 @@ ongakukan_adp_t* boot_ongakukan_adpcm(STREAMFILE* sf, long int data_offset, long handle->data_offset = data_offset; handle->start_offset = data_offset; handle->data_size = data_size; - handle->samples_filled = 0; - handle->samples_consumed = 0; handle->sample_mode = 0; handle->sound_is_adpcm = sound_is_adpcm; - handle->sample_has_base_setup_from_the_start = sample_has_base_setup_from_the_start; handle->sample_startpoint_present = set_up_sample_startpoint(handle); /* if we failed in planting up the seeds for an ADPCM decoder, we simply throw in the towel and take a walk in the park. */ - if (handle->sample_startpoint_present == -1) { goto fail; } + if (handle->sample_startpoint_present == false) { goto fail; } return handle; fail: - free_all_ongakukan_adpcm(handle); + ongakukan_adpcm_free(handle); return NULL; } -void free_all_ongakukan_adpcm(ongakukan_adp_t* handle) +void ongakukan_adpcm_free(ongakukan_adp_t* handle) { if (!handle) return; - close_streamfile(handle->sf); - free(handle->sample_hist); free(handle); } -void reset_all_ongakukan_adpcm(ongakukan_adp_t* handle) +void ongakukan_adpcm_reset(ongakukan_adp_t* handle) { if (!handle) return; /* wipe out certain values from handle so we can start over. */ handle->data_offset = handle->start_offset; - handle->sample_pair_is_decoded = 0; + handle->sample_pair_is_decoded = false; handle->sample_mode = 0; - handle->sample_has_base_setup_from_the_start = 1; handle->alt_sample_work1 = 0; handle->alt_sample_work2 = handle->sample_work; } -void seek_ongakukan_adpcm_pos(ongakukan_adp_t* handle, long int target_sample) +void ongakukan_adpcm_seek(ongakukan_adp_t* handle, long int target_sample) { if (!handle) return; char ts_modulus = 0; /* ts_modulus is here to ensure target_sample gets rounded to a multiple of 2. */ long int ts_data_offset = 0; /* ts_data_offset is basically data_offset but with (left(if PCM)/right(if ADPCM))-shifted target_sample calc by 1. */ - if (handle->sound_is_adpcm == 0) { ts_data_offset = target_sample << 1; } - else { ts_data_offset = target_sample >> 1; ts_modulus = target_sample % 2; target_sample = target_sample - ts_modulus; } + ts_data_offset = target_sample >> 1; + ts_modulus = target_sample % 2; + target_sample = target_sample - ts_modulus; /* if ADPCM, right-shift the former first then have ts_modulus calc remainder of target_sample by 2 so we can subtract it with ts_modulus. * this is needed for the two counters that the decoder has that can both add and subtract with 2, respectively * (and in order, too; meaning one counter does "plus 2" while the other does "minus 2", @@ -130,9 +125,8 @@ void seek_ongakukan_adpcm_pos(ongakukan_adp_t* handle, long int target_sample) * so we'll have data_offset reposition itself to where sound data for that sample ought to be * and (as of now) reset basically all decode state up to this point so we can continue to decode all sample pairs without issue. */ handle->data_offset = handle->start_offset + ts_data_offset; - handle->sample_pair_is_decoded = 0; + handle->sample_pair_is_decoded = false; handle->sample_mode = 0; - handle->sample_has_base_setup_from_the_start = 1; handle->alt_sample_work1 = target_sample; handle->alt_sample_work2 = handle->sample_work - target_sample; @@ -140,139 +134,88 @@ void seek_ongakukan_adpcm_pos(ongakukan_adp_t* handle, long int target_sample) * seek_ongakukan_adpcm_pos in its current state is a bit more involved than the above, but works. */ } -long int grab_num_samples_from_ongakukan_adp(ongakukan_adp_t* handle) +long int get_num_samples_from_ongakukan_adpcm(ongakukan_adp_t* handle) { if (!handle) return 0; return handle->sample_work; } -long int grab_samples_filled_from_ongakukan_adp(ongakukan_adp_t* handle) +void* get_sample_hist_from_ongakukan_adpcm(ongakukan_adp_t* handle) { if (!handle) return 0; - return handle->samples_filled; -} - -void send_samples_filled_to_ongakukan_adp(long int samples_filled, ongakukan_adp_t* handle) -{ - if (!handle) return; - handle->samples_filled = samples_filled; -} - -long int grab_samples_consumed_from_ongakukan_adp(ongakukan_adp_t* handle) -{ - if (!handle) return 0; - return handle->samples_consumed; -} - -void send_samples_consumed_to_ongakukan_adp(long int samples_consumed, ongakukan_adp_t* handle) -{ - if (!handle) return; - handle->samples_consumed = samples_consumed; -} - -void* grab_sample_hist_from_ongakukan_adp(ongakukan_adp_t* handle) -{ - if (!handle) return 0; - return handle->sample_hist; + return &handle->sample_hist; } /* function definitions for the inner workings of codec data. */ -char set_up_sample_startpoint(ongakukan_adp_t* handle) +static bool set_up_sample_startpoint(ongakukan_adp_t* handle) { - /* malloc "sample hist" to 2 short ints */ - handle->sample_hist = malloc(2 * sizeof(short int)); + /* make decoder fail hard if streamfile object isn't opened or downright useless. */ + if (!handle->sf) return false; - /* and make decoder fail hard if they don't have "sample hist" and opened streamfile object. */ - if (!handle->sample_hist) return -1; - if (!handle->sf) return -1; - - if (handle->sound_is_adpcm == 0) { - /* num_samples but for PCM16 sound data. */ - handle->sample_work = handle->data_size >> 1; - } - else { - /* num_samples but for Ongakukan ADPCM sound data. */ - handle->sample_work = handle->data_size << 1; - } + if (handle->sound_is_adpcm == 0) { return false; } + else { /* num_samples but for Ongakukan ADPCM sound data. */ handle->sample_work = handle->data_size << 1; } /* set "beginning" and "end" sample vars and send a "message" that we went through no sample yet.*/ handle->alt_sample_work1 = 0; handle->alt_sample_work2 = handle->sample_work; - handle->sample_pair_is_decoded = 0; + handle->sample_pair_is_decoded = false; - return 1; + return true; } -void decode_ongakukan_adp_data(ongakukan_adp_t* handle) +void decode_ongakukan_adpcm_data(ongakukan_adp_t* handle) { /* set samples_filled to 0 and have our decoder go through every sample that exists in the sound data.*/ - handle->samples_filled = 0; - if (handle->sample_pair_is_decoded == 0) - { - handle->samples_filled = 0; - handle->samples_consumed = 0; - } - decode_ongakukan_adpcm_sample(handle, handle->sample_hist); + decode_ongakukan_adpcm_samples(handle); /* if setup is established for further decoding, switch gears and have the decoder use that setup for as long as possible. */ - if (handle->sample_has_base_setup_from_the_start == 1) - { - handle->sample_has_base_setup_from_the_start = 0; - handle->sample_mode = 1; - } /* if sample pair is decoded, advance to next byte, tell our handle that we went through 2 samples and make decoder go through next available data again. */ - if (handle->sample_pair_is_decoded == 1) + if (handle->sample_pair_is_decoded == true) { handle->data_offset++; handle->alt_sample_work1 += 2; handle->alt_sample_work2 -= 2; - handle->samples_filled = 2; - handle->sample_pair_is_decoded = 0; + handle->sample_pair_is_decoded = false; } } -void decode_ongakukan_adpcm_sample(ongakukan_adp_t* handle, short int* sample_hist) +static void decode_ongakukan_adpcm_samples(ongakukan_adp_t* handle) { unsigned char nibble1 = 0, nibble2 = 0; /* two chars representing a 4-bit nibble. */ long int nibble1_1 = 0, nibble2_1 = 0; /* two long ints representing pure sample data. */ - if (handle->sample_pair_is_decoded == 0) + if (handle->sample_pair_is_decoded == false) { /* sample_mode being 0 means we can just do a setup for future sample decoding so we have nothing to worry about in the future. */ if (handle->sample_mode == 0) { /* set "base scale", two "sample hist"s, and "base pair", respectively. */ - handle->base_scale = 0x10; /* yes, this is how "base scale" is set; to 16. */ - *(sample_hist+0) = 0; /* dereference first sample hist pos to something we can use. */ - *(sample_hist+1) = 0; /* dereference second sample hist pos to something we can use. */ - handle->base_pair = 0; /* set representing byte to 0 while we're at it. */ + handle->base_scale = 0x10; + handle->sample_hist[0] = 0; + handle->sample_hist[1] = 0; + handle->base_pair = 0; + handle->sample_mode = 1; /* indicates we have the setup we need to decode samples. */ } - /* "pinch off" of a single-byte read. remember that we need two nibbles. */ handle->base_pair = (uint8_t)read_u8_wrapper(handle); - /* now pick two nibbles, subtract them, reverse the order of said nibbles so we can calc them one-by-one, - * and finally tell handle that we're done with two samples and would like to take a break, please. */ nibble1 = handle->base_pair & 0xf; nibble1_1 = nibble1 + -8; nibble2 = (handle->base_pair >> 4) & 0xf; nibble2_1 = nibble2 + -8; nibble2_1 = nibble2_1 * handle->base_scale; - *(sample_hist+0) = *(sample_hist+1) + nibble2_1; + handle->sample_hist[0] = handle->sample_hist[1] + nibble2_1; handle->base_scale = (handle->base_scale * (ongakukan_adpcm_filter[nibble2])) >> 8; nibble1_1 = nibble1_1 * handle->base_scale; - *(sample_hist+1) = *(sample_hist+0) + nibble1_1; + handle->sample_hist[1] = handle->sample_hist[0] + nibble1_1; handle->base_scale = (handle->base_scale * (ongakukan_adpcm_filter[nibble1])) >> 8; - handle->sample_pair_is_decoded = 1; + handle->sample_pair_is_decoded = true; } } /* streamfile read function definitions at the very bottom. */ -uint8_t read_u8_wrapper(ongakukan_adp_t* handle) +static uint8_t read_u8_wrapper(ongakukan_adp_t* handle) { - /* if data_offset minus start_offset goes beyond data_size, return 0. */ if ((handle->data_offset - handle->start_offset) > handle->data_size) return 0; - /* if data_offset minus start_offset goes below 0, same. */ if ((handle->data_offset - handle->start_offset) < 0) return 0; - /* otherwise, read the byte from data_offset and see history get made. */ return read_u8((off_t)(handle->data_offset), handle->sf); } diff --git a/src/coding/libs/ongakukan_adp_lib.h b/src/coding/libs/ongakukan_adp_lib.h index ce3b4d9f..f127c85c 100644 --- a/src/coding/libs/ongakukan_adp_lib.h +++ b/src/coding/libs/ongakukan_adp_lib.h @@ -1,7 +1,7 @@ -#ifndef _ONGAKUKAN_ADP_LIB_ -#define _ONGAKUKAN_ADP_LIB_ +#ifndef _ONGAKUKAN_ADP_LIB_H_ +#define _ONGAKUKAN_ADP_LIB_H_ -/* Ongakukan ADP codec, found in PS2 and PSP games. */ +/* Ongakukan ADPCM codec, found in PS2 and PSP games. */ #include "../../util/reader_sf.h" @@ -9,23 +9,19 @@ typedef struct ongakukan_adp_t ongakukan_adp_t; /* function declaration for we need to set up the codec data. */ -ongakukan_adp_t* boot_ongakukan_adpcm(STREAMFILE* sf, long int data_offset, long int data_size, - char sample_needs_setup, char sample_has_base_setup_from_the_start); +ongakukan_adp_t* init_ongakukan_adpcm(STREAMFILE* sf, long int data_offset, long int data_size, + bool sound_is_adpcm); /* function declaration for freeing all memory related to ongakukan_adp_t struct var. */ -void free_all_ongakukan_adpcm(ongakukan_adp_t* handle); -void reset_all_ongakukan_adpcm(ongakukan_adp_t* handle); -void seek_ongakukan_adpcm_pos(ongakukan_adp_t* handle, long int target_sample); +void ongakukan_adpcm_free(ongakukan_adp_t* handle); +void ongakukan_adpcm_reset(ongakukan_adp_t* handle); +void ongakukan_adpcm_seek(ongakukan_adp_t* handle, long int target_sample); /* function declaration for when we need to get (and send) certain values from ongakukan_adp_t handle */ -long int grab_num_samples_from_ongakukan_adp(ongakukan_adp_t* handle); -long int grab_samples_filled_from_ongakukan_adp(ongakukan_adp_t* handle); -void send_samples_filled_to_ongakukan_adp(long int samples_filled, ongakukan_adp_t* handle); -long int grab_samples_consumed_from_ongakukan_adp(ongakukan_adp_t* handle); -void send_samples_consumed_to_ongakukan_adp(long int samples_consumed, ongakukan_adp_t* handle); -void* grab_sample_hist_from_ongakukan_adp(ongakukan_adp_t* handle); +long int get_num_samples_from_ongakukan_adpcm(ongakukan_adp_t* handle); +void* get_sample_hist_from_ongakukan_adpcm(ongakukan_adp_t* handle); /* function declaration for actually decoding samples, can't be that hard, right? */ -void decode_ongakukan_adp_data(ongakukan_adp_t* handle); +void decode_ongakukan_adpcm_data(ongakukan_adp_t* handle); -#endif /* _ONGAKUKAN_ADP_LIB_ */ +#endif // _ONGAKUKAN_ADP_LIB_H_ diff --git a/src/coding/ongakukan_adp_decoder.c b/src/coding/ongakukan_adp_decoder.c index 97bcc3aa..b22887ea 100644 --- a/src/coding/ongakukan_adp_decoder.c +++ b/src/coding/ongakukan_adp_decoder.c @@ -4,94 +4,87 @@ struct ongakukan_adp_data { - void* handle; - int16_t* samples; - int32_t samples_done; - int32_t samples_filled; - int32_t samples_consumed; - int32_t getting_samples; - STREAMFILE* sf; + void* handle; + int16_t* samples; + int32_t samples_done; + bool samples_filled; /* false - no, true - yes */ + int32_t getting_samples; /* initialized to 2 on decode_ongakukan_adp. i mean, we literally get two decoded samples here. */ + STREAMFILE* sf; }; ongakukan_adp_data* init_ongakukan_adp(STREAMFILE* sf, int32_t data_offset, int32_t data_size, - char sample_needs_setup, char sample_has_base_setup_from_the_start) + bool sound_is_adpcm) { - ongakukan_adp_data* data = NULL; + ongakukan_adp_data* data = NULL; - data = calloc(1, sizeof(ongakukan_adp_data)); - if (!data) goto fail; + data = calloc(1, sizeof(ongakukan_adp_data)); + if (!data) goto fail; - /* reopen STREAMFILE from here, then pass it as an argument for our init function. we need to be able to read the file directly. */ - data->sf = reopen_streamfile(sf, 0); - if (!data->sf) goto fail; - data->handle = boot_ongakukan_adpcm(data->sf, (long int)(data_offset), (long int)(data_size), - sample_needs_setup, sample_has_base_setup_from_the_start); - if (!data->handle) goto fail; + /* reopen STREAMFILE from here, then pass it as an argument for our init function. */ + data->sf = reopen_streamfile(sf, 0); + if (!data->sf) goto fail; + data->handle = init_ongakukan_adpcm(data->sf, (long int)(data_offset), (long int)(data_size), + sound_is_adpcm); + if (!data->handle) goto fail; - printf(" return data; \n"); - return data; + return data; fail: - free_ongakukan_adp(data); - return NULL; + free_ongakukan_adp(data); + return NULL; } void decode_ongakukan_adp(VGMSTREAM* vgmstream, sample_t* outbuf, int32_t samples_to_do) { - ongakukan_adp_data* data = vgmstream->codec_data; + ongakukan_adp_data* data = vgmstream->codec_data; - data->samples_done = 0; - data->samples_filled = 0; - data->samples_consumed = 0; - data->samples = (int16_t*)grab_sample_hist_from_ongakukan_adp(data->handle); /* this'll return a pointer from the handle containing the samples themselves. */ - while (data->samples_done < samples_to_do) - { - if (data->samples_filled) - { - data->getting_samples = data->samples_filled; - if (data->getting_samples > samples_to_do - data->samples_done) - data->getting_samples = samples_to_do - data->samples_done; + data->getting_samples = 2; + data->samples_done = 0; + data->samples_filled = false; + /* ^ samples_filled is boolean here because we need to simplify how decoding will work here. + * so, rather than making samples_filled into a long int counter, + * we make it into a boolean flag instead so as to let data->samples_done shine as a counter + * and the decoder to do its job without worry. */ - memcpy(outbuf + data->samples_done, - data->samples + data->samples_consumed, - data->getting_samples * sizeof(int16_t)); - data->samples_done += data->getting_samples; + while (data->samples_done < samples_to_do) + { + if (data->samples_filled) + { + memcpy(outbuf + data->samples_done, + data->samples, + data->getting_samples * sizeof(int16_t)); + data->samples_done += data->getting_samples; - /* mark consumed samples. */ - data->samples_consumed += data->getting_samples; - data->samples_filled -= data->getting_samples; - - /* and keep the lib updated while doing so. */ - send_samples_consumed_to_ongakukan_adp((long int)(data->samples_consumed), data->handle); - send_samples_filled_to_ongakukan_adp((long int)(data->samples_filled), data->handle); - } - else { decode_ongakukan_adp_data(data->handle); - data->samples_filled = (int32_t)grab_samples_filled_from_ongakukan_adp(data->handle); - data->samples_consumed = (int32_t)grab_samples_consumed_from_ongakukan_adp(data->handle); - data->samples = (int16_t*)grab_sample_hist_from_ongakukan_adp(data->handle); } - } + data->samples_filled = false; + } + else { decode_ongakukan_adpcm_data(data->handle); + data->samples_filled = true; + data->samples = (int16_t*)get_sample_hist_from_ongakukan_adpcm(data->handle); } + } } void reset_ongakukan_adp(ongakukan_adp_data* data) { - if (!data) return; - reset_all_ongakukan_adpcm(data->handle); + if (!data) return; + ongakukan_adpcm_reset(data->handle); } void seek_ongakukan_adp(ongakukan_adp_data* data, int32_t current_sample) { - if (!data) return; - seek_ongakukan_adpcm_pos(data->handle, current_sample); + if (!data) return; + ongakukan_adpcm_seek(data->handle, current_sample); } void free_ongakukan_adp(ongakukan_adp_data* data) { - if (!data) return; - free_all_ongakukan_adpcm(data->handle); - free(data); + if (!data) return; + close_streamfile(data->sf); + ongakukan_adpcm_free(data->handle); + free(data->samples); + free(data); } int32_t ongakukan_adp_get_samples(ongakukan_adp_data* data) { - if (!data) return 0; - return (int32_t)(grab_num_samples_from_ongakukan_adp(data->handle)); + if (!data) return 0; + return (int32_t)get_num_samples_from_ongakukan_adpcm(data->handle); } diff --git a/src/meta/adp_ongakukan.c b/src/meta/adp_ongakukan.c index 010ad6ef..9069c358 100644 --- a/src/meta/adp_ongakukan.c +++ b/src/meta/adp_ongakukan.c @@ -4,113 +4,100 @@ /* Ongakukan RIFF with "ADP" extension [Train Simulator - Midousuji-sen (PS2)] */ VGMSTREAM* init_vgmstream_ongakukan_adp(STREAMFILE* sf) { - VGMSTREAM* vgmstream = NULL; - off_t start_offset; - size_t file_size; - int has_data_chunk = 0, has_fact_chunk = 0, found_start_offset = 0; - int loop_flag = 0; - int riff_wave_header_size = 0x2c; - char sound_is_adpcm = 0, sample_has_base_setup_from_the_start = 0; - /* ^ the entire RIFF WAVE header size, set to this fixed number - * because *surprise* this is also how sound data begins. */ - int32_t fmt_size, fmt_offset, offset_of_supposed_last_chunk; - int32_t sample_rate, bitrate, data_size; - int16_t num_channels, block_size; + VGMSTREAM* vgmstream = NULL; + off_t start_offset; + size_t file_size; + bool has_data_chunk = false, has_fact_chunk = false; + int loop_flag = 0; + int riff_wave_header_size = 0x2c; + /* ^ where sound data begins, as a consequence their tools couldn't even write full RIFF WAVE header to file beyond that point.. */ + bool sound_is_adpcm = false; + int32_t supposed_size, fmt_size, fmt_offset, offset_of_supposed_last_chunk; + int32_t sample_rate, data_size; + int16_t num_channels, block_size; - /* RIFF+WAVE checks */ - if (!is_id32be(0x00, sf, "RIFF")) goto fail; - if (!is_id32be(0x08, sf, "WAVE")) goto fail; - /* WAVE "fmt " check */ - if (!is_id32be(0x0c, sf, "fmt ")) goto fail; - /* "adp" extension check (literally only one) */ - if (!check_extensions(sf, "adp")) goto fail; - - /* catch adp file size from here and use it whenever needed. */ - file_size = get_streamfile_size(sf); + /* RIFF+WAVE checks */ + if (!is_id32be(0x00, sf, "RIFF")) goto fail; + if (!is_id32be(0x08, sf, "WAVE")) goto fail; + /* WAVE "fmt " check */ + if (!is_id32be(0x0c, sf, "fmt ")) goto fail; + /* "adp" extension check (literally only one) */ + if (!check_extensions(sf, "adp")) goto fail; - /* RIFF size from adp file (e.g: 10MB) can go beyond actual adp file size (e.g: 2MB), - * have vgmstream call it quits if the former is reported to be less than the latter. */ - if (read_s32le(0x04, sf) < file_size) goto fail; + /* catch adp file size from here and use it whenever needed. */ + file_size = get_streamfile_size(sf); - /* read entire WAVE "fmt " chunk. we start by reading fmt_size from yours truly and setting fmt_offset. */ - fmt_size = read_s32le(0x10, sf); - fmt_offset = 0x14; - if ((fmt_size >= 0x10) && (fmt_size <= 0x12)) /* fmt_size is mostly 0x10, rarely 0x12 */ - { - if (read_s16le(fmt_offset + 0, sf) != 1) goto fail; /* chunk reports codec number as signed little-endian PCM, couldn't be more wrong. */ - num_channels = read_s16le(fmt_offset + 2, sf); - sample_rate = read_s32le(fmt_offset + 4, sf); - bitrate = read_s32le(fmt_offset + 8, sf); - /* ^ yes, this is technically correct, tho does not reflect actual data. - * chunk reports bitrate as if it was a 16-bit PCM file. */ - block_size = read_s16le(fmt_offset + 12, sf); /* mostly 2, rarely 4. */ - if (read_s16le(fmt_offset + 14, sf) != 0x10) goto fail; /* bit depth as chunk reports it. */ - /* additional checks, this time with bitrate field in the chunk. */ - if (bitrate != (sample_rate * block_size)) goto fail; - /* if fmt_size == 0x12 there is an additional s16 field that's always zero. */ - } - else { - goto fail; - } + /* RIFF size from adp file can go beyond actual size (e.g: reported 10MB vs 2MB). do quick calcs around this. */ + supposed_size = ((read_s32le(0x04, sf) - 0x24) >> 2) + 0x2c; + if (file_size != supposed_size) goto fail; - /* now calc the var so we can read either "data" or "fact" chunk; */ - offset_of_supposed_last_chunk = fmt_offset + fmt_size; + /* read entire WAVE "fmt " chunk. we start by reading fmt_size from yours truly and setting fmt_offset. */ + fmt_size = read_s32le(0x10, sf); + fmt_offset = 0x14; + if ((fmt_size >= 0x10) && (fmt_size <= 0x12)) /* depending on the adp, fmt_size alternates between 0x10 and 0x12 */ + { + if (read_s16le(fmt_offset + 0, sf) != 1) goto fail; /* chunk reports codec number as signed little-endian PCM, couldn't be more wrong. */ + num_channels = read_s16le(fmt_offset + 2, sf); + sample_rate = read_s32le(fmt_offset + 4, sf); + if (read_s16le(fmt_offset + 14, sf) != 0x10) goto fail; /* bit depth as chunk reports it. */ + /* rest of fmt header is the usual header for 16-bit PCM wav files: bitrate, block size, and the like (see riff.c) */ + /* if fmt_size == 0x12 there is an additional s16 field that's always zero. */ + } + else { + goto fail; + } - /* then read either one of the two chunks, both cannot co-exist it seems. - * while there, we set start_offset by themselves instead of relying on both chunks to do so. - * see comments for code handling both chunks below for more info. */ - if (is_id32be(offset_of_supposed_last_chunk + 0, sf, "data")) has_data_chunk = 1; - if (is_id32be(offset_of_supposed_last_chunk + 0, sf, "fact")) has_fact_chunk = 1; + /* now calc the var so we can read either "data" or "fact" chunk; */ + offset_of_supposed_last_chunk = fmt_offset + fmt_size; - /* and because sound data *must* start at 0x2c, they have to bork both chunks too, so they're now essentially useless. - * well, except for trying to deduct how many samples a sound actually has*/ - if (has_data_chunk) - { - /* RIFF adp files have borked "data" chunk so much it's not even remotely useful for... well, *anything*, really. - * it doesn't report actual data size as RIFF WAVE files usually do, instead we're left with basically RIFF size with ~50 less numbers now. */ - if (read_s32le(offset_of_supposed_last_chunk + 4, sf) < file_size) goto fail; - /* ^ reported data size is meant to be bigger than actual adp size, have vgmstream throw out the towel if it isn't. */ - } + /* we need to get to the last WAVE chunk manually, and that means the calc below. */ + offset_of_supposed_last_chunk = fmt_offset + fmt_size; + if (is_id32be(offset_of_supposed_last_chunk + 0, sf, "data")) has_data_chunk = true; + if (is_id32be(offset_of_supposed_last_chunk + 0, sf, "fact")) has_fact_chunk = true; - if (has_fact_chunk) - { - /* RIFF adp files also borked "fact" chunk so it no longer reports useful info. - * instead it just leaves out a s16 field containing a static number. */ - if (read_s16le(offset_of_supposed_last_chunk + 4, sf) != 4) goto fail; - /* ^ this number is supposed to be 4, have vgmstream ragequit if it isn't. */ - } + /* and because sound data *must* start at 0x2c, they have to bork both chunks too, so they're now essentially useless. + * they're basically leftovers from original (lossless) WAV files at this point. */ + if (has_data_chunk) + { + /* RIFF adp files have leftover "data" chunk size... that does NOT match the ADP file size at hand. */ + supposed_size = (read_s32le(offset_of_supposed_last_chunk + 4, sf) >> 2) + 0x2c; + if (file_size != supposed_size) goto fail; + } - /* set start_offset value to riff_wave_header_size - * and calculate data_size by ourselves */ - start_offset = riff_wave_header_size; - data_size = (int32_t)(file_size) - riff_wave_header_size; + if (has_fact_chunk) + { + /* RIFF adp files have also cut off "fact" chunk so we're just left with a useless number now. */ + if (read_s16le(offset_of_supposed_last_chunk + 4, sf) != 4) goto fail; + } - /* Ongagukan games using this format just read it by checking "ADP" extension - * in an provided file name of a programmer's own choosing, - * and if it's there they just read the reported "number of samples" and sample_rate from RIFF WAVE "fmt " chunk - * based on an already-opened file with that same name. - * they also calculate start_offset and data_size in much the same manner. */ + /* set start_offset value to riff_wave_header_size and calculate data_size by ourselves, basically how Ongakukan does it also. */ + start_offset = riff_wave_header_size; + data_size = (int32_t)(file_size) - riff_wave_header_size; - /* silly flags, needed to init our custom decoder. */ - sound_is_adpcm = 1; - sample_has_base_setup_from_the_start = 1; + /* Ongagukan games using this format just read it by checking "ADP" extension in an provided file name of a programmer's own choosing, + * and if extension is there they just read the reported "number of samples" and "sample_rate" vars + * from RIFF WAVE "fmt " chunk based on an already-opened file with that same name. + * and they don't even read RIFF chunks, they just pick these two vars and that's basically it. */ - /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(num_channels, loop_flag); - if (!vgmstream) goto fail; + /* our custom decoder needs at least one flag set. */ + sound_is_adpcm = true; - vgmstream->meta_type = meta_ONGAKUKAN_RIFF_ADP; - vgmstream->sample_rate = sample_rate; - vgmstream->codec_data = init_ongakukan_adp(sf, start_offset, data_size, sound_is_adpcm, sample_has_base_setup_from_the_start); - if (!vgmstream->codec_data) goto fail; - vgmstream->coding_type = coding_ONGAKUKAN_ADPCM; - vgmstream->layout_type = layout_none; - vgmstream->num_samples = ongakukan_adp_get_samples(vgmstream->codec_data); + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(num_channels, loop_flag); + if (!vgmstream) goto fail; - if (!vgmstream_open_stream(vgmstream, sf, start_offset)) - goto fail; - return vgmstream; + vgmstream->meta_type = meta_ONGAKUKAN_RIFF_ADP; + vgmstream->sample_rate = sample_rate; + vgmstream->codec_data = init_ongakukan_adp(sf, start_offset, data_size, sound_is_adpcm); + if (!vgmstream->codec_data) goto fail; + vgmstream->coding_type = coding_ONGAKUKAN_ADPCM; + vgmstream->layout_type = layout_none; + vgmstream->num_samples = ongakukan_adp_get_samples(vgmstream->codec_data); + + if (!vgmstream_open_stream(vgmstream, sf, start_offset)) + goto fail; + return vgmstream; fail: - close_vgmstream(vgmstream); - return NULL; + close_vgmstream(vgmstream); + return NULL; } diff --git a/src/meta/riff.c b/src/meta/riff.c index b7bdaf7b..8bb5e62c 100644 --- a/src/meta/riff.c +++ b/src/meta/riff.c @@ -350,7 +350,6 @@ VGMSTREAM* init_vgmstream_riff(STREAMFILE* sf) { off_t mwv_pflt_offset = 0; off_t mwv_ctrl_offset = 0; int ignore_riff_size = 0; - int riff_size_bigger_than_pcm_file = 0; /* checks*/ @@ -474,17 +473,8 @@ VGMSTREAM* init_vgmstream_riff(STREAMFILE* sf) { file_size -= 0x40; /* [Megami no Etsubo (PSP)] (has extra padding in all files) */ else if (codec == 0x0011 && file_size - riff_size - 0x08 <= 0x900 && is_id32be(riff_size + 0x08, sf, "cont")) - riff_size = file_size - 0x08; /* [Shin Megami Tensei: Imagine (PC)] (extra "cont" info 0x800/0x900 chunk) */ + riff_size = file_size - 0x08; /* [Shin Megami Tensei: Imagine (PC)] (extra "cont" info 0x800/0x900 chunk) */ - else if (codec == 0x0001 && riff_size > file_size + 0x8000) - riff_size_bigger_than_pcm_file = 1; /* [Train Simulator: Midousuji-hen (PS2)] (reports bigger RIFF sizes than should be possible) */ - } - - /* throw out when RIFF size is bigger than actual file size */ - if (riff_size_bigger_than_pcm_file) - { - /* vgm_logi("RIFF: reported size (%d) bigger than actual file (%d)\n", riff_size, file_size); */ - goto fail; } /* check for truncated RIFF */ @@ -1205,7 +1195,7 @@ VGMSTREAM* init_vgmstream_rifx(STREAMFILE* sf) { /* end must add +1, but check in case of faulty tools */ if (vgmstream->loop_end_sample - 1 == vgmstream->num_samples) vgmstream->loop_end_sample--; - + vgmstream->meta_type = meta_RIFX_WAVE_smpl; } }