Merge remote-tracking branch 'irixxxx/master' into master

This commit is contained in:
kub committed 2025-10-24 00:16:12 +02:00
commit 5b8cdea5cb
82 files changed
+15695 -955

No files matched your search

+4
View File
@@ -22,6 +22,10 @@ jobs:
- uses: actions/checkout@v4
with:
submodules: true
- name: Install dependencies
run: |
sudo apt-get update -qq
sudo apt-get install -y libvorbis-dev
- name: make
run: LDFLAGS=-Wl,--no-undefined make -j$(getconf _NPROCESSORS_ONLN) -f Makefile.libretro
- name: artifacts
+2
View File
@@ -11,6 +11,8 @@
*.a
tags
cscope.out
compile_commands.json
.gdb_history
config.mak
config.log
cpu/musashi/m68kmake
+17 -1
View File
@@ -330,6 +330,21 @@ OBJS += platform/common/mp3_drmp3.o
endif
endif
OBJS += platform/common/ogg.o
ifeq "$(PLATFORM_TREMOR)" "1"
TREMOR = platform/common/tremor
TREMOR_OBJS += $(TREMOR)/block.o $(TREMOR)/codebook.o $(TREMOR)/floor0.o $(TREMOR)/floor1.o
TREMOR_OBJS += $(TREMOR)/info.o $(TREMOR)/mapping0.o $(TREMOR)/mdct.o $(TREMOR)/registry.o
TREMOR_OBJS += $(TREMOR)/res012.o $(TREMOR)/sharedbook.o $(TREMOR)/synthesis.o $(TREMOR)/window.o
TREMOR_OBJS += $(TREMOR)/vorbisfile.o $(TREMOR)/framing.o $(TREMOR)/bitwise.o
$(TREMOR_OBJS) platform/common/ogg.o: CFLAGS += -I$(TREMOR) -DUSE_TREMOR
# API conflict between libvorbis and libvorbisidec (aka tremor) when compiling for retroarch
$(TREMOR_OBJS): CFLAGS += $(call chkCCflag, -fvisibility=hidden)
OBJS += $(TREMOR_OBJS)
else
LDLIBS += -lvorbisfile -lvorbis -logg
endif
ifeq (1,$(use_libchdr))
CFLAGS += -DUSE_LIBCHDR
@@ -368,9 +383,10 @@ endif
ifeq "$(PLATFORM_ZLIB)" "1"
# zlib
OBJS += zlib/gzio.o zlib/inffast.o zlib/inflate.o zlib/inftrees.o zlib/trees.o \
ZLIB_OBJS = zlib/gzio.o zlib/inffast.o zlib/inflate.o zlib/inftrees.o zlib/trees.o \
zlib/deflate.o zlib/crc32.o zlib/adler32.o zlib/zutil.o zlib/compress.o zlib/uncompr.o
CFLAGS += -Izlib
OBJS += $(ZLIB_OBJS)
endif
# unzip
OBJS += unzip/unzip.o
+12
View File
@@ -205,6 +205,7 @@ else ifeq ($(platform), psp1)
AR = psp-ar$(EXE_EXT)
CFLAGS += -DPSP -G0 -ftracer
CFLAGS += -I$(shell psp-config --pspsdk-path)/include
PLATFORM_TREMOR ?= 1
STATIC_LINKING = 1
STATIC_LINKING_LINK = 1
@@ -216,6 +217,7 @@ else ifeq ($(platform), ps2)
AR = mips64r5900el-ps2-elf-ar$(EXE_EXT)
CFLAGS += -Wall -DPS2 -D_EE -DUSE_BGR555 -DFAMEC_NO_GOTOS -DRENDER_GSKIT_PS2 -fsingle-precision-constant
CFLAGS += -I$(PS2DEV)/gsKit/include -I$(PS2SDK)/ee/include -I$(PS2SDK)/common/include
PLATFORM_TREMOR ?= 1
STATIC_LINKING = 1
STATIC_LINKING_LINK = 1
@@ -261,6 +263,7 @@ else ifeq ($(platform), vita)
CFLAGS += -fno-asynchronous-unwind-tables -ftree-vectorize -funroll-loops
CFLAGS += -mword-relocations -fno-unwind-tables
CFLAGS += -fno-optimize-sibling-calls
PLATFORM_TREMOR ?= 1
STATIC_LINKING = 1
STATIC_LINKING_LINK = 1
@@ -277,6 +280,7 @@ else ifeq ($(platform), ngc)
CC = $(DEVKITPPC)/bin/powerpc-eabi-gcc$(EXE_EXT)
AR = $(DEVKITPPC)/bin/powerpc-eabi-ar$(EXE_EXT)
CFLAGS += -DGEKKO -DHW_DOL -mrvl -mcpu=750 -meabi -mhard-float
PLATFORM_TREMOR ?= 1
STATIC_LINKING = 1
STATIC_LINKING_LINK = 1
@@ -286,6 +290,7 @@ else ifeq ($(platform), wii)
CC = $(DEVKITPPC)/bin/powerpc-eabi-gcc$(EXE_EXT)
AR = $(DEVKITPPC)/bin/powerpc-eabi-ar$(EXE_EXT)
CFLAGS += -DGEKKO -DHW_RVL -mrvl -mcpu=750 -meabi -mhard-float -ffat-lto-objects
PLATFORM_TREMOR ?= 1
STATIC_LINKING = 1
STATIC_LINKING_LINK = 1
@@ -296,6 +301,7 @@ else ifeq ($(platform), wiiu)
CXX = $(DEVKITPPC)/bin/powerpc-eabi-g++$(EXE_EXT)
AR = $(DEVKITPPC)/bin/powerpc-eabi-ar$(EXE_EXT)
CFLAGS += -DGEKKO -DWIIU -DHW_RVL -DHW_WUP -mwup -mcpu=750 -meabi -mhard-float
PLATFORM_TREMOR ?= 1
STATIC_LINKING = 1
STATIC_LINKING_LINK = 1
@@ -711,6 +717,12 @@ else
LD = $(CC)
endif
# detect if the toolchain contains the vorbis decoder; use internal libtremor
# only if not, since there might be name clashes if retroarch also uses vorbis
NO_VORBIS_HEADER := $(shell echo '\#include <vorbis/vorbisfile.h>' | \
$(CC) $(CFLAGS) $(CPPFLAGS) -x c - -c -o /dev/null 2>/dev/null && \
echo 0 || echo 1)
PLATFORM_TREMOR ?= $(NO_VORBIS_HEADER)
PLATFORM_ZLIB ?= 1
include Makefile
Vendored
+6 -9
View File
@@ -496,15 +496,12 @@ echo >> $config_mak
echo "ARCH = $ARCH" >> $config_mak
echo "PLATFORM = $platform" >> $config_mak
echo "SOUND_DRIVERS = $sound_drivers" >> $config_mak
if [ "$have_gles" = "yes" ]; then
echo "HAVE_GLES = 1" >> $config_mak
fi
if [ "$have_libavcodec" = "yes" ]; then
echo "HAVE_LIBAVCODEC = 1" >> $config_mak
fi
if [ "$need_zlib" = "yes" ]; then
echo "PLATFORM_ZLIB = 1" >> $config_mak
fi
[ "$have_gles" = "yes" ] && echo "HAVE_GLES = 1" >> $config_mak
[ "$have_libavcodec" = "yes" ] && echo "HAVE_LIBAVCODEC = 1" >> $config_mak
[ "$need_zlib" = "yes" ] && echo "PLATFORM_ZLIB = 1" >> $config_mak
# we always use the internal tremor decoder for standalone
echo "PLATFORM_TREMOR = 1" >> $config_mak
if [ "$ARCH" = "arm" -a "$have_armv6" != "yes" -a "$have_armv7" != "yes" ]; then
# pass info to cyclone not to use newer arm arch instructions
echo "HAVE_ARMv6 = 0" >> $config_mak
+165 -211
View File
@@ -269,17 +269,17 @@ static void emith_flush(void)
#define EOP_C_DOP_REG_XIMM(cond,op,s,rn,rd,shift_imm,shift_op,rm) EOP_C_DOP_X(cond,op,s,rn,rd,A_AM1_REG_XIMM(shift_imm,shift_op,rm), rm, NO)
#define EOP_C_DOP_REG_XREG(cond,op,s,rn,rd,rs, shift_op,rm) EOP_C_DOP_X(cond,op,s,rn,rd,A_AM1_REG_XREG(rs, shift_op,rm), rm, rs)
#define EOP_MOV_IMM(rd, ror2,imm8) EOP_C_DOP_IMM(A_COND_AL,A_OP_MOV,0, 0,rd,ror2,imm8)
#define EOP_MVN_IMM(rd, ror2,imm8) EOP_C_DOP_IMM(A_COND_AL,A_OP_MVN,0, 0,rd,ror2,imm8)
#define EOP_ORR_IMM(rd,rn,ror2,imm8) EOP_C_DOP_IMM(A_COND_AL,A_OP_ORR,0,rn,rd,ror2,imm8)
#define EOP_EOR_IMM(rd,rn,ror2,imm8) EOP_C_DOP_IMM(A_COND_AL,A_OP_EOR,0,rn,rd,ror2,imm8)
#define EOP_ADD_IMM(rd,rn,ror2,imm8) EOP_C_DOP_IMM(A_COND_AL,A_OP_ADD,0,rn,rd,ror2,imm8)
#define EOP_BIC_IMM(rd,rn,ror2,imm8) EOP_C_DOP_IMM(A_COND_AL,A_OP_BIC,0,rn,rd,ror2,imm8)
#define EOP_AND_IMM(rd,rn,ror2,imm8) EOP_C_DOP_IMM(A_COND_AL,A_OP_AND,0,rn,rd,ror2,imm8)
#define EOP_SUB_IMM(rd,rn,ror2,imm8) EOP_C_DOP_IMM(A_COND_AL,A_OP_SUB,0,rn,rd,ror2,imm8)
#define EOP_TST_IMM( rn,ror2,imm8) EOP_C_DOP_IMM(A_COND_AL,A_OP_TST,1,rn, 0,ror2,imm8)
#define EOP_CMP_IMM( rn,ror2,imm8) EOP_C_DOP_IMM(A_COND_AL,A_OP_CMP,1,rn, 0,ror2,imm8)
#define EOP_RSB_IMM(rd,rn,ror2,imm8) EOP_C_DOP_IMM(A_COND_AL,A_OP_RSB,0,rn,rd,ror2,imm8)
#define EOP_MOV_IMM(rd, ror2,imm8) EOP_C_DOP_IMM(insn_cond,A_OP_MOV,0, 0,rd,ror2,imm8)
#define EOP_MVN_IMM(rd, ror2,imm8) EOP_C_DOP_IMM(insn_cond,A_OP_MVN,0, 0,rd,ror2,imm8)
#define EOP_ORR_IMM(rd,rn,ror2,imm8) EOP_C_DOP_IMM(insn_cond,A_OP_ORR,0,rn,rd,ror2,imm8)
#define EOP_EOR_IMM(rd,rn,ror2,imm8) EOP_C_DOP_IMM(insn_cond,A_OP_EOR,0,rn,rd,ror2,imm8)
#define EOP_ADD_IMM(rd,rn,ror2,imm8) EOP_C_DOP_IMM(insn_cond,A_OP_ADD,0,rn,rd,ror2,imm8)
#define EOP_BIC_IMM(rd,rn,ror2,imm8) EOP_C_DOP_IMM(insn_cond,A_OP_BIC,0,rn,rd,ror2,imm8)
#define EOP_AND_IMM(rd,rn,ror2,imm8) EOP_C_DOP_IMM(insn_cond,A_OP_AND,0,rn,rd,ror2,imm8)
#define EOP_SUB_IMM(rd,rn,ror2,imm8) EOP_C_DOP_IMM(insn_cond,A_OP_SUB,0,rn,rd,ror2,imm8)
#define EOP_TST_IMM( rn,ror2,imm8) EOP_C_DOP_IMM(insn_cond,A_OP_TST,1,rn, 0,ror2,imm8)
#define EOP_CMP_IMM( rn,ror2,imm8) EOP_C_DOP_IMM(insn_cond,A_OP_CMP,1,rn, 0,ror2,imm8)
#define EOP_RSB_IMM(rd,rn,ror2,imm8) EOP_C_DOP_IMM(insn_cond,A_OP_RSB,0,rn,rd,ror2,imm8)
#define EOP_MOV_IMM_C(cond,rd, ror2,imm8) EOP_C_DOP_IMM(cond,A_OP_MOV,0, 0,rd,ror2,imm8)
#define EOP_ORR_IMM_C(cond,rd,rn,ror2,imm8) EOP_C_DOP_IMM(cond,A_OP_ORR,0,rn,rd,ror2,imm8)
@@ -298,27 +298,27 @@ static void emith_flush(void)
#define EOP_TST_REG(cond, rn,rm,shift_op,shift_imm) EOP_C_DOP_REG_XIMM(cond,A_OP_TST,1,rn, 0,shift_imm,shift_op,rm)
#define EOP_TEQ_REG(cond, rn,rm,shift_op,shift_imm) EOP_C_DOP_REG_XIMM(cond,A_OP_TEQ,1,rn, 0,shift_imm,shift_op,rm)
#define EOP_MOV_REG2(s,rd, rm,shift_op,rs) EOP_C_DOP_REG_XREG(A_COND_AL,A_OP_MOV,s, 0,rd,rs,shift_op,rm)
#define EOP_ADD_REG2(s,rd,rn,rm,shift_op,rs) EOP_C_DOP_REG_XREG(A_COND_AL,A_OP_ADD,s,rn,rd,rs,shift_op,rm)
#define EOP_SUB_REG2(s,rd,rn,rm,shift_op,rs) EOP_C_DOP_REG_XREG(A_COND_AL,A_OP_SUB,s,rn,rd,rs,shift_op,rm)
#define EOP_MOV_REG2(s,rd, rm,shift_op,rs) EOP_C_DOP_REG_XREG(insn_cond,A_OP_MOV,s, 0,rd,rs,shift_op,rm)
#define EOP_ADD_REG2(s,rd,rn,rm,shift_op,rs) EOP_C_DOP_REG_XREG(insn_cond,A_OP_ADD,s,rn,rd,rs,shift_op,rm)
#define EOP_SUB_REG2(s,rd,rn,rm,shift_op,rs) EOP_C_DOP_REG_XREG(insn_cond,A_OP_SUB,s,rn,rd,rs,shift_op,rm)
#define EOP_MOV_REG_SIMPLE(rd,rm) EOP_MOV_REG(A_COND_AL,0,rd,rm,A_AM1_LSL,0)
#define EOP_MOV_REG_LSL(rd, rm,shift_imm) EOP_MOV_REG(A_COND_AL,0,rd,rm,A_AM1_LSL,shift_imm)
#define EOP_MOV_REG_LSR(rd, rm,shift_imm) EOP_MOV_REG(A_COND_AL,0,rd,rm,A_AM1_LSR,shift_imm)
#define EOP_MOV_REG_ASR(rd, rm,shift_imm) EOP_MOV_REG(A_COND_AL,0,rd,rm,A_AM1_ASR,shift_imm)
#define EOP_MOV_REG_ROR(rd, rm,shift_imm) EOP_MOV_REG(A_COND_AL,0,rd,rm,A_AM1_ROR,shift_imm)
#define EOP_MOV_REG_SIMPLE(rd,rm) EOP_MOV_REG(insn_cond,0,rd,rm,A_AM1_LSL,0)
#define EOP_MOV_REG_LSL(rd, rm,shift_imm) EOP_MOV_REG(insn_cond,0,rd,rm,A_AM1_LSL,shift_imm)
#define EOP_MOV_REG_LSR(rd, rm,shift_imm) EOP_MOV_REG(insn_cond,0,rd,rm,A_AM1_LSR,shift_imm)
#define EOP_MOV_REG_ASR(rd, rm,shift_imm) EOP_MOV_REG(insn_cond,0,rd,rm,A_AM1_ASR,shift_imm)
#define EOP_MOV_REG_ROR(rd, rm,shift_imm) EOP_MOV_REG(insn_cond,0,rd,rm,A_AM1_ROR,shift_imm)
#define EOP_ORR_REG_SIMPLE(rd,rm) EOP_ORR_REG(A_COND_AL,0,rd,rd,rm,A_AM1_LSL,0)
#define EOP_ORR_REG_LSL(rd,rn,rm,shift_imm) EOP_ORR_REG(A_COND_AL,0,rd,rn,rm,A_AM1_LSL,shift_imm)
#define EOP_ORR_REG_LSR(rd,rn,rm,shift_imm) EOP_ORR_REG(A_COND_AL,0,rd,rn,rm,A_AM1_LSR,shift_imm)
#define EOP_ORR_REG_ASR(rd,rn,rm,shift_imm) EOP_ORR_REG(A_COND_AL,0,rd,rn,rm,A_AM1_ASR,shift_imm)
#define EOP_ORR_REG_ROR(rd,rn,rm,shift_imm) EOP_ORR_REG(A_COND_AL,0,rd,rn,rm,A_AM1_ROR,shift_imm)
#define EOP_ORR_REG_SIMPLE(rd,rm) EOP_ORR_REG(insn_cond,0,rd,rd,rm,A_AM1_LSL,0)
#define EOP_ORR_REG_LSL(rd,rn,rm,shift_imm) EOP_ORR_REG(insn_cond,0,rd,rn,rm,A_AM1_LSL,shift_imm)
#define EOP_ORR_REG_LSR(rd,rn,rm,shift_imm) EOP_ORR_REG(insn_cond,0,rd,rn,rm,A_AM1_LSR,shift_imm)
#define EOP_ORR_REG_ASR(rd,rn,rm,shift_imm) EOP_ORR_REG(insn_cond,0,rd,rn,rm,A_AM1_ASR,shift_imm)
#define EOP_ORR_REG_ROR(rd,rn,rm,shift_imm) EOP_ORR_REG(insn_cond,0,rd,rn,rm,A_AM1_ROR,shift_imm)
#define EOP_ADD_REG_SIMPLE(rd,rm) EOP_ADD_REG(A_COND_AL,0,rd,rd,rm,A_AM1_LSL,0)
#define EOP_ADD_REG_LSL(rd,rn,rm,shift_imm) EOP_ADD_REG(A_COND_AL,0,rd,rn,rm,A_AM1_LSL,shift_imm)
#define EOP_ADD_REG_LSR(rd,rn,rm,shift_imm) EOP_ADD_REG(A_COND_AL,0,rd,rn,rm,A_AM1_LSR,shift_imm)
#define EOP_ADD_REG_SIMPLE(rd,rm) EOP_ADD_REG(insn_cond,0,rd,rd,rm,A_AM1_LSL,0)
#define EOP_ADD_REG_LSL(rd,rn,rm,shift_imm) EOP_ADD_REG(insn_cond,0,rd,rn,rm,A_AM1_LSL,shift_imm)
#define EOP_ADD_REG_LSR(rd,rn,rm,shift_imm) EOP_ADD_REG(insn_cond,0,rd,rn,rm,A_AM1_LSR,shift_imm)
#define EOP_TST_REG_SIMPLE(rn,rm) EOP_TST_REG(A_COND_AL, rn, 0,A_AM1_LSL,rm)
#define EOP_TST_REG_SIMPLE(rn,rm) EOP_TST_REG(insn_cond, rn, 0,A_AM1_LSL,rm)
#define EOP_MOV_REG2_LSL(rd, rm,rs) EOP_MOV_REG2(0,rd, rm,A_AM1_LSL,rs)
#define EOP_MOV_REG2_ROR(rd, rm,rs) EOP_MOV_REG2(0,rd, rm,A_AM1_ROR,rs)
@@ -348,10 +348,10 @@ static void emith_flush(void)
#define EOP_LDRB_IMM2(cond,rd,rn,offset_12) EOP_C_AM2_IMM(cond,(offset_12) >= 0,1,1,rn,rd,pabs(offset_12))
#define EOP_STR_IMM2(cond,rd,rn,offset_12) EOP_C_AM2_IMM(cond,(offset_12) >= 0,0,0,rn,rd,pabs(offset_12))
#define EOP_LDR_IMM( rd,rn,offset_12) EOP_C_AM2_IMM(A_COND_AL,(offset_12) >= 0,0,1,rn,rd,pabs(offset_12))
#define EOP_LDR_SIMPLE(rd,rn) EOP_C_AM2_IMM(A_COND_AL,1,0,1,rn,rd,0)
#define EOP_STR_IMM( rd,rn,offset_12) EOP_C_AM2_IMM(A_COND_AL,(offset_12) >= 0,0,0,rn,rd,pabs(offset_12))
#define EOP_STR_SIMPLE(rd,rn) EOP_C_AM2_IMM(A_COND_AL,1,0,0,rn,rd,0)
#define EOP_LDR_IMM( rd,rn,offset_12) EOP_C_AM2_IMM(insn_cond,(offset_12) >= 0,0,1,rn,rd,pabs(offset_12))
#define EOP_LDR_SIMPLE(rd,rn) EOP_C_AM2_IMM(insn_cond,1,0,1,rn,rd,0)
#define EOP_STR_IMM( rd,rn,offset_12) EOP_C_AM2_IMM(insn_cond,(offset_12) >= 0,0,0,rn,rd,pabs(offset_12))
#define EOP_STR_SIMPLE(rd,rn) EOP_C_AM2_IMM(insn_cond,1,0,0,rn,rd,0)
#define EOP_LDR_REG_LSL(cond,rd,rn,rm,shift_imm) EOP_C_AM2_REG(cond,1,0,1,rn,rd,shift_imm,A_AM1_LSL,rm)
#define EOP_LDR_REG_LSL_WB(cond,rd,rn,rm,shift_imm) EOP_C_AM2_REG(cond,1,0,3,rn,rd,shift_imm,A_AM1_LSL,rm)
@@ -361,12 +361,12 @@ static void emith_flush(void)
#define EOP_LDRH_IMM2(cond,rd,rn,offset_8) EOP_C_AM3_IMM(cond,(offset_8) >= 0,1,rn,rd,0,1,pabs(offset_8))
#define EOP_LDRH_REG2(cond,rd,rn,rm) EOP_C_AM3_REG(cond,1,1,rn,rd,0,1,rm)
#define EOP_LDRH_IMM( rd,rn,offset_8) EOP_C_AM3_IMM(A_COND_AL,(offset_8) >= 0,1,rn,rd,0,1,pabs(offset_8))
#define EOP_LDRH_SIMPLE(rd,rn) EOP_C_AM3_IMM(A_COND_AL,1,1,rn,rd,0,1,0)
#define EOP_LDRH_REG( rd,rn,rm) EOP_C_AM3_REG(A_COND_AL,1,1,rn,rd,0,1,rm)
#define EOP_STRH_IMM( rd,rn,offset_8) EOP_C_AM3_IMM(A_COND_AL,(offset_8) >= 0,0,rn,rd,0,1,pabs(offset_8))
#define EOP_STRH_SIMPLE(rd,rn) EOP_C_AM3_IMM(A_COND_AL,1,0,rn,rd,0,1,0)
#define EOP_STRH_REG( rd,rn,rm) EOP_C_AM3_REG(A_COND_AL,1,0,rn,rd,0,1,rm)
#define EOP_LDRH_IMM( rd,rn,offset_8) EOP_C_AM3_IMM(insn_cond,(offset_8) >= 0,1,rn,rd,0,1,pabs(offset_8))
#define EOP_LDRH_SIMPLE(rd,rn) EOP_C_AM3_IMM(insn_cond,1,1,rn,rd,0,1,0)
#define EOP_LDRH_REG( rd,rn,rm) EOP_C_AM3_REG(insn_cond,1,1,rn,rd,0,1,rm)
#define EOP_STRH_IMM( rd,rn,offset_8) EOP_C_AM3_IMM(insn_cond,(offset_8) >= 0,0,rn,rd,0,1,pabs(offset_8))
#define EOP_STRH_SIMPLE(rd,rn) EOP_C_AM3_IMM(insn_cond,1,0,rn,rd,0,1,0)
#define EOP_STRH_REG( rd,rn,rm) EOP_C_AM3_REG(insn_cond,1,0,rn,rd,0,1,rm)
#define EOP_LDRSB_IMM2(cond,rd,rn,offset_8) EOP_C_AM3_IMM(cond,(offset_8) >= 0,1,rn,rd,1,0,pabs(offset_8))
#define EOP_LDRSB_REG2(cond,rd,rn,rm) EOP_C_AM3_REG(cond,1,1,rn,rd,1,0,rm)
@@ -378,11 +378,11 @@ static void emith_flush(void)
EMIT(((cond)<<28) | (1<<27) | ((p)<<24) | ((u)<<23) | ((s)<<22) | ((w)<<21) | ((l)<<20) | ((rn)<<16) | (list), \
M2(rn,l?NO:MEM)|(l?list:0), M3(rn,l?MEM:NO,l?CYC2:NO)|(l?0:list))
#define EOP_STMIA(rb,list) EOP_XXM(A_COND_AL,0,1,0,0,0,rb,list)
#define EOP_LDMIA(rb,list) EOP_XXM(A_COND_AL,0,1,0,0,1,rb,list)
#define EOP_STMIA(rb,list) EOP_XXM(insn_cond,0,1,0,0,0,rb,list)
#define EOP_LDMIA(rb,list) EOP_XXM(insn_cond,0,1,0,0,1,rb,list)
#define EOP_STMFD_SP(list) EOP_XXM(A_COND_AL,1,0,0,1,0,SP,list)
#define EOP_LDMFD_SP(list) EOP_XXM(A_COND_AL,0,1,0,1,1,SP,list)
#define EOP_STMFD_SP(list) EOP_XXM(insn_cond,1,0,0,1,0,SP,list)
#define EOP_LDMFD_SP(list) EOP_XXM(insn_cond,0,1,0,1,1,SP,list)
/* branches */
#define EOP_C_BX(cond,rm) \
@@ -394,8 +394,8 @@ static void emith_flush(void)
#define EOP_C_B(cond,l,signed_immed_24) \
EMIT(((cond)<<28) | 0x0a000000 | ((l)<<24) | (signed_immed_24), M2(PC,l?LR:NO), M1(PC))
#define EOP_B( signed_immed_24) EOP_C_B(A_COND_AL,0,signed_immed_24)
#define EOP_BL(signed_immed_24) EOP_C_B(A_COND_AL,1,signed_immed_24)
#define EOP_B( signed_immed_24) EOP_C_B(insn_cond,0,signed_immed_24)
#define EOP_BL(signed_immed_24) EOP_C_B(insn_cond,1,signed_immed_24)
/* misc */
#define EOP_C_MUL(cond,s,rd,rs,rm) \
@@ -410,7 +410,7 @@ static void emith_flush(void)
#define EOP_C_SMLAL(cond,s,rdhi,rdlo,rs,rm) \
EMIT(((cond)<<28) | 0x00e00000 | ((s)<<20) | ((rdhi)<<16) | ((rdlo)<<12) | ((rs)<<8) | 0x90 | (rm), M3(rdhi,rdlo,s?SR:NO), M6(rs,rm,rdlo,rdhi,CYC1,CYC2))
#define EOP_MUL(rd,rm,rs) EOP_C_MUL(A_COND_AL,0,rd,rs,rm) // note: rd != rm
#define EOP_MUL(rd,rm,rs) EOP_C_MUL(insn_cond,0,rd,rs,rm) // note: rd != rm
#define EOP_C_MRS(cond,rd) \
EMIT(((cond)<<28) | 0x010f0000 | ((rd)<<12), M1(rd), M1(SR))
@@ -421,9 +421,9 @@ static void emith_flush(void)
#define EOP_C_MSR_REG(cond,rm) \
EMIT(((cond)<<28) | 0x0128f000 | (rm), M1(SR), M1(rm)) // cpsr_f
#define EOP_MRS(rd) EOP_C_MRS(A_COND_AL,rd)
#define EOP_MSR_IMM(ror2,imm) EOP_C_MSR_IMM(A_COND_AL,ror2,imm)
#define EOP_MSR_REG(rm) EOP_C_MSR_REG(A_COND_AL,rm)
#define EOP_MRS(rd) EOP_C_MRS(insn_cond,rd)
#define EOP_MSR_IMM(ror2,imm) EOP_C_MSR_IMM(insn_cond,ror2,imm)
#define EOP_MSR_REG(rm) EOP_C_MSR_REG(insn_cond,rm)
#define EOP_MOVW(cond,rd,imm) \
EMIT(((cond)<<28) | 0x03000000 | ((rd)<<12) | ((imm)&0xfff) | (((imm)<<4)&0xf0000), M1(rd), NO)
@@ -667,6 +667,8 @@ static inline void emith_pool_adjust(int tcache_offs, int move_offs)
literal_insn[i] += move_offs;
}
static int insn_cond = A_COND_AL;
#define EMITH_HINT_COND(cond) /**/
#define JMP_POS(ptr) { \
@@ -680,80 +682,79 @@ static inline void emith_pool_adjust(int tcache_offs, int move_offs)
EOP_C_B_PTR(ptr, cond, 0, val_ & 0xffffff); \
}
#define EMITH_JMP_START(cond) { \
void *cond_ptr; \
#define EMITH_JMP_START(cond) \
{ void *cond_ptr; \
JMP_POS(cond_ptr)
#define EMITH_JMP_END(cond) \
JMP_EMIT(cond, cond_ptr); \
}
// fake "simple" or "short" jump - using cond insns instead
#define EMITH_NOTHING1(cond) \
(void)(cond)
#define EMITH_COND_START(cond) \
{ int insn_cond = (cond)^1;
#define EMITH_COND_MID(cond) \
insn_cond = cond;
#define EMITH_COND_END(cond) \
}
#define EMITH_SJMP_START(cond) EMITH_NOTHING1(cond)
#define EMITH_SJMP_END(cond) EMITH_NOTHING1(cond)
#define EMITH_SJMP2_START(cond) EMITH_NOTHING1(cond)
#define EMITH_SJMP2_MID(cond) EMITH_JMP_START((cond)^1) // inverse cond
#define EMITH_SJMP2_END(cond) EMITH_JMP_END((cond)^1)
#define EMITH_SJMP3_START(cond) EMITH_NOTHING1(cond)
#define EMITH_SJMP3_MID(cond) EMITH_NOTHING1(cond)
#define EMITH_SJMP3_END()
#define EMITH_SJMP_START(cond) EMITH_COND_START(cond)
#define EMITH_SJMP_END(cond) EMITH_COND_END(cond)
#define EMITH_SJMP2_START(cond) EMITH_COND_START(cond)
#define EMITH_SJMP2_MID(cond) EMITH_COND_END(cond); \
EMITH_JMP_START((cond)^1) // inverse cond
#define EMITH_SJMP2_END(cond) EMITH_JMP_END((cond)^1);
#define EMITH_SJMP3_START(cond) EMITH_COND_START(cond)
#define EMITH_SJMP3_MID(cond) EMITH_COND_MID(cond)
#define EMITH_SJMP3_END() EMITH_COND_END(cond)
#define emith_move_r_r_c(cond, d, s) \
EOP_MOV_REG(cond,0,d,s,A_AM1_LSL,0)
#define emith_move_r_r(d, s) \
emith_move_r_r_c(A_COND_AL, d, s)
#define emith_move_r_r_ptr_c(cond, d, s) \
emith_move_r_r_c(cond, d, s)
EOP_MOV_REG(insn_cond,0,d,s,A_AM1_LSL,0)
#define emith_move_r_r_ptr(d, s) \
emith_move_r_r(d, s)
#define emith_mvn_r_r(d, s) \
EOP_MVN_REG(A_COND_AL,0,d,s,A_AM1_LSL,0)
EOP_MVN_REG(insn_cond,0,d,s,A_AM1_LSL,0)
#define emith_add_r_r_r_lsl(d, s1, s2, lslimm) \
EOP_ADD_REG(A_COND_AL,0,d,s1,s2,A_AM1_LSL,lslimm)
EOP_ADD_REG(insn_cond,0,d,s1,s2,A_AM1_LSL,lslimm)
#define emith_add_r_r_r_lsl_ptr(d, s1, s2, lslimm) \
emith_add_r_r_r_lsl(d, s1, s2, lslimm)
#define emith_adc_r_r_r_lsl(d, s1, s2, lslimm) \
EOP_ADC_REG(A_COND_AL,0,d,s1,s2,A_AM1_LSL,lslimm)
EOP_ADC_REG(insn_cond,0,d,s1,s2,A_AM1_LSL,lslimm)
#define emith_addf_r_r_r_lsl(d, s1, s2, lslimm) \
EOP_ADD_REG(A_COND_AL,1,d,s1,s2,A_AM1_LSL,lslimm)
EOP_ADD_REG(insn_cond,1,d,s1,s2,A_AM1_LSL,lslimm)
#define emith_addf_r_r_r_lsr(d, s1, s2, lslimm) \
EOP_ADD_REG(A_COND_AL,1,d,s1,s2,A_AM1_LSR,lslimm)
EOP_ADD_REG(insn_cond,1,d,s1,s2,A_AM1_LSR,lslimm)
#define emith_adcf_r_r_r_lsl(d, s1, s2, lslimm) \
EOP_ADC_REG(A_COND_AL,1,d,s1,s2,A_AM1_LSL,lslimm)
EOP_ADC_REG(insn_cond,1,d,s1,s2,A_AM1_LSL,lslimm)
#define emith_sub_r_r_r_lsl(d, s1, s2, lslimm) \
EOP_SUB_REG(A_COND_AL,0,d,s1,s2,A_AM1_LSL,lslimm)
EOP_SUB_REG(insn_cond,0,d,s1,s2,A_AM1_LSL,lslimm)
#define emith_sbc_r_r_r_lsl(d, s1, s2, lslimm) \
EOP_SBC_REG(A_COND_AL,0,d,s1,s2,A_AM1_LSL,lslimm)
EOP_SBC_REG(insn_cond,0,d,s1,s2,A_AM1_LSL,lslimm)
#define emith_subf_r_r_r_lsl(d, s1, s2, lslimm) \
EOP_SUB_REG(A_COND_AL,1,d,s1,s2,A_AM1_LSL,lslimm)
EOP_SUB_REG(insn_cond,1,d,s1,s2,A_AM1_LSL,lslimm)
#define emith_sbcf_r_r_r_lsl(d, s1, s2, lslimm) \
EOP_SBC_REG(A_COND_AL,1,d,s1,s2,A_AM1_LSL,lslimm)
EOP_SBC_REG(insn_cond,1,d,s1,s2,A_AM1_LSL,lslimm)
#define emith_or_r_r_r_lsl(d, s1, s2, lslimm) \
EOP_ORR_REG(A_COND_AL,0,d,s1,s2,A_AM1_LSL,lslimm)
EOP_ORR_REG(insn_cond,0,d,s1,s2,A_AM1_LSL,lslimm)
#define emith_or_r_r_r_lsr(d, s1, s2, lsrimm) \
EOP_ORR_REG(A_COND_AL,0,d,s1,s2,A_AM1_LSR,lsrimm)
EOP_ORR_REG(insn_cond,0,d,s1,s2,A_AM1_LSR,lsrimm)
#define emith_eor_r_r_r_lsl(d, s1, s2, lslimm) \
EOP_EOR_REG(A_COND_AL,0,d,s1,s2,A_AM1_LSL,lslimm)
EOP_EOR_REG(insn_cond,0,d,s1,s2,A_AM1_LSL,lslimm)
#define emith_eor_r_r_r_lsr(d, s1, s2, lsrimm) \
EOP_EOR_REG(A_COND_AL,0,d,s1,s2,A_AM1_LSR,lsrimm)
EOP_EOR_REG(insn_cond,0,d,s1,s2,A_AM1_LSR,lsrimm)
#define emith_and_r_r_r_lsl(d, s1, s2, lslimm) \
EOP_AND_REG(A_COND_AL,0,d,s1,s2,A_AM1_LSL,lslimm)
EOP_AND_REG(insn_cond,0,d,s1,s2,A_AM1_LSL,lslimm)
#define emith_or_r_r_lsl(d, s, lslimm) \
emith_or_r_r_r_lsl(d, d, s, lslimm)
@@ -814,12 +815,10 @@ static inline void emith_pool_adjust(int tcache_offs, int move_offs)
emith_sbc_r_r_r(d, d, s)
#define emith_negc_r_r(d, s) \
EOP_C_DOP_IMM(A_COND_AL,A_OP_RSC,0,s,d,0,0)
EOP_C_DOP_IMM(insn_cond,A_OP_RSC,0,s,d,0,0)
#define emith_and_r_r_c(cond, d, s) \
EOP_AND_REG(cond,0,d,d,s,A_AM1_LSL,0)
#define emith_and_r_r(d, s) \
EOP_AND_REG(A_COND_AL,0,d,d,s,A_AM1_LSL,0)
EOP_AND_REG(insn_cond,0,d,d,s,A_AM1_LSL,0)
#define emith_or_r_r(d, s) \
emith_or_r_r_r(d, d, s)
@@ -828,68 +827,68 @@ static inline void emith_pool_adjust(int tcache_offs, int move_offs)
emith_eor_r_r_r(d, d, s)
#define emith_tst_r_r(d, s) \
EOP_TST_REG(A_COND_AL,d,s,A_AM1_LSL,0)
EOP_TST_REG(insn_cond,d,s,A_AM1_LSL,0)
#define emith_tst_r_r_ptr(d, s) \
emith_tst_r_r(d, s)
#define emith_teq_r_r(d, s) \
EOP_TEQ_REG(A_COND_AL,d,s,A_AM1_LSL,0)
EOP_TEQ_REG(insn_cond,d,s,A_AM1_LSL,0)
#define emith_cmp_r_r(d, s) \
EOP_CMP_REG(A_COND_AL,d,s,A_AM1_LSL,0)
EOP_CMP_REG(insn_cond,d,s,A_AM1_LSL,0)
#define emith_addf_r_r(d, s) \
EOP_ADD_REG(A_COND_AL,1,d,d,s,A_AM1_LSL,0)
EOP_ADD_REG(insn_cond,1,d,d,s,A_AM1_LSL,0)
#define emith_subf_r_r(d, s) \
EOP_SUB_REG(A_COND_AL,1,d,d,s,A_AM1_LSL,0)
EOP_SUB_REG(insn_cond,1,d,d,s,A_AM1_LSL,0)
#define emith_adcf_r_r(d, s) \
EOP_ADC_REG(A_COND_AL,1,d,d,s,A_AM1_LSL,0)
EOP_ADC_REG(insn_cond,1,d,d,s,A_AM1_LSL,0)
#define emith_sbcf_r_r(d, s) \
EOP_SBC_REG(A_COND_AL,1,d,d,s,A_AM1_LSL,0)
EOP_SBC_REG(insn_cond,1,d,d,s,A_AM1_LSL,0)
#define emith_eorf_r_r(d, s) \
EOP_EOR_REG(A_COND_AL,1,d,d,s,A_AM1_LSL,0)
EOP_EOR_REG(insn_cond,1,d,d,s,A_AM1_LSL,0)
#define emith_move_r_imm(r, imm) \
emith_op_imm(A_COND_AL, 0, A_OP_MOV, r, imm)
emith_op_imm(insn_cond, 0, A_OP_MOV, r, imm)
#define emith_move_r_ptr_imm(r, imm) \
emith_move_r_imm(r, (u32)(imm))
#define emith_add_r_imm(r, imm) \
emith_op_imm(A_COND_AL, 0, A_OP_ADD, r, imm)
emith_op_imm(insn_cond, 0, A_OP_ADD, r, imm)
#define emith_adc_r_imm(r, imm) \
emith_op_imm(A_COND_AL, 0, A_OP_ADC, r, imm)
emith_op_imm(insn_cond, 0, A_OP_ADC, r, imm)
#define emith_adcf_r_imm(r, imm) \
emith_op_imm(A_COND_AL, 1, A_OP_ADC, r, imm)
emith_op_imm(insn_cond, 1, A_OP_ADC, r, imm)
#define emith_sub_r_imm(r, imm) \
emith_op_imm(A_COND_AL, 0, A_OP_SUB, r, imm)
emith_op_imm(insn_cond, 0, A_OP_SUB, r, imm)
#define emith_bic_r_imm(r, imm) \
emith_op_imm(A_COND_AL, 0, A_OP_BIC, r, imm)
emith_op_imm(insn_cond, 0, A_OP_BIC, r, imm)
#define emith_and_r_imm(r, imm) \
emith_op_imm(A_COND_AL, 0, A_OP_AND, r, imm)
emith_op_imm(insn_cond, 0, A_OP_AND, r, imm)
#define emith_or_r_imm(r, imm) \
emith_op_imm(A_COND_AL, 0, A_OP_ORR, r, imm)
emith_op_imm(insn_cond, 0, A_OP_ORR, r, imm)
#define emith_eor_r_imm(r, imm) \
emith_op_imm(A_COND_AL, 0, A_OP_EOR, r, imm)
emith_op_imm(insn_cond, 0, A_OP_EOR, r, imm)
#define emith_eor_r_imm_ptr(r, imm) \
emith_eor_r_imm(r, imm)
// note: only use 8bit imm for these
#define emith_tst_r_imm(r, imm) \
emith_top_imm(A_COND_AL, A_OP_TST, r, imm)
emith_top_imm(insn_cond, A_OP_TST, r, imm)
#define emith_cmp_r_imm(r, imm) do { \
u32 op_ = A_OP_CMP, imm_ = (u8)imm; \
@@ -897,11 +896,11 @@ static inline void emith_pool_adjust(int tcache_offs, int move_offs)
imm_ = (u8)-imm_; \
op_ = A_OP_CMN; \
} \
emith_top_imm(A_COND_AL, op_, r, imm_); \
emith_top_imm(insn_cond, op_, r, imm_); \
} while (0)
#define emith_subf_r_imm(r, imm) \
emith_op_imm(A_COND_AL, 1, A_OP_SUB, r, imm)
emith_op_imm(insn_cond, 1, A_OP_SUB, r, imm)
#define emith_move_r_imm_c(cond, r, imm) \
emith_op_imm(cond, 0, A_OP_MOV, r, imm)
@@ -943,10 +942,10 @@ static inline void emith_pool_adjust(int tcache_offs, int move_offs)
} while (0)
#define emith_and_r_r_imm(d, s, imm) \
emith_op_imm2(A_COND_AL, 0, A_OP_AND, d, s, imm)
emith_op_imm2(insn_cond, 0, A_OP_AND, d, s, imm)
#define emith_add_r_r_imm(d, s, imm) \
emith_op_imm2(A_COND_AL, 0, A_OP_ADD, d, s, imm)
emith_op_imm2(insn_cond, 0, A_OP_ADD, d, s, imm)
#define emith_add_r_r_ptr_imm(d, s, imm) \
emith_add_r_r_imm(d, s, imm)
@@ -955,56 +954,53 @@ static inline void emith_pool_adjust(int tcache_offs, int move_offs)
emith_op_imm2(cond, 0, A_OP_SUB, d, s, (imm))
#define emith_sub_r_r_imm(d, s, imm) \
emith_op_imm2(A_COND_AL, 0, A_OP_SUB, d, s, imm)
emith_op_imm2(insn_cond, 0, A_OP_SUB, d, s, imm)
#define emith_subf_r_r_imm(d, s, imm) \
emith_op_imm2(A_COND_AL, 1, A_OP_SUB, d, s, imm)
emith_op_imm2(insn_cond, 1, A_OP_SUB, d, s, imm)
#define emith_or_r_r_imm(d, s, imm) \
emith_op_imm2(A_COND_AL, 0, A_OP_ORR, d, s, imm)
emith_op_imm2(insn_cond, 0, A_OP_ORR, d, s, imm)
#define emith_eor_r_r_imm(d, s, imm) \
emith_op_imm2(A_COND_AL, 0, A_OP_EOR, d, s, imm)
emith_op_imm2(insn_cond, 0, A_OP_EOR, d, s, imm)
#define emith_neg_r_r(d, s) \
EOP_RSB_IMM(d, s, 0, 0)
#define emith_lsl(d, s, cnt) \
EOP_MOV_REG(A_COND_AL,0,d,s,A_AM1_LSL,cnt)
EOP_MOV_REG(insn_cond,0,d,s,A_AM1_LSL,cnt)
#define emith_lsr(d, s, cnt) \
EOP_MOV_REG(A_COND_AL,0,d,s,A_AM1_LSR,cnt)
EOP_MOV_REG(insn_cond,0,d,s,A_AM1_LSR,cnt)
#define emith_asr(d, s, cnt) \
EOP_MOV_REG(A_COND_AL,0,d,s,A_AM1_ASR,cnt)
#define emith_ror_c(cond, d, s, cnt) \
EOP_MOV_REG(cond,0,d,s,A_AM1_ROR,cnt)
EOP_MOV_REG(insn_cond,0,d,s,A_AM1_ASR,cnt)
#define emith_ror(d, s, cnt) \
emith_ror_c(A_COND_AL, d, s, cnt)
EOP_MOV_REG(insn_cond,0,d,s,A_AM1_ROR,cnt)
#define emith_rol(d, s, cnt) \
EOP_MOV_REG(A_COND_AL,0,d,s,A_AM1_ROR,32-(cnt)); \
EOP_MOV_REG(insn_cond,0,d,s,A_AM1_ROR,32-(cnt)); \
#define emith_lslf(d, s, cnt) \
EOP_MOV_REG(A_COND_AL,1,d,s,A_AM1_LSL,cnt)
EOP_MOV_REG(insn_cond,1,d,s,A_AM1_LSL,cnt)
#define emith_lsrf(d, s, cnt) \
EOP_MOV_REG(A_COND_AL,1,d,s,A_AM1_LSR,cnt)
EOP_MOV_REG(insn_cond,1,d,s,A_AM1_LSR,cnt)
#define emith_asrf(d, s, cnt) \
EOP_MOV_REG(A_COND_AL,1,d,s,A_AM1_ASR,cnt)
EOP_MOV_REG(insn_cond,1,d,s,A_AM1_ASR,cnt)
// note: only C flag updated correctly
#define emith_rolf(d, s, cnt) do { \
EOP_MOV_REG(A_COND_AL,1,d,s,A_AM1_ROR,32-(cnt)); \
EOP_MOV_REG(insn_cond,1,d,s,A_AM1_ROR,32-(cnt)); \
/* we don't have ROL so we shift to get the right carry */ \
EOP_TST_REG(A_COND_AL,d,d,A_AM1_LSR,1); \
EOP_TST_REG(insn_cond,d,d,A_AM1_LSR,1); \
} while (0)
#define emith_rorf(d, s, cnt) \
EOP_MOV_REG(A_COND_AL,1,d,s,A_AM1_ROR,cnt)
EOP_MOV_REG(insn_cond,1,d,s,A_AM1_ROR,cnt)
#define emith_rolcf(d) \
emith_adcf_r_r(d, d)
@@ -1012,12 +1008,12 @@ static inline void emith_pool_adjust(int tcache_offs, int move_offs)
emith_adc_r_r(d, d)
#define emith_rorcf(d) \
EOP_MOV_REG(A_COND_AL,1,d,d,A_AM1_ROR,0) /* ROR #0 -> RRX */
EOP_MOV_REG(insn_cond,1,d,d,A_AM1_ROR,0) /* ROR #0 -> RRX */
#define emith_rorc(d) \
EOP_MOV_REG(A_COND_AL,0,d,d,A_AM1_ROR,0) /* ROR #0 -> RRX */
EOP_MOV_REG(insn_cond,0,d,d,A_AM1_ROR,0) /* ROR #0 -> RRX */
#define emith_negcf_r_r(d, s) \
EOP_C_DOP_IMM(A_COND_AL,A_OP_RSC,1,s,d,0,0)
EOP_C_DOP_IMM(insn_cond,A_OP_RSC,1,s,d,0,0)
#define emith_mul(d, s1, s2) do { \
if ((d) != (s1)) /* rd != rm limitation */ \
@@ -1027,79 +1023,51 @@ static inline void emith_pool_adjust(int tcache_offs, int move_offs)
} while (0)
#define emith_mul_u64(dlo, dhi, s1, s2) \
EOP_C_UMULL(A_COND_AL,0,dhi,dlo,s1,s2)
EOP_C_UMULL(insn_cond,0,dhi,dlo,s1,s2)
#define emith_mul_s64(dlo, dhi, s1, s2) \
EOP_C_SMULL(A_COND_AL,0,dhi,dlo,s1,s2)
EOP_C_SMULL(insn_cond,0,dhi,dlo,s1,s2)
#define emith_mula_s64_c(cond, dlo, dhi, s1, s2) \
EOP_C_SMLAL(cond,0,dhi,dlo,s1,s2)
#define emith_mula_s64(dlo, dhi, s1, s2) \
EOP_C_SMLAL(A_COND_AL,0,dhi,dlo,s1,s2)
EOP_C_SMLAL(insn_cond,0,dhi,dlo,s1,s2)
// misc
#define emith_read_r_r_offs_c(cond, r, rs, offs) \
EOP_LDR_IMM2(cond, r, rs, offs)
#define emith_read_r_r_offs_ptr_c(cond, r, rs, offs) \
emith_read_r_r_offs_c(cond, r, rs, offs)
#define emith_read_r_r_r_c(cond, r, rs, rm) \
EOP_LDR_REG_LSL(cond, r, rs, rm, 0)
#define emith_read_r_r_offs(r, rs, offs) \
emith_read_r_r_offs_c(A_COND_AL, r, rs, offs)
EOP_LDR_IMM2(insn_cond, r, rs, offs)
#define emith_read_r_r_offs_ptr(r, rs, offs) \
emith_read_r_r_offs_c(A_COND_AL, r, rs, offs)
emith_read_r_r_offs(r, rs, offs)
#define emith_read_r_r_r(r, rs, rm) \
EOP_LDR_REG_LSL(A_COND_AL, r, rs, rm, 0)
EOP_LDR_REG_LSL(insn_cond, r, rs, rm, 0)
#define emith_read_r_r_r(r, rs, rm) \
EOP_LDR_REG_LSL(insn_cond, r, rs, rm, 0)
#define emith_read8_r_r_offs_c(cond, r, rs, offs) \
EOP_LDRB_IMM2(cond, r, rs, offs)
#define emith_read8_r_r_r_c(cond, r, rs, rm) \
EOP_LDRB_REG_LSL(cond, r, rs, rm, 0)
#define emith_read8_r_r_offs(r, rs, offs) \
emith_read8_r_r_offs_c(A_COND_AL, r, rs, offs)
EOP_LDRB_IMM2(insn_cond, r, rs, offs)
#define emith_read8_r_r_r(r, rs, rm) \
emith_read8_r_r_r_c(A_COND_AL, r, rs, rm)
EOP_LDRB_REG_LSL(insn_cond, r, rs, rm, 0)
#define emith_read16_r_r_offs_c(cond, r, rs, offs) \
EOP_LDRH_IMM2(cond, r, rs, offs)
#define emith_read16_r_r_r_c(cond, r, rs, rm) \
EOP_LDRH_REG2(cond, r, rs, rm)
#define emith_read16_r_r_offs(r, rs, offs) \
emith_read16_r_r_offs_c(A_COND_AL, r, rs, offs)
EOP_LDRH_IMM2(insn_cond, r, rs, offs)
#define emith_read16_r_r_r(r, rs, rm) \
emith_read16_r_r_r_c(A_COND_AL, r, rs, rm)
EOP_LDRH_REG2(insn_cond, r, rs, rm)
#define emith_read8s_r_r_offs_c(cond, r, rs, offs) \
EOP_LDRSB_IMM2(cond, r, rs, offs)
#define emith_read8s_r_r_r_c(cond, r, rs, rm) \
EOP_LDRSB_REG2(cond, r, rs, rm)
#define emith_read8s_r_r_offs(r, rs, offs) \
emith_read8s_r_r_offs_c(A_COND_AL, r, rs, offs)
EOP_LDRSB_IMM2(insn_cond, r, rs, offs)
#define emith_read8s_r_r_r(r, rs, rm) \
emith_read8s_r_r_r_c(A_COND_AL, r, rs, rm)
EOP_LDRSB_REG2(insn_cond, r, rs, rm)
#define emith_read16s_r_r_offs_c(cond, r, rs, offs) \
EOP_LDRSH_IMM2(cond, r, rs, offs)
#define emith_read16s_r_r_r_c(cond, r, rs, rm) \
EOP_LDRSH_REG2(cond, r, rs, rm)
#define emith_read16s_r_r_offs(r, rs, offs) \
emith_read16s_r_r_offs_c(A_COND_AL, r, rs, offs)
EOP_LDRSH_IMM2(insn_cond, r, rs, offs)
#define emith_read16s_r_r_r(r, rs, rm) \
emith_read16s_r_r_r_c(A_COND_AL, r, rs, rm)
EOP_LDRSH_REG2(insn_cond, r, rs, rm)
#define emith_write_r_r_offs_c(cond, r, rs, offs) \
EOP_STR_IMM2(cond, r, rs, offs)
#define emith_write_r_r_offs_ptr_c(cond, r, rs, offs) \
emith_write_r_r_offs_c(cond, r, rs, offs)
#define emith_write_r_r_offs(r, rs, offs) \
emith_write_r_r_offs_c(A_COND_AL, r, rs, offs)
EOP_STR_IMM2(insn_cond, r, rs, offs)
#define emith_write_r_r_offs_ptr(r, rs, offs) \
emith_write_r_r_offs_c(A_COND_AL, r, rs, offs)
emith_write_r_r_offs(r, rs, offs)
#define emith_ctx_read_c(cond, r, offs) \
emith_read_r_r_offs_c(cond, r, CONTEXT_REG, offs)
#define emith_ctx_read(r, offs) \
emith_ctx_read_c(A_COND_AL, r, offs)
emith_read_r_r_offs(r, CONTEXT_REG, offs)
#define emith_ctx_read_ptr(r, offs) \
emith_ctx_read(r, offs)
@@ -1124,25 +1092,22 @@ static inline void emith_pool_adjust(int tcache_offs, int move_offs)
#define emith_ctx_write_multiple(r, offs, count, tmpr) \
emith_ctx_do_multiple(EOP_STMIA, r, offs, count, tmpr)
#define emith_clear_msb_c(cond, d, s, count) do { \
#define emith_clear_msb(d, s, count) do { \
u32 t; \
if ((count) <= 8) { \
t = 8 - (count); \
t = (0xff << t) & 0xff; \
EOP_C_DOP_IMM(cond,A_OP_BIC,0,s,d,8/2,t); \
EOP_C_DOP_IMM(insn_cond,A_OP_BIC,0,s,d,8/2,t); \
} else if ((count) >= 24) { \
t = (count) - 24; \
t = 0xff >> t; \
EOP_C_DOP_IMM(cond,A_OP_AND,0,s,d,0,t); \
EOP_C_DOP_IMM(insn_cond,A_OP_AND,0,s,d,0,t); \
} else { \
EOP_MOV_REG(cond,0,d,s,A_AM1_LSL,count); \
EOP_MOV_REG(cond,0,d,d,A_AM1_LSR,count); \
EOP_MOV_REG(insn_cond,0,d,s,A_AM1_LSL,count); \
EOP_MOV_REG(insn_cond,0,d,d,A_AM1_LSR,count); \
} \
} while (0)
#define emith_clear_msb(d, s, count) \
emith_clear_msb_c(A_COND_AL, d, s, count)
#define emith_sext(d, s, bits) do { \
EOP_MOV_REG_LSL(d,s,32 - (bits)); \
EOP_MOV_REG_ASR(d,d,32 - (bits)); \
@@ -1173,7 +1138,7 @@ static inline void emith_pool_adjust(int tcache_offs, int move_offs)
emith_move_r_imm(arg, imm)
#define emith_jump(target) \
emith_jump_cond(A_COND_AL, target)
emith_jump_cond(insn_cond, target)
#define emith_jump_patchable(target) \
emith_jump(target)
@@ -1197,31 +1162,25 @@ static inline void emith_pool_adjust(int tcache_offs, int move_offs)
#define emith_jump_at(ptr, target) do { \
u32 *ptr_ = (u32 *)ptr; \
u32 val_ = (u32 *)(target) - ptr_ - 2; \
EOP_C_B_PTR(ptr_, A_COND_AL, 0, val_ & 0xffffff); \
EOP_C_B_PTR(ptr_, insn_cond, 0, val_ & 0xffffff); \
} while (0)
#define emith_jump_at_size() 4
#define emith_jump_reg_c(cond, r) \
EOP_C_BX(cond, r)
#define emith_jump_reg(r) \
emith_jump_reg_c(A_COND_AL, r)
#define emith_jump_ctx_c(cond, offs) \
EOP_LDR_IMM2(cond,PC,CONTEXT_REG,offs)
EOP_C_BX(insn_cond, r)
#define emith_jump_ctx(offs) \
emith_jump_ctx_c(A_COND_AL, offs)
EOP_LDR_IMM2(insn_cond,PC,CONTEXT_REG,offs)
#define emith_call_cond(cond, target) \
emith_xbranch(cond, target, 1)
#define emith_call(target) \
emith_call_cond(A_COND_AL, target)
emith_call_cond(insn_cond, target)
#define emith_call_reg(r) do { \
emith_move_r_r(LR, PC); \
EOP_C_BX(A_COND_AL, r); \
EOP_C_BX(insn_cond, r); \
} while (0)
#define emith_abicall_ctx(offs) do { \
@@ -1231,8 +1190,6 @@ static inline void emith_pool_adjust(int tcache_offs, int move_offs)
#define emith_abijump_reg(r) \
emith_jump_reg(r)
#define emith_abijump_reg_c(cond, r) \
emith_jump_reg_c(cond, r)
#define emith_abicall(target) \
emith_call(target)
#define emith_abicall_cond(cond, target) \
@@ -1242,11 +1199,8 @@ static inline void emith_pool_adjust(int tcache_offs, int move_offs)
#define emith_call_cleanup() /**/
#define emith_ret_c(cond) \
emith_jump_reg_c(cond, LR)
#define emith_ret() \
emith_ret_c(A_COND_AL)
emith_jump_reg(LR)
#define emith_ret_to_ctx(offs) \
emith_ctx_write(LR, offs)
@@ -1421,7 +1375,7 @@ static inline void emith_pool_adjust(int tcache_offs, int move_offs)
#define emith_sh2_macl(ml, mh, rn, rm, sr) do { \
emith_tst_r_imm(sr, S); \
EMITH_SJMP2_START(DCOND_NE); \
emith_mula_s64_c(DCOND_EQ, ml, mh, rn, rm); \
emith_mula_s64(ml, mh, rn, rm); \
EMITH_SJMP2_MID(DCOND_NE); \
/* MACH top 16 bits unused if saturated. sign ext for overfl detect */ \
emith_sext(mh, mh, 16); \
@@ -1431,11 +1385,11 @@ static inline void emith_pool_adjust(int tcache_offs, int move_offs)
emith_asr(rn, mh, 15); \
emith_addf_r_r_r_lsr(rn, rn, mh, 31); \
EMITH_SJMP_START(DCOND_EQ); /* sum != 0 -> -ovl */ \
emith_move_r_imm_c(DCOND_NE, ml, 0x00000000); \
emith_move_r_imm_c(DCOND_NE, mh, 0x00008000); \
emith_move_r_imm(ml, 0x00000000); \
emith_move_r_imm(mh, 0x00008000); \
EMITH_SJMP_START(DCOND_MI); /* sum > 0 -> +ovl */ \
emith_sub_r_imm_c(DCOND_PL, ml, 1); /* 0xffffffff */ \
emith_sub_r_imm_c(DCOND_PL, mh, 1); /* 0x00007fff */ \
emith_sub_r_imm(ml, 1); /* 0xffffffff */ \
emith_sub_r_imm(mh, 1); /* 0x00007fff */ \
EMITH_SJMP_END(DCOND_MI); \
EMITH_SJMP_END(DCOND_EQ); \
EMITH_SJMP2_END(DCOND_NE); \
@@ -1445,7 +1399,7 @@ static inline void emith_pool_adjust(int tcache_offs, int move_offs)
#define emith_sh2_macw(ml, mh, rn, rm, sr) do { \
emith_tst_r_imm(sr, S); \
EMITH_SJMP2_START(DCOND_NE); \
emith_mula_s64_c(DCOND_EQ, ml, mh, rn, rm); \
emith_mula_s64(ml, mh, rn, rm); \
EMITH_SJMP2_MID(DCOND_NE); \
/* XXX: MACH should be untouched when S is set? */ \
emith_asr(mh, ml, 31); /* sign ext MACL to MACH for ovrfl check */ \
@@ -1455,10 +1409,10 @@ static inline void emith_pool_adjust(int tcache_offs, int move_offs)
emith_addf_r_r_r_lsr(mh, mh, ml, 31); /* sum = MACH + ((MACL>>31)&1) */\
EMITH_SJMP_START(DCOND_EQ); /* sum != 0 -> overflow */ \
/* XXX: LSB signalling only in SH1, or in SH2 too? */ \
emith_move_r_imm_c(DCOND_NE, mh, 0x00000001); /* LSB of MACH */ \
emith_move_r_imm_c(DCOND_NE, ml, 0x80000000); /* -ovrfl */ \
emith_move_r_imm(mh, 0x00000001); /* LSB of MACH */ \
emith_move_r_imm(ml, 0x80000000); /* -ovrfl */ \
EMITH_SJMP_START(DCOND_MI); /* sum > 0 -> +ovrfl */ \
emith_sub_r_imm_c(DCOND_PL, ml, 1); /* 0x7fffffff */ \
emith_sub_r_imm(ml, 1); /* 0x7fffffff */ \
EMITH_SJMP_END(DCOND_MI); \
EMITH_SJMP_END(DCOND_EQ); \
EMITH_SJMP2_END(DCOND_NE); \
+13 -83
View File
@@ -363,16 +363,16 @@ enum { AM_IDX, AM_IDXPOST, AM_IDXREG, AM_IDXPRE };
EMIT_PTR(ptr, A64_B(val_ & 0x0fffffff)); \
}
#define EMITH_JMP_START(cond) { \
u8 *cond_ptr; \
#define EMITH_JMP_START(cond) \
{ u8 *cond_ptr; \
JMP_POS(cond_ptr)
#define EMITH_JMP_END(cond) \
JMP_EMIT(cond, cond_ptr); \
}
#define EMITH_JMP3_START(cond) { \
u8 *cond_ptr, *else_ptr; \
#define EMITH_JMP3_START(cond) \
{ u8 *cond_ptr, *else_ptr; \
JMP_POS(cond_ptr)
#define EMITH_JMP3_MID(cond) \
@@ -405,13 +405,9 @@ enum { AM_IDX, AM_IDXPOST, AM_IDXREG, AM_IDXPRE };
// data processing, register
#define emith_move_r_r_ptr(d, s) \
EMIT(A64_MOVX_REG(d, s, ST_LSL, 0))
#define emith_move_r_r_ptr_c(cond, d, s) \
emith_move_r_r_ptr(d, s)
#define emith_move_r_r(d, s) \
EMIT(A64_MOV_REG(d, s, ST_LSL, 0))
#define emith_move_r_r_c(cond, d, s) \
emith_move_r_r(d, s)
#define emith_mvn_r_r(d, s) \
EMIT(A64_MVN_REG(d, s, ST_LSL, 0))
@@ -530,8 +526,6 @@ enum { AM_IDX, AM_IDXPOST, AM_IDXREG, AM_IDXPRE };
#define emith_and_r_r(d, s) \
emith_and_r_r_r(d, d, s)
#define emith_and_r_r_c(cond, d, s) \
emith_and_r_r(d, s)
#define emith_or_r_r(d, s) \
emith_or_r_r_r(d, d, s)
@@ -598,8 +592,6 @@ static void emith_move_imm64(int r, int wx, int64_t imm)
#define emith_move_r_imm(r, imm) \
emith_move_imm64(r, 0, (s32)(imm))
#define emith_move_r_imm_c(cond, r, imm) \
emith_move_r_imm(r, imm)
#define emith_move_r_imm_s8_patchable(r, imm) do { \
if ((s8)(imm) < 0) \
@@ -648,16 +640,12 @@ static void emith_arith_imm(int op, int wx, int rd, int rn, s32 imm)
#define emith_add_r_imm(r, imm) \
emith_arith_imm(OP_ADD, 0, r, r, imm)
#define emith_add_r_imm_c(cond, r, imm) \
emith_add_r_imm(r, imm)
#define emith_addf_r_imm(r, imm) \
emith_arith_imm(OP_ADDS, 0, r, r, imm)
#define emith_sub_r_imm(r, imm) \
emith_arith_imm(OP_SUB, 0, r, r, imm)
#define emith_sub_r_imm_c(cond, r, imm) \
emith_sub_r_imm(r, imm)
#define emith_subf_r_imm(r, imm) \
emith_arith_imm(OP_SUBS, 0, r, r, imm)
@@ -695,8 +683,6 @@ static void emith_arith_imm(int op, int wx, int rd, int rn, s32 imm)
#define emith_sub_r_r_imm(d, s, imm) \
emith_arith_imm(OP_SUB, 0, d, s, imm)
#define emith_sub_r_r_imm_c(cond, d, s, imm) \
emith_sub_r_r_imm(d, s, imm)
#define emith_subf_r_r_imm(d, s, imm) \
emith_arith_imm(OP_SUBS, 0, d, s, imm)
@@ -748,29 +734,19 @@ static void emith_log_imm(int op, int wx, int rd, int rn, u32 imm)
#define emith_or_r_imm(r, imm) \
emith_log_imm(OP_OR, 0, r, r, imm)
#define emith_or_r_imm_c(cond, r, imm) \
emith_or_r_imm(r, imm)
#define emith_eor_r_imm_ptr(r, imm) \
emith_log_imm(OP_EOR, 1, r, r, imm)
#define emith_eor_r_imm_ptr_c(cond, r, imm) \
emith_eor_r_imm_ptr(r, imm)
#define emith_eor_r_imm(r, imm) \
emith_log_imm(OP_EOR, 0, r, r, imm)
#define emith_eor_r_imm_c(cond, r, imm) \
emith_eor_r_imm(r, imm)
/* NB: BIC #imm not available in A64; use AND #~imm instead */
#define emith_bic_r_imm(r, imm) \
emith_log_imm(OP_AND, 0, r, r, ~(imm))
#define emith_bic_r_imm_c(cond, r, imm) \
emith_bic_r_imm(r, imm)
#define emith_tst_r_imm(r, imm) \
emith_log_imm(OP_ANDS, 0, Z0, r, imm)
#define emith_tst_r_imm_c(cond, r, imm) \
emith_tst_r_imm(r, imm)
#define emith_and_r_r_imm(d, s, imm) \
emith_log_imm(OP_AND, 0, d, s, imm)
@@ -794,8 +770,6 @@ static void emith_log_imm(int op, int wx, int rd, int rn, u32 imm)
#define emith_ror(d, s, cnt) \
EMIT(A64_ROR_IMM(d, s, cnt))
#define emith_ror_c(cond, d, s, cnt) \
emith_ror(d, s, cnt)
#define emith_rol(d, s, cnt) \
EMIT(A64_ROR_IMM(d, s, 32-(cnt)))
@@ -867,8 +841,6 @@ static void emith_log_imm(int op, int wx, int rd, int rn, u32 imm)
// signed/unsigned extend
#define emith_clear_msb(d, s, count) /* bits to clear */ \
EMIT(A64_UXT_IMM(d, s, 32-(count)))
#define emith_clear_msb_c(cond, d, s, count) \
emith_clear_msb(d, s, count)
#define emith_sext(d, s, count) /* bits to keep */ \
EMIT(A64_SXT_IMM(d, s, count))
@@ -901,8 +873,6 @@ static void emith_log_imm(int op, int wx, int rd, int rn, u32 imm)
EMIT(A64_SMADDL(dlo, s1, s2, dlo)); \
emith_split64(dlo, dhi); \
} while (0)
#define emith_mula_s64_c(cond, dlo, dhi, s1, s2) \
emith_mula_s64(dlo, dhi, s1, s2)
// load/store. offs has 9 bits signed, hence larger offs may use a temp
static void emith_ldst_offs(int sz, int rd, int rn, int o9, int ld, int mode)
@@ -925,90 +895,58 @@ static void emith_ldst_offs(int sz, int rd, int rn, int o9, int ld, int mode)
#define emith_read_r_r_offs_ptr(r, rs, offs) \
emith_ldst_offs(AM_X, r, rs, offs, LT_LD, AM_IDX)
#define emith_read_r_r_offs_ptr_c(cond, r, rs, offs) \
emith_read_r_r_offs_ptr(r, rs, offs)
#define emith_read_r_r_offs(r, rs, offs) \
emith_ldst_offs(AM_W, r, rs, offs, LT_LD, AM_IDX)
#define emith_read_r_r_offs_c(cond, r, rs, offs) \
emith_read_r_r_offs(r, rs, offs)
#define emith_read_r_r_r_ptr(r, rs, rm) \
EMIT(A64_LDSTX_REG(r, rs, rm, LT_LD, XT_SXTW))
#define emith_read_r_r_r(r, rs, rm) \
EMIT(A64_LDST_REG(r, rs, rm, LT_LD, XT_SXTW))
#define emith_read_r_r_r_c(cond, r, rs, rm) \
emith_read_r_r_r(r, rs, rm)
#define emith_read8_r_r_offs(r, rs, offs) \
emith_ldst_offs(AM_B, r, rs, offs, LT_LD, AM_IDX)
#define emith_read8_r_r_offs_c(cond, r, rs, offs) \
emith_read8_r_r_offs(r, rs, offs)
#define emith_read8_r_r_r(r, rs, rm) \
EMIT(A64_LDSTB_REG(r, rs, rm, LT_LD, XT_SXTW))
#define emith_read8_r_r_r_c(cond, r, rs, rm) \
emith_read8_r_r_r(r, rs, rm)
#define emith_read16_r_r_offs(r, rs, offs) \
emith_ldst_offs(AM_H, r, rs, offs, LT_LD, AM_IDX)
#define emith_read16_r_r_offs_c(cond, r, rs, offs) \
emith_read16_r_r_offs(r, rs, offs)
#define emith_read16_r_r_r(r, rs, rm) \
EMIT(A64_LDSTH_REG(r, rs, rm, LT_LD, XT_SXTW))
#define emith_read16_r_r_r_c(cond, r, rs, rm) \
emith_read16_r_r_r(r, rs, rm)
#define emith_read8s_r_r_offs(r, rs, offs) \
emith_ldst_offs(AM_B, r, rs, offs, LT_LDS, AM_IDX)
#define emith_read8s_r_r_offs_c(cond, r, rs, offs) \
emith_read8s_r_r_offs(r, rs, offs)
#define emith_read8s_r_r_r(r, rs, rm) \
EMIT(A64_LDSTB_REG(r, rs, rm, LT_LDS, XT_SXTW))
#define emith_read8s_r_r_r_c(cond, r, rs, rm) \
emith_read8s_r_r_r(r, rs, rm)
#define emith_read16s_r_r_offs(r, rs, offs) \
emith_ldst_offs(AM_H, r, rs, offs, LT_LDS, AM_IDX)
#define emith_read16s_r_r_offs_c(cond, r, rs, offs) \
emith_read16s_r_r_offs(r, rs, offs)
#define emith_read16s_r_r_r(r, rs, rm) \
EMIT(A64_LDSTH_REG(r, rs, rm, LT_LDS, XT_SXTW))
#define emith_read16s_r_r_r_c(cond, r, rs, rm) \
emith_read16s_r_r_r(r, rs, rm)
#define emith_write_r_r_offs_ptr(r, rs, offs) \
emith_ldst_offs(AM_X, r, rs, offs, LT_ST, AM_IDX)
#define emith_write_r_r_offs_ptr_c(cond, r, rs, offs) \
emith_write_r_r_offs_ptr(r, rs, offs)
#define emith_write_r_r_r_ptr(r, rs, rm) \
EMIT(A64_LDSTX_REG(r, rs, rm, LT_ST, XT_SXTW))
#define emith_write_r_r_r_ptr_c(cond, r, rs, rm) \
emith_write_r_r_r_ptr(r, rs, rm)
#define emith_write_r_r_offs(r, rs, offs) \
emith_ldst_offs(AM_W, r, rs, offs, LT_ST, AM_IDX)
#define emith_write_r_r_offs_c(cond, r, rs, offs) \
emith_write_r_r_offs(r, rs, offs)
#define emith_write_r_r_r(r, rs, rm) \
EMIT(A64_LDST_REG(r, rs, rm, LT_ST, XT_SXTW))
#define emith_write_r_r_r_c(cond, r, rs, rm) \
emith_write_r_r_r(r, rs, rm)
#define emith_ctx_read_ptr(r, offs) \
emith_read_r_r_offs_ptr(r, CONTEXT_REG, offs)
#define emith_ctx_read(r, offs) \
emith_read_r_r_offs(r, CONTEXT_REG, offs)
#define emith_ctx_read_c(cond, r, offs) \
emith_ctx_read(r, offs)
#define emith_ctx_write_ptr(r, offs) \
emith_write_r_r_offs_ptr(r, CONTEXT_REG, offs)
@@ -1117,8 +1055,6 @@ static void emith_ldst_offs(int sz, int rd, int rn, int o9, int ld, int mode)
#define emith_jump_reg(r) \
EMIT(A64_BR(r))
#define emith_jump_reg_c(cond, r) \
emith_jump_reg(r)
#define emith_jump_ctx(offs) do { \
int _t = rcache_get_tmp(); \
@@ -1126,8 +1062,6 @@ static void emith_ldst_offs(int sz, int rd, int rn, int o9, int ld, int mode)
emith_jump_reg(_t); \
rcache_free_tmp(_t); \
} while (0)
#define emith_jump_ctx_c(cond, offs) \
emith_jump_ctx(offs)
#define emith_call(target) do { \
u32 disp_ = (u8 *)target - (u8 *)tcache_ptr; \
@@ -1148,8 +1082,6 @@ static void emith_ldst_offs(int sz, int rd, int rn, int o9, int ld, int mode)
#define emith_abijump_reg(r) \
emith_jump_reg(r)
#define emith_abijump_reg_c(cond, r) \
emith_abijump_reg(r)
#define emith_abicall(target) \
emith_call(target)
#define emith_abicall_cond(cond, target) \
@@ -1161,8 +1093,6 @@ static void emith_ldst_offs(int sz, int rd, int rn, int o9, int ld, int mode)
#define emith_ret() \
EMIT(A64_RET(LR))
#define emith_ret_c(cond) \
emith_ret()
#define emith_ret_to_ctx(offs) \
emith_ctx_write_ptr(LR, offs)
@@ -1250,12 +1180,12 @@ static void emith_ldst_offs(int sz, int rd, int rn, int o9, int ld, int mode)
t3 = rcache_get_reg(reg, RC_GR_RMW, NULL); \
emith_cmp_r_r(t3, t2); \
EMITH_SJMP_START(DCOND_HI); \
emith_sub_r_r_imm_c(DCOND_LS, t2, t3, 1); \
emith_sub_r_r_imm(t2, t3, 1); \
EMITH_SJMP_END(DCOND_HI); \
/* if (reg <= 1) turns = 0 */ \
emith_cmp_r_imm(t3, 1); \
EMITH_SJMP_START(DCOND_HI); \
emith_move_r_imm_c(DCOND_LS, t2, 0); \
emith_move_r_imm(t2, 0); \
EMITH_SJMP_END(DCOND_HI); \
/* reg -= turns */ \
emith_sub_r_r(t3, t2); \
@@ -1310,11 +1240,11 @@ static void emith_ldst_offs(int sz, int rd, int rn, int o9, int ld, int mode)
emith_asr(rn, mh, 15); \
emith_addf_r_r_r_lsr(rn, rn, mh, 31); \
EMITH_SJMP_START(DCOND_EQ); /* sum != 0 -> -ovl */ \
emith_move_r_imm_c(DCOND_NE, ml, 0x00000000); \
emith_move_r_imm_c(DCOND_NE, mh, 0x00008000); \
emith_move_r_imm(ml, 0x00000000); \
emith_move_r_imm(mh, 0x00008000); \
EMITH_SJMP_START(DCOND_MI); /* sum > 0 -> +ovl */ \
emith_sub_r_imm_c(DCOND_PL, ml, 1); /* 0xffffffff */ \
emith_sub_r_imm_c(DCOND_PL, mh, 1); /* 0x00007fff */ \
emith_sub_r_imm(ml, 1); /* 0xffffffff */ \
emith_sub_r_imm(mh, 1); /* 0x00007fff */ \
EMITH_SJMP_END(DCOND_MI); \
EMITH_SJMP_END(DCOND_EQ); \
EMITH_SJMP_END(DCOND_EQ); \
@@ -1335,10 +1265,10 @@ static void emith_ldst_offs(int sz, int rd, int rn, int o9, int ld, int mode)
emith_addf_r_r_r_lsr(rn, mh, ml, 31); /* sum = MACH + (MACL>>31) */ \
EMITH_SJMP_START(DCOND_EQ); /* sum != 0 -> overflow */ \
/* XXX: LSB signalling only in SH1, or in SH2 too? */ \
emith_move_r_imm_c(DCOND_NE, mh, 0x00000001); /* LSB of MACH */ \
emith_move_r_imm_c(DCOND_NE, ml, 0x80000000); /* -ovrfl */ \
emith_move_r_imm(mh, 0x00000001); /* LSB of MACH */ \
emith_move_r_imm(ml, 0x80000000); /* -ovrfl */ \
EMITH_SJMP_START(DCOND_MI); /* sum > 0 -> +ovrfl */ \
emith_sub_r_imm_c(DCOND_PL, ml, 1); /* 0x7fffffff */ \
emith_sub_r_imm(ml, 1); /* 0x7fffffff */ \
EMITH_SJMP_END(DCOND_MI); \
EMITH_SJMP_END(DCOND_EQ); \
EMITH_SJMP_END(DCOND_EQ); \
+13 -83
View File
@@ -462,8 +462,8 @@ static void *emith_branch(u32 op)
EMIT_PTR(ptr, MIPS_B(val_ & 0x0003ffff)); \
}
#define EMITH_JMP_START(cond) { \
int cond_r, cond_m = emith_cond_check(cond, &cond_r); \
#define EMITH_JMP_START(cond) \
{ int cond_r, cond_m = emith_cond_check(cond, &cond_r); \
u8 *cond_ptr; \
JMP_POS(cond_ptr)
@@ -471,8 +471,8 @@ static void *emith_branch(u32 op)
JMP_EMIT(cond, cond_ptr); \
}
#define EMITH_JMP3_START(cond) { \
int cond_r, cond_m = emith_cond_check(cond, &cond_r); \
#define EMITH_JMP3_START(cond) \
{ int cond_r, cond_m = emith_cond_check(cond, &cond_r); \
u8 *cond_ptr, *else_ptr; \
JMP_POS(cond_ptr)
@@ -567,13 +567,9 @@ static void emith_set_compare_flags(int rs, int rt, s32 imm)
// data processing, register
#define emith_move_r_r_ptr(d, s) \
EMIT(MIPS_MOVE_REG(d, s))
#define emith_move_r_r_ptr_c(cond, d, s) \
emith_move_r_r_ptr(d, s)
#define emith_move_r_r(d, s) \
emith_move_r_r_ptr(d, s)
#define emith_move_r_r_c(cond, d, s) \
emith_move_r_r(d, s)
#define emith_mvn_r_r(d, s) \
EMIT(MIPS_MVN_REG(d, s))
@@ -765,8 +761,6 @@ static void emith_set_compare_flags(int rs, int rt, s32 imm)
#define emith_and_r_r(d, s) \
emith_and_r_r_r(d, d, s)
#define emith_and_r_r_c(cond, d, s) \
emith_and_r_r(d, s)
#define emith_or_r_r(d, s) \
emith_or_r_r_r(d, d, s)
@@ -918,8 +912,6 @@ static void emith_move_ptr_imm(int r, uintptr_t imm)
#define emith_move_r_imm(r, imm) \
emith_move_imm(r, (s32)(imm))
#define emith_move_r_imm_c(cond, r, imm) \
emith_move_r_imm(r, imm)
#define emith_move_r_imm_s8_patchable(r, imm) \
EMIT(MIPS_ADD_IMM(r, Z0, (s8)(imm)))
@@ -946,16 +938,12 @@ static void emith_add_imm(int ptr, int rd, int rs, u32 imm)
#define emith_add_r_imm(r, imm) \
emith_add_r_r_imm(r, r, imm)
#define emith_add_r_imm_c(cond, r, imm) \
emith_add_r_imm(r, imm)
#define emith_addf_r_imm(r, imm) \
emith_addf_r_r_imm(r, imm)
#define emith_sub_r_imm(r, imm) \
emith_sub_r_r_imm(r, r, imm)
#define emith_sub_r_imm_c(cond, r, imm) \
emith_sub_r_imm(r, imm)
#define emith_subf_r_imm(r, imm) \
emith_subf_r_r_imm(r, r, imm)
@@ -1002,8 +990,6 @@ static void emith_add_imm(int ptr, int rd, int rs, u32 imm)
// NB: no SUBI in MIPS II, since ADDI takes a signed imm
#define emith_sub_r_r_imm(d, s, imm) \
emith_add_r_r_imm(d, s, -(imm))
#define emith_sub_r_r_imm_c(cond, d, s, imm) \
emith_sub_r_r_imm(d, s, imm)
#define emith_subf_r_r_imm(d, s, imm) do { \
emith_sub_r_r_imm(FNZ, s, imm); \
@@ -1025,31 +1011,21 @@ static void emith_log_imm(int op, int rd, int rs, u32 imm)
#define emith_or_r_imm(r, imm) \
emith_log_imm(OP_ORI, r, r, imm)
#define emith_or_r_imm_c(cond, r, imm) \
emith_or_r_imm(r, imm)
#define emith_eor_r_imm_ptr(r, imm) \
emith_log_imm(OP_XORI, r, r, imm)
#define emith_eor_r_imm_ptr_c(cond, r, imm) \
emith_eor_r_imm_ptr(r, imm)
#define emith_eor_r_imm(r, imm) \
emith_eor_r_imm_ptr(r, imm)
#define emith_eor_r_imm_c(cond, r, imm) \
emith_eor_r_imm(r, imm)
/* NB: BIC #imm not available in MIPS; use AND #~imm instead */
#define emith_bic_r_imm(r, imm) \
emith_log_imm(OP_ANDI, r, r, ~(imm))
#define emith_bic_r_imm_c(cond, r, imm) \
emith_bic_r_imm(r, imm)
#define emith_tst_r_imm(r, imm) do { \
emith_log_imm(OP_ANDI, FNZ, r, imm); \
emith_cmp_rs = emith_cmp_rt = -1; \
} while (0)
#define emith_tst_r_imm_c(cond, r, imm) \
emith_tst_r_imm(r, imm)
#define emith_and_r_r_imm(d, s, imm) \
emith_log_imm(OP_ANDI, d, s, imm)
@@ -1077,8 +1053,6 @@ static void emith_log_imm(int op, int rd, int rs, u32 imm)
EMIT(MIPS_OR_REG(d, d, AT)); \
} else EMIT(MIPS_ROR_IMM(d, s, cnt)); \
} while (0)
#define emith_ror_c(cond, d, s, cnt) \
emith_ror(d, s, cnt)
#define emith_rol(d, s, cnt) do { \
if (__mips_isa_rev < 2) { \
@@ -1189,8 +1163,6 @@ static void emith_log_imm(int op, int rd, int rs, u32 imm)
emith_lsr(d, d, count); \
} \
} while (0)
#define emith_clear_msb_c(cond, d, s, count) \
emith_clear_msb(d, s, count)
#define emith_sext(d, s, count) /* bits to keep */ do { \
if (__mips_isa_rev >= 2 && count == 8) \
@@ -1247,19 +1219,13 @@ static void emith_lohi_nops(void)
emith_add_r_r(dhi, t_); \
rcache_free_tmp(t_); \
} while (0)
#define emith_mula_s64_c(cond, dlo, dhi, s1, s2) \
emith_mula_s64(dlo, dhi, s1, s2)
// load/store. offs has 16 bits signed, which is currently sufficient
#define emith_read_r_r_offs_ptr(r, rs, offs) \
EMIT(MIPS_OP_IMM(OP_LP, r, rs, offs))
#define emith_read_r_r_offs_ptr_c(cond, r, rs, offs) \
emith_read_r_r_offs_ptr(r, rs, offs)
#define emith_read_r_r_offs(r, rs, offs) \
EMIT(MIPS_LW(r, rs, offs))
#define emith_read_r_r_offs_c(cond, r, rs, offs) \
emith_read_r_r_offs(r, rs, offs)
#define emith_read_r_r_r_ptr(r, rs, rm) do { \
emith_add_r_r_r_ptr(AT, rs, rm); \
@@ -1270,89 +1236,61 @@ static void emith_lohi_nops(void)
emith_add_r_r_r_ptr(AT, rs, rm); \
EMIT(MIPS_LW(r, AT, 0)); \
} while (0)
#define emith_read_r_r_r_c(cond, r, rs, rm) \
emith_read_r_r_r(r, rs, rm)
#define emith_read8_r_r_offs(r, rs, offs) \
EMIT(MIPS_LBU(r, rs, offs))
#define emith_read8_r_r_offs_c(cond, r, rs, offs) \
emith_read8_r_r_offs(r, rs, offs)
#define emith_read8_r_r_r(r, rs, rm) do { \
emith_add_r_r_r_ptr(AT, rs, rm); \
EMIT(MIPS_LBU(r, AT, 0)); \
} while (0)
#define emith_read8_r_r_r_c(cond, r, rs, rm) \
emith_read8_r_r_r(r, rs, rm)
#define emith_read16_r_r_offs(r, rs, offs) \
EMIT(MIPS_LHU(r, rs, offs))
#define emith_read16_r_r_offs_c(cond, r, rs, offs) \
emith_read16_r_r_offs(r, rs, offs)
#define emith_read16_r_r_r(r, rs, rm) do { \
emith_add_r_r_r_ptr(AT, rs, rm); \
EMIT(MIPS_LHU(r, AT, 0)); \
} while (0)
#define emith_read16_r_r_r_c(cond, r, rs, rm) \
emith_read16_r_r_r(r, rs, rm)
#define emith_read8s_r_r_offs(r, rs, offs) \
EMIT(MIPS_LB(r, rs, offs))
#define emith_read8s_r_r_offs_c(cond, r, rs, offs) \
emith_read8s_r_r_offs(r, rs, offs)
#define emith_read8s_r_r_r(r, rs, rm) do { \
emith_add_r_r_r_ptr(AT, rs, rm); \
EMIT(MIPS_LB(r, AT, 0)); \
} while (0)
#define emith_read8s_r_r_r_c(cond, r, rs, rm) \
emith_read8s_r_r_r(r, rs, rm)
#define emith_read16s_r_r_offs(r, rs, offs) \
EMIT(MIPS_LH(r, rs, offs))
#define emith_read16s_r_r_offs_c(cond, r, rs, offs) \
emith_read16s_r_r_offs(r, rs, offs)
#define emith_read16s_r_r_r(r, rs, rm) do { \
emith_add_r_r_r_ptr(AT, rs, rm); \
EMIT(MIPS_LH(r, AT, 0)); \
} while (0)
#define emith_read16s_r_r_r_c(cond, r, rs, rm) \
emith_read16s_r_r_r(r, rs, rm)
#define emith_write_r_r_offs_ptr(r, rs, offs) \
EMIT(MIPS_OP_IMM(OP_SP, r, rs, offs))
#define emith_write_r_r_offs_ptr_c(cond, r, rs, offs) \
emith_write_r_r_offs_ptr(r, rs, offs)
#define emith_write_r_r_r_ptr(r, rs, rm) do { \
emith_add_r_r_r_ptr(AT, rs, rm); \
EMIT(MIPS_OP_IMM(OP_SP, r, AT, 0)); \
} while (0)
#define emith_write_r_r_r_ptr_c(cond, r, rs, rm) \
emith_write_r_r_r_ptr(r, rs, rm)
#define emith_write_r_r_offs(r, rs, offs) \
EMIT(MIPS_SW(r, rs, offs))
#define emith_write_r_r_offs_c(cond, r, rs, offs) \
emith_write_r_r_offs(r, rs, offs)
#define emith_write_r_r_r(r, rs, rm) do { \
emith_add_r_r_r_ptr(AT, rs, rm); \
EMIT(MIPS_SW(r, AT, 0)); \
} while (0)
#define emith_write_r_r_r_c(cond, r, rs, rm) \
emith_write_r_r_r(r, rs, rm)
#define emith_ctx_read_ptr(r, offs) \
emith_read_r_r_offs_ptr(r, CONTEXT_REG, offs)
#define emith_ctx_read(r, offs) \
emith_read_r_r_offs(r, CONTEXT_REG, offs)
#define emith_ctx_read_c(cond, r, offs) \
emith_ctx_read(r, offs)
#define emith_ctx_write_ptr(r, offs) \
emith_write_r_r_offs_ptr(r, CONTEXT_REG, offs)
@@ -1588,15 +1526,11 @@ static int emith_cond_check(int cond, int *r)
#define emith_jump_reg(r) \
emith_branch(MIPS_JR(r))
#define emith_jump_reg_c(cond, r) \
emith_jump_reg(r)
#define emith_jump_ctx(offs) do { \
emith_ctx_read_ptr(CR, offs); \
emith_jump_reg(CR); \
} while (0)
#define emith_jump_ctx_c(cond, offs) \
emith_jump_ctx(offs)
#define emith_call(target) \
emith_branch(MIPS_JAL((uintptr_t)target & 0x0fffffff))
@@ -1614,8 +1548,6 @@ static int emith_cond_check(int cond, int *r)
if ((r) != CR) emith_move_r_r(CR, r); \
emith_branch(MIPS_JR(CR)); \
} while (0)
#define emith_abijump_reg_c(cond, r) \
emith_abijump_reg(r)
#define emith_abicall(target) do { \
emith_move_r_ptr_imm(CR, target); \
emith_branch(MIPS_JALR(LR, CR)); \
@@ -1631,8 +1563,6 @@ static int emith_cond_check(int cond, int *r)
#define emith_ret() \
emith_branch(MIPS_JR(LR))
#define emith_ret_c(cond) \
emith_ret()
#define emith_ret_to_ctx(offs) \
emith_ctx_write_ptr(LR, offs)
@@ -1752,12 +1682,12 @@ static NOINLINE void host_instructions_updated(void *base, void *end, int force)
t3 = rcache_get_reg(reg, RC_GR_RMW, NULL); \
emith_cmp_r_r(t3, t2); \
EMITH_SJMP_START(DCOND_HI); \
emith_sub_r_r_imm_c(DCOND_LS, t2, t3, 1); \
emith_sub_r_r_imm(t2, t3, 1); \
EMITH_SJMP_END(DCOND_HI); \
/* if (reg <= 1) turns = 0 */ \
emith_cmp_r_imm(t3, 1); \
EMITH_SJMP_START(DCOND_HI); \
emith_move_r_imm_c(DCOND_LS, t2, 0); \
emith_move_r_imm(t2, 0); \
EMITH_SJMP_END(DCOND_HI); \
/* reg -= turns */ \
emith_sub_r_r(t3, t2); \
@@ -1815,11 +1745,11 @@ static NOINLINE void host_instructions_updated(void *base, void *end, int force)
emith_add_r_r_r_lsr(rn, rn, mh, 31); /* sum = (MACH>>31)+(MACH>>15) */ \
emith_teq_r_r(rn, Z0); /* (need only N and Z flags) */ \
EMITH_SJMP_START(DCOND_EQ); /* sum != 0 -> -ovl */ \
emith_move_r_imm_c(DCOND_NE, ml, 0x00000000); \
emith_move_r_imm_c(DCOND_NE, mh, 0x00008000); \
emith_move_r_imm(ml, 0x00000000); \
emith_move_r_imm(mh, 0x00008000); \
EMITH_SJMP_START(DCOND_MI); /* sum > 0 -> +ovl */ \
emith_sub_r_imm_c(DCOND_PL, ml, 1); /* 0xffffffff */ \
emith_sub_r_imm_c(DCOND_PL, mh, 1); /* 0x00007fff */ \
emith_sub_r_imm(ml, 1); /* 0xffffffff */ \
emith_sub_r_imm(mh, 1); /* 0x00007fff */ \
EMITH_SJMP_END(DCOND_MI); \
EMITH_SJMP_END(DCOND_EQ); \
EMITH_SJMP_END(DCOND_EQ); \
@@ -1842,10 +1772,10 @@ static NOINLINE void host_instructions_updated(void *base, void *end, int force)
emith_teq_r_r(rn, Z0); /* (need only N and Z flags) */ \
EMITH_SJMP_START(DCOND_EQ); /* sum != 0 -> overflow */ \
/* XXX: LSB signalling only in SH1, or in SH2 too? */ \
emith_move_r_imm_c(DCOND_NE, mh, 0x00000001); /* LSB of MACH */ \
emith_move_r_imm_c(DCOND_NE, ml, 0x80000000); /* -ovrfl */ \
emith_move_r_imm(mh, 0x00000001); /* LSB of MACH */ \
emith_move_r_imm(ml, 0x80000000); /* -ovrfl */ \
EMITH_SJMP_START(DCOND_MI); /* sum < 0 -> +ovrfl */ \
emith_sub_r_imm_c(DCOND_PL, ml, 1); /* 0x7fffffff */ \
emith_sub_r_imm(ml, 1); /* 0x7fffffff */ \
EMITH_SJMP_END(DCOND_MI); \
EMITH_SJMP_END(DCOND_EQ); \
EMITH_SJMP_END(DCOND_EQ); \
+13 -83
View File
@@ -510,8 +510,8 @@ enum { OPS_STD, OPS_STDU /*,OPS_STQ*/ };
EMIT_PTR(ptr, PPC_B(val_ & 0x03ffffffc)); \
}
#define EMITH_JMP_START(cond) { \
int cond_m = emith_cond_check(cond); \
#define EMITH_JMP_START(cond) \
{ int cond_m = emith_cond_check(cond); \
u8 *cond_ptr; \
JMP_POS(cond_ptr)
@@ -519,8 +519,8 @@ enum { OPS_STD, OPS_STDU /*,OPS_STQ*/ };
JMP_EMIT(cond, cond_ptr); \
}
#define EMITH_JMP3_START(cond) { \
int cond_m = emith_cond_check(cond); \
#define EMITH_JMP3_START(cond) \
{ int cond_m = emith_cond_check(cond); \
u8 *cond_ptr, *else_ptr; \
JMP_POS(cond_ptr)
@@ -616,13 +616,9 @@ static void emith_set_compare_flags(int ra, int rb, s32 imm)
#define emith_move_r_r_ptr(d, s) \
EMIT(PPC_MOV_REG(d, s))
#define emith_move_r_r_ptr_c(cond, d, s) \
emith_move_r_r_ptr(d, s)
#define emith_move_r_r(d, s) \
emith_move_r_r_ptr(d, s)
#define emith_move_r_r_c(cond, d, s) \
emith_move_r_r(d, s)
#define emith_mvn_r_r(d, s) \
EMIT(PPC_MVN_REG(d, s))
@@ -810,8 +806,6 @@ static void emith_set_compare_flags(int ra, int rb, s32 imm)
#define emith_and_r_r(d, s) \
emith_and_r_r_r(d, d, s)
#define emith_and_r_r_c(cond, d, s) \
emith_and_r_r(d, s)
#define emith_or_r_r(d, s) \
emith_or_r_r_r(d, d, s)
@@ -884,8 +878,6 @@ static void emith_move_imm(int r, int ptr, uintptr_t imm)
#define emith_move_r_imm(r, imm) \
emith_move_imm(r, 0, (u32)(imm))
#define emith_move_r_imm_c(cond, r, imm) \
emith_move_r_imm(r, imm)
#define emith_move_r_imm_s8_patchable(r, imm) \
EMIT(PPC_ADD_IMM(r, Z0, (s8)(imm)))
@@ -911,16 +903,12 @@ static void emith_add_imm(int rt, int ra, u32 imm)
#define emith_add_r_imm(r, imm) \
emith_add_r_r_imm(r, r, imm)
#define emith_add_r_imm_c(cond, r, imm) \
emith_add_r_imm(r, imm)
#define emith_addf_r_imm(r, imm) \
emith_addf_r_r_imm(r, imm)
#define emith_sub_r_imm(r, imm) \
emith_sub_r_r_imm(r, r, imm)
#define emith_sub_r_imm_c(cond, r, imm) \
emith_sub_r_imm(r, imm)
#define emith_subf_r_imm(r, imm) \
emith_subf_r_r_imm(r, r, imm)
@@ -968,8 +956,6 @@ static void emith_add_imm(int rt, int ra, u32 imm)
// NB: no SUBI, since ADDI takes a signed imm
#define emith_sub_r_r_imm(d, s, imm) \
emith_add_r_r_imm(d, s, -(imm))
#define emith_sub_r_r_imm_c(cond, d, s, imm) \
emith_sub_r_r_imm(d, s, imm)
#define emith_subf_r_r_imm(d, s, imm) do { \
emith_sub_r_r_imm(FNZ, s, imm); \
@@ -993,31 +979,21 @@ static void emith_add_imm(int rt, int ra, u32 imm)
#define emith_or_r_imm(r, imm) \
emith_log_imm(OR, r, r, imm)
#define emith_or_r_imm_c(cond, r, imm) \
emith_or_r_imm(r, imm)
#define emith_eor_r_imm_ptr(r, imm) \
emith_log_imm(XOR, r, r, imm)
#define emith_eor_r_imm_ptr_c(cond, r, imm) \
emith_eor_r_imm_ptr(r, imm)
#define emith_eor_r_imm(r, imm) \
emith_eor_r_imm_ptr(r, imm)
#define emith_eor_r_imm_c(cond, r, imm) \
emith_eor_r_imm(r, imm)
/* NB: BIC #imm not available; use AND #~imm instead */
#define emith_bic_r_imm(r, imm) \
emith_log_imm(AND, r, r, ~(imm))
#define emith_bic_r_imm_c(cond, r, imm) \
emith_bic_r_imm(r, imm)
#define emith_tst_r_imm(r, imm) do { \
emith_log_imm(AND, FNZ, r, imm); \
emith_cmp_ra = emith_cmp_rb = -1; \
} while (0)
#define emith_tst_r_imm_c(cond, r, imm) \
emith_tst_r_imm(r, imm)
#define emith_and_r_r_imm(d, s, imm) \
emith_log_imm(AND, d, s, imm)
@@ -1041,8 +1017,6 @@ static void emith_add_imm(int rt, int ra, u32 imm)
#define emith_ror(d, s, cnt) \
EMIT(PPC_ROLW_IMM(d, s, 32-(cnt)))
#define emith_ror_c(cond, d, s, cnt) \
emith_ror(d, s, cnt)
#define emith_rol(d, s, cnt) \
EMIT(PPC_ROLW_IMM(d, s, cnt)); \
@@ -1139,8 +1113,6 @@ static void emith_add_imm(int rt, int ra, u32 imm)
#define emith_clear_msb(d, s, count) /* bits to clear */ \
EMIT(PPC_BFXW_IMM(d, s, count, 32-(count)))
#define emith_clear_msb_c(cond, d, s, count) \
emith_clear_msb(d, s, count)
#define emith_sext(d, s, count) /* bits to keep */ do { \
if (count == 8) \
@@ -1166,104 +1138,70 @@ static void emith_add_imm(int rt, int ra, u32 imm)
#define emith_mula_s64(dlo, dhi, s1, s2) \
EMIT_PPC_MACLS_REG(dlo, dhi, s1, s2)
#define emith_mula_s64_c(cond, dlo, dhi, s1, s2) \
emith_mula_s64(dlo, dhi, s1, s2)
// load/store. offs has 16 bits signed, which is currently sufficient
#define emith_read_r_r_offs_ptr(r, ra, offs) \
EMIT(PPC_LDP_IMM(r, ra, offs))
#define emith_read_r_r_offs_ptr_c(cond, r, ra, offs) \
emith_read_r_r_offs_ptr(r, ra, offs)
#define emith_read_r_r_offs(r, ra, offs) \
EMIT(PPC_LDW_IMM(r, ra, offs))
#define emith_read_r_r_offs_c(cond, r, ra, offs) \
emith_read_r_r_offs(r, ra, offs)
#define emith_read_r_r_r_ptr(r, ra, rm) \
EMIT(PPC_LDP_REG(r, ra, rm))
#define emith_read_r_r_r(r, ra, rm) \
EMIT(PPC_LDW_REG(r, ra, rm))
#define emith_read_r_r_r_c(cond, r, ra, rm) \
emith_read_r_r_r(r, ra, rm)
#define emith_read8_r_r_offs(r, ra, offs) \
EMIT(PPC_LDB_IMM(r, ra, offs))
#define emith_read8_r_r_offs_c(cond, r, ra, offs) \
emith_read8_r_r_offs(r, ra, offs)
#define emith_read8_r_r_r(r, ra, rm) \
EMIT(PPC_LDB_REG(r, ra, rm))
#define emith_read8_r_r_r_c(cond, r, ra, rm) \
emith_read8_r_r_r(r, ra, rm)
#define emith_read16_r_r_offs(r, ra, offs) \
EMIT(PPC_LDH_IMM(r, ra, offs))
#define emith_read16_r_r_offs_c(cond, r, ra, offs) \
emith_read16_r_r_offs(r, ra, offs)
#define emith_read16_r_r_r(r, ra, rm) \
EMIT(PPC_LDH_REG(r, ra, rm))
#define emith_read16_r_r_r_c(cond, r, ra, rm) \
emith_read16_r_r_r(r, ra, rm)
#define emith_read8s_r_r_offs(r, ra, offs) do { \
EMIT(PPC_LDB_IMM(r, ra, offs)); \
EMIT(PPC_EXTSB_REG(r, r)); \
} while (0)
#define emith_read8s_r_r_offs_c(cond, r, ra, offs) \
emith_read8s_r_r_offs(r, ra, offs)
#define emith_read8s_r_r_r(r, ra, rm) do { \
EMIT(PPC_LDB_REG(r, ra, rm)); \
EMIT(PPC_EXTSB_REG(r, r)); \
} while (0)
#define emith_read8s_r_r_r_c(cond, r, ra, rm) \
emith_read8s_r_r_r(r, ra, rm)
#define emith_read16s_r_r_offs(r, ra, offs) do { \
EMIT(PPC_LDH_IMM(r, ra, offs)); \
EMIT(PPC_EXTSH_REG(r, r)); \
} while (0)
#define emith_read16s_r_r_offs_c(cond, r, ra, offs) \
emith_read16s_r_r_offs(r, ra, offs)
#define emith_read16s_r_r_r(r, ra, rm) do { \
EMIT(PPC_LDH_REG(r, ra, rm)); \
EMIT(PPC_EXTSH_REG(r, r)); \
} while (0)
#define emith_read16s_r_r_r_c(cond, r, ra, rm) \
emith_read16s_r_r_r(r, ra, rm)
#define emith_write_r_r_offs_ptr(r, ra, offs) \
EMIT(PPC_STP_IMM(r, ra, offs))
#define emith_write_r_r_offs_ptr_c(cond, r, ra, offs) \
emith_write_r_r_offs_ptr(r, ra, offs)
#define emith_write_r_r_r_ptr(r, ra, rm) \
EMIT(PPC_STP_REG(r, ra, rm))
#define emith_write_r_r_r_ptr_c(cond, r, ra, rm) \
emith_write_r_r_r_ptr(r, ra, rm)
#define emith_write_r_r_offs(r, ra, offs) \
EMIT(PPC_STW_IMM(r, ra, offs))
#define emith_write_r_r_offs_c(cond, r, ra, offs) \
emith_write_r_r_offs(r, ra, offs)
#define emith_write_r_r_r(r, ra, rm) \
EMIT(PPC_STW_REG(r, ra, rm))
#define emith_write_r_r_r_c(cond, r, ra, rm) \
emith_write_r_r_r(r, ra, rm)
#define emith_ctx_read_ptr(r, offs) \
emith_read_r_r_offs_ptr(r, CONTEXT_REG, offs)
#define emith_ctx_read(r, offs) \
emith_read_r_r_offs(r, CONTEXT_REG, offs)
#define emith_ctx_read_c(cond, r, offs) \
emith_ctx_read(r, offs)
#define emith_ctx_write_ptr(r, offs) \
emith_write_r_r_offs_ptr(r, CONTEXT_REG, offs)
@@ -1486,15 +1424,11 @@ static int emith_cond_check(int cond)
EMIT(PPC_MTSP_REG(r, CTR)); \
EMIT(PPC_BCTRCOND(BXX)); \
} while(0)
#define emith_jump_reg_c(cond, r) \
emith_jump_reg(r)
#define emith_jump_ctx(offs) do { \
emith_ctx_read_ptr(CR, offs); \
emith_jump_reg(CR); \
} while (0)
#define emith_jump_ctx_c(cond, offs) \
emith_jump_ctx(offs)
#define emith_call(target) do { \
u32 disp_ = (u8 *)target - (u8 *)tcache_ptr; \
@@ -1523,8 +1457,6 @@ static int emith_cond_check(int cond)
if ((r) != CR) emith_move_r_r(CR, r); \
emith_jump_reg(CR)
#endif
#define emith_abijump_reg_c(cond, r) \
emith_abijump_reg(r)
#define emith_abicall(target) \
emith_move_r_ptr_imm(CR, target); \
emith_abicall_reg(CR);
@@ -1547,8 +1479,6 @@ static int emith_cond_check(int cond)
#define emith_ret() \
EMIT(PPC_RET())
#define emith_ret_c(cond) \
emith_ret()
#define emith_ret_to_ctx(offs) do { \
EMIT(PPC_MFSP_REG(AT, LR)); \
@@ -1678,12 +1608,12 @@ static NOINLINE void host_instructions_updated(void *base, void *end, int force)
t3 = rcache_get_reg(reg, RC_GR_RMW, NULL); \
emith_cmp_r_r(t3, t2); \
EMITH_SJMP_START(DCOND_HI); \
emith_sub_r_r_imm_c(DCOND_LS, t2, t3, 1); \
emith_sub_r_r_imm(t2, t3, 1); \
EMITH_SJMP_END(DCOND_HI); \
/* if (reg <= 1) turns = 0 */ \
emith_cmp_r_imm(t3, 1); \
EMITH_SJMP_START(DCOND_HI); \
emith_move_r_imm_c(DCOND_LS, t2, 0); \
emith_move_r_imm(t2, 0); \
EMITH_SJMP_END(DCOND_HI); \
/* reg -= turns */ \
emith_sub_r_r(t3, t2); \
@@ -1743,11 +1673,11 @@ static NOINLINE void host_instructions_updated(void *base, void *end, int force)
emith_add_r_r_r_lsr(rn, rn, mh, 31); /* sum = (MACH>>31)+(MACH>>15) */ \
emith_tst_r_r(rn, rn); /* (need only N and Z flags) */ \
EMITH_SJMP_START(DCOND_EQ); /* sum != 0 -> -ovl */ \
emith_move_r_imm_c(DCOND_NE, ml, 0x00000000); \
emith_move_r_imm_c(DCOND_NE, mh, 0x00008000); \
emith_move_r_imm(ml, 0x00000000); \
emith_move_r_imm(mh, 0x00008000); \
EMITH_SJMP_START(DCOND_MI); /* sum > 0 -> +ovl */ \
emith_sub_r_imm_c(DCOND_PL, ml, 1); /* 0xffffffff */ \
emith_sub_r_imm_c(DCOND_PL, mh, 1); /* 0x00007fff */ \
emith_sub_r_imm(ml, 1); /* 0xffffffff */ \
emith_sub_r_imm(mh, 1); /* 0x00007fff */ \
EMITH_SJMP_END(DCOND_MI); \
EMITH_SJMP_END(DCOND_EQ); \
EMITH_SJMP_END(DCOND_EQ); \
@@ -1770,10 +1700,10 @@ static NOINLINE void host_instructions_updated(void *base, void *end, int force)
emith_tst_r_r(rn, rn); /* (need only N and Z flags) */ \
EMITH_SJMP_START(DCOND_EQ); /* sum != 0 -> overflow */ \
/* XXX: LSB signalling only in SH1, or in SH2 too? */ \
emith_move_r_imm_c(DCOND_NE, mh, 0x00000001); /* LSB of MACH */ \
emith_move_r_imm_c(DCOND_NE, ml, 0x80000000); /* -ovrfl */ \
emith_move_r_imm(mh, 0x00000001); /* LSB of MACH */ \
emith_move_r_imm(ml, 0x80000000); /* -ovrfl */ \
EMITH_SJMP_START(DCOND_MI); /* sum > 0 -> +ovrfl */ \
emith_sub_r_imm_c(DCOND_PL, ml, 1); /* 0x7fffffff */ \
emith_sub_r_imm(ml, 1); /* 0x7fffffff */ \
EMITH_SJMP_END(DCOND_MI); \
EMITH_SJMP_END(DCOND_EQ); \
EMITH_SJMP_END(DCOND_EQ); \
+13 -83
View File
@@ -296,8 +296,8 @@ enum { F2_ALT=0x20, F2_MULDIV=0x01 };
EMIT_PTR(ptr, R5_B(val_ & 0x00001fff)); \
}
#define EMITH_JMP_START(cond) { \
int cond_r, cond_s, cond_m = emith_cond_check(cond, &cond_r, &cond_s); \
#define EMITH_JMP_START(cond) \
{ int cond_r, cond_s, cond_m = emith_cond_check(cond, &cond_r, &cond_s); \
u8 *cond_ptr; \
JMP_POS(cond_ptr)
@@ -305,8 +305,8 @@ enum { F2_ALT=0x20, F2_MULDIV=0x01 };
JMP_EMIT(cond, cond_ptr); \
}
#define EMITH_JMP3_START(cond) { \
int cond_r, cond_s, cond_m = emith_cond_check(cond, &cond_r, &cond_s); \
#define EMITH_JMP3_START(cond) \
{ int cond_r, cond_s, cond_m = emith_cond_check(cond, &cond_r, &cond_s); \
u8 *cond_ptr, *else_ptr; \
JMP_POS(cond_ptr)
@@ -401,13 +401,9 @@ static void emith_set_compare_flags(int rs, int rt, s32 imm)
// data processing, register
#define emith_move_r_r_ptr(d, s) \
EMIT(R5_MOV_REG(d, s))
#define emith_move_r_r_ptr_c(cond, d, s) \
emith_move_r_r_ptr(d, s)
#define emith_move_r_r(d, s) \
emith_move_r_r_ptr(d, s)
#define emith_move_r_r_c(cond, d, s) \
emith_move_r_r(d, s)
#define emith_mvn_r_r(d, s) \
EMIT(R5_MVN_REG(d, s))
@@ -599,8 +595,6 @@ static void emith_set_compare_flags(int rs, int rt, s32 imm)
#define emith_and_r_r(d, s) \
emith_and_r_r_r(d, d, s)
#define emith_and_r_r_c(cond, d, s) \
emith_and_r_r(d, s)
#define emith_or_r_r(d, s) \
emith_or_r_r_r(d, d, s)
@@ -743,8 +737,6 @@ static void emith_move_ptr_imm(int r, uintptr_t imm)
#define emith_move_r_imm(r, imm) \
emith_move_imm(r, (u32)(imm))
#define emith_move_r_imm_c(cond, r, imm) \
emith_move_r_imm(r, imm)
#define emith_move_r_imm_s8_patchable(r, imm) \
EMIT(R5_ADD_IMM(r, Z0, (s8)(imm)))
@@ -768,16 +760,12 @@ static void emith_op_imm(int f1, int rd, int rs, u32 imm)
// arithmetic, immediate - can only be ADDI, since SUBI doesn't exist
#define emith_add_r_imm(r, imm) \
emith_add_r_r_imm(r, r, imm)
#define emith_add_r_imm_c(cond, r, imm) \
emith_add_r_imm(r, imm)
#define emith_addf_r_imm(r, imm) \
emith_addf_r_r_imm(r, imm)
#define emith_sub_r_imm(r, imm) \
emith_sub_r_r_imm(r, r, imm)
#define emith_sub_r_imm_c(cond, r, imm) \
emith_sub_r_imm(r, imm)
#define emith_subf_r_imm(r, imm) \
emith_subf_r_r_imm(r, r, imm)
@@ -824,8 +812,6 @@ static void emith_op_imm(int f1, int rd, int rs, u32 imm)
// NB: no SUBI in R5, since ADDI takes a signed imm
#define emith_sub_r_r_imm(d, s, imm) \
emith_add_r_r_imm(d, s, -(imm))
#define emith_sub_r_r_imm_c(cond, d, s, imm) \
emith_sub_r_r_imm(d, s, imm)
#define emith_subf_r_r_imm(d, s, imm) do { \
emith_sub_r_r_imm(FNZ, s, imm); \
@@ -838,31 +824,21 @@ static void emith_op_imm(int f1, int rd, int rs, u32 imm)
#define emith_or_r_imm(r, imm) \
emith_op_imm(F1_OR, r, r, imm)
#define emith_or_r_imm_c(cond, r, imm) \
emith_or_r_imm(r, imm)
#define emith_eor_r_imm_ptr(r, imm) \
emith_op_imm(F1_XOR, r, r, imm)
#define emith_eor_r_imm_ptr_c(cond, r, imm) \
emith_eor_r_imm_ptr(r, imm)
#define emith_eor_r_imm(r, imm) \
emith_eor_r_imm_ptr(r, imm)
#define emith_eor_r_imm_c(cond, r, imm) \
emith_eor_r_imm(r, imm)
/* NB: BIC #imm not available in R5; use AND #~imm instead */
#define emith_bic_r_imm(r, imm) \
emith_op_imm(F1_AND, r, r, ~(imm))
#define emith_bic_r_imm_c(cond, r, imm) \
emith_bic_r_imm(r, imm)
#define emith_tst_r_imm(r, imm) do { \
emith_op_imm(F1_AND, FNZ, r, imm); \
emith_cmp_rs = emith_cmp_rt = -1; \
} while (0)
#define emith_tst_r_imm_c(cond, r, imm) \
emith_tst_r_imm(r, imm)
#define emith_and_r_r_imm(d, s, imm) \
emith_op_imm(F1_AND, d, s, imm)
@@ -888,8 +864,6 @@ static void emith_op_imm(int f1, int rd, int rs, u32 imm)
EMIT(R5_LSRW_IMM(d, s, cnt)); \
EMIT(R5_OR_REG(d, d, AT)); \
} while (0)
#define emith_ror_c(cond, d, s, cnt) \
emith_ror(d, s, cnt)
#define emith_rol(d, s, cnt) do { \
EMIT(R5_LSRW_IMM(AT, s, 32-(cnt))); \
@@ -997,8 +971,6 @@ static void emith_op_imm(int f1, int rd, int rs, u32 imm)
emith_lsr(d, d, count); \
} \
} while (0)
#define emith_clear_msb_c(cond, d, s, count) \
emith_clear_msb(d, s, count)
#define emith_sext(d, s, count) /* bits to keep */ do { \
emith_lsl(d, s, 32-(count)); \
@@ -1025,8 +997,6 @@ static void emith_op_imm(int f1, int rd, int rs, u32 imm)
emith_add_r_r(dhi, AT); \
rcache_free_tmp(t_); \
} while (0)
#define emith_mula_s64_c(cond, dlo, dhi, s1, s2) \
emith_mula_s64(dlo, dhi, s1, s2)
// load/store. offs has 12 bits signed, hence larger offs may use a temp
static void emith_ld_offs(int sz, int rd, int rs, int o12)
@@ -1042,13 +1012,9 @@ static void emith_ld_offs(int sz, int rd, int rs, int o12)
#define emith_read_r_r_offs_ptr(r, rs, offs) \
emith_ld_offs(F1_P, r, rs, offs)
#define emith_read_r_r_offs_ptr_c(cond, r, rs, offs) \
emith_read_r_r_offs_ptr(r, rs, offs)
#define emith_read_r_r_offs(r, rs, offs) \
emith_ld_offs(F1_W, r, rs, offs)
#define emith_read_r_r_offs_c(cond, r, rs, offs) \
emith_read_r_r_offs(r, rs, offs)
#define emith_read_r_r_r_ptr(r, rs, rm) do { \
emith_add_r_r_r_ptr(AT, rs, rm); \
@@ -1058,56 +1024,38 @@ static void emith_ld_offs(int sz, int rd, int rs, int o12)
emith_add_r_r_r_ptr(AT, rs, rm); \
emith_ld_offs(F1_W, r, AT, 0); \
} while (0)
#define emith_read_r_r_r_c(cond, r, rs, rm) \
emith_read_r_r_r(r, rs, rm)
#define emith_read8_r_r_offs(r, rs, offs) \
emith_ld_offs(F1_BU, r, rs, offs)
#define emith_read8_r_r_offs_c(cond, r, rs, offs) \
emith_read8_r_r_offs(r, rs, offs)
#define emith_read8_r_r_r(r, rs, rm) do { \
emith_add_r_r_r_ptr(AT, rs, rm); \
emith_ld_offs(F1_BU, r, AT, 0); \
} while (0)
#define emith_read8_r_r_r_c(cond, r, rs, rm) \
emith_read8_r_r_r(r, rs, rm)
#define emith_read16_r_r_offs(r, rs, offs) \
emith_ld_offs(F1_HU, r, rs, offs)
#define emith_read16_r_r_offs_c(cond, r, rs, offs) \
emith_read16_r_r_offs(r, rs, offs)
#define emith_read16_r_r_r(r, rs, rm) do { \
emith_add_r_r_r_ptr(AT, rs, rm); \
emith_ld_offs(F1_HU, r, AT, 0); \
} while (0)
#define emith_read16_r_r_r_c(cond, r, rs, rm) \
emith_read16_r_r_r(r, rs, rm)
#define emith_read8s_r_r_offs(r, rs, offs) \
emith_ld_offs(F1_B, r, rs, offs)
#define emith_read8s_r_r_offs_c(cond, r, rs, offs) \
emith_read8s_r_r_offs(r, rs, offs)
#define emith_read8s_r_r_r(r, rs, rm) do { \
emith_add_r_r_r_ptr(AT, rs, rm); \
emith_ld_offs(F1_B, r, AT, 0); \
} while (0)
#define emith_read8s_r_r_r_c(cond, r, rs, rm) \
emith_read8s_r_r_r(r, rs, rm)
#define emith_read16s_r_r_offs(r, rs, offs) \
emith_ld_offs(F1_H, r, rs, offs)
#define emith_read16s_r_r_offs_c(cond, r, rs, offs) \
emith_read16s_r_r_offs(r, rs, offs)
#define emith_read16s_r_r_r(r, rs, rm) do { \
emith_add_r_r_r_ptr(AT, rs, rm); \
emith_ld_offs(F1_H, r, AT, 0); \
} while (0)
#define emith_read16s_r_r_r_c(cond, r, rs, rm) \
emith_read16s_r_r_r(r, rs, rm)
static void emith_st_offs(int sz, int rt, int rs, int o12)
{
@@ -1122,35 +1070,25 @@ static void emith_st_offs(int sz, int rt, int rs, int o12)
#define emith_write_r_r_offs_ptr(r, rs, offs) \
emith_st_offs(F1_P, r, rs, offs)
#define emith_write_r_r_offs_ptr_c(cond, r, rs, offs) \
emith_write_r_r_offs_ptr(r, rs, offs)
#define emith_write_r_r_r_ptr(r, rs, rm) do { \
emith_add_r_r_r_ptr(AT, rs, rm); \
emith_st_offs(F1_P, r, AT, 0); \
} while (0)
#define emith_write_r_r_r_ptr_c(cond, r, rs, rm) \
emith_write_r_r_r_ptr(r, rs, rm)
#define emith_write_r_r_offs(r, rs, offs) \
emith_st_offs(F1_W, r, rs, offs)
#define emith_write_r_r_offs_c(cond, r, rs, offs) \
emith_write_r_r_offs(r, rs, offs)
#define emith_write_r_r_r(r, rs, rm) do { \
emith_add_r_r_r_ptr(AT, rs, rm); \
emith_st_offs(F1_W, r, AT, 0); \
} while (0)
#define emith_write_r_r_r_c(cond, r, rs, rm) \
emith_write_r_r_r(r, rs, rm)
#define emith_ctx_read_ptr(r, offs) \
emith_read_r_r_offs_ptr(r, CONTEXT_REG, offs)
#define emith_ctx_read(r, offs) \
emith_read_r_r_offs(r, CONTEXT_REG, offs)
#define emith_ctx_read_c(cond, r, offs) \
emith_ctx_read(r, offs)
#define emith_ctx_write_ptr(r, offs) \
emith_write_r_r_offs_ptr(r, CONTEXT_REG, offs)
@@ -1373,15 +1311,11 @@ static int emith_cond_check(int cond, int *r, int *s)
#define emith_jump_reg(r) \
EMIT(R5_JR(r, 0))
#define emith_jump_reg_c(cond, r) \
emith_jump_reg(r)
#define emith_jump_ctx(offs) do { \
emith_ctx_read_ptr(AT, offs); \
emith_jump_reg(AT); \
} while (0)
#define emith_jump_ctx_c(cond, offs) \
emith_jump_ctx(offs)
#define emith_call(target) do { \
uintptr_t target_ = (uintptr_t)(target) - (uintptr_t)tcache_ptr; \
@@ -1401,8 +1335,6 @@ static int emith_cond_check(int cond, int *r, int *s)
#define emith_abijump_reg(r) \
emith_jump_reg(r)
#define emith_abijump_reg_c(cond, r) \
emith_abijump_reg(r)
#define emith_abicall(target) \
emith_call(target)
#define emith_abicall_cond(cond, target) \
@@ -1414,8 +1346,6 @@ static int emith_cond_check(int cond, int *r, int *s)
#define emith_ret() \
EMIT(R5_JR(LR, 0))
#define emith_ret_c(cond) \
emith_ret()
#define emith_ret_to_ctx(offs) \
emith_ctx_write_ptr(LR, offs)
@@ -1502,12 +1432,12 @@ static int emith_cond_check(int cond, int *r, int *s)
t3 = rcache_get_reg(reg, RC_GR_RMW, NULL); \
emith_cmp_r_r(t3, t2); \
EMITH_SJMP_START(DCOND_HI); \
emith_sub_r_r_imm_c(DCOND_LS, t2, t3, 1); \
emith_sub_r_r_imm(t2, t3, 1); \
EMITH_SJMP_END(DCOND_HI); \
/* if (reg <= 1) turns = 0 */ \
emith_cmp_r_imm(t3, 1); \
EMITH_SJMP_START(DCOND_HI); \
emith_move_r_imm_c(DCOND_LS, t2, 0); \
emith_move_r_imm(t2, 0); \
EMITH_SJMP_END(DCOND_HI); \
/* reg -= turns */ \
emith_sub_r_r(t3, t2); \
@@ -1565,11 +1495,11 @@ static int emith_cond_check(int cond, int *r, int *s)
emith_add_r_r_r_lsr(rn, rn, mh, 31); /* sum = (MACH>>31)+(MACH>>15) */ \
emith_teq_r_r(rn, Z0); /* (need only N and Z flags) */ \
EMITH_SJMP_START(DCOND_EQ); /* sum != 0 -> -ovl */ \
emith_move_r_imm_c(DCOND_NE, ml, 0x00000000); \
emith_move_r_imm_c(DCOND_NE, mh, 0x00008000); \
emith_move_r_imm(ml, 0x00000000); \
emith_move_r_imm(mh, 0x00008000); \
EMITH_SJMP_START(DCOND_MI); /* sum > 0 -> +ovl */ \
emith_sub_r_imm_c(DCOND_PL, ml, 1); /* 0xffffffff */ \
emith_sub_r_imm_c(DCOND_PL, mh, 1); /* 0x00007fff */ \
emith_sub_r_imm(ml, 1); /* 0xffffffff */ \
emith_sub_r_imm(mh, 1); /* 0x00007fff */ \
EMITH_SJMP_END(DCOND_MI); \
EMITH_SJMP_END(DCOND_EQ); \
EMITH_SJMP_END(DCOND_EQ); \
@@ -1592,10 +1522,10 @@ static int emith_cond_check(int cond, int *r, int *s)
emith_teq_r_r(rn, Z0); /* (need only N and Z flags) */ \
EMITH_SJMP_START(DCOND_EQ); /* sum != 0 -> overflow */ \
/* XXX: LSB signalling only in SH1, or in SH2 too? */ \
emith_move_r_imm_c(DCOND_NE, mh, 0x00000001); /* LSB of MACH */ \
emith_move_r_imm_c(DCOND_NE, ml, 0x80000000); /* -ovrfl */ \
emith_move_r_imm(mh, 0x00000001); /* LSB of MACH */ \
emith_move_r_imm(ml, 0x80000000); /* -ovrfl */ \
EMITH_SJMP_START(DCOND_MI); /* sum > 0 -> +ovrfl */ \
emith_sub_r_imm_c(DCOND_PL, ml, 1); /* 0x7fffffff */ \
emith_sub_r_imm(ml, 1); /* 0x7fffffff */ \
EMITH_SJMP_END(DCOND_MI); \
EMITH_SJMP_END(DCOND_EQ); \
EMITH_SJMP_END(DCOND_EQ); \
+14 -85
View File
@@ -455,68 +455,6 @@ enum { xAX = 0, xCX, xDX, xBX, xSP, xBP, xSI, xDI, // x86-64,i386 common
#define emith_bic_r_imm(r, imm) \
emith_arith_r_imm(4, r, ~(imm))
// fake conditionals (using SJMP instead)
#define emith_move_r_imm_c(cond, r, imm) \
emith_move_r_imm(r, imm)
#define emith_add_r_imm_c(cond, r, imm) \
emith_add_r_imm(r, imm)
#define emith_sub_r_imm_c(cond, r, imm) \
emith_sub_r_imm(r, imm)
#define emith_or_r_imm_c(cond, r, imm) \
emith_or_r_imm(r, imm)
#define emith_eor_r_imm_c(cond, r, imm) \
emith_eor_r_imm(r, imm)
#define emith_eor_r_imm_ptr_c(cond, r, imm) \
emith_eor_r_imm_ptr(r, imm)
#define emith_bic_r_imm_c(cond, r, imm) \
emith_bic_r_imm(r, imm)
#define emith_tst_r_imm_c(cond, r, imm) \
emith_tst_r_imm(r, imm)
#define emith_move_r_r_ptr_c(cond, d, s) \
emith_move_r_r_ptr(d, s)
#define emith_ror_c(cond, d, s, cnt) \
emith_ror(d, s, cnt)
#define emith_and_r_r_c(cond, d, s) \
emith_and_r_r(d, s)
#define emith_add_r_r_imm_c(cond, d, s, imm) \
emith_add_r_r_imm(d, s, imm)
#define emith_sub_r_r_imm_c(cond, d, s, imm) \
emith_sub_r_r_imm(d, s, imm)
#define emith_read8_r_r_r_c(cond, r, rs, rm) \
emith_read8_r_r_r(r, rs, rm)
#define emith_read8s_r_r_r_c(cond, r, rs, rm) \
emith_read8s_r_r_r(r, rs, rm)
#define emith_read16_r_r_r_c(cond, r, rs, rm) \
emith_read16_r_r_r(r, rs, rm)
#define emith_read16s_r_r_r_c(cond, r, rs, rm) \
emith_read16s_r_r_r(r, rs, rm)
#define emith_read_r_r_r_c(cond, r, rs, rm) \
emith_read_r_r_r(r, rs, rm)
#define emith_read_r_r_offs_c(cond, r, rs, offs) \
emith_read_r_r_offs(r, rs, offs)
#define emith_read_r_r_offs_ptr_c(cond, r, rs, offs) \
emith_read_r_r_offs_ptr(r, rs, offs)
#define emith_write_r_r_offs_c(cond, r, rs, offs) \
emith_write_r_r_offs(r, rs, offs)
#define emith_write_r_r_offs_ptr_c(cond, r, rs, offs) \
emith_write_r_r_offs_ptr(r, rs, offs)
#define emith_read8_r_r_offs_c(cond, r, rs, offs) \
emith_read8_r_r_offs(r, rs, offs)
#define emith_write8_r_r_offs_c(cond, r, rs, offs) \
emith_write8_r_r_offs(r, rs, offs)
#define emith_read16_r_r_offs_c(cond, r, rs, offs) \
emith_read16_r_r_offs(r, rs, offs)
#define emith_write16_r_r_offs_c(cond, r, rs, offs) \
emith_write16_r_r_offs(r, rs, offs)
#define emith_jump_reg_c(cond, r) \
emith_jump_reg(r)
#define emith_jump_ctx_c(cond, offs) \
emith_jump_ctx(offs)
#define emith_ret_c(cond) \
emith_ret()
// _r_r_imm - use lea
#define emith_add_r_r_imm(d, s, imm) do { \
if (imm == 0) \
@@ -629,11 +567,6 @@ enum { xAX = 0, xCX, xDX, xBX, xSP, xBP, xSI, xDI, // x86-64,i386 common
if (count) emith_and_r_imm(d, t); \
} while (0)
#define emith_clear_msb_c(cond, d, s, count) do { \
(void)(cond); \
emith_clear_msb(d, s, count); \
} while (0)
#define emith_sext(d, s, bits) do { \
emith_lsl(d, s, 32 - (bits)); \
emith_asr(d, d, 32 - (bits)); \
@@ -858,8 +791,6 @@ enum { xAX = 0, xCX, xDX, xBX, xSP, xBP, xSI, xDI, // x86-64,i386 common
#define emith_ctx_read(r, offs) \
emith_read_r_r_offs(r, CONTEXT_REG, offs)
#define emith_ctx_read_c(cond, r, offs) \
emith_ctx_read(r, offs)
#define emith_ctx_read_ptr(r, offs) do { \
EMIT_REX_IF(1, r, CONTEXT_REG); \
@@ -980,8 +911,6 @@ enum { xAX = 0, xCX, xDX, xBX, xSP, xBP, xSI, xDI, // x86-64,i386 common
#define emith_abijump_reg(r) \
emith_jump_reg(r)
#define emith_abijump_reg_c(cond, r) \
emith_abijump_reg(r)
#define emith_abicall(target) \
emith_call(target)
#define emith_abicall_cond(cond, target) \
@@ -990,16 +919,16 @@ enum { xAX = 0, xCX, xDX, xBX, xSP, xBP, xSI, xDI, // x86-64,i386 common
emith_call_reg(r)
#define EMITH_JMP_START(cond) { \
u8 *cond_ptr; \
#define EMITH_JMP_START(cond) \
{ u8 *cond_ptr; \
JMP8_POS(cond_ptr)
#define EMITH_JMP_END(cond) \
JMP8_EMIT(cond, cond_ptr); \
}
#define EMITH_JMP3_START(cond) { \
u8 *cond_ptr, *else_ptr; \
#define EMITH_JMP3_START(cond) \
{ u8 *cond_ptr, *else_ptr; \
JMP8_POS(cond_ptr)
#define EMITH_JMP3_MID(cond) \
@@ -1282,12 +1211,12 @@ enum { xAX = 0, xCX, xDX, xBX, xSP, xBP, xSI, xDI, // x86-64,i386 common
t3 = rcache_get_reg(reg, RC_GR_RMW, NULL); \
emith_cmp_r_r(t3, t2); \
EMITH_SJMP_START(DCOND_HI); \
emith_sub_r_r_imm_c(DCOND_LS, t2, t3, 1); \
emith_sub_r_r_imm(t2, t3, 1); \
EMITH_SJMP_END(DCOND_HI); \
/* if (reg <= 1) turns = 0 */ \
emith_cmp_r_imm(t3, 1); \
EMITH_SJMP_START(DCOND_HI); \
emith_move_r_imm_c(DCOND_LS, t2, 0); \
emith_move_r_imm(t2, 0); \
EMITH_SJMP_END(DCOND_HI); \
/* reg -= turns */ \
emith_sub_r_r(t3, t2); \
@@ -1369,11 +1298,11 @@ enum { xAX = 0, xCX, xDX, xBX, xSP, xBP, xSI, xDI, // x86-64,i386 common
emith_lsr(rm, mh, 31); \
emith_addf_r_r(rn, rm); \
EMITH_SJMP_START(DCOND_EQ); /* sum != 0 -> -ovl */ \
emith_move_r_imm_c(DCOND_NE, ml, 0x00000000); \
emith_move_r_imm_c(DCOND_NE, mh, 0x00008000); \
emith_move_r_imm(ml, 0x00000000); \
emith_move_r_imm(mh, 0x00008000); \
EMITH_SJMP_START(DCOND_MI); /* sum < 0 -> -ovl */ \
emith_sub_r_imm_c(DCOND_PL, ml, 1); /* 0xffffffff */ \
emith_sub_r_imm_c(DCOND_PL, mh, 1); /* 0x00007fff */ \
emith_sub_r_imm(ml, 1); /* 0xffffffff */ \
emith_sub_r_imm(mh, 1); /* 0x00007fff */ \
EMITH_SJMP_END(DCOND_MI); \
EMITH_SJMP_END(DCOND_EQ); \
EMITH_SJMP_END(DCOND_EQ); \
@@ -1395,10 +1324,10 @@ enum { xAX = 0, xCX, xDX, xBX, xSP, xBP, xSI, xDI, // x86-64,i386 common
emith_addf_r_r(rn, mh); /* sum = MACH + ((MACL>>31)&1) */ \
EMITH_SJMP_START(DCOND_EQ); /* sum != 0 -> overflow */ \
/* XXX: LSB signalling only in SH1, or in SH2 too? */ \
emith_move_r_imm_c(DCOND_NE, mh, 0x00000001); /* LSB of MACH */ \
emith_move_r_imm_c(DCOND_NE, ml, 0x80000000); /* -overflow */ \
emith_move_r_imm(mh, 0x00000001); /* LSB of MACH */ \
emith_move_r_imm(ml, 0x80000000); /* -overflow */ \
EMITH_SJMP_START(DCOND_MI); /* sum > 0 -> +overflow */ \
emith_sub_r_imm_c(DCOND_PL, ml, 1); /* 0x7fffffff */ \
emith_sub_r_imm(ml, 1); /* 0x7fffffff */ \
EMITH_SJMP_END(DCOND_MI); \
EMITH_SJMP_END(DCOND_EQ); \
EMITH_SJMP_END(DCOND_EQ); \
@@ -1422,7 +1351,7 @@ static void emith_clr_t_cond(int sr)
static void emith_set_t_cond(int sr, int cond)
{
EMITH_SJMP_START(emith_invert_cond(cond));
emith_or_r_imm_c(cond, sr, T);
emith_or_r_imm(sr, T);
EMITH_SJMP_END(emith_invert_cond(cond));
}
+60 -65
View File
@@ -2582,24 +2582,18 @@ static void rcache_init(void)
// ---------------------------------------------------------------
// swap 32 bit value read from mem in generated code (same as CPU_BE2)
static void emit_le_swap(int cond, int r)
static void emit_le_swap(int r)
{
#if CPU_IS_LE
if (cond == -1)
emith_ror(r, r, 16);
else
emith_ror_c(cond, r, r, 16);
emith_ror(r, r, 16);
#endif
}
// fix memory byte ptr in generated code (same as MEM_BE2)
static void emit_le_ptr8(int cond, int r)
static void emit_le_ptr8(int r)
{
#if CPU_IS_LE
if (cond == -1)
emith_eor_r_imm_ptr(r, 1);
else
emith_eor_r_imm_ptr_c(cond, r, 1);
emith_eor_r_imm_ptr(r, 1);
#endif
}
@@ -2853,7 +2847,7 @@ static int emit_memhandler_read_rr(SH2 *sh2, sh2_reg_e rd, sh2_reg_e rs, s32 off
switch (size & MF_SIZEMASK) {
case 0: emith_read8s_r_r_offs(hr2, hr, MEM_BE2(offs)); break; // 8
case 1: emith_read16s_r_r_offs(hr2, hr, offs); break; // 16
case 2: emith_read_r_r_offs(hr2, hr, offs); emit_le_swap(-1, hr2); break;
case 2: emith_read_r_r_offs(hr2, hr, offs); emit_le_swap(hr2); break;
}
rcache_free(hr);
if (size & MF_POSTINCR)
@@ -3524,7 +3518,7 @@ static void REGPARM(2) *sh2_translate(SH2 *sh2, int tcache_id)
emith_move_r_imm(tmp3, 0);
emith_cmp_r_r(tmp, tmp2);
EMITH_SJMP_START(DCOND_EQ);
emith_read_r_r_offs_c(DCOND_NE, tmp3, tmp3, 0); // crash
emith_read_r_r_offs(tmp3, tmp3, 0); // crash
EMITH_SJMP_END(DCOND_EQ);
rcache_free_tmp(tmp);
rcache_free_tmp(tmp2);
@@ -3581,8 +3575,8 @@ static void REGPARM(2) *sh2_translate(SH2 *sh2, int tcache_id)
tmp = rcache_get_tmp_arg(0);
emith_cmp_r_imm(sr, 0);
EMITH_SJMP_START(DCOND_GE);
emith_move_r_imm_c(DCOND_LT, tmp, pc);
emith_jump_cond(DCOND_LT, sh2_drc_exit);
emith_move_r_imm(tmp, pc);
emith_jump(sh2_drc_exit);
EMITH_SJMP_END(DCOND_GE);
rcache_free_tmp(tmp);
}
@@ -3712,7 +3706,7 @@ static void REGPARM(2) *sh2_translate(SH2 *sh2, int tcache_id)
tmp2 = emith_tst_t(sr, (ops[i-1].op == OP_BRANCH_CT));
tmp3 = emith_invert_cond(tmp2);
EMITH_SJMP_START(tmp3);
emith_move_r_imm_c(tmp2, tmp, ops[i-1].imm);
emith_move_r_imm(tmp, ops[i-1].imm);
EMITH_SJMP_END(tmp3);
break;
case OP_BRANCH_N: // BT/BF known not to be taken
@@ -4202,11 +4196,11 @@ static void REGPARM(2) *sh2_translate(SH2 *sh2, int tcache_id)
emith_clr_t_cond(sr);
emith_tst_r_imm(tmp, 0x000000ff);
EMITH_SJMP_START(DCOND_EQ);
emith_tst_r_imm_c(DCOND_NE, tmp, 0x0000ff00);
emith_tst_r_imm(tmp, 0x0000ff00);
EMITH_SJMP_START(DCOND_EQ);
emith_tst_r_imm_c(DCOND_NE, tmp, 0x00ff0000);
emith_tst_r_imm(tmp, 0x00ff0000);
EMITH_SJMP_START(DCOND_EQ);
emith_tst_r_imm_c(DCOND_NE, tmp, 0xff000000);
emith_tst_r_imm(tmp, 0xff000000);
EMITH_SJMP_END(DCOND_EQ);
EMITH_SJMP_END(DCOND_EQ);
EMITH_SJMP_END(DCOND_EQ);
@@ -5000,10 +4994,11 @@ end_op:
} else {
cond = emith_tst_t(sr, (opd_b->op == OP_BRANCH_CT));
if (emith_get_t_cond() >= 0) {
// need t_cond after jump, so can't use sync_t here
if (opd_b->op == OP_BRANCH_CT)
emith_or_r_imm_c(cond, sr, T);
emith_or_r_imm(sr, T);
else
emith_bic_r_imm_c(cond, sr, T);
emith_bic_r_imm(sr, T);
}
}
} else
@@ -5087,7 +5082,7 @@ end_op:
// jump @dispatcher - ARM 32bit version with conditional execution
EMITH_SJMP_START(emith_invert_cond(cond));
tmp = rcache_get_tmp_arg(0);
emith_move_r_imm_c(cond, tmp, target_pc);
emith_move_r_imm(tmp, target_pc);
rcache_free_tmp(tmp);
target = sh2_drc_dispatcher;
@@ -5095,7 +5090,7 @@ end_op:
bl->jump = tcache_ptr;
bl->type = BL_JMP;
}
emith_jump_cond_patchable(cond, target);
emith_jump_patchable(target);
EMITH_SJMP_END(emith_invert_cond(cond));
#endif
} else {
@@ -5288,12 +5283,12 @@ static void sh2_generate_utils(void)
emith_ctx_read_ptr(arg1, offsetof(SH2, read8_map));
EMITH_HINT_COND(DCOND_CS);
emith_sh2_rcall(arg0, arg1, arg2, arg3);
EMITH_SJMP_START(DCOND_CS);
emith_and_r_r_c(DCOND_CC, arg0, arg3);
emit_le_ptr8(DCOND_CC, arg0);
emith_read8s_r_r_r_c(DCOND_CC, RET_REG, arg2, arg0);
emith_ret_c(DCOND_CC);
EMITH_SJMP_END(DCOND_CS);
EMITH_JMP_START(DCOND_CS);
emith_and_r_r(arg0, arg3);
emit_le_ptr8(arg0);
emith_read8s_r_r_r(RET_REG, arg2, arg0);
emith_ret();
EMITH_JMP_END(DCOND_CS);
emith_move_r_r_ptr(arg1, CONTEXT_REG);
emith_abijump_reg(arg2);
emith_flush();
@@ -5303,11 +5298,11 @@ static void sh2_generate_utils(void)
emith_ctx_read_ptr(arg1, offsetof(SH2, read16_map));
EMITH_HINT_COND(DCOND_CS);
emith_sh2_rcall(arg0, arg1, arg2, arg3);
EMITH_SJMP_START(DCOND_CS);
emith_and_r_r_c(DCOND_CC, arg0, arg3);
emith_read16s_r_r_r_c(DCOND_CC, RET_REG, arg2, arg0);
emith_ret_c(DCOND_CC);
EMITH_SJMP_END(DCOND_CS);
EMITH_JMP_START(DCOND_CS);
emith_and_r_r(arg0, arg3);
emith_read16s_r_r_r(RET_REG, arg2, arg0);
emith_ret();
EMITH_JMP_END(DCOND_CS);
emith_move_r_r_ptr(arg1, CONTEXT_REG);
emith_abijump_reg(arg2);
emith_flush();
@@ -5317,12 +5312,12 @@ static void sh2_generate_utils(void)
emith_ctx_read_ptr(arg1, offsetof(SH2, read32_map));
EMITH_HINT_COND(DCOND_CS);
emith_sh2_rcall(arg0, arg1, arg2, arg3);
EMITH_SJMP_START(DCOND_CS);
emith_and_r_r_c(DCOND_CC, arg0, arg3);
emith_read_r_r_r_c(DCOND_CC, RET_REG, arg2, arg0);
emit_le_swap(DCOND_CC, RET_REG);
emith_ret_c(DCOND_CC);
EMITH_SJMP_END(DCOND_CS);
EMITH_JMP_START(DCOND_CS);
emith_and_r_r(arg0, arg3);
emith_read_r_r_r(RET_REG, arg2, arg0);
emit_le_swap(RET_REG);
emith_ret();
EMITH_JMP_END(DCOND_CS);
emith_move_r_r_ptr(arg1, CONTEXT_REG);
emith_abijump_reg(arg2);
emith_flush();
@@ -5333,11 +5328,11 @@ static void sh2_generate_utils(void)
EMITH_HINT_COND(DCOND_CS);
emith_sh2_rcall(arg0, arg1, arg2, arg3);
EMITH_SJMP_START(DCOND_CC);
emith_move_r_r_ptr_c(DCOND_CS, arg1, CONTEXT_REG);
emith_abijump_reg_c(DCOND_CS, arg2);
emith_move_r_r_ptr(arg1, CONTEXT_REG);
emith_abijump_reg(arg2);
EMITH_SJMP_END(DCOND_CC);
emith_and_r_r_r(arg1, arg0, arg3);
emit_le_ptr8(-1, arg1);
emit_le_ptr8(arg1);
emith_read8s_r_r_r(arg1, arg2, arg1);
emith_push_ret(arg1);
emith_move_r_r_ptr(arg2, CONTEXT_REG);
@@ -5351,8 +5346,8 @@ static void sh2_generate_utils(void)
EMITH_HINT_COND(DCOND_CS);
emith_sh2_rcall(arg0, arg1, arg2, arg3);
EMITH_SJMP_START(DCOND_CC);
emith_move_r_r_ptr_c(DCOND_CS, arg1, CONTEXT_REG);
emith_abijump_reg_c(DCOND_CS, arg2);
emith_move_r_r_ptr(arg1, CONTEXT_REG);
emith_abijump_reg(arg2);
EMITH_SJMP_END(DCOND_CC);
emith_and_r_r_r(arg1, arg0, arg3);
emith_read16s_r_r_r(arg1, arg2, arg1);
@@ -5368,12 +5363,12 @@ static void sh2_generate_utils(void)
EMITH_HINT_COND(DCOND_CS);
emith_sh2_rcall(arg0, arg1, arg2, arg3);
EMITH_SJMP_START(DCOND_CC);
emith_move_r_r_ptr_c(DCOND_CS, arg1, CONTEXT_REG);
emith_abijump_reg_c(DCOND_CS, arg2);
emith_move_r_r_ptr(arg1, CONTEXT_REG);
emith_abijump_reg(arg2);
EMITH_SJMP_END(DCOND_CC);
emith_and_r_r_r(arg1, arg0, arg3);
emith_read_r_r_r(arg1, arg2, arg1);
emit_le_swap(-1, arg1);
emit_le_swap(arg1);
emith_push_ret(arg1);
emith_move_r_r_ptr(arg2, CONTEXT_REG);
emith_abicall(p32x_sh2_poll_memory32);
@@ -5399,12 +5394,12 @@ static void sh2_generate_utils(void)
EMITH_SJMP_START(DCOND_NE);
#if (DRC_DEBUG & 128)
emith_move_r_ptr_imm(arg2, (uptr)&bchit);
emith_read_r_r_offs_c(DCOND_EQ, arg3, arg2, 0);
emith_add_r_imm_c(DCOND_EQ, arg3, 1);
emith_write_r_r_offs_c(DCOND_EQ, arg3, arg2, 0);
emith_read_r_r_offs(arg3, arg2, 0);
emith_add_r_imm(arg3, 1);
emith_write_r_r_offs(arg3, arg2, 0);
#endif
emith_read_r_r_offs_ptr_c(DCOND_EQ, RET_REG, arg1, offsetof(SH2, branch_cache) + sizeof(void *));
emith_jump_reg_c(DCOND_EQ, RET_REG);
emith_read_r_r_offs_ptr(RET_REG, arg1, offsetof(SH2, branch_cache) + sizeof(void *));
emith_jump_reg(RET_REG);
EMITH_SJMP_END(DCOND_NE);
#endif
emith_move_r_r_ptr(arg1, CONTEXT_REG);
@@ -5416,17 +5411,17 @@ static void sh2_generate_utils(void)
#if BRANCH_CACHE
#if (DRC_DEBUG & 128)
emith_move_r_ptr_imm(arg2, (uptr)&bcmiss);
emith_read_r_r_offs_c(DCOND_NE, arg3, arg2, 0);
emith_add_r_imm_c(DCOND_NE, arg3, 1);
emith_write_r_r_offs_c(DCOND_NE, arg3, arg2, 0);
emith_read_r_r_offs(arg3, arg2, 0);
emith_add_r_imm(arg3, 1);
emith_write_r_r_offs(arg3, arg2, 0);
#endif
emith_ctx_read_c(DCOND_NE, arg2, SHR_PC * 4);
emith_ctx_read(arg2, SHR_PC * 4);
emith_and_r_r_imm(arg1, arg2, (ARRAY_SIZE(sh2s->branch_cache)-1)*8);
emith_add_r_r_r_lsl_ptr(arg1, CONTEXT_REG, arg1, sizeof(void *) == 8 ? 1 : 0);
emith_write_r_r_offs_c(DCOND_NE, arg2, arg1, offsetof(SH2, branch_cache));
emith_write_r_r_offs_ptr_c(DCOND_NE, RET_REG, arg1, offsetof(SH2, branch_cache) + sizeof(void *));
emith_write_r_r_offs(arg2, arg1, offsetof(SH2, branch_cache));
emith_write_r_r_offs_ptr(RET_REG, arg1, offsetof(SH2, branch_cache) + sizeof(void *));
#endif
emith_jump_reg_c(DCOND_NE, RET_REG);
emith_jump_reg(RET_REG);
EMITH_SJMP_END(DCOND_EQ);
// lookup failed, call sh2_translate()
emith_move_r_r_ptr(arg0, CONTEXT_REG);
@@ -5434,7 +5429,7 @@ static void sh2_generate_utils(void)
emith_abicall(sh2_translate);
emith_tst_r_r_ptr(RET_REG, RET_REG);
EMITH_SJMP_START(DCOND_EQ);
emith_jump_reg_c(DCOND_NE, RET_REG);
emith_jump_reg(RET_REG);
EMITH_SJMP_END(DCOND_EQ);
// XXX: can't translate, fail
emith_abicall(dr_failure);
@@ -5465,10 +5460,10 @@ static void sh2_generate_utils(void)
#if (DRC_DEBUG & 128)
EMITH_SJMP_START(DCOND_EQ);
emith_move_r_ptr_imm(arg3, (uptr)&rcmiss);
emith_read_r_r_offs_c(DCOND_NE, arg1, arg3, 0);
emith_add_r_imm_c(DCOND_NE, arg1, 1);
emith_write_r_r_offs_c(DCOND_NE, arg1, arg3, 0);
emith_jump_cond(DCOND_NE, sh2_drc_dispatcher);
emith_read_r_r_offs(arg1, arg3, 0);
emith_add_r_imm(arg1, 1);
emith_write_r_r_offs(arg1, arg3, 0);
emith_jump(sh2_drc_dispatcher);
EMITH_SJMP_END(DCOND_EQ);
#else
emith_jump_cond(DCOND_NE, sh2_drc_dispatcher);
@@ -5496,7 +5491,7 @@ static void sh2_generate_utils(void)
emith_and_r_imm(arg0, 0x0f);
emith_cmp_r_r(arg1, arg0); // pending_level > ((sr >> 4) & 0x0f)?
EMITH_SJMP_START(DCOND_GT);
emith_ret_c(DCOND_LE); // nope, return
emith_ret(); // nope, return
EMITH_SJMP_END(DCOND_GT);
// adjust SP
tmp = rcache_get_reg(SHR_SP, RC_GR_RMW, NULL);
+19 -1
View File
@@ -57,6 +57,8 @@ LCHDR = $(CORE_DIR)/pico/cd/libchdr
LCHDR_LZMA = $(LCHDR)/deps/lzma-24.05
LCHDR_ZSTD = $(LCHDR)/deps/zstd-1.5.6/lib
TREMOR = $(COMMON_DIR)/tremor
SOURCES_C := $(LIBRETRO_DIR)/libretro.c \
$(LIBRETRO_COMM_DIR)/formats/png/rpng.c \
$(LIBRETRO_COMM_DIR)/streams/trans_stream.c \
@@ -73,6 +75,22 @@ SOURCES_C := $(LIBRETRO_DIR)/libretro.c \
$(COMMON_DIR)/mp3.c \
$(COMMON_DIR)/mp3_sync.c \
$(COMMON_DIR)/mp3_dummy.c \
$(COMMON_DIR)/ogg.c \
$(COMMON_DIR)/tremor/block.c \
$(COMMON_DIR)/tremor/codebook.c \
$(COMMON_DIR)/tremor/floor0.c \
$(COMMON_DIR)/tremor/floor1.c \
$(COMMON_DIR)/tremor/info.c \
$(COMMON_DIR)/tremor/mapping0.c \
$(COMMON_DIR)/tremor/mdct.c \
$(COMMON_DIR)/tremor/registry.c \
$(COMMON_DIR)/tremor/res012.c \
$(COMMON_DIR)/tremor/sharedbook.c \
$(COMMON_DIR)/tremor/synthesis.c \
$(COMMON_DIR)/tremor/window.c \
$(COMMON_DIR)/tremor/vorbisfile.c \
$(COMMON_DIR)/tremor/framing.c \
$(COMMON_DIR)/tremor/bitwise.c \
$(UNZIP_DIR)/unzip.c \
$(LCHDR)/src/libchdr_bitstream.c \
$(LCHDR)/src/libchdr_cdrom.c \
@@ -97,7 +115,7 @@ SOURCES_C := $(LIBRETRO_DIR)/libretro.c \
$(LCHDR_ZSTD)/decompress/zstd_decompress.c
COREFLAGS := $(addprefix -D,$(DEFINES)) -fno-strict-aliasing -DUSE_LIBCHDR=1 -DZ7_ST -DZSTD_DISABLE_ASM
COREFLAGS += -I$(LCHDR)/include -I$(LCHDR_LZMA)/include -I$(LCHDR_ZSTD)
COREFLAGS += -I$(LCHDR)/include -I$(LCHDR_LZMA)/include -I$(LCHDR_ZSTD) -I$(TREMOR) -DUSE_TREMOR
ifeq (,$(call gte,$(APP_PLATFORM_LEVEL),18))
ifneq ($(TARGET_ARCH_ABI),arm64-v8a)
# HACK
+2 -19
View File
@@ -324,7 +324,7 @@ static void p32x_start_blank(void)
Pico32xSwapDRAM(Pico32x.pending_fb ^ P32XV_FS);
}
p32x_schedule_vint(NULL, Pico.t.m68c_aim);
p32x_trigger_irq(NULL, Pico.t.m68c_aim, P32XI_VINT);
p32x_sh2_poll_event(msh2.poll_addr, &msh2, SH2_STATE_VPOLL, Pico.t.m68c_aim);
p32x_sh2_poll_event(ssh2.poll_addr, &ssh2, SH2_STATE_VPOLL, Pico.t.m68c_aim);
}
@@ -336,7 +336,7 @@ static void p32x_end_blank(void)
if ((Pico32x.vdp_regs[0] & P32XV_Mx) != 0) // no forced blanking
Pico32x.vdp_regs[0x0a/2] &= ~P32XV_PEN; // no palette access
if (!(Pico32x.sh2_regs[0] & 0x80)) {
// TODO must be early by min 4 SH-2 cycles to pass Mars Check?
// NB must precede VInt per hw manual, min 4 SH-2 cycles to pass Mars Check
Pico32x.hint_counter = (int)(-1.5*0x10);
p32x_schedule_hint(NULL, Pico.t.m68c_aim);
}
@@ -364,17 +364,6 @@ void p32x_schedule_hint(SH2 *sh2, unsigned int m68k_cycles)
p32x_event_schedule(m68k_cycles, P32X_EVENT_HINT, after);
}
void p32x_schedule_vint(SH2 *sh2, unsigned int m68k_cycles)
{
// according to 32X hw manual, HInt and VInt are tied to HBLANK and VBLANK.
// Moreover, VBLANK is 27 px (224 mclk, 32 68k cycles) after HBLANK.
// TODO check if that matches HBLANK/VBLANK on the cartridge slot?
if (sh2 != NULL)
p32x_event_schedule_sh2(sh2, P32X_EVENT_VINT, 32);
else
p32x_event_schedule(m68k_cycles, P32X_EVENT_VINT, 32);
}
/* events */
static void fillend_event(unsigned int now)
{
@@ -389,11 +378,6 @@ static void hint_event(unsigned int now)
p32x_schedule_hint(NULL, now);
}
static void vint_event(unsigned int now)
{
p32x_trigger_irq(NULL, now, P32XI_VINT);
}
static void mtimer_event(unsigned int now)
{
p32x_timer_irq(&msh2, now);
@@ -413,7 +397,6 @@ static event_cb *p32x_event_cbs[P32X_EVENT_COUNT] = {
p32x_pwm_irq_event, // P32X_EVENT_PWM
fillend_event, // P32X_EVENT_FILLEND
hint_event, // P32X_EVENT_HINT
vint_event, // P32X_EVENT_VINT
mtimer_event, // P32X_EVENT_MTIMER
stimer_event, // P32X_EVENT_STIMER
};
+3 -1
View File
@@ -76,9 +76,11 @@ static void dmac_te_irq(SH2 *sh2, struct dma_chan *chan)
static void dmac_transfer_complete(SH2 *sh2, struct dma_chan *chan)
{
u32 a = sh2->poll_addr;
chan->chcr |= DMA_TE; // DMA has ended normally
p32x_sh2_poll_event(sh2->poll_addr, sh2, SH2_STATE_SLEEP, SekCyclesDone());
// wake SLEEP and CPOLL since xRick has a loop polling on both TE and COMM
p32x_sh2_poll_event(a, sh2, SH2_STATE_SLEEP|SH2_STATE_CPOLL, SekCyclesDone());
if (chan->chcr & DMA_IE)
dmac_te_irq(sh2, chan);
}
+6 -2
View File
@@ -519,7 +519,7 @@ size_t pm_read_audio(void *ptr, size_t bytes, pm_file *stream)
{
if (stream == NULL)
return -1;
#if !(CPU_IS_LE)
#if !CPU_IS_LE
else if (stream->type == PMT_UNCOMPRESSED)
{
// convert little endian audio samples from WAV file
@@ -710,7 +710,7 @@ static int DecodeSmd(unsigned char *data,int len)
return 0;
}
static unsigned char *PicoCartAlloc(int filesize, int is_sms)
void *PicoCartAlloc(int filesize, int is_sms)
{
unsigned char *rom;
@@ -789,6 +789,7 @@ int PicoCartLoad(pm_file *f, const unsigned char *rom, unsigned int romsize,
if (bytes_read <= 0) {
elprintf(EL_STATUS, "read failed");
plat_munmap(rom_data, rom_alloc_size);
rom_alloc_size = 0;
return 3;
}
}
@@ -868,6 +869,7 @@ int PicoCartInsert(unsigned char *rom, unsigned int romsize, const char *carthw_
elprintf(EL_STATUS|EL_ANOMALY, "starting in unknown hw configuration: %x", PicoIn.AHW);
case 0:
case PAHW_SVP: PicoMemSetup(); break;
case PAHW_MCD|PAHW_VGM:
case PAHW_MCD: PicoMemSetupCD(); break;
case PAHW_PICO: PicoMemSetupPico(); break;
case PAHW_SMS: PicoMemSetupMS(); break;
@@ -908,7 +910,9 @@ void PicoCartUnload(void)
if (Pico.rom != NULL) {
SekFinishIdleDet();
plat_munmap(Pico.rom, rom_alloc_size);
rom_alloc_size = 0;
Pico.rom = NULL;
Pico.romsize = 0;
}
PicoGameLoaded = 0;
}
+47 -12
View File
@@ -30,6 +30,14 @@ static int handle_mp3(const char *fname, int index)
fs = ftell(tmp_file);
fseek(tmp_file, 0, SEEK_SET);
kBps = mp3_get_bitrate(tmp_file, fs) / 8;
if (ret != 0 || kBps <= 0)
{
elprintf(EL_STATUS, "track %2i: mp3 bitrate %i", index+1, kBps);
fclose(tmp_file);
return -1;
}
#ifdef _PSP_FW_VERSION
// some systems (like PSP) can't have many open files at a time,
// so we work with their names instead.
@@ -37,18 +45,6 @@ static int handle_mp3(const char *fname, int index)
tmp_file = (void *) strdup(fname);
#endif
kBps = mp3_get_bitrate(tmp_file, fs) / 8;
if (ret != 0 || kBps <= 0)
{
elprintf(EL_STATUS, "track %2i: mp3 bitrate %i", index+1, kBps);
#ifdef _PSP_FW_VERSION
free(tmp_file);
#else
fclose(tmp_file);
#endif
return -1;
}
track->type = CT_MP3;
track->fd = tmp_file;
track->offset = 0;
@@ -58,6 +54,39 @@ static int handle_mp3(const char *fname, int index)
return fs;
}
static int handle_ogg(const char *fname, int index)
{
track_t *track = &cdd.toc.tracks[index];
FILE *tmp_file;
int fs;
tmp_file = fopen(fname, "rb");
if (tmp_file == NULL)
return -1;
fs = ogg_get_length(tmp_file);
if (fs <= 0)
{
elprintf(EL_STATUS, "track %2i: ogg length %i", index+1, fs);
fclose(tmp_file);
return -1;
}
#ifdef _PSP_FW_VERSION
// some systems (like PSP) can't have many open files at a time,
// so we work with their names instead.
fclose(tmp_file);
tmp_file = (void *) strdup(fname);
#endif
track->type = CT_OGG;
track->fd = tmp_file;
track->offset = 0;
return fs * 75 / 1000;
}
static void to_upper(char *d, const char *s)
{
for (; *s != 0; d++, s++) {
@@ -151,6 +180,12 @@ int load_cd_image(const char *cd_img_name, int *type)
break;
length = ret;
}
else if (cue_data->tracks[n].type == CT_OGG) {
ret = handle_ogg(cue_data->tracks[n].fname, index);
if (ret < 0)
break;
length = ret;
}
else if (cue_data->tracks[n].fname != NULL)
{
pm_file *f = pm_open(cue_data->tracks[n].fname);
+2
View File
@@ -341,6 +341,8 @@ file_ok:
data->tracks[count].type = CT_MP3;
else if (strcasecmp(ext, "wav") == 0)
data->tracks[count].type = CT_WAV;
else if (strcasecmp(ext, "ogg") == 0)
data->tracks[count].type = CT_OGG;
else if (strcasecmp(ext, "bin") == 0)
data->tracks[count].type = CT_RAW;
else {
+3 -1
View File
@@ -472,7 +472,7 @@ int cdd_unload(void)
int i;
/* stop audio streaming */
if (Pico_mcd) Pico_mcd->cdda_stream = NULL;
if (Pico_mcd) cdda_stop_play();
/* close CD tracks */
if (cdd.toc.tracks[0].fd)
@@ -499,6 +499,8 @@ int cdd_unload(void)
/* close file */
if (cdd.toc.tracks[i].type == CT_MP3)
fclose(cdd.toc.tracks[i].fd);
else if (cdd.toc.tracks[i].type == CT_OGG)
fclose(cdd.toc.tracks[i].fd);
else
pm_close(cdd.toc.tracks[i].fd);
cdd.toc.tracks[i].fd = NULL;
+13 -1
View File
@@ -10,6 +10,7 @@
#include <string.h>
#include "pico_int.h"
#include "cd/cd_parse.h"
#include "sound/vgm.h"
unsigned char media_id_header[0x100];
@@ -55,9 +56,11 @@ static int detect_media(const char *fname, const unsigned char *rom, unsigned in
if (!strcasecmp(ext, "srm") || !strcasecmp(ext, "gz")) // s.gz ~ .mds.gz
return PM_BAD_DETECT;
/* don't believe in extensions, except .cue and .chd */
/* don't believe in extensions, except .cue, .chd and .vgm */
if (strcasecmp(ext, "cue") == 0 || strcasecmp(ext, "chd") == 0)
return PM_CD;
if (strcasecmp(ext, "vgm") == 0 || strcasecmp(ext, "vgz") == 0)
return PM_VGM;
/* Open rom file, if required */
if (!rom) {
@@ -275,6 +278,8 @@ enum media_type_e PicoLoadMedia(const char *filename,
if ((PicoIn.AHW & PAHW_MCD) && Pico_mcd != NULL)
cdd_unload();
if (PicoIn.AHW & PAHW_VGM)
vgm_finish();
PicoCartUnload();
PicoIn.AHW = 0;
PicoIn.quirks = 0;
@@ -334,6 +339,13 @@ enum media_type_e PicoLoadMedia(const char *filename,
else if (media_type == PM_PICO) {
PicoIn.AHW = PAHW_PICO;
}
else if (media_type == PM_VGM) {
if (vgm_load(rom_fname) == 0)
/* vgm_load() sets up PicoIn.AHW */;
else
media_type = PM_ERROR;
goto out;
}
if (rom == NULL && rom_fname != NULL) {
rom_file = pm_open(rom_fname);
+41 -23
View File
@@ -272,7 +272,7 @@ MAKE_68K_WRITE32(m68k_write32, m68k_write16_map)
// -----------------------------------------------------------------
static u32 ym2612_read_local_68k(void);
static u32 ym2612_read_local_68k(u32 a);
static int ym2612_write_local(u32 a, u32 d, int is_from_z80);
static void z80_mem_setup(void);
@@ -922,7 +922,7 @@ static u32 PicoRead8_z80(u32 a)
if ((a & 0x4000) == 0x0000) {
d = PicoMem.zram[a & 0x1fff];
} else if ((a & 0x6000) == 0x4000) // 0x4000-0x5fff
d = ym2612_read_local_68k();
d = ym2612_read_local_68k(a);
else {
elprintf(EL_UIO|EL_ANOMALY, "68k bad read [%06x] @%06x", a, SekPc);
d = (u8)PicoRead16_floating(a);
@@ -1431,7 +1431,8 @@ static int ym2612_write_local(u32 a, u32 d, int is_from_z80)
elprintf(EL_YMTIMER, "st mode %02x", d);
ym2612_sync_timers(cycles, old_mode, d);
ym2612.OPN.ST.mode = d;
if ((d ^ old_mode) & 0xc0)
break;
/* reset Timer a flag */
if (d & 0x10)
@@ -1441,13 +1442,7 @@ static int ym2612_write_local(u32 a, u32 d, int is_from_z80)
if (d & 0x20)
ym2612.OPN.ST.status &= ~2;
if ((d ^ old_mode) & 0xc0) {
#ifdef __GP2X__
if (PicoIn.opt & POPT_EXT_FM) return YM2612Write_940(a, d, get_scanline(is_from_z80));
#endif
PsndDoFM(cycles);
return 1;
}
ym2612.OPN.ST.mode = d;
return 0;
}
case 0x2a: { /* DAC data */
@@ -1477,28 +1472,40 @@ static int ym2612_write_local(u32 a, u32 d, int is_from_z80)
}
static u32 ym2612_read_local_z80(void)
static u32 ym2612_read_local_z80(unsigned short a)
{
int xcycles = z80_cyclesDone() << 8;
ym2612_update_status(xcycles);
elprintf(EL_YMTIMER, "timer z80 read %i, sched %i, %i @ %i|%i",
ym2612.OPN.ST.status, Pico.t.timer_a_next_oflow >> 8,
Pico.t.timer_b_next_oflow >> 8, xcycles >> 8, (xcycles >> 8) / 228);
return ym2612.OPN.ST.status;
if ((a&0x3) == 0 || !(PicoIn.opt & POPT_FM_YM2612)) {
elprintf(EL_YMTIMER, "timer z80 read %i, sched %i, %i @ %i|%i",
ym2612.OPN.ST.status, Pico.t.timer_a_next_oflow >> 8,
Pico.t.timer_b_next_oflow >> 8, xcycles >> 8, (xcycles >> 8) / 228);
Pico.t.ym2612_decay = xcycles + (OSC_NTSC/15/5<<8); // Q8 for convenience
return ym2612.OPN.ST.status_latch = ym2612.OPN.ST.status;
} else if (xcycles < Pico.t.ym2612_decay)
return ym2612.OPN.ST.status_latch;
else
return 0;
}
static u32 ym2612_read_local_68k(void)
static u32 ym2612_read_local_68k(u32 a)
{
int xcycles = z80_cycles_from_68k() << 8;
ym2612_update_status(xcycles);
elprintf(EL_YMTIMER, "timer 68k read %i, sched %i, %i @ %i|%i",
ym2612.OPN.ST.status, Pico.t.timer_a_next_oflow >> 8,
Pico.t.timer_b_next_oflow >> 8, xcycles >> 8, (xcycles >> 8) / 228);
return ym2612.OPN.ST.status;
if ((a&0x3) == 0 || !(PicoIn.opt & POPT_FM_YM2612)) {
elprintf(EL_YMTIMER, "timer 68k read %i, sched %i, %i @ %i|%i",
ym2612.OPN.ST.status, Pico.t.timer_a_next_oflow >> 8,
Pico.t.timer_b_next_oflow >> 8, xcycles >> 8, (xcycles >> 8) / 228);
Pico.t.ym2612_decay = xcycles + (OSC_NTSC/15/5<<8); // Q8 for convenience
return ym2612.OPN.ST.status_latch = ym2612.OPN.ST.status;
} else if (xcycles < Pico.t.ym2612_decay)
return ym2612.OPN.ST.status_latch;
else
return 0;
}
// legacy code, only used for GP2X
@@ -1526,11 +1533,13 @@ void ym2612_pack_state_old(void)
int ym2612_pack_timers(void *buf, size_t size)
{
// timers are saved as tick counts, in 16.16 int format
int tac, tat = 0, tbc, tbt = 0, busy = 0;
int tac, tat = 0, tbc, tbt = 0, busy = 0, decay = 0;
size_t b = 0;
tac = 1024 - ym2612.OPN.ST.TA;
tbc = 256 - ym2612.OPN.ST.TB;
if (Pico.t.ym2612_decay > 0)
decay = cycles_z80_to_68k(Pico.t.ym2612_decay);
if (Pico.t.ym2612_busy > 0)
busy = cycles_z80_to_68k(Pico.t.ym2612_busy);
if (Pico.t.timer_a_next_oflow != TIMER_NO_OFLOW)
@@ -1540,12 +1549,14 @@ int ym2612_pack_timers(void *buf, size_t size)
elprintf(EL_YMTIMER, "save: timer a %i/%i", tat >> 16, tac);
elprintf(EL_YMTIMER, "save: timer b %i/%i", tbt >> 16, tbc);
assert(size >= 16);
assert(size >= 21);
save_u16(buf, &b, ym2612.OPN.ST.TA);
save_u16(buf, &b, ym2612.OPN.ST.TB);
save_u32(buf, &b, tat);
save_u32(buf, &b, tbt);
save_u32(buf, &b, busy);
save_u32(buf, &b, decay);
save_u8_(buf, &b, ym2612.OPN.ST.status_latch);
return b;
}
@@ -1602,7 +1613,7 @@ void ym2612_unpack_state_old(void)
void ym2612_unpack_timers(const void *buf, size_t size)
{
int tac, tat, tbc, tbt, busy;
int tac, tat, tbc, tbt, busy, decay;
size_t b = 0;
assert(size >= 16);
if (size < 16)
@@ -1615,6 +1626,8 @@ void ym2612_unpack_timers(const void *buf, size_t size)
Pico.t.ym2612_busy = cycles_68k_to_z80(busy);
tac = (1024 - ym2612.OPN.ST.TA) << 16;
tbc = (256 - ym2612.OPN.ST.TB) << 16;
Pico.t.timer_a_step = TIMER_A_TICK_ZCYCLES * (1024 - ym2612.OPN.ST.TA);
Pico.t.timer_b_step = TIMER_B_TICK_ZCYCLES * (256 - ym2612.OPN.ST.TB);
if (ym2612.OPN.ST.mode & 1)
Pico.t.timer_a_next_oflow = (1LL * (tac-tat) * TIMER_A_TICK_ZCYCLES)>>16;
else
@@ -1625,6 +1638,11 @@ void ym2612_unpack_timers(const void *buf, size_t size)
Pico.t.timer_b_next_oflow = TIMER_NO_OFLOW;
elprintf(EL_YMTIMER, "load: %i/%i, timer_a_next_oflow %i", tat>>16, tac>>16, Pico.t.timer_a_next_oflow >> 8);
elprintf(EL_YMTIMER, "load: %i/%i, timer_b_next_oflow %i", tbt>>16, tbc>>16, Pico.t.timer_b_next_oflow >> 8);
if (size >= 21) {
decay = load_u32(buf, &b);
Pico.t.ym2612_decay = cycles_68k_to_z80(decay);
ym2612.OPN.ST.status_latch = load_u8_(buf, &b);
}
}
#if defined(NO_32X) && defined(_ASM_MEMORY_C)
+10
View File
@@ -10,6 +10,7 @@
#include "pico_int.h"
#include "sound/ym2612.h"
#include "sound/vgm.h"
struct Pico Pico;
struct PicoMem PicoMem;
@@ -52,6 +53,8 @@ void PicoExit(void)
PicoCartUnload();
if (PicoIn.AHW & PAHW_MCD)
PicoExitMCD();
if (PicoIn.AHW & PAHW_VGM)
vgm_finish();
z80_exit();
PsndExit();
PicoCloseTape();
@@ -202,6 +205,8 @@ int PicoReset(void)
if (PicoIn.opt & POPT_EN_32X)
PicoReset32x();
if (PicoIn.AHW & PAHW_VGM)
vgm_reset();
if (PicoIn.AHW & PAHW_MCD) {
PicoResetMCD();
return 0;
@@ -284,6 +289,11 @@ void PicoFrame(void)
Pico.m.frame_count++;
if (PicoIn.AHW & PAHW_VGM) {
vgm_frame();
goto end;
}
if (PicoIn.AHW & PAHW_SMS) {
PicoFrameMS();
goto end;
+8 -1
View File
@@ -24,6 +24,10 @@ extern void lprintf(const char *fmt, ...);
extern int mp3_get_bitrate(void *f, int size);
extern void mp3_start_play(void *f, int pos);
extern void mp3_update(s32 *buffer, int length, int stereo);
extern int ogg_get_length(void *f_);
extern void ogg_start_play(void *f_, int sample_offset);
extern void ogg_stop_play(void);
extern void ogg_update(s32 *buffer, int length, int stereo);
// this function should write-back d-cache and invalidate i-cache
// on a mem region [start_addr, end_addr)
@@ -75,7 +79,7 @@ extern void *p32x_bios_g, *p32x_bios_m, *p32x_bios_s;
#define POPT_EN_PWM (1<<21)
#define POPT_PWM_IRQ_OPT (1<<22)
#define POPT_DIS_FM_SSGEG (1<<23)
#define POPT_EN_FM_DAC (1<<24) //x00 0000
#define POPT_FM_YM2612 (1<<24) //x00 0000
#define POPT_EN_FM_FILTER (1<<25)
#define POPT_EN_KBD (1<<26)
@@ -89,6 +93,7 @@ extern void *p32x_bios_g, *p32x_bios_m, *p32x_bios_s;
#define PAHW_SG (1<<6)
#define PAHW_SC (1<<7)
#define PAHW_8BIT (PAHW_SMS|PAHW_GG|PAHW_SG|PAHW_SC)
#define PAHW_VGM (1<<8)
#define PHWS_AUTO 0
#define PHWS_GG 1
@@ -315,6 +320,7 @@ enum media_type_e {
PM_MARK3,
PM_PICO,
PM_CD,
PM_VGM,
};
enum cd_track_type
@@ -329,6 +335,7 @@ enum cd_track_type
CT_CHD = CT_AUDIO | 2,
CT_MP3 = CT_AUDIO | 3,
CT_WAV = CT_AUDIO | 4,
CT_OGG = CT_AUDIO | 5,
};
typedef struct
+8 -3
View File
@@ -467,6 +467,7 @@ struct PicoTiming
int timer_a_next_oflow, timer_a_step; // in z80 cycles
int timer_b_next_oflow, timer_b_step;
int ym2612_busy;
int ym2612_decay;
int vcnt_wrap, vcnt_adj;
};
@@ -710,6 +711,7 @@ extern carthw_state_chunk *carthw_chunks;
// cart.c
extern int rom_strcmp(void *rom, int size, int offset, const char *s1);
extern void *PicoCartAlloc(int filesize, int is_sms);
extern int PicoCartResize(int newsize);
extern void Byteswap(void *dst, const void *src, int len);
extern void (*PicoCartMemSetup)(void);
@@ -912,6 +914,7 @@ void SekInterruptClearS68k(int irq);
extern short cdda_out_buffer[2*1152];
void cdda_start_play(int lba_base, int lba_offset, int lb_len);
void cdda_stop_play(void);
#define YM2612_NATIVE_RATE() (((Pico.m.pal?OSC_PAL:OSC_NTSC)/7 + 3*24) / (6*24))
@@ -933,6 +936,8 @@ void ym2612_unpack_state_old(void);
#define timers_cycle(ticks) \
if (Pico.t.ym2612_busy > 0) \
Pico.t.ym2612_busy -= ticks << 8; \
if (Pico.t.ym2612_decay > 0) \
Pico.t.ym2612_decay -= ticks << 8; \
if (Pico.t.timer_a_next_oflow < TIMER_NO_OFLOW) \
Pico.t.timer_a_next_oflow -= ticks << 8; \
if (Pico.t.timer_b_next_oflow < TIMER_NO_OFLOW) \
@@ -940,7 +945,7 @@ void ym2612_unpack_state_old(void);
ym2612_sync_timers(0, ym2612.OPN.ST.mode, ym2612.OPN.ST.mode);
#define timers_reset() \
Pico.t.ym2612_busy = 0; \
Pico.t.ym2612_busy = Pico.t.ym2612_decay = ym2612.OPN.ST.status_latch = 0; \
Pico.t.timer_a_next_oflow = Pico.t.timer_b_next_oflow = TIMER_NO_OFLOW; \
Pico.t.timer_a_step = TIMER_A_TICK_ZCYCLES * 1024; \
Pico.t.timer_b_step = TIMER_B_TICK_ZCYCLES * 256; \
@@ -1021,6 +1026,7 @@ PICO_INTERNAL void PsndDoDAC(int cycle_to);
PICO_INTERNAL void PsndDoPSG(int cyc_to);
PICO_INTERNAL void PsndDoYM2413(int cyc_to);
PICO_INTERNAL void PsndDoFM(int cyc_to);
PICO_INTERNAL void PsndDoSMSFM(int cyc_to);
PICO_INTERNAL void PsndDoPCM(int cyc_to);
PICO_INTERNAL void PsndClear(void);
PICO_INTERNAL void PsndGetSamples(int y);
@@ -1057,7 +1063,6 @@ enum p32x_event {
P32X_EVENT_PWM,
P32X_EVENT_FILLEND,
P32X_EVENT_HINT,
P32X_EVENT_VINT,
P32X_EVENT_MTIMER,
P32X_EVENT_STIMER,
P32X_EVENT_COUNT,
@@ -1083,7 +1088,6 @@ void p32x_reset_sh2s(void);
void p32x_event_schedule(unsigned int now, enum p32x_event event, int after);
void p32x_event_schedule_sh2(SH2 *sh2, enum p32x_event event, int after);
void p32x_schedule_hint(SH2 *sh2, unsigned int m68k_cycles);
void p32x_schedule_vint(SH2 *sh2, unsigned int m68k_cycles);
#define p32x_sh2_ready(sh2, cycles) \
(CYCLES_GT(cycles,sh2->m68krcycles_done) && \
@@ -1204,6 +1208,7 @@ static __inline int isspace_(int c)
#define EL_PWM 0x00100000 /* 32X PWM stuff (LOTS of output) */
#define EL_32XP 0x00200000 /* 32X peripherals */
#define EL_CD 0x00400000 /* MCD */
#define EL_VGM 0x00800000
#define EL_STATUS 0x40000000 /* status messages */
#define EL_ANOMALY 0x80000000 /* some unexpected conditions (during emulation) */
+2 -2
View File
@@ -41,9 +41,9 @@
// There's no standard way to determine endianess at compile time. Try using
// some well known non-standard macros for detection.
#if defined __BYTE_ORDER__
#define CPU_IS_LE __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#define CPU_IS_LE (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
#elif defined __BYTE_ORDER
#define CPU_IS_LE __BYTE_ORDER == __LITTLE_ENDIAN
#define CPU_IS_LE (__BYTE_ORDER == __LITTLE_ENDIAN)
#elif defined __BIG_ENDIAN__ || defined _M_PPC // Windows on PPC was big endian
#define CPU_IS_LE 0
#elif defined __LITTLE_ENDIAN__ || defined _WIN32 // all other Windows is LE
+36 -16
View File
@@ -29,7 +29,8 @@ static s32 PsndBuffer[2*(54000+100)/50+2];
s16 cdda_out_buffer[2*1152];
// FM resampling polyphase FIR
static resampler_t *fmresampler;
static resampler_t *ym2612_resampler;
static resampler_t *ym2413_resampler;
static int (*PsndFMUpdate)(s32 *buffer, int length, int stereo, int is_buf_empty);
PICO_INTERNAL void PsndInit(void)
@@ -41,10 +42,12 @@ PICO_INTERNAL void PsndInit(void)
PICO_INTERNAL void PsndExit(void)
{
OPLL_delete(opll);
if (opll)
OPLL_delete(opll);
opll = NULL;
resampler_free(fmresampler); fmresampler = NULL;
resampler_free(ym2612_resampler); ym2612_resampler = NULL;
resampler_free(ym2413_resampler); ym2413_resampler = NULL;
}
PICO_INTERNAL void PsndReset(void)
@@ -66,7 +69,7 @@ static void YM2612Update(s32 *buffer, int length, int stereo)
static int YM2612UpdateFIR(s32 *buffer, int length, int stereo, int is_buf_empty)
{
resampler_update(fmresampler, buffer, length, YM2612Update);
resampler_update(ym2612_resampler, buffer, length, YM2612Update);
return ymchans;
}
@@ -83,12 +86,12 @@ static void YM2413Update(s32 *buffer, int length, int stereo)
static int YM2413UpdateFIR(s32 *buffer, int length, int stereo, int is_buf_empty)
{
if (!is_buf_empty) memset(buffer, 0, (length << stereo) * sizeof(*buffer));
resampler_update(fmresampler, buffer, length, YM2413Update);
resampler_update(ym2413_resampler, buffer, length, YM2413Update);
return 0;
}
// FIR setup, looks for a close enough rational number matching the ratio
static void YMFM_setup_FIR(int inrate, int outrate, int stereo)
static resampler_t *YMFM_setup_FIR(int inrate, int outrate, int stereo)
{
int mindiff = 999;
int diff, mul, div;
@@ -108,8 +111,7 @@ static void YMFM_setup_FIR(int inrate, int outrate, int stereo)
printf("FM polyphase FIR ratio=%d/%d error=%.3f%%\n",
Pico.snd.fm_fir_mul, Pico.snd.fm_fir_div, 100.0*mindiff/inrate);
resampler_free(fmresampler);
fmresampler = resampler_new(FMFIR_TAPS, Pico.snd.fm_fir_mul, Pico.snd.fm_fir_div,
return resampler_new(FMFIR_TAPS, Pico.snd.fm_fir_mul, Pico.snd.fm_fir_div,
0.85, 2, 2*inrate/50, stereo);
}
@@ -137,11 +139,11 @@ void PsndRerate(int preserve_state)
int state_size = 4096;
// don't init YM2612 if preserve_state and no parameter changes
ym2612_init |= ymclock != ym2612_clock || ymopts != (PicoIn.opt & (POPT_DIS_FM_SSGEG|POPT_EN_FM_DAC));
ym2612_init |= ymclock != ym2612_clock || ymopts != (PicoIn.opt & (POPT_DIS_FM_SSGEG|POPT_FM_YM2612));
ym2612_init |= ymrate != (PicoIn.opt & POPT_EN_FM_FILTER ? ym2612_rate : PicoIn.sndRate);
ymclock = ym2612_clock;
ymrate = (PicoIn.opt & POPT_EN_FM_FILTER ? ym2612_rate : PicoIn.sndRate);
ymopts = PicoIn.opt & (POPT_DIS_FM_SSGEG|POPT_EN_FM_DAC);
ymopts = PicoIn.opt & (POPT_DIS_FM_SSGEG|POPT_FM_YM2612);
if (preserve_state && ym2612_init) {
state = malloc(state_size);
@@ -149,25 +151,30 @@ void PsndRerate(int preserve_state)
state_size = YM2612PicoStateSave3(state, state_size);
}
if (PicoIn.AHW & PAHW_SMS) {
if (opll && opll->rate != ym2413_rate) {
OPLL_setRate(opll, ym2413_rate);
if (!preserve_state)
OPLL_reset(opll);
YMFM_setup_FIR(ym2413_rate, PicoIn.sndRate, 0);
resampler_free(ym2413_resampler);
ym2413_resampler = YMFM_setup_FIR(ym2413_rate, PicoIn.sndRate, 0);
}
if (PicoIn.AHW & PAHW_SMS) {
PsndFMUpdate = YM2413UpdateFIR;
} else if ((PicoIn.opt & POPT_EN_FM_FILTER) && ym2612_rate != PicoIn.sndRate) {
// polyphase FIR resampler, resampling directly from native to output rate
if (ym2612_init)
YM2612Init(ym2612_clock, ym2612_rate,
((PicoIn.opt&POPT_DIS_FM_SSGEG) ? 0 : ST_SSG) |
((PicoIn.opt&POPT_EN_FM_DAC) ? ST_DAC : 0));
YMFM_setup_FIR(ym2612_rate, PicoIn.sndRate, PicoIn.opt & POPT_EN_STEREO);
((PicoIn.opt&POPT_FM_YM2612) ? ST_DAC : 0));
resampler_free(ym2612_resampler);
ym2612_resampler = YMFM_setup_FIR(ym2612_rate, PicoIn.sndRate,
PicoIn.opt & POPT_EN_STEREO);
PsndFMUpdate = YM2612UpdateFIR;
} else {
if (ym2612_init)
YM2612Init(ym2612_clock, PicoIn.sndRate,
((PicoIn.opt&POPT_DIS_FM_SSGEG) ? 0 : ST_SSG) |
((PicoIn.opt&POPT_EN_FM_DAC) ? ST_DAC : 0));
((PicoIn.opt&POPT_FM_YM2612) ? ST_DAC : 0));
PsndFMUpdate = YM2612UpdateONE;
}
@@ -320,7 +327,7 @@ PICO_INTERNAL void PsndDoSMSFM(int cyc_to)
if (Pico.m.hardware & PMS_HW_FMUSED) {
buf += pos;
PsndFMUpdate(buf32, len, 0, 0);
YM2413UpdateFIR(buf32, len, 0, 0);
if (stereo)
while (len--) {
*buf++ += *buf32;
@@ -431,6 +438,10 @@ void cdda_start_play(int lba_base, int lba_offset, int lb_len)
mp3_start_play(Pico_mcd->cdda_stream, pos1024);
return;
} else if (Pico_mcd->cdda_type == CT_OGG) {
ogg_start_play(Pico_mcd->cdda_stream,
lba_offset * 588 + Pico_mcd->m.cdda_lba_offset);
return;
}
// on restart after loading, consider offset of last played sample
@@ -443,6 +454,13 @@ void cdda_start_play(int lba_base, int lba_offset, int lb_len)
}
}
void cdda_stop_play(void)
{
if (Pico_mcd->cdda_type == CT_OGG)
ogg_stop_play();
Pico_mcd->cdda_stream = NULL;
}
PICO_INTERNAL void PsndClear(void)
{
@@ -536,6 +554,8 @@ static int PsndRender(int offset, int length)
{
if (Pico_mcd->cdda_type == CT_MP3)
mp3_update(buf32, length-offset, stereo);
else if (Pico_mcd->cdda_type == CT_OGG)
ogg_update(buf32, length-offset, stereo);
else
cdda_raw_update(buf32, length-offset, stereo);
}
+644
View File
@@ -0,0 +1,644 @@
/*
* VGM parser for PicoDrive
* SPDX-License-Identifier: MIT
*
* specs:
* https://www.smspower.org/uploads/Music/vgmspec170.txt
* https://vgmrips.net/wiki/VGM_Specification
*/
#include <stdlib.h>
#include <string.h>
#include "../pico_int.h"
#include "sn76496.h"
#include "ym2413.h"
#include "ym2612.h"
#include "vgm.h"
#include <zlib.h>
#define READ_BLOCK (512 * 1024)
#define OVERALLOC 16 // to avoid range checks in the parser
#define BLOCK_TYPE_YM2612 0
#define BLOCK_TYPE_RF5C164 2
#define CHIP_TYPE_YM2612 2
#ifndef min
#define min(a, b) ((a) < (b) ? (a) : (b))
#endif
struct vgm_header
{
char vgm[4];
u32 eof, version, sn76489_clock;
u32 ym2413_clock, gd3_offset, total_samples, loop_offset; // 10
u32 loop_samples, rate, sn_fb_w, ym2612_clock; // 20
u32 ym2151_clock, data_offset, spcm_clock, spcm_interface; // 30
};
struct vgm
{
size_t data_size;
size_t data_pos;
u32 sample_pos;
u32 block_count;
u32 stream_count;
int dacout_nonstream;
struct vgm_block {
u32 start, end, pos;
} blocks[0x40];
struct vgm_stream {
u8 chip_type, ioport, reg, block_i;
u32 pos_inc, pos_fraction; // Q24
u32 pos;
u32 playing:1;
u32 new_sample:1;
//u32 looping:1;
u32 flags_warned:1;
u32 bad_start_warned:1;
} *streams;
union {
struct vgm_header hdr;
u8 data[0];
};
};
static struct vgm *g_vgm;
static size_t gzread_check(gzFile file, void *ptr, size_t size)
{
#if ZLIB_VERNUM >= 0x1290
size_t read_size = gzfread(ptr, 1, size, file);
#else
int read_size = gzread(file, ptr, size);
#endif
if (read_size == 0 || (long)read_size == -1)
{
int erri = Z_OK;
const char *err = gzerror(file, &erri);
if (erri != Z_OK && erri != Z_STREAM_END) {
elprintf(EL_VGM | EL_STATUS | EL_ANOMALY, "gzfread error %d: %s\n", erri, err);
return 0;
}
}
return read_size;
}
static struct vgm_stream *stream_get(struct vgm *vgm, size_t cmd_pos, u8 id)
{
void *tmp;
if (id < vgm->stream_count)
return &vgm->streams[id];
if (id == 0xff) // reserved?
goto problem;
tmp = realloc(vgm->streams, (id + 1) * sizeof(vgm->streams[0]));
if (!tmp)
goto problem;
vgm->streams = tmp;
memset(&vgm->streams[vgm->stream_count], 0,
(id + 1 - vgm->stream_count) * sizeof(vgm->streams[0]));
vgm->stream_count = id + 1;
return &vgm->streams[id];
problem:
elprintf(EL_VGM | EL_ANOMALY, "vgm: %06zx: broken stream %02x", cmd_pos, id);
return NULL;
}
static int vgm_reset_p(struct vgm *vgm, const char *fname)
{
vgm->data_pos = 0x40;
if (vgm->hdr.data_offset != 0) {
size_t data_offset = (size_t)0x34 + CPU_LE4(vgm->hdr.data_offset);
if (data_offset > vgm->data_size) {
elprintf(EL_VGM | EL_STATUS | EL_ANOMALY, "%s: broken data_offset %x",
fname, CPU_LE4(vgm->hdr.data_offset));
return 0;
}
vgm->data_pos = data_offset;
}
Pico.m.pal = CPU_LE4(vgm->hdr.rate) == 50;
// pcd_soft_reset() ?
if (Pico_mcd)
Pico_mcd->pcm.bank = 0;
// conflics md vs sms PMS_HW_FMUSED
Pico.m.hardware = 0;
return 1;
}
int vgm_load(const char *fname)
{
struct vgm *vgm = NULL;
gzFile file = NULL;
size_t alloc_size = 0;
int erri = Z_OK;
size_t read_size;
file = gzopen(fname, "rb");
if (!file) {
perror("gzopen");
goto fail;
}
alloc_size = sizeof(*vgm) + OVERALLOC;
vgm = calloc(1, alloc_size);
if (!vgm)
goto fail;
while (!gzeof(file))
{
void *tmp = realloc(vgm, (alloc_size += READ_BLOCK));
if (!tmp)
goto fail;
vgm = tmp;
read_size = gzread_check(file, vgm->data + vgm->data_size, READ_BLOCK);
if (read_size == 0) {
if (vgm->data_size == 0)
goto fail;
break;
}
vgm->data_size += read_size;
}
erri = gzclose(file);
file = NULL;
if (erri != Z_OK)
elprintf(EL_VGM | EL_STATUS | EL_ANOMALY, "gzclose error %d", erri);
memset(vgm->data + vgm->data_size, 0, OVERALLOC);
if (vgm->data_size <= 0x40) {
elprintf(EL_VGM | EL_STATUS | EL_ANOMALY, "%s: file too small: %zd",
fname, vgm->data_size);
goto fail;
}
if (memcmp(vgm->hdr.vgm, "Vgm ", 4) != 0) {
elprintf(EL_VGM | EL_STATUS | EL_ANOMALY, "%s: wrong ident", fname);
goto fail;
}
if (!vgm_reset_p(vgm, fname))
goto fail;
elprintf(EL_VGM | EL_STATUS, "vgm v%x.%02x pal=%d",
CPU_LE4(vgm->hdr.version) >> 8, CPU_LE4(vgm->hdr.version) & 0xff, Pico.m.pal);
// all supported chips may be used anytime, so partially initialize
PicoIn.AHW |= PAHW_VGM | PAHW_MCD;
PicoCreateMCD(NULL, 0);
// various things assume rom presence, so make a dummy one
if (!Pico.rom) {
Pico.rom = PicoCartAlloc(0x10000, 0);
if (Pico.rom) {
Pico.romsize = 0x10000;
memset(Pico.rom, 0, Pico.romsize);
}
}
PicoCartInsert(Pico.rom, Pico.romsize, NULL);
Pico.m.hardware = 0;
g_vgm = vgm;
return 0;
fail:
elprintf(EL_VGM | EL_STATUS | EL_ANOMALY, "vgm: %s: failed", fname);
if (file)
gzclose(file);
vgm_finish();
return -1;
}
static int try_start_stream(struct vgm *vgm, struct vgm_stream *stream,
size_t cmd_pos, u32 block_i, u8 flags)
{
if (block_i >= ARRAY_SIZE(vgm->blocks) ||
vgm->blocks[block_i].start >= vgm->blocks[block_i].end) {
if (!stream->bad_start_warned) {
elprintf(EL_VGM | EL_ANOMALY,
"vgm: %06zx: stream start: bad block id %02x", cmd_pos, block_i);
stream->bad_start_warned = 1;
}
return 0;
}
if (!stream->pos_inc) {
if (!stream->bad_start_warned) {
elprintf(EL_VGM | EL_ANOMALY,
"vgm: %06zx: stream start: no sample rate", cmd_pos);
stream->bad_start_warned = 1;
}
return 0;
}
if (stream->chip_type == CHIP_TYPE_YM2612 || stream->reg == 0x2a)
/* ok */;
else {
if (!stream->bad_start_warned) {
elprintf(EL_VGM | EL_ANOMALY,
"vgm: %06zx: stream start: unhandled chip config: %02x %02x",
cmd_pos, stream->chip_type, stream->reg);
stream->bad_start_warned = 1;
}
}
if (flags && !stream->flags_warned) {
elprintf(EL_VGM | EL_ANOMALY,
"vgm: %06zx: stream start: ignoring flags %02x", cmd_pos, flags);
stream->flags_warned = 1;
}
stream->block_i = block_i;
stream->pos_fraction = 0;
stream->pos = vgm->blocks[block_i].start;
stream->new_sample = 1;
return 1;
}
int rf5c164_write(struct vgm *vgm, size_t cmd_pos,
u32 doffset, const u8 *src, u32 soffset, u32 length)
{
// affected by current bank, but can go to further banks by using offset
size_t slength = vgm->blocks[0].end - vgm->blocks[0].start;
if (soffset >= slength || soffset + length > slength ||
(Pico_mcd->pcm.bank << 12) + doffset >= sizeof(Pico_mcd->pcm_ram) ||
(Pico_mcd->pcm.bank << 12) + doffset + length > sizeof(Pico_mcd->pcm_ram))
{
elprintf(EL_VGM | EL_ANOMALY, "vgm: %06zx: broken ram write %x->%x l=%x/%zx",
cmd_pos, soffset, doffset, length, slength);
return 0;
}
memcpy(Pico_mcd->pcm_ram_b[Pico_mcd->pcm.bank] + doffset, src + soffset, length);
return 1;
}
static u32 get16(const u8 **p)
{
u32 d_ = *(*p)++; d_ |= *(*p)++ << 8;
return d_;
}
static u32 get24(const u8 **p)
{
u32 d_ = *(*p)++; d_ |= *(*p)++ << 8; d_ |= *(*p)++ << 16;
return d_;
}
static u32 get32(const u8 **p)
{
u32 d_ = *(*p)++; d_ |= *(*p)++ << 8; d_ |= *(*p)++ << 16; d_ |= *(*p)++ << 24;
return d_;
}
void vgm_frame(void)
{
u32 osc_cyc_per_smp = Pico.m.pal ? 256ull*OSC_PAL/44100+1 : 256ull*OSC_NTSC/44100+1;
u32 scd_cyc_per_smp = 256ull*12500000/44100+1; // Q8
u32 samples_per_frame = Pico.m.pal ? 44100/50 : 44100/60;
u32 sample_pos_stream = 0;
u32 s68k_base = SekCycleCntS68k;
int dacout_stream = 0;
int streams_playing = 0;
struct vgm_stream *stream;
struct vgm *vgm = g_vgm;
u32 i;
if (!vgm)
return;
Pico.t.z80c_aim = 0;
PsndStartFrame();
for (i = 0; i < vgm->stream_count; i++) {
stream = &vgm->streams[i];
if (stream->playing) {
dacout_stream += ((int)vgm->data[stream->pos] - 0x80) << DAC_SHIFT;
streams_playing = 1;
}
}
while (vgm->data_pos < vgm->data_size && sample_pos_stream < samples_per_frame)
{
if (vgm->sample_pos < samples_per_frame)
{
size_t cmd_pos = vgm->data_pos; // file offset for logs
const u8 *fdata = vgm->data + vgm->data_pos;
u8 id, type, addr, data, flags, param[3];
u32 offset32, data32, data16;
u32 doffset, length;
int samples, wait_samples;
u8 cmd = *fdata++;
switch (cmd)
{
case 0x4f: // Game Gear PSG stereo
SN76496Config(*fdata++);
break;
case 0x50: // sn76489/sn76496 write
PsndDoPSG(z80_cyclesDone());
SN76496Write(*fdata++);
break;
case 0x51: // ym2413 write
Pico.m.hardware |= PMS_HW_FMUSED;
YM2413_regWrite(*fdata++);
YM2413_dataWrite(*fdata++);
break;
case 0x52: // ym2612 port 0 write
ym2612.OPN.ST.address = *fdata++;
ym2612.addr_A1 = 0;
ym2612.REGS[ym2612.OPN.ST.address] = data = *fdata++;
if (ym2612.OPN.ST.address == 0x2a) {
wait_samples = 0;
goto write_ym2612_dac;
}
goto write_ym2612_d;
case 0x53: // ym2612 port 1 write
ym2612.OPN.ST.address = *fdata++;
ym2612.addr_A1 = 1;
ym2612.REGS[0x100 | ym2612.OPN.ST.address] = data = *fdata++;
write_ym2612_d:
PsndDoFM(z80_cyclesDone());
YM2612Write_(1, data);
break;
case 0x61: // wait n samples
wait_samples = get16(&fdata);
goto wait;
case 0x62: // wait 735 samples
wait_samples = 735;
goto wait;
case 0x63: // wait 882 samples
wait_samples = 882;
goto wait;
case 0x66: // end of sound data
if (vgm->hdr.loop_offset) {
size_t target = (size_t)0x1c + CPU_LE4(vgm->hdr.loop_offset);
if (target <= vgm->data_size) {
fdata = vgm->data + target;
break;
}
elprintf(EL_VGM | EL_ANOMALY, "vgm: %06zx: broken loop_offset %x",
cmd_pos, CPU_LE4(vgm->hdr.loop_offset));
}
elprintf(EL_VGM, "vgm: %06zx: 0x66", cmd_pos);
fdata = vgm->data + vgm->data_size;
break;
case 0x67: // data block
fdata++;
type = *fdata++;
length = get32(&fdata);
if (vgm->data_pos + 7u + length > vgm->data_size) {
elprintf(EL_VGM | EL_ANOMALY, "vgm: %06zx: broken data block, len=%u",
cmd_pos, length);
fdata = vgm->data + vgm->data_size;
break;
}
switch (type) {
case BLOCK_TYPE_YM2612:
case BLOCK_TYPE_RF5C164:
i = vgm->block_count;
if (i < ARRAY_SIZE(vgm->blocks)) {
vgm->blocks[i].start = vgm->blocks[i].pos = vgm->data_pos + 7u;
vgm->blocks[i].end = vgm->data_pos + 7u + length;
vgm->block_count++;
}
else
elprintf(EL_VGM | EL_ANOMALY, "vgm: %06zx: too many data blocks", cmd_pos);
break;
case 0xc1: // RF5C164 RAM write
if (length < 2)
goto bad;
doffset = get16(&fdata);
length -= 2;
rf5c164_write(vgm, cmd_pos, doffset, fdata, 0, length);
break;
default:
bad:
elprintf(EL_VGM | EL_ANOMALY,
"vgm: %06zx: unhandled data block type %02x, len %x",
cmd_pos, type, length);
}
fdata += length;
break;
case 0x68: // PCM RAM write
fdata++;
type = *fdata++;
offset32 = get24(&fdata);
doffset = get24(&fdata);
length = get24(&fdata);
length = ((length - 1) & 0xffffff) + 1;
switch (type)
{
case BLOCK_TYPE_RF5C164:
rf5c164_write(vgm, cmd_pos, doffset, vgm->data + vgm->blocks[0].start,
offset32, length);
break;
default:
elprintf(EL_VGM | EL_ANOMALY, "vgm: %06zx: unhandled pcm ram type %02x",
cmd_pos, type);
}
break;
case 0x70 ... 0x7f: // wait
wait_samples = (cmd & 0x0f) + 1;
wait:
vgm->sample_pos += wait_samples;
samples = min(vgm->sample_pos, samples_per_frame);
Pico.t.z80c_aim = samples * osc_cyc_per_smp / (15 * 256u);
SekCycleCntS68k = s68k_base + (samples * scd_cyc_per_smp >> 8);
break;
case 0x80 ... 0x8f: // ym2612 dac write
data = 0x80;
if (vgm->blocks[0].pos < vgm->blocks[0].end) // always block 0?
data = vgm->data[vgm->blocks[0].pos++];
else
elprintf(EL_VGM | EL_ANOMALY, "vgm: %06zx: dac %x/%x",
cmd_pos, vgm->blocks[0].pos, vgm->blocks[0].end);
wait_samples = cmd & 0x0f;
write_ym2612_dac:
ym2612.OPN.ST.address = 0x2a;
ym2612.addr_A1 = 0;
PsndDoDAC(z80_cyclesDone());
vgm->dacout_nonstream = ((int)data - 0x80) << DAC_SHIFT;
ym2612.dacout = dacout_stream + vgm->dacout_nonstream;
if (wait_samples)
goto wait;
break;
case 0x90: // Stream Control
id = *fdata++;
type = *fdata++;
param[0] = *fdata++;
param[1] = *fdata++;
if (!(stream = stream_get(vgm, cmd_pos, id)))
break;
stream->chip_type = type;
stream->ioport = param[0];
stream->reg = param[1];
break;
case 0x91: // Stream Data
id = *fdata++;
param[0] = *fdata++;
param[1] = *fdata++;
param[2] = *fdata++;
if (!(stream = stream_get(vgm, cmd_pos, id)))
break;
if (param[0] >= ARRAY_SIZE(vgm->blocks)) {
elprintf(EL_VGM | EL_ANOMALY, "vgm: %06zx: bad block id %02x",
cmd_pos, param[0]);
break;
}
if (param[1] != 1 || param[2] != 0)
elprintf(EL_VGM | EL_ANOMALY, "vgm: %06zx: unhandled step %02x,%02x",
cmd_pos, param[1], param[2]);
stream->block_i = param[0];
break;
case 0x92: // Stream Frequency
id = *fdata++;
data32 = get32(&fdata);
if (!(stream = stream_get(vgm, cmd_pos, id)))
break;
stream->pos_inc = ((u64)data32 << 24) / 44100u;
break;
case 0x93: // Start Stream
id = *fdata++;
offset32 = get32(&fdata);
flags = *fdata++;
length = get32(&fdata);
if (!(stream = stream_get(vgm, cmd_pos, id)))
break;
if (!try_start_stream(vgm, stream, cmd_pos, stream->block_i, flags))
break;
if (offset32 != ~0) {
struct vgm_block *block = &vgm->blocks[stream->block_i];
if (offset32 >= block->end - block->start) {
if (!stream->bad_start_warned) {
elprintf(EL_VGM | EL_ANOMALY,
"vgm: %06zx: stream start: bad offset %x", cmd_pos, offset32);
stream->bad_start_warned = 1;
}
stream->playing = 0;
break;
}
stream->pos = block->start + offset32;
}
stream->playing = 1;
streams_playing = 1;
break;
case 0x94: // Stop Stream
id = *fdata++;
streams_playing = 0;
if (id == 0xff) {
for (i = 0; i < vgm->stream_count; i++)
vgm->streams[i].playing = 0;
break;
}
if (!(stream = stream_get(vgm, cmd_pos, id)))
break;
if (vgm->streams[id].playing)
vgm->streams[id].playing = 0;
for (i = 0; i < vgm->stream_count; i++) {
stream = &vgm->streams[i];
if (stream->playing) {
// refresh since the current stream is done now
stream->new_sample = 1;
streams_playing = 1;
}
}
break;
case 0x95: // Start Stream (fast call)
id = *fdata++;
data16 = get16(&fdata);
flags = *fdata++;
if (!(stream = stream_get(vgm, cmd_pos, id)))
break;
if (!try_start_stream(vgm, stream, cmd_pos, data16, flags))
break;
stream->playing = 1;
streams_playing = 1;
break;
case 0xB1: // RF5C164, write
addr = *fdata++;
data = *fdata++;
pcd_pcm_write(addr, data);
break;
case 0xe0: // seek to offset
offset32 = get32(&fdata);
if (offset32 < vgm->blocks[0].end - vgm->blocks[0].start) // always block 0?
vgm->blocks[0].pos = vgm->blocks[0].start + offset32;
else
elprintf(EL_VGM | EL_ANOMALY, "vgm: %06zx: cmd E0 out of range: %x/%x",
cmd_pos, offset32, vgm->blocks[0].end - vgm->blocks[0].start);
break;
default:
elprintf(EL_VGM, "vgm: %06zx: skipping cmd %02x", cmd_pos, cmd);
if (cmd >= 0xE0u)
fdata += 4;
else if (cmd >= 0xC0u)
fdata += 3;
else if (cmd >= 0xA0u)
fdata += 2;
else if ((cmd & 0xf0) == 0x40u)
fdata += CPU_LE4(vgm->hdr.version) >= 0x160 ? 2 : 1;
else if ((cmd & 0xf0) == 0x30u)
fdata += 1;
}
vgm->data_pos = fdata - vgm->data;
}
if (!streams_playing) {
sample_pos_stream = vgm->sample_pos;
continue;
}
// stream to cmd catch-up
{
u32 stream_sample_to = min(vgm->sample_pos, samples_per_frame);
int check_for_new_sample = 1;
for (; sample_pos_stream < stream_sample_to; sample_pos_stream++)
{
if (check_for_new_sample) {
int do_dac_write = 0;
dacout_stream = 0;
for (i = 0; i < vgm->stream_count; i++) {
stream = &vgm->streams[i];
if (!stream->playing)
continue;
do_dac_write |= vgm->streams[i].new_sample;
vgm->streams[i].new_sample = 0;
dacout_stream += ((int)vgm->data[stream->pos] - 0x80) << DAC_SHIFT;
}
if (do_dac_write) {
Pico.t.z80c_aim = sample_pos_stream * osc_cyc_per_smp / (15 * 256u);
ym2612.OPN.ST.address = 0x2a;
ym2612.addr_A1 = 0;
PsndDoDAC(z80_cyclesDone());
ym2612.dacout = dacout_stream + vgm->dacout_nonstream;
}
check_for_new_sample = 0;
}
// advance all streams
streams_playing = 0;
for (i = 0; i < vgm->stream_count; i++) {
u32 inc;
stream = &vgm->streams[i];
if (!stream->playing)
continue;
stream->pos_fraction += stream->pos_inc;
inc = stream->pos_fraction >> 24;
if (inc) {
stream->pos_fraction &= 0xffffff;
stream->pos += inc;
if (stream->pos >= vgm->blocks[stream->block_i].end)
stream->playing = 0;
else
check_for_new_sample = stream->new_sample = 1;
}
streams_playing |= stream->playing;
}
} // for sample_pos_stream
}
}
// for a long wait, do only the current frame's worth of samples
Pico.t.z80c_aim = samples_per_frame * osc_cyc_per_smp / (15 * 256u);
SekCycleCntS68k = s68k_base + (samples_per_frame * scd_cyc_per_smp >> 8);
vgm->sample_pos -= samples_per_frame;
PsndDoSMSFM(Pico.t.z80c_aim);
PsndGetSamples(0);
Pico.m.frame_count++;
}
void vgm_reset(void)
{
if (g_vgm)
vgm_reset_p(g_vgm, NULL);
}
void vgm_finish(void)
{
if (g_vgm) {
free(g_vgm->streams);
free(g_vgm);
g_vgm = NULL;
}
}
// vim:ts=2:sw=2:expandtab
+6
View File
@@ -0,0 +1,6 @@
int vgm_load(const char *fname);
void vgm_frame(void);
void vgm_reset(void);
void vgm_finish(void);
+93 -124
View File
@@ -152,6 +152,7 @@ void memset32(void *dest, int c, int count);
/* globals */
#define FREQ_SH 16 /* 16.16 fixed point (frequency calculations) */
#define FREQBASE_SH 9 /* Q9 fixed point */
#define EG_SH 16 /* 16.16 fixed point (envelope generator timing) */
#define LFO_SH 24 /* 8.24 fixed point (LFO calculations) */
@@ -364,20 +365,25 @@ O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0)
};
#undef O
static const UINT8 dt_tab[4 * 32]={
static const INT8 dt_tab[4][32] = {
/* this is YM2151 and YM2612 phase increment data (in 10.10 fixed point format)*/
{
/* FD=0 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
}, {
/* FD=1 */
0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2,
2, 3, 3, 3, 4, 4, 4, 5, 5, 6, 6, 7, 8, 8, 8, 8,
2, 3, 3, 3, 4, 4, 4, 5, 5, 6, 6, 7, 8, 8, 8, 8
}, {
/* FD=2 */
1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5,
5, 6, 6, 7, 8, 8, 9,10,11,12,13,14,16,16,16,16,
5, 6, 6, 7, 8, 8, 9,10,11,12,13,14,16,16,16,16
}, {
/* FD=3 */
2, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 6, 6, 7,
8 ,8, 9,10,11,12,13,14,16,17,19,20,22,22,22,22
}
};
@@ -509,10 +515,6 @@ static const UINT8 lfo_pm_output[7*8][8]={ /* 7 bits meaningful (of F-NUMBER), 8
/* all 128 LFO PM waveforms */
static INT32 lfo_pm_table[128*8*32]; /* 128 combinations of 7 bits meaningful (of F-NUMBER), 8 LFO depths, 32 LFO output levels per one depth */
/* there are 2048 FNUMs that can be generated using FNUM/BLK registers
but LFO works with one more bit of a precision so we really need 4096 elements */
static UINT32 fn_table[4096]; /* fnumber->increment counter */
/* register number to channel number , slot offset */
#define OPN_CHAN(N) (N&3)
#define OPN_SLOT(N) ((N>>2)&3)
@@ -527,6 +529,9 @@ static UINT32 fn_table[4096]; /* fnumber->increment counter */
/* OPN Mode Register Write */
static INLINE void set_timers( int v )
{
if ((ym2612.OPN.ST.mode ^ v) & 0xc0)
ym2612.CH[2].SLOT[SLOT1].Incr = -1;
/* b7 = CSM MODE */
/* b6 = 3 slot mode */
/* b5 = reset b */
@@ -600,7 +605,7 @@ static INLINE void FM_KEYOFF(int c , int s )
static INLINE void set_det_mul(FM_CH *CH, FM_SLOT *SLOT, int v)
{
SLOT->mul = (v&0x0f)? (v&0x0f)*2 : 1;
SLOT->DT = ym2612.OPN.ST.dt_tab[(v>>4)&7];
SLOT->detune = (v>>4)&7;
CH->SLOT[SLOT1].Incr=-1;
}
@@ -690,7 +695,7 @@ static INLINE void set_sl_rr(FM_SLOT *SLOT, int v)
static INLINE signed int op_calc(UINT32 phase, unsigned int env, signed int pm)
{
int ret, sin = (phase>>16) + (pm>>1);
int ret, sin = (phase >> FREQ_SH) + (pm >> 1);
int neg = sin & 0x200;
if (sin & 0x100) sin ^= 0xff;
sin&=0xff;
@@ -707,7 +712,7 @@ static INLINE signed int op_calc(UINT32 phase, unsigned int env, signed int pm)
static INLINE signed int op_calc1(UINT32 phase, unsigned int env, signed int pm)
{
int ret, sin = (phase+pm)>>16;
int ret, sin = (phase + pm) >> FREQ_SH;
int neg = sin & 0x200;
if (sin & 0x100) sin ^= 0xff;
sin&=0xff;
@@ -1237,13 +1242,28 @@ static void chan_render_finish(s32 *buffer, int length, int active_chans)
ym2612.OPN.lfo_cnt += ym2612.OPN.lfo_inc * length;
}
static UINT32 update_lfo_phase(const FM_SLOT *SLOT, UINT32 block_fnum)
/* calculate the 20bit (Q10) phase increment as in the real chip */
static INLINE UINT32 get_phase_increment(FM_SLOT *SLOT, UINT32 fnum12, UINT32 blk, UINT32 kcode)
{
UINT32 fnum_lfo;
UINT32 inc;
int detune = dt_tab[SLOT->detune & 3][kcode];
if (SLOT->detune & 4)
detune = -detune;
inc = (fnum12 << blk) >> 2;
inc += detune;
SLOT->detune_overflow = inc >> 31;
inc &= (1u << 17) - 1;
inc = inc * SLOT->mul >> 1;
inc &= (1u << 20) - 1;
return inc;
}
static UINT32 update_lfo_phase(FM_SLOT *SLOT, UINT32 freqbase, UINT32 block_fnum, UINT32 kcode)
{
UINT32 fnum_lfo, incr;
INT32 lfo_fn_table_index_offset;
UINT8 blk;
UINT32 fn;
int fc,fdt;
fnum_lfo = ((block_fnum & 0x7f0) >> 4) * 32 * 8;
lfo_fn_table_index_offset = lfo_pm_table[ fnum_lfo + crct.CH->pms + ((crct.pack>>16)&0xff) ];
@@ -1253,19 +1273,15 @@ static UINT32 update_lfo_phase(const FM_SLOT *SLOT, UINT32 block_fnum)
blk = (block_fnum&0x7000) >> 12;
fn = block_fnum & 0xfff;
/* phase increment counter */
fc = (fn_table[fn]>>(7-blk));
fdt = fc + SLOT->DT[crct.CH->kcode];
if (fdt < 0) fdt += fn_table[0x7ff*2] >> 2;
return (fdt * SLOT->mul) >> 1;
incr = get_phase_increment(SLOT, fn, blk, kcode);
return incr * freqbase >> (FREQBASE_SH - (FREQ_SH-10));
} else
return SLOT->Incr;
}
static int chan_render(s32 *buffer, int length, int c, UINT32 flags) // flags: stereo, ?, disabled, ?, pan_r, pan_l
{
UINT32 freqbase = ym2612.OPN.ST.freqbase_ui;
crct.CH = &ym2612.CH[c];
crct.mem = crct.CH->mem_value; /* one sample delay memory */
crct.lfo_cnt = ym2612.OPN.lfo_cnt;
@@ -1298,19 +1314,21 @@ static int chan_render(s32 *buffer, int length, int c, UINT32 flags) // flags: s
if (ym2612.OPN.ST.flags & ST_DAC)
crct.algo |= 0x80;
if(crct.CH->pms && (ym2612.OPN.ST.mode & 0xC0) && c == 2) {
/* 3 slot mode */
crct.incr1 = update_lfo_phase(&crct.CH->SLOT[SLOT1], ym2612.OPN.SL3.block_fnum[1]);
crct.incr2 = update_lfo_phase(&crct.CH->SLOT[SLOT2], ym2612.OPN.SL3.block_fnum[2]);
crct.incr3 = update_lfo_phase(&crct.CH->SLOT[SLOT3], ym2612.OPN.SL3.block_fnum[0]);
crct.incr4 = update_lfo_phase(&crct.CH->SLOT[SLOT4], crct.CH->block_fnum);
}
else if(crct.CH->pms)
{
crct.incr1 = update_lfo_phase(&crct.CH->SLOT[SLOT1], crct.CH->block_fnum);
crct.incr2 = update_lfo_phase(&crct.CH->SLOT[SLOT2], crct.CH->block_fnum);
crct.incr3 = update_lfo_phase(&crct.CH->SLOT[SLOT3], crct.CH->block_fnum);
crct.incr4 = update_lfo_phase(&crct.CH->SLOT[SLOT4], crct.CH->block_fnum);
if (crct.CH->pms) {
UINT32 block_fnum = crct.CH->block_fnum, kcode = crct.CH->kcode;
if ((ym2612.OPN.ST.mode & 0xC0) && c == 2) {
/* 3 slot mode */
const FM_3SLOT *SL3 = &ym2612.OPN.SL3;
crct.incr1 = update_lfo_phase(&crct.CH->SLOT[SLOT1], freqbase, SL3->block_fnum[1], SL3->kcode[1]);
crct.incr2 = update_lfo_phase(&crct.CH->SLOT[SLOT2], freqbase, SL3->block_fnum[2], SL3->kcode[2]);
crct.incr3 = update_lfo_phase(&crct.CH->SLOT[SLOT3], freqbase, SL3->block_fnum[0], SL3->kcode[0]);
}
else {
crct.incr1 = update_lfo_phase(&crct.CH->SLOT[SLOT1], freqbase, block_fnum, kcode);
crct.incr2 = update_lfo_phase(&crct.CH->SLOT[SLOT2], freqbase, block_fnum, kcode);
crct.incr3 = update_lfo_phase(&crct.CH->SLOT[SLOT3], freqbase, block_fnum, kcode);
}
crct.incr4 = update_lfo_phase(&crct.CH->SLOT[SLOT4], freqbase, block_fnum, kcode);
}
else /* no LFO phase modulation */
{
@@ -1339,16 +1357,16 @@ static int chan_render(s32 *buffer, int length, int c, UINT32 flags) // flags: s
}
/* update phase increment and envelope generator */
static INLINE void refresh_fc_eg_slot(FM_SLOT *SLOT, int fc, int kc)
static void refresh_incr_eg_slot(FM_SLOT *SLOT, UINT32 freqbase, UINT32 fnum, UINT32 kc)
{
int ksr, fdt;
int ksr;
/* (frequency) phase increment counter */
fdt = fc+SLOT->DT[kc];
/* detect overflow */
// if (fdt < 0) fdt += fn_table[0x7ff*2] >> (7-blk-1);
if (fdt < 0) fdt += fn_table[0x7ff*2] >> 2;
SLOT->Incr = fdt*SLOT->mul >> 1;
SLOT->Incr = get_phase_increment(SLOT, fnum << 1, kc >> 2, kc);
if (SLOT->detune_overflow)
// always force the native rate phase increment, seems to sound a bit better when w/o filter
SLOT->Incr <<= FREQ_SH-10;
else
SLOT->Incr = SLOT->Incr * freqbase >> (FREQBASE_SH - (FREQ_SH-10));
ksr = kc >> SLOT->KSR;
if( SLOT->ksr != ksr )
@@ -1389,46 +1407,30 @@ static INLINE void refresh_fc_eg_slot(FM_SLOT *SLOT, int fc, int kc)
}
/* update phase increment counters */
static INLINE void refresh_fc_eg_chan(FM_CH *CH)
static INLINE void refresh_fc_eg_chan(FM_CH *CH, UINT32 freqbase)
{
if( CH->SLOT[SLOT1].Incr==-1){
int fc = CH->fc;
int kc = CH->kcode;
refresh_fc_eg_slot(&CH->SLOT[SLOT1] , fc , kc );
refresh_fc_eg_slot(&CH->SLOT[SLOT2] , fc , kc );
refresh_fc_eg_slot(&CH->SLOT[SLOT3] , fc , kc );
refresh_fc_eg_slot(&CH->SLOT[SLOT4] , fc , kc );
}
}
static INLINE void refresh_fc_eg_chan_sl3(void)
{
if( ym2612.CH[2].SLOT[SLOT1].Incr==-1)
if (CH->SLOT[SLOT1].Incr == -1)
{
refresh_fc_eg_slot(&ym2612.CH[2].SLOT[SLOT1], ym2612.OPN.SL3.fc[1], ym2612.OPN.SL3.kcode[1] );
refresh_fc_eg_slot(&ym2612.CH[2].SLOT[SLOT2], ym2612.OPN.SL3.fc[2], ym2612.OPN.SL3.kcode[2] );
refresh_fc_eg_slot(&ym2612.CH[2].SLOT[SLOT3], ym2612.OPN.SL3.fc[0], ym2612.OPN.SL3.kcode[0] );
refresh_fc_eg_slot(&ym2612.CH[2].SLOT[SLOT4], ym2612.CH[2].fc , ym2612.CH[2].kcode );
int kc = CH->kcode;
int fnum = CH->block_fnum & 0x7ff;
refresh_incr_eg_slot(&CH->SLOT[SLOT1], freqbase, fnum, kc);
refresh_incr_eg_slot(&CH->SLOT[SLOT2], freqbase, fnum, kc);
refresh_incr_eg_slot(&CH->SLOT[SLOT3], freqbase, fnum, kc);
refresh_incr_eg_slot(&CH->SLOT[SLOT4], freqbase, fnum, kc);
}
}
/* initialize time tables */
static void init_timetables(const UINT8 *dttable)
static INLINE void refresh_fc_eg_chan_sl3(FM_CH *CH2, const FM_3SLOT *SL3, UINT32 freqbase)
{
int i,d;
double rate;
/* DeTune table */
for (d = 0;d <= 3;d++){
for (i = 0;i <= 31;i++){
rate = ((double)dttable[d*32 + i]) * ym2612.OPN.ST.freqbase * (1<<(FREQ_SH-10));
ym2612.OPN.ST.dt_tab[d][i] = (INT32) rate;
ym2612.OPN.ST.dt_tab[d+4][i] = -ym2612.OPN.ST.dt_tab[d][i];
}
if (CH2->SLOT[SLOT1].Incr == -1)
{
refresh_incr_eg_slot(&CH2->SLOT[SLOT1], freqbase, SL3->block_fnum[1] & 0x7ff, SL3->kcode[1]);
refresh_incr_eg_slot(&CH2->SLOT[SLOT2], freqbase, SL3->block_fnum[2] & 0x7ff, SL3->kcode[2]);
refresh_incr_eg_slot(&CH2->SLOT[SLOT3], freqbase, SL3->block_fnum[0] & 0x7ff, SL3->kcode[0]);
refresh_incr_eg_slot(&CH2->SLOT[SLOT4], freqbase, CH2->block_fnum & 0x7ff, CH2->kcode);
}
}
static void reset_channels(FM_CH *CH)
{
int c,s;
@@ -1441,21 +1443,16 @@ static void reset_channels(FM_CH *CH)
for( c = 0 ; c < 6 ; c++ )
{
CH[c].fc = 0;
memset(&CH[c], 0, sizeof(CH[c]));
for(s = 0 ; s < 4 ; s++ )
{
CH[c].SLOT[s].Incr = -1;
CH[c].SLOT[s].key = 0;
CH[c].SLOT[s].phase = 0;
CH[c].SLOT[s].ar = CH[c].SLOT[s].ksr = 0;
CH[c].SLOT[s].ar_ksr = 0;
CH[c].SLOT[s].ssg = CH[c].SLOT[s].ssgn = 0;
CH[c].SLOT[s].state= EG_OFF;
CH[c].SLOT[s].state = EG_OFF;
CH[c].SLOT[s].volume = MAX_ATT_INDEX;
CH[c].SLOT[s].vol_out = MAX_ATT_INDEX;
}
CH[c].mem_value = CH[c].op1_out = 0;
}
memset(&ym2612.OPN.SL3, 0, sizeof(ym2612.OPN.SL3));
ym2612.slot_mask = 0;
ym2612.ssg_mask = 0;
}
@@ -1593,19 +1590,8 @@ static void OPNSetPres(int pres)
ym2612.OPN.eg_timer_add = (1<<EG_SH) * freqbase;
ym2612.OPN.ST.freqbase = freqbase;
/* make time tables */
init_timetables( dt_tab );
/* there are 2048 FNUMs that can be generated using FNUM/BLK registers
but LFO works with one more bit of a precision so we really need 4096 elements */
/* calculate fnumber -> increment counter table */
for(i = 0; i < 4096; i++)
{
/* freq table for octave 7 */
/* OPN phase increment counter = 20bit */
fn_table[i] = (UINT32)( (double)i * 32 * ym2612.OPN.ST.freqbase * (1<<(FREQ_SH-10)) ); /* -10 because chip works with 10.10 fixed point, while we use 16.16 */
}
ym2612.OPN.ST.freqbase_ui = round((1 << FREQBASE_SH) * freqbase);
//printf("freqbase %f %x\n", freqbase, ym2612.OPN.ST.freqbase_ui);
/* LFO freq. table */
for(i = 0; i < 8; i++)
@@ -1678,8 +1664,6 @@ static int OPNWriteReg(int r, int v)
UINT8 blk = ym2612.OPN.ST.fn_h >> 3;
/* keyscale code */
CH->kcode = (blk<<2) | opn_fktable[fn >> 7];
/* phase increment counter */
CH->fc = fn_table[fn*2]>>(7-blk);
/* store fnum in clear form for LFO PM calculations */
CH->block_fnum = (blk<<11) | fn;
@@ -1698,8 +1682,6 @@ static int OPNWriteReg(int r, int v)
UINT8 blk = ym2612.OPN.SL3.fn_h>>3;
/* keyscale code */
ym2612.OPN.SL3.kcode[c]= (blk<<2) | opn_fktable[fn >> 7];
/* phase increment counter */
ym2612.OPN.SL3.fc[c] = fn_table[fn*2]>>(7-blk);
ym2612.OPN.SL3.block_fnum[c] = (blk<<11) | fn;
ym2612.CH[2].SLOT[SLOT1].Incr=-1;
}
@@ -1760,6 +1742,7 @@ static int OPNWriteReg(int r, int v)
/* Generate samples for YM2612 */
int YM2612UpdateOne_(s32 *buffer, int length, int stereo, int is_buf_empty)
{
UINT32 freqbase = ym2612.OPN.ST.freqbase_ui;
int pan;
int active_chs = 0;
int flags = stereo ? 1:0;
@@ -1786,16 +1769,16 @@ int YM2612UpdateOne_(s32 *buffer, int length, int stereo, int is_buf_empty)
}
*/
/* refresh PG and EG */
refresh_fc_eg_chan( &ym2612.CH[0] );
refresh_fc_eg_chan( &ym2612.CH[1] );
refresh_fc_eg_chan(&ym2612.CH[0], freqbase);
refresh_fc_eg_chan(&ym2612.CH[1], freqbase);
if( (ym2612.OPN.ST.mode & 0xc0) )
/* 3SLOT MODE */
refresh_fc_eg_chan_sl3();
refresh_fc_eg_chan_sl3(&ym2612.CH[2], &ym2612.OPN.SL3, freqbase);
else
refresh_fc_eg_chan( &ym2612.CH[2] );
refresh_fc_eg_chan( &ym2612.CH[3] );
refresh_fc_eg_chan( &ym2612.CH[4] );
refresh_fc_eg_chan( &ym2612.CH[5] );
refresh_fc_eg_chan(&ym2612.CH[2], freqbase);
refresh_fc_eg_chan(&ym2612.CH[3], freqbase);
refresh_fc_eg_chan(&ym2612.CH[4], freqbase);
refresh_fc_eg_chan(&ym2612.CH[5], freqbase);
pan = ym2612.OPN.pan;
@@ -2253,11 +2236,10 @@ int YM2612PicoStateLoad2(int *tat, int *tbt, int *busy)
static size_t save_slot(u8 *buf, const FM_SLOT *slot)
{
size_t tmp, b = 0;
size_t b = 0;
b++; // length, assumes slot state won't grow beyond 255
tmp = (slot->DT - ym2612.OPN.ST.dt_tab[0]) / sizeof(ym2612.OPN.ST.dt_tab[0]);
save_u8_(buf, &b, tmp);
save_u8_(buf, &b, slot->detune);
save_u8_(buf, &b, slot->ar);
save_u8_(buf, &b, slot->d1r);
save_u8_(buf, &b, slot->d2r);
@@ -2283,9 +2265,8 @@ static size_t save_slot(u8 *buf, const FM_SLOT *slot)
static void load_slot(const u8 *buf, FM_SLOT *slot)
{
size_t b = 0;
u8 dt_reg;
dt_reg = load_u8_(buf, &b);
slot->detune = load_u8_(buf, &b);
slot->ar = load_u8_(buf, &b);
slot->d1r = load_u8_(buf, &b);
slot->d2r = load_u8_(buf, &b);
@@ -2301,8 +2282,6 @@ static void load_slot(const u8 *buf, FM_SLOT *slot)
slot->ssg = load_u8_(buf, &b);
slot->ssgn = load_u8_(buf, &b);
assert(dt_reg < 8);
slot->DT = ym2612.OPN.ST.dt_tab[dt_reg & 7];
recalc_volout( slot );
// trigger a refresh
@@ -2338,7 +2317,6 @@ static size_t save_channel(u8 *buf, const FM_CH *ch)
static size_t load_channel(const u8 *buf, size_t size, FM_CH *ch)
{
size_t i, b = 0, slot_size = 0, ch_size;
u32 fn, blk;
for (i = 0; i < 4; i++) {
u8 size_next = load_u8_(buf, &slot_size);
@@ -2364,10 +2342,6 @@ static size_t load_channel(const u8 *buf, size_t size, FM_CH *ch)
ch->block_fnum = load_u16(buf, &b) & 0x3fff;
ch->AMmasks = load_u8_(buf, &b);
fn = ch->block_fnum & 0x7ff;
blk = ch->block_fnum >> 11;
ch->fc = fn_table[fn*2] >> (7 - blk);
assert(ch_size >= b - slot_size - 1);
return slot_size + 1 + ch_size;
}
@@ -2391,7 +2365,7 @@ size_t YM2612PicoStateSave3(void *buf_, size_t size)
save_u8_(buf, &b, ym2612.OPN.ST.address);
save_u8_(buf, &b, ym2612.OPN.ST.status);
save_u8_(buf, &b, ym2612.OPN.ST.mode);
save_u8_(buf, &b, ym2612.OPN.ST.flags);
save_u8_(buf, &b, ym2612.OPN.ST.flags); // incorrect, comes from options
// (timers are saved in CHUNK_FM_TIMERS)
save_u8_(buf, &b, ym2612.OPN.ST.fn_h);
save_u8_(buf, &b, ym2612.OPN.SL3.fn_h);
@@ -2433,17 +2407,12 @@ void YM2612PicoStateLoad3(const void *buf_, size_t size)
ym2612.OPN.ST.address = load_u8_(buf, &b);
ym2612.OPN.ST.status = load_u8_(buf, &b);
ym2612.OPN.ST.mode = load_u8_(buf, &b);
ym2612.OPN.ST.flags = load_u8_(buf, &b);
/*ym2612.OPN.ST.flags*/ load_u8_(buf, &b); // comes from UI options
ym2612.OPN.ST.fn_h = load_u8_(buf, &b);
ym2612.OPN.SL3.fn_h = load_u8_(buf, &b);
for (i = 0; i < 3; i++) {
u32 fn, blk;
ym2612.OPN.SL3.kcode[i] = load_u8_(buf, &b);
ym2612.OPN.SL3.block_fnum[i] = load_u16(buf, &b) & 0x3fff;
fn = ym2612.OPN.SL3.block_fnum[i] & 0x7ff;
blk = ym2612.OPN.SL3.block_fnum[i] >> 11;
ym2612.OPN.SL3.fc[i] = fn_table[fn*2] >> (7 - blk);
}
ym2612.OPN.pan = load_u16(buf, &b);
ym2612.OPN.eg_cnt = load_u16(buf, &b);
+11 -10
View File
@@ -26,7 +26,9 @@ typedef s32 INT32; /* signed 32bit */
/* struct describing a single operator (SLOT) */
typedef struct
{
INT32 *DT; /* #0x00 detune :dt_tab[DT] */
UINT8 detune; /* #0x00 detune */
UINT8 detune_overflow;
UINT8 pad0[2];
UINT8 ar; /* #0x04 attack rate */
UINT8 d1r; /* #0x05 decay rate */
UINT8 d2r; /* #0x06 sustain rate */
@@ -84,21 +86,22 @@ typedef struct
UINT8 kcode; /* +11 key code: */
UINT8 pad2;
UINT8 upd_cnt; /* eg update counter */
UINT32 fc; /* fnum,blk:adjusted to sample rate */
UINT32 pad3;
UINT32 block_fnum; /* current blk/fnum value for this slot (can be different betweeen slots of one channel in 3slot mode) */
/* LFO */
UINT8 AMmasks; /* AM enable flag */
UINT8 pad3[3];
UINT8 pad4[3];
} FM_CH;
typedef struct
{
int clock; /* master clock (Hz) */
int rate; /* sampling rate (Hz) */
double freqbase; /* 08 frequency base */
UINT8 address; /* 10 address register | need_save */
UINT8 status; /* 11 status flag | need_save */
double freqbase; /* frequency base */
UINT32 freqbase_ui;
UINT8 address; /* address register | need_save */
UINT8 status; /* status flag | need_save */
UINT8 mode; /* mode CSM / 3SLOT */
UINT8 flags; /* operational flags */
int TA; /* timer a */
@@ -106,11 +109,10 @@ typedef struct
//int TAT; /* timer a ticker | need_save */
UINT8 TB; /* timer b */
UINT8 fn_h; /* freq latch */
UINT8 pad2[2];
UINT8 status_latch; /* status latch by last read */
UINT8 pad2[1];
//int TBC; /* timer b maxval */
//int TBT; /* timer b ticker | need_save */
/* local time tables */
INT32 dt_tab[8][32];/* DeTune table */
} FM_ST;
#define ST_SSG 1
@@ -123,7 +125,6 @@ typedef struct
/* OPN 3slot struct */
typedef struct
{
UINT32 fc[3]; /* fnum3,blk3: calculated */
UINT8 fn_h; /* freq3 latch */
UINT8 kcode[3]; /* key code */
UINT32 block_fnum[3]; /* current fnum value for this slot (can be different betweeen slots of one channel in 3slot mode) */
+6 -2
View File
@@ -902,12 +902,14 @@ PICO_INTERNAL_ASM void PicoVideoWrite(u32 a,unsigned short d)
if ((pvid->reg[1]&0x40) &&
!(pvid->type == 1 && !(pvid->addr&1) && ((pvid->addr^SATaddr)&SATmask) && PicoMem.vram[pvid->addr>>1] == d) &&
!(pvid->type == 3 && PicoMem.cram[(pvid->addr>>1) & 0x3f] == (d & 0xeee)) &&
!(pvid->type == 5 && PicoMem.vsram[(pvid->addr>>1) & 0x3f] == (d & 0x7ff)))
!(pvid->type == 5 && PicoMem.vsram[(pvid->addr>>1) & 0x3f] == (d & 0x7ff))) {
// the vertical scroll value for this line must be read from VSRAM early,
// since the A/B tile row to be read depends on it. E.g. Skitchin, OD2
// in contrast, CRAM writes would have an immediate effect on the current
// pixel, so sync can be closer to start of actual image data
PicoVideoSync(InHblank(pvid->type == 3 ? 103 : 30)); // cram in Toy Story
static int skip_offs[] = { 30, 103, 13 }; // vram, cram (toy story), vsram (chaekopan)
PicoVideoSync(InHblank(skip_offs[pvid->type>>1]));
}
if (!(PicoIn.opt&POPT_DIS_VDP_FIFO))
{
@@ -967,6 +969,8 @@ PICO_INTERNAL_ASM void PicoVideoWrite(u32 a,unsigned short d)
lineenabled = (d&0x40) ? Pico.m.scanline + !skip: -1;
linedisabled = (d&0x40) ? -1 : Pico.m.scanline + !skip;
lineoffset = (skip ? SekCyclesDone() - Pico.t.m68c_line_start : 0);
} else if (num == 5 && pvid->reg[num] != d) {
PicoVideoSync(InHblank(105)); // chaekopan
} else if (((1<<num) & 0x738ff) && pvid->reg[num] != d)
// VDP regs 0-7,11-13,16-18 influence rendering, ignore all others
PicoVideoSync(InHblank(93)); // Toy Story
+1
View File
@@ -125,6 +125,7 @@ endif
SRCS_COMMON += $(R)pico/sound/sound.c $(R)pico/sound/resampler.c
SRCS_COMMON += $(R)pico/sound/sn76496.c $(R)pico/sound/ym2612.c
SRCS_COMMON += $(R)pico/sound/ym2413.c
SRCS_COMMON += $(R)pico/sound/vgm.c
ifneq "$(ARCH)$(asm_mix)" "arm1"
SRCS_COMMON += $(R)pico/sound/mix.c
endif
+5
View File
@@ -383,6 +383,11 @@ static int custom_read(menu_entry *me, const char *var, const char *val)
if (strcasecmp(val, indev_names[i]) == 0)
currentConfig.input_dev1 = i;
return 1;
case MA_OPT2_FM_CHIP:
PicoIn.opt &= ~POPT_FM_YM2612;
if (strcasecmp(val, "ym2612") == 0)
PicoIn.opt |= POPT_FM_YM2612;
return 1;
/* PSP */
case MA_OPT3_VSYNC:
+1 -1
View File
@@ -664,7 +664,7 @@ void emu_prep_defconfig(void)
defaultConfig.s_PicoOpt = POPT_EN_SNDFILTER|POPT_EN_GG_LCD|POPT_EN_YM2413 |
POPT_EN_STEREO|POPT_EN_FM|POPT_EN_PSG|POPT_EN_Z80 |
POPT_EN_MCD_PCM|POPT_EN_MCD_CDDA|POPT_EN_MCD_GFX |
POPT_EN_DRC|POPT_ACC_SPRITES |
POPT_EN_DRC|POPT_ACC_SPRITES|POPT_FM_YM2612 |
POPT_EN_32X|POPT_EN_PWM;
defaultConfig.s_PsndRate = 44100;
defaultConfig.s_PicoRegion = 0; // auto
+2 -2
View File
@@ -49,7 +49,7 @@ void host_dasm(void *addr, int len)
if (name != NULL)
printf("%s:\n", name);
insn = *(unsigned long *)addr;
insn = *(unsigned *)addr;
printf(" %08lx %08lx ", (long)addr, insn);
if(disasm((uintptr_t)addr, insn, buf, sizeof(buf), &symaddr))
{
@@ -63,7 +63,7 @@ void host_dasm(void *addr, int len)
printf("%s\n", buf);
} else
printf("unknown (0x%08lx)\n", insn);
addr = (char *)addr + sizeof(long);
addr = (char *)addr + sizeof(unsigned);
}
}
#else
+21 -6
View File
@@ -41,6 +41,7 @@ static const char *rom_exts[] = {
"iso", "cso", "cue", "chd",
"32x",
"sms", "gg", "sg", "sc",
"vgm", "vgz",
NULL
};
@@ -745,11 +746,25 @@ static int menu_loop_keyconfig(int id, int keys)
}
// ------------ MD options menu ------------
static const char *fm_chips[] = { "YM3438", "YM2612" };
static int mh_opt_fmchip(int id, int keys)
{
if (keys & (PBTN_LEFT|PBTN_RIGHT))
PicoIn.opt ^= POPT_FM_YM2612;
return 0;
}
static const char *mgn_opt_fmchip(int id, int *offs)
{
int chip = !!(PicoIn.opt & POPT_FM_YM2612);
return fm_chips[chip];
}
static const char h_renderer[] = "16bit is more accurate, 8bit is faster";
static const char h_fmsound[] = "Disabling improves performance, but breaks sound";
static const char h_dacnoise[] = "FM chips in the 1st Mega Drive model have DAC noise,\n"
"newer models used different chips without this";
static const char h_fmchips[] = "Old Mega Drive models have YM2612, newer have YM3438\n"
"some games only work with a specific chip type";
static const char h_fmfilter[] = "Improves sound accuracy but is noticeably slower,\n"
"best quality if native rate isn't working";
static const char h_picopen[] = "Enabling resets Pico display and d-pad input back to\n"
@@ -758,9 +773,9 @@ static const char h_picopen[] = "Enabling resets Pico display and d-pad input b
static menu_entry e_menu_md_options[] =
{
mee_enum_h ("Renderer", MA_OPT_RENDERER, currentConfig.renderer, renderer_names, h_renderer),
mee_onoff_h ("FM audio", MA_OPT2_ENABLE_YM2612, PicoIn.opt, POPT_EN_FM, h_fmsound),
mee_onoff_h ("FM audio", MA_OPT2_ENABLE_FM, PicoIn.opt, POPT_EN_FM, h_fmsound),
mee_cust_h ("FM chip", MA_OPT2_FM_CHIP, mh_opt_fmchip, mgn_opt_fmchip, h_fmchips),
mee_onoff_h ("FM filter", MA_OPT_FM_FILTER, PicoIn.opt, POPT_EN_FM_FILTER, h_fmfilter),
mee_onoff_h ("FM DAC noise", MA_OPT2_ENABLE_YM_DAC, PicoIn.opt, POPT_EN_FM_DAC, h_dacnoise),
mee_onoff_h ("Pen button shows screen", MA_OPT_PICO_PEN, currentConfig.EmuOpt, EOPT_PICO_PEN, h_picopen),
mee_end,
};
@@ -1821,9 +1836,9 @@ static menu_entry e_menu_hidden[] =
mee_onoff("autoload savestates", MA_OPT_AUTOLOAD_SAVE, g_autostateld_opt, 1),
mee_onoff("SDL fullscreen mode", MA_OPT_VOUT_FULL, plat_target.vout_fullscreen, 1),
mee_onoff("Emulate Z80", MA_OPT2_ENABLE_Z80, PicoIn.opt, POPT_EN_Z80),
mee_onoff("Emulate YM2612 (FM)", MA_OPT2_ENABLE_YM2612, PicoIn.opt, POPT_EN_FM),
mee_onoff("Emulate YM2612 (FM)", MA_OPT2_ENABLE_FM, PicoIn.opt, POPT_EN_FM),
mee_onoff("Disable YM2612 SSG-EG", MA_OPT2_DISABLE_YM_SSG,PicoIn.opt, POPT_DIS_FM_SSGEG),
mee_onoff("Enable YM2612 DAC noise", MA_OPT2_ENABLE_YM_DAC, PicoIn.opt, POPT_EN_FM_DAC),
mee_onoff("FM DAC noise", MA_OPT2_FM_CHIP, PicoIn.opt, POPT_FM_YM2612),
mee_onoff("Emulate SN76496 (PSG)", MA_OPT2_ENABLE_SN76496,PicoIn.opt, POPT_EN_PSG),
mee_onoff("Scale/Rot. fx", MA_CDOPT_SCALEROT_CHIP,PicoIn.opt, POPT_EN_MCD_GFX),
mee_onoff("32X enabled", MA_32XOPT_ENABLE_32X, PicoIn.opt, POPT_EN_32X),
+2 -2
View File
@@ -61,9 +61,9 @@ typedef enum
MA_OPT2_DBLBUFF, /* giz */
MA_OPT2_VSYNC,
MA_OPT2_ENABLE_Z80,
MA_OPT2_ENABLE_YM2612,
MA_OPT2_ENABLE_FM,
MA_OPT2_DISABLE_YM_SSG,
MA_OPT2_ENABLE_YM_DAC,
MA_OPT2_FM_CHIP,
MA_OPT2_ENABLE_SN76496,
MA_OPT2_ENABLE_YM2413,
MA_OPT2_ENABLE_GGLCD,
+124
View File
@@ -0,0 +1,124 @@
/*
* PicoDrive
* (C) notaz, 2010,2013
*
* This work is licensed under the terms of MAME license.
* See COPYING file in the top-level directory.
*/
#include <stdio.h>
#include <string.h>
#include <pico/pico_int.h>
#include <pico/sound/mix.h>
#ifdef USE_TREMOR
#include "tremor/ivorbisfile.h"
#define ov_read(vf,b,l,be,w,s,ip) (ov_read)(vf,b,l,ip)
#else
#include <vorbis/vorbisfile.h>
#define ov_time_total(vf,ix) (ov_time_total)(vf,ix)*1000
#endif
static OggVorbis_File ogg_current_file;
static int ogg_current_index;
static int cdda_out_pos;
static int decoder_active;
// need this as ov_clear would close the FILE* otherwise
static int ov_fseek(void *f, ogg_int64_t off, int wence)
{ return fseek(f, off, wence); }
static size_t ov_fread(void *buf, size_t sz, size_t n, void *f)
{ return fread(buf, sz, n, f); }
static long ov_ftell(void *f)
{ return ftell(f); }
static ov_callbacks ogg_cb = { ov_fread, ov_fseek, NULL /*fclose*/, ov_ftell };
int ogg_get_length(void *f_)
{
FILE *f = f_;
int fs, ret;
ret = ov_open_callbacks(f, &ogg_current_file, NULL, 0, ogg_cb);
if (ret < 0)
return ret;
fs = ov_time_total(&ogg_current_file, -1);
ov_clear(&ogg_current_file);
return fs;
}
void ogg_start_play(void *f_, int sample_offset)
{
FILE *f = f_;
int ret;
cdda_out_pos = 0;
decoder_active = 0;
if (!(PicoIn.opt & POPT_EN_MCD_CDDA) || f == NULL) // cdda disabled or no file?
return;
fseek(f, 0, SEEK_SET);
ret = ov_open_callbacks(f, &ogg_current_file, NULL, 0, ogg_cb);
if (ret)
return;
ogg_current_index = 0;
// seek..
ov_pcm_seek(&ogg_current_file, sample_offset);
decoder_active = 1;
}
void ogg_stop_play(void)
{
if (decoder_active)
ov_clear(&ogg_current_file);
decoder_active = 0;
}
void ogg_update(s32 *buffer, int length, int stereo)
{
int length_ogg;
void (*mix_samples)(s32 *dest_buf, short *mp3_buf, int count, int fac16);
if (!decoder_active)
return;
length_ogg = length * Pico.snd.cdda_mult >> 16;
mix_samples = mix_16h_to_32_resample_stereo;
if (!stereo)
mix_samples = mix_16h_to_32_resample_mono;
if (1152 - cdda_out_pos >= length_ogg) {
mix_samples(buffer, cdda_out_buffer + cdda_out_pos * 2,
length, Pico.snd.cdda_mult);
cdda_out_pos += length_ogg;
} else {
int left = (1152 - cdda_out_pos) * Pico.snd.cdda_div >> 16;
int ret, sm = stereo ? 2 : 1;
if (left > 0)
mix_samples(buffer, cdda_out_buffer + cdda_out_pos * 2,
left, Pico.snd.cdda_mult);
for (length_ogg = 4*1152; length_ogg > 0; ) {
ret = ov_read(&ogg_current_file,
(char *)cdda_out_buffer + (4*1152 - length_ogg),
length_ogg, !CPU_IS_LE,2,1, &ogg_current_index);
if (ret > 0)
length_ogg -= ret;
else
break;
}
if (ret > 0) {
mix_samples(buffer + left * sm, cdda_out_buffer,
length-left, Pico.snd.cdda_mult);
cdda_out_pos = (length-left) * Pico.snd.cdda_mult >> 16;
} else
cdda_out_pos = 0;
}
}
+4
View File
@@ -0,0 +1,4 @@
void ogg_start_play(void *f_, int sample_offset);
void ogg_stop_play(void);
void ogg_update(s32 *buffer, int length, int stereo);
+6 -9
View File
@@ -131,7 +131,7 @@ void bgr_to_uyvy_init(void)
#if CPU_IS_LE
yuv_uyvy[i].vyu = (yuv_v[r-y + 32] << 16) | (yuv_y[y] << 8) | yuv_u[b-y + 32];
#else
yuv_uyvy[i].vyu = (yuv_v[b-y + 32] << 16) | (yuv_y[y] << 8) | yuv_u[r-y + 32];
yuv_uyvy[i].vyu = (yuv_u[b-y + 32] << 16) | (yuv_y[y] << 8) | yuv_v[r-y + 32];
#endif
}
}
@@ -367,17 +367,14 @@ void plat_video_menu_update(void)
// WM may grab input while resizing the window; our own window resizing
// is only safe if the WM isn't active anymore, so try to grab input.
if (plat_sdl_is_windowed() && SDL_WM_GrabInput(SDL_GRAB_ON) == SDL_GRAB_ON) {
// w/h might change in resize callback
int w, h;
do {
w = g_menuscreen_w, h = g_menuscreen_h;
plat_sdl_change_video_mode(w, h, 1);
} while (w != g_menuscreen_w || h != g_menuscreen_h);
plat_sdl_change_video_mode(g_menuscreen_w, g_menuscreen_h, 1);
// w/h might change in change_video_mode, e.g. for fullscreen
g_menuscreen_w = plat_sdl_screen->w;
g_menuscreen_h = plat_sdl_screen->h;
plat_sdl_gl_scaling(currentConfig.filter);
SDL_WM_GrabInput(SDL_GRAB_OFF);
resize_buffers();
}
resize_buffers();
}
void plat_video_menu_enter(int is_rom_loaded)
+19
View File
@@ -0,0 +1,19 @@
*** 20020517: 1.0.2 ***
Playback bugfix to floor1; mode mistakenly used for sizing instead
of blockflag
*** 20020515: 1.0.1 ***
Added complete API documentation to source tarball. No code
changes.
*** 20020412: 1.0.1 ***
Fixed a clipping bug that affected ARM processors; negative
overflows were being properly clipped, but then clobbered to
positive by the positive overflow chec (asm_arm.h:CLIP_TO_15)
*** 20020403: 1.0.0 ***
Initial version
+28
View File
@@ -0,0 +1,28 @@
Copyright (c) 2002, Xiph.org Foundation
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
- Neither the name of the Xiph.org Foundation nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``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 THE FOUNDATION
OR CONTRIBUTORS 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.
+46
View File
@@ -0,0 +1,46 @@
This README covers the Ogg Vorbis 'Tremor' integer playback codec
source as of date 2002 09 02, version 1.0.0.
******
The C source in this package will build on any ANSI C compiler and
function completely and properly on any platform. The included build
system assumes GNU build system and make tools (m4, automake,
autoconf, libtool and gmake). GCC is not required, although GCC is
the most tested compiler. To build using GNU tools, type in the
source directory:
./autogen.sh
make
Currently, the source implements playback in pure C on all platforms
except ARM, where a [currently] small amount of assembly (see
asm_arm.h) is used to implement 64 bit math operations and fast LSP
computation. If building on ARM without the benefit of GNU build
system tools, be sure that '_ARM_ASSEM_' is #defined by the build
system if this assembly is desired, else the resulting library will
use whatever 64 bit math builtins the compiler implements.
No math library is required by this source. No floating point
operations are used at any point in either setup or decode. This
decoder library will properly decode any past, current or future
Vorbis I file or stream.
********
The build system produces a static and [when supported by the OS]
dynamic library named 'libvorbisidec'. This library exposes an API
nearly identical to the BSD reference library's 'libvorbisfile',
including all the features familiar to users of vorbisfile. This API
is similar enough that the proper header file to include is named
'ivorbisfile.h' [included in the source build directory]. Lower level
libvorbis-style headers and structures are in 'ivorbiscodec.h'
[included in the source build directory]. A simple example program,
ivorbisfile_example.c, can be built with 'make example'.
********
Detailed Tremor API Documentation begins at doc/index.html
Monty
xiph.org
+245
View File
@@ -0,0 +1,245 @@
/********************************************************************
* *
* THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. *
* *
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 *
* BY THE Xiph.Org FOUNDATION http://www.xiph.org/ *
* *
********************************************************************
function: arm7 and later wide math functions
********************************************************************/
#ifdef _ARM_ASSEM_
#if !defined(_V_WIDE_MATH) && !defined(_LOW_ACCURACY_)
#define _V_WIDE_MATH
static inline ogg_int32_t MULT32(ogg_int32_t x, ogg_int32_t y) {
int lo,hi;
asm volatile("smull\t%0, %1, %2, %3"
: "=&r"(lo),"=&r"(hi)
: "%r"(x),"r"(y)
: "cc");
return(hi);
}
static inline ogg_int32_t MULT31(ogg_int32_t x, ogg_int32_t y) {
return MULT32(x,y)<<1;
}
static inline ogg_int32_t MULT31_SHIFT15(ogg_int32_t x, ogg_int32_t y) {
int lo,hi;
asm volatile("smull %0, %1, %2, %3\n\t"
"movs %0, %0, lsr #15\n\t"
"adc %1, %0, %1, lsl #17\n\t"
: "=&r"(lo),"=&r"(hi)
: "%r"(x),"r"(y)
: "cc");
return(hi);
}
#define MB() asm volatile ("" : : : "memory")
static inline void XPROD32(ogg_int32_t a, ogg_int32_t b,
ogg_int32_t t, ogg_int32_t v,
ogg_int32_t *x, ogg_int32_t *y)
{
int x1, y1, l;
asm( "smull %0, %1, %4, %6\n\t"
"smlal %0, %1, %5, %7\n\t"
"rsb %3, %4, #0\n\t"
"smull %0, %2, %5, %6\n\t"
"smlal %0, %2, %3, %7"
: "=&r" (l), "=&r" (x1), "=&r" (y1), "=r" (a)
: "3" (a), "r" (b), "r" (t), "r" (v)
: "cc" );
*x = x1;
MB();
*y = y1;
}
static inline void XPROD31(ogg_int32_t a, ogg_int32_t b,
ogg_int32_t t, ogg_int32_t v,
ogg_int32_t *x, ogg_int32_t *y)
{
int x1, y1, l;
asm( "smull %0, %1, %4, %6\n\t"
"smlal %0, %1, %5, %7\n\t"
"rsb %3, %4, #0\n\t"
"smull %0, %2, %5, %6\n\t"
"smlal %0, %2, %3, %7"
: "=&r" (l), "=&r" (x1), "=&r" (y1), "=r" (a)
: "3" (a), "r" (b), "r" (t), "r" (v)
: "cc" );
*x = x1 << 1;
MB();
*y = y1 << 1;
}
static inline void XNPROD31(ogg_int32_t a, ogg_int32_t b,
ogg_int32_t t, ogg_int32_t v,
ogg_int32_t *x, ogg_int32_t *y)
{
int x1, y1, l;
asm( "rsb %2, %4, #0\n\t"
"smull %0, %1, %3, %5\n\t"
"smlal %0, %1, %2, %6\n\t"
"smull %0, %2, %4, %5\n\t"
"smlal %0, %2, %3, %6"
: "=&r" (l), "=&r" (x1), "=&r" (y1)
: "r" (a), "r" (b), "r" (t), "r" (v)
: "cc" );
*x = x1 << 1;
MB();
*y = y1 << 1;
}
#endif
#ifndef _V_CLIP_MATH
#define _V_CLIP_MATH
static inline ogg_int32_t CLIP_TO_15(ogg_int32_t x) {
int tmp;
asm volatile("subs %1, %0, #32768\n\t"
"movpl %0, #0x7f00\n\t"
"orrpl %0, %0, #0xff\n"
"adds %1, %0, #32768\n\t"
"movmi %0, #0x8000"
: "+r"(x),"=r"(tmp)
:
: "cc");
return(x);
}
#endif
#ifndef _V_LSP_MATH_ASM
#define _V_LSP_MATH_ASM
static inline void lsp_loop_asm(ogg_uint32_t *qip,ogg_uint32_t *pip,
ogg_int32_t *qexpp,
ogg_int32_t *ilsp,ogg_int32_t wi,
ogg_int32_t m){
ogg_uint32_t qi=*qip,pi=*pip;
ogg_int32_t qexp=*qexpp;
asm("mov r0,%3;"
"movs r1,%5,asr#1;"
"add r0,r0,r1,lsl#3;"
"beq 2f;\n"
"1:"
"ldmdb r0!,{r1,r3};"
"subs r1,r1,%4;" //ilsp[j]-wi
"rsbmi r1,r1,#0;" //labs(ilsp[j]-wi)
"umull %0,r2,r1,%0;" //qi*=labs(ilsp[j]-wi)
"subs r1,r3,%4;" //ilsp[j+1]-wi
"rsbmi r1,r1,#0;" //labs(ilsp[j+1]-wi)
"umull %1,r3,r1,%1;" //pi*=labs(ilsp[j+1]-wi)
"cmn r2,r3;" // shift down 16?
"beq 0f;"
"add %2,%2,#16;"
"mov %0,%0,lsr #16;"
"orr %0,%0,r2,lsl #16;"
"mov %1,%1,lsr #16;"
"orr %1,%1,r3,lsl #16;"
"0:"
"cmp r0,%3;\n"
"bhi 1b;\n"
"2:"
// odd filter assymetry
"ands r0,%5,#1;\n"
"beq 3f;\n"
"add r0,%3,%5,lsl#2;\n"
"ldr r1,[r0,#-4];\n"
"mov r0,#0x4000;\n"
"subs r1,r1,%4;\n" //ilsp[j]-wi
"rsbmi r1,r1,#0;\n" //labs(ilsp[j]-wi)
"umull %0,r2,r1,%0;\n" //qi*=labs(ilsp[j]-wi)
"umull %1,r3,r0,%1;\n" //pi*=labs(ilsp[j+1]-wi)
"cmn r2,r3;\n" // shift down 16?
"beq 3f;\n"
"add %2,%2,#16;\n"
"mov %0,%0,lsr #16;\n"
"orr %0,%0,r2,lsl #16;\n"
"mov %1,%1,lsr #16;\n"
"orr %1,%1,r3,lsl #16;\n"
//qi=(pi>>shift)*labs(ilsp[j]-wi);
//pi=(qi>>shift)*labs(ilsp[j+1]-wi);
//qexp+=shift;
//}
/* normalize to max 16 sig figs */
"3:"
"mov r2,#0;"
"orr r1,%0,%1;"
"tst r1,#0xff000000;"
"addne r2,r2,#8;"
"movne r1,r1,lsr #8;"
"tst r1,#0x00f00000;"
"addne r2,r2,#4;"
"movne r1,r1,lsr #4;"
"tst r1,#0x000c0000;"
"addne r2,r2,#2;"
"movne r1,r1,lsr #2;"
"tst r1,#0x00020000;"
"addne r2,r2,#1;"
"movne r1,r1,lsr #1;"
"tst r1,#0x00010000;"
"addne r2,r2,#1;"
"mov %0,%0,lsr r2;"
"mov %1,%1,lsr r2;"
"add %2,%2,r2;"
: "+r"(qi),"+r"(pi),"+r"(qexp)
: "r"(ilsp),"r"(wi),"r"(m)
: "r0","r1","r2","r3","cc");
*qip=qi;
*pip=pi;
*qexpp=qexp;
}
static inline void lsp_norm_asm(ogg_uint32_t *qip,ogg_int32_t *qexpp){
ogg_uint32_t qi=*qip;
ogg_int32_t qexp=*qexpp;
asm("tst %0,#0x0000ff00;"
"moveq %0,%0,lsl #8;"
"subeq %1,%1,#8;"
"tst %0,#0x0000f000;"
"moveq %0,%0,lsl #4;"
"subeq %1,%1,#4;"
"tst %0,#0x0000c000;"
"moveq %0,%0,lsl #2;"
"subeq %1,%1,#2;"
"tst %0,#0x00008000;"
"moveq %0,%0,lsl #1;"
"subeq %1,%1,#1;"
: "+r"(qi),"+r"(qexp)
:
: "cc");
*qip=qi;
*qexpp=qexp;
}
#endif
#endif
+131
View File
@@ -0,0 +1,131 @@
/********************************************************************
* *
* THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. *
* *
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 *
* BY THE Xiph.Org FOUNDATION http://www.xiph.org/ *
* *
********************************************************************
function: backend and mapping structures
********************************************************************/
/* this is exposed up here because we need it for static modes.
Lookups for each backend aren't exposed because there's no reason
to do so */
#ifndef _vorbis_backend_h_
#define _vorbis_backend_h_
#include "codec_internal.h"
/* this would all be simpler/shorter with templates, but.... */
/* Transform backend generic *************************************/
/* only mdct right now. Flesh it out more if we ever transcend mdct
in the transform domain */
/* Floor backend generic *****************************************/
typedef struct{
vorbis_info_floor *(*unpack)(vorbis_info *,oggpack_buffer *);
vorbis_look_floor *(*look) (vorbis_dsp_state *,vorbis_info_mode *,
vorbis_info_floor *);
void (*free_info) (vorbis_info_floor *);
void (*free_look) (vorbis_look_floor *);
void *(*inverse1) (struct vorbis_block *,vorbis_look_floor *);
int (*inverse2) (struct vorbis_block *,vorbis_look_floor *,
void *buffer,ogg_int32_t *);
} vorbis_func_floor;
typedef struct{
int order;
long rate;
long barkmap;
int ampbits;
int ampdB;
int numbooks; /* <= 16 */
int books[16];
} vorbis_info_floor0;
#define VIF_POSIT 63
#define VIF_CLASS 16
#define VIF_PARTS 31
typedef struct{
int partitions; /* 0 to 31 */
int partitionclass[VIF_PARTS]; /* 0 to 15 */
int class_dim[VIF_CLASS]; /* 1 to 8 */
int class_subs[VIF_CLASS]; /* 0,1,2,3 (bits: 1<<n poss) */
int class_book[VIF_CLASS]; /* subs ^ dim entries */
int class_subbook[VIF_CLASS][8]; /* [VIF_CLASS][subs] */
int mult; /* 1 2 3 or 4 */
int postlist[VIF_POSIT+2]; /* first two implicit */
} vorbis_info_floor1;
/* Residue backend generic *****************************************/
typedef struct{
vorbis_info_residue *(*unpack)(vorbis_info *,oggpack_buffer *);
vorbis_look_residue *(*look) (vorbis_dsp_state *,vorbis_info_mode *,
vorbis_info_residue *);
void (*free_info) (vorbis_info_residue *);
void (*free_look) (vorbis_look_residue *);
int (*inverse) (struct vorbis_block *,vorbis_look_residue *,
ogg_int32_t **,int *,int);
} vorbis_func_residue;
typedef struct vorbis_info_residue0{
/* block-partitioned VQ coded straight residue */
long begin;
long end;
/* first stage (lossless partitioning) */
int grouping; /* group n vectors per partition */
int partitions; /* possible codebooks for a partition */
int partvals; /* partitions ^ groupbook dim */
int groupbook; /* huffbook for partitioning */
int secondstages[64]; /* expanded out to pointers in lookup */
int booklist[512]; /* list of second stage books */
} vorbis_info_residue0;
/* Mapping backend generic *****************************************/
typedef struct{
vorbis_info_mapping *(*unpack)(vorbis_info *,oggpack_buffer *);
vorbis_look_mapping *(*look) (vorbis_dsp_state *,vorbis_info_mode *,
vorbis_info_mapping *);
void (*free_info) (vorbis_info_mapping *);
void (*free_look) (vorbis_look_mapping *);
int (*inverse) (struct vorbis_block *vb,vorbis_look_mapping *);
} vorbis_func_mapping;
typedef struct vorbis_info_mapping0{
int submaps; /* <= 16 */
int chmuxlist[256]; /* up to 256 channels in a Vorbis stream */
int floorsubmap[16]; /* [mux] submap to floors */
int residuesubmap[16]; /* [mux] submap to residue */
int psy[2]; /* by blocktype; impulse/padding for short,
transition/normal for long */
int coupling_steps;
int coupling_mag[256];
int coupling_ang[256];
} vorbis_info_mapping0;
#endif
File diff suppressed because it is too large. Load diff
+497
View File
@@ -0,0 +1,497 @@
/********************************************************************
* *
* THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. *
* *
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 *
* BY THE Xiph.Org FOUNDATION http://www.xiph.org/ *
* *
********************************************************************
function: PCM data vector blocking, windowing and dis/reassembly
********************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ogg/ogg.h>
#include "ivorbiscodec.h"
#include "codec_internal.h"
#include "window.h"
#include "registry.h"
#include "misc.h"
static int ilog(unsigned int v){
int ret=0;
if(v)--v;
while(v){
ret++;
v>>=1;
}
return(ret);
}
/* pcm accumulator examples (not exhaustive):
<-------------- lW ---------------->
<--------------- W ---------------->
: .....|..... _______________ |
: .''' | '''_--- | |\ |
:.....''' |_____--- '''......| | \_______|
:.................|__________________|_______|__|______|
|<------ Sl ------>| > Sr < |endW
|beginSl |endSl | |endSr
|beginW |endlW |beginSr
|< lW >|
<--------------- W ---------------->
| | .. ______________ |
| | ' `/ | ---_ |
|___.'___/`. | ---_____|
|_______|__|_______|_________________|
| >|Sl|< |<------ Sr ----->|endW
| | |endSl |beginSr |endSr
|beginW | |endlW
mult[0] |beginSl mult[n]
<-------------- lW ----------------->
|<--W-->|
: .............. ___ | |
: .''' |`/ \ | |
:.....''' |/`....\|...|
:.........................|___|___|___|
|Sl |Sr |endW
| | |endSr
| |beginSr
| |endSl
|beginSl
|beginW
*/
/* block abstraction setup *********************************************/
#ifndef WORD_ALIGN
#define WORD_ALIGN 8
#endif
int vorbis_block_init(vorbis_dsp_state *v, vorbis_block *vb){
memset(vb,0,sizeof(*vb));
vb->vd=v;
vb->localalloc=0;
vb->localstore=NULL;
return(0);
}
void *_vorbis_block_alloc(vorbis_block *vb,long bytes){
bytes=(bytes+(WORD_ALIGN-1)) & ~(WORD_ALIGN-1);
if(bytes+vb->localtop>vb->localalloc){
/* can't just _ogg_realloc... there are outstanding pointers */
if(vb->localstore){
struct alloc_chain *link=(struct alloc_chain *)_ogg_malloc(sizeof(*link));
vb->totaluse+=vb->localtop;
link->next=vb->reap;
link->ptr=vb->localstore;
vb->reap=link;
}
/* highly conservative */
vb->localalloc=bytes;
vb->localstore=_ogg_malloc(vb->localalloc);
vb->localtop=0;
}
{
void *ret=(void *)(((char *)vb->localstore)+vb->localtop);
vb->localtop+=bytes;
return ret;
}
}
/* reap the chain, pull the ripcord */
void _vorbis_block_ripcord(vorbis_block *vb){
/* reap the chain */
struct alloc_chain *reap=vb->reap;
while(reap){
struct alloc_chain *next=reap->next;
_ogg_free(reap->ptr);
memset(reap,0,sizeof(*reap));
_ogg_free(reap);
reap=next;
}
/* consolidate storage */
if(vb->totaluse){
vb->localstore=_ogg_realloc(vb->localstore,vb->totaluse+vb->localalloc);
vb->localalloc+=vb->totaluse;
vb->totaluse=0;
}
/* pull the ripcord */
vb->localtop=0;
vb->reap=NULL;
}
int vorbis_block_clear(vorbis_block *vb){
_vorbis_block_ripcord(vb);
if(vb->localstore)_ogg_free(vb->localstore);
memset(vb,0,sizeof(*vb));
return(0);
}
static int _vds_init(vorbis_dsp_state *v,vorbis_info *vi){
int i;
codec_setup_info *ci=(codec_setup_info *)vi->codec_setup;
private_state *b=NULL;
if(ci==NULL) return 1;
memset(v,0,sizeof(*v));
b=(private_state *)(v->backend_state=_ogg_calloc(1,sizeof(*b)));
v->vi=vi;
b->modebits=ilog(ci->modes);
/* Vorbis I uses only window type 0 */
b->window[0]=_vorbis_window(0,ci->blocksizes[0]/2);
b->window[1]=_vorbis_window(0,ci->blocksizes[1]/2);
/* finish the codebooks */
if(!ci->fullbooks){
ci->fullbooks=(codebook *)_ogg_calloc(ci->books,sizeof(*ci->fullbooks));
for(i=0;i<ci->books;i++){
if(ci->book_param[i]==NULL)
goto abort_books;
if(vorbis_book_init_decode(ci->fullbooks+i,ci->book_param[i]))
goto abort_books;
/* decode codebooks are now standalone after init */
vorbis_staticbook_destroy(ci->book_param[i]);
ci->book_param[i]=NULL;
}
}
v->pcm_storage=ci->blocksizes[1];
v->pcm=(ogg_int32_t **)_ogg_malloc(vi->channels*sizeof(*v->pcm));
v->pcmret=(ogg_int32_t **)_ogg_malloc(vi->channels*sizeof(*v->pcmret));
for(i=0;i<vi->channels;i++)
v->pcm[i]=(ogg_int32_t *)_ogg_calloc(v->pcm_storage,sizeof(*v->pcm[i]));
/* all 1 (large block) or 0 (small block) */
/* explicitly set for the sake of clarity */
v->lW=0; /* previous window size */
v->W=0; /* current window size */
/* initialize all the mapping/backend lookups */
b->mode=(vorbis_look_mapping **)_ogg_calloc(ci->modes,sizeof(*b->mode));
for(i=0;i<ci->modes;i++){
int mapnum=ci->mode_param[i]->mapping;
int maptype=ci->map_type[mapnum];
b->mode[i]=_mapping_P[maptype]->look(v,ci->mode_param[i],
ci->map_param[mapnum]);
}
return 0;
abort_books:
for(i=0;i<ci->books;i++){
if(ci->book_param[i]!=NULL){
vorbis_staticbook_destroy(ci->book_param[i]);
ci->book_param[i]=NULL;
}
}
vorbis_dsp_clear(v);
return -1;
}
int vorbis_synthesis_restart(vorbis_dsp_state *v){
vorbis_info *vi=v->vi;
codec_setup_info *ci;
if(!v->backend_state)return -1;
if(!vi)return -1;
ci=vi->codec_setup;
if(!ci)return -1;
v->centerW=ci->blocksizes[1]/2;
v->pcm_current=v->centerW;
v->pcm_returned=-1;
v->granulepos=-1;
v->sequence=-1;
((private_state *)(v->backend_state))->sample_count=-1;
return(0);
}
int vorbis_synthesis_init(vorbis_dsp_state *v,vorbis_info *vi){
if(_vds_init(v,vi))return 1;
vorbis_synthesis_restart(v);
return 0;
}
void vorbis_dsp_clear(vorbis_dsp_state *v){
int i;
if(v){
vorbis_info *vi=v->vi;
codec_setup_info *ci=(codec_setup_info *)(vi?vi->codec_setup:NULL);
private_state *b=(private_state *)v->backend_state;
if(v->pcm){
for(i=0;i<vi->channels;i++)
if(v->pcm[i])_ogg_free(v->pcm[i]);
_ogg_free(v->pcm);
if(v->pcmret)_ogg_free(v->pcmret);
}
/* free mode lookups; these are actually vorbis_look_mapping structs */
if(ci){
for(i=0;i<ci->modes;i++){
int mapnum=ci->mode_param[i]->mapping;
int maptype=ci->map_type[mapnum];
if(b && b->mode)_mapping_P[maptype]->free_look(b->mode[i]);
}
}
if(b){
if(b->mode)_ogg_free(b->mode);
_ogg_free(b);
}
memset(v,0,sizeof(*v));
}
}
/* Unlike in analysis, the window is only partially applied for each
block. The time domain envelope is not yet handled at the point of
calling (as it relies on the previous block). */
int vorbis_synthesis_blockin(vorbis_dsp_state *v,vorbis_block *vb){
vorbis_info *vi=v->vi;
codec_setup_info *ci=(codec_setup_info *)vi->codec_setup;
private_state *b=v->backend_state;
int i,j;
if(v->pcm_current>v->pcm_returned && v->pcm_returned!=-1)return(OV_EINVAL);
v->lW=v->W;
v->W=vb->W;
v->nW=-1;
if((v->sequence==-1)||
(v->sequence+1 != vb->sequence)){
v->granulepos=-1; /* out of sequence; lose count */
b->sample_count=-1;
}
v->sequence=vb->sequence;
if(vb->pcm){ /* no pcm to process if vorbis_synthesis_trackonly
was called on block */
int n=ci->blocksizes[v->W]/2;
int n0=ci->blocksizes[0]/2;
int n1=ci->blocksizes[1]/2;
int thisCenter;
int prevCenter;
if(v->centerW){
thisCenter=n1;
prevCenter=0;
}else{
thisCenter=0;
prevCenter=n1;
}
/* v->pcm is now used like a two-stage double buffer. We don't want
to have to constantly shift *or* adjust memory usage. Don't
accept a new block until the old is shifted out */
/* overlap/add PCM */
for(j=0;j<vi->channels;j++){
/* the overlap/add section */
if(v->lW){
if(v->W){
/* large/large */
ogg_int32_t *pcm=v->pcm[j]+prevCenter;
ogg_int32_t *p=vb->pcm[j];
for(i=0;i<n1;i++)
pcm[i]+=p[i];
}else{
/* large/small */
ogg_int32_t *pcm=v->pcm[j]+prevCenter+n1/2-n0/2;
ogg_int32_t *p=vb->pcm[j];
for(i=0;i<n0;i++)
pcm[i]+=p[i];
}
}else{
if(v->W){
/* small/large */
ogg_int32_t *pcm=v->pcm[j]+prevCenter;
ogg_int32_t *p=vb->pcm[j]+n1/2-n0/2;
for(i=0;i<n0;i++)
pcm[i]+=p[i];
for(;i<n1/2+n0/2;i++)
pcm[i]=p[i];
}else{
/* small/small */
ogg_int32_t *pcm=v->pcm[j]+prevCenter;
ogg_int32_t *p=vb->pcm[j];
for(i=0;i<n0;i++)
pcm[i]+=p[i];
}
}
/* the copy section */
{
ogg_int32_t *pcm=v->pcm[j]+thisCenter;
ogg_int32_t *p=vb->pcm[j]+n;
for(i=0;i<n;i++)
pcm[i]=p[i];
}
}
if(v->centerW)
v->centerW=0;
else
v->centerW=n1;
/* deal with initial packet state; we do this using the explicit
pcm_returned==-1 flag otherwise we're sensitive to first block
being short or long */
if(v->pcm_returned==-1){
v->pcm_returned=thisCenter;
v->pcm_current=thisCenter;
}else{
v->pcm_returned=prevCenter;
v->pcm_current=prevCenter+
ci->blocksizes[v->lW]/4+
ci->blocksizes[v->W]/4;
}
}
/* track the frame number... This is for convenience, but also
making sure our last packet doesn't end with added padding. If
the last packet is partial, the number of samples we'll have to
return will be past the vb->granulepos.
This is not foolproof! It will be confused if we begin
decoding at the last page after a seek or hole. In that case,
we don't have a starting point to judge where the last frame
is. For this reason, vorbisfile will always try to make sure
it reads the last two marked pages in proper sequence */
if(b->sample_count==-1){
b->sample_count=0;
}else{
b->sample_count+=ci->blocksizes[v->lW]/4+ci->blocksizes[v->W]/4;
}
if(v->granulepos==-1){
if(vb->granulepos!=-1){ /* only set if we have a position to set to */
v->granulepos=vb->granulepos;
/* is this a short page? */
if(b->sample_count>v->granulepos){
/* corner case; if this is both the first and last audio page,
then spec says the end is cut, not beginning */
long extra=b->sample_count-vb->granulepos;
/* we use ogg_int64_t for granule positions because a
uint64 isn't universally available. Unfortunately,
that means granposes can be 'negative' and result in
extra being negative */
if(extra<0)
extra=0;
if(vb->eofflag){
/* trim the end */
/* no preceeding granulepos; assume we started at zero (we'd
have to in a short single-page stream) */
/* granulepos could be -1 due to a seek, but that would result
in a long coun`t, not short count */
/* Guard against corrupt/malicious frames that set EOP and
a backdated granpos; don't rewind more samples than we
actually have */
if(extra > v->pcm_current - v->pcm_returned)
extra = v->pcm_current - v->pcm_returned;
v->pcm_current-=extra;
}else{
/* trim the beginning */
v->pcm_returned+=extra;
if(v->pcm_returned>v->pcm_current)
v->pcm_returned=v->pcm_current;
}
}
}
}else{
v->granulepos+=ci->blocksizes[v->lW]/4+ci->blocksizes[v->W]/4;
if(vb->granulepos!=-1 && v->granulepos!=vb->granulepos){
if(v->granulepos>vb->granulepos){
long extra=v->granulepos-vb->granulepos;
if(extra)
if(vb->eofflag){
/* partial last frame. Strip the extra samples off */
/* Guard against corrupt/malicious frames that set EOP and
a backdated granpos; don't rewind more samples than we
actually have */
if(extra > v->pcm_current - v->pcm_returned)
extra = v->pcm_current - v->pcm_returned;
/* we use ogg_int64_t for granule positions because a
uint64 isn't universally available. Unfortunately,
that means granposes can be 'negative' and result in
extra being negative */
if(extra<0)
extra=0;
v->pcm_current-=extra;
} /* else {Shouldn't happen *unless* the bitstream is out of
spec. Either way, believe the bitstream } */
} /* else {Shouldn't happen *unless* the bitstream is out of
spec. Either way, believe the bitstream } */
v->granulepos=vb->granulepos;
}
}
/* Update, cleanup */
if(vb->eofflag)v->eofflag=1;
return(0);
}
/* pcm==NULL indicates we just want the pending samples, no more */
int vorbis_synthesis_pcmout(vorbis_dsp_state *v,ogg_int32_t ***pcm){
vorbis_info *vi=v->vi;
if(v->pcm_returned>-1 && v->pcm_returned<v->pcm_current){
if(pcm){
int i;
for(i=0;i<vi->channels;i++)
v->pcmret[i]=v->pcm[i]+v->pcm_returned;
*pcm=v->pcmret;
}
return(v->pcm_current-v->pcm_returned);
}
return(0);
}
int vorbis_synthesis_read(vorbis_dsp_state *v,int bytes){
if(bytes && v->pcm_returned+bytes>v->pcm_current)return(OV_EINVAL);
v->pcm_returned+=bytes;
return(0);
}
+24
View File
@@ -0,0 +1,24 @@
/********************************************************************
* *
* THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. *
* *
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2008 *
* BY THE Xiph.Org FOUNDATION http://www.xiph.org/ *
* *
********************************************************************
function: shared block functions
********************************************************************/
#ifndef _V_BLOCK_
#define _V_BLOCK_
extern void _vorbis_block_ripcord(vorbis_block *vb);
extern void *_vorbis_block_alloc(vorbis_block *vb,long bytes);
#endif
+391
View File
@@ -0,0 +1,391 @@
/********************************************************************
* *
* THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. *
* *
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 *
* BY THE Xiph.Org FOUNDATION http://www.xiph.org/ *
* *
********************************************************************
function: basic codebook pack/unpack/code/decode operations
********************************************************************/
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <ogg/ogg.h>
#include "ivorbiscodec.h"
#include "codebook.h"
#include "misc.h"
/* unpacks a codebook from the packet buffer into the codebook struct,
readies the codebook auxiliary structures for decode *************/
static_codebook *vorbis_staticbook_unpack(oggpack_buffer *opb){
long i,j;
static_codebook *s=_ogg_calloc(1,sizeof(*s));
/* make sure alignment is correct */
if(oggpack_read(opb,24)!=0x564342)goto _eofout;
/* first the basic parameters */
s->dim=oggpack_read(opb,16);
s->entries=oggpack_read(opb,24);
if(s->entries==-1)goto _eofout;
if(_ilog(s->dim)+_ilog(s->entries)>24)goto _eofout;
/* codeword ordering.... length ordered or unordered? */
switch((int)oggpack_read(opb,1)){
case 0:{
long unused;
/* allocated but unused entries? */
unused=oggpack_read(opb,1);
if((s->entries*(unused?1:5)+7)>>3>opb->storage-oggpack_bytes(opb))
goto _eofout;
/* unordered */
s->lengthlist=(long *)_ogg_malloc(sizeof(*s->lengthlist)*s->entries);
/* allocated but unused entries? */
if(unused){
/* yes, unused entries */
for(i=0;i<s->entries;i++){
if(oggpack_read(opb,1)){
long num=oggpack_read(opb,5);
if(num==-1)goto _eofout;
s->lengthlist[i]=num+1;
}else
s->lengthlist[i]=0;
}
}else{
/* all entries used; no tagging */
for(i=0;i<s->entries;i++){
long num=oggpack_read(opb,5);
if(num==-1)goto _eofout;
s->lengthlist[i]=num+1;
}
}
break;
}
case 1:
/* ordered */
{
long length=oggpack_read(opb,5)+1;
if(length==0)goto _eofout;
s->lengthlist=(long *)_ogg_malloc(sizeof(*s->lengthlist)*s->entries);
for(i=0;i<s->entries;){
long num=oggpack_read(opb,_ilog(s->entries-i));
if(num==-1)goto _eofout;
if(length>32 || num>s->entries-i ||
(num>0 && (num-1)>>(length>>1)>>((length+1)>>1))>0){
goto _errout;
}
for(j=0;j<num;j++,i++)
s->lengthlist[i]=length;
length++;
}
}
break;
default:
/* EOF */
goto _eofout;
}
/* Do we have a mapping to unpack? */
switch((s->maptype=oggpack_read(opb,4))){
case 0:
/* no mapping */
break;
case 1: case 2:
/* implicitly populated value mapping */
/* explicitly populated value mapping */
s->q_min=oggpack_read(opb,32);
s->q_delta=oggpack_read(opb,32);
s->q_quant=oggpack_read(opb,4)+1;
s->q_sequencep=oggpack_read(opb,1);
if(s->q_sequencep==-1)goto _eofout;
{
int quantvals=0;
switch(s->maptype){
case 1:
quantvals=(s->dim==0?0:_book_maptype1_quantvals(s));
break;
case 2:
quantvals=s->entries*s->dim;
break;
}
/* quantized values */
if((quantvals*s->q_quant+7)>>3>opb->storage-oggpack_bytes(opb))
goto _eofout;
s->quantlist=(long *)_ogg_malloc(sizeof(*s->quantlist)*quantvals);
for(i=0;i<quantvals;i++)
s->quantlist[i]=oggpack_read(opb,s->q_quant);
if(quantvals&&s->quantlist[quantvals-1]==-1)goto _eofout;
}
break;
default:
goto _errout;
}
/* all set */
return(s);
_errout:
_eofout:
vorbis_staticbook_destroy(s);
return(NULL);
}
/* the 'eliminate the decode tree' optimization actually requires the
codewords to be MSb first, not LSb. This is an annoying inelegancy
(and one of the first places where carefully thought out design
turned out to be wrong; Vorbis II and future Ogg codecs should go
to an MSb bitpacker), but not actually the huge hit it appears to
be. The first-stage decode table catches most words so that
bitreverse is not in the main execution path. */
static ogg_uint32_t bitreverse(ogg_uint32_t x){
x= ((x>>16)&0x0000ffff) | ((x<<16)&0xffff0000);
x= ((x>> 8)&0x00ff00ff) | ((x<< 8)&0xff00ff00);
x= ((x>> 4)&0x0f0f0f0f) | ((x<< 4)&0xf0f0f0f0);
x= ((x>> 2)&0x33333333) | ((x<< 2)&0xcccccccc);
return((x>> 1)&0x55555555) | ((x<< 1)&0xaaaaaaaa);
}
STIN long decode_packed_entry_number(codebook *book,
oggpack_buffer *b){
int read=book->dec_maxlength;
long lo,hi;
long lok = oggpack_look(b,book->dec_firsttablen);
if (lok >= 0) {
long entry = book->dec_firsttable[lok];
if(entry&0x80000000UL){
lo=(entry>>15)&0x7fff;
hi=book->used_entries-(entry&0x7fff);
}else{
oggpack_adv(b, book->dec_codelengths[entry-1]);
return(entry-1);
}
}else{
lo=0;
hi=book->used_entries;
}
lok = oggpack_look(b, read);
while(lok<0 && read>1)
lok = oggpack_look(b, --read);
if(lok<0){
oggpack_adv(b,1); /* force eop */
return -1;
}
/* bisect search for the codeword in the ordered list */
{
ogg_uint32_t testword=bitreverse((ogg_uint32_t)lok);
while(hi-lo>1){
long p=(hi-lo)>>1;
long test=book->codelist[lo+p]>testword;
lo+=p&(test-1);
hi-=p&(-test);
}
if(book->dec_codelengths[lo]<=read){
oggpack_adv(b, book->dec_codelengths[lo]);
return(lo);
}
}
oggpack_adv(b, read+1);
return(-1);
}
/* Decode side is specced and easier, because we don't need to find
matches using different criteria; we simply read and map. There are
two things we need to do 'depending':
We may need to support interleave. We don't really, but it's
convenient to do it here rather than rebuild the vector later.
Cascades may be additive or multiplicitive; this is not inherent in
the codebook, but set in the code using the codebook. Like
interleaving, it's easiest to do it here.
addmul==0 -> declarative (set the value)
addmul==1 -> additive
addmul==2 -> multiplicitive */
/* returns the [original, not compacted] entry number or -1 on eof *********/
long vorbis_book_decode(codebook *book, oggpack_buffer *b){
if(book->used_entries>0){
long packed_entry=decode_packed_entry_number(book,b);
if(packed_entry>=0)
return(book->dec_index[packed_entry]);
}
/* if there's no dec_index, the codebook unpacking isn't collapsed */
return(-1);
}
/* returns 0 on OK or -1 on eof *************************************/
/* decode vector / dim granularity gaurding is done in the upper layer */
long vorbis_book_decodevs_add(codebook *book,ogg_int32_t *a,
oggpack_buffer *b,int n,int point){
if(book->used_entries>0){
int step=n/book->dim;
long *entry = (long *)alloca(sizeof(*entry)*step);
ogg_int32_t **t = (ogg_int32_t **)alloca(sizeof(*t)*step);
int i,j,o;
int shift=point-book->binarypoint;
if(shift>=0){
for (i = 0; i < step; i++) {
entry[i]=decode_packed_entry_number(book,b);
if(entry[i]==-1)return(-1);
t[i] = book->valuelist+entry[i]*book->dim;
}
for(i=0,o=0;i<book->dim;i++,o+=step)
for (j=0;o+j<n && j<step;j++)
a[o+j]+=t[j][i]>>shift;
}else{
for (i = 0; i < step; i++) {
entry[i]=decode_packed_entry_number(book,b);
if(entry[i]==-1)return(-1);
t[i] = book->valuelist+entry[i]*book->dim;
}
for(i=0,o=0;i<book->dim;i++,o+=step)
for (j=0;o+j<n && j<step;j++)
a[o+j]+=t[j][i]<<-shift;
}
}
return(0);
}
/* decode vector / dim granularity gaurding is done in the upper layer */
long vorbis_book_decodev_add(codebook *book,ogg_int32_t *a,
oggpack_buffer *b,int n,int point){
if(book->used_entries>0){
int i,j,entry;
ogg_int32_t *t;
int shift=point-book->binarypoint;
if(shift>=0){
for(i=0;i<n;){
entry = decode_packed_entry_number(book,b);
if(entry==-1)return(-1);
t = book->valuelist+entry*book->dim;
for (j=0;i<n && j<book->dim;)
a[i++]+=t[j++]>>shift;
}
}else{
for(i=0;i<n;){
entry = decode_packed_entry_number(book,b);
if(entry==-1)return(-1);
t = book->valuelist+entry*book->dim;
for (j=0;i<n && j<book->dim;)
a[i++]+=t[j++]<<-shift;
}
}
}
return(0);
}
/* unlike the others, we guard against n not being an integer number
of <dim> internally rather than in the upper layer (called only by
floor0) */
long vorbis_book_decodev_set(codebook *book,ogg_int32_t *a,
oggpack_buffer *b,int n,int point){
if(book->used_entries>0){
int i,j,entry;
ogg_int32_t *t;
int shift=point-book->binarypoint;
if(shift>=0){
for(i=0;i<n;){
entry = decode_packed_entry_number(book,b);
if(entry==-1)return(-1);
t = book->valuelist+entry*book->dim;
for (j=0;i<n && j<book->dim;){
a[i++]=t[j++]>>shift;
}
}
}else{
for(i=0;i<n;){
entry = decode_packed_entry_number(book,b);
if(entry==-1)return(-1);
t = book->valuelist+entry*book->dim;
for (j=0;i<n && j<book->dim;){
a[i++]=t[j++]<<-shift;
}
}
}
}else{
int i;
for(i=0;i<n;){
a[i++]=0;
}
}
return(0);
}
/* decode vector / dim granularity gaurding is done in the upper layer */
long vorbis_book_decodevv_add(codebook *book,ogg_int32_t **a,\
long offset,int ch,
oggpack_buffer *b,int n,int point){
if(book->used_entries>0){
long i,j,entry;
int chptr=0;
int shift=point-book->binarypoint;
int m=offset+n;
if(shift>=0){
for(i=offset;i<m;){
entry = decode_packed_entry_number(book,b);
if(entry==-1)return(-1);
{
const ogg_int32_t *t = book->valuelist+entry*book->dim;
for (j=0;i<m && j<book->dim;j++){
a[chptr++][i]+=t[j]>>shift;
if(chptr==ch){
chptr=0;
i++;
}
}
}
}
}else{
for(i=offset;i<m;){
entry = decode_packed_entry_number(book,b);
if(entry==-1)return(-1);
{
const ogg_int32_t *t = book->valuelist+entry*book->dim;
for (j=0;i<m && j<book->dim;j++){
a[chptr++][i]+=t[j]<<-shift;
if(chptr==ch){
chptr=0;
i++;
}
}
}
}
}
}
return(0);
}
+101
View File
@@ -0,0 +1,101 @@
/********************************************************************
* *
* THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. *
* *
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 *
* BY THE Xiph.Org FOUNDATION http://www.xiph.org/ *
* *
********************************************************************
function: basic shared codebook operations
********************************************************************/
#ifndef _V_CODEBOOK_H_
#define _V_CODEBOOK_H_
#include <ogg/ogg.h>
/* This structure encapsulates huffman and VQ style encoding books; it
doesn't do anything specific to either.
valuelist/quantlist are nonNULL (and q_* significant) only if
there's entry->value mapping to be done.
If encode-side mapping must be done (and thus the entry needs to be
hunted), the auxiliary encode pointer will point to a decision
tree. This is true of both VQ and huffman, but is mostly useful
with VQ.
*/
typedef struct static_codebook{
long dim; /* codebook dimensions (elements per vector) */
long entries; /* codebook entries */
long *lengthlist; /* codeword lengths in bits */
/* mapping ***************************************************************/
int maptype; /* 0=none
1=implicitly populated values from map column
2=listed arbitrary values */
/* The below does a linear, single monotonic sequence mapping. */
long q_min; /* packed 32 bit float; quant value 0 maps to minval */
long q_delta; /* packed 32 bit float; val 1 - val 0 == delta */
int q_quant; /* bits: 0 < quant <= 16 */
int q_sequencep; /* bitflag */
long *quantlist; /* map == 1: (int)(entries^(1/dim)) element column map
map == 2: list of dim*entries quantized entry vals
*/
} static_codebook;
typedef struct codebook{
long dim; /* codebook dimensions (elements per vector) */
long entries; /* codebook entries */
long used_entries; /* populated codebook entries */
/* the below are ordered by bitreversed codeword and only used
entries are populated */
int binarypoint;
ogg_int32_t *valuelist; /* list of dim*entries actual entry values */
ogg_uint32_t *codelist; /* list of bitstream codewords for each entry */
int *dec_index;
char *dec_codelengths;
ogg_uint32_t *dec_firsttable;
int dec_firsttablen;
int dec_maxlength;
long q_min; /* packed 32 bit float; quant value 0 maps to minval */
long q_delta; /* packed 32 bit float; val 1 - val 0 == delta */
} codebook;
extern void vorbis_staticbook_destroy(static_codebook *b);
extern int vorbis_book_init_decode(codebook *dest,const static_codebook *source);
extern void vorbis_book_clear(codebook *b);
extern long _book_maptype1_quantvals(const static_codebook *b);
extern static_codebook *vorbis_staticbook_unpack(oggpack_buffer *b);
extern long vorbis_book_decode(codebook *book, oggpack_buffer *b);
extern long vorbis_book_decodevs_add(codebook *book, ogg_int32_t *a,
oggpack_buffer *b,int n,int point);
extern long vorbis_book_decodev_set(codebook *book, ogg_int32_t *a,
oggpack_buffer *b,int n,int point);
extern long vorbis_book_decodev_add(codebook *book, ogg_int32_t *a,
oggpack_buffer *b,int n,int point);
extern long vorbis_book_decodevv_add(codebook *book, ogg_int32_t **a,
long off,int ch,
oggpack_buffer *b,int n,int point);
extern int _ilog(unsigned int v);
#endif
+92
View File
@@ -0,0 +1,92 @@
/********************************************************************
* *
* THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. *
* *
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 *
* BY THE Xiph.Org FOUNDATION http://www.xiph.org/ *
* *
********************************************************************
function: libvorbis codec headers
********************************************************************/
#ifndef _V_CODECI_H_
#define _V_CODECI_H_
#include "codebook.h"
typedef void vorbis_look_mapping;
typedef void vorbis_look_floor;
typedef void vorbis_look_residue;
typedef void vorbis_look_transform;
/* mode ************************************************************/
typedef struct {
int blockflag;
int windowtype;
int transformtype;
int mapping;
} vorbis_info_mode;
typedef void vorbis_info_floor;
typedef void vorbis_info_residue;
typedef void vorbis_info_mapping;
typedef struct private_state {
/* local lookup storage */
const void *window[2];
/* backend lookups are tied to the mode, not the backend or naked mapping */
int modebits;
vorbis_look_mapping **mode;
ogg_int64_t sample_count;
} private_state;
/* codec_setup_info contains all the setup information specific to the
specific compression/decompression mode in progress (eg,
psychoacoustic settings, channel setup, options, codebook
etc).
*********************************************************************/
typedef struct codec_setup_info {
/* Vorbis supports only short and long blocks, but allows the
encoder to choose the sizes */
long blocksizes[2];
/* modes are the primary means of supporting on-the-fly different
blocksizes, different channel mappings (LR or M/A),
different residue backends, etc. Each mode consists of a
blocksize flag and a mapping (along with the mapping setup */
int modes;
int maps;
int times;
int floors;
int residues;
int books;
vorbis_info_mode *mode_param[64];
int map_type[64];
vorbis_info_mapping *map_param[64];
int time_type[64];
int floor_type[64];
vorbis_info_floor *floor_param[64];
int residue_type[64];
vorbis_info_residue *residue_param[64];
static_codebook *book_param[256];
codebook *fullbooks;
int passlimit[32]; /* iteration limit per couple/quant pass */
int coupling_passes;
} codec_setup_info;
#endif
+278
View File
@@ -0,0 +1,278 @@
/********************************************************************
* *
* THIS FILE IS PART OF THE Ogg CONTAINER SOURCE CODE. *
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2018 *
* by the Xiph.Org Foundation http://www.xiph.org/ *
* *
********************************************************************/
#include <ogg/os_types.h>
static const ogg_uint32_t crc_lookup[8][256]={
{0x00000000,0x04c11db7,0x09823b6e,0x0d4326d9,0x130476dc,0x17c56b6b,0x1a864db2,0x1e475005,
0x2608edb8,0x22c9f00f,0x2f8ad6d6,0x2b4bcb61,0x350c9b64,0x31cd86d3,0x3c8ea00a,0x384fbdbd,
0x4c11db70,0x48d0c6c7,0x4593e01e,0x4152fda9,0x5f15adac,0x5bd4b01b,0x569796c2,0x52568b75,
0x6a1936c8,0x6ed82b7f,0x639b0da6,0x675a1011,0x791d4014,0x7ddc5da3,0x709f7b7a,0x745e66cd,
0x9823b6e0,0x9ce2ab57,0x91a18d8e,0x95609039,0x8b27c03c,0x8fe6dd8b,0x82a5fb52,0x8664e6e5,
0xbe2b5b58,0xbaea46ef,0xb7a96036,0xb3687d81,0xad2f2d84,0xa9ee3033,0xa4ad16ea,0xa06c0b5d,
0xd4326d90,0xd0f37027,0xddb056fe,0xd9714b49,0xc7361b4c,0xc3f706fb,0xceb42022,0xca753d95,
0xf23a8028,0xf6fb9d9f,0xfbb8bb46,0xff79a6f1,0xe13ef6f4,0xe5ffeb43,0xe8bccd9a,0xec7dd02d,
0x34867077,0x30476dc0,0x3d044b19,0x39c556ae,0x278206ab,0x23431b1c,0x2e003dc5,0x2ac12072,
0x128e9dcf,0x164f8078,0x1b0ca6a1,0x1fcdbb16,0x018aeb13,0x054bf6a4,0x0808d07d,0x0cc9cdca,
0x7897ab07,0x7c56b6b0,0x71159069,0x75d48dde,0x6b93dddb,0x6f52c06c,0x6211e6b5,0x66d0fb02,
0x5e9f46bf,0x5a5e5b08,0x571d7dd1,0x53dc6066,0x4d9b3063,0x495a2dd4,0x44190b0d,0x40d816ba,
0xaca5c697,0xa864db20,0xa527fdf9,0xa1e6e04e,0xbfa1b04b,0xbb60adfc,0xb6238b25,0xb2e29692,
0x8aad2b2f,0x8e6c3698,0x832f1041,0x87ee0df6,0x99a95df3,0x9d684044,0x902b669d,0x94ea7b2a,
0xe0b41de7,0xe4750050,0xe9362689,0xedf73b3e,0xf3b06b3b,0xf771768c,0xfa325055,0xfef34de2,
0xc6bcf05f,0xc27dede8,0xcf3ecb31,0xcbffd686,0xd5b88683,0xd1799b34,0xdc3abded,0xd8fba05a,
0x690ce0ee,0x6dcdfd59,0x608edb80,0x644fc637,0x7a089632,0x7ec98b85,0x738aad5c,0x774bb0eb,
0x4f040d56,0x4bc510e1,0x46863638,0x42472b8f,0x5c007b8a,0x58c1663d,0x558240e4,0x51435d53,
0x251d3b9e,0x21dc2629,0x2c9f00f0,0x285e1d47,0x36194d42,0x32d850f5,0x3f9b762c,0x3b5a6b9b,
0x0315d626,0x07d4cb91,0x0a97ed48,0x0e56f0ff,0x1011a0fa,0x14d0bd4d,0x19939b94,0x1d528623,
0xf12f560e,0xf5ee4bb9,0xf8ad6d60,0xfc6c70d7,0xe22b20d2,0xe6ea3d65,0xeba91bbc,0xef68060b,
0xd727bbb6,0xd3e6a601,0xdea580d8,0xda649d6f,0xc423cd6a,0xc0e2d0dd,0xcda1f604,0xc960ebb3,
0xbd3e8d7e,0xb9ff90c9,0xb4bcb610,0xb07daba7,0xae3afba2,0xaafbe615,0xa7b8c0cc,0xa379dd7b,
0x9b3660c6,0x9ff77d71,0x92b45ba8,0x9675461f,0x8832161a,0x8cf30bad,0x81b02d74,0x857130c3,
0x5d8a9099,0x594b8d2e,0x5408abf7,0x50c9b640,0x4e8ee645,0x4a4ffbf2,0x470cdd2b,0x43cdc09c,
0x7b827d21,0x7f436096,0x7200464f,0x76c15bf8,0x68860bfd,0x6c47164a,0x61043093,0x65c52d24,
0x119b4be9,0x155a565e,0x18197087,0x1cd86d30,0x029f3d35,0x065e2082,0x0b1d065b,0x0fdc1bec,
0x3793a651,0x3352bbe6,0x3e119d3f,0x3ad08088,0x2497d08d,0x2056cd3a,0x2d15ebe3,0x29d4f654,
0xc5a92679,0xc1683bce,0xcc2b1d17,0xc8ea00a0,0xd6ad50a5,0xd26c4d12,0xdf2f6bcb,0xdbee767c,
0xe3a1cbc1,0xe760d676,0xea23f0af,0xeee2ed18,0xf0a5bd1d,0xf464a0aa,0xf9278673,0xfde69bc4,
0x89b8fd09,0x8d79e0be,0x803ac667,0x84fbdbd0,0x9abc8bd5,0x9e7d9662,0x933eb0bb,0x97ffad0c,
0xafb010b1,0xab710d06,0xa6322bdf,0xa2f33668,0xbcb4666d,0xb8757bda,0xb5365d03,0xb1f740b4},
{0x00000000,0xd219c1dc,0xa0f29e0f,0x72eb5fd3,0x452421a9,0x973de075,0xe5d6bfa6,0x37cf7e7a,
0x8a484352,0x5851828e,0x2abadd5d,0xf8a31c81,0xcf6c62fb,0x1d75a327,0x6f9efcf4,0xbd873d28,
0x10519b13,0xc2485acf,0xb0a3051c,0x62bac4c0,0x5575baba,0x876c7b66,0xf58724b5,0x279ee569,
0x9a19d841,0x4800199d,0x3aeb464e,0xe8f28792,0xdf3df9e8,0x0d243834,0x7fcf67e7,0xadd6a63b,
0x20a33626,0xf2baf7fa,0x8051a829,0x524869f5,0x6587178f,0xb79ed653,0xc5758980,0x176c485c,
0xaaeb7574,0x78f2b4a8,0x0a19eb7b,0xd8002aa7,0xefcf54dd,0x3dd69501,0x4f3dcad2,0x9d240b0e,
0x30f2ad35,0xe2eb6ce9,0x9000333a,0x4219f2e6,0x75d68c9c,0xa7cf4d40,0xd5241293,0x073dd34f,
0xbabaee67,0x68a32fbb,0x1a487068,0xc851b1b4,0xff9ecfce,0x2d870e12,0x5f6c51c1,0x8d75901d,
0x41466c4c,0x935fad90,0xe1b4f243,0x33ad339f,0x04624de5,0xd67b8c39,0xa490d3ea,0x76891236,
0xcb0e2f1e,0x1917eec2,0x6bfcb111,0xb9e570cd,0x8e2a0eb7,0x5c33cf6b,0x2ed890b8,0xfcc15164,
0x5117f75f,0x830e3683,0xf1e56950,0x23fca88c,0x1433d6f6,0xc62a172a,0xb4c148f9,0x66d88925,
0xdb5fb40d,0x094675d1,0x7bad2a02,0xa9b4ebde,0x9e7b95a4,0x4c625478,0x3e890bab,0xec90ca77,
0x61e55a6a,0xb3fc9bb6,0xc117c465,0x130e05b9,0x24c17bc3,0xf6d8ba1f,0x8433e5cc,0x562a2410,
0xebad1938,0x39b4d8e4,0x4b5f8737,0x994646eb,0xae893891,0x7c90f94d,0x0e7ba69e,0xdc626742,
0x71b4c179,0xa3ad00a5,0xd1465f76,0x035f9eaa,0x3490e0d0,0xe689210c,0x94627edf,0x467bbf03,
0xfbfc822b,0x29e543f7,0x5b0e1c24,0x8917ddf8,0xbed8a382,0x6cc1625e,0x1e2a3d8d,0xcc33fc51,
0x828cd898,0x50951944,0x227e4697,0xf067874b,0xc7a8f931,0x15b138ed,0x675a673e,0xb543a6e2,
0x08c49bca,0xdadd5a16,0xa83605c5,0x7a2fc419,0x4de0ba63,0x9ff97bbf,0xed12246c,0x3f0be5b0,
0x92dd438b,0x40c48257,0x322fdd84,0xe0361c58,0xd7f96222,0x05e0a3fe,0x770bfc2d,0xa5123df1,
0x189500d9,0xca8cc105,0xb8679ed6,0x6a7e5f0a,0x5db12170,0x8fa8e0ac,0xfd43bf7f,0x2f5a7ea3,
0xa22feebe,0x70362f62,0x02dd70b1,0xd0c4b16d,0xe70bcf17,0x35120ecb,0x47f95118,0x95e090c4,
0x2867adec,0xfa7e6c30,0x889533e3,0x5a8cf23f,0x6d438c45,0xbf5a4d99,0xcdb1124a,0x1fa8d396,
0xb27e75ad,0x6067b471,0x128ceba2,0xc0952a7e,0xf75a5404,0x254395d8,0x57a8ca0b,0x85b10bd7,
0x383636ff,0xea2ff723,0x98c4a8f0,0x4add692c,0x7d121756,0xaf0bd68a,0xdde08959,0x0ff94885,
0xc3cab4d4,0x11d37508,0x63382adb,0xb121eb07,0x86ee957d,0x54f754a1,0x261c0b72,0xf405caae,
0x4982f786,0x9b9b365a,0xe9706989,0x3b69a855,0x0ca6d62f,0xdebf17f3,0xac544820,0x7e4d89fc,
0xd39b2fc7,0x0182ee1b,0x7369b1c8,0xa1707014,0x96bf0e6e,0x44a6cfb2,0x364d9061,0xe45451bd,
0x59d36c95,0x8bcaad49,0xf921f29a,0x2b383346,0x1cf74d3c,0xceee8ce0,0xbc05d333,0x6e1c12ef,
0xe36982f2,0x3170432e,0x439b1cfd,0x9182dd21,0xa64da35b,0x74546287,0x06bf3d54,0xd4a6fc88,
0x6921c1a0,0xbb38007c,0xc9d35faf,0x1bca9e73,0x2c05e009,0xfe1c21d5,0x8cf77e06,0x5eeebfda,
0xf33819e1,0x2121d83d,0x53ca87ee,0x81d34632,0xb61c3848,0x6405f994,0x16eea647,0xc4f7679b,
0x79705ab3,0xab699b6f,0xd982c4bc,0x0b9b0560,0x3c547b1a,0xee4dbac6,0x9ca6e515,0x4ebf24c9},
{0x00000000,0x01d8ac87,0x03b1590e,0x0269f589,0x0762b21c,0x06ba1e9b,0x04d3eb12,0x050b4795,
0x0ec56438,0x0f1dc8bf,0x0d743d36,0x0cac91b1,0x09a7d624,0x087f7aa3,0x0a168f2a,0x0bce23ad,
0x1d8ac870,0x1c5264f7,0x1e3b917e,0x1fe33df9,0x1ae87a6c,0x1b30d6eb,0x19592362,0x18818fe5,
0x134fac48,0x129700cf,0x10fef546,0x112659c1,0x142d1e54,0x15f5b2d3,0x179c475a,0x1644ebdd,
0x3b1590e0,0x3acd3c67,0x38a4c9ee,0x397c6569,0x3c7722fc,0x3daf8e7b,0x3fc67bf2,0x3e1ed775,
0x35d0f4d8,0x3408585f,0x3661add6,0x37b90151,0x32b246c4,0x336aea43,0x31031fca,0x30dbb34d,
0x269f5890,0x2747f417,0x252e019e,0x24f6ad19,0x21fdea8c,0x2025460b,0x224cb382,0x23941f05,
0x285a3ca8,0x2982902f,0x2beb65a6,0x2a33c921,0x2f388eb4,0x2ee02233,0x2c89d7ba,0x2d517b3d,
0x762b21c0,0x77f38d47,0x759a78ce,0x7442d449,0x714993dc,0x70913f5b,0x72f8cad2,0x73206655,
0x78ee45f8,0x7936e97f,0x7b5f1cf6,0x7a87b071,0x7f8cf7e4,0x7e545b63,0x7c3daeea,0x7de5026d,
0x6ba1e9b0,0x6a794537,0x6810b0be,0x69c81c39,0x6cc35bac,0x6d1bf72b,0x6f7202a2,0x6eaaae25,
0x65648d88,0x64bc210f,0x66d5d486,0x670d7801,0x62063f94,0x63de9313,0x61b7669a,0x606fca1d,
0x4d3eb120,0x4ce61da7,0x4e8fe82e,0x4f5744a9,0x4a5c033c,0x4b84afbb,0x49ed5a32,0x4835f6b5,
0x43fbd518,0x4223799f,0x404a8c16,0x41922091,0x44996704,0x4541cb83,0x47283e0a,0x46f0928d,
0x50b47950,0x516cd5d7,0x5305205e,0x52dd8cd9,0x57d6cb4c,0x560e67cb,0x54679242,0x55bf3ec5,
0x5e711d68,0x5fa9b1ef,0x5dc04466,0x5c18e8e1,0x5913af74,0x58cb03f3,0x5aa2f67a,0x5b7a5afd,
0xec564380,0xed8eef07,0xefe71a8e,0xee3fb609,0xeb34f19c,0xeaec5d1b,0xe885a892,0xe95d0415,
0xe29327b8,0xe34b8b3f,0xe1227eb6,0xe0fad231,0xe5f195a4,0xe4293923,0xe640ccaa,0xe798602d,
0xf1dc8bf0,0xf0042777,0xf26dd2fe,0xf3b57e79,0xf6be39ec,0xf766956b,0xf50f60e2,0xf4d7cc65,
0xff19efc8,0xfec1434f,0xfca8b6c6,0xfd701a41,0xf87b5dd4,0xf9a3f153,0xfbca04da,0xfa12a85d,
0xd743d360,0xd69b7fe7,0xd4f28a6e,0xd52a26e9,0xd021617c,0xd1f9cdfb,0xd3903872,0xd24894f5,
0xd986b758,0xd85e1bdf,0xda37ee56,0xdbef42d1,0xdee40544,0xdf3ca9c3,0xdd555c4a,0xdc8df0cd,
0xcac91b10,0xcb11b797,0xc978421e,0xc8a0ee99,0xcdaba90c,0xcc73058b,0xce1af002,0xcfc25c85,
0xc40c7f28,0xc5d4d3af,0xc7bd2626,0xc6658aa1,0xc36ecd34,0xc2b661b3,0xc0df943a,0xc10738bd,
0x9a7d6240,0x9ba5cec7,0x99cc3b4e,0x981497c9,0x9d1fd05c,0x9cc77cdb,0x9eae8952,0x9f7625d5,
0x94b80678,0x9560aaff,0x97095f76,0x96d1f3f1,0x93dab464,0x920218e3,0x906bed6a,0x91b341ed,
0x87f7aa30,0x862f06b7,0x8446f33e,0x859e5fb9,0x8095182c,0x814db4ab,0x83244122,0x82fceda5,
0x8932ce08,0x88ea628f,0x8a839706,0x8b5b3b81,0x8e507c14,0x8f88d093,0x8de1251a,0x8c39899d,
0xa168f2a0,0xa0b05e27,0xa2d9abae,0xa3010729,0xa60a40bc,0xa7d2ec3b,0xa5bb19b2,0xa463b535,
0xafad9698,0xae753a1f,0xac1ccf96,0xadc46311,0xa8cf2484,0xa9178803,0xab7e7d8a,0xaaa6d10d,
0xbce23ad0,0xbd3a9657,0xbf5363de,0xbe8bcf59,0xbb8088cc,0xba58244b,0xb831d1c2,0xb9e97d45,
0xb2275ee8,0xb3fff26f,0xb19607e6,0xb04eab61,0xb545ecf4,0xb49d4073,0xb6f4b5fa,0xb72c197d},
{0x00000000,0xdc6d9ab7,0xbc1a28d9,0x6077b26e,0x7cf54c05,0xa098d6b2,0xc0ef64dc,0x1c82fe6b,
0xf9ea980a,0x258702bd,0x45f0b0d3,0x999d2a64,0x851fd40f,0x59724eb8,0x3905fcd6,0xe5686661,
0xf7142da3,0x2b79b714,0x4b0e057a,0x97639fcd,0x8be161a6,0x578cfb11,0x37fb497f,0xeb96d3c8,
0x0efeb5a9,0xd2932f1e,0xb2e49d70,0x6e8907c7,0x720bf9ac,0xae66631b,0xce11d175,0x127c4bc2,
0xeae946f1,0x3684dc46,0x56f36e28,0x8a9ef49f,0x961c0af4,0x4a719043,0x2a06222d,0xf66bb89a,
0x1303defb,0xcf6e444c,0xaf19f622,0x73746c95,0x6ff692fe,0xb39b0849,0xd3ecba27,0x0f812090,
0x1dfd6b52,0xc190f1e5,0xa1e7438b,0x7d8ad93c,0x61082757,0xbd65bde0,0xdd120f8e,0x017f9539,
0xe417f358,0x387a69ef,0x580ddb81,0x84604136,0x98e2bf5d,0x448f25ea,0x24f89784,0xf8950d33,
0xd1139055,0x0d7e0ae2,0x6d09b88c,0xb164223b,0xade6dc50,0x718b46e7,0x11fcf489,0xcd916e3e,
0x28f9085f,0xf49492e8,0x94e32086,0x488eba31,0x540c445a,0x8861deed,0xe8166c83,0x347bf634,
0x2607bdf6,0xfa6a2741,0x9a1d952f,0x46700f98,0x5af2f1f3,0x869f6b44,0xe6e8d92a,0x3a85439d,
0xdfed25fc,0x0380bf4b,0x63f70d25,0xbf9a9792,0xa31869f9,0x7f75f34e,0x1f024120,0xc36fdb97,
0x3bfad6a4,0xe7974c13,0x87e0fe7d,0x5b8d64ca,0x470f9aa1,0x9b620016,0xfb15b278,0x277828cf,
0xc2104eae,0x1e7dd419,0x7e0a6677,0xa267fcc0,0xbee502ab,0x6288981c,0x02ff2a72,0xde92b0c5,
0xcceefb07,0x108361b0,0x70f4d3de,0xac994969,0xb01bb702,0x6c762db5,0x0c019fdb,0xd06c056c,
0x3504630d,0xe969f9ba,0x891e4bd4,0x5573d163,0x49f12f08,0x959cb5bf,0xf5eb07d1,0x29869d66,
0xa6e63d1d,0x7a8ba7aa,0x1afc15c4,0xc6918f73,0xda137118,0x067eebaf,0x660959c1,0xba64c376,
0x5f0ca517,0x83613fa0,0xe3168dce,0x3f7b1779,0x23f9e912,0xff9473a5,0x9fe3c1cb,0x438e5b7c,
0x51f210be,0x8d9f8a09,0xede83867,0x3185a2d0,0x2d075cbb,0xf16ac60c,0x911d7462,0x4d70eed5,
0xa81888b4,0x74751203,0x1402a06d,0xc86f3ada,0xd4edc4b1,0x08805e06,0x68f7ec68,0xb49a76df,
0x4c0f7bec,0x9062e15b,0xf0155335,0x2c78c982,0x30fa37e9,0xec97ad5e,0x8ce01f30,0x508d8587,
0xb5e5e3e6,0x69887951,0x09ffcb3f,0xd5925188,0xc910afe3,0x157d3554,0x750a873a,0xa9671d8d,
0xbb1b564f,0x6776ccf8,0x07017e96,0xdb6ce421,0xc7ee1a4a,0x1b8380fd,0x7bf43293,0xa799a824,
0x42f1ce45,0x9e9c54f2,0xfeebe69c,0x22867c2b,0x3e048240,0xe26918f7,0x821eaa99,0x5e73302e,
0x77f5ad48,0xab9837ff,0xcbef8591,0x17821f26,0x0b00e14d,0xd76d7bfa,0xb71ac994,0x6b775323,
0x8e1f3542,0x5272aff5,0x32051d9b,0xee68872c,0xf2ea7947,0x2e87e3f0,0x4ef0519e,0x929dcb29,
0x80e180eb,0x5c8c1a5c,0x3cfba832,0xe0963285,0xfc14ccee,0x20795659,0x400ee437,0x9c637e80,
0x790b18e1,0xa5668256,0xc5113038,0x197caa8f,0x05fe54e4,0xd993ce53,0xb9e47c3d,0x6589e68a,
0x9d1cebb9,0x4171710e,0x2106c360,0xfd6b59d7,0xe1e9a7bc,0x3d843d0b,0x5df38f65,0x819e15d2,
0x64f673b3,0xb89be904,0xd8ec5b6a,0x0481c1dd,0x18033fb6,0xc46ea501,0xa419176f,0x78748dd8,
0x6a08c61a,0xb6655cad,0xd612eec3,0x0a7f7474,0x16fd8a1f,0xca9010a8,0xaae7a2c6,0x768a3871,
0x93e25e10,0x4f8fc4a7,0x2ff876c9,0xf395ec7e,0xef171215,0x337a88a2,0x530d3acc,0x8f60a07b},
{0x00000000,0x490d678d,0x921acf1a,0xdb17a897,0x20f48383,0x69f9e40e,0xb2ee4c99,0xfbe32b14,
0x41e90706,0x08e4608b,0xd3f3c81c,0x9afeaf91,0x611d8485,0x2810e308,0xf3074b9f,0xba0a2c12,
0x83d20e0c,0xcadf6981,0x11c8c116,0x58c5a69b,0xa3268d8f,0xea2bea02,0x313c4295,0x78312518,
0xc23b090a,0x8b366e87,0x5021c610,0x192ca19d,0xe2cf8a89,0xabc2ed04,0x70d54593,0x39d8221e,
0x036501af,0x4a686622,0x917fceb5,0xd872a938,0x2391822c,0x6a9ce5a1,0xb18b4d36,0xf8862abb,
0x428c06a9,0x0b816124,0xd096c9b3,0x999bae3e,0x6278852a,0x2b75e2a7,0xf0624a30,0xb96f2dbd,
0x80b70fa3,0xc9ba682e,0x12adc0b9,0x5ba0a734,0xa0438c20,0xe94eebad,0x3259433a,0x7b5424b7,
0xc15e08a5,0x88536f28,0x5344c7bf,0x1a49a032,0xe1aa8b26,0xa8a7ecab,0x73b0443c,0x3abd23b1,
0x06ca035e,0x4fc764d3,0x94d0cc44,0xddddabc9,0x263e80dd,0x6f33e750,0xb4244fc7,0xfd29284a,
0x47230458,0x0e2e63d5,0xd539cb42,0x9c34accf,0x67d787db,0x2edae056,0xf5cd48c1,0xbcc02f4c,
0x85180d52,0xcc156adf,0x1702c248,0x5e0fa5c5,0xa5ec8ed1,0xece1e95c,0x37f641cb,0x7efb2646,
0xc4f10a54,0x8dfc6dd9,0x56ebc54e,0x1fe6a2c3,0xe40589d7,0xad08ee5a,0x761f46cd,0x3f122140,
0x05af02f1,0x4ca2657c,0x97b5cdeb,0xdeb8aa66,0x255b8172,0x6c56e6ff,0xb7414e68,0xfe4c29e5,
0x444605f7,0x0d4b627a,0xd65ccaed,0x9f51ad60,0x64b28674,0x2dbfe1f9,0xf6a8496e,0xbfa52ee3,
0x867d0cfd,0xcf706b70,0x1467c3e7,0x5d6aa46a,0xa6898f7e,0xef84e8f3,0x34934064,0x7d9e27e9,
0xc7940bfb,0x8e996c76,0x558ec4e1,0x1c83a36c,0xe7608878,0xae6deff5,0x757a4762,0x3c7720ef,
0x0d9406bc,0x44996131,0x9f8ec9a6,0xd683ae2b,0x2d60853f,0x646de2b2,0xbf7a4a25,0xf6772da8,
0x4c7d01ba,0x05706637,0xde67cea0,0x976aa92d,0x6c898239,0x2584e5b4,0xfe934d23,0xb79e2aae,
0x8e4608b0,0xc74b6f3d,0x1c5cc7aa,0x5551a027,0xaeb28b33,0xe7bfecbe,0x3ca84429,0x75a523a4,
0xcfaf0fb6,0x86a2683b,0x5db5c0ac,0x14b8a721,0xef5b8c35,0xa656ebb8,0x7d41432f,0x344c24a2,
0x0ef10713,0x47fc609e,0x9cebc809,0xd5e6af84,0x2e058490,0x6708e31d,0xbc1f4b8a,0xf5122c07,
0x4f180015,0x06156798,0xdd02cf0f,0x940fa882,0x6fec8396,0x26e1e41b,0xfdf64c8c,0xb4fb2b01,
0x8d23091f,0xc42e6e92,0x1f39c605,0x5634a188,0xadd78a9c,0xe4daed11,0x3fcd4586,0x76c0220b,
0xccca0e19,0x85c76994,0x5ed0c103,0x17dda68e,0xec3e8d9a,0xa533ea17,0x7e244280,0x3729250d,
0x0b5e05e2,0x4253626f,0x9944caf8,0xd049ad75,0x2baa8661,0x62a7e1ec,0xb9b0497b,0xf0bd2ef6,
0x4ab702e4,0x03ba6569,0xd8adcdfe,0x91a0aa73,0x6a438167,0x234ee6ea,0xf8594e7d,0xb15429f0,
0x888c0bee,0xc1816c63,0x1a96c4f4,0x539ba379,0xa878886d,0xe175efe0,0x3a624777,0x736f20fa,
0xc9650ce8,0x80686b65,0x5b7fc3f2,0x1272a47f,0xe9918f6b,0xa09ce8e6,0x7b8b4071,0x328627fc,
0x083b044d,0x413663c0,0x9a21cb57,0xd32cacda,0x28cf87ce,0x61c2e043,0xbad548d4,0xf3d82f59,
0x49d2034b,0x00df64c6,0xdbc8cc51,0x92c5abdc,0x692680c8,0x202be745,0xfb3c4fd2,0xb231285f,
0x8be90a41,0xc2e46dcc,0x19f3c55b,0x50fea2d6,0xab1d89c2,0xe210ee4f,0x390746d8,0x700a2155,
0xca000d47,0x830d6aca,0x581ac25d,0x1117a5d0,0xeaf48ec4,0xa3f9e949,0x78ee41de,0x31e32653},
{0x00000000,0x1b280d78,0x36501af0,0x2d781788,0x6ca035e0,0x77883898,0x5af02f10,0x41d82268,
0xd9406bc0,0xc26866b8,0xef107130,0xf4387c48,0xb5e05e20,0xaec85358,0x83b044d0,0x989849a8,
0xb641ca37,0xad69c74f,0x8011d0c7,0x9b39ddbf,0xdae1ffd7,0xc1c9f2af,0xecb1e527,0xf799e85f,
0x6f01a1f7,0x7429ac8f,0x5951bb07,0x4279b67f,0x03a19417,0x1889996f,0x35f18ee7,0x2ed9839f,
0x684289d9,0x736a84a1,0x5e129329,0x453a9e51,0x04e2bc39,0x1fcab141,0x32b2a6c9,0x299aabb1,
0xb102e219,0xaa2aef61,0x8752f8e9,0x9c7af591,0xdda2d7f9,0xc68ada81,0xebf2cd09,0xf0dac071,
0xde0343ee,0xc52b4e96,0xe853591e,0xf37b5466,0xb2a3760e,0xa98b7b76,0x84f36cfe,0x9fdb6186,
0x0743282e,0x1c6b2556,0x311332de,0x2a3b3fa6,0x6be31dce,0x70cb10b6,0x5db3073e,0x469b0a46,
0xd08513b2,0xcbad1eca,0xe6d50942,0xfdfd043a,0xbc252652,0xa70d2b2a,0x8a753ca2,0x915d31da,
0x09c57872,0x12ed750a,0x3f956282,0x24bd6ffa,0x65654d92,0x7e4d40ea,0x53355762,0x481d5a1a,
0x66c4d985,0x7decd4fd,0x5094c375,0x4bbcce0d,0x0a64ec65,0x114ce11d,0x3c34f695,0x271cfbed,
0xbf84b245,0xa4acbf3d,0x89d4a8b5,0x92fca5cd,0xd32487a5,0xc80c8add,0xe5749d55,0xfe5c902d,
0xb8c79a6b,0xa3ef9713,0x8e97809b,0x95bf8de3,0xd467af8b,0xcf4fa2f3,0xe237b57b,0xf91fb803,
0x6187f1ab,0x7aaffcd3,0x57d7eb5b,0x4cffe623,0x0d27c44b,0x160fc933,0x3b77debb,0x205fd3c3,
0x0e86505c,0x15ae5d24,0x38d64aac,0x23fe47d4,0x622665bc,0x790e68c4,0x54767f4c,0x4f5e7234,
0xd7c63b9c,0xccee36e4,0xe196216c,0xfabe2c14,0xbb660e7c,0xa04e0304,0x8d36148c,0x961e19f4,
0xa5cb3ad3,0xbee337ab,0x939b2023,0x88b32d5b,0xc96b0f33,0xd243024b,0xff3b15c3,0xe41318bb,
0x7c8b5113,0x67a35c6b,0x4adb4be3,0x51f3469b,0x102b64f3,0x0b03698b,0x267b7e03,0x3d53737b,
0x138af0e4,0x08a2fd9c,0x25daea14,0x3ef2e76c,0x7f2ac504,0x6402c87c,0x497adff4,0x5252d28c,
0xcaca9b24,0xd1e2965c,0xfc9a81d4,0xe7b28cac,0xa66aaec4,0xbd42a3bc,0x903ab434,0x8b12b94c,
0xcd89b30a,0xd6a1be72,0xfbd9a9fa,0xe0f1a482,0xa12986ea,0xba018b92,0x97799c1a,0x8c519162,
0x14c9d8ca,0x0fe1d5b2,0x2299c23a,0x39b1cf42,0x7869ed2a,0x6341e052,0x4e39f7da,0x5511faa2,
0x7bc8793d,0x60e07445,0x4d9863cd,0x56b06eb5,0x17684cdd,0x0c4041a5,0x2138562d,0x3a105b55,
0xa28812fd,0xb9a01f85,0x94d8080d,0x8ff00575,0xce28271d,0xd5002a65,0xf8783ded,0xe3503095,
0x754e2961,0x6e662419,0x431e3391,0x58363ee9,0x19ee1c81,0x02c611f9,0x2fbe0671,0x34960b09,
0xac0e42a1,0xb7264fd9,0x9a5e5851,0x81765529,0xc0ae7741,0xdb867a39,0xf6fe6db1,0xedd660c9,
0xc30fe356,0xd827ee2e,0xf55ff9a6,0xee77f4de,0xafafd6b6,0xb487dbce,0x99ffcc46,0x82d7c13e,
0x1a4f8896,0x016785ee,0x2c1f9266,0x37379f1e,0x76efbd76,0x6dc7b00e,0x40bfa786,0x5b97aafe,
0x1d0ca0b8,0x0624adc0,0x2b5cba48,0x3074b730,0x71ac9558,0x6a849820,0x47fc8fa8,0x5cd482d0,
0xc44ccb78,0xdf64c600,0xf21cd188,0xe934dcf0,0xa8ecfe98,0xb3c4f3e0,0x9ebce468,0x8594e910,
0xab4d6a8f,0xb06567f7,0x9d1d707f,0x86357d07,0xc7ed5f6f,0xdcc55217,0xf1bd459f,0xea9548e7,
0x720d014f,0x69250c37,0x445d1bbf,0x5f7516c7,0x1ead34af,0x058539d7,0x28fd2e5f,0x33d52327},
{0x00000000,0x4f576811,0x9eaed022,0xd1f9b833,0x399cbdf3,0x76cbd5e2,0xa7326dd1,0xe86505c0,
0x73397be6,0x3c6e13f7,0xed97abc4,0xa2c0c3d5,0x4aa5c615,0x05f2ae04,0xd40b1637,0x9b5c7e26,
0xe672f7cc,0xa9259fdd,0x78dc27ee,0x378b4fff,0xdfee4a3f,0x90b9222e,0x41409a1d,0x0e17f20c,
0x954b8c2a,0xda1ce43b,0x0be55c08,0x44b23419,0xacd731d9,0xe38059c8,0x3279e1fb,0x7d2e89ea,
0xc824f22f,0x87739a3e,0x568a220d,0x19dd4a1c,0xf1b84fdc,0xbeef27cd,0x6f169ffe,0x2041f7ef,
0xbb1d89c9,0xf44ae1d8,0x25b359eb,0x6ae431fa,0x8281343a,0xcdd65c2b,0x1c2fe418,0x53788c09,
0x2e5605e3,0x61016df2,0xb0f8d5c1,0xffafbdd0,0x17cab810,0x589dd001,0x89646832,0xc6330023,
0x5d6f7e05,0x12381614,0xc3c1ae27,0x8c96c636,0x64f3c3f6,0x2ba4abe7,0xfa5d13d4,0xb50a7bc5,
0x9488f9e9,0xdbdf91f8,0x0a2629cb,0x457141da,0xad14441a,0xe2432c0b,0x33ba9438,0x7cedfc29,
0xe7b1820f,0xa8e6ea1e,0x791f522d,0x36483a3c,0xde2d3ffc,0x917a57ed,0x4083efde,0x0fd487cf,
0x72fa0e25,0x3dad6634,0xec54de07,0xa303b616,0x4b66b3d6,0x0431dbc7,0xd5c863f4,0x9a9f0be5,
0x01c375c3,0x4e941dd2,0x9f6da5e1,0xd03acdf0,0x385fc830,0x7708a021,0xa6f11812,0xe9a67003,
0x5cac0bc6,0x13fb63d7,0xc202dbe4,0x8d55b3f5,0x6530b635,0x2a67de24,0xfb9e6617,0xb4c90e06,
0x2f957020,0x60c21831,0xb13ba002,0xfe6cc813,0x1609cdd3,0x595ea5c2,0x88a71df1,0xc7f075e0,
0xbadefc0a,0xf589941b,0x24702c28,0x6b274439,0x834241f9,0xcc1529e8,0x1dec91db,0x52bbf9ca,
0xc9e787ec,0x86b0effd,0x574957ce,0x181e3fdf,0xf07b3a1f,0xbf2c520e,0x6ed5ea3d,0x2182822c,
0x2dd0ee65,0x62878674,0xb37e3e47,0xfc295656,0x144c5396,0x5b1b3b87,0x8ae283b4,0xc5b5eba5,
0x5ee99583,0x11befd92,0xc04745a1,0x8f102db0,0x67752870,0x28224061,0xf9dbf852,0xb68c9043,
0xcba219a9,0x84f571b8,0x550cc98b,0x1a5ba19a,0xf23ea45a,0xbd69cc4b,0x6c907478,0x23c71c69,
0xb89b624f,0xf7cc0a5e,0x2635b26d,0x6962da7c,0x8107dfbc,0xce50b7ad,0x1fa90f9e,0x50fe678f,
0xe5f41c4a,0xaaa3745b,0x7b5acc68,0x340da479,0xdc68a1b9,0x933fc9a8,0x42c6719b,0x0d91198a,
0x96cd67ac,0xd99a0fbd,0x0863b78e,0x4734df9f,0xaf51da5f,0xe006b24e,0x31ff0a7d,0x7ea8626c,
0x0386eb86,0x4cd18397,0x9d283ba4,0xd27f53b5,0x3a1a5675,0x754d3e64,0xa4b48657,0xebe3ee46,
0x70bf9060,0x3fe8f871,0xee114042,0xa1462853,0x49232d93,0x06744582,0xd78dfdb1,0x98da95a0,
0xb958178c,0xf60f7f9d,0x27f6c7ae,0x68a1afbf,0x80c4aa7f,0xcf93c26e,0x1e6a7a5d,0x513d124c,
0xca616c6a,0x8536047b,0x54cfbc48,0x1b98d459,0xf3fdd199,0xbcaab988,0x6d5301bb,0x220469aa,
0x5f2ae040,0x107d8851,0xc1843062,0x8ed35873,0x66b65db3,0x29e135a2,0xf8188d91,0xb74fe580,
0x2c139ba6,0x6344f3b7,0xb2bd4b84,0xfdea2395,0x158f2655,0x5ad84e44,0x8b21f677,0xc4769e66,
0x717ce5a3,0x3e2b8db2,0xefd23581,0xa0855d90,0x48e05850,0x07b73041,0xd64e8872,0x9919e063,
0x02459e45,0x4d12f654,0x9ceb4e67,0xd3bc2676,0x3bd923b6,0x748e4ba7,0xa577f394,0xea209b85,
0x970e126f,0xd8597a7e,0x09a0c24d,0x46f7aa5c,0xae92af9c,0xe1c5c78d,0x303c7fbe,0x7f6b17af,
0xe4376989,0xab600198,0x7a99b9ab,0x35ced1ba,0xddabd47a,0x92fcbc6b,0x43050458,0x0c526c49},
{0x00000000,0x5ba1dcca,0xb743b994,0xece2655e,0x6a466e9f,0x31e7b255,0xdd05d70b,0x86a40bc1,
0xd48cdd3e,0x8f2d01f4,0x63cf64aa,0x386eb860,0xbecab3a1,0xe56b6f6b,0x09890a35,0x5228d6ff,
0xadd8a7cb,0xf6797b01,0x1a9b1e5f,0x413ac295,0xc79ec954,0x9c3f159e,0x70dd70c0,0x2b7cac0a,
0x79547af5,0x22f5a63f,0xce17c361,0x95b61fab,0x1312146a,0x48b3c8a0,0xa451adfe,0xfff07134,
0x5f705221,0x04d18eeb,0xe833ebb5,0xb392377f,0x35363cbe,0x6e97e074,0x8275852a,0xd9d459e0,
0x8bfc8f1f,0xd05d53d5,0x3cbf368b,0x671eea41,0xe1bae180,0xba1b3d4a,0x56f95814,0x0d5884de,
0xf2a8f5ea,0xa9092920,0x45eb4c7e,0x1e4a90b4,0x98ee9b75,0xc34f47bf,0x2fad22e1,0x740cfe2b,
0x262428d4,0x7d85f41e,0x91679140,0xcac64d8a,0x4c62464b,0x17c39a81,0xfb21ffdf,0xa0802315,
0xbee0a442,0xe5417888,0x09a31dd6,0x5202c11c,0xd4a6cadd,0x8f071617,0x63e57349,0x3844af83,
0x6a6c797c,0x31cda5b6,0xdd2fc0e8,0x868e1c22,0x002a17e3,0x5b8bcb29,0xb769ae77,0xecc872bd,
0x13380389,0x4899df43,0xa47bba1d,0xffda66d7,0x797e6d16,0x22dfb1dc,0xce3dd482,0x959c0848,
0xc7b4deb7,0x9c15027d,0x70f76723,0x2b56bbe9,0xadf2b028,0xf6536ce2,0x1ab109bc,0x4110d576,
0xe190f663,0xba312aa9,0x56d34ff7,0x0d72933d,0x8bd698fc,0xd0774436,0x3c952168,0x6734fda2,
0x351c2b5d,0x6ebdf797,0x825f92c9,0xd9fe4e03,0x5f5a45c2,0x04fb9908,0xe819fc56,0xb3b8209c,
0x4c4851a8,0x17e98d62,0xfb0be83c,0xa0aa34f6,0x260e3f37,0x7dafe3fd,0x914d86a3,0xcaec5a69,
0x98c48c96,0xc365505c,0x2f873502,0x7426e9c8,0xf282e209,0xa9233ec3,0x45c15b9d,0x1e608757,
0x79005533,0x22a189f9,0xce43eca7,0x95e2306d,0x13463bac,0x48e7e766,0xa4058238,0xffa45ef2,
0xad8c880d,0xf62d54c7,0x1acf3199,0x416eed53,0xc7cae692,0x9c6b3a58,0x70895f06,0x2b2883cc,
0xd4d8f2f8,0x8f792e32,0x639b4b6c,0x383a97a6,0xbe9e9c67,0xe53f40ad,0x09dd25f3,0x527cf939,
0x00542fc6,0x5bf5f30c,0xb7179652,0xecb64a98,0x6a124159,0x31b39d93,0xdd51f8cd,0x86f02407,
0x26700712,0x7dd1dbd8,0x9133be86,0xca92624c,0x4c36698d,0x1797b547,0xfb75d019,0xa0d40cd3,
0xf2fcda2c,0xa95d06e6,0x45bf63b8,0x1e1ebf72,0x98bab4b3,0xc31b6879,0x2ff90d27,0x7458d1ed,
0x8ba8a0d9,0xd0097c13,0x3ceb194d,0x674ac587,0xe1eece46,0xba4f128c,0x56ad77d2,0x0d0cab18,
0x5f247de7,0x0485a12d,0xe867c473,0xb3c618b9,0x35621378,0x6ec3cfb2,0x8221aaec,0xd9807626,
0xc7e0f171,0x9c412dbb,0x70a348e5,0x2b02942f,0xada69fee,0xf6074324,0x1ae5267a,0x4144fab0,
0x136c2c4f,0x48cdf085,0xa42f95db,0xff8e4911,0x792a42d0,0x228b9e1a,0xce69fb44,0x95c8278e,
0x6a3856ba,0x31998a70,0xdd7bef2e,0x86da33e4,0x007e3825,0x5bdfe4ef,0xb73d81b1,0xec9c5d7b,
0xbeb48b84,0xe515574e,0x09f73210,0x5256eeda,0xd4f2e51b,0x8f5339d1,0x63b15c8f,0x38108045,
0x9890a350,0xc3317f9a,0x2fd31ac4,0x7472c60e,0xf2d6cdcf,0xa9771105,0x4595745b,0x1e34a891,
0x4c1c7e6e,0x17bda2a4,0xfb5fc7fa,0xa0fe1b30,0x265a10f1,0x7dfbcc3b,0x9119a965,0xcab875af,
0x3548049b,0x6ee9d851,0x820bbd0f,0xd9aa61c5,0x5f0e6a04,0x04afb6ce,0xe84dd390,0xb3ec0f5a,
0xe1c4d9a5,0xba65056f,0x56876031,0x0d26bcfb,0x8b82b73a,0xd0236bf0,0x3cc10eae,0x6760d264}};
+439
View File
@@ -0,0 +1,439 @@
/********************************************************************
* *
* THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. *
* *
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 *
* BY THE Xiph.Org FOUNDATION http://www.xiph.org/ *
* *
********************************************************************
function: floor backend 0 implementation
********************************************************************/
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <ogg/ogg.h>
#include "ivorbiscodec.h"
#include "codec_internal.h"
#include "registry.h"
#include "codebook.h"
#include "misc.h"
#include "block.h"
#define LSP_FRACBITS 14
typedef struct {
long n;
int ln;
int m;
int *linearmap;
vorbis_info_floor0 *vi;
ogg_int32_t *lsp_look;
} vorbis_look_floor0;
/*************** LSP decode ********************/
#include "lsp_lookup.h"
/* interpolated 1./sqrt(p) where .5 <= a < 1. (.100000... to .111111...) in
16.16 format
returns in m.8 format */
static long ADJUST_SQRT2[2]={8192,5792};
STIN ogg_int32_t vorbis_invsqlook_i(long a,long e){
long i=(a&0x7fff)>>(INVSQ_LOOKUP_I_SHIFT-1);
long d=a&INVSQ_LOOKUP_I_MASK; /* 0.10 */
long val=INVSQ_LOOKUP_I[i]- /* 1.16 */
((INVSQ_LOOKUP_IDel[i]*d)>>INVSQ_LOOKUP_I_SHIFT); /* result 1.16 */
val*=ADJUST_SQRT2[e&1];
e=(e>>1)+21;
return(val>>e);
}
/* interpolated lookup based fromdB function, domain -140dB to 0dB only */
/* a is in n.12 format */
STIN ogg_int32_t vorbis_fromdBlook_i(long a){
int i=(-a)>>(12-FROMdB2_SHIFT);
if(i<0) return 0x7fffffff;
if(i>=(FROMdB_LOOKUP_SZ<<FROMdB_SHIFT))return 0;
return FROMdB_LOOKUP[i>>FROMdB_SHIFT] * FROMdB2_LOOKUP[i&FROMdB2_MASK];
}
/* interpolated lookup based cos function, domain 0 to PI only */
/* a is in 0.16 format, where 0==0, 2^^16-1==PI, return 0.14 */
STIN ogg_int32_t vorbis_coslook_i(long a){
int i=a>>COS_LOOKUP_I_SHIFT;
int d=a&COS_LOOKUP_I_MASK;
return COS_LOOKUP_I[i]- ((d*(COS_LOOKUP_I[i]-COS_LOOKUP_I[i+1]))>>
COS_LOOKUP_I_SHIFT);
}
/* interpolated lookup based cos function */
/* a is in 0.16 format, where 0==0, 2^^16==PI, return .LSP_FRACBITS */
STIN ogg_int32_t vorbis_coslook2_i(long a){
a=a&0x1ffff;
if(a>0x10000)a=0x20000-a;
{
int i=a>>COS_LOOKUP_I_SHIFT;
int d=a&COS_LOOKUP_I_MASK;
a=((COS_LOOKUP_I[i]<<COS_LOOKUP_I_SHIFT)-
d*(COS_LOOKUP_I[i]-COS_LOOKUP_I[i+1]))>>
(COS_LOOKUP_I_SHIFT-LSP_FRACBITS+14);
}
return(a);
}
static const int barklook[28]={
0,100,200,301, 405,516,635,766,
912,1077,1263,1476, 1720,2003,2333,2721,
3184,3742,4428,5285, 6376,7791,9662,12181,
15624,20397,27087,36554
};
/* used in init only; interpolate the long way */
STIN ogg_int32_t toBARK(int n){
int i;
for(i=0;i<27;i++)
if(n>=barklook[i] && n<barklook[i+1])break;
if(i==27){
return 27<<15;
}else{
int gap=barklook[i+1]-barklook[i];
int del=n-barklook[i];
return((i<<15)+((del<<15)/gap));
}
}
static const unsigned char MLOOP_1[64]={
0,10,11,11, 12,12,12,12, 13,13,13,13, 13,13,13,13,
14,14,14,14, 14,14,14,14, 14,14,14,14, 14,14,14,14,
15,15,15,15, 15,15,15,15, 15,15,15,15, 15,15,15,15,
15,15,15,15, 15,15,15,15, 15,15,15,15, 15,15,15,15,
};
static const unsigned char MLOOP_2[64]={
0,4,5,5, 6,6,6,6, 7,7,7,7, 7,7,7,7,
8,8,8,8, 8,8,8,8, 8,8,8,8, 8,8,8,8,
9,9,9,9, 9,9,9,9, 9,9,9,9, 9,9,9,9,
9,9,9,9, 9,9,9,9, 9,9,9,9, 9,9,9,9,
};
static const unsigned char MLOOP_3[8]={0,1,2,2,3,3,3,3};
void vorbis_lsp_to_curve(ogg_int32_t *curve,int *map,int n,int ln,
ogg_int32_t *lsp,int m,
ogg_int32_t amp,
ogg_int32_t ampoffset,
ogg_int32_t *icos){
/* 0 <= m < 256 */
/* set up for using all int later */
int i;
int ampoffseti=ampoffset*4096;
int ampi=amp;
ogg_int32_t *ilsp=(ogg_int32_t *)alloca(m*sizeof(*ilsp));
/* lsp is in 8.24, range 0 to PI; coslook wants it in .16 0 to 1*/
for(i=0;i<m;i++){
#ifndef _LOW_ACCURACY_
ogg_int32_t val=MULT32(lsp[i],0x517cc2);
#else
ogg_int32_t val=((lsp[i]>>10)*0x517d)>>14;
#endif
/* safeguard against a malicious stream */
if(val<0 || (val>>COS_LOOKUP_I_SHIFT)>=COS_LOOKUP_I_SZ){
memset(curve,0,sizeof(*curve)*n);
return;
}
ilsp[i]=vorbis_coslook_i(val);
}
i=0;
while(i<n){
int j,k=map[i];
ogg_uint32_t pi=46341; /* 2**-.5 in 0.16 */
ogg_uint32_t qi=46341;
ogg_int32_t qexp=0,shift;
ogg_int32_t wi=icos[k];
#ifdef _V_LSP_MATH_ASM
lsp_loop_asm(&qi,&pi,&qexp,ilsp,wi,m);
pi=((pi*pi)>>16);
qi=((qi*qi)>>16);
if(m&1){
qexp= qexp*2-28*((m+1)>>1)+m;
pi*=(1<<14)-((wi*wi)>>14);
qi+=pi>>14;
}else{
qexp= qexp*2-13*m;
pi*=(1<<14)-wi;
qi*=(1<<14)+wi;
qi=(qi+pi)>>14;
}
if(qi&0xffff0000){ /* checks for 1.xxxxxxxxxxxxxxxx */
qi>>=1; qexp++;
}else
lsp_norm_asm(&qi,&qexp);
#else
j=1;
if(m>1){
qi*=labs(ilsp[0]-wi);
pi*=labs(ilsp[1]-wi);
for(j+=2;j<m;j+=2){
if(!(shift=MLOOP_1[(pi|qi)>>25]))
if(!(shift=MLOOP_2[(pi|qi)>>19]))
shift=MLOOP_3[(pi|qi)>>16];
qi=(qi>>shift)*labs(ilsp[j-1]-wi);
pi=(pi>>shift)*labs(ilsp[j]-wi);
qexp+=shift;
}
}
if(!(shift=MLOOP_1[(pi|qi)>>25]))
if(!(shift=MLOOP_2[(pi|qi)>>19]))
shift=MLOOP_3[(pi|qi)>>16];
/* pi,qi normalized collectively, both tracked using qexp */
if(m&1){
/* odd order filter; slightly assymetric */
/* the last coefficient */
qi=(qi>>shift)*labs(ilsp[j-1]-wi);
pi=(pi>>shift)<<14;
qexp+=shift;
if(!(shift=MLOOP_1[(pi|qi)>>25]))
if(!(shift=MLOOP_2[(pi|qi)>>19]))
shift=MLOOP_3[(pi|qi)>>16];
pi>>=shift;
qi>>=shift;
qexp+=shift-14*((m+1)>>1);
pi=((pi*pi)>>16);
qi=((qi*qi)>>16);
qexp=qexp*2+m;
pi*=(1<<14)-((wi*wi)>>14);
qi+=pi>>14;
}else{
/* even order filter; still symmetric */
/* p*=p(1-w), q*=q(1+w), let normalization drift because it isn't
worth tracking step by step */
pi>>=shift;
qi>>=shift;
qexp+=shift-7*m;
pi=((pi*pi)>>16);
qi=((qi*qi)>>16);
qexp=qexp*2+m;
pi*=(1<<14)-wi;
qi*=(1<<14)+wi;
qi=(qi+pi)>>14;
}
/* we've let the normalization drift because it wasn't important;
however, for the lookup, things must be normalized again. We
need at most one right shift or a number of left shifts */
if(qi&0xffff0000){ /* checks for 1.xxxxxxxxxxxxxxxx */
qi>>=1; qexp++;
}else
while(qi && !(qi&0x8000)){ /* checks for 0.0xxxxxxxxxxxxxxx or less*/
qi<<=1; qexp--;
}
#endif
amp=vorbis_fromdBlook_i(ampi* /* n.4 */
vorbis_invsqlook_i(qi,qexp)-
/* m.8, m+n<=8 */
ampoffseti); /* 8.12[0] */
#ifdef _LOW_ACCURACY_
amp>>=9;
#endif
curve[i]= MULT31_SHIFT15(curve[i],amp);
while(map[++i]==k) curve[i]= MULT31_SHIFT15(curve[i],amp);
}
}
/*************** vorbis decode glue ************/
static void floor0_free_info(vorbis_info_floor *i){
vorbis_info_floor0 *info=(vorbis_info_floor0 *)i;
if(info){
memset(info,0,sizeof(*info));
_ogg_free(info);
}
}
static void floor0_free_look(vorbis_look_floor *i){
vorbis_look_floor0 *look=(vorbis_look_floor0 *)i;
if(look){
if(look->linearmap)_ogg_free(look->linearmap);
if(look->lsp_look)_ogg_free(look->lsp_look);
memset(look,0,sizeof(*look));
_ogg_free(look);
}
}
static vorbis_info_floor *floor0_unpack (vorbis_info *vi,oggpack_buffer *opb){
codec_setup_info *ci=(codec_setup_info *)vi->codec_setup;
int j;
vorbis_info_floor0 *info=(vorbis_info_floor0 *)_ogg_malloc(sizeof(*info));
info->order=oggpack_read(opb,8);
info->rate=oggpack_read(opb,16);
info->barkmap=oggpack_read(opb,16);
info->ampbits=oggpack_read(opb,6);
info->ampdB=oggpack_read(opb,8);
info->numbooks=oggpack_read(opb,4)+1;
if(info->order<1)goto err_out;
if(info->rate<1)goto err_out;
if(info->barkmap<1)goto err_out;
if(info->numbooks<1)goto err_out;
for(j=0;j<info->numbooks;j++){
info->books[j]=oggpack_read(opb,8);
if(info->books[j]<0 || info->books[j]>=ci->books)goto err_out;
if(ci->book_param[info->books[j]]->maptype==0)goto err_out;
if(ci->book_param[info->books[j]]->dim<1)goto err_out;
}
return(info);
err_out:
floor0_free_info(info);
return(NULL);
}
/* initialize Bark scale and normalization lookups. We could do this
with static tables, but Vorbis allows a number of possible
combinations, so it's best to do it computationally.
The below is authoritative in terms of defining scale mapping.
Note that the scale depends on the sampling rate as well as the
linear block and mapping sizes */
static vorbis_look_floor *floor0_look (vorbis_dsp_state *vd,vorbis_info_mode *mi,
vorbis_info_floor *i){
int j;
vorbis_info *vi=vd->vi;
codec_setup_info *ci=(codec_setup_info *)vi->codec_setup;
vorbis_info_floor0 *info=(vorbis_info_floor0 *)i;
vorbis_look_floor0 *look=(vorbis_look_floor0 *)_ogg_calloc(1,sizeof(*look));
look->m=info->order;
look->n=ci->blocksizes[mi->blockflag]/2;
look->ln=info->barkmap;
look->vi=info;
/* the mapping from a linear scale to a smaller bark scale is
straightforward. We do *not* make sure that the linear mapping
does not skip bark-scale bins; the decoder simply skips them and
the encoder may do what it wishes in filling them. They're
necessary in some mapping combinations to keep the scale spacing
accurate */
look->linearmap=(int *)_ogg_malloc((look->n+1)*sizeof(*look->linearmap));
for(j=0;j<look->n;j++){
int val=(look->ln*
((toBARK(info->rate/2*j/look->n)<<11)/toBARK(info->rate/2)))>>11;
if(val>=look->ln)val=look->ln-1; /* guard against the approximation */
look->linearmap[j]=val;
}
look->linearmap[j]=-1;
look->lsp_look=(ogg_int32_t *)_ogg_malloc(look->ln*sizeof(*look->lsp_look));
for(j=0;j<look->ln;j++)
look->lsp_look[j]=vorbis_coslook2_i(0x10000*j/look->ln);
return look;
}
static void *floor0_inverse1(vorbis_block *vb,vorbis_look_floor *i){
vorbis_look_floor0 *look=(vorbis_look_floor0 *)i;
vorbis_info_floor0 *info=look->vi;
int j,k;
int ampraw=oggpack_read(&vb->opb,info->ampbits);
if(ampraw>0){ /* also handles the -1 out of data case */
long maxval=(1<<info->ampbits)-1;
int amp=((ampraw*info->ampdB)<<4)/maxval;
int booknum=oggpack_read(&vb->opb,_ilog(info->numbooks));
if(booknum!=-1 && booknum<info->numbooks){ /* be paranoid */
codec_setup_info *ci=(codec_setup_info *)vb->vd->vi->codec_setup;
codebook *b=ci->fullbooks+info->books[booknum];
ogg_int32_t last=0;
ogg_int32_t *lsp=(ogg_int32_t *)_vorbis_block_alloc(vb,sizeof(*lsp)*(look->m+1));
if(vorbis_book_decodev_set(b,lsp,&vb->opb,look->m,-24)==-1)goto eop;
for(j=0;j<look->m;){
for(k=0;j<look->m && k<b->dim;k++,j++)lsp[j]+=last;
last=lsp[j-1];
}
lsp[look->m]=amp;
return(lsp);
}
}
eop:
return(NULL);
}
static int floor0_inverse2(vorbis_block *vb,vorbis_look_floor *i,
void *memo,ogg_int32_t *out){
vorbis_look_floor0 *look=(vorbis_look_floor0 *)i;
vorbis_info_floor0 *info=look->vi;
if(memo){
ogg_int32_t *lsp=(ogg_int32_t *)memo;
ogg_int32_t amp=lsp[look->m];
/* take the coefficients back to a spectral envelope curve */
vorbis_lsp_to_curve(out,look->linearmap,look->n,look->ln,
lsp,look->m,amp,info->ampdB,look->lsp_look);
return(1);
}
memset(out,0,sizeof(*out)*look->n);
return(0);
}
/* export hooks */
vorbis_func_floor floor0_exportbundle={
&floor0_unpack,&floor0_look,&floor0_free_info,
&floor0_free_look,&floor0_inverse1,&floor0_inverse2
};
+460
View File
@@ -0,0 +1,460 @@
/********************************************************************
* *
* THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. *
* *
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 *
* BY THE Xiph.Org FOUNDATION http://www.xiph.org/ *
* *
********************************************************************
function: floor backend 1 implementation
********************************************************************/
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <ogg/ogg.h>
#include "ivorbiscodec.h"
#include "codec_internal.h"
#include "registry.h"
#include "codebook.h"
#include "misc.h"
#include "block.h"
#define floor1_rangedB 140 /* floor 1 fixed at -140dB to 0dB range */
typedef struct {
int forward_index[VIF_POSIT+2];
int hineighbor[VIF_POSIT];
int loneighbor[VIF_POSIT];
int posts;
int n;
int quant_q;
vorbis_info_floor1 *vi;
} vorbis_look_floor1;
/***********************************************/
static void floor1_free_info(vorbis_info_floor *i){
vorbis_info_floor1 *info=(vorbis_info_floor1 *)i;
if(info){
memset(info,0,sizeof(*info));
_ogg_free(info);
}
}
static void floor1_free_look(vorbis_look_floor *i){
vorbis_look_floor1 *look=(vorbis_look_floor1 *)i;
if(look){
memset(look,0,sizeof(*look));
_ogg_free(look);
}
}
static int ilog(unsigned int v){
int ret=0;
while(v){
ret++;
v>>=1;
}
return(ret);
}
static int icomp(const void *a,const void *b){
return(**(int **)a-**(int **)b);
}
static vorbis_info_floor *floor1_unpack (vorbis_info *vi,oggpack_buffer *opb){
codec_setup_info *ci=(codec_setup_info *)vi->codec_setup;
int j,k,count=0,maxclass=-1,rangebits;
vorbis_info_floor1 *info=(vorbis_info_floor1 *)_ogg_calloc(1,sizeof(*info));
/* read partitions */
info->partitions=oggpack_read(opb,5); /* only 0 to 31 legal */
for(j=0;j<info->partitions;j++){
info->partitionclass[j]=oggpack_read(opb,4); /* only 0 to 15 legal */
if(info->partitionclass[j]<0)goto err_out;
if(maxclass<info->partitionclass[j])maxclass=info->partitionclass[j];
}
/* read partition classes */
for(j=0;j<maxclass+1;j++){
info->class_dim[j]=oggpack_read(opb,3)+1; /* 1 to 8 */
info->class_subs[j]=oggpack_read(opb,2); /* 0,1,2,3 bits */
if(info->class_subs[j]<0)
goto err_out;
if(info->class_subs[j])info->class_book[j]=oggpack_read(opb,8);
if(info->class_book[j]<0 || info->class_book[j]>=ci->books)
goto err_out;
for(k=0;k<(1<<info->class_subs[j]);k++){
info->class_subbook[j][k]=oggpack_read(opb,8)-1;
if(info->class_subbook[j][k]<-1 || info->class_subbook[j][k]>=ci->books)
goto err_out;
}
}
/* read the post list */
info->mult=oggpack_read(opb,2)+1; /* only 1,2,3,4 legal now */
rangebits=oggpack_read(opb,4);
if(rangebits<0)goto err_out;
for(j=0,k=0;j<info->partitions;j++){
count+=info->class_dim[info->partitionclass[j]];
if(count>VIF_POSIT)goto err_out;
for(;k<count;k++){
int t=info->postlist[k+2]=oggpack_read(opb,rangebits);
if(t<0 || t>=(1<<rangebits))
goto err_out;
}
}
info->postlist[0]=0;
info->postlist[1]=1<<rangebits;
/* don't allow repeated values in post list as they'd result in
zero-length segments */
{
int *sortpointer[VIF_POSIT+2];
for(j=0;j<count+2;j++)sortpointer[j]=info->postlist+j;
qsort(sortpointer,count+2,sizeof(*sortpointer),icomp);
for(j=1;j<count+2;j++)
if(*sortpointer[j-1]==*sortpointer[j])goto err_out;
}
return(info);
err_out:
floor1_free_info(info);
return(NULL);
}
static vorbis_look_floor *floor1_look(vorbis_dsp_state *vd,vorbis_info_mode *mi,
vorbis_info_floor *in){
int *sortpointer[VIF_POSIT+2];
vorbis_info_floor1 *info=(vorbis_info_floor1 *)in;
vorbis_look_floor1 *look=(vorbis_look_floor1 *)_ogg_calloc(1,sizeof(*look));
int i,j,n=0;
look->vi=info;
look->n=info->postlist[1];
/* we drop each position value in-between already decoded values,
and use linear interpolation to predict each new value past the
edges. The positions are read in the order of the position
list... we precompute the bounding positions in the lookup. Of
course, the neighbors can change (if a position is declined), but
this is an initial mapping */
for(i=0;i<info->partitions;i++)n+=info->class_dim[info->partitionclass[i]];
n+=2;
look->posts=n;
/* also store a sorted position index */
for(i=0;i<n;i++)sortpointer[i]=info->postlist+i;
qsort(sortpointer,n,sizeof(*sortpointer),icomp);
/* points from sort order back to range number */
for(i=0;i<n;i++)look->forward_index[i]=sortpointer[i]-info->postlist;
/* quantize values to multiplier spec */
switch(info->mult){
case 1: /* 1024 -> 256 */
look->quant_q=256;
break;
case 2: /* 1024 -> 128 */
look->quant_q=128;
break;
case 3: /* 1024 -> 86 */
look->quant_q=86;
break;
case 4: /* 1024 -> 64 */
look->quant_q=64;
break;
}
/* discover our neighbors for decode where we don't use fit flags
(that would push the neighbors outward) */
for(i=0;i<n-2;i++){
int lo=0;
int hi=1;
int lx=0;
int hx=look->n;
int currentx=info->postlist[i+2];
for(j=0;j<i+2;j++){
int x=info->postlist[j];
if(x>lx && x<currentx){
lo=j;
lx=x;
}
if(x<hx && x>currentx){
hi=j;
hx=x;
}
}
look->loneighbor[i]=lo;
look->hineighbor[i]=hi;
}
return(look);
}
static int render_point(int x0,int x1,int y0,int y1,int x){
y0&=0x7fff; /* mask off flag */
y1&=0x7fff;
{
int dy=y1-y0;
int adx=x1-x0;
int ady=abs(dy);
int err=ady*(x-x0);
int off=err/adx;
if(dy<0)return(y0-off);
return(y0+off);
}
}
#ifdef _LOW_ACCURACY_
# define XdB(n) ((((n)>>8)+1)>>1)
#else
# define XdB(n) (n)
#endif
static const ogg_int32_t FLOOR_fromdB_LOOKUP[256]={
XdB(0x000000e5), XdB(0x000000f4), XdB(0x00000103), XdB(0x00000114),
XdB(0x00000126), XdB(0x00000139), XdB(0x0000014e), XdB(0x00000163),
XdB(0x0000017a), XdB(0x00000193), XdB(0x000001ad), XdB(0x000001c9),
XdB(0x000001e7), XdB(0x00000206), XdB(0x00000228), XdB(0x0000024c),
XdB(0x00000272), XdB(0x0000029b), XdB(0x000002c6), XdB(0x000002f4),
XdB(0x00000326), XdB(0x0000035a), XdB(0x00000392), XdB(0x000003cd),
XdB(0x0000040c), XdB(0x00000450), XdB(0x00000497), XdB(0x000004e4),
XdB(0x00000535), XdB(0x0000058c), XdB(0x000005e8), XdB(0x0000064a),
XdB(0x000006b3), XdB(0x00000722), XdB(0x00000799), XdB(0x00000818),
XdB(0x0000089e), XdB(0x0000092e), XdB(0x000009c6), XdB(0x00000a69),
XdB(0x00000b16), XdB(0x00000bcf), XdB(0x00000c93), XdB(0x00000d64),
XdB(0x00000e43), XdB(0x00000f30), XdB(0x0000102d), XdB(0x0000113a),
XdB(0x00001258), XdB(0x0000138a), XdB(0x000014cf), XdB(0x00001629),
XdB(0x0000179a), XdB(0x00001922), XdB(0x00001ac4), XdB(0x00001c82),
XdB(0x00001e5c), XdB(0x00002055), XdB(0x0000226f), XdB(0x000024ac),
XdB(0x0000270e), XdB(0x00002997), XdB(0x00002c4b), XdB(0x00002f2c),
XdB(0x0000323d), XdB(0x00003581), XdB(0x000038fb), XdB(0x00003caf),
XdB(0x000040a0), XdB(0x000044d3), XdB(0x0000494c), XdB(0x00004e10),
XdB(0x00005323), XdB(0x0000588a), XdB(0x00005e4b), XdB(0x0000646b),
XdB(0x00006af2), XdB(0x000071e5), XdB(0x0000794c), XdB(0x0000812e),
XdB(0x00008993), XdB(0x00009283), XdB(0x00009c09), XdB(0x0000a62d),
XdB(0x0000b0f9), XdB(0x0000bc79), XdB(0x0000c8b9), XdB(0x0000d5c4),
XdB(0x0000e3a9), XdB(0x0000f274), XdB(0x00010235), XdB(0x000112fd),
XdB(0x000124dc), XdB(0x000137e4), XdB(0x00014c29), XdB(0x000161bf),
XdB(0x000178bc), XdB(0x00019137), XdB(0x0001ab4a), XdB(0x0001c70e),
XdB(0x0001e4a1), XdB(0x0002041f), XdB(0x000225aa), XdB(0x00024962),
XdB(0x00026f6d), XdB(0x000297f0), XdB(0x0002c316), XdB(0x0002f109),
XdB(0x000321f9), XdB(0x00035616), XdB(0x00038d97), XdB(0x0003c8b4),
XdB(0x000407a7), XdB(0x00044ab2), XdB(0x00049218), XdB(0x0004de23),
XdB(0x00052f1e), XdB(0x0005855c), XdB(0x0005e135), XdB(0x00064306),
XdB(0x0006ab33), XdB(0x00071a24), XdB(0x0007904b), XdB(0x00080e20),
XdB(0x00089422), XdB(0x000922da), XdB(0x0009bad8), XdB(0x000a5cb6),
XdB(0x000b091a), XdB(0x000bc0b1), XdB(0x000c8436), XdB(0x000d5471),
XdB(0x000e3233), XdB(0x000f1e5f), XdB(0x001019e4), XdB(0x001125c1),
XdB(0x00124306), XdB(0x001372d5), XdB(0x0014b663), XdB(0x00160ef7),
XdB(0x00177df0), XdB(0x001904c1), XdB(0x001aa4f9), XdB(0x001c603d),
XdB(0x001e384f), XdB(0x00202f0f), XdB(0x0022467a), XdB(0x002480b1),
XdB(0x0026dff7), XdB(0x002966b3), XdB(0x002c1776), XdB(0x002ef4fc),
XdB(0x0032022d), XdB(0x00354222), XdB(0x0038b828), XdB(0x003c67c2),
XdB(0x004054ae), XdB(0x004482e8), XdB(0x0048f6af), XdB(0x004db488),
XdB(0x0052c142), XdB(0x005821ff), XdB(0x005ddc33), XdB(0x0063f5b0),
XdB(0x006a74a7), XdB(0x00715faf), XdB(0x0078bdce), XdB(0x0080967f),
XdB(0x0088f1ba), XdB(0x0091d7f9), XdB(0x009b5247), XdB(0x00a56a41),
XdB(0x00b02a27), XdB(0x00bb9ce2), XdB(0x00c7ce12), XdB(0x00d4ca17),
XdB(0x00e29e20), XdB(0x00f15835), XdB(0x0101074b), XdB(0x0111bb4e),
XdB(0x01238531), XdB(0x01367704), XdB(0x014aa402), XdB(0x016020a7),
XdB(0x017702c3), XdB(0x018f6190), XdB(0x01a955cb), XdB(0x01c4f9cf),
XdB(0x01e269a8), XdB(0x0201c33b), XdB(0x0223265a), XdB(0x0246b4ea),
XdB(0x026c9302), XdB(0x0294e716), XdB(0x02bfda13), XdB(0x02ed9793),
XdB(0x031e4e09), XdB(0x03522ee4), XdB(0x03896ed0), XdB(0x03c445e2),
XdB(0x0402efd6), XdB(0x0445ac4b), XdB(0x048cbefc), XdB(0x04d87013),
XdB(0x05290c67), XdB(0x057ee5ca), XdB(0x05da5364), XdB(0x063bb204),
XdB(0x06a36485), XdB(0x0711d42b), XdB(0x0787710e), XdB(0x0804b299),
XdB(0x088a17ef), XdB(0x0918287e), XdB(0x09af747c), XdB(0x0a50957e),
XdB(0x0afc2f19), XdB(0x0bb2ef7f), XdB(0x0c759034), XdB(0x0d44d6ca),
XdB(0x0e2195bc), XdB(0x0f0cad0d), XdB(0x10070b62), XdB(0x1111aeea),
XdB(0x122da66c), XdB(0x135c120f), XdB(0x149e24d9), XdB(0x15f525b1),
XdB(0x176270e3), XdB(0x18e7794b), XdB(0x1a85c9ae), XdB(0x1c3f06d1),
XdB(0x1e14f07d), XdB(0x200963d7), XdB(0x221e5ccd), XdB(0x2455f870),
XdB(0x26b2770b), XdB(0x29363e2b), XdB(0x2be3db5c), XdB(0x2ebe06b6),
XdB(0x31c7a55b), XdB(0x3503ccd4), XdB(0x3875c5aa), XdB(0x3c210f44),
XdB(0x4009632b), XdB(0x4432b8cf), XdB(0x48a149bc), XdB(0x4d59959e),
XdB(0x52606733), XdB(0x57bad899), XdB(0x5d6e593a), XdB(0x6380b298),
XdB(0x69f80e9a), XdB(0x70dafda8), XdB(0x78307d76), XdB(0x7fffffff),
};
static void render_line(int n, int x0,int x1,int y0,int y1,ogg_int32_t *d){
int dy=y1-y0;
int adx=x1-x0;
int ady=abs(dy);
int base=dy/adx;
int sy=(dy<0?base-1:base+1);
int x=x0;
int y=y0;
int err=0;
if(n>x1)n=x1;
ady-=abs(base*adx);
if(x<n)
d[x]= MULT31_SHIFT15(d[x],FLOOR_fromdB_LOOKUP[y]);
while(++x<n){
err=err+ady;
if(err>=adx){
err-=adx;
y+=sy;
}else{
y+=base;
}
d[x]= MULT31_SHIFT15(d[x],FLOOR_fromdB_LOOKUP[y]);
}
}
static void *floor1_inverse1(vorbis_block *vb,vorbis_look_floor *in){
vorbis_look_floor1 *look=(vorbis_look_floor1 *)in;
vorbis_info_floor1 *info=look->vi;
codec_setup_info *ci=(codec_setup_info *)vb->vd->vi->codec_setup;
int i,j,k;
codebook *books=ci->fullbooks;
/* unpack wrapped/predicted values from stream */
if(oggpack_read(&vb->opb,1)==1){
int *fit_value=(int *)_vorbis_block_alloc(vb,(look->posts)*sizeof(*fit_value));
fit_value[0]=oggpack_read(&vb->opb,ilog(look->quant_q-1));
fit_value[1]=oggpack_read(&vb->opb,ilog(look->quant_q-1));
/* partition by partition */
/* partition by partition */
for(i=0,j=2;i<info->partitions;i++){
int classv=info->partitionclass[i];
int cdim=info->class_dim[classv];
int csubbits=info->class_subs[classv];
int csub=1<<csubbits;
int cval=0;
/* decode the partition's first stage cascade value */
if(csubbits){
cval=vorbis_book_decode(books+info->class_book[classv],&vb->opb);
if(cval==-1)goto eop;
}
for(k=0;k<cdim;k++){
int book=info->class_subbook[classv][cval&(csub-1)];
cval>>=csubbits;
if(book>=0){
if((fit_value[j+k]=vorbis_book_decode(books+book,&vb->opb))==-1)
goto eop;
}else{
fit_value[j+k]=0;
}
}
j+=cdim;
}
/* unwrap positive values and reconsitute via linear interpolation */
for(i=2;i<look->posts;i++){
int predicted=render_point(info->postlist[look->loneighbor[i-2]],
info->postlist[look->hineighbor[i-2]],
fit_value[look->loneighbor[i-2]],
fit_value[look->hineighbor[i-2]],
info->postlist[i]);
int hiroom=look->quant_q-predicted;
int loroom=predicted;
int room=(hiroom<loroom?hiroom:loroom)<<1;
int val=fit_value[i];
if(val){
if(val>=room){
if(hiroom>loroom){
val = val-loroom;
}else{
val = -1-(val-hiroom);
}
}else{
if(val&1){
val= -((val+1)>>1);
}else{
val>>=1;
}
}
fit_value[i]=(val+predicted)&0x7fff;;
fit_value[look->loneighbor[i-2]]&=0x7fff;
fit_value[look->hineighbor[i-2]]&=0x7fff;
}else{
fit_value[i]=predicted|0x8000;
}
}
return(fit_value);
}
eop:
return(NULL);
}
static int floor1_inverse2(vorbis_block *vb,vorbis_look_floor *in,void *memo,
ogg_int32_t *out){
vorbis_look_floor1 *look=(vorbis_look_floor1 *)in;
vorbis_info_floor1 *info=look->vi;
codec_setup_info *ci=(codec_setup_info *)vb->vd->vi->codec_setup;
int n=ci->blocksizes[vb->W]/2;
int j;
if(memo){
/* render the lines */
int *fit_value=(int *)memo;
int hx=0;
int lx=0;
int ly=fit_value[0]*info->mult;
/* guard lookup against out-of-range values */
ly=(ly<0?0:ly>255?255:ly);
for(j=1;j<look->posts;j++){
int current=look->forward_index[j];
int hy=fit_value[current]&0x7fff;
if(hy==fit_value[current]){
hx=info->postlist[current];
hy*=info->mult;
/* guard lookup against out-of-range values */
hy=(hy<0?0:hy>255?255:hy);
render_line(n,lx,hx,ly,hy,out);
lx=hx;
ly=hy;
}
}
for(j=hx;j<n;j++)out[j]*=ly; /* be certain */
return(1);
}
memset(out,0,sizeof(*out)*n);
return(0);
}
/* export hooks */
vorbis_func_floor floor1_exportbundle={
&floor1_unpack,&floor1_look,&floor1_free_info,
&floor1_free_look,&floor1_inverse1,&floor1_inverse2
};
File diff suppressed because it is too large. Load diff
+401
View File
@@ -0,0 +1,401 @@
/********************************************************************
* *
* THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. *
* *
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2003 *
* BY THE Xiph.Org FOUNDATION http://www.xiph.org/ *
* *
********************************************************************
function: maintain the info structure, info <-> header packets
********************************************************************/
/* general handling of the header and the vorbis_info structure (and
substructures) */
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <limits.h>
#include <ogg/ogg.h>
#include "ivorbiscodec.h"
#include "codec_internal.h"
#include "codebook.h"
#include "registry.h"
#include "window.h"
#include "misc.h"
/* helpers */
static void _v_readstring(oggpack_buffer *o,char *buf,int bytes){
while(bytes--){
*buf++=oggpack_read(o,8);
}
}
void vorbis_comment_init(vorbis_comment *vc){
memset(vc,0,sizeof(*vc));
}
/* This is more or less the same as strncasecmp - but that doesn't exist
* everywhere, and this is a fairly trivial function, so we include it */
static int tagcompare(const char *s1, const char *s2, int n){
int c=0;
while(c < n){
if(toupper(s1[c]) != toupper(s2[c]))
return !0;
c++;
}
return 0;
}
char *vorbis_comment_query(vorbis_comment *vc, char *tag, int count){
long i;
int found = 0;
int taglen = strlen(tag)+1; /* +1 for the = we append */
char *fulltag = (char *)alloca(taglen+ 1);
strcpy(fulltag, tag);
strcat(fulltag, "=");
for(i=0;i<vc->comments;i++){
if(!tagcompare(vc->user_comments[i], fulltag, taglen)){
if(count == found)
/* We return a pointer to the data, not a copy */
return vc->user_comments[i] + taglen;
else
found++;
}
}
return NULL; /* didn't find anything */
}
int vorbis_comment_query_count(vorbis_comment *vc, char *tag){
int i,count=0;
int taglen = strlen(tag)+1; /* +1 for the = we append */
char *fulltag = (char *)alloca(taglen+1);
strcpy(fulltag,tag);
strcat(fulltag, "=");
for(i=0;i<vc->comments;i++){
if(!tagcompare(vc->user_comments[i], fulltag, taglen))
count++;
}
return count;
}
void vorbis_comment_clear(vorbis_comment *vc){
if(vc){
long i;
if(vc->user_comments){
for(i=0;i<vc->comments;i++)
if(vc->user_comments[i])_ogg_free(vc->user_comments[i]);
_ogg_free(vc->user_comments);
}
if(vc->comment_lengths)_ogg_free(vc->comment_lengths);
if(vc->vendor)_ogg_free(vc->vendor);
memset(vc,0,sizeof(*vc));
}
}
/* blocksize 0 is guaranteed to be short, 1 is guarantted to be long.
They may be equal, but short will never ge greater than long */
int vorbis_info_blocksize(vorbis_info *vi,int zo){
codec_setup_info *ci = (codec_setup_info *)vi->codec_setup;
return ci ? ci->blocksizes[zo] : -1;
}
/* used by synthesis, which has a full, alloced vi */
void vorbis_info_init(vorbis_info *vi){
memset(vi,0,sizeof(*vi));
vi->codec_setup=(codec_setup_info *)_ogg_calloc(1,sizeof(codec_setup_info));
}
void vorbis_info_clear(vorbis_info *vi){
codec_setup_info *ci=(codec_setup_info *)vi->codec_setup;
int i;
if(ci){
for(i=0;i<ci->modes;i++)
if(ci->mode_param[i])_ogg_free(ci->mode_param[i]);
for(i=0;i<ci->maps;i++) /* unpack does the range checking */
if(ci->map_param[i])
_mapping_P[ci->map_type[i]]->free_info(ci->map_param[i]);
for(i=0;i<ci->floors;i++) /* unpack does the range checking */
if(ci->floor_param[i])
_floor_P[ci->floor_type[i]]->free_info(ci->floor_param[i]);
for(i=0;i<ci->residues;i++) /* unpack does the range checking */
if(ci->residue_param[i])
_residue_P[ci->residue_type[i]]->free_info(ci->residue_param[i]);
for(i=0;i<ci->books;i++){
if(ci->book_param[i]){
/* knows if the book was not alloced */
vorbis_staticbook_destroy(ci->book_param[i]);
}
if(ci->fullbooks)
vorbis_book_clear(ci->fullbooks+i);
}
if(ci->fullbooks)
_ogg_free(ci->fullbooks);
_ogg_free(ci);
}
memset(vi,0,sizeof(*vi));
}
/* Header packing/unpacking ********************************************/
static int _vorbis_unpack_info(vorbis_info *vi,oggpack_buffer *opb){
codec_setup_info *ci=(codec_setup_info *)vi->codec_setup;
if(!ci)return(OV_EFAULT);
vi->version=oggpack_read(opb,32);
if(vi->version!=0)return(OV_EVERSION);
vi->channels=oggpack_read(opb,8);
vi->rate=oggpack_read(opb,32);
vi->bitrate_upper=oggpack_read(opb,32);
vi->bitrate_nominal=oggpack_read(opb,32);
vi->bitrate_lower=oggpack_read(opb,32);
ci->blocksizes[0]=1<<oggpack_read(opb,4);
ci->blocksizes[1]=1<<oggpack_read(opb,4);
if(vi->rate<1)goto err_out;
if(vi->channels<1)goto err_out;
if(ci->blocksizes[0]<64)goto err_out;
if(ci->blocksizes[1]<ci->blocksizes[0])goto err_out;
if(ci->blocksizes[1]>8192)goto err_out;
if(oggpack_read(opb,1)!=1)goto err_out; /* EOP check */
return(0);
err_out:
vorbis_info_clear(vi);
return(OV_EBADHEADER);
}
static int _vorbis_unpack_comment(vorbis_comment *vc,oggpack_buffer *opb){
int i;
int vendorlen;
vendorlen=oggpack_read(opb,32);
if(vendorlen<0)goto err_out;
if(vendorlen>opb->storage-oggpack_bytes(opb))goto err_out;
vc->vendor=(char *)_ogg_calloc(vendorlen+1,1);
if(vc->vendor==NULL)goto err_out;
_v_readstring(opb,vc->vendor,vendorlen);
i=oggpack_read(opb,32);
if(i<0||i>=INT_MAX||i>(opb->storage-oggpack_bytes(opb))>>2)goto err_out;
vc->user_comments=(char **)_ogg_calloc(i+1,sizeof(*vc->user_comments));
vc->comment_lengths=(int *)_ogg_calloc(i+1, sizeof(*vc->comment_lengths));
if(vc->user_comments==NULL||vc->comment_lengths==NULL)goto err_out;
vc->comments=i;
for(i=0;i<vc->comments;i++){
int len=oggpack_read(opb,32);
if(len<0||len>opb->storage-oggpack_bytes(opb))goto err_out;
vc->comment_lengths[i]=len;
vc->user_comments[i]=(char *)_ogg_calloc(len+1,1);
if(vc->user_comments[i]==NULL){
vc->comments=i;
goto err_out;
}
_v_readstring(opb,vc->user_comments[i],len);
}
if(oggpack_read(opb,1)!=1)goto err_out; /* EOP check */
return(0);
err_out:
vorbis_comment_clear(vc);
return(OV_EBADHEADER);
}
/* all of the real encoding details are here. The modes, books,
everything */
static int _vorbis_unpack_books(vorbis_info *vi,oggpack_buffer *opb){
codec_setup_info *ci=(codec_setup_info *)vi->codec_setup;
int i;
/* codebooks */
ci->books=oggpack_read(opb,8)+1;
if(ci->books<=0)goto err_out;
for(i=0;i<ci->books;i++){
ci->book_param[i]=vorbis_staticbook_unpack(opb);
if(!ci->book_param[i])goto err_out;
}
/* time backend settings */
ci->times=oggpack_read(opb,6)+1;
if(ci->times<=0)goto err_out;
for(i=0;i<ci->times;i++){
ci->time_type[i]=oggpack_read(opb,16);
if(ci->time_type[i]<0 || ci->time_type[i]>=VI_TIMEB)goto err_out;
/* ci->time_param[i]=_time_P[ci->time_type[i]]->unpack(vi,opb);
Vorbis I has no time backend */
/*if(!ci->time_param[i])goto err_out;*/
}
/* floor backend settings */
ci->floors=oggpack_read(opb,6)+1;
if(ci->floors<=0)goto err_out;
for(i=0;i<ci->floors;i++){
ci->floor_type[i]=oggpack_read(opb,16);
if(ci->floor_type[i]<0 || ci->floor_type[i]>=VI_FLOORB)goto err_out;
ci->floor_param[i]=_floor_P[ci->floor_type[i]]->unpack(vi,opb);
if(!ci->floor_param[i])goto err_out;
}
/* residue backend settings */
ci->residues=oggpack_read(opb,6)+1;
if(ci->residues<=0)goto err_out;
for(i=0;i<ci->residues;i++){
ci->residue_type[i]=oggpack_read(opb,16);
if(ci->residue_type[i]<0 || ci->residue_type[i]>=VI_RESB)goto err_out;
ci->residue_param[i]=_residue_P[ci->residue_type[i]]->unpack(vi,opb);
if(!ci->residue_param[i])goto err_out;
}
/* map backend settings */
ci->maps=oggpack_read(opb,6)+1;
if(ci->maps<=0)goto err_out;
for(i=0;i<ci->maps;i++){
ci->map_type[i]=oggpack_read(opb,16);
if(ci->map_type[i]<0 || ci->map_type[i]>=VI_MAPB)goto err_out;
ci->map_param[i]=_mapping_P[ci->map_type[i]]->unpack(vi,opb);
if(!ci->map_param[i])goto err_out;
}
/* mode settings */
ci->modes=oggpack_read(opb,6)+1;
if(ci->modes<=0)goto err_out;
for(i=0;i<ci->modes;i++){
ci->mode_param[i]=(vorbis_info_mode *)_ogg_calloc(1,sizeof(*ci->mode_param[i]));
ci->mode_param[i]->blockflag=oggpack_read(opb,1);
ci->mode_param[i]->windowtype=oggpack_read(opb,16);
ci->mode_param[i]->transformtype=oggpack_read(opb,16);
ci->mode_param[i]->mapping=oggpack_read(opb,8);
if(ci->mode_param[i]->windowtype>=VI_WINDOWB)goto err_out;
if(ci->mode_param[i]->transformtype>=VI_WINDOWB)goto err_out;
if(ci->mode_param[i]->mapping>=ci->maps)goto err_out;
if(ci->mode_param[i]->mapping<0)goto err_out;
}
if(oggpack_read(opb,1)!=1)goto err_out; /* top level EOP check */
return(0);
err_out:
vorbis_info_clear(vi);
return(OV_EBADHEADER);
}
/* Is this packet a vorbis ID header? */
int vorbis_synthesis_idheader(ogg_packet *op){
oggpack_buffer opb;
char buffer[6];
if(op){
oggpack_readinit(&opb,op->packet,op->bytes);
if(!op->b_o_s)
return(0); /* Not the initial packet */
if(oggpack_read(&opb,8) != 1)
return 0; /* not an ID header */
memset(buffer,0,6);
_v_readstring(&opb,buffer,6);
if(memcmp(buffer,"vorbis",6))
return 0; /* not vorbis */
return 1;
}
return 0;
}
/* The Vorbis header is in three packets; the initial small packet in
the first page that identifies basic parameters, a second packet
with bitstream comments and a third packet that holds the
codebook. */
int vorbis_synthesis_headerin(vorbis_info *vi,vorbis_comment *vc,ogg_packet *op){
oggpack_buffer opb;
if(op){
oggpack_readinit(&opb,op->packet,op->bytes);
/* Which of the three types of header is this? */
/* Also verify header-ness, vorbis */
{
char buffer[6];
int packtype=oggpack_read(&opb,8);
memset(buffer,0,6);
_v_readstring(&opb,buffer,6);
if(memcmp(buffer,"vorbis",6)){
/* not a vorbis header */
return(OV_ENOTVORBIS);
}
switch(packtype){
case 0x01: /* least significant *bit* is read first */
if(!op->b_o_s){
/* Not the initial packet */
return(OV_EBADHEADER);
}
if(vi->rate!=0){
/* previously initialized info header */
return(OV_EBADHEADER);
}
return(_vorbis_unpack_info(vi,&opb));
case 0x03: /* least significant *bit* is read first */
if(vi->rate==0){
/* um... we didn't get the initial header */
return(OV_EBADHEADER);
}
if(vc->vendor!=NULL){
/* previously initialized comment header */
return(OV_EBADHEADER);
}
return(_vorbis_unpack_comment(vc,&opb));
case 0x05: /* least significant *bit* is read first */
if(vi->rate==0 || vc->vendor==NULL){
/* um... we didn;t get the initial header or comments yet */
return(OV_EBADHEADER);
}
if(vi->codec_setup==NULL){
/* improperly initialized vorbis_info */
return(OV_EFAULT);
}
if(((codec_setup_info *)vi->codec_setup)->books>0){
/* previously initialized setup header */
return(OV_EBADHEADER);
}
return(_vorbis_unpack_books(vi,&opb));
default:
/* Not a valid vorbis header type */
return(OV_EBADHEADER);
break;
}
}
}
return(OV_EBADHEADER);
}
+204
View File
@@ -0,0 +1,204 @@
/********************************************************************
* *
* THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. *
* *
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 *
* BY THE Xiph.Org FOUNDATION http://www.xiph.org/ *
* *
********************************************************************
function: libvorbis codec headers
********************************************************************/
#ifndef _vorbis_codec_h_
#define _vorbis_codec_h_
#ifdef __cplusplus
extern "C"
{
#endif /* __cplusplus */
#include <ogg/ogg.h>
typedef struct vorbis_info{
int version;
int channels;
long rate;
/* The below bitrate declarations are *hints*.
Combinations of the three values carry the following implications:
all three set to the same value:
implies a fixed rate bitstream
only nominal set:
implies a VBR stream that averages the nominal bitrate. No hard
upper/lower limit
upper and or lower set:
implies a VBR bitstream that obeys the bitrate limits. nominal
may also be set to give a nominal rate.
none set:
the coder does not care to speculate.
*/
long bitrate_upper;
long bitrate_nominal;
long bitrate_lower;
long bitrate_window;
void *codec_setup;
} vorbis_info;
/* vorbis_dsp_state buffers the current vorbis audio
analysis/synthesis state. The DSP state belongs to a specific
logical bitstream ****************************************************/
typedef struct vorbis_dsp_state{
int analysisp;
vorbis_info *vi;
ogg_int32_t **pcm;
ogg_int32_t **pcmret;
int pcm_storage;
int pcm_current;
int pcm_returned;
int preextrapolate;
int eofflag;
long lW;
long W;
long nW;
long centerW;
ogg_int64_t granulepos;
ogg_int64_t sequence;
void *backend_state;
} vorbis_dsp_state;
typedef struct vorbis_block{
/* necessary stream state for linking to the framing abstraction */
ogg_int32_t **pcm; /* this is a pointer into local storage */
oggpack_buffer opb;
long lW;
long W;
long nW;
int pcmend;
int mode;
int eofflag;
ogg_int64_t granulepos;
ogg_int64_t sequence;
vorbis_dsp_state *vd; /* For read-only access of configuration */
/* local storage to avoid remallocing; it's up to the mapping to
structure it */
void *localstore;
long localtop;
long localalloc;
long totaluse;
struct alloc_chain *reap;
} vorbis_block;
/* vorbis_block is a single block of data to be processed as part of
the analysis/synthesis stream; it belongs to a specific logical
bitstream, but is independant from other vorbis_blocks belonging to
that logical bitstream. *************************************************/
struct alloc_chain{
void *ptr;
struct alloc_chain *next;
};
/* vorbis_info contains all the setup information specific to the
specific compression/decompression mode in progress (eg,
psychoacoustic settings, channel setup, options, codebook
etc). vorbis_info and substructures are in backends.h.
*********************************************************************/
/* the comments are not part of vorbis_info so that vorbis_info can be
static storage */
typedef struct vorbis_comment{
/* unlimited user comment fields. libvorbis writes 'libvorbis'
whatever vendor is set to in encode */
char **user_comments;
int *comment_lengths;
int comments;
char *vendor;
} vorbis_comment;
/* libvorbis encodes in two abstraction layers; first we perform DSP
and produce a packet (see docs/analysis.txt). The packet is then
coded into a framed OggSquish bitstream by the second layer (see
docs/framing.txt). Decode is the reverse process; we sync/frame
the bitstream and extract individual packets, then decode the
packet back into PCM audio.
The extra framing/packetizing is used in streaming formats, such as
files. Over the net (such as with UDP), the framing and
packetization aren't necessary as they're provided by the transport
and the streaming layer is not used */
/* Vorbis PRIMITIVES: general ***************************************/
extern void vorbis_info_init(vorbis_info *vi);
extern void vorbis_info_clear(vorbis_info *vi);
extern int vorbis_info_blocksize(vorbis_info *vi,int zo);
extern void vorbis_comment_init(vorbis_comment *vc);
extern void vorbis_comment_add(vorbis_comment *vc, char *comment);
extern void vorbis_comment_add_tag(vorbis_comment *vc,
char *tag, char *contents);
extern char *vorbis_comment_query(vorbis_comment *vc, char *tag, int count);
extern int vorbis_comment_query_count(vorbis_comment *vc, char *tag);
extern void vorbis_comment_clear(vorbis_comment *vc);
extern int vorbis_block_init(vorbis_dsp_state *v, vorbis_block *vb);
extern int vorbis_block_clear(vorbis_block *vb);
extern void vorbis_dsp_clear(vorbis_dsp_state *v);
/* Vorbis PRIMITIVES: synthesis layer *******************************/
extern int vorbis_synthesis_idheader(ogg_packet *op);
extern int vorbis_synthesis_headerin(vorbis_info *vi,vorbis_comment *vc,
ogg_packet *op);
extern int vorbis_synthesis_init(vorbis_dsp_state *v,vorbis_info *vi);
extern int vorbis_synthesis_restart(vorbis_dsp_state *v);
extern int vorbis_synthesis(vorbis_block *vb,ogg_packet *op);
extern int vorbis_synthesis_trackonly(vorbis_block *vb,ogg_packet *op);
extern int vorbis_synthesis_blockin(vorbis_dsp_state *v,vorbis_block *vb);
extern int vorbis_synthesis_pcmout(vorbis_dsp_state *v,ogg_int32_t ***pcm);
extern int vorbis_synthesis_read(vorbis_dsp_state *v,int samples);
extern long vorbis_packet_blocksize(vorbis_info *vi,ogg_packet *op);
/* Vorbis ERRORS and return codes ***********************************/
#define OV_FALSE -1
#define OV_EOF -2
#define OV_HOLE -3
#define OV_EREAD -128
#define OV_EFAULT -129
#define OV_EIMPL -130
#define OV_EINVAL -131
#define OV_ENOTVORBIS -132
#define OV_EBADHEADER -133
#define OV_EVERSION -134
#define OV_ENOTAUDIO -135
#define OV_EBADPACKET -136
#define OV_EBADLINK -137
#define OV_ENOSEEK -138
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif
+131
View File
@@ -0,0 +1,131 @@
/********************************************************************
* *
* THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. *
* *
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 *
* BY THE Xiph.Org FOUNDATION http://www.xiph.org/ *
* *
********************************************************************
function: stdio-based convenience library for opening/seeking/decoding
********************************************************************/
#ifndef _OV_FILE_H_
#define _OV_FILE_H_
#ifdef __cplusplus
extern "C"
{
#endif /* __cplusplus */
#include <stdio.h>
#include "ivorbiscodec.h"
#define CHUNKSIZE 65535
#define READSIZE 1024
/* The function prototypes for the callbacks are basically the same as for
* the stdio functions fread, fseek, fclose, ftell.
* The one difference is that the FILE * arguments have been replaced with
* a void * - this is to be used as a pointer to whatever internal data these
* functions might need. In the stdio case, it's just a FILE * cast to a void *
*
* If you use other functions, check the docs for these functions and return
* the right values. For seek_func(), you *MUST* return -1 if the stream is
* unseekable
*/
typedef struct {
size_t (*read_func) (void *ptr, size_t size, size_t nmemb, void *datasource);
int (*seek_func) (void *datasource, ogg_int64_t offset, int whence);
int (*close_func) (void *datasource);
long (*tell_func) (void *datasource);
} ov_callbacks;
#define NOTOPEN 0
#define PARTOPEN 1
#define OPENED 2
#define STREAMSET 3
#define INITSET 4
typedef struct OggVorbis_File {
void *datasource; /* Pointer to a FILE *, etc. */
int seekable;
ogg_int64_t offset;
ogg_int64_t end;
ogg_sync_state oy;
/* If the FILE handle isn't seekable (eg, a pipe), only the current
stream appears */
int links;
ogg_int64_t *offsets;
ogg_int64_t *dataoffsets;
ogg_uint32_t *serialnos;
ogg_int64_t *pcmlengths;
vorbis_info *vi;
vorbis_comment *vc;
/* Decoding working state local storage */
ogg_int64_t pcm_offset;
int ready_state;
ogg_uint32_t current_serialno;
int current_link;
ogg_int64_t bittrack;
ogg_int64_t samptrack;
ogg_stream_state os; /* take physical pages, weld into a logical
stream of packets */
vorbis_dsp_state vd; /* central working state for the packet->PCM decoder */
vorbis_block vb; /* local working space for packet->PCM decode */
ov_callbacks callbacks;
} OggVorbis_File;
extern int ov_clear(OggVorbis_File *vf);
extern int ov_open(FILE *f,OggVorbis_File *vf,const char *initial,long ibytes);
extern int ov_open_callbacks(void *datasource, OggVorbis_File *vf,
const char *initial, long ibytes, ov_callbacks callbacks);
extern int ov_test(FILE *f,OggVorbis_File *vf,const char *initial,long ibytes);
extern int ov_test_callbacks(void *datasource, OggVorbis_File *vf,
const char *initial, long ibytes, ov_callbacks callbacks);
extern int ov_test_open(OggVorbis_File *vf);
extern long ov_bitrate(OggVorbis_File *vf,int i);
extern long ov_bitrate_instant(OggVorbis_File *vf);
extern long ov_streams(OggVorbis_File *vf);
extern long ov_seekable(OggVorbis_File *vf);
extern long ov_serialnumber(OggVorbis_File *vf,int i);
extern ogg_int64_t ov_raw_total(OggVorbis_File *vf,int i);
extern ogg_int64_t ov_pcm_total(OggVorbis_File *vf,int i);
extern ogg_int64_t ov_time_total(OggVorbis_File *vf,int i);
extern int ov_raw_seek(OggVorbis_File *vf,ogg_int64_t pos);
extern int ov_pcm_seek(OggVorbis_File *vf,ogg_int64_t pos);
extern int ov_pcm_seek_page(OggVorbis_File *vf,ogg_int64_t pos);
extern int ov_time_seek(OggVorbis_File *vf,ogg_int64_t pos);
extern int ov_time_seek_page(OggVorbis_File *vf,ogg_int64_t pos);
extern ogg_int64_t ov_raw_tell(OggVorbis_File *vf);
extern ogg_int64_t ov_pcm_tell(OggVorbis_File *vf);
extern ogg_int64_t ov_time_tell(OggVorbis_File *vf);
extern vorbis_info *ov_info(OggVorbis_File *vf,int link);
extern vorbis_comment *ov_comment(OggVorbis_File *vf,int link);
extern long ov_read(OggVorbis_File *vf,char *buffer,int length,
int *bitstream);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif
+136
View File
@@ -0,0 +1,136 @@
/********************************************************************
* *
* THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. *
* *
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 *
* BY THE Xiph.Org FOUNDATION http://www.xiph.org/ *
* *
********************************************************************
function: lookup data
********************************************************************/
#ifndef _V_LOOKUP_DATA_H_
#define _V_LOOKUP_DATA_H_
#include <ogg/os_types.h>
#define FROMdB_LOOKUP_SZ 35
#define FROMdB2_LOOKUP_SZ 32
#define FROMdB_SHIFT 5
#define FROMdB2_SHIFT 3
#define FROMdB2_MASK 31
static const ogg_int32_t FROMdB_LOOKUP[FROMdB_LOOKUP_SZ]={
0x003fffff, 0x0028619b, 0x00197a96, 0x0010137a,
0x000a24b0, 0x00066666, 0x000409c3, 0x00028c42,
0x00019b8c, 0x000103ab, 0x0000a3d7, 0x00006760,
0x0000413a, 0x00002928, 0x000019f8, 0x00001062,
0x00000a56, 0x00000686, 0x0000041e, 0x00000299,
0x000001a3, 0x00000109, 0x000000a7, 0x00000069,
0x00000042, 0x0000002a, 0x0000001a, 0x00000011,
0x0000000b, 0x00000007, 0x00000004, 0x00000003,
0x00000002, 0x00000001, 0x00000001};
static const ogg_int32_t FROMdB2_LOOKUP[FROMdB2_LOOKUP_SZ]={
0x000001fc, 0x000001f5, 0x000001ee, 0x000001e7,
0x000001e0, 0x000001d9, 0x000001d2, 0x000001cc,
0x000001c5, 0x000001bf, 0x000001b8, 0x000001b2,
0x000001ac, 0x000001a6, 0x000001a0, 0x0000019a,
0x00000194, 0x0000018e, 0x00000188, 0x00000183,
0x0000017d, 0x00000178, 0x00000172, 0x0000016d,
0x00000168, 0x00000163, 0x0000015e, 0x00000159,
0x00000154, 0x0000014f, 0x0000014a, 0x00000145,
};
#define INVSQ_LOOKUP_I_SHIFT 10
#define INVSQ_LOOKUP_I_MASK 1023
static const long INVSQ_LOOKUP_I[64+1]={
92682, 91966, 91267, 90583,
89915, 89261, 88621, 87995,
87381, 86781, 86192, 85616,
85051, 84497, 83953, 83420,
82897, 82384, 81880, 81385,
80899, 80422, 79953, 79492,
79039, 78594, 78156, 77726,
77302, 76885, 76475, 76072,
75674, 75283, 74898, 74519,
74146, 73778, 73415, 73058,
72706, 72359, 72016, 71679,
71347, 71019, 70695, 70376,
70061, 69750, 69444, 69141,
68842, 68548, 68256, 67969,
67685, 67405, 67128, 66855,
66585, 66318, 66054, 65794,
65536,
};
static const long INVSQ_LOOKUP_IDel[64]={
716, 699, 684, 668,
654, 640, 626, 614,
600, 589, 576, 565,
554, 544, 533, 523,
513, 504, 495, 486,
477, 469, 461, 453,
445, 438, 430, 424,
417, 410, 403, 398,
391, 385, 379, 373,
368, 363, 357, 352,
347, 343, 337, 332,
328, 324, 319, 315,
311, 306, 303, 299,
294, 292, 287, 284,
280, 277, 273, 270,
267, 264, 260, 258,
};
#define COS_LOOKUP_I_SHIFT 9
#define COS_LOOKUP_I_MASK 511
#define COS_LOOKUP_I_SZ 128
static const ogg_int32_t COS_LOOKUP_I[COS_LOOKUP_I_SZ+1]={
16384, 16379, 16364, 16340,
16305, 16261, 16207, 16143,
16069, 15986, 15893, 15791,
15679, 15557, 15426, 15286,
15137, 14978, 14811, 14635,
14449, 14256, 14053, 13842,
13623, 13395, 13160, 12916,
12665, 12406, 12140, 11866,
11585, 11297, 11003, 10702,
10394, 10080, 9760, 9434,
9102, 8765, 8423, 8076,
7723, 7366, 7005, 6639,
6270, 5897, 5520, 5139,
4756, 4370, 3981, 3590,
3196, 2801, 2404, 2006,
1606, 1205, 804, 402,
0, -401, -803, -1204,
-1605, -2005, -2403, -2800,
-3195, -3589, -3980, -4369,
-4755, -5138, -5519, -5896,
-6269, -6638, -7004, -7365,
-7722, -8075, -8422, -8764,
-9101, -9433, -9759, -10079,
-10393, -10701, -11002, -11296,
-11584, -11865, -12139, -12405,
-12664, -12915, -13159, -13394,
-13622, -13841, -14052, -14255,
-14448, -14634, -14810, -14977,
-15136, -15285, -15425, -15556,
-15678, -15790, -15892, -15985,
-16068, -16142, -16206, -16260,
-16304, -16339, -16363, -16378,
-16383,
};
#endif
+328
View File
@@ -0,0 +1,328 @@
/********************************************************************
* *
* THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. *
* *
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 *
* BY THE Xiph.Org FOUNDATION http://www.xiph.org/ *
* *
********************************************************************
function: channel mapping 0 implementation
********************************************************************/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <ogg/ogg.h>
#include "ivorbiscodec.h"
#include "mdct.h"
#include "codec_internal.h"
#include "codebook.h"
#include "window.h"
#include "registry.h"
#include "misc.h"
/* simplistic, wasteful way of doing this (unique lookup for each
mode/submapping); there should be a central repository for
identical lookups. That will require minor work, so I'm putting it
off as low priority.
Why a lookup for each backend in a given mode? Because the
blocksize is set by the mode, and low backend lookups may require
parameters from other areas of the mode/mapping */
typedef struct {
vorbis_info_mode *mode;
vorbis_info_mapping0 *map;
vorbis_look_floor **floor_look;
vorbis_look_residue **residue_look;
vorbis_func_floor **floor_func;
vorbis_func_residue **residue_func;
int ch;
long lastframe; /* if a different mode is called, we need to
invalidate decay */
} vorbis_look_mapping0;
static void mapping0_free_info(vorbis_info_mapping *i){
vorbis_info_mapping0 *info=(vorbis_info_mapping0 *)i;
if(info){
memset(info,0,sizeof(*info));
_ogg_free(info);
}
}
static void mapping0_free_look(vorbis_look_mapping *look){
int i;
vorbis_look_mapping0 *l=(vorbis_look_mapping0 *)look;
if(l){
for(i=0;i<l->map->submaps;i++){
l->floor_func[i]->free_look(l->floor_look[i]);
l->residue_func[i]->free_look(l->residue_look[i]);
}
_ogg_free(l->floor_func);
_ogg_free(l->residue_func);
_ogg_free(l->floor_look);
_ogg_free(l->residue_look);
memset(l,0,sizeof(*l));
_ogg_free(l);
}
}
static vorbis_look_mapping *mapping0_look(vorbis_dsp_state *vd,vorbis_info_mode *vm,
vorbis_info_mapping *m){
int i;
vorbis_info *vi=vd->vi;
codec_setup_info *ci=(codec_setup_info *)vi->codec_setup;
vorbis_look_mapping0 *look=(vorbis_look_mapping0 *)_ogg_calloc(1,sizeof(*look));
vorbis_info_mapping0 *info=look->map=(vorbis_info_mapping0 *)m;
look->mode=vm;
look->floor_look=(vorbis_look_floor **)_ogg_calloc(info->submaps,sizeof(*look->floor_look));
look->residue_look=(vorbis_look_residue **)_ogg_calloc(info->submaps,sizeof(*look->residue_look));
look->floor_func=(vorbis_func_floor **)_ogg_calloc(info->submaps,sizeof(*look->floor_func));
look->residue_func=(vorbis_func_residue **)_ogg_calloc(info->submaps,sizeof(*look->residue_func));
for(i=0;i<info->submaps;i++){
int floornum=info->floorsubmap[i];
int resnum=info->residuesubmap[i];
look->floor_func[i]=_floor_P[ci->floor_type[floornum]];
look->floor_look[i]=look->floor_func[i]->
look(vd,vm,ci->floor_param[floornum]);
look->residue_func[i]=_residue_P[ci->residue_type[resnum]];
look->residue_look[i]=look->residue_func[i]->
look(vd,vm,ci->residue_param[resnum]);
}
look->ch=vi->channels;
return(look);
}
static int ilog(unsigned int v){
int ret=0;
if(v)--v;
while(v){
ret++;
v>>=1;
}
return(ret);
}
/* also responsible for range checking */
static vorbis_info_mapping *mapping0_unpack(vorbis_info *vi,oggpack_buffer *opb){
int i,b;
vorbis_info_mapping0 *info=(vorbis_info_mapping0 *)_ogg_calloc(1,sizeof(*info));
codec_setup_info *ci=(codec_setup_info *)vi->codec_setup;
memset(info,0,sizeof(*info));
b=oggpack_read(opb,1);
if(b<0)goto err_out;
if(b){
info->submaps=oggpack_read(opb,4)+1;
if(info->submaps<=0)goto err_out;
}else
info->submaps=1;
b=oggpack_read(opb,1);
if(b<0)goto err_out;
if(b){
info->coupling_steps=oggpack_read(opb,8)+1;
if(info->coupling_steps<=0)goto err_out;
for(i=0;i<info->coupling_steps;i++){
int testM=info->coupling_mag[i]=oggpack_read(opb,ilog(vi->channels));
int testA=info->coupling_ang[i]=oggpack_read(opb,ilog(vi->channels));
if(testM<0 ||
testA<0 ||
testM==testA ||
testM>=vi->channels ||
testA>=vi->channels) goto err_out;
}
}
if(oggpack_read(opb,2)!=0)goto err_out; /* 2,3:reserved */
if(info->submaps>1){
for(i=0;i<vi->channels;i++){
info->chmuxlist[i]=oggpack_read(opb,4);
if(info->chmuxlist[i]>=info->submaps || info->chmuxlist[i]<0)goto err_out;
}
}
for(i=0;i<info->submaps;i++){
int temp=oggpack_read(opb,8);
if(temp>=ci->times)goto err_out;
info->floorsubmap[i]=oggpack_read(opb,8);
if(info->floorsubmap[i]>=ci->floors || info->floorsubmap[i]<0)goto err_out;
info->residuesubmap[i]=oggpack_read(opb,8);
if(info->residuesubmap[i]>=ci->residues || info->residuesubmap[i]<0)
goto err_out;
}
return info;
err_out:
mapping0_free_info(info);
return(NULL);
}
static int seq=0;
static int mapping0_inverse(vorbis_block *vb,vorbis_look_mapping *l){
vorbis_dsp_state *vd=vb->vd;
vorbis_info *vi=vd->vi;
codec_setup_info *ci=(codec_setup_info *)vi->codec_setup;
private_state *b=(private_state *)vd->backend_state;
vorbis_look_mapping0 *look=(vorbis_look_mapping0 *)l;
vorbis_info_mapping0 *info=look->map;
int i,j;
long n=vb->pcmend=ci->blocksizes[vb->W];
ogg_int32_t **pcmbundle=(ogg_int32_t **)alloca(sizeof(*pcmbundle)*vi->channels);
int *zerobundle=(int *)alloca(sizeof(*zerobundle)*vi->channels);
int *nonzero =(int *)alloca(sizeof(*nonzero)*vi->channels);
void **floormemo=(void **)alloca(sizeof(*floormemo)*vi->channels);
/* time domain information decode (note that applying the
information would have to happen later; we'll probably add a
function entry to the harness for that later */
/* NOT IMPLEMENTED */
/* recover the spectral envelope; store it in the PCM vector for now */
for(i=0;i<vi->channels;i++){
int submap=info->chmuxlist[i];
floormemo[i]=look->floor_func[submap]->
inverse1(vb,look->floor_look[submap]);
if(floormemo[i])
nonzero[i]=1;
else
nonzero[i]=0;
memset(vb->pcm[i],0,sizeof(*vb->pcm[i])*n/2);
}
/* channel coupling can 'dirty' the nonzero listing */
for(i=0;i<info->coupling_steps;i++){
if(nonzero[info->coupling_mag[i]] ||
nonzero[info->coupling_ang[i]]){
nonzero[info->coupling_mag[i]]=1;
nonzero[info->coupling_ang[i]]=1;
}
}
/* recover the residue into our working vectors */
for(i=0;i<info->submaps;i++){
int ch_in_bundle=0;
for(j=0;j<vi->channels;j++){
if(info->chmuxlist[j]==i){
if(nonzero[j])
zerobundle[ch_in_bundle]=1;
else
zerobundle[ch_in_bundle]=0;
pcmbundle[ch_in_bundle++]=vb->pcm[j];
}
}
look->residue_func[i]->inverse(vb,look->residue_look[i],
pcmbundle,zerobundle,ch_in_bundle);
}
//for(j=0;j<vi->channels;j++)
//_analysis_output("coupled",seq+j,vb->pcm[j],-8,n/2,0,0);
/* channel coupling */
for(i=info->coupling_steps-1;i>=0;i--){
ogg_int32_t *pcmM=vb->pcm[info->coupling_mag[i]];
ogg_int32_t *pcmA=vb->pcm[info->coupling_ang[i]];
for(j=0;j<n/2;j++){
ogg_int32_t mag=pcmM[j];
ogg_int32_t ang=pcmA[j];
if(mag>0)
if(ang>0){
pcmM[j]=mag;
pcmA[j]=mag-ang;
}else{
pcmA[j]=mag;
pcmM[j]=mag+ang;
}
else
if(ang>0){
pcmM[j]=mag;
pcmA[j]=mag+ang;
}else{
pcmA[j]=mag;
pcmM[j]=mag-ang;
}
}
}
//for(j=0;j<vi->channels;j++)
//_analysis_output("residue",seq+j,vb->pcm[j],-8,n/2,0,0);
/* compute and apply spectral envelope */
for(i=0;i<vi->channels;i++){
ogg_int32_t *pcm=vb->pcm[i];
int submap=info->chmuxlist[i];
look->floor_func[submap]->
inverse2(vb,look->floor_look[submap],floormemo[i],pcm);
}
//for(j=0;j<vi->channels;j++)
//_analysis_output("mdct",seq+j,vb->pcm[j],-24,n/2,0,1);
/* transform the PCM data; takes PCM vector, vb; modifies PCM vector */
/* only MDCT right now.... */
for(i=0;i<vi->channels;i++){
ogg_int32_t *pcm=vb->pcm[i];
mdct_backward(n,pcm,pcm);
}
//for(j=0;j<vi->channels;j++)
//_analysis_output("imdct",seq+j,vb->pcm[j],-24,n,0,0);
/* window the data */
for(i=0;i<vi->channels;i++){
ogg_int32_t *pcm=vb->pcm[i];
if(nonzero[i])
_vorbis_apply_window(pcm,b->window,ci->blocksizes,vb->lW,vb->W,vb->nW);
else
for(j=0;j<n;j++)
pcm[j]=0;
}
//for(j=0;j<vi->channels;j++)
//_analysis_output("window",seq+j,vb->pcm[j],-24,n,0,0);
seq+=vi->channels;
/* all done! */
return(0);
}
/* export hooks */
vorbis_func_mapping mapping0_exportbundle={
&mapping0_unpack,
&mapping0_look,
&mapping0_free_info,
&mapping0_free_look,
&mapping0_inverse
};
+510
View File
@@ -0,0 +1,510 @@
/********************************************************************
* *
* THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. *
* *
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 *
* BY THE Xiph.Org FOUNDATION http://www.xiph.org/ *
* *
********************************************************************
function: normalized modified discrete cosine transform
power of two length transform only [64 <= n ]
last mod: $Id$
Original algorithm adapted long ago from _The use of multirate filter
banks for coding of high quality digital audio_, by T. Sporer,
K. Brandenburg and B. Edler, collection of the European Signal
Processing Conference (EUSIPCO), Amsterdam, June 1992, Vol.1, pp
211-214
The below code implements an algorithm that no longer looks much like
that presented in the paper, but the basic structure remains if you
dig deep enough to see it.
This module DOES NOT INCLUDE code to generate/apply the window
function. Everybody has their own weird favorite including me... I
happen to like the properties of y=sin(.5PI*sin^2(x)), but others may
vehemently disagree.
********************************************************************/
#include "ivorbiscodec.h"
#include "codebook.h"
#include "misc.h"
#include "mdct.h"
#include "mdct_lookup.h"
/* 8 point butterfly (in place) */
STIN void mdct_butterfly_8(DATA_TYPE *x){
REG_TYPE r0 = x[4] + x[0];
REG_TYPE r1 = x[4] - x[0];
REG_TYPE r2 = x[5] + x[1];
REG_TYPE r3 = x[5] - x[1];
REG_TYPE r4 = x[6] + x[2];
REG_TYPE r5 = x[6] - x[2];
REG_TYPE r6 = x[7] + x[3];
REG_TYPE r7 = x[7] - x[3];
x[0] = r5 + r3;
x[1] = r7 - r1;
x[2] = r5 - r3;
x[3] = r7 + r1;
x[4] = r4 - r0;
x[5] = r6 - r2;
x[6] = r4 + r0;
x[7] = r6 + r2;
MB();
}
/* 16 point butterfly (in place, 4 register) */
STIN void mdct_butterfly_16(DATA_TYPE *x){
REG_TYPE r0, r1;
r0 = x[ 0] - x[ 8]; x[ 8] += x[ 0];
r1 = x[ 1] - x[ 9]; x[ 9] += x[ 1];
x[ 0] = MULT31((r0 + r1) , cPI2_8);
x[ 1] = MULT31((r1 - r0) , cPI2_8);
MB();
r0 = x[10] - x[ 2]; x[10] += x[ 2];
r1 = x[ 3] - x[11]; x[11] += x[ 3];
x[ 2] = r1; x[ 3] = r0;
MB();
r0 = x[12] - x[ 4]; x[12] += x[ 4];
r1 = x[13] - x[ 5]; x[13] += x[ 5];
x[ 4] = MULT31((r0 - r1) , cPI2_8);
x[ 5] = MULT31((r0 + r1) , cPI2_8);
MB();
r0 = x[14] - x[ 6]; x[14] += x[ 6];
r1 = x[15] - x[ 7]; x[15] += x[ 7];
x[ 6] = r0; x[ 7] = r1;
MB();
mdct_butterfly_8(x);
mdct_butterfly_8(x+8);
}
/* 32 point butterfly (in place, 4 register) */
STIN void mdct_butterfly_32(DATA_TYPE *x){
REG_TYPE r0, r1;
r0 = x[30] - x[14]; x[30] += x[14];
r1 = x[31] - x[15]; x[31] += x[15];
x[14] = r0; x[15] = r1;
MB();
r0 = x[28] - x[12]; x[28] += x[12];
r1 = x[29] - x[13]; x[29] += x[13];
XNPROD31( r0, r1, cPI1_8, cPI3_8, &x[12], &x[13] );
MB();
r0 = x[26] - x[10]; x[26] += x[10];
r1 = x[27] - x[11]; x[27] += x[11];
x[10] = MULT31((r0 - r1) , cPI2_8);
x[11] = MULT31((r0 + r1) , cPI2_8);
MB();
r0 = x[24] - x[ 8]; x[24] += x[ 8];
r1 = x[25] - x[ 9]; x[25] += x[ 9];
XNPROD31( r0, r1, cPI3_8, cPI1_8, &x[ 8], &x[ 9] );
MB();
r0 = x[22] - x[ 6]; x[22] += x[ 6];
r1 = x[ 7] - x[23]; x[23] += x[ 7];
x[ 6] = r1; x[ 7] = r0;
MB();
r0 = x[ 4] - x[20]; x[20] += x[ 4];
r1 = x[ 5] - x[21]; x[21] += x[ 5];
XPROD31 ( r0, r1, cPI3_8, cPI1_8, &x[ 4], &x[ 5] );
MB();
r0 = x[ 2] - x[18]; x[18] += x[ 2];
r1 = x[ 3] - x[19]; x[19] += x[ 3];
x[ 2] = MULT31((r1 + r0) , cPI2_8);
x[ 3] = MULT31((r1 - r0) , cPI2_8);
MB();
r0 = x[ 0] - x[16]; x[16] += x[ 0];
r1 = x[ 1] - x[17]; x[17] += x[ 1];
XPROD31 ( r0, r1, cPI1_8, cPI3_8, &x[ 0], &x[ 1] );
MB();
mdct_butterfly_16(x);
mdct_butterfly_16(x+16);
}
/* N/stage point generic N stage butterfly (in place, 2 register) */
STIN void mdct_butterfly_generic(DATA_TYPE *x,int points,int step){
LOOKUP_T *T = sincos_lookup0;
DATA_TYPE *x1 = x + points - 8;
DATA_TYPE *x2 = x + (points>>1) - 8;
REG_TYPE r0;
REG_TYPE r1;
do{
r0 = x1[6] - x2[6]; x1[6] += x2[6];
r1 = x2[7] - x1[7]; x1[7] += x2[7];
XPROD31( r1, r0, T[0], T[1], &x2[6], &x2[7] ); T+=step;
r0 = x1[4] - x2[4]; x1[4] += x2[4];
r1 = x2[5] - x1[5]; x1[5] += x2[5];
XPROD31( r1, r0, T[0], T[1], &x2[4], &x2[5] ); T+=step;
r0 = x1[2] - x2[2]; x1[2] += x2[2];
r1 = x2[3] - x1[3]; x1[3] += x2[3];
XPROD31( r1, r0, T[0], T[1], &x2[2], &x2[3] ); T+=step;
r0 = x1[0] - x2[0]; x1[0] += x2[0];
r1 = x2[1] - x1[1]; x1[1] += x2[1];
XPROD31( r1, r0, T[0], T[1], &x2[0], &x2[1] ); T+=step;
x1-=8; x2-=8;
}while(T<sincos_lookup0+1024);
do{
r0 = x1[6] - x2[6]; x1[6] += x2[6];
r1 = x1[7] - x2[7]; x1[7] += x2[7];
XNPROD31( r0, r1, T[0], T[1], &x2[6], &x2[7] ); T-=step;
r0 = x1[4] - x2[4]; x1[4] += x2[4];
r1 = x1[5] - x2[5]; x1[5] += x2[5];
XNPROD31( r0, r1, T[0], T[1], &x2[4], &x2[5] ); T-=step;
r0 = x1[2] - x2[2]; x1[2] += x2[2];
r1 = x1[3] - x2[3]; x1[3] += x2[3];
XNPROD31( r0, r1, T[0], T[1], &x2[2], &x2[3] ); T-=step;
r0 = x1[0] - x2[0]; x1[0] += x2[0];
r1 = x1[1] - x2[1]; x1[1] += x2[1];
XNPROD31( r0, r1, T[0], T[1], &x2[0], &x2[1] ); T-=step;
x1-=8; x2-=8;
}while(T>sincos_lookup0);
do{
r0 = x2[6] - x1[6]; x1[6] += x2[6];
r1 = x2[7] - x1[7]; x1[7] += x2[7];
XPROD31( r0, r1, T[0], T[1], &x2[6], &x2[7] ); T+=step;
r0 = x2[4] - x1[4]; x1[4] += x2[4];
r1 = x2[5] - x1[5]; x1[5] += x2[5];
XPROD31( r0, r1, T[0], T[1], &x2[4], &x2[5] ); T+=step;
r0 = x2[2] - x1[2]; x1[2] += x2[2];
r1 = x2[3] - x1[3]; x1[3] += x2[3];
XPROD31( r0, r1, T[0], T[1], &x2[2], &x2[3] ); T+=step;
r0 = x2[0] - x1[0]; x1[0] += x2[0];
r1 = x2[1] - x1[1]; x1[1] += x2[1];
XPROD31( r0, r1, T[0], T[1], &x2[0], &x2[1] ); T+=step;
x1-=8; x2-=8;
}while(T<sincos_lookup0+1024);
do{
r0 = x1[6] - x2[6]; x1[6] += x2[6];
r1 = x2[7] - x1[7]; x1[7] += x2[7];
XNPROD31( r1, r0, T[0], T[1], &x2[6], &x2[7] ); T-=step;
r0 = x1[4] - x2[4]; x1[4] += x2[4];
r1 = x2[5] - x1[5]; x1[5] += x2[5];
XNPROD31( r1, r0, T[0], T[1], &x2[4], &x2[5] ); T-=step;
r0 = x1[2] - x2[2]; x1[2] += x2[2];
r1 = x2[3] - x1[3]; x1[3] += x2[3];
XNPROD31( r1, r0, T[0], T[1], &x2[2], &x2[3] ); T-=step;
r0 = x1[0] - x2[0]; x1[0] += x2[0];
r1 = x2[1] - x1[1]; x1[1] += x2[1];
XNPROD31( r1, r0, T[0], T[1], &x2[0], &x2[1] ); T-=step;
x1-=8; x2-=8;
}while(T>sincos_lookup0);
}
STIN void mdct_butterflies(DATA_TYPE *x,int points,int shift){
int stages=8-shift;
int i,j;
for(i=0;--stages>0;i++){
for(j=0;j<(1<<i);j++)
mdct_butterfly_generic(x+(points>>i)*j,points>>i,4<<(i+shift));
}
for(j=0;j<points;j+=32)
mdct_butterfly_32(x+j);
}
static unsigned char bitrev[16]={0,8,4,12,2,10,6,14,1,9,5,13,3,11,7,15};
STIN int bitrev12(int x){
return bitrev[x>>8]|(bitrev[(x&0x0f0)>>4]<<4)|(((int)bitrev[x&0x00f])<<8);
}
STIN void mdct_bitreverse(DATA_TYPE *x,int n,int step,int shift){
int bit = 0;
DATA_TYPE *w0 = x;
DATA_TYPE *w1 = x = w0+(n>>1);
LOOKUP_T *T = (step>=4)?(sincos_lookup0+(step>>1)):sincos_lookup1;
LOOKUP_T *Ttop = T+1024;
DATA_TYPE r2;
do{
DATA_TYPE r3 = bitrev12(bit++);
DATA_TYPE *x0 = x + ((r3 ^ 0xfff)>>shift) -1;
DATA_TYPE *x1 = x + (r3>>shift);
REG_TYPE r0 = x0[0] + x1[0];
REG_TYPE r1 = x1[1] - x0[1];
XPROD32( r0, r1, T[1], T[0], &r2, &r3 ); T+=step;
w1 -= 4;
r0 = (x0[1] + x1[1])>>1;
r1 = (x0[0] - x1[0])>>1;
w0[0] = r0 + r2;
w0[1] = r1 + r3;
w1[2] = r0 - r2;
w1[3] = r3 - r1;
r3 = bitrev12(bit++);
x0 = x + ((r3 ^ 0xfff)>>shift) -1;
x1 = x + (r3>>shift);
r0 = x0[0] + x1[0];
r1 = x1[1] - x0[1];
XPROD32( r0, r1, T[1], T[0], &r2, &r3 ); T+=step;
r0 = (x0[1] + x1[1])>>1;
r1 = (x0[0] - x1[0])>>1;
w0[2] = r0 + r2;
w0[3] = r1 + r3;
w1[0] = r0 - r2;
w1[1] = r3 - r1;
w0 += 4;
}while(T<Ttop);
do{
DATA_TYPE r3 = bitrev12(bit++);
DATA_TYPE *x0 = x + ((r3 ^ 0xfff)>>shift) -1;
DATA_TYPE *x1 = x + (r3>>shift);
REG_TYPE r0 = x0[0] + x1[0];
REG_TYPE r1 = x1[1] - x0[1];
T-=step; XPROD32( r0, r1, T[0], T[1], &r2, &r3 );
w1 -= 4;
r0 = (x0[1] + x1[1])>>1;
r1 = (x0[0] - x1[0])>>1;
w0[0] = r0 + r2;
w0[1] = r1 + r3;
w1[2] = r0 - r2;
w1[3] = r3 - r1;
r3 = bitrev12(bit++);
x0 = x + ((r3 ^ 0xfff)>>shift) -1;
x1 = x + (r3>>shift);
r0 = x0[0] + x1[0];
r1 = x1[1] - x0[1];
T-=step; XPROD32( r0, r1, T[0], T[1], &r2, &r3 );
r0 = (x0[1] + x1[1])>>1;
r1 = (x0[0] - x1[0])>>1;
w0[2] = r0 + r2;
w0[3] = r1 + r3;
w1[0] = r0 - r2;
w1[1] = r3 - r1;
w0 += 4;
}while(w0<w1);
}
void mdct_backward(int n, DATA_TYPE *in, DATA_TYPE *out){
int n2=n>>1;
int n4=n>>2;
DATA_TYPE *iX;
DATA_TYPE *oX;
LOOKUP_T *T;
LOOKUP_T *V;
int shift;
int step;
for (shift=6;!(n&(1<<shift));shift++);
shift=13-shift;
step=2<<shift;
/* rotate */
iX = in+n2-7;
oX = out+n2+n4;
T = sincos_lookup0;
do{
oX-=4;
XPROD31( iX[4], iX[6], T[0], T[1], &oX[2], &oX[3] ); T+=step;
XPROD31( iX[0], iX[2], T[0], T[1], &oX[0], &oX[1] ); T+=step;
iX-=8;
}while(iX>=in+n4);
do{
oX-=4;
XPROD31( iX[4], iX[6], T[1], T[0], &oX[2], &oX[3] ); T-=step;
XPROD31( iX[0], iX[2], T[1], T[0], &oX[0], &oX[1] ); T-=step;
iX-=8;
}while(iX>=in);
iX = in+n2-8;
oX = out+n2+n4;
T = sincos_lookup0;
do{
T+=step; XNPROD31( iX[6], iX[4], T[0], T[1], &oX[0], &oX[1] );
T+=step; XNPROD31( iX[2], iX[0], T[0], T[1], &oX[2], &oX[3] );
iX-=8;
oX+=4;
}while(iX>=in+n4);
do{
T-=step; XNPROD31( iX[6], iX[4], T[1], T[0], &oX[0], &oX[1] );
T-=step; XNPROD31( iX[2], iX[0], T[1], T[0], &oX[2], &oX[3] );
iX-=8;
oX+=4;
}while(iX>=in);
mdct_butterflies(out+n2,n2,shift);
mdct_bitreverse(out,n,step,shift);
/* rotate + window */
step>>=2;
{
DATA_TYPE *oX1=out+n2+n4;
DATA_TYPE *oX2=out+n2+n4;
DATA_TYPE *iX =out;
switch(step) {
default: {
T=(step>=4)?(sincos_lookup0+(step>>1)):sincos_lookup1;
do{
oX1-=4;
XPROD31( iX[0], -iX[1], T[0], T[1], &oX1[3], &oX2[0] ); T+=step;
XPROD31( iX[2], -iX[3], T[0], T[1], &oX1[2], &oX2[1] ); T+=step;
XPROD31( iX[4], -iX[5], T[0], T[1], &oX1[1], &oX2[2] ); T+=step;
XPROD31( iX[6], -iX[7], T[0], T[1], &oX1[0], &oX2[3] ); T+=step;
oX2+=4;
iX+=8;
}while(iX<oX1);
break;
}
case 1: {
/* linear interpolation between table values: offset=0.5, step=1 */
REG_TYPE t0,t1,v0,v1;
T = sincos_lookup0;
V = sincos_lookup1;
t0 = (*T++)>>1;
t1 = (*T++)>>1;
do{
oX1-=4;
t0 += (v0 = (*V++)>>1);
t1 += (v1 = (*V++)>>1);
XPROD31( iX[0], -iX[1], t0, t1, &oX1[3], &oX2[0] );
v0 += (t0 = (*T++)>>1);
v1 += (t1 = (*T++)>>1);
XPROD31( iX[2], -iX[3], v0, v1, &oX1[2], &oX2[1] );
t0 += (v0 = (*V++)>>1);
t1 += (v1 = (*V++)>>1);
XPROD31( iX[4], -iX[5], t0, t1, &oX1[1], &oX2[2] );
v0 += (t0 = (*T++)>>1);
v1 += (t1 = (*T++)>>1);
XPROD31( iX[6], -iX[7], v0, v1, &oX1[0], &oX2[3] );
oX2+=4;
iX+=8;
}while(iX<oX1);
break;
}
case 0: {
/* linear interpolation between table values: offset=0.25, step=0.5 */
REG_TYPE t0,t1,v0,v1,q0,q1;
T = sincos_lookup0;
V = sincos_lookup1;
t0 = *T++;
t1 = *T++;
do{
oX1-=4;
v0 = *V++;
v1 = *V++;
t0 += (q0 = (v0-t0)>>2);
t1 += (q1 = (v1-t1)>>2);
XPROD31( iX[0], -iX[1], t0, t1, &oX1[3], &oX2[0] );
t0 = v0-q0;
t1 = v1-q1;
XPROD31( iX[2], -iX[3], t0, t1, &oX1[2], &oX2[1] );
t0 = *T++;
t1 = *T++;
v0 += (q0 = (t0-v0)>>2);
v1 += (q1 = (t1-v1)>>2);
XPROD31( iX[4], -iX[5], v0, v1, &oX1[1], &oX2[2] );
v0 = t0-q0;
v1 = t1-q1;
XPROD31( iX[6], -iX[7], v0, v1, &oX1[0], &oX2[3] );
oX2+=4;
iX+=8;
}while(iX<oX1);
break;
}
}
iX=out+n2+n4;
oX1=out+n4;
oX2=oX1;
do{
oX1-=4;
iX-=4;
oX2[0] = -(oX1[3] = iX[3]);
oX2[1] = -(oX1[2] = iX[2]);
oX2[2] = -(oX1[1] = iX[1]);
oX2[3] = -(oX1[0] = iX[0]);
oX2+=4;
}while(oX2<iX);
iX=out+n2+n4;
oX1=out+n2+n4;
oX2=out+n2;
do{
oX1-=4;
oX1[0]= iX[3];
oX1[1]= iX[2];
oX1[2]= iX[1];
oX1[3]= iX[0];
iX+=4;
}while(oX1>oX2);
}
}
+52
View File
@@ -0,0 +1,52 @@
/********************************************************************
* *
* THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. *
* *
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 *
* BY THE Xiph.Org FOUNDATION http://www.xiph.org/ *
* *
********************************************************************
function: modified discrete cosine transform prototypes
********************************************************************/
#ifndef _OGG_mdct_H_
#define _OGG_mdct_H_
#include "ivorbiscodec.h"
#include "misc.h"
#define DATA_TYPE ogg_int32_t
#define REG_TYPE register ogg_int32_t
#ifdef _LOW_ACCURACY_
#define cPI3_8 (0x0062)
#define cPI2_8 (0x00b5)
#define cPI1_8 (0x00ed)
#else
#define cPI3_8 (0x30fbc54d)
#define cPI2_8 (0x5a82799a)
#define cPI1_8 (0x7641af3d)
#endif
extern void mdct_forward(int n, DATA_TYPE *in, DATA_TYPE *out);
extern void mdct_backward(int n, DATA_TYPE *in, DATA_TYPE *out);
#endif
+540
View File
@@ -0,0 +1,540 @@
/********************************************************************
* *
* THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. *
* *
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 *
* BY THE Xiph.Org FOUNDATION http://www.xiph.org/ *
* *
********************************************************************
function: sin,cos lookup tables
********************************************************************/
#include "misc.h"
/* {sin(2*i*PI/4096), cos(2*i*PI/4096)}, with i = 0 to 512 */
static LOOKUP_T sincos_lookup0[1026] = {
X(0x00000000), X(0x7fffffff), X(0x003243f5), X(0x7ffff621),
X(0x006487e3), X(0x7fffd886), X(0x0096cbc1), X(0x7fffa72c),
X(0x00c90f88), X(0x7fff6216), X(0x00fb5330), X(0x7fff0943),
X(0x012d96b1), X(0x7ffe9cb2), X(0x015fda03), X(0x7ffe1c65),
X(0x01921d20), X(0x7ffd885a), X(0x01c45ffe), X(0x7ffce093),
X(0x01f6a297), X(0x7ffc250f), X(0x0228e4e2), X(0x7ffb55ce),
X(0x025b26d7), X(0x7ffa72d1), X(0x028d6870), X(0x7ff97c18),
X(0x02bfa9a4), X(0x7ff871a2), X(0x02f1ea6c), X(0x7ff75370),
X(0x03242abf), X(0x7ff62182), X(0x03566a96), X(0x7ff4dbd9),
X(0x0388a9ea), X(0x7ff38274), X(0x03bae8b2), X(0x7ff21553),
X(0x03ed26e6), X(0x7ff09478), X(0x041f6480), X(0x7feeffe1),
X(0x0451a177), X(0x7fed5791), X(0x0483ddc3), X(0x7feb9b85),
X(0x04b6195d), X(0x7fe9cbc0), X(0x04e8543e), X(0x7fe7e841),
X(0x051a8e5c), X(0x7fe5f108), X(0x054cc7b1), X(0x7fe3e616),
X(0x057f0035), X(0x7fe1c76b), X(0x05b137df), X(0x7fdf9508),
X(0x05e36ea9), X(0x7fdd4eec), X(0x0615a48b), X(0x7fdaf519),
X(0x0647d97c), X(0x7fd8878e), X(0x067a0d76), X(0x7fd6064c),
X(0x06ac406f), X(0x7fd37153), X(0x06de7262), X(0x7fd0c8a3),
X(0x0710a345), X(0x7fce0c3e), X(0x0742d311), X(0x7fcb3c23),
X(0x077501be), X(0x7fc85854), X(0x07a72f45), X(0x7fc560cf),
X(0x07d95b9e), X(0x7fc25596), X(0x080b86c2), X(0x7fbf36aa),
X(0x083db0a7), X(0x7fbc040a), X(0x086fd947), X(0x7fb8bdb8),
X(0x08a2009a), X(0x7fb563b3), X(0x08d42699), X(0x7fb1f5fc),
X(0x09064b3a), X(0x7fae7495), X(0x09386e78), X(0x7faadf7c),
X(0x096a9049), X(0x7fa736b4), X(0x099cb0a7), X(0x7fa37a3c),
X(0x09cecf89), X(0x7f9faa15), X(0x0a00ece8), X(0x7f9bc640),
X(0x0a3308bd), X(0x7f97cebd), X(0x0a6522fe), X(0x7f93c38c),
X(0x0a973ba5), X(0x7f8fa4b0), X(0x0ac952aa), X(0x7f8b7227),
X(0x0afb6805), X(0x7f872bf3), X(0x0b2d7baf), X(0x7f82d214),
X(0x0b5f8d9f), X(0x7f7e648c), X(0x0b919dcf), X(0x7f79e35a),
X(0x0bc3ac35), X(0x7f754e80), X(0x0bf5b8cb), X(0x7f70a5fe),
X(0x0c27c389), X(0x7f6be9d4), X(0x0c59cc68), X(0x7f671a05),
X(0x0c8bd35e), X(0x7f62368f), X(0x0cbdd865), X(0x7f5d3f75),
X(0x0cefdb76), X(0x7f5834b7), X(0x0d21dc87), X(0x7f531655),
X(0x0d53db92), X(0x7f4de451), X(0x0d85d88f), X(0x7f489eaa),
X(0x0db7d376), X(0x7f434563), X(0x0de9cc40), X(0x7f3dd87c),
X(0x0e1bc2e4), X(0x7f3857f6), X(0x0e4db75b), X(0x7f32c3d1),
X(0x0e7fa99e), X(0x7f2d1c0e), X(0x0eb199a4), X(0x7f2760af),
X(0x0ee38766), X(0x7f2191b4), X(0x0f1572dc), X(0x7f1baf1e),
X(0x0f475bff), X(0x7f15b8ee), X(0x0f7942c7), X(0x7f0faf25),
X(0x0fab272b), X(0x7f0991c4), X(0x0fdd0926), X(0x7f0360cb),
X(0x100ee8ad), X(0x7efd1c3c), X(0x1040c5bb), X(0x7ef6c418),
X(0x1072a048), X(0x7ef05860), X(0x10a4784b), X(0x7ee9d914),
X(0x10d64dbd), X(0x7ee34636), X(0x11082096), X(0x7edc9fc6),
X(0x1139f0cf), X(0x7ed5e5c6), X(0x116bbe60), X(0x7ecf1837),
X(0x119d8941), X(0x7ec8371a), X(0x11cf516a), X(0x7ec14270),
X(0x120116d5), X(0x7eba3a39), X(0x1232d979), X(0x7eb31e78),
X(0x1264994e), X(0x7eabef2c), X(0x1296564d), X(0x7ea4ac58),
X(0x12c8106f), X(0x7e9d55fc), X(0x12f9c7aa), X(0x7e95ec1a),
X(0x132b7bf9), X(0x7e8e6eb2), X(0x135d2d53), X(0x7e86ddc6),
X(0x138edbb1), X(0x7e7f3957), X(0x13c0870a), X(0x7e778166),
X(0x13f22f58), X(0x7e6fb5f4), X(0x1423d492), X(0x7e67d703),
X(0x145576b1), X(0x7e5fe493), X(0x148715ae), X(0x7e57dea7),
X(0x14b8b17f), X(0x7e4fc53e), X(0x14ea4a1f), X(0x7e47985b),
X(0x151bdf86), X(0x7e3f57ff), X(0x154d71aa), X(0x7e37042a),
X(0x157f0086), X(0x7e2e9cdf), X(0x15b08c12), X(0x7e26221f),
X(0x15e21445), X(0x7e1d93ea), X(0x16139918), X(0x7e14f242),
X(0x16451a83), X(0x7e0c3d29), X(0x1676987f), X(0x7e0374a0),
X(0x16a81305), X(0x7dfa98a8), X(0x16d98a0c), X(0x7df1a942),
X(0x170afd8d), X(0x7de8a670), X(0x173c6d80), X(0x7ddf9034),
X(0x176dd9de), X(0x7dd6668f), X(0x179f429f), X(0x7dcd2981),
X(0x17d0a7bc), X(0x7dc3d90d), X(0x1802092c), X(0x7dba7534),
X(0x183366e9), X(0x7db0fdf8), X(0x1864c0ea), X(0x7da77359),
X(0x18961728), X(0x7d9dd55a), X(0x18c7699b), X(0x7d9423fc),
X(0x18f8b83c), X(0x7d8a5f40), X(0x192a0304), X(0x7d808728),
X(0x195b49ea), X(0x7d769bb5), X(0x198c8ce7), X(0x7d6c9ce9),
X(0x19bdcbf3), X(0x7d628ac6), X(0x19ef0707), X(0x7d58654d),
X(0x1a203e1b), X(0x7d4e2c7f), X(0x1a517128), X(0x7d43e05e),
X(0x1a82a026), X(0x7d3980ec), X(0x1ab3cb0d), X(0x7d2f0e2b),
X(0x1ae4f1d6), X(0x7d24881b), X(0x1b161479), X(0x7d19eebf),
X(0x1b4732ef), X(0x7d0f4218), X(0x1b784d30), X(0x7d048228),
X(0x1ba96335), X(0x7cf9aef0), X(0x1bda74f6), X(0x7ceec873),
X(0x1c0b826a), X(0x7ce3ceb2), X(0x1c3c8b8c), X(0x7cd8c1ae),
X(0x1c6d9053), X(0x7ccda169), X(0x1c9e90b8), X(0x7cc26de5),
X(0x1ccf8cb3), X(0x7cb72724), X(0x1d00843d), X(0x7cabcd28),
X(0x1d31774d), X(0x7ca05ff1), X(0x1d6265dd), X(0x7c94df83),
X(0x1d934fe5), X(0x7c894bde), X(0x1dc4355e), X(0x7c7da505),
X(0x1df5163f), X(0x7c71eaf9), X(0x1e25f282), X(0x7c661dbc),
X(0x1e56ca1e), X(0x7c5a3d50), X(0x1e879d0d), X(0x7c4e49b7),
X(0x1eb86b46), X(0x7c4242f2), X(0x1ee934c3), X(0x7c362904),
X(0x1f19f97b), X(0x7c29fbee), X(0x1f4ab968), X(0x7c1dbbb3),
X(0x1f7b7481), X(0x7c116853), X(0x1fac2abf), X(0x7c0501d2),
X(0x1fdcdc1b), X(0x7bf88830), X(0x200d888d), X(0x7bebfb70),
X(0x203e300d), X(0x7bdf5b94), X(0x206ed295), X(0x7bd2a89e),
X(0x209f701c), X(0x7bc5e290), X(0x20d0089c), X(0x7bb9096b),
X(0x21009c0c), X(0x7bac1d31), X(0x21312a65), X(0x7b9f1de6),
X(0x2161b3a0), X(0x7b920b89), X(0x219237b5), X(0x7b84e61f),
X(0x21c2b69c), X(0x7b77ada8), X(0x21f3304f), X(0x7b6a6227),
X(0x2223a4c5), X(0x7b5d039e), X(0x225413f8), X(0x7b4f920e),
X(0x22847de0), X(0x7b420d7a), X(0x22b4e274), X(0x7b3475e5),
X(0x22e541af), X(0x7b26cb4f), X(0x23159b88), X(0x7b190dbc),
X(0x2345eff8), X(0x7b0b3d2c), X(0x23763ef7), X(0x7afd59a4),
X(0x23a6887f), X(0x7aef6323), X(0x23d6cc87), X(0x7ae159ae),
X(0x24070b08), X(0x7ad33d45), X(0x243743fa), X(0x7ac50dec),
X(0x24677758), X(0x7ab6cba4), X(0x2497a517), X(0x7aa8766f),
X(0x24c7cd33), X(0x7a9a0e50), X(0x24f7efa2), X(0x7a8b9348),
X(0x25280c5e), X(0x7a7d055b), X(0x2558235f), X(0x7a6e648a),
X(0x2588349d), X(0x7a5fb0d8), X(0x25b84012), X(0x7a50ea47),
X(0x25e845b6), X(0x7a4210d8), X(0x26184581), X(0x7a332490),
X(0x26483f6c), X(0x7a24256f), X(0x26783370), X(0x7a151378),
X(0x26a82186), X(0x7a05eead), X(0x26d809a5), X(0x79f6b711),
X(0x2707ebc7), X(0x79e76ca7), X(0x2737c7e3), X(0x79d80f6f),
X(0x27679df4), X(0x79c89f6e), X(0x27976df1), X(0x79b91ca4),
X(0x27c737d3), X(0x79a98715), X(0x27f6fb92), X(0x7999dec4),
X(0x2826b928), X(0x798a23b1), X(0x2856708d), X(0x797a55e0),
X(0x288621b9), X(0x796a7554), X(0x28b5cca5), X(0x795a820e),
X(0x28e5714b), X(0x794a7c12), X(0x29150fa1), X(0x793a6361),
X(0x2944a7a2), X(0x792a37fe), X(0x29743946), X(0x7919f9ec),
X(0x29a3c485), X(0x7909a92d), X(0x29d34958), X(0x78f945c3),
X(0x2a02c7b8), X(0x78e8cfb2), X(0x2a323f9e), X(0x78d846fb),
X(0x2a61b101), X(0x78c7aba2), X(0x2a911bdc), X(0x78b6fda8),
X(0x2ac08026), X(0x78a63d11), X(0x2aefddd8), X(0x789569df),
X(0x2b1f34eb), X(0x78848414), X(0x2b4e8558), X(0x78738bb3),
X(0x2b7dcf17), X(0x786280bf), X(0x2bad1221), X(0x7851633b),
X(0x2bdc4e6f), X(0x78403329), X(0x2c0b83fa), X(0x782ef08b),
X(0x2c3ab2b9), X(0x781d9b65), X(0x2c69daa6), X(0x780c33b8),
X(0x2c98fbba), X(0x77fab989), X(0x2cc815ee), X(0x77e92cd9),
X(0x2cf72939), X(0x77d78daa), X(0x2d263596), X(0x77c5dc01),
X(0x2d553afc), X(0x77b417df), X(0x2d843964), X(0x77a24148),
X(0x2db330c7), X(0x7790583e), X(0x2de2211e), X(0x777e5cc3),
X(0x2e110a62), X(0x776c4edb), X(0x2e3fec8b), X(0x775a2e89),
X(0x2e6ec792), X(0x7747fbce), X(0x2e9d9b70), X(0x7735b6af),
X(0x2ecc681e), X(0x77235f2d), X(0x2efb2d95), X(0x7710f54c),
X(0x2f29ebcc), X(0x76fe790e), X(0x2f58a2be), X(0x76ebea77),
X(0x2f875262), X(0x76d94989), X(0x2fb5fab2), X(0x76c69647),
X(0x2fe49ba7), X(0x76b3d0b4), X(0x30133539), X(0x76a0f8d2),
X(0x3041c761), X(0x768e0ea6), X(0x30705217), X(0x767b1231),
X(0x309ed556), X(0x76680376), X(0x30cd5115), X(0x7654e279),
X(0x30fbc54d), X(0x7641af3d), X(0x312a31f8), X(0x762e69c4),
X(0x3158970e), X(0x761b1211), X(0x3186f487), X(0x7607a828),
X(0x31b54a5e), X(0x75f42c0b), X(0x31e39889), X(0x75e09dbd),
X(0x3211df04), X(0x75ccfd42), X(0x32401dc6), X(0x75b94a9c),
X(0x326e54c7), X(0x75a585cf), X(0x329c8402), X(0x7591aedd),
X(0x32caab6f), X(0x757dc5ca), X(0x32f8cb07), X(0x7569ca99),
X(0x3326e2c3), X(0x7555bd4c), X(0x3354f29b), X(0x75419de7),
X(0x3382fa88), X(0x752d6c6c), X(0x33b0fa84), X(0x751928e0),
X(0x33def287), X(0x7504d345), X(0x340ce28b), X(0x74f06b9e),
X(0x343aca87), X(0x74dbf1ef), X(0x3468aa76), X(0x74c7663a),
X(0x34968250), X(0x74b2c884), X(0x34c4520d), X(0x749e18cd),
X(0x34f219a8), X(0x7489571c), X(0x351fd918), X(0x74748371),
X(0x354d9057), X(0x745f9dd1), X(0x357b3f5d), X(0x744aa63f),
X(0x35a8e625), X(0x74359cbd), X(0x35d684a6), X(0x74208150),
X(0x36041ad9), X(0x740b53fb), X(0x3631a8b8), X(0x73f614c0),
X(0x365f2e3b), X(0x73e0c3a3), X(0x368cab5c), X(0x73cb60a8),
X(0x36ba2014), X(0x73b5ebd1), X(0x36e78c5b), X(0x73a06522),
X(0x3714f02a), X(0x738acc9e), X(0x37424b7b), X(0x73752249),
X(0x376f9e46), X(0x735f6626), X(0x379ce885), X(0x73499838),
X(0x37ca2a30), X(0x7333b883), X(0x37f76341), X(0x731dc70a),
X(0x382493b0), X(0x7307c3d0), X(0x3851bb77), X(0x72f1aed9),
X(0x387eda8e), X(0x72db8828), X(0x38abf0ef), X(0x72c54fc1),
X(0x38d8fe93), X(0x72af05a7), X(0x39060373), X(0x7298a9dd),
X(0x3932ff87), X(0x72823c67), X(0x395ff2c9), X(0x726bbd48),
X(0x398cdd32), X(0x72552c85), X(0x39b9bebc), X(0x723e8a20),
X(0x39e6975e), X(0x7227d61c), X(0x3a136712), X(0x7211107e),
X(0x3a402dd2), X(0x71fa3949), X(0x3a6ceb96), X(0x71e35080),
X(0x3a99a057), X(0x71cc5626), X(0x3ac64c0f), X(0x71b54a41),
X(0x3af2eeb7), X(0x719e2cd2), X(0x3b1f8848), X(0x7186fdde),
X(0x3b4c18ba), X(0x716fbd68), X(0x3b78a007), X(0x71586b74),
X(0x3ba51e29), X(0x71410805), X(0x3bd19318), X(0x7129931f),
X(0x3bfdfecd), X(0x71120cc5), X(0x3c2a6142), X(0x70fa74fc),
X(0x3c56ba70), X(0x70e2cbc6), X(0x3c830a50), X(0x70cb1128),
X(0x3caf50da), X(0x70b34525), X(0x3cdb8e09), X(0x709b67c0),
X(0x3d07c1d6), X(0x708378ff), X(0x3d33ec39), X(0x706b78e3),
X(0x3d600d2c), X(0x70536771), X(0x3d8c24a8), X(0x703b44ad),
X(0x3db832a6), X(0x7023109a), X(0x3de4371f), X(0x700acb3c),
X(0x3e10320d), X(0x6ff27497), X(0x3e3c2369), X(0x6fda0cae),
X(0x3e680b2c), X(0x6fc19385), X(0x3e93e950), X(0x6fa90921),
X(0x3ebfbdcd), X(0x6f906d84), X(0x3eeb889c), X(0x6f77c0b3),
X(0x3f1749b8), X(0x6f5f02b2), X(0x3f430119), X(0x6f463383),
X(0x3f6eaeb8), X(0x6f2d532c), X(0x3f9a5290), X(0x6f1461b0),
X(0x3fc5ec98), X(0x6efb5f12), X(0x3ff17cca), X(0x6ee24b57),
X(0x401d0321), X(0x6ec92683), X(0x40487f94), X(0x6eaff099),
X(0x4073f21d), X(0x6e96a99d), X(0x409f5ab6), X(0x6e7d5193),
X(0x40cab958), X(0x6e63e87f), X(0x40f60dfb), X(0x6e4a6e66),
X(0x4121589b), X(0x6e30e34a), X(0x414c992f), X(0x6e174730),
X(0x4177cfb1), X(0x6dfd9a1c), X(0x41a2fc1a), X(0x6de3dc11),
X(0x41ce1e65), X(0x6dca0d14), X(0x41f93689), X(0x6db02d29),
X(0x42244481), X(0x6d963c54), X(0x424f4845), X(0x6d7c3a98),
X(0x427a41d0), X(0x6d6227fa), X(0x42a5311b), X(0x6d48047e),
X(0x42d0161e), X(0x6d2dd027), X(0x42faf0d4), X(0x6d138afb),
X(0x4325c135), X(0x6cf934fc), X(0x4350873c), X(0x6cdece2f),
X(0x437b42e1), X(0x6cc45698), X(0x43a5f41e), X(0x6ca9ce3b),
X(0x43d09aed), X(0x6c8f351c), X(0x43fb3746), X(0x6c748b3f),
X(0x4425c923), X(0x6c59d0a9), X(0x4450507e), X(0x6c3f055d),
X(0x447acd50), X(0x6c242960), X(0x44a53f93), X(0x6c093cb6),
X(0x44cfa740), X(0x6bee3f62), X(0x44fa0450), X(0x6bd3316a),
X(0x452456bd), X(0x6bb812d1), X(0x454e9e80), X(0x6b9ce39b),
X(0x4578db93), X(0x6b81a3cd), X(0x45a30df0), X(0x6b66536b),
X(0x45cd358f), X(0x6b4af279), X(0x45f7526b), X(0x6b2f80fb),
X(0x4621647d), X(0x6b13fef5), X(0x464b6bbe), X(0x6af86c6c),
X(0x46756828), X(0x6adcc964), X(0x469f59b4), X(0x6ac115e2),
X(0x46c9405c), X(0x6aa551e9), X(0x46f31c1a), X(0x6a897d7d),
X(0x471cece7), X(0x6a6d98a4), X(0x4746b2bc), X(0x6a51a361),
X(0x47706d93), X(0x6a359db9), X(0x479a1d67), X(0x6a1987b0),
X(0x47c3c22f), X(0x69fd614a), X(0x47ed5be6), X(0x69e12a8c),
X(0x4816ea86), X(0x69c4e37a), X(0x48406e08), X(0x69a88c19),
X(0x4869e665), X(0x698c246c), X(0x48935397), X(0x696fac78),
X(0x48bcb599), X(0x69532442), X(0x48e60c62), X(0x69368bce),
X(0x490f57ee), X(0x6919e320), X(0x49389836), X(0x68fd2a3d),
X(0x4961cd33), X(0x68e06129), X(0x498af6df), X(0x68c387e9),
X(0x49b41533), X(0x68a69e81), X(0x49dd282a), X(0x6889a4f6),
X(0x4a062fbd), X(0x686c9b4b), X(0x4a2f2be6), X(0x684f8186),
X(0x4a581c9e), X(0x683257ab), X(0x4a8101de), X(0x68151dbe),
X(0x4aa9dba2), X(0x67f7d3c5), X(0x4ad2a9e2), X(0x67da79c3),
X(0x4afb6c98), X(0x67bd0fbd), X(0x4b2423be), X(0x679f95b7),
X(0x4b4ccf4d), X(0x67820bb7), X(0x4b756f40), X(0x676471c0),
X(0x4b9e0390), X(0x6746c7d8), X(0x4bc68c36), X(0x67290e02),
X(0x4bef092d), X(0x670b4444), X(0x4c177a6e), X(0x66ed6aa1),
X(0x4c3fdff4), X(0x66cf8120), X(0x4c6839b7), X(0x66b187c3),
X(0x4c9087b1), X(0x66937e91), X(0x4cb8c9dd), X(0x6675658c),
X(0x4ce10034), X(0x66573cbb), X(0x4d092ab0), X(0x66390422),
X(0x4d31494b), X(0x661abbc5), X(0x4d595bfe), X(0x65fc63a9),
X(0x4d8162c4), X(0x65ddfbd3), X(0x4da95d96), X(0x65bf8447),
X(0x4dd14c6e), X(0x65a0fd0b), X(0x4df92f46), X(0x65826622),
X(0x4e210617), X(0x6563bf92), X(0x4e48d0dd), X(0x6545095f),
X(0x4e708f8f), X(0x6526438f), X(0x4e984229), X(0x65076e25),
X(0x4ebfe8a5), X(0x64e88926), X(0x4ee782fb), X(0x64c99498),
X(0x4f0f1126), X(0x64aa907f), X(0x4f369320), X(0x648b7ce0),
X(0x4f5e08e3), X(0x646c59bf), X(0x4f857269), X(0x644d2722),
X(0x4faccfab), X(0x642de50d), X(0x4fd420a4), X(0x640e9386),
X(0x4ffb654d), X(0x63ef3290), X(0x50229da1), X(0x63cfc231),
X(0x5049c999), X(0x63b0426d), X(0x5070e92f), X(0x6390b34a),
X(0x5097fc5e), X(0x637114cc), X(0x50bf031f), X(0x635166f9),
X(0x50e5fd6d), X(0x6331a9d4), X(0x510ceb40), X(0x6311dd64),
X(0x5133cc94), X(0x62f201ac), X(0x515aa162), X(0x62d216b3),
X(0x518169a5), X(0x62b21c7b), X(0x51a82555), X(0x6292130c),
X(0x51ced46e), X(0x6271fa69), X(0x51f576ea), X(0x6251d298),
X(0x521c0cc2), X(0x62319b9d), X(0x524295f0), X(0x6211557e),
X(0x5269126e), X(0x61f1003f), X(0x528f8238), X(0x61d09be5),
X(0x52b5e546), X(0x61b02876), X(0x52dc3b92), X(0x618fa5f7),
X(0x53028518), X(0x616f146c), X(0x5328c1d0), X(0x614e73da),
X(0x534ef1b5), X(0x612dc447), X(0x537514c2), X(0x610d05b7),
X(0x539b2af0), X(0x60ec3830), X(0x53c13439), X(0x60cb5bb7),
X(0x53e73097), X(0x60aa7050), X(0x540d2005), X(0x60897601),
X(0x5433027d), X(0x60686ccf), X(0x5458d7f9), X(0x604754bf),
X(0x547ea073), X(0x60262dd6), X(0x54a45be6), X(0x6004f819),
X(0x54ca0a4b), X(0x5fe3b38d), X(0x54efab9c), X(0x5fc26038),
X(0x55153fd4), X(0x5fa0fe1f), X(0x553ac6ee), X(0x5f7f8d46),
X(0x556040e2), X(0x5f5e0db3), X(0x5585adad), X(0x5f3c7f6b),
X(0x55ab0d46), X(0x5f1ae274), X(0x55d05faa), X(0x5ef936d1),
X(0x55f5a4d2), X(0x5ed77c8a), X(0x561adcb9), X(0x5eb5b3a2),
X(0x56400758), X(0x5e93dc1f), X(0x566524aa), X(0x5e71f606),
X(0x568a34a9), X(0x5e50015d), X(0x56af3750), X(0x5e2dfe29),
X(0x56d42c99), X(0x5e0bec6e), X(0x56f9147e), X(0x5de9cc33),
X(0x571deefa), X(0x5dc79d7c), X(0x5742bc06), X(0x5da5604f),
X(0x57677b9d), X(0x5d8314b1), X(0x578c2dba), X(0x5d60baa7),
X(0x57b0d256), X(0x5d3e5237), X(0x57d5696d), X(0x5d1bdb65),
X(0x57f9f2f8), X(0x5cf95638), X(0x581e6ef1), X(0x5cd6c2b5),
X(0x5842dd54), X(0x5cb420e0), X(0x58673e1b), X(0x5c9170bf),
X(0x588b9140), X(0x5c6eb258), X(0x58afd6bd), X(0x5c4be5b0),
X(0x58d40e8c), X(0x5c290acc), X(0x58f838a9), X(0x5c0621b2),
X(0x591c550e), X(0x5be32a67), X(0x594063b5), X(0x5bc024f0),
X(0x59646498), X(0x5b9d1154), X(0x598857b2), X(0x5b79ef96),
X(0x59ac3cfd), X(0x5b56bfbd), X(0x59d01475), X(0x5b3381ce),
X(0x59f3de12), X(0x5b1035cf), X(0x5a1799d1), X(0x5aecdbc5),
X(0x5a3b47ab), X(0x5ac973b5), X(0x5a5ee79a), X(0x5aa5fda5),
X(0x5a82799a), X(0x5a82799a)
};
/* {sin((2*i+1)*PI/4096), cos((2*i+1)*PI/4096)}, with i = 0 to 511 */
static LOOKUP_T sincos_lookup1[1024] = {
X(0x001921fb), X(0x7ffffd88), X(0x004b65ee), X(0x7fffe9cb),
X(0x007da9d4), X(0x7fffc251), X(0x00afeda8), X(0x7fff8719),
X(0x00e23160), X(0x7fff3824), X(0x011474f6), X(0x7ffed572),
X(0x0146b860), X(0x7ffe5f03), X(0x0178fb99), X(0x7ffdd4d7),
X(0x01ab3e97), X(0x7ffd36ee), X(0x01dd8154), X(0x7ffc8549),
X(0x020fc3c6), X(0x7ffbbfe6), X(0x024205e8), X(0x7ffae6c7),
X(0x027447b0), X(0x7ff9f9ec), X(0x02a68917), X(0x7ff8f954),
X(0x02d8ca16), X(0x7ff7e500), X(0x030b0aa4), X(0x7ff6bcf0),
X(0x033d4abb), X(0x7ff58125), X(0x036f8a51), X(0x7ff4319d),
X(0x03a1c960), X(0x7ff2ce5b), X(0x03d407df), X(0x7ff1575d),
X(0x040645c7), X(0x7fefcca4), X(0x04388310), X(0x7fee2e30),
X(0x046abfb3), X(0x7fec7c02), X(0x049cfba7), X(0x7feab61a),
X(0x04cf36e5), X(0x7fe8dc78), X(0x05017165), X(0x7fe6ef1c),
X(0x0533ab20), X(0x7fe4ee06), X(0x0565e40d), X(0x7fe2d938),
X(0x05981c26), X(0x7fe0b0b1), X(0x05ca5361), X(0x7fde7471),
X(0x05fc89b8), X(0x7fdc247a), X(0x062ebf22), X(0x7fd9c0ca),
X(0x0660f398), X(0x7fd74964), X(0x06932713), X(0x7fd4be46),
X(0x06c5598a), X(0x7fd21f72), X(0x06f78af6), X(0x7fcf6ce8),
X(0x0729bb4e), X(0x7fcca6a7), X(0x075bea8c), X(0x7fc9ccb2),
X(0x078e18a7), X(0x7fc6df08), X(0x07c04598), X(0x7fc3dda9),
X(0x07f27157), X(0x7fc0c896), X(0x08249bdd), X(0x7fbd9fd0),
X(0x0856c520), X(0x7fba6357), X(0x0888ed1b), X(0x7fb7132b),
X(0x08bb13c5), X(0x7fb3af4e), X(0x08ed3916), X(0x7fb037bf),
X(0x091f5d06), X(0x7facac7f), X(0x09517f8f), X(0x7fa90d8e),
X(0x0983a0a7), X(0x7fa55aee), X(0x09b5c048), X(0x7fa1949e),
X(0x09e7de6a), X(0x7f9dbaa0), X(0x0a19fb04), X(0x7f99ccf4),
X(0x0a4c1610), X(0x7f95cb9a), X(0x0a7e2f85), X(0x7f91b694),
X(0x0ab0475c), X(0x7f8d8de1), X(0x0ae25d8d), X(0x7f895182),
X(0x0b147211), X(0x7f850179), X(0x0b4684df), X(0x7f809dc5),
X(0x0b7895f0), X(0x7f7c2668), X(0x0baaa53b), X(0x7f779b62),
X(0x0bdcb2bb), X(0x7f72fcb4), X(0x0c0ebe66), X(0x7f6e4a5e),
X(0x0c40c835), X(0x7f698461), X(0x0c72d020), X(0x7f64aabf),
X(0x0ca4d620), X(0x7f5fbd77), X(0x0cd6da2d), X(0x7f5abc8a),
X(0x0d08dc3f), X(0x7f55a7fa), X(0x0d3adc4e), X(0x7f507fc7),
X(0x0d6cda53), X(0x7f4b43f2), X(0x0d9ed646), X(0x7f45f47b),
X(0x0dd0d01f), X(0x7f409164), X(0x0e02c7d7), X(0x7f3b1aad),
X(0x0e34bd66), X(0x7f359057), X(0x0e66b0c3), X(0x7f2ff263),
X(0x0e98a1e9), X(0x7f2a40d2), X(0x0eca90ce), X(0x7f247ba5),
X(0x0efc7d6b), X(0x7f1ea2dc), X(0x0f2e67b8), X(0x7f18b679),
X(0x0f604faf), X(0x7f12b67c), X(0x0f923546), X(0x7f0ca2e7),
X(0x0fc41876), X(0x7f067bba), X(0x0ff5f938), X(0x7f0040f6),
X(0x1027d784), X(0x7ef9f29d), X(0x1059b352), X(0x7ef390ae),
X(0x108b8c9b), X(0x7eed1b2c), X(0x10bd6356), X(0x7ee69217),
X(0x10ef377d), X(0x7edff570), X(0x11210907), X(0x7ed94538),
X(0x1152d7ed), X(0x7ed28171), X(0x1184a427), X(0x7ecbaa1a),
X(0x11b66dad), X(0x7ec4bf36), X(0x11e83478), X(0x7ebdc0c6),
X(0x1219f880), X(0x7eb6aeca), X(0x124bb9be), X(0x7eaf8943),
X(0x127d7829), X(0x7ea85033), X(0x12af33ba), X(0x7ea1039b),
X(0x12e0ec6a), X(0x7e99a37c), X(0x1312a230), X(0x7e922fd6),
X(0x13445505), X(0x7e8aa8ac), X(0x137604e2), X(0x7e830dff),
X(0x13a7b1bf), X(0x7e7b5fce), X(0x13d95b93), X(0x7e739e1d),
X(0x140b0258), X(0x7e6bc8eb), X(0x143ca605), X(0x7e63e03b),
X(0x146e4694), X(0x7e5be40c), X(0x149fe3fc), X(0x7e53d462),
X(0x14d17e36), X(0x7e4bb13c), X(0x1503153a), X(0x7e437a9c),
X(0x1534a901), X(0x7e3b3083), X(0x15663982), X(0x7e32d2f4),
X(0x1597c6b7), X(0x7e2a61ed), X(0x15c95097), X(0x7e21dd73),
X(0x15fad71b), X(0x7e194584), X(0x162c5a3b), X(0x7e109a24),
X(0x165dd9f0), X(0x7e07db52), X(0x168f5632), X(0x7dff0911),
X(0x16c0cef9), X(0x7df62362), X(0x16f2443e), X(0x7ded2a47),
X(0x1723b5f9), X(0x7de41dc0), X(0x17552422), X(0x7ddafdce),
X(0x17868eb3), X(0x7dd1ca75), X(0x17b7f5a3), X(0x7dc883b4),
X(0x17e958ea), X(0x7dbf298d), X(0x181ab881), X(0x7db5bc02),
X(0x184c1461), X(0x7dac3b15), X(0x187d6c82), X(0x7da2a6c6),
X(0x18aec0db), X(0x7d98ff17), X(0x18e01167), X(0x7d8f4409),
X(0x19115e1c), X(0x7d85759f), X(0x1942a6f3), X(0x7d7b93da),
X(0x1973ebe6), X(0x7d719eba), X(0x19a52ceb), X(0x7d679642),
X(0x19d669fc), X(0x7d5d7a74), X(0x1a07a311), X(0x7d534b50),
X(0x1a38d823), X(0x7d4908d9), X(0x1a6a0929), X(0x7d3eb30f),
X(0x1a9b361d), X(0x7d3449f5), X(0x1acc5ef6), X(0x7d29cd8c),
X(0x1afd83ad), X(0x7d1f3dd6), X(0x1b2ea43a), X(0x7d149ad5),
X(0x1b5fc097), X(0x7d09e489), X(0x1b90d8bb), X(0x7cff1af5),
X(0x1bc1ec9e), X(0x7cf43e1a), X(0x1bf2fc3a), X(0x7ce94dfb),
X(0x1c240786), X(0x7cde4a98), X(0x1c550e7c), X(0x7cd333f3),
X(0x1c861113), X(0x7cc80a0f), X(0x1cb70f43), X(0x7cbcccec),
X(0x1ce80906), X(0x7cb17c8d), X(0x1d18fe54), X(0x7ca618f3),
X(0x1d49ef26), X(0x7c9aa221), X(0x1d7adb73), X(0x7c8f1817),
X(0x1dabc334), X(0x7c837ad8), X(0x1ddca662), X(0x7c77ca65),
X(0x1e0d84f5), X(0x7c6c06c0), X(0x1e3e5ee5), X(0x7c602fec),
X(0x1e6f342c), X(0x7c5445e9), X(0x1ea004c1), X(0x7c4848ba),
X(0x1ed0d09d), X(0x7c3c3860), X(0x1f0197b8), X(0x7c3014de),
X(0x1f325a0b), X(0x7c23de35), X(0x1f63178f), X(0x7c179467),
X(0x1f93d03c), X(0x7c0b3777), X(0x1fc4840a), X(0x7bfec765),
X(0x1ff532f2), X(0x7bf24434), X(0x2025dcec), X(0x7be5ade6),
X(0x205681f1), X(0x7bd9047c), X(0x208721f9), X(0x7bcc47fa),
X(0x20b7bcfe), X(0x7bbf7860), X(0x20e852f6), X(0x7bb295b0),
X(0x2118e3dc), X(0x7ba59fee), X(0x21496fa7), X(0x7b989719),
X(0x2179f64f), X(0x7b8b7b36), X(0x21aa77cf), X(0x7b7e4c45),
X(0x21daf41d), X(0x7b710a49), X(0x220b6b32), X(0x7b63b543),
X(0x223bdd08), X(0x7b564d36), X(0x226c4996), X(0x7b48d225),
X(0x229cb0d5), X(0x7b3b4410), X(0x22cd12bd), X(0x7b2da2fa),
X(0x22fd6f48), X(0x7b1feee5), X(0x232dc66d), X(0x7b1227d3),
X(0x235e1826), X(0x7b044dc7), X(0x238e646a), X(0x7af660c2),
X(0x23beab33), X(0x7ae860c7), X(0x23eeec78), X(0x7ada4dd8),
X(0x241f2833), X(0x7acc27f7), X(0x244f5e5c), X(0x7abdef25),
X(0x247f8eec), X(0x7aafa367), X(0x24afb9da), X(0x7aa144bc),
X(0x24dfdf20), X(0x7a92d329), X(0x250ffeb7), X(0x7a844eae),
X(0x25401896), X(0x7a75b74f), X(0x25702cb7), X(0x7a670d0d),
X(0x25a03b11), X(0x7a584feb), X(0x25d0439f), X(0x7a497feb),
X(0x26004657), X(0x7a3a9d0f), X(0x26304333), X(0x7a2ba75a),
X(0x26603a2c), X(0x7a1c9ece), X(0x26902b39), X(0x7a0d836d),
X(0x26c01655), X(0x79fe5539), X(0x26effb76), X(0x79ef1436),
X(0x271fda96), X(0x79dfc064), X(0x274fb3ae), X(0x79d059c8),
X(0x277f86b5), X(0x79c0e062), X(0x27af53a6), X(0x79b15435),
X(0x27df1a77), X(0x79a1b545), X(0x280edb23), X(0x79920392),
X(0x283e95a1), X(0x79823f20), X(0x286e49ea), X(0x797267f2),
X(0x289df7f8), X(0x79627e08), X(0x28cd9fc1), X(0x79528167),
X(0x28fd4140), X(0x79427210), X(0x292cdc6d), X(0x79325006),
X(0x295c7140), X(0x79221b4b), X(0x298bffb2), X(0x7911d3e2),
X(0x29bb87bc), X(0x790179cd), X(0x29eb0957), X(0x78f10d0f),
X(0x2a1a847b), X(0x78e08dab), X(0x2a49f920), X(0x78cffba3),
X(0x2a796740), X(0x78bf56f9), X(0x2aa8ced3), X(0x78ae9fb0),
X(0x2ad82fd2), X(0x789dd5cb), X(0x2b078a36), X(0x788cf94c),
X(0x2b36ddf7), X(0x787c0a36), X(0x2b662b0e), X(0x786b088c),
X(0x2b957173), X(0x7859f44f), X(0x2bc4b120), X(0x7848cd83),
X(0x2bf3ea0d), X(0x7837942b), X(0x2c231c33), X(0x78264849),
X(0x2c52478a), X(0x7814e9df), X(0x2c816c0c), X(0x780378f1),
X(0x2cb089b1), X(0x77f1f581), X(0x2cdfa071), X(0x77e05f91),
X(0x2d0eb046), X(0x77ceb725), X(0x2d3db928), X(0x77bcfc3f),
X(0x2d6cbb10), X(0x77ab2ee2), X(0x2d9bb5f6), X(0x77994f11),
X(0x2dcaa9d5), X(0x77875cce), X(0x2df996a3), X(0x7775581d),
X(0x2e287c5a), X(0x776340ff), X(0x2e575af3), X(0x77511778),
X(0x2e863267), X(0x773edb8b), X(0x2eb502ae), X(0x772c8d3a),
X(0x2ee3cbc1), X(0x771a2c88), X(0x2f128d99), X(0x7707b979),
X(0x2f41482e), X(0x76f5340e), X(0x2f6ffb7a), X(0x76e29c4b),
X(0x2f9ea775), X(0x76cff232), X(0x2fcd4c19), X(0x76bd35c7),
X(0x2ffbe95d), X(0x76aa670d), X(0x302a7f3a), X(0x76978605),
X(0x30590dab), X(0x768492b4), X(0x308794a6), X(0x76718d1c),
X(0x30b61426), X(0x765e7540), X(0x30e48c22), X(0x764b4b23),
X(0x3112fc95), X(0x76380ec8), X(0x31416576), X(0x7624c031),
X(0x316fc6be), X(0x76115f63), X(0x319e2067), X(0x75fdec60),
X(0x31cc7269), X(0x75ea672a), X(0x31fabcbd), X(0x75d6cfc5),
X(0x3228ff5c), X(0x75c32634), X(0x32573a3f), X(0x75af6a7b),
X(0x32856d5e), X(0x759b9c9b), X(0x32b398b3), X(0x7587bc98),
X(0x32e1bc36), X(0x7573ca75), X(0x330fd7e1), X(0x755fc635),
X(0x333debab), X(0x754bafdc), X(0x336bf78f), X(0x7537876c),
X(0x3399fb85), X(0x75234ce8), X(0x33c7f785), X(0x750f0054),
X(0x33f5eb89), X(0x74faa1b3), X(0x3423d78a), X(0x74e63108),
X(0x3451bb81), X(0x74d1ae55), X(0x347f9766), X(0x74bd199f),
X(0x34ad6b32), X(0x74a872e8), X(0x34db36df), X(0x7493ba34),
X(0x3508fa66), X(0x747eef85), X(0x3536b5be), X(0x746a12df),
X(0x356468e2), X(0x74552446), X(0x359213c9), X(0x744023bc),
X(0x35bfb66e), X(0x742b1144), X(0x35ed50c9), X(0x7415ece2),
X(0x361ae2d3), X(0x7400b69a), X(0x36486c86), X(0x73eb6e6e),
X(0x3675edd9), X(0x73d61461), X(0x36a366c6), X(0x73c0a878),
X(0x36d0d746), X(0x73ab2ab4), X(0x36fe3f52), X(0x73959b1b),
X(0x372b9ee3), X(0x737ff9ae), X(0x3758f5f2), X(0x736a4671),
X(0x37864477), X(0x73548168), X(0x37b38a6d), X(0x733eaa96),
X(0x37e0c7cc), X(0x7328c1ff), X(0x380dfc8d), X(0x7312c7a5),
X(0x383b28a9), X(0x72fcbb8c), X(0x38684c19), X(0x72e69db7),
X(0x389566d6), X(0x72d06e2b), X(0x38c278d9), X(0x72ba2cea),
X(0x38ef821c), X(0x72a3d9f7), X(0x391c8297), X(0x728d7557),
X(0x39497a43), X(0x7276ff0d), X(0x39766919), X(0x7260771b),
X(0x39a34f13), X(0x7249dd86), X(0x39d02c2a), X(0x72333251),
X(0x39fd0056), X(0x721c7580), X(0x3a29cb91), X(0x7205a716),
X(0x3a568dd4), X(0x71eec716), X(0x3a834717), X(0x71d7d585),
X(0x3aaff755), X(0x71c0d265), X(0x3adc9e86), X(0x71a9bdba),
X(0x3b093ca3), X(0x71929789), X(0x3b35d1a5), X(0x717b5fd3),
X(0x3b625d86), X(0x7164169d), X(0x3b8ee03e), X(0x714cbbeb),
X(0x3bbb59c7), X(0x71354fc0), X(0x3be7ca1a), X(0x711dd220),
X(0x3c143130), X(0x7106430e), X(0x3c408f03), X(0x70eea28e),
X(0x3c6ce38a), X(0x70d6f0a4), X(0x3c992ec0), X(0x70bf2d53),
X(0x3cc5709e), X(0x70a7589f), X(0x3cf1a91c), X(0x708f728b),
X(0x3d1dd835), X(0x70777b1c), X(0x3d49fde1), X(0x705f7255),
X(0x3d761a19), X(0x70475839), X(0x3da22cd7), X(0x702f2ccd),
X(0x3dce3614), X(0x7016f014), X(0x3dfa35c8), X(0x6ffea212),
X(0x3e262bee), X(0x6fe642ca), X(0x3e52187f), X(0x6fcdd241),
X(0x3e7dfb73), X(0x6fb5507a), X(0x3ea9d4c3), X(0x6f9cbd79),
X(0x3ed5a46b), X(0x6f841942), X(0x3f016a61), X(0x6f6b63d8),
X(0x3f2d26a0), X(0x6f529d40), X(0x3f58d921), X(0x6f39c57d),
X(0x3f8481dd), X(0x6f20dc92), X(0x3fb020ce), X(0x6f07e285),
X(0x3fdbb5ec), X(0x6eeed758), X(0x40074132), X(0x6ed5bb10),
X(0x4032c297), X(0x6ebc8db0), X(0x405e3a16), X(0x6ea34f3d),
X(0x4089a7a8), X(0x6e89ffb9), X(0x40b50b46), X(0x6e709f2a),
X(0x40e064ea), X(0x6e572d93), X(0x410bb48c), X(0x6e3daaf8),
X(0x4136fa27), X(0x6e24175c), X(0x416235b2), X(0x6e0a72c5),
X(0x418d6729), X(0x6df0bd35), X(0x41b88e84), X(0x6dd6f6b1),
X(0x41e3abbc), X(0x6dbd1f3c), X(0x420ebecb), X(0x6da336dc),
X(0x4239c7aa), X(0x6d893d93), X(0x4264c653), X(0x6d6f3365),
X(0x428fbabe), X(0x6d551858), X(0x42baa4e6), X(0x6d3aec6e),
X(0x42e584c3), X(0x6d20afac), X(0x43105a50), X(0x6d066215),
X(0x433b2585), X(0x6cec03af), X(0x4365e65b), X(0x6cd1947c),
X(0x43909ccd), X(0x6cb71482), X(0x43bb48d4), X(0x6c9c83c3),
X(0x43e5ea68), X(0x6c81e245), X(0x44108184), X(0x6c67300b),
X(0x443b0e21), X(0x6c4c6d1a), X(0x44659039), X(0x6c319975),
X(0x449007c4), X(0x6c16b521), X(0x44ba74bd), X(0x6bfbc021),
X(0x44e4d71c), X(0x6be0ba7b), X(0x450f2edb), X(0x6bc5a431),
X(0x45397bf4), X(0x6baa7d49), X(0x4563be60), X(0x6b8f45c7),
X(0x458df619), X(0x6b73fdae), X(0x45b82318), X(0x6b58a503),
X(0x45e24556), X(0x6b3d3bcb), X(0x460c5cce), X(0x6b21c208),
X(0x46366978), X(0x6b0637c1), X(0x46606b4e), X(0x6aea9cf8),
X(0x468a624a), X(0x6acef1b2), X(0x46b44e65), X(0x6ab335f4),
X(0x46de2f99), X(0x6a9769c1), X(0x470805df), X(0x6a7b8d1e),
X(0x4731d131), X(0x6a5fa010), X(0x475b9188), X(0x6a43a29a),
X(0x478546de), X(0x6a2794c1), X(0x47aef12c), X(0x6a0b7689),
X(0x47d8906d), X(0x69ef47f6), X(0x48022499), X(0x69d3090e),
X(0x482badab), X(0x69b6b9d3), X(0x48552b9b), X(0x699a5a4c),
X(0x487e9e64), X(0x697dea7b), X(0x48a805ff), X(0x69616a65),
X(0x48d16265), X(0x6944da10), X(0x48fab391), X(0x6928397e),
X(0x4923f97b), X(0x690b88b5), X(0x494d341e), X(0x68eec7b9),
X(0x49766373), X(0x68d1f68f), X(0x499f8774), X(0x68b5153a),
X(0x49c8a01b), X(0x689823bf), X(0x49f1ad61), X(0x687b2224),
X(0x4a1aaf3f), X(0x685e106c), X(0x4a43a5b0), X(0x6840ee9b),
X(0x4a6c90ad), X(0x6823bcb7), X(0x4a957030), X(0x68067ac3),
X(0x4abe4433), X(0x67e928c5), X(0x4ae70caf), X(0x67cbc6c0),
X(0x4b0fc99d), X(0x67ae54ba), X(0x4b387af9), X(0x6790d2b6),
X(0x4b6120bb), X(0x677340ba), X(0x4b89badd), X(0x67559eca),
X(0x4bb24958), X(0x6737ecea), X(0x4bdacc28), X(0x671a2b20),
X(0x4c034345), X(0x66fc596f), X(0x4c2baea9), X(0x66de77dc),
X(0x4c540e4e), X(0x66c0866d), X(0x4c7c622d), X(0x66a28524),
X(0x4ca4aa41), X(0x66847408), X(0x4ccce684), X(0x6666531d),
X(0x4cf516ee), X(0x66482267), X(0x4d1d3b7a), X(0x6629e1ec),
X(0x4d455422), X(0x660b91af), X(0x4d6d60df), X(0x65ed31b5),
X(0x4d9561ac), X(0x65cec204), X(0x4dbd5682), X(0x65b0429f),
X(0x4de53f5a), X(0x6591b38c), X(0x4e0d1c30), X(0x657314cf),
X(0x4e34ecfc), X(0x6554666d), X(0x4e5cb1b9), X(0x6535a86b),
X(0x4e846a60), X(0x6516dacd), X(0x4eac16eb), X(0x64f7fd98),
X(0x4ed3b755), X(0x64d910d1), X(0x4efb4b96), X(0x64ba147d),
X(0x4f22d3aa), X(0x649b08a0), X(0x4f4a4f89), X(0x647bed3f),
X(0x4f71bf2e), X(0x645cc260), X(0x4f992293), X(0x643d8806),
X(0x4fc079b1), X(0x641e3e38), X(0x4fe7c483), X(0x63fee4f8),
X(0x500f0302), X(0x63df7c4d), X(0x50363529), X(0x63c0043b),
X(0x505d5af1), X(0x63a07cc7), X(0x50847454), X(0x6380e5f6),
X(0x50ab814d), X(0x63613fcd), X(0x50d281d5), X(0x63418a50),
X(0x50f975e6), X(0x6321c585), X(0x51205d7b), X(0x6301f171),
X(0x5147388c), X(0x62e20e17), X(0x516e0715), X(0x62c21b7e),
X(0x5194c910), X(0x62a219aa), X(0x51bb7e75), X(0x628208a1),
X(0x51e22740), X(0x6261e866), X(0x5208c36a), X(0x6241b8ff),
X(0x522f52ee), X(0x62217a72), X(0x5255d5c5), X(0x62012cc2),
X(0x527c4bea), X(0x61e0cff5), X(0x52a2b556), X(0x61c06410),
X(0x52c91204), X(0x619fe918), X(0x52ef61ee), X(0x617f5f12),
X(0x5315a50e), X(0x615ec603), X(0x533bdb5d), X(0x613e1df0),
X(0x536204d7), X(0x611d66de), X(0x53882175), X(0x60fca0d2),
X(0x53ae3131), X(0x60dbcbd1), X(0x53d43406), X(0x60bae7e1),
X(0x53fa29ed), X(0x6099f505), X(0x542012e1), X(0x6078f344),
X(0x5445eedb), X(0x6057e2a2), X(0x546bbdd7), X(0x6036c325),
X(0x54917fce), X(0x601594d1), X(0x54b734ba), X(0x5ff457ad),
X(0x54dcdc96), X(0x5fd30bbc), X(0x5502775c), X(0x5fb1b104),
X(0x55280505), X(0x5f90478a), X(0x554d858d), X(0x5f6ecf53),
X(0x5572f8ed), X(0x5f4d4865), X(0x55985f20), X(0x5f2bb2c5),
X(0x55bdb81f), X(0x5f0a0e77), X(0x55e303e6), X(0x5ee85b82),
X(0x5608426e), X(0x5ec699e9), X(0x562d73b2), X(0x5ea4c9b3),
X(0x565297ab), X(0x5e82eae5), X(0x5677ae54), X(0x5e60fd84),
X(0x569cb7a8), X(0x5e3f0194), X(0x56c1b3a1), X(0x5e1cf71c),
X(0x56e6a239), X(0x5dfade20), X(0x570b8369), X(0x5dd8b6a7),
X(0x5730572e), X(0x5db680b4), X(0x57551d80), X(0x5d943c4e),
X(0x5779d65b), X(0x5d71e979), X(0x579e81b8), X(0x5d4f883b),
X(0x57c31f92), X(0x5d2d189a), X(0x57e7afe4), X(0x5d0a9a9a),
X(0x580c32a7), X(0x5ce80e41), X(0x5830a7d6), X(0x5cc57394),
X(0x58550f6c), X(0x5ca2ca99), X(0x58796962), X(0x5c801354),
X(0x589db5b3), X(0x5c5d4dcc), X(0x58c1f45b), X(0x5c3a7a05),
X(0x58e62552), X(0x5c179806), X(0x590a4893), X(0x5bf4a7d2),
X(0x592e5e19), X(0x5bd1a971), X(0x595265df), X(0x5bae9ce7),
X(0x59765fde), X(0x5b8b8239), X(0x599a4c12), X(0x5b68596d),
X(0x59be2a74), X(0x5b452288), X(0x59e1faff), X(0x5b21dd90),
X(0x5a05bdae), X(0x5afe8a8b), X(0x5a29727b), X(0x5adb297d),
X(0x5a4d1960), X(0x5ab7ba6c), X(0x5a70b258), X(0x5a943d5e),
};
+228
View File
@@ -0,0 +1,228 @@
/********************************************************************
* *
* THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. *
* *
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 *
* BY THE Xiph.Org FOUNDATION http://www.xiph.org/ *
* *
********************************************************************
function: miscellaneous math and prototypes
********************************************************************/
#ifndef _V_RANDOM_H_
#define _V_RANDOM_H_
#include "ivorbiscodec.h"
#include "os.h"
#ifdef _LOW_ACCURACY_
# define X(n) (((((n)>>22)+1)>>1) - ((((n)>>22)+1)>>9))
# define LOOKUP_T const unsigned char
#else
# define X(n) (n)
# define LOOKUP_T const ogg_int32_t
#endif
#include "asm_arm.h"
#include <stdlib.h> /* for abs() */
#ifndef _V_WIDE_MATH
#define _V_WIDE_MATH
#ifndef _LOW_ACCURACY_
/* 64 bit multiply */
#if !(defined WIN32 && defined WINCE)
#include <sys/types.h>
#endif
STIN ogg_int32_t MULT32(ogg_int32_t x, ogg_int32_t y) {
return (ogg_int64_t)x * y >> 32;
}
STIN ogg_int32_t MULT31(ogg_int32_t x, ogg_int32_t y) {
return MULT32(x,y)<<1;
}
STIN ogg_int32_t MULT31_SHIFT15(ogg_int32_t x, ogg_int32_t y) {
return (ogg_int64_t)x * y >> 15;
}
#else
/* 32 bit multiply, more portable but less accurate */
/*
* Note: Precision is biased towards the first argument therefore ordering
* is important. Shift values were chosen for the best sound quality after
* many listening tests.
*/
/*
* For MULT32 and MULT31: The second argument is always a lookup table
* value already preshifted from 31 to 8 bits. We therefore take the
* opportunity to save on text space and use unsigned char for those
* tables in this case.
*/
STIN ogg_int32_t MULT32(ogg_int32_t x, ogg_int32_t y) {
return (x >> 9) * y; /* y preshifted >>23 */
}
STIN ogg_int32_t MULT31(ogg_int32_t x, ogg_int32_t y) {
return (x >> 8) * y; /* y preshifted >>23 */
}
STIN ogg_int32_t MULT31_SHIFT15(ogg_int32_t x, ogg_int32_t y) {
return (x >> 6) * y; /* y preshifted >>9 */
}
#endif
/*
* This should be used as a memory barrier, forcing all cached values in
* registers to wr writen back to memory. Might or might not be beneficial
* depending on the architecture and compiler.
*/
#define MB()
/*
* The XPROD functions are meant to optimize the cross products found all
* over the place in mdct.c by forcing memory operation ordering to avoid
* unnecessary register reloads as soon as memory is being written to.
* However this is only beneficial on CPUs with a sane number of general
* purpose registers which exclude the Intel x86. On Intel, better let the
* compiler actually reload registers directly from original memory by using
* macros.
*/
#ifdef __i386__
#define XPROD32(_a, _b, _t, _v, _x, _y) \
{ *(_x)=MULT32(_a,_t)+MULT32(_b,_v); \
*(_y)=MULT32(_b,_t)-MULT32(_a,_v); }
#define XPROD31(_a, _b, _t, _v, _x, _y) \
{ *(_x)=MULT31(_a,_t)+MULT31(_b,_v); \
*(_y)=MULT31(_b,_t)-MULT31(_a,_v); }
#define XNPROD31(_a, _b, _t, _v, _x, _y) \
{ *(_x)=MULT31(_a,_t)-MULT31(_b,_v); \
*(_y)=MULT31(_b,_t)+MULT31(_a,_v); }
#else
STIN void XPROD32(ogg_int32_t a, ogg_int32_t b,
ogg_int32_t t, ogg_int32_t v,
ogg_int32_t *x, ogg_int32_t *y)
{
*x = MULT32(a, t) + MULT32(b, v);
*y = MULT32(b, t) - MULT32(a, v);
}
STIN void XPROD31(ogg_int32_t a, ogg_int32_t b,
ogg_int32_t t, ogg_int32_t v,
ogg_int32_t *x, ogg_int32_t *y)
{
*x = MULT31(a, t) + MULT31(b, v);
*y = MULT31(b, t) - MULT31(a, v);
}
STIN void XNPROD31(ogg_int32_t a, ogg_int32_t b,
ogg_int32_t t, ogg_int32_t v,
ogg_int32_t *x, ogg_int32_t *y)
{
*x = MULT31(a, t) - MULT31(b, v);
*y = MULT31(b, t) + MULT31(a, v);
}
#endif
#endif
#ifndef _V_CLIP_MATH
#define _V_CLIP_MATH
STIN ogg_int32_t CLIP_TO_15(ogg_int32_t x) {
int ret=x;
ret-= ((x<=32767)-1)&(x-32767);
ret-= ((x>=-32768)-1)&(x+32768);
return(ret);
}
#endif
STIN ogg_int32_t VFLOAT_MULT(ogg_int32_t a,ogg_int32_t ap,
ogg_int32_t b,ogg_int32_t bp,
ogg_int32_t *p){
if(a && b){
#ifndef _LOW_ACCURACY_
*p=ap+bp+32;
return MULT32(a,b);
#else
*p=ap+bp+31;
return (a>>15)*(b>>16);
#endif
}else
return 0;
}
int _ilog(unsigned int);
STIN ogg_int32_t VFLOAT_MULTI(ogg_int32_t a,ogg_int32_t ap,
ogg_int32_t i,
ogg_int32_t *p){
int ip=_ilog(abs(i))-31;
return VFLOAT_MULT(a,ap,i<<-ip,ip,p);
}
STIN ogg_int32_t VFLOAT_ADD(ogg_int32_t a,ogg_int32_t ap,
ogg_int32_t b,ogg_int32_t bp,
ogg_int32_t *p){
if(!a){
*p=bp;
return b;
}else if(!b){
*p=ap;
return a;
}
/* yes, this can leak a bit. */
if(ap>bp){
int shift=ap-bp+1;
*p=ap+1;
a>>=1;
if(shift<32){
b=(b+(1<<(shift-1)))>>shift;
}else{
b=0;
}
}else{
int shift=bp-ap+1;
*p=bp+1;
b>>=1;
if(shift<32){
a=(a+(1<<(shift-1)))>>shift;
}else{
a=0;
}
}
a+=b;
if((a&0xc0000000)==0xc0000000 ||
(a&0xc0000000)==0){
a<<=1;
(*p)--;
}
return(a);
}
#endif
+26
View File
@@ -0,0 +1,26 @@
#ifndef __CONFIG_TYPES_H__
#define __CONFIG_TYPES_H__
/* these are filled in by configure or cmake*/
#define INCLUDE_INTTYPES_H 1
#define INCLUDE_STDINT_H 1
#define INCLUDE_SYS_TYPES_H 1
#if INCLUDE_INTTYPES_H
# include <inttypes.h>
#endif
#if INCLUDE_STDINT_H
# include <stdint.h>
#endif
#if INCLUDE_SYS_TYPES_H
# include <sys/types.h>
#endif
typedef int16_t ogg_int16_t;
typedef uint16_t ogg_uint16_t;
typedef int32_t ogg_int32_t;
typedef uint32_t ogg_uint32_t;
typedef int64_t ogg_int64_t;
typedef uint64_t ogg_uint64_t;
#endif
+209
View File
@@ -0,0 +1,209 @@
/********************************************************************
* *
* THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2007 *
* by the Xiph.Org Foundation http://www.xiph.org/ *
* *
********************************************************************
function: toplevel libogg include
********************************************************************/
#ifndef _OGG_H
#define _OGG_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stddef.h>
#include <ogg/os_types.h>
typedef struct {
void *iov_base;
size_t iov_len;
} ogg_iovec_t;
typedef struct {
long endbyte;
int endbit;
unsigned char *buffer;
unsigned char *ptr;
long storage;
} oggpack_buffer;
/* ogg_page is used to encapsulate the data in one Ogg bitstream page *****/
typedef struct {
unsigned char *header;
long header_len;
unsigned char *body;
long body_len;
} ogg_page;
/* ogg_stream_state contains the current encode/decode state of a logical
Ogg bitstream **********************************************************/
typedef struct {
unsigned char *body_data; /* bytes from packet bodies */
long body_storage; /* storage elements allocated */
long body_fill; /* elements stored; fill mark */
long body_returned; /* elements of fill returned */
int *lacing_vals; /* The values that will go to the segment table */
ogg_int64_t *granule_vals; /* granulepos values for headers. Not compact
this way, but it is simple coupled to the
lacing fifo */
long lacing_storage;
long lacing_fill;
long lacing_packet;
long lacing_returned;
unsigned char header[282]; /* working space for header encode */
int header_fill;
int e_o_s; /* set when we have buffered the last packet in the
logical bitstream */
int b_o_s; /* set after we've written the initial page
of a logical bitstream */
long serialno;
long pageno;
ogg_int64_t packetno; /* sequence number for decode; the framing
knows where there's a hole in the data,
but we need coupling so that the codec
(which is in a separate abstraction
layer) also knows about the gap */
ogg_int64_t granulepos;
} ogg_stream_state;
/* ogg_packet is used to encapsulate the data and metadata belonging
to a single raw Ogg/Vorbis packet *************************************/
typedef struct {
unsigned char *packet;
long bytes;
long b_o_s;
long e_o_s;
ogg_int64_t granulepos;
ogg_int64_t packetno; /* sequence number for decode; the framing
knows where there's a hole in the data,
but we need coupling so that the codec
(which is in a separate abstraction
layer) also knows about the gap */
} ogg_packet;
typedef struct {
unsigned char *data;
int storage;
int fill;
int returned;
int unsynced;
int headerbytes;
int bodybytes;
} ogg_sync_state;
/* Ogg BITSTREAM PRIMITIVES: bitstream ************************/
extern void oggpack_writeinit(oggpack_buffer *b);
extern int oggpack_writecheck(oggpack_buffer *b);
extern void oggpack_writetrunc(oggpack_buffer *b,long bits);
extern void oggpack_writealign(oggpack_buffer *b);
extern void oggpack_writecopy(oggpack_buffer *b,void *source,long bits);
extern void oggpack_reset(oggpack_buffer *b);
extern void oggpack_writeclear(oggpack_buffer *b);
extern void oggpack_readinit(oggpack_buffer *b,unsigned char *buf,int bytes);
extern void oggpack_write(oggpack_buffer *b,unsigned long value,int bits);
extern long oggpack_look(oggpack_buffer *b,int bits);
extern long oggpack_look1(oggpack_buffer *b);
extern void oggpack_adv(oggpack_buffer *b,int bits);
extern void oggpack_adv1(oggpack_buffer *b);
extern long oggpack_read(oggpack_buffer *b,int bits);
extern long oggpack_read1(oggpack_buffer *b);
extern long oggpack_bytes(oggpack_buffer *b);
extern long oggpack_bits(oggpack_buffer *b);
extern unsigned char *oggpack_get_buffer(oggpack_buffer *b);
extern void oggpackB_writeinit(oggpack_buffer *b);
extern int oggpackB_writecheck(oggpack_buffer *b);
extern void oggpackB_writetrunc(oggpack_buffer *b,long bits);
extern void oggpackB_writealign(oggpack_buffer *b);
extern void oggpackB_writecopy(oggpack_buffer *b,void *source,long bits);
extern void oggpackB_reset(oggpack_buffer *b);
extern void oggpackB_writeclear(oggpack_buffer *b);
extern void oggpackB_readinit(oggpack_buffer *b,unsigned char *buf,int bytes);
extern void oggpackB_write(oggpack_buffer *b,unsigned long value,int bits);
extern long oggpackB_look(oggpack_buffer *b,int bits);
extern long oggpackB_look1(oggpack_buffer *b);
extern void oggpackB_adv(oggpack_buffer *b,int bits);
extern void oggpackB_adv1(oggpack_buffer *b);
extern long oggpackB_read(oggpack_buffer *b,int bits);
extern long oggpackB_read1(oggpack_buffer *b);
extern long oggpackB_bytes(oggpack_buffer *b);
extern long oggpackB_bits(oggpack_buffer *b);
extern unsigned char *oggpackB_get_buffer(oggpack_buffer *b);
/* Ogg BITSTREAM PRIMITIVES: encoding **************************/
extern int ogg_stream_packetin(ogg_stream_state *os, ogg_packet *op);
extern int ogg_stream_iovecin(ogg_stream_state *os, ogg_iovec_t *iov,
int count, long e_o_s, ogg_int64_t granulepos);
extern int ogg_stream_pageout(ogg_stream_state *os, ogg_page *og);
extern int ogg_stream_pageout_fill(ogg_stream_state *os, ogg_page *og, int nfill);
extern int ogg_stream_flush(ogg_stream_state *os, ogg_page *og);
extern int ogg_stream_flush_fill(ogg_stream_state *os, ogg_page *og, int nfill);
/* Ogg BITSTREAM PRIMITIVES: decoding **************************/
extern int ogg_sync_init(ogg_sync_state *oy);
extern int ogg_sync_clear(ogg_sync_state *oy);
extern int ogg_sync_reset(ogg_sync_state *oy);
extern int ogg_sync_destroy(ogg_sync_state *oy);
extern int ogg_sync_check(ogg_sync_state *oy);
extern char *ogg_sync_buffer(ogg_sync_state *oy, long size);
extern int ogg_sync_wrote(ogg_sync_state *oy, long bytes);
extern long ogg_sync_pageseek(ogg_sync_state *oy,ogg_page *og);
extern int ogg_sync_pageout(ogg_sync_state *oy, ogg_page *og);
extern int ogg_stream_pagein(ogg_stream_state *os, ogg_page *og);
extern int ogg_stream_packetout(ogg_stream_state *os,ogg_packet *op);
extern int ogg_stream_packetpeek(ogg_stream_state *os,ogg_packet *op);
/* Ogg BITSTREAM PRIMITIVES: general ***************************/
extern int ogg_stream_init(ogg_stream_state *os,int serialno);
extern int ogg_stream_clear(ogg_stream_state *os);
extern int ogg_stream_reset(ogg_stream_state *os);
extern int ogg_stream_reset_serialno(ogg_stream_state *os,int serialno);
extern int ogg_stream_destroy(ogg_stream_state *os);
extern int ogg_stream_check(ogg_stream_state *os);
extern int ogg_stream_eos(ogg_stream_state *os);
extern void ogg_page_checksum_set(ogg_page *og);
extern int ogg_page_version(const ogg_page *og);
extern int ogg_page_continued(const ogg_page *og);
extern int ogg_page_bos(const ogg_page *og);
extern int ogg_page_eos(const ogg_page *og);
extern ogg_int64_t ogg_page_granulepos(const ogg_page *og);
extern int ogg_page_serialno(const ogg_page *og);
extern long ogg_page_pageno(const ogg_page *og);
extern int ogg_page_packets(const ogg_page *og);
extern void ogg_packet_clear(ogg_packet *op);
#ifdef __cplusplus
}
#endif
#endif /* _OGG_H */
+158
View File
@@ -0,0 +1,158 @@
/********************************************************************
* *
* THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2002 *
* by the Xiph.Org Foundation http://www.xiph.org/ *
* *
********************************************************************
function: Define a consistent set of types on each platform.
********************************************************************/
#ifndef _OS_TYPES_H
#define _OS_TYPES_H
/* make it easy on the folks that want to compile the libs with a
different malloc than stdlib */
#define _ogg_malloc malloc
#define _ogg_calloc calloc
#define _ogg_realloc realloc
#define _ogg_free free
#if defined(_WIN32)
# if defined(__CYGWIN__)
# include <stdint.h>
typedef int16_t ogg_int16_t;
typedef uint16_t ogg_uint16_t;
typedef int32_t ogg_int32_t;
typedef uint32_t ogg_uint32_t;
typedef int64_t ogg_int64_t;
typedef uint64_t ogg_uint64_t;
# elif defined(__MINGW32__)
# include <sys/types.h>
typedef short ogg_int16_t;
typedef unsigned short ogg_uint16_t;
typedef int ogg_int32_t;
typedef unsigned int ogg_uint32_t;
typedef long long ogg_int64_t;
typedef unsigned long long ogg_uint64_t;
# elif defined(__MWERKS__)
typedef long long ogg_int64_t;
typedef unsigned long long ogg_uint64_t;
typedef int ogg_int32_t;
typedef unsigned int ogg_uint32_t;
typedef short ogg_int16_t;
typedef unsigned short ogg_uint16_t;
# else
# if defined(_MSC_VER) && (_MSC_VER >= 1800) /* MSVC 2013 and newer */
# include <stdint.h>
typedef int16_t ogg_int16_t;
typedef uint16_t ogg_uint16_t;
typedef int32_t ogg_int32_t;
typedef uint32_t ogg_uint32_t;
typedef int64_t ogg_int64_t;
typedef uint64_t ogg_uint64_t;
# else
/* MSVC/Borland */
typedef __int64 ogg_int64_t;
typedef __int32 ogg_int32_t;
typedef unsigned __int32 ogg_uint32_t;
typedef unsigned __int64 ogg_uint64_t;
typedef __int16 ogg_int16_t;
typedef unsigned __int16 ogg_uint16_t;
# endif
# endif
#elif (defined(__APPLE__) && defined(__MACH__)) /* MacOS X Framework build */
# include <sys/types.h>
typedef int16_t ogg_int16_t;
typedef u_int16_t ogg_uint16_t;
typedef int32_t ogg_int32_t;
typedef u_int32_t ogg_uint32_t;
typedef int64_t ogg_int64_t;
typedef u_int64_t ogg_uint64_t;
#elif defined(__HAIKU__)
/* Haiku */
# include <sys/types.h>
typedef short ogg_int16_t;
typedef unsigned short ogg_uint16_t;
typedef int ogg_int32_t;
typedef unsigned int ogg_uint32_t;
typedef long long ogg_int64_t;
typedef unsigned long long ogg_uint64_t;
#elif defined(__BEOS__)
/* Be */
# include <inttypes.h>
typedef int16_t ogg_int16_t;
typedef uint16_t ogg_uint16_t;
typedef int32_t ogg_int32_t;
typedef uint32_t ogg_uint32_t;
typedef int64_t ogg_int64_t;
typedef uint64_t ogg_uint64_t;
#elif defined (__EMX__)
/* OS/2 GCC */
typedef short ogg_int16_t;
typedef unsigned short ogg_uint16_t;
typedef int ogg_int32_t;
typedef unsigned int ogg_uint32_t;
typedef long long ogg_int64_t;
typedef unsigned long long ogg_uint64_t;
#elif defined (DJGPP)
/* DJGPP */
typedef short ogg_int16_t;
typedef int ogg_int32_t;
typedef unsigned int ogg_uint32_t;
typedef long long ogg_int64_t;
typedef unsigned long long ogg_uint64_t;
#elif defined(R5900)
/* PS2 EE */
typedef long ogg_int64_t;
typedef unsigned long ogg_uint64_t;
typedef int ogg_int32_t;
typedef unsigned ogg_uint32_t;
typedef short ogg_int16_t;
#elif defined(__SYMBIAN32__)
/* Symbian GCC */
typedef signed short ogg_int16_t;
typedef unsigned short ogg_uint16_t;
typedef signed int ogg_int32_t;
typedef unsigned int ogg_uint32_t;
typedef long long int ogg_int64_t;
typedef unsigned long long int ogg_uint64_t;
#elif defined(__TMS320C6X__)
/* TI C64x compiler */
typedef signed short ogg_int16_t;
typedef unsigned short ogg_uint16_t;
typedef signed int ogg_int32_t;
typedef unsigned int ogg_uint32_t;
typedef long long int ogg_int64_t;
typedef unsigned long long int ogg_uint64_t;
#else
# include <ogg/config_types.h>
#endif
#endif /* _OS_TYPES_H */
+64
View File
@@ -0,0 +1,64 @@
#ifndef _OS_H
#define _OS_H
/********************************************************************
* *
* THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. *
* *
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 *
* BY THE Xiph.Org FOUNDATION http://www.xiph.org/ *
* *
********************************************************************
function: #ifdef jail to whip a few platforms into the UNIX ideal.
********************************************************************/
#include <math.h>
#include <ogg/os_types.h>
#ifndef _V_IFDEFJAIL_H_
# define _V_IFDEFJAIL_H_
# ifdef __GNUC__
# define STIN static __inline__
# elif _WIN32
# define STIN static __inline
# endif
#else
# define STIN static
#endif
#ifndef M_PI
# define M_PI (3.1415926536f)
#endif
#ifdef _WIN32
# include <malloc.h>
# define rint(x) (floor((x)+0.5f))
# define NO_FLOAT_MATH_LIB
# define FAST_HYPOT(a, b) sqrt((a)*(a) + (b)*(b))
# define LITTLE_ENDIAN 1
# define BYTE_ORDER LITTLE_ENDIAN
#endif
#ifdef HAVE_ALLOCA_H
# include <alloca.h>
#endif
#ifdef USE_MEMORY_H
# include <memory.h>
#endif
#ifndef min
# define min(x,y) ((x)>(y)?(y):(x))
#endif
#ifndef max
# define max(x,y) ((x)<(y)?(y):(x))
#endif
#endif /* _OS_H */
+46
View File
@@ -0,0 +1,46 @@
/********************************************************************
* *
* THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. *
* *
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 *
* BY THE Xiph.Org FOUNDATION http://www.xiph.org/ *
* *
********************************************************************
function: #ifdef jail to whip a few platforms into the UNIX ideal.
********************************************************************/
#ifndef _OS_TYPES_H
#define _OS_TYPES_H
#ifdef _LOW_ACCURACY_
# define X(n) (((((n)>>22)+1)>>1) - ((((n)>>22)+1)>>9))
# define LOOKUP_T const unsigned char
#else
# define X(n) (n)
# define LOOKUP_T const ogg_int32_t
#endif
/* make it easy on the folks that want to compile the libs with a
different malloc than stdlib */
#define _ogg_malloc malloc
#define _ogg_calloc calloc
#define _ogg_realloc realloc
#define _ogg_free free
#if defined(_WIN32) && defined(__LIBRETRO__)
#include <stdint.h>
#else
#include <inttypes.h>
#endif
typedef int64_t ogg_int64_t;
typedef int32_t ogg_int32_t;
typedef uint32_t ogg_uint32_t;
typedef int16_t ogg_int16_t;
#endif /* _OS_TYPES_H */
+50
View File
@@ -0,0 +1,50 @@
/********************************************************************
* *
* THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. *
* *
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 *
* BY THE Xiph.Org FOUNDATION http://www.xiph.org/ *
* *
********************************************************************
function: registry for floor, res backends and channel mappings
********************************************************************/
#include "ivorbiscodec.h"
#include "codec_internal.h"
#include "registry.h"
#include "misc.h"
/* seems like major overkill now; the backend numbers will grow into
the infrastructure soon enough */
extern vorbis_func_floor floor0_exportbundle;
extern vorbis_func_floor floor1_exportbundle;
extern vorbis_func_residue residue0_exportbundle;
extern vorbis_func_residue residue1_exportbundle;
extern vorbis_func_residue residue2_exportbundle;
extern vorbis_func_mapping mapping0_exportbundle;
vorbis_func_floor *_floor_P[]={
&floor0_exportbundle,
&floor1_exportbundle,
};
vorbis_func_residue *_residue_P[]={
&residue0_exportbundle,
&residue1_exportbundle,
&residue2_exportbundle,
};
vorbis_func_mapping *_mapping_P[]={
&mapping0_exportbundle,
};
+40
View File
@@ -0,0 +1,40 @@
/********************************************************************
* *
* THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. *
* *
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 *
* BY THE Xiph.Org FOUNDATION http://www.xiph.org/ *
* *
********************************************************************
function: registry for time, floor, res backends and channel mappings
********************************************************************/
#ifndef _V_REG_H_
#define _V_REG_H_
#define VI_TRANSFORMB 1
#define VI_WINDOWB 1
#define VI_TIMEB 1
#define VI_FLOORB 2
#define VI_RESB 3
#define VI_MAPB 1
#include "backends.h"
#if defined(_WIN32) && defined(VORBISDLL_IMPORT)
# define EXTERN __declspec(dllimport) extern
#else
# define EXTERN extern
#endif
EXTERN vorbis_func_floor *_floor_P[];
EXTERN vorbis_func_residue *_residue_P[];
EXTERN vorbis_func_mapping *_mapping_P[];
#endif
+374
View File
@@ -0,0 +1,374 @@
/********************************************************************
* *
* THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. *
* *
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 *
* BY THE Xiph.Org FOUNDATION http://www.xiph.org/ *
* *
********************************************************************
function: residue backend 0, 1 and 2 implementation
********************************************************************/
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <ogg/ogg.h>
#include "ivorbiscodec.h"
#include "codec_internal.h"
#include "registry.h"
#include "codebook.h"
#include "misc.h"
#include "os.h"
#include "block.h"
typedef struct {
vorbis_info_residue0 *info;
int map;
int parts;
int stages;
codebook *fullbooks;
codebook *phrasebook;
codebook ***partbooks;
int partvals;
int **decodemap;
} vorbis_look_residue0;
void res0_free_info(vorbis_info_residue *i){
vorbis_info_residue0 *info=(vorbis_info_residue0 *)i;
if(info){
memset(info,0,sizeof(*info));
_ogg_free(info);
}
}
void res0_free_look(vorbis_look_residue *i){
int j;
if(i){
vorbis_look_residue0 *look=(vorbis_look_residue0 *)i;
for(j=0;j<look->parts;j++)
if(look->partbooks[j])_ogg_free(look->partbooks[j]);
_ogg_free(look->partbooks);
for(j=0;j<look->partvals;j++)
_ogg_free(look->decodemap[j]);
_ogg_free(look->decodemap);
memset(look,0,sizeof(*look));
_ogg_free(look);
}
}
static int ilog(unsigned int v){
int ret=0;
while(v){
ret++;
v>>=1;
}
return(ret);
}
static int icount(unsigned int v){
int ret=0;
while(v){
ret+=v&1;
v>>=1;
}
return(ret);
}
/* vorbis_info is for range checking */
vorbis_info_residue *res0_unpack(vorbis_info *vi,oggpack_buffer *opb){
int j,acc=0;
vorbis_info_residue0 *info=(vorbis_info_residue0 *)_ogg_calloc(1,sizeof(*info));
codec_setup_info *ci=(codec_setup_info *)vi->codec_setup;
info->begin=oggpack_read(opb,24);
info->end=oggpack_read(opb,24);
info->grouping=oggpack_read(opb,24)+1;
info->partitions=oggpack_read(opb,6)+1;
info->groupbook=oggpack_read(opb,8);
/* check for premature EOP */
if(info->groupbook<0)goto errout;
for(j=0;j<info->partitions;j++){
int cascade=oggpack_read(opb,3);
int cflag=oggpack_read(opb,1);
if(cflag<0) goto errout;
if(cflag){
int c=oggpack_read(opb,5);
if(c<0) goto errout;
cascade|=(c<<3);
}
info->secondstages[j]=cascade;
acc+=icount(cascade);
}
for(j=0;j<acc;j++){
int book=oggpack_read(opb,8);
if(book<0) goto errout;
info->booklist[j]=book;
}
if(info->groupbook>=ci->books)goto errout;
for(j=0;j<acc;j++){
if(info->booklist[j]>=ci->books)goto errout;
if(ci->book_param[info->booklist[j]]->maptype==0)goto errout;
}
/* verify the phrasebook is not specifying an impossible or
inconsistent partitioning scheme. */
/* modify the phrasebook ranging check from r16327; an early beta
encoder had a bug where it used an oversized phrasebook by
accident. These files should continue to be playable, but don't
allow an exploit */
{
int entries = ci->book_param[info->groupbook]->entries;
int dim = ci->book_param[info->groupbook]->dim;
int partvals = 1;
if (dim<1) goto errout;
while(dim>0){
partvals *= info->partitions;
if(partvals > entries) goto errout;
dim--;
}
info->partvals = partvals;
}
return(info);
errout:
res0_free_info(info);
return(NULL);
}
vorbis_look_residue *res0_look(vorbis_dsp_state *vd,vorbis_info_mode *vm,
vorbis_info_residue *vr){
vorbis_info_residue0 *info=(vorbis_info_residue0 *)vr;
vorbis_look_residue0 *look=(vorbis_look_residue0 *)_ogg_calloc(1,sizeof(*look));
codec_setup_info *ci=(codec_setup_info *)vd->vi->codec_setup;
int j,k,acc=0;
int dim;
int maxstage=0;
look->info=info;
look->map=vm->mapping;
look->parts=info->partitions;
look->fullbooks=ci->fullbooks;
look->phrasebook=ci->fullbooks+info->groupbook;
dim=look->phrasebook->dim;
look->partbooks=(codebook ***)_ogg_calloc(look->parts,sizeof(*look->partbooks));
for(j=0;j<look->parts;j++){
int stages=ilog(info->secondstages[j]);
if(stages){
if(stages>maxstage)maxstage=stages;
look->partbooks[j]=(codebook **)_ogg_calloc(stages,sizeof(*look->partbooks[j]));
for(k=0;k<stages;k++)
if(info->secondstages[j]&(1<<k)){
look->partbooks[j][k]=ci->fullbooks+info->booklist[acc++];
#ifdef TRAIN_RES
look->training_data[k][j]=calloc(look->partbooks[j][k]->entries,
sizeof(***look->training_data));
#endif
}
}
}
look->partvals=look->parts;
for(j=1;j<dim;j++)look->partvals*=look->parts;
look->stages=maxstage;
look->decodemap=(int **)_ogg_malloc(look->partvals*sizeof(*look->decodemap));
for(j=0;j<look->partvals;j++){
long val=j;
long mult=look->partvals/look->parts;
look->decodemap[j]=(int *)_ogg_malloc(dim*sizeof(*look->decodemap[j]));
for(k=0;k<dim;k++){
long deco=val/mult;
val-=deco*mult;
mult/=look->parts;
look->decodemap[j][k]=deco;
}
}
return(look);
}
/* a truncated packet here just means 'stop working'; it's not an error */
static int _01inverse(vorbis_block *vb,vorbis_look_residue *vl,
ogg_int32_t **in,int ch,
long (*decodepart)(codebook *, ogg_int32_t *,
oggpack_buffer *,int,int)){
long i,j,k,l,s;
vorbis_look_residue0 *look=(vorbis_look_residue0 *)vl;
vorbis_info_residue0 *info=look->info;
/* move all this setup out later */
int samples_per_partition=info->grouping;
int partitions_per_word=look->phrasebook->dim;
int max=vb->pcmend>>1;
int end=(info->end<max?info->end:max);
int n=end-info->begin;
if(n>0){
int partvals=n/samples_per_partition;
int partwords=(partvals+partitions_per_word-1)/partitions_per_word;
int ***partword=(int ***)alloca(ch*sizeof(*partword));
for(j=0;j<ch;j++)
partword[j]=(int **)_vorbis_block_alloc(vb,partwords*sizeof(*partword[j]));
for(s=0;s<look->stages;s++){
/* each loop decodes on partition codeword containing
partitions_pre_word partitions */
for(i=0,l=0;i<partvals;l++){
if(s==0){
/* fetch the partition word for each channel */
for(j=0;j<ch;j++){
int temp=vorbis_book_decode(look->phrasebook,&vb->opb);
if(temp==-1 || temp>=info->partvals)goto eopbreak;
partword[j][l]=look->decodemap[temp];
if(partword[j][l]==NULL)goto errout;
}
}
/* now we decode residual values for the partitions */
for(k=0;k<partitions_per_word && i<partvals;k++,i++)
for(j=0;j<ch;j++){
long offset=info->begin+i*samples_per_partition;
if(info->secondstages[partword[j][l][k]]&(1<<s)){
codebook *stagebook=look->partbooks[partword[j][l][k]][s];
if(stagebook){
if(decodepart(stagebook,in[j]+offset,&vb->opb,
samples_per_partition,-8)==-1)goto eopbreak;
}
}
}
}
}
}
errout:
eopbreak:
return(0);
}
int res0_inverse(vorbis_block *vb,vorbis_look_residue *vl,
ogg_int32_t **in,int *nonzero,int ch){
int i,used=0;
for(i=0;i<ch;i++)
if(nonzero[i])
in[used++]=in[i];
if(used)
return(_01inverse(vb,vl,in,used,vorbis_book_decodevs_add));
else
return(0);
}
int res1_inverse(vorbis_block *vb,vorbis_look_residue *vl,
ogg_int32_t **in,int *nonzero,int ch){
int i,used=0;
for(i=0;i<ch;i++)
if(nonzero[i])
in[used++]=in[i];
if(used)
return(_01inverse(vb,vl,in,used,vorbis_book_decodev_add));
else
return(0);
}
/* duplicate code here as speed is somewhat more important */
int res2_inverse(vorbis_block *vb,vorbis_look_residue *vl,
ogg_int32_t **in,int *nonzero,int ch){
long i,k,l,s;
vorbis_look_residue0 *look=(vorbis_look_residue0 *)vl;
vorbis_info_residue0 *info=look->info;
/* move all this setup out later */
int samples_per_partition=info->grouping;
int partitions_per_word=look->phrasebook->dim;
int max=(vb->pcmend*ch)>>1;
int end=(info->end<max?info->end:max);
int n=end-info->begin;
if(n>0){
int partvals=n/samples_per_partition;
int partwords=(partvals+partitions_per_word-1)/partitions_per_word;
int **partword=(int **)_vorbis_block_alloc(vb,partwords*sizeof(*partword));
int beginoff=info->begin/ch;
for(i=0;i<ch;i++)if(nonzero[i])break;
if(i==ch)return(0); /* no nonzero vectors */
samples_per_partition/=ch;
for(s=0;s<look->stages;s++){
for(i=0,l=0;i<partvals;l++){
if(s==0){
/* fetch the partition word */
int temp=vorbis_book_decode(look->phrasebook,&vb->opb);
if(temp==-1 || temp>=info->partvals)goto eopbreak;
partword[l]=look->decodemap[temp];
if(partword[l]==NULL)goto errout;
}
/* now we decode residual values for the partitions */
for(k=0;k<partitions_per_word && i<partvals;k++,i++)
if(info->secondstages[partword[l][k]]&(1<<s)){
codebook *stagebook=look->partbooks[partword[l][k]][s];
if(stagebook){
if(vorbis_book_decodevv_add(stagebook,in,
i*samples_per_partition+beginoff,ch,
&vb->opb,
samples_per_partition,-8)==-1)
goto eopbreak;
}
}
}
}
}
errout:
eopbreak:
return(0);
}
vorbis_func_residue residue0_exportbundle={
&res0_unpack,
&res0_look,
&res0_free_info,
&res0_free_look,
&res0_inverse
};
vorbis_func_residue residue1_exportbundle={
&res0_unpack,
&res0_look,
&res0_free_info,
&res0_free_look,
&res1_inverse
};
vorbis_func_residue residue2_exportbundle={
&res0_unpack,
&res0_look,
&res0_free_info,
&res0_free_look,
&res2_inverse
};
+453
View File
@@ -0,0 +1,453 @@
/********************************************************************
* *
* THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. *
* *
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 *
* BY THE Xiph.Org FOUNDATION http://www.xiph.org/ *
* *
********************************************************************
function: basic shared codebook operations
********************************************************************/
#include <stdlib.h>
#include <limits.h>
#include <math.h>
#include <string.h>
#include <ogg/ogg.h>
#include "misc.h"
#include "ivorbiscodec.h"
#include "codebook.h"
/**** pack/unpack helpers ******************************************/
int _ilog(unsigned int v){
int ret=0;
while(v){
ret++;
v>>=1;
}
return(ret);
}
/* 32 bit float (not IEEE; nonnormalized mantissa +
biased exponent) : neeeeeee eeemmmmm mmmmmmmm mmmmmmmm
Why not IEEE? It's just not that important here. */
#define VQ_FEXP 10
#define VQ_FMAN 21
#define VQ_FEXP_BIAS 768 /* bias toward values smaller than 1. */
static ogg_int32_t _float32_unpack(long val,int *point){
long mant=val&0x1fffff;
int sign=val&0x80000000;
long exp =(val&0x7fe00000L)>>VQ_FMAN;
exp-=(VQ_FMAN-1)+VQ_FEXP_BIAS;
if(mant){
while(!(mant&0x40000000)){
mant<<=1;
exp-=1;
}
if(sign)mant= -mant;
}else{
sign=0;
exp=-9999;
}
*point=exp;
return mant;
}
/* given a list of word lengths, generate a list of codewords. Works
for length ordered or unordered, always assigns the lowest valued
codewords first. Extended to handle unused entries (length 0) */
ogg_uint32_t *_make_words(long *l,long n,long sparsecount){
long i,j,count=0;
ogg_uint32_t marker[33];
ogg_uint32_t *r=(ogg_uint32_t *)_ogg_malloc((sparsecount?sparsecount:n)*sizeof(*r));
memset(marker,0,sizeof(marker));
for(i=0;i<n;i++){
long length=l[i];
if(length>0){
ogg_uint32_t entry=marker[length];
/* when we claim a node for an entry, we also claim the nodes
below it (pruning off the imagined tree that may have dangled
from it) as well as blocking the use of any nodes directly
above for leaves */
/* update ourself */
if(length<32 && (entry>>length)){
/* error condition; the lengths must specify an overpopulated tree */
_ogg_free(r);
return(NULL);
}
r[count++]=entry;
/* Look to see if the next shorter marker points to the node
above. if so, update it and repeat. */
{
for(j=length;j>0;j--){
if(marker[j]&1){
/* have to jump branches */
if(j==1)
marker[1]++;
else
marker[j]=marker[j-1]<<1;
break; /* invariant says next upper marker would already
have been moved if it was on the same path */
}
marker[j]++;
}
}
/* prune the tree; the implicit invariant says all the longer
markers were dangling from our just-taken node. Dangle them
from our *new* node. */
for(j=length+1;j<33;j++)
if((marker[j]>>1) == entry){
entry=marker[j];
marker[j]=marker[j-1]<<1;
}else
break;
}else
if(sparsecount==0)count++;
}
/* sanity check the huffman tree; an underpopulated tree must be
rejected. The only exception is the one-node pseudo-nil tree,
which appears to be underpopulated because the tree doesn't
really exist; there's only one possible 'codeword' or zero bits,
but the above tree-gen code doesn't mark that. */
if(sparsecount != 1){
for(i=1;i<33;i++)
if(marker[i] & (0xffffffffUL>>(32-i))){
_ogg_free(r);
return(NULL);
}
}
/* bitreverse the words because our bitwise packer/unpacker is LSb
endian */
for(i=0,count=0;i<n;i++){
ogg_uint32_t temp=0;
for(j=0;j<l[i];j++){
temp<<=1;
temp|=(r[count]>>j)&1;
}
if(sparsecount){
if(l[i])
r[count++]=temp;
}else
r[count++]=temp;
}
return(r);
}
/* there might be a straightforward one-line way to do the below
that's portable and totally safe against roundoff, but I haven't
thought of it. Therefore, we opt on the side of caution */
long _book_maptype1_quantvals(const static_codebook *b){
/* get us a starting hint, we'll polish it below */
int bits=_ilog(b->entries);
int vals=b->entries>>((bits-1)*(b->dim-1)/b->dim);
if(b->entries<1){
return(0);
}
while(1){
long acc=1;
long acc1=1;
int i;
for(i=0;i<b->dim;i++){
if(b->entries/vals<acc)break;
acc*=vals;
if(LONG_MAX/(vals+1)<acc1)acc1=LONG_MAX;
else acc1*=vals+1;
}
if(i>=b->dim && acc<=b->entries && acc1>b->entries){
return(vals);
}else{
if(i<b->dim || acc>b->entries){
vals--;
}else{
vals++;
}
}
}
}
/* different than what _book_unquantize does for mainline:
we repack the book in a fixed point format that shares the same
binary point. Upon first use, we can shift point if needed */
/* we need to deal with two map types: in map type 1, the values are
generated algorithmically (each column of the vector counts through
the values in the quant vector). in map type 2, all the values came
in in an explicit list. Both value lists must be unpacked */
ogg_int32_t *_book_unquantize(const static_codebook *b,int n,int *sparsemap,
int *maxpoint){
long j,k,count=0;
if(b->maptype==1 || b->maptype==2){
int quantvals;
int minpoint,delpoint;
ogg_int32_t mindel=_float32_unpack(b->q_min,&minpoint);
ogg_int32_t delta=_float32_unpack(b->q_delta,&delpoint);
ogg_int32_t *r=(ogg_int32_t *)_ogg_calloc(n*b->dim,sizeof(*r));
int *rp=(int *)_ogg_calloc(n*b->dim,sizeof(*rp));
*maxpoint=minpoint;
/* maptype 1 and 2 both use a quantized value vector, but
different sizes */
switch(b->maptype){
case 1:
/* most of the time, entries%dimensions == 0, but we need to be
well defined. We define that the possible vales at each
scalar is values == entries/dim. If entries%dim != 0, we'll
have 'too few' values (values*dim<entries), which means that
we'll have 'left over' entries; left over entries use zeroed
values (and are wasted). So don't generate codebooks like
that */
quantvals=_book_maptype1_quantvals(b);
for(j=0;j<b->entries;j++){
if((sparsemap && b->lengthlist[j]) || !sparsemap){
ogg_int32_t last=0;
int lastpoint=0;
int indexdiv=1;
for(k=0;k<b->dim;k++){
int index= (j/indexdiv)%quantvals;
ogg_int32_t point=0;
int val=VFLOAT_MULTI(delta,delpoint,
labs(b->quantlist[index]),&point);
val=VFLOAT_ADD(mindel,minpoint,val,point,&point);
val=VFLOAT_ADD(last,lastpoint,val,point,&point);
if(b->q_sequencep){
last=val;
lastpoint=point;
}
if(sparsemap){
r[sparsemap[count]*b->dim+k]=val;
rp[sparsemap[count]*b->dim+k]=point;
}else{
r[count*b->dim+k]=val;
rp[count*b->dim+k]=point;
}
if(*maxpoint<point)*maxpoint=point;
indexdiv*=quantvals;
}
count++;
}
}
break;
case 2:
for(j=0;j<b->entries;j++){
if((sparsemap && b->lengthlist[j]) || !sparsemap){
ogg_int32_t last=0;
int lastpoint=0;
for(k=0;k<b->dim;k++){
ogg_int32_t point=0;
int val=VFLOAT_MULTI(delta,delpoint,
labs(b->quantlist[j*b->dim+k]),&point);
val=VFLOAT_ADD(mindel,minpoint,val,point,&point);
val=VFLOAT_ADD(last,lastpoint,val,point,&point);
if(b->q_sequencep){
last=val;
lastpoint=point;
}
if(sparsemap){
r[sparsemap[count]*b->dim+k]=val;
rp[sparsemap[count]*b->dim+k]=point;
}else{
r[count*b->dim+k]=val;
rp[count*b->dim+k]=point;
}
if(*maxpoint<point)*maxpoint=point;
}
count++;
}
}
break;
}
for(j=0;j<n*b->dim;j++)
if(rp[j]<*maxpoint)
r[j]>>=*maxpoint-rp[j];
_ogg_free(rp);
return(r);
}
return(NULL);
}
void vorbis_staticbook_destroy(static_codebook *b){
if(b->quantlist)_ogg_free(b->quantlist);
if(b->lengthlist)_ogg_free(b->lengthlist);
memset(b,0,sizeof(*b));
_ogg_free(b);
}
void vorbis_book_clear(codebook *b){
/* static book is not cleared; we're likely called on the lookup and
the static codebook belongs to the info struct */
if(b->valuelist)_ogg_free(b->valuelist);
if(b->codelist)_ogg_free(b->codelist);
if(b->dec_index)_ogg_free(b->dec_index);
if(b->dec_codelengths)_ogg_free(b->dec_codelengths);
if(b->dec_firsttable)_ogg_free(b->dec_firsttable);
memset(b,0,sizeof(*b));
}
static ogg_uint32_t bitreverse(ogg_uint32_t x){
x= ((x>>16)&0x0000ffffUL) | ((x<<16)&0xffff0000UL);
x= ((x>> 8)&0x00ff00ffUL) | ((x<< 8)&0xff00ff00UL);
x= ((x>> 4)&0x0f0f0f0fUL) | ((x<< 4)&0xf0f0f0f0UL);
x= ((x>> 2)&0x33333333UL) | ((x<< 2)&0xccccccccUL);
return((x>> 1)&0x55555555UL) | ((x<< 1)&0xaaaaaaaaUL);
}
static int sort32a(const void *a,const void *b){
return (**(ogg_uint32_t **)a>**(ogg_uint32_t **)b)-
(**(ogg_uint32_t **)a<**(ogg_uint32_t **)b);
}
/* decode codebook arrangement is more heavily optimized than encode */
int vorbis_book_init_decode(codebook *c,const static_codebook *s){
int i,j,n=0,tabn;
int *sortindex;
memset(c,0,sizeof(*c));
/* count actually used entries */
for(i=0;i<s->entries;i++)
if(s->lengthlist[i]>0)
n++;
c->entries=s->entries;
c->used_entries=n;
c->dim=s->dim;
if(n>0){
/* two different remappings go on here.
First, we collapse the likely sparse codebook down only to
actually represented values/words. This collapsing needs to be
indexed as map-valueless books are used to encode original entry
positions as integers.
Second, we reorder all vectors, including the entry index above,
by sorted bitreversed codeword to allow treeless decode. */
/* perform sort */
ogg_uint32_t *codes=_make_words(s->lengthlist,s->entries,c->used_entries);
ogg_uint32_t **codep=(ogg_uint32_t **)alloca(sizeof(*codep)*n);
if(codes==NULL)goto err_out;
for(i=0;i<n;i++){
codes[i]=bitreverse(codes[i]);
codep[i]=codes+i;
}
qsort(codep,n,sizeof(*codep),sort32a);
sortindex=(int *)alloca(n*sizeof(*sortindex));
c->codelist=(ogg_uint32_t *)_ogg_malloc(n*sizeof(*c->codelist));
/* the index is a reverse index */
for(i=0;i<n;i++){
int position=codep[i]-codes;
sortindex[position]=i;
}
for(i=0;i<n;i++)
c->codelist[sortindex[i]]=codes[i];
_ogg_free(codes);
c->valuelist=_book_unquantize(s,n,sortindex,&c->binarypoint);
c->dec_index=(int *)_ogg_malloc(n*sizeof(*c->dec_index));
for(n=0,i=0;i<s->entries;i++)
if(s->lengthlist[i]>0)
c->dec_index[sortindex[n++]]=i;
c->dec_codelengths=(char *)_ogg_malloc(n*sizeof(*c->dec_codelengths));
for(n=0,i=0;i<s->entries;i++)
if(s->lengthlist[i]>0)
c->dec_codelengths[sortindex[n++]]=s->lengthlist[i];
c->dec_firsttablen=_ilog(c->used_entries)-4; /* this is magic */
if(c->dec_firsttablen<5)c->dec_firsttablen=5;
if(c->dec_firsttablen>8)c->dec_firsttablen=8;
tabn=1<<c->dec_firsttablen;
c->dec_firsttable=(ogg_uint32_t *)_ogg_calloc(tabn,sizeof(*c->dec_firsttable));
c->dec_maxlength=0;
for(i=0;i<n;i++){
if(c->dec_maxlength<c->dec_codelengths[i])
c->dec_maxlength=c->dec_codelengths[i];
if(c->dec_codelengths[i]<=c->dec_firsttablen){
ogg_uint32_t orig=bitreverse(c->codelist[i]);
for(j=0;j<(1<<(c->dec_firsttablen-c->dec_codelengths[i]));j++)
c->dec_firsttable[orig|(j<<c->dec_codelengths[i])]=i+1;
}
}
/* now fill in 'unused' entries in the firsttable with hi/lo search
hints for the non-direct-hits */
{
ogg_uint32_t mask=0xfffffffeUL<<(31-c->dec_firsttablen);
long lo=0,hi=0;
for(i=0;i<tabn;i++){
ogg_uint32_t word=((ogg_uint32_t)i<<(32-c->dec_firsttablen));
if(c->dec_firsttable[bitreverse(word)]==0){
while((lo+1)<n && c->codelist[lo+1]<=word)lo++;
while( hi<n && word>=(c->codelist[hi]&mask))hi++;
/* we only actually have 15 bits per hint to play with here.
In order to overflow gracefully (nothing breaks, efficiency
just drops), encode as the difference from the extremes. */
{
unsigned long loval=lo;
unsigned long hival=n-hi;
if(loval>0x7fff)loval=0x7fff;
if(hival>0x7fff)hival=0x7fff;
c->dec_firsttable[bitreverse(word)]=
0x80000000UL | (loval<<15) | hival;
}
}
}
}
}
return(0);
err_out:
vorbis_book_clear(c);
return(-1);
}
+131
View File
@@ -0,0 +1,131 @@
/********************************************************************
* *
* THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. *
* *
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2003 *
* BY THE Xiph.Org FOUNDATION http://www.xiph.org/ *
* *
********************************************************************
function: single-block PCM synthesis
last mod: $Id: synthesis.c,v 1.4 2003/03/29 03:07:21 xiphmont Exp $
********************************************************************/
#include <stdio.h>
#include <ogg/ogg.h>
#include "ivorbiscodec.h"
#include "codec_internal.h"
#include "registry.h"
#include "misc.h"
#include "block.h"
static int _vorbis_synthesis1(vorbis_block *vb,ogg_packet *op,int decodep){
vorbis_dsp_state *vd= vb ? vb->vd : 0;
private_state *b= vd ? (private_state *)vd->backend_state: 0;
vorbis_info *vi= vd ? vd->vi : 0;
codec_setup_info *ci= vi ? (codec_setup_info *)vi->codec_setup : 0;
oggpack_buffer *opb=vb ? &vb->opb : 0;
int type,mode,i;
if (!vd || !b || !vi || !ci || !opb) {
return OV_EBADPACKET;
}
/* first things first. Make sure decode is ready */
_vorbis_block_ripcord(vb);
oggpack_readinit(opb,op->packet,op->bytes);
/* Check the packet type */
if(oggpack_read(opb,1)!=0){
/* Oops. This is not an audio data packet */
return(OV_ENOTAUDIO);
}
/* read our mode and pre/post windowsize */
mode=oggpack_read(opb,b->modebits);
if(mode==-1)return(OV_EBADPACKET);
vb->mode=mode;
if(!ci->mode_param[mode]){
return(OV_EBADPACKET);
}
vb->W=ci->mode_param[mode]->blockflag;
if(vb->W){
vb->lW=oggpack_read(opb,1);
vb->nW=oggpack_read(opb,1);
if(vb->nW==-1) return(OV_EBADPACKET);
}else{
vb->lW=0;
vb->nW=0;
}
/* more setup */
vb->granulepos=op->granulepos;
vb->sequence=op->packetno; /* first block is third packet */
vb->eofflag=op->e_o_s;
if(decodep){
/* alloc pcm passback storage */
vb->pcmend=ci->blocksizes[vb->W];
vb->pcm=(ogg_int32_t **)_vorbis_block_alloc(vb,sizeof(*vb->pcm)*vi->channels);
for(i=0;i<vi->channels;i++)
vb->pcm[i]=(ogg_int32_t *)_vorbis_block_alloc(vb,vb->pcmend*sizeof(*vb->pcm[i]));
/* unpack_header enforces range checking */
type=ci->map_type[ci->mode_param[mode]->mapping];
return(_mapping_P[type]->inverse(vb,b->mode[mode]));
}else{
/* no pcm */
vb->pcmend=0;
vb->pcm=NULL;
return(0);
}
}
int vorbis_synthesis(vorbis_block *vb,ogg_packet *op){
return _vorbis_synthesis1(vb,op,1);
}
/* used to track pcm position without actually performing decode.
Useful for sequential 'fast forward' */
int vorbis_synthesis_trackonly(vorbis_block *vb,ogg_packet *op){
return _vorbis_synthesis1(vb,op,0);
}
long vorbis_packet_blocksize(vorbis_info *vi,ogg_packet *op){
codec_setup_info *ci=(codec_setup_info *)vi->codec_setup;
oggpack_buffer opb;
int mode;
oggpack_readinit(&opb,op->packet,op->bytes);
/* Check the packet type */
if(oggpack_read(&opb,1)!=0){
/* Oops. This is not an audio data packet */
return(OV_ENOTAUDIO);
}
{
int modebits=0;
int v=ci->modes;
while(v>1){
modebits++;
v>>=1;
}
/* read our mode and pre/post windowsize */
mode=oggpack_read(&opb,modebits);
}
if(mode==-1 || !ci->mode_param[mode])return(OV_EBADPACKET);
return(ci->blocksizes[ci->mode_param[mode]->blockflag]);
}
File diff suppressed because it is too large. Load diff
+83
View File
@@ -0,0 +1,83 @@
/********************************************************************
* *
* THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. *
* *
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 *
* BY THE Xiph.Org FOUNDATION http://www.xiph.org/ *
* *
********************************************************************
function: window functions
********************************************************************/
#include <stdlib.h>
#include <math.h>
#include "misc.h"
#include "window.h"
#include "window_lookup.h"
const void *_vorbis_window(int type, int left){
switch(type){
case 0:
switch(left){
case 32:
return vwin64;
case 64:
return vwin128;
case 128:
return vwin256;
case 256:
return vwin512;
case 512:
return vwin1024;
case 1024:
return vwin2048;
case 2048:
return vwin4096;
case 4096:
return vwin8192;
default:
return(0);
}
break;
default:
return(0);
}
}
void _vorbis_apply_window(ogg_int32_t *d,const void *window_p[2],
long *blocksizes,
int lW,int W,int nW){
LOOKUP_T *window[2]={window_p[0],window_p[1]};
long n=blocksizes[W];
long ln=blocksizes[lW];
long rn=blocksizes[nW];
long leftbegin=n/4-ln/4;
long leftend=leftbegin+ln/2;
long rightbegin=n/2+n/4-rn/4;
long rightend=rightbegin+rn/2;
int i,p;
for(i=0;i<leftbegin;i++)
d[i]=0;
for(p=0;i<leftend;i++,p++)
d[i]=MULT31(d[i],window[lW][p]);
for(i=rightbegin,p=rn/2-1;i<rightend;i++,p--)
d[i]=MULT31(d[i],window[nW][p]);
for(;i<n;i++)
d[i]=0;
}
+27
View File
@@ -0,0 +1,27 @@
/********************************************************************
* *
* THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. *
* *
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 *
* BY THE Xiph.Org FOUNDATION http://www.xiph.org/ *
* *
********************************************************************
function: window functions
********************************************************************/
#ifndef _V_WINDOW_
#define _V_WINDOW_
extern const void *_vorbis_window(int type,int left);
extern void _vorbis_apply_window(ogg_int32_t *d,const void *window[2],
long *blocksizes,
int lW,int W,int nW);
#endif
File diff suppressed because it is too large. Load diff
+8 -6
View File
@@ -630,6 +630,8 @@ void lprintf(const char *fmt, ...)
/* libretro */
bool libretro_supports_bitmasks = false;
#define EXTENSIONS "bin|gen|smd|md|32x|cue|iso|chd|m3u|sms|gg|sg|sc|68k|sgd|pco|vgm|vgz"
void retro_set_environment(retro_environment_t cb)
{
bool option_categories_supported;
@@ -639,7 +641,7 @@ void retro_set_environment(retro_environment_t cb)
static const struct retro_system_content_info_override content_overrides[] = {
{
"bin|gen|smd|md|32x|sms|gg|sg|sc|68k|sgd|pco", /* extensions */
EXTENSIONS,
#if defined(LOW_MEMORY)
true, /* need_fullpath */
#else
@@ -685,7 +687,7 @@ void retro_get_system_info(struct retro_system_info *info)
memset(info, 0, sizeof(*info));
info->library_name = "PicoDrive";
info->library_version = VERSION;
info->valid_extensions = "bin|gen|smd|md|32x|cue|iso|chd|sms|gg|sg|sc|m3u|68k|sgd|pco";
info->valid_extensions = EXTENSIONS;
info->need_fullpath = true;
}
@@ -1997,12 +1999,12 @@ static void update_variables(bool first_run)
#endif
var.value = NULL;
var.key = "picodrive_dacnoise";
var.key = "picodrive_fmchip";
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) {
if (strcmp(var.value, "enabled") == 0)
PicoIn.opt |= POPT_EN_FM_DAC;
if (strcmp(var.value, "ym2612") == 0)
PicoIn.opt |= POPT_FM_YM2612;
else
PicoIn.opt &= ~POPT_EN_FM_DAC;
PicoIn.opt &= ~POPT_FM_YM2612;
}
var.value = NULL;
+6 -6
View File
@@ -64,7 +64,7 @@ struct retro_core_option_v2_category option_cats_us[] = {
{
"audio",
"Audio",
"Configure sample rate / emulated audio devices / low pass filter / DAC noise."
"Configure sample rate / emulated audio devices / low pass filter / FM chip type."
},
{
"input",
@@ -264,15 +264,15 @@ struct retro_core_option_v2_definition option_defs_us[] = {
"off"
},
{
"picodrive_dacnoise",
"Mega Drive FM DAC noise",
"picodrive_fmchip",
"Mega Drive FM chip type",
NULL,
"Enable emulation of YM2612 DAC noise. This option generates a distortion which existed on most Model 1 Mega Drive/Genesis, but not on newer models.",
"Select the Mega Drive/Genesis FM chip type. Model 1 Mega Drive/Genesis mostly used YM2612, which produced a distinct distortion. YM3438 was used in model 2 consoles.",
NULL,
"audio",
{
{ "off", "disabled" },
{ "on", "enabled" },
{ "ym2612", "YM2612" },
{ "ym3438", "YM3438" },
{ NULL, NULL },
},
"off"
+1 -1
View File
@@ -193,7 +193,7 @@ static void LoadROM(const char *cmdpath)
rompath[sizeof(rompath) - 1] = 0;
strncpy(rompath, rom_fname_loaded, sizeof(rompath) - 1);
of.lStructSize = sizeof(of);
of.lpstrFilter = "ROMs, CD images\0*.smd;*.bin;*.gen;*.zip;*.32x;*.sms;*.iso;*.cso;*.cue\0"
of.lpstrFilter = "ROMs, CD images\0*.smd;*.bin;*.gen;*.zip;*.32x;*.sms;*.iso;*.cso;*.cue;*.vgm;*.vgz\0"
"whatever\0*.*\0";
of.lpstrFile = rompath;
of.nMaxFile = MAX_PATH;