~implemented faster/better FIR resampler, removed libsamplerate

~fixed some memory leaks with Blip Buffer
~reverted previous change regarding frame synchronization: always use VSYNC when switched to 60hz (fix video issues in interlace mode 2)
~optimized cell rendering (less byte swapping)
~fixed savestate file version checking
This commit is contained in:
ekeeke31 2009-07-22 17:25:41 +00:00
parent 9800c00f5a
commit dbc4d02fea
29 changed files with 477 additions and 368074 deletions

View File

@ -700,9 +700,7 @@ static void soundmenu ()
float psg_volume = (double)config.psg_preamp/100.0;
float fm_volume = (double)config.fm_preamp/100.0;
if (config.hq_fm == 0) sprintf (items[0].text, "High-Quality FM: OFF");
else if (config.hq_fm == 1) sprintf (items[0].text, "High-Quality FM: LINEAR");
else sprintf (items[0].text, "High-Quality FM: SINC");
sprintf (items[0].text, "High-Quality FM: %s", config.hq_fm ? "ON":"OFF");
sprintf (items[1].text, "PSG Noise Boost: %s", config.psgBoostNoise ? "ON":"OFF");
sprintf (items[2].text, "PSG Volume: %1.2f", psg_volume);
sprintf (items[3].text, "FM Volume: %1.2f", (double)config.fm_preamp/100.0);
@ -729,11 +727,8 @@ static void soundmenu ()
switch (ret)
{
case 0:
config.hq_fm ++;
if (config.hq_fm > 2) config.hq_fm = 0;
if (config.hq_fm == 0) sprintf (items[0].text, "High-Quality FM: OFF");
else if (config.hq_fm == 1) sprintf (items[0].text, "High-Quality FM: LINEAR");
else sprintf (items[0].text, "High-Quality FM: SINC");
config.hq_fm ^= 1;
sprintf (items[0].text, "High-Quality FM: %s", config.hq_fm ? "ON":"OFF");
if (genromsize)
{
unsigned char *temp = memalign(32,YM2612GetContextSize());

View File

@ -156,29 +156,28 @@ void gx_audio_Start(void)
StopOgg();
ASND_Pause(1);
AUDIO_StopDMA ();
AUDIO_RegisterDMACallback(NULL);
audioStarted = 0;
/* initialize default DMA length */
/* PAL (50Hz): 20000 us period --> 960 samples/frame @48kHz */
/* NTSC (60Hz): 16667 us period --> 800 samples/frame @48kHz */
dma_len = vdp_pal ? 960 : 800;
dma_sync = 0;
mixbuffer = 0;
delta = 0;
/* reset sound buffers */
memset(soundbuffer, 0, 2 * 3840);
/* let's use audio DMA to synchronize frame emulation */
AUDIO_RegisterDMACallback(ai_callback);
/* By default, use audio DMA to synchronize frame emulation */
if (gc_pal | vdp_pal) AUDIO_RegisterDMACallback(ai_callback);
/* 60hz video mode requires synchronization with Video interrupt */
/* VSYNC period is 16715 us which is approx. 802.32 samples */
/* to prevent audio/video desynchronization, we approximate the exact */
/* number of samples by changing audio DMA length on each frame */
if (vdp_pal | gc_pal)
dma_sync = 0;
else
dma_sync = 80232;
else dma_sync = 80232;
}
/***

View File

@ -334,6 +334,12 @@ static camera cam = {
{0.0F, 0.0F, 0.0F}
};
/* VSYNC callback */
static void vi_callback(u32 cnt)
{
frameticker++;
}
/* Vertex Rendering */
static inline void draw_vert(u8 pos, f32 s, f32 t)
{
@ -1246,7 +1252,8 @@ void gx_video_Stop(void)
gxResetRendering(1);
gxResetView(vmode);
/* inputs should be updated during VSYNC */
/* VSYNC default callbacks */
VIDEO_SetPreRetraceCallback(NULL);
VIDEO_SetPostRetraceCallback(gx_input_UpdateMenu);
/* reset VI & adjust overscan */
@ -1266,7 +1273,9 @@ void gx_video_Start(void)
else
gc_pal = 0;
/* disable VSYNC callback */
/* VSYNC callbacks */
/* in 60hz mode we use VSYNC to synchronize frame emulation */
if (!gc_pal && !vdp_pal) VIDEO_SetPreRetraceCallback(vi_callback);
VIDEO_SetPostRetraceCallback(NULL);
VIDEO_Flush();

View File

@ -156,9 +156,8 @@ static __inline__ void WRITE_LONG(void *address, uint32 data)
src++;
#else
#define DRAW_COLUMN(ATTR, LINE) \
attr_msb = ATTR >> 16; \
atex = atex_table[(ATTR_MSB >> 13) & 7]; \
src = (uint32 *)&bg_pattern_cache[(ATTR_MSB & 0x1FFF) << 6 | (LINE)]; \
atex = atex_table[(ATTR >> 29) & 7]; \
src = (uint32 *)&bg_pattern_cache[(ATTR & 0x1FFF0000) >> 10 | (LINE)]; \
WRITE_LONG(dst, READ_LONG(src) | atex); \
dst++; \
src++; \
@ -188,9 +187,8 @@ static __inline__ void WRITE_LONG(void *address, uint32 data)
*dst++ = (*src++ | atex);
#else
#define DRAW_COLUMN(ATTR, LINE) \
attr_msb = ATTR >> 16; \
atex = atex_table[(attr_msb >> 13) & 7]; \
src = (uint32 *)&bg_pattern_cache[(attr_msb & 0x1FFF) << 6 | (LINE)]; \
atex = atex_table[(ATTR >> 29) & 7]; \
src = (uint32 *)&bg_pattern_cache[(ATTR & 0x1FFF0000) >> 10 | (LINE)]; \
*dst++ = (*src++ | atex); \
*dst++ = (*src++ | atex); \
atex = atex_table[(ATTR >> 13) & 7]; \
@ -238,10 +236,9 @@ static __inline__ void WRITE_LONG(void *address, uint32 data)
src++;
#else
#define DRAW_COLUMN_IM2(ATTR, LINE) \
attr_msb = ATTR >> 16; \
atex = atex_table[(attr_msb >> 13) & 7]; \
offs = (attr_msb & 0x03FF) << 7 | (attr_msb & 0x1800) << 6 | (LINE); \
if(attr_msb & 0x1000) offs ^= 0x40; \
atex = atex_table[(ATTR >> 29) & 7]; \
offs = (ATTR & 0x03FF0000) >> 9 | (ATTR & 0x18000000) >> 10 | (LINE); \
if(ATTR & 0x10000000) offs ^= 0x40; \
src = (uint32 *)&bg_pattern_cache[offs]; \
WRITE_LONG(dst, READ_LONG(src) | atex); \
dst++; \
@ -278,10 +275,9 @@ static __inline__ void WRITE_LONG(void *address, uint32 data)
*dst++ = (*src++ | atex);
#else
#define DRAW_COLUMN_IM2(ATTR, LINE) \
attr_msb = ATTR >> 16; \
atex = atex_table[(attr_msb >> 13) & 7]; \
offs = (attr_msb & 0x03FF) << 7 | (attr_msb & 0x1800) << 6 | (LINE); \
if(attr_msb & 0x1000) offs ^= 0x40; \
atex = atex_table[(ATTR >> 29) & 7]; \
offs = (ATTR & 0x03FF0000) >> 9 | (ATTR & 0x18000000) >> 10 | (LINE); \
if(ATTR & 0x10000000) offs ^= 0x40; \
src = (uint32 *)&bg_pattern_cache[offs]; \
*dst++ = (*src++ | atex); \
*dst++ = (*src++ | atex); \
@ -756,7 +752,8 @@ static uint32 make_lut_bgobj_ste(uint32 bx, uint32 sx)
static void color_update_8(int index, uint16 data)
{
/* Palette Selection bit */
/* VDP Palette Selection bit */
/* color value is limited to 00X00X00X */
if (!(reg[0] & 4)) data &= 0x49;
if(reg[12] & 8)
@ -776,7 +773,8 @@ static void color_update_8(int index, uint16 data)
static void color_update_15(int index, uint16 data)
{
/* Palette Selection bit */
/* VDP Palette Selection bit */
/* color value is limited to 00X00X00X */
if (!(reg[0] & 4)) data &= 0x49;
if(reg[12] & 8)
@ -796,7 +794,8 @@ static void color_update_15(int index, uint16 data)
static void color_update_32(int index, uint16 data)
{
/* Palette Selection bit */
/* VDP Palette Selection bit */
/* color value is limited to 00X00X00X */
if (!(reg[0] & 4)) data &= 0x49;
if(reg[12] & 8)
@ -818,7 +817,8 @@ static void color_update_32(int index, uint16 data)
static void color_update_16(int index, uint16 data)
{
/* Palette Selection bit */
/* VDP Palette Selection bit */
/* color value is limited to 00X00X00X */
if (!(reg[0] & 4)) data &= 0x49;
if(reg[12] & 8)
@ -967,9 +967,6 @@ static inline uint32 get_hscroll(uint32 line)
static void render_bg(uint32 line, uint32 width)
{
uint32 column, atex, atbuf, *src, *dst;
#ifndef LSB_FIRST
uint32 attr_msb;
#endif
/* common data */
uint32 xscroll = get_hscroll(line);
@ -1088,9 +1085,6 @@ static void render_bg(uint32 line, uint32 width)
static void render_bg_vs(uint32 line, uint32 width)
{
uint32 column, atex, atbuf, *src, *dst;
#ifndef LSB_FIRST
uint32 attr_msb;
#endif
/* common data */
uint32 xscroll = get_hscroll(line);
@ -1221,9 +1215,6 @@ static void render_bg_vs(uint32 line, uint32 width)
static void render_bg_im2(uint32 line, uint32 width, uint32 odd)
{
uint32 column, atex, atbuf, offs, *src, *dst;
#ifndef LSB_FIRST
uint32 attr_msb;
#endif
/* common data */
uint32 xscroll = get_hscroll(line);
@ -1728,7 +1719,7 @@ void remap_buffer(uint32 line, uint32 width)
#endif
}
/* Update Window Clipping (only called when registers change) */
/* Update Window Clipping (now only called on VDP registers change) */
void window_clip(void)
{
/* Window size and invert flags */

View File

@ -0,0 +1,298 @@
/* Game_Music_Emu 0.5.2. http://www.slack.net/~ant/ */
/* Copyright (C) 2004-2006 Shay Green. */
/* Modified by Eke-Eke for use in Genesis Plus (2009). */
#include "Fir_Resampler.h"
#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
/* sound buffer */
static sample_t *buffer = NULL;
static int buffer_size = 0;
static sample_t impulses[MAX_RES][WIDTH];
static sample_t* write_pos = NULL;
static int res = 1;
static int imp_phase = 0;
static unsigned long skip_bits = 0;
static int step = STEREO;
static int input_per_cycle;
static double ratio = 1.0;
static void gen_sinc(double rolloff, int width, double offset, double spacing, double scale, int count, sample_t *out )
{
double const maxh = 256;
double const fstep = M_PI / maxh * spacing;
double const to_w = maxh * 2 / width;
double const pow_a_n = pow( rolloff, maxh );
scale /= maxh * 2;
double angle = (count / 2 - 1 + offset) * -fstep;
while ( count-- )
{
*out++ = 0;
double w = angle * to_w;
if ( fabs( w ) < M_PI )
{
double rolloff_cos_a = ROLLOFF * cos( angle );
double num = 1 - rolloff_cos_a -
pow_a_n * cos( maxh * angle ) +
pow_a_n * ROLLOFF * cos( (maxh - 1) * angle );
double den = 1 - rolloff_cos_a - rolloff_cos_a + ROLLOFF * ROLLOFF;
double sinc = scale * num / den - scale;
out [-1] = (short) (cos( w ) * sinc + sinc);
}
angle += fstep;
}
}
static int available( unsigned long input_count )
{
int cycle_count = input_count / input_per_cycle;
int output_count = cycle_count * res * STEREO;
input_count -= cycle_count * input_per_cycle;
unsigned long skip = skip_bits >> imp_phase;
int remain = res - imp_phase;
while ( input_count >= 0 )
{
input_count -= step + (skip & 1) * STEREO;
skip >>= 1;
if ( !--remain )
{
skip = skip_bits;
remain = res;
}
output_count += 2;
}
return output_count;
}
int Fir_Resampler_initialize( int new_size )
{
buffer = (sample_t *) realloc( buffer, (new_size + WRITE_OFFSET) * sizeof (sample_t) );
if ( !buffer && new_size ) return 0;
buffer_size = new_size + WRITE_OFFSET;
Fir_Resampler_clear();
return 1;
}
void Fir_Resampler_shutdown( void )
{
if (buffer) free(buffer);
buffer = 0;
buffer_size = 0;
write_pos = 0;
}
void Fir_Resampler_clear()
{
imp_phase = 0;
if ( buffer_size )
{
write_pos = &buffer [WRITE_OFFSET];
memset( buffer, 0, buffer_size * sizeof (sample_t) );
}
}
double Fir_Resampler_time_ratio( double new_factor )
{
ratio = new_factor;
int i, r;
double fstep = 0.0;
double least_error = 2;
double pos = 0.0;
res = -1;
for ( r = 1; r <= MAX_RES; r++ )
{
pos += ratio;
double nearest = floor( pos + 0.5 );
double error = fabs( pos - nearest );
if ( error < least_error )
{
res = r;
fstep = nearest / res;
least_error = error;
}
}
skip_bits = 0;
step = STEREO * (int) floor( fstep );
ratio = fstep;
fstep = fmod( fstep, 1.0 );
double filter = (ratio < 1.0) ? 1.0 : 1.0 / ratio;
pos = 0.0;
input_per_cycle = 0;
for ( i = 0; i < res; i++ )
{
gen_sinc( ROLLOFF, (int) (WIDTH * filter + 1) & ~1, pos, filter,
(double) (0x7FFF * GAIN * filter),
(int) WIDTH, impulses[i] );
pos += fstep;
input_per_cycle += step;
if ( pos >= 0.9999999 )
{
pos -= 1.0;
skip_bits |= 1 << i;
input_per_cycle++;
}
}
Fir_Resampler_clear();
return ratio;
}
/* Current ratio */
double Fir_Resampler_ratio( void )
{
return ratio;
}
/* Number of input samples that can be written */
int Fir_Resampler_max_write( void )
{
return buffer + buffer_size - write_pos;
}
/* Pointer to place to write input samples */
sample_t* Fir_Resampler_buffer( void )
{
return write_pos;
}
/* Number of input samples in buffer */
int Fir_Resampler_written( void )
{
return write_pos - &buffer [WRITE_OFFSET];
}
/* Number of output samples available */
int Fir_Resampler_avail( void )
{
return available( write_pos - &buffer [WIDTH * STEREO] );
}
void Fir_Resampler_write( long count )
{
write_pos += count;
assert( write_pos <= ( buffer + buffer_size ) );
}
int Fir_Resampler_read( sample_t** out, unsigned long count )
{
sample_t* out_l = out[0];
sample_t* out_r = out[1];
const sample_t* in = buffer;
sample_t* end_pos = write_pos;
unsigned long skip = skip_bits >> imp_phase;
sample_t const* imp = impulses [imp_phase];
int remain = res - imp_phase;
int n;
if ( end_pos - in >= WIDTH * STEREO )
{
end_pos -= WIDTH * STEREO;
do
{
count--;
/* accumulate in extended precision */
unsigned long l = 0;
unsigned long r = 0;
const sample_t* i = in;
if ( count < 0 )
break;
for ( n = WIDTH / 2; n; --n )
{
int pt0 = imp [0];
l += pt0 * i [0];
r += pt0 * i [1];
int pt1 = imp [1];
imp += 2;
l += pt1 * i [2];
r += pt1 * i [3];
i += 4;
}
remain--;
l >>= 15;
r >>= 15;
in += (skip * STEREO) & STEREO;
skip >>= 1;
in += step;
if ( !remain )
{
imp = impulses [0];
skip = skip_bits;
remain = res;
}
*out_l++ = (sample_t) l;
*out_r++ = (sample_t) r;
}
while ( in <= end_pos );
}
imp_phase = res - remain;
int left = write_pos - in;
write_pos = &buffer [left];
memmove( buffer, in, left * sizeof *in );
return out_l - out[0];
}
int Fir_Resampler_input_needed( unsigned long output_count )
{
unsigned long input_count = 0;
unsigned long skip = skip_bits >> imp_phase;
int remain = res - imp_phase;
while ( (output_count -= 2) > 0 )
{
input_count += step + (skip & 1) * STEREO;
skip >>= 1;
if ( !--remain )
{
skip = skip_bits;
remain = res;
}
output_count -= 2;
}
long input_extra = input_count - (write_pos - &buffer [(WIDTH - 1) * STEREO]);
if ( input_extra < 0 )
input_extra = 0;
return input_extra;
}
int Fir_Resampler_skip_input( long count )
{
int remain = write_pos - buffer;
int max_count = remain - WIDTH * STEREO;
if ( count > max_count )
count = max_count;
remain -= count;
write_pos = &buffer [remain];
memmove( buffer, &buffer [count], remain * sizeof buffer [0] );
return count;
}

View File

@ -0,0 +1,30 @@
/* Finite impulse response (FIR) resampler with adjustable FIR size */
/* Game_Music_Emu 0.5.2 */
#ifndef FIR_RESAMPLER_H
#define FIR_RESAMPLER_H
#define STEREO 2
#define MAX_RES 32
#define WIDTH 16
#define WRITE_OFFSET (WIDTH * STEREO) - STEREO
#define ROLLOFF 0.999
#define GAIN 1.0
typedef short sample_t;
extern int Fir_Resampler_initialize( int new_size );
extern void Fir_Resampler_shutdown( void );
extern void Fir_Resampler_clear( void );
extern double Fir_Resampler_time_ratio( double new_factor );
extern double Fir_Resampler_ratio( void );
extern int Fir_Resampler_max_write( void );
extern sample_t* Fir_Resampler_buffer( void );
extern int Fir_Resampler_written( void );
extern int Fir_Resampler_avail( void );
extern void Fir_Resampler_write( long count );
extern int Fir_Resampler_read( sample_t** out, unsigned long count );
extern int Fir_Resampler_input_needed( unsigned long output_count );
extern int Fir_Resampler_skip_input( long count );
#endif

View File

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

View File

@ -1,340 +0,0 @@
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.

View File

@ -1,23 +0,0 @@
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.

View File

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

View File

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

View File

@ -1,143 +0,0 @@
/* 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. */
#ifdef DOS
#define HAVE_LRINT 0
#else
#define HAVE_LRINT 1
#endif
/* Define if you have C99's lrintf function. */
#define HAVE_LRINTF 1
/* 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

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

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

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

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

View File

@ -1,478 +0,0 @@
/*
** 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"
#ifndef NGC
#include "mid_qual_coeffs.h"
#include "high_qual_coeffs.h"
#endif
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)
{
#ifndef NGC
case SRC_SINC_BEST_QUALITY :
return "Best Sinc Interpolator" ;
case SRC_SINC_MEDIUM_QUALITY :
return "Medium Sinc Interpolator" ;
#endif
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)
{
#ifndef NGC
case SRC_SINC_FASTEST :
return "Band limited sinc interpolation, fastest, 97dB SNR, 80% BW." ;
case SRC_SINC_MEDIUM_QUALITY :
return "Band limited sinc interpolation, medium quality, 121dB SNR, 90% BW." ;
#endif
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 ;
#ifndef NGC
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 ;
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 */

View File

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

@ -29,19 +29,20 @@ typedef int buf_t; /* type of element in delta buffer */
struct blip_buffer_t
{
int factor; /* clocks to samples conversion factor */
int offset; /* fractional position of clock 0 in delta buffer */
int amp; /* current output amplitude (sum of all deltas up to now) */
int size; /* size of delta buffer */
buf_t buf [65536]; /* delta buffer, only size elements actually allocated */
int factor; /* clocks to samples conversion factor */
int offset; /* fractional position of clock 0 in delta buffer */
int amp; /* current output amplitude (sum of all deltas up to now) */
int size; /* size of delta buffer */
buf_t *buf; /* delta buffer, only size elements actually allocated */
};
blip_buffer_t* blip_alloc( int clock_rate, int sample_rate, int size )
{
/* Allocate space for structure and delta buffer */
blip_buffer_t* s = (blip_buffer_t*) malloc(
offsetof (blip_buffer_t, buf) + (size + buf_extra) * sizeof (buf_t) );
if ( s != NULL )
blip_buffer_t* s = (blip_buffer_t*) malloc( sizeof(blip_buffer_t) );
if (!s) return 0;
s->buf = (buf_t*) malloc((size + buf_extra) * sizeof (buf_t) );
if ( s->buf != NULL )
{
/* Calculate output:input ratio and convert to fixed-point */
double ratio = (double) sample_rate / clock_rate;
@ -55,6 +56,7 @@ blip_buffer_t* blip_alloc( int clock_rate, int sample_rate, int size )
void blip_free( blip_buffer_t* s )
{
if (s->buf) free(s->buf);
free( s );
}

View File

@ -22,44 +22,41 @@
****************************************************************************************/
#include "shared.h"
#include "Fir_Resampler.h"
/* cycle-accurate samples */
static int m68cycles_per_sample[2];
/* return the number of samples that should have been rendered so far */
static inline uint32 fm_sample_cnt(uint8 is_z80)
/* return the number of samples that should be retrieved */
static inline int fm_sample_cnt(uint8 z80)
{
if (is_z80) return ((count_z80 + current_z80 - z80_ICount) * 15) / (m68cycles_per_sample[0] * 7);
else return (count_m68k / m68cycles_per_sample[0]);
if (z80) return ((((count_z80 + current_z80 - z80_ICount) * 15) / (m68cycles_per_sample[0] * 7)) - snd.fm.pos);
else return ((count_m68k / m68cycles_per_sample[0]) - snd.fm.pos);
}
static inline uint32 psg_sample_cnt(uint8 is_z80)
static inline int psg_sample_cnt(uint8 z80)
{
if (is_z80) return ((count_z80 + current_z80 - z80_ICount) * 15) / (m68cycles_per_sample[1] * 7);
else return (count_m68k / m68cycles_per_sample[1]);
if (z80) return ((((count_z80 + current_z80 - z80_ICount) * 15) / (m68cycles_per_sample[1] * 7)) - snd.psg.pos);
else return ((count_m68k / m68cycles_per_sample[1]) - snd.psg.pos);
}
/* update FM samples */
static inline void fm_update()
static inline void fm_update(int cnt)
{
if(snd.fm.curStage - snd.fm.lastStage > 0)
if (cnt > 0)
{
int *tempBuffer[2];
tempBuffer[0] = snd.fm.buffer[0] + snd.fm.lastStage;
tempBuffer[1] = snd.fm.buffer[1] + snd.fm.lastStage;
YM2612UpdateOne(tempBuffer, snd.fm.curStage - snd.fm.lastStage);
snd.fm.lastStage = snd.fm.curStage;
YM2612Update(cnt);
snd.fm.pos += cnt;
}
}
/* update PSG samples */
static inline void psg_update()
static inline void psg_update(int cnt)
{
if(snd.psg.curStage - snd.psg.lastStage > 0)
if (cnt > 0)
{
int16 *tempBuffer = snd.psg.buffer + snd.psg.lastStage;
SN76489_Update(tempBuffer, snd.psg.curStage - snd.psg.lastStage);
snd.psg.lastStage = snd.psg.curStage;
SN76489_Update(snd.psg.buffer + snd.psg.pos, cnt);
snd.psg.pos += cnt;
}
}
@ -72,9 +69,12 @@ void sound_init(int rate)
m68cycles_per_sample[0] = (int)(((double)m68cycles_per_line * (double)lines_per_frame * (double)vdp_rate / (double)rate) + 0.5);
m68cycles_per_sample[1] = m68cycles_per_sample[0];
/* YM2612 is emulated at original frequency (VLCK/144) */
/* YM2612 is emulated at its original frequency (VLCK/144) */
if (config.hq_fm)
{
m68cycles_per_sample[0] = 144;
Fir_Resampler_time_ratio(vclk/144.0/(double)rate);
}
/* initialize sound chips */
SN76489_Init((int)zclk,rate);
@ -83,37 +83,26 @@ void sound_init(int rate)
void sound_update(int fm_len, int psg_len)
{
/* finalize sound buffers */
snd.fm.curStage = fm_len;
snd.psg.curStage = psg_len;
/* update last samples (if needed) */
fm_update();
psg_update();
fm_update(fm_len - snd.fm.pos);
psg_update(psg_len - snd.psg.pos);
/* reset samples count */
snd.fm.curStage = 0;
snd.fm.lastStage = 0;
snd.psg.curStage = 0;
snd.psg.lastStage = 0;
snd.fm.pos = 0;
snd.psg.pos = 0;
}
/* write FM chip */
void fm_write(unsigned int cpu, unsigned int address, unsigned int data)
{
if (address & 1)
{
snd.fm.curStage = fm_sample_cnt(cpu);
fm_update();
}
if (address & 1) fm_update(fm_sample_cnt(cpu));
YM2612Write(address, data);
}
/* read FM status */
unsigned int fm_read(unsigned int cpu, unsigned int address)
{
snd.fm.curStage = fm_sample_cnt(cpu);
fm_update();
fm_update(fm_sample_cnt(cpu));
return YM2612Read();
}
@ -121,7 +110,6 @@ unsigned int fm_read(unsigned int cpu, unsigned int address)
/* PSG write */
void psg_write(unsigned int cpu, unsigned int data)
{
snd.psg.curStage = psg_sample_cnt(cpu);
psg_update();
psg_update(psg_sample_cnt(cpu));
SN76489_Write(data);
}

View File

@ -124,6 +124,7 @@
#include <math.h>
#include "shared.h"
#include "Fir_Resampler.h"
/* globals */
#define FREQ_SH 16 /* 16.16 fixed point (frequency calculations) */
@ -1276,7 +1277,7 @@ INLINE void update_phase_lfo_channel(FM_CH *CH)
/* keyscale code */
int kc = (blk<<2) | opn_fktable[fn >> 8];
/* (frequency) phase increment counter */
int fc = (ym2612.OPN.fn_table[fn]>>(7-blk));
@ -1604,7 +1605,7 @@ INLINE void INTERNAL_TIMER_B(int step)
/* reload the counter */
if (ym2612.OPN.ST.TBL) ym2612.OPN.ST.TBC += ym2612.OPN.ST.TBL;
else ym2612.OPN.ST.TBC = ym2612.OPN.ST.TBL;
}
}
}
}
@ -1616,7 +1617,7 @@ static void OPNSetPres(int pres)
/* frequency base */
ym2612.OPN.ST.freqbase = ((double) ym2612.OPN.ST.clock / (double) ym2612.OPN.ST.rate) / ((double) pres);
/* YM2612 running at original frequency (~53 kHz) */
/* YM2612 running at original frequency (~53267 Hz) */
if (config.hq_fm) ym2612.OPN.ST.freqbase = 1.0;
ym2612.OPN.eg_timer_add = (UINT32)((1<<EG_SH) * ym2612.OPN.ST.freqbase);
@ -1902,17 +1903,21 @@ INLINE void OPNWriteReg(int r, int v)
}
/* Generate 32bits samples for ym2612 */
void YM2612UpdateOne(int **buffer, int length)
void YM2612Update(int length)
{
int i;
int lt,rt;
int16 *bufL,*bufR;
/* set buffers */
int *bufL = buffer[0];
int *bufR = buffer[1];
float *bufSRC = snd.fm.src_buffer ? (snd.fm.src_buffer + (2*snd.fm.lastStage)) : 0;
int16 *bufFIR = Fir_Resampler_buffer();
if (!bufFIR)
{
bufL = snd.fm.buffer[0] + snd.fm.pos;
bufR = snd.fm.buffer[1] + snd.fm.pos;
}
/* refresh PG and EG */
/* refresh PG and EG parameters */
refresh_fc_eg_chan(&ym2612.CH[0]);
refresh_fc_eg_chan(&ym2612.CH[1]);
@ -1946,7 +1951,7 @@ void YM2612UpdateOne(int **buffer, int length)
out_fm[4] = 0;
out_fm[5] = 0;
/* update SSG-EG enveloppe type */
/* update SSG-EG */
update_ssg_eg_channel(&ym2612.CH[0].SLOT[SLOT1]);
update_ssg_eg_channel(&ym2612.CH[1].SLOT[SLOT1]);
update_ssg_eg_channel(&ym2612.CH[2].SLOT[SLOT1]);
@ -1982,28 +1987,28 @@ void YM2612UpdateOne(int **buffer, int length)
}
else chan_calc(&ym2612.CH[5]);
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 = (out_fm[0] & ym2612.OPN.pan[0]);
rt = (out_fm[0] & ym2612.OPN.pan[1]);
lt += (out_fm[1] & ym2612.OPN.pan[2]);
rt += (out_fm[1] & ym2612.OPN.pan[3]);
lt += (out_fm[2] & ym2612.OPN.pan[4]);
rt += (out_fm[2] & ym2612.OPN.pan[5]);
lt += (out_fm[3] & ym2612.OPN.pan[6]);
rt += (out_fm[3] & ym2612.OPN.pan[7]);
lt += (out_fm[4] & ym2612.OPN.pan[8]);
rt += (out_fm[4] & ym2612.OPN.pan[9]);
lt += (out_fm[5] & ym2612.OPN.pan[10]);
rt += (out_fm[5] & ym2612.OPN.pan[11]);
/* limiter */
Limit(lt,MAXOUT,MINOUT);
Limit(rt,MAXOUT,MINOUT);
/* buffering */
if (bufSRC)
if (bufFIR)
{
*bufSRC++ = ((float) (lt)) / (8.0 * 0x10000000);
*bufSRC++ = ((float) (rt)) / (8.0 * 0x10000000);
*bufFIR++ = lt;
*bufFIR++ = rt;
}
else
{
@ -2030,8 +2035,12 @@ void YM2612UpdateOne(int **buffer, int length)
}
}
/* timer B control */
INTERNAL_TIMER_B(length);
/* update FIR resampler */
if (bufFIR)
Fir_Resampler_write(length * 2);
}
/* initialize ym2612 emulator(s) */

View File

@ -21,7 +21,7 @@
extern int YM2612Init(int baseclock, int rate);
extern int YM2612ResetChip(void);
extern void YM2612UpdateOne(int **buffer, int length);
extern void YM2612Update(int length);
extern void YM2612Write(unsigned int a, unsigned int v);
extern unsigned int YM2612Read(void);
extern unsigned char *YM2612GetContextPtr(void);

View File

@ -124,7 +124,7 @@ int state_load(unsigned char *buffer)
int state_save(unsigned char *buffer)
{
/* buffer size */
int bufferptr = 16;
int bufferptr = 0;
/* version string */
char version[16];

View File

@ -22,7 +22,7 @@
****************************************************************************************/
#include "shared.h"
#include "samplerate.h"
#include "Fir_Resampler.h"
#include "eq.h"
#define SND_SIZE (snd.buffer_size * sizeof(int16))
@ -60,8 +60,6 @@ void audio_set_equalizer(void)
* AUDIO stream update
****************************************************************/
static int ll, rr;
static SRC_DATA src_data;
void audio_update (int size)
{
int i;
@ -70,25 +68,24 @@ void audio_update (int size)
int fm_preamp = config.fm_preamp;
int filter = config.filter;
int16 *fm[2] = {snd.fm.buffer[0],snd.fm.buffer[1]};
int16 *psg = snd.psg.buffer;
#ifdef NGC
int16 *sb = (int16 *) soundbuffer[mixbuffer];
#endif
int *fm_l = snd.fm.buffer[0];
int *fm_r = snd.fm.buffer[1];
int16 *psg = snd.psg.buffer;
float *src = src_data.data_out;
double scaled_value;
/* resampling */
if (src)
if (config.hq_fm)
{
src_data.output_frames = size;
src_data.input_frames = (int)((double)size / src_data.src_ratio + 0.5);
sound_update(src_data.input_frames,size);
src_simple(&src_data,(config.hq_fm&1) ? SRC_LINEAR : SRC_SINC_FASTEST, 2);
int fm_len = (int) ((double)size * Fir_Resampler_ratio() + 0.5) ;
sound_update(fm_len,size);
Fir_Resampler_read(fm,size);
}
else
{
sound_update(size,size);
}
else sound_update(size,size);
/* mix samples */
for (i = 0; i < size; i ++)
@ -97,33 +94,8 @@ void audio_update (int size)
l = r = (((int)*psg++) * psg_preamp)/100;
/* FM samples (stereo) */
if (src)
{
/* left channel */
scaled_value = (*src++) * (8.0 * 0x10000000);
if (scaled_value >= (1.0 * 0x7FFFFFFF))
l = 0x7fffffff;
else if (scaled_value <= (-8.0 * 0x10000000))
l = -1 - 0x7fffffff;
else
l += (lrint(scaled_value) * fm_preamp)/100;
/* right channel */
scaled_value = (*src++) * (8.0 * 0x10000000);
if (scaled_value >= (1.0 * 0x7FFFFFFF))
r = 0x7fffffff;
else if (scaled_value <= (-8.0 * 0x10000000))
r = -1 - 0x7fffffff;
else
r += (lrint(scaled_value) * fm_preamp)/100;
}
else
{
l += (*fm_l * fm_preamp)/100;
r += (*fm_r * fm_preamp)/100;
*fm_l++ = 0;
*fm_r++ = 0;
}
l += (*fm[0]++ * fm_preamp)/100;
r += (*fm[1]++ * fm_preamp)/100;
/* filtering */
if (filter & 1)
@ -168,7 +140,6 @@ int audio_init (int rate)
/* Clear the sound data context */
memset(&snd, 0, sizeof (snd));
memset(&src_data, 0, sizeof(src_data));
/* Make sure the requested sample rate is valid */
if (!rate || ((rate < 8000) | (rate > 48000))) return (-1);
@ -181,44 +152,27 @@ int audio_init (int rate)
#else
snd.buffer_size = (rate / vdp_rate);
/* allocate output buffers */
/* Output buffers */
snd.buffer[0] = (int16 *) malloc(SND_SIZE);
snd.buffer[1] = (int16 *) malloc(SND_SIZE);
if (!snd.buffer[0] || !snd.buffer[1]) return (-1);
#endif
/* SRC */
if (config.hq_fm)
{
/* SRC ratio (YM2612 original samplerate is VCLK/144) */
src_data.src_ratio = ((double)rate * 144.0) / ((double) vdp_rate * (double)m68cycles_per_line * (double)lines_per_frame);
/* max. output */
src_data.output_frames = snd.buffer_size;
/* max. input */
snd.fm.size = (int)((double)src_data.output_frames / src_data.src_ratio + 0.5);
src_data.input_frames = snd.fm.size;
/* SRC buffers */
src_data.data_in = (float *) malloc(snd.fm.size*2*sizeof(float));
src_data.data_out = (float *) malloc(snd.buffer_size*2*sizeof(float));
if (!src_data.data_in || !src_data.data_out) return (-1);
snd.fm.src_buffer = src_data.data_in;
}
else
{
/* YM2612 stream buffers */
snd.fm.size = snd.buffer_size;
snd.fm.buffer[0] = (int *)malloc (snd.fm.size * sizeof(int));
snd.fm.buffer[1] = (int *)malloc (snd.fm.size * sizeof(int));
if (!snd.fm.buffer[0] || !snd.fm.buffer[1]) return (-1);
}
/* SN76489 stream buffers */
snd.psg.buffer = (int16 *)malloc (SND_SIZE);
if (!snd.psg.buffer) return (-1);
/* YM2612 stream buffers */
snd.fm.buffer[0] = (int16 *)malloc (SND_SIZE);
snd.fm.buffer[1] = (int16 *)malloc (SND_SIZE);
if (!snd.fm.buffer[0] || !snd.fm.buffer[1]) return (-1);
/* Resampling buffer */
if (config.hq_fm)
{
if (!Fir_Resampler_initialize(4096)) return (-1);
}
/* 3 band EQ */
audio_init_equalizer();
@ -236,16 +190,15 @@ int audio_init (int rate)
****************************************************************/
void audio_shutdown(void)
{
/* free sound buffers */
/* Sound buffers */
if (snd.buffer[0]) free(snd.buffer[0]);
if (snd.buffer[1]) free(snd.buffer[1]);
if (snd.fm.buffer[0]) free(snd.fm.buffer[0]);
if (snd.fm.buffer[1]) free(snd.fm.buffer[1]);
if (snd.psg.buffer) free(snd.psg.buffer);
/* SRC */
if (src_data.data_in) free(src_data.data_in);
if (src_data.data_out) free(src_data.data_out);
/* Resampling buffer */
Fir_Resampler_shutdown();
/* sn76489 chip (Blip Buffer allocated memory) */
SN76489_Shutdown();
@ -277,10 +230,11 @@ void system_reset (void)
io_reset();
SN76489_Reset();
/* Sound Buffers */
/* Clear Sound Buffers */
if (snd.psg.buffer) memset (snd.psg.buffer, 0, SND_SIZE);
if (snd.fm.buffer[0]) memset (snd.fm.buffer[0], 0, snd.fm.size * sizeof(int));
if (snd.fm.buffer[1]) memset (snd.fm.buffer[1], 0, snd.fm.size * sizeof(int));
if (snd.fm.buffer[0]) memset (snd.fm.buffer[0], 0, SND_SIZE);
if (snd.fm.buffer[1]) memset (snd.fm.buffer[1], 0, SND_SIZE);
Fir_Resampler_clear();
}
/****************************************************************

View File

@ -65,16 +65,12 @@ typedef struct
int16 *buffer[2]; /* Signed 16-bit stereo sound data */
struct
{
int size;
int curStage;
int lastStage;
int *buffer[2];
float *src_buffer;
int pos;
int16 *buffer[2];
} fm;
struct
{
int curStage;
int lastStage;
int pos;
int16 *buffer;
} psg;
} t_snd;

View File

@ -766,7 +766,7 @@ static inline void reg_w(unsigned int r, unsigned int d)
sat_addr_mask = 0x03FF;
satb = (reg[5] << 9) & sat_base_mask;
/* update HC table */
/* Update HC table */
hctab = cycle2hc40;
#ifndef NGC
@ -782,7 +782,7 @@ static inline void reg_w(unsigned int r, unsigned int d)
sat_addr_mask = 0x01FF;
satb = (reg[5] << 9) & sat_base_mask;
/* update HC table */
/* Update HC table */
hctab = cycle2hc32;
#ifndef NGC
@ -831,7 +831,7 @@ static inline void reg_w(unsigned int r, unsigned int d)
y_mask = y_mask_table[(d & 3)];
break;
case 17: /* update clipping */
case 17: /* Update clipping */
reg[17] = d;
window_clip();
break;