- 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:
Bart Trzynadlowski 2011-07-31 02:37:31 +00:00
parent 62f695cc96
commit ddd6fa92ef
46 changed files with 8253 additions and 1091 deletions

View file

@ -119,11 +119,11 @@ CC = "$(VC_BIN)\cl.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" \
/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
CPPFLAGS = $(COMPILER_FLAGS) /TP /EHsc
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 \
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)/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)/SCSP.obj $(OBJ_DIR)/SCSPDSP.obj $(OBJ_DIR)/M68K.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)/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)/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)/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
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)
$(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)
$(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
$(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

View file

@ -20,7 +20,7 @@
**/
/*
* M68K.cpp
* 68K.cpp
*
* 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
@ -30,26 +30,28 @@
#include "Supermodel.h"
#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
******************************************************************************/
// 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
UINT32 M68KGetARegister(int n)
{
m68k_register_t r;
@ -110,6 +112,7 @@ int M68KRun(int numCycles)
void M68KReset(void)
{
m68k_pulse_reset();
DebugLog("68K reset\n");
}
// Callback setup
@ -119,49 +122,26 @@ void M68KSetIRQCallback(int (*F)(int nIRQ))
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;
}
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;
IRQAck = Src->IRQAck;
Bus = Src->Bus;
m68k_set_context(Src->musashiCtx);
}
// One-time initialization
@ -171,11 +151,12 @@ BOOL M68KInit(void)
m68k_init();
m68k_set_cpu_type(M68K_CPU_TYPE_68000);
m68k_set_int_ack_callback(M68KIRQCallback);
Bus = NULL;
DebugLog("Initialized 68K\n");
return OKAY;
}
} // extern "C"
/******************************************************************************
Musashi 68K Handlers
@ -187,55 +168,58 @@ extern "C" {
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;
}
else
return IRQAck(nIRQ);
}
unsigned int FASTCALL M68KFetch8(unsigned int a)
{
return Fetch8(a);
return Bus->Read8(a);
}
unsigned int FASTCALL M68KFetch16(unsigned int a)
{
return Fetch16(a);
return Bus->Read16(a);
}
unsigned int FASTCALL M68KFetch32(unsigned int a)
{
return Fetch32(a);
return Bus->Read32(a);
}
unsigned int FASTCALL M68KRead8(unsigned int a)
{
return Read8(a);
return Bus->Read8(a);
}
unsigned int FASTCALL M68KRead16(unsigned int a)
{
return Read16(a);
return Bus->Read16(a);
}
unsigned int FASTCALL M68KRead32(unsigned int a)
{
return Read32(a);
return Bus->Read32(a);
}
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)
{
Write16(a, d);
Bus->Write16(a, d);
}
void FASTCALL M68KWrite32(unsigned int a, unsigned int d)
{
Write32(a, d);
Bus->Write32(a, d);
}
} // extern "C"

View file

@ -20,26 +20,21 @@
**/
/*
* M68K.h
* 68K.h
*
* Header file for 68K CPU interface. Caution: there is only a single 68K core
* available to Supermodel right now. Therefore, multiple 68K CPUs are not
* presently supported. See M68K.c for more details.
* Header file for 68K CPU interface. Caution: 68K emulator is not thread-safe.
*
* TO-DO List:
* -----------
* - Optimize things, perhaps by using FASTCALL
*/
#ifndef INCLUDED_M68K_H
#define INCLUDED_M68K_H
#ifndef INCLUDED_68K_H
#define INCLUDED_68K_H
#include "Types.h"
#include "Musashi/m68k.h"
#ifdef __cplusplus
extern "C" {
#endif
#include "CPU/Bus.h"
// This doesn't work for now (needs to be added to the prototypes in m68k.h for m68k_read_memory*)
//#ifndef FASTCALL
@ -57,8 +52,44 @@ extern "C" {
#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
Unless otherwise noted, all functions operate on the active context.
******************************************************************************/
/*
@ -124,8 +155,8 @@ extern void M68KReset(void);
/*
* M68KSetIRQCallback(F):
*
* Installs an interrupt acknowledge callback. The default behavior is to
* always assume autovectored interrupts.
* Installs an interrupt acknowledge callback for the currently active CPU. The
* default behavior is to always assume autovectored interrupts.
*
* Parameters:
* F Callback function.
@ -133,44 +164,50 @@ extern void M68KReset(void);
extern void M68KSetIRQCallback(int (*F)(int));
/*
* M68KSetFetch8Callback(F):
* M68KSetFetch16Callback(F):
* M68KSetFetch32Callback(F):
* M68KSetRead8Callback(F):
* M68KSetRead16Callback(F):
* M68KSetRead32Callback(F):
* M68KSetWrite8Callback(F):
* M68KSetWrite16Callback(F):
* M68KSetWrite32Callback(F):
* M68KAttachBus(CBus *BusPtr):
*
* Installs address space handler callbacks. There is no default behavior;
* these must all be set up before any 68K-related emulation functions are
* invoked.
* Attaches a bus object to the 68K, which will be used to perform all address
* space accesses. The 8, 16, and 32-bit read and write handlers are used.
* This must be set up before any 68K-related emulation functions are invoked
* or the program will crash!
*
* Parameters:
* F Callback function.
* BusPtr Pointer to bus object to use for all address space accesses.
*/
extern void M68KSetFetch8Callback(UINT8 (*F)(UINT32));
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));
extern void M68KAttachBus(CBus *BusPtr);
/*
* M68KInit():
*
* 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:
* Always returns OKAY.
*/
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
@ -178,6 +215,8 @@ extern BOOL M68KInit(void);
Intended for use directly by the 68K core.
******************************************************************************/
extern "C" {
/*
* 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 M68KWrite32(unsigned int a, unsigned int d);
#ifdef __cplusplus
}
#endif
} // extern "C"
#endif // INCLUDED_M68K_H
#endif // INCLUDED_68K_H

View file

@ -203,7 +203,20 @@
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 */
#define m68k_read_pcrelative_8(address) M68KFetch8(address)

File diff suppressed because it is too large Load diff

View file

@ -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 sampleSize; // size of sample ROMS (8 or 16 MB; if 8 MB, will have to be mirrored)
unsigned inputFlags; // game input types
int mpegBoard; // MPEG music board type: 0 = none, 1 = DSB1 (Z80), 2 = DSB2 (68K).
// ROM files
struct ROMInfo ROM[42];
struct ROMInfo ROM[48];
};

