mirror of
https://github.com/vgmstream/vgmstream.git
synced 2025-01-18 15:54:05 +01:00
acm that at least builds
git-svn-id: https://vgmstream.svn.sourceforge.net/svnroot/vgmstream@348 51a99a44-fe44-0410-b1ba-c3e57ba2b86b
This commit is contained in:
parent
3e8d8edb40
commit
a14cd4082d
19
COPYING.libacm
Normal file
19
COPYING.libacm
Normal file
@ -0,0 +1,19 @@
|
||||
|
||||
Starting from version 0.9.2, the libacm core code is licensed under
|
||||
minimal BSD/ISC license. (Core code = everything except plugins.)
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2004-2008, Marko Kreen
|
||||
|
||||
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.
|
@ -11,7 +11,8 @@ CODING_OBJS=coding/adx_decoder.o \
|
||||
coding/ogg_vorbis_decoder.o \
|
||||
coding/sdx2_decoder.o \
|
||||
coding/ws_decoder.o \
|
||||
coding/mpeg_decoder.o
|
||||
coding/mpeg_decoder.o \
|
||||
coding/acm_decoder.o
|
||||
|
||||
LAYOUT_OBJS=layout/ast_blocked.o \
|
||||
layout/blocked.o \
|
||||
@ -92,7 +93,8 @@ META_OBJS=meta/adx_header.o \
|
||||
meta/sat_dvi.o \
|
||||
meta/ps2_bg00.o \
|
||||
meta/dc_kcey.o \
|
||||
meta/ps2_rstm.o
|
||||
meta/ps2_rstm.o \
|
||||
meta/acm.o
|
||||
|
||||
OBJECTS=vgmstream.o streamfile.o util.o $(CODING_OBJS) $(LAYOUT_OBJS) $(META_OBJS)
|
||||
|
||||
|
@ -4,6 +4,6 @@ AM_CFLAGS = -Wall @CFLAGS@ -I$(top_builddir) -I$(top_srcdir)
|
||||
AM_MAKEFLAGS=-f Makefile.unix
|
||||
|
||||
libcoding_la_LDFLAGS =
|
||||
libcoding_la_SOURCES = adx_decoder.c eaxa_decoder.c g721_decoder.c ima_decoder.c ngc_afc_decoder.c ngc_dsp_decoder.c ngc_dtk_decoder.c pcm_decoder.c psx_decoder.c xa_decoder.c ogg_vorbis_decoder.c sdx2_decoder.c ws_decoder.c mpeg_decoder.c
|
||||
libcoding_la_SOURCES = adx_decoder.c eaxa_decoder.c g721_decoder.c ima_decoder.c ngc_afc_decoder.c ngc_dsp_decoder.c ngc_dtk_decoder.c pcm_decoder.c psx_decoder.c xa_decoder.c ogg_vorbis_decoder.c sdx2_decoder.c ws_decoder.c mpeg_decoder.c acm_decoder.c
|
||||
|
||||
EXTRA_DIST = coding.h g72x_state.h
|
||||
|
782
src/coding/acm_decoder.c
Normal file
782
src/coding/acm_decoder.c
Normal file
@ -0,0 +1,782 @@
|
||||
/*
|
||||
* 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 "../vgmstream.h"
|
||||
#include "../streamtypes.h"
|
||||
#include "../streamfile.h"
|
||||
#include "acm_decoder.h"
|
||||
|
||||
#define ACM_BUFLEN (64*1024)
|
||||
|
||||
typedef int (*filler_t)(ACMStream *acm, int ind, int n_col);
|
||||
|
||||
/**************************************
|
||||
* Stream processing
|
||||
**************************************/
|
||||
|
||||
/* NB: bits <= 31! Thus less checks in code. */
|
||||
|
||||
static int get_bits_reload(ACMStream *acm, int 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:
|
||||
return ACM_ERR_UNEXPECTED_EOF;
|
||||
case 1:
|
||||
b_data = read_8bit(acm->buf_start_ofs,acm->streamfile);
|
||||
b_avail = 8;
|
||||
acm->buf_start_ofs += 1;
|
||||
break;
|
||||
case 2:
|
||||
b_data = read_16bitLE(acm->buf_start_ofs,acm->streamfile);
|
||||
b_avail = 16;
|
||||
acm->buf_start_ofs += 2;
|
||||
break;
|
||||
case 3:
|
||||
b_data = read_8bit(acm->buf_start_ofs,acm->streamfile);
|
||||
b_data |= (int32_t)read_16bitLE(acm->buf_start_ofs+1,acm->streamfile)<<8;
|
||||
b_avail = 24;
|
||||
acm->buf_start_ofs += 3;
|
||||
case 4:
|
||||
default:
|
||||
/* shouldn't happen */
|
||||
if (acm->data_len - acm->buf_start_ofs < 0)
|
||||
return ACM_ERR_UNEXPECTED_EOF;
|
||||
|
||||
b_data = read_32bitLE(acm->buf_start_ofs,acm->streamfile);
|
||||
b_avail = 32;
|
||||
acm->buf_start_ofs += 4;
|
||||
}
|
||||
|
||||
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(res, acm, bits) do { \
|
||||
if (acm->bit_avail >= bits) { \
|
||||
res = acm->bit_data & ((1 << bits) - 1); \
|
||||
acm->bit_data >>= bits; \
|
||||
acm->bit_avail -= bits; \
|
||||
} else \
|
||||
res = get_bits_reload(acm, bits); \
|
||||
} while (0)
|
||||
|
||||
#define GET_BITS(res, acm, bits) do { \
|
||||
GET_BITS_NOERR(res, acm, bits); \
|
||||
if (res < 0) \
|
||||
return res; \
|
||||
} while (0)
|
||||
|
||||
#define GET_BITS_ERR_OUT(res, acm, bits) do { \
|
||||
GET_BITS_NOERR(res, acm, bits); \
|
||||
if (res < 0) \
|
||||
goto err_out; \
|
||||
} 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()
|
||||
{
|
||||
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 { \
|
||||
int pos = (r << acm->info.acm_level) + c; \
|
||||
acm->block[pos] = acm->midbuf[idx]; \
|
||||
} while (0)
|
||||
|
||||
/************ Fillers **********/
|
||||
|
||||
static int f_zero(ACMStream *acm, int ind, int col)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < acm->info.acm_rows; i++)
|
||||
set_pos(acm, i, col, 0);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int f_bad(ACMStream *acm, int ind, int col)
|
||||
{
|
||||
/* corrupt block? */
|
||||
return ACM_ERR_CORRUPT;
|
||||
}
|
||||
|
||||
static int f_linear(ACMStream *acm, int ind, int col)
|
||||
{
|
||||
int i, b;
|
||||
int 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, int ind, int col)
|
||||
{
|
||||
int 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, int ind, int col)
|
||||
{
|
||||
int 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, int ind, int col)
|
||||
{
|
||||
int 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, int ind, int col)
|
||||
{
|
||||
int 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, int ind, int col)
|
||||
{
|
||||
int 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, int ind, int col)
|
||||
{
|
||||
int 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, int ind, int col)
|
||||
{
|
||||
int 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, int ind, int col)
|
||||
{
|
||||
int 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, int ind, int col)
|
||||
{
|
||||
int i, b, 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, int ind, int col)
|
||||
{
|
||||
int i, b, 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, int ind, int col)
|
||||
{
|
||||
int i, b, 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 filler_t filler_list[] = {
|
||||
f_zero, f_bad, f_bad, f_linear,
|
||||
f_linear, f_linear, f_linear, f_linear,
|
||||
f_linear, f_linear, f_linear, f_linear,
|
||||
f_linear, f_linear, f_linear, f_linear,
|
||||
f_linear, f_k13, f_k12, f_t15,
|
||||
f_k24, f_k23, f_t27, f_k35,
|
||||
f_k34, f_bad, f_k45, f_k44,
|
||||
f_bad, f_t37, f_bad, f_bad
|
||||
};
|
||||
|
||||
static int fill_block(ACMStream *acm)
|
||||
{
|
||||
int i, err, ind;
|
||||
for (i = 0; i < acm->info.acm_cols; i++) {
|
||||
/* here eof => acm2wav */
|
||||
GET_BITS_NOERR(ind, acm, 5);
|
||||
if (ind < 0)
|
||||
return -2; /* expected eof? */
|
||||
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, int sub_len, int sub_count)
|
||||
{
|
||||
int i, j, *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)
|
||||
{
|
||||
int sub_count, sub_len, todo_count, i;
|
||||
int *wrap_p, *block_p, *p;
|
||||
int step_subcount;
|
||||
|
||||
/* juggle only if subblock_len > 1 */
|
||||
if (acm->info.acm_level == 0)
|
||||
return;
|
||||
|
||||
/* 2048 / subblock_len */
|
||||
step_subcount = (2048 >> acm->info.acm_level) - 2;
|
||||
if (step_subcount < 1)
|
||||
step_subcount = 1;
|
||||
|
||||
/* 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 (todo_count > 0) {
|
||||
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;
|
||||
}
|
||||
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(pwr, acm, 4); /* to_check? -> ret val */
|
||||
GET_BITS(val, acm, 16);
|
||||
count = 1 << pwr;
|
||||
|
||||
/* generate tables */
|
||||
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 char *out_s16le(int *src, char *dst, int n, int shift)
|
||||
{
|
||||
while (n--) {
|
||||
int val = *src++ >> shift;
|
||||
*dst++ = val & 0xFF;
|
||||
*dst++ = (val >> 8) & 0xFF;
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
static char *out_s16be(int *src, char *dst, int n, int shift)
|
||||
{
|
||||
while (n--) {
|
||||
int val = *src++ >> shift;
|
||||
*dst++ = (val >> 8) & 0xFF;
|
||||
*dst++ = val & 0xFF;
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
static char *out_u16le(int *src, char *dst, int n, int shift)
|
||||
{
|
||||
while (n--) {
|
||||
int val = (*src++ >> shift) + 0x8000;
|
||||
*dst++ = val & 0xFF;
|
||||
*dst++ = (val >> 8) & 0xFF;
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
static char *out_u16be(int *src, char *dst, int n, int shift)
|
||||
{
|
||||
while (n--) {
|
||||
int val = (*src++ >> shift) + 0x8000;
|
||||
*dst++ = (val >> 8) & 0xFF;
|
||||
*dst++ = val & 0xFF;
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
static int output_values(int *src, char *dst, int n,
|
||||
int acm_level, int bigendianp, int wordlen, int sgned)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
/***********************************************
|
||||
* Public functions
|
||||
***********************************************/
|
||||
|
||||
int acm_open_decoder(ACMStream **res, STREAMFILE *facilitator_file,
|
||||
const char *const filename)
|
||||
{
|
||||
int err = ACM_ERR_OTHER, tmp;
|
||||
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 */
|
||||
err = ACM_ERR_NOT_ACM;
|
||||
GET_BITS_ERR_OUT(acm->info.acm_id, acm, 24);
|
||||
if (acm->info.acm_id != ACM_ID)
|
||||
goto err_out;
|
||||
GET_BITS_ERR_OUT(acm->info.acm_version, acm, 8);
|
||||
if (acm->info.acm_version != 1)
|
||||
goto err_out;
|
||||
GET_BITS_ERR_OUT(acm->total_values, acm, 16);
|
||||
GET_BITS_ERR_OUT(tmp, acm, 16);
|
||||
acm->total_values += tmp << 16;
|
||||
if (acm->total_values == 0)
|
||||
goto err_out;
|
||||
GET_BITS_ERR_OUT(acm->info.channels, acm, 16);
|
||||
if (acm->info.channels < 1)
|
||||
goto err_out;
|
||||
GET_BITS_ERR_OUT(acm->info.rate, acm, 16);
|
||||
|
||||
GET_BITS_ERR_OUT(acm->info.acm_level, acm, 4);
|
||||
GET_BITS_ERR_OUT(acm->info.acm_rows, acm, 12);
|
||||
acm->info.acm_cols = 1 << acm->info.acm_level;
|
||||
|
||||
/* calculate blocks */
|
||||
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:
|
||||
/* dont let it close here */
|
||||
acm_close(acm);
|
||||
return err;
|
||||
}
|
||||
|
||||
int acm_read(ACMStream *acm, char *dst, int 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 == -2)
|
||||
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 decode_acm(mus_acm_codec_data * data, sample * outbuf,
|
||||
int32_t samples_to_do, int channelspacing) {
|
||||
if (data->file_count == 1 && data->current_file == 0)
|
||||
{
|
||||
acm_read(data->files[0],(char*)outbuf,samples_to_do*sizeof(sample)*
|
||||
channelspacing,
|
||||
0,2,1);
|
||||
}
|
||||
}
|
||||
|
||||
void acm_close(ACMStream *acm)
|
||||
{
|
||||
if (acm == NULL)
|
||||
return;
|
||||
if (acm->streamfile) {
|
||||
close_streamfile(acm->streamfile);
|
||||
}
|
||||
if (acm->block)
|
||||
free(acm->block);
|
||||
if (acm->wrapbuf)
|
||||
free(acm->wrapbuf);
|
||||
if (acm->ampbuf)
|
||||
free(acm->ampbuf);
|
||||
free(acm);
|
||||
}
|
||||
|
100
src/coding/acm_decoder.h
Normal file
100
src/coding/acm_decoder.h
Normal file
@ -0,0 +1,100 @@
|
||||
/*
|
||||
* libacm - Interplay ACM audio decoder.
|
||||
*
|
||||
* Copyright (c) 2004-2008, Marko Kreen
|
||||
*
|
||||
* 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
|
||||
|
||||
#include "../streamfile.h"
|
||||
|
||||
#define LIBACM_VERSION "0.9.2"
|
||||
|
||||
#define ACM_ID 0x032897
|
||||
#define ACM_WORD 2
|
||||
|
||||
#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 {
|
||||
int channels;
|
||||
int rate;
|
||||
int acm_id;
|
||||
int acm_version;
|
||||
int acm_level;
|
||||
int acm_cols; /* 1 << acm_level */
|
||||
int acm_rows;
|
||||
} ACMInfo;
|
||||
|
||||
struct ACMStream {
|
||||
ACMInfo info;
|
||||
int total_values;
|
||||
|
||||
/* acm data stream */
|
||||
STREAMFILE *streamfile;
|
||||
int data_len;
|
||||
|
||||
/* acm stream buffer */
|
||||
int bit_avail;
|
||||
unsigned bit_data;
|
||||
unsigned buf_start_ofs;
|
||||
|
||||
/* block lengths (in samples) */
|
||||
int block_len;
|
||||
int wrapbuf_len;
|
||||
/* buffers */
|
||||
int *block;
|
||||
int *wrapbuf;
|
||||
int *ampbuf;
|
||||
int *midbuf; /* pointer into ampbuf */
|
||||
/* result */
|
||||
int block_ready;
|
||||
int stream_pos; /* in words. absolute */
|
||||
int 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, char *buf, int nbytes,
|
||||
int bigendianp, int wordlen, int sgned);
|
||||
void acm_close(ACMStream *acm);
|
||||
|
||||
/* util.c */
|
||||
const ACMInfo *acm_info(ACMStream *acm);
|
||||
int acm_seekable(ACMStream *acm);
|
||||
int acm_bitrate(ACMStream *acm);
|
||||
int acm_raw_total(ACMStream *acm);
|
||||
int acm_raw_tell(ACMStream *acm);
|
||||
int acm_pcm_total(ACMStream *acm);
|
||||
int acm_pcm_tell(ACMStream *acm);
|
||||
int acm_time_total(ACMStream *acm);
|
||||
int acm_time_tell(ACMStream *acm);
|
||||
int acm_read_loop(ACMStream *acm, char *dst, int len,
|
||||
int bigendianp, int wordlen, int sgned);
|
||||
int acm_seek_pcm(ACMStream *acm, int pcm_pos);
|
||||
int acm_seek_time(ACMStream *acm, int pos_ms);
|
||||
const char *acm_strerror(int err);
|
||||
|
||||
#endif
|
||||
|
@ -58,4 +58,7 @@ void decode_mpeg(VGMSTREAMCHANNEL * stream,
|
||||
sample * outbuf, int32_t samples_to_do, int channels);
|
||||
#endif
|
||||
|
||||
void decode_acm(mus_acm_codec_data * data, sample * outbuf,
|
||||
int32_t samples_to_do, int channelspacing);
|
||||
|
||||
#endif
|
||||
|
@ -71,5 +71,6 @@ 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
|
||||
|
||||
EXTRA_DIST = meta.h
|
||||
|
65
src/meta/acm.c
Normal file
65
src/meta/acm.c
Normal file
@ -0,0 +1,65 @@
|
||||
#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[260];
|
||||
|
||||
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;
|
||||
|
||||
vgmstream->codec_data = data;
|
||||
|
||||
return vgmstream;
|
||||
|
||||
/* clean up anything we may have opened */
|
||||
fail:
|
||||
if (vgmstream) close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
@ -155,4 +155,6 @@ VGMSTREAM * init_vgmstream_kcey(STREAMFILE * streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_ps2_rstm(STREAMFILE * streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_acm(STREAMFILE * streamFile);
|
||||
|
||||
#endif
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "meta.h"
|
||||
#include "../util.h"
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#ifdef WIN32
|
||||
#define DIRSEP '\\'
|
||||
|
@ -93,6 +93,7 @@ VGMSTREAM * (*init_vgmstream_fcns[])(STREAMFILE *streamFile) = {
|
||||
init_vgmstream_dvi,
|
||||
init_vgmstream_kcey,
|
||||
init_vgmstream_ps2_rstm,
|
||||
init_vgmstream_acm,
|
||||
};
|
||||
|
||||
#define INIT_VGMSTREAM_FCNS (sizeof(init_vgmstream_fcns)/sizeof(init_vgmstream_fcns[0]))
|
||||
@ -185,6 +186,8 @@ void reset_vgmstream(VGMSTREAM * vgmstream) {
|
||||
data->buffer_full = data->buffer_used = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* TODO: reset ACM */
|
||||
}
|
||||
|
||||
/* simply allocate memory for the VGMSTREAM and its channels */
|
||||
@ -302,6 +305,28 @@ void close_vgmstream(VGMSTREAM * vgmstream) {
|
||||
}
|
||||
#endif
|
||||
|
||||
if (vgmstream->coding_type==coding_ACM) {
|
||||
mus_acm_codec_data *data = vgmstream->codec_data;
|
||||
|
||||
if (data) {
|
||||
if (data->files) {
|
||||
int i;
|
||||
for (i=0; i<data->file_count; i++) {
|
||||
/* shouldn't be duplicates */
|
||||
if (data->files[i]) {
|
||||
acm_close(data->files[i]);
|
||||
data->files[i] = NULL;
|
||||
}
|
||||
}
|
||||
free(data->files);
|
||||
data->files = NULL;
|
||||
}
|
||||
|
||||
free(vgmstream->codec_data);
|
||||
vgmstream->codec_data = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
free(vgmstream);
|
||||
}
|
||||
|
||||
@ -324,6 +349,7 @@ void render_vgmstream(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstre
|
||||
case layout_fake_mpeg:
|
||||
case layout_mpeg:
|
||||
#endif
|
||||
case layout_acm:
|
||||
case layout_dtk_interleave:
|
||||
case layout_none:
|
||||
render_vgmstream_nolayout(buffer,sample_count,vgmstream);
|
||||
@ -373,6 +399,7 @@ int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream) {
|
||||
#endif
|
||||
case coding_SDX2:
|
||||
case coding_SDX2_int:
|
||||
case coding_ACM:
|
||||
return 1;
|
||||
case coding_NDS_IMA:
|
||||
return (vgmstream->interleave_block_size-4)*2;
|
||||
@ -681,6 +708,12 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to
|
||||
buffer+samples_written*vgmstream->channels,samples_to_do,
|
||||
vgmstream->channels);
|
||||
break;
|
||||
case coding_ACM:
|
||||
decode_acm(
|
||||
vgmstream->codec_data,
|
||||
buffer+samples_written*vgmstream->channels,samples_to_do,
|
||||
vgmstream->channels);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@ -943,6 +976,9 @@ void describe_vgmstream(VGMSTREAM * vgmstream, char * desc, int length) {
|
||||
snprintf(temp,TEMPSIZE,"MPEG-2.5 Layer III Audio (MP3)");
|
||||
break;
|
||||
#endif
|
||||
case coding_ACM:
|
||||
snprintf(temp,TEMPSIZE,"InterPlay ACM");
|
||||
break;
|
||||
default:
|
||||
snprintf(temp,TEMPSIZE,"CANNOT DECODE");
|
||||
}
|
||||
@ -1007,7 +1043,9 @@ void describe_vgmstream(VGMSTREAM * vgmstream, char * desc, int length) {
|
||||
snprintf(temp,TEMPSIZE,"MPEG Audio stream");
|
||||
break;
|
||||
#endif
|
||||
|
||||
case layout_acm:
|
||||
snprintf(temp,TEMPSIZE,"However ACM Does That");
|
||||
break;
|
||||
default:
|
||||
snprintf(temp,TEMPSIZE,"INCONCEIVABLE");
|
||||
}
|
||||
@ -1318,6 +1356,9 @@ void describe_vgmstream(VGMSTREAM * vgmstream, char * desc, int length) {
|
||||
case meta_PS2_RSTM:
|
||||
snprintf(temp,TEMPSIZE,"Rockstar Games RSTM Header");
|
||||
break;
|
||||
case meta_ACM:
|
||||
snprintf(temp,TEMPSIZE,"InterPlay ACM Header");
|
||||
break;
|
||||
default:
|
||||
snprintf(temp,TEMPSIZE,"THEY SHOULD HAVE SENT A POET");
|
||||
}
|
||||
|
@ -20,6 +20,7 @@
|
||||
#ifdef VGM_USE_MPEG
|
||||
#include <mpg123.h>
|
||||
#endif
|
||||
#include "coding/acm_decoder.h"
|
||||
|
||||
/* The encoding type specifies the format the sound data itself takes */
|
||||
typedef enum {
|
||||
@ -73,6 +74,8 @@ typedef enum {
|
||||
coding_MPEG25_L2,
|
||||
coding_MPEG25_L3,
|
||||
#endif
|
||||
|
||||
coding_ACM, /* InterPlay ACM */
|
||||
} coding_t;
|
||||
|
||||
/* The layout type specifies how the sound data is laid out in the file */
|
||||
@ -107,6 +110,7 @@ typedef enum {
|
||||
layout_fake_mpeg, /* MPEG audio stream with bad frame headers (AHX) */
|
||||
layout_mpeg, /* proper MPEG audio stream */
|
||||
#endif
|
||||
layout_acm, /* dummy, let libacm handle layout */
|
||||
} layout_t;
|
||||
|
||||
/* The meta type specifies how we know what we know about the file. We may know because of a header we read, some of it may have been guessed from filenames, etc. */
|
||||
@ -225,6 +229,8 @@ typedef enum {
|
||||
meta_NWA_GAMEEXEINI, /* NWA w/ Gameexe.ini for looping */
|
||||
meta_DVI, /* DVI Interleaved */
|
||||
meta_KCEY, /* KCEYCOMP */
|
||||
meta_ACM, /* InterPlay ACM header */
|
||||
meta_MUS_ACM, /* MUS playlist of InterPlay ACM files */
|
||||
} meta_t;
|
||||
|
||||
typedef struct {
|
||||
@ -349,6 +355,14 @@ typedef struct {
|
||||
} mpeg_codec_data;
|
||||
#endif
|
||||
|
||||
/* with one file this is also used for just
|
||||
ACM */
|
||||
typedef struct {
|
||||
int file_count;
|
||||
int current_file;
|
||||
ACMStream **files;
|
||||
} mus_acm_codec_data;
|
||||
|
||||
/* do format detection, return pointer to a usable VGMSTREAM, or NULL on failure */
|
||||
VGMSTREAM * init_vgmstream(const char * const filename);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user