mirror of
https://github.com/RetroDECK/Supermodel.git
synced 2024-11-22 13:55:38 +00:00
- Improved 68K interface. Now supports context switching.
- CSoundBoard is not derived from CBus. - Optimized sound board memory handlers (now using switch statements). - Added DSB emulation (based on R. Belmont's M1 source code). - Improved ROM loading: only unique ROMs (those not shared amongst games) are used to identify games. The ROM loader will no longer get confused as easily. - General cleanup here and there, removed unused Render.h file.
This commit is contained in:
parent
62f695cc96
commit
ddd6fa92ef
|
@ -119,11 +119,11 @@ CC = "$(VC_BIN)\cl.exe"
|
||||||
LD = "$(VC_BIN)\link.exe"
|
LD = "$(VC_BIN)\link.exe"
|
||||||
COMPILER_FLAGS = /I "$(SDL_INCLUDEPATH)" /I "$(ZLIB_INCLUDEPATH)" /I "$(DIRECTX_INCLUDEPATH)" /I "Src" /I "Src\\OSD" /I "Src\\OSD\\SDL" \
|
COMPILER_FLAGS = /I "$(SDL_INCLUDEPATH)" /I "$(ZLIB_INCLUDEPATH)" /I "$(DIRECTX_INCLUDEPATH)" /I "Src" /I "Src\\OSD" /I "Src\\OSD\\SDL" \
|
||||||
/I "Src\\OSD\\Windows" /Ox /D "SUPERMODEL_WIN32" /D "GLEW_STATIC" /D "_MBCS" /D "_CRT_SECURE_NO_WARNINGS" /MT /Gy /W3 /nologo /c /Zi /GL \
|
/I "Src\\OSD\\Windows" /Ox /D "SUPERMODEL_WIN32" /D "GLEW_STATIC" /D "_MBCS" /D "_CRT_SECURE_NO_WARNINGS" /MT /Gy /W3 /nologo /c /Zi /GL \
|
||||||
/D "DEBUG" /DEBUG
|
/DEBUG /Zi #/D "DEBUG" /DEBUG
|
||||||
CFLAGS = $(COMPILER_FLAGS) /TC
|
CFLAGS = $(COMPILER_FLAGS) /TC
|
||||||
CPPFLAGS = $(COMPILER_FLAGS) /TP /EHsc
|
CPPFLAGS = $(COMPILER_FLAGS) /TP /EHsc
|
||||||
LFLAGS = /MACHINE:$(ARCH) $(ARCH_LIBS) /LIBPATH:"$(SDL_LIBPATH)" /LIBPATH:"$(ZLIB_LIBPATH)" /LIBPATH:"$(DIRECTX_LIBPATH)" /OUT:"$(OUTFILE)" \
|
LFLAGS = /MACHINE:$(ARCH) $(ARCH_LIBS) /LIBPATH:"$(SDL_LIBPATH)" /LIBPATH:"$(ZLIB_LIBPATH)" /LIBPATH:"$(DIRECTX_LIBPATH)" /OUT:"$(OUTFILE)" \
|
||||||
/MANIFEST:NO /SUBSYSTEM:CONSOLE /NOLOGO /OPT:REF /OPT:ICF /DYNAMICBASE /NXCOMPAT /LTCG #/DEBUG
|
/MANIFEST:NO /SUBSYSTEM:CONSOLE /NOLOGO /OPT:REF /OPT:ICF /DYNAMICBASE /NXCOMPAT /LTCG /DEBUG
|
||||||
OBJ_LIBS = kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib \
|
OBJ_LIBS = kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib \
|
||||||
odbc32.lib odbccp32.lib OpenGL32.lib GLu32.lib SDL.lib SDLmain.lib zlib.lib dinput8.lib dxguid.lib
|
odbc32.lib odbccp32.lib OpenGL32.lib GLu32.lib SDL.lib SDLmain.lib zlib.lib dinput8.lib dxguid.lib
|
||||||
|
|
||||||
|
@ -160,10 +160,15 @@ OBJ = $(OBJ_DIR)/PPCDisasm.obj $(OBJ_DIR)/Games.obj $(OBJ_DIR)/INIFile.obj $(OBJ
|
||||||
$(OBJ_DIR)/ROMLoad.obj $(OBJ_DIR)/unzip.obj $(OBJ_DIR)/ioapi.obj $(OBJ_DIR)/Error.obj $(OBJ_DIR)/glew.obj $(OBJ_DIR)/Shader.obj \
|
$(OBJ_DIR)/ROMLoad.obj $(OBJ_DIR)/unzip.obj $(OBJ_DIR)/ioapi.obj $(OBJ_DIR)/Error.obj $(OBJ_DIR)/glew.obj $(OBJ_DIR)/Shader.obj \
|
||||||
$(OBJ_DIR)/Real3D.obj $(OBJ_DIR)/Render3D.obj $(OBJ_DIR)/Models.obj $(OBJ_DIR)/Render2D.obj $(OBJ_DIR)/TileGen.obj \
|
$(OBJ_DIR)/Real3D.obj $(OBJ_DIR)/Render3D.obj $(OBJ_DIR)/Models.obj $(OBJ_DIR)/Render2D.obj $(OBJ_DIR)/TileGen.obj \
|
||||||
$(OBJ_DIR)/Model3.obj $(OBJ_DIR)/ppc.obj $(OBJ_DIR)/Main.obj $(OBJ_DIR)/Audio.obj $(OBJ_DIR)/Thread.obj $(OBJ_DIR)/SoundBoard.obj \
|
$(OBJ_DIR)/Model3.obj $(OBJ_DIR)/ppc.obj $(OBJ_DIR)/Main.obj $(OBJ_DIR)/Audio.obj $(OBJ_DIR)/Thread.obj $(OBJ_DIR)/SoundBoard.obj \
|
||||||
$(OBJ_DIR)/SCSP.obj $(OBJ_DIR)/SCSPDSP.obj $(OBJ_DIR)/M68K.obj $(OBJ_DIR)/m68kcpu.obj $(OBJ_DIR)/m68kopnz.obj $(OBJ_DIR)/m68kopdm.obj \
|
$(OBJ_DIR)/SCSP.obj $(OBJ_DIR)/SCSPDSP.obj $(OBJ_DIR)/68K.obj $(OBJ_DIR)/m68kcpu.obj $(OBJ_DIR)/m68kopnz.obj $(OBJ_DIR)/m68kopdm.obj \
|
||||||
$(OBJ_DIR)/m68kopac.obj $(OBJ_DIR)/m68kops.obj $(OBJ_DIR)/IRQ.obj $(OBJ_DIR)/53C810.obj $(OBJ_DIR)/PCI.obj $(OBJ_DIR)/RTC72421.obj \
|
$(OBJ_DIR)/m68kopac.obj $(OBJ_DIR)/m68kops.obj $(OBJ_DIR)/DSB.obj $(OBJ_DIR)/Z80.obj \
|
||||||
|
$(OBJ_DIR)/IRQ.obj $(OBJ_DIR)/53C810.obj $(OBJ_DIR)/PCI.obj $(OBJ_DIR)/RTC72421.obj \
|
||||||
$(OBJ_DIR)/MPC10x.obj $(OBJ_DIR)/Input.obj $(OBJ_DIR)/Inputs.obj $(OBJ_DIR)/InputSource.obj $(OBJ_DIR)/InputSystem.obj \
|
$(OBJ_DIR)/MPC10x.obj $(OBJ_DIR)/Input.obj $(OBJ_DIR)/Inputs.obj $(OBJ_DIR)/InputSource.obj $(OBJ_DIR)/InputSystem.obj \
|
||||||
$(OBJ_DIR)/InputTypes.obj $(OBJ_DIR)/MultiInputSource.obj $(OBJ_DIR)/SDLInputSystem.obj $(OBJ_DIR)/DirectInputSystem.obj
|
$(OBJ_DIR)/InputTypes.obj $(OBJ_DIR)/MultiInputSource.obj $(OBJ_DIR)/SDLInputSystem.obj $(OBJ_DIR)/DirectInputSystem.obj \
|
||||||
|
$(OBJ_DIR)/amp_audio.obj $(OBJ_DIR)/amp_dump.obj $(OBJ_DIR)/amp_getbits.obj $(OBJ_DIR)/amp_getdata.obj $(OBJ_DIR)/amp_huffman.obj \
|
||||||
|
$(OBJ_DIR)/amp_layer2.obj $(OBJ_DIR)/amp_layer3.obj $(OBJ_DIR)/amp_misc2.obj $(OBJ_DIR)/amp_position.obj $(OBJ_DIR)/amp_transform.obj \
|
||||||
|
$(OBJ_DIR)/amp_util.obj
|
||||||
|
|
||||||
|
|
||||||
# If built-in debugger enabled, include all debugging classes
|
# If built-in debugger enabled, include all debugging classes
|
||||||
ifeq ($(strip $(ENABLE_DEBUGGER)),yes)
|
ifeq ($(strip $(ENABLE_DEBUGGER)),yes)
|
||||||
|
@ -278,6 +283,9 @@ $(OBJ_DIR)/%.obj: Src/CPU/PowerPC/%.cpp Src/CPU/PowerPC/%.h Src/CPU/PowerPC/ppc6
|
||||||
$(OBJ_DIR)/%.obj: Src/CPU/68K/%.cpp Src/CPU/68K/%.h $(HEADERS)
|
$(OBJ_DIR)/%.obj: Src/CPU/68K/%.cpp Src/CPU/68K/%.h $(HEADERS)
|
||||||
$(CC) $< $(CPPFLAGS) /Fo$(OBJ_DIR)/$(*F).obj
|
$(CC) $< $(CPPFLAGS) /Fo$(OBJ_DIR)/$(*F).obj
|
||||||
|
|
||||||
|
$(OBJ_DIR)/%.obj: Src/CPU/Z80/%.cpp Src/CPU/Z80/%.h $(HEADERS)
|
||||||
|
$(CC) $< $(CPPFLAGS) /Fo$(OBJ_DIR)/$(*F).obj
|
||||||
|
|
||||||
$(OBJ_DIR)/%.obj: Src/Inputs/%.cpp Src/Inputs/%.h $(HEADERS)
|
$(OBJ_DIR)/%.obj: Src/Inputs/%.cpp Src/Inputs/%.h $(HEADERS)
|
||||||
$(CC) $< $(CPPFLAGS) /Fo$(OBJ_DIR)/$(*F).obj
|
$(CC) $< $(CPPFLAGS) /Fo$(OBJ_DIR)/$(*F).obj
|
||||||
|
|
||||||
|
@ -295,3 +303,14 @@ $(OBJ_DIR)/%.obj: Src/Pkgs/%.c Src/Pkgs/%.h
|
||||||
|
|
||||||
$(OBJ_DIR)/%.obj: Src/Pkgs/%.c
|
$(OBJ_DIR)/%.obj: Src/Pkgs/%.c
|
||||||
$(CC) $< $(CFLAGS) /Fo$(OBJ_DIR)/$(*F).obj
|
$(CC) $< $(CFLAGS) /Fo$(OBJ_DIR)/$(*F).obj
|
||||||
|
|
||||||
|
#
|
||||||
|
# AMP MPEG decoder library
|
||||||
|
#
|
||||||
|
# To eliminate name conflicts, object files have the prefix "amp_" attached.
|
||||||
|
#
|
||||||
|
$(OBJ_DIR)/amp_%.obj: Src/Sound/MPEG/%.cpp Src/Sound/MPEG/%.h
|
||||||
|
$(CC) $< $(CPPFLAGS) /Fo$(OBJ_DIR)/amp_$(*F).obj
|
||||||
|
|
||||||
|
$(OBJ_DIR)/amp_%.obj: Src/Sound/MPEG/%.cpp
|
||||||
|
$(CC) $< $(CPPFLAGS) /Fo$(OBJ_DIR)/amp_$(*F).obj
|
|
@ -20,7 +20,7 @@
|
||||||
**/
|
**/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* M68K.cpp
|
* 68K.cpp
|
||||||
*
|
*
|
||||||
* 68K CPU interface. This is presently just a wrapper for the Musashi 68K core
|
* 68K CPU interface. This is presently just a wrapper for the Musashi 68K core
|
||||||
* and therefore, only a single CPU is supported. In the future, we may want to
|
* and therefore, only a single CPU is supported. In the future, we may want to
|
||||||
|
@ -30,26 +30,28 @@
|
||||||
#include "Supermodel.h"
|
#include "Supermodel.h"
|
||||||
#include "Musashi/m68k.h" // Musashi 68K core
|
#include "Musashi/m68k.h" // Musashi 68K core
|
||||||
|
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
Internal Context
|
||||||
|
|
||||||
|
An active context must be mapped before calling M68K interface functions. Only
|
||||||
|
the bus and IRQ handlers are copied here; the CPU context is passed directly
|
||||||
|
to Musashi.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
// Bus
|
||||||
|
static CBus *Bus = NULL;
|
||||||
|
|
||||||
|
// IRQ callback
|
||||||
|
static int (*IRQAck)(int nIRQ) = NULL;
|
||||||
|
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
68K Interface
|
68K Interface
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
// Interface function pointers
|
|
||||||
static int (*IRQAck)(int nIRQ) = NULL;
|
|
||||||
static UINT8 (*Fetch8)(UINT32 addr) = NULL;
|
|
||||||
static UINT16 (*Fetch16)(UINT32 addr) = NULL;
|
|
||||||
static UINT32 (*Fetch32)(UINT32 addr) = NULL;
|
|
||||||
static UINT8 (*Read8)(UINT32 addr) = NULL;
|
|
||||||
static UINT16 (*Read16)(UINT32 addr) = NULL;
|
|
||||||
static UINT32 (*Read32)(UINT32 addr) = NULL;
|
|
||||||
static void (*Write8)(UINT32 addr, UINT8 data) = NULL;
|
|
||||||
static void (*Write16)(UINT32 addr, UINT16 data) = NULL;
|
|
||||||
static void (*Write32)(UINT32 addr, UINT32 data) = NULL;
|
|
||||||
|
|
||||||
extern "C" {
|
|
||||||
|
|
||||||
// CPU state
|
// CPU state
|
||||||
|
|
||||||
UINT32 M68KGetARegister(int n)
|
UINT32 M68KGetARegister(int n)
|
||||||
{
|
{
|
||||||
m68k_register_t r;
|
m68k_register_t r;
|
||||||
|
@ -110,6 +112,7 @@ int M68KRun(int numCycles)
|
||||||
void M68KReset(void)
|
void M68KReset(void)
|
||||||
{
|
{
|
||||||
m68k_pulse_reset();
|
m68k_pulse_reset();
|
||||||
|
DebugLog("68K reset\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Callback setup
|
// Callback setup
|
||||||
|
@ -119,49 +122,26 @@ void M68KSetIRQCallback(int (*F)(int nIRQ))
|
||||||
IRQAck = F;
|
IRQAck = F;
|
||||||
}
|
}
|
||||||
|
|
||||||
void M68KSetFetch8Callback(UINT8 (*F)(UINT32))
|
void M68KAttachBus(CBus *BusPtr)
|
||||||
{
|
{
|
||||||
Fetch8 = F;
|
Bus = BusPtr;
|
||||||
|
DebugLog("Attached bus to 68K\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void M68KSetFetch16Callback(UINT16 (*F)(UINT32))
|
// Context switching
|
||||||
|
|
||||||
|
void M68KGetContext(M68KCtx *Dest)
|
||||||
{
|
{
|
||||||
Fetch16 = F;
|
Dest->IRQAck = IRQAck;
|
||||||
|
Dest->Bus = Bus;
|
||||||
|
m68k_get_context(Dest->musashiCtx);
|
||||||
}
|
}
|
||||||
|
|
||||||
void M68KSetFetch32Callback(UINT32 (*F)(UINT32))
|
void M68KSetContext(M68KCtx *Src)
|
||||||
{
|
{
|
||||||
Fetch32 = F;
|
IRQAck = Src->IRQAck;
|
||||||
}
|
Bus = Src->Bus;
|
||||||
|
m68k_set_context(Src->musashiCtx);
|
||||||
void M68KSetRead8Callback(UINT8 (*F)(UINT32))
|
|
||||||
{
|
|
||||||
Read8 = F;
|
|
||||||
}
|
|
||||||
|
|
||||||
void M68KSetRead16Callback(UINT16 (*F)(UINT32))
|
|
||||||
{
|
|
||||||
Read16 = F;
|
|
||||||
}
|
|
||||||
|
|
||||||
void M68KSetRead32Callback(UINT32 (*F)(UINT32))
|
|
||||||
{
|
|
||||||
Read32 = F;
|
|
||||||
}
|
|
||||||
|
|
||||||
void M68KSetWrite8Callback(void (*F)(UINT32,UINT8))
|
|
||||||
{
|
|
||||||
Write8 = F;
|
|
||||||
}
|
|
||||||
|
|
||||||
void M68KSetWrite16Callback(void (*F)(UINT32,UINT16))
|
|
||||||
{
|
|
||||||
Write16 = F;
|
|
||||||
}
|
|
||||||
|
|
||||||
void M68KSetWrite32Callback(void (*F)(UINT32,UINT32))
|
|
||||||
{
|
|
||||||
Write32 = F;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// One-time initialization
|
// One-time initialization
|
||||||
|
@ -171,11 +151,12 @@ BOOL M68KInit(void)
|
||||||
m68k_init();
|
m68k_init();
|
||||||
m68k_set_cpu_type(M68K_CPU_TYPE_68000);
|
m68k_set_cpu_type(M68K_CPU_TYPE_68000);
|
||||||
m68k_set_int_ack_callback(M68KIRQCallback);
|
m68k_set_int_ack_callback(M68KIRQCallback);
|
||||||
|
Bus = NULL;
|
||||||
|
|
||||||
|
DebugLog("Initialized 68K\n");
|
||||||
return OKAY;
|
return OKAY;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // extern "C"
|
|
||||||
|
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
Musashi 68K Handlers
|
Musashi 68K Handlers
|
||||||
|
@ -187,55 +168,58 @@ extern "C" {
|
||||||
|
|
||||||
int M68KIRQCallback(int nIRQ)
|
int M68KIRQCallback(int nIRQ)
|
||||||
{
|
{
|
||||||
if (NULL == IRQAck)
|
if (NULL == IRQAck) // no handler, use default behavior
|
||||||
|
{
|
||||||
|
m68k_set_irq(0); // clear line
|
||||||
return M68K_IRQ_AUTOVECTOR;
|
return M68K_IRQ_AUTOVECTOR;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
return IRQAck(nIRQ);
|
return IRQAck(nIRQ);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int FASTCALL M68KFetch8(unsigned int a)
|
unsigned int FASTCALL M68KFetch8(unsigned int a)
|
||||||
{
|
{
|
||||||
return Fetch8(a);
|
return Bus->Read8(a);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int FASTCALL M68KFetch16(unsigned int a)
|
unsigned int FASTCALL M68KFetch16(unsigned int a)
|
||||||
{
|
{
|
||||||
return Fetch16(a);
|
return Bus->Read16(a);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int FASTCALL M68KFetch32(unsigned int a)
|
unsigned int FASTCALL M68KFetch32(unsigned int a)
|
||||||
{
|
{
|
||||||
return Fetch32(a);
|
return Bus->Read32(a);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int FASTCALL M68KRead8(unsigned int a)
|
unsigned int FASTCALL M68KRead8(unsigned int a)
|
||||||
{
|
{
|
||||||
return Read8(a);
|
return Bus->Read8(a);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int FASTCALL M68KRead16(unsigned int a)
|
unsigned int FASTCALL M68KRead16(unsigned int a)
|
||||||
{
|
{
|
||||||
return Read16(a);
|
return Bus->Read16(a);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int FASTCALL M68KRead32(unsigned int a)
|
unsigned int FASTCALL M68KRead32(unsigned int a)
|
||||||
{
|
{
|
||||||
return Read32(a);
|
return Bus->Read32(a);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FASTCALL M68KWrite8(unsigned int a, unsigned int d)
|
void FASTCALL M68KWrite8(unsigned int a, unsigned int d)
|
||||||
{
|
{
|
||||||
Write8(a, d);
|
Bus->Write8(a, d);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FASTCALL M68KWrite16(unsigned int a, unsigned int d)
|
void FASTCALL M68KWrite16(unsigned int a, unsigned int d)
|
||||||
{
|
{
|
||||||
Write16(a, d);
|
Bus->Write16(a, d);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FASTCALL M68KWrite32(unsigned int a, unsigned int d)
|
void FASTCALL M68KWrite32(unsigned int a, unsigned int d)
|
||||||
{
|
{
|
||||||
Write32(a, d);
|
Bus->Write32(a, d);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // extern "C"
|
} // extern "C"
|
|
@ -20,26 +20,21 @@
|
||||||
**/
|
**/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* M68K.h
|
* 68K.h
|
||||||
*
|
*
|
||||||
* Header file for 68K CPU interface. Caution: there is only a single 68K core
|
* Header file for 68K CPU interface. Caution: 68K emulator is not thread-safe.
|
||||||
* available to Supermodel right now. Therefore, multiple 68K CPUs are not
|
|
||||||
* presently supported. See M68K.c for more details.
|
|
||||||
*
|
*
|
||||||
* TO-DO List:
|
* TO-DO List:
|
||||||
* -----------
|
* -----------
|
||||||
* - Optimize things, perhaps by using FASTCALL
|
* - Optimize things, perhaps by using FASTCALL
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef INCLUDED_M68K_H
|
#ifndef INCLUDED_68K_H
|
||||||
#define INCLUDED_M68K_H
|
#define INCLUDED_68K_H
|
||||||
|
|
||||||
#include "Types.h"
|
#include "Types.h"
|
||||||
#include "Musashi/m68k.h"
|
#include "Musashi/m68k.h"
|
||||||
|
#include "CPU/Bus.h"
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// This doesn't work for now (needs to be added to the prototypes in m68k.h for m68k_read_memory*)
|
// This doesn't work for now (needs to be added to the prototypes in m68k.h for m68k_read_memory*)
|
||||||
//#ifndef FASTCALL
|
//#ifndef FASTCALL
|
||||||
|
@ -57,8 +52,44 @@ extern "C" {
|
||||||
#define M68K_IRQ_SPURIOUS M68K_INT_ACK_SPURIOUS // signals a spurious interrupt
|
#define M68K_IRQ_SPURIOUS M68K_INT_ACK_SPURIOUS // signals a spurious interrupt
|
||||||
|
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
CPU Context
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* M68KCtx:
|
||||||
|
*
|
||||||
|
* Complete state of a single 68K. Do NOT manipulate these directly. Set the
|
||||||
|
* context and then use the M68K* functions below to attach a bus and IRQ
|
||||||
|
* callback to the active context.
|
||||||
|
*/
|
||||||
|
typedef struct SM68KCtx
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CBus *Bus; // memory handlers
|
||||||
|
int (*IRQAck)(int); // IRQ acknowledge callback
|
||||||
|
unsigned char *musashiCtx; // holds CPU state
|
||||||
|
|
||||||
|
SM68KCtx(void)
|
||||||
|
{
|
||||||
|
Bus = NULL;
|
||||||
|
IRQAck = NULL;
|
||||||
|
musashiCtx = new unsigned char[m68k_context_size()];
|
||||||
|
}
|
||||||
|
|
||||||
|
~SM68KCtx(void)
|
||||||
|
{
|
||||||
|
Bus = NULL;
|
||||||
|
IRQAck = NULL;
|
||||||
|
delete [] musashiCtx;
|
||||||
|
}
|
||||||
|
} M68KCtx;
|
||||||
|
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
68K Interface
|
68K Interface
|
||||||
|
|
||||||
|
Unless otherwise noted, all functions operate on the active context.
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -124,8 +155,8 @@ extern void M68KReset(void);
|
||||||
/*
|
/*
|
||||||
* M68KSetIRQCallback(F):
|
* M68KSetIRQCallback(F):
|
||||||
*
|
*
|
||||||
* Installs an interrupt acknowledge callback. The default behavior is to
|
* Installs an interrupt acknowledge callback for the currently active CPU. The
|
||||||
* always assume autovectored interrupts.
|
* default behavior is to always assume autovectored interrupts.
|
||||||
*
|
*
|
||||||
* Parameters:
|
* Parameters:
|
||||||
* F Callback function.
|
* F Callback function.
|
||||||
|
@ -133,44 +164,50 @@ extern void M68KReset(void);
|
||||||
extern void M68KSetIRQCallback(int (*F)(int));
|
extern void M68KSetIRQCallback(int (*F)(int));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* M68KSetFetch8Callback(F):
|
* M68KAttachBus(CBus *BusPtr):
|
||||||
* M68KSetFetch16Callback(F):
|
|
||||||
* M68KSetFetch32Callback(F):
|
|
||||||
* M68KSetRead8Callback(F):
|
|
||||||
* M68KSetRead16Callback(F):
|
|
||||||
* M68KSetRead32Callback(F):
|
|
||||||
* M68KSetWrite8Callback(F):
|
|
||||||
* M68KSetWrite16Callback(F):
|
|
||||||
* M68KSetWrite32Callback(F):
|
|
||||||
*
|
*
|
||||||
* Installs address space handler callbacks. There is no default behavior;
|
* Attaches a bus object to the 68K, which will be used to perform all address
|
||||||
* these must all be set up before any 68K-related emulation functions are
|
* space accesses. The 8, 16, and 32-bit read and write handlers are used.
|
||||||
* invoked.
|
* This must be set up before any 68K-related emulation functions are invoked
|
||||||
|
* or the program will crash!
|
||||||
*
|
*
|
||||||
* Parameters:
|
* Parameters:
|
||||||
* F Callback function.
|
* BusPtr Pointer to bus object to use for all address space accesses.
|
||||||
*/
|
*/
|
||||||
extern void M68KSetFetch8Callback(UINT8 (*F)(UINT32));
|
extern void M68KAttachBus(CBus *BusPtr);
|
||||||
extern void M68KSetFetch16Callback(UINT16 (*F)(UINT32));
|
|
||||||
extern void M68KSetFetch32Callback(UINT32 (*F)(UINT32));
|
|
||||||
extern void M68KSetRead8Callback(UINT8 (*F)(UINT32));
|
|
||||||
extern void M68KSetRead16Callback(UINT16 (*F)(UINT32));
|
|
||||||
extern void M68KSetRead32Callback(UINT32 (*F)(UINT32));
|
|
||||||
extern void M68KSetWrite8Callback(void (*F)(UINT32,UINT8));
|
|
||||||
extern void M68KSetWrite16Callback(void (*F)(UINT32,UINT16));
|
|
||||||
extern void M68KSetWrite32Callback(void (*F)(UINT32,UINT32));
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* M68KInit():
|
* M68KInit():
|
||||||
*
|
*
|
||||||
* Initializes the 68K emulator. Must be called once per program session prior
|
* Initializes the 68K emulator. Must be called once per program session prior
|
||||||
* to any other 68K interface calls.
|
* to any 68K emulation functions. A context must be mapped before calling
|
||||||
|
* this.
|
||||||
*
|
*
|
||||||
* Returns:
|
* Returns:
|
||||||
* Always returns OKAY.
|
* Always returns OKAY.
|
||||||
*/
|
*/
|
||||||
extern BOOL M68KInit(void);
|
extern BOOL M68KInit(void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* M68KGetContext(M68KCtx *Dest):
|
||||||
|
*
|
||||||
|
* Copies the internal (active) 68K context back to the destination.
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* Dest Location to which to copy 68K context.
|
||||||
|
*/
|
||||||
|
extern void M68KGetContext(M68KCtx *Dest);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* M68KSetContext(M68KCtx *Src):
|
||||||
|
*
|
||||||
|
* Sets the specified 68K context by copying it to the internal context.
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* Src Location from which to copy 68K context.
|
||||||
|
*/
|
||||||
|
extern void M68KSetContext(M68KCtx *Src);
|
||||||
|
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
68K Handlers
|
68K Handlers
|
||||||
|
@ -178,6 +215,8 @@ extern BOOL M68KInit(void);
|
||||||
Intended for use directly by the 68K core.
|
Intended for use directly by the 68K core.
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* M68KIRQCallback(nIRQ):
|
* M68KIRQCallback(nIRQ):
|
||||||
*
|
*
|
||||||
|
@ -243,10 +282,7 @@ void FASTCALL M68KWrite8(unsigned int a, unsigned int d);
|
||||||
void FASTCALL M68KWrite16(unsigned int a, unsigned int d);
|
void FASTCALL M68KWrite16(unsigned int a, unsigned int d);
|
||||||
void FASTCALL M68KWrite32(unsigned int a, unsigned int d);
|
void FASTCALL M68KWrite32(unsigned int a, unsigned int d);
|
||||||
|
|
||||||
|
} // extern "C"
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#endif // INCLUDED_M68K_H
|
#endif // INCLUDED_68K_H
|
|
@ -203,7 +203,20 @@
|
||||||
Supermodel Interface
|
Supermodel Interface
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
#include "../M68K.h" // Supermodel's 68K interface
|
// Supermodel 68K interface (these functions defined in CPU/68K.cpp)
|
||||||
|
//#ifndef FASTCALL (this doesn't work for now (needs to be added to the prototypes in m68k.h for m68k_read_memory*)
|
||||||
|
#undef FASTCALL
|
||||||
|
#define FASTCALL
|
||||||
|
//#endif
|
||||||
|
unsigned int FASTCALL M68KFetch8(unsigned int a);
|
||||||
|
unsigned int FASTCALL M68KFetch16(unsigned int a);
|
||||||
|
unsigned int FASTCALL M68KFetch32(unsigned int a);
|
||||||
|
unsigned int FASTCALL M68KRead8(unsigned int a);
|
||||||
|
unsigned int FASTCALL M68KRead16(unsigned int a);
|
||||||
|
unsigned int FASTCALL M68KRead32(unsigned int a);
|
||||||
|
void FASTCALL M68KWrite8(unsigned int a, unsigned int d);
|
||||||
|
void FASTCALL M68KWrite16(unsigned int a, unsigned int d);
|
||||||
|
void FASTCALL M68KWrite32(unsigned int a, unsigned int d);
|
||||||
|
|
||||||
/* Read data relative to the PC */
|
/* Read data relative to the PC */
|
||||||
#define m68k_read_pcrelative_8(address) M68KFetch8(address)
|
#define m68k_read_pcrelative_8(address) M68KFetch8(address)
|
||||||
|
|
1048
Src/Games.cpp
1048
Src/Games.cpp
File diff suppressed because it is too large
Load diff
|
@ -74,9 +74,10 @@ struct GameInfo
|
||||||
unsigned vromSize; // size of video ROMs (32 or 64 MB; if 32 MB, will have to be mirrored)
|
unsigned vromSize; // size of video ROMs (32 or 64 MB; if 32 MB, will have to be mirrored)
|
||||||
unsigned sampleSize; // size of sample ROMS (8 or 16 MB; if 8 MB, will have to be mirrored)
|
unsigned sampleSize; // size of sample ROMS (8 or 16 MB; if 8 MB, will have to be mirrored)
|
||||||
unsigned inputFlags; // game input types
|
unsigned inputFlags; // game input types
|
||||||
|
int mpegBoard; // MPEG music board type: 0 = none, 1 = DSB1 (Z80), 2 = DSB2 (68K).
|
||||||
|
|
||||||
// ROM files
|
// ROM files
|
||||||
struct ROMInfo ROM[42];
|
struct ROMInfo ROM[48];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,170 +0,0 @@
|
||||||
/**
|
|
||||||
** Supermodel
|
|
||||||
** A Sega Model 3 Arcade Emulator.
|
|
||||||
** Copyright 2011 Bart Trzynadlowski
|
|
||||||
**
|
|
||||||
** This file is part of Supermodel.
|
|
||||||
**
|
|
||||||
** Supermodel is free software: you can redistribute it and/or modify it under
|
|
||||||
** the terms of the GNU General Public License as published by the Free
|
|
||||||
** Software Foundation, either version 3 of the License, or (at your option)
|
|
||||||
** any later version.
|
|
||||||
**
|
|
||||||
** Supermodel is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
** FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
||||||
** more details.
|
|
||||||
**
|
|
||||||
** You should have received a copy of the GNU General Public License along
|
|
||||||
** with Supermodel. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
**/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Render.h
|
|
||||||
*
|
|
||||||
* Header file defining the CRender class: container for both the 2D and 3D
|
|
||||||
* renderers.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef INCLUDED_RENDER_H
|
|
||||||
#define INCLUDED_RENDER_H
|
|
||||||
|
|
||||||
/*
|
|
||||||
* CRender:
|
|
||||||
*
|
|
||||||
* Tile generator graphics engine. This must be constructed and initialized
|
|
||||||
* before being attached to any objects that want to make use of it. Apart from
|
|
||||||
* the constructor, all members assume that a global GL device
|
|
||||||
* context is available and that GL functions may be called.
|
|
||||||
*/
|
|
||||||
class CRender2D
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
/*
|
|
||||||
* BeginFrame(layerFormats):
|
|
||||||
*
|
|
||||||
* Prepare to render a new frame. Must be called once per frame prior to
|
|
||||||
* drawing anything.
|
|
||||||
*
|
|
||||||
* Parameters:
|
|
||||||
* layerFormats A bit field indicating how to interpret each of the
|
|
||||||
* four layers: 0=8-bit pixels, 1=4-bit pixels. Bits
|
|
||||||
* 3-0 correspond to layers 3-0.
|
|
||||||
*/
|
|
||||||
void BeginFrame(unsigned layerFormats);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* EndFrame(void):
|
|
||||||
*
|
|
||||||
* Signals the end of rendering for this frame. Must be called last during
|
|
||||||
* the frame.
|
|
||||||
*/
|
|
||||||
void EndFrame(void);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* WriteVRAM(addr, data):
|
|
||||||
*
|
|
||||||
* Indicates what will be written next to the tile generator's RAM. The
|
|
||||||
* VRAM address must not have yet been updated, to allow the renderer to
|
|
||||||
* check for changes. Data is accepted in the same form as the tile
|
|
||||||
* generator: the MSB is what was written to addr+3. This function is
|
|
||||||
* intended to facilitate on-the-fly decoding of tiles and palette data.
|
|
||||||
*
|
|
||||||
* Parameters:
|
|
||||||
* addr Address in tile generator RAM. Caller must ensure it is
|
|
||||||
* clamped to the range 0x000000 to 0x11FFFF because this
|
|
||||||
* function does not.
|
|
||||||
* data The data to write.
|
|
||||||
*/
|
|
||||||
void WriteVRAM(unsigned addr, UINT32 data);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* AttachRegisters(regPtr):
|
|
||||||
*
|
|
||||||
* Attaches tile generator registers. This must be done prior to any
|
|
||||||
* rendering otherwise the program may crash with an access violation.
|
|
||||||
*
|
|
||||||
* Parameters:
|
|
||||||
* regPtr Pointer to the base of the tile generator registers.
|
|
||||||
* There are assumed to be 64 in all.
|
|
||||||
*/
|
|
||||||
void AttachRegisters(const UINT32 *regPtr);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* AttachVRAM(vramPtr):
|
|
||||||
*
|
|
||||||
* Attaches tile generator RAM. This must be done prior to any rendering
|
|
||||||
* otherwise the program may crash with an access violation.
|
|
||||||
*
|
|
||||||
* Parameters:
|
|
||||||
* vramPtr Pointer to the base of the tile generator RAM (0x120000
|
|
||||||
* bytes). VRAM is assumed to be in little endian format.
|
|
||||||
*/
|
|
||||||
void AttachVRAM(const UINT8 *vramPtr);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Init(xOffset, yOffset, xRes, yRes):
|
|
||||||
*
|
|
||||||
* One-time initialization of the context. Must be called before any other
|
|
||||||
* members (meaning it should be called even before being attached to any
|
|
||||||
* other objects that want to use it).
|
|
||||||
*
|
|
||||||
* Parameters:
|
|
||||||
* xOffset X offset within OpenGL display surface in pixels.
|
|
||||||
* yOffset Y offset.
|
|
||||||
* xRes Horizontal resolution of display surface in pixels.
|
|
||||||
* yRes Vertical resolution.
|
|
||||||
*
|
|
||||||
* Returns:
|
|
||||||
* OKAY is successful, otherwise FAILED if a non-recoverable error
|
|
||||||
* occurred. Prints own error messages.
|
|
||||||
*/
|
|
||||||
BOOL Init(unsigned xOffset, unsigned yOffset, unsigned xRes, unsigned yRes);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* CRender2D(void):
|
|
||||||
* ~CRender2D(void):
|
|
||||||
*
|
|
||||||
* Constructor and destructor.
|
|
||||||
*/
|
|
||||||
CRender2D(void);
|
|
||||||
~CRender2D(void);
|
|
||||||
|
|
||||||
private:
|
|
||||||
// Private member functions
|
|
||||||
void DrawTile4Bit(unsigned tile, UINT32 *buf, unsigned pitch);
|
|
||||||
void DrawTile8Bit(unsigned tile, UINT32 *buf, unsigned pitch);
|
|
||||||
void DrawRect(int layerNum, UINT32 *layerSurf, const UINT32 *nameTable, unsigned x, unsigned y, unsigned w, unsigned h);
|
|
||||||
void UpdateLayer(int layerNum);
|
|
||||||
void DisplayLayer(int layerNum, GLfloat z, GLfloat scroll);
|
|
||||||
void Setup2D(void);
|
|
||||||
|
|
||||||
// Data received from tile generator device object
|
|
||||||
const UINT32 *vram;
|
|
||||||
const UINT32 *regs;
|
|
||||||
|
|
||||||
// OpenGL data
|
|
||||||
GLuint texID[4]; // IDs for the 4 layer textures
|
|
||||||
unsigned xPixels, yPixels; // display surface resolution
|
|
||||||
unsigned xOffs, yOffs; // offset
|
|
||||||
|
|
||||||
// Shader programs and input data locations
|
|
||||||
GLuint shaderProgram; // shader program object
|
|
||||||
GLuint vertexShader; // vertex shader handle
|
|
||||||
GLuint fragmentShader; // fragment shader
|
|
||||||
GLuint textureMapLoc; // location of "textureMap" uniform
|
|
||||||
GLuint bottomLayerLoc; // uniform
|
|
||||||
|
|
||||||
|
|
||||||
// Dirty rectangles (non-zero indicates region is dirty)
|
|
||||||
UINT8 dirty[4][64/DIRTY_RECT_HEIGHT][64/DIRTY_RECT_WIDTH];
|
|
||||||
BOOL allDirty; // global dirty flag (forces everything to be updated)
|
|
||||||
|
|
||||||
// Buffers
|
|
||||||
UINT8 *memoryPool; // all memory is allocated here
|
|
||||||
UINT32 *surf; // 4 512x512x32bpp pixel surfaces
|
|
||||||
UINT32 *pal; // 0x20000 byte (32K colors) palette
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif // INCLUDED_RENDER2D_H
|
|
877
Src/Model3/DSB.cpp
Normal file
877
Src/Model3/DSB.cpp
Normal file
|
@ -0,0 +1,877 @@
|
||||||
|
/**
|
||||||
|
** Supermodel
|
||||||
|
** A Sega Model 3 Arcade Emulator.
|
||||||
|
** Copyright 2011 Bart Trzynadlowski
|
||||||
|
**
|
||||||
|
** This file is part of Supermodel.
|
||||||
|
**
|
||||||
|
** Supermodel is free software: you can redistribute it and/or modify it under
|
||||||
|
** the terms of the GNU General Public License as published by the Free
|
||||||
|
** Software Foundation, either version 3 of the License, or (at your option)
|
||||||
|
** any later version.
|
||||||
|
**
|
||||||
|
** Supermodel is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
** FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
** more details.
|
||||||
|
**
|
||||||
|
** You should have received a copy of the GNU General Public License along
|
||||||
|
** with Supermodel. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
**/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* DSB.cpp
|
||||||
|
*
|
||||||
|
* Sega Digital Sound Board (MPEG audio). Implementation of the CDSB1 and CDSB2
|
||||||
|
* classes. Based on code donated by R. Belmont. Many Bothans died to bring us
|
||||||
|
* this emulation.
|
||||||
|
*
|
||||||
|
* TODO List
|
||||||
|
* ---------
|
||||||
|
* - Music looping on DSB2 does not work in Daytona 2 (will play next track).
|
||||||
|
* - Check actual MPEG sample rate. So far, all games seem to use 32 KHz, which
|
||||||
|
* may be a hardware requirement, but if other sampling rates are allowable,
|
||||||
|
* the code here will fail (it is hard coded for 32 KHz).
|
||||||
|
* - Should we do some bounds checking on the MPEG start/end points?
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Supermodel.h"
|
||||||
|
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
Resampler
|
||||||
|
|
||||||
|
MPEG Layer 2 audio can be 32, 44.1, or 48 KHz. Here, an up-sampling algorithm
|
||||||
|
is provided, which should work for any frequency less than 44.1 KHz and an
|
||||||
|
output frequency of 44.1 KHz. Down-sampling is not yet implemented, but would
|
||||||
|
work in a similar fashion. The chief difference is that the input index would
|
||||||
|
sometimes advance by more than one for a single output sample and the
|
||||||
|
fractions, nFrac and pFrac, would sometimes exceed 1.0.
|
||||||
|
|
||||||
|
Up-Sampling Description
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
Linear interpolation is used to up-sample. Not as accurate as the Shannon
|
||||||
|
reconstruction equation but it seems to work quite well.
|
||||||
|
|
||||||
|
1. Linear Interpolation
|
||||||
|
|
||||||
|
Input samples for a given frame (here, this means 1/60Hz, not to be confused
|
||||||
|
with an MPEG frame, which is shorter) are numbered 0 ... L-1 (L samples in
|
||||||
|
total). Output samples are 0 ... M-1.
|
||||||
|
|
||||||
|
For two adjacent input samples at times p ("previous") and n ("next"), in[p]
|
||||||
|
and in[n], and output out[t] at time t, linear interpolation yields:
|
||||||
|
|
||||||
|
out[t] = (n-t)/(n-p) * in[p] + (t-p)/(n-p) * in[n]
|
||||||
|
|
||||||
|
Note that (n-p) = 1/fin (fin being the input sampling frequency).
|
||||||
|
|
||||||
|
Let pFrac = (n-t)/(n-p) and nFrac = (t-p)/(n-p). As t moves from p to n, pFrac
|
||||||
|
moves from 1 to 0 and nFrac from 0 to 1, as we expect.
|
||||||
|
|
||||||
|
If we proceed one output sample at a time, we must add the time difference
|
||||||
|
between output samples, 1/fout, to t. Call this delta_t. If we divide delta_t
|
||||||
|
by (n-p), we can add it directly to nFrac and subtract from pFrac. Therefore:
|
||||||
|
|
||||||
|
delta = (1/fout)/(n-p) = fin/fout
|
||||||
|
|
||||||
|
What happens when nFrac exceeds 1.0 or pFrac goes below 0.0? That can't
|
||||||
|
be allowed to happen -- it means that we've actually moved along the line into
|
||||||
|
the region between the next set of samples. We use pFrac < 0 as the condition
|
||||||
|
to update the input samples.
|
||||||
|
|
||||||
|
It so happens that when fin < fout, pFrac and nFrac will never exceed 1.0. So
|
||||||
|
there is no need to check or mask the fixed point values when using them to
|
||||||
|
interpolate samples.
|
||||||
|
|
||||||
|
2. Input Buffer Overflows
|
||||||
|
|
||||||
|
For some low sampling rates, particularly those that are a factor of 2 or 4
|
||||||
|
smaller, it is possible that the very last sample or two needed from the input
|
||||||
|
stream will be beyond the end. Fetching two extra samples (which can introduce
|
||||||
|
an update lag of two samples -- imperceptible and inconsequential) fixes this,
|
||||||
|
and so we do it.
|
||||||
|
|
||||||
|
3. Continuity Between Frames
|
||||||
|
|
||||||
|
The very last output sample will typically sit somewhere between two input
|
||||||
|
samples. It is wrong to start the next frame by assuming everything is lined
|
||||||
|
up again. The first sample of the next frame will often have to be interpol-
|
||||||
|
ated with the last sample of the previous frame. To facilitate this, we check
|
||||||
|
to see how many input samples remain unprocessed when up-sampling is finished,
|
||||||
|
and then copy those to the beginning of the buffer. We then return the number
|
||||||
|
of samples so that the buffer update function will know to skip them.
|
||||||
|
|
||||||
|
We also must maintain the state of pFrac and nFrac to resume interpolation
|
||||||
|
correctly. Therefore, these variables are persistent.
|
||||||
|
|
||||||
|
4. Fixed Point Arithmetic
|
||||||
|
|
||||||
|
Fixed point arithmetic is used to track fractions. For such numbers, the low
|
||||||
|
8 bits represent a fraction (0x100 would be 1.0, 0x080 would be 0.5, etc.)
|
||||||
|
and the upper bits are the integral portion.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
void CDSBResampler::Reset(void)
|
||||||
|
{
|
||||||
|
// Initial state of fractions (24.8 fixed point)
|
||||||
|
nFrac = 0<<8; // fraction of next sample to use (0->1.0 as x moves p->n)
|
||||||
|
pFrac = 1<<8; // previous sample (1.0->0 as x moves p->n)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mixes 16-bit samples (sign extended in a and b)
|
||||||
|
static inline INT16 MixAndClip(INT32 a, INT32 b)
|
||||||
|
{
|
||||||
|
a += b;
|
||||||
|
if (a > 32767)
|
||||||
|
a = 32767;
|
||||||
|
else if (a < -32768)
|
||||||
|
a = -32768;
|
||||||
|
return (INT16) a;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mixes audio and returns number of samples copied back to start of buffer (ie. offset at which new samples should be written)
|
||||||
|
int CDSBResampler::UpSampleAndMix(INT16 *outL, INT16 *outR, INT16 *inL, INT16 *inR, int sizeOut, int sizeIn, int outRate, int inRate)
|
||||||
|
{
|
||||||
|
int delta = (inRate<<8)/outRate; // (1/fout)/(1/fin)=fin/fout, 24.8 fixed point
|
||||||
|
int outIdx = 0;
|
||||||
|
int inIdx = 0;
|
||||||
|
INT16 leftSample, rightSample;
|
||||||
|
|
||||||
|
while (outIdx < sizeOut)
|
||||||
|
{
|
||||||
|
// nFrac, pFrac will never exceed 1.0 (0x100) (only true if delta does not exceed 1)
|
||||||
|
leftSample = ((int)inL[inIdx]*pFrac+(int)inL[inIdx+1]*nFrac) >> 8; // left channel
|
||||||
|
rightSample = ((int)inR[inIdx]*pFrac+(int)inR[inIdx+1]*nFrac) >> 8; // right channel
|
||||||
|
|
||||||
|
|
||||||
|
outL[outIdx] = MixAndClip(outL[outIdx], leftSample);
|
||||||
|
outR[outIdx] = MixAndClip(outR[outIdx], rightSample);
|
||||||
|
outIdx++;
|
||||||
|
|
||||||
|
// Time step
|
||||||
|
pFrac -= delta;
|
||||||
|
nFrac += delta;
|
||||||
|
|
||||||
|
// Time to move to next samples?
|
||||||
|
if (pFrac <= 0) // when pFrac becomes 0, advance samples, reset pFrac to 1
|
||||||
|
{
|
||||||
|
pFrac += (1<<8);
|
||||||
|
nFrac -= (1<<8);
|
||||||
|
inIdx++; // advance samples (for upsampling only; downsampling may advance by more than one -- add delta every loop iteration)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy remaining "active" input samples to start of buffer
|
||||||
|
int i = 0;
|
||||||
|
int j = inIdx;
|
||||||
|
while (j < sizeIn)
|
||||||
|
{
|
||||||
|
inL[i] = inL[j];
|
||||||
|
inR[i] = inR[j];
|
||||||
|
i++;
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
return i; // first free position in input buffer to copy next MPEG update to
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
Digital Sound Board Type 1: Z80 CPU
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
UINT8 CDSB1::Read8(UINT32 addr)
|
||||||
|
{
|
||||||
|
// ROM: 0x0000-0x7FFF
|
||||||
|
if (addr < 0x8000)
|
||||||
|
return progROM[addr];
|
||||||
|
|
||||||
|
// RAM: 0x8000-0xFFFF
|
||||||
|
return ram[addr&0x7FFF];
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDSB1::Write8(UINT32 addr, UINT8 data)
|
||||||
|
{
|
||||||
|
if (addr >= 0x8000)
|
||||||
|
ram[addr&0x7FFF] = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDSB1::IOWrite8(UINT32 addr, UINT8 data)
|
||||||
|
{
|
||||||
|
switch ((addr&0xFF))
|
||||||
|
{
|
||||||
|
case 0xE0: // MPEG trigger
|
||||||
|
mpegState = data;
|
||||||
|
|
||||||
|
if (data == 0) // stop
|
||||||
|
{
|
||||||
|
MPEG_StopPlaying();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data == 1) // play without loop
|
||||||
|
{
|
||||||
|
MPEG_SetLoop(NULL, 0);
|
||||||
|
//printf("====> Playing %06X\n", mpegStart);
|
||||||
|
MPEG_PlayMemory((const char *) &mpegROM[mpegStart], mpegEnd-mpegStart);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data == 2) // play with loop
|
||||||
|
{
|
||||||
|
//printf("====> Playing %06X\n", mpegStart);
|
||||||
|
MPEG_PlayMemory((const char *) &mpegROM[mpegStart], mpegEnd-mpegStart);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xE2: // MPEG start, high byte
|
||||||
|
startLatch &= 0x00FFFF;
|
||||||
|
startLatch |= ((UINT32)data) << 16;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xE3: // MPEG start, middle byte
|
||||||
|
startLatch &= 0xFF00FF;
|
||||||
|
startLatch |= ((UINT32)data) << 8;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xE4: // MPEG start, low byte
|
||||||
|
startLatch &= 0xFFFF00;
|
||||||
|
startLatch |= data;
|
||||||
|
|
||||||
|
if (mpegState == 0)
|
||||||
|
{
|
||||||
|
mpegStart = startLatch;
|
||||||
|
//printf("mpegStart = %08X\n", mpegStart);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
loopStart = startLatch;
|
||||||
|
//printf("loopStart = %08X\n", loopStart);
|
||||||
|
// SWA: if loop end is zero, it means "keep previous end marker"
|
||||||
|
if (loopEnd == 0)
|
||||||
|
{
|
||||||
|
MPEG_SetLoop((const char *) &mpegROM[loopStart], mpegEnd-loopStart);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
MPEG_SetLoop((const char *) &mpegROM[loopStart], loopEnd-loopStart);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xE5: // MPEG end, high byte
|
||||||
|
endLatch &= 0x00FFFF;
|
||||||
|
endLatch |= ((UINT32)data) << 16;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xE6: // MPEG end, middle byte
|
||||||
|
endLatch &= 0xFF00FF;
|
||||||
|
endLatch |= ((UINT32)data) << 8;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xE7: // MPEG end, low byte
|
||||||
|
endLatch &= 0xFFFF00;
|
||||||
|
endLatch |= data;
|
||||||
|
|
||||||
|
if (mpegState == 0)
|
||||||
|
{
|
||||||
|
mpegEnd = endLatch;
|
||||||
|
//printf("mpegEnd = %08X\n", mpegEnd);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
loopEnd = endLatch;
|
||||||
|
//printf("loopEnd = %08X\n", loopEnd);
|
||||||
|
MPEG_SetLoop((const char *) &mpegROM[loopStart], loopEnd-loopStart);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xE8: // MPEG volume
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xE9: // MPEG stereo
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xF0: // command echo back
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
//printf("Z80 Port %02X=%08X\n", addr, data);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT8 CDSB1::IORead8(UINT32 addr)
|
||||||
|
{
|
||||||
|
int progress;
|
||||||
|
|
||||||
|
switch ((addr&0xFF))
|
||||||
|
{
|
||||||
|
case 0xE2: // MPEG position, high byte
|
||||||
|
progress = MPEG_GetProgress() + mpegStart; // byte address currently playing
|
||||||
|
return (progress>>16)&0xFF;
|
||||||
|
|
||||||
|
case 0xE3: // MPEG position, middle byte
|
||||||
|
progress = MPEG_GetProgress() + mpegStart;
|
||||||
|
return (progress>>8)&0xFF;
|
||||||
|
|
||||||
|
case 0xE4: // MPEG position, low byte
|
||||||
|
progress = MPEG_GetProgress() + mpegStart;
|
||||||
|
return progress&0xFF;
|
||||||
|
|
||||||
|
case 0xF0: // Latch
|
||||||
|
UINT8 d;
|
||||||
|
d = fifo[fifoIdxR]; // retrieve next command byte
|
||||||
|
if (fifoIdxR != fifoIdxW) // if these are equal, nothing has been written yet (don't advance)
|
||||||
|
{
|
||||||
|
fifoIdxR++;
|
||||||
|
fifoIdxR &= 127;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fifoIdxR == fifoIdxW) // FIFO empty?
|
||||||
|
status &= ~2; // yes, indicate no commands left
|
||||||
|
else
|
||||||
|
status |= 2;
|
||||||
|
|
||||||
|
Z80.SetINT(FALSE); // clear IRQ
|
||||||
|
//printf("Z80: INT cleared, read from FIFO\n");
|
||||||
|
return d;
|
||||||
|
|
||||||
|
case 0xF1: // Status
|
||||||
|
/*
|
||||||
|
* Bit 0: Must be 1 for most games.
|
||||||
|
* Bit 1: Command pending (used by SWA instead of IRQ)
|
||||||
|
* SWA requires (status&0x38)==0 or else it loops endlessly
|
||||||
|
*/
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
//printf("Z80 Port Read %02X\n", addr);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int Z80IRQCallback(CZ80 *Z80)
|
||||||
|
{
|
||||||
|
return 0x38;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDSB1::SendCommand(UINT8 data)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Commands are buffered in a FIFO. This probably does not actually exist
|
||||||
|
* on the real DSB but is necessary because the Z80 is not really synced
|
||||||
|
* up with the other CPUs and must process all commands it has received
|
||||||
|
* over the course of a frame at once.
|
||||||
|
*/
|
||||||
|
fifo[fifoIdxW++] = data;
|
||||||
|
fifoIdxW &= 127;
|
||||||
|
//printf("Write FIFO: %02X\n", data);
|
||||||
|
|
||||||
|
// Have we caught up to the read pointer?
|
||||||
|
#ifdef DEBUG
|
||||||
|
if (fifoIdxW == fifoIdxR)
|
||||||
|
printf("DSB1 FIFO overflow!\n");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDSB1::RunFrame(INT16 *audioL, INT16 *audioR)
|
||||||
|
{
|
||||||
|
#ifdef SUPERMODEL_SOUND
|
||||||
|
int cycles;
|
||||||
|
|
||||||
|
// While FIFO not empty, fire interrupts, run for up to one frame
|
||||||
|
for (cycles = (4000000/60)/4; (cycles > 0) && (fifoIdxR != fifoIdxW); )
|
||||||
|
{
|
||||||
|
Z80.SetINT(TRUE); // fire an IRQ to indicate pending command
|
||||||
|
//printf("Z80 INT fired\n");
|
||||||
|
cycles -= Z80.Run(500);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run remaining cycles
|
||||||
|
Z80.Run(cycles);
|
||||||
|
|
||||||
|
// Decode MPEG for this frame
|
||||||
|
INT16 *mpegFill[2] = { &mpegL[retainedSamples], &mpegR[retainedSamples] };
|
||||||
|
MPEG_Decode(mpegFill, 32000/60-retainedSamples+2);
|
||||||
|
retainedSamples = Resampler.UpSampleAndMix(audioL, audioR, mpegL, mpegR, 44100/60, 32000/60+2, 44100, 32000);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDSB1::Reset(void)
|
||||||
|
{
|
||||||
|
MPEG_StopPlaying();
|
||||||
|
Resampler.Reset();
|
||||||
|
retainedSamples = 0;
|
||||||
|
|
||||||
|
memset(fifo, 0, sizeof(fifo));
|
||||||
|
fifoIdxW = fifoIdxR = 0;
|
||||||
|
|
||||||
|
status = 1;
|
||||||
|
mpegState = 0; // why doesn't RB ever init this?
|
||||||
|
|
||||||
|
Z80.Reset();
|
||||||
|
DebugLog("DSB1 Reset\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Offsets of memory regions within DSB2's pool
|
||||||
|
#define DSB1_OFFSET_RAM 0 // 32KB Z80 RAM
|
||||||
|
#define DSB1_OFFSET_MPEG_LEFT 0x8000 // 1604 bytes (48 KHz max., 1/60th second, 2 extra = 2*(48000/60+2)) left MPEG buffer
|
||||||
|
#define DSB1_OFFSET_MPEG_RIGHT 0x8644 // 1604 bytes right MPEG buffer
|
||||||
|
#define DSB1_MEMORY_POOL_SIZE (0x8000+0x644+0x644)
|
||||||
|
|
||||||
|
BOOL CDSB1::Init(const UINT8 *progROMPtr, const UINT8 *mpegROMPtr)
|
||||||
|
{
|
||||||
|
float memSizeMB = (float)DSB1_MEMORY_POOL_SIZE/(float)0x100000;
|
||||||
|
|
||||||
|
// Receive ROM
|
||||||
|
progROM = progROMPtr;
|
||||||
|
mpegROM = mpegROMPtr;
|
||||||
|
|
||||||
|
// Allocate memory pool
|
||||||
|
memoryPool = new(std::nothrow) UINT8[DSB1_MEMORY_POOL_SIZE];
|
||||||
|
if (NULL == memoryPool)
|
||||||
|
return ErrorLog("Insufficient memory for DSB1 board (needs %1.1f MB).", memSizeMB);
|
||||||
|
memset(memoryPool, 0, DSB1_MEMORY_POOL_SIZE);
|
||||||
|
|
||||||
|
// Set up memory pointers
|
||||||
|
ram = &memoryPool[DSB1_OFFSET_RAM];
|
||||||
|
mpegL = (INT16 *) &memoryPool[DSB1_OFFSET_MPEG_LEFT];
|
||||||
|
mpegR = (INT16 *) &memoryPool[DSB1_OFFSET_MPEG_RIGHT];
|
||||||
|
|
||||||
|
// Initialize Z80 CPU
|
||||||
|
Z80.Init(this, Z80IRQCallback);
|
||||||
|
|
||||||
|
// MPEG decoder
|
||||||
|
if (OKAY != MPEG_Init())
|
||||||
|
return ErrorLog("Insufficient memory to initialize MPEG decoder.");
|
||||||
|
retainedSamples = 0;
|
||||||
|
|
||||||
|
return OKAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
CDSB1::CDSB1(void)
|
||||||
|
{
|
||||||
|
progROM = NULL;
|
||||||
|
mpegROM = NULL;
|
||||||
|
memoryPool = NULL;
|
||||||
|
ram = NULL;
|
||||||
|
mpegL = NULL;
|
||||||
|
mpegR = NULL;
|
||||||
|
|
||||||
|
DebugLog("Built DSB1 Board\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
CDSB1::~CDSB1(void)
|
||||||
|
{
|
||||||
|
MPEG_Shutdown();
|
||||||
|
|
||||||
|
if (memoryPool != NULL)
|
||||||
|
{
|
||||||
|
delete [] memoryPool;
|
||||||
|
memoryPool = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
progROM = NULL;
|
||||||
|
mpegROM = NULL;
|
||||||
|
ram = NULL;
|
||||||
|
mpegL = NULL;
|
||||||
|
mpegR = NULL;
|
||||||
|
|
||||||
|
DebugLog("Destroyed DSB1 Board\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
Digital Sound Board Type 2: 68K CPU
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
ST_IDLE = 0,
|
||||||
|
ST_GOT14, // start/loop addr
|
||||||
|
ST_14_0,
|
||||||
|
ST_14_1,
|
||||||
|
ST_GOT24, // end addr
|
||||||
|
ST_24_0,
|
||||||
|
ST_24_1,
|
||||||
|
ST_GOT74,
|
||||||
|
ST_GOTA0,
|
||||||
|
ST_GOTA1,
|
||||||
|
ST_GOTA4,
|
||||||
|
ST_GOTA5,
|
||||||
|
ST_GOTB0,
|
||||||
|
ST_GOTB1,
|
||||||
|
ST_GOTB4,
|
||||||
|
ST_GOTB5,
|
||||||
|
};
|
||||||
|
|
||||||
|
void CDSB2::WriteMPEGFIFO(UINT8 byte)
|
||||||
|
{
|
||||||
|
//printf("fifo: %x (state %d)\n", byte, mpegState);
|
||||||
|
switch (mpegState)
|
||||||
|
{
|
||||||
|
case ST_IDLE:
|
||||||
|
if (byte == 0x14) mpegState = ST_GOT14;
|
||||||
|
else if (byte == 0x15) mpegState = ST_GOT14;
|
||||||
|
else if (byte == 0x24) mpegState = ST_GOT24;
|
||||||
|
else if (byte == 0x25) mpegState = ST_GOT24;
|
||||||
|
|
||||||
|
else if (byte == 0x74 || byte == 0x75) // "start play"
|
||||||
|
{
|
||||||
|
MPEG_PlayMemory((const char *) &mpegROM[mpegStart], mpegEnd-mpegStart);
|
||||||
|
mpegState = ST_IDLE;
|
||||||
|
playing = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (byte == 0x84 || byte == 0x85)
|
||||||
|
{
|
||||||
|
MPEG_StopPlaying();
|
||||||
|
playing = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (byte == 0xa0) mpegState = ST_GOTA0;
|
||||||
|
else if (byte == 0xa1) mpegState = ST_GOTA1;
|
||||||
|
else if (byte == 0xa4) mpegState = ST_GOTA4;
|
||||||
|
else if (byte == 0xa5) mpegState = ST_GOTA5;
|
||||||
|
|
||||||
|
else if (byte == 0xb0) mpegState = ST_GOTB0;
|
||||||
|
else if (byte == 0xb1) mpegState = ST_GOTB1;
|
||||||
|
else if (byte == 0xb4) mpegState = ST_GOTB4;
|
||||||
|
else if (byte == 0xb5) mpegState = ST_GOTB5;
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ST_GOT14:
|
||||||
|
mpegStart &= ~0xff0000;
|
||||||
|
mpegStart |= (byte<<16);
|
||||||
|
mpegState++;
|
||||||
|
break;
|
||||||
|
case ST_14_0:
|
||||||
|
mpegStart &= ~0xff00;
|
||||||
|
mpegStart |= (byte<<8);
|
||||||
|
mpegState++;
|
||||||
|
break;
|
||||||
|
case ST_14_1:
|
||||||
|
mpegStart &= ~0xff;
|
||||||
|
mpegStart |= (byte);
|
||||||
|
mpegState = ST_IDLE;
|
||||||
|
|
||||||
|
if (playing)
|
||||||
|
{
|
||||||
|
//printf("Setting loop point to %x\n", mpegStart);
|
||||||
|
MPEG_PlayMemory((const char *) &mpegROM[mpegStart], mpegEnd-mpegStart);
|
||||||
|
}
|
||||||
|
|
||||||
|
//printf("mpegStart=%x\n", mpegStart);
|
||||||
|
break;
|
||||||
|
case ST_GOT24:
|
||||||
|
mpegEnd &= ~0xff0000;
|
||||||
|
mpegEnd |= (byte<<16);
|
||||||
|
mpegState++;
|
||||||
|
break;
|
||||||
|
case ST_24_0:
|
||||||
|
mpegEnd &= ~0xff00;
|
||||||
|
mpegEnd |= (byte<<8);
|
||||||
|
mpegState++;
|
||||||
|
break;
|
||||||
|
case ST_24_1:
|
||||||
|
mpegEnd &= ~0xff;
|
||||||
|
mpegEnd |= (byte);
|
||||||
|
//printf("mpegEnd=%x\n", mpegEnd);
|
||||||
|
|
||||||
|
// default to full stereo
|
||||||
|
// mixer_set_stereo_volume(0, 255, 255);
|
||||||
|
// mixer_set_stereo_pan(0, MIXER_PAN_RIGHT, MIXER_PAN_LEFT);
|
||||||
|
mpegState = ST_IDLE;
|
||||||
|
break;
|
||||||
|
case ST_GOTA0:
|
||||||
|
// ch 0 mono
|
||||||
|
// mixer_set_stereo_volume(0, 0, 255);
|
||||||
|
// printf("ch 0 mono\n");
|
||||||
|
// mixer_set_stereo_pan(0, MIXER_PAN_CENTER, MIXER_PAN_CENTER);
|
||||||
|
mpegState = ST_IDLE;
|
||||||
|
break;
|
||||||
|
case ST_GOTA1:
|
||||||
|
mpegState = ST_IDLE;
|
||||||
|
break;
|
||||||
|
case ST_GOTA4:
|
||||||
|
mpegState = ST_IDLE;
|
||||||
|
break;
|
||||||
|
case ST_GOTA5:
|
||||||
|
mpegState = ST_IDLE;
|
||||||
|
break;
|
||||||
|
case ST_GOTB0:
|
||||||
|
mpegState = ST_IDLE;
|
||||||
|
break;
|
||||||
|
case ST_GOTB1:
|
||||||
|
// ch 1 mono
|
||||||
|
// printf("ch 1 mono\n");
|
||||||
|
// mixer_set_stereo_volume(0, 255, 0);
|
||||||
|
// mixer_set_stereo_pan(0, MIXER_PAN_CENTER, MIXER_PAN_CENTER);
|
||||||
|
mpegState = ST_IDLE;
|
||||||
|
break;
|
||||||
|
case ST_GOTB4:
|
||||||
|
mpegState = ST_IDLE;
|
||||||
|
break;
|
||||||
|
case ST_GOTB5:
|
||||||
|
mpegState = ST_IDLE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT8 CDSB2::Read8(UINT32 addr)
|
||||||
|
{
|
||||||
|
if (addr < (128*1024))
|
||||||
|
return progROM[addr^1];
|
||||||
|
|
||||||
|
if (addr == 0xc00001)
|
||||||
|
{
|
||||||
|
return cmdLatch;
|
||||||
|
}
|
||||||
|
if (addr == 0xc00003) // bit 0 = command valid
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (addr == 0xe80001)
|
||||||
|
{
|
||||||
|
return 0x01; // MPEG busy status: bit 1 = busy
|
||||||
|
} // polled by irq2, stored | 0x10 at f01010
|
||||||
|
|
||||||
|
if ((addr >= 0xf00000) && (addr < 0xf10000))
|
||||||
|
{
|
||||||
|
addr &= 0x1ffff;
|
||||||
|
return ram[addr^1];
|
||||||
|
}
|
||||||
|
|
||||||
|
// printf("R8 @ %x\n", addr);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT16 CDSB2::Read16(UINT32 addr)
|
||||||
|
{
|
||||||
|
if (addr < (128*1024))
|
||||||
|
{
|
||||||
|
return *(UINT16 *) &progROM[addr];
|
||||||
|
}
|
||||||
|
if ((addr >= 0xf00000) && (addr < 0xf20000))
|
||||||
|
{
|
||||||
|
addr &= 0x1ffff;
|
||||||
|
return *(UINT16 *) &ram[addr];
|
||||||
|
}
|
||||||
|
|
||||||
|
// printf("R16 @ %x\n", addr);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT32 CDSB2::Read32(UINT32 addr)
|
||||||
|
{
|
||||||
|
UINT32 hi, lo;
|
||||||
|
|
||||||
|
if (addr < (128*1024))
|
||||||
|
{
|
||||||
|
hi = *(UINT16 *) &progROM[addr];
|
||||||
|
lo = *(UINT16 *) &progROM[addr+2];
|
||||||
|
return (hi<<16)|lo;
|
||||||
|
}
|
||||||
|
if ((addr >= 0xf00000) && (addr < 0xf20000))
|
||||||
|
{
|
||||||
|
addr &= 0x1ffff;
|
||||||
|
hi = *(UINT16 *) &ram[addr];
|
||||||
|
lo = *(UINT16 *) &ram[addr+2];
|
||||||
|
return (hi<<16)|lo;
|
||||||
|
}
|
||||||
|
// printf("R32 @ %x\n", addr);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDSB2::Write8(UINT32 addr, UINT8 data)
|
||||||
|
{
|
||||||
|
if ((addr >= 0xf00000) && (addr < 0xf20000))
|
||||||
|
{
|
||||||
|
addr &= 0x1ffff;
|
||||||
|
ram[addr^1] = data;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (addr == 0xd00001) return;
|
||||||
|
|
||||||
|
if (addr == 0xe00003)
|
||||||
|
{
|
||||||
|
WriteMPEGFIFO(data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// printf("W8: %x @ %x (PC=%x)\n", data, addr, m68k_get_reg(NULL, M68K_REG_PC));
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDSB2::Write16(UINT32 addr, UINT16 data)
|
||||||
|
{
|
||||||
|
if ((addr >= 0xf00000) && (addr < 0xf20000))
|
||||||
|
{
|
||||||
|
addr &= 0x1ffff;
|
||||||
|
*(UINT16 *) &ram[addr] = data;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// printf("W16: %x @ %x\n", data, addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDSB2::Write32(UINT32 addr, UINT32 data)
|
||||||
|
{
|
||||||
|
if ((addr >= 0xf00000) && (addr < 0xf20000))
|
||||||
|
{
|
||||||
|
addr &= 0x1ffff;
|
||||||
|
*(UINT16 *) &ram[addr+0] = (data>>16);
|
||||||
|
*(UINT16 *) &ram[addr+2] = data&0xFFFF;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// printf("W32: %x @ %x\n", data, addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDSB2::SendCommand(UINT8 data)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Commands are buffered in a FIFO. This probably does not actually exist
|
||||||
|
* on the real DSB but is necessary because the Z80 is not really synced
|
||||||
|
* up with the other CPUs and must process all commands it has received
|
||||||
|
* over the course of a frame at once.
|
||||||
|
*/
|
||||||
|
fifo[fifoIdxW++] = data;
|
||||||
|
fifoIdxW &= 127;
|
||||||
|
//printf("Write FIFO: %02X\n", data);
|
||||||
|
|
||||||
|
// Have we caught up to the read pointer?
|
||||||
|
#ifdef DEBUG
|
||||||
|
if (fifoIdxW == fifoIdxR)
|
||||||
|
printf("DSB2 FIFO overflow!\n");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void CDSB2::RunFrame(INT16 *audioL, INT16 *audioR)
|
||||||
|
{
|
||||||
|
#ifdef SUPERMODEL_SOUND
|
||||||
|
M68KSetContext(&M68K);
|
||||||
|
|
||||||
|
// While FIFO not empty...
|
||||||
|
while (fifoIdxR != fifoIdxW)
|
||||||
|
{
|
||||||
|
cmdLatch = fifo[fifoIdxR]; // retrieve next command byte
|
||||||
|
fifoIdxR++;
|
||||||
|
fifoIdxR &= 127;
|
||||||
|
|
||||||
|
M68KSetIRQ(1); // indicate pending command
|
||||||
|
//printf("68K INT fired\n");
|
||||||
|
M68KRun(500);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Per-frame interrupt
|
||||||
|
M68KSetIRQ(2);
|
||||||
|
M68KRun(4000000/60);
|
||||||
|
|
||||||
|
M68KGetContext(&M68K);
|
||||||
|
|
||||||
|
// Decode MPEG for this frame
|
||||||
|
INT16 *mpegFill[2] = { &mpegL[retainedSamples], &mpegR[retainedSamples] };
|
||||||
|
MPEG_Decode(mpegFill, 32000/60-retainedSamples+2);
|
||||||
|
retainedSamples = Resampler.UpSampleAndMix(audioL, audioR, mpegL, mpegR, 44100/60, 32000/60+2, 44100, 32000);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDSB2::Reset(void)
|
||||||
|
{
|
||||||
|
MPEG_StopPlaying();
|
||||||
|
Resampler.Reset();
|
||||||
|
retainedSamples = 0;
|
||||||
|
|
||||||
|
memset(fifo, 0, sizeof(fifo));
|
||||||
|
fifoIdxW = fifoIdxR = 0;
|
||||||
|
|
||||||
|
mpegState = ST_IDLE;
|
||||||
|
playing = 0;
|
||||||
|
|
||||||
|
M68KSetContext(&M68K);
|
||||||
|
M68KReset();
|
||||||
|
M68KGetContext(&M68K);
|
||||||
|
|
||||||
|
DebugLog("DSB2 Reset\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Offsets of memory regions within DSB2's pool
|
||||||
|
#define DSB2_OFFSET_RAM 0 // 128KB 68K RAM
|
||||||
|
#define DSB2_OFFSET_MPEG_LEFT 0x20000 // 1604 bytes (48 KHz max., 1/60th second, 2 extra = 2*(48000/60+2)) left MPEG buffer
|
||||||
|
#define DSB2_OFFSET_MPEG_RIGHT 0x20644 // 1604 bytes right MPEG buffer
|
||||||
|
#define DSB2_MEMORY_POOL_SIZE (0x20000+0x644+0x644)
|
||||||
|
|
||||||
|
BOOL CDSB2::Init(const UINT8 *progROMPtr, const UINT8 *mpegROMPtr)
|
||||||
|
{
|
||||||
|
float memSizeMB = (float)DSB2_MEMORY_POOL_SIZE/(float)0x100000;
|
||||||
|
|
||||||
|
// Receive ROM
|
||||||
|
progROM = progROMPtr;
|
||||||
|
mpegROM = mpegROMPtr;
|
||||||
|
|
||||||
|
// Allocate memory pool
|
||||||
|
memoryPool = new(std::nothrow) UINT8[DSB2_MEMORY_POOL_SIZE];
|
||||||
|
if (NULL == memoryPool)
|
||||||
|
return ErrorLog("Insufficient memory for DSB2 board (needs %1.1f MB).", memSizeMB);
|
||||||
|
memset(memoryPool, 0, DSB2_MEMORY_POOL_SIZE);
|
||||||
|
|
||||||
|
// Set up memory pointers
|
||||||
|
ram = &memoryPool[DSB2_OFFSET_RAM];
|
||||||
|
mpegL = (INT16 *) &memoryPool[DSB2_OFFSET_MPEG_LEFT];
|
||||||
|
mpegR = (INT16 *) &memoryPool[DSB2_OFFSET_MPEG_RIGHT];
|
||||||
|
|
||||||
|
// Initialize 68K CPU
|
||||||
|
M68KSetContext(&M68K);
|
||||||
|
M68KInit();
|
||||||
|
M68KAttachBus(this);
|
||||||
|
M68KSetIRQCallback(NULL); // use default behavior (autovector, clear interrupt)
|
||||||
|
M68KGetContext(&M68K);
|
||||||
|
|
||||||
|
// MPEG decoder
|
||||||
|
if (OKAY != MPEG_Init())
|
||||||
|
return ErrorLog("Insufficient memory to initialize MPEG decoder.");
|
||||||
|
retainedSamples = 0;
|
||||||
|
|
||||||
|
return OKAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
CDSB2::CDSB2(void)
|
||||||
|
{
|
||||||
|
progROM = NULL;
|
||||||
|
mpegROM = NULL;
|
||||||
|
memoryPool = NULL;
|
||||||
|
ram = NULL;
|
||||||
|
mpegL = NULL;
|
||||||
|
mpegR = NULL;
|
||||||
|
|
||||||
|
DebugLog("Built DSB2 Board\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
CDSB2::~CDSB2(void)
|
||||||
|
{
|
||||||
|
MPEG_Shutdown();
|
||||||
|
|
||||||
|
if (memoryPool != NULL)
|
||||||
|
{
|
||||||
|
delete [] memoryPool;
|
||||||
|
memoryPool = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
progROM = NULL;
|
||||||
|
mpegROM = NULL;
|
||||||
|
ram = NULL;
|
||||||
|
mpegL = NULL;
|
||||||
|
mpegR = NULL;
|
||||||
|
|
||||||
|
DebugLog("Destroyed DSB2 Board\n");
|
||||||
|
}
|
256
Src/Model3/DSB.h
Normal file
256
Src/Model3/DSB.h
Normal file
|
@ -0,0 +1,256 @@
|
||||||
|
/**
|
||||||
|
** Supermodel
|
||||||
|
** A Sega Model 3 Arcade Emulator.
|
||||||
|
** Copyright 2011 Bart Trzynadlowski
|
||||||
|
**
|
||||||
|
** This file is part of Supermodel.
|
||||||
|
**
|
||||||
|
** Supermodel is free software: you can redistribute it and/or modify it under
|
||||||
|
** the terms of the GNU General Public License as published by the Free
|
||||||
|
** Software Foundation, either version 3 of the License, or (at your option)
|
||||||
|
** any later version.
|
||||||
|
**
|
||||||
|
** Supermodel is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
** FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
** more details.
|
||||||
|
**
|
||||||
|
** You should have received a copy of the GNU General Public License along
|
||||||
|
** with Supermodel. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
**/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* DSB.h
|
||||||
|
*
|
||||||
|
* Header file for the Sega Digital Sound Board (Type 1 and 2) devices. CDSB1
|
||||||
|
* is an implementation of the Z80-based DSB Type 1, and CDSB2 is the 68K-based
|
||||||
|
* Type 2 board. Only one may be active at a time because they rely on non-
|
||||||
|
* reentrant MPEG playback code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef INCLUDED_DSB_H
|
||||||
|
#define INCLUDED_DSB_H
|
||||||
|
|
||||||
|
#include "Types.h"
|
||||||
|
#include "CPU/Bus.h"
|
||||||
|
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
Resampling
|
||||||
|
|
||||||
|
Used internally by the DSB's MPEG code. If this becomes sufficiently generic,
|
||||||
|
it can be moved to Sound/. Not intended for general use for now.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* CDSBResampler:
|
||||||
|
*
|
||||||
|
* Frame-by-frame resampler. Resamples one single frame of audio and maintains
|
||||||
|
* continuity between frames by copying unprocessed input samples to the
|
||||||
|
* beginning of the buffer and retaining the internal interpolation state.
|
||||||
|
*
|
||||||
|
* See DSB.cpp for a detailed description of how this works.
|
||||||
|
*
|
||||||
|
* NOTE: If the sampling frequencies change, it is probably best to call
|
||||||
|
* Reset(). Whether the resampler will otherwise behave correctly and stay
|
||||||
|
* within array bounds has not been verified.
|
||||||
|
*
|
||||||
|
* Designed for use at 60 Hz, for input frequencies of 11.025, 22.05, 16, and
|
||||||
|
* 32 KHz and 44.1 KHz output frequencies. Theoretically, it should be able to
|
||||||
|
* operate on most output frequencies and input frequencies that are simply
|
||||||
|
* lower, but it has not been extensively verified.
|
||||||
|
*/
|
||||||
|
class CDSBResampler
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
int UpSampleAndMix(INT16 *outL, INT16 *outR, INT16 *inL, INT16 *inR, int sizeOut, int sizeIn, int outRate, int inRate);
|
||||||
|
void Reset(void);
|
||||||
|
private:
|
||||||
|
int nFrac;
|
||||||
|
int pFrac;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
DSB Base Class
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* CDSB:
|
||||||
|
*
|
||||||
|
* Abstract base class defining the common interface for both DSB board types.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class CDSB: public CBus
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/*
|
||||||
|
* SendCommand(data):
|
||||||
|
*
|
||||||
|
* Send a MIDI command to the DSB board.
|
||||||
|
*/
|
||||||
|
virtual void SendCommand(UINT8 data) = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* RunFrame(audioL, audioR):
|
||||||
|
*
|
||||||
|
* Runs one frame and updates the MPEG audio. Audio is mixed into the
|
||||||
|
* supplied buffers (they are assumed to already contain audio data).
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* audioL Left audio channel, one frame (44 KHz, 1/60th second).
|
||||||
|
* audioR Right audio channel.
|
||||||
|
*/
|
||||||
|
virtual void RunFrame(INT16 *audioL, INT16 *audioR) = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Reset(void):
|
||||||
|
*
|
||||||
|
* Resets the DSB. Must be called prior to RunFrame().
|
||||||
|
*/
|
||||||
|
virtual void Reset(void) = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Init(progROMPtr, mpegROMPtr):
|
||||||
|
*
|
||||||
|
* Initializes the DSB board. This member must be called first.
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* progROMPtr Program (68K or Z80) ROM.
|
||||||
|
* mpegROMPtr MPEG data ROM.
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* OKAY if successful, otherwise FAIL.
|
||||||
|
*/
|
||||||
|
virtual BOOL Init(const UINT8 *progROMPtr, const UINT8 *mpegROMPtr) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
DSB Classes
|
||||||
|
|
||||||
|
DSB1 and DSB2 hardware. The base class, CDSB, should ideally be dynamically
|
||||||
|
allocated using one of these. See CDSB for descriptions of member functions.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* CDSB1:
|
||||||
|
*
|
||||||
|
* Sega Digital Sound Board Type 1: Z80 plus custom gate array for MPEG
|
||||||
|
* decoding.
|
||||||
|
*/
|
||||||
|
class CDSB1: public CDSB
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// Read and write handlers for the Z80 (required by CBus)
|
||||||
|
UINT8 IORead8(UINT32 addr);
|
||||||
|
void IOWrite8(UINT32 addr, UINT8 data);
|
||||||
|
UINT8 Read8(UINT32 addr);
|
||||||
|
void Write8(UINT32 addr, UINT8 data);
|
||||||
|
|
||||||
|
// DSB interface (see CDSB definition)
|
||||||
|
void SendCommand(UINT8 data);
|
||||||
|
void RunFrame(INT16 *audioL, INT16 *audioR);
|
||||||
|
void Reset(void);
|
||||||
|
BOOL Init(const UINT8 *progROMPtr, const UINT8 *mpegROMPtr);
|
||||||
|
|
||||||
|
// Constructor and destructor
|
||||||
|
CDSB1(void);
|
||||||
|
~CDSB1(void);
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Resampler
|
||||||
|
CDSBResampler Resampler;
|
||||||
|
int retainedSamples; // how many MPEG samples carried over from previous frame
|
||||||
|
|
||||||
|
// MPEG decode buffers (48KHz, 1/60th second + 2 extra padding samples)
|
||||||
|
INT16 *mpegL, *mpegR;
|
||||||
|
|
||||||
|
// DSB memory
|
||||||
|
const UINT8 *progROM; // Z80 program ROM (passed in from parent object)
|
||||||
|
const UINT8 *mpegROM; // MPEG music ROM
|
||||||
|
UINT8 *memoryPool; // all memory allocated here
|
||||||
|
UINT8 *ram; // Z80 RAM
|
||||||
|
|
||||||
|
// Command FIFO
|
||||||
|
UINT8 fifo[128];
|
||||||
|
int fifoIdxR; // read position
|
||||||
|
int fifoIdxW; // write position
|
||||||
|
|
||||||
|
// MPEG playback variables
|
||||||
|
int mpegStart;
|
||||||
|
int mpegEnd;
|
||||||
|
int mpegState;
|
||||||
|
int loopStart;
|
||||||
|
int loopEnd;
|
||||||
|
|
||||||
|
// Registers
|
||||||
|
UINT32 startLatch; // MPEG start address latch
|
||||||
|
UINT32 endLatch; // MPEG end address latch
|
||||||
|
UINT8 status;
|
||||||
|
UINT8 chain;
|
||||||
|
UINT8 cmdLatch;
|
||||||
|
|
||||||
|
// Z80 CPU
|
||||||
|
CZ80 Z80;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* CDSB2:
|
||||||
|
*
|
||||||
|
* Sega Digital Sound Board Type 2: 68K CPU.
|
||||||
|
*/
|
||||||
|
class CDSB2: public CDSB
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// Read and write handlers for the 68K (required by CBus)
|
||||||
|
UINT8 Read8(UINT32 addr);
|
||||||
|
UINT16 Read16(UINT32 addr);
|
||||||
|
UINT32 Read32(UINT32 addr);
|
||||||
|
void Write8(UINT32 addr, UINT8 data);
|
||||||
|
void Write16(UINT32 addr, UINT16 data);
|
||||||
|
void Write32(UINT32 addr, UINT32 data);
|
||||||
|
|
||||||
|
// DSB interface (see definition of CDSB)
|
||||||
|
void SendCommand(UINT8 data);
|
||||||
|
void RunFrame(INT16 *audioL, INT16 *audioR);
|
||||||
|
void Reset(void);
|
||||||
|
BOOL Init(const UINT8 *progROMPtr, const UINT8 *mpegROMPtr);
|
||||||
|
|
||||||
|
// Constructor and destructor
|
||||||
|
CDSB2(void);
|
||||||
|
~CDSB2(void);
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Private helper functions
|
||||||
|
void WriteMPEGFIFO(UINT8 byte);
|
||||||
|
|
||||||
|
// Resampler
|
||||||
|
CDSBResampler Resampler;
|
||||||
|
int retainedSamples; // how many MPEG samples carried over from previous frame
|
||||||
|
|
||||||
|
// MPEG decode buffers (48KHz, 1/60th second + 2 extra padding samples)
|
||||||
|
INT16 *mpegL, *mpegR;
|
||||||
|
|
||||||
|
// DSB memory
|
||||||
|
const UINT8 *progROM; // Z80 program ROM (passed in from parent object)
|
||||||
|
const UINT8 *mpegROM; // MPEG music ROM
|
||||||
|
UINT8 *memoryPool; // all memory allocated here
|
||||||
|
UINT8 *ram; // Z80 RAM
|
||||||
|
|
||||||
|
// Command FIFO
|
||||||
|
UINT8 fifo[128];
|
||||||
|
int fifoIdxR; // read position
|
||||||
|
int fifoIdxW; // write position
|
||||||
|
|
||||||
|
// Registers
|
||||||
|
int cmdLatch;
|
||||||
|
int mpegState;
|
||||||
|
int mpegStart, mpegEnd, playing;
|
||||||
|
|
||||||
|
// M68K CPU
|
||||||
|
M68KCtx M68K;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // INCLUDED_DSB_H
|
|
@ -1,5 +1,6 @@
|
||||||
//TODO: Update save state file format (must output) MIDI control port; will no longer be compatible with 0.1a save states
|
//TODO: Update save state file format (must output) MIDI control port; will no longer be compatible with 0.1a save states
|
||||||
//TODO: should sample roms be byteswapped? They currently are. This could also be done in the game list with the byteswap flag...
|
//TODO: Star Wars expects bit 0x80 to be set when reading from MIDI control port. This should be made explicit! Lostwsga may behave similarly
|
||||||
|
|
||||||
/**
|
/**
|
||||||
** Supermodel
|
** Supermodel
|
||||||
** A Sega Model 3 Arcade Emulator.
|
** A Sega Model 3 Arcade Emulator.
|
||||||
|
@ -1125,7 +1126,7 @@ void CModel3::Write8(UINT32 addr, UINT8 data)
|
||||||
|
|
||||||
// Sound Board
|
// Sound Board
|
||||||
case 0x08:
|
case 0x08:
|
||||||
printf("PPC: %08X=%02X * (PC=%08X, LR=%08X)\n", addr, data, ppc_get_pc(), ppc_get_lr());
|
//printf("PPC: %08X=%02X * (PC=%08X, LR=%08X)\n", addr, data, ppc_get_pc(), ppc_get_lr());
|
||||||
if ((addr&0xF) == 0) // MIDI data port
|
if ((addr&0xF) == 0) // MIDI data port
|
||||||
SoundBoard.WriteMIDIPort(data);
|
SoundBoard.WriteMIDIPort(data);
|
||||||
else if ((addr&0xF) == 4) // MIDI control port
|
else if ((addr&0xF) == 4) // MIDI control port
|
||||||
|
@ -2112,23 +2113,38 @@ void CModel3::RunMainBoardFrame(void)
|
||||||
IRQ.Assert(0x02);
|
IRQ.Assert(0x02);
|
||||||
ppc_execute(10000); // TO-DO: Vblank probably needs to be longer. Maybe that's why some games run too fast/slow
|
ppc_execute(10000); // TO-DO: Vblank probably needs to be longer. Maybe that's why some games run too fast/slow
|
||||||
|
|
||||||
// Sound
|
/*
|
||||||
|
* Sound:
|
||||||
|
*
|
||||||
|
* Bit 0x20 of the MIDI control port appears to enable periodic interrupts,
|
||||||
|
* which are used to send MIDI commands. Often games will write 0x27, send
|
||||||
|
* a series of commands, and write 0x06 to stop. Other games, like Star
|
||||||
|
* Wars Trilogy and Sega Rally 2, will enable interrupts at the beginning
|
||||||
|
* by writing 0x37 and will disable/enable interrupts to control command
|
||||||
|
* output.
|
||||||
|
*/
|
||||||
int irqCount = 0;
|
int irqCount = 0;
|
||||||
while (midiCtrlPort == 0x27) // 27 triggers IRQ sequence, 06 stops it
|
while ((midiCtrlPort&0x20))
|
||||||
|
//while (midiCtrlPort == 0x27) // 27 triggers IRQ sequence, 06 stops it
|
||||||
{
|
{
|
||||||
|
// Don't waste time firing MIDI interrupts if game has disabled them
|
||||||
|
if ((IRQ.ReadIRQEnable()&0x40) == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Process MIDI interrupt
|
||||||
IRQ.Assert(0x40);
|
IRQ.Assert(0x40);
|
||||||
ppc_execute(200);
|
ppc_execute(200); // give PowerPC time to acknowledge IRQ
|
||||||
IRQ.Deassert(0x40);
|
IRQ.Deassert(0x40);
|
||||||
ppc_execute(200);
|
ppc_execute(200); // acknowledge that IRQ was deasserted (TODO: is this really needed?)
|
||||||
|
|
||||||
++irqCount;
|
++irqCount;
|
||||||
if (irqCount > (128))
|
if (irqCount > 128)
|
||||||
{
|
{
|
||||||
printf("MIDI TIMEOUT!\n");
|
printf("MIDI FIFO OVERFLOW!\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
IRQ.Deassert(0x40);
|
IRQ.Deassert(0x40); //todo: no longer needed, remove it
|
||||||
}
|
}
|
||||||
|
|
||||||
void CModel3::Reset(void)
|
void CModel3::Reset(void)
|
||||||
|
@ -2409,9 +2425,11 @@ static void Dump(const char *file, UINT8 *buf, unsigned size, BOOL reverse32, BO
|
||||||
#define OFFSET_VROM 0x9000000 // 64 MB
|
#define OFFSET_VROM 0x9000000 // 64 MB
|
||||||
#define OFFSET_BACKUPRAM 0xD000000 // 128 KB
|
#define OFFSET_BACKUPRAM 0xD000000 // 128 KB
|
||||||
#define OFFSET_SECURITYRAM 0xD020000 // 128 KB
|
#define OFFSET_SECURITYRAM 0xD020000 // 128 KB
|
||||||
#define OFFSET_SOUNDROM 0xD040000 // 512 KB
|
#define OFFSET_SOUNDROM 0xD040000 // 512 KB (68K sound board program)
|
||||||
#define OFFSET_SAMPLEROM 0xD0C0000 // 16 MB
|
#define OFFSET_SAMPLEROM 0xD0C0000 // 16 MB (sound board samples)
|
||||||
#define MEMORY_POOL_SIZE (0x800000+0x800000+0x8000000+0x4000000+0x20000+0x20000+0x80000+0x1000000)
|
#define OFFSET_DSBPROGROM 0xE0C0000 // 128 KB (DSB program)
|
||||||
|
#define OFFSET_DSBMPEGROM 0xE0E0000 // 16 MB (DSB MPEG data -- Z80 version only uses 8MB)
|
||||||
|
#define MEMORY_POOL_SIZE (0x800000+0x800000+0x8000000+0x4000000+0x20000+0x20000+0x80000+0x1000000+0x20000+0x1000000)
|
||||||
|
|
||||||
const struct GameInfo * CModel3::GetGameInfo(void)
|
const struct GameInfo * CModel3::GetGameInfo(void)
|
||||||
{
|
{
|
||||||
|
@ -2428,6 +2446,8 @@ BOOL CModel3::LoadROMSet(const struct GameInfo *GameList, const char *zipFile)
|
||||||
{ "VROM", vrom },
|
{ "VROM", vrom },
|
||||||
{ "SndProg", soundROM },
|
{ "SndProg", soundROM },
|
||||||
{ "Samples", sampleROM },
|
{ "Samples", sampleROM },
|
||||||
|
{ "DSBProg", dsbROM },
|
||||||
|
{ "DSBMPEG", mpegROM },
|
||||||
{ NULL, NULL }
|
{ NULL, NULL }
|
||||||
};
|
};
|
||||||
PPC_CONFIG PPCConfig;
|
PPC_CONFIG PPCConfig;
|
||||||
|
@ -2450,9 +2470,9 @@ BOOL CModel3::LoadROMSet(const struct GameInfo *GameList, const char *zipFile)
|
||||||
// Byte reverse the PowerPC ROMs (convert to little endian words)
|
// Byte reverse the PowerPC ROMs (convert to little endian words)
|
||||||
Reverse32(crom, 0x800000+0x8000000);
|
Reverse32(crom, 0x800000+0x8000000);
|
||||||
|
|
||||||
// Byte swap 68K ROMs
|
// Byte swap sound board 68K ROMs
|
||||||
Reverse16(soundROM, 0x80000);
|
Reverse16(soundROM, 0x80000);
|
||||||
Reverse16(sampleROM, 0x1000000); // is this correct?
|
Reverse16(sampleROM, 0x1000000);
|
||||||
|
|
||||||
// Initialize CPU and configure hardware (CPU speed is set in Init())
|
// Initialize CPU and configure hardware (CPU speed is set in Init())
|
||||||
if (Game->step >= 0x20) // Step 2.0+
|
if (Game->step >= 0x20) // Step 2.0+
|
||||||
|
@ -2499,6 +2519,26 @@ BOOL CModel3::LoadROMSet(const struct GameInfo *GameList, const char *zipFile)
|
||||||
|
|
||||||
ppc_set_fetch(PPCFetchRegions);
|
ppc_set_fetch(PPCFetchRegions);
|
||||||
|
|
||||||
|
// DSB board (if present)
|
||||||
|
if (Game->mpegBoard == 1) // Z80 board, do not byte swap program ROM
|
||||||
|
{
|
||||||
|
DSB = new(std::nothrow) CDSB1();
|
||||||
|
if (NULL == DSB)
|
||||||
|
return ErrorLog("Insufficient memory for Digital Sound Board object.");
|
||||||
|
if (OKAY != DSB->Init(dsbROM,mpegROM))
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
|
else if (Game->mpegBoard == 2) // 68K board
|
||||||
|
{
|
||||||
|
Reverse16(dsbROM, 0x20000); // byte swap program ROM
|
||||||
|
DSB = new(std::nothrow) CDSB2();
|
||||||
|
if (NULL == DSB)
|
||||||
|
return ErrorLog("Insufficient memory for Digital Sound Board object.");
|
||||||
|
if (OKAY != DSB->Init(dsbROM,mpegROM))
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
|
SoundBoard.AttachDSB(DSB);
|
||||||
|
|
||||||
// Apply ROM patches
|
// Apply ROM patches
|
||||||
Patch();
|
Patch();
|
||||||
|
|
||||||
|
@ -2525,6 +2565,7 @@ void CModel3::AttachInputs(CInputs *InputsPtr)
|
||||||
DebugLog("Model 3 attached inputs\n");
|
DebugLog("Model 3 attached inputs\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Model 3 initialization. Some initialization is deferred until ROMs are loaded in LoadROMSet()
|
||||||
BOOL CModel3::Init(unsigned ppcFrequencyParam, BOOL multiThreadedParam)
|
BOOL CModel3::Init(unsigned ppcFrequencyParam, BOOL multiThreadedParam)
|
||||||
{
|
{
|
||||||
float memSizeMB = (float)MEMORY_POOL_SIZE/(float)0x100000;
|
float memSizeMB = (float)MEMORY_POOL_SIZE/(float)0x100000;
|
||||||
|
@ -2546,11 +2587,13 @@ BOOL CModel3::Init(unsigned ppcFrequencyParam, BOOL multiThreadedParam)
|
||||||
vrom = &memoryPool[OFFSET_VROM];
|
vrom = &memoryPool[OFFSET_VROM];
|
||||||
soundROM = &memoryPool[OFFSET_SOUNDROM];
|
soundROM = &memoryPool[OFFSET_SOUNDROM];
|
||||||
sampleROM = &memoryPool[OFFSET_SAMPLEROM];
|
sampleROM = &memoryPool[OFFSET_SAMPLEROM];
|
||||||
|
dsbROM = &memoryPool[OFFSET_DSBPROGROM];
|
||||||
|
mpegROM = &memoryPool[OFFSET_DSBMPEGROM];
|
||||||
backupRAM = &memoryPool[OFFSET_BACKUPRAM];
|
backupRAM = &memoryPool[OFFSET_BACKUPRAM];
|
||||||
securityRAM = &memoryPool[OFFSET_SECURITYRAM];
|
securityRAM = &memoryPool[OFFSET_SECURITYRAM];
|
||||||
SetCROMBank(0xFF);
|
SetCROMBank(0xFF);
|
||||||
|
|
||||||
// Initialize other devices
|
// Initialize other devices (PowerPC and DSB initialized after ROMs loaded)
|
||||||
IRQ.Init();
|
IRQ.Init();
|
||||||
PCIBridge.Init();
|
PCIBridge.Init();
|
||||||
PCIBus.Init();
|
PCIBus.Init();
|
||||||
|
@ -2561,8 +2604,9 @@ BOOL CModel3::Init(unsigned ppcFrequencyParam, BOOL multiThreadedParam)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
if (OKAY != GPU.Init(vrom,this,&IRQ,0x100)) // same for Real3D DMA interrupt
|
if (OKAY != GPU.Init(vrom,this,&IRQ,0x100)) // same for Real3D DMA interrupt
|
||||||
return FAIL;
|
return FAIL;
|
||||||
if (OKAY != SoundBoard.Init(soundROM,sampleROM,&IRQ,0x40))
|
if (OKAY != SoundBoard.Init(soundROM,sampleROM))
|
||||||
return FAIL;
|
return FAIL;
|
||||||
|
|
||||||
#ifdef SUPERMODEL_DRIVEBOARD
|
#ifdef SUPERMODEL_DRIVEBOARD
|
||||||
DriveBoard.Init();
|
DriveBoard.Init();
|
||||||
#endif
|
#endif
|
||||||
|
@ -2589,10 +2633,14 @@ CModel3::CModel3(void)
|
||||||
vrom = NULL;
|
vrom = NULL;
|
||||||
soundROM = NULL;
|
soundROM = NULL;
|
||||||
sampleROM = NULL;
|
sampleROM = NULL;
|
||||||
|
dsbROM = NULL;
|
||||||
|
mpegROM = NULL;
|
||||||
cromBank = NULL;
|
cromBank = NULL;
|
||||||
backupRAM = NULL;
|
backupRAM = NULL;
|
||||||
securityRAM = NULL;
|
securityRAM = NULL;
|
||||||
|
|
||||||
|
DSB = NULL;
|
||||||
|
|
||||||
securityPtr = 0;
|
securityPtr = 0;
|
||||||
|
|
||||||
multiThreaded = true;
|
multiThreaded = true;
|
||||||
|
@ -2630,18 +2678,27 @@ CModel3::~CModel3(void)
|
||||||
// Stop all threads
|
// Stop all threads
|
||||||
StopThreads();
|
StopThreads();
|
||||||
|
|
||||||
|
// Free memory
|
||||||
if (memoryPool != NULL)
|
if (memoryPool != NULL)
|
||||||
{
|
{
|
||||||
delete [] memoryPool;
|
delete [] memoryPool;
|
||||||
memoryPool = NULL;
|
memoryPool = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (DSB != NULL)
|
||||||
|
{
|
||||||
|
delete DSB;
|
||||||
|
DSB = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
Game = NULL;
|
Game = NULL;
|
||||||
ram = NULL;
|
ram = NULL;
|
||||||
crom = NULL;
|
crom = NULL;
|
||||||
vrom = NULL;
|
vrom = NULL;
|
||||||
soundROM = NULL;
|
soundROM = NULL;
|
||||||
sampleROM = NULL;
|
sampleROM = NULL;
|
||||||
|
dsbROM = NULL;
|
||||||
|
mpegROM = NULL;
|
||||||
cromBank = NULL;
|
cromBank = NULL;
|
||||||
backupRAM = NULL;
|
backupRAM = NULL;
|
||||||
securityRAM = NULL;
|
securityRAM = NULL;
|
||||||
|
|
|
@ -250,7 +250,7 @@ public:
|
||||||
*/
|
*/
|
||||||
CModel3(void);
|
CModel3(void);
|
||||||
~CModel3(void);
|
~CModel3(void);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Private Property.
|
* Private Property.
|
||||||
* Tresspassers will be shot! ;)
|
* Tresspassers will be shot! ;)
|
||||||
|
@ -265,14 +265,14 @@ private:
|
||||||
UINT8 ReadSystemRegister(unsigned reg);
|
UINT8 ReadSystemRegister(unsigned reg);
|
||||||
void WriteSystemRegister(unsigned reg, UINT8 data);
|
void WriteSystemRegister(unsigned reg, UINT8 data);
|
||||||
void Patch(void);
|
void Patch(void);
|
||||||
|
|
||||||
void RunMainBoardFrame(); // Runs the main board (PPC) for a frame
|
void RunMainBoardFrame(); // Runs the main board (PPC) for a frame
|
||||||
bool StartThreads(); // Starts all threads
|
bool StartThreads(); // Starts all threads
|
||||||
void StopThreads(); // Stops all threads
|
void StopThreads(); // Stops all threads
|
||||||
void DeleteThreadObjects(); // Deletes all threads and synchronization objects
|
void DeleteThreadObjects(); // Deletes all threads and synchronization objects
|
||||||
|
|
||||||
static int StartSoundBoardThread(void *data); // Callback to start sound board thread
|
static int StartSoundBoardThread(void *data); // Callback to start sound board thread
|
||||||
#ifdef SUPERMODEL_DRIVEBOARD
|
#ifdef SUPERMODEL_DRIVEBOARD
|
||||||
static int StartDriveBoardThread(void *data); // Callback to start drive board thread
|
static int StartDriveBoardThread(void *data); // Callback to start drive board thread
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -303,6 +303,8 @@ private:
|
||||||
UINT8 *vrom; // 64 MB VROM (video ROM, visible only to Real3D)
|
UINT8 *vrom; // 64 MB VROM (video ROM, visible only to Real3D)
|
||||||
UINT8 *soundROM; // 512 KB sound ROM (68K program)
|
UINT8 *soundROM; // 512 KB sound ROM (68K program)
|
||||||
UINT8 *sampleROM; // 8 MB samples (68K)
|
UINT8 *sampleROM; // 8 MB samples (68K)
|
||||||
|
UINT8 *dsbROM; // 128 KB DSB ROM (Z80 program)
|
||||||
|
UINT8 *mpegROM; // 8 MB DSB MPEG ROM
|
||||||
UINT8 *backupRAM; // 128 KB Backup RAM (battery backed)
|
UINT8 *backupRAM; // 128 KB Backup RAM (battery backed)
|
||||||
UINT8 *securityRAM; // 128 KB Security Board RAM
|
UINT8 *securityRAM; // 128 KB Security Board RAM
|
||||||
|
|
||||||
|
@ -318,23 +320,23 @@ private:
|
||||||
unsigned ppcFrequency; // clock frequency (Hz)
|
unsigned ppcFrequency; // clock frequency (Hz)
|
||||||
|
|
||||||
// Multiple threading
|
// Multiple threading
|
||||||
bool multiThreaded; // True if should run CPUs in multiple threads, otherwise everything is run in a single thread
|
bool multiThreaded; // True if should run CPUs in multiple threads, otherwise everything is run in a single thread
|
||||||
bool startedThreads; // True if threads have been created and started
|
bool startedThreads; // True if threads have been created and started
|
||||||
CThread *sndBrdThread; // Sound board thread
|
CThread *sndBrdThread; // Sound board thread
|
||||||
#ifdef SUPERMODEL_DRIVEBOARD
|
#ifdef SUPERMODEL_DRIVEBOARD
|
||||||
CThread *drvBrdThread; // Drive board thread
|
CThread *drvBrdThread; // Drive board thread
|
||||||
#endif
|
#endif
|
||||||
bool sndBrdThreadDone; // Flag to indicate sound board thread has finished processing for current frame
|
bool sndBrdThreadDone; // Flag to indicate sound board thread has finished processing for current frame
|
||||||
#ifdef SUPERMODEL_DRIVEBOARD
|
#ifdef SUPERMODEL_DRIVEBOARD
|
||||||
bool drvBrdThreadDone; // Flag to indicate drive board thread has finished processing for current frame
|
bool drvBrdThreadDone; // Flag to indicate drive board thread has finished processing for current frame
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Thread synchronization objects
|
// Thread synchronization objects
|
||||||
CSemaphore *sndBrdThreadSync;
|
CSemaphore *sndBrdThreadSync;
|
||||||
#ifdef SUPERMODEL_DRIVEBOARD
|
#ifdef SUPERMODEL_DRIVEBOARD
|
||||||
CSemaphore *drvBrdThreadSync;
|
CSemaphore *drvBrdThreadSync;
|
||||||
#endif
|
#endif
|
||||||
CMutex *notifyLock;
|
CMutex *notifyLock;
|
||||||
CCondVar *notifySync;
|
CCondVar *notifySync;
|
||||||
|
|
||||||
// Other devices
|
// Other devices
|
||||||
|
@ -346,7 +348,8 @@ private:
|
||||||
C93C46 EEPROM; // 93C46 EEPROM
|
C93C46 EEPROM; // 93C46 EEPROM
|
||||||
CTileGen TileGen; // Sega 2D tile generator
|
CTileGen TileGen; // Sega 2D tile generator
|
||||||
CReal3D GPU; // Real3D graphics hardware
|
CReal3D GPU; // Real3D graphics hardware
|
||||||
CSoundBoard SoundBoard; // Sound board
|
CSoundBoard SoundBoard; // Sound board
|
||||||
|
CDSB *DSB; // Digital Sound Board (type determined dynamically at load time)
|
||||||
#ifdef SUPERMODEL_DRIVEBOARD
|
#ifdef SUPERMODEL_DRIVEBOARD
|
||||||
CDriveBoard DriveBoard; // Drive board
|
CDriveBoard DriveBoard; // Drive board
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
//TODO: clean up M68K interface. pass a bus pointer (SoundBoard should be derived from it), so that M68K handlers have access to CSoundBoard
|
|
||||||
//TODO: must store actual value of bank register so we can save it to save states
|
//TODO: must store actual value of bank register so we can save it to save states
|
||||||
/**
|
/**
|
||||||
** Supermodel
|
** Supermodel
|
||||||
|
@ -26,11 +25,7 @@
|
||||||
*
|
*
|
||||||
* Model 3 sound board. Implementation of the CSoundBoard class. This class can
|
* Model 3 sound board. Implementation of the CSoundBoard class. This class can
|
||||||
* only be instantiated once because it relies on global variables (the non-OOP
|
* only be instantiated once because it relies on global variables (the non-OOP
|
||||||
* 68K core).
|
* 68K core and an IRQ line).
|
||||||
*
|
|
||||||
* TO-DO List
|
|
||||||
* ----------
|
|
||||||
* - Optimize memory handlers (jump table).
|
|
||||||
*
|
*
|
||||||
* Bank Switching
|
* Bank Switching
|
||||||
* --------------
|
* --------------
|
||||||
|
@ -62,248 +57,261 @@
|
||||||
|
|
||||||
#include "Supermodel.h"
|
#include "Supermodel.h"
|
||||||
|
|
||||||
//TEMP: these need to be dynamically allocated in the memory pool
|
// DEBUG
|
||||||
static INT16 leftBuffer[44100/60],rightBuffer[44100/60];
|
//#define SUPERMODEL_LOG_AUDIO // define this to log all audio to sound.bin
|
||||||
|
#ifdef SUPERMODEL_LOG_AUDIO
|
||||||
static FILE *soundFP;
|
static FILE *soundFP;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
68K Access Handlers
|
68K Access Handlers
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
// Memory regions passed out of CSoundBoard object for global access handlers
|
UINT8 CSoundBoard::Read8(UINT32 a)
|
||||||
static UINT8 *sbRAM1, *sbRAM2;
|
|
||||||
static const UINT8 *sbSoundROM, *sbSampleROM, *sbSampleBankLo, *sbSampleBankHi;
|
|
||||||
|
|
||||||
static UINT8 Read8(UINT32 a)
|
|
||||||
{
|
{
|
||||||
// SCSP RAM 1
|
switch ((a>>20)&0xF)
|
||||||
if ((a >= 0x000000) && (a <= 0x0FFFFF))
|
{
|
||||||
return sbRAM1[a^1];
|
case 0x0: // SCSP RAM 1 (master): 000000-0FFFFF
|
||||||
|
return ram1[a^1];
|
||||||
// SCSP RAM 2
|
|
||||||
else if ((a >= 0x200000) && (a <= 0x2FFFFF))
|
|
||||||
return sbRAM2[(a-0x200000)^1];
|
|
||||||
|
|
||||||
// Program ROM
|
case 0x1: // SCSP registers (master): 100000-10FFFF (unlike real hardware, we mirror up to 1FFFFF)
|
||||||
else if ((a >= 0x600000) && (a <= 0x67FFFF))
|
|
||||||
return sbSoundROM[(a-0x600000)^1];
|
|
||||||
|
|
||||||
// Sample ROM (low 2MB, fixed)
|
|
||||||
else if ((a >= 0x800000) && (a <= 0x9FFFFF))
|
|
||||||
return sbSampleROM[(a-0x800000)^1];
|
|
||||||
|
|
||||||
// Sample ROM (bank)
|
|
||||||
else if ((a >= 0xA00000) && (a <= 0xDFFFFF))
|
|
||||||
return sbSampleBankLo[(a-0xA00000)^1];
|
|
||||||
|
|
||||||
// Sample ROM (bank)
|
|
||||||
else if ((a >= 0xE00000) && (a <= 0xFFFFFF))
|
|
||||||
return sbSampleBankHi[(a-0xE00000)^1];
|
|
||||||
|
|
||||||
// SCSP (Master)
|
|
||||||
else if ((a >= 0x100000) && (a <= 0x10FFFF))
|
|
||||||
return SCSP_Master_r8(a);
|
return SCSP_Master_r8(a);
|
||||||
|
|
||||||
// SCSP (Slave)
|
case 0x2: // SCSP RAM 2 (slave): 200000-2FFFFF
|
||||||
else if ((a >= 0x300000) && (a <= 0x30FFFF))
|
return ram2[(a&0x0FFFFF)^1];
|
||||||
|
|
||||||
|
case 0x3: // SCSP registers (slave): 300000-30FFFF (unlike real hardware, we mirror up to 3FFFFF)
|
||||||
return SCSP_Slave_r8(a);
|
return SCSP_Slave_r8(a);
|
||||||
|
|
||||||
// Unknown
|
case 0x6: // Program ROM: 600000-67FFFF (unlike real hardware, we mirror up to 6FFFFF here)
|
||||||
else
|
return soundROM[(a&0x07FFFF)^1];
|
||||||
{
|
|
||||||
|
case 0x8: // Sample ROM (low 2MB, fixed): 800000-9FFFFF
|
||||||
|
case 0x9:
|
||||||
|
return sampleROM[(a&0x1FFFFF)^1];
|
||||||
|
|
||||||
|
case 0xA: // Sample ROM (bank): A00000-DFFFFF
|
||||||
|
case 0xB:
|
||||||
|
case 0xC:
|
||||||
|
case 0xD:
|
||||||
|
return sampleBankLo[(a-0xA00000)^1];
|
||||||
|
|
||||||
|
case 0xE: // Sample ROM (bank): E00000-FFFFFF
|
||||||
|
case 0xF:
|
||||||
|
return sampleBankHi[(a&0x1FFFFF)^1];
|
||||||
|
|
||||||
|
default:
|
||||||
printf("68K: Unknown read8 %06X\n", a);
|
printf("68K: Unknown read8 %06X\n", a);
|
||||||
return 0;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static UINT16 Read16(UINT32 a)
|
UINT16 CSoundBoard::Read16(UINT32 a)
|
||||||
{
|
{
|
||||||
// SCSP RAM 1
|
switch ((a>>20)&0xF)
|
||||||
if ((a >= 0x000000) && (a <= 0x0FFFFF))
|
{
|
||||||
return *(UINT16 *) &sbRAM1[a];
|
case 0x0: // SCSP RAM 1 (master): 000000-0FFFFF
|
||||||
|
return *(UINT16 *) &ram1[a];
|
||||||
// SCSP RAM 2
|
|
||||||
else if ((a >= 0x200000) && (a <= 0x2FFFFF))
|
|
||||||
return *(UINT16 *) &sbRAM2[(a-0x200000)];
|
|
||||||
|
|
||||||
// Program ROM
|
case 0x1: // SCSP registers (master): 100000-10FFFF
|
||||||
else if ((a >= 0x600000) && (a <= 0x67FFFF))
|
|
||||||
return *(UINT16 *) &sbSoundROM[(a-0x600000)];
|
|
||||||
|
|
||||||
// Sample ROM (low 2MB, fixed)
|
|
||||||
else if ((a >= 0x800000) && (a <= 0x9FFFFF))
|
|
||||||
return *(UINT16 *) &sbSampleROM[(a-0x800000)];
|
|
||||||
|
|
||||||
// Sample ROM (bank)
|
|
||||||
else if ((a >= 0xA00000) && (a <= 0xDFFFFF))
|
|
||||||
return *(UINT16 *) &sbSampleBankLo[(a-0xA00000)];
|
|
||||||
|
|
||||||
// Sample ROM (bank)
|
|
||||||
else if ((a >= 0xE00000) && (a <= 0xFFFFFF))
|
|
||||||
return *(UINT16 *) &sbSampleBankHi[(a-0xE00000)];
|
|
||||||
|
|
||||||
// SCSP (Master)
|
|
||||||
else if ((a >= 0x100000) && (a <= 0x10FFFF))
|
|
||||||
return SCSP_Master_r16(a);
|
return SCSP_Master_r16(a);
|
||||||
|
|
||||||
// SCSP (Slave)
|
case 0x2: // SCSP RAM 2 (slave): 200000-2FFFFF
|
||||||
else if ((a >= 0x300000) && (a <= 0x30FFFF))
|
return *(UINT16 *) &ram2[a&0x0FFFFF];
|
||||||
|
|
||||||
|
case 0x3: // SCSP registers (slave): 300000-30FFFF
|
||||||
return SCSP_Slave_r16(a);
|
return SCSP_Slave_r16(a);
|
||||||
|
|
||||||
// Unknown
|
case 0x6: // Program ROM: 600000-67FFFF
|
||||||
else
|
return *(UINT16 *) &soundROM[a&0x07FFFF];
|
||||||
{
|
|
||||||
|
case 0x8: // Sample ROM (low 2MB, fixed): 800000-9FFFFF
|
||||||
|
case 0x9:
|
||||||
|
return *(UINT16 *) &sampleROM[a&0x1FFFFF];
|
||||||
|
|
||||||
|
case 0xA: // Sample ROM (bank): A00000-DFFFFF
|
||||||
|
case 0xB:
|
||||||
|
case 0xC:
|
||||||
|
case 0xD:
|
||||||
|
return *(UINT16 *) &sampleBankLo[a-0xA00000];
|
||||||
|
|
||||||
|
case 0xE: // Sample ROM (bank): E00000-FFFFFF
|
||||||
|
case 0xF:
|
||||||
|
return *(UINT16 *) &sampleBankHi[a&0x1FFFFF];
|
||||||
|
|
||||||
|
default:
|
||||||
printf("68K: Unknown read16 %06X\n", a);
|
printf("68K: Unknown read16 %06X\n", a);
|
||||||
return 0;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static UINT32 Read32(UINT32 a)
|
UINT32 CSoundBoard::Read32(UINT32 a)
|
||||||
{
|
{
|
||||||
// SCSP RAM 1
|
UINT32 hi, lo;
|
||||||
if ((a >= 0x000000) && (a <= 0x0FFFFF))
|
|
||||||
return (Read16(a)<<16)|Read16(a+2);
|
|
||||||
|
|
||||||
// SCSP RAM 2
|
switch ((a>>20)&0xF)
|
||||||
else if ((a >= 0x200000) && (a <= 0x2FFFFF))
|
{
|
||||||
return (Read16(a)<<16)|Read16(a+2);
|
case 0x0: // SCSP RAM 1 (master): 000000-0FFFFF
|
||||||
|
hi = *(UINT16 *) &ram1[a];
|
||||||
|
lo = *(UINT16 *) &ram1[a+2]; // TODO: clamp? Possible bounds hazard.
|
||||||
|
return (hi<<16)|lo;
|
||||||
|
|
||||||
// Program ROM
|
case 0x1: // SCSP registers (master): 100000-10FFFF
|
||||||
else if ((a >= 0x600000) && (a <= 0x67FFFF))
|
|
||||||
return (Read16(a)<<16)|Read16(a+2);
|
|
||||||
|
|
||||||
// Sample ROM (low 2MB, fixed)
|
|
||||||
else if ((a >= 0x800000) && (a <= 0x9FFFFF))
|
|
||||||
return (Read16(a)<<16)|Read16(a+2);
|
|
||||||
|
|
||||||
// Sample ROM (bank)
|
|
||||||
else if ((a >= 0xA00000) && (a <= 0xDFFFFF))
|
|
||||||
return (Read16(a)<<16)|Read16(a+2);
|
|
||||||
|
|
||||||
// Sample ROM (bank)
|
|
||||||
else if ((a >= 0xE00000) && (a <= 0xFFFFFF))
|
|
||||||
return (Read16(a)<<16)|Read16(a+2);
|
|
||||||
|
|
||||||
// SCSP (Master)
|
|
||||||
else if ((a >= 0x100000) && (a <= 0x10FFFF))
|
|
||||||
return SCSP_Master_r32(a);
|
return SCSP_Master_r32(a);
|
||||||
|
|
||||||
// SCSP (Slave)
|
case 0x2: // SCSP RAM 2 (slave): 200000-2FFFFF
|
||||||
else if ((a >= 0x300000) && (a <= 0x30FFFF))
|
hi = *(UINT16 *) &ram2[a&0x0FFFFF];
|
||||||
|
lo = *(UINT16 *) &ram2[(a+2)&0x0FFFFF];
|
||||||
|
return (hi<<16)|lo;
|
||||||
|
|
||||||
|
case 0x3: // SCSP registers (slave): 300000-30FFFF
|
||||||
return SCSP_Slave_r32(a);
|
return SCSP_Slave_r32(a);
|
||||||
|
|
||||||
// Unknown
|
case 0x6: // Program ROM: 600000-67FFFF
|
||||||
else
|
hi = *(UINT16 *) &soundROM[a&0x07FFFF];
|
||||||
{
|
lo = *(UINT16 *) &soundROM[(a+2)&0x07FFFF];
|
||||||
|
return (hi<<16)|lo;
|
||||||
|
|
||||||
|
case 0x8: // Sample ROM (low 2MB, fixed): 800000-9FFFFF
|
||||||
|
case 0x9:
|
||||||
|
hi = *(UINT16 *) &sampleROM[a&0x1FFFFF];
|
||||||
|
lo = *(UINT16 *) &sampleROM[(a+2)&0x1FFFFF];
|
||||||
|
return (hi<<16)|lo;
|
||||||
|
|
||||||
|
case 0xA: // Sample ROM (bank): A00000-DFFFFF
|
||||||
|
case 0xB:
|
||||||
|
case 0xC:
|
||||||
|
case 0xD:
|
||||||
|
hi = *(UINT16 *) &sampleBankLo[a-0xA00000];
|
||||||
|
lo = *(UINT16 *) &sampleBankLo[a+2-0xA00000];
|
||||||
|
return (hi<<16)|lo;
|
||||||
|
|
||||||
|
case 0xE: // Sample ROM (bank): E00000-FFFFFF
|
||||||
|
case 0xF:
|
||||||
|
hi = *(UINT16 *) &sampleBankHi[a&0x1FFFFF];
|
||||||
|
lo = *(UINT16 *) &sampleBankHi[(a+2)&0x1FFFFF];
|
||||||
|
return (hi<<16)|lo;
|
||||||
|
|
||||||
|
default:
|
||||||
printf("68K: Unknown read32 %06X\n", a);
|
printf("68K: Unknown read32 %06X\n", a);
|
||||||
return 0;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Write8(unsigned int a,unsigned char d)
|
void CSoundBoard::Write8(unsigned int a,unsigned char d)
|
||||||
{
|
{
|
||||||
|
switch ((a>>20)&0xF)
|
||||||
// SCSP RAM 1
|
|
||||||
if ((a >= 0x000000) && (a <= 0x0FFFFF))
|
|
||||||
sbRAM1[a^1] = d;
|
|
||||||
|
|
||||||
// SCSP RAM 2
|
|
||||||
else if ((a >= 0x200000) && (a <= 0x2FFFFF))
|
|
||||||
sbRAM2[(a-0x200000)^1] = d;
|
|
||||||
|
|
||||||
// SCSP (Master)
|
|
||||||
else if ((a >= 0x100000) && (a <= 0x10FFFF))
|
|
||||||
SCSP_Master_w8(a,d);
|
|
||||||
|
|
||||||
// SCSP (Slave)
|
|
||||||
else if ((a >= 0x300000) && (a <= 0x30FFFF))
|
|
||||||
SCSP_Slave_w8(a,d);
|
|
||||||
|
|
||||||
// Bank register
|
|
||||||
else if (a == 0x400001)
|
|
||||||
{
|
{
|
||||||
if ((d&0x10))
|
case 0x0: // SCSP RAM 1 (master): 000000-0FFFFF
|
||||||
|
ram1[a^1] = d;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x1: // SCSP registers (master): 100000-10FFFF
|
||||||
|
SCSP_Master_w8(a,d);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x2: // SCSP RAM 2 (slave): 200000-2FFFFF
|
||||||
|
ram2[(a&0x0FFFFF)^1] = d;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x3: // SCSP registers (slave): 300000-30FFFF
|
||||||
|
SCSP_Slave_w8(a,d);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
if (a == 0x400001)
|
||||||
{
|
{
|
||||||
sbSampleBankLo = &sbSampleROM[0xA00000];
|
if ((d&0x10))
|
||||||
sbSampleBankHi = &sbSampleROM[0xE00000];
|
{
|
||||||
|
sampleBankLo = &sampleROM[0xA00000];
|
||||||
|
sampleBankHi = &sampleROM[0xE00000];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sampleBankLo = &sampleROM[0x200000];
|
||||||
|
sampleBankHi = &sampleROM[0x600000];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
printf("68K: Unknown write8 %06X=%02X\n", a, d);
|
||||||
sbSampleBankLo = &sbSampleROM[0x200000];
|
break;
|
||||||
sbSampleBankHi = &sbSampleROM[0x600000];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unknown
|
|
||||||
else
|
|
||||||
printf("68K: Unknown write8 %06X=%02X\n", a, d);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Write16(unsigned int a,unsigned short d)
|
void CSoundBoard::Write16(unsigned int a,unsigned short d)
|
||||||
{
|
{
|
||||||
|
switch ((a>>20)&0xF)
|
||||||
|
{
|
||||||
|
case 0x0: // SCSP RAM 1 (master): 000000-0FFFFF
|
||||||
|
*(UINT16 *) &ram1[a] = d;
|
||||||
|
break;
|
||||||
|
|
||||||
// SCSP RAM 1
|
case 0x1: // SCSP registers (master): 100000-10FFFF
|
||||||
if ((a >= 0x000000) && (a <= 0x0FFFFF))
|
|
||||||
*(UINT16 *) &sbRAM1[a] = d;
|
|
||||||
|
|
||||||
// SCSP RAM 2
|
|
||||||
else if ((a >= 0x200000) && (a <= 0x2FFFFF))
|
|
||||||
*(UINT16 *) &sbRAM2[(a-0x200000)] = d;
|
|
||||||
|
|
||||||
// SCSP (Master)
|
|
||||||
else if ((a >= 0x100000) && (a <= 0x10FFFF))
|
|
||||||
SCSP_Master_w16(a,d);
|
SCSP_Master_w16(a,d);
|
||||||
|
break;
|
||||||
|
|
||||||
// SCSP (Slave)
|
case 0x2: // SCSP RAM 2 (slave): 200000-2FFFFF
|
||||||
else if ((a >= 0x300000) && (a <= 0x30FFFF))
|
*(UINT16 *) &ram2[a&0x0FFFFF] = d;
|
||||||
SCSP_Slave_w16(a,d);
|
break;
|
||||||
|
|
||||||
// Unknown
|
|
||||||
else
|
|
||||||
printf("68K: Unknown write16 %06X=%04X\n", a, d);
|
|
||||||
|
|
||||||
|
case 0x3: // SCSP registers (slave): 300000-30FFFF
|
||||||
|
SCSP_Slave_w16(a,d);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
printf("68K: Unknown write16 %06X=%04X\n", a, d);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Write32(unsigned int a,unsigned int d)
|
void CSoundBoard::Write32(unsigned int a,unsigned int d)
|
||||||
{
|
{
|
||||||
// SCSP RAM 1
|
switch ((a>>20)&0xF)
|
||||||
if ((a >= 0x000000) && (a <= 0x0FFFFF))
|
|
||||||
{
|
{
|
||||||
Write16(a,d>>16);
|
case 0x0: // SCSP RAM 1 (master): 000000-0FFFFF
|
||||||
Write16(a+2,d&0xFFFF);
|
*(UINT16 *) &ram1[a] = (d>>16);
|
||||||
}
|
*(UINT16 *) &ram1[a+2] = (d&0xFFFF);
|
||||||
|
break;
|
||||||
|
|
||||||
// SCSP RAM 2
|
case 0x1: // SCSP registers (master): 100000-10FFFF
|
||||||
else if ((a >= 0x200000) && (a <= 0x2FFFFF))
|
|
||||||
{
|
|
||||||
Write16(a,d>>16);
|
|
||||||
Write16(a+2,d&0xFFFF);
|
|
||||||
}
|
|
||||||
|
|
||||||
// SCSP (Master)
|
|
||||||
else if ((a >= 0x100000) && (a <= 0x10FFFF))
|
|
||||||
SCSP_Master_w32(a,d);
|
SCSP_Master_w32(a,d);
|
||||||
|
break;
|
||||||
|
|
||||||
// SCSP (Slave)
|
case 0x2: // SCSP RAM 2 (slave): 200000-2FFFFF
|
||||||
else if ((a >= 0x300000) && (a <= 0x30FFFF))
|
*(UINT16 *) &ram2[a&0x0FFFFF] = (d>>16);
|
||||||
|
*(UINT16 *) &ram2[(a+2)&0x0FFFFF] = (d&0xFFFF);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x3: // SCSP registers (slave): 300000-30FFFF
|
||||||
SCSP_Slave_w32(a,d);
|
SCSP_Slave_w32(a,d);
|
||||||
|
break;
|
||||||
// Unknown
|
|
||||||
else
|
default:
|
||||||
printf("68K: Unknown write32 %06X=%08X\n", a, d);
|
printf("68K: Unknown write32 %06X=%08X\n", a, d);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
SCSP 68K Callbacks
|
SCSP 68K Callbacks
|
||||||
|
|
||||||
The SCSP emulator drives the 68K via callbacks.
|
The SCSP emulator drives the 68K via callbacks. These have to live outside of
|
||||||
|
the CSoundBoard object for now, unfortunately.
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
// Status of IRQ pins (IPL2-0) on 68K
|
// Status of IRQ pins (IPL2-0) on 68K
|
||||||
|
// TODO: can we get rid of this global variable altogether?
|
||||||
static int irqLine = 0;
|
static int irqLine = 0;
|
||||||
|
|
||||||
// Interrupt acknowledge callback (TODO: don't need this, default behavior in M68K.cpp is fine)
|
// Interrupt acknowledge callback (TODO: don't need this, default behavior in M68K.cpp should be fine)
|
||||||
int IRQAck(int irqLevel)
|
int IRQAck(int irqLevel)
|
||||||
{
|
{
|
||||||
M68KSetIRQ(0);
|
M68KSetIRQ(0);
|
||||||
|
@ -334,41 +342,55 @@ int SCSP68KRunCallback(int numCycles)
|
||||||
|
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
Sound Board Emulation
|
Sound Board Interface
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
void CSoundBoard::WriteMIDIPort(UINT8 data)
|
void CSoundBoard::WriteMIDIPort(UINT8 data)
|
||||||
{
|
{
|
||||||
SCSP_MidiIn(data);
|
SCSP_MidiIn(data);
|
||||||
|
if (NULL != DSB) // DSB receives all commands as well
|
||||||
|
DSB->SendCommand(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSoundBoard::RunFrame(void)
|
void CSoundBoard::RunFrame(void)
|
||||||
{
|
{
|
||||||
#ifdef SUPERMODEL_SOUND
|
#ifdef SUPERMODEL_SOUND
|
||||||
|
// Run sound board first to generate SCSP audio
|
||||||
|
M68KSetContext(&M68K);
|
||||||
SCSP_Update();
|
SCSP_Update();
|
||||||
|
M68KGetContext(&M68K);
|
||||||
|
|
||||||
|
// Run DSB and mix with existing audio
|
||||||
|
if (NULL != DSB)
|
||||||
|
DSB->RunFrame(audioL, audioR);
|
||||||
|
|
||||||
// Output the audio buffers
|
// Output the audio buffers
|
||||||
OutputAudio(44100/60, leftBuffer, rightBuffer);
|
OutputAudio(44100/60, audioL, audioR);
|
||||||
|
|
||||||
|
#ifdef SUPERMODEL_LOG_AUDIO
|
||||||
// Output to binary file
|
// Output to binary file
|
||||||
INT16 s;
|
INT16 s;
|
||||||
for (int i = 0; i < 44100/60; i++)
|
for (int i = 0; i < 44100/60; i++)
|
||||||
{
|
{
|
||||||
s = ((UINT16)leftBuffer[i]>>8) | ((leftBuffer[i]&0xFF)<<8);
|
s = audioL[i];
|
||||||
fwrite(&s, sizeof(INT16), 1, soundFP); // left channel
|
fwrite(&s, sizeof(INT16), 1, soundFP); // left channel
|
||||||
s = ((UINT16)rightBuffer[i]>>8) | ((rightBuffer[i]&0xFF)<<8);
|
s = audioR[i];
|
||||||
fwrite(&s, sizeof(INT16), 1, soundFP); // right channel
|
fwrite(&s, sizeof(INT16), 1, soundFP); // right channel
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSoundBoard::Reset(void)
|
void CSoundBoard::Reset(void)
|
||||||
{
|
{
|
||||||
// lets hope he does better... ->
|
|
||||||
memcpy(ram1, soundROM, 16); // copy 68K vector table
|
memcpy(ram1, soundROM, 16); // copy 68K vector table
|
||||||
sbSampleBankLo = &sampleROM[0x200000]; // default banks
|
sampleBankLo = &sampleROM[0x200000]; // default banks
|
||||||
sbSampleBankHi = &sampleROM[0x600000];
|
sampleBankHi = &sampleROM[0x600000];
|
||||||
|
M68KSetContext(&M68K);
|
||||||
M68KReset();
|
M68KReset();
|
||||||
|
M68KGetContext(&M68K);
|
||||||
|
if (NULL != DSB)
|
||||||
|
DSB->Reset();
|
||||||
DebugLog("Sound Board Reset\n");
|
DebugLog("Sound Board Reset\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -377,22 +399,28 @@ void CSoundBoard::Reset(void)
|
||||||
Configuration, Initialization, and Shutdown
|
Configuration, Initialization, and Shutdown
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
|
void CSoundBoard::AttachDSB(CDSB *DSBPtr)
|
||||||
|
{
|
||||||
|
DSB = DSBPtr;
|
||||||
|
DebugLog("Sound Board connected to DSB\n");
|
||||||
|
}
|
||||||
|
|
||||||
// Offsets of memory regions within sound board's pool
|
// Offsets of memory regions within sound board's pool
|
||||||
#define OFFSET_RAM1 0 // 1 MB SCSP1 RAM
|
#define OFFSET_RAM1 0 // 1 MB SCSP1 RAM
|
||||||
#define OFFSET_RAM2 0x100000 // 1 MB SCSP2 RAM
|
#define OFFSET_RAM2 0x100000 // 1 MB SCSP2 RAM
|
||||||
#define MEMORY_POOL_SIZE (0x100000+0x100000)
|
#define OFFSET_AUDIO_LEFT 0x200000 // 1470 bytes (16 bits, 44.1 KHz, 1/60th second) left audio channel
|
||||||
|
#define OFFSET_AUDIO_RIGHT 0x2005BE // 1470 bytes right audio channel
|
||||||
|
#define MEMORY_POOL_SIZE (0x100000+0x100000+0x5BE+0x5BE)
|
||||||
|
|
||||||
BOOL CSoundBoard::Init(const UINT8 *soundROMPtr, const UINT8 *sampleROMPtr, CIRQ *ppcIRQObjectPtr, unsigned soundIRQBit)
|
BOOL CSoundBoard::Init(const UINT8 *soundROMPtr, const UINT8 *sampleROMPtr)
|
||||||
{
|
{
|
||||||
float memSizeMB = (float)MEMORY_POOL_SIZE/(float)0x100000;
|
float memSizeMB = (float)MEMORY_POOL_SIZE/(float)0x100000;
|
||||||
|
|
||||||
// Attach IRQ controller
|
|
||||||
ppcIRQ = ppcIRQObjectPtr;
|
|
||||||
ppcSoundIRQBit = soundIRQBit;
|
|
||||||
|
|
||||||
// Receive sound ROMs
|
// Receive sound ROMs
|
||||||
soundROM = soundROMPtr;
|
soundROM = soundROMPtr;
|
||||||
sampleROM = sampleROMPtr;
|
sampleROM = sampleROMPtr;
|
||||||
|
sampleBankLo = &sampleROM[0x200000];
|
||||||
|
sampleBankHi = &sampleROM[0x600000];
|
||||||
|
|
||||||
// Allocate all memory for RAM
|
// Allocate all memory for RAM
|
||||||
memoryPool = new(std::nothrow) UINT8[MEMORY_POOL_SIZE];
|
memoryPool = new(std::nothrow) UINT8[MEMORY_POOL_SIZE];
|
||||||
|
@ -403,37 +431,25 @@ BOOL CSoundBoard::Init(const UINT8 *soundROMPtr, const UINT8 *sampleROMPtr, CIRQ
|
||||||
// Set up memory pointers
|
// Set up memory pointers
|
||||||
ram1 = &memoryPool[OFFSET_RAM1];
|
ram1 = &memoryPool[OFFSET_RAM1];
|
||||||
ram2 = &memoryPool[OFFSET_RAM2];
|
ram2 = &memoryPool[OFFSET_RAM2];
|
||||||
|
audioL = (INT16 *) &memoryPool[OFFSET_AUDIO_LEFT];
|
||||||
|
audioR = (INT16 *) &memoryPool[OFFSET_AUDIO_RIGHT];
|
||||||
|
|
||||||
// Make global copies of memory pointers for 68K access handlers
|
|
||||||
sbRAM1 = ram1;
|
|
||||||
sbRAM2 = ram2;
|
|
||||||
sbSoundROM = soundROM;
|
|
||||||
sbSampleROM = sampleROM;
|
|
||||||
sbSampleBankLo = &sampleROM[0x200000];
|
|
||||||
sbSampleBankHi = &sampleROM[0x600000];
|
|
||||||
|
|
||||||
// Initialize 68K core
|
// Initialize 68K core
|
||||||
|
M68KSetContext(&M68K);
|
||||||
M68KInit();
|
M68KInit();
|
||||||
|
M68KAttachBus(this);
|
||||||
M68KSetIRQCallback(IRQAck);
|
M68KSetIRQCallback(IRQAck);
|
||||||
M68KSetFetch8Callback(Read8);
|
M68KGetContext(&M68K);
|
||||||
M68KSetFetch16Callback(Read16);
|
|
||||||
M68KSetFetch32Callback(Read32);
|
|
||||||
M68KSetRead8Callback(Read8);
|
|
||||||
M68KSetRead16Callback(Read16);
|
|
||||||
M68KSetRead32Callback(Read32);
|
|
||||||
M68KSetWrite8Callback(Write8);
|
|
||||||
M68KSetWrite16Callback(Write16);
|
|
||||||
M68KSetWrite32Callback(Write32);
|
|
||||||
|
|
||||||
// Initialize SCSPs
|
// Initialize SCSPs
|
||||||
SCSP_SetBuffers(leftBuffer, rightBuffer, 44100/60);
|
SCSP_SetBuffers(audioL, audioR, 44100/60);
|
||||||
SCSP_SetCB(SCSP68KRunCallback, SCSP68KIRQCallback, ppcIRQ, ppcSoundIRQBit);
|
SCSP_SetCB(SCSP68KRunCallback, SCSP68KIRQCallback);
|
||||||
SCSP_Init(2);
|
SCSP_Init(2);
|
||||||
SCSP_SetRAM(0, ram1);
|
SCSP_SetRAM(0, ram1);
|
||||||
SCSP_SetRAM(1, ram2);
|
SCSP_SetRAM(1, ram2);
|
||||||
|
|
||||||
// Binary logging
|
// Binary logging
|
||||||
#ifdef SUPERMODEL_SOUND
|
#ifdef SUPERMODEL_LOG_AUDIO
|
||||||
soundFP = fopen("sound.bin","wb"); // delete existing file
|
soundFP = fopen("sound.bin","wb"); // delete existing file
|
||||||
fclose(soundFP);
|
fclose(soundFP);
|
||||||
soundFP = fopen("sound.bin","ab"); // append mode
|
soundFP = fopen("sound.bin","ab"); // append mode
|
||||||
|
@ -444,9 +460,14 @@ BOOL CSoundBoard::Init(const UINT8 *soundROMPtr, const UINT8 *sampleROMPtr, CIRQ
|
||||||
|
|
||||||
CSoundBoard::CSoundBoard(void)
|
CSoundBoard::CSoundBoard(void)
|
||||||
{
|
{
|
||||||
|
DSB = NULL;
|
||||||
memoryPool = NULL;
|
memoryPool = NULL;
|
||||||
ram1 = NULL;
|
ram1 = NULL;
|
||||||
ram2 = NULL;
|
ram2 = NULL;
|
||||||
|
audioL = NULL;
|
||||||
|
audioR = NULL;
|
||||||
|
soundROM = NULL;
|
||||||
|
sampleROM = NULL;
|
||||||
|
|
||||||
DebugLog("Built Sound Board\n");
|
DebugLog("Built Sound Board\n");
|
||||||
}
|
}
|
||||||
|
@ -466,35 +487,15 @@ static void Reverse16(UINT8 *buf, unsigned size)
|
||||||
|
|
||||||
CSoundBoard::~CSoundBoard(void)
|
CSoundBoard::~CSoundBoard(void)
|
||||||
{
|
{
|
||||||
#ifdef SUPERMODEL_SOUND
|
#ifdef SUPERMODEL_LOG_AUDIO
|
||||||
// close binary log file
|
// close binary log file
|
||||||
fclose(soundFP);
|
fclose(soundFP);
|
||||||
//#if 0
|
|
||||||
FILE *fp;
|
|
||||||
|
|
||||||
Reverse16(ram1, 0x100000);
|
|
||||||
Reverse16(ram2, 0x100000);
|
|
||||||
fp = fopen("scspRAM1", "wb");
|
|
||||||
if (NULL != fp)
|
|
||||||
{
|
|
||||||
fwrite(ram1, sizeof(UINT8), 0x100000, fp);
|
|
||||||
fclose(fp);
|
|
||||||
printf("dumped %s\n", "scspRAM1");
|
|
||||||
|
|
||||||
}
|
|
||||||
fp = fopen("scspRAM2", "wb");
|
|
||||||
if (NULL != fp)
|
|
||||||
{
|
|
||||||
fwrite(ram2, sizeof(UINT8), 0x100000, fp);
|
|
||||||
fclose(fp);
|
|
||||||
printf("dumped %s\n", "scspRAM2");
|
|
||||||
|
|
||||||
}
|
|
||||||
//#endif
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
SCSP_Deinit();
|
SCSP_Deinit();
|
||||||
|
|
||||||
|
DSB = NULL;
|
||||||
|
|
||||||
if (memoryPool != NULL)
|
if (memoryPool != NULL)
|
||||||
{
|
{
|
||||||
delete [] memoryPool;
|
delete [] memoryPool;
|
||||||
|
@ -502,5 +503,10 @@ CSoundBoard::~CSoundBoard(void)
|
||||||
}
|
}
|
||||||
ram1 = NULL;
|
ram1 = NULL;
|
||||||
ram2 = NULL;
|
ram2 = NULL;
|
||||||
|
audioL = NULL;
|
||||||
|
audioR = NULL;
|
||||||
|
soundROM = NULL;
|
||||||
|
sampleROM = NULL;
|
||||||
|
|
||||||
DebugLog("Destroyed Sound Board\n");
|
DebugLog("Destroyed Sound Board\n");
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,15 +28,52 @@
|
||||||
#ifndef INCLUDED_SOUNDBOARD_H
|
#ifndef INCLUDED_SOUNDBOARD_H
|
||||||
#define INCLUDED_SOUNDBOARD_H
|
#define INCLUDED_SOUNDBOARD_H
|
||||||
|
|
||||||
|
#include "Types.h"
|
||||||
|
#include "CPU/Bus.h"
|
||||||
|
#include "Model3/DSB.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* CSoundBoard:
|
* CSoundBoard:
|
||||||
*
|
*
|
||||||
* Model 3 sound board (68K CPU + 2 x SCSP).
|
* Model 3 sound board (68K CPU + 2 x SCSP).
|
||||||
*/
|
*/
|
||||||
class CSoundBoard
|
class CSoundBoard: public CBus
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
/*
|
||||||
|
* Read8(addr):
|
||||||
|
* Read16(addr):
|
||||||
|
* Read32(addr):
|
||||||
|
* Read64(addr):
|
||||||
|
*
|
||||||
|
* Read a byte, 16-bit word, or 32-bit long word from the 68K address
|
||||||
|
* space.
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* addr Address to read.
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* Data at the address.
|
||||||
|
*/
|
||||||
|
UINT8 Read8(UINT32 addr);
|
||||||
|
UINT16 Read16(UINT32 addr);
|
||||||
|
UINT32 Read32(UINT32 addr);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write8(addr, data):
|
||||||
|
* Write16(addr, data):
|
||||||
|
* Write32(addr, data):
|
||||||
|
*
|
||||||
|
* Write a byte, word, or long word to the 68K address space.
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* addr Address to write.
|
||||||
|
* data Data to write.
|
||||||
|
*/
|
||||||
|
void Write8(UINT32 addr, UINT8 data);
|
||||||
|
void Write16(UINT32 addr, UINT16 data);
|
||||||
|
void Write32(UINT32 addr, UINT32 data);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* WriteMIDIPort(data):
|
* WriteMIDIPort(data):
|
||||||
*
|
*
|
||||||
|
@ -61,6 +98,18 @@ public:
|
||||||
*/
|
*/
|
||||||
void Reset(void);
|
void Reset(void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* AttachDSB(CDSB *DSBPtr):
|
||||||
|
*
|
||||||
|
* Connects a Digital Sound Board. The sound board passes MIDI commands,
|
||||||
|
* resets the board, and runs it each frame to generate audio. If there is
|
||||||
|
* no DSB, this function does not need to be called.
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* DSBPtr Pointer to DSB object.
|
||||||
|
*/
|
||||||
|
void AttachDSB(CDSB *DSBPtr);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Init(soundROMPtr, sampleROMPtr):
|
* Init(soundROMPtr, sampleROMPtr):
|
||||||
*
|
*
|
||||||
|
@ -69,14 +118,12 @@ public:
|
||||||
* Parameters:
|
* Parameters:
|
||||||
* soundROMPtr Pointer to sound ROM (68K program).
|
* soundROMPtr Pointer to sound ROM (68K program).
|
||||||
* sampleROMPtr Pointer to sample ROM.
|
* sampleROMPtr Pointer to sample ROM.
|
||||||
* ppcIRQObjectPtr Pointer to PowerPC-side IRQ object.
|
|
||||||
* soundIRQBit IRQ bit mask to use for sound board PowerPC IRQs.
|
|
||||||
*
|
*
|
||||||
* Returns:
|
* Returns:
|
||||||
* OKAY if successful, FAIL if unable to allocate memory. Prints own
|
* OKAY if successful, FAIL if unable to allocate memory. Prints own
|
||||||
* error messages.
|
* error messages.
|
||||||
*/
|
*/
|
||||||
BOOL Init(const UINT8 *soundROMPtr, const UINT8 *sampleROMPtr, CIRQ *ppcIRQObjectPtr, unsigned soundIRQBit);
|
BOOL Init(const UINT8 *soundROMPtr, const UINT8 *sampleROMPtr);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* CSoundBoard(void):
|
* CSoundBoard(void):
|
||||||
|
@ -88,15 +135,22 @@ public:
|
||||||
~CSoundBoard(void);
|
~CSoundBoard(void);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// PowerPC IRQ controller
|
// Digital Sound Board
|
||||||
CIRQ *ppcIRQ;
|
CDSB *DSB;
|
||||||
unsigned ppcSoundIRQBit;
|
|
||||||
|
// 68K context
|
||||||
|
M68KCtx M68K;
|
||||||
|
|
||||||
// Sound board memory
|
// Sound board memory
|
||||||
const UINT8 *soundROM; // 68K program ROM (passed in from parent object)
|
const UINT8 *soundROM; // 68K program ROM (passed in from parent object)
|
||||||
const UINT8 *sampleROM; // 68K sample ROM (passed in from parent object)
|
const UINT8 *sampleROM; // 68K sample ROM (passed in from parent object)
|
||||||
|
const UINT8 *sampleBankLo; // sample ROM bank switching
|
||||||
|
const UINT8 *sampleBankHi;
|
||||||
UINT8 *memoryPool; // single allocated region for all sound board RAM
|
UINT8 *memoryPool; // single allocated region for all sound board RAM
|
||||||
UINT8 *ram1, *ram2; // SCSP1 and SCSP2 RAM
|
UINT8 *ram1, *ram2; // SCSP1 and SCSP2 RAM
|
||||||
|
|
||||||
|
// Audio
|
||||||
|
INT16 *audioL, *audioR; // left and right audio channels (1/60th second, 44.1 KHz)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -534,27 +534,6 @@ int Supermodel(const char *zipFile, CInputs *Inputs, unsigned ppcFrequency, BOOL
|
||||||
// Toggle frame limiting
|
// Toggle frame limiting
|
||||||
noThrottle = !noThrottle;
|
noThrottle = !noThrottle;
|
||||||
printf("Frame limiting: %s\n", noThrottle?"Off":"On");
|
printf("Frame limiting: %s\n", noThrottle?"Off":"On");
|
||||||
/*
|
|
||||||
SCSP_MidiIn(0xA0);
|
|
||||||
SCSP_MidiIn(0x00);
|
|
||||||
SCSP_MidiIn(0x01); // stop?
|
|
||||||
|
|
||||||
SCSP_MidiIn(0xA0);
|
|
||||||
SCSP_MidiIn(0x11);
|
|
||||||
SCSP_MidiIn(0x2E);
|
|
||||||
|
|
||||||
SCSP_MidiIn(0xA1);
|
|
||||||
SCSP_MidiIn(0x70);
|
|
||||||
SCSP_MidiIn(0x03);
|
|
||||||
|
|
||||||
SCSP_MidiIn(0xAF);SCSP_MidiIn(0x10);SCSP_MidiIn(0x01);
|
|
||||||
*/
|
|
||||||
SCSP_MidiIn(0xAF);SCSP_MidiIn(0x10);SCSP_MidiIn(0x00);
|
|
||||||
//static int snd=0xF;
|
|
||||||
//SCSP_MidiIn(0xA0);SCSP_MidiIn(0x11);SCSP_MidiIn(snd++);
|
|
||||||
//Sound codes:
|
|
||||||
// A0 11 xx (0F=time extend, 11=jumbo left right)
|
|
||||||
// AF 10 xx (music -- 01 seems to work)
|
|
||||||
}
|
}
|
||||||
#ifdef SUPERMODEL_DEBUGGER
|
#ifdef SUPERMODEL_DEBUGGER
|
||||||
else if (Inputs->uiEnterDebugger->Pressed())
|
else if (Inputs->uiEnterDebugger->Pressed())
|
||||||
|
|
|
@ -68,7 +68,7 @@ static BOOL FindROMByCRCInGame(const struct GameInfo **gamePtr, int *romIdxPtr,
|
||||||
{
|
{
|
||||||
if (crc == Game->ROM[j].crc) // found it!
|
if (crc == Game->ROM[j].crc) // found it!
|
||||||
{
|
{
|
||||||
*gamePtr = Game;
|
*gamePtr = Game; // I know this seems redundant, but we do it here because FindROMByCRC() uses this function
|
||||||
*romIdxPtr = j;
|
*romIdxPtr = j;
|
||||||
return OKAY;
|
return OKAY;
|
||||||
}
|
}
|
||||||
|
@ -97,6 +97,23 @@ static BOOL FindROMByCRC(const struct GameInfo **gamePtr, int *romIdxPtr, const
|
||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns TRUE if this ROM appears only a single time in the entire game list (ie., it is not shared between games)
|
||||||
|
static BOOL ROMIsUnique(const struct GameInfo *GameList, UINT32 crc)
|
||||||
|
{
|
||||||
|
int timesFound = 0;
|
||||||
|
|
||||||
|
for (int i = 0; GameList[i].title != NULL; i++)
|
||||||
|
{
|
||||||
|
for (int j = 0; GameList[i].ROM[j].region != NULL; j++)
|
||||||
|
{
|
||||||
|
if (crc == GameList[i].ROM[j].crc)
|
||||||
|
timesFound++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (timesFound == 1) ? TRUE : FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
static void ByteSwap(UINT8 *buf, unsigned size)
|
static void ByteSwap(UINT8 *buf, unsigned size)
|
||||||
{
|
{
|
||||||
unsigned i;
|
unsigned i;
|
||||||
|
@ -189,8 +206,9 @@ const struct GameInfo * LoadROMSetFromZIPFile(const struct ROMMap *Map, const st
|
||||||
{
|
{
|
||||||
unzFile zf;
|
unzFile zf;
|
||||||
unz_file_info fileInfo;
|
unz_file_info fileInfo;
|
||||||
const struct GameInfo *Game = NULL, *CurGame;
|
const struct GameInfo *Game = NULL;
|
||||||
int romIdx; // index within Game->ROM
|
const struct GameInfo *CurGame; // this is the game to which the last ROM found is thought to belong
|
||||||
|
int romIdx; // index within Game->ROM
|
||||||
unsigned romsFound[sizeof(Game->ROM)/sizeof(struct ROMInfo)], numROMs;
|
unsigned romsFound[sizeof(Game->ROM)/sizeof(struct ROMInfo)], numROMs;
|
||||||
int err;
|
int err;
|
||||||
unsigned i, n, maxSize;
|
unsigned i, n, maxSize;
|
||||||
|
@ -205,8 +223,7 @@ const struct GameInfo * LoadROMSetFromZIPFile(const struct ROMMap *Map, const st
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check ROMs: scan ZIP file for first known ROM and check to ensure all ROMs are present
|
// First pass: scan every file and determine the game
|
||||||
memset(romsFound, 0, sizeof(romsFound));
|
|
||||||
err = unzGoToFirstFile(zf);
|
err = unzGoToFirstFile(zf);
|
||||||
if (UNZ_OK != err)
|
if (UNZ_OK != err)
|
||||||
{
|
{
|
||||||
|
@ -221,54 +238,73 @@ const struct GameInfo * LoadROMSetFromZIPFile(const struct ROMMap *Map, const st
|
||||||
continue;
|
continue;
|
||||||
if (OKAY != FindROMByCRC(&CurGame, &romIdx, GameList, Game, fileInfo.crc))
|
if (OKAY != FindROMByCRC(&CurGame, &romIdx, GameList, Game, fileInfo.crc))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
// If the ROM appears in multiple games, do not use it to identify the game!
|
||||||
|
if (!ROMIsUnique(GameList, fileInfo.crc))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// We have a unique ROM used by a single game; identify that game
|
||||||
if (Game == NULL) // this is the first game we've identified within the ZIP
|
if (Game == NULL) // this is the first game we've identified within the ZIP
|
||||||
{
|
{
|
||||||
Game = CurGame;
|
Game = CurGame;
|
||||||
DebugLog("%ROM set identified: %s (%s), %s\n", Game->id, Game->title, zipFile);
|
DebugLog("ROM set identified: %s (%s), %s\n", Game->id, Game->title, zipFile);
|
||||||
}
|
}
|
||||||
else
|
else // we've already identified a game
|
||||||
{
|
{
|
||||||
if (CurGame != Game)
|
if (CurGame != Game) // another game?
|
||||||
{
|
{
|
||||||
DebugLog("%s also contains: %s (%s)\n", zipFile, CurGame->id, CurGame->title);
|
DebugLog("%s also contains: %s (%s)\n", zipFile, CurGame->id, CurGame->title);
|
||||||
if (multipleGameError == FALSE) // only warn about this once
|
if (multipleGameError == FALSE) // only warn about this once
|
||||||
{
|
{
|
||||||
|
printf("ROM=%s\n", CurGame->ROM[romIdx].fileName);
|
||||||
ErrorLog("Multiple games were found in %s; loading \"%s\".", zipFile, Game->title);
|
ErrorLog("Multiple games were found in %s; loading \"%s\".", zipFile, Game->title);
|
||||||
multipleGameError = TRUE;
|
multipleGameError = TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we have found a ROM for the correct game, mark it
|
|
||||||
if (Game == CurGame)
|
|
||||||
romsFound[romIdx] = 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Game == NULL)
|
// Second pass: check if all ROM files for the identified game are present
|
||||||
|
err = unzGoToFirstFile(zf);
|
||||||
|
if (UNZ_OK != err)
|
||||||
{
|
{
|
||||||
ErrorLog("%s contains no supported games.", zipFile);
|
ErrorLog("Unable to read the contents of %s (code %X)", zipFile, err);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
memset(romsFound, 0, sizeof(romsFound)); // here, romsFound[] indicates which ROMs were found in the ZIP file for the game
|
||||||
|
for (; err != UNZ_END_OF_LIST_OF_FILE; err = unzGoToNextFile(zf))
|
||||||
|
{
|
||||||
|
// Identify the file we're looking at
|
||||||
|
err = unzGetCurrentFileInfo(zf, &fileInfo, NULL, 0, NULL, 0, NULL, 0);
|
||||||
|
if (err != UNZ_OK)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// If it's not part of the game we've identified, skip it
|
||||||
|
if (OKAY != FindROMByCRCInGame(&CurGame, &romIdx, Game, fileInfo.crc))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// If we have found a ROM for the correct game, mark its corresponding indicator
|
||||||
|
romsFound[romIdx] = 1;
|
||||||
|
}
|
||||||
|
|
||||||
// Compute how many ROM files this game has
|
// Compute how many ROM files this game has
|
||||||
for (numROMs = 0; Game->ROM[numROMs].region != NULL; numROMs++)
|
for (numROMs = 0; Game->ROM[numROMs].region != NULL; numROMs++)
|
||||||
;
|
;
|
||||||
|
|
||||||
// If not all ROMs were present, tell the user
|
// If not all ROMs were present, tell the user
|
||||||
err = OKAY;
|
err = OKAY;
|
||||||
for (i = 0; i < numROMs; i++)
|
for (i = 0; i < numROMs; i++)
|
||||||
{
|
{
|
||||||
if (romsFound[i] == 0)
|
if (romsFound[i] == 0)
|
||||||
err |= ErrorLog("%s (CRC=%08X) is missing from %s.", Game->ROM[i].file, Game->ROM[i].crc, zipFile);
|
err |= ErrorLog("%s (CRC=%08X) is missing from %s.", Game->ROM[i].fileName, Game->ROM[i].crc, zipFile);
|
||||||
}
|
}
|
||||||
if (err != OKAY)
|
if (err != OKAY)
|
||||||
{
|
{
|
||||||
unzClose(zf);
|
unzClose(zf);
|
||||||
return NULL;
|
return NULL;
|
||||||
//return FAIL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allocate memory for the largest ROM to load
|
// Allocate a scratch buffer big enough to hold the biggest ROM
|
||||||
maxSize = 0;
|
maxSize = 0;
|
||||||
for (i = 0; i < numROMs; i++)
|
for (i = 0; i < numROMs; i++)
|
||||||
{
|
{
|
||||||
|
@ -283,8 +319,8 @@ const struct GameInfo * LoadROMSetFromZIPFile(const struct ROMMap *Map, const st
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load ROMs
|
// Third pass: load the ROMs
|
||||||
memset(romsFound, 0, sizeof(romsFound));
|
memset(romsFound, 0, sizeof(romsFound)); // now, romsFound[] is used to indicate whether we successfully loaded the ROM
|
||||||
err = unzGoToFirstFile(zf);
|
err = unzGoToFirstFile(zf);
|
||||||
if (UNZ_OK != err)
|
if (UNZ_OK != err)
|
||||||
{
|
{
|
||||||
|
@ -297,13 +333,14 @@ const struct GameInfo * LoadROMSetFromZIPFile(const struct ROMMap *Map, const st
|
||||||
err = unzGetCurrentFileInfo(zf, &fileInfo, NULL, 0, NULL, 0, NULL, 0);
|
err = unzGetCurrentFileInfo(zf, &fileInfo, NULL, 0, NULL, 0, NULL, 0);
|
||||||
if (err != UNZ_OK)
|
if (err != UNZ_OK)
|
||||||
continue;
|
continue;
|
||||||
if (OKAY != FindROMByCRC(&CurGame, &romIdx, GameList, Game, fileInfo.crc))
|
|
||||||
|
// If this ROM is not part of the game we're loading, skip it
|
||||||
|
if (OKAY != FindROMByCRCInGame(&CurGame, &romIdx, Game, fileInfo.crc))
|
||||||
continue;
|
continue;
|
||||||
if (CurGame == Game) // if ROM belongs to correct game
|
|
||||||
{
|
// Load the ROM and mark that we did so successfully
|
||||||
if (OKAY == LoadROM(buf, maxSize, Map, &Game->ROM[romIdx], zf, zipFile, loadAll))
|
if (OKAY == LoadROM(buf, maxSize, Map, &Game->ROM[romIdx], zf, zipFile, loadAll))
|
||||||
romsFound[romIdx] = 1; // success! mark as loaded
|
romsFound[romIdx] = 1; // success! mark as loaded
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure all ROMs were loaded
|
// Ensure all ROMs were loaded
|
||||||
|
@ -315,7 +352,7 @@ const struct GameInfo * LoadROMSetFromZIPFile(const struct ROMMap *Map, const st
|
||||||
if (romsFound[i])
|
if (romsFound[i])
|
||||||
++n;
|
++n;
|
||||||
else
|
else
|
||||||
ErrorLog("Failed to load %s (CRC=%08X) from %s.", Game->ROM[i].file, Game->ROM[i].crc, zipFile);
|
ErrorLog("Failed to load %s (CRC=%08X) from %s.", Game->ROM[i].fileName, Game->ROM[i].crc, zipFile);
|
||||||
}
|
}
|
||||||
if (n < numROMs)
|
if (n < numROMs)
|
||||||
err = FAIL;
|
err = FAIL;
|
||||||
|
|
|
@ -44,7 +44,7 @@ struct ROMInfo
|
||||||
const char *region; // ROM region identifier (used as a key to search ROMMap)
|
const char *region; // ROM region identifier (used as a key to search ROMMap)
|
||||||
|
|
||||||
// Information used to identify files
|
// Information used to identify files
|
||||||
const char *file; // file name
|
const char *fileName; // file name
|
||||||
UINT32 crc; // CRC-32 checksum (same as zip format)
|
UINT32 crc; // CRC-32 checksum (same as zip format)
|
||||||
unsigned fileSize; // file size in bytes (must be the same as all other ROMs with same region ID)
|
unsigned fileSize; // file size in bytes (must be the same as all other ROMs with same region ID)
|
||||||
|
|
||||||
|
|
114
Src/Sound/MPEG/MPEG.h
Normal file
114
Src/Sound/MPEG/MPEG.h
Normal file
|
@ -0,0 +1,114 @@
|
||||||
|
/**
|
||||||
|
** Supermodel
|
||||||
|
** A Sega Model 3 Arcade Emulator.
|
||||||
|
** Copyright 2011 Bart Trzynadlowski
|
||||||
|
**
|
||||||
|
** This file is part of Supermodel.
|
||||||
|
**
|
||||||
|
** Supermodel is free software: you can redistribute it and/or modify it under
|
||||||
|
** the terms of the GNU General Public License as published by the Free
|
||||||
|
** Software Foundation, either version 3 of the License, or (at your option)
|
||||||
|
** any later version.
|
||||||
|
**
|
||||||
|
** Supermodel is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
** FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
** more details.
|
||||||
|
**
|
||||||
|
** You should have received a copy of the GNU General Public License along
|
||||||
|
** with Supermodel. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
**/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* MPEG.cpp
|
||||||
|
*
|
||||||
|
* Header file for MPEG decoder based on AMP by Tomislav Uzalec, modified to
|
||||||
|
* play from memory buffers by R. Belmont for his music player, M1.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef INCLUDED_MPEG_H
|
||||||
|
#define INCLUDED_MPEG_H
|
||||||
|
|
||||||
|
#include "Types.h"
|
||||||
|
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
Functions
|
||||||
|
|
||||||
|
The MPEG decoder is not thread-safe and must not be used by multiple sources.
|
||||||
|
These functions are located in audio.cpp and getbits.cpp.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* MPEG_GetProgress(void):
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* The current byte offset within the MPEG stream.
|
||||||
|
*/
|
||||||
|
extern int MPEG_GetProgress(void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* MPEG_SetLoop(loop, loopend):
|
||||||
|
*
|
||||||
|
* Sets the start and end offsets for looped playback.
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* loop Start address.
|
||||||
|
* loopend End address.
|
||||||
|
*/
|
||||||
|
extern void MPEG_SetLoop(const char *loop, int loopend);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* MPEG_Decode(outputs, length):
|
||||||
|
*
|
||||||
|
* Decodes the requested number of samples from the currently playing MPEG
|
||||||
|
* stream and updates the internal play position. If an MPEG is not playing,
|
||||||
|
* writes silence (zeros).
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* outputs A two-element array of pointers to equal-length signed 16-
|
||||||
|
* bit sample buffers. The first is the left channel and the
|
||||||
|
* second is the right channel. Audio is decoded to these.
|
||||||
|
* length Number of samples to decode.
|
||||||
|
*/
|
||||||
|
extern void MPEG_Decode(INT16 **outputs, int length);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* MPEG_PlayMemory(sa, length):
|
||||||
|
*
|
||||||
|
* Specifies the memory buffer to decode from. This initializes the playback
|
||||||
|
* process and will decode the first MPEG frame internally.
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* sa Start address of MPEG stream.
|
||||||
|
* length Length in bytes.
|
||||||
|
*/
|
||||||
|
extern void MPEG_PlayMemory(const char *sa, int length);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* MPEG_StopPlaying(void):
|
||||||
|
*
|
||||||
|
* Stop playing the current MPEG stream. The decoder will return silence.
|
||||||
|
*/
|
||||||
|
extern void MPEG_StopPlaying(void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* MPEG_Init(void):
|
||||||
|
*
|
||||||
|
* Initializes the MPEG decoder. This should be called once per program
|
||||||
|
* session. Allocates an internal buffer for MPEG decoding.
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* OKAY if successful, FAIL if internal buffer could not be allocated.
|
||||||
|
*/
|
||||||
|
extern BOOL MPEG_Init(void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* MPEG_Shutdown(void):
|
||||||
|
*
|
||||||
|
* Shuts down the MPEG decoder. Releases internal memory.
|
||||||
|
*/
|
||||||
|
extern void MPEG_Shutdown(void);
|
||||||
|
|
||||||
|
|
||||||
|
#endif // INCLUDED_MPEG_H
|
63
Src/Sound/MPEG/amp.h
Normal file
63
Src/Sound/MPEG/amp.h
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
/* this file is a part of amp software, (C) tomislav uzelac 1996,1997
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* these should not be touched
|
||||||
|
*/
|
||||||
|
#define SYNCWORD 0xfff
|
||||||
|
#ifndef TRUE
|
||||||
|
#define TRUE 1
|
||||||
|
#endif
|
||||||
|
#ifndef FALSE
|
||||||
|
#define FALSE 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* version
|
||||||
|
*/
|
||||||
|
#define MAJOR 0
|
||||||
|
#define MINOR 7
|
||||||
|
#define PATCH 6
|
||||||
|
|
||||||
|
#define MAX(a,b) ((a) > (b) ? (a) : (b))
|
||||||
|
#define MAX3(a,b,c) ((a) > (b) ? MAX(a, c) : MAX(b, c))
|
||||||
|
#define MIN(a,b) ((a) < (b) ? (a) : (b))
|
||||||
|
|
||||||
|
|
||||||
|
/* Debugging flags */
|
||||||
|
|
||||||
|
struct debugFlags_t {
|
||||||
|
int audio,args,buffer,buffer2,misc,misc2;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct debugLookup_t {
|
||||||
|
char *name; int *var;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern struct debugFlags_t debugFlags;
|
||||||
|
|
||||||
|
/* This is only here to keep all the debug stuff together */
|
||||||
|
#ifdef AMP_UTIL
|
||||||
|
struct debugLookup_t debugLookup[] = {
|
||||||
|
{"audio", &debugFlags.audio},
|
||||||
|
{"args", &debugFlags.args},
|
||||||
|
{"buffer", &debugFlags.buffer},
|
||||||
|
{"buffer2", &debugFlags.buffer2},
|
||||||
|
{"misc", &debugFlags.misc},
|
||||||
|
{"misc2", &debugFlags.misc2},
|
||||||
|
{0,0}
|
||||||
|
};
|
||||||
|
#endif /* AMP_UTIL */
|
||||||
|
|
||||||
|
extern struct debugLookup_t debugLookup[];
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
#define DB(type,cmd) if (debugFlags.type) { cmd ; }
|
||||||
|
#else
|
||||||
|
#define DB(type,cmd)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include "proto.h"
|
||||||
|
|
||||||
|
|
||||||
|
extern int AUDIO_BUFFER_SIZE;
|
396
Src/Sound/MPEG/audio.cpp
Normal file
396
Src/Sound/MPEG/audio.cpp
Normal file
|
@ -0,0 +1,396 @@
|
||||||
|
/* this file is a part of amp software, (C) tomislav uzelac 1996,1997
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* audio.c main amp source file
|
||||||
|
*
|
||||||
|
* Created by: tomislav uzelac Apr 1996
|
||||||
|
* Karl Anders Oygard added the IRIX code, 10 Mar 1997.
|
||||||
|
* Ilkka Karvinen fixed /dev/dsp initialization, 11 Mar 1997.
|
||||||
|
* Lutz Vieweg added the HP/UX code, 14 Mar 1997.
|
||||||
|
* Dan Nelson added FreeBSD modifications, 23 Mar 1997.
|
||||||
|
* Andrew Richards complete reorganisation, new features, 25 Mar 1997
|
||||||
|
* Edouard Lafargue added sajber jukebox support, 12 May 1997
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "amp.h"
|
||||||
|
|
||||||
|
#define AUDIO
|
||||||
|
#include "audio.h"
|
||||||
|
#include "formats.h"
|
||||||
|
#include "getbits.h"
|
||||||
|
#include "huffman.h"
|
||||||
|
#include "layer2.h"
|
||||||
|
#include "layer3.h"
|
||||||
|
#include "position.h"
|
||||||
|
#include "rtbuf.h"
|
||||||
|
#include "transform.h"
|
||||||
|
|
||||||
|
//#ifndef __BEOS__
|
||||||
|
//typedef int bool;
|
||||||
|
//#endif
|
||||||
|
|
||||||
|
#include <new>
|
||||||
|
#include <cstring>
|
||||||
|
#include "Types.h"
|
||||||
|
#include "MPEG.h"
|
||||||
|
|
||||||
|
//#include "m1snd.h"
|
||||||
|
//#include "oss.h"
|
||||||
|
//#include "mpeg.h"
|
||||||
|
|
||||||
|
#define BUF_SIZE (1152 * sizeof(short) * 2)
|
||||||
|
|
||||||
|
void calculate_t43(void);
|
||||||
|
|
||||||
|
static int decoder_init = 0;
|
||||||
|
static int cnt = 0;
|
||||||
|
static int stream = -1;
|
||||||
|
static char *buf0;
|
||||||
|
static int playing = 0;
|
||||||
|
static int outpos = 0;
|
||||||
|
static int mpeg_eof = 0;
|
||||||
|
static char *dst, *readbuf;
|
||||||
|
static struct AUDIO_HEADER m1hdr;;
|
||||||
|
|
||||||
|
void statusDisplay(struct AUDIO_HEADER *header, int frameNo)
|
||||||
|
{
|
||||||
|
int minutes,seconds;
|
||||||
|
|
||||||
|
if ((A_SHOW_CNT || A_SHOW_TIME) && !(frameNo%10))
|
||||||
|
msg("\r");
|
||||||
|
if (A_SHOW_CNT && !(frameNo%10) ) {
|
||||||
|
msg("{ %d } ",frameNo);
|
||||||
|
}
|
||||||
|
if (A_SHOW_TIME && !(frameNo%10)) {
|
||||||
|
seconds=frameNo*1152/t_sampling_frequency[header->ID][header->sampling_frequency];
|
||||||
|
minutes=seconds/60;
|
||||||
|
seconds=seconds % 60;
|
||||||
|
msg("[%d:%02d]",minutes,seconds);
|
||||||
|
}
|
||||||
|
if (A_SHOW_CNT || A_SHOW_TIME)
|
||||||
|
fflush(stderr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// one mpeg frame is 576 samples.
|
||||||
|
int decodeMPEGOneFrame(struct AUDIO_HEADER *header)
|
||||||
|
{
|
||||||
|
int snd_eof = 0, g;
|
||||||
|
|
||||||
|
if ((g=gethdr(header))!=0) {
|
||||||
|
report_header_error(g);
|
||||||
|
snd_eof=1;
|
||||||
|
return snd_eof;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (header->protection_bit==0) getcrc();
|
||||||
|
|
||||||
|
statusDisplay(header,0);
|
||||||
|
|
||||||
|
if (header->layer==1) {
|
||||||
|
if (layer3_frame(header,cnt)) {
|
||||||
|
warn(" error. blip.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
} else if (header->layer==2)
|
||||||
|
if (layer2_frame(header,cnt)) {
|
||||||
|
warn(" error. blip.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
cnt++;
|
||||||
|
|
||||||
|
return snd_eof;
|
||||||
|
}
|
||||||
|
|
||||||
|
int decodeMPEG(void)
|
||||||
|
{
|
||||||
|
struct AUDIO_HEADER header;
|
||||||
|
int g,snd_eof=0;
|
||||||
|
|
||||||
|
initialise_globals();
|
||||||
|
|
||||||
|
cnt = 0;
|
||||||
|
|
||||||
|
if ((g=gethdr(&header))!=0) {
|
||||||
|
report_header_error(g);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (header.protection_bit==0) getcrc();
|
||||||
|
|
||||||
|
printf("%d Hz, layer %d\n", t_sampling_frequency[header.ID][header.sampling_frequency], header.layer);
|
||||||
|
|
||||||
|
if (setup_audio(&header)!=0) {
|
||||||
|
warn("Cannot set up audio. Exiting\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (header.layer==1) {
|
||||||
|
if (layer3_frame(&header,cnt)) {
|
||||||
|
warn(" error. blip.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
} else if (header.layer==2)
|
||||||
|
if (layer2_frame(&header,cnt)) {
|
||||||
|
warn(" error. blip.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* decoder loop **********************************
|
||||||
|
*/
|
||||||
|
snd_eof=0;
|
||||||
|
while (!snd_eof) {
|
||||||
|
while (!snd_eof && ready_audio()) {
|
||||||
|
snd_eof = decodeMPEGOneFrame(&header);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* call this once at the beginning
|
||||||
|
*/
|
||||||
|
void initialise_decoder(void)
|
||||||
|
{
|
||||||
|
premultiply();
|
||||||
|
imdct_init();
|
||||||
|
calculate_t43();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* call this before each file is played
|
||||||
|
*/
|
||||||
|
void initialise_globals(void)
|
||||||
|
{
|
||||||
|
append=data=nch=0;
|
||||||
|
f_bdirty=TRUE;
|
||||||
|
bclean_bytes=0;
|
||||||
|
|
||||||
|
memset(s,0,sizeof s);
|
||||||
|
memset(res,0,sizeof res);
|
||||||
|
}
|
||||||
|
|
||||||
|
void report_header_error(int err)
|
||||||
|
{
|
||||||
|
switch (err) {
|
||||||
|
case GETHDR_ERR: die("error reading mpeg bitstream. exiting.\n");
|
||||||
|
break;
|
||||||
|
case GETHDR_NS : warn("this is a file in MPEG 2.5 format, which is not defined\n");
|
||||||
|
warn("by ISO/MPEG. It is \"a special Fraunhofer format\".\n");
|
||||||
|
warn("amp does not support this format. sorry.\n");
|
||||||
|
break;
|
||||||
|
case GETHDR_FL1: warn("ISO/MPEG layer 1 is not supported by amp.\n");
|
||||||
|
break;
|
||||||
|
case GETHDR_FF : warn("free format bitstreams are not supported. sorry.\n");
|
||||||
|
break;
|
||||||
|
case GETHDR_SYN: warn("oops, we're out of sync.\n");
|
||||||
|
break;
|
||||||
|
case GETHDR_EOF:
|
||||||
|
default: ; /* some stupid compilers need the semicolon */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int setup_audio(struct AUDIO_HEADER *header)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void close_audio(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
int ready_audio(void)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// callback: called by the engine to output a frame of audio
|
||||||
|
void printout(void)
|
||||||
|
{
|
||||||
|
int j;
|
||||||
|
|
||||||
|
if (nch==2)
|
||||||
|
{
|
||||||
|
j=32 * 18 * 2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
j=32 * 18;
|
||||||
|
}
|
||||||
|
|
||||||
|
// printf("printout: %x, %d\n", (unsigned int), j*2);
|
||||||
|
memcpy(dst, sample_buffer, j*2);
|
||||||
|
|
||||||
|
dst += j*2;
|
||||||
|
outpos += j/2;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MPEG_Decode(INT16 **outputs, int length)
|
||||||
|
{
|
||||||
|
int i, remaining, bias;
|
||||||
|
INT16 *get;
|
||||||
|
|
||||||
|
remaining = length;
|
||||||
|
|
||||||
|
// printf("%d: %x %x\n", length, (unsigned int)outputs[0], (unsigned int)outputs[1]);
|
||||||
|
|
||||||
|
if (!playing)
|
||||||
|
{
|
||||||
|
memset(&outputs[0][0], 0, length * sizeof(INT16));
|
||||||
|
memset(&outputs[1][0], 0, length * sizeof(INT16));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bias = 0;
|
||||||
|
|
||||||
|
// will we need more data from the decoder?
|
||||||
|
if (outpos < length)
|
||||||
|
{
|
||||||
|
// if there's anything left in the current buffer, drain it first
|
||||||
|
if (outpos != 0)
|
||||||
|
{
|
||||||
|
get = (INT16 *)readbuf;
|
||||||
|
|
||||||
|
for (i = 0; i < outpos; i++)
|
||||||
|
{
|
||||||
|
outputs[1][i] = *get++;
|
||||||
|
outputs[0][i] = *get++;
|
||||||
|
}
|
||||||
|
|
||||||
|
remaining -= outpos;
|
||||||
|
bias = outpos;
|
||||||
|
readbuf += (outpos * 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
outpos = 0;
|
||||||
|
dst = buf0;
|
||||||
|
while ((outpos < remaining) && (playing))
|
||||||
|
{
|
||||||
|
mpeg_eof = decodeMPEGOneFrame(&m1hdr);
|
||||||
|
if (mpeg_eof)
|
||||||
|
{
|
||||||
|
MPEG_StopPlaying();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// reset read pointer
|
||||||
|
readbuf = buf0;
|
||||||
|
}
|
||||||
|
|
||||||
|
get = (INT16 *)readbuf;
|
||||||
|
|
||||||
|
for (i = 0; i < remaining; i++)
|
||||||
|
{
|
||||||
|
outputs[1][i+bias] = *get++;
|
||||||
|
outputs[0][i+bias] = *get++;
|
||||||
|
}
|
||||||
|
|
||||||
|
outpos -= remaining;
|
||||||
|
readbuf += (remaining * 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MPEG_PlayFile(char *filename)
|
||||||
|
{
|
||||||
|
memset(buf0, 0, BUF_SIZE);
|
||||||
|
|
||||||
|
in_file = fopen(filename, "rb");
|
||||||
|
|
||||||
|
initialise_globals();
|
||||||
|
|
||||||
|
cnt = 0;
|
||||||
|
mpeg_eof = 0;
|
||||||
|
outpos = 0;
|
||||||
|
dst = buf0;
|
||||||
|
readbuf = buf0;
|
||||||
|
|
||||||
|
gethdr(&m1hdr);
|
||||||
|
if (m1hdr.protection_bit == 0) getcrc();
|
||||||
|
|
||||||
|
// printf("%d Hz, layer %d\n", t_sampling_frequency[m1hdr.ID][m1hdr.sampling_frequency], m1hdr.layer);
|
||||||
|
|
||||||
|
// stream_set_srate(stream, t_sampling_frequency[m1hdr.ID][m1hdr.sampling_frequency]);
|
||||||
|
|
||||||
|
// prime the stream
|
||||||
|
if (m1hdr.layer == 1)
|
||||||
|
{
|
||||||
|
layer3_frame(&m1hdr, cnt);
|
||||||
|
}
|
||||||
|
else if (m1hdr.layer == 2)
|
||||||
|
{
|
||||||
|
layer2_frame(&m1hdr, cnt);
|
||||||
|
}
|
||||||
|
|
||||||
|
playing = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern void m1setfile(const char *mstart, int mend);
|
||||||
|
void MPEG_PlayMemory(const char *sa, int length)
|
||||||
|
{
|
||||||
|
memset(buf0, 0, BUF_SIZE);
|
||||||
|
|
||||||
|
m1setfile(sa, length);
|
||||||
|
|
||||||
|
initialise_globals();
|
||||||
|
|
||||||
|
cnt = 0;
|
||||||
|
mpeg_eof = 0;
|
||||||
|
outpos = 0;
|
||||||
|
dst = buf0;
|
||||||
|
readbuf = buf0;
|
||||||
|
|
||||||
|
gethdr(&m1hdr);
|
||||||
|
if (m1hdr.protection_bit == 0) getcrc();
|
||||||
|
|
||||||
|
// printf("%d Hz, layer %d\n", t_sampling_frequency[m1hdr.ID][m1hdr.sampling_frequency], m1hdr.layer);
|
||||||
|
|
||||||
|
// stream_set_srate(stream, t_sampling_frequency[m1hdr.ID][m1hdr.sampling_frequency]);
|
||||||
|
|
||||||
|
// prime the stream
|
||||||
|
if (m1hdr.layer == 1)
|
||||||
|
{
|
||||||
|
layer3_frame(&m1hdr, cnt);
|
||||||
|
}
|
||||||
|
else if (m1hdr.layer == 2)
|
||||||
|
{
|
||||||
|
layer2_frame(&m1hdr, cnt);
|
||||||
|
}
|
||||||
|
|
||||||
|
in_file = NULL;
|
||||||
|
|
||||||
|
playing = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MPEG_StopPlaying(void)
|
||||||
|
{
|
||||||
|
if (playing)
|
||||||
|
{
|
||||||
|
playing = 0;
|
||||||
|
if (in_file)
|
||||||
|
fclose(in_file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL MPEG_Init(void)
|
||||||
|
{
|
||||||
|
if (!decoder_init)
|
||||||
|
{
|
||||||
|
initialise_decoder(); /* initialise decoder */
|
||||||
|
decoder_init = 1;
|
||||||
|
buf0 = new(std::nothrow) char[BUF_SIZE];
|
||||||
|
if (NULL == buf0)
|
||||||
|
return FAIL;
|
||||||
|
memset(buf0, 0, BUF_SIZE);
|
||||||
|
playing = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return OKAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MPEG_Shutdown( void )
|
||||||
|
{
|
||||||
|
decoder_init = 0;
|
||||||
|
if (buf0 != NULL)
|
||||||
|
delete [] buf0;
|
||||||
|
buf0 = NULL;
|
||||||
|
}
|
||||||
|
|
180
Src/Sound/MPEG/audio.h
Normal file
180
Src/Sound/MPEG/audio.h
Normal file
|
@ -0,0 +1,180 @@
|
||||||
|
/* this file is a part of amp software, (C) tomislav uzelac 1996,1997
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* audio.h some global variables
|
||||||
|
*
|
||||||
|
* Created by: tomislav uzelac Mar/Apr, Jul 96
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
struct AUDIO_HEADER {
|
||||||
|
int ID;
|
||||||
|
int layer;
|
||||||
|
int protection_bit;
|
||||||
|
int bitrate_index;
|
||||||
|
int sampling_frequency;
|
||||||
|
int padding_bit;
|
||||||
|
int private_bit;
|
||||||
|
int mode;
|
||||||
|
int mode_extension;
|
||||||
|
int copyright;
|
||||||
|
int original;
|
||||||
|
int emphasis;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SIDE_INFO {
|
||||||
|
int main_data_begin;
|
||||||
|
int scfsi[2][4];
|
||||||
|
int part2_3_length[2][2];
|
||||||
|
int big_values[2][2];
|
||||||
|
int global_gain[2][2];
|
||||||
|
int scalefac_compress[2][2];
|
||||||
|
int window_switching_flag[2][2];
|
||||||
|
int block_type[2][2];
|
||||||
|
int mixed_block_flag[2][2];
|
||||||
|
int table_select[2][2][3];
|
||||||
|
int subblock_gain[2][2][3];
|
||||||
|
int region0_count[2][2];
|
||||||
|
int region1_count[2][2];
|
||||||
|
int preflag[2][2];
|
||||||
|
int scalefac_scale[2][2];
|
||||||
|
int count1table_select[2][2];
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* global stuff
|
||||||
|
*/
|
||||||
|
|
||||||
|
extern FILE *in_file,*out_file;
|
||||||
|
|
||||||
|
extern void statusDisplay(struct AUDIO_HEADER *header, int frameNo);
|
||||||
|
extern int decodeMPEG(void);
|
||||||
|
extern void initialise_globals(void);
|
||||||
|
extern void report_header_error(int err);
|
||||||
|
|
||||||
|
extern int scalefac_l[2][2][22];
|
||||||
|
extern int scalefac_s[2][2][13][3];
|
||||||
|
extern int t_b8_l[2][3][22];
|
||||||
|
extern int t_b8_s[2][3][13];
|
||||||
|
extern short t_bitrate[2][3][15];
|
||||||
|
|
||||||
|
extern int is[2][578];
|
||||||
|
extern float xr[2][32][18];
|
||||||
|
|
||||||
|
extern int *t_l,*t_s;
|
||||||
|
extern int nch;
|
||||||
|
extern int t_sampling_frequency[2][3];
|
||||||
|
|
||||||
|
extern int A_QUIET,A_SHOW_CNT,A_FORMAT_WAVE,A_DUMP_BINARY;
|
||||||
|
extern int A_WRITE_TO_AUDIO,A_WRITE_TO_FILE;
|
||||||
|
extern short pcm_sample[64];
|
||||||
|
extern int A_AUDIO_PLAY;
|
||||||
|
extern int A_SET_VOLUME,A_SHOW_TIME;
|
||||||
|
extern int A_MSG_STDOUT;
|
||||||
|
extern int A_DOWNMIX;
|
||||||
|
|
||||||
|
/* GUI CONTROL STUFF */
|
||||||
|
extern int GUI_PLAY;
|
||||||
|
extern int GUI_PLAYING;
|
||||||
|
extern int GUI_PAUSE;
|
||||||
|
extern int GUI_PAUSED;
|
||||||
|
extern int GUI_STOP;
|
||||||
|
extern int GUI_STOPPED;
|
||||||
|
extern int GUI_FD_TO_PLAY;
|
||||||
|
extern int GUI_NEXT_FILE_READY;
|
||||||
|
|
||||||
|
/* GUI control stuff */
|
||||||
|
extern int send_fd;
|
||||||
|
extern int receive_fd;
|
||||||
|
|
||||||
|
extern int stop_flag;
|
||||||
|
extern int quit_flag;
|
||||||
|
|
||||||
|
/* ...
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef AUDIO
|
||||||
|
|
||||||
|
FILE *in_file,*out_file;
|
||||||
|
|
||||||
|
int scalefac_l[2][2][22];
|
||||||
|
int scalefac_s[2][2][13][3];
|
||||||
|
|
||||||
|
int is[2][578];
|
||||||
|
float xr[2][32][18];
|
||||||
|
|
||||||
|
int *t_l,*t_s;
|
||||||
|
int nch;
|
||||||
|
int t_sampling_frequency[2][3] = {
|
||||||
|
{ 22050 , 24000 , 16000},
|
||||||
|
{ 44100 , 48000 , 32000}
|
||||||
|
};
|
||||||
|
|
||||||
|
/* GUI control stuff */
|
||||||
|
int send_fd;
|
||||||
|
int receive_fd;
|
||||||
|
|
||||||
|
int stop_flag;
|
||||||
|
int quit_flag;
|
||||||
|
|
||||||
|
int GUI_PLAY,GUI_PLAYING,GUI_STOP,GUI_STOPPED,GUI_PAUSE,GUI_PAUSED;
|
||||||
|
int GUI_FD_TO_PLAY,GUI_NEXT_FILE_READY;
|
||||||
|
|
||||||
|
int A_QUIET,A_SHOW_CNT,A_FORMAT_WAVE,A_DUMP_BINARY;
|
||||||
|
int A_WRITE_TO_FILE;
|
||||||
|
int A_AUDIO_PLAY;
|
||||||
|
int A_SET_VOLUME, A_SHOW_TIME;
|
||||||
|
int A_MSG_STDOUT;
|
||||||
|
int A_DOWNMIX;
|
||||||
|
|
||||||
|
short pcm_sample[64];
|
||||||
|
|
||||||
|
short t_bitrate[2][3][15] = {{
|
||||||
|
{0,32,48,56,64,80,96,112,128,144,160,176,192,224,256},
|
||||||
|
{0,8,16,24,32,40,48,56,64,80,96,112,128,144,160},
|
||||||
|
{0,8,16,24,32,40,48,56,64,80,96,112,128,144,160}
|
||||||
|
},{
|
||||||
|
{0,32,64,96,128,160,192,224,256,288,320,352,384,416,448},
|
||||||
|
{0,32,48,56,64,80,96,112,128,160,192,224,256,320,384},
|
||||||
|
{0,32,40,48,56,64,80,96,112,128,160,192,224,256,320}
|
||||||
|
}};
|
||||||
|
|
||||||
|
/* the last sfb is given implicitly on pg.28. of the standard. scalefactors
|
||||||
|
* for that one are 0, pretab also
|
||||||
|
*/
|
||||||
|
/* leftmost index denotes ID, so first three tables are for MPEG2 (header->ID==0)
|
||||||
|
* and the other three are for MPEG1 (header->ID==1)
|
||||||
|
*/
|
||||||
|
/* 22.05, 24, 16 */
|
||||||
|
int t_b8_l[2][3][22]={{ /* table B.8b ISO/IEC 11172-3 */
|
||||||
|
{5,11,17,23,29,35,43,53,65,79,95,115,139,167,199,237,283,335,395,463,521,575},
|
||||||
|
{5,11,17,23,29,35,43,53,65,79,95,113,135,161,193,231,277,331,393,463,539,575},
|
||||||
|
{5,11,17,23,29,35,43,53,65,79,95,115,139,167,199,237,283,335,395,463,521,575}
|
||||||
|
},{
|
||||||
|
{3,7,11,15,19,23,29,35,43,51,61,73,89,109,133,161,195,237,287,341,417,575},
|
||||||
|
{3,7,11,15,19,23,29,35,41,49,59,71,87,105,127,155,189,229,275,329,383,575},
|
||||||
|
{3,7,11,15,19,23,29,35,43,53,65,81,101,125,155,193,239,295,363,447,549,575}
|
||||||
|
}};
|
||||||
|
int t_b8_s[2][3][13]={{ /* table B.8b ISO/IEC 11172-3 */
|
||||||
|
{3,7,11,17,23,31,41,55,73,99,131,173,191},
|
||||||
|
{3,7,11,17,25,35,47,61,79,103,135,179,191},
|
||||||
|
{3,7,11,17,25,35,47,61,79,103,133,173,191}
|
||||||
|
},{
|
||||||
|
{3,7,11,15,21,29,39,51,65,83,105,135,191},
|
||||||
|
{3,7,11,15,21,27,37,49,63,79,99,125,191},
|
||||||
|
{3,7,11,15,21,29,41,57,77,103,137,179,191}
|
||||||
|
}};
|
||||||
|
|
||||||
|
int args(int argc,char **argv);
|
||||||
|
void initialise_decoder(void);
|
||||||
|
int decodeMPEG(void);
|
||||||
|
void initialise_globals(void);
|
||||||
|
void report_header_error(int err);
|
||||||
|
int setup_audio(struct AUDIO_HEADER *header);
|
||||||
|
void close_audio(void);
|
||||||
|
int ready_audio(void);
|
||||||
|
|
||||||
|
void play(char *inFileStr, char *outFileStr);
|
||||||
|
|
||||||
|
#endif /* AUDIO */
|
62
Src/Sound/MPEG/config.h
Normal file
62
Src/Sound/MPEG/config.h
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
/* Define to empty if the keyword does not work. */
|
||||||
|
/* #undef const */
|
||||||
|
|
||||||
|
/* Define if you don't have vprintf but do have _doprnt. */
|
||||||
|
/* #undef HAVE_DOPRNT */
|
||||||
|
|
||||||
|
/* Define if you have <sys/wait.h> that is POSIX.1 compatible. */
|
||||||
|
//#define HAVE_SYS_WAIT_H 1
|
||||||
|
|
||||||
|
/* Define if you have the vprintf function. */
|
||||||
|
//#define HAVE_VPRINTF 1
|
||||||
|
|
||||||
|
/* Define as __inline if that's what the C compiler calls it. */
|
||||||
|
/* #undef inline */
|
||||||
|
|
||||||
|
/* Define if you have the ANSI C header files. */
|
||||||
|
#define STDC_HEADERS 1
|
||||||
|
|
||||||
|
/* Define if you can safely include both <sys/time.h> and <time.h>. */
|
||||||
|
//#define TIME_WITH_SYS_TIME 1
|
||||||
|
|
||||||
|
/* Define if you have the mlock function. */
|
||||||
|
//#define HAVE_MLOCK 1
|
||||||
|
|
||||||
|
/* Define if you have the mlockall function. */
|
||||||
|
//#define HAVE_MLOCKALL 1
|
||||||
|
|
||||||
|
/* Define if you have the sched_setscheduler function. */
|
||||||
|
//#define HAVE_SCHED_SETSCHEDULER 1
|
||||||
|
|
||||||
|
/* Define if you have the select function. */
|
||||||
|
//#define HAVE_SELECT 1
|
||||||
|
|
||||||
|
/* Define if you have the <dmedia/audio.h> header file. */
|
||||||
|
/* #undef HAVE_DMEDIA_AUDIO_H */
|
||||||
|
|
||||||
|
/* Define if you have the <fcntl.h> header file. */
|
||||||
|
//#define HAVE_FCNTL_H 1
|
||||||
|
|
||||||
|
/* Define if you have the <linux/soundcard.h> header file. */
|
||||||
|
//#define HAVE_LINUX_SOUNDCARD_H 1
|
||||||
|
|
||||||
|
/* Define if you have the <machine/soundcard.h> header file. */
|
||||||
|
/* #undef HAVE_MACHINE_SOUNDCARD_H */
|
||||||
|
|
||||||
|
/* Define if you have the <sys/audioio.h> header file. */
|
||||||
|
/* #undef HAVE_SYS_AUDIOIO_H */
|
||||||
|
|
||||||
|
/* Define if you have the <sys/ioctl.h> header file. */
|
||||||
|
//#define HAVE_SYS_IOCTL_H 1
|
||||||
|
|
||||||
|
/* Define if you have the <sys/select.h> header file. */
|
||||||
|
//#define HAVE_SYS_SELECT_H 1
|
||||||
|
|
||||||
|
/* Define if you have the <sys/time.h> header file. */
|
||||||
|
//#define HAVE_SYS_TIME_H 1
|
||||||
|
|
||||||
|
/* Define if you have the <unistd.h> header file. */
|
||||||
|
#define HAVE_UNISTD_H 1
|
||||||
|
|
||||||
|
/* define if you want playing to use Linux realtime features */
|
||||||
|
/* #undef LINUX_REALTIME */
|
64
Src/Sound/MPEG/dump.cpp
Normal file
64
Src/Sound/MPEG/dump.cpp
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
/* this file is a part of amp software, (C) tomislav uzelac 1996,1997
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* dump.c binary/hex dump from buffer
|
||||||
|
*
|
||||||
|
* Created by: tomislav uzelac May 1996
|
||||||
|
* Last modified by: tomislav May 31 1997
|
||||||
|
*/
|
||||||
|
//#include <unistd.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "audio.h"
|
||||||
|
#include "getbits.h"
|
||||||
|
|
||||||
|
#define DUMP
|
||||||
|
#include "dump.h"
|
||||||
|
|
||||||
|
/* no hex dump, sorry
|
||||||
|
*/
|
||||||
|
void dump(int *length) /* in fact int length[4] */
|
||||||
|
{
|
||||||
|
int i,j;
|
||||||
|
int _data,space=0;
|
||||||
|
printf(" *********** binary dump\n");
|
||||||
|
_data=data;
|
||||||
|
for (i=0;i<4;i++) {
|
||||||
|
for (j=0;j<space;j++) printf(" ");
|
||||||
|
for (j=0;j<length[i];j++) {
|
||||||
|
printf("%1d",(buffer[_data/8] >> (7-(_data&7)) )&1 );
|
||||||
|
space++;
|
||||||
|
_data++;
|
||||||
|
_data&=8*BUFFER_SIZE-1;
|
||||||
|
if (!(_data & 7)) {
|
||||||
|
printf(" ");
|
||||||
|
space++;
|
||||||
|
if (space>70) {
|
||||||
|
printf("\n");
|
||||||
|
space=0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printf("~\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void show_header(struct AUDIO_HEADER *header)
|
||||||
|
{
|
||||||
|
int bitrate=t_bitrate[header->ID][3-header->layer][header->bitrate_index];
|
||||||
|
int fs=t_sampling_frequency[header->ID][header->sampling_frequency];
|
||||||
|
int mpg,layer;
|
||||||
|
char stm[8];
|
||||||
|
if (A_QUIET) return;
|
||||||
|
layer=4-header->layer;
|
||||||
|
if (header->ID==1) mpg=1;
|
||||||
|
else mpg=2;
|
||||||
|
if (header->mode==3) strcpy(stm,"mono");
|
||||||
|
else strcpy(stm,"stereo");
|
||||||
|
|
||||||
|
printf("\n\
|
||||||
|
Properties: %s %dHz\n\
|
||||||
|
Coding Method: MPEG%1d.0 layer%1d\n\
|
||||||
|
Bitrate: %dkbit/s\n"\
|
||||||
|
,stm,fs,mpg,layer,bitrate);
|
||||||
|
}
|
18
Src/Sound/MPEG/dump.h
Normal file
18
Src/Sound/MPEG/dump.h
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
/* this file is a part of amp software, (C) tomislav uzelac 1996,1997
|
||||||
|
*/
|
||||||
|
/* dump.h
|
||||||
|
*
|
||||||
|
* Last modified by: tomislav uzelac May 31 1997
|
||||||
|
*/
|
||||||
|
|
||||||
|
extern void dump(int *length);
|
||||||
|
extern void show_header(struct AUDIO_HEADER *header);
|
||||||
|
|
||||||
|
#ifdef DUMP
|
||||||
|
void dump(int *length);
|
||||||
|
void show_header(struct AUDIO_HEADER *header);
|
||||||
|
/*
|
||||||
|
static char *t_modes[] = {
|
||||||
|
"stereo","joint_stereo","dual_channel","single_channel"};
|
||||||
|
*/
|
||||||
|
#endif /* DUMP */
|
14
Src/Sound/MPEG/formats.h
Normal file
14
Src/Sound/MPEG/formats.h
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
/* this file is a part of amp software, (C) tomislav uzelac 1996,1997
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* formats.h
|
||||||
|
*
|
||||||
|
* Created by: tomislav uzelac Dec 22 1996
|
||||||
|
*/
|
||||||
|
extern void wav_end(struct AUDIO_HEADER *header);
|
||||||
|
extern void wav_begin(void);
|
||||||
|
|
||||||
|
#ifdef FORMATS
|
||||||
|
void wav_end(struct AUDIO_HEADER *header);
|
||||||
|
void wav_begin(void);
|
||||||
|
#endif /* FORMATS */
|
370
Src/Sound/MPEG/getbits.cpp
Normal file
370
Src/Sound/MPEG/getbits.cpp
Normal file
|
@ -0,0 +1,370 @@
|
||||||
|
/* this file is a part of amp software, (C) tomislav uzelac 1996,1997
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* getbits.c bit level routines, input buffer
|
||||||
|
*
|
||||||
|
* Created by: tomislav uzelac Apr 1996
|
||||||
|
* better synchronization, tomislav uzelac, Apr 23 1997
|
||||||
|
*/
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "amp.h"
|
||||||
|
#include "audio.h"
|
||||||
|
#include "formats.h"
|
||||||
|
#include "rtbuf.h"
|
||||||
|
|
||||||
|
#define GETBITS
|
||||||
|
#include "getbits.h"
|
||||||
|
|
||||||
|
static const char *fstart, *lstart;
|
||||||
|
static int offset, end, eof, lend;
|
||||||
|
|
||||||
|
int MPEG_GetProgress(void)
|
||||||
|
{
|
||||||
|
if (in_file) return ftell(in_file);
|
||||||
|
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
void m1setfile(const char *mstart, int mend)
|
||||||
|
{
|
||||||
|
fstart = mstart;
|
||||||
|
offset = 0;
|
||||||
|
eof = 0;
|
||||||
|
end = mend;
|
||||||
|
lstart = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MPEG_SetLoop(const char *loop, int loopend)
|
||||||
|
{
|
||||||
|
lstart = loop;
|
||||||
|
lend = loopend;
|
||||||
|
}
|
||||||
|
|
||||||
|
int m1fread(unsigned char *buf, int size1, int size2, void *f)
|
||||||
|
{
|
||||||
|
int total = size1 * size2;
|
||||||
|
|
||||||
|
if (in_file) return fread(buf, size1, size2, (FILE *) f);
|
||||||
|
|
||||||
|
// if past EOF
|
||||||
|
if ((total + offset) >= end)
|
||||||
|
{
|
||||||
|
if (lstart == NULL)
|
||||||
|
{
|
||||||
|
total = end - offset;
|
||||||
|
eof = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// if past the end, do the xfer in 2 pieces
|
||||||
|
if ((total + offset) > end)
|
||||||
|
{
|
||||||
|
memcpy(buf, fstart + offset, end-offset);
|
||||||
|
buf += (end-offset);
|
||||||
|
total -= (end-offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
fstart = lstart;
|
||||||
|
offset = 0;
|
||||||
|
end = lend;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(buf, fstart + offset, total);
|
||||||
|
|
||||||
|
offset += total;
|
||||||
|
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
|
int m1feof(void *f)
|
||||||
|
{
|
||||||
|
if (in_file) return feof((FILE *)f);
|
||||||
|
return eof;
|
||||||
|
}
|
||||||
|
|
||||||
|
int m1fseek(void *f, int offs, int whence)
|
||||||
|
{
|
||||||
|
if (in_file) return fseek((FILE *) f, offs, whence);
|
||||||
|
|
||||||
|
switch (whence)
|
||||||
|
{
|
||||||
|
case SEEK_CUR:
|
||||||
|
if ((offset + offs) < 0)
|
||||||
|
{
|
||||||
|
offset = 0;
|
||||||
|
eof = 0;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if ((offset + offs) > end)
|
||||||
|
{
|
||||||
|
offset = end;
|
||||||
|
eof = 1;
|
||||||
|
return end;
|
||||||
|
}
|
||||||
|
offset += offs;
|
||||||
|
eof = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* buffer and bit manipulation functions ***************************************
|
||||||
|
*/
|
||||||
|
static inline int _fillbfr(unsigned int size)
|
||||||
|
{
|
||||||
|
_bptr=0;
|
||||||
|
return get_input(_buffer, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int readsync()
|
||||||
|
{
|
||||||
|
_bptr=0;
|
||||||
|
_buffer[0]=_buffer[1];
|
||||||
|
_buffer[1]=_buffer[2];
|
||||||
|
_buffer[2]=_buffer[3];
|
||||||
|
return get_input(&_buffer[3],1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline unsigned int _getbits(int n)
|
||||||
|
{
|
||||||
|
unsigned int pos,ret_value;
|
||||||
|
|
||||||
|
pos = _bptr >> 3;
|
||||||
|
ret_value = _buffer[pos] << 24 |
|
||||||
|
_buffer[pos+1] << 16 |
|
||||||
|
_buffer[pos+2] << 8 |
|
||||||
|
_buffer[pos+3];
|
||||||
|
ret_value <<= _bptr & 7;
|
||||||
|
ret_value >>= 32 - n;
|
||||||
|
_bptr += n;
|
||||||
|
return ret_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fillbfr(unsigned int advance)
|
||||||
|
{
|
||||||
|
int overflow,retval;
|
||||||
|
|
||||||
|
retval=get_input(&buffer[append], advance);
|
||||||
|
|
||||||
|
if ( append + advance >= BUFFER_SIZE ) {
|
||||||
|
overflow = append + advance - BUFFER_SIZE;
|
||||||
|
memcpy (buffer,&buffer[BUFFER_SIZE], overflow);
|
||||||
|
if (overflow < 4) memcpy(&buffer[BUFFER_SIZE],buffer,4);
|
||||||
|
append = overflow;
|
||||||
|
} else {
|
||||||
|
if (append==0) memcpy(&buffer[BUFFER_SIZE],buffer,4);
|
||||||
|
append+=advance;
|
||||||
|
}
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int getbits(int n)
|
||||||
|
{
|
||||||
|
if (n) {
|
||||||
|
unsigned int pos,ret_value;
|
||||||
|
|
||||||
|
pos = data >> 3;
|
||||||
|
ret_value = buffer[pos] << 24 |
|
||||||
|
buffer[pos+1] << 16 |
|
||||||
|
buffer[pos+2] << 8 |
|
||||||
|
buffer[pos+3];
|
||||||
|
ret_value <<= data & 7;
|
||||||
|
ret_value >>= 32 - n;
|
||||||
|
|
||||||
|
data += n;
|
||||||
|
data &= (8*BUFFER_SIZE)-1;
|
||||||
|
|
||||||
|
return ret_value;
|
||||||
|
} else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* header and side info parsing stuff ******************************************
|
||||||
|
*/
|
||||||
|
static inline void parse_header(struct AUDIO_HEADER *header)
|
||||||
|
{
|
||||||
|
header->ID=_getbits(1);
|
||||||
|
header->layer=_getbits(2);
|
||||||
|
header->protection_bit=_getbits(1);
|
||||||
|
header->bitrate_index=_getbits(4);
|
||||||
|
header->sampling_frequency=_getbits(2);
|
||||||
|
header->padding_bit=_getbits(1);
|
||||||
|
header->private_bit=_getbits(1);
|
||||||
|
header->mode=_getbits(2);
|
||||||
|
header->mode_extension=_getbits(2);
|
||||||
|
if (!header->mode) header->mode_extension=0;
|
||||||
|
header->copyright=_getbits(1);
|
||||||
|
header->original=_getbits(1);
|
||||||
|
header->emphasis=_getbits(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int header_sanity_check(struct AUDIO_HEADER *header)
|
||||||
|
{
|
||||||
|
if ( header->layer==0 ||
|
||||||
|
header->bitrate_index==15 ||
|
||||||
|
header->sampling_frequency==3) return -1;
|
||||||
|
|
||||||
|
/* an additional check to make shure that stuffing never gets mistaken
|
||||||
|
* for a syncword. This rules out some legal layer1 streams, but who
|
||||||
|
* cares about layer1 anyway :-). I must get this right sometime.
|
||||||
|
*/
|
||||||
|
if ( header->ID==1 && header->layer==3 && header->protection_bit==1) return -1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int gethdr(struct AUDIO_HEADER *header)
|
||||||
|
{
|
||||||
|
int s,retval;
|
||||||
|
struct AUDIO_HEADER tmp;
|
||||||
|
|
||||||
|
/* TODO: add a simple byte counter to check only first, say, 1024
|
||||||
|
* bytes for a new header and then return GETHDR_SYN
|
||||||
|
*/
|
||||||
|
if ((retval=_fillbfr(4))!=0) return retval;
|
||||||
|
|
||||||
|
for(;;) {
|
||||||
|
while ((s=_getbits(12)) != 0xfff) {
|
||||||
|
if (s==0xffe) {
|
||||||
|
parse_header(&tmp);
|
||||||
|
if (header_sanity_check(&tmp)==0) return GETHDR_NS;
|
||||||
|
}
|
||||||
|
if ((retval=readsync())!=0) return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
parse_header(&tmp);
|
||||||
|
if (header_sanity_check(&tmp)!=0) {
|
||||||
|
if ((retval=readsync())!=0) return retval;
|
||||||
|
} else break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tmp.layer==3) return GETHDR_FL1;
|
||||||
|
/* if (tmp.layer==2) return GETHDR_FL2; */
|
||||||
|
if (tmp.bitrate_index==0) return GETHDR_FF;
|
||||||
|
|
||||||
|
//printf("layer: %d\n", tmp.layer);
|
||||||
|
//printf("sampling frequency: %d\n", tmp.sampling_frequency);
|
||||||
|
|
||||||
|
memcpy(header,&tmp,sizeof(tmp));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* dummy function, to get crc out of the way
|
||||||
|
*/
|
||||||
|
void getcrc()
|
||||||
|
{
|
||||||
|
_fillbfr(2);
|
||||||
|
_getbits(16);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* sizes of side_info:
|
||||||
|
* MPEG1 1ch 17 2ch 32
|
||||||
|
* MPEG2 1ch 9 2ch 17
|
||||||
|
*/
|
||||||
|
void getinfo(struct AUDIO_HEADER *header,struct SIDE_INFO *info)
|
||||||
|
{
|
||||||
|
int gr,ch,scfsi_band,region,window;
|
||||||
|
int nch;
|
||||||
|
if (header->mode==3) {
|
||||||
|
nch=1;
|
||||||
|
if (header->ID) {
|
||||||
|
_fillbfr(17);
|
||||||
|
info->main_data_begin=_getbits(9);
|
||||||
|
_getbits(5);
|
||||||
|
} else {
|
||||||
|
_fillbfr(9);
|
||||||
|
info->main_data_begin=_getbits(8);
|
||||||
|
_getbits(1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
nch=2;
|
||||||
|
if (header->ID) {
|
||||||
|
_fillbfr(32);
|
||||||
|
info->main_data_begin=_getbits(9);
|
||||||
|
_getbits(3);
|
||||||
|
} else {
|
||||||
|
_fillbfr(17);
|
||||||
|
info->main_data_begin=_getbits(8);
|
||||||
|
_getbits(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (header->ID) for (ch=0;ch<nch;ch++)
|
||||||
|
for (scfsi_band=0;scfsi_band<4;scfsi_band++)
|
||||||
|
info->scfsi[ch][scfsi_band]=_getbits(1);
|
||||||
|
|
||||||
|
for (gr=0;gr<(header->ID ? 2:1);gr++)
|
||||||
|
for (ch=0;ch<nch;ch++) {
|
||||||
|
info->part2_3_length[gr][ch]=_getbits(12);
|
||||||
|
info->big_values[gr][ch]=_getbits(9);
|
||||||
|
info->global_gain[gr][ch]=_getbits(8);
|
||||||
|
if (header->ID) info->scalefac_compress[gr][ch]=_getbits(4);
|
||||||
|
else info->scalefac_compress[gr][ch]=_getbits(9);
|
||||||
|
info->window_switching_flag[gr][ch]=_getbits(1);
|
||||||
|
|
||||||
|
if (info->window_switching_flag[gr][ch]) {
|
||||||
|
info->block_type[gr][ch]=_getbits(2);
|
||||||
|
info->mixed_block_flag[gr][ch]=_getbits(1);
|
||||||
|
|
||||||
|
for (region=0;region<2;region++)
|
||||||
|
info->table_select[gr][ch][region]=_getbits(5);
|
||||||
|
info->table_select[gr][ch][2]=0;
|
||||||
|
|
||||||
|
for (window=0;window<3;window++)
|
||||||
|
info->subblock_gain[gr][ch][window]=_getbits(3);
|
||||||
|
} else {
|
||||||
|
for (region=0;region<3;region++)
|
||||||
|
info->table_select[gr][ch][region]=_getbits(5);
|
||||||
|
|
||||||
|
info->region0_count[gr][ch]=_getbits(4);
|
||||||
|
info->region1_count[gr][ch]=_getbits(3);
|
||||||
|
info->block_type[gr][ch]=0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (header->ID) info->preflag[gr][ch]=_getbits(1);
|
||||||
|
info->scalefac_scale[gr][ch]=_getbits(1);
|
||||||
|
info->count1table_select[gr][ch]=_getbits(1);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dummy_getinfo(int n)
|
||||||
|
{
|
||||||
|
n-=4;
|
||||||
|
if ( m1fseek(in_file,n,SEEK_CUR) != 0)
|
||||||
|
{
|
||||||
|
if (m1feof(in_file)) return GETHDR_EOF;
|
||||||
|
else return GETHDR_ERR;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int rewind_stream(int nbytes)
|
||||||
|
{
|
||||||
|
nbytes+=5;
|
||||||
|
if (m1fseek(in_file, -nbytes, SEEK_CUR) != 0) {
|
||||||
|
/* what if we need to be at the very beginning? */
|
||||||
|
nbytes--;
|
||||||
|
if (m1fseek(in_file, -nbytes, SEEK_CUR) != 0) return GETHDR_ERR;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int get_input(unsigned char* bp, unsigned int size)
|
||||||
|
{
|
||||||
|
#ifdef LINUX_REALTIME
|
||||||
|
return prefetch_get_input(bp,size);
|
||||||
|
#else /* LINUX_REALTIME */
|
||||||
|
if ( m1fread( bp , 1, size, in_file) != size)
|
||||||
|
{
|
||||||
|
if (m1feof(in_file)) return GETHDR_EOF;
|
||||||
|
else return GETHDR_ERR;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
#endif /* LINUX_REALTIME */
|
||||||
|
}
|
79
Src/Sound/MPEG/getbits.h
Normal file
79
Src/Sound/MPEG/getbits.h
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
/* this file is a part of amp software, (C) tomislav uzelac 1996,1997
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* getbits.h
|
||||||
|
*
|
||||||
|
* Created by: tomislav uzelac Apr 1996
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* gethdr() error codes
|
||||||
|
*/
|
||||||
|
#define GETHDR_ERR 0x1
|
||||||
|
#define GETHDR_NS 0x2
|
||||||
|
#define GETHDR_FL1 0x4
|
||||||
|
#define GETHDR_FL2 0x8
|
||||||
|
#define GETHDR_FF 0x10
|
||||||
|
#define GETHDR_SYN 0x20
|
||||||
|
#define GETHDR_EOF 0x30
|
||||||
|
|
||||||
|
/* buffer for the 'bit reservoir'
|
||||||
|
*/
|
||||||
|
#define BUFFER_SIZE 4096
|
||||||
|
#define BUFFER_AUX 2048
|
||||||
|
extern unsigned char buffer[];
|
||||||
|
extern int append,data,f_bdirty,bclean_bytes;
|
||||||
|
|
||||||
|
/* exports
|
||||||
|
*/
|
||||||
|
extern int fillbfr(unsigned int advance);
|
||||||
|
extern unsigned int getbits(int n);
|
||||||
|
extern int gethdr(struct AUDIO_HEADER *header);
|
||||||
|
extern void getcrc();
|
||||||
|
extern void getinfo(struct AUDIO_HEADER *header,struct SIDE_INFO *info);
|
||||||
|
extern int dummy_getinfo(int n);
|
||||||
|
extern int rewind_stream(int nbytes);
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef GETBITS
|
||||||
|
|
||||||
|
/* buffer, AUX is used in case of input buffer "overflow", and its contents
|
||||||
|
* are copied to the beginning of the buffer
|
||||||
|
*/
|
||||||
|
unsigned char buffer[BUFFER_SIZE+BUFFER_AUX];
|
||||||
|
|
||||||
|
/* buffer pointers: append counts in bytes, data in bits
|
||||||
|
*/
|
||||||
|
int append,data;
|
||||||
|
|
||||||
|
/* bit reservoir stuff. f_bdirty must be set to TRUE when starting play!
|
||||||
|
*/
|
||||||
|
int f_bdirty,bclean_bytes;
|
||||||
|
|
||||||
|
/* internal buffer, _bptr holds the position in _bits_
|
||||||
|
*/
|
||||||
|
static unsigned char _buffer[32];
|
||||||
|
static int _bptr;
|
||||||
|
|
||||||
|
|
||||||
|
/* buffer and bit manipulation functions
|
||||||
|
*/
|
||||||
|
static inline int _fillbfr(unsigned int size);
|
||||||
|
static inline int readsync();
|
||||||
|
static inline int get_input(unsigned char* bp, unsigned int size);
|
||||||
|
static inline unsigned int _getbits(int n);
|
||||||
|
int fillbfr(unsigned int advance);
|
||||||
|
unsigned int getbits(int n);
|
||||||
|
int dummy_getinfo(int n);
|
||||||
|
int rewind_stream(int nbytes);
|
||||||
|
|
||||||
|
/* header and side info parsing stuff
|
||||||
|
*/
|
||||||
|
static inline void parse_header(struct AUDIO_HEADER *header);
|
||||||
|
static inline int header_sanity_check(struct AUDIO_HEADER *header);
|
||||||
|
|
||||||
|
int gethdr(struct AUDIO_HEADER *header);
|
||||||
|
void getcrc();
|
||||||
|
void getinfo(struct AUDIO_HEADER *header,struct SIDE_INFO *info);
|
||||||
|
|
||||||
|
#endif /* GETBITS */
|
||||||
|
|
232
Src/Sound/MPEG/getdata.cpp
Normal file
232
Src/Sound/MPEG/getdata.cpp
Normal file
|
@ -0,0 +1,232 @@
|
||||||
|
/* this file is a part of amp software, (C) tomislav uzelac 1996,1997
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* getdata.c scalefactor & huffman data extraction
|
||||||
|
*
|
||||||
|
* Created by: tomislav uzelac Apr 1996
|
||||||
|
* Last modified by: tomislav uzelac Feb 27 1997
|
||||||
|
*/
|
||||||
|
#include "amp.h"
|
||||||
|
#include "audio.h"
|
||||||
|
#include "getbits.h"
|
||||||
|
#include "huffman.h"
|
||||||
|
|
||||||
|
#define GETDATA
|
||||||
|
#include "getdata.h"
|
||||||
|
|
||||||
|
/* layer3 scalefactor decoding. should we check for the number
|
||||||
|
* of bits read, just in case?
|
||||||
|
*/
|
||||||
|
int decode_scalefactors(struct SIDE_INFO *info,struct AUDIO_HEADER *header,int gr,int ch)
|
||||||
|
{
|
||||||
|
int sfb,window;
|
||||||
|
int slen1,slen2;
|
||||||
|
int i1,i2,i=0;
|
||||||
|
int j,k;
|
||||||
|
if (header->ID==1) {
|
||||||
|
/* this is MPEG-1 scalefactors format, quite different than
|
||||||
|
* the MPEG-2 format.
|
||||||
|
*/
|
||||||
|
slen1=t_slen1[info->scalefac_compress[gr][ch]];
|
||||||
|
slen2=t_slen2[info->scalefac_compress[gr][ch]];
|
||||||
|
i1=3*slen1;
|
||||||
|
i2=3*slen2;
|
||||||
|
|
||||||
|
if (info->window_switching_flag[gr][ch] && info->block_type[gr][ch]==2) {
|
||||||
|
if (info->mixed_block_flag[gr][ch]) {
|
||||||
|
for (sfb=0;sfb<8;sfb++) {
|
||||||
|
scalefac_l[gr][ch][sfb]=getbits(slen1);
|
||||||
|
i+=slen1;
|
||||||
|
}
|
||||||
|
for (sfb=3;sfb<6;sfb++) {
|
||||||
|
for (window=0;window<3;window++)
|
||||||
|
scalefac_s[gr][ch][sfb][window]=getbits(slen1);
|
||||||
|
i+=i1;
|
||||||
|
}
|
||||||
|
for (;sfb<12;sfb++) {
|
||||||
|
for (window=0;window<3;window++)
|
||||||
|
scalefac_s[gr][ch][sfb][window]=getbits(slen2);
|
||||||
|
i+=i2;
|
||||||
|
}
|
||||||
|
} else { /* !mixed_block_flag */
|
||||||
|
for (sfb=0;sfb<6;sfb++) {
|
||||||
|
for (window=0;window<3;window++)
|
||||||
|
scalefac_s[gr][ch][sfb][window]=getbits(slen1);
|
||||||
|
i+=i1;
|
||||||
|
}
|
||||||
|
for (;sfb<12;sfb++) {
|
||||||
|
for (window=0;window<3;window++)
|
||||||
|
scalefac_s[gr][ch][sfb][window]=getbits(slen2);
|
||||||
|
i+=i2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (window=0;window<3;window++)
|
||||||
|
scalefac_s[gr][ch][12][window]=0;
|
||||||
|
} else { /* block_type!=2 */
|
||||||
|
if ( !info->scfsi[ch][0] || !gr )
|
||||||
|
for (sfb=0;sfb<6;sfb++) {
|
||||||
|
scalefac_l[gr][ch][sfb]=getbits(slen1);
|
||||||
|
i+=slen1;
|
||||||
|
}
|
||||||
|
else for (sfb=0;sfb<6;sfb++) {
|
||||||
|
scalefac_l[1][ch][sfb]=scalefac_l[0][ch][sfb];
|
||||||
|
}
|
||||||
|
if ( !info->scfsi[ch][1] || !gr )
|
||||||
|
for (sfb=6;sfb<11;sfb++) {
|
||||||
|
scalefac_l[gr][ch][sfb]=getbits(slen1);
|
||||||
|
i+=slen1;
|
||||||
|
}
|
||||||
|
else for (sfb=6;sfb<11;sfb++) {
|
||||||
|
scalefac_l[1][ch][sfb]=scalefac_l[0][ch][sfb];
|
||||||
|
}
|
||||||
|
if ( !info->scfsi[ch][2] || !gr )
|
||||||
|
for (sfb=11;sfb<16;sfb++) {
|
||||||
|
scalefac_l[gr][ch][sfb]=getbits(slen2);
|
||||||
|
i+=slen2;
|
||||||
|
}
|
||||||
|
else for (sfb=11;sfb<16;sfb++) {
|
||||||
|
scalefac_l[1][ch][sfb]=scalefac_l[0][ch][sfb];
|
||||||
|
}
|
||||||
|
if ( !info->scfsi[ch][3] || !gr )
|
||||||
|
for (sfb=16;sfb<21;sfb++) {
|
||||||
|
scalefac_l[gr][ch][sfb]=getbits(slen2);
|
||||||
|
i+=slen2;
|
||||||
|
}
|
||||||
|
else for (sfb=16;sfb<21;sfb++) {
|
||||||
|
scalefac_l[1][ch][sfb]=scalefac_l[0][ch][sfb];
|
||||||
|
}
|
||||||
|
scalefac_l[gr][ch][21]=0;
|
||||||
|
}
|
||||||
|
} else { /* ID==0 */
|
||||||
|
int index=0,index2,spooky_index;
|
||||||
|
int slen[6],nr_of_sfb[6]; /* actually, there's four of each, not five, labelled 1 through 4, but
|
||||||
|
* what's a word of storage compared to one's sanity. so [0] is irellevant.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* ok, so we got 3 indexes.
|
||||||
|
* spooky_index - indicates whether we use the normal set of slen eqs and nr_of_sfb tables
|
||||||
|
* or the one for the right channel of intensity stereo coded frame
|
||||||
|
* index - corresponds to the value of scalefac_compress, as listed in the standard
|
||||||
|
* index2 - 0 for long blocks, 1 for short wo/ mixed_block_flag, 2 for short with it
|
||||||
|
*/
|
||||||
|
if ( (header->mode_extension==1 || header->mode_extension==3) && ch==1) { /* right ch... */
|
||||||
|
int int_scalefac_compress=info->scalefac_compress[0][ch]>>1;
|
||||||
|
intensity_scale=info->scalefac_compress[0][1]&1;
|
||||||
|
spooky_index=1;
|
||||||
|
if (int_scalefac_compress < 180) {
|
||||||
|
slen[1]=int_scalefac_compress/36;
|
||||||
|
slen[2]=(int_scalefac_compress%36)/6;
|
||||||
|
slen[3]=(int_scalefac_compress%36)%6;
|
||||||
|
slen[4]=0;
|
||||||
|
info->preflag[0][ch]=0;
|
||||||
|
index=0;
|
||||||
|
}
|
||||||
|
if ( 180 <= int_scalefac_compress && int_scalefac_compress < 244) {
|
||||||
|
slen[1]=((int_scalefac_compress-180)%64)>>4;
|
||||||
|
slen[2]=((int_scalefac_compress-180)%16)>>2;
|
||||||
|
slen[3]=(int_scalefac_compress-180)%4;
|
||||||
|
slen[4]=0;
|
||||||
|
info->preflag[0][ch]=0;
|
||||||
|
index=1;
|
||||||
|
}
|
||||||
|
if ( 244 <= int_scalefac_compress && int_scalefac_compress < 255) {
|
||||||
|
slen[1]=(int_scalefac_compress-244)/3;
|
||||||
|
slen[2]=(int_scalefac_compress-244)%3;
|
||||||
|
slen[3]=0;
|
||||||
|
slen[4]=0;
|
||||||
|
info->preflag[0][ch]=0;
|
||||||
|
index=2;
|
||||||
|
}
|
||||||
|
} else { /* the usual */
|
||||||
|
spooky_index=0;
|
||||||
|
if (info->scalefac_compress[0][ch] < 400) {
|
||||||
|
slen[1]=(info->scalefac_compress[0][ch]>>4)/5;
|
||||||
|
slen[2]=(info->scalefac_compress[0][ch]>>4)%5;
|
||||||
|
slen[3]=(info->scalefac_compress[0][ch]%16)>>2;
|
||||||
|
slen[4]=info->scalefac_compress[0][ch]%4;
|
||||||
|
info->preflag[0][ch]=0;
|
||||||
|
index=0;
|
||||||
|
}
|
||||||
|
if (info->scalefac_compress[0][ch] >= 400 && info->scalefac_compress[0][ch] < 500) {
|
||||||
|
slen[1]=((info->scalefac_compress[0][ch]-400)>>2)/5;
|
||||||
|
slen[2]=((info->scalefac_compress[0][ch]-400)>>2)%5;
|
||||||
|
slen[3]=(info->scalefac_compress[0][ch]-400)%4;
|
||||||
|
slen[4]=0;
|
||||||
|
info->preflag[0][ch]=0;
|
||||||
|
index=1;
|
||||||
|
}
|
||||||
|
if (info->scalefac_compress[0][ch] >= 500 && info->scalefac_compress[0][ch] < 512) {
|
||||||
|
slen[1]=(info->scalefac_compress[0][ch]-500)/3;
|
||||||
|
slen[2]=(info->scalefac_compress[0][ch]-500)%3;
|
||||||
|
slen[3]=0;
|
||||||
|
slen[4]=0;
|
||||||
|
info->preflag[0][ch]=1;
|
||||||
|
index=2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info->window_switching_flag[0][ch] && info->block_type[0][ch]==2)
|
||||||
|
if (info->mixed_block_flag[0][ch]) index2=2;
|
||||||
|
else index2=1;
|
||||||
|
else index2=0;
|
||||||
|
|
||||||
|
for (j=1;j<=4;j++) nr_of_sfb[j]=spooky_table[spooky_index][index][index2][j-1];
|
||||||
|
|
||||||
|
/* now we'll do some actual scalefactor extraction, and a little more.
|
||||||
|
* for each scalefactor band we'll set the value of is_max to indicate
|
||||||
|
* illegal is_pos, since with MPEG2 it's not 'hardcoded' to 7.
|
||||||
|
*/
|
||||||
|
if (!info->window_switching_flag[0][ch] || (info->window_switching_flag[0][ch] && info->block_type[0][ch]!=2)) {
|
||||||
|
sfb=0;
|
||||||
|
for (j=1;j<=4;j++)
|
||||||
|
for (k=0;k<nr_of_sfb[j];k++) {
|
||||||
|
scalefac_l[0][ch][sfb]=getbits(slen[j]);
|
||||||
|
i+=slen[j];
|
||||||
|
if (ch) is_max[sfb]=(1<<slen[j])-1;
|
||||||
|
sfb++;
|
||||||
|
}
|
||||||
|
} else if (info->block_type[0][ch]==2)
|
||||||
|
{
|
||||||
|
if (!info->mixed_block_flag[0][ch]) {
|
||||||
|
sfb=0;
|
||||||
|
for (j=1;j<=4;j++)
|
||||||
|
for (k=0;k<nr_of_sfb[j];k+=3) {
|
||||||
|
/* we assume here that nr_of_sfb is divisible by 3. it is.
|
||||||
|
*/
|
||||||
|
scalefac_s[0][ch][sfb][0]=getbits(slen[j]);
|
||||||
|
scalefac_s[0][ch][sfb][1]=getbits(slen[j]);
|
||||||
|
scalefac_s[0][ch][sfb][2]=getbits(slen[j]);
|
||||||
|
i+=3*slen[j];
|
||||||
|
if (ch) is_max[sfb+6]=(1<<slen[j])-1;
|
||||||
|
sfb++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* what we do here is:
|
||||||
|
* 1. assume that for every fs, the two lowest subbands are equal to the
|
||||||
|
* six lowest scalefactor bands for long blocks/MPEG2. they are.
|
||||||
|
* 2. assume that for every fs, the two lowest subbands are equal to the
|
||||||
|
* three lowest scalefactor bands for short blocks. they are.
|
||||||
|
*/
|
||||||
|
sfb=0;
|
||||||
|
for (k=0;k<6;k++) {
|
||||||
|
scalefac_l[0][ch][sfb]=getbits(slen[1]);
|
||||||
|
i+=slen[j];
|
||||||
|
if (ch) is_max[sfb]=(1<<slen[1])-1;
|
||||||
|
sfb++;
|
||||||
|
}
|
||||||
|
nr_of_sfb[1]-=6;
|
||||||
|
sfb=3;
|
||||||
|
for (j=1;j<=4;j++)
|
||||||
|
for (k=0;k<nr_of_sfb[j];k+=3) {
|
||||||
|
scalefac_s[0][ch][sfb][0]=getbits(slen[j]);
|
||||||
|
scalefac_s[0][ch][sfb][1]=getbits(slen[j]);
|
||||||
|
scalefac_s[0][ch][sfb][2]=getbits(slen[j]);
|
||||||
|
i+=3*slen[j];
|
||||||
|
if (ch) is_max[sfb+6]=(1<<slen[j])-1;
|
||||||
|
sfb++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
42
Src/Sound/MPEG/getdata.h
Normal file
42
Src/Sound/MPEG/getdata.h
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
/* this file is a part of amp software, (C) tomislav uzelac 1996,1997
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* getdata.h
|
||||||
|
*
|
||||||
|
* tomislav uzelac Apr 1996
|
||||||
|
*/
|
||||||
|
|
||||||
|
extern int decode_scalefactors(struct SIDE_INFO *info,struct AUDIO_HEADER *header,int gr,int ch);
|
||||||
|
|
||||||
|
extern int is_max[21];
|
||||||
|
extern int intensity_scale;
|
||||||
|
|
||||||
|
#ifdef GETDATA
|
||||||
|
|
||||||
|
static char t_slen1[16]={0,0,0,0,3,1,1,1,2,2,2,3,3,3,4,4};
|
||||||
|
static char t_slen2[16]={0,1,2,3,0,1,2,3,1,2,3,1,2,3,2,3};
|
||||||
|
|
||||||
|
int is_max[21]; /* the maximum value of is_pos. for short blocks is_max[sfb=0] == is_max[6],
|
||||||
|
* it's sloppy but i'm sick of waisting storage. blaah...
|
||||||
|
*/
|
||||||
|
int intensity_scale;
|
||||||
|
|
||||||
|
int decode_scalefactors(struct SIDE_INFO *info,struct AUDIO_HEADER *header,int gr,int ch);
|
||||||
|
|
||||||
|
/* my implementation of MPEG2 scalefactor decoding is, admitably, horrible
|
||||||
|
* anyway, just take a look at pg.18 of MPEG2 specs, and you'll know what
|
||||||
|
* this is all about
|
||||||
|
*/
|
||||||
|
static const char spooky_table[2][3][3][4]={
|
||||||
|
{
|
||||||
|
{ {6,5,5,5}, {9,9,9,9}, {6,9,9,9} },
|
||||||
|
{ {6,5,7,3}, {9,9,12,6}, {6,9,12,6}},
|
||||||
|
{ {11,10,0,0}, {18,18,0,0}, {15,18,0,0}}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{ {7,7,7,0}, {12,12,12,0}, {6,15,12,0}},
|
||||||
|
{ {6,6,6,3}, {12,9,9,6}, {6,12,9,6}},
|
||||||
|
{ {8,8,5,0}, {15,12,9,0}, {6,18,9,0}}
|
||||||
|
}};
|
||||||
|
|
||||||
|
#endif /* GETDATA */
|
209
Src/Sound/MPEG/huffman.cpp
Normal file
209
Src/Sound/MPEG/huffman.cpp
Normal file
|
@ -0,0 +1,209 @@
|
||||||
|
/* this file is a part of amp software, (C) tomislav uzelac 1996,1997
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* huffman.c huffman decoding
|
||||||
|
*
|
||||||
|
* Created by: tomislav uzelac Mar,Apr 1996
|
||||||
|
* Last modified by: tomislav uzelac Mar 8 97
|
||||||
|
*/
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "audio.h"
|
||||||
|
#include "getbits.h"
|
||||||
|
|
||||||
|
#define HUFFMAN
|
||||||
|
#include "huffman.h"
|
||||||
|
|
||||||
|
static inline unsigned int viewbits(int n)
|
||||||
|
{
|
||||||
|
unsigned int pos,ret_value;
|
||||||
|
|
||||||
|
pos = data >> 3;
|
||||||
|
ret_value = buffer[pos] << 24 |
|
||||||
|
buffer[pos+1] << 16 |
|
||||||
|
buffer[pos+2] << 8 |
|
||||||
|
buffer[pos+3];
|
||||||
|
ret_value <<= data & 7;
|
||||||
|
ret_value >>= 32 - n;
|
||||||
|
|
||||||
|
return ret_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void sackbits(int n)
|
||||||
|
{
|
||||||
|
data += n;
|
||||||
|
data &= 8*BUFFER_SIZE-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* huffman_decode() is supposed to be faster now
|
||||||
|
* decodes one codeword and returns no. of bits
|
||||||
|
*/
|
||||||
|
static inline int huffman_decode(int tbl,int *x,int *y)
|
||||||
|
{
|
||||||
|
unsigned int chunk;
|
||||||
|
register unsigned int *h_tab;
|
||||||
|
register unsigned int lag;
|
||||||
|
register unsigned int half_lag;
|
||||||
|
int len;
|
||||||
|
|
||||||
|
h_tab=tables[tbl];
|
||||||
|
chunk=viewbits(19);
|
||||||
|
|
||||||
|
h_tab += h_cue[tbl][chunk >> (19-NC_O)];
|
||||||
|
|
||||||
|
len=(*h_tab>>8)&0x1f;
|
||||||
|
|
||||||
|
/* check for an immediate hit, so we can decode those short codes very fast
|
||||||
|
*/
|
||||||
|
if ((*h_tab>>(32-len)) != (chunk>>(19-len))) {
|
||||||
|
if (chunk >> (19-NC_O) < N_CUE-1)
|
||||||
|
lag=(h_cue[tbl][(chunk >> (19-NC_O))+1] -
|
||||||
|
h_cue[tbl][chunk >> (19-NC_O)]);
|
||||||
|
else {
|
||||||
|
/* we strongly depend on h_cue[N_CUE-1] to point to
|
||||||
|
* the last entry in the huffman table, so we should
|
||||||
|
* not get here anyway. if it didn't, we'd have to
|
||||||
|
* have another table with huffman tables lengths, and
|
||||||
|
* it would be a mess. just in case, scream&shout.
|
||||||
|
*/
|
||||||
|
printf(" h_cue clobbered. this is a bug. blip.\n");
|
||||||
|
exit (-1);
|
||||||
|
}
|
||||||
|
chunk <<= 32-19;
|
||||||
|
chunk |= 0x1ff;
|
||||||
|
|
||||||
|
half_lag = lag >> 1;
|
||||||
|
|
||||||
|
h_tab += half_lag;
|
||||||
|
lag -= half_lag;
|
||||||
|
|
||||||
|
while (lag > 1) {
|
||||||
|
half_lag = lag >> 1;
|
||||||
|
|
||||||
|
if (*h_tab < chunk)
|
||||||
|
h_tab += half_lag;
|
||||||
|
else
|
||||||
|
h_tab -= half_lag;
|
||||||
|
|
||||||
|
lag -= half_lag;
|
||||||
|
}
|
||||||
|
|
||||||
|
len=(*h_tab>>8)&0x1f;
|
||||||
|
if ((*h_tab>>(32-len)) != (chunk>>(32-len))) {
|
||||||
|
if (*h_tab > chunk)
|
||||||
|
h_tab--;
|
||||||
|
else
|
||||||
|
h_tab++;
|
||||||
|
|
||||||
|
len=(*h_tab>>8)&0x1f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sackbits(len);
|
||||||
|
*x=(*h_tab>>4)&0xf;
|
||||||
|
*y=*h_tab&0xf;
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int _qsign(int x,int *q)
|
||||||
|
{
|
||||||
|
int ret_value=0,i;
|
||||||
|
for (i=3;i>=0;i--)
|
||||||
|
if ((x>>i) & 1) {
|
||||||
|
if (getbits(1)) *q++=-1;
|
||||||
|
else *q++=1;
|
||||||
|
ret_value++;
|
||||||
|
}
|
||||||
|
else *q++=0;
|
||||||
|
return ret_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
int decode_huffman_data(struct SIDE_INFO *info,int gr,int ch,int ssize)
|
||||||
|
{
|
||||||
|
int l,i,cnt,x,y;
|
||||||
|
int q[4],r[3],linbits[3],tr[4]={0,0,0,0};
|
||||||
|
int big_value = info->big_values[gr][ch] << 1;
|
||||||
|
|
||||||
|
for (l=0;l<3;l++) {
|
||||||
|
tr[l]=info->table_select[gr][ch][l];
|
||||||
|
linbits[l]=t_linbits[info->table_select[gr][ch][l]];
|
||||||
|
}
|
||||||
|
|
||||||
|
tr[3]=32+info->count1table_select[gr][ch];
|
||||||
|
|
||||||
|
/* we have to be careful here because big_values are not necessarily
|
||||||
|
* aligned with sfb boundaries
|
||||||
|
*/
|
||||||
|
if (!info->window_switching_flag[gr][ch] && info->block_type[gr][ch]==0) {
|
||||||
|
|
||||||
|
/* this code needed some cleanup
|
||||||
|
*/
|
||||||
|
r[0]=t_l[info->region0_count[gr][ch]] + 1;
|
||||||
|
if (r[0] > big_value)
|
||||||
|
r[0]=r[1]=big_value;
|
||||||
|
else {
|
||||||
|
r[1]=t_l[ info->region0_count[gr][ch] + info->region1_count[gr][ch] + 1 ] + 1;
|
||||||
|
if (r[1] > big_value)
|
||||||
|
r[1]=big_value;
|
||||||
|
}
|
||||||
|
r[2]=big_value;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if (info->block_type[gr][ch]==2 && info->mixed_block_flag[gr][ch]==0)
|
||||||
|
r[0]=3*(t_s[2]+1);
|
||||||
|
else
|
||||||
|
r[0]=t_l[7]+1;
|
||||||
|
|
||||||
|
if (r[0] > big_value)
|
||||||
|
r[0]=big_value;
|
||||||
|
|
||||||
|
r[1]=r[2]=big_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
l=0; cnt=0;
|
||||||
|
for (i=0;i<3;i++) {
|
||||||
|
for (;l<r[i];l+=2) {
|
||||||
|
int j = linbits[i];
|
||||||
|
|
||||||
|
cnt+=huffman_decode(tr[i],&x,&y);
|
||||||
|
|
||||||
|
if (x==15 && j>0) {
|
||||||
|
x+=getbits(j);
|
||||||
|
cnt+=j;
|
||||||
|
}
|
||||||
|
if (x) {
|
||||||
|
if (getbits(1)) x=-x;
|
||||||
|
cnt++;
|
||||||
|
}
|
||||||
|
if (y==15 && j>0) {
|
||||||
|
y+=getbits(j);
|
||||||
|
cnt+=j;
|
||||||
|
}
|
||||||
|
if (y) {
|
||||||
|
if (getbits(1)) y=-y;
|
||||||
|
cnt++;
|
||||||
|
}
|
||||||
|
|
||||||
|
is[ch][l]=x;
|
||||||
|
is[ch][l+1]=y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while ((cnt < info->part2_3_length[gr][ch]-ssize) && (l<576)) {
|
||||||
|
cnt+=huffman_decode(tr[3],&x,&y);
|
||||||
|
cnt+=_qsign(x,q);
|
||||||
|
for (i=0;i<4;i++) is[ch][l+i]=q[i]; /* ziher je ziher, is[578]*/
|
||||||
|
l+=4;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* set position to start of the next gr/ch
|
||||||
|
*/
|
||||||
|
if (cnt != info->part2_3_length[gr][ch] - ssize ) {
|
||||||
|
data-=cnt-(info->part2_3_length[gr][ch] - ssize);
|
||||||
|
data&= 8*BUFFER_SIZE - 1;
|
||||||
|
}
|
||||||
|
if (l<576) non_zero[ch]=l;
|
||||||
|
else non_zero[ch]=576;
|
||||||
|
/* zero out everything else
|
||||||
|
*/
|
||||||
|
for (;l<576;l++) is[ch][l]=0;
|
||||||
|
return 1;
|
||||||
|
}
|
259
Src/Sound/MPEG/huffman.h
Normal file
259
Src/Sound/MPEG/huffman.h
Normal file
|
@ -0,0 +1,259 @@
|
||||||
|
/* this file is a part of amp software, (C) tomislav uzelac 1996,1997
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* huffman.h
|
||||||
|
*
|
||||||
|
* Created by: tomislav uzelac Mar 1996
|
||||||
|
* Last edited by: tomislav uzelac Mar 8 97
|
||||||
|
*/
|
||||||
|
|
||||||
|
extern int decode_huffman_data(struct SIDE_INFO *info,int gr,int ch,int ssize);
|
||||||
|
|
||||||
|
extern int non_zero[2];
|
||||||
|
extern int t_linbits[32];
|
||||||
|
|
||||||
|
#ifdef HUFFMAN
|
||||||
|
|
||||||
|
static inline unsigned int viewbits(int n);
|
||||||
|
static inline void sackbits(int n);
|
||||||
|
static inline int huffman_decode(int tbl,int *x,int *y);
|
||||||
|
static inline int _qsign(int x,int *q);
|
||||||
|
int decode_huffman_data(struct SIDE_INFO *info,int gr,int ch,int ssize);
|
||||||
|
|
||||||
|
int non_zero[2]; /* this is 2*bigvalues+4*count1, i guess...*/
|
||||||
|
|
||||||
|
#define N_CUE 16
|
||||||
|
#define NC_O 4
|
||||||
|
|
||||||
|
int t_linbits[32]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,3,4,6,8,10,13,4,5,6,7,8,9,11,13};
|
||||||
|
|
||||||
|
/* these are the huffman tables, rearranged for lookup
|
||||||
|
*/
|
||||||
|
unsigned int h0[1]={0x0};
|
||||||
|
unsigned int h1[4]={0x311, 0x20000301, 0x40000210, 0x80000100};
|
||||||
|
unsigned int h2[9]={0x622, 0x4000602, 0x8000512, 0x10000521, 0x18000520, 0x20000311, 0x40000301, 0x60000310,
|
||||||
|
0x80000100};
|
||||||
|
unsigned int h3[9]={ 0x622, 0x4000602, 0x8000512, 0x10000521, 0x18000520, 0x20000310, 0x40000211, 0x80000201,
|
||||||
|
0xc0000200};
|
||||||
|
unsigned int h5[16]={0x833, 0x1000823, 0x2000732, 0x4000631, 0x8000713, 0xa000703, 0xc000730, 0xe000722,
|
||||||
|
0x10000612, 0x14000621, 0x18000602, 0x1c000620, 0x20000311, 0x40000301, 0x60000310, 0x80000100};
|
||||||
|
unsigned int h6[16]={0x733, 0x2000703, 0x4000623, 0x8000632, 0xc000630, 0x10000513, 0x18000531, 0x20000522,
|
||||||
|
0x28000502, 0x30000412, 0x40000421, 0x50000420, 0x60000301, 0x80000211, 0xc0000310, 0xe0000300};
|
||||||
|
unsigned int h7[36]={ 0xa55, 0x400a45, 0x800a54, 0xc00a53, 0x1000935, 0x1800944, 0x2000925, 0x2800952,
|
||||||
|
0x3000815, 0x4000851, 0x5000905, 0x5800934, 0x6000850, 0x7000943, 0x7800933, 0x8000824,
|
||||||
|
0x9000842, 0xa000714, 0xc000741, 0xe000740, 0x10000804, 0x11000823, 0x12000832, 0x13000803,
|
||||||
|
0x14000713, 0x16000731, 0x18000730, 0x1a000722, 0x1c000612, 0x20000521, 0x28000602, 0x2c000620,
|
||||||
|
0x30000411, 0x40000301, 0x60000310, 0x80000100};
|
||||||
|
unsigned int h8[36]={0xb55, 0x200b54, 0x400a45, 0x800953, 0x1000a35, 0x1400a44, 0x1800925, 0x2000952,
|
||||||
|
0x2800905, 0x3000815, 0x4000851, 0x5000934, 0x5800943, 0x6000950, 0x6800933, 0x7000824,
|
||||||
|
0x8000842, 0x9000814, 0xa000741, 0xc000804, 0xd000840, 0xe000823, 0xf000832, 0x10000813,
|
||||||
|
0x11000831, 0x12000803, 0x13000830, 0x14000622, 0x18000602, 0x1c000620, 0x20000412, 0x30000421,
|
||||||
|
0x40000211, 0x80000301, 0xa0000310, 0xc0000200};
|
||||||
|
unsigned int h9[36]={ 0x955, 0x800945, 0x1000835, 0x2000853, 0x3000954, 0x3800905, 0x4000844, 0x5000825,
|
||||||
|
0x6000852, 0x7000815, 0x8000751, 0xa000734, 0xc000743, 0xe000850, 0xf000804, 0x10000724,
|
||||||
|
0x12000742, 0x14000733, 0x16000740, 0x18000614, 0x1c000641, 0x20000623, 0x24000632, 0x28000513,
|
||||||
|
0x30000531, 0x38000603, 0x3c000630, 0x40000522, 0x48000502, 0x50000412, 0x60000421, 0x70000420,
|
||||||
|
0x80000311, 0xa0000301, 0xc0000310, 0xe0000300};
|
||||||
|
unsigned int h10[64]={ 0xb77, 0x200b67, 0x400b76, 0x600b57, 0x800b75, 0xa00b66, 0xc00a47, 0x1000a74,
|
||||||
|
0x1400a56, 0x1800a65, 0x1c00a37, 0x2000a73, 0x2400a46, 0x2800b55, 0x2a00b54, 0x2c00a63,
|
||||||
|
0x3000927, 0x3800972, 0x4000a64, 0x4400a07, 0x4800970, 0x5000962, 0x5800a45, 0x5c00a35,
|
||||||
|
0x6000906, 0x6800a53, 0x6c00a44, 0x7000817, 0x8000871, 0x9000936, 0x9800926, 0xa000a25,
|
||||||
|
0xa400a52, 0xa800915, 0xb000951, 0xb800a34, 0xbc00a43, 0xc000816, 0xd000861, 0xe000860,
|
||||||
|
0xf000905, 0xf800950, 0x10000924, 0x10800942, 0x11000933, 0x11800904, 0x12000814, 0x13000841,
|
||||||
|
0x14000840, 0x15000823, 0x16000832, 0x17000803, 0x18000713, 0x1a000731, 0x1c000730, 0x1e000722,
|
||||||
|
0x20000612, 0x24000621, 0x28000602, 0x2c000620, 0x30000411, 0x40000301, 0x60000310, 0x80000100};
|
||||||
|
unsigned int h11[64]={ 0xa77, 0x400a67, 0x800a76, 0xc00a75, 0x1000a66, 0x1400a47, 0x1800a74, 0x1c00b57,
|
||||||
|
0x1e00b55, 0x2000a56, 0x2400a65, 0x2800937, 0x3000973, 0x3800946, 0x4000a45, 0x4400a54,
|
||||||
|
0x4800a35, 0x4c00a53, 0x5000827, 0x6000872, 0x7000964, 0x7800907, 0x8000771, 0xa000817,
|
||||||
|
0xb000870, 0xc000836, 0xd000863, 0xe000860, 0xf000944, 0xf800925, 0x10000952, 0x10800905,
|
||||||
|
0x11000815, 0x12000762, 0x14000826, 0x15000806, 0x16000716, 0x18000761, 0x1a000851, 0x1b000834,
|
||||||
|
0x1c000850, 0x1d000943, 0x1d800933, 0x1e000824, 0x1f000842, 0x20000814, 0x21000841, 0x22000804,
|
||||||
|
0x23000840, 0x24000723, 0x26000732, 0x28000613, 0x2c000631, 0x30000703, 0x32000730, 0x34000622,
|
||||||
|
0x38000521, 0x40000412, 0x50000502, 0x58000520, 0x60000311, 0x80000301, 0xa0000310, 0xc0000200};
|
||||||
|
unsigned int h12[64]={ 0xa77, 0x400a67, 0x800976, 0x1000957, 0x1800975, 0x2000966, 0x2800947, 0x3000974,
|
||||||
|
0x3800965, 0x4000856, 0x5000837, 0x6000973, 0x6800955, 0x7000827, 0x8000872, 0x9000846,
|
||||||
|
0xa000864, 0xb000817, 0xc000871, 0xd000907, 0xd800970, 0xe000836, 0xf000863, 0x10000845,
|
||||||
|
0x11000854, 0x12000844, 0x13000906, 0x13800905, 0x14000726, 0x16000762, 0x18000761, 0x1a000816,
|
||||||
|
0x1b000860, 0x1c000835, 0x1d000853, 0x1e000825, 0x1f000852, 0x20000715, 0x22000751, 0x24000734,
|
||||||
|
0x26000743, 0x28000850, 0x29000804, 0x2a000724, 0x2c000742, 0x2e000714, 0x30000633, 0x34000641,
|
||||||
|
0x38000623, 0x3c000632, 0x40000740, 0x42000703, 0x44000630, 0x48000513, 0x50000531, 0x58000522,
|
||||||
|
0x60000412, 0x70000421, 0x80000502, 0x88000520, 0x90000400, 0xa0000311, 0xc0000301, 0xe0000310};
|
||||||
|
unsigned int h13[256]={
|
||||||
|
0x13fe, 0x33fc, 0x52fd, 0x91ed, 0x110ff, 0x210ef, 0x310df, 0x410ee,
|
||||||
|
0x510cf, 0x610de, 0x710bf, 0x810fb, 0x910ce, 0xa10dc, 0xb11af, 0xb91e9,
|
||||||
|
0xc0fec, 0xe0fdd, 0x1010fa, 0x1110cd, 0x120fbe, 0x140feb, 0x160f9f, 0x180ff9,
|
||||||
|
0x1a0fea, 0x1c0fbd, 0x1e0fdb, 0x200f8f, 0x220ff8, 0x240fcc, 0x2610ae, 0x27109e,
|
||||||
|
0x280f8e, 0x2a107f, 0x2b107e, 0x2c0ef7, 0x300eda, 0x340fad, 0x360fbc, 0x380fcb,
|
||||||
|
0x3a0ff6, 0x3c0e6f, 0x400ee8, 0x440e5f, 0x480e9d, 0x4c0ed9, 0x500ef5, 0x540ee7,
|
||||||
|
0x580eac, 0x5c0ebb, 0x600e4f, 0x640ef4, 0x680fca, 0x6a0fe6, 0x6c0ef3, 0x700d3f,
|
||||||
|
0x780e8d, 0x7c0ed8, 0x800d2f, 0x880df2, 0x900e6e, 0x940e9c, 0x980d0f, 0xa00ec9,
|
||||||
|
0xa40e5e, 0xa80dab, 0xb00e7d, 0xb40ed7, 0xb80d4e, 0xc00ec8, 0xc40ed6, 0xc80d3e,
|
||||||
|
0xd00db9, 0xd80e9b, 0xdc0eaa, 0xe00c1f, 0xf00cf1, 0x1000cf0, 0x1100dba, 0x1180de5,
|
||||||
|
0x1200de4, 0x1280d8c, 0x1300d6d, 0x1380de3, 0x1400ce2, 0x1500d2e, 0x1580d0e, 0x1600c1e,
|
||||||
|
0x1700ce1, 0x1800de0, 0x1880d5d, 0x1900dd5, 0x1980d7c, 0x1a00dc7, 0x1a80d4d, 0x1b00d8b,
|
||||||
|
0x1b80db8, 0x1c00dd4, 0x1c80d9a, 0x1d00da9, 0x1d80d6c, 0x1e00cc6, 0x1f00c3d, 0x2000dd3,
|
||||||
|
0x2080d7b, 0x2100c2d, 0x2200cd2, 0x2300c1d, 0x2400cb7, 0x2500d5c, 0x2580dc5, 0x2600d99,
|
||||||
|
0x2680d7a, 0x2700cc3, 0x2800da7, 0x2880d97, 0x2900c4b, 0x2a00bd1, 0x2c00c0d, 0x2d00cd0,
|
||||||
|
0x2e00c8a, 0x2f00ca8, 0x3000c4c, 0x3100cc4, 0x3200c6b, 0x3300cb6, 0x3400b3c, 0x3600b2c,
|
||||||
|
0x3800bc2, 0x3a00b5b, 0x3c00cb5, 0x3d00c89, 0x3e00b1c, 0x4000bc1, 0x4200c98, 0x4300c0c,
|
||||||
|
0x4400bc0, 0x4600cb4, 0x4700c6a, 0x4800ca6, 0x4900c79, 0x4a00b3b, 0x4c00bb3, 0x4e00c88,
|
||||||
|
0x4f00c5a, 0x5000b2b, 0x5200ca5, 0x5300c69, 0x5400ba4, 0x5600c78, 0x5700c87, 0x5800b94,
|
||||||
|
0x5a00c77, 0x5b00c76, 0x5c00ab2, 0x6000a1b, 0x6400ab1, 0x6800b0b, 0x6a00bb0, 0x6c00b96,
|
||||||
|
0x6e00b4a, 0x7000b3a, 0x7200ba3, 0x7400b59, 0x7600b95, 0x7800a2a, 0x7c00aa2, 0x8000a1a,
|
||||||
|
0x8400aa1, 0x8800b0a, 0x8a00b68, 0x8c00aa0, 0x9000b86, 0x9200b49, 0x9400a93, 0x9800b39,
|
||||||
|
0x9a00b58, 0x9c00b85, 0x9e00b67, 0xa000a29, 0xa400a92, 0xa800b57, 0xaa00b75, 0xac00a38,
|
||||||
|
0xb000a83, 0xb400b66, 0xb600b47, 0xb800b74, 0xba00b56, 0xbc00b65, 0xbe00b73, 0xc000919,
|
||||||
|
0xc800991, 0xd000a09, 0xd400a90, 0xd800a48, 0xdc00a84, 0xe000a72, 0xe400b46, 0xe600b64,
|
||||||
|
0xe800928, 0xf000982, 0xf800918, 0x10000a37, 0x10400a27, 0x10800917, 0x11000971, 0x11800a55,
|
||||||
|
0x11c00a07, 0x12000a70, 0x12400a36, 0x12800a63, 0x12c00a45, 0x13000a54, 0x13400a26, 0x13800a62,
|
||||||
|
0x13c00a35, 0x14000881, 0x15000908, 0x15800980, 0x16000916, 0x16800961, 0x17000906, 0x17800960,
|
||||||
|
0x18000a53, 0x18400a44, 0x18800925, 0x19000952, 0x19800905, 0x1a000815, 0x1b000851, 0x1c000934,
|
||||||
|
0x1c800943, 0x1d000950, 0x1d800924, 0x1e000942, 0x1e800933, 0x1f000814, 0x20000741, 0x22000804,
|
||||||
|
0x23000840, 0x24000823, 0x25000832, 0x26000713, 0x28000731, 0x2a000703, 0x2c000730, 0x2e000722,
|
||||||
|
0x30000612, 0x34000621, 0x38000602, 0x3c000620, 0x40000411, 0x50000401, 0x60000310, 0x80000100};
|
||||||
|
unsigned int h15[256]={ 0xdff, 0x80def, 0x100dfe, 0x180ddf, 0x200cee, 0x300dfd, 0x380dcf, 0x400dfc,
|
||||||
|
0x480dde, 0x500ded, 0x580dbf, 0x600cfb, 0x700dce, 0x780dec, 0x800cdd, 0x900caf,
|
||||||
|
0xa00cfa, 0xb00cbe, 0xc00ceb, 0xd00ccd, 0xe00cdc, 0xf00c9f, 0x1000cf9, 0x1100cea,
|
||||||
|
0x1200cbd, 0x1300cdb, 0x1400c8f, 0x1500cf8, 0x1600ccc, 0x1700c9e, 0x1800ce9, 0x1900c7f,
|
||||||
|
0x1a00cf7, 0x1b00cad, 0x1c00cda, 0x1d00cbc, 0x1e00c6f, 0x1f00dae, 0x1f80d0f, 0x2000bcb,
|
||||||
|
0x2200bf6, 0x2400c8e, 0x2500ce8, 0x2600c5f, 0x2700c9d, 0x2800bf5, 0x2a00b7e, 0x2c00be7,
|
||||||
|
0x2e00bac, 0x3000bca, 0x3200bbb, 0x3400cd9, 0x3500c8d, 0x3600b4f, 0x3800bf4, 0x3a00b3f,
|
||||||
|
0x3c00bf3, 0x3e00bd8, 0x4000be6, 0x4200b2f, 0x4400bf2, 0x4600c6e, 0x4700cf0, 0x4800b1f,
|
||||||
|
0x4a00bf1, 0x4c00b9c, 0x4e00bc9, 0x5000b5e, 0x5200bab, 0x5400bba, 0x5600be5, 0x5800b7d,
|
||||||
|
0x5a00bd7, 0x5c00b4e, 0x5e00be4, 0x6000b8c, 0x6200bc8, 0x6400b3e, 0x6600b6d, 0x6800bd6,
|
||||||
|
0x6a00be3, 0x6c00b9b, 0x6e00bb9, 0x7000b2e, 0x7200baa, 0x7400be2, 0x7600b1e, 0x7800be1,
|
||||||
|
0x7a00c0e, 0x7b00ce0, 0x7c00b5d, 0x7e00bd5, 0x8000b7c, 0x8200bc7, 0x8400b4d, 0x8600b8b,
|
||||||
|
0x8800ad4, 0x8c00bb8, 0x8e00b9a, 0x9000ba9, 0x9200b6c, 0x9400bc6, 0x9600b3d, 0x9800ad3,
|
||||||
|
0x9c00ad2, 0xa000b2d, 0xa200b0d, 0xa400a1d, 0xa800a7b, 0xac00ab7, 0xb000ad1, 0xb400b5c,
|
||||||
|
0xb600bd0, 0xb800ac5, 0xbc00a8a, 0xc000aa8, 0xc400a4c, 0xc800ac4, 0xcc00a6b, 0xd000ab6,
|
||||||
|
0xd400b99, 0xd600b0c, 0xd800a3c, 0xdc00ac3, 0xe000a7a, 0xe400aa7, 0xe800aa6, 0xec00bc0,
|
||||||
|
0xee00b0b, 0xf0009c2, 0xf800a2c, 0xfc00a5b, 0x10000ab5, 0x10400a1c, 0x10800a89, 0x10c00a98,
|
||||||
|
0x11000ac1, 0x11400a4b, 0x11800ab4, 0x11c00a6a, 0x12000a3b, 0x12400a79, 0x128009b3, 0x13000a97,
|
||||||
|
0x13400a88, 0x13800a2b, 0x13c00a5a, 0x140009b2, 0x14800aa5, 0x14c00a1b, 0x150009b1, 0x15800ab0,
|
||||||
|
0x15c00a69, 0x16000a96, 0x16400a4a, 0x16800aa4, 0x16c00a78, 0x17000a87, 0x17400a3a, 0x178009a3,
|
||||||
|
0x18000959, 0x18800995, 0x1900092a, 0x198009a2, 0x1a00091a, 0x1a8009a1, 0x1b000a0a, 0x1b400aa0,
|
||||||
|
0x1b800968, 0x1c000986, 0x1c800949, 0x1d000994, 0x1d800939, 0x1e000993, 0x1e800a77, 0x1ec00a09,
|
||||||
|
0x1f000958, 0x1f800985, 0x20000929, 0x20800967, 0x21000976, 0x21800992, 0x22000891, 0x23000919,
|
||||||
|
0x23800990, 0x24000948, 0x24800984, 0x25000957, 0x25800975, 0x26000938, 0x26800983, 0x27000966,
|
||||||
|
0x27800947, 0x28000828, 0x29000882, 0x2a000818, 0x2b000881, 0x2c000974, 0x2c800908, 0x2d000980,
|
||||||
|
0x2d800956, 0x2e000965, 0x2e800937, 0x2f000973, 0x2f800946, 0x30000827, 0x31000872, 0x32000864,
|
||||||
|
0x33000817, 0x34000855, 0x35000871, 0x36000907, 0x36800970, 0x37000836, 0x38000863, 0x39000845,
|
||||||
|
0x3a000854, 0x3b000826, 0x3c000862, 0x3d000816, 0x3e000906, 0x3e800960, 0x3f000835, 0x40000761,
|
||||||
|
0x42000853, 0x43000844, 0x44000725, 0x46000752, 0x48000715, 0x4a000751, 0x4c000805, 0x4d000850,
|
||||||
|
0x4e000734, 0x50000743, 0x52000724, 0x54000742, 0x56000733, 0x58000641, 0x5c000714, 0x5e000704,
|
||||||
|
0x60000623, 0x64000632, 0x68000740, 0x6a000703, 0x6c000613, 0x70000631, 0x74000630, 0x78000522,
|
||||||
|
0x80000512, 0x88000521, 0x90000502, 0x98000520, 0xa0000311, 0xc0000401, 0xd0000410, 0xe0000300};
|
||||||
|
unsigned int h16[256]={ 0xbef, 0x200bfe, 0x400bdf, 0x600bfd, 0x800bcf, 0xa00bfc, 0xc00bbf, 0xe00bfb,
|
||||||
|
0x1000aaf, 0x1400bfa, 0x1600b9f, 0x1800bf9, 0x1a00bf8, 0x1c00a8f, 0x2000a7f, 0x2400af7,
|
||||||
|
0x2800a6f, 0x2c00af6, 0x30008ff, 0x4000a5f, 0x4400af5, 0x480094f, 0x50009f4, 0x58009f3,
|
||||||
|
0x60009f0, 0x6800a3f, 0x6c010ce, 0x6c111ec, 0x6c191dd, 0x6c20fde, 0x6c40fe9, 0x6c610ea,
|
||||||
|
0x6c710d9, 0x6c80eee, 0x6cc0fed, 0x6ce0feb, 0x6d00ebe, 0x6d40ecd, 0x6d80fdc, 0x6da0fdb,
|
||||||
|
0x6dc0eae, 0x6e00ecc, 0x6e40fad, 0x6e60fda, 0x6e80f7e, 0x6ea0fac, 0x6ec0eca, 0x6f00fc9,
|
||||||
|
0x6f20f7d, 0x6f40e5e, 0x6f80dbd, 0x70008f2, 0x800092f, 0x880090f, 0x900081f, 0xa0008f1,
|
||||||
|
0xb000d9e, 0xb080ebc, 0xb0c0ecb, 0xb100e8e, 0xb140ee8, 0xb180e9d, 0xb1c0ee7, 0xb200ebb,
|
||||||
|
0xb240e8d, 0xb280ed8, 0xb2c0e6e, 0xb300de6, 0xb380d9c, 0xb400eab, 0xb440eba, 0xb480ee5,
|
||||||
|
0xb4c0ed7, 0xb500d4e, 0xb580ee4, 0xb5c0e8c, 0xb600dc8, 0xb680d3e, 0xb700d6d, 0xb780ed6,
|
||||||
|
0xb7c0e9b, 0xb800eb9, 0xb840eaa, 0xb880de1, 0xb900dd4, 0xb980eb8, 0xb9c0ea9, 0xba00d7b,
|
||||||
|
0xba80eb7, 0xbac0ed0, 0xbb00ce3, 0xbc00d0e, 0xbc80de0, 0xbd00d5d, 0xbd80dd5, 0xbe00d7c,
|
||||||
|
0xbe80dc7, 0xbf00d4d, 0xbf80d8b, 0xc000d9a, 0xc080d6c, 0xc100dc6, 0xc180d3d, 0xc200d5c,
|
||||||
|
0xc280dc5, 0xc300c0d, 0xc400d8a, 0xc480da8, 0xc500d99, 0xc580d4c, 0xc600db6, 0xc680d7a,
|
||||||
|
0xc700c3c, 0xc800d5b, 0xc880d89, 0xc900c1c, 0xca00cc0, 0xcb00d98, 0xcb80d79, 0xcc00be2,
|
||||||
|
0xce00c2e, 0xcf00c1e, 0xd000cd3, 0xd100c2d, 0xd200cd2, 0xd300cd1, 0xd400c3b, 0xd500d97,
|
||||||
|
0xd580d88, 0xd600b1d, 0xd800cc4, 0xd900c6b, 0xda00cc3, 0xdb00ca7, 0xdc00b2c, 0xde00cc2,
|
||||||
|
0xdf00cb5, 0xe000cc1, 0xe100c0c, 0xe200c4b, 0xe300cb4, 0xe400c6a, 0xe500ca6, 0xe600bb3,
|
||||||
|
0xe800c5a, 0xe900ca5, 0xea00b2b, 0xec00bb2, 0xee00b1b, 0xf000bb1, 0xf200c0b, 0xf300cb0,
|
||||||
|
0xf400c69, 0xf500c96, 0xf600c4a, 0xf700ca4, 0xf800c78, 0xf900c87, 0xfa00ba3, 0xfc00c3a,
|
||||||
|
0xfd00c59, 0xfe00b2a, 0x10000c95, 0x10100c68, 0x10200ba1, 0x10400c86, 0x10500c77, 0x10600b94,
|
||||||
|
0x10800c49, 0x10900c57, 0x10a00b67, 0x10c00aa2, 0x11000a1a, 0x11400b0a, 0x11600ba0, 0x11800b39,
|
||||||
|
0x11a00b93, 0x11c00b58, 0x11e00b85, 0x12000a29, 0x12400a92, 0x12800b76, 0x12a00b09, 0x12c00a19,
|
||||||
|
0x13000a91, 0x13400b90, 0x13600b48, 0x13800b84, 0x13a00b75, 0x13c00b38, 0x13e00b83, 0x14000b66,
|
||||||
|
0x14200b28, 0x14400a82, 0x14800b47, 0x14a00b74, 0x14c00a18, 0x15000a81, 0x15400a80, 0x15800b08,
|
||||||
|
0x15a00b56, 0x15c00a37, 0x16000a73, 0x16400b65, 0x16600b46, 0x16800a27, 0x16c00a72, 0x17000b64,
|
||||||
|
0x17200b55, 0x17400a07, 0x17800917, 0x18000971, 0x18800a70, 0x18c00a36, 0x19000a63, 0x19400a45,
|
||||||
|
0x19800a54, 0x19c00a26, 0x1a000962, 0x1a800916, 0x1b000961, 0x1b800a06, 0x1bc00a60, 0x1c000953,
|
||||||
|
0x1c800a35, 0x1cc00a44, 0x1d000925, 0x1d800952, 0x1e000851, 0x1f000915, 0x1f800905, 0x20000934,
|
||||||
|
0x20800943, 0x21000950, 0x21800924, 0x22000942, 0x22800933, 0x23000814, 0x24000841, 0x25000904,
|
||||||
|
0x25800940, 0x26000823, 0x27000832, 0x28000713, 0x2a000731, 0x2c000803, 0x2d000830, 0x2e000722,
|
||||||
|
0x30000612, 0x34000621, 0x38000602, 0x3c000620, 0x40000411, 0x50000401, 0x60000310, 0x80000100};
|
||||||
|
unsigned int h24[256]={ 0x8ef, 0x10008fe, 0x20008df, 0x30008fd, 0x40008cf, 0x50008fc, 0x60008bf, 0x70008fb,
|
||||||
|
0x80007fa, 0xa0008af, 0xb00089f, 0xc0007f9, 0xe0007f8, 0x1000088f, 0x1100087f, 0x120007f7,
|
||||||
|
0x1400076f, 0x160007f6, 0x1800075f, 0x1a0007f5, 0x1c00074f, 0x1e0007f4, 0x2000073f, 0x220007f3,
|
||||||
|
0x2400072f, 0x260007f2, 0x280007f1, 0x2a00081f, 0x2b0008f0, 0x2c00090f, 0x2c800bee, 0x2ca00bde,
|
||||||
|
0x2cc00bed, 0x2ce00bce, 0x2d000bec, 0x2d200bdd, 0x2d400bbe, 0x2d600beb, 0x2d800bcd, 0x2da00bdc,
|
||||||
|
0x2dc00bae, 0x2de00bea, 0x2e000bbd, 0x2e200bdb, 0x2e400bcc, 0x2e600b9e, 0x2e800be9, 0x2ea00bad,
|
||||||
|
0x2ec00bda, 0x2ee00bbc, 0x2f000bcb, 0x2f200b8e, 0x2f400be8, 0x2f600b9d, 0x2f800bd9, 0x2fa00b7e,
|
||||||
|
0x2fc00be7, 0x2fe00bac, 0x300004ff, 0x40000bca, 0x40200bbb, 0x40400b8d, 0x40600bd8, 0x40800c0e,
|
||||||
|
0x40900ce0, 0x40a00b0d, 0x40c00ae6, 0x41000b6e, 0x41200b9c, 0x41400ac9, 0x41800a5e, 0x41c00aba,
|
||||||
|
0x42000ae5, 0x42400bab, 0x42600b7d, 0x42800ad7, 0x42c00ae4, 0x43000a8c, 0x43400ac8, 0x43800b4e,
|
||||||
|
0x43a00b2e, 0x43c00a3e, 0x44000a6d, 0x44400ad6, 0x44800ae3, 0x44c00a9b, 0x45000ab9, 0x45400aaa,
|
||||||
|
0x45800ae2, 0x45c00a1e, 0x46000ae1, 0x46400a5d, 0x46800ad5, 0x46c00a7c, 0x47000ac7, 0x47400a4d,
|
||||||
|
0x47800a8b, 0x47c00ab8, 0x48000ad4, 0x48400a9a, 0x48800aa9, 0x48c00a6c, 0x49000ac6, 0x49400a3d,
|
||||||
|
0x49800ad3, 0x49c00a2d, 0x4a000ad2, 0x4a400a1d, 0x4a800a7b, 0x4ac00ab7, 0x4b000ad1, 0x4b400a5c,
|
||||||
|
0x4b800ac5, 0x4bc00a8a, 0x4c000aa8, 0x4c400a99, 0x4c800a4c, 0x4cc00ac4, 0x4d000a6b, 0x4d400ab6,
|
||||||
|
0x4d800bd0, 0x4da00b0c, 0x4dc00a3c, 0x4e000ac3, 0x4e400a7a, 0x4e800aa7, 0x4ec00a2c, 0x4f000ac2,
|
||||||
|
0x4f400a5b, 0x4f800ab5, 0x4fc00a1c, 0x50000a89, 0x50400a98, 0x50800ac1, 0x50c00a4b, 0x51000bc0,
|
||||||
|
0x51200b0b, 0x51400a3b, 0x51800bb0, 0x51a00b0a, 0x51c00a1a, 0x520009b4, 0x52800a6a, 0x52c00aa6,
|
||||||
|
0x53000a79, 0x53400a97, 0x53800ba0, 0x53a00b09, 0x53c00a90, 0x540009b3, 0x54800988, 0x55000a2b,
|
||||||
|
0x55400a5a, 0x558009b2, 0x56000aa5, 0x56400a1b, 0x56800ab1, 0x56c00a69, 0x57000996, 0x578009a4,
|
||||||
|
0x58000a4a, 0x58400a78, 0x58800987, 0x5900093a, 0x598009a3, 0x5a000959, 0x5a800995, 0x5b00092a,
|
||||||
|
0x5b8009a2, 0x5c0009a1, 0x5c800968, 0x5d000986, 0x5d800977, 0x5e000949, 0x5e800994, 0x5f000939,
|
||||||
|
0x5f800993, 0x60000958, 0x60800985, 0x61000929, 0x61800967, 0x62000976, 0x62800992, 0x63000919,
|
||||||
|
0x63800991, 0x64000948, 0x64800984, 0x65000957, 0x65800975, 0x66000938, 0x66800983, 0x67000966,
|
||||||
|
0x67800928, 0x68000982, 0x68800918, 0x69000947, 0x69800974, 0x6a000981, 0x6a800a08, 0x6ac00a80,
|
||||||
|
0x6b000956, 0x6b800965, 0x6c000917, 0x6c800a07, 0x6cc00a70, 0x6d000873, 0x6e000937, 0x6e800927,
|
||||||
|
0x6f000872, 0x70000846, 0x71000864, 0x72000855, 0x73000871, 0x74000836, 0x75000863, 0x76000845,
|
||||||
|
0x77000854, 0x78000826, 0x79000862, 0x7a000816, 0x7b000861, 0x7c000906, 0x7c800960, 0x7d000835,
|
||||||
|
0x7e000853, 0x7f000844, 0x80000825, 0x81000852, 0x82000815, 0x83000905, 0x83800950, 0x84000751,
|
||||||
|
0x86000834, 0x87000843, 0x88000724, 0x8a000742, 0x8c000733, 0x8e000714, 0x90000741, 0x92000804,
|
||||||
|
0x93000840, 0x94000723, 0x96000732, 0x98000613, 0x9c000631, 0xa0000703, 0xa2000730, 0xa4000622,
|
||||||
|
0xa8000512, 0xb0000521, 0xb8000602, 0xbc000620, 0xc0000411, 0xd0000401, 0xe0000410, 0xf0000400};
|
||||||
|
unsigned int hA[16]={ 0x6b0, 0x40006f0, 0x80006d0, 0xc0006e0, 0x10000670, 0x14000650, 0x18000590, 0x20000560,
|
||||||
|
0x28000530, 0x300005a0, 0x380005c0, 0x40000420, 0x50000410, 0x60000440, 0x70000480, 0x80000100};
|
||||||
|
unsigned int hB[16]={ 0x4f0, 0x100004e0, 0x200004d0, 0x300004c0, 0x400004b0, 0x500004a0, 0x60000490, 0x70000480,
|
||||||
|
0x80000470, 0x90000460, 0xa0000450, 0xb0000440, 0xc0000430, 0xd0000420, 0xe0000410, 0xf0000400};
|
||||||
|
|
||||||
|
/* now the cues, remember to change these tables if you change N_CUE
|
||||||
|
*/
|
||||||
|
unsigned char h_cue[34][N_CUE]={
|
||||||
|
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
|
||||||
|
{0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3},
|
||||||
|
{0,3,5,5,6,6,7,7,8,8,8,8,8,8,8,8},
|
||||||
|
{0,3,5,5,6,6,6,6,7,7,7,7,8,8,8,8},
|
||||||
|
{0,8,12,12,13,13,14,14,15,15,15,15,15,15,15,15},
|
||||||
|
{0,8,12,12,13,13,14,14,15,15,15,15,15,15,15,15},
|
||||||
|
{0,5,7,9,10,11,12,12,13,13,13,13,14,14,15,15},
|
||||||
|
{0,20,29,32,33,33,34,34,35,35,35,35,35,35,35,35},
|
||||||
|
{0,23,30,31,32,32,32,32,33,33,34,34,35,35,35,35},
|
||||||
|
{0,15,21,24,27,29,30,31,32,32,33,33,34,34,35,35},
|
||||||
|
{0,42,56,60,61,61,62,62,63,63,63,63,63,63,63,63},
|
||||||
|
{0,30,45,53,57,58,60,60,61,61,62,62,63,63,63,63},
|
||||||
|
{0,23,37,46,50,54,56,57,58,60,61,61,62,62,63,63},
|
||||||
|
{0,203,238,248,252,253,254,254,255,255,255,255,255,255,255,255},
|
||||||
|
{0,132,178,205,223,233,240,245,248,250,252,252,253,254,255,255},
|
||||||
|
{0,132,178,205,223,233,240,245,248,250,252,252,253,254,255,255},
|
||||||
|
{0,162,231,248,252,253,254,254,255,255,255,255,255,255,255,255},
|
||||||
|
{0,162,231,248,252,253,254,254,255,255,255,255,255,255,255,255},
|
||||||
|
{0,162,231,248,252,253,254,254,255,255,255,255,255,255,255,255},
|
||||||
|
{0,162,231,248,252,253,254,254,255,255,255,255,255,255,255,255},
|
||||||
|
{0,162,231,248,252,253,254,254,255,255,255,255,255,255,255,255},
|
||||||
|
{0,162,231,248,252,253,254,254,255,255,255,255,255,255,255,255},
|
||||||
|
{0,162,231,248,252,253,254,254,255,255,255,255,255,255,255,255},
|
||||||
|
{0,162,231,248,252,253,254,254,255,255,255,255,255,255,255,255},
|
||||||
|
{0,13,22,58,59,131,177,209,226,238,245,249,252,253,254,255},
|
||||||
|
{0,13,22,58,59,131,177,209,226,238,245,249,252,253,254,255},
|
||||||
|
{0,13,22,58,59,131,177,209,226,238,245,249,252,253,254,255},
|
||||||
|
{0,13,22,58,59,131,177,209,226,238,245,249,252,253,254,255},
|
||||||
|
{0,13,22,58,59,131,177,209,226,238,245,249,252,253,254,255},
|
||||||
|
{0,13,22,58,59,131,177,209,226,238,245,249,252,253,254,255},
|
||||||
|
{0,13,22,58,59,131,177,209,226,238,245,249,252,253,254,255},
|
||||||
|
{0,13,22,58,59,131,177,209,226,238,245,249,252,253,254,255},
|
||||||
|
{0,4,7,9,11,12,13,14,15,15,15,15,15,15,15,15},
|
||||||
|
{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}
|
||||||
|
};
|
||||||
|
|
||||||
|
/* h4->h5, h14->h15 as suggested by Fraunhofer
|
||||||
|
* tomislav Aug 21 1997
|
||||||
|
*/
|
||||||
|
unsigned int *tables[34]={h0,h1,h2,h3,h5,h5,h6,h7,h8,h9,h10,h11,h12,h13,h15,h15,
|
||||||
|
h16,h16,h16,h16,h16,h16,h16,h16,h24,h24,h24,h24,h24,h24,h24,h24,hA,hB};
|
||||||
|
#endif /* HUFFMAN */
|
324
Src/Sound/MPEG/layer2.cpp
Normal file
324
Src/Sound/MPEG/layer2.cpp
Normal file
|
@ -0,0 +1,324 @@
|
||||||
|
/* this file is a part of amp software, (C) tomislav uzelac 1996,1997
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* layer2.c MPEG audio layer2 support
|
||||||
|
*
|
||||||
|
* Created by: Tomislav Uzelac Mar 1996
|
||||||
|
* merged with amp, May 19 1997
|
||||||
|
*/
|
||||||
|
#include "amp.h"
|
||||||
|
#include "audio.h"
|
||||||
|
#include "getbits.h"
|
||||||
|
#include "transform.h"
|
||||||
|
|
||||||
|
#define LAYER2
|
||||||
|
#include "layer2.h"
|
||||||
|
|
||||||
|
int layer2_frame(struct AUDIO_HEADER *header,int cnt)
|
||||||
|
{
|
||||||
|
int i,s,sb,ch,gr,bitrate,bound=0;
|
||||||
|
char (*nbal)[],(*bit_alloc_index)[][16];
|
||||||
|
unsigned char allocation[2][32];
|
||||||
|
unsigned char scfsi[2][32];
|
||||||
|
float scalefactor[2][32][3];
|
||||||
|
float subband_sample[2][32][36];
|
||||||
|
int sblimit,nlevels,grouping;
|
||||||
|
|
||||||
|
float c,d;
|
||||||
|
int no_of_bits,mpi;
|
||||||
|
unsigned short sb_sample_buf[3];
|
||||||
|
|
||||||
|
int hsize,fs,mean_frame_size;
|
||||||
|
|
||||||
|
bit_alloc_index=(char (*)[][16])&t_alloc0;
|
||||||
|
nbal=(char (*)[])&t_nbal0; // shut up compiler
|
||||||
|
sblimit = 0;
|
||||||
|
|
||||||
|
hsize=4;
|
||||||
|
if (header->protection_bit==0) hsize+=2;
|
||||||
|
|
||||||
|
bitrate=t_bitrate[header->ID][3-header->layer][header->bitrate_index];
|
||||||
|
fs=t_sampling_frequency[header->ID][header->sampling_frequency];
|
||||||
|
if (header->ID) mean_frame_size=144000*bitrate/fs;
|
||||||
|
else mean_frame_size=72000*bitrate/fs;
|
||||||
|
|
||||||
|
/* layers 1 and 2 do not have a 'bit reservoir'
|
||||||
|
*/
|
||||||
|
append=data=0;
|
||||||
|
|
||||||
|
fillbfr(mean_frame_size + header->padding_bit - hsize);
|
||||||
|
|
||||||
|
switch (header->mode)
|
||||||
|
{
|
||||||
|
case 0 :
|
||||||
|
case 2 : nch=2; bound=32; bitrate=bitrate/2;
|
||||||
|
break;
|
||||||
|
case 3 : nch=1; bound=32;
|
||||||
|
break;
|
||||||
|
case 1 : nch=2; bitrate=bitrate/2; bound=(header->mode_extension+1)*4;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (header->ID==1) switch (header->sampling_frequency) {
|
||||||
|
case 0 : switch (bitrate) /* 0 = 44.1 kHz */
|
||||||
|
{
|
||||||
|
case 56 :
|
||||||
|
case 64 :
|
||||||
|
case 80 : bit_alloc_index=(char (*)[][16])&t_alloc0;
|
||||||
|
nbal=(char (*)[])&t_nbal0;
|
||||||
|
sblimit=27;
|
||||||
|
break;
|
||||||
|
case 96 :
|
||||||
|
case 112 :
|
||||||
|
case 128 :
|
||||||
|
case 160 :
|
||||||
|
case 192 : bit_alloc_index=(char (*)[][16])&t_alloc1;
|
||||||
|
nbal=(char (*)[])&t_nbal1;
|
||||||
|
sblimit=30;
|
||||||
|
break;
|
||||||
|
case 32 :
|
||||||
|
case 48 : bit_alloc_index=(char (*)[][16])&t_alloc2;
|
||||||
|
nbal=(char (*)[])&t_nbal2;
|
||||||
|
sblimit=8;
|
||||||
|
break;
|
||||||
|
default : printf(" bit alloc info no gud ");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 1 : switch (bitrate) /* 1 = 48 kHz */
|
||||||
|
{
|
||||||
|
case 56 :
|
||||||
|
case 64 :
|
||||||
|
case 80 :
|
||||||
|
case 96 :
|
||||||
|
case 112 :
|
||||||
|
case 128 :
|
||||||
|
case 160 :
|
||||||
|
case 192 : bit_alloc_index=(char (*)[][16])&t_alloc0;
|
||||||
|
nbal=(char (*)[])&t_nbal0;
|
||||||
|
sblimit=27;
|
||||||
|
break;
|
||||||
|
case 32 :
|
||||||
|
case 48 : bit_alloc_index=(char (*)[][16])&t_alloc2;
|
||||||
|
nbal=(char (*)[])&t_nbal2;
|
||||||
|
sblimit=8;
|
||||||
|
break;
|
||||||
|
default : printf(" bit alloc info no gud ");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 2 : switch (bitrate) /* 2 = 32 kHz */
|
||||||
|
{
|
||||||
|
case 56 :
|
||||||
|
case 64 :
|
||||||
|
case 80 : bit_alloc_index=(char (*)[][16])&t_alloc0;
|
||||||
|
nbal=(char (*)[])&t_nbal0;
|
||||||
|
sblimit=27;
|
||||||
|
break;
|
||||||
|
case 96 :
|
||||||
|
case 112 :
|
||||||
|
case 128 :
|
||||||
|
case 160 :
|
||||||
|
case 192 : bit_alloc_index=(char (*)[][16])&t_alloc1;
|
||||||
|
nbal=(char (*)[])&t_nbal1;
|
||||||
|
sblimit=30;
|
||||||
|
break;
|
||||||
|
case 32 :
|
||||||
|
case 48 : bit_alloc_index=(char (*)[][16])&t_alloc3;
|
||||||
|
nbal=(char (*)[])&t_nbal3;
|
||||||
|
sblimit=12;
|
||||||
|
break;
|
||||||
|
default : printf("bit alloc info not ok\n");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default : printf("sampling freq. not ok/n");
|
||||||
|
} else {
|
||||||
|
bit_alloc_index=(char (*)[][16])&t_allocMPG2;
|
||||||
|
nbal=(char (*)[])&t_nbalMPG2;
|
||||||
|
sblimit=30;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* bit allocation per subband per channel decoding *****************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (bound==32) bound=sblimit; /* bound=32 means there is no intensity stereo */
|
||||||
|
|
||||||
|
for (sb=0;sb<bound;sb++)
|
||||||
|
for (ch=0;ch<nch;ch++)
|
||||||
|
allocation[ch][sb]=getbits((*nbal)[sb]);
|
||||||
|
|
||||||
|
for (sb=bound;sb<sblimit;sb++)
|
||||||
|
allocation[1][sb] = allocation[0][sb] = getbits((*nbal)[sb]);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* scfsi ***********************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
for (sb=0;sb<sblimit;sb++)
|
||||||
|
for (ch=0;ch<nch;ch++)
|
||||||
|
if (allocation[ch][sb]!=0) scfsi[ch][sb]=getbits(2);
|
||||||
|
else scfsi[ch][sb]=0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* scalefactors ****************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
for (sb=0;sb<sblimit;sb++)
|
||||||
|
for (ch=0;ch<nch;ch++)
|
||||||
|
if (allocation[ch][sb]!=0) {
|
||||||
|
scalefactor[ch][sb][0]=(float)t_scalefactor[getbits(6)];
|
||||||
|
switch (scfsi[ch][sb])
|
||||||
|
{
|
||||||
|
case 0: scalefactor[ch][sb][1]=(float)t_scalefactor[getbits(6)];
|
||||||
|
scalefactor[ch][sb][2]=(float)t_scalefactor[getbits(6)];
|
||||||
|
break;
|
||||||
|
case 1: scalefactor[ch][sb][2]=(float)t_scalefactor[getbits(6)];
|
||||||
|
scalefactor[ch][sb][1]=scalefactor[ch][sb][0];
|
||||||
|
break;
|
||||||
|
case 2: scalefactor[ch][sb][1]=(float)scalefactor[ch][sb][0];
|
||||||
|
scalefactor[ch][sb][2]=scalefactor[ch][sb][0];
|
||||||
|
break;
|
||||||
|
case 3: scalefactor[ch][sb][2]=(float)t_scalefactor[getbits(6)];
|
||||||
|
scalefactor[ch][sb][1]=scalefactor[ch][sb][2];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else scalefactor[ch][sb][0]=scalefactor[ch][sb][1]=\
|
||||||
|
scalefactor[ch][sb][2]=0.0;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* samples *********************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
for (gr=0;gr<12;gr++) {
|
||||||
|
/*
|
||||||
|
* normal ********************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
for (sb=0;sb<bound;sb++)
|
||||||
|
for (ch=0;ch<nch;ch++)
|
||||||
|
if (allocation[ch][sb]!=0) {
|
||||||
|
mpi=(*bit_alloc_index)[sb][allocation[ch][sb]];
|
||||||
|
no_of_bits=t_bpc[mpi];
|
||||||
|
c=(float)t_c[mpi];
|
||||||
|
d=(float)t_d[mpi];
|
||||||
|
grouping=t_grouping[mpi];
|
||||||
|
nlevels=t_nlevels[mpi];
|
||||||
|
|
||||||
|
if (grouping) {
|
||||||
|
int samplecode=getbits(no_of_bits);
|
||||||
|
convert_samplecode(samplecode,grouping,sb_sample_buf);
|
||||||
|
|
||||||
|
for (s=0;s<3;s++)
|
||||||
|
subband_sample[ch][sb][3*gr+s]=requantize_sample (sb_sample_buf[s],nlevels,c,d,scalefactor[ch][sb][gr/4]);
|
||||||
|
} else {
|
||||||
|
for (s=0;s<3;s++) sb_sample_buf[s]=getbits(no_of_bits);
|
||||||
|
|
||||||
|
for (s=0;s<3;s++) {
|
||||||
|
/*subband_sample[ch][sb][3*gr+s]=requantize_sample (sb_sample_buf[s],nlevels,c,d,scalefactor[ch][sb][gr/4]);*/
|
||||||
|
subband_sample[ch][sb][3*gr+s]=(t_dd[mpi]+sb_sample_buf[s]*t_nli[mpi])*c*scalefactor[ch][sb][gr>>2];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
for (s=0;s<3;s++) subband_sample[ch][sb][3*gr+s]=0;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* joint stereo ********************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
for (sb=bound;sb<sblimit;sb++)
|
||||||
|
if (allocation[0][sb]!=0) {
|
||||||
|
/*ispravka!
|
||||||
|
*/
|
||||||
|
mpi=(*bit_alloc_index)[sb][allocation[0][sb]];
|
||||||
|
no_of_bits=t_bpc[mpi];
|
||||||
|
c=(float)t_c[mpi];
|
||||||
|
d=(float)t_d[mpi];
|
||||||
|
grouping=t_grouping[mpi];
|
||||||
|
nlevels=t_nlevels[mpi];
|
||||||
|
|
||||||
|
if (grouping) {
|
||||||
|
int samplecode=getbits(no_of_bits);
|
||||||
|
convert_samplecode(samplecode,grouping,sb_sample_buf);
|
||||||
|
|
||||||
|
for (s=0;s<3;s++) {
|
||||||
|
subband_sample[0][sb][3*gr+s]=requantize_sample (sb_sample_buf[s],nlevels,c,d,scalefactor[0][sb][gr/4]);
|
||||||
|
subband_sample[1][sb][3*gr+s]=subband_sample[0][sb][3*gr+s];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (s=0;s<3;s++) sb_sample_buf[s]=getbits(no_of_bits);
|
||||||
|
|
||||||
|
for (s=0;s<3;s++) {
|
||||||
|
subband_sample[0][sb][3*gr+s]=subband_sample[1][sb][3*gr+s]=\
|
||||||
|
(t_dd[mpi]+sb_sample_buf[s]*t_nli[mpi])*c*scalefactor[0][sb][gr>>2];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else for (s=0;s<3;s++) {
|
||||||
|
subband_sample[0][sb][3*gr+s]=0;
|
||||||
|
subband_sample[1][sb][3*gr+s]=0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* the rest *******************************************
|
||||||
|
*/
|
||||||
|
for (sb=sblimit;sb<32;sb++)
|
||||||
|
for (ch=0;ch<nch;ch++)
|
||||||
|
|
||||||
|
for (s=0;s<3;s++) subband_sample[ch][sb][3*gr+s]=0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* this is, in fact, horrible, but I had to adjust it to amp/mp3. The hack to make downmixing
|
||||||
|
* work is as ugly as possible.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (A_DOWNMIX && header->mode!=3) {
|
||||||
|
for (ch=0;ch<nch;ch++)
|
||||||
|
for (sb=0;sb<32;sb++)
|
||||||
|
for (i=0;i<36;i++)
|
||||||
|
subband_sample[0][sb][i]=(subband_sample[0][sb][i]+subband_sample[1][sb][i])*0.5f;
|
||||||
|
nch=1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (ch=0;ch<nch;ch++) {
|
||||||
|
for (sb=0;sb<32;sb++)
|
||||||
|
for (i=0;i<18;i++) res[sb][i]=subband_sample[ch][sb][i];
|
||||||
|
for (i=0;i<18;i++)
|
||||||
|
poly(ch,i);
|
||||||
|
}
|
||||||
|
printout();
|
||||||
|
for (ch=0;ch<nch;ch++) {
|
||||||
|
for (sb=0;sb<32;sb++)
|
||||||
|
for (i=0;i<18;i++) res[sb][i]=subband_sample[ch][sb][i+18];
|
||||||
|
for (i=0;i<18;i++)
|
||||||
|
poly(ch,i);
|
||||||
|
}
|
||||||
|
printout();
|
||||||
|
|
||||||
|
if (A_DOWNMIX && header->mode!=3) nch=2;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/****************************************************************************/
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
void convert_samplecode(unsigned int samplecode,unsigned int nlevels,unsigned short* sb_sample_buf)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i=0;i<3;i++) {
|
||||||
|
*sb_sample_buf=samplecode%nlevels;
|
||||||
|
samplecode=samplecode/nlevels;
|
||||||
|
sb_sample_buf++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float requantize_sample(unsigned short s4,unsigned short nlevels,float c,float d,float factor)
|
||||||
|
{
|
||||||
|
register float s,s2,s3;
|
||||||
|
s3=(float) (-1.0+s4*2.0/(nlevels+1));
|
||||||
|
s2=c*(s3+d);
|
||||||
|
s=factor*s2;
|
||||||
|
return s;
|
||||||
|
}
|
190
Src/Sound/MPEG/layer2.h
Normal file
190
Src/Sound/MPEG/layer2.h
Normal file
|
@ -0,0 +1,190 @@
|
||||||
|
/* this file is a part of amp software, (C) tomislav uzelac 1996,1997
|
||||||
|
*/
|
||||||
|
/* layer2.h
|
||||||
|
* Tomislav Uzelac - cca. Feb 1996
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
extern int layer2_frame(struct AUDIO_HEADER *header,int cnt);
|
||||||
|
|
||||||
|
#ifdef LAYER2
|
||||||
|
|
||||||
|
int layer2_frame(struct AUDIO_HEADER *header,int cnt);
|
||||||
|
float requantize_sample(unsigned short s4,unsigned short nlevels,float c,float d,float factor);
|
||||||
|
void convert_samplecode(unsigned int samplecode,unsigned int nlevels,unsigned short* sb_sample_buf);
|
||||||
|
|
||||||
|
char t_nbal0[27]={4,4,4,4,4,4,4,4,4,4,4,3,3,3,3,3,3,3,3,3,3,3,3,2,2,2,2};
|
||||||
|
char t_nbal1[30]={4,4,4,4,4,4,4,4,4,4,4,3,3,3,3,3,3,3,3,3,3,3,3,2,2,2,2,2,2,2};
|
||||||
|
char t_nbal2[8] ={4,4,3,3,3,3,3,3};
|
||||||
|
char t_nbal3[12]={4,4,3,3,3,3,3,3,3,3,3,3};
|
||||||
|
char t_nbalMPG2[30]={4,4,4,4,3,3,3,3,3,3,3,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2};
|
||||||
|
|
||||||
|
char t_alloc0[27][16] = { /* table B.2a ISO/IEC 11172-3 */
|
||||||
|
{0,1,3,5,6,7,8,9,10,11,12,13,14,15,16,17},
|
||||||
|
{0,1,3,5,6,7,8,9,10,11,12,13,14,15,16,17},
|
||||||
|
{0,1,3,5,6,7,8,9,10,11,12,13,14,15,16,17},
|
||||||
|
{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,17},
|
||||||
|
{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,17},
|
||||||
|
{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,17},
|
||||||
|
{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,17},
|
||||||
|
{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,17},
|
||||||
|
{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,17},
|
||||||
|
{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,17},
|
||||||
|
{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,17},
|
||||||
|
{0,1,2,3,4,5,6,17},
|
||||||
|
{0,1,2,3,4,5,6,17},
|
||||||
|
{0,1,2,3,4,5,6,17},
|
||||||
|
{0,1,2,3,4,5,6,17},
|
||||||
|
{0,1,2,3,4,5,6,17},
|
||||||
|
{0,1,2,3,4,5,6,17},
|
||||||
|
{0,1,2,3,4,5,6,17},
|
||||||
|
{0,1,2,3,4,5,6,17},
|
||||||
|
{0,1,2,3,4,5,6,17},
|
||||||
|
{0,1,2,3,4,5,6,17},
|
||||||
|
{0,1,2,3,4,5,6,17},
|
||||||
|
{0,1,2,3,4,5,6,17},
|
||||||
|
{0,1,2,17},
|
||||||
|
{0,1,2,17},
|
||||||
|
{0,1,2,17},
|
||||||
|
{0,1,2,17}};
|
||||||
|
|
||||||
|
char t_alloc1[30][16] = { /* table B.2b ISO/IEC 11172-3 */
|
||||||
|
{0,1,3,5,6,7,8,9,10,11,12,13,14,15,16,17},
|
||||||
|
{0,1,3,5,6,7,8,9,10,11,12,13,14,15,16,17},
|
||||||
|
{0,1,3,5,6,7,8,9,10,11,12,13,14,15,16,17},
|
||||||
|
{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,17},
|
||||||
|
{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,17},
|
||||||
|
{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,17},
|
||||||
|
{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,17},
|
||||||
|
{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,17},
|
||||||
|
{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,17},
|
||||||
|
{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,17},
|
||||||
|
{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,17},
|
||||||
|
{0,1,2,3,4,5,6,17},
|
||||||
|
{0,1,2,3,4,5,6,17},
|
||||||
|
{0,1,2,3,4,5,6,17},
|
||||||
|
{0,1,2,3,4,5,6,17},
|
||||||
|
{0,1,2,3,4,5,6,17},
|
||||||
|
{0,1,2,3,4,5,6,17},
|
||||||
|
{0,1,2,3,4,5,6,17},
|
||||||
|
{0,1,2,3,4,5,6,17},
|
||||||
|
{0,1,2,3,4,5,6,17},
|
||||||
|
{0,1,2,3,4,5,6,17},
|
||||||
|
{0,1,2,3,4,5,6,17},
|
||||||
|
{0,1,2,3,4,5,6,17},
|
||||||
|
{0,1,2,17},
|
||||||
|
{0,1,2,17},
|
||||||
|
{0,1,2,17},
|
||||||
|
{0,1,2,17},
|
||||||
|
{0,1,2,17},
|
||||||
|
{0,1,2,17},
|
||||||
|
{0,1,2,17}};
|
||||||
|
|
||||||
|
char t_alloc2[8][16] = { /* table B.2c ISO/IEC 11172-3 */
|
||||||
|
{0,1,2,4,5,6,7,8,9,10,11,12,13,14,15,16},
|
||||||
|
{0,1,2,4,5,6,7,8,9,10,11,12,13,14,15,16},
|
||||||
|
{0,1,2,4,5,6,7,127},
|
||||||
|
{0,1,2,4,5,6,7,127},
|
||||||
|
{0,1,2,4,5,6,7,127},
|
||||||
|
{0,1,2,4,5,6,7,127},
|
||||||
|
{0,1,2,4,5,6,7,127},
|
||||||
|
{0,1,2,4,5,6,7,127}};
|
||||||
|
|
||||||
|
char t_alloc3[12][16] = { /* table B.2d ISO/IEC 11172-3 */
|
||||||
|
{0,1,2,4,5,6,7,8,9,10,11,12,13,14,15,16},
|
||||||
|
{0,1,2,4,5,6,7,8,9,10,11,12,13,14,15,16},
|
||||||
|
{0,1,2,4,5,6,7,127},
|
||||||
|
{0,1,2,4,5,6,7,127},
|
||||||
|
{0,1,2,4,5,6,7,127},
|
||||||
|
{0,1,2,4,5,6,7,127},
|
||||||
|
{0,1,2,4,5,6,7,127},
|
||||||
|
{0,1,2,4,5,6,7,127},
|
||||||
|
{0,1,2,4,5,6,7,127},
|
||||||
|
{0,1,2,4,5,6,7,127},
|
||||||
|
{0,1,2,4,5,6,7,127},
|
||||||
|
{0,1,2,4,5,6,7,127}};
|
||||||
|
|
||||||
|
char t_allocMPG2[30][16] = { /* table B.1. ISO/IEC 13818-3 */
|
||||||
|
{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15},
|
||||||
|
{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15},
|
||||||
|
{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15},
|
||||||
|
{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15},
|
||||||
|
{0,1,2,4,5,6,7,8},
|
||||||
|
{0,1,2,4,5,6,7,8},
|
||||||
|
{0,1,2,4,5,6,7,8},
|
||||||
|
{0,1,2,4,5,6,7,8},
|
||||||
|
{0,1,2,4,5,6,7,8},
|
||||||
|
{0,1,2,4,5,6,7,8},
|
||||||
|
{0,1,2,4,5,6,7,8},
|
||||||
|
{0,1,2,4},
|
||||||
|
{0,1,2,4},
|
||||||
|
{0,1,2,4},
|
||||||
|
{0,1,2,4},
|
||||||
|
{0,1,2,4},
|
||||||
|
{0,1,2,4},
|
||||||
|
{0,1,2,4},
|
||||||
|
{0,1,2,4},
|
||||||
|
{0,1,2,4},
|
||||||
|
{0,1,2,4},
|
||||||
|
{0,1,2,4},
|
||||||
|
{0,1,2,4},
|
||||||
|
{0,1,2,4},
|
||||||
|
{0,1,2,4},
|
||||||
|
{0,1,2,4},
|
||||||
|
{0,1,2,4},
|
||||||
|
{0,1,2,4},
|
||||||
|
{0,1,2,4},
|
||||||
|
{0,1,2,4}};
|
||||||
|
|
||||||
|
double t_scalefactor[64] = {
|
||||||
|
2.00000000000000, 1.58740105196820, 1.25992104989487,
|
||||||
|
1.00000000000000, 0.79370052598410, 0.62996052494744, 0.50000000000000,
|
||||||
|
0.39685026299205, 0.31498026247372, 0.25000000000000, 0.19842513149602,
|
||||||
|
0.15749013123686, 0.12500000000000, 0.09921256574801, 0.07874506561843,
|
||||||
|
0.06250000000000, 0.04960628287401, 0.03937253280921, 0.03125000000000,
|
||||||
|
0.02480314143700, 0.01968626640461, 0.01562500000000, 0.01240157071850,
|
||||||
|
0.00984313320230, 0.00781250000000, 0.00620078535925, 0.00492156660115,
|
||||||
|
0.00390625000000, 0.00310039267963, 0.00246078330058, 0.00195312500000,
|
||||||
|
0.00155019633981, 0.00123039165029, 0.00097656250000, 0.00077509816991,
|
||||||
|
0.00061519582514, 0.00048828125000, 0.00038754908495, 0.00030759791257,
|
||||||
|
0.00024414062500, 0.00019377454248, 0.00015379895629, 0.00012207031250,
|
||||||
|
0.00009688727124, 0.00007689947814, 0.00006103515625, 0.00004844363562,
|
||||||
|
0.00003844973907, 0.00003051757813, 0.00002422181781, 0.00001922486954,
|
||||||
|
0.00001525878906, 0.00001211090890, 0.00000961243477, 0.00000762939453,
|
||||||
|
0.00000605545445, 0.00000480621738, 0.00000381469727, 0.00000302772723,
|
||||||
|
0.00000240310869, 0.00000190734863, 0.00000151386361, 0.00000120155435,
|
||||||
|
1E-20};
|
||||||
|
|
||||||
|
double t_c[18] = { 0,
|
||||||
|
1.33333333333, 1.60000000000, 1.14285714286,
|
||||||
|
1.77777777777, 1.06666666666, 1.03225806452,
|
||||||
|
1.01587301587, 1.00787401575, 1.00392156863,
|
||||||
|
1.00195694716, 1.00097751711, 1.00048851979,
|
||||||
|
1.00024420024, 1.00012208522, 1.00006103888,
|
||||||
|
1.00003051851, 1.00001525902 };
|
||||||
|
|
||||||
|
double t_d[18] = {0,
|
||||||
|
0.500000000, 0.500000000, 0.250000000, 0.500000000,
|
||||||
|
0.125000000, 0.062500000, 0.031250000, 0.015625000,
|
||||||
|
0.007812500, 0.003906250, 0.001953125, 0.0009765625,
|
||||||
|
0.00048828125,0.00024414063,0.00012207031,
|
||||||
|
0.00006103516,0.00003051758 };
|
||||||
|
|
||||||
|
float t_dd[18]={ -1.0f, -0.5f, -0.5f, -0.75f, -0.5f, -0.875f, -0.9375f, -0.96875f, -0.984375f,
|
||||||
|
-0.992188f, -0.996094f, -0.998047f, -0.999023f, -0.999512f, -0.999756f, -0.999878f, -0.999939f,
|
||||||
|
-0.999969f};
|
||||||
|
|
||||||
|
char t_grouping[18]={0,3,5,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0};
|
||||||
|
|
||||||
|
/*
|
||||||
|
int t_nlevels[18] = {0,3,5,7,9,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535};
|
||||||
|
*/
|
||||||
|
int t_nlevels[18] = {0,3,7,7,15,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535};
|
||||||
|
|
||||||
|
|
||||||
|
float t_nli[18]={ 0.0f, 0.5f, 0.25f, 0.25f, 0.125f, 0.125f, 0.0625f, 0.03125f, 0.015625f, 0.0078125f, 0.00390625f,
|
||||||
|
0.00195313f, 0.000976563f, 0.000488281f, 0.000244141f, 0.00012207f, 6.10352e-05f, 3.05176e-05f};
|
||||||
|
|
||||||
|
int t_bpc[18] = {0,5,7,3,10,4,5,6,7,8,9,10,11,12,13,14,15,16};
|
||||||
|
|
||||||
|
#endif /* LAYER2 */
|
197
Src/Sound/MPEG/layer3.cpp
Normal file
197
Src/Sound/MPEG/layer3.cpp
Normal file
|
@ -0,0 +1,197 @@
|
||||||
|
/* this file is a part of amp software, (C) tomislav uzelac 1996,1997
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* layer3.c layer3 audio decoding
|
||||||
|
*
|
||||||
|
* Created by: tomislav uzelac Mar 1 97
|
||||||
|
* Last modified by:
|
||||||
|
*/
|
||||||
|
#include "amp.h"
|
||||||
|
#include "audio.h"
|
||||||
|
#include "dump.h"
|
||||||
|
#include "getbits.h"
|
||||||
|
#include "getdata.h"
|
||||||
|
#include "huffman.h"
|
||||||
|
#include "misc2.h"
|
||||||
|
#include "rtbuf.h"
|
||||||
|
#include "transform.h"
|
||||||
|
|
||||||
|
#define LAYER3
|
||||||
|
#include "layer3.h"
|
||||||
|
|
||||||
|
void requantize_downmix(int gr,struct SIDE_INFO *info,struct AUDIO_HEADER *header);
|
||||||
|
|
||||||
|
/* this function decodes one layer3 audio frame, except for the header decoding
|
||||||
|
* which is done in main() [audio.c]. returns 0 if everything is ok.
|
||||||
|
*/
|
||||||
|
int layer3_frame(struct AUDIO_HEADER *header,int cnt)
|
||||||
|
{
|
||||||
|
static struct SIDE_INFO info;
|
||||||
|
|
||||||
|
int gr,ch,sb,i;
|
||||||
|
int mean_frame_size,bitrate,fs,hsize,ssize;
|
||||||
|
|
||||||
|
/* we need these later, hsize is the size of header+side_info
|
||||||
|
*/
|
||||||
|
if (header->ID)
|
||||||
|
if (header->mode==3) {
|
||||||
|
nch=1;
|
||||||
|
hsize=21;
|
||||||
|
} else {
|
||||||
|
nch=2;
|
||||||
|
hsize=36;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if (header->mode==3) {
|
||||||
|
nch=1;
|
||||||
|
hsize=13;
|
||||||
|
} else {
|
||||||
|
nch=2;
|
||||||
|
hsize=21;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* crc increases hsize by 2
|
||||||
|
*/
|
||||||
|
if (header->protection_bit==0) hsize+=2;
|
||||||
|
|
||||||
|
|
||||||
|
/* read layer3 specific side_info
|
||||||
|
*/
|
||||||
|
getinfo(header,&info);
|
||||||
|
|
||||||
|
|
||||||
|
/* MPEG2 only has one granule
|
||||||
|
*/
|
||||||
|
bitrate=t_bitrate[header->ID][3-header->layer][header->bitrate_index];
|
||||||
|
fs=t_sampling_frequency[header->ID][header->sampling_frequency];
|
||||||
|
if (header->ID) mean_frame_size=144000*bitrate/fs;
|
||||||
|
else mean_frame_size=72000*bitrate/fs;
|
||||||
|
|
||||||
|
|
||||||
|
/* check if mdb is too big for the first few frames. this means that
|
||||||
|
* a part of the stream could be missing. We must still fill the buffer
|
||||||
|
*
|
||||||
|
* don't forget to (re)initialise bclean_bytes to 0, and f_bdirty to FALSE!!!
|
||||||
|
*/
|
||||||
|
if (f_bdirty)
|
||||||
|
{
|
||||||
|
if (info.main_data_begin > bclean_bytes) {
|
||||||
|
fillbfr(mean_frame_size + header->padding_bit - hsize);
|
||||||
|
bclean_bytes+=mean_frame_size + header->padding_bit - hsize;
|
||||||
|
/* warn(" frame %d discarded, incomplete main_data\n",cnt); */
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
/* re-initialise */
|
||||||
|
f_bdirty=FALSE;
|
||||||
|
bclean_bytes=0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* now update the data 'pointer' (counting in bits) according to
|
||||||
|
* the main_data_begin information
|
||||||
|
*/
|
||||||
|
data = 8 * ((append - info.main_data_begin) & (BUFFER_SIZE-1));
|
||||||
|
|
||||||
|
|
||||||
|
/* read into the buffer all bytes up to the start of next header
|
||||||
|
*/
|
||||||
|
fillbfr(mean_frame_size + header->padding_bit - hsize);
|
||||||
|
|
||||||
|
|
||||||
|
/* these two should go away
|
||||||
|
*/
|
||||||
|
t_l=&t_b8_l[header->ID][header->sampling_frequency][0];
|
||||||
|
t_s=&t_b8_s[header->ID][header->sampling_frequency][0];
|
||||||
|
|
||||||
|
/* debug/dump stuff
|
||||||
|
*/
|
||||||
|
if (A_DUMP_BINARY) dump((int *)info.part2_3_length);
|
||||||
|
|
||||||
|
/* decode the scalefactors and huffman data
|
||||||
|
* this part needs to be enhanced for error robustness
|
||||||
|
*/
|
||||||
|
for (gr=0;gr < ((header->ID) ? 2 : 1);gr++) {
|
||||||
|
for (ch=0;ch<nch;ch++) {
|
||||||
|
ssize=decode_scalefactors(&info,header,gr,ch);
|
||||||
|
decode_huffman_data(&info,gr,ch,ssize);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* requantization, stereo processing, reordering(shortbl)
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (A_DOWNMIX && nch==2) requantize_downmix(gr,&info,header);
|
||||||
|
else
|
||||||
|
if (header->mode!=1 || (header->mode==1 && header->mode_extension==0))
|
||||||
|
for (ch=0;ch<nch;ch++) requantize_mono(gr,ch,&info,header);
|
||||||
|
else requantize_ms(gr,&info,header);
|
||||||
|
|
||||||
|
/* just which window?
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* this is a very temporary, very ugly hack.
|
||||||
|
*/
|
||||||
|
if (A_DOWNMIX) nch=1;
|
||||||
|
|
||||||
|
for (ch=0; ch < (A_DOWNMIX ? 1:nch) ;ch++) {
|
||||||
|
int win_type; /* same as in the standard, long=0, start=1 ,.... */
|
||||||
|
int window_switching_flag = info.window_switching_flag[gr][ch];
|
||||||
|
int block_type = info.block_type[gr][ch];
|
||||||
|
int mixed_block_flag = info.mixed_block_flag[gr][ch];
|
||||||
|
|
||||||
|
/* antialiasing butterflies
|
||||||
|
*/
|
||||||
|
if (!(window_switching_flag &&
|
||||||
|
block_type==2))
|
||||||
|
alias_reduction(ch);
|
||||||
|
|
||||||
|
if (window_switching_flag &&
|
||||||
|
block_type==2 &&
|
||||||
|
mixed_block_flag)
|
||||||
|
win_type=0;
|
||||||
|
else
|
||||||
|
if (!window_switching_flag) win_type=0;
|
||||||
|
else win_type=block_type;
|
||||||
|
|
||||||
|
/* imdct ...
|
||||||
|
*/
|
||||||
|
for (sb=0;sb<2;sb++)
|
||||||
|
imdct(win_type,sb,ch);
|
||||||
|
|
||||||
|
if (window_switching_flag &&
|
||||||
|
block_type==2 &&
|
||||||
|
mixed_block_flag)
|
||||||
|
win_type=2;
|
||||||
|
|
||||||
|
/* no_of_imdcts tells us how many subbands from the top are all zero
|
||||||
|
* it is set by the requantize functions in misc2.c
|
||||||
|
*/
|
||||||
|
for (sb=2;sb<no_of_imdcts[ch];sb++)
|
||||||
|
imdct(win_type,sb,ch);
|
||||||
|
|
||||||
|
for (;sb<32;sb++)
|
||||||
|
for (i=0;i<18;i++) {
|
||||||
|
res[sb][i]=s[ch][sb][i];
|
||||||
|
s[ch][sb][i]=0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* polyphase filterbank
|
||||||
|
*/
|
||||||
|
/* if (nch == 2) this was a bug, tomislav */
|
||||||
|
for (i=0;i<18;i++)
|
||||||
|
poly(ch,i);
|
||||||
|
}
|
||||||
|
|
||||||
|
printout();
|
||||||
|
|
||||||
|
/* this is part2 of a particularily ugly hack. this should vanish as soon as nch isn't
|
||||||
|
a global variable anymore
|
||||||
|
*/
|
||||||
|
if (A_DOWNMIX && header->mode!=3) nch=2;
|
||||||
|
|
||||||
|
} /* for (gr... */
|
||||||
|
|
||||||
|
/* return status: 0 for ok, errors will be added
|
||||||
|
*/
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
16
Src/Sound/MPEG/layer3.h
Normal file
16
Src/Sound/MPEG/layer3.h
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
/* this file is a part of amp software, (C) tomislav uzelac 1996,1997
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* layer3.h
|
||||||
|
*
|
||||||
|
* Created by: tomislav uzelac Mar 1 97
|
||||||
|
* Last modified by:
|
||||||
|
*/
|
||||||
|
|
||||||
|
extern int layer3_frame(struct AUDIO_HEADER *header,int cnt);
|
||||||
|
|
||||||
|
#ifdef LAYER3
|
||||||
|
|
||||||
|
int layer3_frame(struct AUDIO_HEADER *header,int cnt);
|
||||||
|
|
||||||
|
#endif /* LAYER3 */
|
822
Src/Sound/MPEG/misc2.cpp
Normal file
822
Src/Sound/MPEG/misc2.cpp
Normal file
|
@ -0,0 +1,822 @@
|
||||||
|
/* this file is a part of amp software, (C) tomislav uzelac 1996,1997
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* misc2.c requantization, stereo processing, reordering(shortbl) and antialiasing butterflies
|
||||||
|
*
|
||||||
|
* misc.c was created by tomislav uzelac in May 1996, and was completely awful
|
||||||
|
* Created by: tomislav uzelac Dec 22 1996
|
||||||
|
* some more speed injected, cca. Jun 1 1997
|
||||||
|
*/
|
||||||
|
#include <math.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "amp.h"
|
||||||
|
#include "audio.h"
|
||||||
|
#include "getdata.h"
|
||||||
|
#include "huffman.h"
|
||||||
|
|
||||||
|
#define MISC2
|
||||||
|
#include "misc2.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* fras == Formula for Requantization and All Scaling **************************
|
||||||
|
*/
|
||||||
|
static inline float fras_l(int sfb,int global_gain,int scalefac_scale,int scalefac,int preflag)
|
||||||
|
{
|
||||||
|
register int a,scale;
|
||||||
|
/*
|
||||||
|
if (scalefac_scale) scale=2;
|
||||||
|
else scale=1;
|
||||||
|
*/
|
||||||
|
scale=scalefac_scale+1;
|
||||||
|
a= global_gain -210 -(scalefac << scale);
|
||||||
|
if (preflag) a-=(t_pretab[sfb] << scale);
|
||||||
|
|
||||||
|
/* bugfix, Mar 13 97: shifting won't produce a legal result if we shift by more than 31
|
||||||
|
* since global_gain<256, this can only occur for (very) negative values of a.
|
||||||
|
*/
|
||||||
|
if (a < -127) return 0;
|
||||||
|
|
||||||
|
/* a minor change here as well, no point in abs() if we now that a<0
|
||||||
|
*/
|
||||||
|
if (a>=0) return tab[a&3]*(1 << (a>>2));
|
||||||
|
else return tabi[(-a)&3]/(1 << ((-a) >> 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline float fras_s(int global_gain,int subblock_gain,int scalefac_scale,int scalefac)
|
||||||
|
{
|
||||||
|
int a;
|
||||||
|
a=global_gain - 210 - (subblock_gain << 3);
|
||||||
|
if (scalefac_scale) a-= (scalefac << 2);
|
||||||
|
else a-= (scalefac << 1);
|
||||||
|
|
||||||
|
if (a < -127) return 0;
|
||||||
|
|
||||||
|
if (a>=0) return tab[a&3]*(1 << (a>>2));
|
||||||
|
else return tabi[(-a)&3]/(1 << ((-a) >> 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* this should be faster than pow()
|
||||||
|
*/
|
||||||
|
static inline float fras2(int is,float a)
|
||||||
|
{
|
||||||
|
if (is > 0) return t_43[is]*a;
|
||||||
|
else return -t_43[-is]*a;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* requantize_mono *************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* generally, the two channels do not have to be of the same block type - that's why we do two passes with requantize_mono.
|
||||||
|
* if ms or intensity stereo is enabled we do a single pass with requantize_ms because both channels are same block type
|
||||||
|
*/
|
||||||
|
|
||||||
|
void requantize_mono(int gr,int ch,struct SIDE_INFO *info,struct AUDIO_HEADER *header)
|
||||||
|
{
|
||||||
|
int l,i,sfb;
|
||||||
|
float a;
|
||||||
|
int global_gain=info->global_gain[gr][ch];
|
||||||
|
int scalefac_scale=info->scalefac_scale[gr][ch];
|
||||||
|
int sfreq=header->sampling_frequency;
|
||||||
|
|
||||||
|
|
||||||
|
no_of_imdcts[0]=no_of_imdcts[1]=32;
|
||||||
|
|
||||||
|
if (info->window_switching_flag[gr][ch] && info->block_type[gr][ch]==2)
|
||||||
|
if (info->mixed_block_flag[gr][ch]) {
|
||||||
|
/*
|
||||||
|
* requantize_mono - mixed blocks/long block part **********************
|
||||||
|
*/
|
||||||
|
int window,window_len,preflag=0; /* pretab is all zero in this low frequency area */
|
||||||
|
int scalefac=scalefac_l[gr][ch][0];
|
||||||
|
|
||||||
|
l=0;sfb=0;
|
||||||
|
a=fras_l(sfb,global_gain,scalefac_scale,scalefac,preflag);
|
||||||
|
while (l<36) {
|
||||||
|
xr[ch][0][l]=fras2(is[ch][l],a);
|
||||||
|
if (l==t_l[sfb]) {
|
||||||
|
scalefac=scalefac_l[gr][ch][++sfb];
|
||||||
|
a=fras_l(sfb,global_gain,scalefac_scale,scalefac,preflag);
|
||||||
|
}
|
||||||
|
l++;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* requantize_mono - mixed blocks/short block part *********************
|
||||||
|
*/
|
||||||
|
sfb=3;
|
||||||
|
window_len=t_s[sfb]-t_s[sfb-1];
|
||||||
|
while (l<non_zero[ch]) {
|
||||||
|
for (window=0;window<3;window++) {
|
||||||
|
int scalefac=scalefac_s[gr][ch][sfb][window];
|
||||||
|
int subblock_gain=info->subblock_gain[gr][ch][window];
|
||||||
|
a=fras_s(global_gain,subblock_gain,scalefac_scale,scalefac);
|
||||||
|
for (i=0;i<window_len;i++) {
|
||||||
|
xr[ch][0][t_reorder[header->ID][sfreq][l]]=fras2(is[ch][l],a);
|
||||||
|
l++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sfb++;
|
||||||
|
window_len=t_s[sfb]-t_s[sfb-1];
|
||||||
|
}
|
||||||
|
while (l<576) xr[ch][0][t_reorder[header->ID][sfreq][l++]]=0;
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* requantize mono - short blocks **************************************
|
||||||
|
*/
|
||||||
|
int window,window_len;
|
||||||
|
|
||||||
|
sfb=0; l=0;
|
||||||
|
window_len=t_s[0]+1;
|
||||||
|
while (l<non_zero[ch]) {
|
||||||
|
for (window=0;window<3;window++) {
|
||||||
|
int scalefac=scalefac_s[gr][ch][sfb][window];
|
||||||
|
int subblock_gain=info->subblock_gain[gr][ch][window];
|
||||||
|
float a=fras_s(global_gain,subblock_gain,scalefac_scale,scalefac);
|
||||||
|
for (i=0;i<window_len;i++) {
|
||||||
|
xr[ch][0][t_reorder[header->ID][sfreq][l]]=fras2(is[ch][l],a);
|
||||||
|
l++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sfb++;
|
||||||
|
window_len=t_s[sfb]-t_s[sfb-1];
|
||||||
|
}
|
||||||
|
while (l<576) xr[ch][0][t_reorder[header->ID][sfreq][l++]]=0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* long blocks */
|
||||||
|
int preflag=info->preflag[gr][ch];
|
||||||
|
int scalefac=scalefac_l[gr][ch][0];
|
||||||
|
|
||||||
|
sfb=0; l=0;
|
||||||
|
a=fras_l(sfb,global_gain,scalefac_scale,scalefac,preflag);
|
||||||
|
while (l<non_zero[ch]) {
|
||||||
|
xr[ch][0][l]=fras2(is[ch][l],a);
|
||||||
|
if (l==t_l[sfb]) {
|
||||||
|
scalefac=scalefac_l[gr][ch][++sfb];
|
||||||
|
a=fras_l(sfb,global_gain,scalefac_scale,scalefac,preflag);
|
||||||
|
}
|
||||||
|
l++;
|
||||||
|
}
|
||||||
|
while (l<576) xr[ch][0][l++]=0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* stereo stuff ****************************************************************
|
||||||
|
*/
|
||||||
|
static int find_isbound(int isbound[3],int gr,struct SIDE_INFO *info,struct AUDIO_HEADER *header)
|
||||||
|
{
|
||||||
|
int sfb,window,window_len,ms_flag,tmp,i;
|
||||||
|
|
||||||
|
isbound[0]=isbound[1]=isbound[2]=-1;
|
||||||
|
no_of_imdcts[0]=no_of_imdcts[1]=32;
|
||||||
|
|
||||||
|
if (header->mode_extension==1 || header->mode_extension==3) {
|
||||||
|
if (info->window_switching_flag[gr][0] && info->block_type[gr][0]==2) {
|
||||||
|
|
||||||
|
/* find that isbound!
|
||||||
|
*/
|
||||||
|
tmp=non_zero[1];
|
||||||
|
sfb=0; while ((3*t_s[sfb]+2) < tmp && sfb < 12) sfb++;
|
||||||
|
while ((isbound[0]<0 || isbound[1]<0 || isbound[2]<0) && !(info->mixed_block_flag[gr][0] && sfb<3) && sfb) {
|
||||||
|
for (window=0;window<3;window++) {
|
||||||
|
if (sfb==0) {
|
||||||
|
window_len=t_s[0]+1;
|
||||||
|
tmp=(window+1)*window_len - 1;
|
||||||
|
} else {
|
||||||
|
window_len=t_s[sfb]-t_s[sfb-1];
|
||||||
|
tmp=(3*t_s[sfb-1]+2) + (window+1)*window_len;
|
||||||
|
}
|
||||||
|
if (isbound[window] < 0)
|
||||||
|
for (i=0;i<window_len;i++)
|
||||||
|
if (is[1][tmp--] != 0) {
|
||||||
|
isbound[window]=t_s[sfb]+1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sfb--;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* mixed block magic now...
|
||||||
|
*/
|
||||||
|
if (sfb==2 && info->mixed_block_flag[gr][0])
|
||||||
|
{
|
||||||
|
if (isbound[0]<0 && isbound[1]<0 && isbound[2]<0)
|
||||||
|
{
|
||||||
|
tmp=35;
|
||||||
|
while (is[1][tmp] == 0) tmp--;
|
||||||
|
sfb=0; while (t_l[sfb] < tmp && sfb < 21) sfb++;
|
||||||
|
isbound[0]=isbound[1]=isbound[2]=t_l[sfb]+1;
|
||||||
|
}
|
||||||
|
else for (window=0;window<3;window++)
|
||||||
|
if (isbound[window]<0) isbound[window]=36;
|
||||||
|
}
|
||||||
|
if (header->ID==1) isbound[0]=isbound[1]=isbound[2]=MAX(isbound[0],MAX(isbound[1],isbound[2]));
|
||||||
|
|
||||||
|
/* just how many imdcts?
|
||||||
|
*/
|
||||||
|
tmp=non_zero[0];
|
||||||
|
sfb=0; while ((3*t_s[sfb]+2) < tmp && sfb < 12) sfb++;
|
||||||
|
no_of_imdcts[0]=no_of_imdcts[1]=(t_s[sfb]-1)/6+1;
|
||||||
|
} else {
|
||||||
|
|
||||||
|
/* long blocks now
|
||||||
|
*/
|
||||||
|
tmp=non_zero[1];
|
||||||
|
while (is[1][tmp] == 0) tmp--;
|
||||||
|
sfb=0; while (t_l[sfb] < tmp && sfb < 21) sfb++;
|
||||||
|
isbound[0]=isbound[1]=isbound[2]=t_l[sfb]+1;
|
||||||
|
no_of_imdcts[0]=no_of_imdcts[1]=(non_zero[0]-1)/18+1;
|
||||||
|
}
|
||||||
|
if (header->mode_extension==1) ms_flag=0;
|
||||||
|
else ms_flag=1;
|
||||||
|
} else {
|
||||||
|
|
||||||
|
/* intensity stereo is, regretably, turned off
|
||||||
|
*/
|
||||||
|
ms_flag=1;
|
||||||
|
|
||||||
|
/* i really put a lot of work in this, but it still looks like shit (works, though)
|
||||||
|
*/
|
||||||
|
if (!info->window_switching_flag[gr][0] || (info->window_switching_flag[gr][0] && info->block_type[gr][0]!=2))
|
||||||
|
isbound[0]=isbound[1]=isbound[2]=(MAX(non_zero[0],non_zero[1]));
|
||||||
|
else isbound[0]=isbound[1]=isbound[2]=576;
|
||||||
|
|
||||||
|
if (info->window_switching_flag[gr][0] && info->block_type[gr][0]==2) {
|
||||||
|
/* should do for mixed blocks too, though i havent tested... */
|
||||||
|
tmp=(MAX(non_zero[0],non_zero[1]))/3;
|
||||||
|
sfb=0; while (t_s[sfb]<tmp && sfb<12) sfb++;
|
||||||
|
no_of_imdcts[0]=no_of_imdcts[1]=(t_s[sfb]-1)/6+1;
|
||||||
|
}
|
||||||
|
else no_of_imdcts[0]=no_of_imdcts[1]=(isbound[0]-1)/18+1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return ms_flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void stereo_s(int l,float a[2],int pos,int ms_flag,int is_pos,struct AUDIO_HEADER *header)
|
||||||
|
{
|
||||||
|
float ftmp,Mi,Si;
|
||||||
|
|
||||||
|
if (l>=576) return; /* brrr... */
|
||||||
|
|
||||||
|
if ((is_pos != IS_ILLEGAL) && (header->ID==1)) {
|
||||||
|
ftmp=fras2(is[0][l],a[0]);
|
||||||
|
xr[0][0][pos]=(1-t_is[is_pos])*ftmp;
|
||||||
|
xr[1][0][pos]=t_is[is_pos]*ftmp;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((is_pos != IS_ILLEGAL) && (header->ID==0)) {
|
||||||
|
ftmp=fras2(is[0][l],a[0]);
|
||||||
|
if (is_pos&1) {
|
||||||
|
xr[0][0][pos]= t_is2[intensity_scale][(is_pos+1)>>1] * ftmp;
|
||||||
|
xr[1][0][pos]= ftmp;
|
||||||
|
} else {
|
||||||
|
xr[0][0][pos]= ftmp;
|
||||||
|
xr[1][0][pos]= t_is2[intensity_scale][is_pos>>1] * ftmp;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ms_flag) {
|
||||||
|
Mi=fras2(is[0][l],a[0]);
|
||||||
|
Si=fras2(is[1][l],a[1]);
|
||||||
|
xr[0][0][pos]=(Mi+Si)*i_sq2;
|
||||||
|
xr[1][0][pos]=(Mi-Si)*i_sq2;
|
||||||
|
} else {
|
||||||
|
xr[0][0][pos]=fras2(is[0][l],a[0]);
|
||||||
|
xr[1][0][pos]=fras2(is[1][l],a[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void stereo_l(int l,float a[2],int ms_flag,int is_pos,struct AUDIO_HEADER *header)
|
||||||
|
{
|
||||||
|
float ftmp,Mi,Si;
|
||||||
|
if (l>=576) return;
|
||||||
|
|
||||||
|
/* new code by ???
|
||||||
|
*/
|
||||||
|
if (is_pos != IS_ILLEGAL) {
|
||||||
|
ftmp = fras2(is[0][l], a[0]);
|
||||||
|
if (header -> ID ==1) {
|
||||||
|
xr[0][0][l] = (1 - t_is[is_pos]) * ftmp;
|
||||||
|
xr[1][0][l] = t_is[is_pos] * ftmp;
|
||||||
|
return;
|
||||||
|
} else if (is_pos & 1) {
|
||||||
|
xr[0][0][l] = t_is2[intensity_scale][(is_pos + 1) >> 1] * ftmp;
|
||||||
|
xr[1][0][l] = ftmp;
|
||||||
|
} else {
|
||||||
|
xr[0][0][l] = ftmp;
|
||||||
|
xr[1][0][l] = t_is2[intensity_scale][is_pos >> 1] * ftmp;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ms_flag) {
|
||||||
|
Mi=fras2(is[0][l],a[0]);
|
||||||
|
Si=fras2(is[1][l],a[1]);
|
||||||
|
xr[0][0][l]=(Mi+Si)*i_sq2;
|
||||||
|
xr[1][0][l]=(Mi-Si)*i_sq2;
|
||||||
|
} else {
|
||||||
|
xr[0][0][l]=fras2(is[0][l],a[0]);
|
||||||
|
xr[1][0][l]=fras2(is[1][l],a[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* requantize_ms ***************************************************************
|
||||||
|
*/
|
||||||
|
void requantize_ms(int gr,struct SIDE_INFO *info,struct AUDIO_HEADER *header)
|
||||||
|
{
|
||||||
|
int l,sfb,ms_flag,is_pos,i,ch;
|
||||||
|
int *global_gain,subblock_gain[2],*scalefac_scale,scalefac[2],isbound[3];
|
||||||
|
int sfreq=header->sampling_frequency;
|
||||||
|
int id = header->ID;
|
||||||
|
float a[2];
|
||||||
|
|
||||||
|
memset(a, 0, sizeof(a));
|
||||||
|
|
||||||
|
global_gain=info->global_gain[gr];
|
||||||
|
scalefac_scale=info->scalefac_scale[gr];
|
||||||
|
|
||||||
|
if (info->window_switching_flag[gr][0] && info->block_type[gr][0]==2)
|
||||||
|
if (info->mixed_block_flag[gr][0]) {
|
||||||
|
/*
|
||||||
|
* mixed blocks w/stereo processing - long block part ******************
|
||||||
|
*/
|
||||||
|
int window,window_len;
|
||||||
|
int preflag[2]={0,0};
|
||||||
|
|
||||||
|
ms_flag=find_isbound(isbound,gr,info,header);
|
||||||
|
|
||||||
|
sfb=0; l=0;
|
||||||
|
for (ch=0;ch<2;ch++) {
|
||||||
|
scalefac[ch]=scalefac_l[gr][ch][0];
|
||||||
|
a[ch]=fras_l(0,global_gain[ch],scalefac_scale[ch],scalefac[ch],preflag[ch]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
while (l<36) {
|
||||||
|
int is_pos;
|
||||||
|
if (l<isbound[0]) is_pos=IS_ILLEGAL;
|
||||||
|
else {
|
||||||
|
is_pos=scalefac[1];
|
||||||
|
if (id==1) /* MPEG1 */
|
||||||
|
{
|
||||||
|
if (is_pos==7) is_pos=IS_ILLEGAL;
|
||||||
|
}
|
||||||
|
else /* MPEG2 */
|
||||||
|
{
|
||||||
|
if (is_pos==is_max[sfb]) is_pos=IS_ILLEGAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stereo_l(l,a,ms_flag,is_pos,header);
|
||||||
|
|
||||||
|
if (l==t_l[sfb]) {
|
||||||
|
sfb++;
|
||||||
|
for (ch=0;ch<2;ch++) {
|
||||||
|
scalefac[ch]=scalefac_l[gr][ch][sfb];
|
||||||
|
a[ch]=fras_l(sfb,global_gain[ch],scalefac_scale[ch],scalefac[ch],preflag[ch]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
l++;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* mixed blocks w/stereo processing - short block part *****************
|
||||||
|
*/
|
||||||
|
sfb=3;
|
||||||
|
window_len=t_s[sfb]-t_s[sfb-1];
|
||||||
|
|
||||||
|
while (l<(MAX(non_zero[0],non_zero[1]))) {
|
||||||
|
for (window=0;window<3;window++) {
|
||||||
|
subblock_gain[0]=info->subblock_gain[gr][0][window];
|
||||||
|
subblock_gain[1]=info->subblock_gain[gr][1][window];
|
||||||
|
scalefac[0]=scalefac_s[gr][0][sfb][window];
|
||||||
|
scalefac[1]=scalefac_s[gr][1][sfb][window];
|
||||||
|
|
||||||
|
if (t_s[sfb] < isbound[window]) {
|
||||||
|
is_pos=IS_ILLEGAL;
|
||||||
|
a[0]=fras_s(global_gain[0],subblock_gain[0],scalefac_scale[0],scalefac[0]);
|
||||||
|
a[1]=fras_s(global_gain[1],subblock_gain[1],scalefac_scale[1],scalefac[1]);
|
||||||
|
} else {
|
||||||
|
is_pos=scalefac[1];
|
||||||
|
if (id==1) /* MPEG1 */
|
||||||
|
{
|
||||||
|
if (is_pos==7) is_pos=IS_ILLEGAL;
|
||||||
|
}
|
||||||
|
else /* MPEG2 */
|
||||||
|
{
|
||||||
|
if (is_pos==is_max[sfb+6]) is_pos=IS_ILLEGAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
a[0]=fras_s(global_gain[0],subblock_gain[0],scalefac_scale[0],scalefac[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i=0;i<window_len;i++) {
|
||||||
|
stereo_s(l,a,t_reorder[id][sfreq][l],ms_flag,is_pos,header);
|
||||||
|
l++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sfb++;
|
||||||
|
window_len=t_s[sfb]-t_s[sfb-1];
|
||||||
|
}
|
||||||
|
while (l<576) {
|
||||||
|
int reorder = t_reorder[id][sfreq][l++];
|
||||||
|
|
||||||
|
xr[0][0][reorder]=xr[1][0][reorder]=0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* requantize_ms - short blocks w/stereo processing ********************
|
||||||
|
*/
|
||||||
|
int window,window_len;
|
||||||
|
|
||||||
|
ms_flag=find_isbound(isbound,gr,info,header);
|
||||||
|
sfb=0; l=0;
|
||||||
|
window_len=t_s[0]+1;
|
||||||
|
|
||||||
|
while (l<(MAX(non_zero[0],non_zero[1]))) {
|
||||||
|
for (window=0;window<3;window++) {
|
||||||
|
subblock_gain[0]=info->subblock_gain[gr][0][window];
|
||||||
|
subblock_gain[1]=info->subblock_gain[gr][1][window];
|
||||||
|
scalefac[0]=scalefac_s[gr][0][sfb][window];
|
||||||
|
scalefac[1]=scalefac_s[gr][1][sfb][window];
|
||||||
|
|
||||||
|
if (t_s[sfb] < isbound[window]) {
|
||||||
|
is_pos=IS_ILLEGAL;
|
||||||
|
a[0]=fras_s(global_gain[0],subblock_gain[0],scalefac_scale[0],scalefac[0]);
|
||||||
|
a[1]=fras_s(global_gain[1],subblock_gain[1],scalefac_scale[1],scalefac[1]);
|
||||||
|
} else {
|
||||||
|
is_pos=scalefac[1];
|
||||||
|
if (id==1) /* MPEG1 */
|
||||||
|
{
|
||||||
|
if (is_pos==7) is_pos=IS_ILLEGAL;
|
||||||
|
}
|
||||||
|
else /* MPEG2 */
|
||||||
|
{
|
||||||
|
if (is_pos==is_max[sfb+6]) is_pos=IS_ILLEGAL;
|
||||||
|
}
|
||||||
|
a[0]=fras_s(global_gain[0],subblock_gain[0],scalefac_scale[0],scalefac[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i=0;i<window_len;i++) {
|
||||||
|
stereo_s(l,a,t_reorder[id][sfreq][l],ms_flag,is_pos,header);
|
||||||
|
l++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* this won't do anymore
|
||||||
|
* window_len=-t_s[sfb]+t_s[++sfb];
|
||||||
|
*/
|
||||||
|
window_len = -t_s[sfb++];
|
||||||
|
window_len += t_s[sfb];
|
||||||
|
|
||||||
|
}
|
||||||
|
while (l<576) {
|
||||||
|
int reorder = t_reorder[id][sfreq][l++];
|
||||||
|
|
||||||
|
xr[0][0][reorder]=xr[1][0][reorder]=0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/*
|
||||||
|
* long blocks w/stereo processing *************************************
|
||||||
|
*/
|
||||||
|
int *preflag=info->preflag[gr];
|
||||||
|
|
||||||
|
ms_flag=find_isbound(isbound,gr,info,header);
|
||||||
|
|
||||||
|
sfb=0; l=0;
|
||||||
|
scalefac[0]=scalefac_l[gr][0][sfb];
|
||||||
|
a[0]=fras_l(sfb,global_gain[0],scalefac_scale[0],scalefac[0],preflag[0]);
|
||||||
|
scalefac[1]=scalefac_l[gr][1][sfb];
|
||||||
|
a[1]=fras_l(sfb,global_gain[1],scalefac_scale[1],scalefac[1],preflag[1]);
|
||||||
|
|
||||||
|
/* no intensity stereo part
|
||||||
|
*/
|
||||||
|
if (ms_flag)
|
||||||
|
while (l< isbound[0]) {
|
||||||
|
#if defined(PENTIUM_RDTSC)
|
||||||
|
|
||||||
|
unsigned int cnt4, cnt3, cnt2, cnt1;
|
||||||
|
static int min_cycles = 99999999;
|
||||||
|
|
||||||
|
__asm__(".byte 0x0f,0x31" : "=a" (cnt1), "=d" (cnt4));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
{
|
||||||
|
register float Mi = fras2(is[0][l],a[0]);
|
||||||
|
register float Si = fras2(is[1][l],a[1]);
|
||||||
|
register float tmp = i_sq2;
|
||||||
|
xr[0][0][l]=(Mi+Si)*tmp;
|
||||||
|
xr[1][0][l]=(Mi-Si)*tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(PENTIUM_RDTSC)
|
||||||
|
__asm__(".byte 0x0f,0x31" : "=a" (cnt2), "=d" (cnt4));
|
||||||
|
|
||||||
|
if (cnt2-cnt1 < min_cycles) {
|
||||||
|
min_cycles = cnt2-cnt1;
|
||||||
|
printf("%d cycles\n", min_cycles);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
if (l==t_l[sfb]) {
|
||||||
|
#if defined(PENTIUM_RDTSC2)
|
||||||
|
|
||||||
|
unsigned int cnt4, cnt2, cnt1;
|
||||||
|
static int min_cycles = 99999999;
|
||||||
|
|
||||||
|
__asm__(".byte 0x0f,0x31" : "=a" (cnt1), "=d" (cnt4));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
sfb++;
|
||||||
|
scalefac[0]=scalefac_l[gr][0][sfb];
|
||||||
|
a[0]=fras_l(sfb,global_gain[0],scalefac_scale[0],scalefac[0],preflag[0]);
|
||||||
|
scalefac[1]=scalefac_l[gr][1][sfb];
|
||||||
|
a[1]=fras_l(sfb,global_gain[1],scalefac_scale[1],scalefac[1],preflag[1]);
|
||||||
|
#if defined(PENTIUM_RDTSC2)
|
||||||
|
__asm__(".byte 0x0f,0x31" : "=a" (cnt2), "=d" (cnt4));
|
||||||
|
|
||||||
|
if (cnt2-cnt1 < min_cycles) {
|
||||||
|
min_cycles = cnt2-cnt1;
|
||||||
|
printf("%d cycles, sfb %d\n", min_cycles, sfb);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
l++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
while (l< isbound[0]) {
|
||||||
|
xr[0][0][l]=fras2(is[0][l],a[0]);
|
||||||
|
xr[1][0][l]=fras2(is[1][l],a[1]);
|
||||||
|
if (l==t_l[sfb]) {
|
||||||
|
sfb++;
|
||||||
|
scalefac[0]=scalefac_l[gr][0][sfb];
|
||||||
|
a[0]=fras_l(sfb,global_gain[0],scalefac_scale[0],scalefac[0],preflag[0]);
|
||||||
|
scalefac[1]=scalefac_l[gr][1][sfb];
|
||||||
|
a[1]=fras_l(sfb,global_gain[1],scalefac_scale[1],scalefac[1],preflag[1]);
|
||||||
|
}
|
||||||
|
l++;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* intensity stereo part
|
||||||
|
*/
|
||||||
|
while (l<(MAX(non_zero[0],non_zero[1]))) {
|
||||||
|
int is_pos=scalefac[1];
|
||||||
|
|
||||||
|
if (id==1) /* MPEG1 */
|
||||||
|
{
|
||||||
|
if (is_pos==7) is_pos=IS_ILLEGAL;
|
||||||
|
}
|
||||||
|
else /* MPEG2 */
|
||||||
|
{
|
||||||
|
if (is_pos==is_max[sfb]) is_pos=IS_ILLEGAL;
|
||||||
|
}
|
||||||
|
stereo_l(l,a,ms_flag,is_pos,header);
|
||||||
|
|
||||||
|
if (l==t_l[sfb]) {
|
||||||
|
sfb++;
|
||||||
|
scalefac[0]=scalefac_l[gr][0][sfb];
|
||||||
|
scalefac[1]=scalefac_l[gr][1][sfb];
|
||||||
|
a[0]=fras_l(sfb,global_gain[0],scalefac_scale[0],scalefac[0],preflag[0]);
|
||||||
|
}
|
||||||
|
l++;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (l<576) {
|
||||||
|
xr[0][0][l]=0;
|
||||||
|
xr[1][0][l]=0;
|
||||||
|
l++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* requantize_downmix **********************************************************
|
||||||
|
*/
|
||||||
|
void requantize_downmix(int gr,struct SIDE_INFO *info,struct AUDIO_HEADER *header)
|
||||||
|
{
|
||||||
|
int l,sfb,ms_flag,i;
|
||||||
|
int *global_gain,subblock_gain[2],*scalefac_scale,scalefac[2];
|
||||||
|
int sfreq=header->sampling_frequency;
|
||||||
|
int id = header->ID;
|
||||||
|
float a[2];
|
||||||
|
|
||||||
|
/* first set some variables
|
||||||
|
*/
|
||||||
|
global_gain=info->global_gain[gr];
|
||||||
|
scalefac_scale=info->scalefac_scale[gr];
|
||||||
|
|
||||||
|
if (header->mode_extension==2 || header->mode_extension==3) ms_flag=1;
|
||||||
|
else ms_flag=0;
|
||||||
|
|
||||||
|
/* ... and then we're off for requantization
|
||||||
|
*/
|
||||||
|
if (info->window_switching_flag[gr][0] && info->block_type[gr][0]==2)
|
||||||
|
if (info->mixed_block_flag[gr][0]) {
|
||||||
|
die("mixed block? hmmmm...., downmix for mixed blocks is not yet implemented\n");
|
||||||
|
} else {
|
||||||
|
int window,window_len;
|
||||||
|
int isbound[3];
|
||||||
|
int is_pos;
|
||||||
|
|
||||||
|
memset(isbound, 0, sizeof(isbound));
|
||||||
|
|
||||||
|
sfb=0; l=0; window_len=t_s[0]+1;
|
||||||
|
|
||||||
|
while (l<(MAX(non_zero[0],non_zero[1]))) {
|
||||||
|
for (window=0;window<3;window++) {
|
||||||
|
subblock_gain[0]=info->subblock_gain[gr][0][window];
|
||||||
|
subblock_gain[1]=info->subblock_gain[gr][1][window];
|
||||||
|
scalefac[0]=scalefac_s[gr][0][sfb][window];
|
||||||
|
is_pos=scalefac[1]=scalefac_s[gr][1][sfb][window];
|
||||||
|
|
||||||
|
if (t_s[sfb] < isbound[window]) {
|
||||||
|
a[0]=fras_s(global_gain[0],subblock_gain[0],scalefac_scale[0],scalefac[0]);
|
||||||
|
if (ms_flag) {
|
||||||
|
for (i=0;i<window_len;i++) {
|
||||||
|
register float Mi=fras2(is[0][l],a[0]);
|
||||||
|
xr[0][0][t_reorder[id][sfreq][l]]=Mi*i_sq2;
|
||||||
|
l++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
a[1]=fras_s(global_gain[1],subblock_gain[1],scalefac_scale[1],scalefac[1]);
|
||||||
|
for (i=0;i<window_len;i++) {
|
||||||
|
register float tmp1=fras2(is[0][l],a[0]);
|
||||||
|
register float tmp2=fras2(is[1][l],a[1]);
|
||||||
|
xr[0][0][t_reorder[id][sfreq][l]]=(tmp1+tmp2)*0.5f;
|
||||||
|
l++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
a[0]=fras_s(global_gain[0],subblock_gain[0],scalefac_scale[0],scalefac[0]);
|
||||||
|
for (i=0;i<window_len;i++) {
|
||||||
|
register float ftmp = fras2(is[0][l], a[0]);
|
||||||
|
if (id==0 && is_pos<is_max[sfb])
|
||||||
|
ftmp*=t_downmix[intensity_scale][(is_pos+1)>>1];
|
||||||
|
xr[0][0][t_reorder[id][sfreq][l]] = ftmp;
|
||||||
|
l++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
window_len = -t_s[sfb++];
|
||||||
|
window_len += t_s[sfb];
|
||||||
|
}
|
||||||
|
while (l<576) {
|
||||||
|
xr[0][0][l]=0;
|
||||||
|
l++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
int *preflag=info->preflag[gr];
|
||||||
|
int isbound;
|
||||||
|
|
||||||
|
if (header->mode_extension==1 || header->mode_extension==3) {
|
||||||
|
int tmp=non_zero[1];
|
||||||
|
while (is[1][tmp] == 0) tmp--;
|
||||||
|
sfb=0; while (t_l[sfb] < tmp && sfb < 21) sfb++;
|
||||||
|
isbound=t_l[sfb]+1;
|
||||||
|
no_of_imdcts[0]=no_of_imdcts[1]=(non_zero[0]-1)/18+1;
|
||||||
|
} else {
|
||||||
|
isbound=(MAX(non_zero[0],non_zero[1]));
|
||||||
|
no_of_imdcts[0]=no_of_imdcts[1]=(isbound-1)/18+1;
|
||||||
|
}
|
||||||
|
|
||||||
|
sfb=0; l=0;
|
||||||
|
scalefac[0]=scalefac_l[gr][0][sfb];
|
||||||
|
a[0]=fras_l(sfb,global_gain[0],scalefac_scale[0],scalefac[0],preflag[0]);
|
||||||
|
scalefac[1]=scalefac_l[gr][1][sfb];
|
||||||
|
a[1]=fras_l(sfb,global_gain[1],scalefac_scale[1],scalefac[1],preflag[1]);
|
||||||
|
|
||||||
|
/* no intensity stereo part
|
||||||
|
*/
|
||||||
|
if (ms_flag)
|
||||||
|
while (l < isbound) {
|
||||||
|
register float Mi = fras2(is[0][l],a[0]);
|
||||||
|
register float tmp = i_sq2;
|
||||||
|
xr[0][0][l]=Mi*tmp;
|
||||||
|
|
||||||
|
if (l==t_l[sfb]) {
|
||||||
|
sfb++;
|
||||||
|
scalefac[0]=scalefac_l[gr][0][sfb];
|
||||||
|
a[0]=fras_l(sfb,global_gain[0],scalefac_scale[0],scalefac[0],preflag[0]);
|
||||||
|
scalefac[1]=scalefac_l[gr][1][sfb];
|
||||||
|
}
|
||||||
|
l++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
while (l < isbound) {
|
||||||
|
register float tmp1=fras2(is[0][l],a[0]);
|
||||||
|
register float tmp2=fras2(is[1][l],a[1]);
|
||||||
|
xr[0][0][l]=(tmp1+tmp2)*0.5f;
|
||||||
|
if (l==t_l[sfb]) {
|
||||||
|
sfb++;
|
||||||
|
scalefac[0]=scalefac_l[gr][0][sfb];
|
||||||
|
a[0]=fras_l(sfb,global_gain[0],scalefac_scale[0],scalefac[0],preflag[0]);
|
||||||
|
scalefac[1]=scalefac_l[gr][1][sfb];
|
||||||
|
a[1]=fras_l(sfb,global_gain[1],scalefac_scale[1],scalefac[1],preflag[1]);
|
||||||
|
}
|
||||||
|
l++;
|
||||||
|
}
|
||||||
|
/* intensity stereo part
|
||||||
|
*/
|
||||||
|
while (l<(MAX(non_zero[0],non_zero[1]))) {
|
||||||
|
int is_pos=scalefac[1];
|
||||||
|
register float ftmp=fras2(is[0][l], a[0]);
|
||||||
|
|
||||||
|
if (id==0 && is_pos<is_max[sfb]) {
|
||||||
|
ftmp*=t_downmix[intensity_scale][(is_pos+1)>>1];
|
||||||
|
}
|
||||||
|
|
||||||
|
xr[0][0][l] = ftmp;
|
||||||
|
|
||||||
|
if (l==t_l[sfb]) {
|
||||||
|
sfb++;
|
||||||
|
scalefac[0]=scalefac_l[gr][0][sfb];
|
||||||
|
a[0]=fras_l(sfb,global_gain[0],scalefac_scale[0],scalefac[0],preflag[0]);
|
||||||
|
scalefac[1]=scalefac_l[gr][1][sfb];
|
||||||
|
}
|
||||||
|
l++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* _always_ zero out everything else
|
||||||
|
*/
|
||||||
|
while (l<576) {
|
||||||
|
xr[0][0][l]=0;
|
||||||
|
l++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* antialiasing butterflies ****************************************************
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void alias_reduction(int ch)
|
||||||
|
{
|
||||||
|
unsigned int sb;
|
||||||
|
|
||||||
|
for (sb=1;sb<32;sb++) {
|
||||||
|
float *x = xr[ch][sb];
|
||||||
|
register float a, b;
|
||||||
|
|
||||||
|
a = x[0];
|
||||||
|
b = x[-1];
|
||||||
|
x[-1] = b * Cs[0] - a * Ca[0];
|
||||||
|
x[0] = a * Cs[0] + b * Ca[0];
|
||||||
|
|
||||||
|
a = x[1];
|
||||||
|
b = x[-2];
|
||||||
|
x[-2] = b * Cs[1] - a * Ca[1];
|
||||||
|
x[1] = a * Cs[1] + b * Ca[1];
|
||||||
|
|
||||||
|
a = x[2];
|
||||||
|
b = x[-3];
|
||||||
|
x[-3] = b * Cs[2] - a * Ca[2];
|
||||||
|
x[2] = a * Cs[2] + b * Ca[2];
|
||||||
|
|
||||||
|
a = x[3];
|
||||||
|
b = x[-4];
|
||||||
|
x[-4] = b * Cs[3] - a * Ca[3];
|
||||||
|
x[3] = a * Cs[3] + b * Ca[3];
|
||||||
|
|
||||||
|
a = x[4];
|
||||||
|
b = x[-5];
|
||||||
|
x[-5] = b * Cs[4] - a * Ca[4];
|
||||||
|
x[4] = a * Cs[4] + b * Ca[4];
|
||||||
|
|
||||||
|
a = x[5];
|
||||||
|
b = x[-6];
|
||||||
|
x[-6] = b * Cs[5] - a * Ca[5];
|
||||||
|
x[5] = a * Cs[5] + b * Ca[5];
|
||||||
|
|
||||||
|
a = x[6];
|
||||||
|
b = x[-7];
|
||||||
|
x[-7] = b * Cs[6] - a * Ca[6];
|
||||||
|
x[6] = a * Cs[6] + b * Ca[6];
|
||||||
|
|
||||||
|
a = x[7];
|
||||||
|
b = x[-8];
|
||||||
|
x[-8] = b * Cs[7] - a * Ca[7];
|
||||||
|
x[7] = a * Cs[7] + b * Ca[7];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* calculating t_43 instead of having that big table in misc2.h
|
||||||
|
*/
|
||||||
|
|
||||||
|
void calculate_t43(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i=0;i<8192;i++)
|
||||||
|
t_43[i]=(float)pow((float)i,1.33333333333f);
|
||||||
|
}
|
253
Src/Sound/MPEG/misc2.h
Normal file
253
Src/Sound/MPEG/misc2.h
Normal file
|
@ -0,0 +1,253 @@
|
||||||
|
/* this file is a part of amp software, (C) tomislav uzelac 1996,1997
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* misc2.h
|
||||||
|
*
|
||||||
|
* Created by: tomislav uzelac May 1996
|
||||||
|
* Last modified by: tomislav uzelac Jan 8 1997
|
||||||
|
*/
|
||||||
|
|
||||||
|
extern void requantize_mono(int gr,int ch,struct SIDE_INFO *info,struct AUDIO_HEADER *header);
|
||||||
|
extern void requantize_ms(int gr,struct SIDE_INFO *info,struct AUDIO_HEADER *header);
|
||||||
|
extern void alias_reduction(int ch);
|
||||||
|
extern void calculate_t43(void);
|
||||||
|
|
||||||
|
extern int no_of_imdcts[2];
|
||||||
|
|
||||||
|
#ifdef MISC2
|
||||||
|
|
||||||
|
#define i_sq2 0.707106781188
|
||||||
|
#define IS_ILLEGAL 0xfeed
|
||||||
|
|
||||||
|
void requantize_mono(int gr,int ch,struct SIDE_INFO *info,struct AUDIO_HEADER *header);
|
||||||
|
void requantize_ms(int gr,struct SIDE_INFO *info,struct AUDIO_HEADER *header);
|
||||||
|
void alias_reduction(int ch);
|
||||||
|
|
||||||
|
static inline float fras_l(int sfb,int global_gain,int scalefac_scale,int scalefac,int preflag);
|
||||||
|
static inline float fras_s(int global_gain,int subblock_gain,int scalefac_scale,int scalefac);
|
||||||
|
static inline float fras2(int is,float a);
|
||||||
|
static int find_isbound(int isbound[3],int gr,struct SIDE_INFO *info,struct AUDIO_HEADER *header);
|
||||||
|
static inline void stereo_s(int l,float a[2],int pos,int ms_flag,int is_pos,struct AUDIO_HEADER *header);
|
||||||
|
static inline void stereo_l(int l,float a[2],int ms_flag,int is_pos,struct AUDIO_HEADER *header);
|
||||||
|
|
||||||
|
int no_of_imdcts[2];
|
||||||
|
|
||||||
|
static const int t_pretab[22]={0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,2,2,3,3,3,2,0};
|
||||||
|
static const float t_is[7]={ 1.0f, 0.788675134596f, 0.633974596215f,
|
||||||
|
0.5f, 0.366025403784f, 0.211324865405f, 0.0f};
|
||||||
|
static const float t_is2[2][32]={
|
||||||
|
{ 1.0f, 0.840896f, 0.707107f, 0.594604f, 0.5f, 0.420448f,
|
||||||
|
0.353553f, 0.297302f, 0.25f, 0.210224f, 0.176777f, 0.148651f,
|
||||||
|
0.125f, 0.105112f, 0.0883883f, 0.0743254f},
|
||||||
|
{ 1.0f, 0.707107f, 0.5f, 0.353553f, 0.25f, 0.176777f,
|
||||||
|
0.125f, 0.0883883f, 0.0625f, 0.0441942f, 0.03125f, 0.0220971f,
|
||||||
|
0.015625f, 0.0110485f, 0.0078125f, 0.00552427f}
|
||||||
|
};
|
||||||
|
static const float t_downmix[2][32]={
|
||||||
|
{ 1.000000f, 0.920448f, 0.853554f, 0.797302f, 0.750000f, 0.710224f,
|
||||||
|
0.676776f, 0.648651f, 0.625000f, 0.605112f, 0.588389f, 0.574326f,
|
||||||
|
0.562500f, 0.552556f, 0.544194f, 0.537163f},
|
||||||
|
{ 1.000000f, 0.853554f, 0.750000f, 0.676776f, 0.625000f, 0.588389f,
|
||||||
|
0.562500f, 0.544194f, 0.531250f, 0.522097f, 0.515625f, 0.511049f,
|
||||||
|
0.507813f, 0.505524f, 0.503906f, 0.502762f}
|
||||||
|
};
|
||||||
|
|
||||||
|
static const float Cs[8]={0.857492925712f, 0.881741997318f, 0.949628649103f,
|
||||||
|
0.983314592492f, 0.995517816065f, 0.999160558175f,
|
||||||
|
0.999899195243f, 0.999993155067f};
|
||||||
|
static const float Ca[8]={-0.5144957554270f, -0.4717319685650f, -0.3133774542040f,
|
||||||
|
-0.1819131996110f, -0.0945741925262f, -0.0409655828852f,
|
||||||
|
-0.0141985685725f, -0.00369997467375f};
|
||||||
|
static const float tab[4]={1.0f,1.189207115f,1.414213562f,1.6817928301f};
|
||||||
|
static const float tabi[4]={1.0f,0.840896415f,0.707106781f,0.594603557f};
|
||||||
|
|
||||||
|
static float t_43[8192];
|
||||||
|
|
||||||
|
|
||||||
|
/* leftmost index denotes header->ID, so first three are for MPEG2
|
||||||
|
* and the others are for MPEG1
|
||||||
|
*/
|
||||||
|
static const short t_reorder[2][3][576]={{
|
||||||
|
{ 0, 1, 2, 3, 6, 7, 8, 9, 12, 13, 14, 15, 4, 5, 18, 19, 10, 11, 24, 25,
|
||||||
|
16, 17, 30, 31, 20, 21, 22, 23, 26, 27, 28, 29, 32, 33, 34, 35, 36, 37, 38, 39,
|
||||||
|
40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
|
||||||
|
60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 90, 91,
|
||||||
|
78, 79, 80, 81, 82, 83, 96, 97, 84, 85, 86, 87, 88, 89, 102, 103, 92, 93, 94, 95,
|
||||||
|
108, 109, 110, 111, 112, 113, 98, 99, 100, 101, 114, 115, 116, 117, 118, 119, 104, 105, 106, 107,
|
||||||
|
120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 144, 145, 146, 147, 148, 149, 162, 163,
|
||||||
|
132, 133, 134, 135, 136, 137, 150, 151, 152, 153, 154, 155, 168, 169, 138, 139, 140, 141, 142, 143,
|
||||||
|
156, 157, 158, 159, 160, 161, 174, 175, 164, 165, 166, 167, 180, 181, 182, 183, 184, 185, 198, 199,
|
||||||
|
200, 201, 202, 203, 216, 217, 170, 171, 172, 173, 186, 187, 188, 189, 190, 191, 204, 205, 206, 207,
|
||||||
|
208, 209, 222, 223, 176, 177, 178, 179, 192, 193, 194, 195, 196, 197, 210, 211, 212, 213, 214, 215,
|
||||||
|
228, 229, 218, 219, 220, 221, 234, 235, 236, 237, 238, 239, 252, 253, 254, 255, 256, 257, 270, 271,
|
||||||
|
272, 273, 274, 275, 288, 289, 290, 291, 224, 225, 226, 227, 240, 241, 242, 243, 244, 245, 258, 259,
|
||||||
|
260, 261, 262, 263, 276, 277, 278, 279, 280, 281, 294, 295, 296, 297, 230, 231, 232, 233, 246, 247,
|
||||||
|
248, 249, 250, 251, 264, 265, 266, 267, 268, 269, 282, 283, 284, 285, 286, 287, 300, 301, 302, 303,
|
||||||
|
292, 293, 306, 307, 308, 309, 310, 311, 324, 325, 326, 327, 328, 329, 342, 343, 344, 345, 346, 347,
|
||||||
|
360, 361, 362, 363, 364, 365, 378, 379, 380, 381, 382, 383, 298, 299, 312, 313, 314, 315, 316, 317,
|
||||||
|
330, 331, 332, 333, 334, 335, 348, 349, 350, 351, 352, 353, 366, 367, 368, 369, 370, 371, 384, 385,
|
||||||
|
386, 387, 388, 389, 304, 305, 318, 319, 320, 321, 322, 323, 336, 337, 338, 339, 340, 341, 354, 355,
|
||||||
|
356, 357, 358, 359, 372, 373, 374, 375, 376, 377, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399,
|
||||||
|
400, 401, 414, 415, 416, 417, 418, 419, 432, 433, 434, 435, 436, 437, 450, 451, 452, 453, 454, 455,
|
||||||
|
468, 469, 470, 471, 472, 473, 486, 487, 488, 489, 490, 491, 504, 505, 506, 507, 508, 509, 402, 403,
|
||||||
|
404, 405, 406, 407, 420, 421, 422, 423, 424, 425, 438, 439, 440, 441, 442, 443, 456, 457, 458, 459,
|
||||||
|
460, 461, 474, 475, 476, 477, 478, 479, 492, 493, 494, 495, 496, 497, 510, 511, 512, 513, 514, 515,
|
||||||
|
408, 409, 410, 411, 412, 413, 426, 427, 428, 429, 430, 431, 444, 445, 446, 447, 448, 449, 462, 463,
|
||||||
|
464, 465, 466, 467, 480, 481, 482, 483, 484, 485, 498, 499, 500, 501, 502, 503, 516, 517, 518, 519,
|
||||||
|
520, 521, 522, 523, 524, 525, 526, 527, 540, 541, 542, 543, 544, 545, 558, 559, 560, 561, 562, 563,
|
||||||
|
528, 529, 530, 531, 532, 533, 546, 547, 548, 549, 550, 551, 564, 565, 566, 567, 568, 569, 534, 535,
|
||||||
|
536, 537, 538, 539, 552, 553, 554, 555, 556, 557, 570, 571, 572, 573, 574, 575},
|
||||||
|
|
||||||
|
{ 0, 1, 2, 3, 6, 7, 8, 9, 12, 13, 14, 15, 4, 5, 18, 19, 10, 11, 24, 25,
|
||||||
|
16, 17, 30, 31, 20, 21, 22, 23, 26, 27, 28, 29, 32, 33, 34, 35, 36, 37, 38, 39,
|
||||||
|
40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
|
||||||
|
72, 73, 60, 61, 62, 63, 64, 65, 78, 79, 66, 67, 68, 69, 70, 71, 84, 85, 74, 75,
|
||||||
|
76, 77, 90, 91, 92, 93, 94, 95, 80, 81, 82, 83, 96, 97, 98, 99, 100, 101, 86, 87,
|
||||||
|
88, 89, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 126, 127, 128, 129, 130, 131,
|
||||||
|
114, 115, 116, 117, 118, 119, 132, 133, 134, 135, 136, 137, 120, 121, 122, 123, 124, 125, 138, 139,
|
||||||
|
140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 162, 163, 164, 165, 166, 167, 180, 181, 150, 151,
|
||||||
|
152, 153, 154, 155, 168, 169, 170, 171, 172, 173, 186, 187, 156, 157, 158, 159, 160, 161, 174, 175,
|
||||||
|
176, 177, 178, 179, 192, 193, 182, 183, 184, 185, 198, 199, 200, 201, 202, 203, 216, 217, 218, 219,
|
||||||
|
220, 221, 234, 235, 188, 189, 190, 191, 204, 205, 206, 207, 208, 209, 222, 223, 224, 225, 226, 227,
|
||||||
|
240, 241, 194, 195, 196, 197, 210, 211, 212, 213, 214, 215, 228, 229, 230, 231, 232, 233, 246, 247,
|
||||||
|
236, 237, 238, 239, 252, 253, 254, 255, 256, 257, 270, 271, 272, 273, 274, 275, 288, 289, 290, 291,
|
||||||
|
292, 293, 306, 307, 242, 243, 244, 245, 258, 259, 260, 261, 262, 263, 276, 277, 278, 279, 280, 281,
|
||||||
|
294, 295, 296, 297, 298, 299, 312, 313, 248, 249, 250, 251, 264, 265, 266, 267, 268, 269, 282, 283,
|
||||||
|
284, 285, 286, 287, 300, 301, 302, 303, 304, 305, 318, 319, 308, 309, 310, 311, 324, 325, 326, 327,
|
||||||
|
328, 329, 342, 343, 344, 345, 346, 347, 360, 361, 362, 363, 364, 365, 378, 379, 380, 381, 382, 383,
|
||||||
|
396, 397, 398, 399, 314, 315, 316, 317, 330, 331, 332, 333, 334, 335, 348, 349, 350, 351, 352, 353,
|
||||||
|
366, 367, 368, 369, 370, 371, 384, 385, 386, 387, 388, 389, 402, 403, 404, 405, 320, 321, 322, 323,
|
||||||
|
336, 337, 338, 339, 340, 341, 354, 355, 356, 357, 358, 359, 372, 373, 374, 375, 376, 377, 390, 391,
|
||||||
|
392, 393, 394, 395, 408, 409, 410, 411, 400, 401, 414, 415, 416, 417, 418, 419, 432, 433, 434, 435,
|
||||||
|
436, 437, 450, 451, 452, 453, 454, 455, 468, 469, 470, 471, 472, 473, 486, 487, 488, 489, 490, 491,
|
||||||
|
504, 505, 506, 507, 508, 509, 522, 523, 524, 525, 526, 527, 406, 407, 420, 421, 422, 423, 424, 425,
|
||||||
|
438, 439, 440, 441, 442, 443, 456, 457, 458, 459, 460, 461, 474, 475, 476, 477, 478, 479, 492, 493,
|
||||||
|
494, 495, 496, 497, 510, 511, 512, 513, 514, 515, 528, 529, 530, 531, 532, 533, 412, 413, 426, 427,
|
||||||
|
428, 429, 430, 431, 444, 445, 446, 447, 448, 449, 462, 463, 464, 465, 466, 467, 480, 481, 482, 483,
|
||||||
|
484, 485, 498, 499, 500, 501, 502, 503, 516, 517, 518, 519, 520, 521, 534, 535, 536, 537, 538, 539,
|
||||||
|
540, 541, 542, 543, 544, 545, 558, 559, 560, 561, 562, 563, 546, 547, 548, 549, 550, 551, 564, 565,
|
||||||
|
566, 567, 568, 569, 552, 553, 554, 555, 556, 557, 570, 571, 572, 573, 574, 575},
|
||||||
|
|
||||||
|
{ 0, 1, 2, 3, 6, 7, 8, 9, 12, 13, 14, 15, 4, 5, 18, 19, 10, 11, 24, 25,
|
||||||
|
16, 17, 30, 31, 20, 21, 22, 23, 26, 27, 28, 29, 32, 33, 34, 35, 36, 37, 38, 39,
|
||||||
|
40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
|
||||||
|
72, 73, 60, 61, 62, 63, 64, 65, 78, 79, 66, 67, 68, 69, 70, 71, 84, 85, 74, 75,
|
||||||
|
76, 77, 90, 91, 92, 93, 94, 95, 80, 81, 82, 83, 96, 97, 98, 99, 100, 101, 86, 87,
|
||||||
|
88, 89, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 126, 127, 128, 129, 130, 131,
|
||||||
|
114, 115, 116, 117, 118, 119, 132, 133, 134, 135, 136, 137, 120, 121, 122, 123, 124, 125, 138, 139,
|
||||||
|
140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 162, 163, 164, 165, 166, 167, 180, 181, 150, 151,
|
||||||
|
152, 153, 154, 155, 168, 169, 170, 171, 172, 173, 186, 187, 156, 157, 158, 159, 160, 161, 174, 175,
|
||||||
|
176, 177, 178, 179, 192, 193, 182, 183, 184, 185, 198, 199, 200, 201, 202, 203, 216, 217, 218, 219,
|
||||||
|
220, 221, 234, 235, 188, 189, 190, 191, 204, 205, 206, 207, 208, 209, 222, 223, 224, 225, 226, 227,
|
||||||
|
240, 241, 194, 195, 196, 197, 210, 211, 212, 213, 214, 215, 228, 229, 230, 231, 232, 233, 246, 247,
|
||||||
|
236, 237, 238, 239, 252, 253, 254, 255, 256, 257, 270, 271, 272, 273, 274, 275, 288, 289, 290, 291,
|
||||||
|
292, 293, 306, 307, 242, 243, 244, 245, 258, 259, 260, 261, 262, 263, 276, 277, 278, 279, 280, 281,
|
||||||
|
294, 295, 296, 297, 298, 299, 312, 313, 248, 249, 250, 251, 264, 265, 266, 267, 268, 269, 282, 283,
|
||||||
|
284, 285, 286, 287, 300, 301, 302, 303, 304, 305, 318, 319, 308, 309, 310, 311, 324, 325, 326, 327,
|
||||||
|
328, 329, 342, 343, 344, 345, 346, 347, 360, 361, 362, 363, 364, 365, 378, 379, 380, 381, 382, 383,
|
||||||
|
396, 397, 314, 315, 316, 317, 330, 331, 332, 333, 334, 335, 348, 349, 350, 351, 352, 353, 366, 367,
|
||||||
|
368, 369, 370, 371, 384, 385, 386, 387, 388, 389, 402, 403, 320, 321, 322, 323, 336, 337, 338, 339,
|
||||||
|
340, 341, 354, 355, 356, 357, 358, 359, 372, 373, 374, 375, 376, 377, 390, 391, 392, 393, 394, 395,
|
||||||
|
408, 409, 398, 399, 400, 401, 414, 415, 416, 417, 418, 419, 432, 433, 434, 435, 436, 437, 450, 451,
|
||||||
|
452, 453, 454, 455, 468, 469, 470, 471, 472, 473, 486, 487, 488, 489, 490, 491, 504, 505, 506, 507,
|
||||||
|
508, 509, 404, 405, 406, 407, 420, 421, 422, 423, 424, 425, 438, 439, 440, 441, 442, 443, 456, 457,
|
||||||
|
458, 459, 460, 461, 474, 475, 476, 477, 478, 479, 492, 493, 494, 495, 496, 497, 510, 511, 512, 513,
|
||||||
|
514, 515, 410, 411, 412, 413, 426, 427, 428, 429, 430, 431, 444, 445, 446, 447, 448, 449, 462, 463,
|
||||||
|
464, 465, 466, 467, 480, 481, 482, 483, 484, 485, 498, 499, 500, 501, 502, 503, 516, 517, 518, 519,
|
||||||
|
520, 521, 522, 523, 524, 525, 526, 527, 540, 541, 542, 543, 544, 545, 558, 559, 560, 561, 562, 563,
|
||||||
|
528, 529, 530, 531, 532, 533, 546, 547, 548, 549, 550, 551, 564, 565, 566, 567, 568, 569, 534, 535,
|
||||||
|
536, 537, 538, 539, 552, 553, 554, 555, 556, 557, 570, 571, 572, 573, 574, 575}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{ 0, 1, 2, 3, 6, 7, 8, 9, 12, 13, 14, 15, 4, 5, 18, 19, 10, 11, 24, 25,
|
||||||
|
16, 17, 30, 31, 20, 21, 22, 23, 26, 27, 28, 29, 32, 33, 34, 35, 36, 37, 38, 39,
|
||||||
|
42, 43, 44, 45, 48, 49, 50, 51, 40, 41, 54, 55, 56, 57, 46, 47, 60, 61, 62, 63,
|
||||||
|
52, 53, 66, 67, 68, 69, 58, 59, 72, 73, 74, 75, 76, 77, 64, 65, 78, 79, 80, 81,
|
||||||
|
82, 83, 70, 71, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 108, 109, 110, 111,
|
||||||
|
96, 97, 98, 99, 100, 101, 114, 115, 116, 117, 102, 103, 104, 105, 106, 107, 120, 121, 122, 123,
|
||||||
|
112, 113, 126, 127, 128, 129, 130, 131, 144, 145, 146, 147, 118, 119, 132, 133, 134, 135, 136, 137,
|
||||||
|
150, 151, 152, 153, 124, 125, 138, 139, 140, 141, 142, 143, 156, 157, 158, 159, 148, 149, 162, 163,
|
||||||
|
164, 165, 166, 167, 180, 181, 182, 183, 184, 185, 154, 155, 168, 169, 170, 171, 172, 173, 186, 187,
|
||||||
|
188, 189, 190, 191, 160, 161, 174, 175, 176, 177, 178, 179, 192, 193, 194, 195, 196, 197, 198, 199,
|
||||||
|
200, 201, 202, 203, 216, 217, 218, 219, 220, 221, 234, 235, 236, 237, 238, 239, 204, 205, 206, 207,
|
||||||
|
208, 209, 222, 223, 224, 225, 226, 227, 240, 241, 242, 243, 244, 245, 210, 211, 212, 213, 214, 215,
|
||||||
|
228, 229, 230, 231, 232, 233, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 270, 271,
|
||||||
|
272, 273, 274, 275, 288, 289, 290, 291, 292, 293, 306, 307, 308, 309, 258, 259, 260, 261, 262, 263,
|
||||||
|
276, 277, 278, 279, 280, 281, 294, 295, 296, 297, 298, 299, 312, 313, 314, 315, 264, 265, 266, 267,
|
||||||
|
268, 269, 282, 283, 284, 285, 286, 287, 300, 301, 302, 303, 304, 305, 318, 319, 320, 321, 310, 311,
|
||||||
|
324, 325, 326, 327, 328, 329, 342, 343, 344, 345, 346, 347, 360, 361, 362, 363, 364, 365, 378, 379,
|
||||||
|
380, 381, 382, 383, 396, 397, 398, 399, 316, 317, 330, 331, 332, 333, 334, 335, 348, 349, 350, 351,
|
||||||
|
352, 353, 366, 367, 368, 369, 370, 371, 384, 385, 386, 387, 388, 389, 402, 403, 404, 405, 322, 323,
|
||||||
|
336, 337, 338, 339, 340, 341, 354, 355, 356, 357, 358, 359, 372, 373, 374, 375, 376, 377, 390, 391,
|
||||||
|
392, 393, 394, 395, 408, 409, 410, 411, 400, 401, 414, 415, 416, 417, 418, 419, 432, 433, 434, 435,
|
||||||
|
436, 437, 450, 451, 452, 453, 454, 455, 468, 469, 470, 471, 472, 473, 486, 487, 488, 489, 490, 491,
|
||||||
|
504, 505, 506, 507, 508, 509, 522, 523, 524, 525, 526, 527, 540, 541, 542, 543, 544, 545, 558, 559,
|
||||||
|
560, 561, 562, 563, 406, 407, 420, 421, 422, 423, 424, 425, 438, 439, 440, 441, 442, 443, 456, 457,
|
||||||
|
458, 459, 460, 461, 474, 475, 476, 477, 478, 479, 492, 493, 494, 495, 496, 497, 510, 511, 512, 513,
|
||||||
|
514, 515, 528, 529, 530, 531, 532, 533, 546, 547, 548, 549, 550, 551, 564, 565, 566, 567, 568, 569,
|
||||||
|
412, 413, 426, 427, 428, 429, 430, 431, 444, 445, 446, 447, 448, 449, 462, 463, 464, 465, 466, 467,
|
||||||
|
480, 481, 482, 483, 484, 485, 498, 499, 500, 501, 502, 503, 516, 517, 518, 519, 520, 521, 534, 535,
|
||||||
|
536, 537, 538, 539, 552, 553, 554, 555, 556, 557, 570, 571, 572, 573, 574, 575},
|
||||||
|
|
||||||
|
{ 0, 1, 2, 3, 6, 7, 8, 9, 12, 13, 14, 15, 4, 5, 18, 19, 10, 11, 24, 25,
|
||||||
|
16, 17, 30, 31, 20, 21, 22, 23, 26, 27, 28, 29, 32, 33, 34, 35, 36, 37, 38, 39,
|
||||||
|
42, 43, 44, 45, 48, 49, 50, 51, 40, 41, 54, 55, 56, 57, 46, 47, 60, 61, 62, 63,
|
||||||
|
52, 53, 66, 67, 68, 69, 58, 59, 72, 73, 74, 75, 64, 65, 78, 79, 80, 81, 70, 71,
|
||||||
|
84, 85, 86, 87, 76, 77, 90, 91, 92, 93, 94, 95, 108, 109, 82, 83, 96, 97, 98, 99,
|
||||||
|
100, 101, 114, 115, 88, 89, 102, 103, 104, 105, 106, 107, 120, 121, 110, 111, 112, 113, 126, 127,
|
||||||
|
128, 129, 130, 131, 144, 145, 116, 117, 118, 119, 132, 133, 134, 135, 136, 137, 150, 151, 122, 123,
|
||||||
|
124, 125, 138, 139, 140, 141, 142, 143, 156, 157, 146, 147, 148, 149, 162, 163, 164, 165, 166, 167,
|
||||||
|
180, 181, 182, 183, 152, 153, 154, 155, 168, 169, 170, 171, 172, 173, 186, 187, 188, 189, 158, 159,
|
||||||
|
160, 161, 174, 175, 176, 177, 178, 179, 192, 193, 194, 195, 184, 185, 198, 199, 200, 201, 202, 203,
|
||||||
|
216, 217, 218, 219, 220, 221, 234, 235, 190, 191, 204, 205, 206, 207, 208, 209, 222, 223, 224, 225,
|
||||||
|
226, 227, 240, 241, 196, 197, 210, 211, 212, 213, 214, 215, 228, 229, 230, 231, 232, 233, 246, 247,
|
||||||
|
236, 237, 238, 239, 252, 253, 254, 255, 256, 257, 270, 271, 272, 273, 274, 275, 288, 289, 290, 291,
|
||||||
|
242, 243, 244, 245, 258, 259, 260, 261, 262, 263, 276, 277, 278, 279, 280, 281, 294, 295, 296, 297,
|
||||||
|
248, 249, 250, 251, 264, 265, 266, 267, 268, 269, 282, 283, 284, 285, 286, 287, 300, 301, 302, 303,
|
||||||
|
292, 293, 306, 307, 308, 309, 310, 311, 324, 325, 326, 327, 328, 329, 342, 343, 344, 345, 346, 347,
|
||||||
|
360, 361, 362, 363, 364, 365, 298, 299, 312, 313, 314, 315, 316, 317, 330, 331, 332, 333, 334, 335,
|
||||||
|
348, 349, 350, 351, 352, 353, 366, 367, 368, 369, 370, 371, 304, 305, 318, 319, 320, 321, 322, 323,
|
||||||
|
336, 337, 338, 339, 340, 341, 354, 355, 356, 357, 358, 359, 372, 373, 374, 375, 376, 377, 378, 379,
|
||||||
|
380, 381, 382, 383, 396, 397, 398, 399, 400, 401, 414, 415, 416, 417, 418, 419, 432, 433, 434, 435,
|
||||||
|
436, 437, 450, 451, 452, 453, 454, 455, 468, 469, 470, 471, 472, 473, 486, 487, 488, 489, 490, 491,
|
||||||
|
504, 505, 506, 507, 508, 509, 522, 523, 524, 525, 526, 527, 540, 541, 542, 543, 544, 545, 558, 559,
|
||||||
|
560, 561, 562, 563, 384, 385, 386, 387, 388, 389, 402, 403, 404, 405, 406, 407, 420, 421, 422, 423,
|
||||||
|
424, 425, 438, 439, 440, 441, 442, 443, 456, 457, 458, 459, 460, 461, 474, 475, 476, 477, 478, 479,
|
||||||
|
492, 493, 494, 495, 496, 497, 510, 511, 512, 513, 514, 515, 528, 529, 530, 531, 532, 533, 546, 547,
|
||||||
|
548, 549, 550, 551, 564, 565, 566, 567, 568, 569, 390, 391, 392, 393, 394, 395, 408, 409, 410, 411,
|
||||||
|
412, 413, 426, 427, 428, 429, 430, 431, 444, 445, 446, 447, 448, 449, 462, 463, 464, 465, 466, 467,
|
||||||
|
480, 481, 482, 483, 484, 485, 498, 499, 500, 501, 502, 503, 516, 517, 518, 519, 520, 521, 534, 535,
|
||||||
|
536, 537, 538, 539, 552, 553, 554, 555, 556, 557, 570, 571, 572, 573, 574, 575},
|
||||||
|
|
||||||
|
{ 0, 1, 2, 3, 6, 7, 8, 9, 12, 13, 14, 15, 4, 5, 18, 19, 10, 11, 24, 25,
|
||||||
|
16, 17, 30, 31, 20, 21, 22, 23, 26, 27, 28, 29, 32, 33, 34, 35, 36, 37, 38, 39,
|
||||||
|
42, 43, 44, 45, 48, 49, 50, 51, 40, 41, 54, 55, 56, 57, 46, 47, 60, 61, 62, 63,
|
||||||
|
52, 53, 66, 67, 68, 69, 58, 59, 72, 73, 74, 75, 76, 77, 64, 65, 78, 79, 80, 81,
|
||||||
|
82, 83, 70, 71, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 108, 109, 110, 111,
|
||||||
|
112, 113, 96, 97, 98, 99, 100, 101, 114, 115, 116, 117, 118, 119, 102, 103, 104, 105, 106, 107,
|
||||||
|
120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 144, 145, 146, 147, 148, 149, 162, 163,
|
||||||
|
164, 165, 132, 133, 134, 135, 136, 137, 150, 151, 152, 153, 154, 155, 168, 169, 170, 171, 138, 139,
|
||||||
|
140, 141, 142, 143, 156, 157, 158, 159, 160, 161, 174, 175, 176, 177, 166, 167, 180, 181, 182, 183,
|
||||||
|
184, 185, 198, 199, 200, 201, 202, 203, 216, 217, 218, 219, 220, 221, 172, 173, 186, 187, 188, 189,
|
||||||
|
190, 191, 204, 205, 206, 207, 208, 209, 222, 223, 224, 225, 226, 227, 178, 179, 192, 193, 194, 195,
|
||||||
|
196, 197, 210, 211, 212, 213, 214, 215, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
|
||||||
|
252, 253, 254, 255, 256, 257, 270, 271, 272, 273, 274, 275, 288, 289, 290, 291, 292, 293, 306, 307,
|
||||||
|
240, 241, 242, 243, 244, 245, 258, 259, 260, 261, 262, 263, 276, 277, 278, 279, 280, 281, 294, 295,
|
||||||
|
296, 297, 298, 299, 312, 313, 246, 247, 248, 249, 250, 251, 264, 265, 266, 267, 268, 269, 282, 283,
|
||||||
|
284, 285, 286, 287, 300, 301, 302, 303, 304, 305, 318, 319, 308, 309, 310, 311, 324, 325, 326, 327,
|
||||||
|
328, 329, 342, 343, 344, 345, 346, 347, 360, 361, 362, 363, 364, 365, 378, 379, 380, 381, 382, 383,
|
||||||
|
396, 397, 398, 399, 400, 401, 314, 315, 316, 317, 330, 331, 332, 333, 334, 335, 348, 349, 350, 351,
|
||||||
|
352, 353, 366, 367, 368, 369, 370, 371, 384, 385, 386, 387, 388, 389, 402, 403, 404, 405, 406, 407,
|
||||||
|
320, 321, 322, 323, 336, 337, 338, 339, 340, 341, 354, 355, 356, 357, 358, 359, 372, 373, 374, 375,
|
||||||
|
376, 377, 390, 391, 392, 393, 394, 395, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419,
|
||||||
|
432, 433, 434, 435, 436, 437, 450, 451, 452, 453, 454, 455, 468, 469, 470, 471, 472, 473, 486, 487,
|
||||||
|
488, 489, 490, 491, 504, 505, 506, 507, 508, 509, 522, 523, 524, 525, 526, 527, 420, 421, 422, 423,
|
||||||
|
424, 425, 438, 439, 440, 441, 442, 443, 456, 457, 458, 459, 460, 461, 474, 475, 476, 477, 478, 479,
|
||||||
|
492, 493, 494, 495, 496, 497, 510, 511, 512, 513, 514, 515, 528, 529, 530, 531, 532, 533, 426, 427,
|
||||||
|
428, 429, 430, 431, 444, 445, 446, 447, 448, 449, 462, 463, 464, 465, 466, 467, 480, 481, 482, 483,
|
||||||
|
484, 485, 498, 499, 500, 501, 502, 503, 516, 517, 518, 519, 520, 521, 534, 535, 536, 537, 538, 539,
|
||||||
|
540, 541, 542, 543, 544, 545, 558, 559, 560, 561, 562, 563, 546, 547, 548, 549, 550, 551, 564, 565,
|
||||||
|
566, 567, 568, 569, 552, 553, 554, 555, 556, 557, 570, 571, 572, 573, 574, 575}
|
||||||
|
}};
|
||||||
|
|
||||||
|
#endif
|
103
Src/Sound/MPEG/position.cpp
Normal file
103
Src/Sound/MPEG/position.cpp
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
/* this file is a part of amp software, (C) tomislav uzelac 1996,1997
|
||||||
|
*/
|
||||||
|
/* position.c ffwd/rew within a stream
|
||||||
|
*
|
||||||
|
* Creted by: Tomislav Uzelac, May 10 1997
|
||||||
|
*/
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "amp.h"
|
||||||
|
#include "audio.h"
|
||||||
|
#include "getbits.h"
|
||||||
|
|
||||||
|
#define POSITION
|
||||||
|
#include "position.h"
|
||||||
|
|
||||||
|
/* Returns the number of frames actually skipped, -1 on error.
|
||||||
|
*
|
||||||
|
* Values in header are not changed if retval!=nframes.
|
||||||
|
* This is not necessary because gethdr() doesn't clobber
|
||||||
|
* the contents of header, but I don't want to rely on that.
|
||||||
|
*/
|
||||||
|
int ffwd(struct AUDIO_HEADER *header, int nframes)
|
||||||
|
{
|
||||||
|
int cnt=0,g;
|
||||||
|
int hsize,bitrate,fs,mean_frame_size;
|
||||||
|
struct AUDIO_HEADER tmp;
|
||||||
|
memcpy(&tmp,header,sizeof(tmp));
|
||||||
|
|
||||||
|
while (cnt < nframes) {
|
||||||
|
if (tmp.ID)
|
||||||
|
if (tmp.mode==3) hsize=21;
|
||||||
|
else hsize=36;
|
||||||
|
else
|
||||||
|
if (tmp.mode==3) hsize=13;
|
||||||
|
else hsize=21;
|
||||||
|
if (tmp.protection_bit==0) hsize+=2;
|
||||||
|
if ((g=dummy_getinfo(hsize))) /* dummy_getinfo: reads hsize-4 bytes */
|
||||||
|
switch (g) {
|
||||||
|
case GETHDR_EOF: return cnt;
|
||||||
|
case GETHDR_ERR:
|
||||||
|
default: return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bitrate=t_bitrate[tmp.ID][3-tmp.layer][tmp.bitrate_index];
|
||||||
|
fs=t_sampling_frequency[tmp.ID][tmp.sampling_frequency];
|
||||||
|
if (tmp.ID) mean_frame_size=144000*bitrate/fs;
|
||||||
|
else mean_frame_size=72000*bitrate/fs;
|
||||||
|
fillbfr(mean_frame_size + tmp.padding_bit - hsize);
|
||||||
|
|
||||||
|
if ((g=gethdr(&tmp)))
|
||||||
|
switch (g) {
|
||||||
|
case GETHDR_EOF: return cnt;
|
||||||
|
case GETHDR_ERR:
|
||||||
|
default: return -1;
|
||||||
|
}
|
||||||
|
cnt++;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(header,&tmp,sizeof(tmp));
|
||||||
|
return cnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Mostly the same as ffwd. Some streams might be 'tough', i.e.
|
||||||
|
* the ones switching bitrates.
|
||||||
|
*/
|
||||||
|
int rew(struct AUDIO_HEADER *header, int nframes)
|
||||||
|
{
|
||||||
|
int cnt=0;
|
||||||
|
int bitrate,fs,mean_frame_size;
|
||||||
|
struct AUDIO_HEADER tmp;
|
||||||
|
memcpy(&tmp,header,sizeof(tmp));
|
||||||
|
|
||||||
|
while (cnt < nframes) {
|
||||||
|
/* ffwd/rew functions are to be called right after the header has been parsed
|
||||||
|
* so we have to go back one frame + 4 bytes + 1 byte (in case padding was used).
|
||||||
|
*/
|
||||||
|
bitrate=t_bitrate[tmp.ID][3-tmp.layer][tmp.bitrate_index];
|
||||||
|
fs=t_sampling_frequency[tmp.ID][tmp.sampling_frequency];
|
||||||
|
if (tmp.ID) mean_frame_size=144000*bitrate/fs;
|
||||||
|
else mean_frame_size=72000*bitrate/fs;
|
||||||
|
|
||||||
|
if (rewind_stream(mean_frame_size) !=0) {
|
||||||
|
memcpy(header,&tmp,sizeof(tmp));
|
||||||
|
return cnt;
|
||||||
|
}
|
||||||
|
if ((gethdr(&tmp))) return -1;
|
||||||
|
cnt++;
|
||||||
|
}
|
||||||
|
/* We have to make sure that the bit reservoir contains enough data.
|
||||||
|
* Hopefully, layer3_frame will take care of that.
|
||||||
|
*/
|
||||||
|
f_bdirty=TRUE;
|
||||||
|
bclean_bytes=0;
|
||||||
|
|
||||||
|
memcpy(header,&tmp,sizeof(tmp));
|
||||||
|
return cnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO: after the gethdr function is enhanced with the counter to count
|
||||||
|
* the number of bytes to search for the next syncword, make the call to
|
||||||
|
* gethdr() from rew() have that counter something like (frame_size-1) so
|
||||||
|
* that we don't go back again and again to the same header. (not very important)
|
||||||
|
*/
|
10
Src/Sound/MPEG/position.h
Normal file
10
Src/Sound/MPEG/position.h
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
/* this file is a part of amp software, (C) tomislav uzelac 1996,1997
|
||||||
|
*/
|
||||||
|
|
||||||
|
extern int ffwd(struct AUDIO_HEADER *header, int nframes);
|
||||||
|
extern int rew(struct AUDIO_HEADER *header, int nframes);
|
||||||
|
|
||||||
|
#ifdef POSITION
|
||||||
|
int ffwd(struct AUDIO_HEADER *header, int nframes);
|
||||||
|
int rew(struct AUDIO_HEADER *header, int nframes);
|
||||||
|
#endif
|
26
Src/Sound/MPEG/proto.h
Normal file
26
Src/Sound/MPEG/proto.h
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
/* From: util.c */
|
||||||
|
void die(char *, ...);
|
||||||
|
void warn(char *, ...);
|
||||||
|
void msg(char *, ...);
|
||||||
|
void debugSetup(char *);
|
||||||
|
void debugOptions();
|
||||||
|
|
||||||
|
/* From: audioIO_<OSTYPE>.c */
|
||||||
|
void audioOpen(int frequency, int stereo, int volume);
|
||||||
|
void audioSetVolume(int);
|
||||||
|
void audioFlush();
|
||||||
|
void audioClose();
|
||||||
|
int audioWrite(char *, int);
|
||||||
|
int getAudioFd();
|
||||||
|
void audioBufferOn(int);
|
||||||
|
|
||||||
|
|
||||||
|
/* From: buffer.c */
|
||||||
|
void printout(void);
|
||||||
|
int audioBufferOpen(int, int, int);
|
||||||
|
void audioBufferClose();
|
||||||
|
void audioBufferWrite(char *, int);
|
||||||
|
void audioBufferFlush();
|
||||||
|
|
||||||
|
/* From: audio.c */
|
||||||
|
void displayUsage();
|
63
Src/Sound/MPEG/rtbuf.h
Normal file
63
Src/Sound/MPEG/rtbuf.h
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* rtbuf.h -- Linux realtime audio output.
|
||||||
|
*
|
||||||
|
* Copyright (C) 1996 Thomas Sailer (sailer@ife.ee.ethz.ch)
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* This is the Linux realtime sound output driver
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#ifndef HAVE_MLOCKALL
|
||||||
|
#undef LINUX_REALTIME
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef HAVE_SCHED_SETSCHEDULER
|
||||||
|
#undef LINUX_REALTIME
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
#ifndef _POSIX_MEMLOCK
|
||||||
|
#undef LINUX_REALTIME
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef _POSIX_PRIORITY_SCHEDULING
|
||||||
|
#undef LINUX_REALTIME
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef LINUX_REALTIME
|
||||||
|
|
||||||
|
int prefetch_get_input(unsigned char *bp, int bytes);
|
||||||
|
int rt_play(char *file);
|
||||||
|
void rt_printout(short *sbuf, int ln);
|
||||||
|
int setup_fancy_audio(struct AUDIO_HEADER *mpegheader);
|
||||||
|
int start_fancy_audio(struct AUDIO_HEADER *mpegheader);
|
||||||
|
int stop_fancy_audio(void);
|
||||||
|
int block_fancy_audio(int snd_eof);
|
||||||
|
int ready_fancy_audio(void);
|
||||||
|
void cleanup_fancy_audio(void);
|
||||||
|
void prefetch_initial_fill(void);
|
||||||
|
int set_realtime_priority(void);
|
||||||
|
|
||||||
|
#endif /* LINUX_REALTIME */
|
||||||
|
|
1518
Src/Sound/MPEG/transform.cpp
Normal file
1518
Src/Sound/MPEG/transform.cpp
Normal file
File diff suppressed because it is too large
Load diff
168
Src/Sound/MPEG/transform.h
Normal file
168
Src/Sound/MPEG/transform.h
Normal file
|
@ -0,0 +1,168 @@
|
||||||
|
/* this file is a part of amp software, (C) tomislav uzelac 1996,1997
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* transform.h tables galore
|
||||||
|
*
|
||||||
|
* Created by: tomislav uzelac May 1996
|
||||||
|
* Last modified by: tomislav uzelac Mar 1 97
|
||||||
|
*/
|
||||||
|
extern void imdct_init();
|
||||||
|
extern void imdct(int win_type,int sb,int ch);
|
||||||
|
extern void poly(int ch,int i);
|
||||||
|
extern void premultiply();
|
||||||
|
|
||||||
|
extern short sample_buffer[18][32][2];
|
||||||
|
extern float res[32][18];
|
||||||
|
extern float s[2][32][18];
|
||||||
|
|
||||||
|
#ifdef TRANSFORM
|
||||||
|
|
||||||
|
void imdct_init();
|
||||||
|
void imdct(int win_type,int sb,int ch);
|
||||||
|
void poly(int ch,int i);
|
||||||
|
void premultiply();
|
||||||
|
|
||||||
|
short sample_buffer[18][32][2];
|
||||||
|
float s[2][32][18];
|
||||||
|
float res[32][18];
|
||||||
|
float win[4][36];
|
||||||
|
|
||||||
|
static const float t_sin[4][36]={{
|
||||||
|
-0.032160f, 0.103553f, -0.182543f, 0.266729f, -0.353554f, 0.440377f,
|
||||||
|
-0.524563f, 0.603553f, -0.674947f, 0.736575f, -0.786566f, 0.823400f,
|
||||||
|
-0.845957f, 0.853554f, -0.845957f, 0.823399f, -0.786566f, 0.736575f,
|
||||||
|
-0.674947f, 0.603553f, -0.524564f, 0.440378f, -0.353553f, 0.266729f,
|
||||||
|
-0.182544f, 0.103553f, -0.032160f, -0.029469f, 0.079459f, -0.116293f,
|
||||||
|
0.138851f, -0.146446f, 0.138851f, -0.116293f, 0.079459f, -0.029469f
|
||||||
|
},{
|
||||||
|
-0.032160f, 0.103553f, -0.182543f, 0.266729f, -0.353554f, 0.440377f,
|
||||||
|
-0.524563f, 0.603553f, -0.674947f, 0.736575f, -0.786566f, 0.823400f,
|
||||||
|
-0.845957f, 0.853554f, -0.845957f, 0.823399f, -0.786566f, 0.736575f,
|
||||||
|
-0.675590f, 0.608761f, -0.537300f, 0.461749f, -0.382683f, 0.300706f,
|
||||||
|
-0.214588f, 0.120590f, -0.034606f, -0.026554f, 0.049950f, -0.028251f,
|
||||||
|
0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f
|
||||||
|
},{
|
||||||
|
-0.103553f, 0.353554f, -0.603553f, 0.786566f, -0.853554f, 0.786566f,
|
||||||
|
-0.603553f, 0.353553f, -0.103553f, -0.079459f, 0.146446f, -0.079459f,
|
||||||
|
0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
|
||||||
|
0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
|
||||||
|
0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
|
||||||
|
0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f
|
||||||
|
},{
|
||||||
|
0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
|
||||||
|
-0.127432f, 0.379410f, -0.608182f, 0.792598f, -0.915976f, 0.967944f,
|
||||||
|
-0.953717f, 0.923880f, -0.887011f, 0.843391f, -0.793353f, 0.737277f,
|
||||||
|
-0.674947f, 0.603553f, -0.524564f, 0.440378f, -0.353553f, 0.266729f,
|
||||||
|
-0.182544f, 0.103553f, -0.032160f, -0.029469f, 0.079459f, -0.116293f,
|
||||||
|
0.138851f, -0.146446f, 0.138851f, -0.116293f, 0.079459f, -0.029469f
|
||||||
|
}};
|
||||||
|
|
||||||
|
static const float t_2cos[4][18]={
|
||||||
|
{ -0.174311f, -0.517638f, -0.845237f, -1.147153f, -1.414214f, -1.638304f, -1.812616f, -1.931852f, -1.992389f,
|
||||||
|
0.174311f, 0.517638f, 0.845237f, 1.147153f, 1.414214f, 1.638304f, 1.812616f, 1.931852f, 1.992389f},
|
||||||
|
{ -0.174311f, -0.517638f, -0.845237f, -1.147153f, -1.414214f, -1.638304f, -1.812616f, -1.931852f, -1.992389f,
|
||||||
|
0.174311f, 0.517638f, 0.845237f, 1.147153f, 1.414214f, 1.638304f, 1.812616f, 1.931852f, 1.992389f},
|
||||||
|
{ -0.517638f, -1.41421f, -1.93185f, 0.517638f, 1.41421f, 1.93185f,0,0,0,0,0,0,0,0,0,0,0,0},
|
||||||
|
{ -0.174311f, -0.517638f, -0.845237f, -1.147153f, -1.414214f, -1.638304f, -1.812616f, -1.931852f, -1.992389f,
|
||||||
|
0.174311f, 0.517638f, 0.845237f, 1.147153f, 1.414214f, 1.638304f, 1.812616f, 1.931852f, 1.992389f}
|
||||||
|
};
|
||||||
|
|
||||||
|
static const float b1 = 1.997590912f; static const float b2 = 1.990369453f; static const float b3 = 1.978353019f;
|
||||||
|
static const float b4 = 1.961570560f; static const float b5 = 1.940062506f; static const float b6 = 1.913880671f;
|
||||||
|
static const float b7 = 1.883088130f; static const float b8 = 1.847759065f; static const float b9 = 1.807978586f;
|
||||||
|
static const float b10= 1.763842529f; static const float b11= 1.715457220f; static const float b12= 1.662939225f;
|
||||||
|
static const float b13= 1.606415063f; static const float b14= 1.546020907f; static const float b15= 1.481902251f;
|
||||||
|
static const float b16= 1.414213562f; static const float b17= 1.343117910f; static const float b18= 1.268786568f;
|
||||||
|
static const float b19= 1.191398609f; static const float b20= 1.111140466f; static const float b21= 1.028205488f;
|
||||||
|
static const float b22= 0.942793474f; static const float b23= 0.855110187f; static const float b24= 0.765366865f;
|
||||||
|
static const float b25= 0.673779707f; static const float b26= 0.580569355f; static const float b27= 0.485960360f;
|
||||||
|
static const float b28= 0.390180644f; static const float b29= 0.293460949f; static const float b30= 0.196034281f;
|
||||||
|
static const float b31= 0.098135349f;
|
||||||
|
|
||||||
|
static float t_dewindow[17][32] = {{
|
||||||
|
0.000000000f,-0.000442505f, 0.003250122f,-0.007003784f, 0.031082153f,-0.078628540f, 0.100311279f,-0.572036743f,
|
||||||
|
1.144989014f, 0.572036743f, 0.100311279f, 0.078628540f, 0.031082153f, 0.007003784f, 0.003250122f, 0.000442505f,
|
||||||
|
0.000000000f,-0.000442505f, 0.003250122f,-0.007003784f, 0.031082153f,-0.078628540f, 0.100311279f,-0.572036743f,
|
||||||
|
1.144989014f, 0.572036743f, 0.100311279f, 0.078628540f, 0.031082153f, 0.007003784f, 0.003250122f, 0.000442505f,
|
||||||
|
},{
|
||||||
|
-0.000015259f,-0.000473022f, 0.003326416f,-0.007919312f, 0.030517578f,-0.084182739f, 0.090927124f,-0.600219727f,
|
||||||
|
1.144287109f, 0.543823242f, 0.108856201f, 0.073059082f, 0.031478882f, 0.006118774f, 0.003173828f, 0.000396729f,
|
||||||
|
-0.000015259f,-0.000473022f, 0.003326416f,-0.007919312f, 0.030517578f,-0.084182739f, 0.090927124f,-0.600219727f,
|
||||||
|
1.144287109f, 0.543823242f, 0.108856201f, 0.073059082f, 0.031478882f, 0.006118774f, 0.003173828f, 0.000396729f,
|
||||||
|
},{
|
||||||
|
-0.000015259f,-0.000534058f, 0.003387451f,-0.008865356f, 0.029785156f,-0.089706421f, 0.080688477f,-0.628295898f,
|
||||||
|
1.142211914f, 0.515609741f, 0.116577148f, 0.067520142f, 0.031738281f, 0.005294800f, 0.003082275f, 0.000366211f,
|
||||||
|
-0.000015259f,-0.000534058f, 0.003387451f,-0.008865356f, 0.029785156f,-0.089706421f, 0.080688477f,-0.628295898f,
|
||||||
|
1.142211914f, 0.515609741f, 0.116577148f, 0.067520142f, 0.031738281f, 0.005294800f, 0.003082275f, 0.000366211f,
|
||||||
|
},{
|
||||||
|
-0.000015259f,-0.000579834f, 0.003433228f,-0.009841919f, 0.028884888f,-0.095169067f, 0.069595337f,-0.656219482f,
|
||||||
|
1.138763428f, 0.487472534f, 0.123474121f, 0.061996460f, 0.031845093f, 0.004486084f, 0.002990723f, 0.000320435f,
|
||||||
|
-0.000015259f,-0.000579834f, 0.003433228f,-0.009841919f, 0.028884888f,-0.095169067f, 0.069595337f,-0.656219482f,
|
||||||
|
1.138763428f, 0.487472534f, 0.123474121f, 0.061996460f, 0.031845093f, 0.004486084f, 0.002990723f, 0.000320435f,
|
||||||
|
},{
|
||||||
|
-0.000015259f,-0.000625610f, 0.003463745f,-0.010848999f, 0.027801514f,-0.100540161f, 0.057617187f,-0.683914185f,
|
||||||
|
1.133926392f, 0.459472656f, 0.129577637f, 0.056533813f, 0.031814575f, 0.003723145f, 0.002899170f, 0.000289917f,
|
||||||
|
-0.000015259f,-0.000625610f, 0.003463745f,-0.010848999f, 0.027801514f,-0.100540161f, 0.057617187f,-0.683914185f,
|
||||||
|
1.133926392f, 0.459472656f, 0.129577637f, 0.056533813f, 0.031814575f, 0.003723145f, 0.002899170f, 0.000289917f,
|
||||||
|
},{
|
||||||
|
-0.000015259f,-0.000686646f, 0.003479004f,-0.011886597f, 0.026535034f,-0.105819702f, 0.044784546f,-0.711318970f,
|
||||||
|
1.127746582f, 0.431655884f, 0.134887695f, 0.051132202f, 0.031661987f, 0.003005981f, 0.002792358f, 0.000259399f,
|
||||||
|
-0.000015259f,-0.000686646f, 0.003479004f,-0.011886597f, 0.026535034f,-0.105819702f, 0.044784546f,-0.711318970f,
|
||||||
|
1.127746582f, 0.431655884f, 0.134887695f, 0.051132202f, 0.031661987f, 0.003005981f, 0.002792358f, 0.000259399f,
|
||||||
|
},{
|
||||||
|
-0.000015259f,-0.000747681f, 0.003479004f,-0.012939453f, 0.025085449f,-0.110946655f, 0.031082153f,-0.738372803f,
|
||||||
|
1.120223999f, 0.404083252f, 0.139450073f, 0.045837402f, 0.031387329f, 0.002334595f, 0.002685547f, 0.000244141f,
|
||||||
|
-0.000015259f,-0.000747681f, 0.003479004f,-0.012939453f, 0.025085449f,-0.110946655f, 0.031082153f,-0.738372803f,
|
||||||
|
1.120223999f, 0.404083252f, 0.139450073f, 0.045837402f, 0.031387329f, 0.002334595f, 0.002685547f, 0.000244141f,
|
||||||
|
},{
|
||||||
|
-0.000030518f,-0.000808716f, 0.003463745f,-0.014022827f, 0.023422241f,-0.115921021f, 0.016510010f,-0.765029907f,
|
||||||
|
1.111373901f, 0.376800537f, 0.143264771f, 0.040634155f, 0.031005859f, 0.001693726f, 0.002578735f, 0.000213623f,
|
||||||
|
-0.000030518f,-0.000808716f, 0.003463745f,-0.014022827f, 0.023422241f,-0.115921021f, 0.016510010f,-0.765029907f,
|
||||||
|
1.111373901f, 0.376800537f, 0.143264771f, 0.040634155f, 0.031005859f, 0.001693726f, 0.002578735f, 0.000213623f,
|
||||||
|
},{
|
||||||
|
-0.000030518f,-0.000885010f, 0.003417969f,-0.015121460f, 0.021575928f,-0.120697021f, 0.001068115f,-0.791213989f,
|
||||||
|
1.101211548f, 0.349868774f, 0.146362305f, 0.035552979f, 0.030532837f, 0.001098633f, 0.002456665f, 0.000198364f,
|
||||||
|
-0.000030518f,-0.000885010f, 0.003417969f,-0.015121460f, 0.021575928f,-0.120697021f, 0.001068115f,-0.791213989f,
|
||||||
|
1.101211548f, 0.349868774f, 0.146362305f, 0.035552979f, 0.030532837f, 0.001098633f, 0.002456665f, 0.000198364f,
|
||||||
|
},{
|
||||||
|
-0.000030518f,-0.000961304f, 0.003372192f,-0.016235352f, 0.019531250f,-0.125259399f,-0.015228271f,-0.816864014f,
|
||||||
|
1.089782715f, 0.323318481f, 0.148773193f, 0.030609131f, 0.029937744f, 0.000549316f, 0.002349854f, 0.000167847f,
|
||||||
|
-0.000030518f,-0.000961304f, 0.003372192f,-0.016235352f, 0.019531250f,-0.125259399f,-0.015228271f,-0.816864014f,
|
||||||
|
1.089782715f, 0.323318481f, 0.148773193f, 0.030609131f, 0.029937744f, 0.000549316f, 0.002349854f, 0.000167847f,
|
||||||
|
},{
|
||||||
|
-0.000030518f,-0.001037598f, 0.003280640f,-0.017349243f, 0.017257690f,-0.129562378f,-0.032379150f,-0.841949463f,
|
||||||
|
1.077117920f, 0.297210693f, 0.150497437f, 0.025817871f, 0.029281616f, 0.000030518f, 0.002243042f, 0.000152588f,
|
||||||
|
-0.000030518f,-0.001037598f, 0.003280640f,-0.017349243f, 0.017257690f,-0.129562378f,-0.032379150f,-0.841949463f,
|
||||||
|
1.077117920f, 0.297210693f, 0.150497437f, 0.025817871f, 0.029281616f, 0.000030518f, 0.002243042f, 0.000152588f,
|
||||||
|
},{
|
||||||
|
-0.000045776f,-0.001113892f, 0.003173828f,-0.018463135f, 0.014801025f,-0.133590698f,-0.050354004f,-0.866363525f,
|
||||||
|
1.063217163f, 0.271591187f, 0.151596069f, 0.021179199f, 0.028533936f,-0.000442505f, 0.002120972f, 0.000137329f,
|
||||||
|
-0.000045776f,-0.001113892f, 0.003173828f,-0.018463135f, 0.014801025f,-0.133590698f,-0.050354004f,-0.866363525f,
|
||||||
|
1.063217163f, 0.271591187f, 0.151596069f, 0.021179199f, 0.028533936f,-0.000442505f, 0.002120972f, 0.000137329f,
|
||||||
|
},{
|
||||||
|
-0.000045776f,-0.001205444f, 0.003051758f,-0.019577026f, 0.012115479f,-0.137298584f,-0.069168091f,-0.890090942f,
|
||||||
|
1.048156738f, 0.246505737f, 0.152069092f, 0.016708374f, 0.027725220f,-0.000869751f, 0.002014160f, 0.000122070f,
|
||||||
|
-0.000045776f,-0.001205444f, 0.003051758f,-0.019577026f, 0.012115479f,-0.137298584f,-0.069168091f,-0.890090942f,
|
||||||
|
1.048156738f, 0.246505737f, 0.152069092f, 0.016708374f, 0.027725220f,-0.000869751f, 0.002014160f, 0.000122070f,
|
||||||
|
},{
|
||||||
|
-0.000061035f,-0.001296997f, 0.002883911f,-0.020690918f, 0.009231567f,-0.140670776f,-0.088775635f,-0.913055420f,
|
||||||
|
1.031936646f, 0.221984863f, 0.151962280f, 0.012420654f, 0.026840210f,-0.001266479f, 0.001907349f, 0.000106812f,
|
||||||
|
-0.000061035f,-0.001296997f, 0.002883911f,-0.020690918f, 0.009231567f,-0.140670776f,-0.088775635f,-0.913055420f,
|
||||||
|
1.031936646f, 0.221984863f, 0.151962280f, 0.012420654f, 0.026840210f,-0.001266479f, 0.001907349f, 0.000106812f,
|
||||||
|
},{
|
||||||
|
-0.000061035f,-0.001388550f, 0.002700806f,-0.021789551f, 0.006134033f,-0.143676758f,-0.109161377f,-0.935195923f,
|
||||||
|
1.014617920f, 0.198059082f, 0.151306152f, 0.008316040f, 0.025909424f,-0.001617432f, 0.001785278f, 0.000106812f,
|
||||||
|
-0.000061035f,-0.001388550f, 0.002700806f,-0.021789551f, 0.006134033f,-0.143676758f,-0.109161377f,-0.935195923f,
|
||||||
|
1.014617920f, 0.198059082f, 0.151306152f, 0.008316040f, 0.025909424f,-0.001617432f, 0.001785278f, 0.000106812f,
|
||||||
|
},{
|
||||||
|
-0.000076294f,-0.001480103f, 0.002487183f,-0.022857666f, 0.002822876f,-0.146255493f,-0.130310059f,-0.956481934f,
|
||||||
|
0.996246338f, 0.174789429f, 0.150115967f, 0.004394531f, 0.024932861f,-0.001937866f, 0.001693726f, 0.000091553f,
|
||||||
|
-0.000076294f,-0.001480103f, 0.002487183f,-0.022857666f, 0.002822876f,-0.146255493f,-0.130310059f,-0.956481934f,
|
||||||
|
0.996246338f, 0.174789429f, 0.150115967f, 0.004394531f, 0.024932861f,-0.001937866f, 0.001693726f, 0.000091553f,
|
||||||
|
},{
|
||||||
|
-0.000076294f,-0.001586914f, 0.002227783f,-0.023910522f,-0.000686646f,-0.148422241f,-0.152206421f,-0.976852417f,
|
||||||
|
0.976852417f, 0.152206421f, 0.148422241f, 0.000686646f, 0.023910522f,-0.002227783f, 0.001586914f, 0.000076294f,
|
||||||
|
-0.000076294f,-0.001586914f, 0.002227783f,-0.023910522f,-0.000686646f,-0.148422241f,-0.152206421f,-0.976852417f,
|
||||||
|
0.976852417f, 0.152206421f, 0.148422241f, 0.000686646f, 0.023910522f,-0.002227783f, 0.001586914f, 0.000076294f,
|
||||||
|
} };
|
||||||
|
#endif /* TRANSFORM */
|
110
Src/Sound/MPEG/util.cpp
Normal file
110
Src/Sound/MPEG/util.cpp
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
/* this file is a part of amp software
|
||||||
|
|
||||||
|
util.c: created by Andrew Richards
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define AMP_UTIL
|
||||||
|
#include "amp.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "audio.h"
|
||||||
|
|
||||||
|
struct debugFlags_t debugFlags;
|
||||||
|
|
||||||
|
|
||||||
|
/* die - for terminal conditions prints the error message and exits */
|
||||||
|
/* can not be suppressed with -q,-quiet */
|
||||||
|
void
|
||||||
|
die(char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap,fmt);
|
||||||
|
vfprintf(stderr, fmt, ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* warn - for warning messages. Can be suppressed by -q,-quiet */
|
||||||
|
void
|
||||||
|
warn(char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap,fmt);
|
||||||
|
if (!A_QUIET) {
|
||||||
|
fprintf(stderr,"Warning: ");
|
||||||
|
vfprintf(stderr, fmt, ap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* msg - for general output. Can be suppressed by -q,-quiet. Output */
|
||||||
|
/* goes to stderr so it doesn't conflict with stdout output */
|
||||||
|
void
|
||||||
|
msg(char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap,fmt);
|
||||||
|
|
||||||
|
if (!A_QUIET)
|
||||||
|
{
|
||||||
|
if (A_MSG_STDOUT) {
|
||||||
|
vfprintf(stdout, fmt, ap);
|
||||||
|
fflush(stdout);
|
||||||
|
} else {
|
||||||
|
vfprintf(stderr, fmt, ap);
|
||||||
|
fflush(stderr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
debugOptions()
|
||||||
|
{
|
||||||
|
int idx;
|
||||||
|
msg("Possible options are: ");
|
||||||
|
for(idx=0;debugLookup[idx].name!=0;idx++)
|
||||||
|
msg("%s,",debugLookup[idx].name);
|
||||||
|
msg("\010 \n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* debugSetup - if debugging is turned on sets up the debug flags from */
|
||||||
|
/* the command line arguments */
|
||||||
|
|
||||||
|
void
|
||||||
|
debugSetup(char *dbgFlags)
|
||||||
|
{
|
||||||
|
#ifndef DEBUG
|
||||||
|
warn("Debugging has not been compiled into this version of amp\n");
|
||||||
|
#else
|
||||||
|
char *ptr;
|
||||||
|
int idx;
|
||||||
|
|
||||||
|
memset(&debugFlags,0,sizeof(debugFlags));
|
||||||
|
|
||||||
|
ptr=strtok(dbgFlags,",");
|
||||||
|
while(ptr) {
|
||||||
|
for(idx=0;debugLookup[idx].name!=0;idx++) {
|
||||||
|
if (strcmp(debugLookup[idx].name,ptr)==0) {
|
||||||
|
*(debugLookup[idx].var)=1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (debugLookup[idx].name==0) {
|
||||||
|
warn("Debug option, %s, does not exist\n",ptr);
|
||||||
|
debugOptions();
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
ptr=strtok(NULL,",");
|
||||||
|
}
|
||||||
|
|
||||||
|
DB(args,
|
||||||
|
for(idx=0;debugLookup[idx].name!=0;idx++)
|
||||||
|
printf("Flag: %s = %d\n",debugLookup[idx].name,*(debugLookup[idx].var));
|
||||||
|
);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
|
@ -113,8 +113,6 @@ unsigned int RevR,RevW;
|
||||||
#define DWORD UINT32
|
#define DWORD UINT32
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static CIRQ *ppcIRQ;
|
|
||||||
static unsigned ppcSoundIRQBit;
|
|
||||||
static int (*Run68kCB)(int cycles);
|
static int (*Run68kCB)(int cycles);
|
||||||
static void (*Int68kCB)(int irq);
|
static void (*Int68kCB)(int irq);
|
||||||
static void (*RetIntCB)();
|
static void (*RetIntCB)();
|
||||||
|
@ -745,7 +743,7 @@ void SCSP_UpdateSlotReg(int s,int r)
|
||||||
if(KEYONB(s2) && (!s2->active || (s2->active && s2->EG.state==RELEASE)))
|
if(KEYONB(s2) && (!s2->active || (s2->active && s2->EG.state==RELEASE)))
|
||||||
{
|
{
|
||||||
DebugLog("KEYON %d",sl);
|
DebugLog("KEYON %d",sl);
|
||||||
printf("68K: KEYON %d\n",sl);
|
//printf("68K: KEYON %d\n",sl);
|
||||||
SCSP_StartSlot(s2);
|
SCSP_StartSlot(s2);
|
||||||
}
|
}
|
||||||
if(!KEYONB(s2) && s2->active)
|
if(!KEYONB(s2) && s2->active)
|
||||||
|
@ -1851,12 +1849,10 @@ void SCSP_Update()
|
||||||
SCSP_DoMasterSamples(length);
|
SCSP_DoMasterSamples(length);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SCSP_SetCB(int (*Run68k)(int cycles),void (*Int68k)(int irq), CIRQ *ppcIRQObjectPtr, unsigned ppcIRQBit)
|
void SCSP_SetCB(int (*Run68k)(int cycles),void (*Int68k)(int irq))
|
||||||
{
|
{
|
||||||
Int68kCB=Int68k;
|
Int68kCB=Int68k;
|
||||||
Run68kCB=Run68k;
|
Run68kCB=Run68k;
|
||||||
ppcIRQ = ppcIRQObjectPtr;
|
|
||||||
ppcSoundIRQBit = ppcIRQBit;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SCSP_MidiIn(BYTE val)
|
void SCSP_MidiIn(BYTE val)
|
||||||
|
@ -1872,7 +1868,7 @@ void SCSP_MidiIn(BYTE val)
|
||||||
|
|
||||||
void SCSP_MidiOutW(BYTE val)
|
void SCSP_MidiOutW(BYTE val)
|
||||||
{
|
{
|
||||||
printf("68K: MIDI out\n");
|
//printf("68K: MIDI out\n");
|
||||||
DebugLog("Midi Out Buffer push %02X",val);
|
DebugLog("Midi Out Buffer push %02X",val);
|
||||||
MidiStack[MidiOutW++]=val;
|
MidiStack[MidiOutW++]=val;
|
||||||
MidiOutW&=7;
|
MidiOutW&=7;
|
||||||
|
|
|
@ -36,7 +36,7 @@ unsigned char SCSP_r8(unsigned int addr);
|
||||||
unsigned short SCSP_r16(unsigned int addr);
|
unsigned short SCSP_r16(unsigned int addr);
|
||||||
unsigned int SCSP_r32(unsigned int addr);
|
unsigned int SCSP_r32(unsigned int addr);
|
||||||
|
|
||||||
void SCSP_SetCB(int (*Run68k)(int cycles),void (*Int68k)(int irq), CIRQ *ppcIRQObjectPtr, unsigned soundIRQBit);
|
void SCSP_SetCB(int (*Run68k)(int cycles),void (*Int68k)(int irq));
|
||||||
void SCSP_Update();
|
void SCSP_Update();
|
||||||
void SCSP_MidiIn(unsigned char);
|
void SCSP_MidiIn(unsigned char);
|
||||||
void SCSP_MidiOutW(unsigned char);
|
void SCSP_MidiOutW(unsigned char);
|
||||||
|
|
|
@ -147,7 +147,7 @@ extern void InfoLog(const char *fmt, ...);
|
||||||
#include "CPU/Bus.h"
|
#include "CPU/Bus.h"
|
||||||
#include "CPU/PowerPC/PPCDisasm.h"
|
#include "CPU/PowerPC/PPCDisasm.h"
|
||||||
#include "CPU/PowerPC/ppc.h"
|
#include "CPU/PowerPC/ppc.h"
|
||||||
#include "CPU/68K/M68K.h"
|
#include "CPU/68K/68K.h"
|
||||||
#include "CPU/Z80/Z80.h"
|
#include "CPU/Z80/Z80.h"
|
||||||
#include "Inputs/Input.h"
|
#include "Inputs/Input.h"
|
||||||
#include "Inputs/Inputs.h"
|
#include "Inputs/Inputs.h"
|
||||||
|
@ -164,7 +164,9 @@ extern void InfoLog(const char *fmt, ...);
|
||||||
#include "Model3/TileGen.h"
|
#include "Model3/TileGen.h"
|
||||||
#include "Model3/Real3D.h"
|
#include "Model3/Real3D.h"
|
||||||
#include "Sound/SCSP.h"
|
#include "Sound/SCSP.h"
|
||||||
|
#include "Sound/MPEG/MPEG.h"
|
||||||
#include "Model3/SoundBoard.h"
|
#include "Model3/SoundBoard.h"
|
||||||
|
#include "Model3/DSB.h"
|
||||||
#include "Model3/Model3.h"
|
#include "Model3/Model3.h"
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
|
|
Loading…
Reference in a new issue