View file

@ -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
View 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
View 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

View file

@ -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: 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
** A Sega Model 3 Arcade Emulator.
@ -1125,7 +1126,7 @@ void CModel3::Write8(UINT32 addr, UINT8 data)
// Sound Board
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
SoundBoard.WriteMIDIPort(data);
else if ((addr&0xF) == 4) // MIDI control port
@ -2112,23 +2113,38 @@ void CModel3::RunMainBoardFrame(void)
IRQ.Assert(0x02);
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;
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);
ppc_execute(200);
ppc_execute(200); // give PowerPC time to acknowledge IRQ
IRQ.Deassert(0x40);
ppc_execute(200);
ppc_execute(200); // acknowledge that IRQ was deasserted (TODO: is this really needed?)
++irqCount;
if (irqCount > (128))
if (irqCount > 128)
{
printf("MIDI TIMEOUT!\n");
printf("MIDI FIFO OVERFLOW!\n");
break;
}
}
IRQ.Deassert(0x40);
IRQ.Deassert(0x40); //todo: no longer needed, remove it
}
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_BACKUPRAM 0xD000000 // 128 KB
#define OFFSET_SECURITYRAM 0xD020000 // 128 KB
#define OFFSET_SOUNDROM 0xD040000 // 512 KB
#define OFFSET_SAMPLEROM 0xD0C0000 // 16 MB
#define MEMORY_POOL_SIZE (0x800000+0x800000+0x8000000+0x4000000+0x20000+0x20000+0x80000+0x1000000)
#define OFFSET_SOUNDROM 0xD040000 // 512 KB (68K sound board program)
#define OFFSET_SAMPLEROM 0xD0C0000 // 16 MB (sound board samples)
#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)
{
@ -2428,6 +2446,8 @@ BOOL CModel3::LoadROMSet(const struct GameInfo *GameList, const char *zipFile)
{ "VROM", vrom },
{ "SndProg", soundROM },
{ "Samples", sampleROM },
{ "DSBProg", dsbROM },
{ "DSBMPEG", mpegROM },
{ NULL, NULL }
};
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)
Reverse32(crom, 0x800000+0x8000000);
// Byte swap 68K ROMs
// Byte swap sound board 68K ROMs
Reverse16(soundROM, 0x80000);
Reverse16(sampleROM, 0x1000000); // is this correct?
Reverse16(sampleROM, 0x1000000);
// Initialize CPU and configure hardware (CPU speed is set in Init())
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);
// 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
Patch();
@ -2525,6 +2565,7 @@ void CModel3::AttachInputs(CInputs *InputsPtr)
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)
{
float memSizeMB = (float)MEMORY_POOL_SIZE/(float)0x100000;
@ -2546,11 +2587,13 @@ BOOL CModel3::Init(unsigned ppcFrequencyParam, BOOL multiThreadedParam)
vrom = &memoryPool[OFFSET_VROM];
soundROM = &memoryPool[OFFSET_SOUNDROM];
sampleROM = &memoryPool[OFFSET_SAMPLEROM];
dsbROM = &memoryPool[OFFSET_DSBPROGROM];
mpegROM = &memoryPool[OFFSET_DSBMPEGROM];
backupRAM = &memoryPool[OFFSET_BACKUPRAM];
securityRAM = &memoryPool[OFFSET_SECURITYRAM];
SetCROMBank(0xFF);
// Initialize other devices
// Initialize other devices (PowerPC and DSB initialized after ROMs loaded)
IRQ.Init();
PCIBridge.Init();
PCIBus.Init();
@ -2561,8 +2604,9 @@ BOOL CModel3::Init(unsigned ppcFrequencyParam, BOOL multiThreadedParam)
return FAIL;
if (OKAY != GPU.Init(vrom,this,&IRQ,0x100)) // same for Real3D DMA interrupt
return FAIL;
if (OKAY != SoundBoard.Init(soundROM,sampleROM,&IRQ,0x40))
if (OKAY != SoundBoard.Init(soundROM,sampleROM))
return FAIL;
#ifdef SUPERMODEL_DRIVEBOARD
DriveBoard.Init();
#endif
@ -2589,10 +2633,14 @@ CModel3::CModel3(void)
vrom = NULL;
soundROM = NULL;
sampleROM = NULL;
dsbROM = NULL;
mpegROM = NULL;
cromBank = NULL;
backupRAM = NULL;
securityRAM = NULL;
DSB = NULL;
securityPtr = 0;
multiThreaded = true;
@ -2630,18 +2678,27 @@ CModel3::~CModel3(void)
// Stop all threads
StopThreads();
// Free memory
if (memoryPool != NULL)
{
delete [] memoryPool;
memoryPool = NULL;
}
if (DSB != NULL)
{
delete DSB;
DSB = NULL;
}
Game = NULL;
ram = NULL;
crom = NULL;
vrom = NULL;
soundROM = NULL;
sampleROM = NULL;
dsbROM = NULL;
mpegROM = NULL;
cromBank = NULL;
backupRAM = NULL;
securityRAM = NULL;

View file

@ -250,7 +250,7 @@ public:
*/
CModel3(void);
~CModel3(void);
/*
* Private Property.
* Tresspassers will be shot! ;)
@ -265,14 +265,14 @@ private:
UINT8 ReadSystemRegister(unsigned reg);
void WriteSystemRegister(unsigned reg, UINT8 data);
void Patch(void);
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 DeleteThreadObjects(); // Deletes all threads and synchronization objects
static int StartSoundBoardThread(void *data); // Callback to start sound board thread
#ifdef SUPERMODEL_DRIVEBOARD
static int StartSoundBoardThread(void *data); // Callback to start sound board thread
#ifdef SUPERMODEL_DRIVEBOARD
static int StartDriveBoardThread(void *data); // Callback to start drive board thread
#endif
@ -303,6 +303,8 @@ private:
UINT8 *vrom; // 64 MB VROM (video ROM, visible only to Real3D)
UINT8 *soundROM; // 512 KB sound ROM (68K program)
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 *securityRAM; // 128 KB Security Board RAM
@ -318,23 +320,23 @@ private:
unsigned ppcFrequency; // clock frequency (Hz)
// Multiple threading
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
CThread *sndBrdThread; // Sound board thread
#ifdef SUPERMODEL_DRIVEBOARD
CThread *drvBrdThread; // Drive board thread
#endif
bool sndBrdThreadDone; // Flag to indicate sound board thread has finished processing for current frame
#ifdef SUPERMODEL_DRIVEBOARD
bool drvBrdThreadDone; // Flag to indicate drive board thread has finished processing for current frame
#endif
// Thread synchronization objects
CSemaphore *sndBrdThreadSync;
#ifdef SUPERMODEL_DRIVEBOARD
CSemaphore *drvBrdThreadSync;
#endif
CMutex *notifyLock;
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
CThread *sndBrdThread; // Sound board thread
#ifdef SUPERMODEL_DRIVEBOARD
CThread *drvBrdThread; // Drive board thread
#endif
bool sndBrdThreadDone; // Flag to indicate sound board thread has finished processing for current frame
#ifdef SUPERMODEL_DRIVEBOARD
bool drvBrdThreadDone; // Flag to indicate drive board thread has finished processing for current frame
#endif
// Thread synchronization objects
CSemaphore *sndBrdThreadSync;
#ifdef SUPERMODEL_DRIVEBOARD
CSemaphore *drvBrdThreadSync;
#endif
CMutex *notifyLock;
CCondVar *notifySync;
// Other devices
@ -346,7 +348,8 @@ private:
C93C46 EEPROM; // 93C46 EEPROM
CTileGen TileGen; // Sega 2D tile generator
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
CDriveBoard DriveBoard; // Drive board
#endif

View file

@ -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
/**
** Supermodel
@ -26,11 +25,7 @@
*
* 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
* 68K core).
*
* TO-DO List
* ----------
* - Optimize memory handlers (jump table).
* 68K core and an IRQ line).
*
* Bank Switching
* --------------
@ -62,248 +57,261 @@
#include "Supermodel.h"
//TEMP: these need to be dynamically allocated in the memory pool
static INT16 leftBuffer[44100/60],rightBuffer[44100/60];
// DEBUG
//#define SUPERMODEL_LOG_AUDIO // define this to log all audio to sound.bin
#ifdef SUPERMODEL_LOG_AUDIO
static FILE *soundFP;
#endif
/******************************************************************************
68K Access Handlers
******************************************************************************/
// Memory regions passed out of CSoundBoard object for global access handlers
static UINT8 *sbRAM1, *sbRAM2;
static const UINT8 *sbSoundROM, *sbSampleROM, *sbSampleBankLo, *sbSampleBankHi;
static UINT8 Read8(UINT32 a)
UINT8 CSoundBoard::Read8(UINT32 a)
{
// SCSP RAM 1
if ((a >= 0x000000) && (a <= 0x0FFFFF))
return sbRAM1[a^1];
// SCSP RAM 2
else if ((a >= 0x200000) && (a <= 0x2FFFFF))
return sbRAM2[(a-0x200000)^1];
switch ((a>>20)&0xF)
{
case 0x0: // SCSP RAM 1 (master): 000000-0FFFFF
return ram1[a^1];
// Program ROM
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))
case 0x1: // SCSP registers (master): 100000-10FFFF (unlike real hardware, we mirror up to 1FFFFF)
return SCSP_Master_r8(a);
// SCSP (Slave)
else if ((a >= 0x300000) && (a <= 0x30FFFF))
case 0x2: // SCSP RAM 2 (slave): 200000-2FFFFF
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);
// Unknown
else
{
case 0x6: // Program ROM: 600000-67FFFF (unlike real hardware, we mirror up to 6FFFFF here)
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);
return 0;
break;
}
return 0;
}
static UINT16 Read16(UINT32 a)
UINT16 CSoundBoard::Read16(UINT32 a)
{
// SCSP RAM 1
if ((a >= 0x000000) && (a <= 0x0FFFFF))
return *(UINT16 *) &sbRAM1[a];
// SCSP RAM 2
else if ((a >= 0x200000) && (a <= 0x2FFFFF))
return *(UINT16 *) &sbRAM2[(a-0x200000)];
switch ((a>>20)&0xF)
{
case 0x0: // SCSP RAM 1 (master): 000000-0FFFFF
return *(UINT16 *) &ram1[a];
// Program ROM
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))
case 0x1: // SCSP registers (master): 100000-10FFFF
return SCSP_Master_r16(a);
// SCSP (Slave)
else if ((a >= 0x300000) && (a <= 0x30FFFF))
case 0x2: // SCSP RAM 2 (slave): 200000-2FFFFF
return *(UINT16 *) &ram2[a&0x0FFFFF];
case 0x3: // SCSP registers (slave): 300000-30FFFF
return SCSP_Slave_r16(a);
// Unknown
else
{
case 0x6: // Program ROM: 600000-67FFFF
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);
return 0;
break;
}
return 0;
}
static UINT32 Read32(UINT32 a)
{
// SCSP RAM 1
if ((a >= 0x000000) && (a <= 0x0FFFFF))
return (Read16(a)<<16)|Read16(a+2);
UINT32 CSoundBoard::Read32(UINT32 a)
{
UINT32 hi, lo;
// SCSP RAM 2
else if ((a >= 0x200000) && (a <= 0x2FFFFF))
return (Read16(a)<<16)|Read16(a+2);
switch ((a>>20)&0xF)
{
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
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))
case 0x1: // SCSP registers (master): 100000-10FFFF
return SCSP_Master_r32(a);
// SCSP (Slave)
else if ((a >= 0x300000) && (a <= 0x30FFFF))
case 0x2: // SCSP RAM 2 (slave): 200000-2FFFFF
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);
// Unknown
else
{
case 0x6: // Program ROM: 600000-67FFFF
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);
return 0;
break;
}
return 0;
}
static void Write8(unsigned int a,unsigned char d)
void CSoundBoard::Write8(unsigned int a,unsigned char d)
{
// 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)
switch ((a>>20)&0xF)
{
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];
sbSampleBankHi = &sbSampleROM[0xE00000];
if ((d&0x10))
{
sampleBankLo = &sampleROM[0xA00000];
sampleBankHi = &sampleROM[0xE00000];
}
else
{
sampleBankLo = &sampleROM[0x200000];
sampleBankHi = &sampleROM[0x600000];
}
}
else
{
sbSampleBankLo = &sbSampleROM[0x200000];
sbSampleBankHi = &sbSampleROM[0x600000];
}
printf("68K: Unknown write8 %06X=%02X\n", a, d);
break;
}
// 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
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))
case 0x1: // SCSP registers (master): 100000-10FFFF
SCSP_Master_w16(a,d);
break;
// SCSP (Slave)
else if ((a >= 0x300000) && (a <= 0x30FFFF))
SCSP_Slave_w16(a,d);
// Unknown
else
printf("68K: Unknown write16 %06X=%04X\n", a, d);
case 0x2: // SCSP RAM 2 (slave): 200000-2FFFFF
*(UINT16 *) &ram2[a&0x0FFFFF] = d;
break;
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
if ((a >= 0x000000) && (a <= 0x0FFFFF))
switch ((a>>20)&0xF)
{
Write16(a,d>>16);
Write16(a+2,d&0xFFFF);
}
case 0x0: // SCSP RAM 1 (master): 000000-0FFFFF
*(UINT16 *) &ram1[a] = (d>>16);
*(UINT16 *) &ram1[a+2] = (d&0xFFFF);
break;
// SCSP RAM 2
else if ((a >= 0x200000) && (a <= 0x2FFFFF))
{
Write16(a,d>>16);
Write16(a+2,d&0xFFFF);
}
// SCSP (Master)
else if ((a >= 0x100000) && (a <= 0x10FFFF))
case 0x1: // SCSP registers (master): 100000-10FFFF
SCSP_Master_w32(a,d);
break;
// SCSP (Slave)
else if ((a >= 0x300000) && (a <= 0x30FFFF))
case 0x2: // SCSP RAM 2 (slave): 200000-2FFFFF
*(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);
// Unknown
else
break;
default:
printf("68K: Unknown write32 %06X=%08X\n", a, d);
break;
}
}
/******************************************************************************
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
// TODO: can we get rid of this global variable altogether?
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)
{
M68KSetIRQ(0);
@ -334,41 +342,55 @@ int SCSP68KRunCallback(int numCycles)
/******************************************************************************
Sound Board Emulation
Sound Board Interface
******************************************************************************/
void CSoundBoard::WriteMIDIPort(UINT8 data)
{
SCSP_MidiIn(data);
if (NULL != DSB) // DSB receives all commands as well
DSB->SendCommand(data);
}
void CSoundBoard::RunFrame(void)
{
#ifdef SUPERMODEL_SOUND
// Run sound board first to generate SCSP audio
M68KSetContext(&M68K);
SCSP_Update();
M68KGetContext(&M68K);
// Run DSB and mix with existing audio
if (NULL != DSB)
DSB->RunFrame(audioL, audioR);
// Output the audio buffers
OutputAudio(44100/60, leftBuffer, rightBuffer);
OutputAudio(44100/60, audioL, audioR);
#ifdef SUPERMODEL_LOG_AUDIO
// Output to binary file
INT16 s;
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
s = ((UINT16)rightBuffer[i]>>8) | ((rightBuffer[i]&0xFF)<<8);
s = audioR[i];
fwrite(&s, sizeof(INT16), 1, soundFP); // right channel
}
#endif
#endif
}
void CSoundBoard::Reset(void)
{
// lets hope he does better... ->
memcpy(ram1, soundROM, 16); // copy 68K vector table
sbSampleBankLo = &sampleROM[0x200000]; // default banks
sbSampleBankHi = &sampleROM[0x600000];
sampleBankLo = &sampleROM[0x200000]; // default banks
sampleBankHi = &sampleROM[0x600000];
M68KSetContext(&M68K);
M68KReset();
M68KGetContext(&M68K);
if (NULL != DSB)
DSB->Reset();
DebugLog("Sound Board Reset\n");
}
@ -377,22 +399,28 @@ void CSoundBoard::Reset(void)
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
#define OFFSET_RAM1 0 // 1 MB SCSP1 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;
// Attach IRQ controller
ppcIRQ = ppcIRQObjectPtr;
ppcSoundIRQBit = soundIRQBit;
// Receive sound ROMs
soundROM = soundROMPtr;
sampleROM = sampleROMPtr;
sampleBankLo = &sampleROM[0x200000];
sampleBankHi = &sampleROM[0x600000];
// Allocate all memory for RAM
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
ram1 = &memoryPool[OFFSET_RAM1];
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
M68KSetContext(&M68K);
M68KInit();
M68KAttachBus(this);
M68KSetIRQCallback(IRQAck);
M68KSetFetch8Callback(Read8);
M68KSetFetch16Callback(Read16);
M68KSetFetch32Callback(Read32);
M68KSetRead8Callback(Read8);
M68KSetRead16Callback(Read16);
M68KSetRead32Callback(Read32);
M68KSetWrite8Callback(Write8);
M68KSetWrite16Callback(Write16);
M68KSetWrite32Callback(Write32);
M68KGetContext(&M68K);
// Initialize SCSPs
SCSP_SetBuffers(leftBuffer, rightBuffer, 44100/60);
SCSP_SetCB(SCSP68KRunCallback, SCSP68KIRQCallback, ppcIRQ, ppcSoundIRQBit);
SCSP_SetBuffers(audioL, audioR, 44100/60);
SCSP_SetCB(SCSP68KRunCallback, SCSP68KIRQCallback);
SCSP_Init(2);
SCSP_SetRAM(0, ram1);
SCSP_SetRAM(1, ram2);
// Binary logging
#ifdef SUPERMODEL_SOUND
#ifdef SUPERMODEL_LOG_AUDIO
soundFP = fopen("sound.bin","wb"); // delete existing file
fclose(soundFP);
soundFP = fopen("sound.bin","ab"); // append mode
@ -444,9 +460,14 @@ BOOL CSoundBoard::Init(const UINT8 *soundROMPtr, const UINT8 *sampleROMPtr, CIRQ
CSoundBoard::CSoundBoard(void)
{
DSB = NULL;
memoryPool = NULL;
ram1 = NULL;
ram2 = NULL;
audioL = NULL;
audioR = NULL;
soundROM = NULL;
sampleROM = NULL;
DebugLog("Built Sound Board\n");
}
@ -466,35 +487,15 @@ static void Reverse16(UINT8 *buf, unsigned size)
CSoundBoard::~CSoundBoard(void)
{
#ifdef SUPERMODEL_SOUND
#ifdef SUPERMODEL_LOG_AUDIO
// close binary log file
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
SCSP_Deinit();
DSB = NULL;
if (memoryPool != NULL)
{
delete [] memoryPool;
@ -502,5 +503,10 @@ CSoundBoard::~CSoundBoard(void)
}
ram1 = NULL;
ram2 = NULL;
audioL = NULL;
audioR = NULL;
soundROM = NULL;
sampleROM = NULL;
DebugLog("Destroyed Sound Board\n");
}

View file

@ -28,15 +28,52 @@
#ifndef INCLUDED_SOUNDBOARD_H
#define INCLUDED_SOUNDBOARD_H
#include "Types.h"
#include "CPU/Bus.h"
#include "Model3/DSB.h"
/*
* CSoundBoard:
*
* Model 3 sound board (68K CPU + 2 x SCSP).
*/
class CSoundBoard
class CSoundBoard: public CBus
{
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):
*
@ -61,6 +98,18 @@ public:
*/
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):
*
@ -69,14 +118,12 @@ public:
* Parameters:
* soundROMPtr Pointer to sound ROM (68K program).
* sampleROMPtr Pointer to sample ROM.
* ppcIRQObjectPtr Pointer to PowerPC-side IRQ object.
* soundIRQBit IRQ bit mask to use for sound board PowerPC IRQs.
*
* Returns:
* OKAY if successful, FAIL if unable to allocate memory. Prints own
* error messages.
*/
BOOL Init(const UINT8 *soundROMPtr, const UINT8 *sampleROMPtr, CIRQ *ppcIRQObjectPtr, unsigned soundIRQBit);
BOOL Init(const UINT8 *soundROMPtr, const UINT8 *sampleROMPtr);
/*
* CSoundBoard(void):
@ -88,15 +135,22 @@ public:
~CSoundBoard(void);
private:
// PowerPC IRQ controller
CIRQ *ppcIRQ;
unsigned ppcSoundIRQBit;
// Digital Sound Board
CDSB *DSB;
// 68K context
M68KCtx M68K;
// Sound board memory
const UINT8 *soundROM; // 68K program 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 *ram1, *ram2; // SCSP1 and SCSP2 RAM
// Audio
INT16 *audioL, *audioR; // left and right audio channels (1/60th second, 44.1 KHz)
};

View file

@ -534,27 +534,6 @@ int Supermodel(const char *zipFile, CInputs *Inputs, unsigned ppcFrequency, BOOL
// Toggle frame limiting
noThrottle = !noThrottle;
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
else if (Inputs->uiEnterDebugger->Pressed())

View file

@ -68,7 +68,7 @@ static BOOL FindROMByCRCInGame(const struct GameInfo **gamePtr, int *romIdxPtr,
{
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;
return OKAY;
}
@ -97,6 +97,23 @@ static BOOL FindROMByCRC(const struct GameInfo **gamePtr, int *romIdxPtr, const
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)
{
unsigned i;
@ -189,8 +206,9 @@ const struct GameInfo * LoadROMSetFromZIPFile(const struct ROMMap *Map, const st
{
unzFile zf;
unz_file_info fileInfo;
const struct GameInfo *Game = NULL, *CurGame;
int romIdx; // index within Game->ROM
const struct GameInfo *Game = NULL;
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;
int err;
unsigned i, n, maxSize;
@ -205,8 +223,7 @@ const struct GameInfo * LoadROMSetFromZIPFile(const struct ROMMap *Map, const st
return NULL;
}
// Check ROMs: scan ZIP file for first known ROM and check to ensure all ROMs are present
memset(romsFound, 0, sizeof(romsFound));
// First pass: scan every file and determine the game
err = unzGoToFirstFile(zf);
if (UNZ_OK != err)
{
@ -221,54 +238,73 @@ const struct GameInfo * LoadROMSetFromZIPFile(const struct ROMMap *Map, const st
continue;
if (OKAY != FindROMByCRC(&CurGame, &romIdx, GameList, Game, fileInfo.crc))
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
{
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);
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);
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;
}
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
for (numROMs = 0; Game->ROM[numROMs].region != NULL; numROMs++)
;
// If not all ROMs were present, tell the user
err = OKAY;
for (i = 0; i < numROMs; i++)
{
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)
{
unzClose(zf);
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;
for (i = 0; i < numROMs; i++)
{
@ -283,8 +319,8 @@ const struct GameInfo * LoadROMSetFromZIPFile(const struct ROMMap *Map, const st
return NULL;
}
// Load ROMs
memset(romsFound, 0, sizeof(romsFound));
// Third pass: load the ROMs
memset(romsFound, 0, sizeof(romsFound)); // now, romsFound[] is used to indicate whether we successfully loaded the ROM
err = unzGoToFirstFile(zf);
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);
if (err != UNZ_OK)
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;
if (CurGame == Game) // if ROM belongs to correct game
{
if (OKAY == LoadROM(buf, maxSize, Map, &Game->ROM[romIdx], zf, zipFile, loadAll))
romsFound[romIdx] = 1; // success! mark as loaded
}
// Load the ROM and mark that we did so successfully
if (OKAY == LoadROM(buf, maxSize, Map, &Game->ROM[romIdx], zf, zipFile, loadAll))
romsFound[romIdx] = 1; // success! mark as loaded
}
// Ensure all ROMs were loaded
@ -315,7 +352,7 @@ const struct GameInfo * LoadROMSetFromZIPFile(const struct ROMMap *Map, const st
if (romsFound[i])
++n;
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)
err = FAIL;

View file

@ -44,7 +44,7 @@ struct ROMInfo
const char *region; // ROM region identifier (used as a key to search ROMMap)
// Information used to identify files
const char *file; // file name
const char *fileName; // file name
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)

114
Src/Sound/MPEG/MPEG.h Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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

File diff suppressed because it is too large Load diff

168
Src/Sound/MPEG/transform.h Normal file
View 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
View 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
}

View file

@ -113,8 +113,6 @@ unsigned int RevR,RevW;
#define DWORD UINT32
#endif
static CIRQ *ppcIRQ;
static unsigned ppcSoundIRQBit;
static int (*Run68kCB)(int cycles);
static void (*Int68kCB)(int irq);
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)))
{
DebugLog("KEYON %d",sl);
printf("68K: KEYON %d\n",sl);
//printf("68K: KEYON %d\n",sl);
SCSP_StartSlot(s2);
}
if(!KEYONB(s2) && s2->active)
@ -1851,12 +1849,10 @@ void SCSP_Update()
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;
Run68kCB=Run68k;
ppcIRQ = ppcIRQObjectPtr;
ppcSoundIRQBit = ppcIRQBit;
}
void SCSP_MidiIn(BYTE val)
@ -1872,7 +1868,7 @@ void SCSP_MidiIn(BYTE val)
void SCSP_MidiOutW(BYTE val)
{
printf("68K: MIDI out\n");
//printf("68K: MIDI out\n");
DebugLog("Midi Out Buffer push %02X",val);
MidiStack[MidiOutW++]=val;
MidiOutW&=7;

View file

@ -36,7 +36,7 @@ unsigned char SCSP_r8(unsigned int addr);
unsigned short SCSP_r16(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_MidiIn(unsigned char);
void SCSP_MidiOutW(unsigned char);

View file

@ -147,7 +147,7 @@ extern void InfoLog(const char *fmt, ...);
#include "CPU/Bus.h"
#include "CPU/PowerPC/PPCDisasm.h"
#include "CPU/PowerPC/ppc.h"
#include "CPU/68K/M68K.h"
#include "CPU/68K/68K.h"
#include "CPU/Z80/Z80.h"
#include "Inputs/Input.h"
#include "Inputs/Inputs.h"
@ -164,7 +164,9 @@ extern void InfoLog(const char *fmt, ...);
#include "Model3/TileGen.h"
#include "Model3/Real3D.h"
#include "Sound/SCSP.h"
#include "Sound/MPEG/MPEG.h"
#include "Model3/SoundBoard.h"
#include "Model3/DSB.h"
#include "Model3/Model3.h"
/******************************************************************************