Merge pull request #1571 from bnnm/api-misc6

- Add HCA keys
- Fix some custom/buggy .dsp
- foobar: tweak file info
- cleanup
This commit is contained in:
bnnm 2024-08-11 02:04:01 +02:00 committed by GitHub
commit 7ab622d335
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
94 changed files with 1993 additions and 1899 deletions

View File

@ -52,6 +52,7 @@ FILES_SKIP = [
'txth.c','txtp.c','genh.c',
'silence.c', 'mp4_faac.c', 'deblock_streamfile.c',
'ps_headerless.c', 'zwdsp.c',
'txtp_parser.c', 'txtp_process.c',
]
EXT_RENAMES = {'...': '(any)', '': '(extensionless)'}

11
.gitignore vendored
View File

@ -46,8 +46,8 @@ ipch
# build
/version_auto.h
/dependencies
/bin/**/*
/tmp/**/*
/bin
/tmp
/**/vgmstream-win.zip
/**/foo_input_vgmstream.fb2k-component
@ -64,10 +64,7 @@ CMakeFiles
/audacious/Makefile
cmake_install.cmake
#doc build
doc/INFO.md
doc/_build
# doc stuff
changelog.txt
formats-info.md
__pycache__
__pycache__

View File

@ -6,6 +6,12 @@
<ImportGroup Label="PropertySheets" />
<!-- size mismatch warnings, should rework stuff rather than castings all the time
(plus compilers can't detect code that logically can't lose precision, such as a clamped values) -->
<PropertyGroup>
<NoWarn>C4267;C4244</NoWarn>
</PropertyGroup>
<PropertyGroup Label="Configuration">
<PlatformToolset>v143</PlatformToolset>
</PropertyGroup>

View File

