added libsamplerate support, improved zipped rom loading, improved SSG-EG support

This commit is contained in:
ekeeke31 2008-08-17 20:17:49 +00:00
parent 8a2d4a03ff
commit 0db46554ef
37 changed files with 369751 additions and 381 deletions

View File

@ -18,18 +18,18 @@ include $(DEVKITPPC)/gamecube_rules
TARGET := genplus_cube
BUILD := build_cube
SOURCES := source source/m68k source/cpu source/sound source/cart_hw \
source/cart_hw/svp source/ngc source/ngc/gui
source/cart_hw/svp source/ngc source/ngc/gui source/sound/SRC
INCLUDES := source source/m68k source/cpu source/sound source/cart_hw \
source/cart_hw/svp source/ngc source/ngc/gui
source/cart_hw/svp source/ngc source/ngc/gui source/sound/SRC
#---------------------------------------------------------------------------------
# options for code generation
#---------------------------------------------------------------------------------
CFLAGS = -g -fno-strict-aliasing -O2 -Wall $(MACHDEP) $(INCLUDE) -DWORDS_BIGENDIAN -DNGC="1" -DHW_DOL
CFLAGS = -fno-strict-aliasing -O2 -Wall $(MACHDEP) $(INCLUDE) -DWORDS_BIGENDIAN -DNGC="1" -DHW_DOL
CXXFLAGS = $(CFLAGS)
LDFLAGS = -g $(MACHDEP) -Wl,-Map,$(notdir $@).map
LDFLAGS = $(MACHDEP) -Wl,-Map,$(notdir $@).map
#---------------------------------------------------------------------------------
# any extra libraries we wish to link with the project

View File

@ -18,18 +18,18 @@ include $(DEVKITPPC)/wii_rules
TARGET := genplus_wii
BUILD := build_wii
SOURCES := source source/m68k source/cpu source/sound source/cart_hw\
source/cart_hw/svp source/ngc source/ngc/gui
source/cart_hw/svp source/ngc source/ngc/gui source/sound/SRC
INCLUDES := source source/m68k source/cpu source/sound source/cart_hw\
source/cart_hw/svp source/ngc source/ngc/gui
source/cart_hw/svp source/ngc source/ngc/gui source/sound/SRC
#---------------------------------------------------------------------------------
# options for code generation
#---------------------------------------------------------------------------------
CFLAGS = -g -O2 -mrvl -Wall $(MACHDEP) -fno-strict-aliasing $(INCLUDE) -DWORDS_BIGENDIAN -DNGC="1" -DHW_RVL
CFLAGS = -O2 -mrvl -Wall $(MACHDEP) -fno-strict-aliasing $(INCLUDE) -DWORDS_BIGENDIAN -DNGC="1" -DHW_RVL
CXXFLAGS = $(CFLAGS)
LDFLAGS = -g $(MACHDEP) -Wl,-Map,$(notdir $@).map
LDFLAGS = $(MACHDEP) -Wl,-Map,$(notdir $@).map
#---------------------------------------------------------------------------------
# any extra libraries we wish to link with the project

View File

