code cleanup

This commit is contained in:
ekeeke31 2008-12-11 17:38:29 +00:00
parent 822de1bd3f
commit 00a61b4762
83 changed files with 33831 additions and 35082 deletions

View File

@ -17,10 +17,10 @@ include $(DEVKITPPC)/gamecube_rules
#--------------------------------------------------------------------------------- #---------------------------------------------------------------------------------
TARGET := genplus_cube TARGET := genplus_cube
BUILD := build_cube BUILD := build_cube
SOURCES := source source/m68k source/z80 source/sound source/cart_hw \ SOURCES := source source/m68k source/z80 source/sound source/sound/SRC source/ntsc \
source/cart_hw/svp source/ngc source/ngc/gui source/sound/SRC source/ntsc source/cart_hw source/cart_hw/svp source/ngc source/ngc/gui source/ngc/fileio
INCLUDES := source source/m68k source/z80 source/sound source/cart_hw \ INCLUDES := source source/m68k source/z80 source/sound source/sound/SRC source/ntsc \
source/cart_hw/svp source/ngc source/ngc/gui source/sound/SRC source/ntsc source/cart_hw source/cart_hw/svp source/ngc source/ngc/gui source/ngc/fileio
#--------------------------------------------------------------------------------- #---------------------------------------------------------------------------------
# options for code generation # options for code generation

View File

@ -17,10 +17,10 @@ include $(DEVKITPPC)/wii_rules
#--------------------------------------------------------------------------------- #---------------------------------------------------------------------------------
TARGET := genplus_wii TARGET := genplus_wii
BUILD := build_wii BUILD := build_wii
SOURCES := source source/m68k source/z80 source/sound source/cart_hw\ SOURCES := source source/m68k source/z80 source/sound source/sound/SRC source/ntsc \
source/cart_hw/svp source/ngc source/ngc/gui source/sound/SRC source/ntsc source/cart_hw source/cart_hw/svp source/ngc source/ngc/gui source/ngc/fileio
INCLUDES := source source/m68k source/z80 source/sound source/cart_hw\ INCLUDES := source source/m68k source/z80 source/sound source/sound/SRC source/ntsc \
source/cart_hw/svp source/ngc source/ngc/gui source/sound/SRC source/ntsc source/cart_hw source/cart_hw/svp source/ngc source/ngc/gui source/ngc/fileio
#--------------------------------------------------------------------------------- #---------------------------------------------------------------------------------
# options for code generation # options for code generation

View File

@ -43,71 +43,71 @@ void special_regs_w(uint32 address, uint32 data);
/* Cart database entry */ /* Cart database entry */
typedef struct typedef struct
{ {
uint16 chk_1; /* header checksum */ uint16 chk_1; /* header checksum */
uint16 chk_2; /* real checksum */ uint16 chk_2; /* real checksum */
uint8 bank_start; /* first mapped bank in $400000-$7fffff region */ uint8 bank_start; /* first mapped bank in $400000-$7fffff region */
uint8 bank_end; /* last mapped bank in $400000-$7fffff region */ uint8 bank_end; /* last mapped bank in $400000-$7fffff region */
T_CART_HW cart_hw; /* hardware description */ T_CART_HW cart_hw; /* hardware description */
} T_CART_ENTRY; } T_CART_ENTRY;
/* Games that need extra hardware emulation: /* Games that need extra hardware emulation:
- copy protection device - copy protection device
- custom ROM banking device - custom ROM banking device
*/ */
T_CART_ENTRY rom_database[CART_CNT] = T_CART_ENTRY rom_database[CART_CNT] =
{ {
/* Game no Kanzume Otokuyou */ /* Game no Kanzume Otokuyou */
{0x0000,0xf9d1,0,0,{{0,0,0,0},{0,0,0,0},{0,0,0,0},0,0,0,seganet_mapper_w,0,0}}, {0x0000,0xf9d1,0,0,{{0,0,0,0},{0,0,0,0},{0,0,0,0},0,0,0,seganet_mapper_w,0,0}},
/* RADICA (Volume 1) (not byteswapped) */ /* RADICA (Volume 1) (not byteswapped) */
{0x0000,0x2326,0,0,{{0,0,0,0},{0,0,0,0},{0,0,0,0},0,1,radica_mapper_r,0,0,0}}, {0x0000,0x2326,0,0,{{0,0,0,0},{0,0,0,0},{0,0,0,0},0,1,radica_mapper_r,0,0,0}},
/* RADICA (Volume 2) */ /* RADICA (Volume 2) */
{0x4f10,0x0836,0,0,{{0,0,0,0},{0,0,0,0},{0,0,0,0},0,1,radica_mapper_r,0,0,0}}, {0x4f10,0x0836,0,0,{{0,0,0,0},{0,0,0,0},{0,0,0,0},0,1,radica_mapper_r,0,0,0}},
/* RADICA (Volume 1) */ /* RADICA (Volume 1) */
{0xf424,0x9f82,0,0,{{0,0,0,0},{0,0,0,0},{0,0,0,0},0,1,radica_mapper_r,0,0,0}}, {0xf424,0x9f82,0,0,{{0,0,0,0},{0,0,0,0},{0,0,0,0},0,1,radica_mapper_r,0,0,0}},
/* Funny World & Balloon Boy */ /* Funny World & Balloon Boy */
{0x0000,0x06ab,0x40,0x40,{{0,0,0,0},{0,0,0,0},{0,0,0,0},1,1,0,0,0,realtec_mapper_w}}, {0x0000,0x06ab,0x40,0x40,{{0,0,0,0},{0,0,0,0},{0,0,0,0},1,1,0,0,0,realtec_mapper_w}},
/* Whac-a-Critter */ /* Whac-a-Critter */
{0xffff,0xf863,0x40,0x40,{{0,0,0,0},{0,0,0,0},{0,0,0,0},1,1,0,0,0,realtec_mapper_w}}, {0xffff,0xf863,0x40,0x40,{{0,0,0,0},{0,0,0,0},{0,0,0,0},1,1,0,0,0,realtec_mapper_w}},
/* Earth Defense */ /* Earth Defense */
{0xffff,0x44fb,0x40,0x40,{{0,0,0,0},{0,0,0,0},{0,0,0,0},1,1,0,0,0,realtec_mapper_w}}, {0xffff,0x44fb,0x40,0x40,{{0,0,0,0},{0,0,0,0},{0,0,0,0},1,1,0,0,0,realtec_mapper_w}},
/* Super Mario 2 1998 */ /* Super Mario 2 1998 */
{0xffff,0x0474,0,0,{{0x0a,0,0,0},{0xffffff,0,0,0},{0xa13000,0,0,0},0,0,default_regs_r,0,0,0}}, {0xffff,0x0474,0,0,{{0x0a,0,0,0},{0xffffff,0,0,0},{0xa13000,0,0,0},0,0,default_regs_r,0,0,0}},
/* Super Mario 2 1998 */ /* Super Mario 2 1998 */
{0x2020,0xb4eb,0,0,{{0x1c,0,0,0},{0xffffff,0,0,0},{0xa13000,0,0,0},0,0,default_regs_r,0,0,0}}, {0x2020,0xb4eb,0,0,{{0x1c,0,0,0},{0xffffff,0,0,0},{0xa13000,0,0,0},0,0,default_regs_r,0,0,0}},
/* Supper Bubble Bobble */ /* Supper Bubble Bobble */
{0x0000,0x16cd,0x40,0x40,{{0x55,0x0f,0,0},{0xffffff,0xffffff,0,0},{0x400000,0x400002,0,0},0,0,0,0,default_regs_r,0}}, {0x0000,0x16cd,0x40,0x40,{{0x55,0x0f,0,0},{0xffffff,0xffffff,0,0},{0x400000,0x400002,0,0},0,0,0,0,default_regs_r,0}},
/* Mahjong Lover */ /* Mahjong Lover */
{0x0000,0x7037,0x40,0x40,{{0x90,0xd3,0,0},{0xffffff,0xffffff,0,0},{0x400000,0x401000,0,0},0,0,0,0,default_regs_r,0}}, {0x0000,0x7037,0x40,0x40,{{0x90,0xd3,0,0},{0xffffff,0xffffff,0,0},{0x400000,0x401000,0,0},0,0,0,0,default_regs_r,0}},
/* Lion King 2 */ /* Lion King 2 */
{0xffff,0x1d9b,0x40,0x40,{{0,0,0,0},{0xfffffd,0xfffffd,0,0},{0x400000,0x400004,0,0},0,0,0,0,default_regs_r,default_regs_w}}, {0xffff,0x1d9b,0x40,0x40,{{0,0,0,0},{0xfffffd,0xfffffd,0,0},{0x400000,0x400004,0,0},0,0,0,0,default_regs_r,default_regs_w}},
/* Squirell King */ /* Squirell King */
{0x0000,0x8ec8,0x40,0x40,{{0,0,0,0},{0xfffffd,0xfffffd,0,0},{0x400000,0x400004,0,0},0,0,0,0,default_regs_r,default_regs_w}}, {0x0000,0x8ec8,0x40,0x40,{{0,0,0,0},{0xfffffd,0xfffffd,0,0},{0x400000,0x400004,0,0},0,0,0,0,default_regs_r,default_regs_w}},
/* Rockman X3 */ /* Rockman X3 */
{0x0000,0x9d0e,0x40,0x40,{{0x0c,0x88,0,0},{0xffffff,0xffffff,0,0},{0xa13000,0x400004,0,0},0,0,default_regs_r,0,default_regs_r,0}}, {0x0000,0x9d0e,0x40,0x40,{{0x0c,0x88,0,0},{0xffffff,0xffffff,0,0},{0xa13000,0x400004,0,0},0,0,default_regs_r,0,default_regs_r,0}},
/* A Bug's Life */ /* A Bug's Life */
{0x7f7f,0x2aad,0,0,{{0x28,0x1f,0x01,0},{0xffffff,0xffffff,0xffffff,0},{0xa13000,0xa13002,0xa1303e,0},0,0,default_regs_r,0,0,0}}, {0x7f7f,0x2aad,0,0,{{0x28,0x1f,0x01,0},{0xffffff,0xffffff,0xffffff,0},{0xa13000,0xa13002,0xa1303e,0},0,0,default_regs_r,0,0,0}},
/* King of Fighter 99 */ /* King of Fighter 99 */
{0x0000,0x21e,0,0,{{0x00,0x01,0x1f,0},{0xffffff,0xffffff,0xffffff,0},{0xa13000,0xa13002,0xa1303e,0},0,0,default_regs_r,0,0,0}}, {0x0000,0x21e,0,0,{{0x00,0x01,0x1f,0},{0xffffff,0xffffff,0xffffff,0},{0xa13000,0xa13002,0xa1303e,0},0,0,default_regs_r,0,0,0}},
/* Pocket Monster */ /* Pocket Monster */
{0xd6fc,0x1eb1,0,0,{{0x00,0x01,0x1f,0},{0xffffff,0xffffff,0xffffff,0},{0xa13000,0xa13002,0xa1303e,0},0,0,default_regs_r,0,0,0}}, {0xd6fc,0x1eb1,0,0,{{0x00,0x01,0x1f,0},{0xffffff,0xffffff,0xffffff,0},{0xa13000,0xa13002,0xa1303e,0},0,0,default_regs_r,0,0,0}},
/* Lion King 3 */ /* Lion King 3 */
{0x0000,0x507c,0x60,0x7f,{{0,0,0,0},{0xf0000e,0xf0000e,0xf0000e,0},{0x600000,0x600002,0x600004,0},0,1,0,0,default_regs_r,special_regs_w}}, {0x0000,0x507c,0x60,0x7f,{{0,0,0,0},{0xf0000e,0xf0000e,0xf0000e,0},{0x600000,0x600002,0x600004,0},0,1,0,0,default_regs_r,special_regs_w}},
/* Super King Kong 99 */ /* Super King Kong 99 */
{0x0000,0x7d6e,0x60,0x7f,{{0,0,0,0},{0xf0000e,0xf0000e,0xf0000e,0},{0x600000,0x600002,0x600004,0},0,1,0,0,default_regs_r,special_regs_w}}, {0x0000,0x7d6e,0x60,0x7f,{{0,0,0,0},{0xf0000e,0xf0000e,0xf0000e,0},{0x600000,0x600002,0x600004,0},0,1,0,0,default_regs_r,special_regs_w}},
/* Pokemon Stadium */ /* Pokemon Stadium */
{0x0000,0x843c,0x70,0x7f,{{0,0,0,0},{0,0,0,0},{0,0,0,0},0,1,0,0,0,special_regs_w}}, {0x0000,0x843c,0x70,0x7f,{{0,0,0,0},{0,0,0,0},{0,0,0,0},0,1,0,0,0,special_regs_w}},
/* Elf Wor */ /* Elf Wor */
{0x0080,0x3dba,0x40,0x40,{{0x55,0x0f,0xc9,0x18},{0xffffff,0xffffff,0xffffff,0xffffff},{0x400000,0x400002,0x400004,0x400006},0,0,0,0,default_regs_r,0}}, {0x0080,0x3dba,0x40,0x40,{{0x55,0x0f,0xc9,0x18},{0xffffff,0xffffff,0xffffff,0xffffff},{0x400000,0x400002,0x400004,0x400006},0,0,0,0,default_regs_r,0}},
/* Huan Le Tao Qi Shu - Smart Mouse */ /* Huan Le Tao Qi Shu - Smart Mouse */
{0x0000,0x1a28,0x40,0x40,{{0x55,0x0f,0xaa,0xf0},{0xffffff,0xffffff,0xffffff,0xffffff},{0x400000,0x400002,0x400004,0x400006},0,0,0,0,default_regs_r,0}}, {0x0000,0x1a28,0x40,0x40,{{0x55,0x0f,0xaa,0xf0},{0xffffff,0xffffff,0xffffff,0xffffff},{0x400000,0x400002,0x400004,0x400006},0,0,0,0,default_regs_r,0}},
/* Ya-Se Chuanshuo */ /* Ya-Se Chuanshuo */
{0xffff,0xd472,0x40,0x40,{{0x63,0x98,0xc9,0x18},{0xffffff,0xffffff,0xffffff,0xffffff},{0x400000,0x400002,0x400004,0x400006},0,0,0,0,default_regs_r,0}}, {0xffff,0xd472,0x40,0x40,{{0x63,0x98,0xc9,0x18},{0xffffff,0xffffff,0xffffff,0xffffff},{0x400000,0x400002,0x400004,0x400006},0,0,0,0,default_regs_r,0}},
/* Soul Blade */ /* Soul Blade */
{0x0000,0x0c5b,0x40,0x40,{{0x00,0x98,0xc9,0xF0},{0xffffff,0xffffff,0xffffff,0xffffff},{0x400000,0x400002,0x400004,0x400006},0,0,0,0,default_regs_r,0}}, {0x0000,0x0c5b,0x40,0x40,{{0x00,0x98,0xc9,0xF0},{0xffffff,0xffffff,0xffffff,0xffffff},{0x400000,0x400002,0x400004,0x400006},0,0,0,0,default_regs_r,0}},
/* King of Fighter 98 */ /* King of Fighter 98 */
{0x0000,0xd0a0,0x48,0x4f,{{0xaa,0xa0,0xf0,0xa0},{0xfc0000,0xffffff,0xffffff,0xffffff},{0x480000,0x4c82c0,0x4cdda0,0x4f8820},0,0,0,0,default_regs_r,0}}, {0x0000,0xd0a0,0x48,0x4f,{{0xaa,0xa0,0xf0,0xa0},{0xfc0000,0xffffff,0xffffff,0xffffff},{0x480000,0x4c82c0,0x4cdda0,0x4f8820},0,0,0,0,default_regs_r,0}},
/* Lian Huan Pao - Barver Battle Saga */ /* Lian Huan Pao - Barver Battle Saga */
{0x30b9,0x1c2a,0x40,0x40,{{0,0,0,0},{0,0,0,0},{0,0,0,0},0,0,0,0,default_regs_r,0}} {0x30b9,0x1c2a,0x40,0x40,{{0,0,0,0},{0,0,0,0},{0,0,0,0},0,0,0,0,default_regs_r,0}}
}; };
@ -118,7 +118,7 @@ int old_system[2] = {-1,-1};
uint8 mem_chunk[0x10000]; uint8 mem_chunk[0x10000];
/************************************************************ /************************************************************
Cart Hardware initialization Cart Hardware initialization
*************************************************************/ *************************************************************/
/* hardware that need to be reseted on power on */ /* hardware that need to be reseted on power on */
@ -132,34 +132,34 @@ void cart_hw_reset()
for (i=0x00; i<0x40; i++) for (i=0x00; i<0x40; i++)
m68k_memory_map[i].base = cart_rom + (i<<16); m68k_memory_map[i].base = cart_rom + (i<<16);
} }
/* Realtec mapper */ /* Realtec mapper */
if (cart_hw.realtec & 1) if (cart_hw.realtec & 1)
{ {
/* enable BOOTROM */ /* enable BOOTROM */
for (i=0; i<0x40; i++) m68k_memory_map[i].base = mem_chunk; for (i=0; i<0x40; i++) m68k_memory_map[i].base = mem_chunk;
for (i=0; i<8; i++) memcpy(mem_chunk + i*0x2000, cart_rom + 0x7e000, 0x2000); for (i=0; i<8; i++) memcpy(mem_chunk + i*0x2000, cart_rom + 0x7e000, 0x2000);
cart_hw.realtec |= 2; cart_hw.realtec |= 2;
} }
/* save default cartridge slot mapping */ /* save default cartridge slot mapping */
default_rom = m68k_memory_map[0].base; default_rom = m68k_memory_map[0].base;
/* SVP chip */ /* SVP chip */
if (svp) svp_reset(); if (svp) svp_reset();
} }
/* cart hardware detection */ /* cart hardware detection */
void cart_hw_init() void cart_hw_init()
{ {
int i; int i;
/********************************************** /**********************************************
DEFAULT CARTRIDGE MAPPING DEFAULT CARTRIDGE MAPPING
***********************************************/ ***********************************************/
for (i=0; i<0x40; i++) for (i=0; i<0x40; i++)
{ {
/* cartridge ROM */ /* cartridge ROM */
m68k_memory_map[i].base = cart_rom + (i<<16); m68k_memory_map[i].base = cart_rom + (i<<16);
m68k_memory_map[i].read8 = NULL; m68k_memory_map[i].read8 = NULL;
m68k_memory_map[i].read16 = NULL; m68k_memory_map[i].read16 = NULL;
@ -167,33 +167,33 @@ void cart_hw_init()
m68k_memory_map[i].write16 = m68k_unused_16_w; m68k_memory_map[i].write16 = m68k_unused_16_w;
zbank_memory_map[i].read = NULL; zbank_memory_map[i].read = NULL;
zbank_memory_map[i].write = zbank_unused_w; zbank_memory_map[i].write = zbank_unused_w;
} }
for (i=0x40; i<0x80; i++) for (i=0x40; i<0x80; i++)
{ {
/* unused area */ /* unused area */
m68k_memory_map[i].read8 = m68k_read_bus_8; m68k_memory_map[i].read8 = m68k_read_bus_8;
m68k_memory_map[i].read16 = m68k_read_bus_16; m68k_memory_map[i].read16 = m68k_read_bus_16;
m68k_memory_map[i].write8 = m68k_unused_8_w; m68k_memory_map[i].write8 = m68k_unused_8_w;
m68k_memory_map[i].write16 = m68k_unused_16_w; m68k_memory_map[i].write16 = m68k_unused_16_w;
zbank_memory_map[i].read = zbank_unused_r; zbank_memory_map[i].read = zbank_unused_r;
zbank_memory_map[i].write = zbank_unused_w; zbank_memory_map[i].write = zbank_unused_w;
} }
/* restore previous setting */ /* restore previous setting */
if (old_system[0] != -1) input.system[0] = old_system[0]; if (old_system[0] != -1) input.system[0] = old_system[0];
if (old_system[1] != -1) input.system[1] = old_system[1]; if (old_system[1] != -1) input.system[1] = old_system[1];
/********************************************** /**********************************************
EXTERNAL RAM EXTERNAL RAM
***********************************************/ ***********************************************/
sram_init(); sram_init();
eeprom_init(); eeprom_init();
if (sram.on) if (sram.on)
{ {
if (sram.custom) if (sram.custom)
{ {
/* serial EEPROM */ /* serial EEPROM */
m68k_memory_map[eeprom.type.sda_out_adr >> 16].read8 = eeprom_read_byte; m68k_memory_map[eeprom.type.sda_out_adr >> 16].read8 = eeprom_read_byte;
m68k_memory_map[eeprom.type.sda_out_adr >> 16].read16 = eeprom_read_word; m68k_memory_map[eeprom.type.sda_out_adr >> 16].read16 = eeprom_read_word;
m68k_memory_map[eeprom.type.sda_in_adr >> 16].read8 = eeprom_read_byte; m68k_memory_map[eeprom.type.sda_in_adr >> 16].read8 = eeprom_read_byte;
@ -203,10 +203,10 @@ void cart_hw_init()
zbank_memory_map[eeprom.type.sda_out_adr >> 16].read = eeprom_read_byte; zbank_memory_map[eeprom.type.sda_out_adr >> 16].read = eeprom_read_byte;
zbank_memory_map[eeprom.type.sda_in_adr >> 16].read = eeprom_read_byte; zbank_memory_map[eeprom.type.sda_in_adr >> 16].read = eeprom_read_byte;
zbank_memory_map[eeprom.type.scl_adr >> 16].write = eeprom_write_byte; zbank_memory_map[eeprom.type.scl_adr >> 16].write = eeprom_write_byte;
} }
else else
{ {
/* Static RAM (64k max.) */ /* Static RAM (64k max.) */
m68k_memory_map[sram.start >> 16].base = sram.sram; m68k_memory_map[sram.start >> 16].base = sram.sram;
m68k_memory_map[sram.start >> 16].read8 = NULL; m68k_memory_map[sram.start >> 16].read8 = NULL;
m68k_memory_map[sram.start >> 16].read16 = NULL; m68k_memory_map[sram.start >> 16].read16 = NULL;
@ -214,16 +214,16 @@ void cart_hw_init()
m68k_memory_map[sram.start >> 16].write16 = NULL; m68k_memory_map[sram.start >> 16].write16 = NULL;
zbank_memory_map[sram.start >> 16].read = NULL; zbank_memory_map[sram.start >> 16].read = NULL;
zbank_memory_map[sram.start >> 16].write = NULL; zbank_memory_map[sram.start >> 16].write = NULL;
} }
} }
/********************************************** /**********************************************
SVP CHIP SVP CHIP
***********************************************/ ***********************************************/
svp = NULL; svp = NULL;
if (strstr(rominfo.international,"Virtua Racing") != NULL) if (strstr(rominfo.international,"Virtua Racing") != NULL)
{ {
svp_init(); svp_init();
m68k_memory_map[0x30].base = svp->dram; m68k_memory_map[0x30].base = svp->dram;
m68k_memory_map[0x30].read16 = NULL; m68k_memory_map[0x30].read16 = NULL;
@ -235,30 +235,30 @@ void cart_hw_init()
m68k_memory_map[0x39].read16 = svp_read_cell_1; m68k_memory_map[0x39].read16 = svp_read_cell_1;
m68k_memory_map[0x3a].read16 = svp_read_cell_2; m68k_memory_map[0x3a].read16 = svp_read_cell_2;
} }
/* default GUN settings */ /* default GUN settings */
input.x_offset = 0x00; input.x_offset = 0x00;
input.y_offset = 0x00; input.y_offset = 0x00;
/********************************************** /**********************************************
SEGA MENACER SEGA MENACER
***********************************************/ ***********************************************/
if (strstr(rominfo.international,"MENACER") != NULL) if (strstr(rominfo.international,"MENACER") != NULL)
{ {
/* save current setting */ /* save current setting */
if (old_system[0] == -1) old_system[0] = input.system[0]; if (old_system[0] == -1) old_system[0] = input.system[0];
if (old_system[1] == -1) old_system[1] = input.system[1]; if (old_system[1] == -1) old_system[1] = input.system[1];
input.system[0] = NO_SYSTEM; input.system[0] = NO_SYSTEM;
input.system[1] = SYSTEM_MENACER; input.system[1] = SYSTEM_MENACER;
input.x_offset = 0x52; input.x_offset = 0x52;
input.y_offset = 0x00; input.y_offset = 0x00;
} }
else if (strstr(rominfo.international,"T2 ; THE ARCADE GAME") != NULL) else if (strstr(rominfo.international,"T2 ; THE ARCADE GAME") != NULL)
{ {
/* save current setting */ /* save current setting */
if (old_system[0] == -1) old_system[0] = input.system[0]; if (old_system[0] == -1) old_system[0] = input.system[0];
if (old_system[1] == -1) old_system[1] = input.system[1]; if (old_system[1] == -1) old_system[1] = input.system[1];
@ -266,10 +266,10 @@ void cart_hw_init()
input.system[1] = SYSTEM_MENACER; input.system[1] = SYSTEM_MENACER;
input.x_offset = 0x84; input.x_offset = 0x84;
input.y_offset = 0x08; input.y_offset = 0x08;
} }
else if (strstr(rominfo.international,"BODY COUNT") != NULL) else if (strstr(rominfo.international,"BODY COUNT") != NULL)
{ {
/* save current setting */ /* save current setting */
if (old_system[0] == -1) old_system[0] = input.system[0]; if (old_system[0] == -1) old_system[0] = input.system[0];
if (old_system[1] == -1) old_system[1] = input.system[1]; if (old_system[1] == -1) old_system[1] = input.system[1];
@ -277,14 +277,14 @@ void cart_hw_init()
input.system[1] = SYSTEM_MENACER; input.system[1] = SYSTEM_MENACER;
input.x_offset = 0x44; input.x_offset = 0x44;
input.y_offset = 0x18; input.y_offset = 0x18;
} }
/********************************************** /**********************************************
KONAMI JUSTIFIER KONAMI JUSTIFIER
***********************************************/ ***********************************************/
if (strstr(rominfo.international,"LETHAL ENFORCERS II") != NULL) if (strstr(rominfo.international,"LETHAL ENFORCERS II") != NULL)
{ {
/* save current setting */ /* save current setting */
if (old_system[0] == -1) old_system[0] = input.system[0]; if (old_system[0] == -1) old_system[0] = input.system[0];
if (old_system[1] == -1) old_system[1] = input.system[1]; if (old_system[1] == -1) old_system[1] = input.system[1];
@ -292,10 +292,10 @@ void cart_hw_init()
input.system[1] = SYSTEM_JUSTIFIER; input.system[1] = SYSTEM_JUSTIFIER;
input.x_offset = 0x18; input.x_offset = 0x18;
input.y_offset = 0x00; input.y_offset = 0x00;
} }
else if (strstr(rominfo.international,"LETHAL ENFORCERS") != NULL) else if (strstr(rominfo.international,"LETHAL ENFORCERS") != NULL)
{ {
/* save current setting */ /* save current setting */
if (old_system[0] == -1) old_system[0] = input.system[0]; if (old_system[0] == -1) old_system[0] = input.system[0];
if (old_system[1] == -1) old_system[1] = input.system[1]; if (old_system[1] == -1) old_system[1] = input.system[1];
@ -305,22 +305,22 @@ void cart_hw_init()
input.y_offset = 0x00; input.y_offset = 0x00;
} }
/********************************************** /**********************************************
J-CART J-CART
***********************************************/ ***********************************************/
j_cart = 0; j_cart = 0;
if (((strstr(rominfo.product,"00000000") != NULL) && (rominfo.checksum == 0x168b)) || /* Super Skidmarks, Micro Machines Military*/ if (((strstr(rominfo.product,"00000000") != NULL) && (rominfo.checksum == 0x168b)) || /* Super Skidmarks, Micro Machines Military*/
((strstr(rominfo.product,"00000000") != NULL) && (rominfo.checksum == 0x165e)) || /* Pete Sampras Tennis (1991), Micro Machines 96 */ ((strstr(rominfo.product,"00000000") != NULL) && (rominfo.checksum == 0x165e)) || /* Pete Sampras Tennis (1991), Micro Machines 96 */
((strstr(rominfo.product,"00000000") != NULL) && (rominfo.checksum == 0xcee0)) || /* Micro Machines Military (bad) */ ((strstr(rominfo.product,"00000000") != NULL) && (rominfo.checksum == 0xcee0)) || /* Micro Machines Military (bad) */
((strstr(rominfo.product,"00000000") != NULL) && (rominfo.checksum == 0x2c41)) || /* Micro Machines 96 (bad) */ ((strstr(rominfo.product,"00000000") != NULL) && (rominfo.checksum == 0x2c41)) || /* Micro Machines 96 (bad) */
((strstr(rominfo.product,"XXXXXXXX") != NULL) && (rominfo.checksum == 0xdf39)) || /* Sampras Tennis 96 */ ((strstr(rominfo.product,"XXXXXXXX") != NULL) && (rominfo.checksum == 0xdf39)) || /* Sampras Tennis 96 */
((strstr(rominfo.product,"T-123456") != NULL) && (rominfo.checksum == 0x1eae)) || /* Sampras Tennis 96 */ ((strstr(rominfo.product,"T-123456") != NULL) && (rominfo.checksum == 0x1eae)) || /* Sampras Tennis 96 */
((strstr(rominfo.product,"T-120066") != NULL) && (rominfo.checksum == 0x16a4)) || /* Pete Sampras Tennis (1994)*/ ((strstr(rominfo.product,"T-120066") != NULL) && (rominfo.checksum == 0x16a4)) || /* Pete Sampras Tennis (1994)*/
(strstr(rominfo.product,"T-120096") != NULL)) /* Micro Machines 2 */ (strstr(rominfo.product,"T-120096") != NULL)) /* Micro Machines 2 */
{ {
if (genromsize <= 0x380000) /* just to be sure (checksum might not be enough) */ if (genromsize <= 0x380000) /* just to be sure (checksum might not be enough) */
{ {
j_cart = 1; j_cart = 1;
m68k_memory_map[0x38].read16 = jcart_read; m68k_memory_map[0x38].read16 = jcart_read;
m68k_memory_map[0x38].write16 = jcart_write; m68k_memory_map[0x38].write16 = jcart_write;
m68k_memory_map[0x3f].read16 = jcart_read; m68k_memory_map[0x3f].read16 = jcart_read;
@ -333,47 +333,47 @@ void cart_hw_init()
/* PORT B by default */ /* PORT B by default */
input.system[0] = SYSTEM_GAMEPAD; input.system[0] = SYSTEM_GAMEPAD;
input.system[1] = SYSTEM_GAMEPAD; input.system[1] = SYSTEM_GAMEPAD;
} }
} }
/********************************************** /**********************************************
Mappers & HW registers Mappers & HW registers
***********************************************/ ***********************************************/
memset(&cart_hw, 0, sizeof(cart_hw)); memset(&cart_hw, 0, sizeof(cart_hw));
/* search for game into database */ /* search for game into database */
for (i=0; i < CART_CNT + 1; i++) for (i=0; i < CART_CNT + 1; i++)
{ {
/* known cart found ! */ /* known cart found ! */
if ((rominfo.checksum == rom_database[i].chk_1) && if ((rominfo.checksum == rom_database[i].chk_1) &&
(realchecksum == rom_database[i].chk_2)) (realchecksum == rom_database[i].chk_2))
{ {
/* retrieve hardware information */ /* retrieve hardware information */
memcpy(&cart_hw, &(rom_database[i].cart_hw), sizeof(cart_hw)); memcpy(&cart_hw, &(rom_database[i].cart_hw), sizeof(cart_hw));
/* initialize memory handlers for $400000-$7fffff region */ /* initialize memory handlers for $400000-$7fffff region */
int j = rom_database[i].bank_start; int j = rom_database[i].bank_start;
while (j <= rom_database[i].bank_end) while (j <= rom_database[i].bank_end)
{ {
if (cart_hw.regs_r) if (cart_hw.regs_r)
{ {
m68k_memory_map[j].read8 = cart_hw.regs_r; m68k_memory_map[j].read8 = cart_hw.regs_r;
m68k_memory_map[j].read16 = cart_hw.regs_r; m68k_memory_map[j].read16 = cart_hw.regs_r;
zbank_memory_map[j].read = cart_hw.regs_r; zbank_memory_map[j].read = cart_hw.regs_r;
} }
if (cart_hw.regs_w) if (cart_hw.regs_w)
{ {
m68k_memory_map[j].write8 = cart_hw.regs_w; m68k_memory_map[j].write8 = cart_hw.regs_w;
m68k_memory_map[j].write16 = cart_hw.regs_w; m68k_memory_map[j].write16 = cart_hw.regs_w;
zbank_memory_map[j].write = cart_hw.regs_w; zbank_memory_map[j].write = cart_hw.regs_w;
} }
j++; j++;
} }
/* leave loop */ /* leave loop */
i = CART_CNT + 1; i = CART_CNT + 1;
} }
} }
#if M68K_EMULATE_ADDRESS_ERROR #if M68K_EMULATE_ADDRESS_ERROR
/* default behavior */ /* default behavior */
@ -403,26 +403,26 @@ void cart_hw_init()
cart_hw.bankshift = 1; cart_hw.bankshift = 1;
} }
/* default write handler for !TIME signal */ /* default write handler for !TIME signal */
if (!cart_hw.time_w) cart_hw.time_w = default_time_w; if (!cart_hw.time_w) cart_hw.time_w = default_time_w;
} }
/************************************************************ /************************************************************
MAPPER handlers MAPPER handlers
*************************************************************/ *************************************************************/
/* /*
"official" ROM/RAM switch "official" ROM/RAM switch
*/ */
static inline void sega_mapper_w(uint32 address, uint32 data) static inline void sega_mapper_w(uint32 address, uint32 data)
{ {
uint32 i,slot = (address >> 1) & 7; uint32 i,slot = (address >> 1) & 7;
uint8 *src; uint8 *src;
switch (slot) switch (slot)
{ {
case 0: case 0:
/* ROM/SRAM switch (Phantasy Star IV, Story of Thor/Beyond Oasis, Sonic 3 & Knuckles) */ /* ROM/SRAM switch (Phantasy Star IV, Story of Thor/Beyond Oasis, Sonic 3 & Knuckles) */
if (data & 1) if (data & 1)
{ {
/* SRAM enabled */ /* SRAM enabled */
@ -448,38 +448,38 @@ static inline void sega_mapper_w(uint32 address, uint32 data)
/* ROM enabled */ /* ROM enabled */
m68k_memory_map[0x20].base = cart_rom + 0x200000; m68k_memory_map[0x20].base = cart_rom + 0x200000;
} }
break; break;
default: default:
/* ROM Bankswitch (Super Street Fighter 2) /* ROM Bankswitch (Super Street Fighter 2)
documented by Bart Trzynadlowski (http://www.trzy.org/files/ssf2.txt) documented by Bart Trzynadlowski (http://www.trzy.org/files/ssf2.txt)
*/ */
slot = slot << 3; /* 8 x 512k banks */ slot = slot << 3; /* 8 x 512k banks */
src = cart_rom + (data << 19); src = cart_rom + (data << 19);
for (i=0; i<8; i++) m68k_memory_map[slot++].base = src + (i<<16); for (i=0; i<8; i++) m68k_memory_map[slot++].base = src + (i<<16);
break; break;
} }
} }
/* /*
custom ROM Bankswitch used by pirate "Multi-in-1" carts custom ROM Bankswitch used by pirate "Multi-in-1" carts
*/ */
static inline void multi_mapper_w(uint32 address, uint32 data) static inline void multi_mapper_w(uint32 address, uint32 data)
{ {
int i; int i;
cart_hw.bankshift = 1; cart_hw.bankshift = 1;
/* 64 x 64k banks */ /* 64 x 64k banks */
for (i=0; i<64; i++) for (i=0; i<64; i++)
{ {
m68k_memory_map[i].base = &cart_rom[((address++) & 0x3f) << 16]; m68k_memory_map[i].base = &cart_rom[((address++) & 0x3f) << 16];
} }
} }
/* /*
Special ROM Bankswitch used for copy protection Special ROM Bankswitch used for copy protection
Used by unlicensed cartridges (Lion King III, Super King Kong 99) Used by unlicensed cartridges (Lion King III, Super King Kong 99)
*/ */
void special_mapper_w(uint32 address, uint32 data) void special_mapper_w(uint32 address, uint32 data)
{ {
@ -490,60 +490,60 @@ void special_mapper_w(uint32 address, uint32 data)
} }
/* /*
Realtec ROM Bankswitch (Earth Defend, Balloon Boy & Funny World, Whac-A-Critter) Realtec ROM Bankswitch (Earth Defend, Balloon Boy & Funny World, Whac-A-Critter)
*/ */
void realtec_mapper_w(uint32 address, uint32 data) void realtec_mapper_w(uint32 address, uint32 data)
{ {
int i; int i;
uint32 base; uint32 base;
/* 32 x 128k banks */ /* 32 x 128k banks */
switch (address) switch (address)
{ {
case 0x404000: /* three lower bits of ROM base address */ case 0x404000: /* three lower bits of ROM base address */
cart_hw.regs[0] = data & 7; cart_hw.regs[0] = data & 7;
base = ((data & 7) | (cart_hw.regs[1] << 2)); base = ((data & 7) | (cart_hw.regs[1] << 2));
for (i=0; i<=cart_hw.regs[2]; i++) for (i=0; i<=cart_hw.regs[2]; i++)
{ {
m68k_memory_map[i*2].base = &cart_rom[((base + i)*2 & 0x3f) << 16]; m68k_memory_map[i*2].base = &cart_rom[((base + i)*2 & 0x3f) << 16];
m68k_memory_map[i*2+1].base = &cart_rom[(((base + i)*2 + 1) & 0x3f) << 16]; m68k_memory_map[i*2+1].base = &cart_rom[(((base + i)*2 + 1) & 0x3f) << 16];
} }
return; return;
case 0x400000: /* two higher bits of ROM base address */ case 0x400000: /* two higher bits of ROM base address */
cart_hw.regs[1] = data & 6; cart_hw.regs[1] = data & 6;
base = cart_hw.regs[0] | ((data & 6) << 2); base = cart_hw.regs[0] | ((data & 6) << 2);
for (i=0; i<=cart_hw.regs[2]; i++) for (i=0; i<=cart_hw.regs[2]; i++)
{ {
m68k_memory_map[i*2].base = &cart_rom[((base + i)*2 & 0x3f) << 16]; m68k_memory_map[i*2].base = &cart_rom[((base + i)*2 & 0x3f) << 16];
m68k_memory_map[i*2+1].base = &cart_rom[(((base + i)*2 + 1) & 0x3f) << 16]; m68k_memory_map[i*2+1].base = &cart_rom[(((base + i)*2 + 1) & 0x3f) << 16];
} }
return; return;
case 0x402000: /* number of 128k blocks to map */ case 0x402000: /* number of 128k blocks to map */
cart_hw.regs[2] = data & 0x1f; cart_hw.regs[2] = data & 0x1f;
base = cart_hw.regs[0] | (cart_hw.regs[1] << 2); base = cart_hw.regs[0] | (cart_hw.regs[1] << 2);
for (i=0; i<=(data & 0x1f); i++) for (i=0; i<=(data & 0x1f); i++)
{ {
m68k_memory_map[i*2].base = &cart_rom[((base + i)*2 & 0x3f) << 16]; m68k_memory_map[i*2].base = &cart_rom[((base + i)*2 & 0x3f) << 16];
m68k_memory_map[i*2+1].base = &cart_rom[(((base + i)*2 + 1) & 0x3f) << 16]; m68k_memory_map[i*2+1].base = &cart_rom[(((base + i)*2 + 1) & 0x3f) << 16];
} }
return; return;
} }
} }
/* Game no Kanzume Otokuyou ROM Mapper */ /* Game no Kanzume Otokuyou ROM Mapper */
void seganet_mapper_w(uint32 address, uint32 data) void seganet_mapper_w(uint32 address, uint32 data)
{ {
if ((address & 0xff) == 0xf1) if ((address & 0xff) == 0xf1)
{ {
int i; int i;
if (data & 1) if (data & 1)
{ {
/* ROM Write protected */ /* ROM Write protected */
for (i=0; i<0x40; i++) for (i=0; i<0x40; i++)
{ {
m68k_memory_map[i].write8 = m68k_unused_8_w; m68k_memory_map[i].write8 = m68k_unused_8_w;
m68k_memory_map[i].write16 = m68k_unused_16_w; m68k_memory_map[i].write16 = m68k_unused_16_w;
zbank_memory_map[i].write = zbank_unused_w; zbank_memory_map[i].write = zbank_unused_w;
@ -557,99 +557,99 @@ void seganet_mapper_w(uint32 address, uint32 data)
m68k_memory_map[i].write8 = NULL; m68k_memory_map[i].write8 = NULL;
m68k_memory_map[i].write16 = NULL; m68k_memory_map[i].write16 = NULL;
zbank_memory_map[i].write = NULL; zbank_memory_map[i].write = NULL;
} }
} }
} }
} }
/* /*
RADICA ROM Bankswitch (use !TIME) RADICA ROM Bankswitch (use !TIME)
*/ */
uint32 radica_mapper_r(uint32 address) uint32 radica_mapper_r(uint32 address)
{ {
int i = 0; int i = 0;
address = (address >> 1); address = (address >> 1);
/* 64 x 64k banks */ /* 64 x 64k banks */
for (i = 0; i < 64; i++) for (i = 0; i < 64; i++)
{ {
m68k_memory_map[i].base = &cart_rom[((address++)& 0x3f)<< 16]; m68k_memory_map[i].base = &cart_rom[((address++)& 0x3f)<< 16];
} }
return 0xff; return 0xff;
} }
/************************************************************ /************************************************************
default !TIME signal handler default !TIME signal handler
*************************************************************/ *************************************************************/
/* default ROM bankswitch */ /* default ROM bankswitch */
void default_time_w(uint32 address, uint32 data) void default_time_w(uint32 address, uint32 data)
{ {
if ((address & 0xf1) == 0xf1) sega_mapper_w(address, data); if ((address & 0xf1) == 0xf1) sega_mapper_w(address, data);
else if (address < 0xa13040) multi_mapper_w(address, data); else if (address < 0xa13040) multi_mapper_w(address, data);
} }
/************************************************************ /************************************************************
Internal register handlers Internal register handlers
*************************************************************/ *************************************************************/
uint32 default_regs_r(uint32 address) uint32 default_regs_r(uint32 address)
{ {
int i; int i;
for (i=0; i<4; i++) for (i=0; i<4; i++)
{ {
if ((address & cart_hw.mask[i]) == cart_hw.addr[i]) if ((address & cart_hw.mask[i]) == cart_hw.addr[i])
return cart_hw.regs[i]; return cart_hw.regs[i];
} }
/* unused */ /* unused */
return 0xffff; return 0xffff;
} }
void default_regs_w(uint32 address, uint32 data) void default_regs_w(uint32 address, uint32 data)
{ {
int i; int i;
for (i=0; i<4; i++) for (i=0; i<4; i++)
{ {
if ((address & cart_hw.mask[i]) == cart_hw.addr[i]) if ((address & cart_hw.mask[i]) == cart_hw.addr[i])
{ {
cart_hw.regs[i] = data; cart_hw.regs[i] = data;
} }
} }
} }
/* special register behaviour (Lion King III, Super Donkey Kong 99) */ /* special register behaviour (Lion King III, Super Donkey Kong 99) */
void special_regs_w(uint32 address, uint32 data) void special_regs_w(uint32 address, uint32 data)
{ {
/* ROM bankswitch */ /* ROM bankswitch */
if ((address >> 16) > 0x6f) if ((address >> 16) > 0x6f)
{ {
special_mapper_w(address, data); special_mapper_w(address, data);
return; return;
} }
/* write regs */ /* write regs */
default_regs_w(address, data); default_regs_w(address, data);
/* bitswapping (documented by Haze) */ /* bitswapping (documented by Haze) */
uint32 temp = cart_hw.regs[0]; uint32 temp = cart_hw.regs[0];
switch (cart_hw.regs[1]) switch (cart_hw.regs[1])
{ {
case 1: case 1:
cart_hw.regs[2] = (temp >> 1); cart_hw.regs[2] = (temp >> 1);
return; return;
case 2: case 2:
cart_hw.regs[2] = ((temp >> 4) | ((temp & 0x0F) << 4)); cart_hw.regs[2] = ((temp >> 4) | ((temp & 0x0F) << 4));
return; return;
default: default:
cart_hw.regs[2] = (((temp >> 7) & 0x01) | ((temp >> 5) & 0x02) | cart_hw.regs[2] = (((temp >> 7) & 0x01) | ((temp >> 5) & 0x02) |
((temp >> 3) & 0x04) | ((temp >> 1) & 0x08) | ((temp >> 3) & 0x04) | ((temp >> 1) & 0x08) |
((temp << 1) & 0x10) | ((temp << 3) & 0x20) | ((temp << 1) & 0x10) | ((temp << 3) & 0x20) |
((temp << 5) & 0x40) | ((temp << 7) & 0x80)); ((temp << 5) & 0x40) | ((temp << 7) & 0x80));
return; return;
} }
} }

View File

@ -30,15 +30,15 @@
/* Hardware description */ /* Hardware description */
typedef struct typedef struct
{ {
uint8 regs[4]; /* internal registers (R/W) */ uint8 regs[4]; /* internal registers (R/W) */
uint32 mask[4]; /* registers address mask */ uint32 mask[4]; /* registers address mask */
uint32 addr[4]; /* registers address */ uint32 addr[4]; /* registers address */
uint32 realtec; /* bit 0: realtec mapper detected, bit 1: bootrom enabled */ uint32 realtec; /* bit 0: realtec mapper detected, bit 1: bootrom enabled */
uint32 bankshift; /* cartridge with bankshift mecanism */ uint32 bankshift; /* cartridge with bankshift mecanism */
unsigned int (*time_r)(unsigned int address); /* !TIME signal ($a130xx) read handler */ unsigned int (*time_r)(unsigned int address); /* !TIME signal ($a130xx) read handler */
void (*time_w)(unsigned int address, unsigned int data); /* !TIME signal ($a130xx) write handler */ void (*time_w)(unsigned int address, unsigned int data); /* !TIME signal ($a130xx) write handler */
unsigned int (*regs_r)(unsigned int address); /* cart hardware region ($400000-$7fffff) read handler */ unsigned int (*regs_r)(unsigned int address); /* cart hardware region ($400000-$7fffff) read handler */
void (*regs_w)(unsigned int address, unsigned int data); /* cart hardware region ($400000-$7fffff) write handler */ void (*regs_w)(unsigned int address, unsigned int data); /* cart hardware region ($400000-$7fffff) write handler */
} T_CART_HW; } T_CART_HW;
/* global variables */ /* global variables */

View File

@ -23,53 +23,53 @@
typedef struct typedef struct
{ {
char game_id[14]; char game_id[14];
uint16 chk; uint16 chk;
T_EEPROM_TYPE type; T_EEPROM_TYPE type;
} T_GAME_ENTRY; } T_GAME_ENTRY;
T_GAME_ENTRY database[24] = T_GAME_ENTRY database[24] =
{ {
/* ACCLAIM mappers */ /* ACCLAIM mappers */
/* 24C02 (old mapper) */ /* 24C02 (old mapper) */
{{"T-081326" }, 0, {8, 0xFF, 0xFF, 0x200001, 0x200001, 0x200001, 0, 1, 1}}, /* NBA Jam (UE) */ {{"T-081326" }, 0, {8, 0xFF, 0xFF, 0x200001, 0x200001, 0x200001, 0, 1, 1}}, /* NBA Jam (UE) */
{{"T-81033" }, 0, {8, 0xFF, 0xFF, 0x200001, 0x200001, 0x200001, 0, 1, 1}}, /* NBA Jam (J) */ {{"T-81033" }, 0, {8, 0xFF, 0xFF, 0x200001, 0x200001, 0x200001, 0, 1, 1}}, /* NBA Jam (J) */
/* 24C02 */ /* 24C02 */
{{"T-81406" }, 0, {8, 0xFF, 0xFF, 0x200001, 0x200001, 0x200000, 0, 0, 0}}, /* NBA Jam TE */ {{"T-81406" }, 0, {8, 0xFF, 0xFF, 0x200001, 0x200001, 0x200000, 0, 0, 0}}, /* NBA Jam TE */
{{"T-081276" }, 0, {8, 0xFF, 0xFF, 0x200001, 0x200001, 0x200000, 0, 0, 0}}, /* NFL Quarterback Club */ {{"T-081276" }, 0, {8, 0xFF, 0xFF, 0x200001, 0x200001, 0x200000, 0, 0, 0}}, /* NFL Quarterback Club */
/* 24C16 */ /* 24C16 */
{{"T-081586" }, 0, {8, 0x7FF, 0x7FF, 0x200001, 0x200001, 0x200000, 0, 0, 0}}, /* NFL Quarterback Club '96 */ {{"T-081586" }, 0, {8, 0x7FF, 0x7FF, 0x200001, 0x200001, 0x200000, 0, 0, 0}}, /* NFL Quarterback Club '96 */
/* 24C65 */ /* 24C65 */
{{"T-81576" }, 0, {16, 0x1FFF, 0x1FFF, 0x200001, 0x200001, 0x200000, 0, 0, 0}}, /* College Slam */ {{"T-81576" }, 0, {16, 0x1FFF, 0x1FFF, 0x200001, 0x200001, 0x200000, 0, 0, 0}}, /* College Slam */
{{"T-81476" }, 0, {16, 0x1FFF, 0x1FFF, 0x200001, 0x200001, 0x200000, 0, 0, 0}}, /* Frank Thomas Big Hurt Baseball */ {{"T-81476" }, 0, {16, 0x1FFF, 0x1FFF, 0x200001, 0x200001, 0x200000, 0, 0, 0}}, /* Frank Thomas Big Hurt Baseball */
/* EA mapper (24C01 only) */ /* EA mapper (24C01 only) */
{{"T-50396" }, 0, {7, 0x7F, 0x7F, 0x200001, 0x200001, 0x200001, 7, 7, 6}}, /* NHLPA Hockey 93 (UE) */ {{"T-50396" }, 0, {7, 0x7F, 0x7F, 0x200001, 0x200001, 0x200001, 7, 7, 6}}, /* NHLPA Hockey 93 (UE) */
{{"T-50176" }, 0, {7, 0x7F, 0x7F, 0x200001, 0x200001, 0x200001, 7, 7, 6}}, /* Rings of Power */ {{"T-50176" }, 0, {7, 0x7F, 0x7F, 0x200001, 0x200001, 0x200001, 7, 7, 6}}, /* Rings of Power */
/* SEGA mapper (24C01 only) */ /* SEGA mapper (24C01 only) */
{{"T-12046" }, 0, {7, 0x7F, 0x7F, 0x200001, 0x200001, 0x200001, 0, 0, 1}}, /* Megaman - The Wily Wars */ {{"T-12046" }, 0, {7, 0x7F, 0x7F, 0x200001, 0x200001, 0x200001, 0, 0, 1}}, /* Megaman - The Wily Wars */
{{"T-12053" }, 0xEA80, {7, 0x7F, 0x7F, 0x200001, 0x200001, 0x200001, 0, 0, 1}}, /* Rockman Mega World (J) [A] */ {{"T-12053" }, 0xEA80, {7, 0x7F, 0x7F, 0x200001, 0x200001, 0x200001, 0, 0, 1}}, /* Rockman Mega World (J) [A] */
{{"MK-1215" }, 0, {7, 0x7F, 0x7F, 0x200001, 0x200001, 0x200001, 0, 0, 1}}, /* Evander 'Real Deal' Holyfield's Boxing */ {{"MK-1215" }, 0, {7, 0x7F, 0x7F, 0x200001, 0x200001, 0x200001, 0, 0, 1}}, /* Evander 'Real Deal' Holyfield's Boxing */
{{"MK-1228" }, 0, {7, 0x7F, 0x7F, 0x200001, 0x200001, 0x200001, 0, 0, 1}}, /* Greatest Heavyweights of the Ring (U) */ {{"MK-1228" }, 0, {7, 0x7F, 0x7F, 0x200001, 0x200001, 0x200001, 0, 0, 1}}, /* Greatest Heavyweights of the Ring (U) */
{{"G-5538" }, 0, {7, 0x7F, 0x7F, 0x200001, 0x200001, 0x200001, 0, 0, 1}}, /* Greatest Heavyweights of the Ring (J) */ {{"G-5538" }, 0, {7, 0x7F, 0x7F, 0x200001, 0x200001, 0x200001, 0, 0, 1}}, /* Greatest Heavyweights of the Ring (J) */
{{"PR-1993" }, 0, {7, 0x7F, 0x7F, 0x200001, 0x200001, 0x200001, 0, 0, 1}}, /* Greatest Heavyweights of the Ring (E) */ {{"PR-1993" }, 0, {7, 0x7F, 0x7F, 0x200001, 0x200001, 0x200001, 0, 0, 1}}, /* Greatest Heavyweights of the Ring (E) */
{{"G-4060" }, 0, {7, 0x7F, 0x7F, 0x200001, 0x200001, 0x200001, 0, 0, 1}}, /* Wonderboy in Monster World */ {{"G-4060" }, 0, {7, 0x7F, 0x7F, 0x200001, 0x200001, 0x200001, 0, 0, 1}}, /* Wonderboy in Monster World */
{{"00001211-00"}, 0, {7, 0x7F, 0x7F, 0x200001, 0x200001, 0x200001, 0, 0, 1}}, /* Sports Talk Baseball */ {{"00001211-00"}, 0, {7, 0x7F, 0x7F, 0x200001, 0x200001, 0x200001, 0, 0, 1}}, /* Sports Talk Baseball */
/* CODEMASTERS mapper */ /* CODEMASTERS mapper */
/* 24C01 */ /* 24C01 */
{{"T-120106"}, 0, {7, 0x7F, 0x7F, 0x300000, 0x380001, 0x300000, 0, 7, 1}}, /* Brian Lara Cricket */ {{"T-120106"}, 0, {7, 0x7F, 0x7F, 0x300000, 0x380001, 0x300000, 0, 7, 1}}, /* Brian Lara Cricket */
/* 24C08 */ /* 24C08 */
{{"T-120096" }, 0, {8, 0x3FF, 0x3FF, 0x300000, 0x380001, 0x300000, 0, 7, 1}}, /* Micro Machines 2 - Turbo Tournament (E) */ {{"T-120096" }, 0, {8, 0x3FF, 0x3FF, 0x300000, 0x380001, 0x300000, 0, 7, 1}}, /* Micro Machines 2 - Turbo Tournament (E) */
{{"00000000-00"}, 0x168B, {8, 0x3FF, 0x3FF, 0x300000, 0x380001, 0x300000, 0, 7, 1}}, /* Micro Machines Military */ {{"00000000-00"}, 0x168B, {8, 0x3FF, 0x3FF, 0x300000, 0x380001, 0x300000, 0, 7, 1}}, /* Micro Machines Military */
{{"00000000-00"}, 0xCEE0, {8, 0x3FF, 0x3FF, 0x300000, 0x380001, 0x300000, 0, 7, 1}}, /* Micro Machines Military (Bad)*/ {{"00000000-00"}, 0xCEE0, {8, 0x3FF, 0x3FF, 0x300000, 0x380001, 0x300000, 0, 7, 1}}, /* Micro Machines Military (Bad)*/
/* 24C16 */ /* 24C16 */
{{"00000000-00"}, 0x165E, {8, 0x7FF, 0x7FF, 0x300000, 0x380001, 0x300000, 0, 7, 1}}, /* Micro Machines Turbo Tournament 96 */ {{"00000000-00"}, 0x165E, {8, 0x7FF, 0x7FF, 0x300000, 0x380001, 0x300000, 0, 7, 1}}, /* Micro Machines Turbo Tournament 96 */
{{"00000000-00"}, 0x2C41, {8, 0x7FF, 0x7FF, 0x300000, 0x380001, 0x300000, 0, 7, 1}}, /* Micro Machines Turbo Tournament 96 (Bad)*/ {{"00000000-00"}, 0x2C41, {8, 0x7FF, 0x7FF, 0x300000, 0x380001, 0x300000, 0, 7, 1}}, /* Micro Machines Turbo Tournament 96 (Bad)*/
/* 24C65 */ /* 24C65 */
{{"T-120146-50"}, 0, {16, 0x1FFF, 0x1FFF, 0x300000, 0x380001, 0x300000, 0, 7, 1}} /* Brian Lara Cricket 96, Shane Warne Cricket */ {{"T-120146-50"}, 0, {16, 0x1FFF, 0x1FFF, 0x300000, 0x380001, 0x300000, 0, 7, 1}} /* Brian Lara Cricket 96, Shane Warne Cricket */
}; };
@ -77,85 +77,85 @@ T_EEPROM eeprom;
void eeprom_init() void eeprom_init()
{ {
uint8 i = 0; uint8 i = 0;
/* initialize eeprom */
memset(&eeprom, 0, sizeof(T_EEPROM));
eeprom.sda = eeprom.old_sda = 1;
eeprom.scl = eeprom.old_scl = 1;
eeprom.state = STAND_BY;
sram.custom = 0; /* initialize eeprom */
memset(&eeprom, 0, sizeof(T_EEPROM));
/* look into game database */ eeprom.sda = eeprom.old_sda = 1;
while ((i<24) && (!sram.custom)) eeprom.scl = eeprom.old_scl = 1;
{ eeprom.state = STAND_BY;
if (strstr(rominfo.product,database[i].game_id) != NULL)
{
/* additional check (Micro Machines, Rockman Mega World) */
if ((database[i].chk == 0) || (database[i].chk == rominfo.checksum))
{
sram.custom = 1;
sram.on = 1;
sram.write = 1;
memcpy(&eeprom.type, &database[i].type, sizeof(T_EEPROM_TYPE));
}
}
i++;
}
/* Game not found in database but header seems to indicate it uses EEPROM */ sram.custom = 0;
/* look into game database */
while ((i<24) && (!sram.custom))
{
if (strstr(rominfo.product,database[i].game_id) != NULL)
{
/* additional check (Micro Machines, Rockman Mega World) */
if ((database[i].chk == 0) || (database[i].chk == rominfo.checksum))
{
sram.custom = 1;
sram.on = 1;
sram.write = 1;
memcpy(&eeprom.type, &database[i].type, sizeof(T_EEPROM_TYPE));
}
}
i++;
}
/* Game not found in database but header seems to indicate it uses EEPROM */
if (!sram.custom) if (!sram.custom)
{ {
if ((sram.end - sram.start) < 2) if ((sram.end - sram.start) < 2)
{ {
sram.custom = 1; sram.custom = 1;
sram.on = 1; sram.on = 1;
sram.write = 1; sram.write = 1;
/* set SEGA mapper as default */ /* set SEGA mapper as default */
memcpy(&eeprom.type, &database[9].type, sizeof(T_EEPROM_TYPE)); memcpy(&eeprom.type, &database[9].type, sizeof(T_EEPROM_TYPE));
} }
} }
} }
static inline void Detect_START() static inline void Detect_START()
{ {
if (eeprom.old_scl && eeprom.scl) if (eeprom.old_scl && eeprom.scl)
{ {
if (eeprom.old_sda && !eeprom.sda) if (eeprom.old_sda && !eeprom.sda)
{ {
eeprom.cycles = 0; eeprom.cycles = 0;
eeprom.slave_mask = 0; eeprom.slave_mask = 0;
if (eeprom.type.address_bits == 7) if (eeprom.type.address_bits == 7)
{ {
eeprom.word_address = 0; eeprom.word_address = 0;
eeprom.state = GET_WORD_ADR_7BITS; eeprom.state = GET_WORD_ADR_7BITS;
} }
else eeprom.state = GET_SLAVE_ADR; else eeprom.state = GET_SLAVE_ADR;
} }
} }
} }
static inline void Detect_STOP() static inline void Detect_STOP()
{ {
if (eeprom.old_scl && eeprom.scl) if (eeprom.old_scl && eeprom.scl)
{ {
if (!eeprom.old_sda && eeprom.sda) if (!eeprom.old_sda && eeprom.sda)
{ {
eeprom.state = STAND_BY; eeprom.state = STAND_BY;
} }
} }
} }
void eeprom_write(uint32 address, uint32 value, uint32 word_access) void eeprom_write(uint32 address, uint32 value, uint32 word_access)
{ {
/* decode SCL and SDA value */ /* decode SCL and SDA value */
if (word_access) if (word_access)
{ {
/* 16-bits access */ /* 16-bits access */
if (eeprom.type.sda_in_adr == address) eeprom.sda = (value >> (8 + eeprom.type.sda_in_bit)) & 1; /* MSB */ if (eeprom.type.sda_in_adr == address) eeprom.sda = (value >> (8 + eeprom.type.sda_in_bit)) & 1; /* MSB */
else if (eeprom.type.sda_in_adr == (address | 1)) eeprom.sda = (value >> eeprom.type.sda_in_bit) & 1; /* LSB */ else if (eeprom.type.sda_in_adr == (address | 1)) eeprom.sda = (value >> eeprom.type.sda_in_bit) & 1; /* LSB */
else eeprom.sda = eeprom.old_sda; else eeprom.sda = eeprom.old_sda;
if (eeprom.type.scl_adr == address) eeprom.scl = (value >> (8 + eeprom.type.scl_bit)) & 1; /* MSB */ if (eeprom.type.scl_adr == address) eeprom.scl = (value >> (8 + eeprom.type.scl_bit)) & 1; /* MSB */
@ -170,284 +170,282 @@ void eeprom_write(uint32 address, uint32 value, uint32 word_access)
if (eeprom.type.scl_adr == address) eeprom.scl = (value >> eeprom.type.scl_bit) & 1; if (eeprom.type.scl_adr == address) eeprom.scl = (value >> eeprom.type.scl_bit) & 1;
else eeprom.scl = eeprom.old_scl; else eeprom.scl = eeprom.old_scl;
} }
/* EEPROM current state */ /* EEPROM current state */
switch (eeprom.state) switch (eeprom.state)
{ {
/* Standby Mode */ /* Standby Mode */
case STAND_BY: case STAND_BY:
Detect_START(); Detect_START();
Detect_STOP(); Detect_STOP();
break; break;
/* Suspended Mode */
case WAIT_STOP:
Detect_STOP();
break;
/* Get Word Address 7 bits: MODE-1 only (24C01)
* and R/W bit
*/
case GET_WORD_ADR_7BITS:
Detect_START();
Detect_STOP();
/* look for SCL LOW to HIGH transition */
if (!eeprom.old_scl && eeprom.scl)
{
if (eeprom.cycles == 0) eeprom.cycles ++;
}
/* Suspended Mode */ /* look for SCL HIGH to LOW transition */
case WAIT_STOP: if (eeprom.old_scl && !eeprom.scl && (eeprom.cycles > 0))
Detect_STOP(); {
break; if (eeprom.cycles < 8)
/* Get Word Address 7 bits: MODE-1 only (24C01)
* and R/W bit
*/
case GET_WORD_ADR_7BITS:
Detect_START();
Detect_STOP();
/* look for SCL LOW to HIGH transition */
if (!eeprom.old_scl && eeprom.scl)
{
if (eeprom.cycles == 0) eeprom.cycles ++;
}
/* look for SCL HIGH to LOW transition */
if (eeprom.old_scl && !eeprom.scl && (eeprom.cycles > 0))
{
if (eeprom.cycles < 8)
{ {
eeprom.word_address |= (eeprom.old_sda << (7 - eeprom.cycles)); eeprom.word_address |= (eeprom.old_sda << (7 - eeprom.cycles));
} }
else if (eeprom.cycles == 8) else if (eeprom.cycles == 8)
{ {
eeprom.rw = eeprom.old_sda; eeprom.rw = eeprom.old_sda;
} }
else else
{ /* ACK CYCLE */ { /* ACK CYCLE */
eeprom.cycles = 0; eeprom.cycles = 0;
eeprom.word_address &= eeprom.type.size_mask; eeprom.word_address &= eeprom.type.size_mask;
eeprom.state = eeprom.rw ? READ_DATA : WRITE_DATA; eeprom.state = eeprom.rw ? READ_DATA : WRITE_DATA;
} }
eeprom.cycles ++; eeprom.cycles ++;
} }
break; break;
/* Get Slave Address (3bits) : MODE-2 & MODE-3 only (24C01 - 24C512) (0-3bits, depending on the array size) /* Get Slave Address (3bits) : MODE-2 & MODE-3 only (24C01 - 24C512) (0-3bits, depending on the array size)
* or/and Word Address MSB: MODE-2 only (24C04 - 24C16) (0-3bits, depending on the array size) * or/and Word Address MSB: MODE-2 only (24C04 - 24C16) (0-3bits, depending on the array size)
* and R/W bit * and R/W bit
*/ */
case GET_SLAVE_ADR: case GET_SLAVE_ADR:
Detect_START(); Detect_START();
Detect_STOP(); Detect_STOP();
/* look for SCL LOW to HIGH transition */ /* look for SCL LOW to HIGH transition */
if (!eeprom.old_scl && eeprom.scl) if (!eeprom.old_scl && eeprom.scl)
{ {
if (eeprom.cycles == 0) eeprom.cycles ++; if (eeprom.cycles == 0) eeprom.cycles ++;
} }
/* look for SCL HIGH to LOW transition */ /* look for SCL HIGH to LOW transition */
if (eeprom.old_scl && !eeprom.scl && (eeprom.cycles > 0)) if (eeprom.old_scl && !eeprom.scl && (eeprom.cycles > 0))
{ {
if ((eeprom.cycles > 4) && (eeprom.cycles <8)) if ((eeprom.cycles > 4) && (eeprom.cycles <8))
{ {
if ((eeprom.type.address_bits == 16) || if ((eeprom.type.address_bits == 16) ||
(eeprom.type.size_mask < (1 << (15 - eeprom.cycles)))) (eeprom.type.size_mask < (1 << (15 - eeprom.cycles))))
{ {
/* this is a SLAVE ADDRESS bit */ /* this is a SLAVE ADDRESS bit */
eeprom.slave_mask |= (eeprom.old_sda << (7 - eeprom.cycles)); eeprom.slave_mask |= (eeprom.old_sda << (7 - eeprom.cycles));
} }
else else
{ {
/* this is a WORD ADDRESS high bit */ /* this is a WORD ADDRESS high bit */
if (eeprom.old_sda) eeprom.word_address |= (1 << (15 - eeprom.cycles)); if (eeprom.old_sda) eeprom.word_address |= (1 << (15 - eeprom.cycles));
else eeprom.word_address &= ~(1 << (15 - eeprom.cycles)); else eeprom.word_address &= ~(1 << (15 - eeprom.cycles));
} }
} }
else if (eeprom.cycles == 8) eeprom.rw = eeprom.old_sda; else if (eeprom.cycles == 8) eeprom.rw = eeprom.old_sda;
else if (eeprom.cycles > 8) else if (eeprom.cycles > 8)
{ {
/* ACK CYCLE */ /* ACK CYCLE */
eeprom.cycles = 0; eeprom.cycles = 0;
if (eeprom.type.address_bits == 16) if (eeprom.type.address_bits == 16)
{ {
/* two ADDRESS bytes */ /* two ADDRESS bytes */
eeprom.state = eeprom.rw ? READ_DATA : GET_WORD_ADR_HIGH; eeprom.state = eeprom.rw ? READ_DATA : GET_WORD_ADR_HIGH;
eeprom.slave_mask <<= 16; eeprom.slave_mask <<= 16;
} }
else else
{ {
/* one ADDRESS byte */ /* one ADDRESS byte */
eeprom.state = eeprom.rw ? READ_DATA : GET_WORD_ADR_LOW; eeprom.state = eeprom.rw ? READ_DATA : GET_WORD_ADR_LOW;
eeprom.slave_mask <<= 8; eeprom.slave_mask <<= 8;
} }
} }
eeprom.cycles ++; eeprom.cycles ++;
} }
break; break;
/* Get Word Address MSB (4-8bits depending on the array size) /* Get Word Address MSB (4-8bits depending on the array size)
* MODE-3 only (24C32 - 24C512) * MODE-3 only (24C32 - 24C512)
*/ */
case GET_WORD_ADR_HIGH: case GET_WORD_ADR_HIGH:
Detect_START(); Detect_START();
Detect_STOP(); Detect_STOP();
/* look for SCL HIGH to LOW transition */ /* look for SCL HIGH to LOW transition */
if (eeprom.old_scl && !eeprom.scl) if (eeprom.old_scl && !eeprom.scl)
{ {
if (eeprom.cycles < 9) if (eeprom.cycles < 9)
{ {
if ((eeprom.type.size_mask + 1) < (1 << (17 - eeprom.cycles))) if ((eeprom.type.size_mask + 1) < (1 << (17 - eeprom.cycles)))
{ {
/* ignored bit: slave mask should be right-shifted by one */ /* ignored bit: slave mask should be right-shifted by one */
eeprom.slave_mask >>= 1; eeprom.slave_mask >>= 1;
} }
else else
{ {
/* this is a WORD ADDRESS high bit */ /* this is a WORD ADDRESS high bit */
if (eeprom.old_sda) eeprom.word_address |= (1 << (16 - eeprom.cycles)); if (eeprom.old_sda) eeprom.word_address |= (1 << (16 - eeprom.cycles));
else eeprom.word_address &= ~(1 << (16 - eeprom.cycles)); else eeprom.word_address &= ~(1 << (16 - eeprom.cycles));
} }
eeprom.cycles ++; eeprom.cycles ++;
} }
else else
{ {
/* ACK CYCLE */ /* ACK CYCLE */
eeprom.cycles = 1; eeprom.cycles = 1;
eeprom.state = GET_WORD_ADR_LOW; eeprom.state = GET_WORD_ADR_LOW;
} }
} }
break; break;
/* Get Word Address LSB: 7bits (24C01) or 8bits (24C02-24C512) /* Get Word Address LSB: 7bits (24C01) or 8bits (24C02-24C512)
* MODE-2 and MODE-3 only (24C01 - 24C512) * MODE-2 and MODE-3 only (24C01 - 24C512)
*/ */
case GET_WORD_ADR_LOW: case GET_WORD_ADR_LOW:
Detect_START(); Detect_START();
Detect_STOP(); Detect_STOP();
/* look for SCL HIGH to LOW transition */ /* look for SCL HIGH to LOW transition */
if (eeprom.old_scl && !eeprom.scl) if (eeprom.old_scl && !eeprom.scl)
{ {
if (eeprom.cycles < 9) if (eeprom.cycles < 9)
{ {
if ((eeprom.type.size_mask + 1) < (1 << (9 - eeprom.cycles))) if ((eeprom.type.size_mask + 1) < (1 << (9 - eeprom.cycles)))
{ {
/* ignored bit (X24C01): slave mask should be right-shifted by one */ /* ignored bit (X24C01): slave mask should be right-shifted by one */
eeprom.slave_mask >>= 1; eeprom.slave_mask >>= 1;
} }
else else
{ {
/* this is a WORD ADDRESS high bit */ /* this is a WORD ADDRESS high bit */
if (eeprom.old_sda) eeprom.word_address |= (1 << (8 - eeprom.cycles)); if (eeprom.old_sda) eeprom.word_address |= (1 << (8 - eeprom.cycles));
else eeprom.word_address &= ~(1 << (8 - eeprom.cycles)); else eeprom.word_address &= ~(1 << (8 - eeprom.cycles));
} }
eeprom.cycles ++; eeprom.cycles ++;
} }
else else
{ {
/* ACK CYCLE */ /* ACK CYCLE */
eeprom.cycles = 1; eeprom.cycles = 1;
eeprom.word_address &= eeprom.type.size_mask; eeprom.word_address &= eeprom.type.size_mask;
eeprom.state = WRITE_DATA; eeprom.state = WRITE_DATA;
} }
} }
break; break;
/* /*
* Read Cycle * Read Cycle
*/ */
case READ_DATA: case READ_DATA:
Detect_START(); Detect_START();
Detect_STOP(); Detect_STOP();
/* look for SCL HIGH to LOW transition */ /* look for SCL HIGH to LOW transition */
if (eeprom.old_scl && !eeprom.scl) if (eeprom.old_scl && !eeprom.scl)
{ {
if (eeprom.cycles < 9) eeprom.cycles ++; if (eeprom.cycles < 9) eeprom.cycles ++;
else else
{ {
eeprom.cycles = 1; eeprom.cycles = 1;
/* ACK not received */ /* ACK not received */
if (eeprom.old_sda) eeprom.state = WAIT_STOP; if (eeprom.old_sda) eeprom.state = WAIT_STOP;
} }
} }
break; break;
/* /*
* Write Cycle * Write Cycle
*/ */
case WRITE_DATA: case WRITE_DATA:
Detect_START(); Detect_START();
Detect_STOP(); Detect_STOP();
/* look for SCL HIGH to LOW transition */ /* look for SCL HIGH to LOW transition */
if (eeprom.old_scl && !eeprom.scl) if (eeprom.old_scl && !eeprom.scl)
{ {
if (eeprom.cycles < 9) if (eeprom.cycles < 9)
{ {
/* Write DATA bits (max 64kBytes) */ /* Write DATA bits (max 64kBytes) */
uint16 sram_address = (eeprom.slave_mask | eeprom.word_address) & 0xFFFF; uint16 sram_address = (eeprom.slave_mask | eeprom.word_address) & 0xFFFF;
if (eeprom.old_sda) sram.sram[sram_address] |= (1 << (8 - eeprom.cycles)); if (eeprom.old_sda) sram.sram[sram_address] |= (1 << (8 - eeprom.cycles));
else sram.sram[sram_address] &= ~(1 << (8 - eeprom.cycles)); else sram.sram[sram_address] &= ~(1 << (8 - eeprom.cycles));
if (eeprom.cycles == 8) if (eeprom.cycles == 8)
{ {
/* WORD ADDRESS is incremented (roll up at maximum pagesize) */ /* WORD ADDRESS is incremented (roll up at maximum pagesize) */
eeprom.word_address = (eeprom.word_address & (0xFFFF - eeprom.type.pagewrite_mask)) | eeprom.word_address = (eeprom.word_address & (0xFFFF - eeprom.type.pagewrite_mask)) |
((eeprom.word_address + 1) & eeprom.type.pagewrite_mask); ((eeprom.word_address + 1) & eeprom.type.pagewrite_mask);
} }
eeprom.cycles ++; eeprom.cycles ++;
} }
else eeprom.cycles = 1; /* ACK cycle */ else eeprom.cycles = 1; /* ACK cycle */
} }
break; break;
} }
eeprom.old_scl = eeprom.scl; eeprom.old_scl = eeprom.scl;
eeprom.old_sda = eeprom.sda; eeprom.old_sda = eeprom.sda;
} }
uint32 eeprom_read(uint32 address, uint32 word_access) uint32 eeprom_read(uint32 address, uint32 word_access)
{ {
uint8 sda_out = eeprom.sda; uint8 sda_out = eeprom.sda;
/* EEPROM state */ /* EEPROM state */
switch (eeprom.state) switch (eeprom.state)
{ {
case READ_DATA: case READ_DATA:
if (eeprom.cycles < 9) if (eeprom.cycles < 9)
{ {
/* Return DATA bits (max 64kBytes) */ /* Return DATA bits (max 64kBytes) */
uint16 sram_address = (eeprom.slave_mask | eeprom.word_address) & 0xffff; uint16 sram_address = (eeprom.slave_mask | eeprom.word_address) & 0xffff;
sda_out = (sram.sram[sram_address] >> (8 - eeprom.cycles)) & 1; sda_out = (sram.sram[sram_address] >> (8 - eeprom.cycles)) & 1;
if (eeprom.cycles == 8) if (eeprom.cycles == 8)
{ {
/* WORD ADDRESS is incremented (roll up at maximum array size) */ /* WORD ADDRESS is incremented (roll up at maximum array size) */
eeprom.word_address ++; eeprom.word_address ++;
eeprom.word_address &= eeprom.type.size_mask; eeprom.word_address &= eeprom.type.size_mask;
} }
} }
break; break;
case GET_WORD_ADR_7BITS: case GET_WORD_ADR_7BITS:
case GET_SLAVE_ADR: case GET_SLAVE_ADR:
case GET_WORD_ADR_HIGH: case GET_WORD_ADR_HIGH:
case GET_WORD_ADR_LOW: case GET_WORD_ADR_LOW:
case WRITE_DATA: case WRITE_DATA:
if (eeprom.cycles == 9) sda_out = 0; if (eeprom.cycles == 9) sda_out = 0;
break; break;
default: default:
break; break;
} }
/* memory access */ /* memory access */
if (word_access) if (word_access)

View File

@ -24,14 +24,14 @@
typedef enum typedef enum
{ {
STAND_BY = 0, STAND_BY = 0,
WAIT_STOP, WAIT_STOP,
GET_SLAVE_ADR, GET_SLAVE_ADR,
GET_WORD_ADR_7BITS, GET_WORD_ADR_7BITS,
GET_WORD_ADR_HIGH, GET_WORD_ADR_HIGH,
GET_WORD_ADR_LOW, GET_WORD_ADR_LOW,
WRITE_DATA, WRITE_DATA,
READ_DATA, READ_DATA,
} T_EEPROM_STATE; } T_EEPROM_STATE;
@ -53,31 +53,31 @@ typedef enum
typedef struct typedef struct
{ {
uint8 address_bits; /* number of bits needed to address memory: 7, 8 or 16 */ uint8 address_bits; /* number of bits needed to address memory: 7, 8 or 16 */
uint16 size_mask; /* depends on the max size of the memory (in bytes) */ uint16 size_mask; /* depends on the max size of the memory (in bytes) */
uint16 pagewrite_mask; /* depends on the maximal number of bytes that can be written in a single write cycle */ uint16 pagewrite_mask; /* depends on the maximal number of bytes that can be written in a single write cycle */
uint32 sda_in_adr; /* 68000 memory address mapped to SDA_IN */ uint32 sda_in_adr; /* 68000 memory address mapped to SDA_IN */
uint32 sda_out_adr; /* 68000 memory address mapped to SDA_OUT */ uint32 sda_out_adr; /* 68000 memory address mapped to SDA_OUT */
uint32 scl_adr; /* 68000 memory address mapped to SCL */ uint32 scl_adr; /* 68000 memory address mapped to SCL */
uint8 sda_in_bit; /* bit offset for SDA_IN */ uint8 sda_in_bit; /* bit offset for SDA_IN */
uint8 sda_out_bit; /* bit offset for SDA_OUT */ uint8 sda_out_bit; /* bit offset for SDA_OUT */
uint8 scl_bit; /* bit offset for SCL */ uint8 scl_bit; /* bit offset for SCL */
} T_EEPROM_TYPE; } T_EEPROM_TYPE;
typedef struct typedef struct
{ {
uint8 sda; /* current /SDA line state */ uint8 sda; /* current /SDA line state */
uint8 scl; /* current /SCL line state */ uint8 scl; /* current /SCL line state */
uint8 old_sda; /* previous /SDA line state */ uint8 old_sda; /* previous /SDA line state */
uint8 old_scl; /* previous /SCL line state */ uint8 old_scl; /* previous /SCL line state */
uint8 cycles; /* current operation cycle number (0-9) */ uint8 cycles; /* current operation cycle number (0-9) */
uint8 rw; /* operation type (1:READ, 0:WRITE) */ uint8 rw; /* operation type (1:READ, 0:WRITE) */
uint16 slave_mask; /* device address (shifted by the memory address width)*/ uint16 slave_mask; /* device address (shifted by the memory address width)*/
uint16 word_address; /* memory address */ uint16 word_address; /* memory address */
T_EEPROM_STATE state; /* current operation state */ T_EEPROM_STATE state; /* current operation state */
T_EEPROM_TYPE type; /* EEPROM characteristics for this game */ T_EEPROM_TYPE type; /* EEPROM characteristics for this game */
} T_EEPROM; } T_EEPROM;

View File

@ -29,9 +29,9 @@ T_SRAM sram;
* *
* The SRAM definition is held at offset 0x1b0 of the ROM header. * The SRAM definition is held at offset 0x1b0 of the ROM header.
* *
* 1B0h: dc.b 'RA', %1x1yz000, %00100000 * 1B0h: dc.b 'RA', %1x1yz000, %00100000
* 1B4h: dc.l RAM start address * 1B4h: dc.l RAM start address
* 1B8h: dc.l RAM end address * 1B8h: dc.l RAM end address
* x 1 for BACKUP and 0 If not BACKUP * x 1 for BACKUP and 0 If not BACKUP
* yz 10 if even address only * yz 10 if even address only
* 11 if odd address only * 11 if odd address only
@ -48,51 +48,51 @@ void sram_init()
if ((cart_rom[0x1b0] == 0x52) && (cart_rom[0x1b1] == 0x41)) if ((cart_rom[0x1b0] == 0x52) && (cart_rom[0x1b1] == 0x41))
{ {
/* retrieve informations from headezr */ /* retrieve informations from headezr */
sram.detected = 1; sram.detected = 1;
sram.start = READ_WORD_LONG(cart_rom, 0x1b4); sram.start = READ_WORD_LONG(cart_rom, 0x1b4);
sram.end = READ_WORD_LONG(cart_rom, 0x1b8); sram.end = READ_WORD_LONG(cart_rom, 0x1b8);
/* fixe some bad header informations */ /* fixe some bad header informations */
if ((sram.start > sram.end) || ((sram.end - sram.start) >= 0x10000)) if ((sram.start > sram.end) || ((sram.end - sram.start) >= 0x10000))
sram.end = sram.start + 0xffff; sram.end = sram.start + 0xffff;
sram.start &= 0xfffffffe; sram.start &= 0xfffffffe;
sram.end |= 1; sram.end |= 1;
} }
else else
{ {
/* default SRAM region */ /* default SRAM region */
sram.start = 0x200000; sram.start = 0x200000;
sram.end = 0x20ffff; sram.end = 0x20ffff;
} }
/* set SRAM ON by default when ROM is not mapped */ /* set SRAM ON by default when ROM is not mapped */
if (genromsize <= sram.start) if (genromsize <= sram.start)
{ {
sram.on = 1; sram.on = 1;
sram.write = 1; sram.write = 1;
} }
/* Some games with bad header or specific configuration */ /* Some games with bad header or specific configuration */
if (strstr(rominfo.product,"T-113016") != NULL) if (strstr(rominfo.product,"T-113016") != NULL)
{ {
/* Pugsy (try accessing unmapped area for copy protection) */ /* Pugsy (try accessing unmapped area for copy protection) */
sram.on = 0; sram.on = 0;
sram.write = 0; sram.write = 0;
} }
else if ((strstr(rominfo.product,"T-26013") != NULL) && (rominfo.checksum == 0xa837)) else if ((strstr(rominfo.product,"T-26013") != NULL) && (rominfo.checksum == 0xa837))
{ {
/* Psy-O-Blade (bad header) */ /* Psy-O-Blade (bad header) */
sram.on = 1; sram.on = 1;
sram.write = 1; sram.write = 1;
sram.start = 0x200001; sram.start = 0x200001;
sram.end = 0x203fff; sram.end = 0x203fff;
} }
else if (((realchecksum == 0xaeaa) || (realchecksum == 0x8dba)) && (rominfo.checksum == 0x8104)) else if (((realchecksum == 0xaeaa) || (realchecksum == 0x8dba)) && (rominfo.checksum == 0x8104))
{ {
/* Xin Qigai Wangzi, aka Beggar Prince (no header, use uncommon area) */ /* Xin Qigai Wangzi, aka Beggar Prince (no header, use uncommon area) */
sram.on = 1; sram.on = 1;
sram.write = 1; sram.write = 1;
sram.start = 0x400000; sram.start = 0x400000;
sram.end = 0x40ffff; sram.end = 0x40ffff;
} }
} }

View File

@ -2,13 +2,14 @@
vscroll: 1 (0); 209 (26) - alternates every 4 frames vscroll: 1 (0); 209 (26) - alternates every 4 frames
vram range for patterns: 0000-999f (low scr 0000-395f,72e0-999f; high 3980-999f) vram range for patterns: 0000-999f (low scr 0000-395f,72e0-999f; high 3980-999f)
name table address: c000 name table address: c000
seen DMAs (in order): [300002-3026c3]->[0020-26e1] len 4961 seen DMAs (in order):
[3026c2-303943]->[26e0-3961] len 2369 [300002-3026c3]->[0020-26e1] len 4961
[303942-306003]->[72e0-99a1] len 4961 [3026c2-303943]->[26e0-3961] len 2369
--- [303942-306003]->[72e0-99a1] len 4961
[306002-3086c3]->[3980-6041] len 4961 ---
[3086c2-309943]->[6040-72c1] len 2369 [306002-3086c3]->[3980-6041] len 4961
[309942-30c003]->[72e0-99a2] len 4961 [3086c2-309943]->[6040-72c1] len 2369
[309942-30c003]->[72e0-99a2] len 4961
tile arrangement: tile arrangement:
000: 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000: 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000

File diff suppressed because it is too large Load Diff

View File

@ -23,56 +23,56 @@
/* register names */ /* register names */
enum { enum {
SSP_GR0, SSP_X, SSP_Y, SSP_A, SSP_GR0, SSP_X, SSP_Y, SSP_A,
SSP_ST, SSP_STACK, SSP_PC, SSP_P, SSP_ST, SSP_STACK, SSP_PC, SSP_P,
SSP_PM0, SSP_PM1, SSP_PM2, SSP_XST, SSP_PM0, SSP_PM1, SSP_PM2, SSP_XST,
SSP_PM4, SSP_gr13, SSP_PMC, SSP_AL SSP_PM4, SSP_gr13, SSP_PMC, SSP_AL
}; };
typedef union typedef union
{ {
unsigned int v; unsigned int v;
struct { struct {
#ifdef LSB_FIRST #ifdef LSB_FIRST
unsigned short l; unsigned short l;
unsigned short h; unsigned short h;
#else #else
unsigned short h; unsigned short h;
unsigned short l; unsigned short l;
#endif #endif
}; };
} ssp_reg_t; } ssp_reg_t;
typedef struct typedef struct
{ {
union { union {
unsigned short RAM[256*2]; // 2 internal RAM banks unsigned short RAM[256*2]; // 2 internal RAM banks
struct { struct {
unsigned short RAM0[256]; unsigned short RAM0[256];
unsigned short RAM1[256]; unsigned short RAM1[256];
}; };
}; };
ssp_reg_t gr[16]; // general registers ssp_reg_t gr[16]; // general registers
union { union {
unsigned char r[8]; // BANK pointers unsigned char r[8]; // BANK pointers
struct { struct {
unsigned char r0[4]; unsigned char r0[4];
unsigned char r1[4]; unsigned char r1[4];
}; };
}; };
unsigned short stack[6]; unsigned short stack[6];
unsigned int pmac_read[6]; // read modes/addrs for PM0-PM5 unsigned int pmac_read[6]; // read modes/addrs for PM0-PM5
unsigned int pmac_write[6]; // write ... unsigned int pmac_write[6]; // write ...
//
#define SSP_PMC_HAVE_ADDR 0x0001 // address written to PMAC, waiting for mode #define SSP_PMC_HAVE_ADDR 0x0001 // address written to PMAC, waiting for mode
#define SSP_PMC_SET 0x0002 // PMAC is set #define SSP_PMC_SET 0x0002 // PMAC is set
#define SSP_HANG 0x1000 // 68000 hangs SVP #define SSP_HANG 0x1000 // 68000 hangs SVP
#define SSP_WAIT_PM0 0x2000 // bit1 in PM0 #define SSP_WAIT_PM0 0x2000 // bit1 in PM0
#define SSP_WAIT_30FE06 0x4000 // ssp tight loops on 30FE08 to become non-zero #define SSP_WAIT_30FE06 0x4000 // ssp tight loops on 30FE08 to become non-zero
#define SSP_WAIT_30FE08 0x8000 // same for 30FE06 #define SSP_WAIT_30FE08 0x8000 // same for 30FE06
#define SSP_WAIT_MASK 0xf000 #define SSP_WAIT_MASK 0xf000
unsigned int emu_status; unsigned int emu_status;
unsigned int pad[30]; unsigned int pad[30];
} ssp1601_t; } ssp1601_t;

View File

@ -15,14 +15,14 @@ uint16 SVP_cycles = 850;
void svp_init(void) void svp_init(void)
{ {
svp = (void *) ((char *)cart_rom + 0x200000); svp = (void *) ((char *)cart_rom + 0x200000);
memset(svp, 0, sizeof(*svp)); memset(svp, 0, sizeof(*svp));
} }
void svp_reset(void) void svp_reset(void)
{ {
memcpy(svp->iram_rom + 0x800, cart_rom + 0x800, 0x20000 - 0x800); memcpy(svp->iram_rom + 0x800, cart_rom + 0x800, 0x20000 - 0x800);
ssp1601_reset(&svp->ssp1601); ssp1601_reset(&svp->ssp1601);
} }
void svp_write_dram(uint32 address, uint32 data) void svp_write_dram(uint32 address, uint32 data)

View File

@ -16,9 +16,9 @@
#include "ssp16.h" #include "ssp16.h"
typedef struct { typedef struct {
unsigned char iram_rom[0x20000]; // IRAM (0-0x7ff) and program ROM (0x800-0x1ffff) unsigned char iram_rom[0x20000]; // IRAM (0-0x7ff) and program ROM (0x800-0x1ffff)
unsigned char dram[0x20000]; unsigned char dram[0x20000];
ssp1601_t ssp1601; ssp1601_t ssp1601;
} svp_t; } svp_t;
extern svp_t *svp; extern svp_t *svp;

View File

@ -31,33 +31,33 @@ t_input input;
*****************************************************************************/ *****************************************************************************/
/* H counter values for a 256-pixel wide display (342 pixel max.) */ /* H counter values for a 256-pixel wide display (342 pixel max.) */
uint8 hc_256[171] = { uint8 hc_256[171] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
0x90, 0x91, 0x92, 0x93, 0x90, 0x91, 0x92, 0x93,
0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF
}; };
/* H counter values for a 320-pixel wide display (442 pixels max.) */ /* H counter values for a 320-pixel wide display (442 pixels max.) */
uint8 hc_320[210] = { uint8 hc_320[210] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6,
0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED,
0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD,
@ -77,7 +77,7 @@ static inline void lightgun_update(int num)
/* HL enabled ? */ /* HL enabled ? */
if (io_reg[5] & 0x80) if (io_reg[5] & 0x80)
{ {
/* External Interrupt ? */ /* External Interrupt ? */
if (reg[11] & 0x08) {irq_status &= 0xff; irq_status |= 0x12;} if (reg[11] & 0x08) {irq_status &= 0xff; irq_status |= 0x12;}
/* HVC Latch: /* HVC Latch:
@ -86,11 +86,8 @@ static inline void lightgun_update(int num)
H-Counter range is approx. 292 pixel clocks H-Counter range is approx. 292 pixel clocks
*/ */
hc_latch = 0x100; hc_latch = 0x100;
if (reg[12] & 1) if (reg[12] & 1) hc_latch |= hc_320[((input.analog[num][0] * 290) / (2 * 320) + input.x_offset) % 210];
hc_latch |= hc_320[((input.analog[num][0] * 290) / (2 * 320) + input.x_offset) % 210]; else hc_latch |= hc_256[(input.analog[num][0] / 2 + input.x_offset)%171];
else
hc_latch |= hc_256[(input.analog[num][0] / 2 + input.x_offset)%171];
} }
} }
} }

View File

@ -69,59 +69,59 @@
/* CPU types for use in m68k_set_cpu_type() */ /* CPU types for use in m68k_set_cpu_type() */
enum enum
{ {
M68K_CPU_TYPE_INVALID, M68K_CPU_TYPE_INVALID,
M68K_CPU_TYPE_68000, M68K_CPU_TYPE_68000,
M68K_CPU_TYPE_68008, M68K_CPU_TYPE_68008,
M68K_CPU_TYPE_68010, M68K_CPU_TYPE_68010,
M68K_CPU_TYPE_68EC020, M68K_CPU_TYPE_68EC020,
M68K_CPU_TYPE_68020, M68K_CPU_TYPE_68020,
M68K_CPU_TYPE_68030, /* Supported by disassembler ONLY */ M68K_CPU_TYPE_68030, /* Supported by disassembler ONLY */
M68K_CPU_TYPE_68040 /* Supported by disassembler ONLY */ M68K_CPU_TYPE_68040 /* Supported by disassembler ONLY */
}; };
/* Registers used by m68k_get_reg() and m68k_set_reg() */ /* Registers used by m68k_get_reg() and m68k_set_reg() */
typedef enum typedef enum
{ {
/* Real registers */ /* Real registers */
M68K_REG_D0, /* Data registers */ M68K_REG_D0, /* Data registers */
M68K_REG_D1, M68K_REG_D1,
M68K_REG_D2, M68K_REG_D2,
M68K_REG_D3, M68K_REG_D3,
M68K_REG_D4, M68K_REG_D4,
M68K_REG_D5, M68K_REG_D5,
M68K_REG_D6, M68K_REG_D6,
M68K_REG_D7, M68K_REG_D7,
M68K_REG_A0, /* Address registers */ M68K_REG_A0, /* Address registers */
M68K_REG_A1, M68K_REG_A1,
M68K_REG_A2, M68K_REG_A2,
M68K_REG_A3, M68K_REG_A3,
M68K_REG_A4, M68K_REG_A4,
M68K_REG_A5, M68K_REG_A5,
M68K_REG_A6, M68K_REG_A6,
M68K_REG_A7, M68K_REG_A7,
M68K_REG_PC, /* Program Counter */ M68K_REG_PC, /* Program Counter */
M68K_REG_SR, /* Status Register */ M68K_REG_SR, /* Status Register */
M68K_REG_SP, /* The current Stack Pointer (located in A7) */ M68K_REG_SP, /* The current Stack Pointer (located in A7) */
M68K_REG_USP, /* User Stack Pointer */ M68K_REG_USP, /* User Stack Pointer */
M68K_REG_ISP, /* Interrupt Stack Pointer */ M68K_REG_ISP, /* Interrupt Stack Pointer */
M68K_REG_MSP, /* Master Stack Pointer */ M68K_REG_MSP, /* Master Stack Pointer */
M68K_REG_SFC, /* Source Function Code */ M68K_REG_SFC, /* Source Function Code */
M68K_REG_DFC, /* Destination Function Code */ M68K_REG_DFC, /* Destination Function Code */
M68K_REG_VBR, /* Vector Base Register */ M68K_REG_VBR, /* Vector Base Register */
M68K_REG_CACR, /* Cache Control Register */ M68K_REG_CACR, /* Cache Control Register */
M68K_REG_CAAR, /* Cache Address Register */ M68K_REG_CAAR, /* Cache Address Register */
/* Assumed registers */ /* Assumed registers */
/* These are cheat registers which emulate the 1-longword prefetch /* These are cheat registers which emulate the 1-longword prefetch
* present in the 68000 and 68010. * present in the 68000 and 68010.
*/ */
M68K_REG_PREF_ADDR, /* Last prefetch address */ M68K_REG_PREF_ADDR, /* Last prefetch address */
M68K_REG_PREF_DATA, /* Last prefetch data */ M68K_REG_PREF_DATA, /* Last prefetch data */
/* Convenience registers */ /* Convenience registers */
M68K_REG_PPC, /* Previous value in the program counter */ M68K_REG_PPC, /* Previous value in the program counter */
M68K_REG_IR, /* Instruction register */ M68K_REG_IR, /* Instruction register */
M68K_REG_CPU_TYPE /* Type of CPU being run */ M68K_REG_CPU_TYPE /* Type of CPU being run */
} m68k_register_t; } m68k_register_t;
/* ======================================================================== */ /* ======================================================================== */
@ -180,7 +180,7 @@ _m68k_memory_map m68k_memory_map[256];
/* Read data immediately following the PC */ /* Read data immediately following the PC */
#define m68k_read_immediate_16(address) *(uint16 *)(m68k_memory_map[((address)>>16)&0xff].base + ((address) & 0xffff)) #define m68k_read_immediate_16(address) *(uint16 *)(m68k_memory_map[((address)>>16)&0xff].base + ((address) & 0xffff))
#define m68k_read_immediate_32(address) (m68k_read_immediate_16(address) << 16) | (m68k_read_immediate_16(address+2)) #define m68k_read_immediate_32(address) (m68k_read_immediate_16(address) << 16) | (m68k_read_immediate_16(address+2))
/* Read data relative to the PC */ /* Read data relative to the PC */
#define m68k_read_pcrelative_8(address) READ_BYTE(m68k_memory_map[((address)>>16)&0xff].base, (address) & 0xffff) #define m68k_read_pcrelative_8(address) READ_BYTE(m68k_memory_map[((address)>>16)&0xff].base, (address) & 0xffff)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,27 @@
/****************************************************************************
* config.c
*
* Genesis Plus GX configuration file support
*
* code by Eke-Eke (2008)
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
***************************************************************************/
#include "shared.h" #include "shared.h"
#include "font.h"
#include <fat.h>
#include <sys/dir.h> #include <sys/dir.h>
#ifdef HW_RVL #ifdef HW_RVL

View File

@ -1,3 +1,25 @@
/****************************************************************************
* config.c
*
* Genesis Plus GX configuration file support
*
* code by Eke-Eke (2008)
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
***************************************************************************/
#ifndef _CONFIG_H_ #ifndef _CONFIG_H_
#define _CONFIG_H_ #define _CONFIG_H_

View File

@ -1,19 +0,0 @@
/****************************************************************************
* Nintendo Gamecube DVD Reading Library
*
* Low-Level DVD access
*
***************************************************************************/
#ifndef _DVD_H_
#define _DVD_H_
extern u32 dvd_read (void *dst, u32 len, u64 offset);
extern void dvd_motor_off ();
#ifndef HW_RVL
extern void uselessinquiry ();
extern void dvd_drive_detect();
#endif
#endif

View File

@ -1,9 +1,26 @@
/**************************************************************************** /*
* Nintendo Gamecube DVD Reading Library * dvd.c
*
* Low-level DVD access
* *
* Low-Level DVD access * code by Softdev (2006), Eke-Eke (2007,2008)
* *
***************************************************************************/ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
********************************************************************************/
#include "shared.h" #include "shared.h"
#ifdef HW_RVL #ifdef HW_RVL

36
source/ngc/fileio/dvd.h Normal file
View File

@ -0,0 +1,36 @@
/*
* dvd.c
*
* Low-level DVD access
*
* code by Softdev (2006), Eke-Eke (2007,2008)
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
********************************************************************************/
#ifndef _DVD_H_
#define _DVD_H_
extern u32 dvd_read (void *dst, u32 len, u64 offset);
extern void dvd_motor_off ();
#ifndef HW_RVL
extern void uselessinquiry ();
extern void dvd_drive_detect();
#endif
#endif

View File

@ -1,14 +1,31 @@
/**************************************************************************** /*
* file_dvd.c
*
* generic ISO9660/Joliet DVD loading support
* *
* DVD ISO9660/Joliet loading support * code by Eke-Eke (2008)
* *
***************************************************************************/ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
********************************************************************************/
#include "shared.h" #include "shared.h"
#include "font.h" #include "font.h"
#include "fileio_dvd.h"
#include "filesel.h"
#include "fileio.h"
#include "dvd.h" #include "dvd.h"
#include "unzip.h"
#include "filesel.h"
#ifdef HW_RVL #ifdef HW_RVL
#include "di/di.h" #include "di/di.h"
@ -269,7 +286,7 @@ int DVD_ParseDirectory ()
* This functions return the actual size of data copied into the buffer * This functions return the actual size of data copied into the buffer
* *
****************************************************************************/ ****************************************************************************/
int DVD_LoadFile (unsigned char *buffer) int DVD_LoadFile (u8 *buffer)
{ {
/* file size */ /* file size */
int length = filelist[selection].length; int length = filelist[selection].length;
@ -284,6 +301,9 @@ int DVD_LoadFile (unsigned char *buffer)
/* determine file type */ /* determine file type */
if (!IsZipFile ((char *) readbuffer)) if (!IsZipFile ((char *) readbuffer))
{ {
char msg[50];
sprintf(msg,"Loading %d bytes...", length);
ShowAction(msg);
/* How many 2k blocks to read */ /* How many 2k blocks to read */
int blocks = length / 2048; int blocks = length / 2048;
int readoffset = 0; int readoffset = 0;
@ -310,7 +330,7 @@ int DVD_LoadFile (unsigned char *buffer)
} }
else else
{ {
return UnZipDVD (buffer, discoffset, length); return UnZipBuffer (buffer, discoffset, NULL);
} }
} }
@ -323,7 +343,7 @@ int DVD_LoadFile (unsigned char *buffer)
* Function to load a DVD directory and display to user. * Function to load a DVD directory and display to user.
****************************************************************************/ ****************************************************************************/
int DVD_Open () int DVD_Open (u8 *buffer)
{ {
/* reset flags */ /* reset flags */
useFAT = 0; useFAT = 0;
@ -385,7 +405,7 @@ int DVD_Open ()
selection = 0; selection = 0;
old_offset = 0; old_offset = 0;
old_selection = 0; old_selection = 0;
return FileSelector (); return FileSelector (buffer);
} }
else else
{ {
@ -395,5 +415,5 @@ int DVD_Open ()
} }
} }
return FileSelector (); return FileSelector (buffer);
} }

View File

@ -0,0 +1,32 @@
/*
* file_dvd.c
*
* generic ISO9660/Joliet DVD loading support
*
* code by Eke-Eke (2008)
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
********************************************************************************/
#ifndef _FILE_DVD_H
#define _FILE_DVD_H
extern int DVD_UpdateDir(int go_up);
extern int DVD_ParseDirectory();
extern int DVD_LoadFile(u8 *buffer);
extern int DVD_Open (u8 *buffer);
#endif

View File

@ -1,16 +1,35 @@
/**************************************************************************** /*
* FAT loading support * file_fat.c
*
* generic FAT loading support
* *
***************************************************************************/ * code by Eke-Eke (2008)
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
********************************************************************************/
#include "shared.h" #include "shared.h"
#include "font.h" #include "font.h"
#include "fileio_fat.h"
#include "filesel.h"
#include "fileio.h"
#include "history.h" #include "history.h"
#include "unzip.h"
#include "filesel.h"
#include "file_fat.h"
/* current FAT directory */ /* current FAT directory */
static char fatdir[256]; static char fatdir[MAXPATHLEN];
/* current FAT device */ /* current FAT device */
static int fat_type = 0; static int fat_type = 0;
@ -149,7 +168,7 @@ int FAT_ParseDirectory()
* This functions return the actual size of data copied into the buffer * This functions return the actual size of data copied into the buffer
* *
****************************************************************************/ ****************************************************************************/
int FAT_LoadFile (unsigned char *buffer) int FAT_LoadFile (u8 *buffer)
{ {
/* If loading from history then we need to setup a few more things. */ /* If loading from history then we need to setup a few more things. */
if(useHistory) if(useHistory)
@ -203,6 +222,9 @@ int FAT_LoadFile (unsigned char *buffer)
sdfile = fopen(fname, "rb"); sdfile = fopen(fname, "rb");
if (sdfile) if (sdfile)
{ {
char msg[50];
sprintf(msg,"Loading %d bytes...", length);
ShowAction(msg);
fread(buffer, 1, length, sdfile); fread(buffer, 1, length, sdfile);
fclose(sdfile); fclose(sdfile);
return length; return length;
@ -211,7 +233,7 @@ int FAT_LoadFile (unsigned char *buffer)
else else
{ {
/* unzip file */ /* unzip file */
return UnZipFAT(buffer, fname); return UnZipBuffer (buffer, 0, fname);
} }
} }
@ -223,7 +245,7 @@ int FAT_LoadFile (unsigned char *buffer)
* *
* Function to load a FAT directory and display to user. * Function to load a FAT directory and display to user.
****************************************************************************/ ****************************************************************************/
int FAT_Open(int type) int FAT_Open(int type, u8 *buffer)
{ {
int max = 0; int max = 0;
char root[10] = ""; char root[10] = "";
@ -299,7 +321,7 @@ int FAT_Open(int type)
selection = 0; selection = 0;
old_offset = 0; old_offset = 0;
old_selection = 0; old_selection = 0;
return FileSelector (); return FileSelector (buffer);
} }
else else
{ {
@ -309,5 +331,5 @@ int FAT_Open(int type)
} }
} }
return FileSelector (); return FileSelector (buffer);
} }

View File

@ -0,0 +1,39 @@
/*
* file_fat.c
*
* generic FAT loading support
*
* code by Eke-Eke (2008)
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
********************************************************************************/
#ifndef _FILE_FAT_H
#define _FILE_FAT_H
#define TYPE_RECENT 0
#define TYPE_SD 1
#ifdef HW_RVL
#define TYPE_USB 2
#endif
extern int FAT_UpdateDir(int go_up);
extern int FAT_ParseDirectory(void);
extern int FAT_LoadFile(u8* buffer);
extern int FAT_Open (int type, u8 *buffer);
#endif

View File

@ -1,19 +1,30 @@
/**************************************************************************** /*
* ROM Selection Interface * filesel.c
*
* File Selection menu
* *
* The following features are implemented: * code by Softdev (2006), Eke-Eke (2007,2008)
* . SDCARD access with LFN support (through softdev's VFAT library)
* . DVD access
* . easy subdirectory browsing
* . ROM browser
* . alphabetical file sorting (Marty Disibio)
* . load from history list (Marty Disibio)
* *
***************************************************************************/ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
********************************************************************************/
#include "shared.h" #include "shared.h"
#include "font.h" #include "font.h"
#include "fileio_dvd.h" #include "file_dvd.h"
#include "fileio_fat.h" #include "file_fat.h"
#include "filesel.h" #include "filesel.h"
/* Global Variables */ /* Global Variables */
@ -27,6 +38,7 @@ int useHistory = 0;
int haveDVDdir = 0; int haveDVDdir = 0;
int haveFATdir = 0; int haveFATdir = 0;
FILEENTRIES filelist[MAXFILES];
/*************************************************************************** /***************************************************************************
* ShowFiles * ShowFiles
@ -46,8 +58,8 @@ static void ShowFiles (int offset, int selection)
memset(text,0,MAXJOLIET+2); memset(text,0,MAXJOLIET+2);
if (filelist[i].flags) sprintf(text, "[%s]", filelist[i].filename + filelist[i].filename_offset); if (filelist[i].flags) sprintf(text, "[%s]", filelist[i].filename + filelist[i].filename_offset);
else sprintf (text, "%s", filelist[i].filename + filelist[i].filename_offset); else sprintf (text, "%s", filelist[i].filename + filelist[i].filename_offset);
if (j == (selection - offset)) WriteCentre_HL ((j * fheight) + 120, text); if (j == (selection - offset)) WriteCentre_HL ((j * fheight) + PAGEOFFSET, text);
else WriteCentre ((j * fheight) + 120, text); else WriteCentre ((j * fheight) + PAGEOFFSET, text);
j++; j++;
} }
SetScreen (); SetScreen ();
@ -57,8 +69,11 @@ static void ShowFiles (int offset, int selection)
* FileSelector * FileSelector
* *
* Let user select a file from the File listing * Let user select a file from the File listing
.* ROM file buffer is provided as input
* ROM size is returned
*
****************************************************************************/ ****************************************************************************/
int FileSelector() int FileSelector(unsigned char *buffer)
{ {
short p; short p;
int redraw = 1; int redraw = 1;
@ -168,10 +183,15 @@ int FileSelector()
if (filelist[selection].flags) if (filelist[selection].flags)
{ {
/* get new directory */ /* get new directory */
ret = useFAT ? FAT_UpdateDir(go_up) : DVD_UpdateDir(go_up); if (useFAT) ret =FAT_UpdateDir(go_up);
else ret = DVD_UpdateDir(go_up);
/* get new entry list or quit */ /* get new entry list or quit */
if (ret) maxfiles = useFAT ? FAT_ParseDirectory() : DVD_ParseDirectory(); if (ret)
{
if (useFAT) maxfiles = FAT_ParseDirectory();
else maxfiles = DVD_ParseDirectory();
}
else return 0; else return 0;
} }
@ -179,16 +199,8 @@ int FileSelector()
else else
{ {
/* Load file */ /* Load file */
genromsize = useFAT ? FAT_LoadFile(cart_rom) : DVD_LoadFile(cart_rom); if (useFAT) return FAT_LoadFile(buffer);
if (genromsize) else return DVD_LoadFile(buffer);
{
memfile_autosave();
reloadrom();
memfile_autoload();
return 1;
}
return 0;
} }
redraw = 1; redraw = 1;
} }

View File

@ -0,0 +1,59 @@
/*
* filesel.c
*
* File Selection menu
*
* code by Softdev (2006), Eke-Eke (2007,2008)
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
********************************************************************************/
#ifndef _FILESEL_H
#define _FILESEL_H
#define MAXJOLIET 256
#define MAXFILES 1000
/* this is emulator specific ! */
#define PAGESIZE 12
#define PAGEOFFSET 120
/* Filelist structure */
typedef struct
{
u64 offset;
unsigned int length;
char flags;
char filename[MAXJOLIET];
u16 filename_offset;
}FILEENTRIES;
/* Global Variables */
extern FILEENTRIES filelist[MAXFILES];
extern int maxfiles;
extern int offset;
extern int selection;
extern int old_selection;
extern int old_offset;
extern int useFAT;
extern int haveDVDdir;
extern int haveFATdir;
extern int FileSelector(unsigned char *buffer);
#endif

View File

@ -1,11 +1,25 @@
/* /*
* history.c * history.c
* genplusgx-mdisibio
* *
* Created by Martin Disibio on 6/17/08. * Generic ROM history list managment
* Copyright 2008 __MyCompanyName__. All rights reserved.
* *
*/ * code by Martin Disibio (6/17/08)
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
********************************************************************************/
#include "shared.h" #include "shared.h"
#include "history.h" #include "history.h"

View File

@ -0,0 +1,51 @@
/*
* history.c
*
* Generic ROM history list managment
*
* code by Martin Disibio (6/17/08)
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
********************************************************************************/
#ifndef _HISTORY_H
#define _HISTORY_H
#include "filesel.h"
#define NUM_HISTORY_ENTRIES (10)
/****************************************************************************
* ROM Play History
*
****************************************************************************/
typedef struct
{
char filepath[MAXJOLIET];
char filename[MAXJOLIET];
} t_history_entry;
typedef struct
{
t_history_entry entries[NUM_HISTORY_ENTRIES];
} t_history;
extern t_history history;
extern void history_add_file(char *filepath, char *filename);
extern void history_load();
extern void set_history_defaults();
#endif

View File

@ -1,16 +1,33 @@
/****************************************************************************** /******************************************************************************
* *
* Nintendo Gamecube Zip Support * unzip.c
* *
* Only partial support is included, in that only the first file within the archive * Zip Support
* is considered to be a ROM image. *
***************************************************************************/ * Only partial support is included, in that only the first file within the archive
* is considered to be a ROM image.
*
* code by Softdev (2006), Eke-Eke (2007,2008)
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
********************************************************************************/
#include "shared.h" #include "shared.h"
#include "dvd.h" #include "dvd.h"
#include "font.h" #include "font.h"
#include "unzip.h"
#include <zlib.h>
/* /*
* PKWare Zip Header - adopted into zip standard * PKWare Zip Header - adopted into zip standard
@ -72,12 +89,12 @@ int IsZipFile (char *buffer)
return 0; return 0;
} }
/***************************************************************************** /*****************************************************************************
* UnZipBuffer * UnZipBuffer
* *
* It should be noted that there is a limit of 5MB total size for any ROM * It should be noted that there is a limit of 5MB total size for any ROM
******************************************************************************/ ******************************************************************************/
int UnZipDVD (unsigned char *outbuffer, u64 discoffset, int length) int UnZipBuffer (unsigned char *outbuffer, u64 discoffset, char *filename)
{ {
PKZIPHEADER pkzip; PKZIPHEADER pkzip;
int zipoffset = 0; int zipoffset = 0;
@ -89,9 +106,25 @@ int UnZipDVD (unsigned char *outbuffer, u64 discoffset, int length)
int have = 0; int have = 0;
char readbuffer[2048]; char readbuffer[2048];
char msg[128]; char msg[128];
FILE *fatfile = NULL;
/*** FAT file support ***/
if (filename)
{
fatfile = fopen(filename, "rb");
if (fatfile == NULL) return 0;
}
/*** Read Zip Header ***/ /*** Read Zip Header ***/
dvd_read (&readbuffer, 2048, discoffset); if (fatfile)
{
fseek(fatfile, 0, SEEK_SET);
fread(readbuffer, 1, 2048, fatfile);
}
else
{
dvd_read (&readbuffer, 2048, discoffset);
}
/*** Copy PKZip header to local, used as info ***/ /*** Copy PKZip header to local, used as info ***/
memcpy (&pkzip, &readbuffer, sizeof (PKZIPHEADER)); memcpy (&pkzip, &readbuffer, sizeof (PKZIPHEADER));
@ -125,7 +158,7 @@ int UnZipDVD (unsigned char *outbuffer, u64 discoffset, int length)
{ {
zs.avail_out = ZIPCHUNK; zs.avail_out = ZIPCHUNK;
zs.next_out = (Bytef *) & out; zs.next_out = (Bytef *) & out;
res = inflate (&zs, Z_NO_FLUSH); res = inflate (&zs, Z_NO_FLUSH);
if (res == Z_MEM_ERROR) if (res == Z_MEM_ERROR)
{ {
@ -147,13 +180,23 @@ int UnZipDVD (unsigned char *outbuffer, u64 discoffset, int length)
zipoffset = 0; zipoffset = 0;
zipchunk = ZIPCHUNK; zipchunk = ZIPCHUNK;
discoffset += 2048; if (fatfile)
dvd_read (&readbuffer, 2048, discoffset); {
fread(readbuffer, 1, 2048, fatfile);
}
else
{
discoffset += 2048;
dvd_read (&readbuffer, 2048, discoffset);
}
} }
while (res != Z_STREAM_END); while (res != Z_STREAM_END);
inflateEnd (&zs); inflateEnd (&zs);
/* close file */
if (fatfile) fclose(fatfile);
if (res == Z_STREAM_END) if (res == Z_STREAM_END)
{ {
if (FLIP32 (pkzip.uncompressedSize) == (u32) bufferoffset) return bufferoffset; if (FLIP32 (pkzip.uncompressedSize) == (u32) bufferoffset) return bufferoffset;
@ -163,72 +206,5 @@ int UnZipDVD (unsigned char *outbuffer, u64 discoffset, int length)
return 0; return 0;
} }
int UnZipFAT (unsigned char *outbuffer, char *filename)
{
unzFile *fd = NULL;
unz_file_info info;
int ret = 0;
int size;
char msg[128];
/* Attempt to open the archive */
fd = unzOpen(filename);
if(!fd) return (0);
/* Go to first file in archive */
ret = unzGoToFirstFile(fd);
if(ret != UNZ_OK)
{
unzClose(fd);
return (0);
}
ret = unzGetCurrentFileInfo(fd, &info, NULL, 0, NULL, 0, NULL, 0);
if(ret != UNZ_OK)
{
unzClose(fd);
return (0);
}
/* Open the file for reading */
ret = unzOpenCurrentFile(fd);
if(ret != UNZ_OK)
{
unzClose(fd);
return (0);
}
/* Allocate file data buffer */
size = info.uncompressed_size;
sprintf (msg, "Unzipping %d bytes ... Wait", size);
ShowAction (msg);
/* Read (decompress) the file */
ret = unzReadCurrentFile(fd, outbuffer, info.uncompressed_size);
if(ret != info.uncompressed_size)
{
unzCloseCurrentFile(fd);
unzClose(fd);
return (0);
}
/* Close the current file */
ret = unzCloseCurrentFile(fd);
if(ret != UNZ_OK)
{
unzClose(fd);
return (0);
}
/* Close the archive */
ret = unzClose(fd);
if(ret != UNZ_OK)
{
return (0);
}
/* Update file size and return pointer to file data */
return (size);
}

View File

@ -5,11 +5,10 @@
* Only partial support is included, in that only the first file within the archive * Only partial support is included, in that only the first file within the archive
* is considered to be a ROM image. * is considered to be a ROM image.
***************************************************************************/ ***************************************************************************/
#ifndef _FILEIO_H_ #ifndef _UNZIP_H_
#define _FILEIO_H_ #define _UNZIP_H_
extern int IsZipFile (char *buffer); extern int IsZipFile (char *buffer);
int UnZipDVD (unsigned char *outbuffer, u64 discoffset, int length); int UnZipBuffer (unsigned char *outbuffer, u64 discoffset, char *filename);
int UnZipFAT (unsigned char *outbuffer, char *filename);
#endif #endif

View File

@ -1,14 +0,0 @@
/****************************************************************************
*
* DVD ISO9660/Joliet loading support
*
***************************************************************************/
#ifndef _FILEIO_DVD_H
#define _FILEIO_DVD_H
extern int DVD_UpdateDir(int go_up);
extern int DVD_ParseDirectory();
extern int DVD_LoadFile(unsigned char* buffer);
extern int DVD_Open ();
#endif

View File

@ -1,21 +0,0 @@
/****************************************************************************
*
* FAT loading support
*
***************************************************************************/
#ifndef _FILEIO_FAT_H
#define _FILEIO_FAT_H
#define TYPE_RECENT 0
#define TYPE_SD 1
#ifdef HW_RVL
#define TYPE_USB 2
#endif
extern int FAT_UpdateDir(int go_up);
extern int FAT_ParseDirectory(void);
extern int FAT_LoadFile(unsigned char* buffer);
extern int FAT_Open (int device);
#endif

View File

@ -1,8 +1,26 @@
/*************************************************************************** /*
* SDCARD/MEMCARD File support * filemem.c
* *
* FAT and Memory Card SRAM/Savestate files managment
*
* code by Softdev (2006), Eke-Eke (2007,2008)
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
***************************************************************************/ ***************************************************************************/
#include "shared.h" #include "shared.h"
#include "font.h" #include "font.h"
#include "saveicon.h" #include "saveicon.h"
@ -11,7 +29,6 @@
#include "dvd.h" #include "dvd.h"
#endif #endif
#include <fat.h>
#include <sys/dir.h> #include <sys/dir.h>
/* Support for MemCards */ /* Support for MemCards */

View File

@ -1,11 +1,27 @@
/** /****************************************************************************
* Nintendo GameCube ARAM Wrapper for libOGC aram.c * gcaram.c
* *
* This is an often overlooked area of ~16Mb extra RAM * ARAM wrapper for libogc
* It's use in Genesis Plus is to shadow the ROM. *
* Actually, only SSF2TNC needs shadowing, but it's always * code by Softdev (2006)
* Good to know :) *
*/ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
***************************************************************************/
#include "shared.h" #include "shared.h"
#define ARAMSTART 0x8000 #define ARAMSTART 0x8000

View File

@ -1,11 +1,25 @@
/** /****************************************************************************
* Nintendo GameCube ARAM Wrapper for libOGC aram.c * gcaram.c
* *
* This is an often overlooked area of ~16Mb extra RAM * ARAM wrapper for libogc
* It's use in Genesis Plus is to shadow the ROM. *
* Actually, only SSF2TNC needs shadowing, but it's always * code by Softdev (2006)
* Good to know :) *
*/ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
***************************************************************************/
#ifndef _ARAM_H #ifndef _ARAM_H
#define _ARAM_H #define _ARAM_H

View File

@ -1,35 +0,0 @@
/****************************************************************************
* ROM Selection Interface
*
***************************************************************************/
#ifndef _FILESEL_H
#define _FILESEL_H
#define MAXJOLIET 256
#define MAXFILES 1000
#define PAGESIZE 12
typedef struct
{
u64 offset;
unsigned int length;
char flags;
char filename[MAXJOLIET];
u16 filename_offset;
}FILEENTRIES;
FILEENTRIES filelist[MAXFILES];
/* Global Variables */
extern int maxfiles;
extern int offset;
extern int selection;
extern int old_selection;
extern int old_offset;
extern int useFAT;
extern int haveDVDdir;
extern int haveFATdir;
extern int FileSelector();
#endif

View File

@ -1,9 +1,27 @@
/***************************************************************************** /*****************************************************************************
* IPL FONT Engine * font.c
* *
* Based on Qoob MP3 Player Font * IPL FONT Engine, based on Qoob MP3 Player Font
* Added IPL font extraction *
*****************************************************************************/ * code by Softdev (2006), Eke-Eke(2007-2008)
*
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
********************************************************************************/
#include "shared.h" #include "shared.h"
#include "gpback.h" #include "gpback.h"

View File

@ -1,9 +1,27 @@
/***************************************************************************** /*****************************************************************************
* IPL FONT Engine * font.c
* *
* Based on Qoob MP3 Player Font * IPL FONT Engine, based on Qoob MP3 Player Font
* Added IPL font extraction *
*****************************************************************************/ * code by Softdev (2006), Eke-Eke(2007-2008)
*
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
********************************************************************************/
#ifndef _FONT_H #ifndef _FONT_H
#define _FONT_H #define _FONT_H

View File

@ -1,7 +1,9 @@
/**************************************************************************** /****************************************************************************
* Genesis Plus 1.2a * ggentry.c
* *
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald * Genesis Plus GX Game Genie
*
* code by Softdev (2006), Eke-Eke (2007,2008)
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -17,7 +19,6 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* Nintendo Gamecube Game Genie Entry
***************************************************************************/ ***************************************************************************/
#include "shared.h" #include "shared.h"

View File

@ -1,7 +1,9 @@
/**************************************************************************** /****************************************************************************
* Genesis Plus 1.2a * legal.c
* *
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald * generic legal informations screen
*
* code by Softdev (2006), Eke-Eke (2007,2008)
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -16,8 +18,10 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
***************************************************************************/ ***************************************************************************/
#include "shared.h" #include "shared.h"
#include "font.h" #include "font.h"
#include "dkpro.h" #include "dkpro.h"

View File

@ -1,7 +1,9 @@
/**************************************************************************** /****************************************************************************
* Genesis Plus 1.2a * menu.c
* *
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald * Genesis Plus GX menu
*
* code by Softdev (March 2006), Eke-Eke (2007,2008)
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -17,15 +19,13 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* Nintendo Gamecube Menus
* Please put any user menus here! - softdev March 12 2006
***************************************************************************/ ***************************************************************************/
#include "shared.h" #include "shared.h"
#include "dvd.h" #include "dvd.h"
#include "font.h" #include "font.h"
#include "fileio_dvd.h" #include "file_dvd.h"
#include "fileio_fat.h" #include "file_fat.h"
#ifdef HW_RVL #ifdef HW_RVL
#include <wiiuse/wpad.h> #include <wiiuse/wpad.h>
@ -896,10 +896,9 @@ static u8 dvd_on = 0;
int loadmenu () int loadmenu ()
{ {
int prevmenu = menu; int prevmenu = menu;
int ret; int ret,count,size;
int quit = 0; int quit = 0;
#ifdef HW_RVL #ifdef HW_RVL
int count = 4 + dvd_on;
char item[5][25] = { char item[5][25] = {
{"Load Recent"}, {"Load Recent"},
{"Load from SD"}, {"Load from SD"},
@ -908,7 +907,6 @@ int loadmenu ()
{"Stop DVD Motor"} {"Stop DVD Motor"}
}; };
#else #else
int count = 3 + dvd_on;
char item[4][25] = { char item[4][25] = {
{"Load Recent"}, {"Load Recent"},
{"Load from SD"}, {"Load from SD"},
@ -921,6 +919,11 @@ int loadmenu ()
while (quit == 0) while (quit == 0)
{ {
#ifdef HW_RVL
count = 4 + dvd_on;
#else
count = 3 + dvd_on;
#endif
strcpy (menutitle, "Press B to return"); strcpy (menutitle, "Press B to return");
ret = domenu (&item[0], count, 0); ret = domenu (&item[0], count, 0);
switch (ret) switch (ret)
@ -937,9 +940,14 @@ int loadmenu ()
case 2: case 2:
#endif #endif
load_menu = menu; load_menu = menu;
if (DVD_Open()) size = DVD_Open(cart_rom);
if (size)
{ {
dvd_on = 1; dvd_on = 1;
genromsize = size;
memfile_autosave();
reloadrom();
memfile_autoload();
return 1; return 1;
} }
break; break;
@ -952,18 +960,21 @@ int loadmenu ()
#endif #endif
dvd_motor_off(); dvd_motor_off();
dvd_on = 0; dvd_on = 0;
#ifdef HW_RVL
count = 4 + dvd_on;
#else
count = 3 + dvd_on;
#endif
menu = load_menu; menu = load_menu;
break; break;
/*** Load from FAT device ***/ /*** Load from FAT device ***/
default: default:
load_menu = menu; load_menu = menu;
if (FAT_Open(ret)) return 1; size = FAT_Open(ret,cart_rom);
if (size)
{
genromsize = size;
memfile_autosave();
reloadrom();
memfile_autoload();
return 1;
}
break; break;
} }

View File

@ -1,37 +0,0 @@
/*
* history.h
* genplusgx-mdisibio
*
* Created by Martin Disibio on 6/17/08.
*
*/
#ifndef _HISTORY_H
#define _HISTORY_H
#include "types.h"
#include "filesel.h"
#define NUM_HISTORY_ENTRIES (10)
/****************************************************************************
* ROM Play History
*
****************************************************************************/
typedef struct
{
char filepath[MAXJOLIET];
char filename[MAXJOLIET];
} t_history_entry;
typedef struct
{
t_history_entry entries[NUM_HISTORY_ENTRIES];
} t_history;
extern t_history history;
extern void history_add_file(char *filepath, char *filename);
extern void history_load();
extern void set_history_defaults();
#endif

View File

@ -0,0 +1,20 @@
Copyright (C) 2004 - 2008
Michael Wiedenbauer (shagkur)
Dave Murphy (WinterMute)
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
damages arising from the use of this software.
Permission is granted to anyone to use this software for any
purpose, including commercial applications, and to alter it and
redistribute it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you
must not claim that you wrote the original software. If you use
this software in a product, an acknowledgment in the product
documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and
must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.

View File

@ -1,7 +1,9 @@
/**************************************************************************** /****************************************************************************
* Genesis Plus 1.2a * ngc.c
* *
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald * Genesis Plus GX main
*
* code by Softdev (2006), Eke-Eke (2007,2008)
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -16,7 +18,9 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
***************************************************************************/ ***************************************************************************/
#include "shared.h" #include "shared.h"
#include "gcaram.h" #include "gcaram.h"
#include "font.h" #include "font.h"
@ -54,7 +58,7 @@ static void load_bios()
config.bios_enabled &= ~2; config.bios_enabled &= ~2;
/* open file */ /* open file */
sprintf (pathname, "%s/BIOS.bin", DEFAULT_PATH); sprintf (pathname, "%s/BIOS.bin",DEFAULT_PATH);
FILE *fp = fopen(pathname, "rb"); FILE *fp = fopen(pathname, "rb");
if (fp == NULL) return; if (fp == NULL) return;

View File

@ -1,26 +1,27 @@
/****************************************************************************** /****************************************************************************
* ogc_video.c
* *
* Genesis Plus - Sega Megadrive / Genesis Emulator * Genesis Plus GX audio support
* *
* NGC/Wii Audio support * code by Softdev (2006), Eke-Eke (2007,2008)
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or * the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/ ***************************************************************************/
#include "shared.h" #include "shared.h"
#include "ogc_input.h"
/* global datas */ /* global datas */
unsigned char soundbuffer[16][3840] ATTRIBUTE_ALIGN(32); unsigned char soundbuffer[16][3840] ATTRIBUTE_ALIGN(32);

View File

@ -1,23 +1,26 @@
/****************************************************************************** /****************************************************************************
* ogc_video.c
* *
* SMS Plus - Sega Master System / GameGear Emulator * Genesis Plus GX audio support
* *
* NGC/Wii Audio support * code by Softdev (2006), Eke-Eke (2007,2008)
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or * the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/ ***************************************************************************/
#ifndef _GC_AUDIO_H_ #ifndef _GC_AUDIO_H_
#define _GC_AUDIO_H_ #define _GC_AUDIO_H_

View File

@ -1,22 +1,24 @@
/****************************************************************************** /****************************************************************************
* ogc_input.c
* *
* SMS Plus GX - Sega Master System / GameGear Emulator * Genesis Plus GX input support
* *
* SMS Plus - Sega Master System / GameGear Emulator * code by Eke-Eke (2008)
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or * the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/ ***************************************************************************/
#include "shared.h" #include "shared.h"

View File

@ -1,23 +1,27 @@
/****************************************************************************** /****************************************************************************
* ogc_input.c
* *
* SMS Plus - Sega Master System / GameGear Emulator * Genesis Plus GX input support
* *
* NGC/Wii Controller support * code by Eke-Eke (2008)
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or * the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/ ***************************************************************************/
#ifndef _GC_INPUT_H_ #ifndef _GC_INPUT_H_
#define _GC_INPUT_H_ #define _GC_INPUT_H_

View File

@ -1,24 +1,27 @@
/****************************************************************************** /****************************************************************************
* ogc_video.c
* *
* Genesis Plus - Sega Megadrive / Genesis Emulator * Genesis Plus GX video support
* *
* NGC/Wii Video support * code by Softdev (2006), Eke-Eke (2007,2008)
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or * the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/ ***************************************************************************/
#include "shared.h" #include "shared.h"
#include "font.h" #include "font.h"
#include "gcaram.h" #include "gcaram.h"

View File

@ -1,23 +1,26 @@
/****************************************************************************** /****************************************************************************
* ogc_video.c
* *
* SMS Plus - Sega Master System / GameGear Emulator * Genesis Plus GX video support
* *
* NGC/Wii Video support * code by Softdev (2006), Eke-Eke (2007,2008)
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or * the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/ ***************************************************************************/
#ifndef _GC_VIDEO_H_ #ifndef _GC_VIDEO_H_
#define _GC_VIDEO_H_ #define _GC_VIDEO_H_

View File

@ -16,12 +16,11 @@
#include "ogc_audio.h" #include "ogc_audio.h"
#include "ogc_video.h" #include "ogc_video.h"
#include "config.h" #include "config.h"
#include "history.h"
#define DEFAULT_PATH "/genplus"
#define update_input() ogc_input__update() #define update_input() ogc_input__update()
#define DEFAULT_PATH "/genplus"
/* globals */ /* globals */
extern u32 diff_usec(long long start,long long end); extern u32 diff_usec(long long start,long long end);
extern long long gettime(); extern long long gettime();
@ -35,9 +34,6 @@ extern void MainMenu();
extern void set_region(); extern void set_region();
extern int ManageSRAM(u8 direction, u8 device); extern int ManageSRAM(u8 direction, u8 device);
extern int ManageState(u8 direction, u8 device); extern int ManageState(u8 direction, u8 device);
extern int OpenDVD();
extern int OpenFAT(char *name);
extern int OpenHistory();
extern void memfile_autosave(); extern void memfile_autosave();
extern void memfile_autoload(); extern void memfile_autoload();

View File

@ -38,65 +38,65 @@ md_ntsc_setup_t const md_ntsc_rgb = { 0, 0, 0, 0,.2, 0,.7, -1, -1,-1, 0,
/* 2 input pixels -> 4 composite samples */ /* 2 input pixels -> 4 composite samples */
pixel_info_t const md_ntsc_pixels [alignment_count] = { pixel_info_t const md_ntsc_pixels [alignment_count] = {
{ PIXEL_OFFSET( -4, -9 ), { 0.1f, 0.9f, 0.9f, 0.1f } }, { PIXEL_OFFSET( -4, -9 ), { 0.1f, 0.9f, 0.9f, 0.1f } },
{ PIXEL_OFFSET( -2, -7 ), { 0.1f, 0.9f, 0.9f, 0.1f } }, { PIXEL_OFFSET( -2, -7 ), { 0.1f, 0.9f, 0.9f, 0.1f } },
}; };
static void correct_errors( md_ntsc_rgb_t color, md_ntsc_rgb_t* out ) static void correct_errors( md_ntsc_rgb_t color, md_ntsc_rgb_t* out )
{ {
unsigned i; unsigned i;
for ( i = 0; i < rgb_kernel_size / 4; i++ ) for ( i = 0; i < rgb_kernel_size / 4; i++ )
{ {
md_ntsc_rgb_t error = color - md_ntsc_rgb_t error = color -
out [i ] - out [i + 2 +16] - out [i + 4 ] - out [i + 6 +16] - out [i ] - out [i + 2 +16] - out [i + 4 ] - out [i + 6 +16] -
out [i + 8] - out [(i+10)%16+16] - out [(i+12)%16] - out [(i+14)%16+16]; out [i + 8] - out [(i+10)%16+16] - out [(i+12)%16] - out [(i+14)%16+16];
CORRECT_ERROR( i + 6 + 16 ); CORRECT_ERROR( i + 6 + 16 );
/*DISTRIBUTE_ERROR( 2+16, 4, 6+16 );*/ /*DISTRIBUTE_ERROR( 2+16, 4, 6+16 );*/
} }
} }
void md_ntsc_init( md_ntsc_t* ntsc, md_ntsc_setup_t const* setup ) void md_ntsc_init( md_ntsc_t* ntsc, md_ntsc_setup_t const* setup )
{ {
int entry; int entry;
init_t impl; init_t impl;
if ( !setup ) if ( !setup )
setup = &md_ntsc_composite; setup = &md_ntsc_composite;
init( &impl, setup ); init( &impl, setup );
for ( entry = 0; entry < md_ntsc_palette_size; entry++ ) for ( entry = 0; entry < md_ntsc_palette_size; entry++ )
{ {
float bb = impl.to_float [entry >> 6 & 7]; float bb = impl.to_float [entry >> 6 & 7];
float gg = impl.to_float [entry >> 3 & 7]; float gg = impl.to_float [entry >> 3 & 7];
float rr = impl.to_float [entry & 7]; float rr = impl.to_float [entry & 7];
float y, i, q = RGB_TO_YIQ( rr, gg, bb, y, i ); float y, i, q = RGB_TO_YIQ( rr, gg, bb, y, i );
int r, g, b = YIQ_TO_RGB( y, i, q, impl.to_rgb, int, r, g ); int r, g, b = YIQ_TO_RGB( y, i, q, impl.to_rgb, int, r, g );
md_ntsc_rgb_t rgb = PACK_RGB( r, g, b ); md_ntsc_rgb_t rgb = PACK_RGB( r, g, b );
if ( setup->palette_out ) if ( setup->palette_out )
RGB_PALETTE_OUT( rgb, &setup->palette_out [entry * 3] ); RGB_PALETTE_OUT( rgb, &setup->palette_out [entry * 3] );
if ( ntsc ) if ( ntsc )
{ {
gen_kernel( &impl, y, i, q, ntsc->table [entry] ); gen_kernel( &impl, y, i, q, ntsc->table [entry] );
correct_errors( rgb, ntsc->table [entry] ); correct_errors( rgb, ntsc->table [entry] );
} }
} }
} }
#ifndef MD_NTSC_NO_BLITTERS #ifndef MD_NTSC_NO_BLITTERS
/* modified blitters to work on a line basis with genesis plus renderer*/ /* modified blitters to work on a line basis with genesis plus renderer*/
void md_ntsc_blit( md_ntsc_t const* ntsc, MD_NTSC_IN_T const* table, unsigned char* input, void md_ntsc_blit( md_ntsc_t const* ntsc, MD_NTSC_IN_T const* table, unsigned char* input,
int in_width, int vline) int in_width, int vline)
{ {
int const chunk_count = in_width / md_ntsc_in_chunk - 1; int const chunk_count = in_width / md_ntsc_in_chunk - 1;
MD_NTSC_IN_T border = table[0]; MD_NTSC_IN_T border = table[0];
MD_NTSC_BEGIN_ROW( ntsc, border, MD_NTSC_BEGIN_ROW( ntsc, border,
MD_NTSC_ADJ_IN( table[*input++] ), MD_NTSC_ADJ_IN( table[*input++] ),
MD_NTSC_ADJ_IN( table[*input++] ), MD_NTSC_ADJ_IN( table[*input++] ),
MD_NTSC_ADJ_IN( table[*input++] ) ); MD_NTSC_ADJ_IN( table[*input++] ) );
#ifdef NGC #ifdef NGC
/* directly fill the RGB565 texture */ /* directly fill the RGB565 texture */
@ -112,52 +112,52 @@ void md_ntsc_blit( md_ntsc_t const* ntsc, MD_NTSC_IN_T const* table, unsigned ch
int n; int n;
for ( n = chunk_count; n; --n ) for ( n = chunk_count; n; --n )
{ {
/* order of input and output pixels must not be altered */ /* order of input and output pixels must not be altered */
MD_NTSC_COLOR_IN( 0, ntsc, MD_NTSC_ADJ_IN( table[*input++] ) ); MD_NTSC_COLOR_IN( 0, ntsc, MD_NTSC_ADJ_IN( table[*input++] ) );
MD_NTSC_RGB_OUT( 0, *line_out++, MD_NTSC_OUT_DEPTH ); MD_NTSC_RGB_OUT( 0, *line_out++, MD_NTSC_OUT_DEPTH );
MD_NTSC_RGB_OUT( 1, *line_out++, MD_NTSC_OUT_DEPTH ); MD_NTSC_RGB_OUT( 1, *line_out++, MD_NTSC_OUT_DEPTH );
MD_NTSC_COLOR_IN( 1, ntsc, MD_NTSC_ADJ_IN( table[*input++] ) ); MD_NTSC_COLOR_IN( 1, ntsc, MD_NTSC_ADJ_IN( table[*input++] ) );
MD_NTSC_RGB_OUT( 2, *line_out++, MD_NTSC_OUT_DEPTH ); MD_NTSC_RGB_OUT( 2, *line_out++, MD_NTSC_OUT_DEPTH );
MD_NTSC_RGB_OUT( 3, *line_out++, MD_NTSC_OUT_DEPTH ); MD_NTSC_RGB_OUT( 3, *line_out++, MD_NTSC_OUT_DEPTH );
#ifdef NGC #ifdef NGC
line_out += 12; line_out += 12;
#endif #endif
MD_NTSC_COLOR_IN( 2, ntsc, MD_NTSC_ADJ_IN( table[*input++] ) ); MD_NTSC_COLOR_IN( 2, ntsc, MD_NTSC_ADJ_IN( table[*input++] ) );
MD_NTSC_RGB_OUT( 4, *line_out++, MD_NTSC_OUT_DEPTH ); MD_NTSC_RGB_OUT( 4, *line_out++, MD_NTSC_OUT_DEPTH );
MD_NTSC_RGB_OUT( 5, *line_out++, MD_NTSC_OUT_DEPTH ); MD_NTSC_RGB_OUT( 5, *line_out++, MD_NTSC_OUT_DEPTH );
MD_NTSC_COLOR_IN( 3, ntsc, MD_NTSC_ADJ_IN( table[*input++] ) ); MD_NTSC_COLOR_IN( 3, ntsc, MD_NTSC_ADJ_IN( table[*input++] ) );
MD_NTSC_RGB_OUT( 6, *line_out++, MD_NTSC_OUT_DEPTH ); MD_NTSC_RGB_OUT( 6, *line_out++, MD_NTSC_OUT_DEPTH );
MD_NTSC_RGB_OUT( 7, *line_out++, MD_NTSC_OUT_DEPTH ); MD_NTSC_RGB_OUT( 7, *line_out++, MD_NTSC_OUT_DEPTH );
#ifdef NGC #ifdef NGC
line_out += 12; line_out += 12;
#endif #endif
} }
/* finish final pixels */ /* finish final pixels */
MD_NTSC_COLOR_IN( 0, ntsc, MD_NTSC_ADJ_IN( table[*input++] ) ); MD_NTSC_COLOR_IN( 0, ntsc, MD_NTSC_ADJ_IN( table[*input++] ) );
MD_NTSC_RGB_OUT( 0, *line_out++, MD_NTSC_OUT_DEPTH ); MD_NTSC_RGB_OUT( 0, *line_out++, MD_NTSC_OUT_DEPTH );
MD_NTSC_RGB_OUT( 1, *line_out++, MD_NTSC_OUT_DEPTH ); MD_NTSC_RGB_OUT( 1, *line_out++, MD_NTSC_OUT_DEPTH );
MD_NTSC_COLOR_IN( 1, ntsc, border ); MD_NTSC_COLOR_IN( 1, ntsc, border );
MD_NTSC_RGB_OUT( 2, *line_out++, MD_NTSC_OUT_DEPTH ); MD_NTSC_RGB_OUT( 2, *line_out++, MD_NTSC_OUT_DEPTH );
MD_NTSC_RGB_OUT( 3, *line_out++, MD_NTSC_OUT_DEPTH ); MD_NTSC_RGB_OUT( 3, *line_out++, MD_NTSC_OUT_DEPTH );
#ifdef NGC #ifdef NGC
line_out += 12; line_out += 12;
#endif #endif
MD_NTSC_COLOR_IN( 2, ntsc, border ); MD_NTSC_COLOR_IN( 2, ntsc, border );
MD_NTSC_RGB_OUT( 4, *line_out++, MD_NTSC_OUT_DEPTH ); MD_NTSC_RGB_OUT( 4, *line_out++, MD_NTSC_OUT_DEPTH );
MD_NTSC_RGB_OUT( 5, *line_out++, MD_NTSC_OUT_DEPTH ); MD_NTSC_RGB_OUT( 5, *line_out++, MD_NTSC_OUT_DEPTH );
MD_NTSC_COLOR_IN( 3, ntsc, border ); MD_NTSC_COLOR_IN( 3, ntsc, border );
MD_NTSC_RGB_OUT( 6, *line_out++, MD_NTSC_OUT_DEPTH ); MD_NTSC_RGB_OUT( 6, *line_out++, MD_NTSC_OUT_DEPTH );
MD_NTSC_RGB_OUT( 7, *line_out++, MD_NTSC_OUT_DEPTH ); MD_NTSC_RGB_OUT( 7, *line_out++, MD_NTSC_OUT_DEPTH );
} }
#endif #endif

View File

@ -7,29 +7,29 @@
#include "md_ntsc_config.h" #include "md_ntsc_config.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
/* Image parameters, ranging from -1.0 to 1.0. Actual internal values shown /* Image parameters, ranging from -1.0 to 1.0. Actual internal values shown
in parenthesis and should remain fairly stable in future versions. */ in parenthesis and should remain fairly stable in future versions. */
typedef struct md_ntsc_setup_t typedef struct md_ntsc_setup_t
{ {
/* Basic parameters */ /* Basic parameters */
double hue; /* -1 = -180 degrees +1 = +180 degrees */ double hue; /* -1 = -180 degrees +1 = +180 degrees */
double saturation; /* -1 = grayscale (0.0) +1 = oversaturated colors (2.0) */ double saturation; /* -1 = grayscale (0.0) +1 = oversaturated colors (2.0) */
double contrast; /* -1 = dark (0.5) +1 = light (1.5) */ double contrast; /* -1 = dark (0.5) +1 = light (1.5) */
double brightness; /* -1 = dark (0.5) +1 = light (1.5) */ double brightness; /* -1 = dark (0.5) +1 = light (1.5) */
double sharpness; /* edge contrast enhancement/blurring */ double sharpness; /* edge contrast enhancement/blurring */
/* Advanced parameters */ /* Advanced parameters */
double gamma; /* -1 = dark (1.5) +1 = light (0.5) */ double gamma; /* -1 = dark (1.5) +1 = light (0.5) */
double resolution; /* image resolution */ double resolution; /* image resolution */
double artifacts; /* artifacts caused by color changes */ double artifacts; /* artifacts caused by color changes */
double fringing; /* color artifacts caused by brightness changes */ double fringing; /* color artifacts caused by brightness changes */
double bleed; /* color bleed (color resolution reduction) */ double bleed; /* color bleed (color resolution reduction) */
float const* decoder_matrix; /* optional RGB decoder matrix, 6 elements */ float const* decoder_matrix; /* optional RGB decoder matrix, 6 elements */
unsigned char* palette_out; /* optional RGB palette out, 3 bytes per color */ unsigned char* palette_out; /* optional RGB palette out, 3 bytes per color */
} md_ntsc_setup_t; } md_ntsc_setup_t;
/* Video format presets */ /* Video format presets */
@ -50,17 +50,17 @@ and output RGB depth is set by MD_NTSC_OUT_DEPTH. Both default to 16-bit RGB.
In_row_width is the number of pixels to get to the next input row. Out_pitch In_row_width is the number of pixels to get to the next input row. Out_pitch
is the number of *bytes* to get to the next output row. */ is the number of *bytes* to get to the next output row. */
void md_ntsc_blit( md_ntsc_t const* ntsc, MD_NTSC_IN_T const* table, unsigned char* input, void md_ntsc_blit( md_ntsc_t const* ntsc, MD_NTSC_IN_T const* table, unsigned char* input,
int in_width, int vline); int in_width, int vline);
/* Number of output pixels written by blitter for given input width. */ /* Number of output pixels written by blitter for given input width. */
#define MD_NTSC_OUT_WIDTH( in_width ) \ #define MD_NTSC_OUT_WIDTH( in_width ) \
(((in_width) - 3) / md_ntsc_in_chunk * md_ntsc_out_chunk + md_ntsc_out_chunk) (((in_width) - 3) / md_ntsc_in_chunk * md_ntsc_out_chunk + md_ntsc_out_chunk)
/* Number of input pixels that will fit within given output width. Might be /* Number of input pixels that will fit within given output width. Might be
rounded down slightly; use MD_NTSC_OUT_WIDTH() on result to find rounded rounded down slightly; use MD_NTSC_OUT_WIDTH() on result to find rounded
value. */ value. */
#define MD_NTSC_IN_WIDTH( out_width ) \ #define MD_NTSC_IN_WIDTH( out_width ) \
((out_width) / md_ntsc_out_chunk * md_ntsc_in_chunk - md_ntsc_in_chunk + 3) ((out_width) / md_ntsc_out_chunk * md_ntsc_in_chunk - md_ntsc_in_chunk + 3)
/* Interface for user-defined custom blitters */ /* Interface for user-defined custom blitters */
@ -73,22 +73,22 @@ enum { md_ntsc_black = 0 }; /* palette index for black */
Use md_ntsc_black for unused pixels. Declares variables, so must be before first Use md_ntsc_black for unused pixels. Declares variables, so must be before first
statement in a block (unless you're using C++). */ statement in a block (unless you're using C++). */
#define MD_NTSC_BEGIN_ROW( ntsc, pixel0, pixel1, pixel2, pixel3 ) \ #define MD_NTSC_BEGIN_ROW( ntsc, pixel0, pixel1, pixel2, pixel3 ) \
unsigned const md_pixel0_ = (pixel0);\ unsigned const md_pixel0_ = (pixel0);\
md_ntsc_rgb_t const* kernel0 = MD_NTSC_IN_FORMAT( ntsc, md_pixel0_ );\ md_ntsc_rgb_t const* kernel0 = MD_NTSC_IN_FORMAT( ntsc, md_pixel0_ );\
unsigned const md_pixel1_ = (pixel1);\ unsigned const md_pixel1_ = (pixel1);\
md_ntsc_rgb_t const* kernel1 = MD_NTSC_IN_FORMAT( ntsc, md_pixel1_ );\ md_ntsc_rgb_t const* kernel1 = MD_NTSC_IN_FORMAT( ntsc, md_pixel1_ );\
unsigned const md_pixel2_ = (pixel2);\ unsigned const md_pixel2_ = (pixel2);\
md_ntsc_rgb_t const* kernel2 = MD_NTSC_IN_FORMAT( ntsc, md_pixel2_ );\ md_ntsc_rgb_t const* kernel2 = MD_NTSC_IN_FORMAT( ntsc, md_pixel2_ );\
unsigned const md_pixel3_ = (pixel3);\ unsigned const md_pixel3_ = (pixel3);\
md_ntsc_rgb_t const* kernel3 = MD_NTSC_IN_FORMAT( ntsc, md_pixel3_ );\ md_ntsc_rgb_t const* kernel3 = MD_NTSC_IN_FORMAT( ntsc, md_pixel3_ );\
md_ntsc_rgb_t const* kernelx0;\ md_ntsc_rgb_t const* kernelx0;\
md_ntsc_rgb_t const* kernelx1 = kernel0;\ md_ntsc_rgb_t const* kernelx1 = kernel0;\
md_ntsc_rgb_t const* kernelx2 = kernel0;\ md_ntsc_rgb_t const* kernelx2 = kernel0;\
md_ntsc_rgb_t const* kernelx3 = kernel0 md_ntsc_rgb_t const* kernelx3 = kernel0
/* Begin input pixel */ /* Begin input pixel */
#define MD_NTSC_COLOR_IN( index, ntsc, color ) \ #define MD_NTSC_COLOR_IN( index, ntsc, color ) \
MD_NTSC_COLOR_IN_( index, color, MD_NTSC_IN_FORMAT, ntsc ) MD_NTSC_COLOR_IN_( index, color, MD_NTSC_IN_FORMAT, ntsc )
/* Generate output pixel. Bits can be 24, 16, 15, 32 (treated as 24), or 0: /* Generate output pixel. Bits can be 24, 16, 15, 32 (treated as 24), or 0:
24: RRRRRRRR GGGGGGGG BBBBBBBB 24: RRRRRRRR GGGGGGGG BBBBBBBB
@ -96,11 +96,11 @@ statement in a block (unless you're using C++). */
15: RRRRRGG GGGBBBBB 15: RRRRRGG GGGBBBBB
0: xxxRRRRR RRRxxGGG GGGGGxxB BBBBBBBx (native internal format; x = junk bits) */ 0: xxxRRRRR RRRxxGGG GGGGGxxB BBBBBBBx (native internal format; x = junk bits) */
#define MD_NTSC_RGB_OUT( x, rgb_out, bits ) {\ #define MD_NTSC_RGB_OUT( x, rgb_out, bits ) {\
md_ntsc_rgb_t raw_ =\ md_ntsc_rgb_t raw_ =\
kernel0 [x+ 0] + kernel1 [(x+6)%8+16] + kernel2 [(x+4)%8 ] + kernel3 [(x+2)%8+16] +\ kernel0 [x+ 0] + kernel1 [(x+6)%8+16] + kernel2 [(x+4)%8 ] + kernel3 [(x+2)%8+16] +\
kernelx0 [x+ 8] + kernelx1 [(x+6)%8+24] + kernelx2 [(x+4)%8+8] + kernelx3 [(x+2)%8+24];\ kernelx0 [x+ 8] + kernelx1 [(x+6)%8+24] + kernelx2 [(x+4)%8+8] + kernelx3 [(x+2)%8+24];\
MD_NTSC_CLAMP_( raw_, 0 );\ MD_NTSC_CLAMP_( raw_, 0 );\
MD_NTSC_RGB_OUT_( rgb_out, bits, 0 );\ MD_NTSC_RGB_OUT_( rgb_out, bits, 0 );\
} }
@ -108,41 +108,41 @@ statement in a block (unless you're using C++). */
enum { md_ntsc_entry_size = 2 * 16 }; enum { md_ntsc_entry_size = 2 * 16 };
typedef unsigned long md_ntsc_rgb_t; typedef unsigned long md_ntsc_rgb_t;
struct md_ntsc_t { struct md_ntsc_t {
md_ntsc_rgb_t table [md_ntsc_palette_size] [md_ntsc_entry_size]; md_ntsc_rgb_t table [md_ntsc_palette_size] [md_ntsc_entry_size];
}; };
#define MD_NTSC_BGR9( ntsc, n ) (ntsc)->table [n & 0x1FF] #define MD_NTSC_BGR9( ntsc, n ) (ntsc)->table [n & 0x1FF]
#define MD_NTSC_RGB16( ntsc, n ) \ #define MD_NTSC_RGB16( ntsc, n ) \
(md_ntsc_rgb_t*) ((char*) (ntsc)->table +\ (md_ntsc_rgb_t*) ((char*) (ntsc)->table +\
((n << 9 & 0x3800) | (n & 0x0700) | (n >> 8 & 0x00E0)) *\ ((n << 9 & 0x3800) | (n & 0x0700) | (n >> 8 & 0x00E0)) *\
(md_ntsc_entry_size * sizeof (md_ntsc_rgb_t) / 32)) (md_ntsc_entry_size * sizeof (md_ntsc_rgb_t) / 32))
/* common ntsc macros */ /* common ntsc macros */
#define md_ntsc_rgb_builder ((1L << 21) | (1 << 11) | (1 << 1)) #define md_ntsc_rgb_builder ((1L << 21) | (1 << 11) | (1 << 1))
#define md_ntsc_clamp_mask (md_ntsc_rgb_builder * 3 / 2) #define md_ntsc_clamp_mask (md_ntsc_rgb_builder * 3 / 2)
#define md_ntsc_clamp_add (md_ntsc_rgb_builder * 0x101) #define md_ntsc_clamp_add (md_ntsc_rgb_builder * 0x101)
#define MD_NTSC_CLAMP_( io, shift ) {\ #define MD_NTSC_CLAMP_( io, shift ) {\
md_ntsc_rgb_t sub = (io) >> (9-(shift)) & md_ntsc_clamp_mask;\ md_ntsc_rgb_t sub = (io) >> (9-(shift)) & md_ntsc_clamp_mask;\
md_ntsc_rgb_t clamp = md_ntsc_clamp_add - sub;\ md_ntsc_rgb_t clamp = md_ntsc_clamp_add - sub;\
io |= clamp;\ io |= clamp;\
clamp -= sub;\ clamp -= sub;\
io &= clamp;\ io &= clamp;\
} }
#define MD_NTSC_COLOR_IN_( index, color, ENTRY, table ) {\ #define MD_NTSC_COLOR_IN_( index, color, ENTRY, table ) {\
unsigned color_;\ unsigned color_;\
kernelx##index = kernel##index;\ kernelx##index = kernel##index;\
kernel##index = (color_ = (color), ENTRY( table, color_ ));\ kernel##index = (color_ = (color), ENTRY( table, color_ ));\
} }
/* x is always zero except in snes_ntsc library */ /* x is always zero except in snes_ntsc library */
#define MD_NTSC_RGB_OUT_( rgb_out, bits, x ) {\ #define MD_NTSC_RGB_OUT_( rgb_out, bits, x ) {\
rgb_out = (raw_>>(13-x)& 0xF800)|(raw_>>(8-x)&0x07E0)|(raw_>>(4-x)&0x001F);\ rgb_out = (raw_>>(13-x)& 0xF800)|(raw_>>(8-x)&0x07E0)|(raw_>>(4-x)&0x001F);\
} }
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
#endif #endif

View File

@ -22,22 +22,22 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
#define PI 3.14159265358979323846f #define PI 3.14159265358979323846f
#ifndef LUMA_CUTOFF #ifndef LUMA_CUTOFF
#define LUMA_CUTOFF 0.20 #define LUMA_CUTOFF 0.20
#endif #endif
#ifndef gamma_size #ifndef gamma_size
#define gamma_size 1 #define gamma_size 1
#endif #endif
#ifndef rgb_bits #ifndef rgb_bits
#define rgb_bits 8 #define rgb_bits 8
#endif #endif
#ifndef artifacts_max #ifndef artifacts_max
#define artifacts_max (artifacts_mid * 1.5f) #define artifacts_max (artifacts_mid * 1.5f)
#endif #endif
#ifndef fringing_max #ifndef fringing_max
#define fringing_max (fringing_mid * 2) #define fringing_max (fringing_mid * 2)
#endif #endif
#ifndef STD_HUE_CONDITION #ifndef STD_HUE_CONDITION
#define STD_HUE_CONDITION( setup ) 1 #define STD_HUE_CONDITION( setup ) 1
#endif #endif
#define ext_decoder_hue (std_decoder_hue + 15) #define ext_decoder_hue (std_decoder_hue + 15)
@ -50,236 +50,236 @@ enum { kernel_size = kernel_half * 2 + 1 };
typedef struct init_t typedef struct init_t
{ {
float to_rgb [burst_count * 6]; float to_rgb [burst_count * 6];
float to_float [gamma_size]; float to_float [gamma_size];
float contrast; float contrast;
float brightness; float brightness;
float artifacts; float artifacts;
float fringing; float fringing;
float kernel [rescale_out * kernel_size * 2]; float kernel [rescale_out * kernel_size * 2];
} init_t; } init_t;
#define ROTATE_IQ( i, q, sin_b, cos_b ) {\ #define ROTATE_IQ( i, q, sin_b, cos_b ) {\
float t;\ float t;\
t = i * cos_b - q * sin_b;\ t = i * cos_b - q * sin_b;\
q = i * sin_b + q * cos_b;\ q = i * sin_b + q * cos_b;\
i = t;\ i = t;\
} }
static void init_filters( init_t* impl, md_ntsc_setup_t const* setup ) static void init_filters( init_t* impl, md_ntsc_setup_t const* setup )
{ {
#if rescale_out > 1 #if rescale_out > 1
float kernels [kernel_size * 2]; float kernels [kernel_size * 2];
#else #else
float* const kernels = impl->kernel; float* const kernels = impl->kernel;
#endif #endif
/* generate luma (y) filter using sinc kernel */ /* generate luma (y) filter using sinc kernel */
{ {
/* sinc with rolloff (dsf) */ /* sinc with rolloff (dsf) */
float const rolloff = 1 + (float) setup->sharpness * (float) 0.032; float const rolloff = 1 + (float) setup->sharpness * (float) 0.032;
float const maxh = 32; float const maxh = 32;
float const pow_a_n = (float) pow( rolloff, maxh ); float const pow_a_n = (float) pow( rolloff, maxh );
float sum; float sum;
int i; int i;
/* quadratic mapping to reduce negative (blurring) range */ /* quadratic mapping to reduce negative (blurring) range */
float to_angle = (float) setup->resolution + 1; float to_angle = (float) setup->resolution + 1;
to_angle = PI / maxh * (float) LUMA_CUTOFF * (to_angle * to_angle + 1); to_angle = PI / maxh * (float) LUMA_CUTOFF * (to_angle * to_angle + 1);
kernels [kernel_size * 3 / 2] = maxh; /* default center value */ kernels [kernel_size * 3 / 2] = maxh; /* default center value */
for ( i = 0; i < kernel_half * 2 + 1; i++ ) for ( i = 0; i < kernel_half * 2 + 1; i++ )
{ {
int x = i - kernel_half; int x = i - kernel_half;
float angle = x * to_angle; float angle = x * to_angle;
/* instability occurs at center point with rolloff very close to 1.0 */ /* instability occurs at center point with rolloff very close to 1.0 */
if ( x || pow_a_n > (float) 1.056 || pow_a_n < (float) 0.981 ) if ( x || pow_a_n > (float) 1.056 || pow_a_n < (float) 0.981 )
{ {
float rolloff_cos_a = rolloff * (float) cos( angle ); float rolloff_cos_a = rolloff * (float) cos( angle );
float num = 1 - rolloff_cos_a - float num = 1 - rolloff_cos_a -
pow_a_n * (float) cos( maxh * angle ) + pow_a_n * (float) cos( maxh * angle ) +
pow_a_n * rolloff * (float) cos( (maxh - 1) * angle ); pow_a_n * rolloff * (float) cos( (maxh - 1) * angle );
float den = 1 - rolloff_cos_a - rolloff_cos_a + rolloff * rolloff; float den = 1 - rolloff_cos_a - rolloff_cos_a + rolloff * rolloff;
float dsf = num / den; float dsf = num / den;
kernels [kernel_size * 3 / 2 - kernel_half + i] = dsf - (float) 0.5; kernels [kernel_size * 3 / 2 - kernel_half + i] = dsf - (float) 0.5;
} }
} }
/* apply blackman window and find sum */ /* apply blackman window and find sum */
sum = 0; sum = 0;
for ( i = 0; i < kernel_half * 2 + 1; i++ ) for ( i = 0; i < kernel_half * 2 + 1; i++ )
{ {
float x = PI * 2 / (kernel_half * 2) * i; float x = PI * 2 / (kernel_half * 2) * i;
float blackman = 0.42f - 0.5f * (float) cos( x ) + 0.08f * (float) cos( x * 2 ); float blackman = 0.42f - 0.5f * (float) cos( x ) + 0.08f * (float) cos( x * 2 );
sum += (kernels [kernel_size * 3 / 2 - kernel_half + i] *= blackman); sum += (kernels [kernel_size * 3 / 2 - kernel_half + i] *= blackman);
} }
/* normalize kernel */ /* normalize kernel */
sum = 1.0f / sum; sum = 1.0f / sum;
for ( i = 0; i < kernel_half * 2 + 1; i++ ) for ( i = 0; i < kernel_half * 2 + 1; i++ )
{ {
int x = kernel_size * 3 / 2 - kernel_half + i; int x = kernel_size * 3 / 2 - kernel_half + i;
kernels [x] *= sum; kernels [x] *= sum;
assert( kernels [x] == kernels [x] ); /* catch numerical instability */ assert( kernels [x] == kernels [x] ); /* catch numerical instability */
} }
} }
/* generate chroma (iq) filter using gaussian kernel */ /* generate chroma (iq) filter using gaussian kernel */
{ {
float const cutoff_factor = -0.03125f; float const cutoff_factor = -0.03125f;
float cutoff = (float) setup->bleed; float cutoff = (float) setup->bleed;
int i; int i;
if ( cutoff < 0 ) if ( cutoff < 0 )
{ {
/* keep extreme value accessible only near upper end of scale (1.0) */ /* keep extreme value accessible only near upper end of scale (1.0) */
cutoff *= cutoff; cutoff *= cutoff;
cutoff *= cutoff; cutoff *= cutoff;
cutoff *= cutoff; cutoff *= cutoff;
cutoff *= -30.0f / 0.65f; cutoff *= -30.0f / 0.65f;
} }
cutoff = cutoff_factor - 0.65f * cutoff_factor * cutoff; cutoff = cutoff_factor - 0.65f * cutoff_factor * cutoff;
for ( i = -kernel_half; i <= kernel_half; i++ ) for ( i = -kernel_half; i <= kernel_half; i++ )
kernels [kernel_size / 2 + i] = (float) exp( i * i * cutoff ); kernels [kernel_size / 2 + i] = (float) exp( i * i * cutoff );
/* normalize even and odd phases separately */ /* normalize even and odd phases separately */
for ( i = 0; i < 2; i++ ) for ( i = 0; i < 2; i++ )
{ {
float sum = 0; float sum = 0;
int x; int x;
for ( x = i; x < kernel_size; x += 2 ) for ( x = i; x < kernel_size; x += 2 )
sum += kernels [x]; sum += kernels [x];
sum = 1.0f / sum; sum = 1.0f / sum;
for ( x = i; x < kernel_size; x += 2 ) for ( x = i; x < kernel_size; x += 2 )
{ {
kernels [x] *= sum; kernels [x] *= sum;
assert( kernels [x] == kernels [x] ); /* catch numerical instability */ assert( kernels [x] == kernels [x] ); /* catch numerical instability */
} }
} }
} }
/* /*
printf( "luma:\n" ); printf( "luma:\n" );
for ( i = kernel_size; i < kernel_size * 2; i++ ) for ( i = kernel_size; i < kernel_size * 2; i++ )
printf( "%f\n", kernels [i] ); printf( "%f\n", kernels [i] );
printf( "chroma:\n" ); printf( "chroma:\n" );
for ( i = 0; i < kernel_size; i++ ) for ( i = 0; i < kernel_size; i++ )
printf( "%f\n", kernels [i] ); printf( "%f\n", kernels [i] );
*/ */
/* generate linear rescale kernels */ /* generate linear rescale kernels */
#if rescale_out > 1 #if rescale_out > 1
{ {
float weight = 1.0f; float weight = 1.0f;
float* out = impl->kernel; float* out = impl->kernel;
int n = rescale_out; int n = rescale_out;
do do
{ {
float remain = 0; float remain = 0;
int i; int i;
weight -= 1.0f / rescale_in; weight -= 1.0f / rescale_in;
for ( i = 0; i < kernel_size * 2; i++ ) for ( i = 0; i < kernel_size * 2; i++ )
{ {
float cur = kernels [i]; float cur = kernels [i];
float m = cur * weight; float m = cur * weight;
*out++ = m + remain; *out++ = m + remain;
remain = cur - m; remain = cur - m;
} }
} }
while ( --n ); while ( --n );
} }
#endif #endif
} }
static float const default_decoder [6] = static float const default_decoder [6] =
{ 0.956f, 0.621f, -0.272f, -0.647f, -1.105f, 1.702f }; { 0.956f, 0.621f, -0.272f, -0.647f, -1.105f, 1.702f };
static void init( init_t* impl, md_ntsc_setup_t const* setup ) static void init( init_t* impl, md_ntsc_setup_t const* setup )
{ {
impl->brightness = (float) setup->brightness * (0.5f * rgb_unit) + rgb_offset; impl->brightness = (float) setup->brightness * (0.5f * rgb_unit) + rgb_offset;
impl->contrast = (float) setup->contrast * (0.5f * rgb_unit) + rgb_unit; impl->contrast = (float) setup->contrast * (0.5f * rgb_unit) + rgb_unit;
#ifdef default_palette_contrast #ifdef default_palette_contrast
if ( !setup->palette ) if ( !setup->palette )
impl->contrast *= default_palette_contrast; impl->contrast *= default_palette_contrast;
#endif #endif
impl->artifacts = (float) setup->artifacts; impl->artifacts = (float) setup->artifacts;
if ( impl->artifacts > 0 ) if ( impl->artifacts > 0 )
impl->artifacts *= artifacts_max - artifacts_mid; impl->artifacts *= artifacts_max - artifacts_mid;
impl->artifacts = impl->artifacts * artifacts_mid + artifacts_mid; impl->artifacts = impl->artifacts * artifacts_mid + artifacts_mid;
impl->fringing = (float) setup->fringing; impl->fringing = (float) setup->fringing;
if ( impl->fringing > 0 ) if ( impl->fringing > 0 )
impl->fringing *= fringing_max - fringing_mid; impl->fringing *= fringing_max - fringing_mid;
impl->fringing = impl->fringing * fringing_mid + fringing_mid; impl->fringing = impl->fringing * fringing_mid + fringing_mid;
init_filters( impl, setup ); init_filters( impl, setup );
/* generate gamma table */ /* generate gamma table */
if ( gamma_size > 1 ) if ( gamma_size > 1 )
{ {
float const to_float = 1.0f / (gamma_size - (gamma_size > 1)); float const to_float = 1.0f / (gamma_size - (gamma_size > 1));
float const gamma = 1.1333f - (float) setup->gamma * 0.5f; float const gamma = 1.1333f - (float) setup->gamma * 0.5f;
/* match common PC's 2.2 gamma to TV's 2.65 gamma */ /* match common PC's 2.2 gamma to TV's 2.65 gamma */
int i; int i;
for ( i = 0; i < gamma_size; i++ ) for ( i = 0; i < gamma_size; i++ )
impl->to_float [i] = impl->to_float [i] =
(float) pow( i * to_float, gamma ) * impl->contrast + impl->brightness; (float) pow( i * to_float, gamma ) * impl->contrast + impl->brightness;
} }
/* setup decoder matricies */ /* setup decoder matricies */
{ {
float hue = (float) setup->hue * PI + PI / 180 * ext_decoder_hue; float hue = (float) setup->hue * PI + PI / 180 * ext_decoder_hue;
float sat = (float) setup->saturation + 1; float sat = (float) setup->saturation + 1;
float const* decoder = setup->decoder_matrix; float const* decoder = setup->decoder_matrix;
if ( !decoder ) if ( !decoder )
{ {
decoder = default_decoder; decoder = default_decoder;
if ( STD_HUE_CONDITION( setup ) ) if ( STD_HUE_CONDITION( setup ) )
hue += PI / 180 * (std_decoder_hue - ext_decoder_hue); hue += PI / 180 * (std_decoder_hue - ext_decoder_hue);
} }
{ {
float s = (float) sin( hue ) * sat; float s = (float) sin( hue ) * sat;
float c = (float) cos( hue ) * sat; float c = (float) cos( hue ) * sat;
float* out = impl->to_rgb; float* out = impl->to_rgb;
int n; int n;
n = burst_count; n = burst_count;
do do
{ {
float const* in = decoder; float const* in = decoder;
int n = 3; int n = 3;
do do
{ {
float i = *in++; float i = *in++;
float q = *in++; float q = *in++;
*out++ = i * c - q * s; *out++ = i * c - q * s;
*out++ = i * s + q * c; *out++ = i * s + q * c;
} }
while ( --n ); while ( --n );
if ( burst_count <= 1 ) if ( burst_count <= 1 )
break; break;
ROTATE_IQ( s, c, 0.866025f, -0.5f ); /* +120 degrees */ ROTATE_IQ( s, c, 0.866025f, -0.5f ); /* +120 degrees */
} }
while ( --n ); while ( --n );
} }
} }
} }
/* kernel generation */ /* kernel generation */
#define RGB_TO_YIQ( r, g, b, y, i ) (\ #define RGB_TO_YIQ( r, g, b, y, i ) (\
(y = (r) * 0.299f + (g) * 0.587f + (b) * 0.114f),\ (y = (r) * 0.299f + (g) * 0.587f + (b) * 0.114f),\
(i = (r) * 0.596f - (g) * 0.275f - (b) * 0.321f),\ (i = (r) * 0.596f - (g) * 0.275f - (b) * 0.321f),\
((r) * 0.212f - (g) * 0.523f + (b) * 0.311f)\ ((r) * 0.212f - (g) * 0.523f + (b) * 0.311f)\
) )
#define YIQ_TO_RGB( y, i, q, to_rgb, type, r, g ) (\ #define YIQ_TO_RGB( y, i, q, to_rgb, type, r, g ) (\
r = (type) (y + to_rgb [0] * i + to_rgb [1] * q),\ r = (type) (y + to_rgb [0] * i + to_rgb [1] * q),\
g = (type) (y + to_rgb [2] * i + to_rgb [3] * q),\ g = (type) (y + to_rgb [2] * i + to_rgb [3] * q),\
(type) (y + to_rgb [4] * i + to_rgb [5] * q)\ (type) (y + to_rgb [4] * i + to_rgb [5] * q)\
) )
#define PACK_RGB( r, g, b ) ((r) << 21 | (g) << 11 | (b) << 1) #define PACK_RGB( r, g, b ) ((r) << 21 | (g) << 11 | (b) << 1)
@ -289,24 +289,24 @@ enum { rgb_bias = rgb_unit * 2 * md_ntsc_rgb_builder };
typedef struct pixel_info_t typedef struct pixel_info_t
{ {
int offset; int offset;
float negate; float negate;
float kernel [4]; float kernel [4];
} pixel_info_t; } pixel_info_t;
#if rescale_in > 1 #if rescale_in > 1
#define PIXEL_OFFSET_( ntsc, scaled ) \ #define PIXEL_OFFSET_( ntsc, scaled ) \
(kernel_size / 2 + ntsc + (scaled != 0) + (rescale_out - scaled) % rescale_out + \ (kernel_size / 2 + ntsc + (scaled != 0) + (rescale_out - scaled) % rescale_out + \
(kernel_size * 2 * scaled)) (kernel_size * 2 * scaled))
#define PIXEL_OFFSET( ntsc, scaled ) \ #define PIXEL_OFFSET( ntsc, scaled ) \
PIXEL_OFFSET_( ((ntsc) - (scaled) / rescale_out * rescale_in),\ PIXEL_OFFSET_( ((ntsc) - (scaled) / rescale_out * rescale_in),\
(((scaled) + rescale_out * 10) % rescale_out) ),\ (((scaled) + rescale_out * 10) % rescale_out) ),\
(1.0f - (((ntsc) + 100) & 2)) (1.0f - (((ntsc) + 100) & 2))
#else #else
#define PIXEL_OFFSET( ntsc, scaled ) \ #define PIXEL_OFFSET( ntsc, scaled ) \
(kernel_size / 2 + (ntsc) - (scaled)),\ (kernel_size / 2 + (ntsc) - (scaled)),\
(1.0f - (((ntsc) + 100) & 2)) (1.0f - (((ntsc) + 100) & 2))
#endif #endif
extern pixel_info_t const md_ntsc_pixels [alignment_count]; extern pixel_info_t const md_ntsc_pixels [alignment_count];
@ -314,126 +314,126 @@ extern pixel_info_t const md_ntsc_pixels [alignment_count];
/* Generate pixel at all burst phases and column alignments */ /* Generate pixel at all burst phases and column alignments */
static void gen_kernel( init_t* impl, float y, float i, float q, md_ntsc_rgb_t* out ) static void gen_kernel( init_t* impl, float y, float i, float q, md_ntsc_rgb_t* out )
{ {
/* generate for each scanline burst phase */ /* generate for each scanline burst phase */
float const* to_rgb = impl->to_rgb; float const* to_rgb = impl->to_rgb;
int burst_remain = burst_count; int burst_remain = burst_count;
y -= rgb_offset; y -= rgb_offset;
do do
{ {
/* Encode yiq into *two* composite signals (to allow control over artifacting). /* Encode yiq into *two* composite signals (to allow control over artifacting).
Convolve these with kernels which: filter respective components, apply Convolve these with kernels which: filter respective components, apply
sharpening, and rescale horizontally. Convert resulting yiq to rgb and pack sharpening, and rescale horizontally. Convert resulting yiq to rgb and pack
into integer. Based on algorithm by NewRisingSun. */ into integer. Based on algorithm by NewRisingSun. */
pixel_info_t const* pixel = md_ntsc_pixels; pixel_info_t const* pixel = md_ntsc_pixels;
int alignment_remain = alignment_count; int alignment_remain = alignment_count;
do do
{ {
/* negate is -1 when composite starts at odd multiple of 2 */ /* negate is -1 when composite starts at odd multiple of 2 */
float const yy = y * impl->fringing * pixel->negate; float const yy = y * impl->fringing * pixel->negate;
float const ic0 = (i + yy) * pixel->kernel [0]; float const ic0 = (i + yy) * pixel->kernel [0];
float const qc1 = (q + yy) * pixel->kernel [1]; float const qc1 = (q + yy) * pixel->kernel [1];
float const ic2 = (i - yy) * pixel->kernel [2]; float const ic2 = (i - yy) * pixel->kernel [2];
float const qc3 = (q - yy) * pixel->kernel [3]; float const qc3 = (q - yy) * pixel->kernel [3];
float const factor = impl->artifacts * pixel->negate; float const factor = impl->artifacts * pixel->negate;
float const ii = i * factor; float const ii = i * factor;
float const yc0 = (y + ii) * pixel->kernel [0]; float const yc0 = (y + ii) * pixel->kernel [0];
float const yc2 = (y - ii) * pixel->kernel [2]; float const yc2 = (y - ii) * pixel->kernel [2];
float const qq = q * factor; float const qq = q * factor;
float const yc1 = (y + qq) * pixel->kernel [1]; float const yc1 = (y + qq) * pixel->kernel [1];
float const yc3 = (y - qq) * pixel->kernel [3]; float const yc3 = (y - qq) * pixel->kernel [3];
float const* k = &impl->kernel [pixel->offset]; float const* k = &impl->kernel [pixel->offset];
int n; int n;
++pixel; ++pixel;
for ( n = rgb_kernel_size; n; --n ) for ( n = rgb_kernel_size; n; --n )
{ {
float i = k[0]*ic0 + k[2]*ic2; float i = k[0]*ic0 + k[2]*ic2;
float q = k[1]*qc1 + k[3]*qc3; float q = k[1]*qc1 + k[3]*qc3;
float y = k[kernel_size+0]*yc0 + k[kernel_size+1]*yc1 + float y = k[kernel_size+0]*yc0 + k[kernel_size+1]*yc1 +
k[kernel_size+2]*yc2 + k[kernel_size+3]*yc3 + rgb_offset; k[kernel_size+2]*yc2 + k[kernel_size+3]*yc3 + rgb_offset;
if ( rescale_out <= 1 ) if ( rescale_out <= 1 )
k--; k--;
else if ( k < &impl->kernel [kernel_size * 2 * (rescale_out - 1)] ) else if ( k < &impl->kernel [kernel_size * 2 * (rescale_out - 1)] )
k += kernel_size * 2 - 1; k += kernel_size * 2 - 1;
else else
k -= kernel_size * 2 * (rescale_out - 1) + 2; k -= kernel_size * 2 * (rescale_out - 1) + 2;
{ {
int r, g, b = YIQ_TO_RGB( y, i, q, to_rgb, int, r, g ); int r, g, b = YIQ_TO_RGB( y, i, q, to_rgb, int, r, g );
*out++ = PACK_RGB( r, g, b ) - rgb_bias; *out++ = PACK_RGB( r, g, b ) - rgb_bias;
} }
} }
} }
while ( alignment_count > 1 && --alignment_remain ); while ( alignment_count > 1 && --alignment_remain );
if ( burst_count <= 1 ) if ( burst_count <= 1 )
break; break;
to_rgb += 6; to_rgb += 6;
ROTATE_IQ( i, q, -0.866025f, -0.5f ); /* -120 degrees */ ROTATE_IQ( i, q, -0.866025f, -0.5f ); /* -120 degrees */
} }
while ( --burst_remain ); while ( --burst_remain );
} }
static void correct_errors( md_ntsc_rgb_t color, md_ntsc_rgb_t* out ); static void correct_errors( md_ntsc_rgb_t color, md_ntsc_rgb_t* out );
#if DISABLE_CORRECTION #if DISABLE_CORRECTION
#define CORRECT_ERROR( a ) { out [i] += rgb_bias; } #define CORRECT_ERROR( a ) { out [i] += rgb_bias; }
#define DISTRIBUTE_ERROR( a, b, c ) { out [i] += rgb_bias; } #define DISTRIBUTE_ERROR( a, b, c ) { out [i] += rgb_bias; }
#else #else
#define CORRECT_ERROR( a ) { out [a] += error; } #define CORRECT_ERROR( a ) { out [a] += error; }
#define DISTRIBUTE_ERROR( a, b, c ) {\ #define DISTRIBUTE_ERROR( a, b, c ) {\
md_ntsc_rgb_t fourth = (error + 2 * md_ntsc_rgb_builder) >> 2;\ md_ntsc_rgb_t fourth = (error + 2 * md_ntsc_rgb_builder) >> 2;\
fourth &= (rgb_bias >> 1) - md_ntsc_rgb_builder;\ fourth &= (rgb_bias >> 1) - md_ntsc_rgb_builder;\
fourth -= rgb_bias >> 2;\ fourth -= rgb_bias >> 2;\
out [a] += fourth;\ out [a] += fourth;\
out [b] += fourth;\ out [b] += fourth;\
out [c] += fourth;\ out [c] += fourth;\
out [i] += error - (fourth * 3);\ out [i] += error - (fourth * 3);\
} }
#endif #endif
#define RGB_PALETTE_OUT( rgb, out_ )\ #define RGB_PALETTE_OUT( rgb, out_ )\
{\ {\
unsigned char* out = (out_);\ unsigned char* out = (out_);\
md_ntsc_rgb_t clamped = (rgb);\ md_ntsc_rgb_t clamped = (rgb);\
MD_NTSC_CLAMP_( clamped, (8 - rgb_bits) );\ MD_NTSC_CLAMP_( clamped, (8 - rgb_bits) );\
out [0] = (unsigned char) (clamped >> 21);\ out [0] = (unsigned char) (clamped >> 21);\
out [1] = (unsigned char) (clamped >> 11);\ out [1] = (unsigned char) (clamped >> 11);\
out [2] = (unsigned char) (clamped >> 1);\ out [2] = (unsigned char) (clamped >> 1);\
} }
/* blitter related */ /* blitter related */
#ifndef restrict #ifndef restrict
#if defined (__GNUC__) #if defined (__GNUC__)
#define restrict __restrict__ #define restrict __restrict__
#elif defined (_MSC_VER) && _MSC_VER > 1300 #elif defined (_MSC_VER) && _MSC_VER > 1300
#define restrict #define restrict
#else #else
/* no support for restricted pointers */ /* no support for restricted pointers */
#define restrict #define restrict
#endif #endif
#endif #endif
#include <limits.h> #include <limits.h>
#if MD_NTSC_OUT_DEPTH <= 16 #if MD_NTSC_OUT_DEPTH <= 16
#if USHRT_MAX == 0xFFFF #if USHRT_MAX == 0xFFFF
typedef unsigned short md_ntsc_out_t; typedef unsigned short md_ntsc_out_t;
#else #else
#error "Need 16-bit int type" #error "Need 16-bit int type"
#endif #endif
#else #else
#if UINT_MAX == 0xFFFFFFFF #if UINT_MAX == 0xFFFFFFFF
typedef unsigned int md_ntsc_out_t; typedef unsigned int md_ntsc_out_t;
#elif ULONG_MAX == 0xFFFFFFFF #elif ULONG_MAX == 0xFFFFFFFF
typedef unsigned long md_ntsc_out_t; typedef unsigned long md_ntsc_out_t;
#else #else
#error "Need 32-bit int type" #error "Need 32-bit int type"
#endif #endif
#endif #endif

View File

@ -35,71 +35,71 @@ sms_ntsc_setup_t const sms_ntsc_rgb = { 0, 0, 0, 0,.2, 0,.70, -1, -1,-1,
/* 3 input pixels -> 8 composite samples */ /* 3 input pixels -> 8 composite samples */
pixel_info_t const sms_ntsc_pixels [alignment_count] = { pixel_info_t const sms_ntsc_pixels [alignment_count] = {
{ PIXEL_OFFSET( -4, -9 ), { 1, 1, .6667f, 0 } }, { PIXEL_OFFSET( -4, -9 ), { 1, 1, .6667f, 0 } },
{ PIXEL_OFFSET( -2, -7 ), { .3333f, 1, 1, .3333f } }, { PIXEL_OFFSET( -2, -7 ), { .3333f, 1, 1, .3333f } },
{ PIXEL_OFFSET( 0, -5 ), { 0, .6667f, 1, 1 } }, { PIXEL_OFFSET( 0, -5 ), { 0, .6667f, 1, 1 } },
}; };
static void correct_errors( sms_ntsc_rgb_t color, sms_ntsc_rgb_t* out ) static void correct_errors( sms_ntsc_rgb_t color, sms_ntsc_rgb_t* out )
{ {
unsigned i; unsigned i;
for ( i = 0; i < rgb_kernel_size / 2; i++ ) for ( i = 0; i < rgb_kernel_size / 2; i++ )
{ {
sms_ntsc_rgb_t error = color - sms_ntsc_rgb_t error = color -
out [i ] - out [(i+12)%14+14] - out [(i+10)%14+28] - out [i ] - out [(i+12)%14+14] - out [(i+10)%14+28] -
out [i + 7] - out [i + 5 +14] - out [i + 3 +28]; out [i + 7] - out [i + 5 +14] - out [i + 3 +28];
CORRECT_ERROR( i + 3 + 28 ); CORRECT_ERROR( i + 3 + 28 );
} }
} }
void sms_ntsc_init( sms_ntsc_t* ntsc, sms_ntsc_setup_t const* setup ) void sms_ntsc_init( sms_ntsc_t* ntsc, sms_ntsc_setup_t const* setup )
{ {
int entry; int entry;
init_t impl; init_t impl;
if ( !setup ) if ( !setup )
setup = &sms_ntsc_composite; setup = &sms_ntsc_composite;
init( &impl, setup ); init( &impl, setup );
for ( entry = 0; entry < sms_ntsc_palette_size; entry++ ) for ( entry = 0; entry < sms_ntsc_palette_size; entry++ )
{ {
float bb = impl.to_float [entry >> 8 & 0x0F]; float bb = impl.to_float [entry >> 8 & 0x0F];
float gg = impl.to_float [entry >> 4 & 0x0F]; float gg = impl.to_float [entry >> 4 & 0x0F];
float rr = impl.to_float [entry & 0x0F]; float rr = impl.to_float [entry & 0x0F];
float y, i, q = RGB_TO_YIQ( rr, gg, bb, y, i ); float y, i, q = RGB_TO_YIQ( rr, gg, bb, y, i );
int r, g, b = YIQ_TO_RGB( y, i, q, impl.to_rgb, int, r, g ); int r, g, b = YIQ_TO_RGB( y, i, q, impl.to_rgb, int, r, g );
sms_ntsc_rgb_t rgb = PACK_RGB( r, g, b ); sms_ntsc_rgb_t rgb = PACK_RGB( r, g, b );
if ( setup->palette_out ) if ( setup->palette_out )
RGB_PALETTE_OUT( rgb, &setup->palette_out [entry * 3] ); RGB_PALETTE_OUT( rgb, &setup->palette_out [entry * 3] );
if ( ntsc ) if ( ntsc )
{ {
gen_kernel( &impl, y, i, q, ntsc->table [entry] ); gen_kernel( &impl, y, i, q, ntsc->table [entry] );
correct_errors( rgb, ntsc->table [entry] ); correct_errors( rgb, ntsc->table [entry] );
} }
} }
} }
#ifndef SMS_NTSC_NO_BLITTERS #ifndef SMS_NTSC_NO_BLITTERS
/* modified blitters to work on a line basis with genesis plus renderer*/ /* modified blitters to work on a line basis with genesis plus renderer*/
void sms_ntsc_blit( sms_ntsc_t const* ntsc, SMS_NTSC_IN_T const* table, unsigned char* input, void sms_ntsc_blit( sms_ntsc_t const* ntsc, SMS_NTSC_IN_T const* table, unsigned char* input,
int in_width, int vline) int in_width, int vline)
{ {
int const chunk_count = in_width / sms_ntsc_in_chunk; int const chunk_count = in_width / sms_ntsc_in_chunk;
/* handle extra 0, 1, or 2 pixels by placing them at beginning of row */ /* handle extra 0, 1, or 2 pixels by placing them at beginning of row */
int const in_extra = in_width - chunk_count * sms_ntsc_in_chunk; int const in_extra = in_width - chunk_count * sms_ntsc_in_chunk;
unsigned const extra2 = (unsigned) -(in_extra >> 1 & 1); /* (unsigned) -1 = ~0 */ unsigned const extra2 = (unsigned) -(in_extra >> 1 & 1); /* (unsigned) -1 = ~0 */
unsigned const extra1 = (unsigned) -(in_extra & 1) | extra2; unsigned const extra1 = (unsigned) -(in_extra & 1) | extra2;
SMS_NTSC_IN_T border = table[0]; SMS_NTSC_IN_T border = table[0];
SMS_NTSC_BEGIN_ROW( ntsc, border, SMS_NTSC_BEGIN_ROW( ntsc, border,
(SMS_NTSC_ADJ_IN( table[input[0]] )) & extra2, (SMS_NTSC_ADJ_IN( table[input[0]] )) & extra2,
(SMS_NTSC_ADJ_IN( table[input[extra2 & 1]] )) & extra1 ); (SMS_NTSC_ADJ_IN( table[input[extra2 & 1]] )) & extra1 );
#ifdef NGC #ifdef NGC
/* directly fill the RGB565 texture */ /* directly fill the RGB565 texture */
@ -113,83 +113,83 @@ void sms_ntsc_blit( sms_ntsc_t const* ntsc, SMS_NTSC_IN_T const* table, unsigned
sms_ntsc_out_t* restrict line_out = (sms_ntsc_out_t*)(&bitmap.data[(vline * bitmap.pitch)]); sms_ntsc_out_t* restrict line_out = (sms_ntsc_out_t*)(&bitmap.data[(vline * bitmap.pitch)]);
#endif #endif
int n; int n;
input += in_extra; input += in_extra;
for ( n = chunk_count; n; --n ) for ( n = chunk_count; n; --n )
{ {
/* order of input and output pixels must not be altered */ /* order of input and output pixels must not be altered */
SMS_NTSC_COLOR_IN( 0, ntsc, SMS_NTSC_ADJ_IN( table[*input++] ) ); SMS_NTSC_COLOR_IN( 0, ntsc, SMS_NTSC_ADJ_IN( table[*input++] ) );
#ifdef NGC #ifdef NGC
SMS_NTSC_RGB_OUT( 0, line_out[offset++], SMS_NTSC_OUT_DEPTH ); SMS_NTSC_RGB_OUT( 0, line_out[offset++], SMS_NTSC_OUT_DEPTH );
if ((offset % 4) == 0) offset += 12; if ((offset % 4) == 0) offset += 12;
SMS_NTSC_RGB_OUT( 1, line_out[offset++], SMS_NTSC_OUT_DEPTH ); SMS_NTSC_RGB_OUT( 1, line_out[offset++], SMS_NTSC_OUT_DEPTH );
if ((offset % 4) == 0) offset += 12; if ((offset % 4) == 0) offset += 12;
#else #else
SMS_NTSC_RGB_OUT( 0, *line_out++, SMS_NTSC_OUT_DEPTH ); SMS_NTSC_RGB_OUT( 0, *line_out++, SMS_NTSC_OUT_DEPTH );
SMS_NTSC_RGB_OUT( 1, *line_out++, SMS_NTSC_OUT_DEPTH ); SMS_NTSC_RGB_OUT( 1, *line_out++, SMS_NTSC_OUT_DEPTH );
#endif #endif
SMS_NTSC_COLOR_IN( 1, ntsc, SMS_NTSC_ADJ_IN( table[*input++] ) ); SMS_NTSC_COLOR_IN( 1, ntsc, SMS_NTSC_ADJ_IN( table[*input++] ) );
#ifdef NGC #ifdef NGC
SMS_NTSC_RGB_OUT( 2, line_out[offset++], SMS_NTSC_OUT_DEPTH ); SMS_NTSC_RGB_OUT( 2, line_out[offset++], SMS_NTSC_OUT_DEPTH );
if ((offset % 4) == 0) offset += 12; if ((offset % 4) == 0) offset += 12;
SMS_NTSC_RGB_OUT( 3, line_out[offset++], SMS_NTSC_OUT_DEPTH ); SMS_NTSC_RGB_OUT( 3, line_out[offset++], SMS_NTSC_OUT_DEPTH );
if ((offset % 4) == 0) offset += 12; if ((offset % 4) == 0) offset += 12;
#else #else
SMS_NTSC_RGB_OUT( 2, *line_out++, SMS_NTSC_OUT_DEPTH ); SMS_NTSC_RGB_OUT( 2, *line_out++, SMS_NTSC_OUT_DEPTH );
SMS_NTSC_RGB_OUT( 3, *line_out++, SMS_NTSC_OUT_DEPTH ); SMS_NTSC_RGB_OUT( 3, *line_out++, SMS_NTSC_OUT_DEPTH );
#endif #endif
SMS_NTSC_COLOR_IN( 2, ntsc, SMS_NTSC_ADJ_IN( table[*input++] ) ); SMS_NTSC_COLOR_IN( 2, ntsc, SMS_NTSC_ADJ_IN( table[*input++] ) );
#ifdef NGC #ifdef NGC
SMS_NTSC_RGB_OUT( 4, line_out[offset++], SMS_NTSC_OUT_DEPTH ); SMS_NTSC_RGB_OUT( 4, line_out[offset++], SMS_NTSC_OUT_DEPTH );
if ((offset % 4) == 0) offset += 12; if ((offset % 4) == 0) offset += 12;
SMS_NTSC_RGB_OUT( 5, line_out[offset++], SMS_NTSC_OUT_DEPTH ); SMS_NTSC_RGB_OUT( 5, line_out[offset++], SMS_NTSC_OUT_DEPTH );
if ((offset % 4) == 0) offset += 12; if ((offset % 4) == 0) offset += 12;
SMS_NTSC_RGB_OUT( 6, line_out[offset++], SMS_NTSC_OUT_DEPTH ); SMS_NTSC_RGB_OUT( 6, line_out[offset++], SMS_NTSC_OUT_DEPTH );
if ((offset % 4) == 0) offset += 12; if ((offset % 4) == 0) offset += 12;
#else #else
SMS_NTSC_RGB_OUT( 4, *line_out++, SMS_NTSC_OUT_DEPTH ); SMS_NTSC_RGB_OUT( 4, *line_out++, SMS_NTSC_OUT_DEPTH );
SMS_NTSC_RGB_OUT( 5, *line_out++, SMS_NTSC_OUT_DEPTH ); SMS_NTSC_RGB_OUT( 5, *line_out++, SMS_NTSC_OUT_DEPTH );
SMS_NTSC_RGB_OUT( 6, *line_out++, SMS_NTSC_OUT_DEPTH ); SMS_NTSC_RGB_OUT( 6, *line_out++, SMS_NTSC_OUT_DEPTH );
#endif #endif
} }
/* finish final pixels */ /* finish final pixels */
SMS_NTSC_COLOR_IN( 0, ntsc, border ); SMS_NTSC_COLOR_IN( 0, ntsc, border );
#ifdef NGC #ifdef NGC
SMS_NTSC_RGB_OUT( 0, line_out[offset++], SMS_NTSC_OUT_DEPTH ); SMS_NTSC_RGB_OUT( 0, line_out[offset++], SMS_NTSC_OUT_DEPTH );
if ((offset % 4) == 0) offset += 12; if ((offset % 4) == 0) offset += 12;
SMS_NTSC_RGB_OUT( 1, line_out[offset++], SMS_NTSC_OUT_DEPTH ); SMS_NTSC_RGB_OUT( 1, line_out[offset++], SMS_NTSC_OUT_DEPTH );
if ((offset % 4) == 0) offset += 12; if ((offset % 4) == 0) offset += 12;
#else #else
SMS_NTSC_RGB_OUT( 0, *line_out++, SMS_NTSC_OUT_DEPTH ); SMS_NTSC_RGB_OUT( 0, *line_out++, SMS_NTSC_OUT_DEPTH );
SMS_NTSC_RGB_OUT( 1, *line_out++, SMS_NTSC_OUT_DEPTH ); SMS_NTSC_RGB_OUT( 1, *line_out++, SMS_NTSC_OUT_DEPTH );
#endif #endif
SMS_NTSC_COLOR_IN( 1, ntsc, border ); SMS_NTSC_COLOR_IN( 1, ntsc, border );
#ifdef NGC #ifdef NGC
SMS_NTSC_RGB_OUT( 2, line_out[offset++], SMS_NTSC_OUT_DEPTH ); SMS_NTSC_RGB_OUT( 2, line_out[offset++], SMS_NTSC_OUT_DEPTH );
if ((offset % 4) == 0) offset += 12; if ((offset % 4) == 0) offset += 12;
SMS_NTSC_RGB_OUT( 3, line_out[offset++], SMS_NTSC_OUT_DEPTH ); SMS_NTSC_RGB_OUT( 3, line_out[offset++], SMS_NTSC_OUT_DEPTH );
if ((offset % 4) == 0) offset += 12; if ((offset % 4) == 0) offset += 12;
#else #else
SMS_NTSC_RGB_OUT( 2, *line_out++, SMS_NTSC_OUT_DEPTH ); SMS_NTSC_RGB_OUT( 2, *line_out++, SMS_NTSC_OUT_DEPTH );
SMS_NTSC_RGB_OUT( 3, *line_out++, SMS_NTSC_OUT_DEPTH ); SMS_NTSC_RGB_OUT( 3, *line_out++, SMS_NTSC_OUT_DEPTH );
#endif #endif
SMS_NTSC_COLOR_IN( 2, ntsc, border ); SMS_NTSC_COLOR_IN( 2, ntsc, border );
#ifdef NGC #ifdef NGC
SMS_NTSC_RGB_OUT( 4, line_out[offset++], SMS_NTSC_OUT_DEPTH ); SMS_NTSC_RGB_OUT( 4, line_out[offset++], SMS_NTSC_OUT_DEPTH );
if ((offset % 4) == 0) offset += 12; if ((offset % 4) == 0) offset += 12;
SMS_NTSC_RGB_OUT( 5, line_out[offset++], SMS_NTSC_OUT_DEPTH ); SMS_NTSC_RGB_OUT( 5, line_out[offset++], SMS_NTSC_OUT_DEPTH );
if ((offset % 4) == 0) offset += 12; if ((offset % 4) == 0) offset += 12;
SMS_NTSC_RGB_OUT( 6, line_out[offset++], SMS_NTSC_OUT_DEPTH ); SMS_NTSC_RGB_OUT( 6, line_out[offset++], SMS_NTSC_OUT_DEPTH );
if ((offset % 4) == 0) offset += 12; if ((offset % 4) == 0) offset += 12;
#else #else
SMS_NTSC_RGB_OUT( 4, *line_out++, SMS_NTSC_OUT_DEPTH ); SMS_NTSC_RGB_OUT( 4, *line_out++, SMS_NTSC_OUT_DEPTH );
SMS_NTSC_RGB_OUT( 5, *line_out++, SMS_NTSC_OUT_DEPTH ); SMS_NTSC_RGB_OUT( 5, *line_out++, SMS_NTSC_OUT_DEPTH );
SMS_NTSC_RGB_OUT( 6, *line_out++, SMS_NTSC_OUT_DEPTH ); SMS_NTSC_RGB_OUT( 6, *line_out++, SMS_NTSC_OUT_DEPTH );
#endif #endif
} }
#endif #endif

View File

@ -7,29 +7,29 @@
#include "sms_ntsc_config.h" #include "sms_ntsc_config.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
/* Image parameters, ranging from -1.0 to 1.0. Actual internal values shown /* Image parameters, ranging from -1.0 to 1.0. Actual internal values shown
in parenthesis and should remain fairly stable in future versions. */ in parenthesis and should remain fairly stable in future versions. */
typedef struct sms_ntsc_setup_t typedef struct sms_ntsc_setup_t
{ {
/* Basic parameters */ /* Basic parameters */
double hue; /* -1 = -180 degrees +1 = +180 degrees */ double hue; /* -1 = -180 degrees +1 = +180 degrees */
double saturation; /* -1 = grayscale (0.0) +1 = oversaturated colors (2.0) */ double saturation; /* -1 = grayscale (0.0) +1 = oversaturated colors (2.0) */
double contrast; /* -1 = dark (0.5) +1 = light (1.5) */ double contrast; /* -1 = dark (0.5) +1 = light (1.5) */
double brightness; /* -1 = dark (0.5) +1 = light (1.5) */ double brightness; /* -1 = dark (0.5) +1 = light (1.5) */
double sharpness; /* edge contrast enhancement/blurring */ double sharpness; /* edge contrast enhancement/blurring */
/* Advanced parameters */ /* Advanced parameters */
double gamma; /* -1 = dark (1.5) +1 = light (0.5) */ double gamma; /* -1 = dark (1.5) +1 = light (0.5) */
double resolution; /* image resolution */ double resolution; /* image resolution */
double artifacts; /* artifacts caused by color changes */ double artifacts; /* artifacts caused by color changes */
double fringing; /* color artifacts caused by brightness changes */ double fringing; /* color artifacts caused by brightness changes */
double bleed; /* color bleed (color resolution reduction) */ double bleed; /* color bleed (color resolution reduction) */
float const* decoder_matrix; /* optional RGB decoder matrix, 6 elements */ float const* decoder_matrix; /* optional RGB decoder matrix, 6 elements */
unsigned char* palette_out; /* optional RGB palette out, 3 bytes per color */ unsigned char* palette_out; /* optional RGB palette out, 3 bytes per color */
} sms_ntsc_setup_t; } sms_ntsc_setup_t;
/* Video format presets */ /* Video format presets */
@ -50,17 +50,17 @@ and output RGB depth is set by SMS_NTSC_OUT_DEPTH. Both default to 16-bit RGB.
In_row_width is the number of pixels to get to the next input row. Out_pitch In_row_width is the number of pixels to get to the next input row. Out_pitch
is the number of *bytes* to get to the next output row. */ is the number of *bytes* to get to the next output row. */
void sms_ntsc_blit( sms_ntsc_t const* ntsc, SMS_NTSC_IN_T const* table, unsigned char* input, void sms_ntsc_blit( sms_ntsc_t const* ntsc, SMS_NTSC_IN_T const* table, unsigned char* input,
int in_width, int vline); int in_width, int vline);
/* Number of output pixels written by blitter for given input width. */ /* Number of output pixels written by blitter for given input width. */
#define SMS_NTSC_OUT_WIDTH( in_width ) \ #define SMS_NTSC_OUT_WIDTH( in_width ) \
(((in_width) / sms_ntsc_in_chunk + 1) * sms_ntsc_out_chunk) (((in_width) / sms_ntsc_in_chunk + 1) * sms_ntsc_out_chunk)
/* Number of input pixels that will fit within given output width. Might be /* Number of input pixels that will fit within given output width. Might be
rounded down slightly; use SMS_NTSC_OUT_WIDTH() on result to find rounded rounded down slightly; use SMS_NTSC_OUT_WIDTH() on result to find rounded
value. */ value. */
#define SMS_NTSC_IN_WIDTH( out_width ) \ #define SMS_NTSC_IN_WIDTH( out_width ) \
(((out_width) / sms_ntsc_out_chunk - 1) * sms_ntsc_in_chunk + 2) (((out_width) / sms_ntsc_out_chunk - 1) * sms_ntsc_in_chunk + 2)
/* Interface for user-defined custom blitters */ /* Interface for user-defined custom blitters */
@ -73,11 +73,11 @@ enum { sms_ntsc_black = 0 }; /* palette index for black */
Use sms_ntsc_black for unused pixels. Declares variables, so must be before first Use sms_ntsc_black for unused pixels. Declares variables, so must be before first
statement in a block (unless you're using C++). */ statement in a block (unless you're using C++). */
#define SMS_NTSC_BEGIN_ROW( ntsc, pixel0, pixel1, pixel2 ) \ #define SMS_NTSC_BEGIN_ROW( ntsc, pixel0, pixel1, pixel2 ) \
SMS_NTSC_BEGIN_ROW_6_( pixel0, pixel1, pixel2, SMS_NTSC_IN_FORMAT, ntsc ) SMS_NTSC_BEGIN_ROW_6_( pixel0, pixel1, pixel2, SMS_NTSC_IN_FORMAT, ntsc )
/* Begins input pixel */ /* Begins input pixel */
#define SMS_NTSC_COLOR_IN( in_index, ntsc, color_in ) \ #define SMS_NTSC_COLOR_IN( in_index, ntsc, color_in ) \
SMS_NTSC_COLOR_IN_( in_index, color_in, SMS_NTSC_IN_FORMAT, ntsc ) SMS_NTSC_COLOR_IN_( in_index, color_in, SMS_NTSC_IN_FORMAT, ntsc )
/* Generates output pixel. Bits can be 24, 16, 15, 32 (treated as 24), or 0: /* Generates output pixel. Bits can be 24, 16, 15, 32 (treated as 24), or 0:
24: RRRRRRRR GGGGGGGG BBBBBBBB (8-8-8 RGB) 24: RRRRRRRR GGGGGGGG BBBBBBBB (8-8-8 RGB)
@ -85,46 +85,46 @@ statement in a block (unless you're using C++). */
15: RRRRRGG GGGBBBBB (5-5-5 RGB) 15: RRRRRGG GGGBBBBB (5-5-5 RGB)
0: xxxRRRRR RRRxxGGG GGGGGxxB BBBBBBBx (native internal format; x = junk bits) */ 0: xxxRRRRR RRRxxGGG GGGGGxxB BBBBBBBx (native internal format; x = junk bits) */
#define SMS_NTSC_RGB_OUT( index, rgb_out, bits ) \ #define SMS_NTSC_RGB_OUT( index, rgb_out, bits ) \
SMS_NTSC_RGB_OUT_14_( index, rgb_out, bits, 0 ) SMS_NTSC_RGB_OUT_14_( index, rgb_out, bits, 0 )
/* private */ /* private */
enum { sms_ntsc_entry_size = 3 * 14 }; enum { sms_ntsc_entry_size = 3 * 14 };
typedef unsigned long sms_ntsc_rgb_t; typedef unsigned long sms_ntsc_rgb_t;
struct sms_ntsc_t { struct sms_ntsc_t {
sms_ntsc_rgb_t table [sms_ntsc_palette_size] [sms_ntsc_entry_size]; sms_ntsc_rgb_t table [sms_ntsc_palette_size] [sms_ntsc_entry_size];
}; };
#define SMS_NTSC_BGR12( ntsc, n ) (ntsc)->table [n & 0xFFF] #define SMS_NTSC_BGR12( ntsc, n ) (ntsc)->table [n & 0xFFF]
#define SMS_NTSC_RGB16( ntsc, n ) \ #define SMS_NTSC_RGB16( ntsc, n ) \
(sms_ntsc_rgb_t const*) ((char const*) (ntsc)->table +\ (sms_ntsc_rgb_t const*) ((char const*) (ntsc)->table +\
((n << 10 & 0x7800) | (n & 0x0780) | (n >> 9 & 0x0078)) *\ ((n << 10 & 0x7800) | (n & 0x0780) | (n >> 9 & 0x0078)) *\
(sms_ntsc_entry_size * sizeof (sms_ntsc_rgb_t) / 8)) (sms_ntsc_entry_size * sizeof (sms_ntsc_rgb_t) / 8))
#define SMS_NTSC_RGB15( ntsc, n ) \ #define SMS_NTSC_RGB15( ntsc, n ) \
(sms_ntsc_rgb_t const*) ((char const*) (ntsc)->table +\ (sms_ntsc_rgb_t const*) ((char const*) (ntsc)->table +\
((n << 9 & 0x3C00) | (n & 0x03C0) | (n >> 9 & 0x003C)) *\ ((n << 9 & 0x3C00) | (n & 0x03C0) | (n >> 9 & 0x003C)) *\
(sms_ntsc_entry_size * sizeof (sms_ntsc_rgb_t) / 4)) (sms_ntsc_entry_size * sizeof (sms_ntsc_rgb_t) / 4))
/* common 3->7 ntsc macros */ /* common 3->7 ntsc macros */
#define SMS_NTSC_BEGIN_ROW_6_( pixel0, pixel1, pixel2, ENTRY, table ) \ #define SMS_NTSC_BEGIN_ROW_6_( pixel0, pixel1, pixel2, ENTRY, table ) \
unsigned const sms_ntsc_pixel0_ = (pixel0);\ unsigned const sms_ntsc_pixel0_ = (pixel0);\
sms_ntsc_rgb_t const* kernel0 = ENTRY( table, sms_ntsc_pixel0_ );\ sms_ntsc_rgb_t const* kernel0 = ENTRY( table, sms_ntsc_pixel0_ );\
unsigned const sms_ntsc_pixel1_ = (pixel1);\ unsigned const sms_ntsc_pixel1_ = (pixel1);\
sms_ntsc_rgb_t const* kernel1 = ENTRY( table, sms_ntsc_pixel1_ );\ sms_ntsc_rgb_t const* kernel1 = ENTRY( table, sms_ntsc_pixel1_ );\
unsigned const sms_ntsc_pixel2_ = (pixel2);\ unsigned const sms_ntsc_pixel2_ = (pixel2);\
sms_ntsc_rgb_t const* kernel2 = ENTRY( table, sms_ntsc_pixel2_ );\ sms_ntsc_rgb_t const* kernel2 = ENTRY( table, sms_ntsc_pixel2_ );\
sms_ntsc_rgb_t const* kernelx0;\ sms_ntsc_rgb_t const* kernelx0;\
sms_ntsc_rgb_t const* kernelx1 = kernel0;\ sms_ntsc_rgb_t const* kernelx1 = kernel0;\
sms_ntsc_rgb_t const* kernelx2 = kernel0 sms_ntsc_rgb_t const* kernelx2 = kernel0
#define SMS_NTSC_RGB_OUT_14_( x, rgb_out, bits, shift ) {\ #define SMS_NTSC_RGB_OUT_14_( x, rgb_out, bits, shift ) {\
sms_ntsc_rgb_t raw_ =\ sms_ntsc_rgb_t raw_ =\
kernel0 [x ] + kernel1 [(x+12)%7+14] + kernel2 [(x+10)%7+28] +\ kernel0 [x ] + kernel1 [(x+12)%7+14] + kernel2 [(x+10)%7+28] +\
kernelx0 [(x+7)%14] + kernelx1 [(x+ 5)%7+21] + kernelx2 [(x+ 3)%7+35];\ kernelx0 [(x+7)%14] + kernelx1 [(x+ 5)%7+21] + kernelx2 [(x+ 3)%7+35];\
SMS_NTSC_CLAMP_( raw_, shift );\ SMS_NTSC_CLAMP_( raw_, shift );\
SMS_NTSC_RGB_OUT_( rgb_out, bits, shift );\ SMS_NTSC_RGB_OUT_( rgb_out, bits, shift );\
} }
/* common ntsc macros */ /* common ntsc macros */
@ -132,26 +132,26 @@ struct sms_ntsc_t {
#define sms_ntsc_clamp_mask (sms_ntsc_rgb_builder * 3 / 2) #define sms_ntsc_clamp_mask (sms_ntsc_rgb_builder * 3 / 2)
#define sms_ntsc_clamp_add (sms_ntsc_rgb_builder * 0x101) #define sms_ntsc_clamp_add (sms_ntsc_rgb_builder * 0x101)
#define SMS_NTSC_CLAMP_( io, shift ) {\ #define SMS_NTSC_CLAMP_( io, shift ) {\
sms_ntsc_rgb_t sub = (io) >> (9-(shift)) & sms_ntsc_clamp_mask;\ sms_ntsc_rgb_t sub = (io) >> (9-(shift)) & sms_ntsc_clamp_mask;\
sms_ntsc_rgb_t clamp = sms_ntsc_clamp_add - sub;\ sms_ntsc_rgb_t clamp = sms_ntsc_clamp_add - sub;\
io |= clamp;\ io |= clamp;\
clamp -= sub;\ clamp -= sub;\
io &= clamp;\ io &= clamp;\
} }
#define SMS_NTSC_COLOR_IN_( index, color, ENTRY, table ) {\ #define SMS_NTSC_COLOR_IN_( index, color, ENTRY, table ) {\
unsigned color_;\ unsigned color_;\
kernelx##index = kernel##index;\ kernelx##index = kernel##index;\
kernel##index = (color_ = (color), ENTRY( table, color_ ));\ kernel##index = (color_ = (color), ENTRY( table, color_ ));\
} }
/* x is always zero except in snes_ntsc library */ /* x is always zero except in snes_ntsc library */
#define SMS_NTSC_RGB_OUT_( rgb_out, bits, x ) {\ #define SMS_NTSC_RGB_OUT_( rgb_out, bits, x ) {\
rgb_out = (raw_>>(13-x)& 0xF800)|(raw_>>(8-x)&0x07E0)|(raw_>>(4-x)&0x001F);\ rgb_out = (raw_>>(13-x)& 0xF800)|(raw_>>(8-x)&0x07E0)|(raw_>>(4-x)&0x001F);\
} }
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
#endif #endif

View File

@ -22,22 +22,22 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
#define PI 3.14159265358979323846f #define PI 3.14159265358979323846f
#ifndef LUMA_CUTOFF #ifndef LUMA_CUTOFF
#define LUMA_CUTOFF 0.20 #define LUMA_CUTOFF 0.20
#endif #endif
#ifndef gamma_size #ifndef gamma_size
#define gamma_size 1 #define gamma_size 1
#endif #endif
#ifndef rgb_bits #ifndef rgb_bits
#define rgb_bits 8 #define rgb_bits 8
#endif #endif
#ifndef artifacts_max #ifndef artifacts_max
#define artifacts_max (artifacts_mid * 1.5f) #define artifacts_max (artifacts_mid * 1.5f)
#endif #endif
#ifndef fringing_max #ifndef fringing_max
#define fringing_max (fringing_mid * 2) #define fringing_max (fringing_mid * 2)
#endif #endif
#ifndef STD_HUE_CONDITION #ifndef STD_HUE_CONDITION
#define STD_HUE_CONDITION( setup ) 1 #define STD_HUE_CONDITION( setup ) 1
#endif #endif
#define ext_decoder_hue (std_decoder_hue + 15) #define ext_decoder_hue (std_decoder_hue + 15)
@ -50,236 +50,236 @@ enum { kernel_size = kernel_half * 2 + 1 };
typedef struct init_t typedef struct init_t
{ {
float to_rgb [burst_count * 6]; float to_rgb [burst_count * 6];
float to_float [gamma_size]; float to_float [gamma_size];
float contrast; float contrast;
float brightness; float brightness;
float artifacts; float artifacts;
float fringing; float fringing;
float kernel [rescale_out * kernel_size * 2]; float kernel [rescale_out * kernel_size * 2];
} init_t; } init_t;
#define ROTATE_IQ( i, q, sin_b, cos_b ) {\ #define ROTATE_IQ( i, q, sin_b, cos_b ) {\
float t;\ float t;\
t = i * cos_b - q * sin_b;\ t = i * cos_b - q * sin_b;\
q = i * sin_b + q * cos_b;\ q = i * sin_b + q * cos_b;\
i = t;\ i = t;\
} }
static void init_filters( init_t* impl, sms_ntsc_setup_t const* setup ) static void init_filters( init_t* impl, sms_ntsc_setup_t const* setup )
{ {
#if rescale_out > 1 #if rescale_out > 1
float kernels [kernel_size * 2]; float kernels [kernel_size * 2];
#else #else
float* const kernels = impl->kernel; float* const kernels = impl->kernel;
#endif #endif
/* generate luma (y) filter using sinc kernel */ /* generate luma (y) filter using sinc kernel */
{ {
/* sinc with rolloff (dsf) */ /* sinc with rolloff (dsf) */
float const rolloff = 1 + (float) setup->sharpness * (float) 0.032; float const rolloff = 1 + (float) setup->sharpness * (float) 0.032;
float const maxh = 32; float const maxh = 32;
float const pow_a_n = (float) pow( rolloff, maxh ); float const pow_a_n = (float) pow( rolloff, maxh );
float sum; float sum;
int i; int i;
/* quadratic mapping to reduce negative (blurring) range */ /* quadratic mapping to reduce negative (blurring) range */
float to_angle = (float) setup->resolution + 1; float to_angle = (float) setup->resolution + 1;
to_angle = PI / maxh * (float) LUMA_CUTOFF * (to_angle * to_angle + 1); to_angle = PI / maxh * (float) LUMA_CUTOFF * (to_angle * to_angle + 1);
kernels [kernel_size * 3 / 2] = maxh; /* default center value */ kernels [kernel_size * 3 / 2] = maxh; /* default center value */
for ( i = 0; i < kernel_half * 2 + 1; i++ ) for ( i = 0; i < kernel_half * 2 + 1; i++ )
{ {
int x = i - kernel_half; int x = i - kernel_half;
float angle = x * to_angle; float angle = x * to_angle;
/* instability occurs at center point with rolloff very close to 1.0 */ /* instability occurs at center point with rolloff very close to 1.0 */
if ( x || pow_a_n > (float) 1.056 || pow_a_n < (float) 0.981 ) if ( x || pow_a_n > (float) 1.056 || pow_a_n < (float) 0.981 )
{ {
float rolloff_cos_a = rolloff * (float) cos( angle ); float rolloff_cos_a = rolloff * (float) cos( angle );
float num = 1 - rolloff_cos_a - float num = 1 - rolloff_cos_a -
pow_a_n * (float) cos( maxh * angle ) + pow_a_n * (float) cos( maxh * angle ) +
pow_a_n * rolloff * (float) cos( (maxh - 1) * angle ); pow_a_n * rolloff * (float) cos( (maxh - 1) * angle );
float den = 1 - rolloff_cos_a - rolloff_cos_a + rolloff * rolloff; float den = 1 - rolloff_cos_a - rolloff_cos_a + rolloff * rolloff;
float dsf = num / den; float dsf = num / den;
kernels [kernel_size * 3 / 2 - kernel_half + i] = dsf - (float) 0.5; kernels [kernel_size * 3 / 2 - kernel_half + i] = dsf - (float) 0.5;
} }
} }
/* apply blackman window and find sum */ /* apply blackman window and find sum */
sum = 0; sum = 0;
for ( i = 0; i < kernel_half * 2 + 1; i++ ) for ( i = 0; i < kernel_half * 2 + 1; i++ )
{ {
float x = PI * 2 / (kernel_half * 2) * i; float x = PI * 2 / (kernel_half * 2) * i;
float blackman = 0.42f - 0.5f * (float) cos( x ) + 0.08f * (float) cos( x * 2 ); float blackman = 0.42f - 0.5f * (float) cos( x ) + 0.08f * (float) cos( x * 2 );
sum += (kernels [kernel_size * 3 / 2 - kernel_half + i] *= blackman); sum += (kernels [kernel_size * 3 / 2 - kernel_half + i] *= blackman);
} }
/* normalize kernel */ /* normalize kernel */
sum = 1.0f / sum; sum = 1.0f / sum;
for ( i = 0; i < kernel_half * 2 + 1; i++ ) for ( i = 0; i < kernel_half * 2 + 1; i++ )
{ {
int x = kernel_size * 3 / 2 - kernel_half + i; int x = kernel_size * 3 / 2 - kernel_half + i;
kernels [x] *= sum; kernels [x] *= sum;
assert( kernels [x] == kernels [x] ); /* catch numerical instability */ assert( kernels [x] == kernels [x] ); /* catch numerical instability */
} }
} }
/* generate chroma (iq) filter using gaussian kernel */ /* generate chroma (iq) filter using gaussian kernel */
{ {
float const cutoff_factor = -0.03125f; float const cutoff_factor = -0.03125f;
float cutoff = (float) setup->bleed; float cutoff = (float) setup->bleed;
int i; int i;
if ( cutoff < 0 ) if ( cutoff < 0 )
{ {
/* keep extreme value accessible only near upper end of scale (1.0) */ /* keep extreme value accessible only near upper end of scale (1.0) */
cutoff *= cutoff; cutoff *= cutoff;
cutoff *= cutoff; cutoff *= cutoff;
cutoff *= cutoff; cutoff *= cutoff;
cutoff *= -30.0f / 0.65f; cutoff *= -30.0f / 0.65f;
} }
cutoff = cutoff_factor - 0.65f * cutoff_factor * cutoff; cutoff = cutoff_factor - 0.65f * cutoff_factor * cutoff;
for ( i = -kernel_half; i <= kernel_half; i++ ) for ( i = -kernel_half; i <= kernel_half; i++ )
kernels [kernel_size / 2 + i] = (float) exp( i * i * cutoff ); kernels [kernel_size / 2 + i] = (float) exp( i * i * cutoff );
/* normalize even and odd phases separately */ /* normalize even and odd phases separately */
for ( i = 0; i < 2; i++ ) for ( i = 0; i < 2; i++ )
{ {
float sum = 0; float sum = 0;
int x; int x;
for ( x = i; x < kernel_size; x += 2 ) for ( x = i; x < kernel_size; x += 2 )
sum += kernels [x]; sum += kernels [x];
sum = 1.0f / sum; sum = 1.0f / sum;
for ( x = i; x < kernel_size; x += 2 ) for ( x = i; x < kernel_size; x += 2 )
{ {
kernels [x] *= sum; kernels [x] *= sum;
assert( kernels [x] == kernels [x] ); /* catch numerical instability */ assert( kernels [x] == kernels [x] ); /* catch numerical instability */
} }
} }
} }
/* /*
printf( "luma:\n" ); printf( "luma:\n" );
for ( i = kernel_size; i < kernel_size * 2; i++ ) for ( i = kernel_size; i < kernel_size * 2; i++ )
printf( "%f\n", kernels [i] ); printf( "%f\n", kernels [i] );
printf( "chroma:\n" ); printf( "chroma:\n" );
for ( i = 0; i < kernel_size; i++ ) for ( i = 0; i < kernel_size; i++ )
printf( "%f\n", kernels [i] ); printf( "%f\n", kernels [i] );
*/ */
/* generate linear rescale kernels */ /* generate linear rescale kernels */
#if rescale_out > 1 #if rescale_out > 1
{ {
float weight = 1.0f; float weight = 1.0f;
float* out = impl->kernel; float* out = impl->kernel;
int n = rescale_out; int n = rescale_out;
do do
{ {
float remain = 0; float remain = 0;
int i; int i;
weight -= 1.0f / rescale_in; weight -= 1.0f / rescale_in;
for ( i = 0; i < kernel_size * 2; i++ ) for ( i = 0; i < kernel_size * 2; i++ )
{ {
float cur = kernels [i]; float cur = kernels [i];
float m = cur * weight; float m = cur * weight;
*out++ = m + remain; *out++ = m + remain;
remain = cur - m; remain = cur - m;
} }
} }
while ( --n ); while ( --n );
} }
#endif #endif
} }
static float const default_decoder [6] = static float const default_decoder [6] =
{ 0.956f, 0.621f, -0.272f, -0.647f, -1.105f, 1.702f }; { 0.956f, 0.621f, -0.272f, -0.647f, -1.105f, 1.702f };
static void init( init_t* impl, sms_ntsc_setup_t const* setup ) static void init( init_t* impl, sms_ntsc_setup_t const* setup )
{ {
impl->brightness = (float) setup->brightness * (0.5f * rgb_unit) + rgb_offset; impl->brightness = (float) setup->brightness * (0.5f * rgb_unit) + rgb_offset;
impl->contrast = (float) setup->contrast * (0.5f * rgb_unit) + rgb_unit; impl->contrast = (float) setup->contrast * (0.5f * rgb_unit) + rgb_unit;
#ifdef default_palette_contrast #ifdef default_palette_contrast
if ( !setup->palette ) if ( !setup->palette )
impl->contrast *= default_palette_contrast; impl->contrast *= default_palette_contrast;
#endif #endif
impl->artifacts = (float) setup->artifacts; impl->artifacts = (float) setup->artifacts;
if ( impl->artifacts > 0 ) if ( impl->artifacts > 0 )
impl->artifacts *= artifacts_max - artifacts_mid; impl->artifacts *= artifacts_max - artifacts_mid;
impl->artifacts = impl->artifacts * artifacts_mid + artifacts_mid; impl->artifacts = impl->artifacts * artifacts_mid + artifacts_mid;
impl->fringing = (float) setup->fringing; impl->fringing = (float) setup->fringing;
if ( impl->fringing > 0 ) if ( impl->fringing > 0 )
impl->fringing *= fringing_max - fringing_mid; impl->fringing *= fringing_max - fringing_mid;
impl->fringing = impl->fringing * fringing_mid + fringing_mid; impl->fringing = impl->fringing * fringing_mid + fringing_mid;
init_filters( impl, setup ); init_filters( impl, setup );
/* generate gamma table */ /* generate gamma table */
if ( gamma_size > 1 ) if ( gamma_size > 1 )
{ {
float const to_float = 1.0f / (gamma_size - (gamma_size > 1)); float const to_float = 1.0f / (gamma_size - (gamma_size > 1));
float const gamma = 1.1333f - (float) setup->gamma * 0.5f; float const gamma = 1.1333f - (float) setup->gamma * 0.5f;
/* match common PC's 2.2 gamma to TV's 2.65 gamma */ /* match common PC's 2.2 gamma to TV's 2.65 gamma */
int i; int i;
for ( i = 0; i < gamma_size; i++ ) for ( i = 0; i < gamma_size; i++ )
impl->to_float [i] = impl->to_float [i] =
(float) pow( i * to_float, gamma ) * impl->contrast + impl->brightness; (float) pow( i * to_float, gamma ) * impl->contrast + impl->brightness;
} }
/* setup decoder matricies */ /* setup decoder matricies */
{ {
float hue = (float) setup->hue * PI + PI / 180 * ext_decoder_hue; float hue = (float) setup->hue * PI + PI / 180 * ext_decoder_hue;
float sat = (float) setup->saturation + 1; float sat = (float) setup->saturation + 1;
float const* decoder = setup->decoder_matrix; float const* decoder = setup->decoder_matrix;
if ( !decoder ) if ( !decoder )
{ {
decoder = default_decoder; decoder = default_decoder;
if ( STD_HUE_CONDITION( setup ) ) if ( STD_HUE_CONDITION( setup ) )
hue += PI / 180 * (std_decoder_hue - ext_decoder_hue); hue += PI / 180 * (std_decoder_hue - ext_decoder_hue);
} }
{ {
float s = (float) sin( hue ) * sat; float s = (float) sin( hue ) * sat;
float c = (float) cos( hue ) * sat; float c = (float) cos( hue ) * sat;
float* out = impl->to_rgb; float* out = impl->to_rgb;
int n; int n;
n = burst_count; n = burst_count;
do do
{ {
float const* in = decoder; float const* in = decoder;
int n = 3; int n = 3;
do do
{ {
float i = *in++; float i = *in++;
float q = *in++; float q = *in++;
*out++ = i * c - q * s; *out++ = i * c - q * s;
*out++ = i * s + q * c; *out++ = i * s + q * c;
} }
while ( --n ); while ( --n );
if ( burst_count <= 1 ) if ( burst_count <= 1 )
break; break;
ROTATE_IQ( s, c, 0.866025f, -0.5f ); /* +120 degrees */ ROTATE_IQ( s, c, 0.866025f, -0.5f ); /* +120 degrees */
} }
while ( --n ); while ( --n );
} }
} }
} }
/* kernel generation */ /* kernel generation */
#define RGB_TO_YIQ( r, g, b, y, i ) (\ #define RGB_TO_YIQ( r, g, b, y, i ) (\
(y = (r) * 0.299f + (g) * 0.587f + (b) * 0.114f),\ (y = (r) * 0.299f + (g) * 0.587f + (b) * 0.114f),\
(i = (r) * 0.596f - (g) * 0.275f - (b) * 0.321f),\ (i = (r) * 0.596f - (g) * 0.275f - (b) * 0.321f),\
((r) * 0.212f - (g) * 0.523f + (b) * 0.311f)\ ((r) * 0.212f - (g) * 0.523f + (b) * 0.311f)\
) )
#define YIQ_TO_RGB( y, i, q, to_rgb, type, r, g ) (\ #define YIQ_TO_RGB( y, i, q, to_rgb, type, r, g ) (\
r = (type) (y + to_rgb [0] * i + to_rgb [1] * q),\ r = (type) (y + to_rgb [0] * i + to_rgb [1] * q),\
g = (type) (y + to_rgb [2] * i + to_rgb [3] * q),\ g = (type) (y + to_rgb [2] * i + to_rgb [3] * q),\
(type) (y + to_rgb [4] * i + to_rgb [5] * q)\ (type) (y + to_rgb [4] * i + to_rgb [5] * q)\
) )
#define PACK_RGB( r, g, b ) ((r) << 21 | (g) << 11 | (b) << 1) #define PACK_RGB( r, g, b ) ((r) << 21 | (g) << 11 | (b) << 1)
@ -289,24 +289,24 @@ enum { rgb_bias = rgb_unit * 2 * sms_ntsc_rgb_builder };
typedef struct pixel_info_t typedef struct pixel_info_t
{ {
int offset; int offset;
float negate; float negate;
float kernel [4]; float kernel [4];
} pixel_info_t; } pixel_info_t;
#if rescale_in > 1 #if rescale_in > 1
#define PIXEL_OFFSET_( ntsc, scaled ) \ #define PIXEL_OFFSET_( ntsc, scaled ) \
(kernel_size / 2 + ntsc + (scaled != 0) + (rescale_out - scaled) % rescale_out + \ (kernel_size / 2 + ntsc + (scaled != 0) + (rescale_out - scaled) % rescale_out + \
(kernel_size * 2 * scaled)) (kernel_size * 2 * scaled))
#define PIXEL_OFFSET( ntsc, scaled ) \ #define PIXEL_OFFSET( ntsc, scaled ) \
PIXEL_OFFSET_( ((ntsc) - (scaled) / rescale_out * rescale_in),\ PIXEL_OFFSET_( ((ntsc) - (scaled) / rescale_out * rescale_in),\
(((scaled) + rescale_out * 10) % rescale_out) ),\ (((scaled) + rescale_out * 10) % rescale_out) ),\
(1.0f - (((ntsc) + 100) & 2)) (1.0f - (((ntsc) + 100) & 2))
#else #else
#define PIXEL_OFFSET( ntsc, scaled ) \ #define PIXEL_OFFSET( ntsc, scaled ) \
(kernel_size / 2 + (ntsc) - (scaled)),\ (kernel_size / 2 + (ntsc) - (scaled)),\
(1.0f - (((ntsc) + 100) & 2)) (1.0f - (((ntsc) + 100) & 2))
#endif #endif
extern pixel_info_t const sms_ntsc_pixels [alignment_count]; extern pixel_info_t const sms_ntsc_pixels [alignment_count];
@ -314,126 +314,126 @@ extern pixel_info_t const sms_ntsc_pixels [alignment_count];
/* Generate pixel at all burst phases and column alignments */ /* Generate pixel at all burst phases and column alignments */
static void gen_kernel( init_t* impl, float y, float i, float q, sms_ntsc_rgb_t* out ) static void gen_kernel( init_t* impl, float y, float i, float q, sms_ntsc_rgb_t* out )
{ {
/* generate for each scanline burst phase */ /* generate for each scanline burst phase */
float const* to_rgb = impl->to_rgb; float const* to_rgb = impl->to_rgb;
int burst_remain = burst_count; int burst_remain = burst_count;
y -= rgb_offset; y -= rgb_offset;
do do
{ {
/* Encode yiq into *two* composite signals (to allow control over artifacting). /* Encode yiq into *two* composite signals (to allow control over artifacting).
Convolve these with kernels which: filter respective components, apply Convolve these with kernels which: filter respective components, apply
sharpening, and rescale horizontally. Convert resulting yiq to rgb and pack sharpening, and rescale horizontally. Convert resulting yiq to rgb and pack
into integer. Based on algorithm by NewRisingSun. */ into integer. Based on algorithm by NewRisingSun. */
pixel_info_t const* pixel = sms_ntsc_pixels; pixel_info_t const* pixel = sms_ntsc_pixels;
int alignment_remain = alignment_count; int alignment_remain = alignment_count;
do do
{ {
/* negate is -1 when composite starts at odd multiple of 2 */ /* negate is -1 when composite starts at odd multiple of 2 */
float const yy = y * impl->fringing * pixel->negate; float const yy = y * impl->fringing * pixel->negate;
float const ic0 = (i + yy) * pixel->kernel [0]; float const ic0 = (i + yy) * pixel->kernel [0];
float const qc1 = (q + yy) * pixel->kernel [1]; float const qc1 = (q + yy) * pixel->kernel [1];
float const ic2 = (i - yy) * pixel->kernel [2]; float const ic2 = (i - yy) * pixel->kernel [2];
float const qc3 = (q - yy) * pixel->kernel [3]; float const qc3 = (q - yy) * pixel->kernel [3];
float const factor = impl->artifacts * pixel->negate; float const factor = impl->artifacts * pixel->negate;
float const ii = i * factor; float const ii = i * factor;
float const yc0 = (y + ii) * pixel->kernel [0]; float const yc0 = (y + ii) * pixel->kernel [0];
float const yc2 = (y - ii) * pixel->kernel [2]; float const yc2 = (y - ii) * pixel->kernel [2];
float const qq = q * factor; float const qq = q * factor;
float const yc1 = (y + qq) * pixel->kernel [1]; float const yc1 = (y + qq) * pixel->kernel [1];
float const yc3 = (y - qq) * pixel->kernel [3]; float const yc3 = (y - qq) * pixel->kernel [3];
float const* k = &impl->kernel [pixel->offset]; float const* k = &impl->kernel [pixel->offset];
int n; int n;
++pixel; ++pixel;
for ( n = rgb_kernel_size; n; --n ) for ( n = rgb_kernel_size; n; --n )
{ {
float i = k[0]*ic0 + k[2]*ic2; float i = k[0]*ic0 + k[2]*ic2;
float q = k[1]*qc1 + k[3]*qc3; float q = k[1]*qc1 + k[3]*qc3;
float y = k[kernel_size+0]*yc0 + k[kernel_size+1]*yc1 + float y = k[kernel_size+0]*yc0 + k[kernel_size+1]*yc1 +
k[kernel_size+2]*yc2 + k[kernel_size+3]*yc3 + rgb_offset; k[kernel_size+2]*yc2 + k[kernel_size+3]*yc3 + rgb_offset;
if ( rescale_out <= 1 ) if ( rescale_out <= 1 )
k--; k--;
else if ( k < &impl->kernel [kernel_size * 2 * (rescale_out - 1)] ) else if ( k < &impl->kernel [kernel_size * 2 * (rescale_out - 1)] )
k += kernel_size * 2 - 1; k += kernel_size * 2 - 1;
else else
k -= kernel_size * 2 * (rescale_out - 1) + 2; k -= kernel_size * 2 * (rescale_out - 1) + 2;
{ {
int r, g, b = YIQ_TO_RGB( y, i, q, to_rgb, int, r, g ); int r, g, b = YIQ_TO_RGB( y, i, q, to_rgb, int, r, g );
*out++ = PACK_RGB( r, g, b ) - rgb_bias; *out++ = PACK_RGB( r, g, b ) - rgb_bias;
} }
} }
} }
while ( alignment_count > 1 && --alignment_remain ); while ( alignment_count > 1 && --alignment_remain );
if ( burst_count <= 1 ) if ( burst_count <= 1 )
break; break;
to_rgb += 6; to_rgb += 6;
ROTATE_IQ( i, q, -0.866025f, -0.5f ); /* -120 degrees */ ROTATE_IQ( i, q, -0.866025f, -0.5f ); /* -120 degrees */
} }
while ( --burst_remain ); while ( --burst_remain );
} }
static void correct_errors( sms_ntsc_rgb_t color, sms_ntsc_rgb_t* out ); static void correct_errors( sms_ntsc_rgb_t color, sms_ntsc_rgb_t* out );
#if DISABLE_CORRECTION #if DISABLE_CORRECTION
#define CORRECT_ERROR( a ) { out [i] += rgb_bias; } #define CORRECT_ERROR( a ) { out [i] += rgb_bias; }
#define DISTRIBUTE_ERROR( a, b, c ) { out [i] += rgb_bias; } #define DISTRIBUTE_ERROR( a, b, c ) { out [i] += rgb_bias; }
#else #else
#define CORRECT_ERROR( a ) { out [a] += error; } #define CORRECT_ERROR( a ) { out [a] += error; }
#define DISTRIBUTE_ERROR( a, b, c ) {\ #define DISTRIBUTE_ERROR( a, b, c ) {\
sms_ntsc_rgb_t fourth = (error + 2 * sms_ntsc_rgb_builder) >> 2;\ sms_ntsc_rgb_t fourth = (error + 2 * sms_ntsc_rgb_builder) >> 2;\
fourth &= (rgb_bias >> 1) - sms_ntsc_rgb_builder;\ fourth &= (rgb_bias >> 1) - sms_ntsc_rgb_builder;\
fourth -= rgb_bias >> 2;\ fourth -= rgb_bias >> 2;\
out [a] += fourth;\ out [a] += fourth;\
out [b] += fourth;\ out [b] += fourth;\
out [c] += fourth;\ out [c] += fourth;\
out [i] += error - (fourth * 3);\ out [i] += error - (fourth * 3);\
} }
#endif #endif
#define RGB_PALETTE_OUT( rgb, out_ )\ #define RGB_PALETTE_OUT( rgb, out_ )\
{\ {\
unsigned char* out = (out_);\ unsigned char* out = (out_);\
sms_ntsc_rgb_t clamped = (rgb);\ sms_ntsc_rgb_t clamped = (rgb);\
SMS_NTSC_CLAMP_( clamped, (8 - rgb_bits) );\ SMS_NTSC_CLAMP_( clamped, (8 - rgb_bits) );\
out [0] = (unsigned char) (clamped >> 21);\ out [0] = (unsigned char) (clamped >> 21);\
out [1] = (unsigned char) (clamped >> 11);\ out [1] = (unsigned char) (clamped >> 11);\
out [2] = (unsigned char) (clamped >> 1);\ out [2] = (unsigned char) (clamped >> 1);\
} }
/* blitter related */ /* blitter related */
#ifndef restrict #ifndef restrict
#if defined (__GNUC__) #if defined (__GNUC__)
#define restrict __restrict__ #define restrict __restrict__
#elif defined (_MSC_VER) && _MSC_VER > 1300 #elif defined (_MSC_VER) && _MSC_VER > 1300
#define restrict __restrict #define restrict __restrict
#else #else
/* no support for restricted pointers */ /* no support for restricted pointers */
#define restrict #define restrict
#endif #endif
#endif #endif
#include <limits.h> #include <limits.h>
#if SMS_NTSC_OUT_DEPTH <= 16 #if SMS_NTSC_OUT_DEPTH <= 16
#if USHRT_MAX == 0xFFFF #if USHRT_MAX == 0xFFFF
typedef unsigned short sms_ntsc_out_t; typedef unsigned short sms_ntsc_out_t;
#else #else
#error "Need 16-bit int type" #error "Need 16-bit int type"
#endif #endif
#else #else
#if UINT_MAX == 0xFFFFFFFF #if UINT_MAX == 0xFFFFFFFF
typedef unsigned int sms_ntsc_out_t; typedef unsigned int sms_ntsc_out_t;
#elif ULONG_MAX == 0xFFFFFFFF #elif ULONG_MAX == 0xFFFFFFFF
typedef unsigned long sms_ntsc_out_t; typedef unsigned long sms_ntsc_out_t;
#else #else
#error "Need 32-bit int type" #error "Need 32-bit int type"
#endif #endif
#endif #endif

View File

@ -1,12 +1,12 @@
GNU GENERAL PUBLIC LICENSE GNU GENERAL PUBLIC LICENSE
Version 2, June 1991 Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc. Copyright (C) 1989, 1991 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed. of this license document, but changing it is not allowed.
Preamble Preamble
The licenses for most software are designed to take away your The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public freedom to share and change it. By contrast, the GNU General Public
@ -56,7 +56,7 @@ patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and The precise terms and conditions for copying, distribution and
modification follow. modification follow.
GNU GENERAL PUBLIC LICENSE GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains 0. This License applies to any program or other work which contains
@ -255,7 +255,7 @@ make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally. of promoting the sharing and reuse of software generally.
NO WARRANTY NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
@ -277,9 +277,9 @@ YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES. POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it possible use to the public, the best way to achieve this is to make it

View File

@ -22,8 +22,8 @@ Win32
There are detailed instructions for building libsamplerate on Win32 There are detailed instructions for building libsamplerate on Win32
in the file in the file
doc/win32.html doc/win32.html
MacOSX MacOSX
------ ------
@ -36,15 +36,15 @@ OTHER PLATFORMS
To compile libsamplerate on platforms which have a Bourne Shell compatible To compile libsamplerate on platforms which have a Bourne Shell compatible
shell, an ANSI C compiler and a make utility should require no more that shell, an ANSI C compiler and a make utility should require no more that
the following three commands : the following three commands :
./configure ./configure
make make
make install make install
CONTACTS CONTACTS
-------- --------
libsamplerate was written by Erik de Castro Lopo (erikd AT mega-nerd DOT com). libsamplerate was written by Erik de Castro Lopo (erikd AT mega-nerd DOT com).
The libsamplerate home page is at : The libsamplerate home page is at :
http://www.mega-nerd.com/libsamplerate/ http://www.mega-nerd.com/libsamplerate/

View File

@ -19,7 +19,7 @@
/* /*
** This code is part of Secret Rabibt Code aka libsamplerate. A commercial ** This code is part of Secret Rabibt Code aka libsamplerate. A commercial
** use license for this code is available, please see: ** use license for this code is available, please see:
** http://www.mega-nerd.com/SRC/procedure.html ** http://www.mega-nerd.com/SRC/procedure.html
*/ */
#ifndef COMMON_H_INCLUDED #ifndef COMMON_H_INCLUDED
@ -28,87 +28,87 @@
#ifdef HAVE_STDINT_H #ifdef HAVE_STDINT_H
#include <stdint.h> #include <stdint.h>
#elif (SIZEOF_INT == 4) #elif (SIZEOF_INT == 4)
typedef int int32_t ; typedef int int32_t ;
#elif (SIZEOF_LONG == 4) #elif (SIZEOF_LONG == 4)
typedef long int32_t ; typedef long int32_t ;
#endif #endif
#define SRC_MAX_RATIO 256 #define SRC_MAX_RATIO 256
#define SRC_MIN_RATIO_DIFF (1e-20) #define SRC_MIN_RATIO_DIFF (1e-20)
#define MAX(a,b) (((a) > (b)) ? (a) : (b)) #define MAX(a,b) (((a) > (b)) ? (a) : (b))
#define MIN(a,b) (((a) < (b)) ? (a) : (b)) #define MIN(a,b) (((a) < (b)) ? (a) : (b))
#define ARRAY_LEN(x) ((int) (sizeof (x) / sizeof ((x) [0]))) #define ARRAY_LEN(x) ((int) (sizeof (x) / sizeof ((x) [0])))
#define OFFSETOF(type,member) ((int) (&((type*) 0)->member)) #define OFFSETOF(type,member) ((int) (&((type*) 0)->member))
#define MAKE_MAGIC(a,b,c,d,e,f) ((a) + ((b) << 4) + ((c) << 8) + ((d) << 12) + ((e) << 16) + ((f) << 20)) #define MAKE_MAGIC(a,b,c,d,e,f) ((a) + ((b) << 4) + ((c) << 8) + ((d) << 12) + ((e) << 16) + ((f) << 20))
#include "samplerate.h" #include "samplerate.h"
enum enum
{ SRC_FALSE = 0, { SRC_FALSE = 0,
SRC_TRUE = 1, SRC_TRUE = 1,
SRC_MODE_PROCESS = 555, SRC_MODE_PROCESS = 555,
SRC_MODE_CALLBACK = 556 SRC_MODE_CALLBACK = 556
} ; } ;
enum enum
{ SRC_ERR_NO_ERROR = 0, { SRC_ERR_NO_ERROR = 0,
SRC_ERR_MALLOC_FAILED, SRC_ERR_MALLOC_FAILED,
SRC_ERR_BAD_STATE, SRC_ERR_BAD_STATE,
SRC_ERR_BAD_DATA, SRC_ERR_BAD_DATA,
SRC_ERR_BAD_DATA_PTR, SRC_ERR_BAD_DATA_PTR,
SRC_ERR_NO_PRIVATE, SRC_ERR_NO_PRIVATE,
SRC_ERR_BAD_SRC_RATIO, SRC_ERR_BAD_SRC_RATIO,
SRC_ERR_BAD_PROC_PTR, SRC_ERR_BAD_PROC_PTR,
SRC_ERR_SHIFT_BITS, SRC_ERR_SHIFT_BITS,
SRC_ERR_FILTER_LEN, SRC_ERR_FILTER_LEN,
SRC_ERR_BAD_CONVERTER, SRC_ERR_BAD_CONVERTER,
SRC_ERR_BAD_CHANNEL_COUNT, SRC_ERR_BAD_CHANNEL_COUNT,
SRC_ERR_SINC_BAD_BUFFER_LEN, SRC_ERR_SINC_BAD_BUFFER_LEN,
SRC_ERR_SIZE_INCOMPATIBILITY, SRC_ERR_SIZE_INCOMPATIBILITY,
SRC_ERR_BAD_PRIV_PTR, SRC_ERR_BAD_PRIV_PTR,
SRC_ERR_BAD_SINC_STATE, SRC_ERR_BAD_SINC_STATE,
SRC_ERR_DATA_OVERLAP, SRC_ERR_DATA_OVERLAP,
SRC_ERR_BAD_CALLBACK, SRC_ERR_BAD_CALLBACK,
SRC_ERR_BAD_MODE, SRC_ERR_BAD_MODE,
SRC_ERR_NULL_CALLBACK, SRC_ERR_NULL_CALLBACK,
SRC_ERR_NO_VARIABLE_RATIO, SRC_ERR_NO_VARIABLE_RATIO,
/* This must be the last error number. */ /* This must be the last error number. */
SRC_ERR_MAX_ERROR SRC_ERR_MAX_ERROR
} ; } ;
typedef struct SRC_PRIVATE_tag typedef struct SRC_PRIVATE_tag
{ double last_ratio, last_position ; { double last_ratio, last_position ;
int error ; int error ;
int channels ; int channels ;
/* SRC_MODE_PROCESS or SRC_MODE_CALLBACK */ /* SRC_MODE_PROCESS or SRC_MODE_CALLBACK */
int mode ; int mode ;
/* Pointer to data to converter specific data. */ /* Pointer to data to converter specific data. */
void *private_data ; void *private_data ;
/* Varispeed process function. */ /* Varispeed process function. */
int (*vari_process) (struct SRC_PRIVATE_tag *psrc, SRC_DATA *data) ; int (*vari_process) (struct SRC_PRIVATE_tag *psrc, SRC_DATA *data) ;
/* Constant speed process function. */ /* Constant speed process function. */
int (*const_process) (struct SRC_PRIVATE_tag *psrc, SRC_DATA *data) ; int (*const_process) (struct SRC_PRIVATE_tag *psrc, SRC_DATA *data) ;
/* State reset. */ /* State reset. */
void (*reset) (struct SRC_PRIVATE_tag *psrc) ; void (*reset) (struct SRC_PRIVATE_tag *psrc) ;
/* Data specific to SRC_MODE_CALLBACK. */ /* Data specific to SRC_MODE_CALLBACK. */
src_callback_t callback_func ; src_callback_t callback_func ;
void *user_callback_data ; void *user_callback_data ;
long saved_frames ; long saved_frames ;
float *saved_data ; float *saved_data ;
} SRC_PRIVATE ; } SRC_PRIVATE ;
/* In src_sinc.c */ /* In src_sinc.c */
@ -130,19 +130,19 @@ const char* zoh_get_description (int src_enum) ;
int zoh_set_converter (SRC_PRIVATE *psrc, int src_enum) ; int zoh_set_converter (SRC_PRIVATE *psrc, int src_enum) ;
/*---------------------------------------------------------- /*----------------------------------------------------------
** Common static inline functions. ** Common static inline functions.
*/ */
static inline double static inline double
fmod_one (double x) fmod_one (double x)
{ double res ; { double res ;
res = x - lrint (x) ; res = x - lrint (x) ;
if (res < 0.0) if (res < 0.0)
return res + 1.0 ; return res + 1.0 ;
return res ; return res ;
} /* fmod_one */ } /* fmod_one */
#endif /* COMMON_H_INCLUDED */ #endif /* COMMON_H_INCLUDED */

View File

@ -19,7 +19,7 @@
/* /*
** This code is part of Secret Rabibt Code aka libsamplerate. A commercial ** This code is part of Secret Rabibt Code aka libsamplerate. A commercial
** use license for this code is available, please see: ** use license for this code is available, please see:
** http://www.mega-nerd.com/SRC/procedure.html ** http://www.mega-nerd.com/SRC/procedure.html
*/ */
/* /*
@ -32,10 +32,10 @@
*/ */
static const struct fastest_coeffs_s static const struct fastest_coeffs_s
{ int increment ; { int increment ;
coeff_t coeffs [2464] ; coeff_t coeffs [2464] ;
} fastest_coeffs = } fastest_coeffs =
{ 128, { 128,
{ {
8.31472372954840555082e-01, 8.31472372954840555082e-01,
8.31414005540308198583e-01, 8.31414005540308198583e-01,
@ -2500,6 +2500,6 @@ static const struct fastest_coeffs_s
-3.59691078491283933177e-07, -3.59691078491283933177e-07,
-2.38952398011216803052e-07, -2.38952398011216803052e-07,
-1.22889677382464548894e-07, -1.22889677382464548894e-07,
0.0 /* Need a final zero coefficient */ 0.0 /* Need a final zero coefficient */
} }
} ; /* fastest_coeffs */ } ; /* fastest_coeffs */

View File

@ -22,231 +22,231 @@
#define FLOAT_CAST_HEADER #define FLOAT_CAST_HEADER
/*============================================================================ /*============================================================================
** On Intel Pentium processors (especially PIII and probably P4), converting ** On Intel Pentium processors (especially PIII and probably P4), converting
** from float to int is very slow. To meet the C specs, the code produced by ** from float to int is very slow. To meet the C specs, the code produced by
** most C compilers targeting Pentium needs to change the FPU rounding mode ** most C compilers targeting Pentium needs to change the FPU rounding mode
** before the float to int conversion is performed. ** before the float to int conversion is performed.
** **
** Changing the FPU rounding mode causes the FPU pipeline to be flushed. It ** Changing the FPU rounding mode causes the FPU pipeline to be flushed. It
** is this flushing of the pipeline which is so slow. ** is this flushing of the pipeline which is so slow.
** **
** Fortunately the ISO C99 specifications define the functions lrint, lrintf, ** Fortunately the ISO C99 specifications define the functions lrint, lrintf,
** llrint and llrintf which fix this problem as a side effect. ** llrint and llrintf which fix this problem as a side effect.
** **
** On Unix-like systems, the configure process should have detected the ** On Unix-like systems, the configure process should have detected the
** presence of these functions. If they weren't found we have to replace them ** presence of these functions. If they weren't found we have to replace them
** here with a standard C cast. ** here with a standard C cast.
*/ */
/* /*
** The C99 prototypes for lrint and lrintf are as follows: ** The C99 prototypes for lrint and lrintf are as follows:
** **
** long int lrintf (float x) ; ** long int lrintf (float x) ;
** long int lrint (double x) ; ** long int lrint (double x) ;
*/ */
#include "config.h" #include "config.h"
/* /*
** The presence of the required functions are detected during the configure ** The presence of the required functions are detected during the configure
** process and the values HAVE_LRINT and HAVE_LRINTF are set accordingly in ** process and the values HAVE_LRINT and HAVE_LRINTF are set accordingly in
** the config.h file. ** the config.h file.
*/ */
#define HAVE_LRINT_REPLACEMENT 0 #define HAVE_LRINT_REPLACEMENT 0
#if (HAVE_LRINT && HAVE_LRINTF) #if (HAVE_LRINT && HAVE_LRINTF)
/* /*
** These defines enable functionality introduced with the 1999 ISO C ** These defines enable functionality introduced with the 1999 ISO C
** standard. They must be defined before the inclusion of math.h to ** standard. They must be defined before the inclusion of math.h to
** engage them. If optimisation is enabled, these functions will be ** engage them. If optimisation is enabled, these functions will be
** inlined. With optimisation switched off, you have to link in the ** inlined. With optimisation switched off, you have to link in the
** maths library using -lm. ** maths library using -lm.
*/ */
#define _ISOC9X_SOURCE 1 #define _ISOC9X_SOURCE 1
#define _ISOC99_SOURCE 1 #define _ISOC99_SOURCE 1
#define __USE_ISOC9X 1 #define __USE_ISOC9X 1
#define __USE_ISOC99 1 #define __USE_ISOC99 1
#include <math.h> #include <math.h>
#elif (defined (__CYGWIN__)) #elif (defined (__CYGWIN__))
#include <math.h> #include <math.h>
#undef HAVE_LRINT_REPLACEMENT #undef HAVE_LRINT_REPLACEMENT
#define HAVE_LRINT_REPLACEMENT 1 #define HAVE_LRINT_REPLACEMENT 1
#undef lrint #undef lrint
#undef lrintf #undef lrintf
#define lrint double2int #define lrint double2int
#define lrintf float2int #define lrintf float2int
/* /*
** The native CYGWIN lrint and lrintf functions are buggy: ** The native CYGWIN lrint and lrintf functions are buggy:
** http://sourceware.org/ml/cygwin/2005-06/msg00153.html ** http://sourceware.org/ml/cygwin/2005-06/msg00153.html
** http://sourceware.org/ml/cygwin/2005-09/msg00047.html ** http://sourceware.org/ml/cygwin/2005-09/msg00047.html
** and slow. ** and slow.
** These functions (pulled from the Public Domain MinGW math.h header) ** These functions (pulled from the Public Domain MinGW math.h header)
** replace the native versions. ** replace the native versions.
*/ */
static inline long double2int (double in) static inline long double2int (double in)
{ long retval ; { long retval ;
__asm__ __volatile__ __asm__ __volatile__
( "fistpl %0" ( "fistpl %0"
: "=m" (retval) : "=m" (retval)
: "t" (in) : "t" (in)
: "st" : "st"
) ; ) ;
return retval ; return retval ;
} /* double2int */ } /* double2int */
static inline long float2int (float in) static inline long float2int (float in)
{ long retval ; { long retval ;
__asm__ __volatile__ __asm__ __volatile__
( "fistpl %0" ( "fistpl %0"
: "=m" (retval) : "=m" (retval)
: "t" (in) : "t" (in)
: "st" : "st"
) ; ) ;
return retval ; return retval ;
} /* float2int */ } /* float2int */
#elif (defined (WIN32) || defined (_WIN32)) #elif (defined (WIN32) || defined (_WIN32))
#undef HAVE_LRINT_REPLACEMENT #undef HAVE_LRINT_REPLACEMENT
#define HAVE_LRINT_REPLACEMENT 1 #define HAVE_LRINT_REPLACEMENT 1
#include <math.h> #include <math.h>
/* /*
** Win32 doesn't seem to have these functions. ** Win32 doesn't seem to have these functions.
** Therefore implement inline versions of these functions here. ** Therefore implement inline versions of these functions here.
*/ */
__inline long int __inline long int
lrint (double flt) lrint (double flt)
{ int intgr ; { int intgr ;
_asm _asm
{ fld flt { fld flt
fistp intgr fistp intgr
} ; } ;
return intgr ; return intgr ;
} }
__inline long int __inline long int
lrintf (float flt) lrintf (float flt)
{ int intgr ; { int intgr ;
_asm _asm
{ fld flt { fld flt
fistp intgr fistp intgr
} ; } ;
return intgr ; return intgr ;
} }
#elif (defined (__MWERKS__) && defined (macintosh)) #elif (defined (__MWERKS__) && defined (macintosh))
/* This MacOS 9 solution was provided by Stephane Letz */ /* This MacOS 9 solution was provided by Stephane Letz */
#undef HAVE_LRINT_REPLACEMENT #undef HAVE_LRINT_REPLACEMENT
#define HAVE_LRINT_REPLACEMENT 1 #define HAVE_LRINT_REPLACEMENT 1
#include <math.h> #include <math.h>
#undef lrint #undef lrint
#undef lrintf #undef lrintf
#define lrint double2int #define lrint double2int
#define lrintf float2int #define lrintf float2int
inline int inline int
float2int (register float in) float2int (register float in)
{ long res [2] ; { long res [2] ;
asm asm
{ fctiw in, in { fctiw in, in
stfd in, res stfd in, res
} }
return res [1] ; return res [1] ;
} /* float2int */ } /* float2int */
inline int inline int
double2int (register double in) double2int (register double in)
{ long res [2] ; { long res [2] ;
asm asm
{ fctiw in, in { fctiw in, in
stfd in, res stfd in, res
} }
return res [1] ; return res [1] ;
} /* double2int */ } /* double2int */
#elif (defined (__MACH__) && defined (__APPLE__)) #elif (defined (__MACH__) && defined (__APPLE__))
/* For Apple MacOSX. */ /* For Apple MacOSX. */
#undef HAVE_LRINT_REPLACEMENT #undef HAVE_LRINT_REPLACEMENT
#define HAVE_LRINT_REPLACEMENT 1 #define HAVE_LRINT_REPLACEMENT 1
#include <math.h> #include <math.h>
#undef lrint #undef lrint
#undef lrintf #undef lrintf
#define lrint double2int #define lrint double2int
#define lrintf float2int #define lrintf float2int
inline static long inline static long
float2int (register float in) float2int (register float in)
{ int res [2] ; { int res [2] ;
__asm__ __volatile__ __asm__ __volatile__
( "fctiw %1, %1\n\t" ( "fctiw %1, %1\n\t"
"stfd %1, %0" "stfd %1, %0"
: "=m" (res) /* Output */ : "=m" (res) /* Output */
: "f" (in) /* Input */ : "f" (in) /* Input */
: "memory" : "memory"
) ; ) ;
return res [1] ; return res [1] ;
} /* lrintf */ } /* lrintf */
inline static long inline static long
double2int (register double in) double2int (register double in)
{ int res [2] ; { int res [2] ;
__asm__ __volatile__ __asm__ __volatile__
( "fctiw %1, %1\n\t" ( "fctiw %1, %1\n\t"
"stfd %1, %0" "stfd %1, %0"
: "=m" (res) /* Output */ : "=m" (res) /* Output */
: "f" (in) /* Input */ : "f" (in) /* Input */
: "memory" : "memory"
) ; ) ;
return res [1] ; return res [1] ;
} /* lrint */ } /* lrint */
#else #else
#ifndef __sgi #ifndef __sgi
#warning "Don't have the functions lrint() and lrintf()." #warning "Don't have the functions lrint() and lrintf()."
#warning "Replacing these functions with a standard C cast." #warning "Replacing these functions with a standard C cast."
#endif #endif
#include <math.h> #include <math.h>
#define lrint(dbl) ((long) (dbl)) #define lrint(dbl) ((long) (dbl))
#define lrintf(flt) ((long) (flt)) #define lrintf(flt) ((long) (flt))
#endif #endif

View File

@ -19,7 +19,7 @@
/* /*
** This code is part of Secret Rabibt Code aka libsamplerate. A commercial ** This code is part of Secret Rabibt Code aka libsamplerate. A commercial
** use license for this code is available, please see: ** use license for this code is available, please see:
** http://www.mega-nerd.com/SRC/procedure.html ** http://www.mega-nerd.com/SRC/procedure.html
*/ */
/* /*
@ -31,10 +31,10 @@
** increment : 2381 ** increment : 2381
*/ */
static const struct slow_high_qual_coeffs_s static const struct slow_high_qual_coeffs_s
{ int increment ; { int increment ;
coeff_t coeffs [340239] ; coeff_t coeffs [340239] ;
} slow_high_qual_coeffs = } slow_high_qual_coeffs =
{ 2381, { 2381,
{ {
9.657284235393746030e-01, 9.657284235393746030e-01,
9.657281621412726613e-01, 9.657281621412726613e-01,

View File

@ -19,7 +19,7 @@
/* /*
** This code is part of Secret Rabibt Code aka libsamplerate. A commercial ** This code is part of Secret Rabibt Code aka libsamplerate. A commercial
** use license for this code is available, please see: ** use license for this code is available, please see:
** http://www.mega-nerd.com/SRC/procedure.html ** http://www.mega-nerd.com/SRC/procedure.html
*/ */
/* /*
@ -32,10 +32,10 @@
*/ */
static const struct slow_mid_qual_coeffs_s static const struct slow_mid_qual_coeffs_s
{ int increment ; { int increment ;
coeff_t coeffs [22438] ; coeff_t coeffs [22438] ;
} slow_mid_qual_coeffs = } slow_mid_qual_coeffs =
{ 491, { 491,
{ {
9.190632349861385109e-01, 9.190632349861385109e-01,
9.190579273831620544e-01, 9.190579273831620544e-01,

View File

@ -19,255 +19,255 @@
/* /*
** This code is part of Secret Rabibt Code aka libsamplerate. A commercial ** This code is part of Secret Rabibt Code aka libsamplerate. A commercial
** use license for this code is available, please see: ** use license for this code is available, please see:
** http://www.mega-nerd.com/SRC/procedure.html ** http://www.mega-nerd.com/SRC/procedure.html
*/ */
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "config.h" #include "config.h"
#include "samplerate.h" #include "samplerate.h"
#include "float_cast.h" #include "float_cast.h"
#include "common.h" #include "common.h"
static int psrc_set_converter (SRC_PRIVATE *psrc, int converter_type) ; static int psrc_set_converter (SRC_PRIVATE *psrc, int converter_type) ;
static inline int static inline int
is_bad_src_ratio (double ratio) is_bad_src_ratio (double ratio)
{ return (ratio < (1.0 / SRC_MAX_RATIO) || ratio > (1.0 * SRC_MAX_RATIO)) ; { return (ratio < (1.0 / SRC_MAX_RATIO) || ratio > (1.0 * SRC_MAX_RATIO)) ;
} /* is_bad_src_ratio */ } /* is_bad_src_ratio */
SRC_STATE * SRC_STATE *
src_new (int converter_type, int channels, int *error) src_new (int converter_type, int channels, int *error)
{ SRC_PRIVATE *psrc ; { SRC_PRIVATE *psrc ;
if (error) if (error)
*error = SRC_ERR_NO_ERROR ; *error = SRC_ERR_NO_ERROR ;
if (channels < 1) if (channels < 1)
{ if (error) { if (error)
*error = SRC_ERR_BAD_CHANNEL_COUNT ; *error = SRC_ERR_BAD_CHANNEL_COUNT ;
return NULL ; return NULL ;
} ; } ;
if ((psrc = calloc (1, sizeof (*psrc))) == NULL) if ((psrc = calloc (1, sizeof (*psrc))) == NULL)
{ if (error) { if (error)
*error = SRC_ERR_MALLOC_FAILED ; *error = SRC_ERR_MALLOC_FAILED ;
return NULL ; return NULL ;
} ; } ;
psrc->channels = channels ; psrc->channels = channels ;
psrc->mode = SRC_MODE_PROCESS ; psrc->mode = SRC_MODE_PROCESS ;
if (psrc_set_converter (psrc, converter_type) != SRC_ERR_NO_ERROR) if (psrc_set_converter (psrc, converter_type) != SRC_ERR_NO_ERROR)
{ if (error) { if (error)
*error = SRC_ERR_BAD_CONVERTER ; *error = SRC_ERR_BAD_CONVERTER ;
free (psrc) ; free (psrc) ;
psrc = NULL ; psrc = NULL ;
} ; } ;
src_reset ((SRC_STATE*) psrc) ; src_reset ((SRC_STATE*) psrc) ;
return (SRC_STATE*) psrc ; return (SRC_STATE*) psrc ;
} /* src_new */ } /* src_new */
SRC_STATE* SRC_STATE*
src_callback_new (src_callback_t func, int converter_type, int channels, int *error, void* cb_data) src_callback_new (src_callback_t func, int converter_type, int channels, int *error, void* cb_data)
{ SRC_STATE *src_state ; { SRC_STATE *src_state ;
if (func == NULL) if (func == NULL)
{ if (error) { if (error)
*error = SRC_ERR_BAD_CALLBACK ; *error = SRC_ERR_BAD_CALLBACK ;
return NULL ; return NULL ;
} ; } ;
if (error != NULL) if (error != NULL)
*error = 0 ; *error = 0 ;
src_state = src_new (converter_type, channels, error) ; src_state = src_new (converter_type, channels, error) ;
src_reset (src_state) ; src_reset (src_state) ;
((SRC_PRIVATE*) src_state)->mode = SRC_MODE_CALLBACK ; ((SRC_PRIVATE*) src_state)->mode = SRC_MODE_CALLBACK ;
((SRC_PRIVATE*) src_state)->callback_func = func ; ((SRC_PRIVATE*) src_state)->callback_func = func ;
((SRC_PRIVATE*) src_state)->user_callback_data = cb_data ; ((SRC_PRIVATE*) src_state)->user_callback_data = cb_data ;
return src_state ; return src_state ;
} /* src_callback_new */ } /* src_callback_new */
SRC_STATE * SRC_STATE *
src_delete (SRC_STATE *state) src_delete (SRC_STATE *state)
{ SRC_PRIVATE *psrc ; { SRC_PRIVATE *psrc ;
psrc = (SRC_PRIVATE*) state ; psrc = (SRC_PRIVATE*) state ;
if (psrc) if (psrc)
{ if (psrc->private_data) { if (psrc->private_data)
free (psrc->private_data) ; free (psrc->private_data) ;
memset (psrc, 0, sizeof (SRC_PRIVATE)) ; memset (psrc, 0, sizeof (SRC_PRIVATE)) ;
free (psrc) ; free (psrc) ;
} ; } ;
return NULL ; return NULL ;
} /* src_state */ } /* src_state */
int int
src_process (SRC_STATE *state, SRC_DATA *data) src_process (SRC_STATE *state, SRC_DATA *data)
{ SRC_PRIVATE *psrc ; { SRC_PRIVATE *psrc ;
int error ; int error ;
psrc = (SRC_PRIVATE*) state ; psrc = (SRC_PRIVATE*) state ;
if (psrc == NULL) if (psrc == NULL)
return SRC_ERR_BAD_STATE ; return SRC_ERR_BAD_STATE ;
if (psrc->vari_process == NULL || psrc->const_process == NULL) if (psrc->vari_process == NULL || psrc->const_process == NULL)
return SRC_ERR_BAD_PROC_PTR ; return SRC_ERR_BAD_PROC_PTR ;
if (psrc->mode != SRC_MODE_PROCESS) if (psrc->mode != SRC_MODE_PROCESS)
return SRC_ERR_BAD_MODE ; return SRC_ERR_BAD_MODE ;
/* Check for valid SRC_DATA first. */ /* Check for valid SRC_DATA first. */
if (data == NULL) if (data == NULL)
return SRC_ERR_BAD_DATA ; return SRC_ERR_BAD_DATA ;
/* Check src_ratio is in range. */ /* Check src_ratio is in range. */
if (is_bad_src_ratio (data->src_ratio)) if (is_bad_src_ratio (data->src_ratio))
return SRC_ERR_BAD_SRC_RATIO ; return SRC_ERR_BAD_SRC_RATIO ;
/* And that data_in and data_out are valid. */ /* And that data_in and data_out are valid. */
if (data->data_in == NULL || data->data_out == NULL) if (data->data_in == NULL || data->data_out == NULL)
return SRC_ERR_BAD_DATA_PTR ; return SRC_ERR_BAD_DATA_PTR ;
if (data->data_in == NULL) if (data->data_in == NULL)
data->input_frames = 0 ; data->input_frames = 0 ;
if (data->input_frames < 0) if (data->input_frames < 0)
data->input_frames = 0 ; data->input_frames = 0 ;
if (data->output_frames < 0) if (data->output_frames < 0)
data->output_frames = 0 ; data->output_frames = 0 ;
if (data->data_in < data->data_out) if (data->data_in < data->data_out)
{ if (data->data_in + data->input_frames * psrc->channels > data->data_out) { if (data->data_in + data->input_frames * psrc->channels > data->data_out)
{ /*-printf ("\n\ndata_in: %p data_out: %p\n", { /*-printf ("\n\ndata_in: %p data_out: %p\n",
(void*) (data->data_in + data->input_frames * psrc->channels), (void*) data->data_out) ;-*/ (void*) (data->data_in + data->input_frames * psrc->channels), (void*) data->data_out) ;-*/
return SRC_ERR_DATA_OVERLAP ; return SRC_ERR_DATA_OVERLAP ;
} ; } ;
} }
else if (data->data_out + data->output_frames * psrc->channels > data->data_in) else if (data->data_out + data->output_frames * psrc->channels > data->data_in)
{ /*-printf ("\n\ndata_in : %p ouput frames: %ld data_out: %p\n", (void*) data->data_in, data->output_frames, (void*) data->data_out) ; { /*-printf ("\n\ndata_in : %p ouput frames: %ld data_out: %p\n", (void*) data->data_in, data->output_frames, (void*) data->data_out) ;
printf ("data_out: %p (%p) data_in: %p\n", (void*) data->data_out, printf ("data_out: %p (%p) data_in: %p\n", (void*) data->data_out,
(void*) (data->data_out + data->input_frames * psrc->channels), (void*) data->data_in) ;-*/ (void*) (data->data_out + data->input_frames * psrc->channels), (void*) data->data_in) ;-*/
return SRC_ERR_DATA_OVERLAP ; return SRC_ERR_DATA_OVERLAP ;
} ; } ;
/* Set the input and output counts to zero. */ /* Set the input and output counts to zero. */
data->input_frames_used = 0 ; data->input_frames_used = 0 ;
data->output_frames_gen = 0 ; data->output_frames_gen = 0 ;
/* Special case for when last_ratio has not been set. */ /* Special case for when last_ratio has not been set. */
if (psrc->last_ratio < (1.0 / SRC_MAX_RATIO)) if (psrc->last_ratio < (1.0 / SRC_MAX_RATIO))
psrc->last_ratio = data->src_ratio ; psrc->last_ratio = data->src_ratio ;
/* Now process. */ /* Now process. */
if (fabs (psrc->last_ratio - data->src_ratio) < 1e-15) if (fabs (psrc->last_ratio - data->src_ratio) < 1e-15)
error = psrc->const_process (psrc, data) ; error = psrc->const_process (psrc, data) ;
else else
error = psrc->vari_process (psrc, data) ; error = psrc->vari_process (psrc, data) ;
return error ; return error ;
} /* src_process */ } /* src_process */
long long
src_callback_read (SRC_STATE *state, double src_ratio, long frames, float *data) src_callback_read (SRC_STATE *state, double src_ratio, long frames, float *data)
{ SRC_PRIVATE *psrc ; { SRC_PRIVATE *psrc ;
SRC_DATA src_data ; SRC_DATA src_data ;
long output_frames_gen ; long output_frames_gen ;
int error = 0 ; int error = 0 ;
if (state == NULL) if (state == NULL)
return 0 ; return 0 ;
if (frames <= 0) if (frames <= 0)
return 0 ; return 0 ;
psrc = (SRC_PRIVATE*) state ; psrc = (SRC_PRIVATE*) state ;
if (psrc->mode != SRC_MODE_CALLBACK) if (psrc->mode != SRC_MODE_CALLBACK)
{ psrc->error = SRC_ERR_BAD_MODE ; { psrc->error = SRC_ERR_BAD_MODE ;
return 0 ; return 0 ;
} ; } ;
if (psrc->callback_func == NULL) if (psrc->callback_func == NULL)
{ psrc->error = SRC_ERR_NULL_CALLBACK ; { psrc->error = SRC_ERR_NULL_CALLBACK ;
return 0 ; return 0 ;
} ; } ;
memset (&src_data, 0, sizeof (src_data)) ; memset (&src_data, 0, sizeof (src_data)) ;
/* Check src_ratio is in range. */ /* Check src_ratio is in range. */
if (is_bad_src_ratio (src_ratio)) if (is_bad_src_ratio (src_ratio))
{ psrc->error = SRC_ERR_BAD_SRC_RATIO ; { psrc->error = SRC_ERR_BAD_SRC_RATIO ;
return 0 ; return 0 ;
} ; } ;
/* Switch modes temporarily. */ /* Switch modes temporarily. */
src_data.src_ratio = src_ratio ; src_data.src_ratio = src_ratio ;
src_data.data_out = data ; src_data.data_out = data ;
src_data.output_frames = frames ; src_data.output_frames = frames ;
src_data.data_in = psrc->saved_data ; src_data.data_in = psrc->saved_data ;
src_data.input_frames = psrc->saved_frames ; src_data.input_frames = psrc->saved_frames ;
output_frames_gen = 0 ; output_frames_gen = 0 ;
while (output_frames_gen < frames) while (output_frames_gen < frames)
{ {
if (src_data.input_frames == 0) if (src_data.input_frames == 0)
{ float *ptr ; { float *ptr ;
src_data.input_frames = psrc->callback_func (psrc->user_callback_data, &ptr) ; src_data.input_frames = psrc->callback_func (psrc->user_callback_data, &ptr) ;
src_data.data_in = ptr ; src_data.data_in = ptr ;
if (src_data.input_frames == 0) if (src_data.input_frames == 0)
src_data.end_of_input = 1 ; src_data.end_of_input = 1 ;
} ; } ;
/* /*
** Now call process function. However, we need to set the mode ** Now call process function. However, we need to set the mode
** to SRC_MODE_PROCESS first and when we return set it back to ** to SRC_MODE_PROCESS first and when we return set it back to
** SRC_MODE_CALLBACK. ** SRC_MODE_CALLBACK.
*/ */
psrc->mode = SRC_MODE_PROCESS ; psrc->mode = SRC_MODE_PROCESS ;
error = src_process (state, &src_data) ; error = src_process (state, &src_data) ;
psrc->mode = SRC_MODE_CALLBACK ; psrc->mode = SRC_MODE_CALLBACK ;
if (error != 0) if (error != 0)
break ; break ;
src_data.data_in += src_data.input_frames_used * psrc->channels ; src_data.data_in += src_data.input_frames_used * psrc->channels ;
src_data.input_frames -= src_data.input_frames_used ; src_data.input_frames -= src_data.input_frames_used ;
src_data.data_out += src_data.output_frames_gen * psrc->channels ; src_data.data_out += src_data.output_frames_gen * psrc->channels ;
src_data.output_frames -= src_data.output_frames_gen ; src_data.output_frames -= src_data.output_frames_gen ;
output_frames_gen += src_data.output_frames_gen ; output_frames_gen += src_data.output_frames_gen ;
if (src_data.end_of_input == SRC_TRUE && src_data.output_frames_gen == 0) if (src_data.end_of_input == SRC_TRUE && src_data.output_frames_gen == 0)
break ; break ;
} ; } ;
psrc->saved_data = src_data.data_in ; psrc->saved_data = src_data.data_in ;
psrc->saved_frames = src_data.input_frames ; psrc->saved_frames = src_data.input_frames ;
if (error != 0) if (error != 0)
{ psrc->error = error ; { psrc->error = error ;
return 0 ; return 0 ;
} ; } ;
return output_frames_gen ; return output_frames_gen ;
} /* src_callback_read */ } /* src_callback_read */
/*========================================================================== /*==========================================================================
@ -275,265 +275,265 @@ src_callback_read (SRC_STATE *state, double src_ratio, long frames, float *data)
int int
src_set_ratio (SRC_STATE *state, double new_ratio) src_set_ratio (SRC_STATE *state, double new_ratio)
{ SRC_PRIVATE *psrc ; { SRC_PRIVATE *psrc ;
psrc = (SRC_PRIVATE*) state ; psrc = (SRC_PRIVATE*) state ;
if (psrc == NULL) if (psrc == NULL)
return SRC_ERR_BAD_STATE ; return SRC_ERR_BAD_STATE ;
if (psrc->vari_process == NULL || psrc->const_process == NULL) if (psrc->vari_process == NULL || psrc->const_process == NULL)
return SRC_ERR_BAD_PROC_PTR ; return SRC_ERR_BAD_PROC_PTR ;
if (is_bad_src_ratio (new_ratio)) if (is_bad_src_ratio (new_ratio))
return SRC_ERR_BAD_SRC_RATIO ; return SRC_ERR_BAD_SRC_RATIO ;
psrc->last_ratio = new_ratio ; psrc->last_ratio = new_ratio ;
return SRC_ERR_NO_ERROR ; return SRC_ERR_NO_ERROR ;
} /* src_set_ratio */ } /* src_set_ratio */
int int
src_reset (SRC_STATE *state) src_reset (SRC_STATE *state)
{ SRC_PRIVATE *psrc ; { SRC_PRIVATE *psrc ;
if ((psrc = (SRC_PRIVATE*) state) == NULL) if ((psrc = (SRC_PRIVATE*) state) == NULL)
return SRC_ERR_BAD_STATE ; return SRC_ERR_BAD_STATE ;
if (psrc->reset != NULL) if (psrc->reset != NULL)
psrc->reset (psrc) ; psrc->reset (psrc) ;
psrc->last_position = 0.0 ; psrc->last_position = 0.0 ;
psrc->last_ratio = 0.0 ; psrc->last_ratio = 0.0 ;
psrc->saved_data = NULL ; psrc->saved_data = NULL ;
psrc->saved_frames = 0 ; psrc->saved_frames = 0 ;
psrc->error = SRC_ERR_NO_ERROR ; psrc->error = SRC_ERR_NO_ERROR ;
return SRC_ERR_NO_ERROR ; return SRC_ERR_NO_ERROR ;
} /* src_reset */ } /* src_reset */
/*============================================================================== /*==============================================================================
** Control functions. ** Control functions.
*/ */
const char * const char *
src_get_name (int converter_type) src_get_name (int converter_type)
{ const char *desc ; { const char *desc ;
if ((desc = sinc_get_name (converter_type)) != NULL) if ((desc = sinc_get_name (converter_type)) != NULL)
return desc ; return desc ;
if ((desc = zoh_get_name (converter_type)) != NULL) if ((desc = zoh_get_name (converter_type)) != NULL)
return desc ; return desc ;
if ((desc = linear_get_name (converter_type)) != NULL) if ((desc = linear_get_name (converter_type)) != NULL)
return desc ; return desc ;
return NULL ; return NULL ;
} /* src_get_name */ } /* src_get_name */
const char * const char *
src_get_description (int converter_type) src_get_description (int converter_type)
{ const char *desc ; { const char *desc ;
if ((desc = sinc_get_description (converter_type)) != NULL) if ((desc = sinc_get_description (converter_type)) != NULL)
return desc ; return desc ;
if ((desc = zoh_get_description (converter_type)) != NULL) if ((desc = zoh_get_description (converter_type)) != NULL)
return desc ; return desc ;
if ((desc = linear_get_description (converter_type)) != NULL) if ((desc = linear_get_description (converter_type)) != NULL)
return desc ; return desc ;
return NULL ; return NULL ;
} /* src_get_description */ } /* src_get_description */
const char * const char *
src_get_version (void) src_get_version (void)
{ return PACKAGE "-" VERSION " (c) 2002-2008 Erik de Castro Lopo" ; { return PACKAGE "-" VERSION " (c) 2002-2008 Erik de Castro Lopo" ;
} /* src_get_version */ } /* src_get_version */
int int
src_is_valid_ratio (double ratio) src_is_valid_ratio (double ratio)
{ {
if (is_bad_src_ratio (ratio)) if (is_bad_src_ratio (ratio))
return SRC_FALSE ; return SRC_FALSE ;
return SRC_TRUE ; return SRC_TRUE ;
} /* src_is_valid_ratio */ } /* src_is_valid_ratio */
/*============================================================================== /*==============================================================================
** Error reporting functions. ** Error reporting functions.
*/ */
int int
src_error (SRC_STATE *state) src_error (SRC_STATE *state)
{ if (state) { if (state)
return ((SRC_PRIVATE*) state)->error ; return ((SRC_PRIVATE*) state)->error ;
return SRC_ERR_NO_ERROR ; return SRC_ERR_NO_ERROR ;
} /* src_error */ } /* src_error */
const char* const char*
src_strerror (int error) src_strerror (int error)
{ {
switch (error) switch (error)
{ case SRC_ERR_NO_ERROR : { case SRC_ERR_NO_ERROR :
return "No error." ; return "No error." ;
case SRC_ERR_MALLOC_FAILED : case SRC_ERR_MALLOC_FAILED :
return "Malloc failed." ; return "Malloc failed." ;
case SRC_ERR_BAD_STATE : case SRC_ERR_BAD_STATE :
return "SRC_STATE pointer is NULL." ; return "SRC_STATE pointer is NULL." ;
case SRC_ERR_BAD_DATA : case SRC_ERR_BAD_DATA :
return "SRC_DATA pointer is NULL." ; return "SRC_DATA pointer is NULL." ;
case SRC_ERR_BAD_DATA_PTR : case SRC_ERR_BAD_DATA_PTR :
return "SRC_DATA->data_out is NULL." ; return "SRC_DATA->data_out is NULL." ;
case SRC_ERR_NO_PRIVATE : case SRC_ERR_NO_PRIVATE :
return "Internal error. No private data." ; return "Internal error. No private data." ;
case SRC_ERR_BAD_SRC_RATIO : case SRC_ERR_BAD_SRC_RATIO :
return "SRC ratio outside [1/12, 12] range." ; return "SRC ratio outside [1/12, 12] range." ;
case SRC_ERR_BAD_SINC_STATE : case SRC_ERR_BAD_SINC_STATE :
return "src_process() called without reset after end_of_input." ; return "src_process() called without reset after end_of_input." ;
case SRC_ERR_BAD_PROC_PTR : case SRC_ERR_BAD_PROC_PTR :
return "Internal error. No process pointer." ; return "Internal error. No process pointer." ;
case SRC_ERR_SHIFT_BITS : case SRC_ERR_SHIFT_BITS :
return "Internal error. SHIFT_BITS too large." ; return "Internal error. SHIFT_BITS too large." ;
case SRC_ERR_FILTER_LEN : case SRC_ERR_FILTER_LEN :
return "Internal error. Filter length too large." ; return "Internal error. Filter length too large." ;
case SRC_ERR_BAD_CONVERTER : case SRC_ERR_BAD_CONVERTER :
return "Bad converter number." ; return "Bad converter number." ;
case SRC_ERR_BAD_CHANNEL_COUNT : case SRC_ERR_BAD_CHANNEL_COUNT :
return "Channel count must be >= 1." ; return "Channel count must be >= 1." ;
case SRC_ERR_SINC_BAD_BUFFER_LEN : case SRC_ERR_SINC_BAD_BUFFER_LEN :
return "Internal error. Bad buffer length. Please report this." ; return "Internal error. Bad buffer length. Please report this." ;
case SRC_ERR_SIZE_INCOMPATIBILITY : case SRC_ERR_SIZE_INCOMPATIBILITY :
return "Internal error. Input data / internal buffer size difference. Please report this." ; return "Internal error. Input data / internal buffer size difference. Please report this." ;
case SRC_ERR_BAD_PRIV_PTR : case SRC_ERR_BAD_PRIV_PTR :
return "Internal error. Private pointer is NULL. Please report this." ; return "Internal error. Private pointer is NULL. Please report this." ;
case SRC_ERR_DATA_OVERLAP : case SRC_ERR_DATA_OVERLAP :
return "Input and output data arrays overlap." ; return "Input and output data arrays overlap." ;
case SRC_ERR_BAD_CALLBACK : case SRC_ERR_BAD_CALLBACK :
return "Supplied callback function pointer is NULL." ; return "Supplied callback function pointer is NULL." ;
case SRC_ERR_BAD_MODE : case SRC_ERR_BAD_MODE :
return "Calling mode differs from initialisation mode (ie process v callback)." ; return "Calling mode differs from initialisation mode (ie process v callback)." ;
case SRC_ERR_NULL_CALLBACK : case SRC_ERR_NULL_CALLBACK :
return "Callback function pointer is NULL in src_callback_read ()." ; return "Callback function pointer is NULL in src_callback_read ()." ;
case SRC_ERR_NO_VARIABLE_RATIO : case SRC_ERR_NO_VARIABLE_RATIO :
return "This converter only allows constant conversion ratios." ; return "This converter only allows constant conversion ratios." ;
case SRC_ERR_MAX_ERROR : case SRC_ERR_MAX_ERROR :
return "Placeholder. No error defined for this error number." ; return "Placeholder. No error defined for this error number." ;
default : break ; default : break ;
} }
return NULL ; return NULL ;
} /* src_strerror */ } /* src_strerror */
/*============================================================================== /*==============================================================================
** Simple interface for performing a single conversion from input buffer to ** Simple interface for performing a single conversion from input buffer to
** output buffer at a fixed conversion ratio. ** output buffer at a fixed conversion ratio.
*/ */
int int
src_simple (SRC_DATA *src_data, int converter, int channels) src_simple (SRC_DATA *src_data, int converter, int channels)
{ SRC_STATE *src_state ; { SRC_STATE *src_state ;
int error ; int error ;
if ((src_state = src_new (converter, channels, &error)) == NULL) if ((src_state = src_new (converter, channels, &error)) == NULL)
return error ; return error ;
src_data->end_of_input = 1 ; /* Only one buffer worth of input. */ src_data->end_of_input = 1 ; /* Only one buffer worth of input. */
error = src_process (src_state, src_data) ; error = src_process (src_state, src_data) ;
src_state = src_delete (src_state) ; src_state = src_delete (src_state) ;
return error ; return error ;
} /* src_simple */ } /* src_simple */
void void
src_short_to_float_array (const short *in, float *out, int len) src_short_to_float_array (const short *in, float *out, int len)
{ {
while (len) while (len)
{ len -- ; { len -- ;
out [len] = (float) (in [len] / (1.0 * 0x8000)) ; out [len] = (float) (in [len] / (1.0 * 0x8000)) ;
} ; } ;
return ; return ;
} /* src_short_to_float_array */ } /* src_short_to_float_array */
void void
src_float_to_short_array (const float *in, short *out, int len) src_float_to_short_array (const float *in, short *out, int len)
{ double scaled_value ; { double scaled_value ;
while (len) while (len)
{ len -- ; { len -- ;
scaled_value = in [len] * (8.0 * 0x10000000) ; scaled_value = in [len] * (8.0 * 0x10000000) ;
if (CPU_CLIPS_POSITIVE == 0 && scaled_value >= (1.0 * 0x7FFFFFFF)) if (CPU_CLIPS_POSITIVE == 0 && scaled_value >= (1.0 * 0x7FFFFFFF))
{ out [len] = 32767 ; { out [len] = 32767 ;
continue ; continue ;
} ; } ;
if (CPU_CLIPS_NEGATIVE == 0 && scaled_value <= (-8.0 * 0x10000000)) if (CPU_CLIPS_NEGATIVE == 0 && scaled_value <= (-8.0 * 0x10000000))
{ out [len] = -32768 ; { out [len] = -32768 ;
continue ; continue ;
} ; } ;
out [len] = (short) (lrint (scaled_value) >> 16) ; out [len] = (short) (lrint (scaled_value) >> 16) ;
} ; } ;
} /* src_float_to_short_array */ } /* src_float_to_short_array */
void void
src_int_to_float_array (const int *in, float *out, int len) src_int_to_float_array (const int *in, float *out, int len)
{ {
while (len) while (len)
{ len -- ; { len -- ;
out [len] = (float) (in [len] / (8.0 * 0x10000000)) ; out [len] = (float) (in [len] / (8.0 * 0x10000000)) ;
} ; } ;
return ; return ;
} /* src_int_to_float_array */ } /* src_int_to_float_array */
void void
src_float_to_int_array (const float *in, int *out, int len) src_float_to_int_array (const float *in, int *out, int len)
{ double scaled_value ; { double scaled_value ;
while (len) while (len)
{ len -- ; { len -- ;
scaled_value = in [len] * (8.0 * 0x10000000) ; scaled_value = in [len] * (8.0 * 0x10000000) ;
if (CPU_CLIPS_POSITIVE == 0 && scaled_value >= (1.0 * 0x7FFFFFFF)) if (CPU_CLIPS_POSITIVE == 0 && scaled_value >= (1.0 * 0x7FFFFFFF))
{ out [len] = 0x7fffffff ; { out [len] = 0x7fffffff ;
continue ; continue ;
} ; } ;
if (CPU_CLIPS_NEGATIVE == 0 && scaled_value <= (-8.0 * 0x10000000)) if (CPU_CLIPS_NEGATIVE == 0 && scaled_value <= (-8.0 * 0x10000000))
{ out [len] = -1 - 0x7fffffff ; { out [len] = -1 - 0x7fffffff ;
continue ; continue ;
} ; } ;
out [len] = lrint (scaled_value) ; out [len] = lrint (scaled_value) ;
} ; } ;
} /* src_float_to_int_array */ } /* src_float_to_int_array */
/*============================================================================== /*==============================================================================
** Private functions. ** Private functions.
*/ */
static int static int
psrc_set_converter (SRC_PRIVATE *psrc, int converter_type) psrc_set_converter (SRC_PRIVATE *psrc, int converter_type)
{ {
if (sinc_set_converter (psrc, converter_type) == SRC_ERR_NO_ERROR) if (sinc_set_converter (psrc, converter_type) == SRC_ERR_NO_ERROR)
return SRC_ERR_NO_ERROR ; return SRC_ERR_NO_ERROR ;
if (zoh_set_converter (psrc, converter_type) == SRC_ERR_NO_ERROR) if (zoh_set_converter (psrc, converter_type) == SRC_ERR_NO_ERROR)
return SRC_ERR_NO_ERROR ; return SRC_ERR_NO_ERROR ;
if (linear_set_converter (psrc, converter_type) == SRC_ERR_NO_ERROR) if (linear_set_converter (psrc, converter_type) == SRC_ERR_NO_ERROR)
return SRC_ERR_NO_ERROR ; return SRC_ERR_NO_ERROR ;
return SRC_ERR_BAD_CONVERTER ; return SRC_ERR_BAD_CONVERTER ;
} /* psrc_set_converter */ } /* psrc_set_converter */

View File

@ -19,7 +19,7 @@
/* /*
** This code is part of Secret Rabibt Code aka libsamplerate. A commercial ** This code is part of Secret Rabibt Code aka libsamplerate. A commercial
** use license for this code is available, please see: ** use license for this code is available, please see:
** http://www.mega-nerd.com/SRC/procedure.html ** http://www.mega-nerd.com/SRC/procedure.html
*/ */
/* /*
@ -32,7 +32,7 @@
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif /* __cplusplus */ #endif /* __cplusplus */
/* Opaque data type SRC_STATE. */ /* Opaque data type SRC_STATE. */
@ -40,20 +40,20 @@ typedef struct SRC_STATE_tag SRC_STATE ;
/* SRC_DATA is used to pass data to src_simple() and src_process(). */ /* SRC_DATA is used to pass data to src_simple() and src_process(). */
typedef struct typedef struct
{ float *data_in, *data_out ; { float *data_in, *data_out ;
long input_frames, output_frames ; long input_frames, output_frames ;
long input_frames_used, output_frames_gen ; long input_frames_used, output_frames_gen ;
int end_of_input ; int end_of_input ;
double src_ratio ; double src_ratio ;
} SRC_DATA ; } SRC_DATA ;
/* SRC_CB_DATA is used with callback based API. */ /* SRC_CB_DATA is used with callback based API. */
typedef struct typedef struct
{ long frames ; { long frames ;
float *data_in ; float *data_in ;
} SRC_CB_DATA ; } SRC_CB_DATA ;
/* /*
@ -68,49 +68,49 @@ typedef struct
typedef long (*src_callback_t) (void *cb_data, float **data) ; typedef long (*src_callback_t) (void *cb_data, float **data) ;
/* /*
** Standard initialisation function : return an anonymous pointer to the ** Standard initialisation function : return an anonymous pointer to the
** internal state of the converter. Choose a converter from the enums below. ** internal state of the converter. Choose a converter from the enums below.
** Error returned in *error. ** Error returned in *error.
*/ */
SRC_STATE* src_new (int converter_type, int channels, int *error) ; SRC_STATE* src_new (int converter_type, int channels, int *error) ;
/* /*
** Initilisation for callback based API : return an anonymous pointer to the ** Initilisation for callback based API : return an anonymous pointer to the
** internal state of the converter. Choose a converter from the enums below. ** internal state of the converter. Choose a converter from the enums below.
** The cb_data pointer can point to any data or be set to NULL. Whatever the ** The cb_data pointer can point to any data or be set to NULL. Whatever the
** value, when processing, user supplied function "func" gets called with ** value, when processing, user supplied function "func" gets called with
** cb_data as first parameter. ** cb_data as first parameter.
*/ */
SRC_STATE* src_callback_new (src_callback_t func, int converter_type, int channels, SRC_STATE* src_callback_new (src_callback_t func, int converter_type, int channels,
int *error, void* cb_data) ; int *error, void* cb_data) ;
/* /*
** Cleanup all internal allocations. ** Cleanup all internal allocations.
** Always returns NULL. ** Always returns NULL.
*/ */
SRC_STATE* src_delete (SRC_STATE *state) ; SRC_STATE* src_delete (SRC_STATE *state) ;
/* /*
** Standard processing function. ** Standard processing function.
** Returns non zero on error. ** Returns non zero on error.
*/ */
int src_process (SRC_STATE *state, SRC_DATA *data) ; int src_process (SRC_STATE *state, SRC_DATA *data) ;
/* /*
** Callback based processing function. Read up to frames worth of data from ** Callback based processing function. Read up to frames worth of data from
** the converter int *data and return frames read or -1 on error. ** the converter int *data and return frames read or -1 on error.
*/ */
long src_callback_read (SRC_STATE *state, double src_ratio, long frames, float *data) ; long src_callback_read (SRC_STATE *state, double src_ratio, long frames, float *data) ;
/* /*
** Simple interface for performing a single conversion from input buffer to ** Simple interface for performing a single conversion from input buffer to
** output buffer at a fixed conversion ratio. ** output buffer at a fixed conversion ratio.
** Simple interface does not require initialisation as it can only operate on ** Simple interface does not require initialisation as it can only operate on
** a single buffer worth of audio. ** a single buffer worth of audio.
*/ */
int src_simple (SRC_DATA *data, int converter_type, int channels) ; int src_simple (SRC_DATA *data, int converter_type, int channels) ;
@ -129,18 +129,18 @@ const char *src_get_description (int converter_type) ;
const char *src_get_version (void) ; const char *src_get_version (void) ;
/* /*
** Set a new SRC ratio. This allows step responses ** Set a new SRC ratio. This allows step responses
** in the conversion ratio. ** in the conversion ratio.
** Returns non zero on error. ** Returns non zero on error.
*/ */
int src_set_ratio (SRC_STATE *state, double new_ratio) ; int src_set_ratio (SRC_STATE *state, double new_ratio) ;
/* /*
** Reset the internal SRC state. ** Reset the internal SRC state.
** Does not modify the quality settings. ** Does not modify the quality settings.
** Does not free any memory allocations. ** Does not free any memory allocations.
** Returns non zero on error. ** Returns non zero on error.
*/ */
int src_reset (SRC_STATE *state) ; int src_reset (SRC_STATE *state) ;
@ -153,13 +153,13 @@ int src_reset (SRC_STATE *state) ;
int src_is_valid_ratio (double ratio) ; int src_is_valid_ratio (double ratio) ;
/* /*
** Return an error number. ** Return an error number.
*/ */
int src_error (SRC_STATE *state) ; int src_error (SRC_STATE *state) ;
/* /*
** Convert the error number into a string. ** Convert the error number into a string.
*/ */
const char* src_strerror (int error) ; const char* src_strerror (int error) ;
@ -170,11 +170,11 @@ const char* src_strerror (int error) ;
enum enum
{ {
SRC_SINC_BEST_QUALITY = 0, SRC_SINC_BEST_QUALITY = 0,
SRC_SINC_MEDIUM_QUALITY = 1, SRC_SINC_MEDIUM_QUALITY = 1,
SRC_SINC_FASTEST = 2, SRC_SINC_FASTEST = 2,
SRC_ZERO_ORDER_HOLD = 3, SRC_ZERO_ORDER_HOLD = 3,
SRC_LINEAR = 4, SRC_LINEAR = 4,
} ; } ;
/* /*
@ -190,8 +190,8 @@ void src_float_to_int_array (const float *in, int *out, int len) ;
#ifdef __cplusplus #ifdef __cplusplus
} /* extern "C" */ } /* extern "C" */
#endif /* __cplusplus */ #endif /* __cplusplus */
#endif /* SAMPLERATE_H */ #endif /* SAMPLERATE_H */

View File

@ -19,7 +19,7 @@
/* /*
** This code is part of Secret Rabibt Code aka libsamplerate. A commercial ** This code is part of Secret Rabibt Code aka libsamplerate. A commercial
** use license for this code is available, please see: ** use license for this code is available, please see:
** http://www.mega-nerd.com/SRC/procedure.html ** http://www.mega-nerd.com/SRC/procedure.html
*/ */
#include <stdio.h> #include <stdio.h>
@ -36,17 +36,17 @@ static void linear_reset (SRC_PRIVATE *psrc) ;
/*======================================================================================== /*========================================================================================
*/ */
#define LINEAR_MAGIC_MARKER MAKE_MAGIC ('l', 'i', 'n', 'e', 'a', 'r') #define LINEAR_MAGIC_MARKER MAKE_MAGIC ('l', 'i', 'n', 'e', 'a', 'r')
#define SRC_DEBUG 0 #define SRC_DEBUG 0
typedef struct typedef struct
{ int linear_magic_marker ; { int linear_magic_marker ;
int channels ; int channels ;
int reset ; int reset ;
long in_count, in_used ; long in_count, in_used ;
long out_count, out_gen ; long out_count, out_gen ;
float last_value [1] ; float last_value [1] ;
} LINEAR_DATA ; } LINEAR_DATA ;
/*---------------------------------------------------------------------------------------- /*----------------------------------------------------------------------------------------
@ -54,95 +54,95 @@ typedef struct
static int static int
linear_vari_process (SRC_PRIVATE *psrc, SRC_DATA *data) linear_vari_process (SRC_PRIVATE *psrc, SRC_DATA *data)
{ LINEAR_DATA *linear ; { LINEAR_DATA *linear ;
double src_ratio, input_index, rem ; double src_ratio, input_index, rem ;
int ch ; int ch ;
if (psrc->private_data == NULL) if (psrc->private_data == NULL)
return SRC_ERR_NO_PRIVATE ; return SRC_ERR_NO_PRIVATE ;
linear = (LINEAR_DATA*) psrc->private_data ; linear = (LINEAR_DATA*) psrc->private_data ;
if (linear->reset) if (linear->reset)
{ /* If we have just been reset, set the last_value data. */ { /* If we have just been reset, set the last_value data. */
for (ch = 0 ; ch < linear->channels ; ch++) for (ch = 0 ; ch < linear->channels ; ch++)
linear->last_value [ch] = data->data_in [ch] ; linear->last_value [ch] = data->data_in [ch] ;
linear->reset = 0 ; linear->reset = 0 ;
} ; } ;
linear->in_count = data->input_frames * linear->channels ; linear->in_count = data->input_frames * linear->channels ;
linear->out_count = data->output_frames * linear->channels ; linear->out_count = data->output_frames * linear->channels ;
linear->in_used = linear->out_gen = 0 ; linear->in_used = linear->out_gen = 0 ;
src_ratio = psrc->last_ratio ; src_ratio = psrc->last_ratio ;
input_index = psrc->last_position ; input_index = psrc->last_position ;
/* Calculate samples before first sample in input array. */ /* Calculate samples before first sample in input array. */
while (input_index < 1.0 && linear->out_gen < linear->out_count) while (input_index < 1.0 && linear->out_gen < linear->out_count)
{ {
if (linear->in_used + linear->channels * input_index > linear->in_count) if (linear->in_used + linear->channels * input_index > linear->in_count)
break ; break ;
if (linear->out_count > 0 && fabs (psrc->last_ratio - data->src_ratio) > SRC_MIN_RATIO_DIFF) if (linear->out_count > 0 && fabs (psrc->last_ratio - data->src_ratio) > SRC_MIN_RATIO_DIFF)
src_ratio = psrc->last_ratio + linear->out_gen * (data->src_ratio - psrc->last_ratio) / linear->out_count ; src_ratio = psrc->last_ratio + linear->out_gen * (data->src_ratio - psrc->last_ratio) / linear->out_count ;
for (ch = 0 ; ch < linear->channels ; ch++) for (ch = 0 ; ch < linear->channels ; ch++)
{ data->data_out [linear->out_gen] = (float) (linear->last_value [ch] + input_index * { data->data_out [linear->out_gen] = (float) (linear->last_value [ch] + input_index *
(data->data_in [ch] - linear->last_value [ch])) ; (data->data_in [ch] - linear->last_value [ch])) ;
linear->out_gen ++ ; linear->out_gen ++ ;
} ; } ;
/* Figure out the next index. */ /* Figure out the next index. */
input_index += 1.0 / src_ratio ; input_index += 1.0 / src_ratio ;
} ; } ;
rem = fmod_one (input_index) ; rem = fmod_one (input_index) ;
linear->in_used += linear->channels * lrint (input_index - rem) ; linear->in_used += linear->channels * lrint (input_index - rem) ;
input_index = rem ; input_index = rem ;
/* Main processing loop. */ /* Main processing loop. */
while (linear->out_gen < linear->out_count && linear->in_used + linear->channels * input_index <= linear->in_count) while (linear->out_gen < linear->out_count && linear->in_used + linear->channels * input_index <= linear->in_count)
{ {
if (linear->out_count > 0 && fabs (psrc->last_ratio - data->src_ratio) > SRC_MIN_RATIO_DIFF) if (linear->out_count > 0 && fabs (psrc->last_ratio - data->src_ratio) > SRC_MIN_RATIO_DIFF)
src_ratio = psrc->last_ratio + linear->out_gen * (data->src_ratio - psrc->last_ratio) / linear->out_count ; src_ratio = psrc->last_ratio + linear->out_gen * (data->src_ratio - psrc->last_ratio) / linear->out_count ;
if (SRC_DEBUG && linear->in_used < linear->channels && input_index < 1.0) if (SRC_DEBUG && linear->in_used < linear->channels && input_index < 1.0)
{ printf ("Whoops!!!! in_used : %ld channels : %d input_index : %f\n", linear->in_used, linear->channels, input_index) ; { printf ("Whoops!!!! in_used : %ld channels : %d input_index : %f\n", linear->in_used, linear->channels, input_index) ;
exit (1) ; exit (1) ;
} ; } ;
for (ch = 0 ; ch < linear->channels ; ch++) for (ch = 0 ; ch < linear->channels ; ch++)
{ data->data_out [linear->out_gen] = (float) (data->data_in [linear->in_used - linear->channels + ch] + input_index * { data->data_out [linear->out_gen] = (float) (data->data_in [linear->in_used - linear->channels + ch] + input_index *
(data->data_in [linear->in_used + ch] - data->data_in [linear->in_used - linear->channels + ch])) ; (data->data_in [linear->in_used + ch] - data->data_in [linear->in_used - linear->channels + ch])) ;
linear->out_gen ++ ; linear->out_gen ++ ;
} ; } ;
/* Figure out the next index. */ /* Figure out the next index. */
input_index += 1.0 / src_ratio ; input_index += 1.0 / src_ratio ;
rem = fmod_one (input_index) ; rem = fmod_one (input_index) ;
linear->in_used += linear->channels * lrint (input_index - rem) ; linear->in_used += linear->channels * lrint (input_index - rem) ;
input_index = rem ; input_index = rem ;
} ; } ;
if (linear->in_used > linear->in_count) if (linear->in_used > linear->in_count)
{ input_index += (linear->in_used - linear->in_count) / linear->channels ; { input_index += (linear->in_used - linear->in_count) / linear->channels ;
linear->in_used = linear->in_count ; linear->in_used = linear->in_count ;
} ; } ;
psrc->last_position = input_index ; psrc->last_position = input_index ;
if (linear->in_used > 0) if (linear->in_used > 0)
for (ch = 0 ; ch < linear->channels ; ch++) for (ch = 0 ; ch < linear->channels ; ch++)
linear->last_value [ch] = data->data_in [linear->in_used - linear->channels + ch] ; linear->last_value [ch] = data->data_in [linear->in_used - linear->channels + ch] ;
/* Save current ratio rather then target ratio. */ /* Save current ratio rather then target ratio. */
psrc->last_ratio = src_ratio ; psrc->last_ratio = src_ratio ;
data->input_frames_used = linear->in_used / linear->channels ; data->input_frames_used = linear->in_used / linear->channels ;
data->output_frames_gen = linear->out_gen / linear->channels ; data->output_frames_gen = linear->out_gen / linear->channels ;
return SRC_ERR_NO_ERROR ; return SRC_ERR_NO_ERROR ;
} /* linear_vari_process */ } /* linear_vari_process */
/*------------------------------------------------------------------------------ /*------------------------------------------------------------------------------
@ -151,53 +151,53 @@ linear_vari_process (SRC_PRIVATE *psrc, SRC_DATA *data)
const char* const char*
linear_get_name (int src_enum) linear_get_name (int src_enum)
{ {
if (src_enum == SRC_LINEAR) if (src_enum == SRC_LINEAR)
return "Linear Interpolator" ; return "Linear Interpolator" ;
return NULL ; return NULL ;
} /* linear_get_name */ } /* linear_get_name */
const char* const char*
linear_get_description (int src_enum) linear_get_description (int src_enum)
{ {
if (src_enum == SRC_LINEAR) if (src_enum == SRC_LINEAR)
return "Linear interpolator, very fast, poor quality." ; return "Linear interpolator, very fast, poor quality." ;
return NULL ; return NULL ;
} /* linear_get_descrition */ } /* linear_get_descrition */
int int
linear_set_converter (SRC_PRIVATE *psrc, int src_enum) linear_set_converter (SRC_PRIVATE *psrc, int src_enum)
{ LINEAR_DATA *linear = NULL ; { LINEAR_DATA *linear = NULL ;
if (src_enum != SRC_LINEAR) if (src_enum != SRC_LINEAR)
return SRC_ERR_BAD_CONVERTER ; return SRC_ERR_BAD_CONVERTER ;
if (psrc->private_data != NULL) if (psrc->private_data != NULL)
{ linear = (LINEAR_DATA*) psrc->private_data ; { linear = (LINEAR_DATA*) psrc->private_data ;
if (linear->linear_magic_marker != LINEAR_MAGIC_MARKER) if (linear->linear_magic_marker != LINEAR_MAGIC_MARKER)
{ free (psrc->private_data) ; { free (psrc->private_data) ;
psrc->private_data = NULL ; psrc->private_data = NULL ;
} ; } ;
} ; } ;
if (psrc->private_data == NULL) if (psrc->private_data == NULL)
{ linear = calloc (1, sizeof (*linear) + psrc->channels * sizeof (float)) ; { linear = calloc (1, sizeof (*linear) + psrc->channels * sizeof (float)) ;
if (linear == NULL) if (linear == NULL)
return SRC_ERR_MALLOC_FAILED ; return SRC_ERR_MALLOC_FAILED ;
psrc->private_data = linear ; psrc->private_data = linear ;
} ; } ;
linear->linear_magic_marker = LINEAR_MAGIC_MARKER ; linear->linear_magic_marker = LINEAR_MAGIC_MARKER ;
linear->channels = psrc->channels ; linear->channels = psrc->channels ;
psrc->const_process = linear_vari_process ; psrc->const_process = linear_vari_process ;
psrc->vari_process = linear_vari_process ; psrc->vari_process = linear_vari_process ;
psrc->reset = linear_reset ; psrc->reset = linear_reset ;
linear_reset (psrc) ; linear_reset (psrc) ;
return SRC_ERR_NO_ERROR ; return SRC_ERR_NO_ERROR ;
} /* linear_set_converter */ } /* linear_set_converter */
/*=================================================================================== /*===================================================================================
@ -205,15 +205,15 @@ linear_set_converter (SRC_PRIVATE *psrc, int src_enum)
static void static void
linear_reset (SRC_PRIVATE *psrc) linear_reset (SRC_PRIVATE *psrc)
{ LINEAR_DATA *linear = NULL ; { LINEAR_DATA *linear = NULL ;
linear = (LINEAR_DATA*) psrc->private_data ; linear = (LINEAR_DATA*) psrc->private_data ;
if (linear == NULL) if (linear == NULL)
return ; return ;
linear->channels = psrc->channels ; linear->channels = psrc->channels ;
linear->reset = 1 ; linear->reset = 1 ;
memset (linear->last_value, 0, sizeof (linear->last_value [0]) * linear->channels) ; memset (linear->last_value, 0, sizeof (linear->last_value [0]) * linear->channels) ;
} /* linear_reset */ } /* linear_reset */

View File

@ -19,7 +19,7 @@
/* /*
** This code is part of Secret Rabibt Code aka libsamplerate. A commercial ** This code is part of Secret Rabibt Code aka libsamplerate. A commercial
** use license for this code is available, please see: ** use license for this code is available, please see:
** http://www.mega-nerd.com/SRC/procedure.html ** http://www.mega-nerd.com/SRC/procedure.html
*/ */
#include <stdio.h> #include <stdio.h>
@ -30,22 +30,22 @@
#include "float_cast.h" #include "float_cast.h"
#include "common.h" #include "common.h"
#define SINC_MAGIC_MARKER MAKE_MAGIC (' ', 's', 'i', 'n', 'c', ' ') #define SINC_MAGIC_MARKER MAKE_MAGIC (' ', 's', 'i', 'n', 'c', ' ')
/*======================================================================================== /*========================================================================================
*/ */
#define MAKE_INCREMENT_T(x) ((increment_t) (x)) #define MAKE_INCREMENT_T(x) ((increment_t) (x))
#define SHIFT_BITS 12 #define SHIFT_BITS 12
#define FP_ONE ((double) (((increment_t) 1) << SHIFT_BITS)) #define FP_ONE ((double) (((increment_t) 1) << SHIFT_BITS))
#define INV_FP_ONE (1.0 / FP_ONE) #define INV_FP_ONE (1.0 / FP_ONE)
/*======================================================================================== /*========================================================================================
*/ */
typedef int32_t increment_t ; typedef int32_t increment_t ;
typedef float coeff_t ; typedef float coeff_t ;
#include "fastest_coeffs.h" #include "fastest_coeffs.h"
#ifndef NGC #ifndef NGC
@ -54,20 +54,20 @@ typedef float coeff_t ;
#endif #endif
typedef struct typedef struct
{ int sinc_magic_marker ; { int sinc_magic_marker ;
int channels ; int channels ;
long in_count, in_used ; long in_count, in_used ;
long out_count, out_gen ; long out_count, out_gen ;
int coeff_half_len, index_inc ; int coeff_half_len, index_inc ;
double src_ratio, input_index ; double src_ratio, input_index ;
coeff_t const *coeffs ; coeff_t const *coeffs ;
int b_current, b_end, b_real_end, b_len ; int b_current, b_end, b_real_end, b_len ;
float buffer [1] ; float buffer [1] ;
} SINC_FILTER ; } SINC_FILTER ;
static int sinc_vari_process (SRC_PRIVATE *psrc, SRC_DATA *data) ; static int sinc_vari_process (SRC_PRIVATE *psrc, SRC_DATA *data) ;
@ -80,29 +80,29 @@ static void sinc_reset (SRC_PRIVATE *psrc) ;
static inline increment_t static inline increment_t
double_to_fp (double x) double_to_fp (double x)
{ if (sizeof (increment_t) == 8) { if (sizeof (increment_t) == 8)
return (llrint ((x) * FP_ONE)) ; return (llrint ((x) * FP_ONE)) ;
return (lrint ((x) * FP_ONE)) ; return (lrint ((x) * FP_ONE)) ;
} /* double_to_fp */ } /* double_to_fp */
static inline increment_t static inline increment_t
int_to_fp (int x) int_to_fp (int x)
{ return (((increment_t) (x)) << SHIFT_BITS) ; { return (((increment_t) (x)) << SHIFT_BITS) ;
} /* int_to_fp */ } /* int_to_fp */
static inline int static inline int
fp_to_int (increment_t x) fp_to_int (increment_t x)
{ return (((x) >> SHIFT_BITS)) ; { return (((x) >> SHIFT_BITS)) ;
} /* fp_to_int */ } /* fp_to_int */
static inline increment_t static inline increment_t
fp_fraction_part (increment_t x) fp_fraction_part (increment_t x)
{ return ((x) & ((((increment_t) 1) << SHIFT_BITS) - 1)) ; { return ((x) & ((((increment_t) 1) << SHIFT_BITS) - 1)) ;
} /* fp_fraction_part */ } /* fp_fraction_part */
static inline double static inline double
fp_to_double (increment_t x) fp_to_double (increment_t x)
{ return fp_fraction_part (x) * INV_FP_ONE ; { return fp_fraction_part (x) * INV_FP_ONE ;
} /* fp_to_double */ } /* fp_to_double */
@ -112,245 +112,245 @@ fp_to_double (increment_t x)
const char* const char*
sinc_get_name (int src_enum) sinc_get_name (int src_enum)
{ {
switch (src_enum) switch (src_enum)
{ {
#ifndef NGC #ifndef NGC
case SRC_SINC_BEST_QUALITY : case SRC_SINC_BEST_QUALITY :
return "Best Sinc Interpolator" ; return "Best Sinc Interpolator" ;
case SRC_SINC_MEDIUM_QUALITY : case SRC_SINC_MEDIUM_QUALITY :
return "Medium Sinc Interpolator" ; return "Medium Sinc Interpolator" ;
#endif #endif
case SRC_SINC_FASTEST : case SRC_SINC_FASTEST :
return "Fastest Sinc Interpolator" ; return "Fastest Sinc Interpolator" ;
default: break ; default: break ;
} ; } ;
return NULL ; return NULL ;
} /* sinc_get_descrition */ } /* sinc_get_descrition */
const char* const char*
sinc_get_description (int src_enum) sinc_get_description (int src_enum)
{ {
switch (src_enum) switch (src_enum)
{ {
#ifndef NGC #ifndef NGC
case SRC_SINC_FASTEST : case SRC_SINC_FASTEST :
return "Band limited sinc interpolation, fastest, 97dB SNR, 80% BW." ; return "Band limited sinc interpolation, fastest, 97dB SNR, 80% BW." ;
case SRC_SINC_MEDIUM_QUALITY : case SRC_SINC_MEDIUM_QUALITY :
return "Band limited sinc interpolation, medium quality, 121dB SNR, 90% BW." ; return "Band limited sinc interpolation, medium quality, 121dB SNR, 90% BW." ;
#endif #endif
case SRC_SINC_BEST_QUALITY : case SRC_SINC_BEST_QUALITY :
return "Band limited sinc interpolation, best quality, 145dB SNR, 96% BW." ; return "Band limited sinc interpolation, best quality, 145dB SNR, 96% BW." ;
default : default :
break ; break ;
} ; } ;
return NULL ; return NULL ;
} /* sinc_get_descrition */ } /* sinc_get_descrition */
int int
sinc_set_converter (SRC_PRIVATE *psrc, int src_enum) sinc_set_converter (SRC_PRIVATE *psrc, int src_enum)
{ SINC_FILTER *filter, temp_filter ; { SINC_FILTER *filter, temp_filter ;
increment_t count ; increment_t count ;
int bits ; int bits ;
/* Quick sanity check. */ /* Quick sanity check. */
if (SHIFT_BITS >= sizeof (increment_t) * 8 - 1) if (SHIFT_BITS >= sizeof (increment_t) * 8 - 1)
return SRC_ERR_SHIFT_BITS ; return SRC_ERR_SHIFT_BITS ;
if (psrc->private_data != NULL) if (psrc->private_data != NULL)
{ filter = (SINC_FILTER*) psrc->private_data ; { filter = (SINC_FILTER*) psrc->private_data ;
if (filter->sinc_magic_marker != SINC_MAGIC_MARKER) if (filter->sinc_magic_marker != SINC_MAGIC_MARKER)
{ free (psrc->private_data) ; { free (psrc->private_data) ;
psrc->private_data = NULL ; psrc->private_data = NULL ;
} ; } ;
} ; } ;
memset (&temp_filter, 0, sizeof (temp_filter)) ; memset (&temp_filter, 0, sizeof (temp_filter)) ;
temp_filter.sinc_magic_marker = SINC_MAGIC_MARKER ; temp_filter.sinc_magic_marker = SINC_MAGIC_MARKER ;
temp_filter.channels = psrc->channels ; temp_filter.channels = psrc->channels ;
psrc->const_process = sinc_vari_process ; psrc->const_process = sinc_vari_process ;
psrc->vari_process = sinc_vari_process ; psrc->vari_process = sinc_vari_process ;
psrc->reset = sinc_reset ; psrc->reset = sinc_reset ;
switch (src_enum) switch (src_enum)
{ case SRC_SINC_FASTEST : { case SRC_SINC_FASTEST :
temp_filter.coeffs = fastest_coeffs.coeffs ; temp_filter.coeffs = fastest_coeffs.coeffs ;
temp_filter.coeff_half_len = ARRAY_LEN (fastest_coeffs.coeffs) - 1 ; temp_filter.coeff_half_len = ARRAY_LEN (fastest_coeffs.coeffs) - 1 ;
temp_filter.index_inc = fastest_coeffs.increment ; temp_filter.index_inc = fastest_coeffs.increment ;
break ; break ;
#ifndef NGC #ifndef NGC
case SRC_SINC_MEDIUM_QUALITY : case SRC_SINC_MEDIUM_QUALITY :
temp_filter.coeffs = slow_mid_qual_coeffs.coeffs ; temp_filter.coeffs = slow_mid_qual_coeffs.coeffs ;
temp_filter.coeff_half_len = ARRAY_LEN (slow_mid_qual_coeffs.coeffs) - 1 ; temp_filter.coeff_half_len = ARRAY_LEN (slow_mid_qual_coeffs.coeffs) - 1 ;
temp_filter.index_inc = slow_mid_qual_coeffs.increment ; temp_filter.index_inc = slow_mid_qual_coeffs.increment ;
break ; break ;
case SRC_SINC_BEST_QUALITY : case SRC_SINC_BEST_QUALITY :
temp_filter.coeffs = slow_high_qual_coeffs.coeffs ; temp_filter.coeffs = slow_high_qual_coeffs.coeffs ;
temp_filter.coeff_half_len = ARRAY_LEN (slow_high_qual_coeffs.coeffs) - 1 ; temp_filter.coeff_half_len = ARRAY_LEN (slow_high_qual_coeffs.coeffs) - 1 ;
temp_filter.index_inc = slow_high_qual_coeffs.increment ; temp_filter.index_inc = slow_high_qual_coeffs.increment ;
break ; break ;
#endif #endif
default : default :
return SRC_ERR_BAD_CONVERTER ; return SRC_ERR_BAD_CONVERTER ;
} ; } ;
/* /*
** FIXME : This needs to be looked at more closely to see if there is ** FIXME : This needs to be looked at more closely to see if there is
** a better way. Need to look at prepare_data () at the same time. ** a better way. Need to look at prepare_data () at the same time.
*/ */
temp_filter.b_len = 2 * lrint (1.0 + temp_filter.coeff_half_len / (temp_filter.index_inc * 1.0) * SRC_MAX_RATIO) ; temp_filter.b_len = 2 * lrint (1.0 + temp_filter.coeff_half_len / (temp_filter.index_inc * 1.0) * SRC_MAX_RATIO) ;
temp_filter.b_len = MAX (temp_filter.b_len, 4096) ; temp_filter.b_len = MAX (temp_filter.b_len, 4096) ;
temp_filter.b_len *= temp_filter.channels ; temp_filter.b_len *= temp_filter.channels ;
if ((filter = calloc (1, sizeof (SINC_FILTER) + sizeof (filter->buffer [0]) * (temp_filter.b_len + temp_filter.channels))) == NULL) if ((filter = calloc (1, sizeof (SINC_FILTER) + sizeof (filter->buffer [0]) * (temp_filter.b_len + temp_filter.channels))) == NULL)
return SRC_ERR_MALLOC_FAILED ; return SRC_ERR_MALLOC_FAILED ;
*filter = temp_filter ; *filter = temp_filter ;
memset (&temp_filter, 0xEE, sizeof (temp_filter)) ; memset (&temp_filter, 0xEE, sizeof (temp_filter)) ;
psrc->private_data = filter ; psrc->private_data = filter ;
sinc_reset (psrc) ; sinc_reset (psrc) ;
count = filter->coeff_half_len ; count = filter->coeff_half_len ;
for (bits = 0 ; (MAKE_INCREMENT_T (1) << bits) < count ; bits++) for (bits = 0 ; (MAKE_INCREMENT_T (1) << bits) < count ; bits++)
count |= (MAKE_INCREMENT_T (1) << bits) ; count |= (MAKE_INCREMENT_T (1) << bits) ;
if (bits + SHIFT_BITS - 1 >= (int) (sizeof (increment_t) * 8)) if (bits + SHIFT_BITS - 1 >= (int) (sizeof (increment_t) * 8))
return SRC_ERR_FILTER_LEN ; return SRC_ERR_FILTER_LEN ;
return SRC_ERR_NO_ERROR ; return SRC_ERR_NO_ERROR ;
} /* sinc_set_converter */ } /* sinc_set_converter */
static void static void
sinc_reset (SRC_PRIVATE *psrc) sinc_reset (SRC_PRIVATE *psrc)
{ SINC_FILTER *filter ; { SINC_FILTER *filter ;
filter = (SINC_FILTER*) psrc->private_data ; filter = (SINC_FILTER*) psrc->private_data ;
if (filter == NULL) if (filter == NULL)
return ; return ;
filter->b_current = filter->b_end = 0 ; filter->b_current = filter->b_end = 0 ;
filter->b_real_end = -1 ; filter->b_real_end = -1 ;
filter->src_ratio = filter->input_index = 0.0 ; filter->src_ratio = filter->input_index = 0.0 ;
memset (filter->buffer, 0, filter->b_len * sizeof (filter->buffer [0])) ; memset (filter->buffer, 0, filter->b_len * sizeof (filter->buffer [0])) ;
/* Set this for a sanity check */ /* Set this for a sanity check */
memset (filter->buffer + filter->b_len, 0xAA, filter->channels * sizeof (filter->buffer [0])) ; memset (filter->buffer + filter->b_len, 0xAA, filter->channels * sizeof (filter->buffer [0])) ;
} /* sinc_reset */ } /* sinc_reset */
/*======================================================================================== /*========================================================================================
** Beware all ye who dare pass this point. There be dragons here. ** Beware all ye who dare pass this point. There be dragons here.
*/ */
static int static int
sinc_vari_process (SRC_PRIVATE *psrc, SRC_DATA *data) sinc_vari_process (SRC_PRIVATE *psrc, SRC_DATA *data)
{ SINC_FILTER *filter ; { SINC_FILTER *filter ;
double input_index, src_ratio, count, float_increment, terminate, rem ; double input_index, src_ratio, count, float_increment, terminate, rem ;
increment_t increment, start_filter_index ; increment_t increment, start_filter_index ;
int half_filter_chan_len, samples_in_hand, ch ; int half_filter_chan_len, samples_in_hand, ch ;
if (psrc->private_data == NULL) if (psrc->private_data == NULL)
return SRC_ERR_NO_PRIVATE ; return SRC_ERR_NO_PRIVATE ;
filter = (SINC_FILTER*) psrc->private_data ; filter = (SINC_FILTER*) psrc->private_data ;
/* If there is not a problem, this will be optimised out. */ /* If there is not a problem, this will be optimised out. */
if (sizeof (filter->buffer [0]) != sizeof (data->data_in [0])) if (sizeof (filter->buffer [0]) != sizeof (data->data_in [0]))
return SRC_ERR_SIZE_INCOMPATIBILITY ; return SRC_ERR_SIZE_INCOMPATIBILITY ;
filter->in_count = data->input_frames * filter->channels ; filter->in_count = data->input_frames * filter->channels ;
filter->out_count = data->output_frames * filter->channels ; filter->out_count = data->output_frames * filter->channels ;
filter->in_used = filter->out_gen = 0 ; filter->in_used = filter->out_gen = 0 ;
src_ratio = psrc->last_ratio ; src_ratio = psrc->last_ratio ;
/* Check the sample rate ratio wrt the buffer len. */ /* Check the sample rate ratio wrt the buffer len. */
count = (filter->coeff_half_len + 2.0) / filter->index_inc ; count = (filter->coeff_half_len + 2.0) / filter->index_inc ;
if (MIN (psrc->last_ratio, data->src_ratio) < 1.0) if (MIN (psrc->last_ratio, data->src_ratio) < 1.0)
count /= MIN (psrc->last_ratio, data->src_ratio) ; count /= MIN (psrc->last_ratio, data->src_ratio) ;
/* Maximum coefficientson either side of center point. */ /* Maximum coefficientson either side of center point. */
half_filter_chan_len = filter->channels * (lrint (count) + 1) ; half_filter_chan_len = filter->channels * (lrint (count) + 1) ;
input_index = psrc->last_position ; input_index = psrc->last_position ;
float_increment = filter->index_inc ; float_increment = filter->index_inc ;
rem = fmod_one (input_index) ; rem = fmod_one (input_index) ;
filter->b_current = (filter->b_current + filter->channels * lrint (input_index - rem)) % filter->b_len ; filter->b_current = (filter->b_current + filter->channels * lrint (input_index - rem)) % filter->b_len ;
input_index = rem ; input_index = rem ;
terminate = 1.0 / src_ratio + 1e-20 ; terminate = 1.0 / src_ratio + 1e-20 ;
/* Main processing loop. */ /* Main processing loop. */
while (filter->out_gen < filter->out_count) while (filter->out_gen < filter->out_count)
{ {
/* Need to reload buffer? */ /* Need to reload buffer? */
samples_in_hand = (filter->b_end - filter->b_current + filter->b_len) % filter->b_len ; samples_in_hand = (filter->b_end - filter->b_current + filter->b_len) % filter->b_len ;
if (samples_in_hand <= half_filter_chan_len) if (samples_in_hand <= half_filter_chan_len)
{ prepare_data (filter, data, half_filter_chan_len) ; { prepare_data (filter, data, half_filter_chan_len) ;
samples_in_hand = (filter->b_end - filter->b_current + filter->b_len) % filter->b_len ; samples_in_hand = (filter->b_end - filter->b_current + filter->b_len) % filter->b_len ;
if (samples_in_hand <= half_filter_chan_len) if (samples_in_hand <= half_filter_chan_len)
break ; break ;
} ; } ;
/* This is the termination condition. */ /* This is the termination condition. */
if (filter->b_real_end >= 0) if (filter->b_real_end >= 0)
{ if (filter->b_current + input_index + terminate >= filter->b_real_end) { if (filter->b_current + input_index + terminate >= filter->b_real_end)
break ; break ;
} ; } ;
if (filter->out_count > 0 && fabs (psrc->last_ratio - data->src_ratio) > 1e-10) if (filter->out_count > 0 && fabs (psrc->last_ratio - data->src_ratio) > 1e-10)
src_ratio = psrc->last_ratio + filter->out_gen * (data->src_ratio - psrc->last_ratio) / filter->out_count ; src_ratio = psrc->last_ratio + filter->out_gen * (data->src_ratio - psrc->last_ratio) / filter->out_count ;
float_increment = filter->index_inc * 1.0 ; float_increment = filter->index_inc * 1.0 ;
if (src_ratio < 1.0) if (src_ratio < 1.0)
float_increment = filter->index_inc * src_ratio ; float_increment = filter->index_inc * src_ratio ;
increment = double_to_fp (float_increment) ; increment = double_to_fp (float_increment) ;
start_filter_index = double_to_fp (input_index * float_increment) ; start_filter_index = double_to_fp (input_index * float_increment) ;
for (ch = 0 ; ch < filter->channels ; ch++) for (ch = 0 ; ch < filter->channels ; ch++)
{ data->data_out [filter->out_gen] = (float) ((float_increment / filter->index_inc) * { data->data_out [filter->out_gen] = (float) ((float_increment / filter->index_inc) *
calc_output (filter, increment, start_filter_index, ch)) ; calc_output (filter, increment, start_filter_index, ch)) ;
filter->out_gen ++ ; filter->out_gen ++ ;
} ; } ;
/* Figure out the next index. */ /* Figure out the next index. */
input_index += 1.0 / src_ratio ; input_index += 1.0 / src_ratio ;
rem = fmod_one (input_index) ; rem = fmod_one (input_index) ;
filter->b_current = (filter->b_current + filter->channels * lrint (input_index - rem)) % filter->b_len ; filter->b_current = (filter->b_current + filter->channels * lrint (input_index - rem)) % filter->b_len ;
input_index = rem ; input_index = rem ;
} ; } ;
psrc->last_position = input_index ; psrc->last_position = input_index ;
/* Save current ratio rather then target ratio. */ /* Save current ratio rather then target ratio. */
psrc->last_ratio = src_ratio ; psrc->last_ratio = src_ratio ;
data->input_frames_used = filter->in_used / filter->channels ; data->input_frames_used = filter->in_used / filter->channels ;
data->output_frames_gen = filter->out_gen / filter->channels ; data->output_frames_gen = filter->out_gen / filter->channels ;
return SRC_ERR_NO_ERROR ; return SRC_ERR_NO_ERROR ;
} /* sinc_vari_process */ } /* sinc_vari_process */
/*---------------------------------------------------------------------------------------- /*----------------------------------------------------------------------------------------
@ -358,121 +358,121 @@ sinc_vari_process (SRC_PRIVATE *psrc, SRC_DATA *data)
static void static void
prepare_data (SINC_FILTER *filter, SRC_DATA *data, int half_filter_chan_len) prepare_data (SINC_FILTER *filter, SRC_DATA *data, int half_filter_chan_len)
{ int len = 0 ; { int len = 0 ;
if (filter->b_real_end >= 0) if (filter->b_real_end >= 0)
return ; /* This doesn't make sense, so return. */ return ; /* This doesn't make sense, so return. */
if (filter->b_current == 0) if (filter->b_current == 0)
{ /* Initial state. Set up zeros at the start of the buffer and { /* Initial state. Set up zeros at the start of the buffer and
** then load new data after that. ** then load new data after that.
*/ */
len = filter->b_len - 2 * half_filter_chan_len ; len = filter->b_len - 2 * half_filter_chan_len ;
filter->b_current = filter->b_end = half_filter_chan_len ; filter->b_current = filter->b_end = half_filter_chan_len ;
} }
else if (filter->b_end + half_filter_chan_len + filter->channels < filter->b_len) else if (filter->b_end + half_filter_chan_len + filter->channels < filter->b_len)
{ /* Load data at current end position. */ { /* Load data at current end position. */
len = MAX (filter->b_len - filter->b_current - half_filter_chan_len, 0) ; len = MAX (filter->b_len - filter->b_current - half_filter_chan_len, 0) ;
} }
else else
{ /* Move data at end of buffer back to the start of the buffer. */ { /* Move data at end of buffer back to the start of the buffer. */
len = filter->b_end - filter->b_current ; len = filter->b_end - filter->b_current ;
memmove (filter->buffer, filter->buffer + filter->b_current - half_filter_chan_len, memmove (filter->buffer, filter->buffer + filter->b_current - half_filter_chan_len,
(half_filter_chan_len + len) * sizeof (filter->buffer [0])) ; (half_filter_chan_len + len) * sizeof (filter->buffer [0])) ;
filter->b_current = half_filter_chan_len ; filter->b_current = half_filter_chan_len ;
filter->b_end = filter->b_current + len ; filter->b_end = filter->b_current + len ;
/* Now load data at current end of buffer. */ /* Now load data at current end of buffer. */
len = MAX (filter->b_len - filter->b_current - half_filter_chan_len, 0) ; len = MAX (filter->b_len - filter->b_current - half_filter_chan_len, 0) ;
} ; } ;
len = MIN (filter->in_count - filter->in_used, len) ; len = MIN (filter->in_count - filter->in_used, len) ;
len -= (len % filter->channels) ; len -= (len % filter->channels) ;
memcpy (filter->buffer + filter->b_end, data->data_in + filter->in_used, memcpy (filter->buffer + filter->b_end, data->data_in + filter->in_used,
len * sizeof (filter->buffer [0])) ; len * sizeof (filter->buffer [0])) ;
filter->b_end += len ; filter->b_end += len ;
filter->in_used += len ; filter->in_used += len ;
if (filter->in_used == filter->in_count && if (filter->in_used == filter->in_count &&
filter->b_end - filter->b_current < 2 * half_filter_chan_len && data->end_of_input) filter->b_end - filter->b_current < 2 * half_filter_chan_len && data->end_of_input)
{ /* Handle the case where all data in the current buffer has been { /* Handle the case where all data in the current buffer has been
** consumed and this is the last buffer. ** consumed and this is the last buffer.
*/ */
if (filter->b_len - filter->b_end < half_filter_chan_len + 5) if (filter->b_len - filter->b_end < half_filter_chan_len + 5)
{ /* If necessary, move data down to the start of the buffer. */ { /* If necessary, move data down to the start of the buffer. */
len = filter->b_end - filter->b_current ; len = filter->b_end - filter->b_current ;
memmove (filter->buffer, filter->buffer + filter->b_current - half_filter_chan_len, memmove (filter->buffer, filter->buffer + filter->b_current - half_filter_chan_len,
(half_filter_chan_len + len) * sizeof (filter->buffer [0])) ; (half_filter_chan_len + len) * sizeof (filter->buffer [0])) ;
filter->b_current = half_filter_chan_len ; filter->b_current = half_filter_chan_len ;
filter->b_end = filter->b_current + len ; filter->b_end = filter->b_current + len ;
} ; } ;
filter->b_real_end = filter->b_end ; filter->b_real_end = filter->b_end ;
len = half_filter_chan_len + 5 ; len = half_filter_chan_len + 5 ;
memset (filter->buffer + filter->b_end, 0, len * sizeof (filter->buffer [0])) ; memset (filter->buffer + filter->b_end, 0, len * sizeof (filter->buffer [0])) ;
filter->b_end += len ; filter->b_end += len ;
} ; } ;
return ; return ;
} /* prepare_data */ } /* prepare_data */
static double static double
calc_output (SINC_FILTER *filter, increment_t increment, increment_t start_filter_index, int ch) calc_output (SINC_FILTER *filter, increment_t increment, increment_t start_filter_index, int ch)
{ double fraction, left, right, icoeff ; { double fraction, left, right, icoeff ;
increment_t filter_index, max_filter_index ; increment_t filter_index, max_filter_index ;
int data_index, coeff_count, indx ; int data_index, coeff_count, indx ;
/* Convert input parameters into fixed point. */ /* Convert input parameters into fixed point. */
max_filter_index = int_to_fp (filter->coeff_half_len) ; max_filter_index = int_to_fp (filter->coeff_half_len) ;
/* First apply the left half of the filter. */ /* First apply the left half of the filter. */
filter_index = start_filter_index ; filter_index = start_filter_index ;
coeff_count = (max_filter_index - filter_index) / increment ; coeff_count = (max_filter_index - filter_index) / increment ;
filter_index = filter_index + coeff_count * increment ; filter_index = filter_index + coeff_count * increment ;
data_index = filter->b_current - filter->channels * coeff_count + ch ; data_index = filter->b_current - filter->channels * coeff_count + ch ;
left = 0.0 ; left = 0.0 ;
do do
{ fraction = fp_to_double (filter_index) ; { fraction = fp_to_double (filter_index) ;
indx = fp_to_int (filter_index) ; indx = fp_to_int (filter_index) ;
icoeff = filter->coeffs [indx] + fraction * (filter->coeffs [indx + 1] - filter->coeffs [indx]) ; icoeff = filter->coeffs [indx] + fraction * (filter->coeffs [indx + 1] - filter->coeffs [indx]) ;
left += icoeff * filter->buffer [data_index] ; left += icoeff * filter->buffer [data_index] ;
filter_index -= increment ; filter_index -= increment ;
data_index = data_index + filter->channels ; data_index = data_index + filter->channels ;
} }
while (filter_index >= MAKE_INCREMENT_T (0)) ; while (filter_index >= MAKE_INCREMENT_T (0)) ;
/* Now apply the right half of the filter. */ /* Now apply the right half of the filter. */
filter_index = increment - start_filter_index ; filter_index = increment - start_filter_index ;
coeff_count = (max_filter_index - filter_index) / increment ; coeff_count = (max_filter_index - filter_index) / increment ;
filter_index = filter_index + coeff_count * increment ; filter_index = filter_index + coeff_count * increment ;
data_index = filter->b_current + filter->channels * (1 + coeff_count) + ch ; data_index = filter->b_current + filter->channels * (1 + coeff_count) + ch ;
right = 0.0 ; right = 0.0 ;
do do
{ fraction = fp_to_double (filter_index) ; { fraction = fp_to_double (filter_index) ;
indx = fp_to_int (filter_index) ; indx = fp_to_int (filter_index) ;
icoeff = filter->coeffs [indx] + fraction * (filter->coeffs [indx + 1] - filter->coeffs [indx]) ; icoeff = filter->coeffs [indx] + fraction * (filter->coeffs [indx + 1] - filter->coeffs [indx]) ;
right += icoeff * filter->buffer [data_index] ; right += icoeff * filter->buffer [data_index] ;
filter_index -= increment ; filter_index -= increment ;
data_index = data_index - filter->channels ; data_index = data_index - filter->channels ;
} }
while (filter_index > MAKE_INCREMENT_T (0)) ; while (filter_index > MAKE_INCREMENT_T (0)) ;
return (left + right) ; return (left + right) ;
} /* calc_output */ } /* calc_output */

View File

@ -19,7 +19,7 @@
/* /*
** This code is part of Secret Rabibt Code aka libsamplerate. A commercial ** This code is part of Secret Rabibt Code aka libsamplerate. A commercial
** use license for this code is available, please see: ** use license for this code is available, please see:
** http://www.mega-nerd.com/SRC/procedure.html ** http://www.mega-nerd.com/SRC/procedure.html
*/ */
#include <stdio.h> #include <stdio.h>
@ -36,15 +36,15 @@ static void zoh_reset (SRC_PRIVATE *psrc) ;
/*======================================================================================== /*========================================================================================
*/ */
#define ZOH_MAGIC_MARKER MAKE_MAGIC ('s', 'r', 'c', 'z', 'o', 'h') #define ZOH_MAGIC_MARKER MAKE_MAGIC ('s', 'r', 'c', 'z', 'o', 'h')
typedef struct typedef struct
{ int zoh_magic_marker ; { int zoh_magic_marker ;
int channels ; int channels ;
int reset ; int reset ;
long in_count, in_used ; long in_count, in_used ;
long out_count, out_gen ; long out_count, out_gen ;
float last_value [1] ; float last_value [1] ;
} ZOH_DATA ; } ZOH_DATA ;
/*---------------------------------------------------------------------------------------- /*----------------------------------------------------------------------------------------
@ -52,88 +52,88 @@ typedef struct
static int static int
zoh_vari_process (SRC_PRIVATE *psrc, SRC_DATA *data) zoh_vari_process (SRC_PRIVATE *psrc, SRC_DATA *data)
{ ZOH_DATA *zoh ; { ZOH_DATA *zoh ;
double src_ratio, input_index, rem ; double src_ratio, input_index, rem ;
int ch ; int ch ;
if (psrc->private_data == NULL) if (psrc->private_data == NULL)
return SRC_ERR_NO_PRIVATE ; return SRC_ERR_NO_PRIVATE ;
zoh = (ZOH_DATA*) psrc->private_data ; zoh = (ZOH_DATA*) psrc->private_data ;
if (zoh->reset) if (zoh->reset)
{ /* If we have just been reset, set the last_value data. */ { /* If we have just been reset, set the last_value data. */
for (ch = 0 ; ch < zoh->channels ; ch++) for (ch = 0 ; ch < zoh->channels ; ch++)
zoh->last_value [ch] = data->data_in [ch] ; zoh->last_value [ch] = data->data_in [ch] ;
zoh->reset = 0 ; zoh->reset = 0 ;
} ; } ;
zoh->in_count = data->input_frames * zoh->channels ; zoh->in_count = data->input_frames * zoh->channels ;
zoh->out_count = data->output_frames * zoh->channels ; zoh->out_count = data->output_frames * zoh->channels ;
zoh->in_used = zoh->out_gen = 0 ; zoh->in_used = zoh->out_gen = 0 ;
src_ratio = psrc->last_ratio ; src_ratio = psrc->last_ratio ;
input_index = psrc->last_position ; input_index = psrc->last_position ;
/* Calculate samples before first sample in input array. */ /* Calculate samples before first sample in input array. */
while (input_index < 1.0 && zoh->out_gen < zoh->out_count) while (input_index < 1.0 && zoh->out_gen < zoh->out_count)
{ {
if (zoh->in_used + zoh->channels * input_index >= zoh->in_count) if (zoh->in_used + zoh->channels * input_index >= zoh->in_count)
break ; break ;
if (zoh->out_count > 0 && fabs (psrc->last_ratio - data->src_ratio) > SRC_MIN_RATIO_DIFF) if (zoh->out_count > 0 && fabs (psrc->last_ratio - data->src_ratio) > SRC_MIN_RATIO_DIFF)
src_ratio = psrc->last_ratio + zoh->out_gen * (data->src_ratio - psrc->last_ratio) / zoh->out_count ; src_ratio = psrc->last_ratio + zoh->out_gen * (data->src_ratio - psrc->last_ratio) / zoh->out_count ;
for (ch = 0 ; ch < zoh->channels ; ch++) for (ch = 0 ; ch < zoh->channels ; ch++)
{ data->data_out [zoh->out_gen] = zoh->last_value [ch] ; { data->data_out [zoh->out_gen] = zoh->last_value [ch] ;
zoh->out_gen ++ ; zoh->out_gen ++ ;
} ; } ;
/* Figure out the next index. */ /* Figure out the next index. */
input_index += 1.0 / src_ratio ; input_index += 1.0 / src_ratio ;
} ; } ;
rem = fmod_one (input_index) ; rem = fmod_one (input_index) ;
zoh->in_used += zoh->channels * lrint (input_index - rem) ; zoh->in_used += zoh->channels * lrint (input_index - rem) ;
input_index = rem ; input_index = rem ;
/* Main processing loop. */ /* Main processing loop. */
while (zoh->out_gen < zoh->out_count && zoh->in_used + zoh->channels * input_index <= zoh->in_count) while (zoh->out_gen < zoh->out_count && zoh->in_used + zoh->channels * input_index <= zoh->in_count)
{ {
if (zoh->out_count > 0 && fabs (psrc->last_ratio - data->src_ratio) > SRC_MIN_RATIO_DIFF) if (zoh->out_count > 0 && fabs (psrc->last_ratio - data->src_ratio) > SRC_MIN_RATIO_DIFF)
src_ratio = psrc->last_ratio + zoh->out_gen * (data->src_ratio - psrc->last_ratio) / zoh->out_count ; src_ratio = psrc->last_ratio + zoh->out_gen * (data->src_ratio - psrc->last_ratio) / zoh->out_count ;
for (ch = 0 ; ch < zoh->channels ; ch++) for (ch = 0 ; ch < zoh->channels ; ch++)
{ data->data_out [zoh->out_gen] = data->data_in [zoh->in_used - zoh->channels + ch] ; { data->data_out [zoh->out_gen] = data->data_in [zoh->in_used - zoh->channels + ch] ;
zoh->out_gen ++ ; zoh->out_gen ++ ;
} ; } ;
/* Figure out the next index. */ /* Figure out the next index. */
input_index += 1.0 / src_ratio ; input_index += 1.0 / src_ratio ;
rem = fmod_one (input_index) ; rem = fmod_one (input_index) ;
zoh->in_used += zoh->channels * lrint (input_index - rem) ; zoh->in_used += zoh->channels * lrint (input_index - rem) ;
input_index = rem ; input_index = rem ;
} ; } ;
if (zoh->in_used > zoh->in_count) if (zoh->in_used > zoh->in_count)
{ input_index += (zoh->in_used - zoh->in_count) / zoh->channels ; { input_index += (zoh->in_used - zoh->in_count) / zoh->channels ;
zoh->in_used = zoh->in_count ; zoh->in_used = zoh->in_count ;
} ; } ;
psrc->last_position = input_index ; psrc->last_position = input_index ;
if (zoh->in_used > 0) if (zoh->in_used > 0)
for (ch = 0 ; ch < zoh->channels ; ch++) for (ch = 0 ; ch < zoh->channels ; ch++)
zoh->last_value [ch] = data->data_in [zoh->in_used - zoh->channels + ch] ; zoh->last_value [ch] = data->data_in [zoh->in_used - zoh->channels + ch] ;
/* Save current ratio rather then target ratio. */ /* Save current ratio rather then target ratio. */
psrc->last_ratio = src_ratio ; psrc->last_ratio = src_ratio ;
data->input_frames_used = zoh->in_used / zoh->channels ; data->input_frames_used = zoh->in_used / zoh->channels ;
data->output_frames_gen = zoh->out_gen / zoh->channels ; data->output_frames_gen = zoh->out_gen / zoh->channels ;
return SRC_ERR_NO_ERROR ; return SRC_ERR_NO_ERROR ;
} /* zoh_vari_process */ } /* zoh_vari_process */
/*------------------------------------------------------------------------------ /*------------------------------------------------------------------------------
@ -142,53 +142,53 @@ zoh_vari_process (SRC_PRIVATE *psrc, SRC_DATA *data)
const char* const char*
zoh_get_name (int src_enum) zoh_get_name (int src_enum)
{ {
if (src_enum == SRC_ZERO_ORDER_HOLD) if (src_enum == SRC_ZERO_ORDER_HOLD)
return "ZOH Interpolator" ; return "ZOH Interpolator" ;
return NULL ; return NULL ;
} /* zoh_get_name */ } /* zoh_get_name */
const char* const char*
zoh_get_description (int src_enum) zoh_get_description (int src_enum)
{ {
if (src_enum == SRC_ZERO_ORDER_HOLD) if (src_enum == SRC_ZERO_ORDER_HOLD)
return "Zero order hold interpolator, very fast, poor quality." ; return "Zero order hold interpolator, very fast, poor quality." ;
return NULL ; return NULL ;
} /* zoh_get_descrition */ } /* zoh_get_descrition */
int int
zoh_set_converter (SRC_PRIVATE *psrc, int src_enum) zoh_set_converter (SRC_PRIVATE *psrc, int src_enum)
{ ZOH_DATA *zoh = NULL ; { ZOH_DATA *zoh = NULL ;
if (src_enum != SRC_ZERO_ORDER_HOLD) if (src_enum != SRC_ZERO_ORDER_HOLD)
return SRC_ERR_BAD_CONVERTER ; return SRC_ERR_BAD_CONVERTER ;
if (psrc->private_data != NULL) if (psrc->private_data != NULL)
{ zoh = (ZOH_DATA*) psrc->private_data ; { zoh = (ZOH_DATA*) psrc->private_data ;
if (zoh->zoh_magic_marker != ZOH_MAGIC_MARKER) if (zoh->zoh_magic_marker != ZOH_MAGIC_MARKER)
{ free (psrc->private_data) ; { free (psrc->private_data) ;
psrc->private_data = NULL ; psrc->private_data = NULL ;
} ; } ;
} ; } ;
if (psrc->private_data == NULL) if (psrc->private_data == NULL)
{ zoh = calloc (1, sizeof (*zoh) + psrc->channels * sizeof (float)) ; { zoh = calloc (1, sizeof (*zoh) + psrc->channels * sizeof (float)) ;
if (zoh == NULL) if (zoh == NULL)
return SRC_ERR_MALLOC_FAILED ; return SRC_ERR_MALLOC_FAILED ;
psrc->private_data = zoh ; psrc->private_data = zoh ;
} ; } ;
zoh->zoh_magic_marker = ZOH_MAGIC_MARKER ; zoh->zoh_magic_marker = ZOH_MAGIC_MARKER ;
zoh->channels = psrc->channels ; zoh->channels = psrc->channels ;
psrc->const_process = zoh_vari_process ; psrc->const_process = zoh_vari_process ;
psrc->vari_process = zoh_vari_process ; psrc->vari_process = zoh_vari_process ;
psrc->reset = zoh_reset ; psrc->reset = zoh_reset ;
zoh_reset (psrc) ; zoh_reset (psrc) ;
return SRC_ERR_NO_ERROR ; return SRC_ERR_NO_ERROR ;
} /* zoh_set_converter */ } /* zoh_set_converter */
/*=================================================================================== /*===================================================================================
@ -196,16 +196,16 @@ zoh_set_converter (SRC_PRIVATE *psrc, int src_enum)
static void static void
zoh_reset (SRC_PRIVATE *psrc) zoh_reset (SRC_PRIVATE *psrc)
{ ZOH_DATA *zoh ; { ZOH_DATA *zoh ;
zoh = (ZOH_DATA*) psrc->private_data ; zoh = (ZOH_DATA*) psrc->private_data ;
if (zoh == NULL) if (zoh == NULL)
return ; return ;
zoh->channels = psrc->channels ; zoh->channels = psrc->channels ;
zoh->reset = 1 ; zoh->reset = 1 ;
memset (zoh->last_value, 0, sizeof (zoh->last_value [0]) * zoh->channels) ; memset (zoh->last_value, 0, sizeof (zoh->last_value [0]) * zoh->channels) ;
return ; return ;
} /* zoh_reset */ } /* zoh_reset */

File diff suppressed because it is too large Load Diff

View File

@ -37,7 +37,7 @@ static const int PSGVolumeValues[2][16] = {
/* These values are taken from a real SMS2's output */ /* These values are taken from a real SMS2's output */
{892,892,892,760,623,497,404,323,257,198,159,123,96,75,60,0}, /* I can't remember why 892... :P some scaling I did at some point */ {892,892,892,760,623,497,404,323,257,198,159,123,96,75,60,0}, /* I can't remember why 892... :P some scaling I did at some point */
/* these values are true volumes for 2dB drops at each step (multiply previous by 10^-0.1), normalised at 760 */ /* these values are true volumes for 2dB drops at each step (multiply previous by 10^-0.1), normalised at 760 */
{1516,1205,957,760,603,479,381,303,240,191,152,120,96,76,60,0} {1516,1205,957,760,603,479,381,303,240,191,152,120,96,76,60,0}
}; };
static SN76489_Context SN76489[MAX_SN76489]; static SN76489_Context SN76489[MAX_SN76489];
@ -126,33 +126,33 @@ void SN76489_Write(int which, int data)
{ {
SN76489_Context *p = &SN76489[which]; SN76489_Context *p = &SN76489[which];
if (data&0x80) { if (data&0x80) {
/* Latch/data byte %1 cc t dddd */ /* Latch/data byte %1 cc t dddd */
p->LatchedRegister=((data>>4)&0x07); p->LatchedRegister=((data>>4)&0x07);
p->Registers[p->LatchedRegister]= p->Registers[p->LatchedRegister]=
(p->Registers[p->LatchedRegister] & 0x3f0) /* zero low 4 bits */ (p->Registers[p->LatchedRegister] & 0x3f0) /* zero low 4 bits */
| (data&0xf); /* and replace with data */ | (data&0xf); /* and replace with data */
} else { } else {
/* Data byte %0 - dddddd */ /* Data byte %0 - dddddd */
if (!(p->LatchedRegister%2)&&(p->LatchedRegister<5)) if (!(p->LatchedRegister%2)&&(p->LatchedRegister<5))
/* Tone register */ /* Tone register */
p->Registers[p->LatchedRegister]= p->Registers[p->LatchedRegister]=
(p->Registers[p->LatchedRegister] & 0x00f) /* zero high 6 bits */ (p->Registers[p->LatchedRegister] & 0x00f) /* zero high 6 bits */
| ((data&0x3f)<<4); /* and replace with data */ | ((data&0x3f)<<4); /* and replace with data */
else else
/* Other register */ /* Other register */
p->Registers[p->LatchedRegister]=data&0x0f; /* Replace with data */ p->Registers[p->LatchedRegister]=data&0x0f; /* Replace with data */
} }
switch (p->LatchedRegister) { switch (p->LatchedRegister) {
case 0: case 0:
case 2: case 2:
case 4: /* Tone channels */ case 4: /* Tone channels */
if (p->Registers[p->LatchedRegister]==0) p->Registers[p->LatchedRegister]=1; /* Zero frequency changed to 1 to avoid div/0 */ if (p->Registers[p->LatchedRegister]==0) p->Registers[p->LatchedRegister]=1; /* Zero frequency changed to 1 to avoid div/0 */
break; break;
case 6: /* Noise */ case 6: /* Noise */
p->NoiseShiftRegister=NoiseInitialState; /* reset shift register */ p->NoiseShiftRegister=NoiseInitialState; /* reset shift register */
p->NoiseFreq=0x10<<(p->Registers[6]&0x3); /* set noise signal generator frequency */ p->NoiseFreq=0x10<<(p->Registers[6]&0x3); /* set noise signal generator frequency */
break; break;
} }
} }

View File

@ -48,56 +48,56 @@ int fm_reg[2][0x100];
/* return the number of samples that should have been rendered so far */ /* return the number of samples that should have been rendered so far */
static inline uint32 fm_sample_cnt(uint8 is_z80) static inline uint32 fm_sample_cnt(uint8 is_z80)
{ {
if (is_z80) return (uint32) ((double)(count_z80 + current_z80 - z80_ICount) / z80cycles_per_sample[0]); if (is_z80) return (uint32) ((double)(count_z80 + current_z80 - z80_ICount) / z80cycles_per_sample[0]);
else return (uint32) ((double) count_m68k / m68cycles_per_sample[0]); else return (uint32) ((double) count_m68k / m68cycles_per_sample[0]);
} }
static inline uint32 psg_sample_cnt(uint8 is_z80) static inline uint32 psg_sample_cnt(uint8 is_z80)
{ {
if (is_z80) return (uint32) ((double)(count_z80 + current_z80 - z80_ICount) / z80cycles_per_sample[1]); if (is_z80) return (uint32) ((double)(count_z80 + current_z80 - z80_ICount) / z80cycles_per_sample[1]);
else return (uint32) ((double) count_m68k / m68cycles_per_sample[1]); else return (uint32) ((double) count_m68k / m68cycles_per_sample[1]);
} }
/* update FM samples */ /* update FM samples */
static inline void fm_update() static inline void fm_update()
{ {
if(snd.fm.curStage - snd.fm.lastStage > 0) if(snd.fm.curStage - snd.fm.lastStage > 0)
{ {
int *tempBuffer[2]; int *tempBuffer[2];
if (config.hq_fm && !config.fm_core) if (config.hq_fm && !config.fm_core)
{ {
tempBuffer[0] = src_buffer[0] + snd.fm.lastStage; tempBuffer[0] = src_buffer[0] + snd.fm.lastStage;
tempBuffer[1] = src_buffer[1] + snd.fm.lastStage; tempBuffer[1] = src_buffer[1] + snd.fm.lastStage;
} }
else else
{ {
tempBuffer[0] = snd.fm.buffer[0] + snd.fm.lastStage; tempBuffer[0] = snd.fm.buffer[0] + snd.fm.lastStage;
tempBuffer[1] = snd.fm.buffer[1] + snd.fm.lastStage; tempBuffer[1] = snd.fm.buffer[1] + snd.fm.lastStage;
} }
_YM2612_Update(tempBuffer, snd.fm.curStage - snd.fm.lastStage); _YM2612_Update(tempBuffer, snd.fm.curStage - snd.fm.lastStage);
snd.fm.lastStage = snd.fm.curStage; snd.fm.lastStage = snd.fm.curStage;
} }
} }
/* update PSG samples */ /* update PSG samples */
static inline void psg_update() static inline void psg_update()
{ {
if(snd.psg.curStage - snd.psg.lastStage > 0) if(snd.psg.curStage - snd.psg.lastStage > 0)
{ {
int16 *tempBuffer = snd.psg.buffer + snd.psg.lastStage; int16 *tempBuffer = snd.psg.buffer + snd.psg.lastStage;
SN76489_Update (0, tempBuffer, snd.psg.curStage - snd.psg.lastStage); SN76489_Update (0, tempBuffer, snd.psg.curStage - snd.psg.lastStage);
snd.psg.lastStage = snd.psg.curStage; snd.psg.lastStage = snd.psg.curStage;
} }
} }
void sound_init(int rate) void sound_init(int rate)
{ {
double vclk = (vdp_pal ? (double)CLOCK_PAL : (double)CLOCK_NTSC) / 7.0; /* 68000 and YM2612 clock */ double vclk = (vdp_pal ? (double)CLOCK_PAL : (double)CLOCK_NTSC) / 7.0; /* 68000 and YM2612 clock */
double zclk = (vdp_pal ? (double)CLOCK_PAL : (double)CLOCK_NTSC) / 15.0; /* Z80 and SN76489 clock */ double zclk = (vdp_pal ? (double)CLOCK_PAL : (double)CLOCK_NTSC) / 15.0; /* Z80 and SN76489 clock */
/* cycle-accurate FM samples */ /* cycle-accurate FM samples */
if (config.hq_fm && !config.fm_core) if (config.hq_fm && !config.fm_core)
{ {
m68cycles_per_sample[0] = 144.0; m68cycles_per_sample[0] = 144.0;
@ -113,44 +113,44 @@ void sound_init(int rate)
else else
{ {
m68cycles_per_sample[0] = ((double)m68cycles_per_line * (double)lines_per_frame) / (double) (rate / vdp_rate); m68cycles_per_sample[0] = ((double)m68cycles_per_line * (double)lines_per_frame) / (double) (rate / vdp_rate);
z80cycles_per_sample[0] = ((double)z80cycles_per_line * (double)lines_per_frame) / (double) (rate / vdp_rate); z80cycles_per_sample[0] = ((double)z80cycles_per_line * (double)lines_per_frame) / (double) (rate / vdp_rate);
} }
/* cycle-accurate PSG samples */ /* cycle-accurate PSG samples */
m68cycles_per_sample[1] = ((double)m68cycles_per_line * (double)lines_per_frame) / (double) (rate / vdp_rate); m68cycles_per_sample[1] = ((double)m68cycles_per_line * (double)lines_per_frame) / (double) (rate / vdp_rate);
z80cycles_per_sample[1] = ((double)z80cycles_per_line * (double)lines_per_frame) / (double) (rate / vdp_rate); z80cycles_per_sample[1] = ((double)z80cycles_per_line * (double)lines_per_frame) / (double) (rate / vdp_rate);
/* initialize sound chips */ /* initialize sound chips */
SN76489_Init(0, (int)zclk, rate); SN76489_Init(0, (int)zclk, rate);
SN76489_Config(0, MUTE_ALLON, VOL_FULL, FB_SEGAVDP, SRW_SEGAVDP, 0); SN76489_Config(0, MUTE_ALLON, VOL_FULL, FB_SEGAVDP, SRW_SEGAVDP, 0);
if (config.fm_core) if (config.fm_core)
{ {
_YM2612_Write = YM2612_Write; _YM2612_Write = YM2612_Write;
_YM2612_Read = YM2612_Read; _YM2612_Read = YM2612_Read;
_YM2612_Update = YM2612_Update; _YM2612_Update = YM2612_Update;
_YM2612_Reset = YM2612_Reset; _YM2612_Reset = YM2612_Reset;
YM2612_Init((int)vclk, rate, config.hq_fm); YM2612_Init((int)vclk, rate, config.hq_fm);
} }
else else
{ {
_YM2612_Write = YM2612Write; _YM2612_Write = YM2612Write;
_YM2612_Read = YM2612Read; _YM2612_Read = YM2612Read;
_YM2612_Update = YM2612UpdateOne; _YM2612_Update = YM2612UpdateOne;
_YM2612_Reset = YM2612ResetChip; _YM2612_Reset = YM2612ResetChip;
YM2612Init ((int)vclk, rate); YM2612Init ((int)vclk, rate);
} }
} }
void sound_update(void) void sound_update(void)
{ {
/* finalize sound buffers */ /* finalize sound buffers */
snd.fm.curStage = (config.hq_fm && !config.fm_core) ? src_data.input_frames : snd.buffer_size; snd.fm.curStage = (config.hq_fm && !config.fm_core) ? src_data.input_frames : snd.buffer_size;
snd.psg.curStage = snd.buffer_size; snd.psg.curStage = snd.buffer_size;
/* update last samples (if needed) */ /* update last samples (if needed) */
fm_update(); fm_update();
psg_update(); psg_update();
/* Resampling */ /* Resampling */
if (config.hq_fm && !config.fm_core) if (config.hq_fm && !config.fm_core)
@ -158,18 +158,18 @@ void sound_update(void)
double scaled_value ; double scaled_value ;
int len = src_data.input_frames; int len = src_data.input_frames;
/* this is basically libsamplerate "src_int_to_float_array" function, adapted to interlace samples */ /* this is basically libsamplerate "src_int_to_float_array" function, adapted to interlace samples */
while (len) while (len)
{ {
len -- ; len -- ;
src_in[len*2] = (float) (src_buffer[0] [len] / (8.0 * 0x10000000)); src_in[len*2] = (float) (src_buffer[0] [len] / (8.0 * 0x10000000));
src_in[len*2 + 1] = (float) (src_buffer[1] [len] / (8.0 * 0x10000000)); src_in[len*2 + 1] = (float) (src_buffer[1] [len] / (8.0 * 0x10000000));
} }
/* samplerate conversion */ /* samplerate conversion */
src_simple (&src_data, (config.hq_fm&1) ? SRC_LINEAR : SRC_SINC_FASTEST, 2); src_simple (&src_data, (config.hq_fm&1) ? SRC_LINEAR : SRC_SINC_FASTEST, 2);
/* this is basically libsamplerate "src_float_to_int_array" function, adapted to interlace samples */ /* this is basically libsamplerate "src_float_to_int_array" function, adapted to interlace samples */
len = snd.buffer_size; len = snd.buffer_size;
while (len) while (len)
{ {
@ -194,28 +194,28 @@ void sound_update(void)
} }
/* reset samples count */ /* reset samples count */
snd.fm.curStage = 0; snd.fm.curStage = 0;
snd.fm.lastStage = 0; snd.fm.lastStage = 0;
snd.psg.curStage = 0; snd.psg.curStage = 0;
snd.psg.lastStage = 0; snd.psg.lastStage = 0;
} }
/* YM2612 control */ /* YM2612 control */
/* restore FM registers */ /* restore FM registers */
void fm_restore(void) void fm_restore(void)
{ {
int i; int i;
_YM2612_Reset(); _YM2612_Reset();
/* feed all the registers and update internal state */ /* feed all the registers and update internal state */
for(i = 0; i < 0x100; i++) for(i = 0; i < 0x100; i++)
{ {
_YM2612_Write(0, i); _YM2612_Write(0, i);
_YM2612_Write(1, fm_reg[0][i]); _YM2612_Write(1, fm_reg[0][i]);
_YM2612_Write(2, i); _YM2612_Write(2, i);
_YM2612_Write(3, fm_reg[1][i]); _YM2612_Write(3, fm_reg[1][i]);
} }
} }
/* write FM chip */ /* write FM chip */
@ -224,7 +224,7 @@ void fm_write(unsigned int cpu, unsigned int address, unsigned int data)
if (address & 1) if (address & 1)
{ {
snd.fm.curStage = fm_sample_cnt(cpu); snd.fm.curStage = fm_sample_cnt(cpu);
fm_update(); fm_update();
} }
_YM2612_Write(address & 3, data); _YM2612_Write(address & 3, data);
} }
@ -232,16 +232,16 @@ void fm_write(unsigned int cpu, unsigned int address, unsigned int data)
/* read FM status */ /* read FM status */
unsigned int fm_read(unsigned int cpu, unsigned int address) unsigned int fm_read(unsigned int cpu, unsigned int address)
{ {
snd.fm.curStage = fm_sample_cnt(cpu); snd.fm.curStage = fm_sample_cnt(cpu);
fm_update(); fm_update();
return (_YM2612_Read() & 0xff); return (_YM2612_Read() & 0xff);
} }
/* PSG write */ /* PSG write */
void psg_write(unsigned int cpu, unsigned int data) void psg_write(unsigned int cpu, unsigned int data)
{ {
snd.psg.curStage = psg_sample_cnt(cpu); snd.psg.curStage = psg_sample_cnt(cpu);
psg_update(); psg_update();
SN76489_Write(0, data); SN76489_Write(0, data);
} }

File diff suppressed because it is too large Load Diff

View File

@ -14,93 +14,93 @@
#define _YM2612_H_ #define _YM2612_H_
// Change it if you need to do long update // Change it if you need to do long update
#define MAX_UPDATE_LENGHT 2000 #define MAX_UPDATE_LENGHT 2000
// Gens always uses 16 bits sound (in 32 bits buffer) and do the convertion later if needed. // Gens always uses 16 bits sound (in 32 bits buffer) and do the convertion later if needed.
#define OUTPUT_BITS 16 #define OUTPUT_BITS 16
typedef struct slot__ { typedef struct slot__ {
int *DT; // paramètre detune int *DT; // paramètre detune
int MUL; // paramètre "multiple de fréquence" int MUL; // paramètre "multiple de fréquence"
int TL; // Total Level = volume lorsque l'enveloppe est au plus haut int TL; // Total Level = volume lorsque l'enveloppe est au plus haut
int TLL; // Total Level ajusted int TLL; // Total Level ajusted
int SLL; // Sustin Level (ajusted) = volume où l'enveloppe termine sa première phase de régression int SLL; // Sustin Level (ajusted) = volume où l'enveloppe termine sa première phase de régression
int KSR_S; // Key Scale Rate Shift = facteur de prise en compte du KSL dans la variations de l'enveloppe int KSR_S; // Key Scale Rate Shift = facteur de prise en compte du KSL dans la variations de l'enveloppe
int KSR; // Key Scale Rate = cette valeur est calculée par rapport à la fréquence actuelle, elle va influer int KSR; // Key Scale Rate = cette valeur est calculée par rapport à la fréquence actuelle, elle va influer
// sur les différents paramètres de l'enveloppe comme l'attaque, le decay ... comme dans la réalité ! // sur les différents paramètres de l'enveloppe comme l'attaque, le decay ... comme dans la réalité !
int SEG; // Type enveloppe SSG int SEG; // Type enveloppe SSG
int *AR; // Attack Rate (table pointeur) = Taux d'attaque (AR[KSR]) int *AR; // Attack Rate (table pointeur) = Taux d'attaque (AR[KSR])
int *DR; // Decay Rate (table pointeur) = Taux pour la régression (DR[KSR]) int *DR; // Decay Rate (table pointeur) = Taux pour la régression (DR[KSR])
int *SR; // Sustin Rate (table pointeur) = Taux pour le maintien (SR[KSR]) int *SR; // Sustin Rate (table pointeur) = Taux pour le maintien (SR[KSR])
int *RR; // Release Rate (table pointeur) = Taux pour le relâchement (RR[KSR]) int *RR; // Release Rate (table pointeur) = Taux pour le relâchement (RR[KSR])
int Fcnt; // Frequency Count = compteur-fréquence pour déterminer l'amplitude actuelle (SIN[Finc >> 16]) int Fcnt; // Frequency Count = compteur-fréquence pour déterminer l'amplitude actuelle (SIN[Finc >> 16])
int Finc; // frequency step = pas d'incrémentation du compteur-fréquence int Finc; // frequency step = pas d'incrémentation du compteur-fréquence
// plus le pas est grand, plus la fréquence est aïgu (ou haute) // plus le pas est grand, plus la fréquence est aïgu (ou haute)
int Ecurp; // Envelope current phase = cette variable permet de savoir dans quelle phase int Ecurp; // Envelope current phase = cette variable permet de savoir dans quelle phase
// de l'enveloppe on se trouve, par exemple phase d'attaque ou phase de maintenue ... // de l'enveloppe on se trouve, par exemple phase d'attaque ou phase de maintenue ...
// en fonction de la valeur de cette variable, on va appeler une fonction permettant // en fonction de la valeur de cette variable, on va appeler une fonction permettant
// de mettre à jour l'enveloppe courante. // de mettre à jour l'enveloppe courante.
int Ecnt; // Envelope counter = le compteur-enveloppe permet de savoir où l'on se trouve dans l'enveloppe int Ecnt; // Envelope counter = le compteur-enveloppe permet de savoir où l'on se trouve dans l'enveloppe
int Einc; // Envelope step courant int Einc; // Envelope step courant
int Ecmp; // Envelope counter limite pour la prochaine phase int Ecmp; // Envelope counter limite pour la prochaine phase
int EincA; // Envelope step for Attack = pas d'incrémentation du compteur durant la phase d'attaque int EincA; // Envelope step for Attack = pas d'incrémentation du compteur durant la phase d'attaque
// cette valeur est égal à AR[KSR] // cette valeur est égal à AR[KSR]
int EincD; // Envelope step for Decay = pas d'incrémentation du compteur durant la phase de regression int EincD; // Envelope step for Decay = pas d'incrémentation du compteur durant la phase de regression
// cette valeur est égal à DR[KSR] // cette valeur est égal à DR[KSR]
int EincS; // Envelope step for Sustain = pas d'incrémentation du compteur durant la phase de maintenue int EincS; // Envelope step for Sustain = pas d'incrémentation du compteur durant la phase de maintenue
// cette valeur est égal à SR[KSR] // cette valeur est égal à SR[KSR]
int EincR; // Envelope step for Release = pas d'incrémentation du compteur durant la phase de relâchement int EincR; // Envelope step for Release = pas d'incrémentation du compteur durant la phase de relâchement
// cette valeur est égal à RR[KSR] // cette valeur est égal à RR[KSR]
int *OUTp; // pointeur of SLOT output = pointeur permettant de connecter la sortie de ce slot à l'entrée int *OUTp; // pointeur of SLOT output = pointeur permettant de connecter la sortie de ce slot à l'entrée
// d'un autre ou carrement à la sortie de la voie // d'un autre ou carrement à la sortie de la voie
int INd; // input data of the slot = données en entrée du slot int INd; // input data of the slot = données en entrée du slot
int ChgEnM; // Change envelop mask. int ChgEnM; // Change envelop mask.
int AMS; // AMS depth level of this SLOT = degré de modulation de l'amplitude par le LFO int AMS; // AMS depth level of this SLOT = degré de modulation de l'amplitude par le LFO
int AMSon; // AMS enable flag = drapeau d'activation de l'AMS int AMSon; // AMS enable flag = drapeau d'activation de l'AMS
} slot_; } slot_;
typedef struct channel__ { typedef struct channel__ {
int S0_OUT[4]; // anciennes sorties slot 0 (pour le feed back) int S0_OUT[4]; // anciennes sorties slot 0 (pour le feed back)
int Old_OUTd; // ancienne sortie de la voie (son brut) int Old_OUTd; // ancienne sortie de la voie (son brut)
int OUTd; // sortie de la voie (son brut) int OUTd; // sortie de la voie (son brut)
int LEFT; // LEFT enable flag int LEFT; // LEFT enable flag
int RIGHT; // RIGHT enable flag int RIGHT; // RIGHT enable flag
int ALGO; // Algorythm = détermine les connections entre les opérateurs int ALGO; // Algorythm = détermine les connections entre les opérateurs
int FB; // shift count of self feed back = degré de "Feed-Back" du SLOT 1 (il est son unique entrée) int FB; // shift count of self feed back = degré de "Feed-Back" du SLOT 1 (il est son unique entrée)
int FMS; // Fréquency Modulation Sensitivity of channel = degré de modulation de la fréquence sur la voie par le LFO int FMS; // Fréquency Modulation Sensitivity of channel = degré de modulation de la fréquence sur la voie par le LFO
int AMS; // Amplitude Modulation Sensitivity of channel = degré de modulation de l'amplitude sur la voie par le LFO int AMS; // Amplitude Modulation Sensitivity of channel = degré de modulation de l'amplitude sur la voie par le LFO
int FNUM[4]; // hauteur fréquence de la voie (+ 3 pour le mode spécial) int FNUM[4]; // hauteur fréquence de la voie (+ 3 pour le mode spécial)
int FOCT[4]; // octave de la voie (+ 3 pour le mode spécial) int FOCT[4]; // octave de la voie (+ 3 pour le mode spécial)
int KC[4]; // Key Code = valeur fonction de la fréquence (voir KSR pour les slots, KSR = KC >> KSR_S) int KC[4]; // Key Code = valeur fonction de la fréquence (voir KSR pour les slots, KSR = KC >> KSR_S)
struct slot__ SLOT[4]; // four slot.operators = les 4 slots de la voie struct slot__ SLOT[4]; // four slot.operators = les 4 slots de la voie
int FFlag; // Frequency step recalculation flag int FFlag; // Frequency step recalculation flag
} channel_; } channel_;
typedef struct ym2612__ { typedef struct ym2612__ {
int Clock; // Horloge YM2612 int Clock; // Horloge YM2612
int Rate; // Sample Rate (11025/22050/44100) int Rate; // Sample Rate (11025/22050/44100)
int TimerBase; // TimerBase calculation int TimerBase; // TimerBase calculation
int Status; // YM2612 Status (timer overflow) int Status; // YM2612 Status (timer overflow)
int OPNAadr; // addresse pour l'écriture dans l'OPN A (propre à l'émulateur) int OPNAadr; // addresse pour l'écriture dans l'OPN A (propre à l'émulateur)
int OPNBadr; // addresse pour l'écriture dans l'OPN B (propre à l'émulateur) int OPNBadr; // addresse pour l'écriture dans l'OPN B (propre à l'émulateur)
int LFOcnt; // LFO counter = compteur-fréquence pour le LFO int LFOcnt; // LFO counter = compteur-fréquence pour le LFO
int LFOinc; // LFO step counter = pas d'incrémentation du compteur-fréquence du LFO int LFOinc; // LFO step counter = pas d'incrémentation du compteur-fréquence du LFO
// plus le pas est grand, plus la fréquence est grande // plus le pas est grand, plus la fréquence est grande
int TimerA; // timerA limit = valeur jusqu'à laquelle le timer A doit compter int TimerA; // timerA limit = valeur jusqu'à laquelle le timer A doit compter
int TimerAL; int TimerAL;
int TimerAcnt; // timerA counter = valeur courante du Timer A int TimerAcnt; // timerA counter = valeur courante du Timer A
int TimerB; // timerB limit = valeur jusqu'à laquelle le timer B doit compter int TimerB; // timerB limit = valeur jusqu'à laquelle le timer B doit compter
int TimerBL; int TimerBL;
int TimerBcnt; // timerB counter = valeur courante du Timer B int TimerBcnt; // timerB counter = valeur courante du Timer B
int Mode; // Mode actuel des voie 3 et 6 (normal / spécial) int Mode; // Mode actuel des voie 3 et 6 (normal / spécial)
int DAC; // DAC enabled flag int DAC; // DAC enabled flag
int DACdata; // DAC data int DACdata; // DAC data
double Frequence; // Fréquence de base, se calcul par rapport à l'horlage et au sample rate double Frequence; // Fréquence de base, se calcul par rapport à l'horlage et au sample rate
unsigned int Inter_Cnt; // Interpolation Counter unsigned int Inter_Cnt; // Interpolation Counter
unsigned int Inter_Step; // Interpolation Step unsigned int Inter_Step; // Interpolation Step
struct channel__ CHANNEL[6]; // Les 6 voies du YM2612 struct channel__ CHANNEL[6]; // Les 6 voies du YM2612
int REG[2][0x100]; // Sauvegardes des valeurs de tout les registres, c'est facultatif int REG[2][0x100]; // Sauvegardes des valeurs de tout les registres, c'est facultatif
// cela nous rend le débuggage plus facile // cela nous rend le débuggage plus facile
} ym2612_; } ym2612_;

View File

@ -21,8 +21,8 @@
#define uint8 unsigned char #define uint8 unsigned char
#define uint16 unsigned short #define uint16 unsigned short
#define uint32 unsigned int #define uint32 unsigned int
#define int8 signed char #define int8 signed char
#define int16 signed short #define int16 signed short
#define int32 signed long int #define int32 signed long int

File diff suppressed because it is too large Load Diff

View File

@ -1,274 +0,0 @@
/* unzip.h -- IO for uncompress .zip files using zlib
Version 0.15 beta, Mar 19th, 1998,
Copyright (C) 1998 Gilles Vollant
This unzip package allow extract file from .ZIP file, compatible with PKZip 2.04g
WinZip, InfoZip tools and compatible.
Encryption and multi volume ZipFile (span) are not supported.
Old compressions used by old PKZip 1.x are not supported
THIS IS AN ALPHA VERSION. AT THIS STAGE OF DEVELOPPEMENT, SOMES API OR STRUCTURE
CAN CHANGE IN FUTURE VERSION !!
I WAIT FEEDBACK at mail info@winimage.com
Visit also http://www.winimage.com/zLibDll/unzip.htm for evolution
Condition of use and distribution are the same than zlib :
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
/* for more info about .ZIP format, see
ftp://ftp.cdrom.com/pub/infozip/doc/appnote-970311-iz.zip
PkWare has also a specification at :
ftp://ftp.pkware.com/probdesc.zip */
#ifndef _unz_H
#define _unz_H
#ifdef __cplusplus
extern "C" {
#endif
#ifndef _ZLIB_H
#include "zlib.h"
#endif
#if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP)
/* like the STRICT of WIN32, we define a pointer that cannot be converted
from (void*) without cast */
typedef struct TagunzFile__ { int unused; } unzFile__;
typedef unzFile__ *unzFile;
#else
typedef voidp unzFile;
#endif
#define UNZ_OK (0)
#define UNZ_END_OF_LIST_OF_FILE (-100)
#define UNZ_ERRNO (Z_ERRNO)
#define UNZ_EOF (0)
#define UNZ_PARAMERROR (-102)
#define UNZ_BADZIPFILE (-103)
#define UNZ_INTERNALERROR (-104)
#define UNZ_CRCERROR (-105)
/* tm_unz contain date/time info */
typedef struct tm_unz_s
{
uInt tm_sec; /* seconds after the minute - [0,59] */
uInt tm_min; /* minutes after the hour - [0,59] */
uInt tm_hour; /* hours since midnight - [0,23] */
uInt tm_mday; /* day of the month - [1,31] */
uInt tm_mon; /* months since January - [0,11] */
uInt tm_year; /* years - [1980..2044] */
} tm_unz;
/* unz_global_info structure contain global data about the ZIPfile
These data comes from the end of central dir */
typedef struct unz_global_info_s
{
uLong number_entry; /* total number of entries in
the central dir on this disk */
uLong size_comment; /* size of the global comment of the zipfile */
} unz_global_info;
/* unz_file_info contain information about a file in the zipfile */
typedef struct unz_file_info_s
{
uLong version; /* version made by 2 bytes */
uLong version_needed; /* version needed to extract 2 bytes */
uLong flag; /* general purpose bit flag 2 bytes */
uLong compression_method; /* compression method 2 bytes */
uLong dosDate; /* last mod file date in Dos fmt 4 bytes */
uLong crc; /* crc-32 4 bytes */
uLong compressed_size; /* compressed size 4 bytes */
uLong uncompressed_size; /* uncompressed size 4 bytes */
uLong size_filename; /* filename length 2 bytes */
uLong size_file_extra; /* extra field length 2 bytes */
uLong size_file_comment; /* file comment length 2 bytes */
uLong disk_num_start; /* disk number start 2 bytes */
uLong internal_fa; /* internal file attributes 2 bytes */
uLong external_fa; /* external file attributes 4 bytes */
tm_unz tmu_date;
} unz_file_info;
extern int ZEXPORT unzStringFileNameCompare OF ((const char* fileName1,
const char* fileName2,
int iCaseSensitivity));
/*
Compare two filename (fileName1,fileName2).
If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp)
If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi
or strcasecmp)
If iCaseSenisivity = 0, case sensitivity is defaut of your operating system
(like 1 on Unix, 2 on Windows)
*/
extern unzFile ZEXPORT unzOpen OF((const char *path));
/*
Open a Zip file. path contain the full pathname (by example,
on a Windows NT computer "c:\\zlib\\zlib111.zip" or on an Unix computer
"zlib/zlib111.zip".
If the zipfile cannot be opened (file don't exist or in not valid), the
return value is NULL.
Else, the return value is a unzFile Handle, usable with other function
of this unzip package.
*/
extern int ZEXPORT unzClose OF((unzFile file));
/*
Close a ZipFile opened with unzipOpen.
If there is files inside the .Zip opened with unzOpenCurrentFile (see later),
these files MUST be closed with unzipCloseCurrentFile before call unzipClose.
return UNZ_OK if there is no problem. */
extern int ZEXPORT unzGetGlobalInfo OF((unzFile file,
unz_global_info *pglobal_info));
/*
Write info about the ZipFile in the *pglobal_info structure.
No preparation of the structure is needed
return UNZ_OK if there is no problem. */
extern int ZEXPORT unzGetGlobalComment OF((unzFile file,
char *szComment,
uLong uSizeBuf));
/*
Get the global comment string of the ZipFile, in the szComment buffer.
uSizeBuf is the size of the szComment buffer.
return the number of byte copied or an error code <0
*/
/***************************************************************************/
/* Unzip package allow you browse the directory of the zipfile */
extern int ZEXPORT unzGoToFirstFile OF((unzFile file));
/*
Set the current file of the zipfile to the first file.
return UNZ_OK if there is no problem
*/
extern int ZEXPORT unzGoToNextFile OF((unzFile file));
/*
Set the current file of the zipfile to the next file.
return UNZ_OK if there is no problem
return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest.
*/
extern int ZEXPORT unzLocateFile OF((unzFile file,
const char *szFileName,
int iCaseSensitivity));
/*
Try locate the file szFileName in the zipfile.
For the iCaseSensitivity signification, see unzStringFileNameCompare
return value :
UNZ_OK if the file is found. It becomes the current file.
UNZ_END_OF_LIST_OF_FILE if the file is not found
*/
extern int ZEXPORT unzGetCurrentFileInfo OF((unzFile file,
unz_file_info *pfile_info,
char *szFileName,
uLong fileNameBufferSize,
void *extraField,
uLong extraFieldBufferSize,
char *szComment,
uLong commentBufferSize));
/*
Get Info about the current file
if pfile_info!=NULL, the *pfile_info structure will contain somes info about
the current file
if szFileName!=NULL, the filemane string will be copied in szFileName
(fileNameBufferSize is the size of the buffer)
if extraField!=NULL, the extra field information will be copied in extraField
(extraFieldBufferSize is the size of the buffer).
This is the Central-header version of the extra field
if szComment!=NULL, the comment string of the file will be copied in szComment
(commentBufferSize is the size of the buffer)
*/
/***************************************************************************/
/* for reading the content of the current zipfile, you can open it, read data
from it, and close it (you can close it before reading all the file)
*/
extern int ZEXPORT unzOpenCurrentFile OF((unzFile file));
/*
Open for reading data the current file in the zipfile.
If there is no error, the return value is UNZ_OK.
*/
extern int ZEXPORT unzCloseCurrentFile OF((unzFile file));
/*
Close the file in zip opened with unzOpenCurrentFile
Return UNZ_CRCERROR if all the file was read but the CRC is not good
*/
extern int ZEXPORT unzReadCurrentFile OF((unzFile file,
voidp buf,
unsigned len));
/*
Read bytes from the current file (opened by unzOpenCurrentFile)
buf contain buffer where data must be copied
len the size of buf.
return the number of byte copied if somes bytes are copied
return 0 if the end of file was reached
return <0 with error code if there is an error
(UNZ_ERRNO for IO error, or zLib error for uncompress error)
*/
extern z_off_t ZEXPORT unztell OF((unzFile file));
/*
Give the current position in uncompressed data
*/
extern int ZEXPORT unzeof OF((unzFile file));
/*
return 1 if the end of file was reached, 0 elsewhere
*/
extern int ZEXPORT unzGetLocalExtrafield OF((unzFile file,
voidp buf,
unsigned len));
/*
Read extra field from the current file (opened by unzOpenCurrentFile)
This is the local-header version of the extra field (sometimes, there is
more info in the local-header version than in the central-header)
if buf==NULL, it return the size of the local extra field
if buf!=NULL, len is the size of the buffer, the extra header is copied in
buf.
the return value is the number of bytes copied in buf, or (if <0)
the error code
*/
#ifdef __cplusplus
}
#endif
#endif /* _unz_H */

View File

@ -7,48 +7,48 @@
/* Interrupt line constants */ /* Interrupt line constants */
enum enum
{ {
/* line states */ /* line states */
CLEAR_LINE = 0, /* clear (a fired, held or pulsed) line */ CLEAR_LINE = 0, /* clear (a fired, held or pulsed) line */
ASSERT_LINE, /* assert an interrupt immediately */ ASSERT_LINE, /* assert an interrupt immediately */
HOLD_LINE, /* hold interrupt line until acknowledged */ HOLD_LINE, /* hold interrupt line until acknowledged */
PULSE_LINE, /* pulse interrupt line for one instruction */ PULSE_LINE, /* pulse interrupt line for one instruction */
/* internal flags (not for use by drivers!) */ /* internal flags (not for use by drivers!) */
INTERNAL_CLEAR_LINE = 100 + CLEAR_LINE, INTERNAL_CLEAR_LINE = 100 + CLEAR_LINE,
INTERNAL_ASSERT_LINE = 100 + ASSERT_LINE, INTERNAL_ASSERT_LINE = 100 + ASSERT_LINE,
/* input lines */ /* input lines */
MAX_INPUT_LINES = 32+3, MAX_INPUT_LINES = 32+3,
INPUT_LINE_IRQ0 = 0, INPUT_LINE_IRQ0 = 0,
INPUT_LINE_IRQ1 = 1, INPUT_LINE_IRQ1 = 1,
INPUT_LINE_IRQ2 = 2, INPUT_LINE_IRQ2 = 2,
INPUT_LINE_IRQ3 = 3, INPUT_LINE_IRQ3 = 3,
INPUT_LINE_IRQ4 = 4, INPUT_LINE_IRQ4 = 4,
INPUT_LINE_IRQ5 = 5, INPUT_LINE_IRQ5 = 5,
INPUT_LINE_IRQ6 = 6, INPUT_LINE_IRQ6 = 6,
INPUT_LINE_IRQ7 = 7, INPUT_LINE_IRQ7 = 7,
INPUT_LINE_IRQ8 = 8, INPUT_LINE_IRQ8 = 8,
INPUT_LINE_IRQ9 = 9, INPUT_LINE_IRQ9 = 9,
INPUT_LINE_NMI = MAX_INPUT_LINES - 3, INPUT_LINE_NMI = MAX_INPUT_LINES - 3,
/* special input lines that are implemented in the core */ /* special input lines that are implemented in the core */
INPUT_LINE_RESET = MAX_INPUT_LINES - 2, INPUT_LINE_RESET = MAX_INPUT_LINES - 2,
INPUT_LINE_HALT = MAX_INPUT_LINES - 1, INPUT_LINE_HALT = MAX_INPUT_LINES - 1,
/* output lines */ /* output lines */
MAX_OUTPUT_LINES = 32 MAX_OUTPUT_LINES = 32
}; };
/* daisy-chain link */ /* daisy-chain link */
typedef struct { typedef struct {
void (*reset)(int); /* reset callback */ void (*reset)(int); /* reset callback */
int (*interrupt_entry)(int); /* entry callback */ int (*interrupt_entry)(int); /* entry callback */
void (*interrupt_reti)(int); /* reti callback */ void (*interrupt_reti)(int); /* reti callback */
int irq_param; /* callback paramater */ int irq_param; /* callback paramater */
} Z80_DaisyChain; } Z80_DaisyChain;
#define Z80_MAXDAISY 4 /* maximum of daisy chan device */ #define Z80_MAXDAISY 4 /* maximum of daisy chan device */
#define Z80_INT_REQ 0x01 /* interrupt request mask */ #define Z80_INT_REQ 0x01 /* interrupt request mask */
#define Z80_INT_IEO 0x02 /* interrupt disable mask(IEO) */ #define Z80_INT_IEO 0x02 /* interrupt disable mask(IEO) */
@ -56,4 +56,4 @@ typedef struct {
#define Z80_VECTOR(device,state) (((device)<<8)|(state)) #define Z80_VECTOR(device,state) (((device)<<8)|(state))
#endif /* CPUINTRF_H */ #endif /* CPUINTRF_H */

View File

@ -1,24 +1,24 @@
/******************************************************************************* /*******************************************************************************
* * * *
* Define size independent data types and operations. * * Define size independent data types and operations. *
* * * *
* The following types must be supported by all platforms: * * The following types must be supported by all platforms: *
* * * *
* UINT8 - Unsigned 8-bit Integer INT8 - Signed 8-bit integer * * UINT8 - Unsigned 8-bit Integer INT8 - Signed 8-bit integer *
* UINT16 - Unsigned 16-bit Integer INT16 - Signed 16-bit integer * * UINT16 - Unsigned 16-bit Integer INT16 - Signed 16-bit integer *
* UINT32 - Unsigned 32-bit Integer INT32 - Signed 32-bit integer * * UINT32 - Unsigned 32-bit Integer INT32 - Signed 32-bit integer *
* UINT64 - Unsigned 64-bit Integer INT64 - Signed 64-bit integer * * UINT64 - Unsigned 64-bit Integer INT64 - Signed 64-bit integer *
* * * *
* * * *
* The macro names for the artithmatic operations are composed as follows: * * The macro names for the artithmatic operations are composed as follows: *
* * * *
* XXX_R_A_B, where XXX - 3 letter operation code (ADD, SUB, etc.) * * XXX_R_A_B, where XXX - 3 letter operation code (ADD, SUB, etc.) *
* R - The type of the result * * R - The type of the result *
* A - The type of operand 1 * * A - The type of operand 1 *
* B - The type of operand 2 (if binary operation) * * B - The type of operand 2 (if binary operation) *
* * * *
* Each type is one of: U8,8,U16,16,U32,32,U64,64 * * Each type is one of: U8,8,U16,16,U32,32,U64,64 *
* * * *
*******************************************************************************/ *******************************************************************************/
@ -35,14 +35,14 @@
#define FALSE 0 #define FALSE 0
#endif #endif
typedef unsigned char UINT8; typedef unsigned char UINT8;
typedef unsigned short UINT16; typedef unsigned short UINT16;
//#ifdef DOS //#ifdef DOS
typedef unsigned int UINT32; typedef unsigned int UINT32;
__extension__ typedef unsigned long long UINT64; __extension__ typedef unsigned long long UINT64;
//#endif //#endif
typedef signed char INT8; typedef signed char INT8;
typedef signed short INT16; typedef signed short INT16;
//#ifdef DOS //#ifdef DOS
typedef signed int INT32; typedef signed int INT32;
__extension__ typedef signed long long INT64; __extension__ typedef signed long long INT64;
@ -53,20 +53,20 @@ __extension__ typedef signed long long INT64;
#define COMBINE_U64_U32_U32(A,B) COMBINE_64_32_32(A,B) #define COMBINE_U64_U32_U32(A,B) COMBINE_64_32_32(A,B)
/* Return upper 32 bits of a 64-bit integer */ /* Return upper 32 bits of a 64-bit integer */
#define HI32_32_64(A) (((UINT64)(A)) >> 32) #define HI32_32_64(A) (((UINT64)(A)) >> 32)
#define HI32_U32_U64(A) HI32_32_64(A) #define HI32_U32_U64(A) HI32_32_64(A)
/* Return lower 32 bits of a 64-bit integer */ /* Return lower 32 bits of a 64-bit integer */
#define LO32_32_64(A) ((A) & 0xffffffff) #define LO32_32_64(A) ((A) & 0xffffffff)
#define LO32_U32_U64(A) LO32_32_64(A) #define LO32_U32_U64(A) LO32_32_64(A)
#define DIV_64_64_32(A,B) ((A)/(B)) #define DIV_64_64_32(A,B) ((A)/(B))
#define DIV_U64_U64_U32(A,B) ((A)/(UINT32)(B)) #define DIV_U64_U64_U32(A,B) ((A)/(UINT32)(B))
#define MOD_32_64_32(A,B) ((A)%(B)) #define MOD_32_64_32(A,B) ((A)%(B))
#define MOD_U32_U64_U32(A,B) ((A)%(UINT32)(B)) #define MOD_U32_U64_U32(A,B) ((A)%(UINT32)(B))
#define MUL_64_32_32(A,B) ((A)*(INT64)(B)) #define MUL_64_32_32(A,B) ((A)*(INT64)(B))
#define MUL_U64_U32_U32(A,B) ((A)*(UINT64)(UINT32)(B)) #define MUL_U64_U32_U32(A,B) ((A)*(UINT64)(UINT32)(B))
@ -79,13 +79,13 @@ __extension__ typedef signed long long INT64;
******************************************************************************/ ******************************************************************************/
typedef union { typedef union {
#ifdef LSB_FIRST #ifdef LSB_FIRST
struct { UINT8 l,h,h2,h3; } b; struct { UINT8 l,h,h2,h3; } b;
struct { UINT16 l,h; } w; struct { UINT16 l,h; } w;
#else #else
struct { UINT8 h3,h2,h,l; } b; struct { UINT8 h3,h2,h,l; } b;
struct { UINT16 h,l; } w; struct { UINT16 h,l; } w;
#endif #endif
UINT32 d; UINT32 d;
} PAIR; } PAIR;
#endif /* defined OSD_CPU_H */ #endif /* defined OSD_CPU_H */

File diff suppressed because it is too large Load Diff

View File

@ -4,21 +4,21 @@
#include "cpuintrf.h" #include "cpuintrf.h"
enum { enum {
Z80_PC=1, Z80_SP, Z80_A, Z80_B, Z80_PC=1, Z80_SP, Z80_A, Z80_B,
Z80_C, Z80_D, Z80_E, Z80_H, Z80_L, Z80_C, Z80_D, Z80_E, Z80_H, Z80_L,
Z80_AF, Z80_BC, Z80_DE, Z80_HL, Z80_AF, Z80_BC, Z80_DE, Z80_HL,
Z80_IX, Z80_IY, Z80_AF2, Z80_BC2, Z80_DE2, Z80_HL2, Z80_IX, Z80_IY, Z80_AF2, Z80_BC2, Z80_DE2, Z80_HL2,
Z80_R, Z80_I, Z80_IM, Z80_IFF1, Z80_IFF2, Z80_HALT, Z80_R, Z80_I, Z80_IM, Z80_IFF1, Z80_IFF2, Z80_HALT,
Z80_DC0, Z80_DC1, Z80_DC2, Z80_DC3 Z80_DC0, Z80_DC1, Z80_DC2, Z80_DC3
}; };
enum { enum {
Z80_TABLE_op, Z80_TABLE_op,
Z80_TABLE_cb, Z80_TABLE_cb,
Z80_TABLE_ed, Z80_TABLE_ed,
Z80_TABLE_xy, Z80_TABLE_xy,
Z80_TABLE_xycb, Z80_TABLE_xycb,
Z80_TABLE_ex /* cycles counts for taken jr/jp/call and interrupt latency (rst opcodes) */ Z80_TABLE_ex /* cycles counts for taken jr/jp/call and interrupt latency (rst opcodes) */
}; };
/****************************************************************************/ /****************************************************************************/
@ -27,16 +27,16 @@ enum {
/****************************************************************************/ /****************************************************************************/
typedef struct typedef struct
{ {
PAIR prvpc,pc,sp,af,bc,de,hl,ix,iy; PAIR prvpc,pc,sp,af,bc,de,hl,ix,iy;
PAIR af2,bc2,de2,hl2; PAIR af2,bc2,de2,hl2;
UINT8 r,r2,iff1,iff2,halt,im,i; UINT8 r,r2,iff1,iff2,halt,im,i;
UINT8 nmi_state; /* nmi line state */ UINT8 nmi_state; /* nmi line state */
UINT8 nmi_pending; /* nmi pending */ UINT8 nmi_pending; /* nmi pending */
UINT8 irq_state; /* irq line state */ UINT8 irq_state; /* irq line state */
UINT8 after_ei; /* are we in the EI shadow? */ UINT8 after_ei; /* are we in the EI shadow? */
const struct z80_irq_daisy_chain *daisy; const struct z80_irq_daisy_chain *daisy;
int (*irq_callback)(int irqline); int (*irq_callback)(int irqline);
} Z80_Regs; } Z80_Regs;
extern int z80_ICount; extern int z80_ICount;