@ -26,7 +26,7 @@ static FILE* get_output_file(const char* filename) {
}
static libvgmstream_streamfile_t* get_streamfile(const char* filename) {
return libvgmstream_streamfile_from_filename(filename);
return libvgmstream_streamfile_open_from_stdio(filename);
}
static int api_example(const char* infile) {
@ -204,10 +204,10 @@ static libvgmstream_streamfile_t* test_libsf_open() {
libvgmstream_streamfile_t* libsf = NULL;
libsf = libvgmstream_streamfile_from_filename("api.bin_wrong");
libsf = libvgmstream_streamfile_open_from_stdio("api.bin_wrong");
assert(libsf == NULL);
libsf = libvgmstream_streamfile_from_filename("api.bin");
libsf = libvgmstream_streamfile_open_from_stdio("api.bin");
assert(libsf != NULL);
return libsf;
@ -335,7 +335,7 @@ static void test_lib_tags() {
libvgmstream_tags_t* tags = NULL;
bool more = false;
libsf = libvgmstream_streamfile_from_filename("sample_!tags.m3u");
libsf = libvgmstream_streamfile_open_from_stdio("sample_!tags.m3u");
assert(libsf != NULL);
tags = libvgmstream_tags_init(libsf);

View File

@ -342,7 +342,7 @@ static int play_vgmstream(const char* filename, song_settings_t* cfg) {
if (!buffer) goto fail;
}
max_buffer_samples = buffer_size / (input_channels * sizeof(sample));
max_buffer_samples = buffer_size / (input_channels * sizeof(sample_t));
vgmstream_mixing_enable(vgmstream, max_buffer_samples, NULL, NULL); /* enable */
@ -423,7 +423,7 @@ static int play_vgmstream(const char* filename, song_settings_t* cfg) {
fflush(stdout);
}
if (!ao_play(device, (char *)buffer, to_do * output_channels * sizeof(sample))) {
if (!ao_play(device, (char *)buffer, to_do * output_channels * sizeof(sample_t))) {
fputs("\nAudio playback error\n", stderr);
ao_close(device);
device = NULL;

View File

@ -272,7 +272,7 @@ different internally (encrypted, different versions, etc) and not always can be
- RIFX WAVE header (smpl looping) [*RIFX_WAVE_smpl*]
- *riff*: `.wav .lwav .xwav .mwv .da .dax .cd .med .snd .adx .adp .xss .xsew .adpcm .adw .wd .(extensionless) .sbv .wvx .str .at3 .rws .aud .at9 .ckd .saf .ima .nsa .pcm .xvag .ogg .logg .p1d .xms .mus .dat .ldat .wma .lwma .caf .wax .voi .se`
- *rifx*: `.wav .lwav`
- Codecs: AICA_int PCM32LE PCM24LE PCM16BE PCM16LE PCM8_U MSADPCM IMA PCMFLOAT MS_IMA AICA MPEG_custom XBOX_IMA MS_IMA_3BIT DVI_IMA L5_555 OGG_VORBIS ATRAC9 ATRAC3 MPEG MSADPCM_mono
- Codecs: AICA_int PCM32LE PCM24LE PCM16BE PCM16LE PCM8_U MSADPCM IMA PCMFLOAT MS_IMA AICA MPEG_custom XBOX_IMA MS_IMA_3BIT DVI_IMA LEVEL5 OGG_VORBIS ATRAC9 ATRAC3 MPEG MSADPCM_mono
- **nwa.c**
- VisualArt's NWA header (NWAINFO.INI looping) [*NWA_NWAINFOINI*]
- VisualArt's NWA header (Gameexe.ini looping) [*NWA_GAMEEXEINI*]
@ -389,10 +389,6 @@ different internally (encrypted, different versions, etc) and not always can be
- Square Enix .vsv Header [*VSV*]
- *vsv*: `.vsv .psh`
- Codecs: PSX
- **ps2_pcm.c**
- Konami .PCM header [*PS2_PCM*]
- *ps2_pcm*: `.pcm`
- Codecs: PCM16LE
- **rkv.c**
- Legacy of Kain - Blood Omen 2 RKV PS2 header [*PS2_RKV*]
- Legacy of Kain - Blood Omen 2 RKV GC header [*NGC_RKV*]
@ -503,8 +499,8 @@ different internally (encrypted, different versions, etc) and not always can be
- Subfiles: *ogg_vorbis_config*
- Codecs: PCM16LE PCM16BE PSX XBOX_IMA_mch XBOX_IMA NGC_DSP NGC_DSP_subint RAD_IMA OGG FFmpeg(various) ATRAC3 XMA
- **bgw.c**
- Square Enix .BGW header [*FFXI_BGW*]
- Square Enix .SPW header [*FFXI_SPW*]
- Square Enix BGMStream header [*BGW*]
- Square Enix SeWave header [*SPW*]
- *bgw*: `.bgw`
- *spw*: `.spw`
- Codecs: PSX_cfg ATRAC3 PCM16LE
@ -676,9 +672,9 @@ different internally (encrypted, different versions, etc) and not always can be
- beatmania IIDX 2DX9 header [*2DX9*]
- *2dx9*: `.2dx9`
- Codecs: MSADPCM
- **ngc_dsp_ygo.c**
- Konami custom DSP Header [*DSP_YGO*]
- *dsp_ygo*: `.dsp`
- **dsp_kceje.c**
- Konami .DSP Header [*DSP_KCEJE*]
- *dsp_kceje*: `.dsp`
- Codecs: NGC_DSP
- **ps2_vgv.c**
- Rune: Viking Warlord VGV Header [*PS2_VGV*]
@ -894,7 +890,7 @@ different internally (encrypted, different versions, etc) and not always can be
- *alp*: `.tun .pcm`
- Codecs: HV_IMA
- **wpd.c**
- WPD 'DPW' header [*WPD*]
- Navel WPD header [*WPD*]
- *wpd*: `.wpd`
- Codecs: PCM16LE
- **mn_str.c**
@ -1095,7 +1091,7 @@ different internally (encrypted, different versions, etc) and not always can be
- Rockstar AWC header [*AWC*]
- *awc*: `.awc`
- Subfiles: *riff*
- Codecs: PCM16BE PCM16LE AWC_IMA XMA2 MPEG VORBIS_custom ATRAC9 NGC_DSP
- Codecs: PCM16BE PCM16LE AWC_IMA XMA2 MPEG_custom MPEG VORBIS_custom ATRAC9 NGC_DSP
- **opus.c**
- Nintendo Switch OPUS header [*OPUS*]
- *opus_std*: `.opus .lopus .bgm .opu .ogg .logg + .psi`
@ -1878,6 +1874,10 @@ different internally (encrypted, different versions, etc) and not always can be
- Naxat .ASD header [*ASD_NAXAT*]
- *asd_naxat*: `.asd`
- Codecs: PCM16LE
- **pcm_kceje.c**
- Konami .PCM header [*PCM_KCEJE*]
- *pcm_kceje*: `.pcm`
- Codecs: PCM16LE
- **pos.c**
- RIFF WAVE header (.pos looping) [*RIFF_WAVE_POS*]
- *pos*: `.pos + .wav`
@ -2014,7 +2014,7 @@ are used in few games.
- Konami MTA2 ADPCM
- FMOD FADPCM ADPCM
- Procyon Studio ADPCM
- Level-5 0x555 ADPCM
- Level-5 ADPCM
- Konami XMD ADPCM
- Argonaut ASF ADPCM
- Tantalus ADPCM

View File

@ -1,28 +1,32 @@
#ifndef _FOO_FILETYPES_H_
#define _FOO_FILETYPES_H_
class input_file_type_v2_impl_vgmstream : public input_file_type_v2 {
public:
input_file_type_v2_impl_vgmstream() {
ext_list = vgmstream_get_formats(&ext_list_len);
}
unsigned get_count() { return ext_list_len; }
bool is_associatable(unsigned idx) { return true; }
void get_format_name(unsigned idx, pfc::string_base & out, bool isPlural) {
out.reset();
pfc::stringToUpperAppend(out, ext_list[idx], pfc::strlen_utf8(ext_list[idx]));
out += " Audio File";
if (isPlural) out += "s";
}
void get_extensions(unsigned idx, pfc::string_base & out) {
out = ext_list[idx];
}
private:
const char ** ext_list;
size_t ext_list_len;
};
namespace { static service_factory_single_t<input_file_type_v2_impl_vgmstream> g_filetypes; }
#endif /*_FOO_FILETYPES_H_ */
#ifndef _FOO_FILETYPES_H_
#define _FOO_FILETYPES_H_
class input_file_type_v2_impl_vgmstream : public input_file_type_v2 {
public:
input_file_type_v2_impl_vgmstream() {
ext_list = vgmstream_get_formats(&ext_list_len);
}
unsigned get_count() { return ext_list_len; }
bool is_associatable(unsigned idx) { return true; }
void get_format_name(unsigned idx, pfc::string_base & out, bool isPlural) {
out.reset();
pfc::stringToUpperAppend(out, ext_list[idx], pfc::strlen_utf8(ext_list[idx]));
out += " Audio File";
if (isPlural) out += "s";
}
void get_extensions(unsigned idx, pfc::string_base & out) {
out = ext_list[idx];
}
private:
const char ** ext_list;
size_t ext_list_len;
};
namespace { static service_factory_single_t<input_file_type_v2_impl_vgmstream> g_filetypes; }
#endif /*_FOO_FILETYPES_H_ */

View File

@ -5,10 +5,6 @@
#include <io.h>
#include "foo_prefs.h"
extern "C" {
#include "../src/vgmstream.h"
#include "../src/util.h"
}
#include "foo_vgmstream.h"
@ -27,13 +23,13 @@ static cfg_bool cfg_ExtsCommonOn ({0x405af423,0x5037,0x4eae,{0xa6,0xe3,0x
// Needs to be here in rder to access the static config
void input_vgmstream::load_settings() {
// no verification needed here, as it is done below
sscanf(cfg_FadeLength.get_ptr(),"%lf",&fade_seconds);
sscanf(cfg_LoopCount.get_ptr(),"%lf",&loop_count);
sscanf(cfg_FadeDelay.get_ptr(),"%lf",&fade_delay_seconds);
sscanf(cfg_FadeLength.get_ptr(), "%lf", &fade_seconds);
sscanf(cfg_LoopCount.get_ptr(), "%lf", &loop_count);
sscanf(cfg_FadeDelay.get_ptr(), "%lf", &fade_delay_seconds);
loop_forever = cfg_LoopForever;
ignore_loop = cfg_IgnoreLoop;
disable_subsongs = cfg_DisableSubsongs;
sscanf(cfg_DownmixChannels.get_ptr(),"%d",&downmix_channels);
sscanf(cfg_DownmixChannels.get_ptr(), "%d", &downmix_channels);
tagfile_disable = cfg_TagfileDisable;
override_title = cfg_OverrideTitle;
//exts_unknown_on = cfg_ExtsUnknownOn;
@ -43,13 +39,13 @@ void input_vgmstream::load_settings() {
if (loop_count <= 0)
loop_count = 1;
}
void input_vgmstream::g_load_cfg(int *accept_unknown, int *accept_common) {
//todo improve
*accept_unknown = cfg_ExtsUnknownOn ? 1 : 0;
*accept_common = cfg_ExtsCommonOn ? 1 : 0;
void input_vgmstream::g_load_cfg(int* accept_unknown, int* accept_common) {
//TODO improve
*accept_unknown = cfg_ExtsUnknownOn;
*accept_common = cfg_ExtsCommonOn;
}
const char * vgmstream_prefs::get_name() {
const char* vgmstream_prefs::get_name() {
return input_vgmstream::g_get_name();
}
@ -61,50 +57,55 @@ GUID vgmstream_prefs::get_parent_guid() {
return guid_input;
}
static UINT get_check(bool value) {
return value ? BST_CHECKED : BST_UNCHECKED;
}
BOOL vgmstreamPreferences::OnInitDialog(CWindow, LPARAM) {
CheckDlgButton(IDC_LOOP_FOREVER, cfg_LoopForever?BST_CHECKED:BST_UNCHECKED);
CheckDlgButton(IDC_IGNORE_LOOP, cfg_IgnoreLoop?BST_CHECKED:BST_UNCHECKED);
CheckDlgButton(IDC_LOOP_NORMALLY, (!cfg_IgnoreLoop && !cfg_LoopForever)?BST_CHECKED:BST_UNCHECKED);
CheckDlgButton(IDC_LOOP_FOREVER, get_check(cfg_LoopForever));
CheckDlgButton(IDC_IGNORE_LOOP, get_check(cfg_IgnoreLoop));
CheckDlgButton(IDC_LOOP_NORMALLY, get_check(!cfg_IgnoreLoop && !cfg_LoopForever));
uSetDlgItemText(m_hWnd, IDC_LOOP_COUNT, cfg_LoopCount);
uSetDlgItemText(m_hWnd, IDC_FADE_SECONDS, cfg_FadeLength);
uSetDlgItemText(m_hWnd, IDC_FADE_DELAY_SECONDS, cfg_FadeDelay);
CheckDlgButton(IDC_DISABLE_SUBSONGS, cfg_DisableSubsongs?BST_CHECKED:BST_UNCHECKED);
CheckDlgButton(IDC_DISABLE_SUBSONGS, get_check(cfg_DisableSubsongs));
uSetDlgItemText(m_hWnd, IDC_DOWNMIX_CHANNELS, cfg_DownmixChannels);
CheckDlgButton(IDC_TAGFILE_DISABLE, cfg_TagfileDisable?BST_CHECKED:BST_UNCHECKED);
CheckDlgButton(IDC_OVERRIDE_TITLE, cfg_OverrideTitle?BST_CHECKED:BST_UNCHECKED);
CheckDlgButton(IDC_EXTS_UNKNOWN_ON, cfg_ExtsUnknownOn?BST_CHECKED:BST_UNCHECKED);
CheckDlgButton(IDC_EXTS_COMMON_ON, cfg_ExtsCommonOn?BST_CHECKED:BST_UNCHECKED);
CheckDlgButton(IDC_TAGFILE_DISABLE, get_check(cfg_TagfileDisable));
CheckDlgButton(IDC_OVERRIDE_TITLE, get_check(cfg_OverrideTitle));
CheckDlgButton(IDC_EXTS_UNKNOWN_ON, get_check(cfg_ExtsUnknownOn));
CheckDlgButton(IDC_EXTS_COMMON_ON, get_check(cfg_ExtsCommonOn));
return TRUE;
}
t_uint32 vgmstreamPreferences::get_state() {
t_uint32 state = preferences_state::resettable;
if (HasChanged()) state |= preferences_state::changed;
if (HasChanged())
state |= preferences_state::changed;
return state;
}
void vgmstreamPreferences::reset() {
CheckDlgButton(IDC_LOOP_FOREVER, DEFAULT_LOOP_FOREVER?BST_CHECKED:BST_UNCHECKED);
CheckDlgButton(IDC_IGNORE_LOOP, DEFAULT_IGNORE_LOOP?BST_CHECKED:BST_UNCHECKED);
CheckDlgButton(IDC_LOOP_NORMALLY, (!DEFAULT_IGNORE_LOOP && !DEFAULT_LOOP_FOREVER)?BST_CHECKED:BST_UNCHECKED);
CheckDlgButton(IDC_LOOP_FOREVER, get_check(DEFAULT_LOOP_FOREVER));
CheckDlgButton(IDC_IGNORE_LOOP, get_check(DEFAULT_IGNORE_LOOP));
CheckDlgButton(IDC_LOOP_NORMALLY, get_check(!DEFAULT_IGNORE_LOOP && !DEFAULT_LOOP_FOREVER));
uSetDlgItemText(m_hWnd, IDC_LOOP_COUNT, DEFAULT_LOOP_COUNT);
uSetDlgItemText(m_hWnd, IDC_FADE_SECONDS, DEFAULT_FADE_SECONDS);
uSetDlgItemText(m_hWnd, IDC_FADE_DELAY_SECONDS, DEFAULT_FADE_DELAY_SECONDS);
CheckDlgButton(IDC_DISABLE_SUBSONGS, DEFAULT_DISABLE_SUBSONGS?BST_CHECKED:BST_UNCHECKED);
CheckDlgButton(IDC_DISABLE_SUBSONGS, get_check(DEFAULT_DISABLE_SUBSONGS));
uSetDlgItemText(m_hWnd, IDC_DOWNMIX_CHANNELS, DEFAULT_DOWNMIX_CHANNELS);
CheckDlgButton(IDC_TAGFILE_DISABLE, DEFAULT_TAGFILE_DISABLE?BST_CHECKED:BST_UNCHECKED);
CheckDlgButton(IDC_OVERRIDE_TITLE, DEFAULT_OVERRIDE_TITLE?BST_CHECKED:BST_UNCHECKED);
CheckDlgButton(IDC_EXTS_UNKNOWN_ON, DEFAULT_EXTS_UNKNOWN_ON?BST_CHECKED:BST_UNCHECKED);
CheckDlgButton(IDC_EXTS_COMMON_ON, DEFAULT_EXTS_COMMON_ON?BST_CHECKED:BST_UNCHECKED);
CheckDlgButton(IDC_TAGFILE_DISABLE, get_check(DEFAULT_TAGFILE_DISABLE));
CheckDlgButton(IDC_OVERRIDE_TITLE, get_check(DEFAULT_OVERRIDE_TITLE));
CheckDlgButton(IDC_EXTS_UNKNOWN_ON, get_check(DEFAULT_EXTS_UNKNOWN_ON));
CheckDlgButton(IDC_EXTS_COMMON_ON, get_check(DEFAULT_EXTS_COMMON_ON));
}
@ -125,9 +126,8 @@ void vgmstreamPreferences::apply() {
pfc::string buf;
buf = uGetDlgItemText(m_hWnd, IDC_FADE_SECONDS);
if (sscanf(buf.get_ptr(),"%lf%n",&temp_fade_seconds,&consumed)<1
|| consumed!=strlen(buf.get_ptr()) ||
temp_fade_seconds<0) {
if (sscanf(buf.get_ptr(), "%lf%n", &temp_fade_seconds, &consumed) < 1
|| consumed != strlen(buf.get_ptr()) || temp_fade_seconds < 0) {
uMessageBox(m_hWnd,
"Invalid value for Fade Length\n"
"Must be a number greater than or equal to zero",
@ -136,9 +136,8 @@ void vgmstreamPreferences::apply() {
} else cfg_FadeLength = buf.get_ptr();
buf = uGetDlgItemText(m_hWnd, IDC_LOOP_COUNT);
if (sscanf(buf.get_ptr(),"%lf%n",&temp_loop_count,&consumed)<1
|| consumed!=strlen(buf.get_ptr()) ||
temp_loop_count<0) {
if (sscanf(buf.get_ptr(), "%lf%n", &temp_loop_count, &consumed) < 1
|| consumed != strlen(buf.get_ptr()) || temp_loop_count < 0) {
uMessageBox(m_hWnd,
"Invalid value for Loop Count\n"
"Must be a number greater than or equal to zero",
@ -147,24 +146,22 @@ void vgmstreamPreferences::apply() {
} else cfg_LoopCount = buf.get_ptr();
buf = uGetDlgItemText(m_hWnd, IDC_FADE_DELAY_SECONDS);
if (sscanf(buf.get_ptr(),"%lf%n",&temp_fade_delay_seconds,&consumed)<1
|| consumed!=strlen(buf.get_ptr()) ||
temp_fade_delay_seconds<0) {
if (sscanf(buf.get_ptr(), "%lf%n", &temp_fade_delay_seconds, &consumed) < 1
|| consumed != strlen(buf.get_ptr()) || temp_fade_delay_seconds < 0) {
uMessageBox(m_hWnd,
"Invalid value for Fade Delay\n"
"Must be a number",
"Error",MB_OK|MB_ICONERROR);
"Error", MB_OK|MB_ICONERROR);
return;
} else cfg_FadeDelay = buf.get_ptr();
buf = uGetDlgItemText(m_hWnd, IDC_DOWNMIX_CHANNELS);
if (sscanf(buf.get_ptr(),"%d%n",&temp_downmix_channels,&consumed)<1
|| consumed!=strlen(buf.get_ptr()) ||
temp_downmix_channels<0) {
if (sscanf(buf.get_ptr(), "%d%n", &temp_downmix_channels, &consumed) < 1
|| consumed != strlen(buf.get_ptr()) || temp_downmix_channels < 0) {
uMessageBox(m_hWnd,
"Invalid value for Downmix Channels\n"
"Must be a number greater than or equal to zero",
"Error",MB_OK|MB_ICONERROR);
"Error", MB_OK|MB_ICONERROR);
return;
} else cfg_DownmixChannels = buf.get_ptr();

View File

@ -115,12 +115,15 @@ static size_t foo_read(FOO_STREAMFILE* sf, uint8_t* dst, offv_t offset, size_t l
sf->offset = offset; /* last fread offset */
return read_total;
}
static size_t foo_get_size(FOO_STREAMFILE* sf) {
return sf->file_size;
}
static offv_t foo_get_offset(FOO_STREAMFILE* sf) {
return sf->offset;
}
static void foo_get_name(FOO_STREAMFILE* sf, char* name, size_t name_size) {
int copy_size = sf->name_len + 1;
if (copy_size > name_size)
@ -138,6 +141,7 @@ static void foo_get_name(FOO_STREAMFILE* sf, char* name, size_t name_size) {
}
*/
}
static void foo_close(FOO_STREAMFILE* sf) {
sf->m_file.release(); //release alloc'ed ptr
free(sf->name);
@ -247,11 +251,11 @@ static STREAMFILE* open_foo_streamfile_buffer_by_file(service_ptr_t<file> m_file
if (strncmp(filename, "unpack", 6) == 0) {
const char* archfile_ptr = strrchr(this_sf->name, '|');
if (archfile_ptr)
this_sf->archfile_end = (intptr_t)archfile_ptr + 1 - (intptr_t)this_sf->name; // after "|""
this_sf->archfile_end = (int)((intptr_t)archfile_ptr + 1 - (intptr_t)this_sf->name); // after "|""
const char* archpath_ptr = strrchr(this_sf->name, '\\');
if (archpath_ptr)
this_sf->archpath_end = (intptr_t)archpath_ptr + 1 - (intptr_t)this_sf->name; // after "\\"
this_sf->archpath_end = (int)((intptr_t)archpath_ptr + 1 - (intptr_t)this_sf->name); // after "\\"
if (this_sf->archpath_end <= 0 || this_sf->archfile_end <= 0 || this_sf->archpath_end > this_sf->archfile_end ||
this_sf->archfile_end > this_sf->name_len || this_sf->archfile_end >= PATH_LIMIT) {

View File

@ -59,7 +59,7 @@ input_vgmstream::input_vgmstream() {
fade_delay_seconds = 0.0;
loop_count = 2.0;
loop_forever = false;
ignore_loop = 0;
ignore_loop = false;
disable_subsongs = false;
downmix_channels = 0;
tagfile_disable = false;
@ -80,53 +80,48 @@ input_vgmstream::~input_vgmstream() {
// called first when a new file is accepted, before playing it
void input_vgmstream::open(service_ptr_t<file> p_filehint, const char * p_path, t_input_open_reason p_reason, abort_callback & p_abort) {
if (!p_path) { // shouldn't be possible
if (!p_path) // shouldn't be possible
throw exception_io_data();
return; //???
}
filename = p_path;
// allow non-existing files in some cases
bool infile_virtual = !filesystem::g_exists(p_path, p_abort)
&& vgmstream_is_virtual_filename(filename) == 1;
bool infile_virtual = !filesystem::g_exists(p_path, p_abort) && vgmstream_is_virtual_filename(filename);
// don't try to open virtual files as it'll fail
// (doesn't seem to have any adverse effect, except maybe no stats)
// setup_vgmstream also makes further checks before file is finally opened
if (!infile_virtual) {
// keep file stats around (timestamp, filesize)
if ( p_filehint.is_empty() )
if ( p_filehint.is_empty() ) {
input_open_file_helper( p_filehint, filename, p_reason, p_abort );
}
stats = p_filehint->get_stats( p_abort );
uint32_t flags = stats2_legacy; //foobar2000_io.stats2_xxx, not sure about the implications
uint32_t flags = stats2_legacy; //foobar2000_io.stats2_xxx, not sure about implications
stats2 = p_filehint->get_stats2_(flags, p_abort); // ???
}
switch(p_reason) {
case input_open_decode: // prepare to retrieve info and decode
case input_open_info_read: // prepare to retrieve info
setup_vgmstream(p_abort); // must init vgmstream to get subsongs
case input_open_decode: // prepare to retrieve info and decode
case input_open_info_read: // prepare to retrieve info
// init vgmstream to get subsongs
setup_vgmstream(p_abort);
break;
case input_open_info_write: // prepare to retrieve info and tag
case input_open_info_write: // prepare to retrieve info and tag
default:
throw exception_io_data();
break;
default: // nothing else should be possible
throw exception_io_data();
break;
}
}
// called after opening file (possibly per subsong too)
unsigned input_vgmstream::get_subsong_count() {
// if the plugin uses input_factory_t template and returns > 1 here when adding a song to the playlist,
// foobar will automagically "unpack" it by calling decode_initialize/get_info with all subsong indexes.
// There is no need to add any playlist code, only properly handle the subsong index.
if (disable_subsongs)
return 1;
// If the plugin uses input_factory_t template and returns > 1 here when adding a song to the playlist,
// foobar will automagically "unpack" it by calling decode_initialize/get_info with all subsong indexes.
// There is no need to add any playlist code, only properly handle the subsong index.
// vgmstream ready as method is valid after open() with any reason
int subsong_count = vgmstream->num_streams;
@ -142,117 +137,155 @@ unsigned input_vgmstream::get_subsong_count() {
// called after get_subsong_count to play subsong N (even when count is 1)
t_uint32 input_vgmstream::get_subsong(unsigned p_index) {
return p_index + 1; // translates index (0..N < subsong_count) for vgmstream: 1=first
// translates index (0..N < subsong_count) for vgmstream: 1=first
return p_index + 1;
}
// called before playing to get info
void input_vgmstream::get_info(t_uint32 p_subsong, file_info & p_info, abort_callback & p_abort) {
int length_in_ms=0, channels = 0, samplerate = 0;
int total_samples = -1;
int bitrate = 0;
int loop_flag = -1, loop_start = -1, loop_end = -1;
pfc::string8 description;
pfc::string8_fast temp;
void input_vgmstream::get_info(t_uint32 p_subsong, file_info& p_info, abort_callback& p_abort) {
vgmstream_info_t v_info = {}; // init default (not {0} since it has classes)
get_subsong_info(p_subsong, temp, &length_in_ms, &total_samples, &loop_flag, &loop_start, &loop_end, &samplerate, &channels, &bitrate, description, p_abort);
query_subsong_info(p_subsong, v_info, p_abort);
// export tags ('metadata' tab in file properties)
put_info_tags(p_info, v_info);
put_into_tagfile(p_info, p_abort);
/* set tag info (metadata tab in file properties) */
// set technical info ('details' tab in file properties)
put_info_details(p_info, v_info);
}
/* Shows a custom subsong title by default with subsong name, to simplify for average users.
* This can be overriden and extended using the exported STREAM_x below and foobar's formatting.
* foobar defaults to filename minus extension if there is no meta "title" value. */
void input_vgmstream::put_info_tags(file_info& p_info, vgmstream_info_t& v_info) {
if (!override_title) {
p_info.meta_set("TITLE",temp);
}
if (get_description_tag(temp,description,"stream count: ")) p_info.meta_set("stream_count",temp);
if (get_description_tag(temp,description,"stream index: ")) p_info.meta_set("stream_index",temp);
if (get_description_tag(temp,description,"stream name: ")) p_info.meta_set("stream_name",temp);
if (loop_end) {
p_info.meta_set("loop_start", pfc::format_int(loop_start));
p_info.meta_set("loop_end", pfc::format_int(loop_end));
// has extra text info
//if (get_description_tag(temp,description,"loop start: ")) p_info.meta_set("loop_start",temp);
//if (get_description_tag(temp,description,"loop end: ")) p_info.meta_set("loop_end",temp);
/* Shows a default (sub)song title with stream name.
* This can be overriden and extended using the exported STREAM_x below and foobar's formatting.
* foobar defaults to filename minus extension if there is no meta "title" value. */
p_info.meta_set("TITLE", v_info.title);
}
/* get external file tags */
//todo optimize and don't parse tags again for this session (not sure how), seems foobar
// calls get_info on every play even if the file hasn't changes, and won't refresh "meta"
// unless forced or closing playlist+exe
if (!tagfile_disable) {
//todo use foobar's fancy-but-arcane string functions
char tagfile_path[PATH_LIMIT];
strcpy(tagfile_path, filename);
if (!v_info.stream_name.is_empty()) {
p_info.meta_set("stream_name", v_info.stream_name);
}
char *path = strrchr(tagfile_path,'\\');
if (path!=NULL) {
path[1] = '\0'; /* includes "\", remove after that from tagfile_path */
strcat(tagfile_path,tagfile_name);
if (v_info.subsong_count > 1) {
p_info.meta_set("stream_count", pfc::format_int(v_info.subsong_count));
p_info.meta_set("stream_index", pfc::format_int(v_info.subsong_index == 0 ? 1 : v_info.subsong_index));
}
if (v_info.loop_end > 0) {
p_info.meta_set("loop_start", pfc::format_int(v_info.loop_start));
p_info.meta_set("loop_end", pfc::format_int(v_info.loop_end));
}
}
void input_vgmstream::put_into_tagfile(file_info& p_info, abort_callback& p_abort) {
if (tagfile_disable)
return;
//TODO: optimize and don't parse tags again for this session (not sure how).
// Seems foobar calls get_info on every play even if the file hasn't changed,
// and won't refresh "meta" unless forced or closing playlist + exe.
//TODO: use foobar's fancy-but-arcane string functions
char tagfile_path[FOO_PATH_LIMIT];
strcpy(tagfile_path, filename);
char* path = strrchr(tagfile_path, '\\');
if (path != NULL) {
path[1] = '\0'; // includes "\", remove after that from tagfile_path
strcat(tagfile_path, tagfile_name);
}
else {
// possible?
strcpy(tagfile_path, tagfile_name);
}
STREAMFILE* sf_tags = open_foo_streamfile(tagfile_path, &p_abort, NULL);
if (sf_tags == NULL)
return;
VGMSTREAM_TAGS* tags;
const char *tag_key, *tag_val;
tags = vgmstream_tags_init(&tag_key, &tag_val);
vgmstream_tags_reset(tags, filename);
while (vgmstream_tags_next_tag(tags, sf_tags)) {
if (replaygain_info::g_is_meta_replaygain(tag_key)) {
p_info.info_set_replaygain(tag_key, tag_val);
// there is set_replaygain_auto/set_replaygain_ex too but no doc
}
else { /* ??? */
strcpy(tagfile_path,tagfile_name);
else if (stricmp_utf8("ALBUMARTIST", tag_key) == 0) {
// normalize tag for foobar as otherwise can't understand it (though it's recognized in .ogg)
p_info.meta_set("ALBUM ARTIST", tag_val);
}
STREAMFILE* sf_tags = open_foo_streamfile(tagfile_path, &p_abort, NULL);
if (sf_tags != NULL) {
VGMSTREAM_TAGS* tags;
const char *tag_key, *tag_val;
tags = vgmstream_tags_init(&tag_key, &tag_val);
vgmstream_tags_reset(tags, filename);
while (vgmstream_tags_next_tag(tags, sf_tags)) {
if (replaygain_info::g_is_meta_replaygain(tag_key)) {
p_info.info_set_replaygain(tag_key, tag_val);
/* there is info_set_replaygain_auto too but no doc */
}
else if (stricmp_utf8("ALBUMARTIST", tag_key) == 0)
/* normalize as foobar won't handle (though it's accepted in .ogg) */
p_info.meta_set("ALBUM ARTIST", tag_val);
else {
p_info.meta_set(tag_key, tag_val);
}
}
vgmstream_tags_close(tags);
close_streamfile(sf_tags);
else {
p_info.meta_set(tag_key, tag_val);
}
}
vgmstream_tags_close(tags);
close_streamfile(sf_tags);
}
/* set technical info (details tab in file properties) */
// include main info, note that order doesn't matter (foobar sorts by fixed order + name)
void input_vgmstream::put_info_details(file_info& p_info, vgmstream_info_t& v_info) {
p_info.info_set("vgmstream_version", PLUGIN_VERSION); //to make clearer vgmsrteam is actually opening the file
p_info.info_set("vgmstream_version", PLUGIN_VERSION);
p_info.info_set_int("samplerate", samplerate);
p_info.info_set_int("channels", channels);
p_info.info_set_int("bitspersample", 16);
/* not quite accurate but some people are confused by "lossless"
* (could set lossless if PCM, but then again PCMFloat or PCM8 are converted/"lossy" in vgmstream) */
p_info.info_set("encoding","lossy/lossless");
p_info.info_set_bitrate(bitrate / 1000);
if (total_samples > 0)
p_info.info_set_int("stream_total_samples", total_samples);
if (loop_start >= 0 && loop_end > loop_start) {
if (!loop_flag) p_info.info_set("looping", "disabled");
p_info.info_set_int("loop_start", loop_start);
p_info.info_set_int("loop_end", loop_end);
// not quite accurate but some people are confused by "lossless"
// (could set lossless if PCM, but then again in vgm may be converted/"lossy" vs original source)
p_info.info_set("encoding", "lossy/lossless");
p_info.info_set_int("channels", v_info.channels);
p_info.info_set_int("samplerate", v_info.sample_rate);
p_info.info_set_int("bitspersample", v_info.bits_per_sample);
p_info.info_set_bitrate(v_info.bitrate / 1000);
if (v_info.input_channels > 0 && v_info.channels != v_info.input_channels) {
p_info.info_set_int("input_channels", v_info.input_channels);
//p_info.info_set_int("output_channels", v_info.output_channels);
}
p_info.set_length(((double)length_in_ms)/1000);
if (get_description_tag(temp,description,"encoding: ")) p_info.info_set("codec",temp);
if (get_description_tag(temp,description,"layout: ")) p_info.info_set("layout",temp);
if (get_description_tag(temp,description,"interleave: ",' ')) p_info.info_set("interleave",temp);
if (get_description_tag(temp,description,"interleave last block:",' ')) p_info.info_set("interleave_last_block",temp);
p_info.set_length(v_info.play_length_s);
if (get_description_tag(temp,description,"block size: ")) p_info.info_set("block_size",temp);
if (get_description_tag(temp,description,"metadata from: ")) p_info.info_set("metadata_source",temp);
if (get_description_tag(temp,description,"stream count: ")) p_info.info_set("stream_count",temp);
if (get_description_tag(temp,description,"stream index: ")) p_info.info_set("stream_index",temp);
if (get_description_tag(temp,description,"stream name: ")) p_info.info_set("stream_name",temp);
if (v_info.stream_samples > 0) { // ?
p_info.info_set_int("samples", v_info.stream_samples);
}
if (get_description_tag(temp,description,"channel mask: ")) p_info.info_set("channel_mask",temp);
if (get_description_tag(temp,description,"output channels: ")) p_info.info_set("output_channels",temp);
if (get_description_tag(temp,description,"input channels: ")) p_info.info_set("input_channels",temp);
if (v_info.loop_end > 0) {
p_info.info_set_int("loop_start", v_info.loop_start);
p_info.info_set_int("loop_end", v_info.loop_end);
if (!v_info.loop_flag)
p_info.info_set("looping", "disabled");
}
p_info.info_set("codec", v_info.codec_name);
p_info.info_set("layout", v_info.layout_name);
p_info.info_set("metadata", v_info.meta_name);
if (!v_info.stream_name.is_empty()) {
p_info.info_set("stream_name", v_info.stream_name);
}
if (v_info.subsong_count > 1) {
p_info.info_set_int("stream_count", v_info.subsong_count);
p_info.info_set_int("stream_index", v_info.subsong_index);
}
if (!v_info.channel_mask.is_empty()) {
p_info.info_set("channel_mask", v_info.channel_mask);
}
/*
// for >2ch foobar writes info like "Channels - 8: FL FR FC LFE BL BR FCL FCR", which may be undesirable?
if (v_info.channel_layout > 0) {
// there is info_set_channels_ex in newer SDKs too
p_info.info_set_wfx_chanMask(v_info.channel_layout);
}
*/
//if (v_info.interleave > 0) p_info.info_set("interleave", v_info.interleave);
//if (v_info.interleave_last > 0) p_info.info_set("interleave_last_block", v_info.interleave_last);
//if (v_info.block_size > 0) p_info.info_set("block_size", v_info.block_size);
}
t_filestats input_vgmstream::get_file_stats(abort_callback & p_abort) {
@ -283,8 +316,10 @@ void input_vgmstream::decode_initialize(t_uint32 p_subsong, unsigned p_flags, ab
// called when audio buffer needs to be filled
bool input_vgmstream::decode_run(audio_chunk & p_chunk, abort_callback & p_abort) {
if (!decoding) return false;
if (!vgmstream) return false;
if (!decoding)
return false;
if (!vgmstream)
return false;
int max_buffer_samples = SAMPLE_BUFFER_SIZE;
int samples_to_do = max_buffer_samples;
@ -319,44 +354,46 @@ bool input_vgmstream::decode_run(audio_chunk & p_chunk, abort_callback & p_abort
}
// called when seeking
void input_vgmstream::decode_seek(double p_seconds, abort_callback & p_abort) {
int32_t seek_sample = (int)audio_math::time_to_samples(p_seconds, vgmstream->sample_rate);
void input_vgmstream::decode_seek(double p_seconds, abort_callback& p_abort) {
int64_t seek_sample = (int64_t)audio_math::time_to_samples(p_seconds, vgmstream->sample_rate);
bool play_forever = vgmstream_get_play_forever(vgmstream);
// TODO: check play position after seek_sample and let seek clamp
// possible when disabling looping without refreshing foobar's cached song length
// (p_seconds can't go over seek bar with infinite looping on, though)
if (seek_sample > length_samples)
seek_sample = length_samples;
seek_vgmstream(vgmstream, seek_sample);
seek_vgmstream(vgmstream, (int32_t)seek_sample);
decode_pos_samples = seek_sample;
decode_pos_ms = decode_pos_samples * 1000LL / vgmstream->sample_rate;
decoding = play_forever || decode_pos_samples < length_samples;
}
bool input_vgmstream::decode_can_seek() {return true;}
bool input_vgmstream::decode_get_dynamic_info(file_info & p_out, double & p_timestamp_delta) { return false; }
bool input_vgmstream::decode_get_dynamic_info_track(file_info & p_out, double & p_timestamp_delta) {return false;}
void input_vgmstream::decode_on_idle(abort_callback & p_abort) {/*m_file->on_idle(p_abort);*/}
bool input_vgmstream::decode_can_seek() { return true; }
bool input_vgmstream::decode_get_dynamic_info(file_info& p_out, double& p_timestamp_delta) { return false; }
bool input_vgmstream::decode_get_dynamic_info_track(file_info& p_out, double& p_timestamp_delta) { return false; }
void input_vgmstream::decode_on_idle(abort_callback& p_abort) { /*m_file->on_idle(p_abort);*/ }
void input_vgmstream::retag_set_info(t_uint32 p_subsong, const file_info & p_info, abort_callback & p_abort) { /*throw exception_io_data();*/ }
void input_vgmstream::retag_commit(abort_callback & p_abort) { /*throw exception_io_data();*/ }
void input_vgmstream::remove_tags(abort_callback & p_abort) { /*throw exception_io_data();*/ }
void input_vgmstream::retag_set_info(t_uint32 p_subsong, const file_info& p_info, abort_callback& p_abort) { /*throw exception_io_data();*/ }
void input_vgmstream::retag_commit(abort_callback& p_abort) { /*throw exception_io_data();*/ }
void input_vgmstream::remove_tags(abort_callback& p_abort) { /*throw exception_io_data();*/ }
bool input_vgmstream::g_is_our_content_type(const char * p_content_type) { return false; }
bool input_vgmstream::g_is_our_content_type(const char* p_content_type) { return false; }
// called to check if file can be processed by the plugin
bool input_vgmstream::g_is_our_path(const char * p_path, const char * p_extension) {
bool input_vgmstream::g_is_our_path(const char* p_path, const char* p_extension) {
vgmstream_ctx_valid_cfg cfg = {0};
cfg.is_extension = 1;
cfg.is_extension = true;
input_vgmstream::g_load_cfg(&cfg.accept_unknown, &cfg.accept_common);
return vgmstream_ctx_is_valid(p_extension, &cfg) > 0 ? true : false;
}
// internal util to create a VGMSTREAM
VGMSTREAM* input_vgmstream::init_vgmstream_foo(t_uint32 p_subsong, const char * const filename, abort_callback & p_abort) {
VGMSTREAM* input_vgmstream::init_vgmstream_foo(t_uint32 p_subsong, const char* const filename, abort_callback& p_abort) {
VGMSTREAM* vgmstream = NULL;
/* Workaround for a foobar bug (mainly for complex TXTP):
@ -387,10 +424,8 @@ void input_vgmstream::setup_vgmstream(abort_callback & p_abort) {
// subsong and filename are always defined before this
vgmstream = init_vgmstream_foo(subsong, filename, p_abort);
if (!vgmstream) {
if (!vgmstream)
throw exception_io_data();
return;
}
// default subsong is 0, meaning first init (vgmstream should open first stream, but not set stream_index).
// if the stream_index is already set, then the subsong was opened directly by some means (txtp, playlist, etc).
@ -414,92 +449,10 @@ void input_vgmstream::setup_vgmstream(abort_callback & p_abort) {
length_samples = vgmstream_get_samples(vgmstream);
}
// internal util to get info
void input_vgmstream::get_subsong_info(t_uint32 p_subsong, pfc::string_base & title, int *length_in_ms, int *total_samples, int *loop_flag, int *loop_start, int *loop_end, int *sample_rate, int *channels, int *bitrate, pfc::string_base & description, abort_callback & p_abort) {
VGMSTREAM* infostream = NULL;
bool is_infostream = false;
char temp[1024];
int info_channels;
// reuse current vgmstream if not querying a new subsong
// if it's a direct subsong then subsong may be N while p_subsong 1
// there is no need to recreate the infostream, there is only one subsong used
if (subsong != p_subsong && !direct_subsong) {
infostream = init_vgmstream_foo(p_subsong, filename, p_abort);
if (!infostream) {
throw exception_io_data();
}
is_infostream = true;
apply_config(infostream);
vgmstream_mixing_autodownmix(infostream, downmix_channels);
vgmstream_mixing_enable(infostream, 0, NULL /*&input_channels*/, &info_channels);
} else {
// vgmstream ready as get_info is valid after open() with any reason
infostream = vgmstream;
info_channels = output_channels;
}
if (length_in_ms) {
*length_in_ms = -1000;
if (infostream) {
*channels = info_channels;
*sample_rate = infostream->sample_rate;
*total_samples = infostream->num_samples;
*bitrate = get_vgmstream_average_bitrate(infostream);
*loop_flag = infostream->loop_flag;
*loop_start = infostream->loop_start_sample;
*loop_end = infostream->loop_end_sample;
int num_samples = vgmstream_get_samples(infostream);
*length_in_ms = num_samples*1000LL / infostream->sample_rate;
describe_vgmstream(infostream, temp, sizeof(temp));
description = temp;
}
}
/* infostream gets added with index 0 (other) or 1 (current) */
if (infostream && title) {
vgmstream_title_t tcfg = {0};
tcfg.remove_extension = 1;
tcfg.remove_archive = 1;
const char* filename_str = filename;
vgmstream_get_title(temp, sizeof(temp), filename_str, infostream, &tcfg);
title = temp;
}
// and only close if was querying a new subsong
if (is_infostream) {
close_vgmstream(infostream);
infostream = NULL;
}
}
bool input_vgmstream::get_description_tag(pfc::string_base & temp, pfc::string_base const& description, const char *tag, char delimiter) {
// extract a "tag" from the description string
t_size pos = description.find_first(tag);
t_size eos;
if (pos != pfc::infinite_size) {
pos += strlen(tag);
eos = description.find_first(delimiter, pos);
if (eos == pfc::infinite_size) eos = description.length();
temp.set_string(description + pos, eos - pos);
//console::formatter() << "tag=" << tag << ", delim=" << delimiter << "temp=" << temp << ", pos=" << pos << "" << eos;
return true;
}
return false;
}
void input_vgmstream::apply_config(VGMSTREAM* vgmstream) {
vgmstream_cfg_t vcfg = {0};
vcfg.allow_play_forever = 1;
vcfg.allow_play_forever = true;
vcfg.play_forever = loop_forever;
vcfg.loop_count = loop_count;
vcfg.fade_time = fade_seconds;
@ -509,23 +462,132 @@ void input_vgmstream::apply_config(VGMSTREAM* vgmstream) {
vgmstream_apply_config(vgmstream, &vcfg);
}
// internal util to get info
void input_vgmstream::query_subsong_info(t_uint32 p_subsong, vgmstream_info_t& v_info, abort_callback& p_abort) {
VGMSTREAM* infostream = NULL;
bool is_infostream = false;
int info_channels;
char temp[1024];
// Reuse current vgmstream if not querying a new subsong.
// If it's a direct subsong then subsong may be N while p_subsong = 1
// so there is no need to recreate the infostream, only one subsong is used.
if (subsong != p_subsong && !direct_subsong) {
infostream = init_vgmstream_foo(p_subsong, filename, p_abort);
if (!infostream)
throw exception_io_data();
is_infostream = true;
apply_config(infostream);
vgmstream_mixing_autodownmix(infostream, downmix_channels);
vgmstream_mixing_enable(infostream, 0, NULL /*&input_channels*/, &info_channels);
}
else {
// vgmstream ready as get_info is valid after open() with any reason
infostream = vgmstream;
info_channels = output_channels;
}
if (!infostream)
throw exception_io_data();
/* basic info */
{
v_info.channels = info_channels;
v_info.input_channels = infostream->channels;
v_info.sample_rate = infostream->sample_rate;
v_info.stream_samples = infostream->num_samples;
v_info.bitrate = get_vgmstream_average_bitrate(infostream);
v_info.loop_flag = infostream->loop_flag;
v_info.loop_start = infostream->loop_start_sample;
v_info.loop_end = infostream->loop_end_sample;
v_info.subsong_count = infostream->num_streams;
v_info.subsong_index = infostream->stream_index;
if (v_info.subsong_index == 0)
v_info.subsong_index = 1;
v_info.channel_layout = infostream->channel_layout;
int64_t play_duration = vgmstream_get_samples(infostream);
v_info.play_length_s = (double)play_duration / (double)infostream->sample_rate;
v_info.bits_per_sample = sizeof(short) * 8;
}
// formatted info
{
pfc::string8 description;
describe_vgmstream(infostream, temp, sizeof(temp));
description = temp;
query_description_tag(v_info.codec_name, description, "encoding: ");
query_description_tag(v_info.layout_name, description, "layout: ");
query_description_tag(v_info.meta_name, description, "metadata from: ");
query_description_tag(v_info.stream_name, description, "stream name: ");
query_description_tag(v_info.channel_mask, description, "channel mask: ");
//query_description_tag(temp, description,"interleave: ",' ');
//query_description_tag(temp, description,"interleave last block:",' ');
//query_description_tag(temp, description,"block size: ");
}
// infostream gets added with index 0 (other) or 1 (current)
{
vgmstream_title_t tcfg = {0};
tcfg.remove_extension = true;
tcfg.remove_archive = true;
const char* filename_str = filename;
vgmstream_get_title(temp, sizeof(temp), filename_str, infostream, &tcfg);
v_info.title = temp;
}
// and only close if was querying a new subsong
if (is_infostream) {
close_vgmstream(infostream);
infostream = NULL;
}
}
// extract a "tag" from the description string
bool input_vgmstream::query_description_tag(pfc::string_base& tag_value, pfc::string_base const& description, const char* tag_key, char delimiter) {
t_size pos = description.find_first(tag_key);
if (pos == pfc::infinite_size)
return false;
pos += strlen(tag_key);
t_size eos = description.find_first(delimiter, pos);
if (eos == pfc::infinite_size)
eos = description.length();
tag_value.set_string(description + pos, eos - pos);
return true;
}
// checks priority (foobar 1.4+)
bool input_vgmstream::g_is_low_merit() {
return true;
}
// foobar recognizes plugin with this (meaning, different GUID = different plugin)
GUID input_vgmstream::g_get_guid() {
static const GUID guid = { 0x9e7263c7, 0x4cdd, 0x482c,{ 0x9a, 0xec, 0x5e, 0x71, 0x28, 0xcb, 0xc3, 0x4 } };
return guid;
}
const char * input_vgmstream::g_get_name() {
return "vgmstream";
}
GUID input_vgmstream::g_get_preferences_guid() {
static const GUID guid = { 0x2b5d0302, 0x165b, 0x409c,{ 0x94, 0x74, 0x2c, 0x8c, 0x2c, 0xd7, 0x6a, 0x25 } };
return guid;
}
// checks priority (foobar 1.4+)
bool input_vgmstream::g_is_low_merit() {
return true;
const char* input_vgmstream::g_get_name() {
return "vgmstream";
}
// foobar plugin defs

View File

@ -1,12 +1,41 @@
#ifndef _FOO_VGMSTREAM_
#define _FOO_VGMSTREAM_
#define SAMPLE_BUFFER_SIZE 1024
#define SAMPLE_BUFFER_SIZE 1024
#define FOO_PATH_LIMIT 4096 /* see vgmstream_limits.h*/
extern "C" {
#include "../src/vgmstream.h"
}
typedef struct {
pfc::string8_fast title;
pfc::string8_fast stream_name;
pfc::string8_fast layout_name;
pfc::string8_fast codec_name;
pfc::string8_fast meta_name;
pfc::string8_fast channel_mask;
int channels;
int sample_rate;
int input_channels;
int subsong_count;
int subsong_index;
int bits_per_sample;
int64_t stream_samples;
int64_t loop_start;
int64_t loop_end;
bool loop_flag;
int bitrate;
uint32_t channel_layout;
double play_length_s;
} vgmstream_info_t;
class input_vgmstream : public input_stubs {
public:
@ -65,7 +94,7 @@ class input_vgmstream : public input_stubs {
double fade_delay_seconds;
double loop_count;
bool loop_forever;
int ignore_loop;
bool ignore_loop;
bool disable_subsongs;
int downmix_channels;
@ -76,13 +105,19 @@ class input_vgmstream : public input_stubs {
//bool exts_unknown_on;
/* helpers */
void load_settings();
void put_info_tags(file_info& p_info, vgmstream_info_t& v_info);
void put_into_tagfile(file_info& p_info, abort_callback& p_abort);
void put_info_details(file_info& p_info, vgmstream_info_t& v_info);
VGMSTREAM* init_vgmstream_foo(t_uint32 p_subsong, const char* const filename, abort_callback& p_abort);
void setup_vgmstream(abort_callback& p_abort);
void load_settings();
void get_subsong_info(t_uint32 p_subsong, pfc::string_base& title, int* length_in_ms, int* total_samples, int* loop_flag, int *loop_start, int* loop_end, int* sample_rate, int* channels, int* bitrate, pfc::string_base& description, abort_callback& p_abort);
bool get_description_tag(pfc::string_base& temp, pfc::string_base const& description, const char* tag, char delimiter = '\n');
void apply_config(VGMSTREAM* vgmstream);
void query_subsong_info(t_uint32 p_subsong, vgmstream_info_t& v_info, abort_callback& p_abort);
bool query_description_tag(pfc::string_base& temp, pfc::string_base const& description, const char* tag, char delimiter = '\n');
static void g_load_cfg(int* accept_unknown, int* accept_common);
};

View File

@ -132,7 +132,7 @@ fail:
}
LIBVGMSTREAM_API libvgmstream_streamfile_t* libvgmstream_streamfile_from_filename(const char* filename) {
LIBVGMSTREAM_API libvgmstream_streamfile_t* libvgmstream_streamfile_open_from_stdio(const char* filename) {
STREAMFILE* sf = open_stdio_streamfile(filename);
if (!sf)
return NULL;

View File

@ -502,7 +502,7 @@ int decode_get_samples_per_frame(VGMSTREAM* vgmstream) {
return (0x40-0x04) * 2;
case coding_NDS_PROCYON:
return 30;
case coding_L5_555:
case coding_LEVEL5:
return 32;
case coding_LSF:
return 54;
@ -729,7 +729,7 @@ int decode_get_frame_size(VGMSTREAM* vgmstream) {
return 0x40;
case coding_NDS_PROCYON:
return 0x10;
case coding_L5_555:
case coding_LEVEL5:
return 0x12;
case coding_LSF:
return 0x1C;
@ -1447,7 +1447,7 @@ void decode_vgmstream(VGMSTREAM* vgmstream, int samples_written, int samples_to_
vgmstream->channels, vgmstream->samples_into_block, samples_to_do);
}
break;
case coding_L5_555:
case coding_LEVEL5:
for (ch = 0; ch < vgmstream->channels; ch++) {
decode_l5_555(&vgmstream->ch[ch], buffer+ch,
vgmstream->channels, vgmstream->samples_into_block, samples_to_do);

View File

@ -1,6 +1,7 @@
#include <ctype.h>
#include "../vgmstream.h"
#include "../coding/coding.h"
#include "../layout/layout.h"
#include "mixing.h"
#include "../util/channel_mappings.h"
#include "../util/sf_utils.h"
@ -12,7 +13,7 @@
static void describe_get_time(int32_t samples, int sample_rate, double* p_time_mm, double* p_time_ss) {
double seconds = (double)samples / sample_rate;
*p_time_mm = (int)(seconds / 60.0);
*p_time_ss = seconds - *p_time_mm * 60.0f;
*p_time_ss = seconds - *p_time_mm * 60.0;
if (*p_time_ss >= 59.999) /* avoid round up to 60.0 when printing to %06.3f */
*p_time_ss = 59.999;
}
@ -51,7 +52,7 @@ void describe_vgmstream(VGMSTREAM* vgmstream, char* desc, int length) {
}
if (vgmstream->channel_layout) {
int cl = vgmstream->channel_layout;
uint32_t cl = vgmstream->channel_layout;
/* not "channel layout: " to avoid mixups with "layout: " */
snprintf(temp,TEMPSIZE, "channel mask: 0x%x /", vgmstream->channel_layout);
@ -62,8 +63,8 @@ void describe_vgmstream(VGMSTREAM* vgmstream, char* desc, int length) {
if (cl & speaker_LFE) concatn(length,desc," LFE");
if (cl & speaker_BL) concatn(length,desc," BL");
if (cl & speaker_BR) concatn(length,desc," BR");
if (cl & speaker_FLC) concatn(length,desc," FLC");
if (cl & speaker_FRC) concatn(length,desc," FRC");
if (cl & speaker_FLC) concatn(length,desc," FLC"); //FCL is also common
if (cl & speaker_FRC) concatn(length,desc," FRC"); //FCR is also common
if (cl & speaker_BC) concatn(length,desc," BC");
if (cl & speaker_SL) concatn(length,desc," SL");
if (cl & speaker_SR) concatn(length,desc," SR");

View File

@ -12,7 +12,7 @@ static inline float get_fade_gain_curve(char shape, float index) {
return index;
}
//TODO optimizations: interleave calcs, maybe use cosf, powf, etc? (with extra defines)
//TODO optimizations: interleave calcs
/* (curve math mostly from SoX/FFmpeg) */
switch(shape) {
@ -20,25 +20,25 @@ static inline float get_fade_gain_curve(char shape, float index) {
* (alt calculations with 'exp' from FFmpeg use (factor)*ln(0.1) = -NN.N... */
case 'E': /* exponential (for fade-outs, closer to natural decay of sound) */
//gain = pow(0.1f, (1.0f - index) * 2.5f);
gain = exp(-5.75646273248511f * (1.0f - index));
//gain = powf(0.1f, (1.0f - index) * 2.5f);
gain = expf(-5.75646273248511f * (1.0f - index));
break;
case 'L': /* logarithmic (inverse of the above, maybe for crossfades) */
//gain = 1 - pow(0.1f, (index) * 2.5f);
gain = 1 - exp(-5.75646273248511f * (index));
//gain = 1 - powf(0.1f, (index) * 2.5f);
gain = 1 - expf(-5.75646273248511f * (index));
break;
case 'H': /* raised sine wave or cosine wave (for more musical crossfades) */
gain = (1.0f - cos(index * MIXING_PI)) / 2.0f;
gain = (1.0f - cosf(index * MIXING_PI)) / 2.0f;
break;
case 'Q': /* quarter of sine wave (for musical fades) */
gain = sin(index * MIXING_PI / 2.0f);
gain = sinf(index * MIXING_PI / 2.0f);
break;
case 'p': /* parabola (maybe for crossfades) */
gain = 1.0f - sqrt(1.0f - index);
gain = 1.0f - sqrtf(1.0f - index);
break;
case 'P': /* inverted parabola (maybe for fades) */
@ -154,7 +154,7 @@ bool mixer_op_fade_is_active(mixer_t* mixer, int32_t current_start, int32_t curr
/* check is current range falls within a fade
* (assuming fades were already optimized on add) */
if (mix->time_pre < 0 && vol_start == 1.0) {
if (mix->time_pre < 0 && vol_start == 1.0f) {
fade_start = mix->time_start; /* ignore unused */
}
else {

View File

@ -4,6 +4,7 @@
#include "mixer.h"
#include "mixer_priv.h"
#include "sbuf.h"
#include "../layout/layout.h"
#include <math.h>
#include <limits.h>

View File

@ -1,5 +1,6 @@
#include "../vgmstream.h"
#include "../util/channel_mappings.h"
#include "../layout/layout.h"
#include "mixing.h"
#include "mixer_priv.h"
#include <math.h>

View File

@ -8,6 +8,14 @@
#include "../vgmstream.h"
/* List supported formats and return elements in the list, for plugins that need to know.
* The list disables some common formats that may conflict (.wav, .ogg, etc). */
const char** vgmstream_get_formats(size_t* size);
/* same, but for common-but-disabled formats in the above list. */
const char** vgmstream_get_common_formats(size_t* size);
/* ****************************************** */
/* CONTEXT: simplifies plugin code */
/* ****************************************** */

View File

@ -6,7 +6,7 @@
// TODO decide if using float 1.0 style or 32767 style (fuzzy PCM changes when doing that)
static inline void sbuf_copy_s16_to_f32(float* buf_f32, int16_t* buf_s16, int samples, int channels) {
for (int s = 0; s < samples * channels; s++) {
buf_f32[s] = buf_s16[s]; // / 32767.0f
buf_f32[s] = (float)buf_s16[s]; // / 32767.0f
}
}

View File

@ -2,7 +2,7 @@
#include "libs/libacm.h"
#include <stdio.h>
/* libacm 1.2 (despite what libacm.h says) from: https://github.com/markokr/libacm */
/* libacm 1.2 (despite libacm.h saying 1.1) from: https://github.com/markokr/libacm */
/* libacm interface */
@ -26,10 +26,10 @@ acm_codec_data* init_acm(STREAMFILE* sf, int force_channel_number) {
acm_codec_data* data = NULL;
data = calloc(1,sizeof(acm_codec_data));
data = calloc(1, sizeof(acm_codec_data));
if (!data) goto fail;
data->io_config = calloc(1,sizeof(acm_io_config));
data->io_config = calloc(1, sizeof(acm_io_config));
if (!data->io_config) goto fail;
data->streamfile = reopen_streamfile(sf, 0);
@ -74,12 +74,12 @@ void decode_acm(acm_codec_data* data, sample_t* outbuf, int32_t samples_to_do, i
while (samples_read < samples_to_do) {
int32_t bytes_read_just_now = acm_read(
acm,
(char*)(outbuf+samples_read*channelspacing),
(samples_to_do-samples_read)*sizeof(sample)*channelspacing,
(char*)(outbuf + samples_read * channelspacing),
(samples_to_do - samples_read) * sizeof(sample_t) * channelspacing,
0,2,1);
if (bytes_read_just_now > 0) {
samples_read += bytes_read_just_now/sizeof(sample)/channelspacing;
samples_read += bytes_read_just_now / sizeof(sample_t) / channelspacing;
} else {
return;
}

View File

@ -90,7 +90,7 @@ void decode_adx(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing,
stream->adpcm_history2_32 = hist2;
if ((coding_type == coding_CRI_ADX_enc_8 || coding_type == coding_CRI_ADX_enc_9) && !(i % 32)) {
for (i =0; i < stream->adx_channels; i++) {
for (i = 0; i < channelspacing; i++) {
adx_next_key(stream);
}
}

View File

@ -50,9 +50,9 @@ atrac9_codec_data* init_atrac9(atrac9_config* cfg) {
/* must hold at least one superframe and its samples */
data->data_buffer_size = data->info.superframeSize;
/* extra leeway as Atrac9Decode seems to overread ~2 bytes (doesn't affect decoding though) */
data->data_buffer = calloc(sizeof(uint8_t), data->data_buffer_size + 0x10);
/* while ATRAC9 uses float internally, Sony's API only return PCM16 */
data->sample_buffer = calloc(sizeof(sample_t), data->info.channels * data->info.frameSamples * data->info.framesInSuperframe);
data->data_buffer = calloc(data->data_buffer_size + 0x10, sizeof(uint8_t));
/* while ATRAC9 uses float internally, Sony's API only returns PCM16 */
data->sample_buffer = calloc(data->info.channels * data->info.frameSamples * data->info.framesInSuperframe, sizeof(sample_t));
data->samples_to_discard = cfg->encoder_delay;
@ -89,7 +89,7 @@ void decode_atrac9(VGMSTREAM* vgmstream, sample_t* outbuf, int32_t samples_to_do
memcpy(outbuf + samples_done*channels,
data->sample_buffer + data->samples_used*channels,
samples_to_get*channels * sizeof(sample));
samples_to_get*channels * sizeof(sample_t));
samples_done += samples_to_get;
}
@ -131,7 +131,7 @@ void decode_atrac9(VGMSTREAM* vgmstream, sample_t* outbuf, int32_t samples_to_do
decode_fail:
/* on error just put some 0 samples */
VGM_LOG("ATRAC9: decode fail at %x, missing %i samples\n", (uint32_t)stream->offset, (samples_to_do - samples_done));
memset(outbuf + samples_done * channels, 0, (samples_to_do - samples_done) * sizeof(sample) * channels);
memset(outbuf + samples_done * channels, 0, (samples_to_do - samples_done) * sizeof(sample_t) * channels);
}
void reset_atrac9(atrac9_codec_data* data) {
@ -221,7 +221,7 @@ void free_atrac9(atrac9_codec_data* data) {
}
static int atrac9_parse_config(uint32_t atrac9_config, int *out_sample_rate, int *out_channels, size_t *out_frame_size, size_t *out_samples_per_frame) {
static int atrac9_parse_config(uint32_t config_data, int* p_sample_rate, int* p_channels, size_t* p_frame_size, size_t* p_samples_per_frame) {
static const int sample_rate_table[16] = {
11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000,
44100, 48000, 64000, 88200, 96000,128000,176400,192000
@ -235,13 +235,13 @@ static int atrac9_parse_config(uint32_t atrac9_config, int *out_sample_rate, int
};
int superframe_size, frames_per_superframe, samples_per_frame, samples_per_superframe;
uint32_t sync = (atrac9_config >> 24) & 0xff; /* 8b */
uint8_t sample_rate_index = (atrac9_config >> 20) & 0x0f; /* 4b */
uint8_t channels_index = (atrac9_config >> 17) & 0x07; /* 3b */
/* uint8_t validation bit = (atrac9_config >> 16) & 0x01; */ /* 1b */
size_t frame_size = (atrac9_config >> 5) & 0x7FF; /* 11b */
size_t superframe_index = (atrac9_config >> 3) & 0x3; /* 2b */
/* uint8_t unused = (atrac9_config >> 0) & 0x7);*/ /* 3b */
uint32_t sync = (config_data >> 24) & 0xff; /* 8b */
uint8_t sample_rate_index = (config_data >> 20) & 0x0f; /* 4b */
uint8_t channels_index = (config_data >> 17) & 0x07; /* 3b */
/* uint8_t validation bit = (config_data >> 16) & 0x01; */ /* 1b */
size_t frame_size = (config_data >> 5) & 0x7FF; /* 11b */
size_t superframe_index = (config_data >> 3) & 0x3; /* 2b */
/* uint8_t unused = (config_data >> 0) & 0x7);*/ /* 3b */
superframe_size = ((frame_size+1) << superframe_index);
frames_per_superframe = (1 << superframe_index);
@ -250,14 +250,14 @@ static int atrac9_parse_config(uint32_t atrac9_config, int *out_sample_rate, int
if (sync != 0xFE)
goto fail;
if (out_sample_rate)
*out_sample_rate = sample_rate_table[sample_rate_index];
if (out_channels)
*out_channels = channel_table[channels_index];
if (out_frame_size)
*out_frame_size = superframe_size;
if (out_samples_per_frame)
*out_samples_per_frame = samples_per_superframe;
if (p_sample_rate)
*p_sample_rate = sample_rate_table[sample_rate_index];
if (p_channels)
*p_channels = channel_table[channels_index];
if (p_frame_size)
*p_frame_size = superframe_size;
if (p_samples_per_frame)
*p_samples_per_frame = samples_per_superframe;
return 1;
fail:
@ -268,9 +268,9 @@ size_t atrac9_bytes_to_samples(size_t bytes, atrac9_codec_data* data) {
return bytes / data->info.superframeSize * (data->info.frameSamples * data->info.framesInSuperframe);
}
size_t atrac9_bytes_to_samples_cfg(size_t bytes, uint32_t atrac9_config) {
size_t atrac9_bytes_to_samples_cfg(size_t bytes, uint32_t config_data) {
size_t frame_size, samples_per_frame;
if (!atrac9_parse_config(atrac9_config, NULL, NULL, &frame_size, &samples_per_frame))
if (!atrac9_parse_config(config_data, NULL, NULL, &frame_size, &samples_per_frame))
return 0;
return bytes / frame_size * samples_per_frame;
}

View File

@ -67,7 +67,7 @@ celt_codec_data* init_celt_fsb(int channels, celt_lib_t version) {
goto fail;
}
data->sample_buffer = calloc(sizeof(sample), data->channel_mode * FSB_CELT_SAMPLES_PER_FRAME);
data->sample_buffer = calloc(data->channel_mode * FSB_CELT_SAMPLES_PER_FRAME, sizeof(sample_t));
if (!data->sample_buffer) goto fail;
/* there is ~128 samples of encoder delay, but FMOD DLLs don't discard it? */
@ -103,7 +103,7 @@ void decode_celt_fsb(VGMSTREAM* vgmstream, sample_t* outbuf, int32_t samples_to_
memcpy(outbuf + samples_done*channels,
data->sample_buffer + data->samples_used*channels,
samples_to_get*channels * sizeof(sample));
samples_to_get*channels * sizeof(sample_t));
samples_done += samples_to_get;
}
@ -158,7 +158,7 @@ void decode_celt_fsb(VGMSTREAM* vgmstream, sample_t* outbuf, int32_t samples_to_
decode_fail:
/* on error just put some 0 samples */
VGM_LOG("CELT: decode fail at %x, missing %i samples\n", (uint32_t)stream->offset, (samples_to_do - samples_done));
memset(outbuf + samples_done * channels, 0, (samples_to_do - samples_done) * sizeof(sample) * channels);
memset(outbuf + samples_done * channels, 0, (samples_to_do - samples_done) * sizeof(sample_t) * channels);
}
void reset_celt_fsb(celt_codec_data* data) {

View File

@ -592,7 +592,7 @@ void reset_atrac9(atrac9_codec_data* data);
void seek_atrac9(VGMSTREAM* vgmstream, int32_t num_sample);
void free_atrac9(atrac9_codec_data* data);
size_t atrac9_bytes_to_samples(size_t bytes, atrac9_codec_data* data);
size_t atrac9_bytes_to_samples_cfg(size_t bytes, uint32_t atrac9_config);
size_t atrac9_bytes_to_samples_cfg(size_t bytes, uint32_t config_data);
#endif
@ -767,4 +767,4 @@ int mpc_get_samples(STREAMFILE* sf, off_t offset, int32_t* p_samples, int32_t* p
/* helper to pass a wrapped, clamped, fake extension-ed, SF to another meta */
STREAMFILE* setup_subfile_streamfile(STREAMFILE* sf, offv_t subfile_offset, size_t subfile_size, const char* extension);
#endif /*_CODING_H*/
#endif

View File

@ -18,7 +18,7 @@ static const int derf_steps[96] = {
};
/* Xilam DERF DPCM for Stupid Invaders (PC), decompiled from the exe */
void decode_derf(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
void decode_derf(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
int i, sample_pos = 0, index;
int32_t hist = stream->adpcm_history1_32;
off_t frame_offset = stream->offset; /* frame size is 1 */

View File

@ -113,7 +113,7 @@ void decode_ea_xas_v1(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspa
/* EA-XAS v0 (xas0), without complex layouts and closer to EA-XA. Somewhat based on daemon1's decoder. */
void decode_ea_xas_v0(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
void decode_ea_xas_v0(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
uint8_t frame[0x13] = {0};
off_t frame_offset;
int frames_in, samples_done = 0, sample_count = 0;

View File

@ -772,19 +772,29 @@ static void copy_samples(ffmpeg_codec_data* data, sample_t* outbuf, int samples_
switch (data->codecCtx->sample_fmt) {
/* unused? */
case AV_SAMPLE_FMT_U8P: if (is_planar) { samples_u8p_to_s16(outbuf, ibuf, channels, samples_to_do, data->samples_consumed); break; }
// fall through
case AV_SAMPLE_FMT_U8: samples_u8_to_s16(outbuf, ibuf, channels, samples_to_do, data->samples_consumed); break;
/* common */
case AV_SAMPLE_FMT_S16P: if (is_planar) { samples_s16p_to_s16(outbuf, ibuf, channels, samples_to_do, data->samples_consumed); break; }
// fall through
case AV_SAMPLE_FMT_S16: samples_s16_to_s16(outbuf, ibuf, channels, samples_to_do, data->samples_consumed); break;
/* possibly FLAC and other lossless codecs */
case AV_SAMPLE_FMT_S32P: if (is_planar) { samples_s32p_to_s16(outbuf, ibuf, channels, samples_to_do, data->samples_consumed); break; }
// fall through
case AV_SAMPLE_FMT_S32: samples_s32_to_s16(outbuf, ibuf, channels, samples_to_do, data->samples_consumed); break;
/* mainly MDCT-like codecs (Ogg, AAC, etc) */
case AV_SAMPLE_FMT_FLTP: if (is_planar) { samples_fltp_to_s16(outbuf, ibuf, channels, samples_to_do, data->samples_consumed, data->invert_floats_set); break; }
// fall through
case AV_SAMPLE_FMT_FLT: samples_flt_to_s16(outbuf, ibuf, channels, samples_to_do, data->samples_consumed, data->invert_floats_set); break;
/* possibly PCM64 only (not enabled) */
case AV_SAMPLE_FMT_DBLP: if (is_planar) { samples_dblp_to_s16(outbuf, ibuf, channels, samples_to_do, data->samples_consumed); break; }
// fall through
case AV_SAMPLE_FMT_DBL: samples_dbl_to_s16(outbuf, ibuf, channels, samples_to_do, data->samples_consumed); break;
default:
break;
}

View File

@ -22,7 +22,7 @@ static int ffmpeg_make_riff_atrac3(uint8_t* buf, size_t buf_size, size_t sample_
put_u16le(buf+0x14, 0x0270); /* ATRAC3 codec */
put_u16le(buf+0x16, channels);
put_u32le(buf+0x18, sample_rate);
put_u32le(buf+0x1c, sample_rate * channels / sizeof(sample)); /* average bytes per second (wrong) */
put_u32le(buf+0x1c, sample_rate * channels / sizeof(sample_t)); /* average bytes per second (wrong) */
put_u16le(buf+0x20, block_align); /* block align */
put_u16le(buf+0x24, 0x0e); /* extra data size */
@ -215,7 +215,7 @@ static int ffmpeg_make_riff_atrac3plus(uint8_t* buf, int buf_size, uint32_t data
put_u16le(buf+0x14, 0xfffe); /* WAVEFORMATEXTENSIBLE */
put_u16le(buf+0x16, channels);
put_u32le(buf+0x18, sample_rate);
put_u32le(buf+0x1c, sample_rate * channels / sizeof(sample)); /* average bytes per second (wrong) */
put_u32le(buf+0x1c, sample_rate * channels / sizeof(sample_t)); /* average bytes per second (wrong) */
put_u32le(buf+0x20, block_align); /* block align */
put_u16le(buf+0x24, 0x22); /* extra data size */
@ -417,7 +417,7 @@ static int ffmpeg_make_riff_xma1(uint8_t* buf, size_t buf_size, size_t data_size
}
}
put_u32le(buf+off+0x00, sample_rate*stream_channels / sizeof(sample)); /* average bytes per second (wrong, unneeded) */
put_u32le(buf+off+0x00, sample_rate*stream_channels / sizeof(sample_t)); /* average bytes per second (wrong, unneeded) */
put_u32le(buf+off+0x04, sample_rate);
put_u32le(buf+off+0x08, 0); /* loop start */
put_u32le(buf+off+0x0c, 0); /* loop end */
@ -477,7 +477,7 @@ static int ffmpeg_make_riff_xma2(uint8_t* buf, size_t buf_size, size_t data_size
default: speakers = 0; break;
}
bytecount = sample_count * channels * sizeof(sample);
bytecount = sample_count * channels * sizeof(sample_t);
memcpy (buf+0x00, "RIFF", 0x04);
put_u32le(buf+0x04, buf_max - (0x04 * 2) + data_size); /* riff size */
@ -488,8 +488,8 @@ static int ffmpeg_make_riff_xma2(uint8_t* buf, size_t buf_size, size_t data_size
put_u16le(buf+0x14, 0x0166); /* XMA2 */
put_u16le(buf+0x16, channels);
put_u32le(buf+0x18, sample_rate);
put_u32le(buf+0x1c, sample_rate * channels / sizeof(sample)); /* average bytes per second (wrong, unneeded) */
put_u16le(buf+0x20, (uint16_t)(channels * sizeof(sample))); /* block align */
put_u32le(buf+0x1c, sample_rate * channels / sizeof(sample_t)); /* average bytes per second (wrong, unneeded) */
put_u16le(buf+0x20, (uint16_t)(channels * sizeof(sample_t))); /* block align */
put_u16le(buf+0x22, 16); /* bits per sample */
put_u16le(buf+0x24, 0x22); /* extra data size */

View File

@ -65,24 +65,24 @@ quan(
*/
static int
fmult(
int an,
int srn)
int an,
int srn)
{
short anmag, anexp, anmant;
short wanexp, wanmant;
short retval;
short anmag, anexp, anmant;
short wanexp, wanmant;
short retval;
anmag = (an > 0) ? an : ((-an) & 0x1FFF);
anexp = quan(anmag, power2, 15) - 6;
anmant = (anmag == 0) ? 32 :
(anexp >= 0) ? anmag >> anexp : anmag << -anexp;
wanexp = anexp + ((srn >> 6) & 0xF) - 13;
anmag = (an > 0) ? an : ((-an) & 0x1FFF);
anexp = quan(anmag, power2, 15) - 6;
anmant = (anmag == 0) ? 32 :
(anexp >= 0) ? anmag >> anexp : anmag << -anexp;
wanexp = anexp + ((srn >> 6) & 0xF) - 13;
wanmant = (anmant * (srn & 077) + 0x30) >> 4;
retval = (wanexp >= 0) ? ((wanmant << wanexp) & 0x7FFF) :
(wanmant >> -wanexp);
wanmant = (anmant * (srn & 077) + 0x30) >> 4;
retval = (wanexp >= 0) ? ((wanmant << wanexp) & 0x7FFF) :
(wanmant >> -wanexp);
return (((an ^ srn) < 0) ? -retval : retval);
return (((an ^ srn) < 0) ? -retval : retval);
}
/*
@ -94,25 +94,25 @@ fmult(
*/
void
g72x_init_state(
struct g72x_state *state_ptr)
struct g72x_state *state_ptr)
{
int cnta;
int cnta;
state_ptr->yl = 34816;
state_ptr->yu = 544;
state_ptr->dms = 0;
state_ptr->dml = 0;
state_ptr->ap = 0;
for (cnta = 0; cnta < 2; cnta++) {
state_ptr->a[cnta] = 0;
state_ptr->pk[cnta] = 0;
state_ptr->sr[cnta] = 32;
}
for (cnta = 0; cnta < 6; cnta++) {
state_ptr->b[cnta] = 0;
state_ptr->dq[cnta] = 32;
}
state_ptr->td = 0;
state_ptr->yl = 34816;
state_ptr->yu = 544;
state_ptr->dms = 0;
state_ptr->dml = 0;
state_ptr->ap = 0;
for (cnta = 0; cnta < 2; cnta++) {
state_ptr->a[cnta] = 0;
state_ptr->pk[cnta] = 0;
state_ptr->sr[cnta] = 32;
}
for (cnta = 0; cnta < 6; cnta++) {
state_ptr->b[cnta] = 0;
state_ptr->dq[cnta] = 32;
}
state_ptr->td = 0;
}
/*
@ -123,15 +123,15 @@ g72x_init_state(
*/
static int
predictor_zero(
struct g72x_state *state_ptr)
struct g72x_state *state_ptr)
{
int i;
int sezi;
int i;
int sezi;
sezi = fmult(state_ptr->b[0] >> 2, state_ptr->dq[0]);
for (i = 1; i < 6; i++) /* ACCUM */
sezi += fmult(state_ptr->b[i] >> 2, state_ptr->dq[i]);
return (sezi);
sezi = fmult(state_ptr->b[0] >> 2, state_ptr->dq[0]);
for (i = 1; i < 6; i++) /* ACCUM */
sezi += fmult(state_ptr->b[i] >> 2, state_ptr->dq[i]);
return (sezi);
}
/*
* predictor_pole()
@ -141,10 +141,10 @@ predictor_zero(
*/
static int
predictor_pole(
struct g72x_state *state_ptr)
struct g72x_state *state_ptr)
{
return (fmult(state_ptr->a[1] >> 2, state_ptr->sr[1]) +
fmult(state_ptr->a[0] >> 2, state_ptr->sr[0]));
return (fmult(state_ptr->a[1] >> 2, state_ptr->sr[1]) +
fmult(state_ptr->a[0] >> 2, state_ptr->sr[0]));
}
/*
* step_size()
@ -154,24 +154,24 @@ predictor_pole(
*/
static int
step_size(
struct g72x_state *state_ptr)
struct g72x_state *state_ptr)
{
int y;
int dif;
int al;
int y;
int dif;
int al;
if (state_ptr->ap >= 256)
return (state_ptr->yu);
else {
y = state_ptr->yl >> 6;
dif = state_ptr->yu - y;
al = state_ptr->ap >> 2;
if (dif > 0)
y += (dif * al) >> 6;
else if (dif < 0)
y += (dif * al + 0x3F) >> 6;
return (y);
}
if (state_ptr->ap >= 256)
return (state_ptr->yu);
else {
y = state_ptr->yl >> 6;
dif = state_ptr->yu - y;
al = state_ptr->ap >> 2;
if (dif > 0)
y += (dif * al) >> 6;
else if (dif < 0)
y += (dif * al + 0x3F) >> 6;
return (y);
}
}
/*
@ -183,25 +183,25 @@ step_size(
*/
static int
reconstruct(
int sign, /* 0 for non-negative value */
int dqln, /* G.72x codeword */
int y) /* Step size multiplier */
int sign, /* 0 for non-negative value */
int dqln, /* G.72x codeword */
int y) /* Step size multiplier */
{
short dql; /* Log of 'dq' magnitude */
short dex; /* Integer part of log */
short dqt;
short dq; /* Reconstructed difference signal sample */
short dql; /* Log of 'dq' magnitude */
short dex; /* Integer part of log */
short dqt;
short dq; /* Reconstructed difference signal sample */
dql = dqln + (y >> 2); /* ADDA */
dql = dqln + (y >> 2); /* ADDA */
if (dql < 0) {
return ((sign) ? -0x8000 : 0);
} else { /* ANTILOG */
dex = (dql >> 7) & 15;
dqt = 128 + (dql & 127);
dq = (dqt << 7) >> (14 - dex);
return ((sign) ? (dq - 0x8000) : dq);
}
if (dql < 0) {
return ((sign) ? -0x8000 : 0);
} else { /* ANTILOG */
dex = (dql >> 7) & 15;
dqt = 128 + (dql & 127);
dq = (dqt << 7) >> (14 - dex);
return ((sign) ? (dq - 0x8000) : dq);
}
}
@ -212,212 +212,212 @@ reconstruct(
*/
static void
update(
/*int code_size,*/ /* distinguish 723_40 with others */
int y, /* quantizer step size */
int wi, /* scale factor multiplier */
int fi, /* for long/short term energies */
int dq, /* quantized prediction difference */
int sr, /* reconstructed signal */
int dqsez, /* difference from 2-pole predictor */
struct g72x_state *state_ptr) /* coder state pointer */
/*int code_size,*/ /* distinguish 723_40 with others */
int y, /* quantizer step size */
int wi, /* scale factor multiplier */
int fi, /* for long/short term energies */
int dq, /* quantized prediction difference */
int sr, /* reconstructed signal */
int dqsez, /* difference from 2-pole predictor */
struct g72x_state *state_ptr) /* coder state pointer */
{
int cnt;
short mag, exp; /* Adaptive predictor, FLOAT A */
short a2p; /* LIMC */
short a1ul; /* UPA1 */
short pks1; /* UPA2 */
short fa1;
char tr; /* tone/transition detector */
short ylint, thr2, dqthr;
short ylfrac, thr1;
short pk0;
int cnt;
short mag, exp; /* Adaptive predictor, FLOAT A */
short a2p; /* LIMC */
short a1ul; /* UPA1 */
short pks1; /* UPA2 */
short fa1;
char tr; /* tone/transition detector */
short ylint, thr2, dqthr;
short ylfrac, thr1;
short pk0;
pk0 = (dqsez < 0) ? 1 : 0; /* needed in updating predictor poles */
pk0 = (dqsez < 0) ? 1 : 0; /* needed in updating predictor poles */
mag = dq & 0x7FFF; /* prediction difference magnitude */
/* TRANS */
ylint = state_ptr->yl >> 15; /* exponent part of yl */
ylfrac = (state_ptr->yl >> 10) & 0x1F; /* fractional part of yl */
thr1 = (32 + ylfrac) << ylint; /* threshold */
thr2 = (ylint > 9) ? 31 << 10 : thr1; /* limit thr2 to 31 << 10 */
dqthr = (thr2 + (thr2 >> 1)) >> 1; /* dqthr = 0.75 * thr2 */
if (state_ptr->td == 0) /* signal supposed voice */
tr = 0;
else if (mag <= dqthr) /* supposed data, but small mag */
tr = 0; /* treated as voice */
else /* signal is data (modem) */
tr = 1;
mag = dq & 0x7FFF; /* prediction difference magnitude */
/* TRANS */
ylint = state_ptr->yl >> 15; /* exponent part of yl */
ylfrac = (state_ptr->yl >> 10) & 0x1F; /* fractional part of yl */
thr1 = (32 + ylfrac) << ylint; /* threshold */
thr2 = (ylint > 9) ? 31 << 10 : thr1; /* limit thr2 to 31 << 10 */
dqthr = (thr2 + (thr2 >> 1)) >> 1; /* dqthr = 0.75 * thr2 */
if (state_ptr->td == 0) /* signal supposed voice */
tr = 0;
else if (mag <= dqthr) /* supposed data, but small mag */
tr = 0; /* treated as voice */
else /* signal is data (modem) */
tr = 1;
/*
* Quantizer scale factor adaptation.
*/
/*
* Quantizer scale factor adaptation.
*/
/* FUNCTW & FILTD & DELAY */
/* update non-steady state step size multiplier */
state_ptr->yu = y + ((wi - y) >> 5);
/* FUNCTW & FILTD & DELAY */
/* update non-steady state step size multiplier */
state_ptr->yu = y + ((wi - y) >> 5);
/* LIMB */
if (state_ptr->yu < 544) /* 544 <= yu <= 5120 */
state_ptr->yu = 544;
else if (state_ptr->yu > 5120)
state_ptr->yu = 5120;
/* LIMB */
if (state_ptr->yu < 544) /* 544 <= yu <= 5120 */
state_ptr->yu = 544;
else if (state_ptr->yu > 5120)
state_ptr->yu = 5120;
/* FILTE & DELAY */
/* update steady state step size multiplier */
state_ptr->yl += state_ptr->yu + ((-state_ptr->yl) >> 6);
/* FILTE & DELAY */
/* update steady state step size multiplier */
state_ptr->yl += state_ptr->yu + ((-state_ptr->yl) >> 6);
/*
* Adaptive predictor coefficients.
*/
if (tr == 1) { /* reset a's and b's for modem signal */
state_ptr->a[0] = 0;
state_ptr->a[1] = 0;
state_ptr->b[0] = 0;
state_ptr->b[1] = 0;
state_ptr->b[2] = 0;
state_ptr->b[3] = 0;
state_ptr->b[4] = 0;
state_ptr->b[5] = 0;
/*
* Adaptive predictor coefficients.
*/
if (tr == 1) { /* reset a's and b's for modem signal */
state_ptr->a[0] = 0;
state_ptr->a[1] = 0;
state_ptr->b[0] = 0;
state_ptr->b[1] = 0;
state_ptr->b[2] = 0;
state_ptr->b[3] = 0;
state_ptr->b[4] = 0;
state_ptr->b[5] = 0;
a2p=0; /* won't be used, clear warning */
} else { /* update a's and b's */
pks1 = pk0 ^ state_ptr->pk[0]; /* UPA2 */
} else { /* update a's and b's */
pks1 = pk0 ^ state_ptr->pk[0]; /* UPA2 */
/* update predictor pole a[1] */
a2p = state_ptr->a[1] - (state_ptr->a[1] >> 7);
if (dqsez != 0) {
fa1 = (pks1) ? state_ptr->a[0] : -state_ptr->a[0];
if (fa1 < -8191) /* a2p = function of fa1 */
a2p -= 0x100;
else if (fa1 > 8191)
a2p += 0xFF;
else
a2p += fa1 >> 5;
/* update predictor pole a[1] */
a2p = state_ptr->a[1] - (state_ptr->a[1] >> 7);
if (dqsez != 0) {
fa1 = (pks1) ? state_ptr->a[0] : -state_ptr->a[0];
if (fa1 < -8191) /* a2p = function of fa1 */
a2p -= 0x100;
else if (fa1 > 8191)
a2p += 0xFF;
else
a2p += fa1 >> 5;
if (pk0 ^ state_ptr->pk[1])
/* LIMC */
if (a2p <= -12160)
a2p = -12288;
else if (a2p >= 12416)
a2p = 12288;
else
a2p -= 0x80;
else if (a2p <= -12416)
a2p = -12288;
else if (a2p >= 12160)
a2p = 12288;
else
a2p += 0x80;
}
/* TRIGB & DELAY */
state_ptr->a[1] = a2p;
/* UPA1 */
/* update predictor pole a[0] */
state_ptr->a[0] -= state_ptr->a[0] >> 8;
if (dqsez != 0) {
if (pks1 == 0)
state_ptr->a[0] += 192;
else
state_ptr->a[0] -= 192;
if (pk0 ^ state_ptr->pk[1])
/* LIMC */
if (a2p <= -12160)
a2p = -12288;
else if (a2p >= 12416)
a2p = 12288;
else
a2p -= 0x80;
else if (a2p <= -12416)
a2p = -12288;
else if (a2p >= 12160)
a2p = 12288;
else
a2p += 0x80;
}
/* LIMD */
a1ul = 15360 - a2p;
if (state_ptr->a[0] < -a1ul)
state_ptr->a[0] = -a1ul;
else if (state_ptr->a[0] > a1ul)
state_ptr->a[0] = a1ul;
/* TRIGB & DELAY */
state_ptr->a[1] = a2p;
/* UPB : update predictor zeros b[6] */
for (cnt = 0; cnt < 6; cnt++) {
/*if (code_size == 5)*/ /* for 40Kbps G.723 */
/* state_ptr->b[cnt] -= state_ptr->b[cnt] >> 9;*/
/*else*/ /* for G.721 and 24Kbps G.723 */
state_ptr->b[cnt] -= state_ptr->b[cnt] >> 8;
if (dq & 0x7FFF) { /* XOR */
if ((dq ^ state_ptr->dq[cnt]) >= 0)
state_ptr->b[cnt] += 128;
else
state_ptr->b[cnt] -= 128;
}
}
}
/* UPA1 */
/* update predictor pole a[0] */
state_ptr->a[0] -= state_ptr->a[0] >> 8;
if (dqsez != 0) {
if (pks1 == 0)
state_ptr->a[0] += 192;
else
state_ptr->a[0] -= 192;
}
for (cnt = 5; cnt > 0; cnt--)
state_ptr->dq[cnt] = state_ptr->dq[cnt-1];
/* FLOAT A : convert dq[0] to 4-bit exp, 6-bit mantissa f.p. */
if (mag == 0) {
state_ptr->dq[0] = (dq >= 0) ? 0x20 : 0xFC20;
} else {
exp = quan(mag, power2, 15);
state_ptr->dq[0] = (dq >= 0) ?
(exp << 6) + ((mag << 6) >> exp) :
(exp << 6) + ((mag << 6) >> exp) - 0x400;
}
/* LIMD */
a1ul = 15360 - a2p;
if (state_ptr->a[0] < -a1ul)
state_ptr->a[0] = -a1ul;
else if (state_ptr->a[0] > a1ul)
state_ptr->a[0] = a1ul;
state_ptr->sr[1] = state_ptr->sr[0];
/* FLOAT B : convert sr to 4-bit exp., 6-bit mantissa f.p. */
if (sr == 0) {
state_ptr->sr[0] = 0x20;
} else if (sr > 0) {
exp = quan(sr, power2, 15);
state_ptr->sr[0] = (exp << 6) + ((sr << 6) >> exp);
} else if (sr > -32768) {
mag = -sr;
exp = quan(mag, power2, 15);
state_ptr->sr[0] = (exp << 6) + ((mag << 6) >> exp) - 0x400;
} else
state_ptr->sr[0] = 0xFC20;
/* UPB : update predictor zeros b[6] */
for (cnt = 0; cnt < 6; cnt++) {
/*if (code_size == 5)*/ /* for 40Kbps G.723 */
/* state_ptr->b[cnt] -= state_ptr->b[cnt] >> 9;*/
/*else*/ /* for G.721 and 24Kbps G.723 */
state_ptr->b[cnt] -= state_ptr->b[cnt] >> 8;
if (dq & 0x7FFF) { /* XOR */
if ((dq ^ state_ptr->dq[cnt]) >= 0)
state_ptr->b[cnt] += 128;
else
state_ptr->b[cnt] -= 128;
}
}
}
/* DELAY A */
state_ptr->pk[1] = state_ptr->pk[0];
state_ptr->pk[0] = pk0;
for (cnt = 5; cnt > 0; cnt--)
state_ptr->dq[cnt] = state_ptr->dq[cnt-1];
/* FLOAT A : convert dq[0] to 4-bit exp, 6-bit mantissa f.p. */
if (mag == 0) {
state_ptr->dq[0] = (dq >= 0) ? 0x20 : 0xFC20;
} else {
exp = quan(mag, power2, 15);
state_ptr->dq[0] = (dq >= 0) ?
(exp << 6) + ((mag << 6) >> exp) :
(exp << 6) + ((mag << 6) >> exp) - 0x400;
}
/* TONE */
if (tr == 1) /* this sample has been treated as data */
state_ptr->td = 0; /* next one will be treated as voice */
else if (a2p < -11776) /* small sample-to-sample correlation */
state_ptr->td = 1; /* signal may be data */
else /* signal is voice */
state_ptr->td = 0;
state_ptr->sr[1] = state_ptr->sr[0];
/* FLOAT B : convert sr to 4-bit exp., 6-bit mantissa f.p. */
if (sr == 0) {
state_ptr->sr[0] = 0x20;
} else if (sr > 0) {
exp = quan(sr, power2, 15);
state_ptr->sr[0] = (exp << 6) + ((sr << 6) >> exp);
} else if (sr > -32768) {
mag = -sr;
exp = quan(mag, power2, 15);
state_ptr->sr[0] = (exp << 6) + ((mag << 6) >> exp) - 0x400;
} else
state_ptr->sr[0] = 0xFC20;
/*
* Adaptation speed control.
*/
state_ptr->dms += (fi - state_ptr->dms) >> 5; /* FILTA */
state_ptr->dml += (((fi << 2) - state_ptr->dml) >> 7); /* FILTB */
/* DELAY A */
state_ptr->pk[1] = state_ptr->pk[0];
state_ptr->pk[0] = pk0;
if (tr == 1)
state_ptr->ap = 256;
else if (y < 1536) /* SUBTC */
state_ptr->ap += (0x200 - state_ptr->ap) >> 4;
else if (state_ptr->td == 1)
state_ptr->ap += (0x200 - state_ptr->ap) >> 4;
else if (abs((state_ptr->dms << 2) - state_ptr->dml) >=
(state_ptr->dml >> 3))
state_ptr->ap += (0x200 - state_ptr->ap) >> 4;
else
state_ptr->ap += (-state_ptr->ap) >> 4;
/* TONE */
if (tr == 1) /* this sample has been treated as data */
state_ptr->td = 0; /* next one will be treated as voice */
else if (a2p < -11776) /* small sample-to-sample correlation */
state_ptr->td = 1; /* signal may be data */
else /* signal is voice */
state_ptr->td = 0;
/*
* Adaptation speed control.
*/
state_ptr->dms += (fi - state_ptr->dms) >> 5; /* FILTA */
state_ptr->dml += (((fi << 2) - state_ptr->dml) >> 7); /* FILTB */
if (tr == 1)
state_ptr->ap = 256;
else if (y < 1536) /* SUBTC */
state_ptr->ap += (0x200 - state_ptr->ap) >> 4;
else if (state_ptr->td == 1)
state_ptr->ap += (0x200 - state_ptr->ap) >> 4;
else if (abs((state_ptr->dms << 2) - state_ptr->dml) >=
(state_ptr->dml >> 3))
state_ptr->ap += (0x200 - state_ptr->ap) >> 4;
else
state_ptr->ap += (-state_ptr->ap) >> 4;
}
/*
* Maps G.721 code word to reconstructed scale factor normalized log
* magnitude values.
*/
static short _dqlntab[16] = {-2048, 4, 135, 213, 273, 323, 373, 425,
425, 373, 323, 273, 213, 135, 4, -2048};
static short _dqlntab[16] = {-2048, 4, 135, 213, 273, 323, 373, 425,
425, 373, 323, 273, 213, 135, 4, -2048};
/* Maps G.721 code word to log of scale factor multiplier. */
static short _witab[16] = {-12, 18, 41, 64, 112, 198, 355, 1122,
1122, 355, 198, 112, 64, 41, 18, -12};
static short _witab[16] = {-12, 18, 41, 64, 112, 198, 355, 1122,
1122, 355, 198, 112, 64, 41, 18, -12};
/*
* Maps G.721 code words to a set of values whose long and short
* term averages are computed and then compared to give an indication
* how stationary (steady state) the signal is.
*/
static short _fitab[16] = {0, 0, 0, 0x200, 0x200, 0x200, 0x600, 0xE00,
0xE00, 0x600, 0x200, 0x200, 0x200, 0, 0, 0};
static short _fitab[16] = {0, 0, 0, 0x200, 0x200, 0x200, 0x600, 0xE00,
0xE00, 0x600, 0x200, 0x200, 0x200, 0, 0, 0};
/*
* g721_decoder()
*
@ -429,39 +429,39 @@ static short _fitab[16] = {0, 0, 0, 0x200, 0x200, 0x200, 0x600, 0xE00,
*/
static int
g721_decoder(
int i,
struct g72x_state *state_ptr)
int i,
struct g72x_state *state_ptr)
{
short sezi, sei, sez, se; /* ACCUM */
short y; /* MIX */
short sr; /* ADDB */
short dq;
short dqsez;
short sezi, sei, sez, se; /* ACCUM */
short y; /* MIX */
short sr; /* ADDB */
short dq;
short dqsez;
i &= 0x0f; /* mask to get proper bits */
sezi = predictor_zero(state_ptr);
sez = sezi >> 1;
sei = sezi + predictor_pole(state_ptr);
se = sei >> 1; /* se = estimated signal */
i &= 0x0f; /* mask to get proper bits */
sezi = predictor_zero(state_ptr);
sez = sezi >> 1;
sei = sezi + predictor_pole(state_ptr);
se = sei >> 1; /* se = estimated signal */
y = step_size(state_ptr); /* dynamic quantizer step size */
y = step_size(state_ptr); /* dynamic quantizer step size */
dq = reconstruct(i & 0x08, _dqlntab[i], y); /* quantized diff. */
dq = reconstruct(i & 0x08, _dqlntab[i], y); /* quantized diff. */
sr = (dq < 0) ? (se - (dq & 0x3FFF)) : se + dq; /* reconst. signal */
sr = (dq < 0) ? (se - (dq & 0x3FFF)) : se + dq; /* reconst. signal */
dqsez = sr - se + sez; /* pole prediction diff. */
dqsez = sr - se + sez; /* pole prediction diff. */
update(y, _witab[i] << 5, _fitab[i], dq, sr, dqsez, state_ptr);
update(y, _witab[i] << 5, _fitab[i], dq, sr, dqsez, state_ptr);
return (sr << 2); /* sr was 14-bit dynamic range */
return (sr << 2); /* sr was 14-bit dynamic range */
}
void decode_g721(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
void decode_g721(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
int i;
int32_t sample_count;
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
for (i = first_sample, sample_count = 0; i < first_sample + samples_to_do; i++, sample_count += channelspacing) {
outbuf[sample_count]=
g721_decoder(
read_8bit(stream->offset+i/2,stream->streamfile)>>(i&1?4:0),

View File

@ -95,7 +95,7 @@ void decode_hca(hca_codec_data* data, sample_t* outbuf, int32_t samples_to_do) {
memcpy(outbuf + samples_done*channels,
data->sample_buffer + data->samples_consumed*channels,
samples_to_get*channels * sizeof(sample));
samples_to_get*channels * sizeof(sample_t));
samples_done += samples_to_get;
}
@ -110,7 +110,7 @@ void decode_hca(hca_codec_data* data, sample_t* outbuf, int32_t samples_to_do) {
/* EOF/error */
if (data->current_block >= data->info.blockCount) {
memset(outbuf, 0, (samples_to_do - samples_done) * channels * sizeof(sample));
memset(outbuf, 0, (samples_to_do - samples_done) * channels * sizeof(sample_t));
break;
}

View File

@ -1113,14 +1113,14 @@ void decode_ubi_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspa
/* write PCM samples, must be written to match header's num_samples (hist mustn't) */
max_samples_to_do = ((samples_to_do > header_samples) ? header_samples : samples_to_do);
for (i = first_sample; i < max_samples_to_do; i++, sample_count += channelspacing) {
outbuf[sample_count] = read_16bit(offset + channel*sizeof(sample) + i*channelspacing*sizeof(sample),stream->streamfile);
outbuf[sample_count] = read_16bit(offset + channel * sizeof(sample_t) + i*channelspacing * sizeof(sample_t), stream->streamfile);
first_sample++;
samples_to_do--;
}
/* header done */
if (i == header_samples) {
stream->offset = offset + header_samples*channelspacing*sizeof(sample);
stream->offset = offset + header_samples*channelspacing * sizeof(sample_t);
}
}

View File

@ -1,13 +1,15 @@
#include "coding.h"
#include "../util.h"
/* AKA iShiftVal__8snd_strm */
static const int32_t l5_scales[32] = {
0x00001000, 0x0000144E, 0x000019C5, 0x000020B4, 0x00002981, 0x000034AC, 0x000042D9, 0x000054D6,
0x00006BAB, 0x000088A4, 0x0000AD69, 0x0000DC13, 0x0001174C, 0x00016275, 0x0001C1D8, 0x00023AE5,
0x0002D486, 0x0003977E, 0x00048EEE, 0x0005C8F3, 0x00075779, 0x0009513E, 0x000BD31C, 0x000F01B5,
0x00130B82, 0x00182B83, 0x001EAC92, 0x0026EDB2, 0x00316777, 0x003EB2E6, 0x004F9232, 0x0064FBD1
0x00130B82, 0x00182B83, 0x001EAC92, 0x0026EDB2, 0x00316777, 0x003EB2E6, 0x004F9232, 0x0064FBD1,
};
/* reverse engineered from exe (SLPM_624.90's DecAdpcm__8snd_strmFRQ28snd_strm10SOUND_HEADiPsPUci / SLUS_212.07's @258D70)*/
void decode_l5_555(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
uint8_t frame[0x12] = {0};
off_t frame_offset;
@ -31,7 +33,7 @@ void decode_l5_555(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacin
/* parse frame header */
frame_offset = stream->offset + bytes_per_frame * frames_in;
read_streamfile(frame, frame_offset, bytes_per_frame, stream->streamfile); /* ignore EOF errors */
header = get_u32le(frame);
header = get_u16le(frame);
coef_index = (header >> 10) & 0x1f;
pos_scale = l5_scales[(header >> 5) & 0x1f];
neg_scale = l5_scales[(header >> 0) & 0x1f];
@ -41,18 +43,19 @@ void decode_l5_555(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacin
coef3 = stream->adpcm_coef_3by32[coef_index * 3 + 2];
for (i = first_sample; i < first_sample + samples_to_do; i++) {
int32_t prediction, sample = 0;
/* sample is 64b in PS2 registers, though encoder probably won't let it get too high */
int32_t prediction, sample;
uint8_t nibbles = frame[0x02 + i/2];
sample = (i&1) ?
get_low_nibble_signed(nibbles):
get_high_nibble_signed(nibbles);
prediction = -(hist1 * coef1 + hist2 * coef2 + hist3 * coef3);
prediction = (hist1 * coef1 + hist2 * coef2 + hist3 * coef3);
if (sample >= 0)
sample = (prediction + sample * pos_scale) >> 12;
sample = (sample * pos_scale - prediction) >> 12;
else
sample = (prediction + sample * neg_scale) >> 12;
sample = (sample * neg_scale - prediction) >> 12;
sample = clamp16(sample);
outbuf[sample_count] = sample;

File diff suppressed because it is too large Load Diff

View File

@ -4,24 +4,24 @@
typedef struct TCompressWaveData TCompressWaveData;
void TCompressWaveData_GetLoopState(TCompressWaveData* this);
void TCompressWaveData_SetLoopState(TCompressWaveData* this);
void TCompressWaveData_GetLoopState(TCompressWaveData* self);
void TCompressWaveData_SetLoopState(TCompressWaveData* self);
TCompressWaveData* TCompressWaveData_Create(void);
void TCompressWaveData_Free(TCompressWaveData* this);
int TCompressWaveData_Rendering(TCompressWaveData* this, int16_t* buf, uint32_t Len);
int TCompressWaveData_LoadFromStream(TCompressWaveData* this, STREAMFILE* ss);
void TCompressWaveData_SetCipherCode(TCompressWaveData* this, uint32_t Num);
void TCompressWaveData_Free(TCompressWaveData* self);
int TCompressWaveData_Rendering(TCompressWaveData* self, int16_t* buf, uint32_t Len);
int TCompressWaveData_LoadFromStream(TCompressWaveData* self, STREAMFILE* ss);
void TCompressWaveData_SetCipherCode(TCompressWaveData* self, uint32_t Num);
void TCompressWaveData_Play(TCompressWaveData* this, int loop);
void TCompressWaveData_Stop(TCompressWaveData* this);
void TCompressWaveData_Previous(TCompressWaveData* this);
void TCompressWaveData_Pause(TCompressWaveData* this);
void TCompressWaveData_SetVolume(TCompressWaveData* this, float vol, float fade);
float TCompressWaveData_GetVolume(TCompressWaveData* this);
float TCompressWaveData_GetSetVolume(TCompressWaveData* this);
float TCompressWaveData_GetFade(TCompressWaveData* this);
float TCompressWaveData_GetPlayTime(TCompressWaveData* this);
float TCompressWaveData_GetTotalTime(TCompressWaveData* this);
void TCompressWaveData_Play(TCompressWaveData* self, int loop);
void TCompressWaveData_Stop(TCompressWaveData* self);
void TCompressWaveData_Previous(TCompressWaveData* self);
void TCompressWaveData_Pause(TCompressWaveData* self);
void TCompressWaveData_SetVolume(TCompressWaveData* self, float vol, float fade);
float TCompressWaveData_GetVolume(TCompressWaveData* self);
float TCompressWaveData_GetSetVolume(TCompressWaveData* self);
float TCompressWaveData_GetFade(TCompressWaveData* self);
float TCompressWaveData_GetPlayTime(TCompressWaveData* self);
float TCompressWaveData_GetTotalTime(TCompressWaveData* self);
#endif /*_COMPRESSWAVE_LIB_H */

View File

@ -1072,7 +1072,7 @@ static int unpack_frame(int bit_rate, const uint8_t* data, int frame_size, /*int
if (test_errors) {
int max_pad_bytes = 0x8; /* usually 0x04 and rarely ~0x08 */
int bits_left = 8 * expected_frame_size - bitpos;
int i, endpos, test_bits;
int endpos, test_bits;
if (bits_left > 0) {

View File

@ -205,7 +205,7 @@ static int getbits(const uint8_t** p_data, int* shift, int bits) {
// NWADecode
static void decode_block(NWAData* nwa, const uint8_t* data, int outdatasize) {
sample d[2];
short d[2];
int i;
int shift = 0;

View File

@ -1252,9 +1252,9 @@ int tac_decode_frame(tac_handle_t* handle, const uint8_t* block) {
static inline int16_t clamp16f(float sample) {
if (sample > 32767.0)
if (sample > 32767.0f)
return 32767;
else if (sample < -32768.0)
else if (sample < -32768.0f)
return -32768;
return (int16_t)sample;
}

View File

@ -154,7 +154,7 @@ fail:
}
static void convert_samples(INT_PCM * src, sample * dest, int32_t count) {
static void convert_samples(INT_PCM * src, sample_t* dest, int32_t count) {
int32_t i;
for ( i = 0; i < count; i++ ) {
INT_PCM sample = *src++;
@ -164,7 +164,7 @@ static void convert_samples(INT_PCM * src, sample * dest, int32_t count) {
}
}
void decode_mp4_aac(mp4_aac_codec_data * data, sample * outbuf, int32_t samples_to_do, int channels) {
void decode_mp4_aac(mp4_aac_codec_data * data, sample_t* outbuf, int32_t samples_to_do, int channels) {
int samples_done = 0;
uint8_t * buffer = NULL;
@ -199,7 +199,7 @@ void decode_mp4_aac(mp4_aac_codec_data * data, sample * outbuf, int32_t samples_
while ( samples_done < samples_to_do ) {
if (data->sampleId >= data->numSamples) {
memset(outbuf, 0, (samples_to_do - samples_done) * stream_info->numChannels * sizeof(sample));
memset(outbuf, 0, (samples_to_do - samples_done) * stream_info->numChannels * sizeof(sample_t));
break;
}
if (!MP4ReadSample( data->h_mp4file, data->track_id, ++data->sampleId, (uint8_t**)(&buffer), (uint32_t*)(&buffer_size), 0, 0, 0, 0)) return;

View File

@ -670,20 +670,20 @@ static void ealayer3_copy_pcm_block(uint8_t* outbuf, off_t pcm_offset, int pcm_n
int16_t pcm_sample = get_s16be(pcm_block + pos);
put_s16le(outbuf + pos, pcm_sample);
pos += sizeof(sample);
pos += sizeof(sample_t);
}
}
else {
/* all of ch0 first, then all of ch1 (EAL3 v1b only) */
int get_pos = 0;
for (ch = 0; ch < channels_per_frame; ch++) {
int put_pos = sizeof(sample) * ch;
int put_pos = sizeof(sample_t) * ch;
for (i = 0; i < pcm_number; i++) {
int16_t pcm_sample = get_s16be(pcm_block + get_pos);
put_s16le(outbuf + put_pos, pcm_sample);
get_pos += sizeof(sample);
put_pos += sizeof(sample) * channels_per_frame;
get_pos += sizeof(sample_t);
put_pos += sizeof(sample_t) * channels_per_frame;
}
}
}
@ -697,7 +697,7 @@ static int ealayer3_write_pcm_block(VGMSTREAMCHANNEL* stream, mpeg_codec_data* d
size_t bytes_filled;
bytes_filled = sizeof(sample) * ms->samples_filled * channels_per_frame;
bytes_filled = sizeof(sample_t) * ms->samples_filled * channels_per_frame;
if (bytes_filled + eaf->pcm_size > ms->output_buffer_size) {
VGM_LOG("EAL3: can't fill the sample buffer with 0x%x\n", eaf->pcm_size);
goto fail;

View File

@ -130,7 +130,7 @@ static int eamp3_write_pcm_block(VGMSTREAMCHANNEL *stream, mpeg_codec_data *data
int i;
bytes_filled = sizeof(sample) * ms->samples_filled * data->channels_per_frame;
bytes_filled = sizeof(sample_t) * ms->samples_filled * data->channels_per_frame;
if (bytes_filled + eaf->pcm_size > ms->output_buffer_size) {
VGM_LOG("EAMP3: can't fill the sample buffer with 0x%x\n", eaf->pcm_size);
goto fail;
@ -141,9 +141,9 @@ static int eamp3_write_pcm_block(VGMSTREAMCHANNEL *stream, mpeg_codec_data *data
/* read + write PCM block samples (always LE) */
for (i = 0; i < eaf->pcm_number * data->channels_per_frame; i++) {
off_t pcm_offset = stream->offset + eaf->pre_size + eaf->mpeg_size + sizeof(sample)*i;
off_t pcm_offset = stream->offset + eaf->pre_size + eaf->mpeg_size + sizeof(sample_t)*i;
int16_t pcm_sample = read_s16le(pcm_offset,stream->streamfile);
put_s16le(ms->output_buffer + bytes_filled + sizeof(sample) * i, pcm_sample);
put_s16le(ms->output_buffer + bytes_filled + sizeof(sample_t) * i, pcm_sample);
}
ms->samples_filled += eaf->pcm_number;

View File

@ -23,7 +23,7 @@ mpeg_codec_data* init_mpeg(STREAMFILE* sf, off_t start_offset, coding_t* coding_
if (!data) goto fail;
data->buffer_size = MPEG_DATA_BUFFER_SIZE;
data->buffer = calloc(sizeof(uint8_t), data->buffer_size);
data->buffer = calloc(data->buffer_size, sizeof(uint8_t));
if (!data->buffer) goto fail;
data->m = init_mpg123_handle();
@ -170,13 +170,13 @@ mpeg_codec_data* init_mpeg_custom(STREAMFILE* sf, off_t start_offset, coding_t*
if (!data->streams[i].handle) goto fail;
/* size could be any value */
data->streams[i].output_buffer_size = sizeof(sample) * data->channels_per_frame * data->samples_per_frame;
data->streams[i].output_buffer_size = sizeof(sample_t) * data->channels_per_frame * data->samples_per_frame;
data->streams[i].output_buffer = calloc(data->streams[i].output_buffer_size, sizeof(uint8_t));
if (!data->streams[i].output_buffer) goto fail;
/* one per stream as sometimes mpg123 can't read the whole buffer in one pass */
data->streams[i].buffer_size = data->default_buffer_size;
data->streams[i].buffer = calloc(sizeof(uint8_t), data->streams[i].buffer_size);
data->streams[i].buffer = calloc(data->streams[i].buffer_size, sizeof(uint8_t));
if (!data->streams[i].buffer) goto fail;
data->streams[i].channels_per_frame = data->channels_per_frame;
@ -260,7 +260,7 @@ static void decode_mpeg_standard(VGMSTREAMCHANNEL* stream, mpeg_codec_data* data
/* end of stream, fill rest with 0s */
if (data->bytes_in_buffer <= 0) {
VGM_ASSERT(samples_to_do < samples_done, "MPEG: end of stream, filling %i\n", (samples_to_do - samples_done));
memset(outbuf + samples_done * channels, 0, (samples_to_do - samples_done) * channels * sizeof(sample));
memset(outbuf + samples_done * channels, 0, (samples_to_do - samples_done) * channels * sizeof(sample_t));
break;
}
@ -270,7 +270,7 @@ static void decode_mpeg_standard(VGMSTREAMCHANNEL* stream, mpeg_codec_data* data
stream->offset += data->bytes_in_buffer;
}
bytes_to_do = (samples_to_do-samples_done)*sizeof(sample)*channels;
bytes_to_do = (samples_to_do-samples_done)*sizeof(sample_t)*channels;
/* feed new raw data to the decoder if needed, copy decoded results to output */
if (!data->buffer_used) {
@ -288,7 +288,7 @@ static void decode_mpeg_standard(VGMSTREAMCHANNEL* stream, mpeg_codec_data* data
VGM_ASSERT(rc != MPG123_NEED_MORE && rc != MPG123_OK, "MPEG: error %i\n", rc);
/* update copied samples */
samples_done += bytes_done/sizeof(sample)/channels;
samples_done += bytes_done / sizeof(sample_t) / channels;
outbytes += bytes_done;
}
}
@ -430,7 +430,7 @@ static void decode_mpeg_custom_stream(VGMSTREAMCHANNEL* stream, mpeg_codec_data*
}
bytes_filled = sizeof(sample) * ms->samples_filled * channels_per_frame;
bytes_filled = sizeof(sample_t) * ms->samples_filled * channels_per_frame;
/* feed new raw data to the decoder if needed, copy decoded results to frame buffer output */
if (!ms->buffer_used) {
//;VGM_LOG("MPEG: feed new data and get samples\n");
@ -447,7 +447,7 @@ static void decode_mpeg_custom_stream(VGMSTREAMCHANNEL* stream, mpeg_codec_data*
(unsigned char*)ms->output_buffer + bytes_filled, ms->output_buffer_size - bytes_filled,
&bytes_done);
}
samples_filled = (bytes_done / sizeof(sample) / channels_per_frame);
samples_filled = (bytes_done / sizeof(sample_t) / channels_per_frame);
/* discard for weird features (EALayer3 and PCM blocks, AWC and repeated frames) */
if (ms->decode_to_discard) {
@ -455,7 +455,7 @@ static void decode_mpeg_custom_stream(VGMSTREAMCHANNEL* stream, mpeg_codec_data*
size_t decode_to_discard = ms->decode_to_discard;
if (decode_to_discard > samples_filled)
decode_to_discard = samples_filled;
bytes_to_discard = sizeof(sample) * decode_to_discard * channels_per_frame;
bytes_to_discard = sizeof(sample_t) * decode_to_discard * channels_per_frame;
bytes_done -= bytes_to_discard;
ms->decode_to_discard -= decode_to_discard;
@ -478,9 +478,9 @@ static void decode_mpeg_custom_stream(VGMSTREAMCHANNEL* stream, mpeg_codec_data*
decode_fail:
/* 0-fill but continue with other streams */
bytes_filled = ms->samples_filled * channels_per_frame * sizeof(sample);
bytes_filled = ms->samples_filled * channels_per_frame * sizeof(sample_t);
memset(ms->output_buffer + bytes_filled, 0, ms->output_buffer_size - bytes_filled);
ms->samples_filled = (ms->output_buffer_size / channels_per_frame / sizeof(sample));
ms->samples_filled = (ms->output_buffer_size / channels_per_frame / sizeof(sample_t));
}

View File

@ -219,7 +219,7 @@ void decode_ogg_vorbis(ogg_vorbis_codec_data* data, sample_t* outbuf, int32_t sa
(char *)(outbuf), /* buffer */
(samples_to_do - samples_done) * sizeof(sample_t) * channels, /* length in bytes */
0, /* pcm endianness */
sizeof(sample), /* pcm size */
sizeof(sample_t), /* pcm size */
1, /* pcm signedness */
&data->bitstream); /* bitstream */
if (rc <= 0) goto fail; /* rc is bytes done (for all channels) */
@ -234,7 +234,7 @@ void decode_ogg_vorbis(ogg_vorbis_codec_data* data, sample_t* outbuf, int32_t sa
return;
fail:
VGM_LOG("OGG: error %lx during decode\n", rc);
memset(outbuf, 0, (samples_to_do - samples_done) * channels * sizeof(sample));
memset(outbuf, 0, (samples_to_do - samples_done) * channels * sizeof(sample_t));
}
/* vorbis encodes channels in non-standard order, so we remap during conversion to fix this oddity.

View File

@ -20,134 +20,134 @@
/* ADPCM table */
static const float hevag_coefs_f[128][4] = {
{-0.0, -0.0, -0.0, -0.0 },
{ 0.9375, -0.0, -0.0, -0.0 },
{ 1.796875, -0.8125, -0.0, -0.0 },
{ 1.53125, -0.859375, -0.0, -0.0 },
{ 1.90625, -0.9375, -0.0, -0.0 },
{ 1.7982178, -0.86169434, -0.0, -0.0 },
{ 1.770874, -0.89916992, -0.0, -0.0 },
{ 1.6992188, -0.91821289, -0.0, -0.0 },
{ 1.6031494, -0.9375, -0.0, -0.0 },
{ 1.4682617, -0.9375, -0.0, -0.0 },
{ 1.3139648, -0.9375, -0.0, -0.0 },
{ 1.1424561, -0.9375, -0.0, -0.0 },
{ 0.95605469, -0.9375, -0.0, -0.0 },
{ 0.75695801, -0.9375, -0.0, -0.0 },
{ 0.54785156, -0.9375, -0.0, -0.0 },
{ 0.33166504, -0.9375, -0.0, -0.0 },
{ 0.11108398, -0.9375, -0.0, -0.0 },
{-0.11108398, -0.9375, -0.0, -0.0 },
{-0.33166504, -0.9375, -0.0, -0.0 },
{-0.54785156, -0.9375, -0.0, -0.0 },
{-0.75695801, -0.9375, -0.0, -0.0 },
{-0.95605469, -0.9375, -0.0, -0.0 },
{-1.1424561, -0.9375, -0.0, -0.0 },
{-1.3139648, -0.9375, -0.0, -0.0 },
{-1.4682617, -0.9375, -0.0, -0.0 },
{-1.6031494, -0.9375, -0.0, -0.0 },
{-1.6992188, -0.91821289, -0.0, -0.0 },
{-1.770874, -0.89916992, -0.0, -0.0 },
{-1.7982178, -0.86169434, -0.0, -0.0 },
{ 0.65625, -1.125, 0.40625, -0.375 },
{-0.78125, -0.875, -0.40625, -0.28125 },
{-1.28125, -0.90625, -0.4375, -0.125 },
{-0.020385742, -0.33227539, -0.060302734, -0.066040039 },
{-0.90698242, -0.27111816, -0.28051758, 0.051757812 },
{-0.97668457, -0.38647461, -0.34350586, 0.03527832 },
{ 0.73461914, -0.57983398, 0.32336426, -0.15844727 },
{ 0.46362305, -0.84790039, 0.47302246, -0.1484375 },
{-1.0054932, -0.31689453, -0.25280762, 0.027709961 },
{ 1.1229248, 0.24194336, -0.16870117, -0.28271484 },
{ 1.5894775, -0.37158203, -0.46289062, 0.15466309 },
{ 1.6005859, -0.54772949, -0.2746582, 0.20324707 },
{-0.20361328, -0.45703125, -0.78808594, 0.10253906 },
{ 0.95446777, -0.52832031, 0.25769043, -0.061767578 },
{ 1.168335, -0.16308594, -0.092407227, 0.059448242 },
{ 1.2246094, -0.31274414, 0.036621094, 0.024291992 },
{-0.57922363, -0.50317383, -0.66967773, -0.18225098 },
{-0.71972656, 0.2902832, -0.58435059, -0.84802246 },
{-0.14562988, -1.112915, -0.15100098, -0.38012695 },
{ 0.33972168, -0.86767578, -0.19226074, -0.17663574 },
{-0.89526367, -0.25170898, -0.27001953, 0.054443359 },
{ 0.7479248, -0.3145752, -0.038452148, -0.0021972656 },
{ 1.1544189, -0.22680664, 0.012451172, 0.031494141 },
{ 0.96142578, -0.54724121, 0.25952148, -0.065673828 },
{-0.87548828, -0.21911621, -0.25256348, 0.058837891 },
{-0.89819336, -0.2565918, -0.27258301, 0.053710938 },
{-1.1193848, -0.42834473, -0.32641602, -0.047729492 },
{-0.32202148, -0.32312012, -0.23547363, -0.1998291 },
{ 0.2286377, 1.1209717, 0.22705078, -0.70141602 },
{ 1.1247559, 0.22692871, -0.13720703, -0.29626465 },
{ 1.6118164, -0.36767578, -0.50524902, 0.16723633 },
{ 1.5181885, -0.58496094, -0.03125, 0.075927734 },
{-0.32385254, -0.13964844, -0.38842773, -0.83959961 },
{ 1.1390381, -0.12792969, -0.10107422, 0.061889648 },
{ 0.20043945, -0.075683594, -0.11547852, -0.51623535 },
{ 0.51831055, -0.92590332, -0.065063477, -0.27575684 },
{-1.097168, -0.47497559, -0.34265137, 0.0053710938 },
{-0.31274414, -0.3338623, -0.21118164, -0.23181152 },
{ 0.38842773, -0.058959961, -0.087158203, -0.17346191 },
{ 0.96887207, -0.46923828, 0.34436035, -0.12438965 },
{ 1.229126, -0.31848145, 0.038330078, 0.023803711 },
{ 1.0253906, -0.40246582, 0.18933105, -0.018920898 },
{-1.0411377, -0.33874512, -0.296875, -0.041015625 },
{ 1.1568604, -0.22973633, 0.013183594, 0.03125 },
{ 0.0091552734, -0.27355957, -0.036376953, -0.84680176 },
{-1.1160889, -0.5078125, -0.36169434, 0.00061035156 },
{-0.88745117, -0.23901367, -0.26318359, 0.056152344 },
{-0.33447266, 0.45715332, 0.72460938, -0.13293457 },
{ 1.0977783, 0.23779297, -0.083374023, -0.33007812 },
{ 1.5992432, -0.34606934, -0.47045898, 0.12878418 },
{ 1.164917, -0.23937988, 0.015869141, 0.030517578 },
{ 0.64355469, -0.52124023, 0.38134766, -0.38537598 },
{-0.93945312, -0.41296387, -0.3548584, -0.055664062 },
{ 0.89221191, 0.3079834, 0.052978516, -0.30041504 },
{ 1.2542725, -0.34997559, 0.047729492, 0.020996094 },
{ 1.3354492, -0.45422363, 0.081176758, 0.01184082 },
{ 0.0029296875, -0.037841797, -0.15405273, 0.0390625 },
{-0.99145508, -0.29431152, -0.28210449, -0.033081055 },
{-1.0389404, -0.37438965, -0.28527832, 0.019897461 },
{ 0.039794922, -0.46948242, 0.051147461, -0.1138916 },
{ 1.0858154, 0.26782227, -0.066040039, -0.3515625 },
{ 1.4737549, -0.22900391, -0.24621582, -0.073364258 },
{ 1.0655518, -0.41784668, 0.2043457, -0.020629883 },
{ 1.5808105, -0.46960449, -0.36706543, 0.23754883 },
{ 1.2253418, -0.3137207, 0.036865234, 0.024169922 },
{ 1.1456299, -0.33654785, 0.12304688, 0.0050048828 },
{-0.57617188, -0.61108398, -0.34814453, -0.14172363 },
{ 0.96057129, -0.52807617, 0.26062012, -0.061157227 },
{ 0.29907227, -1.0494385, 0.15856934, -0.33935547 },
{ 1.2441406, -0.33728027, 0.043945312, 0.022094727 },
{ 1.3809814, -0.51428223, 0.10168457, 0.0064697266 },
{ 1.239502, -0.33154297, 0.042114258, 0.022583008 },
{ 1.1765137, -0.17297363, -0.08996582, 0.058837891 },
{ 0.47045898, -0.5559082, 0.3470459, -0.41467285 },
{ 0.81774902, -0.6907959, 0.27453613, -0.13110352 },
{ 1.3527832, -0.47705078, 0.088867188, 0.009765625 },
{-0.12524414, -1.1975098, -0.098266602, -0.42260742 },
{ 1.269043, -0.45727539, 0.16687012, -0.01171875 },
{ 1.2557373, 0.12060547, -0.23376465, -0.17541504 },
{ 0.9708252, 0.47338867, -0.093261719, -0.39831543 },
{ 1.5489502, -0.4119873, -0.40942383, 0.25378418 },
{ 0.81066895, 0.38647461, 0.028198242, -0.25500488 },
{-0.28662109, -0.89770508, -0.23730469, -0.50317383 },
{ 1.1340332, -0.49304199, 0.23010254, -0.030029297 },
{ 0.56555176, -0.78161621, 0.21337891, -0.19763184 },
{ 1.3729248, -0.50354004, 0.097900391, 0.0074462891 },
{ 1.1971436, -0.27880859, 0.026733398, 0.027099609 },
{ 1.1884766, -0.1875, -0.086181641, 0.057739258 },
{ 1.0302734, -0.41943359, 0.19067383, -0.021484375 },
{ 1.1361084, -0.12463379, -0.10192871, 0.062133789 },
{ 0.20727539, -1.1016846, 0.083984375, -0.37072754 },
{ 1.2468262, -0.34069824, 0.044921875, 0.021850586 },
{ 1.0241699, 0.39648438, -0.092529297, -0.36486816 },
{ 0.87902832, 0.40478516, 0.0056152344, -0.3190918 },
{-0.010742188, -0.95324707, -0.065673828, -0.5579834 },
{ 0.75598145, -0.63342285, 0.33691406, -0.15197754 },
{ 1.5045166, -0.1574707, -0.40087891, 0.030883789 },
{ 1.5947266, -0.49743652, -0.34472656, 0.22912598 },
{ 0.65100098, 0.36608887, 0.094604492, -0.13818359 },
{-0.0f, -0.0f, -0.0f, -0.0f },
{ 0.9375f, -0.0f, -0.0f, -0.0f },
{ 1.796875f, -0.8125f, -0.0f, -0.0f },
{ 1.53125f, -0.859375f, -0.0f, -0.0f },
{ 1.90625f, -0.9375f, -0.0f, -0.0f },
{ 1.7982178f, -0.86169434f, -0.0f, -0.0f },
{ 1.770874f, -0.89916992f, -0.0f, -0.0f },
{ 1.6992188f, -0.91821289f, -0.0f, -0.0f },
{ 1.6031494f, -0.9375f, -0.0f, -0.0f },
{ 1.4682617f, -0.9375f, -0.0f, -0.0f },
{ 1.3139648f, -0.9375f, -0.0f, -0.0f },
{ 1.1424561f, -0.9375f, -0.0f, -0.0f },
{ 0.95605469f, -0.9375f, -0.0f, -0.0f },
{ 0.75695801f, -0.9375f, -0.0f, -0.0f },
{ 0.54785156f, -0.9375f, -0.0f, -0.0f },
{ 0.33166504f, -0.9375f, -0.0f, -0.0f },
{ 0.11108398f, -0.9375f, -0.0f, -0.0f },
{-0.11108398f, -0.9375f, -0.0f, -0.0f },
{-0.33166504f, -0.9375f, -0.0f, -0.0f },
{-0.54785156f, -0.9375f, -0.0f, -0.0f },
{-0.75695801f, -0.9375f, -0.0f, -0.0f },
{-0.95605469f, -0.9375f, -0.0f, -0.0f },
{-1.1424561f, -0.9375f, -0.0f, -0.0f },
{-1.3139648f, -0.9375f, -0.0f, -0.0f },
{-1.4682617f, -0.9375f, -0.0f, -0.0f },
{-1.6031494f, -0.9375f, -0.0f, -0.0f },
{-1.6992188f, -0.91821289f, -0.0f, -0.0f },
{-1.770874f, -0.89916992f, -0.0f, -0.0f },
{-1.7982178f, -0.86169434f, -0.0f, -0.0f },
{ 0.65625f, -1.125f, 0.40625f, -0.375f },
{-0.78125f, -0.875f, -0.40625f, -0.28125f },
{-1.28125f, -0.90625f, -0.4375f, -0.125f },
{-0.020385742f, -0.33227539f, -0.060302734f, -0.066040039f },
{-0.90698242f, -0.27111816f, -0.28051758f, 0.051757812f },
{-0.97668457f, -0.38647461f, -0.34350586f, 0.03527832f },
{ 0.73461914f, -0.57983398f, 0.32336426f, -0.15844727f },
{ 0.46362305f, -0.84790039f, 0.47302246f, -0.1484375f },
{-1.0054932f, -0.31689453f, -0.25280762f, 0.027709961f },
{ 1.1229248f, 0.24194336f, -0.16870117f, -0.28271484f },
{ 1.5894775f, -0.37158203f, -0.46289062f, 0.15466309f },
{ 1.6005859f, -0.54772949f, -0.2746582f, 0.20324707f },
{-0.20361328f, -0.45703125f, -0.78808594f, 0.10253906f },
{ 0.95446777f, -0.52832031f, 0.25769043f, -0.061767578f },
{ 1.168335f, -0.16308594f, -0.092407227f, 0.059448242f },
{ 1.2246094f, -0.31274414f, 0.036621094f, 0.024291992f },
{-0.57922363f, -0.50317383f, -0.66967773f, -0.18225098f },
{-0.71972656f, 0.2902832f, -0.58435059f, -0.84802246f },
{-0.14562988f, -1.112915f, -0.15100098f, -0.38012695f },
{ 0.33972168f, -0.86767578f, -0.19226074f, -0.17663574f },
{-0.89526367f, -0.25170898f, -0.27001953f, 0.054443359f },
{ 0.7479248f, -0.3145752f, -0.038452148f, -0.0021972656f },
{ 1.1544189f, -0.22680664f, 0.012451172f, 0.031494141f },
{ 0.96142578f, -0.54724121f, 0.25952148f, -0.065673828f },
{-0.87548828f, -0.21911621f, -0.25256348f, 0.058837891f },
{-0.89819336f, -0.2565918f, -0.27258301f, 0.053710938f },
{-1.1193848f, -0.42834473f, -0.32641602f, -0.047729492f },
{-0.32202148f, -0.32312012f, -0.23547363f, -0.1998291f },
{ 0.2286377f, 1.1209717f, 0.22705078f, -0.70141602f },
{ 1.1247559f, 0.22692871f, -0.13720703f, -0.29626465f },
{ 1.6118164f, -0.36767578f, -0.50524902f, 0.16723633f },
{ 1.5181885f, -0.58496094f, -0.03125f, 0.075927734f },
{-0.32385254f, -0.13964844f, -0.38842773f, -0.83959961f },
{ 1.1390381f, -0.12792969f, -0.10107422f, 0.061889648f },
{ 0.20043945f, -0.075683594f, -0.11547852f, -0.51623535f },
{ 0.51831055f, -0.92590332f, -0.065063477f, -0.27575684f },
{-1.097168f, -0.47497559f, -0.34265137f, 0.0053710938f },
{-0.31274414f, -0.3338623f, -0.21118164f, -0.23181152f },
{ 0.38842773f, -0.058959961f, -0.087158203f, -0.17346191f },
{ 0.96887207f, -0.46923828f, 0.34436035f, -0.12438965f },
{ 1.229126f, -0.31848145f, 0.038330078f, 0.023803711f },
{ 1.0253906f, -0.40246582f, 0.18933105f, -0.018920898f },
{-1.0411377f, -0.33874512f, -0.296875f, -0.041015625f },
{ 1.1568604f, -0.22973633f, 0.013183594f, 0.03125f },
{ 0.0091552734f, -0.27355957f, -0.036376953f, -0.84680176f },
{-1.1160889f, -0.5078125f, -0.36169434f, 0.00061035156f },
{-0.88745117f, -0.23901367f, -0.26318359f, 0.056152344f },
{-0.33447266f, 0.45715332f, 0.72460938f, -0.13293457f },
{ 1.0977783f, 0.23779297f, -0.083374023f, -0.33007812f },
{ 1.5992432f, -0.34606934f, -0.47045898f, 0.12878418f },
{ 1.164917f, -0.23937988f, 0.015869141f, 0.030517578f },
{ 0.64355469f, -0.52124023f, 0.38134766f, -0.38537598f },
{-0.93945312f, -0.41296387f, -0.3548584f, -0.055664062f },
{ 0.89221191f, 0.3079834f, 0.052978516f, -0.30041504f },
{ 1.2542725f, -0.34997559f, 0.047729492f, 0.020996094f },
{ 1.3354492f, -0.45422363f, 0.081176758f, 0.01184082f },
{ 0.0029296875f, -0.037841797f, -0.15405273f, 0.0390625f },
{-0.99145508f, -0.29431152f, -0.28210449f, -0.033081055f },
{-1.0389404f, -0.37438965f, -0.28527832f, 0.019897461f },
{ 0.039794922f, -0.46948242f, 0.051147461f, -0.1138916f },
{ 1.0858154f, 0.26782227f, -0.066040039f, -0.3515625f },
{ 1.4737549f, -0.22900391f, -0.24621582f, -0.073364258f },
{ 1.0655518f, -0.41784668f, 0.2043457f, -0.020629883f },
{ 1.5808105f, -0.46960449f, -0.36706543f, 0.23754883f },
{ 1.2253418f, -0.3137207f, 0.036865234f, 0.024169922f },
{ 1.1456299f, -0.33654785f, 0.12304688f, 0.0050048828f },
{-0.57617188f, -0.61108398f, -0.34814453f, -0.14172363f },
{ 0.96057129f, -0.52807617f, 0.26062012f, -0.061157227f },
{ 0.29907227f, -1.0494385f, 0.15856934f, -0.33935547f },
{ 1.2441406f, -0.33728027f, 0.043945312f, 0.022094727f },
{ 1.3809814f, -0.51428223f, 0.10168457f, 0.0064697266f },
{ 1.239502f, -0.33154297f, 0.042114258f, 0.022583008f },
{ 1.1765137f, -0.17297363f, -0.08996582f, 0.058837891f },
{ 0.47045898f, -0.5559082f, 0.3470459f, -0.41467285f },
{ 0.81774902f, -0.6907959f, 0.27453613f, -0.13110352f },
{ 1.3527832f, -0.47705078f, 0.088867188f, 0.009765625f },
{-0.12524414f, -1.1975098f, -0.098266602f, -0.42260742f },
{ 1.269043f, -0.45727539f, 0.16687012f, -0.01171875f },
{ 1.2557373f, 0.12060547f, -0.23376465f, -0.17541504f },
{ 0.9708252f, 0.47338867f, -0.093261719f, -0.39831543f },
{ 1.5489502f, -0.4119873f, -0.40942383f, 0.25378418f },
{ 0.81066895f, 0.38647461f, 0.028198242f, -0.25500488f },
{-0.28662109f, -0.89770508f, -0.23730469f, -0.50317383f },
{ 1.1340332f, -0.49304199f, 0.23010254f, -0.030029297f },
{ 0.56555176f, -0.78161621f, 0.21337891f, -0.19763184f },
{ 1.3729248f, -0.50354004f, 0.097900391f, 0.0074462891f },
{ 1.1971436f, -0.27880859f, 0.026733398f, 0.027099609f },
{ 1.1884766f, -0.1875f, -0.086181641f, 0.057739258f },
{ 1.0302734f, -0.41943359f, 0.19067383f, -0.021484375f },
{ 1.1361084f, -0.12463379f, -0.10192871f, 0.062133789f },
{ 0.20727539f, -1.1016846f, 0.083984375f, -0.37072754f },
{ 1.2468262f, -0.34069824f, 0.044921875f, 0.021850586f },
{ 1.0241699f, 0.39648438f, -0.092529297f, -0.36486816f },
{ 0.87902832f, 0.40478516f, 0.0056152344f, -0.3190918f },
{-0.010742188f, -0.95324707f, -0.065673828f, -0.5579834f },
{ 0.75598145f, -0.63342285f, 0.33691406f, -0.15197754f },
{ 1.5045166f, -0.1574707f, -0.40087891f, 0.030883789f },
{ 1.5947266f, -0.49743652f, -0.34472656f, 0.22912598f },
{ 0.65100098f, 0.36608887f, 0.094604492f, -0.13818359f },
};
#if 0

View File

@ -3,23 +3,23 @@
/* PS-ADPCM table, defined as rational numbers (as in the spec) */
static const float ps_adpcm_coefs_f[16][2] = {
{ 0.0 , 0.0 }, //{ 0.0 , 0.0 },
{ 0.9375 , 0.0 }, //{ 60.0 / 64.0 , 0.0 },
{ 1.796875 , -0.8125 }, //{ 115.0 / 64.0 , -52.0 / 64.0 },
{ 1.53125 , -0.859375 }, //{ 98.0 / 64.0 , -55.0 / 64.0 },
{ 1.90625 , -0.9375 }, //{ 122.0 / 64.0 , -60.0 / 64.0 },
{ 0.0f , 0.0f }, //{ 0.0 , 0.0 },
{ 0.9375f , 0.0f }, //{ 60.0 / 64.0 , 0.0 },
{ 1.796875f , -0.8125f }, //{ 115.0 / 64.0 , -52.0 / 64.0 },
{ 1.53125f , -0.859375f }, //{ 98.0 / 64.0 , -55.0 / 64.0 },
{ 1.90625f , -0.9375f }, //{ 122.0 / 64.0 , -60.0 / 64.0 },
/* extended table used in few PS3 games, found in ELFs */
{ 0.46875 , -0.0 }, //{ 30.0 / 64.0 , -0.0 / 64.0 },
{ 0.8984375 , -0.40625 }, //{ 57.5 / 64.0 , -26.0 / 64.0 },
{ 0.765625 , -0.4296875 }, //{ 49.0 / 64.0 , -27.5 / 64.0 },
{ 0.953125 , -0.46875 }, //{ 61.0 / 64.0 , -30.0 / 64.0 },
{ 0.234375 , -0.0 }, //{ 15.0 / 64.0 , -0.0 / 64.0 },
{ 0.44921875, -0.203125 }, //{ 28.75/ 64.0 , -13.0 / 64.0 },
{ 0.3828125 , -0.21484375}, //{ 24.5 / 64.0 , -13.75/ 64.0 },
{ 0.4765625 , -0.234375 }, //{ 30.5 / 64.0 , -15.0 / 64.0 },
{ 0.5 , -0.9375 }, //{ 32.0 / 64.0 , -60.0 / 64.0 },
{ 0.234375 , -0.9375 }, //{ 15.0 / 64.0 , -60.0 / 64.0 },
{ 0.109375 , -0.9375 }, //{ 7.0 / 64.0 , -60.0 / 64.0 },
{ 0.46875f , -0.0f }, //{ 30.0 / 64.0 , -0.0 / 64.0 },
{ 0.8984375f, -0.40625f }, //{ 57.5 / 64.0 , -26.0 / 64.0 },
{ 0.765625f , -0.4296875f }, //{ 49.0 / 64.0 , -27.5 / 64.0 },
{ 0.953125f , -0.46875f }, //{ 61.0 / 64.0 , -30.0 / 64.0 },
{ 0.234375f , -0.0f }, //{ 15.0 / 64.0 , -0.0 / 64.0 },
{ 0.44921875f,-0.203125f }, //{ 28.75/ 64.0 , -13.0 / 64.0 },
{ 0.3828125f, -0.21484375f}, //{ 24.5 / 64.0 , -13.75/ 64.0 },
{ 0.4765625f, -0.234375f }, //{ 30.5 / 64.0 , -15.0 / 64.0 },
{ 0.5f , -0.9375f }, //{ 32.0 / 64.0 , -60.0 / 64.0 },
{ 0.234375f , -0.9375f }, //{ 15.0 / 64.0 , -60.0 / 64.0 },
{ 0.109375f , -0.9375f }, //{ 7.0 / 64.0 , -60.0 / 64.0 },
};
/* PS-ADPCM table, defined as spec_coef*64 (for int implementations) */

View File

@ -92,7 +92,7 @@ void decode_relic(VGMSTREAMCHANNEL* stream, relic_codec_data* data, sample_t* ou
decode_fail:
/* on error just put some 0 samples */
VGM_LOG("RELIC: decode fail, missing %i samples\n", samples_to_do);
memset(outbuf, 0, samples_to_do * data->channels * sizeof(sample));
memset(outbuf, 0, samples_to_do * data->channels * sizeof(sample_t));
}
void reset_relic(relic_codec_data* data) {

View File

@ -4,30 +4,28 @@
/* Activision / EXAKT Entertainment's DPCM for Supercar Street Challenge */
#if 0
To build table:
int32_t bring_round(int32_t v)
{
int32_t bring_round(int32_t v) {
return v | (v >> 12);
}
for (i=0x00;i<0x20;i++)
SASSC_steps[i] = bring_round(i<<4);
sassc_steps[i] = bring_round(i<<4);
for (i=0x20;i<0x40;i++)
SASSC_steps[i] = bring_round(((i-0x20)*7+0x20)<<4);
sassc_steps[i] = bring_round(((i-0x20)*7+0x20)<<4);
for (i=0x40;i<0x60;i++)
SASSC_steps[i] = bring_round(((i-0x40)*24+0x100)<<4);
sassc_steps[i] = bring_round(((i-0x40)*24+0x100)<<4);
for (i=0x60;i<0x80;i++)
SASSC_steps[i] = bring_round(((i-0x60)*96+0x400)<<4);
sassc_steps[i] = bring_round(((i-0x60)*96+0x400)<<4);
for (i=0x80;i<0xFF;i++)
SASSC_steps[i] = -SASSC_steps[i-0x80];
sassc_steps[i] = -sassc_steps[i-0x80];
SASSC_steps[0xFF] = SASSC_steps[0x7F];
sassc_steps[0xFF] = sassc_steps[0x7F];
#endif
int32_t SASSC_steps[256] =
{
static const int32_t sassc_steps[256] = {
0, 16, 32, 48, 64, 80, 96, 112,
128, 144, 160, 176, 192, 208, 224, 240,
256, 272, 288, 304, 320, 336, 352, 368,
@ -63,13 +61,14 @@ int32_t SASSC_steps[256] =
-53261, -54797, -56333, -57870, -59406, -60942, -62479, 64015,
};
void decode_sassc(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
void decode_sassc(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
int i;
int32_t sample_count;
int32_t hist = stream->adpcm_history1_32;
for(i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
hist = hist + SASSC_steps[(uint8_t)read_8bit(stream->offset+i,stream->streamfile)];
for (i = first_sample, sample_count = 0; i < first_sample + samples_to_do; i++, sample_count += channelspacing) {
uint8_t index = read_u8(stream->offset + i, stream->streamfile);
hist = hist + sassc_steps[index];
outbuf[sample_count] = clamp16(hist);
}

View File

@ -139,8 +139,8 @@ void decode_ubi_adpcm(VGMSTREAM* vgmstream, sample_t* outbuf, int32_t samples_to
samples_to_get = samples_to_do - samples_done;
memcpy(outbuf + samples_done*channels,
data->samples + data->samples_consumed*channels,
samples_to_get*channels * sizeof(sample));
data->samples + data->samples_consumed * channels,
samples_to_get * channels * sizeof(sample_t));
samples_done += samples_to_get;
}

View File

@ -23,11 +23,11 @@ vorbis_custom_codec_data* init_vorbis_custom(STREAMFILE* sf, off_t start_offset,
int ok;
/* init stuff */
data = calloc(1,sizeof(vorbis_custom_codec_data));
data = calloc(1, sizeof(vorbis_custom_codec_data));
if (!data) goto fail;
data->buffer_size = VORBIS_DEFAULT_BUFFER_SIZE;
data->buffer = calloc(sizeof(uint8_t), data->buffer_size);
data->buffer = calloc(data->buffer_size, sizeof(uint8_t));
if (!data->buffer) goto fail;
/* keep around to decode too */
@ -165,7 +165,7 @@ void decode_vorbis_custom(VGMSTREAM* vgmstream, sample_t* outbuf, int32_t sample
decode_fail:
/* on error just put some 0 samples */
VGM_LOG("VORBIS: decode fail at %x, missing %i samples\n", (uint32_t)stream->offset, (samples_to_do - samples_done));
memset(outbuf + samples_done * channels, 0, (samples_to_do - samples_done) * channels * sizeof(sample));
memset(outbuf + samples_done * channels, 0, (samples_to_do - samples_done) * channels * sizeof(sample_t));
}
/* converts from internal Vorbis format to standard PCM (mostly from Xiph's decoder_example.c) */

View File

@ -3,135 +3,148 @@
#include "../util.h"
/* Westwood Studios ADPCM */
/* Based on Valery V. Anisimovsky's WS-AUD.txt */
static char WSTable2bit[4] = { -2,-1,0,1 };
static char WSTable4bit[16] = { -9,-8,-6,-5,-4,-3,-2,-1, 0, 1, 2, 3, 4, 5 ,6, 8 };
static char WSTable2bit[4] = { -2, -1, 0, 1 };
static char WSTable4bit[16] = { -9, -8, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 8 };
/* We pass in the VGMSTREAM here, unlike in other codings, because
the decoder has to know about the block structure. */
void decode_ws(VGMSTREAM * vgmstream, int channel, sample * outbuf, int channelspacing, int32_t first_sample,
int32_t samples_to_do) {
VGMSTREAMCHANNEL * stream = &(vgmstream->ch[channel]);
/* We pass in the VGMSTREAM here, unlike in other codings, because the decoder has to know about the block structure. */
void decode_ws(VGMSTREAM* vgmstream, int channel, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
VGMSTREAMCHANNEL* stream = &(vgmstream->ch[channel]);
STREAMFILE* sf = stream->streamfile;
int16_t hist = stream->adpcm_history1_16;
off_t offset = stream->offset;
int samples_left_in_frame = stream->samples_left_in_frame;
off_t header_off = stream->frame_header_offset;
int samples_left_in_frame = stream->ws_samples_left_in_frame;
off_t header_offset = stream->ws_frame_header_offset;
int i;
int32_t sample_count;
//int i;
int32_t sample_count = 0;
if (vgmstream->ws_output_size == vgmstream->current_block_size) {
/* uncompressed, we just need to convert to 16-bit */
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing,offset++) {
outbuf[sample_count]=((uint8_t)read_8bit(offset,stream->streamfile)-0x80)*0x100;
/* uncompressed pcm8 to pcm16 */
for (int i = first_sample; i < first_sample + samples_to_do; i++) {
outbuf[sample_count] = (read_u8(offset,sf) - 0x80) * 0x100;
sample_count += channelspacing;
offset++;
}
} else {
}
else {
if (first_sample == 0) {
hist = 0x80;
samples_left_in_frame = 0;
}
/* actually decompress */
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; ) {
uint8_t header;
uint8_t count;
/* decompress */
for (int i = first_sample; i < first_sample + samples_to_do; /* manually incremented */) {
if (samples_left_in_frame == 0) {
header_off = offset;
header_offset = offset;
offset++;
}
header = read_8bit(header_off,stream->streamfile);
count = header & 0x3f;
switch (header>>6) { /* code */
uint8_t header = read_u8(header_offset, sf);
uint8_t count = header & 0x3f;
uint8_t code = header >> 6;
switch (code) { /* code */
case 0: /* 2-bit ADPCM */
if (samples_left_in_frame == 0) {
samples_left_in_frame = (count + 1)*4;
}
for (;samples_left_in_frame>0 && /* read this frame */
i<first_sample+samples_to_do; /* up to samples_to_do */
i++,sample_count+=channelspacing, /* done with writing a sample */
samples_left_in_frame--) { /* done with reading a sample */
int twobit = ((count + 1)*4-samples_left_in_frame)%4;
uint8_t sample;
sample = read_8bit(offset,stream->streamfile);
sample = (sample >> (twobit*2)) & 0x3;
if (samples_left_in_frame == 0)
samples_left_in_frame = (count + 1) * 4;
/* read this frame up to samples_to_do */
for ( ; samples_left_in_frame>0 && i < first_sample + samples_to_do; i++) {
int twobit = ((count + 1) * 4 - samples_left_in_frame) % 4;
uint8_t sample = read_u8(offset,sf);
sample = (sample >> (twobit * 2)) & 0x3;
hist += WSTable2bit[sample];
if (hist < 0) hist = 0;
if (hist > 0xff) hist = 0xff;
outbuf[sample_count]=(hist-0x80)*0x100;
else if (hist > 0xff) hist = 0xff;
outbuf[sample_count] = (hist - 0x80) * 0x100;
sample_count += channelspacing;
samples_left_in_frame--;
if (twobit == 3)
offset++; /* done with that byte */
}
break;
case 1: /* 4-bit ADPCM */
if (samples_left_in_frame == 0) {
samples_left_in_frame = (count + 1)*2;
}
for (;samples_left_in_frame>0 && /* read this frame */
i<first_sample+samples_to_do; /* up to samples_to_do */
i++,sample_count+=channelspacing, /* done with writing a sample */
samples_left_in_frame--) { /* done with reading a sample */
int nibble = ((count + 1)*4-samples_left_in_frame)%2;
uint8_t sample;
sample = read_8bit(offset,stream->streamfile);
if (samples_left_in_frame == 0)
samples_left_in_frame = (count + 1) * 2;
/* read this frame up to samples_to_do */
for ( ; samples_left_in_frame>0 && i < first_sample + samples_to_do; i++) {
int nibble = ((count + 1) * 4 - samples_left_in_frame) % 2;
uint8_t sample = read_u8(offset, sf);
if (nibble == 0)
sample &= 0xf;
else
sample >>= 4;
hist += WSTable4bit[sample];
if (hist < 0) hist = 0;
if (hist > 0xff) hist = 0xff;
outbuf[sample_count]=(hist-0x80)*0x100;
else if (hist > 0xff) hist = 0xff;
outbuf[sample_count] = (hist - 0x80) * 0x100;
sample_count += channelspacing;
samples_left_in_frame--;
if (nibble == 1)
offset++; /* done with that byte */
}
break;
case 2: /* no compression */
if (count & 0x20) { /* delta */
/* Note no checks against samples_to_do here,
at the top of the for loop we can always do at
least one sample */
if (count & 0x20) { /* new delta */
/* Note no checks against samples_to_do here, at the top of the for loop
* we can always do at least one sample */
/* low 5 bits are a signed delta */
if (count & 0x10) {
hist -= ((count & 0xf)^0xf) + 1;
hist -= ((count & 0x0f) ^ 0x0f) + 1;
} else {
hist += count & 0xf;
hist += count & 0x0f;
}
/* Valery doesn't specify this, but I will assume */
/* Valery doesn't specify this, but clamp just in case */
if (hist < 0) hist = 0;
if (hist > 0xff) hist = 0xff;
else if (hist > 0xff) hist = 0xff;
outbuf[sample_count]=(hist-0x80)*0x100;
sample_count+=channelspacing;
i++;
/* just one, and we got it */
samples_left_in_frame = 0;
} else { /* copy bytes verbatim */
outbuf[sample_count] = (hist - 0x80) * 0x100;
sample_count += channelspacing;
samples_left_in_frame = 0; /* just one */
}
else {
/* copy bytes verbatim */
if (samples_left_in_frame == 0)
samples_left_in_frame=count+1;
for (;samples_left_in_frame>0 && /* read this frame */
i<first_sample+samples_to_do; /* up to samples_to_do */
offset++, /* done with a byte */
i++,sample_count+=channelspacing, /* done with writing a sample */
samples_left_in_frame--) { /* done with reading a sample */
outbuf[sample_count]=((hist=(uint8_t)read_8bit(offset,stream->streamfile))-0x80)*0x100;
samples_left_in_frame = (count + 1);
/* read this frame up to samples_to_do */
for ( ; samples_left_in_frame > 0 && i < first_sample + samples_to_do; i++) {
hist = read_u8(offset,sf);
offset++;
outbuf[sample_count] = (hist - 0x80) * 0x100;
sample_count += channelspacing;
samples_left_in_frame--;
}
}
break;
case 3: /* RLE */
if (samples_left_in_frame == 0)
samples_left_in_frame=count+1;
for (;samples_left_in_frame>0 && /* read this frame */
i<first_sample+samples_to_do; /* up to samples_to_do */
i++,sample_count+=channelspacing, /* done with writing a sample */
samples_left_in_frame--) { /* done with reading a sample */
outbuf[sample_count]=(hist-0x80)*0x100;
samples_left_in_frame = (count + 1);
/* read this frame up to samples_to_do */
for ( ; samples_left_in_frame > 0 && i < first_sample + samples_to_do; i++) {
outbuf[sample_count] = (hist - 0x80) * 0x100;
sample_count += channelspacing;
samples_left_in_frame--;
}
default:
break;
@ -141,6 +154,6 @@ void decode_ws(VGMSTREAM * vgmstream, int channel, sample * outbuf, int channels
stream->offset = offset;
stream->adpcm_history1_16 = hist;
stream->samples_left_in_frame = samples_left_in_frame;
stream->frame_header_offset = header_off;
stream->ws_samples_left_in_frame = samples_left_in_frame;
stream->ws_frame_header_offset = header_offset;
}

View File

@ -1,5 +1,6 @@
#include "vgmstream.h"
#include "coding/coding.h"
#include "layout/layout.h"
/* Defines the list of accepted extensions. vgmstream doesn't use it internally so it's here
@ -863,7 +864,7 @@ static const coding_info coding_info_list[] = {
{coding_NXAP, "Nex NXAP 4-bit ADPCM"},
{coding_TGC, "Tiger Game.com 4-bit ADPCM"},
{coding_NDS_PROCYON, "Procyon Studio Digital Sound Elements NDS 4-bit APDCM"},
{coding_L5_555, "Level-5 0x555 4-bit ADPCM"},
{coding_LEVEL5, "Level-5 4-bit ADPCM"},
{coding_LSF, "Gizmondo Studios Helsingborg LSF 4-bit ADPCM"},
{coding_MTAF, "Konami MTAF 4-bit ADPCM"},
{coding_MTA2, "Konami MTA2 4-bit ADPCM"},
@ -1095,7 +1096,7 @@ static const meta_info meta_info_list[] = {
{meta_RIFX_WAVE_smpl, "RIFX WAVE header (smpl looping)"},
{meta_XNB, "Microsoft XNA Game Studio header"},
{meta_SCD_PCM, "Lunar: Eternal Blue .PCM header"},
{meta_PS2_PCM, "Konami .PCM header"},
{meta_PCM_KCEJE, "Konami .PCM header"},
{meta_PS2_RKV, "Legacy of Kain - Blood Omen 2 RKV PS2 header"},
{meta_VAS_KCEO, "Konami .VAS header"},
{meta_LP_AP_LEP, "Konami LP/AP/LEP header"},
@ -1119,8 +1120,8 @@ static const meta_info meta_info_list[] = {
{meta_RSD, "Radical RSD header"},
{meta_ASD_NAXAT, "Naxat .ASD header"},
{meta_SPSD, "Sega Naomi SPSD header"},
{meta_FFXI_BGW, "Square Enix .BGW header"},
{meta_FFXI_SPW, "Square Enix .SPW header"},
{meta_BGW, "Square Enix BGMStream header"},
{meta_SPW, "Square Enix SeWave header"},
{meta_PS2_ASS, "SystemSoft .ASS header"},
{meta_NUB, "Namco NUB header"},
{meta_IDSP_NL, "Next Level IDSP header"},
@ -1167,7 +1168,7 @@ static const meta_info meta_info_list[] = {
{meta_NAOMI_ADPCM, "NAOMI/NAOMI2 Arcade games ADPCM header"},
{meta_SD9, "beatmania IIDX SD9 header"},
{meta_2DX9, "beatmania IIDX 2DX9 header"},
{meta_DSP_YGO, "Konami custom DSP Header"},
{meta_DSP_KCEJE, "Konami .DSP Header"},
{meta_PS2_VGV, "Rune: Viking Warlord VGV Header"},
{meta_GCUB, "Sega GCub header"},
{meta_NGC_SCK_DSP, "The Scorpion King SCK Header"},
@ -1237,7 +1238,7 @@ static const meta_info meta_info_list[] = {
{meta_EB_SF0, "assumed Excitebots .sf0 by extension"},
{meta_MTAF, "Konami MTAF header"},
{meta_ALP, "High Voltage ALP header"},
{meta_WPD, "WPD 'DPW' header"},
{meta_WPD, "Navel WPD header"},
{meta_MN_STR, "Mini Ninjas 'STR' header"},
{meta_MSS, "Guerilla MCSS header"},
{meta_PS2_HSF, "Lowrider 'HSF' header"},

View File

@ -233,81 +233,3 @@ void reset_layout_layered(layered_layout_data *data) {
reset_vgmstream(data->layers[i]);
}
}
/* helper for easier creation of layers */
VGMSTREAM* allocate_layered_vgmstream(layered_layout_data* data) {
VGMSTREAM* vgmstream = NULL;
int i, channels, loop_flag, sample_rate, external_looping;
int32_t num_samples, loop_start, loop_end;
int delta = 1024;
coding_t coding_type = data->layers[0]->coding_type;
/* get data */
channels = data->output_channels;
num_samples = 0;
loop_flag = 1;
loop_start = data->layers[0]->loop_start_sample;
loop_end = data->layers[0]->loop_end_sample;
external_looping = 0;
sample_rate = 0;
for (i = 0; i < data->layer_count; i++) {
int32_t layer_samples = vgmstream_get_samples(data->layers[i]);
int layer_loop = data->layers[i]->loop_flag;
int32_t layer_loop_start = data->layers[i]->loop_start_sample;
int32_t layer_loop_end = data->layers[i]->loop_end_sample;
int layer_rate = data->layers[i]->sample_rate;
/* internal has own config (and maybe looping), looping now must be done on layout level
* (instead of on each layer, that is faster) */
if (data->layers[i]->config_enabled) {
loop_flag = 0;
layer_loop = 0;
external_looping = 1;
}
/* all layers should share loop pointsto consider looping enabled,
* but allow some leeway (ex. Dragalia Lost bgm+vocals ~12 samples) */
if (!layer_loop
|| !(loop_start >= layer_loop_start - delta && loop_start <= layer_loop_start + delta)
|| !(loop_end >= layer_loop_end - delta && loop_start <= layer_loop_end + delta)) {
loop_flag = 0;
loop_start = 0;
loop_end = 0;
}
if (num_samples < layer_samples) /* max */
num_samples = layer_samples;
if (sample_rate < layer_rate)
sample_rate = layer_rate;
if (coding_type == coding_SILENCE)
coding_type = data->layers[i]->coding_type;
}
data->external_looping = external_looping;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channels, loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = data->layers[0]->meta_type;
vgmstream->sample_rate = sample_rate;
vgmstream->num_samples = num_samples;
vgmstream->loop_start_sample = loop_start;
vgmstream->loop_end_sample = loop_end;
vgmstream->coding_type = coding_type;
vgmstream->layout_type = layout_layered;
vgmstream->layout_data = data;
return vgmstream;
fail:
if (vgmstream) vgmstream->layout_data = NULL;
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -6,6 +6,51 @@
#include "../util/reader_sf.h"
#include "../util/log.h"
/* basic layouts */
void render_vgmstream_flat(sample_t* buffer, int32_t sample_count, VGMSTREAM* vgmstream);
void render_vgmstream_interleave(sample_t* buffer, int32_t sample_count, VGMSTREAM* vgmstream);
/* segmented layout */
/* for files made of "continuous" segments, one per section of a song (using a complete sub-VGMSTREAM) */
typedef struct {
int segment_count;
VGMSTREAM** segments;
int current_segment;
sample_t* buffer;
int input_channels; /* internal buffer channels */
int output_channels; /* resulting channels (after mixing, if applied) */
int mixed_channels; /* segments have different number of channels */
} segmented_layout_data;
void render_vgmstream_segmented(sample_t* buffer, int32_t sample_count, VGMSTREAM* vgmstream);
segmented_layout_data* init_layout_segmented(int segment_count);
int setup_layout_segmented(segmented_layout_data* data);
void free_layout_segmented(segmented_layout_data* data);
void reset_layout_segmented(segmented_layout_data* data);
void seek_layout_segmented(VGMSTREAM* vgmstream, int32_t seek_sample);
void loop_layout_segmented(VGMSTREAM* vgmstream, int32_t loop_sample);
/* layered layout */
/* for files made of "parallel" layers, one per group of channels (using a complete sub-VGMSTREAM) */
typedef struct {
int layer_count;
VGMSTREAM** layers;
sample_t* buffer;
int input_channels; /* internal buffer channels */
int output_channels; /* resulting channels (after mixing, if applied) */
int external_looping; /* don't loop using per-layer loops, but layout's own looping */
int curr_layer; /* helper */
} layered_layout_data;
void render_vgmstream_layered(sample_t* buffer, int32_t sample_count, VGMSTREAM* vgmstream);
layered_layout_data* init_layout_layered(int layer_count);
int setup_layout_layered(layered_layout_data* data);
void free_layout_layered(layered_layout_data* data);
void reset_layout_layered(layered_layout_data* data);
void seek_layout_layered(VGMSTREAM* vgmstream, int32_t seek_sample);
void loop_layout_layered(VGMSTREAM* vgmstream, int32_t loop_sample);
/* blocked layouts */
void render_vgmstream_blocked(sample_t* buffer, int32_t sample_count, VGMSTREAM* vgmstream);
void block_update(off_t block_offset, VGMSTREAM* vgmstream);
@ -51,27 +96,4 @@ void block_update_ubi_sce(off_t block_offset, VGMSTREAM* vgmstream);
void block_update_tt_ad(off_t block_offset, VGMSTREAM* vgmstream);
void block_update_vas(off_t block_offset, VGMSTREAM* vgmstream);
/* other layouts */
void render_vgmstream_interleave(sample_t* buffer, int32_t sample_count, VGMSTREAM* vgmstream);
void render_vgmstream_flat(sample_t* buffer, int32_t sample_count, VGMSTREAM* vgmstream);
void render_vgmstream_segmented(sample_t* buffer, int32_t sample_count, VGMSTREAM* vgmstream);
segmented_layout_data* init_layout_segmented(int segment_count);
int setup_layout_segmented(segmented_layout_data* data);
void free_layout_segmented(segmented_layout_data* data);
void reset_layout_segmented(segmented_layout_data* data);
void seek_layout_segmented(VGMSTREAM* vgmstream, int32_t seek_sample);
void loop_layout_segmented(VGMSTREAM* vgmstream, int32_t loop_sample);
VGMSTREAM *allocate_segmented_vgmstream(segmented_layout_data* data, int loop_flag, int loop_start_segment, int loop_end_segment);
void render_vgmstream_layered(sample_t* buffer, int32_t sample_count, VGMSTREAM* vgmstream);
layered_layout_data* init_layout_layered(int layer_count);
int setup_layout_layered(layered_layout_data* data);
void free_layout_layered(layered_layout_data* data);
void reset_layout_layered(layered_layout_data* data);
void seek_layout_layered(VGMSTREAM* vgmstream, int32_t seek_sample);
void loop_layout_layered(VGMSTREAM* vgmstream, int32_t loop_sample);
VGMSTREAM *allocate_layered_vgmstream(layered_layout_data* data);
#endif

View File

@ -289,67 +289,3 @@ void reset_layout_segmented(segmented_layout_data* data) {
reset_vgmstream(data->segments[i]);
}
}
/* helper for easier creation of segments */
VGMSTREAM* allocate_segmented_vgmstream(segmented_layout_data* data, int loop_flag, int loop_start_segment, int loop_end_segment) {
VGMSTREAM* vgmstream = NULL;
int channel_layout;
int i, sample_rate;
int32_t num_samples, loop_start, loop_end;
coding_t coding_type = data->segments[0]->coding_type;
/* save data */
channel_layout = data->segments[0]->channel_layout;
num_samples = 0;
loop_start = 0;
loop_end = 0;
sample_rate = 0;
for (i = 0; i < data->segment_count; i++) {
/* needs get_samples since element may use play settings */
int32_t segment_samples = vgmstream_get_samples(data->segments[i]);
int segment_rate = data->segments[i]->sample_rate;
if (loop_flag && i == loop_start_segment)
loop_start = num_samples;
num_samples += segment_samples;
if (loop_flag && i == loop_end_segment)
loop_end = num_samples;
/* inherit first segment's layout but only if all segments' layout match */
if (channel_layout != 0 && channel_layout != data->segments[i]->channel_layout)
channel_layout = 0;
if (sample_rate < segment_rate)
sample_rate = segment_rate;
if (coding_type == coding_SILENCE)
coding_type = data->segments[i]->coding_type;
}
/* respect loop_flag even when no loop_end found as it's possible file loops are set outside */
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(data->output_channels, loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = data->segments[0]->meta_type;
vgmstream->sample_rate = sample_rate;
vgmstream->num_samples = num_samples;
vgmstream->loop_start_sample = loop_start;
vgmstream->loop_end_sample = loop_end;
vgmstream->coding_type = coding_type;
vgmstream->channel_layout = channel_layout;
vgmstream->layout_type = layout_segmented;
vgmstream->layout_data = data;
return vgmstream;
fail:
if (vgmstream) vgmstream->layout_data = NULL;
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -454,6 +454,7 @@
<ClCompile Include="meta\dmsg_segh.c" />
<ClCompile Include="meta\dsb.c" />
<ClCompile Include="meta\dsf.c" />
<ClCompile Include="meta\dsp_kceje.c" />
<ClCompile Include="meta\ea_1snh.c" />
<ClCompile Include="meta\ea_eaac.c" />
<ClCompile Include="meta\ea_eaac_abk.c" />
@ -577,7 +578,6 @@
<ClCompile Include="meta\ngc_dsp_konami.c" />
<ClCompile Include="meta\ngc_dsp_mpds.c" />
<ClCompile Include="meta\ngc_dsp_std.c" />
<ClCompile Include="meta\ngc_dsp_ygo.c" />
<ClCompile Include="meta\ngc_ffcc_str.c" />
<ClCompile Include="meta\ngc_lps.c" />
<ClCompile Include="meta\ngc_nst_dsp.c" />
@ -604,6 +604,7 @@
<ClCompile Include="meta\p2bt_move_visa.c" />
<ClCompile Include="meta\p3d.c" />
<ClCompile Include="meta\pasx.c" />
<ClCompile Include="meta\pcm_kceje.c" />
<ClCompile Include="meta\pcm_sre.c" />
<ClCompile Include="meta\pcm_success.c" />
<ClCompile Include="meta\pc_ast.c" />
@ -620,7 +621,6 @@
<ClCompile Include="meta\ps2_iab.c" />
<ClCompile Include="meta\ps2_joe.c" />
<ClCompile Include="meta\ps2_mcg.c" />
<ClCompile Include="meta\ps2_pcm.c" />
<ClCompile Include="meta\ps2_rnd.c" />
<ClCompile Include="meta\ps2_snd.c" />
<ClCompile Include="meta\ps2_sps.c" />

View File

@ -1192,6 +1192,9 @@
<ClCompile Include="meta\dsf.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
<ClCompile Include="meta\dsp_kceje.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
<ClCompile Include="meta\ea_1snh.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
@ -1561,9 +1564,6 @@
<ClCompile Include="meta\ngc_dsp_std.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
<ClCompile Include="meta\ngc_dsp_ygo.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
<ClCompile Include="meta\ngc_ffcc_str.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
@ -1642,6 +1642,9 @@
<ClCompile Include="meta\pasx.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
<ClCompile Include="meta\pcm_kceje.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
<ClCompile Include="meta\pcm_sre.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
@ -1690,9 +1693,6 @@
<ClCompile Include="meta\ps2_mcg.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
<ClCompile Include="meta\ps2_pcm.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
<ClCompile Include="meta\ps2_rnd.c">
<Filter>meta\Source Files</Filter>
</ClCompile>

View File

@ -60,7 +60,7 @@ static inline void libvgmstream_streamfile_close(libvgmstream_streamfile_t* libs
}
LIBVGMSTREAM_API libvgmstream_streamfile_t* libvgmstream_streamfile_from_filename(const char* filename);
LIBVGMSTREAM_API libvgmstream_streamfile_t* libvgmstream_streamfile_open_from_stdio(const char* filename);
#endif
#endif

View File

@ -1,6 +1,7 @@
#include "meta.h"
#include "../coding/coding.h"
#include "../layout/layout.h"
#include "../util/layout_utils.h"
#include "9tav_streamfile.h"
/* 9TAV - from Metal Gear Solid 2/3 HD (Vita) */

View File

@ -31,55 +31,51 @@ VGMSTREAM* init_vgmstream_adx_subkey(STREAMFILE* sf, uint16_t subkey) {
int32_t num_samples, loop_start_sample = 0, loop_end_sample = 0;
uint16_t cutoff;
uint16_t version;
uint8_t encoding_type, frame_size;
int16_t coef1, coef2;
uint16_t xor_start = 0, xor_mult = 0, xor_add = 0;
meta_t header_type;
coding_t coding_type;
/* checks*/
if (read_u16be(0x00,sf) != 0x8000)
goto fail;
return NULL;
/* .adx: standard
* .adp: Headhunter (DC) */
if (!check_extensions(sf,"adx,adp"))
goto fail;
return NULL;
/* CRI checks both 0x8000 and memcmps this */
start_offset = read_u16be(0x02,sf) + 0x04;
if (read_u16be(start_offset - 0x06,sf) != 0x2863 || /* "(c" */
read_u32be(start_offset - 0x04,sf) != 0x29435249) /* ")CRI" */
goto fail;
encoding_type = read_u8(0x04, sf);
uint8_t encoding_type = read_u8(0x04, sf);
switch (encoding_type) {
case 0x02:
coding_type = coding_CRI_ADX_fixed;
coding_type = coding_CRI_ADX_fixed; /* unused/encoder only */
break;
case 0x03:
coding_type = coding_CRI_ADX;
break;
case 0x04:
coding_type = coding_CRI_ADX_exp;
coding_type = coding_CRI_ADX_exp; /* unused/encoder only */
break;
default: /* 0x10 is AHX for DC, 0x11 is AHX */
goto fail;
return NULL;
}
/* ADX encoders can't set this value, but is honored by ADXPlay if changed and multiple of 0x12,
* though output is unusual and may not be fully supported (works in mono so not an interleave)
* Later versions of the decode just use constant 0x12 ignoring it, though. */
frame_size = read_u8(0x05, sf);
* Later versions of the decoder just use constant 0x12 ignoring it, though. */
uint8_t frame_size = read_u8(0x05, sf);
if (frame_size != 0x12)
return NULL;
uint8_t bits_per_sample = read_u8(0x06,sf);
if (bits_per_sample != 4)
return NULL;
if (read_u8(0x06,sf) != 4) /* bits per sample */
goto fail;
/* older ADX (adxencd) up to 2ch, newer ADX (criatomencd) up to 8 */
channels = read_u8(0x07,sf);
channels = read_u8(0x07,sf); /* older ADX (adxencd) up to 2ch, newer ADX (criatomencd) up to 8 */
if (channels > 8)
return NULL;
sample_rate = read_s32be(0x08,sf);
num_samples = read_s32be(0x0c,sf);
cutoff = read_u16be(0x10,sf); /* high-pass cutoff frequency, always 500 */
@ -132,8 +128,9 @@ VGMSTREAM* init_vgmstream_adx_subkey(STREAMFILE* sf, uint16_t subkey) {
hist_size = (channels > 1 ? 0x04 * channels : 0x04 + 0x04); /* min is 0x8, even in 1ch files */
ainf_offset = base_size + hist_size + 0x04; /* not seen with >2ch though */
if (is_id32be(ainf_offset+0x00,sf, "AINF"))
if (is_id32be(ainf_offset+0x00,sf, "AINF")) {
ainf_size = read_u32be(ainf_offset+0x04,sf);
}
if (start_offset - ainf_size - 0x06 >= hist_offset + hist_size + loops_size) { /* enough space for loop info? */
off_t loops_offset = base_size + hist_size;
@ -169,10 +166,18 @@ VGMSTREAM* init_vgmstream_adx_subkey(STREAMFILE* sf, uint16_t subkey) {
header_type = meta_ADX_05;
}
else { /* not a known/supported version signature */
goto fail;
return NULL;
}
/* CRI mainly checks value 0x8000 at 0x00, and memcmps this, but offset is right before data start
* usually aligned to 0x100/0x800/0x1000, so do other checks first to avoid seeking back and forth */
uint8_t cri_str[0x06] = {0};
read_streamfile(cri_str, start_offset - 0x06, sizeof(cri_str), sf);
if (memcmp(cri_str, "(c)CRI", sizeof(cri_str)) != 0)
return NULL;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channels, loop_flag);
if (!vgmstream) goto fail;
@ -191,9 +196,8 @@ VGMSTREAM* init_vgmstream_adx_subkey(STREAMFILE* sf, uint16_t subkey) {
/* calculate filter coefficients */
if (coding_type == coding_CRI_ADX_fixed) {
int i;
/* standard XA coefs * (2<<11) */
for (i = 0; i < channels; i++) {
/* standard XA coefs * (2 << 11) */
for (int i = 0; i < channels; i++) {
vgmstream->ch[i].adpcm_coef[0] = 0x0000;
vgmstream->ch[i].adpcm_coef[1] = 0x0000;
vgmstream->ch[i].adpcm_coef[2] = 0x0F00;
@ -206,7 +210,6 @@ VGMSTREAM* init_vgmstream_adx_subkey(STREAMFILE* sf, uint16_t subkey) {
}
else {
/* coefs from cutoff frequency (some info from decomps, uses floats but no diffs if using doubles due to rounding) */
int i;
float x, y, z, a, b, c;
x = cutoff;
@ -220,34 +223,28 @@ VGMSTREAM* init_vgmstream_adx_subkey(STREAMFILE* sf, uint16_t subkey) {
coef1 = (short)(c * 8192);
coef2 = (short)(c * c * -4096);
for (i = 0; i < channels; i++) {
for (int i = 0; i < channels; i++) {
vgmstream->ch[i].adpcm_coef[0] = coef1;
vgmstream->ch[i].adpcm_coef[1] = coef2;
}
}
/* init decoder */
{
int i;
for (int i = 0; i < channels; i++) {
/* 2 hist shorts per ch, corresponding to the very first original sample repeated (verified with CRI's encoders).
* Not vital as their effect is small, after a few samples they don't matter, and most songs start in silence. */
if (hist_offset) {
vgmstream->ch[i].adpcm_history1_32 = read_s16be(hist_offset + i*4 + 0x00,sf);
vgmstream->ch[i].adpcm_history2_32 = read_s16be(hist_offset + i*4 + 0x02,sf);
}
for (i = 0; i < channels; i++) {
/* 2 hist shorts per ch, corresponding to the very first original sample repeated (verified with CRI's encoders).
* Not vital as their effect is small, after a few samples they don't matter, and most songs start in silence. */
if (hist_offset) {
vgmstream->ch[i].adpcm_history1_32 = read_s16be(hist_offset + i*4 + 0x00,sf);
vgmstream->ch[i].adpcm_history2_32 = read_s16be(hist_offset + i*4 + 0x02,sf);
}
if (coding_type == coding_CRI_ADX_enc_8 || coding_type == coding_CRI_ADX_enc_9) {
vgmstream->ch[i].adx_xor = xor_start;
vgmstream->ch[i].adx_mult = xor_mult;
vgmstream->ch[i].adx_add = xor_add;
if (coding_type == coding_CRI_ADX_enc_8 || coding_type == coding_CRI_ADX_enc_9) {
int j;
vgmstream->ch[i].adx_channels = channels;
vgmstream->ch[i].adx_xor = xor_start;
vgmstream->ch[i].adx_mult = xor_mult;
vgmstream->ch[i].adx_add = xor_add;
for (j = 0; j < i; j++)
adx_next_key(&vgmstream->ch[i]);
}
for (int j = 0; j < i; j++)
adx_next_key(&vgmstream->ch[i]);
}
}
@ -255,7 +252,6 @@ VGMSTREAM* init_vgmstream_adx_subkey(STREAMFILE* sf, uint16_t subkey) {
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
@ -387,13 +383,13 @@ static bool find_adx_key(STREAMFILE* sf, uint8_t type, uint16_t *xor_start, uint
/* read the prescales */
for (i = 0; i < bruteframe_start; i++) {
prescales[i] = read_16bitBE(start_offset + i*frame_size, sf);
prescales[i] = read_u16be(start_offset + i * frame_size, sf);
}
}
/* read in the scales */
for (i = 0; i < bruteframe_count; i++) {
scales[i] = read_16bitBE(start_offset + (bruteframe_start + i)*frame_size, sf);
scales[i] = read_u16be(start_offset + (bruteframe_start + i) * frame_size, sf);
}
}

View File

@ -1,5 +1,6 @@
#include "meta.h"
#include "../layout/layout.h"
#include "../util/layout_utils.h"
#include "aix_streamfile.h"

View File

@ -4,47 +4,45 @@
/* BGW - from Final Fantasy XI (PC) music files */
VGMSTREAM * init_vgmstream_bgw(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
STREAMFILE *temp_streamFile = NULL;
VGMSTREAM* init_vgmstream_bgw(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
STREAMFILE* temp_sf = NULL;
uint32_t codec, file_size, block_size, sample_rate, block_align;
int32_t loop_start;
off_t start_offset;
int channel_count, loop_flag = 0;
int channels, loop_flag = 0;
/* check extensions */
if ( !check_extensions(streamFile, "bgw") )
goto fail;
/* check header */
if (read_32bitBE(0x00,streamFile) != 0x42474d53 || /* "BGMS" */
read_32bitBE(0x04,streamFile) != 0x74726561 || /* "trea" */
read_32bitBE(0x08,streamFile) != 0x6d000000 ) /* "m\0\0\0" */
goto fail;
/* checks */
if (!is_id32be(0x00,sf, "BGMS") || !is_id32be(0x04,sf, "trea") || !is_id32be(0x08,sf, "m\0\0\0"))
return NULL;
codec = read_32bitLE(0x0c,streamFile);
file_size = read_32bitLE(0x10,streamFile);
/* file_id = read_32bitLE(0x14,streamFile); */
block_size = read_32bitLE(0x18,streamFile);
loop_start = read_32bitLE(0x1c,streamFile);
sample_rate = (read_32bitLE(0x20,streamFile) + read_32bitLE(0x24,streamFile)) & 0x7FFFFFFF; /* bizarrely obfuscated sample rate */
start_offset = read_32bitLE(0x28,streamFile);
/* 0x2c: unk (vol?) */
/* 0x2d: unk (0x10?) */
channel_count = read_8bit(0x2e,streamFile);
block_align = (uint8_t)read_8bit(0x2f,streamFile);
if (!check_extensions(sf, "bgw"))
return NULL;
if (file_size != get_streamfile_size(streamFile))
codec = read_u32le(0x0c,sf);
file_size = read_u32le(0x10,sf);
//14: file_id
block_size = read_u32le(0x18,sf);
loop_start = read_s32le(0x1c,sf);
sample_rate = (read_u32le(0x20,sf) + read_u32le(0x24,sf)) & 0x7FFFFFFF; /* bizarrely obfuscated sample rate */
start_offset = read_u32le(0x28,sf);
//2c: unk (vol?)
//2d: unk (bps?)
channels = read_s8(0x2e,sf);
block_align = read_u8(0x2f,sf);
if (file_size != get_streamfile_size(sf))
goto fail;
loop_flag = (loop_start > 0);
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
vgmstream = allocate_vgmstream(channels,loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_FFXI_BGW;
vgmstream->meta_type = meta_BGW;
vgmstream->sample_rate = sample_rate;
switch (codec) {
@ -64,16 +62,16 @@ VGMSTREAM * init_vgmstream_bgw(STREAMFILE *streamFile) {
#ifdef VGM_USE_FFMPEG
case 3: { /* ATRAC3 (encrypted) */
size_t data_size = file_size - start_offset;
int encoder_delay, block_align;
int encoder_delay, frame_size;
encoder_delay = 1024*2 + 69*2; /* observed value, all files start at +2200 (PS-ADPCM also starts around 50-150 samples in) */
block_align = 0xC0 * vgmstream->channels; /* 0x00 in header */
frame_size = 0xC0 * vgmstream->channels; /* 0x00 in header */
vgmstream->num_samples = block_size - encoder_delay; /* atrac3_bytes_to_samples gives block_size */
temp_streamFile = setup_bgw_atrac3_streamfile(streamFile, start_offset,data_size, 0xC0,channel_count);
if (!temp_streamFile) goto fail;
temp_sf = setup_bgw_atrac3_streamfile(sf, start_offset,data_size, 0xC0,channels);
if (!temp_sf) goto fail;
vgmstream->codec_data = init_ffmpeg_atrac3_raw(temp_streamFile, 0x00,data_size, vgmstream->num_samples,vgmstream->channels,vgmstream->sample_rate, block_align, encoder_delay);
vgmstream->codec_data = init_ffmpeg_atrac3_raw(temp_sf, 0x00, data_size, vgmstream->num_samples, vgmstream->channels, vgmstream->sample_rate, frame_size, encoder_delay);
if (!vgmstream->codec_data) goto fail;
vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_none;
@ -83,7 +81,8 @@ VGMSTREAM * init_vgmstream_bgw(STREAMFILE *streamFile) {
vgmstream->loop_end_sample = vgmstream->num_samples;
}
close_streamfile(temp_streamFile);
close_streamfile(temp_sf);
temp_sf = NULL;
break;
}
#endif
@ -93,59 +92,57 @@ VGMSTREAM * init_vgmstream_bgw(STREAMFILE *streamFile) {
}
if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) )
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
goto fail;
return vgmstream;
fail:
close_streamfile(temp_streamFile);
close_streamfile(temp_sf);
close_vgmstream(vgmstream);
return NULL;
}
/* SPW (SEWave) - from PlayOnline viewer for Final Fantasy XI (PC) */
VGMSTREAM * init_vgmstream_spw(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
STREAMFILE *temp_streamFile = NULL;
/* SPW (SEWave) - from PlayOnline viewer for Final Fantasy XI (PC) */
VGMSTREAM* init_vgmstream_spw(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
STREAMFILE* temp_sf = NULL;
uint32_t codec, file_size, block_size, sample_rate, block_align;
int32_t loop_start;
off_t start_offset;
int channel_count, loop_flag = 0;
int channels, loop_flag = 0;
/* check extensions */
if ( !check_extensions(streamFile, "spw") )
goto fail;
/* checks */
if (!is_id32be(0x00,sf, "SeWa") || !is_id32be(0x04,sf, "ve\0\0"))
return NULL;
/* check header */
if (read_32bitBE(0,streamFile) != 0x53655761 || /* "SeWa" */
read_32bitBE(4,streamFile) != 0x76650000) /* "ve\0\0" */
goto fail;
if (!check_extensions(sf, "spw"))
return NULL;
file_size = read_32bitLE(0x08,streamFile);
codec = read_32bitLE(0x0c,streamFile);
/* file_id = read_32bitLE(0x10,streamFile);*/
block_size = read_32bitLE(0x14,streamFile);
loop_start = read_32bitLE(0x18,streamFile);
sample_rate = (read_32bitLE(0x1c,streamFile) + read_32bitLE(0x20,streamFile)) & 0x7FFFFFFF; /* bizarrely obfuscated sample rate */
start_offset = read_32bitLE(0x24,streamFile);
/* 0x2c: unk (0x00?) */
/* 0x2d: unk (0x00/01?) */
channel_count = read_8bit(0x2a,streamFile);
file_size = read_u32le(0x08,sf);
codec = read_u32le(0x0c,sf);
//10: file_id
block_size = read_u32le(0x14,sf);
loop_start = read_s32le(0x18,sf);
sample_rate = (read_u32le(0x1c,sf) + read_u32le(0x20,sf)) & 0x7FFFFFFF; /* bizarrely obfuscated sample rate */
start_offset = read_u32le(0x24,sf);
// 2c: unk (0x00?)
// 2d: unk (0x00/01?)
channels = read_s8(0x2a,sf);
/*0x2b: unk (0x01 when PCM, 0x10 when VAG?) */
block_align = read_8bit(0x2c,streamFile);
block_align = read_u8(0x2c,sf);
if (file_size != get_streamfile_size(streamFile))
if (file_size != get_streamfile_size(sf))
goto fail;
loop_flag = (loop_start > 0);
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
vgmstream = allocate_vgmstream(channels,loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_FFXI_SPW;
vgmstream->meta_type = meta_SPW;
vgmstream->sample_rate = sample_rate;
switch (codec) {
@ -178,16 +175,16 @@ VGMSTREAM * init_vgmstream_spw(STREAMFILE *streamFile) {
#ifdef VGM_USE_FFMPEG
case 3: { /* ATRAC3 (encrypted) */
size_t data_size = file_size - start_offset;
int encoder_delay, block_align;
int encoder_delay, frame_size;
encoder_delay = 1024*2 + 69*2; /* observed value, all files start at +2200 (PS-ADPCM also starts around 50-150 samples in) */
block_align = 0xC0 * vgmstream->channels; /* 0x00 in header */
frame_size = 0xC0 * vgmstream->channels; /* 0x00 in header */
vgmstream->num_samples = block_size - encoder_delay; /* atrac3_bytes_to_samples gives block_size */
temp_streamFile = setup_bgw_atrac3_streamfile(streamFile, start_offset,data_size, 0xC0,channel_count);
if (!temp_streamFile) goto fail;
temp_sf = setup_bgw_atrac3_streamfile(sf, start_offset,data_size, 0xC0, channels);
if (!temp_sf) goto fail;
vgmstream->codec_data = init_ffmpeg_atrac3_raw(temp_streamFile, 0x00,data_size, vgmstream->num_samples,vgmstream->channels,vgmstream->sample_rate, block_align, encoder_delay);
vgmstream->codec_data = init_ffmpeg_atrac3_raw(temp_sf, 0x00, data_size, vgmstream->num_samples, vgmstream->channels, vgmstream->sample_rate, frame_size, encoder_delay);
if (!vgmstream->codec_data) goto fail;
vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_none;
@ -197,7 +194,8 @@ VGMSTREAM * init_vgmstream_spw(STREAMFILE *streamFile) {
vgmstream->loop_end_sample = vgmstream->num_samples;
}
close_streamfile(temp_streamFile);
close_streamfile(temp_sf);
temp_sf = NULL;
break;
}
#endif
@ -206,15 +204,12 @@ VGMSTREAM * init_vgmstream_spw(STREAMFILE *streamFile) {
goto fail;
}
/* open the file for reading */
if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) )
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
goto fail;
return vgmstream;
fail:
close_streamfile(temp_streamFile);
close_streamfile(temp_sf);
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -148,8 +148,8 @@ VGMSTREAM* init_vgmstream_bkhd(STREAMFILE* sf) {
vgmstream = init_vgmstream_adm3(temp_sf);
if (!vgmstream) goto fail;
}
else if (read_f32(subfile_offset + 0x02, temp_sf) >= 30.0 &&
read_f32(subfile_offset + 0x02, temp_sf) <= 250.0) {
else if (read_f32(subfile_offset + 0x02, temp_sf) >= 30.0f &&
read_f32(subfile_offset + 0x02, temp_sf) <= 250.0f) {
is_wmid = 1;
/* ignore Wwise's custom .wmid (similar to a regular midi but with simplified
* chunks and custom fields: 0x00=MThd's division, 0x02: bpm (new), etc) */

52
src/meta/dsp_kceje.c Normal file
View File

@ -0,0 +1,52 @@
#include "meta.h"
#include "../coding/coding.h"
/* .dsp - from KCE Japan East GC games [Yu-Gi-Oh! The Falsebound Kingdom (GC), Hikaru No Go 3 (GC)] */
VGMSTREAM* init_vgmstream_dsp_kceje(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
int channels, loop_flag;
off_t start_offset;
/* checks */
if (read_u32be(0x00,sf) + 0xE0 != get_streamfile_size(sf))
return NULL;
if (read_u32be(0x04,sf) != 0x01)
return NULL;
if (read_u32be(0x08,sf) != 0x10000000)
return NULL;
if (read_u32be(0x0c,sf) != 0x00)
return NULL;
/* .dsp: assumed (no names in .pac bigfile and refs to DSP streams) */
if (!check_extensions(sf, "dsp"))
return NULL;
channels = 1;
loop_flag = read_u16be(0x2C,sf) != 0x00;
start_offset = 0xE0;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channels, loop_flag);
if (!vgmstream) goto fail;
vgmstream->sample_rate = read_u32be(0x28,sf);
vgmstream->num_samples = read_u32be(0x20,sf);
vgmstream->loop_start_sample = dsp_bytes_to_samples(read_u32be(0x30,sf), 2);
vgmstream->loop_end_sample = dsp_bytes_to_samples(read_u32be(0x34,sf), 2);
vgmstream->allow_dual_stereo = true;
vgmstream->meta_type = meta_DSP_KCEJE;
vgmstream->coding_type = coding_NGC_DSP;
vgmstream->layout_type = layout_none;
dsp_read_coefs_be(vgmstream, sf, 0x3c, 0x00);
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -71,7 +71,7 @@ typedef struct {
uint32_t header_size;
} eaac_header_t;
static VGMSTREAM* init_vgmstream_eaaudiocore_main(eaac_header_t* eaac, STREAMFILE* sf_head, STREAMFILE* sf_data, off_t header_offset, off_t start_offset, meta_t meta_type, bool standalone);
static VGMSTREAM* init_vgmstream_eaaudiocore_main(eaac_header_t* eaac, STREAMFILE* sf_head, STREAMFILE* sf_data, off_t header_offset, meta_t meta_type, bool standalone);
/* EA newest header from RwAudioCore (RenderWare?) / EAAudioCore library (still generated by sx.exe).
@ -244,7 +244,7 @@ static VGMSTREAM* init_vgmstream_eaaudiocore_header(STREAMFILE* sf_head, STREAMF
}
/* header done, setup decoding */
return init_vgmstream_eaaudiocore_main(&eaac, sf_head, sf_data, header_offset, start_offset, meta_type, standalone);
return init_vgmstream_eaaudiocore_main(&eaac, sf_head, sf_data, header_offset, meta_type, standalone);
fail:
return NULL;
}
@ -255,7 +255,7 @@ static STREAMFILE* setup_eaac_streamfile(eaac_header_t* ea, STREAMFILE* sf_head,
static size_t calculate_eaac_size(STREAMFILE* sf, eaac_header_t* ea, uint32_t num_samples, off_t start_offset, int is_ram);
static VGMSTREAM* init_vgmstream_eaaudiocore_main(eaac_header_t* eaac, STREAMFILE* sf_head, STREAMFILE* sf_data, off_t header_offset, off_t _start_offset, meta_t meta_type, bool standalone) {
static VGMSTREAM* init_vgmstream_eaaudiocore_main(eaac_header_t* eaac, STREAMFILE* sf_head, STREAMFILE* sf_data, off_t header_offset, meta_t meta_type, bool standalone) {
VGMSTREAM* vgmstream = NULL;
STREAMFILE *temp_sf = NULL, *sf = NULL, *sf_sns = NULL;

View File

@ -1,6 +1,7 @@
#include "meta.h"
#include "../util/endianness.h"
#include "../layout/layout.h"
#include "../util/layout_utils.h"
#include "../util/companion_files.h"

View File

@ -1,6 +1,7 @@
#include "meta.h"
#include "../layout/layout.h"
#include "../util/endianness.h"
#include "../util/layout_utils.h"
#define EA_BLOCKID_HEADER 0x5343486C /* "SCHl" */

View File

@ -2,6 +2,7 @@
#include "../util/endianness.h"
#include "../layout/layout.h"
#include "../util/companion_files.h"
#include "../util/layout_utils.h"
#define EA_BLOCKID_HEADER 0x5343486C /* "SCHl" */

View File

@ -1320,6 +1320,12 @@ static const hcakey_info hcakey_list[] = {
// Reynatis (Switch)
{5963496778882477625}, // 52C298B97479EE39
// Buddysma!! ~Smartphone Start! Buddyfight (Android)
{8132462270}, // 00000001E4BB86BE
// Code Geass: Lost Stories (Android)
{9182735170}, // 0000000223556B42
};
#endif/*_HCA_KEYS_H_*/

View File

@ -248,7 +248,7 @@ VGMSTREAM * init_vgmstream_mus_acm(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_scd_pcm(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_ps2_pcm(STREAMFILE * streamFile);
VGMSTREAM* init_vgmstream_pcm_kceje(STREAMFILE* sf);
VGMSTREAM * init_vgmstream_ps2_rkv(STREAMFILE * streamFile);
@ -394,7 +394,7 @@ VGMSTREAM * init_vgmstream_sd9(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_2dx9(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_dsp_ygo(STREAMFILE * streamFile);
VGMSTREAM* init_vgmstream_dsp_kceje(STREAMFILE* sf);
VGMSTREAM * init_vgmstream_ps2_vgv(STREAMFILE * streamFile);

View File

@ -54,7 +54,7 @@ VGMSTREAM* init_vgmstream_mul(STREAMFILE* sf) {
{
float check1 = read_f32(0x38,sf);
float check2 = read_f32(0x3c,sf);
if (!(check1 >= 1.0 && check1 <= 3000.0) && check2 != 1.0)
if (!(check1 >= 1.0f && check1 <= 3000.0f) && check2 != 1.0f)
goto fail;
}

View File

@ -1,11 +1,12 @@
#include "meta.h"
#include "../layout/layout.h"
#include "../coding/coding.h"
#include "../util/endianness.h"
/* If these variables are packed properly in the struct (one after another)
* then this is actually how they are laid out in the file, albeit big-endian */
struct dsp_header {
typedef struct {
uint32_t sample_count; /* 0x00 */
uint32_t nibble_count; /* 0x04 (includes frame headers) */
uint32_t sample_rate; /* 0x08 (generally 22/32/44/48kz but games like Wario World set 32028hz to adjust for GC's rate) */
@ -26,13 +27,13 @@ struct dsp_header {
uint16_t block_size; /* 0x4c */
/* padding/reserved up to 0x60, DSPADPCM.exe from GC adds garbage here (uninitialized MSVC memory?)
* [ex. Batallion Wars (GC), Timesplitters 2 (GC)], 0xcccc...cccc with DSPADPCMD */
};
} dsp_header_t;
/* read and do basic validations to the above struct */
static bool read_dsp_header_endian(struct dsp_header *header, off_t offset, STREAMFILE* sf, int big_endian) {
uint32_t (*get_u32)(const uint8_t*) = big_endian ? get_u32be : get_u32le;
uint16_t (*get_u16)(const uint8_t*) = big_endian ? get_u16be : get_u16le;
int16_t (*get_s16)(const uint8_t*) = big_endian ? get_s16be : get_s16le;
static bool read_dsp_header_endian(dsp_header_t* header, off_t offset, STREAMFILE* sf, bool big_endian) {
get_u32_t get_u32 = big_endian ? get_u32be : get_u32le;
get_u16_t get_u16 = big_endian ? get_u16be : get_u16le;
get_s16_t get_s16 = big_endian ? get_s16be : get_s16le;
uint8_t buf[0x60];
int zero_coefs;
@ -71,9 +72,11 @@ static bool read_dsp_header_endian(struct dsp_header *header, off_t offset, STRE
header->loop_start_offset = get_u32(buf+0x10);
header->loop_end_offset = get_u32(buf+0x14);
//TODO: test if games react to changed initial offset
/* Dr. Muto uses 0, and some custom Metroid Prime loop start, so probably ignored by the hardware */
header->initial_offset = get_u32(buf+0x18);
if (header->initial_offset != 2 && header->initial_offset != 0)
goto fail; /* Dr. Muto uses 0 */
if (header->initial_offset != 2 && header->initial_offset != 0 && header->initial_offset != header->loop_start_offset)
goto fail;
zero_coefs = 0;
for (int i = 0; i < 16; i++) {
@ -110,10 +113,10 @@ static bool read_dsp_header_endian(struct dsp_header *header, off_t offset, STRE
fail:
return false;
}
static int read_dsp_header_be(struct dsp_header *header, off_t offset, STREAMFILE* file) {
static int read_dsp_header_be(dsp_header_t *header, off_t offset, STREAMFILE* file) {
return read_dsp_header_endian(header, offset, file, 1);
}
static int read_dsp_header_le(struct dsp_header *header, off_t offset, STREAMFILE* file) {
static int read_dsp_header_le(dsp_header_t *header, off_t offset, STREAMFILE* file) {
return read_dsp_header_endian(header, offset, file, 0);
}
@ -154,7 +157,7 @@ static VGMSTREAM* init_vgmstream_dsp_common(STREAMFILE* sf, dsp_meta* dspm) {
VGMSTREAM* vgmstream = NULL;
int i, j;
int loop_flag;
struct dsp_header ch_header[COMMON_DSP_MAX_CHANNELS];
dsp_header_t ch_header[COMMON_DSP_MAX_CHANNELS];
if (dspm->channels > dspm->max_channels)
@ -306,7 +309,7 @@ fail:
/* .dsp - standard mono dsp as generated by DSPADPCM.exe */
VGMSTREAM* init_vgmstream_ngc_dsp_std(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
struct dsp_header header;
dsp_header_t header;
const size_t header_size = 0x60;
off_t start_offset;
int i, channels;
@ -338,7 +341,7 @@ VGMSTREAM* init_vgmstream_ngc_dsp_std(STREAMFILE* sf) {
// (but .dsp is the common case, so it'd be slower)
{
int ko;
struct dsp_header header2;
dsp_header_t header2;
/* ignore headers one after another */
ko = !read_dsp_header_be(&header2, header_size, sf);
@ -427,7 +430,7 @@ fail:
/* .dsp - little endian dsp, possibly main Switch .dsp [LEGO Worlds (Switch)] */
VGMSTREAM* init_vgmstream_ngc_dsp_std_le(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
struct dsp_header header;
dsp_header_t header;
const size_t header_size = 0x60;
off_t start_offset;
int i, channels;
@ -450,7 +453,7 @@ VGMSTREAM* init_vgmstream_ngc_dsp_std_le(STREAMFILE* sf) {
* In many cases these will pass all the other checks, including the
* predictor/scale check if the first byte is 0 */
{
struct dsp_header header2;
dsp_header_t header2;
int ko;
ko = !read_dsp_header_le(&header2, header_size, sf);
@ -510,7 +513,7 @@ fail:
/* .dsp - standard multi-channel dsp as generated by DSPADPCM.exe (later revisions) */
VGMSTREAM* init_vgmstream_ngc_mdsp_std(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
struct dsp_header header;
dsp_header_t header;
const size_t header_size = 0x60;
off_t start_offset;
int i, c, channels;

View File

@ -1,75 +0,0 @@
#include "meta.h"
#include "../util.h"
/* .dsp found in:
Hikaru No Go 3 (NGC)
Yu-Gi-Oh! The Falsebound Kingdom (NGC)
2010-01-31 - added loop stuff and some header checks...
*/
VGMSTREAM * init_vgmstream_dsp_ygo(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
char filename[PATH_LIMIT];
int loop_flag;
int channel_count;
off_t start_offset;
int i;
/* check extension, case insensitive */
streamFile->get_name(streamFile,filename,sizeof(filename));
if (strcasecmp("dsp",filename_extension(filename))) goto fail;
/* check file size with size given in header */
if ((read_32bitBE(0x0,streamFile)+0xE0) != (get_streamfile_size(streamFile)))
goto fail;
loop_flag = (uint16_t)(read_16bitBE(0x2C,streamFile) != 0x0);
channel_count = 1;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
/* fill in the vital statistics */
start_offset = 0xE0;
vgmstream->channels = channel_count;
vgmstream->sample_rate = read_32bitBE(0x28,streamFile);
vgmstream->coding_type = coding_NGC_DSP;
vgmstream->num_samples = read_32bitBE(0x20,streamFile);
vgmstream->layout_type = layout_none;
vgmstream->meta_type = meta_DSP_YGO;
vgmstream->allow_dual_stereo = 1;
if (loop_flag) {
vgmstream->loop_start_sample = (read_32bitBE(0x30,streamFile)*14/16);
vgmstream->loop_end_sample = (read_32bitBE(0x34,streamFile)*14/16);
}
// read coef stuff
{
for (i=0;i<16;i++) {
vgmstream->ch[0].adpcm_coef[i] = read_16bitBE(0x3C+i*2,streamFile);
}
}
/* open the file for reading */
{
int i;
STREAMFILE * file;
file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
if (!file) goto fail;
for (i=0;i<channel_count;i++) {
vgmstream->ch[i].streamfile = file;
vgmstream->ch[i].channel_start_offset=
vgmstream->ch[i].offset=start_offset+
vgmstream->interleave_block_size*i;
}
}
return vgmstream;
fail:
/* clean up anything we may have opened */
if (vgmstream) close_vgmstream(vgmstream);
return NULL;
}

46
src/meta/pcm_kceje.c Normal file
View File

@ -0,0 +1,46 @@
#include "meta.h"
#include "../coding/coding.h"
/* .PCM - from KCE Japan East PS2 games [Ephemeral Fantasia (PS2), Yu-Gi-Oh! The Duelists of the Roses (PS2), 7 Blades (PS2)] */
VGMSTREAM* init_vgmstream_pcm_kceje(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
off_t start_offset;
int loop_flag, channels;
/* checks */
uint32_t data_size = read_u32le(0x00,sf);
if (data_size > 0x00 && data_size + 0x800 >= get_streamfile_size(sf) && data_size + 0x1000 <= get_streamfile_size(sf))
return NULL; /* usually 0x800 but may be padded */
if (pcm16_bytes_to_samples(data_size, 2) != read_u32le(0x04,sf))
return NULL;
if (!check_extensions(sf,"pcm"))
return NULL;
loop_flag = (read_s32le(0x0C,sf) != 0x00);
channels = 2;
start_offset = 0x800;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channels, loop_flag);
if (!vgmstream) goto fail;
vgmstream->channels = channels;
vgmstream->sample_rate = 24000;
vgmstream->num_samples = read_s32le(0x04,sf);
vgmstream->loop_start_sample = read_s32le(0x08,sf);
vgmstream->loop_end_sample = read_s32le(0x0C,sf);
vgmstream->coding_type = coding_PCM16LE;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x02;
vgmstream->meta_type = meta_PCM_KCEJE;
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
goto fail;
return vgmstream;
fail:
if (vgmstream) close_vgmstream(vgmstream);
return NULL;
}

View File

@ -1,48 +0,0 @@
#include "meta.h"
#include "../coding/coding.h"
/* .PCM - KCE Japan East PS2 games (Ephemeral Fantasia, Yu-Gi-Oh! The Duelists of the Roses, 7 Blades) */
VGMSTREAM * init_vgmstream_ps2_pcm(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset;
int loop_flag, channel_count;
/* check extension */
if ( !check_extensions(streamFile,"pcm") )
goto fail;
/* check header (data_size vs num_samples) */
if (pcm_bytes_to_samples(read_32bitLE(0x00,streamFile), 2, 16) != read_32bitLE(0x04,streamFile))
goto fail;
/* should work too */
//if (read_32bitLE(0x00,streamFile)+0x800 != get_streamfile_size(streamFile))
// goto fail;
loop_flag = (read_32bitLE(0x0C,streamFile) != 0x00);
channel_count = 2;
start_offset = 0x800;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
vgmstream->channels = channel_count;
vgmstream->sample_rate = 24000;
vgmstream->num_samples = read_32bitLE(0x04,streamFile);
vgmstream->loop_start_sample = read_32bitLE(0x08,streamFile);
vgmstream->loop_end_sample = read_32bitLE(0x0C,streamFile);
vgmstream->coding_type = coding_PCM16LE;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x2;
vgmstream->meta_type = meta_PS2_PCM;
/* open the file for reading */
if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) )
goto fail;
return vgmstream;
fail:
if (vgmstream) close_vgmstream(vgmstream);
return NULL;
}

View File

@ -823,7 +823,7 @@ static int parse_psb(STREAMFILE* sf, psb_header_t* psb) {
/* enforced by M2 code */
version = psb_node_get_float(&nroot, "version");
if (version < 1.02f || version > 1.02f) {
vgm_logi("PSB: unsupported version %f (report)\n", version);
vgm_logi("PSB: unsupported version %f (report)\n", (double)version);
goto fail;
}

View File

@ -1,6 +1,7 @@
#include "meta.h"
#include "../layout/layout.h"
#include "../coding/coding.h"
#include "../util/layout_utils.h"
/* PSF single - Pivotal games single segment (external in some PC/Xbox or inside bigfiles) [The Great Escape, Conflict series] */

View File

@ -244,8 +244,8 @@ static int read_fmt(int big_endian, STREAMFILE* sf, off_t offset, riff_fmt_chunk
/* real 0x300 is "Fujitsu FM Towns SND" with block align 0x01 */
break;
case 0x0555: /* Level-5 0x555 ADPCM (unofficial) */
fmt->coding_type = coding_L5_555;
case 0x0555: /* Level-5 ADPCM (unofficial) */
fmt->coding_type = coding_LEVEL5;
fmt->interleave = 0x12;
break;
@ -473,7 +473,7 @@ 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) */
}
@ -738,7 +738,7 @@ VGMSTREAM* init_vgmstream_riff(STREAMFILE* sf) {
vgmstream->num_samples = pcm_bytes_to_samples(data_size, fmt.channels, fmt.bps);
break;
case coding_L5_555:
case coding_LEVEL5:
vgmstream->num_samples = data_size / 0x12 / fmt.channels * 32;
/* coefs */
@ -912,7 +912,7 @@ VGMSTREAM* init_vgmstream_riff(STREAMFILE* sf) {
vgmstream->loop_end_sample = loop_end_wsmp;
vgmstream->meta_type = meta_RIFF_WAVE_wsmp;
}
else if (fmt.coding_type == coding_L5_555 && mwv_ctrl_offset) {
else if (fmt.coding_type == coding_LEVEL5 && mwv_ctrl_offset) {
vgmstream->loop_start_sample = read_s32le(mwv_ctrl_offset + 0x0c, sf);
vgmstream->loop_end_sample = vgmstream->num_samples;
vgmstream->meta_type = meta_RIFF_WAVE_MWV;

View File

@ -1,6 +1,7 @@
#include "meta.h"
#include "../coding/coding.h"
#include "../layout/layout.h"
#include "../util/layout_utils.h"
#include "sab_streamfile.h"
typedef struct {
@ -234,7 +235,6 @@ static VGMSTREAM* build_layered_vgmstream(STREAMFILE* sf, sab_header* sab) {
VGMSTREAM* vgmstream = NULL;
STREAMFILE* temp_sf = NULL;
layered_layout_data* data = NULL;
int i;
if (sab->sound_count == 1 || !sab->is_stream) {
return build_vgmstream(sf, sab);
@ -245,7 +245,7 @@ static VGMSTREAM* build_layered_vgmstream(STREAMFILE* sf, sab_header* sab) {
if (!data) goto fail;
/* de-chunk audio layers */
for (i = 0; i < sab->sound_count; i++) {
for (int i = 0; i < sab->sound_count; i++) {
temp_sf = setup_sab_streamfile(sf, sab->stream_offset, sab->sound_count, i, sab->block_size);
if (!temp_sf) goto fail;

View File

@ -2,6 +2,7 @@
#include "../layout/layout.h"
#include "../coding/coding.h"
#include "../util/endianness.h"
#include "../util/layout_utils.h"
/* also see init_vgmstream_dsp_sps_n1 and init_vgmstream_opus_sps_n1 */

View File

@ -5,6 +5,7 @@
#include "../layout/layout.h"
#include "../base/mixing.h"
#include "../base/plugins.h"
#include "../util/layout_utils.h"
/*******************************************************************************/

View File

@ -990,7 +990,7 @@ static int parse_type_silence(ubi_bao_header* bao, off_t offset, STREAMFILE* sf)
bao->duration = read_f32(h_offset + bao->cfg.silence_duration_float, sf);
if (bao->duration <= 0.0f) {
VGM_LOG("UBI BAO: bad duration %f at %x\n", bao->duration, (uint32_t)offset);
VGM_LOG("UBI BAO: bad duration %f at %x\n", (double)bao->duration, (uint32_t)offset);
goto fail;
}

View File

@ -2494,6 +2494,8 @@ static int parse_header(ubi_sb_header* sb, STREAMFILE* sf, off_t offset, int ind
sb->duration = 1.0f;
break;
}
// fall through
default:
VGM_LOG("UBI SB: unknown header type %x at %x\n", sb->header_type, (uint32_t)offset);
goto fail;

View File

@ -1,59 +1,33 @@
#include "meta.h"
#include "../util.h"
/* WPD (from Shuffle! (PC)) */
VGMSTREAM * init_vgmstream_wpd(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
char filename[PATH_LIMIT];
off_t start_offset;
int channel_count;
int loop_flag;
/* check extension, case insensitive */
streamFile->get_name(streamFile,filename,sizeof(filename));
if (strcasecmp("wpd",filename_extension(filename))) goto fail;
/* check header */
if (read_32bitBE(0x00,streamFile) != 0x20445057) /* " DPW" */
goto fail;
channel_count = read_32bitLE(0x4,streamFile);
loop_flag = 0;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
/* fill in the vital statistics */
start_offset = 0x30;
vgmstream->channels = channel_count;
vgmstream->sample_rate = read_32bitLE(0x10,streamFile);
vgmstream->coding_type = coding_PCM16LE;
vgmstream->num_samples = (read_32bitLE(0x14,streamFile))/2/channel_count;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 2;
vgmstream->meta_type = meta_WPD;
/* open the file for reading */
{
int i;
STREAMFILE * file;
file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
if (!file) goto fail;
for (i=0;i<channel_count;i++) {
vgmstream->ch[i].streamfile = file;
vgmstream->ch[i].channel_start_offset=
vgmstream->ch[i].offset=start_offset+
vgmstream->interleave_block_size*i;
}
}
return vgmstream;
/* clean up anything we may have opened */
fail:
if (vgmstream) close_vgmstream(vgmstream);
return NULL;
}
#include "meta.h"
#include "../util/meta_utils.h"
/* WPD - from Shuffle! (PC) */
VGMSTREAM* init_vgmstream_wpd(STREAMFILE* sf) {
/* checks */
if (!is_id32be(0x00,sf, " DPW"))
return NULL;
if (!check_extensions(sf, "wpd"))
return NULL;
meta_header_t h = {0};
h.meta = meta_WPD;
h.channels = read_u32le(0x04,sf); /* always 2? */
// 08: always 2?
// 0c: bits per sample (16)
h.sample_rate = read_s32le(0x10,sf); /* big endian? */
h.data_size = read_u32le(0x14,sf);
// 18: PCM fmt (codec 0001, channels, srate, bitrate...)
h.stream_offset = 0x30;
h.num_samples = pcm16_bytes_to_samples(h.data_size, h.channels);
h.coding = coding_PCM16LE;
h.layout = layout_interleave;
h.interleave = 0x02;
h.sf = sf;
h.open_stream = true;
return alloc_metastream(&h);
}

View File

@ -2,15 +2,11 @@
#include "../layout/layout.h"
#include "../util.h"
/* Westwood Studios .aud (WS-AUD) */
/* .AUD - from Westwood Studios games [Command & Conquer (PC), ] */
VGMSTREAM* init_vgmstream_ws_aud(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
coding_t coding_type = -1;
off_t format_offset;
int channels;
bool new_type = false;
int bytes_per_sample = 0;
/* checks **/
@ -31,82 +27,69 @@ VGMSTREAM* init_vgmstream_ws_aud(STREAMFILE* sf) {
}
/* blocked format with a mini-header */
int sample_rate = read_u16le(0x00,sf);
uint8_t channel_flags = read_u8(format_offset + 0x00, sf);
uint8_t format_flags = read_u8(format_offset + 0x01, sf);
if (read_u8(format_offset + 0x00, sf) & 1)
channels = 2;
else
channels = 1;
int channels = channel_flags & 1 ? 2 : 1;
if (channels == 2)
goto fail; /* not seen */
return NULL; /* not seen */
int bytes_per_sample = (channel_flags & 2) ? 2 : 1;
if (read_u8(format_offset + 0x01,sf) & 2)
bytes_per_sample = 2;
else
bytes_per_sample = 1;
/* check codec type */
switch (read_u8(format_offset + 0x01,sf)) {
case 1: /* Westwood custom */
coding_type = coding_WS;
if (bytes_per_sample != 1) goto fail; /* shouldn't happen? */
break;
case 99: /* IMA ADPCM */
coding_type = coding_IMA_int;
break;
default:
goto fail;
uint32_t data_size;
if (new_type) {
data_size = read_u32le(0x06,sf);
}
else {
/* to read through the file looking at chunk headers */
off_t offset = 0x08;
off_t file_size = get_streamfile_size(sf);
data_size = 0;
while (offset < file_size) {
uint16_t chunk_size = read_u16le(offset + 0x00,sf);
data_size += read_u16le(offset + 0x02,sf);
/* while we're here might as well check for valid chunks */
if (read_u32le(offset + 0x04, sf) != 0x0000DEAF)
goto fail;
offset += 0x08 + chunk_size;
}
}
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channels, 0);
if (!vgmstream) goto fail;
if (new_type) {
vgmstream->num_samples = read_32bitLE(0x06,sf)/bytes_per_sample/channels;
}
else {
/* Doh, no output size in old type files. We have to read through the
* file looking at chunk headers! Crap! */
int32_t out_size = 0;
off_t current_offset = 0x8;
off_t file_size = get_streamfile_size(sf);
while (current_offset < file_size) {
int16_t chunk_size;
chunk_size = read_16bitLE(current_offset,sf);
out_size += read_16bitLE(current_offset+2,sf);
/* while we're here might as well check for valid chunks */
if (read_32bitLE(current_offset+4,sf) != 0x0000DEAF) goto fail;
current_offset+=8+chunk_size;
}
vgmstream->num_samples = out_size/bytes_per_sample/channels;
}
vgmstream->meta_type = meta_WS_AUD;
vgmstream->sample_rate = sample_rate;
vgmstream->num_samples = data_size / bytes_per_sample / channels;
/* they tend to not actually have data for the last odd sample */
if (vgmstream->num_samples & 1) vgmstream->num_samples--;
vgmstream->sample_rate = (uint16_t)read_16bitLE(0x00,sf);
if (vgmstream->num_samples & 1)
vgmstream->num_samples--;
vgmstream->coding_type = coding_type;
if (new_type) {
vgmstream->meta_type = meta_WS_AUD;
switch (format_flags) {
case 0x01: /* Westwood ADPCM [The Legend of Kyrandia - Book 3 (PC)] */
vgmstream->coding_type = coding_WS;
if (bytes_per_sample != 1) /* shouldn't happen? */
goto fail;
break;
case 0x63: /* IMA ADPCM [Blade Runner (PC)] */
vgmstream->coding_type = coding_IMA_int;
break;
default:
goto fail;
}
vgmstream->layout_type = layout_blocked_ws_aud;
if (!vgmstream_open_stream(vgmstream, sf, 0x00) )
goto fail;
if (new_type) {
block_update(0x0c, vgmstream);
} else {
block_update(0x08, vgmstream);
}
block_update(new_type ? 0x0c : 0x08, vgmstream);
return vgmstream;
fail:
if (vgmstream) close_vgmstream(vgmstream);
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -156,8 +156,8 @@ static int lz4mg_decompress(lz4mg_stream_t* strm) {
} while (next_len == LZ4MG_VARLEN_CONTINUE);
ctx->state = SET_MATCH;
//break; // Falthrough for MSVC
//break; // for MSVC (jump threading optimization compiler bug, fixed in ~2023-12)
// fall through
case SET_MATCH:
ctx->match_len += LZ4MG_MIN_MATCH_LEN;
@ -166,8 +166,8 @@ static int lz4mg_decompress(lz4mg_stream_t* strm) {
ctx->match_pos = LZ4MG_WINDOW_SIZE + ctx->match_pos;
ctx->state = COPY_MATCH;
//break; // Fallthrough for MSVC
//break; // for MSVC (jump threading optimization compiler bug, fixed in ~2023-12)
// fall through
case COPY_MATCH:
while (ctx->match_len > 0) {
if (dst_pos >= dst_size)

View File

@ -38,7 +38,6 @@
#endif /* _MSC_VER */
typedef int16_t sample; //TODO: deprecated, remove
typedef int16_t sample_t;
#endif

View File

@ -33,7 +33,7 @@ static inline int guess_endian32(off_t offset, STREAMFILE* sf) {
}
static inline read_u32_t guess_read_u32(off_t offset, STREAMFILE* sf) {
return guess_endian32(0x08,sf) ? read_u32be : read_u32le;
return guess_endian32(offset,sf) ? read_u32be : read_u32le;
}
#endif

View File

@ -3,6 +3,7 @@
#include "../vgmstream.h"
#include "../layout/layout.h"
#include "../coding/coding.h"
#include "../base/plugins.h"
typedef VGMSTREAM* (*init_vgmstream_t)(STREAMFILE*);
@ -147,3 +148,148 @@ bool layered_add_done(VGMSTREAM* vs) {
fail:
return false;
}
/* helper for easier creation of layers */
VGMSTREAM* allocate_layered_vgmstream(layered_layout_data* data) {
VGMSTREAM* vgmstream = NULL;
int i, channels, loop_flag, sample_rate, external_looping;
int32_t num_samples, loop_start, loop_end;
int delta = 1024;
coding_t coding_type = data->layers[0]->coding_type;
/* get data */
channels = data->output_channels;
num_samples = 0;
loop_flag = 1;
loop_start = data->layers[0]->loop_start_sample;
loop_end = data->layers[0]->loop_end_sample;
external_looping = 0;
sample_rate = 0;
for (i = 0; i < data->layer_count; i++) {
int32_t layer_samples = vgmstream_get_samples(data->layers[i]);
int layer_loop = data->layers[i]->loop_flag;
int32_t layer_loop_start = data->layers[i]->loop_start_sample;
int32_t layer_loop_end = data->layers[i]->loop_end_sample;
int layer_rate = data->layers[i]->sample_rate;
/* internal has own config (and maybe looping), looping now must be done on layout level
* (instead of on each layer, that is faster) */
if (data->layers[i]->config_enabled) {
loop_flag = 0;
layer_loop = 0;
external_looping = 1;
}
/* all layers should share loop pointsto consider looping enabled,
* but allow some leeway (ex. Dragalia Lost bgm+vocals ~12 samples) */
if (!layer_loop
|| !(loop_start >= layer_loop_start - delta && loop_start <= layer_loop_start + delta)
|| !(loop_end >= layer_loop_end - delta && loop_start <= layer_loop_end + delta)) {
loop_flag = 0;
loop_start = 0;
loop_end = 0;
}
if (num_samples < layer_samples) /* max */
num_samples = layer_samples;
if (sample_rate < layer_rate)
sample_rate = layer_rate;
if (coding_type == coding_SILENCE)
coding_type = data->layers[i]->coding_type;
}
data->external_looping = external_looping;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channels, loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = data->layers[0]->meta_type;
vgmstream->sample_rate = sample_rate;
vgmstream->num_samples = num_samples;
vgmstream->loop_start_sample = loop_start;
vgmstream->loop_end_sample = loop_end;
vgmstream->coding_type = coding_type;
vgmstream->layout_type = layout_layered;
vgmstream->layout_data = data;
return vgmstream;
fail:
if (vgmstream) vgmstream->layout_data = NULL;
close_vgmstream(vgmstream);
return NULL;
}
/* helper for easier creation of segments */
VGMSTREAM* allocate_segmented_vgmstream(segmented_layout_data* data, int loop_flag, int loop_start_segment, int loop_end_segment) {
VGMSTREAM* vgmstream = NULL;
int channel_layout;
int i, sample_rate;
int32_t num_samples, loop_start, loop_end;
coding_t coding_type = data->segments[0]->coding_type;
/* save data */
channel_layout = data->segments[0]->channel_layout;
num_samples = 0;
loop_start = 0;
loop_end = 0;
sample_rate = 0;
for (i = 0; i < data->segment_count; i++) {
/* needs get_samples since element may use play settings */
int32_t segment_samples = vgmstream_get_samples(data->segments[i]);
int segment_rate = data->segments[i]->sample_rate;
if (loop_flag && i == loop_start_segment)
loop_start = num_samples;
num_samples += segment_samples;
if (loop_flag && i == loop_end_segment)
loop_end = num_samples;
/* inherit first segment's layout but only if all segments' layout match */
if (channel_layout != 0 && channel_layout != data->segments[i]->channel_layout)
channel_layout = 0;
if (sample_rate < segment_rate)
sample_rate = segment_rate;
if (coding_type == coding_SILENCE)
coding_type = data->segments[i]->coding_type;
}
/* respect loop_flag even when no loop_end found as it's possible file loops are set outside */
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(data->output_channels, loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = data->segments[0]->meta_type;
vgmstream->sample_rate = sample_rate;
vgmstream->num_samples = num_samples;
vgmstream->loop_start_sample = loop_start;
vgmstream->loop_end_sample = loop_end;
vgmstream->coding_type = coding_type;
vgmstream->channel_layout = channel_layout;
vgmstream->layout_type = layout_segmented;
vgmstream->layout_data = data;
return vgmstream;
fail:
if (vgmstream) vgmstream->layout_data = NULL;
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -2,6 +2,7 @@
#define _LAYOUTS_UTIL_H
#include "../vgmstream.h"
#include "../layout/layout.h"
typedef VGMSTREAM* (*init_vgmstream_t)(STREAMFILE*);
@ -18,4 +19,7 @@ bool layered_add_codec(VGMSTREAM* vs, int layers, int layer_channels);
/* call when done adding layers */
bool layered_add_done(VGMSTREAM* vs);
VGMSTREAM* allocate_layered_vgmstream(layered_layout_data* data);
VGMSTREAM* allocate_segmented_vgmstream(segmented_layout_data* data, int loop_flag, int loop_start_segment, int loop_end_segment);
#endif

View File

@ -812,7 +812,7 @@ static void print_internal(psb_node_t* curr, int depth) {
break;
case PSB_TYPE_FLOAT:
printf("%f,\n", res.flt);
printf("%f,\n", (double)res.flt);
break;
case PSB_TYPE_STRING:

View File

@ -94,27 +94,28 @@ typedef struct {
} play_state_t;
/* info for a single vgmstream channel */
/* info for a single vgmstream 'channel' (or rather, mono stream) */
typedef struct {
STREAMFILE* streamfile; /* file used by this channel */
off_t channel_start_offset; /* where data for this channel begins */
off_t offset; /* current location in the file */
off_t frame_header_offset; /* offset of the current frame header (for WS) */
int samples_left_in_frame; /* for WS */
/* format and channel specific */
/* format specific */
/* adpcm */
int16_t adpcm_coef[16]; /* formats with decode coefficients built in (DSP, some ADX) */
int32_t adpcm_coef_3by32[0x60]; /* Level-5 0x555 */
int16_t vadpcm_coefs[8*2*8]; /* VADPCM: max 8 groups * max 2 order * fixed 8 subframe coefs */
/* ADPCM with built or variable decode coefficients */
union {
int16_t adpcm_history1_16; /* previous sample */
int16_t adpcm_coef[16]; /* DSP, some ADX (in rare cases may change per block) */
int16_t vadpcm_coefs[8*2*8]; /* VADPCM: max 8 groups * max 2 order * fixed 8 subframe = 128 coefs */
int32_t adpcm_coef_3by32[96]; /* Level-5 0x555 */
};
/* previous ADPCM samples */
union {
int16_t adpcm_history1_16;
int32_t adpcm_history1_32;
};
union {
int16_t adpcm_history2_16; /* previous previous sample */
int16_t adpcm_history2_16;
int32_t adpcm_history2_32;
};
union {
@ -129,14 +130,20 @@ typedef struct {
//double adpcm_history1_double;
//double adpcm_history2_double;
int adpcm_step_index; /* for IMA */
int adpcm_scale; /* for MS ADPCM */
/* for ADPCM decoders that store steps (IMA) or scales (MSADPCM) */
union {
int adpcm_step_index;
int adpcm_scale;
};
/* Westwood Studios decoder */
off_t ws_frame_header_offset; /* offset of the current frame header */
int ws_samples_left_in_frame; /* last decoded info */
/* state for G.721 decoder, sort of big but we might as well keep it around */
struct g72x_state g72x_state;
/* ADX encryption */
int adx_channels;
uint16_t adx_xor;
uint16_t adx_mult;
uint16_t adx_add;
@ -147,9 +154,9 @@ typedef struct {
/* main vgmstream info */
typedef struct {
/* basic config */
int32_t num_samples; /* the actual max number of samples */
int channels; /* number of channels for the current stream */
int32_t sample_rate; /* sample rate in Hz */
int channels; /* number of channels */
int32_t num_samples; /* the actual max number of samples */
coding_t coding_type; /* type of encoding */
layout_t layout_type; /* type of layout */
meta_t meta_type; /* type of metadata */
@ -180,13 +187,13 @@ typedef struct {
int format_id; /* internal format ID */
/* layout/block state */
size_t full_block_size; /* actual data size of an entire block (ie. may be fixed, include padding/headers, etc) */
int32_t current_sample; /* sample point within the file (for loop detection) */
int32_t samples_into_block; /* number of samples into the current block/interleave/segment/etc */
off_t current_block_offset; /* start of this block (offset of block header) */
size_t current_block_size; /* size in usable bytes of the block we're in now (used to calculate num_samples per block) */
int32_t current_block_samples; /* size in samples of the block we're in now (used over current_block_size if possible) */
off_t next_block_offset; /* offset of header of the next block */
size_t full_block_size; /* actual data size of an entire block (ie. may be fixed, include padding/headers, etc) */
/* loop state (saved when loop is hit to restore later) */
int32_t loop_current_sample; /* saved from current_sample (same as loop_start_sample, but more state-like) */
@ -228,35 +235,13 @@ typedef struct {
play_state_t pstate; /* player state (applied over decoding) */
int loop_count; /* counter of complete loops (1=looped once) */
int loop_target; /* max loops before continuing with the stream end (loops forever if not set) */
sample_t* tmpbuf; /* garbage buffer used for seeking/trimming */
size_t tmpbuf_size; /* for all channels (samples = tmpbuf_size / channels) */
} VGMSTREAM;
/* for files made of "continuous" segments, one per section of a song (using a complete sub-VGMSTREAM) */
typedef struct {
int segment_count;
VGMSTREAM** segments;
int current_segment;
sample_t* buffer;
int input_channels; /* internal buffer channels */
int output_channels; /* resulting channels (after mixing, if applied) */
int mixed_channels; /* segments have different number of channels */
} segmented_layout_data;
/* for files made of "parallel" layers, one per group of channels (using a complete sub-VGMSTREAM) */
typedef struct {
int layer_count;
VGMSTREAM** layers;
sample_t* buffer;
int input_channels; /* internal buffer channels */
int output_channels; /* resulting channels (after mixing, if applied) */
int external_looping; /* don't loop using per-layer loops, but layout's own looping */
int curr_layer; /* helper */
} layered_layout_data;
// VGMStream description in structure format
typedef struct {
int sample_rate;
@ -304,9 +289,6 @@ void reset_vgmstream(VGMSTREAM* vgmstream);
/* close an open vgmstream */
void close_vgmstream(VGMSTREAM* vgmstream);
/* calculate the number of samples to be played based on looping parameters */
int32_t get_vgmstream_play_samples(double looptimes, double fadeseconds, double fadedelayseconds, VGMSTREAM* vgmstream);
/* Decode data into sample buffer. Returns < sample_count on stream end */
int render_vgmstream(sample_t* buffer, int32_t sample_count, VGMSTREAM* vgmstream);
@ -321,20 +303,6 @@ void describe_vgmstream_info(VGMSTREAM* vgmstream, vgmstream_info* desc);
/* Return the average bitrate in bps of all unique files contained within this stream. */
int get_vgmstream_average_bitrate(VGMSTREAM* vgmstream);
/* List supported formats and return elements in the list, for plugins that need to know.
* The list disables some common formats that may conflict (.wav, .ogg, etc). */
const char** vgmstream_get_formats(size_t* size);
/* same, but for common-but-disabled formats in the above list. */
const char** vgmstream_get_common_formats(size_t* size);
/* Force enable/disable internal looping. Should be done before playing anything (or after reset),
* and not all codecs support arbitrary loop values ATM. */
void vgmstream_force_loop(VGMSTREAM* vgmstream, int loop_flag, int loop_start_sample, int loop_end_sample);
/* Set number of max loops to do, then play up to stream end (for songs with proper endings) */
void vgmstream_set_loop_target(VGMSTREAM* vgmstream, int loop_target);
/* Return 1 if vgmstream detects from the filename that said file can be used even if doesn't physically exist */
int vgmstream_is_virtual_filename(const char* filename);
@ -358,5 +326,16 @@ void get_vgmstream_coding_description(VGMSTREAM* vgmstream, char* out, size_t ou
void get_vgmstream_layout_description(VGMSTREAM* vgmstream, char* out, size_t out_size);
void get_vgmstream_meta_description(VGMSTREAM* vgmstream, char* out, size_t out_size);
/* calculate the number of samples to be played based on looping parameters */
int32_t get_vgmstream_play_samples(double looptimes, double fadeseconds, double fadedelayseconds, VGMSTREAM* vgmstream);
void setup_state_vgmstream(VGMSTREAM* vgmstream);
/* Force enable/disable internal looping. Should be done before playing anything (or after reset),
* and not all codecs support arbitrary loop values ATM. */
void vgmstream_force_loop(VGMSTREAM* vgmstream, int loop_flag, int loop_start_sample, int loop_end_sample);
/* Set number of max loops to do, then play up to stream end (for songs with proper endings) */
void vgmstream_set_loop_target(VGMSTREAM* vgmstream, int loop_target);
#endif

View File

@ -81,7 +81,6 @@ init_vgmstream_t init_vgmstream_functions[] = {
init_vgmstream_vig_kces,
init_vgmstream_hxd,
init_vgmstream_vsv,
init_vgmstream_ps2_pcm,
init_vgmstream_ps2_rkv,
init_vgmstream_lp_ap_lep,
init_vgmstream_sdt,
@ -158,7 +157,7 @@ init_vgmstream_t init_vgmstream_functions[] = {
init_vgmstream_naomi_adpcm,
init_vgmstream_sd9,
init_vgmstream_2dx9,
init_vgmstream_dsp_ygo,
init_vgmstream_dsp_kceje,
init_vgmstream_ps2_vgv,
init_vgmstream_gcub,
init_vgmstream_maxis_xa,
@ -527,6 +526,7 @@ init_vgmstream_t init_vgmstream_functions[] = {
init_vgmstream_tgc,
init_vgmstream_rage_aud,
init_vgmstream_asd_naxat,
init_vgmstream_pcm_kceje,
/* need companion files */
init_vgmstream_pos,
init_vgmstream_sli_loops,

View File

@ -106,7 +106,7 @@ typedef enum {
coding_TGC, /* Tiger Game.com 4-bit ADPCM */
coding_NDS_PROCYON, /* Procyon Studio ADPCM */
coding_L5_555, /* Level-5 0x555 ADPCM */
coding_LEVEL5, /* Level-5 ADPCM */
coding_LSF, /* lsf ADPCM (Fastlane Street Racing iPhone)*/
coding_MTAF, /* Konami MTAF ADPCM */
coding_MTA2, /* Konami MTA2 ADPCM */
@ -265,7 +265,7 @@ typedef enum {
meta_MUS_KROME,
meta_DSP_WII_WSD, /* Phantom Brave (WII) */
meta_WII_NDP, /* Vertigo (Wii) */
meta_DSP_YGO, /* Konami: Yu-Gi-Oh! The Falsebound Kingdom (NGC), Hikaru no Go 3 (NGC) */
meta_DSP_KCEJE,
meta_STRM, /* Nintendo STRM */
meta_RSTM, /* Nintendo RSTM (Revolution Stream, similar to STRM) */
@ -345,7 +345,7 @@ typedef enum {
meta_HXD,
meta_VSV,
meta_SCD_PCM, /* Lunar - Eternal Blue */
meta_PS2_PCM, /* Konami KCEJ East: Ephemeral Fantasia, Yu-Gi-Oh! The Duelists of the Roses, 7 Blades */
meta_PCM_KCEJE,
meta_PS2_RKV, /* Legacy of Kain - Blood Omen 2 (PS2) */
meta_VAS_KCEO,
meta_LP_AP_LEP,
@ -429,8 +429,8 @@ typedef enum {
meta_MUS_ACM, /* MUS playlist of InterPlay ACM files */
meta_DEC, /* Falcom PC games (Xanadu Next, Gurumin) */
meta_VS, /* Men in Black .vs */
meta_FFXI_BGW, /* FFXI (PC) BGW */
meta_FFXI_SPW, /* FFXI (PC) SPW */
meta_BGW,
meta_SPW,
meta_STS,
meta_P2BT_MOVE_VISA,
meta_GBTS,
@ -505,7 +505,7 @@ typedef enum {
meta_EB_SF0, /* Excitebots .sf0 */
meta_MTAF,
meta_ALP,
meta_WPD, /* Shuffle! (PC) */
meta_WPD,
meta_MN_STR, /* Mini Ninjas (PC/PS3/WII) */
meta_MSS, /* Guerilla: ShellShock Nam '67 (PS2/Xbox), Killzone (PS2) */
meta_PS2_HSF, /* Lowrider (PS2) */

View File

@ -40,7 +40,7 @@ void build_extension_list(char* winamp_list, int winamp_list_size) {
for (i = 0; i < ext_list_len; i++) {
int used = add_extension(winamp_list, winamp_list_size - description_size, ext_list[i]);
if (used <= 0) {
vgm_logi("build_extension_list: not enough buf for all exts\n");
//vgm_logi("build_extension_list: not enough buf for all exts\n");
break;
}
winamp_list += used;

View File

@ -237,8 +237,9 @@ void WINAPI xmplay_GetInfoText(char* format, char* length) {
rate = vgmstream->sample_rate;
samples = vgmstream->num_samples;
bps = get_vgmstream_average_bitrate(vgmstream) / 1000;
get_vgmstream_coding_description(vgmstream, fmt, sizeof(fmt));
if (strcmp(fmt, "FFmpeg") == 0)
//get_vgmstream_coding_description(vgmstream, fmt, sizeof(fmt));
//if (strcmp(fmt, "FFmpeg") == 0)
{
char buffer[1024];
buffer[0] = '\0';