@ -4,22 +4,31 @@ Genesis Plus for Gamecube
current:
---------
[Genesis]
- (YM2612) fixed LFO phase update for CH3 special mode in MAME core: fix some SFX in Warlock & Alladin (thanks to AamirM)
- (YM2612) fixed enveloppe attenuation level on "KEY ON" in MAME core: fix Ecco 2's splash sound
- implemented cycle-accurate HINT timings: every timing sensitive games/demos are now *finally* working fine
- fixed a bug affecting CRAM/VSRAM DMA timings
- fixed Sprite Attribute Table address mask for VRAM writes
- improved accuracy of 68k access to Z80: fix music in Pacman 2 when entering PAUSE menu
- disabled "Address Error" emulation when UMK3 hack is loaded: fix game crashing after a round ends up
- added support for some more unlicensed games: Pocket Monster, King of Fighter 98, Soul Blade (credits to Haze)
- improved Menacer emulation: fix lightgun support in Body Count & T2: The Arcade Game
- implemented Konami Justifier emulation: fix lightgun support in Lethal Enforcers 1 & 2
- implemented Sega Mouse emulation (Populous 2, Body Count, Shangai 2, Fun'n Games, ...)
[Wii]
- added lightgun support (Menacer/Justifier) through Wiimote IR
(MAME YM2612) fixed LFO phase update for CH3 special mode: fix sound effects in Warlock & Aladdin (thanks to AamirM)
(MAME YM2612) fixed enveloppe attenuation level on "KEY ON": fix Ecco 2's splash sound
(MAME YM2612) minor fixes on SSG-EG emulation
(MAME YM2612) added libsamplerate (Secret Rabbit Code) support for better FM resampling (HQ mode)
(VDP) implemented cycle-accurate HINT timings: every timing sensitive games/demos are now *finally* working fine
(VDP) fixed a bug affecting CRAM/VSRAM DMA timings
(VDP) fixed Sprite Attribute Table address mask for VRAM writes
(CPU) improved accuracy of 68k access to Z80: fix music in Pacman 2 when entering PAUSE menu
(CPU) disabled "Address Error" emulation when UMK3 hack is loaded: fix game crashing after a round ends up
(CART) added support for some more unlicensed games: Pocket Monster, King of Fighter 98, Soul Blade (credits to Haze)
(IO) improved Menacer emulation: fix lightgun support in Body Count & T2: The Arcade Game
(IO) implemented Konami Justifier emulation: fix lightgun support in Lethal Enforcers 1 & 2
(IO) implemented Sega Mouse emulation (Populous 2, Body Count, Shangai 2, Fun'n Games, ...)
[Wii only]
- added lightgun & mouse support through Wiimote IR
[NGC/Wii]
- added "Gun cursor" option to enable/disable gun position display
- added "Invert Mouse" option to invert Sega Mouse vertical axe (required by some games)
- improved Controller options: Wiimote/Nunchuk and Classical Controllers can now be affected separately to ANY player
- faster zipped ROM loading from SDCARD
- reduced binaries size using Dollz3
16/07/2008:
-----------

View File

@ -55,7 +55,7 @@ int main( int argc, char *argv[] )
if ( argc != 4 )
{
printf("Usage : %s genplus.dol genesisrom.smd output.dol\n", argv[0]);
printf("Usage : %s genplus.dol filename_of_your_rom.bin (or .smd) output.dol\n", argv[0]);
return 1;
}

View File

@ -4,6 +4,8 @@
#include <fat.h>
#include <sys/dir.h>
#define CONFIG_VERSION "GENPLUS 1.2.1 "
t_config config;
void config_save()
@ -25,25 +27,34 @@ void config_save()
void config_load()
{
char version[15];
/* open file for writing */
FILE *fp = fopen("/genplus/genplus.ini", "rb");
if (fp == NULL) return;
/* read file */
fread(&config, sizeof(config), 1, fp);
/* read version */
fread(version, 15, 1, fp);
fclose(fp);
if (strcmp(version,CONFIG_VERSION)) return;
/* read file */
fp = fopen("/genplus/genplus.ini", "rb");
fread(&config, sizeof(config), 1, fp);
fclose(fp);
}
void set_config_defaults(void)
{
/* version TAG */
strncpy(config.version,CONFIG_VERSION,15);
/* sound options */
config.psg_preamp = 1.5;
config.fm_preamp = 1.0;
config.boost = 1;
config.hq_fm = 1;
config.fm_core = 0;
config.ssg_enabled = 0;
/* system options */
config.freeze_auto = -1;

View File

@ -8,12 +8,12 @@
****************************************************************************/
typedef struct
{
char version[15];
double psg_preamp;
double fm_preamp;
uint8 boost;
uint8 hq_fm;
uint8 fm_core;
uint8 ssg_enabled;
int8 sram_auto;
int8 freeze_auto;
uint8 region_detect;

View File

@ -52,17 +52,16 @@ int dvd_read (void *dst, unsigned int len, u64 offset)
#ifdef HW_DOL
unsigned char *buffer = (unsigned char *) (unsigned int) DVDreadbuffer;
DCInvalidateRange((void *)buffer, len);
/*dvd[0] = 0x2E;
dvd[0] = 0x2E;
dvd[1] = 0;
dvd[2] = 0xA8000000;
dvd[3] = (u32)(offset >> 2);
dvd[4] = len;
dvd[5] = (u32) buffer;
dvd[6] = len;
dvd[7] = 3; */
dvd[7] = 3;
/*** Enable reading with DMA ***/
DVD_LowRead(buffer,len,offset,NULL);
while (dvd[7] & 1);
memcpy (dst, buffer, len);
@ -91,10 +90,6 @@ int dvd_read (void *dst, unsigned int len, u64 offset)
#ifdef HW_DOL
void uselessinquiry ()
{
dvddrvinfo drive_info;
DVD_LowInquiry(&drive_info,NULL);
/*
dvd[0] = 0;
dvd[1] = 0;
dvd[2] = 0x12000000;
@ -104,7 +99,7 @@ void uselessinquiry ()
dvd[6] = 0x20;
dvd[7] = 1;
while (dvd[7] & 1);*/
while (dvd[7] & 1);
}
#endif
@ -118,10 +113,6 @@ void uselessinquiry ()
#ifdef HW_DOL
void dvd_motor_off( )
{
DVD_LowStopMotor(NULL);
/*
dvd[0] = 0x2e;
dvd[1] = 0;
dvd[2] = 0xe3000000;
@ -130,11 +121,11 @@ void dvd_motor_off( )
dvd[5] = 0;
dvd[6] = 0;
dvd[7] = 1; // Do immediate
while (dvd[7] & 1);*/
while (dvd[7] & 1);
/*** PSO Stops blackscreen at reload ***/
/* dvd[0] = 0x14;
dvd[1] = 0;*/
dvd[0] = 0x14;
dvd[1] = 0;
}
#endif
@ -147,7 +138,7 @@ void dvd_motor_off( )
#ifdef HW_DOL
void dvd_drive_detect()
{
/*dvd[0] = 0x2e;
dvd[0] = 0x2e;
dvd[1] = 0;
dvd[2] = 0x12000000;
dvd[3] = 0;
@ -156,14 +147,9 @@ void dvd_drive_detect()
dvd[6] = 0x20;
dvd[7] = 3;
while( dvd[7] & 1 );
DCFlushRange((void *)0x80000000, 32);*/
DCFlushRange((void *)0x80000000, 32);
dvddrvinfo drive_info;
DVD_LowInquiry(&drive_info,NULL);
//int driveid = (int)inquiry[2];
int driveid = drive_info.dev_code;
int driveid = (int)inquiry[2];
if ((driveid == 4) || (driveid == 6) || (driveid == 8))
{

View File

@ -8,10 +8,9 @@
#include "shared.h"
#include "dvd.h"
#include "font.h"
#include "unzip.h"
#include <zlib.h>
/* SDCARD File access */
extern FILE *sdfile;
/*
* PKWare Zip Header - adopted into zip standard
@ -78,7 +77,7 @@ int IsZipFile (char *buffer)
*
* It should be noted that there is a limit of 5MB total size for any ROM
******************************************************************************/
int UnZipBuffer (unsigned char *outbuffer, u64 discoffset, int length, u8 UseSDCARD)
int UnZipDVD (unsigned char *outbuffer, u64 discoffset, int length)
{
PKZIPHEADER pkzip;
int zipoffset = 0;
@ -92,15 +91,7 @@ int UnZipBuffer (unsigned char *outbuffer, u64 discoffset, int length, u8 UseSDC
char msg[128];
/*** Read Zip Header ***/
if ( UseSDCARD )
{
fseek(sdfile, 0, SEEK_SET);
fread(readbuffer, 1, 2048, sdfile);
}
else
{
dvd_read (&readbuffer, 2048, discoffset);
}
dvd_read (&readbuffer, 2048, discoffset);
/*** Copy PKZip header to local, used as info ***/
memcpy (&pkzip, &readbuffer, sizeof (PKZIPHEADER));
@ -156,15 +147,8 @@ int UnZipBuffer (unsigned char *outbuffer, u64 discoffset, int length, u8 UseSDC
zipoffset = 0;
zipchunk = ZIPCHUNK;
if (UseSDCARD)
{
fread(readbuffer, 1, 2048, sdfile);
}
else
{
discoffset += 2048;
dvd_read (&readbuffer, 2048, discoffset);
}
discoffset += 2048;
dvd_read (&readbuffer, 2048, discoffset);
}
while (res != Z_STREAM_END);
@ -178,3 +162,73 @@ int UnZipBuffer (unsigned char *outbuffer, u64 discoffset, int length, u8 UseSDC
return 0;
}
int UnZipSDCARD (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

@ -9,6 +9,7 @@
#define _UNZIP_H_
extern int IsZipFile (char *buffer);
int UnZipBuffer (unsigned char *outbuffer, u64 discoffset, int length, u8 UseSDCARD);
int UnZipDVD (unsigned char *outbuffer, u64 discoffset, int length);
int UnZipSDCARD (unsigned char *outbuffer, char *filename);
#endif

View File

@ -14,7 +14,7 @@
#include "dvd.h"
#include "iso9660.h"
#include "font.h"
#include "unzip.h"
#include "fileio.h"
#include "history.h"
#define PAGESIZE 12
@ -558,13 +558,12 @@ void OpenHistory()
****************************************************************************/
static int LoadFile (unsigned char *buffer)
{
int readoffset;
int blocks;
int i;
u64 discoffset = 0;
char readbuffer[2048];
char fname[MAXPATHLEN];
if (rootdirlength == 0) return 0;
/* SDCard access */
if (UseSDCARD)
{
@ -578,11 +577,6 @@ static int LoadFile (unsigned char *buffer)
return 0;
}
}
/* How many 2k blocks to read */
if (rootdirlength == 0) return 0;
blocks = rootdirlength / 2048;
readoffset = 0;
ShowAction ("Loading ... Wait");
@ -600,46 +594,44 @@ static int LoadFile (unsigned char *buffer)
/* determine file type */
if (!IsZipFile ((char *) readbuffer))
{
/* go back to file start */
if (UseSDCARD)
{
/* go back to file start and read file */
fseek(sdfile, 0, SEEK_SET);
fread(buffer, 1, rootdirlength, sdfile);
fclose(sdfile);
}
/* read data chunks */
for (i = 0; i < blocks; i++)
else
{
if (UseSDCARD)
{
fread(readbuffer, 1, 2048, sdfile);
}
else
/* How many 2k blocks to read */
int blocks = rootdirlength / 2048;
int readoffset = 0;
int i;
/* read data chunks */
for (i = 0; i < blocks; i++)
{
dvd_read(readbuffer, 2048, discoffset);
discoffset += 2048;
memcpy (buffer + readoffset, readbuffer, 2048);
readoffset += 2048;
}
memcpy (buffer + readoffset, readbuffer, 2048);
readoffset += 2048;
}
/* final read */
i = rootdirlength % 2048;
if (i)
{
if (UseSDCARD) fread(readbuffer, 1, i, sdfile);
else dvd_read (readbuffer, 2048, discoffset);
memcpy (buffer + readoffset, readbuffer, i);
/* final read */
i = rootdirlength % 2048;
if (i)
{
dvd_read (readbuffer, 2048, discoffset);
memcpy (buffer + readoffset, readbuffer, i);
}
}
}
else
{
/* unzip file */
return UnZipBuffer (buffer, discoffset, rootdirlength, UseSDCARD);
if (UseSDCARD) return UnZipSDCARD (buffer, fname);
else return UnZipDVD (buffer, discoffset, rootdirlength);
}
/* close SD file */
if (UseSDCARD) fclose(sdfile);
return rootdirlength;
}

View File

@ -133,8 +133,8 @@ void soundmenu ()
int ret;
int quit = 0;
int prevmenu = menu;
int count = 6;
char items[6][20];
int count = 5;
char items[5][20];
strcpy (menutitle, "Press B to return");
@ -144,9 +144,24 @@ void soundmenu ()
sprintf (items[0], "PSG Volume: %1.2f", config.psg_preamp);
sprintf (items[1], "FM Volume: %1.2f", config.fm_preamp);
sprintf (items[2], "Volume Boost: %dX", config.boost);
sprintf (items[3], "HQ YM2612: %s", config.hq_fm ? "Y" : "N");
sprintf (items[4], "SSG-EG: %s", config.ssg_enabled ? "ON" : "OFF");
sprintf (items[5], "FM core: %s", config.fm_core ? "GENS" : "MAME");
if (config.hq_fm == 0) sprintf (items[3], "HQ YM2612: OFF");
else if (config.fm_core)
{
/* GENS core only got linear resampling */
sprintf (items[3], "HQ YM2612: LINEAR");
}
else
{
/* MAME core uses libsamplerate */
if (config.hq_fm == 1) sprintf (items[3], "HQ YM2612: LINEAR");
else if (config.hq_fm == 2) sprintf (items[3], "HQ YM2612: LOW");
else if (config.hq_fm == 3) sprintf (items[3], "HQ YM2612: FAST");
else if (config.hq_fm == 4) sprintf (items[3], "HQ YM2612: MEDIUM");
#ifdef USE_SINC_BEST
else if (config.hq_fm == 5) sprintf (items[3], "HQ YM2612: BEST");
#endif
}
sprintf (items[4], "FM core: %s", config.fm_core ? "GENS" : "MAME");
ret = domenu (&items[0], count, 1);
switch (ret)
@ -173,8 +188,12 @@ void soundmenu ()
break;
case 3:
config.hq_fm ^= 1;
if (genromsize)
#ifdef USE_SINC_BEST
config.hq_fm = (config.hq_fm + 1) % (config.fm_core ? 2 : 6);
#else
config.hq_fm = (config.hq_fm + 1) % (config.fm_core ? 2 : 5);
#endif
if (genromsize)
{
audio_init(48000);
fm_restore();
@ -182,14 +201,6 @@ void soundmenu ()
break;
case 4:
config.ssg_enabled ^= 1;
if (genromsize)
{
fm_restore();
}
break;
case 5:
config.fm_core ^= 1;
config.psg_preamp = config.fm_core ? 2.5 : 1.5;
config.fm_preamp = 1.0;

View File

@ -200,7 +200,7 @@ static void pad_update(s8 num, u8 i)
if (input.dev[i] == DEVICE_LIGHTGUN)
{
input.analog[i-4][0] += x / sensitivity;
input.analog[i-4][1] += y / sensitivity;
input.analog[i-4][1] -= y / sensitivity;
if (input.analog[i-4][0] < 0) input.analog[i-4][0] = 0;
else if (input.analog[i-4][0] > bitmap.viewport.w) input.analog[i-4][0] = bitmap.viewport.w;
if (input.analog[i-4][1] < 0) input.analog[i-4][1] = 0;
@ -211,7 +211,7 @@ static void pad_update(s8 num, u8 i)
else if ((system_hw == SYSTEM_PICO) && (i == 0))
{
input.analog[0][0] += x / sensitivity;
input.analog[0][1] += y / sensitivity;
input.analog[0][1] -= y / sensitivity;
if (input.analog[0][0] < 0x17c) input.analog[0][0] = 0x17c;
else if (input.analog[0][0] > 0x3c) input.analog[0][0] = 0x3c;
if (input.analog[0][1] < 0x1fc) input.analog[0][1] = 0x1fc;
@ -222,8 +222,8 @@ static void pad_update(s8 num, u8 i)
else if (input.dev[i] == DEVICE_MOUSE)
{
input.analog[2][0] = (x / sensitivity) * 2;
input.analog[2][1] = (x / sensitivity) * 2;
if (!config.invert_mouse) input.analog[2][1] = 0 - input.analog[2][1];
input.analog[2][1] = (y / sensitivity) * 2;
if (config.invert_mouse) input.analog[2][1] = 0 - input.analog[2][1];
}
/* GAMEPAD directional buttons */
@ -435,7 +435,7 @@ static void wpad_update(s8 num, u8 i, u32 exp)
{
/* analog stick */
input.analog[i-4][0] += x / sensitivity;
input.analog[i-4][1] += y / sensitivity;
input.analog[i-4][1] -= y / sensitivity;
if (input.analog[i-4][0] < 0) input.analog[i-4][0] = 0;
else if (input.analog[i-4][0] > bitmap.viewport.w) input.analog[i-4][0] = bitmap.viewport.w;
if (input.analog[i-4][1] < 0) input.analog[i-4][1] = 0;
@ -462,7 +462,7 @@ static void wpad_update(s8 num, u8 i, u32 exp)
{
/* analog stick */
input.analog[0][0] += x / sensitivity;
input.analog[0][1] += y / sensitivity;
input.analog[0][1] -= y / sensitivity;
if (input.analog[0][0] < 0x17c) input.analog[0][0] = 0x17c;
else if (input.analog[0][0] > 0x3c) input.analog[0][0] = 0x3c;
if (input.analog[0][1] < 0x1fc) input.analog[0][1] = 0x1fc;
@ -487,7 +487,7 @@ static void wpad_update(s8 num, u8 i, u32 exp)
{
/* analog stick */
input.analog[2][0] = x * 2 / sensitivity;
input.analog[2][1] = y * 2 / sensitivity;
input.analog[2][1] = 0 - y * 2 / sensitivity;
if (exp != WPAD_EXP_CLASSIC)
{
@ -528,6 +528,11 @@ static void wpad_update(s8 num, u8 i, u32 exp)
old_y = ir.y;
}
}
else
{
old_x -= input.analog[2][0];
old_y -= input.analog[2][1];
}
}
if (!config.invert_mouse) input.analog[2][1] = 0 - input.analog[2][1];

1
source/sound/SRC/AUTHORS Normal file
View File

@ -0,0 +1 @@
Erik de Castro Lopo <erikd@mega-nerd.com>

340
source/sound/SRC/COPYING Normal file
View File

@ -0,0 +1,340 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
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 promoting the sharing and reuse of software generally.
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
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
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
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
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
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
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
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.

23
source/sound/SRC/NEWS Normal file
View File

@ -0,0 +1,23 @@
Version 0.1.4 (2008-07-02)
* Fix bug which causes a segfault with extremely low conversion ratios.
Version 0.1.3 (2008-03-23)
* Huge improvement to the quality of conversion with the
SRC_SINC_MEDIUM_QUALITY and SRC_SINC_BEST_QUALITY converters.
* Minor bug fixes.
Version 0.1.2 (2004-09-12)
* Fixed where callback based API wasn't being reset properly.
* Minor bug fixes.
Version 0.1.1 (2004-07-17)
* Fixed bug in callback based API.
* Fixed a bug brought to light by aggressive optimisations of gcc-3.4.
* Minor bug fixes.
Version 0.1.0 (2004-03-14)
* Added callback based API.
* Added a pair of functions for doing short to float and float to short
conversions on an arrays of data.
* Many minor bug fixes.

50
source/sound/SRC/README Normal file
View File

@ -0,0 +1,50 @@
This is libsamplerate, 0.1.4
libsamplerate (also known as Secret Rabbit Code) is a library for
perfroming sample rate conversion of audio data.
The src/ directory contains the source code for library itself.
The doc/ directory contains the libsamplerate documentation.
The examples/ directory contains examples of how to write code using
libsamplerate.
The tests/ directory contains programs which link against
libsamplerate and test its functionality.
The Win32/ directory contains files and documentation to allow
libsamplerate to compile under Win32 with the Microsoft Visual C++
compiler.
Win32
-----
There are detailed instructions for building libsamplerate on Win32
in the file
doc/win32.html
MacOSX
------
Building on MacOSX should be the same as building it on any other
Unix.
OTHER PLATFORMS
---------------
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
the following three commands :
./configure
make
make install
CONTACTS
--------
libsamplerate was written by Erik de Castro Lopo (erikd AT mega-nerd DOT com).
The libsamplerate home page is at :
http://www.mega-nerd.com/libsamplerate/

148
source/sound/SRC/common.h Normal file
View File

@ -0,0 +1,148 @@
/*
** Copyright (C) 2002-2008 Erik de Castro Lopo <erikd@mega-nerd.com>
**
** 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.
*/
/*
** This code is part of Secret Rabibt Code aka libsamplerate. A commercial
** use license for this code is available, please see:
** http://www.mega-nerd.com/SRC/procedure.html
*/
#ifndef COMMON_H_INCLUDED
#define COMMON_H_INCLUDED
#ifdef HAVE_STDINT_H
#include <stdint.h>
#elif (SIZEOF_INT == 4)
typedef int int32_t ;
#elif (SIZEOF_LONG == 4)
typedef long int32_t ;
#endif
#define SRC_MAX_RATIO 256
#define SRC_MIN_RATIO_DIFF (1e-20)
#define MAX(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 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))
#include "samplerate.h"
enum
{ SRC_FALSE = 0,
SRC_TRUE = 1,
SRC_MODE_PROCESS = 555,
SRC_MODE_CALLBACK = 556
} ;
enum
{ SRC_ERR_NO_ERROR = 0,
SRC_ERR_MALLOC_FAILED,
SRC_ERR_BAD_STATE,
SRC_ERR_BAD_DATA,
SRC_ERR_BAD_DATA_PTR,
SRC_ERR_NO_PRIVATE,
SRC_ERR_BAD_SRC_RATIO,
SRC_ERR_BAD_PROC_PTR,
SRC_ERR_SHIFT_BITS,
SRC_ERR_FILTER_LEN,
SRC_ERR_BAD_CONVERTER,
SRC_ERR_BAD_CHANNEL_COUNT,
SRC_ERR_SINC_BAD_BUFFER_LEN,
SRC_ERR_SIZE_INCOMPATIBILITY,
SRC_ERR_BAD_PRIV_PTR,
SRC_ERR_BAD_SINC_STATE,
SRC_ERR_DATA_OVERLAP,
SRC_ERR_BAD_CALLBACK,
SRC_ERR_BAD_MODE,
SRC_ERR_NULL_CALLBACK,
SRC_ERR_NO_VARIABLE_RATIO,
/* This must be the last error number. */
SRC_ERR_MAX_ERROR
} ;
typedef struct SRC_PRIVATE_tag
{ double last_ratio, last_position ;
int error ;
int channels ;
/* SRC_MODE_PROCESS or SRC_MODE_CALLBACK */
int mode ;
/* Pointer to data to converter specific data. */
void *private_data ;
/* Varispeed process function. */
int (*vari_process) (struct SRC_PRIVATE_tag *psrc, SRC_DATA *data) ;
/* Constant speed process function. */
int (*const_process) (struct SRC_PRIVATE_tag *psrc, SRC_DATA *data) ;
/* State reset. */
void (*reset) (struct SRC_PRIVATE_tag *psrc) ;
/* Data specific to SRC_MODE_CALLBACK. */
src_callback_t callback_func ;
void *user_callback_data ;
long saved_frames ;
float *saved_data ;
} SRC_PRIVATE ;
/* In src_sinc.c */
const char* sinc_get_name (int src_enum) ;
const char* sinc_get_description (int src_enum) ;
int sinc_set_converter (SRC_PRIVATE *psrc, int src_enum) ;
/* In src_linear.c */
const char* linear_get_name (int src_enum) ;
const char* linear_get_description (int src_enum) ;
int linear_set_converter (SRC_PRIVATE *psrc, int src_enum) ;
/* In src_zoh.c */
const char* zoh_get_name (int src_enum) ;
const char* zoh_get_description (int src_enum) ;
int zoh_set_converter (SRC_PRIVATE *psrc, int src_enum) ;
/*----------------------------------------------------------
** Common static inline functions.
*/
static inline double
fmod_one (double x)
{ double res ;
res = x - lrint (x) ;
if (res < 0.0)
return res + 1.0 ;
return res ;
} /* fmod_one */
#endif /* COMMON_H_INCLUDED */

139
source/sound/SRC/config.h Normal file
View File

@ -0,0 +1,139 @@
/* src/config.h.in. Generated from configure.ac by autoheader. */
/* Set to 1 if the compile is GNU GCC. */
#undef COMPILER_IS_GCC
/* Target processor clips on negative float to int conversion. */
#define CPU_CLIPS_NEGATIVE 0
/* Target processor clips on positive float to int conversion. */
#define CPU_CLIPS_POSITIVE 0
/* Target processor is big endian. */
#undef CPU_IS_BIG_ENDIAN
/* Target processor is little endian. */
#undef CPU_IS_LITTLE_ENDIAN
/* Major version of GCC or 3 otherwise. */
#undef GCC_MAJOR_VERSION
/* Define to 1 if you have the `alarm' function. */
#undef HAVE_ALARM
/* Define to 1 if you have the `calloc' function. */
#undef HAVE_CALLOC
/* Define to 1 if you have the `ceil' function. */
#undef HAVE_CEIL
/* Define to 1 if you have the <dlfcn.h> header file. */
#undef HAVE_DLFCN_H
/* Set to 1 if you have libfftw3. */
#undef HAVE_FFTW3
/* Define to 1 if you have the `floor' function. */
#undef HAVE_FLOOR
/* Define to 1 if you have the `fmod' function. */
#undef HAVE_FMOD
/* Define to 1 if you have the `free' function. */
#undef HAVE_FREE
/* Define to 1 if you have the <inttypes.h> header file. */
#undef HAVE_INTTYPES_H
/* Define to 1 if you have the `m' library (-lm). */
#undef HAVE_LIBM
/* Define if you have C99's lrint function. */
#define HAVE_LRINT 0
/* Define if you have C99's lrintf function. */
#define HAVE_LRINTF 0
/* Define to 1 if you have the `malloc' function. */
#undef HAVE_MALLOC
/* Define to 1 if you have the `memcpy' function. */
#undef HAVE_MEMCPY
/* Define to 1 if you have the `memmove' function. */
#undef HAVE_MEMMOVE
/* Define to 1 if you have the <memory.h> header file. */
#undef HAVE_MEMORY_H
/* Define if you have signal SIGALRM. */
#undef HAVE_SIGALRM
/* Define to 1 if you have the `signal' function. */
#undef HAVE_SIGNAL
/* Set to 1 if you have libsndfile. */
#undef HAVE_SNDFILE
/* Define to 1 if you have the <stdint.h> header file. */
#define HAVE_STDINT_H 1
/* Define to 1 if you have the <stdlib.h> header file. */
#undef HAVE_STDLIB_H
/* Define to 1 if you have the <strings.h> header file. */
#undef HAVE_STRINGS_H
/* Define to 1 if you have the <string.h> header file. */
#undef HAVE_STRING_H
/* Define to 1 if you have the <sys/stat.h> header file. */
#undef HAVE_SYS_STAT_H
/* Define to 1 if you have the <sys/times.h> header file. */
#undef HAVE_SYS_TIMES_H
/* Define to 1 if you have the <sys/types.h> header file. */
#undef HAVE_SYS_TYPES_H
/* Define to 1 if you have the <unistd.h> header file. */
#undef HAVE_UNISTD_H
/* Set to 1 if compiling for Win32 */
#undef OS_IS_WIN32
/* Name of package */
#define PACKAGE "OGC"
/* Define to the address where bug reports for this package should be sent. */
#undef PACKAGE_BUGREPORT
/* Define to the full name of this package. */
#undef PACKAGE_NAME
/* Define to the full name and version of this package. */
#undef PACKAGE_STRING
/* Define to the one symbol short name of this package. */
#undef PACKAGE_TARNAME
/* Define to the version of this package. */
#undef PACKAGE_VERSION
/* The size of `double', as computed by sizeof. */
#undef SIZEOF_DOUBLE
/* The size of `float', as computed by sizeof. */
#undef SIZEOF_FLOAT
/* The size of `int', as computed by sizeof. */
#undef SIZEOF_INT
/* The size of `long', as computed by sizeof. */
#undef SIZEOF_LONG
/* Define to 1 if you have the ANSI C header files. */
#undef STDC_HEADERS
/* Version number of package */
#define VERSION "0.1.4"

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,255 @@
/*
** Copyright (C) 2001-2008 Erik de Castro Lopo <erikd@mega-nerd.com>
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU Lesser General Public License as published by
** the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser 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.
*/
/* Version 1.4 */
#ifndef FLOAT_CAST_HEADER
#define FLOAT_CAST_HEADER
/*============================================================================
** 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
** most C compilers targeting Pentium needs to change the FPU rounding mode
** before the float to int conversion is performed.
**
** Changing the FPU rounding mode causes the FPU pipeline to be flushed. It
** is this flushing of the pipeline which is so slow.
**
** Fortunately the ISO C99 specifications define the functions lrint, lrintf,
** llrint and llrintf which fix this problem as a side effect.
**
** 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
** here with a standard C cast.
*/
/*
** The C99 prototypes for lrint and lrintf are as follows:
**
** long int lrintf (float x) ;
** long int lrint (double x) ;
*/
#include "config.h"
/*
** The presence of the required functions are detected during the configure
** process and the values HAVE_LRINT and HAVE_LRINTF are set accordingly in
** the config.h file.
*/
#define HAVE_LRINT_REPLACEMENT 0
#if (HAVE_LRINT && HAVE_LRINTF)
/*
** These defines enable functionality introduced with the 1999 ISO C
** standard. They must be defined before the inclusion of math.h to
** engage them. If optimisation is enabled, these functions will be
** inlined. With optimisation switched off, you have to link in the
** maths library using -lm.
*/
#define _ISOC9X_SOURCE 1
#define _ISOC99_SOURCE 1
#define __USE_ISOC9X 1
#define __USE_ISOC99 1
#include <math.h>
#elif (defined (__CYGWIN__))
#include <math.h>
#undef HAVE_LRINT_REPLACEMENT
#define HAVE_LRINT_REPLACEMENT 1
#undef lrint
#undef lrintf
#define lrint double2int
#define lrintf float2int
/*
** The native CYGWIN lrint and lrintf functions are buggy:
** http://sourceware.org/ml/cygwin/2005-06/msg00153.html
** http://sourceware.org/ml/cygwin/2005-09/msg00047.html
** and slow.
** These functions (pulled from the Public Domain MinGW math.h header)
** replace the native versions.
*/
static inline long double2int (double in)
{ long retval ;
__asm__ __volatile__
( "fistpl %0"
: "=m" (retval)
: "t" (in)
: "st"
) ;
return retval ;
} /* double2int */
static inline long float2int (float in)
{ long retval ;
__asm__ __volatile__
( "fistpl %0"
: "=m" (retval)
: "t" (in)
: "st"
) ;
return retval ;
} /* float2int */
#elif (defined (WIN32) || defined (_WIN32))
#undef HAVE_LRINT_REPLACEMENT
#define HAVE_LRINT_REPLACEMENT 1
#include <math.h>
/*
** Win32 doesn't seem to have these functions.
** Therefore implement inline versions of these functions here.
*/
__inline long int
lrint (double flt)
{ int intgr ;
_asm
{ fld flt
fistp intgr
} ;
return intgr ;
}
__inline long int
lrintf (float flt)
{ int intgr ;
_asm
{ fld flt
fistp intgr
} ;
return intgr ;
}
#elif (defined (__MWERKS__) && defined (macintosh))
/* This MacOS 9 solution was provided by Stephane Letz */
#undef HAVE_LRINT_REPLACEMENT
#define HAVE_LRINT_REPLACEMENT 1
#include <math.h>
#undef lrint
#undef lrintf
#define lrint double2int
#define lrintf float2int
inline int
float2int (register float in)
{ long res [2] ;
asm
{ fctiw in, in
stfd in, res
}
return res [1] ;
} /* float2int */
inline int
double2int (register double in)
{ long res [2] ;
asm
{ fctiw in, in
stfd in, res
}
return res [1] ;
} /* double2int */
#elif (defined (__MACH__) && defined (__APPLE__))
/* For Apple MacOSX. */
#undef HAVE_LRINT_REPLACEMENT
#define HAVE_LRINT_REPLACEMENT 1
#include <math.h>
#undef lrint
#undef lrintf
#define lrint double2int
#define lrintf float2int
inline static long
float2int (register float in)
{ int res [2] ;
__asm__ __volatile__
( "fctiw %1, %1\n\t"
"stfd %1, %0"
: "=m" (res) /* Output */
: "f" (in) /* Input */
: "memory"
) ;
return res [1] ;
} /* lrintf */
inline static long
double2int (register double in)
{ int res [2] ;
__asm__ __volatile__
( "fctiw %1, %1\n\t"
"stfd %1, %0"
: "=m" (res) /* Output */
: "f" (in) /* Input */
: "memory"
) ;
return res [1] ;
} /* lrint */
#else
#ifndef __sgi
#warning "Don't have the functions lrint() and lrintf()."
#warning "Replacing these functions with a standard C cast."
#endif
#include <math.h>
#define lrint(dbl) ((long) (dbl))
#define lrintf(flt) ((long) (flt))
#endif
#endif /* FLOAT_CAST_HEADER */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -0,0 +1,197 @@
/*
** Copyright (C) 2002-2008 Erik de Castro Lopo <erikd@mega-nerd.com>
**
** 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.
*/
/*
** This code is part of Secret Rabibt Code aka libsamplerate. A commercial
** use license for this code is available, please see:
** http://www.mega-nerd.com/SRC/procedure.html
*/
/*
** API documentation is available here:
** http://www.mega-nerd.com/SRC/api.html
*/
#ifndef SAMPLERATE_H
#define SAMPLERATE_H
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/* Opaque data type SRC_STATE. */
typedef struct SRC_STATE_tag SRC_STATE ;
/* SRC_DATA is used to pass data to src_simple() and src_process(). */
typedef struct
{ float *data_in, *data_out ;
long input_frames, output_frames ;
long input_frames_used, output_frames_gen ;
int end_of_input ;
double src_ratio ;
} SRC_DATA ;
/* SRC_CB_DATA is used with callback based API. */
typedef struct
{ long frames ;
float *data_in ;
} SRC_CB_DATA ;
/*
** User supplied callback function type for use with src_callback_new()
** and src_callback_read(). First parameter is the same pointer that was
** passed into src_callback_new(). Second parameter is pointer to a
** pointer. The user supplied callback function must modify *data to
** point to the start of the user supplied float array. The user supplied
** function must return the number of frames that **data points to.
*/
typedef long (*src_callback_t) (void *cb_data, float **data) ;
/*
** Standard initialisation function : return an anonymous pointer to the
** internal state of the converter. Choose a converter from the enums below.
** Error returned in *error.
*/
SRC_STATE* src_new (int converter_type, int channels, int *error) ;
/*
** Initilisation for callback based API : return an anonymous pointer to the
** 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
** value, when processing, user supplied function "func" gets called with
** cb_data as first parameter.
*/
SRC_STATE* src_callback_new (src_callback_t func, int converter_type, int channels,
int *error, void* cb_data) ;
/*
** Cleanup all internal allocations.
** Always returns NULL.
*/
SRC_STATE* src_delete (SRC_STATE *state) ;
/*
** Standard processing function.
** Returns non zero on error.
*/
int src_process (SRC_STATE *state, SRC_DATA *data) ;
/*
** Callback based processing function. Read up to frames worth of data from
** 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) ;
/*
** Simple interface for performing a single conversion from input buffer to
** output buffer at a fixed conversion ratio.
** Simple interface does not require initialisation as it can only operate on
** a single buffer worth of audio.
*/
int src_simple (SRC_DATA *data, int converter_type, int channels) ;
/*
** This library contains a number of different sample rate converters,
** numbered 0 through N.
**
** Return a string giving either a name or a more full description of each
** sample rate converter or NULL if no sample rate converter exists for
** the given value. The converters are sequentially numbered from 0 to N.
*/
const char *src_get_name (int converter_type) ;
const char *src_get_description (int converter_type) ;
const char *src_get_version (void) ;
/*
** Set a new SRC ratio. This allows step responses
** in the conversion ratio.
** Returns non zero on error.
*/
int src_set_ratio (SRC_STATE *state, double new_ratio) ;
/*
** Reset the internal SRC state.
** Does not modify the quality settings.
** Does not free any memory allocations.
** Returns non zero on error.
*/
int src_reset (SRC_STATE *state) ;
/*
** Return TRUE if ratio is a valid conversion ratio, FALSE
** otherwise.
*/
int src_is_valid_ratio (double ratio) ;
/*
** Return an error number.
*/
int src_error (SRC_STATE *state) ;
/*
** Convert the error number into a string.
*/
const char* src_strerror (int error) ;
/*
** The following enums can be used to set the interpolator type
** using the function src_set_converter().
*/
enum
{
SRC_SINC_BEST_QUALITY = 0,
SRC_SINC_MEDIUM_QUALITY = 1,
SRC_SINC_FASTEST = 2,
SRC_ZERO_ORDER_HOLD = 3,
SRC_LINEAR = 4,
} ;
/*
** Extra helper functions for converting from short to float and
** back again.
*/
void src_short_to_float_array (const short *in, float *out, int len) ;
void src_float_to_short_array (const float *in, short *out, int len) ;
void src_int_to_float_array (const int *in, float *out, int len) ;
void src_float_to_int_array (const float *in, int *out, int len) ;
#ifdef __cplusplus
} /* extern "C" */
#endif /* __cplusplus */
#endif /* SAMPLERATE_H */

View File

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

476
source/sound/SRC/src_sinc.c Normal file
View File

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

211
source/sound/SRC/src_zoh.c Normal file
View File

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

View File

@ -18,7 +18,6 @@
** - removed unused multichip support and YMxxx support
** - fixed CH3 CSM mode (credits to Nemesis)
** - implemented PG overflow, aka "detune bug" (Ariel, Comix Zone, Shaq Fu, Spiderman,...), credits to Nemesis
** - implemented sample interpolation, highly based on GENS code (HQ YM2612)
** - fixed SSG-EG support, credits to Nemesis and additional fixes from Alone Coder
** - modified EG rates and frequency, tested by Nemesis on real hardware
** - fixed EG attenuation level on KEY ON (Ecco 2 splash sound)
@ -550,9 +549,6 @@ typedef struct
/* local time tables */
INT32 dt_tab[8][32];/* DeTune table */
// UINT32 Inter_Cnt; // Interpolation Counter
// UINT32 Inter_Step; // Interpolation Step
} FM_ST;
@ -605,14 +601,12 @@ typedef struct
} YM2612;
static YM2612 ym2612;
static long dac_highpass;
/* current chip state */
static INT32 m2,c1,c2; /* Phase Modulation input for operators 2,3,4 */
static INT32 mem; /* one sample delay memory */
static INT32 out_fm[8]; /* outputs of working channels */
static INT32 old_out_fm[8]; /* old outputs of working channels */
static UINT32 LFO_AM; /* runtime LFO calculations helper */
static INT32 LFO_PM; /* runtime LFO calculations helper */
@ -654,16 +648,17 @@ INLINE void set_timers(int v )
INLINE void FM_KEYON(FM_CH *CH , int s )
{
FM_SLOT *SLOT = &CH->SLOT[s];
if( !SLOT->key )
{
SLOT->key = 1;
//if( !SLOT->key )
if(SLOT->state <= EG_REL)
{
//SLOT->key = 1;
SLOT->phase = 0; /* restart Phase Generator */
SLOT->ssgn = (SLOT->ssg & 0x04) >> 1;
if ((SLOT->ar + SLOT->ksr) < 94 /*32+62*/)
{
SLOT->state = EG_ATT; /* phase -> Attack */
SLOT->volume = 511; /* fix Ecco 2 splash sound */
SLOT->volume = MAX_ATT_INDEX; /* fix Ecco 2 splash sound */
}
else
{
@ -677,15 +672,15 @@ INLINE void FM_KEYON(FM_CH *CH , int s )
INLINE void FM_KEYOFF(FM_CH *CH , int s )
{
FM_SLOT *SLOT = &CH->SLOT[s];
if( SLOT->key )
{
SLOT->key = 0;
//if( SLOT->key )
//{
//SLOT->key = 0;
if (SLOT->state>EG_REL)
{
SLOT->state = EG_REL; /* phase -> Release */
//SLOT->ssgn = 0; /* reset Invert Flag (from Nemesis) */
SLOT->ssgn = 0; /* reset Invert Flag (from Nemesis) */
}
}
// }
}
/* set algorithm connection */
@ -792,33 +787,16 @@ INLINE void set_tl(FM_CH *CH,FM_SLOT *SLOT , int v)
/* set attack rate & key scale */
INLINE void set_ar_ksr(FM_CH *CH,FM_SLOT *SLOT,int v)
{
UINT8 old_KSR = SLOT->KSR;
SLOT->ar = (v&0x1f) ? 32 + ((v&0x1f)<<1) : 0;
SLOT->ar = (v&0x1f) ? (32 + ((v&0x1f)<<1)) : 0;
SLOT->KSR = 3-(v>>6);
if (SLOT->KSR != old_KSR)
{
CH->SLOT[SLOT1].Incr=-1;
}
/* refresh Attack rate */
if ((SLOT->ar + SLOT->ksr) < 94 /*32+62*/)
{
SLOT->eg_sh_ar = eg_rate_shift [SLOT->ar + SLOT->ksr ];
SLOT->eg_sel_ar = eg_rate_select[SLOT->ar + SLOT->ksr ];
}
else
{
SLOT->eg_sh_ar = 0;
SLOT->eg_sel_ar = 17*RATE_STEPS;
}
CH->SLOT[SLOT1].Incr=-1;
}
/* set decay rate */
INLINE void set_dr(FM_SLOT *SLOT,int v)
{
SLOT->d1r = (v&0x1f) ? 32 + ((v&0x1f)<<1) : 0;
SLOT->d1r = (v&0x1f) ? (32 + ((v&0x1f)<<1)) : 0;
SLOT->eg_sh_d1r = eg_rate_shift [SLOT->d1r + SLOT->ksr];
SLOT->eg_sel_d1r= eg_rate_select[SLOT->d1r + SLOT->ksr];
@ -828,7 +806,7 @@ INLINE void set_dr(FM_SLOT *SLOT,int v)
/* set sustain rate */
INLINE void set_sr(FM_SLOT *SLOT,int v)
{
SLOT->d2r = (v&0x1f) ? 32 + ((v&0x1f)<<1) : 0;
SLOT->d2r = (v&0x1f) ? (32 + ((v&0x1f)<<1)) : 0;
SLOT->eg_sh_d2r = eg_rate_shift [SLOT->d2r + SLOT->ksr];
SLOT->eg_sel_d2r= eg_rate_select[SLOT->d2r + SLOT->ksr];
@ -977,7 +955,7 @@ INLINE void advance_eg_channel(FM_SLOT *SLOT)
//SLOT->volume += 4 * eg_inc[SLOT->eg_sel_d2r + ((ym2612.OPN.eg_cnt>>SLOT->eg_sh_d2r)&7)];
SLOT->volume += 6 * eg_inc[SLOT->eg_sel_d2r + ((ym2612.OPN.eg_cnt>>SLOT->eg_sh_d2r)&7)]; /* from Nemesis */
if ( SLOT->volume >= 512 /* áûëî MAX_ATT_INDEX */ ) //Alone Coder
if ( SLOT->volume >= MAX_ATT_INDEX)
{
SLOT->volume = MAX_ATT_INDEX;
@ -995,13 +973,20 @@ INLINE void advance_eg_channel(FM_SLOT *SLOT)
{
/* same as KEY-ON operation */
/* restart of the Phase Generator should be here,
only if AR is not maximum ??? ALWAYS! */
SLOT->phase = 0; //Alone Coder
/* restart of the Phase Generator should be here */
SLOT->phase = 0;
/* phase -> Attack */
SLOT->volume = 511; //Alone Coder
SLOT->state = EG_ATT;
if ((SLOT->ar + SLOT->ksr) < 94 /*32+62*/)
{
SLOT->state = EG_ATT; /* phase -> Attack */
SLOT->volume = MAX_ATT_INDEX;
}
else
{
/* Attack Rate is maximal: directly switch to Decay */
SLOT->state = EG_DEC;
SLOT->volume = MIN_ATT_INDEX;
}
swap_flag = (SLOT->ssg&0x02); /* bit 1 = alternate */
}
@ -1046,15 +1031,15 @@ INLINE void advance_eg_channel(FM_SLOT *SLOT)
}
out = SLOT->tl + ((UINT32)SLOT->volume);
out = /*SLOT->tl +*/ ((UINT32)SLOT->volume);
/* negate output (changes come from alternate bit, init comes from attack bit) */
if ((SLOT->ssg&0x08) && (SLOT->ssgn&2) && ((SLOT->state == EG_DEC) || (SLOT->state == EG_SUS)))
out ^= 511 /* Alone Coder*/; //((1<<ENV_BITS)-1); /* 1023 */
if ((SLOT->ssg&0x08) && (SLOT->ssgn&2))
out ^= MAX_ATT_INDEX;
/* we need to store the result here because we are going to change ssgn
in next instruction */
SLOT->vol_out = out;
SLOT->vol_out = out + SLOT->tl;
/* reverse SLOT inversion flag if required */
SLOT->ssgn ^= swap_flag;
@ -1235,7 +1220,7 @@ INLINE void refresh_fc_eg_slot(FM_SLOT *SLOT , int fc , int kc )
{
SLOT->ksr = ksr;
/* calculate envelope generator rates */
/* recalculate envelope generator rates */
if ((SLOT->ar + SLOT->ksr) < 94 /*32+62*/)
{
SLOT->eg_sh_ar = eg_rate_shift [SLOT->ar + SLOT->ksr ];
@ -1458,28 +1443,17 @@ static void OPNSetPres(int pres)
if (config.hq_fm)
{
//ym2612.OPN.ST.Inter_Step = (unsigned int) ((1.0 / ym2612.OPN.ST.freqbase) * (double) (0x4000));
//ym2612.OPN.ST.Inter_Cnt = 0;
//ym2612.OPN.ST.freqbase = 1.0;
ym2612.OPN.ST.rate = ym2612.OPN.ST.clock / pres;
}
//else
//{
//ym2612.OPN.ST.Inter_Step = 0x4000;
//ym2612.OPN.ST.Inter_Cnt = 0;
//}
/* frequency base */
ym2612.OPN.ST.freqbase = ((double) ym2612.OPN.ST.clock / (double) ym2612.OPN.ST.rate) / ((double) pres);
/* timer increment in usecs (timers are incremented after each updated samples) */
ym2612.OPN.ST.TimerBase = 1000000.0 / (double)ym2612.OPN.ST.rate;
ym2612.OPN.eg_timer_add = (UINT32)((1<<EG_SH) * ym2612.OPN.ST.freqbase);
//ym2612.OPN.eg_timer_overflow = ( 3 ) * (1<<EG_SH);
ym2612.OPN.eg_timer_overflow = (351 * (1<<EG_SH)) / 144; /* correct frequency (Nemesis: tested on real HW) */
@ -1603,7 +1577,6 @@ static void OPNWriteReg(int r, int v)
break;
case 0x90: /* SSG-EG */
if (!config.ssg_enabled) v = 0;
SLOT->ssg = v&0x0f;
SLOT->ssgn = (v&0x04)>>1; /* bit 1 in ssgn = attack */
@ -1752,9 +1725,6 @@ static void OPNWriteReg(int r, int v)
}
/* Generate 32bits samples for ym2612 */
static long dac;
//int int_cnt; // Interpolation calculation
void YM2612UpdateOne(int **buffer, int length)
{
int i;
@ -1786,8 +1756,6 @@ void YM2612UpdateOne(int **buffer, int length)
refresh_fc_eg_chan(&ym2612.CH[4]);
refresh_fc_eg_chan(&ym2612.CH[5]);
//int_cnt = ym2612.OPN.ST.Inter_Cnt;
/* buffering */
for(i=0; i < length ; i++)
{
@ -1826,93 +1794,37 @@ void YM2612UpdateOne(int **buffer, int length)
/* DAC Mode */
if (ym2612.dacen)
{
/* High Pass Filter */
dac = (ym2612.dacout << 15) - dac_highpass;
dac_highpass += dac >> 9;
dac >>= 15;
*(ym2612.CH[5].connect4) += (int)dac;/**/
*(ym2612.CH[5].connect4) += ym2612.dacout;
}
else chan_calc(&ym2612.CH[5]);
#if 0
if (config.hq_fm)
{
if ((int_cnt += ym2612.OPN.ST.Inter_Step) & 0x04000)
{
int_cnt &= 0x3FFF;
old_out_fm[0] = (((int_cnt ^ 0x3FFF) * out_fm[0]) + (int_cnt * old_out_fm[0])) >> 14;
old_out_fm[1] = (((int_cnt ^ 0x3FFF) * out_fm[1]) + (int_cnt * old_out_fm[1])) >> 14;
old_out_fm[2] = (((int_cnt ^ 0x3FFF) * out_fm[2]) + (int_cnt * old_out_fm[2])) >> 14;
old_out_fm[3] = (((int_cnt ^ 0x3FFF) * out_fm[3]) + (int_cnt * old_out_fm[3])) >> 14;
old_out_fm[4] = (((int_cnt ^ 0x3FFF) * out_fm[4]) + (int_cnt * old_out_fm[4])) >> 14;
old_out_fm[5] = (((int_cnt ^ 0x3FFF) * out_fm[5]) + (int_cnt * old_out_fm[5])) >> 14;
lt = ((out_fm[0]>>0) & ym2612.OPN.pan[0]);
rt = ((out_fm[0]>>0) & ym2612.OPN.pan[1]);
lt += ((out_fm[1]>>0) & ym2612.OPN.pan[2]);
rt += ((out_fm[1]>>0) & ym2612.OPN.pan[3]);
lt += ((out_fm[2]>>0) & ym2612.OPN.pan[4]);
rt += ((out_fm[2]>>0) & ym2612.OPN.pan[5]);
lt += ((out_fm[3]>>0) & ym2612.OPN.pan[6]);
rt += ((out_fm[3]>>0) & ym2612.OPN.pan[7]);
lt += ((out_fm[4]>>0) & ym2612.OPN.pan[8]);
rt += ((out_fm[4]>>0) & ym2612.OPN.pan[9]);
lt += ((out_fm[5]>>0) & ym2612.OPN.pan[10]);
rt += ((out_fm[5]>>0) & ym2612.OPN.pan[11]);
lt = ((old_out_fm[0]>>0) & ym2612.OPN.pan[0]);
rt = ((old_out_fm[0]>>0) & ym2612.OPN.pan[1]);
lt += ((old_out_fm[1]>>0) & ym2612.OPN.pan[2]);
rt += ((old_out_fm[1]>>0) & ym2612.OPN.pan[3]);
lt += ((old_out_fm[2]>>0) & ym2612.OPN.pan[4]);
rt += ((old_out_fm[2]>>0) & ym2612.OPN.pan[5]);
lt += ((old_out_fm[3]>>0) & ym2612.OPN.pan[6]);
rt += ((old_out_fm[3]>>0) & ym2612.OPN.pan[7]);
lt += ((old_out_fm[4]>>0) & ym2612.OPN.pan[8]);
rt += ((old_out_fm[4]>>0) & ym2612.OPN.pan[9]);
lt += ((old_out_fm[5]>>0) & ym2612.OPN.pan[10]);
rt += ((old_out_fm[5]>>0) & ym2612.OPN.pan[11]);
/* limiter */
Limit(lt,MAXOUT,MINOUT);
Limit(rt,MAXOUT,MINOUT);
/* limiter */
Limit(lt,MAXOUT,MINOUT);
Limit(rt,MAXOUT,MINOUT);
/* buffering */
bufL[i] = lt;
bufR[i] = rt;
/* buffering */
bufL[i] = lt;
bufR[i] = rt;
/* timer A control */
INTERNAL_TIMER_A();
}
else i--;
old_out_fm[0] = out_fm[0];
old_out_fm[1] = out_fm[1];
old_out_fm[2] = out_fm[2];
old_out_fm[3] = out_fm[3];
old_out_fm[4] = out_fm[4];
old_out_fm[5] = out_fm[5];
}
else
#endif
{
lt = ((out_fm[0]>>0) & ym2612.OPN.pan[0]);
rt = ((out_fm[0]>>0) & ym2612.OPN.pan[1]);
lt += ((out_fm[1]>>0) & ym2612.OPN.pan[2]);
rt += ((out_fm[1]>>0) & ym2612.OPN.pan[3]);
lt += ((out_fm[2]>>0) & ym2612.OPN.pan[4]);
rt += ((out_fm[2]>>0) & ym2612.OPN.pan[5]);
lt += ((out_fm[3]>>0) & ym2612.OPN.pan[6]);
rt += ((out_fm[3]>>0) & ym2612.OPN.pan[7]);
lt += ((out_fm[4]>>0) & ym2612.OPN.pan[8]);
rt += ((out_fm[4]>>0) & ym2612.OPN.pan[9]);
lt += ((out_fm[5]>>0) & ym2612.OPN.pan[10]);
rt += ((out_fm[5]>>0) & ym2612.OPN.pan[11]);
/* limiter */
Limit(lt,MAXOUT,MINOUT);
Limit(rt,MAXOUT,MINOUT);
/* buffering */
bufL[i] = lt;
bufR[i] = rt;
/* timer A control */
INTERNAL_TIMER_A();
}
/* timer A control */
INTERNAL_TIMER_A();
}
INTERNAL_TIMER_B(length);
//ym2612.OPN.ST.Inter_Cnt = int_cnt;
}
/* initialize ym2612 emulator(s) */
@ -1962,15 +1874,6 @@ int YM2612ResetChip(void)
/* DAC mode clear */
ym2612.dacen = 0;
ym2612.dacout = 0;
dac_highpass = 0;
/* clear outputs */
old_out_fm[0] = 0;
old_out_fm[1] = 0;
old_out_fm[2] = 0;
old_out_fm[3] = 0;
old_out_fm[4] = 0;
old_out_fm[5] = 0;
return 0;
}

View File

@ -33,11 +33,10 @@ int (*_YM2612_Reset)(void);
static double m68cycles_per_sample[2];
static double z80cycles_per_sample[2];
static float fm_buffer_48kHz[960*2];
static float fm_buffer_53kHz[1060*2];
static int fm_buffer[2][1060];
/* libsamplerate buffers */
static float fm_buffer_48kHz[1000*2];
static float fm_buffer_53kHz[1061*2];
static int fm_buffer[2][1061];
static SRC_DATA data;
/* YM2612 data */
@ -61,7 +60,7 @@ static inline uint32 psg_sample_cnt(uint8 is_z80)
/* update FM samples */
static inline void fm_update()
{
if(snd.fm.curStage - snd.fm.lastStage > 1)
if(snd.fm.curStage - snd.fm.lastStage > 0)
{
int *tempBuffer[2];
@ -84,7 +83,7 @@ static inline void fm_update()
/* update PSG samples */
static inline void psg_update()
{
if(snd.psg.curStage - snd.psg.lastStage > 1)
if(snd.psg.curStage - snd.psg.lastStage > 0)
{
int16 *tempBuffer = snd.psg.buffer + snd.psg.lastStage;
SN76489_Update (0, tempBuffer, snd.psg.curStage - snd.psg.lastStage);
@ -109,15 +108,15 @@ void sound_init(int rate)
/* cycle-accurate FM samples */
if (config.hq_fm && !config.fm_core)
{
m68cycles_per_sample[0] = 144;
z80cycles_per_sample[0] = (144 * 7) / 15;
m68cycles_per_sample[0] = 144.0;
z80cycles_per_sample[0] = (144.0 * 7.0) / 15.0;
/* set samplerate converter data */
data.data_in = fm_buffer_53kHz;
data.data_out = fm_buffer_48kHz;
data.input_frames = vdp_pal ? 1060 : 888;
data.output_frames = vdp_pal ? 960 : 800;
data.src_ratio = 48000.0 / (vdp_pal ? 52781.0 : 53267.0);
/* initialize samplerate converter data */
data.data_in = fm_buffer_53kHz;
data.data_out = fm_buffer_48kHz;
data.input_frames = vdp_pal ? 1061 : 888;
data.output_frames = 1000;
data.src_ratio = vdp_pal ? (960.0/1061.0) : (800.0/888.0);
}
else
{
@ -154,7 +153,7 @@ void sound_init(int rate)
void sound_update(void)
{
/* finalize sound buffers */
snd.fm.curStage = snd.buffer_size;
snd.fm.curStage = (config.hq_fm && !config.fm_core) ? data.input_frames : snd.buffer_size;
snd.psg.curStage = snd.buffer_size;
/* update last samples (if needed) */
@ -165,7 +164,7 @@ void sound_update(void)
if (config.hq_fm && !config.fm_core)
{
double scaled_value ;
int len = vdp_pal ? 1060 : 888;
int len = data.input_frames;
/* this is basically libsamplerate "src_int_to_float_array" function, adapted to interlace samples */
while (len)
@ -176,7 +175,7 @@ void sound_update(void)
}
/* samplerate conversion */
src_simple (&data, SRC_SINC_FASTEST, 2);
src_simple (&data, 5 - config.hq_fm, 2);
/* this is basically libsamplerate "src_float_to_int_array" function, adapted to interlace samples */
len = vdp_pal ? 960 : 800;

View File

@ -524,16 +524,13 @@ int SLOT_SET(int Adr, unsigned char data)
// Al = Altern
// H = Hold
*/
if (config.ssg_enabled)
{
if (data & 0x08) SL->SEG = data & 0x0F;
else SL->SEG = 0;
if (data & 0x08) SL->SEG = data & 0x0F;
else SL->SEG = 0;
#if YM_DEBUG_LEVEL > 1
fprintf(debug_file, "CHANNEL[%d], SLOT[%d] SSG-EG = %.2X\n", nch, nsl, data);
#endif
}
break;
break;
}
return 0;
@ -841,8 +838,6 @@ void Env_Decay_Next(slot_ *SL)
void Env_Substain_Next(slot_ *SL)
{
if (config.ssg_enabled)
{
if (SL->SEG & 8) // SSG envelope type
{
if (SL->SEG & 1)
@ -870,13 +865,6 @@ void Env_Substain_Next(slot_ *SL)
SL->Einc = 0;
SL->Ecmp = ENV_END + 1;
}
}
else
{
SL->Ecnt = ENV_END;
SL->Einc = 0;
SL->Ecmp = ENV_END + 1;
}
}

View File

@ -99,7 +99,6 @@ void set_config_default()
config.boost = 1;
config.hq_fm = 1;
config.fm_core = 0;
config.ssg_enabled = 0;
/* system options */
config.freeze_auto = -1;

View File

@ -50,12 +50,12 @@ typedef struct
typedef struct
{
char[10] version;
double psg_preamp;
double fm_preamp;
uint8 boost;
uint8 hq_fm;
uint8 fm_core;
uint8 ssg_enabled;
int8 sram_auto;
int8 freeze_auto;
uint8 region_detect;

View File

@ -16,15 +16,12 @@ uint8 overscan = 1;
uint8 use_480i = 1;
uint8 FM_GENS = 1;
uint8 hq_fm = 1;
uint8 ssg_enabled = 0;
double psg_preamp = 0.5;
double fm_preamp = 1.0;
uint8 boost = 1;
uint8 region_detect = 0;
uint8 sys_type[2] = {0,0};
uint8 force_dtack = 0;
uint8 dmatiming = 1;
uint8 vdptiming = 1;
uint8 log_error = 1;
uint8 debug_on = 0;

View File

@ -7,15 +7,12 @@ extern uint8 overscan;
extern uint8 use_480i;
extern uint8 FM_GENS;
extern uint8 hq_fm;
extern uint8 ssg_enabled;
extern double psg_preamp;
extern double fm_preamp;
extern uint8 boost;
extern uint8 region_detect;
extern uint8 sys_type[2];
extern uint8 force_dtack;
extern uint8 dmatiming;
extern uint8 vdptiming;
extern uint8 debug_on;
extern uint8 log_error;

1301
source/unzip.c Normal file

File diff suppressed because it is too large Load Diff

274
source/unzip.h Normal file
View File

@ -0,0 +1,274 @@
/* 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

@ -91,10 +91,6 @@ static uint16 sat_addr_mask; /* Index bits of SAT */
static uint32 dma_endCycles; /* 68k cycles to DMA end */
static uint8 dma_type; /* Type of DMA */
/* TODO: set as default */
static uint8 dmatiming = 1;
static uint8 vdptiming = 1;
/* DMA Timings
According to the manual, here's a table that describes the transfer
@ -252,21 +248,9 @@ void vdp_restore(uint8 *vdp_regs)
bitmap.viewport.y = config.overscan ? (((reg[1] & 8) ? 0 : 8) + (vdp_pal ? 24 : 0)) : 0;
bitmap.viewport.changed = 1;
/* restore VDP FIFO timings */
if (vdptiming)
{
/* VDP timings:
------------
HDISP is 256*10/7 = approx. 366 cycles (same for both modes)
this gives:
H32: 16 accesses --> 366/16 = 23 cycles per access
H40: 20 accesses --> 366/20 = 18 cycles per access
VRAM access are byte wide --> VRAM writes takes 2x CPU cycles
*/
fifo_latency = (reg[12] & 1) ? 27 : 30;
if ((code & 0x0F) == 0x01) fifo_latency = fifo_latency * 2;
}
/* restore VDP timings */
fifo_latency = (reg[12] & 1) ? 27 : 30;
if ((code & 0x0F) == 0x01) fifo_latency = fifo_latency * 2;
/* remake cache */
for (i=0;i<0x800;i++)
@ -292,8 +276,6 @@ void dma_update()
uint32 dma_cycles, dma_bytes;
uint8 index = 0;
if (!dmatiming) return;
/* get the appropriate tranfer rate (bytes/line) for this DMA operation */
if ((status&8) || !(reg[1] & 0x40)) index = 2; /* VBLANK or Display OFF */
index += (reg[12] & 1); /* 32 or 40 Horizontal Cells */
@ -570,21 +552,17 @@ void vdp_ctrl_w(unsigned int data)
}
}
/* FIFO emulation */
if (vdptiming)
{
/* VDP timings:
------------
HDISP is 256*10/7 = approx. 366 cycles (same for both modes)
this gives:
H32: 16 accesses --> 366/16 = 23 cycles per access
H40: 20 accesses --> 366/20 = 18 cycles per access
/* FIFO emulation:
---------------
HDISP is 256*10/7 = approx. 366 cycles (same for both modes)
this gives:
H32: 16 accesses --> 366/16 = 23 cycles per access
H40: 20 accesses --> 366/20 = 18 cycles per access
VRAM access are byte wide --> VRAM writes takes 2x CPU cycles
*/
fifo_latency = (reg[12] & 1) ? 27 : 30;
if ((code & 0x0F) == 0x01) fifo_latency = fifo_latency * 2;
}
VRAM access are byte wide --> VRAM writes takes 2x CPU cycles
*/
fifo_latency = (reg[12] & 1) ? 27 : 30;
if ((code & 0x0F) == 0x01) fifo_latency = fifo_latency * 2;
}
@ -607,15 +585,12 @@ unsigned int vdp_ctrl_r(void)
* 10 - 15 Next word on bus
*/
/* update FIFO flags */
if (vdptiming)
{
fifo_update();
if (fifo_write_cnt < 4)
{
status &= 0xFEFF;
if (fifo_write_cnt == 0) status |= 0x200;
}
/* update FIFO flags */
fifo_update();
if (fifo_write_cnt < 4)
{
status &= 0xFEFF;
if (fifo_write_cnt == 0) status |= 0x200;
}
else status ^= 0x200;
@ -651,26 +626,28 @@ void vdp_data_w(unsigned int data)
return;
}
/* VDP latency (Chaos Engine, Soldiers of Fortune) */
if (vdptiming && !(status&8) && (reg[1]&0x40))
{
fifo_update();
if (fifo_write_cnt == 0)
{
fifo_lastwrite = count_m68k; /* reset cycle counter */
status &= 0xFDFF; /* FIFO is not empty anymore */
}
/* FIFO emulation */
fifo_update();
if (fifo_write_cnt == 0)
{
/* reset cycle counter */
fifo_lastwrite = count_m68k;
/* FIFO is not empty anymore */
status &= 0xFDFF;
}
/* increase write counter */
fifo_write_cnt ++;
/* increase write counter */
fifo_write_cnt ++;
/* is FIFO full ? */
if (fifo_write_cnt >= 4)
{
status |= 0x100;
if (fifo_write_cnt > 4) count_m68k = fifo_lastwrite + fifo_latency;
}
}
/* is FIFO full ? */
if (fifo_write_cnt >= 4)
{
status |= 0x100;
/* VDP latency (Chaos Engine, Soldiers of Fortune, Double Clutch) */
if (fifo_write_cnt > 4) count_m68k = fifo_lastwrite + fifo_latency;
}
/* write data */
data_write(data);