Added vgmstream plugin
parent
85cc09e07f
commit
a4d0959623
|
@ -141,6 +141,7 @@
|
|||
8359009D17FF06570060F3ED /* ArchiveSource.bundle in CopyFiles */ = {isa = PBXBuildFile; fileRef = 8359FF3117FEF35D0060F3ED /* ArchiveSource.bundle */; };
|
||||
8360EF6D17F92E56005208A4 /* HighlyComplete.bundle in CopyFiles */ = {isa = PBXBuildFile; fileRef = 8360EF0517F92B24005208A4 /* HighlyComplete.bundle */; };
|
||||
836D28A818086386005B7299 /* MiniModeMenuTitleTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = 836D28A718086386005B7299 /* MiniModeMenuTitleTransformer.m */; };
|
||||
836F706218BDD1230095E648 /* vgmstream.bundle in CopyFiles */ = {isa = PBXBuildFile; fileRef = 836F6B2E18BDB80E0095E648 /* vgmstream.bundle */; };
|
||||
836FB5A718206F2500B3AD2D /* Hively.bundle in CopyFiles */ = {isa = PBXBuildFile; fileRef = 836FB5471820538800B3AD2D /* Hively.bundle */; };
|
||||
8375B36517FFEF130092A79F /* Opus.bundle in CopyFiles */ = {isa = PBXBuildFile; fileRef = 8375B05717FFEA410092A79F /* Opus.bundle */; };
|
||||
83790D501809F4980073CF51 /* NSObject+SPInvocationGrabbing.m in Sources */ = {isa = PBXBuildFile; fileRef = 83790D4D1809F4980073CF51 /* NSObject+SPInvocationGrabbing.m */; };
|
||||
|
@ -434,6 +435,13 @@
|
|||
remoteGlobalIDString = 8360EEE417F92AC8005208A4;
|
||||
remoteInfo = HighlyComplete;
|
||||
};
|
||||
836F6B2D18BDB80E0095E648 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 836F6B2518BDB80D0095E648 /* vgmstream.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = 836F6B1018BDB80D0095E648;
|
||||
remoteInfo = vgmstream;
|
||||
};
|
||||
836FB5461820538800B3AD2D /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 836FB5421820538700B3AD2D /* Hively.xcodeproj */;
|
||||
|
@ -620,6 +628,7 @@
|
|||
dstPath = "";
|
||||
dstSubfolderSpec = 13;
|
||||
files = (
|
||||
836F706218BDD1230095E648 /* vgmstream.bundle in CopyFiles */,
|
||||
836FB5A718206F2500B3AD2D /* Hively.bundle in CopyFiles */,
|
||||
83A0F4E31816DBF900119DB4 /* playptmod.bundle in CopyFiles */,
|
||||
83B06704180D579E008E3612 /* MIDI.bundle in CopyFiles */,
|
||||
|
@ -866,6 +875,7 @@
|
|||
8360EF0017F92B23005208A4 /* HighlyComplete.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = HighlyComplete.xcodeproj; path = Plugins/HighlyComplete/HighlyComplete.xcodeproj; sourceTree = "<group>"; };
|
||||
836D28A618086386005B7299 /* MiniModeMenuTitleTransformer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MiniModeMenuTitleTransformer.h; path = Window/MiniModeMenuTitleTransformer.h; sourceTree = "<group>"; };
|
||||
836D28A718086386005B7299 /* MiniModeMenuTitleTransformer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MiniModeMenuTitleTransformer.m; path = Window/MiniModeMenuTitleTransformer.m; sourceTree = "<group>"; };
|
||||
836F6B2518BDB80D0095E648 /* vgmstream.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = vgmstream.xcodeproj; path = Plugins/vgmstream/vgmstream.xcodeproj; sourceTree = "<group>"; };
|
||||
836FB5421820538700B3AD2D /* Hively.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = Hively.xcodeproj; path = Plugins/Hively/Hively.xcodeproj; sourceTree = "<group>"; };
|
||||
8375B05117FFEA400092A79F /* Opus.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = Opus.xcodeproj; path = Plugins/Opus/Opus.xcodeproj; sourceTree = "<group>"; };
|
||||
83790D4C1809F4980073CF51 /* NSObject+SPInvocationGrabbing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSObject+SPInvocationGrabbing.h"; sourceTree = "<group>"; };
|
||||
|
@ -1221,6 +1231,7 @@
|
|||
83B0669C180D5668008E3612 /* MIDI.xcodeproj */,
|
||||
83A0F4841816CE5E00119DB4 /* playptmod.xcodeproj */,
|
||||
836FB5421820538700B3AD2D /* Hively.xcodeproj */,
|
||||
836F6B2518BDB80D0095E648 /* vgmstream.xcodeproj */,
|
||||
);
|
||||
name = PlugIns;
|
||||
sourceTree = "<group>";
|
||||
|
@ -1551,6 +1562,14 @@
|
|||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
836F6B2618BDB80D0095E648 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
836F6B2E18BDB80E0095E648 /* vgmstream.bundle */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
836FB5431820538700B3AD2D /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -1908,6 +1927,10 @@
|
|||
ProductGroup = 17C808B10C3BD1C5005707C4 /* Products */;
|
||||
ProjectRef = 17C808B00C3BD1C5005707C4 /* TagLib.xcodeproj */;
|
||||
},
|
||||
{
|
||||
ProductGroup = 836F6B2618BDB80D0095E648 /* Products */;
|
||||
ProjectRef = 836F6B2518BDB80D0095E648 /* vgmstream.xcodeproj */;
|
||||
},
|
||||
{
|
||||
ProductGroup = 17C808B80C3BD1D2005707C4 /* Products */;
|
||||
ProjectRef = 17C808B70C3BD1D2005707C4 /* Vorbis.xcodeproj */;
|
||||
|
@ -2044,6 +2067,13 @@
|
|||
remoteRef = 8360EF0417F92B24005208A4 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
836F6B2E18BDB80E0095E648 /* vgmstream.bundle */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = wrapper.cfbundle;
|
||||
path = vgmstream.bundle;
|
||||
remoteRef = 836F6B2D18BDB80E0095E648 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
836FB5471820538800B3AD2D /* Hively.bundle */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = wrapper.cfbundle;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,2 @@
|
|||
/* Localized versions of Info.plist keys */
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
noinst_LTLIBRARIES = libcoding.la
|
||||
|
||||
AM_CFLAGS = -Wall @CFLAGS@ -I$(top_builddir) -I$(top_srcdir)
|
||||
AM_MAKEFLAGS=-f Makefile.unix
|
||||
|
||||
libcoding_la_LDFLAGS =
|
||||
libcoding_la_SOURCES =
|
||||
libcoding_la_SOURCES += adx_decoder.c
|
||||
libcoding_la_SOURCES += eaxa_decoder.c
|
||||
libcoding_la_SOURCES += g721_decoder.c
|
||||
libcoding_la_SOURCES += ima_decoder.c
|
||||
libcoding_la_SOURCES += ngc_afc_decoder.c
|
||||
libcoding_la_SOURCES += ngc_dsp_decoder.c
|
||||
libcoding_la_SOURCES += ngc_dtk_decoder.c
|
||||
libcoding_la_SOURCES += pcm_decoder.c
|
||||
libcoding_la_SOURCES += psx_decoder.c
|
||||
libcoding_la_SOURCES += xa_decoder.c
|
||||
libcoding_la_SOURCES += ogg_vorbis_decoder.c
|
||||
libcoding_la_SOURCES += sdx2_decoder.c
|
||||
libcoding_la_SOURCES += ws_decoder.c
|
||||
libcoding_la_SOURCES += mpeg_decoder.c
|
||||
libcoding_la_SOURCES += acm_decoder.c
|
||||
libcoding_la_SOURCES += nwa_decoder.c
|
||||
libcoding_la_SOURCES += aica_decoder.c
|
||||
libcoding_la_SOURCES += msadpcm_decoder.c
|
||||
libcoding_la_SOURCES += nds_procyon_decoder.c
|
||||
libcoding_la_SOURCES += l5_555_decoder.c
|
||||
libcoding_la_SOURCES += SASSC_decoder.c
|
||||
libcoding_la_SOURCES += g7221_decoder.c
|
||||
libcoding_la_SOURCES += lsf_decoder.c
|
||||
libcoding_la_SOURCES += mtaf_decoder.c
|
||||
|
||||
EXTRA_DIST = coding.h g72x_state.h
|
|
@ -0,0 +1,77 @@
|
|||
#include "coding.h"
|
||||
#include "../util.h"
|
||||
|
||||
/* Activision / EXAKT Entertainment's DPCM for Supercar Street Challenge */
|
||||
|
||||
#if 0
|
||||
|
||||
To build table:
|
||||
|
||||
int32_t bring_round(int32_t v)
|
||||
{
|
||||
return v | (v >> 12);
|
||||
}
|
||||
|
||||
for (i=0x00;i<0x20;i++)
|
||||
SASSC_steps[i] = bring_round(i<<4);
|
||||
for (i=0x20;i<0x40;i++)
|
||||
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);
|
||||
for (i=0x60;i<0x80;i++)
|
||||
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[0xFF] = SASSC_steps[0x7F];
|
||||
#endif
|
||||
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,
|
||||
384, 400, 416, 432, 448, 464, 480, 496,
|
||||
512, 624, 736, 848, 960, 1072, 1184, 1296,
|
||||
1408, 1520, 1632, 1744, 1856, 1968, 2080, 2192,
|
||||
2304, 2416, 2528, 2640, 2752, 2864, 2976, 3088,
|
||||
3200, 3312, 3424, 3536, 3648, 3760, 3872, 3984,
|
||||
4097, 4481, 4865, 5249, 5633, 6017, 6401, 6785,
|
||||
7169, 7553, 7937, 8322, 8706, 9090, 9474, 9858,
|
||||
10242, 10626, 11010, 11394, 11778, 12162, 12547, 12931,
|
||||
13315, 13699, 14083, 14467, 14851, 15235, 15619, 16003,
|
||||
16388, 17924, 19460, 20997, 22533, 24069, 25606, 27142,
|
||||
28679, 30215, 31751, 33288, 34824, 36360, 37897, 39433,
|
||||
40970, 42506, 44042, 45579, 47115, 48651, 50188, 51724,
|
||||
53261, 54797, 56333, 57870, 59406, 60942, 62479, 64015,
|
||||
|
||||
0, -16, -32, -48, -64, -80, -96, -112,
|
||||
-128, -144, -160, -176, -192, -208, -224, -240,
|
||||
-256, -272, -288, -304, -320, -336, -352, -368,
|
||||
-384, -400, -416, -432, -448, -464, -480, -496,
|
||||
-512, -624, -736, -848, -960, -1072, -1184, -1296,
|
||||
-1408, -1520, -1632, -1744, -1856, -1968, -2080, -2192,
|
||||
-2304, -2416, -2528, -2640, -2752, -2864, -2976, -3088,
|
||||
-3200, -3312, -3424, -3536, -3648, -3760, -3872, -3984,
|
||||
-4097, -4481, -4865, -5249, -5633, -6017, -6401, -6785,
|
||||
-7169, -7553, -7937, -8322, -8706, -9090, -9474, -9858,
|
||||
-10242, -10626, -11010, -11394, -11778, -12162, -12547, -12931,
|
||||
-13315, -13699, -14083, -14467, -14851, -15235, -15619, -16003,
|
||||
-16388, -17924, -19460, -20997, -22533, -24069, -25606, -27142,
|
||||
-28679, -30215, -31751, -33288, -34824, -36360, -37897, -39433,
|
||||
-40970, -42506, -44042, -45579, -47115, -48651, -50188, -51724,
|
||||
-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) {
|
||||
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)];
|
||||
outbuf[sample_count] = clamp16(hist);
|
||||
}
|
||||
|
||||
stream->adpcm_history1_32 = hist;
|
||||
}
|
|
@ -0,0 +1,839 @@
|
|||
/*
|
||||
* ACM decoder.
|
||||
*
|
||||
* Copyright (c) 2004-2008, Marko Kreen
|
||||
* Copyright (c) 2008, Adam Gashlin
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "coding.h"
|
||||
#include "../vgmstream.h"
|
||||
#include "../streamtypes.h"
|
||||
#include "acm_decoder.h"
|
||||
|
||||
#define ACM_EXPECTED_EOF -99
|
||||
|
||||
typedef int (*filler_t)(ACMStream *acm, unsigned ind, unsigned col);
|
||||
|
||||
/**************************************
|
||||
* Stream processing
|
||||
**************************************/
|
||||
|
||||
/* NB: bits <= 31! Thus less checks in code. */
|
||||
|
||||
static int get_bits_reload(ACMStream *acm, unsigned bits)
|
||||
{
|
||||
int got;
|
||||
unsigned data, b_data, b_avail;
|
||||
|
||||
data = acm->bit_data;
|
||||
got = acm->bit_avail;
|
||||
bits -= got;
|
||||
|
||||
switch (acm->data_len - acm->buf_start_ofs) {
|
||||
case 0:
|
||||
b_data = 0;
|
||||
b_avail = 8;
|
||||
break;
|
||||
case 1:
|
||||
b_data = (uint8_t)read_8bit(acm->buf_start_ofs,acm->streamfile);
|
||||
b_avail = 8;
|
||||
acm->buf_start_ofs += 1;
|
||||
break;
|
||||
case 2:
|
||||
b_data = (uint16_t)read_16bitLE(acm->buf_start_ofs,acm->streamfile);
|
||||
b_avail = 16;
|
||||
acm->buf_start_ofs += 2;
|
||||
break;
|
||||
case 3:
|
||||
b_data = (uint8_t)read_8bit(acm->buf_start_ofs,acm->streamfile);
|
||||
b_data |= (int32_t)(uint16_t)read_16bitLE(acm->buf_start_ofs+1,acm->streamfile)<<8;
|
||||
b_avail = 24;
|
||||
acm->buf_start_ofs += 3;
|
||||
break;
|
||||
case 4:
|
||||
default:
|
||||
if (acm->data_len - acm->buf_start_ofs <= 0) {
|
||||
b_data = 0;
|
||||
b_avail = 8;
|
||||
break;
|
||||
}
|
||||
|
||||
b_data = read_32bitLE(acm->buf_start_ofs,acm->streamfile);
|
||||
b_avail = 32;
|
||||
acm->buf_start_ofs += 4;
|
||||
break;
|
||||
}
|
||||
|
||||
data |= (b_data & ((1 << bits) - 1)) << got;
|
||||
acm->bit_data = b_data >> bits;
|
||||
acm->bit_avail = b_avail - bits;
|
||||
return data;
|
||||
}
|
||||
|
||||
#define GET_BITS_NOERR(tmpval, acm, bits) do { \
|
||||
if (acm->bit_avail >= bits) { \
|
||||
tmpval = acm->bit_data & ((1 << bits) - 1); \
|
||||
acm->bit_data >>= bits; \
|
||||
acm->bit_avail -= bits; \
|
||||
} else \
|
||||
tmpval = get_bits_reload(acm, bits); \
|
||||
} while (0)
|
||||
|
||||
#define GET_BITS(res, acm, bits) do { \
|
||||
int tmpval; \
|
||||
GET_BITS_NOERR(tmpval, acm, bits); \
|
||||
if (tmpval < 0) \
|
||||
return tmpval; \
|
||||
res = tmpval; \
|
||||
} while (0)
|
||||
|
||||
#define GET_BITS_EXPECT_EOF(res, acm, bits) do { \
|
||||
int tmpval; \
|
||||
GET_BITS_NOERR(tmpval, acm, bits); \
|
||||
if (tmpval < 0) { \
|
||||
if (tmpval == ACM_ERR_UNEXPECTED_EOF) \
|
||||
return ACM_EXPECTED_EOF; \
|
||||
return tmpval; \
|
||||
} \
|
||||
res = tmpval; \
|
||||
} while (0)
|
||||
|
||||
/*************************************************
|
||||
* Table filling
|
||||
*************************************************/
|
||||
static const int map_1bit[] = { -1, +1 };
|
||||
static const int map_2bit_near[] = { -2, -1, +1, +2 };
|
||||
static const int map_2bit_far[] = { -3, -2, +2, +3 };
|
||||
static const int map_3bit[] = { -4, -3, -2, -1, +1, +2, +3, +4 };
|
||||
static int mul_3x3[3*3*3];
|
||||
static int mul_3x5[5*5*5];
|
||||
static int mul_2x11[11*11];
|
||||
static int tables_generated;
|
||||
|
||||
static void generate_tables(void)
|
||||
{
|
||||
int x1, x2, x3;
|
||||
if (tables_generated)
|
||||
return;
|
||||
for (x3 = 0; x3 < 3; x3++)
|
||||
for (x2 = 0; x2 < 3; x2++)
|
||||
for (x1 = 0; x1 < 3; x1++)
|
||||
mul_3x3[x1 + x2*3 + x3*3*3] =
|
||||
x1 + (x2 << 4) + (x3 << 8);
|
||||
for (x3 = 0; x3 < 5; x3++)
|
||||
for (x2 = 0; x2 < 5; x2++)
|
||||
for (x1 = 0; x1 < 5; x1++)
|
||||
mul_3x5[x1 + x2*5 + x3*5*5] =
|
||||
x1 + (x2 << 4) + (x3 << 8);
|
||||
for (x2 = 0; x2 < 11; x2++)
|
||||
for (x1 = 0; x1 < 11; x1++)
|
||||
mul_2x11[x1 + x2*11] = x1 + (x2 << 4);
|
||||
|
||||
tables_generated = 1;
|
||||
}
|
||||
|
||||
/* IOW: (r * acm->subblock_len) + c */
|
||||
#define set_pos(acm, r, c, idx) do { \
|
||||
unsigned _pos = ((r) << acm->info.acm_level) + (c); \
|
||||
acm->block[_pos] = acm->midbuf[idx]; \
|
||||
} while (0)
|
||||
|
||||
/************ Fillers **********/
|
||||
|
||||
static int f_zero(ACMStream *acm, unsigned ind, unsigned col)
|
||||
{
|
||||
unsigned i;
|
||||
for (i = 0; i < acm->info.acm_rows; i++)
|
||||
set_pos(acm, i, col, 0);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int f_bad(ACMStream *acm, unsigned ind, unsigned col)
|
||||
{
|
||||
/* corrupt block? */
|
||||
return ACM_ERR_CORRUPT;
|
||||
}
|
||||
|
||||
static int f_linear(ACMStream *acm, unsigned ind, unsigned col)
|
||||
{
|
||||
unsigned int i;
|
||||
int b, middle = 1 << (ind - 1);
|
||||
|
||||
for (i = 0; i < acm->info.acm_rows; i++) {
|
||||
GET_BITS(b, acm, ind);
|
||||
set_pos(acm, i, col, b - middle);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int f_k13(ACMStream *acm, unsigned ind, unsigned col)
|
||||
{
|
||||
unsigned i, b;
|
||||
for (i = 0; i < acm->info.acm_rows; i++) {
|
||||
GET_BITS(b, acm, 1);
|
||||
if (b == 0) {
|
||||
/* 0 */
|
||||
set_pos(acm, i++, col, 0);
|
||||
if (i >= acm->info.acm_rows)
|
||||
break;
|
||||
set_pos(acm, i, col, 0);
|
||||
continue;
|
||||
}
|
||||
GET_BITS(b, acm, 1);
|
||||
if (b == 0) {
|
||||
/* 1, 0 */
|
||||
set_pos(acm, i, col, 0);
|
||||
continue;
|
||||
}
|
||||
/* 1, 1, ? */
|
||||
GET_BITS(b, acm, 1);
|
||||
set_pos(acm, i, col, map_1bit[b]);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int f_k12(ACMStream *acm, unsigned ind, unsigned col)
|
||||
{
|
||||
unsigned i, b;
|
||||
for (i = 0; i < acm->info.acm_rows; i++) {
|
||||
GET_BITS(b, acm, 1);
|
||||
if (b == 0) {
|
||||
/* 0 */
|
||||
set_pos(acm, i, col, 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* 1, ? */
|
||||
GET_BITS(b, acm, 1);
|
||||
set_pos(acm, i, col, map_1bit[b]);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int f_k24(ACMStream *acm, unsigned ind, unsigned col)
|
||||
{
|
||||
unsigned i, b;
|
||||
for (i = 0; i < acm->info.acm_rows; i++) {
|
||||
GET_BITS(b, acm, 1);
|
||||
if (b == 0) {
|
||||
/* 0 */
|
||||
set_pos(acm, i++, col, 0);
|
||||
if (i >= acm->info.acm_rows) break;
|
||||
set_pos(acm, i, col, 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
GET_BITS(b, acm, 1);
|
||||
if (b == 0) {
|
||||
/* 1, 0 */
|
||||
set_pos(acm, i, col, 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* 1, 1, ?, ? */
|
||||
GET_BITS(b, acm, 2);
|
||||
set_pos(acm, i, col, map_2bit_near[b]);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int f_k23(ACMStream *acm, unsigned ind, unsigned col)
|
||||
{
|
||||
unsigned i, b;
|
||||
for (i = 0; i < acm->info.acm_rows; i++) {
|
||||
GET_BITS(b, acm, 1);
|
||||
if (b == 0) {
|
||||
/* 0 */
|
||||
set_pos(acm, i, col, 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* 1, ?, ? */
|
||||
GET_BITS(b, acm, 2);
|
||||
set_pos(acm, i, col, map_2bit_near[b]);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int f_k35(ACMStream *acm, unsigned ind, unsigned col)
|
||||
{
|
||||
unsigned i, b;
|
||||
for (i = 0; i < acm->info.acm_rows; i++) {
|
||||
GET_BITS(b, acm, 1);
|
||||
if (b == 0) {
|
||||
/* 0 */
|
||||
set_pos(acm, i++, col, 0);
|
||||
if (i >= acm->info.acm_rows)
|
||||
break;
|
||||
set_pos(acm, i, col, 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
GET_BITS(b, acm, 1);
|
||||
if (b == 0) {
|
||||
/* 1, 0 */
|
||||
set_pos(acm, i, col, 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
GET_BITS(b, acm, 1);
|
||||
if (b == 0) {
|
||||
/* 1, 1, 0, ? */
|
||||
GET_BITS(b, acm, 1);
|
||||
set_pos(acm, i, col, map_1bit[b]);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* 1, 1, 1, ?, ? */
|
||||
GET_BITS(b, acm, 2);
|
||||
set_pos(acm, i, col, map_2bit_far[b]);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int f_k34(ACMStream *acm, unsigned ind, unsigned col)
|
||||
{
|
||||
unsigned i, b;
|
||||
for (i = 0; i < acm->info.acm_rows; i++) {
|
||||
GET_BITS(b, acm, 1);
|
||||
if (b == 0) {
|
||||
/* 0 */
|
||||
set_pos(acm, i, col, 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
GET_BITS(b, acm, 1);
|
||||
if (b == 0) {
|
||||
/* 1, 0, ? */
|
||||
GET_BITS(b, acm, 1);
|
||||
set_pos(acm, i, col, map_1bit[b]);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* 1, 1, ?, ? */
|
||||
GET_BITS(b, acm, 2);
|
||||
set_pos(acm, i, col, map_2bit_far[b]);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int f_k45(ACMStream *acm, unsigned ind, unsigned col)
|
||||
{
|
||||
unsigned i, b;
|
||||
for (i = 0; i < acm->info.acm_rows; i++) {
|
||||
GET_BITS(b, acm, 1);
|
||||
if (b == 0) {
|
||||
/* 0 */
|
||||
set_pos(acm, i, col, 0); i++;
|
||||
if (i >= acm->info.acm_rows)
|
||||
break;
|
||||
set_pos(acm, i, col, 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
GET_BITS(b, acm, 1);
|
||||
if (b == 0) {
|
||||
/* 1, 0 */
|
||||
set_pos(acm, i, col, 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* 1, 1, ?, ?, ? */
|
||||
GET_BITS(b, acm, 3);
|
||||
set_pos(acm, i, col, map_3bit[b]);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int f_k44(ACMStream *acm, unsigned ind, unsigned col)
|
||||
{
|
||||
unsigned i, b;
|
||||
for (i = 0; i < acm->info.acm_rows; i++) {
|
||||
GET_BITS(b, acm, 1);
|
||||
if (b == 0) {
|
||||
/* 0 */
|
||||
set_pos(acm, i, col, 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* 1, ?, ?, ? */
|
||||
GET_BITS(b, acm, 3);
|
||||
set_pos(acm, i, col, map_3bit[b]);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int f_t15(ACMStream *acm, unsigned ind, unsigned col)
|
||||
{
|
||||
unsigned i, b;
|
||||
int n1, n2, n3;
|
||||
for (i = 0; i < acm->info.acm_rows; i++) {
|
||||
/* b = (x1) + (x2 * 3) + (x3 * 9) */
|
||||
GET_BITS(b, acm, 5);
|
||||
|
||||
n1 = (mul_3x3[b] & 0x0F) - 1;
|
||||
n2 = ((mul_3x3[b] >> 4) & 0x0F) - 1;
|
||||
n3 = ((mul_3x3[b] >> 8) & 0x0F) - 1;
|
||||
|
||||
set_pos(acm, i++, col, n1);
|
||||
if (i >= acm->info.acm_rows)
|
||||
break;
|
||||
set_pos(acm, i++, col, n2);
|
||||
if (i >= acm->info.acm_rows)
|
||||
break;
|
||||
set_pos(acm, i, col, n3);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int f_t27(ACMStream *acm, unsigned ind, unsigned col)
|
||||
{
|
||||
unsigned i, b;
|
||||
int n1, n2, n3;
|
||||
for (i = 0; i < acm->info.acm_rows; i++) {
|
||||
/* b = (x1) + (x2 * 5) + (x3 * 25) */
|
||||
GET_BITS(b, acm, 7);
|
||||
|
||||
n1 = (mul_3x5[b] & 0x0F) - 2;
|
||||
n2 = ((mul_3x5[b] >> 4) & 0x0F) - 2;
|
||||
n3 = ((mul_3x5[b] >> 8) & 0x0F) - 2;
|
||||
|
||||
set_pos(acm, i++, col, n1);
|
||||
if (i >= acm->info.acm_rows)
|
||||
break;
|
||||
set_pos(acm, i++, col, n2);
|
||||
if (i >= acm->info.acm_rows)
|
||||
break;
|
||||
set_pos(acm, i, col, n3);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int f_t37(ACMStream *acm, unsigned ind, unsigned col)
|
||||
{
|
||||
unsigned i, b;
|
||||
int n1, n2;
|
||||
for (i = 0; i < acm->info.acm_rows; i++) {
|
||||
/* b = (x1) + (x2 * 11) */
|
||||
GET_BITS(b, acm, 7);
|
||||
|
||||
n1 = (mul_2x11[b] & 0x0F) - 5;
|
||||
n2 = ((mul_2x11[b] >> 4) & 0x0F) - 5;
|
||||
|
||||
set_pos(acm, i++, col, n1);
|
||||
if (i >= acm->info.acm_rows)
|
||||
break;
|
||||
set_pos(acm, i, col, n2);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/****************/
|
||||
|
||||
static const filler_t filler_list[] = {
|
||||
f_zero, f_bad, f_bad, f_linear, /* 0..3 */
|
||||
f_linear, f_linear, f_linear, f_linear, /* 4..7 */
|
||||
f_linear, f_linear, f_linear, f_linear, /* 8..11 */
|
||||
f_linear, f_linear, f_linear, f_linear, /* 12..15 */
|
||||
f_linear, f_k13, f_k12, f_t15, /* 16..19 */
|
||||
f_k24, f_k23, f_t27, f_k35, /* 20..23 */
|
||||
f_k34, f_bad, f_k45, f_k44, /* 24..27 */
|
||||
f_bad, f_t37, f_bad, f_bad /* 28..31 */
|
||||
};
|
||||
|
||||
static int fill_block(ACMStream *acm)
|
||||
{
|
||||
unsigned i, ind;
|
||||
int err;
|
||||
for (i = 0; i < acm->info.acm_cols; i++) {
|
||||
GET_BITS_EXPECT_EOF(ind, acm, 5);
|
||||
err = filler_list[ind](acm, ind, i);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**********************************************
|
||||
* Decompress code
|
||||
**********************************************/
|
||||
|
||||
static void juggle(int *wrap_p, int *block_p, unsigned sub_len, unsigned sub_count)
|
||||
{
|
||||
unsigned int i, j;
|
||||
int *p, r0, r1, r2, r3;
|
||||
for (i = 0; i < sub_len; i++) {
|
||||
p = block_p;
|
||||
r0 = wrap_p[0];
|
||||
r1 = wrap_p[1];
|
||||
for (j = 0; j < sub_count/2; j++) {
|
||||
r2 = *p; *p = r1*2 + (r0 + r2); p += sub_len;
|
||||
r3 = *p; *p = r2*2 - (r1 + r3); p += sub_len;
|
||||
r0 = r2; r1 = r3;
|
||||
}
|
||||
*wrap_p++ = r0;
|
||||
*wrap_p++ = r1;
|
||||
block_p++;
|
||||
}
|
||||
}
|
||||
|
||||
static void juggle_block(ACMStream *acm)
|
||||
{
|
||||
unsigned sub_count, sub_len, todo_count, step_subcount, i;
|
||||
int *wrap_p, *block_p, *p;
|
||||
|
||||
/* juggle only if subblock_len > 1 */
|
||||
if (acm->info.acm_level == 0)
|
||||
return;
|
||||
|
||||
/* 2048 / subblock_len */
|
||||
if (acm->info.acm_level > 9)
|
||||
step_subcount = 1;
|
||||
else
|
||||
step_subcount = (2048 >> acm->info.acm_level) - 2;
|
||||
|
||||
/* Apply juggle() (rows)x(cols)
|
||||
* from (step_subcount * 2) x (subblock_len/2)
|
||||
* to (step_subcount * subblock_len) x (1)
|
||||
*/
|
||||
todo_count = acm->info.acm_rows;
|
||||
block_p = acm->block;
|
||||
while (1) {
|
||||
wrap_p = acm->wrapbuf;
|
||||
sub_count = step_subcount;
|
||||
if (sub_count > todo_count)
|
||||
sub_count = todo_count;
|
||||
|
||||
sub_len = acm->info.acm_cols / 2;
|
||||
sub_count *= 2;
|
||||
|
||||
juggle(wrap_p, block_p, sub_len, sub_count);
|
||||
wrap_p += sub_len*2;
|
||||
|
||||
for (i = 0, p = block_p; i < sub_count; i++) {
|
||||
p[0]++;
|
||||
p += sub_len;
|
||||
}
|
||||
|
||||
while (sub_len > 1) {
|
||||
sub_len /= 2;
|
||||
sub_count *= 2;
|
||||
juggle(wrap_p, block_p, sub_len, sub_count);
|
||||
wrap_p += sub_len*2;
|
||||
}
|
||||
if (todo_count <= step_subcount)
|
||||
break;
|
||||
todo_count -= step_subcount;
|
||||
block_p += step_subcount << acm->info.acm_level;
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************/
|
||||
static int decode_block(ACMStream *acm)
|
||||
{
|
||||
int pwr, count, val, i, x, err;
|
||||
|
||||
acm->block_ready = 0;
|
||||
acm->block_pos = 0;
|
||||
|
||||
/* read header */
|
||||
GET_BITS_EXPECT_EOF(pwr, acm, 4);
|
||||
GET_BITS_EXPECT_EOF(val, acm, 16);
|
||||
|
||||
/* generate tables */
|
||||
count = 1 << pwr;
|
||||
for (i = 0, x = 0; i < count; i++) {
|
||||
acm->midbuf[i] = x;
|
||||
x += val;
|
||||
}
|
||||
for (i = 1, x = -val; i <= count; i++) {
|
||||
acm->midbuf[-i] = x;
|
||||
x -= val;
|
||||
}
|
||||
|
||||
/* to_check? */
|
||||
if ((err = fill_block(acm)) <= 0)
|
||||
return err;
|
||||
|
||||
juggle_block(acm);
|
||||
|
||||
acm->block_ready = 1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/******************************
|
||||
* Output formats
|
||||
******************************/
|
||||
|
||||
static unsigned char *out_s16le(int *src, unsigned char *dst, unsigned n, unsigned shift)
|
||||
{
|
||||
while (n--) {
|
||||
int val = *src++ >> shift;
|
||||
*dst++ = val & 0xFF;
|
||||
*dst++ = (val >> 8) & 0xFF;
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
static unsigned char *out_s16be(int *src, unsigned char *dst, unsigned n, unsigned shift)
|
||||
{
|
||||
while (n--) {
|
||||
int val = *src++ >> shift;
|
||||
*dst++ = (val >> 8) & 0xFF;
|
||||
*dst++ = val & 0xFF;
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
static unsigned char *out_u16le(int *src, unsigned char *dst, unsigned n, unsigned shift)
|
||||
{
|
||||
while (n--) {
|
||||
int val = (*src++ >> shift) + 0x8000;
|
||||
*dst++ = val & 0xFF;
|
||||
*dst++ = (val >> 8) & 0xFF;
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
static unsigned char *out_u16be(int *src, unsigned char *dst, unsigned n, unsigned shift)
|
||||
{
|
||||
while (n--) {
|
||||
int val = (*src++ >> shift) + 0x8000;
|
||||
*dst++ = (val >> 8) & 0xFF;
|
||||
*dst++ = val & 0xFF;
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
static int output_values(int *src, unsigned char *dst, int n,
|
||||
int acm_level, int bigendianp, int wordlen, int sgned)
|
||||
{
|
||||
unsigned char *res = NULL;
|
||||
if (wordlen == 2) {
|
||||
if (bigendianp == 0) {
|
||||
if (sgned)
|
||||
res = out_s16le(src, dst, n, acm_level);
|
||||
else
|
||||
res = out_u16le(src, dst, n, acm_level);
|
||||
} else {
|
||||
if (sgned)
|
||||
res = out_s16be(src, dst, n, acm_level);
|
||||
else
|
||||
res = out_u16be(src, dst, n, acm_level);
|
||||
}
|
||||
}
|
||||
if (res != NULL)
|
||||
return res - dst;
|
||||
return ACM_ERR_BADFMT;
|
||||
}
|
||||
|
||||
/*
|
||||
* Header parsing.
|
||||
*/
|
||||
|
||||
static int read_header(ACMStream *acm)
|
||||
{
|
||||
int tmp;
|
||||
/* read header */
|
||||
GET_BITS(acm->info.acm_id, acm, 24);
|
||||
if (acm->info.acm_id != ACM_ID)
|
||||
return ACM_ERR_NOT_ACM;
|
||||
GET_BITS(acm->info.acm_version, acm, 8);
|
||||
if (acm->info.acm_version != 1)
|
||||
return ACM_ERR_NOT_ACM;
|
||||
GET_BITS(acm->total_values, acm, 16);
|
||||
GET_BITS(tmp, acm, 16);
|
||||
acm->total_values += tmp << 16;
|
||||
if (acm->total_values == 0)
|
||||
return ACM_ERR_NOT_ACM;
|
||||
GET_BITS(acm->info.channels, acm, 16);
|
||||
if (acm->info.channels < 1)
|
||||
return ACM_ERR_NOT_ACM;
|
||||
/* we play music, music is stereo, though not all headers agree */
|
||||
acm->info.channels = 2;
|
||||
GET_BITS(acm->info.rate, acm, 16);
|
||||
|
||||
GET_BITS(acm->info.acm_level, acm, 4);
|
||||
GET_BITS(acm->info.acm_rows, acm, 12);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/***********************************************
|
||||
* Public functions
|
||||
***********************************************/
|
||||
|
||||
int acm_open_decoder(ACMStream **res, STREAMFILE *facilitator_file,
|
||||
const char *const filename)
|
||||
{
|
||||
int err = ACM_ERR_OTHER;
|
||||
ACMStream *acm;
|
||||
|
||||
acm = malloc(sizeof(*acm));
|
||||
if (!acm)
|
||||
return err;
|
||||
memset(acm, 0, sizeof(*acm));
|
||||
|
||||
acm->streamfile = facilitator_file->open(facilitator_file,filename,
|
||||
STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
|
||||
if (!acm->streamfile)
|
||||
{
|
||||
err = ACM_ERR_OPEN;
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
acm->data_len = get_streamfile_size(acm->streamfile);
|
||||
|
||||
/* read header data */
|
||||
err = ACM_ERR_NOT_ACM;
|
||||
if (read_header(acm) < 0)
|
||||
goto err_out;
|
||||
|
||||
/* calculate blocks */
|
||||
acm->info.acm_cols = 1 << acm->info.acm_level;
|
||||
acm->wrapbuf_len = 2 * acm->info.acm_cols - 2;
|
||||
acm->block_len = acm->info.acm_rows * acm->info.acm_cols;
|
||||
|
||||
/* allocate */
|
||||
acm->block = malloc(acm->block_len * sizeof(int));
|
||||
acm->wrapbuf = malloc(acm->wrapbuf_len * sizeof(int));
|
||||
acm->ampbuf = malloc(0x10000 * sizeof(int));
|
||||
acm->midbuf = acm->ampbuf + 0x8000;
|
||||
|
||||
memset(acm->wrapbuf, 0, acm->wrapbuf_len * sizeof(int));
|
||||
|
||||
generate_tables();
|
||||
|
||||
*res = acm;
|
||||
return ACM_OK;
|
||||
|
||||
err_out:
|
||||
|
||||
acm_close(acm);
|
||||
return err;
|
||||
}
|
||||
|
||||
int acm_read(ACMStream *acm, void *dst, unsigned numbytes,
|
||||
int bigendianp, int wordlen, int sgned)
|
||||
{
|
||||
int avail, gotbytes = 0, err;
|
||||
int *src, numwords;
|
||||
|
||||
if (wordlen == 2)
|
||||
numwords = numbytes / 2;
|
||||
else
|
||||
return ACM_ERR_BADFMT;
|
||||
|
||||
if (acm->stream_pos >= acm->total_values)
|
||||
return 0;
|
||||
|
||||
if (!acm->block_ready) {
|
||||
err = decode_block(acm);
|
||||
if (err == ACM_EXPECTED_EOF)
|
||||
return 0;
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
/* check how many words can be read */
|
||||
avail = acm->block_len - acm->block_pos;
|
||||
if (avail < numwords)
|
||||
numwords = avail;
|
||||
|
||||
if (acm->stream_pos + numwords > acm->total_values)
|
||||
numwords = acm->total_values - acm->stream_pos;
|
||||
|
||||
if (acm->info.channels > 1)
|
||||
numwords -= numwords % acm->info.channels;
|
||||
|
||||
/* convert, but if dst == NULL, simulate */
|
||||
if (dst != NULL) {
|
||||
src = acm->block + acm->block_pos;
|
||||
gotbytes = output_values(src, dst, numwords,
|
||||
acm->info.acm_level,
|
||||
bigendianp, wordlen, sgned);
|
||||
} else
|
||||
gotbytes = numwords * wordlen;
|
||||
|
||||
if (gotbytes >= 0) {
|
||||
acm->stream_pos += numwords;
|
||||
acm->block_pos += numwords;
|
||||
if (acm->block_pos == acm->block_len)
|
||||
acm->block_ready = 0;
|
||||
}
|
||||
|
||||
return gotbytes;
|
||||
}
|
||||
|
||||
void acm_close(ACMStream *acm)
|
||||
{
|
||||
if (acm == NULL)
|
||||
return;
|
||||
if (acm->streamfile) {
|
||||
close_streamfile(acm->streamfile);
|
||||
acm->streamfile = NULL;
|
||||
}
|
||||
if (acm->block)
|
||||
free(acm->block);
|
||||
if (acm->wrapbuf)
|
||||
free(acm->wrapbuf);
|
||||
if (acm->ampbuf)
|
||||
free(acm->ampbuf);
|
||||
free(acm);
|
||||
}
|
||||
|
||||
void acm_reset(ACMStream *acm)
|
||||
{
|
||||
acm->bit_avail = 0;
|
||||
acm->bit_data = 0;
|
||||
|
||||
acm->stream_pos = 0;
|
||||
acm->block_pos = 0;
|
||||
acm->block_ready = 0;
|
||||
acm->buf_start_ofs = ACM_HEADER_LEN;
|
||||
|
||||
memset(acm->wrapbuf, 0, acm->wrapbuf_len * sizeof(int));
|
||||
}
|
||||
|
||||
/* interface to vgmstream */
|
||||
void decode_acm(ACMStream * acm, sample * outbuf,
|
||||
int32_t samples_to_do, int channelspacing) {
|
||||
int32_t samples_read = 0;
|
||||
while (samples_read < samples_to_do) {
|
||||
int32_t bytes_read_just_now;
|
||||
bytes_read_just_now =
|
||||
acm_read(acm,(char*)(
|
||||
outbuf+samples_read*channelspacing),
|
||||
(samples_to_do-samples_read)*sizeof(sample)*
|
||||
channelspacing,0,2,1);
|
||||
|
||||
if (bytes_read_just_now > 0) {
|
||||
samples_read +=
|
||||
bytes_read_just_now/sizeof(sample)/channelspacing;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
* libacm - Interplay ACM audio decoder.
|
||||
*
|
||||
* Copyright (c) 2004-2008, Marko Kreen
|
||||
* Copyright (c) 2008, Adam Gashlin
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __LIBACM_H
|
||||
#define __LIBACM_H
|
||||
|
||||
#ifdef BUILD_VGMSTREAM
|
||||
#include "../streamfile.h"
|
||||
#else
|
||||
#include "streamfile.h"
|
||||
#endif
|
||||
|
||||
#define LIBACM_VERSION "1.0-svn"
|
||||
|
||||
#define ACM_ID 0x032897
|
||||
#define ACM_WORD 2
|
||||
|
||||
#define ACM_HEADER_LEN 14
|
||||
#define ACM_OK 0
|
||||
#define ACM_ERR_OTHER -1
|
||||
#define ACM_ERR_OPEN -2
|
||||
#define ACM_ERR_NOT_ACM -3
|
||||
#define ACM_ERR_READ_ERR -4
|
||||
#define ACM_ERR_BADFMT -5
|
||||
#define ACM_ERR_CORRUPT -6
|
||||
#define ACM_ERR_UNEXPECTED_EOF -7
|
||||
#define ACM_ERR_NOT_SEEKABLE -8
|
||||
|
||||
typedef struct ACMInfo {
|
||||
unsigned channels;
|
||||
unsigned rate;
|
||||
unsigned acm_id;
|
||||
unsigned acm_version;
|
||||
unsigned acm_level;
|
||||
unsigned acm_cols; /* 1 << acm_level */
|
||||
unsigned acm_rows;
|
||||
} ACMInfo;
|
||||
|
||||
struct ACMStream {
|
||||
ACMInfo info;
|
||||
unsigned total_values;
|
||||
|
||||
/* acm data stream */
|
||||
STREAMFILE *streamfile;
|
||||
unsigned data_len;
|
||||
|
||||
/* acm stream buffer */
|
||||
unsigned bit_avail;
|
||||
unsigned bit_data;
|
||||
unsigned buf_start_ofs;
|
||||
|
||||
/* block lengths (in samples) */
|
||||
unsigned block_len;
|
||||
unsigned wrapbuf_len;
|
||||
/* buffers */
|
||||
int *block;
|
||||
int *wrapbuf;
|
||||
int *ampbuf;
|
||||
int *midbuf; /* pointer into ampbuf */
|
||||
/* result */
|
||||
unsigned block_ready:1;
|
||||
unsigned file_eof:1;
|
||||
unsigned stream_pos; /* in words. absolute */
|
||||
unsigned block_pos; /* in words, relative */
|
||||
};
|
||||
typedef struct ACMStream ACMStream;
|
||||
|
||||
/* decode.c */
|
||||
int acm_open_decoder(ACMStream **res, STREAMFILE *facilitator_file, const char *const filename);
|
||||
int acm_read(ACMStream *acm, void *buf, unsigned nbytes,
|
||||
int bigendianp, int wordlen, int sgned);
|
||||
void acm_close(ACMStream *acm);
|
||||
void acm_reset(ACMStream *acm);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,81 @@
|
|||
#include "coding.h"
|
||||
#include "../util.h"
|
||||
|
||||
void decode_adx(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
int i;
|
||||
int32_t sample_count;
|
||||
|
||||
int framesin = first_sample/32;
|
||||
|
||||
int32_t scale = read_16bitBE(stream->offset+framesin*18,stream->streamfile) + 1;
|
||||
int32_t hist1 = stream->adpcm_history1_32;
|
||||
int32_t hist2 = stream->adpcm_history2_32;
|
||||
int coef1 = stream->adpcm_coef[0];
|
||||
int coef2 = stream->adpcm_coef[1];
|
||||
|
||||
first_sample = first_sample%32;
|
||||
|
||||
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
|
||||
int sample_byte = read_8bit(stream->offset+framesin*18+2+i/2,stream->streamfile);
|
||||
|
||||
outbuf[sample_count] = clamp16(
|
||||
(i&1?
|
||||
get_low_nibble_signed(sample_byte):
|
||||
get_high_nibble_signed(sample_byte)
|
||||
) * scale +
|
||||
((coef1 * hist1 + coef2 * hist2) >> 12)
|
||||
);
|
||||
|
||||
hist2 = hist1;
|
||||
hist1 = outbuf[sample_count];
|
||||
}
|
||||
|
||||
stream->adpcm_history1_32 = hist1;
|
||||
stream->adpcm_history2_32 = hist2;
|
||||
}
|
||||
|
||||
void adx_next_key(VGMSTREAMCHANNEL * stream)
|
||||
{
|
||||
stream->adx_xor = ( stream->adx_xor * stream->adx_mult + stream->adx_add ) & 0x7fff;
|
||||
}
|
||||
|
||||
void decode_adx_enc(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
int i;
|
||||
int32_t sample_count;
|
||||
|
||||
int framesin = first_sample/32;
|
||||
|
||||
int32_t scale = ((read_16bitBE(stream->offset+framesin*18,stream->streamfile) ^ stream->adx_xor)&0x1fff) + 1;
|
||||
int32_t hist1 = stream->adpcm_history1_32;
|
||||
int32_t hist2 = stream->adpcm_history2_32;
|
||||
int coef1 = stream->adpcm_coef[0];
|
||||
int coef2 = stream->adpcm_coef[1];
|
||||
|
||||
first_sample = first_sample%32;
|
||||
|
||||
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
|
||||
int sample_byte = read_8bit(stream->offset+framesin*18+2+i/2,stream->streamfile);
|
||||
|
||||
outbuf[sample_count] = clamp16(
|
||||
(i&1?
|
||||
get_low_nibble_signed(sample_byte):
|
||||
get_high_nibble_signed(sample_byte)
|
||||
) * scale +
|
||||
((coef1 * hist1 + coef2 * hist2) >> 12)
|
||||
);
|
||||
|
||||
hist2 = hist1;
|
||||
hist1 = outbuf[sample_count];
|
||||
}
|
||||
|
||||
stream->adpcm_history1_32 = hist1;
|
||||
stream->adpcm_history2_32 = hist2;
|
||||
|
||||
if (!(i % 32)) {
|
||||
for (i=0;i<stream->adx_channels;i++)
|
||||
{
|
||||
adx_next_key(stream);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
#include "../util.h"
|
||||
#include "coding.h"
|
||||
|
||||
/* fixed point (.8) amount to scale the current step size by */
|
||||
/* part of the same series as used in MS ADPCM "ADPCMTable" */
|
||||
static const unsigned int scale_step[16] =
|
||||
{
|
||||
230, 230, 230, 230, 307, 409, 512, 614,
|
||||
230, 230, 230, 230, 307, 409, 512, 614
|
||||
};
|
||||
|
||||
/* expand an unsigned four bit delta to a wider signed range */
|
||||
static const int scale_delta[16] =
|
||||
{
|
||||
1, 3, 5, 7, 9, 11, 13, 15,
|
||||
-1, -3, -5, -7, -9,-11,-13,-15
|
||||
};
|
||||
|
||||
/* Yamaha AICA ADPCM (as seen in Dreamcast) */
|
||||
|
||||
void decode_aica(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
int i;
|
||||
int32_t sample_count;
|
||||
int32_t hist1 = stream->adpcm_history1_16;
|
||||
unsigned long step_size = stream->adpcm_step_index;
|
||||
|
||||
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
|
||||
int sample_nibble =
|
||||
(
|
||||
(unsigned)read_8bit(stream->offset+i/2,stream->streamfile) >>
|
||||
(i&1?4:0)
|
||||
)&0xf;
|
||||
|
||||
int32_t sample_delta = (int32_t)step_size * scale_delta[sample_nibble];
|
||||
int32_t new_sample;
|
||||
|
||||
new_sample = hist1 + sample_delta/8;
|
||||
|
||||
outbuf[sample_count] = clamp16(new_sample);
|
||||
|
||||
hist1 = outbuf[sample_count];
|
||||
|
||||
step_size = (step_size * scale_step[sample_nibble])/0x100;
|
||||
if (step_size < 0x7f) step_size = 0x7f;
|
||||
if (step_size > 0x6000) step_size = 0x6000;
|
||||
}
|
||||
|
||||
stream->adpcm_history1_16 = hist1;
|
||||
stream->adpcm_step_index = step_size;
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
#include "../vgmstream.h"
|
||||
|
||||
#ifdef VGM_USE_MAIATRAC3PLUS
|
||||
#include "maiatrac3plus.h"
|
||||
#include "coding.h"
|
||||
#include "../util.h"
|
||||
|
||||
void decode_at3plus(VGMSTREAM * vgmstream,
|
||||
sample * outbuf, int channelspacing, int32_t samples_to_do, int channel) {
|
||||
VGMSTREAMCHANNEL *ch = &vgmstream->ch[0];
|
||||
maiatrac3plus_codec_data *data = vgmstream->codec_data;
|
||||
int i;
|
||||
|
||||
int first_sample = vgmstream->samples_into_block % 2048;
|
||||
|
||||
if (0 == channel && (0 == first_sample || data->samples_discard == first_sample))
|
||||
{
|
||||
uint8_t code_buffer[0x8000];
|
||||
int blocks_to_decode = 1;
|
||||
int max_blocks_to_decode = (ch->offset - ch->channel_start_offset) / vgmstream->interleave_block_size + 1;
|
||||
if (data->samples_discard) blocks_to_decode = 8;
|
||||
if (blocks_to_decode > max_blocks_to_decode) blocks_to_decode = max_blocks_to_decode;
|
||||
while (blocks_to_decode--) {
|
||||
ch->streamfile->read(ch->streamfile, code_buffer, ch->offset - blocks_to_decode * vgmstream->interleave_block_size, vgmstream->interleave_block_size);
|
||||
Atrac3plusDecoder_decodeFrame(data->handle, code_buffer, vgmstream->interleave_block_size, &data->channels, (void**)&data->buffer);
|
||||
}
|
||||
data->samples_discard = 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < samples_to_do; i++)
|
||||
{
|
||||
outbuf[i*channelspacing] = data->buffer[(first_sample+i)*data->channels+channel];
|
||||
}
|
||||
|
||||
if (0 == channel && 2048 == first_sample + samples_to_do) {
|
||||
ch->offset += vgmstream->interleave_block_size;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,128 @@
|
|||
#ifndef _CODING_H
|
||||
#define _CODING_H
|
||||
|
||||
#include "../vgmstream.h"
|
||||
|
||||
void decode_adx(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
void decode_adx_enc(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
|
||||
void adx_next_key(VGMSTREAMCHANNEL * stream);
|
||||
|
||||
void decode_g721(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
void g72x_init_state(struct g72x_state *state_ptr);
|
||||
|
||||
void decode_nds_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
void decode_dat4_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
void decode_xbox_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel);
|
||||
void decode_int_xbox_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel);
|
||||
void decode_dvi_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
void decode_eacs_ima(VGMSTREAM * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
|
||||
|
||||
void decode_snds_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
|
||||
|
||||
void decode_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
|
||||
void decode_ms_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel);
|
||||
|
||||
void decode_rad_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel);
|
||||
|
||||
void decode_rad_ima_mono(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
|
||||
void decode_apple_ima4(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
|
||||
void decode_ms_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel);
|
||||
void decode_ngc_afc(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
|
||||
void decode_ngc_dsp(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
void decode_ngc_dsp_mem(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, uint8_t * mem);
|
||||
|
||||
int32_t dsp_nibbles_to_samples(int32_t nibbles);
|
||||
|
||||
void decode_ngc_dtk(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
|
||||
|
||||
void decode_pcm16LE(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
void decode_pcm16LE_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
void decode_pcm16LE_XOR_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
void decode_pcm16BE(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
void decode_pcm8(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
void decode_pcm8_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
void decode_pcm8_sb_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
void decode_pcm8_unsigned_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
void decode_pcm8_unsigned(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
|
||||
void decode_psx(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
|
||||
void decode_invert_psx(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
|
||||
void decode_psx_badflags(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
|
||||
void decode_ffxi_adpcm(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
|
||||
void decode_baf_adpcm(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
|
||||
void decode_xa(VGMSTREAM * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
|
||||
void init_get_high_nibble(VGMSTREAM * vgmstream);
|
||||
|
||||
void decode_eaxa(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel);
|
||||
void decode_ea_adpcm(VGMSTREAM * vgmstream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
|
||||
void decode_maxis_adpcm(VGMSTREAM * vgmstream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
|
||||
|
||||
#ifdef VGM_USE_VORBIS
|
||||
void decode_ogg_vorbis(ogg_vorbis_codec_data * data, sample * outbuf, int32_t samples_to_do, int channels);
|
||||
#endif
|
||||
|
||||
#if defined(VGM_USE_MP4V2) && defined(VGM_USE_FDKAAC)
|
||||
void decode_mp4_aac(mp4_aac_codec_data * data, sample * outbuf, int32_t samples_to_do, int channels);
|
||||
#endif
|
||||
|
||||
void decode_sdx2(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
void decode_sdx2_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
void decode_cbd2(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
void decode_cbd2_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
|
||||
void decode_ws(VGMSTREAM * vgmstream, int channel, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
|
||||
#ifdef VGM_USE_MPEG
|
||||
void decode_fake_mpeg2_l2(VGMSTREAMCHANNEL * stream,
|
||||
mpeg_codec_data * data,
|
||||
sample * outbuf, int32_t samples_to_do);
|
||||
mpeg_codec_data *init_mpeg_codec_data(STREAMFILE *streamfile, off_t start_offset, long given_sample_rate, int given_channels, coding_t *coding_type, int * actual_sample_rate, int * actual_channels);
|
||||
long mpeg_bytes_to_samples(long bytes, const struct mpg123_frameinfo *mi);
|
||||
void decode_mpeg(VGMSTREAMCHANNEL * stream,
|
||||
mpeg_codec_data * data,
|
||||
sample * outbuf, int32_t samples_to_do, int channels);
|
||||
#endif
|
||||
|
||||
#ifdef VGM_USE_G7221
|
||||
void decode_g7221(VGMSTREAM *vgmstream,
|
||||
sample * outbuf, int channelspacing, int32_t samples_to_do, int channel);
|
||||
#endif
|
||||
|
||||
#ifdef VGM_USE_MAIATRAC3PLUS
|
||||
void decode_at3plus(VGMSTREAM *vgmstream,
|
||||
sample * outbuf, int channelspacing, int32_t samples_to_do, int channel);
|
||||
#endif
|
||||
|
||||
void decode_acm(ACMStream * acm, sample * outbuf,
|
||||
int32_t samples_to_do, int channelspacing);
|
||||
|
||||
void decode_nwa(NWAData *nwa, sample *outbuf, int32_t samples_to_do);
|
||||
|
||||
long msadpcm_bytes_to_samples(long bytes, int block_size, int channels);
|
||||
void decode_msadpcm_stereo(VGMSTREAM * vgmstream, sample * outbuf, int32_t first_sample, int32_t samples_to_do);
|
||||
|
||||
void decode_msadpcm_mono(VGMSTREAM * vgmstream, sample * outbuf, int32_t first_sample, int32_t samples_to_do);
|
||||
|
||||
void decode_aica(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
|
||||
void decode_nds_procyon(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
|
||||
void decode_l5_555(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
|
||||
void decode_SASSC(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
|
||||
void decode_lsf(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
|
||||
void decode_mtaf(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, int channels);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,170 @@
|
|||
#include "coding.h"
|
||||
#include "../util.h"
|
||||
|
||||
long EA_XA_TABLE[28] = {0,0,240,0,460,-208,0x0188,-220,
|
||||
0x0000,0x0000,0x00F0,0x0000,
|
||||
0x01CC,0x0000,0x0188,0x0000,
|
||||
0x0000,0x0000,0x0000,0x0000,
|
||||
-208,-1,-220,-1,
|
||||
0x0000,0x0000,0x0000,0x3F70};
|
||||
|
||||
long EA_TABLE[20]= { 0x00000000, 0x000000F0, 0x000001CC, 0x00000188,
|
||||
0x00000000, 0x00000000, 0xFFFFFF30, 0xFFFFFF24,
|
||||
0x00000000, 0x00000001, 0x00000003, 0x00000004,
|
||||
0x00000007, 0x00000008, 0x0000000A, 0x0000000B,
|
||||
0x00000000, 0xFFFFFFFF, 0xFFFFFFFD, 0xFFFFFFFC};
|
||||
|
||||
void decode_eaxa(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel) {
|
||||
uint8_t frame_info;
|
||||
int32_t sample_count;
|
||||
long coef1,coef2;
|
||||
int i,shift;
|
||||
off_t channel_offset=stream->channel_start_offset;
|
||||
|
||||
first_sample = first_sample%28;
|
||||
frame_info = (uint8_t)read_8bit(stream->offset+channel_offset,stream->streamfile);
|
||||
|
||||
if(frame_info==0xEE) {
|
||||
|
||||
channel_offset++;
|
||||
stream->adpcm_history1_32 = read_16bitBE(stream->offset+channel_offset,stream->streamfile);
|
||||
stream->adpcm_history2_32 = read_16bitBE(stream->offset+channel_offset+2,stream->streamfile);
|
||||
|
||||
channel_offset+=4;
|
||||
|
||||
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
|
||||
outbuf[sample_count]=read_16bitBE(stream->offset+channel_offset,stream->streamfile);
|
||||
channel_offset+=2;
|
||||
}
|
||||
|
||||
// Only increment offset on complete frame
|
||||
if(channel_offset-stream->channel_start_offset==(2*28)+5)
|
||||
stream->channel_start_offset+=(2*28)+5;
|
||||
|
||||
} else {
|
||||
|
||||
|
||||
coef1 = EA_XA_TABLE[((frame_info >> 4) & 0x0F) << 1];
|
||||
coef2 = EA_XA_TABLE[(((frame_info >> 4) & 0x0F) << 1) + 1];
|
||||
shift = (frame_info & 0x0F) + 8;
|
||||
|
||||
channel_offset++;
|
||||
|
||||
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
|
||||
uint8_t sample_byte = (uint8_t)read_8bit(stream->offset+channel_offset+i/2,stream->streamfile);
|
||||
int32_t sample = ((((i&1?
|
||||
sample_byte & 0x0F:
|
||||
sample_byte >> 4
|
||||
) << 0x1C) >> shift) +
|
||||
(coef1 * stream->adpcm_history1_32) + (coef2 * stream->adpcm_history2_32)) >> 8;
|
||||
|
||||
outbuf[sample_count] = clamp16(sample);
|
||||
stream->adpcm_history2_32 = stream->adpcm_history1_32;
|
||||
stream->adpcm_history1_32 = sample;
|
||||
}
|
||||
|
||||
channel_offset+=i/2;
|
||||
|
||||
// Only increment offset on complete frame
|
||||
if(channel_offset-stream->channel_start_offset==0x0F)
|
||||
stream->channel_start_offset+=0x0F;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void decode_ea_adpcm(VGMSTREAM * vgmstream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel) {
|
||||
uint8_t frame_info;
|
||||
int32_t sample_count;
|
||||
long coef1,coef2;
|
||||
int i,shift;
|
||||
VGMSTREAMCHANNEL *stream = &(vgmstream->ch[channel]);
|
||||
off_t channel_offset=stream->channel_start_offset;
|
||||
|
||||
vgmstream->get_high_nibble=!vgmstream->get_high_nibble;
|
||||
|
||||
first_sample = first_sample%28;
|
||||
frame_info = read_8bit(stream->offset+channel_offset,stream->streamfile);
|
||||
|
||||
coef1 = EA_TABLE[(vgmstream->get_high_nibble? frame_info & 0x0F: frame_info >> 4)];
|
||||
coef2 = EA_TABLE[(vgmstream->get_high_nibble? frame_info & 0x0F: frame_info >> 4) + 4];
|
||||
|
||||
channel_offset++;
|
||||
|
||||
frame_info = read_8bit(stream->offset+channel_offset,stream->streamfile);
|
||||
shift = (vgmstream->get_high_nibble? frame_info & 0x0F : frame_info >> 4)+8;
|
||||
|
||||
channel_offset++;
|
||||
|
||||
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
|
||||
uint8_t sample_byte;
|
||||
int32_t sample;
|
||||
|
||||
sample_byte = (uint8_t)read_8bit(stream->offset+channel_offset+i,stream->streamfile);
|
||||
|
||||
sample = ((((vgmstream->get_high_nibble?
|
||||
sample_byte & 0x0F:
|
||||
sample_byte >> 4
|
||||
) << 0x1C) >> shift) +
|
||||
(coef1 * stream->adpcm_history1_32) + (coef2 * stream->adpcm_history2_32) + 0x80) >> 8;
|
||||
|
||||
outbuf[sample_count] = clamp16(sample);
|
||||
stream->adpcm_history2_32 = stream->adpcm_history1_32;
|
||||
stream->adpcm_history1_32 = sample;
|
||||
}
|
||||
|
||||
channel_offset+=i;
|
||||
|
||||
// Only increment offset on complete frame
|
||||
if(channel_offset-stream->channel_start_offset==0x1E)
|
||||
stream->channel_start_offset+=0x1E;
|
||||
}
|
||||
|
||||
|
||||
void decode_maxis_adpcm(VGMSTREAM * vgmstream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel) {
|
||||
uint8_t frame_info;
|
||||
int32_t sample_count;
|
||||
long coef1,coef2;
|
||||
int i,shift;
|
||||
int frameSize = channelspacing*15;//mono samples have a frame of 15, stereo files have frames of 30
|
||||
VGMSTREAMCHANNEL *stream = &(vgmstream->ch[channel]);
|
||||
off_t channel_offset=stream->channel_start_offset;
|
||||
|
||||
first_sample = first_sample%28;
|
||||
frame_info = read_8bit(channel_offset,stream->streamfile);
|
||||
|
||||
coef1 = EA_TABLE[frame_info >> 4];
|
||||
coef2 = EA_TABLE[(frame_info >> 4) + 4];
|
||||
shift = (frame_info & 0x0F)+8;
|
||||
|
||||
channel_offset+=channelspacing;
|
||||
//stream->offset = first_sample*channelspacing/2;
|
||||
|
||||
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
|
||||
uint8_t sample_byte;
|
||||
int32_t sample;
|
||||
|
||||
sample_byte = (uint8_t)read_8bit(stream->offset+channel_offset,stream->streamfile);
|
||||
|
||||
sample = (((((i&1)?
|
||||
sample_byte & 0x0F:
|
||||
sample_byte >> 4
|
||||
) << 0x1C) >> shift) +
|
||||
(coef1 * stream->adpcm_history1_32) + (coef2 * stream->adpcm_history2_32) + 0x80) >> 8;
|
||||
|
||||
outbuf[sample_count] = clamp16(sample);
|
||||
stream->adpcm_history2_32 = stream->adpcm_history1_32;
|
||||
stream->adpcm_history1_32 = sample;
|
||||
|
||||
if(i&1)
|
||||
stream->offset+=channelspacing;
|
||||
}
|
||||
|
||||
channel_offset+=i;
|
||||
|
||||
// Only increment offset on complete frame
|
||||
|
||||
if(channel_offset-stream->channel_start_offset==frameSize) {
|
||||
stream->channel_start_offset+=frameSize;
|
||||
stream->offset=0;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,471 @@
|
|||
/* G.721 decoder, from Sun's public domain CCITT-ADPCM sources,
|
||||
* retrieved from ftp://ftp.cwi.nl/pub/audio/ccitt-adpcm.tar.gz
|
||||
*
|
||||
* For reference, here's the original license:
|
||||
*
|
||||
* This source code is a product of Sun Microsystems, Inc. and is provided
|
||||
* for unrestricted use. Users may copy or modify this source code without
|
||||
* charge.
|
||||
*
|
||||
* SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING
|
||||
* THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
|
||||
*
|
||||
* Sun source code is provided with no support and without any obligation on
|
||||
* the part of Sun Microsystems, Inc. to assist in its use, correction,
|
||||
* modification or enhancement.
|
||||
*
|
||||
* SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
|
||||
* INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE
|
||||
* OR ANY PART THEREOF.
|
||||
*
|
||||
* In no event will Sun Microsystems, Inc. be liable for any lost revenue
|
||||
* or profits or other special, indirect and consequential damages, even if
|
||||
* Sun has been advised of the possibility of such damages.
|
||||
*
|
||||
* Sun Microsystems, Inc.
|
||||
* 2550 Garcia Avenue
|
||||
* Mountain View, California 94043
|
||||
*
|
||||
*/
|
||||
|
||||
#include "coding.h"
|
||||
#include "../util.h"
|
||||
|
||||
static short power2[15] = {1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80,
|
||||
0x100, 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000};
|
||||
|
||||
/*
|
||||
* quan()
|
||||
*
|
||||
* quantizes the input val against the table of size short integers.
|
||||
* It returns i if table[i - 1] <= val < table[i].
|
||||
*
|
||||
* Using linear search for simple coding.
|
||||
*/
|
||||
static int
|
||||
quan(
|
||||
int val,
|
||||
short *table,
|
||||
int size)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < size; i++)
|
||||
if (val < *table++)
|
||||
break;
|
||||
return (i);
|
||||
}
|
||||
|
||||
/*
|
||||
* fmult()
|
||||
*
|
||||
* returns the integer product of the 14-bit integer "an" and
|
||||
* "floating point" representation (4-bit exponent, 6-bit mantessa) "srn".
|
||||
*/
|
||||
static int
|
||||
fmult(
|
||||
int an,
|
||||
int srn)
|
||||
{
|
||||
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;
|
||||
|
||||
wanmant = (anmant * (srn & 077) + 0x30) >> 4;
|
||||
retval = (wanexp >= 0) ? ((wanmant << wanexp) & 0x7FFF) :
|
||||
(wanmant >> -wanexp);
|
||||
|
||||
return (((an ^ srn) < 0) ? -retval : retval);
|
||||
}
|
||||
|
||||
/*
|
||||
* g72x_init_state()
|
||||
*
|
||||
* This routine initializes and/or resets the g72x_state structure
|
||||
* pointed to by 'state_ptr'.
|
||||
* All the initial state values are specified in the CCITT G.721 document.
|
||||
*/
|
||||
void
|
||||
g72x_init_state(
|
||||
struct g72x_state *state_ptr)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* predictor_zero()
|
||||
*
|
||||
* computes the estimated signal from 6-zero predictor.
|
||||
*
|
||||
*/
|
||||
int
|
||||
predictor_zero(
|
||||
struct g72x_state *state_ptr)
|
||||
{
|
||||
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);
|
||||
}
|
||||
/*
|
||||
* predictor_pole()
|
||||
*
|
||||
* computes the estimated signal from 2-pole predictor.
|
||||
*
|
||||
*/
|
||||
int
|
||||
predictor_pole(
|
||||
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]));
|
||||
}
|
||||
/*
|
||||
* step_size()
|
||||
*
|
||||
* computes the quantization step size of the adaptive quantizer.
|
||||
*
|
||||
*/
|
||||
int
|
||||
step_size(
|
||||
struct g72x_state *state_ptr)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* reconstruct()
|
||||
*
|
||||
* Returns reconstructed difference signal 'dq' obtained from
|
||||
* codeword 'i' and quantization step size scale factor 'y'.
|
||||
* Multiplication is performed in log base 2 domain as addition.
|
||||
*/
|
||||
int
|
||||
reconstruct(
|
||||
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 */
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* update()
|
||||
*
|
||||
* updates the state variables for each output code
|
||||
*/
|
||||
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 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 */
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
/* 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;
|
||||
|
||||
/* 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;
|
||||
a2p=0; /* won't be used, clear warning */
|
||||
} 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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
/* DELAY A */
|
||||
state_ptr->pk[1] = state_ptr->pk[0];
|
||||
state_ptr->pk[0] = pk0;
|
||||
|
||||
/* 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};
|
||||
|
||||
/* 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};
|
||||
/*
|
||||
* 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};
|
||||
/*
|
||||
* g721_decoder()
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Decodes a 4-bit code of G.721 encoded data of i and
|
||||
* returns the resulting linear PCM, A-law or u-law value.
|
||||
* return -1 for unknown out_coding value.
|
||||
*/
|
||||
int
|
||||
g721_decoder(
|
||||
int i,
|
||||
struct g72x_state *state_ptr)
|
||||
{
|
||||
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 */
|
||||
|
||||
y = step_size(state_ptr); /* dynamic quantizer step size */
|
||||
|
||||
dq = reconstruct(i & 0x08, _dqlntab[i], y); /* quantized diff. */
|
||||
|
||||
sr = (dq < 0) ? (se - (dq & 0x3FFF)) : se + dq; /* reconst. signal */
|
||||
|
||||
dqsez = sr - se + sez; /* pole prediction diff. */
|
||||
|
||||
update(y, _witab[i] << 5, _fitab[i], dq, sr, dqsez, state_ptr);
|
||||
|
||||
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) {
|
||||
int i;
|
||||
int32_t sample_count;
|
||||
|
||||
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),
|
||||
&(stream->g72x_state)
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
#include "../vgmstream.h"
|
||||
|
||||
#ifdef VGM_USE_G7221
|
||||
#include "g7221.h"
|
||||
#include "coding.h"
|
||||
#include "../util.h"
|
||||
|
||||
void decode_g7221(VGMSTREAM * vgmstream,
|
||||
sample * outbuf, int channelspacing, int32_t samples_to_do, int channel) {
|
||||
VGMSTREAMCHANNEL *ch = &vgmstream->ch[channel];
|
||||
g7221_codec_data *data = vgmstream->codec_data;
|
||||
g7221_codec_data *ch_data = &data[channel];
|
||||
int i;
|
||||
|
||||
if (0 == vgmstream->samples_into_block)
|
||||
{
|
||||
int16_t code_buffer[960/8];
|
||||
vgmstream->ch[channel].streamfile->read(ch->streamfile, (uint8_t*)code_buffer, ch->offset, vgmstream->interleave_block_size);
|
||||
g7221_decode_frame(ch_data->handle, code_buffer, ch_data->buffer);
|
||||
}
|
||||
|
||||
for (i = 0; i < samples_to_do; i++)
|
||||
{
|
||||
outbuf[i*channelspacing] = ch_data->buffer[vgmstream->samples_into_block+i];
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* streamtypes.h - widely used type definitions
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _G72X_STATE_H
|
||||
#define _G72X_STATE_H
|
||||
|
||||
struct g72x_state {
|
||||
long yl; /* Locked or steady state step size multiplier. */
|
||||
short yu; /* Unlocked or non-steady state step size multiplier. */
|
||||
short dms; /* Short term energy estimate. */
|
||||
short dml; /* Long term energy estimate. */
|
||||
short ap; /* Linear weighting coefficient of 'yl' and 'yu'. */
|
||||
|
||||
short a[2]; /* Coefficients of pole portion of prediction filter. */
|
||||
short b[6]; /* Coefficients of zero portion of prediction filter. */
|
||||
short pk[2]; /*
|
||||
* Signs of previous two samples of a partially
|
||||
* reconstructed signal.
|
||||
*/
|
||||
short dq[6]; /*
|
||||
* Previous 6 samples of the quantized difference
|
||||
* signal represented in an internal floating point
|
||||
* format.
|
||||
*/
|
||||
short sr[2]; /*
|
||||
* Previous 2 samples of the quantized difference
|
||||
* signal represented in an internal floating point
|
||||
* format.
|
||||
*/
|
||||
char td; /* delayed tone detect, new in 1988 version */
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,637 @@
|
|||
#include "../util.h"
|
||||
#include "coding.h"
|
||||
|
||||
const int32_t ADPCMTable[89] =
|
||||
|
||||
{
|
||||
|
||||
7, 8, 9, 10, 11, 12, 13, 14,
|
||||
16, 17, 19, 21, 23, 25, 28, 31,
|
||||
34, 37, 41, 45, 50, 55, 60, 66,
|
||||
73, 80, 88, 97, 107, 118, 130, 143,
|
||||
157, 173, 190, 209, 230, 253, 279, 307,
|
||||
337, 371, 408, 449, 494, 544, 598, 658,
|
||||
724, 796, 876, 963, 1060, 1166, 1282, 1411,
|
||||
1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024,
|
||||
3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484,
|
||||
7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
|
||||
15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794,
|
||||
32767
|
||||
|
||||
};
|
||||
|
||||
const int IMA_IndexTable[16] =
|
||||
|
||||
{
|
||||
-1, -1, -1, -1, 2, 4, 6, 8,
|
||||
-1, -1, -1, -1, 2, 4, 6, 8
|
||||
};
|
||||
|
||||
void decode_nds_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
int i=first_sample;
|
||||
int32_t sample_count;
|
||||
int32_t hist1 = stream->adpcm_history1_16;
|
||||
int step_index = stream->adpcm_step_index;
|
||||
|
||||
if (first_sample==0) {
|
||||
hist1 = read_16bitLE(stream->offset,stream->streamfile);
|
||||
step_index = read_16bitLE(stream->offset+2,stream->streamfile);
|
||||
}
|
||||
|
||||
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
|
||||
int sample_nibble =
|
||||
(read_8bit(stream->offset+4+i/2,stream->streamfile) >> (i&1?4:0))&0xf;
|
||||
int delta;
|
||||
int step = ADPCMTable[step_index];
|
||||
|
||||
delta = step >> 3;
|
||||
if (sample_nibble & 1) delta += step >> 2;
|
||||
if (sample_nibble & 2) delta += step >> 1;
|
||||
if (sample_nibble & 4) delta += step;
|
||||
if (sample_nibble & 8)
|
||||
outbuf[sample_count] = clamp16(hist1 - delta);
|
||||
else
|
||||
outbuf[sample_count] = clamp16(hist1 + delta);
|
||||
|
||||
step_index += IMA_IndexTable[sample_nibble];
|
||||
if (step_index < 0) step_index=0;
|
||||
if (step_index > 88) step_index=88;
|
||||
|
||||
hist1 = outbuf[sample_count];
|
||||
}
|
||||
|
||||
stream->adpcm_history1_16 = hist1;
|
||||
stream->adpcm_step_index = step_index;
|
||||
}
|
||||
|
||||
void decode_dat4_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
int i=first_sample;
|
||||
int32_t sample_count;
|
||||
int32_t hist1 = stream->adpcm_history1_16;
|
||||
int step_index = stream->adpcm_step_index;
|
||||
|
||||
if (first_sample==0) {
|
||||
hist1 = read_16bitLE(stream->offset,stream->streamfile);
|
||||
step_index = read_8bit(stream->offset+2,stream->streamfile);
|
||||
}
|
||||
|
||||
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
|
||||
int sample_nibble =
|
||||
(read_8bit(stream->offset+4+i/2,stream->streamfile) >> (i&1?0:4))&0xf;
|
||||
int delta;
|
||||
int step = ADPCMTable[step_index];
|
||||
|
||||
delta = step >> 3;
|
||||
if (sample_nibble & 1) delta += step >> 2;
|
||||
if (sample_nibble & 2) delta += step >> 1;
|
||||
if (sample_nibble & 4) delta += step;
|
||||
if (sample_nibble & 8)
|
||||
outbuf[sample_count] = clamp16(hist1 - delta);
|
||||
else
|
||||
outbuf[sample_count] = clamp16(hist1 + delta);
|
||||
|
||||
step_index += IMA_IndexTable[sample_nibble];
|
||||
if (step_index < 0) step_index=0;
|
||||
if (step_index > 88) step_index=88;
|
||||
|
||||
hist1 = outbuf[sample_count];
|
||||
}
|
||||
|
||||
stream->adpcm_history1_16 = hist1;
|
||||
stream->adpcm_step_index = step_index;
|
||||
}
|
||||
|
||||
/* Xbox IMA is MS IMA, but I'll leave it alone for now (esp as it has > 2 channel support) */
|
||||
void decode_ms_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel) {
|
||||
int i=first_sample;
|
||||
int sample_nibble;
|
||||
int sample_decoded;
|
||||
int delta;
|
||||
int block_samples = (vgmstream->interleave_block_size - vgmstream->channels * 4) * 2 / vgmstream->channels;
|
||||
|
||||
int32_t sample_count=0;
|
||||
int32_t hist1=stream->adpcm_history1_32;
|
||||
int step_index = stream->adpcm_step_index;
|
||||
off_t offset=stream->offset;
|
||||
|
||||
first_sample = first_sample % block_samples;
|
||||
|
||||
if (first_sample == 0) {
|
||||
|
||||
hist1 = read_16bitLE(offset+channel*4,stream->streamfile);
|
||||
step_index = read_16bitLE(offset+channel*4+2,stream->streamfile);
|
||||
|
||||
if (step_index < 0) step_index=0;
|
||||
if (step_index > 88) step_index=88;
|
||||
}
|
||||
|
||||
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
|
||||
int step = ADPCMTable[step_index];
|
||||
|
||||
offset = stream->offset + 4*vgmstream->channels + (i/8*4*vgmstream->channels) + (i%8)/2 + 4*channel;
|
||||
|
||||
sample_nibble = (read_8bit(offset,stream->streamfile) >> (i&1?4:0))&0xf;
|
||||
|
||||
sample_decoded=hist1;
|
||||
|
||||
delta = step >> 3;
|
||||
if (sample_nibble & 1) delta += step >> 2;
|
||||
if (sample_nibble & 2) delta += step >> 1;
|
||||
if (sample_nibble & 4) delta += step;
|
||||
if (sample_nibble & 8)
|
||||
sample_decoded -= delta;
|
||||
else
|
||||
sample_decoded += delta;
|
||||
|
||||
hist1=clamp16(sample_decoded);
|
||||
|
||||
step_index += IMA_IndexTable[sample_nibble];
|
||||
if (step_index < 0) step_index=0;
|
||||
if (step_index > 88) step_index=88;
|
||||
|
||||
outbuf[sample_count]=(short)(hist1);
|
||||
|
||||
}
|
||||
|
||||
// Only increment offset on complete frame
|
||||
if (i == block_samples) stream->offset += vgmstream->interleave_block_size;
|
||||
|
||||
stream->adpcm_history1_32=hist1;
|
||||
stream->adpcm_step_index=step_index;
|
||||
}
|
||||
|
||||
// "Radical ADPCM", essentially MS IMA
|
||||
void decode_rad_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel) {
|
||||
int i=first_sample;
|
||||
int sample_nibble;
|
||||
int sample_decoded;
|
||||
int delta;
|
||||
int block_samples = (vgmstream->interleave_block_size - vgmstream->channels * 4) * 2 / vgmstream->channels;
|
||||
|
||||
int32_t sample_count=0;
|
||||
int32_t hist1=stream->adpcm_history1_32;
|
||||
int step_index = stream->adpcm_step_index;
|
||||
off_t offset=stream->offset;
|
||||
|
||||
first_sample = first_sample % block_samples;
|
||||
|
||||
if (first_sample == 0) {
|
||||
|
||||
hist1 = read_16bitLE(offset+channel*4+2,stream->streamfile);
|
||||
step_index = read_16bitLE(offset+channel*4,stream->streamfile);
|
||||
|
||||
if (step_index < 0) step_index=0;
|
||||
if (step_index > 88) step_index=88;
|
||||
}
|
||||
|
||||
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
|
||||
int step = ADPCMTable[step_index];
|
||||
|
||||
offset = stream->offset + 4*vgmstream->channels + (i/2*vgmstream->channels) + channel;
|
||||
|
||||
sample_nibble = (read_8bit(offset,stream->streamfile) >> (i&1?4:0))&0xf;
|
||||
|
||||
sample_decoded=hist1;
|
||||
|
||||
delta = step >> 3;
|
||||
if (sample_nibble & 1) delta += step >> 2;
|
||||
if (sample_nibble & 2) delta += step >> 1;
|
||||
if (sample_nibble & 4) delta += step;
|
||||
if (sample_nibble & 8)
|
||||
sample_decoded -= delta;
|
||||
else
|
||||
sample_decoded += delta;
|
||||
|
||||
hist1=clamp16(sample_decoded);
|
||||
|
||||
step_index += IMA_IndexTable[sample_nibble];
|
||||
if (step_index < 0) step_index=0;
|
||||
if (step_index > 88) step_index=88;
|
||||
|
||||
outbuf[sample_count]=(short)(hist1);
|
||||
|
||||
}
|
||||
|
||||
// Only increment offset on complete frame
|
||||
if (i == block_samples) stream->offset += vgmstream->interleave_block_size;
|
||||
|
||||
stream->adpcm_history1_32=hist1;
|
||||
stream->adpcm_step_index=step_index;
|
||||
}
|
||||
|
||||
// "Radical ADPCM", mono form (for use with interleave layout)
|
||||
// I think this is exactly equivalent to mono MS APDCM, but I need a
|
||||
// channel-agnostic version to use within an interleave.
|
||||
void decode_rad_ima_mono(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
int i=first_sample;
|
||||
int sample_nibble;
|
||||
int sample_decoded;
|
||||
int delta;
|
||||
int block_samples = 0x14 * 2;
|
||||
|
||||
int32_t sample_count=0;
|
||||
int32_t hist1=stream->adpcm_history1_32;
|
||||
int step_index = stream->adpcm_step_index;
|
||||
off_t offset=stream->offset;
|
||||
|
||||
first_sample = first_sample % block_samples;
|
||||
|
||||
if (first_sample == 0) {
|
||||
|
||||
hist1 = read_16bitLE(offset+2,stream->streamfile);
|
||||
step_index = read_16bitLE(offset,stream->streamfile);
|
||||
|
||||
if (step_index < 0) step_index=0;
|
||||
if (step_index > 88) step_index=88;
|
||||
}
|
||||
|
||||
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
|
||||
int step = ADPCMTable[step_index];
|
||||
|
||||
offset = stream->offset + 4 + (i/2);
|
||||
|
||||
sample_nibble = (read_8bit(offset,stream->streamfile) >> (i&1?4:0))&0xf;
|
||||
|
||||
sample_decoded=hist1;
|
||||
|
||||
delta = step >> 3;
|
||||
if (sample_nibble & 1) delta += step >> 2;
|
||||
if (sample_nibble & 2) delta += step >> 1;
|
||||
if (sample_nibble & 4) delta += step;
|
||||
if (sample_nibble & 8)
|
||||
sample_decoded -= delta;
|
||||
else
|
||||
sample_decoded += delta;
|
||||
|
||||
hist1=clamp16(sample_decoded);
|
||||
|
||||
step_index += IMA_IndexTable[sample_nibble];
|
||||
if (step_index < 0) step_index=0;
|
||||
if (step_index > 88) step_index=88;
|
||||
|
||||
outbuf[sample_count]=(short)(hist1);
|
||||
|
||||
}
|
||||
|
||||
stream->adpcm_history1_32=hist1;
|
||||
stream->adpcm_step_index=step_index;
|
||||
}
|
||||
|
||||
void decode_xbox_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel) {
|
||||
int i=first_sample;
|
||||
int sample_nibble;
|
||||
int sample_decoded;
|
||||
int delta;
|
||||
|
||||
int32_t sample_count=0;
|
||||
int32_t hist1=stream->adpcm_history1_32;
|
||||
int step_index = stream->adpcm_step_index;
|
||||
off_t offset=stream->offset;
|
||||
|
||||
if(vgmstream->channels==1)
|
||||
first_sample = first_sample % 32;
|
||||
else
|
||||
first_sample = first_sample % (32*(vgmstream->channels&2));
|
||||
|
||||
if (first_sample == 0) {
|
||||
|
||||
if(vgmstream->layout_type==layout_ea_blocked) {
|
||||
hist1 = read_16bitLE(offset,stream->streamfile);
|
||||
step_index = read_16bitLE(offset+2,stream->streamfile);
|
||||
} else {
|
||||
hist1 = read_16bitLE(offset+(channel%2)*4,stream->streamfile);
|
||||
step_index = read_16bitLE(offset+(channel%2)*4+2,stream->streamfile);
|
||||
}
|
||||
if (step_index < 0) step_index=0;
|
||||
if (step_index > 88) step_index=88;
|
||||
}
|
||||
|
||||
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
|
||||
int step = ADPCMTable[step_index];
|
||||
|
||||
if(vgmstream->layout_type==layout_ea_blocked)
|
||||
offset = stream->offset + (i/8*4+(i%8)/2+4);
|
||||
else {
|
||||
if(channelspacing==1)
|
||||
offset = stream->offset + 4 + (i/8*4+(i%8)/2+4*(channel%2));
|
||||
else
|
||||
offset = stream->offset + 4*2 + (i/8*4*2+(i%8)/2+4*(channel%2));
|
||||
}
|
||||
|
||||
sample_nibble = (read_8bit(offset,stream->streamfile) >> (i&1?4:0))&0xf;
|
||||
|
||||
sample_decoded=hist1;
|
||||
|
||||
delta = step >> 3;
|
||||
if (sample_nibble & 1) delta += step >> 2;
|
||||
if (sample_nibble & 2) delta += step >> 1;
|
||||
if (sample_nibble & 4) delta += step;
|
||||
if (sample_nibble & 8)
|
||||
sample_decoded -= delta;
|
||||
else
|
||||
sample_decoded += delta;
|
||||
|
||||
hist1=clamp16(sample_decoded);
|
||||
|
||||
step_index += IMA_IndexTable[sample_nibble];
|
||||
if (step_index < 0) step_index=0;
|
||||
if (step_index > 88) step_index=88;
|
||||
|
||||
outbuf[sample_count]=(short)(hist1);
|
||||
}
|
||||
|
||||
// Only increment offset on complete frame
|
||||
if(vgmstream->layout_type==layout_ea_blocked) {
|
||||
if(offset-stream->offset==32+3) // ??
|
||||
stream->offset+=36;
|
||||
} else {
|
||||
if(channelspacing==1) {
|
||||
if(offset-stream->offset==32+3) // ??
|
||||
stream->offset+=36;
|
||||
} else {
|
||||
if(offset-stream->offset==64+(4*(channel%2))+3) // ??
|
||||
stream->offset+=36*channelspacing;
|
||||
}
|
||||
}
|
||||
stream->adpcm_history1_32=hist1;
|
||||
stream->adpcm_step_index=step_index;
|
||||
}
|
||||
|
||||
void decode_int_xbox_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel) {
|
||||
int i=first_sample;
|
||||
int sample_nibble;
|
||||
int sample_decoded;
|
||||
int delta;
|
||||
|
||||
int32_t sample_count=0;
|
||||
int32_t hist1=stream->adpcm_history1_32;
|
||||
int step_index = stream->adpcm_step_index;
|
||||
off_t offset=stream->offset;
|
||||
|
||||
if(vgmstream->channels==1)
|
||||
first_sample = first_sample % 32;
|
||||
else
|
||||
first_sample = first_sample % (32*(vgmstream->channels&2));
|
||||
|
||||
if (first_sample == 0) {
|
||||
|
||||
hist1 = read_16bitLE(offset,stream->streamfile);
|
||||
step_index = read_16bitLE(offset+2,stream->streamfile);
|
||||
|
||||
if (step_index < 0) step_index=0;
|
||||
if (step_index > 88) step_index=88;
|
||||
}
|
||||
|
||||
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
|
||||
int step = ADPCMTable[step_index];
|
||||
|
||||
offset = stream->offset + 4 + (i/8*4+(i%8)/2);
|
||||
|
||||
sample_nibble = (read_8bit(offset,stream->streamfile) >> (i&1?4:0))&0xf;
|
||||
|
||||
sample_decoded=hist1;
|
||||
|
||||
delta = step >> 3;
|
||||
if (sample_nibble & 1) delta += step >> 2;
|
||||
if (sample_nibble & 2) delta += step >> 1;
|
||||
if (sample_nibble & 4) delta += step;
|
||||
if (sample_nibble & 8)
|
||||
sample_decoded -= delta;
|
||||
else
|
||||
sample_decoded += delta;
|
||||
|
||||
hist1=clamp16(sample_decoded);
|
||||
|
||||
step_index += IMA_IndexTable[sample_nibble];
|
||||
if (step_index < 0) step_index=0;
|
||||
if (step_index > 88) step_index=88;
|
||||
|
||||
outbuf[sample_count]=(short)(hist1);
|
||||
}
|
||||
|
||||
// Only increment offset on complete frame
|
||||
if(channelspacing==1) {
|
||||
if(offset-stream->offset==32+3) // ??
|
||||
stream->offset+=36;
|
||||
} else {
|
||||
if(offset-stream->offset==64+(4*(channel%2))+3) // ??
|
||||
stream->offset+=36*channelspacing;
|
||||
}
|
||||
stream->adpcm_history1_32=hist1;
|
||||
stream->adpcm_step_index=step_index;
|
||||
}
|
||||
|
||||
void decode_dvi_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
int i;
|
||||
|
||||
int32_t sample_count=0;
|
||||
int32_t hist1=stream->adpcm_history1_32;
|
||||
int step_index = stream->adpcm_step_index;
|
||||
|
||||
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
|
||||
int step = ADPCMTable[step_index];
|
||||
uint8_t sample_byte;
|
||||
int sample_nibble;
|
||||
int sample_decoded;
|
||||
int delta;
|
||||
|
||||
sample_byte = read_8bit(stream->offset+i/2,stream->streamfile);
|
||||
/* old-style DVI takes high nibble first */
|
||||
sample_nibble = (sample_byte >> (i&1?0:4))&0xf;
|
||||
|
||||
sample_decoded = hist1;
|
||||
delta = step >> 3;
|
||||
if (sample_nibble & 1) delta += step >> 2;
|
||||
if (sample_nibble & 2) delta += step >> 1;
|
||||
if (sample_nibble & 4) delta += step;
|
||||
if (sample_nibble & 8)
|
||||
sample_decoded -= delta;
|
||||
else
|
||||
sample_decoded += delta;
|
||||
|
||||
hist1=clamp16(sample_decoded);
|
||||
|
||||
step_index += IMA_IndexTable[sample_nibble&0x7];
|
||||
if (step_index < 0) step_index=0;
|
||||
if (step_index > 88) step_index=88;
|
||||
|
||||
outbuf[sample_count]=(short)(hist1);
|
||||
}
|
||||
|
||||
stream->adpcm_history1_32=hist1;
|
||||
stream->adpcm_step_index=step_index;
|
||||
}
|
||||
|
||||
|
||||
void decode_eacs_ima(VGMSTREAM * vgmstream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
|
||||
int i;
|
||||
VGMSTREAMCHANNEL * stream = &(vgmstream->ch[channel]);
|
||||
|
||||
int32_t sample_count=0;
|
||||
int32_t hist1=stream->adpcm_history1_32;
|
||||
int step_index = stream->adpcm_step_index;
|
||||
|
||||
vgmstream->get_high_nibble=!vgmstream->get_high_nibble;
|
||||
|
||||
if((first_sample) && (channelspacing==1))
|
||||
vgmstream->get_high_nibble=!vgmstream->get_high_nibble;
|
||||
|
||||
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
|
||||
int step = ADPCMTable[step_index];
|
||||
uint8_t sample_byte;
|
||||
int sample_nibble;
|
||||
int sample_decoded;
|
||||
int delta;
|
||||
|
||||
sample_byte = read_8bit(stream->offset+i,stream->streamfile);
|
||||
sample_nibble = (sample_byte >> (vgmstream->get_high_nibble?0:4))&0xf;
|
||||
|
||||
sample_decoded = hist1;
|
||||
delta = step >> 3;
|
||||
if (sample_nibble & 1) delta += step >> 2;
|
||||
if (sample_nibble & 2) delta += step >> 1;
|
||||
if (sample_nibble & 4) delta += step;
|
||||
if (sample_nibble & 8)
|
||||
sample_decoded -= delta;
|
||||
else
|
||||
sample_decoded += delta;
|
||||
|
||||
hist1=clamp16(sample_decoded);
|
||||
|
||||
step_index += IMA_IndexTable[sample_nibble&0x7];
|
||||
if (step_index < 0) step_index=0;
|
||||
if (step_index > 88) step_index=88;
|
||||
|
||||
outbuf[sample_count]=(short)(hist1);
|
||||
}
|
||||
|
||||
stream->adpcm_history1_32=hist1;
|
||||
stream->adpcm_step_index=step_index;
|
||||
}
|
||||
|
||||
void decode_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
int i;
|
||||
|
||||
int32_t sample_count=0;
|
||||
int32_t hist1=stream->adpcm_history1_32;
|
||||
int step_index = stream->adpcm_step_index;
|
||||
|
||||
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
|
||||
int step = ADPCMTable[step_index];
|
||||
uint8_t sample_byte;
|
||||
int sample_nibble;
|
||||
int sample_decoded;
|
||||
int delta;
|
||||
|
||||
sample_byte = read_8bit(stream->offset+i/2,stream->streamfile);
|
||||
sample_nibble = (sample_byte >> (i&1?4:0))&0xf;
|
||||
|
||||
sample_decoded = hist1;
|
||||
delta = step >> 3;
|
||||
if (sample_nibble & 1) delta += step >> 2;
|
||||
if (sample_nibble & 2) delta += step >> 1;
|
||||
if (sample_nibble & 4) delta += step;
|
||||
if (sample_nibble & 8)
|
||||
sample_decoded -= delta;
|
||||
else
|
||||
sample_decoded += delta;
|
||||
|
||||
hist1=clamp16(sample_decoded);
|
||||
|
||||
step_index += IMA_IndexTable[sample_nibble&0x7];
|
||||
if (step_index < 0) step_index=0;
|
||||
if (step_index > 88) step_index=88;
|
||||
|
||||
outbuf[sample_count]=(short)(hist1);
|
||||
}
|
||||
|
||||
stream->adpcm_history1_32=hist1;
|
||||
stream->adpcm_step_index=step_index;
|
||||
}
|
||||
|
||||
void decode_apple_ima4(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
int i;
|
||||
|
||||
int32_t sample_count=0;
|
||||
int16_t hist1=stream->adpcm_history1_16;
|
||||
int step_index = stream->adpcm_step_index;
|
||||
|
||||
off_t packet_offset = stream->offset + first_sample/64*34;
|
||||
|
||||
first_sample = first_sample % 64;
|
||||
|
||||
if (first_sample == 0)
|
||||
{
|
||||
hist1 = (int16_t)((uint16_t)read_16bitBE(packet_offset,stream->streamfile) & 0xff80);
|
||||
step_index = read_8bit(packet_offset+1,stream->streamfile) & 0x7f;
|
||||
}
|
||||
|
||||
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
|
||||
int step = ADPCMTable[step_index];
|
||||
uint8_t sample_byte;
|
||||
int sample_nibble;
|
||||
int sample_decoded;
|
||||
int delta;
|
||||
|
||||
sample_byte = read_8bit(packet_offset+2+i/2,stream->streamfile);
|
||||
sample_nibble = (sample_byte >> (i&1?4:0))&0xf;
|
||||
|
||||
sample_decoded = hist1;
|
||||
delta = step >> 3;
|
||||
if (sample_nibble & 1) delta += step >> 2;
|
||||
if (sample_nibble & 2) delta += step >> 1;
|
||||
if (sample_nibble & 4) delta += step;
|
||||
if (sample_nibble & 8)
|
||||
sample_decoded -= delta;
|
||||
else
|
||||
sample_decoded += delta;
|
||||
|
||||
hist1=clamp16(sample_decoded);
|
||||
|
||||
step_index += IMA_IndexTable[sample_nibble&0x7];
|
||||
if (step_index < 0) step_index=0;
|
||||
if (step_index > 88) step_index=88;
|
||||
|
||||
outbuf[sample_count]=(short)(hist1);
|
||||
}
|
||||
|
||||
stream->adpcm_history1_16=hist1;
|
||||
stream->adpcm_step_index=step_index;
|
||||
}
|
||||
|
||||
void decode_snds_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
|
||||
int i;
|
||||
|
||||
int32_t sample_count=0;
|
||||
int32_t hist1=stream->adpcm_history1_32;
|
||||
int step_index = stream->adpcm_step_index;
|
||||
|
||||
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
|
||||
int step;
|
||||
uint8_t sample_byte;
|
||||
int sample_nibble;
|
||||
int sample_decoded;
|
||||
int delta;
|
||||
|
||||
sample_byte = read_8bit(stream->offset+i,stream->streamfile);
|
||||
sample_nibble = (sample_byte >> (channel==0?0:4))&0xf;
|
||||
|
||||
// update step before doing current sample
|
||||
step_index += IMA_IndexTable[sample_nibble];
|
||||
if (step_index < 0) step_index=0;
|
||||
if (step_index > 88) step_index=88;
|
||||
step = ADPCMTable[step_index];
|
||||
|
||||
delta = (sample_nibble & 7) * step / 4 + step / 8;
|
||||
if (sample_nibble & 8) delta = -delta;
|
||||
sample_decoded = hist1 + delta;
|
||||
|
||||
hist1=clamp16(sample_decoded);
|
||||
|
||||
outbuf[sample_count]=(short)(hist1);
|
||||
}
|
||||
|
||||
stream->adpcm_history1_32=hist1;
|
||||
stream->adpcm_step_index=step_index;
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
#include "coding.h"
|
||||
#include "../util.h"
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
void decode_l5_555(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
int i=first_sample;
|
||||
int32_t sample_count;
|
||||
|
||||
int framesin = first_sample/32;
|
||||
|
||||
uint16_t header = (uint16_t)read_16bitLE(framesin*0x12+stream->offset,stream->streamfile);
|
||||
int32_t pos_scale = l5_scales[(header>>5)&0x1f];
|
||||
int32_t neg_scale = l5_scales[header&0x1f];
|
||||
|
||||
int coef_index = (header >> 10) & 0x1f;
|
||||
int16_t hist1 = stream->adpcm_history1_16;
|
||||
int16_t hist2 = stream->adpcm_history2_16;
|
||||
int16_t hist3 = stream->adpcm_history3_16;
|
||||
int32_t coef1 = stream->adpcm_coef_3by32[coef_index*3];
|
||||
int32_t coef2 = stream->adpcm_coef_3by32[coef_index*3+1];
|
||||
int32_t coef3 = stream->adpcm_coef_3by32[coef_index*3+2];
|
||||
/*printf("offset: %x\nscale: %d\nindex: %d (%lf,%lf)\nhist: %d %d\n",
|
||||
(unsigned)stream->offset,scale,coef_index,coef1/2048.0,coef2/2048.0,hist1,hist2);*/
|
||||
|
||||
first_sample = first_sample%32;
|
||||
|
||||
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
|
||||
int sample_byte = read_8bit(framesin*0x12+stream->offset+2+i/2,stream->streamfile);
|
||||
int nibble = (i&1?
|
||||
get_low_nibble_signed(sample_byte):
|
||||
get_high_nibble_signed(sample_byte));
|
||||
int32_t prediction =
|
||||
-(hist1 * coef1 + hist2 * coef2 + hist3 * coef3);
|
||||
|
||||
if (nibble >= 0)
|
||||
{
|
||||
outbuf[sample_count] = clamp16((prediction + nibble * pos_scale) >> 12);
|
||||
}
|
||||
else
|
||||
{
|
||||
outbuf[sample_count] = clamp16((prediction + nibble * neg_scale) >> 12);
|
||||
}
|
||||
|
||||
hist3 = hist2;
|
||||
hist2 = hist1;
|
||||
hist1 = outbuf[sample_count];
|
||||
}
|
||||
|
||||
stream->adpcm_history1_16 = hist1;
|
||||
stream->adpcm_history2_16 = hist2;
|
||||
stream->adpcm_history3_16 = hist3;
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
#include "coding.h"
|
||||
#include "../util.h"
|
||||
|
||||
/* lsf ADPCM, as seen in Fastlane Street Racing */
|
||||
|
||||
static const short lsf_coefs[5][2] = {
|
||||
{0x73, -0x34},
|
||||
{0, 0},
|
||||
{0x62, -0x37},
|
||||
{0x3C, 0},
|
||||
{0x7A, -0x3c}
|
||||
};
|
||||
|
||||
void decode_lsf(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
int i=first_sample;
|
||||
int32_t sample_count;
|
||||
const int bytes_per_frame = 0x1c;
|
||||
const int samples_per_frame = (bytes_per_frame-1)*2;
|
||||
|
||||
int framesin = first_sample/samples_per_frame;
|
||||
|
||||
uint8_t q = 0xFF - read_8bit(framesin*bytes_per_frame + stream->offset,stream->streamfile);
|
||||
int scale = (q&0xF0)>>4;
|
||||
int coef_idx = q&0x0F;
|
||||
int32_t hist1 = stream->adpcm_history1_16;
|
||||
int32_t hist2 = stream->adpcm_history2_16;
|
||||
|
||||
first_sample = first_sample%samples_per_frame;
|
||||
|
||||
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
|
||||
int sample_byte = read_8bit(framesin*bytes_per_frame+stream->offset+1+i/2,stream->streamfile);
|
||||
|
||||
long prediction =
|
||||
(hist1 * lsf_coefs[coef_idx][0] +
|
||||
hist2 * lsf_coefs[coef_idx][1]) / 0x40;
|
||||
|
||||
prediction += (i&1?
|
||||
get_high_nibble_signed(sample_byte):
|
||||
get_low_nibble_signed(sample_byte)
|
||||
) * (1 << (12-scale));
|
||||
|
||||
prediction = clamp16(prediction);
|
||||
|
||||
hist2 = hist1;
|
||||
hist1 = prediction;
|
||||
|
||||
outbuf[sample_count] = prediction;
|
||||
}
|
||||
|
||||
stream->adpcm_history1_16 = hist1;
|
||||
stream->adpcm_history2_16 = hist2;
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
#include "../vgmstream.h"
|
||||
|
||||
#if defined(VGM_USE_MP4V2) && defined(VGM_USE_FDKAAC)
|
||||
static void convert_samples(INT_PCM * src, sample * dest, int32_t count) {
|
||||
int32_t i;
|
||||
for ( i = 0; i < count; i++ ) {
|
||||
INT_PCM sample = *src++;
|
||||
sample >>= SAMPLE_BITS - 16;
|
||||
if ( ( sample + 0x8000 ) & 0xFFFF0000 ) sample = 0x7FFF ^ ( sample >> 31 );
|
||||
*dest++ = sample;
|
||||
}
|
||||
}
|
||||
|
||||
void decode_mp4_aac(mp4_aac_codec_data * data, sample * outbuf, int32_t samples_to_do, int channels) {
|
||||
int samples_done = 0;
|
||||
|
||||
uint8_t * buffer = NULL;
|
||||
uint32_t buffer_size;
|
||||
UINT ubuffer_size, bytes_valid;
|
||||
|
||||
CStreamInfo * stream_info = aacDecoder_GetStreamInfo( data->h_aacdecoder );
|
||||
|
||||
int32_t samples_remain = data->samples_per_frame - data->sample_ptr;
|
||||
|
||||
if ( data->samples_discard ) {
|
||||
if ( samples_remain <= data->samples_discard ) {
|
||||
data->samples_discard -= samples_remain;
|
||||
samples_remain = 0;
|
||||
}
|
||||
else {
|
||||
samples_remain -= data->samples_discard;
|
||||
data->sample_ptr += data->samples_discard;
|
||||
data->samples_discard = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if ( samples_remain > samples_to_do ) samples_remain = samples_to_do;
|
||||
|
||||
convert_samples( data->sample_buffer + data->sample_ptr * stream_info->numChannels, outbuf, samples_remain * stream_info->numChannels );
|
||||
|
||||
outbuf += samples_remain * stream_info->numChannels;
|
||||
|
||||
data->sample_ptr += samples_remain;
|
||||
|
||||
samples_done += samples_remain;
|
||||
|
||||
while ( samples_done < samples_to_do ) {
|
||||
if (data->sampleId >= data->numSamples) {
|
||||
memset(outbuf, 0, (samples_to_do - samples_done) * stream_info->numChannels * sizeof(sample));
|
||||
break;
|
||||
}
|
||||
if (!MP4ReadSample( data->h_mp4file, data->track_id, ++data->sampleId, (uint8_t**)(&buffer), (uint32_t*)(&buffer_size), 0, 0, 0, 0)) return;
|
||||
ubuffer_size = buffer_size;
|
||||
bytes_valid = buffer_size;
|
||||
if ( aacDecoder_Fill( data->h_aacdecoder, &buffer, &ubuffer_size, &bytes_valid ) || bytes_valid ) {
|
||||
free( buffer );
|
||||
return;
|
||||
}
|
||||
if ( aacDecoder_DecodeFrame( data->h_aacdecoder, data->sample_buffer, ( (6) * (2048)*4 ), 0 ) ) {
|
||||
free( buffer );
|
||||
return;
|
||||
}
|
||||
free( buffer ); buffer = NULL;
|
||||
stream_info = aacDecoder_GetStreamInfo( data->h_aacdecoder );
|
||||
samples_remain = data->samples_per_frame = stream_info->frameSize;
|
||||
data->sample_ptr = 0;
|
||||
if ( data->samples_discard ) {
|
||||
if ( samples_remain <= data->samples_discard ) {
|
||||
data->samples_discard -= samples_remain;
|
||||
samples_remain = 0;
|
||||
}
|
||||
else {
|
||||
samples_remain -= data->samples_discard;
|
||||
data->sample_ptr = data->samples_discard;
|
||||
data->samples_discard = 0;
|
||||
}
|
||||
}
|
||||
if ( samples_remain > samples_to_do - samples_done ) samples_remain = samples_to_do - samples_done;
|
||||
convert_samples( data->sample_buffer + data->sample_ptr * stream_info->numChannels, outbuf, samples_remain * stream_info->numChannels );
|
||||
samples_done += samples_remain;
|
||||
outbuf += samples_remain * stream_info->numChannels;
|
||||
data->sample_ptr = samples_remain;
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,229 @@
|
|||
#include "../vgmstream.h"
|
||||
|
||||
#ifdef VGM_USE_MPEG
|
||||
#include <string.h>
|
||||
#include <mpg123.h>
|
||||
#include "coding.h"
|
||||
#include "../util.h"
|
||||
|
||||
/* mono, mpg123 expects frames of 0x414 (160kbps, 22050Hz) but they
|
||||
* actually vary and are much shorter */
|
||||
void decode_fake_mpeg2_l2(VGMSTREAMCHANNEL *stream,
|
||||
mpeg_codec_data * data,
|
||||
sample * outbuf, int32_t samples_to_do) {
|
||||
int samples_done = 0;
|
||||
|
||||
while (samples_done < samples_to_do) {
|
||||
size_t bytes_done;
|
||||
int rc;
|
||||
|
||||
if (!data->buffer_full) {
|
||||
/* fill buffer up to next frame ending (or file ending) */
|
||||
int bytes_into_header = 0;
|
||||
const uint8_t header[4] = {0xff,0xf5,0xe0,0xc0};
|
||||
off_t frame_offset = 0;
|
||||
|
||||
/* assume that we are starting at a header, skip it and look for the
|
||||
* next one */
|
||||
read_streamfile(data->buffer, stream->offset+frame_offset, 4,
|
||||
stream->streamfile);
|
||||
frame_offset += 4;
|
||||
|
||||
do {
|
||||
uint8_t byte;
|
||||
byte =
|
||||
read_8bit(stream->offset+frame_offset,stream->streamfile);
|
||||
data->buffer[frame_offset] = byte;
|
||||
frame_offset++;
|
||||
|
||||
if (byte == header[bytes_into_header]) {
|
||||
bytes_into_header++;
|
||||
} else {
|
||||
/* This might have been the first byte of the header, so
|
||||
* we need to check again.
|
||||
* No need to get more complicated than this, though, since
|
||||
* there are no repeated characters in the search string. */
|
||||
if (bytes_into_header>0) {
|
||||
frame_offset--;
|
||||
}
|
||||
bytes_into_header=0;
|
||||
}
|
||||
|
||||
if (bytes_into_header==4) {
|
||||
break;
|
||||
}
|
||||
} while (frame_offset < AHX_EXPECTED_FRAME_SIZE);
|
||||
|
||||
if (bytes_into_header==4) frame_offset-=4;
|
||||
memset(data->buffer+frame_offset,0,
|
||||
AHX_EXPECTED_FRAME_SIZE-frame_offset);
|
||||
|
||||
data->buffer_full = 1;
|
||||
data->buffer_used = 0;
|
||||
|
||||
stream->offset += frame_offset;
|
||||
}
|
||||
|
||||
if (!data->buffer_used) {
|
||||
rc = mpg123_decode(data->m,
|
||||
data->buffer,AHX_EXPECTED_FRAME_SIZE,
|
||||
(unsigned char *)(outbuf+samples_done),
|
||||
(samples_to_do-samples_done)*sizeof(sample),
|
||||
&bytes_done);
|
||||
data->buffer_used = 1;
|
||||
} else {
|
||||
rc = mpg123_decode(data->m,
|
||||
NULL,0,
|
||||
(unsigned char *)(outbuf+samples_done),
|
||||
(samples_to_do-samples_done)*sizeof(sample),
|
||||
&bytes_done);
|
||||
}
|
||||
|
||||
if (rc == MPG123_NEED_MORE) data->buffer_full = 0;
|
||||
|
||||
samples_done += bytes_done/sizeof(sample);
|
||||
}
|
||||
}
|
||||
|
||||
mpeg_codec_data *init_mpeg_codec_data(STREAMFILE *streamfile, off_t start_offset, long given_sample_rate, int given_channels, coding_t *coding_type, int * actual_sample_rate, int * actual_channels) {
|
||||
int rc;
|
||||
off_t read_offset;
|
||||
mpeg_codec_data *data = NULL;
|
||||
|
||||
data = calloc(1,sizeof(mpeg_codec_data));
|
||||
if (!data) goto mpeg_fail;
|
||||
|
||||
data->m = mpg123_new(NULL,&rc);
|
||||
if (rc==MPG123_NOT_INITIALIZED) {
|
||||
if (mpg123_init()!=MPG123_OK) goto mpeg_fail;
|
||||
data->m = mpg123_new(NULL,&rc);
|
||||
if (rc!=MPG123_OK) goto mpeg_fail;
|
||||
} else if (rc!=MPG123_OK) {
|
||||
goto mpeg_fail;
|
||||
}
|
||||
|
||||
mpg123_param(data->m,MPG123_REMOVE_FLAGS,MPG123_GAPLESS,0.0);
|
||||
|
||||
if (mpg123_open_feed(data->m)!=MPG123_OK) {
|
||||
goto mpeg_fail;
|
||||
}
|
||||
|
||||
/* check format */
|
||||
read_offset=0;
|
||||
do {
|
||||
size_t bytes_done;
|
||||
if (read_streamfile(data->buffer, start_offset+read_offset,
|
||||
MPEG_BUFFER_SIZE,streamfile) !=
|
||||
MPEG_BUFFER_SIZE) goto mpeg_fail;
|
||||
read_offset+=1;
|
||||
rc = mpg123_decode(data->m,data->buffer,MPEG_BUFFER_SIZE,
|
||||
NULL,0,&bytes_done);
|
||||
if (rc != MPG123_OK && rc != MPG123_NEW_FORMAT &&
|
||||
rc != MPG123_NEED_MORE) goto mpeg_fail;
|
||||
} while (rc != MPG123_NEW_FORMAT);
|
||||
|
||||
{
|
||||
long rate;
|
||||
int channels,encoding;
|
||||
struct mpg123_frameinfo mi;
|
||||
rc = mpg123_getformat(data->m,&rate,&channels,&encoding);
|
||||
if (rc != MPG123_OK) goto mpeg_fail;
|
||||
//fprintf(stderr,"getformat ok, sr=%ld (%ld) ch=%d (%d) enc=%d (%d)\n",rate,given_sample_rate,channels,vgmstream->channels,encoding,MPG123_ENC_SIGNED_16);
|
||||
if ((given_sample_rate != -1 && rate != given_sample_rate) ||
|
||||
(given_channels != -1 && channels != given_channels) ||
|
||||
encoding != MPG123_ENC_SIGNED_16) goto mpeg_fail;
|
||||
mpg123_info(data->m,&mi);
|
||||
if (given_sample_rate != -1 &&
|
||||
mi.rate != given_sample_rate) goto mpeg_fail;
|
||||
|
||||
//fprintf(stderr,"mi.version=%d, mi.layer=%d\n",mi.version,mi.layer);
|
||||
|
||||
if (mi.version == MPG123_1_0 && mi.layer == 1)
|
||||
*coding_type = coding_MPEG1_L1;
|
||||
else if (mi.version == MPG123_1_0 && mi.layer == 2)
|
||||
*coding_type = coding_MPEG1_L2;
|
||||
else if (mi.version == MPG123_1_0 && mi.layer == 3)
|
||||
*coding_type = coding_MPEG1_L3;
|
||||
else if (mi.version == MPG123_2_0 && mi.layer == 1)
|
||||
*coding_type = coding_MPEG2_L1;
|
||||
else if (mi.version == MPG123_2_0 && mi.layer == 2)
|
||||
*coding_type = coding_MPEG2_L2;
|
||||
else if (mi.version == MPG123_2_0 && mi.layer == 3)
|
||||
*coding_type = coding_MPEG2_L3;
|
||||
else if (mi.version == MPG123_2_5 && mi.layer == 1)
|
||||
*coding_type = coding_MPEG25_L1;
|
||||
else if (mi.version == MPG123_2_5 && mi.layer == 2)
|
||||
*coding_type = coding_MPEG25_L2;
|
||||
else if (mi.version == MPG123_2_5 && mi.layer == 3)
|
||||
*coding_type = coding_MPEG25_L3;
|
||||
else goto mpeg_fail;
|
||||
|
||||
if ( actual_sample_rate ) *actual_sample_rate = rate;
|
||||
if ( actual_channels ) *actual_channels = channels;
|
||||
}
|
||||
|
||||
/* reinit, to ignore the reading we've done so far */
|
||||
mpg123_open_feed(data->m);
|
||||
|
||||
return data;
|
||||
|
||||
mpeg_fail:
|
||||
fprintf(stderr, "mpeg_fail start_offset=%x\n",(unsigned int)start_offset);
|
||||
if (data) {
|
||||
mpg123_delete(data->m);
|
||||
free(data);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* decode anything mpg123 can */
|
||||
void decode_mpeg(VGMSTREAMCHANNEL *stream,
|
||||
mpeg_codec_data * data,
|
||||
sample * outbuf, int32_t samples_to_do, int channels) {
|
||||
int samples_done = 0;
|
||||
|
||||
while (samples_done < samples_to_do) {
|
||||
size_t bytes_done;
|
||||
int rc;
|
||||
|
||||
if (!data->buffer_full) {
|
||||
data->bytes_in_buffer = read_streamfile(data->buffer,
|
||||
stream->offset,MPEG_BUFFER_SIZE,stream->streamfile);
|
||||
|
||||
if (!data->bytes_in_buffer) {
|
||||
memset(outbuf + samples_done * channels, 0, (samples_to_do - samples_done) * sizeof(sample));
|
||||
break;
|
||||
}
|
||||
|
||||
data->buffer_full = 1;
|
||||
data->buffer_used = 0;
|
||||
|
||||
stream->offset += data->bytes_in_buffer;
|
||||
}
|
||||
|
||||
if (!data->buffer_used) {
|
||||
rc = mpg123_decode(data->m,
|
||||
data->buffer,data->bytes_in_buffer,
|
||||
(unsigned char *)(outbuf+samples_done*channels),
|
||||
(samples_to_do-samples_done)*sizeof(sample)*channels,
|
||||
&bytes_done);
|
||||
data->buffer_used = 1;
|
||||
} else {
|
||||
rc = mpg123_decode(data->m,
|
||||
NULL,0,
|
||||
(unsigned char *)(outbuf+samples_done*channels),
|
||||
(samples_to_do-samples_done)*sizeof(sample)*channels,
|
||||
&bytes_done);
|
||||
}
|
||||
|
||||
if (rc == MPG123_NEED_MORE) data->buffer_full = 0;
|
||||
|
||||
samples_done += bytes_done/sizeof(sample)/channels;
|
||||
}
|
||||
}
|
||||
|
||||
long mpeg_bytes_to_samples(long bytes, const struct mpg123_frameinfo *mi) {
|
||||
return (int64_t)bytes * mi->rate * 8 / (mi->bitrate * 1000);
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,163 @@
|
|||
#include "../util.h"
|
||||
#include "coding.h"
|
||||
|
||||
/* used to compute next scale */
|
||||
static const int ADPCMTable[16] =
|
||||
{
|
||||
230, 230, 230, 230,
|
||||
307, 409, 512, 614,
|
||||
768, 614, 512, 409,
|
||||
307, 230, 230, 230
|
||||
};
|
||||
|
||||
static const int ADPCMCoeffs[7][2] =
|
||||
{
|
||||
{ 256, 0 },
|
||||
{ 512, -256 },
|
||||
{ 0, 0 },
|
||||
{ 192, 64 },
|
||||
{ 240, 0 },
|
||||
{ 460, -208 },
|
||||
{ 392, -232 }
|
||||
};
|
||||
|
||||
long msadpcm_bytes_to_samples(long bytes, int block_size, int channels) {
|
||||
return bytes/block_size*((block_size-(7-1)*channels)*2/channels);
|
||||
}
|
||||
|
||||
void decode_msadpcm_stereo(VGMSTREAM * vgmstream, sample * outbuf, int32_t first_sample, int32_t samples_to_do) {
|
||||
VGMSTREAMCHANNEL *ch1,*ch2;
|
||||
int i;
|
||||
int framesin;
|
||||
STREAMFILE *streamfile;
|
||||
off_t offset;
|
||||
|
||||
framesin = first_sample/get_vgmstream_samples_per_frame(vgmstream);
|
||||
first_sample = first_sample%get_vgmstream_samples_per_frame(vgmstream);
|
||||
|
||||
ch1 = &vgmstream->ch[0];
|
||||
ch2 = &vgmstream->ch[1];
|
||||
streamfile = ch1->streamfile;
|
||||
offset = ch1->offset+framesin*get_vgmstream_frame_size(vgmstream);
|
||||
|
||||
if (first_sample==0) {
|
||||
ch1->adpcm_coef[0] = ADPCMCoeffs[read_8bit(offset,streamfile)][0];
|
||||
ch1->adpcm_coef[1] = ADPCMCoeffs[read_8bit(offset,streamfile)][1];
|
||||
ch2->adpcm_coef[0] = ADPCMCoeffs[read_8bit(offset+1,streamfile)][0];
|
||||
ch2->adpcm_coef[1] = ADPCMCoeffs[read_8bit(offset+1,streamfile)][1];
|
||||
ch1->adpcm_scale = read_16bitLE(offset+2,streamfile);
|
||||
ch2->adpcm_scale = read_16bitLE(offset+4,streamfile);
|
||||
ch1->adpcm_history1_16 = read_16bitLE(offset+6,streamfile);
|
||||
ch2->adpcm_history1_16 = read_16bitLE(offset+8,streamfile);
|
||||
ch1->adpcm_history2_16 = read_16bitLE(offset+10,streamfile);
|
||||
ch2->adpcm_history2_16 = read_16bitLE(offset+12,streamfile);
|
||||
|
||||
outbuf[0] = ch1->adpcm_history2_16;
|
||||
outbuf[1] = ch2->adpcm_history2_16;
|
||||
|
||||
outbuf+=2;
|
||||
first_sample++;
|
||||
samples_to_do--;
|
||||
}
|
||||
if (first_sample==1 && samples_to_do > 0) {
|
||||
outbuf[0] = ch1->adpcm_history1_16;
|
||||
outbuf[1] = ch2->adpcm_history1_16;
|
||||
|
||||
outbuf+=2;
|
||||
first_sample++;
|
||||
samples_to_do--;
|
||||
}
|
||||
|
||||
for (i=first_sample; i<first_sample+samples_to_do; i++) {
|
||||
int j;
|
||||
|
||||
for (j=0;j<2;j++)
|
||||
{
|
||||
VGMSTREAMCHANNEL *ch = &vgmstream->ch[j];
|
||||
int sample_nibble =
|
||||
(j == 0 ?
|
||||
get_high_nibble_signed(read_8bit(offset+14+i-2,streamfile)) :
|
||||
get_low_nibble_signed(read_8bit(offset+14+i-2,streamfile))
|
||||
);
|
||||
int32_t hist1,hist2;
|
||||
int32_t predicted;
|
||||
|
||||
hist1 = ch->adpcm_history1_16;
|
||||
hist2 = ch->adpcm_history2_16;
|
||||
predicted = hist1 * ch->adpcm_coef[0] + hist2 * ch->adpcm_coef[1];
|
||||
predicted /= 256;
|
||||
predicted += sample_nibble*ch->adpcm_scale;
|
||||
outbuf[0] = clamp16(predicted);
|
||||
ch->adpcm_history2_16 = ch->adpcm_history1_16;
|
||||
ch->adpcm_history1_16 = outbuf[0];
|
||||
ch->adpcm_scale = (ADPCMTable[sample_nibble&0xf] *
|
||||
ch->adpcm_scale) / 256;
|
||||
if (ch->adpcm_scale < 0x10) ch->adpcm_scale = 0x10;
|
||||
|
||||
outbuf++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void decode_msadpcm_mono(VGMSTREAM * vgmstream, sample * outbuf, int32_t first_sample, int32_t samples_to_do) {
|
||||
VGMSTREAMCHANNEL *ch1;
|
||||
int i;
|
||||
int framesin;
|
||||
STREAMFILE *streamfile;
|
||||
off_t offset;
|
||||
|
||||
framesin = first_sample/get_vgmstream_samples_per_frame(vgmstream);
|
||||
first_sample = first_sample%get_vgmstream_samples_per_frame(vgmstream);
|
||||
|
||||
ch1 = &vgmstream->ch[0];
|
||||
streamfile = ch1->streamfile;
|
||||
offset = ch1->offset+framesin*get_vgmstream_frame_size(vgmstream);
|
||||
|
||||
if (first_sample==0) {
|
||||
ch1->adpcm_coef[0] = ADPCMCoeffs[read_8bit(offset,streamfile)][0];
|
||||
ch1->adpcm_coef[1] = ADPCMCoeffs[read_8bit(offset,streamfile)][1];
|
||||
ch1->adpcm_scale = read_16bitLE(offset+1,streamfile);
|
||||
ch1->adpcm_history1_16 = read_16bitLE(offset+3,streamfile);
|
||||
ch1->adpcm_history2_16 = read_16bitLE(offset+5,streamfile);
|
||||
|
||||
outbuf[0] = ch1->adpcm_history2_16;
|
||||
|
||||
outbuf++;
|
||||
first_sample++;
|
||||
samples_to_do--;
|
||||
}
|
||||
if (first_sample==1 && samples_to_do > 0) {
|
||||
outbuf[0] = ch1->adpcm_history1_16;
|
||||
|
||||
outbuf++;
|
||||
first_sample++;
|
||||
samples_to_do--;
|
||||
}
|
||||
|
||||
for (i=first_sample; i<first_sample+samples_to_do; i++) {
|
||||
{
|
||||
VGMSTREAMCHANNEL *ch = &vgmstream->ch[0];
|
||||
int sample_nibble =
|
||||
(i & 1 ?
|
||||
get_low_nibble_signed(read_8bit(offset+7+(i-2)/2,streamfile)) :
|
||||
get_high_nibble_signed(read_8bit(offset+7+(i-2)/2,streamfile))
|
||||
);
|
||||
int32_t hist1,hist2;
|
||||
int32_t predicted;
|
||||
|
||||
hist1 = ch->adpcm_history1_16;
|
||||
hist2 = ch->adpcm_history2_16;
|
||||
predicted = hist1 * ch->adpcm_coef[0] + hist2 * ch->adpcm_coef[1];
|
||||
predicted /= 256;
|
||||
predicted += sample_nibble*ch->adpcm_scale;
|
||||
outbuf[0] = clamp16(predicted);
|
||||
ch->adpcm_history2_16 = ch->adpcm_history1_16;
|
||||
ch->adpcm_history1_16 = outbuf[0];
|
||||
ch->adpcm_scale = (ADPCMTable[sample_nibble&0xf] *
|
||||
ch->adpcm_scale) / 256;
|
||||
if (ch->adpcm_scale < 0x10) ch->adpcm_scale = 0x10;
|
||||
|
||||
outbuf++;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,154 @@
|
|||
//#include <stdlib.h>
|
||||
//#include <stdio.h>
|
||||
#include "coding.h"
|
||||
#include "../util.h"
|
||||
|
||||
// A hybrid of IMA and Yamaha ADPCM found in Metal Gear Solid 3
|
||||
// Thanks to X_Tra (http://metalgear.in/) for pointing me to the step size table.
|
||||
|
||||
int index_table[16] = {
|
||||
-1, -1, -1, -1, 2, 4, 6, 8,
|
||||
-1, -1, -1, -1, 2, 4, 6, 8
|
||||
};
|
||||
|
||||
static int16_t step_size[32][16] = {
|
||||
{ 1, 5, 9, 13, 16, 20, 24, 28,
|
||||
-1, -5, -9, -13, -16, -20, -24, -28, },
|
||||
{ 2, 6, 11, 15, 20, 24, 29, 33,
|
||||
-2, -6, -11, -15, -20, -24, -29, -33, },
|
||||
{ 2, 7, 13, 18, 23, 28, 34, 39,
|
||||
-2, -7, -13, -18, -23, -28, -34, -39, },
|
||||
{ 3, 9, 15, 21, 28, 34, 40, 46,
|
||||
-3, -9, -15, -21, -28, -34, -40, -46, },
|
||||
{ 3, 11, 18, 26, 33, 41, 48, 56,
|
||||
-3, -11, -18, -26, -33, -41, -48, -56, },
|
||||
{ 4, 13, 22, 31, 40, 49, 58, 67,
|
||||
-4, -13, -22, -31, -40, -49, -58, -67, },
|
||||
{ 5, 16, 26, 37, 48, 59, 69, 80,
|
||||
-5, -16, -26, -37, -48, -59, -69, -80, },
|
||||
{ 6, 19, 31, 44, 57, 70, 82, 95,
|
||||
-6, -19, -31, -44, -57, -70, -82, -95, },
|
||||
{ 7, 22, 38, 53, 68, 83, 99, 114,
|
||||
-7, -22, -38, -53, -68, -83, -99, -114, },
|
||||
{ 9, 27, 45, 63, 81, 99, 117, 135,
|
||||
-9, -27, -45, -63, -81, -99, -117, -135, },
|
||||
{ 10, 32, 53, 75, 96, 118, 139, 161,
|
||||
-10, -32, -53, -75, -96, -118, -139, -161, },
|
||||
{ 12, 38, 64, 90, 115, 141, 167, 193,
|
||||
-12, -38, -64, -90, -115, -141, -167, -193, },
|
||||
{ 15, 45, 76, 106, 137, 167, 198, 228,
|
||||
-15, -45, -76, -106, -137, -167, -198, -228, },
|
||||
{ 18, 54, 91, 127, 164, 200, 237, 273,
|
||||
-18, -54, -91, -127, -164, -200, -237, -273, },
|
||||
{ 21, 65, 108, 152, 195, 239, 282, 326,
|
||||
-21, -65, -108, -152, -195, -239, -282, -326, },
|
||||
{ 25, 77, 129, 181, 232, 284, 336, 388,
|
||||
-25, -77, -129, -181, -232, -284, -336, -388, },
|
||||
{ 30, 92, 153, 215, 276, 338, 399, 461,
|
||||
-30, -92, -153, -215, -276, -338, -399, -461, },
|
||||
{ 36, 109, 183, 256, 329, 402, 476, 549,
|
||||
-36, -109, -183, -256, -329, -402, -476, -549, },
|
||||
{ 43, 130, 218, 305, 392, 479, 567, 654,
|
||||
-43, -130, -218, -305, -392, -479, -567, -654, },
|
||||
{ 52, 156, 260, 364, 468, 572, 676, 780,
|
||||
-52, -156, -260, -364, -468, -572, -676, -780, },
|
||||
{ 62, 186, 310, 434, 558, 682, 806, 930,
|
||||
-62, -186, -310, -434, -558, -682, -806, -930, },
|
||||
{ 73, 221, 368, 516, 663, 811, 958, 1106,
|
||||
-73, -221, -368, -516, -663, -811, -958, -1106, },
|
||||
{ 87, 263, 439, 615, 790, 966, 1142, 1318,
|
||||
-87, -263, -439, -615, -790, -966, -1142, -1318, },
|
||||
{ 104, 314, 523, 733, 942, 1152, 1361, 1571,
|
||||
-104, -314, -523, -733, -942, -1152, -1361, -1571, },
|
||||
{ 124, 374, 623, 873, 1122, 1372, 1621, 1871,
|
||||
-124, -374, -623, -873, -1122, -1372, -1621, -1871, },
|
||||
{ 148, 445, 743, 1040, 1337, 1634, 1932, 2229,
|
||||
-148, -445, -743, -1040, -1337, -1634, -1932, -2229, },
|
||||
{ 177, 531, 885, 1239, 1593, 1947, 2301, 2655,
|
||||
-177, -531, -885, -1239, -1593, -1947, -2301, -2655, },
|
||||
{ 210, 632, 1053, 1475, 1896, 2318, 2739, 3161,
|
||||
-210, -632, -1053, -1475, -1896, -2318, -2739, -3161, },
|
||||
{ 251, 753, 1255, 1757, 2260, 2762, 3264, 3766,
|
||||
-251, -753, -1255, -1757, -2260, -2762, -3264, -3766, },
|
||||
{ 299, 897, 1495, 2093, 2692, 3290, 3888, 4486,
|
||||
-299, -897, -1495, -2093, -2692, -3290, -3888, -4486, },
|
||||
{ 356, 1068, 1781, 2493, 3206, 3918, 4631, 5343,
|
||||
-356, -1068, -1781, -2493, -3206, -3918, -4631, -5343, },
|
||||
{ 424, 1273, 2121, 2970, 3819, 4668, 5516, 6365,
|
||||
-424, -1273, -2121, -2970, -3819, -4668, -5516, -6365, },
|
||||
};
|
||||
|
||||
|
||||
void decode_mtaf(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, int channels) {
|
||||
int32_t sample_count;
|
||||
int framesin = first_sample / 0x100;
|
||||
unsigned long cur_off = stream->offset + framesin*(0x10+0x80*2)*(channels/2);
|
||||
int i;
|
||||
int c = channel%2;
|
||||
int16_t init_idx = read_16bitLE(cur_off+4+c*2, stream->streamfile);
|
||||
int16_t init_hist = read_16bitLE(cur_off+8+c*4, stream->streamfile);
|
||||
int32_t hist = stream->adpcm_history1_16;
|
||||
int step_idx = stream->adpcm_step_index;
|
||||
|
||||
//printf("channel %d: first_sample = %d, stream->offset = 0x%lx, cur_off = 0x%lx init_idx = %d\n", channel, first_sample, (unsigned long)stream->offset, cur_off, init_idx);
|
||||
|
||||
#if 0
|
||||
if (init_idx < 0 || init_idx > 31) {
|
||||
fprintf(stderr, "step idx out of range at 0x%lx ch %d\n", cur_off, c);
|
||||
exit(1);
|
||||
}
|
||||
if (0 != read_16bitLE(cur_off+10+c*4, stream->streamfile)) {
|
||||
fprintf(stderr, "exp. zero after hist at 0x%lx ch %d\n", cur_off, c);
|
||||
exit(1);
|
||||
}
|
||||
#endif
|
||||
|
||||
first_sample = first_sample%0x100;
|
||||
|
||||
if (first_sample%0x100 == 0) {
|
||||
hist = init_hist;
|
||||
|
||||
#if 0
|
||||
if (step_idx != init_idx) {
|
||||
fprintf(stderr, "step_idx does not match at 0x%lx, %d!=%d\n",cur_off,step_idx, init_idx);
|
||||
exit(1);
|
||||
}
|
||||
#endif
|
||||
step_idx = init_idx;
|
||||
}
|
||||
|
||||
|
||||
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
|
||||
uint8_t byte, nibble;
|
||||
byte = read_8bit(cur_off + 0x10 + 0x80*c + i/2, stream->streamfile);
|
||||
if (i%2!=1)
|
||||
{
|
||||
// low nibble first
|
||||
nibble = byte&0xf;
|
||||
}
|
||||
else
|
||||
{
|
||||
// high nibble last
|
||||
nibble = byte >> 4;
|
||||
}
|
||||
|
||||
hist = clamp16(hist+step_size[step_idx][nibble]);
|
||||
|
||||
outbuf[sample_count] = hist;
|
||||
|
||||
step_idx += index_table[nibble];
|
||||
if (step_idx < 0)
|
||||
{
|
||||
step_idx = 0;
|
||||
}
|
||||
if (step_idx > 31)
|
||||
{
|
||||
step_idx = 31;
|
||||
}
|
||||
} /* end sample loop */
|
||||
|
||||
// update state
|
||||
stream->adpcm_step_index = step_idx;
|
||||
stream->adpcm_history1_16 = hist;
|
||||
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
#include "coding.h"
|
||||
#include "../util.h"
|
||||
|
||||
/* ADPCM found in NDS games using Procyon Studio Digital Sound Elements */
|
||||
|
||||
static const int8_t proc_coef[5][2] =
|
||||
{
|
||||
{0x00,0x00},
|
||||
{0x3C,0x00},
|
||||
{0x73,0xCC},
|
||||
{0x62,0xC9},
|
||||
{0x7A,0xC4},
|
||||
};
|
||||
|
||||
void decode_nds_procyon(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
int i=first_sample;
|
||||
int32_t sample_count;
|
||||
|
||||
int framesin = first_sample/30;
|
||||
|
||||
uint8_t header = read_8bit(framesin*16+15+stream->offset,stream->streamfile) ^ 0x80;
|
||||
int scale = 12 - (header & 0xf);
|
||||
int coef_index = (header >> 4) & 0xf;
|
||||
int32_t hist1 = stream->adpcm_history1_32;
|
||||
int32_t hist2 = stream->adpcm_history2_32;
|
||||
int32_t coef1;
|
||||
int32_t coef2;
|
||||
|
||||
if (coef_index > 4) coef_index = 0;
|
||||
coef1 = proc_coef[coef_index][0];
|
||||
coef2 = proc_coef[coef_index][1];
|
||||
first_sample = first_sample%30;
|
||||
|
||||
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
|
||||
int sample_byte = read_8bit(framesin*16+stream->offset+i/2,stream->streamfile) ^ 0x80;
|
||||
|
||||
int32_t sample =
|
||||
(int32_t)
|
||||
(i&1?
|
||||
get_high_nibble_signed(sample_byte):
|
||||
get_low_nibble_signed(sample_byte)
|
||||
) * 64 * 64;
|
||||
if (scale < 0)
|
||||
{
|
||||
sample <<= -scale;
|
||||
}
|
||||
else
|
||||
sample >>= scale;
|
||||
|
||||
sample = (hist1 * coef1 + hist2 * coef2 + 32) / 64 + (sample * 64);
|
||||
|
||||
hist2 = hist1;
|
||||
hist1 = sample;
|
||||
|
||||
outbuf[sample_count] = clamp16((sample + 32) / 64) / 64 * 64;
|
||||
}
|
||||
|
||||
stream->adpcm_history1_32 = hist1;
|
||||
stream->adpcm_history2_32 = hist2;
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
#include "coding.h"
|
||||
#include "../util.h"
|
||||
|
||||
const short afc_coef[16][2] =
|
||||
{{0,0},
|
||||
{0x0800,0},
|
||||
{0,0x0800},
|
||||
{0x0400,0x0400},
|
||||
{0x1000,0xf800},
|
||||
{0x0e00,0xfa00},
|
||||
{0x0c00,0xfc00},
|
||||
{0x1200,0xf600},
|
||||
{0x1068,0xf738},
|
||||
{0x12c0,0xf704},
|
||||
{0x1400,0xf400},
|
||||
{0x0800,0xf800},
|
||||
{0x0400,0xfc00},
|
||||
{0xfc00,0x0400},
|
||||
{0xfc00,0},
|
||||
{0xf800,0}};
|
||||
|
||||
void decode_ngc_afc(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
int i=first_sample;
|
||||
int32_t sample_count;
|
||||
|
||||
int framesin = first_sample/16;
|
||||
|
||||
int8_t header = read_8bit(framesin*9+stream->offset,stream->streamfile);
|
||||
int32_t scale = 1 << ((header>>4) & 0xf);
|
||||
int coef_index = (header & 0xf);
|
||||
int32_t hist1 = stream->adpcm_history1_16;
|
||||
int32_t hist2 = stream->adpcm_history2_16;
|
||||
int coef1 = afc_coef[coef_index][0];
|
||||
int coef2 = afc_coef[coef_index][1];
|
||||
/*printf("offset: %x\nscale: %d\nindex: %d (%lf,%lf)\nhist: %d %d\n",
|
||||
(unsigned)stream->offset,scale,coef_index,coef1/2048.0,coef2/2048.0,hist1,hist2);*/
|
||||
|
||||
first_sample = first_sample%16;
|
||||
|
||||
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
|
||||
int sample_byte = read_8bit(framesin*9+stream->offset+1+i/2,stream->streamfile);
|
||||
|
||||
outbuf[sample_count] = clamp16((
|
||||
(((i&1?
|
||||
get_low_nibble_signed(sample_byte):
|
||||
get_high_nibble_signed(sample_byte)
|
||||
) * scale)<<11) +
|
||||
(coef1 * hist1 + coef2 * hist2))>>11
|
||||
);
|
||||
/*printf("%hd\n",outbuf[sample_count]);*/
|
||||
|
||||
hist2 = hist1;
|
||||
hist1 = outbuf[sample_count];
|
||||
}
|
||||
|
||||
stream->adpcm_history1_16 = hist1;
|
||||
stream->adpcm_history2_16 = hist2;
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
#include "coding.h"
|
||||
#include "../util.h"
|
||||
|
||||
void decode_ngc_dsp(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
int i=first_sample;
|
||||
int32_t sample_count;
|
||||
|
||||
int framesin = first_sample/14;
|
||||
|
||||
int8_t header = read_8bit(framesin*8+stream->offset,stream->streamfile);
|
||||
int32_t scale = 1 << (header & 0xf);
|
||||
int coef_index = (header >> 4) & 0xf;
|
||||
int32_t hist1 = stream->adpcm_history1_16;
|
||||
int32_t hist2 = stream->adpcm_history2_16;
|
||||
int coef1 = stream->adpcm_coef[coef_index*2];
|
||||
int coef2 = stream->adpcm_coef[coef_index*2+1];
|
||||
|
||||
first_sample = first_sample%14;
|
||||
|
||||
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
|
||||
int sample_byte = read_8bit(framesin*8+stream->offset+1+i/2,stream->streamfile);
|
||||
|
||||
#ifdef DEBUG
|
||||
if (hist1==stream->loop_history1 && hist2==stream->loop_history2) fprintf(stderr,"yo! %#x (start %#x) %d\n",stream->offset+framesin*8+i/2,stream->channel_start_offset,stream->samples_done);
|
||||
stream->samples_done++;
|
||||
#endif
|
||||
|
||||
outbuf[sample_count] = clamp16((
|
||||
(((i&1?
|
||||
get_low_nibble_signed(sample_byte):
|
||||
get_high_nibble_signed(sample_byte)
|
||||
) * scale)<<11) + 1024 +
|
||||
(coef1 * hist1 + coef2 * hist2))>>11
|
||||
);
|
||||
|
||||
hist2 = hist1;
|
||||
hist1 = outbuf[sample_count];
|
||||
}
|
||||
|
||||
stream->adpcm_history1_16 = hist1;
|
||||
stream->adpcm_history2_16 = hist2;
|
||||
}
|
||||
|
||||
/* read from memory rather than a file */
|
||||
void decode_ngc_dsp_mem(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, uint8_t * mem) {
|
||||
int i=first_sample;
|
||||
int32_t sample_count;
|
||||
|
||||
int framesin = first_sample/14;
|
||||
|
||||
int8_t header = mem[framesin*8];
|
||||
int32_t scale = 1 << (header & 0xf);
|
||||
int coef_index = (header >> 4) & 0xf;
|
||||
int32_t hist1 = stream->adpcm_history1_16;
|
||||
int32_t hist2 = stream->adpcm_history2_16;
|
||||
int coef1 = stream->adpcm_coef[coef_index*2];
|
||||
int coef2 = stream->adpcm_coef[coef_index*2+1];
|
||||
|
||||
first_sample = first_sample%14;
|
||||
|
||||
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
|
||||
int sample_byte = mem[framesin*8+1+i/2];
|
||||
|
||||
#ifdef DEBUG
|
||||
if (hist1==stream->loop_history1 && hist2==stream->loop_history2) fprintf(stderr,"yo! %#x (start %#x) %d\n",stream->offset+framesin*8+i/2,stream->channel_start_offset,stream->samples_done);
|
||||
stream->samples_done++;
|
||||
#endif
|
||||
|
||||
outbuf[sample_count] = clamp16((
|
||||
(((i&1?
|
||||
get_low_nibble_signed(sample_byte):
|
||||
get_high_nibble_signed(sample_byte)
|
||||
) * scale)<<11) + 1024 +
|
||||
(coef1 * hist1 + coef2 * hist2))>>11
|
||||
);
|
||||
|
||||
hist2 = hist1;
|
||||
hist1 = outbuf[sample_count];
|
||||
}
|
||||
|
||||
stream->adpcm_history1_16 = hist1;
|
||||
stream->adpcm_history2_16 = hist2;
|
||||
}
|
||||
|
||||
/*
|
||||
* The original DSP spec uses nibble counts for loop points, and some
|
||||
* variants don't have a proper sample count, so we (who are interested
|
||||
* in sample counts) need to do this conversion occasionally.
|
||||
*/
|
||||
int32_t dsp_nibbles_to_samples(int32_t nibbles) {
|
||||
int32_t whole_frames = nibbles/16;
|
||||
int32_t remainder = nibbles%16;
|
||||
|
||||
/*
|
||||
fprintf(stderr,"%d (%#x) nibbles => %x bytes and %d samples\n",nibbles,nibbles,whole_frames*8,remainder);
|
||||
*/
|
||||
|
||||
#if 0
|
||||
if (remainder > 0 && remainder < 14)
|
||||
return whole_frames*14 + remainder;
|
||||
else if (remainder >= 14)
|
||||
fprintf(stderr,"***** last frame %d leftover nibbles makes no sense\n",remainder);
|
||||
#endif
|
||||
if (remainder>0) return whole_frames*14+remainder-2;
|
||||
else return whole_frames*14;
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
#include "coding.h"
|
||||
#include "../util.h"
|
||||
|
||||
void decode_ngc_dtk(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
|
||||
int i=first_sample;
|
||||
int32_t sample_count;
|
||||
|
||||
int framesin = first_sample/28;
|
||||
|
||||
uint8_t q = read_8bit(framesin*32+stream->offset+channel,stream->streamfile);
|
||||
int32_t hist1 = stream->adpcm_history1_32;
|
||||
int32_t hist2 = stream->adpcm_history2_32;
|
||||
|
||||
first_sample = first_sample%28;
|
||||
|
||||
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
|
||||
int sample_byte = read_8bit(framesin*32+stream->offset+4+i,stream->streamfile);
|
||||
|
||||
int32_t hist=0;
|
||||
|
||||
switch (q>>4)
|
||||
{
|
||||
case 0:
|
||||
hist = 0;
|
||||
break;
|
||||
case 1:
|
||||
hist = (hist1 * 0x3c);
|
||||
break;
|
||||
case 2:
|
||||
hist = (hist1 * 0x73) - (hist2 * 0x34);
|
||||
break;
|
||||
case 3:
|
||||
hist = (hist1 * 0x62) - (hist2 * 0x37);
|
||||
break;
|
||||
}
|
||||
|
||||
hist = (hist+0x20)>>6;
|
||||
if (hist > 0x1fffff) hist = 0x1fffff;
|
||||
if (hist < -0x200000) hist = -0x200000;
|
||||
|
||||
hist2 = hist1;
|
||||
|
||||
hist1 = ((((channel==0?
|
||||
get_low_nibble_signed(sample_byte):
|
||||
get_high_nibble_signed(sample_byte)
|
||||
) << 12) >> (q & 0xf)) << 6) + hist;
|
||||
|
||||
outbuf[sample_count] = clamp16(hist1 >> 6);
|
||||
}
|
||||
|
||||
stream->adpcm_history1_32 = hist1;
|
||||
stream->adpcm_history2_32 = hist2;
|
||||
}
|
|
@ -0,0 +1,351 @@
|
|||
/* originally from nwatowav.cc 2007.7.28 version, which read: */
|
||||
/*
|
||||
* Copyright 2001-2007 jagarl / Kazunori Ueno <jagarl@creator.club.ne.jp>
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted.
|
||||
*
|
||||
* このプログラムの作者は jagarl です。
|
||||
*
|
||||
* このプログラム、及びコンパイルによって生成したバイナリは
|
||||
* プログラムを変更する、しないにかかわらず再配布可能です。
|
||||
* その際、上記 Copyright 表示を保持するなどの条件は課しま
|
||||
* せん。対応が面倒なのでバグ報告を除き、メールで連絡をする
|
||||
* などの必要もありません。ソースの一部を流用することを含め、
|
||||
* ご自由にお使いください。
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY KAZUNORI 'jagarl' UENO ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KAZUNORI UENO BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "nwa_decoder.h"
|
||||
|
||||
/* can serve up 8 bits at a time */
|
||||
static int
|
||||
getbits (STREAMFILE *file, off_t *offset, int *shift, int bits)
|
||||
{
|
||||
int ret;
|
||||
if (*shift > 8)
|
||||
{
|
||||
++*offset;
|
||||
*shift -= 8;
|
||||
}
|
||||
ret = read_16bitLE(*offset,file) >> *shift;
|
||||
*shift += bits;
|
||||
return ret & ((1 << bits) - 1); /* mask */
|
||||
}
|
||||
|
||||
NWAData *
|
||||
open_nwa (STREAMFILE * streamFile, const char *filename)
|
||||
{
|
||||
int i;
|
||||
NWAData * const nwa = malloc(sizeof(NWAData));
|
||||
if (!nwa) goto fail;
|
||||
|
||||
nwa->channels = read_16bitLE(0x00,streamFile);
|
||||
nwa->bps = read_16bitLE(0x02,streamFile);
|
||||
nwa->freq = read_32bitLE(0x04,streamFile);
|
||||
nwa->complevel = read_32bitLE(0x08,streamFile);
|
||||
nwa->blocks = read_32bitLE(0x10,streamFile);
|
||||
nwa->datasize = read_32bitLE(0x14,streamFile);
|
||||
nwa->compdatasize = read_32bitLE(0x18,streamFile);
|
||||
nwa->samplecount = read_32bitLE(0x1c,streamFile);
|
||||
nwa->blocksize = read_32bitLE(0x20,streamFile);
|
||||
nwa->restsize = read_32bitLE(0x24,streamFile);
|
||||
nwa->offsets = NULL;
|
||||
nwa->buffer = NULL;
|
||||
nwa->buffer_readpos = NULL;
|
||||
nwa->file = NULL;
|
||||
|
||||
/* PCM not handled here */
|
||||
if (nwa->complevel < 0 || nwa->complevel > 5) goto fail;
|
||||
|
||||
if (nwa->channels != 1 && nwa->channels != 2) goto fail;
|
||||
|
||||
if (nwa->bps != 8 && nwa->bps != 16) goto fail;
|
||||
|
||||
if (nwa->blocks <= 0) goto fail;
|
||||
|
||||
if (nwa->compdatasize == 0
|
||||
|| get_streamfile_size(streamFile) != nwa->compdatasize) goto fail;
|
||||
|
||||
if (nwa->datasize != nwa->samplecount * (nwa->bps/8)) goto fail;
|
||||
|
||||
if (nwa->samplecount !=
|
||||
(nwa->blocks-1) * nwa->blocksize + nwa->restsize) goto fail;
|
||||
|
||||
nwa->offsets = malloc(sizeof(off_t)*nwa->blocks);
|
||||
if (!nwa->offsets) goto fail;
|
||||
|
||||
for (i = 0; i < nwa->blocks; i++)
|
||||
{
|
||||
int32_t o = read_32bitLE(0x2c+i*4,streamFile);
|
||||
if (o < 0) goto fail;
|
||||
nwa->offsets[i] = o;
|
||||
}
|
||||
|
||||
if (nwa->offsets[nwa->blocks-1] >= nwa->compdatasize) goto fail;
|
||||
|
||||
if (nwa->restsize > nwa->blocksize) nwa->buffer =
|
||||
malloc(sizeof(sample)*nwa->restsize);
|
||||
else nwa->buffer =
|
||||
malloc(sizeof(sample)*nwa->blocksize);
|
||||
if (nwa->buffer == NULL) goto fail;
|
||||
|
||||
nwa->buffer_readpos = nwa->buffer;
|
||||
|
||||
nwa->samples_in_buffer = 0;
|
||||
|
||||
nwa->curblock = 0;
|
||||
|
||||
/* if we got this far, it's probably safe */
|
||||
nwa->file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
if (!nwa->file) goto fail;
|
||||
|
||||
return nwa;
|
||||
fail:
|
||||
if (nwa)
|
||||
{
|
||||
close_nwa(nwa);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
close_nwa(NWAData * nwa)
|
||||
{
|
||||
if (!nwa) return;
|
||||
|
||||
if (nwa->offsets)
|
||||
free (nwa->offsets);
|
||||
nwa->offsets = NULL;
|
||||
if (nwa->buffer)
|
||||
free (nwa->buffer);
|
||||
nwa->buffer = NULL;
|
||||
if (nwa->file)
|
||||
close_streamfile (nwa->file);
|
||||
nwa->file = NULL;
|
||||
free(nwa);
|
||||
}
|
||||
|
||||
void
|
||||
reset_nwa(NWAData *nwa)
|
||||
{
|
||||
nwa->curblock = 0;
|
||||
nwa->buffer_readpos = nwa->buffer;
|
||||
nwa->samples_in_buffer = 0;
|
||||
}
|
||||
|
||||
static int use_runlength(NWAData *nwa)
|
||||
{
|
||||
if (nwa->channels == 2 && nwa->bps == 16 && nwa->complevel == 2)
|
||||
{
|
||||
/* sw2 */
|
||||
return 0;
|
||||
}
|
||||
if (nwa->complevel == 5)
|
||||
{
|
||||
if (nwa->channels == 2) return 0; /* BGM*.nwa in Little Busters! */
|
||||
return 1; /* Tomoyo After (.nwk koe file) */
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
nwa_decode_block(NWAData *nwa)
|
||||
{
|
||||
/* 今回読み込む/デコードするデータの大きさを得る */
|
||||
int curblocksize, curcompsize;
|
||||
if (nwa->curblock != nwa->blocks - 1)
|
||||
{
|
||||
curblocksize = nwa->blocksize * (nwa->bps / 8);
|
||||
curcompsize = nwa->offsets[nwa->curblock + 1] - nwa->offsets[nwa->curblock];
|
||||
}
|
||||
else
|
||||
{
|
||||
curblocksize = nwa->restsize * (nwa->bps / 8);
|
||||
curcompsize = nwa->blocksize * (nwa->bps / 8) * 2;
|
||||
}
|
||||
|
||||
nwa->samples_in_buffer = 0;
|
||||
nwa->buffer_readpos = nwa->buffer;
|
||||
|
||||
{
|
||||
sample d[2];
|
||||
int i;
|
||||
int shift = 0;
|
||||
off_t offset = nwa->offsets[nwa->curblock];
|
||||
int dsize = curblocksize / (nwa->bps / 8);
|
||||
int flip_flag = 0; /* stereo 用 */
|
||||
int runlength = 0;
|
||||
|
||||
/* read initial sample value */
|
||||
for (i=0;i<nwa->channels;i++)
|
||||
{
|
||||
if (nwa->bps == 8) { d[i] = read_8bit(offset,nwa->file); }
|
||||
else /* bps == 16 */
|
||||
{
|
||||
d[i] = read_16bitLE(offset,nwa->file);
|
||||
offset += 2;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < dsize; i++)
|
||||
{
|
||||
if (runlength == 0)
|
||||
{ /* コピーループ中でないならデータ読み込み */
|
||||
int type = getbits(nwa->file, &offset, &shift, 3);
|
||||
/* type により分岐:0, 1-6, 7 */
|
||||
if (type == 7)
|
||||
{
|
||||
/* 7 : 大きな差分 */
|
||||
/* RunLength() 有効時(CompLevel==5, 音声ファイル) では無効 */
|
||||
if (getbits(nwa->file, &offset, &shift, 1) == 1)
|
||||
{
|
||||
d[flip_flag] = 0; /* 未使用 */
|
||||
}
|
||||
else
|
||||
{
|
||||
int BITS, SHIFT;
|
||||
if (nwa->complevel >= 3)
|
||||
{
|
||||
BITS = 8;
|
||||
SHIFT = 9;
|
||||
}
|
||||
else
|
||||
{
|
||||
BITS = 8 - nwa->complevel;
|
||||
SHIFT = 2 + 7 + nwa->complevel;
|
||||
}
|
||||
{
|
||||
const int MASK1 = (1 << (BITS - 1));
|
||||
const int MASK2 = (1 << (BITS - 1)) - 1;
|
||||
int b = getbits(nwa->file, &offset, &shift, BITS);
|
||||
if (b & MASK1)
|
||||
d[flip_flag] -= (b & MASK2) << SHIFT;
|
||||
else
|
||||
d[flip_flag] += (b & MASK2) << SHIFT;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (type != 0)
|
||||
{
|
||||
/* 1-6 : 通常の差分 */
|
||||
int BITS, SHIFT;
|
||||
if (nwa->complevel >= 3)
|
||||
{
|
||||
BITS = nwa->complevel + 3;
|
||||
SHIFT = 1 + type;
|
||||
}
|
||||
else
|
||||
{
|
||||
BITS = 5 - nwa->complevel;
|
||||
SHIFT = 2 + type + nwa->complevel;
|
||||
}
|
||||
{
|
||||
const int MASK1 = (1 << (BITS - 1));
|
||||
const int MASK2 = (1 << (BITS - 1)) - 1;
|
||||
int b = getbits(nwa->file, &offset, &shift, BITS);
|
||||
if (b & MASK1)
|
||||
d[flip_flag] -= (b & MASK2) << SHIFT;
|
||||
else
|
||||
d[flip_flag] += (b & MASK2) << SHIFT;
|
||||
}
|
||||
}
|
||||
else
|
||||
{ /* type == 0 */
|
||||
/* ランレングス圧縮なしの場合はなにもしない */
|
||||
if (use_runlength(nwa))
|
||||
{
|
||||
/* ランレングス圧縮ありの場合 */
|
||||
runlength = getbits(nwa->file, &offset, &shift, 1);
|
||||
if (runlength == 1)
|
||||
{
|
||||
runlength = getbits(nwa->file, &offset, &shift, 2);
|
||||
if (runlength == 3)
|
||||
{
|
||||
runlength = getbits(nwa->file, &offset, &shift, 8);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
runlength--;
|
||||
}
|
||||
if (nwa->bps == 8)
|
||||
{
|
||||
nwa->buffer[i] = d[flip_flag]*0x100;
|
||||
}
|
||||
else
|
||||
{
|
||||
nwa->buffer[i] = d[flip_flag];
|
||||
}
|
||||
nwa->samples_in_buffer++;
|
||||
if (nwa->channels == 2)
|
||||
flip_flag ^= 1; /* channel 切り替え */
|
||||
}
|
||||
}
|
||||
|
||||
nwa->curblock++;
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
seek_nwa(NWAData *nwa, int32_t seekpos)
|
||||
{
|
||||
int dest_block = seekpos/(nwa->blocksize/nwa->channels);
|
||||
int32_t remainder = seekpos%(nwa->blocksize/nwa->channels);
|
||||
|
||||
nwa->curblock = dest_block;
|
||||
|
||||
nwa_decode_block(nwa);
|
||||
|
||||
nwa->buffer_readpos = nwa->buffer + remainder*nwa->channels;
|
||||
nwa->samples_in_buffer -= remainder*nwa->channels;
|
||||
}
|
||||
|
||||
/* interface to vgmstream */
|
||||
void
|
||||
decode_nwa(NWAData *nwa, sample *outbuf,
|
||||
int32_t samples_to_do)
|
||||
{
|
||||
while (samples_to_do > 0)
|
||||
{
|
||||
int32_t samples_to_read;
|
||||
|
||||
if (nwa->samples_in_buffer > 0)
|
||||
{
|
||||
samples_to_read = nwa->samples_in_buffer/nwa->channels;
|
||||
if (samples_to_read > samples_to_do)
|
||||
samples_to_read = samples_to_do;
|
||||
|
||||
memcpy(outbuf,nwa->buffer_readpos,
|
||||
sizeof(sample)*samples_to_read*nwa->channels);
|
||||
|
||||
nwa->buffer_readpos += samples_to_read*nwa->channels;
|
||||
nwa->samples_in_buffer -= samples_to_read*nwa->channels;
|
||||
outbuf += samples_to_read*nwa->channels;
|
||||
samples_to_do -= samples_to_read;
|
||||
}
|
||||
else
|
||||
{
|
||||
nwa_decode_block(nwa);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
/* originally from nwatowav.cc 2007.7.28 version, which read: */
|
||||
/*
|
||||
* Copyright 2001-2007 jagarl / Kazunori Ueno <jagarl@creator.club.ne.jp>
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted.
|
||||
*
|
||||
* このプログラムの作者は jagarl です。
|
||||
*
|
||||
* このプログラム、及びコンパイルによって生成したバイナリは
|
||||
* プログラムを変更する、しないにかかわらず再配布可能です。
|
||||
* その際、上記 Copyright 表示を保持するなどの条件は課しま
|
||||
* せん。対応が面倒なのでバグ報告を除き、メールで連絡をする
|
||||
* などの必要もありません。ソースの一部を流用することを含め、
|
||||
* ご自由にお使いください。
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY KAZUNORI 'jagarl' UENO ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KAZUNORI UENO BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _NWA_DECODER_H
|
||||
#define _NWA_DECODER_H
|
||||
|
||||
#ifdef BUILD_VGMSTREAM
|
||||
#include "../streamfile.h"
|
||||
#else
|
||||
#include "streamfile.h"
|
||||
#endif
|
||||
|
||||
typedef struct NWAData_s
|
||||
{
|
||||
int channels;
|
||||
int bps; /* bits per sample */
|
||||
int freq; /* samples per second */
|
||||
int complevel; /* compression level */
|
||||
int blocks; /* block count */
|
||||
int datasize; /* all data size */
|
||||
int compdatasize; /* compressed data size */
|
||||
int samplecount; /* all samples */
|
||||
int blocksize; /* samples per block */
|
||||
int restsize; /* samples of the last block */
|
||||
|
||||
int curblock;
|
||||
off_t *offsets;
|
||||
|
||||
STREAMFILE *file;
|
||||
|
||||
/* temporarily store samples */
|
||||
sample *buffer;
|
||||
sample *buffer_readpos;
|
||||
int samples_in_buffer;
|
||||
} NWAData;
|
||||
|
||||
NWAData *open_nwa(STREAMFILE *streamFile, const char *filename);
|
||||
void close_nwa(NWAData *nwa);
|
||||
void reset_nwa(NWAData *nwa);
|
||||
void seek_nwa(NWAData *nwa, int32_t seekpos);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,22 @@
|
|||
#include "../vgmstream.h"
|
||||
|
||||
#ifdef VGM_USE_VORBIS
|
||||
#include <vorbis/vorbisfile.h>
|
||||
#include "coding.h"
|
||||
#include "../util.h"
|
||||
|
||||
void decode_ogg_vorbis(ogg_vorbis_codec_data * data, sample * outbuf, int32_t samples_to_do, int channels) {
|
||||
int samples_done = 0;
|
||||
OggVorbis_File *ogg_vorbis_file = &data->ogg_vorbis_file;
|
||||
|
||||
do {
|
||||
long rc = ov_read(ogg_vorbis_file, (char *)(outbuf + samples_done*channels),
|
||||
(samples_to_do - samples_done)*sizeof(sample)*channels, 0,
|
||||
sizeof(sample), 1, &data->bitstream);
|
||||
|
||||
if (rc > 0) samples_done += rc/sizeof(sample)/channels;
|
||||
else return;
|
||||
} while (samples_done < samples_to_do);
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,87 @@
|
|||
#include "coding.h"
|
||||
#include "../util.h"
|
||||
|
||||
void decode_pcm16LE(VGMSTREAMCHANNEL * stream, sample * 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) {
|
||||
outbuf[sample_count]=read_16bitLE(stream->offset+i*2,stream->streamfile);
|
||||
}
|
||||
}
|
||||
|
||||
void decode_pcm16BE(VGMSTREAMCHANNEL * stream, sample * 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) {
|
||||
outbuf[sample_count]=read_16bitBE(stream->offset+i*2,stream->streamfile);
|
||||
}
|
||||
}
|
||||
|
||||
void decode_pcm8(VGMSTREAMCHANNEL * stream, sample * 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) {
|
||||
outbuf[sample_count]=read_8bit(stream->offset+i,stream->streamfile)*0x100;
|
||||
}
|
||||
}
|
||||
|
||||
void decode_pcm8_int(VGMSTREAMCHANNEL * stream, sample * 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) {
|
||||
outbuf[sample_count]=read_8bit(stream->offset+i*channelspacing,stream->streamfile)*0x100;
|
||||
}
|
||||
}
|
||||
|
||||
void decode_pcm8_sb_int(VGMSTREAMCHANNEL * stream, sample * 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) {
|
||||
int16_t v = (uint8_t)read_8bit(stream->offset+i*channelspacing,stream->streamfile);
|
||||
if (v&0x80) v = 0-(v&0x7f);
|
||||
outbuf[sample_count] = v*0x100;
|
||||
}
|
||||
}
|
||||
|
||||
void decode_pcm8_unsigned_int(VGMSTREAMCHANNEL * stream, sample * 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) {
|
||||
int16_t v = (uint8_t)read_8bit(stream->offset+i*channelspacing,stream->streamfile);
|
||||
outbuf[sample_count] = v*0x100 - 0x8000;
|
||||
}
|
||||
}
|
||||
|
||||
void decode_pcm8_unsigned(VGMSTREAMCHANNEL * stream, sample * 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) {
|
||||
int16_t v = (uint8_t)read_8bit(stream->offset+i,stream->streamfile);
|
||||
outbuf[sample_count] = v*0x100 - 0x8000;
|
||||
}
|
||||
}
|
||||
|
||||
void decode_pcm16LE_int(VGMSTREAMCHANNEL * stream, sample * 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) {
|
||||
outbuf[sample_count]=read_16bitLE(stream->offset+i*2*channelspacing,stream->streamfile);
|
||||
}
|
||||
}
|
||||
|
||||
void decode_pcm16LE_XOR_int(VGMSTREAMCHANNEL * stream, sample * 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) {
|
||||
outbuf[sample_count]=read_16bitLE(stream->offset+i*2*channelspacing,stream->streamfile)^stream->key_xor;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,214 @@
|
|||
#include <math.h>
|
||||
#include "coding.h"
|
||||
#include "../util.h"
|
||||
|
||||
double VAG_f[5][2] = { { 0.0 , 0.0 },
|
||||
{ 60.0 / 64.0 , 0.0 },
|
||||
{ 115.0 / 64.0 , -52.0 / 64.0 },
|
||||
{ 98.0 / 64.0 , -55.0 / 64.0 } ,
|
||||
{ 122.0 / 64.0 , -60.0 / 64.0 } } ;
|
||||
long VAG_coefs[5][2] = { { 0 , 0 },
|
||||
{ 60 , 0 },
|
||||
{ 115 , -52 },
|
||||
{ 98 , -55 } ,
|
||||
{ 122 , -60 } } ;
|
||||
|
||||
void decode_psx(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
|
||||
int predict_nr, shift_factor, sample;
|
||||
int32_t hist1=stream->adpcm_history1_32;
|
||||
int32_t hist2=stream->adpcm_history2_32;
|
||||
|
||||
short scale;
|
||||
int i;
|
||||
int32_t sample_count;
|
||||
uint8_t flag;
|
||||
|
||||
int framesin = first_sample/28;
|
||||
|
||||
predict_nr = read_8bit(stream->offset+framesin*16,stream->streamfile) >> 4;
|
||||
shift_factor = read_8bit(stream->offset+framesin*16,stream->streamfile) & 0xf;
|
||||
flag = read_8bit(stream->offset+framesin*16+1,stream->streamfile);
|
||||
|
||||
first_sample = first_sample % 28;
|
||||
|
||||
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
|
||||
|
||||
sample=0;
|
||||
|
||||
if(flag<0x07) {
|
||||
|
||||
short sample_byte = (short)read_8bit(stream->offset+(framesin*16)+2+i/2,stream->streamfile);
|
||||
|
||||
scale = ((i&1 ?
|
||||
sample_byte >> 4 :
|
||||
sample_byte & 0x0f)<<12);
|
||||
|
||||
sample=(int)((scale >> shift_factor)+hist1*VAG_f[predict_nr][0]+hist2*VAG_f[predict_nr][1]);
|
||||
}
|
||||
|
||||
outbuf[sample_count] = clamp16(sample);
|
||||
hist2=hist1;
|
||||
hist1=sample;
|
||||
}
|
||||
stream->adpcm_history1_32=hist1;
|
||||
stream->adpcm_history2_32=hist2;
|
||||
}
|
||||
|
||||
void decode_invert_psx(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
|
||||
int predict_nr, shift_factor, sample;
|
||||
int32_t hist1=stream->adpcm_history1_32;
|
||||
int32_t hist2=stream->adpcm_history2_32;
|
||||
|
||||
short scale;
|
||||
int i;
|
||||
int32_t sample_count;
|
||||
uint8_t flag;
|
||||
|
||||
int framesin = first_sample/28;
|
||||
int head = read_8bit(stream->offset+framesin*16,stream->streamfile) ^ stream->bmdx_xor;
|
||||
|
||||
predict_nr = ((head >> 4) & 0xf);
|
||||
shift_factor = (head & 0xf);
|
||||
flag = read_8bit(stream->offset+framesin*16+1,stream->streamfile);
|
||||
|
||||
first_sample = first_sample % 28;
|
||||
|
||||
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
|
||||
|
||||
sample=0;
|
||||
|
||||
if(flag<0x07) {
|
||||
|
||||
short sample_byte = (short)read_8bit(stream->offset+(framesin*16)+2+i/2,stream->streamfile);
|
||||
if (i/2 == 0)
|
||||
sample_byte = (short)(int8_t)(sample_byte+stream->bmdx_add);
|
||||
|
||||
scale = ((i&1 ?
|
||||
sample_byte >> 4 :
|
||||
sample_byte & 0x0f)<<12);
|
||||
|
||||
sample=(int)((scale >> shift_factor)+hist1*VAG_f[predict_nr][0]+hist2*VAG_f[predict_nr][1]);
|
||||
}
|
||||
|
||||
outbuf[sample_count] = clamp16(sample);
|
||||
hist2=hist1;
|
||||
hist1=sample;
|
||||
}
|
||||
stream->adpcm_history1_32=hist1;
|
||||
stream->adpcm_history2_32=hist2;
|
||||
}
|
||||
|
||||
/* some TAITO games have garbage (?) in their flags, this decoder
|
||||
* just ignores that byte */
|
||||
void decode_psx_badflags(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
|
||||
int predict_nr, shift_factor, sample;
|
||||
int32_t hist1=stream->adpcm_history1_32;
|
||||
int32_t hist2=stream->adpcm_history2_32;
|
||||
|
||||
short scale;
|
||||
int i;
|
||||
int32_t sample_count;
|
||||
|
||||
int framesin = first_sample/28;
|
||||
|
||||
predict_nr = read_8bit(stream->offset+framesin*16,stream->streamfile) >> 4;
|
||||
shift_factor = read_8bit(stream->offset+framesin*16,stream->streamfile) & 0xf;
|
||||
first_sample = first_sample % 28;
|
||||
|
||||
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
|
||||
short sample_byte = (short)read_8bit(stream->offset+(framesin*16)+2+i/2,stream->streamfile);
|
||||
|
||||
scale = ((i&1 ?
|
||||
sample_byte >> 4 :
|
||||
sample_byte & 0x0f)<<12);
|
||||
|
||||
sample=(int)((scale >> shift_factor)+hist1*VAG_f[predict_nr][0]+hist2*VAG_f[predict_nr][1]);
|
||||
|
||||
outbuf[sample_count] = clamp16(sample);
|
||||
hist2=hist1;
|
||||
hist1=sample;
|
||||
}
|
||||
stream->adpcm_history1_32=hist1;
|
||||
stream->adpcm_history2_32=hist2;
|
||||
}
|
||||
|
||||
/* FF XI's Vag-ish format */
|
||||
void decode_ffxi_adpcm(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
|
||||
int predict_nr, shift_factor, sample;
|
||||
int32_t hist1=stream->adpcm_history1_32;
|
||||
int32_t hist2=stream->adpcm_history2_32;
|
||||
|
||||
short scale;
|
||||
int i;
|
||||
int32_t sample_count;
|
||||
long predictor;
|
||||
|
||||
int framesin = first_sample/16;
|
||||
|
||||
predict_nr = read_8bit(stream->offset+framesin*9,stream->streamfile) >> 4;
|
||||
shift_factor = read_8bit(stream->offset+framesin*9,stream->streamfile) & 0xf;
|
||||
first_sample = first_sample % 16;
|
||||
|
||||
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
|
||||
short sample_byte = (short)read_8bit(stream->offset+(framesin*9)+1+i/2,stream->streamfile);
|
||||
|
||||
sample=0;
|
||||
|
||||
scale = ((i&1 ?
|
||||
sample_byte >> 4 :
|
||||
sample_byte & 0x0f)<<12);
|
||||
|
||||
#if 1
|
||||
predictor =
|
||||
(int)((hist1*VAG_f[predict_nr][0]+hist2*VAG_f[predict_nr][1]));
|
||||
#else
|
||||
predictor =
|
||||
(hist1*VAG_coefs[predict_nr][0]+hist2*VAG_coefs[predict_nr][1])/64;
|
||||
#endif
|
||||
sample=(scale >> shift_factor) + predictor;
|
||||
|
||||
outbuf[sample_count] = clamp16(sample);
|
||||
hist2=hist1;
|
||||
hist1=sample;
|
||||
}
|
||||
stream->adpcm_history1_32=hist1;
|
||||
stream->adpcm_history2_32=hist2;
|
||||
}
|
||||
|
||||
void decode_baf_adpcm(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
|
||||
int predict_nr, shift_factor, sample;
|
||||
int32_t hist1=stream->adpcm_history1_32;
|
||||
int32_t hist2=stream->adpcm_history2_32;
|
||||
|
||||
short scale;
|
||||
int i;
|
||||
int32_t sample_count;
|
||||
|
||||
int framesin = first_sample/64;
|
||||
|
||||
predict_nr = read_8bit(stream->offset+framesin*33,stream->streamfile) >> 4;
|
||||
shift_factor = read_8bit(stream->offset+framesin*33,stream->streamfile) & 0xf;
|
||||
|
||||
first_sample = first_sample % 64;
|
||||
|
||||
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
|
||||
short sample_byte = (short)read_8bit(stream->offset+(framesin*33)+1+i/2,stream->streamfile);
|
||||
|
||||
scale = ((i&1 ?
|
||||
sample_byte >> 4 :
|
||||
sample_byte & 0x0f)<<12);
|
||||
|
||||
sample=(int)((scale >> shift_factor)+hist1*VAG_f[predict_nr][0]+hist2*VAG_f[predict_nr][1]);
|
||||
|
||||
outbuf[sample_count] = clamp16(sample);
|
||||
hist2=hist1;
|
||||
hist1=sample;
|
||||
}
|
||||
stream->adpcm_history1_32=hist1;
|
||||
stream->adpcm_history2_32=hist2;
|
||||
}
|
|
@ -0,0 +1,118 @@
|
|||
#include <math.h>
|
||||
#include "coding.h"
|
||||
#include "../util.h"
|
||||
|
||||
/* SDX2 - 2:1 Squareroot-delta-exact compression */
|
||||
/* CBD2 - 2:1 Cuberoot-delta-exact compression (from the unreleased 3DO M2) */
|
||||
|
||||
/* for (i=-128;i<128;i++) squares[i+128]=i<0?(-i*i)*2:(i*i)*2; */
|
||||
static int16_t squares[256] = {
|
||||
-32768,-32258,-31752,-31250,-30752,-30258,-29768,-29282,-28800,-28322,-27848,
|
||||
-27378,-26912,-26450,-25992,-25538,-25088,-24642,-24200,-23762,-23328,-22898,
|
||||
-22472,-22050,-21632,-21218,-20808,-20402,-20000,-19602,-19208,-18818,-18432,
|
||||
-18050,-17672,-17298,-16928,-16562,-16200,-15842,-15488,-15138,-14792,-14450,
|
||||
-14112,-13778,-13448,-13122,-12800,-12482,-12168,-11858,-11552,-11250,-10952,
|
||||
-10658,-10368,-10082, -9800, -9522, -9248, -8978, -8712, -8450, -8192, -7938,
|
||||
-7688, -7442, -7200, -6962, -6728, -6498, -6272, -6050, -5832, -5618, -5408,
|
||||
-5202, -5000, -4802, -4608, -4418, -4232, -4050, -3872, -3698, -3528, -3362,
|
||||
-3200, -3042, -2888, -2738, -2592, -2450, -2312, -2178, -2048, -1922, -1800,
|
||||
-1682, -1568, -1458, -1352, -1250, -1152, -1058, -968, -882, -800, -722,
|
||||
-648, -578, -512, -450, -392, -338, -288, -242, -200, -162, -128,
|
||||
-98, -72, -50, -32, -18, -8, -2, 0, 2, 8, 18,
|
||||
32, 50, 72, 98, 128, 162, 200, 242, 288, 338, 392,
|
||||
450, 512, 578, 648, 722, 800, 882, 968, 1058, 1152, 1250,
|
||||
1352, 1458, 1568, 1682, 1800, 1922, 2048, 2178, 2312, 2450, 2592,
|
||||
2738, 2888, 3042, 3200, 3362, 3528, 3698, 3872, 4050, 4232, 4418,
|
||||
4608, 4802, 5000, 5202, 5408, 5618, 5832, 6050, 6272, 6498, 6728,
|
||||
6962, 7200, 7442, 7688, 7938, 8192, 8450, 8712, 8978, 9248, 9522,
|
||||
9800, 10082, 10368, 10658, 10952, 11250, 11552, 11858, 12168, 12482, 12800,
|
||||
13122, 13448, 13778, 14112, 14450, 14792, 15138, 15488, 15842, 16200, 16562,
|
||||
16928, 17298, 17672, 18050, 18432, 18818, 19208, 19602, 20000, 20402, 20808,
|
||||
21218, 21632, 22050, 22472, 22898, 23328, 23762, 24200, 24642, 25088, 25538,
|
||||
25992, 26450, 26912, 27378, 27848, 28322, 28800, 29282, 29768, 30258, 30752,
|
||||
31250, 31752, 32258
|
||||
};
|
||||
|
||||
//for (i=-128;i<128;i++)
|
||||
//{
|
||||
// double j = (i/2)/2.0;
|
||||
// cubes[i+128]=floor(j*j*j);
|
||||
//}
|
||||
static int16_t cubes[256]={
|
||||
-32768,-31256,-31256,-29791,-29791,-28373,-28373,-27000,-27000,-25672,-25672,
|
||||
-24389,-24389,-23149,-23149,-21952,-21952,-20797,-20797,-19683,-19683,-18610,
|
||||
-18610,-17576,-17576,-16581,-16581,-15625,-15625,-14706,-14706,-13824,-13824,
|
||||
-12978,-12978,-12167,-12167,-11391,-11391,-10648,-10648, -9938, -9938, -9261,
|
||||
-9261, -8615, -8615, -8000, -8000, -7415, -7415, -6859, -6859, -6332, -6332,
|
||||
-5832, -5832, -5359, -5359, -4913, -4913, -4492, -4492, -4096, -4096, -3724,
|
||||
-3724, -3375, -3375, -3049, -3049, -2744, -2744, -2460, -2460, -2197, -2197,
|
||||
-1953, -1953, -1728, -1728, -1521, -1521, -1331, -1331, -1158, -1158, -1000,
|
||||
-1000, -857, -857, -729, -729, -614, -614, -512, -512, -422, -422,
|
||||
-343, -343, -275, -275, -216, -216, -166, -166, -125, -125, -91,
|
||||
-91, -64, -64, -43, -43, -27, -27, -16, -16, -8, -8,
|
||||
-3, -3, -1, -1, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 1, 3, 3, 8, 8, 16, 16, 27, 27, 43,
|
||||
43, 64, 64, 91, 91, 125, 125, 166, 166, 216, 216,
|
||||
275, 275, 343, 343, 422, 422, 512, 512, 614, 614, 729,
|
||||
729, 857, 857, 1000, 1000, 1158, 1158, 1331, 1331, 1521, 1521,
|
||||
1728, 1728, 1953, 1953, 2197, 2197, 2460, 2460, 2744, 2744, 3049,
|
||||
3049, 3375, 3375, 3724, 3724, 4096, 4096, 4492, 4492, 4913, 4913,
|
||||
5359, 5359, 5832, 5832, 6332, 6332, 6859, 6859, 7415, 7415, 8000,
|
||||
8000, 8615, 8615, 9261, 9261, 9938, 9938, 10648, 10648, 11391, 11391,
|
||||
12167, 12167, 12978, 12978, 13824, 13824, 14706, 14706, 15625, 15625, 16581,
|
||||
16581, 17576, 17576, 18610, 18610, 19683, 19683, 20797, 20797, 21952, 21952,
|
||||
23149, 23149, 24389, 24389, 25672, 25672, 27000, 27000, 28373, 28373, 29791,
|
||||
29791, 31256, 31256};
|
||||
static void decode_delta_exact(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int16_t * table) {
|
||||
|
||||
int32_t hist = stream->adpcm_history1_32;
|
||||
|
||||
int i;
|
||||
int32_t sample_count;
|
||||
|
||||
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
|
||||
int8_t sample_byte = read_8bit(stream->offset+i,stream->streamfile);
|
||||
int16_t sample;
|
||||
|
||||
if (!(sample_byte & 1)) hist = 0;
|
||||
sample = hist + table[sample_byte+128];
|
||||
|
||||
hist = outbuf[sample_count] = clamp16(sample);
|
||||
}
|
||||
stream->adpcm_history1_32=hist;
|
||||
}
|
||||
|
||||
static void decode_delta_exact_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int16_t * table) {
|
||||
|
||||
int32_t hist = stream->adpcm_history1_32;
|
||||
|
||||
int i;
|
||||
int32_t sample_count;
|
||||
|
||||
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
|
||||
int8_t sample_byte = read_8bit(stream->offset+i*channelspacing,stream->streamfile);
|
||||
int16_t sample;
|
||||
|
||||
if (!(sample_byte & 1)) hist = 0;
|
||||
sample = hist + table[sample_byte+128];
|
||||
|
||||
hist = outbuf[sample_count] = clamp16(sample);
|
||||
}
|
||||
stream->adpcm_history1_32=hist;
|
||||
}
|
||||
|
||||
void decode_sdx2(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
decode_delta_exact(stream, outbuf, channelspacing, first_sample, samples_to_do, squares);
|
||||
}
|
||||
|
||||
void decode_sdx2_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
decode_delta_exact_int(stream, outbuf, channelspacing, first_sample, samples_to_do, squares);
|
||||
}
|
||||
|
||||
void decode_cbd2(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
decode_delta_exact(stream, outbuf, channelspacing, first_sample, samples_to_do, cubes);
|
||||
}
|
||||
|
||||
void decode_cbd2_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
decode_delta_exact_int(stream, outbuf, channelspacing, first_sample, samples_to_do, cubes);
|
||||
}
|
|
@ -0,0 +1,146 @@
|
|||
#include <math.h>
|
||||
#include "coding.h"
|
||||
#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};
|
||||
|
||||
/* 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]);
|
||||
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 i;
|
||||
int32_t sample_count;
|
||||
|
||||
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;
|
||||
}
|
||||
} 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;
|
||||
|
||||
if (samples_left_in_frame == 0) {
|
||||
header_off = offset;
|
||||
offset++;
|
||||
}
|
||||
|
||||
header = read_8bit(header_off,stream->streamfile);
|
||||
count = header & 0x3f;
|
||||
switch (header>>6) { /* 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;
|
||||
hist += WSTable2bit[sample];
|
||||
if (hist < 0) hist = 0;
|
||||
if (hist > 0xff) hist = 0xff;
|
||||
outbuf[sample_count]=(hist-0x80)*0x100;
|
||||
|
||||
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 (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;
|
||||
|
||||
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 */
|
||||
/* low 5 bits are a signed delta */
|
||||
if (count & 0x10) {
|
||||
hist -= ((count & 0xf)^0xf) + 1;
|
||||
} else {
|
||||
hist += count & 0xf;
|
||||
}
|
||||
|
||||
/* Valery doesn't specify this, but I will assume */
|
||||
if (hist < 0) hist = 0;
|
||||
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 */
|
||||
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;
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stream->offset = offset;
|
||||
stream->adpcm_history1_16 = hist;
|
||||
stream->samples_left_in_frame = samples_left_in_frame;
|
||||
stream->frame_header_offset = header_off;
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
#include "coding.h"
|
||||
#include "../util.h"
|
||||
|
||||
const int SH = 4;
|
||||
const int SHC = 10;
|
||||
|
||||
double K0[4] = { 0.0, 0.9375, 1.796875, 1.53125};
|
||||
double K1[4] = { 0.0, 0.0, -0.8125,-0.859375};
|
||||
|
||||
int IK0(int fid)
|
||||
{ return ((int)((-K0[fid]) * (1 << SHC))); }
|
||||
|
||||
int IK1(int fid)
|
||||
{ return ((int)((-K1[fid]) * (1 << SHC))); }
|
||||
|
||||
int CLAMP(int value, int Minim, int Maxim)
|
||||
{
|
||||
if (value < Minim) value = Minim;
|
||||
if (value > Maxim) value = Maxim;
|
||||
return value;
|
||||
}
|
||||
|
||||
void init_get_high_nibble(VGMSTREAM *vgmstream) {
|
||||
vgmstream->get_high_nibble=1;
|
||||
}
|
||||
|
||||
void decode_xa(VGMSTREAM * vgmstream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
|
||||
|
||||
VGMSTREAMCHANNEL * stream = &(vgmstream->ch[channel]);
|
||||
int predict_nr, shift_factor, sample;
|
||||
int32_t hist1=stream->adpcm_history1_32;
|
||||
int32_t hist2=stream->adpcm_history2_32;
|
||||
int HeadTable[8]={0,2,8,10};
|
||||
|
||||
short scale;
|
||||
int i;
|
||||
int32_t sample_count;
|
||||
|
||||
int framesin = first_sample / (56 / channelspacing);
|
||||
|
||||
|
||||
first_sample = first_sample % 28;
|
||||
|
||||
vgmstream->get_high_nibble=!vgmstream->get_high_nibble;
|
||||
|
||||
if((first_sample) && (channelspacing==1))
|
||||
vgmstream->get_high_nibble=!vgmstream->get_high_nibble;
|
||||
|
||||
predict_nr = read_8bit(stream->offset+HeadTable[framesin]+vgmstream->get_high_nibble,stream->streamfile) >> 4;
|
||||
shift_factor = read_8bit(stream->offset+HeadTable[framesin]+vgmstream->get_high_nibble,stream->streamfile) & 0xf;
|
||||
|
||||
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
|
||||
short sample_byte = (short)read_8bit(stream->offset+16+framesin+(i*4),stream->streamfile);
|
||||
|
||||
scale = ((vgmstream->get_high_nibble ?
|
||||
sample_byte >> 4 :
|
||||
sample_byte & 0x0f)<<12);
|
||||
|
||||
sample = (short)(scale & 0xf000) >> shift_factor;
|
||||
sample <<= SH;
|
||||
sample -= (IK0(predict_nr) * hist1 + (IK1(predict_nr) * hist2)) >> SHC;
|
||||
|
||||
hist2=hist1;
|
||||
hist1=sample;
|
||||
|
||||
sample = CLAMP(sample, -32768 << SH, 32767 << SH);
|
||||
outbuf[sample_count] = (short)(sample >> SH);
|
||||
}
|
||||
|
||||
stream->adpcm_history1_32=hist1;
|
||||
stream->adpcm_history2_32=hist2;
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
noinst_LTLIBRARIES = liblayout.la
|
||||
|
||||
AM_CFLAGS = -Wall @CFLAGS@ -I$(top_builddir) -I$(top_srcdir)
|
||||
AM_MAKEFLAGS=-f Makefile.unix
|
||||
|
||||
liblayout_la_LDFLAGS =
|
||||
liblayout_la_SOURCES =
|
||||
liblayout_la_SOURCES += ast_blocked.c
|
||||
liblayout_la_SOURCES += blocked.c
|
||||
liblayout_la_SOURCES += caf_blocked.c
|
||||
liblayout_la_SOURCES += ea_block.c
|
||||
liblayout_la_SOURCES += halpst_blocked.c
|
||||
liblayout_la_SOURCES += interleave.c
|
||||
liblayout_la_SOURCES += nolayout.c
|
||||
liblayout_la_SOURCES += xa_blocked.c
|
||||
liblayout_la_SOURCES += wsi_blocked.c
|
||||
liblayout_la_SOURCES += str_snds_blocked.c
|
||||
liblayout_la_SOURCES += ws_aud_blocked.c
|
||||
liblayout_la_SOURCES += interleave_byte.c
|
||||
liblayout_la_SOURCES += mus_acm_layout.c
|
||||
liblayout_la_SOURCES += aix_layout.c
|
||||
liblayout_la_SOURCES += ims_block.c
|
||||
liblayout_la_SOURCES += de2_blocked.c
|
||||
liblayout_la_SOURCES += xvas_block.c
|
||||
liblayout_la_SOURCES += vs_blocked.c
|
||||
liblayout_la_SOURCES += emff_blocked.c
|
||||
liblayout_la_SOURCES += thp_blocked.c
|
||||
liblayout_la_SOURCES += gsb_blocked.c
|
||||
liblayout_la_SOURCES += filp_blocked.c
|
||||
liblayout_la_SOURCES += aax_layout.c
|
||||
liblayout_la_SOURCES += ivaud_layout.c
|
||||
liblayout_la_SOURCES += mxch_blocked.c
|
||||
liblayout_la_SOURCES += psx_mgav_blocked.c
|
||||
liblayout_la_SOURCES += ps2_adm_blocked.c
|
||||
liblayout_la_SOURCES += bdsp_blocked.c
|
||||
liblayout_la_SOURCES += tra_blocked.c
|
||||
liblayout_la_SOURCES += ps2_iab_blocked.c
|
||||
liblayout_la_SOURCES += ps2_strlr_blocked.c
|
||||
liblayout_la_SOURCES += scd_int_layout.c
|
||||
|
||||
EXTRA_DIST = layout.h
|
|
@ -0,0 +1,67 @@
|
|||
#include "layout.h"
|
||||
#include "../vgmstream.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
void render_vgmstream_aax(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream) {
|
||||
int samples_written=0;
|
||||
aax_codec_data *data = vgmstream->codec_data;
|
||||
|
||||
while (samples_written<sample_count) {
|
||||
int samples_to_do;
|
||||
int samples_this_block = data->sample_counts[data->current_segment];
|
||||
|
||||
if (vgmstream->loop_flag && vgmstream_do_loop(vgmstream)) {
|
||||
int i;
|
||||
data->current_segment = data->loop_segment;
|
||||
|
||||
reset_vgmstream(data->adxs[data->current_segment]);
|
||||
|
||||
/* carry over the history from the loop point */
|
||||
if (data->loop_segment > 0)
|
||||
{
|
||||
for (i=0;i<data->adxs[0]->channels;i++)
|
||||
{
|
||||
data->adxs[data->loop_segment]->ch[i].adpcm_history1_32 =
|
||||
data->adxs[data->loop_segment-1]->ch[i].adpcm_history1_32;
|
||||
data->adxs[data->loop_segment]->ch[i].adpcm_history2_32 =
|
||||
data->adxs[data->loop_segment-1]->ch[i].adpcm_history2_32;
|
||||
}
|
||||
}
|
||||
vgmstream->samples_into_block = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
samples_to_do = vgmstream_samples_to_do(samples_this_block, 1, vgmstream);
|
||||
|
||||
/*printf("samples_to_do=%d,samples_this_block=%d,samples_written=%d,sample_count=%d\n",samples_to_do,samples_this_block,samples_written,sample_count);*/
|
||||
|
||||
if (samples_written+samples_to_do > sample_count)
|
||||
samples_to_do=sample_count-samples_written;
|
||||
|
||||
if (samples_to_do == 0)
|
||||
{
|
||||
int i;
|
||||
data->current_segment++;
|
||||
/*printf("advance to %d at %d samples\n",data->current_segment,vgmstream->current_sample);*/
|
||||
reset_vgmstream(data->adxs[data->current_segment]);
|
||||
|
||||
/* carry over the history from the previous segment */
|
||||
for (i=0;i<data->adxs[0]->channels;i++)
|
||||
{
|
||||
data->adxs[data->current_segment]->ch[i].adpcm_history1_32 =
|
||||
data->adxs[data->current_segment-1]->ch[i].adpcm_history1_32;
|
||||
data->adxs[data->current_segment]->ch[i].adpcm_history2_32 =
|
||||
data->adxs[data->current_segment-1]->ch[i].adpcm_history2_32;
|
||||
}
|
||||
vgmstream->samples_into_block = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
render_vgmstream(&buffer[samples_written*data->adxs[data->current_segment]->channels],
|
||||
samples_to_do,data->adxs[data->current_segment]);
|
||||
|
||||
samples_written += samples_to_do;
|
||||
vgmstream->current_sample += samples_to_do;
|
||||
vgmstream->samples_into_block+=samples_to_do;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
#include "layout.h"
|
||||
#include "../vgmstream.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
void render_vgmstream_aix(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream) {
|
||||
int samples_written=0;
|
||||
aix_codec_data *data = vgmstream->codec_data;
|
||||
|
||||
while (samples_written<sample_count) {
|
||||
int samples_to_do;
|
||||
int samples_this_block = data->sample_counts[data->current_segment];
|
||||
int current_stream;
|
||||
int channels_sofar = 0;
|
||||
|
||||
if (vgmstream->loop_flag && vgmstream_do_loop(vgmstream)) {
|
||||
data->current_segment = 1;
|
||||
for (current_stream = 0; current_stream < data->stream_count; current_stream++)
|
||||
{
|
||||
int i;
|
||||
reset_vgmstream(data->adxs[data->current_segment*data->stream_count+current_stream]);
|
||||
|
||||
/* carry over the history from the loop point */
|
||||
for (i=0;i<data->adxs[data->stream_count+current_stream]->channels;i++)
|
||||
{
|
||||
data->adxs[1*data->stream_count+current_stream]->ch[i].adpcm_history1_32 =
|
||||
data->adxs[0+current_stream]->ch[i].adpcm_history1_32;
|
||||
data->adxs[1*data->stream_count+current_stream]->ch[i].adpcm_history2_32 =
|
||||
data->adxs[0+current_stream]->ch[i].adpcm_history2_32;
|
||||
}
|
||||
}
|
||||
vgmstream->samples_into_block = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
samples_to_do = vgmstream_samples_to_do(samples_this_block, 1, vgmstream);
|
||||
|
||||
/*printf("samples_to_do=%d,samples_this_block=%d,samples_written=%d,sample_count=%d\n",samples_to_do,samples_this_block,samples_written,sample_count);*/
|
||||
|
||||
if (samples_written+samples_to_do > sample_count)
|
||||
samples_to_do=sample_count-samples_written;
|
||||
|
||||
if (samples_to_do == 0)
|
||||
{
|
||||
int i;
|
||||
data->current_segment++;
|
||||
/*printf("next %d, %d samples\n",data->current_file,data->files[data->current_file]->total_values/data->files[data->current_file]->info.channels);*/
|
||||
for (current_stream = 0; current_stream < data->stream_count; current_stream++)
|
||||
{
|
||||
reset_vgmstream(data->adxs[data->current_segment*data->stream_count+current_stream]);
|
||||
|
||||
/* carry over the history from the previous segment */
|
||||
for (i=0;i<data->adxs[data->current_segment*data->stream_count+current_stream]->channels;i++)
|
||||
{
|
||||
data->adxs[data->current_segment*data->stream_count+current_stream]->ch[i].adpcm_history1_32 =
|
||||
data->adxs[(data->current_segment-1)*data->stream_count+current_stream]->ch[i].adpcm_history1_32;
|
||||
data->adxs[data->current_segment*data->stream_count+current_stream]->ch[i].adpcm_history2_32 =
|
||||
data->adxs[(data->current_segment-1)*data->stream_count+current_stream]->ch[i].adpcm_history2_32;
|
||||
}
|
||||
}
|
||||
vgmstream->samples_into_block = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
/*printf("decode %d samples file %d\n",samples_to_do,data->current_file);*/
|
||||
if (samples_to_do > AIX_BUFFER_SIZE/2)
|
||||
{
|
||||
samples_to_do = AIX_BUFFER_SIZE/2;
|
||||
}
|
||||
|
||||
for (current_stream = 0; current_stream < data->stream_count; current_stream++)
|
||||
{
|
||||
int i,j;
|
||||
VGMSTREAM *adx = data->adxs[data->current_segment*data->stream_count+current_stream];
|
||||
|
||||
render_vgmstream(data->buffer,samples_to_do,adx);
|
||||
|
||||
for (i = 0; i < samples_to_do; i++)
|
||||
{
|
||||
for (j = 0; j < adx->channels; j++)
|
||||
{
|
||||
buffer[(i+samples_written)*vgmstream->channels+channels_sofar+j] = data->buffer[i*adx->channels+j];
|
||||
}
|
||||
}
|
||||
|
||||
channels_sofar += adx->channels;
|
||||
}
|
||||
|
||||
samples_written += samples_to_do;
|
||||
vgmstream->current_sample += samples_to_do;
|
||||
vgmstream->samples_into_block+=samples_to_do;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
#include "layout.h"
|
||||
#include "../vgmstream.h"
|
||||
|
||||
/* set up for the block at the given offset */
|
||||
void ast_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
int i;
|
||||
vgmstream->current_block_offset = block_offset;
|
||||
vgmstream->current_block_size = read_32bitBE(
|
||||
vgmstream->current_block_offset+4,
|
||||
vgmstream->ch[0].streamfile);
|
||||
vgmstream->next_block_offset = vgmstream->current_block_offset +
|
||||
vgmstream->current_block_size*vgmstream->channels + 0x20;
|
||||
|
||||
for (i=0;i<vgmstream->channels;i++) {
|
||||
vgmstream->ch[i].offset = vgmstream->current_block_offset +
|
||||
0x20 + vgmstream->current_block_size*i;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
#include "layout.h"
|
||||
#include "../vgmstream.h"
|
||||
|
||||
/* set up for the block at the given offset */
|
||||
void dsp_bdsp_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
int i;
|
||||
|
||||
vgmstream->current_block_offset = block_offset;
|
||||
vgmstream->current_block_size = read_32bitBE(vgmstream->current_block_offset,vgmstream->ch[0].streamfile)/7*8;
|
||||
vgmstream->next_block_offset = vgmstream->current_block_offset + vgmstream->current_block_size+0xC0;
|
||||
|
||||
for (i=0;i<vgmstream->channels;i++) {
|
||||
|
||||
vgmstream->ch[i].channel_start_offset=
|
||||
vgmstream->ch[i].offset=vgmstream->current_block_offset*i;
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,150 @@
|
|||
#include "layout.h"
|
||||
#include "../vgmstream.h"
|
||||
|
||||
void render_vgmstream_blocked(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream) {
|
||||
int samples_written=0;
|
||||
|
||||
int frame_size = get_vgmstream_frame_size(vgmstream);
|
||||
int samples_per_frame = get_vgmstream_samples_per_frame(vgmstream);
|
||||
int samples_this_block;
|
||||
|
||||
if (frame_size == 0) {
|
||||
/* assume 4 bit */
|
||||
/* TODO: get_vgmstream_frame_size() really should return bits... */
|
||||
samples_this_block = vgmstream->current_block_size * 2 * samples_per_frame;
|
||||
} else {
|
||||
samples_this_block = vgmstream->current_block_size / frame_size * samples_per_frame;
|
||||
}
|
||||
|
||||
while (samples_written<sample_count) {
|
||||
int samples_to_do;
|
||||
|
||||
if (vgmstream->loop_flag && vgmstream_do_loop(vgmstream)) {
|
||||
if (frame_size == 0) {
|
||||
samples_this_block = vgmstream->current_block_size * 2 * samples_per_frame;
|
||||
} else {
|
||||
samples_this_block = vgmstream->current_block_size / frame_size * samples_per_frame;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
samples_to_do = vgmstream_samples_to_do(samples_this_block, samples_per_frame, vgmstream);
|
||||
|
||||
if (samples_written+samples_to_do > sample_count)
|
||||
samples_to_do=sample_count-samples_written;
|
||||
|
||||
if (vgmstream->current_block_offset>=0)
|
||||
decode_vgmstream(vgmstream, samples_written, samples_to_do, buffer);
|
||||
else {
|
||||
int i;
|
||||
/* we've run off the end! */
|
||||
for (i=samples_written*vgmstream->channels;
|
||||
i<(samples_written+samples_to_do)*vgmstream->channels;i++)
|
||||
buffer[i]=0;
|
||||
}
|
||||
|
||||
samples_written += samples_to_do;
|
||||
vgmstream->current_sample += samples_to_do;
|
||||
vgmstream->samples_into_block+=samples_to_do;
|
||||
|
||||
if (vgmstream->samples_into_block==samples_this_block) {
|
||||
switch (vgmstream->layout_type) {
|
||||
case layout_ast_blocked:
|
||||
ast_block_update(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_mxch_blocked:
|
||||
mxch_block_update(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_halpst_blocked:
|
||||
if (vgmstream->next_block_offset>=0)
|
||||
halpst_block_update(vgmstream->next_block_offset,vgmstream);
|
||||
else
|
||||
vgmstream->current_block_offset=-1;
|
||||
break;
|
||||
case layout_xa_blocked:
|
||||
xa_block_update(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_ea_blocked:
|
||||
ea_block_update(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_eacs_blocked:
|
||||
eacs_block_update(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_caf_blocked:
|
||||
caf_block_update(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_wsi_blocked:
|
||||
wsi_block_update(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_str_snds_blocked:
|
||||
str_snds_block_update(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_ws_aud_blocked:
|
||||
ws_aud_block_update(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_matx_blocked:
|
||||
matx_block_update(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_de2_blocked:
|
||||
de2_block_update(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_emff_ps2_blocked:
|
||||
emff_ps2_block_update(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_emff_ngc_blocked:
|
||||
emff_ngc_block_update(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_gsb_blocked:
|
||||
gsb_block_update(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_vs_blocked:
|
||||
vs_block_update(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_xvas_blocked:
|
||||
xvas_block_update(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_thp_blocked:
|
||||
thp_block_update(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_filp_blocked:
|
||||
filp_block_update(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_ivaud_blocked:
|
||||
ivaud_block_update(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_psx_mgav_blocked:
|
||||
psx_mgav_block_update(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_ps2_adm_blocked:
|
||||
ps2_adm_block_update(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_dsp_bdsp_blocked:
|
||||
dsp_bdsp_block_update(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_tra_blocked:
|
||||
tra_block_update(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_ps2_iab_blocked:
|
||||
ps2_iab_block_update(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_ps2_strlr_blocked:
|
||||
ps2_strlr_block_update(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* for VBR these may change */
|
||||
frame_size = get_vgmstream_frame_size(vgmstream);
|
||||
samples_per_frame = get_vgmstream_samples_per_frame(vgmstream);
|
||||
|
||||
if (frame_size == 0) {
|
||||
samples_this_block = vgmstream->current_block_size * 2 * samples_per_frame;
|
||||
} else {
|
||||
samples_this_block = vgmstream->current_block_size / frame_size * samples_per_frame;
|
||||
}
|
||||
vgmstream->samples_into_block=0;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
#include "layout.h"
|
||||
#include "../vgmstream.h"
|
||||
|
||||
/* set up for the block at the given offset */
|
||||
void caf_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
int i;
|
||||
|
||||
vgmstream->current_block_offset = block_offset;
|
||||
vgmstream->current_block_size = read_32bitBE(
|
||||
vgmstream->current_block_offset+0x14,
|
||||
vgmstream->ch[0].streamfile);
|
||||
vgmstream->next_block_offset = vgmstream->current_block_offset +
|
||||
(off_t)read_32bitBE(vgmstream->current_block_offset+0x04,
|
||||
vgmstream->ch[0].streamfile);
|
||||
|
||||
for (i=0;i<vgmstream->channels;i++) {
|
||||
vgmstream->ch[i].offset = vgmstream->current_block_offset +
|
||||
read_32bitBE(block_offset+0x10+(8*i),vgmstream->ch[0].streamfile);
|
||||
}
|
||||
|
||||
/* coeffs */
|
||||
for (i=0;i<16;i++) {
|
||||
vgmstream->ch[0].adpcm_coef[i] = read_16bitBE(block_offset+0x34+(2*i),vgmstream->ch[0].streamfile);
|
||||
vgmstream->ch[1].adpcm_coef[i] = read_16bitBE(block_offset+0x60+(2*i),vgmstream->ch[0].streamfile);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
#include "layout.h"
|
||||
#include "../vgmstream.h"
|
||||
|
||||
/* set up for the block at the given offset */
|
||||
void de2_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
int i;
|
||||
vgmstream->current_block_offset = block_offset;
|
||||
vgmstream->current_block_size = read_32bitLE(
|
||||
vgmstream->current_block_offset,
|
||||
vgmstream->ch[0].streamfile);
|
||||
vgmstream->next_block_offset = block_offset+8+read_32bitLE(
|
||||
vgmstream->current_block_offset,
|
||||
vgmstream->ch[0].streamfile);
|
||||
|
||||
for (i=0;i<vgmstream->channels;i++) {
|
||||
vgmstream->ch[i].offset = vgmstream->current_block_offset + 8;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,149 @@
|
|||
#include "layout.h"
|
||||
#include "../coding/coding.h"
|
||||
#include "../vgmstream.h"
|
||||
|
||||
/* set up for the block at the given offset */
|
||||
void ea_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
int i;
|
||||
|
||||
init_get_high_nibble(vgmstream);
|
||||
|
||||
// Search for next SCDL or SCEl block ...
|
||||
do {
|
||||
block_offset+=4;
|
||||
if(block_offset>=(off_t)get_streamfile_size(vgmstream->ch[0].streamfile)) {
|
||||
vgmstream->next_block_offset=block_offset;
|
||||
return;
|
||||
}
|
||||
} while (read_32bitBE(block_offset,vgmstream->ch[0].streamfile)!=0x5343446C);
|
||||
|
||||
// reset channel offset
|
||||
for(i=0;i<vgmstream->channels;i++) {
|
||||
vgmstream->ch[i].channel_start_offset=0;
|
||||
}
|
||||
|
||||
vgmstream->current_block_offset = block_offset;
|
||||
vgmstream->next_block_offset = block_offset+read_32bitLE(block_offset+4,vgmstream->ch[0].streamfile)-4;
|
||||
|
||||
if(vgmstream->ea_big_endian) {
|
||||
vgmstream->current_block_size = read_32bitBE(block_offset+8,vgmstream->ch[0].streamfile);
|
||||
|
||||
for(i=0;i<vgmstream->channels;i++) {
|
||||
vgmstream->ch[i].offset=read_32bitBE(block_offset+0x0C+(i*4),vgmstream->ch[0].streamfile)+(4*vgmstream->channels);
|
||||
vgmstream->ch[i].offset+=vgmstream->current_block_offset+0x0C;
|
||||
}
|
||||
vgmstream->current_block_size /= 28;
|
||||
|
||||
} else {
|
||||
switch(vgmstream->coding_type) {
|
||||
case coding_PSX:
|
||||
vgmstream->ch[0].offset=vgmstream->current_block_offset+0x10;
|
||||
vgmstream->ch[1].offset=(read_32bitLE(block_offset+0x04,vgmstream->ch[0].streamfile)-0x10)/vgmstream->channels;
|
||||
vgmstream->ch[1].offset+=vgmstream->ch[0].offset;
|
||||
vgmstream->current_block_size=read_32bitLE(block_offset+0x04,vgmstream->ch[0].streamfile)-0x10;
|
||||
vgmstream->current_block_size/=vgmstream->channels;
|
||||
break;
|
||||
case coding_EA_ADPCM:
|
||||
vgmstream->current_block_size = read_32bitLE(block_offset+4,vgmstream->ch[0].streamfile);
|
||||
for(i=0;i<vgmstream->channels;i++) {
|
||||
vgmstream->ch[i].offset=vgmstream->current_block_offset+0x0C+(4*vgmstream->channels);
|
||||
vgmstream->ch[i].adpcm_history1_32=(uint32_t)read_16bitLE(vgmstream->current_block_offset+0x0c+(i*4),vgmstream->ch[0].streamfile);
|
||||
vgmstream->ch[i].adpcm_history2_32=(uint32_t)read_16bitLE(vgmstream->current_block_offset+0x0e +(i*4),vgmstream->ch[0].streamfile);
|
||||
}
|
||||
break;
|
||||
case coding_PCM16BE:
|
||||
vgmstream->current_block_size = read_32bitLE(block_offset+4,vgmstream->ch[0].streamfile)-0x14;
|
||||
for(i=0;i<vgmstream->channels;i++) {
|
||||
vgmstream->ch[i].offset=block_offset+0x14+vgmstream->current_block_size/vgmstream->channels*i;
|
||||
}
|
||||
vgmstream->current_block_size/=vgmstream->channels;
|
||||
break;
|
||||
case coding_PCM16LE_int:
|
||||
vgmstream->current_block_size = read_32bitLE(block_offset+4,vgmstream->ch[0].streamfile)-0x0C;
|
||||
for(i=0;i<vgmstream->channels;i++) {
|
||||
vgmstream->ch[i].offset=block_offset+0x0C+(i*2);
|
||||
}
|
||||
vgmstream->current_block_size/=2;
|
||||
vgmstream->current_block_size-=2;
|
||||
break;
|
||||
case coding_XBOX:
|
||||
vgmstream->current_block_size = read_32bitLE(block_offset+0x10,vgmstream->ch[0].streamfile);
|
||||
for(i=0;i<vgmstream->channels;i++) {
|
||||
vgmstream->ch[i].offset=read_32bitLE(block_offset+0x0C+(i*4),vgmstream->ch[0].streamfile)+(4*vgmstream->channels);
|
||||
vgmstream->ch[i].offset+=vgmstream->current_block_offset+0x0C;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
vgmstream->current_block_size = read_32bitLE(block_offset+8,vgmstream->ch[0].streamfile);
|
||||
for(i=0;i<vgmstream->channels;i++) {
|
||||
vgmstream->ch[i].offset=read_32bitLE(block_offset+0x0C+(i*4),vgmstream->ch[0].streamfile)+(4*vgmstream->channels);
|
||||
vgmstream->ch[i].offset+=vgmstream->current_block_offset+0x0C;
|
||||
}
|
||||
vgmstream->current_block_size /= 28;
|
||||
}
|
||||
}
|
||||
|
||||
if((vgmstream->ea_compression_version<3) && (vgmstream->coding_type!=coding_PSX) && (vgmstream->coding_type!=coding_EA_ADPCM) && (vgmstream->coding_type!=coding_XBOX) && (vgmstream->coding_type!=coding_PCM16BE)) {
|
||||
for(i=0;i<vgmstream->channels;i++) {
|
||||
if(vgmstream->ea_big_endian) {
|
||||
vgmstream->ch[i].adpcm_history1_32=read_16bitBE(vgmstream->ch[i].offset,vgmstream->ch[0].streamfile);
|
||||
vgmstream->ch[i].adpcm_history2_32=read_16bitBE(vgmstream->ch[i].offset+2,vgmstream->ch[0].streamfile);
|
||||
} else {
|
||||
vgmstream->ch[i].adpcm_history1_32=read_16bitLE(vgmstream->ch[i].offset,vgmstream->ch[0].streamfile);
|
||||
vgmstream->ch[i].adpcm_history2_32=read_16bitLE(vgmstream->ch[i].offset+2,vgmstream->ch[0].streamfile);
|
||||
}
|
||||
vgmstream->ch[i].offset+=4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void eacs_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
int i;
|
||||
off_t block_size=vgmstream->current_block_size;
|
||||
|
||||
if(read_32bitBE(block_offset,vgmstream->ch[0].streamfile)==0x31534E6C) {
|
||||
block_offset+=0x0C;
|
||||
}
|
||||
|
||||
vgmstream->current_block_offset = block_offset;
|
||||
|
||||
if(read_32bitBE(block_offset,vgmstream->ch[0].streamfile)==0x31534E64) { /* 1Snd */
|
||||
block_offset+=4;
|
||||
if(vgmstream->ea_platform==0)
|
||||
block_size=read_32bitLE(vgmstream->current_block_offset+0x04,
|
||||
vgmstream->ch[0].streamfile);
|
||||
else
|
||||
block_size=read_32bitBE(vgmstream->current_block_offset+0x04,
|
||||
vgmstream->ch[0].streamfile);
|
||||
block_offset+=4;
|
||||
}
|
||||
|
||||
vgmstream->current_block_size=block_size-8;
|
||||
|
||||
if(vgmstream->coding_type==coding_EACS_IMA) {
|
||||
init_get_high_nibble(vgmstream);
|
||||
vgmstream->current_block_size=read_32bitLE(block_offset,vgmstream->ch[0].streamfile);
|
||||
|
||||
for(i=0;i<vgmstream->channels;i++) {
|
||||
vgmstream->ch[i].adpcm_step_index = read_32bitLE(block_offset+0x04+i*4,vgmstream->ch[0].streamfile);
|
||||
vgmstream->ch[i].adpcm_history1_32 = read_32bitLE(block_offset+0x04+i*4+(4*vgmstream->channels),vgmstream->ch[0].streamfile);
|
||||
vgmstream->ch[i].offset = block_offset+0x14;
|
||||
}
|
||||
} else {
|
||||
if(vgmstream->coding_type==coding_PSX) {
|
||||
for (i=0;i<vgmstream->channels;i++)
|
||||
vgmstream->ch[i].offset = vgmstream->current_block_offset+8+(i*(vgmstream->current_block_size/2));
|
||||
} else {
|
||||
|
||||
for (i=0;i<vgmstream->channels;i++) {
|
||||
if(vgmstream->coding_type==coding_PCM16LE_int)
|
||||
vgmstream->ch[i].offset = block_offset+(i*2);
|
||||
else
|
||||
vgmstream->ch[i].offset = block_offset+i;
|
||||
}
|
||||
}
|
||||
vgmstream->current_block_size/=vgmstream->channels;
|
||||
}
|
||||
vgmstream->next_block_offset = vgmstream->current_block_offset +
|
||||
(off_t)block_size;
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
#include "layout.h"
|
||||
#include "../vgmstream.h"
|
||||
|
||||
/* set up for the block at the given offset */
|
||||
void emff_ps2_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
int i;
|
||||
|
||||
vgmstream->current_block_offset = block_offset;
|
||||
vgmstream->current_block_size = read_32bitLE(
|
||||
vgmstream->current_block_offset+0x10,
|
||||
vgmstream->ch[0].streamfile);
|
||||
vgmstream->next_block_offset = vgmstream->current_block_offset + vgmstream->current_block_size+0x20;
|
||||
vgmstream->current_block_size/=vgmstream->channels;
|
||||
|
||||
for (i=0;i<vgmstream->channels;i++) {
|
||||
vgmstream->ch[i].offset = vgmstream->current_block_offset+0x20+(vgmstream->current_block_size*i);
|
||||
}
|
||||
}
|
||||
|
||||
void emff_ngc_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
int i;
|
||||
|
||||
vgmstream->current_block_offset = block_offset;
|
||||
vgmstream->current_block_size = read_32bitBE(
|
||||
vgmstream->current_block_offset+0x20,
|
||||
vgmstream->ch[0].streamfile);
|
||||
vgmstream->next_block_offset = vgmstream->current_block_offset + vgmstream->current_block_size+0x40;
|
||||
vgmstream->current_block_size/=vgmstream->channels;
|
||||
|
||||
for (i=0;i<vgmstream->channels;i++) {
|
||||
vgmstream->ch[i].offset = vgmstream->current_block_offset+0x40+(vgmstream->current_block_size*i);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
#include "layout.h"
|
||||
#include "../vgmstream.h"
|
||||
|
||||
/* set up for the block at the given offset */
|
||||
void filp_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
int i;
|
||||
|
||||
vgmstream->current_block_offset = block_offset;
|
||||
vgmstream->current_block_size = read_32bitLE(
|
||||
vgmstream->current_block_offset+0x18,
|
||||
vgmstream->ch[0].streamfile)-0x800;
|
||||
vgmstream->next_block_offset = vgmstream->current_block_offset+vgmstream->current_block_size+0x800;
|
||||
vgmstream->current_block_size/=vgmstream->channels;
|
||||
|
||||
for (i=0;i<vgmstream->channels;i++) {
|
||||
vgmstream->ch[i].offset = vgmstream->current_block_offset+0x800+(vgmstream->current_block_size*i);
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
#include "layout.h"
|
||||
#include "../vgmstream.h"
|
||||
|
||||
/* set up for the block at the given offset */
|
||||
void gsb_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
int i;
|
||||
|
||||
vgmstream->current_block_offset = block_offset;
|
||||
vgmstream->current_block_size = 0x10000; /*read_32bitLE(
|
||||
vgmstream->current_block_offset+0x10,
|
||||
vgmstream->ch[0].streamfile); */
|
||||
vgmstream->next_block_offset = vgmstream->current_block_offset + vgmstream->current_block_size+0x20;
|
||||
vgmstream->current_block_size/=vgmstream->channels;
|
||||
|
||||
for (i=0;i<vgmstream->channels;i++) {
|
||||
vgmstream->ch[i].offset = vgmstream->current_block_offset+0x20+(vgmstream->current_block_size*i);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
#include "layout.h"
|
||||
#include "../vgmstream.h"
|
||||
|
||||
/* set up for the block at the given offset */
|
||||
void halpst_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
int i;
|
||||
vgmstream->current_block_offset = block_offset;
|
||||
vgmstream->current_block_size = read_32bitBE(
|
||||
vgmstream->current_block_offset,
|
||||
vgmstream->ch[0].streamfile)/vgmstream->channels;
|
||||
vgmstream->next_block_offset = read_32bitBE(
|
||||
vgmstream->current_block_offset+8,
|
||||
vgmstream->ch[0].streamfile);
|
||||
|
||||
for (i=0;i<vgmstream->channels;i++) {
|
||||
vgmstream->ch[i].offset = vgmstream->current_block_offset +
|
||||
0x20 + vgmstream->current_block_size*i;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
#include "layout.h"
|
||||
#include "../vgmstream.h"
|
||||
|
||||
/* set up for the block at the given offset */
|
||||
void matx_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
int i;
|
||||
|
||||
vgmstream->current_block_offset = block_offset;
|
||||
vgmstream->current_block_size = read_32bitLE(
|
||||
vgmstream->current_block_offset,
|
||||
vgmstream->ch[0].streamfile);
|
||||
vgmstream->next_block_offset = vgmstream->current_block_offset + vgmstream->current_block_size + 8;
|
||||
vgmstream->current_block_size/=vgmstream->channels;
|
||||
|
||||
for (i=0;i<vgmstream->channels;i++) {
|
||||
vgmstream->ch[i].offset = vgmstream->current_block_offset + 8;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
#include "layout.h"
|
||||
#include "../vgmstream.h"
|
||||
|
||||
void render_vgmstream_interleave(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream) {
|
||||
int samples_written=0;
|
||||
|
||||
int frame_size = get_vgmstream_frame_size(vgmstream);
|
||||
int samples_per_frame = get_vgmstream_samples_per_frame(vgmstream);
|
||||
int samples_this_block;
|
||||
|
||||
samples_this_block = vgmstream->interleave_block_size / frame_size * samples_per_frame;
|
||||
|
||||
if (vgmstream->layout_type == layout_interleave_shortblock &&
|
||||
vgmstream->current_sample - vgmstream->samples_into_block + samples_this_block> vgmstream->num_samples) {
|
||||
frame_size = get_vgmstream_shortframe_size(vgmstream);
|
||||
samples_per_frame = get_vgmstream_samples_per_shortframe(vgmstream);
|
||||
|
||||
samples_this_block = vgmstream->interleave_smallblock_size / frame_size * samples_per_frame;
|
||||
}
|
||||
|
||||
while (samples_written<sample_count) {
|
||||
int samples_to_do;
|
||||
|
||||
if (vgmstream->loop_flag && vgmstream_do_loop(vgmstream)) {
|
||||
/* we assume that the loop is not back into a short block */
|
||||
if (vgmstream->layout_type == layout_interleave_shortblock) {
|
||||
frame_size = get_vgmstream_frame_size(vgmstream);
|
||||
samples_per_frame = get_vgmstream_samples_per_frame(vgmstream);
|
||||
samples_this_block = vgmstream->interleave_block_size / frame_size * samples_per_frame;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
samples_to_do = vgmstream_samples_to_do(samples_this_block, samples_per_frame, vgmstream);
|
||||
/*printf("vgmstream_samples_to_do(samples_this_block=%d,samples_per_frame=%d,vgmstream) returns %d\n",samples_this_block,samples_per_frame,samples_to_do);*/
|
||||
|
||||
if (samples_written+samples_to_do > sample_count)
|
||||
samples_to_do=sample_count-samples_written;
|
||||
|
||||
decode_vgmstream(vgmstream, samples_written, samples_to_do, buffer);
|
||||
|
||||
samples_written += samples_to_do;
|
||||
vgmstream->current_sample += samples_to_do;
|
||||
vgmstream->samples_into_block+=samples_to_do;
|
||||
|
||||
if (vgmstream->samples_into_block==samples_this_block) {
|
||||
int chan;
|
||||
if (vgmstream->layout_type == layout_interleave_shortblock &&
|
||||
vgmstream->current_sample + samples_this_block > vgmstream->num_samples) {
|
||||
frame_size = get_vgmstream_shortframe_size(vgmstream);
|
||||
samples_per_frame = get_vgmstream_samples_per_shortframe(vgmstream);
|
||||
|
||||
samples_this_block = vgmstream->interleave_smallblock_size / frame_size * samples_per_frame;
|
||||
for (chan=0;chan<vgmstream->channels;chan++)
|
||||
vgmstream->ch[chan].offset+=vgmstream->interleave_block_size*(vgmstream->channels-chan)+vgmstream->interleave_smallblock_size*chan;
|
||||
} else {
|
||||
|
||||
for (chan=0;chan<vgmstream->channels;chan++)
|
||||
vgmstream->ch[chan].offset+=vgmstream->interleave_block_size*vgmstream->channels;
|
||||
}
|
||||
vgmstream->samples_into_block=0;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
#include "layout.h"
|
||||
#include "../vgmstream.h"
|
||||
|
||||
/* for formats where the interleave is smaller than a frame, so we need to
|
||||
* deinterleave in memory before passing it along to a specialized decoder which
|
||||
* reads from memory
|
||||
*/
|
||||
|
||||
/* just do one frame at a time */
|
||||
|
||||
void render_vgmstream_interleave_byte(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream) {
|
||||
/* frame sizes are much smaller than this */
|
||||
uint8_t sample_data[0x400];
|
||||
int samples_written=0;
|
||||
|
||||
int frame_size = get_vgmstream_frame_size(vgmstream);
|
||||
int samples_per_frame = get_vgmstream_samples_per_frame(vgmstream);
|
||||
int samples_this_block;
|
||||
|
||||
samples_this_block = samples_per_frame;
|
||||
|
||||
while (samples_written<sample_count) {
|
||||
int samples_to_do;
|
||||
|
||||
if (vgmstream->loop_flag && vgmstream_do_loop(vgmstream)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
samples_to_do = vgmstream_samples_to_do(samples_this_block, samples_per_frame, vgmstream);
|
||||
|
||||
if (samples_written+samples_to_do > sample_count)
|
||||
samples_to_do=sample_count-samples_written;
|
||||
|
||||
{
|
||||
int i,j;
|
||||
for (j=0;j<vgmstream->channels;j++) {
|
||||
for (i=0;i<frame_size;i++) {
|
||||
sample_data[i] = read_8bit(vgmstream->ch[j].offset+
|
||||
i/vgmstream->interleave_block_size*
|
||||
vgmstream->interleave_block_size*
|
||||
vgmstream->channels+
|
||||
i%vgmstream->interleave_block_size,
|
||||
vgmstream->ch[j].streamfile);
|
||||
}
|
||||
decode_vgmstream_mem(vgmstream, samples_written,
|
||||
samples_to_do, buffer, sample_data, j);
|
||||
}
|
||||
}
|
||||
|
||||
samples_written += samples_to_do;
|
||||
vgmstream->current_sample += samples_to_do;
|
||||
vgmstream->samples_into_block+=samples_to_do;
|
||||
|
||||
if (vgmstream->samples_into_block==samples_this_block) {
|
||||
int chan;
|
||||
for (chan=0;chan<vgmstream->channels;chan++)
|
||||
vgmstream->ch[chan].offset+=frame_size*vgmstream->channels;
|
||||
vgmstream->samples_into_block=0;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
#include "layout.h"
|
||||
#include "../vgmstream.h"
|
||||
|
||||
/* set up for the block at the given offset */
|
||||
void ivaud_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
int i;
|
||||
off_t start_offset;
|
||||
off_t interleave_size;
|
||||
int32_t nextFrame=0;
|
||||
STREAMFILE *streamFile=vgmstream->ch[0].streamfile;
|
||||
|
||||
vgmstream->current_block_offset = block_offset;
|
||||
|
||||
nextFrame=(read_32bitLE(vgmstream->current_block_offset+0x28,streamFile)<<12)+0x800;
|
||||
|
||||
vgmstream->next_block_offset = vgmstream->current_block_offset + nextFrame;
|
||||
vgmstream->current_block_size=read_32bitLE(block_offset+0x24,streamFile)/2;
|
||||
|
||||
start_offset=vgmstream->current_block_offset + 0x800;
|
||||
interleave_size=(read_32bitLE(block_offset+0x28,streamFile)<<12)/2;
|
||||
|
||||
for(i=0;i<vgmstream->channels;i++) {
|
||||
vgmstream->ch[i].offset = start_offset + (i*interleave_size);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
#ifndef _LAYOUT_H
|
||||
#define _LAYOUT_H
|
||||
|
||||
#include "../streamtypes.h"
|
||||
#include "../vgmstream.h"
|
||||
|
||||
void ast_block_update(off_t block_ofset, VGMSTREAM * vgmstream);
|
||||
|
||||
void mxch_block_update(off_t block_ofset, VGMSTREAM * vgmstream);
|
||||
|
||||
void render_vgmstream_blocked(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream);
|
||||
|
||||
void halpst_block_update(off_t block_ofset, VGMSTREAM * vgmstream);
|
||||
|
||||
void xa_block_update(off_t block_offset, VGMSTREAM * vgmstream);
|
||||
|
||||
void ea_block_update(off_t block_offset, VGMSTREAM * vgmstream);
|
||||
|
||||
void eacs_block_update(off_t block_offset, VGMSTREAM * vgmstream);
|
||||
|
||||
void caf_block_update(off_t block_offset, VGMSTREAM * vgmstream);
|
||||
|
||||
void wsi_block_update(off_t block_offset, VGMSTREAM * vgmstream);
|
||||
|
||||
void str_snds_block_update(off_t block_offset, VGMSTREAM * vgmstream);
|
||||
|
||||
void ws_aud_block_update(off_t block_offset, VGMSTREAM * vgmstream);
|
||||
|
||||
void matx_block_update(off_t block_offset, VGMSTREAM * vgmstream);
|
||||
|
||||
void de2_block_update(off_t block_offset, VGMSTREAM * vgmstream);
|
||||
|
||||
void vs_block_update(off_t block_offset, VGMSTREAM * vgmstream);
|
||||
|
||||
void emff_ps2_block_update(off_t block_offset, VGMSTREAM * vgmstream);
|
||||
|
||||
void emff_ngc_block_update(off_t block_offset, VGMSTREAM * vgmstream);
|
||||
|
||||
void gsb_block_update(off_t block_offset, VGMSTREAM * vgmstream);
|
||||
|
||||
void xvas_block_update(off_t block_offset, VGMSTREAM * vgmstream);
|
||||
|
||||
void thp_block_update(off_t block_offset, VGMSTREAM * vgmstream);
|
||||
|
||||
void filp_block_update(off_t block_offset, VGMSTREAM * vgmstream);
|
||||
|
||||
void ivaud_block_update(off_t block_offset, VGMSTREAM * vgmstream);
|
||||
|
||||
void render_vgmstream_interleave(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream);
|
||||
|
||||
void render_vgmstream_nolayout(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream);
|
||||
|
||||
void render_vgmstream_interleave_byte(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream);
|
||||
|
||||
void render_vgmstream_mus_acm(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream);
|
||||
|
||||
void render_vgmstream_aix(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream);
|
||||
|
||||
void render_vgmstream_aax(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream);
|
||||
|
||||
void render_vgmstream_scd_int(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream);
|
||||
|
||||
void psx_mgav_block_update(off_t block_offset, VGMSTREAM * vgmstream);
|
||||
|
||||
void ps2_adm_block_update(off_t block_offset, VGMSTREAM * vgmstream);
|
||||
|
||||
void dsp_bdsp_block_update(off_t block_offset, VGMSTREAM * vgmstream);
|
||||
|
||||
void tra_block_update(off_t block_offset, VGMSTREAM * vgmstream);
|
||||
|
||||
void mtaf_block_update(off_t block_offset, VGMSTREAM * vgmstream);
|
||||
|
||||
void ps2_iab_block_update(off_t block_offset, VGMSTREAM * vgmstream);
|
||||
|
||||
void ps2_strlr_block_update(off_t block_offset, VGMSTREAM * vgmstream);
|
||||
|
||||
void ps2_mtaf_block_update(off_t block_ofset, VGMSTREAM * vgmstream);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,50 @@
|
|||
#include "layout.h"
|
||||
#include "../vgmstream.h"
|
||||
#include "../coding/acm_decoder.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
void render_vgmstream_mus_acm(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream) {
|
||||
int samples_written=0;
|
||||
mus_acm_codec_data *data = vgmstream->codec_data;
|
||||
|
||||
while (samples_written<sample_count) {
|
||||
ACMStream *acm = data->files[data->current_file];
|
||||
int samples_to_do;
|
||||
int samples_this_block = acm->total_values / acm->info.channels;
|
||||
|
||||
if (vgmstream->loop_flag && vgmstream_do_loop(vgmstream)) {
|
||||
data->current_file = data->loop_start_file;
|
||||
acm_reset(data->files[data->current_file]);
|
||||
vgmstream->samples_into_block = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
samples_to_do = vgmstream_samples_to_do(samples_this_block, 1, vgmstream);
|
||||
|
||||
/*printf("samples_to_do=%d,samples_this_block=%d,samples_written=%d,sample_count=%d\n",samples_to_do,samples_this_block,samples_written,sample_count);*/
|
||||
|
||||
if (samples_written+samples_to_do > sample_count)
|
||||
samples_to_do=sample_count-samples_written;
|
||||
|
||||
if (samples_to_do == 0)
|
||||
{
|
||||
data->current_file++;
|
||||
/*printf("next %d, %d samples\n",data->current_file,data->files[data->current_file]->total_values/data->files[data->current_file]->info.channels);*/
|
||||
/* force loop back to first file in case we're still playing for some
|
||||
* reason, prevent out of bounds stuff */
|
||||
if (data->current_file >= data->file_count) data->current_file = 0;
|
||||
acm_reset(data->files[data->current_file]);
|
||||
vgmstream->samples_into_block = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
/*printf("decode %d samples file %d\n",samples_to_do,data->current_file);*/
|
||||
decode_acm(acm,
|
||||
buffer+samples_written*vgmstream->channels,
|
||||
samples_to_do, vgmstream->channels);
|
||||
|
||||
samples_written += samples_to_do;
|
||||
vgmstream->current_sample += samples_to_do;
|
||||
vgmstream->samples_into_block+=samples_to_do;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
#include "layout.h"
|
||||
#include "../vgmstream.h"
|
||||
|
||||
//MxCh blocked layout as used by Lego Island
|
||||
void mxch_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
vgmstream->current_block_offset = block_offset;
|
||||
vgmstream->next_block_offset = block_offset +
|
||||
read_32bitLE(vgmstream->current_block_offset+4,vgmstream->ch[0].streamfile)+8;
|
||||
/* skip pad blocks */
|
||||
while (
|
||||
read_32bitBE(vgmstream->current_block_offset,
|
||||
vgmstream->ch[0].streamfile) == 0x70616420)
|
||||
{
|
||||
vgmstream->current_block_offset = vgmstream->next_block_offset;
|
||||
vgmstream->next_block_offset = vgmstream->current_block_offset +
|
||||
read_32bitLE(vgmstream->current_block_offset+4,vgmstream->ch[0].streamfile)+8;
|
||||
}
|
||||
vgmstream->current_block_size =
|
||||
read_32bitLE(vgmstream->current_block_offset+4, vgmstream->ch[0].streamfile)-0xe;
|
||||
// only one channel for now
|
||||
vgmstream->ch[0].offset = vgmstream->current_block_offset+8+0xe;
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
#include "layout.h"
|
||||
#include "../vgmstream.h"
|
||||
|
||||
void render_vgmstream_nolayout(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream) {
|
||||
int samples_written=0;
|
||||
|
||||
const int samples_this_block = vgmstream->num_samples;
|
||||
int samples_per_frame = get_vgmstream_samples_per_frame(vgmstream);
|
||||
|
||||
while (samples_written<sample_count) {
|
||||
int samples_to_do;
|
||||
|
||||
if (vgmstream->loop_flag && vgmstream_do_loop(vgmstream)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
samples_to_do = vgmstream_samples_to_do(samples_this_block, samples_per_frame, vgmstream);
|
||||
|
||||
if (samples_written+samples_to_do > sample_count)
|
||||
samples_to_do=sample_count-samples_written;
|
||||
|
||||
decode_vgmstream(vgmstream, samples_written, samples_to_do, buffer);
|
||||
|
||||
samples_written += samples_to_do;
|
||||
vgmstream->current_sample += samples_to_do;
|
||||
vgmstream->samples_into_block+=samples_to_do;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
#include "layout.h"
|
||||
#include "../vgmstream.h"
|
||||
|
||||
/* set up for the block at the given offset */
|
||||
void ps2_adm_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
int i;
|
||||
|
||||
vgmstream->current_block_offset = block_offset;
|
||||
vgmstream->current_block_size = 0x1000; /*read_32bitLE(
|
||||
vgmstream->current_block_offset+0x10,
|
||||
vgmstream->ch[0].streamfile); */
|
||||
vgmstream->next_block_offset = vgmstream->current_block_offset + vgmstream->current_block_size;
|
||||
//vgmstream->current_block_size/=vgmstream->channels;
|
||||
|
||||
for (i=0;i<vgmstream->channels;i++) {
|
||||
vgmstream->ch[i].offset = vgmstream->current_block_offset+(0x400*i);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
#include "layout.h"
|
||||
#include "../vgmstream.h"
|
||||
|
||||
/* set up for the block at the given offset */
|
||||
void ps2_iab_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
int i;
|
||||
|
||||
vgmstream->current_block_offset = block_offset;
|
||||
vgmstream->current_block_size = read_32bitLE(vgmstream->current_block_offset+0x08,vgmstream->ch[0].streamfile);
|
||||
vgmstream->next_block_offset = vgmstream->current_block_offset+vgmstream->current_block_size+0x10;
|
||||
vgmstream->current_block_size/=vgmstream->channels;
|
||||
|
||||
for (i=0;i<vgmstream->channels;i++) {
|
||||
vgmstream->ch[i].offset = vgmstream->current_block_offset+0x10+(vgmstream->current_block_size*i);
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
#include "layout.h"
|
||||
#include "../vgmstream.h"
|
||||
|
||||
/* set up for the block at the given offset */
|
||||
void ps2_strlr_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
int i;
|
||||
|
||||
vgmstream->current_block_offset = block_offset;
|
||||
vgmstream->current_block_size = read_32bitLE(
|
||||
vgmstream->current_block_offset+0x4,
|
||||
vgmstream->ch[0].streamfile)*2;
|
||||
vgmstream->next_block_offset = vgmstream->current_block_offset+vgmstream->current_block_size+0x40;
|
||||
//vgmstream->current_block_size/=vgmstream->channels;
|
||||
|
||||
for (i=0;i<vgmstream->channels;i++) {
|
||||
vgmstream->ch[i].offset = vgmstream->current_block_offset+0x20+(0x800*i);
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
#include "layout.h"
|
||||
#include "../vgmstream.h"
|
||||
|
||||
/* set up for the block at the given offset */
|
||||
void psx_mgav_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
int i;
|
||||
|
||||
vgmstream->current_block_offset = block_offset;
|
||||
vgmstream->current_block_size = read_32bitLE(vgmstream->current_block_offset+0x04,vgmstream->ch[0].streamfile)-0x1C;
|
||||
vgmstream->next_block_offset = vgmstream->current_block_offset+vgmstream->current_block_size+0x1C;
|
||||
vgmstream->current_block_size/=vgmstream->channels;
|
||||
|
||||
for (i=0;i<vgmstream->channels;i++) {
|
||||
vgmstream->ch[i].offset = vgmstream->current_block_offset+0x1C+(vgmstream->current_block_size*i);
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
#include "layout.h"
|
||||
#include "../vgmstream.h"
|
||||
|
||||
/* TODO: currently only properly handles mono substreams */
|
||||
/* TODO: there must be a reasonable way to respect the loop settings, as is
|
||||
the substreams are in their own little world */
|
||||
|
||||
#define INTERLEAVE_BUF_SIZE 512
|
||||
void render_vgmstream_scd_int(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream) {
|
||||
sample interleave_buf[INTERLEAVE_BUF_SIZE];
|
||||
int32_t samples_done = 0;
|
||||
scd_int_codec_data *data = vgmstream->codec_data;
|
||||
|
||||
while (samples_done < sample_count)
|
||||
{
|
||||
int32_t samples_to_do = INTERLEAVE_BUF_SIZE;
|
||||
int c;
|
||||
if (samples_to_do > sample_count - samples_done)
|
||||
samples_to_do = sample_count - samples_done;
|
||||
|
||||
for (c=0; c < data->substream_count; c++)
|
||||
{
|
||||
int32_t i;
|
||||
|
||||
render_vgmstream(interleave_buf,
|
||||
samples_to_do, data->substreams[c]);
|
||||
|
||||
for (i=0; i < samples_to_do; i++)
|
||||
{
|
||||
buffer[(samples_done+i)*data->substream_count + c] = interleave_buf[i];
|
||||
}
|
||||
}
|
||||
|
||||
samples_done += samples_to_do;
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
#include "layout.h"
|
||||
#include "../vgmstream.h"
|
||||
|
||||
/* set up for the block at the given offset */
|
||||
void str_snds_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
off_t current_chunk;
|
||||
size_t file_size;
|
||||
int i;
|
||||
STREAMFILE *streamfile;
|
||||
int FoundSSMP = 0;
|
||||
off_t SSMP_offset = -1;
|
||||
|
||||
current_chunk = block_offset;
|
||||
streamfile = vgmstream->ch[0].streamfile;
|
||||
file_size = get_streamfile_size(streamfile);
|
||||
|
||||
/* we may have to skip some chunks */
|
||||
while (!FoundSSMP && current_chunk < file_size) {
|
||||
if (current_chunk+read_32bitBE(current_chunk+4,streamfile)>=file_size)
|
||||
break;
|
||||
switch (read_32bitBE(current_chunk,streamfile)) {
|
||||
case 0x534e4453: /* SNDS */
|
||||
/* SSMP */
|
||||
if (read_32bitBE(current_chunk+0x10,streamfile)==0x53534d50) {
|
||||
FoundSSMP = 1;
|
||||
SSMP_offset = current_chunk;
|
||||
}
|
||||
break;
|
||||
case 0x46494c4c: /* FILL, the main culprit */
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
current_chunk += read_32bitBE(current_chunk+4,streamfile);
|
||||
}
|
||||
|
||||
if (!FoundSSMP) {
|
||||
/* if we couldn't find it all we can do is try playing the current
|
||||
* block, which is going to suck */
|
||||
vgmstream->current_block_offset = block_offset;
|
||||
}
|
||||
|
||||
vgmstream->current_block_offset = SSMP_offset;
|
||||
vgmstream->current_block_size = (read_32bitBE(
|
||||
vgmstream->current_block_offset+4,
|
||||
vgmstream->ch[0].streamfile) - 0x18) / vgmstream->channels;
|
||||
vgmstream->next_block_offset = vgmstream->current_block_offset +
|
||||
read_32bitBE(vgmstream->current_block_offset+4,
|
||||
vgmstream->ch[0].streamfile);
|
||||
|
||||
for (i=0;i<vgmstream->channels;i++) {
|
||||
vgmstream->ch[i].offset = vgmstream->current_block_offset + 0x18;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
#include "layout.h"
|
||||
#include "../vgmstream.h"
|
||||
|
||||
/* set up for the block at the given offset */
|
||||
void thp_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
int i,j;
|
||||
STREAMFILE *streamFile=vgmstream->ch[0].streamfile;
|
||||
off_t start_offset;
|
||||
int32_t nextFrameSize;
|
||||
|
||||
vgmstream->current_block_offset = block_offset;
|
||||
nextFrameSize=read_32bitBE(vgmstream->current_block_offset,streamFile);
|
||||
|
||||
vgmstream->next_block_offset = vgmstream->current_block_offset
|
||||
+ vgmstream->thpNextFrameSize;
|
||||
vgmstream->thpNextFrameSize=nextFrameSize;
|
||||
|
||||
start_offset=vgmstream->current_block_offset
|
||||
+ read_32bitBE(vgmstream->current_block_offset+0x08,streamFile)+0x10;
|
||||
vgmstream->current_block_size=read_32bitBE(start_offset,streamFile);
|
||||
start_offset+=8;
|
||||
|
||||
for(i=0;i<vgmstream->channels;i++) {
|
||||
for(j=0;j<16;j++) {
|
||||
vgmstream->ch[i].adpcm_coef[j]=read_16bitBE(start_offset+(i*0x20)+(j*2),streamFile);
|
||||
}
|
||||
vgmstream->ch[i].adpcm_history1_16=read_16bitBE(start_offset + (0x20*vgmstream->channels) + (i*4),streamFile);
|
||||
vgmstream->ch[i].adpcm_history2_16=read_16bitBE(start_offset + (0x20*vgmstream->channels) + (i*4) + 2,streamFile);
|
||||
vgmstream->ch[i].offset = start_offset + (0x24*vgmstream->channels)+(i*vgmstream->current_block_size);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
#include "layout.h"
|
||||
#include "../vgmstream.h"
|
||||
|
||||
/* set up for the block at the given offset (first 32bytes is useless for decoding) */
|
||||
void tra_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
int i;
|
||||
|
||||
vgmstream->current_block_offset = block_offset;
|
||||
vgmstream->current_block_size = 0x400;
|
||||
vgmstream->next_block_offset = vgmstream->current_block_offset+vgmstream->current_block_size+8;
|
||||
vgmstream->current_block_size/=vgmstream->channels;
|
||||
|
||||
for (i=0;i<vgmstream->channels;i++) {
|
||||
vgmstream->ch[i].offset = vgmstream->current_block_offset+(vgmstream->current_block_size*i)+0x4*(i+1);
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
#include "layout.h"
|
||||
#include "../vgmstream.h"
|
||||
|
||||
/* set up for the block at the given offset */
|
||||
void vs_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
int i;
|
||||
|
||||
for (i=0;i<vgmstream->channels;i++) {
|
||||
vgmstream->current_block_offset = block_offset;
|
||||
vgmstream->current_block_size = read_32bitLE(
|
||||
vgmstream->current_block_offset,
|
||||
vgmstream->ch[0].streamfile);
|
||||
vgmstream->next_block_offset = vgmstream->current_block_offset + vgmstream->current_block_size + 0x4;
|
||||
vgmstream->ch[i].offset = vgmstream->current_block_offset + 0x4;
|
||||
if(i==0) block_offset=vgmstream->next_block_offset;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
#include "layout.h"
|
||||
#include "../vgmstream.h"
|
||||
|
||||
/* set up for the block at the given offset */
|
||||
void ws_aud_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
int i;
|
||||
vgmstream->current_block_offset = block_offset;
|
||||
vgmstream->current_block_size = read_16bitLE(
|
||||
vgmstream->current_block_offset,
|
||||
vgmstream->ch[0].streamfile);
|
||||
vgmstream->next_block_offset = vgmstream->current_block_offset +
|
||||
vgmstream->current_block_size + 8;
|
||||
|
||||
if (vgmstream->coding_type == coding_WS) {
|
||||
vgmstream->ws_output_size = read_16bitLE(
|
||||
vgmstream->current_block_offset+2,
|
||||
vgmstream->ch[0].streamfile);
|
||||
}
|
||||
|
||||
for (i=0;i<vgmstream->channels;i++) {
|
||||
vgmstream->ch[i].offset = vgmstream->current_block_offset +
|
||||
8 + vgmstream->current_block_size*i;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
#include "layout.h"
|
||||
#include "../vgmstream.h"
|
||||
|
||||
/* set up for the block at the given offset */
|
||||
void wsi_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
int i;
|
||||
|
||||
/* assume that all channels have the same size for this block */
|
||||
|
||||
vgmstream->current_block_offset = block_offset;
|
||||
/* current_block_size is the data size in this block, so subtract header */
|
||||
vgmstream->current_block_size = read_32bitBE(
|
||||
vgmstream->current_block_offset,
|
||||
vgmstream->ch[0].streamfile) - 0x10;
|
||||
vgmstream->next_block_offset =
|
||||
vgmstream->current_block_offset +
|
||||
(vgmstream->current_block_size + 0x10) * vgmstream->channels;
|
||||
|
||||
for (i=0;i<vgmstream->channels;i++) {
|
||||
vgmstream->ch[i].offset = vgmstream->current_block_offset +
|
||||
0x10 + (vgmstream->current_block_size+0x10)*i;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
#include "layout.h"
|
||||
#include "../coding/coding.h"
|
||||
#include "../vgmstream.h"
|
||||
|
||||
/* set up for the block at the given offset */
|
||||
void xa_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
|
||||
int i;
|
||||
int8_t currentChannel=0;
|
||||
int8_t subAudio=0;
|
||||
|
||||
init_get_high_nibble(vgmstream);
|
||||
|
||||
if(vgmstream->samples_into_block!=0)
|
||||
// don't change this variable in the init process
|
||||
vgmstream->xa_sector_length+=128;
|
||||
|
||||
// We get to the end of a sector ?
|
||||
if(vgmstream->xa_sector_length==(18*128)) {
|
||||
vgmstream->xa_sector_length=0;
|
||||
|
||||
// 0x30 of unused bytes/sector :(
|
||||
if (!vgmstream->xa_headerless) {
|
||||
block_offset+=0x30;
|
||||
begin:
|
||||
// Search for selected channel & valid audio
|
||||
currentChannel=read_8bit(block_offset-7,vgmstream->ch[0].streamfile);
|
||||
subAudio=read_8bit(block_offset-6,vgmstream->ch[0].streamfile);
|
||||
|
||||
// audio is coded as 0x64
|
||||
if(!((subAudio==0x64) && (currentChannel==vgmstream->xa_channel))) {
|
||||
// go to next sector
|
||||
block_offset+=2352;
|
||||
if(currentChannel!=-1) goto begin;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vgmstream->current_block_offset = block_offset;
|
||||
|
||||
// Quid : how to stop the current channel ???
|
||||
// i set up 0 to current_block_size to make vgmstream not playing bad samples
|
||||
// another way to do it ???
|
||||
// (as the number of samples can be false in cd-xa due to multi-channels)
|
||||
vgmstream->current_block_size = (currentChannel==-1?0:112);
|
||||
|
||||
vgmstream->next_block_offset = vgmstream->current_block_offset+128;
|
||||
for (i=0;i<vgmstream->channels;i++) {
|
||||
vgmstream->ch[i].offset = vgmstream->current_block_offset;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
#include "layout.h"
|
||||
#include "../vgmstream.h"
|
||||
|
||||
/* set up for the block at the given offset */
|
||||
void xvas_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
int i;
|
||||
|
||||
vgmstream->current_block_offset = block_offset;
|
||||
|
||||
if((vgmstream->current_block_offset-get_streamfile_size(vgmstream->ch[0].streamfile))>(0x20000-0x20))
|
||||
vgmstream->current_block_size = 0x20000-0x20;
|
||||
else
|
||||
vgmstream->current_block_size = vgmstream->current_block_offset-get_streamfile_size(vgmstream->ch[0].streamfile)-0x20;
|
||||
|
||||
vgmstream->next_block_offset =
|
||||
vgmstream->current_block_offset +
|
||||
(vgmstream->current_block_size + 0x20);
|
||||
|
||||
for (i=0;i<vgmstream->channels;i++) {
|
||||
vgmstream->ch[i].offset = vgmstream->current_block_offset;
|
||||
}
|
||||
vgmstream->current_block_size /=2;
|
||||
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
#include "meta.h"
|
||||
#include "../util.h"
|
||||
|
||||
/* 2DX9 (found in beatmaniaIIDX16 - EMPRESS (Arcade) */
|
||||
VGMSTREAM * init_vgmstream_2dx9(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
char filename[PATH_LIMIT];
|
||||
off_t start_offset;
|
||||
|
||||
int loop_flag;
|
||||
int channel_count;
|
||||
|
||||
/* check extension, case insensitive */
|
||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||
if (strcasecmp("2dx9",filename_extension(filename))) goto fail;
|
||||
|
||||
/* check header */
|
||||
if (read_32bitBE(0x0,streamFile) != 0x32445839) /* 2DX9 */
|
||||
goto fail;
|
||||
if (read_32bitBE(0x18,streamFile) != 0x52494646) /* RIFF */
|
||||
goto fail;
|
||||
if (read_32bitBE(0x20,streamFile) != 0x57415645) /* WAVE */
|
||||
goto fail;
|
||||
if (read_32bitBE(0x24,streamFile) != 0x666D7420) /* fmt */
|
||||
goto fail;
|
||||
if (read_32bitBE(0x6a,streamFile) != 0x64617461) /* data */
|
||||
goto fail;
|
||||
|
||||
loop_flag = 0;
|
||||
channel_count = read_16bitLE(0x2e,streamFile);
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
/* fill in the vital statistics */
|
||||
start_offset = 0x72;
|
||||
vgmstream->channels = channel_count;
|
||||
vgmstream->sample_rate = read_32bitLE(0x30,streamFile);
|
||||
vgmstream->coding_type = coding_MSADPCM;
|
||||
vgmstream->num_samples = read_32bitLE(0x66,streamFile);
|
||||
vgmstream->layout_type = layout_none;
|
||||
vgmstream->interleave_block_size = read_16bitLE(0x38,streamFile);
|
||||
vgmstream->meta_type = meta_2DX9;
|
||||
|
||||
/* 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;
|
||||
}
|
|
@ -0,0 +1,303 @@
|
|||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
#include "../util.h"
|
||||
|
||||
/* .dsp w/ Cstr header, seen in Star Fox Assault and Donkey Konga */
|
||||
|
||||
VGMSTREAM * init_vgmstream_Cstr(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
char filename[PATH_LIMIT];
|
||||
|
||||
int loop_flag;
|
||||
off_t start_offset;
|
||||
off_t first_data;
|
||||
off_t loop_offset;
|
||||
size_t interleave;
|
||||
int loop_adjust;
|
||||
int double_loop_end = 0;
|
||||
|
||||
/* check extension, case insensitive */
|
||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||
if (strcasecmp("dsp",filename_extension(filename))) goto fail;
|
||||
|
||||
/* check header */
|
||||
if ((uint32_t)read_32bitBE(0,streamFile)!=0x43737472) /* "Cstr" */
|
||||
goto fail;
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr,"header ok\n");
|
||||
#endif
|
||||
|
||||
if (read_8bit(0x1b,streamFile)==1) {
|
||||
/* mono version, much simpler to handle */
|
||||
/* Only seen in R Racing Evolution radio sfx */
|
||||
|
||||
start_offset = 0x80;
|
||||
loop_flag = read_16bitBE(0x2c,streamFile);
|
||||
|
||||
/* check initial predictor/scale */
|
||||
if (read_16bitBE(0x5e,streamFile) != (uint8_t)read_8bit(start_offset,streamFile))
|
||||
goto fail;
|
||||
|
||||
/* check type==0 and gain==0 */
|
||||
if (read_16bitBE(0x2e,streamFile) || read_16bitBE(0x5c,streamFile))
|
||||
goto fail;
|
||||
|
||||
loop_offset = start_offset+read_32bitBE(0x10,streamFile);
|
||||
if (loop_flag) {
|
||||
if (read_16bitBE(0x64,streamFile) != (uint8_t)read_8bit(loop_offset,streamFile)) goto fail;
|
||||
}
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
|
||||
vgmstream = allocate_vgmstream(1,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
/* fill in the vital statistics */
|
||||
vgmstream->sample_rate = read_32bitBE(0x28,streamFile);
|
||||
vgmstream->num_samples = read_32bitBE(0x20,streamFile);
|
||||
|
||||
if (loop_flag) {
|
||||
vgmstream->loop_start_sample = dsp_nibbles_to_samples(
|
||||
read_32bitBE(0x30,streamFile));
|
||||
vgmstream->loop_end_sample = dsp_nibbles_to_samples(
|
||||
read_32bitBE(0x34,streamFile))+1;
|
||||
}
|
||||
|
||||
vgmstream->coding_type = coding_NGC_DSP;
|
||||
vgmstream->layout_type = layout_none;
|
||||
vgmstream->meta_type = meta_DSP_CSTR;
|
||||
|
||||
{
|
||||
int i;
|
||||
for (i=0;i<16;i++)
|
||||
vgmstream->ch[0].adpcm_coef[i]=read_16bitBE(0x3c+i*2,streamFile);
|
||||
}
|
||||
|
||||
/* open the file for reading by each channel */
|
||||
vgmstream->ch[0].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
|
||||
if (!vgmstream->ch[0].streamfile) goto fail;
|
||||
|
||||
vgmstream->ch[0].channel_start_offset=
|
||||
vgmstream->ch[0].offset=
|
||||
start_offset;
|
||||
|
||||
return vgmstream;
|
||||
} /* end mono */
|
||||
|
||||
interleave = read_16bitBE(0x06,streamFile);
|
||||
start_offset = 0xe0;
|
||||
first_data = start_offset+read_32bitBE(0x0c,streamFile);
|
||||
loop_flag = read_16bitBE(0x2c,streamFile);
|
||||
|
||||
if (!loop_flag) {
|
||||
/* Nonlooped tracks seem to follow no discernable pattern
|
||||
* with where they actually start.
|
||||
* But! with the magic of initial p/s redundancy, we can guess.
|
||||
*/
|
||||
while (first_data<start_offset+0x800 &&
|
||||
(read_16bitBE(0x5e,streamFile) != (uint8_t)read_8bit(first_data,streamFile) ||
|
||||
read_16bitBE(0xbe,streamFile) != (uint8_t)read_8bit(first_data+interleave,streamFile)))
|
||||
first_data+=8;
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr,"guessed first_data at %#x\n",first_data);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* check initial predictor/scale */
|
||||
if (read_16bitBE(0x5e,streamFile) != (uint8_t)read_8bit(first_data,streamFile))
|
||||
goto fail;
|
||||
if (read_16bitBE(0xbe,streamFile) != (uint8_t)read_8bit(first_data+interleave,streamFile))
|
||||
goto fail;
|
||||
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr,"p/s ok\n");
|
||||
#endif
|
||||
|
||||
/* check type==0 and gain==0 */
|
||||
if (read_16bitBE(0x2e,streamFile) || read_16bitBE(0x5c,streamFile))
|
||||
goto fail;
|
||||
if (read_16bitBE(0x8e,streamFile) || read_16bitBE(0xbc,streamFile))
|
||||
goto fail;
|
||||
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr,"type & gain ok\n");
|
||||
#endif
|
||||
|
||||
/* check for loop flag agreement */
|
||||
if (read_16bitBE(0x2c,streamFile) != read_16bitBE(0x8c,streamFile))
|
||||
goto fail;
|
||||
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr,"loop flags agree\n");
|
||||
#endif
|
||||
|
||||
loop_offset = start_offset+read_32bitBE(0x10,streamFile)*2;
|
||||
if (loop_flag) {
|
||||
int loops_ok=0;
|
||||
/* check loop predictor/scale */
|
||||
/* some fuzz allowed */
|
||||
for (loop_adjust=0;loop_adjust>=-0x10;loop_adjust-=8) {
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr,"looking for loop p/s at %#x,%#x\n",loop_offset-interleave+loop_adjust,loop_offset+loop_adjust);
|
||||
#endif
|
||||
if (read_16bitBE(0x64,streamFile) == (uint8_t)read_8bit(loop_offset-interleave+loop_adjust,streamFile) &&
|
||||
read_16bitBE(0xc4,streamFile) == (uint8_t)read_8bit(loop_offset+loop_adjust,streamFile)) {
|
||||
loops_ok=1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!loops_ok)
|
||||
for (loop_adjust=interleave;loop_adjust<=interleave+0x10;loop_adjust+=8) {
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr,"looking for loop p/s at %#x,%#x\n",loop_offset-interleave+loop_adjust,loop_offset+loop_adjust);
|
||||
#endif
|
||||
if (read_16bitBE(0x64,streamFile) == (uint8_t)read_8bit(loop_offset-interleave+loop_adjust,streamFile) &&
|
||||
read_16bitBE(0xc4,streamFile) == (uint8_t)read_8bit(loop_offset+loop_adjust,streamFile)) {
|
||||
loops_ok=1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!loops_ok) goto fail;
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr,"loop p/s ok (with %#4x adjust)\n",loop_adjust);
|
||||
#endif
|
||||
|
||||
/* check for agreement */
|
||||
/* loop end (channel 1 & 2 headers) */
|
||||
if (read_32bitBE(0x34,streamFile) != read_32bitBE(0x94,streamFile))
|
||||
goto fail;
|
||||
|
||||
/* Mr. Driller oddity */
|
||||
if (dsp_nibbles_to_samples(read_32bitBE(0x34,streamFile)*2)+1 <= read_32bitBE(0x20,streamFile)) {
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr,"loop end <= half total samples, should be doubled\n");
|
||||
#endif
|
||||
double_loop_end = 1;
|
||||
}
|
||||
|
||||
/* loop start (Cstr header and channel 1 header) */
|
||||
if (read_32bitBE(0x30,streamFile) != read_32bitBE(0x10,streamFile)
|
||||
#if 0
|
||||
/* this particular glitch only true for SFA, though it
|
||||
* seems like something similar happens in Donkey Konga */
|
||||
/* loop start (Cstr, channel 1 & 2 headers) */
|
||||
|| (read_32bitBE(0x0c,streamFile)+read_32bitLE(0x30,streamFile)) !=
|
||||
read_32bitBE(0x90,streamFile)
|
||||
#endif
|
||||
)
|
||||
/* alternatively (Donkey Konga) the header loop is 0x0c+0x10 */
|
||||
if (
|
||||
/* loop start (Cstr header and channel 1 header) */
|
||||
read_32bitBE(0x30,streamFile) != read_32bitBE(0x10,streamFile)+
|
||||
read_32bitBE(0x0c,streamFile))
|
||||
/* further alternatively (Donkey Konga), if we loop back to
|
||||
* the very first frame 0x30 might be 0x00000002 (which
|
||||
* is a *valid* std dsp loop start, imagine that) while 0x10
|
||||
* is 0x00000000 */
|
||||
if (!(read_32bitBE(0x30,streamFile) == 2 &&
|
||||
read_32bitBE(0x10,streamFile) == 0))
|
||||
/* lest there be too few alternatives, in Mr. Driller we
|
||||
* find that [0x30] + [0x0c] + 8 = [0x10]*2 */
|
||||
if (!(double_loop_end &&
|
||||
read_32bitBE(0x30,streamFile) +
|
||||
read_32bitBE(0x0c,streamFile) + 8 ==
|
||||
read_32bitBE(0x10,streamFile)*2))
|
||||
goto fail;
|
||||
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr,"loop points agree\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
/* assure that sample counts, sample rates agree */
|
||||
if (
|
||||
/* sample count (channel 1 & 2 headers) */
|
||||
read_32bitBE(0x20,streamFile) != read_32bitBE(0x80,streamFile) ||
|
||||
/* sample rate (channel 1 & 2 headers) */
|
||||
read_32bitBE(0x28,streamFile) != read_32bitBE(0x88,streamFile) ||
|
||||
/* sample count (Cstr header and channel 1 header) */
|
||||
read_32bitLE(0x14,streamFile) != read_32bitBE(0x20,streamFile) ||
|
||||
/* sample rate (Cstr header and channel 1 header) */
|
||||
(uint16_t)read_16bitLE(0x18,streamFile) != read_32bitBE(0x28,streamFile))
|
||||
goto fail;
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
|
||||
vgmstream = allocate_vgmstream(2,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
/* fill in the vital statistics */
|
||||
vgmstream->sample_rate = read_32bitBE(0x28,streamFile);
|
||||
/* This is a slight hack to counteract their hack.
|
||||
* All the data is ofset by first_data so that the loop
|
||||
* point occurs at a block boundary. However, I always begin decoding
|
||||
* right after the header, as that is the start of the first block and
|
||||
* my interleave code relies on starting at the beginning of a block.
|
||||
* So we decode a few silent samples at the beginning, and here we make up
|
||||
* for it by lengthening the track by that much.
|
||||
*/
|
||||
vgmstream->num_samples = read_32bitBE(0x20,streamFile) +
|
||||
(first_data-start_offset)/8*14;
|
||||
|
||||
if (loop_flag) {
|
||||
off_t loop_start_bytes = loop_offset-start_offset-interleave;
|
||||
vgmstream->loop_start_sample = dsp_nibbles_to_samples((loop_start_bytes/(2*interleave)*interleave+loop_start_bytes%(interleave*2))*2);
|
||||
/*dsp_nibbles_to_samples(loop_start_bytes);*/
|
||||
/*dsp_nibbles_to_samples(read_32bitBE(0x30,streamFile)*2-inter);*/
|
||||
vgmstream->loop_end_sample = dsp_nibbles_to_samples(
|
||||
read_32bitBE(0x34,streamFile))+1;
|
||||
|
||||
if (double_loop_end)
|
||||
vgmstream->loop_end_sample =
|
||||
dsp_nibbles_to_samples(read_32bitBE(0x34,streamFile)*2)+1;
|
||||
|
||||
if (vgmstream->loop_end_sample > vgmstream->num_samples) {
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr,"loop_end_sample > num_samples, adjusting\n");
|
||||
#endif
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
}
|
||||
}
|
||||
|
||||
vgmstream->coding_type = coding_NGC_DSP;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = interleave;
|
||||
vgmstream->meta_type = meta_DSP_CSTR;
|
||||
|
||||
{
|
||||
int i;
|
||||
for (i=0;i<16;i++)
|
||||
vgmstream->ch[0].adpcm_coef[i]=read_16bitBE(0x3c+i*2,streamFile);
|
||||
for (i=0;i<16;i++)
|
||||
vgmstream->ch[1].adpcm_coef[i]=read_16bitBE(0x9c+i*2,streamFile);
|
||||
}
|
||||
#ifdef DEBUG
|
||||
vgmstream->ch[0].loop_history1 = read_16bitBE(0x66,streamFile);
|
||||
vgmstream->ch[0].loop_history2 = read_16bitBE(0x68,streamFile);
|
||||
vgmstream->ch[1].loop_history1 = read_16bitBE(0xc6,streamFile);
|
||||
vgmstream->ch[1].loop_history2 = read_16bitBE(0xc8,streamFile);
|
||||
#endif
|
||||
|
||||
/* open the file for reading by each channel */
|
||||
{
|
||||
int i;
|
||||
for (i=0;i<2;i++) {
|
||||
vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,interleave);
|
||||
|
||||
if (!vgmstream->ch[i].streamfile) goto fail;
|
||||
|
||||
vgmstream->ch[i].channel_start_offset=
|
||||
vgmstream->ch[i].offset=
|
||||
start_offset+interleave*i;
|
||||
}
|
||||
}
|
||||
|
||||
return vgmstream;
|
||||
|
||||
/* clean up anything we may have opened */
|
||||
fail:
|
||||
if (vgmstream) close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
|
@ -0,0 +1,241 @@
|
|||
noinst_LTLIBRARIES = libmeta.la
|
||||
|
||||
AM_CFLAGS = -Wall @CFLAGS@ -I$(top_builddir) -I$(top_srcdir)
|
||||
AM_MAKEFLAGS=-f Makefile.unix
|
||||
|
||||
libmeta_la_LDFLAGS =
|
||||
libmeta_la_SOURCES =
|
||||
libmeta_la_SOURCES += Cstr.c
|
||||
libmeta_la_SOURCES += adx_header.c
|
||||
libmeta_la_SOURCES += afc_header.c
|
||||
libmeta_la_SOURCES += agsc.c
|
||||
libmeta_la_SOURCES += ast.c
|
||||
libmeta_la_SOURCES += brstm.c
|
||||
libmeta_la_SOURCES += ea_header.c
|
||||
libmeta_la_SOURCES += gcsw.c halpst.c
|
||||
libmeta_la_SOURCES += nds_strm.c
|
||||
libmeta_la_SOURCES += ngc_adpdtk.c
|
||||
libmeta_la_SOURCES += ngc_caf.c
|
||||
libmeta_la_SOURCES += ngc_dsp_std.c
|
||||
libmeta_la_SOURCES += ps2_ads.c
|
||||
libmeta_la_SOURCES += ps2_exst.c
|
||||
libmeta_la_SOURCES += ps2_ild.c
|
||||
libmeta_la_SOURCES += ps2_int.c
|
||||
libmeta_la_SOURCES += ps2_mib.c
|
||||
libmeta_la_SOURCES += ps2_mic.c
|
||||
libmeta_la_SOURCES += ps2_npsf.c
|
||||
libmeta_la_SOURCES += ps2_pnb.c
|
||||
libmeta_la_SOURCES += ps2_rxw.c
|
||||
libmeta_la_SOURCES += ps2_str.c
|
||||
libmeta_la_SOURCES += ps2_svag.c
|
||||
libmeta_la_SOURCES += ps2_vag.c
|
||||
libmeta_la_SOURCES += ps2_vpk.c
|
||||
libmeta_la_SOURCES += psx_cdxa.c
|
||||
libmeta_la_SOURCES += raw.c
|
||||
libmeta_la_SOURCES += rs03.c
|
||||
libmeta_la_SOURCES += rsf.c
|
||||
libmeta_la_SOURCES += rwsd.c
|
||||
libmeta_la_SOURCES += psx_gms.c
|
||||
libmeta_la_SOURCES += xbox_xwav.c
|
||||
libmeta_la_SOURCES += xbox_wavm.c
|
||||
libmeta_la_SOURCES += genh.c
|
||||
libmeta_la_SOURCES += ogg_vorbis_file.c
|
||||
libmeta_la_SOURCES += ps2_bmdx.c
|
||||
libmeta_la_SOURCES += aifc.c
|
||||
libmeta_la_SOURCES += str_snds.c
|
||||
libmeta_la_SOURCES += ws_aud.c
|
||||
libmeta_la_SOURCES += ahx.c
|
||||
libmeta_la_SOURCES += ivb.c
|
||||
libmeta_la_SOURCES += svs.c
|
||||
libmeta_la_SOURCES += riff.c
|
||||
libmeta_la_SOURCES += pos.c
|
||||
libmeta_la_SOURCES += nwa.c
|
||||
libmeta_la_SOURCES += ps2_rws.c
|
||||
libmeta_la_SOURCES += ps2_hgc1.c
|
||||
libmeta_la_SOURCES += xss.c
|
||||
libmeta_la_SOURCES += ps2_sl3.c
|
||||
libmeta_la_SOURCES += ps2_aus.c
|
||||
libmeta_la_SOURCES += fsb.c
|
||||
libmeta_la_SOURCES += rsd.c
|
||||
libmeta_la_SOURCES += rwx.c
|
||||
libmeta_la_SOURCES += xwb.c
|
||||
libmeta_la_SOURCES += ea_old.c
|
||||
libmeta_la_SOURCES += ps2_xa30.c
|
||||
libmeta_la_SOURCES += musc.c
|
||||
libmeta_la_SOURCES += ps2_leg.c
|
||||
libmeta_la_SOURCES += ps2_filp.c
|
||||
libmeta_la_SOURCES += ps2_ikm.c
|
||||
libmeta_la_SOURCES += musx.c
|
||||
libmeta_la_SOURCES += ps2_sfs.c
|
||||
libmeta_la_SOURCES += sat_dvi.c
|
||||
libmeta_la_SOURCES += ps2_bg00.c
|
||||
libmeta_la_SOURCES += dc_kcey.c
|
||||
libmeta_la_SOURCES += ps2_rstm.c
|
||||
libmeta_la_SOURCES += acm.c
|
||||
libmeta_la_SOURCES += ps2_kces.c
|
||||
libmeta_la_SOURCES += ps2_dxh.c
|
||||
libmeta_la_SOURCES += ps2_psh.c
|
||||
libmeta_la_SOURCES += mus_acm.c
|
||||
libmeta_la_SOURCES += sli.c
|
||||
libmeta_la_SOURCES += sfl.c
|
||||
libmeta_la_SOURCES += pcm.c
|
||||
libmeta_la_SOURCES += ps2_psw.c
|
||||
libmeta_la_SOURCES += rkv.c
|
||||
libmeta_la_SOURCES += ps2_vas.c
|
||||
libmeta_la_SOURCES += ps2_tec.c
|
||||
libmeta_la_SOURCES += ps2_enth.c
|
||||
libmeta_la_SOURCES += sdt.c
|
||||
libmeta_la_SOURCES += aix.c
|
||||
libmeta_la_SOURCES += ngc_tydsp.c
|
||||
libmeta_la_SOURCES += wvs.c
|
||||
libmeta_la_SOURCES += xbox_stma.c
|
||||
libmeta_la_SOURCES += xbox_ims.c
|
||||
libmeta_la_SOURCES += de2.c
|
||||
libmeta_la_SOURCES += dc_str.c
|
||||
libmeta_la_SOURCES += xbox_xmu.c
|
||||
libmeta_la_SOURCES += ngc_bh2pcm.c
|
||||
libmeta_la_SOURCES += sat_sap.c
|
||||
libmeta_la_SOURCES += dc_idvi.c
|
||||
libmeta_la_SOURCES += ps2_rnd.c
|
||||
libmeta_la_SOURCES += xbox_xvas.c
|
||||
libmeta_la_SOURCES += kraw.c
|
||||
libmeta_la_SOURCES += ps2_xa2.c
|
||||
libmeta_la_SOURCES += idsp.c
|
||||
libmeta_la_SOURCES += ngc_ymf.c
|
||||
libmeta_la_SOURCES += nds_sad.c
|
||||
libmeta_la_SOURCES += ps2_ccc.c
|
||||
libmeta_la_SOURCES += psx_fag.c
|
||||
libmeta_la_SOURCES += ps2_mihb.c
|
||||
libmeta_la_SOURCES += ngc_pdt.c
|
||||
libmeta_la_SOURCES += wii_mus.c
|
||||
libmeta_la_SOURCES += dc_asd.c
|
||||
libmeta_la_SOURCES += naomi_spsd.c
|
||||
libmeta_la_SOURCES += bgw.c
|
||||
libmeta_la_SOURCES += ps2_ass.c
|
||||
libmeta_la_SOURCES += ngc_waa_wac_wad_wam.c
|
||||
libmeta_la_SOURCES += seg.c
|
||||
libmeta_la_SOURCES += str_asr.c
|
||||
libmeta_la_SOURCES += zwdsp.c
|
||||
libmeta_la_SOURCES += gca.c
|
||||
libmeta_la_SOURCES += ish_isd.c
|
||||
libmeta_la_SOURCES += spt_spd.c
|
||||
libmeta_la_SOURCES += ydsp.c
|
||||
libmeta_la_SOURCES += gsp_gsb.c
|
||||
libmeta_la_SOURCES += ngc_ssm.c
|
||||
libmeta_la_SOURCES += msvp.c
|
||||
libmeta_la_SOURCES += ps2_joe.c
|
||||
libmeta_la_SOURCES += vs.c
|
||||
libmeta_la_SOURCES += vgs.c
|
||||
libmeta_la_SOURCES += dc_dcsw_dcs.c
|
||||
libmeta_la_SOURCES += wii_smp.c
|
||||
libmeta_la_SOURCES += ss_stream.c
|
||||
libmeta_la_SOURCES += emff.c
|
||||
libmeta_la_SOURCES += thp.c
|
||||
libmeta_la_SOURCES += wii_sts.c
|
||||
libmeta_la_SOURCES += capdsp.c
|
||||
libmeta_la_SOURCES += wii_sng.c
|
||||
libmeta_la_SOURCES += aax.c
|
||||
libmeta_la_SOURCES += ps2_p2bt.c
|
||||
libmeta_la_SOURCES += ps2_gbts.c
|
||||
libmeta_la_SOURCES += ngc_ffcc_str.c
|
||||
libmeta_la_SOURCES += sat_baka.c
|
||||
libmeta_la_SOURCES += nds_swav.c
|
||||
libmeta_la_SOURCES += vsf.c
|
||||
libmeta_la_SOURCES += nds_rrds.c
|
||||
libmeta_la_SOURCES += ps2_tk5.c
|
||||
libmeta_la_SOURCES += ads.c
|
||||
libmeta_la_SOURCES += wii_str.c
|
||||
libmeta_la_SOURCES += zsd.c
|
||||
libmeta_la_SOURCES += ps2_mcg.c
|
||||
libmeta_la_SOURCES += redspark.c
|
||||
libmeta_la_SOURCES += ivaud.c
|
||||
libmeta_la_SOURCES += ps2_vgs.c
|
||||
libmeta_la_SOURCES += ps2_sps.c
|
||||
libmeta_la_SOURCES += nds_hwas.c
|
||||
libmeta_la_SOURCES += ngc_lps.c
|
||||
libmeta_la_SOURCES += ps2_snd.c
|
||||
libmeta_la_SOURCES += naomi_adpcm.c
|
||||
libmeta_la_SOURCES += sd9.c
|
||||
libmeta_la_SOURCES += 2dx9.c
|
||||
libmeta_la_SOURCES += ngc_dsp_ygo.c
|
||||
libmeta_la_SOURCES += ps2_vgv.c
|
||||
libmeta_la_SOURCES += ngc_gcub.c
|
||||
libmeta_la_SOURCES += maxis_xa.c
|
||||
libmeta_la_SOURCES += ngc_sck_dsp.c
|
||||
libmeta_la_SOURCES += apple_caff.c
|
||||
libmeta_la_SOURCES += pc_mxst.c
|
||||
libmeta_la_SOURCES += pc_sob.c
|
||||
libmeta_la_SOURCES += exakt_sc.c
|
||||
libmeta_la_SOURCES += wii_bns.c
|
||||
libmeta_la_SOURCES += pona.c
|
||||
libmeta_la_SOURCES += xbox_hlwav.c
|
||||
libmeta_la_SOURCES += stx.c
|
||||
libmeta_la_SOURCES += ps2_stm.c
|
||||
libmeta_la_SOURCES += myspd.c
|
||||
libmeta_la_SOURCES += his.c
|
||||
libmeta_la_SOURCES += ps2_ast.c
|
||||
libmeta_la_SOURCES += dmsg_segh.c
|
||||
libmeta_la_SOURCES += ngc_dsp_konami.c
|
||||
libmeta_la_SOURCES += ps2_ster.c
|
||||
libmeta_la_SOURCES += bnsf.c
|
||||
libmeta_la_SOURCES += ps2_wb.c
|
||||
libmeta_la_SOURCES += s14_sss.c
|
||||
libmeta_la_SOURCES += ps2_gcm.c
|
||||
libmeta_la_SOURCES += ps2_smpl.c
|
||||
libmeta_la_SOURCES += ps2_msa.c
|
||||
libmeta_la_SOURCES += pc_smp.c
|
||||
libmeta_la_SOURCES += p3d.c
|
||||
libmeta_la_SOURCES += ps2_adsc.c
|
||||
libmeta_la_SOURCES += psx_str_mgav.c
|
||||
libmeta_la_SOURCES += ngc_bo2.c
|
||||
libmeta_la_SOURCES += ngc_dsp_mpds.c
|
||||
libmeta_la_SOURCES += ps2_khv.c
|
||||
libmeta_la_SOURCES += ps2_voi.c
|
||||
libmeta_la_SOURCES += dsp_sth_str.c
|
||||
libmeta_la_SOURCES += ps2_b1s.c
|
||||
libmeta_la_SOURCES += ps2_wad.c
|
||||
libmeta_la_SOURCES += ps2_lpcm.c
|
||||
libmeta_la_SOURCES += ps2_adm.c
|
||||
libmeta_la_SOURCES += dsp_bdsp.c
|
||||
libmeta_la_SOURCES += ps2_vms.c
|
||||
libmeta_la_SOURCES += ps2_xau.c
|
||||
libmeta_la_SOURCES += gh3_bar.c
|
||||
libmeta_la_SOURCES += ffw.c
|
||||
libmeta_la_SOURCES += ps2_jstm.c
|
||||
libmeta_la_SOURCES += ps3_xvag.c
|
||||
libmeta_la_SOURCES += ps3_cps.c
|
||||
libmeta_la_SOURCES += sqex_scd.c
|
||||
libmeta_la_SOURCES += ngc_nst_dsp.c
|
||||
libmeta_la_SOURCES += baf.c
|
||||
libmeta_la_SOURCES += ps3_msf.c
|
||||
libmeta_la_SOURCES += nub.c
|
||||
libmeta_la_SOURCES += ps3_past.c
|
||||
libmeta_la_SOURCES += ps3_sgh_sgb.c
|
||||
libmeta_la_SOURCES += ngca.c
|
||||
libmeta_la_SOURCES += wii_ras.c
|
||||
libmeta_la_SOURCES += ps2_spm.c
|
||||
libmeta_la_SOURCES += x360_tra.c
|
||||
libmeta_la_SOURCES += ps2_iab.c
|
||||
libmeta_la_SOURCES += ps2_strlr.c
|
||||
libmeta_la_SOURCES += lsf.c
|
||||
libmeta_la_SOURCES += ps3_vawx.c
|
||||
libmeta_la_SOURCES += pc_snds.c
|
||||
libmeta_la_SOURCES += ps2_wmus.c
|
||||
libmeta_la_SOURCES += mattel_hyperscan.c
|
||||
libmeta_la_SOURCES += ios_psnd.c
|
||||
libmeta_la_SOURCES += pc_adp.c
|
||||
libmeta_la_SOURCES += excitebots.c
|
||||
libmeta_la_SOURCES += ps2_mtaf.c
|
||||
libmeta_la_SOURCES += ps3_klbs.c
|
||||
libmeta_la_SOURCES += tun.c
|
||||
libmeta_la_SOURCES += wpd.c
|
||||
libmeta_la_SOURCES += mn_str.c
|
||||
libmeta_la_SOURCES += ps2_mss.c
|
||||
libmeta_la_SOURCES += ps2_hsf.c
|
||||
libmeta_la_SOURCES += ps3_ivag.c
|
||||
libmeta_la_SOURCES += ps2_2pfs.c
|
||||
libmeta_la_SOURCES += ubi_ckd.c
|
||||
libmeta_la_SOURCES += otm.c
|
||||
libmeta_la_SOURCES += bcstm.c
|
||||
|
||||
EXTRA_DIST = meta.h
|
|
@ -0,0 +1,846 @@
|
|||
#include "../vgmstream.h"
|
||||
#include "meta.h"
|
||||
#include "../util.h"
|
||||
|
||||
typedef struct _AAXSTREAMFILE
|
||||
{
|
||||
STREAMFILE sf;
|
||||
STREAMFILE *real_file;
|
||||
off_t start_physical_offset;
|
||||
size_t file_size;
|
||||
} AAXSTREAMFILE;
|
||||
|
||||
static STREAMFILE *open_aax_with_STREAMFILE(STREAMFILE *file,off_t start_offset,size_t file_size);
|
||||
|
||||
struct utf_query
|
||||
{
|
||||
/* if 0 */
|
||||
const char *name;
|
||||
int index;
|
||||
};
|
||||
|
||||
struct offset_size_pair
|
||||
{
|
||||
uint32_t offset;
|
||||
uint32_t size;
|
||||
};
|
||||
|
||||
struct utf_query_result
|
||||
{
|
||||
int valid; /* table is valid */
|
||||
int found;
|
||||
int type; /* one of COLUMN_TYPE_* */
|
||||
union
|
||||
{
|
||||
uint64_t value_u64;
|
||||
uint32_t value_u32;
|
||||
uint16_t value_u16;
|
||||
uint8_t value_u8;
|
||||
float value_float;
|
||||
struct offset_size_pair value_data;
|
||||
uint32_t value_string;
|
||||
} value;
|
||||
|
||||
/* info for the queried table */
|
||||
uint32_t rows;
|
||||
uint32_t name_offset;
|
||||
uint32_t string_table_offset;
|
||||
uint32_t data_offset;
|
||||
};
|
||||
|
||||
static struct utf_query_result analyze_utf(STREAMFILE *infile, long offset,
|
||||
const struct utf_query *query);
|
||||
|
||||
static struct utf_query_result query_utf(STREAMFILE *infile, long offset,
|
||||
const struct utf_query *query);
|
||||
|
||||
static struct utf_query_result query_utf_nofail(STREAMFILE *infile, const long offset,
|
||||
const struct utf_query *query, int *error);
|
||||
|
||||
static struct utf_query_result query_utf_key(STREAMFILE *infile, const long offset,
|
||||
int index, const char *name, int *error);
|
||||
|
||||
static uint8_t query_utf_1byte(STREAMFILE *infile, const long offset,
|
||||
int index, const char *name, int *error);
|
||||
|
||||
static struct offset_size_pair query_utf_data(STREAMFILE *infile, const long offset,
|
||||
int index, const char *name, int *error);
|
||||
|
||||
#define COLUMN_STORAGE_MASK 0xf0
|
||||
#define COLUMN_STORAGE_PERROW 0x50
|
||||
#define COLUMN_STORAGE_CONSTANT 0x30
|
||||
#define COLUMN_STORAGE_ZERO 0x10
|
||||
|
||||
#define COLUMN_TYPE_MASK 0x0f
|
||||
#define COLUMN_TYPE_DATA 0x0b
|
||||
#define COLUMN_TYPE_STRING 0x0a
|
||||
#define COLUMN_TYPE_FLOAT 0x08
|
||||
#define COLUMN_TYPE_8BYTE 0x06
|
||||
#define COLUMN_TYPE_4BYTE 0x04
|
||||
#define COLUMN_TYPE_2BYTE2 0x03
|
||||
#define COLUMN_TYPE_2BYTE 0x02
|
||||
#define COLUMN_TYPE_1BYTE2 0x01
|
||||
#define COLUMN_TYPE_1BYTE 0x00
|
||||
|
||||
struct utf_column_info
|
||||
{
|
||||
uint8_t type;
|
||||
const char *column_name;
|
||||
long constant_offset;
|
||||
};
|
||||
|
||||
struct utf_table_info
|
||||
{
|
||||
long table_offset;
|
||||
uint32_t table_size;
|
||||
uint32_t schema_offset;
|
||||
uint32_t rows_offset;
|
||||
uint32_t string_table_offset;
|
||||
uint32_t data_offset;
|
||||
const char *string_table;
|
||||
const char *table_name;
|
||||
uint16_t columns;
|
||||
uint16_t row_width;
|
||||
uint32_t rows;
|
||||
|
||||
const struct utf_column_info *schema;
|
||||
};
|
||||
|
||||
|
||||
/* Actual AAX init fcn */
|
||||
VGMSTREAM * init_vgmstream_aax(STREAMFILE *streamFile) {
|
||||
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
STREAMFILE * streamFileAAX = NULL;
|
||||
STREAMFILE * streamFileADX = NULL;
|
||||
char filename[PATH_LIMIT];
|
||||
off_t *segment_offset = NULL;
|
||||
off_t *segment_size = NULL;
|
||||
int32_t sample_count;
|
||||
int table_error = 0;
|
||||
|
||||
int loop_flag = 0;
|
||||
int32_t loop_start_sample=0;
|
||||
int32_t loop_end_sample=0;
|
||||
int loop_segment = 0;
|
||||
|
||||
aax_codec_data *data = NULL;
|
||||
|
||||
const long AAX_offset = 0;
|
||||
|
||||
int channel_count = 0, segment_count;
|
||||
int sample_rate = 0;
|
||||
|
||||
int i;
|
||||
|
||||
|
||||
long aax_data_offset;
|
||||
|
||||
/* check extension, case insensitive */
|
||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||
if (strcasecmp("aax",filename_extension(filename))) goto fail;
|
||||
|
||||
/* get AAX entry count, data offset */
|
||||
{
|
||||
struct utf_query_result result;
|
||||
long aax_string_table_offset;
|
||||
long aax_string_table_size;
|
||||
|
||||
result = query_utf_nofail(streamFile, AAX_offset, NULL, &table_error);
|
||||
if (table_error) goto fail;
|
||||
segment_count = result.rows;
|
||||
aax_string_table_offset = AAX_offset + 8 + result.string_table_offset;
|
||||
aax_data_offset = AAX_offset + 8 + result.data_offset;
|
||||
aax_string_table_size = aax_data_offset - aax_string_table_offset;
|
||||
|
||||
if (result.name_offset+4 > aax_string_table_size) goto fail;
|
||||
if (read_32bitBE(aax_string_table_offset + result.name_offset,
|
||||
streamFile) != 0x41415800) /* "AAX\0" */
|
||||
goto fail;
|
||||
}
|
||||
|
||||
segment_offset = calloc(segment_count,sizeof(off_t));
|
||||
if (!segment_offset)
|
||||
goto fail;
|
||||
segment_size = calloc(segment_count,sizeof(off_t));
|
||||
if (!segment_size)
|
||||
goto fail;
|
||||
|
||||
/* get offsets of constituent ADXs */
|
||||
for (i = 0; i < segment_count; i++)
|
||||
{
|
||||
struct offset_size_pair offset_size;
|
||||
offset_size = query_utf_data(streamFile, AAX_offset, i, "data", &table_error);
|
||||
if (table_error) goto fail;
|
||||
segment_offset[i] = aax_data_offset + offset_size.offset;
|
||||
segment_size[i] = offset_size.size;
|
||||
}
|
||||
|
||||
streamFileAAX = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
if (!streamFileAAX) goto fail;
|
||||
|
||||
data = malloc(sizeof(aax_codec_data));
|
||||
if (!data) goto fail;
|
||||
data->segment_count = segment_count;
|
||||
data->adxs = malloc(sizeof(STREAMFILE *)*segment_count);
|
||||
if (!data->adxs) goto fail;
|
||||
for (i=0;i<segment_count;i++) {
|
||||
data->adxs[i] = NULL;
|
||||
}
|
||||
data->sample_counts = calloc(segment_count,sizeof(int32_t));
|
||||
if (!data->sample_counts) goto fail;
|
||||
|
||||
/* for each segment */
|
||||
for (i = 0; i < segment_count; i++)
|
||||
{
|
||||
VGMSTREAM *adx;
|
||||
/*printf("try opening segment %d/%d %x\n",i,segment_count,segment_offset[i]);*/
|
||||
streamFileADX = open_aax_with_STREAMFILE(streamFileAAX,segment_offset[i],segment_size[i]);
|
||||
if (!streamFileADX) goto fail;
|
||||
adx = data->adxs[i] = init_vgmstream_adx(streamFileADX);
|
||||
if (!adx)
|
||||
goto fail;
|
||||
data->sample_counts[i] = adx->num_samples;
|
||||
close_streamfile(streamFileADX); streamFileADX = NULL;
|
||||
|
||||
if (i == 0)
|
||||
{
|
||||
channel_count = adx->channels;
|
||||
sample_rate = adx->sample_rate;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (channel_count != adx->channels)
|
||||
goto fail;
|
||||
if (sample_rate != adx->sample_rate)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (adx->loop_flag != 0)
|
||||
goto fail;
|
||||
|
||||
/* save start things so we can restart for seeking/looping */
|
||||
/* copy the channels */
|
||||
memcpy(adx->start_ch,adx->ch,sizeof(VGMSTREAMCHANNEL)*adx->channels);
|
||||
/* copy the whole VGMSTREAM */
|
||||
memcpy(adx->start_vgmstream,adx,sizeof(VGMSTREAM));
|
||||
|
||||
}
|
||||
|
||||
sample_count = 0;
|
||||
loop_flag = 0;
|
||||
for (i = 0; i < segment_count; i++)
|
||||
{
|
||||
int segment_loop_flag = query_utf_1byte(streamFile, AAX_offset, i,
|
||||
"lpflg", &table_error);
|
||||
if (table_error) segment_loop_flag = 0;
|
||||
|
||||
if (!loop_flag && segment_loop_flag)
|
||||
{
|
||||
loop_start_sample = sample_count;
|
||||
loop_segment = i;
|
||||
}
|
||||
|
||||
sample_count += data->sample_counts[i];
|
||||
|
||||
if (!loop_flag && segment_loop_flag)
|
||||
{
|
||||
loop_end_sample = sample_count;
|
||||
loop_flag = 1;
|
||||
}
|
||||
}
|
||||
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
|
||||
vgmstream->num_samples = sample_count;
|
||||
vgmstream->sample_rate = sample_rate;
|
||||
|
||||
vgmstream->loop_start_sample = loop_start_sample;
|
||||
vgmstream->loop_end_sample = loop_end_sample;
|
||||
|
||||
vgmstream->coding_type = data->adxs[0]->coding_type;
|
||||
vgmstream->layout_type = layout_aax;
|
||||
vgmstream->meta_type = meta_AAX;
|
||||
|
||||
vgmstream->ch[0].streamfile = streamFileAAX;
|
||||
data->current_segment = 0;
|
||||
data->loop_segment = loop_segment;
|
||||
|
||||
vgmstream->codec_data = data;
|
||||
free(segment_offset);
|
||||
free(segment_size);
|
||||
|
||||
return vgmstream;
|
||||
|
||||
/* clean up anything we may have opened */
|
||||
fail:
|
||||
if (streamFileAAX) close_streamfile(streamFileAAX);
|
||||
if (streamFileADX) close_streamfile(streamFileADX);
|
||||
if (vgmstream) close_vgmstream(vgmstream);
|
||||
if (segment_offset) free(segment_offset);
|
||||
if (segment_size) free(segment_size);
|
||||
if (data) {
|
||||
if (data->adxs)
|
||||
{
|
||||
int i;
|
||||
for (i=0;i<data->segment_count;i++)
|
||||
if (data->adxs)
|
||||
close_vgmstream(data->adxs[i]);
|
||||
free(data->adxs);
|
||||
}
|
||||
if (data->sample_counts)
|
||||
{
|
||||
free(data->sample_counts);
|
||||
}
|
||||
free(data);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* virtual file, a piece of the overall file */
|
||||
|
||||
static size_t read_aax(AAXSTREAMFILE *streamfile,uint8_t *dest,off_t offset,size_t length)
|
||||
{
|
||||
/* truncate at end of logical file */
|
||||
if (offset+length > streamfile->file_size)
|
||||
{
|
||||
long signed_length = length;
|
||||
signed_length = streamfile->file_size - offset;
|
||||
if (signed_length < 0) signed_length = 0;
|
||||
length = signed_length;
|
||||
}
|
||||
return read_streamfile(dest,
|
||||
streamfile->start_physical_offset+offset,
|
||||
length,streamfile->real_file);
|
||||
}
|
||||
|
||||
static void close_aax(AAXSTREAMFILE *streamfile)
|
||||
{
|
||||
free(streamfile);
|
||||
return;
|
||||
}
|
||||
|
||||
static size_t get_size_aax(AAXSTREAMFILE *streamfile)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static size_t get_offset_aax(AAXSTREAMFILE *streamfile)
|
||||
{
|
||||
long offset = streamfile->real_file->get_offset(streamfile->real_file);
|
||||
offset -= streamfile->start_physical_offset;
|
||||
if (offset < 0) offset = 0;
|
||||
if (offset > streamfile->file_size) offset = streamfile->file_size;
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
static void get_name_aax(AAXSTREAMFILE *streamfile,char *buffer,size_t length)
|
||||
{
|
||||
strncpy(buffer,"ARBITRARY.ADX",length);
|
||||
buffer[length-1]='\0';
|
||||
}
|
||||
|
||||
static STREAMFILE *open_aax_impl(AAXSTREAMFILE *streamfile,const char * const filename,size_t buffersize)
|
||||
{
|
||||
AAXSTREAMFILE *newfile;
|
||||
if (strcmp(filename,"ARBITRARY.ADX"))
|
||||
return NULL;
|
||||
|
||||
newfile = malloc(sizeof(AAXSTREAMFILE));
|
||||
if (!newfile)
|
||||
return NULL;
|
||||
memcpy(newfile,streamfile,sizeof(AAXSTREAMFILE));
|
||||
return &newfile->sf;
|
||||
}
|
||||
|
||||
static STREAMFILE *open_aax_with_STREAMFILE(STREAMFILE *file,off_t start_offset,size_t file_size)
|
||||
{
|
||||
AAXSTREAMFILE *streamfile = malloc(sizeof(AAXSTREAMFILE));
|
||||
|
||||
if (!streamfile)
|
||||
return NULL;
|
||||
|
||||
/* success, set our pointers */
|
||||
|
||||
streamfile->sf.read = (void*)read_aax;
|
||||
streamfile->sf.get_size = (void*)get_size_aax;
|
||||
streamfile->sf.get_offset = (void*)get_offset_aax;
|
||||
streamfile->sf.get_name = (void*)get_name_aax;
|
||||
streamfile->sf.get_realname = (void*)get_name_aax;
|
||||
streamfile->sf.open = (void*)open_aax_impl;
|
||||
streamfile->sf.close = (void*)close_aax;
|
||||
#ifdef PROFILE_STREAMFILE
|
||||
streamfile->sf.get_bytes_read = NULL;
|
||||
streamfile->sf.get_error_count = NULL;
|
||||
#endif
|
||||
|
||||
streamfile->real_file = file;
|
||||
streamfile->start_physical_offset = start_offset;
|
||||
streamfile->file_size = file_size;
|
||||
|
||||
return &streamfile->sf;
|
||||
}
|
||||
|
||||
/* @UTF table reading, abridged */
|
||||
static struct utf_query_result analyze_utf(STREAMFILE *infile, const long offset, const struct utf_query *query)
|
||||
{
|
||||
unsigned char buf[4];
|
||||
struct utf_table_info table_info;
|
||||
char *string_table = NULL;
|
||||
struct utf_column_info * schema = NULL;
|
||||
struct utf_query_result result;
|
||||
uint32_t table_name_string;
|
||||
int string_table_size;
|
||||
|
||||
result.valid = 0;
|
||||
|
||||
table_info.table_offset = offset;
|
||||
|
||||
/* check header */
|
||||
{
|
||||
static const char UTF_signature[4] = "@UTF"; /* intentionally unterminated */
|
||||
if (4 != read_streamfile(buf, offset, 4, infile)) goto cleanup_error;
|
||||
if (memcmp(buf, UTF_signature, sizeof(UTF_signature)))
|
||||
{
|
||||
goto cleanup_error;
|
||||
}
|
||||
}
|
||||
|
||||
/* get table size */
|
||||
table_info.table_size = read_32bitBE(offset+4, infile);
|
||||
|
||||
table_info.schema_offset = 0x20;
|
||||
table_info.rows_offset = read_32bitBE(offset+8, infile);
|
||||
table_info.string_table_offset = read_32bitBE(offset+0xc,infile);
|
||||
table_info.data_offset = read_32bitBE(offset+0x10,infile);
|
||||
table_name_string = read_32bitBE(offset+0x14,infile);
|
||||
table_info.columns = read_16bitBE(offset+0x18,infile);
|
||||
table_info.row_width = read_16bitBE(offset+0x1a,infile);
|
||||
table_info.rows = read_32bitBE(offset+0x1c,infile);
|
||||
|
||||
/* allocate for string table */
|
||||
string_table_size = table_info.data_offset-table_info.string_table_offset;
|
||||
string_table = malloc(string_table_size+1);
|
||||
if (!string_table) goto cleanup_error;
|
||||
table_info.string_table = string_table;
|
||||
memset(string_table, 0, string_table_size+1);
|
||||
|
||||
/* load schema */
|
||||
schema = malloc(sizeof(struct utf_column_info) * table_info.columns);
|
||||
if (!schema) goto cleanup_error;
|
||||
|
||||
{
|
||||
int i;
|
||||
long schema_current_offset = table_info.schema_offset;
|
||||
for (i = 0; i < table_info.columns; i++)
|
||||
{
|
||||
schema[i].type = read_8bit(schema_current_offset,infile);
|
||||
schema_current_offset ++;
|
||||
schema[i].column_name = string_table + read_32bitBE(schema_current_offset,infile);
|
||||
schema_current_offset += 4;
|
||||
|
||||
if ((schema[i].type & COLUMN_STORAGE_MASK) == COLUMN_STORAGE_CONSTANT)
|
||||
{
|
||||
schema[i].constant_offset = schema_current_offset;
|
||||
switch (schema[i].type & COLUMN_TYPE_MASK)
|
||||
{
|
||||
case COLUMN_TYPE_8BYTE:
|
||||
case COLUMN_TYPE_DATA:
|
||||
schema_current_offset+=8;
|
||||
break;
|
||||
case COLUMN_TYPE_STRING:
|
||||
case COLUMN_TYPE_FLOAT:
|
||||
case COLUMN_TYPE_4BYTE:
|
||||
schema_current_offset+=4;
|
||||
break;
|
||||
case COLUMN_TYPE_2BYTE2:
|
||||
case COLUMN_TYPE_2BYTE:
|
||||
schema_current_offset+=2;
|
||||
break;
|
||||
case COLUMN_TYPE_1BYTE2:
|
||||
case COLUMN_TYPE_1BYTE:
|
||||
schema_current_offset++;
|
||||
break;
|
||||
default:
|
||||
goto cleanup_error;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
table_info.schema = schema;
|
||||
|
||||
/* read string table */
|
||||
read_streamfile((unsigned char *)string_table,
|
||||
table_info.string_table_offset+8+offset,
|
||||
string_table_size, infile);
|
||||
table_info.table_name = table_info.string_table+table_name_string;
|
||||
|
||||
/* fill in the default stuff */
|
||||
result.found = 0;
|
||||
result.rows = table_info.rows;
|
||||
result.name_offset = table_name_string;
|
||||
result.string_table_offset = table_info.string_table_offset;
|
||||
result.data_offset = table_info.data_offset;
|
||||
|
||||
/* explore the values */
|
||||
if (query) {
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < table_info.rows; i++)
|
||||
{
|
||||
uint32_t row_offset =
|
||||
table_info.table_offset + 8 + table_info.rows_offset +
|
||||
i * table_info.row_width;
|
||||
const uint32_t row_start_offset = row_offset;
|
||||
|
||||
if (query && i != query->index) continue;
|
||||
|
||||
for (j = 0; j < table_info.columns; j++)
|
||||
{
|
||||
uint8_t type = table_info.schema[j].type;
|
||||
long constant_offset = table_info.schema[j].constant_offset;
|
||||
int constant = 0;
|
||||
|
||||
int qthis = (query && i == query->index &&
|
||||
!strcmp(table_info.schema[j].column_name, query->name));
|
||||
|
||||
if (qthis)
|
||||
{
|
||||
result.found = 1;
|
||||
result.type = schema[j].type & COLUMN_TYPE_MASK;
|
||||
}
|
||||
|
||||
switch (schema[j].type & COLUMN_STORAGE_MASK)
|
||||
{
|
||||
case COLUMN_STORAGE_PERROW:
|
||||
break;
|
||||
case COLUMN_STORAGE_CONSTANT:
|
||||
constant = 1;
|
||||
break;
|
||||
case COLUMN_STORAGE_ZERO:
|
||||
if (qthis)
|
||||
{
|
||||
memset(&result.value, 0,
|
||||
sizeof(result.value));
|
||||
}
|
||||
continue;
|
||||
default:
|
||||
goto cleanup_error;
|
||||
}
|
||||
|
||||
if (1)
|
||||
{
|
||||
long data_offset;
|
||||
int bytes_read;
|
||||
|
||||
if (constant)
|
||||
{
|
||||
data_offset = constant_offset;
|
||||
}
|
||||
else
|
||||
{
|
||||
data_offset = row_offset;
|
||||
}
|
||||
|
||||
switch (type & COLUMN_TYPE_MASK)
|
||||
{
|
||||
case COLUMN_TYPE_STRING:
|
||||
{
|
||||
uint32_t string_offset;
|
||||
string_offset = read_32bitBE(data_offset, infile);
|
||||
bytes_read = 4;
|
||||
if (qthis)
|
||||
{
|
||||
result.value.value_string = string_offset;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case COLUMN_TYPE_DATA:
|
||||
{
|
||||
uint32_t vardata_offset, vardata_size;
|
||||
|
||||
vardata_offset = read_32bitBE(data_offset, infile);
|
||||
vardata_size = read_32bitBE(data_offset+4, infile);
|
||||
bytes_read = 8;
|
||||
if (qthis)
|
||||
{
|
||||
result.value.value_data.offset = vardata_offset;
|
||||
result.value.value_data.size = vardata_size;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case COLUMN_TYPE_8BYTE:
|
||||
{
|
||||
uint64_t value =
|
||||
read_32bitBE(data_offset, infile);
|
||||
value <<= 32;
|
||||
value |=
|
||||
read_32bitBE(data_offset+4, infile);
|
||||
if (qthis)
|
||||
{
|
||||
result.value.value_u64 = value;
|
||||
}
|
||||
bytes_read = 8;
|
||||
break;
|
||||
}
|
||||
case COLUMN_TYPE_4BYTE:
|
||||
{
|
||||
uint32_t value =
|
||||
read_32bitBE(data_offset, infile);
|
||||
if (qthis)
|
||||
{
|
||||
result.value.value_u32 = value;
|
||||
}
|
||||
bytes_read = 4;
|
||||
}
|
||||
break;
|
||||
case COLUMN_TYPE_2BYTE2:
|
||||
case COLUMN_TYPE_2BYTE:
|
||||
{
|
||||
uint16_t value =
|
||||
read_16bitBE(data_offset, infile);
|
||||
if (qthis)
|
||||
{
|
||||
result.value.value_u16 = value;
|
||||
}
|
||||
bytes_read = 2;
|
||||
}
|
||||
break;
|
||||
case COLUMN_TYPE_FLOAT:
|
||||
if (sizeof(float) == 4)
|
||||
{
|
||||
union {
|
||||
float float_value;
|
||||
uint32_t int_value;
|
||||
} int_float;
|
||||
|
||||
int_float.int_value = read_32bitBE(data_offset, infile);
|
||||
if (qthis)
|
||||
{
|
||||
result.value.value_float = int_float.float_value;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
read_32bitBE(data_offset, infile);
|
||||
if (qthis)
|
||||
{
|
||||
goto cleanup_error;
|
||||
}
|
||||
}
|
||||
bytes_read = 4;
|
||||
break;
|
||||
case COLUMN_TYPE_1BYTE2:
|
||||
case COLUMN_TYPE_1BYTE:
|
||||
{
|
||||
uint8_t value =
|
||||
read_8bit(data_offset, infile);
|
||||
if (qthis)
|
||||
{
|
||||
result.value.value_u8 = value;
|
||||
}
|
||||
bytes_read = 1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
goto cleanup_error;
|
||||
}
|
||||
|
||||
if (!constant)
|
||||
{
|
||||
row_offset += bytes_read;
|
||||
}
|
||||
} /* useless if end */
|
||||
} /* column for loop end */
|
||||
|
||||
if (row_offset - row_start_offset != table_info.row_width)
|
||||
goto cleanup_error;
|
||||
|
||||
if (query && i >= query->index) break;
|
||||
} /* row for loop end */
|
||||
} /* explore values block end */
|
||||
|
||||
//cleanup:
|
||||
|
||||
result.valid = 1;
|
||||
cleanup_error:
|
||||
|
||||
if (string_table)
|
||||
{
|
||||
free(string_table);
|
||||
string_table = NULL;
|
||||
}
|
||||
|
||||
if (schema)
|
||||
{
|
||||
free(schema);
|
||||
schema = NULL;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static struct utf_query_result query_utf(STREAMFILE *infile, const long offset, const struct utf_query *query)
|
||||
{
|
||||
return analyze_utf(infile, offset, query);
|
||||
}
|
||||
|
||||
static struct utf_query_result query_utf_nofail(STREAMFILE *infile, const long offset, const struct utf_query *query, int *error)
|
||||
{
|
||||
const struct utf_query_result result = query_utf(infile, offset, query);
|
||||
|
||||
if (error)
|
||||
{
|
||||
*error = 0;
|
||||
if (!result.valid) *error = 1;
|
||||
if (query && !result.found) *error = 1;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static struct utf_query_result query_utf_key(STREAMFILE *infile, const long offset, int index, const char *name, int *error)
|
||||
{
|
||||
struct utf_query query;
|
||||
query.index = index;
|
||||
query.name = name;
|
||||
|
||||
return query_utf_nofail(infile, offset, &query, error);
|
||||
}
|
||||
|
||||
static uint8_t query_utf_1byte(STREAMFILE *infile, const long offset, int index, const char *name, int *error)
|
||||
{
|
||||
struct utf_query_result result = query_utf_key(infile, offset, index, name, error);
|
||||
if (error)
|
||||
{
|
||||
if (result.type != COLUMN_TYPE_1BYTE) *error = 1;
|
||||
}
|
||||
return result.value.value_u8;
|
||||
}
|
||||
|
||||
static uint32_t query_utf_4byte(STREAMFILE *infile, const long offset, int index, const char *name, int *error)
|
||||
{
|
||||
struct utf_query_result result = query_utf_key(infile, offset, index, name, error);
|
||||
if (error)
|
||||
{
|
||||
if (result.type != COLUMN_TYPE_4BYTE) *error = 1;
|
||||
}
|
||||
return result.value.value_u32;
|
||||
}
|
||||
|
||||
static struct offset_size_pair query_utf_data(STREAMFILE *infile, const long offset,
|
||||
int index, const char *name, int *error)
|
||||
{
|
||||
struct utf_query_result result = query_utf_key(infile, offset, index, name, error);
|
||||
if (error)
|
||||
{
|
||||
if (result.type != COLUMN_TYPE_DATA) *error = 1;
|
||||
}
|
||||
return result.value.value_data;
|
||||
}
|
||||
|
||||
/* CRI's UTF wrapper around DSP */
|
||||
VGMSTREAM * init_vgmstream_utf_dsp(STREAMFILE *streamFile) {
|
||||
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
char filename[PATH_LIMIT];
|
||||
int table_error = 0;
|
||||
|
||||
int loop_flag = 0;
|
||||
|
||||
const long top_offset = 0;
|
||||
|
||||
int channel_count;
|
||||
int sample_rate;
|
||||
long sample_count;
|
||||
|
||||
long top_data_offset, segment_count;
|
||||
long body_offset, body_size;
|
||||
long header_offset, header_size;
|
||||
|
||||
/* check extension, case insensitive */
|
||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||
//if (strcasecmp("aax",filename_extension(filename))) goto fail;
|
||||
|
||||
/* get entry count, data offset */
|
||||
{
|
||||
struct utf_query_result result;
|
||||
long top_string_table_offset;
|
||||
long top_string_table_size;
|
||||
long name_offset;
|
||||
|
||||
result = query_utf_nofail(streamFile, top_offset, NULL, &table_error);
|
||||
if (table_error) goto fail;
|
||||
segment_count = result.rows;
|
||||
if (segment_count != 1) goto fail; // only simple stuff for now
|
||||
top_string_table_offset = top_offset + 8 + result.string_table_offset;
|
||||
top_data_offset = top_offset + 8 + result.data_offset;
|
||||
top_string_table_size = top_data_offset - top_string_table_offset;
|
||||
|
||||
if (result.name_offset+10 > top_string_table_size) goto fail;
|
||||
|
||||
name_offset = top_string_table_offset + result.name_offset;
|
||||
if (read_32bitBE(name_offset, streamFile) != 0x41445043 ||// "ADPC"
|
||||
read_32bitBE(name_offset+4, streamFile) != 0x4D5F5749 ||// "M_WI"
|
||||
read_16bitBE(name_offset+8, streamFile) != 0x4900) // "I\0"
|
||||
goto fail;
|
||||
}
|
||||
|
||||
{
|
||||
struct offset_size_pair offset_size;
|
||||
|
||||
offset_size = query_utf_data(streamFile, top_offset, 0, "data", &table_error);
|
||||
if (table_error) goto fail;
|
||||
body_offset = top_data_offset + offset_size.offset;
|
||||
body_size = offset_size.size;
|
||||
|
||||
offset_size = query_utf_data(streamFile, top_offset, 0, "header", &table_error);
|
||||
if (table_error) goto fail;
|
||||
header_offset = top_data_offset + offset_size.offset;
|
||||
header_size = offset_size.size;
|
||||
}
|
||||
|
||||
channel_count = query_utf_1byte(streamFile, top_offset, 0, "nch", &table_error);
|
||||
sample_count = query_utf_4byte(streamFile, top_offset, 0, "nsmpl", &table_error);
|
||||
sample_rate = query_utf_4byte(streamFile, top_offset, 0, "sfreq", &table_error);
|
||||
if (table_error) goto fail;
|
||||
if (channel_count != 1 && channel_count != 2) goto fail;
|
||||
if (header_size != channel_count * 0x60) goto fail;
|
||||
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
|
||||
vgmstream->num_samples = sample_count;
|
||||
vgmstream->sample_rate = sample_rate;
|
||||
|
||||
vgmstream->coding_type = coding_NGC_DSP;
|
||||
vgmstream->layout_type = layout_none;
|
||||
vgmstream->meta_type = meta_UTF_DSP;
|
||||
|
||||
{
|
||||
int i,j;
|
||||
long channel_size = (body_size+7)/8*8/channel_count;
|
||||
for (i = 0; i < channel_count; i++)
|
||||
{
|
||||
vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
if (!vgmstream->ch[i].streamfile) goto fail;
|
||||
vgmstream->ch[i].channel_start_offset =
|
||||
vgmstream->ch[i].offset = body_offset + i * channel_size;
|
||||
for (j=0;j<16;j++)
|
||||
{
|
||||
vgmstream->ch[i].adpcm_coef[j] =
|
||||
read_16bitBE(header_offset + 0x60*i + 0x1c + j*2, streamFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return vgmstream;
|
||||
|
||||
/* clean up anything we may have opened */
|
||||
fail:
|
||||
if (vgmstream) close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
#include "../vgmstream.h"
|
||||
#include "meta.h"
|
||||
#include "../util.h"
|
||||
#include "../coding/acm_decoder.h"
|
||||
|
||||
/* InterPlay ACM */
|
||||
/* The real work is done by libacm */
|
||||
VGMSTREAM * init_vgmstream_acm(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
ACMStream *acm_stream = NULL;
|
||||
mus_acm_codec_data *data;
|
||||
|
||||
char filename[PATH_LIMIT];
|
||||
|
||||
int loop_flag = 0;
|
||||
int channel_count;
|
||||
|
||||
/* check extension, case insensitive */
|
||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||
if (strcasecmp("acm",filename_extension(filename))) goto fail;
|
||||
|
||||
/* check header */
|
||||
if (read_32bitBE(0x0,streamFile) != 0x97280301)
|
||||
goto fail;
|
||||
|
||||
data = calloc(1,sizeof(mus_acm_codec_data));
|
||||
if (!data) goto fail;
|
||||
|
||||
data->files = calloc(1,sizeof(ACMStream *));
|
||||
if (!data->files) {
|
||||
free(data); data = NULL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* gonna do this a little backwards, open and parse the file
|
||||
before creating the vgmstream */
|
||||
|
||||
if (acm_open_decoder(&acm_stream,streamFile,filename) != ACM_OK) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
channel_count = acm_stream->info.channels;
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->channels = channel_count;
|
||||
vgmstream->sample_rate = acm_stream->info.rate;
|
||||
vgmstream->coding_type = coding_ACM;
|
||||
vgmstream->num_samples = acm_stream->total_values / acm_stream->info.channels;
|
||||
vgmstream->layout_type = layout_acm;
|
||||
vgmstream->meta_type = meta_ACM;
|
||||
|
||||
data->file_count = 1;
|
||||
data->current_file = 0;
|
||||
data->files[0] = acm_stream;
|
||||
/*data->end_file = -1;*/
|
||||
|
||||
vgmstream->codec_data = data;
|
||||
|
||||
return vgmstream;
|
||||
|
||||
/* clean up anything we may have opened */
|
||||
fail:
|
||||
if (vgmstream) close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
|
@ -0,0 +1,120 @@
|
|||
#include "meta.h"
|
||||
#include "../util.h"
|
||||
|
||||
/* ADS (from Gauntlet Dark Legends (GC)) */
|
||||
VGMSTREAM * init_vgmstream_ads(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
char filename[PATH_LIMIT];
|
||||
off_t start_offset;
|
||||
int loop_flag;
|
||||
int channel_count;
|
||||
int identifer_byte;
|
||||
|
||||
/* check extension, case insensitive */
|
||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||
if (strcasecmp("ads",filename_extension(filename))) goto fail;
|
||||
|
||||
/* check dhSS Header */
|
||||
if (read_32bitBE(0x00,streamFile) != 0x64685353)
|
||||
goto fail;
|
||||
|
||||
/* check dbSS Header */
|
||||
if (read_32bitBE(0x20,streamFile) != 0x64625353)
|
||||
goto fail;
|
||||
|
||||
loop_flag = 1;
|
||||
channel_count = read_32bitBE(0x10,streamFile);
|
||||
|
||||
if (channel_count > 0x2)
|
||||
goto fail;
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
/* fill in the vital statistics */
|
||||
identifer_byte = read_32bitBE(0x08,streamFile);
|
||||
switch (identifer_byte) {
|
||||
case 0x00000020:
|
||||
start_offset = 0xE8;
|
||||
vgmstream->channels = channel_count;
|
||||
vgmstream->sample_rate = read_32bitBE(0x0c,streamFile);
|
||||
vgmstream->coding_type = coding_NGC_DSP;
|
||||
vgmstream->num_samples = read_32bitBE(0x28,streamFile);
|
||||
if (loop_flag) {
|
||||
vgmstream->loop_start_sample = 0;
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
}
|
||||
|
||||
if (channel_count == 1){
|
||||
vgmstream->layout_type = layout_none;
|
||||
} else if (channel_count == 2){
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = read_32bitBE(0x14,streamFile);
|
||||
}
|
||||
break;
|
||||
case 0x00000021:
|
||||
start_offset = 0x28;
|
||||
vgmstream->channels = channel_count;
|
||||
vgmstream->sample_rate = read_32bitBE(0x0c,streamFile);
|
||||
vgmstream->coding_type = coding_INT_XBOX;
|
||||
vgmstream->num_samples = (read_32bitBE(0x24,streamFile) / 36 *64 / vgmstream->channels)-64; // to avoid the "pop" at the loop point
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x24;
|
||||
if (loop_flag) {
|
||||
vgmstream->loop_start_sample = 0;
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
|
||||
vgmstream->meta_type = meta_ADS;
|
||||
|
||||
{
|
||||
int i;
|
||||
for (i=0;i<16;i++)
|
||||
vgmstream->ch[0].adpcm_coef[i] = read_16bitBE(0x44+i*2,streamFile);
|
||||
if (channel_count == 2) {
|
||||
for (i=0;i<16;i++)
|
||||
vgmstream->ch[1].adpcm_coef[i] = read_16bitBE(0xA4+i*2,streamFile);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* open the file for reading */
|
||||
if (vgmstream->coding_type == coding_NGC_DSP) {
|
||||
int i,c;
|
||||
for (c=0;c<channel_count;c++) {
|
||||
for (i=0;i<16;i++) {
|
||||
vgmstream->ch[c].adpcm_coef[i] =
|
||||
read_16bitBE(0x44+c*0x60 +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=
|
||||
start_offset+vgmstream->interleave_block_size*i;
|
||||
vgmstream->ch[i].offset = vgmstream->ch[i].channel_start_offset;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
/* clean up anything we may have opened */
|
||||
if (vgmstream) close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
|
@ -0,0 +1,598 @@
|
|||
#ifdef _MSC_VER
|
||||
#define _USE_MATH_DEFINES
|
||||
#endif
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include "meta.h"
|
||||
|
||||
#include "../coding/coding.h"
|
||||
#include "../util.h"
|
||||
|
||||
static int find_key(STREAMFILE *file, uint8_t type, uint16_t *xor_start, uint16_t *xor_mult, uint16_t *xor_add);
|
||||
|
||||
VGMSTREAM * init_vgmstream_adx(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
off_t stream_offset;
|
||||
size_t filesize;
|
||||
uint16_t version_signature;
|
||||
int loop_flag=0;
|
||||
int channel_count;
|
||||
int32_t loop_start_offset=0;
|
||||
int32_t loop_end_offset=0;
|
||||
int32_t loop_start_sample=0;
|
||||
int32_t loop_end_sample=0;
|
||||
meta_t header_type;
|
||||
int16_t coef1, coef2;
|
||||
uint16_t cutoff;
|
||||
char filename[PATH_LIMIT];
|
||||
int coding_type = coding_CRI_ADX;
|
||||
uint16_t xor_start=0,xor_mult=0,xor_add=0;
|
||||
|
||||
/* check extension, case insensitive */
|
||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||
if (strcasecmp("adx",filename_extension(filename))) goto fail;
|
||||
|
||||
filesize = get_streamfile_size(streamFile);
|
||||
|
||||
/* check first 2 bytes */
|
||||
if ((uint16_t)read_16bitBE(0,streamFile)!=0x8000) goto fail;
|
||||
|
||||
/* get stream offset, check for CRI signature just before */
|
||||
stream_offset = (uint16_t)read_16bitBE(2,streamFile) + 4;
|
||||
if ((uint16_t)read_16bitBE(stream_offset-6,streamFile)!=0x2863 ||/* "(c" */
|
||||
(uint32_t)read_32bitBE(stream_offset-4,streamFile)!=0x29435249 /* ")CRI" */
|
||||
) goto fail;
|
||||
|
||||
/* check for encoding type */
|
||||
/* 2 is for some unknown fixed filter, 3 is standard ADX, 4 is
|
||||
* ADX with exponential scale, 0x11 is AHX */
|
||||
if (read_8bit(4,streamFile) != 3) goto fail;
|
||||
|
||||
/* check for frame size (only 18 is supported at the moment) */
|
||||
if (read_8bit(5,streamFile) != 18) goto fail;
|
||||
|
||||
/* check for bits per sample? (only 4 makes sense for ADX) */
|
||||
if (read_8bit(6,streamFile) != 4) goto fail;
|
||||
|
||||
/* check version signature, read loop info */
|
||||
version_signature = read_16bitBE(0x12,streamFile);
|
||||
/* encryption */
|
||||
if (version_signature == 0x0408) {
|
||||
if (find_key(streamFile, 8, &xor_start, &xor_mult, &xor_add))
|
||||
{
|
||||
coding_type = coding_CRI_ADX_enc_8;
|
||||
version_signature = 0x0400;
|
||||
}
|
||||
}
|
||||
else if (version_signature == 0x0409) {
|
||||
if (find_key(streamFile, 9, &xor_start, &xor_mult, &xor_add))
|
||||
{
|
||||
coding_type = coding_CRI_ADX_enc_9;
|
||||
version_signature = 0x0400;
|
||||
}
|
||||
}
|
||||
|
||||
if (version_signature == 0x0300) { /* type 03 */
|
||||
header_type = meta_ADX_03;
|
||||
if (stream_offset-6 >= 0x2c) { /* enough space for loop info? */
|
||||
loop_flag = (read_32bitBE(0x18,streamFile) != 0);
|
||||
loop_start_sample = read_32bitBE(0x1c,streamFile);
|
||||
loop_start_offset = read_32bitBE(0x20,streamFile);
|
||||
loop_end_sample = read_32bitBE(0x24,streamFile);
|
||||
loop_end_offset = read_32bitBE(0x28,streamFile);
|
||||
}
|
||||
} else if (version_signature == 0x0400) {
|
||||
|
||||
off_t ainf_info_length=0;
|
||||
|
||||
if((uint32_t)read_32bitBE(0x24,streamFile)==0x41494E46) /* AINF Header */
|
||||
ainf_info_length = (off_t)read_32bitBE(0x28,streamFile);
|
||||
|
||||
header_type = meta_ADX_04;
|
||||
if (stream_offset-ainf_info_length-6 >= 0x38) { /* enough space for loop info? */
|
||||
if (read_32bitBE(0x24,streamFile) == 0xFFFEFFFE)
|
||||
loop_flag = 0;
|
||||
else
|
||||
loop_flag = (read_32bitBE(0x24,streamFile) != 0);
|
||||
|
||||
loop_start_sample = read_32bitBE(0x28,streamFile);
|
||||
loop_start_offset = read_32bitBE(0x2c,streamFile);
|
||||
loop_end_sample = read_32bitBE(0x30,streamFile);
|
||||
loop_end_offset = read_32bitBE(0x34,streamFile);
|
||||
}
|
||||
} else if (version_signature == 0x0500) { /* found in some SFD : Buggy Heat, appears to have no loop */
|
||||
header_type = meta_ADX_05;
|
||||
} else goto fail; /* not a known/supported version signature */
|
||||
|
||||
/* At this point we almost certainly have an ADX file,
|
||||
* so let's build the VGMSTREAM. */
|
||||
|
||||
/* high-pass cutoff frequency, always 500 that I've seen */
|
||||
cutoff = (uint16_t)read_16bitBE(0x10,streamFile);
|
||||
|
||||
if (loop_start_sample == 0 && loop_end_sample == 0) {
|
||||
loop_flag = 0;
|
||||
}
|
||||
|
||||
channel_count = read_8bit(7,streamFile);
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
/* fill in the vital statistics */
|
||||
vgmstream->num_samples = read_32bitBE(0xc,streamFile);
|
||||
vgmstream->sample_rate = read_32bitBE(8,streamFile);
|
||||
/* channels and loop flag are set by allocate_vgmstream */
|
||||
vgmstream->loop_start_sample = loop_start_sample;
|
||||
vgmstream->loop_end_sample = loop_end_sample;
|
||||
|
||||
vgmstream->coding_type = coding_type;
|
||||
if (channel_count==1)
|
||||
vgmstream->layout_type = layout_none;
|
||||
else
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->meta_type = header_type;
|
||||
|
||||
vgmstream->interleave_block_size=18;
|
||||
|
||||
/* calculate filter coefficients */
|
||||
{
|
||||
double x,y,z,a,b,c;
|
||||
|
||||
x = cutoff;
|
||||
y = vgmstream->sample_rate;
|
||||
z = cos(2.0*M_PI*x/y);
|
||||
|
||||
a = M_SQRT2-z;
|
||||
b = M_SQRT2-1.0;
|
||||
c = (a-sqrt((a+b)*(a-b)))/b;
|
||||
|
||||
coef1 = floor(c*8192);
|
||||
coef2 = floor(c*c*-4096);
|
||||
}
|
||||
|
||||
{
|
||||
int i;
|
||||
STREAMFILE * chstreamfile;
|
||||
|
||||
/* ADX is so tightly interleaved that having two buffers is silly */
|
||||
chstreamfile = streamFile->open(streamFile,filename,18*0x400);
|
||||
if (!chstreamfile) goto fail;
|
||||
|
||||
for (i=0;i<channel_count;i++) {
|
||||
vgmstream->ch[i].streamfile = chstreamfile;
|
||||
|
||||
vgmstream->ch[i].channel_start_offset=
|
||||
vgmstream->ch[i].offset=
|
||||
stream_offset+18*i;
|
||||
|
||||
vgmstream->ch[i].adpcm_coef[0] = coef1;
|
||||
vgmstream->ch[i].adpcm_coef[1] = coef2;
|
||||
|
||||
if (coding_type == coding_CRI_ADX_enc_8 ||
|
||||
coding_type == coding_CRI_ADX_enc_9)
|
||||
{
|
||||
int j;
|
||||
vgmstream->ch[i].adx_channels = channel_count;
|
||||
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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return vgmstream;
|
||||
|
||||
/* clean up anything we may have opened */
|
||||
fail:
|
||||
if (vgmstream) close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* guessadx stuff */
|
||||
|
||||
/* type 8 keys */
|
||||
static struct {
|
||||
uint16_t start,mult,add;
|
||||
} keys_8[] = {
|
||||
/* Clover Studio (GOD HAND, Okami) */
|
||||
/* I'm pretty sure this is right, based on a decrypted version of some GOD HAND tracks. */
|
||||
/* Also it is the 2nd result from guessadx */
|
||||
{0x49e1,0x4a57,0x553d},
|
||||
|
||||
/* Grasshopper Manufacture 0 (Blood+) */
|
||||
/* this is estimated */
|
||||
{0x5f5d,0x58bd,0x55ed},
|
||||
|
||||
/* Grasshopper Manufacture 1 (Killer7) */
|
||||
/* this is estimated */
|
||||
{0x50fb,0x5803,0x5701},
|
||||
|
||||
/* Grasshopper Manufacture 2 (Samurai Champloo) */
|
||||
/* confirmed unique with guessadx */
|
||||
{0x4f3f,0x472f,0x562f},
|
||||
|
||||
/* Moss Ltd (Raiden III) */
|
||||
/* this is estimated */
|
||||
{0x66f5,0x58bd,0x4459},
|
||||
|
||||
/* Sonic Team 0 (Phantasy Star Universe) */
|
||||
/* this is estimated */
|
||||
{0x5deb,0x5f27,0x673f},
|
||||
|
||||
/* G.rev 0 (Senko no Ronde) */
|
||||
/* this is estimated */
|
||||
{0x46d3,0x5ced,0x474d},
|
||||
|
||||
/* Sonic Team 1 (NiGHTS: Journey of Dreams) */
|
||||
/* this seems to be dead on, but still estimated */
|
||||
{0x440b,0x6539,0x5723},
|
||||
|
||||
/* from guessadx (unique?), unknown source */
|
||||
{0x586d,0x5d65,0x63eb},
|
||||
|
||||
/* Navel (Shuffle! On the Stage) */
|
||||
/* 2nd key from guessadx */
|
||||
{0x4969,0x5deb,0x467f},
|
||||
|
||||
/* Success (Aoishiro) */
|
||||
/* 1st key from guessadx */
|
||||
{0x4d65,0x5eb7,0x5dfd},
|
||||
|
||||
/* Sonic Team 2 (Sonic and the Black Knight) */
|
||||
/* confirmed unique with guessadx */
|
||||
{0x55b7,0x6191,0x5a77},
|
||||
|
||||
/* Enterbrain (Amagami) */
|
||||
/* one of 32 from guessadx */
|
||||
{0x5a17,0x509f,0x5bfd},
|
||||
|
||||
/* Yamasa (Yamasa Digi Portable: Matsuri no Tatsujin) */
|
||||
/* confirmed unique with guessadx */
|
||||
{0x4c01,0x549d,0x676f},
|
||||
|
||||
/* Kadokawa Shoten (Fragments Blue) */
|
||||
/* confirmed unique with guessadx */
|
||||
{0x5803,0x4555,0x47bf},
|
||||
|
||||
/* Namco (Soulcalibur IV) */
|
||||
/* confirmed unique with guessadx */
|
||||
{0x59ed,0x4679,0x46c9},
|
||||
|
||||
/* G.rev 1 (Senko no Ronde DUO) */
|
||||
/* from guessadx */
|
||||
{0x6157,0x6809,0x4045},
|
||||
|
||||
/* ASCII Media Works 0 (Nogizaka Haruka no Himitsu: Cosplay Hajimemashita) */
|
||||
/* 2nd from guessadx, other was {0x45ad,0x5f27,0x10fd} */
|
||||
{0x45af,0x5f27,0x52b1},
|
||||
|
||||
/* D3 Publisher 0 (Little Anchor) */
|
||||
/* confirmed unique with guessadx */
|
||||
{0x5f65,0x5b3d,0x5f65},
|
||||
|
||||
/* Marvelous 0 (Hanayoi Romanesque: Ai to Kanashimi) */
|
||||
/* 2nd from guessadx, other was {0x5562,0x5047,0x1433} */
|
||||
{0x5563,0x5047,0x43ed},
|
||||
|
||||
/* Capcom (Mobile Suit Gundam: Gundam vs. Gundam NEXT PLUS) */
|
||||
/* confirmed unique with guessadx */
|
||||
{0x4f7b,0x4fdb,0x5cbf},
|
||||
|
||||
/* Developer: Bridge NetShop
|
||||
* Publisher: Kadokawa Shoten (Shoukan Shoujo: Elemental Girl Calling) */
|
||||
/* confirmed unique with guessadx */
|
||||
{0x4f7b,0x5071,0x4c61},
|
||||
|
||||
/* Developer: Net Corporation
|
||||
* Publisher: Tecmo (Rakushou! Pachi-Slot Sengen 6: Rio 2 Cruising Vanadis) */
|
||||
/* confirmed unique with guessadx */
|
||||
{0x53e9,0x586d,0x4eaf},
|
||||
|
||||
/* Developer: Aquaplus
|
||||
* Tears to Tiara Gaiden Avalon no Kagi (PS3) */
|
||||
/* confirmed unique with guessadx */
|
||||
{0x47e1,0x60e9,0x51c1},
|
||||
|
||||
/* Developer: Broccoli
|
||||
* Neon Genesis Evangelion: Koutetsu no Girlfriend 2nd (PS2) */
|
||||
/* confirmed unique with guessadx */
|
||||
{0x481d,0x4f25,0x5243},
|
||||
|
||||
/* Developer: Marvelous
|
||||
* Futakoi Alternative (PS2) */
|
||||
/* confirmed unique with guessadx */
|
||||
{0x413b,0x543b,0x57d1},
|
||||
|
||||
/* Developer: Marvelous
|
||||
* Gakuen Utopia - Manabi Straight! KiraKira Happy Festa! (PS2)
|
||||
* Second guess from guessadx, other was
|
||||
* {0x440b,0x4327,0x564b}
|
||||
**/
|
||||
{0x440d,0x4327,0x4fff},
|
||||
|
||||
/* Developer: Datam Polystar
|
||||
* Soshite Kono Uchuu ni Kirameku Kimi no Shi XXX (PS2) */
|
||||
/* confirmed unique with guessadx */
|
||||
{0x5f5d,0x552b,0x5507},
|
||||
|
||||
/* Developer: Sega
|
||||
* Sakura Taisen: Atsuki Chishio Ni (PS2) */
|
||||
/* confirmed unique with guessadx */
|
||||
{0x645d,0x6011,0x5c29},
|
||||
|
||||
/* Developer: Sega
|
||||
* Sakura Taisen 3 ~Paris wa Moeteiru ka~ (PS2) */
|
||||
/* confirmed unique with guessadx */
|
||||
{0x62ad,0x4b13,0x5957},
|
||||
|
||||
/* Developer: Jinx
|
||||
* Sotsugyou 2nd Generation (PS2)
|
||||
* First guess from guessadx, other was
|
||||
* {0x6307,0x509f,0x2ac5}
|
||||
*/
|
||||
{0x6305,0x509f,0x4c01},
|
||||
|
||||
/*
|
||||
* La Corda d'Oro (2005)(-)(Koei)[PSP]
|
||||
* confirmed unique with guessadx */
|
||||
{0x55b7,0x67e5,0x5387},
|
||||
|
||||
/*
|
||||
* Nanatsuiro * Drops Pure!! (2007)(Media Works)[PS2]
|
||||
* confirmed unique with guessadx */
|
||||
{0x6731,0x645d,0x566b},
|
||||
|
||||
/*
|
||||
* Shakugan no Shana (2006)(Vridge)(Media Works)[PS2]
|
||||
* confirmed unique with guessadx */
|
||||
{0x5fc5,0x63d9,0x599f},
|
||||
|
||||
/*
|
||||
* Uragiri wa Boku no Namae o Shitteiru (2010)(Kadokawa Shoten)[PS2]
|
||||
* confirmed unique with guessadx */
|
||||
{0x4c73,0x4d8d,0x5827},
|
||||
|
||||
/*
|
||||
* StormLover Kai!! (2012)(D3 Publisher)[PSP]
|
||||
* confirmed unique with guessadx */
|
||||
{0x5a11,0x67e5,0x6751},
|
||||
|
||||
/*
|
||||
* Sora no Otoshimono - DokiDoki Summer Vacation (2010)(Kadokawa Shoten)[PSP]
|
||||
* confirmed unique with guessadx */
|
||||
{0x5e75,0x4a89,0x4c61},
|
||||
|
||||
/*
|
||||
* Boku wa Koukuu Kanseikan - Airport Hero Naha (2006)(Sonic Powered)(Electronic Arts)[PSP]
|
||||
* confirmed unique with guessadx */
|
||||
{0x64ab,0x5297,0x632f},
|
||||
|
||||
/*
|
||||
* Lucky Star - Net Idol Meister (2009)(Kadokawa Shoten)[PSP]
|
||||
* confirmed unique with guessadx */
|
||||
{0x4d82,0x5243,0x685},
|
||||
|
||||
/*
|
||||
* Ishin Renka: Ryouma Gaiden (2010-11-25)(-)(D3 Publisher)[PSP]
|
||||
*/
|
||||
{0x54d1,0x526d,0x5e8b},
|
||||
|
||||
/*
|
||||
* Lucky Star - Ryouou Gakuen Outousai Portable (2010-12-22)(-)(Kadokawa Shoten)[PSP]
|
||||
*/
|
||||
{0x4d06,0x663b,0x7d09},
|
||||
|
||||
/*
|
||||
* Marriage Royale - Prism Story (2010-04-28)(-)(ASCII Media Works)[PSP]
|
||||
*/
|
||||
{0x40a9,0x46b1,0x62ad},
|
||||
|
||||
/*
|
||||
* Nogizaka Haruka no Himitsu - Doujinshi Hajime Mashita (2010-10-28)(-)(ASCII Media Works)[PSP]
|
||||
*/
|
||||
{0x4601,0x671f,0x0455},
|
||||
|
||||
/*
|
||||
* Slotter Mania P - Mach Go Go Go III (2011-01-06)(-)(Dorart)[PSP]
|
||||
*/
|
||||
{0x41ef,0x463d,0x5507},
|
||||
|
||||
/*
|
||||
* Nichijou - Uchuujin (2011-07-28)(-)(Kadokawa Shoten)[PSP]
|
||||
*/
|
||||
{0x4369,0x486d,0x5461},
|
||||
|
||||
/*
|
||||
* R-15 Portable (2011-10-27)(-)(Kadokawa Shoten)[PSP]
|
||||
*/
|
||||
{0x6809,0x5fd5,0x5bb1},
|
||||
|
||||
/*
|
||||
* Suzumiya Haruhi-chan no Mahjong (2011-07-07)(-)(Kadokawa Shoten)[PSP]
|
||||
*/
|
||||
{0x5c33,0x4133,0x4ce7},
|
||||
|
||||
};
|
||||
|
||||
/* type 9 keys */
|
||||
static struct {
|
||||
uint16_t start,mult,add;
|
||||
} keys_9[] = {
|
||||
/* Phantasy Star Online 2
|
||||
* guessed with degod */
|
||||
{0x07d2,0x1ec5,0x0c7f},
|
||||
};
|
||||
|
||||
static const int keys_8_count = sizeof(keys_8)/sizeof(keys_8[0]);
|
||||
static const int keys_9_count = sizeof(keys_9)/sizeof(keys_9[0]);
|
||||
|
||||
/* return 0 if not found, 1 if found and set parameters */
|
||||
static int find_key(STREAMFILE *file, uint8_t type, uint16_t *xor_start, uint16_t *xor_mult, uint16_t *xor_add)
|
||||
{
|
||||
uint16_t * scales = NULL;
|
||||
uint16_t * prescales = NULL;
|
||||
int bruteframe=0,bruteframecount=-1;
|
||||
int startoff, endoff;
|
||||
int rc = 0;
|
||||
|
||||
startoff=read_16bitBE(2, file)+4;
|
||||
endoff=(read_32bitBE(12, file)+31)/32*18*read_8bit(7, file)+startoff;
|
||||
|
||||
/* how many scales? */
|
||||
{
|
||||
int framecount=(endoff-startoff)/18;
|
||||
if (framecount<bruteframecount || bruteframecount<0)
|
||||
bruteframecount=framecount;
|
||||
}
|
||||
|
||||
/* find longest run of nonzero frames */
|
||||
{
|
||||
int longest=-1,longest_length=-1;
|
||||
int i;
|
||||
int length=0;
|
||||
for (i=0;i<bruteframecount;i++) {
|
||||
static const unsigned char zeroes[18]={0};
|
||||
unsigned char buf[18];
|
||||
read_streamfile(buf, startoff+i*18, 18, file);
|
||||
if (memcmp(zeroes,buf,18)) length++;
|
||||
else length=0;
|
||||
if (length > longest_length) {
|
||||
longest_length=length;
|
||||
longest=i-length+1;
|
||||
if (longest_length >= 0x8000) break;
|
||||
}
|
||||
}
|
||||
if (longest==-1) {
|
||||
goto find_key_cleanup;
|
||||
}
|
||||
bruteframecount = longest_length;
|
||||
bruteframe = longest;
|
||||
}
|
||||
|
||||
{
|
||||
/* try to guess key */
|
||||
#define MAX_FRAMES (INT_MAX/0x8000)
|
||||
int scales_to_do;
|
||||
int key_id;
|
||||
|
||||
/* allocate storage for scales */
|
||||
scales_to_do = (bruteframecount > MAX_FRAMES ? MAX_FRAMES : bruteframecount);
|
||||
scales = malloc(scales_to_do*sizeof(uint16_t));
|
||||
if (!scales) {
|
||||
goto find_key_cleanup;
|
||||
}
|
||||
/* prescales are those scales before the first frame we test
|
||||
* against, we use these to compute the actual start */
|
||||
if (bruteframe > 0) {
|
||||
int i;
|
||||
/* allocate memory for the prescales */
|
||||
prescales = malloc(bruteframe*sizeof(uint16_t));
|
||||
if (!prescales) {
|
||||
goto find_key_cleanup;
|
||||
}
|
||||
/* read the prescales */
|
||||
for (i=0; i<bruteframe; i++) {
|
||||
prescales[i] = read_16bitBE(startoff+i*18, file);
|
||||
}
|
||||
}
|
||||
|
||||
/* read in the scales */
|
||||
{
|
||||
int i;
|
||||
for (i=0; i < scales_to_do; i++) {
|
||||
scales[i] = read_16bitBE(startoff+(bruteframe+i)*18, file);
|
||||
}
|
||||
}
|
||||
|
||||
if (type == 8)
|
||||
{
|
||||
/* guess each of the keys */
|
||||
for (key_id=0;key_id<keys_8_count;key_id++) {
|
||||
/* test pre-scales */
|
||||
uint16_t xor = keys_8[key_id].start;
|
||||
uint16_t mult = keys_8[key_id].mult;
|
||||
uint16_t add = keys_8[key_id].add;
|
||||
int i;
|
||||
|
||||
for (i=0;i<bruteframe &&
|
||||
((prescales[i]&0x6000)==(xor&0x6000) ||
|
||||
prescales[i]==0);
|
||||
i++) {
|
||||
xor = xor * mult + add;
|
||||
}
|
||||
|
||||
if (i == bruteframe)
|
||||
{
|
||||
/* test */
|
||||
for (i=0;i<scales_to_do &&
|
||||
(scales[i]&0x6000)==(xor&0x6000);i++) {
|
||||
xor = xor * mult + add;
|
||||
}
|
||||
if (i == scales_to_do)
|
||||
{
|
||||
*xor_start = keys_8[key_id].start;
|
||||
*xor_mult = keys_8[key_id].mult;
|
||||
*xor_add = keys_8[key_id].add;
|
||||
|
||||
rc = 1;
|
||||
goto find_key_cleanup;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (type == 9)
|
||||
{
|
||||
/* smarter XOR as seen in PSO2, can't do an exact match so we
|
||||
* have to search for the lowest */
|
||||
long best_score = MAX_FRAMES * 0x1fff;
|
||||
|
||||
/* guess each of the keys */
|
||||
for (key_id=0;key_id<keys_9_count;key_id++) {
|
||||
/* run past pre-scales */
|
||||
uint16_t xor = keys_9[key_id].start;
|
||||
uint16_t mult = keys_9[key_id].mult;
|
||||
uint16_t add = keys_9[key_id].add;
|
||||
int i;
|
||||
long total_score = 0;
|
||||
|
||||
for (i=0;i<bruteframe;i++) {
|
||||
xor = xor * mult + add;
|
||||
}
|
||||
|
||||
if (i == bruteframe)
|
||||
{
|
||||
/* test */
|
||||
for (i=0;i<scales_to_do && total_score < best_score;i++) {
|
||||
xor = xor * mult + add;
|
||||
total_score += (scales[i]^xor)&0x1fff;
|
||||
}
|
||||
|
||||
if (total_score < best_score)
|
||||
{
|
||||
*xor_start = keys_9[key_id].start;
|
||||
*xor_mult = keys_9[key_id].mult;
|
||||
*xor_add = keys_9[key_id].add;
|
||||
|
||||
best_score = total_score;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* arbitrarily decide if we have won? */
|
||||
if (best_score < scales_to_do * 0x1000)
|
||||
{
|
||||
rc = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
find_key_cleanup:
|
||||
if (scales) free(scales);
|
||||
if (prescales) free(prescales);
|
||||
return rc;
|
||||
}
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
#include "meta.h"
|
||||
#include "../util.h"
|
||||
|
||||
VGMSTREAM * init_vgmstream_afc(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
char filename[PATH_LIMIT];
|
||||
|
||||
int loop_flag;
|
||||
const int channel_count = 2; /* .afc seems to be stereo only */
|
||||
|
||||
/* check extension, case insensitive */
|
||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||
if (strcasecmp("afc",filename_extension(filename))) goto fail;
|
||||
|
||||
/* don't grab AIFF-C with .afc extension */
|
||||
if ((uint32_t)read_32bitBE(0x0,streamFile)==0x464F524D) /* FORM */
|
||||
goto fail;
|
||||
|
||||
/* we will get a sample rate, that's as close to checking as I think
|
||||
* we can get */
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
|
||||
loop_flag = read_32bitBE(0x10,streamFile);
|
||||
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
/* fill in the vital statistics */
|
||||
vgmstream->num_samples = read_32bitBE(0x04,streamFile);
|
||||
vgmstream->sample_rate = (uint16_t)read_16bitBE(0x08,streamFile);
|
||||
/* channels and loop flag are set by allocate_vgmstream */
|
||||
vgmstream->loop_start_sample = read_32bitBE(0x14,streamFile);
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
|
||||
vgmstream->coding_type = coding_NGC_AFC;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->meta_type = meta_AFC;
|
||||
|
||||
/* frame-level interleave (9 bytes) */
|
||||
vgmstream->interleave_block_size = 9;
|
||||
|
||||
/* open the file for reading by each channel */
|
||||
{
|
||||
STREAMFILE *chstreamfile;
|
||||
int i;
|
||||
|
||||
/* both channels use same buffer, as interleave is so small */
|
||||
chstreamfile = streamFile->open(streamFile,filename,9*channel_count*0x100);
|
||||
if (!chstreamfile) goto fail;
|
||||
|
||||
for (i=0;i<channel_count;i++) {
|
||||
vgmstream->ch[i].streamfile = chstreamfile;
|
||||
|
||||
vgmstream->ch[i].channel_start_offset=
|
||||
vgmstream->ch[i].offset=
|
||||
0x20 + i*vgmstream->interleave_block_size;
|
||||
}
|
||||
}
|
||||
|
||||
return vgmstream;
|
||||
|
||||
/* clean up anything we may have opened */
|
||||
fail:
|
||||
if (vgmstream) close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
#include "meta.h"
|
||||
#include "../util.h"
|
||||
|
||||
/* .agsc - from Metroid Prime 2 */
|
||||
|
||||
VGMSTREAM * init_vgmstream_agsc(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
char filename[PATH_LIMIT];
|
||||
|
||||
off_t header_offset;
|
||||
off_t start_offset;
|
||||
int channel_count;
|
||||
int i;
|
||||
|
||||
/* check extension, case insensitive */
|
||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||
if (strcasecmp("agsc",filename_extension(filename))) goto fail;
|
||||
|
||||
/* check header */
|
||||
if ((uint32_t)read_32bitBE(0,streamFile)!=0x00000001)
|
||||
goto fail;
|
||||
|
||||
/* count length of name, including terminating 0 */
|
||||
for (header_offset=4;header_offset < get_streamfile_size(streamFile) && read_8bit(header_offset,streamFile)!='\0';header_offset++);
|
||||
|
||||
header_offset ++;
|
||||
|
||||
channel_count = 1;
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
|
||||
vgmstream = allocate_vgmstream(1,1);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
/* fill in the vital statistics */
|
||||
vgmstream->num_samples = read_32bitBE(header_offset+0xda,streamFile);
|
||||
vgmstream->sample_rate = (uint16_t)read_16bitBE(header_offset+0xd8,streamFile);
|
||||
|
||||
vgmstream->loop_start_sample = read_32bitBE(header_offset+0xde,streamFile);
|
||||
/* this is cute, we actually have a "loop length" */
|
||||
vgmstream->loop_end_sample = (vgmstream->loop_start_sample + read_32bitBE(header_offset+0xe2,streamFile))-1;
|
||||
|
||||
vgmstream->coding_type = coding_NGC_DSP;
|
||||
vgmstream->layout_type = layout_none;
|
||||
vgmstream->meta_type = meta_DSP_AGSC;
|
||||
|
||||
for (i=0;i<16;i++) {
|
||||
vgmstream->ch[0].adpcm_coef[i]=read_16bitBE(header_offset+0xf6+i*2,streamFile);
|
||||
}
|
||||
|
||||
start_offset = header_offset+0x116;
|
||||
|
||||
/* open the file for reading by each channel */
|
||||
{
|
||||
int i;
|
||||
for (i=0;i<channel_count;i++) {
|
||||
vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
|
||||
if (!vgmstream->ch[i].streamfile) goto fail;
|
||||
|
||||
vgmstream->ch[i].channel_start_offset=
|
||||
vgmstream->ch[i].offset=
|
||||
start_offset;
|
||||
}
|
||||
}
|
||||
|
||||
return vgmstream;
|
||||
|
||||
/* clean up anything we may have opened */
|
||||
fail:
|
||||
if (vgmstream) close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
|
@ -0,0 +1,121 @@
|
|||
#include "../vgmstream.h"
|
||||
|
||||
#ifdef VGM_USE_MPEG
|
||||
|
||||
#include "meta.h"
|
||||
#include "../util.h"
|
||||
|
||||
/* AHX is a CRI format which contains an MPEG-2 Layer 2 audio stream.
|
||||
* Although the MPEG frame headers are incorrect... */
|
||||
|
||||
VGMSTREAM * init_vgmstream_ahx(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
off_t stream_offset;
|
||||
size_t filesize;
|
||||
char filename[PATH_LIMIT];
|
||||
int channel_count = 1;
|
||||
int loop_flag = 0;
|
||||
mpeg_codec_data *data = NULL;
|
||||
|
||||
/* check extension, case insensitive */
|
||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||
if (strcasecmp("ahx",filename_extension(filename))) goto fail;
|
||||
|
||||
filesize = get_streamfile_size(streamFile);
|
||||
|
||||
/* check first 2 bytes */
|
||||
if ((uint16_t)read_16bitBE(0,streamFile)!=0x8000) goto fail;
|
||||
|
||||
/* get stream offset, check for CRI signature just before */
|
||||
stream_offset = (uint16_t)read_16bitBE(2,streamFile) + 4;
|
||||
if ((uint16_t)read_16bitBE(stream_offset-6,streamFile)!=0x2863 ||/* "(c" */
|
||||
(uint32_t)read_32bitBE(stream_offset-4,streamFile)!=0x29435249 /* ")CRI" */
|
||||
) goto fail;
|
||||
|
||||
/* check for encoding type */
|
||||
/* 2 is for some unknown fixed filter, 3 is standard ADX, 4 is
|
||||
* ADX with exponential scale, 0x11 is AHX */
|
||||
/* Sappharad reports that old AHXs (Sonic Adventure 2) don't have this flag.
|
||||
* When I see one perhaps I can add an exception for those. */
|
||||
if (read_8bit(4,streamFile) != 0x11) goto fail;
|
||||
|
||||
/* check for frame size (0 for AHX) */
|
||||
if (read_8bit(5,streamFile) != 0) goto fail;
|
||||
|
||||
/* check for bits per sample? (0 for AHX) */
|
||||
if (read_8bit(6,streamFile) != 0) goto fail;
|
||||
|
||||
/* check channel count (only mono AHXs are known) */
|
||||
if (read_8bit(7,streamFile) != 1) goto fail;
|
||||
|
||||
/* At this point we almost certainly have an ADX file,
|
||||
* so let's build the VGMSTREAM. */
|
||||
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
/* fill in the vital statistics */
|
||||
vgmstream->num_samples = read_32bitBE(0xc,streamFile);
|
||||
/* This is the One True Samplerate, the MPEG headers lie. */
|
||||
vgmstream->sample_rate = read_32bitBE(8,streamFile);
|
||||
|
||||
vgmstream->coding_type = coding_fake_MPEG2_L2;
|
||||
vgmstream->layout_type = layout_fake_mpeg;
|
||||
vgmstream->meta_type = meta_AHX;
|
||||
|
||||
{
|
||||
int i;
|
||||
STREAMFILE * chstreamfile;
|
||||
|
||||
chstreamfile = streamFile->open(streamFile,filename,
|
||||
STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
if (!chstreamfile) goto fail;
|
||||
|
||||
for (i=0;i<channel_count;i++) {
|
||||
vgmstream->ch[i].streamfile = chstreamfile;
|
||||
|
||||
vgmstream->ch[i].channel_start_offset=
|
||||
vgmstream->ch[i].offset=
|
||||
stream_offset;
|
||||
}
|
||||
}
|
||||
|
||||
/* ooh, fun part, set up mpg123 */
|
||||
{
|
||||
int rc;
|
||||
data = calloc(1,sizeof(mpeg_codec_data));
|
||||
if (!data) goto fail;
|
||||
|
||||
data->m = mpg123_new(NULL,&rc);
|
||||
if (rc==MPG123_NOT_INITIALIZED) {
|
||||
if (mpg123_init()!=MPG123_OK) goto fail;
|
||||
data->m = mpg123_new(NULL,&rc);
|
||||
if (rc!=MPG123_OK) goto fail;
|
||||
} else if (rc!=MPG123_OK) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (mpg123_open_feed(data->m)!=MPG123_OK) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
vgmstream->codec_data = data;
|
||||
}
|
||||
|
||||
return vgmstream;
|
||||
|
||||
/* clean up anything we may have opened */
|
||||
fail:
|
||||
if (data) {
|
||||
if (data->m) {
|
||||
mpg123_delete(data->m);
|
||||
data->m = NULL;
|
||||
}
|
||||
free(data);
|
||||
data = NULL;
|
||||
}
|
||||
if (vgmstream) close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,310 @@
|
|||
#include "meta.h"
|
||||
#include "../layout/layout.h"
|
||||
#include "../util.h"
|
||||
|
||||
/* Audio Interchange File Format AIFF-C */
|
||||
/* also plain AIFF, for good measure */
|
||||
|
||||
/* Included primarily for 3DO */
|
||||
|
||||
/* for reading integers inexplicably packed into 80 bit floats */
|
||||
uint32_t read80bitSANE(off_t offset, STREAMFILE *streamFile) {
|
||||
uint8_t buf[10];
|
||||
int32_t exponent;
|
||||
int32_t mantissa;
|
||||
int i;
|
||||
|
||||
if (read_streamfile(buf,offset,10,streamFile) != 10) return 0;
|
||||
|
||||
exponent = ((buf[0]<<8)|(buf[1]))&0x7fff;
|
||||
exponent -= 16383;
|
||||
|
||||
mantissa = 0;
|
||||
for (i=0;i<8;i++) {
|
||||
int32_t shift = exponent-7-i*8;
|
||||
if (shift >= 0)
|
||||
mantissa |= buf[i+2] << shift;
|
||||
else if (shift > -8)
|
||||
mantissa |= buf[i+2] >> -shift;
|
||||
}
|
||||
|
||||
return mantissa*((buf[0]&0x80)?-1:1);
|
||||
}
|
||||
|
||||
uint32_t find_marker(STREAMFILE *streamFile, off_t MarkerChunkOffset,
|
||||
int marker_id) {
|
||||
uint16_t marker_count;
|
||||
int i;
|
||||
off_t marker_offset;
|
||||
|
||||
marker_count = read_16bitBE(MarkerChunkOffset+8,streamFile);
|
||||
marker_offset = MarkerChunkOffset+10;
|
||||
for (i=0;i<marker_count;i++) {
|
||||
int name_length;
|
||||
|
||||
if (read_16bitBE(marker_offset,streamFile) == marker_id)
|
||||
return read_32bitBE(marker_offset+2,streamFile);
|
||||
|
||||
name_length = (uint8_t)read_8bit(marker_offset+6,streamFile) + 1;
|
||||
if (name_length % 2) name_length++;
|
||||
marker_offset += 6 + name_length;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
VGMSTREAM * init_vgmstream_aifc(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
char filename[PATH_LIMIT];
|
||||
|
||||
off_t file_size = -1;
|
||||
int channel_count = 0;
|
||||
int sample_count = 0;
|
||||
int sample_size = 0;
|
||||
int sample_rate = 0;
|
||||
int coding_type = -1;
|
||||
off_t start_offset = -1;
|
||||
int interleave = -1;
|
||||
|
||||
int loop_flag = 0;
|
||||
int32_t loop_start = -1;
|
||||
int32_t loop_end = -1;
|
||||
|
||||
int AIFFext = 0;
|
||||
int AIFCext = 0;
|
||||
int AIFF = 0;
|
||||
int AIFC = 0;
|
||||
int FormatVersionChunkFound = 0;
|
||||
int CommonChunkFound = 0;
|
||||
int SoundDataChunkFound = 0;
|
||||
int MarkerChunkFound = 0;
|
||||
off_t MarkerChunkOffset = -1;
|
||||
int InstrumentChunkFound =0;
|
||||
off_t InstrumentChunkOffset = -1;
|
||||
|
||||
/* check extension, case insensitive */
|
||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||
if (!strcasecmp("aifc",filename_extension(filename)) ||
|
||||
!strcasecmp("afc",filename_extension(filename)) ||
|
||||
!strcasecmp("aifcl",filename_extension(filename)) ||
|
||||
!strcasecmp("cbd2",filename_extension(filename)))
|
||||
{
|
||||
AIFCext = 1;
|
||||
}
|
||||
else if (!strcasecmp("aiff",filename_extension(filename)) ||
|
||||
!strcasecmp("aif",filename_extension(filename)) ||
|
||||
!strcasecmp("aiffl",filename_extension(filename)))
|
||||
{
|
||||
AIFFext = 1;
|
||||
}
|
||||
else goto fail;
|
||||
|
||||
/* check header */
|
||||
if ((uint32_t)read_32bitBE(0,streamFile)==0x464F524D && /* "FORM" */
|
||||
/* check that file = header (8) + data */
|
||||
(uint32_t)read_32bitBE(4,streamFile)+8==get_streamfile_size(streamFile))
|
||||
{
|
||||
if ((uint32_t)read_32bitBE(8,streamFile)==0x41494643) /* "AIFC" */
|
||||
{
|
||||
if (!AIFCext) goto fail;
|
||||
AIFC = 1;
|
||||
}
|
||||
else if ((uint32_t)read_32bitBE(8,streamFile)==0x41494646) /* "AIFF" */
|
||||
{
|
||||
if (!AIFFext) goto fail;
|
||||
AIFF = 1;
|
||||
}
|
||||
else goto fail;
|
||||
} else goto fail;
|
||||
|
||||
file_size = get_streamfile_size(streamFile);
|
||||
|
||||
/* read through chunks to verify format and find metadata */
|
||||
{
|
||||
off_t current_chunk = 0xc; /* start with first chunk within FORM */
|
||||
|
||||
while (current_chunk < file_size) {
|
||||
uint32_t chunk_type = read_32bitBE(current_chunk,streamFile);
|
||||
off_t chunk_size = read_32bitBE(current_chunk+4,streamFile);
|
||||
|
||||
/* chunks must be padded to an even number of bytes but chunk
|
||||
* size does not include that padding */
|
||||
if (chunk_size % 2) chunk_size++;
|
||||
|
||||
if (current_chunk+8+chunk_size > file_size) goto fail;
|
||||
|
||||
switch(chunk_type) {
|
||||
case 0x46564552: /* FVER */
|
||||
/* only one per file */
|
||||
if (FormatVersionChunkFound) goto fail;
|
||||
/* plain AIFF shouldn't have */
|
||||
if (AIFF) goto fail;
|
||||
FormatVersionChunkFound = 1;
|
||||
|
||||
/* specific size */
|
||||
if (chunk_size != 4) goto fail;
|
||||
|
||||
/* Version 1 of AIFF-C spec timestamp */
|
||||
if ((uint32_t)read_32bitBE(current_chunk+8,streamFile) !=
|
||||
0xA2805140) goto fail;
|
||||
break;
|
||||
case 0x434F4D4D: /* COMM */
|
||||
/* only one per file */
|
||||
if (CommonChunkFound) goto fail;
|
||||
CommonChunkFound = 1;
|
||||
|
||||
channel_count = read_16bitBE(current_chunk+8,streamFile);
|
||||
if (channel_count <= 0) goto fail;
|
||||
|
||||
sample_count = (uint32_t)read_32bitBE(current_chunk+0xa,streamFile);
|
||||
|
||||
sample_size = read_16bitBE(current_chunk+0xe,streamFile);
|
||||
|
||||
sample_rate = read80bitSANE(current_chunk+0x10,streamFile);
|
||||
|
||||
if (AIFC) {
|
||||
switch (read_32bitBE(current_chunk+0x1a,streamFile)) {
|
||||
case 0x53445832: /* SDX2 */
|
||||
coding_type = coding_SDX2;
|
||||
interleave = 1;
|
||||
break;
|
||||
case 0x43424432: /* CBD2 */
|
||||
coding_type = coding_CBD2;
|
||||
interleave = 1;
|
||||
break;
|
||||
case 0x41445034: /* ADP4 */
|
||||
coding_type = coding_DVI_IMA;
|
||||
/* don't know how stereo DVI is laid out */
|
||||
if (channel_count != 1) break;
|
||||
break;
|
||||
default:
|
||||
/* we should probably support uncompressed here */
|
||||
goto fail;
|
||||
}
|
||||
} else if (AIFF) {
|
||||
switch (sample_size) {
|
||||
case 8:
|
||||
coding_type = coding_PCM8;
|
||||
interleave = 1;
|
||||
break;
|
||||
case 16:
|
||||
coding_type = coding_PCM16BE;
|
||||
interleave = 2;
|
||||
break;
|
||||
/* 32 is a possibility, but we don't see it and I
|
||||
* don't have a reader for it yet */
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
/* we don't check the human-readable portion of AIFF-C*/
|
||||
|
||||
break;
|
||||
case 0x53534E44: /* SSND */
|
||||
/* at most one per file */
|
||||
if (SoundDataChunkFound) goto fail;
|
||||
SoundDataChunkFound = 1;
|
||||
|
||||
start_offset = current_chunk + 16 + read_32bitBE(current_chunk+8,streamFile);
|
||||
break;
|
||||
case 0x4D41524B: /* MARK */
|
||||
if (MarkerChunkFound) goto fail;
|
||||
MarkerChunkFound = 1;
|
||||
MarkerChunkOffset = current_chunk;
|
||||
break;
|
||||
case 0x494E5354: /* INST */
|
||||
if (InstrumentChunkFound) goto fail;
|
||||
InstrumentChunkFound = 1;
|
||||
InstrumentChunkOffset = current_chunk;
|
||||
break;
|
||||
default:
|
||||
/* spec says we can skip unrecognized chunks */
|
||||
break;
|
||||
}
|
||||
|
||||
current_chunk += 8+chunk_size;
|
||||
}
|
||||
}
|
||||
|
||||
if (AIFC) {
|
||||
if (!FormatVersionChunkFound || !CommonChunkFound || !SoundDataChunkFound)
|
||||
goto fail;
|
||||
} else if (AIFF) {
|
||||
if (!CommonChunkFound || !SoundDataChunkFound)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* read loop points */
|
||||
if (InstrumentChunkFound && MarkerChunkFound) {
|
||||
int start_marker;
|
||||
int end_marker;
|
||||
/* use the sustain loop */
|
||||
/* if playMode=ForwardLooping */
|
||||
if (read_16bitBE(InstrumentChunkOffset+16,streamFile) == 1) {
|
||||
start_marker = read_16bitBE(InstrumentChunkOffset+18,streamFile);
|
||||
end_marker = read_16bitBE(InstrumentChunkOffset+20,streamFile);
|
||||
/* check for sustain markers != 0 (invalid marker no) */
|
||||
if (start_marker && end_marker) {
|
||||
/* find start marker */
|
||||
loop_start = find_marker(streamFile,MarkerChunkOffset,start_marker);
|
||||
loop_end = find_marker(streamFile,MarkerChunkOffset,end_marker);
|
||||
|
||||
/* find_marker is type uint32_t as the spec says that's the type
|
||||
* of the position value, but it returns a -1 on error, and the
|
||||
* loop_start and loop_end variables are int32_t, so the error
|
||||
* will become apparent.
|
||||
* We shouldn't have a loop point that overflows an int32_t
|
||||
* anyway. */
|
||||
loop_flag = 1;
|
||||
if (loop_start==loop_end) loop_flag = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
/* fill in the vital statistics */
|
||||
vgmstream->num_samples = sample_count;
|
||||
vgmstream->sample_rate = sample_rate;
|
||||
|
||||
vgmstream->coding_type = coding_type;
|
||||
if (channel_count > 1)
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
else
|
||||
vgmstream->layout_type = layout_none;
|
||||
vgmstream->interleave_block_size = interleave;
|
||||
vgmstream->loop_start_sample = loop_start;
|
||||
vgmstream->loop_end_sample = loop_end;
|
||||
|
||||
if (AIFC)
|
||||
vgmstream->meta_type = meta_AIFC;
|
||||
else if (AIFF)
|
||||
vgmstream->meta_type = meta_AIFF;
|
||||
|
||||
/* open the file, set up each channel */
|
||||
{
|
||||
int i;
|
||||
|
||||
vgmstream->ch[0].streamfile = streamFile->open(streamFile,filename,
|
||||
STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
if (!vgmstream->ch[0].streamfile) goto fail;
|
||||
|
||||
for (i=0;i<channel_count;i++) {
|
||||
vgmstream->ch[i].streamfile = vgmstream->ch[0].streamfile;
|
||||
vgmstream->ch[i].offset = vgmstream->ch[i].channel_start_offset =
|
||||
start_offset+i*interleave;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return vgmstream;
|
||||
|
||||
/* clean up anything we may have opened */
|
||||
fail:
|
||||
if (vgmstream) close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
|
@ -0,0 +1,417 @@
|
|||
#include "../vgmstream.h"
|
||||
#include "meta.h"
|
||||
#include "../util.h"
|
||||
|
||||
typedef struct _AIXSTREAMFILE
|
||||
{
|
||||
STREAMFILE sf;
|
||||
STREAMFILE *real_file;
|
||||
off_t start_physical_offset;
|
||||
off_t current_physical_offset;
|
||||
off_t current_logical_offset;
|
||||
off_t current_block_size;
|
||||
int stream_id;
|
||||
} AIXSTREAMFILE;
|
||||
|
||||
static STREAMFILE *open_aix_with_STREAMFILE(STREAMFILE *file,off_t start_offset,int stream_id);
|
||||
|
||||
VGMSTREAM * init_vgmstream_aix(STREAMFILE *streamFile) {
|
||||
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
STREAMFILE * streamFileAIX = NULL;
|
||||
STREAMFILE * streamFileADX = NULL;
|
||||
char filename[PATH_LIMIT];
|
||||
off_t *segment_offset = NULL;
|
||||
int32_t *samples_in_segment = NULL;
|
||||
int32_t sample_count;
|
||||
|
||||
int loop_flag = 0;
|
||||
int32_t loop_start_sample=0;
|
||||
int32_t loop_end_sample=0;
|
||||
|
||||
aix_codec_data *data = NULL;
|
||||
|
||||
off_t first_AIXP;
|
||||
off_t stream_list_offset;
|
||||
off_t stream_list_end;
|
||||
const int segment_list_entry_size = 0x10;
|
||||
const off_t segment_list_offset = 0x20;
|
||||
|
||||
int stream_count,channel_count,segment_count;
|
||||
int sample_rate;
|
||||
|
||||
int i;
|
||||
|
||||
/* check extension, case insensitive */
|
||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||
if (strcasecmp("aix",filename_extension(filename))) goto fail;
|
||||
|
||||
if (read_32bitBE(0x0,streamFile) != 0x41495846 || /* "AIXF" */
|
||||
read_32bitBE(0x08,streamFile) != 0x01000014 ||
|
||||
read_32bitBE(0x0c,streamFile) != 0x00000800)
|
||||
goto fail;
|
||||
|
||||
first_AIXP = read_32bitBE(0x4,streamFile)+8;
|
||||
segment_count = (uint16_t)read_16bitBE(0x18,streamFile);
|
||||
stream_list_offset = segment_list_offset+segment_list_entry_size*segment_count+0x10;
|
||||
|
||||
if (stream_list_offset >= first_AIXP)
|
||||
goto fail;
|
||||
if (segment_count < 1)
|
||||
goto fail;
|
||||
|
||||
sample_rate = read_32bitBE(stream_list_offset+8,streamFile);
|
||||
if (!check_sample_rate(sample_rate))
|
||||
goto fail;
|
||||
|
||||
samples_in_segment = calloc(segment_count,sizeof(int32_t));
|
||||
if (!samples_in_segment)
|
||||
goto fail;
|
||||
segment_offset = calloc(segment_count,sizeof(off_t));
|
||||
if (!segment_offset)
|
||||
goto fail;
|
||||
|
||||
for (i = 0; i < segment_count; i++)
|
||||
{
|
||||
segment_offset[i] = read_32bitBE(segment_list_offset+segment_list_entry_size*i+0,streamFile);
|
||||
samples_in_segment[i] = read_32bitBE(segment_list_offset+segment_list_entry_size*i+0x08,streamFile);
|
||||
/*printf("samples_in_segment[%d]=%d\n",i,samples_in_segment[i]);*/
|
||||
/* all segments must have equal sample rate */
|
||||
if (read_32bitBE(segment_list_offset+segment_list_entry_size*i+0x0c,streamFile) != sample_rate)
|
||||
{
|
||||
/* segments > 0 can have 0 sample rate (Ryu ga gotoku: Kenzan! tenkei_sng1.aix),
|
||||
seems to indicate same sample rate as first */
|
||||
if (!(i > 0 && read_32bitBE(segment_list_offset+segment_list_entry_size*i+0x0c,streamFile) == 0))
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
if (segment_offset[0] != first_AIXP)
|
||||
goto fail;
|
||||
|
||||
stream_count = (uint8_t)read_8bit(stream_list_offset,streamFile);
|
||||
if (stream_count < 1)
|
||||
goto fail;
|
||||
stream_list_end = stream_list_offset + 0x8 + stream_count * 8;
|
||||
|
||||
if (stream_list_end >= first_AIXP)
|
||||
goto fail;
|
||||
|
||||
channel_count = 0;
|
||||
for (i = 0; i < stream_count; i++)
|
||||
{
|
||||
/* all streams must have same samplerate as segments */
|
||||
if (read_32bitBE(stream_list_offset+8+i*8,streamFile)!=sample_rate)
|
||||
goto fail;
|
||||
channel_count += read_8bit(stream_list_offset+8+i*8+4,streamFile);
|
||||
}
|
||||
|
||||
/* check for existence of segments */
|
||||
for (i = 0; i < segment_count; i++)
|
||||
{
|
||||
int j;
|
||||
off_t AIXP_offset = segment_offset[i];
|
||||
for (j = 0; j < stream_count; j++)
|
||||
{
|
||||
if (read_32bitBE(AIXP_offset,streamFile)!=0x41495850) /* "AIXP" */
|
||||
goto fail;
|
||||
if (read_8bit(AIXP_offset+8,streamFile)!=j)
|
||||
goto fail;
|
||||
AIXP_offset += read_32bitBE(AIXP_offset+4,streamFile)+8;
|
||||
}
|
||||
}
|
||||
|
||||
/*streamFileAIX = streamFile->open(streamFile,filename,sample_rate*0.0375*2/32*18segment_count);*/
|
||||
streamFileAIX = streamFile->open(streamFile,filename,sample_rate*0.1*segment_count);
|
||||
if (!streamFileAIX) goto fail;
|
||||
|
||||
data = malloc(sizeof(aix_codec_data));
|
||||
if (!data) goto fail;
|
||||
data->segment_count = segment_count;
|
||||
data->stream_count = stream_count;
|
||||
data->adxs = malloc(sizeof(STREAMFILE *)*segment_count*stream_count);
|
||||
if (!data->adxs) goto fail;
|
||||
for (i=0;i<segment_count*stream_count;i++) {
|
||||
data->adxs[i] = NULL;
|
||||
}
|
||||
data->sample_counts = calloc(segment_count,sizeof(int32_t));
|
||||
if (!data->sample_counts) goto fail;
|
||||
memcpy(data->sample_counts,samples_in_segment,segment_count*sizeof(int32_t));
|
||||
|
||||
/* for each segment */
|
||||
for (i = 0; i < segment_count; i++)
|
||||
{
|
||||
int j;
|
||||
/* for each stream */
|
||||
for (j = 0; j < stream_count; j++)
|
||||
{
|
||||
VGMSTREAM *adx;
|
||||
/*printf("try opening segment %d/%d stream %d/%d %x\n",i,segment_count,j,stream_count,segment_offset[i]);*/
|
||||
streamFileADX = open_aix_with_STREAMFILE(streamFileAIX,segment_offset[i],j);
|
||||
if (!streamFileADX) goto fail;
|
||||
adx = data->adxs[i*stream_count+j] = init_vgmstream_adx(streamFileADX);
|
||||
if (!adx)
|
||||
goto fail;
|
||||
close_streamfile(streamFileADX); streamFileADX = NULL;
|
||||
|
||||
if (adx->num_samples != data->sample_counts[i] ||
|
||||
adx->loop_flag != 0)
|
||||
goto fail;
|
||||
|
||||
/* save start things so we can restart for seeking/looping */
|
||||
/* copy the channels */
|
||||
memcpy(adx->start_ch,adx->ch,sizeof(VGMSTREAMCHANNEL)*adx->channels);
|
||||
/* copy the whole VGMSTREAM */
|
||||
memcpy(adx->start_vgmstream,adx,sizeof(VGMSTREAM));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (segment_count > 1)
|
||||
{
|
||||
loop_flag = 1;
|
||||
}
|
||||
|
||||
sample_count = 0;
|
||||
for (i = 0; i < segment_count; i++)
|
||||
{
|
||||
sample_count += data->sample_counts[i];
|
||||
|
||||
if (i == 0)
|
||||
loop_start_sample = sample_count;
|
||||
if (i == 1)
|
||||
loop_end_sample = sample_count;
|
||||
}
|
||||
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
|
||||
vgmstream->num_samples = sample_count;
|
||||
vgmstream->sample_rate = sample_rate;
|
||||
|
||||
vgmstream->loop_start_sample = loop_start_sample;
|
||||
vgmstream->loop_end_sample = loop_end_sample;
|
||||
|
||||
vgmstream->coding_type = data->adxs[0]->coding_type;
|
||||
vgmstream->layout_type = layout_aix;
|
||||
vgmstream->meta_type = meta_AIX;
|
||||
|
||||
vgmstream->ch[0].streamfile = streamFileAIX;
|
||||
data->current_segment = 0;
|
||||
|
||||
vgmstream->codec_data = data;
|
||||
free(segment_offset);
|
||||
free(samples_in_segment);
|
||||
|
||||
return vgmstream;
|
||||
|
||||
/* clean up anything we may have opened */
|
||||
fail:
|
||||
if (streamFileAIX) close_streamfile(streamFileAIX);
|
||||
if (streamFileADX) close_streamfile(streamFileADX);
|
||||
if (vgmstream) close_vgmstream(vgmstream);
|
||||
if (samples_in_segment) free(samples_in_segment);
|
||||
if (segment_offset) free(segment_offset);
|
||||
if (data) {
|
||||
if (data->adxs)
|
||||
{
|
||||
int i;
|
||||
for (i=0;i<data->segment_count*data->stream_count;i++)
|
||||
if (data->adxs)
|
||||
close_vgmstream(data->adxs[i]);
|
||||
free(data->adxs);
|
||||
}
|
||||
if (data->sample_counts)
|
||||
{
|
||||
free(data->sample_counts);
|
||||
}
|
||||
free(data);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
static size_t read_aix(AIXSTREAMFILE *streamfile,uint8_t *dest,off_t offset,size_t length)
|
||||
{
|
||||
size_t sz = 0;
|
||||
|
||||
/*printf("trying to read %x bytes from %x (str%d)\n",length,offset,streamfile->stream_id);*/
|
||||
while (length > 0)
|
||||
{
|
||||
int read_something = 0;
|
||||
|
||||
/* read the beginning of the requested block, if we can */
|
||||
if (offset >= streamfile->current_logical_offset)
|
||||
{
|
||||
off_t to_read;
|
||||
off_t length_available;
|
||||
|
||||
length_available =
|
||||
(streamfile->current_logical_offset+
|
||||
streamfile->current_block_size) -
|
||||
offset;
|
||||
|
||||
if (length < length_available)
|
||||
{
|
||||
to_read = length;
|
||||
}
|
||||
else
|
||||
{
|
||||
to_read = length_available;
|
||||
}
|
||||
|
||||
if (to_read > 0)
|
||||
{
|
||||
size_t bytes_read;
|
||||
|
||||
bytes_read = read_streamfile(dest,
|
||||
streamfile->current_physical_offset+0x10+
|
||||
(offset-streamfile->current_logical_offset),
|
||||
to_read,streamfile->real_file);
|
||||
|
||||
sz += bytes_read;
|
||||
if (bytes_read != to_read)
|
||||
{
|
||||
/* an error which we will not attempt to handle here */
|
||||
return sz;
|
||||
}
|
||||
|
||||
read_something = 1;
|
||||
|
||||
dest += bytes_read;
|
||||
offset += bytes_read;
|
||||
length -= bytes_read;
|
||||
}
|
||||
}
|
||||
|
||||
if (!read_something)
|
||||
{
|
||||
/* couldn't read anything, must seek */
|
||||
int found_block = 0;
|
||||
|
||||
/* as we have no memory we must start seeking from the beginning */
|
||||
if (offset < streamfile->current_logical_offset)
|
||||
{
|
||||
streamfile->current_logical_offset = 0;
|
||||
streamfile->current_block_size = 0;
|
||||
streamfile->current_physical_offset =
|
||||
streamfile->start_physical_offset;
|
||||
}
|
||||
|
||||
/* seek ye forwards */
|
||||
while (!found_block) {
|
||||
/*printf("seek looks at %x\n",streamfile->current_physical_offset);*/
|
||||
switch (read_32bitBE(streamfile->current_physical_offset,
|
||||
streamfile->real_file))
|
||||
{
|
||||
case 0x41495850: /* AIXP */
|
||||
if (read_8bit(
|
||||
streamfile->current_physical_offset+8,
|
||||
streamfile->real_file) ==
|
||||
streamfile->stream_id)
|
||||
{
|
||||
streamfile->current_block_size =
|
||||
(uint16_t)read_16bitBE(
|
||||
streamfile->current_physical_offset+0x0a,
|
||||
streamfile->real_file);
|
||||
|
||||
if (offset >= streamfile->current_logical_offset+
|
||||
streamfile->current_block_size)
|
||||
{
|
||||
streamfile->current_logical_offset +=
|
||||
streamfile->current_block_size;
|
||||
}
|
||||
else
|
||||
{
|
||||
found_block = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found_block)
|
||||
{
|
||||
streamfile->current_physical_offset +=
|
||||
read_32bitBE(
|
||||
streamfile->current_physical_offset+0x04,
|
||||
streamfile->real_file
|
||||
) + 8;
|
||||
}
|
||||
|
||||
break;
|
||||
case 0x41495846: /* AIXF */
|
||||
/* shouldn't ever see this */
|
||||
case 0x41495845: /* AIXE */
|
||||
/* shouldn't have reached the end o' the line... */
|
||||
default:
|
||||
return sz;
|
||||
break;
|
||||
} /* end block/chunk type select */
|
||||
} /* end while !found_block */
|
||||
} /* end if !read_something */
|
||||
} /* end while length > 0 */
|
||||
|
||||
return sz;
|
||||
}
|
||||
|
||||
static void close_aix(AIXSTREAMFILE *streamfile)
|
||||
{
|
||||
free(streamfile);
|
||||
return;
|
||||
}
|
||||
|
||||
static size_t get_size_aix(AIXSTREAMFILE *streamfile)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static size_t get_offset_aix(AIXSTREAMFILE *streamfile)
|
||||
{
|
||||
return streamfile->current_logical_offset;
|
||||
}
|
||||
|
||||
static void get_name_aix(AIXSTREAMFILE *streamfile,char *buffer,size_t length)
|
||||
{
|
||||
strncpy(buffer,"ARBITRARY.ADX",length);
|
||||
buffer[length-1]='\0';
|
||||
}
|
||||
|
||||
static STREAMFILE *open_aix_impl(AIXSTREAMFILE *streamfile,const char * const filename,size_t buffersize)
|
||||
{
|
||||
AIXSTREAMFILE *newfile;
|
||||
if (strcmp(filename,"ARBITRARY.ADX"))
|
||||
return NULL;
|
||||
|
||||
newfile = malloc(sizeof(AIXSTREAMFILE));
|
||||
if (!newfile)
|
||||
return NULL;
|
||||
memcpy(newfile,streamfile,sizeof(AIXSTREAMFILE));
|
||||
return &newfile->sf;
|
||||
}
|
||||
|
||||
static STREAMFILE *open_aix_with_STREAMFILE(STREAMFILE *file,off_t start_offset,int stream_id)
|
||||
{
|
||||
AIXSTREAMFILE *streamfile = malloc(sizeof(AIXSTREAMFILE));
|
||||
|
||||
if (!streamfile)
|
||||
return NULL;
|
||||
|
||||
/* success, set our pointers */
|
||||
|
||||
streamfile->sf.read = (void*)read_aix;
|
||||
streamfile->sf.get_size = (void*)get_size_aix;
|
||||
streamfile->sf.get_offset = (void*)get_offset_aix;
|
||||
streamfile->sf.get_name = (void*)get_name_aix;
|
||||
streamfile->sf.get_realname = (void*)get_name_aix;
|
||||
streamfile->sf.open = (void*)open_aix_impl;
|
||||
streamfile->sf.close = (void*)close_aix;
|
||||
#ifdef PROFILE_STREAMFILE
|
||||
streamfile->sf.get_bytes_read = NULL;
|
||||
streamfile->sf.get_error_count = NULL;
|
||||
#endif
|
||||
|
||||
streamfile->real_file = file;
|
||||
streamfile->current_physical_offset =
|
||||
streamfile->start_physical_offset = start_offset;
|
||||
streamfile->current_logical_offset = 0;
|
||||
streamfile->current_block_size = 0;
|
||||
streamfile->stream_id = stream_id;
|
||||
|
||||
return &streamfile->sf;
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
#include "../vgmstream.h"
|
||||
#include "meta.h"
|
||||
|
||||
#if defined(VGM_USE_MP4V2) && defined(VGM_USE_FDKAAC)
|
||||
VGMSTREAM * init_vgmstream_akb(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
|
||||
size_t filesize;
|
||||
uint32_t loop_start, loop_end;
|
||||
|
||||
if ((uint32_t)read_32bitBE(0, streamFile) != 0x414b4220) goto fail;
|
||||
|
||||
loop_start = read_32bitLE(0x14, streamFile);
|
||||
loop_end = read_32bitLE(0x18, streamFile);
|
||||
|
||||
filesize = get_streamfile_size( streamFile );
|
||||
|
||||
vgmstream = init_vgmstream_mp4_aac_offset( streamFile, 0x20, filesize - 0x20 );
|
||||
if ( !vgmstream ) goto fail;
|
||||
|
||||
if ( loop_start || loop_end ) {
|
||||
vgmstream->loop_flag = 1;
|
||||
vgmstream->loop_start_sample = loop_start;
|
||||
vgmstream->loop_end_sample = loop_end;
|
||||
}
|
||||
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,170 @@
|
|||
#include "meta.h"
|
||||
#include "../util.h"
|
||||
|
||||
/* Apple Core Audio Format */
|
||||
|
||||
VGMSTREAM * init_vgmstream_apple_caff(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
char filename[PATH_LIMIT];
|
||||
|
||||
off_t start_offset = 0;
|
||||
off_t data_size = 0;
|
||||
off_t sample_count = 0;
|
||||
off_t interleave = 0;
|
||||
int sample_rate = -1, unused_frames = 0;
|
||||
int channel_count = 0;
|
||||
|
||||
off_t file_length;
|
||||
off_t chunk_offset = 8;
|
||||
int found_desc = 0, found_pakt = 0, found_data = 0;
|
||||
|
||||
/* check extension, case insensitive */
|
||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||
if (strcasecmp("caf",filename_extension(filename))) goto fail;
|
||||
|
||||
/* check "caff" id */
|
||||
if (read_32bitBE(0,streamFile)!=0x63616666) goto fail;
|
||||
/* check version, flags */
|
||||
if (read_32bitBE(4,streamFile)!=0x00010000) goto fail;
|
||||
|
||||
file_length = (off_t)get_streamfile_size(streamFile);
|
||||
|
||||
while (chunk_offset < file_length)
|
||||
{
|
||||
/* high half of size (expect 0s) */
|
||||
if (read_32bitBE(chunk_offset+4,streamFile) != 0) goto fail;
|
||||
|
||||
/* handle chunk type */
|
||||
switch (read_32bitBE(chunk_offset,streamFile))
|
||||
{
|
||||
case 0x64657363: /* desc */
|
||||
found_desc = 1;
|
||||
{
|
||||
/* rather than put a convoluted conversion here for
|
||||
portability, just look it up */
|
||||
uint32_t sratefloat = read_32bitBE(chunk_offset+0x0c, streamFile);
|
||||
if (read_32bitBE(chunk_offset+0x10, streamFile) != 0) goto fail;
|
||||
switch (sratefloat)
|
||||
{
|
||||
case 0x40D19400:
|
||||
sample_rate = 18000;
|
||||
break;
|
||||
case 0x40D58880:
|
||||
sample_rate = 22050;
|
||||
break;
|
||||
case 0x40DF4000:
|
||||
sample_rate = 32000;
|
||||
break;
|
||||
case 0x40E58880:
|
||||
sample_rate = 44100;
|
||||
break;
|
||||
case 0x40E77000:
|
||||
sample_rate = 48000;
|
||||
break;
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
uint32_t bytes_per_packet, frames_per_packet, channels_per_frame, bits_per_channel;
|
||||
uint32_t codec_4cc = read_32bitBE(chunk_offset+0x14, streamFile);
|
||||
/* only supporting ima4 for now */
|
||||
if (codec_4cc != 0x696d6134) goto fail;
|
||||
|
||||
/* format flags */
|
||||
if (read_32bitBE(chunk_offset+0x18, streamFile) != 0) goto fail;
|
||||
bytes_per_packet = read_32bitBE(chunk_offset+0x1c, streamFile);
|
||||
frames_per_packet = read_32bitBE(chunk_offset+0x20, streamFile);
|
||||
channels_per_frame = read_32bitBE(chunk_offset+0x24, streamFile);
|
||||
bits_per_channel = read_32bitBE(chunk_offset+0x28, streamFile);
|
||||
|
||||
interleave = bytes_per_packet / channels_per_frame;
|
||||
channel_count = channels_per_frame;
|
||||
if (channels_per_frame != 1 && channels_per_frame != 2)
|
||||
goto fail;
|
||||
/* ima4-specific */
|
||||
if (frames_per_packet != 64) goto fail;
|
||||
if ((frames_per_packet / 2 + 2) * channels_per_frame !=
|
||||
bytes_per_packet) goto fail;
|
||||
if (bits_per_channel != 0) goto fail;
|
||||
}
|
||||
break;
|
||||
case 0x70616b74: /* pakt */
|
||||
found_pakt = 1;
|
||||
/* 64-bit packet table size, 0 for constant bitrate */
|
||||
if (
|
||||
read_32bitBE(chunk_offset+0x0c,streamFile) != 0 ||
|
||||
read_32bitBE(chunk_offset+0x10,streamFile) != 0) goto fail;
|
||||
/* high half of valid frames count */
|
||||
if (read_32bitBE(chunk_offset+0x14,streamFile) != 0) goto fail;
|
||||
/* frame count */
|
||||
sample_count = read_32bitBE(chunk_offset+0x18,streamFile);
|
||||
/* priming frames */
|
||||
if (read_32bitBE(chunk_offset+0x1c,streamFile) != 0) goto fail;
|
||||
/* remainder (unused) frames */
|
||||
unused_frames = read_32bitBE(chunk_offset+0x20,streamFile);
|
||||
break;
|
||||
case 0x66726565: /* free */
|
||||
/* padding, ignore */
|
||||
break;
|
||||
case 0x64617461: /* data */
|
||||
if (read_32bitBE(chunk_offset+12,streamFile) != 1) goto fail;
|
||||
found_data = 1;
|
||||
start_offset = chunk_offset + 16;
|
||||
data_size = read_32bitBE(chunk_offset+8,streamFile) - 4;
|
||||
break;
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* done with chunk */
|
||||
chunk_offset += 12 + read_32bitBE(chunk_offset+8,streamFile);
|
||||
}
|
||||
|
||||
if (!found_pakt || !found_desc || !found_data) goto fail;
|
||||
if (start_offset == 0 || data_size == 0 || sample_count == 0 ||
|
||||
sample_rate == -1 || channel_count == 0) goto fail;
|
||||
|
||||
/* ima4-specific */
|
||||
/* check for full packets */
|
||||
if (data_size % (interleave*channel_count) != 0) goto fail;
|
||||
if ((sample_count+unused_frames)%((interleave-2)*2) != 0) goto fail;
|
||||
/* check that all packets are accounted for */
|
||||
if (data_size/interleave/channel_count !=
|
||||
(sample_count+unused_frames)/((interleave-2)*2)) goto fail;
|
||||
|
||||
vgmstream = allocate_vgmstream(channel_count,0);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->channels = channel_count;
|
||||
vgmstream->sample_rate = sample_rate;
|
||||
vgmstream->num_samples = sample_count;
|
||||
/* ima4-specific */
|
||||
vgmstream->coding_type = coding_APPLE_IMA4;
|
||||
if (channel_count == 2)
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
else
|
||||
vgmstream->layout_type = layout_none;
|
||||
vgmstream->interleave_block_size = interleave;
|
||||
vgmstream->meta_type = meta_CAFF;
|
||||
|
||||
/* open the file for reading by each channel */
|
||||
{
|
||||
int i;
|
||||
for (i=0;i<channel_count;i++)
|
||||
{
|
||||
vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
if (!vgmstream->ch[i].streamfile) goto fail;
|
||||
|
||||
vgmstream->ch[i].offset =
|
||||
vgmstream->ch[i].channel_start_offset =
|
||||
start_offset + interleave * i;
|
||||
}
|
||||
}
|
||||
|
||||
return vgmstream;
|
||||
fail:
|
||||
if (vgmstream) close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
#include "meta.h"
|
||||
#include "../layout/layout.h"
|
||||
#include "../util.h"
|
||||
|
||||
VGMSTREAM * init_vgmstream_ast(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
char filename[PATH_LIMIT];
|
||||
|
||||
coding_t coding_type;
|
||||
|
||||
int codec_number;
|
||||
int channel_count;
|
||||
int loop_flag;
|
||||
|
||||
size_t max_block;
|
||||
|
||||
/* check extension, case insensitive */
|
||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||
if (strcasecmp("ast",filename_extension(filename))) goto fail;
|
||||
|
||||
/* check header */
|
||||
if ((uint32_t)read_32bitBE(0,streamFile)!=0x5354524D || /* "STRM" */
|
||||
read_16bitBE(0xa,streamFile)!=0x10 ||
|
||||
/* check that file = header (0x40) + data */
|
||||
read_32bitBE(4,streamFile)+0x40!=get_streamfile_size(streamFile))
|
||||
goto fail;
|
||||
|
||||
/* check for a first block */
|
||||
if (read_32bitBE(0x40,streamFile)!=0x424C434B) /* "BLCK" */
|
||||
goto fail;
|
||||
|
||||
/* check type details */
|
||||
codec_number = read_16bitBE(8,streamFile);
|
||||
loop_flag = read_16bitBE(0xe,streamFile);
|
||||
channel_count = read_16bitBE(0xc,streamFile);
|
||||
max_block = read_32bitBE(0x20,streamFile);
|
||||
|
||||
switch (codec_number) {
|
||||
case 0:
|
||||
coding_type = coding_NGC_AFC;
|
||||
break;
|
||||
case 1:
|
||||
coding_type = coding_PCM16BE;
|
||||
break;
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
/* fill in the vital statistics */
|
||||
vgmstream->num_samples = read_32bitBE(0x14,streamFile);
|
||||
vgmstream->sample_rate = read_32bitBE(0x10,streamFile);
|
||||
/* channels and loop flag are set by allocate_vgmstream */
|
||||
vgmstream->loop_start_sample = read_32bitBE(0x18,streamFile);
|
||||
vgmstream->loop_end_sample = read_32bitBE(0x1c,streamFile);
|
||||
|
||||
vgmstream->coding_type = coding_type;
|
||||
vgmstream->layout_type = layout_ast_blocked;
|
||||
vgmstream->meta_type = meta_AST;
|
||||
|
||||
/* open the file for reading by each channel */
|
||||
{
|
||||
int i;
|
||||
for (i=0;i<channel_count;i++) {
|
||||
vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,
|
||||
(i==0?
|
||||
max_block+0x20-4: /* first buffer a bit bigger to
|
||||
read block header without
|
||||
inefficiency */
|
||||
max_block
|
||||
)
|
||||
);
|
||||
|
||||
if (!vgmstream->ch[i].streamfile) goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
/* start me up */
|
||||
ast_block_update(0x40,vgmstream);
|
||||
|
||||
return vgmstream;
|
||||
|
||||
/* clean up anything we may have opened */
|
||||
fail:
|
||||
if (vgmstream) close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
#include "meta.h"
|
||||
#include "../util.h"
|
||||
|
||||
/* .BAF - Bizarre Creations (Blur, James Bond 007: Blood Stone, etc) */
|
||||
|
||||
VGMSTREAM * init_vgmstream_baf(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
char filename[PATH_LIMIT];
|
||||
off_t WAVE_size,DATA_size;
|
||||
off_t start_offset;
|
||||
long sample_count;
|
||||
|
||||
const int frame_size = 33;
|
||||
const int frame_samples = 64;
|
||||
int channels;
|
||||
int loop_flag = 0;
|
||||
|
||||
/* check extension, case insensitive */
|
||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||
if (strcasecmp("baf",filename_extension(filename))) goto fail;
|
||||
|
||||
/* check WAVE */
|
||||
if (read_32bitBE(0,streamFile) != 0x57415645) goto fail;
|
||||
WAVE_size = read_32bitBE(4,streamFile);
|
||||
if (WAVE_size != 0x4c) goto fail;
|
||||
/* check for DATA after WAVE */
|
||||
if (read_32bitBE(WAVE_size,streamFile) != 0x44415441) goto fail;
|
||||
/* check that WAVE size is data size */
|
||||
DATA_size = read_32bitBE(0x30,streamFile);
|
||||
if (read_32bitBE(WAVE_size+4,streamFile)-8 != DATA_size) goto fail;
|
||||
|
||||
sample_count = read_32bitBE(0x44,streamFile);
|
||||
|
||||
/* unsure how to detect channel count, so use a hack */
|
||||
channels = (long long)DATA_size / frame_size * frame_samples / sample_count;
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channels,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
/* fill in the vital statistics */
|
||||
start_offset = WAVE_size + 8;
|
||||
vgmstream->sample_rate = read_32bitBE(0x40,streamFile);
|
||||
vgmstream->num_samples = sample_count;
|
||||
|
||||
vgmstream->coding_type = coding_BAF_ADPCM;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = frame_size;
|
||||
vgmstream->meta_type = meta_BAF;
|
||||
|
||||
/* open the file for reading by each channel */
|
||||
{
|
||||
int i;
|
||||
STREAMFILE *file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
if (!file) goto fail;
|
||||
for (i=0;i<channels;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;
|
||||
}
|
||||
|
|
@ -0,0 +1,126 @@
|
|||
#include "meta.h"
|
||||
#include "../util.h"
|
||||
|
||||
VGMSTREAM * init_vgmstream_bcstm(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
char filename[PATH_LIMIT];
|
||||
|
||||
coding_t coding_type;
|
||||
|
||||
off_t head_offset;
|
||||
int codec_number;
|
||||
int channel_count;
|
||||
int loop_flag;
|
||||
off_t start_offset;
|
||||
|
||||
/* check extension, case insensitive */
|
||||
streamFile->get_name(streamFile, filename, sizeof(filename));
|
||||
if (strcasecmp("bcstm", filename_extension(filename)))
|
||||
goto fail;
|
||||
|
||||
|
||||
/* check header */
|
||||
if ((uint32_t)read_32bitBE(0, streamFile) != 0x4353544D) /* "CSTM" */
|
||||
goto fail;
|
||||
if ((uint32_t)read_32bitBE(4, streamFile) != 0xFFFE4000)
|
||||
goto fail;
|
||||
|
||||
|
||||
|
||||
/* get head offset, check */
|
||||
head_offset = read_32bitLE(0x18, streamFile);
|
||||
|
||||
if ((uint32_t)read_32bitBE(head_offset, streamFile) != 0x494E464F) /* "INFO" */
|
||||
goto fail;
|
||||
|
||||
|
||||
/* check type details */
|
||||
codec_number = read_8bit(head_offset + 0x20, streamFile);
|
||||
loop_flag = read_8bit(head_offset + 0x21, streamFile);
|
||||
channel_count = read_8bit(head_offset + 0x22, streamFile);
|
||||
|
||||
switch (codec_number) {
|
||||
case 0:
|
||||
coding_type = coding_PCM8;
|
||||
break;
|
||||
case 1:
|
||||
coding_type = coding_PCM16BE;
|
||||
break;
|
||||
case 2:
|
||||
coding_type = coding_NGC_DSP;
|
||||
break;
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (channel_count < 1) goto fail;
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
|
||||
vgmstream = allocate_vgmstream(channel_count, loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
/* fill in the vital statistics */
|
||||
vgmstream->num_samples = read_32bitLE(head_offset + 0x2c, streamFile);
|
||||
vgmstream->sample_rate = (uint16_t)read_16bitLE(head_offset + 0x24, streamFile);
|
||||
/* channels and loop flag are set by allocate_vgmstream */
|
||||
vgmstream->loop_start_sample = read_32bitLE(head_offset + 0x28, streamFile);
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
|
||||
vgmstream->coding_type = coding_type;
|
||||
if (channel_count == 1)
|
||||
vgmstream->layout_type = layout_none;
|
||||
else
|
||||
vgmstream->layout_type = layout_interleave_shortblock;
|
||||
vgmstream->meta_type = meta_CSTM;
|
||||
|
||||
vgmstream->interleave_block_size = read_32bitLE(head_offset + 0x34, streamFile);
|
||||
vgmstream->interleave_smallblock_size = read_32bitLE(head_offset + 0x44, streamFile);
|
||||
|
||||
if (vgmstream->coding_type == coding_NGC_DSP) {
|
||||
off_t coef_offset;
|
||||
off_t coef_offset1;
|
||||
off_t coef_offset2;
|
||||
int i, j;
|
||||
int coef_spacing = 0x2E;
|
||||
|
||||
|
||||
coef_offset1 = read_32bitLE(head_offset + 0x1c, streamFile);
|
||||
coef_offset = coef_offset1 + 0x40;
|
||||
|
||||
|
||||
for (j = 0; j<vgmstream->channels; j++) {
|
||||
for (i = 0; i<16; i++) {
|
||||
vgmstream->ch[j].adpcm_coef[i] = read_16bitLE(head_offset + coef_offset + j*coef_spacing + i * 2, streamFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
start_offset = read_32bitLE(0x30, streamFile) + 0x20;
|
||||
|
||||
/* open the file for reading by each channel */
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i<channel_count; i++) {
|
||||
if (vgmstream->layout_type == layout_interleave_shortblock)
|
||||
vgmstream->ch[i].streamfile = streamFile->open(streamFile, filename,
|
||||
vgmstream->interleave_block_size);
|
||||
else
|
||||
vgmstream->ch[i].streamfile = streamFile->open(streamFile, filename,
|
||||
0x1000);
|
||||
|
||||
if (!vgmstream->ch[i].streamfile) goto fail;
|
||||
|
||||
vgmstream->ch[i].channel_start_offset =
|
||||
vgmstream->ch[i].offset =
|
||||
start_offset + i*vgmstream->interleave_block_size;
|
||||
}
|
||||
}
|
||||
|
||||
return vgmstream;
|
||||
|
||||
/* clean up anything we may have opened */
|
||||
fail:
|
||||
if (vgmstream) close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
|
@ -0,0 +1,140 @@
|
|||
#include "meta.h"
|
||||
#include "../util.h"
|
||||
|
||||
/* BGW (FF XI) */
|
||||
VGMSTREAM * init_vgmstream_bgw(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
char filename[PATH_LIMIT];
|
||||
off_t start_offset;
|
||||
int32_t loop_start;
|
||||
|
||||
int loop_flag = 0;
|
||||
int channel_count;
|
||||
|
||||
/* check extension, case insensitive */
|
||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||
if (strcasecmp("bgw",filename_extension(filename))) goto fail;
|
||||
|
||||
/* "BGMStream" */
|
||||
if (read_32bitBE(0,streamFile) != 0x42474d53 ||
|
||||
read_32bitBE(4,streamFile) != 0x74726561 ||
|
||||
read_32bitBE(8,streamFile) != 0x6d000000 ||
|
||||
read_32bitBE(12,streamFile) != 0) goto fail;
|
||||
|
||||
/* check file size with header value */
|
||||
if (read_32bitLE(0x10,streamFile) != get_streamfile_size(streamFile))
|
||||
goto fail;
|
||||
|
||||
channel_count = read_8bit(0x2e,streamFile);
|
||||
loop_start = read_32bitLE(0x1c,streamFile);
|
||||
loop_flag = (loop_start > 0);
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
/* fill in the vital statistics */
|
||||
start_offset = read_32bitLE(0x28,streamFile);
|
||||
vgmstream->channels = channel_count;
|
||||
vgmstream->sample_rate = 44100;
|
||||
vgmstream->coding_type = coding_FFXI;
|
||||
vgmstream->num_samples = read_32bitLE(0x18,streamFile)*16;
|
||||
if (loop_flag) {
|
||||
vgmstream->loop_start_sample = (loop_start-1)*16;
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
}
|
||||
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 9;
|
||||
vgmstream->meta_type = meta_FFXI_BGW;
|
||||
|
||||
/* 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+i*9;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return vgmstream;
|
||||
|
||||
/* clean up anything we may have opened */
|
||||
fail:
|
||||
if (vgmstream) close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* .spw (SEWave, PlayOnline viewer for FFXI), very similar to bgw */
|
||||
VGMSTREAM * init_vgmstream_spw(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
char filename[PATH_LIMIT];
|
||||
off_t start_offset;
|
||||
|
||||
int loop_flag = 0;
|
||||
int32_t loop_start;
|
||||
int channel_count;
|
||||
|
||||
/* check extension, case insensitive */
|
||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||
if (strcasecmp("spw",filename_extension(filename))) goto fail;
|
||||
|
||||
/* "SeWave" */
|
||||
if (read_32bitBE(0,streamFile) != 0x53655761 ||
|
||||
read_32bitBE(4,streamFile) != 0x76650000) goto fail;
|
||||
|
||||
/* check file size with header value */
|
||||
if (read_32bitLE(0x8,streamFile) != get_streamfile_size(streamFile))
|
||||
goto fail;
|
||||
|
||||
channel_count = read_8bit(0x2a,streamFile);
|
||||
loop_start = read_32bitLE(0x18,streamFile);
|
||||
loop_flag = (loop_start > 0);
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
/* fill in the vital statistics */
|
||||
start_offset = read_32bitLE(0x24,streamFile);
|
||||
vgmstream->channels = channel_count;
|
||||
vgmstream->sample_rate = 44100;
|
||||
vgmstream->coding_type = coding_FFXI;
|
||||
vgmstream->num_samples = read_32bitLE(0x14,streamFile)*16;
|
||||
if (loop_flag) {
|
||||
vgmstream->loop_start_sample = (loop_start-1)*16;
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
}
|
||||
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 9;
|
||||
vgmstream->meta_type = meta_FFXI_SPW;
|
||||
|
||||
/* 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+i*9;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return vgmstream;
|
||||
|
||||
/* clean up anything we may have opened */
|
||||
fail:
|
||||
if (vgmstream) close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
|
@ -0,0 +1,202 @@
|
|||
#include "meta.h"
|
||||
#include "../layout/layout.h"
|
||||
#include "../util.h"
|
||||
#include "../vgmstream.h"
|
||||
|
||||
/* Namco Bandai's Bandai Namco Sound Format/File (BNSF) */
|
||||
/* similar to RIFX */
|
||||
|
||||
VGMSTREAM * init_vgmstream_bnsf(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
char filename[PATH_LIMIT];
|
||||
|
||||
off_t file_size = -1;
|
||||
uint32_t riff_size;
|
||||
uint32_t bnsf_form;
|
||||
enum {
|
||||
form_IS14 = UINT32_C(0x49533134), /* IS14 */
|
||||
};
|
||||
|
||||
int channel_count = 0;
|
||||
int sample_count = 0;
|
||||
int sample_rate = 0;
|
||||
int coding_type = -1;
|
||||
off_t start_offset = -1;
|
||||
|
||||
int loop_flag = 0;
|
||||
off_t loop_start = -1;
|
||||
off_t loop_end = -1;
|
||||
uint32_t data_size = 0;
|
||||
uint32_t block_size = 0;
|
||||
uint32_t block_samples = 0;
|
||||
|
||||
int FormatChunkFound = 0;
|
||||
int DataChunkFound = 0;
|
||||
|
||||
/* check extension, case insensitive */
|
||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||
if (strcasecmp("bnsf",filename_extension(filename)))
|
||||
{
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* check header */
|
||||
if ((uint32_t)read_32bitBE(0,streamFile)!=0x424E5346) /* BNSF */
|
||||
goto fail;
|
||||
|
||||
/* check form */
|
||||
bnsf_form = read_32bitBE(8,streamFile);
|
||||
switch (bnsf_form)
|
||||
{
|
||||
#ifdef VGM_USE_G7221
|
||||
case form_IS14:
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
|
||||
riff_size = read_32bitBE(4,streamFile);
|
||||
file_size = get_streamfile_size(streamFile);
|
||||
|
||||
/* check for tructated RIFF */
|
||||
if (file_size < riff_size+8) goto fail;
|
||||
|
||||
/* read through chunks to verify format and find metadata */
|
||||
{
|
||||
off_t current_chunk = 0xc; /* start with first chunk */
|
||||
|
||||
while (current_chunk < file_size && current_chunk < riff_size+8) {
|
||||
uint32_t chunk_type = read_32bitBE(current_chunk,streamFile);
|
||||
off_t chunk_size = read_32bitBE(current_chunk+4,streamFile);
|
||||
|
||||
if (current_chunk+8+chunk_size > file_size) goto fail;
|
||||
|
||||
switch(chunk_type) {
|
||||
case 0x73666d74: /* "sfmt" */
|
||||
/* only one per file */
|
||||
if (FormatChunkFound) goto fail;
|
||||
FormatChunkFound = 1;
|
||||
|
||||
sample_rate = read_32bitBE(current_chunk+0x0c,streamFile);
|
||||
channel_count = read_16bitBE(current_chunk+0x0a,streamFile);
|
||||
// read_32bitBE(current_chunk+0x10,streamFile); // ?
|
||||
// read_32bitBE(current_chunk+0x14,streamFile); // ?
|
||||
block_size = read_16bitBE(current_chunk+0x18,streamFile);
|
||||
block_samples = read_16bitBE(current_chunk+0x1a,streamFile);
|
||||
|
||||
/* I assume this is still the codec id, but as the codec is
|
||||
specified by the BNSF "form" I've only seen this zero */
|
||||
switch ((uint16_t)read_16bitBE(current_chunk+0x8,streamFile)) {
|
||||
case 0:
|
||||
break;
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
case 0x73646174: /* sdat */
|
||||
/* at most one per file */
|
||||
if (DataChunkFound) goto fail;
|
||||
DataChunkFound = 1;
|
||||
|
||||
start_offset = current_chunk + 8;
|
||||
data_size = chunk_size;
|
||||
break;
|
||||
case 0x6C6F6F70: /* loop */
|
||||
loop_flag = 1;
|
||||
loop_start =
|
||||
read_32bitBE(current_chunk+8, streamFile);
|
||||
loop_end =
|
||||
read_32bitBE(current_chunk+0xc,streamFile);
|
||||
break;
|
||||
default:
|
||||
/* ignorance is bliss */
|
||||
break;
|
||||
}
|
||||
|
||||
current_chunk += 8+chunk_size;
|
||||
}
|
||||
}
|
||||
|
||||
if (!FormatChunkFound || !DataChunkFound) goto fail;
|
||||
|
||||
switch (bnsf_form) {
|
||||
#ifdef VGM_USE_G7221
|
||||
case form_IS14:
|
||||
coding_type = coding_G7221C;
|
||||
sample_count = data_size/block_size*block_samples;
|
||||
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
/* fill in the vital statistics */
|
||||
vgmstream->num_samples = sample_count;
|
||||
vgmstream->sample_rate = sample_rate;
|
||||
|
||||
vgmstream->coding_type = coding_type;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = block_size/channel_count;
|
||||
|
||||
if (loop_flag) {
|
||||
vgmstream->loop_start_sample = loop_start;
|
||||
vgmstream->loop_end_sample = loop_end;
|
||||
}
|
||||
vgmstream->meta_type = meta_BNSF;
|
||||
|
||||
#ifdef VGM_USE_G7221
|
||||
if (coding_G7221C == coding_type)
|
||||
{
|
||||
int i;
|
||||
g7221_codec_data *data;
|
||||
|
||||
/* one data structure per channel */
|
||||
data = malloc(sizeof(g7221_codec_data) * channel_count);
|
||||
if (!data)
|
||||
{
|
||||
goto fail;
|
||||
}
|
||||
memset(data,0,sizeof(g7221_codec_data) * channel_count);
|
||||
vgmstream->codec_data = data;
|
||||
|
||||
for (i = 0; i < channel_count; i++)
|
||||
{
|
||||
/* Siren 14 == 14khz bandwidth */
|
||||
data[i].handle = g7221_init(vgmstream->interleave_block_size, 14000);
|
||||
if (!data[i].handle)
|
||||
{
|
||||
goto fail; /* close_vgmstream is able to clean up */
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* open the file, set up each channel */
|
||||
{
|
||||
int i;
|
||||
|
||||
vgmstream->ch[0].streamfile = streamFile->open(streamFile,filename,
|
||||
STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
if (!vgmstream->ch[0].streamfile) goto fail;
|
||||
|
||||
for (i=0;i<channel_count;i++) {
|
||||
vgmstream->ch[i].streamfile = vgmstream->ch[0].streamfile;
|
||||
vgmstream->ch[i].offset = vgmstream->ch[i].channel_start_offset =
|
||||
start_offset+i*vgmstream->interleave_block_size;
|
||||
}
|
||||
}
|
||||
|
||||
return vgmstream;
|
||||
|
||||
/* clean up anything we may have opened */
|
||||
fail:
|
||||
if (vgmstream) close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
|
@ -0,0 +1,163 @@
|
|||
#include "meta.h"
|
||||
#include "../util.h"
|
||||
|
||||
VGMSTREAM * init_vgmstream_brstm(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
char filename[PATH_LIMIT];
|
||||
|
||||
coding_t coding_type;
|
||||
|
||||
off_t head_offset;
|
||||
int codec_number;
|
||||
int channel_count;
|
||||
int loop_flag;
|
||||
/* Certain Super Paper Mario tracks have a 44.1KHz sample rate in the
|
||||
* header, but they should be played at 22.05KHz. We will make this
|
||||
* correction if we see a file with a .brstmspm extension. */
|
||||
int spm_flag = 0;
|
||||
/* Trauma Center Second Opinion has an odd, semi-corrupt header */
|
||||
int atlus_shrunken_head = 0;
|
||||
|
||||
off_t start_offset;
|
||||
|
||||
/* check extension, case insensitive */
|
||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||
if (strcasecmp("brstm",filename_extension(filename))) {
|
||||
if (strcasecmp("brstmspm",filename_extension(filename))) goto fail;
|
||||
else spm_flag = 1;
|
||||
}
|
||||
|
||||
/* check header */
|
||||
if ((uint32_t)read_32bitBE(0,streamFile)!=0x5253544D) /* "RSTM" */
|
||||
goto fail;
|
||||
if ((uint32_t)read_32bitBE(4,streamFile)!=0xFEFF0100)
|
||||
{
|
||||
if ((uint32_t)read_32bitBE(4,streamFile)!=0xFEFF0001)
|
||||
goto fail;
|
||||
else
|
||||
atlus_shrunken_head = 1;
|
||||
}
|
||||
|
||||
/* get head offset, check */
|
||||
head_offset = read_32bitBE(0x10,streamFile);
|
||||
if (atlus_shrunken_head)
|
||||
{
|
||||
/* the HEAD chunk is where we would expect to find the offset of that
|
||||
* chunk... */
|
||||
|
||||
if ((uint32_t)head_offset!=0x48454144 || read_32bitBE(0x14,streamFile) != 8)
|
||||
goto fail;
|
||||
|
||||
head_offset = -8; /* most of the normal Nintendo RSTM offsets work
|
||||
with this assumption */
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((uint32_t)read_32bitBE(head_offset,streamFile)!=0x48454144) /* "HEAD" */
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* check type details */
|
||||
codec_number = read_8bit(head_offset+0x20,streamFile);
|
||||
loop_flag = read_8bit(head_offset+0x21,streamFile);
|
||||
channel_count = read_8bit(head_offset+0x22,streamFile);
|
||||
|
||||
switch (codec_number) {
|
||||
case 0:
|
||||
coding_type = coding_PCM8;
|
||||
break;
|
||||
case 1:
|
||||
coding_type = coding_PCM16BE;
|
||||
break;
|
||||
case 2:
|
||||
coding_type = coding_NGC_DSP;
|
||||
break;
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (channel_count < 1) goto fail;
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
/* fill in the vital statistics */
|
||||
vgmstream->num_samples = read_32bitBE(head_offset+0x2c,streamFile);
|
||||
vgmstream->sample_rate = (uint16_t)read_16bitBE(head_offset+0x24,streamFile);
|
||||
/* channels and loop flag are set by allocate_vgmstream */
|
||||
vgmstream->loop_start_sample = read_32bitBE(head_offset+0x28,streamFile);
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
|
||||
vgmstream->coding_type = coding_type;
|
||||
if (channel_count==1)
|
||||
vgmstream->layout_type = layout_none;
|
||||
else
|
||||
vgmstream->layout_type = layout_interleave_shortblock;
|
||||
vgmstream->meta_type = meta_RSTM;
|
||||
if (atlus_shrunken_head)
|
||||
vgmstream->meta_type = meta_RSTM_shrunken;
|
||||
|
||||
if (spm_flag&& vgmstream->sample_rate == 44100) {
|
||||
vgmstream->meta_type = meta_RSTM_SPM;
|
||||
vgmstream->sample_rate = 22050;
|
||||
}
|
||||
|
||||
vgmstream->interleave_block_size = read_32bitBE(head_offset+0x38,streamFile);
|
||||
vgmstream->interleave_smallblock_size = read_32bitBE(head_offset+0x48,streamFile);
|
||||
|
||||
if (vgmstream->coding_type == coding_NGC_DSP) {
|
||||
off_t coef_offset;
|
||||
off_t coef_offset1;
|
||||
off_t coef_offset2;
|
||||
int i,j;
|
||||
int coef_spacing = 0x38;
|
||||
|
||||
if (atlus_shrunken_head)
|
||||
{
|
||||
coef_offset = 0x50;
|
||||
coef_spacing = 0x30;
|
||||
}
|
||||
else
|
||||
{
|
||||
coef_offset1=read_32bitBE(head_offset+0x1c,streamFile);
|
||||
coef_offset2=read_32bitBE(head_offset+0x10+coef_offset1,streamFile);
|
||||
coef_offset=coef_offset2+0x10;
|
||||
}
|
||||
|
||||
for (j=0;j<vgmstream->channels;j++) {
|
||||
for (i=0;i<16;i++) {
|
||||
vgmstream->ch[j].adpcm_coef[i]=read_16bitBE(head_offset+coef_offset+j*coef_spacing+i*2,streamFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
start_offset = read_32bitBE(head_offset+0x30,streamFile);
|
||||
|
||||
/* open the file for reading by each channel */
|
||||
{
|
||||
int i;
|
||||
for (i=0;i<channel_count;i++) {
|
||||
if (vgmstream->layout_type==layout_interleave_shortblock)
|
||||
vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,
|
||||
vgmstream->interleave_block_size);
|
||||
else
|
||||
vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,
|
||||
0x1000);
|
||||
|
||||
if (!vgmstream->ch[i].streamfile) goto fail;
|
||||
|
||||
vgmstream->ch[i].channel_start_offset=
|
||||
vgmstream->ch[i].offset=
|
||||
start_offset + i*vgmstream->interleave_block_size;
|
||||
}
|
||||
}
|
||||
|
||||
return vgmstream;
|
||||
|
||||
/* clean up anything we may have opened */
|
||||
fail:
|
||||
if (vgmstream) close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
#include "meta.h"
|
||||
#include "../util.h"
|
||||
|
||||
/* CAPDSP (found in Capcom games) */
|
||||
VGMSTREAM * init_vgmstream_capdsp(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
char filename[PATH_LIMIT];
|
||||
off_t start_offset;
|
||||
int loop_flag;
|
||||
int channel_count;
|
||||
|
||||
/* check extension, case insensitive */
|
||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||
if (strcasecmp("capdsp",filename_extension(filename))) goto fail;
|
||||
|
||||
loop_flag = (read_32bitBE(0x14,streamFile) !=2);
|
||||
channel_count = read_32bitBE(0x10,streamFile);
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
/* fill in the vital statistics */
|
||||
start_offset = 0x80;
|
||||
vgmstream->channels = channel_count;
|
||||
vgmstream->sample_rate = read_32bitBE(0x0C,streamFile);
|
||||
vgmstream->coding_type = coding_NGC_DSP;
|
||||
vgmstream->num_samples = read_32bitBE(0x04,streamFile);
|
||||
if (loop_flag) {
|
||||
vgmstream->loop_start_sample = read_32bitBE(0x14,streamFile)/8/channel_count*14;
|
||||
vgmstream->loop_end_sample = read_32bitBE(0x18,streamFile)/8/channel_count*14;
|
||||
}
|
||||
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x4000;
|
||||
vgmstream->meta_type = meta_CAPDSP;
|
||||
|
||||
if (vgmstream->coding_type == coding_NGC_DSP) {
|
||||
int i;
|
||||
for (i=0;i<8;i++) {
|
||||
vgmstream->ch[0].adpcm_coef[i*2]=read_16bitBE(0x20+i*2,streamFile);
|
||||
vgmstream->ch[0].adpcm_coef[i*2+1]=read_16bitBE(0x30+i*2,streamFile);
|
||||
vgmstream->ch[1].adpcm_coef[i*2]=read_16bitBE(0x40+i*2,streamFile);
|
||||
vgmstream->ch[1].adpcm_coef[i*2+1]=read_16bitBE(0x50+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;
|
||||
|
||||
/* clean up anything we may have opened */
|
||||
fail:
|
||||
if (vgmstream) close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
#include "meta.h"
|
||||
#include "../util.h"
|
||||
|
||||
/* ASD - found in Miss Moonlight (DC) */
|
||||
VGMSTREAM * init_vgmstream_dc_asd(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
char filename[PATH_LIMIT];
|
||||
off_t start_offset;
|
||||
int loop_flag;
|
||||
int channel_count;
|
||||
|
||||
/* check extension, case insensitive */
|
||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||
if (strcasecmp("asd",filename_extension(filename))) goto fail;
|
||||
|
||||
/* We have no "Magic" words in this header format, so we have to do some,
|
||||
other checks, it seems the samplecount is stored twice in the header,
|
||||
we'll compare it... */
|
||||
if (read_32bitLE(0x0,streamFile) != read_32bitLE(0x4,streamFile))
|
||||
goto fail;
|
||||
/* compare the frequency with the bitrate, if it doesn't match we'll close
|
||||
the vgmstream... */
|
||||
if (read_32bitLE(0x10,streamFile)/read_32bitLE(0xC,streamFile) != (uint16_t)read_16bitLE(0xA,streamFile)*2)
|
||||
goto fail;
|
||||
|
||||
loop_flag = 0;
|
||||
channel_count = read_16bitLE(0x0A,streamFile);
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
/* fill in the vital statistics */
|
||||
start_offset = get_streamfile_size(streamFile) - read_32bitLE(0x0,streamFile);
|
||||
vgmstream->channels = channel_count;
|
||||
vgmstream->sample_rate = read_32bitLE(0x0C,streamFile);
|
||||
vgmstream->coding_type = coding_PCM16LE;
|
||||
vgmstream->num_samples = read_32bitLE(0x0,streamFile)/2/channel_count;
|
||||
if (loop_flag) {
|
||||
vgmstream->loop_start_sample = 0;
|
||||
vgmstream->loop_end_sample = read_32bitLE(0x0,streamFile)/2/channel_count;
|
||||
}
|
||||
|
||||
vgmstream->meta_type = meta_DC_ASD;
|
||||
|
||||
if (vgmstream->channels == 1) {
|
||||
vgmstream->layout_type = layout_none;
|
||||
} else if (vgmstream->channels == 2) {
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x2;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
|
@ -0,0 +1,119 @@
|
|||
#include "meta.h"
|
||||
#include "../util.h"
|
||||
|
||||
/* WAV+DCS (DCSW+DCS)
|
||||
2008-12-06 - manakoAT : Evil Twin - Cypriens Chronicles...
|
||||
2008-12-07 - manakoAT : Added a function to read the Header file and for
|
||||
retrieving the channels/frequency, Frequency starts
|
||||
always at a "data" chunk - 0x0C bytes, Channels
|
||||
always - 0x0E bytes...
|
||||
2010-01-13 - manakoAT : Changed the 'Helper' extension from .wav to .dcws, to prevent conflicts */
|
||||
|
||||
VGMSTREAM * init_vgmstream_dc_dcsw_dcs(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
STREAMFILE * streamFileDCSW = NULL;
|
||||
char filename[PATH_LIMIT];
|
||||
char filenameDCSW[260];
|
||||
int i;
|
||||
int channel_count;
|
||||
int loop_flag;
|
||||
int frequency;
|
||||
int dataBuffer = 0;
|
||||
int Founddata = 0;
|
||||
size_t file_size;
|
||||
off_t current_chunk;
|
||||
|
||||
/* check extension, case insensitive */
|
||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||
if (strcasecmp("dcs",filename_extension(filename))) goto fail;
|
||||
|
||||
/* Getting the Header file name... */
|
||||
strcpy(filenameDCSW,filename);
|
||||
strcpy(filenameDCSW+strlen(filenameDCSW)-3,"dcsw");
|
||||
|
||||
/* Look if the Header file is present, else cancel vgmstream */
|
||||
streamFileDCSW = streamFile->open(streamFile,filenameDCSW,STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
if (!streamFileDCSW) goto fail;
|
||||
|
||||
/* check header */
|
||||
if (read_32bitBE(0x00,streamFileDCSW) != 0x52494646 || /* "RIFF" */
|
||||
read_32bitBE(0x08,streamFileDCSW) != 0x57415645 || /* "WAVE" */
|
||||
read_32bitBE(0x0C,streamFileDCSW) != 0x34582E76 || /* 0x34582E76 */
|
||||
read_32bitBE(0x3C,streamFileDCSW) != 0x406E616D) /* "@nam" */
|
||||
goto fail;
|
||||
|
||||
/* scan file until we find a "data" string */
|
||||
file_size = get_streamfile_size(streamFileDCSW);
|
||||
{
|
||||
current_chunk = 0;
|
||||
/* Start at 0 and loop until we reached the
|
||||
file size, or until we found a "data string */
|
||||
while (!Founddata && current_chunk < file_size) {
|
||||
dataBuffer = (read_32bitBE(current_chunk,streamFileDCSW));
|
||||
if (dataBuffer == 0x64617461) { /* "data" */
|
||||
/* if "data" string found, retrieve the needed infos */
|
||||
Founddata = 1;
|
||||
/* We will cancel the search here if we have a match */
|
||||
break;
|
||||
}
|
||||
/* else we will increase the search offset by 1 */
|
||||
current_chunk = current_chunk + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (Founddata == 0) {
|
||||
goto fail;
|
||||
} else if (Founddata == 1) {
|
||||
channel_count = (uint16_t)read_16bitLE(current_chunk-0x0E,streamFileDCSW);
|
||||
frequency = read_32bitLE(current_chunk-0x0C,streamFileDCSW);
|
||||
}
|
||||
|
||||
loop_flag = 0;
|
||||
|
||||
/* Seems we're dealing with a vaild file+header,
|
||||
now we can finally build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
/* fill in the vital statistics */
|
||||
vgmstream->channels = channel_count;
|
||||
vgmstream->sample_rate = frequency;
|
||||
vgmstream->num_samples=(get_streamfile_size(streamFile))*2/channel_count;
|
||||
|
||||
if(loop_flag) {
|
||||
vgmstream->loop_start_sample = 0;
|
||||
vgmstream->loop_end_sample = (get_streamfile_size(streamFile))*2/channel_count;
|
||||
}
|
||||
|
||||
if (channel_count == 1) {
|
||||
vgmstream->layout_type = layout_none;
|
||||
} else if (channel_count > 1) {
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x4000;
|
||||
}
|
||||
|
||||
vgmstream->coding_type = coding_AICA;
|
||||
vgmstream->meta_type = meta_DC_DCSW_DCS;
|
||||
|
||||
/* open the file for reading by each channel */
|
||||
{
|
||||
for (i=0;i<channel_count;i++) {
|
||||
vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,vgmstream->interleave_block_size);
|
||||
|
||||
if (!vgmstream->ch[i].streamfile) goto fail;
|
||||
vgmstream->ch[i].channel_start_offset=
|
||||
vgmstream->ch[i].offset=i*vgmstream->interleave_block_size;
|
||||
vgmstream->ch[i].adpcm_step_index = 0x7f; /* AICA */
|
||||
}
|
||||
}
|
||||
|
||||
close_streamfile(streamFileDCSW); streamFileDCSW=NULL;
|
||||
|
||||
return vgmstream;
|
||||
|
||||
/* clean up anything we may have opened */
|
||||
fail:
|
||||
if (streamFileDCSW) close_streamfile(streamFileDCSW);
|
||||
if (vgmstream) close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
#include "meta.h"
|
||||
#include "../util.h"
|
||||
|
||||
/* IDVI (Eldorado Gate Volume 1-7) */
|
||||
VGMSTREAM * init_vgmstream_dc_idvi(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
char filename[PATH_LIMIT];
|
||||
off_t start_offset;
|
||||
|
||||
int loop_flag;
|
||||
int channel_count;
|
||||
|
||||
/* check extension, case insensitive */
|
||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||
if (strcasecmp("idvi",filename_extension(filename))) goto fail;
|
||||
|
||||
/* check header */
|
||||
if (read_32bitBE(0x00,streamFile) != 0x49445649) /* "IDVI." */
|
||||
goto fail;
|
||||
|
||||
loop_flag = read_32bitLE(0x0C,streamFile);
|
||||
channel_count = read_32bitLE(0x04,streamFile);
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
/* fill in the vital statistics */
|
||||
vgmstream->channels = channel_count;
|
||||
start_offset = 0x800;
|
||||
vgmstream->sample_rate = read_32bitLE(0x08,streamFile);
|
||||
vgmstream->coding_type = coding_INT_DVI_IMA;
|
||||
vgmstream->num_samples = (get_streamfile_size(streamFile)-start_offset);
|
||||
if (loop_flag) {
|
||||
vgmstream->loop_start_sample = read_32bitLE(0x0C,streamFile);
|
||||
vgmstream->loop_end_sample = (get_streamfile_size(streamFile)-start_offset);
|
||||
}
|
||||
vgmstream->meta_type = meta_DC_IDVI;
|
||||
|
||||
/* Calculating the short block... */
|
||||
if (channel_count > 1) {
|
||||
vgmstream->interleave_block_size = 0x400;
|
||||
vgmstream->interleave_smallblock_size = ((get_streamfile_size(streamFile)-start_offset)%(vgmstream->channels*vgmstream->interleave_block_size))/vgmstream->channels;
|
||||
vgmstream->layout_type = layout_interleave_shortblock;
|
||||
} else {
|
||||
vgmstream->layout_type = layout_none;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
#include "../util.h"
|
||||
|
||||
VGMSTREAM * init_vgmstream_kcey(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
char filename[PATH_LIMIT];
|
||||
off_t start_offset;
|
||||
|
||||
int loop_flag = 0;
|
||||
int channel_count;
|
||||
|
||||
/* check extension, case insensitive */
|
||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||
if (strcasecmp("kcey",filename_extension(filename))) goto fail;
|
||||
|
||||
/* check header */
|
||||
if (read_32bitBE(0x00,streamFile) != 0x4B434559) /* "DVI." */
|
||||
goto fail;
|
||||
|
||||
loop_flag = (read_32bitBE(0x14,streamFile)!=0xFFFFFFFF);
|
||||
channel_count = read_32bitBE(0x08,streamFile);
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
/* fill in the vital statistics */
|
||||
vgmstream->channels = channel_count;
|
||||
start_offset = read_32bitBE(0x10,streamFile);
|
||||
vgmstream->sample_rate = 37800;
|
||||
vgmstream->coding_type = coding_EACS_IMA;
|
||||
|
||||
vgmstream->num_samples = read_32bitBE(0x0C,streamFile);
|
||||
|
||||
if (loop_flag) {
|
||||
vgmstream->loop_start_sample = read_32bitBE(0x14,streamFile);
|
||||
vgmstream->loop_end_sample = read_32bitBE(0x0C,streamFile);
|
||||
}
|
||||
|
||||
vgmstream->layout_type = layout_none;
|
||||
vgmstream->meta_type = meta_KCEY;
|
||||
vgmstream->get_high_nibble=1;
|
||||
|
||||
/* 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+(i*vgmstream->interleave_block_size);
|
||||
vgmstream->ch[i].adpcm_history1_32=0;
|
||||
vgmstream->ch[i].adpcm_step_index=0;
|
||||
}
|
||||
}
|
||||
|
||||
return vgmstream;
|
||||
|
||||
/* clean up anything we may have opened */
|
||||
fail:
|
||||
if (vgmstream) close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
|
@ -0,0 +1,165 @@
|
|||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
#include "../util.h"
|
||||
|
||||
/* SEGA Stream Asset Builder...
|
||||
this meta handles only V1 and V3... */
|
||||
|
||||
VGMSTREAM * init_vgmstream_dc_str(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
char filename[PATH_LIMIT];
|
||||
off_t start_offset;
|
||||
int loop_flag = 0;
|
||||
int interleave;
|
||||
int channel_count;
|
||||
int samples;
|
||||
|
||||
/* check extension, case insensitive */
|
||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||
if (strcasecmp("str",filename_extension(filename))) goto fail;
|
||||
|
||||
/* check header */
|
||||
if (read_32bitBE(0xD5,streamFile) != 0x53656761) /* "Sega" */
|
||||
goto fail;
|
||||
|
||||
interleave = read_32bitLE(0xC,streamFile);
|
||||
if ((get_streamfile_size(streamFile)-0x800) != (read_32bitLE(0x10,streamFile) *
|
||||
((read_32bitLE(0x0,streamFile)*(read_32bitLE(0x18,streamFile))))*interleave))
|
||||
goto fail;
|
||||
|
||||
|
||||
loop_flag = 0; /* (read_32bitLE(0x00,streamFile)!=0x00000000); */
|
||||
samples = read_32bitLE(0x08,streamFile);
|
||||
channel_count = (read_32bitLE(0x0,streamFile))*(read_32bitLE(0x18,streamFile));
|
||||
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
|
||||
/* fill in the vital statistics */
|
||||
switch (samples) {
|
||||
case 4:
|
||||
vgmstream->coding_type = coding_AICA;
|
||||
vgmstream->num_samples = read_32bitLE(0x14,streamFile);
|
||||
if (loop_flag) {
|
||||
vgmstream->loop_start_sample = 0;
|
||||
vgmstream->loop_end_sample = read_32bitLE(0x14,streamFile);
|
||||
}
|
||||
break;
|
||||
case 16:
|
||||
vgmstream->coding_type = coding_PCM16LE;
|
||||
vgmstream->num_samples = read_32bitLE(0x14,streamFile)/2/channel_count;
|
||||
if (loop_flag) {
|
||||
vgmstream->loop_start_sample = 0;
|
||||
vgmstream->loop_end_sample = read_32bitLE(0x14,streamFile)/2/channel_count;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
||||
start_offset = 0x800;
|
||||
vgmstream->channels = channel_count;
|
||||
vgmstream->sample_rate = read_32bitLE(0x04,streamFile);
|
||||
|
||||
if (vgmstream->channels == 1) {
|
||||
vgmstream->layout_type = layout_none;
|
||||
} else if (vgmstream->channels > 1) {
|
||||
vgmstream->interleave_block_size = interleave;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
}
|
||||
|
||||
vgmstream->meta_type = meta_DC_STR;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* This handles V2, not sure if it is really V2, cause the header is always
|
||||
the same, not like in V1 and V3, only found in "102 Dalmatians - Puppies to the Rescue"
|
||||
until now... */
|
||||
|
||||
VGMSTREAM * init_vgmstream_dc_str_v2(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
char filename[PATH_LIMIT];
|
||||
off_t start_offset;
|
||||
int loop_flag = 0;
|
||||
int channel_count;
|
||||
|
||||
/* check extension, case insensitive */
|
||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||
if (strcasecmp("str",filename_extension(filename))) goto fail;
|
||||
|
||||
/* check header */
|
||||
if ((read_32bitLE(0x00,streamFile) != 0x2))
|
||||
goto fail;
|
||||
if ((read_32bitLE(0x10,streamFile) != 0x10000))
|
||||
goto fail;
|
||||
if ((read_32bitLE(0x1C,streamFile) != 0x1F))
|
||||
goto fail;
|
||||
|
||||
channel_count = 2;
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
/* fill in the vital statistics */
|
||||
start_offset = 0x800;
|
||||
vgmstream->channels = channel_count;
|
||||
vgmstream->sample_rate = read_32bitLE(0x4,streamFile);
|
||||
vgmstream->coding_type = coding_PCM16LE;
|
||||
vgmstream->num_samples = (get_streamfile_size(streamFile)-start_offset)/2/channel_count;
|
||||
if (loop_flag) {
|
||||
vgmstream->loop_start_sample = 0;
|
||||
vgmstream->loop_end_sample = (get_streamfile_size(streamFile)-start_offset)/2/channel_count;
|
||||
}
|
||||
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = read_32bitLE(0xC,streamFile);
|
||||
vgmstream->meta_type = meta_DC_STR_V2;
|
||||
|
||||
/* 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;
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
#include "meta.h"
|
||||
#include "../layout/layout.h"
|
||||
#include "../util.h"
|
||||
|
||||
/* Gurumin .de2 */
|
||||
/* A ways into the file we have a fake RIFF header wrapping MS ADPCM */
|
||||
|
||||
VGMSTREAM * init_vgmstream_de2(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
char filename[PATH_LIMIT];
|
||||
|
||||
off_t riff_off;
|
||||
int channel_count;
|
||||
int sample_count;
|
||||
int sample_rate;
|
||||
off_t start_offset;
|
||||
|
||||
int loop_flag = 0;
|
||||
uint32_t data_size;
|
||||
|
||||
/* check extension, case insensitive */
|
||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||
if (strcasecmp("de2",filename_extension(filename))) goto fail;
|
||||
|
||||
/* still not sure what this is for, but consistently 0xb */
|
||||
if (read_32bitLE(0x04,streamFile)!=0xb) goto fail;
|
||||
|
||||
/* legitimate! really! */
|
||||
riff_off = 0x10 +
|
||||
(read_32bitLE(0x0c,streamFile) ^ read_32bitLE(0x04,streamFile));
|
||||
|
||||
/* check header */
|
||||
if ((uint32_t)read_32bitBE(riff_off+0,streamFile)!=0x52494646) /* "RIFF" */
|
||||
goto fail;
|
||||
/* check for WAVE form */
|
||||
if ((uint32_t)read_32bitBE(riff_off+8,streamFile)!=0x57415645) /* "WAVE" */
|
||||
goto fail;
|
||||
/* check for "fmt " */
|
||||
if ((uint32_t)read_32bitBE(riff_off+12,streamFile)!=0x666d7420) /* "fmt " */
|
||||
goto fail;
|
||||
/* check for "data" */
|
||||
if ((uint32_t)read_32bitBE(riff_off+0x24,streamFile)!=0x64617461) /* "data" */
|
||||
goto fail;
|
||||
/* check for bad fmt chunk size */
|
||||
if (read_32bitLE(riff_off+0x10,streamFile)!=0x12) goto fail;
|
||||
|
||||
sample_rate = read_32bitLE(riff_off+0x18,streamFile);
|
||||
|
||||
channel_count = read_16bitLE(riff_off+0x16,streamFile);
|
||||
if (channel_count != 2) goto fail;
|
||||
|
||||
/* PCM */
|
||||
if (read_16bitLE(riff_off+0x14,streamFile) != 1) goto fail;
|
||||
|
||||
/* 16-bit */
|
||||
if (read_16bitLE(riff_off+0x20,streamFile) != 4 ||
|
||||
read_16bitLE(riff_off+0x22,streamFile) != 16) goto fail;
|
||||
|
||||
start_offset = riff_off + 0x2c;
|
||||
data_size = read_32bitLE(riff_off+0x28,streamFile);
|
||||
|
||||
sample_count = data_size/2/channel_count;
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
/* fill in the vital statistics */
|
||||
vgmstream->num_samples = sample_count;
|
||||
vgmstream->sample_rate = sample_rate;
|
||||
|
||||
vgmstream->coding_type = coding_MSADPCM;
|
||||
vgmstream->layout_type = layout_de2_blocked;
|
||||
vgmstream->interleave_block_size = 0x800;
|
||||
|
||||
vgmstream->meta_type = meta_DE2;
|
||||
|
||||
/* open the file, set up each channel */
|
||||
{
|
||||
int i;
|
||||
|
||||
vgmstream->ch[0].streamfile = streamFile->open(streamFile,filename,
|
||||
STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
if (!vgmstream->ch[0].streamfile) goto fail;
|
||||
|
||||
for (i=0;i<channel_count;i++) {
|
||||
vgmstream->ch[i].streamfile = vgmstream->ch[0].streamfile;
|
||||
}
|
||||
}
|
||||
|
||||
/* start me up */
|
||||
de2_block_update(start_offset,vgmstream);
|
||||
|
||||
return vgmstream;
|
||||
|
||||
/* clean up anything we may have opened */
|
||||
fail:
|
||||
if (vgmstream) close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
|
@ -0,0 +1,110 @@
|
|||
#include "meta.h"
|
||||
#include "../util.h"
|
||||
|
||||
/* DMSG
|
||||
found in: Nightcaster II - Equinox
|
||||
2010-01-05 (manakoAT): Seems it's a corrupted "SGT" file, but I'm not sure...
|
||||
*/
|
||||
VGMSTREAM * init_vgmstream_dmsg(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
char filename[PATH_LIMIT];
|
||||
int loop_flag = 0;
|
||||
int frequency;
|
||||
int channel_count;
|
||||
int dataBuffer = 0;
|
||||
int Founddata = 0;
|
||||
size_t file_size;
|
||||
off_t current_chunk;
|
||||
off_t start_offset;
|
||||
|
||||
/* check extension, case insensitive */
|
||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||
if (strcasecmp("dmsg",filename_extension(filename))) goto fail;
|
||||
|
||||
/* check header */
|
||||
if (read_32bitBE(0x00,streamFile) != 0x52494646) /* "RIFF" */
|
||||
goto fail;
|
||||
if (read_32bitBE(0x08,streamFile) != 0x444D5347) /* "DMSG" */
|
||||
goto fail;
|
||||
if (read_32bitBE(0x0C,streamFile) != 0x73656768) /* "segh" */
|
||||
goto fail;
|
||||
if (read_32bitBE(0x10,streamFile) != 0x38000000) /* "0x38" */
|
||||
goto fail;
|
||||
|
||||
/* scan file until we find a "data" string */
|
||||
file_size = get_streamfile_size(streamFile);
|
||||
{
|
||||
current_chunk = 0;
|
||||
/* Start at 0 and loop until we reached the
|
||||
file size, or until we found a "data string */
|
||||
while (!Founddata && current_chunk < file_size) {
|
||||
dataBuffer = (read_32bitBE(current_chunk,streamFile));
|
||||
if (dataBuffer == 0x64617461) { /* "data" */
|
||||
/* if "data" string found, retrieve the needed infos */
|
||||
Founddata = 1;
|
||||
/* We will cancel the search here if we have a match */
|
||||
break;
|
||||
}
|
||||
/* else we will increase the search offset by 1 */
|
||||
current_chunk = current_chunk + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (Founddata == 0) {
|
||||
goto fail;
|
||||
} else if (Founddata == 1) {
|
||||
channel_count = (uint16_t)read_16bitLE(current_chunk-0x10,streamFile);
|
||||
frequency = read_32bitLE(current_chunk-0xE,streamFile);
|
||||
}
|
||||
|
||||
loop_flag = 1;
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
/* fill in the vital statistics */
|
||||
if (Founddata == 0) {
|
||||
goto fail;
|
||||
} else if (Founddata == 1) {
|
||||
start_offset = current_chunk+0x8;
|
||||
vgmstream->channels = channel_count;
|
||||
vgmstream->sample_rate = frequency;
|
||||
vgmstream->coding_type = coding_PCM16LE;
|
||||
vgmstream->num_samples = (read_32bitLE(current_chunk+0x4,streamFile)/2/channel_count);
|
||||
if (loop_flag) {
|
||||
vgmstream->loop_start_sample = 0;
|
||||
vgmstream->loop_end_sample = (read_32bitLE(current_chunk+0x4,streamFile)/2/channel_count);
|
||||
}
|
||||
}
|
||||
|
||||
if (channel_count == 1) {
|
||||
vgmstream->layout_type = layout_none;
|
||||
} else if (channel_count > 1) {
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x2;
|
||||
}
|
||||
|
||||
vgmstream->meta_type = meta_DMSG;
|
||||
|
||||
/* 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;
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
#include "meta.h"
|
||||
#include "../layout/layout.h"
|
||||
#include "../util.h"
|
||||
|
||||
VGMSTREAM * init_vgmstream_dsp_bdsp(STREAMFILE *streamFile) {
|
||||
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
char filename[PATH_LIMIT];
|
||||
int channel_count;
|
||||
int loop_flag;
|
||||
int i;
|
||||
off_t start_offset;
|
||||
|
||||
/* check extension, case insensitive */
|
||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||
if (strcasecmp("bdsp",filename_extension(filename))) goto fail;
|
||||
|
||||
channel_count = 2;
|
||||
loop_flag = 0;
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
/* fill in the vital statistics */
|
||||
vgmstream->channels = channel_count;
|
||||
vgmstream->sample_rate = read_32bitBE(0x8,streamFile);
|
||||
vgmstream->coding_type = coding_NGC_DSP;
|
||||
|
||||
#if 0
|
||||
if(loop_flag) {
|
||||
vgmstream->loop_start_sample = read_32bitBE(0x64,streamFile);
|
||||
vgmstream->loop_end_sample = read_32bitBE(0x68,streamFile);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
vgmstream->layout_type = layout_dsp_bdsp_blocked;
|
||||
vgmstream->interleave_block_size = 0x8;
|
||||
vgmstream->meta_type = meta_DSP_BDSP;
|
||||
|
||||
/* open the file for reading by each channel */
|
||||
{
|
||||
for (i=0;i<channel_count;i++) {
|
||||
vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,vgmstream->interleave_block_size);
|
||||
|
||||
if (!vgmstream->ch[i].streamfile) goto fail;
|
||||
vgmstream->ch[i].channel_start_offset=
|
||||
vgmstream->ch[i].offset=i*vgmstream->interleave_block_size;
|
||||
}
|
||||
}
|
||||
|
||||
if (vgmstream->coding_type == coding_NGC_DSP) {
|
||||
int i;
|
||||
for (i=0;i<16;i++) {
|
||||
vgmstream->ch[0].adpcm_coef[i] = read_16bitBE(0x1C+i*2,streamFile);
|
||||
}
|
||||
if (vgmstream->channels == 2) {
|
||||
for (i=0;i<16;i++) {
|
||||
vgmstream->ch[1].adpcm_coef[i] = read_16bitBE(0x7C+i*2,streamFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Calc num_samples */
|
||||
start_offset = 0x0;
|
||||
dsp_bdsp_block_update(start_offset,vgmstream);
|
||||
vgmstream->num_samples=0;
|
||||
|
||||
do
|
||||
{
|
||||
vgmstream->num_samples += vgmstream->current_block_size*14/8;
|
||||
dsp_bdsp_block_update(vgmstream->next_block_offset,vgmstream);
|
||||
}
|
||||
while (vgmstream->next_block_offset<get_streamfile_size(streamFile));
|
||||
|
||||
dsp_bdsp_block_update(start_offset,vgmstream);
|
||||
|
||||
|
||||
return vgmstream;
|
||||
|
||||
|
||||
/* clean up anything we may have opened */
|
||||
fail:
|
||||
if (vgmstream) close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
|
@ -0,0 +1,320 @@
|
|||
#include "meta.h"
|
||||
#include "../util.h"
|
||||
|
||||
/*
|
||||
STH+STR
|
||||
found in SpongebobSquarepants: Creature From The Krusty Krab (NGC)
|
||||
*/
|
||||
|
||||
VGMSTREAM * init_vgmstream_ngc_dsp_sth_str1(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
STREAMFILE * streamFileSTR = NULL;
|
||||
char filename[PATH_LIMIT];
|
||||
char filenameSTR[260];
|
||||
int i, j;
|
||||
int channel_count;
|
||||
int loop_flag;
|
||||
off_t coef_table[8] = {0x12C,0x18C,0x1EC,0x24C,0x2AC,0x30C,0x36C,0x3CC};
|
||||
|
||||
/* check extension, case insensitive */
|
||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||
if (strcasecmp("sth",filename_extension(filename))) goto fail;
|
||||
|
||||
strcpy(filenameSTR,filename);
|
||||
strcpy(filenameSTR+strlen(filenameSTR)-3,"str");
|
||||
streamFileSTR = streamFile->open(streamFile,filenameSTR,STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
if (!streamFileSTR) goto fail;
|
||||
|
||||
if (read_32bitBE(0x0,streamFile) != 0x0)
|
||||
{
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (read_32bitBE(0x4,streamFile) != 0x800)
|
||||
{
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Not really channel_count, just 'included tracks * channels per track */
|
||||
loop_flag = (read_32bitBE(0xD8,streamFile) != 0xFFFFFFFF);
|
||||
channel_count = (read_32bitBE(0x70,streamFile)) * (read_32bitBE(0x88,streamFile));
|
||||
|
||||
if (channel_count > 8)
|
||||
{
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
/* fill in the vital statistics */
|
||||
vgmstream->channels = channel_count;
|
||||
vgmstream->sample_rate = read_32bitBE(0x24,streamFile);
|
||||
vgmstream->num_samples=get_streamfile_size(streamFileSTR)/8/channel_count*14;
|
||||
vgmstream->coding_type = coding_NGC_DSP;
|
||||
|
||||
if(loop_flag)
|
||||
{
|
||||
vgmstream->loop_start_sample = read_32bitBE(0xD8,streamFile);
|
||||
vgmstream->loop_end_sample = read_32bitBE(0xDC,streamFile);
|
||||
}
|
||||
|
||||
if (channel_count == 1)
|
||||
{
|
||||
vgmstream->layout_type = layout_none;
|
||||
}
|
||||
else
|
||||
{
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
if (channel_count == 2)
|
||||
{
|
||||
vgmstream->interleave_block_size=0x10000;
|
||||
}
|
||||
else
|
||||
{
|
||||
vgmstream->interleave_block_size=0x8000;
|
||||
}
|
||||
}
|
||||
|
||||
vgmstream->meta_type = meta_NGC_DSP_STH_STR;
|
||||
|
||||
/* open the file for reading */
|
||||
for (i=0;i<channel_count;i++)
|
||||
{
|
||||
vgmstream->ch[i].streamfile = streamFileSTR->open(streamFileSTR,filenameSTR,0x8000);
|
||||
if (!vgmstream->ch[i].streamfile) goto fail;
|
||||
vgmstream->ch[i].channel_start_offset=vgmstream->ch[i].offset=i*vgmstream->interleave_block_size;
|
||||
}
|
||||
|
||||
// COEFFS
|
||||
for (j=0;j<vgmstream->channels;j++)
|
||||
{
|
||||
for (i=0;i<16;i++)
|
||||
{
|
||||
vgmstream->ch[j].adpcm_coef[i] = read_16bitBE(coef_table[j]+i*2,streamFile);
|
||||
}
|
||||
}
|
||||
|
||||
close_streamfile(streamFileSTR); streamFileSTR=NULL;
|
||||
return vgmstream;
|
||||
|
||||
/* clean up anything we may have opened */
|
||||
fail:
|
||||
if (streamFileSTR) close_streamfile(streamFileSTR);
|
||||
if (vgmstream) close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
STH+STR
|
||||
found in Taz Wanted (NGC), Cubix Robots for Everyone: Showdown (NGC)
|
||||
*/
|
||||
|
||||
VGMSTREAM * init_vgmstream_ngc_dsp_sth_str2(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
STREAMFILE * streamFileSTR = NULL;
|
||||
char filename[PATH_LIMIT];
|
||||
char filenameSTR[260];
|
||||
int i, j;
|
||||
int channel_count;
|
||||
int loop_flag;
|
||||
off_t coef_table[8] = {0xDC,0x13C,0x19C,0x1FC,0x25C,0x2BC,0x31C,0x37C};
|
||||
|
||||
/* check extension, case insensitive */
|
||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||
if (strcasecmp("sth",filename_extension(filename))) goto fail;
|
||||
|
||||
strcpy(filenameSTR,filename);
|
||||
strcpy(filenameSTR+strlen(filenameSTR)-3,"str");
|
||||
streamFileSTR = streamFile->open(streamFile,filenameSTR,STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
if (!streamFileSTR) goto fail;
|
||||
|
||||
if (read_32bitBE(0x0,streamFile) != 0x0)
|
||||
{
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (read_32bitBE(0x4,streamFile) != 0x900)
|
||||
{
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Not really channel_count, just 'included tracks * channels per track */
|
||||
loop_flag = (read_32bitBE(0xB8,streamFile) != 0xFFFFFFFF);
|
||||
channel_count = read_32bitBE(0x50,streamFile)*2;
|
||||
|
||||
if (channel_count > 8)
|
||||
{
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
/* fill in the vital statistics */
|
||||
vgmstream->channels = channel_count;
|
||||
vgmstream->sample_rate = read_32bitBE(0x24,streamFile);
|
||||
vgmstream->num_samples=get_streamfile_size(streamFileSTR)/8/channel_count*14;
|
||||
vgmstream->coding_type = coding_NGC_DSP;
|
||||
|
||||
if(loop_flag)
|
||||
{
|
||||
vgmstream->loop_start_sample = read_32bitBE(0xB8,streamFile);
|
||||
vgmstream->loop_end_sample = read_32bitBE(0xBC,streamFile);
|
||||
}
|
||||
|
||||
if (channel_count == 1)
|
||||
{
|
||||
vgmstream->layout_type = layout_none;
|
||||
}
|
||||
else
|
||||
{
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
if (channel_count == 2)
|
||||
{
|
||||
vgmstream->interleave_block_size=0x10000;
|
||||
}
|
||||
else
|
||||
{
|
||||
vgmstream->interleave_block_size=0x8000;
|
||||
}
|
||||
}
|
||||
|
||||
vgmstream->meta_type = meta_NGC_DSP_STH_STR;
|
||||
|
||||
/* open the file for reading */
|
||||
for (i=0;i<channel_count;i++)
|
||||
{
|
||||
vgmstream->ch[i].streamfile = streamFileSTR->open(streamFileSTR,filenameSTR,0x8000);
|
||||
if (!vgmstream->ch[i].streamfile) goto fail;
|
||||
vgmstream->ch[i].channel_start_offset=vgmstream->ch[i].offset=i*vgmstream->interleave_block_size;
|
||||
}
|
||||
|
||||
// COEFFS
|
||||
for (j=0;j<vgmstream->channels;j++)
|
||||
{
|
||||
for (i=0;i<16;i++)
|
||||
{
|
||||
vgmstream->ch[j].adpcm_coef[i] = read_16bitBE(coef_table[j]+i*2,streamFile);
|
||||
}
|
||||
}
|
||||
|
||||
close_streamfile(streamFileSTR); streamFileSTR=NULL;
|
||||
return vgmstream;
|
||||
|
||||
/* clean up anything we may have opened */
|
||||
fail:
|
||||
if (streamFileSTR) close_streamfile(streamFileSTR);
|
||||
if (vgmstream) close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
STH+STR
|
||||
found in Tak and the Guardians of Gross (WII)
|
||||
*/
|
||||
|
||||
VGMSTREAM * init_vgmstream_ngc_dsp_sth_str3(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
STREAMFILE * streamFileSTR = NULL;
|
||||
char filename[PATH_LIMIT];
|
||||
char filenameSTR[260];
|
||||
int i, j;
|
||||
int channel_count;
|
||||
int loop_flag;
|
||||
off_t coef_table[8] = {read_32bitBE(0x7C,streamFile),read_32bitBE(0x80,streamFile),read_32bitBE(0x84,streamFile),read_32bitBE(0x88,streamFile),read_32bitBE(0x8C,streamFile),read_32bitBE(0x90,streamFile),read_32bitBE(0x94,streamFile),read_32bitBE(0x98,streamFile)};
|
||||
|
||||
/* check extension, case insensitive */
|
||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||
if (strcasecmp("sth",filename_extension(filename))) goto fail;
|
||||
|
||||
strcpy(filenameSTR,filename);
|
||||
strcpy(filenameSTR+strlen(filenameSTR)-3,"str");
|
||||
streamFileSTR = streamFile->open(streamFile,filenameSTR,STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
if (!streamFileSTR) goto fail;
|
||||
|
||||
if (read_32bitBE(0x0,streamFile) != 0x0)
|
||||
{
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if ((read_32bitBE(0x4,streamFile) != 0x700) &&
|
||||
(read_32bitBE(0x4,streamFile) != 0x800))
|
||||
{
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Not really channel_count, just 'included tracks * channels per track */
|
||||
loop_flag = 0;
|
||||
channel_count = read_32bitBE(0x70,streamFile);
|
||||
|
||||
if (channel_count > 8)
|
||||
{
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
/* fill in the vital statistics */
|
||||
vgmstream->channels = channel_count;
|
||||
vgmstream->sample_rate = read_32bitBE(0x38,streamFile);
|
||||
vgmstream->num_samples=get_streamfile_size(streamFileSTR)/8/channel_count*14;
|
||||
vgmstream->coding_type = coding_NGC_DSP;
|
||||
|
||||
if(loop_flag)
|
||||
{
|
||||
vgmstream->loop_start_sample = 0;
|
||||
vgmstream->loop_end_sample = 0;
|
||||
}
|
||||
|
||||
if (channel_count == 1)
|
||||
{
|
||||
vgmstream->layout_type = layout_none;
|
||||
}
|
||||
else
|
||||
{
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
if (channel_count == 2 || channel_count == 4)
|
||||
{
|
||||
vgmstream->interleave_block_size=0x8000;
|
||||
}
|
||||
else
|
||||
{
|
||||
vgmstream->interleave_block_size=0x4000;
|
||||
}
|
||||
}
|
||||
|
||||
vgmstream->meta_type = meta_NGC_DSP_STH_STR;
|
||||
|
||||
/* open the file for reading */
|
||||
for (i=0;i<channel_count;i++)
|
||||
{
|
||||
vgmstream->ch[i].streamfile = streamFileSTR->open(streamFileSTR,filenameSTR,0x8000);
|
||||
if (!vgmstream->ch[i].streamfile) goto fail;
|
||||
vgmstream->ch[i].channel_start_offset=vgmstream->ch[i].offset=i*vgmstream->interleave_block_size;
|
||||
}
|
||||
|
||||
// COEFFS
|
||||
for (j=0;j<vgmstream->channels;j++)
|
||||
{
|
||||
for (i=0;i<16;i++)
|
||||
{
|
||||
vgmstream->ch[j].adpcm_coef[i] = read_16bitBE(coef_table[j]+i*2,streamFile);
|
||||
}
|
||||
}
|
||||
|
||||
close_streamfile(streamFileSTR); streamFileSTR=NULL;
|
||||
return vgmstream;
|
||||
|
||||
/* clean up anything we may have opened */
|
||||
fail:
|
||||
if (streamFileSTR) close_streamfile(streamFileSTR);
|
||||
if (vgmstream) close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
|
@ -0,0 +1,308 @@
|
|||
#include "meta.h"
|
||||
#include "../layout/layout.h"
|
||||
#include "../coding/coding.h"
|
||||
#include "../util.h"
|
||||
|
||||
// Platform constants
|
||||
#define EA_PC 0x00
|
||||
#define EA_PSX 0x01
|
||||
#define EA_PS2 0x05
|
||||
#define EA_GC 0x06
|
||||
#define EA_XBOX 0x07
|
||||
#define EA_X360 0x09
|
||||
|
||||
// Compression Version
|
||||
#define EAXA_R1 0x01
|
||||
#define EAXA_R2 0x02
|
||||
#define EAXA_R3 0x03
|
||||
|
||||
// Compression Type
|
||||
#define EA_VAG 0x01
|
||||
#define EA_EAXA 0x0A
|
||||
#define EA_ADPCM 0x30
|
||||
#define EA_PCM_BE 0x07
|
||||
#define EA_PCM_LE 0x08
|
||||
#define EA_IMA 0x14
|
||||
|
||||
typedef struct {
|
||||
int32_t num_samples;
|
||||
int32_t sample_rate;
|
||||
uint8_t channels;
|
||||
uint8_t platform;
|
||||
int32_t interleave;
|
||||
uint8_t compression_type;
|
||||
uint8_t compression_version;
|
||||
} EA_STRUCT;
|
||||
|
||||
uint32_t readPatch(STREAMFILE* streamFile, off_t* offset) {
|
||||
|
||||
uint32_t result=0;
|
||||
uint8_t byteCount;
|
||||
|
||||
byteCount = read_8bit(*offset,streamFile);
|
||||
(*offset)++;
|
||||
|
||||
for(;byteCount>0;byteCount--) {
|
||||
result <<=8;
|
||||
result+=(uint8_t)read_8bit(*offset,streamFile);
|
||||
(*offset)++;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void Parse_Header(STREAMFILE* streamFile,EA_STRUCT* ea, off_t offset, int length) {
|
||||
|
||||
uint8_t byteRead;
|
||||
off_t begin_offset=offset;
|
||||
|
||||
// default value ...
|
||||
ea->channels=1;
|
||||
ea->compression_type=0;
|
||||
ea->compression_version=0x01;
|
||||
ea->platform=EA_GC;
|
||||
|
||||
if(read_32bitBE(offset, streamFile)==0x47535452) { // GSTR
|
||||
ea->compression_version=0x03;
|
||||
offset+=8;
|
||||
ea->platform=6;
|
||||
} else {
|
||||
if(read_16bitBE(offset,streamFile)!=0x5054) // PT
|
||||
offset+=4;
|
||||
|
||||
ea->platform=(uint8_t)read_16bitLE(offset+2,streamFile);
|
||||
offset+=4;
|
||||
}
|
||||
|
||||
do {
|
||||
byteRead = read_8bit(offset++,streamFile);
|
||||
|
||||
switch(byteRead) {
|
||||
case 0xFF:
|
||||
case 0xFE:
|
||||
case 0xFC:
|
||||
case 0xFD:
|
||||
break;
|
||||
#if 0
|
||||
// was added for My Sims Kingdom, apparently this is not the right
|
||||
// way to do it (see NFS Most Wanted and Underground 2)
|
||||
case 0x06: //
|
||||
if (readPatch(streamFile, &offset) == 0x65)
|
||||
ea->compression_type = EA_PCM_BE;
|
||||
break;
|
||||
#endif
|
||||
case 0x80: // compression version
|
||||
ea->compression_version = (uint8_t)readPatch(streamFile, &offset);
|
||||
break;
|
||||
case 0x82: // channels count
|
||||
ea->channels = (uint8_t)readPatch(streamFile, &offset);
|
||||
break;
|
||||
case 0x83: // compression type
|
||||
ea->compression_type = (uint8_t)readPatch(streamFile, &offset);
|
||||
if(ea->compression_type==0x07) ea->compression_type=0x30;
|
||||
break;
|
||||
case 0x84: // sample frequency
|
||||
ea->sample_rate = readPatch(streamFile,&offset);
|
||||
break;
|
||||
case 0x85: // samples count
|
||||
ea->num_samples = readPatch(streamFile, &offset);
|
||||
break;
|
||||
case 0x8A:
|
||||
offset+=4;
|
||||
if(ea->compression_type==0) ea->compression_type=EA_PCM_LE;
|
||||
break;
|
||||
case 0x86:
|
||||
case 0x87:
|
||||
case 0x8C:
|
||||
case 0x92:
|
||||
case 0x9C:
|
||||
case 0x9D: // unknown patch
|
||||
readPatch(streamFile, &offset);
|
||||
break;
|
||||
case 0x88: // interleave
|
||||
ea->interleave = readPatch(streamFile, &offset);
|
||||
break;
|
||||
case 0xA0: // compression type
|
||||
ea->compression_type = (uint8_t)readPatch(streamFile, &offset);
|
||||
break;
|
||||
}
|
||||
} while(offset-begin_offset<length);
|
||||
|
||||
if(ea->platform==EA_PSX)
|
||||
ea->compression_type=EA_VAG;
|
||||
if(ea->compression_type==0)
|
||||
ea->compression_type=EA_EAXA;
|
||||
}
|
||||
|
||||
VGMSTREAM * init_vgmstream_ea(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
EA_STRUCT ea;
|
||||
char filename[PATH_LIMIT];
|
||||
|
||||
int loop_flag=0;
|
||||
int channel_count;
|
||||
int header_length;
|
||||
off_t start_offset;
|
||||
int i;
|
||||
|
||||
memset(&ea,0,sizeof(EA_STRUCT));
|
||||
|
||||
/* check extension, case insensitive */
|
||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||
if (strcasecmp("strm",filename_extension(filename)) &&
|
||||
strcasecmp("xa",filename_extension(filename)) &&
|
||||
strcasecmp("sng",filename_extension(filename)) &&
|
||||
strcasecmp("asf",filename_extension(filename)) &&
|
||||
strcasecmp("str",filename_extension(filename)) &&
|
||||
strcasecmp("xsf",filename_extension(filename)) &&
|
||||
strcasecmp("eam",filename_extension(filename))) goto fail;
|
||||
|
||||
/* check Header */
|
||||
if (read_32bitBE(0x00,streamFile) != 0x5343486C) // SCHl
|
||||
goto fail;
|
||||
|
||||
header_length = read_32bitLE(0x04,streamFile);
|
||||
start_offset=8;
|
||||
|
||||
if(header_length>0x100) goto fail;
|
||||
|
||||
Parse_Header(streamFile,&ea,start_offset,header_length-8);
|
||||
|
||||
/* unknown loop value for the moment */
|
||||
loop_flag = 0;
|
||||
|
||||
channel_count=ea.channels;
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
/* fill in the vital statistics */
|
||||
vgmstream->channels = channel_count;
|
||||
vgmstream->ea_platform=ea.platform;
|
||||
|
||||
vgmstream->ea_compression_type=ea.compression_type;
|
||||
vgmstream->ea_compression_version=ea.compression_version;
|
||||
|
||||
// Set defaut sample rate if not define in the header
|
||||
if(ea.sample_rate!=0) {
|
||||
vgmstream->sample_rate = ea.sample_rate;
|
||||
} else {
|
||||
if(read_32bitBE(0x08,streamFile)==0x47535452) { // GSTR
|
||||
vgmstream->sample_rate=44100;
|
||||
} else {
|
||||
switch(vgmstream->ea_platform) {
|
||||
case EA_XBOX:
|
||||
vgmstream->sample_rate=24000;
|
||||
break;
|
||||
case EA_X360:
|
||||
vgmstream->sample_rate=44100;
|
||||
break;
|
||||
default:
|
||||
vgmstream->sample_rate=22050;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set default compression scheme if not define in the header
|
||||
switch(vgmstream->ea_platform) {
|
||||
case EA_X360:
|
||||
vgmstream->ea_compression_version=0x03;
|
||||
break;
|
||||
}
|
||||
|
||||
vgmstream->num_samples=ea.num_samples;
|
||||
|
||||
switch(vgmstream->ea_compression_type) {
|
||||
case EA_EAXA:
|
||||
if(vgmstream->ea_compression_version==0x03)
|
||||
vgmstream->meta_type=meta_EAXA_R3;
|
||||
else {
|
||||
// seems there's no EAXA R2 on PC
|
||||
if(ea.platform==EA_PC) {
|
||||
vgmstream->ea_compression_version=0x03;
|
||||
vgmstream->meta_type=meta_EAXA_R3;
|
||||
} else
|
||||
vgmstream->meta_type=meta_EAXA_R2;
|
||||
}
|
||||
|
||||
vgmstream->coding_type=coding_EAXA;
|
||||
vgmstream->layout_type=layout_ea_blocked;
|
||||
if((vgmstream->ea_platform==EA_GC) || (vgmstream->ea_platform==EA_X360))
|
||||
vgmstream->ea_big_endian=1;
|
||||
|
||||
break;
|
||||
case EA_VAG:
|
||||
vgmstream->meta_type=meta_EAXA_PSX;
|
||||
vgmstream->coding_type=coding_PSX;
|
||||
vgmstream->layout_type=layout_ea_blocked;
|
||||
break;
|
||||
case EA_PCM_LE:
|
||||
vgmstream->meta_type=meta_EA_PCM;
|
||||
vgmstream->coding_type=coding_PCM16LE_int;
|
||||
vgmstream->layout_type=layout_ea_blocked;
|
||||
break;
|
||||
case EA_PCM_BE:
|
||||
vgmstream->meta_type=meta_EA_PCM;
|
||||
vgmstream->coding_type=coding_PCM16BE;
|
||||
vgmstream->layout_type=layout_ea_blocked;
|
||||
break;
|
||||
case EA_ADPCM:
|
||||
vgmstream->meta_type=meta_EA_ADPCM;
|
||||
vgmstream->coding_type=coding_EA_ADPCM;
|
||||
vgmstream->layout_type=layout_ea_blocked;
|
||||
break;
|
||||
case EA_IMA:
|
||||
vgmstream->meta_type=meta_EA_IMA;
|
||||
vgmstream->coding_type=coding_XBOX;
|
||||
vgmstream->layout_type=layout_ea_blocked;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
/* open the file for reading by each channel */
|
||||
{
|
||||
for (i=0;i<channel_count;i++) {
|
||||
vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,0x8000);
|
||||
|
||||
if (!vgmstream->ch[i].streamfile) goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Special function for .EAM files ...
|
||||
if(!strcasecmp("eam",filename_extension(filename))) {
|
||||
|
||||
size_t file_length=get_streamfile_size(streamFile);
|
||||
size_t block_length;
|
||||
|
||||
vgmstream->next_block_offset=start_offset+header_length;
|
||||
vgmstream->num_samples=0;
|
||||
|
||||
// to initialize the block length
|
||||
ea_block_update(start_offset+header_length,vgmstream);
|
||||
block_length=vgmstream->next_block_offset-start_offset+header_length;
|
||||
|
||||
do {
|
||||
ea_block_update(vgmstream->next_block_offset,vgmstream);
|
||||
if(vgmstream->coding_type==coding_PSX)
|
||||
vgmstream->num_samples+=(int32_t)vgmstream->current_block_size/16*28;
|
||||
else if (vgmstream->coding_type==coding_EA_ADPCM)
|
||||
vgmstream->num_samples+=(int32_t)vgmstream->current_block_size;
|
||||
else if (vgmstream->coding_type==coding_PCM16LE_int)
|
||||
vgmstream->num_samples+=(int32_t)vgmstream->current_block_size/vgmstream->channels;
|
||||
else
|
||||
vgmstream->num_samples+=(int32_t)vgmstream->current_block_size*28;
|
||||
} while(vgmstream->next_block_offset<(off_t)(file_length-block_length));
|
||||
}
|
||||
|
||||
ea_block_update(start_offset+header_length,vgmstream);
|
||||
|
||||
init_get_high_nibble(vgmstream);
|
||||
|
||||
return vgmstream;
|
||||
|
||||
/* clean up anything we may have opened */
|
||||
fail:
|
||||
if (vgmstream) close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
|
@ -0,0 +1,162 @@
|
|||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
#include "../layout/layout.h"
|
||||
#include "../util.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char szID[4];
|
||||
int dwSampleRate;
|
||||
char bBits;
|
||||
char bChannels;
|
||||
char bCompression;
|
||||
char bType;
|
||||
int dwNumSamples;
|
||||
int dwLoopStart;
|
||||
int dwLoopLength;
|
||||
int dwDataStart;
|
||||
int dwUnknown;
|
||||
} EACSHeader;
|
||||
|
||||
VGMSTREAM * init_vgmstream_eacs(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
char filename[PATH_LIMIT];
|
||||
int channel_count;
|
||||
int loop_flag=0;
|
||||
char little_endian=0;
|
||||
off_t start_offset;
|
||||
EACSHeader *ea_header = NULL;
|
||||
int32_t samples_count=0;
|
||||
int i;
|
||||
|
||||
/* check extension, case insensitive */
|
||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||
if (strcasecmp("cnk",filename_extension(filename)) &&
|
||||
strcasecmp("as4",filename_extension(filename)) &&
|
||||
strcasecmp("asf",filename_extension(filename))) goto fail;
|
||||
|
||||
ea_header=(EACSHeader *)malloc(sizeof(EACSHeader));
|
||||
|
||||
/* check header */
|
||||
if ((uint32_t)read_32bitBE(0,streamFile)!=0x31534E68) /* "1SNh" */
|
||||
goto fail;
|
||||
|
||||
/* check if we are little or big endian */
|
||||
if ((uint32_t)read_32bitBE(4,streamFile)<0x40)
|
||||
little_endian=1;
|
||||
|
||||
/* check type details */
|
||||
start_offset = read_32bitLE(0x04,streamFile);
|
||||
|
||||
if((uint32_t)read_32bitBE(0x08,streamFile)==0x45414353) { /* EACS */
|
||||
read_streamfile((uint8_t*)ea_header,0x08,sizeof(EACSHeader),streamFile);
|
||||
loop_flag = 0; //(ea_header->dwLoopStart!=0);
|
||||
channel_count = (ea_header->bChannels);
|
||||
/* build the VGMSTREAM */
|
||||
|
||||
vgmstream = allocate_vgmstream(channel_count,0);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
/* fill in the vital statistics */
|
||||
init_get_high_nibble(vgmstream);
|
||||
|
||||
vgmstream->sample_rate = ea_header->dwSampleRate;
|
||||
|
||||
if(ea_header->bCompression==0) {
|
||||
vgmstream->coding_type = coding_PCM16LE_int;
|
||||
if(ea_header->bBits==1)
|
||||
vgmstream->coding_type = coding_PCM8_int;
|
||||
}
|
||||
else
|
||||
vgmstream->coding_type = coding_EACS_IMA;
|
||||
|
||||
vgmstream->layout_type = layout_eacs_blocked;
|
||||
vgmstream->meta_type = meta_EACS_PC;
|
||||
|
||||
if(little_endian)
|
||||
vgmstream->meta_type = meta_EACS_SAT;
|
||||
|
||||
} else {
|
||||
channel_count=read_32bitLE(0x20,streamFile);
|
||||
|
||||
vgmstream = allocate_vgmstream(channel_count,0);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->sample_rate = read_32bitLE(0x08,streamFile);
|
||||
vgmstream->coding_type = coding_PSX;
|
||||
vgmstream->layout_type=layout_eacs_blocked;
|
||||
vgmstream->meta_type=meta_EACS_PSX;
|
||||
}
|
||||
|
||||
vgmstream->ea_platform=little_endian;
|
||||
|
||||
/* open the file for reading by each channel */
|
||||
{
|
||||
for (i=0;i<channel_count;i++) {
|
||||
vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,0x8000);
|
||||
if (!vgmstream->ch[i].streamfile) goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
// calc the samples length ...
|
||||
if(little_endian)
|
||||
vgmstream->next_block_offset=read_32bitBE(0x04,streamFile);
|
||||
else
|
||||
vgmstream->next_block_offset=read_32bitLE(0x04,streamFile);
|
||||
|
||||
if(vgmstream->next_block_offset>0x30) {
|
||||
vgmstream->current_block_size=vgmstream->next_block_offset-sizeof(EACSHeader);
|
||||
samples_count=(int32_t)vgmstream->current_block_size/get_vgmstream_frame_size(vgmstream)*get_vgmstream_samples_per_frame(vgmstream);
|
||||
samples_count/=vgmstream->channels;
|
||||
}
|
||||
|
||||
do {
|
||||
if(read_32bitBE(vgmstream->next_block_offset,vgmstream->ch[0].streamfile)==0x31534E6C) {
|
||||
ea_header->dwLoopStart=read_32bitLE(vgmstream->next_block_offset+0x08,vgmstream->ch[0].streamfile);
|
||||
vgmstream->next_block_offset+=0x0C;
|
||||
}
|
||||
|
||||
if(read_32bitBE(vgmstream->next_block_offset,vgmstream->ch[0].streamfile)==0x31534E65)
|
||||
break;
|
||||
|
||||
eacs_block_update(vgmstream->next_block_offset,vgmstream);
|
||||
samples_count+=vgmstream->current_block_size/get_vgmstream_frame_size(vgmstream)*get_vgmstream_samples_per_frame(vgmstream);
|
||||
} while(vgmstream->next_block_offset<get_streamfile_size(streamFile)-8);
|
||||
|
||||
// Reset values ...
|
||||
// setting up the first header by calling the eacs_block_update sub
|
||||
if(little_endian)
|
||||
vgmstream->next_block_offset=read_32bitBE(0x04,streamFile);
|
||||
else
|
||||
vgmstream->next_block_offset=read_32bitLE(0x04,streamFile);
|
||||
|
||||
vgmstream->current_block_size=vgmstream->next_block_offset-sizeof(EACSHeader);
|
||||
|
||||
if(vgmstream->coding_type!=coding_PSX)
|
||||
vgmstream->current_block_size-=8;
|
||||
|
||||
if(vgmstream->coding_type==coding_PSX)
|
||||
eacs_block_update(0x2C,vgmstream);
|
||||
else
|
||||
eacs_block_update(0x28,vgmstream);
|
||||
|
||||
// re-allocate the sample count
|
||||
vgmstream->num_samples=samples_count;
|
||||
|
||||
if(loop_flag) {
|
||||
vgmstream->loop_start_sample = ea_header->dwLoopStart;
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
}
|
||||
|
||||
if(ea_header)
|
||||
free(ea_header);
|
||||
|
||||
return vgmstream;
|
||||
|
||||
/* clean up anything we may have opened */
|
||||
fail:
|
||||
if(ea_header)
|
||||
free(ea_header);
|
||||
if (vgmstream) close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue