#include "vgmstream.h" #include "decode.h" #include "layout/layout.h" #include "coding/coding.h" #include "mixing.h" #include "plugins.h" /* custom codec handling, not exactly "decode" stuff but here to simplify adding new codecs */ void free_codec(VGMSTREAM* vgmstream) { #ifdef VGM_USE_VORBIS if (vgmstream->coding_type == coding_OGG_VORBIS) { free_ogg_vorbis(vgmstream->codec_data); } if (vgmstream->coding_type == coding_VORBIS_custom) { free_vorbis_custom(vgmstream->codec_data); } #endif if (vgmstream->coding_type == coding_CIRCUS_VQ) { free_circus_vq(vgmstream->codec_data); } if (vgmstream->coding_type == coding_RELIC) { free_relic(vgmstream->codec_data); } if (vgmstream->coding_type == coding_CRI_HCA) { free_hca(vgmstream->codec_data); } if (vgmstream->coding_type == coding_TAC) { free_tac(vgmstream->codec_data); } if (vgmstream->coding_type == coding_UBI_ADPCM) { free_ubi_adpcm(vgmstream->codec_data); } if (vgmstream->coding_type == coding_IMUSE) { free_imuse(vgmstream->codec_data); } if (vgmstream->coding_type == coding_COMPRESSWAVE) { free_compresswave(vgmstream->codec_data); } if (vgmstream->coding_type == coding_EA_MT) { free_ea_mt(vgmstream->codec_data, vgmstream->channels); } #ifdef VGM_USE_FFMPEG if (vgmstream->coding_type == coding_FFmpeg) { free_ffmpeg(vgmstream->codec_data); } #endif #if defined(VGM_USE_MP4V2) && defined(VGM_USE_FDKAAC) if (vgmstream->coding_type == coding_MP4_AAC) { free_mp4_aac(vgmstream->codec_data); } #endif #ifdef VGM_USE_MPEG if (vgmstream->coding_type == coding_MPEG_custom || vgmstream->coding_type == coding_MPEG_ealayer3 || vgmstream->coding_type == coding_MPEG_layer1 || vgmstream->coding_type == coding_MPEG_layer2 || vgmstream->coding_type == coding_MPEG_layer3) { free_mpeg(vgmstream->codec_data); } #endif #ifdef VGM_USE_G7221 if (vgmstream->coding_type == coding_G7221C) { free_g7221(vgmstream->codec_data); } #endif #ifdef VGM_USE_G719 if (vgmstream->coding_type == coding_G719) { free_g719(vgmstream->codec_data, vgmstream->channels); } #endif #ifdef VGM_USE_MAIATRAC3PLUS if (vgmstream->coding_type == coding_AT3plus) { free_at3plus(vgmstream->codec_data); } #endif #ifdef VGM_USE_ATRAC9 if (vgmstream->coding_type == coding_ATRAC9) { free_atrac9(vgmstream->codec_data); } #endif #ifdef VGM_USE_CELT if (vgmstream->coding_type == coding_CELT_FSB) { free_celt_fsb(vgmstream->codec_data); } #endif #ifdef VGM_USE_SPEEX if (vgmstream->coding_type == coding_SPEEX) { free_speex(vgmstream->codec_data); } #endif if (vgmstream->coding_type == coding_ACM) { free_acm(vgmstream->codec_data); } if (vgmstream->coding_type == coding_NWA) { free_nwa(vgmstream->codec_data); } } void seek_codec(VGMSTREAM* vgmstream) { if (vgmstream->coding_type == coding_CIRCUS_VQ) { seek_circus_vq(vgmstream->codec_data, vgmstream->loop_current_sample); } if (vgmstream->coding_type == coding_RELIC) { seek_relic(vgmstream->codec_data, vgmstream->loop_current_sample); } if (vgmstream->coding_type == coding_TAC) { seek_tac(vgmstream->codec_data, vgmstream->loop_current_sample); } if (vgmstream->coding_type == coding_UBI_ADPCM) { seek_ubi_adpcm(vgmstream->codec_data, vgmstream->loop_current_sample); } if (vgmstream->coding_type == coding_IMUSE) { seek_imuse(vgmstream->codec_data, vgmstream->loop_current_sample); } if (vgmstream->coding_type == coding_COMPRESSWAVE) { seek_compresswave(vgmstream->codec_data, vgmstream->loop_current_sample); } if (vgmstream->coding_type == coding_EA_MT) { seek_ea_mt(vgmstream, vgmstream->loop_current_sample); } #ifdef VGM_USE_VORBIS if (vgmstream->coding_type == coding_OGG_VORBIS) { seek_ogg_vorbis(vgmstream->codec_data, vgmstream->loop_current_sample); } if (vgmstream->coding_type == coding_VORBIS_custom) { seek_vorbis_custom(vgmstream, vgmstream->loop_current_sample); } #endif #ifdef VGM_USE_FFMPEG if (vgmstream->coding_type == coding_FFmpeg) { seek_ffmpeg(vgmstream->codec_data, vgmstream->loop_current_sample); } #endif #if defined(VGM_USE_MP4V2) && defined(VGM_USE_FDKAAC) if (vgmstream->coding_type == coding_MP4_AAC) { seek_mp4_aac(vgmstream, vgmstream->loop_sample); } #endif #ifdef VGM_USE_MAIATRAC3PLUS if (vgmstream->coding_type == coding_AT3plus) { seek_at3plus(vgmstream, vgmstream->loop_current_sample); } #endif #ifdef VGM_USE_ATRAC9 if (vgmstream->coding_type == coding_ATRAC9) { seek_atrac9(vgmstream, vgmstream->loop_current_sample); } #endif #ifdef VGM_USE_CELT if (vgmstream->coding_type == coding_CELT_FSB) { seek_celt_fsb(vgmstream, vgmstream->loop_current_sample); } #endif #ifdef VGM_USE_SPEEX if (vgmstream->coding_type == coding_SPEEX) { seek_speex(vgmstream, vgmstream->loop_current_sample); } #endif #ifdef VGM_USE_MPEG if (vgmstream->coding_type == coding_MPEG_custom || vgmstream->coding_type == coding_MPEG_ealayer3 || vgmstream->coding_type == coding_MPEG_layer1 || vgmstream->coding_type == coding_MPEG_layer2 || vgmstream->coding_type == coding_MPEG_layer3) { seek_mpeg(vgmstream, vgmstream->loop_current_sample); } #endif if (vgmstream->coding_type == coding_NWA) { seek_nwa(vgmstream->codec_data, vgmstream->loop_current_sample); } } void reset_codec(VGMSTREAM* vgmstream) { #ifdef VGM_USE_VORBIS if (vgmstream->coding_type == coding_OGG_VORBIS) { reset_ogg_vorbis(vgmstream); } if (vgmstream->coding_type == coding_VORBIS_custom) { reset_vorbis_custom(vgmstream); } #endif if (vgmstream->coding_type == coding_CIRCUS_VQ) { reset_circus_vq(vgmstream->codec_data); } if (vgmstream->coding_type == coding_RELIC) { reset_relic(vgmstream->codec_data); } if (vgmstream->coding_type == coding_TAC) { reset_tac(vgmstream->codec_data); } if (vgmstream->coding_type == coding_UBI_ADPCM) { reset_ubi_adpcm(vgmstream->codec_data); } if (vgmstream->coding_type == coding_IMUSE) { reset_imuse(vgmstream->codec_data); } if (vgmstream->coding_type == coding_COMPRESSWAVE) { reset_compresswave(vgmstream->codec_data); } if (vgmstream->coding_type == coding_EA_MT) { reset_ea_mt(vgmstream); } #if defined(VGM_USE_MP4V2) && defined(VGM_USE_FDKAAC) if (vgmstream->coding_type == coding_MP4_AAC) { reset_mp4_aac(vgmstream); } #endif #ifdef VGM_USE_MPEG if (vgmstream->coding_type == coding_MPEG_custom || vgmstream->coding_type == coding_MPEG_ealayer3 || vgmstream->coding_type == coding_MPEG_layer1 || vgmstream->coding_type == coding_MPEG_layer2 || vgmstream->coding_type == coding_MPEG_layer3) { reset_mpeg(vgmstream->codec_data); } #endif #ifdef VGM_USE_G7221 if (vgmstream->coding_type == coding_G7221C) { reset_g7221(vgmstream->codec_data); } #endif #ifdef VGM_USE_G719 if (vgmstream->coding_type == coding_G719) { reset_g719(vgmstream->codec_data, vgmstream->channels); } #endif #ifdef VGM_USE_MAIATRAC3PLUS if (vgmstream->coding_type == coding_AT3plus) { reset_at3plus(vgmstream); } #endif #ifdef VGM_USE_ATRAC9 if (vgmstream->coding_type == coding_ATRAC9) { reset_atrac9(vgmstream->codec_data); } #endif #ifdef VGM_USE_CELT if (vgmstream->coding_type == coding_CELT_FSB) { reset_celt_fsb(vgmstream->codec_data); } #endif #ifdef VGM_USE_SPEEX if (vgmstream->coding_type == coding_SPEEX) { reset_speex(vgmstream->codec_data); } #endif #ifdef VGM_USE_FFMPEG if (vgmstream->coding_type == coding_FFmpeg) { reset_ffmpeg(vgmstream->codec_data); } #endif if (vgmstream->coding_type == coding_ACM) { reset_acm(vgmstream->codec_data); } if (vgmstream->coding_type == coding_NWA) { reset_nwa(vgmstream->codec_data); } } /* Get the number of samples of a single frame (smallest self-contained sample group, 1/N channels) */ int get_vgmstream_samples_per_frame(VGMSTREAM* vgmstream) { /* Value returned here is the max (or less) that vgmstream will ask a decoder per * "decode_x" call. Decoders with variable samples per frame or internal discard * may return 0 here and handle arbitrary samples_to_do values internally * (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: case coding_CRI_ADX_enc_8: case coding_CRI_ADX_enc_9: return (vgmstream->interleave_block_size - 2) * 2; case coding_NGC_DSP: case coding_NGC_DSP_subint: return 14; case coding_NGC_AFC: case coding_VADPCM: return 16; case coding_NGC_DTK: return 28; case coding_G721: return 1; case coding_PCM16LE: case coding_PCM16BE: case coding_PCM16_int: case coding_PCM8: case coding_PCM8_int: case coding_PCM8_U: case coding_PCM8_U_int: case coding_PCM8_SB: case coding_ULAW: case coding_ULAW_int: case coding_ALAW: case coding_PCMFLOAT: return 1; #ifdef VGM_USE_VORBIS case coding_OGG_VORBIS: case coding_VORBIS_custom: #endif #ifdef VGM_USE_MPEG case coding_MPEG_custom: case coding_MPEG_ealayer3: case coding_MPEG_layer1: case coding_MPEG_layer2: case coding_MPEG_layer3: #endif case coding_SDX2: case coding_SDX2_int: case coding_CBD2: case coding_CBD2_int: case coding_ACM: case coding_DERF: case coding_WADY: case coding_NWA: case coding_SASSC: case coding_CIRCUS_ADPCM: return 1; case coding_IMA: case coding_DVI_IMA: case coding_SNDS_IMA: case coding_OTNS_IMA: case coding_UBI_IMA: case coding_UBI_SCE_IMA: case coding_OKI16: case coding_OKI4S: case coding_MTF_IMA: return 1; case coding_PCM4: case coding_PCM4_U: case coding_IMA_int: case coding_DVI_IMA_int: case coding_3DS_IMA: case coding_WV6_IMA: case coding_ALP_IMA: case coding_FFTA2_IMA: case coding_BLITZ_IMA: case coding_PCFX: return 2; case coding_XBOX_IMA: case coding_XBOX_IMA_mch: case coding_XBOX_IMA_int: case coding_FSB_IMA: case coding_WWISE_IMA: case coding_CD_IMA: return 64; case coding_APPLE_IMA4: return 64; case coding_MS_IMA: case coding_REF_IMA: return ((vgmstream->interleave_block_size - 0x04*vgmstream->channels) * 2 / vgmstream->channels) + 1; case coding_RAD_IMA: return (vgmstream->interleave_block_size - 0x04*vgmstream->channels) * 2 / vgmstream->channels; case coding_NDS_IMA: case coding_DAT4_IMA: return (vgmstream->interleave_block_size - 0x04) * 2; case coding_AWC_IMA: return (0x800 - 0x04) * 2; case coding_RAD_IMA_mono: return 32; case coding_H4M_IMA: return 0; /* variable (block-controlled) */ case coding_XA: return 28*8 / vgmstream->channels; /* 8 subframes per frame, mono/stereo */ case coding_PSX: case coding_PSX_badflags: case coding_HEVAG: return 28; case coding_PSX_cfg: case coding_PSX_pivotal: return (vgmstream->interleave_block_size - 0x01) * 2; /* size 0x01 header */ case coding_EA_XA: case coding_EA_XA_int: case coding_EA_XA_V2: case coding_MAXIS_XA: return 28; case coding_EA_XAS_V0: return 32; case coding_EA_XAS_V1: return 128; case coding_MSADPCM: return (vgmstream->frame_size - 0x07*vgmstream->channels)*2 / vgmstream->channels + 2; case coding_MSADPCM_int: case coding_MSADPCM_ck: return (vgmstream->frame_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_ASKA: return (vgmstream->frame_size - 0x04*vgmstream->channels) * 2 / vgmstream->channels; case coding_NXAP: return (0x40-0x04) * 2; case coding_NDS_PROCYON: return 30; case coding_L5_555: return 32; case coding_LSF: return 54; #ifdef VGM_USE_G7221 case coding_G7221C: return 32000/50; /* Siren7: 16000/50 */ #endif #ifdef VGM_USE_G719 case coding_G719: return 48000/50; #endif #ifdef VGM_USE_FFMPEG case coding_FFmpeg: return 0; #endif case coding_MTAF: return 128*2; case coding_MTA2: return 128*2; case coding_MC3: return 10; case coding_FADPCM: return 256; /* (0x8c - 0xc) * 2 */ case coding_ASF: return 32; /* (0x11 - 0x1) * 2 */ case coding_DSA: return 14; /* (0x08 - 0x1) * 2 */ case coding_XMD: return (vgmstream->interleave_block_size - 0x06)*2 + 2; case coding_PTADPCM: return (vgmstream->interleave_block_size - 0x05)*2 + 2; case coding_UBI_ADPCM: return 0; /* varies per mode */ case coding_IMUSE: return 0; /* varies per frame */ case coding_COMPRESSWAVE: return 0; /* multiple of 2 */ case coding_EA_MT: return 0; /* 432, but variable in looped files */ case coding_CIRCUS_VQ: return 0; case coding_RELIC: return 0; /* 512 */ case coding_CRI_HCA: return 0; /* 1024 - delay/padding (which can be bigger than 1024) */ case coding_TAC: return 0; /* 1024 - delay/padding */ #if defined(VGM_USE_MP4V2) && defined(VGM_USE_FDKAAC) case coding_MP4_AAC: return ((mp4_aac_codec_data*)vgmstream->codec_data)->samples_per_frame; #endif #ifdef VGM_USE_MAIATRAC3PLUS case coding_AT3plus: return 2048 - ((maiatrac3plus_codec_data*)vgmstream->codec_data)->samples_discard; #endif #ifdef VGM_USE_ATRAC9 case coding_ATRAC9: return 0; /* varies with config data, usually 256 or 1024 */ #endif #ifdef VGM_USE_CELT case coding_CELT_FSB: return 0; /* 512? */ #endif #ifdef VGM_USE_SPEEX case coding_SPEEX: return 0; #endif default: return 0; } } /* 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: case coding_CRI_ADX_enc_8: case coding_CRI_ADX_enc_9: return vgmstream->interleave_block_size; case coding_NGC_DSP: return 0x08; case coding_NGC_DSP_subint: return 0x08 * vgmstream->channels; case coding_NGC_AFC: case coding_VADPCM: return 0x09; case coding_NGC_DTK: return 0x20; case coding_G721: return 0; case coding_PCM16LE: case coding_PCM16BE: case coding_PCM16_int: return 0x02; case coding_PCM8: case coding_PCM8_int: case coding_PCM8_U: case coding_PCM8_U_int: case coding_PCM8_SB: case coding_ULAW: case coding_ULAW_int: case coding_ALAW: return 0x01; case coding_PCMFLOAT: return 0x04; case coding_SDX2: case coding_SDX2_int: case coding_CBD2: case coding_CBD2_int: case coding_DERF: case coding_WADY: case coding_NWA: case coding_SASSC: case coding_CIRCUS_ADPCM: return 0x01; case coding_PCM4: case coding_PCM4_U: case coding_IMA: case coding_IMA_int: case coding_DVI_IMA: case coding_DVI_IMA_int: case coding_3DS_IMA: case coding_WV6_IMA: case coding_ALP_IMA: case coding_FFTA2_IMA: case coding_BLITZ_IMA: case coding_PCFX: case coding_OKI16: case coding_OKI4S: case coding_MTF_IMA: return 0x01; case coding_MS_IMA: case coding_RAD_IMA: case coding_NDS_IMA: case coding_DAT4_IMA: case coding_REF_IMA: return vgmstream->interleave_block_size; case coding_AWC_IMA: return 0x800; case coding_RAD_IMA_mono: return 0x14; case coding_SNDS_IMA: case coding_OTNS_IMA: return 0; //todo: 0x01? case coding_UBI_IMA: /* variable (PCM then IMA) */ return 0; case coding_UBI_SCE_IMA: return 0; case coding_XBOX_IMA: //todo should be 0x48 when stereo, but blocked/interleave layout don't understand stereo codecs return 0x24; //vgmstream->channels==1 ? 0x24 : 0x48; case coding_XBOX_IMA_int: case coding_WWISE_IMA: case coding_CD_IMA: return 0x24; case coding_XBOX_IMA_mch: case coding_FSB_IMA: return 0x24 * vgmstream->channels; case coding_APPLE_IMA4: return 0x22; case coding_H4M_IMA: return 0x00; /* variable (block-controlled) */ case coding_XA: return 0x80; case coding_PSX: case coding_PSX_badflags: case coding_HEVAG: return 0x10; case coding_PSX_cfg: case coding_PSX_pivotal: return vgmstream->interleave_block_size; case coding_EA_XA: return 0x1E; case coding_EA_XA_int: return 0x0F; case coding_MAXIS_XA: return 0x0F*vgmstream->channels; case coding_EA_XA_V2: return 0; /* variable (ADPCM frames of 0x0f or PCM frames of 0x3d) */ case coding_EA_XAS_V0: return 0xF+0x02+0x02; case coding_EA_XAS_V1: return 0x4c*vgmstream->channels; case coding_MSADPCM: case coding_MSADPCM_int: case coding_MSADPCM_ck: return vgmstream->frame_size; case coding_WS: return vgmstream->current_block_size; case coding_AICA: case coding_AICA_int: return 0x01; case coding_ASKA: return vgmstream->frame_size; case coding_NXAP: return 0x40; case coding_NDS_PROCYON: return 0x10; case coding_L5_555: return 0x12; case coding_LSF: return 0x1C; #ifdef VGM_USE_G7221 case coding_G7221C: #endif #ifdef VGM_USE_G719 case coding_G719: #endif #ifdef VGM_USE_MAIATRAC3PLUS case coding_AT3plus: #endif #ifdef VGM_USE_FFMPEG case coding_FFmpeg: #endif case coding_MTAF: return vgmstream->interleave_block_size; case coding_MTA2: return 0x90; case coding_MC3: return 0x04; case coding_FADPCM: return 0x8c; case coding_ASF: return 0x11; case coding_DSA: return 0x08; case coding_XMD: return vgmstream->interleave_block_size; case coding_PTADPCM: return vgmstream->interleave_block_size; /* UBI_ADPCM: varies per mode? */ /* IMUSE: VBR */ /* EA_MT: VBR, frames of bit counts or PCM frames */ /* COMPRESSWAVE: VBR/huffman bits */ /* ATRAC9: CBR around 0x100-200 */ /* CELT FSB: varies, usually 0x80-100 */ /* SPEEX: varies, usually 0x40-60 */ /* TAC: VBR around ~0x200-300 */ /* Vorbis, MPEG, ACM, etc: varies */ default: /* (VBR or managed by decoder) */ return 0; } } /* In NDS IMA the frame size is the block size, so the last one is short */ int get_vgmstream_samples_per_shortframe(VGMSTREAM* vgmstream) { switch (vgmstream->coding_type) { case coding_NDS_IMA: return (vgmstream->interleave_last_block_size-4)*2; default: return get_vgmstream_samples_per_frame(vgmstream); } } int get_vgmstream_shortframe_size(VGMSTREAM* vgmstream) { switch (vgmstream->coding_type) { case coding_NDS_IMA: return vgmstream->interleave_last_block_size; default: return get_vgmstream_frame_size(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 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; 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: case coding_CRI_ADX_enc_8: case coding_CRI_ADX_enc_9: for (ch = 0; ch < vgmstream->channels; ch++) { decode_adx(&vgmstream->ch[ch], buffer+ch, vgmstream->channels, vgmstream->samples_into_block, samples_to_do, vgmstream->interleave_block_size, vgmstream->coding_type); } break; case coding_NGC_DSP: for (ch = 0; ch < vgmstream->channels; ch++) { decode_ngc_dsp(&vgmstream->ch[ch], buffer+ch, vgmstream->channels, vgmstream->samples_into_block, samples_to_do); } break; case coding_NGC_DSP_subint: for (ch = 0; ch < vgmstream->channels; ch++) { decode_ngc_dsp_subint(&vgmstream->ch[ch], buffer+ch, vgmstream->channels, vgmstream->samples_into_block, samples_to_do, ch, vgmstream->interleave_block_size); } break; case coding_PCM16LE: for (ch = 0; ch < vgmstream->channels; ch++) { decode_pcm16le(&vgmstream->ch[ch], buffer+ch, vgmstream->channels, vgmstream->samples_into_block, samples_to_do); } break; case coding_PCM16BE: for (ch = 0; ch < vgmstream->channels; ch++) { decode_pcm16be(&vgmstream->ch[ch], buffer+ch, vgmstream->channels, vgmstream->samples_into_block, samples_to_do); } break; case coding_PCM16_int: for (ch = 0; ch < vgmstream->channels; ch++) { decode_pcm16_int(&vgmstream->ch[ch], buffer+ch, vgmstream->channels, vgmstream->samples_into_block, samples_to_do, vgmstream->codec_endian); } break; case coding_PCM8: for (ch = 0; ch < vgmstream->channels; ch++) { decode_pcm8(&vgmstream->ch[ch], buffer+ch, vgmstream->channels, vgmstream->samples_into_block, samples_to_do); } break; case coding_PCM8_int: for (ch = 0; ch < vgmstream->channels; ch++) { decode_pcm8_int(&vgmstream->ch[ch], buffer+ch, vgmstream->channels, vgmstream->samples_into_block, samples_to_do); } break; case coding_PCM8_U: for (ch = 0; ch < vgmstream->channels; ch++) { decode_pcm8_unsigned(&vgmstream->ch[ch], buffer+ch, vgmstream->channels, vgmstream->samples_into_block, samples_to_do); } break; case coding_PCM8_U_int: for (ch = 0; ch < vgmstream->channels; ch++) { decode_pcm8_unsigned_int(&vgmstream->ch[ch], buffer+ch, vgmstream->channels, vgmstream->samples_into_block, samples_to_do); } break; case coding_PCM8_SB: for (ch = 0; ch < vgmstream->channels; ch++) { decode_pcm8_sb(&vgmstream->ch[ch], buffer+ch, vgmstream->channels, vgmstream->samples_into_block, samples_to_do); } break; case coding_PCM4: for (ch = 0; ch < vgmstream->channels; ch++) { decode_pcm4(vgmstream,&vgmstream->ch[ch], buffer+ch, vgmstream->channels, vgmstream->samples_into_block, samples_to_do, ch); } break; case coding_PCM4_U: for (ch = 0; ch < vgmstream->channels; ch++) { decode_pcm4_unsigned(vgmstream, &vgmstream->ch[ch], buffer+ch, vgmstream->channels, vgmstream->samples_into_block, samples_to_do, ch); } break; case coding_ULAW: for (ch = 0; ch < vgmstream->channels; ch++) { decode_ulaw(&vgmstream->ch[ch], buffer+ch, vgmstream->channels, vgmstream->samples_into_block, samples_to_do); } break; case coding_ULAW_int: for (ch = 0; ch < vgmstream->channels; ch++) { decode_ulaw_int(&vgmstream->ch[ch], buffer+ch, vgmstream->channels, vgmstream->samples_into_block, samples_to_do); } break; case coding_ALAW: for (ch = 0; ch < vgmstream->channels; ch++) { decode_alaw(&vgmstream->ch[ch], buffer+ch, vgmstream->channels, vgmstream->samples_into_block, samples_to_do); } break; case coding_PCMFLOAT: for (ch = 0; ch < vgmstream->channels; ch++) { decode_pcmfloat(&vgmstream->ch[ch], buffer+ch, vgmstream->channels, vgmstream->samples_into_block, samples_to_do, vgmstream->codec_endian); } break; case coding_NDS_IMA: for (ch = 0; ch < vgmstream->channels; ch++) { decode_nds_ima(&vgmstream->ch[ch], buffer+ch, vgmstream->channels, vgmstream->samples_into_block, samples_to_do); } break; case coding_DAT4_IMA: for (ch = 0; ch < vgmstream->channels; ch++) { decode_dat4_ima(&vgmstream->ch[ch], buffer+ch, vgmstream->channels, vgmstream->samples_into_block, samples_to_do); } break; case coding_XBOX_IMA: case coding_XBOX_IMA_int: { int is_stereo = (vgmstream->channels > 1 && vgmstream->coding_type == coding_XBOX_IMA); for (ch = 0; ch < vgmstream->channels; ch++) { decode_xbox_ima(&vgmstream->ch[ch], buffer+ch, vgmstream->channels, vgmstream->samples_into_block, samples_to_do, ch, is_stereo); } break; } case coding_XBOX_IMA_mch: for (ch = 0; ch < vgmstream->channels; ch++) { decode_xbox_ima_mch(&vgmstream->ch[ch], buffer+ch, vgmstream->channels, vgmstream->samples_into_block, samples_to_do, ch); } break; case coding_MS_IMA: for (ch = 0; ch < vgmstream->channels; ch++) { decode_ms_ima(vgmstream,&vgmstream->ch[ch], buffer+ch, vgmstream->channels, vgmstream->samples_into_block, samples_to_do, ch); } break; case coding_RAD_IMA: for (ch = 0; ch < vgmstream->channels; ch++) { decode_rad_ima(vgmstream,&vgmstream->ch[ch], buffer+ch, vgmstream->channels, vgmstream->samples_into_block, samples_to_do, ch); } break; case coding_RAD_IMA_mono: for (ch = 0; ch < vgmstream->channels; ch++) { decode_rad_ima_mono(&vgmstream->ch[ch], buffer+ch, vgmstream->channels, vgmstream->samples_into_block, samples_to_do); } break; case coding_NGC_DTK: for (ch = 0; ch < vgmstream->channels; ch++) { decode_ngc_dtk(&vgmstream->ch[ch], buffer+ch, vgmstream->channels, vgmstream->samples_into_block, samples_to_do, ch); } break; case coding_G721: for (ch = 0; ch < vgmstream->channels; ch++) { decode_g721(&vgmstream->ch[ch], buffer+ch, vgmstream->channels, vgmstream->samples_into_block, samples_to_do); } break; case coding_NGC_AFC: for (ch = 0; ch < vgmstream->channels; ch++) { decode_ngc_afc(&vgmstream->ch[ch], buffer+ch, vgmstream->channels, vgmstream->samples_into_block, samples_to_do); } break; case coding_VADPCM: { int order = vgmstream->codec_config; for (ch = 0; ch < vgmstream->channels; ch++) { decode_vadpcm(&vgmstream->ch[ch], buffer+ch, vgmstream->channels, vgmstream->samples_into_block, samples_to_do, order); } break; } case coding_PSX: for (ch = 0; ch < vgmstream->channels; ch++) { decode_psx(&vgmstream->ch[ch], buffer+ch, vgmstream->channels, vgmstream->samples_into_block, samples_to_do, 0, vgmstream->codec_config); } break; case coding_PSX_badflags: for (ch = 0; ch < vgmstream->channels; ch++) { decode_psx(&vgmstream->ch[ch], buffer+ch, vgmstream->channels, vgmstream->samples_into_block, samples_to_do, 1, vgmstream->codec_config); } break; case coding_PSX_cfg: for (ch = 0; ch < vgmstream->channels; ch++) { decode_psx_configurable(&vgmstream->ch[ch], buffer+ch, vgmstream->channels, vgmstream->samples_into_block, samples_to_do, vgmstream->interleave_block_size, vgmstream->codec_config); } break; case coding_PSX_pivotal: for (ch = 0; ch < vgmstream->channels; ch++) { decode_psx_pivotal(&vgmstream->ch[ch], buffer+ch, vgmstream->channels, vgmstream->samples_into_block, samples_to_do, vgmstream->interleave_block_size); } break; case coding_HEVAG: for (ch = 0; ch < vgmstream->channels; ch++) { decode_hevag(&vgmstream->ch[ch], buffer+ch, vgmstream->channels, vgmstream->samples_into_block, samples_to_do); } break; case coding_XA: for (ch = 0; ch < vgmstream->channels; ch++) { decode_xa(&vgmstream->ch[ch], buffer+ch, vgmstream->channels, vgmstream->samples_into_block, samples_to_do, ch); } break; case coding_EA_XA: case coding_EA_XA_int: { int is_stereo = (vgmstream->channels > 1 && vgmstream->coding_type == coding_EA_XA); for (ch = 0; ch < vgmstream->channels; ch++) { decode_ea_xa(&vgmstream->ch[ch], buffer+ch, vgmstream->channels, vgmstream->samples_into_block, samples_to_do, ch, is_stereo); } break; } case coding_EA_XA_V2: for (ch = 0; ch < vgmstream->channels; ch++) { decode_ea_xa_v2(&vgmstream->ch[ch], buffer+ch, vgmstream->channels, vgmstream->samples_into_block, samples_to_do, ch); } break; case coding_MAXIS_XA: for (ch = 0; ch < vgmstream->channels; ch++) { decode_maxis_xa(&vgmstream->ch[ch], buffer+ch, vgmstream->channels, vgmstream->samples_into_block, samples_to_do, ch); } break; case coding_EA_XAS_V0: for (ch = 0; ch < vgmstream->channels; ch++) { decode_ea_xas_v0(&vgmstream->ch[ch], buffer+ch, vgmstream->channels, vgmstream->samples_into_block, samples_to_do, ch); } break; case coding_EA_XAS_V1: for (ch = 0; ch < vgmstream->channels; ch++) { decode_ea_xas_v1(&vgmstream->ch[ch], buffer+ch, vgmstream->channels, vgmstream->samples_into_block, samples_to_do, ch); } break; #ifdef VGM_USE_VORBIS case coding_OGG_VORBIS: decode_ogg_vorbis(vgmstream->codec_data, buffer, samples_to_do, vgmstream->channels); break; case coding_VORBIS_custom: decode_vorbis_custom(vgmstream, buffer, samples_to_do, vgmstream->channels); break; #endif case coding_CIRCUS_VQ: decode_circus_vq(vgmstream->codec_data, buffer, samples_to_do, vgmstream->channels); break; case coding_RELIC: decode_relic(&vgmstream->ch[0], vgmstream->codec_data, buffer, samples_to_do); break; case coding_CRI_HCA: decode_hca(vgmstream->codec_data, buffer, samples_to_do); break; case coding_TAC: decode_tac(vgmstream, buffer, samples_to_do); break; #ifdef VGM_USE_FFMPEG case coding_FFmpeg: decode_ffmpeg(vgmstream, buffer, samples_to_do, vgmstream->channels); break; #endif #if defined(VGM_USE_MP4V2) && defined(VGM_USE_FDKAAC) case coding_MP4_AAC: decode_mp4_aac(vgmstream->codec_data, buffer, samples_to_do, vgmstream->channels); break; #endif case coding_SDX2: for (ch = 0; ch < vgmstream->channels; ch++) { decode_sdx2(&vgmstream->ch[ch], buffer+ch, vgmstream->channels, vgmstream->samples_into_block, samples_to_do); } break; case coding_SDX2_int: for (ch = 0; ch < vgmstream->channels; ch++) { decode_sdx2_int(&vgmstream->ch[ch], buffer+ch, vgmstream->channels, vgmstream->samples_into_block, samples_to_do); } break; case coding_CBD2: for (ch = 0; ch < vgmstream->channels; ch++) { decode_cbd2(&vgmstream->ch[ch], buffer+ch, vgmstream->channels, vgmstream->samples_into_block, samples_to_do); } break; case coding_CBD2_int: for (ch = 0; ch < vgmstream->channels; ch++) { decode_cbd2_int(&vgmstream->ch[ch], buffer+ch, vgmstream->channels, vgmstream->samples_into_block, samples_to_do); } break; case coding_DERF: for (ch = 0; ch < vgmstream->channels; ch++) { decode_derf(&vgmstream->ch[ch], buffer+ch, vgmstream->channels, vgmstream->samples_into_block, samples_to_do); } break; case coding_WADY: for (ch = 0; ch < vgmstream->channels; ch++) { decode_wady(&vgmstream->ch[ch], buffer+ch, vgmstream->channels, vgmstream->samples_into_block, samples_to_do); } break; case coding_CIRCUS_ADPCM: for (ch = 0; ch < vgmstream->channels; ch++) { decode_circus_adpcm(&vgmstream->ch[ch], buffer+ch, vgmstream->channels, vgmstream->samples_into_block, samples_to_do); } break; case coding_IMA: case coding_IMA_int: case coding_DVI_IMA: case coding_DVI_IMA_int: { int is_stereo = (vgmstream->channels > 1 && vgmstream->coding_type == coding_IMA) || (vgmstream->channels > 1 && vgmstream->coding_type == coding_DVI_IMA); int is_high_first = vgmstream->coding_type == coding_DVI_IMA || vgmstream->coding_type == coding_DVI_IMA_int; for (ch = 0; ch < vgmstream->channels; ch++) { decode_standard_ima(&vgmstream->ch[ch], buffer+ch, vgmstream->channels, vgmstream->samples_into_block, samples_to_do, ch, is_stereo, is_high_first); } break; } case coding_MTF_IMA: { int is_stereo = (vgmstream->channels > 1); for (ch = 0; ch < vgmstream->channels; ch++) { decode_mtf_ima(&vgmstream->ch[ch], buffer+ch, vgmstream->channels, vgmstream->samples_into_block, samples_to_do, ch, is_stereo); } break; } case coding_3DS_IMA: for (ch = 0; ch < vgmstream->channels; ch++) { decode_3ds_ima(&vgmstream->ch[ch], buffer+ch, vgmstream->channels, vgmstream->samples_into_block, samples_to_do); } break; case coding_WV6_IMA: for (ch = 0; ch < vgmstream->channels; ch++) { decode_wv6_ima(&vgmstream->ch[ch], buffer+ch, vgmstream->channels, vgmstream->samples_into_block, samples_to_do); } break; case coding_ALP_IMA: for (ch = 0; ch < vgmstream->channels; ch++) { decode_alp_ima(&vgmstream->ch[ch], buffer+ch, vgmstream->channels, vgmstream->samples_into_block, samples_to_do); } break; case coding_FFTA2_IMA: for (ch = 0; ch < vgmstream->channels; ch++) { decode_ffta2_ima(&vgmstream->ch[ch], buffer+ch, vgmstream->channels, vgmstream->samples_into_block, samples_to_do); } break; case coding_BLITZ_IMA: for (ch = 0; ch < vgmstream->channels; ch++) { decode_blitz_ima(&vgmstream->ch[ch], buffer+ch, vgmstream->channels, vgmstream->samples_into_block, samples_to_do); } break; case coding_APPLE_IMA4: for (ch = 0; ch < vgmstream->channels; ch++) { decode_apple_ima4(&vgmstream->ch[ch], buffer+ch, vgmstream->channels, vgmstream->samples_into_block, samples_to_do); } break; case coding_SNDS_IMA: for (ch = 0; ch < vgmstream->channels; ch++) { decode_snds_ima(&vgmstream->ch[ch], buffer+ch, vgmstream->channels, vgmstream->samples_into_block, samples_to_do, ch); } break; case coding_OTNS_IMA: for (ch = 0; ch < vgmstream->channels; ch++) { decode_otns_ima(vgmstream, &vgmstream->ch[ch], buffer+ch, vgmstream->channels, vgmstream->samples_into_block, samples_to_do, ch); } break; case coding_FSB_IMA: for (ch = 0; ch < vgmstream->channels; ch++) { decode_fsb_ima(vgmstream, &vgmstream->ch[ch], buffer+ch, vgmstream->channels, vgmstream->samples_into_block, samples_to_do, ch); } break; case coding_WWISE_IMA: for (ch = 0; ch < vgmstream->channels; ch++) { decode_wwise_ima(vgmstream,&vgmstream->ch[ch], buffer+ch, vgmstream->channels, vgmstream->samples_into_block, samples_to_do, ch); } break; case coding_REF_IMA: for (ch = 0; ch < vgmstream->channels; ch++) { decode_ref_ima(vgmstream,&vgmstream->ch[ch], buffer+ch, vgmstream->channels, vgmstream->samples_into_block, samples_to_do, ch); } break; case coding_AWC_IMA: for (ch = 0; ch < vgmstream->channels; ch++) { decode_awc_ima(&vgmstream->ch[ch], buffer+ch, vgmstream->channels, vgmstream->samples_into_block, samples_to_do); } break; case coding_UBI_IMA: for (ch = 0; ch < vgmstream->channels; ch++) { decode_ubi_ima(&vgmstream->ch[ch], buffer+ch, vgmstream->channels, vgmstream->samples_into_block, samples_to_do, ch); } break; case coding_UBI_SCE_IMA: for (ch = 0; ch < vgmstream->channels; ch++) { decode_ubi_sce_ima(&vgmstream->ch[ch], buffer+ch, vgmstream->channels, vgmstream->samples_into_block, samples_to_do, ch); } break; case coding_H4M_IMA: for (ch = 0; ch < vgmstream->channels; ch++) { uint16_t frame_format = (uint16_t)((vgmstream->codec_config >> 8) & 0xFFFF); decode_h4m_ima(&vgmstream->ch[ch], buffer+ch, vgmstream->channels, vgmstream->samples_into_block, samples_to_do, ch, frame_format); } break; case coding_CD_IMA: for (ch = 0; ch < vgmstream->channels; ch++) { decode_cd_ima(&vgmstream->ch[ch], buffer+ch, vgmstream->channels, vgmstream->samples_into_block, samples_to_do, ch); } break; case coding_WS: for (ch = 0; ch < vgmstream->channels; ch++) { decode_ws(vgmstream, ch, buffer+ch, vgmstream->channels, vgmstream->samples_into_block, samples_to_do); } break; #ifdef VGM_USE_MPEG case coding_MPEG_custom: case coding_MPEG_ealayer3: case coding_MPEG_layer1: case coding_MPEG_layer2: case coding_MPEG_layer3: decode_mpeg(vgmstream, buffer, samples_to_do, vgmstream->channels); break; #endif #ifdef VGM_USE_G7221 case coding_G7221C: for (ch = 0; ch < vgmstream->channels; ch++) { decode_g7221(vgmstream, buffer+ch, vgmstream->channels, samples_to_do, ch); } break; #endif #ifdef VGM_USE_G719 case coding_G719: for (ch = 0; ch < vgmstream->channels; ch++) { decode_g719(vgmstream, buffer+ch, vgmstream->channels, samples_to_do, ch); } break; #endif #ifdef VGM_USE_MAIATRAC3PLUS case coding_AT3plus: for (ch = 0; ch < vgmstream->channels; ch++) { decode_at3plus(vgmstream, buffer+ch, vgmstream->channels, samples_to_do, ch); } break; #endif #ifdef VGM_USE_ATRAC9 case coding_ATRAC9: decode_atrac9(vgmstream, buffer, samples_to_do, vgmstream->channels); break; #endif #ifdef VGM_USE_CELT case coding_CELT_FSB: decode_celt_fsb(vgmstream, buffer, samples_to_do, vgmstream->channels); break; #endif #ifdef VGM_USE_SPEEX case coding_SPEEX: decode_speex(vgmstream, buffer, samples_to_do); break; #endif case coding_ACM: decode_acm(vgmstream->codec_data, buffer, samples_to_do, vgmstream->channels); break; case coding_NWA: decode_nwa(vgmstream->codec_data, buffer, samples_to_do); break; case coding_MSADPCM: case coding_MSADPCM_int: if (vgmstream->channels == 1 || vgmstream->coding_type == coding_MSADPCM_int) { for (ch = 0; ch < vgmstream->channels; ch++) { decode_msadpcm_mono(vgmstream,buffer+ch, vgmstream->channels,vgmstream->samples_into_block, samples_to_do, ch); } } else if (vgmstream->channels == 2) { decode_msadpcm_stereo(vgmstream, buffer, vgmstream->samples_into_block,samples_to_do); } break; case coding_MSADPCM_ck: for (ch = 0; ch < vgmstream->channels; ch++) { decode_msadpcm_ck(vgmstream, buffer+ch, vgmstream->channels, vgmstream->samples_into_block, samples_to_do, ch); } break; case coding_AICA: case coding_AICA_int: { int is_stereo = (vgmstream->channels > 1 && vgmstream->coding_type == coding_AICA); for (ch = 0; ch < vgmstream->channels; ch++) { decode_aica(&vgmstream->ch[ch], buffer+ch, vgmstream->channels, vgmstream->samples_into_block, samples_to_do, ch, is_stereo); } break; } case coding_ASKA: for (ch = 0; ch < vgmstream->channels; ch++) { decode_aska(&vgmstream->ch[ch], buffer+ch, vgmstream->channels, vgmstream->samples_into_block, samples_to_do, ch, vgmstream->frame_size); } break; case coding_NXAP: for (ch = 0; ch < vgmstream->channels; ch++) { decode_nxap(&vgmstream->ch[ch], buffer+ch, vgmstream->channels, vgmstream->samples_into_block, samples_to_do); } break; case coding_TGC: for (ch = 0; ch < vgmstream->channels; ch++) { decode_tgc(&vgmstream->ch[ch], buffer+ch, vgmstream->samples_into_block, samples_to_do); } break; case coding_NDS_PROCYON: for (ch = 0; ch < vgmstream->channels; ch++) { decode_nds_procyon(&vgmstream->ch[ch], buffer+ch, vgmstream->channels, vgmstream->samples_into_block, samples_to_do); } break; case coding_L5_555: for (ch = 0; ch < vgmstream->channels; ch++) { decode_l5_555(&vgmstream->ch[ch], buffer+ch, vgmstream->channels, vgmstream->samples_into_block, samples_to_do); } break; case coding_SASSC: for (ch = 0; ch < vgmstream->channels; ch++) { decode_sassc(&vgmstream->ch[ch], buffer+ch, vgmstream->channels, vgmstream->samples_into_block, samples_to_do); } break; case coding_LSF: for (ch = 0; ch < vgmstream->channels; ch++) { decode_lsf(&vgmstream->ch[ch], buffer+ch, vgmstream->channels, vgmstream->samples_into_block, samples_to_do); } break; case coding_MTAF: for (ch = 0; ch < vgmstream->channels; ch++) { decode_mtaf(&vgmstream->ch[ch], buffer+ch, vgmstream->channels, vgmstream->samples_into_block, samples_to_do, ch); } break; case coding_MTA2: for (ch = 0; ch < vgmstream->channels; ch++) { decode_mta2(&vgmstream->ch[ch], buffer+ch, vgmstream->channels, vgmstream->samples_into_block, samples_to_do, ch); } break; case coding_MC3: for (ch = 0; ch < vgmstream->channels; ch++) { decode_mc3(vgmstream, &vgmstream->ch[ch], buffer+ch, vgmstream->channels, vgmstream->samples_into_block, samples_to_do, ch); } break; case coding_FADPCM: for (ch = 0; ch < vgmstream->channels; ch++) { decode_fadpcm(&vgmstream->ch[ch], buffer+ch, vgmstream->channels,vgmstream->samples_into_block, samples_to_do); } break; case coding_ASF: for (ch = 0; ch < vgmstream->channels; ch++) { decode_asf(&vgmstream->ch[ch], buffer+ch, vgmstream->channels, vgmstream->samples_into_block, samples_to_do); } break; case coding_DSA: for (ch = 0; ch < vgmstream->channels; ch++) { decode_dsa(&vgmstream->ch[ch], buffer+ch, vgmstream->channels, vgmstream->samples_into_block, samples_to_do); } break; case coding_XMD: for (ch = 0; ch < vgmstream->channels; ch++) { decode_xmd(&vgmstream->ch[ch], buffer+ch, vgmstream->channels, vgmstream->samples_into_block, samples_to_do, vgmstream->interleave_block_size); } break; case coding_PTADPCM: for (ch = 0; ch < vgmstream->channels; ch++) { decode_ptadpcm(&vgmstream->ch[ch], buffer+ch, vgmstream->channels, vgmstream->samples_into_block, samples_to_do, vgmstream->interleave_block_size); } break; case coding_PCFX: for (ch = 0; ch < vgmstream->channels; ch++) { decode_pcfx(&vgmstream->ch[ch], buffer+ch, vgmstream->channels, vgmstream->samples_into_block, samples_to_do, vgmstream->codec_config); } break; case coding_OKI16: for (ch = 0; ch < vgmstream->channels; ch++) { decode_oki16(&vgmstream->ch[ch], buffer+ch, vgmstream->channels, vgmstream->samples_into_block, samples_to_do, ch); } break; case coding_OKI4S: for (ch = 0; ch < vgmstream->channels; ch++) { decode_oki4s(&vgmstream->ch[ch], buffer+ch, vgmstream->channels, vgmstream->samples_into_block, samples_to_do, ch); } break; case coding_UBI_ADPCM: decode_ubi_adpcm(vgmstream, buffer, samples_to_do); break; case coding_IMUSE: decode_imuse(vgmstream, buffer, samples_to_do); break; case coding_COMPRESSWAVE: decode_compresswave(vgmstream->codec_data, buffer, samples_to_do); break; case coding_EA_MT: for (ch = 0; ch < vgmstream->channels; ch++) { decode_ea_mt(vgmstream, buffer+ch, vgmstream->channels, samples_to_do, ch); } break; default: break; } } /* Calculate number of consecutive samples we can decode. Takes into account hitting * a loop start or end, or going past a single frame. */ int get_vgmstream_samples_to_do(int samples_this_block, int samples_per_frame, VGMSTREAM* vgmstream) { int samples_to_do; int samples_left_this_block; samples_left_this_block = samples_this_block - vgmstream->samples_into_block; samples_to_do = samples_left_this_block; /* by default decodes all samples left */ /* fun loopy crap, why did I think this would be any simpler? */ if (vgmstream->loop_flag) { int samples_after_decode = vgmstream->current_sample + samples_left_this_block; /* are we going to hit the loop end during this block? */ if (samples_after_decode > vgmstream->loop_end_sample) { /* only do samples up to loop end */ samples_to_do = vgmstream->loop_end_sample - vgmstream->current_sample; } /* are we going to hit the loop start during this block? (first time only) */ if (samples_after_decode > vgmstream->loop_start_sample && !vgmstream->hit_loop) { /* only do samples up to loop start */ samples_to_do = vgmstream->loop_start_sample - vgmstream->current_sample; } } /* if it's a framed encoding don't do more than one frame */ if (samples_per_frame > 1 && (vgmstream->samples_into_block % samples_per_frame) + samples_to_do > samples_per_frame) samples_to_do = samples_per_frame - (vgmstream->samples_into_block % samples_per_frame); return samples_to_do; } /* Detect loop start and save values, or detect loop end and restore (loop back). * Returns 1 if loop was done. */ int vgmstream_do_loop(VGMSTREAM* vgmstream) { /*if (!vgmstream->loop_flag) return 0;*/ /* is this the loop end? = new loop, continue from loop_start_sample */ if (vgmstream->current_sample == vgmstream->loop_end_sample) { /* disable looping if target count reached and continue normally * (only needed with the "play stream end after looping N times" option enabled) */ vgmstream->loop_count++; if (vgmstream->loop_target && vgmstream->loop_target == vgmstream->loop_count) { vgmstream->loop_flag = 0; /* could be improved but works ok, will be restored on resets */ return 0; } /* against everything I hold sacred, preserve adpcm history before looping for certain types */ if (vgmstream->meta_type == meta_DSP_STD || vgmstream->meta_type == meta_DSP_RS03 || vgmstream->meta_type == meta_DSP_CSTR || vgmstream->coding_type == coding_PSX || vgmstream->coding_type == coding_PSX_badflags) { int ch; for (ch = 0; ch < vgmstream->channels; ch++) { vgmstream->loop_ch[ch].adpcm_history1_16 = vgmstream->ch[ch].adpcm_history1_16; vgmstream->loop_ch[ch].adpcm_history2_16 = vgmstream->ch[ch].adpcm_history2_16; vgmstream->loop_ch[ch].adpcm_history1_32 = vgmstream->ch[ch].adpcm_history1_32; vgmstream->loop_ch[ch].adpcm_history2_32 = vgmstream->ch[ch].adpcm_history2_32; } } /* loop codecs */ seek_codec(vgmstream); /* restore! */ memcpy(vgmstream->ch, vgmstream->loop_ch, sizeof(VGMSTREAMCHANNEL) * vgmstream->channels); vgmstream->current_sample = vgmstream->loop_current_sample; vgmstream->samples_into_block = vgmstream->loop_samples_into_block; vgmstream->current_block_size = vgmstream->loop_block_size; vgmstream->current_block_samples = vgmstream->loop_block_samples; vgmstream->current_block_offset = vgmstream->loop_block_offset; vgmstream->next_block_offset = vgmstream->loop_next_block_offset; //vgmstream->pstate = vgmstream->lstate; /* play state is applied over loops */ /* loop layouts (after restore, in case layout needs state manipulations) */ switch(vgmstream->layout_type) { case layout_segmented: loop_layout_segmented(vgmstream, vgmstream->loop_current_sample); break; case layout_layered: loop_layout_layered(vgmstream, vgmstream->loop_current_sample); break; default: break; } return 1; /* looped */ } /* is this the loop start? save if we haven't saved yet (right when first loop starts) */ if (!vgmstream->hit_loop && vgmstream->current_sample == vgmstream->loop_start_sample) { /* save! */ memcpy(vgmstream->loop_ch, vgmstream->ch, sizeof(VGMSTREAMCHANNEL)*vgmstream->channels); vgmstream->loop_current_sample = vgmstream->current_sample; vgmstream->loop_samples_into_block = vgmstream->samples_into_block; vgmstream->loop_block_size = vgmstream->current_block_size; vgmstream->loop_block_samples = vgmstream->current_block_samples; vgmstream->loop_block_offset = vgmstream->current_block_offset; vgmstream->loop_next_block_offset = vgmstream->next_block_offset; //vgmstream->lstate = vgmstream->pstate; /* play state is applied over loops */ vgmstream->hit_loop = 1; /* info that loop is now ready to use */ } return 0; /* not looped */ }